feat(piezo): 도넛 위 status chip 을 posture 아이콘+텍스트로 교체
- urgency message Text 자리에 자세 chip (아이콘 + 라벨) 배치 - 색·아이콘·라벨이 currentPosture 에 따라 Crossfade 300ms 로 부드럽게 전환 - top bar 의 작은 inline posture Row 제거 (중복 표시 방지) - UNKNOWN 상태 가시성 ↑ : tint #616161 + 라벨 'Detecting' (회색 투명+'—' 대비) - Raw BLE 녹화 버튼은 dev 모드에서만 노출 (legacy 유지) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+49
-46
@@ -1115,38 +1115,9 @@ fun PiezoMonitoringView(appState: AppState) {
|
|||||||
|
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
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/)
|
// Raw BLE capture toggle — IMU/packet 디버그용 (Downloads/VesiScan_RawBLE/)
|
||||||
|
// Dev mode 에서만 노출 (legacy 유지) — 일반 사용자에겐 숨김.
|
||||||
|
if (appState.isDevMode) {
|
||||||
var rawBleCapturing by remember {
|
var rawBleCapturing by remember {
|
||||||
mutableStateOf(com.example.medilightv2android.services.RawBleLogger.isCapturing)
|
mutableStateOf(com.example.medilightv2android.services.RawBleLogger.isCapturing)
|
||||||
}
|
}
|
||||||
@@ -1177,6 +1148,7 @@ fun PiezoMonitoringView(appState: AppState) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.width(4.dp))
|
Spacer(modifier = Modifier.width(4.dp))
|
||||||
|
}
|
||||||
|
|
||||||
// Catheter count (탭하면 추가 팝업)
|
// Catheter count (탭하면 추가 팝업)
|
||||||
var showAddCatheter by remember { mutableStateOf(false) }
|
var showAddCatheter by remember { mutableStateOf(false) }
|
||||||
@@ -1276,21 +1248,37 @@ fun PiezoMonitoringView(appState: AppState) {
|
|||||||
Arrangement.spacedBy(nonDevSpacing)
|
Arrangement.spacedBy(nonDevSpacing)
|
||||||
) {
|
) {
|
||||||
|
|
||||||
// Status badge — 임상 모드에선 측정 라벨, 일반 모드에선 urgency 메시지.
|
// Status chip — 자세 아이콘+텍스트 (urgency message 자리에 배치).
|
||||||
// 빌드 114: dev 모드 한정 탭 시 더미 측정값 주입
|
// 빌드 114: dev 모드 한정 탭 시 더미 측정값 주입.
|
||||||
val clinicalSession = com.example.medilightv2android.services.ClinicalSessionStore.currentSession
|
// 색/아이콘/라벨은 currentPosture 에 따라 변하며 Crossfade 300ms 로 부드럽게 전환.
|
||||||
val statusText = if (clinicalSession != null)
|
androidx.compose.animation.Crossfade(
|
||||||
"${clinicalSession.posture.label} · ${clinicalSession.step.label}"
|
targetState = currentPosture,
|
||||||
else urgency.message
|
animationSpec = androidx.compose.animation.core.tween(300),
|
||||||
val statusColor = urgency.accentColor
|
label = "posture-chip"
|
||||||
Text(
|
) { posture ->
|
||||||
text = statusText,
|
val icon = when (posture) {
|
||||||
fontSize = (14 * fontScale).sp,
|
com.example.medilightv2android.managers.Posture.LYING -> Icons.Default.Hotel
|
||||||
fontWeight = FontWeight.Bold,
|
com.example.medilightv2android.managers.Posture.NON_LYING -> Icons.Default.AccessibilityNew
|
||||||
color = statusColor,
|
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
|
modifier = Modifier
|
||||||
.clip(RoundedCornerShape(20.dp))
|
.clip(RoundedCornerShape(20.dp))
|
||||||
.background(statusColor.copy(alpha = 0.15f))
|
.background(tint.copy(alpha = 0.15f))
|
||||||
.then(if (appState.isDevMode) Modifier.clickable {
|
.then(if (appState.isDevMode) Modifier.clickable {
|
||||||
val maxVol = appState.piezoSettings.maxVolume
|
val maxVol = appState.piezoSettings.maxVolume
|
||||||
val dummy = (60..(maxVol - 50).coerceAtLeast(70)).random().toDouble()
|
val dummy = (60..(maxVol - 50).coerceAtLeast(70)).random().toDouble()
|
||||||
@@ -1298,11 +1286,26 @@ fun PiezoMonitoringView(appState: AppState) {
|
|||||||
maxVolumeMl = maxOf(maxVolumeMl, dummy)
|
maxVolumeMl = maxOf(maxVolumeMl, dummy)
|
||||||
displayMaxVolumeMl = maxVolumeMl
|
displayMaxVolumeMl = maxVolumeMl
|
||||||
val pct = (dummy / maxVol.toDouble()).coerceAtMost(1.0)
|
val pct = (dummy / maxVol.toDouble()).coerceAtMost(1.0)
|
||||||
val level = (pct * BladderLevel.MAX_LEVEL).toInt().coerceIn(0, BladderLevel.MAX_LEVEL)
|
val lvl = (pct * BladderLevel.MAX_LEVEL).toInt().coerceIn(0, BladderLevel.MAX_LEVEL)
|
||||||
appState.bladderLevel = appState.bladderLevel.copy(currentLevel = level)
|
appState.bladderLevel = appState.bladderLevel.copy(currentLevel = lvl)
|
||||||
} else Modifier)
|
} else Modifier)
|
||||||
.padding(horizontal = 20.dp, vertical = 8.dp)
|
.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/일반 통일.
|
// Donut + Bladdy sizing — 회의 결정: dev/일반 통일.
|
||||||
val baseDonutSize = donutFitSize
|
val baseDonutSize = donutFitSize
|
||||||
|
|||||||
Reference in New Issue
Block a user