react-native-mytatva-rn-sdk 1.2.46 → 1.2.49

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.
Files changed (29) hide show
  1. package/android/src/main/java/com/mytatvarnsdk/CgmTrackyLibModule.kt +128 -58
  2. package/android/src/main/java/com/mytatvarnsdk/activity/BtManageActivity.java +345 -345
  3. package/android/src/main/java/com/mytatvarnsdk/activity/ConnectSensorActivity.kt +17 -38
  4. package/android/src/main/java/com/mytatvarnsdk/activity/ExitJourneyBottomSheet.kt +51 -51
  5. package/android/src/main/java/com/mytatvarnsdk/activity/PermissionActivity.kt +10 -5
  6. package/android/src/main/java/com/mytatvarnsdk/activity/PlaceSensorActivity.kt +4 -5
  7. package/android/src/main/java/com/mytatvarnsdk/activity/PlaceTransmitterActivity.kt +4 -5
  8. package/android/src/main/java/com/mytatvarnsdk/activity/QRActivity.kt +96 -92
  9. package/android/src/main/java/com/mytatvarnsdk/activity/SearchTransmitterActivity.kt +2 -2
  10. package/android/src/main/java/com/mytatvarnsdk/activity/SensorConnectSuccessActivity.kt +1 -1
  11. package/android/src/main/java/com/mytatvarnsdk/activity/StartCGMActivity.kt +4 -2
  12. package/android/src/main/java/com/mytatvarnsdk/activity/VideoActivity.kt +12 -7
  13. package/android/src/main/java/com/mytatvarnsdk/utils/TatvaEncryptionConfig.kt +0 -5
  14. package/android/src/main/res/layout/activity_video.xml +13 -2
  15. package/ios/Database/KLTBluetoothManager.m +9 -4
  16. package/ios/Database/KLTDatabaseHandler.m +53 -6
  17. package/ios/MyReactNativeBridge.h +4 -1
  18. package/ios/MyReactNativeBridge.m +433 -191
  19. package/ios/Support/API.swift +0 -1
  20. package/ios/Support/Global.swift +12 -0
  21. package/ios/ViewControllers/AttachTransmitterViewController.swift +33 -2
  22. package/ios/ViewControllers/ChatWithExpertViewController.swift +33 -3
  23. package/ios/ViewControllers/ConnectToSensorViewController.swift +101 -12
  24. package/ios/ViewControllers/ConnectToTransmitterViewController.swift +121 -5
  25. package/ios/ViewControllers/ProvidePermissionViewController.swift +37 -5
  26. package/ios/ViewControllers/PutOnTheSensorViewController.swift +22 -2
  27. package/ios/ViewControllers/StartConnectionViewController.swift +31 -3
  28. package/ios/ViewModel/FinalViewModel.swift +155 -48
  29. 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,11 +74,11 @@ 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
72
-
77
+ private var isBatchProcessing = false
73
78
  private var lastDeviceStatus: String? = null
74
-
75
79
  private var glucoseObserver: Observer<PocGlucose?>? = null
76
80
  private var isObserving = false
81
+ private var lastProcessedSyncTimeInMillis: Long? = null
77
82
 
