@kingstinct/react-native-healthkit 8.4.0 → 8.6.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.
Files changed (42) hide show
  1. package/ios/Helpers.swift +180 -31
  2. package/ios/ReactNativeHealthkit.m +14 -0
  3. package/ios/ReactNativeHealthkit.swift +504 -268
  4. package/lib/commonjs/index.ios.js +19 -1
  5. package/lib/commonjs/index.ios.js.map +1 -1
  6. package/lib/commonjs/index.native.js +7 -1
  7. package/lib/commonjs/index.native.js.map +1 -1
  8. package/lib/commonjs/native-types.js +16 -1
  9. package/lib/commonjs/native-types.js.map +1 -1
  10. package/lib/commonjs/test-setup.js +3 -1
  11. package/lib/commonjs/test-setup.js.map +1 -1
  12. package/lib/commonjs/utils/saveStateOfMindSample.js +17 -0
  13. package/lib/commonjs/utils/saveStateOfMindSample.js.map +1 -0
  14. package/lib/commonjs/utils/subscribeToChanges.js.map +1 -1
  15. package/lib/commonjs/utils/workoutSessionMirroringStartHandler.js +17 -0
  16. package/lib/commonjs/utils/workoutSessionMirroringStartHandler.js.map +1 -0
  17. package/lib/module/index.ios.js +5 -1
  18. package/lib/module/index.ios.js.map +1 -1
  19. package/lib/module/index.native.js +5 -1
  20. package/lib/module/index.native.js.map +1 -1
  21. package/lib/module/native-types.js +16 -0
  22. package/lib/module/native-types.js.map +1 -1
  23. package/lib/module/test-setup.js +3 -1
  24. package/lib/module/test-setup.js.map +1 -1
  25. package/lib/module/utils/saveStateOfMindSample.js +10 -0
  26. package/lib/module/utils/saveStateOfMindSample.js.map +1 -0
  27. package/lib/module/utils/subscribeToChanges.js.map +1 -1
  28. package/lib/module/utils/workoutSessionMirroringStartHandler.js +11 -0
  29. package/lib/module/utils/workoutSessionMirroringStartHandler.js.map +1 -0
  30. package/lib/typescript/src/index.ios.d.ts +5 -1
  31. package/lib/typescript/src/index.native.d.ts +2 -2
  32. package/lib/typescript/src/native-types.d.ts +43 -2
  33. package/lib/typescript/src/utils/saveStateOfMindSample.d.ts +11 -0
  34. package/lib/typescript/src/utils/workoutSessionMirroringStartHandler.d.ts +8 -0
  35. package/package.json +1 -1
  36. package/src/index.ios.tsx +6 -0
  37. package/src/index.native.tsx +6 -0
  38. package/src/native-types.ts +58 -3
  39. package/src/test-setup.ts +2 -0
  40. package/src/utils/saveStateOfMindSample.ts +38 -0
  41. package/src/utils/subscribeToChanges.ts +1 -1
  42. package/src/utils/workoutSessionMirroringStartHandler.ts +11 -0
