fix(clinical): 병원 임상 모드에서 기기 연결로 갈 길이 없었다

"기기를 먼저 연결해 주세요" 라고 안내만 하고 정작 가는 길이 없었다. 연결이 이 모드의
첫 단계인데, 조작자는 홈까지 되돌아가 일반 흐름을 타고 다시 들어와야 했다.

## 복귀처를 불리언이 아니라 값으로
기기 연결 화면은 여러 곳에서 불려 온다. 원래는 `ClinicalSessionStore.inClinicalFlow`
불리언 하나로 "임상 흐름이면 CLINICAL_HOME, 아니면 HOME" 만 갈랐다. 여기에 병원 모드용
불리언을 하나 더 만들면 그 순간부터 두 깃발이 어긋나기 시작한다.

그래서 `AppState.connectReturnScreen` 에 **어디로 돌아갈지를 값으로** 담는다. null 이면
기존 규칙 그대로라 **기존 호출부는 하나도 건드리지 않았다.** 한 번 쓰면 비운다
(consumeConnectReturn) — 안 비우면 다음에 다른 경로로 들어온 연결 화면까지 엉뚱한
곳으로 보낸다.

## 나가는 길이 셋이라 셋 다 손봤다
  · 연결 성공        AppState.deviceConnected()
  · 시스템 뒤로가기   MainActivity BackHandler
  · 화면 안 화살표    AppState.backToSensorSelect()

세 번째에서 기존 문제도 드러났다 — 화면 안 화살표는 `inClinicalFlow` 를 보지 않고 늘
HOME 으로 간다. 시스템 뒤로가기와 목적지가 다르다. 기존부터 그랬고 지금 고치면 임상
흐름의 동작이 바뀌므로 그대로 두고 주석으로 남겼다. 복귀처를 지정한 화면만 두 경로가
같아진다.

