feat: Spot 3회 median + Placement 가이드 딜레이 3초
Spot: - 1회 즉시 → 3회 연속 측정(200ms 간격) → median 표시 - 측정 중 로딩 인디케이터 - 2회 이상 유효 시 median 적용 Placement: - 가이드 텍스트 최소 유지시간 4초 → 3초 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+31
-6
@@ -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<Double>()
|
||||
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)
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user