@infilectorg/infiviz-shots-react-sdk 1.2.1 → 1.2.3
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/InfivizShotSDK.xcframework/Info.plist +5 -5
- package/ios/InfivizShotSDK.xcframework/ios-arm64/InfivizShotSDK.framework/Assets.car +0 -0
- package/ios/InfivizShotSDK.xcframework/ios-arm64/InfivizShotSDK.framework/InfivizShotSDK +0 -0
- package/ios/InfivizShotSDK.xcframework/ios-arm64/InfivizShotSDK.framework/Modules/InfivizShotSDK.swiftmodule/arm64-apple-ios.abi.json +60 -60
- package/ios/InfivizShotSDK.xcframework/ios-arm64/InfivizShotSDK.framework/Modules/InfivizShotSDK.swiftmodule/arm64-apple-ios.swiftmodule +0 -0
- package/ios/InfivizShotSDK.xcframework/ios-arm64/InfivizShotSDK.framework/shotsSDK.storyboardc/xUL-ol-gRQ-view-6A8-mO-Rhi.nib +0 -0
- package/ios/InfivizShotSDK.xcframework/ios-arm64_x86_64-simulator/InfivizShotSDK.framework/InfivizShotSDK +0 -0
- package/ios/InfivizShotSDK.xcframework/ios-arm64_x86_64-simulator/InfivizShotSDK.framework/Modules/InfivizShotSDK.swiftmodule/arm64-apple-ios-simulator.abi.json +60 -60
- package/ios/InfivizShotSDK.xcframework/ios-arm64_x86_64-simulator/InfivizShotSDK.framework/Modules/InfivizShotSDK.swiftmodule/arm64-apple-ios-simulator.swiftmodule +0 -0
- package/ios/InfivizShotSDK.xcframework/ios-arm64_x86_64-simulator/InfivizShotSDK.framework/Modules/InfivizShotSDK.swiftmodule/x86_64-apple-ios-simulator.abi.json +60 -60
- package/ios/InfivizShotSDK.xcframework/ios-arm64_x86_64-simulator/InfivizShotSDK.framework/Modules/InfivizShotSDK.swiftmodule/x86_64-apple-ios-simulator.swiftmodule +0 -0
- package/ios/InfivizShotSDK.xcframework/ios-arm64_x86_64-simulator/InfivizShotSDK.framework/shotsSDK.storyboardc/xUL-ol-gRQ-view-6A8-mO-Rhi.nib +0 -0
- package/ios/InfivizShotsReactSdk.swift +593 -570
- package/lib/module/NativeInfivizShotsReactSdk.js +0 -2
- package/lib/module/NativeInfivizShotsReactSdk.js.map +1 -1
- package/lib/module/index.js +2 -4
- package/lib/module/index.js.map +1 -1
- package/lib/module/types/Environment.js +0 -2
- package/lib/module/types/Environment.js.map +1 -1
- package/lib/module/types/ImageMetaData.js +0 -2
- package/lib/module/types/ImageMetaData.js.map +1 -1
- package/lib/module/types/InfiSession.js +0 -2
- package/lib/module/types/InfiSession.js.map +1 -1
- package/lib/module/types/LabelScore.js +1 -1
- package/lib/module/types/LabelScore.js.map +1 -1
- package/lib/module/types/SessionStatus.js +1 -1
- package/lib/module/types/SessionStatus.js.map +1 -1
- package/lib/module/types/SessionSyncStateEnum.js +0 -2
- package/lib/module/types/SessionSyncStateEnum.js.map +1 -1
- package/package.json +1 -1
- package/react-native-infiviz-shots.podspec +1 -1
- package/lib/module/package.json +0 -1
- package/lib/typescript/package.json +0 -1
- package/lib/typescript/src/NativeInfivizShotsReactSdk.d.ts +0 -23
- package/lib/typescript/src/NativeInfivizShotsReactSdk.d.ts.map +0 -1
- package/lib/typescript/src/index.d.ts +0 -24
- package/lib/typescript/src/index.d.ts.map +0 -1
- package/lib/typescript/src/types/Environment.d.ts +0 -5
- package/lib/typescript/src/types/Environment.d.ts.map +0 -1
- package/lib/typescript/src/types/ImageMetaData.d.ts +0 -13
- package/lib/typescript/src/types/ImageMetaData.d.ts.map +0 -1
- package/lib/typescript/src/types/InfiSession.d.ts +0 -18
- package/lib/typescript/src/types/InfiSession.d.ts.map +0 -1
- package/lib/typescript/src/types/LabelScore.d.ts +0 -5
- package/lib/typescript/src/types/LabelScore.d.ts.map +0 -1
- package/lib/typescript/src/types/SessionStatus.d.ts +0 -5
- package/lib/typescript/src/types/SessionStatus.d.ts.map +0 -1
- package/lib/typescript/src/types/SessionSyncStateEnum.d.ts +0 -8
- package/lib/typescript/src/types/SessionSyncStateEnum.d.ts.map +0 -1
|
@@ -12,313 +12,336 @@ import React
|
|
|
12
12
|
|
|
13
13
|
@objc(InfivizShotsReactSdk)
|
|
14
14
|
class InfivizShotsReactSdk: RCTEventEmitter {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
15
|
+
@objc
|
|
16
|
+
override static func moduleName() -> String! {
|
|
17
|
+
return "InfivizShotsReactSdk"
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@objc
|
|
21
|
+
override static func requiresMainQueueSetup() -> Bool {
|
|
22
|
+
return false
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// MARK: – RCTEventEmitter Boilerplate
|
|
26
|
+
|
|
27
|
+
private var hasListeners = false
|
|
28
|
+
|
|
29
|
+
// 3. List of events that JS can subscribe to:
|
|
30
|
+
override func supportedEvents() -> [String]! {
|
|
31
|
+
return [
|
|
32
|
+
"SyncEvent",
|
|
33
|
+
"ActionsGeneratedEvent",
|
|
34
|
+
"SessionRealTimeResultEvent"]
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// 4. Only send events if JS has at least one listener:
|
|
38
|
+
override func startObserving() {
|
|
39
|
+
hasListeners = true
|
|
40
|
+
|
|
41
41
|
NotificationCenter.default.addObserver(self,
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
42
|
+
selector: #selector(handleActionsGeneratedEvent(_:)),
|
|
43
|
+
name: NSNotification.Name("ActionsGeneratedEvent"),
|
|
44
|
+
object: nil)
|
|
45
|
+
NotificationCenter.default.addObserver(self,
|
|
46
|
+
selector: #selector(handleSessionRealTimeResultEvent(_:)),
|
|
47
|
+
name: NSNotification.Name("SessionRealTimeResultEvent"),
|
|
48
|
+
object: nil)
|
|
49
|
+
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
override func stopObserving() {
|
|
53
|
+
hasListeners = false
|
|
54
|
+
NotificationCenter.default.removeObserver(self, name: NSNotification.Name("ActionsGeneratedEvent"), object: nil)
|
|
55
|
+
NotificationCenter.default.removeObserver(self, name: NSNotification.Name("SessionRealTimeResultEvent"), object: nil)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// 5. If you have no constants to export, just return empty:
|
|
59
|
+
override func constantsToExport() -> [AnyHashable: Any]! {
|
|
60
|
+
return [:]
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
var activity: InfivizShotsActivity?
|
|
65
|
+
|
|
66
|
+
// MARK: –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
|
|
67
|
+
// MARK: – Helper Methods (not directly exposed to JS)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
// MARK: - Universal Session ID
|
|
71
|
+
@objc
|
|
72
|
+
func fetchUniversalSessionId(_ tempID: NSString, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
73
|
+
InfivizShotsSDK.shared.fetchUniversalSessionId(temporarySessionID: tempID as String, completion: { sessionID, error in
|
|
74
|
+
if let id = sessionID {
|
|
75
|
+
resolve(id)
|
|
76
|
+
} else {
|
|
77
|
+
reject("FETCH_SESSION_ID_ERROR", "Session not found", nil)
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
@objc
|
|
83
|
+
func syncSession(_ sessionId: NSString) {
|
|
84
|
+
// Kick off the upload. No resolver/rejecter—just emit events once it’s done.
|
|
85
|
+
InfivizShotsSDK.shared.uploadSession(temporarySessionID: sessionId as String) { result in
|
|
86
|
+
switch result {
|
|
87
|
+
case .success(let response):
|
|
88
|
+
if self.hasListeners {
|
|
89
|
+
let payload: [String: Any] = [
|
|
90
|
+
"status": "200",
|
|
91
|
+
"universalSessionID": response,
|
|
92
|
+
"temporarySessionID": sessionId as String
|
|
93
|
+
]
|
|
94
|
+
self.sendEvent(withName: "SyncEvent", body: payload)
|
|
95
|
+
}
|
|
96
|
+
case .failure(let error):
|
|
97
|
+
if self.hasListeners {
|
|
98
|
+
let payload: [String: Any] = [
|
|
99
|
+
"status": "400",
|
|
100
|
+
"message": error.localizedDescription,
|
|
101
|
+
"temporarySessionID": sessionId as String
|
|
102
|
+
]
|
|
103
|
+
self.sendEvent(withName: "SyncEvent", body: payload)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// MARK: - Sync Multiple Sessions
|
|
110
|
+
/// Bridge to InfivizShotsSDK.shared.syncSessions(temporarySessionIDs:completionHandler:)
|
|
111
|
+
|
|
112
|
+
@objc
|
|
113
|
+
func uploadSession(temporarySessionIDs: NSArray) {
|
|
114
114
|
var ids: [String] = []
|
|
115
115
|
if let arr = temporarySessionIDs as? [String] {
|
|
116
|
-
|
|
116
|
+
ids = arr
|
|
117
117
|
} else if let arr = temporarySessionIDs as? [NSString] {
|
|
118
|
-
|
|
118
|
+
ids = arr.map { $0 as String }
|
|
119
119
|
}
|
|
120
|
-
|
|
120
|
+
|
|
121
121
|
guard !ids.isEmpty else { return }
|
|
122
|
-
|
|
122
|
+
|
|
123
123
|
InfivizShotsSDK.shared.syncSessions(temporarySessionIDs: ids) { sessionId, result in
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
124
|
+
switch result {
|
|
125
|
+
case .success(let message):
|
|
126
|
+
if self.hasListeners {
|
|
127
|
+
let payload: [String: Any] = [
|
|
128
|
+
"status": "200",
|
|
129
|
+
"universalSessionID": message,
|
|
130
|
+
"temporarySessionID": sessionId
|
|
131
|
+
]
|
|
132
|
+
self.sendEvent(withName: "SyncEvent", body: payload)
|
|
133
|
+
}
|
|
134
|
+
case .failure(let error):
|
|
135
|
+
if self.hasListeners {
|
|
136
|
+
let payload: [String: Any] = [
|
|
137
|
+
"status": "400",
|
|
138
|
+
"universalSessionID": error,
|
|
139
|
+
"temporarySessionID": sessionId
|
|
140
|
+
]
|
|
141
|
+
self.sendEvent(withName: "SyncEvent", body: payload)
|
|
142
|
+
}
|
|
142
143
|
}
|
|
143
|
-
}
|
|
144
144
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// MARK: - Get Session Result
|
|
148
|
+
|
|
149
149
|
@objc
|
|
150
150
|
func getSessionStatus(
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
151
|
+
_ temporarySessionID: NSString,
|
|
152
|
+
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
153
|
+
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
154
154
|
) {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
155
|
+
InfivizShotsSDK.shared.checkState(sessionID: temporarySessionID as String) { result in
|
|
156
|
+
switch result {
|
|
157
|
+
case .success(let response):
|
|
158
|
+
let json = ["sessionId": temporarySessionID,
|
|
159
|
+
"status": response]
|
|
160
|
+
|
|
161
|
+
if let jsonData = try? JSONSerialization.data(withJSONObject: json, options: []) {
|
|
162
|
+
let jsonString = String(data: jsonData, encoding: .utf8)
|
|
163
|
+
resolve(jsonString)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
case .failure(let error):
|
|
167
|
+
reject(
|
|
168
|
+
"RESULT_FAILED",
|
|
169
|
+
"Failed to get result for \(temporarySessionID): \(error.localizedDescription)",
|
|
170
|
+
nil
|
|
171
|
+
)
|
|
164
172
|
}
|
|
165
|
-
|
|
166
|
-
case .failure(let error):
|
|
167
|
-
reject(
|
|
168
|
-
"RESULT_FAILED",
|
|
169
|
-
"Failed to get result for \(temporarySessionID): \(error.localizedDescription)",
|
|
170
|
-
nil
|
|
171
|
-
)
|
|
172
173
|
}
|
|
173
|
-
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// MARK: - Sync All Data
|
|
177
|
+
@objc
|
|
178
|
+
func syncAllData(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
179
|
+
InfivizShotsSDK.shared.syncAllData { result in
|
|
180
|
+
switch result {
|
|
181
|
+
case .success(let message):
|
|
182
|
+
resolve(message)
|
|
183
|
+
case .failure(let error):
|
|
184
|
+
reject("SYNC_FAILED", "Sync failed: \(error)", nil)
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// MARK: - Fetch Session Details
|
|
190
|
+
@objc
|
|
191
|
+
func fetchSessionDetails(_ temporarySessionID: NSString, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
192
|
+
InfivizShotsSDK.shared.fetchSessionDetails(temporarySessionID: temporarySessionID as String) { result in
|
|
193
|
+
switch result {
|
|
194
|
+
case .success(let value):
|
|
195
|
+
// Convert any value to a clean dictionary that handles Optionals properly
|
|
196
|
+
let cleanDict = self.convertToCleanDictionary(value)
|
|
197
|
+
// Return the dictionary directly instead of JSON string
|
|
198
|
+
resolve(cleanDict)
|
|
199
|
+
case .failure(let error):
|
|
200
|
+
reject("RESULT_FAILED", "Failed to get result: \(error)", nil)
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Helper method to convert any value to a clean dictionary that handles Optionals
|
|
206
|
+
// MARK: - Convert Any Value to Clean Dictionary
|
|
207
|
+
private func convertToCleanDictionary(_ value: Any) -> [String: Any] {
|
|
208
|
+
if let dict = value as? [String: Any] {
|
|
209
|
+
return cleanDictionary(dict)
|
|
210
|
+
} else if let dict = value as? [AnyHashable: Any] {
|
|
211
|
+
var result: [String: Any] = [:]
|
|
212
|
+
for (k, v) in dict {
|
|
213
|
+
result[String(describing: k)] = unwrapOptional(v)
|
|
214
|
+
}
|
|
215
|
+
return result
|
|
216
|
+
} else {
|
|
217
|
+
// Try to convert to dictionary using Mirror reflection
|
|
218
|
+
let mirror = Mirror(reflecting: value)
|
|
219
|
+
var result: [String: Any] = [:]
|
|
220
|
+
for child in mirror.children {
|
|
221
|
+
if let label = child.label {
|
|
222
|
+
result[label] = unwrapOptional(child.value)
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return result
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// MARK: - Recursively Clean Dictionary
|
|
230
|
+
private func cleanDictionary(_ dict: [String: Any]) -> [String: Any] {
|
|
231
|
+
var cleaned: [String: Any] = [:]
|
|
232
|
+
for (key, value) in dict {
|
|
233
|
+
cleaned[key] = unwrapOptional(value)
|
|
234
|
+
}
|
|
235
|
+
return cleaned
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// MARK: - Unwrap Optionals and Clean Nested Structures
|
|
239
|
+
private func unwrapOptional(_ value: Any) -> Any {
|
|
240
|
+
let mirror = Mirror(reflecting: value)
|
|
241
|
+
|
|
242
|
+
// 1. Handle Optional
|
|
243
|
+
let typeName = String(describing: type(of: value))
|
|
244
|
+
if typeName.hasPrefix("Optional<") {
|
|
245
|
+
if let unwrapped = mirror.children.first?.value {
|
|
246
|
+
return unwrapOptional(unwrapped)
|
|
247
|
+
} else {
|
|
248
|
+
return NSNull()
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// 2. Strings cleanup
|
|
253
|
+
if let str = value as? String {
|
|
254
|
+
return str.replacingOccurrences(of: "Optional\\(|\\)",
|
|
255
|
+
with: "",
|
|
256
|
+
options: .regularExpression)
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// 3. Arrays
|
|
260
|
+
if let array = value as? [Any] {
|
|
261
|
+
return array.map { unwrapOptional($0) }
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// 4. Dictionaries
|
|
265
|
+
if let dict = value as? [String: Any] {
|
|
266
|
+
// 👇 Detect special case: metadata dictionaries
|
|
267
|
+
if dict.keys.count == 1, let firstKey = dict.keys.first {
|
|
268
|
+
if ["string", "bool", "int", "double", "float"].contains(firstKey.lowercased()) {
|
|
269
|
+
return unwrapOptional(dict[firstKey]!)
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
return cleanDictionary(dict)
|
|
273
|
+
} else if let dict = value as? [AnyHashable: Any] {
|
|
274
|
+
var result: [String: Any] = [:]
|
|
275
|
+
for (k, v) in dict {
|
|
276
|
+
result[String(describing: k)] = unwrapOptional(v)
|
|
277
|
+
}
|
|
278
|
+
return result
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// 5. Dates
|
|
282
|
+
if let date = value as? Date {
|
|
283
|
+
let formatter = DateFormatter()
|
|
284
|
+
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
|
|
285
|
+
return formatter.string(from: date)
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// 6. Custom objects
|
|
289
|
+
let objectMirror = Mirror(reflecting: value)
|
|
290
|
+
if !objectMirror.children.isEmpty {
|
|
291
|
+
var result: [String: Any] = [:]
|
|
292
|
+
for child in objectMirror.children {
|
|
293
|
+
if let label = child.label {
|
|
294
|
+
result[label] = unwrapOptional(child.value)
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return result
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// 7. Primitives
|
|
301
|
+
return value
|
|
174
302
|
}
|
|
175
303
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
return result
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// Recursively clean a dictionary to handle Optionals
|
|
224
|
-
private func cleanDictionary(_ dict: [String: Any]) -> [String: Any] {
|
|
225
|
-
var cleaned: [String: Any] = [:]
|
|
226
|
-
|
|
227
|
-
for (key, value) in dict {
|
|
228
|
-
cleaned[key] = unwrapOptional(value)
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
return cleaned
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// Unwrap Optional values and clean nested structures
|
|
235
|
-
private func unwrapOptional(_ value: Any) -> Any {
|
|
236
|
-
let mirror = Mirror(reflecting: value)
|
|
237
|
-
|
|
238
|
-
// Check if it's an Optional by checking the type name
|
|
239
|
-
let typeName = String(describing: type(of: value))
|
|
240
|
-
if typeName.hasPrefix("Optional<") {
|
|
241
|
-
if let unwrapped = mirror.children.first?.value {
|
|
242
|
-
return unwrapOptional(unwrapped)
|
|
243
|
-
} else {
|
|
244
|
-
return NSNull() // nil value
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
// Handle arrays
|
|
249
|
-
if let array = value as? [Any] {
|
|
250
|
-
return array.map { unwrapOptional($0) }
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
// Handle dictionaries
|
|
254
|
-
if let dict = value as? [String: Any] {
|
|
255
|
-
return cleanDictionary(dict)
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
// Handle Date objects
|
|
259
|
-
if let date = value as? Date {
|
|
260
|
-
let formatter = DateFormatter()
|
|
261
|
-
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
|
|
262
|
-
return formatter.string(from: date)
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
// Handle custom objects (like ImageMetaData) using Mirror reflection
|
|
266
|
-
// This ensures that objects with optional properties are properly serialized
|
|
267
|
-
let objectMirror = Mirror(reflecting: value)
|
|
268
|
-
if !objectMirror.children.isEmpty {
|
|
269
|
-
var result: [String: Any] = [:]
|
|
270
|
-
for child in objectMirror.children {
|
|
271
|
-
if let label = child.label {
|
|
272
|
-
result[label] = unwrapOptional(child.value)
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
return result
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
// Return the value as-is if it's a basic type
|
|
279
|
-
return value
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
// MARK: - Logout
|
|
283
|
-
@objc
|
|
284
|
-
func logout(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
285
|
-
InfivizShotsSDK.shared.callLogoutAPI { result in
|
|
286
|
-
switch result {
|
|
287
|
-
case .success(let success):
|
|
288
|
-
resolve(success)
|
|
289
|
-
case .failure(let error):
|
|
290
|
-
reject("LOGOUT_FAILED", "Logout error: \(error)", nil)
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
// MARK: - Reprocessing Enable Time
|
|
296
|
-
@objc
|
|
297
|
-
func getReprocessingButtonEnableTime(_ sessionID: NSString, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
298
|
-
InfivizShotsSDK.shared.getReprocessingButtonEnableTime(sessionID: sessionID as String) { result in
|
|
299
|
-
switch result {
|
|
300
|
-
case .success(let time):
|
|
301
|
-
resolve(time)
|
|
302
|
-
case .failure(let error):
|
|
303
|
-
reject("REPROCESS_TIME_ERROR", "Error fetching reprocessing time: \(error)", nil)
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
// MARK: - Start Reprocessing Workflow
|
|
309
|
-
@objc
|
|
310
|
-
func startReprocessingWorkflow(_ sessionID: NSString, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
311
|
-
InfivizShotsSDK.shared.startReprocessingWorkflow(sessionID: sessionID as String) { result in
|
|
312
|
-
switch result {
|
|
313
|
-
case .success(let time):
|
|
314
|
-
resolve(time)
|
|
315
|
-
case .failure(let error):
|
|
316
|
-
reject("REPROCESS_WORKFLOW_ERROR", "Reprocessing workflow error: \(error)", nil)
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
// MARK: - Start Camera
|
|
304
|
+
|
|
305
|
+
// MARK: - Logout
|
|
306
|
+
@objc
|
|
307
|
+
func logout(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
308
|
+
InfivizShotsSDK.shared.callLogoutAPI { result in
|
|
309
|
+
switch result {
|
|
310
|
+
case .success(let success):
|
|
311
|
+
resolve(success)
|
|
312
|
+
case .failure(let error):
|
|
313
|
+
reject("LOGOUT_FAILED", "Logout error: \(error)", nil)
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// MARK: - Reprocessing Enable Time
|
|
319
|
+
@objc
|
|
320
|
+
func getReprocessingButtonEnableTime(_ sessionID: NSString, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
321
|
+
InfivizShotsSDK.shared.getReprocessingButtonEnableTime(sessionID: sessionID as String) { result in
|
|
322
|
+
switch result {
|
|
323
|
+
case .success(let time):
|
|
324
|
+
resolve(time)
|
|
325
|
+
case .failure(let error):
|
|
326
|
+
reject("REPROCESS_TIME_ERROR", "Error fetching reprocessing time: \(error)", nil)
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// MARK: - Start Reprocessing Workflow
|
|
332
|
+
@objc
|
|
333
|
+
func startReprocessingWorkflow(_ sessionID: NSString, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
334
|
+
InfivizShotsSDK.shared.startReprocessingWorkflow(sessionID: sessionID as String) { result in
|
|
335
|
+
switch result {
|
|
336
|
+
case .success(let time):
|
|
337
|
+
resolve(time)
|
|
338
|
+
case .failure(let error):
|
|
339
|
+
reject("REPROCESS_WORKFLOW_ERROR", "Reprocessing workflow error: \(error)", nil)
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// MARK: - Start Camera
|
|
322
345
|
@objc(startCamera:storeTitle:storeId:photoType:category:maxPhoto:maxPhotoOneGo:metaData:resolver:rejecter:)
|
|
323
346
|
func startCamera(_ taskName: NSString,
|
|
324
347
|
storeTitle: NSString,
|
|
@@ -330,229 +353,229 @@ class InfivizShotsReactSdk: RCTEventEmitter {
|
|
|
330
353
|
metaData: NSDictionary,
|
|
331
354
|
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
332
355
|
rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
356
|
+
|
|
357
|
+
DispatchQueue.main.async {
|
|
358
|
+
// 1️⃣ Build the CameraContext just like before
|
|
359
|
+
let metadataDict: [String: Any]? = metaData as? [String: Any]
|
|
360
|
+
let context = CameraContext(
|
|
361
|
+
taskName: taskName as String,
|
|
362
|
+
storeTitle: storeTitle as String,
|
|
363
|
+
storeId: storeId as String,
|
|
364
|
+
photoType: photoType as String,
|
|
365
|
+
category: category as String,
|
|
366
|
+
maxPhoto: maxPhoto.intValue,
|
|
367
|
+
maxPhotoOneGo: maxPhotoOneGo.intValue,
|
|
368
|
+
tempSessionId: nil,
|
|
369
|
+
imageURI: nil,
|
|
370
|
+
navigationController: nil,
|
|
371
|
+
retake: false,
|
|
372
|
+
metaData: metadataDict
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
// 2️⃣ Instantiate the SDK activity
|
|
376
|
+
let activity = InfilectSDKCameraActivityForResult(cameraContext: context)
|
|
377
|
+
|
|
378
|
+
// 3️⃣ Call its existing `start(completion:)` which will handle validation,
|
|
379
|
+
activity.start { result in
|
|
380
|
+
switch result {
|
|
381
|
+
case .success(let sessionID):
|
|
382
|
+
resolve(sessionID)
|
|
383
|
+
case .failure(let apiError):
|
|
384
|
+
reject("CAMERA_ERROR", apiError.localizedDescription, nil)
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
@objc
|
|
391
|
+
func initialize(_ appID: NSString,
|
|
392
|
+
authSecret: NSString,
|
|
393
|
+
accountKey: NSString,
|
|
394
|
+
userID: NSString,
|
|
395
|
+
clientID: NSString,
|
|
396
|
+
apiToken: NSString,
|
|
397
|
+
env: NSString,
|
|
398
|
+
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
399
|
+
rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
400
|
+
|
|
401
|
+
let model = InfivizUserLoginContext(
|
|
402
|
+
appID: appID as String,
|
|
403
|
+
authSecret: authSecret as String,
|
|
404
|
+
accountKey: accountKey as String,
|
|
405
|
+
userID: userID as String,
|
|
406
|
+
clientID: clientID as String,
|
|
407
|
+
apiToken: apiToken as String
|
|
350
408
|
)
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
}
|
|
409
|
+
|
|
410
|
+
let environment = APIEnvironment(rawValue: env as String) ?? .production
|
|
411
|
+
InfivizShotsSDK.shared.initializeEnvironent(environment)
|
|
412
|
+
activity = InfivizShotsActivity(model: model)
|
|
413
|
+
activity?.initialize { result in
|
|
414
|
+
switch result {
|
|
415
|
+
case .success(let success):
|
|
416
|
+
resolve(success)
|
|
417
|
+
case .failure(let error):
|
|
418
|
+
reject("LOGIN_FAILED", error.localizedDescription, nil)
|
|
419
|
+
}
|
|
363
420
|
}
|
|
364
|
-
}
|
|
365
421
|
}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
422
|
+
|
|
423
|
+
@objc
|
|
424
|
+
func fetchSessionID(_ taskCategory: NSString,
|
|
425
|
+
storeID: NSString,
|
|
426
|
+
taskPhotoType: NSString,
|
|
427
|
+
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
428
|
+
rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
429
|
+
|
|
430
|
+
InfivizShotsSDK.shared.fetchSessionID(
|
|
431
|
+
taskCategory: taskCategory as String,
|
|
432
|
+
storeID: storeID as String,
|
|
433
|
+
taskPhotoType: taskPhotoType as String
|
|
434
|
+
) { sessionID, error in
|
|
435
|
+
if let id = sessionID {
|
|
436
|
+
resolve(id)
|
|
437
|
+
} else {
|
|
438
|
+
reject("SESSION_NOT_FOUND", "Session not found", nil)
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// MARK: - View IR Results via bridge
|
|
444
|
+
@objc(viewIRResults:resolver:rejecter:)
|
|
445
|
+
func viewIRResults(_ sessionID: NSString,
|
|
375
446
|
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
reject("NAV_ERROR", "No navigation controller available", nil)
|
|
432
|
-
return
|
|
433
|
-
}
|
|
434
|
-
let realTimeView = InfivizRealTimeView(sessionID: sessionID as String,
|
|
435
|
-
navigationController: navigationController)
|
|
436
|
-
realTimeView.viewIRResults(sessionID: sessionID as String) { result in
|
|
437
|
-
switch result {
|
|
438
|
-
case .success(let value): resolve(value)
|
|
439
|
-
case .failure(let error): reject("VIEW_IR_FAILED", error.localizedDescription, nil)
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
// MARK: - Start Actions Workflow via bridge
|
|
446
|
-
@objc(startActionsWorkFlow:sessionId:latitude:longitude:dateTimeStamp:resolver:rejecter:)
|
|
447
|
-
func startActionsWorkFlow(_ storeId: NSString,
|
|
448
|
-
sessionId: NSString,
|
|
449
|
-
latitude: NSString,
|
|
450
|
-
longitude: NSString,
|
|
451
|
-
dateTimeStamp: NSString,
|
|
452
|
-
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
453
|
-
rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
454
|
-
DispatchQueue.main.async {
|
|
455
|
-
guard let navigationController = UIApplication.shared.connectedScenes
|
|
456
|
-
.compactMap({ $0 as? UIWindowScene })
|
|
457
|
-
.flatMap({ $0.windows })
|
|
458
|
-
.first(where: { $0.isKeyWindow })?
|
|
459
|
-
.rootViewController?.navigationController else {
|
|
460
|
-
reject("NAV_ERROR", "No navigation controller available", nil)
|
|
461
|
-
return
|
|
462
|
-
}
|
|
463
|
-
let realTimeView = InfivizRealTimeView(sessionID: sessionId as String,
|
|
464
|
-
navigationController: navigationController)
|
|
465
|
-
realTimeView.startActionsWorkFlow(storeId: storeId as String,
|
|
466
|
-
sessionId: sessionId as String,
|
|
467
|
-
latitude: latitude as String,
|
|
468
|
-
longitude: longitude as String,
|
|
469
|
-
dateTimeStamp: dateTimeStamp as String) { result in
|
|
470
|
-
switch result {
|
|
471
|
-
case .success(let value): resolve(value)
|
|
472
|
-
case .failure(let error): reject("ACTIONS_WORKFLOW_FAILED", error.localizedDescription, nil)
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
@objc(resumeCamera:metaData:resolver:rejecter:)
|
|
447
|
+
rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
448
|
+
DispatchQueue.main.async {
|
|
449
|
+
guard let navigationController = UIApplication.shared.connectedScenes
|
|
450
|
+
.compactMap({ $0 as? UIWindowScene })
|
|
451
|
+
.flatMap({ $0.windows })
|
|
452
|
+
.first(where: { $0.isKeyWindow })?
|
|
453
|
+
.rootViewController?.navigationController else {
|
|
454
|
+
reject("NAV_ERROR", "No navigation controller available", nil)
|
|
455
|
+
return
|
|
456
|
+
}
|
|
457
|
+
let realTimeView = InfivizRealTimeView(sessionID: sessionID as String,
|
|
458
|
+
navigationController: navigationController)
|
|
459
|
+
realTimeView.viewIRResults(sessionID: sessionID as String) { result in
|
|
460
|
+
switch result {
|
|
461
|
+
case .success(let value): resolve(value)
|
|
462
|
+
case .failure(let error): reject("VIEW_IR_FAILED", error.localizedDescription, nil)
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// MARK: - Start Actions Workflow via bridge
|
|
469
|
+
@objc(startActionsWorkFlow:sessionId:latitude:longitude:dateTimeStamp:resolver:rejecter:)
|
|
470
|
+
func startActionsWorkFlow(_ storeId: NSString,
|
|
471
|
+
sessionId: NSString,
|
|
472
|
+
latitude: NSString,
|
|
473
|
+
longitude: NSString,
|
|
474
|
+
dateTimeStamp: NSString,
|
|
475
|
+
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
476
|
+
rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
477
|
+
DispatchQueue.main.async {
|
|
478
|
+
guard let navigationController = UIApplication.shared.connectedScenes
|
|
479
|
+
.compactMap({ $0 as? UIWindowScene })
|
|
480
|
+
.flatMap({ $0.windows })
|
|
481
|
+
.first(where: { $0.isKeyWindow })?
|
|
482
|
+
.rootViewController?.navigationController else {
|
|
483
|
+
reject("NAV_ERROR", "No navigation controller available", nil)
|
|
484
|
+
return
|
|
485
|
+
}
|
|
486
|
+
let realTimeView = InfivizRealTimeView(sessionID: sessionId as String,
|
|
487
|
+
navigationController: navigationController)
|
|
488
|
+
realTimeView.startActionsWorkFlow(storeId: storeId as String,
|
|
489
|
+
sessionId: sessionId as String,
|
|
490
|
+
latitude: latitude as String,
|
|
491
|
+
longitude: longitude as String,
|
|
492
|
+
dateTimeStamp: dateTimeStamp as String) { result in
|
|
493
|
+
switch result {
|
|
494
|
+
case .success(let value): resolve(value)
|
|
495
|
+
case .failure(let error): reject("ACTIONS_WORKFLOW_FAILED", error.localizedDescription, nil)
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
@objc(resumeCamera:metaData:resolver:rejecter:)
|
|
479
502
|
func resumeCamera(
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
503
|
+
_ temporarySessionID: NSString,
|
|
504
|
+
metaData: NSDictionary?,
|
|
505
|
+
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
506
|
+
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
484
507
|
) {
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
508
|
+
// Build whatever CameraContext your SDK needs. In your original UI code,
|
|
509
|
+
// you were reading from text fields (e.g. shelfTextField.text, traderTextField.text, etc.).
|
|
510
|
+
// In a module method you typically won't have those outlets available, so you'll
|
|
511
|
+
// need to pass any required "taskName", "storeTitle" etc. from JS into this call
|
|
512
|
+
// or hard‐code defaults here. For now, I'll show a minimal example:
|
|
513
|
+
|
|
514
|
+
let context = CameraContext(
|
|
515
|
+
taskName: "", // ← pass in from JS if you really need it
|
|
516
|
+
storeTitle: "",
|
|
517
|
+
storeId: "",
|
|
518
|
+
photoType: "",
|
|
519
|
+
category: "",
|
|
520
|
+
maxPhoto: 0,
|
|
521
|
+
maxPhotoOneGo: 0,
|
|
522
|
+
navigationController: nil // ← no UIKit nav controller in RN module
|
|
523
|
+
)
|
|
524
|
+
|
|
525
|
+
// Instantiate your SDK's camera controller just like before:
|
|
526
|
+
let controller = InfilectSDKCameraActivityForResult(cameraContext: context)
|
|
527
|
+
|
|
528
|
+
// Convert NSDictionary to [String: Any]
|
|
529
|
+
let metadataDict: [String: Any]? = metaData as? [String: Any]
|
|
530
|
+
|
|
531
|
+
// Call the updated `resumeCamera(sessionID:metaData:completion:)` API with metadata
|
|
532
|
+
controller.resumeCamera(sessionID: temporarySessionID as String, metaData: metadataDict) { result in
|
|
533
|
+
switch result {
|
|
534
|
+
case .success(let successString):
|
|
535
|
+
// fulfill the JS promise with the returned string
|
|
536
|
+
resolve(successString)
|
|
537
|
+
|
|
538
|
+
case .failure(let sdkError):
|
|
539
|
+
// reject the JS promise
|
|
540
|
+
let nsError = sdkError as NSError
|
|
541
|
+
reject(
|
|
542
|
+
"ResumeCameraError",
|
|
543
|
+
"Failed to resume camera: \(nsError.localizedDescription)",
|
|
544
|
+
nsError
|
|
545
|
+
)
|
|
546
|
+
}
|
|
523
547
|
}
|
|
524
|
-
}
|
|
525
548
|
}
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
549
|
+
|
|
550
|
+
@objc
|
|
551
|
+
func deletePhoto(
|
|
552
|
+
_ imageURI: NSString,
|
|
553
|
+
temporarySessionId: NSString,
|
|
554
|
+
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
555
|
+
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
556
|
+
) {
|
|
557
|
+
let context = CameraContext(
|
|
558
|
+
taskName: "",
|
|
559
|
+
storeTitle: "",
|
|
560
|
+
storeId: "",
|
|
561
|
+
photoType: "",
|
|
562
|
+
|
|
563
|
+
category: "",
|
|
564
|
+
maxPhoto: 0,
|
|
565
|
+
maxPhotoOneGo: 0,
|
|
566
|
+
navigationController: nil
|
|
567
|
+
)
|
|
568
|
+
let controller = InfilectSDKCameraActivityForResult(cameraContext: context)
|
|
569
|
+
controller.deleteImage(imageID: imageURI as String, sessionID: temporarySessionId as String) { result in
|
|
570
|
+
switch result {
|
|
571
|
+
case .success(let successMessage):
|
|
572
|
+
resolve(successMessage)
|
|
573
|
+
case .failure(let error):
|
|
574
|
+
reject("DELETE_IMAGE_ERROR", "Failed to delete image: \(error.localizedDescription)", error)
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
|
|
556
579
|
@objc(retakeImage:imageURL:metaData:resolver:rejecter:)
|
|
557
580
|
func retakeImage(
|
|
558
581
|
_ temporarySessionId: NSString,
|
|
@@ -593,70 +616,70 @@ class InfivizShotsReactSdk: RCTEventEmitter {
|
|
|
593
616
|
}
|
|
594
617
|
}
|
|
595
618
|
}
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
/// Expose `getActionsResult(sessionID:completion:)` to JavaScript as:
|
|
628
|
-
/// InfiBridge.getActionsResult("session-123").then(...).catch(...)
|
|
629
|
-
@objc
|
|
630
|
-
func getActionsResult(
|
|
631
|
-
_ sessionId: NSString,
|
|
632
|
-
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
633
|
-
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
634
|
-
) {
|
|
635
|
-
// Call the Swift helper (which calls outputAPI.getActionsResult)
|
|
636
|
-
InfivizShotsSDK.shared.getActionsResult(sessionID: sessionId as String) { (dataAny, error) in
|
|
637
|
-
if let err = error {
|
|
638
|
-
reject("ACTIONS_FAILED", err as? String, nil)
|
|
639
|
-
} else if let output = dataAny {
|
|
640
|
-
resolve(output)
|
|
641
|
-
} else {
|
|
642
|
-
resolve(nil)
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
@objc
|
|
648
|
-
private func handleActionsGeneratedEvent(_ notification: Notification) {
|
|
649
|
-
guard hasListeners else { return }
|
|
650
|
-
|
|
651
|
-
let payload = notification.userInfo ?? [:]
|
|
652
|
-
sendEvent(withName: "ActionsGeneratedEvent", body: payload)
|
|
619
|
+
|
|
620
|
+
// MARK: – React Native Promise Exposures for OutputAPI
|
|
621
|
+
/// Expose `getIRResult(sessionID:completion:)` to JavaScript as:
|
|
622
|
+
/// InfiBridge.getIRResult("session-123").then(...).catch(...)
|
|
623
|
+
@objc
|
|
624
|
+
func getIrResult(
|
|
625
|
+
_ sessionId: NSString,
|
|
626
|
+
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
627
|
+
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
628
|
+
) {
|
|
629
|
+
print("Inside GetIrResult sessionId -> \(sessionId)")
|
|
630
|
+
// Call the Swift helper (which calls outputAPI.getIRResult)
|
|
631
|
+
InfivizShotsSDK.shared.getIrResult(sessionID: sessionId as String) { (dataAny, error) in
|
|
632
|
+
if let err = error {
|
|
633
|
+
// If the SDK returned an error, reject the JS promise
|
|
634
|
+
print("err", err)
|
|
635
|
+
reject(
|
|
636
|
+
"IR_RESULT_ERROR", // error code (custom identifier)
|
|
637
|
+
err as? String, // error message
|
|
638
|
+
nil // optional NSError (can be nil)
|
|
639
|
+
)
|
|
640
|
+
} else if let output = dataAny {
|
|
641
|
+
// If the SDK returned data (Any), pass it back to JS.
|
|
642
|
+
resolve(output)
|
|
643
|
+
} else {
|
|
644
|
+
// Neither data nor error? Just resolve with `nil`.
|
|
645
|
+
resolve(nil)
|
|
646
|
+
}
|
|
653
647
|
}
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/// Expose `getActionsResult(sessionID:completion:)` to JavaScript as:
|
|
651
|
+
/// InfiBridge.getActionsResult("session-123").then(...).catch(...)
|
|
652
|
+
@objc
|
|
653
|
+
func getActionsResult(
|
|
654
|
+
_ sessionId: NSString,
|
|
655
|
+
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
656
|
+
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
657
|
+
) {
|
|
658
|
+
// Call the Swift helper (which calls outputAPI.getActionsResult)
|
|
659
|
+
InfivizShotsSDK.shared.getActionsResult(sessionID: sessionId as String) { (dataAny, error) in
|
|
660
|
+
if let err = error {
|
|
661
|
+
reject("ACTIONS_FAILED", err as? String, nil)
|
|
662
|
+
} else if let output = dataAny {
|
|
663
|
+
resolve(output)
|
|
664
|
+
} else {
|
|
665
|
+
resolve(nil)
|
|
666
|
+
}
|
|
661
667
|
}
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
@objc
|
|
671
|
+
private func handleActionsGeneratedEvent(_ notification: Notification) {
|
|
672
|
+
guard hasListeners else { return }
|
|
673
|
+
|
|
674
|
+
let payload = notification.userInfo ?? [:]
|
|
675
|
+
sendEvent(withName: "ActionsGeneratedEvent", body: payload)
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
@objc
|
|
679
|
+
private func handleSessionRealTimeResultEvent(_ notification: Notification) {
|
|
680
|
+
guard hasListeners else { return }
|
|
681
|
+
|
|
682
|
+
let payload = notification.userInfo ?? [:]
|
|
683
|
+
sendEvent(withName: "SessionRealTimeResultEvent", body: payload)
|
|
684
|
+
}
|
|
662
685
|
}
|