ux: Sensor Alignment hint 빈 칸 숨김 + V2 게이트 강화 (demo-final)
1) 힌트 메세지 박스 자체 숨김 (내용 없을 때)
기존: waitingForStart 시 Hint 2 = AnnotatedString(" ") — 빈 칸 자체는 유지
변경: 빈 텍스트면 Box 자체 렌더 X (Spacer 도 같이 제거).
Hint 1: waitingForStart 일 때만 렌더
Hint 2: !waitingForStart && displayHint.text.isNotBlank() 일 때만 렌더
레이아웃: 빈 칸이 사라지므로 일러스트 위/아래 여백이 자연스럽게 통합.
2) Hint 1/2 텍스트 상하 중앙 정렬
기존: Text 에 .padding(vertical=14dp) 만 — baseline 기준이라 일부 폰트에서
미세 비대칭 가능.
변경: Box(contentAlignment=Center) 로 감싸고 Text 를 그 안에 배치 →
박스 높이 = padding 14dp top + 텍스트 + 14dp bottom 정확히 매칭.
3) PiezoMonitoring → PlacementGuide 진입 시 항상 V1 (clinical 만 V2)
기존: currentSession.mode == ALIGNMENT 만 체크 → 잔여 세션이 있으면
일반 흐름에서도 V2 강제됨.
변경: !appState.placementFromMonitoring 조건도 같이 체크.
enterPlacementFromMonitoring() 가 placementFromMonitoring=true 설정 →
이 경우 항상 V1.
enterAlignmentSession() (clinical 전용) 만 placementFromMonitoring=false +
mode=ALIGNMENT 이라 V2 로 라우팅.
영향:
- PiezoMonitoring → "재정렬" 진입 시 항상 V1 ✓
- Clinical → Sensor Alignment → V2 ✓
- 위저드 흐름 + 잔여 세션 → V1 (위저드는 placementFromMonitoring 변경 안 함)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+31
-17
@@ -121,10 +121,12 @@ fun PlacementGuideView(appState: AppState) {
|
|||||||
var sweepLastDetected by remember { mutableIntStateOf(0) }
|
var sweepLastDetected by remember { mutableIntStateOf(0) }
|
||||||
var sweepEverSawAll by remember { mutableStateOf(false) }
|
var sweepEverSawAll by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
// 화면 진입 시 전체 상태 리셋. clinical alignment session 이면 V2, 그 외 V1 자동 강제.
|
// 화면 진입 시 전체 상태 리셋. clinical alignment session (placementFromMonitoring=false +
|
||||||
|
// 활성 ALIGNMENT 세션) 이면 V2, 그 외 (PiezoMonitoring 에서 진입 / 위저드 진입 / 잔여 세션) 는 항상 V1.
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
val sess = com.example.medilightv2android.services.ClinicalSessionStore.currentSession
|
val sess = com.example.medilightv2android.services.ClinicalSessionStore.currentSession
|
||||||
val isClinicalAlign = sess != null &&
|
val isClinicalAlign = !appState.placementFromMonitoring &&
|
||||||
|
sess != null &&
|
||||||
sess.mode == com.example.medilightv2android.models.SessionMode.ALIGNMENT
|
sess.mode == com.example.medilightv2android.models.SessionMode.ALIGNMENT
|
||||||
com.example.medilightv2android.managers.GreenZoneConstants.alignmentAlgo =
|
com.example.medilightv2android.managers.GreenZoneConstants.alignmentAlgo =
|
||||||
if (isClinicalAlign) com.example.medilightv2android.managers.AlignmentAlgo.V2
|
if (isClinicalAlign) com.example.medilightv2android.managers.AlignmentAlgo.V2
|
||||||
@@ -232,10 +234,11 @@ fun PlacementGuideView(appState: AppState) {
|
|||||||
.padding(horizontal = 24.dp),
|
.padding(horizontal = 24.dp),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
// ─── (1) Hint 1 — 시작 전 안내 (칸 상시 유지, "pubic bone" 빨강 강조) ───
|
// ─── (1) Hint 1 — waitingForStart 일 때만 렌더 (빈 칸 자체 숨김) ───
|
||||||
|
if (waitingForStart) {
|
||||||
val hint1Bg = Color(0xFFFFF3E0)
|
val hint1Bg = Color(0xFFFFF3E0)
|
||||||
val hint1Text = remember(waitingForStart) {
|
val hint1Text = remember {
|
||||||
if (waitingForStart) buildAnnotatedString {
|
buildAnnotatedString {
|
||||||
val full = "Place VesiScan above the pubic bone, then press Start"
|
val full = "Place VesiScan above the pubic bone, then press Start"
|
||||||
val key = "pubic bone"
|
val key = "pubic bone"
|
||||||
val idx = full.indexOf(key, ignoreCase = true)
|
val idx = full.indexOf(key, ignoreCase = true)
|
||||||
@@ -246,20 +249,25 @@ fun PlacementGuideView(appState: AppState) {
|
|||||||
}
|
}
|
||||||
append(full.substring(idx + key.length))
|
append(full.substring(idx + key.length))
|
||||||
} else append(full)
|
} else append(full)
|
||||||
} else AnnotatedString(" ") // 공백 — 칸 높이 유지
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.background(hint1Bg.copy(alpha = 0.7f), RoundedCornerShape(16.dp))
|
||||||
|
.padding(horizontal = 20.dp, vertical = 14.dp),
|
||||||
|
contentAlignment = Alignment.Center // 상하 중앙 정렬
|
||||||
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = hint1Text,
|
text = hint1Text,
|
||||||
fontSize = 26.sp,
|
fontSize = 26.sp,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
color = Color.Black,
|
color = Color.Black,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.background(hint1Bg.copy(alpha = 0.7f), RoundedCornerShape(16.dp))
|
|
||||||
.padding(horizontal = 20.dp, vertical = 14.dp)
|
|
||||||
)
|
)
|
||||||
|
}
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
}
|
||||||
// 타이틀은 top bar 로 이동 (← 옆 절대 가운데) — 본문 중복 제거.
|
// 타이틀은 top bar 로 이동 (← 옆 절대 가운데) — 본문 중복 제거.
|
||||||
|
|
||||||
// ── 가이드 텍스트 (Step 아래, 몸 위) — "pubic bone" 인라인 빨강 ExtraBold 강조 ──
|
// ── 가이드 텍스트 (Step 아래, 몸 위) — "pubic bone" 인라인 빨강 ExtraBold 강조 ──
|
||||||
@@ -524,20 +532,26 @@ fun PlacementGuideView(appState: AppState) {
|
|||||||
|
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
|
||||||
// ─── (5) Hint 2 — 측정 중 방향 안내 (waitingForStart 시 공백, pubic bone 중복 X) ───
|
// ─── (5) Hint 2 — 측정 중 방향 안내 (waitingForStart 또는 빈 텍스트면 칸 자체 숨김) ───
|
||||||
|
val hint2Visible = !waitingForStart && displayHint.text.isNotBlank()
|
||||||
|
if (hint2Visible) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.background(hintBg.copy(alpha = 0.7f), RoundedCornerShape(16.dp))
|
||||||
|
.padding(horizontal = 20.dp, vertical = 14.dp),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = if (waitingForStart) AnnotatedString(" ") else displayHint,
|
text = displayHint,
|
||||||
fontSize = 28.sp,
|
fontSize = 28.sp,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
color = Color.Black,
|
color = Color.Black,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.background(hintBg.copy(alpha = 0.7f), RoundedCornerShape(16.dp))
|
|
||||||
.padding(horizontal = 20.dp, vertical = 14.dp)
|
|
||||||
)
|
)
|
||||||
|
}
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
}
|
||||||
|
|
||||||
// 채널 dot row (개발자 모드에서만 표시)
|
// 채널 dot row (개발자 모드에서만 표시)
|
||||||
if (appState.isDevMode) {
|
if (appState.isDevMode) {
|
||||||
|
|||||||
Reference in New Issue
Block a user