78
83
  init {
79
84
  mReactContext = reactContext
@@ -107,8 +112,7 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
107
112
  Handler(Looper.getMainLooper()).post {
108
113
  mModel.device.observeForever { device ->
109
114
  if (device != null) {
110
- postEventDataToAPI(device, "", device?.qrMessage ?: "")
111
-
115
+ postEventDataToAPI(device, "", device.qrMessage ?: "")
112
116
  Log.d("observeDeviceStatus: ", device.toString())
113
117
  }
114
118
  }
@@ -119,7 +123,7 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
119
123
  }
120
124
 
121
125
  @ReactMethod
122
- fun observeTransmitterUnbindStatus(token: String, apiResponse: String) {
126
+ fun observeTransmitterUnbindStatus(token: String, apiResponse: String?) {
123
127
  try {
124
128
  if (apiResponse != null && apiResponse.isNotEmpty()) {
125
129
  userToken = token
@@ -189,19 +193,13 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
189
193
  val endDate = sensor.endDate
190
194
  val sensorId = sensor.sensorId
191
195
 
192
- println("Start Date: $startDate")
193
- println("End Date: $endDate")
194
-
195
196
  if (isCurrentDateInRange(startDate, endDate)) {
196
-
197
197
  println("Current date is in range")
198
198
 
199
199
  val pocDevice =
200
200
  RepositoryDevice.getInstance(BApplication.getContext()).latestDeviceIoThread
201
201
 
202
202
  if (pocDevice != null) {
203
- Log.d("pocDevice logsss", pocDevice.toString())
204
-
205
203
  if (pocDevice.isUnBind) {
206
204
  postEventDataToAPI(
207
205
  pocDevice,
@@ -210,8 +208,6 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
210
208
  )
211
209
  }
212
210
  } else {
213
- Log.d("pocDevice logsss", "Data null")
214
-
215
211
  postEventDataToAPI(
216
212
  pocDevice,
217
213
  DeviceStatus.TRANSMITTER_DISCONNECT.id,
@@ -231,65 +227,93 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
231
227
  }
232
228
  }
233
229
 
230
+ private var debounceDeviceTimer: Timer? = null
231
+ private var isDebounceTimerActive: Boolean = false
232
+
233
+
234
234
  private fun postEventDataToAPI(device: PocDevice?, mStatus: String, sensorId: String?) {
235
235
  apiScope.launch {
236
236
  try {
237
237
  val bluetoothAdapter: BluetoothAdapter? = BluetoothAdapter.getDefaultAdapter()
238
238
  val bleStatus = bluetoothAdapter?.isEnabled == true
239
- var status = ""
240
239
 
241
- status = if (mStatus.isEmpty()) {
240
+ val status: String = mStatus.ifEmpty {
242
241
  when {
243
242
  device?.isBoundAndConnect == true -> DeviceStatus.CONNECTED.id
244
243
  !bleStatus -> DeviceStatus.BLUETOOTH_OFF.id
245
244
  device?.isUnBind == true -> DeviceStatus.TRANSMITTER_DISCONNECT.id
246
245
  device?.isBoundButDisConnect == true -> DeviceStatus.DISCONNECTED.id
247
- else -> "" // fallback if no status matches
246
+ else -> ""
248
247
  }
249
- } else {
250
- mStatus
251
248
  }
252
249
 
253
- Log.d("postEventDataToAPI: ", "Device Event Status==> $status")
254
-
255
- if (status.isNotEmpty()) {
256
- if (status != lastDeviceStatus) {
250
+ Log.d("Device event Status", "Device event Status: $status")
257
251
 
258
- lastDeviceStatus = status
259
- Log.d("postEventDataToAPI: ", "Device Event Status API==> $status")
252
+ if (status == DeviceStatus.DISCONNECTED.id && !isDebounceTimerActive) {
253
+ // Start debounce timer for 1 minutes
254
+ debounceDeviceTimer = Timer()
255
+ isDebounceTimerActive = true
260
256
 
261
- val rawData = JSONObject().apply {
262
- put("transmitterName", device?.name ?: "")
263
- put("SensorId", sensorId ?: "")
264
- put("Sensor", sensorId ?: "")
265
- put("timeInMillis", System.currentTimeMillis())
257
+ debounceDeviceTimer?.schedule(object : TimerTask() {
258
+ override fun run() {
259
+ isDebounceTimerActive = false
260
+ callEventAPI(device, status, sensorId)
266
261
  }
262
+ }, 1 * 60 * 1000) // 1 minutes in milliseconds
267
263
 
268
- val obj = JSONObject().apply {
269
- put("sensorId", sensorId ?: "")
270
- put("status", status)
271
- put("rawData", rawData)
272
- }
264
+ Log.d("Debounce", "Timer started for disconnection reminder")
265
+ } else {
266
+ // Either device is not disconnected or timer already running
267
+ debounceDeviceTimer?.cancel()
268
+ debounceDeviceTimer = null
269
+ isDebounceTimerActive = false
273
270
 
274
- authenticateSDKService.postDeviceData(
275
- environment = if ("uat".uppercase() == "PROD") TATVA_ENVIRONMENT.PROD else TATVA_ENVIRONMENT.STAGE,
276
- data = obj.toString(),
277
- token = userToken,
278
- loaderListener = object : LoaderListener {
279
- override fun onShowLoader() {}
280
- override fun onHideLoader() {}
281
- }
282
- )
271
+ Log.d("Debounce", "Timer cancelled, event triggered immediately")
283
272
 
284
- resetDebounceTimer()
285
- }
273
+ callEventAPI(device, status, sensorId)
286
274
  }
275
+
287
276
  } catch (e: Exception) {
288
277
  e.printStackTrace()
289
278
  }
290
279
  }
291
280
  }
292
281
 
282
+ private fun callEventAPI(device: PocDevice?, status: String, sensorId: String?) {
283
+ Log.d("Device event Status", "Last Device event lastDeviceStatus API: $lastDeviceStatus")
284
+
285
+ if (status.isNotEmpty() && status != lastDeviceStatus) {
286
+ lastDeviceStatus = status
287
+
288
+ Log.d("Device event Status", "Device event Status API: $status")
289
+
290
+ val rawData = JSONObject().apply {
291
+ put("transmitterName", device?.name ?: "")
292
+ put("SensorId", sensorId ?: "")
293
+ put("Sensor", sensorId ?: "")
294
+ put("timeInMillis", Date().time)
295
+ }
296
+
297
+ val obj = JSONObject().apply {
298
+ put("sensorId", sensorId ?: "")
299
+ put("status", status)
300
+ put("rawData", rawData)
301
+ }
302
+
303
+ authenticateSDKService.postDeviceData(
304
+ environment = if ("uat".uppercase() == "PROD") TATVA_ENVIRONMENT.PROD else TATVA_ENVIRONMENT.STAGE,
305
+ data = obj.toString(),
306
+ token = userToken,
307
+ loaderListener = object : LoaderListener {
308
+ override fun onShowLoader() {}
309
+ override fun onHideLoader() {}
310
+ }
311
+ )
312
+
313
+ resetDebounceTimer()
314
+ }
315
+ }
316
+
293
317
  private fun resetDebounceTimer() {
294
318
  debounceJob?.cancel() // Cancel any existing timer
295
319
  debounceJob = apiScope.launch {
@@ -360,6 +384,13 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
360
384
  )
361
385
  return
362
386
  }
387
+ if (isBatchProcessing) {
388
+ Log.d(
389
+ "observeAllGlucoseData",
390
+ "Batch processing in progress, skipping duplicate call"
391
+ )
392
+ return
393
+ }
363
394
 
364
395
  // Remove existing observer if any to prevent memory leaks
365
396
  stopObservingGlucoseData()
@@ -371,22 +402,38 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
371
402
  val currentTime = System.currentTimeMillis()
372
403
  var dataAge = System.currentTimeMillis()
373
404
 
374
- if (prefsHelper.lastSyncData != null) {
375
- dataAge = currentTime - prefsHelper.lastSyncData.timeInMillis
405
+ val lastSyncData = prefsHelper.lastSyncData
406
+ val currentSyncTimeInMillis = lastSyncData?.timeInMillis
407
+
408
+ if (lastSyncData != null) {
409
+ dataAge = currentTime - lastSyncData.timeInMillis
410
+ }
411
+
412
+ // Only proceed if timeInMillis is different from last processed
413
+ if (currentSyncTimeInMillis != null && lastProcessedSyncTimeInMillis != null && currentSyncTimeInMillis == lastProcessedSyncTimeInMillis) {
414
+ Log.d("SyncTimeCheck", "Duplicate sync time, skipping function calls")
415
+ return@Observer
376
416
  }
377
417
 
378
- if ((pocGlucose != null && prefsHelper.lastSyncData == null) || (pocGlucose != null && prefsHelper.lastSyncData != null && dataAge <= 4 * 60 * 1000L)) {
418
+ if ((pocGlucose != null && lastSyncData == null) || (pocGlucose != null && lastSyncData != null && dataAge <= 4 * 60 * 1000L)) {
379
419
  handleGlucoseData(pocGlucose)
380
420
  Log.d(
381
421
  "observeGlucoseData",
382
422
  "Received glucose data - processing"
383
423
  )
424
+ // Update last processed sync time
425
+ lastProcessedSyncTimeInMillis = currentSyncTimeInMillis
384
426
  } else {
385
- observeAllGlucoseData(userToken)
427
+
428
+ Handler(Looper.getMainLooper()).postDelayed({
429
+ observeAllGlucoseData(userToken)
430
+ }, 100)
386
431
  Log.d(
387
432
  "observeGlucoseData",
388
433
  "Received null glucose data - skipping processing"
389
434
  )
435
+ // Update last processed sync time
436
+ lastProcessedSyncTimeInMillis = currentSyncTimeInMillis
390
437
  }
391
438
  }
392
439
 
@@ -515,6 +562,11 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
515
562
 
516
563
  @ReactMethod
517
564
  fun observeAllGlucoseData(token: String) {
565
+ Log.d("function call", "observeAllGlucoseData")
566
+ if (isBatchProcessing) {
567
+ Log.d("observeAllGlucoseData", "Batch processing in progress, skipping duplicate call")
568
+ return
569
+ }
518
570
  userToken = token
519
571
 
520
572
  // FIX: Ensure proper cleanup and reset state
@@ -525,10 +577,19 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
525
577
  try {
526
578
  val lastSyncData = prefsHelper.lastSyncData
527
579
  Log.d("lastSyncData: ", Gson().toJson(lastSyncData).toString())
580
+ val currentTime = System.currentTimeMillis()
581
+ var dataAge = System.currentTimeMillis()
582
+
583
+ if (prefsHelper.lastSyncData != null) {
584
+ dataAge = currentTime - prefsHelper.lastSyncData.timeInMillis
585
+ }
528
586
 
529
- if (lastSyncData != null) {
587
+ if (lastSyncData != null && dataAge > 3 * 60 * 1000L) {
588
+ isBatchProcessing = true
530
589
  CoroutineScope(Dispatchers.IO).launch {
531
- val glucoseData = mModel.getGlucoseBetweenTime(lastSyncData.lastSyncTime)
590
+
591
+ val glucoseData = mModel.getGlucoseBetweenTime(lastSyncData.timeInMillis)
592
+
532
593
 
533
594
  Log.d("observeAllGlucoseData: ", glucoseData.toString())
534
595
  Log.d("Last sync time: ", lastSyncData.lastSyncTime.toString())
@@ -541,16 +602,18 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
541
602
  "observeAllGlucoseData",
542
603
  "No historical data found, starting live observation"
543
604
  )
544
- Handler(Looper.getMainLooper()).post {
605
+
606
+ withContext(Dispatchers.Main) {
545
607
  observeGlucoseData(userToken)
546
608
  }
547
609
  }
548
610
  }
549
611
  } else {
612
+ isBatchProcessing = false
550
613
  observeGlucoseData(userToken)
551
614
  }
552
615
  } catch (e: Exception) {
553
- Log.e("observeAllGlucoseData", "observeAllGlucoseData Error: ${e.message}")
616
+ isBatchProcessing = false
554
617
  observeGlucoseData(userToken)
555
618
  }
556
619
  }, 100) // Small delay to ensure cleanup
@@ -573,7 +636,8 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
573
636
  }
574
637
 
575
638
  // Ensure we're on main thread and not already observing
576
- Handler(Looper.getMainLooper()).post {
639
+ isBatchProcessing = false
640
+ withContext(Dispatchers.Main) {
577
641
  if (!isObserving) {
578
642
  Log.d(
579
643
  "processBatchDataAndStartObserver",
@@ -591,7 +655,8 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
591
655
  } catch (e: Exception) {
592
656
  Log.e("processBatchDataAndStartObserver", "Error in batch processing: ${e.message}")
593
657
  // Start live observation even on error
594
- Handler(Looper.getMainLooper()).post {
658
+ isBatchProcessing = false
659
+ withContext(Dispatchers.Main) {
595
660
  if (!isObserving) {
596
661
  observeGlucoseData(userToken)
597
662
  }
@@ -620,6 +685,9 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
620
685
  // Clear any cached data if needed
621
686
  prefsHelper.clearQRInformation() // if you have such method
622
687
 
688
+ // Reset last processed sync time
689
+ lastProcessedSyncTimeInMillis = null
690
+
623
691
  } catch (e: Exception) {
624
692
  Log.e("resetCgmState", "Error resetting CGM state: ${e.message}")
625
693
  }
@@ -761,6 +829,9 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
761
829
  // Reset last device status
762
830
  lastDeviceStatus = null
763
831
 
832
+ // Reset last processed sync time
833
+ lastProcessedSyncTimeInMillis = null
834
+
764
835
  } catch (e: Exception) {
765
836
  Log.e("stopObservingGlucoseData", "Error stopping observer: ${e.message}")
766
837
  }
@@ -801,6 +872,7 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
801
872
  it.glucoseId
802
873
  )
803
874
  prefsHelper.lastSyncData = syncData
875
+ lastProcessedSyncTimeInMillis = null
804
876
  Log.d(
805
877
  "Sync Metadata",
806
878
  "Sync metadata updated: glucoseId=${it.glucoseId}, time=${it.timeInMillis}"
@@ -892,6 +964,4 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
892
964
  }
893
965
  }
894
966
 
895
-
896
- }
897
-
967
+ }