From 4e85091b9024a8b652f8f0f266fd6c496cd1a17a Mon Sep 17 00:00:00 2001 From: jjangddu Date: Wed, 24 Jun 2026 16:36:20 +0900 Subject: [PATCH] =?UTF-8?q?feat(alignment):=20=EC=84=BC=EC=84=9C=20detach?= =?UTF-8?q?=20=EC=8B=9C=20=EC=A3=BC=ED=99=A9=20=EA=B2=BD=EA=B3=A0=20?= =?UTF-8?q?=ED=8C=9D=EC=97=85=20=E2=80=94=20=ED=85=8D=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=EB=A7=8C=EC=9C=BC=EB=A1=9C=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=EC=9E=90=EA=B0=80=20=EB=86=93=EC=B9=98=EB=8D=98=20?= =?UTF-8?q?=EB=AC=B8=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - DetachmentDetection.isDetached 가 true 가 되는 rising edge 에 Dialog 팝업 - wakeup 알람과 동일한 주황(Material 500) 톤 + Warning 아이콘 - 재부착 시 팝업 자동 dismiss (사용자 확인 부담 ↓) - 기존 directionHint / LED mode 4 / phase reset 동작은 그대로 유지 Co-Authored-By: Claude Opus 4.7 --- .../ui/views/monitoring/PlacementGuideView.kt | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/PlacementGuideView.kt b/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/PlacementGuideView.kt index 14fcc58..6a84c6e 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/PlacementGuideView.kt +++ b/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/PlacementGuideView.kt @@ -161,6 +161,10 @@ fun PlacementGuideView(appState: AppState) { onDispose { bleManager.sendLedMode(0) } } + // Detachment alert (rising edge → 팝업, 재부착 시 자동 해제) + var showDetachAlert by remember { mutableStateOf(false) } + var prevDetached by remember { mutableStateOf(false) } + val detectedCount = channelDetected.count { it } val isGreenZone = isLocked || placementScore >= 70 @@ -176,6 +180,53 @@ fun PlacementGuideView(appState: AppState) { 1f to MlPrimary.copy(alpha = 0.10f) ) + // 센서 분리 알림 (주황 warning) — wakeup 알람과 동일 패턴 + if (showDetachAlert) { + androidx.compose.ui.window.Dialog( + onDismissRequest = { }, + properties = androidx.compose.ui.window.DialogProperties( + dismissOnBackPress = false, dismissOnClickOutside = false + ) + ) { + Box( + modifier = Modifier + .fillMaxWidth(0.92f) + .clip(RoundedCornerShape(24.dp)) + .background(Color(0xFFFF9800)) // Material Orange 500 + .padding(horizontal = 28.dp, vertical = 36.dp), + contentAlignment = Alignment.Center + ) { + Column(horizontalAlignment = Alignment.CenterHorizontally) { + Icon(Icons.Default.Warning, contentDescription = null, + tint = Color.White, modifier = Modifier.size(56.dp)) + Spacer(modifier = Modifier.height(12.dp)) + Text("센서가 분리되었습니다", fontSize = 26.sp, + fontWeight = FontWeight.ExtraBold, color = Color.White, + textAlign = TextAlign.Center) + Spacer(modifier = Modifier.height(6.dp)) + Text("Sensor detached", fontSize = 16.sp, + fontWeight = FontWeight.Medium, color = Color.White.copy(alpha = 0.9f), + textAlign = TextAlign.Center) + Spacer(modifier = Modifier.height(8.dp)) + Text("치골 위쪽에 다시 위치시켜 주세요", + fontSize = 14.sp, color = Color.White.copy(alpha = 0.85f), + textAlign = TextAlign.Center) + Spacer(modifier = Modifier.height(24.dp)) + Button( + onClick = { showDetachAlert = false }, + colors = ButtonDefaults.buttonColors( + containerColor = Color.White, contentColor = Color(0xFFFF9800) + ), + modifier = Modifier.fillMaxWidth().height(56.dp), + shape = RoundedCornerShape(14.dp) + ) { + Text("확인", fontSize = 20.sp, fontWeight = FontWeight.Bold) + } + } + } + } + } + Column( modifier = Modifier .fillMaxSize() @@ -756,6 +807,10 @@ fun PlacementGuideView(appState: AppState) { val fullCh = channels.filter { it.buffer.size >= 20 } val buffers = channels.sortedBy { it.channel }.map { it.buffer } val detachResult = if (fullCh.size >= 6) DetachmentDetection.detect(buffers) else null + val nowDetached = detachResult?.isDetached == true + if (nowDetached && !prevDetached) showDetachAlert = true // rising edge → 팝업 + if (!nowDetached && prevDetached) showDetachAlert = false // 재부착 → 자동 dismiss + prevDetached = nowDetached if (detachResult != null && detachResult.isDetached) { directionHint = "Sensor detached. Restart above pubic bone."