ux: Sensor Alignment 레이아웃 정형화 — 박스 항상 자리, weight 5등분
요구사항 (사용자 정의 순서):
Title / spacer / Hint1 / spacer / Illustration / spacer /
Step / spacer / Hint2 / spacer / Start / Skip
변경:
1) Hint 1 박스: if(waitingForStart) 외부 가드 제거 → 박스는
항상 렌더. 텍스트만 waitingForStart 시 표시. heightIn min
96dp (현재 자연 높이 ~64dp 의 1.5배).
2) Hint 2 박스: 동일 패턴 — 박스 항상 렌더, 텍스트는
hint2Visible 시만, heightIn min 102dp (28sp 텍스트 기준 1.5배).
3) Step ↔ Hint 2 간격: Spacer 8dp → weight 1f (5번째 분할).
4) Skip ↔ 하단: weight 1f → 고정 16dp (사용자 요구 — Skip 이
화면 아래 가깝게).
결과: 빈 공간이 5개 위치 (Title↔Hint1, Hint1↔Illustration,
Illustration↔Step, Step↔Hint2, Hint2↔Button) 에 균등 분배.
내용 없을 때도 Hint 박스 자리는 그대로 유지 (배경/높이).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+38
-37
@@ -237,30 +237,31 @@ fun PlacementGuideView(appState: AppState) {
|
||||
// Title(top bar) ↔ Hint 1 사이 — 첫 weight spacer (위쪽 빈 공간 균등 분배).
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
// ─── (1) Hint 1 — waitingForStart 일 때만 렌더 (빈 칸 자체 숨김) ───
|
||||
if (waitingForStart) {
|
||||
val hint1Bg = Color(0xFFFFF3E0)
|
||||
val hint1Text = remember {
|
||||
buildAnnotatedString {
|
||||
val full = "Place VesiScan above the pubic bone, then press Start"
|
||||
val key = "pubic bone"
|
||||
val idx = full.indexOf(key, ignoreCase = true)
|
||||
if (idx >= 0) {
|
||||
append(full.substring(0, idx))
|
||||
withStyle(SpanStyle(color = Color.Red, fontWeight = FontWeight.ExtraBold)) {
|
||||
append(full.substring(idx, idx + key.length))
|
||||
}
|
||||
append(full.substring(idx + key.length))
|
||||
} else append(full)
|
||||
}
|
||||
// ─── (1) Hint 1 — 박스는 항상 자리(높이 1.5×), 텍스트는 waitingForStart 시만 ───
|
||||
val hint1Bg = Color(0xFFFFF3E0)
|
||||
val hint1Text = remember {
|
||||
buildAnnotatedString {
|
||||
val full = "Place VesiScan above the pubic bone, then press Start"
|
||||
val key = "pubic bone"
|
||||
val idx = full.indexOf(key, ignoreCase = true)
|
||||
if (idx >= 0) {
|
||||
append(full.substring(0, idx))
|
||||
withStyle(SpanStyle(color = Color.Red, fontWeight = FontWeight.ExtraBold)) {
|
||||
append(full.substring(idx, idx + key.length))
|
||||
}
|
||||
append(full.substring(idx + key.length))
|
||||
} else append(full)
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(hint1Bg.copy(alpha = 0.7f), RoundedCornerShape(16.dp))
|
||||
.padding(horizontal = 20.dp, vertical = 14.dp),
|
||||
contentAlignment = Alignment.Center // 상하 중앙 정렬
|
||||
) {
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(min = 96.dp) // 1.5× of current ~64dp natural height
|
||||
.background(hint1Bg.copy(alpha = 0.7f), RoundedCornerShape(16.dp))
|
||||
.padding(horizontal = 20.dp, vertical = 14.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
if (waitingForStart) {
|
||||
Text(
|
||||
text = hint1Text,
|
||||
fontSize = 26.sp,
|
||||
@@ -269,7 +270,6 @@ fun PlacementGuideView(appState: AppState) {
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
}
|
||||
// 타이틀은 top bar 로 이동 (← 옆 절대 가운데) — 본문 중복 제거.
|
||||
|
||||
@@ -532,18 +532,20 @@ fun PlacementGuideView(appState: AppState) {
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
// Step ↔ Hint 2 사이 — weight spacer
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
// ─── (5) Hint 2 — 측정 중 방향 안내 (waitingForStart 또는 빈 텍스트면 칸 자체 숨김) ───
|
||||
// ─── (5) Hint 2 — 박스는 항상 자리(높이 1.5×), 텍스트는 가시 조건일 때만 ───
|
||||
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
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(min = 102.dp) // 1.5× of current ~68dp natural height
|
||||
.background(hintBg.copy(alpha = 0.7f), RoundedCornerShape(16.dp))
|
||||
.padding(horizontal = 20.dp, vertical = 14.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
if (hint2Visible) {
|
||||
Text(
|
||||
text = displayHint,
|
||||
fontSize = 28.sp,
|
||||
@@ -552,7 +554,6 @@ fun PlacementGuideView(appState: AppState) {
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
}
|
||||
|
||||
// 채널 dot row (개발자 모드에서만 표시)
|
||||
@@ -1091,8 +1092,8 @@ fun PlacementGuideView(appState: AppState) {
|
||||
)
|
||||
}
|
||||
|
||||
// 하단 weight spacer — Skip 아래 빈 공간 (세 번째 분할).
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
// 하단 작은 padding 만 (Skip 이 화면 아래 가까이 오도록).
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
} // end scrollable Column
|
||||
|
||||
// Floating settings overlay (개발자 모드)
|
||||
|
||||
Reference in New Issue
Block a user