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 dab89c0..9c9e7e9 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 @@ -3,6 +3,8 @@ package com.example.medilightv2android.ui.views.monitoring import android.os.Handler import android.os.Looper import android.util.Log +import androidx.compose.runtime.rememberCoroutineScope +import kotlinx.coroutines.launch import com.example.medilightv2android.AppScreen import androidx.compose.material3.OutlinedTextField import androidx.compose.foundation.Canvas @@ -817,24 +819,47 @@ fun PiezoMonitoringView(appState: AppState) { } } - // Spot (single measurement, 1.5초 쿨다운) + // Spot (3회 측정 → median) var spotCooldown by remember { mutableStateOf(false) } + var spotInProgress by remember { mutableStateOf(false) } + val spotScope = rememberCoroutineScope() Button( onClick = { - if (!isMeasuring && !isAutoMeasuring && !spotCooldown) { - measure() + if (!isMeasuring && !isAutoMeasuring && !spotCooldown && !spotInProgress) { + spotInProgress = true spotCooldown = true - handler.postDelayed({ spotCooldown = false }, 1500) + spotScope.launch { + val spotResults = mutableListOf() + repeat(3) { + measure() + while (isMeasuring) { kotlinx.coroutines.delay(100) } + if (lastVolumeMl > 0) spotResults.add(lastVolumeMl) + kotlinx.coroutines.delay(200) + } + if (spotResults.size >= 2) { + spotResults.sort() + val median = spotResults[spotResults.size / 2] + lastVolumeMl = median + maxVolumeMl = maxOf(maxVolumeMl, median) + Log.d("PiezoMonitor", "SPOT median=${"%.1f".format(median)}ml from ${spotResults.map { "%.0f".format(it) }}") + val maxVol = appState.piezoSettings.maxVolume.toDouble() + val pct = if (maxVol > 0) (median / maxVol).coerceAtMost(1.0) else 0.0 + val level = (pct * BladderLevel.MAX_LEVEL).toInt().coerceIn(1, BladderLevel.MAX_LEVEL) + appState.bladderLevel = appState.bladderLevel.copy(currentLevel = level) + } + spotInProgress = false + handler.postDelayed({ spotCooldown = false }, 1000) + } } }, - enabled = !isMeasuring && !isAutoMeasuring && !spotCooldown, + enabled = !isMeasuring && !isAutoMeasuring && !spotCooldown && !spotInProgress, modifier = Modifier.weight(1f).height(56.dp), shape = RoundedCornerShape(14.dp), colors = ButtonDefaults.buttonColors( containerColor = urgency.gradientColors.first() ) ) { - if (isMeasuring && !isAutoMeasuring) { + if (spotInProgress) { CircularProgressIndicator(color = Color.White, modifier = Modifier.size(18.dp), strokeWidth = 2.dp) } else { Text("Spot", fontSize = 13.sp, fontWeight = FontWeight.SemiBold, color = Color.White) 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 47181e1..68da804 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 @@ -545,7 +545,7 @@ fun PlacementGuideView(appState: AppState) { val now = System.currentTimeMillis() val elapsed = now - lastHintChangeMs - if ((debounceCount >= 2 && elapsed >= 4000) || guideResult.isPass) { + if ((debounceCount >= 2 && elapsed >= 3000) || guideResult.isPass) { directionHint = guideResult.hint directionIcon = guideResult.icon placementScore = guideResult.score