@kingstinct/react-native-healthkit 4.1.1 → 4.4.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 +1 -1
- package/ios/ReactNativeHealthkit.m +15 -10
- package/ios/ReactNativeHealthkit.swift +365 -177
- package/lib/commonjs/index.ios.js +104 -106
- package/lib/commonjs/index.ios.js.map +1 -1
- package/lib/commonjs/index.js +11 -10
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/native-types.js +25 -1
- package/lib/commonjs/native-types.js.map +1 -1
- package/lib/commonjs/types.js +4 -0
- package/lib/commonjs/types.js.map +1 -1
- package/lib/example/App.js +197 -0
- package/lib/index.ios.js +310 -0
- package/lib/index.js +44 -0
- package/lib/module/index.ios.js +104 -106
- package/lib/module/index.ios.js.map +1 -1
- package/lib/module/index.js +4 -3
- package/lib/module/index.js.map +1 -1
- package/lib/module/native-types.js +20 -1
- package/lib/module/native-types.js.map +1 -1
- package/lib/module/types.js +1 -1
- package/lib/module/types.js.map +1 -1
- package/lib/native-types.js +447 -0
- package/lib/src/index.ios.js +314 -0
- package/lib/src/index.js +45 -0
- package/lib/src/native-types.js +453 -0
- package/lib/src/types.js +1 -0
- package/lib/types.js +1 -0
- package/lib/typescript/src/index.d.ts +1 -1
- package/lib/typescript/src/index.ios.d.ts +1 -1
- package/lib/typescript/src/native-types.d.ts +142 -108
- package/lib/typescript/src/types.d.ts +80 -78
- package/package.json +25 -39
- package/src/index.ios.tsx +260 -264
- package/src/index.tsx +14 -13
- package/src/native-types.ts +213 -179
- package/src/types.ts +106 -100
- package/ios/ReactNativeHealthkit.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -4
- package/ios/ReactNativeHealthkit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
- package/ios/ReactNativeHealthkit.xcodeproj/project.xcworkspace/xcuserdata/robertherber.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/ios/ReactNativeHealthkit.xcodeproj/xcuserdata/robertherber.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
package/src/index.ios.tsx
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useCallback, useEffect, useState } from 'react'
|
|
2
|
+
|
|
2
3
|
import Native, {
|
|
3
4
|
EventEmitter,
|
|
5
|
+
HKQuantityTypeIdentifier,
|
|
6
|
+
HKUnit,
|
|
7
|
+
} from './native-types'
|
|
8
|
+
|
|
9
|
+
import type {
|
|
4
10
|
HKCategorySampleRaw,
|
|
5
11
|
HKCategoryTypeIdentifier,
|
|
6
12
|
HKCategoryValueForIdentifier,
|
|
@@ -8,14 +14,14 @@ import Native, {
|
|
|
8
14
|
HKCorrelationRaw,
|
|
9
15
|
HKCorrelationTypeIdentifier,
|
|
10
16
|
HKQuantitySampleRaw,
|
|
11
|
-
HKQuantityTypeIdentifier,
|
|
12
17
|
HKSampleTypeIdentifier,
|
|
13
|
-
HKUnit,
|
|
14
18
|
HKUnitSI,
|
|
15
19
|
HKUnitSIPrefix,
|
|
16
20
|
HKWorkoutRaw,
|
|
17
21
|
MetadataMapperForCategoryIdentifier,
|
|
18
|
-
|
|
22
|
+
ReadPermissions,
|
|
23
|
+
WritePermissions,
|
|
24
|
+
} from './native-types'
|
|
19
25
|
import type {
|
|
20
26
|
GenericQueryOptions,
|
|
21
27
|
GetMostRecentCategorySampleFn,
|
|
@@ -23,6 +29,7 @@ import type {
|
|
|
23
29
|
GetMostRecentWorkoutFn,
|
|
24
30
|
GetPreferredUnitFn,
|
|
25
31
|
GetPreferredUnitsFn,
|
|
32
|
+
GetWorkoutRoutesFn,
|
|
26
33
|
HKCategorySample,
|
|
27
34
|
HKCorrelation,
|
|
28
35
|
HKQuantitySample,
|
|
@@ -37,76 +44,73 @@ import type {
|
|
|
37
44
|
SaveQuantitySampleFn,
|
|
38
45
|
SaveWorkoutSampleFn,
|
|
39
46
|
SubscribeToChangesFn,
|
|
40
|
-
} from './types'
|
|
47
|
+
} from './types'
|
|
41
48
|
|
|
42
49
|
const getPreferredUnit: GetPreferredUnitFn = async (type) => {
|
|
43
|
-
const [unit] = await getPreferredUnits([type])
|
|
44
|
-
return unit
|
|
45
|
-
}
|
|
50
|
+
const [unit] = await getPreferredUnits([type])
|
|
51
|
+
return unit
|
|
52
|
+
}
|
|
46
53
|
|
|
47
54
|
const ensureUnit = async <TUnit extends HKUnit>(
|
|
48
55
|
type: HKQuantityTypeIdentifier,
|
|
49
|
-
providedUnit?: TUnit
|
|
56
|
+
providedUnit?: TUnit,
|
|
50
57
|
) => {
|
|
51
58
|
if (providedUnit) {
|
|
52
|
-
return providedUnit
|
|
59
|
+
return providedUnit
|
|
53
60
|
}
|
|
54
|
-
const unit = await Native.getPreferredUnits([type])
|
|
55
|
-
return unit[type] as TUnit
|
|
56
|
-
}
|
|
61
|
+
const unit = await Native.getPreferredUnits([type])
|
|
62
|
+
return unit[type] as TUnit
|
|
63
|
+
}
|
|
57
64
|
|
|
58
65
|
function deserializeSample<
|
|
59
66
|
TIdentifier extends HKQuantityTypeIdentifier,
|
|
60
67
|
TUnit extends HKUnit
|
|
61
68
|
>(
|
|
62
|
-
sample: HKQuantitySampleRaw<TIdentifier, TUnit
|
|
69
|
+
sample: HKQuantitySampleRaw<TIdentifier, TUnit>,
|
|
63
70
|
): HKQuantitySample<TIdentifier, TUnit> {
|
|
64
71
|
return {
|
|
65
72
|
...sample,
|
|
66
73
|
startDate: new Date(sample.startDate),
|
|
67
74
|
endDate: new Date(sample.endDate),
|
|
68
|
-
}
|
|
75
|
+
}
|
|
69
76
|
}
|
|
70
77
|
|
|
71
78
|
function deserializeWorkout<TEnergy extends HKUnit, TDistance extends HKUnit>(
|
|
72
|
-
sample: HKWorkoutRaw<TEnergy, TDistance
|
|
79
|
+
sample: HKWorkoutRaw<TEnergy, TDistance>,
|
|
73
80
|
): HKWorkout<TEnergy, TDistance> {
|
|
74
81
|
return {
|
|
75
82
|
...sample,
|
|
76
83
|
startDate: new Date(sample.startDate),
|
|
77
84
|
endDate: new Date(sample.endDate),
|
|
78
|
-
}
|
|
85
|
+
}
|
|
79
86
|
}
|
|
80
87
|
|
|
81
88
|
const deserializCategorySample = <T extends HKCategoryTypeIdentifier>(
|
|
82
|
-
sample: HKCategorySampleRaw<T
|
|
83
|
-
): HKCategorySample<T> => {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
};
|
|
89
|
-
};
|
|
89
|
+
sample: HKCategorySampleRaw<T>,
|
|
90
|
+
): HKCategorySample<T> => ({
|
|
91
|
+
...sample,
|
|
92
|
+
startDate: new Date(sample.startDate),
|
|
93
|
+
endDate: new Date(sample.endDate),
|
|
94
|
+
})
|
|
90
95
|
|
|
91
|
-
const serializeDate = (date?: Date | null): string =>
|
|
92
|
-
return date ? date.toISOString() : new Date(0).toISOString();
|
|
93
|
-
};
|
|
96
|
+
const serializeDate = (date?: Date | null): string => (date ? date.toISOString() : new Date(0).toISOString())
|
|
94
97
|
|
|
95
98
|
const prepareOptions = (options: GenericQueryOptions) => {
|
|
96
|
-
const limit =
|
|
97
|
-
|
|
98
|
-
const
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
99
|
+
const limit = !options.limit || options.limit === Infinity ? 0 : options.limit
|
|
100
|
+
const ascending = options.ascending ?? limit === 0
|
|
101
|
+
const from = serializeDate(options.from)
|
|
102
|
+
const to = serializeDate(options.to)
|
|
103
|
+
return {
|
|
104
|
+
limit, ascending, from, to,
|
|
105
|
+
}
|
|
106
|
+
}
|
|
103
107
|
|
|
104
108
|
const queryQuantitySamples: QueryQuantitySamplesFn = async (
|
|
105
109
|
identifier,
|
|
106
|
-
options
|
|
110
|
+
options,
|
|
107
111
|
) => {
|
|
108
|
-
const unit = await ensureUnit(identifier, options.unit)
|
|
109
|
-
const opts = prepareOptions(options)
|
|
112
|
+
const unit = await ensureUnit(identifier, options.unit)
|
|
113
|
+
const opts = prepareOptions(options)
|
|
110
114
|
|
|
111
115
|
const quantitySamples = await Native.queryQuantitySamples(
|
|
112
116
|
identifier,
|
|
@@ -114,121 +118,153 @@ const queryQuantitySamples: QueryQuantitySamplesFn = async (
|
|
|
114
118
|
opts.from,
|
|
115
119
|
opts.to,
|
|
116
120
|
opts.limit,
|
|
117
|
-
opts.ascending
|
|
118
|
-
)
|
|
121
|
+
opts.ascending,
|
|
122
|
+
)
|
|
119
123
|
|
|
120
|
-
return quantitySamples.map(deserializeSample)
|
|
121
|
-
}
|
|
124
|
+
return quantitySamples.map(deserializeSample)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async function getPreferredUnitsTyped<
|
|
128
|
+
TEnergy extends HKUnit,
|
|
129
|
+
TDistance extends HKUnit
|
|
130
|
+
>(options?: { readonly energyUnit?: TEnergy; readonly distanceUnit?: TDistance }) {
|
|
131
|
+
let energyUnit = options?.energyUnit
|
|
132
|
+
let distanceUnit = options?.distanceUnit
|
|
133
|
+
if (!energyUnit || !distanceUnit) {
|
|
134
|
+
const units = await Native.getPreferredUnits([
|
|
135
|
+
HKQuantityTypeIdentifier.distanceWalkingRunning,
|
|
136
|
+
HKQuantityTypeIdentifier.activeEnergyBurned,
|
|
137
|
+
])
|
|
138
|
+
if (!energyUnit) {
|
|
139
|
+
energyUnit = units[HKQuantityTypeIdentifier.distanceWalkingRunning] as
|
|
140
|
+
| TEnergy
|
|
141
|
+
| undefined
|
|
142
|
+
}
|
|
143
|
+
if (!distanceUnit) {
|
|
144
|
+
distanceUnit = units[HKQuantityTypeIdentifier.activeEnergyBurned] as
|
|
145
|
+
| TDistance
|
|
146
|
+
| undefined
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (!energyUnit) {
|
|
150
|
+
energyUnit = HKUnit.Kilocalories as TEnergy
|
|
151
|
+
}
|
|
152
|
+
if (!distanceUnit) {
|
|
153
|
+
distanceUnit = HKUnit.Meters as TDistance
|
|
154
|
+
}
|
|
155
|
+
return { energyUnit, distanceUnit }
|
|
156
|
+
}
|
|
122
157
|
|
|
123
158
|
const subscribeToChanges: SubscribeToChangesFn = async (
|
|
124
159
|
identifier,
|
|
125
|
-
callback
|
|
160
|
+
callback,
|
|
126
161
|
) => {
|
|
127
162
|
const subscription = EventEmitter.addListener(
|
|
128
163
|
'onChange',
|
|
129
164
|
({ typeIdentifier }) => {
|
|
130
165
|
if (typeIdentifier === identifier) {
|
|
131
|
-
callback()
|
|
166
|
+
callback()
|
|
132
167
|
}
|
|
133
|
-
}
|
|
134
|
-
)
|
|
168
|
+
},
|
|
169
|
+
)
|
|
135
170
|
|
|
136
171
|
const queryId = await Native.subscribeToObserverQuery(identifier).catch(
|
|
137
|
-
(error) => {
|
|
138
|
-
subscription.remove()
|
|
139
|
-
return Promise.reject(error)
|
|
140
|
-
}
|
|
141
|
-
)
|
|
142
|
-
|
|
143
|
-
return () => {
|
|
144
|
-
subscription.remove()
|
|
145
|
-
return Native.unsubscribeQuery(queryId)
|
|
146
|
-
}
|
|
147
|
-
}
|
|
172
|
+
async (error) => {
|
|
173
|
+
subscription.remove()
|
|
174
|
+
return Promise.reject(error)
|
|
175
|
+
},
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
return async () => {
|
|
179
|
+
subscription.remove()
|
|
180
|
+
return Native.unsubscribeQuery(queryId)
|
|
181
|
+
}
|
|
182
|
+
}
|
|
148
183
|
|
|
149
184
|
const getMostRecentQuantitySample: GetMostRecentQuantitySampleFn = async (
|
|
150
185
|
identifier,
|
|
151
|
-
unit
|
|
186
|
+
unit,
|
|
152
187
|
) => {
|
|
153
188
|
const samples = await queryQuantitySamples(identifier, {
|
|
154
189
|
limit: 1,
|
|
155
|
-
unit
|
|
156
|
-
})
|
|
157
|
-
return samples[0]
|
|
158
|
-
}
|
|
190
|
+
unit,
|
|
191
|
+
})
|
|
192
|
+
return samples[0]
|
|
193
|
+
}
|
|
159
194
|
|
|
160
195
|
function useMostRecentWorkout<
|
|
161
196
|
TEnergy extends HKUnit,
|
|
162
197
|
TDistance extends HKUnit
|
|
163
|
-
>(options?: { energyUnit?: TEnergy; distanceUnit?: TDistance }) {
|
|
198
|
+
>(options?: { readonly energyUnit?: TEnergy; readonly distanceUnit?: TDistance }) {
|
|
164
199
|
const [workout, setWorkout] = useState<HKWorkout<TEnergy, TDistance> | null>(
|
|
165
|
-
null
|
|
166
|
-
)
|
|
200
|
+
null,
|
|
201
|
+
)
|
|
167
202
|
useEffect(() => {
|
|
168
|
-
let cancelSubscription: (() => Promise<boolean>) | undefined
|
|
203
|
+
let cancelSubscription: (() => Promise<boolean>) | undefined
|
|
169
204
|
|
|
170
205
|
const init = async () => {
|
|
171
206
|
const { energyUnit, distanceUnit } = await getPreferredUnitsTyped(
|
|
172
|
-
options
|
|
173
|
-
)
|
|
207
|
+
options,
|
|
208
|
+
)
|
|
174
209
|
|
|
175
210
|
cancelSubscription = await subscribeToChanges(
|
|
176
211
|
'HKWorkoutTypeIdentifier',
|
|
177
|
-
() => {
|
|
178
|
-
getMostRecentWorkout({ energyUnit, distanceUnit })
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
212
|
+
async () => {
|
|
213
|
+
const w = await getMostRecentWorkout({ energyUnit, distanceUnit })
|
|
214
|
+
setWorkout(w)
|
|
215
|
+
},
|
|
216
|
+
)
|
|
217
|
+
}
|
|
218
|
+
void init()
|
|
183
219
|
return () => {
|
|
184
|
-
|
|
185
|
-
}
|
|
186
|
-
}, [options])
|
|
187
|
-
return workout
|
|
220
|
+
void cancelSubscription?.()
|
|
221
|
+
}
|
|
222
|
+
}, [options])
|
|
223
|
+
return workout
|
|
188
224
|
}
|
|
189
225
|
|
|
190
226
|
const getMostRecentCategorySample: GetMostRecentCategorySampleFn = async (
|
|
191
|
-
identifier
|
|
227
|
+
identifier,
|
|
192
228
|
) => {
|
|
193
229
|
const samples = await queryCategorySamples(identifier, {
|
|
194
230
|
limit: 1,
|
|
195
231
|
ascending: false,
|
|
196
|
-
})
|
|
197
|
-
|
|
198
|
-
return samples[0];
|
|
199
|
-
};
|
|
200
|
-
|
|
201
|
-
function useMostRecentCategorySample<
|
|
202
|
-
TCategory extends HKCategoryTypeIdentifier
|
|
203
|
-
>(identifier: TCategory) {
|
|
204
|
-
const [category, setCategory] = useState<HKCategorySample<TCategory> | null>(
|
|
205
|
-
null
|
|
206
|
-
);
|
|
207
|
-
const updater = useCallback(() => {
|
|
208
|
-
getMostRecentCategorySample(identifier).then(setCategory);
|
|
209
|
-
}, [identifier]);
|
|
232
|
+
})
|
|
210
233
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
return category;
|
|
234
|
+
return samples[0]
|
|
214
235
|
}
|
|
215
236
|
|
|
216
237
|
function useSubscribeToChanges<TIdentifier extends HKSampleTypeIdentifier>(
|
|
217
238
|
identifier: TIdentifier,
|
|
218
|
-
onChange: () => void
|
|
239
|
+
onChange: () => void,
|
|
219
240
|
): void {
|
|
220
241
|
useEffect(() => {
|
|
221
|
-
let cancelSubscription: (() => Promise<boolean>) | undefined
|
|
242
|
+
let cancelSubscription: (() => Promise<boolean>) | undefined
|
|
222
243
|
|
|
223
244
|
const init = async () => {
|
|
224
|
-
cancelSubscription = await subscribeToChanges(identifier, onChange)
|
|
225
|
-
}
|
|
226
|
-
init()
|
|
245
|
+
cancelSubscription = await subscribeToChanges(identifier, onChange)
|
|
246
|
+
}
|
|
247
|
+
void init()
|
|
227
248
|
|
|
228
249
|
return () => {
|
|
229
|
-
|
|
230
|
-
}
|
|
231
|
-
}, [identifier, onChange])
|
|
250
|
+
void cancelSubscription?.()
|
|
251
|
+
}
|
|
252
|
+
}, [identifier, onChange])
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function useMostRecentCategorySample<
|
|
256
|
+
TCategory extends HKCategoryTypeIdentifier
|
|
257
|
+
>(identifier: TCategory) {
|
|
258
|
+
const [category, setCategory] = useState<HKCategorySample<TCategory> | null>(
|
|
259
|
+
null,
|
|
260
|
+
)
|
|
261
|
+
const updater = useCallback(() => {
|
|
262
|
+
void getMostRecentCategorySample(identifier).then(setCategory)
|
|
263
|
+
}, [identifier])
|
|
264
|
+
|
|
265
|
+
useSubscribeToChanges(identifier, updater)
|
|
266
|
+
|
|
267
|
+
return category
|
|
232
268
|
}
|
|
233
269
|
|
|
234
270
|
function useMostRecentQuantitySample<
|
|
@@ -236,41 +272,40 @@ function useMostRecentQuantitySample<
|
|
|
236
272
|
TUnit extends HKUnit = HKUnit
|
|
237
273
|
>(identifier: TIdentifier, unit?: TUnit) {
|
|
238
274
|
const [lastSample, setLastSample] = useState<HKQuantitySample<
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
> | null>(null)
|
|
275
|
+
TIdentifier,
|
|
276
|
+
TUnit
|
|
277
|
+
> | null>(null)
|
|
242
278
|
|
|
243
279
|
useEffect(() => {
|
|
244
|
-
let cancelSubscription: (() => Promise<boolean>) | undefined
|
|
280
|
+
let cancelSubscription: (() => Promise<boolean>) | undefined
|
|
245
281
|
|
|
246
282
|
const init = async () => {
|
|
247
|
-
const actualUnit = await ensureUnit(identifier, unit)
|
|
283
|
+
const actualUnit = await ensureUnit(identifier, unit)
|
|
248
284
|
|
|
249
|
-
cancelSubscription = await subscribeToChanges(identifier, () => {
|
|
250
|
-
getMostRecentQuantitySample(identifier, actualUnit)
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
init();
|
|
285
|
+
cancelSubscription = await subscribeToChanges(identifier, async () => {
|
|
286
|
+
const value = await getMostRecentQuantitySample(identifier, actualUnit)
|
|
287
|
+
setLastSample(value)
|
|
288
|
+
})
|
|
289
|
+
}
|
|
290
|
+
void init()
|
|
256
291
|
|
|
257
292
|
return () => {
|
|
258
|
-
|
|
259
|
-
}
|
|
260
|
-
}, [identifier, unit])
|
|
293
|
+
void cancelSubscription?.()
|
|
294
|
+
}
|
|
295
|
+
}, [identifier, unit])
|
|
261
296
|
|
|
262
|
-
return lastSample
|
|
297
|
+
return lastSample
|
|
263
298
|
}
|
|
264
299
|
|
|
265
|
-
const saveQuantitySample: SaveQuantitySampleFn = (
|
|
300
|
+
const saveQuantitySample: SaveQuantitySampleFn = async (
|
|
266
301
|
identifier,
|
|
267
302
|
unit,
|
|
268
303
|
value,
|
|
269
|
-
options
|
|
304
|
+
options,
|
|
270
305
|
) => {
|
|
271
|
-
const start = options?.start || options?.end || new Date()
|
|
272
|
-
const end = options?.end || options?.start || new Date()
|
|
273
|
-
const metadata = options?.metadata || {}
|
|
306
|
+
const start = options?.start || options?.end || new Date()
|
|
307
|
+
const end = options?.end || options?.start || new Date()
|
|
308
|
+
const metadata = options?.metadata || {}
|
|
274
309
|
|
|
275
310
|
return Native.saveQuantitySample(
|
|
276
311
|
identifier,
|
|
@@ -278,133 +313,91 @@ const saveQuantitySample: SaveQuantitySampleFn = (
|
|
|
278
313
|
value,
|
|
279
314
|
start.toISOString(),
|
|
280
315
|
end.toISOString(),
|
|
281
|
-
metadata
|
|
282
|
-
)
|
|
283
|
-
}
|
|
316
|
+
metadata,
|
|
317
|
+
)
|
|
318
|
+
}
|
|
284
319
|
|
|
285
320
|
const queryStatisticsForQuantity: QueryStatisticsForQuantityFn = async (
|
|
286
321
|
identifier,
|
|
287
322
|
options,
|
|
288
323
|
from,
|
|
289
324
|
to,
|
|
290
|
-
unit
|
|
325
|
+
unit,
|
|
291
326
|
) => {
|
|
292
|
-
const actualUnit = await ensureUnit(identifier, unit)
|
|
293
|
-
const toDate = to || new Date()
|
|
294
|
-
const {
|
|
295
|
-
mostRecentQuantityDateInterval,
|
|
296
|
-
...rawResponse
|
|
297
|
-
} = await Native.queryStatisticsForQuantity(
|
|
327
|
+
const actualUnit = await ensureUnit(identifier, unit)
|
|
328
|
+
const toDate = to || new Date()
|
|
329
|
+
const { mostRecentQuantityDateInterval, ...rawResponse } = await Native.queryStatisticsForQuantity(
|
|
298
330
|
identifier,
|
|
299
331
|
actualUnit,
|
|
300
332
|
from.toISOString(),
|
|
301
333
|
toDate.toISOString(),
|
|
302
|
-
options
|
|
303
|
-
)
|
|
334
|
+
options,
|
|
335
|
+
)
|
|
304
336
|
|
|
305
337
|
const response = {
|
|
306
338
|
...rawResponse,
|
|
307
339
|
...(mostRecentQuantityDateInterval
|
|
308
340
|
? {
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
341
|
+
mostRecentQuantityDateInterval: {
|
|
342
|
+
from: new Date(mostRecentQuantityDateInterval.from),
|
|
343
|
+
to: new Date(mostRecentQuantityDateInterval.to),
|
|
344
|
+
},
|
|
345
|
+
}
|
|
314
346
|
: {}),
|
|
315
|
-
}
|
|
347
|
+
}
|
|
316
348
|
|
|
317
|
-
return response
|
|
318
|
-
}
|
|
349
|
+
return response
|
|
350
|
+
}
|
|
319
351
|
|
|
320
|
-
const requestAuthorization = (
|
|
321
|
-
read: (HKCharacteristicTypeIdentifier | HKSampleTypeIdentifier)[],
|
|
322
|
-
write: HKSampleTypeIdentifier[] = []
|
|
352
|
+
const requestAuthorization = async (
|
|
353
|
+
read: readonly (HKCharacteristicTypeIdentifier | HKSampleTypeIdentifier)[],
|
|
354
|
+
write: readonly HKSampleTypeIdentifier[] = [],
|
|
323
355
|
): Promise<boolean> => {
|
|
324
|
-
const readPermissions = read.reduce((obj, cur) => {
|
|
325
|
-
return { ...obj, [cur]: true };
|
|
326
|
-
}, {});
|
|
356
|
+
const readPermissions = read.reduce((obj, cur) => ({ ...obj, [cur]: true }), {} as ReadPermissions)
|
|
327
357
|
|
|
328
|
-
const writePermissions = write.reduce((obj, cur) => {
|
|
329
|
-
return { ...obj, [cur]: true };
|
|
330
|
-
}, {});
|
|
358
|
+
const writePermissions = write.reduce((obj, cur) => ({ ...obj, [cur]: true }), {} as WritePermissions)
|
|
331
359
|
|
|
332
|
-
return Native.requestAuthorization(writePermissions, readPermissions)
|
|
333
|
-
}
|
|
360
|
+
return Native.requestAuthorization(writePermissions, readPermissions)
|
|
361
|
+
}
|
|
334
362
|
|
|
335
363
|
const getDateOfBirth = async () => {
|
|
336
|
-
const dateOfBirth = await Native.getDateOfBirth()
|
|
337
|
-
return new Date(dateOfBirth)
|
|
338
|
-
}
|
|
364
|
+
const dateOfBirth = await Native.getDateOfBirth()
|
|
365
|
+
return new Date(dateOfBirth)
|
|
366
|
+
}
|
|
339
367
|
|
|
340
|
-
const getRequestStatusForAuthorization = (
|
|
341
|
-
read: (HKCharacteristicTypeIdentifier | HKSampleTypeIdentifier)[],
|
|
342
|
-
write: HKSampleTypeIdentifier[] = []
|
|
368
|
+
const getRequestStatusForAuthorization = async (
|
|
369
|
+
read: readonly (HKCharacteristicTypeIdentifier | HKSampleTypeIdentifier)[],
|
|
370
|
+
write: readonly HKSampleTypeIdentifier[] = [],
|
|
343
371
|
) => {
|
|
344
|
-
const readPermissions = read.reduce((obj, cur) => {
|
|
345
|
-
return { ...obj, [cur]: true };
|
|
346
|
-
}, {});
|
|
372
|
+
const readPermissions = read.reduce((obj, cur) => ({ ...obj, [cur]: true }), {} as ReadPermissions)
|
|
347
373
|
|
|
348
|
-
const writePermissions = write.reduce((obj, cur) => {
|
|
349
|
-
return { ...obj, [cur]: true };
|
|
350
|
-
}, {});
|
|
374
|
+
const writePermissions = write.reduce((obj, cur) => ({ ...obj, [cur]: true }), {} as WritePermissions)
|
|
351
375
|
|
|
352
376
|
return Native.getRequestStatusForAuthorization(
|
|
353
377
|
writePermissions,
|
|
354
|
-
readPermissions
|
|
355
|
-
)
|
|
356
|
-
}
|
|
378
|
+
readPermissions,
|
|
379
|
+
)
|
|
380
|
+
}
|
|
357
381
|
|
|
358
382
|
const queryCategorySamples: QueryCategorySamplesFn = async (
|
|
359
383
|
identifier,
|
|
360
|
-
options
|
|
384
|
+
options,
|
|
361
385
|
) => {
|
|
362
|
-
const opts = prepareOptions(options)
|
|
386
|
+
const opts = prepareOptions(options)
|
|
363
387
|
const results = await Native.queryCategorySamples(
|
|
364
388
|
identifier,
|
|
365
389
|
opts.from,
|
|
366
390
|
opts.to,
|
|
367
391
|
opts.limit,
|
|
368
|
-
opts.ascending
|
|
369
|
-
)
|
|
370
|
-
|
|
371
|
-
return results.map(deserializCategorySample);
|
|
372
|
-
};
|
|
392
|
+
opts.ascending,
|
|
393
|
+
)
|
|
373
394
|
|
|
374
|
-
|
|
375
|
-
TEnergy extends HKUnit,
|
|
376
|
-
TDistance extends HKUnit
|
|
377
|
-
>(options?: { energyUnit?: TEnergy; distanceUnit?: TDistance }) {
|
|
378
|
-
let energyUnit = options?.energyUnit;
|
|
379
|
-
let distanceUnit = options?.distanceUnit;
|
|
380
|
-
if (!energyUnit || !distanceUnit) {
|
|
381
|
-
const units = await Native.getPreferredUnits([
|
|
382
|
-
HKQuantityTypeIdentifier.distanceWalkingRunning,
|
|
383
|
-
HKQuantityTypeIdentifier.activeEnergyBurned,
|
|
384
|
-
]);
|
|
385
|
-
if (!energyUnit) {
|
|
386
|
-
energyUnit = units[HKQuantityTypeIdentifier.distanceWalkingRunning] as
|
|
387
|
-
| TEnergy
|
|
388
|
-
| undefined;
|
|
389
|
-
}
|
|
390
|
-
if (!distanceUnit) {
|
|
391
|
-
distanceUnit = units[HKQuantityTypeIdentifier.activeEnergyBurned] as
|
|
392
|
-
| TDistance
|
|
393
|
-
| undefined;
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
if (!energyUnit) {
|
|
397
|
-
energyUnit = HKUnit.Kilocalories as TEnergy;
|
|
398
|
-
}
|
|
399
|
-
if (!distanceUnit) {
|
|
400
|
-
distanceUnit = HKUnit.Meters as TDistance;
|
|
401
|
-
}
|
|
402
|
-
return { energyUnit, distanceUnit };
|
|
395
|
+
return results.map(deserializCategorySample)
|
|
403
396
|
}
|
|
404
397
|
|
|
405
398
|
const queryWorkouts: QueryWorkoutsFn = async (options) => {
|
|
406
|
-
const { energyUnit, distanceUnit } = await getPreferredUnitsTyped(options)
|
|
407
|
-
const opts = prepareOptions(options)
|
|
399
|
+
const { energyUnit, distanceUnit } = await getPreferredUnitsTyped(options)
|
|
400
|
+
const opts = prepareOptions(options)
|
|
408
401
|
|
|
409
402
|
const workouts = await Native.queryWorkoutSamples(
|
|
410
403
|
energyUnit,
|
|
@@ -412,11 +405,11 @@ const queryWorkouts: QueryWorkoutsFn = async (options) => {
|
|
|
412
405
|
opts.from,
|
|
413
406
|
opts.to,
|
|
414
407
|
opts.limit,
|
|
415
|
-
opts.ascending
|
|
416
|
-
)
|
|
408
|
+
opts.ascending,
|
|
409
|
+
)
|
|
417
410
|
|
|
418
|
-
return workouts.map(deserializeWorkout)
|
|
419
|
-
}
|
|
411
|
+
return workouts.map(deserializeWorkout)
|
|
412
|
+
}
|
|
420
413
|
|
|
421
414
|
const getMostRecentWorkout: GetMostRecentWorkoutFn = async (options) => {
|
|
422
415
|
const workouts = await queryWorkouts({
|
|
@@ -424,41 +417,39 @@ const getMostRecentWorkout: GetMostRecentWorkoutFn = async (options) => {
|
|
|
424
417
|
ascending: false,
|
|
425
418
|
energyUnit: options?.energyUnit,
|
|
426
419
|
distanceUnit: options?.distanceUnit,
|
|
427
|
-
})
|
|
420
|
+
})
|
|
428
421
|
|
|
429
|
-
return workouts[0]
|
|
430
|
-
}
|
|
422
|
+
return workouts[0]
|
|
423
|
+
}
|
|
431
424
|
|
|
432
|
-
function saveCategorySample<T extends HKCategoryTypeIdentifier>(
|
|
425
|
+
async function saveCategorySample<T extends HKCategoryTypeIdentifier>(
|
|
433
426
|
identifier: T,
|
|
434
427
|
value: HKCategoryValueForIdentifier<T>,
|
|
435
428
|
options?: {
|
|
436
|
-
start?: Date;
|
|
437
|
-
end?: Date;
|
|
438
|
-
metadata?: MetadataMapperForCategoryIdentifier<T>;
|
|
439
|
-
}
|
|
429
|
+
readonly start?: Date;
|
|
430
|
+
readonly end?: Date;
|
|
431
|
+
readonly metadata?: MetadataMapperForCategoryIdentifier<T>;
|
|
432
|
+
},
|
|
440
433
|
) {
|
|
441
|
-
const start = options?.start || options?.end || new Date()
|
|
442
|
-
const end = options?.end || options?.start || new Date()
|
|
443
|
-
const metadata = options?.metadata || {}
|
|
434
|
+
const start = options?.start || options?.end || new Date()
|
|
435
|
+
const end = options?.end || options?.start || new Date()
|
|
436
|
+
const metadata = options?.metadata || {}
|
|
444
437
|
|
|
445
438
|
return Native.saveCategorySample(
|
|
446
439
|
identifier,
|
|
447
440
|
value,
|
|
448
441
|
start.toISOString(),
|
|
449
442
|
end.toISOString(),
|
|
450
|
-
metadata || {}
|
|
451
|
-
)
|
|
443
|
+
metadata || {},
|
|
444
|
+
)
|
|
452
445
|
}
|
|
453
446
|
|
|
454
447
|
const getPreferredUnits: GetPreferredUnitsFn = async (identifiers) => {
|
|
455
|
-
const units = await Native.getPreferredUnits(identifiers)
|
|
456
|
-
return identifiers.map((i) => units[i])
|
|
457
|
-
}
|
|
448
|
+
const units = await Native.getPreferredUnits(identifiers)
|
|
449
|
+
return identifiers.map((i) => units[i])
|
|
450
|
+
}
|
|
458
451
|
|
|
459
|
-
const buildUnitWithPrefix = (prefix: HKUnitSIPrefix, unit: HKUnitSI) => {
|
|
460
|
-
return `${prefix}${unit}` as HKUnit;
|
|
461
|
-
};
|
|
452
|
+
const buildUnitWithPrefix = (prefix: HKUnitSIPrefix, unit: HKUnitSI) => `${prefix}${unit}` as HKUnit
|
|
462
453
|
|
|
463
454
|
function deserializeCorrelation<
|
|
464
455
|
TIdentifier extends HKCorrelationTypeIdentifier
|
|
@@ -466,75 +457,78 @@ function deserializeCorrelation<
|
|
|
466
457
|
return {
|
|
467
458
|
...s,
|
|
468
459
|
objects: s.objects.map((o) => {
|
|
460
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
469
461
|
// @ts-ignore
|
|
470
462
|
if (o.quantity !== undefined) {
|
|
471
|
-
return deserializeSample(o as HKQuantitySampleRaw)
|
|
463
|
+
return deserializeSample(o as HKQuantitySampleRaw)
|
|
472
464
|
}
|
|
473
465
|
|
|
474
|
-
return deserializCategorySample(o as HKCategorySampleRaw)
|
|
466
|
+
return deserializCategorySample(o as HKCategorySampleRaw)
|
|
475
467
|
}),
|
|
476
468
|
endDate: new Date(s.endDate),
|
|
477
469
|
startDate: new Date(s.startDate),
|
|
478
|
-
}
|
|
470
|
+
}
|
|
479
471
|
}
|
|
480
472
|
|
|
481
473
|
function ensureMetadata<TMetadata>(metadata?: TMetadata) {
|
|
482
|
-
return metadata || ({} as TMetadata)
|
|
474
|
+
return metadata || ({} as TMetadata)
|
|
483
475
|
}
|
|
484
476
|
|
|
485
477
|
const queryCorrelationSamples: QueryCorrelationSamplesFn = async (
|
|
486
478
|
typeIdentifier,
|
|
487
|
-
options
|
|
479
|
+
options,
|
|
488
480
|
) => {
|
|
489
|
-
const opts = prepareOptions(options)
|
|
481
|
+
const opts = prepareOptions(options)
|
|
490
482
|
const correlations = await Native.queryCorrelationSamples(
|
|
491
483
|
typeIdentifier,
|
|
492
484
|
opts.from,
|
|
493
|
-
opts.to
|
|
494
|
-
)
|
|
485
|
+
opts.to,
|
|
486
|
+
)
|
|
495
487
|
|
|
496
|
-
return correlations.map(deserializeCorrelation)
|
|
497
|
-
}
|
|
488
|
+
return correlations.map(deserializeCorrelation)
|
|
489
|
+
}
|
|
498
490
|
|
|
499
491
|
const saveCorrelationSample: SaveCorrelationSampleFn = async (
|
|
500
492
|
typeIdentifier,
|
|
501
493
|
samples,
|
|
502
|
-
options
|
|
494
|
+
options,
|
|
503
495
|
) => {
|
|
504
|
-
const start = (options?.start || new Date()).toISOString()
|
|
505
|
-
const end = (options?.end || new Date()).toISOString()
|
|
496
|
+
const start = (options?.start || new Date()).toISOString()
|
|
497
|
+
const end = (options?.end || new Date()).toISOString()
|
|
506
498
|
|
|
507
499
|
return Native.saveCorrelationSample(
|
|
508
500
|
typeIdentifier,
|
|
509
501
|
samples,
|
|
510
502
|
start,
|
|
511
503
|
end,
|
|
512
|
-
ensureMetadata(options?.metadata)
|
|
513
|
-
)
|
|
514
|
-
}
|
|
504
|
+
ensureMetadata(options?.metadata),
|
|
505
|
+
)
|
|
506
|
+
}
|
|
515
507
|
|
|
516
|
-
const saveWorkoutSample: SaveWorkoutSampleFn = (
|
|
508
|
+
const saveWorkoutSample: SaveWorkoutSampleFn = async (
|
|
517
509
|
typeIdentifier,
|
|
518
510
|
quantities,
|
|
519
511
|
_start,
|
|
520
|
-
options
|
|
512
|
+
options,
|
|
521
513
|
) => {
|
|
522
|
-
const start = _start.toISOString()
|
|
523
|
-
const end = (options?.end || new Date()).toISOString()
|
|
514
|
+
const start = _start.toISOString()
|
|
515
|
+
const end = (options?.end || new Date()).toISOString()
|
|
524
516
|
|
|
525
517
|
return Native.saveWorkoutSample(
|
|
526
518
|
typeIdentifier,
|
|
527
519
|
quantities,
|
|
528
520
|
start,
|
|
529
521
|
end,
|
|
530
|
-
ensureMetadata(options?.metadata)
|
|
531
|
-
)
|
|
532
|
-
}
|
|
522
|
+
ensureMetadata(options?.metadata),
|
|
523
|
+
)
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
const getWorkoutRoutes: GetWorkoutRoutesFn = async (workoutUUID: string) => Native.getWorkoutRoutes(workoutUUID)
|
|
533
527
|
|
|
534
528
|
const Healthkit: ReactNativeHealthkit = {
|
|
535
|
-
authorizationStatusFor: Native.authorizationStatusFor,
|
|
529
|
+
authorizationStatusFor: Native.authorizationStatusFor.bind(Native),
|
|
536
530
|
|
|
537
|
-
isHealthDataAvailable: Native.isHealthDataAvailable,
|
|
531
|
+
isHealthDataAvailable: Native.isHealthDataAvailable.bind(Native),
|
|
538
532
|
|
|
539
533
|
buildUnitWithPrefix,
|
|
540
534
|
|
|
@@ -543,10 +537,10 @@ const Healthkit: ReactNativeHealthkit = {
|
|
|
543
537
|
enableBackgroundDelivery: Native.enableBackgroundDelivery,
|
|
544
538
|
|
|
545
539
|
// simple convenience getters
|
|
546
|
-
getBiologicalSex: Native.getBiologicalSex,
|
|
547
|
-
getFitzpatrickSkinType: Native.getFitzpatrickSkinType,
|
|
540
|
+
getBiologicalSex: Native.getBiologicalSex.bind(Native),
|
|
541
|
+
getFitzpatrickSkinType: Native.getFitzpatrickSkinType.bind(Native),
|
|
548
542
|
getWheelchairUse: Native.getWheelchairUse,
|
|
549
|
-
getBloodType: Native.getBloodType,
|
|
543
|
+
getBloodType: Native.getBloodType.bind(Native),
|
|
550
544
|
getDateOfBirth,
|
|
551
545
|
|
|
552
546
|
getMostRecentQuantitySample,
|
|
@@ -557,6 +551,8 @@ const Healthkit: ReactNativeHealthkit = {
|
|
|
557
551
|
getPreferredUnits,
|
|
558
552
|
getRequestStatusForAuthorization,
|
|
559
553
|
|
|
554
|
+
getWorkoutRoutes,
|
|
555
|
+
|
|
560
556
|
// query methods
|
|
561
557
|
queryCategorySamples,
|
|
562
558
|
queryCorrelationSamples,
|
|
@@ -582,9 +578,9 @@ const Healthkit: ReactNativeHealthkit = {
|
|
|
582
578
|
useMostRecentWorkout,
|
|
583
579
|
|
|
584
580
|
useSubscribeToChanges,
|
|
585
|
-
}
|
|
581
|
+
}
|
|
586
582
|
|
|
587
|
-
export * from './types'
|
|
588
|
-
export * from './
|
|
583
|
+
export * from './native-types'
|
|
584
|
+
export * from './types'
|
|
589
585
|
|
|
590
|
-
export default Healthkit
|
|
586
|
+
export default Healthkit
|