package/ios/Helpers.swift CHANGED
@@ -18,7 +18,8 @@ func limitOrNilIfZero(limit: Int) -> Int {
18
18
 
19
19
  func createPredicate(from: Date?, to: Date?) -> NSPredicate? {
20
20
  if from != nil || to != nil {
21
- return HKQuery.predicateForSamples(withStart: from, end: to, options: [.strictEndDate, .strictStartDate])
21
+ return HKQuery.predicateForSamples(
22
+ withStart: from, end: to, options: [.strictEndDate, .strictStartDate])
22
23
  } else {
23
24
  return nil
24
25
  }
@@ -29,23 +30,23 @@ func getSortDescriptors(ascending: Bool) -> [NSSortDescriptor] {
29
30
  }
30
31
 
31
32
  func base64StringToHKQueryAnchor(base64String: String) -> HKQueryAnchor? {
32
- // Step 1: Decode the base64 string to a Data object
33
- guard let data = Data(base64Encoded: base64String) else {
34
- print("Error: Invalid base64 string")
35
- return nil
36
- }
33
+ // Step 1: Decode the base64 string to a Data object
34
+ guard let data = Data(base64Encoded: base64String) else {
35
+ print("Error: Invalid base64 string")
36
+ return nil
37
+ }
37
38
 
38
- // Step 2: Use NSKeyedUnarchiver to unarchive the data and create an HKQueryAnchor object
39
- do {
40
- let unarchiver = try NSKeyedUnarchiver(forReadingFrom: data)
41
- unarchiver.requiresSecureCoding = true
42
- let anchor = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data)
39
+ // Step 2: Use NSKeyedUnarchiver to unarchive the data and create an HKQueryAnchor object
40
+ do {
41
+ let unarchiver = try NSKeyedUnarchiver(forReadingFrom: data)
42
+ unarchiver.requiresSecureCoding = true
43
+ let anchor = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data)
43
44
 
44
- return anchor as? HKQueryAnchor
45
- } catch {
46
- print("Error: Unable to unarchive HKQueryAnchor object: \(error)")
47
- return nil
48
- }
45
+ return anchor as? HKQueryAnchor
46
+ } catch {
47
+ print("Error: Unable to unarchive HKQueryAnchor object: \(error)")
48
+ return nil
49
+ }
49
50
  }
50
51
 
51
52
  func sampleTypeFromString(typeIdentifier: String) -> HKSampleType? {
@@ -70,6 +71,14 @@ func sampleTypeFromString(typeIdentifier: String) -> HKSampleType? {
70
71
  }
71
72
  }
72
73
 
74
+ #if compiler(>=6)
75
+ if #available(iOS 18, *) {
76
+ if typeIdentifier == HKStateOfMindTypeIdentifier {
77
+ return HKObjectType.stateOfMindType()
78
+ }
79
+ }
80
+ #endif
81
+
73
82
  if typeIdentifier == HKWorkoutTypeIdentifier {
74
83
  return HKSampleType.workoutType()
75
84
  }
@@ -102,7 +111,7 @@ func sampleTypesFromDictionary(typeIdentifiers: NSDictionary) -> Set<HKSampleTyp
102
111
  if item.value as! Bool {
103
112
  let sampleType = sampleTypeFromString(typeIdentifier: item.key as! String)
104
113
  if sampleType != nil {
105
- share.insert(sampleType!)
114
+ share.insert(sampleType!)
106
115
  }
107
116
  }
108
117
  }
@@ -134,11 +143,13 @@ func objectTypeFromString(typeIdentifier: String) -> HKObjectType? {
134
143
  return HKObjectType.activitySummaryType()
135
144
  }
136
145
 
137
- if #available(iOS 18, *) {
138
- if typeIdentifier == HKStateOfMindTypeIdentifier {
139
- return HKObjectType.stateOfMindType()
140
- }
141
- }
146
+ #if compiler(>=6)
147
+ if #available(iOS 18, *) {
148
+ if typeIdentifier == HKStateOfMindTypeIdentifier {
149
+ return HKObjectType.stateOfMindType()
150
+ }
151
+ }
152
+ #endif
142
153
 
143
154
  if #available(iOS 13, *) {
