Commit 33a7b6b505d339b4bfdb18a183ec61bacdc25880

Authored by 权海
1 parent d55407d9

feat(ui):本地推送条件后置单独记录

... ... @@ -444,9 +444,30 @@ class AppleHealthRawDataCoreService {
'latest_sleep': _latestSleepResultPayload(result.sleepResults),
},
);
if (result.hrvStressPoints.isEmpty &&
result.realtimeStressPoints.isEmpty &&
result.sleepResults.isEmpty) {
final record = await _readLocalNotificationRecordSafely(result.userId);
await _saveLocalNotificationDebugEvent(
<String, Object?>{
'event': 'flutterNotificationRecordRead',
'user_id': result.userId,
'record': _localNotificationRecordPayload(record),
},
);
final candidateData = await _resolveLocalNotificationCandidates(
result: result,
record: record,
);
await _saveLocalNotificationDebugEvent(
<String, Object?>{
'event': 'flutterNotificationLatestDataTimeChecked',
'user_id': result.userId,
'record': _localNotificationRecordPayload(record),
'latest_data_time': candidateData.latestDataTimePayload,
},
);
final candidateResult = candidateData.result;
if (candidateResult.hrvStressPoints.isEmpty &&
candidateResult.realtimeStressPoints.isEmpty &&
candidateResult.sleepResults.isEmpty) {
await _saveLocalNotificationDebugEvent(
<String, Object?>{
'event': 'flutterNotificationNotBuilt',
... ... @@ -457,12 +478,13 @@ class AppleHealthRawDataCoreService {
return;
}
final latestRealtimeStressPoint = result.realtimeStressPoints.isEmpty
? null
: result.realtimeStressPoints.reduce(
(a, b) => a.rawEndTime >= b.rawEndTime ? a : b,
);
var notificationResult = result;
final latestRealtimeStressPoint =
candidateResult.realtimeStressPoints.isEmpty
? null
: candidateResult.realtimeStressPoints.reduce(
(a, b) => a.rawEndTime >= b.rawEndTime ? a : b,
);
var notificationResult = candidateResult;
var realtimeWindow = const <HealthRawRealtimeStressPoint>[];
if (latestRealtimeStressPoint != null) {
final shouldResetRealtimeStressPushTime =
... ... @@ -479,36 +501,28 @@ class AppleHealthRawDataCoreService {
},
);
await _recordRealtimeStressTimeSafely(
userId: result.userId,
userId: candidateResult.userId,
recordTime: latestRealtimeStressPoint.rawEndTime,
);
notificationResult = result.copyWith(
notificationResult = candidateResult.copyWith(
realtimeStressPoints: const <HealthRawRealtimeStressPoint>[],
);
} else {
realtimeWindow = await _queryRealtimeStressNotificationWindowSafely(
userId: result.userId,
userId: candidateResult.userId,
latestRawEndTime: latestRealtimeStressPoint.rawEndTime,
);
}
}
final record = await _readLocalNotificationRecordSafely(result.userId);
await _saveLocalNotificationDebugEvent(
<String, Object?>{
'event': 'flutterNotificationRecordRead',
'user_id': result.userId,
'record': _localNotificationRecordPayload(record),
},
);
await _saveLocalNotificationDebugEvent(
<String, Object?>{
'event': 'flutterNotificationBuildDecisions',
'user_id': result.userId,
'user_id': candidateResult.userId,
'decisions': _localNotificationDecisionPayloads(
result: notificationResult,
hasExistingHrv: hasExistingHrv,
hasExistingSleep: hasExistingSleep,
hasExistingHrv: candidateData.hasExistingHrvDataTime,
hasExistingSleep: candidateData.hasExistingSleepDataTime,
realtimeWindow: realtimeWindow,
record: record,
),
... ... @@ -516,15 +530,15 @@ class AppleHealthRawDataCoreService {
);
final notifications = HealthRawLocalNotificationBuilder(l10n).build(
result: notificationResult,
hasExistingHrv: hasExistingHrv,
hasExistingSleep: hasExistingSleep,
hasExistingHrv: candidateData.hasExistingHrvDataTime,
hasExistingSleep: candidateData.hasExistingSleepDataTime,
realtimeWindow: realtimeWindow,
record: record,
);
await _saveLocalNotificationDebugEvent(
<String, Object?>{
'event': 'flutterNotificationBuildFinished',
'user_id': result.userId,
'user_id': candidateResult.userId,
'notification_count': notifications.length,
'notifications': notifications.map(_localNotificationPayload).toList(),
},
... ... @@ -534,7 +548,7 @@ class AppleHealthRawDataCoreService {
<String, Object?>{
'event': 'flutterNotificationNotSent',
'reason': 'no_built_notifications',
'user_id': result.userId,
'user_id': candidateResult.userId,
},
);
return;
... ... @@ -545,18 +559,18 @@ class AppleHealthRawDataCoreService {
await _saveLocalNotificationDebugEvent(
<String, Object?>{
'event': 'flutterNotificationSendStart',
'user_id': result.userId,
'user_id': candidateResult.userId,
'notification': _localNotificationPayload(notification),
},
);
final sent = await _sendLocalNotificationSafely(
userId: result.userId,
userId: candidateResult.userId,
notification: notification,
);
await _saveLocalNotificationDebugEvent(
<String, Object?>{
'event': 'flutterNotificationSendFinished',
'user_id': result.userId,
'user_id': candidateResult.userId,
'sent': sent,
'reason': sent ? null : 'native_or_dispatcher_returned_false',
'notification': _localNotificationPayload(notification),
... ... @@ -569,6 +583,93 @@ class AppleHealthRawDataCoreService {
_scheduleRealtimeStressServerPush(sentNotifications);
}
Future<_HealthRawLocalNotificationCandidateData>
_resolveLocalNotificationCandidates({
required HealthRawStressCalculationResult result,
required HealthRawLocalNotificationRecord record,
}) async {
final userId = result.userId;
final latestHrvRawEndTime = await _localStore.latestHrvRawEndTime(userId);
final latestRealtimeRawEndTime =
await _localStore.latestRealtimeRawEndTime(userId);
final latestSleepDataTime = await _localStore.latestSleepResultTime(userId);
var hrvPoints = const <HealthRawHrvStressPoint>[];
var realtimePoints = const <HealthRawRealtimeStressPoint>[];
var sleepResults = const <HealthRawSleepResult>[];
int? nextHrvDataTime;
int? nextRealtimeStressDataTime;
int? nextSleepDataTime;
final hrvDataTime = record.latestHrvDataTime;
if (latestHrvRawEndTime != null) {
if (hrvDataTime == null) {
nextHrvDataTime = latestHrvRawEndTime;
} else if (hrvDataTime < latestHrvRawEndTime) {
hrvPoints = await _localStore.queryHrvStressPoints(
userId: userId,
startTime: hrvDataTime + 1,
endTime: latestHrvRawEndTime,
);
nextHrvDataTime = latestHrvRawEndTime;
}
}
final realtimeDataTime = record.latestRealtimeStressDataTime;
if (latestRealtimeRawEndTime != null) {
if (realtimeDataTime == null) {
nextRealtimeStressDataTime = latestRealtimeRawEndTime;
} else if (realtimeDataTime < latestRealtimeRawEndTime) {
realtimePoints = await _localStore.queryRealtimeStressPoints(
userId: userId,
startTime: realtimeDataTime + 1,
endTime: latestRealtimeRawEndTime,
);
nextRealtimeStressDataTime = latestRealtimeRawEndTime;
}
}
final sleepDataTime = record.latestSleepDataTime;
if (latestSleepDataTime != null) {
if (sleepDataTime == null) {
nextSleepDataTime = latestSleepDataTime;
} else if (sleepDataTime < latestSleepDataTime) {
sleepResults = await _localStore.querySleepResults(
userId: userId,
startTime: sleepDataTime + 1,
endTime: latestSleepDataTime,
);
nextSleepDataTime = latestSleepDataTime;
}
}
await _updateProcessedDataTimesSafely(
userId: userId,
latestHrvDataTime: nextHrvDataTime,
latestRealtimeStressDataTime: nextRealtimeStressDataTime,
latestSleepDataTime: nextSleepDataTime,
);
return _HealthRawLocalNotificationCandidateData(
result: HealthRawStressCalculationResult(
userId: userId,
hrvStressPoints: hrvPoints,
realtimeStressPoints: realtimePoints,
dailyStressPoints: result.dailyStressPoints,
sleepResults: sleepResults,
),
hasExistingHrvDataTime: hrvDataTime != null,
hasExistingRealtimeStressDataTime: realtimeDataTime != null,
hasExistingSleepDataTime: sleepDataTime != null,
currentHrvDataTime: latestHrvRawEndTime,
currentRealtimeStressDataTime: latestRealtimeRawEndTime,
currentSleepDataTime: latestSleepDataTime,
nextHrvDataTime: nextHrvDataTime,
nextRealtimeStressDataTime: nextRealtimeStressDataTime,
nextSleepDataTime: nextSleepDataTime,
);
}
Future<HealthRawLocalNotificationRecord> _readLocalNotificationRecordSafely(
int userId,
) async {
... ... @@ -580,6 +681,28 @@ class AppleHealthRawDataCoreService {
}
}
Future<void> _updateProcessedDataTimesSafely({
required int userId,
int? latestHrvDataTime,
int? latestRealtimeStressDataTime,
int? latestSleepDataTime,
}) async {
try {
await _localNotificationDispatcher.updateProcessedDataTimes(
userId: userId,
latestHrvDataTime: latestHrvDataTime,
latestRealtimeStressDataTime: latestRealtimeStressDataTime,
latestSleepDataTime: latestSleepDataTime,
);
} catch (error, stackTrace) {
_logError(
'update local notification processed data time failed',
error,
stackTrace,
);
}
}
Future<void> _recordRealtimeStressTimeSafely({
required int userId,
required int recordTime,
... ... @@ -864,6 +987,9 @@ class AppleHealthRawDataCoreService {
'last_sleep_time': record.lastSleepTime,
'last_hrv_time': record.lastHrvTime,
'last_realtime_stress_time': record.lastRealtimeStressTime,
'latest_hrv_data_time': record.latestHrvDataTime,
'latest_realtime_stress_data_time': record.latestRealtimeStressDataTime,
'latest_sleep_data_time': record.latestSleepDataTime,
};
}
... ... @@ -1675,6 +1801,50 @@ class HealthRawStressDbRows {
final List<Map<String, Object?>> sleepRows;
}
class _HealthRawLocalNotificationCandidateData {
const _HealthRawLocalNotificationCandidateData({
required this.result,
required this.hasExistingHrvDataTime,
required this.hasExistingRealtimeStressDataTime,
required this.hasExistingSleepDataTime,
required this.currentHrvDataTime,
required this.currentRealtimeStressDataTime,
required this.currentSleepDataTime,
required this.nextHrvDataTime,
required this.nextRealtimeStressDataTime,
required this.nextSleepDataTime,
});
final HealthRawStressCalculationResult result;
final bool hasExistingHrvDataTime;
final bool hasExistingRealtimeStressDataTime;
final bool hasExistingSleepDataTime;
final int? currentHrvDataTime;
final int? currentRealtimeStressDataTime;
final int? currentSleepDataTime;
final int? nextHrvDataTime;
final int? nextRealtimeStressDataTime;
final int? nextSleepDataTime;
Map<String, Object?> get latestDataTimePayload {
return <String, Object?>{
'has_existing_hrv_data_time': hasExistingHrvDataTime,
'has_existing_realtime_stress_data_time':
hasExistingRealtimeStressDataTime,
'has_existing_sleep_data_time': hasExistingSleepDataTime,
'current_hrv_data_time': currentHrvDataTime,
'current_realtime_stress_data_time': currentRealtimeStressDataTime,
'current_sleep_data_time': currentSleepDataTime,
'next_hrv_data_time': nextHrvDataTime,
'next_realtime_stress_data_time': nextRealtimeStressDataTime,
'next_sleep_data_time': nextSleepDataTime,
'candidate_hrv_count': result.hrvStressPoints.length,
'candidate_realtime_count': result.realtimeStressPoints.length,
'candidate_sleep_count': result.sleepResults.length,
};
}
}
double _integerDouble(num value) => value.toInt().toDouble();
class HealthRawStressLocalStore {
... ...