Commit 573f5a3e1d2243ee0504cd917f93bb0d1ed4d372

Authored by 权海
1 parent 8fedd40b

feat(ui):使用临时内存保存原始数据提升计算速度

... ... @@ -220,6 +220,8 @@ class _HrvTrendSection extends StatefulWidget {
}
class _HrvTrendSectionState extends State<_HrvTrendSection> {
static const _hrvTrendLogMarker = '[OHOS_HRV_TREND_PROFILE]';
late final HrvReportLogic _logic;
late final Worker _periodWorker;
late final Worker _dateWorker;
... ... @@ -260,14 +262,27 @@ class _HrvTrendSectionState extends State<_HrvTrendSection> {
Future<void> _syncExternalQuery() async {
_syncingExternalQuery = true;
_logic.targetUserId.value = widget.query.targetUserId;
_logHrvTrend(
'section_syncExternalQuery_start period=${widget.query.period.name} '
'date=${widget.query.date} targetUserId=${widget.query.targetUserId} '
'isVip=${widget.isVip}',
);
try {
if (widget.isVip) {
await _logic.selectQuery(widget.query.period, widget.query.date);
await _logic.selectQuery(
widget.query.period,
widget.query.date,
forceRefresh: false,
);
} else {
_logic.initializeQuery(widget.query.period, widget.query.date);
}
} finally {
_syncingExternalQuery = false;
_logHrvTrend(
'section_syncExternalQuery_finish period=${widget.query.period.name} '
'date=${widget.query.date}',
);
}
}
... ... @@ -281,6 +296,11 @@ class _HrvTrendSectionState extends State<_HrvTrendSection> {
Future.microtask(() {
_queryNotificationScheduled = false;
if (!mounted || _syncingExternalQuery || !widget.isSelected) return;
_logHrvTrend(
'section_notifyParentQueryChanged '
'period=${_logic.selectedPeriod.value.name} '
'date=${_logic.selectedDate.value}',
);
widget.onQueryChanged(
_logic.selectedPeriod.value,
_logic.selectedDate.value,
... ... @@ -288,6 +308,10 @@ class _HrvTrendSectionState extends State<_HrvTrendSection> {
});
}
void _logHrvTrend(String message) {
debugPrint('$_hrvTrendLogMarker $message');
}
@override
void dispose() {
_periodWorker.dispose();
... ...
import 'package:flutter/foundation.dart';
import 'package:get/get.dart';
import 'trend_period_controller.dart';
/// HRV 心率变异性 专属 Controller
... ... @@ -11,29 +13,35 @@ class HrvController extends TrendPeriodController {
@override
void loadData() {
final stopwatch = Stopwatch()..start();
_log('legacy_load_start period=${currentPeriod.value.name} '
'offset=${dateOffset.value}');
isLoading.value = true;
// 模拟 API 延迟加载
Future.delayed(const Duration(milliseconds: 300), () {
final offset = dateOffset.value;
// 依据时间范围偏移动态渲染不同数据,模拟真实 API 拉取效果
averageHrv.value = '${46 + offset}';
changeHrv.value = offset >= 0 ? '+3' : '${offset * 2}';
chartData.value = [
42.0 + offset,
48.0 - offset,
55.0 + offset * 2,
46.0 - offset,
52.0 + offset,
58.0 + offset * 3,
50.0 - offset * 2,
].map((e) => e.clamp(20.0, 80.0)).toList();
chartLabels.value = ['一', '二', '三', '四', '五', '六', '日'];
isLoading.value = false;
});
final offset = dateOffset.value;
// 依据时间范围偏移动态渲染不同数据,模拟真实 API 拉取效果
averageHrv.value = '${46 + offset}';
changeHrv.value = offset >= 0 ? '+3' : '${offset * 2}';
chartData.value = [
42.0 + offset,
48.0 - offset,
55.0 + offset * 2,
46.0 - offset,
52.0 + offset,
58.0 + offset * 3,
50.0 - offset * 2,
].map((e) => e.clamp(20.0, 80.0)).toList();
chartLabels.value = ['一', '二', '三', '四', '五', '六', '日'];
isLoading.value = false;
_log('legacy_load_finish period=${currentPeriod.value.name} '
'count=${chartData.length} elapsedMs=${stopwatch.elapsedMilliseconds}');
}
void _log(String message) {
debugPrint('[OHOS_HRV_TREND_PROFILE] $message');
}
}
... ...
... ... @@ -5,6 +5,7 @@ import 'package:doublefeel_flutter/data/datasource/health/health_datasource.dart
import 'package:doublefeel_flutter/data/datasource/health/health_datasource_wrapper.dart';
import 'package:doublefeel_flutter/data/datasource/health/health_local_datasource.dart';
import 'package:doublefeel_flutter/data/datasource/health/health_remote_datasource.dart';
import 'package:flutter/foundation.dart';
import 'package:get/get.dart';
import '../../report_common/controllers/report_period_logic.dart';
... ... @@ -31,6 +32,7 @@ class HrvReportLogic extends ReportPeriodLogic {
final yearlyReport = Rxn<YearlyHrvReport>();
final HrvReportRepository repository;
final _myUserId = Get.find<UserStateService>().userId;
static const _logMarker = '[OHOS_HRV_TREND_PROFILE]';
bool get isMySelf =>
targetUserId.value == null || _myUserId == targetUserId.value;
... ... @@ -49,27 +51,53 @@ class HrvReportLogic extends ReportPeriodLogic {
@override
Future<void> loadReport() async {
final stopwatch = Stopwatch()..start();
final period = selectedPeriod.value;
final date = selectedDate.value;
_log(
'logic_load_start period=${period.name} date=$date '
'targetUserId=${targetUserId.value} isMySelf=$isMySelf',
);
isLoading.value = !isMySelf;
try {
if (selectedPeriod.value == ReportPeriod.year) {
if (period == ReportPeriod.year) {
yearlyReport.value = await repository.getYearlyReport(
selectedDate.value.year,
date.year,
targetUserId: targetUserId.value,
);
} else if (selectedPeriod.value == ReportPeriod.month) {
_log(
'logic_assign_finish period=${period.name} '
'days=${yearlyReport.value?.days.length ?? 0} '
'elapsedMs=${stopwatch.elapsedMilliseconds}',
);
} else if (period == ReportPeriod.month) {
monthlyReport.value = await repository.getMonthlyReport(
monthStart,
targetUserId: targetUserId.value,
);
_log(
'logic_assign_finish period=${period.name} '
'days=${monthlyReport.value?.days.length ?? 0} '
'elapsedMs=${stopwatch.elapsedMilliseconds}',
);
} else {
weeklyReport.value = await repository.getWeeklyReport(
weekStart,
targetUserId: targetUserId.value,
);
_log(
'logic_assign_finish period=${period.name} '
'days=${weeklyReport.value?.days.length ?? 0} '
'elapsedMs=${stopwatch.elapsedMilliseconds}',
);
}
} finally {
isLoading.value = false;
_log(
'logic_load_finish period=$period date=$date '
'elapsedMs=${stopwatch.elapsedMilliseconds}',
);
}
}
... ... @@ -78,4 +106,8 @@ class HrvReportLogic extends ReportPeriodLogic {
targetUserId.value = userId;
return loadReport();
}
void _log(String message) {
debugPrint('$_logMarker $message');
}
}
... ...
import 'package:doublefeel_flutter/core/result/app_result.dart';
import 'package:doublefeel_flutter/data/datasource/health/health_datasource.dart';
import 'package:doublefeel_flutter/data/models/health/hrv/hrv_statistics_data.dart';
import 'package:flutter/foundation.dart';
import '../models/hrv_report_models.dart';
... ... @@ -27,6 +28,7 @@ class ApiHrvReportDataSource implements HrvReportDataSource {
static const _weekDateRangeType = 0;
static const _monthDateRangeType = 1;
static const _yearDateRangeType = 2;
static const _logMarker = '[OHOS_HRV_TREND_PROFILE]';
final HealthDataSource _healthDataSource;
... ... @@ -36,15 +38,27 @@ class ApiHrvReportDataSource implements HrvReportDataSource {
int? targetUserId,
}) async {
final start = DateTime(weekStart.year, weekStart.month, weekStart.day);
final stopwatch = Stopwatch()..start();
_log(
'datasource_week_start weekStart=$start '
'targetUserId=$targetUserId',
);
final result = await _healthDataSource.getHrvStatistics(
_weekDateRangeType,
_dateKey(start),
queryUserId: targetUserId,
);
return switch (result) {
final fetchElapsedMs = stopwatch.elapsedMilliseconds;
final report = switch (result) {
AppSuccess(:final data) => _weeklyReportFromStatistics(start, data),
AppFailure() => WeeklyHrvReport.empty(start),
};
_log(
'datasource_week_finish success=${result is AppSuccess} '
'days=${report.days.length} fetchElapsedMs=$fetchElapsedMs '
'elapsedMs=${stopwatch.elapsedMilliseconds}',
);
return report;
}
@override
... ... @@ -53,15 +67,27 @@ class ApiHrvReportDataSource implements HrvReportDataSource {
int? targetUserId,
}) async {
final start = DateTime(monthStart.year, monthStart.month);
final stopwatch = Stopwatch()..start();
_log(
'datasource_month_start monthStart=$start '
'targetUserId=$targetUserId',
);
final result = await _healthDataSource.getHrvStatistics(
_monthDateRangeType,
_dateKey(start),
queryUserId: targetUserId,
);
return switch (result) {
final fetchElapsedMs = stopwatch.elapsedMilliseconds;
final report = switch (result) {
AppSuccess(:final data) => _monthlyReportFromStatistics(start, data),
AppFailure() => MonthlyHrvReport.empty(start),
};
_log(
'datasource_month_finish success=${result is AppSuccess} '
'days=${report.days.length} fetchElapsedMs=$fetchElapsedMs '
'elapsedMs=${stopwatch.elapsedMilliseconds}',
);
return report;
}
@override
... ... @@ -70,15 +96,28 @@ class ApiHrvReportDataSource implements HrvReportDataSource {
int? targetUserId,
}) async {
final start = DateTime(year);
final stopwatch = Stopwatch()..start();
_log('datasource_year_start year=$year targetUserId=$targetUserId');
final result = await _healthDataSource.getHrvStatistics(
_yearDateRangeType,
_dateKey(start),
queryUserId: targetUserId,
);
return switch (result) {
final fetchElapsedMs = stopwatch.elapsedMilliseconds;
final report = switch (result) {
AppSuccess(:final data) => _yearlyReportFromStatistics(year, data),
AppFailure() => YearlyHrvReport.empty(year),
};
_log(
'datasource_year_finish success=${result is AppSuccess} '
'days=${report.days.length} fetchElapsedMs=$fetchElapsedMs '
'elapsedMs=${stopwatch.elapsedMilliseconds}',
);
return report;
}
static void _log(String message) {
debugPrint('$_logMarker $message');
}
WeeklyHrvReport _weeklyReportFromStatistics(
... ...
import 'package:flutter/foundation.dart';
import '../models/hrv_report_models.dart';
import 'hrv_report_datasource.dart';
... ... @@ -22,34 +24,67 @@ class HrvReportRepositoryImpl implements HrvReportRepository {
const HrvReportRepositoryImpl({required this.dataSource});
final HrvReportDataSource dataSource;
static const _logMarker = '[OHOS_HRV_TREND_PROFILE]';
@override
Future<WeeklyHrvReport> getWeeklyReport(
DateTime weekStart, {
int? targetUserId,
}) {
return dataSource.fetchWeeklyReport(
}) async {
final stopwatch = Stopwatch()..start();
_log(
'repository_week_start weekStart=$weekStart targetUserId=$targetUserId');
final report = await dataSource.fetchWeeklyReport(
weekStart,
targetUserId: targetUserId,
);
_log(
'repository_week_finish days=${report.days.length} '
'elapsedMs=${stopwatch.elapsedMilliseconds}',
);
return report;
}
@override
Future<MonthlyHrvReport> getMonthlyReport(
DateTime monthStart, {
int? targetUserId,
}) {
return dataSource.fetchMonthlyReport(
}) async {
final stopwatch = Stopwatch()..start();
_log(
'repository_month_start monthStart=$monthStart '
'targetUserId=$targetUserId',
);
final report = await dataSource.fetchMonthlyReport(
monthStart,
targetUserId: targetUserId,
);
_log(
'repository_month_finish days=${report.days.length} '
'elapsedMs=${stopwatch.elapsedMilliseconds}',
);
return report;
}
@override
Future<YearlyHrvReport> getYearlyReport(
int year, {
int? targetUserId,
}) {
return dataSource.fetchYearlyReport(year, targetUserId: targetUserId);
}) async {
final stopwatch = Stopwatch()..start();
_log('repository_year_start year=$year targetUserId=$targetUserId');
final report = await dataSource.fetchYearlyReport(
year,
targetUserId: targetUserId,
);
_log(
'repository_year_finish days=${report.days.length} '
'elapsedMs=${stopwatch.elapsedMilliseconds}',
);
return report;
}
static void _log(String message) {
debugPrint('$_logMarker $message');
}
}
... ...
... ... @@ -217,6 +217,11 @@ class _HrvPeriodBar extends StatelessWidget {
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
debugPrint(
'[OHOS_HRV_TREND_PROFILE] period_tab_tap '
'from=${selectedPeriod.name} to=${period.name} '
'locked=${lockedPeriods.contains(period)}',
);
if (lockedPeriods.contains(period)) {
onLockedPeriodTap(period);
} else {
... ...
... ... @@ -140,17 +140,31 @@ abstract class ReportPeriodLogic {
Future<void> selectPeriod(
ReportPeriod period, {
bool? forceRefresh,
}) {
}) async {
final stopwatch = Stopwatch()..start();
final nextPeriod = normalizePeriod(period);
final shouldRefresh = forceRefresh ?? this.forceRefresh;
_logTrendProfile(
'selectPeriod_start from=${selectedPeriod.value.name} '
'to=${nextPeriod.name} selectedDate=${selectedDate.value} '
'forceRefresh=$shouldRefresh',
);
if (!shouldRefresh && selectedPeriod.value == nextPeriod) {
return Future.value();
_logTrendProfile(
'selectPeriod_skip_same period=${nextPeriod.name} '
'elapsedMs=${stopwatch.elapsedMilliseconds}',
);
return;
}
final nextDate = _dateForPeriodTransition(nextPeriod);
selectedPeriod.value = nextPeriod;
selectedDate.value = nextDate;
_setAnchorFor(nextPeriod, nextDate);
return loadReport();
await loadReport();
_logTrendProfile(
'selectPeriod_finish period=${nextPeriod.name} nextDate=$nextDate '
'elapsedMs=${stopwatch.elapsedMilliseconds}',
);
}
Future<void> selectDate(
... ... @@ -327,5 +341,8 @@ abstract class ReportPeriodLogic {
final normalized = DateTime(date.year, date.month, date.day);
return normalized.subtract(Duration(days: normalized.weekday - 1));
}
}
void _logTrendProfile(String message) {
debugPrint('[OHOS_HRV_TREND_PROFILE] $message');
}
... ...
... ... @@ -179,6 +179,19 @@ class OhosHealthRawDataSource implements HealthRawDataSource {
);
}
Future<OhosHealthRawDataCalculationSyncSnapshot>
syncCalculationRawDataSnapshot({
int? startTime,
int? endTime,
List<int>? dataTypes,
}) {
return _syncService.syncCalculationRawDataSnapshot(
startTime: startTime,
endTime: endTime,
dataTypes: dataTypes,
);
}
Future<OhosHealthRawDataSyncResult> syncRawData({
required int dataType,
int? startTime,
... ... @@ -237,6 +250,26 @@ class OhosHealthRawDataSource implements HealthRawDataSource {
.toList(growable: false);
}
List<HealthKitRawDataPoint> getRawDataFromSnapshot({
required OhosHealthRawDataMemorySnapshot snapshot,
required int dataType,
required int startTime,
required int endTime,
}) {
return snapshot
.query(dataType: dataType, startTime: startTime, endTime: endTime)
.map(
(item) => HealthKitRawDataPoint(
dataType: dataType,
startTime: item.dataTime,
endTime: item.dataTime,
value: _doublePayload(item.payload, 'value'),
isMotionLike: _boolPayload(item.payload, 'is_motion_like'),
),
)
.toList(growable: false);
}
@override
Future<List<HealthKitRawSleepDataPoint>> getRawSleepData(
int startTime,
... ... @@ -262,6 +295,21 @@ class OhosHealthRawDataSource implements HealthRawDataSource {
];
}
List<HealthKitRawDataPoint> getRawSleepIntervalsFromSnapshot({
required OhosHealthRawDataMemorySnapshot snapshot,
required int startTime,
required int endTime,
}) {
return snapshot
.query(
dataType: OhosHealthRawDataType.sleepAnalysis,
startTime: startTime,
endTime: endTime,
)
.map(_sleepPointFromItem)
.toList(growable: false);
}
@override
Future<List<HealthKitRawActivityDataPoint>> getRawActivityData(
int startTime,
... ... @@ -342,6 +390,21 @@ class OhosHealthRawDataSource implements HealthRawDataSource {
return items.map(_workoutPointFromItem).toList(growable: false);
}
List<HealthKitRawWorkoutDataPoint> getRawWorkoutDataFromSnapshot({
required OhosHealthRawDataMemorySnapshot snapshot,
required int startTime,
required int endTime,
}) {
return snapshot
.query(
dataType: OhosHealthRawDataType.workout,
startTime: startTime,
endTime: endTime,
)
.map(_workoutPointFromItem)
.toList(growable: false);
}
HealthKitRawDataPoint _sleepPointFromItem(OhosHealthRawDataItem item) {
return HealthKitRawDataPoint(
dataType: item.dataType,
... ...
... ... @@ -2084,6 +2084,7 @@ class HealthRawStressLocalStore {
static const realtimeStressResultsTable = 'realtime_stress_results';
static const dailyStressResultsTable = 'daily_stress_results';
static const sleepResultsTable = 'sleep_results';
static const hrvTrendLogMarker = '[OHOS_HRV_TREND_PROFILE]';
final Directory? _rootDirectory;
final DatabaseFactory? _databaseFactory;
... ... @@ -2217,6 +2218,7 @@ class HealthRawStressLocalStore {
required int startTime,
required int endTime,
}) async {
final stopwatch = Stopwatch()..start();
final db = await _database(userId);
final rows = await db.query(
hrvResultsTable,
... ... @@ -2224,7 +2226,13 @@ class HealthRawStressLocalStore {
whereArgs: [startTime, endTime],
orderBy: 'raw_end_time ASC',
);
return rows.map(HealthRawHrvStressPoint.fromDb).toList();
final points = rows.map(HealthRawHrvStressPoint.fromDb).toList();
_logHrvTrend(
'result_db_query_hrv_finish userId=$userId '
'startTime=$startTime endTime=$endTime rows=${rows.length} '
'elapsedMs=${stopwatch.elapsedMilliseconds}',
);
return points;
}
Future<List<HealthRawHrvStressPoint>> queryPendingHrvStressPoints({
... ... @@ -2275,6 +2283,7 @@ class HealthRawStressLocalStore {
required int startDate,
required int endDate,
}) async {
final stopwatch = Stopwatch()..start();
final db = await _database(userId);
final rows = await db.query(
dailyStressResultsTable,
... ... @@ -2282,7 +2291,13 @@ class HealthRawStressLocalStore {
whereArgs: [startDate, endDate],
orderBy: 'date ASC',
);
return rows.map(HealthRawDailyStressPoint.fromDb).toList();
final points = rows.map(HealthRawDailyStressPoint.fromDb).toList();
_logHrvTrend(
'result_db_query_daily_stress_finish userId=$userId '
'startDate=$startDate endDate=$endDate rows=${rows.length} '
'elapsedMs=${stopwatch.elapsedMilliseconds}',
);
return points;
}
Future<List<HealthRawDailyStressPoint>> queryPendingDailyStressPoints({
... ... @@ -3250,6 +3265,16 @@ CREATE TABLE IF NOT EXISTS $sleepResultsTable (
message.contains('code 2067');
}
void _logHrvTrend(String message) {
final taggedMessage = '$hrvTrendLogMarker $message';
debugPrint(taggedMessage);
try {
AppLogger.i(taggedMessage);
} catch (_) {
// AppLogger may not be initialized in isolated test/bootstrap contexts.
}
}
int _currentUnixSeconds() {
return DateTime.now().millisecondsSinceEpoch ~/ 1000;
}
... ...
... ... @@ -33,6 +33,8 @@ class OHOSHealthRawDataCoreService {
static const String _dailyStressLogMarker = '[OHOS_DAILY_STRESS_CALC]';
static const String _sleepCalcLogMarker = '[OHOS_SLEEP_CALC]';
static const String _profileLogMarker = '[OHOS_HEALTH_RAW_PROFILE]';
static const String _timingLogMarker = '[OHOS_HEALTH_TIMING]';
static const String _hrvTrendLogMarker = '[OHOS_HRV_TREND_PROFILE]';
OHOSHealthRawDataCoreService({
HealthRawDataSource? rawDataSource,
... ... @@ -261,15 +263,22 @@ class OHOSHealthRawDataCoreService {
final willSyncRawData =
hasAuthorization && _rawDataSource is OhosHealthRawDataSource;
final syncStartTime = willSyncRawData ? DateTime.now() : null;
final syncResults = await _syncCalculationRawDataSafely(
final syncSnapshot = await _syncCalculationRawDataSafely(
hasAuthorization: hasAuthorization,
startTime: forceStartTime,
endTime: effectiveEndTime,
);
final syncResults =
syncSnapshot?.results ?? const <OhosHealthRawDataSyncResult>[];
final syncElapsed = syncStartTime == null
? Duration.zero
: DateTime.now().difference(syncStartTime);
final syncedRawStartTime = _earliestStoredTime(syncResults);
_logInfo(
'$_timingLogMarker fetch_all_finish userId=$userId '
'elapsedMs=${syncElapsed.inMilliseconds}',
);
final syncedRawStartTime = syncSnapshot?.rawData.earliestTime() ??
_earliestStoredTime(syncResults);
_logInfo(
'calculate_sync_finish startTime=$requestedStartTime '
'endTime=$effectiveEndTime syncedRawStartTime=$syncedRawStartTime '
... ... @@ -298,6 +307,7 @@ class OHOSHealthRawDataCoreService {
effectiveEndTime: effectiveEndTime,
earliestStartTime: earliestStartTime,
syncedRawStartTime: syncedRawStartTime,
rawDataSnapshot: syncSnapshot?.rawData,
readChunkDays: readChunkDays,
);
} catch (error) {
... ... @@ -323,6 +333,10 @@ class OHOSHealthRawDataCoreService {
'sleep=${storedResult.result.sleepResults.length} '
'elapsedMs=${calculationElapsed.inMilliseconds}',
);
_logInfo(
'$_timingLogMarker calculate_finish userId=$userId '
'elapsedMs=${calculationElapsed.inMilliseconds}',
);
final uploadScheduleStopwatch = Stopwatch()..start();
_scheduleResultUpload();
_profileLog(
... ... @@ -339,7 +353,7 @@ class OHOSHealthRawDataCoreService {
'core_localNotification_finish userId=$userId '
'elapsedMs=${notificationStopwatch.elapsedMilliseconds}',
);
if (_hasStoredRawData(syncResults) ||
if (_hasFetchedRawData(syncResults) ||
_hasCalculatedResult(storedResult.result)) {
_showDebugTimingToast(
syncElapsed: syncElapsed,
... ... @@ -372,6 +386,7 @@ class OHOSHealthRawDataCoreService {
required int effectiveEndTime,
required int earliestStartTime,
required int? syncedRawStartTime,
required OhosHealthRawDataMemorySnapshot? rawDataSnapshot,
required int readChunkDays,
}) async {
final totalStopwatch = Stopwatch()..start();
... ... @@ -486,10 +501,11 @@ class OHOSHealthRawDataCoreService {
);
final hrvFetchStopwatch = Stopwatch()..start();
final hrvPoints = await _fetchRawDataInChunks(
final hrvPoints = await _fetchRawDataForCalculation(
HealthDataUploadType.hrv.type,
hrvStartTime,
effectiveEndTime,
rawDataSnapshot: rawDataSnapshot,
readChunkDays: readChunkDays,
);
_profileLog(
... ... @@ -500,10 +516,11 @@ class OHOSHealthRawDataCoreService {
'elapsedMs=${hrvFetchStopwatch.elapsedMilliseconds}',
);
final heartRateFetchStopwatch = Stopwatch()..start();
final heartRatePoints = await _fetchRawDataInChunks(
final heartRatePoints = await _fetchRawDataForCalculation(
HealthDataUploadType.heartRate.type,
heartRateStartTime,
effectiveEndTime,
rawDataSnapshot: rawDataSnapshot,
readChunkDays: readChunkDays,
);
_profileLog(
... ... @@ -514,10 +531,11 @@ class OHOSHealthRawDataCoreService {
'elapsedMs=${heartRateFetchStopwatch.elapsedMilliseconds}',
);
final restingHeartRateFetchStopwatch = Stopwatch()..start();
final restingHeartRatePoints = await _fetchRawDataInChunks(
final restingHeartRatePoints = await _fetchRawDataForCalculation(
HealthDataUploadType.restingHeartRate.type,
heartRateStartTime,
effectiveEndTime,
rawDataSnapshot: rawDataSnapshot,
readChunkDays: readChunkDays,
);
_profileLog(
... ... @@ -529,9 +547,10 @@ class OHOSHealthRawDataCoreService {
'elapsedMs=${restingHeartRateFetchStopwatch.elapsedMilliseconds}',
);
final sleepFetchStopwatch = Stopwatch()..start();
final sleepIntervals = await _fetchSleepIntervalsInChunks(
final sleepIntervals = await _fetchSleepIntervalsForCalculation(
sleepStartTime,
effectiveEndTime,
rawDataSnapshot: rawDataSnapshot,
readChunkDays: readChunkDays,
);
_profileLog(
... ... @@ -541,9 +560,10 @@ class OHOSHealthRawDataCoreService {
'elapsedMs=${sleepFetchStopwatch.elapsedMilliseconds}',
);
final workoutFetchStopwatch = Stopwatch()..start();
final workoutIntervals = await _fetchWorkoutIntervalsInChunks(
final workoutIntervals = await _fetchWorkoutIntervalsForCalculation(
heartRateStartTime,
effectiveEndTime,
rawDataSnapshot: rawDataSnapshot,
readChunkDays: readChunkDays,
);
_profileLog(
... ... @@ -808,12 +828,19 @@ class OHOSHealthRawDataCoreService {
Future<List<HealthRawHrvStressPoint>> queryHrvStressPoints({
required int startTime,
required int endTime,
}) {
return _localStore.queryHrvStressPoints(
}) async {
final stopwatch = Stopwatch()..start();
final points = await _localStore.queryHrvStressPoints(
userId: _userId,
startTime: startTime,
endTime: endTime,
);
_logInfo(
'$_hrvTrendLogMarker core_query_hrv_results_finish '
'userId=$_userId startTime=$startTime endTime=$endTime '
'count=${points.length} elapsedMs=${stopwatch.elapsedMilliseconds}',
);
return points;
}
Future<List<HealthRawRealtimeStressPoint>> queryRealtimeStressPoints({
... ... @@ -834,12 +861,19 @@ class OHOSHealthRawDataCoreService {
Future<List<HealthRawDailyStressPoint>> queryDailyStressPoints({
required int startDate,
required int endDate,
}) {
return _localStore.queryDailyStressPoints(
}) async {
final stopwatch = Stopwatch()..start();
final points = await _localStore.queryDailyStressPoints(
userId: _userId,
startDate: startDate,
endDate: endDate,
);
_logInfo(
'$_hrvTrendLogMarker core_query_daily_stress_finish '
'userId=$_userId startDate=$startDate endDate=$endDate '
'count=${points.length} elapsedMs=${stopwatch.elapsedMilliseconds}',
);
return points;
}
Future<List<HealthRawSleepResult>> querySleepResults({
... ... @@ -859,12 +893,20 @@ class OHOSHealthRawDataCoreService {
required int endTime,
int readChunkDays = defaultReadChunkDays,
}) async {
return _fetchRawDataInChunks(
final stopwatch = Stopwatch()..start();
final points = await _fetchRawDataInChunks(
dataType,
startTime,
endTime,
readChunkDays: readChunkDays,
);
_logInfo(
'$_hrvTrendLogMarker core_query_raw_data_finish '
'userId=$_userId dataType=$dataType startTime=$startTime '
'endTime=$endTime readChunkDays=$readChunkDays '
'count=${points.length} elapsedMs=${stopwatch.elapsedMilliseconds}',
);
return points;
}
Future<List<HealthKitRawDataPoint>> queryRawSleepIntervals({
... ... @@ -1189,21 +1231,23 @@ class OHOSHealthRawDataCoreService {
}
}
Future<List<OhosHealthRawDataSyncResult>> _syncCalculationRawDataIfNeeded({
Future<OhosHealthRawDataCalculationSyncSnapshot?>
_syncCalculationRawDataIfNeeded({
required int? startTime,
required int endTime,
}) async {
final rawDataSource = _rawDataSource;
if (rawDataSource is! OhosHealthRawDataSource) {
return const <OhosHealthRawDataSyncResult>[];
return null;
}
return rawDataSource.syncCalculationRawData(
return rawDataSource.syncCalculationRawDataSnapshot(
startTime: startTime,
endTime: endTime,
);
}
Future<List<OhosHealthRawDataSyncResult>> _syncCalculationRawDataSafely({
Future<OhosHealthRawDataCalculationSyncSnapshot?>
_syncCalculationRawDataSafely({
required bool hasAuthorization,
required int? startTime,
required int endTime,
... ... @@ -1213,7 +1257,7 @@ class OHOSHealthRawDataCoreService {
'$_calculateLogMarker sync_skipped reason=no_health_privacy_permission '
'startTime=$startTime endTime=$endTime',
);
return const <OhosHealthRawDataSyncResult>[];
return null;
}
try {
return await _syncCalculationRawDataIfNeeded(
... ... @@ -1573,6 +1617,35 @@ class OHOSHealthRawDataCoreService {
return points;
}
Future<List<HealthKitRawDataPoint>> _fetchRawDataForCalculation(
int dataType,
int startTime,
int endTime, {
required OhosHealthRawDataMemorySnapshot? rawDataSnapshot,
required int readChunkDays,
}) async {
final rawDataSource = _rawDataSource;
if (rawDataSnapshot != null && rawDataSource is OhosHealthRawDataSource) {
final points = rawDataSource.getRawDataFromSnapshot(
snapshot: rawDataSnapshot,
dataType: dataType,
startTime: startTime,
endTime: endTime,
)..sort((a, b) => a.endTime.compareTo(b.endTime));
_logInfo(
'$_calculateLogMarker raw_snapshot_hit dataType=$dataType '
'startTime=$startTime endTime=$endTime count=${points.length}',
);
return points;
}
return _fetchRawDataInChunks(
dataType,
startTime,
endTime,
readChunkDays: readChunkDays,
);
}
Future<List<HealthKitRawDataPoint>> _fetchSleepIntervalsInChunks(
int startTime,
int endTime, {
... ... @@ -1590,6 +1663,32 @@ class OHOSHealthRawDataCoreService {
return points;
}
Future<List<HealthKitRawDataPoint>> _fetchSleepIntervalsForCalculation(
int startTime,
int endTime, {
required OhosHealthRawDataMemorySnapshot? rawDataSnapshot,
required int readChunkDays,
}) async {
final rawDataSource = _rawDataSource;
if (rawDataSnapshot != null && rawDataSource is OhosHealthRawDataSource) {
final points = rawDataSource.getRawSleepIntervalsFromSnapshot(
snapshot: rawDataSnapshot,
startTime: startTime,
endTime: endTime,
)..sort((a, b) => a.endTime.compareTo(b.endTime));
_logInfo(
'$_calculateLogMarker sleep_snapshot_hit '
'startTime=$startTime endTime=$endTime count=${points.length}',
);
return points;
}
return _fetchSleepIntervalsInChunks(
startTime,
endTime,
readChunkDays: readChunkDays,
);
}
Future<List<HealthKitRawWorkoutDataPoint>> _fetchWorkoutIntervalsInChunks(
int startTime,
int endTime, {
... ... @@ -1607,6 +1706,33 @@ class OHOSHealthRawDataCoreService {
return points;
}
Future<List<HealthKitRawWorkoutDataPoint>>
_fetchWorkoutIntervalsForCalculation(
int startTime,
int endTime, {
required OhosHealthRawDataMemorySnapshot? rawDataSnapshot,
required int readChunkDays,
}) async {
final rawDataSource = _rawDataSource;
if (rawDataSnapshot != null && rawDataSource is OhosHealthRawDataSource) {
final points = rawDataSource.getRawWorkoutDataFromSnapshot(
snapshot: rawDataSnapshot,
startTime: startTime,
endTime: endTime,
)..sort((a, b) => a.endTime.compareTo(b.endTime));
_logInfo(
'$_calculateLogMarker workout_snapshot_hit '
'startTime=$startTime endTime=$endTime count=${points.length}',
);
return points;
}
return _fetchWorkoutIntervalsInChunks(
startTime,
endTime,
readChunkDays: readChunkDays,
);
}
static int? _minNullable(int? a, int? b) {
if (a == null) return b;
if (b == null) return a;
... ... @@ -1628,13 +1754,15 @@ class OHOSHealthRawDataCoreService {
}) {
if (!_isDebug) return;
_toastSink?.call(
'【测试】本轮同步耗时${_elapsedSecondsText(syncElapsed)} s、'
'【测试】获取数据耗时${_elapsedSecondsText(syncElapsed)} s、'
'计算耗时${_elapsedSecondsText(calculationElapsed)} s',
);
}
bool _hasStoredRawData(List<OhosHealthRawDataSyncResult> syncResults) {
return syncResults.any((result) => result.storedCount > 0);
bool _hasFetchedRawData(List<OhosHealthRawDataSyncResult> syncResults) {
return syncResults.any(
(result) => result.fetchedCount > 0 || result.storedCount > 0,
);
}
bool _hasCalculatedResult(HealthRawStressCalculationResult result) {
... ...
... ... @@ -24,6 +24,7 @@ class OhosHealthRawDataSqliteStore implements OhosHealthRawDataLocalStore {
static const sleepDataTable = 'ohos_sleep_data';
static const activityGoalTable = 'ohos_activity_goal';
static const logMarker = '[OHOS_RAW_DATA_DB]';
static const hrvTrendLogMarker = '[OHOS_HRV_TREND_PROFILE]';
final int Function()? _userIdProvider;
final Directory? _rootDirectory;
... ... @@ -282,6 +283,7 @@ class OhosHealthRawDataSqliteStore implements OhosHealthRawDataLocalStore {
required int startTime,
required int endTime,
}) async {
final stopwatch = Stopwatch()..start();
final db = await _database(_userId);
if (dataType == OhosHealthRawDataType.sleepAnalysis) {
final rows = await db.query(
... ... @@ -290,7 +292,13 @@ class OhosHealthRawDataSqliteStore implements OhosHealthRawDataLocalStore {
whereArgs: [startTime, endTime],
orderBy: 'from_time ASC',
);
return rows.map(_sleepItemFromRow).toList(growable: false);
final items = rows.map(_sleepItemFromRow).toList(growable: false);
_log(
'$hrvTrendLogMarker raw_db_query_finish dataType=$dataType '
'startTime=$startTime endTime=$endTime rows=${rows.length} '
'elapsedMs=${stopwatch.elapsedMilliseconds}',
);
return items;
}
if (dataType == OhosHealthRawDataType.workout) {
final table = _rawDataTable(dataType);
... ... @@ -301,9 +309,15 @@ class OhosHealthRawDataSqliteStore implements OhosHealthRawDataLocalStore {
whereArgs: [startTime, endTime],
orderBy: 'from_time ASC',
);
return rows
final items = rows
.map((row) => _intervalItemFromRow(row, dataType))
.toList(growable: false);
_log(
'$hrvTrendLogMarker raw_db_query_finish dataType=$dataType '
'table=$table startTime=$startTime endTime=$endTime '
'rows=${rows.length} elapsedMs=${stopwatch.elapsedMilliseconds}',
);
return items;
}
final storedDataType = _storedHealthDataType(dataType);
... ... @@ -315,9 +329,16 @@ class OhosHealthRawDataSqliteStore implements OhosHealthRawDataLocalStore {
whereArgs: [startTime, endTime],
orderBy: 'time ASC',
);
return rows
final items = rows
.map((row) => _rawItemFromRow(row, storedDataType))
.toList(growable: false);
_log(
'$hrvTrendLogMarker raw_db_query_finish dataType=$dataType '
'storedDataType=$storedDataType table=$table startTime=$startTime '
'endTime=$endTime rows=${rows.length} '
'elapsedMs=${stopwatch.elapsedMilliseconds}',
);
return items;
}
@override
... ...
part of 'ohos_health_raw_data_sync_service.dart';
class OhosHealthRawDataMemorySnapshot {
OhosHealthRawDataMemorySnapshot({
required Iterable<OhosHealthRawDataSyncResult> results,
}) {
for (final result in results) {
for (final item in result.rawItems) {
_itemCount += 1;
_add(result.dataType, item);
if (item.dataType != result.dataType) {
_add(item.dataType, item);
}
}
}
for (final items in _itemsByDataType.values) {
items.sort((a, b) => _itemEndTime(a).compareTo(_itemEndTime(b)));
}
}
final Map<int, List<OhosHealthRawDataItem>> _itemsByDataType =
<int, List<OhosHealthRawDataItem>>{};
var _itemCount = 0;
void _add(int dataType, OhosHealthRawDataItem item) {
_itemsByDataType
.putIfAbsent(dataType, () => <OhosHealthRawDataItem>[])
.add(item);
}
bool get isEmpty => _itemsByDataType.values.every((items) => items.isEmpty);
int get length => _itemCount;
List<OhosHealthRawDataItem> query({
required int dataType,
required int startTime,
required int endTime,
}) {
final items = _itemsByDataType[dataType];
if (items == null || items.isEmpty) return const <OhosHealthRawDataItem>[];
return items
.where(
(item) =>
_itemEndTime(item) >= startTime &&
_itemStartTime(item) <= endTime,
)
.toList(growable: false);
}
int? earliestTime() {
int? earliest;
for (final items in _itemsByDataType.values) {
for (final item in items) {
final time = _dedupeKeyTime(item);
earliest = earliest == null ? time : math.min(earliest, time);
}
}
return earliest;
}
static int _itemStartTime(OhosHealthRawDataItem item) {
return _numPayload(item.payload, 'from_time') ??
_numPayload(item.payload, 'start_time') ??
item.dataTime;
}
static int _itemEndTime(OhosHealthRawDataItem item) {
return _numPayload(item.payload, 'to_time') ??
_numPayload(item.payload, 'end_time') ??
_numPayload(item.payload, 'time') ??
item.dataTime;
}
static int _dedupeKeyTime(OhosHealthRawDataItem item) {
return _numPayload(item.payload, 'from_time') ??
_numPayload(item.payload, 'start_time') ??
_numPayload(item.payload, 'time') ??
item.dataTime;
}
static int? _numPayload(Map<String, Object?> payload, String key) {
final value = payload[key];
return value is num ? value.toInt() : null;
}
}
class OhosHealthRawDataCalculationSyncSnapshot {
const OhosHealthRawDataCalculationSyncSnapshot({
required this.results,
required this.rawData,
this.activityGoal,
this.storeFuture,
});
final List<OhosHealthRawDataSyncResult> results;
final OhosHealthRawDataMemorySnapshot rawData;
final V2ActivityTarget? activityGoal;
final Future<void>? storeFuture;
}
... ...
... ... @@ -16,6 +16,8 @@ import 'package:flutter/foundation.dart';
import 'huawei_health_data_type.dart';
import 'ohos_health_raw_data_events.dart';
part 'ohos_health_raw_data_memory_snapshot.dart';
class OhosHealthRawDataType {
const OhosHealthRawDataType._();
... ... @@ -44,6 +46,8 @@ class OhosHealthRawDataSyncService {
static const int defaultMaxConcurrentFetches = 10;
static const String logMarker = '[OHOS_HEALTH_RAW_SYNC]';
static const String profileLogMarker = '[OHOS_HEALTH_RAW_PROFILE]';
static const String timingLogMarker = '[OHOS_HEALTH_TIMING]';
static const String hrvTrendLogMarker = '[OHOS_HRV_TREND_PROFILE]';
static final List<int> calculationDataTypes = List<int>.unmodifiable(
<int>[
for (final type in HuaweiHealthDataType.values) type.dataType,
... ... @@ -257,6 +261,130 @@ class OhosHealthRawDataSyncService {
return results;
}
Future<OhosHealthRawDataCalculationSyncSnapshot>
syncCalculationRawDataSnapshot({
int? startTime,
int? endTime,
List<int>? dataTypes,
}) async {
final totalStopwatch = Stopwatch()..start();
final resolvedEndTime = endTime ?? _unixSeconds(_nowProvider());
final earliestStartTime = _twoMonthLookbackStart(resolvedEndTime);
final eventStartTime = startTime == null
? earliestStartTime
: math.max(startTime, earliestStartTime);
final resolvedDataTypes = dataTypes ?? calculationDataTypes;
_log(
'calculation_sync_snapshot_start '
'dataTypes=${resolvedDataTypes.join(',')} '
'startTime=${startTime ?? ''} endTime=$resolvedEndTime',
);
_publishSyncEvent(
type: OhosHealthRawDataPipelineEventType.syncStarted,
flow: 'syncCalculationRawDataSnapshot',
dataTypes: resolvedDataTypes,
startTime: eventStartTime,
endTime: resolvedEndTime,
);
try {
final activityGoalFuture = _fetchActivityGoalForCalculationSync();
final rawSyncFuture = Future.wait(
resolvedDataTypes.map(
(dataType) => _syncRawDataForCalculationSnapshot(
dataType: dataType,
startTime: startTime,
endTime: resolvedEndTime,
),
),
eagerError: true,
);
final fetched = await Future.wait<Object?>(
<Future<Object?>>[
activityGoalFuture,
rawSyncFuture,
],
eagerError: true,
);
final activityGoal = fetched[0] as V2ActivityTarget?;
final results = fetched[1] as List<OhosHealthRawDataSyncResult>;
final rawData = OhosHealthRawDataMemorySnapshot(
results: results,
);
final pageCount = results.fold<int>(
0,
(sum, result) => sum + result.pageCount,
);
final fetchedCount = results.fold<int>(
0,
(sum, result) => sum + result.fetchedCount,
);
final storeFuture = _storeCalculationSnapshotInBackground(
results: results,
activityGoal: activityGoal,
);
unawaited(
storeFuture.catchError((Object error, StackTrace stackTrace) {
_log(
'$timingLogMarker db_store_failed '
'dataTypes=${resolvedDataTypes.join(',')} '
'error=${_describeError(error)} stackTrace=$stackTrace',
);
}),
);
_log(
'calculation_sync_snapshot_finish '
'dataTypes=${resolvedDataTypes.join(',')} '
'pageCount=$pageCount fetchedCount=$fetchedCount '
'snapshotCount=${rawData.length}',
);
_log(
'$timingLogMarker fetch_all_finish '
'dataTypes=${resolvedDataTypes.join(',')} '
'pageCount=$pageCount fetchedCount=$fetchedCount '
'elapsedMs=${totalStopwatch.elapsedMilliseconds}',
);
_publishSyncEvent(
type: OhosHealthRawDataPipelineEventType.syncSucceeded,
flow: 'syncCalculationRawDataSnapshot',
dataTypes: resolvedDataTypes,
startTime: eventStartTime,
endTime: resolvedEndTime,
elapsedMs: totalStopwatch.elapsedMilliseconds,
pageCount: pageCount,
storedCount: 0,
);
return OhosHealthRawDataCalculationSyncSnapshot(
results: results,
rawData: rawData,
activityGoal: activityGoal,
storeFuture: storeFuture,
);
} catch (error, stackTrace) {
_log(
'calculation_sync_snapshot_failed '
'dataTypes=${resolvedDataTypes.join(',')} '
'startTime=${startTime ?? ''} endTime=$resolvedEndTime '
'error=${_describeError(error)} stackTrace=$stackTrace',
);
_profileLog(
'calculationSync_fetchAll_failed '
'dataTypes=${resolvedDataTypes.join(',')} '
'elapsedMs=${totalStopwatch.elapsedMilliseconds} '
'error=${_describeError(error)}',
);
_publishSyncEvent(
type: OhosHealthRawDataPipelineEventType.syncFailed,
flow: 'syncCalculationRawDataSnapshot',
dataTypes: resolvedDataTypes,
startTime: eventStartTime,
endTime: resolvedEndTime,
elapsedMs: totalStopwatch.elapsedMilliseconds,
error: _describeError(error),
);
rethrow;
}
}
Future<V2ActivityTarget?> _fetchActivityGoalForCalculationSync() async {
final stopwatch = Stopwatch()..start();
try {
... ... @@ -339,16 +467,66 @@ class OhosHealthRawDataSyncService {
}
}
Future<OhosHealthRawDataSyncResult> _syncRawDataForCalculationSnapshot({
required int dataType,
required int? startTime,
required int endTime,
}) async {
final stopwatch = Stopwatch()..start();
final resolvedStartTime = await _resolveStartTime(
dataType: dataType,
requestedStartTime: startTime,
endTime: endTime,
);
if (endTime < resolvedStartTime) {
throw ArgumentError.value(endTime, 'endTime');
}
_profileLog(
'fetchRawDataSnapshot_resolved dataType=$dataType '
'requestedStartTime=${startTime ?? ''} startTime=$resolvedStartTime '
'endTime=$endTime resolveElapsedMs=${stopwatch.elapsedMilliseconds}',
);
try {
final result = await _syncResolvedRawData(
dataType: dataType,
startTime: resolvedStartTime,
endTime: endTime,
storeRawData: false,
);
_profileLog(
'fetchRawDataSnapshot_finish dataType=$dataType '
'segments=${result.segmentCount} pageCount=${result.pageCount} '
'fetchedCount=${result.fetchedCount} '
'elapsedMs=${stopwatch.elapsedMilliseconds}',
);
return result;
} catch (error) {
_profileLog(
'fetchRawDataSnapshot_failed dataType=$dataType '
'elapsedMs=${stopwatch.elapsedMilliseconds} '
'error=${_describeError(error)}',
);
rethrow;
}
}
Future<List<OhosHealthRawDataItem>> queryRawData({
required int dataType,
required int startTime,
required int endTime,
}) {
return _localStore.queryRawData(
}) async {
final stopwatch = Stopwatch()..start();
final items = await _localStore.queryRawData(
dataType: dataType,
startTime: startTime,
endTime: endTime,
);
_log(
'$hrvTrendLogMarker sync_query_raw_finish '
'dataType=$dataType startTime=$startTime endTime=$endTime '
'count=${items.length} elapsedMs=${stopwatch.elapsedMilliseconds}',
);
return items;
}
Future<V2ActivityTarget?> getActivityGoal({bool refresh = true}) async {
... ... @@ -385,6 +563,7 @@ class OhosHealthRawDataSyncService {
required int startTime,
required int endTime,
Future<void>? storeGate,
bool storeRawData = true,
}) async {
final stopwatch = Stopwatch()..start();
final fetchRanges = _splitIntoFetchRanges(
... ... @@ -415,6 +594,7 @@ class OhosHealthRawDataSyncService {
var fetchedItems = 0;
var storedCount = 0;
int? earliestStoredTime;
final rawItems = <OhosHealthRawDataItem>[];
try {
while (pending.isNotEmpty) {
final outcome = await Future.any(pending);
... ... @@ -428,34 +608,37 @@ class OhosHealthRawDataSyncService {
final page = segment.page;
pageCount += 1;
fetchedItems += page.items.length;
rawItems.addAll(page.items);
if (page.items.isNotEmpty) {
if (storeGate != null) await storeGate;
final pageStoreStopwatch = Stopwatch()..start();
final pageStoredCount = await _localStore.upsertRawDataBatch(
dataType: dataType,
items: page.items,
);
storedCount += pageStoredCount;
if (pageStoredCount > 0) {
for (final item in page.items) {
final keyTime = _dedupeKeyTime(dataType: dataType, item: item);
earliestStoredTime = earliestStoredTime == null
? keyTime
: math.min(earliestStoredTime, keyTime);
if (storeRawData) {
if (storeGate != null) await storeGate;
final pageStoreStopwatch = Stopwatch()..start();
final pageStoredCount = await _localStore.upsertRawDataBatch(
dataType: dataType,
items: page.items,
);
storedCount += pageStoredCount;
if (pageStoredCount > 0) {
for (final item in page.items) {
final keyTime = _dedupeKeyTime(dataType: dataType, item: item);
earliestStoredTime = earliestStoredTime == null
? keyTime
: math.min(earliestStoredTime, keyTime);
}
}
_profileLog(
'page_store_finish dataType=$dataType '
'segment=${segment.segmentIndex + 1}/${fetchRanges.length} '
'fetchedItems=${page.items.length} storedItems=$pageStoredCount '
'elapsedMs=${pageStoreStopwatch.elapsedMilliseconds}',
);
_log(
'page_stored dataType=$dataType '
'segment=${segment.segmentIndex + 1}/${fetchRanges.length} '
'fetchedItems=${page.items.length} '
'storedItems=$pageStoredCount totalStored=$storedCount',
);
}
_profileLog(
'page_store_finish dataType=$dataType '
'segment=${segment.segmentIndex + 1}/${fetchRanges.length} '
'fetchedItems=${page.items.length} storedItems=$pageStoredCount '
'elapsedMs=${pageStoreStopwatch.elapsedMilliseconds}',
);
_log(
'page_stored dataType=$dataType '
'segment=${segment.segmentIndex + 1}/${fetchRanges.length} '
'fetchedItems=${page.items.length} '
'storedItems=$pageStoredCount totalStored=$storedCount',
);
}
_log(
... ... @@ -500,6 +683,43 @@ class OhosHealthRawDataSyncService {
pageCount: pageCount,
storedCount: storedCount,
earliestStoredTime: earliestStoredTime,
fetchedCount: fetchedItems,
rawItems: List<OhosHealthRawDataItem>.unmodifiable(rawItems),
);
}
Future<void> _storeCalculationSnapshotInBackground({
required List<OhosHealthRawDataSyncResult> results,
required V2ActivityTarget? activityGoal,
}) async {
final stopwatch = Stopwatch()..start();
var storedCount = 0;
if (activityGoal != null) {
final goalStopwatch = Stopwatch()..start();
await _localStore.upsertActivityGoal(activityGoal);
_log(
'$timingLogMarker db_store_activity_goal_finish '
'elapsedMs=${goalStopwatch.elapsedMilliseconds}',
);
}
for (final result in results) {
if (result.rawItems.isEmpty) continue;
final typeStopwatch = Stopwatch()..start();
final count = await _localStore.upsertRawDataBatch(
dataType: result.dataType,
items: result.rawItems,
);
storedCount += count;
_log(
'$timingLogMarker db_store_type_finish '
'dataType=${result.dataType} fetched=${result.rawItems.length} '
'stored=$count elapsedMs=${typeStopwatch.elapsedMilliseconds}',
);
}
_log(
'$timingLogMarker db_store_finish '
'dataTypes=${results.map((result) => result.dataType).join(',')} '
'storedCount=$storedCount elapsedMs=${stopwatch.elapsedMilliseconds}',
);
}
... ... @@ -1022,6 +1242,8 @@ class OhosHealthRawDataSyncResult {
required this.pageCount,
required this.storedCount,
this.earliestStoredTime,
this.fetchedCount = 0,
this.rawItems = const <OhosHealthRawDataItem>[],
});
final int dataType;
... ... @@ -1031,6 +1253,8 @@ class OhosHealthRawDataSyncResult {
final int pageCount;
final int storedCount;
final int? earliestStoredTime;
final int fetchedCount;
final List<OhosHealthRawDataItem> rawItems;
@override
String toString() {
... ... @@ -1041,6 +1265,7 @@ class OhosHealthRawDataSyncResult {
'segmentCount=$segmentCount, '
'pageCount=$pageCount, '
'storedCount=$storedCount, '
'fetchedCount=$fetchedCount, '
'earliestStoredTime=$earliestStoredTime'
')';
}
... ...
... ... @@ -4,6 +4,7 @@ import 'package:doublefeel_flutter/data/models/health/activity/activity_burn_sta
import 'package:doublefeel_flutter/data/models/health/health_v2_models.dart';
import 'package:doublefeel_flutter/data/models/health/hrv/hrv_statistics_data.dart';
import 'package:doublefeel_flutter/data/models/health/sleep/sleep_statistics_data.dart';
import 'package:flutter/foundation.dart';
import 'package:get/get_core/src/get_main.dart';
import 'package:get/get_instance/src/extension_instance.dart';
... ... @@ -19,6 +20,7 @@ class HealthDataSourceWrapper implements HealthDataSource {
final HealthDataSource remoteDataSource;
final HealthDataSource localDataSource;
final _myUserId = Get.find<UserStateService>().userId;
static const _hrvTrendLogMarker = '[OHOS_HRV_TREND_PROFILE]';
@override
Future<AppResult<SleepStatisticsData>> getSleepStatistics(
... ... @@ -60,17 +62,31 @@ class HealthDataSourceWrapper implements HealthDataSource {
int dateRangeType,
int startDate, {
int? queryUserId,
}) {
}) async {
final stopwatch = Stopwatch()..start();
HealthDataSource dataSource = remoteDataSource;
if (queryUserId == null || _myUserId == queryUserId) {
dataSource = localDataSource;
}
final sourceName =
identical(dataSource, localDataSource) ? 'local' : 'remote';
_logHrvTrend(
'wrapper_getHrvStatistics_start source=$sourceName '
'dateRangeType=$dateRangeType startDate=$startDate '
'queryUserId=$queryUserId myUserId=$_myUserId',
);
return dataSource.getHrvStatistics(
final result = await dataSource.getHrvStatistics(
dateRangeType,
startDate,
queryUserId: queryUserId,
);
_logHrvTrend(
'wrapper_getHrvStatistics_finish source=$sourceName '
'success=${result is AppSuccess} '
'elapsedMs=${stopwatch.elapsedMilliseconds}',
);
return result;
}
@override
... ... @@ -143,4 +159,8 @@ class HealthDataSourceWrapper implements HealthDataSource {
return dataSource.getV2StressScore(queryUserId, intDate);
}
void _logHrvTrend(String message) {
debugPrint('$_hrvTrendLogMarker $message');
}
}
... ...
... ... @@ -23,6 +23,7 @@ class LocalHealthDataSource implements HealthDataSource {
static const int _ohosDefaultStandGoal = 12;
static const int _ohosDefaultExerciseGoalSeconds = 30 * 60;
static const int _ohosDefaultSleepTargetSeconds = 8 * 60 * 60;
static const String _hrvTrendLogMarker = '[OHOS_HRV_TREND_PROFILE]';
@override
Future<AppResult<SleepStatisticsData>> getSleepStatistics(
... ... @@ -130,7 +131,12 @@ class LocalHealthDataSource implements HealthDataSource {
int startDate, {
int? queryUserId,
}) async {
final totalStopwatch = Stopwatch()..start();
try {
_hrvTrendLog(
'local_statistics_start dateRangeType=$dateRangeType '
'startDate=$startDate queryUserId=$queryUserId',
);
final days = LocalHealthDataConvert.rangeDays(dateRangeType, startDate);
if (days.isEmpty) return AppSuccess(HrvStatisticsDataV2());
... ... @@ -138,36 +144,84 @@ class LocalHealthDataSource implements HealthDataSource {
dateRangeType,
startDate,
);
_hrvTrendLog(
'local_statistics_range_finish dateRangeType=$dateRangeType '
'days=${days.length} previousDays=${previousDays.length} '
'elapsedMs=${totalStopwatch.elapsedMilliseconds}',
);
final hrvQueryStart = LocalHealthDataConvert.unixSeconds(days.first);
final hrvQueryEnd = LocalHealthDataConvert.unixSeconds(
days.last.add(const Duration(days: 1)),
);
final dailyQueryStart = LocalHealthDataConvert.dateKey(
previousDays.isEmpty ? days.first : previousDays.first,
);
final dailyQueryEnd = LocalHealthDataConvert.dateKey(days.last);
final hrvStopwatch = Stopwatch()..start();
final hrvPoints = await coreService.queryHrvStressPoints(
startTime: LocalHealthDataConvert.unixSeconds(days.first),
endTime: LocalHealthDataConvert.unixSeconds(
days.last.add(const Duration(days: 1)),
),
startTime: hrvQueryStart,
endTime: hrvQueryEnd,
);
_hrvTrendLog(
'local_query_hrv_results_finish startTime=$hrvQueryStart '
'endTime=$hrvQueryEnd count=${hrvPoints.length} '
'elapsedMs=${hrvStopwatch.elapsedMilliseconds}',
);
final dailyStopwatch = Stopwatch()..start();
final dailyStressPoints = await coreService.queryDailyStressPoints(
startDate: LocalHealthDataConvert.dateKey(
previousDays.isEmpty ? days.first : previousDays.first),
endDate: LocalHealthDataConvert.dateKey(days.last),
startDate: dailyQueryStart,
endDate: dailyQueryEnd,
);
_hrvTrendLog(
'local_query_daily_stress_finish startDate=$dailyQueryStart '
'endDate=$dailyQueryEnd count=${dailyStressPoints.length} '
'elapsedMs=${dailyStopwatch.elapsedMilliseconds}',
);
final restingHrStopwatch = Stopwatch()..start();
final restingHeartRate = await coreService.queryRawDataPoints(
dataType: HealthDataUploadType.restingHeartRate.type,
startTime: LocalHealthDataConvert.unixSeconds(days.first),
endTime: LocalHealthDataConvert.unixSeconds(
days.last.add(const Duration(days: 1)),
),
startTime: hrvQueryStart,
endTime: hrvQueryEnd,
);
_hrvTrendLog(
'local_query_resting_hr_finish dataType='
'${HealthDataUploadType.restingHeartRate.type} '
'startTime=$hrvQueryStart endTime=$hrvQueryEnd '
'count=${restingHeartRate.length} '
'elapsedMs=${restingHrStopwatch.elapsedMilliseconds}',
);
final convertStopwatch = Stopwatch()..start();
final statistics = LocalHealthDataConvert.hrvStatistics(
dateRangeType: dateRangeType,
days: days,
previousDays: previousDays,
hrvPoints: hrvPoints,
dailyStressPoints: dailyStressPoints,
restingHeartRate: restingHeartRate,
);
_hrvTrendLog(
'local_convert_finish trendCount='
'${statistics.hrvTrendList?.length ?? 0} '
'distributionCount=${statistics.hrvDistributionList?.length ?? 0} '
'elapsedMs=${convertStopwatch.elapsedMilliseconds}',
);
_hrvTrendLog(
'local_statistics_finish dateRangeType=$dateRangeType '
'elapsedMs=${totalStopwatch.elapsedMilliseconds}',
);
return AppSuccess(
LocalHealthDataConvert.hrvStatistics(
dateRangeType: dateRangeType,
days: days,
previousDays: previousDays,
hrvPoints: hrvPoints,
dailyStressPoints: dailyStressPoints,
restingHeartRate: restingHeartRate,
),
statistics,
);
} catch (error) {
_hrvTrendLog(
'local_statistics_failed dateRangeType=$dateRangeType '
'startDate=$startDate elapsedMs=${totalStopwatch.elapsedMilliseconds} '
'error=$error',
);
return AppFailure(AppUnknownError(error));
}
}
... ... @@ -433,6 +487,10 @@ class LocalHealthDataSource implements HealthDataSource {
bool get _isOhosPlatform => defaultTargetPlatform.name == 'ohos';
void _hrvTrendLog(String message) {
debugPrint('$_hrvTrendLogMarker $message');
}
Future<List<HealthKitRawActivityDataPoint>>
_resolveOhosActivityGoalsIfNeeded({
required List<HealthKitRawActivityDataPoint> activity,
... ...
... ... @@ -6,7 +6,7 @@ packages:
description:
name: _fe_analyzer_shared
sha256: da0d9209ca76bde579f2da330aeb9df62b6319c834fa7baae052021b0462401f
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "85.0.0"
analyzer:
... ... @@ -14,7 +14,7 @@ packages:
description:
name: analyzer
sha256: "974859dc0ff5f37bc4313244b3218c791810d03ab3470a579580279ba971a48d"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "7.7.1"
archive:
... ... @@ -22,7 +22,7 @@ packages:
description:
name: archive
sha256: ace891da0862b0e4cabbb064ee3fd87b2728b898949fdb366d83fe98342c9f19
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "4.2.0"
args:
... ... @@ -30,7 +30,7 @@ packages:
description:
name: args
sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.7.0"
async:
... ... @@ -38,7 +38,7 @@ packages:
description:
name: async
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.11.0"
boolean_selector:
... ... @@ -46,7 +46,7 @@ packages:
description:
name: boolean_selector
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
build:
... ... @@ -54,7 +54,7 @@ packages:
description:
name: build
sha256: cef23f1eda9b57566c81e2133d196f8e3df48f244b317368d65c5943d91148f0
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.4.2"
build_config:
... ... @@ -62,7 +62,7 @@ packages:
description:
name: build_config
sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "1.1.2"
build_daemon:
... ... @@ -70,7 +70,7 @@ packages:
description:
name: build_daemon
sha256: "8e928697a82be082206edb0b9c99c5a4ad6bc31c9e9b8b2f291ae65cd4a25daa"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "4.0.4"
build_resolvers:
... ... @@ -78,7 +78,7 @@ packages:
description:
name: build_resolvers
sha256: b9e4fda21d846e192628e7a4f6deda6888c36b5b69ba02ff291a01fd529140f0
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.4.4"
build_runner:
... ... @@ -86,7 +86,7 @@ packages:
description:
name: build_runner
sha256: "058fe9dce1de7d69c4b84fada934df3e0153dd000758c4d65964d0166779aa99"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.4.15"
build_runner_core:
... ... @@ -94,7 +94,7 @@ packages:
description:
name: build_runner_core
sha256: "22e3aa1c80e0ada3722fe5b63fd43d9c8990759d0a2cf489c8c5d7b2bdebc021"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "8.0.0"
built_collection:
... ... @@ -102,7 +102,7 @@ packages:
description:
name: built_collection
sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "5.1.1"
built_value:
... ... @@ -110,7 +110,7 @@ packages:
description:
name: built_value
sha256: f87ea98192116f7093cb214551ce1929caae0681fdba282b3d8b4462adee7bb7
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "8.13.0"
cached_network_image:
... ... @@ -118,7 +118,7 @@ packages:
description:
name: cached_network_image
sha256: "7c1183e361e5c8b0a0f21a28401eecdbde252441106a9816400dd4c2b2424916"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "3.4.1"
cached_network_image_platform_interface:
... ... @@ -126,7 +126,7 @@ packages:
description:
name: cached_network_image_platform_interface
sha256: "35814b016e37fbdc91f7ae18c8caf49ba5c88501813f73ce8a07027a395e2829"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "4.1.1"
cached_network_image_web:
... ... @@ -134,7 +134,7 @@ packages:
description:
name: cached_network_image_web
sha256: "980842f4e8e2535b8dbd3d5ca0b1f0ba66bf61d14cc3a17a9b4788a3685ba062"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "1.3.1"
characters:
... ... @@ -142,7 +142,7 @@ packages:
description:
name: characters
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "1.3.0"
checked_yaml:
... ... @@ -150,7 +150,7 @@ packages:
description:
name: checked_yaml
sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.0.3"
clock:
... ... @@ -158,7 +158,7 @@ packages:
description:
name: clock
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "1.1.1"
code_builder:
... ... @@ -166,7 +166,7 @@ packages:
description:
name: code_builder
sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "4.10.1"
collection:
... ... @@ -174,7 +174,7 @@ packages:
description:
name: collection
sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "1.19.0"
convert:
... ... @@ -182,7 +182,7 @@ packages:
description:
name: convert
sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "3.1.2"
cross_file:
... ... @@ -190,7 +190,7 @@ packages:
description:
name: cross_file
sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "0.3.4+2"
crypto:
... ... @@ -198,7 +198,7 @@ packages:
description:
name: crypto
sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "3.0.7"
cupertino_icons:
... ... @@ -206,7 +206,7 @@ packages:
description:
name: cupertino_icons
sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "1.0.8"
dart_style:
... ... @@ -214,7 +214,7 @@ packages:
description:
name: dart_style
sha256: "27eb0ae77836989a3bc541ce55595e8ceee0992807f14511552a898ddd0d88ac"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
dio:
... ... @@ -222,7 +222,7 @@ packages:
description:
name: dio
sha256: "852ec3b48cc431ac04fff978413c541502b67ffc3e26921e74e3d994694192c1"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "5.11.1"
dio_web_adapter:
... ... @@ -230,7 +230,7 @@ packages:
description:
name: dio_web_adapter
sha256: "3a1b2cd7be71086f38504956e3ebcd2837288d231ff454bafa78021244102bfc"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.2.2"
equatable:
... ... @@ -238,7 +238,7 @@ packages:
description:
name: equatable
sha256: "3bce007a596ff8b3119c45d68aaef631272537c03d30e5d4534dd24bf4c5eaa2"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
fake_async:
... ... @@ -246,7 +246,7 @@ packages:
description:
name: fake_async
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "1.3.1"
ffi:
... ... @@ -254,7 +254,7 @@ packages:
description:
name: ffi
sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.1.3"
file:
... ... @@ -262,7 +262,7 @@ packages:
description:
name: file
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "7.0.1"
file_selector_linux:
... ... @@ -270,7 +270,7 @@ packages:
description:
name: file_selector_linux
sha256: "54cbbd957e1156d29548c7d9b9ec0c0ebb6de0a90452198683a7d23aed617a33"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "0.9.3+2"
file_selector_macos:
... ... @@ -278,7 +278,7 @@ packages:
description:
name: file_selector_macos
sha256: "8c9250b2bd2d8d4268e39c82543bacbaca0fda7d29e0728c3c4bbb7c820fd711"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "0.9.4+3"
file_selector_platform_interface:
... ... @@ -286,7 +286,7 @@ packages:
description:
name: file_selector_platform_interface
sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.6.2"
file_selector_windows:
... ... @@ -294,7 +294,7 @@ packages:
description:
name: file_selector_windows
sha256: "320fcfb6f33caa90f0b58380489fc5ac05d99ee94b61aa96ec2bff0ba81d3c2b"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "0.9.3+4"
fixnum:
... ... @@ -302,7 +302,7 @@ packages:
description:
name: fixnum
sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "1.1.1"
fl_chart:
... ... @@ -310,7 +310,7 @@ packages:
description:
name: fl_chart
sha256: "5276944c6ffc975ae796569a826c38a62d2abcf264e26b88fa6f482e107f4237"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "0.70.2"
flutter:
... ... @@ -323,7 +323,7 @@ packages:
description:
name: flutter_cache_manager
sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "3.4.1"
flutter_lints:
... ... @@ -331,7 +331,7 @@ packages:
description:
name: flutter_lints
sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "5.0.0"
flutter_localizations:
... ... @@ -344,7 +344,7 @@ packages:
description:
name: flutter_plugin_android_lifecycle
sha256: "6382ce712ff69b0f719640ce957559dde459e55ecd433c767e06d139ddf16cab"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.0.29"
flutter_test:
... ... @@ -357,7 +357,7 @@ packages:
description:
name: flutter_timezone
sha256: "869677426fde92dbe170fb7d2d4929f2a8343c2f5f62f08b0bb64f908630b073"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "5.1.0"
flutter_web_plugins:
... ... @@ -379,7 +379,7 @@ packages:
description:
name: frontend_server_client
sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "4.0.0"
get:
... ... @@ -387,7 +387,7 @@ packages:
description:
name: get
sha256: "5ed34a7925b85336e15d472cc4cfe7d9ebf4ab8e8b9f688585bf6b50f4c3d79a"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "4.7.3"
glob:
... ... @@ -395,7 +395,7 @@ packages:
description:
name: glob
sha256: "218aeb56050c714f62a3182775320dfa04602b55074873e24e31bbd39bda96fb"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.2.0"
graphs:
... ... @@ -403,7 +403,7 @@ packages:
description:
name: graphs
sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
http:
... ... @@ -411,7 +411,7 @@ packages:
description:
name: http
sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "1.6.0"
http_multi_server:
... ... @@ -419,7 +419,7 @@ packages:
description:
name: http_multi_server
sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "3.2.2"
http_parser:
... ... @@ -427,7 +427,7 @@ packages:
description:
name: http_parser
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "4.1.2"
image_cropper:
... ... @@ -471,7 +471,7 @@ packages:
description:
name: image_picker_android
sha256: e83b2b05141469c5e19d77e1dfa11096b6b1567d09065b2265d7c6904560050c
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "0.8.13"
image_picker_for_web:
... ... @@ -479,7 +479,7 @@ packages:
description:
name: image_picker_for_web
sha256: "40c2a6a0da15556dc0f8e38a3246064a971a9f512386c3339b89f76db87269b6"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "3.1.0"
image_picker_ios:
... ... @@ -487,7 +487,7 @@ packages:
description:
name: image_picker_ios
sha256: eb06fe30bab4c4497bad449b66448f50edcc695f1c59408e78aa3a8059eb8f0e
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "0.8.13"
image_picker_linux:
... ... @@ -495,7 +495,7 @@ packages:
description:
name: image_picker_linux
sha256: "1f81c5f2046b9ab724f85523e4af65be1d47b038160a8c8deed909762c308ed4"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "0.2.2"
image_picker_macos:
... ... @@ -503,7 +503,7 @@ packages:
description:
name: image_picker_macos
sha256: d58cd9d67793d52beefd6585b12050af0a7663c0c2a6ece0fb110a35d6955e04
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "0.2.2"
image_picker_ohos:
... ... @@ -520,7 +520,7 @@ packages:
description:
name: image_picker_platform_interface
sha256: "9f143b0dba3e459553209e20cc425c9801af48e6dfa4f01a0fcf927be3f41665"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.11.0"
image_picker_windows:
... ... @@ -528,7 +528,7 @@ packages:
description:
name: image_picker_windows
sha256: d248c86554a72b5495a31c56f060cf73a41c7ff541689327b1a7dbccc33adfae
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "0.2.2"
intl:
... ... @@ -536,7 +536,7 @@ packages:
description:
name: intl
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "0.19.0"
io:
... ... @@ -544,7 +544,7 @@ packages:
description:
name: io
sha256: "2635216ca6a737e60de577ffa1a48a0bec76ca8a62917cfc1bb88c14c570646f"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
js:
... ... @@ -552,7 +552,7 @@ packages:
description:
name: js
sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "0.7.1"
json_annotation:
... ... @@ -560,7 +560,7 @@ packages:
description:
name: json_annotation
sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "4.9.0"
leak_tracker:
... ... @@ -568,7 +568,7 @@ packages:
description:
name: leak_tracker
sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "10.0.7"
leak_tracker_flutter_testing:
... ... @@ -576,7 +576,7 @@ packages:
description:
name: leak_tracker_flutter_testing
sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "3.0.8"
leak_tracker_testing:
... ... @@ -584,7 +584,7 @@ packages:
description:
name: leak_tracker_testing
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
lints:
... ... @@ -592,23 +592,23 @@ packages:
description:
name: lints
sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "5.1.1"
logger:
dependency: "direct main"
description:
name: logger
sha256: "25aee487596a6257655a1e091ec2ae66bc30e7af663592cc3a27e6591e05035c"
url: "https://pub.flutter-io.cn"
sha256: "2a0dc097e7b01d942475bdd552356db2d0f768b05540bd4b2b53f1840f2239a7"
url: "https://pub.dev"
source: hosted
version: "2.7.0"
version: "2.8.0"
logging:
dependency: transitive
description:
name: logging
sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "1.3.0"
lottie:
... ... @@ -616,7 +616,7 @@ packages:
description:
name: lottie
sha256: c5fa04a80a620066c15cf19cc44773e19e9b38e989ff23ea32e5903ef1015950
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "3.3.1"
matcher:
... ... @@ -624,7 +624,7 @@ packages:
description:
name: matcher
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "0.12.16+1"
material_color_utilities:
... ... @@ -632,7 +632,7 @@ packages:
description:
name: material_color_utilities
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "0.11.1"
meta:
... ... @@ -640,7 +640,7 @@ packages:
description:
name: meta
sha256: "307249ce4ff29d58a18e97f6345f539382eb9c9c29ecda628900f31de0443dd9"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "1.19.0"
mime:
... ... @@ -648,7 +648,7 @@ packages:
description:
name: mime
sha256: bd47de35f07e27267e69c8c8b22edf9473bfee170a60d60fcc93730c5144b7f6
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
octo_image:
... ... @@ -656,7 +656,7 @@ packages:
description:
name: octo_image
sha256: "34faa6639a78c7e3cbe79be6f9f96535867e879748ade7d17c9b1ae7536293bd"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
package_config:
... ... @@ -664,7 +664,7 @@ packages:
description:
name: package_config
sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.2.0"
path:
... ... @@ -672,7 +672,7 @@ packages:
description:
name: path
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "1.9.0"
path_provider:
... ... @@ -689,7 +689,7 @@ packages:
description:
name: path_provider_android
sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.2.17"
path_provider_foundation:
... ... @@ -697,7 +697,7 @@ packages:
description:
name: path_provider_foundation
sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
path_provider_linux:
... ... @@ -705,7 +705,7 @@ packages:
description:
name: path_provider_linux
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.2.1"
path_provider_ohos:
... ... @@ -722,7 +722,7 @@ packages:
description:
name: path_provider_platform_interface
sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
path_provider_windows:
... ... @@ -730,7 +730,7 @@ packages:
description:
name: path_provider_windows
sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.3.0"
permission_handler:
... ... @@ -738,7 +738,7 @@ packages:
description:
name: permission_handler
sha256: "59adad729136f01ea9e35a48f5d1395e25cba6cea552249ddbe9cf950f5d7849"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "11.4.0"
permission_handler_android:
... ... @@ -746,7 +746,7 @@ packages:
description:
name: permission_handler_android
sha256: d3971dcdd76182a0c198c096b5db2f0884b0d4196723d21a866fc4cdea057ebc
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "12.1.0"
permission_handler_apple:
... ... @@ -754,7 +754,7 @@ packages:
description:
name: permission_handler_apple
sha256: f49cb15a064ea9d974fc7fbb302099353b7b170d07284e86e264561579e5bcf8
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "9.6.1"
permission_handler_html:
... ... @@ -762,7 +762,7 @@ packages:
description:
name: permission_handler_html
sha256: "6ea98b3f17f60d3b527f2647ed2ab4dc0f6bfe25b22cb1c363f5d8f62252f6ac"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "0.1.4+1"
permission_handler_ohos:
... ... @@ -778,16 +778,16 @@ packages:
dependency: transitive
description:
name: permission_handler_platform_interface
sha256: a5c8a97ecf5616112a5b16d4b8e9ec0e5ae90ef63ac69c0d7b8ae240be760b23
url: "https://pub.flutter-io.cn"
sha256: ed86a61c190258fdd65de395ea0632822e3415c1faec38eae0c31b479c28a531
url: "https://pub.dev"
source: hosted
version: "4.4.0"
version: "4.4.1"
permission_handler_windows:
dependency: transitive
description:
name: permission_handler_windows
sha256: caeae01858a0a7d2df67a445ac98e1ad95e55a0e77c73044f4e9b1c8c2289cbd
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "0.2.2"
pigeon:
... ... @@ -804,7 +804,7 @@ packages:
description:
name: platform
sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "3.1.6"
plugin_platform_interface:
... ... @@ -812,7 +812,7 @@ packages:
description:
name: plugin_platform_interface
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.1.8"
pool:
... ... @@ -820,7 +820,7 @@ packages:
description:
name: pool
sha256: "4177f68c237ea2128d1bee66ac17b2ce05ba3dbaafcbdd54c5d40a39d0b6b11c"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "1.5.3"
posix:
... ... @@ -828,7 +828,7 @@ packages:
description:
name: posix
sha256: bc1bad54ad2b735816e31f8d4600cfde6c7839975085ddfbca48b6c9f7c4044e
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "6.5.2"
pretty_dio_logger:
... ... @@ -836,7 +836,7 @@ packages:
description:
name: pretty_dio_logger
sha256: "36f2101299786d567869493e2f5731de61ce130faa14679473b26905a92b6407"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "1.4.0"
pub_semver:
... ... @@ -844,7 +844,7 @@ packages:
description:
name: pub_semver
sha256: "261236774e8b1d69cfc6b9eabbc96c40f25e7a2d6b171f3385d4f65d5734fb24"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.2.1"
pubspec_parse:
... ... @@ -852,7 +852,7 @@ packages:
description:
name: pubspec_parse
sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "1.5.0"
rxdart:
... ... @@ -860,7 +860,7 @@ packages:
description:
name: rxdart
sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "0.28.0"
share_plus:
... ... @@ -895,7 +895,7 @@ packages:
description:
name: shared_preferences_android
sha256: "5bcf0772a761b04f8c6bf814721713de6f3e5d9d89caf8d3fe031b02a342379e"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.4.11"
shared_preferences_foundation:
... ... @@ -903,7 +903,7 @@ packages:
description:
name: shared_preferences_foundation
sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.5.4"
shared_preferences_linux:
... ... @@ -911,7 +911,7 @@ packages:
description:
name: shared_preferences_linux
sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
shared_preferences_ohos:
... ... @@ -928,7 +928,7 @@ packages:
description:
name: shared_preferences_platform_interface
sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
shared_preferences_web:
... ... @@ -936,7 +936,7 @@ packages:
description:
name: shared_preferences_web
sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.4.3"
shared_preferences_windows:
... ... @@ -944,7 +944,7 @@ packages:
description:
name: shared_preferences_windows
sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
shelf:
... ... @@ -952,7 +952,7 @@ packages:
description:
name: shelf
sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "1.4.2"
shelf_web_socket:
... ... @@ -960,7 +960,7 @@ packages:
description:
name: shelf_web_socket
sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "3.0.0"
simple_gesture_detector:
... ... @@ -968,7 +968,7 @@ packages:
description:
name: simple_gesture_detector
sha256: ba2cd5af24ff20a0b8d609cec3f40e5b0744d2a71804a2616ae086b9c19d19a3
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "0.2.1"
sky_engine:
... ... @@ -981,7 +981,7 @@ packages:
description:
name: source_span
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "1.10.0"
sqflite:
... ... @@ -998,7 +998,7 @@ packages:
description:
name: sqflite_android
sha256: "78f489aab276260cdd26676d2169446c7ecd3484bbd5fead4ca14f3ed4dd9ee3"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.4.0"
sqflite_common:
... ... @@ -1006,7 +1006,7 @@ packages:
description:
name: sqflite_common
sha256: "761b9740ecbd4d3e66b8916d784e581861fd3c3553eda85e167bc49fdb68f709"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.5.4+6"
sqflite_darwin:
... ... @@ -1014,7 +1014,7 @@ packages:
description:
name: sqflite_darwin
sha256: "22adfd9a2c7d634041e96d6241e6e1c8138ca6817018afc5d443fef91dcefa9c"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.4.1+1"
sqflite_ohos:
... ... @@ -1031,7 +1031,7 @@ packages:
description:
name: sqflite_platform_interface
sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.4.0"
stack_trace:
... ... @@ -1039,7 +1039,7 @@ packages:
description:
name: stack_trace
sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "1.12.0"
stream_channel:
... ... @@ -1047,7 +1047,7 @@ packages:
description:
name: stream_channel
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
stream_transform:
... ... @@ -1055,7 +1055,7 @@ packages:
description:
name: stream_transform
sha256: a00e5f18bffc764f923e7dec1038527f7fe7a1791361a7117f0358193f13d53a
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
string_scanner:
... ... @@ -1063,7 +1063,7 @@ packages:
description:
name: string_scanner
sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "1.3.0"
synchronized:
... ... @@ -1071,7 +1071,7 @@ packages:
description:
name: synchronized
sha256: "69fe30f3a8b04a0be0c15ae6490fc859a78ef4c43ae2dd5e8a623d45bfcf9225"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "3.3.0+3"
table_calendar:
... ... @@ -1079,7 +1079,7 @@ packages:
description:
name: table_calendar
sha256: b2896b7c86adf3a4d9c911d860120fe3dbe03c85db43b22fd61f14ee78cdbb63
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "3.1.3"
term_glyph:
... ... @@ -1087,7 +1087,7 @@ packages:
description:
name: term_glyph
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "1.2.1"
test_api:
... ... @@ -1095,7 +1095,7 @@ packages:
description:
name: test_api
sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "0.7.3"
thinking_analytics:
... ... @@ -1103,7 +1103,7 @@ packages:
description:
name: thinking_analytics
sha256: b01cac0b5482e71c1d75c44c77d27f427662cc65a77b7bc3c8b49617d7a01e02
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "3.3.3"
timing:
... ... @@ -1111,7 +1111,7 @@ packages:
description:
name: timing
sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "1.0.2"
typed_data:
... ... @@ -1119,7 +1119,7 @@ packages:
description:
name: typed_data
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "1.4.0"
url_launcher_linux:
... ... @@ -1127,7 +1127,7 @@ packages:
description:
name: url_launcher_linux
sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "3.2.1"
url_launcher_platform_interface:
... ... @@ -1135,7 +1135,7 @@ packages:
description:
name: url_launcher_platform_interface
sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
url_launcher_web:
... ... @@ -1143,7 +1143,7 @@ packages:
description:
name: url_launcher_web
sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
url_launcher_windows:
... ... @@ -1151,7 +1151,7 @@ packages:
description:
name: url_launcher_windows
sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "3.1.4"
uuid:
... ... @@ -1159,7 +1159,7 @@ packages:
description:
name: uuid
sha256: "9b129329f58692f6e6578329498a8fe9fbe98f090beb764ffbb8ee2eadd01dcd"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "4.6.0"
vector_math:
... ... @@ -1167,7 +1167,7 @@ packages:
description:
name: vector_math
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
video_thumbnail:
... ... @@ -1175,7 +1175,7 @@ packages:
description:
name: video_thumbnail
sha256: "181a0c205b353918954a881f53a3441476b9e301641688a581e0c13f00dc588b"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "0.5.6"
vm_service:
... ... @@ -1183,7 +1183,7 @@ packages:
description:
name: vm_service
sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "14.3.0"
watcher:
... ... @@ -1191,7 +1191,7 @@ packages:
description:
name: watcher
sha256: "1398c9f081a753f9226febe8900fce8f7d0a67163334e1c94a2438339d79d635"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "1.2.1"
web:
... ... @@ -1199,7 +1199,7 @@ packages:
description:
name: web
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "1.1.1"
web_socket:
... ... @@ -1207,7 +1207,7 @@ packages:
description:
name: web_socket
sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "1.0.1"
web_socket_channel:
... ... @@ -1215,7 +1215,7 @@ packages:
description:
name: web_socket_channel
sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "3.0.3"
webview_flutter:
... ... @@ -1268,7 +1268,7 @@ packages:
description:
name: win32
sha256: daf97c9d80197ed7b619040e86c8ab9a9dad285e7671ee7390f9180cc828a51e
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "5.10.1"
xdg_directories:
... ... @@ -1276,7 +1276,7 @@ packages:
description:
name: xdg_directories
sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
yaml:
... ... @@ -1284,7 +1284,7 @@ packages:
description:
name: yaml
sha256: f67cdd8e07d3c6329146aaef1ba043542b3134c12489f553ca9a7435d1068aea
url: "https://pub.flutter-io.cn"
url: "https://pub.dev"
source: hosted
version: "3.1.4"
sdks:
... ...
... ... @@ -399,7 +399,7 @@ void main() {
expect(toasts, hasLength(1));
expect(
toasts.single,
matches(RegExp(r'^【测试】本轮同步耗时0\.0 s、计算耗时\d+\.\d s$')),
matches(RegExp(r'^【测试】获取数据耗时0\.0 s、计算耗时\d+\.\d s$')),
);
});
... ...