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() {
|
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 previousUrgency = bladderLevel.urgency
|
||||||
val newLevel = bladderLevel.copy()
|
|
||||||
newLevel.increment()
|
val maxVol = piezoSettings.maxVolume.toDouble()
|
||||||
bladderLevel = newLevel
|
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
|
storage.bladderLevel = bladderLevel.currentLevel
|
||||||
|
|
||||||
val record = MeasurementRecord(
|
if (recordHistory) {
|
||||||
eventType = MeasurementEventType.MEASUREMENT,
|
val record = MeasurementRecord(
|
||||||
level = bladderLevel.currentLevel,
|
eventType = MeasurementEventType.MEASUREMENT,
|
||||||
estimatedVolume = estimatedVolume,
|
level = bladderLevel.currentLevel,
|
||||||
urgencyLevel = bladderLevel.urgency,
|
estimatedVolume = volumeMl.toInt(),
|
||||||
fillPercentage = fillPercentage
|
urgencyLevel = bladderLevel.urgency,
|
||||||
)
|
fillPercentage = fillPercentage,
|
||||||
historyStore.addRecord(record)
|
)
|
||||||
|
historyStore.addRecord(record)
|
||||||
|
}
|
||||||
|
|
||||||
val newUrgency = bladderLevel.urgency
|
val newUrgency = bladderLevel.urgency
|
||||||
if (newUrgency != previousUrgency) {
|
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보다 낮을 때 색깔만 초록색으로
|
// lastVolumeMl 기반으로 두면 auto scan trimmed mean이 max보다 낮을 때 색깔만 초록색으로
|
||||||
// 떨어지고 표시값(309)은 그대로 유지되는 불일치 발생.
|
// 떨어지고 표시값(309)은 그대로 유지되는 불일치 발생.
|
||||||
if (maxVolumeMl > 0 && !isSpotInProgress) {
|
if (maxVolumeMl > 0 && !isSpotInProgress) {
|
||||||
val maxVol = appState.piezoSettings.maxVolume.toDouble()
|
// Phase A (GUARDIAN-01 · cloud-mvp deb7b17): 통합 함수 · auto-scan 은 이력 저장 안 함.
|
||||||
val pct = if (maxVol > 0) (maxVolumeMl / maxVol).coerceAtMost(1.0) else 0.0
|
appState.updateLevelFromMeasurement(maxVolumeMl, recordHistory = false)
|
||||||
val level = (pct * BladderLevel.MAX_LEVEL).toInt().coerceIn(1, BladderLevel.MAX_LEVEL)
|
|
||||||
appState.bladderLevel = appState.bladderLevel.copy(currentLevel = level)
|
|
||||||
}
|
}
|
||||||
if (autoSucceeded) autoFailCount = 0
|
if (autoSucceeded) autoFailCount = 0
|
||||||
|
|
||||||
@@ -1335,14 +1333,14 @@ fun PiezoMonitoringView(appState: AppState) {
|
|||||||
.clip(RoundedCornerShape(20.dp))
|
.clip(RoundedCornerShape(20.dp))
|
||||||
.background(tint.copy(alpha = 0.15f))
|
.background(tint.copy(alpha = 0.15f))
|
||||||
.then(if (appState.isDevMode) Modifier.clickable {
|
.then(if (appState.isDevMode) Modifier.clickable {
|
||||||
|
// Dev-mode 강제 볼륨 랜덤 (테스트).
|
||||||
val maxVol = appState.piezoSettings.maxVolume
|
val maxVol = appState.piezoSettings.maxVolume
|
||||||
val dummy = (60..(maxVol - 50).coerceAtLeast(70)).random().toDouble()
|
val dummy = (60..(maxVol - 50).coerceAtLeast(70)).random().toDouble()
|
||||||
lastVolumeMl = dummy
|
lastVolumeMl = dummy
|
||||||
maxVolumeMl = maxOf(maxVolumeMl, dummy)
|
maxVolumeMl = maxOf(maxVolumeMl, dummy)
|
||||||
displayMaxVolumeMl = maxVolumeMl
|
displayMaxVolumeMl = maxVolumeMl
|
||||||
val pct = (dummy / maxVol.toDouble()).coerceAtMost(1.0)
|
// Phase A (GUARDIAN-01): 통합 함수 사용 · 알람/이력 발동.
|
||||||
val lvl = (pct * BladderLevel.MAX_LEVEL).toInt().coerceIn(0, BladderLevel.MAX_LEVEL)
|
appState.updateLevelFromMeasurement(dummy, recordHistory = true)
|
||||||
appState.bladderLevel = appState.bladderLevel.copy(currentLevel = lvl)
|
|
||||||
} else Modifier)
|
} else Modifier)
|
||||||
.padding(horizontal = 20.dp, vertical = 8.dp)
|
.padding(horizontal = 20.dp, vertical = 8.dp)
|
||||||
) {
|
) {
|
||||||
@@ -1544,10 +1542,8 @@ fun PiezoMonitoringView(appState: AppState) {
|
|||||||
maxVolumeMl = maxOf(maxVolumeMl, trimmedResult)
|
maxVolumeMl = maxOf(maxVolumeMl, trimmedResult)
|
||||||
displayMaxVolumeMl = maxVolumeMl // Spot은 즉시 갱신
|
displayMaxVolumeMl = maxVolumeMl // Spot은 즉시 갱신
|
||||||
Log.d("PiezoMonitor", "SPOT trimmedMean=${"%.1f".format(trimmedResult)}ml from ${finalSpotVolumes.map { "%.0f".format(it) }}")
|
Log.d("PiezoMonitor", "SPOT trimmedMean=${"%.1f".format(trimmedResult)}ml from ${finalSpotVolumes.map { "%.0f".format(it) }}")
|
||||||
val maxVol = appState.piezoSettings.maxVolume.toDouble()
|
// Phase A (GUARDIAN-01): 실측 SPOT · 이력 저장 + 알람 자동.
|
||||||
val pct = if (maxVol > 0) (trimmedResult / maxVol).coerceAtMost(1.0) else 0.0
|
appState.updateLevelFromMeasurement(trimmedResult, recordHistory = true)
|
||||||
val level = (pct * BladderLevel.MAX_LEVEL).toInt().coerceIn(1, BladderLevel.MAX_LEVEL)
|
|
||||||
appState.bladderLevel = appState.bladderLevel.copy(currentLevel = level)
|
|
||||||
}
|
}
|
||||||
if (appState.isDevMode) {
|
if (appState.isDevMode) {
|
||||||
ScanLogStore.appendScanSummary(
|
ScanLogStore.appendScanSummary(
|
||||||
|
|||||||
Reference in New Issue
Block a user