react-native-mytatva-rn-sdk 1.2.45 → 1.2.48
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/android/src/main/java/com/mytatvarnsdk/CgmTrackyLibModule.kt +150 -55
- package/android/src/main/java/com/mytatvarnsdk/activity/SearchTransmitterActivity.kt +1 -1
- package/android/src/main/java/com/mytatvarnsdk/activity/VideoActivity.kt +12 -6
- package/android/src/main/java/com/mytatvarnsdk/model/BaseViewModel.java +1 -1
- package/android/src/main/res/layout/activity_video.xml +13 -2
- package/ios/MyReactNativeBridge.m +60 -55
- package/ios/Support/API.swift +1 -1
- package/ios/ViewControllers/AttachTransmitterViewController.swift +1 -0
- package/ios/ViewControllers/ChatWithExpertViewController.swift +4 -0
- package/ios/ViewControllers/ConnectToSensorViewController.swift +1 -0
- package/ios/ViewControllers/ConnectToTransmitterViewController.swift +19 -6
- package/ios/ViewControllers/ProvidePermissionViewController.swift +3 -0
- package/ios/ViewControllers/PutOnTheSensorViewController.swift +1 -0
- package/ios/ViewControllers/StartConnectionViewController.swift +4 -2
- package/ios/ViewModel/FinalViewModel.swift +15 -22
- package/package.json +1 -1
|
@@ -2,6 +2,8 @@ package com.mytatvarnsdk
|
|
|
2
2
|
|
|
3
3
|
import android.app.Application
|
|
4
4
|
import android.bluetooth.BluetoothAdapter
|
|
5
|
+
import android.bluetooth.BluetoothManager
|
|
6
|
+
import android.content.Context
|
|
5
7
|
import android.content.Intent
|
|
6
8
|
import android.content.pm.PackageManager
|
|
7
9
|
import android.os.Build
|
|
@@ -52,10 +54,13 @@ import kotlinx.coroutines.Job
|
|
|
52
54
|
import kotlinx.coroutines.SupervisorJob
|
|
53
55
|
import kotlinx.coroutines.delay
|
|
54
56
|
import kotlinx.coroutines.launch
|
|
57
|
+
import kotlinx.coroutines.withContext
|
|
55
58
|
import org.json.JSONObject
|
|
56
59
|
import java.text.SimpleDateFormat
|
|
57
60
|
import java.util.Date
|
|
58
61
|
import java.util.Locale
|
|
62
|
+
import java.util.Timer
|
|
63
|
+
import java.util.TimerTask
|
|
59
64
|
import kotlin.coroutines.resume
|
|
60
65
|
import kotlin.coroutines.suspendCoroutine
|
|
61
66
|
|
|
@@ -69,12 +74,15 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
69
74
|
var prefsHelper: SharedPreferencesLibraryUtil
|
|
70
75
|
private val apiScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
|
71
76
|
private var debounceJob: Job? = null
|
|
77
|
+
private var isBatchProcessing = false
|
|
72
78
|
|
|
73
79
|
private var lastDeviceStatus: String? = null
|
|
74
80
|
|
|
75
81
|
private var glucoseObserver: Observer<PocGlucose?>? = null
|
|
76
82
|
private var isObserving = false
|
|
77
83
|
|
|
84
|
+
private var lastProcessedSyncTimeInMillis: Long? = null
|
|
85
|
+
|
|
78
86
|
init {
|
|
79
87
|
mReactContext = reactContext
|
|
80
88
|
prefsHelper = SharedPreferencesLibraryUtil(mReactContext)
|
|
@@ -107,8 +115,7 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
107
115
|
Handler(Looper.getMainLooper()).post {
|
|
108
116
|
mModel.device.observeForever { device ->
|
|
109
117
|
if (device != null) {
|
|
110
|
-
postEventDataToAPI(device, "", device
|
|
111
|
-
|
|
118
|
+
postEventDataToAPI(device, "", device.qrMessage ?: "")
|
|
112
119
|
Log.d("observeDeviceStatus: ", device.toString())
|
|
113
120
|
}
|
|
114
121
|
}
|
|
@@ -119,7 +126,7 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
119
126
|
}
|
|
120
127
|
|
|
121
128
|
@ReactMethod
|
|
122
|
-
fun observeTransmitterUnbindStatus(token: String, apiResponse: String) {
|
|
129
|
+
fun observeTransmitterUnbindStatus(token: String, apiResponse: String?) {
|
|
123
130
|
try {
|
|
124
131
|
if (apiResponse != null && apiResponse.isNotEmpty()) {
|
|
125
132
|
userToken = token
|
|
@@ -189,19 +196,13 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
189
196
|
val endDate = sensor.endDate
|
|
190
197
|
val sensorId = sensor.sensorId
|
|
191
198
|
|
|
192
|
-
println("Start Date: $startDate")
|
|
193
|
-
println("End Date: $endDate")
|
|
194
|
-
|
|
195
199
|
if (isCurrentDateInRange(startDate, endDate)) {
|
|
196
|
-
|
|
197
200
|
println("Current date is in range")
|
|
198
201
|
|
|
199
202
|
val pocDevice =
|
|
200
203
|
RepositoryDevice.getInstance(BApplication.getContext()).latestDeviceIoThread
|
|
201
204
|
|
|
202
205
|
if (pocDevice != null) {
|
|
203
|
-
Log.d("pocDevice logsss", pocDevice.toString())
|
|
204
|
-
|
|
205
206
|
if (pocDevice.isUnBind) {
|
|
206
207
|
postEventDataToAPI(
|
|
207
208
|
pocDevice,
|
|
@@ -210,8 +211,6 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
210
211
|
)
|
|
211
212
|
}
|
|
212
213
|
} else {
|
|
213
|
-
Log.d("pocDevice logsss", "Data null")
|
|
214
|
-
|
|
215
214
|
postEventDataToAPI(
|
|
216
215
|
pocDevice,
|
|
217
216
|
DeviceStatus.TRANSMITTER_DISCONNECT.id,
|
|
@@ -231,65 +230,100 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
231
230
|
}
|
|
232
231
|
}
|
|
233
232
|
|
|
233
|
+
private var debounceDeviceTimer: Timer? = null
|
|
234
|
+
private var isDebounceTimerActive: Boolean = false
|
|
235
|
+
|
|
236
|
+
|
|
234
237
|
private fun postEventDataToAPI(device: PocDevice?, mStatus: String, sensorId: String?) {
|
|
235
|
-
|
|
238
|
+
debounceJob?.cancel()
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
debounceJob = apiScope.launch {
|
|
242
|
+
delay(500)
|
|
243
|
+
|
|
236
244
|
try {
|
|
237
245
|
val bluetoothAdapter: BluetoothAdapter? = BluetoothAdapter.getDefaultAdapter()
|
|
238
246
|
val bleStatus = bluetoothAdapter?.isEnabled == true
|
|
239
|
-
var status = ""
|
|
240
247
|
|
|
241
|
-
status =
|
|
248
|
+
val status: String = mStatus.ifEmpty {
|
|
242
249
|
when {
|
|
243
250
|
device?.isBoundAndConnect == true -> DeviceStatus.CONNECTED.id
|
|
244
251
|
!bleStatus -> DeviceStatus.BLUETOOTH_OFF.id
|
|
245
252
|
device?.isUnBind == true -> DeviceStatus.TRANSMITTER_DISCONNECT.id
|
|
246
253
|
device?.isBoundButDisConnect == true -> DeviceStatus.DISCONNECTED.id
|
|
247
|
-
else -> ""
|
|
254
|
+
else -> ""
|
|
248
255
|
}
|
|
249
|
-
} else {
|
|
250
|
-
mStatus
|
|
251
256
|
}
|
|
252
257
|
|
|
253
|
-
Log.d("
|
|
258
|
+
Log.d("Device event Status", "Device event Status: $status")
|
|
254
259
|
|
|
255
|
-
if (status.
|
|
256
|
-
|
|
260
|
+
if (status == DeviceStatus.DISCONNECTED.id && !isDebounceTimerActive) {
|
|
261
|
+
// Start debounce timer for 1 minutes
|
|
262
|
+
debounceDeviceTimer = Timer()
|
|
263
|
+
isDebounceTimerActive = true
|
|
257
264
|
|
|
258
|
-
|
|
259
|
-
|
|
265
|
+
debounceDeviceTimer?.schedule(object : TimerTask() {
|
|
266
|
+
override fun run() {
|
|
267
|
+
isDebounceTimerActive = false
|
|
260
268
|
|
|
261
|
-
|
|
262
|
-
put("transmitterName", device?.name ?: "")
|
|
263
|
-
put("SensorId", sensorId ?: "")
|
|
264
|
-
put("Sensor", sensorId ?: "")
|
|
265
|
-
put("timeInMillis", Date().time)
|
|
269
|
+
callEventAPI(device, status, sensorId)
|
|
266
270
|
}
|
|
267
271
|
|
|
268
|
-
|
|
269
|
-
put("sensorId", sensorId ?: "")
|
|
270
|
-
put("status", status)
|
|
271
|
-
put("rawData", rawData)
|
|
272
|
-
}
|
|
272
|
+
}, 1 * 60 * 1000) // 1 minutes in milliseconds
|
|
273
273
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
override fun onHideLoader() {}
|
|
281
|
-
}
|
|
282
|
-
)
|
|
274
|
+
Log.d("Debounce", "Timer started for disconnection reminder")
|
|
275
|
+
} else {
|
|
276
|
+
// Either device is not disconnected or timer already running
|
|
277
|
+
debounceDeviceTimer?.cancel()
|
|
278
|
+
debounceDeviceTimer = null
|
|
279
|
+
isDebounceTimerActive = false
|
|
283
280
|
|
|
284
|
-
|
|
285
|
-
|
|
281
|
+
Log.d("Debounce", "Timer cancelled, event triggered immediately")
|
|
282
|
+
|
|
283
|
+
callEventAPI(device, status, sensorId)
|
|
286
284
|
}
|
|
285
|
+
|
|
287
286
|
} catch (e: Exception) {
|
|
288
287
|
e.printStackTrace()
|
|
289
288
|
}
|
|
290
289
|
}
|
|
291
290
|
}
|
|
292
291
|
|
|
292
|
+
private fun callEventAPI(device: PocDevice?, status: String, sensorId: String?) {
|
|
293
|
+
Log.d("Device event Status", "Last Device event Status API: $lastDeviceStatus")
|
|
294
|
+
|
|
295
|
+
if (status.isNotEmpty() && status != lastDeviceStatus) {
|
|
296
|
+
lastDeviceStatus = status
|
|
297
|
+
|
|
298
|
+
Log.d("Device event Status", "Device event Status API: $status")
|
|
299
|
+
|
|
300
|
+
val rawData = JSONObject().apply {
|
|
301
|
+
put("transmitterName", device?.name ?: "")
|
|
302
|
+
put("SensorId", sensorId ?: "")
|
|
303
|
+
put("Sensor", sensorId ?: "")
|
|
304
|
+
put("timeInMillis", Date().time)
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
val obj = JSONObject().apply {
|
|
308
|
+
put("sensorId", sensorId ?: "")
|
|
309
|
+
put("status", status)
|
|
310
|
+
put("rawData", rawData)
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
authenticateSDKService.postDeviceData(
|
|
314
|
+
environment = if ("uat".uppercase() == "PROD") TATVA_ENVIRONMENT.PROD else TATVA_ENVIRONMENT.STAGE,
|
|
315
|
+
data = obj.toString(),
|
|
316
|
+
token = userToken,
|
|
317
|
+
loaderListener = object : LoaderListener {
|
|
318
|
+
override fun onShowLoader() {}
|
|
319
|
+
override fun onHideLoader() {}
|
|
320
|
+
}
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
resetDebounceTimer()
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
293
327
|
private fun resetDebounceTimer() {
|
|
294
328
|
debounceJob?.cancel() // Cancel any existing timer
|
|
295
329
|
debounceJob = apiScope.launch {
|
|
@@ -360,6 +394,10 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
360
394
|
)
|
|
361
395
|
return
|
|
362
396
|
}
|
|
397
|
+
if (isBatchProcessing) {
|
|
398
|
+
Log.d("observeAllGlucoseData", "Batch processing in progress, skipping duplicate call")
|
|
399
|
+
return
|
|
400
|
+
}
|
|
363
401
|
|
|
364
402
|
// Remove existing observer if any to prevent memory leaks
|
|
365
403
|
stopObservingGlucoseData()
|
|
@@ -368,13 +406,42 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
368
406
|
Handler(Looper.getMainLooper()).postDelayed({
|
|
369
407
|
// Create new observer with explicit nullable parameter type
|
|
370
408
|
glucoseObserver = Observer<PocGlucose?> { pocGlucose ->
|
|
371
|
-
|
|
409
|
+
val currentTime = System.currentTimeMillis()
|
|
410
|
+
var dataAge = System.currentTimeMillis()
|
|
411
|
+
|
|
412
|
+
val lastSyncData = prefsHelper.lastSyncData
|
|
413
|
+
val currentSyncTimeInMillis = lastSyncData?.timeInMillis
|
|
414
|
+
|
|
415
|
+
if (lastSyncData != null) {
|
|
416
|
+
dataAge = currentTime - lastSyncData.timeInMillis
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// Only proceed if timeInMillis is different from last processed
|
|
420
|
+
if (currentSyncTimeInMillis != null && lastProcessedSyncTimeInMillis != null && currentSyncTimeInMillis == lastProcessedSyncTimeInMillis) {
|
|
421
|
+
Log.d("SyncTimeCheck", "Duplicate sync time, skipping function calls")
|
|
422
|
+
return@Observer
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
if ((pocGlucose != null && lastSyncData == null) || (pocGlucose != null && lastSyncData != null && dataAge <= 4 * 60 * 1000L)) {
|
|
372
427
|
handleGlucoseData(pocGlucose)
|
|
428
|
+
Log.d(
|
|
429
|
+
"observeGlucoseData",
|
|
430
|
+
"Received glucose data - processing"
|
|
431
|
+
)
|
|
432
|
+
// Update last processed sync time
|
|
433
|
+
lastProcessedSyncTimeInMillis = currentSyncTimeInMillis
|
|
373
434
|
} else {
|
|
374
|
-
|
|
435
|
+
|
|
436
|
+
Handler(Looper.getMainLooper()).postDelayed({
|
|
437
|
+
observeAllGlucoseData(userToken)
|
|
438
|
+
}, 100)
|
|
439
|
+
Log.d(
|
|
375
440
|
"observeGlucoseData",
|
|
376
441
|
"Received null glucose data - skipping processing"
|
|
377
442
|
)
|
|
443
|
+
// Update last processed sync time
|
|
444
|
+
lastProcessedSyncTimeInMillis = currentSyncTimeInMillis
|
|
378
445
|
}
|
|
379
446
|
}
|
|
380
447
|
|
|
@@ -503,6 +570,11 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
503
570
|
|
|
504
571
|
@ReactMethod
|
|
505
572
|
fun observeAllGlucoseData(token: String) {
|
|
573
|
+
Log.d("function call", "observeAllGlucoseData")
|
|
574
|
+
if (isBatchProcessing) {
|
|
575
|
+
Log.d("observeAllGlucoseData", "Batch processing in progress, skipping duplicate call")
|
|
576
|
+
return
|
|
577
|
+
}
|
|
506
578
|
userToken = token
|
|
507
579
|
|
|
508
580
|
// FIX: Ensure proper cleanup and reset state
|
|
@@ -513,10 +585,24 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
513
585
|
try {
|
|
514
586
|
val lastSyncData = prefsHelper.lastSyncData
|
|
515
587
|
Log.d("lastSyncData: ", Gson().toJson(lastSyncData).toString())
|
|
588
|
+
val currentTime = System.currentTimeMillis()
|
|
589
|
+
var dataAge = System.currentTimeMillis()
|
|
516
590
|
|
|
517
|
-
if (lastSyncData != null) {
|
|
591
|
+
if (prefsHelper.lastSyncData != null) {
|
|
592
|
+
dataAge = currentTime - prefsHelper.lastSyncData.timeInMillis
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
if (lastSyncData != null && dataAge > 3 * 60 * 1000L) {
|
|
596
|
+
isBatchProcessing = true
|
|
518
597
|
CoroutineScope(Dispatchers.IO).launch {
|
|
519
|
-
|
|
598
|
+
|
|
599
|
+
val glucoseData = mModel.getGlucoseBetweenTime(lastSyncData.timeInMillis)
|
|
600
|
+
|
|
601
|
+
|
|
602
|
+
Log.d("observeAllGlucoseData: ", glucoseData.toString())
|
|
603
|
+
Log.d("Last sync time: ", lastSyncData.lastSyncTime.toString())
|
|
604
|
+
Log.d("current time: ", System.currentTimeMillis().toString())
|
|
605
|
+
|
|
520
606
|
if (glucoseData != null && glucoseData.isNotEmpty()) {
|
|
521
607
|
processBatchDataAndStartObserver(glucoseData)
|
|
522
608
|
} else {
|
|
@@ -524,16 +610,18 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
524
610
|
"observeAllGlucoseData",
|
|
525
611
|
"No historical data found, starting live observation"
|
|
526
612
|
)
|
|
527
|
-
|
|
613
|
+
|
|
614
|
+
withContext(Dispatchers.Main) {
|
|
528
615
|
observeGlucoseData(userToken)
|
|
529
616
|
}
|
|
530
617
|
}
|
|
531
618
|
}
|
|
532
619
|
} else {
|
|
620
|
+
isBatchProcessing = false
|
|
533
621
|
observeGlucoseData(userToken)
|
|
534
622
|
}
|
|
535
623
|
} catch (e: Exception) {
|
|
536
|
-
|
|
624
|
+
isBatchProcessing = false
|
|
537
625
|
observeGlucoseData(userToken)
|
|
538
626
|
}
|
|
539
627
|
}, 100) // Small delay to ensure cleanup
|
|
@@ -556,7 +644,8 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
556
644
|
}
|
|
557
645
|
|
|
558
646
|
// Ensure we're on main thread and not already observing
|
|
559
|
-
|
|
647
|
+
isBatchProcessing = false
|
|
648
|
+
withContext(Dispatchers.Main) {
|
|
560
649
|
if (!isObserving) {
|
|
561
650
|
Log.d(
|
|
562
651
|
"processBatchDataAndStartObserver",
|
|
@@ -574,7 +663,8 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
574
663
|
} catch (e: Exception) {
|
|
575
664
|
Log.e("processBatchDataAndStartObserver", "Error in batch processing: ${e.message}")
|
|
576
665
|
// Start live observation even on error
|
|
577
|
-
|
|
666
|
+
isBatchProcessing = false
|
|
667
|
+
withContext(Dispatchers.Main) {
|
|
578
668
|
if (!isObserving) {
|
|
579
669
|
observeGlucoseData(userToken)
|
|
580
670
|
}
|
|
@@ -603,6 +693,9 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
603
693
|
// Clear any cached data if needed
|
|
604
694
|
prefsHelper.clearQRInformation() // if you have such method
|
|
605
695
|
|
|
696
|
+
// Reset last processed sync time
|
|
697
|
+
lastProcessedSyncTimeInMillis = null
|
|
698
|
+
|
|
606
699
|
} catch (e: Exception) {
|
|
607
700
|
Log.e("resetCgmState", "Error resetting CGM state: ${e.message}")
|
|
608
701
|
}
|
|
@@ -744,6 +837,9 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
744
837
|
// Reset last device status
|
|
745
838
|
lastDeviceStatus = null
|
|
746
839
|
|
|
840
|
+
// Reset last processed sync time
|
|
841
|
+
lastProcessedSyncTimeInMillis = null
|
|
842
|
+
|
|
747
843
|
} catch (e: Exception) {
|
|
748
844
|
Log.e("stopObservingGlucoseData", "Error stopping observer: ${e.message}")
|
|
749
845
|
}
|
|
@@ -778,12 +874,13 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
778
874
|
lastRecord?.let {
|
|
779
875
|
try {
|
|
780
876
|
val syncData = SyncMeta(
|
|
781
|
-
|
|
877
|
+
System.currentTimeMillis(),
|
|
782
878
|
it.timeInMillis,
|
|
783
879
|
it.deviceId,
|
|
784
880
|
it.glucoseId
|
|
785
881
|
)
|
|
786
882
|
prefsHelper.lastSyncData = syncData
|
|
883
|
+
lastProcessedSyncTimeInMillis = null
|
|
787
884
|
Log.d(
|
|
788
885
|
"Sync Metadata",
|
|
789
886
|
"Sync metadata updated: glucoseId=${it.glucoseId}, time=${it.timeInMillis}"
|
|
@@ -875,6 +972,4 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
875
972
|
}
|
|
876
973
|
}
|
|
877
974
|
|
|
878
|
-
|
|
879
|
-
}
|
|
880
|
-
|
|
975
|
+
}
|
|
@@ -272,8 +272,8 @@ class SearchTransmitterActivity : BaseBleActivity() {
|
|
|
272
272
|
binding.tvTransName.text = "Sno: ${transmitterDeviceInfo!!.pocDevice.name}"
|
|
273
273
|
val formatter = SimpleDateFormat("hh:mm a", Locale.getDefault())
|
|
274
274
|
binding.tvDateTime.text = "Connected on ${formatter.format(Date()).uppercase()}"
|
|
275
|
-
binding.clSuccess.visibility = View.VISIBLE
|
|
276
275
|
binding.clMain.visibility = View.GONE
|
|
276
|
+
binding.clSuccess.visibility = View.VISIBLE
|
|
277
277
|
binding.commonButton.btnProceed.isEnabled = true
|
|
278
278
|
binding.commonButton.btnProceed.alpha = 1.0f
|
|
279
279
|
binding.view2.background = ContextCompat.getDrawable(this, R.drawable.bg_green_progress)
|
|
@@ -46,6 +46,9 @@ class VideoActivity : AppCompatActivity() {
|
|
|
46
46
|
.build()
|
|
47
47
|
binding.youtubePlayerView.enableAutomaticInitialization = false
|
|
48
48
|
|
|
49
|
+
binding.ivClose.setOnClickListener {
|
|
50
|
+
handleBackPressedManually()
|
|
51
|
+
}
|
|
49
52
|
|
|
50
53
|
binding.youtubePlayerView.addFullscreenListener(object : FullscreenListener {
|
|
51
54
|
override fun onEnterFullscreen(fullscreenView: View, exitFullscreen: () -> Unit) {
|
|
@@ -83,12 +86,15 @@ class VideoActivity : AppCompatActivity() {
|
|
|
83
86
|
|
|
84
87
|
private val onBackPressedCallback = object : OnBackPressedCallback(true) {
|
|
85
88
|
override fun handleOnBackPressed() {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
handleBackPressedManually()
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
private fun handleBackPressedManually() {
|
|
94
|
+
if (isFullscreen) {
|
|
95
|
+
youTubePlayer.toggleFullscreen()
|
|
96
|
+
} else {
|
|
97
|
+
finish()
|
|
92
98
|
}
|
|
93
99
|
}
|
|
94
100
|
}
|
|
@@ -99,7 +99,7 @@ public class BaseViewModel extends AndroidViewModel {
|
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
public List<PocGlucose> getGlucoseBetweenTime(long startTime) {
|
|
102
|
-
return mRepositoryGlucose.getGlucoseByTimeMillis(startTime,
|
|
102
|
+
return mRepositoryGlucose.getGlucoseByTimeMillis(startTime, System.currentTimeMillis());
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
public PocDevice getDeviceInfo(int deviceId) {
|
|
@@ -8,6 +8,15 @@
|
|
|
8
8
|
android:background="#E6000000"
|
|
9
9
|
tools:context=".activity.VideoActivity">
|
|
10
10
|
|
|
11
|
+
<androidx.appcompat.widget.AppCompatImageView
|
|
12
|
+
android:id="@+id/ivClose"
|
|
13
|
+
android:layout_width="40dp"
|
|
14
|
+
android:layout_height="40dp"
|
|
15
|
+
android:padding="7dp"
|
|
16
|
+
app:layout_constraintStart_toStartOf="parent"
|
|
17
|
+
app:layout_constraintTop_toTopOf="parent"
|
|
18
|
+
app:srcCompat="@drawable/ic_close_gray" />
|
|
19
|
+
|
|
11
20
|
<com.pierfrancescosoffritti.androidyoutubeplayer.core.player.views.YouTubePlayerView
|
|
12
21
|
android:id="@+id/youtube_player_view"
|
|
13
22
|
android:layout_width="match_parent"
|
|
@@ -23,10 +32,12 @@
|
|
|
23
32
|
android:id="@+id/full_screen_view_container"
|
|
24
33
|
android:layout_width="match_parent"
|
|
25
34
|
android:layout_height="match_parent"
|
|
26
|
-
android:visibility="
|
|
35
|
+
android:visibility="visible"
|
|
27
36
|
app:layout_constraintBottom_toBottomOf="parent"
|
|
28
37
|
app:layout_constraintEnd_toEndOf="parent"
|
|
29
38
|
app:layout_constraintStart_toStartOf="parent"
|
|
30
|
-
app:layout_constraintTop_toTopOf="parent"
|
|
39
|
+
app:layout_constraintTop_toTopOf="parent">
|
|
40
|
+
|
|
41
|
+
</FrameLayout>
|
|
31
42
|
|
|
32
43
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@@ -20,7 +20,7 @@ RCT_EXPORT_MODULE();
|
|
|
20
20
|
|
|
21
21
|
// Define the supported events
|
|
22
22
|
- (NSArray<NSString *> *)supportedEvents {
|
|
23
|
-
return @[@"cgmDeviceEvent"]; // Event names to listen to in JS
|
|
23
|
+
return @[@"cgmDeviceEvent", @"cgmwatchdemoclicked", @"cgmWAsupportclicked"]; // Event names to listen to in JS
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
// Example method to emit an event from native to JS
|
|
@@ -39,7 +39,7 @@ RCT_EXPORT_MODULE();
|
|
|
39
39
|
// This method returns the list of events the module supports
|
|
40
40
|
- (NSArray<NSString *> *)supportedEvents
|
|
41
41
|
{
|
|
42
|
-
return @[@"cgmDeviceEvent"];
|
|
42
|
+
return @[@"cgmDeviceEvent", @"cgmwatchdemoclicked", @"cgmWAsupportclicked"];
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
// Start listening for notifications
|
|
@@ -51,6 +51,17 @@ RCT_EXPORT_MODULE();
|
|
|
51
51
|
selector:@selector(handleNotification:)
|
|
52
52
|
name:@"cgmDeviceEvent"
|
|
53
53
|
object:nil];
|
|
54
|
+
|
|
55
|
+
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
56
|
+
selector:@selector(handleNotification:)
|
|
57
|
+
name:@"cgmwatchdemoclicked"
|
|
58
|
+
object:nil];
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
62
|
+
selector:@selector(handleNotification:)
|
|
63
|
+
name:@"cgmWAsupportclicked"
|
|
64
|
+
object:nil];
|
|
54
65
|
}
|
|
55
66
|
return self;
|
|
56
67
|
}
|
|
@@ -64,6 +75,9 @@ RCT_EXPORT_MODULE();
|
|
|
64
75
|
|
|
65
76
|
// Send the data to React Native via event emitter
|
|
66
77
|
[self sendEventWithName:@"cgmDeviceEvent" body:@{@"status": @"WARM_PERIOD_STARTED"}];
|
|
78
|
+
[self sendEventWithName:@"cgmwatchdemoclicked" body:@{@"status": @"cgm_watch_demo_clicked"}];
|
|
79
|
+
[self sendEventWithName:@"cgmWAsupportclicked" body:@{@"status": @"cgm_WA_support_clicked"}];
|
|
80
|
+
|
|
67
81
|
}
|
|
68
82
|
|
|
69
83
|
// Private helper
|
|
@@ -259,68 +273,59 @@ RCT_EXPORT_METHOD(observeAllGlucoseData:(NSString *)token)
|
|
|
259
273
|
});
|
|
260
274
|
}
|
|
261
275
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
276
|
+
//--------------OLD FUNCTION-----------------
|
|
277
|
+
//RCT_EXPORT_METHOD(observeTransmitterUnbindStatus:(NSString *)token)
|
|
278
|
+
//{
|
|
279
|
+
// NSLog(@"Received token: %@", token);
|
|
280
|
+
// [[NSUserDefaults standardUserDefaults] setObject:token forKey:@"authToken"];
|
|
281
|
+
// [[NSUserDefaults standardUserDefaults] synchronize];
|
|
282
|
+
// FinalViewModelManager *manager = [FinalViewModelManager shared];
|
|
283
|
+
// [manager callForObserveTransmitterUnbindStatus];
|
|
284
|
+
//}
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
RCT_EXPORT_METHOD(observeTransmitterUnbindStatus:(NSString *)token
|
|
289
|
+
response:(NSString *)responseJsonString
|
|
290
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
291
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
|
266
292
|
{
|
|
293
|
+
if (responseJsonString == nil || ![responseJsonString isKindOfClass:[NSString class]]) {
|
|
294
|
+
NSError *error = [NSError errorWithDomain:@"CgmTrackyLib"
|
|
295
|
+
code:1001
|
|
296
|
+
userInfo:@{NSLocalizedDescriptionKey: @"Invalid or nil JSON string passed from JS"}];
|
|
297
|
+
reject(@"invalid_params", @"Response JSON string is nil or invalid", error);
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Parse JSON string to NSDictionary
|
|
302
|
+
NSData *data = [responseJsonString dataUsingEncoding:NSUTF8StringEncoding];
|
|
303
|
+
NSError *parseError = nil;
|
|
304
|
+
NSDictionary *responseDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
|
|
305
|
+
|
|
306
|
+
if (parseError || ![responseDict isKindOfClass:[NSDictionary class]]) {
|
|
307
|
+
reject(@"json_parse_error", @"Failed to parse JSON string to dictionary", parseError);
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
|
|
267
311
|
// Save token
|
|
268
312
|
[[NSUserDefaults standardUserDefaults] setObject:token forKey:@"authToken"];
|
|
269
|
-
[[NSUserDefaults standardUserDefaults] synchronize];
|
|
270
313
|
|
|
271
|
-
// Save
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
[[NSUserDefaults standardUserDefaults] setObject:jsonData forKey:@"CGMStatusItem"];
|
|
275
|
-
[[NSUserDefaults standardUserDefaults] synchronize];
|
|
276
|
-
}
|
|
314
|
+
// Save response data
|
|
315
|
+
[[NSUserDefaults standardUserDefaults] setObject:data forKey:@"CGMStatusItem"];
|
|
316
|
+
[[NSUserDefaults standardUserDefaults] synchronize];
|
|
277
317
|
|
|
278
|
-
// Call
|
|
318
|
+
// Call manager logic
|
|
279
319
|
FinalViewModelManager *manager = [FinalViewModelManager shared];
|
|
280
320
|
[manager callForObserveTransmitterUnbindStatusWithCompletion:^(NSDictionary *response, NSError *error) {
|
|
281
|
-
if (
|
|
282
|
-
|
|
321
|
+
if (error) {
|
|
322
|
+
reject([NSString stringWithFormat:@"%ld", (long)error.code], error.localizedDescription, error);
|
|
323
|
+
} else {
|
|
324
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
325
|
+
resolve(response ?: @{});
|
|
326
|
+
});
|
|
283
327
|
}
|
|
284
328
|
}];
|
|
285
329
|
}
|
|
286
330
|
|
|
287
|
-
//RCT_EXPORT_METHOD(observeTransmitterUnbindStatus:(NSString *)token response:(NSString *)responseJsonString)
|
|
288
|
-
//{
|
|
289
|
-
// // Optional: Parse the JSON string if needed
|
|
290
|
-
// NSData *jsonData = [responseJsonString dataUsingEncoding:NSUTF8StringEncoding];
|
|
291
|
-
// NSError *jsonError;
|
|
292
|
-
// NSDictionary *responseDict = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&jsonError];
|
|
293
|
-
//
|
|
294
|
-
// if (jsonError) {
|
|
295
|
-
// NSLog(@"Failed to parse JSON: %@", jsonError.localizedDescription);
|
|
296
|
-
// [self sendEventWithName:@"observeTransmitterUnbindStatusHandler" body:@{
|
|
297
|
-
// @"token": token ?: @"",
|
|
298
|
-
// @"success": @NO,
|
|
299
|
-
// @"error": @"Invalid JSON response from JS"
|
|
300
|
-
// }];
|
|
301
|
-
// return;
|
|
302
|
-
// }
|
|
303
|
-
//
|
|
304
|
-
// // Now you have responseDict, you can use it
|
|
305
|
-
// [self observeTransmitterUnbindStatusInternal:token response:responseDict completion:^(NSDictionary *response, NSError *error) {
|
|
306
|
-
// if (error) {
|
|
307
|
-
// NSDictionary *errorPayload = @{
|
|
308
|
-
// @"token": token ?: @"",
|
|
309
|
-
// @"success": @NO,
|
|
310
|
-
// @"error": error.localizedDescription ?: @"Unknown error"
|
|
311
|
-
// };
|
|
312
|
-
// [self sendEventWithName:@"observeTransmitterUnbindStatusHandler" body:errorPayload];
|
|
313
|
-
// } else {
|
|
314
|
-
// NSDictionary *successPayload = @{
|
|
315
|
-
// @"token": token ?: @"",
|
|
316
|
-
// @"responseFromBackend": response ?: @{},
|
|
317
|
-
// @"responseFromJS": responseDict ?: @{},
|
|
318
|
-
// @"success": @YES
|
|
319
|
-
// };
|
|
320
|
-
// [self sendEventWithName:@"observeTransmitterUnbindStatusHandler" body:successPayload];
|
|
321
|
-
// }
|
|
322
|
-
// }];
|
|
323
|
-
//
|
|
324
|
-
//}
|
|
325
|
-
|
|
326
331
|
@end
|
package/ios/Support/API.swift
CHANGED
|
@@ -72,6 +72,7 @@ class AttachTransmitterViewController: UIViewController {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
customTopView.onDemoTapped = {
|
|
75
|
+
NotificationCenter.default.post(name: Notification.Name("cgmwatchdemoclicked"), object: nil, userInfo: ["a":"a"])
|
|
75
76
|
let webVC = WebViewController()
|
|
76
77
|
webVC.modalPresentationStyle = .formSheet
|
|
77
78
|
webVC.videoURL = URL(string: watchCGMVideo)
|
|
@@ -27,6 +27,7 @@ class ChatWithExpertViewController: UIViewController {
|
|
|
27
27
|
super.viewDidLoad()
|
|
28
28
|
// Do any additional setup after loading the view.
|
|
29
29
|
setupLayout()
|
|
30
|
+
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
func setupLayout() {
|
|
@@ -43,6 +44,9 @@ class ChatWithExpertViewController: UIViewController {
|
|
|
43
44
|
buttonBack.titleLabel?.font = FontManager.font(ofSize: 16, weight: .medium)
|
|
44
45
|
bottomButton.labelText = "Proceed"
|
|
45
46
|
bottomButton.showLeftWhatsappImage()
|
|
47
|
+
|
|
48
|
+
NotificationCenter.default.post(name: Notification.Name("cgmWAsupportclicked"), object: nil, userInfo: ["a":"a"])
|
|
49
|
+
|
|
46
50
|
bottomButton.buttonTapCallback = {
|
|
47
51
|
|
|
48
52
|
if let url = URL(string: "https://wa.aisensy.com/aaa1qv") {
|
|
@@ -99,6 +99,7 @@ class ConnectToSensorViewController: UIViewController {
|
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
customTopView.onDemoTapped = {
|
|
102
|
+
NotificationCenter.default.post(name: Notification.Name("cgmwatchdemoclicked"), object: nil, userInfo: ["a":"a"])
|
|
102
103
|
let webVC = WebViewController()
|
|
103
104
|
webVC.modalPresentationStyle = .formSheet
|
|
104
105
|
webVC.videoURL = URL(string: watchCGMVideo)
|
|
@@ -96,12 +96,21 @@ class ConnectToTransmitterViewController: UIViewController, KLTBluetoothDelegate
|
|
|
96
96
|
}
|
|
97
97
|
bottomButton.buttonTapCallback = {
|
|
98
98
|
if self.isForReconnect {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
99
|
+
if self.bottomButton.labelText == "Retry" {
|
|
100
|
+
self.manager?.bluetoothDelegate = self
|
|
101
|
+
self.manager?.startScan()
|
|
102
|
+
self.screenType = .searching
|
|
103
|
+
self.tableView.reloadData()
|
|
104
|
+
self.bottomButton.hideRightArrow()
|
|
105
|
+
} else {
|
|
106
|
+
let vc = ConnectToSensorViewController.instantiate(fromStoryboard: Enum_stroyboard.Main.rawValue)
|
|
107
|
+
vc.connected = {
|
|
108
|
+
//self.showConfirmInsulinUser()
|
|
109
|
+
}
|
|
110
|
+
vc.isFromReconnect = true
|
|
111
|
+
self.navigationController?.pushViewController(vc, animated: false)
|
|
102
112
|
}
|
|
103
|
-
|
|
104
|
-
self.navigationController?.pushViewController(vc, animated: false)
|
|
113
|
+
|
|
105
114
|
// NotificationCenter.default.post(name: Notification.Name("cgmDeviceEvent"), object: nil, userInfo: ["a":"a"])
|
|
106
115
|
// if let rootVC = UIApplication.shared.connectedScenes
|
|
107
116
|
// .compactMap({ ($0 as? UIWindowScene)?.windows.first?.rootViewController })
|
|
@@ -112,6 +121,8 @@ class ConnectToTransmitterViewController: UIViewController, KLTBluetoothDelegate
|
|
|
112
121
|
// }
|
|
113
122
|
} else {
|
|
114
123
|
if self.screenType == .error {
|
|
124
|
+
self.manager?.bluetoothDelegate = self
|
|
125
|
+
self.manager?.startScan()
|
|
115
126
|
self.bottomButton.disable()
|
|
116
127
|
self.screenType = .searching
|
|
117
128
|
self.tableView.reloadData()
|
|
@@ -126,6 +137,7 @@ class ConnectToTransmitterViewController: UIViewController, KLTBluetoothDelegate
|
|
|
126
137
|
}
|
|
127
138
|
|
|
128
139
|
customTopView.onDemoTapped = {
|
|
140
|
+
NotificationCenter.default.post(name: Notification.Name("cgmwatchdemoclicked"), object: nil, userInfo: ["a":"a"])
|
|
129
141
|
let webVC = WebViewController()
|
|
130
142
|
webVC.modalPresentationStyle = .formSheet
|
|
131
143
|
webVC.videoURL = URL(string: watchCGMVideo)
|
|
@@ -297,6 +309,7 @@ extension ConnectToTransmitterViewController: UITableViewDelegate, UITableViewDa
|
|
|
297
309
|
|
|
298
310
|
//cell.labelDesc.text = "Sno:\(devices[indexPath.row].name)"
|
|
299
311
|
cell.button.buttonTapCallback = {
|
|
312
|
+
|
|
300
313
|
if self.isForReconnect {
|
|
301
314
|
self.sensorForceEnd()
|
|
302
315
|
}
|
|
@@ -304,7 +317,7 @@ extension ConnectToTransmitterViewController: UITableViewDelegate, UITableViewDa
|
|
|
304
317
|
if !KLTLocalSettingManager.shareInstance().canConnectOtherDevice {
|
|
305
318
|
return
|
|
306
319
|
}
|
|
307
|
-
|
|
320
|
+
|
|
308
321
|
self.manager?.stopScan()
|
|
309
322
|
if self.foundDevices.count > indexPath.row {
|
|
310
323
|
let peripheral = self.foundDevices[indexPath.row] as! CBPeripheral
|
|
@@ -45,11 +45,14 @@ class ProvidePermissionViewController: UIViewController {
|
|
|
45
45
|
|
|
46
46
|
bottomButton.labelText = "Proceed"
|
|
47
47
|
bottomButton.buttonTapCallback = {
|
|
48
|
+
let isForReconnect = UserDefaults.standard.bool(forKey: "isForReconnect")
|
|
48
49
|
let vc = ConnectToTransmitterViewController.instantiate(fromStoryboard: Enum_stroyboard.Main.rawValue)
|
|
50
|
+
vc.isForReconnect = isForReconnect
|
|
49
51
|
self.navigationController?.pushViewController(vc, animated: false)
|
|
50
52
|
}
|
|
51
53
|
|
|
52
54
|
customTopView.onDemoTapped = {
|
|
55
|
+
NotificationCenter.default.post(name: Notification.Name("cgmwatchdemoclicked"), object: nil, userInfo: ["a":"a"])
|
|
53
56
|
let webVC = WebViewController()
|
|
54
57
|
webVC.modalPresentationStyle = .formSheet
|
|
55
58
|
webVC.videoURL = URL(string: watchCGMVideo)
|
|
@@ -42,6 +42,7 @@ class PutOnTheSensorViewController: UIViewController {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
customTopView.onDemoTapped = {
|
|
45
|
+
NotificationCenter.default.post(name: Notification.Name("cgmwatchdemoclicked"), object: nil, userInfo: ["a":"a"])
|
|
45
46
|
let webVC = WebViewController()
|
|
46
47
|
webVC.modalPresentationStyle = .formSheet
|
|
47
48
|
webVC.videoURL = URL(string: watchCGMVideo)
|
|
@@ -51,8 +51,7 @@ class StartConnectionViewController: UIViewController {
|
|
|
51
51
|
ImageTVC.self,
|
|
52
52
|
ChargingIndicatorTVC.self])
|
|
53
53
|
tableView.reloadData()
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
|
|
56
55
|
let isForReconnect = UserDefaults.standard.bool(forKey: "isForReconnect")
|
|
57
56
|
if isForReconnect{
|
|
58
57
|
checkLocationPermission()
|
|
@@ -74,6 +73,7 @@ class StartConnectionViewController: UIViewController {
|
|
|
74
73
|
}
|
|
75
74
|
|
|
76
75
|
customTopView.onDemoTapped = {
|
|
76
|
+
NotificationCenter.default.post(name: Notification.Name("cgmwatchdemoclicked"), object: nil, userInfo: ["a":"a"])
|
|
77
77
|
let webVC = WebViewController()
|
|
78
78
|
webVC.modalPresentationStyle = .formSheet // or .pageSheet, .fullScreen
|
|
79
79
|
webVC.videoURL = URL(string: watchCGMVideo)
|
|
@@ -95,7 +95,9 @@ class StartConnectionViewController: UIViewController {
|
|
|
95
95
|
|
|
96
96
|
private func updateBottomButtonState() {
|
|
97
97
|
if isBluetoothEnabled && isLocationEnabled {
|
|
98
|
+
let isForReconnect = UserDefaults.standard.bool(forKey: "isForReconnect")
|
|
98
99
|
let vc = ConnectToTransmitterViewController.instantiate(fromStoryboard: Enum_stroyboard.Main.rawValue)
|
|
100
|
+
vc.isForReconnect = isForReconnect
|
|
99
101
|
self.navigationController?.pushViewController(vc, animated: false)
|
|
100
102
|
} else {
|
|
101
103
|
let vc = ProvidePermissionViewController.instantiate(fromStoryboard: Enum_stroyboard.Main.rawValue)
|
|
@@ -105,29 +105,25 @@ import Foundation
|
|
|
105
105
|
startDate: String,
|
|
106
106
|
endDate: String
|
|
107
107
|
) -> [String: Any] {
|
|
108
|
-
|
|
108
|
+
var updatedResponse = response
|
|
109
109
|
|
|
110
110
|
if viewModel.isCurrentDateInRange(startDate: startDate, endDate: endDate) {
|
|
111
111
|
print("Current date is in range")
|
|
112
|
-
|
|
112
|
+
|
|
113
|
+
let canConnectOther = KLTLocalSettingManager.shareInstance().canConnectOtherDevice
|
|
114
|
+
let connectedPeripheral = viewModel.manager.connectedPeripheral
|
|
115
|
+
|
|
116
|
+
if connectedPeripheral == nil && !canConnectOther {
|
|
113
117
|
viewModel.manager.startScan()
|
|
114
118
|
viewModel.debouncer.update(with: .transmitterDisconnect)
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
//self.manager.closeBleSensor()
|
|
125
|
-
//manager.startScan()
|
|
126
|
-
//self.debouncer.update(with: .disconnected)
|
|
127
|
-
//debouncer.update(with: .transmitterDisconnectBox)
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if KLTBluetoothManager.shared().currentDevice.connectedDateTime == nil && KLTBluetoothManager.shared().currentDevice.disconnectedDateTime == nil {
|
|
119
|
+
} else {
|
|
120
|
+
if let device = KLTBluetoothManager.shared().currentDevice {
|
|
121
|
+
if device.connectedDateTime == nil && device.disconnectedDateTime == nil {
|
|
122
|
+
viewModel.manager.startScan()
|
|
123
|
+
viewModel.debouncer.update(with: .transmitterDisconnect)
|
|
124
|
+
}
|
|
125
|
+
} else {
|
|
126
|
+
print("⚠️ currentDevice is nil")
|
|
131
127
|
viewModel.manager.startScan()
|
|
132
128
|
viewModel.debouncer.update(with: .transmitterDisconnect)
|
|
133
129
|
}
|
|
@@ -136,9 +132,6 @@ import Foundation
|
|
|
136
132
|
|
|
137
133
|
return updatedResponse
|
|
138
134
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
135
|
}
|
|
143
136
|
|
|
144
137
|
class FinalViewModel: NSObject {
|
|
@@ -335,7 +328,7 @@ class FinalViewModel: NSObject {
|
|
|
335
328
|
let batches = stride(from: 0, to: data.count, by: batchSize).map {
|
|
336
329
|
Array(data[$0..<min($0 + batchSize, data.count)])
|
|
337
330
|
}
|
|
338
|
-
|
|
331
|
+
|
|
339
332
|
uploadBatch(batches: batches, index: 0)
|
|
340
333
|
}
|
|
341
334
|
|