ui(hospital): 정렬 카드를 labdb 바로 아래로 올리고, 정렬 화면에서도 자세를 고르게 한다
접는 구간에 넣어 봤더니 정렬은 환자마다 한 번은 반드시 펴야 해서 불편했다(2026-09-29 오후 피드백). 프로브를 붙이는 순서가 곧 화면 순서다: 연결 → labdb → 정렬 → 환자명 → 자세 → 기울기 → 채움 정도 → 측정 시작/중지 → 채널 접촉 정렬이 자세보다 위로 가면 자세를 안 고른 채 정렬에 들어오는 것이 정상 경로가 된다. 그래서 정렬 화면의 기울기 카드 아래에 자세 칩을 둔다 — AppState.clinicalPosture 공유라 어느 쪽에서 골라도 같은 값이고, Sitting 35°~55° 띠와 BV 의 supine 분기가 거기서 뜬다. 측정·좌우 스캔 중에는 바꾸지 못한다. 접는 구간 A 는 "측정 조건"(반복 횟수·복부 두께)만 남는다. 측정 중 한 줄 요약에 부착 위치를 넣는다. A34 실기: 병원 화면 순서 확인, 정렬 화면에서 Sitting 을 고르면 카드에 띠가 뜬다. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -63,7 +63,8 @@ class AppState(private val context: Context) {
|
||||
* 들고 있으면 같은 프로브·같은 자리에서 **정렬 BV 와 임상 BV 가 다른 식으로**
|
||||
* 계산된다 — 실제로 정렬이 `supine` 을 안 넘겨 그렇게 돌고 있었다(2026-09-10).
|
||||
*
|
||||
* 정렬 화면에는 자세를 고르는 칸이 없다. 병원 모드에서 고른 값을 그대로 쓴다.
|
||||
* 정렬 화면과 병원 모드 어느 쪽에서든 고를 수 있다(2026-09-29 정렬 화면에 칩 추가 —
|
||||
* 병원 화면에서 정렬이 자세보다 위에 있어 자세 없이 들어오는 것이 정상 경로다).
|
||||
*/
|
||||
var clinicalPosture: com.medithings.vesiscan.models.ClinicalPosture by
|
||||
mutableStateOf(com.medithings.vesiscan.models.ClinicalPosture.SUPINE)
|
||||
|
||||
@@ -36,6 +36,7 @@ package com.medithings.vesiscan.ui.views.clinical
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
@@ -604,20 +605,41 @@ fun AnchorAlignView(appState: AppState) {
|
||||
}
|
||||
Spacer(Modifier.height(8.dp))
|
||||
|
||||
// 프로브 기울기 — 상시. 자세는 이 화면에서 고르지 않는다(AppState.clinicalPosture
|
||||
// 참조). 병원 화면에서 고른 값으로 요구 범위를 보이되, 어느 자세 기준인지 적는다 —
|
||||
// 안 적으면 Supine 으로 들어와 띠가 없을 때 "왜 안 뜨나"가 된다.
|
||||
// 프로브 기울기 — 상시. 요구 범위(Sitting 35°~55°)는 바로 아래 자세를 본다.
|
||||
ImuTiltCard(
|
||||
tiltDeg = liveTilt,
|
||||
posture = appState.clinicalPosture,
|
||||
connected = isConnected,
|
||||
running = measuring || lrRunning,
|
||||
)
|
||||
Spacer(Modifier.height(4.dp))
|
||||
Text(
|
||||
"자세 ${appState.clinicalPosture.label} 기준 — 병원 임상 측정 화면에서 고른 값",
|
||||
fontSize = 11.sp, color = MlSecondaryText,
|
||||
)
|
||||
Spacer(Modifier.height(10.dp))
|
||||
|
||||
// 자세 — 여기서도 고른다(2026-09-29). 병원 화면에서 정렬 카드가 자세 칩보다 위에
|
||||
// 있어(연결 → labdb → 정렬) 자세를 안 고른 채 들어오는 것이 정상 경로다. 값은
|
||||
// AppState 공유라 돌아가면 그대로다. 위 카드의 요구 범위와 BV 의 supine 분기가
|
||||
// 이 값을 본다. 측정·좌우 스캔 중에는 바꾸지 못한다 — 그 위치 데이터의 조건이다.
|
||||
Text("자세", fontSize = 13.sp, fontWeight = FontWeight.SemiBold, color = MlSecondaryText)
|
||||
Row(
|
||||
Modifier.fillMaxWidth().padding(top = 6.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(6.dp),
|
||||
) {
|
||||
ClinicalPosture.entries.forEach { p ->
|
||||
val on = p == appState.clinicalPosture
|
||||
Box(
|
||||
Modifier
|
||||
.weight(1f)
|
||||
.background(if (on) MlPrimary else Color.White, RoundedCornerShape(10.dp))
|
||||
.clickable(enabled = !measuring && !lrRunning) { appState.clinicalPosture = p }
|
||||
.padding(vertical = 10.dp),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Text(
|
||||
p.label, fontSize = 14.sp, fontWeight = FontWeight.SemiBold,
|
||||
color = if (on) Color.White else MlSecondaryText,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Spacer(Modifier.height(12.dp))
|
||||
|
||||
Text(
|
||||
|
||||
@@ -17,12 +17,16 @@
|
||||
* 측정하는 동안 실제로 보는 것은 넷이다 — **기울기 · 채움 정도 · 채널 접촉 · 시작/중지**.
|
||||
* 이 넷이 스크롤 없이 한 화면에 있어야 한다. 그래서 위에는 그 흐름만 둔다:
|
||||
*
|
||||
* 연결 → labdb → 환자명 → 자세 → 기울기 → 채움 정도 → 측정 시작/중지 → 채널 접촉(측정 중)
|
||||
* 연결 → labdb → 정렬 → 환자명 → 자세 → 기울기 → 채움 정도 → 측정 시작/중지 → 채널 접촉(측정 중)
|
||||
*
|
||||
* 세션에 한 번 만지거나 안 만지는 것은 아래 접는 구간([Collapsible])이다 — 측정 조건·
|
||||
* 부착 위치(정렬·반복·두께), 회차 상세(용적·파형), labdb 업로드·기록, 수동 확인(프로브
|
||||
* 파라미터 · 1회/연속 BV). 접힌 머리줄에 요약을 적어 미정렬·미업로드는 펴 보지 않아도
|
||||
* 보인다. 수동 확인 값은 저장도 업로드도 되지 않는다 — 한 흐름으로 붙여 두면 조작자가
|
||||
* 정렬은 위에 둔다(2026-09-29 오후) — 접는 구간에 넣어 봤더니 환자마다 한 번은 반드시
|
||||
* 펴야 해서 불편했다. 프로브를 붙이는 순서가 곧 화면 순서다: 연결하고, 붙일 자리를
|
||||
* 찾고, 그 다음이 환자·자세·측정이다. 자세는 정렬 화면에서도 고를 수 있으므로
|
||||
* (AppState.clinicalPosture 공유) 정렬이 자세보다 위에 있어도 요구 각도 띠는 거기서 뜬다.
|
||||
*
|
||||
* 세션에 한 번 만지거나 안 만지는 것은 아래 접는 구간([Collapsible])이다 — 측정 조건
|
||||
* (반복·두께), 회차 상세(용적·파형), labdb 업로드·기록, 수동 확인(프로브 파라미터 ·
|
||||
* 1회/연속 BV). 접힌 머리줄에 요약을 적어 미업로드는 펴 보지 않아도 보인다. 수동 확인 값은 저장도 업로드도 되지 않는다 — 한 흐름으로 붙여 두면 조작자가
|
||||
* 수동 측정을 프로토콜의 한 단계로 착각하므로 제목에 못 박고 접어 둔다.
|
||||
*/
|
||||
package com.medithings.vesiscan.ui.views.clinical
|
||||
@@ -497,10 +501,15 @@ fun HospitalModeView(appState: AppState) {
|
||||
// ── 화면 구성 (2026-09-29 임상 참관 뒤) ─────────────────────────
|
||||
// 측정하는 동안 실제로 보는 것은 넷이다 — 기울기 · 채움 정도 · 채널 접촉 ·
|
||||
// 시작/중지. 이 넷이 스크롤 없이 한 화면에 있어야 한다. 그래서 위에는 그 흐름
|
||||
// (연결 → labdb → 환자 → 자세 → 기울기 → 채움 → 시작 → 접촉)만 두고, 세션에
|
||||
// 한 번 만지거나 안 만지는 것(정렬·반복·두께, 회차 상세, 업로드, 수동 도구)은
|
||||
// (연결 → labdb → 정렬 → 환자 → 자세 → 기울기 → 채움 → 시작 → 접촉)만 두고,
|
||||
// 세션에 한 번 만지거나 안 만지는 것(반복·두께, 회차 상세, 업로드, 수동 도구)은
|
||||
// 아래 [Collapsible] 로 내렸다. 접힌 머리줄에 요약을 적어 펴 보지 않아도
|
||||
// 상태(미정렬·미업로드)가 보이게 한다.
|
||||
// 상태(미업로드)가 보이게 한다.
|
||||
|
||||
val anchorSummary = appState.anchorCm?.let { cm ->
|
||||
if (appState.anchorBasis?.isAlgorithm == true) "부착 위치 ${cm}cm 확정"
|
||||
else "부착 위치 ${cm}cm · ${appState.anchorBasis?.label ?: "근거 불명"}"
|
||||
} ?: "부착 위치 미정렬"
|
||||
|
||||
// 2. labdb 등록 상태. **측정 전에** 보여야 한다 — 미등록이면 업로드 시도조차
|
||||
// 일어나지 않는데(ClinicalSessionStore·HospitalLabdbUploader 가 둘 다
|
||||
@@ -510,7 +519,7 @@ fun HospitalModeView(appState: AppState) {
|
||||
// 진행·중지·접촉이 스크롤 없이 한 화면에 들어오게 한다 — 이 화면을 다시 짠 이유다.
|
||||
if (running) {
|
||||
Text(
|
||||
"환자 ${patient.ifBlank { "(이름 없음)" }} · ${posture.label} · labdb " +
|
||||
"환자 ${patient.ifBlank { "(이름 없음)" }} · ${posture.label} · $anchorSummary · labdb " +
|
||||
(if (LabdbCredentials.isRegistered) "연결됨" else "미등록"),
|
||||
fontSize = 13.sp, fontWeight = FontWeight.SemiBold, color = MlNeutral,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
@@ -522,7 +531,17 @@ fun HospitalModeView(appState: AppState) {
|
||||
LabdbStatusCard(enabled = true)
|
||||
Spacer(Modifier.height(12.dp))
|
||||
|
||||
// 3. 환자명
|
||||
// 3. 부착 위치 정렬 — 연결 여부로 막지 않는다(2026-09-28). 정렬 화면에
|
||||
// [기기 연결] 이 있고 측정 버튼은 거기서 연결을 본다. 들어가서 붙이면 된다.
|
||||
AnchorCard(
|
||||
anchorCm = appState.anchorCm,
|
||||
basis = appState.anchorBasis,
|
||||
enabled = true,
|
||||
onAlign = { appState.currentScreen = AppScreen.ANCHOR_ALIGN },
|
||||
)
|
||||
Spacer(Modifier.height(12.dp))
|
||||
|
||||
// 4. 환자명
|
||||
OutlinedTextField(
|
||||
value = patient,
|
||||
onValueChange = {
|
||||
@@ -642,27 +661,11 @@ fun HospitalModeView(appState: AppState) {
|
||||
|
||||
// ── 접는 구간 ───────────────────────────────────────────────────
|
||||
|
||||
// A. 측정 조건 · 부착 위치 — 환자마다 한 번. 머리줄에 정렬 상태를 적어 미정렬이
|
||||
// 접힌 채로도 보이게 한다(기록에 부착 위치가 남지 않는 상태를 놓치면 안 된다).
|
||||
val anchorSummary = appState.anchorCm?.let { cm ->
|
||||
if (appState.anchorBasis?.isAlgorithm == true) "부착 위치 ${cm}cm 확정"
|
||||
else "부착 위치 ${cm}cm · ${appState.anchorBasis?.label ?: "근거 불명"}"
|
||||
} ?: "부착 위치 미정렬"
|
||||
// A. 측정 조건 — 반복 횟수·복부 두께. 세션에 한 번 정하면 안 건드린다.
|
||||
Collapsible(
|
||||
title = "측정 조건 · 부착 위치",
|
||||
summary = "$anchorSummary · ${repeats}회 × ${thickness.combos.size}조합 · 복부 ${thickness.label}",
|
||||
warn = appState.anchorCm == null,
|
||||
title = "측정 조건",
|
||||
summary = "${repeats}회 × ${thickness.combos.size}조합 · 복부 ${thickness.label}",
|
||||
) {
|
||||
// 연결 여부로 막지 않는다(2026-09-28). 정렬 화면에 [기기 연결] 이 있고
|
||||
// 측정 버튼은 거기서 연결을 본다. 들어가서 붙이면 된다.
|
||||
AnchorCard(
|
||||
anchorCm = appState.anchorCm,
|
||||
basis = appState.anchorBasis,
|
||||
enabled = !running,
|
||||
onAlign = { appState.currentScreen = AppScreen.ANCHOR_ALIGN },
|
||||
)
|
||||
Spacer(Modifier.height(12.dp))
|
||||
|
||||
OutlinedTextField(
|
||||
value = repeatsText,
|
||||
onValueChange = { if (!running) repeatsText = it.filter { c -> c.isDigit() }.take(3) },
|
||||
|
||||
Reference in New Issue
Block a user