react-native-rook-sdk 4.0.0-beta.2 → 5.0.0-beta.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 (99) hide show
  1. package/RNRookSdk.podspec +1 -1
  2. package/android/build.gradle +6 -0
  3. package/android/src/main/java/com/rooksdk/RookSdkModule.kt +1850 -6
  4. package/android/src/main/java/com/rooksdk/broadcasts/AndroidPermissionsReceiverTransmitter.kt +62 -0
  5. package/android/src/main/java/com/rooksdk/broadcasts/HealthConnectPermissionsReceiverTransmitter.kt +64 -0
  6. package/android/src/main/java/com/rooksdk/broadcasts/SamsungHealthPermissionsReceiverTransmitter.kt +44 -0
  7. package/android/src/main/java/com/rooksdk/utils/DatasourceUtils.kt +35 -0
  8. package/android/src/main/java/com/rooksdk/utils/PermissionConvertions.kt +21 -0
  9. package/android/src/main/java/com/rooksdk/utils/ReadableToWritable.kt +144 -0
  10. package/android/src/main/java/com/rooksdk/utils/RookDateTime.kt +26 -0
  11. package/android/src/main/java/com/rooksdk/utils/RookGsonBuilder.kt +20 -0
  12. package/android/src/main/java/com/rooksdk/utils/SamsungAvailability.kt +22 -0
  13. package/android/src/main/java/com/rooksdk/utils/Source.kt +6 -0
  14. package/android/src/main/java/com/rooksdk/utils/StringToSyncType.kt +41 -0
  15. package/android/src/main/java/com/rooksdk/utils/serializers/InstantSerializer.kt +18 -0
  16. package/android/src/main/java/com/rooksdk/utils/serializers/LocalDateSerializer.kt +21 -0
  17. package/android/src/main/java/com/rooksdk/utils/serializers/ZoneDateTimeSerializer.kt +18 -0
  18. package/ios/EncodableSDKState.swift +95 -0
  19. package/ios/NutritionMapper.swift +114 -0
  20. package/ios/RookConfiguration.swift +13 -0
  21. package/ios/RookData.swift +29 -0
  22. package/ios/RookEntry.swift +5 -4
  23. package/ios/RookPermissions.swift +33 -9
  24. package/ios/RookSdk.h +1 -13
  25. package/ios/RookSdk.mm +44 -237
  26. package/lib/module/NativeRookSdk.js +98 -10
  27. package/lib/module/NativeRookSdk.js.map +1 -1
  28. package/lib/module/context/RookSyncGateProvider.js +29 -21
  29. package/lib/module/context/RookSyncGateProvider.js.map +1 -1
  30. package/lib/module/context/RookSyncGateReducer.js +12 -2
  31. package/lib/module/context/RookSyncGateReducer.js.map +1 -1
  32. package/lib/module/hooks/useRookConfiguration.js +20 -1
  33. package/lib/module/hooks/useRookConfiguration.js.map +1 -1
  34. package/lib/module/hooks/useRookData.js +13 -4
  35. package/lib/module/hooks/useRookData.js.map +1 -1
  36. package/lib/module/hooks/useRookPermissions.js +13 -1
  37. package/lib/module/hooks/useRookPermissions.js.map +1 -1
  38. package/lib/module/hooks/useRookSync.js +1 -1
  39. package/lib/module/hooks/useRookSync.js.map +1 -1
  40. package/lib/module/hooks/useRookVariables.js +16 -1
  41. package/lib/module/hooks/useRookVariables.js.map +1 -1
  42. package/lib/module/modules/components/RookStateManager.js +31 -0
  43. package/lib/module/modules/components/RookStateManager.js.map +1 -0
  44. package/lib/module/modules/hook/useRookAutoSync.js +5 -4
  45. package/lib/module/modules/hook/useRookAutoSync.js.map +1 -1
  46. package/lib/module/modules/hook/useRookEmitter.js +61 -0
  47. package/lib/module/modules/hook/useRookEmitter.js.map +1 -0
  48. package/lib/module/types/AppleHealthNutritionEvent.js +72 -0
  49. package/lib/module/types/AppleHealthNutritionEvent.js.map +1 -0
  50. package/lib/module/types/HCMealData.js +61 -0
  51. package/lib/module/types/HCMealData.js.map +1 -0
  52. package/lib/module/types/WriteNutrition.js +14 -0
  53. package/lib/module/types/WriteNutrition.js.map +1 -0
  54. package/lib/module/utils/isValidDate.js +20 -0
  55. package/lib/module/utils/isValidDate.js.map +1 -1
  56. package/lib/typescript/src/NativeRookSdk.d.ts +622 -33
  57. package/lib/typescript/src/NativeRookSdk.d.ts.map +1 -1
  58. package/lib/typescript/src/context/RookSyncGateProvider.d.ts.map +1 -1
  59. package/lib/typescript/src/context/RookSyncGateReducer.d.ts.map +1 -1
  60. package/lib/typescript/src/context/RookSyncGateTypes.d.ts +14 -4
  61. package/lib/typescript/src/context/RookSyncGateTypes.d.ts.map +1 -1
  62. package/lib/typescript/src/hooks/useRookConfiguration.d.ts +3 -1
  63. package/lib/typescript/src/hooks/useRookConfiguration.d.ts.map +1 -1
  64. package/lib/typescript/src/hooks/useRookData.d.ts +2 -2
  65. package/lib/typescript/src/hooks/useRookData.d.ts.map +1 -1
  66. package/lib/typescript/src/hooks/useRookPermissions.d.ts +2 -0
  67. package/lib/typescript/src/hooks/useRookPermissions.d.ts.map +1 -1
  68. package/lib/typescript/src/hooks/useRookVariables.d.ts +2 -0
  69. package/lib/typescript/src/hooks/useRookVariables.d.ts.map +1 -1
  70. package/lib/typescript/src/modules/components/RookStateManager.d.ts +10 -0
  71. package/lib/typescript/src/modules/components/RookStateManager.d.ts.map +1 -0
  72. package/lib/typescript/src/modules/hook/useRookAutoSync.d.ts.map +1 -1
  73. package/lib/typescript/src/modules/hook/useRookEmitter.d.ts +4 -0
  74. package/lib/typescript/src/modules/hook/useRookEmitter.d.ts.map +1 -0
  75. package/lib/typescript/src/types/AppleHealthNutritionEvent.d.ts +76 -0
  76. package/lib/typescript/src/types/AppleHealthNutritionEvent.d.ts.map +1 -0
  77. package/lib/typescript/src/types/HCMealData.d.ts +60 -0
  78. package/lib/typescript/src/types/HCMealData.d.ts.map +1 -0
  79. package/lib/typescript/src/types/WriteNutrition.d.ts +61 -0
  80. package/lib/typescript/src/types/WriteNutrition.d.ts.map +1 -0
  81. package/lib/typescript/src/utils/isValidDate.d.ts +8 -0
  82. package/lib/typescript/src/utils/isValidDate.d.ts.map +1 -1
  83. package/package.json +1 -1
  84. package/src/NativeRookSdk.ts +682 -117
  85. package/src/context/RookSyncGateProvider.tsx +20 -16
  86. package/src/context/RookSyncGateReducer.ts +6 -2
  87. package/src/context/RookSyncGateTypes.ts +9 -3
  88. package/src/hooks/useRookConfiguration.ts +26 -2
  89. package/src/hooks/useRookData.ts +18 -7
  90. package/src/hooks/useRookPermissions.ts +16 -0
  91. package/src/hooks/useRookSync.ts +1 -1
  92. package/src/hooks/useRookVariables.ts +22 -1
  93. package/src/modules/components/RookStateManager.tsx +41 -0
  94. package/src/modules/hook/useRookAutoSync.ts +6 -4
  95. package/src/modules/hook/useRookEmitter.ts +94 -0
  96. package/src/types/AppleHealthNutritionEvent.ts +142 -0
  97. package/src/types/HCMealData.ts +114 -0
  98. package/src/types/WriteNutrition.ts +66 -0
  99. package/src/utils/isValidDate.ts +24 -0
@@ -1,25 +1,1869 @@
1
1
  package com.rooksdk
2
2
 
3
+ import com.facebook.react.bridge.Arguments
4
+ import com.facebook.react.bridge.Callback
3
5
  import com.facebook.react.bridge.Promise
4
6
  import com.facebook.react.bridge.ReactApplicationContext
7
+ import com.facebook.react.bridge.ReadableArray
8
+ import com.facebook.react.bridge.ReadableMap
5
9
  import com.facebook.react.module.annotations.ReactModule
