ux: Sensor Alignment — Step 0/N, arrow↔hint sync, arrow 위치, oval 색
1) 시작 전 (waitingForStart) Step 표기: "Step 1/3" → "Step 0/3" 으로 표시, 점/체크포인트 row 전체 숨김 (시작 후에만 점 등장). 2) 화살표 ↔ Hint 2 텍스트 mismatch 수정 (V1 path): debounce 중 else 분기에서 directionIcon 을 guideResult.icon 으로 즉시 갱신 → 텍스트는 "위로 올려" 인데 화살표는 가끔 아래를 가리키는 깜빡임 발생. 수정: directionHint 텍스트에서 방향 추론 (phaseHoldHint 와 동일 로직) → 화면에 보이는 텍스트와 항상 일관. V2 path 는 이미 동일 source(st.action) 라 영향 없음. 3) 화살표 위치 — 센서/방광 쪽으로 당김: vertCloser = arrowDrawH * 0.45f 도입. - 위 화살표 cya: 기존 + vertCloser (살짝 아래로) - 아래 화살표 cya: 기존 - vertCloser (살짝 위로) 좌/우 화살표는 변경 없음. 4) 방광 oval 색 (센서 주위 테두리) — 미정렬 상태: Cyan → Color(0xFFFFB74D) (Material orange 300, warm hint). greenZone 진입 시는 기존 Green 4CAF50 유지. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+36
-22
@@ -362,7 +362,8 @@ fun PlacementGuideView(appState: AppState) {
|
||||
val bladderCy = navelY + (pubisY - navelY) * 0.75f
|
||||
val bladderRx = w * 0.18f
|
||||
val bladderRy = bladderRx * 0.70f
|
||||
val ovalColor = if (greenZone) Color(0xFF4CAF50) else Color.Cyan
|
||||
// In-position 아닐 때는 연한 주황 (warm hint), 완료되면 기존 그린.
|
||||
val ovalColor = if (greenZone) Color(0xFF4CAF50) else Color(0xFFFFB74D)
|
||||
drawOval(
|
||||
color = ovalColor.copy(alpha = 0.12f),
|
||||
topLeft = Offset(cx - bladderRx, bladderCy - bladderRy),
|
||||
@@ -403,18 +404,20 @@ fun PlacementGuideView(appState: AppState) {
|
||||
val arrowDrawH = arrowDrawW * (arrowBitmap.height.toFloat() / arrowBitmap.width.toFloat())
|
||||
val sensorHalfH = h * 0.08f
|
||||
val gap = 20f
|
||||
// 위/아래 화살표를 센서/방광 쪽으로 가깝게 당김 (사용자 요구).
|
||||
val vertCloser = arrowDrawH * 0.45f
|
||||
|
||||
// 화살표 center 위치 + 회전 각도 (icon 이 우향이므로 right=0°)
|
||||
data class ArrowPlacement(val cxa: Float, val cya: Float, val rot: Float)
|
||||
val placement: ArrowPlacement? = when {
|
||||
directionIcon.contains("up") -> ArrowPlacement(
|
||||
cx,
|
||||
bladderCy - bladderRy - sensorHalfH - gap - arrowDrawH / 2f,
|
||||
bladderCy - bladderRy - sensorHalfH - gap - arrowDrawH / 2f + vertCloser,
|
||||
-90f,
|
||||
)
|
||||
directionIcon.contains("down") -> ArrowPlacement(
|
||||
cx,
|
||||
bladderCy + bladderRy + sensorHalfH + gap + arrowDrawH / 2f,
|
||||
bladderCy + bladderRy + sensorHalfH + gap + arrowDrawH / 2f - vertCloser,
|
||||
90f,
|
||||
)
|
||||
directionIcon.contains("left") -> ArrowPlacement(
|
||||
@@ -482,27 +485,31 @@ fun PlacementGuideView(appState: AppState) {
|
||||
}
|
||||
idx to 3
|
||||
}
|
||||
// waitingForStart 일 때는 "Step 0/N" + 모든 점 숨김 (체크포인트 포함).
|
||||
val displayStepIdx = if (waitingForStart) -1 else currentStepIdx
|
||||
Text(
|
||||
text = "Step ${currentStepIdx + 1}/$totalSteps",
|
||||
text = "Step ${displayStepIdx + 1}/$totalSteps",
|
||||
fontSize = 28.sp, fontWeight = FontWeight.Bold, color = Color.Black
|
||||
)
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically) {
|
||||
repeat(totalSteps) { i ->
|
||||
val isDone = i < currentStepIdx
|
||||
val isCurrent = i == currentStepIdx
|
||||
val dotSize = if (isCurrent) 16.dp else 10.dp // 12/8 → 16/10
|
||||
val dotColor = when {
|
||||
isCurrent -> MlPrimary
|
||||
isDone -> MlPrimary.copy(alpha = 0.6f)
|
||||
else -> Color.Gray.copy(alpha = 0.3f)
|
||||
if (!waitingForStart) {
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically) {
|
||||
repeat(totalSteps) { i ->
|
||||
val isDone = i < currentStepIdx
|
||||
val isCurrent = i == currentStepIdx
|
||||
val dotSize = if (isCurrent) 16.dp else 10.dp
|
||||
val dotColor = when {
|
||||
isCurrent -> MlPrimary
|
||||
isDone -> MlPrimary.copy(alpha = 0.6f)
|
||||
else -> Color.Gray.copy(alpha = 0.3f)
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(dotSize)
|
||||
.clip(CircleShape)
|
||||
.background(dotColor)
|
||||
)
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(dotSize)
|
||||
.clip(CircleShape)
|
||||
.background(dotColor)
|
||||
)
|
||||
}
|
||||
}
|
||||
if (isSweepMode) {
|
||||
@@ -881,8 +888,15 @@ fun PlacementGuideView(appState: AppState) {
|
||||
else -> "checkmark.circle"
|
||||
}
|
||||
} else {
|
||||
// 디바운스 중이라도 화살표 방향은 최신 상태로 갱신
|
||||
directionIcon = guideResult.icon
|
||||
// 디바운스 중 — 화살표를 hint 텍스트에서 추론해 텍스트와 일관 유지.
|
||||
// (이전: guideResult.icon 즉시 갱신 → "위로 올려" 메세지에 아래 화살표 깜빡임)
|
||||
directionIcon = when {
|
||||
directionHint.contains("up", ignoreCase = true) || directionHint.contains("↑") -> "arrow.up"
|
||||
directionHint.contains("down", ignoreCase = true) || directionHint.contains("↓") -> "arrow.down"
|
||||
directionHint.contains("left", ignoreCase = true) || directionHint.contains("←") -> "arrow.left"
|
||||
directionHint.contains("right", ignoreCase = true) || directionHint.contains("→") -> "arrow.right"
|
||||
else -> directionIcon // 유지
|
||||
}
|
||||
}
|
||||
|
||||
// GREEN hold 중이면 힌트 강제 유지
|
||||
|
||||
Reference in New Issue
Block a user