@kingstinct/react-native-healthkit 12.0.0 → 12.1.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/README.md +5 -3
- package/ios/Helpers.swift +1 -1
- package/ios/QuantityTypeModule.swift +2 -11
- package/ios/WorkoutsModule.swift +5 -3
- package/lib/commonjs/healthkit.ios.js +11 -6
- package/lib/commonjs/healthkit.js +12 -4
- package/lib/commonjs/hooks/useSubscribeToQuantitySamples.js +20 -0
- package/lib/commonjs/utils/subscribeToQuantitySamples.js +47 -0
- package/lib/module/healthkit.ios.js +6 -4
- package/lib/module/healthkit.js +11 -3
- package/lib/module/hooks/useSubscribeToQuantitySamples.js +17 -0
- package/lib/module/utils/subscribeToQuantitySamples.js +43 -0
- package/lib/typescript/healthkit.d.ts +9 -2
- package/lib/typescript/healthkit.ios.d.ts +11 -5
- package/lib/typescript/hooks/useSubscribeToQuantitySamples.d.ts +3 -0
- package/lib/typescript/types/Subscriptions.d.ts +14 -1
- package/lib/typescript/utils/subscribeToQuantitySamples.d.ts +5 -0
- package/package.json +1 -1
- package/src/healthkit.ios.ts +11 -6
- package/src/healthkit.ts +19 -6
- package/src/hooks/useSubscribeToQuantitySamples.ts +31 -0
- package/src/types/Subscriptions.ts +19 -1
- package/src/utils/subscribeToQuantitySamples.ts +63 -0
package/README.md
CHANGED
|
@@ -84,14 +84,16 @@ Some imperative examples:
|
|
|
84
84
|
const isAvailable = await isHealthDataAvailable();
|
|
85
85
|
|
|
86
86
|
/* Read latest sample of any data */
|
|
87
|
-
await requestAuthorization(['HKQuantityTypeIdentifierBodyFatPercentage']); // request read permission for bodyFatPercentage
|
|
87
|
+
await requestAuthorization({ toRead: ['HKQuantityTypeIdentifierBodyFatPercentage'] }); // request read permission for bodyFatPercentage
|
|
88
88
|
|
|
89
89
|
const { quantity, unit, startDate, endDate } = await getMostRecentQuantitySample('HKQuantityTypeIdentifierBodyFatPercentage'); // read latest sample
|
|
90
90
|
|
|
91
91
|
console.log(quantity) // 17.5
|
|
92
92
|
console.log(unit) // %
|
|
93
93
|
|
|
94
|
-
await requestAuthorization(
|
|
94
|
+
await requestAuthorization({
|
|
95
|
+
toRead: ['HKQuantityTypeIdentifierHeartRate']
|
|
96
|
+
}); // request read permission for heart rate
|
|
95
97
|
|
|
96
98
|
/* Subscribe to data (Make sure to request permissions before subscribing to changes) */
|
|
97
99
|
const [hasRequestedAuthorization, setHasRequestedAuthorization] = useState(false);
|
|
@@ -113,7 +115,7 @@ Some imperative examples:
|
|
|
113
115
|
}, [hasRequestedAuthorization]);
|
|
114
116
|
|
|
115
117
|
/* write data */
|
|
116
|
-
await requestAuthorization(
|
|
118
|
+
await requestAuthorization({ toShare: ['HKQuantityTypeIdentifierInsulinDelivery'] }); // request write permission for insulin delivery
|
|
117
119
|
|
|
118
120
|
saveQuantitySample(
|
|
119
121
|
'HKQuantityTypeIdentifierInsulinDelivery',
|
package/ios/Helpers.swift
CHANGED
|
@@ -408,16 +408,7 @@ class QuantityTypeModule: HybridQuantityTypeModuleSpec {
|
|
|
408
408
|
let deletedSamples = deletedSamples?.map { serializeDeletedSample(sample: $0) } ?? []
|
|
409
409
|
let newAnchor = serializeAnchor(anchor: newAnchor) ?? ""
|
|
410
410
|
|
|
411
|
-
|
|
412
|
-
let response = QuantitySamplesWithAnchorResponse(
|
|
413
|
-
samples: [],
|
|
414
|
-
deletedSamples: deletedSamples,
|
|
415
|
-
newAnchor: newAnchor
|
|
416
|
-
)
|
|
417
|
-
return continuation.resume(returning: response)
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
let quantitySamples = samples.compactMap { sample in
|
|
411
|
+
let quantitySamples = samples?.compactMap { sample in
|
|
421
412
|
if let quantitySample = sample as? HKQuantitySample {
|
|
422
413
|
do {
|
|
423
414
|
return try serializeQuantitySample(
|
|
@@ -432,7 +423,7 @@ class QuantityTypeModule: HybridQuantityTypeModuleSpec {
|
|
|
432
423
|
}
|
|
433
424
|
|
|
434
425
|
let response = QuantitySamplesWithAnchorResponse(
|
|
435
|
-
samples: quantitySamples,
|
|
426
|
+
samples: quantitySamples ?? [],
|
|
436
427
|
deletedSamples: deletedSamples,
|
|
437
428
|
newAnchor: newAnchor,
|
|
438
429
|
)
|
package/ios/WorkoutsModule.swift
CHANGED
|
@@ -212,15 +212,17 @@ class WorkoutsModule: HybridWorkoutsModuleSpec {
|
|
|
212
212
|
store.save(workout) { (_: Bool, error: Error?) in
|
|
213
213
|
if let error = error {
|
|
214
214
|
return continuation.resume(throwing: error)
|
|
215
|
-
}
|
|
216
|
-
if !initializedSamples.isEmpty {
|
|
215
|
+
} else if !initializedSamples.isEmpty {
|
|
217
216
|
store.add(initializedSamples, to: workout) { (_, error: Error?) in
|
|
218
217
|
if let error = error {
|
|
219
218
|
return continuation.resume(throwing: error)
|
|
220
219
|
}
|
|
220
|
+
return continuation.resume()
|
|
221
221
|
}
|
|
222
|
+
} else {
|
|
223
|
+
return continuation.resume()
|
|
222
224
|
}
|
|
223
|
-
|
|
225
|
+
|
|
224
226
|
}
|
|
225
227
|
}) as Void
|
|
226
228
|
|
|
@@ -17,8 +17,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
17
17
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
18
18
|
};
|
|
19
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
-
exports.
|
|
21
|
-
exports.getWheelchairUseAsync = exports.getFitzpatrickSkinTypeAsync = exports.getDateOfBirthAsync = exports.getBloodTypeAsync = exports.getBiologicalSexAsync = exports.areObjectTypesAvailableAsync = exports.areObjectTypesAvailable = exports.isObjectTypeAvailableAsync = exports.isObjectTypeAvailable = exports.
|
|
20
|
+
exports.isProtectedDataAvailable = exports.startWatchApp = exports.saveWorkoutSample = exports.saveQuantitySample = exports.saveCorrelationSample = exports.saveCategorySample = exports.deleteObjects = exports.requestAuthorization = exports.querySources = exports.queryWorkoutSamplesWithAnchor = exports.queryWorkoutSamples = exports.queryStatisticsCollectionForQuantity = exports.queryStatisticsForQuantity = exports.queryQuantitySamplesWithAnchor = exports.queryQuantitySamples = exports.queryElectrocardiogramSamplesWithAnchor = exports.queryElectrocardiogramSamples = exports.queryHeartbeatSeriesSamplesWithAnchor = exports.queryHeartbeatSeriesSamples = exports.queryCorrelationSamples = exports.queryCategorySamplesWithAnchor = exports.queryCategorySamples = exports.isHealthDataAvailableAsync = exports.isHealthDataAvailable = exports.getWheelchairUse = exports.getRequestStatusForAuthorization = exports.getPreferredUnits = exports.getFitzpatrickSkinType = exports.getDateOfBirth = exports.getBloodType = exports.getBiologicalSex = exports.enableBackgroundDelivery = exports.disableBackgroundDelivery = exports.disableAllBackgroundDelivery = exports.authorizationStatusFor = exports.useSubscribeToQuantitySamples = exports.useSubscribeToChanges = exports.useStatisticsForQuantity = exports.useSources = exports.useMostRecentWorkout = exports.useMostRecentQuantitySample = exports.useMostRecentCategorySample = exports.useIsHealthDataAvailable = exports.useHealthkitAuthorization = exports.subscribeToQuantitySamples = exports.subscribeToChanges = exports.getPreferredUnit = exports.getMostRecentWorkout = exports.getMostRecentQuantitySample = exports.getMostRecentCategorySample = void 0;
|
|
21
|
+
exports.getWheelchairUseAsync = exports.getFitzpatrickSkinTypeAsync = exports.getDateOfBirthAsync = exports.getBloodTypeAsync = exports.getBiologicalSexAsync = exports.areObjectTypesAvailableAsync = exports.areObjectTypesAvailable = exports.isObjectTypeAvailableAsync = exports.isObjectTypeAvailable = exports.isQuantityCompatibleWithUnit = exports.saveStateOfMindSample = exports.queryStateOfMindSamples = void 0;
|
|
22
22
|
const react_native_1 = require("react-native");
|
|
23
23
|
const useHealthkitAuthorization_1 = __importDefault(require("./hooks/useHealthkitAuthorization"));
|
|
24
24
|
exports.useHealthkitAuthorization = useHealthkitAuthorization_1.default;
|
|
@@ -36,6 +36,8 @@ const useStatisticsForQuantity_1 = __importDefault(require("./hooks/useStatistic
|
|
|
36
36
|
exports.useStatisticsForQuantity = useStatisticsForQuantity_1.default;
|
|
37
37
|
const useSubscribeToChanges_1 = __importDefault(require("./hooks/useSubscribeToChanges"));
|
|
38
38
|
exports.useSubscribeToChanges = useSubscribeToChanges_1.default;
|
|
39
|
+
const useSubscribeToQuantitySamples_1 = __importDefault(require("./hooks/useSubscribeToQuantitySamples"));
|
|
40
|
+
exports.useSubscribeToQuantitySamples = useSubscribeToQuantitySamples_1.default;
|
|
39
41
|
const modules_1 = require("./modules");
|
|
40
42
|
const getMostRecentCategorySample_1 = __importDefault(require("./utils/getMostRecentCategorySample"));
|
|
41
43
|
exports.getMostRecentCategorySample = getMostRecentCategorySample_1.default;
|
|
@@ -45,6 +47,10 @@ const getMostRecentWorkout_1 = __importDefault(require("./utils/getMostRecentWor
|
|
|
45
47
|
exports.getMostRecentWorkout = getMostRecentWorkout_1.default;
|
|
46
48
|
const getPreferredUnit_1 = __importDefault(require("./utils/getPreferredUnit"));
|
|
47
49
|
exports.getPreferredUnit = getPreferredUnit_1.default;
|
|
50
|
+
const subscribeToChanges_1 = require("./utils/subscribeToChanges");
|
|
51
|
+
Object.defineProperty(exports, "subscribeToChanges", { enumerable: true, get: function () { return subscribeToChanges_1.subscribeToChanges; } });
|
|
52
|
+
const subscribeToQuantitySamples_1 = require("./utils/subscribeToQuantitySamples");
|
|
53
|
+
Object.defineProperty(exports, "subscribeToQuantitySamples", { enumerable: true, get: function () { return subscribeToQuantitySamples_1.subscribeToQuantitySamples; } });
|
|
48
54
|
__exportStar(require("./types"), exports);
|
|
49
55
|
const currentMajorVersionIOS = react_native_1.Platform.OS === 'ios' ? Number.parseInt(react_native_1.Platform.Version, 10) : 0;
|
|
50
56
|
// Named exports - all functions bound to their respective modules
|
|
@@ -81,13 +87,11 @@ exports.saveCategorySample = modules_1.CategoryTypes.saveCategorySample.bind(mod
|
|
|
81
87
|
exports.saveCorrelationSample = modules_1.CorrelationTypes.saveCorrelationSample.bind(modules_1.CorrelationTypes);
|
|
82
88
|
exports.saveQuantitySample = modules_1.QuantityTypes.saveQuantitySample.bind(modules_1.QuantityTypes);
|
|
83
89
|
exports.saveWorkoutSample = modules_1.Workouts.saveWorkoutSample.bind(modules_1.Workouts);
|
|
84
|
-
exports.subscribeToChanges = modules_1.Core.subscribeToObserverQuery.bind(modules_1.Core);
|
|
85
90
|
exports.startWatchApp = modules_1.Workouts.startWatchAppWithWorkoutConfiguration.bind(modules_1.Workouts);
|
|
86
91
|
exports.isProtectedDataAvailable = modules_1.Core.isProtectedDataAvailable.bind(modules_1.Core);
|
|
87
92
|
exports.queryStateOfMindSamples = modules_1.StateOfMind.queryStateOfMindSamples.bind(modules_1.StateOfMind);
|
|
88
93
|
exports.saveStateOfMindSample = modules_1.StateOfMind.saveStateOfMindSample.bind(modules_1.StateOfMind);
|
|
89
94
|
exports.isQuantityCompatibleWithUnit = modules_1.QuantityTypes.isQuantityCompatibleWithUnit.bind(modules_1.QuantityTypes);
|
|
90
|
-
exports.unsubscribeQueries = modules_1.Core.unsubscribeQueries.bind(modules_1.Core);
|
|
91
95
|
exports.isObjectTypeAvailable = modules_1.Core.isObjectTypeAvailable.bind(modules_1.Core);
|
|
92
96
|
exports.isObjectTypeAvailableAsync = modules_1.Core.isObjectTypeAvailableAsync.bind(modules_1.Core);
|
|
93
97
|
exports.areObjectTypesAvailable = modules_1.Core.areObjectTypesAvailable.bind(modules_1.Core);
|
|
@@ -145,8 +149,8 @@ exports.default = {
|
|
|
145
149
|
saveCorrelationSample: exports.saveCorrelationSample,
|
|
146
150
|
saveQuantitySample: exports.saveQuantitySample,
|
|
147
151
|
saveWorkoutSample: exports.saveWorkoutSample,
|
|
148
|
-
subscribeToChanges:
|
|
149
|
-
|
|
152
|
+
subscribeToChanges: subscribeToChanges_1.subscribeToChanges,
|
|
153
|
+
subscribeToQuantitySamples: subscribeToQuantitySamples_1.subscribeToQuantitySamples,
|
|
150
154
|
startWatchApp: exports.startWatchApp,
|
|
151
155
|
isProtectedDataAvailable: exports.isProtectedDataAvailable,
|
|
152
156
|
queryStateOfMindSamples: exports.queryStateOfMindSamples,
|
|
@@ -156,6 +160,7 @@ exports.default = {
|
|
|
156
160
|
useMostRecentQuantitySample: useMostRecentQuantitySample_1.default,
|
|
157
161
|
useMostRecentWorkout: useMostRecentWorkout_1.default,
|
|
158
162
|
useSubscribeToChanges: useSubscribeToChanges_1.default,
|
|
163
|
+
useSubscribeToQuantitySamples: useSubscribeToQuantitySamples_1.default,
|
|
159
164
|
useHealthkitAuthorization: useHealthkitAuthorization_1.default,
|
|
160
165
|
useIsHealthDataAvailable: useIsHealthDataAvailable_1.useIsHealthDataAvailable,
|
|
161
166
|
useSources: useSources_1.default,
|
|
@@ -15,7 +15,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
exports.useSources = exports.useIsHealthDataAvailable = exports.useHealthkitAuthorization = exports.useSubscribeToChanges = exports.useMostRecentWorkout = exports.useMostRecentQuantitySample = exports.getPreferredUnit = exports.getMostRecentWorkout = exports.getMostRecentQuantitySample = exports.saveStateOfMindSample = exports.queryStateOfMindSamples = exports.startWatchApp = exports.saveWorkoutSample = exports.queryWorkoutSamplesWithAnchor = exports.queryWorkoutSamples = exports.queryElectrocardiogramSamplesWithAnchor = exports.queryElectrocardiogramSamples = exports.queryHeartbeatSeriesSamplesWithAnchor = exports.queryHeartbeatSeriesSamples = exports.saveCorrelationSample = exports.queryCorrelationSamples = exports.saveCategorySample = exports.isQuantityCompatibleWithUnit = exports.saveQuantitySample = exports.queryStatisticsCollectionForQuantity = exports.queryStatisticsForQuantity = exports.queryQuantitySamplesWithAnchor = exports.queryQuantitySamples = exports.getWheelchairUse = exports.getFitzpatrickSkinType = exports.getDateOfBirth = exports.getBloodType = exports.getBiologicalSex = exports.areObjectTypesAvailableAsync = exports.areObjectTypesAvailable = exports.isObjectTypeAvailableAsync = exports.isObjectTypeAvailable = exports.isProtectedDataAvailable = exports.subscribeToChanges = exports.deleteObjects = exports.requestAuthorization = exports.querySources = exports.isHealthDataAvailableAsync = exports.isHealthDataAvailable = exports.getRequestStatusForAuthorization = exports.getPreferredUnits = exports.enableBackgroundDelivery = exports.disableBackgroundDelivery = exports.disableAllBackgroundDelivery = exports.authorizationStatusFor = void 0;
|
|
18
|
-
exports.
|
|
18
|
+
exports.useSubscribeToQuantitySamples = exports.subscribeToQuantitySamples = exports.getWheelchairUseAsync = exports.getFitzpatrickSkinTypeAsync = exports.getDateOfBirthAsync = exports.getBloodTypeAsync = exports.getBiologicalSexAsync = exports.useStatisticsForQuantity = void 0;
|
|
19
19
|
exports.queryCategorySamples = queryCategorySamples;
|
|
20
20
|
exports.queryCategorySamplesWithAnchor = queryCategorySamplesWithAnchor;
|
|
21
21
|
exports.getMostRecentCategorySample = getMostRecentCategorySample;
|
|
@@ -49,7 +49,9 @@ exports.isHealthDataAvailableAsync = UnavailableFnFromModule('isHealthDataAvaila
|
|
|
49
49
|
exports.querySources = UnavailableFnFromModule('querySources', Promise.resolve([]));
|
|
50
50
|
exports.requestAuthorization = UnavailableFnFromModule('requestAuthorization', Promise.resolve(false));
|
|
51
51
|
exports.deleteObjects = UnavailableFnFromModule('deleteObjects', Promise.resolve(0));
|
|
52
|
-
exports.subscribeToChanges = UnavailableFnFromModule('subscribeToChanges',
|
|
52
|
+
exports.subscribeToChanges = UnavailableFnFromModule('subscribeToChanges', {
|
|
53
|
+
remove: () => false,
|
|
54
|
+
}); // Mocking the observer query UUID
|
|
53
55
|
exports.isProtectedDataAvailable = UnavailableFnFromModule('isProtectedDataAvailable', false);
|
|
54
56
|
exports.isObjectTypeAvailable = UnavailableFnFromModule('isObjectTypeAvailable', false);
|
|
55
57
|
exports.isObjectTypeAvailableAsync = UnavailableFnFromModule('isObjectTypeAvailableAsync', Promise.resolve(false));
|
|
@@ -160,14 +162,18 @@ exports.getBloodTypeAsync = UnavailableFnFromModule('getBloodTypeAsync', Promise
|
|
|
160
162
|
exports.getDateOfBirthAsync = UnavailableFnFromModule('getDateOfBirthAsync', Promise.resolve(new Date(0))); // Assuming string for date
|
|
161
163
|
exports.getFitzpatrickSkinTypeAsync = UnavailableFnFromModule('getFitzpatrickSkinTypeAsync', Promise.resolve(Characteristics_1.FitzpatrickSkinType.notSet));
|
|
162
164
|
exports.getWheelchairUseAsync = UnavailableFnFromModule('getWheelchairUseAsync', Promise.resolve(Characteristics_1.WheelchairUse.notSet));
|
|
163
|
-
|
|
165
|
+
const subscribeToQuantitySamples = UnavailableFnFromModule('subscribeToQuantitySamples', {
|
|
166
|
+
remove: () => false,
|
|
167
|
+
}); // Mocking the observer query UUID
|
|
168
|
+
exports.subscribeToQuantitySamples = subscribeToQuantitySamples;
|
|
169
|
+
const useSubscribeToQuantitySamples = UnavailableFnFromModule('useSubscribeToQuantitySamples', undefined); // Mocking callback structure
|
|
170
|
+
exports.useSubscribeToQuantitySamples = useSubscribeToQuantitySamples;
|
|
164
171
|
// --- Default Export ---
|
|
165
172
|
// This attempts to match the structure of the default export from index.ios.ts
|
|
166
173
|
const HealthkitModule = {
|
|
167
174
|
// All named exports are also part of the default export object
|
|
168
175
|
authorizationStatusFor: exports.authorizationStatusFor,
|
|
169
176
|
isObjectTypeAvailable: exports.isObjectTypeAvailable,
|
|
170
|
-
unsubscribeQueries: exports.unsubscribeQueries,
|
|
171
177
|
isObjectTypeAvailableAsync: exports.isObjectTypeAvailableAsync,
|
|
172
178
|
areObjectTypesAvailable: exports.areObjectTypesAvailable,
|
|
173
179
|
areObjectTypesAvailableAsync: exports.areObjectTypesAvailableAsync,
|
|
@@ -213,6 +219,8 @@ const HealthkitModule = {
|
|
|
213
219
|
isProtectedDataAvailable: exports.isProtectedDataAvailable,
|
|
214
220
|
queryStateOfMindSamples: exports.queryStateOfMindSamples,
|
|
215
221
|
saveStateOfMindSample: exports.saveStateOfMindSample,
|
|
222
|
+
subscribeToQuantitySamples,
|
|
223
|
+
useSubscribeToQuantitySamples,
|
|
216
224
|
// Hooks
|
|
217
225
|
useMostRecentCategorySample,
|
|
218
226
|
useMostRecentQuantitySample: exports.useMostRecentQuantitySample,
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useSubscribeToQuantitySamples = useSubscribeToQuantitySamples;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
const subscribeToQuantitySamples_1 = require("../utils/subscribeToQuantitySamples");
|
|
6
|
+
function useSubscribeToQuantitySamples(identifier, onChange) {
|
|
7
|
+
const onChangeRef = (0, react_1.useRef)(onChange);
|
|
8
|
+
(0, react_1.useEffect)(() => {
|
|
9
|
+
onChangeRef.current = onChange;
|
|
10
|
+
}, [onChange]);
|
|
11
|
+
(0, react_1.useEffect)(() => {
|
|
12
|
+
const subscription = (0, subscribeToQuantitySamples_1.subscribeToQuantitySamples)(identifier, (args) => {
|
|
13
|
+
onChangeRef.current(args);
|
|
14
|
+
});
|
|
15
|
+
return () => {
|
|
16
|
+
subscription.remove();
|
|
17
|
+
};
|
|
18
|
+
}, [identifier]);
|
|
19
|
+
}
|
|
20
|
+
exports.default = useSubscribeToQuantitySamples;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.subscribeToQuantitySamples = void 0;
|
|
4
|
+
const modules_1 = require("../modules");
|
|
5
|
+
const subscribeToChanges_1 = require("./subscribeToChanges");
|
|
6
|
+
const subscribeToQuantitySamples = (identifier, callback, after) => {
|
|
7
|
+
let anchor;
|
|
8
|
+
const afterDate = after ?? new Date();
|
|
9
|
+
const init = async () => {
|
|
10
|
+
// we need to do an initial query to get a handle for the deletedSamples
|
|
11
|
+
const { newAnchor } = await modules_1.QuantityTypes.queryQuantitySamplesWithAnchor(identifier, {
|
|
12
|
+
filter: {
|
|
13
|
+
startDate: afterDate,
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
anchor = newAnchor;
|
|
17
|
+
};
|
|
18
|
+
init();
|
|
19
|
+
return (0, subscribeToChanges_1.subscribeToChanges)(identifier, async ({ errorMessage }) => {
|
|
20
|
+
if (errorMessage) {
|
|
21
|
+
return callback({
|
|
22
|
+
typeIdentifier: identifier,
|
|
23
|
+
errorMessage,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
// seems like all deletedSamples are included when no anchor is provided, so we don't want to return those for the first query
|
|
27
|
+
const hadAnchorWhenDoingQuery = !!anchor;
|
|
28
|
+
const { samples, newAnchor, deletedSamples } = await modules_1.QuantityTypes.queryQuantitySamplesWithAnchor(identifier, {
|
|
29
|
+
anchor,
|
|
30
|
+
filter: {
|
|
31
|
+
startDate: afterDate,
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
anchor = newAnchor;
|
|
35
|
+
const hasNewSamples = samples.length > 0 ||
|
|
36
|
+
(deletedSamples.length > 0 && hadAnchorWhenDoingQuery);
|
|
37
|
+
if (hasNewSamples) {
|
|
38
|
+
callback({
|
|
39
|
+
typeIdentifier: identifier,
|
|
40
|
+
samples,
|
|
41
|
+
anchor: newAnchor,
|
|
42
|
+
deletedSamples: hadAnchorWhenDoingQuery ? deletedSamples : [],
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
exports.subscribeToQuantitySamples = subscribeToQuantitySamples;
|
|
@@ -7,14 +7,17 @@ import useMostRecentWorkout from './hooks/useMostRecentWorkout';
|
|
|
7
7
|
import useSources from './hooks/useSources';
|
|
8
8
|
import useStatisticsForQuantity from './hooks/useStatisticsForQuantity';
|
|
9
9
|
import useSubscribeToChanges from './hooks/useSubscribeToChanges';
|
|
10
|
+
import useSubscribeToQuantitySamples from './hooks/useSubscribeToQuantitySamples';
|
|
10
11
|
import { CategoryTypes, Characteristics, Core, CorrelationTypes, Electrocardiograms, HeartbeatSeries, QuantityTypes, StateOfMind, Workouts, } from './modules';
|
|
11
12
|
import getMostRecentCategorySample from './utils/getMostRecentCategorySample';
|
|
12
13
|
import getMostRecentQuantitySample from './utils/getMostRecentQuantitySample';
|
|
13
14
|
import getMostRecentWorkout from './utils/getMostRecentWorkout';
|
|
14
15
|
import getPreferredUnit from './utils/getPreferredUnit';
|
|
16
|
+
import { subscribeToChanges } from './utils/subscribeToChanges';
|
|
17
|
+
import { subscribeToQuantitySamples } from './utils/subscribeToQuantitySamples';
|
|
15
18
|
export * from './types';
|
|
16
19
|
const currentMajorVersionIOS = Platform.OS === 'ios' ? Number.parseInt(Platform.Version, 10) : 0;
|
|
17
|
-
export { getMostRecentCategorySample, getMostRecentQuantitySample, getMostRecentWorkout, getPreferredUnit,
|
|
20
|
+
export { getMostRecentCategorySample, getMostRecentQuantitySample, getMostRecentWorkout, getPreferredUnit, subscribeToChanges, subscribeToQuantitySamples, useHealthkitAuthorization, useIsHealthDataAvailable, useMostRecentCategorySample, useMostRecentQuantitySample, useMostRecentWorkout, useSources, useStatisticsForQuantity, useSubscribeToChanges, useSubscribeToQuantitySamples, };
|
|
18
21
|
// Named exports - all functions bound to their respective modules
|
|
19
22
|
export const authorizationStatusFor = Core.authorizationStatusFor.bind(Core);
|
|
20
23
|
export const disableAllBackgroundDelivery = Core.disableAllBackgroundDelivery.bind(Core);
|
|
@@ -49,13 +52,11 @@ export const saveCategorySample = CategoryTypes.saveCategorySample.bind(Category
|
|
|
49
52
|
export const saveCorrelationSample = CorrelationTypes.saveCorrelationSample.bind(CorrelationTypes);
|
|
50
53
|
export const saveQuantitySample = QuantityTypes.saveQuantitySample.bind(QuantityTypes);
|
|
51
54
|
export const saveWorkoutSample = Workouts.saveWorkoutSample.bind(Workouts);
|
|
52
|
-
export const subscribeToChanges = Core.subscribeToObserverQuery.bind(Core);
|
|
53
55
|
export const startWatchApp = Workouts.startWatchAppWithWorkoutConfiguration.bind(Workouts);
|
|
54
56
|
export const isProtectedDataAvailable = Core.isProtectedDataAvailable.bind(Core);
|
|
55
57
|
export const queryStateOfMindSamples = StateOfMind.queryStateOfMindSamples.bind(StateOfMind);
|
|
56
58
|
export const saveStateOfMindSample = StateOfMind.saveStateOfMindSample.bind(StateOfMind);
|
|
57
59
|
export const isQuantityCompatibleWithUnit = QuantityTypes.isQuantityCompatibleWithUnit.bind(QuantityTypes);
|
|
58
|
-
export const unsubscribeQueries = Core.unsubscribeQueries.bind(Core);
|
|
59
60
|
export const isObjectTypeAvailable = Core.isObjectTypeAvailable.bind(Core);
|
|
60
61
|
export const isObjectTypeAvailableAsync = Core.isObjectTypeAvailableAsync.bind(Core);
|
|
61
62
|
export const areObjectTypesAvailable = Core.areObjectTypesAvailable.bind(Core);
|
|
@@ -114,7 +115,7 @@ export default {
|
|
|
114
115
|
saveQuantitySample,
|
|
115
116
|
saveWorkoutSample,
|
|
116
117
|
subscribeToChanges,
|
|
117
|
-
|
|
118
|
+
subscribeToQuantitySamples,
|
|
118
119
|
startWatchApp,
|
|
119
120
|
isProtectedDataAvailable,
|
|
120
121
|
queryStateOfMindSamples,
|
|
@@ -124,6 +125,7 @@ export default {
|
|
|
124
125
|
useMostRecentQuantitySample,
|
|
125
126
|
useMostRecentWorkout,
|
|
126
127
|
useSubscribeToChanges,
|
|
128
|
+
useSubscribeToQuantitySamples,
|
|
127
129
|
useHealthkitAuthorization,
|
|
128
130
|
useIsHealthDataAvailable,
|
|
129
131
|
useSources,
|
package/lib/module/healthkit.js
CHANGED
|
@@ -27,7 +27,9 @@ export const isHealthDataAvailableAsync = UnavailableFnFromModule('isHealthDataA
|
|
|
27
27
|
export const querySources = UnavailableFnFromModule('querySources', Promise.resolve([]));
|
|
28
28
|
export const requestAuthorization = UnavailableFnFromModule('requestAuthorization', Promise.resolve(false));
|
|
29
29
|
export const deleteObjects = UnavailableFnFromModule('deleteObjects', Promise.resolve(0));
|
|
30
|
-
export const subscribeToChanges = UnavailableFnFromModule('subscribeToChanges',
|
|
30
|
+
export const subscribeToChanges = UnavailableFnFromModule('subscribeToChanges', {
|
|
31
|
+
remove: () => false,
|
|
32
|
+
}); // Mocking the observer query UUID
|
|
31
33
|
export const isProtectedDataAvailable = UnavailableFnFromModule('isProtectedDataAvailable', false);
|
|
32
34
|
export const isObjectTypeAvailable = UnavailableFnFromModule('isObjectTypeAvailable', false);
|
|
33
35
|
export const isObjectTypeAvailableAsync = UnavailableFnFromModule('isObjectTypeAvailableAsync', Promise.resolve(false));
|
|
@@ -138,14 +140,18 @@ export const getBloodTypeAsync = UnavailableFnFromModule('getBloodTypeAsync', Pr
|
|
|
138
140
|
export const getDateOfBirthAsync = UnavailableFnFromModule('getDateOfBirthAsync', Promise.resolve(new Date(0))); // Assuming string for date
|
|
139
141
|
export const getFitzpatrickSkinTypeAsync = UnavailableFnFromModule('getFitzpatrickSkinTypeAsync', Promise.resolve(FitzpatrickSkinType.notSet));
|
|
140
142
|
export const getWheelchairUseAsync = UnavailableFnFromModule('getWheelchairUseAsync', Promise.resolve(WheelchairUse.notSet));
|
|
141
|
-
|
|
143
|
+
const subscribeToQuantitySamples = UnavailableFnFromModule('subscribeToQuantitySamples', {
|
|
144
|
+
remove: () => false,
|
|
145
|
+
}); // Mocking the observer query UUID
|
|
146
|
+
export { subscribeToQuantitySamples };
|
|
147
|
+
const useSubscribeToQuantitySamples = UnavailableFnFromModule('useSubscribeToQuantitySamples', undefined); // Mocking callback structure
|
|
148
|
+
export { useSubscribeToQuantitySamples };
|
|
142
149
|
// --- Default Export ---
|
|
143
150
|
// This attempts to match the structure of the default export from index.ios.ts
|
|
144
151
|
const HealthkitModule = {
|
|
145
152
|
// All named exports are also part of the default export object
|
|
146
153
|
authorizationStatusFor,
|
|
147
154
|
isObjectTypeAvailable,
|
|
148
|
-
unsubscribeQueries,
|
|
149
155
|
isObjectTypeAvailableAsync,
|
|
150
156
|
areObjectTypesAvailable,
|
|
151
157
|
areObjectTypesAvailableAsync,
|
|
@@ -191,6 +197,8 @@ const HealthkitModule = {
|
|
|
191
197
|
isProtectedDataAvailable,
|
|
192
198
|
queryStateOfMindSamples,
|
|
193
199
|
saveStateOfMindSample,
|
|
200
|
+
subscribeToQuantitySamples,
|
|
201
|
+
useSubscribeToQuantitySamples,
|
|
194
202
|
// Hooks
|
|
195
203
|
useMostRecentCategorySample,
|
|
196
204
|
useMostRecentQuantitySample,
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react';
|
|
2
|
+
import { subscribeToQuantitySamples } from '../utils/subscribeToQuantitySamples';
|
|
3
|
+
export function useSubscribeToQuantitySamples(identifier, onChange) {
|
|
4
|
+
const onChangeRef = useRef(onChange);
|
|
5
|
+
useEffect(() => {
|
|
6
|
+
onChangeRef.current = onChange;
|
|
7
|
+
}, [onChange]);
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
const subscription = subscribeToQuantitySamples(identifier, (args) => {
|
|
10
|
+
onChangeRef.current(args);
|
|
11
|
+
});
|
|
12
|
+
return () => {
|
|
13
|
+
subscription.remove();
|
|
14
|
+
};
|
|
15
|
+
}, [identifier]);
|
|
16
|
+
}
|
|
17
|
+
export default useSubscribeToQuantitySamples;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { QuantityTypes } from '../modules';
|
|
2
|
+
import { subscribeToChanges } from './subscribeToChanges';
|
|
3
|
+
export const subscribeToQuantitySamples = (identifier, callback, after) => {
|
|
4
|
+
let anchor;
|
|
5
|
+
const afterDate = after ?? new Date();
|
|
6
|
+
const init = async () => {
|
|
7
|
+
// we need to do an initial query to get a handle for the deletedSamples
|
|
8
|
+
const { newAnchor } = await QuantityTypes.queryQuantitySamplesWithAnchor(identifier, {
|
|
9
|
+
filter: {
|
|
10
|
+
startDate: afterDate,
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
anchor = newAnchor;
|
|
14
|
+
};
|
|
15
|
+
init();
|
|
16
|
+
return subscribeToChanges(identifier, async ({ errorMessage }) => {
|
|
17
|
+
if (errorMessage) {
|
|
18
|
+
return callback({
|
|
19
|
+
typeIdentifier: identifier,
|
|
20
|
+
errorMessage,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
// seems like all deletedSamples are included when no anchor is provided, so we don't want to return those for the first query
|
|
24
|
+
const hadAnchorWhenDoingQuery = !!anchor;
|
|
25
|
+
const { samples, newAnchor, deletedSamples } = await QuantityTypes.queryQuantitySamplesWithAnchor(identifier, {
|
|
26
|
+
anchor,
|
|
27
|
+
filter: {
|
|
28
|
+
startDate: afterDate,
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
anchor = newAnchor;
|
|
32
|
+
const hasNewSamples = samples.length > 0 ||
|
|
33
|
+
(deletedSamples.length > 0 && hadAnchorWhenDoingQuery);
|
|
34
|
+
if (hasNewSamples) {
|
|
35
|
+
callback({
|
|
36
|
+
typeIdentifier: identifier,
|
|
37
|
+
samples,
|
|
38
|
+
anchor: newAnchor,
|
|
39
|
+
deletedSamples: hadAnchorWhenDoingQuery ? deletedSamples : [],
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
};
|
|
@@ -18,7 +18,9 @@ export declare const isHealthDataAvailableAsync: () => Promise<boolean>;
|
|
|
18
18
|
export declare const querySources: (identifier: import("./types").SampleTypeIdentifier) => Promise<readonly import("./specs/SourceProxy.nitro").SourceProxy[]>;
|
|
19
19
|
export declare const requestAuthorization: (toRequest: import("./specs/CoreModule.nitro").AuthDataTypes) => Promise<boolean>;
|
|
20
20
|
export declare const deleteObjects: (objectTypeIdentifier: import("./types").ObjectTypeIdentifier, filter: import("./types").FilterForSamples) => Promise<number>;
|
|
21
|
-
export declare const subscribeToChanges: (
|
|
21
|
+
export declare const subscribeToChanges: (identifier: import("./types").SampleTypeIdentifier, callback: (args: import("./types").OnChangeCallbackArgs) => void) => {
|
|
22
|
+
remove: () => boolean;
|
|
23
|
+
};
|
|
22
24
|
export declare const isProtectedDataAvailable: () => boolean;
|
|
23
25
|
export declare const isObjectTypeAvailable: (objectTypeIdentifier: import("./types").ObjectTypeIdentifier) => boolean;
|
|
24
26
|
export declare const isObjectTypeAvailableAsync: (objectTypeIdentifier: import("./types").ObjectTypeIdentifier) => Promise<boolean>;
|
|
@@ -70,6 +72,11 @@ export declare const getBloodTypeAsync: () => Promise<BloodType>;
|
|
|
70
72
|
export declare const getDateOfBirthAsync: () => Promise<Date | undefined>;
|
|
71
73
|
export declare const getFitzpatrickSkinTypeAsync: () => Promise<FitzpatrickSkinType>;
|
|
72
74
|
export declare const getWheelchairUseAsync: () => Promise<WheelchairUse>;
|
|
73
|
-
|
|
75
|
+
declare const subscribeToQuantitySamples: (identifier: import("./types").QuantityTypeIdentifier, callback: (args: import("./types").OnQuantitySamplesCallback) => void, after?: Date) => {
|
|
76
|
+
remove: () => boolean;
|
|
77
|
+
};
|
|
78
|
+
export { subscribeToQuantitySamples };
|
|
79
|
+
declare const useSubscribeToQuantitySamples: typeof import("./healthkit.ios").useSubscribeToQuantitySamples;
|
|
80
|
+
export { useSubscribeToQuantitySamples };
|
|
74
81
|
declare const _default: typeof ReactNativeHealthkit;
|
|
75
82
|
export default _default;
|
|
@@ -6,11 +6,14 @@ import useMostRecentWorkout from './hooks/useMostRecentWorkout';
|
|
|
6
6
|
import useSources from './hooks/useSources';
|
|
7
7
|
import useStatisticsForQuantity from './hooks/useStatisticsForQuantity';
|
|
8
8
|
import useSubscribeToChanges from './hooks/useSubscribeToChanges';
|
|
9
|
+
import useSubscribeToQuantitySamples from './hooks/useSubscribeToQuantitySamples';
|
|
9
10
|
import type { QuantityTypeIdentifier } from './types/QuantityTypeIdentifier';
|
|
10
11
|
import getMostRecentCategorySample from './utils/getMostRecentCategorySample';
|
|
11
12
|
import getMostRecentQuantitySample from './utils/getMostRecentQuantitySample';
|
|
12
13
|
import getMostRecentWorkout from './utils/getMostRecentWorkout';
|
|
13
14
|
import getPreferredUnit from './utils/getPreferredUnit';
|
|
15
|
+
import { subscribeToChanges } from './utils/subscribeToChanges';
|
|
16
|
+
import { subscribeToQuantitySamples } from './utils/subscribeToQuantitySamples';
|
|
14
17
|
export * from './types';
|
|
15
18
|
declare const currentMajorVersionIOS: number;
|
|
16
19
|
/**
|
|
@@ -21,7 +24,7 @@ type QuantityTypesIOS17Plus = 'HKQuantityTypeIdentifierCyclingCadence' | 'HKQuan
|
|
|
21
24
|
* Available quantity types for iOS versions before iOS 17
|
|
22
25
|
*/
|
|
23
26
|
export type AvailableQuantityTypesBeforeIOS17 = Exclude<QuantityTypeIdentifier, QuantityTypesIOS17Plus>;
|
|
24
|
-
export { getMostRecentCategorySample, getMostRecentQuantitySample, getMostRecentWorkout, getPreferredUnit,
|
|
27
|
+
export { getMostRecentCategorySample, getMostRecentQuantitySample, getMostRecentWorkout, getPreferredUnit, subscribeToChanges, subscribeToQuantitySamples, useHealthkitAuthorization, useIsHealthDataAvailable, useMostRecentCategorySample, useMostRecentQuantitySample, useMostRecentWorkout, useSources, useStatisticsForQuantity, useSubscribeToChanges, useSubscribeToQuantitySamples, };
|
|
25
28
|
/**
|
|
26
29
|
* Available quantity types for iOS 17 and later (all quantity types)
|
|
27
30
|
*/
|
|
@@ -65,13 +68,11 @@ export declare const saveCategorySample: <T extends import("./types").CategoryTy
|
|
|
65
68
|
export declare const saveCorrelationSample: (typeIdentifier: import("./types").CorrelationTypeIdentifier, samples: import("./types").SampleForSaving[], start: Date, end: Date, metadata: import("react-native-nitro-modules").AnyMap) => Promise<boolean>;
|
|
66
69
|
export declare const saveQuantitySample: (identifier: QuantityTypeIdentifier, unit: string, value: number, start: Date, end: Date, metadata: import("react-native-nitro-modules").AnyMap) => Promise<boolean>;
|
|
67
70
|
export declare const saveWorkoutSample: (workoutActivityType: import("./types").WorkoutActivityType, quantities: readonly import("./types").QuantitySampleForSaving[], startDate: Date, endDate: Date, totals?: import("./types").WorkoutTotals, metadata?: import("react-native-nitro-modules").AnyMap) => Promise<import("./specs/WorkoutProxy.nitro").WorkoutProxy>;
|
|
68
|
-
export declare const subscribeToChanges: (typeIdentifier: import("./types").SampleTypeIdentifier, callback: (args: import("./types").OnChangeCallbackArgs) => void) => string;
|
|
69
71
|
export declare const startWatchApp: (workoutConfiguration: import("./types").WorkoutConfiguration) => Promise<boolean>;
|
|
70
72
|
export declare const isProtectedDataAvailable: () => boolean;
|
|
71
73
|
export declare const queryStateOfMindSamples: (options?: import("./types").QueryOptionsWithSortOrder) => Promise<readonly import("./types").StateOfMindSample[]>;
|
|
72
74
|
export declare const saveStateOfMindSample: (date: Date, kind: import("./types").StateOfMindKind, valence: number, labels: readonly import("./types").StateOfMindLabel[], associations: readonly import("./types").StateOfMindAssociation[], metadata?: import("react-native-nitro-modules").AnyMap) => Promise<boolean>;
|
|
73
75
|
export declare const isQuantityCompatibleWithUnit: (identifier: QuantityTypeIdentifier, unit: string) => boolean;
|
|
74
|
-
export declare const unsubscribeQueries: (queryIds: string[]) => number;
|
|
75
76
|
export declare const isObjectTypeAvailable: (objectTypeIdentifier: import("./types").ObjectTypeIdentifier) => boolean;
|
|
76
77
|
export declare const isObjectTypeAvailableAsync: (objectTypeIdentifier: import("./types").ObjectTypeIdentifier) => Promise<boolean>;
|
|
77
78
|
export declare const areObjectTypesAvailable: (objectTypeIdentifiers: readonly import("./types").ObjectTypeIdentifier[]) => Record<string, boolean>;
|
|
@@ -129,8 +130,12 @@ declare const _default: {
|
|
|
129
130
|
saveCorrelationSample: (typeIdentifier: import("./types").CorrelationTypeIdentifier, samples: import("./types").SampleForSaving[], start: Date, end: Date, metadata: import("react-native-nitro-modules").AnyMap) => Promise<boolean>;
|
|
130
131
|
saveQuantitySample: (identifier: QuantityTypeIdentifier, unit: string, value: number, start: Date, end: Date, metadata: import("react-native-nitro-modules").AnyMap) => Promise<boolean>;
|
|
131
132
|
saveWorkoutSample: (workoutActivityType: import("./types").WorkoutActivityType, quantities: readonly import("./types").QuantitySampleForSaving[], startDate: Date, endDate: Date, totals?: import("./types").WorkoutTotals, metadata?: import("react-native-nitro-modules").AnyMap) => Promise<import("./specs/WorkoutProxy.nitro").WorkoutProxy>;
|
|
132
|
-
subscribeToChanges: (
|
|
133
|
-
|
|
133
|
+
subscribeToChanges: (identifier: import("./types").SampleTypeIdentifier, callback: (args: import("./types").OnChangeCallbackArgs) => void) => {
|
|
134
|
+
remove: () => boolean;
|
|
135
|
+
};
|
|
136
|
+
subscribeToQuantitySamples: (identifier: QuantityTypeIdentifier, callback: (args: import("./types").OnQuantitySamplesCallback) => void, after?: Date) => {
|
|
137
|
+
remove: () => boolean;
|
|
138
|
+
};
|
|
134
139
|
startWatchApp: (workoutConfiguration: import("./types").WorkoutConfiguration) => Promise<boolean>;
|
|
135
140
|
isProtectedDataAvailable: () => boolean;
|
|
136
141
|
queryStateOfMindSamples: (options?: import("./types").QueryOptionsWithSortOrder) => Promise<readonly import("./types").StateOfMindSample[]>;
|
|
@@ -139,6 +144,7 @@ declare const _default: {
|
|
|
139
144
|
useMostRecentQuantitySample: typeof useMostRecentQuantitySample;
|
|
140
145
|
useMostRecentWorkout: typeof useMostRecentWorkout;
|
|
141
146
|
useSubscribeToChanges: typeof useSubscribeToChanges;
|
|
147
|
+
useSubscribeToQuantitySamples: typeof useSubscribeToQuantitySamples;
|
|
142
148
|
useHealthkitAuthorization: ({ toWrite, toRead, }: {
|
|
143
149
|
toRead?: readonly import("./types").ObjectTypeIdentifier[];
|
|
144
150
|
toWrite?: readonly import("./types").SampleTypeIdentifierWriteable[];
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { OnQuantitySamplesCallback, QuantityTypeIdentifier } from '../types';
|
|
2
|
+
export declare function useSubscribeToQuantitySamples<TIdentifier extends QuantityTypeIdentifier>(identifier: TIdentifier, onChange: (args: OnQuantitySamplesCallback) => void): void;
|
|
3
|
+
export default useSubscribeToQuantitySamples;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { QuantitySample } from './QuantitySample';
|
|
2
|
+
import type { QuantityTypeIdentifier } from './QuantityTypeIdentifier';
|
|
3
|
+
import type { DeletedSample, SampleTypeIdentifier } from './Shared';
|
|
2
4
|
export interface EmitterSubscription {
|
|
3
5
|
remove: () => void;
|
|
4
6
|
}
|
|
@@ -6,3 +8,14 @@ export interface OnChangeCallbackArgs {
|
|
|
6
8
|
readonly typeIdentifier: SampleTypeIdentifier;
|
|
7
9
|
readonly errorMessage?: string;
|
|
8
10
|
}
|
|
11
|
+
export interface OnQuantitySamplesCallbackError {
|
|
12
|
+
readonly typeIdentifier: QuantityTypeIdentifier;
|
|
13
|
+
readonly errorMessage: string;
|
|
14
|
+
}
|
|
15
|
+
export interface OnQuantitySamplesCallbackSuccess {
|
|
16
|
+
readonly typeIdentifier: QuantityTypeIdentifier;
|
|
17
|
+
readonly anchor: string;
|
|
18
|
+
readonly samples: readonly QuantitySample[];
|
|
19
|
+
readonly deletedSamples: readonly DeletedSample[];
|
|
20
|
+
}
|
|
21
|
+
export type OnQuantitySamplesCallback = OnQuantitySamplesCallbackError | OnQuantitySamplesCallbackSuccess;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { QuantityTypeIdentifier } from '../types';
|
|
2
|
+
import type { OnQuantitySamplesCallback } from '../types/Subscriptions';
|
|
3
|
+
export declare const subscribeToQuantitySamples: (identifier: QuantityTypeIdentifier, callback: (args: OnQuantitySamplesCallback) => void, after?: Date) => {
|
|
4
|
+
remove: () => boolean;
|
|
5
|
+
};
|
package/package.json
CHANGED
package/src/healthkit.ios.ts
CHANGED
|
@@ -7,6 +7,7 @@ import useMostRecentWorkout from './hooks/useMostRecentWorkout'
|
|
|
7
7
|
import useSources from './hooks/useSources'
|
|
8
8
|
import useStatisticsForQuantity from './hooks/useStatisticsForQuantity'
|
|
9
9
|
import useSubscribeToChanges from './hooks/useSubscribeToChanges'
|
|
10
|
+
import useSubscribeToQuantitySamples from './hooks/useSubscribeToQuantitySamples'
|
|
10
11
|
import {
|
|
11
12
|
CategoryTypes,
|
|
12
13
|
Characteristics,
|
|
@@ -23,6 +24,8 @@ import getMostRecentCategorySample from './utils/getMostRecentCategorySample'
|
|
|
23
24
|
import getMostRecentQuantitySample from './utils/getMostRecentQuantitySample'
|
|
24
25
|
import getMostRecentWorkout from './utils/getMostRecentWorkout'
|
|
25
26
|
import getPreferredUnit from './utils/getPreferredUnit'
|
|
27
|
+
import { subscribeToChanges } from './utils/subscribeToChanges'
|
|
28
|
+
import { subscribeToQuantitySamples } from './utils/subscribeToQuantitySamples'
|
|
26
29
|
|
|
27
30
|
export * from './types'
|
|
28
31
|
|
|
@@ -53,14 +56,17 @@ export {
|
|
|
53
56
|
getMostRecentQuantitySample,
|
|
54
57
|
getMostRecentWorkout,
|
|
55
58
|
getPreferredUnit,
|
|
59
|
+
subscribeToChanges,
|
|
60
|
+
subscribeToQuantitySamples,
|
|
61
|
+
useHealthkitAuthorization,
|
|
62
|
+
useIsHealthDataAvailable,
|
|
56
63
|
useMostRecentCategorySample,
|
|
57
64
|
useMostRecentQuantitySample,
|
|
58
65
|
useMostRecentWorkout,
|
|
59
|
-
useSubscribeToChanges,
|
|
60
|
-
useHealthkitAuthorization,
|
|
61
|
-
useIsHealthDataAvailable,
|
|
62
66
|
useSources,
|
|
63
67
|
useStatisticsForQuantity,
|
|
68
|
+
useSubscribeToChanges,
|
|
69
|
+
useSubscribeToQuantitySamples,
|
|
64
70
|
}
|
|
65
71
|
|
|
66
72
|
/**
|
|
@@ -138,7 +144,6 @@ export const saveCorrelationSample =
|
|
|
138
144
|
export const saveQuantitySample =
|
|
139
145
|
QuantityTypes.saveQuantitySample.bind(QuantityTypes)
|
|
140
146
|
export const saveWorkoutSample = Workouts.saveWorkoutSample.bind(Workouts)
|
|
141
|
-
export const subscribeToChanges = Core.subscribeToObserverQuery.bind(Core)
|
|
142
147
|
export const startWatchApp =
|
|
143
148
|
Workouts.startWatchAppWithWorkoutConfiguration.bind(Workouts)
|
|
144
149
|
export const isProtectedDataAvailable = Core.isProtectedDataAvailable.bind(Core)
|
|
@@ -148,7 +153,6 @@ export const saveStateOfMindSample =
|
|
|
148
153
|
StateOfMind.saveStateOfMindSample.bind(StateOfMind)
|
|
149
154
|
export const isQuantityCompatibleWithUnit =
|
|
150
155
|
QuantityTypes.isQuantityCompatibleWithUnit.bind(QuantityTypes)
|
|
151
|
-
export const unsubscribeQueries = Core.unsubscribeQueries.bind(Core)
|
|
152
156
|
|
|
153
157
|
export const isObjectTypeAvailable = Core.isObjectTypeAvailable.bind(Core)
|
|
154
158
|
export const isObjectTypeAvailableAsync =
|
|
@@ -217,7 +221,7 @@ export default {
|
|
|
217
221
|
saveQuantitySample,
|
|
218
222
|
saveWorkoutSample,
|
|
219
223
|
subscribeToChanges,
|
|
220
|
-
|
|
224
|
+
subscribeToQuantitySamples,
|
|
221
225
|
startWatchApp,
|
|
222
226
|
isProtectedDataAvailable,
|
|
223
227
|
queryStateOfMindSamples,
|
|
@@ -228,6 +232,7 @@ export default {
|
|
|
228
232
|
useMostRecentQuantitySample,
|
|
229
233
|
useMostRecentWorkout,
|
|
230
234
|
useSubscribeToChanges,
|
|
235
|
+
useSubscribeToQuantitySamples,
|
|
231
236
|
useHealthkitAuthorization,
|
|
232
237
|
useIsHealthDataAvailable,
|
|
233
238
|
useSources,
|
package/src/healthkit.ts
CHANGED
|
@@ -97,7 +97,9 @@ export const deleteObjects = UnavailableFnFromModule(
|
|
|
97
97
|
)
|
|
98
98
|
export const subscribeToChanges = UnavailableFnFromModule(
|
|
99
99
|
'subscribeToChanges',
|
|
100
|
-
|
|
100
|
+
{
|
|
101
|
+
remove: () => false,
|
|
102
|
+
},
|
|
101
103
|
) // Mocking the observer query UUID
|
|
102
104
|
export const isProtectedDataAvailable = UnavailableFnFromModule(
|
|
103
105
|
'isProtectedDataAvailable',
|
|
@@ -363,18 +365,27 @@ export const getWheelchairUseAsync = UnavailableFnFromModule(
|
|
|
363
365
|
Promise.resolve(WheelchairUse.notSet),
|
|
364
366
|
)
|
|
365
367
|
|
|
366
|
-
|
|
367
|
-
'
|
|
368
|
-
|
|
369
|
-
)
|
|
368
|
+
const subscribeToQuantitySamples = UnavailableFnFromModule(
|
|
369
|
+
'subscribeToQuantitySamples',
|
|
370
|
+
{
|
|
371
|
+
remove: () => false,
|
|
372
|
+
},
|
|
373
|
+
) // Mocking the observer query UUID
|
|
374
|
+
|
|
375
|
+
export { subscribeToQuantitySamples }
|
|
376
|
+
|
|
377
|
+
const useSubscribeToQuantitySamples = UnavailableFnFromModule(
|
|
378
|
+
'useSubscribeToQuantitySamples',
|
|
379
|
+
undefined,
|
|
380
|
+
) // Mocking callback structure
|
|
370
381
|
|
|
382
|
+
export { useSubscribeToQuantitySamples }
|
|
371
383
|
// --- Default Export ---
|
|
372
384
|
// This attempts to match the structure of the default export from index.ios.ts
|
|
373
385
|
const HealthkitModule = {
|
|
374
386
|
// All named exports are also part of the default export object
|
|
375
387
|
authorizationStatusFor,
|
|
376
388
|
isObjectTypeAvailable,
|
|
377
|
-
unsubscribeQueries,
|
|
378
389
|
isObjectTypeAvailableAsync,
|
|
379
390
|
areObjectTypesAvailable,
|
|
380
391
|
areObjectTypesAvailableAsync,
|
|
@@ -420,6 +431,8 @@ const HealthkitModule = {
|
|
|
420
431
|
isProtectedDataAvailable,
|
|
421
432
|
queryStateOfMindSamples,
|
|
422
433
|
saveStateOfMindSample,
|
|
434
|
+
subscribeToQuantitySamples,
|
|
435
|
+
useSubscribeToQuantitySamples,
|
|
423
436
|
|
|
424
437
|
// Hooks
|
|
425
438
|
useMostRecentCategorySample,
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react'
|
|
2
|
+
import type {
|
|
3
|
+
OnQuantitySamplesCallback,
|
|
4
|
+
QuantityTypeIdentifier,
|
|
5
|
+
} from '../types'
|
|
6
|
+
import { subscribeToQuantitySamples } from '../utils/subscribeToQuantitySamples'
|
|
7
|
+
|
|
8
|
+
export function useSubscribeToQuantitySamples<
|
|
9
|
+
TIdentifier extends QuantityTypeIdentifier,
|
|
10
|
+
>(
|
|
11
|
+
identifier: TIdentifier,
|
|
12
|
+
onChange: (args: OnQuantitySamplesCallback) => void,
|
|
13
|
+
): void {
|
|
14
|
+
const onChangeRef = useRef(onChange)
|
|
15
|
+
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
onChangeRef.current = onChange
|
|
18
|
+
}, [onChange])
|
|
19
|
+
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
const subscription = subscribeToQuantitySamples(identifier, (args) => {
|
|
22
|
+
onChangeRef.current(args)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
return () => {
|
|
26
|
+
subscription.remove()
|
|
27
|
+
}
|
|
28
|
+
}, [identifier])
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default useSubscribeToQuantitySamples
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { QuantitySample } from './QuantitySample'
|
|
2
|
+
import type { QuantityTypeIdentifier } from './QuantityTypeIdentifier'
|
|
3
|
+
import type { DeletedSample, SampleTypeIdentifier } from './Shared'
|
|
2
4
|
|
|
3
5
|
export interface EmitterSubscription {
|
|
4
6
|
remove: () => void
|
|
@@ -8,3 +10,19 @@ export interface OnChangeCallbackArgs {
|
|
|
8
10
|
readonly typeIdentifier: SampleTypeIdentifier
|
|
9
11
|
readonly errorMessage?: string
|
|
10
12
|
}
|
|
13
|
+
|
|
14
|
+
export interface OnQuantitySamplesCallbackError {
|
|
15
|
+
readonly typeIdentifier: QuantityTypeIdentifier
|
|
16
|
+
readonly errorMessage: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface OnQuantitySamplesCallbackSuccess {
|
|
20
|
+
readonly typeIdentifier: QuantityTypeIdentifier
|
|
21
|
+
readonly anchor: string
|
|
22
|
+
readonly samples: readonly QuantitySample[]
|
|
23
|
+
readonly deletedSamples: readonly DeletedSample[]
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export type OnQuantitySamplesCallback =
|
|
27
|
+
| OnQuantitySamplesCallbackError
|
|
28
|
+
| OnQuantitySamplesCallbackSuccess
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { QuantityTypes } from '../modules'
|
|
2
|
+
import type { QuantityTypeIdentifier } from '../types'
|
|
3
|
+
import type { OnQuantitySamplesCallback } from '../types/Subscriptions'
|
|
4
|
+
import { subscribeToChanges } from './subscribeToChanges'
|
|
5
|
+
|
|
6
|
+
export const subscribeToQuantitySamples = (
|
|
7
|
+
identifier: QuantityTypeIdentifier,
|
|
8
|
+
callback: (args: OnQuantitySamplesCallback) => void,
|
|
9
|
+
after?: Date,
|
|
10
|
+
) => {
|
|
11
|
+
let anchor: string | undefined
|
|
12
|
+
const afterDate = after ?? new Date()
|
|
13
|
+
|
|
14
|
+
const init = async () => {
|
|
15
|
+
// we need to do an initial query to get a handle for the deletedSamples
|
|
16
|
+
const { newAnchor } = await QuantityTypes.queryQuantitySamplesWithAnchor(
|
|
17
|
+
identifier,
|
|
18
|
+
{
|
|
19
|
+
filter: {
|
|
20
|
+
startDate: afterDate,
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
)
|
|
24
|
+
anchor = newAnchor
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
init()
|
|
28
|
+
|
|
29
|
+
return subscribeToChanges(identifier, async ({ errorMessage }) => {
|
|
30
|
+
if (errorMessage) {
|
|
31
|
+
return callback({
|
|
32
|
+
typeIdentifier: identifier,
|
|
33
|
+
errorMessage,
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// seems like all deletedSamples are included when no anchor is provided, so we don't want to return those for the first query
|
|
38
|
+
const hadAnchorWhenDoingQuery = !!anchor
|
|
39
|
+
|
|
40
|
+
const { samples, newAnchor, deletedSamples } =
|
|
41
|
+
await QuantityTypes.queryQuantitySamplesWithAnchor(identifier, {
|
|
42
|
+
anchor,
|
|
43
|
+
filter: {
|
|
44
|
+
startDate: afterDate,
|
|
45
|
+
},
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
anchor = newAnchor
|
|
49
|
+
|
|
50
|
+
const hasNewSamples =
|
|
51
|
+
samples.length > 0 ||
|
|
52
|
+
(deletedSamples.length > 0 && hadAnchorWhenDoingQuery)
|
|
53
|
+
|
|
54
|
+
if (hasNewSamples) {
|
|
55
|
+
callback({
|
|
56
|
+
typeIdentifier: identifier,
|
|
57
|
+
samples,
|
|
58
|
+
anchor: newAnchor,
|
|
59
|
+
deletedSamples: hadAnchorWhenDoingQuery ? deletedSamples : [],
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
}
|