10
+ import com.google.gson.Gson
11
+ import com.rookmotion.rook.sdk.RookBackgroundSyncManager
12
+ import com.rookmotion.rook.sdk.RookConfigurationManager
13
+ import com.rookmotion.rook.sdk.RookPermissionsManager
14
+ import com.rookmotion.rook.sdk.RookStepsManager
15
+ import com.rookmotion.rook.sdk.RookSyncManager
16
+ import com.rookmotion.rook.sdk.RookWriteManager
17
+ import com.rookmotion.rook.sdk.domain.analytics.HCRookAnalytics
18
+ import com.rookmotion.rook.sdk.domain.analytics.HCRookFramework
19
+ import com.rookmotion.rook.sdk.domain.annotation.ExperimentalRookApi
20
+ import com.rookmotion.rook.sdk.domain.enums.BackgroundReadStatus
21
+ import com.rookmotion.rook.sdk.domain.enums.HealthConnectAvailability
22
+ import com.rookmotion.rook.sdk.domain.enums.RequestPermissionsStatus
23
+ import com.rookmotion.rook.sdk.domain.enums.SyncStatus
24
+ import com.rookmotion.rook.sdk.domain.environment.RookEnvironment
25
+ import com.rookmotion.rook.sdk.domain.exception.HCException
26
+ import com.rookmotion.rook.sdk.domain.exception.HCRecordsNotFoundException
27
+ import com.rookmotion.rook.sdk.domain.model.HCActivityEvent
28
+ import com.rookmotion.rook.sdk.domain.model.HCBodySummary
29
+ import com.rookmotion.rook.sdk.domain.model.HCPhysicalSummary
30
+ import com.rookmotion.rook.sdk.domain.model.HCSleepSummary
31
+ import com.rookmotion.rook.sdk.domain.model.RookConfiguration
32
+ import com.rookmotion.rook.sdk.domain.model.SyncStatusWithData
33
+ import com.rooksdk.broadcasts.AndroidPermissionsReceiverTransmitter
34
+ import com.rooksdk.broadcasts.HealthConnectPermissionsReceiverTransmitter
35
+ import com.rooksdk.broadcasts.SamsungHealthPermissionsReceiverTransmitter
36
+ import com.rooksdk.utils.DatasourceUtils
37
+ import com.rooksdk.utils.DatasourceUtils.mapToDataSourceType
38
+ import com.rooksdk.utils.PermissionConversion
39
+ import com.rooksdk.utils.ReadableToWritable
40
+ import com.rooksdk.utils.RookDateTime
41
+ import com.rooksdk.utils.RookGsonBuilder
42
+ import com.rooksdk.utils.SamsungAvailability
43
+ import com.rooksdk.utils.Source
44
+ import com.rooksdk.utils.StringToSyncType
45
+ import io.tryrook.api.sources.RookApiSources
46
+ import io.tryrook.api.sources.domain.environment.ApiEnvironment
47
+ import io.tryrook.api.sources.domain.exception.ApiException
48
+ import io.tryrook.api.sources.domain.model.ApiConfiguration
49
+ import io.tryrook.sdk.samsung.RookSamsung
50
+ import io.tryrook.sdk.samsung.domain.analytics.SHRookAnalytics
51
+ import io.tryrook.sdk.samsung.domain.analytics.SHRookFramework
52
+ import io.tryrook.sdk.samsung.domain.enums.SHRequestPermissionsStatus
53
+ import io.tryrook.sdk.samsung.domain.enums.SHSyncStatus
54
+ import io.tryrook.sdk.samsung.domain.enums.SamsungHealthAvailability
55
+ import io.tryrook.sdk.samsung.domain.enums.SamsungHealthPermission
56
+ import io.tryrook.sdk.samsung.domain.environment.SHEnvironment
57
+ import io.tryrook.sdk.samsung.domain.exception.SHException
58
+ import io.tryrook.sdk.samsung.domain.model.SHActivityEvent
59
+ import io.tryrook.sdk.samsung.domain.model.SHBodySummary
60
+ import io.tryrook.sdk.samsung.domain.model.SHConfiguration
61
+ import io.tryrook.sdk.samsung.domain.model.SHPhysicalSummary
62
+ import io.tryrook.sdk.samsung.domain.model.SHSleepSummary
63
+ import io.tryrook.sdk.samsung.domain.model.SHSyncStatusWithData
64
+ import kotlinx.coroutines.CoroutineScope
65
+ import kotlinx.coroutines.Dispatchers
66
+ import kotlinx.coroutines.SupervisorJob
67
+ import kotlinx.coroutines.launch
6
68
 
7
69
  @ReactModule(name = RookSdkModule.NAME)
8
70
  class RookSdkModule(reactContext: ReactApplicationContext) :
