@tryvital/vital-health-react-native 0.3.0 → 0.3.2
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/ios/VitalHealthReactNative.m +12 -0
- package/ios/VitalHealthReactNative.swift +74 -15
- package/lib/index.d.ts +32 -0
- package/lib/index.js +60 -0
- package/package.json +1 -1
- package/src/index.tsx +32 -1
- package/vital-health-react-native.podspec +1 -1
|
@@ -12,6 +12,18 @@ RCT_EXTERN_METHOD(askForResources:(NSArray<NSString *> *)resources
|
|
|
12
12
|
resolver:(RCTPromiseResolveBlock)resolve
|
|
13
13
|
rejecter:(RCTPromiseRejectBlock)reject)
|
|
14
14
|
|
|
15
|
+
RCT_EXTERN_METHOD(ask:(NSArray<NSString *> *)readResources
|
|
16
|
+
writeResources:(NSArray<NSString *> *)writeResources
|
|
17
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
18
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
|
19
|
+
|
|
20
|
+
RCT_EXTERN_METHOD(writeHealthData:(NSString *)resource
|
|
21
|
+
value:(double)value
|
|
22
|
+
startDate:(double)startDate
|
|
23
|
+
endDate:(double)endDate
|
|
24
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
25
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
|
26
|
+
|
|
15
27
|
RCT_EXTERN_METHOD(cleanUp:(RCTPromiseResolveBlock)resolve
|
|
16
28
|
rejecter:(RCTPromiseRejectBlock)reject)
|
|
17
29
|
|
|
@@ -18,17 +18,17 @@ class VitalHealthReactNative: RCTEventEmitter {
|
|
|
18
18
|
|
|
19
19
|
cancellable = VitalHealthKitClient.shared.status.sink { status in
|
|
20
20
|
var payload: [String: String] = [:]
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
switch status {
|
|
23
23
|
case let .failedSyncing(resource, error):
|
|
24
24
|
payload["resource"] = String(describing: resource)
|
|
25
25
|
payload["status"] = "failedSyncing"
|
|
26
26
|
payload["extra"] = error?.localizedDescription
|
|
27
|
-
|
|
27
|
+
|
|
28
28
|
case let .nothingToSync(resource):
|
|
29
29
|
payload["resource"] = String(describing: resource)
|
|
30
30
|
payload["status"] = "nothingToSync"
|
|
31
|
-
|
|
31
|
+
|
|
32
32
|
case let .successSyncing(resource, _):
|
|
33
33
|
payload["resource"] = String(describing: resource)
|
|
34
34
|
payload["status"] = "successSyncing"
|
|
@@ -36,11 +36,11 @@ class VitalHealthReactNative: RCTEventEmitter {
|
|
|
36
36
|
case let .syncing(resource):
|
|
37
37
|
payload["resource"] = String(describing: resource)
|
|
38
38
|
payload["status"] = "syncing"
|
|
39
|
-
|
|
39
|
+
|
|
40
40
|
case .syncingCompleted:
|
|
41
41
|
payload["status"] = "completed"
|
|
42
42
|
}
|
|
43
|
-
|
|
43
|
+
|
|
44
44
|
self.sendEvent(withName: "status", body: payload)
|
|
45
45
|
}
|
|
46
46
|
}
|
|
@@ -70,17 +70,18 @@ class VitalHealthReactNative: RCTEventEmitter {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
|
|
73
|
-
@objc(
|
|
74
|
-
func
|
|
75
|
-
_
|
|
73
|
+
@objc(ask:writeResources:resolver:rejecter:)
|
|
74
|
+
func ask(
|
|
75
|
+
_ readResources: [String],
|
|
76
|
+
writeResources: [String],
|
|
76
77
|
resolve: @escaping RCTPromiseResolveBlock,
|
|
77
78
|
reject: @escaping RCTPromiseRejectBlock
|
|
78
79
|
) {
|
|
79
80
|
Task {
|
|
80
81
|
do {
|
|
81
|
-
|
|
82
|
-
let
|
|
83
|
-
let outcome = await VitalHealthKitClient.shared.ask(readPermissions: readPermissions, writePermissions:
|
|
82
|
+
let readPermissions = try readResources.map { try mapResourceToReadableVitalResource($0) }
|
|
83
|
+
let writePermissions = try writeResources.map { try mapResourceToWritableVitalResource($0) }
|
|
84
|
+
let outcome = await VitalHealthKitClient.shared.ask(readPermissions: readPermissions, writePermissions: writePermissions)
|
|
84
85
|
|
|
85
86
|
switch outcome {
|
|
86
87
|
case .success:
|
|
@@ -105,7 +106,7 @@ class VitalHealthReactNative: RCTEventEmitter {
|
|
|
105
106
|
reject: RCTPromiseRejectBlock
|
|
106
107
|
) {
|
|
107
108
|
do {
|
|
108
|
-
try VitalHealthKitClient.shared.syncData(for: resources.map { try
|
|
109
|
+
try VitalHealthKitClient.shared.syncData(for: resources.map { try mapResourceToReadableVitalResource($0) })
|
|
109
110
|
resolve(())
|
|
110
111
|
} catch VitalError.UnsupportedResource(let errorMessage) {
|
|
111
112
|
reject("UnsupportedResource", errorMessage, nil)
|
|
@@ -125,7 +126,7 @@ class VitalHealthReactNative: RCTEventEmitter {
|
|
|
125
126
|
@objc(hasAskedForPermission:resolver:rejecter:)
|
|
126
127
|
func hasAskedForPermission(_ resource: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
|
|
127
128
|
do {
|
|
128
|
-
let vitalResource = try
|
|
129
|
+
let vitalResource = try mapResourceToReadableVitalResource(resource)
|
|
129
130
|
let value: Bool = VitalHealthKitClient.shared.hasAskedForPermission(resource: vitalResource)
|
|
130
131
|
resolve(value)
|
|
131
132
|
} catch VitalError.UnsupportedResource(let errorMessage) {
|
|
@@ -134,9 +135,48 @@ class VitalHealthReactNative: RCTEventEmitter {
|
|
|
134
135
|
reject(nil, "Unknown error", nil)
|
|
135
136
|
}
|
|
136
137
|
}
|
|
138
|
+
|
|
139
|
+
@objc(writeHealthData:value:startDate:endDate:resolver:rejecter:)
|
|
140
|
+
func writeHealthData(_ resource: String,
|
|
141
|
+
value: Double,
|
|
142
|
+
startDate: Double,
|
|
143
|
+
endDate: Double,
|
|
144
|
+
resolve: @escaping RCTPromiseResolveBlock,
|
|
145
|
+
reject: RCTPromiseRejectBlock
|
|
146
|
+
){
|
|
147
|
+
do {
|
|
148
|
+
let resource = try mapResourceToReadableVitalResource(resource)
|
|
149
|
+
|
|
150
|
+
let startDate = Date(timeIntervalSince1970: startDate / 1000)
|
|
151
|
+
let endDate = Date(timeIntervalSince1970: endDate / 1000)
|
|
152
|
+
|
|
153
|
+
let dataInput: DataInput
|
|
154
|
+
|
|
155
|
+
switch resource {
|
|
156
|
+
case .nutrition(.water):
|
|
157
|
+
dataInput = .water(milliliters: Int(value))
|
|
158
|
+
case .nutrition(.caffeine):
|
|
159
|
+
dataInput = .caffeine(grams: Int(value))
|
|
160
|
+
case .vitals(.mindfulSession):
|
|
161
|
+
dataInput = .mindfulSession
|
|
162
|
+
default:
|
|
163
|
+
fatalError("\(resource) not supported for writing to HealthKit")
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
Task {
|
|
167
|
+
try await VitalHealthKitClient.shared.write(input: dataInput, startDate: startDate, endDate: endDate)
|
|
168
|
+
resolve(())
|
|
169
|
+
}
|
|
170
|
+
} catch VitalError.UnsupportedResource(let errorMessage) {
|
|
171
|
+
reject("UnsupportedResource", errorMessage, nil)
|
|
172
|
+
} catch {
|
|
173
|
+
reject(nil, "Unknown error", nil)
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
137
177
|
}
|
|
138
178
|
|
|
139
|
-
private func
|
|
179
|
+
private func mapResourceToReadableVitalResource(_ name: String) throws -> VitalResource {
|
|
140
180
|
switch name {
|
|
141
181
|
case "profile":
|
|
142
182
|
return .profile
|
|
@@ -154,6 +194,8 @@ private func mapResourceToVitalResource(_ name: String) throws -> VitalResource
|
|
|
154
194
|
return .vitals(.bloodPressure)
|
|
155
195
|
case "heartRate":
|
|
156
196
|
return .vitals(.hearthRate)
|
|
197
|
+
case "mindfulSession":
|
|
198
|
+
return .vitals(.mindfulSession)
|
|
157
199
|
case "steps":
|
|
158
200
|
return .individual(.steps)
|
|
159
201
|
case "activeEnergyBurned":
|
|
@@ -170,6 +212,23 @@ private func mapResourceToVitalResource(_ name: String) throws -> VitalResource
|
|
|
170
212
|
return .individual(.weight)
|
|
171
213
|
case "bodyFat":
|
|
172
214
|
return .individual(.bodyFat)
|
|
215
|
+
case "water":
|
|
216
|
+
return .nutrition(.water)
|
|
217
|
+
case "caffeine":
|
|
218
|
+
return .nutrition(.caffeine)
|
|
219
|
+
default:
|
|
220
|
+
throw VitalError.UnsupportedResource(name)
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
private func mapResourceToWritableVitalResource(_ name: String) throws -> WritableVitalResource {
|
|
225
|
+
switch name {
|
|
226
|
+
case "water":
|
|
227
|
+
return .water
|
|
228
|
+
case "caffeine":
|
|
229
|
+
return .caffeine
|
|
230
|
+
case "mindfulSession":
|
|
231
|
+
return .mindfulSession
|
|
173
232
|
default:
|
|
174
233
|
throw VitalError.UnsupportedResource(name)
|
|
175
234
|
}
|
|
@@ -183,4 +242,4 @@ enum VitalError: Error {
|
|
|
183
242
|
case UnsupportedProvider(String)
|
|
184
243
|
case UnsupportedBrand(String)
|
|
185
244
|
case UnsupportedKind(String)
|
|
186
|
-
}
|
|
245
|
+
}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { NativeEventEmitter } from 'react-native';
|
|
2
|
+
export declare class VitalHealth {
|
|
3
|
+
static status: NativeEventEmitter;
|
|
4
|
+
static configure(backgroundDeliveryEnabled: boolean, numberOfDaysToBackFill: number, enableLogs: boolean): Promise<void>;
|
|
5
|
+
static askForResources(resources: VitalResource[]): Promise<void>;
|
|
6
|
+
static ask(readResources: VitalResource[], writeResources: VitalWriteResource[]): Promise<void>;
|
|
7
|
+
static writeHealthData(resource: VitalWriteResource, value: number, startDate: Date, endDate: Date): Promise<void>;
|
|
8
|
+
static hasAskedForPermission(resource: VitalResource): Promise<boolean>;
|
|
9
|
+
static syncData(resources: VitalResource[]): Promise<void>;
|
|
10
|
+
static cleanUp(): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
export declare enum VitalResource {
|
|
13
|
+
Profile = "profile",
|
|
14
|
+
Body = "body",
|
|
15
|
+
Workout = "workout",
|
|
16
|
+
Activity = "activity",
|
|
17
|
+
Sleep = "sleep",
|
|
18
|
+
Glucose = "glucose",
|
|
19
|
+
BloodPressure = "bloodPressure",
|
|
20
|
+
HeartRate = "heartRate",
|
|
21
|
+
Steps = "steps",
|
|
22
|
+
ActiveEnergyBurned = "activeEnergyBurned",
|
|
23
|
+
BasalEnergyBurned = "basalEnergyBurned",
|
|
24
|
+
Water = "water",
|
|
25
|
+
Caffeine = "caffeine",
|
|
26
|
+
MindfulSession = "mindfulSession"
|
|
27
|
+
}
|
|
28
|
+
export declare enum VitalWriteResource {
|
|
29
|
+
Water = "water",
|
|
30
|
+
Caffeine = "caffeine",
|
|
31
|
+
MindfulSession = "mindfulSession"
|
|
32
|
+
}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { NativeEventEmitter, NativeModules, Platform } from 'react-native';
|
|
2
|
+
const LINKING_ERROR = `The package 'vital-health-react-native' doesn't seem to be linked. Make sure: \n\n` +
|
|
3
|
+
Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) +
|
|
4
|
+
'- You rebuilt the app after installing the package\n' +
|
|
5
|
+
'- You are not using Expo Go\n';
|
|
6
|
+
const VitalHealthReactNative = NativeModules.VitalHealthReactNative
|
|
7
|
+
? NativeModules.VitalHealthReactNative
|
|
8
|
+
: new Proxy({}, {
|
|
9
|
+
get() {
|
|
10
|
+
throw new Error(LINKING_ERROR);
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
export class VitalHealth {
|
|
14
|
+
static status = new NativeEventEmitter(VitalHealthReactNative);
|
|
15
|
+
static configure(backgroundDeliveryEnabled, numberOfDaysToBackFill, enableLogs) {
|
|
16
|
+
return VitalHealthReactNative.configure(backgroundDeliveryEnabled, numberOfDaysToBackFill, enableLogs);
|
|
17
|
+
}
|
|
18
|
+
static askForResources(resources) {
|
|
19
|
+
return VitalHealthReactNative.ask(resources, []);
|
|
20
|
+
}
|
|
21
|
+
static ask(readResources, writeResources) {
|
|
22
|
+
return VitalHealthReactNative.ask(readResources, writeResources);
|
|
23
|
+
}
|
|
24
|
+
static writeHealthData(resource, value, startDate, endDate) {
|
|
25
|
+
return VitalHealthReactNative.writeHealthData(resource, value, startDate.getTime(), endDate.getTime());
|
|
26
|
+
}
|
|
27
|
+
static hasAskedForPermission(resource) {
|
|
28
|
+
return VitalHealthReactNative.hasAskedForPermission(resource);
|
|
29
|
+
}
|
|
30
|
+
static syncData(resources) {
|
|
31
|
+
return VitalHealthReactNative.syncData(resources);
|
|
32
|
+
}
|
|
33
|
+
static cleanUp() {
|
|
34
|
+
return VitalHealthReactNative.cleanUp();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// noinspection JSUnusedGlobalSymbols
|
|
38
|
+
export var VitalResource;
|
|
39
|
+
(function (VitalResource) {
|
|
40
|
+
VitalResource["Profile"] = "profile";
|
|
41
|
+
VitalResource["Body"] = "body";
|
|
42
|
+
VitalResource["Workout"] = "workout";
|
|
43
|
+
VitalResource["Activity"] = "activity";
|
|
44
|
+
VitalResource["Sleep"] = "sleep";
|
|
45
|
+
VitalResource["Glucose"] = "glucose";
|
|
46
|
+
VitalResource["BloodPressure"] = "bloodPressure";
|
|
47
|
+
VitalResource["HeartRate"] = "heartRate";
|
|
48
|
+
VitalResource["Steps"] = "steps";
|
|
49
|
+
VitalResource["ActiveEnergyBurned"] = "activeEnergyBurned";
|
|
50
|
+
VitalResource["BasalEnergyBurned"] = "basalEnergyBurned";
|
|
51
|
+
VitalResource["Water"] = "water";
|
|
52
|
+
VitalResource["Caffeine"] = "caffeine";
|
|
53
|
+
VitalResource["MindfulSession"] = "mindfulSession";
|
|
54
|
+
})(VitalResource || (VitalResource = {}));
|
|
55
|
+
export var VitalWriteResource;
|
|
56
|
+
(function (VitalWriteResource) {
|
|
57
|
+
VitalWriteResource["Water"] = "water";
|
|
58
|
+
VitalWriteResource["Caffeine"] = "caffeine";
|
|
59
|
+
VitalWriteResource["MindfulSession"] = "mindfulSession";
|
|
60
|
+
})(VitalWriteResource || (VitalWriteResource = {}));
|
package/package.json
CHANGED
package/src/index.tsx
CHANGED
|
@@ -33,7 +33,28 @@ export class VitalHealth {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
static askForResources(resources: VitalResource[]): Promise<void> {
|
|
36
|
-
return VitalHealthReactNative.
|
|
36
|
+
return VitalHealthReactNative.ask(resources, []);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
static ask(
|
|
40
|
+
readResources: VitalResource[],
|
|
41
|
+
writeResources: VitalWriteResource[]
|
|
42
|
+
): Promise<void> {
|
|
43
|
+
return VitalHealthReactNative.ask(readResources, writeResources);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
static writeHealthData(
|
|
47
|
+
resource: VitalWriteResource,
|
|
48
|
+
value: number,
|
|
49
|
+
startDate: Date,
|
|
50
|
+
endDate: Date
|
|
51
|
+
): Promise<void> {
|
|
52
|
+
return VitalHealthReactNative.writeHealthData(
|
|
53
|
+
resource,
|
|
54
|
+
value,
|
|
55
|
+
startDate.getTime(),
|
|
56
|
+
endDate.getTime()
|
|
57
|
+
);
|
|
37
58
|
}
|
|
38
59
|
|
|
39
60
|
static hasAskedForPermission(resource: VitalResource): Promise<boolean> {
|
|
@@ -49,6 +70,7 @@ export class VitalHealth {
|
|
|
49
70
|
}
|
|
50
71
|
}
|
|
51
72
|
|
|
73
|
+
// noinspection JSUnusedGlobalSymbols
|
|
52
74
|
export enum VitalResource {
|
|
53
75
|
Profile = 'profile',
|
|
54
76
|
Body = 'body',
|
|
@@ -61,4 +83,13 @@ export enum VitalResource {
|
|
|
61
83
|
Steps = 'steps',
|
|
62
84
|
ActiveEnergyBurned = 'activeEnergyBurned',
|
|
63
85
|
BasalEnergyBurned = 'basalEnergyBurned',
|
|
86
|
+
Water = 'water',
|
|
87
|
+
Caffeine = 'caffeine',
|
|
88
|
+
MindfulSession = 'mindfulSession',
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export enum VitalWriteResource {
|
|
92
|
+
Water = 'water',
|
|
93
|
+
Caffeine = 'caffeine', // iOS only
|
|
94
|
+
MindfulSession = 'mindfulSession', // iOS only, value is ignored
|
|
64
95
|
}
|
|
@@ -17,7 +17,7 @@ Pod::Spec.new do |s|
|
|
|
17
17
|
s.source_files = "ios/**/*.{h,m,mm,swift}"
|
|
18
18
|
|
|
19
19
|
s.dependency "React-Core"
|
|
20
|
-
s.dependency "VitalHealthKit", "~> 0.7.
|
|
20
|
+
s.dependency "VitalHealthKit", "~> 0.7.13"
|
|
21
21
|
|
|
22
22
|
# Don't install the dependencies when we run `pod install` in the old architecture.
|
|
23
23
|
if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then
|