@shenai/capacitor-sdk 3.1.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.
- package/CapacitorShenaiSdk.podspec +18 -0
- package/LICENSE.md +5 -0
- package/README.md +0 -0
- package/android/build.gradle +59 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/ai/mxlabs/shenai_sdk/plugins/capacitor/ShenaiSdkCapacitorPlugin.java +1476 -0
- package/android/src/main/res/.gitkeep +0 -0
- package/dist/docs.json +3226 -0
- package/dist/esm/definitions.d.ts +612 -0
- package/dist/esm/definitions.js +208 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +29 -0
- package/dist/plugin.cjs.js +241 -0
- package/dist/plugin.js +244 -0
- package/ios/Sources/ShenaiSdkCapacitorPlugin/ShenaiSdkCapacitorPlugin.swift +1101 -0
- package/package.json +47 -0
|
@@ -0,0 +1,1101 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import Capacitor
|
|
3
|
+
import UIKit
|
|
4
|
+
import WebKit
|
|
5
|
+
import ShenaiSDK // ShenaiSDK.xcframework
|
|
6
|
+
//import ShenaiSDK.ShenaiHealthRisks
|
|
7
|
+
//import ShenaiSDK.ShenaiView
|
|
8
|
+
|
|
9
|
+
private final class ShenaiTouchForwardingRecognizer: UIGestureRecognizer {
|
|
10
|
+
var shouldForwardTouch: ((UITouch) -> Bool)?
|
|
11
|
+
var onTouchesBegan: ((Set<UITouch>, UIEvent?) -> Void)?
|
|
12
|
+
var onTouchesMoved: ((Set<UITouch>, UIEvent?) -> Void)?
|
|
13
|
+
var onTouchesEnded: ((Set<UITouch>, UIEvent?) -> Void)?
|
|
14
|
+
var onTouchesCancelled: ((Set<UITouch>, UIEvent?) -> Void)?
|
|
15
|
+
private var activeForwardedTouches = Set<UITouch>()
|
|
16
|
+
|
|
17
|
+
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
|
|
18
|
+
let forwardedTouches = Set(touches.filter(shouldStartForwarding))
|
|
19
|
+
if forwardedTouches.isEmpty {
|
|
20
|
+
state = .failed
|
|
21
|
+
return
|
|
22
|
+
}
|
|
23
|
+
activeForwardedTouches.formUnion(forwardedTouches)
|
|
24
|
+
onTouchesBegan?(forwardedTouches, event)
|
|
25
|
+
state = .began
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
|
|
29
|
+
let forwardedTouches = touches.intersection(activeForwardedTouches)
|
|
30
|
+
if !forwardedTouches.isEmpty {
|
|
31
|
+
onTouchesMoved?(forwardedTouches, event)
|
|
32
|
+
}
|
|
33
|
+
state = .changed
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent) {
|
|
37
|
+
let forwardedTouches = touches.intersection(activeForwardedTouches)
|
|
38
|
+
if !forwardedTouches.isEmpty {
|
|
39
|
+
onTouchesEnded?(forwardedTouches, event)
|
|
40
|
+
}
|
|
41
|
+
activeForwardedTouches.subtract(touches)
|
|
42
|
+
state = .ended
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent) {
|
|
46
|
+
let forwardedTouches = touches.intersection(activeForwardedTouches)
|
|
47
|
+
if !forwardedTouches.isEmpty {
|
|
48
|
+
onTouchesCancelled?(forwardedTouches, event)
|
|
49
|
+
}
|
|
50
|
+
activeForwardedTouches.subtract(touches)
|
|
51
|
+
state = .cancelled
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
override func canPrevent(_ preventedGestureRecognizer: UIGestureRecognizer) -> Bool {
|
|
55
|
+
false
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
override func canBePrevented(by preventingGestureRecognizer: UIGestureRecognizer) -> Bool {
|
|
59
|
+
false
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
override func reset() {
|
|
63
|
+
activeForwardedTouches.removeAll()
|
|
64
|
+
super.reset()
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private func shouldStartForwarding(_ touch: UITouch) -> Bool {
|
|
68
|
+
guard let shouldForwardTouch else {
|
|
69
|
+
return true
|
|
70
|
+
}
|
|
71
|
+
return shouldForwardTouch(touch)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// MARK: - Capacitor registration ------------------------------------------------
|
|
76
|
+
|
|
77
|
+
@objc(ShenaiSdkCapacitorPlugin)
|
|
78
|
+
public class ShenaiSdkCapacitorPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
79
|
+
|
|
80
|
+
public let identifier = "ShenaiSdkCapacitorPlugin"
|
|
81
|
+
public let jsName = "ShenaiSdkCapacitor"
|
|
82
|
+
|
|
83
|
+
public let pluginMethods: [CAPPluginMethod] = [
|
|
84
|
+
CAPPluginMethod(name: "echo", returnType: CAPPluginReturnPromise),
|
|
85
|
+
CAPPluginMethod(name: "initialize", returnType: CAPPluginReturnPromise),
|
|
86
|
+
CAPPluginMethod(name: "isInitialized", returnType: CAPPluginReturnPromise),
|
|
87
|
+
CAPPluginMethod(name: "deinitialize", returnType: CAPPluginReturnPromise),
|
|
88
|
+
CAPPluginMethod(name: "setViewRect", returnType: CAPPluginReturnPromise),
|
|
89
|
+
CAPPluginMethod(name: "setOverlaysWebview", returnType: CAPPluginReturnPromise),
|
|
90
|
+
CAPPluginMethod(name: "setOperatingMode", returnType: CAPPluginReturnPromise),
|
|
91
|
+
CAPPluginMethod(name: "startMeasurement", returnType: CAPPluginReturnPromise),
|
|
92
|
+
CAPPluginMethod(name: "stopMeasurement", returnType: CAPPluginReturnPromise),
|
|
93
|
+
CAPPluginMethod(name: "resetMeasurementSession", returnType: CAPPluginReturnPromise),
|
|
94
|
+
CAPPluginMethod(name: "getOperatingMode", returnType: CAPPluginReturnPromise),
|
|
95
|
+
CAPPluginMethod(name: "getCalibrationState", returnType: CAPPluginReturnPromise),
|
|
96
|
+
CAPPluginMethod(name: "setPrecisionMode", returnType: CAPPluginReturnPromise),
|
|
97
|
+
CAPPluginMethod(name: "getPrecisionMode", returnType: CAPPluginReturnPromise),
|
|
98
|
+
CAPPluginMethod(name: "setMeasurementPreset", returnType: CAPPluginReturnPromise),
|
|
99
|
+
CAPPluginMethod(name: "getMeasurementPreset", returnType: CAPPluginReturnPromise),
|
|
100
|
+
CAPPluginMethod(name: "setCameraMode", returnType: CAPPluginReturnPromise),
|
|
101
|
+
CAPPluginMethod(name: "getCameraMode", returnType: CAPPluginReturnPromise),
|
|
102
|
+
CAPPluginMethod(name: "getLastCameraError", returnType: CAPPluginReturnPromise),
|
|
103
|
+
CAPPluginMethod(name: "setScreen", returnType: CAPPluginReturnPromise),
|
|
104
|
+
CAPPluginMethod(name: "getScreen", returnType: CAPPluginReturnPromise),
|
|
105
|
+
CAPPluginMethod(name: "setShowUserInterface", returnType: CAPPluginReturnPromise),
|
|
106
|
+
CAPPluginMethod(name: "getShowUserInterface", returnType: CAPPluginReturnPromise),
|
|
107
|
+
CAPPluginMethod(name: "setShowFacePositioningOverlay", returnType: CAPPluginReturnPromise),
|
|
108
|
+
CAPPluginMethod(name: "getShowFacePositioningOverlay", returnType: CAPPluginReturnPromise),
|
|
109
|
+
CAPPluginMethod(name: "setShowVisualWarnings", returnType: CAPPluginReturnPromise),
|
|
110
|
+
CAPPluginMethod(name: "getShowVisualWarnings", returnType: CAPPluginReturnPromise),
|
|
111
|
+
CAPPluginMethod(name: "setEnableCameraSwap", returnType: CAPPluginReturnPromise),
|
|
112
|
+
CAPPluginMethod(name: "getEnableCameraSwap", returnType: CAPPluginReturnPromise),
|
|
113
|
+
CAPPluginMethod(name: "setShowFaceMask", returnType: CAPPluginReturnPromise),
|
|
114
|
+
CAPPluginMethod(name: "getShowFaceMask", returnType: CAPPluginReturnPromise),
|
|
115
|
+
CAPPluginMethod(name: "setShowBloodFlow", returnType: CAPPluginReturnPromise),
|
|
116
|
+
CAPPluginMethod(name: "getShowBloodFlow", returnType: CAPPluginReturnPromise),
|
|
117
|
+
CAPPluginMethod(name: "setIncludeTimestampInPdf", returnType: CAPPluginReturnPromise),
|
|
118
|
+
CAPPluginMethod(name: "getIncludeTimestampInPdf", returnType: CAPPluginReturnPromise),
|
|
119
|
+
CAPPluginMethod(name: "setPdfEmailSubject", returnType: CAPPluginReturnPromise),
|
|
120
|
+
CAPPluginMethod(name: "setPdfEmailBody", returnType: CAPPluginReturnPromise),
|
|
121
|
+
CAPPluginMethod(name: "setShowStartStopButton", returnType: CAPPluginReturnPromise),
|
|
122
|
+
CAPPluginMethod(name: "getShowStartStopButton", returnType: CAPPluginReturnPromise),
|
|
123
|
+
CAPPluginMethod(name: "setEnableMeasurementsDashboard", returnType: CAPPluginReturnPromise),
|
|
124
|
+
CAPPluginMethod(name: "getEnableMeasurementsDashboard", returnType: CAPPluginReturnPromise),
|
|
125
|
+
CAPPluginMethod(name: "setShowInfoButton", returnType: CAPPluginReturnPromise),
|
|
126
|
+
CAPPluginMethod(name: "getShowInfoButton", returnType: CAPPluginReturnPromise),
|
|
127
|
+
CAPPluginMethod(name: "getShowDisclaimer", returnType: CAPPluginReturnPromise),
|
|
128
|
+
CAPPluginMethod(name: "setEnableStartAfterSuccess", returnType: CAPPluginReturnPromise),
|
|
129
|
+
CAPPluginMethod(name: "getEnableStartAfterSuccess", returnType: CAPPluginReturnPromise),
|
|
130
|
+
CAPPluginMethod(name: "getFaceState", returnType: CAPPluginReturnPromise),
|
|
131
|
+
CAPPluginMethod(name: "getNormalizedFaceBbox", returnType: CAPPluginReturnPromise),
|
|
132
|
+
CAPPluginMethod(name: "getMeasurementState", returnType: CAPPluginReturnPromise),
|
|
133
|
+
CAPPluginMethod(name: "getCurrentViolatedMeasurementEnvironmentCondition", returnType: CAPPluginReturnPromise),
|
|
134
|
+
CAPPluginMethod(name: "isReadyToStartMeasurement", returnType: CAPPluginReturnPromise),
|
|
135
|
+
CAPPluginMethod(name: "areRequiredModelsDownloaded", returnType: CAPPluginReturnPromise),
|
|
136
|
+
CAPPluginMethod(name: "getMeasurementProgressPercentage", returnType: CAPPluginReturnPromise),
|
|
137
|
+
CAPPluginMethod(name: "getHeartRate10s", returnType: CAPPluginReturnPromise),
|
|
138
|
+
CAPPluginMethod(name: "getHeartRate4s", returnType: CAPPluginReturnPromise),
|
|
139
|
+
CAPPluginMethod(name: "getRealtimeMetrics", returnType: CAPPluginReturnPromise),
|
|
140
|
+
CAPPluginMethod(name: "getMeasurementResults", returnType: CAPPluginReturnPromise),
|
|
141
|
+
CAPPluginMethod(name: "getMeasurementResultsHistory",returnType: CAPPluginReturnPromise),
|
|
142
|
+
CAPPluginMethod(name: "getRealtimeHeartbeats", returnType: CAPPluginReturnPromise),
|
|
143
|
+
CAPPluginMethod(name: "getFullPpgSignal", returnType: CAPPluginReturnPromise),
|
|
144
|
+
CAPPluginMethod(name: "setRecordingEnabled", returnType: CAPPluginReturnPromise),
|
|
145
|
+
CAPPluginMethod(name: "getRecordingEnabled", returnType: CAPPluginReturnPromise),
|
|
146
|
+
CAPPluginMethod(name: "getTotalBadSignalSeconds", returnType: CAPPluginReturnPromise),
|
|
147
|
+
CAPPluginMethod(name: "getCurrentSignalQualityMetric", returnType: CAPPluginReturnPromise),
|
|
148
|
+
CAPPluginMethod(name: "getSignalQualityMapPng", returnType: CAPPluginReturnPromise),
|
|
149
|
+
CAPPluginMethod(name: "getFaceTexturePng", returnType: CAPPluginReturnPromise),
|
|
150
|
+
CAPPluginMethod(name: "setCustomMeasurementConfig", returnType: CAPPluginReturnPromise),
|
|
151
|
+
CAPPluginMethod(name: "setCustomColorTheme", returnType: CAPPluginReturnPromise),
|
|
152
|
+
CAPPluginMethod(name: "setLanguage", returnType: CAPPluginReturnPromise),
|
|
153
|
+
CAPPluginMethod(name: "getHealthRisksFactors", returnType: CAPPluginReturnPromise),
|
|
154
|
+
CAPPluginMethod(name: "getHealthRisks", returnType: CAPPluginReturnPromise),
|
|
155
|
+
CAPPluginMethod(name: "computeHealthRisks", returnType: CAPPluginReturnPromise),
|
|
156
|
+
CAPPluginMethod(name: "getMaximalRisks", returnType: CAPPluginReturnPromise),
|
|
157
|
+
CAPPluginMethod(name: "getMinimalRisks", returnType: CAPPluginReturnPromise),
|
|
158
|
+
CAPPluginMethod(name: "getReferenceRisks", returnType: CAPPluginReturnPromise),
|
|
159
|
+
CAPPluginMethod(name: "openMeasurementResultsPdfInBrowser", returnType: CAPPluginReturnPromise),
|
|
160
|
+
CAPPluginMethod(name: "sendMeasurementResultsPdfToEmail", returnType: CAPPluginReturnPromise),
|
|
161
|
+
CAPPluginMethod(name: "requestMeasurementResultsPdfUrl", returnType: CAPPluginReturnPromise),
|
|
162
|
+
CAPPluginMethod(name: "getMeasurementResultsPdfUrl", returnType: CAPPluginReturnPromise),
|
|
163
|
+
CAPPluginMethod(name: "requestMeasurementResultsPdfBytes", returnType: CAPPluginReturnPromise),
|
|
164
|
+
CAPPluginMethod(name: "getMeasurementResultsPdfBytes", returnType: CAPPluginReturnPromise),
|
|
165
|
+
CAPPluginMethod(name: "getResultAsFhirObservation", returnType: CAPPluginReturnPromise),
|
|
166
|
+
CAPPluginMethod(name: "sendResultFhirObservation", returnType: CAPPluginReturnPromise)
|
|
167
|
+
]
|
|
168
|
+
|
|
169
|
+
// MARK: - State --------------------------------------------------------------
|
|
170
|
+
|
|
171
|
+
private var shenaiView: ShenaiView?
|
|
172
|
+
private var shenaiContainerView: UIView?
|
|
173
|
+
private var touchForwardingRecognizer: ShenaiTouchForwardingRecognizer?
|
|
174
|
+
|
|
175
|
+
// MARK: - Simple echo --------------------------------------------------------
|
|
176
|
+
|
|
177
|
+
@objc func echo(_ call: CAPPluginCall) {
|
|
178
|
+
let value = call.getString("value") ?? ""
|
|
179
|
+
call.resolve(["value": value])
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// MARK: - INITIALIZATION -----------------------------------------------------
|
|
183
|
+
|
|
184
|
+
@objc func initialize(_ call: CAPPluginCall) {
|
|
185
|
+
guard let apiKey = call.getString("apiKey") else {
|
|
186
|
+
call.reject("apiKey is required"); return
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
let userId = call.getString("userId")
|
|
190
|
+
let settings = InitializationSettings()
|
|
191
|
+
|
|
192
|
+
if let dict = call.getObject("settings") {
|
|
193
|
+
|
|
194
|
+
func bool(_ key: String) -> Bool? { dict[key] as? Bool }
|
|
195
|
+
func int (_ key: String) -> Int? { (dict[key] as? NSNumber)?.intValue }
|
|
196
|
+
func string(_ key: String) -> String? { dict[key] as? String }
|
|
197
|
+
|
|
198
|
+
if let v = int("precisionMode"),
|
|
199
|
+
let e = PrecisionMode(rawValue: v) {
|
|
200
|
+
settings.precisionMode = e
|
|
201
|
+
}
|
|
202
|
+
if let v = int("operatingMode"),
|
|
203
|
+
let e = OperatingMode(rawValue: v) {
|
|
204
|
+
settings.operatingMode = e
|
|
205
|
+
}
|
|
206
|
+
if let v = int("measurementPreset"),
|
|
207
|
+
let e = MeasurementPreset(rawValue: v) {
|
|
208
|
+
settings.measurementPreset = e
|
|
209
|
+
}
|
|
210
|
+
if let v = int("cameraMode"),
|
|
211
|
+
let e = CameraMode(rawValue: v) {
|
|
212
|
+
settings.cameraMode = e
|
|
213
|
+
}
|
|
214
|
+
if let v = int("onboardingMode"),
|
|
215
|
+
let e = OnboardingMode(rawValue: v) {
|
|
216
|
+
settings.onboardingMode = e
|
|
217
|
+
}
|
|
218
|
+
if let v = int("initializationMode"),
|
|
219
|
+
let e = InitializationMode(rawValue: v) {
|
|
220
|
+
settings.initializationMode = e
|
|
221
|
+
}
|
|
222
|
+
if let v = bool("offlineProcessing") {
|
|
223
|
+
settings.offlineProcessing = v
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if let v = bool("showUserInterface") { settings.showUserInterface = v }
|
|
227
|
+
if let v = bool("showFacePositioningOverlay") { settings.showFacePositioningOverlay = v }
|
|
228
|
+
if let v = bool("showVisualWarnings") { settings.showVisualWarnings = v }
|
|
229
|
+
if let v = bool("enableCameraSwap") { settings.enableCameraSwap = v }
|
|
230
|
+
if let v = bool("showFaceMask") { settings.showFaceMask = v }
|
|
231
|
+
if let v = bool("showBloodFlow") { settings.showBloodFlow = v }
|
|
232
|
+
if let v = bool("hideShenaiLogo") { settings.hideShenaiLogo = v }
|
|
233
|
+
if let v = bool("includeTimestampInPdf") { settings.includeTimestampInPdf = v }
|
|
234
|
+
if let v = string("pdfEmailSubject") { settings.pdfEmailSubject = v }
|
|
235
|
+
if let v = string("pdfEmailBody") { settings.pdfEmailBody = v }
|
|
236
|
+
if let v = bool("enableStartAfterSuccess") { settings.enableStartAfterSuccess = v }
|
|
237
|
+
if let v = bool("enableSummaryScreen") { settings.enableSummaryScreen = v }
|
|
238
|
+
if let v = bool("showResultsFinishButton") { settings.showResultsFinishButton = v }
|
|
239
|
+
if let v = bool("enableHealthRisks") { settings.enableHealthRisks = v }
|
|
240
|
+
if let v = bool("showHealthIndicesFinishButton") {
|
|
241
|
+
settings.showHealthIndicesFinishButton = v
|
|
242
|
+
}
|
|
243
|
+
if let v = bool("saveHealthRisksFactors") { settings.saveHealthRisksFactors = v }
|
|
244
|
+
if let v = bool("showOutOfRangeResultIndicators"){ settings.showOutOfRangeResultIndicators = v }
|
|
245
|
+
if let v = bool("showTrialMetricLabels") { settings.showTrialMetricLabels = v }
|
|
246
|
+
if let v = bool("showSignalQualityIndicator") { settings.showSignalQualityIndicator = v }
|
|
247
|
+
if let v = bool("showSignalTile") { settings.showSignalTile = v }
|
|
248
|
+
if let v = bool("showStartStopButton") { settings.showStartStopButton = v }
|
|
249
|
+
if let v = bool("showInfoButton") { settings.showInfoButton = v }
|
|
250
|
+
if let v = bool("showDisclaimer") { settings.showDisclaimer = v }
|
|
251
|
+
if let v = bool("enableMeasurementsDashboard") { settings.enableMeasurementsDashboard = v }
|
|
252
|
+
if let v = int("uiVersion"),
|
|
253
|
+
let e = UiVersion(rawValue: v) {
|
|
254
|
+
settings.uiVersion = e
|
|
255
|
+
}
|
|
256
|
+
if let v = int("frameWidth") {
|
|
257
|
+
settings.frameWidth = Int32(v)
|
|
258
|
+
}
|
|
259
|
+
if let v = int("frameHeight") {
|
|
260
|
+
settings.frameHeight = Int32(v)
|
|
261
|
+
}
|
|
262
|
+
if let v = int("rotation") {
|
|
263
|
+
settings.rotation = Int32(v)
|
|
264
|
+
}
|
|
265
|
+
if let list = dict["uiFlowScreens"] as? [Int] {
|
|
266
|
+
settings.uiFlowScreens = list.map { NSNumber(value: $0) }
|
|
267
|
+
}
|
|
268
|
+
if let rf = dict["risksFactors"] as? [String: Any] {
|
|
269
|
+
settings.risksFactors = risks(from: rf)
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
settings.eventCallback = { [weak self] event in
|
|
274
|
+
var name = "UNKNOWN"
|
|
275
|
+
switch event {
|
|
276
|
+
case .startButtonClicked: name = "START_BUTTON_CLICKED"
|
|
277
|
+
case .stopButtonClicked: name = "STOP_BUTTON_CLICKED"
|
|
278
|
+
case .measurementFinished: name = "MEASUREMENT_FINISHED"
|
|
279
|
+
case .userFlowFinished: name = "USER_FLOW_FINISHED"
|
|
280
|
+
case .screenChanged: name = "SCREEN_CHANGED"
|
|
281
|
+
@unknown default: break
|
|
282
|
+
}
|
|
283
|
+
self?.notifyListeners("ShenAIEvent", data: ["EventName": name])
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
let result = ShenaiSDK.initialize(apiKey, userID: userId, settings: settings)
|
|
287
|
+
|
|
288
|
+
DispatchQueue.main.async { [weak self] in
|
|
289
|
+
guard let self,
|
|
290
|
+
let host = self.bridge?.viewController,
|
|
291
|
+
let webView = self.bridge?.webView else {
|
|
292
|
+
call.reject("Capacitor bridge view is not available")
|
|
293
|
+
return
|
|
294
|
+
}
|
|
295
|
+
self.installShenaiView(in: host.view, alongside: webView)
|
|
296
|
+
call.resolve(["value": result.rawValue])
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
@objc func isInitialized(_ call: CAPPluginCall) {
|
|
301
|
+
call.resolve(["value": ShenaiSDK.isInitialized()])
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
@objc func deinitialize(_ call: CAPPluginCall) {
|
|
305
|
+
ShenaiSDK.deinitialize()
|
|
306
|
+
DispatchQueue.main.async { [weak self] in
|
|
307
|
+
self?.removeShenaiView()
|
|
308
|
+
if let webView = self?.bridge?.webView {
|
|
309
|
+
self?.restoreOpaqueWebView(webView)
|
|
310
|
+
}
|
|
311
|
+
call.resolve()
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
@objc func setViewRect(_ call: CAPPluginCall) {
|
|
316
|
+
let x = CGFloat(call.getDouble("x") ?? 0.0)
|
|
317
|
+
let y = CGFloat(call.getDouble("y") ?? 0.0)
|
|
318
|
+
let width = CGFloat(call.getDouble("width") ?? 0.0)
|
|
319
|
+
let height = CGFloat(call.getDouble("height") ?? 0.0)
|
|
320
|
+
|
|
321
|
+
DispatchQueue.main.async { [weak self] in
|
|
322
|
+
guard let containerView = self?.shenaiContainerView,
|
|
323
|
+
let parent = containerView.superview else {
|
|
324
|
+
call.reject("View not initialized")
|
|
325
|
+
return
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
let fullWidth = width == 0.0
|
|
329
|
+
let fullHeight = height == 0.0
|
|
330
|
+
containerView.frame = CGRect(
|
|
331
|
+
x: x,
|
|
332
|
+
y: y,
|
|
333
|
+
width: fullWidth ? parent.bounds.width : width,
|
|
334
|
+
height: fullHeight ? parent.bounds.height : height
|
|
335
|
+
)
|
|
336
|
+
containerView.autoresizingMask = fullWidth && fullHeight ? [.flexibleWidth, .flexibleHeight] : []
|
|
337
|
+
self?.shenaiView?.view.frame = containerView.bounds
|
|
338
|
+
call.resolve()
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
@objc func setOverlaysWebview(_ call: CAPPluginCall) {
|
|
343
|
+
guard let overlay = call.getBool("overlay") else {
|
|
344
|
+
call.reject("overlay is required")
|
|
345
|
+
return
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
DispatchQueue.main.async { [weak self] in
|
|
349
|
+
guard let self,
|
|
350
|
+
let containerView = self.shenaiContainerView,
|
|
351
|
+
let webView = self.bridge?.webView,
|
|
352
|
+
let parent = containerView.superview else {
|
|
353
|
+
call.reject("View not initialized")
|
|
354
|
+
return
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
if overlay {
|
|
358
|
+
parent.bringSubviewToFront(containerView)
|
|
359
|
+
} else {
|
|
360
|
+
self.configureTransparentWebView(webView)
|
|
361
|
+
parent.bringSubviewToFront(webView)
|
|
362
|
+
}
|
|
363
|
+
call.resolve()
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
private func installShenaiView(in hostView: UIView, alongside webView: UIView) {
|
|
368
|
+
removeShenaiView()
|
|
369
|
+
configureTransparentWebView(webView)
|
|
370
|
+
|
|
371
|
+
let parent: UIView = webView.superview ?? hostView
|
|
372
|
+
let containerView = UIView(frame: parent.bounds)
|
|
373
|
+
containerView.backgroundColor = .clear
|
|
374
|
+
containerView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
375
|
+
|
|
376
|
+
let shenaiView = ShenaiView()
|
|
377
|
+
shenaiView.view.frame = containerView.bounds
|
|
378
|
+
shenaiView.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
379
|
+
containerView.addSubview(shenaiView.view)
|
|
380
|
+
|
|
381
|
+
parent.addSubview(containerView)
|
|
382
|
+
parent.bringSubviewToFront(webView)
|
|
383
|
+
|
|
384
|
+
self.shenaiView = shenaiView
|
|
385
|
+
self.shenaiContainerView = containerView
|
|
386
|
+
installTouchForwardingRecognizer(on: webView)
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
private func removeShenaiView() {
|
|
390
|
+
if let recognizer = touchForwardingRecognizer {
|
|
391
|
+
recognizer.view?.removeGestureRecognizer(recognizer)
|
|
392
|
+
touchForwardingRecognizer = nil
|
|
393
|
+
}
|
|
394
|
+
if let view = shenaiView {
|
|
395
|
+
if view.parent != nil {
|
|
396
|
+
view.willMove(toParent: nil)
|
|
397
|
+
}
|
|
398
|
+
view.view.removeFromSuperview()
|
|
399
|
+
if view.parent != nil {
|
|
400
|
+
view.removeFromParent()
|
|
401
|
+
}
|
|
402
|
+
shenaiView = nil
|
|
403
|
+
}
|
|
404
|
+
shenaiContainerView?.removeFromSuperview()
|
|
405
|
+
shenaiContainerView = nil
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
private func configureTransparentWebView(_ webView: UIView) {
|
|
409
|
+
webView.backgroundColor = .clear
|
|
410
|
+
if let webView = webView as? WKWebView {
|
|
411
|
+
webView.isOpaque = false
|
|
412
|
+
webView.scrollView.backgroundColor = .clear
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
private func restoreOpaqueWebView(_ webView: UIView) {
|
|
417
|
+
webView.backgroundColor = .white
|
|
418
|
+
if let webView = webView as? WKWebView {
|
|
419
|
+
webView.isOpaque = true
|
|
420
|
+
webView.scrollView.backgroundColor = .white
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
private func installTouchForwardingRecognizer(on webView: UIView) {
|
|
425
|
+
let recognizer = ShenaiTouchForwardingRecognizer(target: nil, action: nil)
|
|
426
|
+
recognizer.cancelsTouchesInView = false
|
|
427
|
+
recognizer.delaysTouchesBegan = false
|
|
428
|
+
recognizer.delaysTouchesEnded = false
|
|
429
|
+
|
|
430
|
+
recognizer.shouldForwardTouch = { [weak self] touch in
|
|
431
|
+
guard let containerView = self?.shenaiContainerView else {
|
|
432
|
+
return false
|
|
433
|
+
}
|
|
434
|
+
return containerView.bounds.contains(touch.location(in: containerView))
|
|
435
|
+
}
|
|
436
|
+
recognizer.onTouchesBegan = { [weak self] touches, event in
|
|
437
|
+
self?.shenaiView?.view.touchesBegan(touches, with: event)
|
|
438
|
+
}
|
|
439
|
+
recognizer.onTouchesMoved = { [weak self] touches, event in
|
|
440
|
+
self?.shenaiView?.view.touchesMoved(touches, with: event)
|
|
441
|
+
}
|
|
442
|
+
recognizer.onTouchesEnded = { [weak self] touches, event in
|
|
443
|
+
self?.shenaiView?.view.touchesEnded(touches, with: event)
|
|
444
|
+
}
|
|
445
|
+
recognizer.onTouchesCancelled = { [weak self] touches, event in
|
|
446
|
+
self?.shenaiView?.view.touchesCancelled(touches, with: event)
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
webView.addGestureRecognizer(recognizer)
|
|
450
|
+
touchForwardingRecognizer = recognizer
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// MARK: - ShenaiSDK thin wrappers -------------------------------------------
|
|
454
|
+
|
|
455
|
+
// Example of the simple one-liners; the pattern is identical for every pair
|
|
456
|
+
// ---------------------------------------------------------------------------
|
|
457
|
+
|
|
458
|
+
@objc func setOperatingMode(_ call: CAPPluginCall) {
|
|
459
|
+
guard let raw = call.getInt("operatingMode"),
|
|
460
|
+
let mode = OperatingMode(rawValue: raw) else {
|
|
461
|
+
call.reject("operatingMode must be a valid enum raw value")
|
|
462
|
+
return
|
|
463
|
+
}
|
|
464
|
+
ShenaiSDK.setOperatingMode(mode)
|
|
465
|
+
call.resolve()
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
@objc func startMeasurement(_ call: CAPPluginCall) {
|
|
469
|
+
ShenaiSDK.startMeasurement()
|
|
470
|
+
call.resolve()
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
@objc func stopMeasurement(_ call: CAPPluginCall) {
|
|
474
|
+
ShenaiSDK.stopMeasurement()
|
|
475
|
+
call.resolve()
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
@objc func resetMeasurementSession(_ call: CAPPluginCall) {
|
|
479
|
+
ShenaiSDK.resetMeasurementSession()
|
|
480
|
+
call.resolve()
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
@objc func getOperatingMode(_ call: CAPPluginCall) {
|
|
484
|
+
call.resolve(["value": ShenaiSDK.getOperatingMode().rawValue])
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
@objc func getCalibrationState(_ call: CAPPluginCall) {
|
|
488
|
+
call.resolve(["value": ShenaiSDK.getCalibrationState()])
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
@objc func setPrecisionMode(_ call: CAPPluginCall) {
|
|
492
|
+
guard let raw = call.getInt("precisionMode"),
|
|
493
|
+
let mode = PrecisionMode(rawValue: raw) else {
|
|
494
|
+
call.reject("precisionMode must be a valid enum raw value"); return
|
|
495
|
+
}
|
|
496
|
+
ShenaiSDK.setPrecisionMode(mode)
|
|
497
|
+
call.resolve()
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
@objc func getPrecisionMode(_ call: CAPPluginCall) {
|
|
501
|
+
call.resolve(["value": ShenaiSDK.getPrecisionMode().rawValue])
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
@objc func setMeasurementPreset(_ call: CAPPluginCall) {
|
|
506
|
+
guard let raw = call.getInt("preset"),
|
|
507
|
+
let preset = MeasurementPreset(rawValue: raw) else {
|
|
508
|
+
call.reject("preset must be a valid enum raw value"); return
|
|
509
|
+
}
|
|
510
|
+
ShenaiSDK.setMeasurementPreset(preset)
|
|
511
|
+
call.resolve()
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
@objc func getMeasurementPreset(_ call: CAPPluginCall) {
|
|
515
|
+
call.resolve(["value": ShenaiSDK.getMeasurementPreset().rawValue])
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
@objc func setCameraMode(_ call: CAPPluginCall) {
|
|
519
|
+
guard let raw = call.getInt("cameraMode"),
|
|
520
|
+
let mode = CameraMode(rawValue: raw) else {
|
|
521
|
+
call.reject("cameraMode must be a valid enum raw value"); return
|
|
522
|
+
}
|
|
523
|
+
ShenaiSDK.setCameraMode(mode)
|
|
524
|
+
call.resolve()
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
@objc func getCameraMode(_ call: CAPPluginCall) {
|
|
528
|
+
call.resolve(["value": ShenaiSDK.getCameraMode().rawValue])
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
@objc func getLastCameraError(_ call: CAPPluginCall) {
|
|
532
|
+
call.resolve(["value": ShenaiSDK.getLastCameraError() as Any? ?? NSNull()])
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
@objc func setScreen(_ call: CAPPluginCall) {
|
|
536
|
+
guard let raw = call.getInt("screen"), let screen = Screen(rawValue: raw) else {
|
|
537
|
+
call.reject("screen must be a valid enum raw value"); return
|
|
538
|
+
}
|
|
539
|
+
ShenaiSDK.setScreen(screen)
|
|
540
|
+
call.resolve()
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
@objc func getScreen(_ call: CAPPluginCall) {
|
|
544
|
+
call.resolve(["value": ShenaiSDK.getScreen().rawValue])
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// --------------------------------------------------------------------------
|
|
548
|
+
// BOOL FLAGS (straight through)
|
|
549
|
+
// --------------------------------------------------------------------------
|
|
550
|
+
@objc func setShowUserInterface(_ call: CAPPluginCall) {
|
|
551
|
+
if let v = call.getBool("value") {
|
|
552
|
+
ShenaiSDK.setShowUserInterface(v)
|
|
553
|
+
}
|
|
554
|
+
call.resolve()
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
@objc func getShowUserInterface(_ call: CAPPluginCall) {
|
|
558
|
+
call.resolve(["value": ShenaiSDK.getShowUserInterface()])
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
// … replicate the same tiny pattern for every set/get Bool pair:
|
|
562
|
+
// getShowFacePositioningOverlay, setEnableCameraSwap, etc.
|
|
563
|
+
// --------------------------------------------------------------------------
|
|
564
|
+
|
|
565
|
+
@objc func getMeasurementState(_ call: CAPPluginCall) {
|
|
566
|
+
call.resolve(["value": ShenaiSDK.getMeasurementState().rawValue])
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
@objc func getCurrentViolatedMeasurementEnvironmentCondition(_ call: CAPPluginCall) {
|
|
570
|
+
if let value = ShenaiSDK.getCurrentViolatedMeasurementEnvironmentCondition() {
|
|
571
|
+
call.resolve(["value": value.intValue])
|
|
572
|
+
} else {
|
|
573
|
+
call.resolve(["value": NSNull()])
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
@objc func isReadyToStartMeasurement(_ call: CAPPluginCall) {
|
|
578
|
+
call.resolve(["value": ShenaiSDK.isReadyToStartMeasurement()])
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
@objc func areRequiredModelsDownloaded(_ call: CAPPluginCall) {
|
|
582
|
+
call.resolve(["value": ShenaiSDK.areRequiredModelsDownloaded()])
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
// --------------------------------------------------------------------------
|
|
586
|
+
// FULL SIGNAL / BYTES / ARRAYS (unchanged, helpers exist)
|
|
587
|
+
// --------------------------------------------------------------------------
|
|
588
|
+
@objc func getFullPpgSignal(_ call: CAPPluginCall) {
|
|
589
|
+
call.resolve(["value": ShenaiSDK.getFullPPGSignal()])
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
@objc func setRecordingEnabled(_ call: CAPPluginCall) {
|
|
593
|
+
ShenaiSDK.setRecordingEnabled(call.getBool("enabled") ?? false)
|
|
594
|
+
call.resolve()
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
@objc func getRecordingEnabled(_ call: CAPPluginCall) {
|
|
598
|
+
call.resolve(["value": ShenaiSDK.isRecordingEnabled()])
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
// -------------------------------------------------------------------------
|
|
602
|
+
// ADDITIONAL BOOL FLAGS
|
|
603
|
+
// -------------------------------------------------------------------------
|
|
604
|
+
@objc func setShowFacePositioningOverlay(_ call: CAPPluginCall) {
|
|
605
|
+
if let v = call.getBool("value") { ShenaiSDK.setShowFacePositioningOverlay(v) }
|
|
606
|
+
call.resolve()
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
@objc func getShowFacePositioningOverlay(_ call: CAPPluginCall) {
|
|
610
|
+
call.resolve(["value": ShenaiSDK.getShowFacePositioningOverlay()])
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
@objc func setShowVisualWarnings(_ call: CAPPluginCall) {
|
|
614
|
+
if let v = call.getBool("value") { ShenaiSDK.setShowVisualWarnings(v) }
|
|
615
|
+
call.resolve()
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
@objc func getShowVisualWarnings(_ call: CAPPluginCall) {
|
|
619
|
+
call.resolve(["value": ShenaiSDK.getShowVisualWarnings()])
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
@objc func setEnableCameraSwap(_ call: CAPPluginCall) {
|
|
623
|
+
if let v = call.getBool("value") { ShenaiSDK.setEnableCameraSwap(v) }
|
|
624
|
+
call.resolve()
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
@objc func getEnableCameraSwap(_ call: CAPPluginCall) {
|
|
628
|
+
call.resolve(["value": ShenaiSDK.getEnableCameraSwap()])
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
@objc func setShowFaceMask(_ call: CAPPluginCall) {
|
|
632
|
+
if let v = call.getBool("value") { ShenaiSDK.setShowFaceMask(v) }
|
|
633
|
+
call.resolve()
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
@objc func getShowFaceMask(_ call: CAPPluginCall) {
|
|
637
|
+
call.resolve(["value": ShenaiSDK.getShowFaceMask()])
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
@objc func setShowBloodFlow(_ call: CAPPluginCall) {
|
|
641
|
+
if let v = call.getBool("value") { ShenaiSDK.setShowBloodFlow(v) }
|
|
642
|
+
call.resolve()
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
@objc func getShowBloodFlow(_ call: CAPPluginCall) {
|
|
646
|
+
call.resolve(["value": ShenaiSDK.getShowBloodFlow()])
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
@objc func setIncludeTimestampInPdf(_ call: CAPPluginCall) {
|
|
650
|
+
if let v = call.getBool("value") { ShenaiSDK.setIncludeTimestampInPdf(v) }
|
|
651
|
+
call.resolve()
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
@objc func getIncludeTimestampInPdf(_ call: CAPPluginCall) {
|
|
655
|
+
call.resolve(["value": ShenaiSDK.getIncludeTimestampInPdf()])
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
@objc func setPdfEmailSubject(_ call: CAPPluginCall) {
|
|
659
|
+
ShenaiSDK.setPdfEmailSubject(call.getString("subject") ?? "")
|
|
660
|
+
call.resolve()
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
@objc func setPdfEmailBody(_ call: CAPPluginCall) {
|
|
664
|
+
ShenaiSDK.setPdfEmailBody(call.getString("body") ?? "")
|
|
665
|
+
call.resolve()
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
@objc func setShowStartStopButton(_ call: CAPPluginCall) {
|
|
669
|
+
if let v = call.getBool("value") { ShenaiSDK.setShowStartStopButton(v) }
|
|
670
|
+
call.resolve()
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
@objc func getShowStartStopButton(_ call: CAPPluginCall) {
|
|
674
|
+
call.resolve(["value": ShenaiSDK.getShowStartStopButton()])
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
@objc func setEnableMeasurementsDashboard(_ call: CAPPluginCall) {
|
|
678
|
+
if let v = call.getBool("value") { ShenaiSDK.setEnableMeasurementsDashboard(v) }
|
|
679
|
+
call.resolve()
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
@objc func getEnableMeasurementsDashboard(_ call: CAPPluginCall) {
|
|
683
|
+
call.resolve(["value": ShenaiSDK.getEnableMeasurementsDashboard()])
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
@objc func setShowInfoButton(_ call: CAPPluginCall) {
|
|
687
|
+
if let v = call.getBool("value") { ShenaiSDK.setShowInfoButton(v) }
|
|
688
|
+
call.resolve()
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
@objc func getShowInfoButton(_ call: CAPPluginCall) {
|
|
692
|
+
call.resolve(["value": ShenaiSDK.getShowInfoButton()])
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
@objc func getShowDisclaimer(_ call: CAPPluginCall) {
|
|
696
|
+
call.resolve(["value": ShenaiSDK.getShowDisclaimer()])
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
@objc func setEnableStartAfterSuccess(_ call: CAPPluginCall) {
|
|
700
|
+
if let v = call.getBool("value") { ShenaiSDK.setEnableStartAfterSuccess(v) }
|
|
701
|
+
call.resolve()
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
@objc func getEnableStartAfterSuccess(_ call: CAPPluginCall) {
|
|
705
|
+
call.resolve(["value": ShenaiSDK.getEnableStartAfterSuccess()])
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
// -------------------------------------------------------------------------
|
|
709
|
+
// MEASUREMENT STATUS / RESULTS
|
|
710
|
+
// -------------------------------------------------------------------------
|
|
711
|
+
|
|
712
|
+
@objc func getFaceState(_ call: CAPPluginCall) {
|
|
713
|
+
call.resolve(["value": ShenaiSDK.getFaceState().rawValue])
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
@objc func getNormalizedFaceBbox(_ call: CAPPluginCall) {
|
|
717
|
+
if let box = ShenaiSDK.getNormalizedFaceBbox() {
|
|
718
|
+
call.resolve(["x": box.x, "y": box.y, "width": box.width, "height": box.height])
|
|
719
|
+
} else {
|
|
720
|
+
call.resolve()
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
@objc func getMeasurementProgressPercentage(_ call: CAPPluginCall) {
|
|
725
|
+
call.resolve(["value": ShenaiSDK.getMeasurementProgressPercentage()])
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
@objc func getHeartRate10s(_ call: CAPPluginCall) {
|
|
729
|
+
if let hr = ShenaiSDK.getHeartRate10s() { call.resolve(["value": hr]) } else { call.resolve() }
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
@objc func getHeartRate4s(_ call: CAPPluginCall) {
|
|
733
|
+
if let hr = ShenaiSDK.getHeartRate4s() { call.resolve(["value": hr]) } else { call.resolve() }
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
@objc func getRealtimeMetrics(_ call: CAPPluginCall) {
|
|
737
|
+
let period = call.getDouble("periodSec") ?? 1.0
|
|
738
|
+
if let r = ShenaiSDK.getRealtimeMetrics(period) {
|
|
739
|
+
call.resolve(["value": dict(from: r)])
|
|
740
|
+
} else {
|
|
741
|
+
call.resolve()
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
@objc func getMeasurementResults(_ call: CAPPluginCall) {
|
|
746
|
+
if let r = ShenaiSDK.getMeasurementResults() {
|
|
747
|
+
call.resolve(["value": dict(from: r)])
|
|
748
|
+
} else {
|
|
749
|
+
call.resolve()
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
@objc func getMeasurementResultsHistory(_ call: CAPPluginCall) {
|
|
754
|
+
if let hist = ShenaiSDK.getMeasurementResultsHistory() {
|
|
755
|
+
let arr = hist.history.map { ["measurementResults": dict(from: $0.measurementResults),
|
|
756
|
+
"epochTimestamp": $0.epochTimestamp,
|
|
757
|
+
"isCalibration": $0.isCalibration] }
|
|
758
|
+
call.resolve(["value": arr])
|
|
759
|
+
} else {
|
|
760
|
+
call.resolve()
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
@objc func getRealtimeHeartbeats(_ call: CAPPluginCall) {
|
|
765
|
+
let period = call.getDouble("periodSec")
|
|
766
|
+
let arr = ShenaiSDK.getRealtimeHeartbeats(period == nil ? nil : NSNumber(value: period!))
|
|
767
|
+
.map { ["startLocationSec": $0.startLocationSec, "endLocationSec": $0.endLocationSec, "durationMs": $0.durationMs] }
|
|
768
|
+
call.resolve(["value": arr])
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
@objc func getTotalBadSignalSeconds(_ call: CAPPluginCall) {
|
|
772
|
+
call.resolve(["value": ShenaiSDK.getTotalBadSignalSeconds()])
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
@objc func getCurrentSignalQualityMetric(_ call: CAPPluginCall) {
|
|
776
|
+
call.resolve(["value": ShenaiSDK.getCurrentSignalQualityMetric()])
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
@objc func getSignalQualityMapPng(_ call: CAPPluginCall) {
|
|
780
|
+
if let data = ShenaiSDK.getSignalQualityMapPng() {
|
|
781
|
+
let bytes = [UInt8](data)
|
|
782
|
+
call.resolve(["value": bytes])
|
|
783
|
+
} else { call.resolve() }
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
@objc func getFaceTexturePng(_ call: CAPPluginCall) {
|
|
787
|
+
if let data = ShenaiSDK.getFaceTexturePng() {
|
|
788
|
+
let bytes = [UInt8](data)
|
|
789
|
+
call.resolve(["value": bytes])
|
|
790
|
+
} else { call.resolve() }
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
@objc func setCustomMeasurementConfig(_ call: CAPPluginCall) {
|
|
794
|
+
guard let dict = call.getObject("config") else { call.resolve(); return }
|
|
795
|
+
let c = CustomMeasurementConfig()
|
|
796
|
+
c.durationSeconds = dict["durationSeconds"] as? NSNumber
|
|
797
|
+
c.infiniteMeasurement = dict["infiniteMeasurement"] as? Bool ?? false
|
|
798
|
+
c.instantMetrics = dict["instantMetrics"] as? [NSNumber]
|
|
799
|
+
c.summaryMetrics = dict["summaryMetrics"] as? [NSNumber]
|
|
800
|
+
c.healthIndices = dict["healthIndices"] as? [NSNumber]
|
|
801
|
+
c.realtimeHrPeriodSeconds = dict["realtimeHrPeriodSeconds"] as? NSNumber
|
|
802
|
+
c.realtimeHrvPeriodSeconds = dict["realtimeHrvPeriodSeconds"] as? NSNumber
|
|
803
|
+
c.realtimeCardiacStressPeriodSeconds = dict["realtimeCardiacStressPeriodSeconds"] as? NSNumber
|
|
804
|
+
ShenaiSDK.setCustomMeasurementConfig(c)
|
|
805
|
+
call.resolve()
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
@objc func setCustomColorTheme(_ call: CAPPluginCall) {
|
|
809
|
+
guard let dict = call.getObject("theme") else { call.resolve(); return }
|
|
810
|
+
let t = CustomColorTheme()
|
|
811
|
+
t.themeColor = dict["themeColor"] as? String ?? ""
|
|
812
|
+
t.textColor = dict["textColor"] as? String ?? ""
|
|
813
|
+
t.backgroundColor = dict["backgroundColor"] as? String ?? ""
|
|
814
|
+
t.tileColor = dict["tileColor"] as? String ?? ""
|
|
815
|
+
t.buttonMainColor = dict["buttonMainColor"] as? String ?? ""
|
|
816
|
+
t.buttonSecondaryColor = dict["buttonSecondaryColor"] as? String ?? ""
|
|
817
|
+
ShenaiSDK.setCustomColorTheme(t)
|
|
818
|
+
call.resolve()
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
@objc func setLanguage(_ call: CAPPluginCall) {
|
|
822
|
+
if let lang = call.getString("language") { ShenaiSDK.setLanguage(lang) }
|
|
823
|
+
call.resolve()
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
@objc func getHealthRisksFactors(_ call: CAPPluginCall) {
|
|
827
|
+
let factors = ShenaiHealthRisks.getFactors()
|
|
828
|
+
call.resolve(["value": dict(from: factors)])
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
@objc func getHealthRisks(_ call: CAPPluginCall) {
|
|
832
|
+
let risks = ShenaiHealthRisks.getHealthRisks()
|
|
833
|
+
call.resolve(["value": dict(from: risks)])
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
@objc func computeHealthRisks(_ call: CAPPluginCall) {
|
|
837
|
+
let factors = risks(from: call.getObject("risksFactors"))
|
|
838
|
+
let risks = ShenaiHealthRisks.computeHealthRisks(factors)
|
|
839
|
+
call.resolve(["value": dict(from: risks)])
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
@objc func getMaximalRisks(_ call: CAPPluginCall) {
|
|
843
|
+
let factors = risks(from: call.getObject("risksFactors"))
|
|
844
|
+
let risks = ShenaiHealthRisks.getMaximalRisks(factors)
|
|
845
|
+
call.resolve(["value": dict(from: risks)])
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
@objc func getMinimalRisks(_ call: CAPPluginCall) {
|
|
849
|
+
let factors = risks(from: call.getObject("risksFactors"))
|
|
850
|
+
let risks = ShenaiHealthRisks.getMinimalRisks(factors)
|
|
851
|
+
call.resolve(["value": dict(from: risks)])
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
@objc func getReferenceRisks(_ call: CAPPluginCall) {
|
|
855
|
+
let factors = risks(from: call.getObject("risksFactors"))
|
|
856
|
+
let risks = ShenaiHealthRisks.getReferenceRisks(factors)
|
|
857
|
+
call.resolve(["value": dict(from: risks)])
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
@objc func openMeasurementResultsPdfInBrowser(_ call: CAPPluginCall) {
|
|
861
|
+
ShenaiSDK.openMeasurementResultsPdfInBrowser()
|
|
862
|
+
call.resolve()
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
@objc func sendMeasurementResultsPdfToEmail(_ call: CAPPluginCall) {
|
|
866
|
+
if let email = call.getString("email") { ShenaiSDK.sendMeasurementResultsPdf(toEmail: email) }
|
|
867
|
+
call.resolve()
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
@objc func requestMeasurementResultsPdfUrl(_ call: CAPPluginCall) {
|
|
871
|
+
ShenaiSDK.requestMeasurementResultsPdfUrl()
|
|
872
|
+
call.resolve()
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
@objc func getMeasurementResultsPdfUrl(_ call: CAPPluginCall) {
|
|
876
|
+
if let url = ShenaiSDK.getMeasurementResultsPdfUrl() {
|
|
877
|
+
call.resolve(["value": url])
|
|
878
|
+
} else { call.resolve() }
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
@objc func requestMeasurementResultsPdfBytes(_ call: CAPPluginCall) {
|
|
882
|
+
ShenaiSDK.requestMeasurementResultsPdfBytes()
|
|
883
|
+
call.resolve()
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
@objc func getMeasurementResultsPdfBytes(_ call: CAPPluginCall) {
|
|
887
|
+
if let data = ShenaiSDK.getMeasurementResultsPdfBytes() {
|
|
888
|
+
call.resolve(["valueBase64": data.base64EncodedString()])
|
|
889
|
+
} else { call.resolve() }
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
@objc func getResultAsFhirObservation(_ call: CAPPluginCall) {
|
|
893
|
+
if let observation = ShenaiSDK.getResultAsFhirObservation(), !observation.isEmpty {
|
|
894
|
+
call.resolve(["value": observation])
|
|
895
|
+
} else {
|
|
896
|
+
call.resolve()
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
@objc func sendResultFhirObservation(_ call: CAPPluginCall) {
|
|
901
|
+
guard let url = call.getString("url"), !url.isEmpty else {
|
|
902
|
+
call.reject("url is required")
|
|
903
|
+
return
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
ShenaiSDK.sendResultFhirObservation(url) { response in
|
|
907
|
+
if let response = response, !response.isEmpty {
|
|
908
|
+
call.resolve(["value": response])
|
|
909
|
+
} else {
|
|
910
|
+
call.resolve(["value": NSNull()])
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
|
|
916
|
+
// …repeat the same pattern for all the remaining ≈70 methods …
|
|
917
|
+
// (translation is mechanical: replace `call getXXX` with Swift variant,
|
|
918
|
+
// convert Objective-C structs/objects to dictionaries, then resolve)
|
|
919
|
+
|
|
920
|
+
// MARK: - Helpers -----------------------------------------------------------
|
|
921
|
+
|
|
922
|
+
private func dict(from risks: RisksFactors) -> [String: Any] {
|
|
923
|
+
var d: [String: Any] = [:]
|
|
924
|
+
if let v = risks.age { d["age"] = v }
|
|
925
|
+
if let v = risks.cholesterol { d["cholesterol"] = v }
|
|
926
|
+
if let v = risks.cholesterolHDL { d["cholesterolHdl"] = v }
|
|
927
|
+
if let v = risks.sbp { d["sbp"] = v }
|
|
928
|
+
if let v = risks.dbp { d["dbp"] = v }
|
|
929
|
+
if let v = risks.isSmoker { d["isSmoker"] = v }
|
|
930
|
+
d["hypertensionTreatment"] = risks.hypertensionTreatment
|
|
931
|
+
if let v = risks.hasDiabetes { d["hasDiabetes"] = v }
|
|
932
|
+
if let v = risks.bodyHeight { d["bodyHeight"] = v }
|
|
933
|
+
if let v = risks.bodyWeight { d["bodyWeight"] = v }
|
|
934
|
+
if let v = risks.waistCircumference { d["waistCircumference"] = v }
|
|
935
|
+
if let v = risks.neckCircumference { d["neckCircumference"] = v }
|
|
936
|
+
if let v = risks.hipCircumference { d["hipCircumference"] = v }
|
|
937
|
+
d["gender"] = risks.gender
|
|
938
|
+
d["physicalActivity"] = risks.physicalActivity
|
|
939
|
+
if let v = risks.country { d["country"] = v }
|
|
940
|
+
d["race"] = risks.race
|
|
941
|
+
if let v = risks.vegetableFruitDiet { d["vegetableFruitDiet"] = v }
|
|
942
|
+
if let v = risks.historyOfHighGlucose { d["historyOfHighGlucose"] = v }
|
|
943
|
+
if let v = risks.historyOfHypertension { d["historyOfHypertension"] = v }
|
|
944
|
+
if let v = risks.triglyceride { d["triglyceride"] = v }
|
|
945
|
+
if let v = risks.fastingGlucose { d["fastingGlucose"] = v }
|
|
946
|
+
d["familyDiabetes"] = risks.familyDiabetes
|
|
947
|
+
d["parentalHypertension"] = risks.parentalHypertension
|
|
948
|
+
return d
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
private func risks(from dict: [String: Any]?) -> RisksFactors {
|
|
952
|
+
let f = RisksFactors()
|
|
953
|
+
guard let d = dict else { return f }
|
|
954
|
+
|
|
955
|
+
// Optionals that really are NSNumber in the SDK
|
|
956
|
+
f.age = d["age"] as? NSNumber
|
|
957
|
+
f.cholesterol = d["cholesterol"] as? NSNumber
|
|
958
|
+
f.cholesterolHDL = d["cholesterolHdl"] as? NSNumber
|
|
959
|
+
f.sbp = d["sbp"] as? NSNumber
|
|
960
|
+
f.dbp = d["dbp"] as? NSNumber
|
|
961
|
+
f.isSmoker = d["isSmoker"] as? NSNumber
|
|
962
|
+
f.hasDiabetes = d["hasDiabetes"] as? NSNumber
|
|
963
|
+
f.bodyHeight = d["bodyHeight"] as? NSNumber
|
|
964
|
+
f.bodyWeight = d["bodyWeight"] as? NSNumber
|
|
965
|
+
f.waistCircumference = d["waistCircumference"] as? NSNumber
|
|
966
|
+
f.neckCircumference = d["neckCircumference"] as? NSNumber
|
|
967
|
+
f.hipCircumference = d["hipCircumference"] as? NSNumber
|
|
968
|
+
f.vegetableFruitDiet = d["vegetableFruitDiet"] as? NSNumber
|
|
969
|
+
f.historyOfHighGlucose = d["historyOfHighGlucose"] as? NSNumber
|
|
970
|
+
f.historyOfHypertension = d["historyOfHypertension"] as? NSNumber
|
|
971
|
+
f.triglyceride = d["triglyceride"] as? NSNumber
|
|
972
|
+
f.fastingGlucose = d["fastingGlucose"] as? NSNumber
|
|
973
|
+
|
|
974
|
+
// Enum-backed Ints – convert through rawValue
|
|
975
|
+
if let n = (d["hypertensionTreatment"] as? NSNumber)?.intValue,
|
|
976
|
+
let e = HypertensionTreatment(rawValue: n) {
|
|
977
|
+
f.hypertensionTreatment = e
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
if let n = (d["gender"] as? NSNumber)?.intValue,
|
|
981
|
+
let e = Gender(rawValue: n) {
|
|
982
|
+
f.gender = e
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
if let n = (d["physicalActivity"] as? NSNumber)?.intValue,
|
|
986
|
+
let e = PhysicalActivity(rawValue: n) {
|
|
987
|
+
f.physicalActivity = e
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
if let n = (d["race"] as? NSNumber)?.intValue,
|
|
991
|
+
let e = Race(rawValue: n) {
|
|
992
|
+
f.race = e
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
if let n = (d["familyDiabetes"] as? NSNumber)?.intValue,
|
|
996
|
+
let e = FamilyHistory(rawValue: n) {
|
|
997
|
+
f.familyDiabetes = e
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
if let n = (d["parentalHypertension"] as? NSNumber)?.intValue,
|
|
1001
|
+
let e = ParentalHistory(rawValue: n) {
|
|
1002
|
+
f.parentalHypertension = e
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
return f
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
private func dict(from heartbeat: Heartbeat) -> [String: Any] {
|
|
1009
|
+
[
|
|
1010
|
+
"startLocationSec": heartbeat.startLocationSec,
|
|
1011
|
+
"endLocationSec": heartbeat.endLocationSec,
|
|
1012
|
+
"durationMs": heartbeat.durationMs
|
|
1013
|
+
]
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
private func dict(from qualityMetrics: MeasurementQualityMetrics?) -> [String: Any]? {
|
|
1017
|
+
guard let qualityMetrics = qualityMetrics else { return nil }
|
|
1018
|
+
var d: [String: Any] = [:]
|
|
1019
|
+
if let v = qualityMetrics.ppgQualityIndex { d["ppgQualityIndex"] = v }
|
|
1020
|
+
if let v = qualityMetrics.bcgQualityIndex { d["bcgQualityIndex"] = v }
|
|
1021
|
+
if let v = qualityMetrics.breathingQualityIndex { d["breathingQualityIndex"] = v }
|
|
1022
|
+
if let v = qualityMetrics.bloodPressureQualityIndex { d["bloodPressureQualityIndex"] = v }
|
|
1023
|
+
if let v = qualityMetrics.expectedSbpMedianAbsErrorMmhg { d["expectedSbpMedianAbsErrorMmhg"] = v }
|
|
1024
|
+
if let v = qualityMetrics.expectedSbpP80AbsErrorMmhg { d["expectedSbpP80AbsErrorMmhg"] = v }
|
|
1025
|
+
if let v = qualityMetrics.expectedSbpMeanAbsErrorMmhg { d["expectedSbpMeanAbsErrorMmhg"] = v }
|
|
1026
|
+
if let v = qualityMetrics.expectedSbpBalancedMaeMmhg { d["expectedSbpBalancedMaeMmhg"] = v }
|
|
1027
|
+
if let v = qualityMetrics.expectedDbpMedianAbsErrorMmhg { d["expectedDbpMedianAbsErrorMmhg"] = v }
|
|
1028
|
+
if let v = qualityMetrics.expectedDbpP80AbsErrorMmhg { d["expectedDbpP80AbsErrorMmhg"] = v }
|
|
1029
|
+
if let v = qualityMetrics.expectedDbpMeanAbsErrorMmhg { d["expectedDbpMeanAbsErrorMmhg"] = v }
|
|
1030
|
+
if let v = qualityMetrics.expectedDbpBalancedMaeMmhg { d["expectedDbpBalancedMaeMmhg"] = v }
|
|
1031
|
+
return d
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
private func dict(from results: MeasurementResults) -> [String: Any] {
|
|
1035
|
+
var d: [String: Any] = [
|
|
1036
|
+
"heartRateBpm": results.heartRateBpm,
|
|
1037
|
+
"bmiCategory": results.bmiCategory.rawValue,
|
|
1038
|
+
"averageSignalQuality": results.averageSignalQuality,
|
|
1039
|
+
"heartbeats": results.heartbeats.map { dict(from: $0) }
|
|
1040
|
+
]
|
|
1041
|
+
if let v = results.hrvSdnnMs { d["hrvSdnnMs"] = v }
|
|
1042
|
+
if let v = results.hrvLnrmssdMs { d["hrvLnrmssdMs"] = v }
|
|
1043
|
+
if let v = results.stressIndex { d["stressIndex"] = v }
|
|
1044
|
+
if let v = results.parasympatheticActivity { d["parasympatheticActivity"] = v }
|
|
1045
|
+
if let v = results.breathingRateBpm { d["breathingRateBpm"] = v }
|
|
1046
|
+
if let v = results.systolicBloodPressureMmhg { d["systolicBloodPressureMmhg"] = v }
|
|
1047
|
+
if let v = results.diastolicBloodPressureMmhg { d["diastolicBloodPressureMmhg"] = v }
|
|
1048
|
+
if let v = results.cardiacWorkloadMmhgPerSec { d["cardiacWorkloadMmhgPerSec"] = v }
|
|
1049
|
+
if let v = results.ageYears { d["ageYears"] = v }
|
|
1050
|
+
if let v = results.bmiKgPerM2 { d["bmiKgPerM2"] = v }
|
|
1051
|
+
if let v = results.weightKg { d["weightKg"] = v }
|
|
1052
|
+
if let v = results.heightCm { d["heightCm"] = v }
|
|
1053
|
+
if let qualityMetrics = dict(from: results.qualityMetrics) {
|
|
1054
|
+
d["qualityMetrics"] = qualityMetrics
|
|
1055
|
+
} else {
|
|
1056
|
+
d["qualityMetrics"] = NSNull()
|
|
1057
|
+
}
|
|
1058
|
+
return d
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
private func dict(from healthRisks: HealthRisks) -> [String: Any] {
|
|
1062
|
+
var d: [String: Any] = [
|
|
1063
|
+
"hardAndFatalEvents": [
|
|
1064
|
+
"coronaryDeathEventRisk": healthRisks.hardAndFatalEvents.coronaryDeathEventRisk as Any,
|
|
1065
|
+
"fatalStrokeEventRisk": healthRisks.hardAndFatalEvents.fatalStrokeEventRisk as Any,
|
|
1066
|
+
"totalCvMortalityRisk": healthRisks.hardAndFatalEvents.totalCvMortalityRisk as Any,
|
|
1067
|
+
"hardCvEventRisk": healthRisks.hardAndFatalEvents.hardCvEventRisk as Any
|
|
1068
|
+
],
|
|
1069
|
+
"cvDiseases": [
|
|
1070
|
+
"overallRisk": healthRisks.cvDiseases.overallRisk as Any,
|
|
1071
|
+
"coronaryHeartDiseaseRisk": healthRisks.cvDiseases.coronaryHeartDiseaseRisk as Any,
|
|
1072
|
+
"strokeRisk": healthRisks.cvDiseases.strokeRisk as Any,
|
|
1073
|
+
"heartFailureRisk": healthRisks.cvDiseases.heartFailureRisk as Any,
|
|
1074
|
+
"peripheralVascularDiseaseRisk": healthRisks.cvDiseases.peripheralVascularDiseaseRisk as Any
|
|
1075
|
+
],
|
|
1076
|
+
"scores": [
|
|
1077
|
+
"ageScore": healthRisks.scores.ageScore as Any,
|
|
1078
|
+
"sbpScore": healthRisks.scores.sbpScore as Any,
|
|
1079
|
+
"smokingScore": healthRisks.scores.smokingScore as Any,
|
|
1080
|
+
"diabetesScore": healthRisks.scores.diabetesScore as Any,
|
|
1081
|
+
"bmiScore": healthRisks.scores.bmiScore as Any,
|
|
1082
|
+
"cholesterolScore": healthRisks.scores.cholesterolScore as Any,
|
|
1083
|
+
"cholesterolHdlScore": healthRisks.scores.cholesterolHdlScore as Any,
|
|
1084
|
+
"totalScore": healthRisks.scores.totalScore as Any
|
|
1085
|
+
]
|
|
1086
|
+
]
|
|
1087
|
+
if let v = healthRisks.wellnessScore { d["wellnessScore"] = v }
|
|
1088
|
+
if let v = healthRisks.vascularAge { d["vascularAge"] = v }
|
|
1089
|
+
if let v = healthRisks.bodyFatPercentage { d["bodyFatPercentage"] = v }
|
|
1090
|
+
if let v = healthRisks.basalMetabolicRate { d["basalMetabolicRate"] = v }
|
|
1091
|
+
if let v = healthRisks.waistToHeightRatio { d["waistToHeightRatio"] = v }
|
|
1092
|
+
if let v = healthRisks.bodyRoundnessIndex { d["bodyRoundnessIndex"] = v }
|
|
1093
|
+
if let v = healthRisks.conicityIndex { d["conicityIndex"] = v }
|
|
1094
|
+
if let v = healthRisks.aBodyShapeIndex { d["aBodyShapeIndex"] = v }
|
|
1095
|
+
if let v = healthRisks.totalDailyEnergyExpenditure { d["totalDailyEnergyExpenditure"] = v }
|
|
1096
|
+
if let v = healthRisks.hypertensionRisk { d["hypertensionRisk"] = v }
|
|
1097
|
+
if let v = healthRisks.diabetesRisk { d["diabetesRisk"] = v }
|
|
1098
|
+
d["nonAlcoholicFattyLiverDiseaseRisk"] = healthRisks.nonAlcoholicFattyLiverDiseaseRisk.rawValue
|
|
1099
|
+
return d
|
|
1100
|
+
}
|
|
1101
|
+
}
|