diff --git a/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/PiezoMonitoringView.kt b/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/PiezoMonitoringView.kt index b339a28..4ed1629 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/PiezoMonitoringView.kt +++ b/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/PiezoMonitoringView.kt @@ -1115,68 +1115,40 @@ fun PiezoMonitoringView(appState: AppState) { Spacer(modifier = Modifier.width(8.dp)) - // Posture icon (Phase 1) — flowchart-based 자세 분류 결과 표시. - // SUPINE/SITTING/STANDING/UNKNOWN 에 따라 아이콘+색 변경. - val postureIcon = when (currentPosture) { - com.example.medilightv2android.managers.Posture.LYING -> Icons.Default.Hotel - com.example.medilightv2android.managers.Posture.NON_LYING -> Icons.Default.AccessibilityNew - com.example.medilightv2android.managers.Posture.WALKING -> Icons.Default.DirectionsWalk - com.example.medilightv2android.managers.Posture.UNKNOWN -> Icons.Default.HelpOutline - } - val postureTint = when (currentPosture) { - com.example.medilightv2android.managers.Posture.LYING -> Color(0xFF2196F3) - com.example.medilightv2android.managers.Posture.NON_LYING -> Color(0xFF4CAF50) - com.example.medilightv2android.managers.Posture.WALKING -> Color(0xFFD32F2F) - com.example.medilightv2android.managers.Posture.UNKNOWN -> Color.Gray.copy(alpha = 0.5f) - } - val postureLabel = when (currentPosture) { - com.example.medilightv2android.managers.Posture.LYING -> "Lying" - com.example.medilightv2android.managers.Posture.NON_LYING -> "Upright" - com.example.medilightv2android.managers.Posture.WALKING -> "Walking" - com.example.medilightv2android.managers.Posture.UNKNOWN -> "—" - } - Row(verticalAlignment = Alignment.CenterVertically) { - Icon( - postureIcon, contentDescription = postureLabel, - tint = postureTint, modifier = Modifier.size(20.dp), - ) - Spacer(modifier = Modifier.width(3.dp)) - Text(postureLabel, fontSize = (11 * fontScale).sp, - fontWeight = FontWeight.SemiBold, color = postureTint) - } - Spacer(modifier = Modifier.width(8.dp)) - // Raw BLE capture toggle — IMU/packet 디버그용 (Downloads/VesiScan_RawBLE/) - var rawBleCapturing by remember { - mutableStateOf(com.example.medilightv2android.services.RawBleLogger.isCapturing) + // Dev mode 에서만 노출 (legacy 유지) — 일반 사용자에겐 숨김. + if (appState.isDevMode) { + var rawBleCapturing by remember { + mutableStateOf(com.example.medilightv2android.services.RawBleLogger.isCapturing) + } + IconButton( + onClick = { + if (rawBleCapturing) { + val f = com.example.medilightv2android.services.RawBleLogger.stopCapture() + val n = com.example.medilightv2android.services.RawBleLogger.count + rawBleCapturing = false + android.widget.Toast.makeText(context, + "Raw BLE: $n packets saved to ${f?.name}", + android.widget.Toast.LENGTH_LONG).show() + } else { + val f = com.example.medilightv2android.services.RawBleLogger.startCapture() + rawBleCapturing = true + android.widget.Toast.makeText(context, + "Raw BLE capture started → ${f.name}", + android.widget.Toast.LENGTH_SHORT).show() + } + }, + modifier = Modifier.size(28.dp) + ) { + Icon( + if (rawBleCapturing) Icons.Default.RadioButtonChecked else Icons.Default.FiberManualRecord, + contentDescription = if (rawBleCapturing) "Stop raw BLE capture" else "Start raw BLE capture", + tint = if (rawBleCapturing) Color.Red else Color.Gray.copy(alpha = 0.5f), + modifier = Modifier.size(20.dp) + ) + } + Spacer(modifier = Modifier.width(4.dp)) } - IconButton( - onClick = { - if (rawBleCapturing) { - val f = com.example.medilightv2android.services.RawBleLogger.stopCapture() - val n = com.example.medilightv2android.services.RawBleLogger.count - rawBleCapturing = false - android.widget.Toast.makeText(context, - "Raw BLE: $n packets saved to ${f?.name}", - android.widget.Toast.LENGTH_LONG).show() - } else { - val f = com.example.medilightv2android.services.RawBleLogger.startCapture() - rawBleCapturing = true - android.widget.Toast.makeText(context, - "Raw BLE capture started → ${f.name}", - android.widget.Toast.LENGTH_SHORT).show() - } - }, - modifier = Modifier.size(28.dp) - ) { - Icon( - if (rawBleCapturing) Icons.Default.RadioButtonChecked else Icons.Default.FiberManualRecord, - contentDescription = if (rawBleCapturing) "Stop raw BLE capture" else "Start raw BLE capture", - tint = if (rawBleCapturing) Color.Red else Color.Gray.copy(alpha = 0.5f), - modifier = Modifier.size(20.dp) - ) - } - Spacer(modifier = Modifier.width(4.dp)) // Catheter count (탭하면 추가 팝업) var showAddCatheter by remember { mutableStateOf(false) } @@ -1276,33 +1248,64 @@ fun PiezoMonitoringView(appState: AppState) { Arrangement.spacedBy(nonDevSpacing) ) { - // Status badge — 임상 모드에선 측정 라벨, 일반 모드에선 urgency 메시지. - // 빌드 114: dev 모드 한정 탭 시 더미 측정값 주입 - val clinicalSession = com.example.medilightv2android.services.ClinicalSessionStore.currentSession - val statusText = if (clinicalSession != null) - "${clinicalSession.posture.label} · ${clinicalSession.step.label}" - else urgency.message - val statusColor = urgency.accentColor - Text( - text = statusText, - fontSize = (14 * fontScale).sp, - fontWeight = FontWeight.Bold, - color = statusColor, - modifier = Modifier - .clip(RoundedCornerShape(20.dp)) - .background(statusColor.copy(alpha = 0.15f)) - .then(if (appState.isDevMode) Modifier.clickable { - val maxVol = appState.piezoSettings.maxVolume - val dummy = (60..(maxVol - 50).coerceAtLeast(70)).random().toDouble() - lastVolumeMl = dummy - maxVolumeMl = maxOf(maxVolumeMl, dummy) - displayMaxVolumeMl = maxVolumeMl - val pct = (dummy / maxVol.toDouble()).coerceAtMost(1.0) - val level = (pct * BladderLevel.MAX_LEVEL).toInt().coerceIn(0, BladderLevel.MAX_LEVEL) - appState.bladderLevel = appState.bladderLevel.copy(currentLevel = level) - } else Modifier) - .padding(horizontal = 20.dp, vertical = 8.dp) - ) + // Status chip — 자세 아이콘+텍스트 (urgency message 자리에 배치). + // 빌드 114: dev 모드 한정 탭 시 더미 측정값 주입. + // 색/아이콘/라벨은 currentPosture 에 따라 변하며 Crossfade 300ms 로 부드럽게 전환. + androidx.compose.animation.Crossfade( + targetState = currentPosture, + animationSpec = androidx.compose.animation.core.tween(300), + label = "posture-chip" + ) { posture -> + val icon = when (posture) { + com.example.medilightv2android.managers.Posture.LYING -> Icons.Default.Hotel + com.example.medilightv2android.managers.Posture.NON_LYING -> Icons.Default.AccessibilityNew + com.example.medilightv2android.managers.Posture.WALKING -> Icons.Default.DirectionsWalk + com.example.medilightv2android.managers.Posture.UNKNOWN -> Icons.Default.HelpOutline + } + val tint = when (posture) { + com.example.medilightv2android.managers.Posture.LYING -> Color(0xFF2196F3) + com.example.medilightv2android.managers.Posture.NON_LYING -> Color(0xFF4CAF50) + com.example.medilightv2android.managers.Posture.WALKING -> Color(0xFFD32F2F) + com.example.medilightv2android.managers.Posture.UNKNOWN -> Color(0xFF616161) // 진한 회색 — 가시성 확보 + } + val label = when (posture) { + com.example.medilightv2android.managers.Posture.LYING -> "Lying" + com.example.medilightv2android.managers.Posture.NON_LYING -> "Upright" + com.example.medilightv2android.managers.Posture.WALKING -> "Walking" + com.example.medilightv2android.managers.Posture.UNKNOWN -> "Detecting" + } + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .clip(RoundedCornerShape(20.dp)) + .background(tint.copy(alpha = 0.15f)) + .then(if (appState.isDevMode) Modifier.clickable { + val maxVol = appState.piezoSettings.maxVolume + val dummy = (60..(maxVol - 50).coerceAtLeast(70)).random().toDouble() + lastVolumeMl = dummy + maxVolumeMl = maxOf(maxVolumeMl, dummy) + displayMaxVolumeMl = maxVolumeMl + val pct = (dummy / maxVol.toDouble()).coerceAtMost(1.0) + val lvl = (pct * BladderLevel.MAX_LEVEL).toInt().coerceIn(0, BladderLevel.MAX_LEVEL) + appState.bladderLevel = appState.bladderLevel.copy(currentLevel = lvl) + } else Modifier) + .padding(horizontal = 20.dp, vertical = 8.dp) + ) { + Icon( + icon, + contentDescription = label, + tint = tint, + modifier = Modifier.size(22.dp) + ) + Spacer(modifier = Modifier.width(6.dp)) + Text( + label, + fontSize = (16 * fontScale).sp, + fontWeight = FontWeight.Bold, + color = tint + ) + } + } // Donut + Bladdy sizing — 회의 결정: dev/일반 통일. val baseDonutSize = donutFitSize