@tryvital/vital-health-react-native 5.4.3 → 6.0.0-rc.1

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 (38) hide show
  1. package/android/build.gradle +27 -1
  2. package/android/src/main/java/com/vitalhealthreactnative/HealthConnectVitalHealthProvider.kt +162 -0
  3. package/android/src/main/java/com/vitalhealthreactnative/UnavailableVitalHealthProviderDefinition.kt +37 -0
  4. package/android/src/main/java/com/vitalhealthreactnative/VitalHealthEvent.kt +6 -11
  5. package/android/src/main/java/com/vitalhealthreactnative/VitalHealthProvider.kt +100 -0
  6. package/android/src/main/java/com/vitalhealthreactnative/VitalHealthReactNativeModule.kt +350 -201
  7. package/android/src/samsungHealthDisabled/java/com/vitalhealthreactnative/SamsungHealthVitalHealthProvider.kt +3 -0
  8. package/android/src/samsungHealthEnabled/java/com/vitalhealthreactnative/SamsungHealthVitalHealthProvider.kt +162 -0
  9. package/app.plugin.js +226 -13
  10. package/ios/VitalHealthReactNative.m +28 -14
  11. package/ios/VitalHealthReactNative.swift +192 -100
  12. package/lib/commonjs/app.plugin.js +226 -13
  13. package/lib/commonjs/ask_config.js.map +1 -1
  14. package/lib/commonjs/health_config.js +10 -1
  15. package/lib/commonjs/health_config.js.map +1 -1
  16. package/lib/commonjs/healthkit.js.map +1 -1
  17. package/lib/commonjs/index.js +221 -79
  18. package/lib/commonjs/index.js.map +1 -1
  19. package/lib/module/ask_config.js.map +1 -1
  20. package/lib/module/health_config.js +9 -0
  21. package/lib/module/health_config.js.map +1 -1
  22. package/lib/module/healthkit.js.map +1 -1
  23. package/lib/module/index.js +222 -79
  24. package/lib/module/index.js.map +1 -1
  25. package/lib/typescript/ask_config.d.ts +3 -3
  26. package/lib/typescript/ask_config.d.ts.map +1 -1
  27. package/lib/typescript/health_config.d.ts +8 -0
  28. package/lib/typescript/health_config.d.ts.map +1 -1
  29. package/lib/typescript/healthkit.d.ts +1 -1
  30. package/lib/typescript/healthkit.d.ts.map +1 -1
  31. package/lib/typescript/index.d.ts +55 -19
  32. package/lib/typescript/index.d.ts.map +1 -1
  33. package/package.json +4 -3
  34. package/src/ask_config.ts +16 -16
  35. package/src/health_config.ts +14 -0
  36. package/src/healthkit.ts +205 -234
  37. package/src/index.tsx +332 -81
  38. package/vital-health-react-native.podspec +2 -17
@@ -18,6 +18,20 @@ def isNewArchitectureEnabled() {
18
18
  return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
19
19
  }
20
20
 
21
+ def getSamsungHealthAarPath() {
22
+ if (!rootProject.hasProperty('samsungHealthAarPath')) {
23
+ return null
24
+ }
25
+
26
+ def path = rootProject.getProperty('samsungHealthAarPath')
27
+ return path ? path.toString().trim() : null
28
+ }
29
+
30
+ def hasSamsungHealthAarPath() {
31
+ def path = getSamsungHealthAarPath()
32
+ return path != null && !path.isEmpty()
33
+ }
34
+
21
35
  apply plugin: 'com.android.library'
22
36
  apply plugin: 'kotlin-android'
23
37
 
@@ -56,6 +70,14 @@ android {
56
70
  targetCompatibility JavaVersion.VERSION_1_8
57
71
  }
58
72
 
73
+ sourceSets {
74
+ main {
75
+ java.srcDirs += hasSamsungHealthAarPath()
76
+ ? ['src/samsungHealthEnabled/java']
77
+ : ['src/samsungHealthDisabled/java']
78
+ }
79
+ }
80
+
59
81
  }
