feat(clinical): 부착 위치가 확정되면 카드를 통째로 초록으로

탐색 중에는 흰 카드 안의 숫자만 바뀐다. 확정도 같은 흰 카드에 글자색만 달랐으니
"또 한 번 바뀐 숫자"로 읽힌다. 그런데 여기가 이 화면의 유일한 전환점이다 — 이 뒤로는
프로브를 옮기고 **더 이상 재지 않는다.** 면 색이 바뀌어야 프로브를 잡은 채 곁눈으로
봐도 걸린다.

확정(action == STOP && anchorCm != null)일 때:

    배경   MlSuccess 단색 · 글자 흰색
    라벨   "부착 위치" → "부착 위치 확정"
    숫자   40sp → 44sp
    한 줄  "여기로 옮기고 (최적 2cm + 1cm) 고정하세요. 이 자리는 측정하지 않습니다."

마지막 줄에 최적 cm 을 괄호로 같이 적었다. 간호사가 제일 많이 틀릴 지점이 **최적
위치(best)와 부착 위치(best+1)를 헷갈려 방금 측정했던 자리에 그대로 붙이는 것**이다.
큰 숫자만 있으면 "2cm 에서 완료라고 했는데 왜 3cm 이지"가 되므로 둘의 관계를 그 자리에
보여 준다.

아래 안내 박스는 확정일 때 첫 줄(근거 nch·cap)만 남긴다. 둘째 줄이 "여기서 1cm 더 올려
3cm 에 부착하세요"라 초록 카드와 같은 말이었다 — 같은 지시를 두 번 쓰면 둘 다 안 읽힌다.

REATTACH 는 초록으로 칠하지 않는다. done 이긴 하지만 부착 위치가 확정된 상태가 아니다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-09 15:17:19 +09:00
parent d66b69506f
commit f5afce6d17
@@ -37,6 +37,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.medithings.vesiscan.ui.components.BvPanel
@@ -471,21 +472,45 @@ fun AnchorAlignView(appState: AppState) {
Spacer(Modifier.height(16.dp))
// 현재 위치 — 크게. 간호사가 프로브를 잡은 채 멀리서 봐야 한다.
//
// **확정된 순간에는 카드를 통째로 초록으로 칠한다.** 탐색 중에는 흰 카드에
// 숫자만 바뀌므로, 확정도 흰 카드에 글자색만 다르면 "또 한 번 바뀐 숫자"로
// 읽힌다. 여기서 프로브를 옮기고 더 이상 재지 않는다는 것이 이 화면에서
// 제일 중요한 전환점이라, 색이 면으로 바뀌어야 곁눈으로도 걸린다.
val fixed = last?.action == AnchorAction.STOP && last?.anchorCm != null
Box(
Modifier.fillMaxWidth()
.background(Color.White, RoundedCornerShape(14.dp))
.padding(vertical = 20.dp),
.background(if (fixed) MlSuccess else Color.White, RoundedCornerShape(14.dp))
.padding(vertical = 20.dp, horizontal = 16.dp),
contentAlignment = Alignment.Center,
) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text(if (done) "부착 위치" else "지금 측정할 위치",
fontSize = 13.sp, color = MlSecondaryText)
Spacer(Modifier.height(4.dp))
Text(
if (done) "${last?.anchorCm ?: "-"} cm" else "$cm cm",
fontSize = 40.sp, fontWeight = FontWeight.Bold,
color = if (done) MlSuccess else MlPrimary,
)
if (fixed) {
// 판정이 아니라 **지시**로 읽히게 쓴다.
Text("부착 위치 확정", fontSize = 13.sp, color = Color.White,
fontWeight = FontWeight.Bold)
Spacer(Modifier.height(4.dp))
Text("${last?.anchorCm} cm", fontSize = 44.sp,
fontWeight = FontWeight.Bold, color = Color.White)
Spacer(Modifier.height(6.dp))
// 간호사가 제일 많이 틀리는 지점이다 — 최적 위치(best)와 부착
// 위치(best+1)를 헷갈려 측정했던 자리에 그대로 붙인다.
Text(
"여기로 옮기고 " + (last?.bestCm?.let { "(최적 ${it}cm + 1cm) " } ?: "") +
"고정하세요. 이 자리는 측정하지 않습니다.",
fontSize = 12.sp, color = Color.White.copy(alpha = 0.92f),
textAlign = TextAlign.Center,
)
} else {
Text(if (done) "부착 위치" else "지금 측정할 위치",
fontSize = 13.sp, color = MlSecondaryText)
Spacer(Modifier.height(4.dp))
Text(
if (done) "${last?.anchorCm ?: "-"} cm" else "$cm cm",
fontSize = 40.sp, fontWeight = FontWeight.Bold,
color = if (done) MlSuccess else MlPrimary,
)
}
}
}
Spacer(Modifier.height(12.dp))
@@ -496,11 +521,14 @@ fun AnchorAlignView(appState: AppState) {
AnchorAction.REATTACH -> MlCritical
else -> MlPrimary
}
// 확정 카드가 이미 "여기로 옮기고 고정하세요"를 말했다. 같은 말을 두 번
// 쓰면 둘 다 안 읽힌다 — 여기서는 근거(nch·cap)만 남긴다.
val body = if (fixed) s.message.lineSequence().first() else s.message
Box(
Modifier.fillMaxWidth()
.border(1.5.dp, tone, RoundedCornerShape(12.dp))
.padding(12.dp)
) { Text(s.message, fontSize = 14.sp, color = tone) }
) { Text(body, fontSize = 14.sp, color = tone) }
Spacer(Modifier.height(12.dp))
}