@kingstinct/react-native-healthkit 8.7.2 → 9.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ReactNativeHealthkit.podspec +36 -0
- package/app.plugin.js +43 -33
- package/ios/Bridge.h +8 -0
- package/ios/CategoryTypeModule.swift +128 -0
- package/ios/CharacteristicTypeModule.swift +78 -0
- package/ios/Constants.swift +2 -0
- package/ios/CoreModule.swift +376 -0
- package/ios/CorrelationTypeModule.swift +153 -0
- package/ios/HeartbeatSeriesModule.swift +189 -0
- package/ios/Helpers.swift +529 -251
- package/ios/QuantityTypeModule.swift +461 -0
- package/ios/Serializers.swift +211 -124
- package/ios/SourceProxy.swift +35 -0
- package/ios/StateOfMindModule.swift +160 -0
- package/ios/WorkoutProxy.swift +405 -0
- package/ios/WorkoutSessionModule.swift +182 -0
- package/ios/WorkoutsModule.swift +357 -0
- package/package.json +43 -127
- package/react-native.config.js +16 -0
- package/src/hooks/useHealthkitAuthorization.test.ts +47 -29
- package/src/hooks/useHealthkitAuthorization.ts +21 -15
- package/src/hooks/useIsHealthDataAvailable.test.ts +17 -7
- package/src/hooks/useIsHealthDataAvailable.ts +7 -7
- package/src/hooks/useMostRecentCategorySample.ts +10 -12
- package/src/hooks/useMostRecentQuantitySample.ts +17 -36
- package/src/hooks/useMostRecentWorkout.ts +16 -38
- package/src/hooks/useSources.ts +8 -12
- package/src/hooks/useStatisticsForQuantity.ts +19 -14
- package/src/hooks/useSubscribeToChanges.ts +9 -13
- package/src/index.ios.ts +232 -0
- package/src/index.ts +444 -0
- package/src/modules.ts +43 -0
- package/src/specs/CategoryTypeModule.nitro.ts +64 -0
- package/src/specs/CharacteristicTypeModule.nitro.ts +22 -0
- package/src/specs/CoreModule.nitro.ts +107 -0
- package/src/specs/CorrelationTypeModule.nitro.ts +23 -0
- package/src/specs/HeartbeatSeriesModule.nitro.ts +19 -0
- package/src/specs/QuantityTypeModule.nitro.ts +60 -0
- package/src/specs/SourceProxy.nitro.ts +13 -0
- package/src/specs/StateOfMindModule.nitro.ts +23 -0
- package/src/specs/WorkoutProxy.nitro.ts +18 -0
- package/src/specs/WorkoutSessionModule.nitro.ts +71 -0
- package/src/specs/WorkoutsModule.nitro.ts +32 -0
- package/src/test-setup.ts +68 -54
- package/src/test-utils.ts +3 -2
- package/src/types/Auth.ts +17 -0
- package/src/types/Background.ts +9 -0
- package/src/types/CategoryType.ts +249 -0
- package/src/types/CategoryTypeIdentifier.ts +99 -0
- package/src/types/Characteristics.ts +53 -0
- package/src/types/Constants.ts +25 -0
- package/src/types/CorrelationType.ts +31 -0
- package/src/types/Device.ts +13 -0
- package/src/types/HeartbeatSeries.ts +29 -0
- package/src/types/InterfaceVerification.ts +164 -0
- package/src/types/InterfaceVerificationExample.ts +89 -0
- package/src/types/QuantitySample.ts +30 -0
- package/src/types/QuantityType.ts +192 -0
- package/src/types/QuantityTypeIdentifier.ts +758 -0
- package/src/types/QueryOptions.ts +69 -0
- package/src/types/README-InterfaceVerification.md +103 -0
- package/src/types/Shared.ts +79 -0
- package/src/types/Source.ts +11 -0
- package/src/types/StateOfMind.ts +110 -0
- package/src/types/Subscriptons.ts +10 -0
- package/src/types/Units.ts +190 -0
- package/src/types/WeatherCondition.ts +31 -0
- package/src/types/WorkoutKit.ts +18 -0
- package/src/types/Workouts.ts +282 -0
- package/src/utils/getMostRecentCategorySample.ts +7 -11
- package/src/utils/getMostRecentQuantitySample.ts +8 -18
- package/src/utils/getMostRecentWorkout.ts +7 -17
- package/src/utils/getPreferredUnit.ts +12 -8
- package/src/utils/subscribeToChanges.ts +9 -26
- package/LICENSE +0 -21
- package/README.md +0 -179
- package/ios/ReactNativeHealthkit-Bridging-Header.h +0 -2
- package/ios/ReactNativeHealthkit.m +0 -271
- package/ios/ReactNativeHealthkit.swift +0 -2333
- package/ios/ReactNativeHealthkit.xcodeproj/project.pbxproj +0 -279
- package/kingstinct-react-native-healthkit.podspec +0 -21
- package/lib/commonjs/hooks/useHealthkitAuthorization.js +0 -39
- package/lib/commonjs/hooks/useHealthkitAuthorization.js.map +0 -1
- package/lib/commonjs/hooks/useHealthkitAuthorization.test.js +0 -72
- package/lib/commonjs/hooks/useHealthkitAuthorization.test.js.map +0 -1
- package/lib/commonjs/hooks/useIsHealthDataAvailable.js +0 -27
- package/lib/commonjs/hooks/useIsHealthDataAvailable.js.map +0 -1
- package/lib/commonjs/hooks/useIsHealthDataAvailable.test.js +0 -41
- package/lib/commonjs/hooks/useIsHealthDataAvailable.test.js.map +0 -1
- package/lib/commonjs/hooks/useMostRecentCategorySample.js +0 -23
- package/lib/commonjs/hooks/useMostRecentCategorySample.js.map +0 -1
- package/lib/commonjs/hooks/useMostRecentQuantitySample.js +0 -37
- package/lib/commonjs/hooks/useMostRecentQuantitySample.js.map +0 -1
- package/lib/commonjs/hooks/useMostRecentWorkout.js +0 -48
- package/lib/commonjs/hooks/useMostRecentWorkout.js.map +0 -1
- package/lib/commonjs/hooks/useSources.js +0 -22
- package/lib/commonjs/hooks/useSources.js.map +0 -1
- package/lib/commonjs/hooks/useStatisticsForQuantity.js +0 -28
- package/lib/commonjs/hooks/useStatisticsForQuantity.js.map +0 -1
- package/lib/commonjs/hooks/useSubscribeToChanges.js +0 -28
- package/lib/commonjs/hooks/useSubscribeToChanges.js.map +0 -1
- package/lib/commonjs/index.ios.js +0 -531
- package/lib/commonjs/index.ios.js.map +0 -1
- package/lib/commonjs/index.js +0 -22
- package/lib/commonjs/index.js.map +0 -1
- package/lib/commonjs/index.native.js +0 -235
- package/lib/commonjs/index.native.js.map +0 -1
- package/lib/commonjs/index.web.js +0 -22
- package/lib/commonjs/index.web.js.map +0 -1
- package/lib/commonjs/native-types.js +0 -1575
- package/lib/commonjs/native-types.js.map +0 -1
- package/lib/commonjs/test-setup.js +0 -57
- package/lib/commonjs/test-setup.js.map +0 -1
- package/lib/commonjs/test-utils.js +0 -18
- package/lib/commonjs/test-utils.js.map +0 -1
- package/lib/commonjs/types.js +0 -17
- package/lib/commonjs/types.js.map +0 -1
- package/lib/commonjs/utils/deleteQuantitySample.js +0 -11
- package/lib/commonjs/utils/deleteQuantitySample.js.map +0 -1
- package/lib/commonjs/utils/deleteSamples.js +0 -18
- package/lib/commonjs/utils/deleteSamples.js.map +0 -1
- package/lib/commonjs/utils/deleteWorkoutSample.js +0 -11
- package/lib/commonjs/utils/deleteWorkoutSample.js.map +0 -1
- package/lib/commonjs/utils/deserializeCategorySample.js +0 -13
- package/lib/commonjs/utils/deserializeCategorySample.js.map +0 -1
- package/lib/commonjs/utils/deserializeCategorySample.test.js +0 -26
- package/lib/commonjs/utils/deserializeCategorySample.test.js.map +0 -1
- package/lib/commonjs/utils/deserializeCorrelation.js +0 -26
- package/lib/commonjs/utils/deserializeCorrelation.js.map +0 -1
- package/lib/commonjs/utils/deserializeHeartbeatSeriesSample.js +0 -15
- package/lib/commonjs/utils/deserializeHeartbeatSeriesSample.js.map +0 -1
- package/lib/commonjs/utils/deserializeSample.js +0 -15
- package/lib/commonjs/utils/deserializeSample.js.map +0 -1
- package/lib/commonjs/utils/deserializeWorkout.js +0 -15
- package/lib/commonjs/utils/deserializeWorkout.js.map +0 -1
- package/lib/commonjs/utils/ensureMetadata.js +0 -11
- package/lib/commonjs/utils/ensureMetadata.js.map +0 -1
- package/lib/commonjs/utils/ensureTotals.js +0 -11
- package/lib/commonjs/utils/ensureTotals.js.map +0 -1
- package/lib/commonjs/utils/ensureUnit.js +0 -17
- package/lib/commonjs/utils/ensureUnit.js.map +0 -1
- package/lib/commonjs/utils/getDateOfBirth.js +0 -14
- package/lib/commonjs/utils/getDateOfBirth.js.map +0 -1
- package/lib/commonjs/utils/getMostRecentCategorySample.js +0 -17
- package/lib/commonjs/utils/getMostRecentCategorySample.js.map +0 -1
- package/lib/commonjs/utils/getMostRecentQuantitySample.js +0 -21
- package/lib/commonjs/utils/getMostRecentQuantitySample.js.map +0 -1
- package/lib/commonjs/utils/getMostRecentWorkout.js +0 -19
- package/lib/commonjs/utils/getMostRecentWorkout.js.map +0 -1
- package/lib/commonjs/utils/getPreferredUnit.js +0 -14
- package/lib/commonjs/utils/getPreferredUnit.js.map +0 -1
- package/lib/commonjs/utils/getPreferredUnits.js +0 -14
- package/lib/commonjs/utils/getPreferredUnits.js.map +0 -1
- package/lib/commonjs/utils/getPreferredUnitsTyped.js +0 -33
- package/lib/commonjs/utils/getPreferredUnitsTyped.js.map +0 -1
- package/lib/commonjs/utils/getRequestStatusForAuthorization.js +0 -21
- package/lib/commonjs/utils/getRequestStatusForAuthorization.js.map +0 -1
- package/lib/commonjs/utils/getWorkoutPlanById.js +0 -13
- package/lib/commonjs/utils/getWorkoutPlanById.js.map +0 -1
- package/lib/commonjs/utils/prepareOptions.js +0 -25
- package/lib/commonjs/utils/prepareOptions.js.map +0 -1
- package/lib/commonjs/utils/queryCategorySamples.js +0 -17
- package/lib/commonjs/utils/queryCategorySamples.js.map +0 -1
- package/lib/commonjs/utils/queryCategorySamplesWithAnchor.js +0 -21
- package/lib/commonjs/utils/queryCategorySamplesWithAnchor.js.map +0 -1
- package/lib/commonjs/utils/queryCorrelationSamples.js +0 -17
- package/lib/commonjs/utils/queryCorrelationSamples.js.map +0 -1
- package/lib/commonjs/utils/queryHeartbeatSeriesSamples.js +0 -17
- package/lib/commonjs/utils/queryHeartbeatSeriesSamples.js.map +0 -1
- package/lib/commonjs/utils/queryHeartbeatSeriesSamplesWithAnchor.js +0 -21
- package/lib/commonjs/utils/queryHeartbeatSeriesSamplesWithAnchor.js.map +0 -1
- package/lib/commonjs/utils/queryQuantitySamples.js +0 -19
- package/lib/commonjs/utils/queryQuantitySamples.js.map +0 -1
- package/lib/commonjs/utils/queryQuantitySamplesWithAnchor.js +0 -23
- package/lib/commonjs/utils/queryQuantitySamplesWithAnchor.js.map +0 -1
- package/lib/commonjs/utils/querySources.js +0 -14
- package/lib/commonjs/utils/querySources.js.map +0 -1
- package/lib/commonjs/utils/queryStateOfMindSamples.js +0 -22
- package/lib/commonjs/utils/queryStateOfMindSamples.js.map +0 -1
- package/lib/commonjs/utils/queryStatisticsCollectionForQuantity.js +0 -16
- package/lib/commonjs/utils/queryStatisticsCollectionForQuantity.js.map +0 -1
- package/lib/commonjs/utils/queryStatisticsForQuantity.js +0 -29
- package/lib/commonjs/utils/queryStatisticsForQuantity.js.map +0 -1
- package/lib/commonjs/utils/queryWorkoutSamplesWithAnchor.js +0 -26
- package/lib/commonjs/utils/queryWorkoutSamplesWithAnchor.js.map +0 -1
- package/lib/commonjs/utils/queryWorkouts.js +0 -22
- package/lib/commonjs/utils/queryWorkouts.js.map +0 -1
- package/lib/commonjs/utils/requestAuthorization.js +0 -22
- package/lib/commonjs/utils/requestAuthorization.js.map +0 -1
- package/lib/commonjs/utils/saveCategorySample.js +0 -20
- package/lib/commonjs/utils/saveCategorySample.js.map +0 -1
- package/lib/commonjs/utils/saveCorrelationSample.js +0 -35
- package/lib/commonjs/utils/saveCorrelationSample.js.map +0 -1
- package/lib/commonjs/utils/saveQuantitySample.js +0 -16
- package/lib/commonjs/utils/saveQuantitySample.js.map +0 -1
- package/lib/commonjs/utils/saveStateOfMindSample.js +0 -17
- package/lib/commonjs/utils/saveStateOfMindSample.js.map +0 -1
- package/lib/commonjs/utils/saveWorkoutRoute.js +0 -26
- package/lib/commonjs/utils/saveWorkoutRoute.js.map +0 -1
- package/lib/commonjs/utils/saveWorkoutSample.js +0 -36
- package/lib/commonjs/utils/saveWorkoutSample.js.map +0 -1
- package/lib/commonjs/utils/serializeDate.js +0 -9
- package/lib/commonjs/utils/serializeDate.js.map +0 -1
- package/lib/commonjs/utils/serializeDate.test.js +0 -17
- package/lib/commonjs/utils/serializeDate.test.js.map +0 -1
- package/lib/commonjs/utils/startWatchApp.js +0 -11
- package/lib/commonjs/utils/startWatchApp.js.map +0 -1
- package/lib/commonjs/utils/subscribeToChanges.js +0 -27
- package/lib/commonjs/utils/subscribeToChanges.js.map +0 -1
- package/lib/module/hooks/useHealthkitAuthorization.js +0 -32
- package/lib/module/hooks/useHealthkitAuthorization.js.map +0 -1
- package/lib/module/hooks/useHealthkitAuthorization.test.js +0 -68
- package/lib/module/hooks/useHealthkitAuthorization.test.js.map +0 -1
- package/lib/module/hooks/useIsHealthDataAvailable.js +0 -21
- package/lib/module/hooks/useIsHealthDataAvailable.js.map +0 -1
- package/lib/module/hooks/useIsHealthDataAvailable.test.js +0 -37
- package/lib/module/hooks/useIsHealthDataAvailable.test.js.map +0 -1
- package/lib/module/hooks/useMostRecentCategorySample.js +0 -16
- package/lib/module/hooks/useMostRecentCategorySample.js.map +0 -1
- package/lib/module/hooks/useMostRecentQuantitySample.js +0 -30
- package/lib/module/hooks/useMostRecentQuantitySample.js.map +0 -1
- package/lib/module/hooks/useMostRecentWorkout.js +0 -41
- package/lib/module/hooks/useMostRecentWorkout.js.map +0 -1
- package/lib/module/hooks/useSources.js +0 -15
- package/lib/module/hooks/useSources.js.map +0 -1
- package/lib/module/hooks/useStatisticsForQuantity.js +0 -21
- package/lib/module/hooks/useStatisticsForQuantity.js.map +0 -1
- package/lib/module/hooks/useSubscribeToChanges.js +0 -21
- package/lib/module/hooks/useSubscribeToChanges.js.map +0 -1
- package/lib/module/index.ios.js +0 -209
- package/lib/module/index.ios.js.map +0 -1
- package/lib/module/index.js +0 -4
- package/lib/module/index.js.map +0 -1
- package/lib/module/index.native.js +0 -160
- package/lib/module/index.native.js.map +0 -1
- package/lib/module/index.web.js +0 -4
- package/lib/module/index.web.js.map +0 -1
- package/lib/module/native-types.js +0 -1606
- package/lib/module/native-types.js.map +0 -1
- package/lib/module/test-setup.js +0 -54
- package/lib/module/test-setup.js.map +0 -1
- package/lib/module/test-utils.js +0 -11
- package/lib/module/test-utils.js.map +0 -1
- package/lib/module/types.js +0 -67
- package/lib/module/types.js.map +0 -1
- package/lib/module/utils/deleteQuantitySample.js +0 -4
- package/lib/module/utils/deleteQuantitySample.js.map +0 -1
- package/lib/module/utils/deleteSamples.js +0 -11
- package/lib/module/utils/deleteSamples.js.map +0 -1
- package/lib/module/utils/deleteWorkoutSample.js +0 -4
- package/lib/module/utils/deleteWorkoutSample.js.map +0 -1
- package/lib/module/utils/deserializeCategorySample.js +0 -7
- package/lib/module/utils/deserializeCategorySample.js.map +0 -1
- package/lib/module/utils/deserializeCategorySample.test.js +0 -22
- package/lib/module/utils/deserializeCategorySample.test.js.map +0 -1
- package/lib/module/utils/deserializeCorrelation.js +0 -19
- package/lib/module/utils/deserializeCorrelation.js.map +0 -1
- package/lib/module/utils/deserializeHeartbeatSeriesSample.js +0 -9
- package/lib/module/utils/deserializeHeartbeatSeriesSample.js.map +0 -1
- package/lib/module/utils/deserializeSample.js +0 -9
- package/lib/module/utils/deserializeSample.js.map +0 -1
- package/lib/module/utils/deserializeWorkout.js +0 -9
- package/lib/module/utils/deserializeWorkout.js.map +0 -1
- package/lib/module/utils/ensureMetadata.js +0 -5
- package/lib/module/utils/ensureMetadata.js.map +0 -1
- package/lib/module/utils/ensureTotals.js +0 -5
- package/lib/module/utils/ensureTotals.js.map +0 -1
- package/lib/module/utils/ensureUnit.js +0 -10
- package/lib/module/utils/ensureUnit.js.map +0 -1
- package/lib/module/utils/getDateOfBirth.js +0 -7
- package/lib/module/utils/getDateOfBirth.js.map +0 -1
- package/lib/module/utils/getMostRecentCategorySample.js +0 -10
- package/lib/module/utils/getMostRecentCategorySample.js.map +0 -1
- package/lib/module/utils/getMostRecentQuantitySample.js +0 -14
- package/lib/module/utils/getMostRecentQuantitySample.js.map +0 -1
- package/lib/module/utils/getMostRecentWorkout.js +0 -12
- package/lib/module/utils/getMostRecentWorkout.js.map +0 -1
- package/lib/module/utils/getPreferredUnit.js +0 -7
- package/lib/module/utils/getPreferredUnit.js.map +0 -1
- package/lib/module/utils/getPreferredUnits.js +0 -7
- package/lib/module/utils/getPreferredUnits.js.map +0 -1
- package/lib/module/utils/getPreferredUnitsTyped.js +0 -26
- package/lib/module/utils/getPreferredUnitsTyped.js.map +0 -1
- package/lib/module/utils/getRequestStatusForAuthorization.js +0 -14
- package/lib/module/utils/getRequestStatusForAuthorization.js.map +0 -1
- package/lib/module/utils/getWorkoutPlanById.js +0 -6
- package/lib/module/utils/getWorkoutPlanById.js.map +0 -1
- package/lib/module/utils/prepareOptions.js +0 -18
- package/lib/module/utils/prepareOptions.js.map +0 -1
- package/lib/module/utils/queryCategorySamples.js +0 -10
- package/lib/module/utils/queryCategorySamples.js.map +0 -1
- package/lib/module/utils/queryCategorySamplesWithAnchor.js +0 -14
- package/lib/module/utils/queryCategorySamplesWithAnchor.js.map +0 -1
- package/lib/module/utils/queryCorrelationSamples.js +0 -10
- package/lib/module/utils/queryCorrelationSamples.js.map +0 -1
- package/lib/module/utils/queryHeartbeatSeriesSamples.js +0 -10
- package/lib/module/utils/queryHeartbeatSeriesSamples.js.map +0 -1
- package/lib/module/utils/queryHeartbeatSeriesSamplesWithAnchor.js +0 -14
- package/lib/module/utils/queryHeartbeatSeriesSamplesWithAnchor.js.map +0 -1
- package/lib/module/utils/queryQuantitySamples.js +0 -12
- package/lib/module/utils/queryQuantitySamples.js.map +0 -1
- package/lib/module/utils/queryQuantitySamplesWithAnchor.js +0 -16
- package/lib/module/utils/queryQuantitySamplesWithAnchor.js.map +0 -1
- package/lib/module/utils/querySources.js +0 -7
- package/lib/module/utils/querySources.js.map +0 -1
- package/lib/module/utils/queryStateOfMindSamples.js +0 -14
- package/lib/module/utils/queryStateOfMindSamples.js.map +0 -1
- package/lib/module/utils/queryStatisticsCollectionForQuantity.js +0 -9
- package/lib/module/utils/queryStatisticsCollectionForQuantity.js.map +0 -1
- package/lib/module/utils/queryStatisticsForQuantity.js +0 -22
- package/lib/module/utils/queryStatisticsForQuantity.js.map +0 -1
- package/lib/module/utils/queryWorkoutSamplesWithAnchor.js +0 -19
- package/lib/module/utils/queryWorkoutSamplesWithAnchor.js.map +0 -1
- package/lib/module/utils/queryWorkouts.js +0 -15
- package/lib/module/utils/queryWorkouts.js.map +0 -1
- package/lib/module/utils/requestAuthorization.js +0 -15
- package/lib/module/utils/requestAuthorization.js.map +0 -1
- package/lib/module/utils/saveCategorySample.js +0 -13
- package/lib/module/utils/saveCategorySample.js.map +0 -1
- package/lib/module/utils/saveCorrelationSample.js +0 -28
- package/lib/module/utils/saveCorrelationSample.js.map +0 -1
- package/lib/module/utils/saveQuantitySample.js +0 -9
- package/lib/module/utils/saveQuantitySample.js.map +0 -1
- package/lib/module/utils/saveStateOfMindSample.js +0 -10
- package/lib/module/utils/saveStateOfMindSample.js.map +0 -1
- package/lib/module/utils/saveWorkoutRoute.js +0 -19
- package/lib/module/utils/saveWorkoutRoute.js.map +0 -1
- package/lib/module/utils/saveWorkoutSample.js +0 -29
- package/lib/module/utils/saveWorkoutSample.js.map +0 -1
- package/lib/module/utils/serializeDate.js +0 -3
- package/lib/module/utils/serializeDate.js.map +0 -1
- package/lib/module/utils/serializeDate.test.js +0 -14
- package/lib/module/utils/serializeDate.test.js.map +0 -1
- package/lib/module/utils/startWatchApp.js +0 -4
- package/lib/module/utils/startWatchApp.js.map +0 -1
- package/lib/module/utils/subscribeToChanges.js +0 -20
- package/lib/module/utils/subscribeToChanges.js.map +0 -1
- package/lib/typescript/example-expo/App.d.ts +0 -2
- package/lib/typescript/src/hooks/useHealthkitAuthorization.d.ts +0 -8
- package/lib/typescript/src/hooks/useHealthkitAuthorization.test.d.ts +0 -1
- package/lib/typescript/src/hooks/useIsHealthDataAvailable.d.ts +0 -7
- package/lib/typescript/src/hooks/useIsHealthDataAvailable.test.d.ts +0 -1
- package/lib/typescript/src/hooks/useMostRecentCategorySample.d.ts +0 -7
- package/lib/typescript/src/hooks/useMostRecentQuantitySample.d.ts +0 -7
- package/lib/typescript/src/hooks/useMostRecentWorkout.d.ts +0 -10
- package/lib/typescript/src/hooks/useSources.d.ts +0 -3
- package/lib/typescript/src/hooks/useStatisticsForQuantity.d.ts +0 -4
- package/lib/typescript/src/hooks/useSubscribeToChanges.d.ts +0 -3
- package/lib/typescript/src/index.d.ts +0 -3
- package/lib/typescript/src/index.ios.d.ts +0 -198
- package/lib/typescript/src/index.native.d.ts +0 -41
- package/lib/typescript/src/index.web.d.ts +0 -3
- package/lib/typescript/src/native-types.d.ts +0 -1764
- package/lib/typescript/src/test-setup.d.ts +0 -1
- package/lib/typescript/src/test-utils.d.ts +0 -2
- package/lib/typescript/src/types.d.ts +0 -111
- package/lib/typescript/src/utils/deleteQuantitySample.d.ts +0 -4
- package/lib/typescript/src/utils/deleteSamples.d.ts +0 -8
- package/lib/typescript/src/utils/deleteWorkoutSample.d.ts +0 -3
- package/lib/typescript/src/utils/deserializeCategorySample.d.ts +0 -4
- package/lib/typescript/src/utils/deserializeCategorySample.test.d.ts +0 -1
- package/lib/typescript/src/utils/deserializeCorrelation.d.ts +0 -4
- package/lib/typescript/src/utils/deserializeHeartbeatSeriesSample.d.ts +0 -4
- package/lib/typescript/src/utils/deserializeSample.d.ts +0 -4
- package/lib/typescript/src/utils/deserializeWorkout.d.ts +0 -4
- package/lib/typescript/src/utils/ensureMetadata.d.ts +0 -2
- package/lib/typescript/src/utils/ensureTotals.d.ts +0 -2
- package/lib/typescript/src/utils/ensureUnit.d.ts +0 -3
- package/lib/typescript/src/utils/getDateOfBirth.d.ts +0 -2
- package/lib/typescript/src/utils/getMostRecentCategorySample.d.ts +0 -4
- package/lib/typescript/src/utils/getMostRecentQuantitySample.d.ts +0 -4
- package/lib/typescript/src/utils/getMostRecentWorkout.d.ts +0 -5
- package/lib/typescript/src/utils/getPreferredUnit.d.ts +0 -4
- package/lib/typescript/src/utils/getPreferredUnits.d.ts +0 -4
- package/lib/typescript/src/utils/getPreferredUnitsTyped.d.ts +0 -9
- package/lib/typescript/src/utils/getRequestStatusForAuthorization.d.ts +0 -3
- package/lib/typescript/src/utils/getWorkoutPlanById.d.ts +0 -5
- package/lib/typescript/src/utils/prepareOptions.d.ts +0 -9
- package/lib/typescript/src/utils/queryCategorySamples.d.ts +0 -5
- package/lib/typescript/src/utils/queryCategorySamplesWithAnchor.d.ts +0 -10
- package/lib/typescript/src/utils/queryCorrelationSamples.d.ts +0 -5
- package/lib/typescript/src/utils/queryHeartbeatSeriesSamples.d.ts +0 -10
- package/lib/typescript/src/utils/queryHeartbeatSeriesSamplesWithAnchor.d.ts +0 -10
- package/lib/typescript/src/utils/queryQuantitySamples.d.ts +0 -7
- package/lib/typescript/src/utils/queryQuantitySamplesWithAnchor.d.ts +0 -12
- package/lib/typescript/src/utils/querySources.d.ts +0 -4
- package/lib/typescript/src/utils/queryStateOfMindSamples.d.ts +0 -7
- package/lib/typescript/src/utils/queryStatisticsCollectionForQuantity.d.ts +0 -3
- package/lib/typescript/src/utils/queryStatisticsForQuantity.d.ts +0 -14
- package/lib/typescript/src/utils/queryWorkoutSamplesWithAnchor.d.ts +0 -9
- package/lib/typescript/src/utils/queryWorkouts.d.ts +0 -4
- package/lib/typescript/src/utils/requestAuthorization.d.ts +0 -4
- package/lib/typescript/src/utils/saveCategorySample.d.ts +0 -11
- package/lib/typescript/src/utils/saveCorrelationSample.d.ts +0 -8
- package/lib/typescript/src/utils/saveQuantitySample.d.ts +0 -7
- package/lib/typescript/src/utils/saveStateOfMindSample.d.ts +0 -11
- package/lib/typescript/src/utils/saveWorkoutRoute.d.ts +0 -3
- package/lib/typescript/src/utils/saveWorkoutSample.d.ts +0 -11
- package/lib/typescript/src/utils/serializeDate.d.ts +0 -2
- package/lib/typescript/src/utils/serializeDate.test.d.ts +0 -1
- package/lib/typescript/src/utils/startWatchApp.d.ts +0 -3
- package/lib/typescript/src/utils/subscribeToChanges.d.ts +0 -3
- package/src/index.ios.tsx +0 -292
- package/src/index.native.tsx +0 -233
- package/src/index.tsx +0 -5
- package/src/index.web.tsx +0 -5
- package/src/native-types.ts +0 -2471
- package/src/types.ts +0 -156
- package/src/utils/deleteQuantitySample.ts +0 -14
- package/src/utils/deleteSamples.ts +0 -23
- package/src/utils/deleteWorkoutSample.ts +0 -7
- package/src/utils/deserializeCategorySample.test.ts +0 -24
- package/src/utils/deserializeCategorySample.ts +0 -12
- package/src/utils/deserializeCorrelation.ts +0 -28
- package/src/utils/deserializeHeartbeatSeriesSample.ts +0 -12
- package/src/utils/deserializeSample.ts +0 -17
- package/src/utils/deserializeWorkout.ts +0 -14
- package/src/utils/ensureMetadata.ts +0 -5
- package/src/utils/ensureTotals.ts +0 -5
- package/src/utils/ensureUnit.ts +0 -19
- package/src/utils/getDateOfBirth.ts +0 -8
- package/src/utils/getPreferredUnits.ts +0 -14
- package/src/utils/getPreferredUnitsTyped.ts +0 -38
- package/src/utils/getRequestStatusForAuthorization.ts +0 -21
- package/src/utils/getWorkoutPlanById.ts +0 -7
- package/src/utils/prepareOptions.ts +0 -19
- package/src/utils/queryCategorySamples.ts +0 -29
- package/src/utils/queryCategorySamplesWithAnchor.ts +0 -39
- package/src/utils/queryCorrelationSamples.ts +0 -29
- package/src/utils/queryHeartbeatSeriesSamples.ts +0 -29
- package/src/utils/queryHeartbeatSeriesSamplesWithAnchor.ts +0 -33
- package/src/utils/queryQuantitySamples.ts +0 -38
- package/src/utils/queryQuantitySamplesWithAnchor.ts +0 -46
- package/src/utils/querySources.ts +0 -21
- package/src/utils/queryStateOfMindSamples.ts +0 -14
- package/src/utils/queryStatisticsCollectionForQuantity.ts +0 -38
- package/src/utils/queryStatisticsForQuantity.ts +0 -38
- package/src/utils/queryWorkoutSamplesWithAnchor.ts +0 -46
- package/src/utils/queryWorkouts.ts +0 -28
- package/src/utils/requestAuthorization.ts +0 -19
- package/src/utils/saveCategorySample.ts +0 -31
- package/src/utils/saveCorrelationSample.ts +0 -43
- package/src/utils/saveQuantitySample.ts +0 -29
- package/src/utils/saveStateOfMindSample.ts +0 -38
- package/src/utils/saveWorkoutRoute.ts +0 -21
- package/src/utils/saveWorkoutSample.ts +0 -42
- package/src/utils/serializeDate.test.ts +0 -16
- package/src/utils/serializeDate.ts +0 -5
- package/src/utils/startWatchApp.ts +0 -7
|
@@ -1,2333 +0,0 @@
|
|
|
1
|
-
import CoreLocation
|
|
2
|
-
import HealthKit
|
|
3
|
-
|
|
4
|
-
#if canImport(WorkoutKit)
|
|
5
|
-
import WorkoutKit
|
|
6
|
-
#endif
|
|
7
|
-
|
|
8
|
-
@objc(ReactNativeHealthkit)
|
|
9
|
-
@available(iOS 10.0, *)
|
|
10
|
-
class ReactNativeHealthkit: RCTEventEmitter {
|
|
11
|
-
var _store: HKHealthStore?
|
|
12
|
-
var _runningQueries: [String: HKQuery]
|
|
13
|
-
var _dateFormatter: ISO8601DateFormatter
|
|
14
|
-
var _hasListeners = false
|
|
15
|
-
|
|
16
|
-
override init() {
|
|
17
|
-
self._runningQueries = [String: HKQuery]()
|
|
18
|
-
self._dateFormatter = ISO8601DateFormatter()
|
|
19
|
-
self._dateFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
|
|
20
|
-
if HKHealthStore.isHealthDataAvailable() {
|
|
21
|
-
self._store = HKHealthStore.init()
|
|
22
|
-
}
|
|
23
|
-
super.init()
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
deinit {
|
|
27
|
-
if let store = _store {
|
|
28
|
-
for query in self._runningQueries {
|
|
29
|
-
store.stop(query.value)
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
override func stopObserving() {
|
|
35
|
-
self._hasListeners = false
|
|
36
|
-
if let store = _store {
|
|
37
|
-
for query in self._runningQueries {
|
|
38
|
-
store.stop(query.value)
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
override func startObserving() {
|
|
44
|
-
self._hasListeners = true
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
@objc(isProtectedDataAvailable:withRejecter:)
|
|
48
|
-
func isProtectedDataAvailable(
|
|
49
|
-
resolve: RCTPromiseResolveBlock,
|
|
50
|
-
reject: RCTPromiseRejectBlock
|
|
51
|
-
) {
|
|
52
|
-
resolve(UIApplication.shared.isProtectedDataAvailable)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
@objc(isHealthDataAvailable:withRejecter:)
|
|
56
|
-
func isHealthDataAvailable(
|
|
57
|
-
resolve: RCTPromiseResolveBlock,
|
|
58
|
-
reject: RCTPromiseRejectBlock
|
|
59
|
-
) {
|
|
60
|
-
resolve(HKHealthStore.isHealthDataAvailable())
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
@available(iOS 12.0, *)
|
|
64
|
-
@objc(supportsHealthRecords:withRejecter:)
|
|
65
|
-
func supportsHealthRecords(
|
|
66
|
-
resolve: RCTPromiseResolveBlock,
|
|
67
|
-
reject: RCTPromiseRejectBlock
|
|
68
|
-
) {
|
|
69
|
-
guard let store = _store else {
|
|
70
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
71
|
-
}
|
|
72
|
-
resolve(store.supportsHealthRecords())
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
@available(iOS 12.0, *)
|
|
76
|
-
@objc(getRequestStatusForAuthorization:read:resolve:withRejecter:)
|
|
77
|
-
func getRequestStatusForAuthorization(
|
|
78
|
-
toShare: NSDictionary,
|
|
79
|
-
read: NSDictionary,
|
|
80
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
81
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
82
|
-
) {
|
|
83
|
-
guard let store = _store else {
|
|
84
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
let share = sampleTypesFromDictionary(typeIdentifiers: toShare)
|
|
88
|
-
let toRead = objectTypesFromDictionary(typeIdentifiers: read)
|
|
89
|
-
|
|
90
|
-
store.getRequestStatusForAuthorization(toShare: share, read: toRead) {
|
|
91
|
-
(
|
|
92
|
-
status: HKAuthorizationRequestStatus,
|
|
93
|
-
error: Error?
|
|
94
|
-
) in
|
|
95
|
-
guard let err = error else {
|
|
96
|
-
return resolve(status.rawValue)
|
|
97
|
-
}
|
|
98
|
-
reject(GENERIC_ERROR, err.localizedDescription, err)
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
@objc(getPreferredUnits:resolve:reject:)
|
|
103
|
-
func getPreferredUnits(
|
|
104
|
-
forIdentifiers: NSArray,
|
|
105
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
106
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
107
|
-
) {
|
|
108
|
-
guard let store = _store else {
|
|
109
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
110
|
-
}
|
|
111
|
-
var quantityTypes = Set<HKQuantityType>()
|
|
112
|
-
for identifierString in forIdentifiers {
|
|
113
|
-
let identifier = HKQuantityTypeIdentifier.init(rawValue: identifierString as! String)
|
|
114
|
-
let type = HKSampleType.quantityType(forIdentifier: identifier)
|
|
115
|
-
if type != nil {
|
|
116
|
-
quantityTypes.insert(type!)
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
store.preferredUnits(for: quantityTypes) {
|
|
121
|
-
(typePerUnits: [HKQuantityType: HKUnit], _: Error?) in
|
|
122
|
-
let dic: NSMutableDictionary = NSMutableDictionary()
|
|
123
|
-
|
|
124
|
-
for typePerUnit in typePerUnits {
|
|
125
|
-
dic.setObject(typePerUnit.value.unitString, forKey: typePerUnit.key.identifier as NSCopying)
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
resolve(dic)
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
@objc(getBiologicalSex:withRejecter:)
|
|
133
|
-
func getBiologicalSex(
|
|
134
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
135
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
136
|
-
) {
|
|
137
|
-
guard let store = _store else {
|
|
138
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
do {
|
|
142
|
-
let bioSex = try store.biologicalSex()
|
|
143
|
-
resolve(bioSex.biologicalSex.rawValue)
|
|
144
|
-
} catch {
|
|
145
|
-
reject(GENERIC_ERROR, error.localizedDescription, error)
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
@objc(getDateOfBirth:withRejecter:)
|
|
150
|
-
func getDateOfBirth(
|
|
151
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
152
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
153
|
-
) {
|
|
154
|
-
guard let store = _store else {
|
|
155
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
do {
|
|
159
|
-
let dateOfBirth = try store.dateOfBirthComponents()
|
|
160
|
-
|
|
161
|
-
resolve(_dateFormatter.string(from: dateOfBirth.date!))
|
|
162
|
-
} catch {
|
|
163
|
-
reject(GENERIC_ERROR, error.localizedDescription, error)
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
@objc(getBloodType:withRejecter:)
|
|
168
|
-
func getBloodType(
|
|
169
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
170
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
171
|
-
) {
|
|
172
|
-
guard let store = _store else {
|
|
173
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
do {
|
|
177
|
-
let bloodType = try store.bloodType()
|
|
178
|
-
resolve(bloodType.bloodType.rawValue)
|
|
179
|
-
} catch {
|
|
180
|
-
reject(GENERIC_ERROR, error.localizedDescription, error)
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
@objc(getFitzpatrickSkinType:withRejecter:)
|
|
185
|
-
func getFitzpatrickSkinType(
|
|
186
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
187
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
188
|
-
) {
|
|
189
|
-
guard let store = _store else {
|
|
190
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
do {
|
|
194
|
-
let fitzpatrickSkinType = try store.fitzpatrickSkinType()
|
|
195
|
-
resolve(fitzpatrickSkinType.skinType.rawValue)
|
|
196
|
-
} catch {
|
|
197
|
-
reject(GENERIC_ERROR, error.localizedDescription, error)
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
@available(iOS 10.0, *)
|
|
202
|
-
@objc(getWheelchairUse:withRejecter:)
|
|
203
|
-
func getWheelchairUse(
|
|
204
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
205
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
206
|
-
) {
|
|
207
|
-
guard let store = _store else {
|
|
208
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
do {
|
|
212
|
-
let wheelchairUse = try store.wheelchairUse()
|
|
213
|
-
resolve(wheelchairUse.wheelchairUse.rawValue)
|
|
214
|
-
} catch {
|
|
215
|
-
reject(GENERIC_ERROR, error.localizedDescription, error)
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
@objc(authorizationStatusFor:withResolver:withRejecter:)
|
|
220
|
-
func authorizationStatusFor(
|
|
221
|
-
typeIdentifier: String,
|
|
222
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
223
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
224
|
-
) {
|
|
225
|
-
guard let store = _store else {
|
|
226
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
guard let objectType = objectTypeFromString(typeIdentifier: typeIdentifier) else {
|
|
230
|
-
return reject(TYPE_IDENTIFIER_ERROR, "Failed to initialize " + typeIdentifier, nil)
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
let authStatus = store.authorizationStatus(for: objectType)
|
|
234
|
-
resolve(authStatus.rawValue)
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
@objc(saveQuantitySample:unitString:value:start:end:metadata:resolve:reject:)
|
|
238
|
-
func saveQuantitySample(
|
|
239
|
-
typeIdentifier: String,
|
|
240
|
-
unitString: String,
|
|
241
|
-
value: Double,
|
|
242
|
-
start: Date,
|
|
243
|
-
end: Date,
|
|
244
|
-
metadata: [String: Any],
|
|
245
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
246
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
247
|
-
) {
|
|
248
|
-
guard let store = _store else {
|
|
249
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
let identifier = HKQuantityTypeIdentifier.init(rawValue: typeIdentifier)
|
|
253
|
-
|
|
254
|
-
guard let type = HKObjectType.quantityType(forIdentifier: identifier) else {
|
|
255
|
-
return reject(TYPE_IDENTIFIER_ERROR, "Failed to initialize " + typeIdentifier, nil)
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
let unit = HKUnit.init(from: unitString)
|
|
259
|
-
let quantity = HKQuantity.init(unit: unit, doubleValue: value)
|
|
260
|
-
let sample = HKQuantitySample.init(
|
|
261
|
-
type: type,
|
|
262
|
-
quantity: quantity,
|
|
263
|
-
start: start,
|
|
264
|
-
end: end,
|
|
265
|
-
metadata: metadata
|
|
266
|
-
)
|
|
267
|
-
|
|
268
|
-
store.save(sample) { (success: Bool, error: Error?) in
|
|
269
|
-
guard let err = error else {
|
|
270
|
-
return resolve(success)
|
|
271
|
-
}
|
|
272
|
-
reject(GENERIC_ERROR, err.localizedDescription, error)
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
@objc(deleteQuantitySample:uuid:resolve:reject:)
|
|
277
|
-
func deleteQuantitySample(
|
|
278
|
-
typeIdentifier: String,
|
|
279
|
-
uuid: String,
|
|
280
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
281
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
282
|
-
) {
|
|
283
|
-
guard let store = _store else {
|
|
284
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
let identifier = HKQuantityTypeIdentifier.init(rawValue: typeIdentifier)
|
|
288
|
-
let sampleUuid = UUID.init(uuidString: uuid)!
|
|
289
|
-
|
|
290
|
-
guard let sampleType = HKObjectType.quantityType(forIdentifier: identifier) else {
|
|
291
|
-
return reject(TYPE_IDENTIFIER_ERROR, "Failed to initialize " + typeIdentifier, nil)
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
let samplePredicate = HKQuery.predicateForObject(with: sampleUuid)
|
|
295
|
-
|
|
296
|
-
store.deleteObjects(of: sampleType, predicate: samplePredicate) {
|
|
297
|
-
(success: Bool, _: Int, error: Error?) in
|
|
298
|
-
guard let err = error else {
|
|
299
|
-
return resolve(success)
|
|
300
|
-
}
|
|
301
|
-
reject(GENERIC_ERROR, err.localizedDescription, error)
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
@objc(deleteSamples:start:end:resolve:reject:)
|
|
306
|
-
func deleteSamples(
|
|
307
|
-
typeIdentifier: String,
|
|
308
|
-
start: Date,
|
|
309
|
-
end: Date,
|
|
310
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
311
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
312
|
-
) {
|
|
313
|
-
guard let store = _store else {
|
|
314
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
let identifier = HKQuantityTypeIdentifier.init(rawValue: typeIdentifier)
|
|
318
|
-
|
|
319
|
-
guard let sampleType = HKObjectType.quantityType(forIdentifier: identifier) else {
|
|
320
|
-
return reject(TYPE_IDENTIFIER_ERROR, "Failed to initialize " + typeIdentifier, nil)
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
let samplePredicate = HKQuery.predicateForSamples(
|
|
324
|
-
withStart: start,
|
|
325
|
-
end: end,
|
|
326
|
-
options: HKQueryOptions.strictStartDate
|
|
327
|
-
)
|
|
328
|
-
|
|
329
|
-
store.deleteObjects(of: sampleType, predicate: samplePredicate) {
|
|
330
|
-
(success: Bool, _: Int, error: Error?) in
|
|
331
|
-
guard let err = error else {
|
|
332
|
-
return resolve(success)
|
|
333
|
-
}
|
|
334
|
-
reject(GENERIC_ERROR, err.localizedDescription, error)
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
@objc(deleteWorkoutSample:resolve:reject:)
|
|
339
|
-
func deleteWorkoutSample(
|
|
340
|
-
uuid: String,
|
|
341
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
342
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
343
|
-
) {
|
|
344
|
-
guard let store = _store else {
|
|
345
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
guard let workoutUUID = UUID.init(uuidString: uuid) else {
|
|
349
|
-
return reject(TYPE_IDENTIFIER_ERROR, "Failed to initialize UUID from string", nil)
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
let samplePredicate = HKQuery.predicateForObject(with: workoutUUID)
|
|
353
|
-
|
|
354
|
-
store.deleteObjects(of: HKObjectType.workoutType(), predicate: samplePredicate) { (success: Bool, _: Int, error: Error?) in
|
|
355
|
-
guard let err = error else {
|
|
356
|
-
return resolve(success)
|
|
357
|
-
}
|
|
358
|
-
reject(GENERIC_ERROR, err.localizedDescription, error)
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
@objc(saveCorrelationSample:samples:start:end:metadata:resolve:reject:)
|
|
363
|
-
func saveCorrelationSample(
|
|
364
|
-
typeIdentifier: String,
|
|
365
|
-
samples: [[String: Any]],
|
|
366
|
-
start: Date,
|
|
367
|
-
end: Date,
|
|
368
|
-
metadata: [String: Any],
|
|
369
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
370
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
371
|
-
) {
|
|
372
|
-
guard let store = _store else {
|
|
373
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
let identifier = HKCorrelationTypeIdentifier.init(rawValue: typeIdentifier)
|
|
377
|
-
|
|
378
|
-
guard let type = HKObjectType.correlationType(forIdentifier: identifier) else {
|
|
379
|
-
return reject(TYPE_IDENTIFIER_ERROR, "Failed to initialize " + typeIdentifier, nil)
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
var initializedSamples = Set<HKSample>()
|
|
383
|
-
for sample in samples {
|
|
384
|
-
if sample.keys.contains("quantityType") {
|
|
385
|
-
let typeId = HKQuantityTypeIdentifier.init(rawValue: sample["quantityType"] as! String)
|
|
386
|
-
if let type = HKSampleType.quantityType(forIdentifier: typeId) {
|
|
387
|
-
let unitStr = sample["unit"] as! String
|
|
388
|
-
let quantityVal = sample["quantity"] as! Double
|
|
389
|
-
let metadata = sample["metadata"] as? [String: Any]
|
|
390
|
-
|
|
391
|
-
let unit = HKUnit.init(from: unitStr)
|
|
392
|
-
let quantity = HKQuantity.init(unit: unit, doubleValue: quantityVal)
|
|
393
|
-
let quantitySample = HKQuantitySample.init(
|
|
394
|
-
type: type,
|
|
395
|
-
quantity: quantity,
|
|
396
|
-
start: start,
|
|
397
|
-
end: end,
|
|
398
|
-
metadata: metadata
|
|
399
|
-
)
|
|
400
|
-
initializedSamples.insert(quantitySample)
|
|
401
|
-
}
|
|
402
|
-
} else if sample.keys.contains("categoryType") {
|
|
403
|
-
let typeId = HKCategoryTypeIdentifier.init(rawValue: sample["categoryType"] as! String)
|
|
404
|
-
if let type = HKSampleType.categoryType(forIdentifier: typeId) {
|
|
405
|
-
let value = sample["value"] as! Int
|
|
406
|
-
let metadata = sample["metadata"] as? [String: Any]
|
|
407
|
-
let categorySample = HKCategorySample.init(
|
|
408
|
-
type: type,
|
|
409
|
-
value: value,
|
|
410
|
-
start: start,
|
|
411
|
-
end: end,
|
|
412
|
-
metadata: metadata
|
|
413
|
-
)
|
|
414
|
-
initializedSamples.insert(categorySample)
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
let correlation = HKCorrelation.init(
|
|
421
|
-
type: type,
|
|
422
|
-
start: start,
|
|
423
|
-
end: end,
|
|
424
|
-
objects: initializedSamples,
|
|
425
|
-
metadata: metadata
|
|
426
|
-
)
|
|
427
|
-
|
|
428
|
-
store.save(correlation) { (success: Bool, error: Error?) in
|
|
429
|
-
guard let err = error else {
|
|
430
|
-
return resolve(success)
|
|
431
|
-
}
|
|
432
|
-
reject(GENERIC_ERROR, err.localizedDescription, error)
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
@objc(saveWorkoutSample:quantities:start:end:totals:metadata:resolve:reject:)
|
|
437
|
-
func saveWorkoutSample(
|
|
438
|
-
typeIdentifier: UInt,
|
|
439
|
-
quantities: [[String: Any]],
|
|
440
|
-
start: Date,
|
|
441
|
-
end: Date,
|
|
442
|
-
totals: [String: Any],
|
|
443
|
-
metadata: [String: Any],
|
|
444
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
445
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
446
|
-
) {
|
|
447
|
-
guard let store = _store else {
|
|
448
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
guard let type = HKWorkoutActivityType.init(rawValue: typeIdentifier) else {
|
|
452
|
-
return reject(
|
|
453
|
-
TYPE_IDENTIFIER_ERROR,
|
|
454
|
-
"Failed to initialize HKWorkoutActivityType " + typeIdentifier.description, nil)
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
// if start and end both exist, ensure that start date is before end date
|
|
458
|
-
if let startDate = start as Date?, let endDate = end as Date? {
|
|
459
|
-
if startDate > endDate {
|
|
460
|
-
return reject(GENERIC_ERROR, "Start date must be before end date", nil)
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
var initializedSamples = [HKSample]()
|
|
465
|
-
var totalEnergyBurned: HKQuantity?
|
|
466
|
-
var totalDistance: HKQuantity?
|
|
467
|
-
var totalSwimmingStrokeCount: HKQuantity?
|
|
468
|
-
var totalFlightsClimbed: HKQuantity?
|
|
469
|
-
// generating quantity samples
|
|
470
|
-
for quantity in quantities {
|
|
471
|
-
let typeId = HKQuantityTypeIdentifier.init(rawValue: quantity["quantityType"] as! String)
|
|
472
|
-
if let type = HKSampleType.quantityType(forIdentifier: typeId) {
|
|
473
|
-
let unitStr = quantity["unit"] as! String
|
|
474
|
-
let quantityVal = quantity["quantity"] as! Double
|
|
475
|
-
let metadata = quantity["metadata"] as? [String: Any]
|
|
476
|
-
let quantityStart = quantity["startDate"] as? String
|
|
477
|
-
let quantityEnd = quantity["endDate"] as? String
|
|
478
|
-
let unit = HKUnit.init(from: unitStr)
|
|
479
|
-
let quantity = HKQuantity.init(unit: unit, doubleValue: quantityVal)
|
|
480
|
-
|
|
481
|
-
if quantity.is(compatibleWith: HKUnit.kilocalorie()) {
|
|
482
|
-
totalEnergyBurned = quantity
|
|
483
|
-
}
|
|
484
|
-
if quantity.is(compatibleWith: HKUnit.meter()) {
|
|
485
|
-
totalDistance = quantity
|
|
486
|
-
}
|
|
487
|
-
if typeId == HKQuantityTypeIdentifier.swimmingStrokeCount {
|
|
488
|
-
totalSwimmingStrokeCount = quantity
|
|
489
|
-
}
|
|
490
|
-
if typeId == HKQuantityTypeIdentifier.flightsClimbed {
|
|
491
|
-
totalFlightsClimbed = quantity
|
|
492
|
-
}
|
|
493
|
-
if let quantityStart, let quantityEnd {
|
|
494
|
-
let quantityStartDate = self._dateFormatter.date(from: quantityStart) ?? start
|
|
495
|
-
let quantityEndDate = self._dateFormatter.date(from: quantityEnd) ?? end
|
|
496
|
-
let quantitySample = HKQuantitySample.init(
|
|
497
|
-
type: type,
|
|
498
|
-
quantity: quantity,
|
|
499
|
-
start: quantityStartDate,
|
|
500
|
-
end: quantityEndDate,
|
|
501
|
-
metadata: metadata
|
|
502
|
-
)
|
|
503
|
-
initializedSamples.append(quantitySample)
|
|
504
|
-
} else {
|
|
505
|
-
// Handle the case where either startDate or endDate is nil
|
|
506
|
-
let quantitySample = HKQuantitySample.init(
|
|
507
|
-
type: type,
|
|
508
|
-
quantity: quantity,
|
|
509
|
-
start: start,
|
|
510
|
-
end: end,
|
|
511
|
-
metadata: metadata
|
|
512
|
-
)
|
|
513
|
-
initializedSamples.append(quantitySample)
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
// if totals are provided override samples
|
|
519
|
-
let rawTotalDistance = totals["distance"] as? Double ?? 0.0
|
|
520
|
-
let rawTotalEnergy = totals["energyBurned"] as? Double ?? 0.0
|
|
521
|
-
|
|
522
|
-
if rawTotalDistance != 0.0 {
|
|
523
|
-
totalDistance = HKQuantity(unit: .meter(), doubleValue: rawTotalDistance)
|
|
524
|
-
}
|
|
525
|
-
if rawTotalEnergy != 0.0 {
|
|
526
|
-
totalEnergyBurned = HKQuantity(unit: .kilocalorie(), doubleValue: rawTotalEnergy)
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
// creating workout
|
|
530
|
-
var workout: HKWorkout?
|
|
531
|
-
|
|
532
|
-
if totalSwimmingStrokeCount != nil {
|
|
533
|
-
workout = HKWorkout.init(
|
|
534
|
-
activityType: type,
|
|
535
|
-
start: start,
|
|
536
|
-
end: end,
|
|
537
|
-
workoutEvents: nil,
|
|
538
|
-
totalEnergyBurned: totalEnergyBurned,
|
|
539
|
-
totalDistance: totalDistance,
|
|
540
|
-
totalSwimmingStrokeCount: totalSwimmingStrokeCount,
|
|
541
|
-
device: nil,
|
|
542
|
-
metadata: metadata
|
|
543
|
-
)
|
|
544
|
-
} else {
|
|
545
|
-
if #available(iOS 11, *) {
|
|
546
|
-
if totalFlightsClimbed != nil {
|
|
547
|
-
workout = HKWorkout.init(
|
|
548
|
-
activityType: type,
|
|
549
|
-
start: start,
|
|
550
|
-
end: end,
|
|
551
|
-
workoutEvents: nil,
|
|
552
|
-
totalEnergyBurned: totalEnergyBurned,
|
|
553
|
-
totalDistance: totalDistance,
|
|
554
|
-
totalFlightsClimbed: totalFlightsClimbed,
|
|
555
|
-
device: nil,
|
|
556
|
-
metadata: metadata
|
|
557
|
-
)
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
if workout == nil {
|
|
563
|
-
workout = HKWorkout.init(
|
|
564
|
-
activityType: type,
|
|
565
|
-
start: start,
|
|
566
|
-
end: end,
|
|
567
|
-
workoutEvents: nil,
|
|
568
|
-
totalEnergyBurned: totalEnergyBurned,
|
|
569
|
-
totalDistance: totalDistance,
|
|
570
|
-
metadata: metadata
|
|
571
|
-
)
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
guard let workout = workout else {
|
|
575
|
-
reject(GENERIC_ERROR, "Could not create workout", nil)
|
|
576
|
-
return
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
// saving workout, samples and route
|
|
580
|
-
store.save(workout) { (_: Bool, error: Error?) in
|
|
581
|
-
guard error == nil else {
|
|
582
|
-
reject(GENERIC_ERROR, error!.localizedDescription, error)
|
|
583
|
-
return
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
if initializedSamples.isEmpty {
|
|
587
|
-
return resolve(workout.uuid.uuidString)
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
store.add(initializedSamples, to: workout) { (_, error: Error?) in
|
|
591
|
-
guard error == nil else {
|
|
592
|
-
reject(GENERIC_ERROR, error!.localizedDescription, error)
|
|
593
|
-
return
|
|
594
|
-
}
|
|
595
|
-
return resolve(workout.uuid.uuidString)
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
// function which will take an array of location in string format and create an array of CLLocations
|
|
601
|
-
func _createCLLocations(from locations: [[String: Any]]) -> [CLLocation] {
|
|
602
|
-
var clLocations: [CLLocation] = []
|
|
603
|
-
for location in locations {
|
|
604
|
-
guard let latitude = location["latitude"] as? CLLocationDegrees,
|
|
605
|
-
let longitude = location["longitude"] as? CLLocationDegrees,
|
|
606
|
-
let altitude = location["altitude"] as? CLLocationDistance,
|
|
607
|
-
let horizontalAccuracy = location["horizontalAccuracy"] as? CLLocationAccuracy,
|
|
608
|
-
let verticalAccuracy = location["verticalAccuracy"] as? CLLocationAccuracy,
|
|
609
|
-
let course = location["course"] as? CLLocationDirection,
|
|
610
|
-
let speed = location["speed"] as? CLLocationSpeed,
|
|
611
|
-
let timestamp = location["timestamp"] as? String
|
|
612
|
-
else {
|
|
613
|
-
continue
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
let date = self._dateFormatter.date(from: timestamp) ?? Date()
|
|
617
|
-
let clLocation = CLLocation(
|
|
618
|
-
coordinate: CLLocationCoordinate2D(
|
|
619
|
-
latitude: latitude,
|
|
620
|
-
longitude: longitude
|
|
621
|
-
), altitude: altitude,
|
|
622
|
-
horizontalAccuracy: horizontalAccuracy,
|
|
623
|
-
verticalAccuracy: verticalAccuracy,
|
|
624
|
-
course: course,
|
|
625
|
-
speed: speed,
|
|
626
|
-
timestamp: date
|
|
627
|
-
)
|
|
628
|
-
clLocations.append(clLocation)
|
|
629
|
-
}
|
|
630
|
-
return clLocations
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
@available(iOS 13.0.0, *)
|
|
634
|
-
@objc(saveWorkoutRoute:locations:resolve:reject:)
|
|
635
|
-
func saveWorkoutRoute(
|
|
636
|
-
workoutUUID: String,
|
|
637
|
-
locations: [[String: Any]],
|
|
638
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
639
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
640
|
-
) {
|
|
641
|
-
guard let store = _store else {
|
|
642
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
Task {
|
|
646
|
-
if let uuid = UUID(uuidString: workoutUUID) {
|
|
647
|
-
do {
|
|
648
|
-
let workout = await self.getWorkoutByID(store: store, workoutUUID: uuid)
|
|
649
|
-
if let workout {
|
|
650
|
-
// create CLLocations and return if locations are empty
|
|
651
|
-
let clLocations = self._createCLLocations(from: locations)
|
|
652
|
-
if clLocations.isEmpty {
|
|
653
|
-
return reject(GENERIC_ERROR, "No locations provided", nil)
|
|
654
|
-
}
|
|
655
|
-
// create route
|
|
656
|
-
let routeBuilder = HKWorkoutRouteBuilder(healthStore: store, device: nil)
|
|
657
|
-
try await routeBuilder.insertRouteData(clLocations)
|
|
658
|
-
try await routeBuilder.finishRoute(with: workout, metadata: nil)
|
|
659
|
-
|
|
660
|
-
return resolve(true)
|
|
661
|
-
} else {
|
|
662
|
-
return reject(GENERIC_ERROR, "No workout found", nil)
|
|
663
|
-
}
|
|
664
|
-
} catch {
|
|
665
|
-
return reject(GENERIC_ERROR, error.localizedDescription, error)
|
|
666
|
-
}
|
|
667
|
-
} else {
|
|
668
|
-
return reject(GENERIC_ERROR, "Invalid UUID", nil)
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
@objc(saveStateOfMindSample:kind:valence:labels:associations:metadata:resolve:reject:)
|
|
674
|
-
func saveStateOfMindSample(
|
|
675
|
-
_ date: Date,
|
|
676
|
-
kind: Int,
|
|
677
|
-
valence: Double, // non-integer number, ie 0.5
|
|
678
|
-
labels: [Int],
|
|
679
|
-
associations: [Int],
|
|
680
|
-
metadata: NSDictionary,
|
|
681
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
682
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
683
|
-
) {
|
|
684
|
-
guard let store = _store else {
|
|
685
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
#if compiler(>=6)
|
|
689
|
-
if #available(iOS 18.0, *) {
|
|
690
|
-
|
|
691
|
-
// ensures valence does not exceed -1.0 and 1.0
|
|
692
|
-
let safeValence = max(-1.0, min(1.0, valence))
|
|
693
|
-
|
|
694
|
-
let sample = HKStateOfMind(
|
|
695
|
-
date: date,
|
|
696
|
-
kind: HKStateOfMind.Kind.convertToStateOfMindKind(int: kind),
|
|
697
|
-
valence: safeValence,
|
|
698
|
-
labels: HKStateOfMind.Label.convertToStateOfMindLabels(intArray: labels),
|
|
699
|
-
associations: HKStateOfMind.Association.convertToStateOfMindAssociations(intArray: associations),
|
|
700
|
-
metadata: metadata as? [String: Any]
|
|
701
|
-
)
|
|
702
|
-
|
|
703
|
-
store.save(sample) { (success: Bool, error: Error?) in
|
|
704
|
-
guard let err = error else {
|
|
705
|
-
return resolve(success)
|
|
706
|
-
}
|
|
707
|
-
reject(GENERIC_ERROR, err.localizedDescription, error)
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
} else {
|
|
711
|
-
reject("STATE_OF_MIND_ERROR", "State of Mind features require iOS 18.0 or later", nil)
|
|
712
|
-
}
|
|
713
|
-
#else
|
|
714
|
-
reject(
|
|
715
|
-
"STATE_OF_MIND_ERROR", "State of Mind features require Xcode 16 or later to compile", nil)
|
|
716
|
-
#endif
|
|
717
|
-
}
|
|
718
|
-
|
|
719
|
-
@objc(saveCategorySample:value:start:end:metadata:resolve:reject:)
|
|
720
|
-
func saveCategorySample(
|
|
721
|
-
typeIdentifier: String,
|
|
722
|
-
value: Double,
|
|
723
|
-
start: Date,
|
|
724
|
-
end: Date,
|
|
725
|
-
metadata: NSDictionary,
|
|
726
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
727
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
728
|
-
) {
|
|
729
|
-
guard let store = _store else {
|
|
730
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
731
|
-
}
|
|
732
|
-
|
|
733
|
-
let identifier = HKCategoryTypeIdentifier.init(rawValue: typeIdentifier)
|
|
734
|
-
|
|
735
|
-
guard let type = HKObjectType.categoryType(forIdentifier: identifier) else {
|
|
736
|
-
return reject(TYPE_IDENTIFIER_ERROR, "Failed to initialize " + typeIdentifier, nil)
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
let sample = HKCategorySample.init(
|
|
740
|
-
type: type,
|
|
741
|
-
value: Int(value),
|
|
742
|
-
start: start,
|
|
743
|
-
end: end,
|
|
744
|
-
metadata: metadata as? [String: Any]
|
|
745
|
-
)
|
|
746
|
-
|
|
747
|
-
store.save(sample) { (success: Bool, error: Error?) in
|
|
748
|
-
guard let err = error else {
|
|
749
|
-
return resolve(success)
|
|
750
|
-
}
|
|
751
|
-
reject(GENERIC_ERROR, err.localizedDescription, error)
|
|
752
|
-
}
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
override func supportedEvents() -> [String]! {
|
|
756
|
-
return [
|
|
757
|
-
"onChange",
|
|
758
|
-
"onRemoteWorkoutStateChange",
|
|
759
|
-
"onRemoteWorkoutError",
|
|
760
|
-
"onRemoteWorkoutDataReceived",
|
|
761
|
-
"onRemoteWorkoutEventReceived"
|
|
762
|
-
]
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
@objc(enableBackgroundDelivery:updateFrequency:resolve:reject:)
|
|
766
|
-
func enableBackgroundDelivery(
|
|
767
|
-
typeIdentifier: String,
|
|
768
|
-
updateFrequency: Int,
|
|
769
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
770
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
771
|
-
) {
|
|
772
|
-
guard let store = _store else {
|
|
773
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
774
|
-
}
|
|
775
|
-
|
|
776
|
-
guard let sampleType = objectTypeFromString(typeIdentifier: typeIdentifier) else {
|
|
777
|
-
return reject(TYPE_IDENTIFIER_ERROR, "Failed to initialize " + typeIdentifier, nil)
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
guard let frequency = HKUpdateFrequency.init(rawValue: updateFrequency) else {
|
|
781
|
-
return reject("UpdateFrequency not valid", "UpdateFrequency not valid", nil)
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
store.enableBackgroundDelivery(for: sampleType, frequency: frequency) { (success, error) in
|
|
785
|
-
guard let err = error else {
|
|
786
|
-
return resolve(success)
|
|
787
|
-
}
|
|
788
|
-
reject(GENERIC_ERROR, err.localizedDescription, err)
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
@objc(disableAllBackgroundDelivery:reject:)
|
|
793
|
-
func disableAllBackgroundDelivery(
|
|
794
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
795
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
796
|
-
) {
|
|
797
|
-
guard let store = _store else {
|
|
798
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
799
|
-
}
|
|
800
|
-
|
|
801
|
-
store.disableAllBackgroundDelivery(completion: { (success, error) in
|
|
802
|
-
guard let err = error else {
|
|
803
|
-
return resolve(success)
|
|
804
|
-
}
|
|
805
|
-
reject(GENERIC_ERROR, err.localizedDescription, err)
|
|
806
|
-
})
|
|
807
|
-
}
|
|
808
|
-
|
|
809
|
-
@objc(disableBackgroundDelivery:resolve:reject:)
|
|
810
|
-
func disableBackgroundDelivery(
|
|
811
|
-
typeIdentifier: String,
|
|
812
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
813
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
814
|
-
) {
|
|
815
|
-
guard let store = _store else {
|
|
816
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
817
|
-
}
|
|
818
|
-
|
|
819
|
-
guard let sampleType = objectTypeFromString(typeIdentifier: typeIdentifier) else {
|
|
820
|
-
return reject(TYPE_IDENTIFIER_ERROR, "Failed to initialize " + typeIdentifier, nil)
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
store.disableBackgroundDelivery(for: sampleType) { (success, error) in
|
|
824
|
-
guard let err = error else {
|
|
825
|
-
return resolve(success)
|
|
826
|
-
}
|
|
827
|
-
reject(GENERIC_ERROR, err.localizedDescription, err)
|
|
828
|
-
}
|
|
829
|
-
}
|
|
830
|
-
|
|
831
|
-
@objc(subscribeToObserverQuery:resolve:reject:)
|
|
832
|
-
func subscribeToObserverQuery(
|
|
833
|
-
typeIdentifier: String,
|
|
834
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
835
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
836
|
-
) {
|
|
837
|
-
guard let store = _store else {
|
|
838
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
guard let sampleType = sampleTypeFromString(typeIdentifier: typeIdentifier) else {
|
|
842
|
-
return reject(TYPE_IDENTIFIER_ERROR, "Failed to initialize " + typeIdentifier, nil)
|
|
843
|
-
}
|
|
844
|
-
|
|
845
|
-
let predicate = HKQuery.predicateForSamples(
|
|
846
|
-
withStart: Date.init(),
|
|
847
|
-
end: nil,
|
|
848
|
-
options: HKQueryOptions.strictStartDate
|
|
849
|
-
)
|
|
850
|
-
|
|
851
|
-
let queryId = UUID().uuidString
|
|
852
|
-
|
|
853
|
-
func responder(
|
|
854
|
-
query: HKObserverQuery, handler: @escaping HKObserverQueryCompletionHandler, error: Error?
|
|
855
|
-
) {
|
|
856
|
-
if error == nil {
|
|
857
|
-
DispatchQueue.main.async {
|
|
858
|
-
if self._hasListeners {
|
|
859
|
-
self.sendEvent(
|
|
860
|
-
withName: "onChange",
|
|
861
|
-
body: [
|
|
862
|
-
"typeIdentifier": typeIdentifier
|
|
863
|
-
])
|
|
864
|
-
}
|
|
865
|
-
|
|
866
|
-
}
|
|
867
|
-
handler()
|
|
868
|
-
}
|
|
869
|
-
}
|
|
870
|
-
|
|
871
|
-
let query = HKObserverQuery(
|
|
872
|
-
sampleType: sampleType,
|
|
873
|
-
predicate: predicate
|
|
874
|
-
) {
|
|
875
|
-
(query: HKObserverQuery, handler: @escaping HKObserverQueryCompletionHandler, error: Error?)
|
|
876
|
-
in
|
|
877
|
-
guard let err = error else {
|
|
878
|
-
return responder(query: query, handler: handler, error: error)
|
|
879
|
-
}
|
|
880
|
-
reject(GENERIC_ERROR, err.localizedDescription, err)
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
store.execute(query)
|
|
884
|
-
|
|
885
|
-
self._runningQueries.updateValue(query, forKey: queryId)
|
|
886
|
-
|
|
887
|
-
resolve(queryId)
|
|
888
|
-
}
|
|
889
|
-
|
|
890
|
-
@objc(unsubscribeQuery:resolve:reject:)
|
|
891
|
-
func unsubscribeQuery(
|
|
892
|
-
queryId: String,
|
|
893
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
894
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
895
|
-
) {
|
|
896
|
-
guard let store = _store else {
|
|
897
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
898
|
-
}
|
|
899
|
-
|
|
900
|
-
guard let query = self._runningQueries[queryId] else {
|
|
901
|
-
reject("Error", "Query with id " + queryId + " not found", nil)
|
|
902
|
-
return
|
|
903
|
-
}
|
|
904
|
-
|
|
905
|
-
store.stop(query)
|
|
906
|
-
|
|
907
|
-
self._runningQueries.removeValue(forKey: queryId)
|
|
908
|
-
|
|
909
|
-
resolve(true)
|
|
910
|
-
}
|
|
911
|
-
|
|
912
|
-
static override func requiresMainQueueSetup() -> Bool {
|
|
913
|
-
return true
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
@objc(queryStatisticsForQuantity:unitString:from:to:options:resolve:reject:)
|
|
917
|
-
func queryStatisticsForQuantity(
|
|
918
|
-
typeIdentifier: String,
|
|
919
|
-
unitString: String,
|
|
920
|
-
from: Date,
|
|
921
|
-
to: Date,
|
|
922
|
-
options: NSArray,
|
|
923
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
924
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
925
|
-
) {
|
|
926
|
-
guard let store = _store else {
|
|
927
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
928
|
-
}
|
|
929
|
-
|
|
930
|
-
let identifier = HKQuantityTypeIdentifier.init(rawValue: typeIdentifier)
|
|
931
|
-
guard let quantityType = HKObjectType.quantityType(forIdentifier: identifier) else {
|
|
932
|
-
return reject(TYPE_IDENTIFIER_ERROR, "Failed to initialize " + typeIdentifier, nil)
|
|
933
|
-
}
|
|
934
|
-
|
|
935
|
-
let predicate = HKQuery.predicateForSamples(
|
|
936
|
-
withStart: from,
|
|
937
|
-
end: to,
|
|
938
|
-
options: HKQueryOptions.strictEndDate
|
|
939
|
-
)
|
|
940
|
-
|
|
941
|
-
var opts = HKStatisticsOptions.init()
|
|
942
|
-
|
|
943
|
-
for o in options {
|
|
944
|
-
let str = o as! String
|
|
945
|
-
if str == "cumulativeSum" {
|
|
946
|
-
opts.insert(HKStatisticsOptions.cumulativeSum)
|
|
947
|
-
} else if str == "discreteAverage" {
|
|
948
|
-
opts.insert(HKStatisticsOptions.discreteAverage)
|
|
949
|
-
} else if str == "discreteMax" {
|
|
950
|
-
opts.insert(HKStatisticsOptions.discreteMax)
|
|
951
|
-
} else if str == "discreteMin" {
|
|
952
|
-
opts.insert(HKStatisticsOptions.discreteMin)
|
|
953
|
-
}
|
|
954
|
-
if #available(iOS 12, *) {
|
|
955
|
-
if str == "discreteMostRecent" {
|
|
956
|
-
opts.insert(HKStatisticsOptions.discreteMostRecent)
|
|
957
|
-
}
|
|
958
|
-
}
|
|
959
|
-
if #available(iOS 13, *) {
|
|
960
|
-
if str == "duration" {
|
|
961
|
-
opts.insert(HKStatisticsOptions.duration)
|
|
962
|
-
}
|
|
963
|
-
if str == "mostRecent" {
|
|
964
|
-
opts.insert(HKStatisticsOptions.mostRecent)
|
|
965
|
-
}
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
if str == "separateBySource" {
|
|
969
|
-
opts.insert(HKStatisticsOptions.separateBySource)
|
|
970
|
-
}
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
let query = HKStatisticsQuery.init(
|
|
974
|
-
quantityType: quantityType,
|
|
975
|
-
quantitySamplePredicate: predicate,
|
|
976
|
-
options: opts
|
|
977
|
-
) { (_, stats: HKStatistics?, _: Error?) in
|
|
978
|
-
var dic = [String: [String: Any]?]()
|
|
979
|
-
|
|
980
|
-
guard let gottenStats = stats else {
|
|
981
|
-
return resolve(dic)
|
|
982
|
-
}
|
|
983
|
-
|
|
984
|
-
let unit = HKUnit.init(from: unitString)
|
|
985
|
-
if let averageQuantity = gottenStats.averageQuantity() {
|
|
986
|
-
dic.updateValue(
|
|
987
|
-
serializeQuantity(unit: unit, quantity: averageQuantity), forKey: "averageQuantity")
|
|
988
|
-
}
|
|
989
|
-
if let maximumQuantity = gottenStats.maximumQuantity() {
|
|
990
|
-
dic.updateValue(
|
|
991
|
-
serializeQuantity(unit: unit, quantity: maximumQuantity), forKey: "maximumQuantity")
|
|
992
|
-
}
|
|
993
|
-
if let minimumQuantity = gottenStats.minimumQuantity() {
|
|
994
|
-
dic.updateValue(
|
|
995
|
-
serializeQuantity(unit: unit, quantity: minimumQuantity), forKey: "minimumQuantity")
|
|
996
|
-
}
|
|
997
|
-
if let sumQuantity = gottenStats.sumQuantity() {
|
|
998
|
-
dic.updateValue(serializeQuantity(unit: unit, quantity: sumQuantity), forKey: "sumQuantity")
|
|
999
|
-
}
|
|
1000
|
-
if #available(iOS 12, *) {
|
|
1001
|
-
if let mostRecent = gottenStats.mostRecentQuantity() {
|
|
1002
|
-
dic.updateValue(
|
|
1003
|
-
serializeQuantity(unit: unit, quantity: mostRecent), forKey: "mostRecentQuantity")
|
|
1004
|
-
}
|
|
1005
|
-
|
|
1006
|
-
if let mostRecentDateInterval = gottenStats.mostRecentQuantityDateInterval() {
|
|
1007
|
-
dic.updateValue(
|
|
1008
|
-
[
|
|
1009
|
-
"start": self._dateFormatter.string(from: mostRecentDateInterval.start),
|
|
1010
|
-
"end": self._dateFormatter.string(from: mostRecentDateInterval.end)
|
|
1011
|
-
], forKey: "mostRecentQuantityDateInterval")
|
|
1012
|
-
}
|
|
1013
|
-
}
|
|
1014
|
-
if #available(iOS 13, *) {
|
|
1015
|
-
let durationUnit = HKUnit.second()
|
|
1016
|
-
dic["duration"] = serializeQuantityIfExists(
|
|
1017
|
-
unit: durationUnit, quantity: gottenStats.duration())
|
|
1018
|
-
}
|
|
1019
|
-
|
|
1020
|
-
resolve(dic)
|
|
1021
|
-
}
|
|
1022
|
-
|
|
1023
|
-
store.execute(query)
|
|
1024
|
-
}
|
|
1025
|
-
|
|
1026
|
-
@objc(
|
|
1027
|
-
queryStatisticsCollectionForQuantity:unitString:options:anchorDate:interval:startDate:endDate:
|
|
1028
|
-
resolve:reject:
|
|
1029
|
-
)
|
|
1030
|
-
func queryStatisticsCollectionForQuantity(
|
|
1031
|
-
typeIdentifier: String,
|
|
1032
|
-
unitString: String,
|
|
1033
|
-
options: NSArray,
|
|
1034
|
-
anchorDate: Date,
|
|
1035
|
-
interval: NSDictionary,
|
|
1036
|
-
startDate: Date,
|
|
1037
|
-
endDate: Date,
|
|
1038
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
1039
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
1040
|
-
) {
|
|
1041
|
-
guard let store = _store else {
|
|
1042
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
1043
|
-
}
|
|
1044
|
-
|
|
1045
|
-
guard
|
|
1046
|
-
let quantityType = HKObjectType.quantityType(
|
|
1047
|
-
forIdentifier: HKQuantityTypeIdentifier(rawValue: typeIdentifier))
|
|
1048
|
-
else {
|
|
1049
|
-
return reject(
|
|
1050
|
-
TYPE_IDENTIFIER_ERROR,
|
|
1051
|
-
"Failed to initialize quantity type for identifier: \(typeIdentifier)", nil)
|
|
1052
|
-
}
|
|
1053
|
-
|
|
1054
|
-
let opts = hkStatisticsOptionsFromOptions(options)
|
|
1055
|
-
let intervalComponents = componentsFromInterval(interval)
|
|
1056
|
-
|
|
1057
|
-
let query = HKStatisticsCollectionQuery(
|
|
1058
|
-
quantityType: quantityType,
|
|
1059
|
-
quantitySamplePredicate: nil, // We will use enumerateStatistics to filter with date
|
|
1060
|
-
options: opts,
|
|
1061
|
-
anchorDate: anchorDate,
|
|
1062
|
-
intervalComponents: intervalComponents
|
|
1063
|
-
)
|
|
1064
|
-
|
|
1065
|
-
query.initialResultsHandler = { _, statsCollection, error in
|
|
1066
|
-
if let error = error {
|
|
1067
|
-
return reject(QUERY_ERROR, error.localizedDescription, error)
|
|
1068
|
-
}
|
|
1069
|
-
|
|
1070
|
-
var results = [[String: [String: Any]?]]()
|
|
1071
|
-
|
|
1072
|
-
guard let collection = statsCollection else {
|
|
1073
|
-
return resolve(results)
|
|
1074
|
-
}
|
|
1075
|
-
|
|
1076
|
-
let unit = HKUnit(from: unitString)
|
|
1077
|
-
|
|
1078
|
-
collection.enumerateStatistics(from: startDate, to: endDate) { stats, _ in
|
|
1079
|
-
var dic = [String: [String: Any]?]()
|
|
1080
|
-
|
|
1081
|
-
let startDate = self._dateFormatter.string(from: stats.startDate)
|
|
1082
|
-
let endDate = self._dateFormatter.string(from: stats.endDate)
|
|
1083
|
-
|
|
1084
|
-
dic["averageQuantity"] = serializeQuantityIfExists(
|
|
1085
|
-
unit: unit, quantity: stats.averageQuantity())
|
|
1086
|
-
dic["maximumQuantity"] = serializeQuantityIfExists(
|
|
1087
|
-
unit: unit, quantity: stats.maximumQuantity())
|
|
1088
|
-
dic["minimumQuantity"] = serializeQuantityIfExists(
|
|
1089
|
-
unit: unit, quantity: stats.minimumQuantity())
|
|
1090
|
-
dic["sumQuantity"] = serializeStatisticIfExists(
|
|
1091
|
-
unit: unit, quantity: stats.sumQuantity(), stats: stats)
|
|
1092
|
-
|
|
1093
|
-
if #available(iOS 12, *) {
|
|
1094
|
-
dic["mostRecentQuantity"] = serializeQuantityIfExists(
|
|
1095
|
-
unit: unit, quantity: stats.mostRecentQuantity())
|
|
1096
|
-
if let mostRecentDateInterval = stats.mostRecentQuantityDateInterval() {
|
|
1097
|
-
dic["mostRecentQuantityDateInterval"] = [
|
|
1098
|
-
"start": self._dateFormatter.string(from: mostRecentDateInterval.start),
|
|
1099
|
-
"end": self._dateFormatter.string(from: mostRecentDateInterval.end)
|
|
1100
|
-
]
|
|
1101
|
-
}
|
|
1102
|
-
}
|
|
1103
|
-
|
|
1104
|
-
if #available(iOS 13, *) {
|
|
1105
|
-
let durationUnit = HKUnit.second()
|
|
1106
|
-
dic["duration"] = serializeQuantityIfExists(
|
|
1107
|
-
unit: durationUnit, quantity: stats.duration())
|
|
1108
|
-
}
|
|
1109
|
-
|
|
1110
|
-
results.append(dic)
|
|
1111
|
-
}
|
|
1112
|
-
|
|
1113
|
-
resolve(results)
|
|
1114
|
-
}
|
|
1115
|
-
|
|
1116
|
-
store.execute(query)
|
|
1117
|
-
}
|
|
1118
|
-
|
|
1119
|
-
func mapWorkout(
|
|
1120
|
-
workout: HKWorkout,
|
|
1121
|
-
distanceUnit: HKUnit,
|
|
1122
|
-
energyUnit: HKUnit
|
|
1123
|
-
) -> NSMutableDictionary {
|
|
1124
|
-
let endDate = self._dateFormatter.string(from: workout.endDate)
|
|
1125
|
-
let startDate = self._dateFormatter.string(from: workout.startDate)
|
|
1126
|
-
|
|
1127
|
-
let dict: NSMutableDictionary = [
|
|
1128
|
-
"uuid": workout.uuid.uuidString,
|
|
1129
|
-
"device": serializeDevice(_device: workout.device) as Any,
|
|
1130
|
-
"duration": workout.duration,
|
|
1131
|
-
"totalDistance": serializeQuantity(unit: distanceUnit, quantity: workout.totalDistance)
|
|
1132
|
-
as Any,
|
|
1133
|
-
"totalEnergyBurned": serializeQuantity(unit: energyUnit, quantity: workout.totalEnergyBurned)
|
|
1134
|
-
as Any,
|
|
1135
|
-
"totalSwimmingStrokeCount": serializeQuantity(
|
|
1136
|
-
unit: HKUnit.count(), quantity: workout.totalSwimmingStrokeCount) as Any,
|
|
1137
|
-
"workoutActivityType": workout.workoutActivityType.rawValue,
|
|
1138
|
-
"startDate": startDate,
|
|
1139
|
-
"endDate": endDate,
|
|
1140
|
-
"metadata": serializeMetadata(metadata: workout.metadata),
|
|
1141
|
-
"sourceRevision": serializeSourceRevision(_sourceRevision: workout.sourceRevision) as Any
|
|
1142
|
-
]
|
|
1143
|
-
|
|
1144
|
-
// this is used for our laps functionality to get markers
|
|
1145
|
-
// https://developer.apple.com/documentation/healthkit/hkworkoutevent
|
|
1146
|
-
var eventArray: [[String: Any]] = []
|
|
1147
|
-
if let events = workout.workoutEvents {
|
|
1148
|
-
for event in events {
|
|
1149
|
-
let eventStartDate = self._dateFormatter.string(from: event.dateInterval.start)
|
|
1150
|
-
let eventEndDate = self._dateFormatter.string(from: event.dateInterval.end)
|
|
1151
|
-
let eventDict: [String: Any] = [
|
|
1152
|
-
"type": event.type.rawValue, // https://developer.apple.com/documentation/healthkit/hkworkouteventtype
|
|
1153
|
-
"startDate": eventStartDate,
|
|
1154
|
-
"endDate": eventEndDate
|
|
1155
|
-
]
|
|
1156
|
-
eventArray.append(eventDict)
|
|
1157
|
-
}
|
|
1158
|
-
}
|
|
1159
|
-
dict["events"] = eventArray
|
|
1160
|
-
|
|
1161
|
-
// also used for our laps functionality to get activities for custom workouts defined by the user
|
|
1162
|
-
// https://developer.apple.com/documentation/healthkit/hkworkout/1615340-init
|
|
1163
|
-
// it seems this might be depricated in the latest beta so this might need updating!
|
|
1164
|
-
var activitiesArray: [[String: Any]] = []
|
|
1165
|
-
if #available(iOS 16.0, *) {
|
|
1166
|
-
let activities: [HKWorkoutActivity] = workout.workoutActivities
|
|
1167
|
-
|
|
1168
|
-
if !activities.isEmpty {
|
|
1169
|
-
for activity in activities {
|
|
1170
|
-
var activityStartDate = ""
|
|
1171
|
-
var activityEndDate = ""
|
|
1172
|
-
if let start = activity.startDate as Date? {
|
|
1173
|
-
activityStartDate = self._dateFormatter.string(from: start)
|
|
1174
|
-
}
|
|
1175
|
-
if let end = activity.endDate as Date? {
|
|
1176
|
-
activityEndDate = self._dateFormatter.string(from: end)
|
|
1177
|
-
}
|
|
1178
|
-
let activityDict: [String: Any] = [
|
|
1179
|
-
"startDate": activityStartDate,
|
|
1180
|
-
"endDate": activityEndDate,
|
|
1181
|
-
"uuid": activity.uuid.uuidString,
|
|
1182
|
-
"duration": activity.duration
|
|
1183
|
-
]
|
|
1184
|
-
activitiesArray.append(activityDict)
|
|
1185
|
-
}
|
|
1186
|
-
}
|
|
1187
|
-
}
|
|
1188
|
-
dict["activities"] = activitiesArray
|
|
1189
|
-
|
|
1190
|
-
if #available(iOS 11, *) {
|
|
1191
|
-
dict.setValue(
|
|
1192
|
-
serializeQuantity(unit: HKUnit.count(), quantity: workout.totalFlightsClimbed),
|
|
1193
|
-
forKey: "totalFlightsClimbed")
|
|
1194
|
-
}
|
|
1195
|
-
return dict
|
|
1196
|
-
}
|
|
1197
|
-
|
|
1198
|
-
@objc(queryWorkoutSamples:distanceUnitString:from:to:limit:ascending:resolve:reject:)
|
|
1199
|
-
func queryWorkoutSamples(
|
|
1200
|
-
energyUnitString: String,
|
|
1201
|
-
distanceUnitString: String,
|
|
1202
|
-
from: Date,
|
|
1203
|
-
to: Date,
|
|
1204
|
-
limit: Int,
|
|
1205
|
-
ascending: Bool,
|
|
1206
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
1207
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
1208
|
-
) {
|
|
1209
|
-
guard let store = _store else {
|
|
1210
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
1211
|
-
}
|
|
1212
|
-
|
|
1213
|
-
let from = dateOrNilIfZero(date: from)
|
|
1214
|
-
let to = dateOrNilIfZero(date: to)
|
|
1215
|
-
|
|
1216
|
-
let predicate = createPredicate(from: from, to: to)
|
|
1217
|
-
|
|
1218
|
-
let limit = limitOrNilIfZero(limit: limit)
|
|
1219
|
-
|
|
1220
|
-
let energyUnit = HKUnit.init(from: energyUnitString)
|
|
1221
|
-
let distanceUnit = HKUnit.init(from: distanceUnitString)
|
|
1222
|
-
|
|
1223
|
-
let q = HKSampleQuery(
|
|
1224
|
-
sampleType: .workoutType(),
|
|
1225
|
-
predicate: predicate,
|
|
1226
|
-
limit: limit,
|
|
1227
|
-
sortDescriptors: getSortDescriptors(ascending: ascending)
|
|
1228
|
-
) { (_: HKSampleQuery, sample: [HKSample]?, error: Error?) in
|
|
1229
|
-
guard let err = error else {
|
|
1230
|
-
guard let samples = sample else {
|
|
1231
|
-
return resolve([])
|
|
1232
|
-
}
|
|
1233
|
-
let arr: NSMutableArray = []
|
|
1234
|
-
|
|
1235
|
-
for s in samples {
|
|
1236
|
-
if let workout = s as? HKWorkout {
|
|
1237
|
-
let dict = self.mapWorkout(
|
|
1238
|
-
workout: workout,
|
|
1239
|
-
distanceUnit: distanceUnit,
|
|
1240
|
-
energyUnit: energyUnit
|
|
1241
|
-
)
|
|
1242
|
-
|
|
1243
|
-
arr.add(dict)
|
|
1244
|
-
}
|
|
1245
|
-
}
|
|
1246
|
-
|
|
1247
|
-
return resolve(arr)
|
|
1248
|
-
}
|
|
1249
|
-
reject(GENERIC_ERROR, err.localizedDescription, err)
|
|
1250
|
-
}
|
|
1251
|
-
|
|
1252
|
-
store.execute(q)
|
|
1253
|
-
}
|
|
1254
|
-
|
|
1255
|
-
@objc(queryWorkoutSamplesWithAnchor:distanceUnitString:from:to:limit:anchor:resolve:reject:)
|
|
1256
|
-
func queryWorkoutSamplesWithAnchor(
|
|
1257
|
-
energyUnitString: String,
|
|
1258
|
-
distanceUnitString: String,
|
|
1259
|
-
from: Date,
|
|
1260
|
-
to: Date,
|
|
1261
|
-
limit: Int,
|
|
1262
|
-
anchor: String,
|
|
1263
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
1264
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
1265
|
-
) {
|
|
1266
|
-
guard let store = _store else {
|
|
1267
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
1268
|
-
}
|
|
1269
|
-
|
|
1270
|
-
let from = dateOrNilIfZero(date: from)
|
|
1271
|
-
let to = dateOrNilIfZero(date: to)
|
|
1272
|
-
|
|
1273
|
-
let predicate = createPredicate(from: from, to: to)
|
|
1274
|
-
|
|
1275
|
-
let limit = limitOrNilIfZero(limit: limit)
|
|
1276
|
-
|
|
1277
|
-
let energyUnit = HKUnit.init(from: energyUnitString)
|
|
1278
|
-
let distanceUnit = HKUnit.init(from: distanceUnitString)
|
|
1279
|
-
|
|
1280
|
-
let actualAnchor = deserializeHKQueryAnchor(anchor: anchor)
|
|
1281
|
-
|
|
1282
|
-
let q = HKAnchoredObjectQuery(
|
|
1283
|
-
type: .workoutType(), predicate: predicate, anchor: actualAnchor, limit: limit
|
|
1284
|
-
) {
|
|
1285
|
-
(
|
|
1286
|
-
_: HKAnchoredObjectQuery,
|
|
1287
|
-
s: [HKSample]?,
|
|
1288
|
-
deletedSamples: [HKDeletedObject]?,
|
|
1289
|
-
newAnchor: HKQueryAnchor?,
|
|
1290
|
-
error: Error?
|
|
1291
|
-
) in
|
|
1292
|
-
guard let err = error else {
|
|
1293
|
-
guard let samples = s else {
|
|
1294
|
-
return resolve([])
|
|
1295
|
-
}
|
|
1296
|
-
|
|
1297
|
-
let arr: NSMutableArray = []
|
|
1298
|
-
|
|
1299
|
-
for s in samples {
|
|
1300
|
-
if let workout = s as? HKWorkout {
|
|
1301
|
-
let dict = self.mapWorkout(
|
|
1302
|
-
workout: workout,
|
|
1303
|
-
distanceUnit: distanceUnit,
|
|
1304
|
-
energyUnit: energyUnit
|
|
1305
|
-
)
|
|
1306
|
-
|
|
1307
|
-
arr.add(dict)
|
|
1308
|
-
}
|
|
1309
|
-
}
|
|
1310
|
-
|
|
1311
|
-
return resolve([
|
|
1312
|
-
"samples": arr as Any,
|
|
1313
|
-
"deletedSamples": deletedSamples?.map({ sample in
|
|
1314
|
-
return serializeDeletedSample(sample: sample)
|
|
1315
|
-
}) as Any,
|
|
1316
|
-
"newAnchor": serializeAnchor(anchor: newAnchor) as Any
|
|
1317
|
-
])
|
|
1318
|
-
}
|
|
1319
|
-
reject(GENERIC_ERROR, err.localizedDescription, err)
|
|
1320
|
-
}
|
|
1321
|
-
|
|
1322
|
-
store.execute(q)
|
|
1323
|
-
}
|
|
1324
|
-
|
|
1325
|
-
@objc(queryQuantitySamples:unitString:from:to:limit:ascending:resolve:reject:)
|
|
1326
|
-
func queryQuantitySamples(
|
|
1327
|
-
typeIdentifier: String,
|
|
1328
|
-
unitString: String,
|
|
1329
|
-
from: Date,
|
|
1330
|
-
to: Date,
|
|
1331
|
-
limit: Int,
|
|
1332
|
-
ascending: Bool,
|
|
1333
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
1334
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
1335
|
-
) {
|
|
1336
|
-
guard let store = _store else {
|
|
1337
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
1338
|
-
}
|
|
1339
|
-
|
|
1340
|
-
let identifier = HKQuantityTypeIdentifier.init(rawValue: typeIdentifier)
|
|
1341
|
-
guard let sampleType = HKSampleType.quantityType(forIdentifier: identifier) else {
|
|
1342
|
-
return reject(TYPE_IDENTIFIER_ERROR, "Failed to initialize " + typeIdentifier, nil)
|
|
1343
|
-
}
|
|
1344
|
-
|
|
1345
|
-
let from = dateOrNilIfZero(date: from)
|
|
1346
|
-
let to = dateOrNilIfZero(date: to)
|
|
1347
|
-
let predicate = createPredicate(from: from, to: to)
|
|
1348
|
-
let limit = limitOrNilIfZero(limit: limit)
|
|
1349
|
-
|
|
1350
|
-
let q = HKSampleQuery(
|
|
1351
|
-
sampleType: sampleType,
|
|
1352
|
-
predicate: predicate,
|
|
1353
|
-
limit: limit,
|
|
1354
|
-
sortDescriptors: getSortDescriptors(ascending: ascending)
|
|
1355
|
-
) { (_: HKSampleQuery, sample: [HKSample]?, error: Error?) in
|
|
1356
|
-
guard let err = error else {
|
|
1357
|
-
guard let samples = sample else {
|
|
1358
|
-
return resolve([])
|
|
1359
|
-
}
|
|
1360
|
-
let arr: NSMutableArray = []
|
|
1361
|
-
|
|
1362
|
-
for s in samples {
|
|
1363
|
-
if let sample = s as? HKQuantitySample {
|
|
1364
|
-
let serialized = serializeQuantitySample(
|
|
1365
|
-
sample: sample, unit: HKUnit.init(from: unitString))
|
|
1366
|
-
|
|
1367
|
-
arr.add(serialized)
|
|
1368
|
-
}
|
|
1369
|
-
}
|
|
1370
|
-
|
|
1371
|
-
return resolve(arr)
|
|
1372
|
-
}
|
|
1373
|
-
reject(GENERIC_ERROR, err.localizedDescription, err)
|
|
1374
|
-
}
|
|
1375
|
-
|
|
1376
|
-
store.execute(q)
|
|
1377
|
-
}
|
|
1378
|
-
|
|
1379
|
-
@objc(queryCorrelationSamples:from:to:resolve:reject:)
|
|
1380
|
-
func queryCorrelationSamples(
|
|
1381
|
-
typeIdentifier: String,
|
|
1382
|
-
from: Date,
|
|
1383
|
-
to: Date,
|
|
1384
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
1385
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
1386
|
-
) {
|
|
1387
|
-
guard let store = _store else {
|
|
1388
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
1389
|
-
}
|
|
1390
|
-
|
|
1391
|
-
let identifier = HKCorrelationTypeIdentifier.init(rawValue: typeIdentifier)
|
|
1392
|
-
guard let sampleType = HKSampleType.correlationType(forIdentifier: identifier) else {
|
|
1393
|
-
return reject(TYPE_IDENTIFIER_ERROR, "Failed to initialize " + typeIdentifier, nil)
|
|
1394
|
-
}
|
|
1395
|
-
|
|
1396
|
-
let from = from.timeIntervalSince1970 >= 0 ? from : nil
|
|
1397
|
-
let to = to.timeIntervalSince1970 >= 0 ? to : nil
|
|
1398
|
-
|
|
1399
|
-
let predicate = createPredicate(from: from, to: to)
|
|
1400
|
-
|
|
1401
|
-
let q = HKCorrelationQuery(
|
|
1402
|
-
type: sampleType,
|
|
1403
|
-
predicate: predicate,
|
|
1404
|
-
samplePredicates: nil
|
|
1405
|
-
) { (_: HKCorrelationQuery, _correlations: [HKCorrelation]?, error: Error?) in
|
|
1406
|
-
guard let err = error else {
|
|
1407
|
-
guard let correlations = _correlations else {
|
|
1408
|
-
return resolve([])
|
|
1409
|
-
}
|
|
1410
|
-
|
|
1411
|
-
var qts = Set<HKQuantityType>()
|
|
1412
|
-
for c in correlations {
|
|
1413
|
-
for object in c.objects {
|
|
1414
|
-
if let quantitySample = object as? HKQuantitySample {
|
|
1415
|
-
qts.insert(quantitySample.quantityType)
|
|
1416
|
-
}
|
|
1417
|
-
}
|
|
1418
|
-
}
|
|
1419
|
-
return store.preferredUnits(for: qts) { (map: [HKQuantityType: HKUnit], error: Error?) in
|
|
1420
|
-
guard let e = error else {
|
|
1421
|
-
let collerationsToReturn: NSMutableArray = []
|
|
1422
|
-
for c in correlations {
|
|
1423
|
-
let objects = NSMutableArray()
|
|
1424
|
-
for o in c.objects {
|
|
1425
|
-
if let quantitySample = o as? HKQuantitySample {
|
|
1426
|
-
objects.add(
|
|
1427
|
-
serializeQuantitySample(
|
|
1428
|
-
sample: quantitySample,
|
|
1429
|
-
unit: map[quantitySample.quantityType]!
|
|
1430
|
-
)
|
|
1431
|
-
)
|
|
1432
|
-
}
|
|
1433
|
-
if let categorySample = o as? HKCategorySample {
|
|
1434
|
-
objects.add(serializeCategorySample(sample: categorySample))
|
|
1435
|
-
}
|
|
1436
|
-
}
|
|
1437
|
-
|
|
1438
|
-
collerationsToReturn.add([
|
|
1439
|
-
"uuid": c.uuid.uuidString,
|
|
1440
|
-
"device": serializeDevice(_device: c.device) as Any,
|
|
1441
|
-
"correlationType": c.correlationType.identifier,
|
|
1442
|
-
"objects": objects,
|
|
1443
|
-
"metadata": serializeMetadata(metadata: c.metadata),
|
|
1444
|
-
"startDate": self._dateFormatter.string(from: c.startDate),
|
|
1445
|
-
"endDate": self._dateFormatter.string(from: c.endDate)
|
|
1446
|
-
])
|
|
1447
|
-
}
|
|
1448
|
-
|
|
1449
|
-
return resolve(collerationsToReturn)
|
|
1450
|
-
}
|
|
1451
|
-
reject(GENERIC_ERROR, e.localizedDescription, e)
|
|
1452
|
-
}
|
|
1453
|
-
}
|
|
1454
|
-
reject(GENERIC_ERROR, err.localizedDescription, err)
|
|
1455
|
-
}
|
|
1456
|
-
|
|
1457
|
-
store.execute(q)
|
|
1458
|
-
}
|
|
1459
|
-
|
|
1460
|
-
@objc(queryCategorySamples:from:to:limit:ascending:resolve:reject:)
|
|
1461
|
-
func queryCategorySamples(
|
|
1462
|
-
typeIdentifier: String,
|
|
1463
|
-
from: Date,
|
|
1464
|
-
to: Date,
|
|
1465
|
-
limit: Int,
|
|
1466
|
-
ascending: Bool,
|
|
1467
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
1468
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
1469
|
-
) {
|
|
1470
|
-
guard let store = _store else {
|
|
1471
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
1472
|
-
}
|
|
1473
|
-
|
|
1474
|
-
let identifier = HKCategoryTypeIdentifier.init(rawValue: typeIdentifier)
|
|
1475
|
-
guard let sampleType = HKSampleType.categoryType(forIdentifier: identifier) else {
|
|
1476
|
-
return reject(TYPE_IDENTIFIER_ERROR, "Failed to initialize " + typeIdentifier, nil)
|
|
1477
|
-
}
|
|
1478
|
-
|
|
1479
|
-
let from = dateOrNilIfZero(date: from)
|
|
1480
|
-
let to = dateOrNilIfZero(date: to)
|
|
1481
|
-
let predicate = createPredicate(from: from, to: to)
|
|
1482
|
-
let limit = limitOrNilIfZero(limit: limit)
|
|
1483
|
-
|
|
1484
|
-
let q = HKSampleQuery(
|
|
1485
|
-
sampleType: sampleType, predicate: predicate, limit: limit,
|
|
1486
|
-
sortDescriptors: getSortDescriptors(ascending: ascending)
|
|
1487
|
-
) { (_: HKSampleQuery, sample: [HKSample]?, error: Error?) in
|
|
1488
|
-
guard let err = error else {
|
|
1489
|
-
guard let samples = sample else {
|
|
1490
|
-
return resolve([])
|
|
1491
|
-
}
|
|
1492
|
-
let arr: NSMutableArray = []
|
|
1493
|
-
|
|
1494
|
-
for s in samples {
|
|
1495
|
-
if let sample = s as? HKCategorySample {
|
|
1496
|
-
let serialized = serializeCategorySample(sample: sample)
|
|
1497
|
-
|
|
1498
|
-
arr.add(serialized)
|
|
1499
|
-
}
|
|
1500
|
-
}
|
|
1501
|
-
return resolve(arr)
|
|
1502
|
-
}
|
|
1503
|
-
|
|
1504
|
-
reject(GENERIC_ERROR, err.localizedDescription, err)
|
|
1505
|
-
}
|
|
1506
|
-
|
|
1507
|
-
store.execute(q)
|
|
1508
|
-
}
|
|
1509
|
-
|
|
1510
|
-
@objc(queryQuantitySamplesWithAnchor:unitString:from:to:limit:anchor:resolve:reject:)
|
|
1511
|
-
func queryQuantitySamplesWithAnchor(
|
|
1512
|
-
typeIdentifier: String,
|
|
1513
|
-
unitString: String,
|
|
1514
|
-
from: Date,
|
|
1515
|
-
to: Date,
|
|
1516
|
-
limit: Int,
|
|
1517
|
-
anchor: String,
|
|
1518
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
1519
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
1520
|
-
) {
|
|
1521
|
-
guard let store = _store else {
|
|
1522
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
1523
|
-
}
|
|
1524
|
-
|
|
1525
|
-
let identifier = HKQuantityTypeIdentifier.init(rawValue: typeIdentifier)
|
|
1526
|
-
guard let sampleType = HKSampleType.quantityType(forIdentifier: identifier) else {
|
|
1527
|
-
return reject(TYPE_IDENTIFIER_ERROR, "Failed to initialize " + typeIdentifier, nil)
|
|
1528
|
-
}
|
|
1529
|
-
|
|
1530
|
-
let from = dateOrNilIfZero(date: from)
|
|
1531
|
-
let to = dateOrNilIfZero(date: to)
|
|
1532
|
-
let predicate = createPredicate(from: from, to: to)
|
|
1533
|
-
let limit = limitOrNilIfZero(limit: limit)
|
|
1534
|
-
|
|
1535
|
-
let actualAnchor = deserializeHKQueryAnchor(anchor: anchor)
|
|
1536
|
-
|
|
1537
|
-
let q = HKAnchoredObjectQuery(
|
|
1538
|
-
type: sampleType,
|
|
1539
|
-
predicate: predicate,
|
|
1540
|
-
anchor: actualAnchor,
|
|
1541
|
-
limit: limit
|
|
1542
|
-
) {
|
|
1543
|
-
(
|
|
1544
|
-
_: HKAnchoredObjectQuery,
|
|
1545
|
-
s: [HKSample]?,
|
|
1546
|
-
deletedSamples: [HKDeletedObject]?,
|
|
1547
|
-
newAnchor: HKQueryAnchor?,
|
|
1548
|
-
error: Error?
|
|
1549
|
-
) in
|
|
1550
|
-
guard let err = error else {
|
|
1551
|
-
guard let samples = s else {
|
|
1552
|
-
return resolve([])
|
|
1553
|
-
}
|
|
1554
|
-
|
|
1555
|
-
return resolve([
|
|
1556
|
-
"samples": samples.map({ sample in
|
|
1557
|
-
let serialized = serializeQuantitySample(
|
|
1558
|
-
sample: sample as! HKQuantitySample,
|
|
1559
|
-
unit: HKUnit.init(from: unitString)
|
|
1560
|
-
)
|
|
1561
|
-
|
|
1562
|
-
return serialized
|
|
1563
|
-
}) as Any,
|
|
1564
|
-
"deletedSamples": deletedSamples?.map({ sample in
|
|
1565
|
-
return serializeDeletedSample(sample: sample)
|
|
1566
|
-
}) as Any,
|
|
1567
|
-
"newAnchor": serializeAnchor(anchor: newAnchor) as Any
|
|
1568
|
-
])
|
|
1569
|
-
}
|
|
1570
|
-
reject(GENERIC_ERROR, err.localizedDescription, err)
|
|
1571
|
-
}
|
|
1572
|
-
|
|
1573
|
-
store.execute(q)
|
|
1574
|
-
}
|
|
1575
|
-
|
|
1576
|
-
@objc(queryCategorySamplesWithAnchor:from:to:limit:anchor:resolve:reject:)
|
|
1577
|
-
func queryCategorySamplesWithAnchor(
|
|
1578
|
-
typeIdentifier: String,
|
|
1579
|
-
from: Date,
|
|
1580
|
-
to: Date,
|
|
1581
|
-
limit: Int,
|
|
1582
|
-
anchor: String,
|
|
1583
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
1584
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
1585
|
-
) {
|
|
1586
|
-
guard let store = _store else {
|
|
1587
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
1588
|
-
}
|
|
1589
|
-
|
|
1590
|
-
let identifier = HKCategoryTypeIdentifier.init(rawValue: typeIdentifier)
|
|
1591
|
-
guard let sampleType = HKSampleType.categoryType(forIdentifier: identifier) else {
|
|
1592
|
-
return reject(TYPE_IDENTIFIER_ERROR, "Failed to initialize " + typeIdentifier, nil)
|
|
1593
|
-
}
|
|
1594
|
-
|
|
1595
|
-
let from = dateOrNilIfZero(date: from)
|
|
1596
|
-
let to = dateOrNilIfZero(date: to)
|
|
1597
|
-
let predicate = createPredicate(from: from, to: to)
|
|
1598
|
-
let limit = limitOrNilIfZero(limit: limit)
|
|
1599
|
-
|
|
1600
|
-
let q = HKAnchoredObjectQuery(
|
|
1601
|
-
type: sampleType,
|
|
1602
|
-
predicate: predicate,
|
|
1603
|
-
anchor: anchor != "" ? base64StringToHKQueryAnchor(base64String: anchor) : nil,
|
|
1604
|
-
limit: limit
|
|
1605
|
-
) {
|
|
1606
|
-
(
|
|
1607
|
-
_: HKAnchoredObjectQuery,
|
|
1608
|
-
s: [HKSample]?,
|
|
1609
|
-
deletedSamples: [HKDeletedObject]?,
|
|
1610
|
-
newAnchor: HKQueryAnchor?,
|
|
1611
|
-
error: Error?
|
|
1612
|
-
) in
|
|
1613
|
-
guard let err = error else {
|
|
1614
|
-
guard let samples = s else {
|
|
1615
|
-
return resolve([])
|
|
1616
|
-
}
|
|
1617
|
-
|
|
1618
|
-
let arr: NSMutableArray = []
|
|
1619
|
-
|
|
1620
|
-
for s in samples {
|
|
1621
|
-
if let sample = s as? HKCategorySample {
|
|
1622
|
-
let serialized = serializeCategorySample(sample: sample)
|
|
1623
|
-
|
|
1624
|
-
arr.add(serialized)
|
|
1625
|
-
}
|
|
1626
|
-
}
|
|
1627
|
-
|
|
1628
|
-
return resolve([
|
|
1629
|
-
"samples": arr,
|
|
1630
|
-
"deletedSamples": deletedSamples?.map({ sample in
|
|
1631
|
-
return serializeDeletedSample(sample: sample)
|
|
1632
|
-
}) as Any,
|
|
1633
|
-
"newAnchor": serializeAnchor(anchor: newAnchor) as Any
|
|
1634
|
-
])
|
|
1635
|
-
}
|
|
1636
|
-
reject(GENERIC_ERROR, err.localizedDescription, err)
|
|
1637
|
-
}
|
|
1638
|
-
|
|
1639
|
-
store.execute(q)
|
|
1640
|
-
}
|
|
1641
|
-
|
|
1642
|
-
@objc(querySources:resolve:reject:)
|
|
1643
|
-
func querySources(
|
|
1644
|
-
typeIdentifier: String,
|
|
1645
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
1646
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
1647
|
-
) {
|
|
1648
|
-
|
|
1649
|
-
guard let store = _store else {
|
|
1650
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
1651
|
-
}
|
|
1652
|
-
|
|
1653
|
-
guard let type = objectTypeFromString(typeIdentifier: typeIdentifier) else {
|
|
1654
|
-
return reject(TYPE_IDENTIFIER_ERROR, "Failed to initialize " + typeIdentifier, nil)
|
|
1655
|
-
}
|
|
1656
|
-
|
|
1657
|
-
let query = HKSourceQuery(
|
|
1658
|
-
sampleType: type as! HKSampleType,
|
|
1659
|
-
samplePredicate: nil
|
|
1660
|
-
) {
|
|
1661
|
-
(
|
|
1662
|
-
_: HKSourceQuery,
|
|
1663
|
-
source: Set<HKSource>?,
|
|
1664
|
-
error: Error?
|
|
1665
|
-
) in
|
|
1666
|
-
guard let err = error else {
|
|
1667
|
-
guard let sources = source else {
|
|
1668
|
-
return resolve([])
|
|
1669
|
-
}
|
|
1670
|
-
let arr: NSMutableArray = []
|
|
1671
|
-
|
|
1672
|
-
for s in sources {
|
|
1673
|
-
let serialized = serializeSource(source: s)
|
|
1674
|
-
|
|
1675
|
-
arr.add(serialized)
|
|
1676
|
-
}
|
|
1677
|
-
|
|
1678
|
-
return resolve(arr)
|
|
1679
|
-
}
|
|
1680
|
-
reject(GENERIC_ERROR, err.localizedDescription, err)
|
|
1681
|
-
|
|
1682
|
-
}
|
|
1683
|
-
|
|
1684
|
-
store.execute(query)
|
|
1685
|
-
}
|
|
1686
|
-
|
|
1687
|
-
@objc(requestAuthorization:read:resolve:withRejecter:)
|
|
1688
|
-
func requestAuthorization(
|
|
1689
|
-
toShare: NSDictionary,
|
|
1690
|
-
read: NSDictionary,
|
|
1691
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
1692
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
1693
|
-
) {
|
|
1694
|
-
guard let store = _store else {
|
|
1695
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
1696
|
-
}
|
|
1697
|
-
|
|
1698
|
-
let share = sampleTypesFromDictionary(typeIdentifiers: toShare)
|
|
1699
|
-
let toRead = objectTypesFromDictionary(typeIdentifiers: read)
|
|
1700
|
-
|
|
1701
|
-
store.requestAuthorization(toShare: share, read: toRead) { (success: Bool, error: Error?) in
|
|
1702
|
-
guard let err = error else {
|
|
1703
|
-
return resolve(success)
|
|
1704
|
-
}
|
|
1705
|
-
reject(GENERIC_ERROR, err.localizedDescription, err)
|
|
1706
|
-
}
|
|
1707
|
-
}
|
|
1708
|
-
|
|
1709
|
-
@available(iOS 13.0.0, *)
|
|
1710
|
-
func getWorkoutByID(
|
|
1711
|
-
store: HKHealthStore,
|
|
1712
|
-
workoutUUID: UUID
|
|
1713
|
-
) async -> HKWorkout? {
|
|
1714
|
-
let workoutPredicate = HKQuery.predicateForObject(with: workoutUUID)
|
|
1715
|
-
|
|
1716
|
-
let samples = try! await withCheckedThrowingContinuation {
|
|
1717
|
-
(continuation: CheckedContinuation<[HKSample], Error>) in
|
|
1718
|
-
let query = HKSampleQuery(
|
|
1719
|
-
sampleType: HKObjectType.workoutType(),
|
|
1720
|
-
predicate: workoutPredicate,
|
|
1721
|
-
limit: 1,
|
|
1722
|
-
sortDescriptors: nil
|
|
1723
|
-
) { (_, results, error) in
|
|
1724
|
-
|
|
1725
|
-
if let hasError = error {
|
|
1726
|
-
continuation.resume(throwing: hasError)
|
|
1727
|
-
return
|
|
1728
|
-
}
|
|
1729
|
-
|
|
1730
|
-
guard let samples = results else {
|
|
1731
|
-
fatalError("workout samples unexpectedly nil")
|
|
1732
|
-
}
|
|
1733
|
-
|
|
1734
|
-
continuation.resume(returning: samples)
|
|
1735
|
-
}
|
|
1736
|
-
store.execute(query)
|
|
1737
|
-
}
|
|
1738
|
-
|
|
1739
|
-
guard let workouts = samples as? [HKWorkout] else {
|
|
1740
|
-
return nil
|
|
1741
|
-
}
|
|
1742
|
-
|
|
1743
|
-
return workouts.first ?? nil
|
|
1744
|
-
}
|
|
1745
|
-
|
|
1746
|
-
@available(iOS 13.0.0, *)
|
|
1747
|
-
func _getWorkoutRoutes(
|
|
1748
|
-
store: HKHealthStore,
|
|
1749
|
-
workoutUUID: UUID
|
|
1750
|
-
) async -> [HKWorkoutRoute]? {
|
|
1751
|
-
guard let workout = await getWorkoutByID(store: store, workoutUUID: workoutUUID) else {
|
|
1752
|
-
return nil
|
|
1753
|
-
}
|
|
1754
|
-
|
|
1755
|
-
let workoutPredicate = HKQuery.predicateForObjects(from: workout)
|
|
1756
|
-
let samples = try! await withCheckedThrowingContinuation {
|
|
1757
|
-
(continuation: CheckedContinuation<[HKSample], Error>) in
|
|
1758
|
-
let query = HKAnchoredObjectQuery(
|
|
1759
|
-
type: HKSeriesType.workoutRoute(),
|
|
1760
|
-
predicate: workoutPredicate,
|
|
1761
|
-
anchor: nil,
|
|
1762
|
-
limit: HKObjectQueryNoLimit
|
|
1763
|
-
) {
|
|
1764
|
-
(_, samples, _, _, error) in
|
|
1765
|
-
|
|
1766
|
-
if let hasError = error {
|
|
1767
|
-
continuation.resume(throwing: hasError)
|
|
1768
|
-
return
|
|
1769
|
-
}
|
|
1770
|
-
|
|
1771
|
-
guard let samples = samples else {
|
|
1772
|
-
fatalError("workoutRoute samples unexpectedly nil")
|
|
1773
|
-
}
|
|
1774
|
-
|
|
1775
|
-
continuation.resume(returning: samples)
|
|
1776
|
-
}
|
|
1777
|
-
store.execute(query)
|
|
1778
|
-
}
|
|
1779
|
-
|
|
1780
|
-
guard let routes = samples as? [HKWorkoutRoute] else {
|
|
1781
|
-
return nil
|
|
1782
|
-
}
|
|
1783
|
-
|
|
1784
|
-
return routes
|
|
1785
|
-
}
|
|
1786
|
-
|
|
1787
|
-
@available(iOS 13.0.0, *)
|
|
1788
|
-
func getRouteLocations(
|
|
1789
|
-
store: HKHealthStore,
|
|
1790
|
-
route: HKWorkoutRoute
|
|
1791
|
-
) async -> [CLLocation] {
|
|
1792
|
-
let locations = try! await withCheckedThrowingContinuation {
|
|
1793
|
-
(continuation: CheckedContinuation<[CLLocation], Error>) in
|
|
1794
|
-
var allLocations: [CLLocation] = []
|
|
1795
|
-
|
|
1796
|
-
let query = HKWorkoutRouteQuery(route: route) {
|
|
1797
|
-
(_, locationsOrNil, done, errorOrNil) in
|
|
1798
|
-
|
|
1799
|
-
if let error = errorOrNil {
|
|
1800
|
-
continuation.resume(throwing: error)
|
|
1801
|
-
return
|
|
1802
|
-
}
|
|
1803
|
-
|
|
1804
|
-
guard let currentLocationBatch = locationsOrNil else {
|
|
1805
|
-
fatalError("routeLocations unexpectedly nil")
|
|
1806
|
-
}
|
|
1807
|
-
|
|
1808
|
-
allLocations.append(contentsOf: currentLocationBatch)
|
|
1809
|
-
|
|
1810
|
-
if done {
|
|
1811
|
-
continuation.resume(returning: allLocations)
|
|
1812
|
-
}
|
|
1813
|
-
}
|
|
1814
|
-
|
|
1815
|
-
store.execute(query)
|
|
1816
|
-
}
|
|
1817
|
-
|
|
1818
|
-
return locations
|
|
1819
|
-
}
|
|
1820
|
-
|
|
1821
|
-
@available(iOS 13.0.0, *)
|
|
1822
|
-
func getSerializedWorkoutLocations(
|
|
1823
|
-
store: HKHealthStore,
|
|
1824
|
-
workoutUUID: UUID
|
|
1825
|
-
) async -> [[String: Any]]? {
|
|
1826
|
-
let routes = await _getWorkoutRoutes(
|
|
1827
|
-
store: store,
|
|
1828
|
-
workoutUUID: workoutUUID
|
|
1829
|
-
)
|
|
1830
|
-
|
|
1831
|
-
var allRoutes: [[String: Any]] = []
|
|
1832
|
-
guard let _routes = routes else {
|
|
1833
|
-
return nil
|
|
1834
|
-
}
|
|
1835
|
-
for route in _routes {
|
|
1836
|
-
let routeMetadata =
|
|
1837
|
-
serializeMetadata(
|
|
1838
|
-
metadata: route.metadata
|
|
1839
|
-
) as! [String: Any]
|
|
1840
|
-
let routeCLLocations = await getRouteLocations(
|
|
1841
|
-
store: store,
|
|
1842
|
-
route: route
|
|
1843
|
-
)
|
|
1844
|
-
let routeLocations = routeCLLocations.enumerated().map {
|
|
1845
|
-
(i, loc) in
|
|
1846
|
-
serializeLocation(
|
|
1847
|
-
location: loc,
|
|
1848
|
-
previousLocation: i == 0 ? nil : routeCLLocations[i - 1]
|
|
1849
|
-
)
|
|
1850
|
-
}
|
|
1851
|
-
let routeInfos: [String: Any] = ["locations": routeLocations]
|
|
1852
|
-
|
|
1853
|
-
allRoutes.append(routeInfos.merging(routeMetadata) { (current, _) in current })
|
|
1854
|
-
}
|
|
1855
|
-
return allRoutes
|
|
1856
|
-
}
|
|
1857
|
-
|
|
1858
|
-
@available(iOS 17.0.0, *)
|
|
1859
|
-
func getWorkoutPlan(workout: HKWorkout) async -> [String: Any]? {
|
|
1860
|
-
#if canImport(WorkoutKit)
|
|
1861
|
-
do {
|
|
1862
|
-
let workoutPlan = try await workout.workoutPlan
|
|
1863
|
-
|
|
1864
|
-
var dict = [String: Any]()
|
|
1865
|
-
if (workoutPlan?.id) != nil {
|
|
1866
|
-
dict["id"] = workoutPlan?.id.uuidString
|
|
1867
|
-
|
|
1868
|
-
}
|
|
1869
|
-
if (workoutPlan?.workout.activity) != nil {
|
|
1870
|
-
dict["activityType"] = workoutPlan?.workout.activity.rawValue
|
|
1871
|
-
}
|
|
1872
|
-
|
|
1873
|
-
if dict.isEmpty {
|
|
1874
|
-
return nil
|
|
1875
|
-
}
|
|
1876
|
-
return dict
|
|
1877
|
-
} catch {
|
|
1878
|
-
return nil
|
|
1879
|
-
}
|
|
1880
|
-
#else
|
|
1881
|
-
return nil
|
|
1882
|
-
#endif
|
|
1883
|
-
}
|
|
1884
|
-
|
|
1885
|
-
@objc(getWorkoutPlanById:resolve:reject:)
|
|
1886
|
-
func getWorkoutPlanById(
|
|
1887
|
-
workoutUUID: String,
|
|
1888
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
1889
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
1890
|
-
) {
|
|
1891
|
-
if #available(iOS 17.0, *) {
|
|
1892
|
-
#if canImport(WorkoutKit)
|
|
1893
|
-
guard let store = _store else {
|
|
1894
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
1895
|
-
}
|
|
1896
|
-
|
|
1897
|
-
Task {
|
|
1898
|
-
if let uuid = UUID(uuidString: workoutUUID) {
|
|
1899
|
-
let workout = await self.getWorkoutByID(store: store, workoutUUID: uuid)
|
|
1900
|
-
if let workout {
|
|
1901
|
-
let workoutPlan = await self.getWorkoutPlan(workout: workout)
|
|
1902
|
-
|
|
1903
|
-
return resolve(workoutPlan)
|
|
1904
|
-
} else {
|
|
1905
|
-
return reject(GENERIC_ERROR, "No workout found", nil)
|
|
1906
|
-
}
|
|
1907
|
-
} else {
|
|
1908
|
-
return reject(GENERIC_ERROR, "Invalid UUID", nil)
|
|
1909
|
-
}
|
|
1910
|
-
}
|
|
1911
|
-
#else
|
|
1912
|
-
return resolve(nil)
|
|
1913
|
-
#endif
|
|
1914
|
-
} else {
|
|
1915
|
-
return resolve(nil)
|
|
1916
|
-
}
|
|
1917
|
-
}
|
|
1918
|
-
|
|
1919
|
-
func serializeLocation(location: CLLocation, previousLocation: CLLocation?) -> [String: Any] {
|
|
1920
|
-
var distance: CLLocationDistance?
|
|
1921
|
-
if let previousLocation = previousLocation {
|
|
1922
|
-
distance = location.distance(from: previousLocation)
|
|
1923
|
-
} else {
|
|
1924
|
-
distance = nil
|
|
1925
|
-
}
|
|
1926
|
-
return [
|
|
1927
|
-
"longitude": location.coordinate.longitude,
|
|
1928
|
-
"latitude": location.coordinate.latitude,
|
|
1929
|
-
"altitude": location.altitude,
|
|
1930
|
-
"speed": location.speed,
|
|
1931
|
-
"timestamp": location.timestamp.timeIntervalSince1970,
|
|
1932
|
-
"horizontalAccuracy": location.horizontalAccuracy,
|
|
1933
|
-
"speedAccuracy": location.speedAccuracy,
|
|
1934
|
-
"verticalAccuracy": location.verticalAccuracy,
|
|
1935
|
-
"distance": distance as Any
|
|
1936
|
-
]
|
|
1937
|
-
}
|
|
1938
|
-
|
|
1939
|
-
@available(iOS 13.0.0, *)
|
|
1940
|
-
@objc(getWorkoutRoutes:resolve:reject:)
|
|
1941
|
-
func getWorkoutRoutes(
|
|
1942
|
-
workoutUUID: String,
|
|
1943
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
1944
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
1945
|
-
) {
|
|
1946
|
-
|
|
1947
|
-
guard let store = _store else {
|
|
1948
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
1949
|
-
}
|
|
1950
|
-
|
|
1951
|
-
guard let _workoutUUID = UUID(uuidString: workoutUUID) else {
|
|
1952
|
-
return reject("INVALID_UUID_ERROR", "Invalid UUID received", nil)
|
|
1953
|
-
}
|
|
1954
|
-
|
|
1955
|
-
Task {
|
|
1956
|
-
do {
|
|
1957
|
-
let locations = await getSerializedWorkoutLocations(store: store, workoutUUID: _workoutUUID)
|
|
1958
|
-
resolve(locations)
|
|
1959
|
-
} catch {
|
|
1960
|
-
reject("WORKOUT_LOCATION_ERROR", "Failed to retrieve workout locations", nil)
|
|
1961
|
-
}
|
|
1962
|
-
}
|
|
1963
|
-
}
|
|
1964
|
-
|
|
1965
|
-
typealias HKAnchoredObjectQueryResult = (
|
|
1966
|
-
samples: [HKSample],
|
|
1967
|
-
deletedSamples: [HKDeletedObject]?,
|
|
1968
|
-
newAnchor: HKQueryAnchor?
|
|
1969
|
-
)
|
|
1970
|
-
|
|
1971
|
-
@available(iOS 13.0.0, *)
|
|
1972
|
-
func _queryHeartbeatSeriesSamplesWithAnchor(
|
|
1973
|
-
store: HKHealthStore,
|
|
1974
|
-
predicate: NSPredicate?,
|
|
1975
|
-
limit: Int,
|
|
1976
|
-
anchor: HKQueryAnchor?
|
|
1977
|
-
) async throws -> HKAnchoredObjectQueryResult {
|
|
1978
|
-
let queryResult = try await withCheckedThrowingContinuation {
|
|
1979
|
-
(continuation: CheckedContinuation<HKAnchoredObjectQueryResult, Error>) in
|
|
1980
|
-
let query = HKAnchoredObjectQuery(
|
|
1981
|
-
type: HKSeriesType.heartbeat(),
|
|
1982
|
-
predicate: predicate,
|
|
1983
|
-
anchor: anchor,
|
|
1984
|
-
limit: limit
|
|
1985
|
-
) {
|
|
1986
|
-
(
|
|
1987
|
-
_: HKAnchoredObjectQuery,
|
|
1988
|
-
s: [HKSample]?,
|
|
1989
|
-
deletedSamples: [HKDeletedObject]?,
|
|
1990
|
-
newAnchor: HKQueryAnchor?,
|
|
1991
|
-
error: Error?
|
|
1992
|
-
) in
|
|
1993
|
-
if let err = error {
|
|
1994
|
-
return continuation.resume(throwing: err)
|
|
1995
|
-
} else {
|
|
1996
|
-
guard let samples = s else {
|
|
1997
|
-
fatalError("heartbeatSeries unexpectedly nil")
|
|
1998
|
-
}
|
|
1999
|
-
|
|
2000
|
-
continuation.resume(
|
|
2001
|
-
returning: HKAnchoredObjectQueryResult(
|
|
2002
|
-
samples: samples,
|
|
2003
|
-
deletedSamples: deletedSamples,
|
|
2004
|
-
newAnchor: newAnchor)
|
|
2005
|
-
)
|
|
2006
|
-
}
|
|
2007
|
-
}
|
|
2008
|
-
|
|
2009
|
-
store.execute(query)
|
|
2010
|
-
}
|
|
2011
|
-
|
|
2012
|
-
return queryResult
|
|
2013
|
-
}
|
|
2014
|
-
|
|
2015
|
-
@available(iOS 13.0.0, *)
|
|
2016
|
-
func getHeartbeatSeriesHeartbeats(
|
|
2017
|
-
store: HKHealthStore,
|
|
2018
|
-
sample: HKHeartbeatSeriesSample
|
|
2019
|
-
) async throws -> [[String: Any]] {
|
|
2020
|
-
let beatTimes = try await withCheckedThrowingContinuation {
|
|
2021
|
-
(continuation: CheckedContinuation<[[String: Any]], Error>) in
|
|
2022
|
-
var allBeats: [[String: Any]] = []
|
|
2023
|
-
|
|
2024
|
-
let query = HKHeartbeatSeriesQuery(heartbeatSeries: sample) {
|
|
2025
|
-
(
|
|
2026
|
-
_: HKHeartbeatSeriesQuery,
|
|
2027
|
-
timeSinceSeriesStart: TimeInterval,
|
|
2028
|
-
precededByGap: Bool,
|
|
2029
|
-
done: Bool,
|
|
2030
|
-
error: Error?
|
|
2031
|
-
) in
|
|
2032
|
-
if let err = error {
|
|
2033
|
-
return continuation.resume(throwing: err)
|
|
2034
|
-
} else {
|
|
2035
|
-
let timeDict: [String: Any] = [
|
|
2036
|
-
"timeSinceSeriesStart": timeSinceSeriesStart,
|
|
2037
|
-
"precededByGap": precededByGap
|
|
2038
|
-
]
|
|
2039
|
-
|
|
2040
|
-
allBeats.append(timeDict)
|
|
2041
|
-
|
|
2042
|
-
if done {
|
|
2043
|
-
continuation.resume(returning: allBeats)
|
|
2044
|
-
}
|
|
2045
|
-
}
|
|
2046
|
-
}
|
|
2047
|
-
|
|
2048
|
-
store.execute(query)
|
|
2049
|
-
}
|
|
2050
|
-
|
|
2051
|
-
return beatTimes
|
|
2052
|
-
}
|
|
2053
|
-
|
|
2054
|
-
@available(iOS 13.0.0, *)
|
|
2055
|
-
func getSerializedHeartbeatSeriesSample(
|
|
2056
|
-
store: HKHealthStore,
|
|
2057
|
-
sample: HKHeartbeatSeriesSample
|
|
2058
|
-
) async throws -> [String: Any] {
|
|
2059
|
-
let sampleMetadata = serializeMetadata(metadata: sample.metadata) as! [String: Any]
|
|
2060
|
-
let sampleHeartbeats = try await getHeartbeatSeriesHeartbeats(
|
|
2061
|
-
store: store,
|
|
2062
|
-
sample: sample
|
|
2063
|
-
)
|
|
2064
|
-
|
|
2065
|
-
return [
|
|
2066
|
-
"uuid": sample.uuid.uuidString,
|
|
2067
|
-
"device": serializeDevice(_device: sample.device) as Any,
|
|
2068
|
-
"startDate": self._dateFormatter.string(from: sample.startDate),
|
|
2069
|
-
"endDate": self._dateFormatter.string(from: sample.endDate),
|
|
2070
|
-
"heartbeats": sampleHeartbeats as Any,
|
|
2071
|
-
"metadata": serializeMetadata(metadata: sample.metadata),
|
|
2072
|
-
"sourceRevision": serializeSourceRevision(_sourceRevision: sample.sourceRevision) as Any
|
|
2073
|
-
]
|
|
2074
|
-
}
|
|
2075
|
-
|
|
2076
|
-
@available(iOS 13.0.0, *)
|
|
2077
|
-
@objc(queryHeartbeatSeriesSamplesWithAnchor:to:limit:anchor:resolve:reject:)
|
|
2078
|
-
func queryHeartbeatSeriesSamplesWithAnchor(
|
|
2079
|
-
from: Date,
|
|
2080
|
-
to: Date,
|
|
2081
|
-
limit: Int,
|
|
2082
|
-
anchor: String,
|
|
2083
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
2084
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
2085
|
-
) {
|
|
2086
|
-
guard let store = _store else {
|
|
2087
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
2088
|
-
}
|
|
2089
|
-
|
|
2090
|
-
Task {
|
|
2091
|
-
do {
|
|
2092
|
-
let from = dateOrNilIfZero(date: from)
|
|
2093
|
-
let to = dateOrNilIfZero(date: to)
|
|
2094
|
-
|
|
2095
|
-
let predicate = createPredicate(from: from, to: to)
|
|
2096
|
-
|
|
2097
|
-
let limit = limitOrNilIfZero(limit: limit)
|
|
2098
|
-
|
|
2099
|
-
let actualAnchor = deserializeHKQueryAnchor(anchor: anchor)
|
|
2100
|
-
|
|
2101
|
-
let queryResult = try await _queryHeartbeatSeriesSamplesWithAnchor(
|
|
2102
|
-
store: store,
|
|
2103
|
-
predicate: predicate,
|
|
2104
|
-
limit: limit,
|
|
2105
|
-
anchor: actualAnchor
|
|
2106
|
-
)
|
|
2107
|
-
|
|
2108
|
-
var allHeartbeatSamples: [[String: Any]] = []
|
|
2109
|
-
for sample in queryResult.samples as! [HKHeartbeatSeriesSample] {
|
|
2110
|
-
allHeartbeatSamples.append(
|
|
2111
|
-
try await getSerializedHeartbeatSeriesSample(
|
|
2112
|
-
store: store,
|
|
2113
|
-
sample: sample
|
|
2114
|
-
)
|
|
2115
|
-
)
|
|
2116
|
-
}
|
|
2117
|
-
|
|
2118
|
-
resolve([
|
|
2119
|
-
"samples": allHeartbeatSamples as Any,
|
|
2120
|
-
"deletedSamples": queryResult.deletedSamples?.map({ sample in
|
|
2121
|
-
return serializeDeletedSample(sample: sample)
|
|
2122
|
-
}) as Any,
|
|
2123
|
-
"newAnchor": serializeAnchor(anchor: queryResult.newAnchor) as Any
|
|
2124
|
-
])
|
|
2125
|
-
} catch {
|
|
2126
|
-
reject(GENERIC_ERROR, error.localizedDescription, error)
|
|
2127
|
-
}
|
|
2128
|
-
}
|
|
2129
|
-
}
|
|
2130
|
-
|
|
2131
|
-
@available(iOS 13.0.0, *)
|
|
2132
|
-
func _queryHeartbeatSeriesSamples(
|
|
2133
|
-
store: HKHealthStore,
|
|
2134
|
-
predicate: NSPredicate?,
|
|
2135
|
-
limit: Int,
|
|
2136
|
-
ascending: Bool
|
|
2137
|
-
) async throws -> [HKSample] {
|
|
2138
|
-
let samples = try await withCheckedThrowingContinuation {
|
|
2139
|
-
(continuation: CheckedContinuation<[HKSample], Error>) in
|
|
2140
|
-
|
|
2141
|
-
let query = HKSampleQuery(
|
|
2142
|
-
sampleType: HKSeriesType.heartbeat(),
|
|
2143
|
-
predicate: predicate,
|
|
2144
|
-
limit: limit,
|
|
2145
|
-
sortDescriptors: [
|
|
2146
|
-
NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: ascending)
|
|
2147
|
-
]
|
|
2148
|
-
) { (_: HKSampleQuery, sample: [HKSample]?, error: Error?) in
|
|
2149
|
-
if let err = error {
|
|
2150
|
-
continuation.resume(throwing: err)
|
|
2151
|
-
} else {
|
|
2152
|
-
guard let actualSamples = sample else {
|
|
2153
|
-
fatalError("heartbeatSeries samples unexpectedly nil")
|
|
2154
|
-
}
|
|
2155
|
-
continuation.resume(returning: actualSamples)
|
|
2156
|
-
}
|
|
2157
|
-
}
|
|
2158
|
-
|
|
2159
|
-
store.execute(query)
|
|
2160
|
-
}
|
|
2161
|
-
|
|
2162
|
-
return samples
|
|
2163
|
-
}
|
|
2164
|
-
|
|
2165
|
-
@available(iOS 13.0.0, *)
|
|
2166
|
-
@objc(queryHeartbeatSeriesSamples:to:limit:ascending:resolve:reject:)
|
|
2167
|
-
func queryHeartbeatSeriesSamples(
|
|
2168
|
-
from: Date,
|
|
2169
|
-
to: Date,
|
|
2170
|
-
limit: Int,
|
|
2171
|
-
ascending: Bool,
|
|
2172
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
2173
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
2174
|
-
) {
|
|
2175
|
-
guard let store = _store else {
|
|
2176
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
2177
|
-
}
|
|
2178
|
-
|
|
2179
|
-
Task {
|
|
2180
|
-
do {
|
|
2181
|
-
let from = dateOrNilIfZero(date: from)
|
|
2182
|
-
let to = dateOrNilIfZero(date: to)
|
|
2183
|
-
|
|
2184
|
-
let predicate = createPredicate(
|
|
2185
|
-
from: from,
|
|
2186
|
-
to: to
|
|
2187
|
-
)
|
|
2188
|
-
|
|
2189
|
-
let limit = limitOrNilIfZero(
|
|
2190
|
-
limit: limit
|
|
2191
|
-
)
|
|
2192
|
-
|
|
2193
|
-
let samples = try await _queryHeartbeatSeriesSamples(
|
|
2194
|
-
store: store,
|
|
2195
|
-
predicate: predicate,
|
|
2196
|
-
limit: limit,
|
|
2197
|
-
ascending: ascending
|
|
2198
|
-
)
|
|
2199
|
-
|
|
2200
|
-
var allHeartbeatSamples: [[String: Any]] = []
|
|
2201
|
-
for sample in samples as! [HKHeartbeatSeriesSample] {
|
|
2202
|
-
allHeartbeatSamples.append(
|
|
2203
|
-
try await getSerializedHeartbeatSeriesSample(
|
|
2204
|
-
store: store,
|
|
2205
|
-
sample: sample
|
|
2206
|
-
)
|
|
2207
|
-
)
|
|
2208
|
-
}
|
|
2209
|
-
|
|
2210
|
-
resolve(allHeartbeatSamples as Any)
|
|
2211
|
-
} catch {
|
|
2212
|
-
reject(GENERIC_ERROR, error.localizedDescription, error)
|
|
2213
|
-
}
|
|
2214
|
-
}
|
|
2215
|
-
}
|
|
2216
|
-
|
|
2217
|
-
@objc(queryStateOfMindSamples:to:limit:ascending:resolve:reject:)
|
|
2218
|
-
func queryStateOfMindSamples(
|
|
2219
|
-
from: Date,
|
|
2220
|
-
to: Date,
|
|
2221
|
-
limit: Int,
|
|
2222
|
-
ascending: Bool,
|
|
2223
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
2224
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
2225
|
-
) {
|
|
2226
|
-
#if compiler(>=6)
|
|
2227
|
-
if #available(iOS 18.0, *) {
|
|
2228
|
-
guard let store = _store else {
|
|
2229
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
2230
|
-
}
|
|
2231
|
-
|
|
2232
|
-
Task {
|
|
2233
|
-
let from = dateOrNilIfZero(date: from)
|
|
2234
|
-
let to = dateOrNilIfZero(date: to)
|
|
2235
|
-
|
|
2236
|
-
let predicate = createPredicate(
|
|
2237
|
-
from: from,
|
|
2238
|
-
to: to
|
|
2239
|
-
)
|
|
2240
|
-
|
|
2241
|
-
let limit = limitOrNilIfZero(
|
|
2242
|
-
limit: limit
|
|
2243
|
-
)
|
|
2244
|
-
|
|
2245
|
-
let type = HKStateOfMindType.stateOfMindType()
|
|
2246
|
-
|
|
2247
|
-
let query = HKSampleQuery(
|
|
2248
|
-
sampleType: type,
|
|
2249
|
-
predicate: predicate,
|
|
2250
|
-
limit: limit,
|
|
2251
|
-
sortDescriptors: [
|
|
2252
|
-
NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: ascending)
|
|
2253
|
-
]
|
|
2254
|
-
) { (_, samples, error) in
|
|
2255
|
-
if let error = error {
|
|
2256
|
-
reject(GENERIC_ERROR, error.localizedDescription, error)
|
|
2257
|
-
return
|
|
2258
|
-
}
|
|
2259
|
-
|
|
2260
|
-
guard let samples = samples as? [HKStateOfMind] else {
|
|
2261
|
-
resolve([])
|
|
2262
|
-
return
|
|
2263
|
-
}
|
|
2264
|
-
|
|
2265
|
-
let serializedSamples = samples.map { sample in
|
|
2266
|
-
var associations: [Int] = []
|
|
2267
|
-
if #available(iOS 18.0, *) {
|
|
2268
|
-
associations = sample.associations.map({ association in
|
|
2269
|
-
return association.rawValue
|
|
2270
|
-
})
|
|
2271
|
-
}
|
|
2272
|
-
|
|
2273
|
-
var labels: [Int] = []
|
|
2274
|
-
if #available(iOS 18.0, *) {
|
|
2275
|
-
labels = sample.labels.map({ label in
|
|
2276
|
-
return label.rawValue
|
|
2277
|
-
})
|
|
2278
|
-
}
|
|
2279
|
-
|
|
2280
|
-
return [
|
|
2281
|
-
"uuid": sample.uuid.uuidString,
|
|
2282
|
-
"device": serializeDevice(_device: sample.device) as Any,
|
|
2283
|
-
"startDate": self._dateFormatter.string(from: sample.startDate),
|
|
2284
|
-
"endDate": self._dateFormatter.string(from: sample.endDate),
|
|
2285
|
-
"valence": sample.valence,
|
|
2286
|
-
"kind": sample.kind.rawValue,
|
|
2287
|
-
"valenceClassification": sample.valenceClassification.rawValue,
|
|
2288
|
-
"associations": associations,
|
|
2289
|
-
"labels": labels,
|
|
2290
|
-
"metadata": serializeMetadata(metadata: sample.metadata),
|
|
2291
|
-
"sourceRevision": serializeSourceRevision(_sourceRevision: sample.sourceRevision)
|
|
2292
|
-
as Any
|
|
2293
|
-
]
|
|
2294
|
-
}
|
|
2295
|
-
|
|
2296
|
-
resolve(serializedSamples)
|
|
2297
|
-
}
|
|
2298
|
-
|
|
2299
|
-
store.execute(query)
|
|
2300
|
-
}
|
|
2301
|
-
} else {
|
|
2302
|
-
reject("STATE_OF_MIND_ERROR", "State of Mind features require iOS 18.0 or later", nil)
|
|
2303
|
-
}
|
|
2304
|
-
#else
|
|
2305
|
-
reject(
|
|
2306
|
-
"STATE_OF_MIND_ERROR", "State of Mind features require Xcode 16 or later to compile", nil)
|
|
2307
|
-
#endif
|
|
2308
|
-
}
|
|
2309
|
-
|
|
2310
|
-
@available(iOS 17.0.0, *)
|
|
2311
|
-
@objc(startWatchAppWithWorkoutConfiguration:resolve:reject:)
|
|
2312
|
-
func startWatchAppWithWorkoutConfiguration(
|
|
2313
|
-
_ workoutConfiguration: NSDictionary,
|
|
2314
|
-
resolve: @escaping RCTPromiseResolveBlock,
|
|
2315
|
-
reject: @escaping RCTPromiseRejectBlock
|
|
2316
|
-
) {
|
|
2317
|
-
guard let store = _store else {
|
|
2318
|
-
return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil)
|
|
2319
|
-
}
|
|
2320
|
-
|
|
2321
|
-
let configuration = parseWorkoutConfiguration(workoutConfiguration)
|
|
2322
|
-
|
|
2323
|
-
store.startWatchApp(with: configuration) { success, error in
|
|
2324
|
-
if let error {
|
|
2325
|
-
reject(GENERIC_ERROR, error.localizedDescription, error)
|
|
2326
|
-
return
|
|
2327
|
-
}
|
|
2328
|
-
|
|
2329
|
-
resolve(success)
|
|
2330
|
-
}
|
|
2331
|
-
}
|
|
2332
|
-
}
|
|
2333
|
-
|