@kingstinct/react-native-healthkit 13.0.0 → 13.0.2
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 +2 -0
- package/ios/CoreModule.swift +1 -1
- package/ios/CorrelationTypeModule.swift +5 -2
- package/ios/ExceptionCatcher.h +17 -0
- package/ios/Helpers.swift +55 -33
- package/ios/QuantityTypeModule.swift +65 -74
- package/ios/WorkoutsModule.swift +1 -1
- package/nitrogen/generated/ios/ReactNativeHealthkit-Swift-Cxx-Bridge.cpp +1 -0
- package/nitrogen/generated/ios/swift/AuthDataTypes.swift +1 -0
- package/nitrogen/generated/ios/swift/CategorySample.swift +1 -0
- package/nitrogen/generated/ios/swift/CategorySampleForSaving.swift +1 -0
- package/nitrogen/generated/ios/swift/CategorySamplesWithAnchorResponse.swift +1 -0
- package/nitrogen/generated/ios/swift/CorrelationSample.swift +1 -0
- package/nitrogen/generated/ios/swift/DateFilter.swift +1 -0
- package/nitrogen/generated/ios/swift/DeletedSample.swift +1 -0
- package/nitrogen/generated/ios/swift/Device.swift +1 -0
- package/nitrogen/generated/ios/swift/ECGQueryOptionsWithAnchor.swift +1 -0
- package/nitrogen/generated/ios/swift/ECGQueryOptionsWithSortOrder.swift +1 -0
- package/nitrogen/generated/ios/swift/ElectrocardiogramSample.swift +1 -0
- package/nitrogen/generated/ios/swift/ElectrocardiogramSamplesWithAnchorResponse.swift +1 -0
- package/nitrogen/generated/ios/swift/ElectrocardiogramVoltage.swift +1 -0
- package/nitrogen/generated/ios/swift/FilterForSamples.swift +1 -0
- package/nitrogen/generated/ios/swift/FilterForSamplesBase.swift +1 -0
- package/nitrogen/generated/ios/swift/FilterForWorkouts.swift +1 -0
- package/nitrogen/generated/ios/swift/FilterForWorkoutsBase.swift +1 -0
- package/nitrogen/generated/ios/swift/Func_void_AuthorizationRequestStatus.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_BiologicalSex.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_BloodType.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_CategorySamplesWithAnchorResponse.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_ElectrocardiogramSamplesWithAnchorResponse.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_FitzpatrickSkinType.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_HeartbeatSeriesSamplesWithAnchorResponse.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_MedicationDoseEventsWithAnchorResponse.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_OnChangeCallbackArgs.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_QuantitySamplesWithAnchorResponse.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_QueryCorrelationSamplesWithAnchorResponse.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_QueryStatisticsResponse.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_QueryWorkoutSamplesWithAnchorResponse.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_StateOfMindSamplesWithAnchorResponse.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_WheelchairUse.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_bool.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_double.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_std__optional_CategorySample_.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_std__optional_CorrelationSample_.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_std__optional_QuantitySample_.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_std__optional_QueryStatisticsResponse_.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_std__optional_StateOfMindSample_.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_std__optional_WorkoutPlan_.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_std__optional_std__chrono__system_clock__time_point_.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_std__shared_ptr_HybridWorkoutProxySpec_.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_std__unordered_map_std__string__QueryStatisticsResponse_.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_std__unordered_map_std__string__bool_.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_std__vector_CategorySample_.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_std__vector_CorrelationSample_.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_std__vector_ElectrocardiogramSample_.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_std__vector_HeartbeatSeriesSample_.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_std__vector_IdentifierWithUnit_.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_std__vector_MedicationDoseEvent_.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_std__vector_QuantitySample_.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_std__vector_QueryStatisticsResponseFromSingleSource_.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_std__vector_QueryStatisticsResponse_.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_std__vector_StateOfMindSample_.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_std__vector_UserAnnotatedMedication_.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_std__vector_WorkoutRoute_.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_std__vector_std__shared_ptr_HybridSourceProxySpec__.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_std__vector_std__shared_ptr_HybridWorkoutProxySpec__.swift +1 -1
- package/nitrogen/generated/ios/swift/Heartbeat.swift +1 -0
- package/nitrogen/generated/ios/swift/HeartbeatSeriesSample.swift +1 -0
- package/nitrogen/generated/ios/swift/HeartbeatSeriesSamplesWithAnchorResponse.swift +1 -0
- package/nitrogen/generated/ios/swift/HybridCategoryTypeModuleSpec.swift +0 -1
- package/nitrogen/generated/ios/swift/HybridCategoryTypeModuleSpec_cxx.swift +0 -1
- package/nitrogen/generated/ios/swift/HybridCharacteristicTypeModuleSpec.swift +0 -1
- package/nitrogen/generated/ios/swift/HybridCharacteristicTypeModuleSpec_cxx.swift +0 -1
- package/nitrogen/generated/ios/swift/HybridCoreModuleSpec.swift +0 -1
- package/nitrogen/generated/ios/swift/HybridCoreModuleSpec_cxx.swift +0 -1
- package/nitrogen/generated/ios/swift/HybridCorrelationTypeModuleSpec.swift +0 -1
- package/nitrogen/generated/ios/swift/HybridCorrelationTypeModuleSpec_cxx.swift +0 -1
- package/nitrogen/generated/ios/swift/HybridElectrocardiogramModuleSpec.swift +0 -1
- package/nitrogen/generated/ios/swift/HybridElectrocardiogramModuleSpec_cxx.swift +0 -1
- package/nitrogen/generated/ios/swift/HybridHeartbeatSeriesModuleSpec.swift +0 -1
- package/nitrogen/generated/ios/swift/HybridHeartbeatSeriesModuleSpec_cxx.swift +0 -1
- package/nitrogen/generated/ios/swift/HybridMedicationModuleSpec.swift +0 -1
- package/nitrogen/generated/ios/swift/HybridMedicationModuleSpec_cxx.swift +0 -1
- package/nitrogen/generated/ios/swift/HybridQuantityTypeModuleSpec.swift +0 -1
- package/nitrogen/generated/ios/swift/HybridQuantityTypeModuleSpec_cxx.swift +0 -1
- package/nitrogen/generated/ios/swift/HybridStateOfMindModuleSpec.swift +0 -1
- package/nitrogen/generated/ios/swift/HybridStateOfMindModuleSpec_cxx.swift +0 -1
- package/nitrogen/generated/ios/swift/HybridWorkoutProxySpec.swift +0 -1
- package/nitrogen/generated/ios/swift/HybridWorkoutProxySpec_cxx.swift +0 -1
- package/nitrogen/generated/ios/swift/HybridWorkoutsModuleSpec.swift +0 -1
- package/nitrogen/generated/ios/swift/HybridWorkoutsModuleSpec_cxx.swift +0 -1
- package/nitrogen/generated/ios/swift/IdentifierWithUnit.swift +1 -0
- package/nitrogen/generated/ios/swift/IntervalComponents.swift +1 -0
- package/nitrogen/generated/ios/swift/LocationForSaving.swift +1 -0
- package/nitrogen/generated/ios/swift/MedicationConcept.swift +1 -0
- package/nitrogen/generated/ios/swift/MedicationDoseEvent.swift +1 -0
- package/nitrogen/generated/ios/swift/MedicationDoseEventsWithAnchorResponse.swift +1 -0
- package/nitrogen/generated/ios/swift/OnChangeCallbackArgs.swift +1 -0
- package/nitrogen/generated/ios/swift/PredicateWithMetadataKey.swift +1 -0
- package/nitrogen/generated/ios/swift/Quantity.swift +1 -0
- package/nitrogen/generated/ios/swift/QuantityDateInterval.swift +1 -0
- package/nitrogen/generated/ios/swift/QuantitySample.swift +1 -0
- package/nitrogen/generated/ios/swift/QuantitySampleForSaving.swift +1 -0
- package/nitrogen/generated/ios/swift/QuantitySamplesWithAnchorResponse.swift +1 -0
- package/nitrogen/generated/ios/swift/QueryCorrelationSamplesWithAnchorResponse.swift +1 -0
- package/nitrogen/generated/ios/swift/QueryOptionsWithAnchor.swift +1 -0
- package/nitrogen/generated/ios/swift/QueryOptionsWithAnchorAndUnit.swift +1 -0
- package/nitrogen/generated/ios/swift/QueryOptionsWithSortOrder.swift +1 -0
- package/nitrogen/generated/ios/swift/QueryOptionsWithSortOrderAndUnit.swift +1 -0
- package/nitrogen/generated/ios/swift/QueryStatisticsResponse.swift +1 -0
- package/nitrogen/generated/ios/swift/QueryStatisticsResponseFromSingleSource.swift +1 -0
- package/nitrogen/generated/ios/swift/QueryWorkoutSamplesWithAnchorResponse.swift +1 -0
- package/nitrogen/generated/ios/swift/RelatedCoding.swift +1 -0
- package/nitrogen/generated/ios/swift/SampleType.swift +1 -0
- package/nitrogen/generated/ios/swift/Source.swift +1 -0
- package/nitrogen/generated/ios/swift/SourceRevision.swift +1 -0
- package/nitrogen/generated/ios/swift/StateOfMindSample.swift +1 -0
- package/nitrogen/generated/ios/swift/StateOfMindSamplesWithAnchorResponse.swift +1 -0
- package/nitrogen/generated/ios/swift/StatisticsQueryOptions.swift +1 -0
- package/nitrogen/generated/ios/swift/UserAnnotatedMedication.swift +1 -0
- package/nitrogen/generated/ios/swift/WorkoutActivity.swift +1 -0
- package/nitrogen/generated/ios/swift/WorkoutConfiguration.swift +1 -0
- package/nitrogen/generated/ios/swift/WorkoutDurationPredicate.swift +1 -0
- package/nitrogen/generated/ios/swift/WorkoutEvent.swift +1 -0
- package/nitrogen/generated/ios/swift/WorkoutPlan.swift +1 -0
- package/nitrogen/generated/ios/swift/WorkoutQueryOptions.swift +1 -0
- package/nitrogen/generated/ios/swift/WorkoutQueryOptionsWithAnchor.swift +1 -0
- package/nitrogen/generated/ios/swift/WorkoutRoute.swift +1 -0
- package/nitrogen/generated/ios/swift/WorkoutRouteLocation.swift +1 -0
- package/nitrogen/generated/ios/swift/WorkoutSample.swift +1 -0
- package/nitrogen/generated/ios/swift/WorkoutTotals.swift +1 -0
- package/package.json +4 -4
|
@@ -22,6 +22,8 @@ Pod::Spec.new do |s|
|
|
|
22
22
|
"cpp/**/*.{hpp,cpp}",
|
|
23
23
|
]
|
|
24
24
|
|
|
25
|
+
s.public_header_files = "ios/**/*.h"
|
|
26
|
+
|
|
25
27
|
s.pod_target_xcconfig = {
|
|
26
28
|
# C++ compiler flags, mainly for folly.
|
|
27
29
|
"GCC_PREPROCESSOR_DEFINITIONS" => "$(inherited) FOLLY_NO_CONFIG FOLLY_CFG_NO_COROUTINES"
|
package/ios/CoreModule.swift
CHANGED
|
@@ -19,7 +19,7 @@ private var quantityTypeUnitCache = [HKQuantityType: HKUnit]()
|
|
|
19
19
|
|
|
20
20
|
func getUnitToUse(unitOverride: String?, quantityType: HKQuantityType) async throws -> HKUnit {
|
|
21
21
|
if let unitOverride = unitOverride {
|
|
22
|
-
let unit =
|
|
22
|
+
let unit = try parseUnitStringSafe(unitOverride)
|
|
23
23
|
|
|
24
24
|
if !quantityType.is(compatibleWith: unit) {
|
|
25
25
|
throw runtimeErrorWithPrefix(
|
|
@@ -137,8 +137,11 @@ class CorrelationTypeModule: HybridCorrelationTypeModuleSpec {
|
|
|
137
137
|
continue
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
-
let unit =
|
|
141
|
-
let quantity = HKQuantity(
|
|
140
|
+
let unit = try parseUnitStringSafe(quantitySample.unit)
|
|
141
|
+
let quantity = HKQuantity(
|
|
142
|
+
unit: unit,
|
|
143
|
+
doubleValue: quantitySample.quantity
|
|
144
|
+
)
|
|
142
145
|
let hkQuantitySample = HKQuantitySample(
|
|
143
146
|
type: quantityType,
|
|
144
147
|
quantity: quantity,
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#import <Foundation/Foundation.h>
|
|
2
|
+
#import <HealthKit/HealthKit.h>
|
|
3
|
+
|
|
4
|
+
NS_INLINE HKUnit * _Nullable HKUnitFromStringCatchingExceptions(NSString * _Nonnull unitString, NSError * _Nullable * _Nullable outError) {
|
|
5
|
+
if (outError) { *outError = nil; }
|
|
6
|
+
@try {
|
|
7
|
+
HKUnit *unit = [HKUnit unitFromString:unitString];
|
|
8
|
+
return unit;
|
|
9
|
+
}
|
|
10
|
+
@catch (NSException *exception) {
|
|
11
|
+
if (outError) {
|
|
12
|
+
NSDictionary *userInfo = exception.userInfo ?: @{};
|
|
13
|
+
*outError = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
|
|
14
|
+
}
|
|
15
|
+
return nil;
|
|
16
|
+
}
|
|
17
|
+
}
|
package/ios/Helpers.swift
CHANGED
|
@@ -9,6 +9,17 @@ import Foundation
|
|
|
9
9
|
import HealthKit
|
|
10
10
|
import NitroModules
|
|
11
11
|
|
|
12
|
+
func parseUnitStringSafe(_ unitString: String) throws -> HKUnit {
|
|
13
|
+
var err: NSError?
|
|
14
|
+
let unitOut = HKUnitFromStringCatchingExceptions(unitString, &err)
|
|
15
|
+
|
|
16
|
+
if let hkUnit = unitOut {
|
|
17
|
+
return hkUnit
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
throw runtimeErrorWithPrefix("Supplied invalid '\(unitString)' as HKUnit")
|
|
21
|
+
}
|
|
22
|
+
|
|
12
23
|
func getQueryLimit(_ limit: Double) -> Int {
|
|
13
24
|
if limit == .infinity || limit <= 0 || limit == .nan || limit == .signalingNaN {
|
|
14
25
|
return HKObjectQueryNoLimit
|
|
@@ -355,39 +366,6 @@ func objectTypeFrom(objectTypeIdentifier: ObjectTypeIdentifier) throws -> HKObje
|
|
|
355
366
|
"Failed initializing unrecognized objectType identifier " + typeIdentifier)
|
|
356
367
|
}
|
|
357
368
|
|
|
358
|
-
func hkStatisticsOptionsFromOptions(_ options: NSArray) -> HKStatisticsOptions {
|
|
359
|
-
var opts = HKStatisticsOptions()
|
|
360
|
-
|
|
361
|
-
for o in options {
|
|
362
|
-
guard let str = o as? String else { continue }
|
|
363
|
-
|
|
364
|
-
switch str {
|
|
365
|
-
case "cumulativeSum":
|
|
366
|
-
opts.insert(.cumulativeSum)
|
|
367
|
-
case "discreteAverage":
|
|
368
|
-
opts.insert(.discreteAverage)
|
|
369
|
-
case "discreteMax":
|
|
370
|
-
opts.insert(.discreteMax)
|
|
371
|
-
case "discreteMin":
|
|
372
|
-
opts.insert(.discreteMin)
|
|
373
|
-
case "duration":
|
|
374
|
-
if #available(iOS 13, *) {
|
|
375
|
-
opts.insert(.duration)
|
|
376
|
-
}
|
|
377
|
-
case "mostRecent":
|
|
378
|
-
if #available(iOS 13, *) {
|
|
379
|
-
opts.insert(.mostRecent)
|
|
380
|
-
}
|
|
381
|
-
case "separateBySource":
|
|
382
|
-
opts.insert(.separateBySource)
|
|
383
|
-
default:
|
|
384
|
-
continue
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
return opts
|
|
389
|
-
}
|
|
390
|
-
|
|
391
369
|
func componentsFromInterval(_ interval: NSDictionary) -> DateComponents {
|
|
392
370
|
let componentKeys: [String: WritableKeyPath<DateComponents, Int?>] = [
|
|
393
371
|
"minute": \.minute,
|
|
@@ -443,3 +421,47 @@ func runtimeErrorWithPrefix(_ withMessage: String) -> Error {
|
|
|
443
421
|
func warnWithPrefix(_ withMessage: String) {
|
|
444
422
|
print("[react-native-healthkit] \(withMessage)")
|
|
445
423
|
}
|
|
424
|
+
|
|
425
|
+
func buildStatisticsOptions(statistics: [StatisticsOptions], quantityType: HKQuantityType) -> HKStatisticsOptions {
|
|
426
|
+
|
|
427
|
+
// Build statistics options
|
|
428
|
+
var opts = HKStatisticsOptions()
|
|
429
|
+
opts.insert(.separateBySource)
|
|
430
|
+
for statistic in statistics {
|
|
431
|
+
if statistic == .cumulativesum {
|
|
432
|
+
if quantityType.aggregationStyle == .cumulative {
|
|
433
|
+
opts.insert(HKStatisticsOptions.cumulativeSum)
|
|
434
|
+
} else {
|
|
435
|
+
warnWithPrefix("buildStatisticsOptions: cumulativesum statistic requested for discrete quantity type \(quantityType.identifier)")
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
} else if statistic == .discreteaverage {
|
|
439
|
+
if quantityType.aggregationStyle != .cumulative {
|
|
440
|
+
opts.insert(HKStatisticsOptions.discreteAverage)
|
|
441
|
+
} else {
|
|
442
|
+
warnWithPrefix("buildStatisticsOptions: discreteaverage statistic requested for cumulative quantity type \(quantityType.identifier)")
|
|
443
|
+
}
|
|
444
|
+
} else if statistic == .discretemax {
|
|
445
|
+
if quantityType.aggregationStyle != .cumulative {
|
|
446
|
+
opts.insert(HKStatisticsOptions.discreteMax)
|
|
447
|
+
} else {
|
|
448
|
+
warnWithPrefix("buildStatisticsOptions: discretemax statistic requested for cumulative quantity type \(quantityType.identifier)")
|
|
449
|
+
}
|
|
450
|
+
} else if statistic == .discretemin {
|
|
451
|
+
if quantityType.aggregationStyle != .cumulative {
|
|
452
|
+
opts.insert(HKStatisticsOptions.discreteMin)
|
|
453
|
+
} else {
|
|
454
|
+
warnWithPrefix("buildStatisticsOptions: discretemin statistic requested for cumulative quantity type \(quantityType.identifier)")
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
if #available(iOS 13, *) {
|
|
458
|
+
if statistic == .duration {
|
|
459
|
+
opts.insert(HKStatisticsOptions.duration)
|
|
460
|
+
}
|
|
461
|
+
if statistic == .mostrecent {
|
|
462
|
+
opts.insert(HKStatisticsOptions.mostRecent)
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
return opts
|
|
467
|
+
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import HealthKit
|
|
2
2
|
import NitroModules
|
|
3
3
|
|
|
4
|
-
func emptyStatisticsResponse(from: Date
|
|
4
|
+
func emptyStatisticsResponse(from: Date?, to: Date?) -> QueryStatisticsResponse {
|
|
5
5
|
var response = QueryStatisticsResponse()
|
|
6
6
|
|
|
7
7
|
response.startDate = from
|
|
8
8
|
response.endDate = to
|
|
9
|
+
response.sources = []
|
|
9
10
|
|
|
10
11
|
return response
|
|
11
12
|
}
|
|
@@ -14,18 +15,20 @@ func queryStatisticsForQuantityInternal(
|
|
|
14
15
|
quantityType: HKQuantityType,
|
|
15
16
|
statistics: [StatisticsOptions],
|
|
16
17
|
options: StatisticsQueryOptions?
|
|
17
|
-
) async throws -> HKStatistics {
|
|
18
|
+
) async throws -> HKStatistics? {
|
|
18
19
|
let predicate = createPredicateForSamples(options?.filter)
|
|
19
20
|
|
|
20
21
|
return try await withCheckedThrowingContinuation { continuation in
|
|
21
22
|
let query = HKStatisticsQuery.init(
|
|
22
23
|
quantityType: quantityType,
|
|
23
24
|
quantitySamplePredicate: predicate,
|
|
24
|
-
options: buildStatisticsOptions(statistics: statistics)
|
|
25
|
+
options: buildStatisticsOptions(statistics: statistics, quantityType: quantityType)
|
|
25
26
|
) { (_, stats: HKStatistics?, error: Error?) in
|
|
26
27
|
DispatchQueue.main.async {
|
|
27
28
|
if let error = error {
|
|
28
|
-
return
|
|
29
|
+
return handleHKNoDataOrThrow(error: error, continuation: continuation, noDataFallback: {
|
|
30
|
+
return nil
|
|
31
|
+
})
|
|
29
32
|
}
|
|
30
33
|
|
|
31
34
|
if let stats = stats {
|
|
@@ -49,6 +52,10 @@ func serializeStatistics(gottenStats: HKStatistics, unit: HKUnit) -> QueryStatis
|
|
|
49
52
|
response.startDate = gottenStats.startDate
|
|
50
53
|
response.endDate = gottenStats.endDate
|
|
51
54
|
|
|
55
|
+
response.sources = gottenStats.sources?.map { source in
|
|
56
|
+
return serializeSource(source)
|
|
57
|
+
} ?? []
|
|
58
|
+
|
|
52
59
|
if let averageQuantity = gottenStats.averageQuantity() {
|
|
53
60
|
response.averageQuantity = Quantity(
|
|
54
61
|
unit: unit.unitString,
|
|
@@ -109,7 +116,7 @@ func queryStatisticsCollectionForQuantityInternal(
|
|
|
109
116
|
anchorDate: Date,
|
|
110
117
|
intervalComponents: IntervalComponents,
|
|
111
118
|
options: StatisticsQueryOptions?
|
|
112
|
-
) async throws -> HKStatisticsCollection {
|
|
119
|
+
) async throws -> HKStatisticsCollection? {
|
|
113
120
|
let predicate = createPredicateForSamples(options?.filter)
|
|
114
121
|
|
|
115
122
|
// Create date components from interval
|
|
@@ -131,9 +138,7 @@ func queryStatisticsCollectionForQuantityInternal(
|
|
|
131
138
|
}
|
|
132
139
|
|
|
133
140
|
// Build statistics options
|
|
134
|
-
let opts = buildStatisticsOptions(statistics: statistics)
|
|
135
|
-
|
|
136
|
-
let unit = try await getUnitToUse(unitOverride: options?.unit, quantityType: quantityType)
|
|
141
|
+
let opts = buildStatisticsOptions(statistics: statistics, quantityType: quantityType)
|
|
137
142
|
|
|
138
143
|
return try await withCheckedThrowingContinuation { continuation in
|
|
139
144
|
let query = HKStatisticsCollectionQuery.init(
|
|
@@ -146,7 +151,9 @@ func queryStatisticsCollectionForQuantityInternal(
|
|
|
146
151
|
|
|
147
152
|
query.initialResultsHandler = { (_, results: HKStatisticsCollection?, error: Error?) in
|
|
148
153
|
if let error = error {
|
|
149
|
-
return
|
|
154
|
+
return handleHKNoDataOrThrow(error: error, continuation: continuation, noDataFallback: {
|
|
155
|
+
return nil
|
|
156
|
+
})
|
|
150
157
|
}
|
|
151
158
|
|
|
152
159
|
guard let statistics = results else {
|
|
@@ -250,31 +257,6 @@ func getAnyMapValue(_ anyMap: AnyMap, key: String) -> Any? {
|
|
|
250
257
|
return nil
|
|
251
258
|
}
|
|
252
259
|
|
|
253
|
-
func buildStatisticsOptions(statistics: [StatisticsOptions]) -> HKStatisticsOptions {
|
|
254
|
-
// Build statistics options
|
|
255
|
-
var opts = HKStatisticsOptions()
|
|
256
|
-
for statistic in statistics {
|
|
257
|
-
if statistic == .cumulativesum {
|
|
258
|
-
opts.insert(HKStatisticsOptions.cumulativeSum)
|
|
259
|
-
} else if statistic == .discreteaverage {
|
|
260
|
-
opts.insert(HKStatisticsOptions.discreteAverage)
|
|
261
|
-
} else if statistic == .discretemax {
|
|
262
|
-
opts.insert(HKStatisticsOptions.discreteMax)
|
|
263
|
-
} else if statistic == .discretemin {
|
|
264
|
-
opts.insert(HKStatisticsOptions.discreteMin)
|
|
265
|
-
}
|
|
266
|
-
if #available(iOS 13, *) {
|
|
267
|
-
if statistic == .duration {
|
|
268
|
-
opts.insert(HKStatisticsOptions.duration)
|
|
269
|
-
}
|
|
270
|
-
if statistic == .mostrecent {
|
|
271
|
-
opts.insert(HKStatisticsOptions.mostRecent)
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
return opts
|
|
276
|
-
}
|
|
277
|
-
|
|
278
260
|
/// Handles HealthKit's `errorNoData` by resuming the continuation with a fallback value if provided,
|
|
279
261
|
/// otherwise resumes with `nil` for Optional result types. For other errors, resumes by throwing.
|
|
280
262
|
/// - Parameters:
|
|
@@ -303,20 +285,19 @@ class QuantityTypeModule: HybridQuantityTypeModuleSpec {
|
|
|
303
285
|
return Promise.async {
|
|
304
286
|
let quantityType = try initializeQuantityType(identifier.stringValue)
|
|
305
287
|
|
|
306
|
-
let gottenStats = try await queryStatisticsForQuantityInternal(
|
|
288
|
+
if let gottenStats = try await queryStatisticsForQuantityInternal(
|
|
307
289
|
quantityType: quantityType,
|
|
308
290
|
statistics: statistics,
|
|
309
291
|
options: options
|
|
310
|
-
)
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
return response
|
|
292
|
+
) {
|
|
293
|
+
let unit = try await getUnitToUse(
|
|
294
|
+
unitOverride: options?.unit,
|
|
295
|
+
quantityType: quantityType
|
|
296
|
+
)
|
|
297
|
+
return serializeStatisticsPerSource(gottenStats: gottenStats, unit: unit)
|
|
298
|
+
} else {
|
|
299
|
+
return []
|
|
300
|
+
}
|
|
320
301
|
}
|
|
321
302
|
}
|
|
322
303
|
|
|
@@ -327,22 +308,24 @@ class QuantityTypeModule: HybridQuantityTypeModuleSpec {
|
|
|
327
308
|
return Promise.async {
|
|
328
309
|
let quantityType = try initializeQuantityType(identifier.stringValue)
|
|
329
310
|
|
|
330
|
-
let statistics = try await queryStatisticsCollectionForQuantityInternal(
|
|
311
|
+
if let statistics = try await queryStatisticsCollectionForQuantityInternal(
|
|
331
312
|
quantityType: quantityType,
|
|
332
313
|
statistics: statistics,
|
|
333
314
|
anchorDate: anchorDate,
|
|
334
315
|
intervalComponents: intervalComponents,
|
|
335
316
|
options: options
|
|
336
|
-
)
|
|
317
|
+
) {
|
|
337
318
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
319
|
+
let unit = try await getUnitToUse(
|
|
320
|
+
unitOverride: options?.unit,
|
|
321
|
+
quantityType: quantityType
|
|
322
|
+
)
|
|
342
323
|
|
|
343
|
-
|
|
344
|
-
|
|
324
|
+
return statistics.statistics().flatMap { statistics in
|
|
325
|
+
return serializeStatisticsPerSource(gottenStats: statistics, unit: unit)
|
|
326
|
+
}
|
|
345
327
|
}
|
|
328
|
+
return []
|
|
346
329
|
}
|
|
347
330
|
}
|
|
348
331
|
|
|
@@ -361,30 +344,36 @@ class QuantityTypeModule: HybridQuantityTypeModuleSpec {
|
|
|
361
344
|
func isQuantityCompatibleWithUnit(identifier: QuantityTypeIdentifier, unit: String) throws -> Bool {
|
|
362
345
|
let sampleType = try initializeQuantityType(identifier.stringValue)
|
|
363
346
|
|
|
364
|
-
|
|
347
|
+
let hkUnit = try parseUnitStringSafe(unit)
|
|
348
|
+
|
|
349
|
+
return sampleType.is(compatibleWith: hkUnit)
|
|
365
350
|
}
|
|
366
351
|
|
|
367
352
|
func queryStatisticsForQuantity(
|
|
368
|
-
identifier: QuantityTypeIdentifier,
|
|
353
|
+
identifier: QuantityTypeIdentifier,
|
|
354
|
+
statistics: [StatisticsOptions],
|
|
369
355
|
options: StatisticsQueryOptions?
|
|
370
356
|
) -> Promise<QueryStatisticsResponse> {
|
|
371
357
|
return Promise.async {
|
|
372
358
|
let quantityType = try initializeQuantityType(identifier.stringValue)
|
|
373
359
|
|
|
374
|
-
let gottenStats = try await queryStatisticsForQuantityInternal(
|
|
360
|
+
if let gottenStats = try await queryStatisticsForQuantityInternal(
|
|
375
361
|
quantityType: quantityType,
|
|
376
362
|
statistics: statistics,
|
|
377
363
|
options: options
|
|
378
|
-
)
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
)
|
|
364
|
+
) {
|
|
365
|
+
let unit = try await getUnitToUse(
|
|
366
|
+
unitOverride: options?.unit,
|
|
367
|
+
quantityType: quantityType
|
|
368
|
+
)
|
|
384
369
|
|
|
385
|
-
|
|
370
|
+
return serializeStatistics(gottenStats: gottenStats, unit: unit)
|
|
371
|
+
}
|
|
386
372
|
|
|
387
|
-
return
|
|
373
|
+
return emptyStatisticsResponse(
|
|
374
|
+
from: options?.filter?.date?.startDate,
|
|
375
|
+
to: options?.filter?.date?.endDate
|
|
376
|
+
)
|
|
388
377
|
}
|
|
389
378
|
}
|
|
390
379
|
|
|
@@ -395,22 +384,24 @@ class QuantityTypeModule: HybridQuantityTypeModuleSpec {
|
|
|
395
384
|
return Promise.async {
|
|
396
385
|
let quantityType = try initializeQuantityType(identifier.stringValue)
|
|
397
386
|
|
|
398
|
-
let statistics = try await queryStatisticsCollectionForQuantityInternal(
|
|
387
|
+
if let statistics = try await queryStatisticsCollectionForQuantityInternal(
|
|
399
388
|
quantityType: quantityType,
|
|
400
389
|
statistics: statistics,
|
|
401
390
|
anchorDate: anchorDate,
|
|
402
391
|
intervalComponents: intervalComponents,
|
|
403
392
|
options: options
|
|
404
|
-
)
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
)
|
|
393
|
+
) {
|
|
394
|
+
let unit = try await getUnitToUse(
|
|
395
|
+
unitOverride: options?.unit,
|
|
396
|
+
quantityType: quantityType
|
|
397
|
+
)
|
|
410
398
|
|
|
411
|
-
|
|
412
|
-
|
|
399
|
+
return statistics.statistics().map { statistics in
|
|
400
|
+
return serializeStatistics(gottenStats: statistics, unit: unit)
|
|
401
|
+
}
|
|
413
402
|
}
|
|
403
|
+
|
|
404
|
+
return []
|
|
414
405
|
}
|
|
415
406
|
}
|
|
416
407
|
|
|
@@ -464,7 +455,7 @@ class QuantityTypeModule: HybridQuantityTypeModuleSpec {
|
|
|
464
455
|
metadata: AnyMap?
|
|
465
456
|
) -> Promise<QuantitySample?> {
|
|
466
457
|
return Promise.async {
|
|
467
|
-
let unit =
|
|
458
|
+
let unit = try parseUnitStringSafe(unit)
|
|
468
459
|
let quantity = HKQuantity.init(unit: unit, doubleValue: value)
|
|
469
460
|
let typeIdentifier = HKQuantityType(
|
|
470
461
|
HKQuantityTypeIdentifier(rawValue: identifier.stringValue)
|
package/ios/WorkoutsModule.swift
CHANGED
|
@@ -104,7 +104,7 @@ class WorkoutsModule: HybridWorkoutsModuleSpec {
|
|
|
104
104
|
let quantityVal = quantity.quantity
|
|
105
105
|
let quantityStart = quantity.startDate
|
|
106
106
|
let quantityEnd = quantity.endDate
|
|
107
|
-
let unit =
|
|
107
|
+
let unit = try parseUnitStringSafe(unitStr)
|
|
108
108
|
let quantity = HKQuantity.init(unit: unit, doubleValue: quantityVal)
|
|
109
109
|
|
|
110
110
|
if quantity.is(compatibleWith: HKUnit.kilocalorie()) {
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
/// Copyright © 2025 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
|
+
import Foundation
|
|
8
9
|
import NitroModules
|
|
9
10
|
|
|
10
|
-
|
|
11
11
|
/**
|
|
12
12
|
* Wraps a Swift `(_ value: AuthorizationRequestStatus) -> Void` as a class.
|
|
13
13
|
* This class can be used from C++, e.g. to wrap the Swift closure as a `std::function`.
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
/// Copyright © 2025 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
|
+
import Foundation
|
|
8
9
|
import NitroModules
|
|
9
10
|
|
|
10
|
-
|
|
11
11
|
/**
|
|
12
12
|
* Wraps a Swift `(_ value: BiologicalSex) -> Void` as a class.
|
|
13
13
|
* This class can be used from C++, e.g. to wrap the Swift closure as a `std::function`.
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
/// Copyright © 2025 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
|
+
import Foundation
|
|
8
9
|
import NitroModules
|
|
9
10
|
|
|
10
|
-
|
|
11
11
|
/**
|
|
12
12
|
* Wraps a Swift `(_ value: BloodType) -> Void` as a class.
|
|
13
13
|
* This class can be used from C++, e.g. to wrap the Swift closure as a `std::function`.
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
/// Copyright © 2025 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
|
+
import Foundation
|
|
8
9
|
import NitroModules
|
|
9
10
|
|
|
10
|
-
|
|
11
11
|
/**
|
|
12
12
|
* Wraps a Swift `(_ value: CategorySamplesWithAnchorResponse) -> Void` as a class.
|
|
13
13
|
* This class can be used from C++, e.g. to wrap the Swift closure as a `std::function`.
|
package/nitrogen/generated/ios/swift/Func_void_ElectrocardiogramSamplesWithAnchorResponse.swift
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
/// Copyright © 2025 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
|
+
import Foundation
|
|
8
9
|
import NitroModules
|
|
9
10
|
|
|
10
|
-
|
|
11
11
|
/**
|
|
12
12
|
* Wraps a Swift `(_ value: ElectrocardiogramSamplesWithAnchorResponse) -> Void` as a class.
|
|
13
13
|
* This class can be used from C++, e.g. to wrap the Swift closure as a `std::function`.
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
/// Copyright © 2025 Marc Rousavy @ Margelo
|
|
6
6
|
///
|
|
7
7
|
|
|
8
|
+
import Foundation
|
|
8
9
|
import NitroModules
|
|
9
10
|
|
|
10
|
-
|
|
11
11
|
/**
|
|
12
12
|
* Wraps a Swift `(_ value: FitzpatrickSkinType) -> Void` as a class.
|
|
13
13
|
* This class can be used from C++, e.g. to wrap the Swift closure as a `std::function`.
|