9
71
  NativeRookSdkSpec(reactContext) {
10
72
 
73
+ private var listenerCount = 0
74
+
11
75
  override fun getName(): String {
12
76
  return NAME
13
77
  }
14
78
 
15
- // Example method
16
- // See https://reactnative.dev/docs/native-modules-android
17
- override fun multiply(a: Double, b: Double): Double {
18
- return a * b
79
+ private val rookHealthConnect by lazy {
80
+ RookSyncManager(reactContext)
81
+ }
82
+
83
+ private var scope: CoroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
84
+
85
+ private val rookSync by lazy {
86
+ RookSyncManager(reactContext)
87
+ }
88
+
89
+ private val rookPermissionsManager: RookPermissionsManager by lazy {
90
+ RookPermissionsManager(reactContext)
91
+ }
92
+
93
+ private val rookConfigurationManager: RookConfigurationManager by lazy {
94
+ RookConfigurationManager(reactContext)
95
+ }
96
+
97
+ private val backgroundSyncManager: RookBackgroundSyncManager by lazy {
98
+ RookBackgroundSyncManager(reactContext)
99
+ }
100
+
101
+ private val rookSamsung: RookSamsung by lazy {
102
+ RookSamsung(reactContext)
103
+ }
104
+
105
+ private val rookApiSources: RookApiSources by lazy {
106
+ RookApiSources(reactContext)
107
+ }
108
+
109
+ private val gsonBuilder: Gson by lazy {
110
+ RookGsonBuilder.getGsonBuilder()
111
+ }
112
+
113
+ private val rookStepsManager: RookStepsManager by lazy {
114
+ RookStepsManager(reactContext)
115
+ }
116
+
117
+ private fun tryToSetSamsungUserId() {
118
+ scope.launch {
119
+ val result = rookConfigurationManager.getUserID()
120
+
121
+ if (result != null) {
122
+ val user = rookSamsung.updateUserID(result)
123
+ user.getOrNull()
124
+ }
125
+ }
126
+ }
127
+
128
+ override fun initRook(
129
+ options: ReadableMap?,
130
+ promise: Promise?
131
+ ) {
132
+ if (promise == null) return
133
+
134
+ if (options == null) {
135
+ promise.reject(code = "1001", message = "unknown exception")
136
+ return
137
+ }
138
+
139
+ try {
140
+
141
+ val clientUUID = options.getString("clientUUID")?.trim() ?: ""
142
+ val secret = options.getString("secret")?.trim() ?: ""
143
+ val packageName = options.getString("packageName")?.trim()
144
+
145
+ if (clientUUID.isBlank() || secret.isBlank()) {
146
+ promise.reject(
147
+ code ="3",
148
+ message = "Requested operation needs an authorization level that your clientUUID doesn't have."
149
+ )
150
+ return
151
+ }
152
+
153
+ var environment = RookEnvironment.SANDBOX
154
+ var shEnv = SHEnvironment.SANDBOX
155
+ var apiEnv = ApiEnvironment.SANDBOX
156
+
157
+ if (options.getString("environment") == "production") {
158
+ environment = RookEnvironment.PRODUCTION
159
+ shEnv = SHEnvironment.SANDBOX
160
+ apiEnv = ApiEnvironment.PRODUCTION
161
+ }
162
+
163
+ val rookConfiguration = RookConfiguration(
164
+ environment = environment,
165
+ clientUUID = clientUUID,
166
+ packageName = packageName,
167
+ secret = secret
168
+ )
169
+
170
+ val shConfig = SHConfiguration(
171
+ environment = shEnv,
172
+ clientUUID = clientUUID,
173
+ packageName = packageName,
174
+ secret = secret
175
+ )
176
+
177
+ val apiConfig = ApiConfiguration(
178
+ environment = apiEnv,
179
+ clientUUID = clientUUID,
180
+ packageName = packageName,
181
+ secret = secret
182
+ )
183
+
184
+ val enableLogs = options.getBoolean("enableLogs")
185
+ if(enableLogs) {
186
+ rookConfigurationManager.enableLocalLogs()
187
+ rookSamsung.enableLocalLogs()
188
+ rookApiSources.enableLocalLogs()
189
+ }
190
+
191
+ rookConfigurationManager.setConfiguration(rookConfiguration)
192
+
193
+ HCRookAnalytics.setFramework(HCRookFramework.REACT_NATIVE)
194
+ SHRookAnalytics.setFramework(SHRookFramework.REACT_NATIVE)
195
+
196
+ scope.launch {
197
+ try {
198
+ val result = rookConfigurationManager.initRook()
199
+ rookApiSources.initRook(apiConfig)
200
+
201
+ result.getOrThrow()
202
+
203
+ val availableResult = SamsungAvailability.getSamsungHealthAvailabilityOrDefault(rookSamsung)
204
+
205
+ if (availableResult == SamsungHealthAvailability.INSTALLED) {
206
+ rookSamsung.initRook(shConfig)
207
+ tryToSetSamsungUserId()
208
+ }
209
+
210
+ promise.resolve(true)
211
+ } catch (e: Throwable) {
212
+ when (e) {
213
+ is HCException -> {
214
+ promise.reject(e.code.toString(), e.message, e)
215
+ }
216
+ is SHException -> {
217
+ promise.reject(e.code.toString(), e.message, e)
218
+ }
219
+ else -> {
220
+ promise.reject("1001", e.message, e)
221
+ }
222
+ }
223
+ }
224
+ }
225
+ }
226
+ catch (e: Exception) {
227
+ when (e) {
228
+ is HCException -> {
229
+ promise.reject(e.code.toString(), e.message, e)
230
+ }
231
+ is SHException -> {
232
+ promise.reject(e.code.toString(), e.message, e)
233
+ }
234
+ else -> {
235
+ promise.reject("1001", e.message, e)
236
+ }
237
+ }
238
+ }
239
+ }
240
+
241
+ override fun revokeDataSource(
242
+ userid: String?,
243
+ type: String?,
244
+ promise: Promise?
245
+ ) {
246
+ if (promise == null) return
247
+
248
+ if (type == null || type == "") {
249
+ promise.reject(code = "1001", message = "the type is missing")
250
+ return
251
+ }
252
+
253
+ if (userid == null || userid == "") {
254
+ promise.reject(code = "1001", message = "the user_id is missing")
255
+ return
256
+ }
257
+
258
+ val parsed = mapToDataSourceType(type)
259
+ if(parsed == null) {
260
+ promise.reject(code = "1001", message = "Invalid datasource")
261
+ return
262
+ }
263
+
264
+ scope.launch {
265
+ rookApiSources.revokeDataSource(userID = userid, dataSource = parsed).fold({
266
+ promise.resolve(true)
267
+ }, {
268
+ if (it is ApiException) {
269
+ promise.reject(it.code.toString(), it.message, it)
270
+ } else {
271
+ promise.reject("1001", it.message, it)
272
+ }
273
+ })
274
+ }
275
+ }
276
+
277
+ override fun getDataSourceAuthorizer(
278
+ props: ReadableMap?,
279
+ promise: Promise?
280
+ ) {
281
+ if(promise == null) return
282
+
283
+ if (props == null){
284
+ promise.reject(code = "1001", message = "user and datasource missing")
285
+ return
286
+ }
287
+
288
+ val source = props.getString("dataSource") ?: ""
289
+ val redirect = props.getString("redirectURL")
290
+ val userid = props.getString("userID") ?: ""
291
+
292
+ if (source == "" || userid == "") {
293
+ promise.reject(code = "1001", message = "user and datasource missing")
294
+ return
295
+ }
296
+
297
+ scope.launch {
298
+ rookApiSources.getDataSourceAuthorizer(
299
+ dataSource = source,
300
+ redirectUrl = redirect,
301
+ userID = userid
302
+ ).fold({ value ->
303
+ promise.resolve(gsonBuilder.toJson(value))
304
+ }, {
305
+ if (it is ApiException) {
306
+ promise.reject(it.code.toString(), it.message, it)
307
+ } else {
308
+ promise.reject("1001", it.message, it)
309
+ }
310
+ })
311
+ }
312
+ }
313
+
314
+ override fun getAuthorizedDataSourcesV2(
315
+ userid: String?,
316
+ promise: Promise?
317
+ ) {
318
+ if(promise == null) return
319
+
320
+ if(userid == null || userid == "") {
321
+ promise.reject(code = "1001", message = "missing user id")
322
+ return
323
+ }
324
+
325
+ scope.launch {
326
+ rookApiSources.getAuthorizedDataSourcesV2(
327
+ userID = userid
328
+ ).fold(
329
+ {
330
+ promise.resolve(gsonBuilder.toJson(it))
331
+ }, {
332
+ if (it is ApiException) {
333
+ promise.reject(it.code.toString(), it.message, it)
334
+ } else {
335
+ promise.reject("1001", it.message, it)
336
+ }
337
+ }
338
+ )
339
+ }
340
+ }
341
+
342
+ override fun getUserID(promise: Promise?) {
343
+ if (promise == null) return
344
+
345
+ scope.launch {
346
+ try {
347
+ val user = rookConfigurationManager.getUserID()
348
+ promise.resolve(user)
349
+ }
350
+ catch (it: Exception) {
351
+ if (it is HCException) {
352
+ promise.reject(it.code.toString(), it.message, it)
353
+ } else {
354
+ promise.reject("1001", it.message, it)
355
+ }
356
+ }
357
+ }
358
+ }
359
+
360
+ override fun updateUserID(userID: String?, promise: Promise?) {
361
+ if(promise == null) return
362
+
363
+ if (userID == null || userID == "") {
364
+ promise.reject(code = "1001", message = "Missing user id")
365
+ return
366
+ }
367
+
368
+ scope.launch {
369
+ try {
370
+ if (SamsungAvailability.isSamsungAvailable(rookSamsung)) {
371
+ val samsungResult = rookSamsung.updateUserID(userID)
372
+
373
+ if (samsungResult.isFailure) {
374
+ println("We couldn't initiate the user id in Samsung Health")
375
+ }
376
+
377
+ samsungResult.getOrThrow()
378
+ }
379
+
380
+ val healthConnectResult = rookConfigurationManager.updateUserID(userID)
381
+
382
+ if (healthConnectResult.isFailure) {
383
+ println("We couldn't initiate the user id in Health Connect")
384
+ }
385
+
386
+ healthConnectResult.getOrThrow()
387
+
388
+ promise.resolve(true)
389
+ } catch (it: Exception) {
390
+ if (it is HCException) {
391
+ promise.reject(it.code.toString(), it.message, it)
392
+ } else {
393
+ promise.reject("1001", it.message, it)
394
+ }
395
+ }
396
+ }
397
+ }
398
+
399
+ override fun removeUserFromRook(
400
+ sources: ReadableArray?,
401
+ promise: Promise?
402
+ ) {
403
+ if(promise == null)return
404
+ if (sources == null) {
405
+ promise.reject(code = "1001", message = "Missing datasource")
406
+ return
407
+ }
408
+
409
+ scope.launch {
410
+ try {
411
+ val sources = DatasourceUtils.readableArrayToSourceList(sources)
412
+
413
+ if(Source.HEALTH_CONNECT in sources) {
414
+ val hcResult = rookConfigurationManager.deleteUserFromRook()
415
+ hcResult.getOrThrow()
416
+ }
417
+
418
+ if(Source.SAMSUNG_HEALTH in sources && SamsungAvailability.isSamsungAvailable(rookSamsung)) {
419
+ val hcResult = rookSamsung.deleteUserFromRook()
420
+ hcResult.getOrThrow()
421
+ }
422
+
423
+ promise.resolve(true)
424
+ }
425
+ catch (it: Exception) {
426
+ if (it is HCException) {
427
+ promise.reject(it.code.toString(), it.message, it)
428
+ } else {
429
+ promise.reject("1001", it.message, it)
430
+ }
431
+ }
432
+ }
433
+ }
434
+
435
+ override fun syncUserTimeZone(promise: Promise?) {
436
+ if(promise == null) return
437
+
438
+ scope.launch {
439
+ val result = rookConfigurationManager.syncUserTimeZone()
440
+
441
+ result.fold({
442
+ promise.resolve(true)
443
+ }, {
444
+ if (it is HCException) {
445
+ promise.reject(it.code.toString(), it.message, it)
446
+ } else {
447
+ promise.reject("1001", it.message, it)
448
+ }
449
+ })
450
+ }
451
+ }
452
+
453
+ override fun getHealthConnectDiagnosticState(promise: Promise?) {
454
+ if (promise == null) return
455
+
456
+ scope.launch {
457
+ try {
458
+ val result = rookConfigurationManager.getDiagnosticState().getOrThrow()
459
+ promise.resolve(gsonBuilder.toJson(result))
460
+ } catch (it: Exception) {
461
+ if (it is HCException) {
462
+ promise.reject(it.code.toString(), it.message, it)
463
+ } else {
464
+ promise.reject("1001", it.message, it)
465
+ }
466
+ }
467
+ }
468
+ }
469
+
470
+ override fun getSamsungHealthDiagnosticState(promise: Promise?) {
471
+ if (promise == null) return
472
+
473
+ scope.launch {
474
+ try {
475
+ val result = rookSamsung.getDiagnosticState().getOrThrow()
476
+ promise.resolve(gsonBuilder.toJson(result))
477
+ } catch (it: Exception) {
478
+ if (it is HCException) {
479
+ promise.reject(it.code.toString(), it.message, it)
480
+ } else {
481
+ promise.reject("1001", it.message, it)
482
+ }
483
+ }
484
+ }
485
+ }
486
+
487
+ override fun isStepsAvailable(promise: Promise?) {
488
+ if (promise == null) return
489
+ promise.resolve(rookStepsManager.isAvailable())
490
+ }
491
+
492
+ override fun enableBackgroundAndroidSteps(promise: Promise?) {
493
+ if(promise == null) return
494
+
495
+ rookStepsManager.enableBackgroundAndroidSteps().fold({
496
+ promise.resolve(true)
497
+ }, {
498
+ if (it is HCException) {
499
+ promise.reject(it.code.toString(), it.message, it)
500
+ } else {
501
+ promise.reject("1001", it.message, it)
502
+ }
503
+ })
504
+ }
505
+
506
+ override fun disableBackgroundAndroidSteps(promise: Promise?) {
507
+ if(promise == null) return
508
+
509
+ rookStepsManager
510
+ .disableBackgroundAndroidSteps()
511
+ .fold({
512
+ promise.resolve(true)
513
+ }, {
514
+ if (it is HCException) {
515
+ promise.reject(it.code.toString(), it.message, it)
516
+ } else {
517
+ promise.reject("1001", it.message, it)
518
+ }
519
+ })
520
+ }
521
+
522
+ override fun isBackgroundAndroidStepsActive(promise: Promise?) {
523
+ if(promise == null) return
524
+
525
+ scope.launch {
526
+ val response = rookStepsManager.isBackgroundAndroidStepsActive()
527
+ promise.resolve(response)
528
+ }
529
+ }
530
+
531
+ override fun syncTodayAndroidStepsCount(promise: Promise?) {
532
+ if(promise == null) return
533
+
534
+ scope.launch {
535
+ rookStepsManager
536
+ .syncTodayAndroidStepsCount()
537
+ .fold({
538
+ promise.resolve(it.toString())
539
+ }, {
540
+ if (it is HCException) {
541
+ promise.reject(it.code.toString(), it.message, it)
542
+ } else {
543
+ promise.reject("1001", it.message, it)
544
+ }
545
+ })
546
+ }
547
+ }
548
+
549
+ override fun androidHasBackgroundPermissions(promise: Promise?) {
550
+ if(promise == null) return
551
+
552
+ try {
553
+ val result = rookPermissionsManager.checkAndroidPermissions()
554
+ promise.resolve(result)
555
+ }
556
+ catch (it: Exception) {
557
+ if (it is HCException) {
558
+ promise.reject(it.code.toString(), it.message, it)
559
+ } else {
560
+ promise.reject("1001", it.message, it)
561
+ }
562
+ }
563
+ }
564
+
565
+ override fun checkHealthConnectAvailability(promise: Promise?) {
566
+ if(promise == null) return
567
+
568
+ val r = rookPermissionsManager.checkHealthConnectAvailability()
569
+
570
+ when(r) {
571
+ HealthConnectAvailability.INSTALLED -> promise.resolve("INSTALLED")
572
+ HealthConnectAvailability.NOT_INSTALLED -> promise.resolve("NOT_INSTALLED")
573
+ HealthConnectAvailability.NOT_SUPPORTED -> promise.resolve("NOT_SUPPORTED")
574
+ }
575
+ }
576
+
577
+ override fun checkHealthConnectBackgroundReadStatus(promise: Promise?) {
578
+ if(promise == null) return
579
+
580
+ scope.launch {
581
+ rookPermissionsManager.checkBackgroundReadStatus().fold(
582
+ { status ->
583
+ when (status) {
584
+ BackgroundReadStatus.UNAVAILABLE -> promise.resolve("UNAVAILABLE")
585
+ BackgroundReadStatus.PERMISSION_NOT_GRANTED -> promise.resolve("PERMISSION_NOT_GRANTED")
586
+ BackgroundReadStatus.PERMISSION_GRANTED -> promise.resolve("PERMISSION_GRANTED")
587
+ }
588
+ },
589
+ {
590
+ if (it is HCException) {
591
+ promise.reject(it.code.toString(), it.message, it)
592
+ } else {
593
+ promise.reject("1001", it.message, it)
594
+ }
595
+ }
596
+ )
597
+ }
598
+ }
599
+
600
+ override fun checkSamsungAvailability(promise: Promise?) {
601
+ if (promise == null) return
602
+
603
+ scope.launch {
604
+ rookSamsung.checkSamsungHealthAvailability().fold(
605
+ { availability ->
606
+ when (availability) {
607
+ SamsungHealthAvailability.INSTALLED -> promise.resolve("INSTALLED")
608
+ SamsungHealthAvailability.NOT_INSTALLED -> promise.resolve("NOT_INSTALLED")
609
+ SamsungHealthAvailability.OUTDATED -> promise.resolve("OUTDATED")
610
+ SamsungHealthAvailability.DISABLED -> promise.resolve("DISABLED")
611
+ SamsungHealthAvailability.NOT_READY -> promise.resolve("NOT_READY")
612
+ }
613
+ },
614
+ {
615
+ promise.reject(it)
616
+ },
617
+ )
618
+
619
+ }
620
+ }
621
+
622
+ override fun healthConnectHasPartialPermissions(promise: Promise?) {
623
+ if(promise == null) return
624
+
625
+ scope.launch {
626
+ val result = rookPermissionsManager.checkHealthConnectPermissionsPartially()
627
+
628
+ result.fold({
629
+ promise.resolve(it)
630
+ }, {
631
+ if (it is HCException) {
632
+ promise.reject(it.code.toString(), it.message, it)
633
+ } else {
634
+ promise.reject("1001", it.message, it)
635
+ }
636
+ })
637
+ }
638
+ }
639
+
640
+ override fun healthConnectHasPermissions(promise: Promise?) {
641
+ if(promise == null) return
642
+
643
+ scope.launch {
644
+ val result = rookPermissionsManager.checkHealthConnectPermissions()
645
+
646
+ result.fold({
647
+ promise.resolve(it)
648
+ }, {
649
+ if (it is HCException) {
650
+ promise.reject(it.code.toString(), it.message, it)
651
+ } else {
652
+ promise.reject("1001", it.message, it)
653
+ }
654
+ })
655
+ }
656
+ }
657
+
658
+ override fun samsungHealthHasPermissions(promise: Promise?) {
659
+ if(promise == null) return
660
+
661
+ scope.launch {
662
+ if (!SamsungAvailability.isSamsungAvailable(rookSamsung)){
663
+ promise.reject(Throwable("Samsung health is not available"))
664
+ return@launch
665
+ }
666
+
667
+ rookSamsung.checkSamsungHealthPermissions(SamsungHealthPermission.entries.toSet()).fold(
668
+ { hasAllPermissions ->
669
+ promise.resolve(hasAllPermissions)
670
+ },
671
+ {
672
+ if (it is SHException) {
673
+ promise.reject(it.code.toString(), it.message, it)
674
+ } else {
675
+ promise.reject("1001", it.message, it)
676
+ }
677
+ }
678
+ )
679
+ }
680
+ }
681
+
682
+ override fun samsungHealthHasPartialPermissions(promise: Promise?) {
683
+ if(promise == null) return
684
+
685
+ scope.launch {
686
+ if (!SamsungAvailability.isSamsungAvailable(rookSamsung)){
687
+ promise.reject(Throwable("Samsung health is not available"))
688
+ return@launch
689
+ }
690
+
691
+ rookSamsung.checkSamsungHealthPermissionsPartially(SamsungHealthPermission.entries.toSet()).fold(
692
+ { hasAllPermissions ->
693
+ promise.resolve(hasAllPermissions)
694
+ },
695
+ {
696
+ if (it is SHException) {
697
+ promise.reject(it.code.toString(), it.message, it)
698
+ } else {
699
+ promise.reject("1001", it.message, it)
700
+ }
701
+ }
702
+ )
703
+ }
704
+ }
705
+
706
+ override fun openHealthConnectSettings(promise: Promise?) {
707
+ if (promise == null) return
708
+
709
+ scope.launch {
710
+ val result = rookPermissionsManager.openHealthConnectSettings()
711
+
712
+ result.fold({
713
+ promise.resolve(true)
714
+ },{
715
+ if (it is HCException) {
716
+ promise.reject(it.code.toString(), it.message, it)
717
+ } else {
718
+ promise.reject("1001", it.message, it)
719
+ }
720
+ })
721
+
722
+ }
723
+ }
724
+
725
+ override fun requestAndroidBackgroundPermissions(promise: Promise?) {
726
+ if (promise == null) return
727
+
728
+ try {
729
+ val response = rookPermissionsManager.requestAndroidPermissions()
730
+
731
+ if (response == RequestPermissionsStatus.REQUEST_SENT)
732
+ promise.resolve("REQUEST_SENT")
733
+ else promise.resolve("ALREADY_GRANTED")
734
+ }
735
+ catch (it: Exception) {
736
+ if (it is HCException) {
737
+ promise.reject(it.code.toString(), it.message, it)
738
+ } else {
739
+ promise.reject("1001", it.message, it)
740
+ }
741
+ }
742
+ }
743
+
744
+ override fun requestHealthConnectPermissions(promise: Promise?) {
745
+ if (promise == null) return
746
+
747
+ scope.launch {
748
+ rookPermissionsManager.requestHealthConnectPermissions().fold({
749
+ when(it) {
750
+ RequestPermissionsStatus.REQUEST_SENT -> {
751
+ promise.resolve("REQUEST_SENT")
752
+ }
753
+ RequestPermissionsStatus .ALREADY_GRANTED -> {
754
+ promise.resolve("ALREADY_GRANTED")
755
+ }
756
+ }
757
+ }, {
758
+ if (it is HCException) {
759
+ promise.reject(it.code.toString(), it.message, it)
760
+ } else {
761
+ promise.reject("1001", it.message, it)
762
+ }
763
+ })
764
+ }
765
+ }
766
+
767
+
768
+ override fun requestSamsungHealthPermissions(
769
+ permissions: ReadableArray?,
770
+ promise: Promise?
771
+ ) {
772
+ if (promise == null) return
773
+
774
+ if (permissions == null){
775
+ promise.reject(code = "1001", message = "Missing permissions")
776
+ return
777
+ }
778
+
779
+ val shPermissions = PermissionConversion.parseSamsungPermissions(permissions)
780
+
781
+ scope.launch {
782
+ if (!SamsungAvailability.isSamsungAvailable(rookSamsung)) {
783
+ promise.reject(Throwable("Samsung Health is not available"))
784
+ return@launch
785
+ }
786
+
787
+ rookSamsung.requestSamsungHealthPermissions(shPermissions).fold(
788
+ {
789
+ when (it) {
790
+ SHRequestPermissionsStatus.ALREADY_GRANTED -> promise.resolve("ALREADY_GRANTED")
791
+ SHRequestPermissionsStatus.REQUEST_SENT -> promise.resolve("REQUEST_SENT")
792
+ }
793
+ },
794
+ {
795
+ if (it is SHException) {
796
+ promise.reject(it.code.toString(), it.message, it)
797
+ } else {
798
+ promise.reject("1001", it.message, it)
799
+ }
800
+ }
801
+ )
802
+ }
803
+ }
804
+
805
+ override fun revokeHealthConnectPermissions(promise: Promise?) {
806
+ if(promise == null) return
807
+
808
+ scope.launch {
809
+ rookPermissionsManager.revokeHealthConnectPermissions()
810
+ .fold({
811
+ promise.resolve(true)
812
+ }, {
813
+ if (it is HCException) {
814
+ promise.reject(it.code.toString(), it.message, it)
815
+ } else {
816
+ promise.reject("1001", it.message, it)
817
+ }
818
+ })
819
+ }
820
+ }
821
+
822
+ override fun shouldRequestAndroidBackgroundPermissions(promise: Promise?) {
823
+ if (promise == null) return
824
+
825
+ val activity = reactApplicationContext.currentActivity
826
+
827
+ if (activity == null) {
828
+ promise.reject(Exception("Error trying to request permissions"))
829
+ return
830
+ }
831
+
832
+ try {
833
+ val r = RookPermissionsManager.shouldRequestAndroidPermissions(activity)
834
+ promise.resolve(r)
835
+ }
836
+ catch (it: Exception) {
837
+ if (it is HCException) {
838
+ promise.reject(it.code.toString(), it.message, it)
839
+ } else {
840
+ promise.reject("1001", it.message, it)
841
+ }
842
+ }
843
+ }
844
+
845
+ override fun getHealthConnectSleepSummary(
846
+ date: String?,
847
+ promise: Promise?
848
+ ) {
849
+ if (promise == null) return
850
+
851
+ if (date == null || date == ""){
852
+ promise.reject(code = "1001", message = "Missing date")
853
+ return
854
+ }
855
+
856
+ val localDate = RookDateTime.stringToLocalDate(date)
857
+
858
+ scope.launch {
859
+ rookHealthConnect.getSleepSummary(localDate).fold(
860
+ {
861
+ when (it) {
862
+ SyncStatusWithData.RecordsNotFound -> {
863
+ promise.reject("HealthConnectSleepSummary", "Records Not Found For Date: $date")
864
+ }
865
+
866
+ is SyncStatusWithData.Synced<List<HCSleepSummary>> -> {
867
+ val result =gsonBuilder.toJson(it.data)
868
+ promise.resolve(result)
869
+ }
870
+ }
871
+ },
872
+ {
873
+ if (it is HCException) {
874
+ promise.reject(it.code.toString(), it.message, it)
875
+ } else {
876
+ promise.reject("1001", it.message, it)
877
+ }
878
+ },
879
+ )
880
+ }
881
+ }
882
+
883
+ override fun getSamsungSleepSummary(
884
+ date: String?,
885
+ promise: Promise?
886
+ ) {
887
+ if (promise == null) return
888
+
889
+ if (date == null || date == ""){
890
+ promise.reject(code = "1001", message = "Missin date")
891
+ return
892
+ }
893
+
894
+ val localDate = RookDateTime.stringToLocalDate(date)
895
+
896
+ scope.launch {
897
+ rookSamsung.getSleepSummary(localDate).fold(
898
+ {
899
+ when (it) {
900
+ SHSyncStatusWithData.RecordsNotFound -> {
901
+ promise.reject("SamsungSleepSummary", "Records Not Found For Date: $date")
902
+ }
903
+
904
+ is SHSyncStatusWithData.Synced<List<SHSleepSummary>> -> {
905
+ promise.resolve(gsonBuilder.toJson(it.data))
906
+ }
907
+ }
908
+ },
909
+ {
910
+ if (it is SHException) {
911
+ promise.reject(it.code.toString(), it.message, it)
912
+ } else {
913
+ promise.reject("1001", it.message, it)
914
+ }
915
+ },
916
+ )
917
+ }
918
+ }
919
+
920
+ override fun getHealthConnectBodySummary(
921
+ date: String?,
922
+ promise: Promise?
923
+ ) {
924
+ if (promise == null) return
925
+
926
+ if (date == null || date == ""){
927
+ promise.reject(code = "1001", message = "missing date")
928
+ return
929
+ }
930
+
931
+ val localDate = RookDateTime.stringToLocalDate(date)
932
+
933
+ scope.launch {
934
+ rookHealthConnect.getBodySummary(localDate).fold(
935
+ {
936
+ when (it) {
937
+ SyncStatusWithData.RecordsNotFound -> {
938
+ promise.reject("HealthConnectBodySummary", "Records Not Found For Date: $date")
939
+ }
940
+
941
+ is SyncStatusWithData.Synced<HCBodySummary> -> {
942
+ promise.resolve(gsonBuilder.toJson(it.data))
943
+ }
944
+ }
945
+ },
946
+ {
947
+ if (it is HCException) {
948
+ promise.reject(it.code.toString(), it.message, it)
949
+ } else {
950
+ promise.reject("1001", it.message, it)
951
+ }
952
+ },
953
+ )
954
+ }
955
+ }
956
+
957
+ override fun getSamsungBodySummary(
958
+ date: String?,
959
+ promise: Promise?
960
+ ) {
961
+ if (promise == null) return
962
+
963
+ if (date == null || date == ""){
964
+ promise.reject(code = "1001", message = "missing date")
965
+ return
966
+ }
967
+
968
+ val localDate = RookDateTime.stringToLocalDate(date)
969
+
970
+ scope.launch {
971
+ rookSamsung.getBodySummary(localDate).fold(
972
+ {
973
+ when (it) {
974
+ SHSyncStatusWithData.RecordsNotFound -> {
975
+ promise.reject("SamsungBodySummary", "Records Not Found For Date: $date")
976
+ }
977
+
978
+ is SHSyncStatusWithData.Synced<SHBodySummary> -> {
979
+ promise.resolve(gsonBuilder.toJson(it.data))
980
+ }
981
+ }
982
+ },
983
+ {
984
+ if (it is SHException) {
985
+ promise.reject(it.code.toString(), it.message, it)
986
+ } else {
987
+ promise.reject("1001", it.message, it)
988
+ }
989
+ },
990
+ )
991
+ }
992
+ }
993
+
994
+ override fun getHealthConnectPhysicalSummary(
995
+ date: String?,
996
+ promise: Promise?
997
+ ) {
998
+ if (promise == null) return
999
+
1000
+ if (date == null || date == ""){
1001
+ promise.reject(code = "1001", message = "missing date")
1002
+ return
1003
+ }
1004
+
1005
+ val localDate = RookDateTime.stringToLocalDate(date)
1006
+
1007
+ scope.launch {
1008
+ rookHealthConnect.getPhysicalSummary(localDate).fold(
1009
+ {
1010
+ when (it) {
1011
+ SyncStatusWithData.RecordsNotFound -> {
1012
+ promise.reject("HealthConnectPhysicalSummary", "Records Not Found For Date: $date")
1013
+ }
1014
+
1015
+ is SyncStatusWithData.Synced<HCPhysicalSummary> -> {
1016
+ promise.resolve(gsonBuilder.toJson(it.data))
1017
+ }
1018
+ }
1019
+ },
1020
+ {
1021
+ if (it is HCException) {
1022
+ promise.reject(it.code.toString(), it.message, it)
1023
+ } else {
1024
+ promise.reject("1001", it.message, it)
1025
+ }
1026
+ },
1027
+ )
1028
+ }
1029
+ }
1030
+
1031
+ override fun getSamsungPhysicalSummary(
1032
+ date: String?,
1033
+ promise: Promise?
1034
+ ) {
1035
+ if (promise == null) return
1036
+
1037
+ if (date == null || date == ""){
1038
+ promise.reject(code = "1001", message = "missing date")
1039
+ return
1040
+ }
1041
+
1042
+ val localDate = RookDateTime.stringToLocalDate(date)
1043
+
1044
+ scope.launch {
1045
+ rookSamsung.getPhysicalSummary(localDate).fold(
1046
+ {
1047
+ when (it) {
1048
+ SHSyncStatusWithData.RecordsNotFound -> {
1049
+ promise.reject("SamsungPhysicalSummary", "Records Not Found For Date: $date")
1050
+ }
1051
+
1052
+ is SHSyncStatusWithData.Synced<SHPhysicalSummary> -> {
1053
+ promise.resolve(gsonBuilder.toJson(it.data))
1054
+ }
1055
+ }
1056
+ },
1057
+ {
1058
+ if (it is SHException) {
1059
+ promise.reject(it.code.toString(), it.message, it)
1060
+ } else {
1061
+ promise.reject("1001", it.message, it)
1062
+ }
1063
+ },
1064
+ )
1065
+ }
1066
+ }
1067
+
1068
+ override fun getHealthConnectActivityEvents(
1069
+ date: String?,
1070
+ promise: Promise?
1071
+ ) {
1072
+ if (promise == null) return
1073
+
1074
+ if (date == null || date == ""){
1075
+ promise.reject(code = "1001", message = "missing date")
1076
+ return
1077
+ }
1078
+
1079
+ val localDate = RookDateTime.stringToLocalDate(date)
1080
+
1081
+ scope.launch {
1082
+ rookHealthConnect.getActivityEvents(localDate).fold(
1083
+ {
1084
+ when (it) {
1085
+ SyncStatusWithData.RecordsNotFound -> {
1086
+ promise.reject("HealthConnectActivityEvents", "Records Not Found For Date: $date")
1087
+ }
1088
+
1089
+ is SyncStatusWithData.Synced<List<HCActivityEvent>> -> {
1090
+ promise.resolve(gsonBuilder.toJson(it.data))
1091
+ }
1092
+ }
1093
+ },
1094
+ {
1095
+ if (it is HCException) {
1096
+ promise.reject(it.code.toString(), it.message, it)
1097
+ } else {
1098
+ promise.reject("1001", it.message, it)
1099
+ }
1100
+ },
1101
+ )
1102
+ }
1103
+ }
1104
+
1105
+ override fun getSamsungActivityEvents(
1106
+ date: String?,
1107
+ promise: Promise?
1108
+ ) {
1109
+ if (promise == null) return
1110
+
1111
+ if (date == null || date == ""){
1112
+ promise.reject(code = "1001", message = "missing date")
1113
+ return
1114
+ }
1115
+
1116
+ val localDate = RookDateTime.stringToLocalDate(date)
1117
+
1118
+ scope.launch {
1119
+ rookSamsung.getActivityEvents(localDate).fold(
1120
+ {
1121
+ when (it) {
1122
+ SHSyncStatusWithData.RecordsNotFound -> {
1123
+ promise.reject("SamsungActivityEvents", "Records Not Found For Date: $date")
1124
+ }
1125
+
1126
+ is SHSyncStatusWithData.Synced<List<SHActivityEvent>> -> {
1127
+ promise.resolve(gsonBuilder.toJson(it.data))
1128
+ }
1129
+ }
1130
+ },
1131
+ {
1132
+ if (it is SHException) {
1133
+ promise.reject(it.code.toString(), it.message, it)
1134
+ } else {
1135
+ promise.reject("1001", it.message, it)
1136
+ }
1137
+ },
1138
+ )
1139
+ }
1140
+ }
1141
+
1142
+ @OptIn(ExperimentalRookApi::class)
1143
+ override fun writeHealthConnectMealData(
1144
+ meal: ReadableMap?,
1145
+ promise: Promise?
1146
+ ) {
1147
+ if (promise == null) return
1148
+
1149
+ if (meal == null){
1150
+ promise.reject(code = "1001", message = "Missing meal data")
1151
+ return
1152
+ }
1153
+
1154
+ val mealData = ReadableToWritable.mapReadableMapToHCMealData(meal)
1155
+
1156
+ scope.launch {
1157
+ RookWriteManager.writeNutritionEvent(reactApplicationContext, mealData).fold({
1158
+ promise.resolve(true)
1159
+ }, {
1160
+ if (it is HCException) {
1161
+ promise.reject(it.code.toString(), it.message, it)
1162
+ } else {
1163
+ promise.reject("1001", it.message, it)
1164
+ }
1165
+ })
1166
+ }
1167
+ }
1168
+
1169
+ override fun enableSamsungSync(promise: Promise?) {
1170
+ if (promise == null) return
1171
+
1172
+ scope.launch {
1173
+ rookSamsung.schedule(true)
1174
+ promise.resolve(true)
1175
+ }
1176
+ }
1177
+
1178
+ override fun disableSamsungSync(promise: Promise?) {
1179
+ if (promise == null) return
1180
+
1181
+ scope.launch {
1182
+ rookSamsung.cancel()
1183
+ promise.resolve(true)
1184
+ }
1185
+ }
1186
+
1187
+ override fun isSamsungSyncEnabled(promise: Promise?) {
1188
+ if (promise == null) return
1189
+
1190
+ scope.launch {
1191
+ rookSamsung.isScheduled().fold(
1192
+ {
1193
+ promise.resolve(it)
1194
+ },
1195
+ {
1196
+ if (it is SHException) {
1197
+ promise.reject(it.code.toString(), it.message, it)
1198
+ } else {
1199
+ promise.reject("1001", it.message, it)
1200
+ }
1201
+ }
1202
+ )
1203
+ }
1204
+ }
1205
+
1206
+ override fun scheduleBackgroundSync(
1207
+ enableLogs: Boolean?,
1208
+ promise: Promise?
1209
+ ) {
1210
+ if (promise == null) return
1211
+
1212
+ try {
1213
+ backgroundSyncManager.schedule(enableLogs ?: false)
1214
+ promise.resolve(true)
1215
+ }
1216
+ catch (e: Exception) {
1217
+ if (e is HCException) {
1218
+ promise.reject(e.code.toString(), e.message, e)
1219
+ } else {
1220
+ promise.reject("1001", e.message, e)
1221
+ }
1222
+ }
1223
+ }
1224
+
1225
+ override fun cancelBackgroundSync(promise: Promise?) {
1226
+ if (promise == null) return
1227
+
1228
+ scope.launch {
1229
+ try {
1230
+ backgroundSyncManager.cancel()
1231
+ promise.resolve(true)
1232
+ } catch (e: Exception) {
1233
+ if (e is HCException) {
1234
+ promise.reject(e.code.toString(), e.message, e)
1235
+ } else {
1236
+ promise.reject("1001", e.message, e)
1237
+ }
1238
+ }
1239
+ }
1240
+ }
1241
+
1242
+ override fun isBackgroundSyncEnabled(promise: Promise?) {
1243
+ if (promise == null) return
1244
+
1245
+ scope.launch {
1246
+ backgroundSyncManager.isScheduled().fold(
1247
+ {
1248
+ promise.resolve(it)
1249
+ },
1250
+ {
1251
+ if (it is HCException) {
1252
+ promise.reject(it.code.toString(), it.message, it)
1253
+ } else {
1254
+ promise.reject("1001", it.message, it)
1255
+ }
1256
+ }
1257
+ )
1258
+ }
1259
+ }
1260
+
1261
+ override fun syncTodaySamsungHealthStepsCount(promise: Promise?) {
1262
+ if (promise == null) return
1263
+
1264
+ scope.launch {
1265
+ rookSamsung.getTodayStepsCount().fold({
1266
+ when (it) {
1267
+ SHSyncStatusWithData.RecordsNotFound -> {
1268
+ promise.reject("SamsungStepsCount", "Records Not Found")
1269
+ }
1270
+
1271
+ is SHSyncStatusWithData.Synced -> {
1272
+ val steps = it.data
1273
+ promise.resolve(steps)
1274
+ }
1275
+ }
1276
+ }, {
1277
+ if (it is SHException) {
1278
+ promise.reject(it.code.toString(), it.message, it)
1279
+ } else {
1280
+ promise.reject("1001", it.message, it)
1281
+ }
1282
+ })
1283
+ }
1284
+ }
1285
+
1286
+ override fun syncTodayHealthConnectStepsCount(promise: Promise?) {
1287
+ if (promise == null) return
1288
+
1289
+ scope.launch {
1290
+ rookSync.getTodayStepsCount().fold(
1291
+ {
1292
+ when (it) {
1293
+ SyncStatusWithData.RecordsNotFound -> {
1294
+ promise.reject("HealthConnectStepsCount", "Records Not Found")
1295
+ }
1296
+
1297
+ is SyncStatusWithData.Synced -> {
1298
+ val steps = it.data
1299
+ promise.resolve(steps)
1300
+ }
1301
+ }
1302
+ },
1303
+ {
1304
+ if (it is HCException) {
1305
+ promise.reject(it.code.toString(), it.message, it)
1306
+ } else {
1307
+ promise.reject("1001", it.message, it)
1308
+ }
1309
+ }
1310
+ )
1311
+ }
1312
+ }
1313
+
1314
+ override fun syncTodayCaloriesCount(promise: Promise?) {
1315
+ if (promise == null) return
1316
+
1317
+ scope.launch {
1318
+ rookSync.getTodayCaloriesCount().fold(
1319
+ {
1320
+ when (it) {
1321
+ SyncStatusWithData.RecordsNotFound -> {
1322
+ promise.reject("7", "The SDK could not find any health data related with calories")
1323
+ }
1324
+
1325
+ is SyncStatusWithData.Synced -> {
1326
+ val data = Arguments.createMap().apply {
1327
+ putDouble("basal", it.data.basal ?: 0.0)
1328
+ putDouble("active", it.data.active ?: 0.0)
1329
+ }
1330
+
1331
+ promise.resolve(data)
1332
+ }
1333
+ }
1334
+ },
1335
+ {
1336
+ if (it is HCException) {
1337
+ promise.reject(it.code.toString(), it.message, it)
1338
+ } else {
1339
+ promise.reject("1001", it.message, it)
1340
+ }
1341
+ }
1342
+ )
1343
+ }
1344
+ }
1345
+
1346
+ override fun syncSHTodayCaloriesCount(promise: Promise?) {
1347
+ if (promise == null) return
1348
+
1349
+ scope.launch {
1350
+ rookSamsung.getTodayCaloriesCount().fold(
1351
+ {
1352
+ when (it) {
1353
+ SHSyncStatusWithData.RecordsNotFound -> {
1354
+ promise.reject("7", "The SDK could not find any health data related with calories")
1355
+ }
1356
+
1357
+ is SHSyncStatusWithData.Synced -> {
1358
+ val data = Arguments.createMap().apply {
1359
+ putDouble("basal", it.data.basal ?: 0.0)
1360
+ putDouble("active", it.data.active ?: 0.0)
1361
+ }
1362
+
1363
+ promise.resolve(data)
1364
+ }
1365
+ }
1366
+ },
1367
+ {
1368
+ if (it is SHException) {
1369
+ promise.reject(it.code.toString(), it.message, it)
1370
+ } else {
1371
+ promise.reject("1001", it.message, it)
1372
+ }
1373
+ }
1374
+ )
1375
+ }
1376
+ }
1377
+
1378
+ override fun getTodayHeartRate(promise: Promise?) {
1379
+ if (promise == null) return
1380
+
1381
+ scope.launch {
1382
+ rookSync.getTodayHeartRate().fold(
1383
+ { syncStatus ->
1384
+ when (syncStatus) {
1385
+ SyncStatusWithData.RecordsNotFound -> {
1386
+ promise.reject("7", "The SDK could not find any health data related with calories")
1387
+ }
1388
+
1389
+ is SyncStatusWithData.Synced -> {
1390
+ promise.resolve(gsonBuilder.toJson(syncStatus.data))
1391
+ }
1392
+ }
1393
+ },
1394
+ {
1395
+ if (it is HCException) {
1396
+ promise.reject(it.code.toString(), it.message, it)
1397
+ } else {
1398
+ promise.reject("1001", it.message, it)
1399
+ }
1400
+ },
1401
+ )
1402
+ }
1403
+ }
1404
+
1405
+ override fun getSHTodayHeartRate(promise: Promise?) {
1406
+ if (promise == null) return
1407
+ scope.launch {
1408
+ rookSamsung.getTodayHeartRate().fold(
1409
+ { syncStatus ->
1410
+ when (syncStatus) {
1411
+ SHSyncStatusWithData.RecordsNotFound -> {
1412
+ promise.reject("7", "The SDK could not find any health data related with calories")
1413
+ }
1414
+
1415
+ is SHSyncStatusWithData.Synced -> {
1416
+ promise.resolve(gsonBuilder.toJson(syncStatus.data))
1417
+ }
1418
+ }
1419
+ },
1420
+ {
1421
+ if (it is HCException) {
1422
+ promise.reject(it.code.toString(), it.message, it)
1423
+ } else {
1424
+ promise.reject("1001", it.message, it)
1425
+ }
1426
+ },
1427
+ )
1428
+ }
1429
+ }
1430
+
1431
+ override fun sync(cb: Callback?) {
1432
+ if (cb == null) return
1433
+
1434
+ scope.launch {
1435
+ rookSync.sync(true).fold({ result ->
1436
+ cb.invoke(null, result)
1437
+ }, {
1438
+ val params = Arguments.createMap().apply {
1439
+ if (it is HCException) {
1440
+ putString(it.code.toString(), it.message)
1441
+ } else {
1442
+ putString("1001", it.localizedMessage ?: it.message)
1443
+ }
1444
+ }
1445
+
1446
+ cb.invoke(params, false)
1447
+ })
1448
+ }
1449
+ }
1450
+
1451
+ override fun syncByDate(date: String?, cb: Callback?) {
1452
+ if(cb == null ) return
1453
+
1454
+ if (date == null || date == "") {
1455
+ cb.invoke(null, false)
1456
+ return
1457
+ }
1458
+
1459
+ val localDate = RookDateTime.stringToLocalDate(date)
1460
+
1461
+ scope.launch {
1462
+ val result = rookSync.sync(localDate)
1463
+
1464
+ try {
1465
+ val sleepSummaryStatus = result.sleepSummary.getOrThrow()
1466
+ val physicalSummaryStatus = result.physicalSummary.getOrThrow()
1467
+ val bodySummaryStatus = result.bodySummary.getOrThrow()
1468
+
1469
+ val noSleepData = sleepSummaryStatus == SyncStatus.RECORDS_NOT_FOUND
1470
+ val noPhysicalData = physicalSummaryStatus == SyncStatus.RECORDS_NOT_FOUND
1471
+ val noBodyData = bodySummaryStatus == SyncStatus.RECORDS_NOT_FOUND
1472
+
1473
+ if (noSleepData && noPhysicalData && noBodyData) {
1474
+ val throwable = HCRecordsNotFoundException("Sleep, Physical and Body summary")
1475
+
1476
+ val params = Arguments.createMap().apply {
1477
+ putString(throwable.code.toString(), throwable.message)
1478
+ }
1479
+
1480
+ cb.invoke(params, false)
1481
+ } else {
1482
+ cb.invoke(null, true)
1483
+ }
1484
+ } catch (e: Exception) {
1485
+ val params = Arguments.createMap().apply {
1486
+ if (e is HCException){
1487
+ putString(e.code.toString(), e.message)
1488
+ } else {
1489
+ putString("1001", e.message ?: "Unknown error")
1490
+ }
1491
+ }
1492
+
1493
+ cb.invoke(params, false)
1494
+ }
1495
+ }
1496
+ }
1497
+
1498
+ override fun syncByDefinition(
1499
+ summary: String?,
1500
+ date: String?,
1501
+ cb: Callback?
1502
+ ) {
1503
+ if(cb == null ) return
1504
+
1505
+ if (date == null || date == "" || summary == null || summary == "") {
1506
+ cb.invoke(null, false)
1507
+ return
1508
+ }
1509
+
1510
+ val localDate = RookDateTime.stringToLocalDate(date)
1511
+
1512
+ val type = StringToSyncType.stringToSummary(summary)
1513
+
1514
+ scope.launch {
1515
+ val result = rookSync.sync(localDate, type)
1516
+ result.onSuccess {
1517
+ when (it) {
1518
+ SyncStatus.RECORDS_NOT_FOUND -> {
1519
+ val throwable = HCRecordsNotFoundException(type.toString())
1520
+
1521
+ val params = Arguments.createMap().apply {
1522
+ putString(throwable.code.toString(), throwable.message)
1523
+ }
1524
+
1525
+ cb.invoke(params, false)
1526
+ }
1527
+ SyncStatus.SYNCED -> cb.invoke(null, true)
1528
+ }
1529
+ }
1530
+
1531
+ result.onFailure {
1532
+ val params = Arguments.createMap().apply {
1533
+ if (it is HCException) {
1534
+ putString(it.code.toString(), it.message)
1535
+ } else {
1536
+ putString("1001", it.localizedMessage ?: it.message)
1537
+ }
1538
+ }
1539
+
1540
+ cb.invoke(params, false)
1541
+ }
1542
+ }
1543
+ }
1544
+
1545
+ override fun syncEvent(
1546
+ date: String?,
1547
+ event: String?,
1548
+ promise: Promise?
1549
+ ) {
1550
+ if (promise == null) return
1551
+ if (event == null || event == "" || date == null || date == "") {
1552
+ promise.reject(code = "1001", message = "Missing parameters")
1553
+ return
1554
+ }
1555
+
1556
+ val localDate = RookDateTime.stringToLocalDate(date)
1557
+ val type = StringToSyncType.stringToEvent(event)
1558
+
1559
+ scope.launch {
1560
+ rookSync.syncEvents(localDate, type).fold({ result ->
1561
+ when(result) {
1562
+ SyncStatus.RECORDS_NOT_FOUND -> {
1563
+ val throwable = HCRecordsNotFoundException(type.toString())
1564
+
1565
+ promise.reject(throwable.code.toString(), throwable.message, throwable)
1566
+ }
1567
+ SyncStatus.SYNCED -> promise.resolve(true)
1568
+ }
1569
+ }, {
1570
+ if (it is HCException) {
1571
+ promise.reject(it.code.toString(), it.message, it)
1572
+ } else {
1573
+ promise.reject("1001", it.message, it)
1574
+ }
1575
+ })
1576
+ }
1577
+ }
1578
+
1579
+ override fun shSync(enableLogs: Boolean, cb: Callback?) {
1580
+ if (cb == null) return
1581
+
1582
+ scope.launch {
1583
+ if (!SamsungAvailability.isSamsungAvailable(rookSamsung)){
1584
+ val params = Arguments.createMap().apply {
1585
+ putString("5", "Samsung health is not available")
1586
+ }
1587
+
1588
+ cb.invoke(params, false)
1589
+ return@launch
1590
+ }
1591
+
1592
+ rookSamsung.sync(enableLogs).fold(
1593
+ {
1594
+ cb(null, true)
1595
+ }, {
1596
+ val params = Arguments.createMap().apply {
1597
+ if (it is SHException) {
1598
+ putString(it.code.toString(), it.message)
1599
+ } else {
1600
+ putString("1001", it.localizedMessage ?: it.message)
1601
+ }
1602
+ }
1603
+
1604
+ cb.invoke(params, false)
1605
+ }
1606
+ )
1607
+ }
1608
+ }
1609
+
1610
+ override fun shSyncByDate(date: String?, cb: Callback?) {
1611
+ if (cb == null) return
1612
+
1613
+ val localDate = RookDateTime.stringToLocalDate(date ?: "")
1614
+
1615
+ scope.launch {
1616
+ if (!SamsungAvailability.isSamsungAvailable(rookSamsung)){
1617
+ val params = Arguments.createMap().apply {
1618
+ putString("5", "Samsung health is not available")
1619
+ }
1620
+
1621
+ cb.invoke(params, false)
1622
+ return@launch
1623
+ }
1624
+
1625
+ val result = rookSamsung.sync(localDate)
1626
+
1627
+ try {
1628
+ val sleepSummaryStatus = result.sleepSummary.getOrThrow()
1629
+ val physicalSummaryStatus = result.physicalSummary.getOrThrow()
1630
+ val bodySummaryStatus = result.bodySummary.getOrThrow()
1631
+
1632
+ val noSleepData = sleepSummaryStatus == SHSyncStatus.RECORDS_NOT_FOUND
1633
+ val noPhysicalData = physicalSummaryStatus == SHSyncStatus.RECORDS_NOT_FOUND
1634
+ val noBodyData = bodySummaryStatus == SHSyncStatus.RECORDS_NOT_FOUND
1635
+
1636
+ if (noSleepData && noPhysicalData && noBodyData) {
1637
+ val throwable = HCRecordsNotFoundException("Sleep, Physical and Body summary")
1638
+
1639
+ val params = Arguments.createMap().apply {
1640
+ putString(throwable.code.toString(), throwable.message)
1641
+ }
1642
+
1643
+ cb.invoke(params, false)
1644
+ } else {
1645
+ cb.invoke(null, true)
1646
+ }
1647
+ } catch (e: Exception) {
1648
+ val params = Arguments.createMap().apply {
1649
+ if (e is HCException){
1650
+ putString(e.code.toString(), e.message)
1651
+ } else {
1652
+ putString("1001", e.message ?: "Unknown error")
1653
+ }
1654
+ }
1655
+
1656
+ cb.invoke(params, false)
1657
+ }
1658
+ }
1659
+ }
1660
+
1661
+ override fun shSyncByDefinition(
1662
+ summary: String?,
1663
+ date: String?,
1664
+ cb: Callback?
1665
+ ) {
1666
+ if (cb == null) return
1667
+ if (summary == null || date == null) {
1668
+ cb.invoke(null, false)
1669
+ return
1670
+ }
1671
+
1672
+ val localDate = RookDateTime.stringToLocalDate(date)
1673
+ val type = StringToSyncType.stringToSamsungPillar(summary)
1674
+
1675
+ scope.launch {
1676
+ if (!SamsungAvailability.isSamsungAvailable(rookSamsung)){
1677
+ val params = Arguments.createMap().apply {
1678
+ putString("5", "Samsung health is not available")
1679
+ }
1680
+
1681
+ cb.invoke(params, false)
1682
+ return@launch
1683
+ }
1684
+
1685
+ val result = rookSamsung.sync(localDate, type)
1686
+ result.onSuccess {
1687
+ when (it) {
1688
+ SHSyncStatus.RECORDS_NOT_FOUND -> {
1689
+ val throwable = HCRecordsNotFoundException(type.toString())
1690
+
1691
+ val params = Arguments.createMap().apply {
1692
+ putString(throwable.code.toString(), throwable.message)
1693
+ }
1694
+
1695
+ cb.invoke(params, false)
1696
+ }
1697
+ SHSyncStatus.SYNCED -> cb.invoke(null, true)
1698
+ }
1699
+ }
1700
+
1701
+ result.onFailure {
1702
+ val params = Arguments.createMap().apply {
1703
+ if (it is HCException) {
1704
+ putString(it.code.toString(), it.message)
1705
+ } else {
1706
+ putString("1001", it.localizedMessage ?: it.message)
1707
+ }
1708
+ }
1709
+
1710
+ cb.invoke(params, false)
1711
+ }
1712
+ }
1713
+ }
1714
+
1715
+ override fun shSyncEvent(
1716
+ date: String?,
1717
+ event: String?,
1718
+ promise: Promise?
1719
+ ) {
1720
+ if(promise == null) return
1721
+ if (event == null || date == null){
1722
+ promise.reject(code = "1001", message = "Missing parameters")
1723
+ return
1724
+ }
1725
+
1726
+ val localDate = RookDateTime.stringToLocalDate(date)
1727
+ val type = StringToSyncType.stringToSamsungEvent(event)
1728
+
1729
+ scope.launch {
1730
+ if (!SamsungAvailability.isSamsungAvailable(rookSamsung)){
1731
+ promise.reject(
1732
+ "5",
1733
+ "Samsung health is not available",
1734
+ Throwable("Samsung health is not available")
1735
+ )
1736
+ return@launch
1737
+ }
1738
+
1739
+ rookSamsung.syncEvents(localDate, type).fold({ result ->
1740
+ when(result) {
1741
+ SHSyncStatus.RECORDS_NOT_FOUND -> {
1742
+ val throwable = HCRecordsNotFoundException(type.toString())
1743
+
1744
+ promise.reject(throwable.code.toString(), throwable.message, throwable)
1745
+ }
1746
+ SHSyncStatus.SYNCED -> promise.resolve(true)
1747
+ }
1748
+ }, {
1749
+ if (it is HCException) {
1750
+ promise.reject(it.code.toString(), it.message, it)
1751
+ } else {
1752
+ promise.reject("1001", it.message, it)
1753
+ }
1754
+ })
1755
+ }
1756
+ }
1757
+
1758
+ override fun sendMessage(
1759
+ message: ReadableMap?,
1760
+ promise: Promise?
1761
+ ) {
1762
+ if (message == null || promise == null || !reactApplicationContext.hasActiveReactInstance())
1763
+ return
1764
+
1765
+ val hash = ReadableToWritable.readableMapToHashMap(message)
1766
+ val writable = ReadableToWritable.hashMapToWritableMap(hash)
1767
+
1768
+ emitOnRookMessage(writable)
1769
+ promise.resolve(true)
1770
+ }
1771
+
1772
+
1773
+ // ios methods
1774
+ private fun rejectFunction(promise: Promise) {
1775
+ promise.reject("1001", "This method is only available in android")
1776
+ }
1777
+
1778
+ override fun getDiagnosticState(promise: Promise?) {
1779
+ if (promise == null) return
1780
+ rejectFunction(promise)
1781
+ }
1782
+
1783
+ override fun enableBackGroundUpdates(promise: Promise?) {
1784
+ if (promise == null) return
1785
+ rejectFunction(promise)
1786
+ }
1787
+
1788
+ override fun disableBackGroundUpdates(promise: Promise?) {
1789
+ if (promise == null) return
1790
+ rejectFunction(promise)
1791
+ }
1792
+
1793
+ override fun isBackgroundUpdatesEnabled(promise: Promise?) {
1794
+ if (promise == null) return
1795
+ rejectFunction(promise)
1796
+ }
1797
+
1798
+ override fun appleHealthHasPermissions(
1799
+ param: String?,
1800
+ promise: Promise?
1801
+ ) {
1802
+ if (promise == null) return
1803
+ rejectFunction(promise)
1804
+ }
1805
+
1806
+ override fun openAppleHealthSettings(promise: Promise?) {
1807
+ if (promise == null) return
1808
+ rejectFunction(promise)
1809
+ }
1810
+
1811
+ override fun requestAppleHealthPermissions(
1812
+ permissions: ReadableArray?,
1813
+ promise: Promise?
1814
+ ) {
1815
+ if (promise == null) return
1816
+ rejectFunction(promise)
1817
+ }
1818
+
1819
+ override fun requestAppleWriteNutritionPermission(promise: Promise?) {
1820
+ if (promise == null) return
1821
+ rejectFunction(promise)
1822
+ }
1823
+
1824
+ override fun getAppleHealthSleepSummary(
1825
+ date: String?,
1826
+ promise: Promise?
1827
+ ) {
1828
+ if (promise == null) return
1829
+ rejectFunction(promise)
1830
+ }
1831
+
1832
+ override fun getAppleHealthBodySummary(
1833
+ date: String?,
1834
+ promise: Promise?
1835
+ ) {
1836
+ if (promise == null) return
1837
+ rejectFunction(promise)
1838
+ }
1839
+
1840
+ override fun getAppleHealthPhysicalSummary(
1841
+ date: String?,
1842
+ promise: Promise?
1843
+ ) {
1844
+ if (promise == null) return
1845
+ rejectFunction(promise)
1846
+ }
1847
+
1848
+ override fun getAppleHealthActivityEvents(
1849
+ date: String?,
1850
+ promise: Promise?
1851
+ ) {
1852
+ if (promise == null) return
1853
+ rejectFunction(promise)
1854
+ }
1855
+
1856
+ override fun writeAppleHealthMealData(
1857
+ meal: ReadableMap?,
1858
+ promise: Promise?
1859
+ ) {
1860
+ if (promise == null) return
1861
+ rejectFunction(promise)
19
1862
  }
20
1863
 
21
- override fun simplePromise(promise: Promise?) {
22
- TODO("Not yet implemented")
1864
+ override fun getTodayAppleHealthSteps(promise: Promise?) {
1865
+ if (promise == null) return
1866
+ rejectFunction(promise)
23
1867
  }
24
1868
 
25
1869
  companion object {