144
155
  if typeIdentifier == HKAudiogramTypeIdentifier {
@@ -223,23 +234,161 @@ func serializeQuantityIfExists(unit: HKUnit, quantity: HKQuantity?) -> [String:
223
234
  return serializeQuantity(unit: unit, quantity: quantity)
224
235
  }
225
236
 
226
- func serializeStatisticIfExists(unit: HKUnit, quantity: HKQuantity?, stats: HKStatistics) -> [String: Any]? {
237
+ func serializeStatisticIfExists(unit: HKUnit, quantity: HKQuantity?, stats: HKStatistics)
238
+ -> [String: Any]? {
227
239
  guard let quantity = quantity else { return nil }
228
240
  return serializeStatistic(unit: unit, quantity: quantity, stats: stats)
229
241
  }
230
242
 
231
243
  func parseWorkoutConfiguration(_ dict: NSDictionary) -> HKWorkoutConfiguration {
232
- let configuration = HKWorkoutConfiguration()
244
+ let configuration = HKWorkoutConfiguration()
245
+
246
+ if let activityTypeRaw = dict[HKWorkoutActivityTypePropertyName] as? UInt,
247
+ let activityType = HKWorkoutActivityType(rawValue: activityTypeRaw) {
248
+ configuration.activityType = activityType
249
+ }
233
250
 
234
- if let activityTypeRaw = dict[HKWorkoutActivityTypePropertyName] as? UInt,
235
- let activityType = HKWorkoutActivityType(rawValue: activityTypeRaw) {
236
- configuration.activityType = activityType
251
+ if let locationTypeRaw = dict[HKWorkoutSessionLocationTypePropertyName] as? Int,
252
+ let locationType = HKWorkoutSessionLocationType(rawValue: locationTypeRaw) {
253
+ configuration.locationType = locationType
254
+ }
255
+
256
+ return configuration
257
+ }
258
+
259
+ #if compiler(>=6)
260
+ @available(iOS 18.0, *)
261
+ extension HKStateOfMind.Kind: @retroactive CaseIterable, @retroactive CustomStringConvertible {
262
+ public var description: String {
263
+ switch self {
264
+ case .dailyMood: "Daily mood"
265
+ case .momentaryEmotion: "Momentary Emotion"
266
+ @unknown default: "Unknown"
267
+ }
237
268
  }
238
269
 
239
- if let locationTypeRaw = dict[HKWorkoutSessionLocationTypePropertyName] as? Int,
240
- let locationType = HKWorkoutSessionLocationType(rawValue: locationTypeRaw) {
241
- configuration.locationType = locationType
270
+ public static var allCases: [HKStateOfMind.Kind] {
271
+ [.dailyMood, .momentaryEmotion]
242
272
  }
243
273
 
244
- return configuration
274
+ static func convertToStateOfMindKind(int: Int) -> HKStateOfMind.Kind {
275
+ // default to .dailyMood if we receive an int out of bounds
276
+ return HKStateOfMind.Kind(rawValue: int) ?? .dailyMood
277
+ }
278
+ }
279
+ #endif
280
+
281
+ #if compiler(>=6)
282
+ @available(iOS 18.0, *)
283
+ extension HKStateOfMind.Label: @retroactive CaseIterable, @retroactive CustomStringConvertible {
284
+ public var description: String {
285
+ switch self {
286
+ case .amazed: "Amazed"
287
+ case .amused: "Amused"
288
+ case .angry: "Angry"
289
+ case .anxious: "Anxious"
290
+ case .ashamed: "Ashamed"
291
+ case .brave: "Brave"
292
+ case .calm: "Calm"
293
+ case .content: "Content"
294
+ case .disappointed: "Disappointed"
295
+ case .discouraged: "Discouraged"
296
+ case .disgusted: "Disgusted"
297
+ case .embarrassed: "Embarrassed"
298
+ case .excited: "Excited"
299
+ case .frustrated: "Frustrated"
300
+ case .grateful: "Grateful"
301
+ case .guilty: "Guilty"
302
+ case .happy: "Happy"
303
+ case .hopeless: "Hopeless"
304
+ case .irritated: "Irritated"
305
+ case .jealous: "Jealous"
306
+ case .joyful: "Joyful"
307
+ case .lonely: "Lonely"
308
+ case .passionate: "Passionate"
309
+ case .peaceful: "Peaceful"
310
+ case .proud: "Proud"
311
+ case .relieved: "Relieved"
312
+ case .sad: "Sad"
313
+ case .scared: "Scared"
314
+ case .stressed: "Stressed"
315
+ case .surprised: "Surprised"
316
+ case .worried: "Worried"
317
+ case .annoyed: "Annoyed"
318
+ case .confident: "Confident"
319
+ case .drained: "Drained"
320
+ case .hopeful: "Hopeful"
321
+ case .indifferent: "Indifferent"
322
+ case .overwhelmed: "Overwhelmed"
323
+ case .satisfied: "Satisfied"
324
+ @unknown default: "Unknown"
325
+ }
326
+ }
327
+
328
+ public static var allCases: [HKStateOfMind.Label] {
329
+ [
330
+ .amazed, .amused, .angry, .anxious, .ashamed,
331
+ .brave, .calm, .content, .disappointed, .discouraged,
332
+ .disgusted, .embarrassed, .excited, .frustrated, .grateful,
333
+ .guilty, .happy, .hopeless, .irritated, .jealous,
334
+ .joyful, .lonely, .passionate, .peaceful, .proud,
335
+ .relieved, .sad, .scared, .stressed, .surprised,
336
+ .worried, .annoyed, .confident, .drained, .hopeful,
337
+ .indifferent, .overwhelmed, .satisfied
338
+ ]
339
+ }
340
+
341
+ static func convertToStateOfMindLabels(intArray: [Int]) -> [HKStateOfMind.Label] {
342
+ return intArray.compactMap { index in
343
+ // if any int are out of bounds return nil instead of crashing
344
+ guard index >= 0 && index < HKStateOfMind.Label.allCases.count else { return nil }
345
+ return HKStateOfMind.Label(rawValue: index)
346
+ }
347
+ }
348
+ }
349
+ #endif
350
+
351
+ #if compiler(>=6)
352
+ @available(iOS 18.0, *)
353
+ extension HKStateOfMind.Association: @retroactive CaseIterable, @retroactive CustomStringConvertible {
354
+ public var description: String {
355
+ switch self {
356
+ case .community: "Community"
357
+ case .currentEvents: "Current Events"
358
+ case .dating: "Dating"
359
+ case .education: "Education"
360
+ case .family: "Family"
361
+ case .fitness: "Fitness"
362
+ case .friends: "Friends"
363
+ case .health: "Health"
364
+ case .hobbies: "Hobbies"
365
+ case .identity: "Identity"
366
+ case .money: "Money"
367
+ case .partner: "Partner"
368
+ case .selfCare: "Self Care"
369
+ case .spirituality: "Spirituality"
370
+ case .tasks: "Tasks"
371
+ case .travel: "Travel"
372
+ case .work: "Work"
373
+ case .weather: "Weather"
374
+ @unknown default: "Unknown"
375
+ }
376
+ }
377
+
378
+ public static var allCases: [HKStateOfMind.Association] {
379
+ [
380
+ .community, .currentEvents, .dating, .education, .family,
381
+ .fitness, .friends, .health, .hobbies, .identity,
382
+ .money, .partner, .selfCare, .spirituality, .tasks,
383
+ .travel, .work, .weather
384
+ ]
385
+ }
386
+
387
+ static func convertToStateOfMindAssociations(intArray: [Int]) -> [HKStateOfMind.Association] {
388
+ return intArray.compactMap { index in
389
+ guard index >= 0 && index < HKStateOfMind.Association.allCases.count else { return nil }
390
+ return HKStateOfMind.Association(rawValue: index)
391
+ }
392
+ }
245
393
  }
394
+ #endif
@@ -88,6 +88,16 @@ RCT_EXTERN_METHOD(saveCategorySample:(NSString)typeIdentifier
88
88
  resolve:(RCTPromiseResolveBlock)resolve
89
89
  reject:(RCTPromiseRejectBlock)reject
90
90
  )
91
+ RCT_EXTERN_METHOD(saveStateOfMindSample:(NSDate)date
92
+ kind:(NSInteger)kind
93
+ valence:(double)valence
94
+ labels:(NSArray)labels
95
+ associations:(NSArray)associations
96
+ metadata:(NSDictionary)metadata
97
+ resolve:(RCTPromiseResolveBlock)resolve
98
+ reject:(RCTPromiseRejectBlock)reject
99
+ )
100
+
91
101
 
92
102
  RCT_EXTERN_METHOD(queryWorkoutSamplesWithAnchor:(NSString)energyUnitString
93
103
  distanceUnitString:(NSString)distanceUnitString
@@ -253,4 +263,8 @@ RCT_EXTERN_METHOD(queryStateOfMindSamples:(NSDate)from
253
263
  resolve:(RCTPromiseResolveBlock)resolve
254
264
  reject:(RCTPromiseRejectBlock)reject)
255
265
 
266
+ RCT_EXTERN_METHOD(workoutSessionMirroringStartHandler:(RCTPromiseResolveBlock)resolve
267
+ reject:(RCTPromiseRejectBlock)reject
268
+ )
269
+
256
270
  @end