react-native-mytatva-rn-sdk 1.2.36 → 1.2.38
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/MyReactNativeBridge.m +294 -0
- package/ios/TableViewCell/VIdeoTVC/VideoTVC.swift +31 -0
- package/ios/ViewControllers/ConnectToSensorViewController.swift +415 -0
- package/ios/ViewControllers/StartConnectionViewController.swift +219 -0
- package/ios/ViewModel/FinalViewModel.swift +648 -0
- package/package.json +1 -1
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
//
|
|
2
|
+
// ConnectToSensorViewController.swift
|
|
3
|
+
// MyTatvaCare
|
|
4
|
+
//
|
|
5
|
+
// Created by Nirav Ramani on 08/05/25.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import UIKit
|
|
9
|
+
import AVFoundation
|
|
10
|
+
class ConnectToSensorViewController: UIViewController {
|
|
11
|
+
@IBOutlet weak var contactSupport: CustomOverlayButton!
|
|
12
|
+
@IBOutlet weak var customTopView: CustomTopUIView!
|
|
13
|
+
@IBOutlet weak var tableView: UITableView!
|
|
14
|
+
@IBOutlet weak var bottomButton: CustomOverlayButton!
|
|
15
|
+
|
|
16
|
+
enum enumTableSection: Int, CaseIterable {
|
|
17
|
+
case details
|
|
18
|
+
case success
|
|
19
|
+
case error
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
enum enumTableRow: Int, CaseIterable {
|
|
23
|
+
case separator
|
|
24
|
+
case verticalLabel
|
|
25
|
+
case image
|
|
26
|
+
case camera
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
enum enumSuccessTableRow: Int, CaseIterable {
|
|
30
|
+
case success
|
|
31
|
+
case note
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
enum enumFailureTableRow: Int, CaseIterable {
|
|
35
|
+
case failAnimation
|
|
36
|
+
case details
|
|
37
|
+
case image
|
|
38
|
+
case watchVideo
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
enum enumScreenType {
|
|
42
|
+
case camera
|
|
43
|
+
case success
|
|
44
|
+
case error
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
var isFromReconnect: Bool = false
|
|
48
|
+
var connectedTime: Date?
|
|
49
|
+
var connected:(()->())?
|
|
50
|
+
var screenType: enumScreenType = .camera
|
|
51
|
+
var isCodeDetected = false
|
|
52
|
+
var isPermissionGiven: Bool = false
|
|
53
|
+
let manager = KLTBluetoothManager.shared()
|
|
54
|
+
|
|
55
|
+
override func viewDidLoad() {
|
|
56
|
+
super.viewDidLoad()
|
|
57
|
+
// Do any additional setup after loading the view.
|
|
58
|
+
setupLayout()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
func setupLayout() {
|
|
62
|
+
manager?.addObserver(self, forKeyPath: "status", options: [.new], context: nil)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
tableView.delegate = self
|
|
66
|
+
tableView.dataSource = self
|
|
67
|
+
tableView.registerNibs([VerticalLabelsTVC.self,
|
|
68
|
+
SeparatorTVC.self,
|
|
69
|
+
ImageTVC.self,
|
|
70
|
+
SearchDeviceTVC.self,
|
|
71
|
+
ConnectDeviceTVC.self,
|
|
72
|
+
ConnectSuccessTVC.self,
|
|
73
|
+
NoteTVC.self,
|
|
74
|
+
PodDetailsTVC.self,
|
|
75
|
+
WatchVideoTVC.self])
|
|
76
|
+
tableView.reloadData()
|
|
77
|
+
contactSupport.isHidden = screenType != .error
|
|
78
|
+
contactSupport.labelText = "Contact Support"
|
|
79
|
+
contactSupport.setBorderOnly()
|
|
80
|
+
contactSupport.buttonTapCallback = {
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
bottomButton.labelText = screenType == .error ? "Retry" : "Proceed"
|
|
84
|
+
|
|
85
|
+
if screenType == .error {
|
|
86
|
+
bottomButton.hideRightArrow()
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
bottomButton.buttonTapCallback = {
|
|
90
|
+
let isForReconnect = UserDefaults.standard.bool(forKey: "isForReconnect")
|
|
91
|
+
if isForReconnect {
|
|
92
|
+
let vc = AttachTransmitterViewController.instantiate(fromStoryboard: Enum_stroyboard.Main.rawValue)
|
|
93
|
+
self.navigationController?.pushViewController(vc, animated: false)
|
|
94
|
+
} else {
|
|
95
|
+
let vc = PutOnTheSensorViewController.instantiate(fromStoryboard: Enum_stroyboard.Main.rawValue)
|
|
96
|
+
self.navigationController?.pushViewController(vc, animated: false)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
customTopView.onDemoTapped = {
|
|
101
|
+
let webVC = WebViewController()
|
|
102
|
+
webVC.modalPresentationStyle = .formSheet
|
|
103
|
+
webVC.videoURL = URL(string: watchCGMVideo)
|
|
104
|
+
self.present(webVC, animated: true, completion: nil)
|
|
105
|
+
}
|
|
106
|
+
customTopView.onCloseTapped = {
|
|
107
|
+
let vc = ExitJourneyViewController.instantiate(fromStoryboard: Enum_stroyboard.Main.rawValue)
|
|
108
|
+
vc.modalPresentationStyle = .overFullScreen
|
|
109
|
+
self.present(vc, animated: true, completion: nil)
|
|
110
|
+
}
|
|
111
|
+
customTopView.onWhatsAppTapped = {
|
|
112
|
+
let vc = ChatWithExpertViewController.instantiate(fromStoryboard: Enum_stroyboard.Main.rawValue)
|
|
113
|
+
self.navigationController?.pushViewController(vc, animated: false)
|
|
114
|
+
}
|
|
115
|
+
checkCameraPermission()
|
|
116
|
+
bottomButton.disable()
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
func checkCameraPermission() {
|
|
120
|
+
let status = AVCaptureDevice.authorizationStatus(for: .video)
|
|
121
|
+
|
|
122
|
+
switch status {
|
|
123
|
+
case .authorized:
|
|
124
|
+
self.isPermissionGiven = true
|
|
125
|
+
print("Camera access is authorized")
|
|
126
|
+
case .notDetermined:
|
|
127
|
+
AVCaptureDevice.requestAccess(for: .video) { granted in
|
|
128
|
+
if granted {
|
|
129
|
+
self.isPermissionGiven = true
|
|
130
|
+
DispatchQueue.main.async {
|
|
131
|
+
self.tableView.reloadData()
|
|
132
|
+
}
|
|
133
|
+
print("Camera access granted")
|
|
134
|
+
} else {
|
|
135
|
+
print("Camera access denied")
|
|
136
|
+
self.showCameraAccessAlert()
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
case .denied, .restricted:
|
|
140
|
+
print("Camera access denied or restricted")
|
|
141
|
+
self.showCameraAccessAlert()
|
|
142
|
+
@unknown default:
|
|
143
|
+
self.showCameraAccessAlert()
|
|
144
|
+
print("Unknown camera authorization status")
|
|
145
|
+
}
|
|
146
|
+
DispatchQueue.main.async {
|
|
147
|
+
self.tableView.reloadData()
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
func showCameraAccessAlert() {
|
|
153
|
+
let alert = UIAlertController(
|
|
154
|
+
title: "Camera Access Needed",
|
|
155
|
+
message: "Please enable camera access in Settings to use this feature.",
|
|
156
|
+
preferredStyle: .alert
|
|
157
|
+
)
|
|
158
|
+
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
|
|
159
|
+
alert.addAction(UIAlertAction(title: "Open Settings", style: .default) { _ in
|
|
160
|
+
if let settingsURL = URL(string: UIApplication.openSettingsURLString) {
|
|
161
|
+
UIApplication.shared.open(settingsURL)
|
|
162
|
+
}
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
DispatchQueue.main.async {
|
|
166
|
+
self.present(alert, animated: true)
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
func connectSensor(value: String, controller: ConnectToSensorViewController) {
|
|
171
|
+
UserDefaults.standard.set(value, forKey: "sensorId")
|
|
172
|
+
var isMatch = false
|
|
173
|
+
|
|
174
|
+
var regex = #"^[A-Z0-9][0-9](0[1-9]|[1-9][0-9]|[A-Z][1-9A-Z])(00[1-9]|0[1-9][0-9]|[1-9][0-9][0-9]){2}[0-9]{4,5}[0-9A-Z]{3}$"#
|
|
175
|
+
var predicate = NSPredicate(format: "SELF MATCHES %@", regex)
|
|
176
|
+
|
|
177
|
+
if predicate.evaluate(with: value) {
|
|
178
|
+
isMatch = true
|
|
179
|
+
} else {
|
|
180
|
+
regex = #"^[A-Z1-9][1-9][A-Z0-9][0-9](0[1-9]|[1-9][0-9]|[A-Z][1-9A-Z])(00[1-9]|0[1-9][0-9]|[1-9][0-9][0-9]){2}[0-9]{6}[0-9A-Z]{3}$"#
|
|
181
|
+
predicate = NSPredicate(format: "SELF MATCHES %@", regex)
|
|
182
|
+
if predicate.evaluate(with: value) {
|
|
183
|
+
isMatch = true
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if isMatch {
|
|
188
|
+
let data = AlgorithmTools.decodeCT(value)
|
|
189
|
+
|
|
190
|
+
if data.k > 0 || data.r > 0 {
|
|
191
|
+
//KLTLocalSettingManager.shareInstance.deviceInfoSensor = value
|
|
192
|
+
UserDefaults.standard.set(data.k, forKey: "algo_k")
|
|
193
|
+
UserDefaults.standard.set(data.r, forKey: "algo_r")
|
|
194
|
+
UserDefaults.standard.synchronize()
|
|
195
|
+
//self.connected?()
|
|
196
|
+
//controller.navigationController?.popViewController(animated: true)
|
|
197
|
+
self.showConfirmInsulinUser()
|
|
198
|
+
//showConfirmInsulinUser()
|
|
199
|
+
return
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
//controller.resumeScanning()
|
|
204
|
+
}
|
|
205
|
+
func connectThisSensor() {
|
|
206
|
+
// Connect the transmitter
|
|
207
|
+
manager?.connectPeripheral(manager?.readyToConnectedPeripheral)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
func showConfirmInsulinUser() {
|
|
211
|
+
let typeOfDiabetes = UserDefaults.standard.object(forKey: "profilePatientType") as? NSNumber
|
|
212
|
+
|
|
213
|
+
if let diabetesType = typeOfDiabetes {
|
|
214
|
+
// LocalizedString(@"user_diabete_no") index is 0
|
|
215
|
+
if diabetesType.intValue == 0 {
|
|
216
|
+
// No
|
|
217
|
+
UserDefaults.standard.set(2, forKey: "algo_user_type")
|
|
218
|
+
} else {
|
|
219
|
+
// Yes
|
|
220
|
+
UserDefaults.standard.set(1, forKey: "algo_user_type")
|
|
221
|
+
}
|
|
222
|
+
} else {
|
|
223
|
+
// Not selected
|
|
224
|
+
UserDefaults.standard.set(0, forKey: "algo_user_type")
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
UserDefaults.standard.synchronize() // Optional, rarely needed in modern iOS
|
|
228
|
+
|
|
229
|
+
connectThisSensor()
|
|
230
|
+
}
|
|
231
|
+
override func observeValue(forKeyPath keyPath: String?,
|
|
232
|
+
of object: Any?,
|
|
233
|
+
change: [NSKeyValueChangeKey : Any]?,
|
|
234
|
+
context: UnsafeMutableRawPointer?) {
|
|
235
|
+
if keyPath == "status" && context == nil {
|
|
236
|
+
if let newValue = change?[.newKey] as? Int {
|
|
237
|
+
//let btStatus = newValue
|
|
238
|
+
let btStatus: BluetoothManagerStatus = BluetoothManagerStatus(rawValue: newValue) ?? .scanStart
|
|
239
|
+
|
|
240
|
+
if btStatus == .initialStart {
|
|
241
|
+
self.connectedTime = Date()
|
|
242
|
+
print("Success")
|
|
243
|
+
screenType = .success
|
|
244
|
+
tableView.reloadData()
|
|
245
|
+
bottomButton.enable()
|
|
246
|
+
if self.isFromReconnect {
|
|
247
|
+
let _ = FinalViewModelManager.shared
|
|
248
|
+
NotificationCenter.default.post(name: Notification.Name("cgmDeviceEvent"), object: nil, userInfo: ["a":"a"])
|
|
249
|
+
if let rootVC = UIApplication.shared.connectedScenes
|
|
250
|
+
.compactMap({ ($0 as? UIWindowScene)?.windows.first?.rootViewController })
|
|
251
|
+
.first {
|
|
252
|
+
rootVC.dismiss(animated: true, completion: nil)
|
|
253
|
+
} else if let rootViewController = UIApplication.shared.keyWindow?.rootViewController {
|
|
254
|
+
rootViewController.dismiss(animated: true, completion: nil)
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
} else if btStatus == .closed || btStatus == .modifyVoltageFailed {
|
|
258
|
+
// Handle failed or closed status
|
|
259
|
+
|
|
260
|
+
navigationController?.popToRootViewController(animated: true)
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
} else if keyPath == "status", context != nil {
|
|
264
|
+
if let playerItem = object as? AVPlayerItem {
|
|
265
|
+
if playerItem.status == .readyToPlay {
|
|
266
|
+
if UserDefaults.standard.integer(forKey: "bgmode") == 0 {
|
|
267
|
+
// player?.play()
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
} else {
|
|
272
|
+
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
extension ConnectToSensorViewController: UITableViewDelegate, UITableViewDataSource {
|
|
279
|
+
|
|
280
|
+
func numberOfSections(in tableView: UITableView) -> Int {
|
|
281
|
+
return enumTableSection.allCases.count
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
|
285
|
+
switch enumTableSection(rawValue: section)! {
|
|
286
|
+
case .details:
|
|
287
|
+
return (screenType == .camera) ? enumTableRow.allCases.count : 0
|
|
288
|
+
case .success:
|
|
289
|
+
return screenType == .success ? enumSuccessTableRow.allCases.count : 0
|
|
290
|
+
case .error:
|
|
291
|
+
return screenType == .error ? enumFailureTableRow.allCases.count : 0
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
|
|
296
|
+
switch enumTableSection(rawValue: indexPath.section)! {
|
|
297
|
+
case .details:
|
|
298
|
+
switch enumTableRow(rawValue: indexPath.row) {
|
|
299
|
+
case .image:
|
|
300
|
+
return (UIScreen.main.bounds.width * 120 / 390) + 40
|
|
301
|
+
case .camera:
|
|
302
|
+
return 220
|
|
303
|
+
default:
|
|
304
|
+
return UITableView.automaticDimension
|
|
305
|
+
}
|
|
306
|
+
case .error:
|
|
307
|
+
switch enumFailureTableRow(rawValue: indexPath.row) {
|
|
308
|
+
case .failAnimation:
|
|
309
|
+
return 120
|
|
310
|
+
case .image:
|
|
311
|
+
return (UIScreen.main.bounds.width * 120 / 390) + 20
|
|
312
|
+
default:
|
|
313
|
+
return UITableView.automaticDimension
|
|
314
|
+
}
|
|
315
|
+
default:
|
|
316
|
+
return UITableView.automaticDimension
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
|
321
|
+
switch enumTableSection(rawValue: indexPath.section)! {
|
|
322
|
+
case .details:
|
|
323
|
+
switch enumTableRow(rawValue: indexPath.row)! {
|
|
324
|
+
case .separator:
|
|
325
|
+
let cell: SeparatorTVC = tableView.dequeueReusableCell(for: indexPath)
|
|
326
|
+
return cell
|
|
327
|
+
case .verticalLabel:
|
|
328
|
+
let cell: VerticalLabelsTVC = tableView.dequeueReusableCell(for: indexPath)
|
|
329
|
+
cell.label1.text = "STEP 3"
|
|
330
|
+
cell.label2.text = "Connect to your Sensor"
|
|
331
|
+
cell.label3.text = "Scan the QR on the back of the sensor to connect with the GoodFlip app"
|
|
332
|
+
return cell
|
|
333
|
+
case .image:
|
|
334
|
+
let cell: ImageTVC = tableView.dequeueReusableCell(for: indexPath)
|
|
335
|
+
cell.displayImageView.image = loadImage(named: "flip_the_reference")
|
|
336
|
+
cell.displayImageView.contentMode = .scaleAspectFill
|
|
337
|
+
cell.displayImageView.isHidden = false
|
|
338
|
+
cell.cameraView.isHidden = true
|
|
339
|
+
return cell
|
|
340
|
+
case .camera:
|
|
341
|
+
let cell: ImageTVC = tableView.dequeueReusableCell(for: indexPath)
|
|
342
|
+
cell.displayImageView.contentMode = .scaleAspectFill
|
|
343
|
+
cell.displayImageView.isHidden = true
|
|
344
|
+
cell.cameraView.isHidden = false
|
|
345
|
+
if isPermissionGiven {
|
|
346
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
|
|
347
|
+
cell.setupQRView()
|
|
348
|
+
cell.scannerView?.onCodeDetected = { data in
|
|
349
|
+
if !self.isCodeDetected {
|
|
350
|
+
self.isCodeDetected = true
|
|
351
|
+
self.connectSensor(value: data, controller: self)
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
return cell
|
|
357
|
+
}
|
|
358
|
+
case .success:
|
|
359
|
+
switch enumSuccessTableRow(rawValue: indexPath.row)! {
|
|
360
|
+
case .success:
|
|
361
|
+
let cell: ConnectSuccessTVC = tableView.dequeueReusableCell(for: indexPath)
|
|
362
|
+
let dateFormatter = DateFormatter()
|
|
363
|
+
dateFormatter.dateFormat = "dd-MM-yyyy hh:mm a"
|
|
364
|
+
dateFormatter.timeZone = TimeZone.current
|
|
365
|
+
if let connectedTime = connectedTime {
|
|
366
|
+
// Convert the Date to a String
|
|
367
|
+
let dateString = dateFormatter.string(from: connectedTime)
|
|
368
|
+
cell.labelDate.text = "Connected on \(String(describing: dateString))"
|
|
369
|
+
} else {
|
|
370
|
+
cell.labelDate.text = ""
|
|
371
|
+
}
|
|
372
|
+
cell.labelDesc.isHidden = true
|
|
373
|
+
cell.labelTitle.text = "Sensor Connected Successfully"
|
|
374
|
+
cell.setImageForCGM()
|
|
375
|
+
return cell
|
|
376
|
+
|
|
377
|
+
case .note:
|
|
378
|
+
let cell: NoteTVC = tableView.dequeueReusableCell(for: indexPath)
|
|
379
|
+
cell.setImportantNote(isFromSuccessConnection: true)
|
|
380
|
+
return cell
|
|
381
|
+
}
|
|
382
|
+
case .error:
|
|
383
|
+
switch enumFailureTableRow(rawValue: indexPath.row)! {
|
|
384
|
+
case .failAnimation:
|
|
385
|
+
let cell: ImageTVC = tableView.dequeueReusableCell(for: indexPath)
|
|
386
|
+
cell.displayImageView.loadGif(named: "failure")
|
|
387
|
+
cell.bottomConstraint.constant = 11
|
|
388
|
+
return cell
|
|
389
|
+
case .details:
|
|
390
|
+
let cell: VerticalLabelsTVC = tableView.dequeueReusableCell(for: indexPath)
|
|
391
|
+
cell.topConstraint.constant = 0
|
|
392
|
+
cell.label1.isHidden = true
|
|
393
|
+
cell.label2.text = "Unable to detect sensor"
|
|
394
|
+
cell.label3.text = "Make sure there is proper lighting in the room"
|
|
395
|
+
return cell
|
|
396
|
+
case .image:
|
|
397
|
+
let cell: ImageTVC = tableView.dequeueReusableCell(for: indexPath)
|
|
398
|
+
cell.topConstraint.constant = 0
|
|
399
|
+
cell.displayImageView.image = loadImage(named: "flip_the_reference")
|
|
400
|
+
cell.displayImageView.contentMode = .scaleAspectFill
|
|
401
|
+
return cell
|
|
402
|
+
case .watchVideo:
|
|
403
|
+
let cell: WatchVideoTVC = tableView.dequeueReusableCell(for: indexPath)
|
|
404
|
+
cell.onPlayVideo = {
|
|
405
|
+
let webVC = WebViewController()
|
|
406
|
+
webVC.modalPresentationStyle = .formSheet
|
|
407
|
+
webVC.videoURL = URL(string: qrScanFailed)
|
|
408
|
+
self.present(webVC, animated: true, completion: nil)
|
|
409
|
+
}
|
|
410
|
+
return cell
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
//
|
|
2
|
+
// ViewController.swift
|
|
3
|
+
// MyTatvaCare
|
|
4
|
+
//
|
|
5
|
+
// Created by Nirav Ramani on 05/05/25.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import UIKit
|
|
9
|
+
import WebKit
|
|
10
|
+
import CoreBluetooth
|
|
11
|
+
import CoreLocation
|
|
12
|
+
|
|
13
|
+
class StartConnectionViewController: UIViewController {
|
|
14
|
+
|
|
15
|
+
@IBOutlet weak var customTopView: CustomTopUIView!
|
|
16
|
+
@IBOutlet weak var tableView: UITableView!
|
|
17
|
+
@IBOutlet weak var startConnectionJourneyButton: CustomOverlayButton!
|
|
18
|
+
@objc var isForReconnect: Bool = false
|
|
19
|
+
var webView: WKWebView!
|
|
20
|
+
// Declare the CBCentralManager
|
|
21
|
+
var centralManager: CBCentralManager?
|
|
22
|
+
var isBluetoothEnabled: Bool = false
|
|
23
|
+
|
|
24
|
+
// Declare the CLLocationManager
|
|
25
|
+
var locationManager: CLLocationManager?
|
|
26
|
+
var isLocationEnabled: Bool = false
|
|
27
|
+
|
|
28
|
+
enum enumTableRow: Int, CaseIterable {
|
|
29
|
+
case separator
|
|
30
|
+
case verticalLabel
|
|
31
|
+
case image
|
|
32
|
+
case chargingIndicator
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
override func viewDidLoad() {
|
|
36
|
+
super.viewDidLoad()
|
|
37
|
+
// Do any additional setup after loading the view.
|
|
38
|
+
setupLayout()
|
|
39
|
+
//checkForDevice()
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
func setupLayout() {
|
|
43
|
+
navigationController?.navigationBar.isHidden = true
|
|
44
|
+
tableView.delegate = self
|
|
45
|
+
tableView.dataSource = self
|
|
46
|
+
tableView.registerNibs([VerticalLabelsTVC.self,
|
|
47
|
+
SeparatorTVC.self,
|
|
48
|
+
ImageTVC.self,
|
|
49
|
+
ChargingIndicatorTVC.self])
|
|
50
|
+
tableView.reloadData()
|
|
51
|
+
|
|
52
|
+
UserDefaults.standard.set(isForReconnect, forKey: "isForReconnect")
|
|
53
|
+
let isForReconnect = UserDefaults.standard.bool(forKey: "isForReconnect")
|
|
54
|
+
|
|
55
|
+
if isForReconnect {
|
|
56
|
+
startConnectionJourneyButton.labelText = "Start Reconnection Journey"
|
|
57
|
+
} else {
|
|
58
|
+
startConnectionJourneyButton.labelText = "Start Connection Journey"
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
checkLocationPermission()
|
|
62
|
+
centralManager = CBCentralManager(delegate: self, queue: nil)
|
|
63
|
+
checkBluetoothPermission()
|
|
64
|
+
|
|
65
|
+
startConnectionJourneyButton.buttonTapCallback = {
|
|
66
|
+
let isForReconnect = UserDefaults.standard.bool(forKey: "isForReconnect")
|
|
67
|
+
if isForReconnect {
|
|
68
|
+
self.updateBottomButtonState()
|
|
69
|
+
} else {
|
|
70
|
+
let vc = ProvidePermissionViewController.instantiate(fromStoryboard: Enum_stroyboard.Main.rawValue)
|
|
71
|
+
self.navigationController?.pushViewController(vc, animated: false)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
customTopView.onDemoTapped = {
|
|
76
|
+
let webVC = WebViewController()
|
|
77
|
+
webVC.modalPresentationStyle = .formSheet // or .pageSheet, .fullScreen
|
|
78
|
+
webVC.videoURL = URL(string: watchCGMVideo)
|
|
79
|
+
self.present(webVC, animated: true, completion: nil)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
customTopView.onCloseTapped = {
|
|
83
|
+
let vc = ExitJourneyViewController.instantiate(fromStoryboard: Enum_stroyboard.Main.rawValue)
|
|
84
|
+
vc.modalPresentationStyle = .overFullScreen
|
|
85
|
+
self.present(vc, animated: true, completion: nil)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
customTopView.onWhatsAppTapped = {
|
|
89
|
+
let vc = ChatWithExpertViewController.instantiate(fromStoryboard: Enum_stroyboard.Main.rawValue)
|
|
90
|
+
self.navigationController?.pushViewController(vc, animated: false)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
func checkForDevice() {
|
|
95
|
+
let manager = KLTBluetoothManager.shared()
|
|
96
|
+
let currentDevice = manager?.currentDevice
|
|
97
|
+
|
|
98
|
+
if (currentDevice != nil) {
|
|
99
|
+
let eDevice : EDevice = EDevice.getEnumDevice(currentDevice?.advertise?.localName ?? "")
|
|
100
|
+
let viewModel = FinalViewModel()
|
|
101
|
+
viewModel.initialPeriod = Int(eDevice.initNumber * 3 * 60)
|
|
102
|
+
|
|
103
|
+
let vc = AttachTransmitterViewController.instantiate(fromStoryboard: Enum_stroyboard.Main.rawValue)
|
|
104
|
+
vc.viewModel = viewModel
|
|
105
|
+
self.navigationController?.pushViewController(vc, animated: false)
|
|
106
|
+
} else {
|
|
107
|
+
// 未连接任何发射器
|
|
108
|
+
// stay on this screen
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private func updateBottomButtonState() {
|
|
113
|
+
if isBluetoothEnabled && isLocationEnabled {
|
|
114
|
+
let vc = ConnectToTransmitterViewController.instantiate(fromStoryboard: Enum_stroyboard.Main.rawValue)
|
|
115
|
+
self.navigationController?.pushViewController(vc, animated: false)
|
|
116
|
+
} else {
|
|
117
|
+
let vc = ProvidePermissionViewController.instantiate(fromStoryboard: Enum_stroyboard.Main.rawValue)
|
|
118
|
+
self.navigationController?.pushViewController(vc, animated: false)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Function to check Location Permission and State
|
|
123
|
+
private func checkLocationPermission() {
|
|
124
|
+
// Check if location services are enabled
|
|
125
|
+
|
|
126
|
+
let status = CLLocationManager.authorizationStatus()
|
|
127
|
+
|
|
128
|
+
switch status {
|
|
129
|
+
case .notDetermined:
|
|
130
|
+
print("Location permission is not determined.")
|
|
131
|
+
// Request permission to use location services
|
|
132
|
+
locationManager?.requestWhenInUseAuthorization()
|
|
133
|
+
case .restricted, .denied:
|
|
134
|
+
print("Location permission is restricted or denied.")
|
|
135
|
+
case .authorizedWhenInUse, .authorizedAlways:
|
|
136
|
+
print("Location is authorized.")
|
|
137
|
+
isLocationEnabled = true
|
|
138
|
+
|
|
139
|
+
@unknown default:
|
|
140
|
+
print("Unknown location status.")
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Function to check Bluetooth Permission and State
|
|
145
|
+
private func checkBluetoothPermission() {
|
|
146
|
+
isBluetoothEnabled = false
|
|
147
|
+
switch centralManager?.state {
|
|
148
|
+
case .unknown:
|
|
149
|
+
print("Bluetooth state is unknown.")
|
|
150
|
+
case .resetting:
|
|
151
|
+
print("Bluetooth state is resetting.")
|
|
152
|
+
case .unsupported:
|
|
153
|
+
print("Bluetooth is unsupported on this device.")
|
|
154
|
+
case .unauthorized:
|
|
155
|
+
print("Bluetooth is unauthorized.")
|
|
156
|
+
case .poweredOff:
|
|
157
|
+
print("Bluetooth is powered off.")
|
|
158
|
+
case .poweredOn:
|
|
159
|
+
print("Bluetooth is powered on and available.")
|
|
160
|
+
isBluetoothEnabled = true
|
|
161
|
+
case .none:
|
|
162
|
+
print("Unknown Bluetooth state.")
|
|
163
|
+
@unknown default:
|
|
164
|
+
print("Unknown Bluetooth state.")
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
extension StartConnectionViewController: UITableViewDelegate, UITableViewDataSource {
|
|
170
|
+
|
|
171
|
+
func numberOfSections(in tableView: UITableView) -> Int {
|
|
172
|
+
return 1
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
|
176
|
+
return enumTableRow.allCases.count
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
|
|
180
|
+
switch enumTableRow(rawValue: indexPath.row) {
|
|
181
|
+
case .image:
|
|
182
|
+
return 205
|
|
183
|
+
default:
|
|
184
|
+
return UITableView.automaticDimension
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
|
189
|
+
switch enumTableRow(rawValue: indexPath.row)! {
|
|
190
|
+
case .separator:
|
|
191
|
+
let cell: SeparatorTVC = tableView.dequeueReusableCell(for: indexPath)
|
|
192
|
+
return cell
|
|
193
|
+
case .verticalLabel:
|
|
194
|
+
let cell: VerticalLabelsTVC = tableView.dequeueReusableCell(for: indexPath)
|
|
195
|
+
cell.label1.text = "STEP1"
|
|
196
|
+
cell.label1.isHidden = true
|
|
197
|
+
cell.label2.text = "Before You Start"
|
|
198
|
+
cell.label3.text = "Make sure your transmitter is fully charged. Put it in the charging pod until the blinking white light turns blue. This takes about 15 minutes"
|
|
199
|
+
return cell
|
|
200
|
+
case .image:
|
|
201
|
+
let cell: ImageTVC = tableView.dequeueReusableCell(for: indexPath)
|
|
202
|
+
cell.displayImageView.image = loadImage(named: "charging_pod")
|
|
203
|
+
return cell
|
|
204
|
+
case .chargingIndicator:
|
|
205
|
+
let cell: ChargingIndicatorTVC = tableView.dequeueReusableCell(for: indexPath)
|
|
206
|
+
return cell
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
extension StartConnectionViewController: CBCentralManagerDelegate {
|
|
213
|
+
|
|
214
|
+
// Delegate method called when Bluetooth state changes
|
|
215
|
+
func centralManagerDidUpdateState(_ central: CBCentralManager) {
|
|
216
|
+
checkBluetoothPermission()
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|