Showing
8 changed files
with
244 additions
and
82 deletions
| @@ -31,10 +31,8 @@ class DeveloperOptionsItem { | @@ -31,10 +31,8 @@ class DeveloperOptionsItem { | ||
| 31 | 31 | ||
| 32 | enum DeveloperOptionsAction { | 32 | enum DeveloperOptionsAction { |
| 33 | shareHealthRawDataDatabase, | 33 | shareHealthRawDataDatabase, |
| 34 | - shareHealthRawUploadLog, | ||
| 35 | shareNativeAppleHealthObserverRecord, | 34 | shareNativeAppleHealthObserverRecord, |
| 36 | shareFlutterObserverRecord, | 35 | shareFlutterObserverRecord, |
| 37 | - shareUploadTaskRecord, | ||
| 38 | shareLocalNotificationDebugRecord, | 36 | shareLocalNotificationDebugRecord, |
| 39 | sendTestHrvLocalNotification, | 37 | sendTestHrvLocalNotification, |
| 40 | clearHealthRawDataDatabaseAndUploadLog, | 38 | clearHealthRawDataDatabaseAndUploadLog, |
| @@ -52,61 +50,84 @@ class DeveloperOptionsController extends GetxController { | @@ -52,61 +50,84 @@ class DeveloperOptionsController extends GetxController { | ||
| 52 | final AppPlatformHostApi _platformHostApi = AppPlatformHostApi(); | 50 | final AppPlatformHostApi _platformHostApi = AppPlatformHostApi(); |
| 53 | final TextEditingController tokenController = TextEditingController(); | 51 | final TextEditingController tokenController = TextEditingController(); |
| 54 | 52 | ||
| 55 | - final List<DeveloperOptionsItem> options = const [ | ||
| 56 | - DeveloperOptionsItem( | ||
| 57 | - title: 'User Information', | ||
| 58 | - routeName: Routes.USER_INFORMATION, | ||
| 59 | - ), | ||
| 60 | - DeveloperOptionsItem( | ||
| 61 | - title: 'Route List', | ||
| 62 | - routeName: Routes.ROUTE_LIST, | ||
| 63 | - ), | ||
| 64 | - DeveloperOptionsItem( | ||
| 65 | - title: 'Token Login', | ||
| 66 | - routeName: Routes.TOKEN_LOGIN, | ||
| 67 | - ), | ||
| 68 | - DeveloperOptionsItem( | ||
| 69 | - title: 'Share HealthRawData Database', | ||
| 70 | - action: DeveloperOptionsAction.shareHealthRawDataDatabase, | ||
| 71 | - ), | ||
| 72 | - DeveloperOptionsItem( | ||
| 73 | - title: '本地上传日志', | ||
| 74 | - action: DeveloperOptionsAction.shareHealthRawUploadLog, | ||
| 75 | - ), | ||
| 76 | - DeveloperOptionsItem( | ||
| 77 | - title: '分享原生AppleHealthObserver记录', | ||
| 78 | - action: DeveloperOptionsAction.shareNativeAppleHealthObserverRecord, | ||
| 79 | - ), | ||
| 80 | - DeveloperOptionsItem( | ||
| 81 | - title: '分享Flutter Observer-Caculate记录', | ||
| 82 | - action: DeveloperOptionsAction.shareFlutterObserverRecord, | ||
| 83 | - ), | ||
| 84 | - DeveloperOptionsItem( | ||
| 85 | - title: '分享上传Task日志', | ||
| 86 | - action: DeveloperOptionsAction.shareUploadTaskRecord, | ||
| 87 | - ), | ||
| 88 | - DeveloperOptionsItem( | ||
| 89 | - title: '分享本地推送诊断日志', | ||
| 90 | - action: DeveloperOptionsAction.shareLocalNotificationDebugRecord, | ||
| 91 | - ), | ||
| 92 | - DeveloperOptionsItem( | ||
| 93 | - title: '测试本地推送 HRV', | ||
| 94 | - action: DeveloperOptionsAction.sendTestHrvLocalNotification, | ||
| 95 | - ), | ||
| 96 | - DeveloperOptionsItem( | ||
| 97 | - title: '清除本地数据库、上传日志', | ||
| 98 | - action: DeveloperOptionsAction.clearHealthRawDataDatabaseAndUploadLog, | ||
| 99 | - ), | ||
| 100 | - DeveloperOptionsItem( | ||
| 101 | - title: 'Global Env', | ||
| 102 | - action: DeveloperOptionsAction.globalEnv, | ||
| 103 | - ), | ||
| 104 | - ]; | 53 | + late final List<DeveloperOptionsItem> options; |
| 105 | 54 | ||
| 106 | @override | 55 | @override |
| 107 | void onInit() { | 56 | void onInit() { |
| 108 | super.onInit(); | 57 | super.onInit(); |
| 109 | tokenController.text = _userPreferencesStorage.accessToken; | 58 | tokenController.text = _userPreferencesStorage.accessToken; |
| 59 | + final config = Get.find<AppEnvironmentConfig>(); | ||
| 60 | + if (config.isDebug) { | ||
| 61 | + options = const [ | ||
| 62 | + DeveloperOptionsItem( | ||
| 63 | + title: 'User Information', | ||
| 64 | + routeName: Routes.USER_INFORMATION, | ||
| 65 | + ), | ||
| 66 | + DeveloperOptionsItem( | ||
| 67 | + title: 'Route List', | ||
| 68 | + routeName: Routes.ROUTE_LIST, | ||
| 69 | + ), | ||
| 70 | + DeveloperOptionsItem( | ||
| 71 | + title: 'Token Login', | ||
| 72 | + routeName: Routes.TOKEN_LOGIN, | ||
| 73 | + ), | ||
| 74 | + DeveloperOptionsItem( | ||
| 75 | + title: '分享本地计算数据库文件', | ||
| 76 | + action: DeveloperOptionsAction.shareHealthRawDataDatabase, | ||
| 77 | + ), | ||
| 78 | + DeveloperOptionsItem( | ||
| 79 | + title: '分享原生响应AppleHealth记录', | ||
| 80 | + action: DeveloperOptionsAction.shareNativeAppleHealthObserverRecord, | ||
| 81 | + ), | ||
| 82 | + DeveloperOptionsItem( | ||
| 83 | + title: '分享Flutter 响应AppleHealth回调记录', | ||
| 84 | + action: DeveloperOptionsAction.shareFlutterObserverRecord, | ||
| 85 | + ), | ||
| 86 | + DeveloperOptionsItem( | ||
| 87 | + title: '分享本地推送诊断日志', | ||
| 88 | + action: DeveloperOptionsAction.shareLocalNotificationDebugRecord, | ||
| 89 | + ), | ||
| 90 | + DeveloperOptionsItem( | ||
| 91 | + title: '测试本地推送 HRV', | ||
| 92 | + action: DeveloperOptionsAction.sendTestHrvLocalNotification, | ||
| 93 | + ), | ||
| 94 | + DeveloperOptionsItem( | ||
| 95 | + title: '清除本地数据库、上传日志', | ||
| 96 | + action: DeveloperOptionsAction.clearHealthRawDataDatabaseAndUploadLog, | ||
| 97 | + ), | ||
| 98 | + DeveloperOptionsItem( | ||
| 99 | + title: 'Global Env', | ||
| 100 | + action: DeveloperOptionsAction.globalEnv, | ||
| 101 | + ), | ||
| 102 | + ]; | ||
| 103 | + } else { | ||
| 104 | + options = const [ | ||
| 105 | + DeveloperOptionsItem( | ||
| 106 | + title: 'User Information', | ||
| 107 | + routeName: Routes.USER_INFORMATION, | ||
| 108 | + ), | ||
| 109 | + DeveloperOptionsItem( | ||
| 110 | + title: '分享本地计算数据库文件', | ||
| 111 | + action: DeveloperOptionsAction.shareHealthRawDataDatabase, | ||
| 112 | + ), | ||
| 113 | + DeveloperOptionsItem( | ||
| 114 | + title: '分享原生响应AppleHealth记录', | ||
| 115 | + action: DeveloperOptionsAction.shareNativeAppleHealthObserverRecord, | ||
| 116 | + ), | ||
| 117 | + DeveloperOptionsItem( | ||
| 118 | + title: '分享Flutter 响应AppleHealth回调记录', | ||
| 119 | + action: DeveloperOptionsAction.shareFlutterObserverRecord, | ||
| 120 | + ), | ||
| 121 | + DeveloperOptionsItem( | ||
| 122 | + title: '分享本地推送诊断日志', | ||
| 123 | + action: DeveloperOptionsAction.shareLocalNotificationDebugRecord, | ||
| 124 | + ), | ||
| 125 | + DeveloperOptionsItem( | ||
| 126 | + title: '清除本地数据库、上传日志', | ||
| 127 | + action: DeveloperOptionsAction.clearHealthRawDataDatabaseAndUploadLog, | ||
| 128 | + ), | ||
| 129 | + ]; | ||
| 130 | + } | ||
| 110 | } | 131 | } |
| 111 | 132 | ||
| 112 | Future<void> optionItemOnTap(DeveloperOptionsItem item) async { | 133 | Future<void> optionItemOnTap(DeveloperOptionsItem item) async { |
| @@ -120,18 +141,12 @@ class DeveloperOptionsController extends GetxController { | @@ -120,18 +141,12 @@ class DeveloperOptionsController extends GetxController { | ||
| 120 | case DeveloperOptionsAction.shareHealthRawDataDatabase: | 141 | case DeveloperOptionsAction.shareHealthRawDataDatabase: |
| 121 | await shareHealthRawDataDatabase(); | 142 | await shareHealthRawDataDatabase(); |
| 122 | break; | 143 | break; |
| 123 | - case DeveloperOptionsAction.shareHealthRawUploadLog: | ||
| 124 | - await shareHealthRawUploadLog(); | ||
| 125 | - break; | ||
| 126 | case DeveloperOptionsAction.shareNativeAppleHealthObserverRecord: | 144 | case DeveloperOptionsAction.shareNativeAppleHealthObserverRecord: |
| 127 | await shareNativeAppleHealthObserverRecord(); | 145 | await shareNativeAppleHealthObserverRecord(); |
| 128 | break; | 146 | break; |
| 129 | case DeveloperOptionsAction.shareFlutterObserverRecord: | 147 | case DeveloperOptionsAction.shareFlutterObserverRecord: |
| 130 | await shareFlutterObserverRecord(); | 148 | await shareFlutterObserverRecord(); |
| 131 | break; | 149 | break; |
| 132 | - case DeveloperOptionsAction.shareUploadTaskRecord: | ||
| 133 | - await shareUploadTaskRecord(); | ||
| 134 | - break; | ||
| 135 | case DeveloperOptionsAction.shareLocalNotificationDebugRecord: | 150 | case DeveloperOptionsAction.shareLocalNotificationDebugRecord: |
| 136 | await shareLocalNotificationDebugRecord(); | 151 | await shareLocalNotificationDebugRecord(); |
| 137 | break; | 152 | break; |
| @@ -15,6 +15,9 @@ import '../models/watch_theme_models.dart'; | @@ -15,6 +15,9 @@ import '../models/watch_theme_models.dart'; | ||
| 15 | class WatchThemeController extends GetxController { | 15 | class WatchThemeController extends GetxController { |
| 16 | WatchThemeController(this._themeApi, this._vipApi); | 16 | WatchThemeController(this._themeApi, this._vipApi); |
| 17 | 17 | ||
| 18 | + static const int _developerOptionsTapCount = 8; | ||
| 19 | + static const Duration _developerOptionsTapWindow = Duration(seconds: 3); | ||
| 20 | + | ||
| 18 | final ThemeApi _themeApi; | 21 | final ThemeApi _themeApi; |
| 19 | final VipApi _vipApi; | 22 | final VipApi _vipApi; |
| 20 | 23 | ||
| @@ -23,6 +26,8 @@ class WatchThemeController extends GetxController { | @@ -23,6 +26,8 @@ class WatchThemeController extends GetxController { | ||
| 23 | final officialThemeItems = <WatchThemeItem>[].obs; | 26 | final officialThemeItems = <WatchThemeItem>[].obs; |
| 24 | final customThemeItems = <WatchThemeItem>[].obs; | 27 | final customThemeItems = <WatchThemeItem>[].obs; |
| 25 | final selectedThemeItem = Rx<WatchThemeItem?>(null); | 28 | final selectedThemeItem = Rx<WatchThemeItem?>(null); |
| 29 | + int _headerTapCount = 0; | ||
| 30 | + DateTime? _firstHeaderTapAt; | ||
| 26 | 31 | ||
| 27 | @override | 32 | @override |
| 28 | void onInit() { | 33 | void onInit() { |
| @@ -63,6 +68,26 @@ class WatchThemeController extends GetxController { | @@ -63,6 +68,26 @@ class WatchThemeController extends GetxController { | ||
| 63 | Get.back(); | 68 | Get.back(); |
| 64 | } | 69 | } |
| 65 | 70 | ||
| 71 | + void onHeaderTap() { | ||
| 72 | + final now = DateTime.now(); | ||
| 73 | + final firstTapAt = _firstHeaderTapAt; | ||
| 74 | + if (firstTapAt == null || | ||
| 75 | + now.difference(firstTapAt) > _developerOptionsTapWindow) { | ||
| 76 | + _firstHeaderTapAt = now; | ||
| 77 | + _headerTapCount = 1; | ||
| 78 | + return; | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + _headerTapCount += 1; | ||
| 82 | + if (_headerTapCount < _developerOptionsTapCount) { | ||
| 83 | + return; | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + _firstHeaderTapAt = null; | ||
| 87 | + _headerTapCount = 0; | ||
| 88 | + Get.toNamed(Routes.DEVELOPER_OPTIONS); | ||
| 89 | + } | ||
| 90 | + | ||
| 66 | Future<void> selectOfficialTheme(int index) async { | 91 | Future<void> selectOfficialTheme(int index) async { |
| 67 | await Get.toNamed(Routes.WATCH_THEME_PREVIEW, arguments: { | 92 | await Get.toNamed(Routes.WATCH_THEME_PREVIEW, arguments: { |
| 68 | 'theme': officialThemeItems[index], | 93 | 'theme': officialThemeItems[index], |
| @@ -23,9 +23,13 @@ class WatchThemeView extends GetView<WatchThemeController> { | @@ -23,9 +23,13 @@ class WatchThemeView extends GetView<WatchThemeController> { | ||
| 23 | padding: EdgeInsets.only(top: topPadding, bottom: 24), | 23 | padding: EdgeInsets.only(top: topPadding, bottom: 24), |
| 24 | child: Column( | 24 | child: Column( |
| 25 | children: [ | 25 | children: [ |
| 26 | - WatchThemeHeader( | ||
| 27 | - themeImageUrl: | ||
| 28 | - controller.selectedThemeItem.value?.energeticImage, | 26 | + GestureDetector( |
| 27 | + behavior: HitTestBehavior.opaque, | ||
| 28 | + onTap: controller.onHeaderTap, | ||
| 29 | + child: WatchThemeHeader( | ||
| 30 | + themeImageUrl: | ||
| 31 | + controller.selectedThemeItem.value?.energeticImage, | ||
| 32 | + ), | ||
| 29 | ), | 33 | ), |
| 30 | const SizedBox(height: 26), | 34 | const SizedBox(height: 26), |
| 31 | OfficialThemeGrid( | 35 | OfficialThemeGrid( |
| @@ -18,7 +18,7 @@ typedef AppPigeonPlatformProvider = AppPigeonPlatform Function(); | @@ -18,7 +18,7 @@ typedef AppPigeonPlatformProvider = AppPigeonPlatform Function(); | ||
| 18 | 18 | ||
| 19 | AppPigeonPlatform resolveAppPigeonPlatform({TargetPlatform? targetPlatform}) { | 19 | AppPigeonPlatform resolveAppPigeonPlatform({TargetPlatform? targetPlatform}) { |
| 20 | final platform = targetPlatform ?? defaultTargetPlatform; | 20 | final platform = targetPlatform ?? defaultTargetPlatform; |
| 21 | - if (platform == TargetPlatform.ohos) { | 21 | + if (platform.name == 'ohos') { |
| 22 | return AppPigeonPlatform.ohos; | 22 | return AppPigeonPlatform.ohos; |
| 23 | } | 23 | } |
| 24 | if (platform == TargetPlatform.iOS) { | 24 | if (platform == TargetPlatform.iOS) { |
| @@ -192,26 +192,22 @@ class AppleHealthRawDataCoreService { | @@ -192,26 +192,22 @@ class AppleHealthRawDataCoreService { | ||
| 192 | } | 192 | } |
| 193 | 193 | ||
| 194 | Future<bool> shareNativeAppleHealthObserverRecord() async { | 194 | Future<bool> shareNativeAppleHealthObserverRecord() async { |
| 195 | - if (!_isDebug) return false; | ||
| 196 | return _rawDataApi.shareNativeAppleHealthObserverRecord(); | 195 | return _rawDataApi.shareNativeAppleHealthObserverRecord(); |
| 197 | } | 196 | } |
| 198 | 197 | ||
| 199 | Future<bool> shareFlutterObserverRecord() async { | 198 | Future<bool> shareFlutterObserverRecord() async { |
| 200 | - if (!_isDebug) return false; | ||
| 201 | return _rawDataApi.shareFlutterObserverRecord(); | 199 | return _rawDataApi.shareFlutterObserverRecord(); |
| 202 | } | 200 | } |
| 203 | 201 | ||
| 204 | Future<bool> shareUploadTaskRecord() async { | 202 | Future<bool> shareUploadTaskRecord() async { |
| 205 | - if (!_isDebug) return false; | ||
| 206 | return _rawDataApi.shareUploadTaskRecord(); | 203 | return _rawDataApi.shareUploadTaskRecord(); |
| 207 | } | 204 | } |
| 208 | 205 | ||
| 209 | Future<String> readLocalNotificationDebugLogText() { | 206 | Future<String> readLocalNotificationDebugLogText() { |
| 210 | - return _localNotificationDebugStore.readText(isDebug: _isDebug); | 207 | + return _localNotificationDebugStore.readText(); |
| 211 | } | 208 | } |
| 212 | 209 | ||
| 213 | Future<bool> shareLocalNotificationDebugRecord() async { | 210 | Future<bool> shareLocalNotificationDebugRecord() async { |
| 214 | - if (!_isDebug) return false; | ||
| 215 | return _shareNativeLocalNotificationDebugRecord(); | 211 | return _shareNativeLocalNotificationDebugRecord(); |
| 216 | } | 212 | } |
| 217 | 213 | ||
| @@ -1350,7 +1346,6 @@ class AppleHealthRawDataCoreService { | @@ -1350,7 +1346,6 @@ class AppleHealthRawDataCoreService { | ||
| 1350 | required String apiName, | 1346 | required String apiName, |
| 1351 | required Object? result, | 1347 | required Object? result, |
| 1352 | }) async { | 1348 | }) async { |
| 1353 | - if (!_isDebug) return; | ||
| 1354 | final file = await _uploadApiLogFile(); | 1349 | final file = await _uploadApiLogFile(); |
| 1355 | await file.parent.create(recursive: true); | 1350 | await file.parent.create(recursive: true); |
| 1356 | final line = | 1351 | final line = |
| @@ -1359,7 +1354,6 @@ class AppleHealthRawDataCoreService { | @@ -1359,7 +1354,6 @@ class AppleHealthRawDataCoreService { | ||
| 1359 | } | 1354 | } |
| 1360 | 1355 | ||
| 1361 | Future<void> _saveNativeCallFlutterChange(List<int>? dataTypes) async { | 1356 | Future<void> _saveNativeCallFlutterChange(List<int>? dataTypes) async { |
| 1362 | - if (!_isDebug) return; | ||
| 1363 | try { | 1357 | try { |
| 1364 | await _rawDataApi.saveNativeCallFlutterChange( | 1358 | await _rawDataApi.saveNativeCallFlutterChange( |
| 1365 | relativeDataTypes: dataTypes ?? const <int>[], | 1359 | relativeDataTypes: dataTypes ?? const <int>[], |
| @@ -1370,7 +1364,6 @@ class AppleHealthRawDataCoreService { | @@ -1370,7 +1364,6 @@ class AppleHealthRawDataCoreService { | ||
| 1370 | } | 1364 | } |
| 1371 | 1365 | ||
| 1372 | Future<void> _saveFlutterCaculateFinished(List<int> dataTypes) async { | 1366 | Future<void> _saveFlutterCaculateFinished(List<int> dataTypes) async { |
| 1373 | - if (!_isDebug) return; | ||
| 1374 | try { | 1367 | try { |
| 1375 | await _rawDataApi.saveFlutterCaculateFinished( | 1368 | await _rawDataApi.saveFlutterCaculateFinished( |
| 1376 | relativeDataTypes: dataTypes, | 1369 | relativeDataTypes: dataTypes, |
| @@ -1383,7 +1376,6 @@ class AppleHealthRawDataCoreService { | @@ -1383,7 +1376,6 @@ class AppleHealthRawDataCoreService { | ||
| 1383 | Future<void> _saveLocalNotificationDebugEvent( | 1376 | Future<void> _saveLocalNotificationDebugEvent( |
| 1384 | Map<String, Object?> event, | 1377 | Map<String, Object?> event, |
| 1385 | ) async { | 1378 | ) async { |
| 1386 | - if (!_isDebug) return; | ||
| 1387 | try { | 1379 | try { |
| 1388 | await _localNotificationDebugStore.append(event); | 1380 | await _localNotificationDebugStore.append(event); |
| 1389 | await _saveNativeLocalNotificationDebugEvent(event); | 1381 | await _saveNativeLocalNotificationDebugEvent(event); |
| @@ -2058,7 +2050,7 @@ class HealthRawStressLocalStore { | @@ -2058,7 +2050,7 @@ class HealthRawStressLocalStore { | ||
| 2058 | final db = await factory.openDatabase( | 2050 | final db = await factory.openDatabase( |
| 2059 | path, | 2051 | path, |
| 2060 | options: OpenDatabaseOptions( | 2052 | options: OpenDatabaseOptions( |
| 2061 | - version: 7, | 2053 | + version: 8, |
| 2062 | onCreate: (db, version) async { | 2054 | onCreate: (db, version) async { |
| 2063 | await _createTables(db); | 2055 | await _createTables(db); |
| 2064 | }, | 2056 | }, |
| @@ -2082,6 +2074,9 @@ class HealthRawStressLocalStore { | @@ -2082,6 +2074,9 @@ class HealthRawStressLocalStore { | ||
| 2082 | if (oldVersion < 7) { | 2074 | if (oldVersion < 7) { |
| 2083 | await _createSleepResultsTable(db); | 2075 | await _createSleepResultsTable(db); |
| 2084 | } | 2076 | } |
| 2077 | + if (oldVersion < 8) { | ||
| 2078 | + await _addUpdateTimeColumns(db); | ||
| 2079 | + } | ||
| 2085 | }, | 2080 | }, |
| 2086 | ), | 2081 | ), |
| 2087 | ); | 2082 | ); |
| @@ -2107,7 +2102,8 @@ CREATE TABLE IF NOT EXISTS $hrvResultsTable ( | @@ -2107,7 +2102,8 @@ CREATE TABLE IF NOT EXISTS $hrvResultsTable ( | ||
| 2107 | is_workout_recovery INTEGER NOT NULL DEFAULT 0, | 2102 | is_workout_recovery INTEGER NOT NULL DEFAULT 0, |
| 2108 | is_sleep_likely INTEGER NOT NULL DEFAULT 0, | 2103 | is_sleep_likely INTEGER NOT NULL DEFAULT 0, |
| 2109 | is_suspected_activity INTEGER NOT NULL DEFAULT 0, | 2104 | is_suspected_activity INTEGER NOT NULL DEFAULT 0, |
| 2110 | - uploaded INTEGER NOT NULL DEFAULT 0 | 2105 | + uploaded INTEGER NOT NULL DEFAULT 0, |
| 2106 | + update_time INTEGER NOT NULL DEFAULT 0 | ||
| 2111 | ) | 2107 | ) |
| 2112 | '''); | 2108 | '''); |
| 2113 | await db.execute(''' | 2109 | await db.execute(''' |
| @@ -2122,7 +2118,8 @@ CREATE TABLE IF NOT EXISTS $realtimeStressResultsTable ( | @@ -2122,7 +2118,8 @@ CREATE TABLE IF NOT EXISTS $realtimeStressResultsTable ( | ||
| 2122 | is_workout_recovery INTEGER NOT NULL DEFAULT 0, | 2118 | is_workout_recovery INTEGER NOT NULL DEFAULT 0, |
| 2123 | is_sleep_likely INTEGER NOT NULL DEFAULT 0, | 2119 | is_sleep_likely INTEGER NOT NULL DEFAULT 0, |
| 2124 | is_suspected_activity INTEGER NOT NULL DEFAULT 0, | 2120 | is_suspected_activity INTEGER NOT NULL DEFAULT 0, |
| 2125 | - uploaded INTEGER NOT NULL DEFAULT 0 | 2121 | + uploaded INTEGER NOT NULL DEFAULT 0, |
| 2122 | + update_time INTEGER NOT NULL DEFAULT 0 | ||
| 2126 | ) | 2123 | ) |
| 2127 | '''); | 2124 | '''); |
| 2128 | await _createDailyStressTable(db); | 2125 | await _createDailyStressTable(db); |
| @@ -2138,7 +2135,8 @@ CREATE TABLE IF NOT EXISTS $dailyStressResultsTable ( | @@ -2138,7 +2135,8 @@ CREATE TABLE IF NOT EXISTS $dailyStressResultsTable ( | ||
| 2138 | stress_score INTEGER NOT NULL, | 2135 | stress_score INTEGER NOT NULL, |
| 2139 | state INTEGER NOT NULL, | 2136 | state INTEGER NOT NULL, |
| 2140 | data_time INTEGER NOT NULL, | 2137 | data_time INTEGER NOT NULL, |
| 2141 | - uploaded INTEGER NOT NULL DEFAULT 0 | 2138 | + uploaded INTEGER NOT NULL DEFAULT 0, |
| 2139 | + update_time INTEGER NOT NULL DEFAULT 0 | ||
| 2142 | ) | 2140 | ) |
| 2143 | '''); | 2141 | '''); |
| 2144 | } | 2142 | } |
| @@ -2154,11 +2152,29 @@ CREATE TABLE IF NOT EXISTS $sleepResultsTable ( | @@ -2154,11 +2152,29 @@ CREATE TABLE IF NOT EXISTS $sleepResultsTable ( | ||
| 2154 | in_bed_minutes INTEGER NOT NULL, | 2152 | in_bed_minutes INTEGER NOT NULL, |
| 2155 | awak_minutes INTEGER NOT NULL, | 2153 | awak_minutes INTEGER NOT NULL, |
| 2156 | sleep_minutes INTEGER NOT NULL, | 2154 | sleep_minutes INTEGER NOT NULL, |
| 2157 | - uploaded INTEGER NOT NULL DEFAULT 0 | 2155 | + uploaded INTEGER NOT NULL DEFAULT 0, |
| 2156 | + update_time INTEGER NOT NULL DEFAULT 0 | ||
| 2158 | ) | 2157 | ) |
| 2159 | '''); | 2158 | '''); |
| 2160 | } | 2159 | } |
| 2161 | 2160 | ||
| 2161 | + Future<void> _addUpdateTimeColumns(DatabaseExecutor db) async { | ||
| 2162 | + for (final table in const [ | ||
| 2163 | + hrvResultsTable, | ||
| 2164 | + realtimeStressResultsTable, | ||
| 2165 | + dailyStressResultsTable, | ||
| 2166 | + sleepResultsTable, | ||
| 2167 | + ]) { | ||
| 2168 | + try { | ||
| 2169 | + await db.execute( | ||
| 2170 | + 'ALTER TABLE $table ADD COLUMN update_time INTEGER NOT NULL DEFAULT 0', | ||
| 2171 | + ); | ||
| 2172 | + } on DatabaseException catch (error) { | ||
| 2173 | + if (!error.isDuplicateColumnError()) rethrow; | ||
| 2174 | + } | ||
| 2175 | + } | ||
| 2176 | + } | ||
| 2177 | + | ||
| 2162 | Future<void> _addFlagColumns(DatabaseExecutor db, String table) async { | 2178 | Future<void> _addFlagColumns(DatabaseExecutor db, String table) async { |
| 2163 | for (final column in const [ | 2179 | for (final column in const [ |
| 2164 | 'is_workout', | 2180 | 'is_workout', |
| @@ -2320,6 +2336,7 @@ CREATE TABLE IF NOT EXISTS $sleepResultsTable ( | @@ -2320,6 +2336,7 @@ CREATE TABLE IF NOT EXISTS $sleepResultsTable ( | ||
| 2320 | 'baseline_resting_hr': point.baselineRestingHr, | 2336 | 'baseline_resting_hr': point.baselineRestingHr, |
| 2321 | ..._flagsRow(point.flags), | 2337 | ..._flagsRow(point.flags), |
| 2322 | 'uploaded': point.uploaded ? 1 : 0, | 2338 | 'uploaded': point.uploaded ? 1 : 0, |
| 2339 | + 'update_time': _currentUnixSeconds(), | ||
| 2323 | }; | 2340 | }; |
| 2324 | } | 2341 | } |
| 2325 | 2342 | ||
| @@ -2333,6 +2350,7 @@ CREATE TABLE IF NOT EXISTS $sleepResultsTable ( | @@ -2333,6 +2350,7 @@ CREATE TABLE IF NOT EXISTS $sleepResultsTable ( | ||
| 2333 | 'source_end_time': point.sourceEndTime, | 2350 | 'source_end_time': point.sourceEndTime, |
| 2334 | ..._flagsRow(point.flags), | 2351 | ..._flagsRow(point.flags), |
| 2335 | 'uploaded': point.uploaded ? 1 : 0, | 2352 | 'uploaded': point.uploaded ? 1 : 0, |
| 2353 | + 'update_time': _currentUnixSeconds(), | ||
| 2336 | }; | 2354 | }; |
| 2337 | } | 2355 | } |
| 2338 | 2356 | ||
| @@ -2345,6 +2363,7 @@ CREATE TABLE IF NOT EXISTS $sleepResultsTable ( | @@ -2345,6 +2363,7 @@ CREATE TABLE IF NOT EXISTS $sleepResultsTable ( | ||
| 2345 | 'state': point.state.value, | 2363 | 'state': point.state.value, |
| 2346 | 'data_time': point.dataTime, | 2364 | 'data_time': point.dataTime, |
| 2347 | 'uploaded': point.uploaded ? 1 : 0, | 2365 | 'uploaded': point.uploaded ? 1 : 0, |
| 2366 | + 'update_time': _currentUnixSeconds(), | ||
| 2348 | }; | 2367 | }; |
| 2349 | } | 2368 | } |
| 2350 | 2369 | ||
| @@ -2359,6 +2378,7 @@ CREATE TABLE IF NOT EXISTS $sleepResultsTable ( | @@ -2359,6 +2378,7 @@ CREATE TABLE IF NOT EXISTS $sleepResultsTable ( | ||
| 2359 | 'awak_minutes': result.awakMinutes, | 2378 | 'awak_minutes': result.awakMinutes, |
| 2360 | 'sleep_minutes': result.sleepMinutes, | 2379 | 'sleep_minutes': result.sleepMinutes, |
| 2361 | 'uploaded': result.uploaded ? 1 : 0, | 2380 | 'uploaded': result.uploaded ? 1 : 0, |
| 2381 | + 'update_time': _currentUnixSeconds(), | ||
| 2362 | }; | 2382 | }; |
| 2363 | } | 2383 | } |
| 2364 | 2384 | ||
| @@ -2389,6 +2409,12 @@ CREATE TABLE IF NOT EXISTS $sleepResultsTable ( | @@ -2389,6 +2409,12 @@ CREATE TABLE IF NOT EXISTS $sleepResultsTable ( | ||
| 2389 | final existingRow = existing.first; | 2409 | final existingRow = existing.first; |
| 2390 | if (_matchesStoredValues( | 2410 | if (_matchesStoredValues( |
| 2391 | existingRow, row, _rawResultStoredValueKeys(row))) { | 2411 | existingRow, row, _rawResultStoredValueKeys(row))) { |
| 2412 | + await db.update( | ||
| 2413 | + table, | ||
| 2414 | + <String, Object?>{'update_time': row['update_time']}, | ||
| 2415 | + where: 'raw_end_time = ?', | ||
| 2416 | + whereArgs: [row['raw_end_time']], | ||
| 2417 | + ); | ||
| 2392 | return; | 2418 | return; |
| 2393 | } | 2419 | } |
| 2394 | final uploadPayloadChanged = !_matchesStoredValues( | 2420 | final uploadPayloadChanged = !_matchesStoredValues( |
| @@ -2419,6 +2445,7 @@ CREATE TABLE IF NOT EXISTS $sleepResultsTable ( | @@ -2419,6 +2445,7 @@ CREATE TABLE IF NOT EXISTS $sleepResultsTable ( | ||
| 2419 | 'is_sleep_likely': row['is_sleep_likely'], | 2445 | 'is_sleep_likely': row['is_sleep_likely'], |
| 2420 | 'is_suspected_activity': row['is_suspected_activity'], | 2446 | 'is_suspected_activity': row['is_suspected_activity'], |
| 2421 | 'uploaded': uploadPayloadChanged ? 0 : existingRow['uploaded'], | 2447 | 'uploaded': uploadPayloadChanged ? 0 : existingRow['uploaded'], |
| 2448 | + 'update_time': row['update_time'], | ||
| 2422 | }, | 2449 | }, |
| 2423 | where: 'raw_end_time = ?', | 2450 | where: 'raw_end_time = ?', |
| 2424 | whereArgs: [row['raw_end_time']], | 2451 | whereArgs: [row['raw_end_time']], |
| @@ -2458,6 +2485,7 @@ CREATE TABLE IF NOT EXISTS $sleepResultsTable ( | @@ -2458,6 +2485,7 @@ CREATE TABLE IF NOT EXISTS $sleepResultsTable ( | ||
| 2458 | 'state': row['state'], | 2485 | 'state': row['state'], |
| 2459 | 'data_time': row['data_time'], | 2486 | 'data_time': row['data_time'], |
| 2460 | 'uploaded': isToday ? 0 : (valueChanged ? 0 : existingRow['uploaded']), | 2487 | 'uploaded': isToday ? 0 : (valueChanged ? 0 : existingRow['uploaded']), |
| 2488 | + 'update_time': row['update_time'], | ||
| 2461 | }, | 2489 | }, |
| 2462 | where: 'date = ?', | 2490 | where: 'date = ?', |
| 2463 | whereArgs: [row['date']], | 2491 | whereArgs: [row['date']], |
| @@ -2503,12 +2531,17 @@ CREATE TABLE IF NOT EXISTS $sleepResultsTable ( | @@ -2503,12 +2531,17 @@ CREATE TABLE IF NOT EXISTS $sleepResultsTable ( | ||
| 2503 | 'awak_minutes': row['awak_minutes'], | 2531 | 'awak_minutes': row['awak_minutes'], |
| 2504 | 'sleep_minutes': row['sleep_minutes'], | 2532 | 'sleep_minutes': row['sleep_minutes'], |
| 2505 | 'uploaded': valueChanged ? 0 : existingRow['uploaded'], | 2533 | 'uploaded': valueChanged ? 0 : existingRow['uploaded'], |
| 2534 | + 'update_time': row['update_time'], | ||
| 2506 | }, | 2535 | }, |
| 2507 | where: 'date = ?', | 2536 | where: 'date = ?', |
| 2508 | whereArgs: [row['date']], | 2537 | whereArgs: [row['date']], |
| 2509 | ); | 2538 | ); |
| 2510 | } | 2539 | } |
| 2511 | 2540 | ||
| 2541 | + int _currentUnixSeconds() { | ||
| 2542 | + return DateTime.now().millisecondsSinceEpoch ~/ 1000; | ||
| 2543 | + } | ||
| 2544 | + | ||
| 2512 | List<String> _rawResultStoredValueKeys(Map<String, Object?> row) { | 2545 | List<String> _rawResultStoredValueKeys(Map<String, Object?> row) { |
| 2513 | return <String>[ | 2546 | return <String>[ |
| 2514 | 'user_id', | 2547 | 'user_id', |
lib/core/services/raw_data_service/platform_ios/apple_health_raw_local_notification_debug_store.dart
| @@ -35,10 +35,7 @@ class HealthRawLocalNotificationDebugStore { | @@ -35,10 +35,7 @@ class HealthRawLocalNotificationDebugStore { | ||
| 35 | ); | 35 | ); |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | - Future<String> readText({required bool isDebug}) async { | ||
| 39 | - if (!isDebug) { | ||
| 40 | - return '当前非 Debug 模式,未记录本地推送诊断日志'; | ||
| 41 | - } | 38 | + Future<String> readText() async { |
| 42 | final file = await _file(); | 39 | final file = await _file(); |
| 43 | if (!await file.exists()) { | 40 | if (!await file.exists()) { |
| 44 | return '暂无本地推送诊断日志'; | 41 | return '暂无本地推送诊断日志'; |
| @@ -181,10 +181,10 @@ packages: | @@ -181,10 +181,10 @@ packages: | ||
| 181 | dependency: transitive | 181 | dependency: transitive |
| 182 | description: | 182 | description: |
| 183 | name: cross_file | 183 | name: cross_file |
| 184 | - sha256: "92c9c43c383bfa1c32079d3bc492d55d6d4318044b7b47edaff8971cbb555c51" | 184 | + sha256: f141ea4f277af142a0356955707f6556f37b03947d39d55585981a06ca437bd6 |
| 185 | url: "https://pub.dev" | 185 | url: "https://pub.dev" |
| 186 | source: hosted | 186 | source: hosted |
| 187 | - version: "0.3.5+4" | 187 | + version: "0.3.5+5" |
| 188 | crypto: | 188 | crypto: |
| 189 | dependency: "direct main" | 189 | dependency: "direct main" |
| 190 | description: | 190 | description: |
| @@ -391,6 +391,71 @@ void main() { | @@ -391,6 +391,71 @@ void main() { | ||
| 391 | expect(daily.single.uploaded, isTrue); | 391 | expect(daily.single.uploaded, isTrue); |
| 392 | }); | 392 | }); |
| 393 | 393 | ||
| 394 | + test('local result rows include update time and refresh on upsert', () async { | ||
| 395 | + const base = 1800000000; | ||
| 396 | + final store = _MemoryHealthRawStressLocalStore(); | ||
| 397 | + await store.upsertResult( | ||
| 398 | + HealthRawStressCalculationResult( | ||
| 399 | + userId: 42, | ||
| 400 | + hrvStressPoints: [_hrvStressPoint(base + 10)], | ||
| 401 | + realtimeStressPoints: [_realtimeStressPoint(base + 20)], | ||
| 402 | + dailyStressPoints: const <HealthRawDailyStressPoint>[], | ||
| 403 | + ), | ||
| 404 | + ); | ||
| 405 | + await store.upsertDailyStressPoints( | ||
| 406 | + userId: 42, | ||
| 407 | + points: [ | ||
| 408 | + HealthRawDailyStressPoint( | ||
| 409 | + userId: 42, | ||
| 410 | + date: 20260101, | ||
| 411 | + stressValue: 40, | ||
| 412 | + stressScore: 40, | ||
| 413 | + state: HealthRawStressState.normal, | ||
| 414 | + dataTime: base + 20, | ||
| 415 | + ), | ||
| 416 | + ], | ||
| 417 | + ); | ||
| 418 | + await store.upsertSleepResults( | ||
| 419 | + userId: 42, | ||
| 420 | + results: const [ | ||
| 421 | + HealthRawSleepResult( | ||
| 422 | + userId: 42, | ||
| 423 | + date: base + 30, | ||
| 424 | + startDate: base, | ||
| 425 | + sleepScore: 80, | ||
| 426 | + sleepState: 2, | ||
| 427 | + inBedMinutes: 480, | ||
| 428 | + awakMinutes: 10, | ||
| 429 | + sleepMinutes: 470, | ||
| 430 | + ), | ||
| 431 | + ], | ||
| 432 | + ); | ||
| 433 | + final firstRows = await store.debugQueryAllRows(42); | ||
| 434 | + final firstHrvUpdateTime = firstRows.hrvRows.single['update_time'] as int; | ||
| 435 | + | ||
| 436 | + expect(firstHrvUpdateTime, greaterThan(0)); | ||
| 437 | + expect(firstRows.realtimeRows.single['update_time'], greaterThan(0)); | ||
| 438 | + expect(firstRows.dailyStressRows.single['update_time'], greaterThan(0)); | ||
| 439 | + expect(firstRows.sleepRows.single['update_time'], greaterThan(0)); | ||
| 440 | + | ||
| 441 | + await store.markHrvStressUploaded(rawEndTimes: [base + 10], userId: 42); | ||
| 442 | + await store.upsertResult( | ||
| 443 | + HealthRawStressCalculationResult( | ||
| 444 | + userId: 42, | ||
| 445 | + hrvStressPoints: [_hrvStressPoint(base + 10)], | ||
| 446 | + realtimeStressPoints: const <HealthRawRealtimeStressPoint>[], | ||
| 447 | + dailyStressPoints: const <HealthRawDailyStressPoint>[], | ||
| 448 | + ), | ||
| 449 | + ); | ||
| 450 | + final secondRows = await store.debugQueryAllRows(42); | ||
| 451 | + | ||
| 452 | + expect( | ||
| 453 | + secondRows.hrvRows.single['update_time'], | ||
| 454 | + greaterThan(firstHrvUpdateTime), | ||
| 455 | + ); | ||
| 456 | + expect(secondRows.hrvRows.single['uploaded'], 1); | ||
| 457 | + }); | ||
| 458 | + | ||
| 394 | test( | 459 | test( |
| 395 | 'startCoreCaculate skips raw reads when health auth and local data are missing', | 460 | 'startCoreCaculate skips raw reads when health auth and local data are missing', |
| 396 | () async { | 461 | () async { |
| @@ -1185,7 +1250,12 @@ class _MemoryHealthRawStressLocalStore extends HealthRawStressLocalStore { | @@ -1185,7 +1250,12 @@ class _MemoryHealthRawStressLocalStore extends HealthRawStressLocalStore { | ||
| 1185 | final Map<int, List<HealthRawRealtimeStressPoint>> _realtime = {}; | 1250 | final Map<int, List<HealthRawRealtimeStressPoint>> _realtime = {}; |
| 1186 | final Map<int, List<HealthRawDailyStressPoint>> _daily = {}; | 1251 | final Map<int, List<HealthRawDailyStressPoint>> _daily = {}; |
| 1187 | final Map<int, List<HealthRawSleepResult>> _sleep = {}; | 1252 | final Map<int, List<HealthRawSleepResult>> _sleep = {}; |
| 1253 | + final Map<int, Map<int, int>> _hrvUpdateTimes = {}; | ||
| 1254 | + final Map<int, Map<int, int>> _realtimeUpdateTimes = {}; | ||
| 1255 | + final Map<int, Map<int, int>> _dailyUpdateTimes = {}; | ||
| 1256 | + final Map<int, Map<int, int>> _sleepUpdateTimes = {}; | ||
| 1188 | final List<String> operationLog; | 1257 | final List<String> operationLog; |
| 1258 | + var _updateTimeClock = 1; | ||
| 1189 | var realtimeNotificationWindowQueryCount = 0; | 1259 | var realtimeNotificationWindowQueryCount = 0; |
| 1190 | 1260 | ||
| 1191 | void insertDailyStress(HealthRawDailyStressPoint point) { | 1261 | void insertDailyStress(HealthRawDailyStressPoint point) { |
| @@ -1196,6 +1266,8 @@ class _MemoryHealthRawStressLocalStore extends HealthRawStressLocalStore { | @@ -1196,6 +1266,8 @@ class _MemoryHealthRawStressLocalStore extends HealthRawStressLocalStore { | ||
| 1196 | byDate[point.date] = point; | 1266 | byDate[point.date] = point; |
| 1197 | _daily[point.userId] = byDate.values.toList() | 1267 | _daily[point.userId] = byDate.values.toList() |
| 1198 | ..sort((a, b) => a.date.compareTo(b.date)); | 1268 | ..sort((a, b) => a.date.compareTo(b.date)); |
| 1269 | + _dailyUpdateTimes.putIfAbsent( | ||
| 1270 | + point.userId, () => <int, int>{})[point.date] = _nextUpdateTime(); | ||
| 1199 | } | 1271 | } |
| 1200 | 1272 | ||
| 1201 | @override | 1273 | @override |
| @@ -1232,6 +1304,9 @@ class _MemoryHealthRawStressLocalStore extends HealthRawStressLocalStore { | @@ -1232,6 +1304,9 @@ class _MemoryHealthRawStressLocalStore extends HealthRawStressLocalStore { | ||
| 1232 | flags: point.flags, | 1304 | flags: point.flags, |
| 1233 | uploaded: same ? existing.uploaded : false, | 1305 | uploaded: same ? existing.uploaded : false, |
| 1234 | ); | 1306 | ); |
| 1307 | + _hrvUpdateTimes.putIfAbsent( | ||
| 1308 | + point.userId, () => <int, int>{})[point.rawEndTime] = | ||
| 1309 | + _nextUpdateTime(); | ||
| 1235 | } | 1310 | } |
| 1236 | _hrv[result.userId] = hrvByTime.values.toList() | 1311 | _hrv[result.userId] = hrvByTime.values.toList() |
| 1237 | ..sort((a, b) => a.rawEndTime.compareTo(b.rawEndTime)); | 1312 | ..sort((a, b) => a.rawEndTime.compareTo(b.rawEndTime)); |
| @@ -1255,6 +1330,9 @@ class _MemoryHealthRawStressLocalStore extends HealthRawStressLocalStore { | @@ -1255,6 +1330,9 @@ class _MemoryHealthRawStressLocalStore extends HealthRawStressLocalStore { | ||
| 1255 | flags: point.flags, | 1330 | flags: point.flags, |
| 1256 | uploaded: same ? existing.uploaded : false, | 1331 | uploaded: same ? existing.uploaded : false, |
| 1257 | ); | 1332 | ); |
| 1333 | + _realtimeUpdateTimes.putIfAbsent( | ||
| 1334 | + point.userId, () => <int, int>{})[point.rawEndTime] = | ||
| 1335 | + _nextUpdateTime(); | ||
| 1258 | } | 1336 | } |
| 1259 | _realtime[result.userId] = realtimeByTime.values.toList() | 1337 | _realtime[result.userId] = realtimeByTime.values.toList() |
| 1260 | ..sort((a, b) => a.rawEndTime.compareTo(b.rawEndTime)); | 1338 | ..sort((a, b) => a.rawEndTime.compareTo(b.rawEndTime)); |
| @@ -1287,6 +1365,8 @@ class _MemoryHealthRawStressLocalStore extends HealthRawStressLocalStore { | @@ -1287,6 +1365,8 @@ class _MemoryHealthRawStressLocalStore extends HealthRawStressLocalStore { | ||
| 1287 | dataTime: point.dataTime, | 1365 | dataTime: point.dataTime, |
| 1288 | uploaded: isToday ? false : (same ? existing.uploaded : false), | 1366 | uploaded: isToday ? false : (same ? existing.uploaded : false), |
| 1289 | ); | 1367 | ); |
| 1368 | + _dailyUpdateTimes.putIfAbsent( | ||
| 1369 | + point.userId, () => <int, int>{})[point.date] = _nextUpdateTime(); | ||
| 1290 | } | 1370 | } |
| 1291 | _daily[userId] = byDate.values.toList() | 1371 | _daily[userId] = byDate.values.toList() |
| 1292 | ..sort((a, b) => a.date.compareTo(b.date)); | 1372 | ..sort((a, b) => a.date.compareTo(b.date)); |
| @@ -1303,6 +1383,8 @@ class _MemoryHealthRawStressLocalStore extends HealthRawStressLocalStore { | @@ -1303,6 +1383,8 @@ class _MemoryHealthRawStressLocalStore extends HealthRawStressLocalStore { | ||
| 1303 | }; | 1383 | }; |
| 1304 | for (final result in results) { | 1384 | for (final result in results) { |
| 1305 | byDate[result.date] = result; | 1385 | byDate[result.date] = result; |
| 1386 | + _sleepUpdateTimes.putIfAbsent( | ||
| 1387 | + result.userId, () => <int, int>{})[result.date] = _nextUpdateTime(); | ||
| 1306 | } | 1388 | } |
| 1307 | _sleep[userId] = byDate.values.toList() | 1389 | _sleep[userId] = byDate.values.toList() |
| 1308 | ..sort((a, b) => a.date.compareTo(b.date)); | 1390 | ..sort((a, b) => a.date.compareTo(b.date)); |
| @@ -1630,6 +1712,7 @@ class _MemoryHealthRawStressLocalStore extends HealthRawStressLocalStore { | @@ -1630,6 +1712,7 @@ class _MemoryHealthRawStressLocalStore extends HealthRawStressLocalStore { | ||
| 1630 | 'is_sleep_likely': point.flags.isSleepLikely ? 1 : 0, | 1712 | 'is_sleep_likely': point.flags.isSleepLikely ? 1 : 0, |
| 1631 | 'is_suspected_activity': point.flags.isSuspectedActivity ? 1 : 0, | 1713 | 'is_suspected_activity': point.flags.isSuspectedActivity ? 1 : 0, |
| 1632 | 'uploaded': point.uploaded ? 1 : 0, | 1714 | 'uploaded': point.uploaded ? 1 : 0, |
| 1715 | + 'update_time': _hrvUpdateTimes[point.userId]?[point.rawEndTime] ?? 0, | ||
| 1633 | }; | 1716 | }; |
| 1634 | } | 1717 | } |
| 1635 | 1718 | ||
| @@ -1646,6 +1729,7 @@ class _MemoryHealthRawStressLocalStore extends HealthRawStressLocalStore { | @@ -1646,6 +1729,7 @@ class _MemoryHealthRawStressLocalStore extends HealthRawStressLocalStore { | ||
| 1646 | 'is_sleep_likely': point.flags.isSleepLikely ? 1 : 0, | 1729 | 'is_sleep_likely': point.flags.isSleepLikely ? 1 : 0, |
| 1647 | 'is_suspected_activity': point.flags.isSuspectedActivity ? 1 : 0, | 1730 | 'is_suspected_activity': point.flags.isSuspectedActivity ? 1 : 0, |
| 1648 | 'uploaded': point.uploaded ? 1 : 0, | 1731 | 'uploaded': point.uploaded ? 1 : 0, |
| 1732 | + 'update_time': _realtimeUpdateTimes[point.userId]?[point.rawEndTime] ?? 0, | ||
| 1649 | }; | 1733 | }; |
| 1650 | } | 1734 | } |
| 1651 | 1735 | ||
| @@ -1658,6 +1742,7 @@ class _MemoryHealthRawStressLocalStore extends HealthRawStressLocalStore { | @@ -1658,6 +1742,7 @@ class _MemoryHealthRawStressLocalStore extends HealthRawStressLocalStore { | ||
| 1658 | 'state': point.state.value, | 1742 | 'state': point.state.value, |
| 1659 | 'data_time': point.dataTime, | 1743 | 'data_time': point.dataTime, |
| 1660 | 'uploaded': point.uploaded ? 1 : 0, | 1744 | 'uploaded': point.uploaded ? 1 : 0, |
| 1745 | + 'update_time': _dailyUpdateTimes[point.userId]?[point.date] ?? 0, | ||
| 1661 | }; | 1746 | }; |
| 1662 | } | 1747 | } |
| 1663 | 1748 | ||
| @@ -1672,9 +1757,12 @@ class _MemoryHealthRawStressLocalStore extends HealthRawStressLocalStore { | @@ -1672,9 +1757,12 @@ class _MemoryHealthRawStressLocalStore extends HealthRawStressLocalStore { | ||
| 1672 | 'awak_minutes': result.awakMinutes, | 1757 | 'awak_minutes': result.awakMinutes, |
| 1673 | 'sleep_minutes': result.sleepMinutes, | 1758 | 'sleep_minutes': result.sleepMinutes, |
| 1674 | 'uploaded': result.uploaded ? 1 : 0, | 1759 | 'uploaded': result.uploaded ? 1 : 0, |
| 1760 | + 'update_time': _sleepUpdateTimes[result.userId]?[result.date] ?? 0, | ||
| 1675 | }; | 1761 | }; |
| 1676 | } | 1762 | } |
| 1677 | 1763 | ||
| 1764 | + int _nextUpdateTime() => _updateTimeClock++; | ||
| 1765 | + | ||
| 1678 | int _todayDateKey() { | 1766 | int _todayDateKey() { |
| 1679 | final now = DateTime.now(); | 1767 | final now = DateTime.now(); |
| 1680 | return now.year * 10000 + now.month * 100 + now.day; | 1768 | return now.year * 10000 + now.month * 100 + now.day; |
-
mentioned in commit 4c43a3d4
-
Please register or login to post a comment