## 검증 (실기기 23021RAA2Y)
홈 3연타 → 개발자 모드 → [병원 임상 측정] → [기기 연결] → 검색 화면 →
시스템 뒤로가기 / 화면 안 화살표 **둘 다** 병원 임상 화면으로 복귀. 크래시 0건.
연결 성공 경로는 프로브가 없어 아직 확인 못 했다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-02 17:29:06 +09:00
parent c5dd0fdc3e
commit fba3ef8626
3 changed files with 52 additions and 5 deletions
@@ -23,6 +23,26 @@ enum class AppScreen {
class AppState(private val context: Context) { class AppState(private val context: Context) {
var currentScreen by mutableStateOf(AppScreen.ONBOARDING) var currentScreen by mutableStateOf(AppScreen.ONBOARDING)
/**
* DEVICE_SCAN 을 끝내고(연결 성공이든 뒤로가기든) 돌아갈 화면.
*
* 기기 연결 화면은 여러 곳에서 불려 오는데, 원래는 `ClinicalSessionStore.inClinicalFlow`
* 불리언 하나로 "임상 흐름이면 CLINICAL_HOME, 아니면 HOME" 만 갈랐다. 부르는 곳이
* 셋 이상이 되면 불리언을 더 만들게 되고, 그 순간부터 두 깃발이 어긋나기 시작한다.
*
* 그래서 **어디로 돌아갈지를 값으로** 들고 있는다. null 이면 기존 규칙대로 간다 —
* 기존 호출부는 하나도 건드리지 않았다.
*
* 한 번 쓰면 비운다([consumeConnectReturn]). 안 비우면 다음에 다른 경로로 들어온
* 연결 화면까지 엉뚱한 곳으로 보낸다.
*/
var connectReturnScreen: AppScreen? = null
/** 복귀 화면을 꺼내며 지운다. 없으면 null. */
fun consumeConnectReturn(): AppScreen? =
connectReturnScreen.also { connectReturnScreen = null }
var user by mutableStateOf(User()) var user by mutableStateOf(User())
var sensorMode by mutableStateOf(SensorMode.PIEZO) var sensorMode by mutableStateOf(SensorMode.PIEZO)
var bladderLevel by mutableStateOf(BladderLevel()) var bladderLevel by mutableStateOf(BladderLevel())
@@ -121,12 +141,24 @@ class AppState(private val context: Context) {
currentScreen = AppScreen.DEVICE_SCAN currentScreen = AppScreen.DEVICE_SCAN
} }
/**
* 기기 연결 화면의 **화면 안 뒤로 화살표**.
*
* ⚠ 시스템 뒤로가기(MainActivity BackHandler)와 목적지가 다르다 — 그쪽은
* `inClinicalFlow` 를 보고 CLINICAL_HOME 으로 가는데 여기는 늘 HOME 이다.
* 기존부터 그랬고 지금 손대면 임상 흐름의 동작이 바뀌므로 그대로 둔다.
* 다만 복귀처를 지정한 화면([connectReturnScreen])은 두 경로가 같아야 하므로
* 여기서도 먼저 확인한다.
*/
fun backToSensorSelect() { fun backToSensorSelect() {
consumeConnectReturn()?.let { currentScreen = it; return }
currentScreen = AppScreen.HOME currentScreen = AppScreen.HOME
} }
fun deviceConnected() { fun deviceConnected() {
isDeviceConnected = true isDeviceConnected = true
// 부른 화면이 복귀처를 지정했으면 그리로 (병원 임상 모드 등).
consumeConnectReturn()?.let { currentScreen = it; return }
// 임상 모드에서 BLE 연결 시 ClinicalHome으로 복귀 (Personalization 우회) // 임상 모드에서 BLE 연결 시 ClinicalHome으로 복귀 (Personalization 우회)
if (com.medithings.vesiscan.services.ClinicalSessionStore.inClinicalFlow) { if (com.medithings.vesiscan.services.ClinicalSessionStore.inClinicalFlow) {
currentScreen = AppScreen.CLINICAL_HOME currentScreen = AppScreen.CLINICAL_HOME
@@ -147,9 +147,11 @@ fun MedilightApp(modifier: Modifier = Modifier) {
// DeviceScan Back: 임상 흐름이면 ClinicalHome으로, 아니면 HOME // DeviceScan Back: 임상 흐름이면 ClinicalHome으로, 아니면 HOME
AppScreen.DEVICE_SCAN -> AppScreen.DEVICE_SCAN ->
appState.currentScreen = appState.currentScreen =
if (com.medithings.vesiscan.services.ClinicalSessionStore.inClinicalFlow) // 부른 화면이 복귀처를 지정했으면 그리로 (병원 임상 모드 등).
AppScreen.CLINICAL_HOME appState.consumeConnectReturn()
else AppScreen.HOME ?: if (com.medithings.vesiscan.services.ClinicalSessionStore.inClinicalFlow)
AppScreen.CLINICAL_HOME
else AppScreen.HOME
AppScreen.PIEZO_PERSONALIZATION -> appState.currentScreen = AppScreen.DEVICE_SCAN AppScreen.PIEZO_PERSONALIZATION -> appState.currentScreen = AppScreen.DEVICE_SCAN
// 임상 모드 측정 중이면 endMeasurement → ClinicalHome 복귀 // 임상 모드 측정 중이면 endMeasurement → ClinicalHome 복귀
AppScreen.PLACEMENT_GUIDE -> AppScreen.PLACEMENT_GUIDE ->
@@ -223,7 +223,20 @@ fun HospitalModeView(appState: AppState) {
Column(Modifier.padding(horizontal = 16.dp)) { Column(Modifier.padding(horizontal = 16.dp)) {
StatusRow(isConnected, deviceName) Row(verticalAlignment = Alignment.CenterVertically) {
StatusRow(isConnected, deviceName)
Spacer(Modifier.weight(1f))
// 이 화면에서 바로 연결할 수 있어야 한다. 연결이 이 모드의 첫 단계인데
// 가는 길이 없으면 홈까지 되돌아가 일반 흐름을 타야 했다.
// 복귀처를 지정해 두면 연결 성공/뒤로가기 모두 이 화면으로 돌아온다.
TextButton(
enabled = !running,
onClick = {
appState.connectReturnScreen = AppScreen.HOSPITAL_MODE
appState.currentScreen = AppScreen.DEVICE_SCAN
},
) { Text(if (isConnected) "기기 변경" else "기기 연결", fontWeight = FontWeight.SemiBold) }
}
Spacer(Modifier.height(12.dp)) Spacer(Modifier.height(12.dp))
OutlinedTextField( OutlinedTextField(
@@ -277,7 +290,7 @@ fun HospitalModeView(appState: AppState) {
shape = RoundedCornerShape(14.dp), shape = RoundedCornerShape(14.dp),
) { Text("측정 시작", fontSize = 17.sp, fontWeight = FontWeight.Bold) } ) { Text("측정 시작", fontSize = 17.sp, fontWeight = FontWeight.Bold) }
if (!isConnected) Hint("기기를 먼저 연결해 주세요.") if (!isConnected) Hint("위 [기기 연결] 을 눌러 프로브를 연결해 주세요.")
else if (patient.isBlank()) Hint("환자명을 입력해 주세요.") else if (patient.isBlank()) Hint("환자명을 입력해 주세요.")
if (okCount > 0 || failCount > 0) { if (okCount > 0 || failCount > 0) {