Clinical UI: BLE Connecting 상태 + Notes IME Done + 6채널 그래프 키움

3건 동시 적용:

1. ClinicalHome 'BLE Connecting…' 상태 표시
   증상: Unpair 후 새 기기 페어링 시 처음 3~5초간 'BLE Not Connected' 표시.
   원인: connectGatt 호출부터 STATE_CONNECTED까지 시간 걸리는데 그 사이 isConnected==false.
   기존 isReconnecting state는 reconnect 경로 전용이라 새 페어링엔 안 잡힘.
   수정:
   - BleManager.isConnecting state 신규 추가 (mutableStateOf)
   - connectGatt 호출 직전 true, STATE_CONNECTED/DISCONNECTED 시 false
   - 예외 catch에서도 false (실패 시 stuck 방지)
   - ClinicalHome에서 isConnected==false && (isConnecting || isReconnecting)일 때
     CircularProgressIndicator + 'BLE Connecting…' 텍스트 표시

2. ClinicalHome Notes 필드 IME Done
   기존: 여러 줄 입력 가능했지만 키보드 ✓ 버튼이 없어 닫기 어려움.
   수정: singleLine=true + imeAction=Done + onDone=hide keyboard
   Examiner 필드와 동일한 동작.

3. ClinicalLive 6채널 그래프 키움 (2x3 grid 유지)
   회의 결정: layout 그대로, 셀 크기/폰트/선 굵기 모두 키움.
   - Card height: 120dp → 240dp (2배)
   - Card padding: 4dp → 8dp / corner: 6 → 8
   - 색 box: 8dp → 12dp
   - CH label: 10sp → 16sp
   - ant/post label: 9sp → 14sp
   - peak label: 9sp → 14sp + SemiBold
   - waveform stroke: 1.5 → 2.5
   - ant/post 마커 stroke: 1.5 → 2.5

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-09 14:33:37 +09:00
parent d2e7640292
commit 5703355fc4
3 changed files with 49 additions and 18 deletions
@@ -88,6 +88,9 @@ class BleManager private constructor(private val context: Context) {
@android.annotation.SuppressLint("MissingPermission")
get() = bluetoothGatt?.device?.bondState == android.bluetooth.BluetoothDevice.BOND_BONDED
val isReconnecting = mutableStateOf(false)
/** 새 페어링/재연결 진행 중 (connectGatt 호출 ~ STATE_CONNECTED 또는 실패까지).
* ClinicalHome 등에서 "BLE Connecting…" 표시용. */
val isConnecting = mutableStateOf(false)
val connectionError = mutableStateOf<String?>(null)
// Callbacks
@@ -206,12 +209,14 @@ class BleManager private constructor(private val context: Context) {
if (idx >= 0) discoveredDevices[idx] = discoveredDevices[idx].copy(isConnecting = true)
connectionError.value = null
isConnecting.value = true
try {
bluetoothGatt = bleDevice.device.connectGatt(context, false, gattCallback, BluetoothDevice.TRANSPORT_LE)
logd { "connectGatt called, gatt=${bluetoothGatt != null}" }
} catch (e: Exception) {
loge { "connectGatt failed: ${e.message}" }
isConnecting.value = false
handler.post {
connectionError.value = "Connection failed: ${e.message}"
if (idx >= 0) discoveredDevices[idx] = discoveredDevices[idx].copy(isConnecting = false)
@@ -786,6 +791,7 @@ class BleManager private constructor(private val context: Context) {
BluetoothProfile.STATE_CONNECTED -> {
logd { "Connected to ${gatt.device.address}" }
isReconnecting.value = false
isConnecting.value = false
isUserDisconnect = false
connectionError.value = null
val idx = discoveredDevices.indexOfFirst { it.address == gatt.device.address }
@@ -819,6 +825,7 @@ class BleManager private constructor(private val context: Context) {
}
BluetoothProfile.STATE_DISCONNECTED -> {
logd { "Disconnected from ${gatt.device.address}" }
isConnecting.value = false
stopBatteryPolling()
bluetoothGatt = null
txCharacteristic = null