feat(state): Phase A · 실측 경로 알람/이력 통합 (cloud-mvp deb7b17 이식)
Guardian 공유 이전 선행 작업 (GUARDIAN-01 §5 Phase A).
이전 버그: 데모 경로 (incrementLevel) 만 NotificationService · HistoryStore 호출.
실측 (BLE) 경로는 bladderLevel = ...copy(currentLevel = level) 로 직접
대입 → 알람 미발생 · 이력 미저장.
수정:
- AppState.updateLevelFromMeasurement(volumeMl, recordHistory) 신규 함수
· bladderLevel 계산·갱신·storage 동기화
· MeasurementRecord 저장 (recordHistory=true 시)
· Urgency 변화 시 sendUrgencyNotification (중복 억제는 기존 로직 재사용)
- AppState.incrementLevel(): 데모 1단계 증가를 신규 함수로 위임
- PiezoMonitoringView 3곳 (L578/L1345/L1550) 직접 대입 → 신규 함수 호출
· auto-scan 갱신: recordHistory=false (폭탄 방지)
· SPOT trimmed 실측: recordHistory=true
· dev-mode tap: recordHistory=true
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -203,24 +203,46 @@ class AppState(private val context: Context) {
|
||||
}
|
||||
|
||||
fun incrementLevel() {
|
||||
// 데모 · 1단계 증가 — 신규 함수로 위임 (cloud-mvp deb7b17 이식).
|
||||
val currentVolume = estimatedVolume
|
||||
val stepVolume = piezoSettings.maxVolume.toDouble() / BladderLevel.MAX_LEVEL
|
||||
updateLevelFromMeasurement(currentVolume + stepVolume, recordHistory = true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Phase A · 실측 경로 통합 (GUARDIAN-01, 2026-08-03 · cloud-mvp deb7b17 이식).
|
||||
*
|
||||
* 이전: PiezoMonitoringView 3곳 bladderLevel 직접 대입 →
|
||||
* NotificationService · MeasurementHistoryStore 우회 → 실사용 시 알람 미발생.
|
||||
* 이제: 실측/데모 경로 모두 이 함수로 일원화. 알람 · 이력 자동.
|
||||
*
|
||||
* @param volumeMl 실측 부피 (mL)
|
||||
* @param recordHistory 이력 저장 여부 (기본 true · auto-scan 갱신 시 false 로 폭탄 방지)
|
||||
*/
|
||||
fun updateLevelFromMeasurement(volumeMl: Double, recordHistory: Boolean = true) {
|
||||
val previousUrgency = bladderLevel.urgency
|
||||
val newLevel = bladderLevel.copy()
|
||||
newLevel.increment()
|
||||
bladderLevel = newLevel
|
||||
|
||||
val maxVol = piezoSettings.maxVolume.toDouble()
|
||||
val pct = if (maxVol > 0) (volumeMl / maxVol).coerceAtMost(1.0) else 0.0
|
||||
val level = (pct * BladderLevel.MAX_LEVEL).toInt().coerceIn(0, BladderLevel.MAX_LEVEL)
|
||||
|
||||
bladderLevel = bladderLevel.copy(currentLevel = level)
|
||||
storage.bladderLevel = bladderLevel.currentLevel
|
||||
|
||||
val record = MeasurementRecord(
|
||||
eventType = MeasurementEventType.MEASUREMENT,
|
||||
level = bladderLevel.currentLevel,
|
||||
estimatedVolume = estimatedVolume,
|
||||
urgencyLevel = bladderLevel.urgency,
|
||||
fillPercentage = fillPercentage
|
||||
)
|
||||
historyStore.addRecord(record)
|
||||
if (recordHistory) {
|
||||
val record = MeasurementRecord(
|
||||
eventType = MeasurementEventType.MEASUREMENT,
|
||||
level = bladderLevel.currentLevel,
|
||||
estimatedVolume = volumeMl.toInt(),
|
||||
urgencyLevel = bladderLevel.urgency,
|
||||
fillPercentage = fillPercentage,
|
||||
)
|
||||
historyStore.addRecord(record)
|
||||
}
|
||||
|
||||
val newUrgency = bladderLevel.urgency
|
||||
if (newUrgency != previousUrgency) {
|
||||
notificationService.sendUrgencyNotification(newUrgency, estimatedVolume)
|
||||
notificationService.sendUrgencyNotification(newUrgency, volumeMl.toInt())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+7
-11
@@ -572,10 +572,8 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
// lastVolumeMl 기반으로 두면 auto scan trimmed mean이 max보다 낮을 때 색깔만 초록색으로
|
||||
// 떨어지고 표시값(309)은 그대로 유지되는 불일치 발생.
|
||||
if (maxVolumeMl > 0 && !isSpotInProgress) {
|
||||
val maxVol = appState.piezoSettings.maxVolume.toDouble()
|
||||
val pct = if (maxVol > 0) (maxVolumeMl / 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)
|
||||
// Phase A (GUARDIAN-01 · cloud-mvp deb7b17): 통합 함수 · auto-scan 은 이력 저장 안 함.
|
||||
appState.updateLevelFromMeasurement(maxVolumeMl, recordHistory = false)
|
||||
}
|
||||
if (autoSucceeded) autoFailCount = 0
|
||||
|
||||
@@ -1335,14 +1333,14 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
.clip(RoundedCornerShape(20.dp))
|
||||
.background(tint.copy(alpha = 0.15f))
|
||||
.then(if (appState.isDevMode) Modifier.clickable {
|
||||
// Dev-mode 강제 볼륨 랜덤 (테스트).
|
||||
val maxVol = appState.piezoSettings.maxVolume
|
||||
val dummy = (60..(maxVol - 50).coerceAtLeast(70)).random().toDouble()
|
||||
lastVolumeMl = dummy
|
||||
maxVolumeMl = maxOf(maxVolumeMl, dummy)
|
||||
displayMaxVolumeMl = maxVolumeMl
|
||||
val pct = (dummy / maxVol.toDouble()).coerceAtMost(1.0)
|
||||
val lvl = (pct * BladderLevel.MAX_LEVEL).toInt().coerceIn(0, BladderLevel.MAX_LEVEL)
|
||||
appState.bladderLevel = appState.bladderLevel.copy(currentLevel = lvl)
|
||||
// Phase A (GUARDIAN-01): 통합 함수 사용 · 알람/이력 발동.
|
||||
appState.updateLevelFromMeasurement(dummy, recordHistory = true)
|
||||
} else Modifier)
|
||||
.padding(horizontal = 20.dp, vertical = 8.dp)
|
||||
) {
|
||||
@@ -1544,10 +1542,8 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
maxVolumeMl = maxOf(maxVolumeMl, trimmedResult)
|
||||
displayMaxVolumeMl = maxVolumeMl // Spot은 즉시 갱신
|
||||
Log.d("PiezoMonitor", "SPOT trimmedMean=${"%.1f".format(trimmedResult)}ml from ${finalSpotVolumes.map { "%.0f".format(it) }}")
|
||||
val maxVol = appState.piezoSettings.maxVolume.toDouble()
|
||||
val pct = if (maxVol > 0) (trimmedResult / 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)
|
||||
// Phase A (GUARDIAN-01): 실측 SPOT · 이력 저장 + 알람 자동.
|
||||
appState.updateLevelFromMeasurement(trimmedResult, recordHistory = true)
|
||||
}
|
||||
if (appState.isDevMode) {
|
||||
ScanLogStore.appendScanSummary(
|
||||
|
||||
Reference in New Issue
Block a user