UI #5: 도넛차트 크기 dev/일반 통일 + ml 폰트 키움 + Logs & Charts 일반 모드 노출

회의 피드백:
  - 도넛차트 화면 비율 이상함 → 화면에 꽉 차게
  - ml 숫자 너무 작아서 안 보임 → 키움
  - dev mode와 일반 모드 도넛 크기 다름 → 통일
  - 아래로 내렸을 때 로그/그래프 확인 가능하게

도넛 sizing 통일:
  - nonDonutBudget: dev=280 / 일반=360 → 일관 280dp (도넛에 공간 더 할당)
  - donutFitSize: coerceIn(120, 360) → (160, 420) — 화면 꽉 차게 max 키움
  - baseDonutSize: dev 분기 제거 → 모두 donutFitSize 사용
  - donutLineWidth/bladdySize: dev 분기 제거, 일반 모드 방식으로 통일
  - volFontSize: dev=18 / 일반=24 → 일관 40sp (ml 크게)

Logs & Charts 토글:
  - 토글 버튼: dev 모드 한정 → 일반 모드에서도 표시
    (라벨: dev이면 "Developer Tools", 일반이면 "Logs & Charts")
  - useScrollLayout = appState.isDevMode && showDevPanels → showDevPanels만
  - verticalScroll: dev 조건 제거 → useScrollLayout 따름
  - dev panels 본체: appState.isDevMode && showDevPanels → showDevPanels만

