react-native-mytatva-rn-sdk 1.3.1 → 1.3.2

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.
@@ -34,7 +34,8 @@
34
34
  android:exported="false" />
35
35
  <activity
36
36
  android:name=".activity.ConnectSensorActivity"
37
- android:exported="false" />
37
+ android:exported="false"
38
+ android:windowSoftInputMode="adjustResize" />
38
39
  <activity
39
40
  android:name=".activity.HelpActivity"
40
41
  android:exported="false" />
@@ -120,7 +120,8 @@
120
120
  <activity
121
121
  android:name=".activity.ConnectSensorActivity"
122
122
  android:exported="false"
123
- android:theme="@style/MyTheme" />
123
+ android:theme="@style/MyTheme"
124
+ android:windowSoftInputMode="adjustResize" />
124
125
 
125
126
  <activity
126
127
  android:name=".activity.VideoActivity"
@@ -8,6 +8,8 @@ import android.content.Intent
8
8
  import android.content.pm.PackageManager
9
9
  import android.graphics.Color
10
10
  import android.os.Bundle
11
+ import android.text.Editable
12
+ import android.text.TextWatcher
11
13
  import android.util.Log
12
14
  import android.util.TypedValue
13
15
  import android.view.Gravity
@@ -55,6 +57,7 @@ import kotlinx.coroutines.CoroutineScope
55
57
  import kotlinx.coroutines.Dispatchers
56
58
  import kotlinx.coroutines.SupervisorJob
57
59
  import org.json.JSONObject
60
+ import kotlin.math.max
58
61
 
59
62
 
