|
...
|
...
|
@@ -57,6 +57,10 @@ class HealthRawDataCoreService { |
|
|
|
return _localStore.closeDatabase(userId: _userId);
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<bool> hasHealthData() {
|
|
|
|
return _rawDataApi.hasHealthData();
|
|
|
|
}
|
|
|
|
|
|
|
|
Stream<HealthRawDataUpdatedEvent> get healthDataUpdatedStream =>
|
|
|
|
_healthDataUpdatedController.stream;
|
|
|
|
|
|
...
|
...
|
@@ -732,6 +736,7 @@ class HealthRawDataCoreService { |
|
|
|
HealthRawHrvStressPoint(
|
|
|
|
userId: userId,
|
|
|
|
rawEndTime: point.endTime,
|
|
|
|
rawHrv: pointValue,
|
|
|
|
result: trendHrv,
|
|
|
|
sourceStartTime: sourceRange.start,
|
|
|
|
sourceEndTime: sourceRange.end,
|
|
...
|
...
|
@@ -1263,6 +1268,7 @@ class HealthRawHrvStressPoint { |
|
|
|
const HealthRawHrvStressPoint({
|
|
|
|
required this.userId,
|
|
|
|
required this.rawEndTime,
|
|
|
|
required this.rawHrv,
|
|
|
|
required this.result,
|
|
|
|
required this.sourceStartTime,
|
|
|
|
required this.sourceEndTime,
|
|
...
|
...
|
@@ -1277,6 +1283,7 @@ class HealthRawHrvStressPoint { |
|
|
|
|
|
|
|
final int userId;
|
|
|
|
final int rawEndTime;
|
|
|
|
final double rawHrv;
|
|
|
|
final double result;
|
|
|
|
final int sourceStartTime;
|
|
|
|
final int sourceEndTime;
|
|
...
|
...
|
@@ -1290,16 +1297,18 @@ class HealthRawHrvStressPoint { |
|
|
|
|
|
|
|
factory HealthRawHrvStressPoint.fromDb(Map<String, Object?> row) {
|
|
|
|
final result = (row['result'] as num).toDouble();
|
|
|
|
final rawHrv = _positiveDouble(row['raw_hrv']) ?? result;
|
|
|
|
final baselineHrv = _positiveDouble(row['baseline_hrv']) ?? result;
|
|
|
|
final baselineAwakeHrv =
|
|
|
|
_positiveDouble(row['baseline_awake_hrv']) ?? baselineHrv;
|
|
|
|
return HealthRawHrvStressPoint(
|
|
|
|
userId: row['user_id'] as int,
|
|
|
|
rawEndTime: row['raw_end_time'] as int,
|
|
|
|
rawHrv: rawHrv,
|
|
|
|
result: result,
|
|
|
|
sourceStartTime: row['source_start_time'] as int,
|
|
|
|
sourceEndTime: row['source_end_time'] as int,
|
|
|
|
state: HealthRawStressState.normal,
|
|
|
|
state: _stressStateFromDb(row['state']) ?? HealthRawStressState.normal,
|
|
|
|
baselineHrv: baselineHrv,
|
|
|
|
baselineAwakeHrv: baselineAwakeHrv,
|
|
|
|
baselineSleepHrv: _positiveDouble(row['baseline_sleep_hrv']),
|
|
...
|
...
|
@@ -1329,6 +1338,8 @@ class HealthRawRealtimeStressPoint { |
|
|
|
final HealthRawPointFlags flags;
|
|
|
|
final bool uploaded;
|
|
|
|
|
|
|
|
HealthRawStressState get state => healthRawRealtimeStressState(result);
|
|
|
|
|
|
|
|
factory HealthRawRealtimeStressPoint.fromDb(Map<String, Object?> row) {
|
|
|
|
return HealthRawRealtimeStressPoint(
|
|
|
|
userId: row['user_id'] as int,
|
|
...
|
...
|
@@ -1342,6 +1353,13 @@ class HealthRawRealtimeStressPoint { |
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
HealthRawStressState healthRawRealtimeStressState(num value) {
|
|
|
|
if (value >= 81) return HealthRawStressState.overload;
|
|
|
|
if (value >= 61) return HealthRawStressState.attention;
|
|
|
|
if (value >= 21) return HealthRawStressState.normal;
|
|
|
|
return HealthRawStressState.excellent;
|
|
|
|
}
|
|
|
|
|
|
|
|
HealthRawPointFlags _flagsFromDb(Map<String, Object?> row) {
|
|
|
|
return HealthRawPointFlags(
|
|
|
|
isWorkout: (row['is_workout'] as int? ?? 0) == 1,
|
|
...
|
...
|
@@ -1357,6 +1375,15 @@ double? _positiveDouble(Object? value) { |
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
HealthRawStressState? _stressStateFromDb(Object? value) {
|
|
|
|
final stateValue = value as int?;
|
|
|
|
if (stateValue == null) return null;
|
|
|
|
for (final state in HealthRawStressState.values) {
|
|
|
|
if (state.value == stateValue) return state;
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
class HealthRawStressDbRows {
|
|
|
|
const HealthRawStressDbRows({
|
|
|
|
required this.hrvRows,
|
|
...
|
...
|
@@ -1542,7 +1569,7 @@ class HealthRawStressLocalStore { |
|
|
|
final db = await factory.openDatabase(
|
|
|
|
path,
|
|
|
|
options: OpenDatabaseOptions(
|
|
|
|
version: 3,
|
|
|
|
version: 4,
|
|
|
|
onCreate: (db, version) async {
|
|
|
|
await _createTables(db);
|
|
|
|
},
|
|
...
|
...
|
@@ -1554,6 +1581,9 @@ class HealthRawStressLocalStore { |
|
|
|
if (oldVersion < 3) {
|
|
|
|
await _addHrvBaselineColumns(db);
|
|
|
|
}
|
|
|
|
if (oldVersion < 4) {
|
|
|
|
await _addHrvRawAndStateColumns(db);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
),
|
|
|
|
);
|
|
...
|
...
|
@@ -1566,9 +1596,11 @@ class HealthRawStressLocalStore { |
|
|
|
CREATE TABLE IF NOT EXISTS $hrvResultsTable (
|
|
|
|
raw_end_time INTEGER PRIMARY KEY,
|
|
|
|
user_id INTEGER NOT NULL,
|
|
|
|
raw_hrv REAL NOT NULL DEFAULT 0,
|
|
|
|
result REAL NOT NULL,
|
|
|
|
source_start_time INTEGER NOT NULL,
|
|
|
|
source_end_time INTEGER NOT NULL,
|
|
|
|
state INTEGER NOT NULL DEFAULT 3,
|
|
|
|
baseline_hrv REAL NOT NULL DEFAULT 0,
|
|
|
|
baseline_awake_hrv REAL NOT NULL DEFAULT 0,
|
|
|
|
baseline_sleep_hrv REAL,
|
|
...
|
...
|
@@ -1630,6 +1662,21 @@ CREATE TABLE IF NOT EXISTS $realtimeStressResultsTable ( |
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> _addHrvRawAndStateColumns(DatabaseExecutor db) async {
|
|
|
|
for (final columnSql in const [
|
|
|
|
'raw_hrv REAL NOT NULL DEFAULT 0',
|
|
|
|
'state INTEGER NOT NULL DEFAULT 3',
|
|
|
|
]) {
|
|
|
|
try {
|
|
|
|
await db.execute(
|
|
|
|
'ALTER TABLE $hrvResultsTable ADD COLUMN $columnSql',
|
|
|
|
);
|
|
|
|
} on DatabaseException catch (error) {
|
|
|
|
if (!error.isDuplicateColumnError()) rethrow;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<int?> _latestSourceStartTime(int userId, String table) async {
|
|
|
|
final db = await _database(userId);
|
|
|
|
final rows = await db.query(
|
|
...
|
...
|
@@ -1662,9 +1709,11 @@ CREATE TABLE IF NOT EXISTS $realtimeStressResultsTable ( |
|
|
|
return <String, Object?>{
|
|
|
|
'raw_end_time': point.rawEndTime,
|
|
|
|
'user_id': point.userId,
|
|
|
|
'raw_hrv': point.rawHrv,
|
|
|
|
'result': point.result,
|
|
|
|
'source_start_time': point.sourceStartTime,
|
|
|
|
'source_end_time': point.sourceEndTime,
|
|
|
|
'state': point.state.value,
|
|
|
|
'baseline_hrv': point.baselineHrv,
|
|
|
|
'baseline_awake_hrv': point.baselineAwakeHrv,
|
|
|
|
'baseline_sleep_hrv': point.baselineSleepHrv,
|
|
...
|
...
|
@@ -1709,9 +1758,11 @@ CREATE TABLE IF NOT EXISTS $realtimeStressResultsTable ( |
|
|
|
table,
|
|
|
|
<String, Object?>{
|
|
|
|
'user_id': row['user_id'],
|
|
|
|
if (row.containsKey('raw_hrv')) 'raw_hrv': row['raw_hrv'],
|
|
|
|
'result': row['result'],
|
|
|
|
'source_start_time': row['source_start_time'],
|
|
|
|
'source_end_time': row['source_end_time'],
|
|
|
|
if (row.containsKey('state')) 'state': row['state'],
|
|
|
|
if (row.containsKey('baseline_hrv'))
|
|
|
|
'baseline_hrv': row['baseline_hrv'],
|
|
|
|
if (row.containsKey('baseline_awake_hrv'))
|
...
|
...
|
|