→ 일반 사용자도 토글로 아래 스크롤하여 BLE 로그/채널 그래프 확인 가능.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-08 18:02:44 +09:00
parent 12f1919bc6
commit f00aef50e7
@@ -81,8 +81,8 @@ fun PiezoMonitoringView(appState: AppState) {
val scanLogState by ScanLogStore.scanLog.collectAsState() val scanLogState by ScanLogStore.scanLog.collectAsState()
var devTapCount by remember { mutableIntStateOf(0) } var devTapCount by remember { mutableIntStateOf(0) }
var devLastTapTime by remember { mutableLongStateOf(0L) } var devLastTapTime by remember { mutableLongStateOf(0L) }
// 빌드 110: 스크롤 레이아웃은 dev 패널이 실제로 표시될 때만 활성화 // 회의 결정: 일반 모드에서도 dev panels(로그/그래프) 토글 가능 — 아래로 내려 확인.
val useScrollLayout = appState.isDevMode && showDevPanels val useScrollLayout = showDevPanels
// 빌드 108: Voiding 기록 후 큰 확인 다이얼로그 (1.5초 자동 닫힘) // 빌드 108: Voiding 기록 후 큰 확인 다이얼로그 (1.5초 자동 닫힘)
var showRecordedDialog by remember { mutableStateOf(false) } var showRecordedDialog by remember { mutableStateOf(false) }
if (showRecordedDialog) { if (showRecordedDialog) {
@@ -955,11 +955,10 @@ fun PiezoMonitoringView(appState: AppState) {
// 결정한다. 가로 모드 / 작은 화면에서도 progress + 다른 컨텐츠가 모두 들어오도록. // 결정한다. 가로 모드 / 작은 화면에서도 progress + 다른 컨텐츠가 모두 들어오도록.
androidx.compose.foundation.layout.BoxWithConstraints(modifier = Modifier.fillMaxSize()) { androidx.compose.foundation.layout.BoxWithConstraints(modifier = Modifier.fillMaxSize()) {
val availableH = this.maxHeight val availableH = this.maxHeight
// 비-donut 컨텐츠(status badge + 정보 카드 + 버튼 + spacing + padding) 예약치. // 회의 결정: dev/일반 도넛 크기 통일. nonDonutBudget도 통일.
// 이 값 빼고 남은 공간이 donut. val nonDonutBudget = 280.dp
val nonDonutBudget = if (appState.isDevMode) 280.dp else 360.dp // 화면에 꽉 차게 — max를 420dp까지 허용
// donut max를 키워서 큰 화면(태블릿 portrait, 가로 태블릿)에서도 답답하지 않게. val donutFitSize = (availableH - nonDonutBudget).coerceIn(160.dp, 420.dp)
val donutFitSize = (availableH - nonDonutBudget).coerceIn(120.dp, 360.dp)
// spacing 도 화면 높이에 비례 — 큰 화면에서 컨텐츠 사이 여백 넉넉히. // spacing 도 화면 높이에 비례 — 큰 화면에서 컨텐츠 사이 여백 넉넉히.
val nonDevSpacing = when { val nonDevSpacing = when {
availableH > 800.dp -> 36.dp availableH > 800.dp -> 36.dp
@@ -970,8 +969,8 @@ fun PiezoMonitoringView(appState: AppState) {
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
// dev 모드만 scroll — 일반 사용자에겐 fit-to-screen 고정 레이아웃 // 회의 결정: 일반 모드도 로그/그래프 토글로 아래 스크롤 가능
.then(if (appState.isDevMode) Modifier.verticalScroll(scrollState) else Modifier) .then(if (useScrollLayout) Modifier.verticalScroll(scrollState) else Modifier)
.padding(horizontal = hPad) .padding(horizontal = hPad)
.padding(top = if (isCompact) 8.dp else 16.dp, bottom = if (isCompact) 16.dp else 32.dp), .padding(top = if (isCompact) 8.dp else 16.dp, bottom = if (isCompact) 16.dp else 32.dp),
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
@@ -1009,25 +1008,13 @@ fun PiezoMonitoringView(appState: AppState) {
.padding(horizontal = 20.dp, vertical = 8.dp) .padding(horizontal = 20.dp, vertical = 8.dp)
) )
// Donut + Bladdy sizing — Charles의 height-aware donutFitSize [833c110] // Donut + Bladdy sizing — 회의 결정: dev/일반 통일.
// 우리 UX Phase 1의 의도(Volume 폰트 축소)도 Charles의 24sp로 이미 충족됨. val baseDonutSize = donutFitSize
val baseDonutSize = if (appState.isDevMode) {
if (isCompact) 192.dp else 244.dp
} else {
donutFitSize
}
val donutSize = baseDonutSize * 0.95f val donutSize = baseDonutSize * 0.95f
val donutLineWidth = if (appState.isDevMode) { val donutLineWidth = if (isCompact) 26.dp else 34.dp
if (isCompact) 22.dp else 30.dp val bladdySize = donutSize * 0.85f
} else { // ml 폰트 키움 — 회의 피드백 "숫자가 너무 작아서 안보임"
if (isCompact) 26.dp else 34.dp val volFontSize = 40.sp
}
val bladdySize = if (appState.isDevMode) {
if (isCompact) 80.dp else 110.dp
} else {
donutSize * 0.85f // donut 내부에 항상 들어가는 크기
}
val volFontSize = if (appState.isDevMode) 18.sp else 24.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)
@@ -1231,8 +1218,8 @@ fun PiezoMonitoringView(appState: AppState) {
} }
} }
// ── Developer Tools toggle (개발자 모드에서만 표시) ── // ── Logs & Charts toggle (회의 결정: 일반 모드도 접근 가능) ──
if (appState.isDevMode) Button( Button(
onClick = { showDevPanels = !showDevPanels }, onClick = { showDevPanels = !showDevPanels },
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(8.dp), shape = RoundedCornerShape(8.dp),
@@ -1242,8 +1229,11 @@ fun PiezoMonitoringView(appState: AppState) {
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(6.dp) horizontalArrangement = Arrangement.spacedBy(6.dp)
) { ) {
Icon(Icons.Default.Build, "Dev", tint = Color.White, modifier = Modifier.size(14.dp)) Icon(Icons.Default.Build, "Logs", tint = Color.White, modifier = Modifier.size(14.dp))
Text("Developer Tools", fontSize = 12.sp, fontWeight = FontWeight.SemiBold, color = Color.White) Text(
if (appState.isDevMode) "Developer Tools" else "Logs & Charts",
fontSize = 12.sp, fontWeight = FontWeight.SemiBold, color = Color.White
)
Spacer(modifier = Modifier.weight(1f)) Spacer(modifier = Modifier.weight(1f))
Icon( Icon(
if (showDevPanels) Icons.Default.KeyboardArrowUp else Icons.Default.KeyboardArrowDown, if (showDevPanels) Icons.Default.KeyboardArrowUp else Icons.Default.KeyboardArrowDown,
@@ -1252,7 +1242,8 @@ fun PiezoMonitoringView(appState: AppState) {
} }
} }
if (appState.isDevMode && showDevPanels) { // 회의 결정: 일반 모드도 로그/그래프 접근 가능 (isDevMode 조건 제거)
if (showDevPanels) {
ChannelPanel( ChannelPanel(
lastMultiChannelResult = lastMultiChannelResult, lastMultiChannelResult = lastMultiChannelResult,
analyzer = analyzer, analyzer = analyzer,