react-native-mytatva-rn-sdk 1.2.29 → 1.2.30

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.
@@ -61,924 +61,730 @@ import kotlin.coroutines.suspendCoroutine
61
61
 
62
62
  @ReactModule(name = "CgmTrackyLib")
63
63
  class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
64
- ReactContextBaseJavaModule(reactContext) {
65
- private val mModel: MainActivityModel
66
- var authenticateSDKService: AuthenticateSDKService
67
- private val job = Job()
68
- private val scope = CoroutineScope(Dispatchers.IO + job)
69
- var prefsHelper: SharedPreferencesLibraryUtil
70
- private val apiScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
71
- private var debounceJob: Job? = null
72
- private var lastDeviceStatus: PocDevice? = null
73
-
74
- private var glucoseObserver: Observer<PocGlucose?>? = null
75
- private var isObserving = false
76
-
77
- init {
78
- mReactContext = reactContext
79
- prefsHelper = SharedPreferencesLibraryUtil(mReactContext)
80
- val viewModelStore = ViewModelStore()
81
- val factory =
82
- ViewModelProvider.AndroidViewModelFactory.getInstance(reactContext.applicationContext as Application)
83
- mModel = ViewModelProvider(viewModelStore, factory)[MainActivityModel::class.java]
84
- authenticateSDKService = AuthenticateSDKService(scope = scope)
64
+ ReactContextBaseJavaModule(reactContext) {
65
+ private val mModel: MainActivityModel
66
+ var authenticateSDKService: AuthenticateSDKService
67
+ private val job = Job()
68
+ private val scope = CoroutineScope(Dispatchers.IO + job)
69
+ var prefsHelper: SharedPreferencesLibraryUtil
70
+ private val apiScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
71
+ private var debounceJob: Job? = null
72
+ private var lastDeviceStatus: PocDevice? = null
73
+
74
+ private var glucoseObserver: Observer<PocGlucose?>? = null
75
+ private var isObserving = false
76
+
77
+ init {
78
+ mReactContext = reactContext
79
+ prefsHelper = SharedPreferencesLibraryUtil(mReactContext)
80
+ val viewModelStore = ViewModelStore()
81
+ val factory =
82
+ ViewModelProvider.AndroidViewModelFactory.getInstance(reactContext.applicationContext as Application)
83
+ mModel = ViewModelProvider(viewModelStore, factory)[MainActivityModel::class.java]
84
+ authenticateSDKService = AuthenticateSDKService(scope = scope)
85
+ }
86
+
87
+
88
+ companion object {
89
+ var mReactContext: ReactApplicationContext? = null
90
+ var userToken: String = ""
91
+ }
92
+
93
+ override fun getName(): String {
94
+ return "CgmTrackyLib"
95
+ }
96
+
97
+ @ReactMethod
98
+ fun observeDeviceStatus(token: String) {
99
+ try {
100
+ userToken = token
101
+ Handler(Looper.getMainLooper()).post {
102
+ mModel.device.observeForever { device ->
103
+ if (device != lastDeviceStatus) {
104
+ lastDeviceStatus = device
105
+ postEventDataToAPI(device, "", lastDeviceStatus?.qrMessage ?: "")
106
+ resetDebounceTimer()
107
+ }
108
+
109
+ if (device != null) {
110
+ Log.d("observeDeviceStatus: ", device.toString())
111
+ }
112
+ }
113
+ }
114
+ } catch (e: Exception) {
115
+ Log.e("observeDeviceStatus", "observeDeviceStatus: ${e.message}")
85
116
  }
117
+ }
86
118
 
119
+ @ReactMethod
120
+ fun observeTransmitterUnbindStatus(token: String) {
121
+ try {
122
+ userToken = token
87
123
 
88
- companion object {
89
- var mReactContext: ReactApplicationContext? = null
90
- var userToken: String = ""
91
- }
124
+ authenticateSDKService.getCGMData(
125
+ environment = if ("uat".uppercase() == "PROD") TATVA_ENVIRONMENT.PROD else TATVA_ENVIRONMENT.STAGE,
126
+ token = userToken,
127
+ responseListener = object : AuthenticateSDKService.ResponseListener {
128
+ override fun onResponseSuccess(response: String) {
92
129
 
93
- override fun getName(): String {
94
- return "CgmTrackyLib"
95
- }
130
+ val response = Gson().fromJson(response, CgmSensorResponse::class.java)
131
+ val sensor = response.data?.firstOrNull()
96
132
 
97
- @ReactMethod
98
- fun observeDeviceStatus(token: String) {
99
- try {
100
- userToken = token
101
- Handler(Looper.getMainLooper()).post {
102
- mModel.device.observeForever { device ->
103
- if (device != lastDeviceStatus) {
104
- lastDeviceStatus = device
105
- postEventDataToAPI(device, "", lastDeviceStatus?.qrMessage ?: "")
106
- resetDebounceTimer()
107
- }
108
-
109
- if (device != null) {
110
- Log.d("observeDeviceStatus: ", device.toString())
111
- }
112
- }
113
- }
114
- } catch (e: Exception) {
115
- Log.e("observeDeviceStatus", "observeDeviceStatus: ${e.message}")
116
- }
117
- }
133
+ if (sensor != null && !sensor.startDate.isNullOrEmpty() && !sensor.endDate.isNullOrEmpty()) {
134
+ val startDate = sensor.startDate
135
+ val endDate = sensor.endDate
136
+ val sensorId = sensor.sensorId
118
137
 
119
- @ReactMethod
120
- fun observeTransmitterUnbindStatus(token: String) {
121
- try {
122
- userToken = token
123
-
124
- authenticateSDKService.getCGMData(
125
- environment = if ("uat".uppercase() == "PROD") TATVA_ENVIRONMENT.PROD else TATVA_ENVIRONMENT.STAGE,
126
- token = userToken,
127
- responseListener = object : AuthenticateSDKService.ResponseListener {
128
- override fun onResponseSuccess(response: String) {
129
-
130
- val response = Gson().fromJson(response, CgmSensorResponse::class.java)
131
- val sensor = response.data?.firstOrNull()
132
-
133
- if (sensor != null && !sensor.startDate.isNullOrEmpty() && !sensor.endDate.isNullOrEmpty()) {
134
- val startDate = sensor.startDate
135
- val endDate = sensor.endDate
136
- val sensorId = sensor.sensorId
137
-
138
- println("Start Date: $startDate")
139
- println("End Date: $endDate")
140
-
141
- if (isCurrentDateInRange(startDate, endDate)) {
142
-
143
- println("Current date is in range")
144
-
145
- val pocDevice =
146
- RepositoryDevice.getInstance(BApplication.getContext()).latestDeviceIoThread
147
-
148
- if (pocDevice != null) {
149
- Log.d("pocDevice logsss", pocDevice.toString())
150
-
151
- if (pocDevice.isUnBind) {
152
- postEventDataToAPI(
153
- pocDevice,
154
- DeviceStatus.TRANSMITTER_DISCONNECT.id,
155
- pocDevice.qrMessage
156
- )
157
- }
158
- } else {
159
- Log.d("pocDevice logsss", "Data null")
160
-
161
- postEventDataToAPI(
162
- pocDevice,
163
- DeviceStatus.TRANSMITTER_DISCONNECT.id,
164
- sensorId
165
- )
166
- }
167
-
168
- } else {
169
- println("Current date is out of range")
170
- }
171
- } else {
172
- println("Start or End date not available")
173
- }
174
- }
175
-
176
- override fun onResponseFail() {
177
- }
178
- }
179
- )
138
+ println("Start Date: $startDate")
139
+ println("End Date: $endDate")
180
140
 
181
- } catch (e: Exception) {
182
- Log.e("observeTransmitterUnbindStatus", "observeTransmitterUnbindStatus: ${e.message}")
183
- }
184
- }
141
+ if (isCurrentDateInRange(startDate, endDate)) {
185
142
 
186
- private fun postEventDataToAPI(device: PocDevice?, mStatus: String, sensorId: String?) {
187
- apiScope.launch {
188
- try {
189
- val bluetoothAdapter: BluetoothAdapter? = BluetoothAdapter.getDefaultAdapter()
190
- val bleStatus = bluetoothAdapter?.isEnabled == true
191
- var status = ""
192
-
193
- status = if (mStatus.isEmpty()) {
194
- when {
195
- device?.isBoundAndConnect == true -> DeviceStatus.CONNECTED.id
196
- !bleStatus -> DeviceStatus.BLUETOOTH_OFF.id
197
- device?.isUnBind == true -> DeviceStatus.TRANSMITTER_DISCONNECT.id
198
- device?.isBoundButDisConnect == true -> DeviceStatus.DISCONNECTED.id
199
- else -> "" // fallback if no status matches
200
- }
201
- } else {
202
- mStatus
203
- }
143
+ println("Current date is in range")
144
+
145
+ val pocDevice =
146
+ RepositoryDevice.getInstance(BApplication.getContext()).latestDeviceIoThread
204
147
 
205
- if (status.isNotEmpty()) {
206
- val rawData = JSONObject().apply {
207
- put("transmitterName", device?.name ?: "")
208
- put("SensorId", sensorId ?: "")
209
- put("Sensor", sensorId ?: "")
210
- put("timeInMillis", Date().time)
211
- }
212
-
213
- val obj = JSONObject().apply {
214
- put("sensorId", sensorId ?: "")
215
- put("status", status)
216
- put("rawData", rawData)
217
- }
218
-
219
- authenticateSDKService.postDeviceData(
220
- environment = if ("uat".uppercase() == "PROD") TATVA_ENVIRONMENT.PROD else TATVA_ENVIRONMENT.STAGE,
221
- data = obj.toString(),
222
- token = userToken,
223
- loaderListener = object : LoaderListener {
224
- override fun onShowLoader() {}
225
- override fun onHideLoader() {}
226
- }
148
+ if (pocDevice != null) {
149
+ Log.d("pocDevice logsss", pocDevice.toString())
150
+
151
+ if (pocDevice.isUnBind) {
152
+ postEventDataToAPI(
153
+ pocDevice,
154
+ DeviceStatus.TRANSMITTER_DISCONNECT.id,
155
+ pocDevice.qrMessage
227
156
  )
157
+ }
158
+ } else {
159
+ Log.d("pocDevice logsss", "Data null")
160
+
161
+ postEventDataToAPI(
162
+ pocDevice,
163
+ DeviceStatus.TRANSMITTER_DISCONNECT.id,
164
+ sensorId
165
+ )
228
166
  }
229
167
 
230
- } catch (e: Exception) {
231
- e.printStackTrace()
168
+ } else {
169
+ println("Current date is out of range")
170
+ }
171
+ } else {
172
+ println("Start or End date not available")
232
173
  }
233
- }
234
- }
174
+ }
235
175
 
236
- private fun resetDebounceTimer() {
237
- debounceJob?.cancel() // Cancel any existing timer
238
- debounceJob = apiScope.launch {
239
- delay(60 * 60 * 1000L) // 60 minutes in ms
240
- lastDeviceStatus = null // Reset status after timeout
241
- println("60 min window expired, status reset.")
176
+ override fun onResponseFail() {
177
+ }
242
178
  }
243
- }
179
+ )
244
180
 
245
- @ReactMethod
246
- fun startCgmTracky(token: String) {
247
- try {
248
- userToken = token
249
- val intent = Intent(currentActivity, StartCGMActivity::class.java)
250
- currentActivity?.startActivity(intent)
251
- } catch (e: Exception) {
252
- Log.e("startCgmTracky", "startCgmTracky: ${e.message}")
253
- }
181
+ } catch (e: Exception) {
182
+ Log.e("observeTransmitterUnbindStatus", "observeTransmitterUnbindStatus: ${e.message}")
254
183
  }
184
+ }
255
185
 
256
- fun isCurrentDateInRange(startDateStr: String, endDateStr: String): Boolean {
257
- val format = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
186
+ private fun postEventDataToAPI(device: PocDevice?, mStatus: String, sensorId: String?) {
187
+ apiScope.launch {
188
+ try {
189
+ val bluetoothAdapter: BluetoothAdapter? = BluetoothAdapter.getDefaultAdapter()
190
+ val bleStatus = bluetoothAdapter?.isEnabled == true
191
+ var status = ""
192
+
193
+ status = if (mStatus.isEmpty()) {
194
+ when {
195
+ device?.isBoundAndConnect == true -> DeviceStatus.CONNECTED.id
196
+ !bleStatus -> DeviceStatus.BLUETOOTH_OFF.id
197
+ device?.isUnBind == true -> DeviceStatus.TRANSMITTER_DISCONNECT.id
198
+ device?.isBoundButDisConnect == true -> DeviceStatus.DISCONNECTED.id
199
+ else -> "" // fallback if no status matches
200
+ }
201
+ } else {
202
+ mStatus
203
+ }
258
204
 
259
- val startDate = format.parse(startDateStr)
260
- val endDate = format.parse(endDateStr)
261
- val currentDate = Date()
205
+ if (status.isNotEmpty()) {
206
+ val rawData = JSONObject().apply {
207
+ put("transmitterName", device?.name ?: "")
208
+ put("SensorId", sensorId ?: "")
209
+ put("Sensor", sensorId ?: "")
210
+ put("timeInMillis", Date().time)
211
+ }
262
212
 
263
- return startDate != null && endDate != null &&
264
- !currentDate.before(startDate) && !currentDate.after(endDate)
265
- }
213
+ val obj = JSONObject().apply {
214
+ put("sensorId", sensorId ?: "")
215
+ put("status", status)
216
+ put("rawData", rawData)
217
+ }
266
218
 
267
- @ReactMethod
268
- fun reconnectCgmTracky(token: String) {
269
- try {
270
- userToken = token
271
- val intent = if (areAllPermissionsGranted()) {
272
- Intent(currentActivity, SearchTransmitterActivity::class.java).putExtra(
273
- "IsForReconnect",
274
- true
275
- )
276
- } else {
277
- Intent(currentActivity, PermissionActivity::class.java).putExtra(
278
- "IsForReconnect",
279
- true
280
- )
219
+ authenticateSDKService.postDeviceData(
220
+ environment = if ("uat".uppercase() == "PROD") TATVA_ENVIRONMENT.PROD else TATVA_ENVIRONMENT.STAGE,
221
+ data = obj.toString(),
222
+ token = userToken,
223
+ loaderListener = object : LoaderListener {
224
+ override fun onShowLoader() {}
225
+ override fun onHideLoader() {}
281
226
  }
282
- currentActivity?.startActivity(intent)
283
- } catch (e: Exception) {
284
- Log.e("reconnectCgmTracky", "reconnectCgmTracky: ${e.message}")
227
+ )
285
228
  }
286
- }
287
229
 
288
- @ReactMethod
289
- fun openHelpSupport() {
290
- try {
291
- val intent = Intent(currentActivity, HelpActivity::class.java)
292
- currentActivity?.startActivity(intent)
293
- } catch (e: Exception) {
294
- Log.e("openHelpSupport", "openHelpSupport: ${e.message}")
295
- }
230
+ } catch (e: Exception) {
231
+ e.printStackTrace()
232
+ }
233
+ }
234
+ }
235
+
236
+ private fun resetDebounceTimer() {
237
+ debounceJob?.cancel() // Cancel any existing timer
238
+ debounceJob = apiScope.launch {
239
+ delay(60 * 60 * 1000L) // 60 minutes in ms
240
+ lastDeviceStatus = null // Reset status after timeout
241
+ println("60 min window expired, status reset.")
296
242
  }
243
+ }
297
244
 
298
- private fun areAllPermissionsGranted(): Boolean {
299
- val requiredPermissions = mutableListOf<String>()
245
+ @ReactMethod
246
+ fun startCgmTracky(token: String) {
247
+ try {
248
+ userToken = token
249
+ val intent = Intent(currentActivity, StartCGMActivity::class.java)
250
+ currentActivity?.startActivity(intent)
251
+ } catch (e: Exception) {
252
+ Log.e("startCgmTracky", "startCgmTracky: ${e.message}")
253
+ }
254
+ }
300
255
 
301
- // Add Bluetooth permissions
302
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
303
- requiredPermissions.addAll(PermissionUtils.BLUETOOTH_S)
304
- }
256
+ fun isCurrentDateInRange(startDateStr: String, endDateStr: String): Boolean {
257
+ val format = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
305
258
 
306
- // Add location permissions
307
- requiredPermissions.addAll(PermissionUtils.LOCAL_PERMISSION)
259
+ val startDate = format.parse(startDateStr)
260
+ val endDate = format.parse(endDateStr)
261
+ val currentDate = Date()
308
262
 
309
- // Add camera permission
310
- requiredPermissions.addAll(PermissionUtils.CAMERA_PERMISSION)
263
+ return startDate != null && endDate != null &&
264
+ !currentDate.before(startDate) && !currentDate.after(endDate)
265
+ }
311
266
 
312
- return requiredPermissions.all {
313
- ContextCompat.checkSelfPermission(
314
- mReactContext!!,
315
- it
316
- ) == PackageManager.PERMISSION_GRANTED
317
- }
267
+ @ReactMethod
268
+ fun reconnectCgmTracky(token: String) {
269
+ try {
270
+ userToken = token
271
+ val intent = if (areAllPermissionsGranted()) {
272
+ Intent(currentActivity, SearchTransmitterActivity::class.java).putExtra(
273
+ "IsForReconnect",
274
+ true
275
+ )
276
+ } else {
277
+ Intent(currentActivity, PermissionActivity::class.java).putExtra(
278
+ "IsForReconnect",
279
+ true
280
+ )
281
+ }
282
+ currentActivity?.startActivity(intent)
283
+ } catch (e: Exception) {
284
+ Log.e("reconnectCgmTracky", "reconnectCgmTracky: ${e.message}")
318
285
  }
286
+ }
287
+
288
+ @ReactMethod
289
+ fun openHelpSupport() {
290
+ try {
291
+ val intent = Intent(currentActivity, HelpActivity::class.java)
292
+ currentActivity?.startActivity(intent)
293
+ } catch (e: Exception) {
294
+ Log.e("openHelpSupport", "openHelpSupport: ${e.message}")
295
+ }
296
+ }
319
297
 
298
+ private fun areAllPermissionsGranted(): Boolean {
299
+ val requiredPermissions = mutableListOf<String>()
320
300
 
321
- /*@ReactMethod
322
- fun observeGlucoseData(token: String) {
323
- try {
324
- userToken = token
325
- Handler(Looper.getMainLooper()).post {
326
- //Observe latest glucose data
327
- mModel.latestGlucose.observeForever { pocGlucose ->
328
- if (pocGlucose != null) {
329
-
330
- if (pocGlucose.errorCode == enumError.NONE) {
331
- if (pocGlucose.showGlucoseMG > 0) {
332
- val dto: GlucoseLog = mapToDto(pocGlucose)
333
- val logs: ArrayList<GlucoseLog> = ArrayList()
334
- logs.add(dto)
335
-
336
- val request: GlucoseLogRequest =
337
- GlucoseLogRequest(vendor = "GoodFlip", logs = logs)
338
- val gson: Gson = GsonBuilder().create()
339
- val json = gson.toJson(request)
340
-
341
- Log.d("Glucose data 3 min==> ", "Glucose data 3 min==> final Json: $json")
342
-
343
- authenticateSDKService.postCGMData(
344
- environment = if ("uat".uppercase() == "PROD") TATVA_ENVIRONMENT.PROD else TATVA_ENVIRONMENT.STAGE,
345
- data = json.toString(),
346
- token = userToken,
347
- responseListener = object :
348
- AuthenticateSDKService.ResponseListener {
349
- override fun onResponseSuccess() {
350
- }
351
-
352
- override fun onResponseFail() {
353
- }
354
- }
355
- )
356
- }
357
- } else {
358
- if (pocGlucose.errorCode == enumError.ERROR_FLOODING_WATER) {
359
- lastDeviceStatus =
360
- pocGlucose.deviceId.toInt().let { mModel.getDeviceInfo(it) }
361
- lastDeviceStatus?.let {
362
- postEventDataToAPI(
363
- it,
364
- DeviceStatus.MOISTURE_DETECT.id
365
- )
366
- }
367
- resetDebounceTimer()
368
- } else if (pocGlucose.errorCode == enumError.ERROR_CURRENT_SMALL || pocGlucose.errorCode == enumError.ERROR_NOISE || pocGlucose.errorCode == enumError.ERROR_SENSITIVITY_ATTENUATION) {
369
- lastDeviceStatus =
370
- pocGlucose.deviceId.toInt().let { mModel.getDeviceInfo(it) }
371
- lastDeviceStatus?.let {
372
- postEventDataToAPI(
373
- it,
374
- DeviceStatus.WEAK_SIGNAL.id
375
- )
376
- }
377
- resetDebounceTimer()
378
- } else {
379
- lastDeviceStatus =
380
- pocGlucose.deviceId.toInt().let { mModel.getDeviceInfo(it) }
381
- lastDeviceStatus?.let {
382
- postEventDataToAPI(
383
- it,
384
- DeviceStatus.ERROR_COMMON.id
385
- )
386
- }
387
- resetDebounceTimer()
388
- }
389
- }
390
- }
391
- }
392
- }
393
- } catch (e: Exception) {
394
- Log.e("observeGlucoseData", "observeGlucoseData: ${e.message}")
395
- }
396
- }*/
397
-
398
- @ReactMethod
399
- fun observeGlucoseData(token: String) {
400
- try {
401
- userToken = token
301
+ // Add Bluetooth permissions
302
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
303
+ requiredPermissions.addAll(PermissionUtils.BLUETOOTH_S)
304
+ }
402
305
 
403
- // Remove existing observer if any to prevent memory leaks
404
- stopObservingGlucoseData()
306
+ // Add location permissions
307
+ requiredPermissions.addAll(PermissionUtils.LOCAL_PERMISSION)
405
308
 
406
- // Create new observer with explicit nullable parameter type
407
- glucoseObserver = Observer<PocGlucose?> { pocGlucose ->
408
- // Critical fix: Explicitly handle nullable parameter
409
- if (pocGlucose != null) {
410
- handleGlucoseData(pocGlucose)
411
- } else {
412
- Log.w("observeGlucoseData", "Received null glucose data - skipping processing")
413
- }
414
- }
309
+ // Add camera permission
310
+ requiredPermissions.addAll(PermissionUtils.CAMERA_PERMISSION)
415
311
 
416
- // Add observer on main thread
417
- Handler(Looper.getMainLooper()).post {
418
- glucoseObserver?.let { observer ->
419
- try {
420
- mModel.latestGlucose.observeForever(observer)
421
- isObserving = true
422
- Log.d("observeGlucoseData", "Observer added successfully")
423
- } catch (e: Exception) {
424
- Log.e("observeGlucoseData", "Error adding observer: ${e.message}")
425
- glucoseObserver = null
426
- }
427
- }
428
- }
429
- } catch (e: Exception) {
430
- Log.e("observeGlucoseData", "observeGlucoseData: ${e.message}")
431
- e.printStackTrace()
432
- }
312
+ return requiredPermissions.all {
313
+ ContextCompat.checkSelfPermission(
314
+ mReactContext!!,
315
+ it
316
+ ) == PackageManager.PERMISSION_GRANTED
433
317
  }
318
+ }
434
319
 
320
+ @ReactMethod
321
+ fun observeGlucoseData(token: String) {
322
+ try {
323
+ userToken = token
435
324
 
436
- private fun handleGlucoseData(pocGlucose: PocGlucose) {
437
- try {
438
- // Additional safety check
439
- if (pocGlucose.glucoseId == null) {
440
- Log.w("handleGlucoseData", "Glucose ID is null, skipping processing")
441
- return
442
- }
325
+ // Remove existing observer if any to prevent memory leaks
326
+ stopObservingGlucoseData()
327
+
328
+ // Create new observer with explicit nullable parameter type
329
+ glucoseObserver = Observer<PocGlucose?> { pocGlucose ->
330
+ if (pocGlucose != null) {
331
+ // Add timestamp check to prevent processing old data
332
+ val currentTime = System.currentTimeMillis()
333
+ val dataAge = currentTime - pocGlucose.timeInMillis
334
+
335
+ // Only process data that's relatively recent (within last 10 minutes as example)
336
+ // Adjust this threshold based on your requirements
337
+ if (dataAge <= 10 * 60 * 1000L) { // 10 minutes
338
+ handleGlucoseData(pocGlucose)
339
+ } else {
340
+ Log.d("observeGlucoseData", "Skipping old glucose data: age = ${dataAge}ms")
341
+ }
342
+ } else {
343
+ Log.w("observeGlucoseData", "Received null glucose data - skipping processing")
344
+ }
345
+ }
443
346
 
444
- Log.d("handleGlucoseData", "Processing glucose data: ${pocGlucose.glucoseId}")
445
-
446
- if (pocGlucose.errorCode == enumError.NONE) {
447
- if (pocGlucose.showGlucoseMG > 0) {
448
- val dto: GlucoseLog = mapToDto(pocGlucose)
449
- val logs: ArrayList<GlucoseLog> = ArrayList()
450
- logs.add(dto)
451
-
452
- val request: GlucoseLogRequest =
453
- GlucoseLogRequest(vendor = "GoodFlip", logs = logs)
454
- val gson: Gson = GsonBuilder().create()
455
- val json = gson.toJson(request)
456
-
457
- Log.d("Glucose data 3 min==> ", "Glucose data 3 min==> final Json: $json")
458
-
459
- authenticateSDKService.postCGMData(
460
- environment = if ("uat".uppercase() == "PROD") TATVA_ENVIRONMENT.PROD else TATVA_ENVIRONMENT.STAGE,
461
- data = json,
462
- token = userToken,
463
- responseListener = object : AuthenticateSDKService.ResponseListener {
464
- override fun onResponseSuccess(response: String) {
465
- updateSyncMetadata(pocGlucose)
466
- Log.d("CGM Data", "Single glucose data uploaded successfully")
467
- }
468
-
469
- override fun onResponseFail() {
470
- Log.e("CGM Data", "Failed to upload single glucose data")
471
- }
472
- }
473
- )
474
- } else {
475
- Log.d(
476
- "handleGlucoseData",
477
- "Glucose value is 0 or negative: ${pocGlucose.showGlucoseMG}"
478
- )
479
- }
480
- } else {
481
- Log.d("handleGlucoseData", "Glucose data has error: ${pocGlucose.errorCode}")
482
- handleGlucoseError(pocGlucose)
483
- }
484
- } catch (e: Exception) {
485
- Log.e("handleGlucoseData", "Error handling glucose data: ${e.message}")
486
- e.printStackTrace()
347
+ // Add observer on main thread
348
+ Handler(Looper.getMainLooper()).post {
349
+ glucoseObserver?.let { observer ->
350
+ try {
351
+ mModel.latestGlucose.observeForever(observer)
352
+ isObserving = true
353
+ Log.d("observeGlucoseData", "Live glucose observer started successfully")
354
+ } catch (e: Exception) {
355
+ Log.e("observeGlucoseData", "Error adding observer: ${e.message}")
356
+ glucoseObserver = null
357
+ }
487
358
  }
359
+ }
360
+ } catch (e: Exception) {
361
+ Log.e("observeGlucoseData", "observeGlucoseData: ${e.message}")
362
+ e.printStackTrace()
488
363
  }
364
+ }
365
+
366
+ private fun handleGlucoseData(pocGlucose: PocGlucose) {
367
+ try {
368
+ // Additional safety check
369
+ if (pocGlucose.glucoseId == null) {
370
+ Log.w("handleGlucoseData", "Glucose ID is null, skipping processing")
371
+ return
372
+ }
489
373
 
490
- // Extract error handling logic
491
- private fun handleGlucoseError(pocGlucose: PocGlucose) {
492
- try {
493
- // Additional safety check for deviceId
494
- if (pocGlucose.deviceId == null) {
495
- Log.e("handleGlucoseError", "Device ID is null, cannot process error")
496
- return
497
- }
498
-
499
- val deviceInfo = mModel.getDeviceInfo(pocGlucose.deviceId.toInt())
500
- deviceInfo?.let {
501
- val statusId = when (pocGlucose.errorCode) {
502
- enumError.ERROR_FLOODING_WATER -> {
503
- Log.d("handleGlucoseError", "Moisture detected")
504
- DeviceStatus.MOISTURE_DETECT.id
505
- }
506
-
507
- enumError.ERROR_CURRENT_SMALL,
508
- enumError.ERROR_NOISE,
509
- enumError.ERROR_SENSITIVITY_ATTENUATION -> {
510
- Log.d("handleGlucoseError", "Weak signal detected")
511
- DeviceStatus.WEAK_SIGNAL.id
512
- }
513
-
514
- else -> {
515
- Log.d(
516
- "handleGlucoseError",
517
- "Common error detected: ${pocGlucose.errorCode}"
518
- )
519
- DeviceStatus.ERROR_COMMON.id
520
- }
521
- }
374
+ Log.d("handleGlucoseData", "Processing glucose data: ${pocGlucose.glucoseId}")
375
+
376
+ if (pocGlucose.errorCode == enumError.NONE) {
377
+ if (pocGlucose.showGlucoseMG > 0) {
378
+ val dto: GlucoseLog = mapToDto(pocGlucose)
379
+ val logs: ArrayList<GlucoseLog> = ArrayList()
380
+ logs.add(dto)
381
+
382
+ val request: GlucoseLogRequest =
383
+ GlucoseLogRequest(vendor = "GoodFlip", logs = logs)
384
+ val gson: Gson = GsonBuilder().create()
385
+ val json = gson.toJson(request)
386
+
387
+ Log.d("Glucose data 3 min==> ", "Glucose data 3 min==> final Json: $json")
388
+
389
+ authenticateSDKService.postCGMData(
390
+ environment = if ("uat".uppercase() == "PROD") TATVA_ENVIRONMENT.PROD else TATVA_ENVIRONMENT.STAGE,
391
+ data = json,
392
+ token = userToken,
393
+ responseListener = object : AuthenticateSDKService.ResponseListener {
394
+ override fun onResponseSuccess(response: String) {
395
+ updateSyncMetadata(pocGlucose)
396
+ Log.d("CGM Data", "Single glucose data uploaded successfully")
397
+ }
522
398
 
523
- postEventDataToAPI(it, statusId, it.qrMessage)
524
- resetDebounceTimer()
525
- } ?: run {
526
- Log.e(
527
- "handleGlucoseError",
528
- "Device info not found for deviceId: ${pocGlucose.deviceId}"
529
- )
399
+ override fun onResponseFail() {
400
+ Log.e("CGM Data", "Failed to upload single glucose data")
401
+ }
530
402
  }
531
- } catch (e: Exception) {
532
- Log.e("handleGlucoseError", "Error handling glucose error: ${e.message}")
533
- e.printStackTrace()
403
+ )
404
+ } else {
405
+ Log.d(
406
+ "handleGlucoseData",
407
+ "Glucose value is 0 or negative: ${pocGlucose.showGlucoseMG}"
408
+ )
534
409
  }
410
+ } else {
411
+ Log.d("handleGlucoseData", "Glucose data has error: ${pocGlucose.errorCode}")
412
+ handleGlucoseError(pocGlucose)
413
+ }
414
+ } catch (e: Exception) {
415
+ Log.e("handleGlucoseData", "Error handling glucose data: ${e.message}")
416
+ e.printStackTrace()
535
417
  }
418
+ }
419
+
420
+ // Extract error handling logic
421
+ private fun handleGlucoseError(pocGlucose: PocGlucose) {
422
+ try {
423
+ // Additional safety check for deviceId
424
+ if (pocGlucose.deviceId == null) {
425
+ Log.e("handleGlucoseError", "Device ID is null, cannot process error")
426
+ return
427
+ }
536
428
 
537
- /*@ReactMethod
538
- fun observeAllGlucoseData(token: String) {
539
- userToken = token
540
- Log.e("userToken", "userToken: ${userToken}")
541
- try {
542
- val lastSyncData = prefsHelper.lastSyncData
543
- Log.d("lastSyncData: ", Gson().toJson(lastSyncData).toString())
544
-
545
- if (lastSyncData != null) {
546
- CoroutineScope(Dispatchers.IO).launch {
547
- getGlucoseDataAndUploadInBatch(
548
- mModel.getGlucoseBetweenTime(
549
- lastSyncData.lastSyncTime
550
- )
429
+ val deviceInfo = mModel.getDeviceInfo(pocGlucose.deviceId.toInt())
430
+ deviceInfo?.let {
431
+ val statusId = when (pocGlucose.errorCode) {
432
+ enumError.ERROR_FLOODING_WATER -> {
433
+ Log.d("handleGlucoseError", "Moisture detected")
434
+ DeviceStatus.MOISTURE_DETECT.id
435
+ }
436
+
437
+ enumError.ERROR_CURRENT_SMALL,
438
+ enumError.ERROR_NOISE,
439
+ enumError.ERROR_SENSITIVITY_ATTENUATION -> {
440
+ Log.d("handleGlucoseError", "Weak signal detected")
441
+ DeviceStatus.WEAK_SIGNAL.id
442
+ }
443
+
444
+ else -> {
445
+ Log.d(
446
+ "handleGlucoseError",
447
+ "Common error detected: ${pocGlucose.errorCode}"
551
448
  )
449
+ DeviceStatus.ERROR_COMMON.id
552
450
  }
553
- } else {
554
- observeGlucoseData(userToken)
555
451
  }
556
452
 
557
- } catch (e: Exception) {
558
- Log.e("observeAllGlucoseData", "observeAllGlucoseData Error: ${e.message}")
453
+ postEventDataToAPI(it, statusId, it.qrMessage)
454
+ resetDebounceTimer()
455
+ } ?: run {
456
+ Log.e(
457
+ "handleGlucoseError",
458
+ "Device info not found for deviceId: ${pocGlucose.deviceId}"
459
+ )
559
460
  }
560
- }*/
561
-
562
-
563
- @ReactMethod
564
- fun observeAllGlucoseData(token: String) {
565
- userToken = token
566
- Log.e("userToken", "userToken: $token")
567
-
568
- // Stop current observation to prevent duplicates
569
- stopObservingGlucoseData()
570
-
571
- try {
572
- val lastSyncData = prefsHelper.lastSyncData
573
- Log.d("lastSyncData: ", Gson().toJson(lastSyncData).toString())
574
-
575
- if (lastSyncData != null) {
576
- CoroutineScope(Dispatchers.IO).launch {
577
- val glucoseData = mModel.getGlucoseBetweenTime(lastSyncData.lastSyncTime)
578
- if (glucoseData != null) {
579
- getGlucoseDataAndUploadInBatch(glucoseData)
580
- } else {
581
- Log.d(
582
- "observeAllGlucoseData",
583
- "No glucose data found, starting live observation"
584
- )
585
- observeGlucoseData(userToken)
586
- }
587
- }
588
- } else {
589
- observeGlucoseData(userToken)
590
- }
591
- } catch (e: Exception) {
592
- Log.e("observeAllGlucoseData", "observeAllGlucoseData Error: ${e.message}")
593
- }
461
+ } catch (e: Exception) {
462
+ Log.e("handleGlucoseError", "Error handling glucose error: ${e.message}")
463
+ e.printStackTrace()
594
464
  }
465
+ }
595
466
 
596
- @ReactMethod
597
- fun stopObservingGlucoseData() {
598
- try {
599
- glucoseObserver?.let { observer ->
600
- Handler(Looper.getMainLooper()).post {
601
- try {
602
- mModel.latestGlucose.removeObserver(observer)
603
- isObserving = false
604
- Log.d("stopObservingGlucoseData", "Observer removed successfully")
605
- } catch (e: Exception) {
606
- Log.e("stopObservingGlucoseData", "Error removing observer: ${e.message}")
607
- }
608
- }
609
- }
610
- glucoseObserver = null
611
- } catch (e: Exception) {
612
- Log.e("stopObservingGlucoseData", "Error stopping observer: ${e.message}")
613
- }
614
- }
615
467
 
616
- fun getGlucoseDataAndUploadInBatch(dataList: List<PocGlucose>) {
617
- if (dataList.isEmpty()) {
618
- Log.d("getGlucoseDataAndUploadInBatch", "No data to upload, starting live observation")
619
- if (!isObserving) {
620
- observeGlucoseData(userToken)
621
- }
622
- return
623
- }
468
+ @ReactMethod
469
+ fun observeAllGlucoseData(token: String) {
470
+ userToken = token
624
471
 
625
- val batchSize = 40
626
- val chunks = dataList.chunked(batchSize)
472
+ // Stop current observation to prevent duplicates
473
+ stopObservingGlucoseData()
627
474
 
628
- Log.d("getGlucoseDataAndUploadInBatch", "Starting batch upload with ${chunks.size} batches")
475
+ try {
476
+ val lastSyncData = prefsHelper.lastSyncData
477
+ Log.d("lastSyncData: ", Gson().toJson(lastSyncData).toString())
629
478
 
479
+ if (lastSyncData != null) {
630
480
  CoroutineScope(Dispatchers.IO).launch {
631
- var lastSyncedRecord: PocGlucose? = null
632
- var allBatchesSuccessful = true
633
-
634
- for ((index, batch) in chunks.withIndex()) {
635
- try {
636
- val transformedLogs = batch.filter { it.showGlucoseMG > 0 }.map { pocGlucose ->
637
- CgmLog(
638
- timeInMillis = pocGlucose.timeInMillis,
639
- countdownMinutes = pocGlucose.countdownMinutes,
640
- countdownDays = pocGlucose.countdownDays,
641
- hypoglycemiaEarlyWarnMinutes = pocGlucose.hypoglycemiaEarlyWarnMinutes,
642
- showGlucoseMG = pocGlucose.showGlucoseMG,
643
- glucoseId = pocGlucose.glucoseId,
644
- name = pocGlucose.name,
645
- bytes = pocGlucose.bytes,
646
- showGlucose = pocGlucose.showGlucose,
647
- Ib = pocGlucose.ib,
648
- Iw = pocGlucose.iw,
649
- countdownHours = pocGlucose.countdownHours,
650
- T = pocGlucose.t,
651
- year = pocGlucose.year,
652
- month = pocGlucose.month,
653
- day = pocGlucose.day,
654
- hour = pocGlucose.hour,
655
- minute = pocGlucose.minute,
656
- trendObject = com.mytatvarnsdk.model.TrendObject(
657
- trendId = pocGlucose.trend.trendId,
658
- drawableId = pocGlucose.trend.drawableId,
659
- widgetImg = pocGlucose.trend.widgetImg,
660
- apsChangeRate = pocGlucose.trend.apsChangeRate
661
- ),
662
- glucoseStatusObject = com.mytatvarnsdk.model.GlucoseStatusObject(
663
- statusId = pocGlucose.glucoseStatus.statusId
664
- ),
665
- errorObject = com.mytatvarnsdk.model.ErrorObject(
666
- errorId = pocGlucose.errorCode.errorId,
667
- sound = pocGlucose.errorCode.sound
668
- )
669
- )
670
- }
671
-
672
- if (transformedLogs.isEmpty()) {
673
- Log.d("Batch Upload", "Batch $index skipped - no valid glucose readings")
674
- continue
675
- }
676
-
677
- val allResult = AllCGMLogRequest(vendor = "GoodFlip", logs = transformedLogs)
678
- val json = Gson().toJson(allResult)
679
-
680
- Log.d("Batch Upload JSON", "Batch $index with ${transformedLogs.size} records")
681
- logLongJson("Batch $index JSON=>>> ", json)
682
-
683
- val uploadSuccessful = uploadBatchSynchronously(json, index)
684
-
685
- if (uploadSuccessful) {
686
- lastSyncedRecord = batch.lastOrNull()
687
- updateSyncMetadata(lastSyncedRecord)
688
- Log.d("Batch Upload", "✅ Batch $index uploaded successfully")
689
- } else {
690
- allBatchesSuccessful = false
691
- Log.e("Batch Upload", "❌ Batch $index failed, stopping further uploads")
692
- break
693
- }
694
-
695
- delay(500L) // Rate limiting between batches
696
-
697
- } catch (e: Exception) {
698
- Log.e("Batch Upload", "❌ Batch $index exception: ${e.message}")
699
- allBatchesSuccessful = false
700
- break
701
- }
702
- }
703
-
704
- // Handle last synced record error status
705
- lastSyncedRecord?.let { record ->
706
- if (record.errorCode != enumError.NONE) {
707
- handleGlucoseError(record)
708
- }
481
+ val glucoseData = mModel.getGlucoseBetweenTime(lastSyncData.lastSyncTime)
482
+ if (glucoseData != null && glucoseData.isNotEmpty()) {
483
+ // Process batch data and wait for completion
484
+ processBatchDataAndStartObserver(glucoseData)
485
+ } else {
486
+ Log.d("observeAllGlucoseData", "No historical data found, starting live observation")
487
+ // Start live observation immediately if no historical data
488
+ Handler(Looper.getMainLooper()).post {
489
+ observeGlucoseData(userToken)
709
490
  }
491
+ }
492
+ }
493
+ } else {
494
+ // No sync data exists, start live observation
495
+ observeGlucoseData(userToken)
496
+ }
497
+ } catch (e: Exception) {
498
+ Log.e("observeAllGlucoseData", "observeAllGlucoseData Error: ${e.message}")
499
+ // Fallback to live observation on error
500
+ observeGlucoseData(userToken)
501
+ }
502
+ }
503
+
504
+ // New method to handle batch processing and ensure proper sequencing
505
+ private suspend fun processBatchDataAndStartObserver(dataList: List<PocGlucose>) {
506
+ try {
507
+ // Process all batches
508
+ val success = processBatchDataSynchronously(dataList)
509
+
510
+ // Only start live observer after batch processing is completely done
511
+ if (success) {
512
+ Log.d(
513
+ "processBatchDataAndStartObserver",
514
+ "Batch processing completed successfully, starting live observer"
515
+ )
516
+ } else {
517
+ Log.w(
518
+ "processBatchDataAndStartObserver",
519
+ "Batch processing had failures, still starting live observer"
520
+ )
521
+ }
710
522
 
711
- Log.d("Batch Upload", "Batch upload completed. Success: $allBatchesSuccessful")
523
+ // Start live observation on main thread after batch completion
524
+ Handler(Looper.getMainLooper()).post {
525
+ if (!isObserving) {
526
+ observeGlucoseData(userToken)
527
+ }
528
+ }
712
529
 
713
- // Only start observing new data if we're not already doing so
714
- if (!isObserving) {
715
- observeGlucoseData(userToken)
716
- }
530
+ } catch (e: Exception) {
531
+ Log.e("processBatchDataAndStartObserver", "Error in batch processing: ${e.message}")
532
+ // Start live observation even on error
533
+ Handler(Looper.getMainLooper()).post {
534
+ if (!isObserving) {
535
+ observeGlucoseData(userToken)
717
536
  }
537
+ }
718
538
  }
539
+ }
719
540
 
720
- // Helper method for synchronous batch upload
721
- private suspend fun uploadBatchSynchronously(json: String, batchIndex: Int): Boolean {
722
- return suspendCoroutine { continuation ->
723
- try {
724
- authenticateSDKService.postCGMData(
725
- environment = if ("uat".uppercase() == "PROD") TATVA_ENVIRONMENT.PROD else TATVA_ENVIRONMENT.STAGE,
726
- data = json,
727
- token = userToken,
728
- responseListener = object : AuthenticateSDKService.ResponseListener {
729
- override fun onResponseSuccess(response: String) {
730
- continuation.resume(true)
731
- }
732
-
733
- override fun onResponseFail() {
734
- continuation.resume(false)
735
- }
736
- }
737
- )
738
- } catch (e: Exception) {
739
- Log.e("uploadBatchSynchronously", "Exception in batch $batchIndex: ${e.message}")
740
- continuation.resume(false)
741
- }
742
- }
541
+ // Updated batch processing method with better sync control
542
+ private suspend fun processBatchDataSynchronously(dataList: List<PocGlucose>): Boolean {
543
+ if (dataList.isEmpty()) {
544
+ Log.d("processBatchDataSynchronously", "No data to upload")
545
+ return true
743
546
  }
744
547
 
745
- private fun updateSyncMetadata(lastRecord: PocGlucose?) {
746
- lastRecord?.let {
747
- try {
748
- val syncData = SyncMeta(
749
- Date().time,
750
- it.timeInMillis,
751
- it.deviceId,
752
- it.glucoseId
753
- )
754
- prefsHelper.lastSyncData = syncData
755
- Log.d("Sync Metadata", "Last sync data stored: ${Gson().toJson(syncData)}")
756
- } catch (e: Exception) {
757
- Log.e("updateSyncMetadata", "Error updating sync metadata: ${e.message}")
758
- }
548
+ val batchSize = 40
549
+ val chunks = dataList.chunked(batchSize)
550
+ var lastSyncedRecord: PocGlucose? = null
551
+ var allBatchesSuccessful = true
552
+
553
+ Log.d("processBatchDataSynchronously", "Starting batch upload with ${chunks.size} batches")
554
+
555
+ for ((index, batch) in chunks.withIndex()) {
556
+ try {
557
+ val transformedLogs = batch.filter { it.showGlucoseMG > 0 }.map { pocGlucose ->
558
+ CgmLog(
559
+ timeInMillis = pocGlucose.timeInMillis,
560
+ countdownMinutes = pocGlucose.countdownMinutes,
561
+ countdownDays = pocGlucose.countdownDays,
562
+ hypoglycemiaEarlyWarnMinutes = pocGlucose.hypoglycemiaEarlyWarnMinutes,
563
+ showGlucoseMG = pocGlucose.showGlucoseMG,
564
+ glucoseId = pocGlucose.glucoseId,
565
+ name = pocGlucose.name,
566
+ bytes = pocGlucose.bytes,
567
+ showGlucose = pocGlucose.showGlucose,
568
+ Ib = pocGlucose.ib,
569
+ Iw = pocGlucose.iw,
570
+ countdownHours = pocGlucose.countdownHours,
571
+ T = pocGlucose.t,
572
+ year = pocGlucose.year,
573
+ month = pocGlucose.month,
574
+ day = pocGlucose.day,
575
+ hour = pocGlucose.hour,
576
+ minute = pocGlucose.minute,
577
+ trendObject = com.mytatvarnsdk.model.TrendObject(
578
+ trendId = pocGlucose.trend.trendId,
579
+ drawableId = pocGlucose.trend.drawableId,
580
+ widgetImg = pocGlucose.trend.widgetImg,
581
+ apsChangeRate = pocGlucose.trend.apsChangeRate
582
+ ),
583
+ glucoseStatusObject = com.mytatvarnsdk.model.GlucoseStatusObject(
584
+ statusId = pocGlucose.glucoseStatus.statusId
585
+ ),
586
+ errorObject = com.mytatvarnsdk.model.ErrorObject(
587
+ errorId = pocGlucose.errorCode.errorId,
588
+ sound = pocGlucose.errorCode.sound
589
+ )
590
+ )
759
591
  }
760
- }
761
592
 
762
- /*fun getGlucoseDataAndUploadInBatch(dataList: List<PocGlucose>) {
763
- if (dataList.isNotEmpty()) {
764
- val batchSize = 40
593
+ if (transformedLogs.isEmpty()) {
594
+ Log.d("processBatchDataSynchronously", "Batch $index skipped - no valid glucose readings")
595
+ continue
596
+ }
765
597
 
766
- val chunks = dataList.chunked(batchSize)
598
+ val allResult = AllCGMLogRequest(vendor = "GoodFlip", logs = transformedLogs)
599
+ val json = Gson().toJson(allResult)
767
600
 
768
- CoroutineScope(Dispatchers.IO).launch {
601
+ Log.d("Batch Upload", "Processing batch $index with ${transformedLogs.size} records")
602
+ logLongJson("Batch $index JSON=>>> ", json)
769
603
 
770
- var lastSyncedRecord: PocGlucose? = null
771
-
772
- for ((index, batch) in chunks.withIndex()) {
773
- try {
774
- val transformedLogs = batch.filter { it.showGlucoseMG > 0 }.map {
775
- CgmLog(
776
- timeInMillis = it.timeInMillis,
777
- countdownMinutes = it.countdownMinutes,
778
- countdownDays = it.countdownDays,
779
- hypoglycemiaEarlyWarnMinutes = it.hypoglycemiaEarlyWarnMinutes,
780
- showGlucoseMG = it.showGlucoseMG,
781
- glucoseId = it.glucoseId,
782
- name = it.name,
783
- bytes = it.bytes,
784
- showGlucose = it.showGlucose,
785
- Ib = it.ib,
786
- Iw = it.iw,
787
- countdownHours = it.countdownHours,
788
- T = it.t,
789
- year = it.year,
790
- month = it.month,
791
- day = it.day,
792
- hour = it.hour,
793
- minute = it.minute,
794
- trendObject = com.mytatvarnsdk.model.TrendObject(
795
- trendId = it.trend.trendId,
796
- drawableId = it.trend.drawableId,
797
- widgetImg = it.trend.widgetImg,
798
- apsChangeRate = it.trend.apsChangeRate
799
- ),
800
- glucoseStatusObject = com.mytatvarnsdk.model.GlucoseStatusObject(
801
- statusId = it.glucoseStatus.statusId
802
- ),
803
- errorObject = com.mytatvarnsdk.model.ErrorObject(
804
- errorId = it.errorCode.errorId,
805
- sound = it.errorCode.sound
806
- )
807
- )
808
- }
604
+ val uploadSuccessful = uploadBatchSynchronously(json, index)
809
605
 
810
- val allResult = AllCGMLogRequest(
811
- vendor = "GoodFlip",
812
- logs = transformedLogs
813
- )
814
-
815
- val json = Gson().toJson(allResult)
816
- logLongJson("Final JSON=>>> ", json)
817
-
818
- // sendDataToReact(Gson().toJson(batch).toString(), "DATA_FETCH", "CGMData")
819
-
820
- authenticateSDKService.postCGMData(
821
- environment = if ("uat".uppercase() == "PROD") TATVA_ENVIRONMENT.PROD else TATVA_ENVIRONMENT.STAGE,
822
- data = json.toString(),
823
- token = userToken,
824
- responseListener = object : AuthenticateSDKService.ResponseListener {
825
- override fun onResponseSuccess() {
826
- lastSyncedRecord = batch.lastOrNull()
827
-
828
- lastSyncedRecord?.let {
829
- val syncData =
830
- SyncMeta(
831
- Date().time,
832
- it.timeInMillis,
833
- it.deviceId,
834
- it.glucoseId
835
- )
836
- prefsHelper.lastSyncData = syncData
837
- Log.d(
838
- "lastSyncedRecord stored:--- ",
839
- Gson().toJson(syncData).toString()
840
- )
841
- }
842
- }
606
+ if (uploadSuccessful) {
607
+ lastSyncedRecord = batch.lastOrNull()
608
+ // Update sync metadata after each successful batch
609
+ updateSyncMetadata(lastSyncedRecord)
610
+ Log.d("Batch Upload", "✅ Batch $index uploaded and synced successfully")
611
+ } else {
612
+ allBatchesSuccessful = false
613
+ Log.e("Batch Upload", "❌ Batch $index failed")
614
+ // Continue with next batch instead of breaking (optional based on your needs)
615
+ // break
616
+ }
843
617
 
844
- override fun onResponseFail() {
845
- Log.e("Batch Upload", "❌ Batch $index failed")
846
- }
847
- }
848
- )
618
+ // Rate limiting between batches
619
+ delay(500L)
849
620
 
850
- delay(500L)
851
- } catch (e: Exception) {
852
- Log.e("Batch Upload", "❌ Batch $index exception: ${e.message}")
853
- break // Optional: stop further processing if exception occurs
854
- }
855
- }
621
+ } catch (e: Exception) {
622
+ Log.e("Batch Upload", "❌ Batch $index exception: ${e.message}")
623
+ allBatchesSuccessful = false
624
+ // Continue processing other batches
625
+ }
626
+ }
856
627
 
628
+ // Handle error status for the last processed record
629
+ lastSyncedRecord?.let { record ->
630
+ if (record.errorCode != enumError.NONE) {
631
+ handleGlucoseError(record)
632
+ }
633
+ }
857
634
 
858
- if (lastSyncedRecord != null) {
859
- if (lastSyncedRecord?.errorCode != enumError.NONE) {
860
- if (lastSyncedRecord?.errorCode == enumError.ERROR_FLOODING_WATER) {
861
- lastDeviceStatus =
862
- lastSyncedRecord?.deviceId!!.toInt().let { mModel.getDeviceInfo(it) }
863
- lastDeviceStatus?.let {
864
- postEventDataToAPI(
865
- it,
866
- DeviceStatus.MOISTURE_DETECT.id
867
- )
868
- }
869
- resetDebounceTimer()
870
- } else if (lastSyncedRecord?.errorCode == enumError.ERROR_CURRENT_SMALL || lastSyncedRecord?.errorCode == enumError.ERROR_NOISE || lastSyncedRecord?.errorCode == enumError.ERROR_SENSITIVITY_ATTENUATION) {
871
- lastDeviceStatus =
872
- lastSyncedRecord?.deviceId!!.toInt().let { mModel.getDeviceInfo(it) }
873
- lastDeviceStatus?.let {
874
- postEventDataToAPI(
875
- it,
876
- DeviceStatus.WEAK_SIGNAL.id
877
- )
878
- }
879
- resetDebounceTimer()
880
- } else {
881
- lastDeviceStatus =
882
- lastSyncedRecord?.deviceId!!.toInt().let { mModel.getDeviceInfo(it) }
883
- lastDeviceStatus?.let {
884
- postEventDataToAPI(
885
- it,
886
- DeviceStatus.ERROR_COMMON.id
887
- )
888
- }
889
- resetDebounceTimer()
890
- }
891
- }
892
- }
635
+ Log.d(
636
+ "processBatchDataSynchronously",
637
+ "Batch processing completed. Overall success: $allBatchesSuccessful"
638
+ )
639
+ return allBatchesSuccessful
640
+ }
893
641
 
894
- Log.e("Batch Upload", "All data uploaded")
895
642
 
896
- observeGlucoseData(userToken)
643
+ @ReactMethod
644
+ fun stopObservingGlucoseData() {
645
+ try {
646
+ glucoseObserver?.let { observer ->
647
+ Handler(Looper.getMainLooper()).post {
648
+ try {
649
+ mModel.latestGlucose.removeObserver(observer)
650
+ isObserving = false
651
+ Log.d("stopObservingGlucoseData", "Observer removed successfully")
652
+ } catch (e: Exception) {
653
+ Log.e("stopObservingGlucoseData", "Error removing observer: ${e.message}")
654
+ }
897
655
  }
898
- } else {
899
- observeGlucoseData(userToken)
900
656
  }
901
- }*/
902
-
903
- fun logLongJson(tag: String, message: String) {
904
- val maxLogSize = 4000
905
- for (i in 0..message.length / maxLogSize) {
906
- val start = i * maxLogSize
907
- val end = (i + 1) * maxLogSize
908
- if (start < message.length) {
909
- Log.d(tag, message.substring(start, minOf(end, message.length)))
910
- }
911
- }
657
+ glucoseObserver = null
658
+ } catch (e: Exception) {
659
+ Log.e("stopObservingGlucoseData", "Error stopping observer: ${e.message}")
912
660
  }
661
+ }
913
662
 
914
- fun mapToDto(glucose: PocGlucose): GlucoseLog {
915
- val dto: GlucoseLog = GlucoseLog()
916
- dto.timeInMillis = glucose.getTimeInMillis()
917
- dto.countdownMinutes = glucose.getCountdownMinutes()
918
- dto.countdownHours = glucose.getCountdownHours()
919
- dto.countdownDays = glucose.getCountdownDays()
920
- dto.hypoglycemiaEarlyWarnMinutes = glucose.getHypoglycemiaEarlyWarnMinutes()
921
- dto.showGlucoseMG = glucose.getShowGlucoseMG()
922
- dto.glucoseId = glucose.getGlucoseId()
923
- dto.name = glucose.getName()
924
- dto.showGlucose = glucose.getShowGlucose()
925
- dto.Ib = glucose.getIb()
926
- dto.Iw = glucose.getIw()
927
- dto.T = glucose.getT()
928
- dto.year = glucose.getYear()
929
- dto.month = glucose.getMonth()
930
- dto.day = glucose.getDay()
931
- dto.hour = glucose.getHour()
932
- dto.minute = glucose.getMinute()
933
-
934
- // Convert byte[] to List<Integer>
935
- dto.bytes = ArrayList()
936
- for (b in glucose.getBytes()) {
937
- dto.bytes?.add(b.toInt() and 0xFF) // Prevent negative values
938
- }
663
+ // Helper method for synchronous batch upload
664
+ private suspend fun uploadBatchSynchronously(json: String, batchIndex: Int): Boolean {
665
+ return suspendCoroutine { continuation ->
666
+ try {
667
+ authenticateSDKService.postCGMData(
668
+ environment = if ("uat".uppercase() == "PROD") TATVA_ENVIRONMENT.PROD else TATVA_ENVIRONMENT.STAGE,
669
+ data = json,
670
+ token = userToken,
671
+ responseListener = object : AuthenticateSDKService.ResponseListener {
672
+ override fun onResponseSuccess(response: String) {
673
+ continuation.resume(true)
674
+ }
675
+
676
+ override fun onResponseFail() {
677
+ continuation.resume(false)
678
+ }
679
+ }
680
+ )
681
+ } catch (e: Exception) {
682
+ Log.e("uploadBatchSynchronously", "Exception in batch $batchIndex: ${e.message}")
683
+ continuation.resume(false)
684
+ }
685
+ }
686
+ }
939
687
 
940
- // Trend
941
- val trendObj: TrendObject = TrendObject()
942
- trendObj.trendId = glucose.getTrend().getTrendId()
943
- trendObj.drawableId = glucose.getTrend().getDrawableId()
944
- trendObj.widgetImg = glucose.getTrend().getWidgetImg()
945
- trendObj.apsChangeRate = glucose.getTrend().getApsChangeRate()
946
- dto.trendObject = trendObj
947
-
948
- // Status
949
- val statusObj: GlucoseStatusObject = GlucoseStatusObject()
950
- statusObj.statusId = glucose.getGlucoseStatus().getStatusId()
951
- dto.glucoseStatusObject = statusObj
952
-
953
- // Error
954
- val errorObj: ErrorObject = ErrorObject()
955
- errorObj.errorId = glucose.getErrorCode().getErrorId()
956
- errorObj.sound = glucose.getErrorCode().getSound().toString()
957
- dto.errorObject = errorObj
958
-
959
- return dto
688
+ private fun updateSyncMetadata(lastRecord: PocGlucose?) {
689
+ lastRecord?.let {
690
+ try {
691
+ val syncData = SyncMeta(
692
+ Date().time,
693
+ it.timeInMillis,
694
+ it.deviceId,
695
+ it.glucoseId
696
+ )
697
+ prefsHelper.lastSyncData = syncData
698
+ Log.d(
699
+ "Sync Metadata",
700
+ "Sync metadata updated: glucoseId=${it.glucoseId}, time=${it.timeInMillis}"
701
+ )
702
+ } catch (e: Exception) {
703
+ Log.e("updateSyncMetadata", "Error updating sync metadata: ${e.message}")
704
+ }
960
705
  }
706
+ }
961
707
 
962
708
 
963
- @ReactMethod
964
- fun sendDataToReact(data: String, status: String, eventName: String) {
965
- Log.d("sendDataToReact: data ", data)
709
+ fun logLongJson(tag: String, message: String) {
710
+ val maxLogSize = 4000
711
+ for (i in 0..message.length / maxLogSize) {
712
+ val start = i * maxLogSize
713
+ val end = (i + 1) * maxLogSize
714
+ if (start < message.length) {
715
+ Log.d(tag, message.substring(start, minOf(end, message.length)))
716
+ }
717
+ }
718
+ }
719
+
720
+ fun mapToDto(glucose: PocGlucose): GlucoseLog {
721
+ val dto: GlucoseLog = GlucoseLog()
722
+ dto.timeInMillis = glucose.getTimeInMillis()
723
+ dto.countdownMinutes = glucose.getCountdownMinutes()
724
+ dto.countdownHours = glucose.getCountdownHours()
725
+ dto.countdownDays = glucose.getCountdownDays()
726
+ dto.hypoglycemiaEarlyWarnMinutes = glucose.getHypoglycemiaEarlyWarnMinutes()
727
+ dto.showGlucoseMG = glucose.getShowGlucoseMG()
728
+ dto.glucoseId = glucose.getGlucoseId()
729
+ dto.name = glucose.getName()
730
+ dto.showGlucose = glucose.getShowGlucose()
731
+ dto.Ib = glucose.getIb()
732
+ dto.Iw = glucose.getIw()
733
+ dto.T = glucose.getT()
734
+ dto.year = glucose.getYear()
735
+ dto.month = glucose.getMonth()
736
+ dto.day = glucose.getDay()
737
+ dto.hour = glucose.getHour()
738
+ dto.minute = glucose.getMinute()
739
+
740
+ // Convert byte[] to List<Integer>
741
+ dto.bytes = ArrayList()
742
+ for (b in glucose.getBytes()) {
743
+ dto.bytes?.add(b.toInt() and 0xFF) // Prevent negative values
744
+ }
966
745
 
967
- try {
968
- val map: WritableMap = Arguments.createMap().apply {
969
- putString("data", data)
970
- putString("status", status)
971
- }
746
+ // Trend
747
+ val trendObj: TrendObject = TrendObject()
748
+ trendObj.trendId = glucose.getTrend().getTrendId()
749
+ trendObj.drawableId = glucose.getTrend().getDrawableId()
750
+ trendObj.widgetImg = glucose.getTrend().getWidgetImg()
751
+ trendObj.apsChangeRate = glucose.getTrend().getApsChangeRate()
752
+ dto.trendObject = trendObj
753
+
754
+ // Status
755
+ val statusObj: GlucoseStatusObject = GlucoseStatusObject()
756
+ statusObj.statusId = glucose.getGlucoseStatus().getStatusId()
757
+ dto.glucoseStatusObject = statusObj
758
+
759
+ // Error
760
+ val errorObj: ErrorObject = ErrorObject()
761
+ errorObj.errorId = glucose.getErrorCode().getErrorId()
762
+ errorObj.sound = glucose.getErrorCode().getSound().toString()
763
+ dto.errorObject = errorObj
764
+
765
+ return dto
766
+ }
767
+
768
+
769
+ @ReactMethod
770
+ fun sendDataToReact(data: String, status: String, eventName: String) {
771
+ Log.d("sendDataToReact: data ", data)
772
+
773
+ try {
774
+ val map: WritableMap = Arguments.createMap().apply {
775
+ putString("data", data)
776
+ putString("status", status)
777
+ }
972
778
 
973
- Log.d("sendDataToReact: ", map.toString())
779
+ Log.d("sendDataToReact: ", map.toString())
974
780
 
975
- mReactContext?.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
976
- ?.emit(eventName, map)
977
- } catch (e: Exception) {
978
- Log.e("Error sendDataToReact: ", e.message.toString())
979
- e.printStackTrace()
980
- }
781
+ mReactContext?.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
782
+ ?.emit(eventName, map)
783
+ } catch (e: Exception) {
784
+ Log.e("Error sendDataToReact: ", e.message.toString())
785
+ e.printStackTrace()
981
786
  }
787
+ }
982
788
 
983
789
  }
984
790