UI: 도넛차트 비율 기반 레이아웃 (태블릿 대응)

고정 dp → 화면 너비 비율:
- 도넛: 85% (dev: 65%), 선 두께: 도넛×8%
- Bladdy: 도넛×55% (dev: 30%)
- 볼륨 폰트: 화면×6%
- 패딩: 화면×5%, 간격: 화면×8%
- 버튼: 화면×15% (50~70dp clamp)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-11 11:02:51 +09:00
parent 6287f21a05
commit fab018f19e
@@ -730,7 +730,7 @@ fun PiezoMonitoringView(appState: AppState) {
.background(urgency.backgroundColor) .background(urgency.backgroundColor)
) { ) {
// Top bar // Top bar
val hPad = if (isCompact) 12.dp else 24.dp val hPad = (screenWidth * 0.05f).dp
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@@ -854,7 +854,7 @@ fun PiezoMonitoringView(appState: AppState) {
verticalArrangement = if (appState.isDevMode) verticalArrangement = if (appState.isDevMode)
Arrangement.spacedBy(if (isCompact) 12.dp else 20.dp) Arrangement.spacedBy(if (isCompact) 12.dp else 20.dp)
else else
Arrangement.spacedBy(if (isCompact) 32.dp else 40.dp) Arrangement.spacedBy((screenWidth * 0.08f).dp.coerceIn(20.dp, 48.dp))
) { ) {
// Status badge (항상 urgency 메시지) // Status badge (항상 urgency 메시지)
@@ -871,12 +871,16 @@ fun PiezoMonitoringView(appState: AppState) {
.padding(horizontal = 20.dp, vertical = 8.dp) .padding(horizontal = 20.dp, vertical = 8.dp)
) )
// Donut chart with Bladdy // Donut chart with Bladdy — 화면 비율 기반
val donutSize = if (appState.isDevMode) { val screenWidthDp = screenWidth.dp
if (isCompact) 220.dp else 280.dp val donutRatio = if (appState.isDevMode) 0.65f else 0.85f
} else { val donutSize = screenWidthDp * donutRatio
if (isCompact) 300.dp else 360.dp // 일반 모드: 화면 거의 가득 val lineWidthRatio = if (appState.isDevMode) 0.07f else 0.08f
} val donutLineWidth = donutSize * lineWidthRatio
val bladdyRatio = if (appState.isDevMode) 0.30f else 0.55f
val bladdySize = donutSize * bladdyRatio
val volFontSize = if (appState.isDevMode) 18.sp else (screenWidth * 0.06f).sp
val maxVolumeForDonut = appState.piezoSettings.maxVolume.toDouble() val maxVolumeForDonut = appState.piezoSettings.maxVolume.toDouble()
val donutProgress = if (maxVolumeForDonut > 0 && maxVolumeMl > 0) val donutProgress = if (maxVolumeForDonut > 0 && maxVolumeMl > 0)
(maxVolumeMl / maxVolumeForDonut).coerceIn(0.0, 1.0) else 0.0 (maxVolumeMl / maxVolumeForDonut).coerceIn(0.0, 1.0) else 0.0
@@ -885,7 +889,7 @@ fun PiezoMonitoringView(appState: AppState) {
if (!appState.isDevMode) { if (!appState.isDevMode) {
Box( Box(
modifier = Modifier modifier = Modifier
.size(donutSize - 50.dp) .size(donutSize * 0.85f)
.clip(CircleShape) .clip(CircleShape)
.background(Color.White.copy(alpha = 0.5f)) .background(Color.White.copy(alpha = 0.5f))
) )
@@ -893,11 +897,7 @@ fun PiezoMonitoringView(appState: AppState) {
DonutChartView( DonutChartView(
progress = donutProgress, progress = donutProgress,
urgency = urgency, urgency = urgency,
lineWidth = if (appState.isDevMode) { lineWidth = donutLineWidth,
if (isCompact) 22.dp else 30.dp
} else {
if (isCompact) 26.dp else 34.dp
},
size = donutSize size = donutSize
) )
// Bladdy + 볼륨 (정중앙) // Bladdy + 볼륨 (정중앙)
@@ -906,14 +906,8 @@ fun PiezoMonitoringView(appState: AppState) {
verticalArrangement = Arrangement.Center, verticalArrangement = Arrangement.Center,
modifier = Modifier.matchParentSize() modifier = Modifier.matchParentSize()
) { ) {
val bladdySize = if (appState.isDevMode) {
if (isCompact) 80.dp else 110.dp
} else {
if (isCompact) 180.dp else 220.dp
}
BladdyRiveView(urgency = urgency, size = bladdySize) BladdyRiveView(urgency = urgency, size = bladdySize)
Spacer(modifier = Modifier.height(4.dp)) Spacer(modifier = Modifier.height(4.dp))
val volFontSize = if (appState.isDevMode) 18.sp else 24.sp
Text( Text(
if (displayMaxVolumeMl > 0) "${"%.0f".format(displayMaxVolumeMl)} mL" else "${appState.estimatedVolume} mL", if (displayMaxVolumeMl > 0) "${"%.0f".format(displayMaxVolumeMl)} mL" else "${appState.estimatedVolume} mL",
fontSize = volFontSize, fontSize = volFontSize,
@@ -940,7 +934,7 @@ fun PiezoMonitoringView(appState: AppState) {
} }
// Control buttons: Void/Catheterize / Auto / Spot // Control buttons: Void/Catheterize / Auto / Spot
val btnHeight = if (appState.isDevMode) 56.dp else 62.dp val btnHeight = (screenWidth * 0.15f).dp.coerceIn(50.dp, 70.dp)
Row(horizontalArrangement = Arrangement.spacedBy(if (appState.isDevMode) 8.dp else 10.dp)) { Row(horizontalArrangement = Arrangement.spacedBy(if (appState.isDevMode) 8.dp else 10.dp)) {
// Void / Catheterize — 즉시 카테터 1개 감소 + 기록 // Void / Catheterize — 즉시 카테터 1개 감소 + 기록
Button( Button(