Fix tab switching in CatheterizeSheet + camera launch timing

CatheterizeSheet:
- Replace OutlinedButton with filled Button for tab selection
- Selected tab: filled color, unselected: 10% opacity background
- Tabs now reliably switch between 수기/음성/카메라
- Camera tab directly calls onCameraRequested + onDismiss

PiezoMonitoringView:
- Fix camera launch: use pendingCamera + LaunchedEffect
  to ensure ModalBottomSheet fully closes before camera opens
- Prevents state race condition between sheet dismiss and camera show

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-02 13:06:38 +09:00
parent ada507f4b4
commit b4279d7698
2 changed files with 48 additions and 22 deletions
@@ -124,27 +124,44 @@ fun CatheterizeSheet(
// 3 탭 버튼
Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(8.dp)) {
listOf(
Triple("수기", Icons.Default.Edit, Color(0xFFFF9800)),
Triple("음성", Icons.Default.SettingsVoice, Color(0xFF007AFF)),
Triple("카메라", Icons.Default.CameraAlt, Color(0xFF4CAF50))
).forEachIndexed { idx, (label, icon, color) ->
val isSelected = selectedTab == idx
OutlinedButton(
onClick = {
selectedTab = idx
if (idx == 2) { onCameraRequested(); onDismiss() }
},
modifier = Modifier.weight(1f).height(64.dp),
shape = RoundedCornerShape(12.dp),
colors = ButtonDefaults.outlinedButtonColors(
containerColor = if (isSelected) color.copy(alpha = 0.1f) else Color.Transparent
)
) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Icon(icon, null, tint = color, modifier = Modifier.size(20.dp))
Text(label, fontSize = 11.sp, color = color, fontWeight = FontWeight.SemiBold)
}
// 수기
Button(
onClick = { selectedTab = 0 },
modifier = Modifier.weight(1f).height(64.dp),
shape = RoundedCornerShape(12.dp),
colors = ButtonDefaults.buttonColors(
containerColor = if (selectedTab == 0) Color(0xFFFF9800) else Color(0xFFFF9800).copy(alpha = 0.1f)
)
) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Icon(Icons.Default.Edit, null, Modifier.size(20.dp), tint = if (selectedTab == 0) Color.White else Color(0xFFFF9800))
Text("수기", fontSize = 11.sp, fontWeight = FontWeight.SemiBold, color = if (selectedTab == 0) Color.White else Color(0xFFFF9800))
}
}
// 음성
Button(
onClick = { selectedTab = 1 },
modifier = Modifier.weight(1f).height(64.dp),
shape = RoundedCornerShape(12.dp),
colors = ButtonDefaults.buttonColors(
containerColor = if (selectedTab == 1) Color(0xFF007AFF) else Color(0xFF007AFF).copy(alpha = 0.1f)
)
) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Icon(Icons.Default.SettingsVoice, null, Modifier.size(20.dp), tint = if (selectedTab == 1) Color.White else Color(0xFF007AFF))
Text("음성", fontSize = 11.sp, fontWeight = FontWeight.SemiBold, color = if (selectedTab == 1) Color.White else Color(0xFF007AFF))
}
}
// 카메라
Button(
onClick = { onCameraRequested(); onDismiss() },
modifier = Modifier.weight(1f).height(64.dp),
shape = RoundedCornerShape(12.dp),
colors = ButtonDefaults.buttonColors(containerColor = Color(0xFF4CAF50).copy(alpha = 0.1f))
) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Icon(Icons.Default.CameraAlt, null, Modifier.size(20.dp), tint = Color(0xFF4CAF50))
Text("카메라", fontSize = 11.sp, fontWeight = FontWeight.SemiBold, color = Color(0xFF4CAF50))
}
}
}
@@ -132,13 +132,22 @@ fun PiezoMonitoringView(appState: AppState) {
)
}
// 카메라 요청 대기 상태
var pendingCamera by remember { mutableStateOf(false) }
LaunchedEffect(pendingCamera) {
if (pendingCamera) {
pendingCamera = false
showUrineCamera = true
}
}
// 배뇨 기록 시트 (수기/음성/카메라)
if (showCatheterizeSheet) {
CatheterizeSheet(
onDismiss = { showCatheterizeSheet = false },
onCameraRequested = {
showCatheterizeSheet = false
showUrineCamera = true
pendingCamera = true
},
onCatheterized = {
appState.resetLevel()