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.
- package/android/src/main/AndroidManifest.xml +2 -1
- package/android/src/main/AndroidManifestNew.xml +2 -1
- package/android/src/main/java/com/mytatvarnsdk/activity/ConnectSensorActivity.kt +90 -5
- package/android/src/main/res/layout/activity_connect_sensor.xml +36 -6
- package/android/src/main/res/values/strings.xml +1 -0
- package/ios/Custom/CustomOverlayButton.swift +45 -1
- package/ios/TableViewCell/ConnectDeviceTVC/ConnectDeviceTVC.swift +8 -1
- package/ios/TableViewCell/ImageTVC/ImageTVC.swift +37 -1
- package/ios/ViewControllers/ConnectToSensorViewController.swift +52 -11
- package/ios/ViewControllers/ConnectToTransmitterViewController.swift +87 -46
- package/package.json +1 -1
|
@@ -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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
173
|
-
Toast.makeText(this,
|
|
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.
|
|
122
|
-
android:id="@+id/
|
|
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:
|
|
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="
|
|
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/
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 = .
|
|
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
|
|
663
|
+
guard sensorId.count >= 5 else {
|
|
626
664
|
let alert = UIAlertController(
|
|
627
665
|
title: nil,
|
|
628
|
-
message: "
|
|
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
|
|
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
|
|
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
|
-
|
|
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:
|