60
63
  class ConnectSensorActivity : BaseBleActivity() {
@@ -65,6 +68,10 @@ class ConnectSensorActivity : BaseBleActivity() {
65
68
  private var isForReconnect: Boolean = false
66
69
  private val reactContext = CgmTrackyLibModule.mReactContext
67
70
  private var isManualInputVisible: Boolean = false
71
+
72
+ private companion object {
73
+ const val MIN_SENSOR_ID_LENGTH = 5
74
+ }
68
75
  private var suppressUnbindErrorForSensorRebind = false
69
76
 
70
77
  override fun onCreate(savedInstanceState: Bundle?) {
@@ -75,7 +82,16 @@ class ConnectSensorActivity : BaseBleActivity() {
75
82
  enableEdgeToEdge()
76
83
  ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
77
84
  val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
78
- v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
85
+ val ime = insets.getInsets(WindowInsetsCompat.Type.ime())
86
+ v.setPadding(
87
+ systemBars.left,
88
+ systemBars.top,
89
+ systemBars.right,
90
+ max(systemBars.bottom, ime.bottom)
91
+ )
92
+ if (isManualInputVisible && ime.bottom > 0) {
93
+ binding.scrollMain.post { scrollToManualConnectButton() }
94
+ }
79
95
  insets
80
96
  }
81
97
  initialize()
@@ -141,13 +157,74 @@ class ConnectSensorActivity : BaseBleActivity() {
141
157
  binding.clPermission.visibility = View.VISIBLE
142
158
  }
143
159
 
144
- binding.tvEnterIdManually.setOnClickListener {
160
+ binding.clManualEntry.setOnClickListener {
145
161
  toggleManualInput()
146
162
  }
147
163
 
148
164
  binding.btnConnectManual.setOnClickListener {
149
165
  connectSensorManually()
150
166
  }
167
+
168
+ binding.etSensorId.setOnClickListener {
169
+ binding.scrollMain.postDelayed({ scrollToManualConnectButton() }, 100)
170
+ }
171
+
172
+ binding.etSensorId.setOnFocusChangeListener { _, hasFocus ->
173
+ if (hasFocus) {
174
+ binding.scrollMain.postDelayed({ scrollToManualConnectButton() }, 300)
175
+ }
176
+ }
177
+
178
+ binding.etSensorId.addTextChangedListener(object : TextWatcher {
179
+ override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit
180
+ override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) = Unit
181
+ override fun afterTextChanged(s: Editable?) {
182
+ updateManualConnectButtonState()
183
+ }
184
+ })
185
+ updateManualConnectButtonState()
186
+ }
187
+
188
+ private fun updateManualConnectButtonState() {
189
+ val sensorId = binding.etSensorId.text.toString().trim()
190
+ val isValid = sensorId.length >= MIN_SENSOR_ID_LENGTH
191
+ binding.btnConnectManual.isClickable = isValid
192
+ binding.btnConnectManual.isFocusable = isValid
193
+ binding.btnConnectManual.alpha = if (isValid) 1f else 0.5f
194
+ binding.tvManualConnectValidation.visibility = if (isValid) View.GONE else View.VISIBLE
195
+ }
196
+
197
+ private fun dpToPx(dp: Int): Int {
198
+ return TypedValue.applyDimension(
199
+ TypedValue.COMPLEX_UNIT_DIP,
200
+ dp.toFloat(),
201
+ resources.displayMetrics
202
+ ).toInt()
203
+ }
204
+
205
+ private fun scrollToManualConnectButton() {
206
+ if (!isManualInputVisible) {
207
+ return
208
+ }
209
+
210
+ binding.scrollMain.post {
211
+ val scrollView = binding.scrollMain
212
+ val connectButton = binding.btnConnectManual
213
+
214
+ val buttonLocation = IntArray(2)
215
+ connectButton.getLocationOnScreen(buttonLocation)
216
+ val scrollLocation = IntArray(2)
217
+ scrollView.getLocationOnScreen(scrollLocation)
218
+
219
+ val buttonBottom = buttonLocation[1] + connectButton.height
220
+ val scrollVisibleBottom = scrollLocation[1] + scrollView.height
221
+ val extraPadding = dpToPx(24)
222
+
223
+ if (buttonBottom + extraPadding > scrollVisibleBottom) {
224
+ val delta = buttonBottom + extraPadding - scrollVisibleBottom
225
+ scrollView.smoothScrollBy(0, delta)
226
+ }
227
+ }
151
228
  }
152
229
 
153
230
  private fun toggleManualInput() {
@@ -156,12 +233,20 @@ class ConnectSensorActivity : BaseBleActivity() {
156
233
  binding.clPermission.visibility = View.GONE
157
234
  binding.clManualInput.visibility = View.VISIBLE
158
235
  binding.commonButton.root.visibility = View.GONE
159
- binding.tvCantScanQr.text = "Scan the QR."
236
+ binding.tvCantScanQr.visibility = View.GONE
237
+ binding.tvEnterIdManually.layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT
238
+ binding.tvEnterIdManually.gravity = Gravity.CENTER
160
239
  binding.tvEnterIdManually.text = "Scan QR"
240
+ binding.etSensorId.text?.clear()
241
+ updateManualConnectButtonState()
242
+ binding.scrollMain.post { scrollToManualConnectButton() }
161
243
  } else {
162
244
  binding.clManualInput.visibility = View.GONE
163
245
  binding.clPermission.visibility = View.VISIBLE
164
246
  binding.commonButton.root.visibility = View.VISIBLE
247
+ binding.tvCantScanQr.visibility = View.VISIBLE
248
+ binding.tvEnterIdManually.layoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT
249
+ binding.tvEnterIdManually.gravity = Gravity.NO_GRAVITY
165
250
  binding.tvCantScanQr.setText(R.string.txt_cant_scan_sensor_qr)
166
251
  binding.tvEnterIdManually.setText(R.string.txt_enter_id_manually)
167
252
  }
@@ -169,8 +254,8 @@ class ConnectSensorActivity : BaseBleActivity() {
169
254
 
170
255
  private fun connectSensorManually() {
171
256
  val sensorId = binding.etSensorId.text.toString().trim().uppercase()
172
- if (sensorId.isEmpty()) {
173
- Toast.makeText(this, "Please enter Sensor ID", Toast.LENGTH_SHORT).show()
257
+ if (sensorId.length < MIN_SENSOR_ID_LENGTH) {
258
+ Toast.makeText(this, getString(R.string.txt_manual_sensor_id_min_length), Toast.LENGTH_SHORT).show()
174
259
  return
175
260
  }
176
261
 
@@ -118,17 +118,25 @@
118
118
  app:layout_constraintTop_toBottomOf="@+id/llProgress" />
119
119
 
120
120
 
121
- <androidx.constraintlayout.widget.ConstraintLayout
122
- android:id="@+id/clMain"
121
+ <androidx.core.widget.NestedScrollView
122
+ android:id="@+id/connectSensorScroll"
123
123
  android:layout_width="match_parent"
124
124
  android:layout_height="0dp"
125
125
  android:layout_marginTop="16dp"
126
- android:orientation="vertical"
126
+ android:clipToPadding="false"
127
+ android:fillViewport="true"
127
128
  app:layout_constraintBottom_toTopOf="@+id/commonButton"
128
129
  app:layout_constraintEnd_toEndOf="parent"
129
130
  app:layout_constraintStart_toStartOf="parent"
130
131
  app:layout_constraintTop_toBottomOf="@id/divider">
131
132
 
133
+ <androidx.constraintlayout.widget.ConstraintLayout
134
+ android:id="@+id/clMain"
135
+ android:layout_width="match_parent"
136
+ android:layout_height="wrap_content"
137
+ android:orientation="vertical"
138
+ android:paddingBottom="16dp">
139
+
132
140
  <TextView
133
141
  android:id="@+id/tvStep"
134
142
  android:layout_width="wrap_content"
@@ -335,17 +343,31 @@
335
343
  app:layout_constraintStart_toStartOf="parent"
336
344
  app:layout_constraintTop_toTopOf="parent" />
337
345
 
346
+ <TextView
347
+ android:id="@+id/tvManualConnectValidation"
348
+ android:layout_width="0dp"
349
+ android:layout_height="wrap_content"
350
+ android:layout_marginTop="8dp"
351
+ android:fontFamily="@font/roboto_regular"
352
+ android:text="@string/txt_manual_sensor_id_min_length"
353
+ android:textColor="#F5C26B"
354
+ android:textSize="12sp"
355
+ app:layout_constraintEnd_toEndOf="parent"
356
+ app:layout_constraintStart_toStartOf="parent"
357
+ app:layout_constraintTop_toBottomOf="@+id/etSensorId" />
358
+
338
359
  <androidx.cardview.widget.CardView
339
360
  android:id="@+id/btnConnectManual"
340
361
  android:layout_width="0dp"
341
362
  android:layout_height="54dp"
342
- android:layout_marginTop="12dp"
363
+ android:layout_marginTop="8dp"
364
+ android:alpha="0.5"
343
365
  app:cardBackgroundColor="#2A805A"
344
366
  app:cardCornerRadius="12dp"
345
367
  app:cardElevation="0dp"
346
368
  app:layout_constraintEnd_toEndOf="parent"
347
369
  app:layout_constraintStart_toStartOf="parent"
348
- app:layout_constraintTop_toBottomOf="@+id/etSensorId">
370
+ app:layout_constraintTop_toBottomOf="@+id/tvManualConnectValidation">
349
371
 
350
372
  <androidx.constraintlayout.widget.ConstraintLayout
351
373
  android:layout_width="match_parent"
@@ -393,6 +415,8 @@
393
415
  android:layout_height="wrap_content"
394
416
  android:layout_marginTop="12dp"
395
417
  android:background="@drawable/bg_manual_entry_bar"
418
+ android:clickable="true"
419
+ android:focusable="true"
396
420
  android:gravity="center"
397
421
  android:orientation="horizontal"
398
422
  android:paddingHorizontal="16dp"
@@ -402,6 +426,8 @@
402
426
  android:id="@+id/tvCantScanQr"
403
427
  android:layout_width="wrap_content"
404
428
  android:layout_height="wrap_content"
429
+ android:clickable="false"
430
+ android:focusable="false"
405
431
  android:fontFamily="@font/roboto_regular"
406
432
  android:text="@string/txt_cant_scan_sensor_qr"
407
433
  android:textColor="#2D3282"
@@ -412,6 +438,8 @@
412
438
  android:layout_width="wrap_content"
413
439
  android:layout_height="wrap_content"
414
440
  android:layout_marginStart="4dp"
441
+ android:clickable="false"
442
+ android:focusable="false"
415
443
  android:fontFamily="@font/roboto_bold"
416
444
  android:text="@string/txt_enter_id_manually"
417
445
  android:textColor="@color/color_green"
@@ -423,7 +451,9 @@
423
451
 
424
452
  </FrameLayout>
425
453
 
426
- </androidx.constraintlayout.widget.ConstraintLayout>
454
+ </androidx.constraintlayout.widget.ConstraintLayout>
455
+
456
+ </androidx.core.widget.NestedScrollView>
427
457
 
428
458
  <androidx.constraintlayout.widget.ConstraintLayout
429
459
  android:id="@+id/clFail"
@@ -199,6 +199,7 @@
199
199
  <string name="verification_fail">verification failed</string>
200
200
  <string name="txt_provide_camera_permisison"><u>Provide Camera Permissions</u></string>
201
201
  <string name="txt_cant_scan_sensor_qr">Can\'t scan the sensor QR?</string>
202
+ <string name="txt_manual_sensor_id_min_length">Enter at least 5 characters to enable Connect.</string>
202
203
  <string name="txt_enter_id_manually"><u>Enter ID Manually</u></string>
203
204
  <string name="txt_know_more"><u>Know More</u></string>
204
205
  <string name="txt_open_setting"><u>Open System Settings</u></string>
@@ -22,6 +22,8 @@ class CustomOverlayButton: UIView {
22
22
 
23
23
  private var textLabelCenterXConstraint: NSLayoutConstraint!
24
24
  private var rightImageWidthConstraint: NSLayoutConstraint!
25
+ private var foregroundBottomConstraint: NSLayoutConstraint!
26
+ private let pressDepth: CGFloat = 12
25
27
 
26
28
  // MARK: - Button Callback
27
29
  var buttonTapCallback: (() -> Void)?
@@ -103,6 +105,12 @@ class CustomOverlayButton: UIView {
103
105
  overlayButton.translatesAutoresizingMaskIntoConstraints = false
104
106
  overlayButton.setTitle("", for: .normal)
105
107
  overlayButton.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
108
+ overlayButton.addTarget(self, action: #selector(buttonTouchDown), for: .touchDown)
109
+ overlayButton.addTarget(
110
+ self,
111
+ action: #selector(buttonTouchUp),
112
+ for: [.touchUpInside, .touchUpOutside, .touchCancel]
113
+ )
106
114
  addSubview(overlayButton)
107
115
 
108
116
  // Disable View
@@ -118,6 +126,10 @@ class CustomOverlayButton: UIView {
118
126
  private func setupConstraints() {
119
127
  textLabelCenterXConstraint = textLabel.centerXAnchor.constraint(equalTo: centerXAnchor, constant: -12)
120
128
  rightImageWidthConstraint = rightImageView.widthAnchor.constraint(equalToConstant: 24)
129
+ foregroundBottomConstraint = foregroundView.bottomAnchor.constraint(
130
+ equalTo: bottomAnchor,
131
+ constant: -pressDepth
132
+ )
121
133
 
122
134
  NSLayoutConstraint.activate([
123
135
  // disableView
@@ -136,7 +148,7 @@ class CustomOverlayButton: UIView {
136
148
  foregroundView.topAnchor.constraint(equalTo: topAnchor, constant: 0),
137
149
  foregroundView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 0),
138
150
  foregroundView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: 0),
139
- foregroundView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -12),
151
+ foregroundBottomConstraint,
140
152
 
141
153
  // Label on the left
142
154
  textLabelCenterXConstraint,
@@ -203,10 +215,40 @@ class CustomOverlayButton: UIView {
203
215
 
204
216
  func disable() {
205
217
  disableView.isHidden = false
218
+ overlayButton.isEnabled = false
219
+ setPressed(false, animated: false)
206
220
  }
207
221
 
208
222
  func enable() {
209
223
  disableView.isHidden = true
224
+ overlayButton.isEnabled = true
225
+ }
226
+
227
+ private var isInteractionEnabled: Bool {
228
+ disableView.isHidden && overlayButton.isEnabled
229
+ }
230
+
231
+ private func setPressed(_ pressed: Bool, animated: Bool) {
232
+ foregroundBottomConstraint.constant = pressed ? 0 : -pressDepth
233
+ let animations = {
234
+ self.foregroundView.alpha = pressed ? 0.9 : 1.0
235
+ self.layoutIfNeeded()
236
+ }
237
+ if animated {
238
+ UIView.animate(withDuration: 0.12, delay: 0, options: [.curveEaseOut, .allowUserInteraction], animations: animations)
239
+ } else {
240
+ animations()
241
+ }
242
+ }
243
+
244
+ @objc private func buttonTouchDown() {
245
+ guard isInteractionEnabled else { return }
246
+ setPressed(true, animated: true)
247
+ }
248
+
249
+ @objc private func buttonTouchUp() {
250
+ guard isInteractionEnabled else { return }
251
+ setPressed(false, animated: true)
210
252
  }
211
253
 
212
254
  func setBorderOnly() {
@@ -232,6 +274,8 @@ class CustomOverlayButton: UIView {
232
274
  }
233
275
 
234
276
  @objc private func buttonTapped() {
277
+ guard isInteractionEnabled else { return }
278
+ UIImpactFeedbackGenerator(style: .light).impactOccurred()
235
279
  buttonTapCallback?()
236
280
  }
237
281
  }
@@ -17,12 +17,13 @@ class ConnectDeviceTVC: UITableViewCell {
17
17
 
18
18
  override func awakeFromNib() {
19
19
  super.awakeFromNib()
20
- // Initialization code
20
+ selectionStyle = .none
21
21
 
22
22
  transmitterImageView.image = loadImage(named: "transmitter_image")
23
23
 
24
24
  button.labelText = "Connect"
25
25
  button.hideRightArrow()
26
+ button.enable()
26
27
 
27
28
  labelTitle.textColor = CustomColor.shared.darkTextGreen
28
29
  labelDesc.textColor = CustomColor.shared.darkTextGreen
@@ -39,5 +40,11 @@ class ConnectDeviceTVC: UITableViewCell {
39
40
 
40
41
  // Configure the view for the selected state
41
42
  }
43
+
44
+ override func prepareForReuse() {
45
+ super.prepareForReuse()
46
+ button.buttonTapCallback = nil
47
+ button.enable()
48
+ }
42
49
 
43
50
  }
@@ -10,6 +10,8 @@ import AVFoundation
10
10
 
11
11
  class ImageTVC: UITableViewCell {
12
12
 
13
+ private static let minSensorIdLength = 5
14
+
13
15
  @IBOutlet weak var bottomConstraint: NSLayoutConstraint!
14
16
  @IBOutlet weak var displayImageView: UIImageView!
15
17
  @IBOutlet weak var topConstraint: NSLayoutConstraint!
@@ -27,6 +29,8 @@ class ImageTVC: UITableViewCell {
27
29
 
28
30
  private var manualEntryView: UIView?
29
31
  private var sensorIdTextField: UITextField?
32
+ private var connectButton: UIButton?
33
+ private var validationHintLabel: UILabel?
30
34
  private var isManualEntryVisible = false
31
35
 
32
36
  var activeSensorIdTextField: UITextField? {
@@ -66,6 +70,7 @@ class ImageTVC: UITableViewCell {
66
70
  manualEntryView?.isHidden = true
67
71
  sensorIdTextField?.text = nil
68
72
  isManualEntryVisible = false
73
+ updateConnectButtonState()
69
74
  }
70
75
 
71
76
  // MARK: - Manual Entry UI Setup
@@ -95,8 +100,17 @@ class ImageTVC: UITableViewCell {
95
100
  textField.leftViewMode = .always
96
101
  textField.rightView = UIView(frame: CGRect(x: 0, y: 0, width: 14, height: 1))
97
102
  textField.rightViewMode = .always
103
+ textField.addTarget(self, action: #selector(sensorIdTextChanged), for: .editingChanged)
98
104
  container.addSubview(textField)
99
105
 
106
+ let validationLabel = UILabel()
107
+ validationLabel.translatesAutoresizingMaskIntoConstraints = false
108
+ validationLabel.text = "Enter at least 5 characters to enable Connect."
109
+ validationLabel.font = FontManager.font(ofSize: 12, weight: .regular)
110
+ validationLabel.textColor = UIColor(red: 255/255, green: 200/255, blue: 120/255, alpha: 1)
111
+ validationLabel.numberOfLines = 0
112
+ container.addSubview(validationLabel)
113
+
100
114
  let connectButton = UIButton(type: .custom)
101
115
  connectButton.translatesAutoresizingMaskIntoConstraints = false
102
116
  connectButton.setTitle("Connect", for: .normal)
@@ -122,7 +136,11 @@ class ImageTVC: UITableViewCell {
122
136
  textField.trailingAnchor.constraint(equalTo: container.trailingAnchor, constant: -16),
123
137
  textField.heightAnchor.constraint(equalToConstant: 48),
124
138
 
125
- connectButton.topAnchor.constraint(equalTo: textField.bottomAnchor, constant: 12),
139
+ validationLabel.topAnchor.constraint(equalTo: textField.bottomAnchor, constant: 8),
140
+ validationLabel.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 16),
141
+ validationLabel.trailingAnchor.constraint(equalTo: container.trailingAnchor, constant: -16),
142
+
143
+ connectButton.topAnchor.constraint(equalTo: validationLabel.bottomAnchor, constant: 8),
126
144
  connectButton.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 16),
127
145
  connectButton.trailingAnchor.constraint(equalTo: container.trailingAnchor, constant: -16),
128
146
  connectButton.heightAnchor.constraint(equalToConstant: 52),
@@ -140,6 +158,21 @@ class ImageTVC: UITableViewCell {
140
158
 
141
159
  manualEntryView = container
142
160
  sensorIdTextField = textField
161
+ self.connectButton = connectButton
162
+ validationHintLabel = validationLabel
163
+ updateConnectButtonState()
164
+ }
165
+
166
+ private func updateConnectButtonState() {
167
+ let text = (sensorIdTextField?.text ?? "").trimmingCharacters(in: .whitespaces)
168
+ let isValid = text.count >= Self.minSensorIdLength
169
+ connectButton?.isEnabled = isValid
170
+ connectButton?.alpha = isValid ? 1.0 : 0.5
171
+ validationHintLabel?.isHidden = isValid
172
+ }
173
+
174
+ @objc private func sensorIdTextChanged() {
175
+ updateConnectButtonState()
143
176
  }
144
177
 
145
178
  // MARK: - Public API
@@ -157,11 +190,13 @@ class ImageTVC: UITableViewCell {
157
190
  cameraView.isHidden = true
158
191
  manualEntryView?.isHidden = false
159
192
  scannerView?.stopScanning()
193
+ updateConnectButtonState()
160
194
  } else {
161
195
  cameraView.isHidden = false
162
196
  manualEntryView?.isHidden = true
163
197
  sensorIdTextField?.text = nil
164
198
  sensorIdTextField?.resignFirstResponder()
199
+ updateConnectButtonState()
165
200
  }
166
201
  }
167
202
 
@@ -179,6 +214,7 @@ class ImageTVC: UITableViewCell {
179
214
  @objc private func connectButtonTapped() {
180
215
  sensorIdTextField?.resignFirstResponder()
181
216
  let sensorId = (sensorIdTextField?.text ?? "").trimmingCharacters(in: .whitespaces).uppercased()
217
+ guard sensorId.count >= Self.minSensorIdLength else { return }
182
218
  onConnectTapped?(sensorId)
183
219
  }
184
220
  }
@@ -88,7 +88,8 @@ class ConnectToSensorViewController: UIViewController {
88
88
 
89
89
  tableView.delegate = self
90
90
  tableView.dataSource = self
91
- tableView.keyboardDismissMode = .interactive
91
+ tableView.keyboardDismissMode = .onDrag
92
+ setupDismissKeyboardGesture()
92
93
  tableView.registerNibs([VerticalLabelsTVC.self,
93
94
  SeparatorTVC.self,
94
95
  ImageTVC.self,
@@ -424,6 +425,36 @@ class ConnectToSensorViewController: UIViewController {
424
425
  let fieldRect = textField.convert(textField.bounds, to: tableView)
425
426
  tableView.scrollRectToVisible(fieldRect.insetBy(dx: 0, dy: -12), animated: animated)
426
427
  }
428
+
429
+ private func setupDismissKeyboardGesture() {
430
+ let tap = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboardOnTap))
431
+ tap.cancelsTouchesInView = false
432
+ tap.delegate = self
433
+ view.addGestureRecognizer(tap)
434
+ }
435
+
436
+ @objc private func dismissKeyboardOnTap() {
437
+ guard isManualEntryMode else { return }
438
+ view.endEditing(true)
439
+ }
440
+
441
+ private func isTouchInsideSensorIdTextField(_ touch: UITouch) -> Bool {
442
+ guard isManualEntryMode,
443
+ let cell = tableView.cellForRow(at: manualEntryIndexPath) as? ImageTVC,
444
+ let textField = cell.activeSensorIdTextField,
445
+ let touchedView = touch.view else {
446
+ return false
447
+ }
448
+
449
+ var view: UIView? = touchedView
450
+ while let current = view {
451
+ if current === textField {
452
+ return true
453
+ }
454
+ view = current.superview
455
+ }
456
+ return false
457
+ }
427
458
 
428
459
  private func showSensorInvalidAlert(message: String) {
429
460
  DispatchQueue.main.async {
@@ -546,6 +577,13 @@ class ConnectToSensorViewController: UIViewController {
546
577
 
547
578
  }
548
579
 
580
+ extension ConnectToSensorViewController: UIGestureRecognizerDelegate {
581
+ func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
582
+ guard isManualEntryMode else { return false }
583
+ return !isTouchInsideSensorIdTextField(touch)
584
+ }
585
+ }
586
+
549
587
  extension ConnectToSensorViewController: UITableViewDelegate, UITableViewDataSource {
550
588
 
551
589
  func numberOfSections(in tableView: UITableView) -> Int {
@@ -622,10 +660,10 @@ extension ConnectToSensorViewController: UITableViewDelegate, UITableViewDataSou
622
660
  }
623
661
  cell.onConnectTapped = { [weak self] sensorId in
624
662
  guard let self = self else { return }
625
- guard !sensorId.isEmpty else {
663
+ guard sensorId.count >= 5 else {
626
664
  let alert = UIAlertController(
627
665
  title: nil,
628
- message: "Please enter a Sensor ID",
666
+ message: "Enter at least 5 characters to connect.",
629
667
  preferredStyle: .alert
630
668
  )
631
669
  alert.addAction(UIAlertAction(title: "OK", style: .default))
@@ -659,13 +697,7 @@ extension ConnectToSensorViewController: UITableViewDelegate, UITableViewDataSou
659
697
  bar.layer.borderWidth = 1
660
698
  bar.layer.borderColor = UIColor(red: 220/255, green: 225/255, blue: 245/255, alpha: 1).cgColor
661
699
 
662
- let prefixText = isManualEntryMode ? "Scan the QR." : "Can't scan the sensor QR?"
663
- let linkText = isManualEntryMode ? " Scan QR" : " Enter ID Manually"
664
-
665
- let prefixLabel = UILabel()
666
- prefixLabel.text = prefixText
667
- prefixLabel.font = FontManager.font(ofSize: 14, weight: .regular)
668
- prefixLabel.textColor = UIColor(red: 45/255, green: 50/255, blue: 130/255, alpha: 1)
700
+ let linkText = isManualEntryMode ? "Scan QR" : " Enter ID Manually"
669
701
 
670
702
  let linkLabel = UILabel()
671
703
  let attr = NSMutableAttributedString(string: linkText, attributes: [
@@ -675,7 +707,16 @@ extension ConnectToSensorViewController: UITableViewDelegate, UITableViewDataSou
675
707
  ])
676
708
  linkLabel.attributedText = attr
677
709
 
678
- let stack = UIStackView(arrangedSubviews: [prefixLabel, linkLabel])
710
+ let stack: UIStackView
711
+ if isManualEntryMode {
712
+ stack = UIStackView(arrangedSubviews: [linkLabel])
713
+ } else {
714
+ let prefixLabel = UILabel()
715
+ prefixLabel.text = "Can't scan the sensor QR?"
716
+ prefixLabel.font = FontManager.font(ofSize: 14, weight: .regular)
717
+ prefixLabel.textColor = UIColor(red: 45/255, green: 50/255, blue: 130/255, alpha: 1)
718
+ stack = UIStackView(arrangedSubviews: [prefixLabel, linkLabel])
719
+ }
679
720
  stack.translatesAutoresizingMaskIntoConstraints = false
680
721
  stack.axis = .horizontal
681
722
  stack.alignment = .center
@@ -57,6 +57,7 @@ class ConnectToTransmitterViewController: UIViewController, KLTBluetoothDelegate
57
57
  var foundDevices: NSMutableArray = []
58
58
  let manager = KLTBluetoothManager.shared()
59
59
  private var bluetoothEnableObserver: NSObjectProtocol?
60
+ private var isConnectingTransmitter = false
60
61
 
61
62
  override func viewDidLoad() {
62
63
  super.viewDidLoad()
@@ -328,6 +329,88 @@ class ConnectToTransmitterViewController: UIViewController, KLTBluetoothDelegate
328
329
  }
329
330
  }
330
331
  }
332
+
333
+ private func showTransmitterConnectError(message: String, errorCode: String? = nil) {
334
+ DispatchQueue.main.async {
335
+ let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert)
336
+ alert.addAction(UIAlertAction(title: "OK", style: .default))
337
+ self.present(alert, animated: true)
338
+ }
339
+
340
+ if let errorCode {
341
+ let errorPayload: [String: String] = [
342
+ "status": "cgm_transmitter_detection_failed",
343
+ "error_description": message,
344
+ "error_code": errorCode,
345
+ ]
346
+ NotificationCenter.default.post(
347
+ name: Notification.Name("cgmtransmitterdetectionfailed"),
348
+ object: nil,
349
+ userInfo: errorPayload
350
+ )
351
+ }
352
+ }
353
+
354
+ private func connectToTransmitter(at row: Int) {
355
+ guard !isConnectingTransmitter else { return }
356
+ guard row >= 0, row < foundDevices.count else {
357
+ showTransmitterConnectError(
358
+ message: "Transmitter not found. Please remove it from the charging pod and try again.",
359
+ errorCode: "BT_DEVICE_INDEX_INVALID"
360
+ )
361
+ return
362
+ }
363
+
364
+ guard let peripheral = foundDevices[row] as? CBPeripheral else {
365
+ showTransmitterConnectError(
366
+ message: "Unable to read transmitter details. Please try again.",
367
+ errorCode: "BT_DEVICE_INVALID"
368
+ )
369
+ return
370
+ }
371
+
372
+ if isForReconnect {
373
+ sensorForceEnd()
374
+ }
375
+
376
+ if !isForReconnect && !KLTLocalSettingManager.shareInstance().canConnectOtherDevice {
377
+ showTransmitterConnectError(
378
+ message: "A transmitter is already connected. Please finish or disconnect the current session before connecting another transmitter.",
379
+ errorCode: "BT_ALREADY_CONNECTED"
380
+ )
381
+ return
382
+ }
383
+
384
+ isConnectingTransmitter = true
385
+ manager?.stopScan()
386
+
387
+ guard let device = KLTDatabaseHandler.shared().queryDevice(withId: peripheral.identifier.uuidString) else {
388
+ isConnectingTransmitter = false
389
+ showTransmitterConnectError(
390
+ message: "Unable to read transmitter details. Please remove it from the charging pod and try again.",
391
+ errorCode: "BT_DEVICE_NOT_IN_DB"
392
+ )
393
+ return
394
+ }
395
+
396
+ let payload = [
397
+ "status": "cgm_transmitter_connection_successful",
398
+ ]
399
+
400
+ NotificationCenter.default.post(
401
+ name: Notification.Name("cgmtransmitterconnectionsuccessful"),
402
+ object: nil,
403
+ userInfo: payload
404
+ )
405
+
406
+ connectedTime = Date()
407
+ print("Connected device", device)
408
+ manager?.readyToConnectedPeripheral = peripheral
409
+ screenType = .success
410
+ bottomButton.enable()
411
+ isConnectingTransmitter = false
412
+ tableView.reloadData()
413
+ }
331
414
  }
332
415
 
333
416
  extension ConnectToTransmitterViewController: UITableViewDelegate, UITableViewDataSource {
@@ -413,6 +496,7 @@ extension ConnectToTransmitterViewController: UITableViewDelegate, UITableViewDa
413
496
  case .listOfDevice:
414
497
  let cell: ConnectDeviceTVC = tableView.dequeueReusableCell(for: indexPath)
415
498
  cell.button.hideRightArrow()
499
+ cell.button.enable()
416
500
 
417
501
 
418
502
  let peripheral = foundDevices[indexPath.row] as! CBPeripheral
@@ -420,52 +504,9 @@ extension ConnectToTransmitterViewController: UITableViewDelegate, UITableViewDa
420
504
  let name = device?.advertise?.localName?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
421
505
  cell.labelDesc.text = name.isEmpty ? "Unknown" : name
422
506
 
423
- //cell.labelDesc.text = "Sno:\(devices[indexPath.row].name)"
424
- cell.button.buttonTapCallback = {
425
-
426
- if self.isForReconnect {
427
- self.sensorForceEnd()
428
- }
429
-
430
- if !KLTLocalSettingManager.shareInstance().canConnectOtherDevice {
431
- return
432
- }
433
-
434
- self.manager?.stopScan()
435
- if self.foundDevices.count > indexPath.row {
436
- let peripheral = self.foundDevices[indexPath.row] as! CBPeripheral
437
- if let device = KLTDatabaseHandler.shared().queryDevice(withId: peripheral.identifier.uuidString) {
438
- let payload = [
439
- "status": "cgm_transmitter_connection_successful",
440
- ]
441
-
442
- NotificationCenter.default.post(
443
- name: Notification.Name("cgmtransmitterconnectionsuccessful"),
444
- object: nil,
445
- userInfo: payload
446
- )
447
-
448
- //let snLocalName = device.advertise?.localName?.trimmingCharacters(in: .whitespacesAndNewlines)
449
- self.connectedTime = Date()
450
- print("Connected device", device)
451
- self.manager?.readyToConnectedPeripheral = peripheral
452
- self.screenType = .success
453
- //API.shared.sendStatus(status: .connected)
454
- self.bottomButton.enable()
455
- tableView.reloadData()
456
- } else {
457
- let errorPayload = [
458
- "status": "cgm_transmitter_detection_failed",
459
- "error_description": "Device not found in database",
460
- "error_code": "BT_DEVICE_NOT_IN_DB"
461
- ]
462
- NotificationCenter.default.post(
463
- name: Notification.Name("cgmtransmitterdetectionfailed"),
464
- object: nil,
465
- userInfo: errorPayload
466
- )
467
- }
468
- }
507
+ let row = indexPath.row
508
+ cell.button.buttonTapCallback = { [weak self] in
509
+ self?.connectToTransmitter(at: row)
469
510
  }
470
511
  return cell
471
512
  case .success:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-mytatva-rn-sdk",
3
- "version": "1.3.1",
3
+ "version": "1.3.2",
4
4
  "description": "a package to inject data into visit health pwa",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",