60
82
 
61
83
  repositories {
@@ -129,7 +151,7 @@ repositories {
129
151
  }
130
152
 
131
153
  def kotlin_version = getExtOrDefault('kotlinVersion')
132
- def vital_sdk_version = '4.2.2'
154
+ def vital_sdk_version = '5.0.0-rc.1'
133
155
 
134
156
  dependencies {
135
157
  //noinspection GradleDynamicVersion
@@ -140,6 +162,10 @@ dependencies {
140
162
  implementation "io.tryvital:vital-client:$vital_sdk_version"
141
163
  implementation "io.tryvital:vital-health-connect:$vital_sdk_version"
142
164
 
165
+ if (hasSamsungHealthAarPath()) {
166
+ implementation "io.tryvital:vital-samsung-health:$vital_sdk_version"
167
+ }
168
+
143
169
  implementation project(':tryvital_vital-core-react-native')
144
170
  // From node_modules
145
171
  }
@@ -0,0 +1,162 @@
1
+ package com.vitalhealthreactnative
2
+
3
+ import android.content.Context
4
+ import androidx.activity.result.contract.ActivityResultContract
5
+ import io.tryvital.vitalhealthconnect.DefaultSyncNotificationBuilder
6
+ import io.tryvital.vitalhealthconnect.DefaultSyncNotificationContent
7
+ import io.tryvital.vitalhealthconnect.ExperimentalVitalApi
8
+ import io.tryvital.vitalhealthconnect.VitalHealthConnectManager
9
+ import io.tryvital.vitalhealthconnect.autoSyncThrottle
10
+ import io.tryvital.vitalhealthconnect.backgroundSyncMinimumInterval
11
+ import io.tryvital.vitalhealthconnect.disableBackgroundSync
12
+ import io.tryvital.vitalhealthconnect.enableBackgroundSyncContract
13
+ import io.tryvital.vitalhealthconnect.isBackgroundSyncEnabled
14
+ import io.tryvital.vitalhealthconnect.model.PermissionOutcome as HealthConnectPermissionOutcome
15
+ import io.tryvital.vitalhealthcore.model.ConnectionPolicy
16
+ import io.tryvital.vitalhealthcore.model.ProviderAvailability
17
+ import io.tryvital.vitalhealthcore.model.VitalResource
18
+ import io.tryvital.vitalhealthcore.model.WritableVitalResource
19
+ import kotlinx.coroutines.Deferred
20
+ import java.time.Instant
21
+
22
+ internal object HealthConnectVitalHealthProviderDefinition : VitalHealthProviderDefinition {
23
+ override val provider = AndroidProvider.HealthConnect
24
+ override val displayName = "Health Connect"
25
+ override val supportedWriteResources = setOf(
26
+ WritableVitalResource.Water,
27
+ WritableVitalResource.Glucose,
28
+ )
29
+ override val syncStatusEvent = VitalHealthEvent.HealthConnectSyncStatus
30
+ override val connectionStatusEvent = VitalHealthEvent.HealthConnectConnectionStatus
31
+
32
+ override fun isAvailable(context: Context): ProviderAvailability {
33
+ return VitalHealthConnectManager.isAvailable(context)
34
+ }
35
+
36
+ override fun openPlatformHealthAppIntent(context: Context) =
37
+ VitalHealthConnectManager.openHealthConnectIntent(context)
38
+
39
+ override fun getOrCreateManager(context: Context): VitalHealthManagerBridge {
40
+ return HealthConnectVitalHealthManagerBridge(
41
+ VitalHealthConnectManager.getOrCreate(context),
42
+ )
43
+ }
44
+ }
45
+
46
+ @OptIn(ExperimentalVitalApi::class)
47
+ private class HealthConnectVitalHealthManagerBridge(
48
+ private val manager: VitalHealthConnectManager,
49
+ ) : VitalHealthManagerBridge {
50
+ override val status = manager.status
51
+ override val connectionStatus = manager.connectionStatus
52
+
53
+ override var pauseSynchronization: Boolean
54
+ get() = manager.pauseSynchronization
55
+ set(value) {
56
+ manager.pauseSynchronization = value
57
+ }
58
+
59
+ override val isBackgroundSyncEnabled: Boolean
60
+ get() = manager.isBackgroundSyncEnabled
61
+
62
+ override var autoSyncThrottle
63
+ get() = manager.autoSyncThrottle
64
+ set(value) {
65
+ manager.autoSyncThrottle = value
66
+ }
67
+
68
+ override var backgroundSyncMinimumInterval
69
+ get() = manager.backgroundSyncMinimumInterval
70
+ set(value) {
71
+ manager.backgroundSyncMinimumInterval = value
72
+ }
73
+
74
+ override fun configure(
75
+ syncOnAppStart: Boolean,
76
+ numberOfDaysToBackFill: Int,
77
+ logsEnabled: Boolean,
78
+ connectionPolicy: ConnectionPolicy,
79
+ ) {
80
+ manager.configureHealthConnectClient(
81
+ logsEnabled = logsEnabled,
82
+ syncOnAppStart = syncOnAppStart,
83
+ numberOfDaysToBackFill = numberOfDaysToBackFill,
84
+ connectionPolicy = connectionPolicy,
85
+ )
86
+ }
87
+
88
+ @Suppress("UNCHECKED_CAST")
89
+ override fun createPermissionRequestContract(
90
+ readResources: Set<VitalResource>,
91
+ writeResources: Set<WritableVitalResource>,
92
+ ): ActivityResultContract<Unit, Deferred<*>> {
93
+ return manager.createPermissionRequestContract(
94
+ readResources = readResources,
95
+ writeResources = writeResources,
96
+ ) as ActivityResultContract<Unit, Deferred<*>>
97
+ }
98
+
99
+ @Suppress("UNCHECKED_CAST")
100
+ override suspend fun resolvePermissionOutcome(result: Deferred<*>): VitalHealthPermissionOutcome {
101
+ return when ((result as Deferred<HealthConnectPermissionOutcome>).await()) {
102
+ is HealthConnectPermissionOutcome.Success -> VitalHealthPermissionOutcome.Success
103
+ is HealthConnectPermissionOutcome.HealthConnectUnavailable ->
104
+ VitalHealthPermissionOutcome.HealthDataUnavailable
105
+ is HealthConnectPermissionOutcome.Cancelled -> VitalHealthPermissionOutcome.Cancelled
106
+ is HealthConnectPermissionOutcome.NotPrompted -> VitalHealthPermissionOutcome.NotPrompted
107
+ is HealthConnectPermissionOutcome.UnknownError -> VitalHealthPermissionOutcome.UnknownError
108
+ }
109
+ }
110
+
111
+ override fun hasAskedForPermission(resource: VitalResource): Boolean {
112
+ return manager.hasAskedForPermission(resource)
113
+ }
114
+
115
+ override suspend fun syncData(resources: Set<VitalResource>?) {
116
+ manager.syncData(resources)
117
+ }
118
+
119
+ override suspend fun writeRecord(
120
+ resource: WritableVitalResource,
121
+ startDate: Instant,
122
+ endDate: Instant,
123
+ value: Double,
124
+ ) {
125
+ manager.writeRecord(resource, startDate, endDate, value)
126
+ }
127
+
128
+ override fun enableBackgroundSyncContract(): ActivityResultContract<Unit, Boolean> {
129
+ return manager.enableBackgroundSyncContract()
130
+ }
131
+
132
+ override fun disableBackgroundSync() {
133
+ manager.disableBackgroundSync()
134
+ }
135
+
136
+ override fun setSyncNotificationContent(
137
+ context: Context,
138
+ content: VitalHealthSyncNotificationContent,
139
+ ): Boolean {
140
+ val builder = VitalHealthConnectManager.syncNotificationBuilder(context)
141
+ as? DefaultSyncNotificationBuilder
142
+ ?: return false
143
+
144
+ builder.setContentOverride(
145
+ DefaultSyncNotificationContent(
146
+ notificationTitle = content.notificationTitle,
147
+ notificationContent = content.notificationContent,
148
+ channelName = content.channelName,
149
+ channelDescription = content.channelDescription,
150
+ ),
151
+ )
152
+ return true
153
+ }
154
+
155
+ override suspend fun connect() {
156
+ manager.connect()
157
+ }
158
+
159
+ override suspend fun disconnect() {
160
+ manager.disconnect()
161
+ }
162
+ }
@@ -0,0 +1,37 @@
1
+ package com.vitalhealthreactnative
2
+
3
+ import android.content.Context
4
+ import android.content.Intent
5
+ import io.tryvital.vitalhealthcore.model.ProviderAvailability
6
+ import io.tryvital.vitalhealthcore.model.WritableVitalResource
7
+
8
+ fun raiseUnimplemented(): Nothing {
9
+ throw IllegalArgumentException("the requested provider is unavailable on this device")
10
+ }
11
+
12
+ @Suppress("unused")
13
+ internal object UnavailableVitalHealthProviderDefinition : VitalHealthProviderDefinition {
14
+
15
+ override val provider: AndroidProvider
16
+ get() { raiseUnimplemented() }
17
+ override val displayName: String
18
+ get() { raiseUnimplemented() }
19
+ override val supportedWriteResources: Set<WritableVitalResource>
20
+ get() { raiseUnimplemented() }
21
+ override val syncStatusEvent: VitalHealthEvent
22
+ get() { raiseUnimplemented() }
23
+ override val connectionStatusEvent: VitalHealthEvent
24
+ get() { raiseUnimplemented() }
25
+
26
+ override fun isAvailable(context: Context): ProviderAvailability {
27
+ return ProviderAvailability.NotInstalled
28
+ }
29
+
30
+ override fun openPlatformHealthAppIntent(context: Context): Intent? {
31
+ raiseUnimplemented()
32
+ }
33
+
34
+ override fun getOrCreateManager(context: Context): VitalHealthManagerBridge {
35
+ raiseUnimplemented()
36
+ }
37
+ }
@@ -1,21 +1,16 @@
1
1
  package com.vitalhealthreactnative
2
2
 
3
3
  sealed class VitalHealthEvent(val value: String) {
4
- object Status : VitalHealthEvent("Status")
5
- object ConnectionStatus : VitalHealthEvent("VitalHealthConnectionStatus")
4
+ object HealthConnectSyncStatus : VitalHealthEvent("Status")
5
+ object HealthConnectConnectionStatus : VitalHealthEvent("HealthConnectConnectionStatus")
6
+ object SamsungHealthSyncStatus : VitalHealthEvent("SamsungHealthSyncStatus")
7
+ object SamsungHealthConnectionStatus : VitalHealthEvent("SamsungHealthConnectionStatus")
6
8
 
7
9
  companion object {
8
10
  fun values(): Array<VitalHealthEvent> {
9
- return arrayOf(Status, ConnectionStatus)
11
+ return arrayOf(HealthConnectSyncStatus, HealthConnectConnectionStatus, SamsungHealthSyncStatus, SamsungHealthConnectionStatus)
10
12
  }
11
13
 
12
- fun valueOf(value: String): VitalHealthEvent {
13
- return when (value) {
14
- "Status" -> Status
15
- "VitalHealthConnectionStatus" -> ConnectionStatus
16
- else -> throw IllegalArgumentException("Invalid VitalHealthEvent value: $value")
17
- }
18
- }
14
+ fun valueOf(value: String): VitalHealthEvent = values().first { it.value == value }
19
15
  }
20
-
21
16
  }
@@ -0,0 +1,100 @@
1
+ package com.vitalhealthreactnative
2
+
3
+ import android.content.Context
4
+ import android.content.Intent
5
+ import androidx.activity.result.contract.ActivityResultContract
6
+ import io.tryvital.vitalhealthcore.model.ConnectionPolicy
7
+ import io.tryvital.vitalhealthcore.model.ConnectionStatus
8
+ import io.tryvital.vitalhealthcore.model.ProviderAvailability
9
+ import io.tryvital.vitalhealthcore.model.SyncStatus
10
+ import io.tryvital.vitalhealthcore.model.VitalResource
11
+ import io.tryvital.vitalhealthcore.model.WritableVitalResource
12
+ import kotlinx.coroutines.Deferred
13
+ import kotlinx.coroutines.flow.Flow
14
+ import kotlinx.coroutines.flow.StateFlow
15
+ import java.time.Instant
16
+ import kotlin.time.Duration
17
+
18
+ internal enum class AndroidProvider {
19
+ HealthConnect, SamsungHealth;
20
+
21
+ companion object {
22
+ fun of(rawValue: String) = when (rawValue) {
23
+ "health_connect" -> HealthConnect
24
+ "samsung_health" -> SamsungHealth
25
+ else -> throw IllegalArgumentException("unrecognized AndroidProvider: ${rawValue}")
26
+ }
27
+ }
28
+ }
29
+
30
+ internal interface VitalHealthProviderDefinition {
31
+ val provider: AndroidProvider
32
+ val displayName: String
33
+ val supportedWriteResources: Set<WritableVitalResource>
34
+ val syncStatusEvent: VitalHealthEvent
35
+ val connectionStatusEvent: VitalHealthEvent
36
+
37
+ fun isAvailable(context: Context): ProviderAvailability
38
+ fun openPlatformHealthAppIntent(context: Context): Intent?
39
+ fun getOrCreateManager(context: Context): VitalHealthManagerBridge
40
+ }
41
+
42
+ internal interface VitalHealthManagerBridge {
43
+ val status: Flow<SyncStatus>
44
+ val connectionStatus: StateFlow<ConnectionStatus>
45
+ var pauseSynchronization: Boolean
46
+ val isBackgroundSyncEnabled: Boolean
47
+ var autoSyncThrottle: Duration
48
+ var backgroundSyncMinimumInterval: Duration
49
+
50
+ fun configure(
51
+ syncOnAppStart: Boolean,
52
+ numberOfDaysToBackFill: Int,
53
+ logsEnabled: Boolean,
54
+ connectionPolicy: ConnectionPolicy,
55
+ )
56
+
57
+ fun createPermissionRequestContract(
58
+ readResources: Set<VitalResource>,
59
+ writeResources: Set<WritableVitalResource>,
60
+ ): ActivityResultContract<Unit, Deferred<*>>
61
+
62
+ suspend fun resolvePermissionOutcome(result: Deferred<*>): VitalHealthPermissionOutcome
63
+
64
+ fun hasAskedForPermission(resource: VitalResource): Boolean
65
+
66
+ suspend fun syncData(resources: Set<VitalResource>? = null)
67
+
68
+ suspend fun writeRecord(
69
+ resource: WritableVitalResource,
70
+ startDate: Instant,
71
+ endDate: Instant,
72
+ value: Double,
73
+ )
74
+
75
+ fun enableBackgroundSyncContract(): ActivityResultContract<Unit, Boolean>
76
+ fun disableBackgroundSync()
77
+
78
+ fun setSyncNotificationContent(
79
+ context: Context,
80
+ content: VitalHealthSyncNotificationContent,
81
+ ): Boolean
82
+
83
+ suspend fun connect()
84
+ suspend fun disconnect()
85
+ }
86
+
87
+ internal data class VitalHealthSyncNotificationContent(
88
+ val notificationTitle: String,
89
+ val notificationContent: String,
90
+ val channelName: String,
91
+ val channelDescription: String,
92
+ )
93
+
94
+ internal enum class VitalHealthPermissionOutcome(val jsValue: String) {
95
+ Success("success"),
96
+ HealthDataUnavailable("healthDataUnavailable"),
97
+ Cancelled("cancelled"),
98
+ NotPrompted("notPrompted"),
99
+ UnknownError("unknownError"),
100
+ }