refactor: 데모 브랜치 패키지 통일 com.example.medilightv2android → com.medithings.vesiscan
사용자앱 (feature/tab-navigation) 과 패키지 이름 일치. namespace + applicationId 둘 다 com.medithings.vesiscan 로 변경 (기존 데모 앱은 재설치 필요). ## 변경 범위 - Kotlin 148 파일: package + import 문 (714 occurrences) - 디렉토리 이동: com/example/medilightv2android → com/medithings/vesiscan (main, test, androidTest 각각) - app/build.gradle.kts: namespace, applicationId - docs/FLAVOR_DEMO_STABLE.md: 참조 갱신 - V41DetectorCH4Test: BvDispatchResult.methodChosen → method (dto field name fix) ## 주의 - applicationId 가 바뀌므로 기존 데모 앱 (com.example.medilightv2android.demo) 은 Android 관점에서 다른 앱으로 취급 — 재설치 시 PIN/설정 초기화됨. - Fresh install 권장. 기존 앱 (com.example...) 은 별도로 uninstall 필요. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+2
-2
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android
|
||||
package com.medithings.vesiscan
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
@@ -19,6 +19,6 @@ class ExampleInstrumentedTest {
|
||||
fun useAppContext() {
|
||||
// Context of the app under test.
|
||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
assertEquals("com.example.medilightv2android", appContext.packageName)
|
||||
assertEquals("com.medithings.vesiscan", appContext.packageName)
|
||||
}
|
||||
}
|
||||
+6
-6
@@ -1,14 +1,14 @@
|
||||
package com.example.medilightv2android
|
||||
package com.medithings.vesiscan
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import com.example.medilightv2android.ble.BleManager
|
||||
import com.example.medilightv2android.managers.NirsManager
|
||||
import com.example.medilightv2android.models.*
|
||||
import com.example.medilightv2android.services.*
|
||||
import com.medithings.vesiscan.ble.BleManager
|
||||
import com.medithings.vesiscan.managers.NirsManager
|
||||
import com.medithings.vesiscan.models.*
|
||||
import com.medithings.vesiscan.services.*
|
||||
|
||||
enum class AppScreen {
|
||||
ONBOARDING, CONSENT, REGISTRATION, HOME, SENSOR_SELECT, DEVICE_SCAN,
|
||||
@@ -121,7 +121,7 @@ class AppState(private val context: Context) {
|
||||
fun deviceConnected() {
|
||||
isDeviceConnected = true
|
||||
// 임상 모드에서 BLE 연결 시 ClinicalHome으로 복귀 (Personalization 우회)
|
||||
if (com.example.medilightv2android.services.ClinicalSessionStore.inClinicalFlow) {
|
||||
if (com.medithings.vesiscan.services.ClinicalSessionStore.inClinicalFlow) {
|
||||
currentScreen = AppScreen.CLINICAL_HOME
|
||||
return
|
||||
}
|
||||
+32
-32
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android
|
||||
package com.medithings.vesiscan
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
@@ -20,34 +20,34 @@ import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import app.rive.runtime.kotlin.core.Rive
|
||||
import com.example.medilightv2android.services.KeychainService
|
||||
import com.example.medilightv2android.services.NotificationService
|
||||
import com.example.medilightv2android.R
|
||||
import com.example.medilightv2android.ui.theme.Medilightv2androidTheme
|
||||
import com.example.medilightv2android.ui.views.calibration.CalibrationView
|
||||
import com.example.medilightv2android.ui.views.connection.DeviceScanView
|
||||
import com.example.medilightv2android.ui.views.history.MeasurementHistoryView
|
||||
import com.example.medilightv2android.ui.views.home.HomeView
|
||||
import com.example.medilightv2android.ui.views.monitoring.PlacementGuideView
|
||||
import com.example.medilightv2android.ui.views.monitoring.PiezoMonitoringView
|
||||
import com.example.medilightv2android.ui.views.monitoring.VivamyoMonitoringView
|
||||
import com.example.medilightv2android.ui.views.monitoring.UrineCameraScreen
|
||||
import com.example.medilightv2android.ui.views.monitoring.VoidingDiaryView
|
||||
import com.example.medilightv2android.ui.views.onboarding.OnboardingView
|
||||
import com.example.medilightv2android.ui.views.personalization.PiezoPersonalizationView
|
||||
import com.example.medilightv2android.ui.views.pin.PinMode
|
||||
import com.example.medilightv2android.ui.views.pin.PinView
|
||||
import com.example.medilightv2android.ui.views.registration.RegistrationView
|
||||
import com.example.medilightv2android.ui.views.consent.ConsentView
|
||||
import com.example.medilightv2android.ui.views.reminder.ReminderSettingsView
|
||||
import com.example.medilightv2android.ui.views.sensorselect.SensorSelectView
|
||||
import com.example.medilightv2android.ui.views.clinical.ClinicalHomeView
|
||||
import com.example.medilightv2android.ui.views.clinical.ClinicalLiveView
|
||||
import com.medithings.vesiscan.services.KeychainService
|
||||
import com.medithings.vesiscan.services.NotificationService
|
||||
import com.medithings.vesiscan.R
|
||||
import com.medithings.vesiscan.ui.theme.Medilightv2androidTheme
|
||||
import com.medithings.vesiscan.ui.views.calibration.CalibrationView
|
||||
import com.medithings.vesiscan.ui.views.connection.DeviceScanView
|
||||
import com.medithings.vesiscan.ui.views.history.MeasurementHistoryView
|
||||
import com.medithings.vesiscan.ui.views.home.HomeView
|
||||
import com.medithings.vesiscan.ui.views.monitoring.PlacementGuideView
|
||||
import com.medithings.vesiscan.ui.views.monitoring.PiezoMonitoringView
|
||||
import com.medithings.vesiscan.ui.views.monitoring.VivamyoMonitoringView
|
||||
import com.medithings.vesiscan.ui.views.monitoring.UrineCameraScreen
|
||||
import com.medithings.vesiscan.ui.views.monitoring.VoidingDiaryView
|
||||
import com.medithings.vesiscan.ui.views.onboarding.OnboardingView
|
||||
import com.medithings.vesiscan.ui.views.personalization.PiezoPersonalizationView
|
||||
import com.medithings.vesiscan.ui.views.pin.PinMode
|
||||
import com.medithings.vesiscan.ui.views.pin.PinView
|
||||
import com.medithings.vesiscan.ui.views.registration.RegistrationView
|
||||
import com.medithings.vesiscan.ui.views.consent.ConsentView
|
||||
import com.medithings.vesiscan.ui.views.reminder.ReminderSettingsView
|
||||
import com.medithings.vesiscan.ui.views.sensorselect.SensorSelectView
|
||||
import com.medithings.vesiscan.ui.views.clinical.ClinicalHomeView
|
||||
import com.medithings.vesiscan.ui.views.clinical.ClinicalLiveView
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
/** 사용자가 선택한 앱 언어 적용 — Activity 생성 전에 Locale wrap. */
|
||||
override fun attachBaseContext(newBase: android.content.Context) {
|
||||
super.attachBaseContext(com.example.medilightv2android.services.LocalePref.wrap(newBase))
|
||||
super.attachBaseContext(com.medithings.vesiscan.services.LocalePref.wrap(newBase))
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@@ -106,28 +106,28 @@ fun MedilightApp(modifier: Modifier = Modifier) {
|
||||
// DeviceScan Back: 임상 흐름이면 ClinicalHome으로, 아니면 HOME
|
||||
AppScreen.DEVICE_SCAN ->
|
||||
appState.currentScreen =
|
||||
if (com.example.medilightv2android.services.ClinicalSessionStore.inClinicalFlow)
|
||||
if (com.medithings.vesiscan.services.ClinicalSessionStore.inClinicalFlow)
|
||||
AppScreen.CLINICAL_HOME
|
||||
else AppScreen.HOME
|
||||
AppScreen.PIEZO_PERSONALIZATION -> appState.currentScreen = AppScreen.DEVICE_SCAN
|
||||
// 임상 모드 측정 중이면 endMeasurement → ClinicalHome 복귀
|
||||
AppScreen.PLACEMENT_GUIDE ->
|
||||
if (com.example.medilightv2android.services.ClinicalSessionStore.currentSession != null) {
|
||||
com.example.medilightv2android.services.ClinicalSessionStore.endMeasurement(context)
|
||||
if (com.medithings.vesiscan.services.ClinicalSessionStore.currentSession != null) {
|
||||
com.medithings.vesiscan.services.ClinicalSessionStore.endMeasurement(context)
|
||||
appState.currentScreen = AppScreen.CLINICAL_HOME
|
||||
} else appState.backFromPlacementGuide()
|
||||
AppScreen.PIEZO_MONITORING ->
|
||||
if (com.example.medilightv2android.services.ClinicalSessionStore.currentSession != null) {
|
||||
com.example.medilightv2android.services.ClinicalSessionStore.endMeasurement(context)
|
||||
if (com.medithings.vesiscan.services.ClinicalSessionStore.currentSession != null) {
|
||||
com.medithings.vesiscan.services.ClinicalSessionStore.endMeasurement(context)
|
||||
appState.currentScreen = AppScreen.CLINICAL_HOME
|
||||
} else appState.currentScreen = AppScreen.PLACEMENT_GUIDE
|
||||
AppScreen.CLINICAL_HOME -> {
|
||||
com.example.medilightv2android.services.ClinicalSessionStore.inClinicalFlow = false
|
||||
com.medithings.vesiscan.services.ClinicalSessionStore.inClinicalFlow = false
|
||||
appState.currentScreen = AppScreen.HOME
|
||||
}
|
||||
AppScreen.CLINICAL_LIVE -> {
|
||||
// 측정 폴더 finalize 후 ClinicalHome 복귀
|
||||
com.example.medilightv2android.services.ClinicalSessionStore.endMeasurement(context)
|
||||
com.medithings.vesiscan.services.ClinicalSessionStore.endMeasurement(context)
|
||||
appState.currentScreen = AppScreen.CLINICAL_HOME
|
||||
}
|
||||
// 모니터링 하위 화면 → 모니터링
|
||||
+15
-15
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.ble
|
||||
package com.medithings.vesiscan.ble
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.bluetooth.*
|
||||
@@ -8,7 +8,7 @@ import android.os.Build
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import com.example.medilightv2android.BuildConfig
|
||||
import com.medithings.vesiscan.BuildConfig
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import java.util.UUID
|
||||
@@ -57,7 +57,7 @@ class BleManager private constructor(private val context: Context) {
|
||||
@Volatile private var txCharacteristic: BluetoothGattCharacteristic? = null
|
||||
@Volatile private var rxCharacteristic: BluetoothGattCharacteristic? = null
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
val debugLogger = com.example.medilightv2android.services.BleDebugLogger.getInstance(context)
|
||||
val debugLogger = com.medithings.vesiscan.services.BleDebugLogger.getInstance(context)
|
||||
private var scanTimer: Runnable? = null
|
||||
private var batteryTimer: Runnable? = null
|
||||
private var batteryRetryTimer: Runnable? = null
|
||||
@@ -299,7 +299,7 @@ class BleManager private constructor(private val context: Context) {
|
||||
logw { "removeBond failed: ${e.message}" }
|
||||
}
|
||||
}
|
||||
com.example.medilightv2android.services.KnownDeviceStore.remove(context, address)
|
||||
com.medithings.vesiscan.services.KnownDeviceStore.remove(context, address)
|
||||
debugLogger.info("DEVICE_UNREGISTERED $address")
|
||||
}
|
||||
|
||||
@@ -326,7 +326,7 @@ class BleManager private constructor(private val context: Context) {
|
||||
/** 저장된 마지막 기기에 자동 연결 시도 */
|
||||
fun autoConnectLastDevice() {
|
||||
if (isConnected.value) return
|
||||
val recent = com.example.medilightv2android.services.KnownDeviceStore.mostRecent(context) ?: return
|
||||
val recent = com.medithings.vesiscan.services.KnownDeviceStore.mostRecent(context) ?: return
|
||||
debugLogger.info("AUTO_CONNECT attempting ${recent.name} (${recent.address})")
|
||||
lastConnectedAddress = recent.address
|
||||
scheduleAutoReconnect()
|
||||
@@ -340,7 +340,7 @@ class BleManager private constructor(private val context: Context) {
|
||||
connectionTimer?.let { handler.removeCallbacks(it) }
|
||||
connectionTimer = null
|
||||
bluetoothGatt?.disconnect()
|
||||
com.example.medilightv2android.services.BleForegroundService.stop(context)
|
||||
com.medithings.vesiscan.services.BleForegroundService.stop(context)
|
||||
}
|
||||
|
||||
fun disconnectAndUnbond() {
|
||||
@@ -348,7 +348,7 @@ class BleManager private constructor(private val context: Context) {
|
||||
cancelAutoReconnect()
|
||||
stopWatchdog()
|
||||
stopBatteryPolling()
|
||||
com.example.medilightv2android.services.BleForegroundService.stop(context)
|
||||
com.medithings.vesiscan.services.BleForegroundService.stop(context)
|
||||
connectionTimer?.let { handler.removeCallbacks(it) }
|
||||
connectionTimer = null
|
||||
|
||||
@@ -386,7 +386,7 @@ class BleManager private constructor(private val context: Context) {
|
||||
// 저장된 기기 정보 삭제 — known device list 에서도 제거
|
||||
try {
|
||||
device?.let { dev ->
|
||||
com.example.medilightv2android.services.KnownDeviceStore.remove(context, dev.address)
|
||||
com.medithings.vesiscan.services.KnownDeviceStore.remove(context, dev.address)
|
||||
}
|
||||
} catch (_: Exception) {}
|
||||
|
||||
@@ -900,9 +900,9 @@ class BleManager private constructor(private val context: Context) {
|
||||
isConnected.value = true
|
||||
connectedDeviceName.value = try { gatt.device.name ?: "Unknown" } catch (_: Exception) { "Unknown" }
|
||||
// Auto-detect device preset + endian from name
|
||||
com.example.medilightv2android.managers.PiezoHW.autoDetectPreset(connectedDeviceName.value)
|
||||
com.medithings.vesiscan.managers.PiezoHW.autoDetectPreset(connectedDeviceName.value)
|
||||
piezoCollector.forceBigEndian = connectedDeviceName.value.startsWith("VBT")
|
||||
logd { "Device preset: ${com.example.medilightv2android.managers.PiezoHW.presetName}, endian: ${if (piezoCollector.forceBigEndian) "BE" else "LE"} (from '${connectedDeviceName.value}')" }
|
||||
logd { "Device preset: ${com.medithings.vesiscan.managers.PiezoHW.presetName}, endian: ${if (piezoCollector.forceBigEndian) "BE" else "LE"} (from '${connectedDeviceName.value}')" }
|
||||
|
||||
lastConnectedAddress = gatt.device.address
|
||||
reconnectAttempt = 0
|
||||
@@ -911,9 +911,9 @@ class BleManager private constructor(private val context: Context) {
|
||||
|
||||
// Clinical 흐름에서만 KnownDeviceStore 영속화. 일반 사용자는
|
||||
// 매 세션 fresh scan + pair — 저장 0개.
|
||||
if (com.example.medilightv2android.services.ClinicalSessionStore.inClinicalFlow) {
|
||||
if (com.medithings.vesiscan.services.ClinicalSessionStore.inClinicalFlow) {
|
||||
try {
|
||||
com.example.medilightv2android.services.KnownDeviceStore.add(
|
||||
com.medithings.vesiscan.services.KnownDeviceStore.add(
|
||||
context, gatt.device.address, connectedDeviceName.value
|
||||
)
|
||||
} catch (_: Exception) {}
|
||||
@@ -1030,8 +1030,8 @@ class BleManager private constructor(private val context: Context) {
|
||||
} catch (_: Exception) { false }
|
||||
logd { "requestConnectionPriority(HIGH) → $priorityOk" }
|
||||
debugLogger.info("CONN_PRIORITY HIGH requested (ok=$priorityOk)")
|
||||
com.example.medilightv2android.services.AdcCsvLogger.newSession()
|
||||
com.example.medilightv2android.services.BleForegroundService.start(context)
|
||||
com.medithings.vesiscan.services.AdcCsvLogger.newSession()
|
||||
com.medithings.vesiscan.services.BleForegroundService.start(context)
|
||||
startBatteryPolling()
|
||||
startWatchdog()
|
||||
sendDeviceInfoQuery()
|
||||
@@ -1105,7 +1105,7 @@ class BleManager private constructor(private val context: Context) {
|
||||
private fun processReceivedData(data: ByteArray) {
|
||||
lastRxTimestamp = System.currentTimeMillis()
|
||||
// Raw BLE capture (디버그 — 사용자가 토글로 enable 했을 때만 writes)
|
||||
com.example.medilightv2android.services.RawBleLogger.write(data)
|
||||
com.medithings.vesiscan.services.RawBleLogger.write(data)
|
||||
val prefix = String(data, 0, minOf(4, data.size), Charsets.US_ASCII)
|
||||
logd { "Received: $prefix (${data.size} bytes)" }
|
||||
when (prefix) {
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.ble
|
||||
package com.medithings.vesiscan.ble
|
||||
|
||||
object CRC16 {
|
||||
private const val POLYNOMIAL: Int = 0x1021
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.ble
|
||||
package com.medithings.vesiscan.ble
|
||||
|
||||
/**
|
||||
* IMU 6축 raw 샘플 (Accel xyz + Gyro xyz).
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.ble
|
||||
package com.medithings.vesiscan.ble
|
||||
|
||||
/**
|
||||
* Collects multi-packet Piezo echo responses: reb: → (red:) → raa:
|
||||
+5
-5
@@ -16,12 +16,12 @@
|
||||
*
|
||||
* 기존 PlacementGuide computePlacementGuide(...) 와 병행 — V1/V2 토글로 분기.
|
||||
*/
|
||||
package com.example.medilightv2android.managers
|
||||
package com.medithings.vesiscan.managers
|
||||
|
||||
import com.example.medilightv2android.R
|
||||
import com.example.medilightv2android.walldetect.MethodDResult
|
||||
import com.example.medilightv2android.walldetect.MethodDRunner
|
||||
import com.example.medilightv2android.walldetect.algo.methodd.MethodDParams
|
||||
import com.medithings.vesiscan.R
|
||||
import com.medithings.vesiscan.walldetect.MethodDResult
|
||||
import com.medithings.vesiscan.walldetect.MethodDRunner
|
||||
import com.medithings.vesiscan.walldetect.algo.methodd.MethodDParams
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.managers
|
||||
package com.medithings.vesiscan.managers
|
||||
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.managers
|
||||
package com.medithings.vesiscan.managers
|
||||
|
||||
import kotlin.math.abs
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.managers
|
||||
package com.medithings.vesiscan.managers
|
||||
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.managers
|
||||
package com.medithings.vesiscan.managers
|
||||
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.sqrt
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.managers
|
||||
package com.medithings.vesiscan.managers
|
||||
|
||||
/**
|
||||
* Green Zone 전체 파이프라인의 공유 상수 — Single Source of Truth.
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
package com.example.medilightv2android.managers
|
||||
package com.medithings.vesiscan.managers
|
||||
|
||||
import com.example.medilightv2android.ble.ImuSample
|
||||
import com.medithings.vesiscan.ble.ImuSample
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.atan2
|
||||
import kotlin.math.sqrt
|
||||
+2
-2
@@ -13,9 +13,9 @@
|
||||
* ≤ threshold → NON_LYING (앉음/섬)
|
||||
* threshold default = 25°, dev 모드 설정에서 변경 가능.
|
||||
*/
|
||||
package com.example.medilightv2android.managers
|
||||
package com.medithings.vesiscan.managers
|
||||
|
||||
import com.example.medilightv2android.ble.ImuSample
|
||||
import com.medithings.vesiscan.ble.ImuSample
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.atan
|
||||
import kotlin.math.sqrt
|
||||
+4
-4
@@ -1,8 +1,8 @@
|
||||
package com.example.medilightv2android.managers
|
||||
package com.medithings.vesiscan.managers
|
||||
|
||||
import com.example.medilightv2android.models.NirsConstants
|
||||
import com.example.medilightv2android.models.NirsMagResponse
|
||||
import com.example.medilightv2android.models.NirsOxyResult
|
||||
import com.medithings.vesiscan.models.NirsConstants
|
||||
import com.medithings.vesiscan.models.NirsMagResponse
|
||||
import com.medithings.vesiscan.models.NirsOxyResult
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.ln
|
||||
import kotlin.math.max
|
||||
+6
-6
@@ -1,13 +1,13 @@
|
||||
package com.example.medilightv2android.managers
|
||||
package com.medithings.vesiscan.managers
|
||||
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import com.example.medilightv2android.models.NirsMagResponse
|
||||
import com.example.medilightv2android.models.NirsMcjPacket
|
||||
import com.example.medilightv2android.models.NirsConstants
|
||||
import com.example.medilightv2android.BuildConfig
|
||||
import com.example.medilightv2android.models.NirsOxyResult
|
||||
import com.medithings.vesiscan.models.NirsMagResponse
|
||||
import com.medithings.vesiscan.models.NirsMcjPacket
|
||||
import com.medithings.vesiscan.models.NirsConstants
|
||||
import com.medithings.vesiscan.BuildConfig
|
||||
import com.medithings.vesiscan.models.NirsOxyResult
|
||||
|
||||
class NirsManager private constructor() {
|
||||
companion object {
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
package com.example.medilightv2android.managers
|
||||
package com.medithings.vesiscan.managers
|
||||
|
||||
import com.example.medilightv2android.walldetect.core.WdConfig
|
||||
import com.medithings.vesiscan.walldetect.core.WdConfig
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.hypot
|
||||
@@ -484,7 +484,7 @@ fun estimateBladderVolume6ch(
|
||||
val lateralWalls = PiezoHW.lateralCh.map { if (it < allWalls.size) allWalls[it] else null }
|
||||
// 2026-07-01: algorithm 팀 최신 표준 (piezophantomtest 4830e7c) — lr_ratio_override=1.0
|
||||
// Phantom 검증: computed lr 은 6채널 HW 한계로 -38% 오차. Dev panel 로 전환 가능.
|
||||
val lrRatio = com.example.medilightv2android.managers.GreenZoneConstants.lrRatioOverride
|
||||
val lrRatio = com.medithings.vesiscan.managers.GreenZoneConstants.lrRatioOverride
|
||||
?: computeLrRatio(centerWalls, lateralWalls, sensorZMm = PiezoHW.sensorZMmAll)
|
||||
return estimateBladderVolume(
|
||||
walls = centerWalls,
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
package com.example.medilightv2android.managers
|
||||
package com.medithings.vesiscan.managers
|
||||
|
||||
import com.example.medilightv2android.ble.PiezoChannelData
|
||||
import com.medithings.vesiscan.ble.PiezoChannelData
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.managers
|
||||
package com.medithings.vesiscan.managers
|
||||
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.managers
|
||||
package com.medithings.vesiscan.managers
|
||||
|
||||
/**
|
||||
* UrinAI (UrinGateKeeper) — 소변(액체) 존재 판정 엔진.
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
* // 매 posture 갱신 시:
|
||||
* detector.update(currentPosture, System.currentTimeMillis())
|
||||
*/
|
||||
package com.example.medilightv2android.managers
|
||||
package com.medithings.vesiscan.managers
|
||||
|
||||
class WakeupDetector(
|
||||
/** 알람 발동을 위해 직전 LYING 상태로 유지되어야 하는 최소 시간 (초). */
|
||||
+2
-2
@@ -18,9 +18,9 @@
|
||||
* 입력: 매 mtb cycle (≈1초 주기) 마다 IMU sample 리스트 + 현재 pitch + 시각
|
||||
* 출력: 현재 walking 상태 (Boolean) + 진단 정보
|
||||
*/
|
||||
package com.example.medilightv2android.managers
|
||||
package com.medithings.vesiscan.managers
|
||||
|
||||
import com.example.medilightv2android.ble.ImuSample
|
||||
import com.medithings.vesiscan.ble.ImuSample
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.sqrt
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.measure
|
||||
package com.medithings.vesiscan.measure
|
||||
|
||||
data class CCPosition(
|
||||
val cc: Int,
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.measure
|
||||
package com.medithings.vesiscan.measure
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Color
|
||||
@@ -6,7 +6,7 @@ import android.util.Log
|
||||
import com.google.mlkit.vision.common.InputImage
|
||||
import com.google.mlkit.vision.text.TextRecognition
|
||||
import com.google.mlkit.vision.text.latin.TextRecognizerOptions
|
||||
import com.example.medilightv2android.measure.CCPosition
|
||||
import com.medithings.vesiscan.measure.CCPosition
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlinx.coroutines.withContext
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.measure
|
||||
package com.medithings.vesiscan.measure
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.measure
|
||||
package com.medithings.vesiscan.measure
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.models
|
||||
package com.medithings.vesiscan.models
|
||||
|
||||
data class BladderLevel(
|
||||
var currentLevel: Int = 0,
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.models
|
||||
package com.medithings.vesiscan.models
|
||||
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.models
|
||||
package com.medithings.vesiscan.models
|
||||
|
||||
import java.util.Date
|
||||
import java.util.UUID
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.models
|
||||
package com.medithings.vesiscan.models
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
+4
-4
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.models
|
||||
package com.medithings.vesiscan.models
|
||||
|
||||
data class NirsMcjPacket(
|
||||
val battery: Int,
|
||||
@@ -16,7 +16,7 @@ data class NirsMcjPacket(
|
||||
|
||||
fun parse(data: ByteArray): NirsMcjPacket? {
|
||||
if (data.size < 72) {
|
||||
if (com.example.medilightv2android.BuildConfig.DEBUG) {
|
||||
if (com.medithings.vesiscan.BuildConfig.DEBUG) {
|
||||
android.util.Log.e(TAG, "parse: data too small: ${data.size} < 72")
|
||||
}
|
||||
return null
|
||||
@@ -42,7 +42,7 @@ data class NirsMcjPacket(
|
||||
for (i in 0 until 24) {
|
||||
val offset = base + 20 + (i * 2)
|
||||
if (offset + 1 >= data.size) {
|
||||
if (com.example.medilightv2android.BuildConfig.DEBUG) {
|
||||
if (com.medithings.vesiscan.BuildConfig.DEBUG) {
|
||||
android.util.Log.e(TAG, "parse: LED[$i] out of bounds: offset=${offset+1} >= size=${data.size}")
|
||||
}
|
||||
return null
|
||||
@@ -50,7 +50,7 @@ data class NirsMcjPacket(
|
||||
ledValues[i] = u16(offset)
|
||||
}
|
||||
|
||||
if (com.example.medilightv2android.BuildConfig.DEBUG) {
|
||||
if (com.medithings.vesiscan.BuildConfig.DEBUG) {
|
||||
android.util.Log.d(TAG, "parse OK: battery=$battery led[0..5]=${ledValues.take(6)}")
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.models
|
||||
package com.medithings.vesiscan.models
|
||||
|
||||
enum class Posture(val displayName: String) {
|
||||
STANDING("Standing"),
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.models
|
||||
package com.medithings.vesiscan.models
|
||||
|
||||
enum class SensorMode(val displayName: String) {
|
||||
NIRS("NIRS"),
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.models
|
||||
package com.medithings.vesiscan.models
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.models
|
||||
package com.medithings.vesiscan.models
|
||||
|
||||
enum class Sex { MALE, FEMALE }
|
||||
|
||||
+5
-5
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.services
|
||||
package com.medithings.vesiscan.services
|
||||
|
||||
import android.os.Environment
|
||||
import java.io.File
|
||||
@@ -63,15 +63,15 @@ object AdcCsvLogger {
|
||||
val timestamp = timeFmt.format(Date())
|
||||
val volStr = volumeMl?.let { "%.1f".format(it) } ?: ""
|
||||
val lrStr = "%.2f".format(lrRatio)
|
||||
val analyzer = com.example.medilightv2android.managers.PiezoEchoAnalyzer.shared
|
||||
val analyzer = com.medithings.vesiscan.managers.PiezoEchoAnalyzer.shared
|
||||
val thrStr = if (analyzer.useAdaptiveThreshold && analyzer.lastOtsuThreshold > 0)
|
||||
"%.0f".format(analyzer.lastOtsuThreshold) else "%.0f".format(com.example.medilightv2android.managers.GreenZoneConstants.lowEchoAmp)
|
||||
val dpsStr = "%.3f".format(com.example.medilightv2android.managers.PiezoHW.distancePerSample)
|
||||
"%.0f".format(analyzer.lastOtsuThreshold) else "%.0f".format(com.medithings.vesiscan.managers.GreenZoneConstants.lowEchoAmp)
|
||||
val dpsStr = "%.3f".format(com.medithings.vesiscan.managers.PiezoHW.distancePerSample)
|
||||
val sgStr = if (analyzer.useSgFilter) "ON" else "OFF"
|
||||
|
||||
val clinicalLabel = ClinicalSessionStore.currentLabel() // 일반 모드면 ""
|
||||
// BLE 펌웨어 버전 (연결 안 됐으면 "")
|
||||
val fwVersion = com.example.medilightv2android.ble.BleManager.current?.firmwareVersion?.value ?: ""
|
||||
val fwVersion = com.medithings.vesiscan.ble.BleManager.current?.firmwareVersion?.value ?: ""
|
||||
|
||||
java.io.FileWriter(file, !isNew).buffered().use { writer ->
|
||||
if (isNew) {
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.services
|
||||
package com.medithings.vesiscan.services
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
+5
-5
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.services
|
||||
package com.medithings.vesiscan.services
|
||||
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
@@ -11,8 +11,8 @@ import android.os.Build
|
||||
import android.os.IBinder
|
||||
import android.os.PowerManager
|
||||
import androidx.core.app.NotificationCompat
|
||||
import com.example.medilightv2android.MainActivity
|
||||
import com.example.medilightv2android.R
|
||||
import com.medithings.vesiscan.MainActivity
|
||||
import com.medithings.vesiscan.R
|
||||
|
||||
/**
|
||||
* BLE 연결 유지를 위한 Foreground Service.
|
||||
@@ -25,8 +25,8 @@ class BleForegroundService : Service() {
|
||||
companion object {
|
||||
const val CHANNEL_ID = "vesiscan_ble_channel"
|
||||
const val NOTIFICATION_ID = 1001
|
||||
const val ACTION_START = "com.example.medilightv2android.BLE_START"
|
||||
const val ACTION_STOP = "com.example.medilightv2android.BLE_STOP"
|
||||
const val ACTION_START = "com.medithings.vesiscan.BLE_START"
|
||||
const val ACTION_STOP = "com.medithings.vesiscan.BLE_STOP"
|
||||
|
||||
fun start(context: Context) {
|
||||
// 배터리 최적화 제외 요청 제거 — 다른 페이지로 이동되는 UX 문제
|
||||
+13
-13
@@ -1,10 +1,10 @@
|
||||
package com.example.medilightv2android.services
|
||||
package com.medithings.vesiscan.services
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Environment
|
||||
import com.example.medilightv2android.ble.ImuSample
|
||||
import com.example.medilightv2android.ble.PiezoChannelData
|
||||
import com.example.medilightv2android.models.ClinicalSession
|
||||
import com.medithings.vesiscan.ble.ImuSample
|
||||
import com.medithings.vesiscan.ble.PiezoChannelData
|
||||
import com.medithings.vesiscan.models.ClinicalSession
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import java.io.File
|
||||
@@ -59,16 +59,16 @@ object ClinicalSessionStore {
|
||||
/** 다음 측정 시 기본값으로 자동 채울 사용자 입력 — 같은 피험자/검사자 여러 측정 시 편의 */
|
||||
var lastExaminer: String = ""
|
||||
var lastNotes: String = ""
|
||||
var lastSubjectType: com.example.medilightv2android.models.SubjectType =
|
||||
com.example.medilightv2android.models.SubjectType.PHANTOM
|
||||
var lastSubjectType: com.medithings.vesiscan.models.SubjectType =
|
||||
com.medithings.vesiscan.models.SubjectType.PHANTOM
|
||||
var lastSubject: String = "" // 카테고리 내 식별자 (예: "500mL", "S001")
|
||||
var lastTrueVolumeMl: String = "" // 문자열로 보관 (입력 폼과 동일 형식)
|
||||
var lastAbdomenThicknessMm: String = ""
|
||||
// 회의 결정: Step/Posture 마지막 선택 유지 — 매번 0cm로 리셋되는 불편 제거
|
||||
var lastPosture: com.example.medilightv2android.models.ClinicalPosture =
|
||||
com.example.medilightv2android.models.ClinicalPosture.SUPINE
|
||||
var lastStep: com.example.medilightv2android.models.ClinicalStep =
|
||||
com.example.medilightv2android.models.ClinicalStep.ALIGN_0CM
|
||||
var lastPosture: com.medithings.vesiscan.models.ClinicalPosture =
|
||||
com.medithings.vesiscan.models.ClinicalPosture.SUPINE
|
||||
var lastStep: com.medithings.vesiscan.models.ClinicalStep =
|
||||
com.medithings.vesiscan.models.ClinicalStep.ALIGN_0CM
|
||||
|
||||
/** End 시점에 measurement.json 통합 생성용 — 측정 중 사이클 누적 */
|
||||
private val cyclesBuffer = mutableListOf<MeasurementCycle>()
|
||||
@@ -186,7 +186,7 @@ object ClinicalSessionStore {
|
||||
put("android_release", android.os.Build.VERSION.RELEASE)
|
||||
put("android_sdk", android.os.Build.VERSION.SDK_INT)
|
||||
// VBT 디바이스 정보 (mid?/rid: 응답 파싱값) — 분석 시 펌웨어별 데이터 grouping용
|
||||
val ble = com.example.medilightv2android.ble.BleManager.getInstance(context)
|
||||
val ble = com.medithings.vesiscan.ble.BleManager.getInstance(context)
|
||||
val fw = ble.firmwareVersion.value
|
||||
val hw = ble.hardwareVersion.value
|
||||
val sn = ble.serialNumber.value
|
||||
@@ -224,7 +224,7 @@ object ClinicalSessionStore {
|
||||
|
||||
// meta: writeMeta()와 동일 내용 포함 (단독 파일로 자족 가능)
|
||||
// alignment 모드 → dataType=002, 그 외 = 001 (기존 measurement)
|
||||
val effectiveDataType = if (s.mode == com.example.medilightv2android.models.SessionMode.ALIGNMENT)
|
||||
val effectiveDataType = if (s.mode == com.medithings.vesiscan.models.SessionMode.ALIGNMENT)
|
||||
"002" else DATA_TYPE
|
||||
val meta = JSONObject().apply {
|
||||
put("data_type", effectiveDataType)
|
||||
@@ -254,7 +254,7 @@ object ClinicalSessionStore {
|
||||
put("app_version_name", try {
|
||||
context.packageManager.getPackageInfo(context.packageName, 0).versionName ?: "unknown"
|
||||
} catch (_: Exception) { "unknown" })
|
||||
val ble = com.example.medilightv2android.ble.BleManager.current
|
||||
val ble = com.medithings.vesiscan.ble.BleManager.current
|
||||
ble?.firmwareVersion?.value?.takeIf { it.isNotEmpty() }?.let { put("firmware_version", it) }
|
||||
ble?.hardwareVersion?.value?.takeIf { it.isNotEmpty() }?.let { put("hardware_version", it) }
|
||||
ble?.serialNumber?.value?.takeIf { it.isNotEmpty() }?.let { put("serial_number", it) }
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
package com.example.medilightv2android.services
|
||||
package com.medithings.vesiscan.services
|
||||
|
||||
import com.example.medilightv2android.ble.ImuSample
|
||||
import com.medithings.vesiscan.ble.ImuSample
|
||||
import java.io.File
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
@@ -38,7 +38,7 @@ object ImuCsvLogger {
|
||||
val scanId = AdcCsvLogger.lastScanId // piezo adc.csv와 매칭용
|
||||
val timestamp = timeFmt.format(Date())
|
||||
val clinicalLabel = ClinicalSessionStore.currentLabel()
|
||||
val fwVersion = com.example.medilightv2android.ble.BleManager.current?.firmwareVersion?.value ?: ""
|
||||
val fwVersion = com.medithings.vesiscan.ble.BleManager.current?.firmwareVersion?.value ?: ""
|
||||
|
||||
file.bufferedWriter().use { _ -> } // ensure exists
|
||||
java.io.FileWriter(file, !isNew).buffered().use { writer ->
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.services
|
||||
package com.medithings.vesiscan.services
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.services
|
||||
package com.medithings.vesiscan.services
|
||||
|
||||
import android.content.Context
|
||||
import org.json.JSONArray
|
||||
+1
-1
@@ -13,7 +13,7 @@
|
||||
* Android 13+ 의 per-app locale API (AppCompatDelegate.setApplicationLocales) 와
|
||||
* 무관하게 Configuration override 방식으로 모든 SDK 에서 동작.
|
||||
*/
|
||||
package com.example.medilightv2android.services
|
||||
package com.medithings.vesiscan.services
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
package com.example.medilightv2android.services
|
||||
package com.medithings.vesiscan.services
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import com.example.medilightv2android.models.MeasurementRecord
|
||||
import com.medithings.vesiscan.models.MeasurementRecord
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.services
|
||||
package com.medithings.vesiscan.services
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
@@ -70,7 +70,7 @@ class MeasurementLogService private constructor(private val context: Context) {
|
||||
val clinical = ClinicalSessionStore.currentLabel()
|
||||
if (clinical.isNotEmpty()) put("clinical_label", clinical)
|
||||
// BLE 펌웨어 버전 (연결 시 mid?/rid: 응답에서 받음)
|
||||
val fw = com.example.medilightv2android.ble.BleManager.current?.firmwareVersion?.value
|
||||
val fw = com.medithings.vesiscan.ble.BleManager.current?.firmwareVersion?.value
|
||||
if (!fw.isNullOrEmpty()) put("firmware_version", fw)
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ class MeasurementLogService private constructor(private val context: Context) {
|
||||
val clinical = ClinicalSessionStore.currentLabel()
|
||||
if (clinical.isNotEmpty()) put("clinical_label", clinical)
|
||||
// BLE 펌웨어 버전
|
||||
val fw = com.example.medilightv2android.ble.BleManager.current?.firmwareVersion?.value
|
||||
val fw = com.medithings.vesiscan.ble.BleManager.current?.firmwareVersion?.value
|
||||
if (!fw.isNullOrEmpty()) put("firmware_version", fw)
|
||||
}
|
||||
appendLog(entry, "placements.jsonl")
|
||||
+3
-3
@@ -1,9 +1,9 @@
|
||||
package com.example.medilightv2android.services
|
||||
package com.medithings.vesiscan.services
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import com.example.medilightv2android.ble.BleManager
|
||||
import com.example.medilightv2android.models.SensorMode
|
||||
import com.medithings.vesiscan.ble.BleManager
|
||||
import com.medithings.vesiscan.models.SensorMode
|
||||
|
||||
class MeasurementService private constructor(context: Context) {
|
||||
companion object {
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.services
|
||||
package com.medithings.vesiscan.services
|
||||
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
@@ -6,8 +6,8 @@ import android.content.Context
|
||||
import android.os.Build
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import com.example.medilightv2android.R
|
||||
import com.example.medilightv2android.models.UrgencyLevel
|
||||
import com.medithings.vesiscan.R
|
||||
import com.medithings.vesiscan.models.UrgencyLevel
|
||||
|
||||
class NotificationService private constructor(private val context: Context) {
|
||||
companion object {
|
||||
+1
-1
@@ -23,7 +23,7 @@
|
||||
*
|
||||
* 분석: CSV → Excel / python pandas → ANNOTATION 과 CYCLE 의 walking 전이 대조.
|
||||
*/
|
||||
package com.example.medilightv2android.services
|
||||
package com.medithings.vesiscan.services
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Environment
|
||||
+2
-2
@@ -9,10 +9,10 @@
|
||||
* saveAll(context) — slider 변경 시 호출 → 현재 GreenZoneConstants → SharedPreferences
|
||||
* resetAll(context) — 사용자가 reset 누름 → defaults 로 복원
|
||||
*/
|
||||
package com.example.medilightv2android.services
|
||||
package com.medithings.vesiscan.services
|
||||
|
||||
import android.content.Context
|
||||
import com.example.medilightv2android.managers.GreenZoneConstants
|
||||
import com.medithings.vesiscan.managers.GreenZoneConstants
|
||||
|
||||
object PostureTuningPrefs {
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
* 사용: startCapture() / stopCapture() 토글. 활성화 시 BleManager.processReceivedData
|
||||
* 가 매 notification 마다 write() 호출.
|
||||
*/
|
||||
package com.example.medilightv2android.services
|
||||
package com.medithings.vesiscan.services
|
||||
|
||||
import android.os.Environment
|
||||
import java.io.File
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.services
|
||||
package com.medithings.vesiscan.services
|
||||
|
||||
import android.app.AlarmManager
|
||||
import android.app.NotificationChannel
|
||||
@@ -15,7 +15,7 @@ import android.os.Vibrator
|
||||
import android.os.VibratorManager
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import com.example.medilightv2android.R
|
||||
import com.medithings.vesiscan.R
|
||||
import java.util.Calendar
|
||||
|
||||
class ReminderService private constructor(private val context: Context) {
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
package com.example.medilightv2android.services
|
||||
package com.medithings.vesiscan.services
|
||||
|
||||
import com.example.medilightv2android.ble.PiezoChannelData
|
||||
import com.medithings.vesiscan.ble.PiezoChannelData
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
package com.example.medilightv2android.services
|
||||
package com.medithings.vesiscan.services
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import com.example.medilightv2android.models.*
|
||||
import com.medithings.vesiscan.models.*
|
||||
import com.google.gson.Gson
|
||||
|
||||
class UserStorage private constructor(context: Context) {
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
* 사용자가 "설정 탭" 에서 toggle on/off → 일어남 감지 시 빨간 팝업.
|
||||
* LYING 유지 시간 임계 (default 3 min) 도 함께.
|
||||
*/
|
||||
package com.example.medilightv2android.services
|
||||
package com.medithings.vesiscan.services
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
package com.example.medilightv2android.services.labdb
|
||||
package com.medithings.vesiscan.services.labdb
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import com.example.medilightv2android.ble.BleManager
|
||||
import com.medithings.vesiscan.ble.BleManager
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
package com.example.medilightv2android.services.labdb
|
||||
package com.medithings.vesiscan.services.labdb
|
||||
|
||||
import com.example.medilightv2android.services.KeychainService
|
||||
import com.medithings.vesiscan.services.KeychainService
|
||||
|
||||
/**
|
||||
* labdb (https://labdb.medithings.net) 자격 증명 저장소.
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.services.labdb
|
||||
package com.medithings.vesiscan.services.labdb
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
* MEDiThings Inc.
|
||||
* All rights reserved.
|
||||
*/
|
||||
package com.example.medilightv2android.speech
|
||||
package com.medithings.vesiscan.speech
|
||||
|
||||
import android.util.Log
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
* MEDiThings Inc.
|
||||
* All rights reserved.
|
||||
*/
|
||||
package com.example.medilightv2android.speech
|
||||
package com.medithings.vesiscan.speech
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
* MEDiThings Inc.
|
||||
* All rights reserved.
|
||||
*/
|
||||
package com.example.medilightv2android.speech
|
||||
package com.medithings.vesiscan.speech
|
||||
|
||||
/**
|
||||
* Local (offline) parser that extracts a volume in milliliters from speech-recognition text.
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.ui.components
|
||||
package com.medithings.vesiscan.ui.components
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -22,8 +22,8 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.example.medilightv2android.R
|
||||
import com.example.medilightv2android.ble.BleManager
|
||||
import com.medithings.vesiscan.R
|
||||
import com.medithings.vesiscan.ble.BleManager
|
||||
|
||||
/**
|
||||
* 배터리 잔량 경고 배너 — PlacementGuide / PiezoMonitoring 상단.
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.ui.components
|
||||
package com.medithings.vesiscan.ui.components
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.size
|
||||
@@ -13,8 +13,8 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import app.rive.runtime.kotlin.RiveAnimationView
|
||||
import app.rive.runtime.kotlin.core.Fit
|
||||
import com.example.medilightv2android.R
|
||||
import com.example.medilightv2android.models.UrgencyLevel
|
||||
import com.medithings.vesiscan.R
|
||||
import com.medithings.vesiscan.models.UrgencyLevel
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlin.random.Random
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.ui.components
|
||||
package com.medithings.vesiscan.ui.components
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
@@ -13,7 +13,7 @@ import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.example.medilightv2android.ui.theme.MlPrimary
|
||||
import com.medithings.vesiscan.ui.theme.MlPrimary
|
||||
|
||||
enum class BleReconnectionState {
|
||||
DISCONNECTED, RECONNECTING, FAILED
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.ui.components
|
||||
package com.medithings.vesiscan.ui.components
|
||||
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.tween
|
||||
@@ -14,7 +14,7 @@ import androidx.compose.ui.semantics.contentDescription
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.medilightv2android.models.UrgencyLevel
|
||||
import com.medithings.vesiscan.models.UrgencyLevel
|
||||
|
||||
@Composable
|
||||
fun DonutChartView(
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.ui.components
|
||||
package com.medithings.vesiscan.ui.components
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -26,8 +26,8 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.example.medilightv2android.R
|
||||
import com.example.medilightv2android.ble.BleManager
|
||||
import com.medithings.vesiscan.R
|
||||
import com.medithings.vesiscan.ble.BleManager
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
/**
|
||||
+2
-2
@@ -15,7 +15,7 @@
|
||||
* UX 톤:
|
||||
* "1회 터치 후 조정" 패턴 — 의도된 조작만 허용.
|
||||
*/
|
||||
package com.example.medilightv2android.ui.components
|
||||
package com.medithings.vesiscan.ui.components
|
||||
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
@@ -39,7 +39,7 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.medilightv2android.R
|
||||
import com.medithings.vesiscan.R
|
||||
|
||||
@Composable
|
||||
fun LockableSlider(
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
* measurement, newest at the bottom, monospace, long-press to select spans
|
||||
* across entries. Copy puts the full log on the system clipboard.
|
||||
*/
|
||||
package com.example.medilightv2android.ui.components
|
||||
package com.medithings.vesiscan.ui.components
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.ui.theme
|
||||
package com.medithings.vesiscan.ui.theme
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.ui.theme
|
||||
package com.medithings.vesiscan.ui.theme
|
||||
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.foundation.gestures.detectTapGestures
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.ui.theme
|
||||
package com.medithings.vesiscan.ui.theme
|
||||
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.lightColorScheme
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.ui.theme
|
||||
package com.medithings.vesiscan.ui.theme
|
||||
|
||||
import androidx.compose.material3.Typography
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
+8
-8
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.ui.views.calibration
|
||||
package com.medithings.vesiscan.ui.views.calibration
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
@@ -22,13 +22,13 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.example.medilightv2android.AppState
|
||||
import com.example.medilightv2android.R
|
||||
import com.example.medilightv2android.ble.BleManager
|
||||
import com.example.medilightv2android.managers.NirsManager
|
||||
import com.example.medilightv2android.models.NirsMagResponse
|
||||
import com.example.medilightv2android.ui.components.BladdyIdleRiveView
|
||||
import com.example.medilightv2android.ui.theme.*
|
||||
import com.medithings.vesiscan.AppState
|
||||
import com.medithings.vesiscan.R
|
||||
import com.medithings.vesiscan.ble.BleManager
|
||||
import com.medithings.vesiscan.managers.NirsManager
|
||||
import com.medithings.vesiscan.models.NirsMagResponse
|
||||
import com.medithings.vesiscan.ui.components.BladdyIdleRiveView
|
||||
import com.medithings.vesiscan.ui.theme.*
|
||||
|
||||
@Composable
|
||||
fun CalibrationView(appState: AppState) {
|
||||
+14
-14
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.ui.views.clinical
|
||||
package com.medithings.vesiscan.ui.views.clinical
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.background
|
||||
@@ -23,15 +23,15 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.example.medilightv2android.AppScreen
|
||||
import com.example.medilightv2android.AppState
|
||||
import com.example.medilightv2android.ble.BleManager
|
||||
import com.example.medilightv2android.models.*
|
||||
import com.example.medilightv2android.services.ClinicalSessionStore
|
||||
import com.example.medilightv2android.services.labdb.LabdbClient
|
||||
import com.example.medilightv2android.services.labdb.LabdbCredentials
|
||||
import com.example.medilightv2android.services.labdb.LabdbUploader
|
||||
import com.example.medilightv2android.ui.theme.*
|
||||
import com.medithings.vesiscan.AppScreen
|
||||
import com.medithings.vesiscan.AppState
|
||||
import com.medithings.vesiscan.ble.BleManager
|
||||
import com.medithings.vesiscan.models.*
|
||||
import com.medithings.vesiscan.services.ClinicalSessionStore
|
||||
import com.medithings.vesiscan.services.labdb.LabdbClient
|
||||
import com.medithings.vesiscan.services.labdb.LabdbCredentials
|
||||
import com.medithings.vesiscan.services.labdb.LabdbUploader
|
||||
import com.medithings.vesiscan.ui.theme.*
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
@@ -397,7 +397,7 @@ fun ClinicalHomeView(appState: AppState) {
|
||||
// 측정 대상 분류 — Phantom/Human/ETC 버튼 (회의 결정)
|
||||
LabeledSegmented(
|
||||
label = "Subject Type",
|
||||
options = com.example.medilightv2android.models.SubjectType.values().toList(),
|
||||
options = com.medithings.vesiscan.models.SubjectType.values().toList(),
|
||||
selected = subjectType,
|
||||
onSelect = { subjectType = it }
|
||||
) { it.label }
|
||||
@@ -492,7 +492,7 @@ fun ClinicalHomeView(appState: AppState) {
|
||||
subjectType = subjectType, subject = subject.trim(),
|
||||
trueVolumeMl = trueVolText.toDoubleOrNull(),
|
||||
abdomenThicknessMm = abdomenText.toDoubleOrNull(),
|
||||
mode = com.example.medilightv2android.models.SessionMode.MEASUREMENT,
|
||||
mode = com.medithings.vesiscan.models.SessionMode.MEASUREMENT,
|
||||
)
|
||||
)
|
||||
appState.currentScreen = AppScreen.CLINICAL_LIVE
|
||||
@@ -517,9 +517,9 @@ fun ClinicalHomeView(appState: AppState) {
|
||||
subjectType = subjectType, subject = subject.trim(),
|
||||
trueVolumeMl = trueVolText.toDoubleOrNull(),
|
||||
abdomenThicknessMm = abdomenText.toDoubleOrNull(),
|
||||
mode = com.example.medilightv2android.models.SessionMode.ALIGNMENT,
|
||||
mode = com.medithings.vesiscan.models.SessionMode.ALIGNMENT,
|
||||
// 현재 dev 토글된 algo 그대로 — V1 (default) 또는 V2.
|
||||
alignmentAlgo = com.example.medilightv2android.managers.GreenZoneConstants.alignmentAlgo.name,
|
||||
alignmentAlgo = com.medithings.vesiscan.managers.GreenZoneConstants.alignmentAlgo.name,
|
||||
)
|
||||
)
|
||||
appState.enterAlignmentSession()
|
||||
+17
-17
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.ui.views.clinical
|
||||
package com.medithings.vesiscan.ui.views.clinical
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.Canvas
|
||||
@@ -25,17 +25,17 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.example.medilightv2android.AppScreen
|
||||
import com.example.medilightv2android.AppState
|
||||
import com.example.medilightv2android.ble.BleManager
|
||||
import com.example.medilightv2android.ble.ImuSample
|
||||
import com.example.medilightv2android.ble.PiezoChannelData
|
||||
import com.example.medilightv2android.managers.ImuAnalysis
|
||||
import com.example.medilightv2android.services.AdcCsvLogger
|
||||
import com.example.medilightv2android.services.ClinicalSessionStore
|
||||
import com.example.medilightv2android.services.ImuCsvLogger
|
||||
import com.example.medilightv2android.services.MeasurementLogService
|
||||
import com.example.medilightv2android.ui.theme.*
|
||||
import com.medithings.vesiscan.AppScreen
|
||||
import com.medithings.vesiscan.AppState
|
||||
import com.medithings.vesiscan.ble.BleManager
|
||||
import com.medithings.vesiscan.ble.ImuSample
|
||||
import com.medithings.vesiscan.ble.PiezoChannelData
|
||||
import com.medithings.vesiscan.managers.ImuAnalysis
|
||||
import com.medithings.vesiscan.services.AdcCsvLogger
|
||||
import com.medithings.vesiscan.services.ClinicalSessionStore
|
||||
import com.medithings.vesiscan.services.ImuCsvLogger
|
||||
import com.medithings.vesiscan.services.MeasurementLogService
|
||||
import com.medithings.vesiscan.ui.theme.*
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
@@ -79,7 +79,7 @@ fun ClinicalLiveView(appState: AppState) {
|
||||
var pendingPiezo by remember { mutableStateOf<List<PiezoChannelData>?>(null) }
|
||||
|
||||
// V4.1 wall detection — 채널별 ant/post peak 표시용 (사내 테스트 가시화 요청)
|
||||
val v41 = remember { com.example.medilightv2android.walldetect.V41Detector() }
|
||||
val v41 = remember { com.medithings.vesiscan.walldetect.V41Detector() }
|
||||
var channelWalls by remember { mutableStateOf<List<Pair<Int, Int>?>>(List(6) { null }) }
|
||||
|
||||
DisposableEffect(Unit) {
|
||||
@@ -91,13 +91,13 @@ fun ClinicalLiveView(appState: AppState) {
|
||||
val adcMatrix = (0 until 6).map { ch ->
|
||||
channels.find { it.channel == ch }?.buffer?.map { it.toInt() } ?: List(100) { 0 }
|
||||
}
|
||||
val probe = com.example.medilightv2android.walldetect.dto.ProbeProfileDto(
|
||||
name = com.example.medilightv2android.managers.PiezoHW.presetName,
|
||||
val probe = com.medithings.vesiscan.walldetect.dto.ProbeProfileDto(
|
||||
name = com.medithings.vesiscan.managers.PiezoHW.presetName,
|
||||
rMm = 50.2, anteriorAnchorMm = 32.0,
|
||||
fsHz = 537500, cMmPerUs = 1.54,
|
||||
anglesDeg = com.example.medilightv2android.managers.PiezoHW.degreeAll.toList()
|
||||
anglesDeg = com.medithings.vesiscan.managers.PiezoHW.degreeAll.toList()
|
||||
)
|
||||
val sweepInput = com.example.medilightv2android.walldetect.dto.SweepInput(
|
||||
val sweepInput = com.medithings.vesiscan.walldetect.dto.SweepInput(
|
||||
requestId = "clinical_${System.currentTimeMillis()}",
|
||||
timestampMs = System.currentTimeMillis(),
|
||||
deviceId = bleManager.connectedDeviceName.value,
|
||||
+12
-12
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.ui.views.connection
|
||||
package com.medithings.vesiscan.ui.views.connection
|
||||
|
||||
import android.Manifest
|
||||
import android.content.pm.PackageManager
|
||||
@@ -34,15 +34,15 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.example.medilightv2android.AppState
|
||||
import com.example.medilightv2android.R
|
||||
import com.example.medilightv2android.ble.BleDevice
|
||||
import com.example.medilightv2android.ble.BleManager
|
||||
import com.example.medilightv2android.models.SensorMode
|
||||
import com.example.medilightv2android.services.KnownDevice
|
||||
import com.example.medilightv2android.services.KnownDeviceStore
|
||||
import com.example.medilightv2android.ui.components.BladdyIdleRiveView
|
||||
import com.example.medilightv2android.ui.theme.*
|
||||
import com.medithings.vesiscan.AppState
|
||||
import com.medithings.vesiscan.R
|
||||
import com.medithings.vesiscan.ble.BleDevice
|
||||
import com.medithings.vesiscan.ble.BleManager
|
||||
import com.medithings.vesiscan.models.SensorMode
|
||||
import com.medithings.vesiscan.services.KnownDevice
|
||||
import com.medithings.vesiscan.services.KnownDeviceStore
|
||||
import com.medithings.vesiscan.ui.components.BladdyIdleRiveView
|
||||
import com.medithings.vesiscan.ui.theme.*
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
@@ -55,7 +55,7 @@ fun DeviceScanView(appState: AppState) {
|
||||
var permissionsGranted by remember { mutableStateOf(false) }
|
||||
|
||||
// Clinical 흐름에서만 다중 기기 저장/표시 — 일반 사용자는 fresh scan & pair.
|
||||
val isClinicalFlow = com.example.medilightv2android.services.ClinicalSessionStore.inClinicalFlow
|
||||
val isClinicalFlow = com.medithings.vesiscan.services.ClinicalSessionStore.inClinicalFlow
|
||||
var knownDevices by remember {
|
||||
mutableStateOf(if (isClinicalFlow) KnownDeviceStore.getAll(context) else emptyList())
|
||||
}
|
||||
@@ -287,7 +287,7 @@ fun DeviceScanView(appState: AppState) {
|
||||
Button(
|
||||
onClick = {
|
||||
appState.isDeviceConnected = true
|
||||
appState.currentScreen = com.example.medilightv2android.AppScreen.PIEZO_PERSONALIZATION
|
||||
appState.currentScreen = com.medithings.vesiscan.AppScreen.PIEZO_PERSONALIZATION
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth().height(48.dp),
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
+6
-6
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.ui.views.consent
|
||||
package com.medithings.vesiscan.ui.views.consent
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
@@ -15,13 +15,13 @@ import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import com.example.medilightv2android.R
|
||||
import com.medithings.vesiscan.R
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.example.medilightv2android.AppState
|
||||
import com.example.medilightv2android.services.UserStorage
|
||||
import com.example.medilightv2android.ui.components.BladdyIdleRiveView
|
||||
import com.example.medilightv2android.ui.theme.*
|
||||
import com.medithings.vesiscan.AppState
|
||||
import com.medithings.vesiscan.services.UserStorage
|
||||
import com.medithings.vesiscan.ui.components.BladdyIdleRiveView
|
||||
import com.medithings.vesiscan.ui.theme.*
|
||||
|
||||
@Composable
|
||||
fun ConsentView(appState: AppState) {
|
||||
+6
-6
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.ui.views.history
|
||||
package com.medithings.vesiscan.ui.views.history
|
||||
|
||||
import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.foundation.background
|
||||
@@ -31,11 +31,11 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.example.medilightv2android.AppState
|
||||
import com.example.medilightv2android.R
|
||||
import com.example.medilightv2android.models.*
|
||||
import com.example.medilightv2android.services.MeasurementHistoryStore
|
||||
import com.example.medilightv2android.ui.theme.*
|
||||
import com.medithings.vesiscan.AppState
|
||||
import com.medithings.vesiscan.R
|
||||
import com.medithings.vesiscan.models.*
|
||||
import com.medithings.vesiscan.services.MeasurementHistoryStore
|
||||
import com.medithings.vesiscan.ui.theme.*
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
+11
-11
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.ui.views.home
|
||||
package com.medithings.vesiscan.ui.views.home
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.background
|
||||
@@ -28,12 +28,12 @@ import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import com.example.medilightv2android.R
|
||||
import com.medithings.vesiscan.R
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.example.medilightv2android.AppState
|
||||
import com.example.medilightv2android.ui.components.BladdyIdleRiveView
|
||||
import com.example.medilightv2android.ui.theme.*
|
||||
import com.medithings.vesiscan.AppState
|
||||
import com.medithings.vesiscan.ui.components.BladdyIdleRiveView
|
||||
import com.medithings.vesiscan.ui.theme.*
|
||||
|
||||
@Composable
|
||||
fun HomeView(appState: AppState) {
|
||||
@@ -147,7 +147,7 @@ fun HomeView(appState: AppState) {
|
||||
// Dev 모드 한정 — Clinical R&D Mode 진입
|
||||
if (appState.isDevMode) {
|
||||
Button(
|
||||
onClick = { appState.currentScreen = com.example.medilightv2android.AppScreen.CLINICAL_HOME },
|
||||
onClick = { appState.currentScreen = com.medithings.vesiscan.AppScreen.CLINICAL_HOME },
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 32.dp)
|
||||
@@ -166,7 +166,7 @@ fun HomeView(appState: AppState) {
|
||||
|
||||
// 언어 선택 다이얼로그 — 시스템 / 한국어 / English. 변경 시 Activity recreate.
|
||||
if (showLanguageDialog) {
|
||||
val curMode = com.example.medilightv2android.services.LocalePref.getMode(context)
|
||||
val curMode = com.medithings.vesiscan.services.LocalePref.getMode(context)
|
||||
var selected by remember { mutableStateOf(curMode) }
|
||||
AlertDialog(
|
||||
onDismissRequest = { showLanguageDialog = false },
|
||||
@@ -174,9 +174,9 @@ fun HomeView(appState: AppState) {
|
||||
text = {
|
||||
Column {
|
||||
listOf(
|
||||
com.example.medilightv2android.services.LocalePref.Mode.SYSTEM to stringResource(R.string.language_system_default),
|
||||
com.example.medilightv2android.services.LocalePref.Mode.KO to stringResource(R.string.language_korean),
|
||||
com.example.medilightv2android.services.LocalePref.Mode.EN to stringResource(R.string.language_english),
|
||||
com.medithings.vesiscan.services.LocalePref.Mode.SYSTEM to stringResource(R.string.language_system_default),
|
||||
com.medithings.vesiscan.services.LocalePref.Mode.KO to stringResource(R.string.language_korean),
|
||||
com.medithings.vesiscan.services.LocalePref.Mode.EN to stringResource(R.string.language_english),
|
||||
).forEach { (mode, label) ->
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
@@ -197,7 +197,7 @@ fun HomeView(appState: AppState) {
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(onClick = {
|
||||
com.example.medilightv2android.services.LocalePref.setMode(context, selected)
|
||||
com.medithings.vesiscan.services.LocalePref.setMode(context, selected)
|
||||
showLanguageDialog = false
|
||||
// Activity recreate → attachBaseContext 다시 호출 → 새 locale 적용
|
||||
(context as? android.app.Activity)?.recreate()
|
||||
+6
-6
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.ui.views.monitoring
|
||||
package com.medithings.vesiscan.ui.views.monitoring
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
@@ -21,11 +21,11 @@ import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.example.medilightv2android.R
|
||||
import com.example.medilightv2android.measure.VoidingRecord
|
||||
import com.example.medilightv2android.measure.VoidingRecordStore
|
||||
import com.example.medilightv2android.speech.SpeechRecognizerManager
|
||||
import com.example.medilightv2android.speech.VolumeParser
|
||||
import com.medithings.vesiscan.R
|
||||
import com.medithings.vesiscan.measure.VoidingRecord
|
||||
import com.medithings.vesiscan.measure.VoidingRecordStore
|
||||
import com.medithings.vesiscan.speech.SpeechRecognizerManager
|
||||
import com.medithings.vesiscan.speech.VolumeParser
|
||||
|
||||
/**
|
||||
* Catheterize 바텀시트 — 수기/음성/카메라 3가지 입력
|
||||
+139
-139
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.ui.views.monitoring
|
||||
package com.medithings.vesiscan.ui.views.monitoring
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
@@ -6,7 +6,7 @@ import android.util.Log
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import com.example.medilightv2android.AppScreen
|
||||
import com.medithings.vesiscan.AppScreen
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.foundation.background
|
||||
@@ -42,23 +42,23 @@ import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.example.medilightv2android.AppState
|
||||
import com.example.medilightv2android.ble.BleManager
|
||||
import com.example.medilightv2android.ble.PiezoChannelData
|
||||
import com.example.medilightv2android.managers.PiezoEchoAnalyzer
|
||||
import com.example.medilightv2android.managers.PiezoConstants
|
||||
import com.example.medilightv2android.managers.GreenZoneConstants
|
||||
import com.example.medilightv2android.managers.PiezoHW
|
||||
import com.example.medilightv2android.managers.estimateBladderVolume6ch
|
||||
import com.example.medilightv2android.models.BladderLevel
|
||||
import com.example.medilightv2android.models.UrgencyLevel
|
||||
import com.example.medilightv2android.services.ScanLogStore
|
||||
import com.example.medilightv2android.ui.components.BladdyRiveView
|
||||
import com.example.medilightv2android.ui.components.DonutChartView
|
||||
import com.example.medilightv2android.ui.components.LockableSlider
|
||||
import com.example.medilightv2android.ui.components.ScanLogDialog
|
||||
import com.example.medilightv2android.R
|
||||
import com.example.medilightv2android.ui.theme.*
|
||||
import com.medithings.vesiscan.AppState
|
||||
import com.medithings.vesiscan.ble.BleManager
|
||||
import com.medithings.vesiscan.ble.PiezoChannelData
|
||||
import com.medithings.vesiscan.managers.PiezoEchoAnalyzer
|
||||
import com.medithings.vesiscan.managers.PiezoConstants
|
||||
import com.medithings.vesiscan.managers.GreenZoneConstants
|
||||
import com.medithings.vesiscan.managers.PiezoHW
|
||||
import com.medithings.vesiscan.managers.estimateBladderVolume6ch
|
||||
import com.medithings.vesiscan.models.BladderLevel
|
||||
import com.medithings.vesiscan.models.UrgencyLevel
|
||||
import com.medithings.vesiscan.services.ScanLogStore
|
||||
import com.medithings.vesiscan.ui.components.BladdyRiveView
|
||||
import com.medithings.vesiscan.ui.components.DonutChartView
|
||||
import com.medithings.vesiscan.ui.components.LockableSlider
|
||||
import com.medithings.vesiscan.ui.components.ScanLogDialog
|
||||
import com.medithings.vesiscan.R
|
||||
import com.medithings.vesiscan.ui.theme.*
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@@ -132,21 +132,21 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
val analyzer = remember { PiezoEchoAnalyzer.shared }
|
||||
|
||||
// Posture (flowchart-based, IMU polling — Phase 1) + Wakeup/Walking detector (Phase 2)
|
||||
var currentPosture by remember { mutableStateOf(com.example.medilightv2android.managers.Posture.UNKNOWN) }
|
||||
var currentPosture by remember { mutableStateOf(com.medithings.vesiscan.managers.Posture.UNKNOWN) }
|
||||
var showWakeupAlarm by remember { mutableStateOf(false) } // 주황 — LYING → NON_LYING/WALKING
|
||||
var wakeupAlarmElapsedSec by remember { mutableStateOf(0L) }
|
||||
var showWalkingAlarm by remember { mutableStateOf(false) } // 빨강 — NON_LYING → WALKING
|
||||
val walkingDetector = remember { com.example.medilightv2android.managers.WalkingDetector() }
|
||||
val walkingDetector = remember { com.medithings.vesiscan.managers.WalkingDetector() }
|
||||
val wakeupDetector = remember {
|
||||
com.example.medilightv2android.managers.WakeupDetector(
|
||||
lyingDurationSec = com.example.medilightv2android.services.WakeupAlarmPrefs.lyingDurationSec(context)
|
||||
com.medithings.vesiscan.managers.WakeupDetector(
|
||||
lyingDurationSec = com.medithings.vesiscan.services.WakeupAlarmPrefs.lyingDurationSec(context)
|
||||
).apply {
|
||||
onWakeup = { elapsed ->
|
||||
if (com.example.medilightv2android.services.WakeupAlarmPrefs.isEnabled(context)) {
|
||||
if (com.medithings.vesiscan.services.WakeupAlarmPrefs.isEnabled(context)) {
|
||||
wakeupAlarmElapsedSec = elapsed
|
||||
showWakeupAlarm = true
|
||||
}
|
||||
com.example.medilightv2android.services.PostureEventLogger.logAlarm(
|
||||
com.medithings.vesiscan.services.PostureEventLogger.logAlarm(
|
||||
System.currentTimeMillis(),
|
||||
"wakeup_alarm_lying_${elapsed}s"
|
||||
)
|
||||
@@ -317,7 +317,7 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
val fullChannels = channels.filter { it.buffer.size >= 20 }
|
||||
if (fullChannels.size >= 6) {
|
||||
val sortedBuffers = channels.sortedBy { it.channel }.map { it.buffer }
|
||||
val detachResult = com.example.medilightv2android.managers.DetachmentDetection.detect(sortedBuffers)
|
||||
val detachResult = com.medithings.vesiscan.managers.DetachmentDetection.detect(sortedBuffers)
|
||||
if (detachResult.isDetached) {
|
||||
if (!wasDetached) {
|
||||
Log.w("PiezoMonitor", "DETACHED mean=${"%.1f".format(detachResult.meanAbs)} std=${"%.1f".format(detachResult.stdVal)}")
|
||||
@@ -341,28 +341,28 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
val validChannels = channels.filter { it.isValid }
|
||||
val allChannelsReceived = channels.filter { it.buffer.size >= 20 }.size >= 6
|
||||
if (validChannels.isNotEmpty() && allChannelsReceived) {
|
||||
val method = com.example.medilightv2android.managers.GreenZoneConstants.detectionMethod
|
||||
val analyzerA = com.example.medilightv2android.managers.PiezoEchoAnalyzerA.shared
|
||||
val method = com.medithings.vesiscan.managers.GreenZoneConstants.detectionMethod
|
||||
val analyzerA = com.medithings.vesiscan.managers.PiezoEchoAnalyzerA.shared
|
||||
|
||||
var methodCBvMl: Double? = null
|
||||
val methodLabel: String
|
||||
|
||||
when (method) {
|
||||
com.example.medilightv2android.managers.DetectionMethod.METHOD_C -> {
|
||||
com.medithings.vesiscan.managers.DetectionMethod.METHOD_C -> {
|
||||
methodLabel = "C"
|
||||
// V4.1 detector
|
||||
val v41 = com.example.medilightv2android.walldetect.V41Detector()
|
||||
val v41 = com.medithings.vesiscan.walldetect.V41Detector()
|
||||
val adcMatrix = (0 until 6).map { ch ->
|
||||
val chData = channels.find { it.channel == ch }
|
||||
chData?.buffer?.map { it.toInt() } ?: List(100) { 0 }
|
||||
}
|
||||
val probe = com.example.medilightv2android.walldetect.dto.ProbeProfileDto(
|
||||
name = com.example.medilightv2android.managers.PiezoHW.presetName,
|
||||
val probe = com.medithings.vesiscan.walldetect.dto.ProbeProfileDto(
|
||||
name = com.medithings.vesiscan.managers.PiezoHW.presetName,
|
||||
rMm = 50.2, anteriorAnchorMm = 32.0,
|
||||
fsHz = 537500, cMmPerUs = 1.54,
|
||||
anglesDeg = com.example.medilightv2android.managers.PiezoHW.degreeAll.toList()
|
||||
anglesDeg = com.medithings.vesiscan.managers.PiezoHW.degreeAll.toList()
|
||||
)
|
||||
val sweepInput = com.example.medilightv2android.walldetect.dto.SweepInput(
|
||||
val sweepInput = com.medithings.vesiscan.walldetect.dto.SweepInput(
|
||||
requestId = "measure_${System.currentTimeMillis()}",
|
||||
timestampMs = System.currentTimeMillis(),
|
||||
deviceId = bleManager.connectedDeviceName.value,
|
||||
@@ -395,7 +395,7 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
Log.d("PiezoMonitor", " CH${ch.ch}[C]: ant=${ch.antIdx} post=${ch.postIdx} chord=${ch.chordMm?.let { "%.1f".format(it) }}mm")
|
||||
}
|
||||
}
|
||||
com.example.medilightv2android.managers.DetectionMethod.METHOD_A -> {
|
||||
com.medithings.vesiscan.managers.DetectionMethod.METHOD_A -> {
|
||||
methodLabel = "A"
|
||||
val channelResults = validChannels.map { analyzerA.analyzeChannel(it.buffer, it.channel) }
|
||||
for (ch in channelResults) {
|
||||
@@ -407,14 +407,14 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
if (ch.isValid && ch.result != null) Log.d("PiezoMonitor", " CH${ch.channel}[A]: ant=${ch.result.ant} post=${ch.result.post} urine=${ch.result.urineLen}")
|
||||
}
|
||||
}
|
||||
com.example.medilightv2android.managers.DetectionMethod.METHOD_D -> {
|
||||
com.medithings.vesiscan.managers.DetectionMethod.METHOD_D -> {
|
||||
// 2026-06-30: Detection + BV 통합. MethodDRunner 로 6채널 raw → walls.
|
||||
methodLabel = "D"
|
||||
val signals = (0..5).map { ch ->
|
||||
val cd = channels.find { it.channel == ch }
|
||||
cd?.buffer?.map { it.toDouble() }?.toDoubleArray() ?: DoubleArray(0)
|
||||
}
|
||||
val dets = com.example.medilightv2android.walldetect.MethodDRunner
|
||||
val dets = com.medithings.vesiscan.walldetect.MethodDRunner
|
||||
.detectMultichannel(signals)
|
||||
for (i in 0..5) {
|
||||
val r = dets.getOrNull(i)
|
||||
@@ -443,10 +443,10 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
totalWallCount = allWalls.count { it != null }
|
||||
|
||||
// ADC 로그 저장 — allWalls (선택된 Method) 기준으로 통일
|
||||
val logService = com.example.medilightv2android.services.MeasurementLogService.getInstance(context)
|
||||
val logService = com.medithings.vesiscan.services.MeasurementLogService.getInstance(context)
|
||||
val channelLogs = (0..5).map { ch ->
|
||||
val w = allWalls[ch]
|
||||
com.example.medilightv2android.services.ChannelLogEntry(
|
||||
com.medithings.vesiscan.services.ChannelLogEntry(
|
||||
channel = ch,
|
||||
ant = w?.first,
|
||||
post = w?.second,
|
||||
@@ -456,7 +456,7 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
}
|
||||
val rawADC = channels.sortedBy { it.channel }.map { it.buffer }
|
||||
|
||||
val bvMethodSetting = com.example.medilightv2android.managers.GreenZoneConstants.bvMethod
|
||||
val bvMethodSetting = com.medithings.vesiscan.managers.GreenZoneConstants.bvMethod
|
||||
// ── Ant-offset adjustment for BV calculation ───────────────────────────────
|
||||
// The user-facing setting is a non-negative magnitude in mm. BV calculation
|
||||
// subtracts it from each channel's anterior wall index (probe-ward shift).
|
||||
@@ -467,13 +467,13 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
val antOffsetSamples =
|
||||
if (antOffsetMm != 0)
|
||||
(antOffsetMm.toDouble() /
|
||||
com.example.medilightv2android.managers.PiezoHW.distancePerSample).toInt()
|
||||
com.medithings.vesiscan.managers.PiezoHW.distancePerSample).toInt()
|
||||
else 0
|
||||
|
||||
// 2026-06-30: BvMethod.METHOD_D 시 Method D walls 사용. 단 detection 이
|
||||
// 이미 METHOD_D 면 allWalls 가 곧 Method D → recompute 생략.
|
||||
val useMethodDBv = bvMethodSetting == com.example.medilightv2android.managers.BvMethod.METHOD_D
|
||||
val detectionIsMethodD = method == com.example.medilightv2android.managers.DetectionMethod.METHOD_D
|
||||
val useMethodDBv = bvMethodSetting == com.medithings.vesiscan.managers.BvMethod.METHOD_D
|
||||
val detectionIsMethodD = method == com.medithings.vesiscan.managers.DetectionMethod.METHOD_D
|
||||
val sourceAllWalls: List<Pair<Int, Int>?> = if (useMethodDBv && !detectionIsMethodD) {
|
||||
val signals = (0..5).map { ch ->
|
||||
val cd = channels.find { it.channel == ch }
|
||||
@@ -482,10 +482,10 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
if (signals.all { it.isEmpty() }) allWalls
|
||||
// 2026-07-02: NEW BV lib (piezophantomtest 4830e7c) lumen_inset_frac=0.15
|
||||
// MethodDResult 의 (ls, le) 로 벽을 lumen 안쪽으로 15% 이동.
|
||||
else com.example.medilightv2android.walldetect.MethodDRunner
|
||||
else com.medithings.vesiscan.walldetect.MethodDRunner
|
||||
.detectMultichannel(signals)
|
||||
.map { r -> r?.let {
|
||||
com.example.medilightv2android.managers.applyLumenInsetOne(
|
||||
com.medithings.vesiscan.managers.applyLumenInsetOne(
|
||||
it.ant, it.post, it.lowStart, it.lowEnd
|
||||
)
|
||||
} }
|
||||
@@ -498,8 +498,8 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
}
|
||||
val effectiveCenterWalls = (0..3).count { effectiveAllWalls[it] != null }
|
||||
|
||||
val useV41Bv = method == com.example.medilightv2android.managers.DetectionMethod.METHOD_C
|
||||
&& bvMethodSetting == com.example.medilightv2android.managers.BvMethod.V41
|
||||
val useV41Bv = method == com.medithings.vesiscan.managers.DetectionMethod.METHOD_C
|
||||
&& bvMethodSetting == com.medithings.vesiscan.managers.BvMethod.V41
|
||||
&& methodCBvMl != null
|
||||
&& antOffsetSamples == 0
|
||||
&& effectiveCenterWalls >= 4 // center 4 모두 필요
|
||||
@@ -510,7 +510,7 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
bleManager.debugLogger.measurementResult(methodCBvMl, 1.0, totalWallCount,
|
||||
(0..5).map { allWalls[it]?.let { w -> w.second - w.first } ?: 0 })
|
||||
logService.logMeasurement(methodCBvMl, channelLogs, rawADC)
|
||||
com.example.medilightv2android.services.AdcCsvLogger.log(rawADC, methodCBvMl)
|
||||
com.medithings.vesiscan.services.AdcCsvLogger.log(rawADC, methodCBvMl)
|
||||
} else if (effectiveCenterWalls >= 4) {
|
||||
// 검증 로그 — ant offset 비활성(0)이 아닐 때 chord 변화 출력
|
||||
if (antOffsetSamples != 0) {
|
||||
@@ -534,18 +534,18 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
(0..5).map { allWalls[it]?.let { w -> w.second - w.first } ?: 0 },
|
||||
otsuThreshold = analyzer.lastOtsuThreshold)
|
||||
logService.logMeasurement(bvResult.volumeMl, channelLogs, rawADC)
|
||||
com.example.medilightv2android.services.AdcCsvLogger.log(rawADC, bvResult.volumeMl, bvResult.lrRatio)
|
||||
com.medithings.vesiscan.services.AdcCsvLogger.log(rawADC, bvResult.volumeMl, bvResult.lrRatio)
|
||||
}
|
||||
} else if (totalWallCount > 0) {
|
||||
Log.w("PiezoMonitor", "No center channels: center=0 total=$totalWallCount/6")
|
||||
bleManager.debugLogger.warn("BV_SKIP scan=${com.example.medilightv2android.services.AdcCsvLogger.lastScanId} center=0 total=$totalWallCount/6")
|
||||
com.example.medilightv2android.services.AdcCsvLogger.log(rawADC, null)
|
||||
bleManager.debugLogger.warn("BV_SKIP scan=${com.medithings.vesiscan.services.AdcCsvLogger.lastScanId} center=0 total=$totalWallCount/6")
|
||||
com.medithings.vesiscan.services.AdcCsvLogger.log(rawADC, null)
|
||||
}
|
||||
} else {
|
||||
Log.d("PiezoMonitor", "No valid channels — volume unchanged")
|
||||
bleManager.debugLogger.warn("BV_FAIL scan=${com.example.medilightv2android.services.AdcCsvLogger.lastScanId} no valid channels")
|
||||
bleManager.debugLogger.warn("BV_FAIL scan=${com.medithings.vesiscan.services.AdcCsvLogger.lastScanId} no valid channels")
|
||||
val failADC = channels.sortedBy { it.channel }.map { it.buffer }
|
||||
com.example.medilightv2android.services.AdcCsvLogger.log(failADC, null)
|
||||
com.medithings.vesiscan.services.AdcCsvLogger.log(failADC, null)
|
||||
}
|
||||
|
||||
// allWalls를 UI state에 저장 (ChannelPanel에서 사용)
|
||||
@@ -754,8 +754,8 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
// Posture event 로깅 — 검증용 CSV (앱 진입 시 새 파일)
|
||||
// + 사용자 튜닝 임계값 SharedPreferences 에서 로드
|
||||
LaunchedEffect(Unit) {
|
||||
com.example.medilightv2android.services.PostureTuningPrefs.loadAll(context)
|
||||
com.example.medilightv2android.services.PostureEventLogger.startSession(context)
|
||||
com.medithings.vesiscan.services.PostureTuningPrefs.loadAll(context)
|
||||
com.medithings.vesiscan.services.PostureEventLogger.startSession(context)
|
||||
}
|
||||
|
||||
// IMU polling + 자세 분류 — msp 명령 (rsp: 응답, IMU-only).
|
||||
@@ -766,12 +766,12 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
LaunchedEffect(isConnected, isDemoMode) {
|
||||
Log.d("ImuDbg", "LaunchedEffect start isConnected=$isConnected isDemoMode=$isDemoMode")
|
||||
if (isDemoMode) {
|
||||
currentPosture = com.example.medilightv2android.managers.Posture.LYING
|
||||
currentPosture = com.medithings.vesiscan.managers.Posture.LYING
|
||||
return@LaunchedEffect
|
||||
}
|
||||
var unknownStreak = 0
|
||||
bleManager.imuCollector.onComplete = { samples ->
|
||||
val r = com.example.medilightv2android.managers.ImuPostureClassifier.classify(samples)
|
||||
val r = com.medithings.vesiscan.managers.ImuPostureClassifier.classify(samples)
|
||||
val nowMs = System.currentTimeMillis()
|
||||
// Walking detector — pitch 가 valid 일 때만 의미. acc gate fail 시 그대로 update (wmean/wstd 계산 + 시간 grace 처리).
|
||||
val walkSnap = walkingDetector.update(samples, r.pitchDeg, nowMs)
|
||||
@@ -779,34 +779,34 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
|
||||
// Composite posture — WALKING 이 UNKNOWN/NON_LYING 보다 우선 (자체 게이트 신뢰)
|
||||
val composite = when {
|
||||
isWalkingNow -> com.example.medilightv2android.managers.Posture.WALKING
|
||||
r.posture == com.example.medilightv2android.managers.Posture.UNKNOWN -> com.example.medilightv2android.managers.Posture.UNKNOWN
|
||||
isWalkingNow -> com.medithings.vesiscan.managers.Posture.WALKING
|
||||
r.posture == com.medithings.vesiscan.managers.Posture.UNKNOWN -> com.medithings.vesiscan.managers.Posture.UNKNOWN
|
||||
else -> r.posture // LYING or NON_LYING
|
||||
}
|
||||
|
||||
if (composite != com.example.medilightv2android.managers.Posture.UNKNOWN) {
|
||||
if (composite != com.medithings.vesiscan.managers.Posture.UNKNOWN) {
|
||||
currentPosture = composite
|
||||
wakeupDetector.update(composite)
|
||||
unknownStreak = 0
|
||||
} else {
|
||||
unknownStreak++
|
||||
if (unknownStreak >= 3) currentPosture = com.example.medilightv2android.managers.Posture.UNKNOWN
|
||||
if (unknownStreak >= 3) currentPosture = com.medithings.vesiscan.managers.Posture.UNKNOWN
|
||||
}
|
||||
|
||||
// Walking 시작 전이 (NON_WALKING → WALKING) — critical 알람 (alarm enabled 시)
|
||||
if (isWalkingNow && !prevIsWalking) {
|
||||
if (com.example.medilightv2android.services.WakeupAlarmPrefs.isEnabled(context)) {
|
||||
if (com.medithings.vesiscan.services.WakeupAlarmPrefs.isEnabled(context)) {
|
||||
showWalkingAlarm = true
|
||||
}
|
||||
com.example.medilightv2android.services.PostureEventLogger.logAlarm(nowMs, "walking_start")
|
||||
com.medithings.vesiscan.services.PostureEventLogger.logAlarm(nowMs, "walking_start")
|
||||
}
|
||||
if (!isWalkingNow && prevIsWalking) {
|
||||
com.example.medilightv2android.services.PostureEventLogger.logAlarm(nowMs, "walking_end")
|
||||
com.medithings.vesiscan.services.PostureEventLogger.logAlarm(nowMs, "walking_end")
|
||||
}
|
||||
prevIsWalking = isWalkingNow
|
||||
|
||||
// CSV logging — 검증용
|
||||
com.example.medilightv2android.services.PostureEventLogger.logCycle(
|
||||
com.medithings.vesiscan.services.PostureEventLogger.logCycle(
|
||||
nowMs, composite.name, isWalkingNow,
|
||||
r.pitchDeg, walkSnap.wmean, walkSnap.wstd, r.accMag, r.gyroMagDps,
|
||||
)
|
||||
@@ -961,8 +961,8 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
val quickVol = if (lastVolumeMl > 0) lastVolumeMl.toInt() else appState.estimatedVolume
|
||||
Surface(
|
||||
onClick = {
|
||||
com.example.medilightv2android.measure.VoidingRecordStore.add(
|
||||
context, com.example.medilightv2android.measure.VoidingRecord(
|
||||
com.medithings.vesiscan.measure.VoidingRecordStore.add(
|
||||
context, com.medithings.vesiscan.measure.VoidingRecord(
|
||||
volume = quickVol, method = "catheterize"
|
||||
)
|
||||
)
|
||||
@@ -1021,8 +1021,8 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
TextButton(onClick = {
|
||||
val vol = volumeText.toIntOrNull()
|
||||
if (vol != null && vol in 1..1000) {
|
||||
com.example.medilightv2android.measure.VoidingRecordStore.add(
|
||||
context, com.example.medilightv2android.measure.VoidingRecord(volume = vol, method = "manual")
|
||||
com.medithings.vesiscan.measure.VoidingRecordStore.add(
|
||||
context, com.medithings.vesiscan.measure.VoidingRecord(volume = vol, method = "manual")
|
||||
)
|
||||
appState.resetLevel()
|
||||
android.widget.Toast.makeText(context, context.getString(R.string.registered_diary), android.widget.Toast.LENGTH_SHORT).show()
|
||||
@@ -1038,7 +1038,7 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
if (showVoiceInput) {
|
||||
var voiceResult by remember { mutableStateOf<String?>(null) }
|
||||
var isListening by remember { mutableStateOf(false) }
|
||||
var speechMgr by remember { mutableStateOf<com.example.medilightv2android.speech.SpeechRecognizerManager?>(null) }
|
||||
var speechMgr by remember { mutableStateOf<com.medithings.vesiscan.speech.SpeechRecognizerManager?>(null) }
|
||||
|
||||
DisposableEffect(Unit) { onDispose { speechMgr?.destroy() } }
|
||||
|
||||
@@ -1047,14 +1047,14 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
if (androidx.core.content.ContextCompat.checkSelfPermission(context, android.Manifest.permission.RECORD_AUDIO)
|
||||
== android.content.pm.PackageManager.PERMISSION_GRANTED) {
|
||||
isListening = true
|
||||
speechMgr = com.example.medilightv2android.speech.SpeechRecognizerManager(
|
||||
speechMgr = com.medithings.vesiscan.speech.SpeechRecognizerManager(
|
||||
context = context,
|
||||
onResult = { candidates ->
|
||||
isListening = false
|
||||
val parsed = com.example.medilightv2android.speech.VolumeParser.parseBest(candidates)
|
||||
val parsed = com.medithings.vesiscan.speech.VolumeParser.parseBest(candidates)
|
||||
if (parsed != null) {
|
||||
com.example.medilightv2android.measure.VoidingRecordStore.add(
|
||||
context, com.example.medilightv2android.measure.VoidingRecord(volume = parsed.volumeMl, method = "voice")
|
||||
com.medithings.vesiscan.measure.VoidingRecordStore.add(
|
||||
context, com.medithings.vesiscan.measure.VoidingRecord(volume = parsed.volumeMl, method = "voice")
|
||||
)
|
||||
appState.resetLevel()
|
||||
android.widget.Toast.makeText(context, context.getString(R.string.registered_ml, parsed.volumeMl), android.widget.Toast.LENGTH_SHORT).show()
|
||||
@@ -1168,19 +1168,19 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
// Dev mode 에서만 노출 (legacy 유지) — 일반 사용자에겐 숨김.
|
||||
if (appState.isDevMode) {
|
||||
var rawBleCapturing by remember {
|
||||
mutableStateOf(com.example.medilightv2android.services.RawBleLogger.isCapturing)
|
||||
mutableStateOf(com.medithings.vesiscan.services.RawBleLogger.isCapturing)
|
||||
}
|
||||
IconButton(
|
||||
onClick = {
|
||||
if (rawBleCapturing) {
|
||||
val f = com.example.medilightv2android.services.RawBleLogger.stopCapture()
|
||||
val n = com.example.medilightv2android.services.RawBleLogger.count
|
||||
val f = com.medithings.vesiscan.services.RawBleLogger.stopCapture()
|
||||
val n = com.medithings.vesiscan.services.RawBleLogger.count
|
||||
rawBleCapturing = false
|
||||
android.widget.Toast.makeText(context,
|
||||
"Raw BLE: $n packets saved to ${f?.name}",
|
||||
android.widget.Toast.LENGTH_LONG).show()
|
||||
} else {
|
||||
val f = com.example.medilightv2android.services.RawBleLogger.startCapture()
|
||||
val f = com.medithings.vesiscan.services.RawBleLogger.startCapture()
|
||||
rawBleCapturing = true
|
||||
android.widget.Toast.makeText(context,
|
||||
"Raw BLE capture started → ${f.name}",
|
||||
@@ -1256,8 +1256,8 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
// BLE 끊김 banner는 사내 테스트 피드백으로 제거됨 — 백그라운드 자동 재연결만 유지.
|
||||
|
||||
// 펌웨어 구버전 경고
|
||||
com.example.medilightv2android.ui.components.FirmwareWarningBanner(bleManager)
|
||||
com.example.medilightv2android.ui.components.BatteryWarningBanner(bleManager)
|
||||
com.medithings.vesiscan.ui.components.FirmwareWarningBanner(bleManager)
|
||||
com.medithings.vesiscan.ui.components.BatteryWarningBanner(bleManager)
|
||||
|
||||
val scrollState = rememberScrollState()
|
||||
LaunchedEffect(showSettings) {
|
||||
@@ -1306,22 +1306,22 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
label = "posture-chip"
|
||||
) { posture ->
|
||||
val icon = when (posture) {
|
||||
com.example.medilightv2android.managers.Posture.LYING -> Icons.Default.Hotel
|
||||
com.example.medilightv2android.managers.Posture.NON_LYING -> Icons.Default.AccessibilityNew
|
||||
com.example.medilightv2android.managers.Posture.WALKING -> Icons.Default.DirectionsWalk
|
||||
com.example.medilightv2android.managers.Posture.UNKNOWN -> Icons.Default.HelpOutline
|
||||
com.medithings.vesiscan.managers.Posture.LYING -> Icons.Default.Hotel
|
||||
com.medithings.vesiscan.managers.Posture.NON_LYING -> Icons.Default.AccessibilityNew
|
||||
com.medithings.vesiscan.managers.Posture.WALKING -> Icons.Default.DirectionsWalk
|
||||
com.medithings.vesiscan.managers.Posture.UNKNOWN -> Icons.Default.HelpOutline
|
||||
}
|
||||
val tint = when (posture) {
|
||||
com.example.medilightv2android.managers.Posture.LYING -> Color(0xFF2196F3)
|
||||
com.example.medilightv2android.managers.Posture.NON_LYING -> Color(0xFF4CAF50)
|
||||
com.example.medilightv2android.managers.Posture.WALKING -> Color(0xFFD32F2F)
|
||||
com.example.medilightv2android.managers.Posture.UNKNOWN -> Color(0xFF616161) // 진한 회색 — 가시성 확보
|
||||
com.medithings.vesiscan.managers.Posture.LYING -> Color(0xFF2196F3)
|
||||
com.medithings.vesiscan.managers.Posture.NON_LYING -> Color(0xFF4CAF50)
|
||||
com.medithings.vesiscan.managers.Posture.WALKING -> Color(0xFFD32F2F)
|
||||
com.medithings.vesiscan.managers.Posture.UNKNOWN -> Color(0xFF616161) // 진한 회색 — 가시성 확보
|
||||
}
|
||||
val label = when (posture) {
|
||||
com.example.medilightv2android.managers.Posture.LYING -> stringResource(R.string.piezo_posture_lying)
|
||||
com.example.medilightv2android.managers.Posture.NON_LYING -> stringResource(R.string.piezo_posture_upright)
|
||||
com.example.medilightv2android.managers.Posture.WALKING -> stringResource(R.string.piezo_posture_walking)
|
||||
com.example.medilightv2android.managers.Posture.UNKNOWN -> stringResource(R.string.piezo_posture_detecting)
|
||||
com.medithings.vesiscan.managers.Posture.LYING -> stringResource(R.string.piezo_posture_lying)
|
||||
com.medithings.vesiscan.managers.Posture.NON_LYING -> stringResource(R.string.piezo_posture_upright)
|
||||
com.medithings.vesiscan.managers.Posture.WALKING -> stringResource(R.string.piezo_posture_walking)
|
||||
com.medithings.vesiscan.managers.Posture.UNKNOWN -> stringResource(R.string.piezo_posture_detecting)
|
||||
}
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
@@ -1458,8 +1458,8 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
Button(
|
||||
onClick = {
|
||||
val quickVol = if (lastVolumeMl > 0) lastVolumeMl.toInt() else appState.estimatedVolume
|
||||
com.example.medilightv2android.measure.VoidingRecordStore.add(
|
||||
context, com.example.medilightv2android.measure.VoidingRecord(
|
||||
com.medithings.vesiscan.measure.VoidingRecordStore.add(
|
||||
context, com.medithings.vesiscan.measure.VoidingRecord(
|
||||
volume = quickVol, method = "catheterize"
|
||||
)
|
||||
)
|
||||
@@ -1847,22 +1847,22 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
HorizontalDivider(modifier = Modifier.padding(vertical = dividerPadding))
|
||||
|
||||
// Detection Method A/B/C
|
||||
var selectedMethod by remember { mutableStateOf(com.example.medilightv2android.managers.GreenZoneConstants.detectionMethod) }
|
||||
var selectedMethod by remember { mutableStateOf(com.medithings.vesiscan.managers.GreenZoneConstants.detectionMethod) }
|
||||
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
|
||||
Text("Detection", fontSize = labelSize, fontWeight = FontWeight.SemiBold)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
val methods = listOf(
|
||||
com.example.medilightv2android.managers.DetectionMethod.METHOD_A to "A",
|
||||
com.example.medilightv2android.managers.DetectionMethod.METHOD_B to "B",
|
||||
com.example.medilightv2android.managers.DetectionMethod.METHOD_C to "C",
|
||||
com.example.medilightv2android.managers.DetectionMethod.METHOD_D to "D"
|
||||
com.medithings.vesiscan.managers.DetectionMethod.METHOD_A to "A",
|
||||
com.medithings.vesiscan.managers.DetectionMethod.METHOD_B to "B",
|
||||
com.medithings.vesiscan.managers.DetectionMethod.METHOD_C to "C",
|
||||
com.medithings.vesiscan.managers.DetectionMethod.METHOD_D to "D"
|
||||
)
|
||||
val colors = listOf(Color(0xFF9C27B0), MlPrimary, Color(0xFFFF5722), Color(0xFF7C3AED))
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) {
|
||||
methods.forEachIndexed { idx, (m, label) ->
|
||||
val sel = selectedMethod == m
|
||||
Button(
|
||||
onClick = { selectedMethod = m; com.example.medilightv2android.managers.GreenZoneConstants.detectionMethod = m },
|
||||
onClick = { selectedMethod = m; com.medithings.vesiscan.managers.GreenZoneConstants.detectionMethod = m },
|
||||
modifier = Modifier.height(32.dp),
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
@@ -1880,21 +1880,21 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
HorizontalDivider(modifier = Modifier.padding(vertical = dividerPadding))
|
||||
|
||||
// BV Method (Frustum / V41)
|
||||
var selectedBvMethod by remember { mutableStateOf(com.example.medilightv2android.managers.GreenZoneConstants.bvMethod) }
|
||||
var selectedBvMethod by remember { mutableStateOf(com.medithings.vesiscan.managers.GreenZoneConstants.bvMethod) }
|
||||
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
|
||||
Text("BV", fontSize = labelSize, fontWeight = FontWeight.SemiBold)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
val bvMethods = listOf(
|
||||
com.example.medilightv2android.managers.BvMethod.FRUSTUM to "Frustum",
|
||||
com.example.medilightv2android.managers.BvMethod.V41 to "V41",
|
||||
com.example.medilightv2android.managers.BvMethod.METHOD_D to "Method D"
|
||||
com.medithings.vesiscan.managers.BvMethod.FRUSTUM to "Frustum",
|
||||
com.medithings.vesiscan.managers.BvMethod.V41 to "V41",
|
||||
com.medithings.vesiscan.managers.BvMethod.METHOD_D to "Method D"
|
||||
)
|
||||
val bvColors = listOf(MlPrimary, Color(0xFFFF5722), Color(0xFF7C3AED))
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) {
|
||||
bvMethods.forEachIndexed { idx, (m, label) ->
|
||||
val sel = selectedBvMethod == m
|
||||
Button(
|
||||
onClick = { selectedBvMethod = m; com.example.medilightv2android.managers.GreenZoneConstants.bvMethod = m },
|
||||
onClick = { selectedBvMethod = m; com.medithings.vesiscan.managers.GreenZoneConstants.bvMethod = m },
|
||||
modifier = Modifier.height(32.dp),
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
@@ -1913,7 +1913,7 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
|
||||
// 2026-07-01: lr_ratio override (algorithm 팀 4830e7c 표준)
|
||||
var lrFixed by remember {
|
||||
mutableStateOf(com.example.medilightv2android.managers.GreenZoneConstants.lrRatioOverride != null)
|
||||
mutableStateOf(com.medithings.vesiscan.managers.GreenZoneConstants.lrRatioOverride != null)
|
||||
}
|
||||
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
|
||||
Text("lr=1.0 fixed", fontSize = labelSize, fontWeight = FontWeight.SemiBold)
|
||||
@@ -1921,7 +1921,7 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
Switch(checked = lrFixed,
|
||||
onCheckedChange = {
|
||||
lrFixed = it
|
||||
com.example.medilightv2android.managers.GreenZoneConstants.lrRatioOverride =
|
||||
com.medithings.vesiscan.managers.GreenZoneConstants.lrRatioOverride =
|
||||
if (it) 1.0 else null
|
||||
},
|
||||
colors = SwitchDefaults.colors(checkedTrackColor = MlPrimary))
|
||||
@@ -1970,7 +1970,7 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
LockableSlider(
|
||||
value = pitchThrVal,
|
||||
onValueChange = { pitchThrVal = it; GreenZoneConstants.pitchLyingThreshold = it
|
||||
com.example.medilightv2android.services.PostureTuningPrefs.saveAll(context) },
|
||||
com.medithings.vesiscan.services.PostureTuningPrefs.saveAll(context) },
|
||||
valueRange = 10f..70f,
|
||||
steps = 11,
|
||||
colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary)
|
||||
@@ -1980,7 +1980,7 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
|
||||
// Wakeup Alarm toggle (Personalization 페이지 와 동일 prefs)
|
||||
var wakeupEnabled by remember {
|
||||
mutableStateOf(com.example.medilightv2android.services.WakeupAlarmPrefs.isEnabled(context))
|
||||
mutableStateOf(com.medithings.vesiscan.services.WakeupAlarmPrefs.isEnabled(context))
|
||||
}
|
||||
Row(verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.fillMaxWidth()) {
|
||||
@@ -1993,7 +1993,7 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
checked = wakeupEnabled,
|
||||
onCheckedChange = {
|
||||
wakeupEnabled = it
|
||||
com.example.medilightv2android.services.WakeupAlarmPrefs.setEnabled(context, it)
|
||||
com.medithings.vesiscan.services.WakeupAlarmPrefs.setEnabled(context, it)
|
||||
},
|
||||
colors = SwitchDefaults.colors(checkedTrackColor = Color(0xFFD32F2F))
|
||||
)
|
||||
@@ -2002,7 +2002,7 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
// Wakeup 알람 발동을 위한 LYING 유지 시간 (dev 조절 가능)
|
||||
var lyingDurVal by remember {
|
||||
mutableStateOf(
|
||||
com.example.medilightv2android.services.WakeupAlarmPrefs.lyingDurationSec(context).toFloat()
|
||||
com.medithings.vesiscan.services.WakeupAlarmPrefs.lyingDurationSec(context).toFloat()
|
||||
)
|
||||
}
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
@@ -2021,7 +2021,7 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
onValueChange = {
|
||||
lyingDurVal = it
|
||||
val sec = it.toInt()
|
||||
com.example.medilightv2android.services.WakeupAlarmPrefs.setLyingDurationSec(context, sec)
|
||||
com.medithings.vesiscan.services.WakeupAlarmPrefs.setLyingDurationSec(context, sec)
|
||||
wakeupDetector.lyingDurationSec = sec
|
||||
},
|
||||
valueRange = 5f..600f, // 5초 ~ 10분
|
||||
@@ -2046,7 +2046,7 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
onValueChange = {
|
||||
pollIntervalVal = it
|
||||
GreenZoneConstants.posturePollIntervalMs = (it * 1000).toLong()
|
||||
com.example.medilightv2android.services.PostureTuningPrefs.saveAll(context)
|
||||
com.medithings.vesiscan.services.PostureTuningPrefs.saveAll(context)
|
||||
},
|
||||
valueRange = 1f..15f, // 1초 ~ 15초
|
||||
steps = 0,
|
||||
@@ -2066,7 +2066,7 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
}
|
||||
LockableSlider(value = walkPitchVal, onValueChange = {
|
||||
walkPitchVal = it; GreenZoneConstants.walkingMinPitchDeg = it
|
||||
com.example.medilightv2android.services.PostureTuningPrefs.saveAll(context)
|
||||
com.medithings.vesiscan.services.PostureTuningPrefs.saveAll(context)
|
||||
}, valueRange = 20f..70f, colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary))
|
||||
|
||||
var walkStartWmean by remember { mutableStateOf(GreenZoneConstants.walkingStartWmean) }
|
||||
@@ -2077,7 +2077,7 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
}
|
||||
LockableSlider(value = walkStartWmean, onValueChange = {
|
||||
walkStartWmean = it; GreenZoneConstants.walkingStartWmean = it
|
||||
com.example.medilightv2android.services.PostureTuningPrefs.saveAll(context)
|
||||
com.medithings.vesiscan.services.PostureTuningPrefs.saveAll(context)
|
||||
}, valueRange = 1f..30f, colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary))
|
||||
|
||||
var walkStartWstd by remember { mutableStateOf(GreenZoneConstants.walkingStartWstd) }
|
||||
@@ -2088,7 +2088,7 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
}
|
||||
LockableSlider(value = walkStartWstd, onValueChange = {
|
||||
walkStartWstd = it; GreenZoneConstants.walkingStartWstd = it
|
||||
com.example.medilightv2android.services.PostureTuningPrefs.saveAll(context)
|
||||
com.medithings.vesiscan.services.PostureTuningPrefs.saveAll(context)
|
||||
}, valueRange = 0.5f..10f, colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary))
|
||||
|
||||
var walkKeepWmean by remember { mutableStateOf(GreenZoneConstants.walkingKeepWmean) }
|
||||
@@ -2099,7 +2099,7 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
}
|
||||
LockableSlider(value = walkKeepWmean, onValueChange = {
|
||||
walkKeepWmean = it; GreenZoneConstants.walkingKeepWmean = it
|
||||
com.example.medilightv2android.services.PostureTuningPrefs.saveAll(context)
|
||||
com.medithings.vesiscan.services.PostureTuningPrefs.saveAll(context)
|
||||
}, valueRange = 0.5f..30f, colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary))
|
||||
|
||||
// Walking 시간 변수 (sec)
|
||||
@@ -2111,7 +2111,7 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
}
|
||||
LockableSlider(value = walkStartHold, onValueChange = {
|
||||
walkStartHold = it; GreenZoneConstants.walkingStartHoldMs = (it * 1000).toLong()
|
||||
com.example.medilightv2android.services.PostureTuningPrefs.saveAll(context)
|
||||
com.medithings.vesiscan.services.PostureTuningPrefs.saveAll(context)
|
||||
}, valueRange = 0.5f..10f, colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary))
|
||||
|
||||
var walkKeepHold by remember { mutableStateOf(GreenZoneConstants.walkingKeepHoldMs / 1000f) }
|
||||
@@ -2122,7 +2122,7 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
}
|
||||
LockableSlider(value = walkKeepHold, onValueChange = {
|
||||
walkKeepHold = it; GreenZoneConstants.walkingKeepHoldMs = (it * 1000).toLong()
|
||||
com.example.medilightv2android.services.PostureTuningPrefs.saveAll(context)
|
||||
com.medithings.vesiscan.services.PostureTuningPrefs.saveAll(context)
|
||||
}, valueRange = 0.5f..10f, colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary))
|
||||
|
||||
var walkWindow by remember { mutableStateOf(GreenZoneConstants.walkingWindowMs / 1000f) }
|
||||
@@ -2133,7 +2133,7 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
}
|
||||
LockableSlider(value = walkWindow, onValueChange = {
|
||||
walkWindow = it; GreenZoneConstants.walkingWindowMs = (it * 1000).toLong()
|
||||
com.example.medilightv2android.services.PostureTuningPrefs.saveAll(context)
|
||||
com.medithings.vesiscan.services.PostureTuningPrefs.saveAll(context)
|
||||
}, valueRange = 0.5f..5f, colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary))
|
||||
|
||||
HorizontalDivider(modifier = Modifier.padding(vertical = dividerPadding))
|
||||
@@ -2149,7 +2149,7 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
}
|
||||
LockableSlider(value = accMagMin, onValueChange = {
|
||||
accMagMin = it; GreenZoneConstants.postureAccMagMin = it
|
||||
com.example.medilightv2android.services.PostureTuningPrefs.saveAll(context)
|
||||
com.medithings.vesiscan.services.PostureTuningPrefs.saveAll(context)
|
||||
}, valueRange = 0.3f..1.0f, colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary))
|
||||
|
||||
var accMagMax by remember { mutableStateOf(GreenZoneConstants.postureAccMagMax) }
|
||||
@@ -2160,7 +2160,7 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
}
|
||||
LockableSlider(value = accMagMax, onValueChange = {
|
||||
accMagMax = it; GreenZoneConstants.postureAccMagMax = it
|
||||
com.example.medilightv2android.services.PostureTuningPrefs.saveAll(context)
|
||||
com.medithings.vesiscan.services.PostureTuningPrefs.saveAll(context)
|
||||
}, valueRange = 1.0f..3.0f, colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary))
|
||||
|
||||
HorizontalDivider(modifier = Modifier.padding(vertical = dividerPadding))
|
||||
@@ -2168,7 +2168,7 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
// Reset to defaults — 모든 threshold 를 default 로 복원 + prefs 저장.
|
||||
OutlinedButton(
|
||||
onClick = {
|
||||
com.example.medilightv2android.services.PostureTuningPrefs.resetAll(context)
|
||||
com.medithings.vesiscan.services.PostureTuningPrefs.resetAll(context)
|
||||
android.widget.Toast.makeText(context,
|
||||
"Defaults restored — close & reopen Settings to refresh sliders",
|
||||
android.widget.Toast.LENGTH_LONG).show()
|
||||
@@ -2201,7 +2201,7 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
for ((tag, label) in annotateLabels) {
|
||||
Button(
|
||||
onClick = {
|
||||
com.example.medilightv2android.services.PostureEventLogger.annotate(tag)
|
||||
com.medithings.vesiscan.services.PostureEventLogger.annotate(tag)
|
||||
android.widget.Toast.makeText(context,
|
||||
"Marked: $label", android.widget.Toast.LENGTH_SHORT).show()
|
||||
},
|
||||
@@ -2281,7 +2281,7 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
Text(stringResource(R.string.piezo_settings_app), fontSize = 13.sp, color = MlSecondaryText)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Text(
|
||||
com.example.medilightv2android.BuildConfig.VERSION_NAME,
|
||||
com.medithings.vesiscan.BuildConfig.VERSION_NAME,
|
||||
fontSize = 13.sp,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
color = MlPrimary,
|
||||
@@ -2378,7 +2378,7 @@ fun PiezoMonitoringView(appState: AppState) {
|
||||
Button(onClick = {
|
||||
showRealignPrompt = false
|
||||
autoFailCount = 0
|
||||
appState.currentScreen = com.example.medilightv2android.AppScreen.PLACEMENT_GUIDE
|
||||
appState.currentScreen = com.medithings.vesiscan.AppScreen.PLACEMENT_GUIDE
|
||||
}) { Text(stringResource(R.string.piezo_realign_button)) }
|
||||
},
|
||||
dismissButton = {
|
||||
@@ -2443,11 +2443,11 @@ private fun ChannelPanel(
|
||||
}
|
||||
} else {
|
||||
// Zone indicator
|
||||
val curMethod = com.example.medilightv2android.managers.GreenZoneConstants.detectionMethod
|
||||
val analyzerAPanel = com.example.medilightv2android.managers.PiezoEchoAnalyzerA.shared
|
||||
val curMethod = com.medithings.vesiscan.managers.GreenZoneConstants.detectionMethod
|
||||
val analyzerAPanel = com.medithings.vesiscan.managers.PiezoEchoAnalyzerA.shared
|
||||
val analyses = lastMultiChannelResult.map { chData ->
|
||||
when (curMethod) {
|
||||
com.example.medilightv2android.managers.DetectionMethod.METHOD_A -> analyzerAPanel.analyzeChannel(chData.buffer, chData.channel)
|
||||
com.medithings.vesiscan.managers.DetectionMethod.METHOD_A -> analyzerAPanel.analyzeChannel(chData.buffer, chData.channel)
|
||||
else -> analyzer.analyzeChannel(chData.buffer, chData.channel)
|
||||
}
|
||||
}
|
||||
@@ -2509,7 +2509,7 @@ private fun ChannelPanel(
|
||||
// Per-channel waveforms
|
||||
for (chData in lastMultiChannelResult.filter { it.buffer.isNotEmpty() }) {
|
||||
val chAnalysis = when (curMethod) {
|
||||
com.example.medilightv2android.managers.DetectionMethod.METHOD_A -> analyzerAPanel.analyzeChannel(chData.buffer, chData.channel)
|
||||
com.medithings.vesiscan.managers.DetectionMethod.METHOD_A -> analyzerAPanel.analyzeChannel(chData.buffer, chData.channel)
|
||||
else -> analyzer.analyzeChannel(chData.buffer, chData.channel)
|
||||
}
|
||||
|
||||
@@ -2537,8 +2537,8 @@ private fun ChannelPanel(
|
||||
fontSize = 10.sp, fontWeight = FontWeight.SemiBold, color = Color.Cyan
|
||||
)
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
val dps = com.example.medilightv2android.managers.PiezoHW.distancePerSample
|
||||
val offset = com.example.medilightv2android.managers.PiezoHW.delayOffsetMm
|
||||
val dps = com.medithings.vesiscan.managers.PiezoHW.distancePerSample
|
||||
val offset = com.medithings.vesiscan.managers.PiezoHW.delayOffsetMm
|
||||
Text(
|
||||
"(${"%.0f".format(offset + antIdx * dps)}–${"%.0f".format(offset + postIdx * dps)}mm)",
|
||||
fontSize = 9.sp, color = MlSecondaryText
|
||||
@@ -2804,13 +2804,13 @@ private fun BleDebugPanel(bleManager: BleManager) {
|
||||
) {
|
||||
for (entry in entries) {
|
||||
val color = when (entry.level) {
|
||||
com.example.medilightv2android.services.BleDebugLogger.Level.TX -> Color(0xFF64B5F6)
|
||||
com.example.medilightv2android.services.BleDebugLogger.Level.RX -> Color(0xFF81C784)
|
||||
com.example.medilightv2android.services.BleDebugLogger.Level.ERROR -> Color.Red
|
||||
com.example.medilightv2android.services.BleDebugLogger.Level.WARN -> Color(0xFFFFB74D)
|
||||
com.example.medilightv2android.services.BleDebugLogger.Level.RSSI -> Color(0xFFFFD54F)
|
||||
com.example.medilightv2android.services.BleDebugLogger.Level.CONN -> Color(0xFFCE93D8)
|
||||
com.example.medilightv2android.services.BleDebugLogger.Level.INFO -> Color.White
|
||||
com.medithings.vesiscan.services.BleDebugLogger.Level.TX -> Color(0xFF64B5F6)
|
||||
com.medithings.vesiscan.services.BleDebugLogger.Level.RX -> Color(0xFF81C784)
|
||||
com.medithings.vesiscan.services.BleDebugLogger.Level.ERROR -> Color.Red
|
||||
com.medithings.vesiscan.services.BleDebugLogger.Level.WARN -> Color(0xFFFFB74D)
|
||||
com.medithings.vesiscan.services.BleDebugLogger.Level.RSSI -> Color(0xFFFFD54F)
|
||||
com.medithings.vesiscan.services.BleDebugLogger.Level.CONN -> Color(0xFFCE93D8)
|
||||
com.medithings.vesiscan.services.BleDebugLogger.Level.INFO -> Color.White
|
||||
}
|
||||
Text(
|
||||
entry.toLogLine(),
|
||||
+113
-113
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.ui.views.monitoring
|
||||
package com.medithings.vesiscan.ui.views.monitoring
|
||||
|
||||
import android.util.Log
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
@@ -44,17 +44,17 @@ import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.withStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.example.medilightv2android.AppScreen
|
||||
import com.example.medilightv2android.AppState
|
||||
import com.example.medilightv2android.R
|
||||
import com.example.medilightv2android.ble.BleManager
|
||||
import com.example.medilightv2android.ble.PiezoChannelData
|
||||
import com.example.medilightv2android.managers.DetachmentDetection
|
||||
import com.example.medilightv2android.managers.PiezoEchoAnalyzer
|
||||
import com.example.medilightv2android.managers.PiezoHW
|
||||
import com.example.medilightv2android.managers.UrinAI
|
||||
import com.example.medilightv2android.services.MeasurementLogService
|
||||
import com.example.medilightv2android.ui.theme.*
|
||||
import com.medithings.vesiscan.AppScreen
|
||||
import com.medithings.vesiscan.AppState
|
||||
import com.medithings.vesiscan.R
|
||||
import com.medithings.vesiscan.ble.BleManager
|
||||
import com.medithings.vesiscan.ble.PiezoChannelData
|
||||
import com.medithings.vesiscan.managers.DetachmentDetection
|
||||
import com.medithings.vesiscan.managers.PiezoEchoAnalyzer
|
||||
import com.medithings.vesiscan.managers.PiezoHW
|
||||
import com.medithings.vesiscan.managers.UrinAI
|
||||
import com.medithings.vesiscan.services.MeasurementLogService
|
||||
import com.medithings.vesiscan.ui.theme.*
|
||||
|
||||
/**
|
||||
* Sensor Alignment Guide -- shown after BLE connection, before measurement.
|
||||
@@ -80,8 +80,8 @@ fun PlacementGuideView(appState: AppState) {
|
||||
var phaseHoldHint by remember { mutableStateOf("") } // 강제 힌트
|
||||
val channelDetected = remember { mutableStateListOf(false, false, false, false, false, false) }
|
||||
val channelUrineLen = remember { mutableStateListOf(0, 0, 0, 0, 0, 0) }
|
||||
val isSweepMode = com.example.medilightv2android.managers.GreenZoneConstants.placementGuideMode ==
|
||||
com.example.medilightv2android.managers.PlacementGuideMode.SWEEP
|
||||
val isSweepMode = com.medithings.vesiscan.managers.GreenZoneConstants.placementGuideMode ==
|
||||
com.medithings.vesiscan.managers.PlacementGuideMode.SWEEP
|
||||
var directionHint by remember { mutableStateOf(
|
||||
if (isSweepMode) context.getString(R.string.placement_sweep_initial)
|
||||
else context.getString(R.string.placement_initial_hint)
|
||||
@@ -96,16 +96,16 @@ fun PlacementGuideView(appState: AppState) {
|
||||
var greenFailCount by remember { mutableIntStateOf(0) } // GREEN 이탈 디바운스
|
||||
var lastChannelData by remember { mutableStateOf<List<PiezoChannelData>>(emptyList()) }
|
||||
// 최근 IMU 샘플 (15개, ODR 50Hz, ~300ms 분량). 자세 판정/흔들림 감지/임상 로그용.
|
||||
var lastImuSamples by remember { mutableStateOf<List<com.example.medilightv2android.ble.ImuSample>>(emptyList()) }
|
||||
var lastImuSamples by remember { mutableStateOf<List<com.medithings.vesiscan.ble.ImuSample>>(emptyList()) }
|
||||
var lastWallResults by remember { mutableStateOf<List<Pair<Int, Int>?>>(List(6) { null }) }
|
||||
var debounceCount by remember { mutableIntStateOf(0) }
|
||||
var lastGuidePhase by remember { mutableStateOf(PlacementPhase.VERTICAL) }
|
||||
var lastHintChangeMs by remember { mutableStateOf(0L) }
|
||||
// V2 alignment (alignment.py 포팅) — dev 토글로 활성화.
|
||||
val v2Aligner = remember { com.example.medilightv2android.managers.RollingAligner() }
|
||||
val v2Aligner = remember { com.medithings.vesiscan.managers.RollingAligner() }
|
||||
|
||||
// SWEEP 모드용 sphere-fit state
|
||||
val rTracker = remember { com.example.medilightv2android.managers.BladderSeekRTracker() }
|
||||
val rTracker = remember { com.medithings.vesiscan.managers.BladderSeekRTracker() }
|
||||
var currentRMm by remember { mutableStateOf<Double?>(null) }
|
||||
var bestRMm by remember { mutableStateOf(0.0) }
|
||||
var sagittalArgMaxCh by remember { mutableStateOf<Int?>(null) }
|
||||
@@ -127,13 +127,13 @@ fun PlacementGuideView(appState: AppState) {
|
||||
// V2 (4-stage Method D) 는 R&D/clinical alignment session 전용.
|
||||
// 일반 사용자 flow (Home → Start → Personalization → PlacementGuide) 는 V1 사용.
|
||||
LaunchedEffect(Unit) {
|
||||
val sess = com.example.medilightv2android.services.ClinicalSessionStore.currentSession
|
||||
val sess = com.medithings.vesiscan.services.ClinicalSessionStore.currentSession
|
||||
val isClinicalAlign = !appState.placementFromMonitoring &&
|
||||
sess != null &&
|
||||
sess.mode == com.example.medilightv2android.models.SessionMode.ALIGNMENT
|
||||
com.example.medilightv2android.managers.GreenZoneConstants.alignmentAlgo =
|
||||
if (isClinicalAlign) com.example.medilightv2android.managers.AlignmentAlgo.V2
|
||||
else com.example.medilightv2android.managers.AlignmentAlgo.V1
|
||||
sess.mode == com.medithings.vesiscan.models.SessionMode.ALIGNMENT
|
||||
com.medithings.vesiscan.managers.GreenZoneConstants.alignmentAlgo =
|
||||
if (isClinicalAlign) com.medithings.vesiscan.managers.AlignmentAlgo.V2
|
||||
else com.medithings.vesiscan.managers.AlignmentAlgo.V1
|
||||
v2Aligner.reset()
|
||||
// Clinical alignment session 진입 시 — 자동으로 scan 시작 (Step 0 baseline 캡쳐).
|
||||
// waitingForStart 는 true 유지 — 사용자는 여전히 Start 눌러 알고리즘 시작 결정.
|
||||
@@ -256,10 +256,10 @@ fun PlacementGuideView(appState: AppState) {
|
||||
// Clinical alignment session 진입한 경우 — 저장 후 Clinical Home 으로.
|
||||
// (PiezoMonitoring / Personalization 으로 떨어지지 않게)
|
||||
// Back / Skip 도 endMeasurement → measurement.json + labdb 자동 업로드 (Complete 와 동일).
|
||||
val curSess = com.example.medilightv2android.services.ClinicalSessionStore.currentSession
|
||||
if (curSess != null && curSess.mode == com.example.medilightv2android.models.SessionMode.ALIGNMENT) {
|
||||
com.example.medilightv2android.services.ClinicalSessionStore.endMeasurement(context)
|
||||
com.example.medilightv2android.services.ClinicalSessionStore.inClinicalFlow = true
|
||||
val curSess = com.medithings.vesiscan.services.ClinicalSessionStore.currentSession
|
||||
if (curSess != null && curSess.mode == com.medithings.vesiscan.models.SessionMode.ALIGNMENT) {
|
||||
com.medithings.vesiscan.services.ClinicalSessionStore.endMeasurement(context)
|
||||
com.medithings.vesiscan.services.ClinicalSessionStore.inClinicalFlow = true
|
||||
appState.currentScreen = AppScreen.CLINICAL_HOME
|
||||
} else {
|
||||
appState.backFromPlacementGuide()
|
||||
@@ -279,10 +279,10 @@ fun PlacementGuideView(appState: AppState) {
|
||||
// Skip — top bar 우측 (유일한 Skip 진입점)
|
||||
TextButton(onClick = {
|
||||
isContinuousMode = false
|
||||
val curSess = com.example.medilightv2android.services.ClinicalSessionStore.currentSession
|
||||
if (curSess != null && curSess.mode == com.example.medilightv2android.models.SessionMode.ALIGNMENT) {
|
||||
com.example.medilightv2android.services.ClinicalSessionStore.endMeasurement(context)
|
||||
com.example.medilightv2android.services.ClinicalSessionStore.inClinicalFlow = true
|
||||
val curSess = com.medithings.vesiscan.services.ClinicalSessionStore.currentSession
|
||||
if (curSess != null && curSess.mode == com.medithings.vesiscan.models.SessionMode.ALIGNMENT) {
|
||||
com.medithings.vesiscan.services.ClinicalSessionStore.endMeasurement(context)
|
||||
com.medithings.vesiscan.services.ClinicalSessionStore.inClinicalFlow = true
|
||||
appState.currentScreen = AppScreen.CLINICAL_HOME
|
||||
} else {
|
||||
appState.placementComplete()
|
||||
@@ -311,9 +311,9 @@ fun PlacementGuideView(appState: AppState) {
|
||||
}
|
||||
|
||||
// 펌웨어 구버전 경고
|
||||
com.example.medilightv2android.ui.components.FirmwareWarningBanner(bleManager)
|
||||
com.medithings.vesiscan.ui.components.FirmwareWarningBanner(bleManager)
|
||||
// 배터리 잔량 경고 (<15%)
|
||||
com.example.medilightv2android.ui.components.BatteryWarningBanner(bleManager)
|
||||
com.medithings.vesiscan.ui.components.BatteryWarningBanner(bleManager)
|
||||
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
Column(
|
||||
@@ -435,7 +435,7 @@ fun PlacementGuideView(appState: AppState) {
|
||||
) {
|
||||
// 1) 하복부 일러스트 (배경 — 박스 가득)
|
||||
Image(
|
||||
painter = painterResource(id = com.example.medilightv2android.R.drawable.body_silhouette),
|
||||
painter = painterResource(id = com.medithings.vesiscan.R.drawable.body_silhouette),
|
||||
contentDescription = stringResource(R.string.placement_body_desc),
|
||||
modifier = Modifier.matchParentSize(),
|
||||
contentScale = ContentScale.FillBounds
|
||||
@@ -444,14 +444,14 @@ fun PlacementGuideView(appState: AppState) {
|
||||
val sensorBitmap = remember {
|
||||
android.graphics.BitmapFactory.decodeResource(
|
||||
context.resources,
|
||||
com.example.medilightv2android.R.drawable.sensor_device,
|
||||
com.medithings.vesiscan.R.drawable.sensor_device,
|
||||
).asImageBitmap()
|
||||
}
|
||||
// 방향 화살표 PNG (132x112, 우향). 회전 + tint 로 4방향 + 색감 통일.
|
||||
val arrowBitmap = remember {
|
||||
android.graphics.BitmapFactory.decodeResource(
|
||||
context.resources,
|
||||
com.example.medilightv2android.R.drawable.arrow_transparent,
|
||||
com.medithings.vesiscan.R.drawable.arrow_transparent,
|
||||
).asImageBitmap()
|
||||
}
|
||||
Canvas(modifier = Modifier.fillMaxSize()) {
|
||||
@@ -575,17 +575,17 @@ fun PlacementGuideView(appState: AppState) {
|
||||
) {
|
||||
// V2 활성 시 5-stage step indicator, 아니면 V1 의 3-stage.
|
||||
// 2026-07-01: FINAL_CONFIRM phase 추가 (feature/tab-navigation 동기화).
|
||||
val isV2Active = com.example.medilightv2android.managers.GreenZoneConstants.alignmentAlgo ==
|
||||
com.example.medilightv2android.managers.AlignmentAlgo.V2
|
||||
val isV2Active = com.medithings.vesiscan.managers.GreenZoneConstants.alignmentAlgo ==
|
||||
com.medithings.vesiscan.managers.AlignmentAlgo.V2
|
||||
// 2026-07-02: CENTER_OPTIMIZE 추가 (5-stage → 6-stage)
|
||||
val (currentStepIdx, totalSteps) = if (isV2Active) {
|
||||
val idx = when (v2Aligner.phase) {
|
||||
com.example.medilightv2android.managers.AlignGuide4Stage.Phase4.INITIAL_ACCUM -> 0
|
||||
com.example.medilightv2android.managers.AlignGuide4Stage.Phase4.VERTICAL_CLIMB -> 1
|
||||
com.example.medilightv2android.managers.AlignGuide4Stage.Phase4.CH3_STABILIZE -> 2
|
||||
com.example.medilightv2android.managers.AlignGuide4Stage.Phase4.CENTER_OPTIMIZE -> 3
|
||||
com.example.medilightv2android.managers.AlignGuide4Stage.Phase4.LR_BALANCE -> 4
|
||||
com.example.medilightv2android.managers.AlignGuide4Stage.Phase4.FINAL_CONFIRM -> 5
|
||||
com.medithings.vesiscan.managers.AlignGuide4Stage.Phase4.INITIAL_ACCUM -> 0
|
||||
com.medithings.vesiscan.managers.AlignGuide4Stage.Phase4.VERTICAL_CLIMB -> 1
|
||||
com.medithings.vesiscan.managers.AlignGuide4Stage.Phase4.CH3_STABILIZE -> 2
|
||||
com.medithings.vesiscan.managers.AlignGuide4Stage.Phase4.CENTER_OPTIMIZE -> 3
|
||||
com.medithings.vesiscan.managers.AlignGuide4Stage.Phase4.LR_BALANCE -> 4
|
||||
com.medithings.vesiscan.managers.AlignGuide4Stage.Phase4.FINAL_CONFIRM -> 5
|
||||
}
|
||||
idx to 6
|
||||
} else {
|
||||
@@ -634,13 +634,13 @@ fun PlacementGuideView(appState: AppState) {
|
||||
}
|
||||
if (appState.isDevMode && lastImuSamples.isNotEmpty()) {
|
||||
val posture = remember(lastImuSamples) {
|
||||
com.example.medilightv2android.managers.ImuAnalysis.estimatePosture(lastImuSamples)
|
||||
com.medithings.vesiscan.managers.ImuAnalysis.estimatePosture(lastImuSamples)
|
||||
}
|
||||
val shake = remember(lastImuSamples) {
|
||||
com.example.medilightv2android.managers.ImuAnalysis.shakeRmsDps(lastImuSamples)
|
||||
com.medithings.vesiscan.managers.ImuAnalysis.shakeRmsDps(lastImuSamples)
|
||||
}
|
||||
val tilt = remember(lastImuSamples) {
|
||||
com.example.medilightv2android.managers.ImuAnalysis.tiltDegrees(lastImuSamples)
|
||||
com.medithings.vesiscan.managers.ImuAnalysis.tiltDegrees(lastImuSamples)
|
||||
}
|
||||
Text(
|
||||
"IMU: $posture · tilt=${"%.0f".format(tilt)}° · shake=${"%.1f".format(shake)}dps",
|
||||
@@ -720,7 +720,7 @@ fun PlacementGuideView(appState: AppState) {
|
||||
val detected = if (ch < channelDetected.size) channelDetected[ch] else false
|
||||
val wallPair = if (ch < lastWallResults.size) lastWallResults[ch] else null
|
||||
val showWalls = if (wallPair != null) {
|
||||
com.example.medilightv2android.managers.LowEchoResult(
|
||||
com.medithings.vesiscan.managers.LowEchoResult(
|
||||
ant = wallPair.first, post = wallPair.second,
|
||||
lowStart = wallPair.first, lowEnd = wallPair.second,
|
||||
lowMean = 0.0, urineLen = wallPair.second - wallPair.first,
|
||||
@@ -746,8 +746,8 @@ fun PlacementGuideView(appState: AppState) {
|
||||
if (chData != null && chData.buffer.isNotEmpty()) {
|
||||
// V2 활성 시 RollingAligner 의 10-cycle 평균 신호로 표시 →
|
||||
// 알고리즘 입력 신호와 그래프 일치 (실제 측정 시 보는 화면).
|
||||
val isV2 = com.example.medilightv2android.managers.GreenZoneConstants.alignmentAlgo ==
|
||||
com.example.medilightv2android.managers.AlignmentAlgo.V2
|
||||
val isV2 = com.medithings.vesiscan.managers.GreenZoneConstants.alignmentAlgo ==
|
||||
com.medithings.vesiscan.managers.AlignmentAlgo.V2
|
||||
val avgRaw = if (isV2) v2Aligner.lastAvg?.getOrNull(ch) else null
|
||||
PlacementWaveformChart(
|
||||
buffer = chData.buffer,
|
||||
@@ -806,26 +806,26 @@ fun PlacementGuideView(appState: AppState) {
|
||||
|
||||
val MIN_URINE_LEN_PLACEMENT = 12
|
||||
|
||||
val method = com.example.medilightv2android.managers.GreenZoneConstants.detectionMethod
|
||||
val analyzerA = com.example.medilightv2android.managers.PiezoEchoAnalyzerA.shared
|
||||
val method = com.medithings.vesiscan.managers.GreenZoneConstants.detectionMethod
|
||||
val analyzerA = com.medithings.vesiscan.managers.PiezoEchoAnalyzerA.shared
|
||||
|
||||
for (ch in channels) {
|
||||
if (ch.buffer.isNotEmpty() && ch.channel < 6) {
|
||||
when (method) {
|
||||
com.example.medilightv2android.managers.DetectionMethod.METHOD_C -> {
|
||||
val v41 = com.example.medilightv2android.walldetect.V41Detector()
|
||||
com.medithings.vesiscan.managers.DetectionMethod.METHOD_C -> {
|
||||
val v41 = com.medithings.vesiscan.walldetect.V41Detector()
|
||||
val adcSingle = listOf(ch.buffer.map { it.toInt() })
|
||||
val probe = com.example.medilightv2android.walldetect.dto.ProbeProfileDto(
|
||||
name = com.example.medilightv2android.managers.PiezoHW.presetName,
|
||||
val probe = com.medithings.vesiscan.walldetect.dto.ProbeProfileDto(
|
||||
name = com.medithings.vesiscan.managers.PiezoHW.presetName,
|
||||
rMm = 50.2, anteriorAnchorMm = 32.0,
|
||||
fsHz = 537500, cMmPerUs = 1.54,
|
||||
anglesDeg = com.example.medilightv2android.managers.PiezoHW.degreeAll.toList()
|
||||
anglesDeg = com.medithings.vesiscan.managers.PiezoHW.degreeAll.toList()
|
||||
)
|
||||
// V4.1은 6ch 입력 필요 — 현재 채널만 해당 위치에, 나머지 빈 값
|
||||
val adcMatrix = (0 until 6).map { i ->
|
||||
if (i == ch.channel) ch.buffer.map { it.toInt() } else List(100) { 0 }
|
||||
}
|
||||
val input = com.example.medilightv2android.walldetect.dto.SweepInput(
|
||||
val input = com.medithings.vesiscan.walldetect.dto.SweepInput(
|
||||
requestId = "placement", timestampMs = System.currentTimeMillis(),
|
||||
deviceId = "", sweepSeq = 0, probe = probe, adc = adcMatrix
|
||||
)
|
||||
@@ -841,7 +841,7 @@ fun PlacementGuideView(appState: AppState) {
|
||||
}
|
||||
Log.d("PlacementGuide", "CH${ch.channel}[C] ant=${chResult?.antIdx} post=${chResult?.postIdx}")
|
||||
}
|
||||
com.example.medilightv2android.managers.DetectionMethod.METHOD_A -> {
|
||||
com.medithings.vesiscan.managers.DetectionMethod.METHOD_A -> {
|
||||
val analysis = analyzerA.analyzeChannel(ch.buffer, ch.channel)
|
||||
Log.d("PlacementGuide", "CH${ch.channel}[A] valid=${analysis.isValid} urine=${analysis.result?.urineLen ?: 0}")
|
||||
if (analysis.isValid && analysis.result != null && analysis.result.urineLen >= MIN_URINE_LEN_PLACEMENT) {
|
||||
@@ -864,7 +864,7 @@ fun PlacementGuideView(appState: AppState) {
|
||||
}
|
||||
|
||||
// postMaxIdx 필터: 후벽이 이 샘플 이상이면 바닥반사로 판단 → 제거
|
||||
val postMax = com.example.medilightv2android.managers.GreenZoneConstants.postMaxIdx
|
||||
val postMax = com.medithings.vesiscan.managers.GreenZoneConstants.postMaxIdx
|
||||
for (ch in 0..5) {
|
||||
val w = allWalls[ch]
|
||||
if (w != null && w.second > postMax) {
|
||||
@@ -903,8 +903,8 @@ fun PlacementGuideView(appState: AppState) {
|
||||
bleManager.debugLogger.warn("DETACHED mean=${"%.1f".format(detachResult.meanAbs)} std=${"%.1f".format(detachResult.stdVal)}")
|
||||
Log.w("PlacementGuide", "DETACHED mean=${
|
||||
"%.1f".format(detachResult.meanAbs)} std=${"%.1f".format(detachResult.stdVal)}")
|
||||
} else if (com.example.medilightv2android.managers.GreenZoneConstants.alignmentAlgo ==
|
||||
com.example.medilightv2android.managers.AlignmentAlgo.V2) {
|
||||
} else if (com.medithings.vesiscan.managers.GreenZoneConstants.alignmentAlgo ==
|
||||
com.medithings.vesiscan.managers.AlignmentAlgo.V2) {
|
||||
// ═══ V2 alignment (alignment.py 포팅, method_d 기반) ═══
|
||||
// Clinical alignment session + waitingForStart 일 땐 알고리즘 skip —
|
||||
// baseline cycles 만 누적 (Start 누르기 전 자동 phase 진행 차단).
|
||||
@@ -941,20 +941,20 @@ fun PlacementGuideView(appState: AppState) {
|
||||
directionHint = localizedMsg
|
||||
// STOP 액션은 두 경우 — CH3_STABILIZE 의 "위치 유지" (still in progress) vs
|
||||
// LR_BALANCE 의 "정렬 완료" (truly done). 후자만 finalStop 으로 GREEN lock.
|
||||
val finalStop = st.action == com.example.medilightv2android.managers.AlignAction.STOP &&
|
||||
v2Aligner.phase == com.example.medilightv2android.managers.AlignGuide4Stage.Phase4.LR_BALANCE
|
||||
val finalStop = st.action == com.medithings.vesiscan.managers.AlignAction.STOP &&
|
||||
v2Aligner.phase == com.medithings.vesiscan.managers.AlignGuide4Stage.Phase4.LR_BALANCE
|
||||
directionIcon = when (st.action) {
|
||||
com.example.medilightv2android.managers.AlignAction.MOVE_UP -> "arrow.up"
|
||||
com.example.medilightv2android.managers.AlignAction.MOVE_DOWN -> "arrow.down"
|
||||
com.example.medilightv2android.managers.AlignAction.MOVE_LEFT -> "arrow.left"
|
||||
com.example.medilightv2android.managers.AlignAction.MOVE_RIGHT -> "arrow.right"
|
||||
com.example.medilightv2android.managers.AlignAction.PROBE_LR -> "" // ↔ — 한쪽 화살표 안 어울림. msg 의 ↔ 만 표시
|
||||
com.example.medilightv2android.managers.AlignAction.STOP -> if (finalStop) "checkmark.circle" else ""
|
||||
com.medithings.vesiscan.managers.AlignAction.MOVE_UP -> "arrow.up"
|
||||
com.medithings.vesiscan.managers.AlignAction.MOVE_DOWN -> "arrow.down"
|
||||
com.medithings.vesiscan.managers.AlignAction.MOVE_LEFT -> "arrow.left"
|
||||
com.medithings.vesiscan.managers.AlignAction.MOVE_RIGHT -> "arrow.right"
|
||||
com.medithings.vesiscan.managers.AlignAction.PROBE_LR -> "" // ↔ — 한쪽 화살표 안 어울림. msg 의 ↔ 만 표시
|
||||
com.medithings.vesiscan.managers.AlignAction.STOP -> if (finalStop) "checkmark.circle" else ""
|
||||
null -> ""
|
||||
}
|
||||
placementScore = when {
|
||||
finalStop -> 100
|
||||
st.action == com.example.medilightv2android.managers.AlignAction.STOP -> 60 // CH3_STABILIZE 유지 중
|
||||
st.action == com.medithings.vesiscan.managers.AlignAction.STOP -> 60 // CH3_STABILIZE 유지 중
|
||||
else -> 40
|
||||
}
|
||||
if (finalStop) {
|
||||
@@ -970,14 +970,14 @@ fun PlacementGuideView(appState: AppState) {
|
||||
} // end of !waitingForStart V2 algorithm
|
||||
} else {
|
||||
// Sphere-fit 계산 (SWEEP 모드에서 사용, 다른 모드에서는 무시됨)
|
||||
val fitResult = com.example.medilightv2android.managers.BladderSphereSeek
|
||||
val fitResult = com.medithings.vesiscan.managers.BladderSphereSeek
|
||||
.fitSagittalCircle(allWalls, detected)
|
||||
val rStatus = rTracker.submit(fitResult?.radiusMm)
|
||||
currentRMm = rStatus.currentR
|
||||
bestRMm = rStatus.bestR
|
||||
sagittalArgMaxCh = com.example.medilightv2android.managers.BladderSphereSeek
|
||||
sagittalArgMaxCh = com.medithings.vesiscan.managers.BladderSphereSeek
|
||||
.sagittalArgMaxCh(allWalls, detected)
|
||||
val coronalResult = com.example.medilightv2android.managers.BladderSphereSeek
|
||||
val coronalResult = com.medithings.vesiscan.managers.BladderSphereSeek
|
||||
.computeCoronalLateral(allWalls, detected)
|
||||
lateralOffsetMm = coronalResult?.lateralOffsetMm
|
||||
|
||||
@@ -1112,11 +1112,11 @@ fun PlacementGuideView(appState: AppState) {
|
||||
|
||||
// Phase 라벨 — V2 활성이면 V2 4-stage phase, 아니면 V1 placementPhase.
|
||||
// Step 0 (Start 전 baseline) 은 alignment session 에서만 명시.
|
||||
val isV2 = com.example.medilightv2android.managers.GreenZoneConstants.alignmentAlgo ==
|
||||
com.example.medilightv2android.managers.AlignmentAlgo.V2
|
||||
val clinSess = com.example.medilightv2android.services.ClinicalSessionStore.currentSession
|
||||
val isV2 = com.medithings.vesiscan.managers.GreenZoneConstants.alignmentAlgo ==
|
||||
com.medithings.vesiscan.managers.AlignmentAlgo.V2
|
||||
val clinSess = com.medithings.vesiscan.services.ClinicalSessionStore.currentSession
|
||||
val isClinAlign = clinSess != null &&
|
||||
clinSess.mode == com.example.medilightv2android.models.SessionMode.ALIGNMENT
|
||||
clinSess.mode == com.medithings.vesiscan.models.SessionMode.ALIGNMENT
|
||||
val phaseLabel = when {
|
||||
isClinAlign && waitingForStart -> "STEP_0_BASELINE"
|
||||
isV2 -> v2Aligner.phase.name
|
||||
@@ -1136,10 +1136,10 @@ fun PlacementGuideView(appState: AppState) {
|
||||
// 임상 모드에서는 raw ADC도 adc.csv에 자동 저장.
|
||||
if (clinSess != null) {
|
||||
val rawADC = channels.sortedBy { it.channel }.map { it.buffer }
|
||||
com.example.medilightv2android.services.AdcCsvLogger.log(rawADC, null)
|
||||
com.medithings.vesiscan.services.AdcCsvLogger.log(rawADC, null)
|
||||
// Alignment session 진행 중이면 measurement.json 용 frame 누적.
|
||||
if (clinSess.mode == com.example.medilightv2android.models.SessionMode.ALIGNMENT) {
|
||||
com.example.medilightv2android.services.ClinicalSessionStore.addAlignmentFrame(
|
||||
if (clinSess.mode == com.medithings.vesiscan.models.SessionMode.ALIGNMENT) {
|
||||
com.medithings.vesiscan.services.ClinicalSessionStore.addAlignmentFrame(
|
||||
piezo = channels,
|
||||
imu = lastImuSamples,
|
||||
// Step 0 baseline / V2 phase / V1 phase 통일된 라벨 사용
|
||||
@@ -1159,8 +1159,8 @@ fun PlacementGuideView(appState: AppState) {
|
||||
bleManager.imuCollector.onComplete = { imuSamples ->
|
||||
handler.post {
|
||||
lastImuSamples = imuSamples
|
||||
if (com.example.medilightv2android.services.ClinicalSessionStore.currentSession != null) {
|
||||
com.example.medilightv2android.services.ImuCsvLogger.log(imuSamples)
|
||||
if (com.medithings.vesiscan.services.ClinicalSessionStore.currentSession != null) {
|
||||
com.medithings.vesiscan.services.ImuCsvLogger.log(imuSamples)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1241,16 +1241,16 @@ fun PlacementGuideView(appState: AppState) {
|
||||
}
|
||||
|
||||
// Start Scanning / Complete Alignment 버튼 — clinical alignment 모드면 후자
|
||||
val curClinSess = com.example.medilightv2android.services.ClinicalSessionStore.currentSession
|
||||
val curClinSess = com.medithings.vesiscan.services.ClinicalSessionStore.currentSession
|
||||
val isClinicalAlign = curClinSess != null &&
|
||||
curClinSess.mode == com.example.medilightv2android.models.SessionMode.ALIGNMENT
|
||||
curClinSess.mode == com.medithings.vesiscan.models.SessionMode.ALIGNMENT
|
||||
if (!waitingForStart) Button(
|
||||
onClick = {
|
||||
isContinuousMode = false
|
||||
if (isClinicalAlign) {
|
||||
// endMeasurement → measurement.json finalize + labdb 자동 업로드
|
||||
com.example.medilightv2android.services.ClinicalSessionStore.endMeasurement(context)
|
||||
com.example.medilightv2android.services.ClinicalSessionStore.inClinicalFlow = true
|
||||
com.medithings.vesiscan.services.ClinicalSessionStore.endMeasurement(context)
|
||||
com.medithings.vesiscan.services.ClinicalSessionStore.inClinicalFlow = true
|
||||
appState.currentScreen = AppScreen.CLINICAL_HOME
|
||||
} else {
|
||||
appState.placementComplete()
|
||||
@@ -1300,21 +1300,21 @@ fun PlacementGuideView(appState: AppState) {
|
||||
) {
|
||||
Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
// Method A/B/C
|
||||
var selectedMethod by remember { mutableStateOf(com.example.medilightv2android.managers.GreenZoneConstants.detectionMethod) }
|
||||
var selectedMethod by remember { mutableStateOf(com.medithings.vesiscan.managers.GreenZoneConstants.detectionMethod) }
|
||||
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
|
||||
Text("Detection", fontSize = 14.sp, fontWeight = FontWeight.SemiBold)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
val methods = listOf(
|
||||
com.example.medilightv2android.managers.DetectionMethod.METHOD_A to "A",
|
||||
com.example.medilightv2android.managers.DetectionMethod.METHOD_B to "B",
|
||||
com.example.medilightv2android.managers.DetectionMethod.METHOD_C to "C"
|
||||
com.medithings.vesiscan.managers.DetectionMethod.METHOD_A to "A",
|
||||
com.medithings.vesiscan.managers.DetectionMethod.METHOD_B to "B",
|
||||
com.medithings.vesiscan.managers.DetectionMethod.METHOD_C to "C"
|
||||
)
|
||||
val colors = listOf(Color(0xFF9C27B0), MlPrimary, Color(0xFFFF5722))
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) {
|
||||
methods.forEachIndexed { idx, (m, label) ->
|
||||
val sel = selectedMethod == m
|
||||
Button(
|
||||
onClick = { selectedMethod = m; com.example.medilightv2android.managers.GreenZoneConstants.detectionMethod = m },
|
||||
onClick = { selectedMethod = m; com.medithings.vesiscan.managers.GreenZoneConstants.detectionMethod = m },
|
||||
modifier = Modifier.height(32.dp),
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
@@ -1332,14 +1332,14 @@ fun PlacementGuideView(appState: AppState) {
|
||||
HorizontalDivider()
|
||||
|
||||
// Guide mode (Gradient / Boundary / SWEEP)
|
||||
var selectedGuide by remember { mutableStateOf(com.example.medilightv2android.managers.GreenZoneConstants.placementGuideMode) }
|
||||
var selectedGuide by remember { mutableStateOf(com.medithings.vesiscan.managers.GreenZoneConstants.placementGuideMode) }
|
||||
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
|
||||
Text("Guide", fontSize = 14.sp, fontWeight = FontWeight.SemiBold)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
val guideModes = listOf(
|
||||
com.example.medilightv2android.managers.PlacementGuideMode.SIMPLE to "Gradient",
|
||||
com.example.medilightv2android.managers.PlacementGuideMode.BOUNDARY to "Boundary",
|
||||
com.example.medilightv2android.managers.PlacementGuideMode.SWEEP to "SWEEP"
|
||||
com.medithings.vesiscan.managers.PlacementGuideMode.SIMPLE to "Gradient",
|
||||
com.medithings.vesiscan.managers.PlacementGuideMode.BOUNDARY to "Boundary",
|
||||
com.medithings.vesiscan.managers.PlacementGuideMode.SWEEP to "SWEEP"
|
||||
)
|
||||
val guideColors = listOf(MlPrimary, Color(0xFFFF5722), Color(0xFF7C3AED))
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) {
|
||||
@@ -1348,7 +1348,7 @@ fun PlacementGuideView(appState: AppState) {
|
||||
Button(
|
||||
onClick = {
|
||||
selectedGuide = mode
|
||||
com.example.medilightv2android.managers.GreenZoneConstants.placementGuideMode = mode
|
||||
com.medithings.vesiscan.managers.GreenZoneConstants.placementGuideMode = mode
|
||||
},
|
||||
modifier = Modifier.height(32.dp),
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
@@ -1368,14 +1368,14 @@ fun PlacementGuideView(appState: AppState) {
|
||||
|
||||
// Alignment 알고리즘 V1/V2
|
||||
var selectedAlgo by remember {
|
||||
mutableStateOf(com.example.medilightv2android.managers.GreenZoneConstants.alignmentAlgo)
|
||||
mutableStateOf(com.medithings.vesiscan.managers.GreenZoneConstants.alignmentAlgo)
|
||||
}
|
||||
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
|
||||
Text("Alignment", fontSize = 14.sp, fontWeight = FontWeight.SemiBold)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
val algoModes = listOf(
|
||||
com.example.medilightv2android.managers.AlignmentAlgo.V1 to "V1 (legacy)",
|
||||
com.example.medilightv2android.managers.AlignmentAlgo.V2 to "V2 (new)",
|
||||
com.medithings.vesiscan.managers.AlignmentAlgo.V1 to "V1 (legacy)",
|
||||
com.medithings.vesiscan.managers.AlignmentAlgo.V2 to "V2 (new)",
|
||||
)
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) {
|
||||
algoModes.forEach { (algo, label) ->
|
||||
@@ -1383,8 +1383,8 @@ fun PlacementGuideView(appState: AppState) {
|
||||
Button(
|
||||
onClick = {
|
||||
selectedAlgo = algo
|
||||
com.example.medilightv2android.managers.GreenZoneConstants.alignmentAlgo = algo
|
||||
if (algo == com.example.medilightv2android.managers.AlignmentAlgo.V2) {
|
||||
com.medithings.vesiscan.managers.GreenZoneConstants.alignmentAlgo = algo
|
||||
if (algo == com.medithings.vesiscan.managers.AlignmentAlgo.V2) {
|
||||
v2Aligner.reset()
|
||||
}
|
||||
},
|
||||
@@ -1410,7 +1410,7 @@ fun PlacementGuideView(appState: AppState) {
|
||||
Text("Threshold", fontSize = 14.sp, fontWeight = FontWeight.SemiBold)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text(
|
||||
if (otsuEnabled) "Otsu: ${"%.0f".format(analyzer.lastOtsuThreshold)}" else "${"%.0f".format(com.example.medilightv2android.managers.GreenZoneConstants.lowEchoAmp)}",
|
||||
if (otsuEnabled) "Otsu: ${"%.0f".format(analyzer.lastOtsuThreshold)}" else "${"%.0f".format(com.medithings.vesiscan.managers.GreenZoneConstants.lowEchoAmp)}",
|
||||
fontSize = 13.sp, fontWeight = FontWeight.Bold,
|
||||
color = if (otsuEnabled) Color(0xFF4CAF50) else Color(0xFFFF9800)
|
||||
)
|
||||
@@ -1426,7 +1426,7 @@ fun PlacementGuideView(appState: AppState) {
|
||||
HorizontalDivider()
|
||||
|
||||
// Post Max Index (바닥반사 무시 경계)
|
||||
var postMaxVal by remember { mutableStateOf(com.example.medilightv2android.managers.GreenZoneConstants.postMaxIdx.toFloat()) }
|
||||
var postMaxVal by remember { mutableStateOf(com.medithings.vesiscan.managers.GreenZoneConstants.postMaxIdx.toFloat()) }
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text("Post Max", fontSize = 14.sp, fontWeight = FontWeight.SemiBold)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
@@ -1434,7 +1434,7 @@ fun PlacementGuideView(appState: AppState) {
|
||||
}
|
||||
Slider(
|
||||
value = postMaxVal,
|
||||
onValueChange = { postMaxVal = it; com.example.medilightv2android.managers.GreenZoneConstants.postMaxIdx = it.toInt() },
|
||||
onValueChange = { postMaxVal = it; com.medithings.vesiscan.managers.GreenZoneConstants.postMaxIdx = it.toInt() },
|
||||
valueRange = 50f..95f,
|
||||
steps = 8,
|
||||
colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary)
|
||||
@@ -1651,10 +1651,10 @@ data class PlacementGuideResult(
|
||||
|
||||
// CV threshold는 기기 preset에 따라 다름
|
||||
private val DEFAULT_CV_THR: Double
|
||||
get() = when (com.example.medilightv2android.managers.PiezoHW.activePreset) {
|
||||
com.example.medilightv2android.managers.PiezoHW.DevicePreset.V0 -> 0.07
|
||||
com.example.medilightv2android.managers.PiezoHW.DevicePreset.V1,
|
||||
com.example.medilightv2android.managers.PiezoHW.DevicePreset.V2 -> 0.10
|
||||
get() = when (com.medithings.vesiscan.managers.PiezoHW.activePreset) {
|
||||
com.medithings.vesiscan.managers.PiezoHW.DevicePreset.V0 -> 0.07
|
||||
com.medithings.vesiscan.managers.PiezoHW.DevicePreset.V1,
|
||||
com.medithings.vesiscan.managers.PiezoHW.DevicePreset.V2 -> 0.10
|
||||
else -> 0.08
|
||||
}
|
||||
private const val DEFAULT_LR_DEV_THR = 0.20
|
||||
@@ -1727,10 +1727,10 @@ private fun computePlacementGuide(
|
||||
|
||||
// ═══ 1단계: 상하 탐색 ═══
|
||||
if (currentPhase == PlacementPhase.VERTICAL) {
|
||||
val guideMode = com.example.medilightv2android.managers.GreenZoneConstants.placementGuideMode
|
||||
val guideMode = com.medithings.vesiscan.managers.GreenZoneConstants.placementGuideMode
|
||||
|
||||
// ═══ SWEEP 모드 (CKLaw): top-down sweep → Ch3 dropout → pull-back ═══
|
||||
if (guideMode == com.example.medilightv2android.managers.PlacementGuideMode.SWEEP) {
|
||||
if (guideMode == com.medithings.vesiscan.managers.PlacementGuideMode.SWEEP) {
|
||||
val vs = verticalState ?: VerticalState()
|
||||
val prev = vs.lastDetectedCount
|
||||
vs.lastDetectedCount = centerDetected
|
||||
@@ -2054,8 +2054,8 @@ private fun computePlacementGuide(
|
||||
}
|
||||
|
||||
// R-peak gate (SWEEP 모드에서만 적용)
|
||||
val isSweep = com.example.medilightv2android.managers.GreenZoneConstants.placementGuideMode ==
|
||||
com.example.medilightv2android.managers.PlacementGuideMode.SWEEP
|
||||
val isSweep = com.medithings.vesiscan.managers.GreenZoneConstants.placementGuideMode ==
|
||||
com.medithings.vesiscan.managers.PlacementGuideMode.SWEEP
|
||||
val rPeakOk = !isSweep || currentRMm == null || bestRMm <= 0.0 ||
|
||||
(bestRMm - currentRMm) <= 1.5
|
||||
val isPass = cv <= cvThr && lrPass && rPeakOk && edgePass
|
||||
@@ -2159,7 +2159,7 @@ private fun PlacementWaveformChart(
|
||||
val denoised = analyzer.denoise(raw)
|
||||
val maxVal = 2500f
|
||||
val thrVal = if (analyzer.useAdaptiveThreshold && analyzer.lastOtsuThreshold > 0)
|
||||
analyzer.lastOtsuThreshold.toFloat() else com.example.medilightv2android.managers.GreenZoneConstants.lowEchoAmp
|
||||
analyzer.lastOtsuThreshold.toFloat() else com.medithings.vesiscan.managers.GreenZoneConstants.lowEchoAmp
|
||||
|
||||
Canvas(modifier = modifier.clip(RoundedCornerShape(4.dp))) {
|
||||
val w = size.width
|
||||
+6
-6
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.ui.views.monitoring
|
||||
package com.medithings.vesiscan.ui.views.monitoring
|
||||
|
||||
import android.Manifest
|
||||
import android.content.pm.PackageManager
|
||||
@@ -35,11 +35,11 @@ import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.example.medilightv2android.R
|
||||
import com.example.medilightv2android.measure.SimpleMeasureService
|
||||
import com.example.medilightv2android.measure.VoidingRecord
|
||||
import com.example.medilightv2android.measure.VoidingRecordStore
|
||||
import com.example.medilightv2android.measure.YoloDetector
|
||||
import com.medithings.vesiscan.R
|
||||
import com.medithings.vesiscan.measure.SimpleMeasureService
|
||||
import com.medithings.vesiscan.measure.VoidingRecord
|
||||
import com.medithings.vesiscan.measure.VoidingRecordStore
|
||||
import com.medithings.vesiscan.measure.YoloDetector
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
+10
-10
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.ui.views.monitoring
|
||||
package com.medithings.vesiscan.ui.views.monitoring
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
@@ -29,14 +29,14 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.example.medilightv2android.AppState
|
||||
import com.example.medilightv2android.R
|
||||
import com.example.medilightv2android.ble.BleManager
|
||||
import com.example.medilightv2android.managers.NirsManager
|
||||
import com.example.medilightv2android.models.NirsMcjPacket
|
||||
import com.example.medilightv2android.models.NirsOxyResult
|
||||
import com.example.medilightv2android.ui.components.BladdyIdleRiveView
|
||||
import com.example.medilightv2android.ui.theme.*
|
||||
import com.medithings.vesiscan.AppState
|
||||
import com.medithings.vesiscan.R
|
||||
import com.medithings.vesiscan.ble.BleManager
|
||||
import com.medithings.vesiscan.managers.NirsManager
|
||||
import com.medithings.vesiscan.models.NirsMcjPacket
|
||||
import com.medithings.vesiscan.models.NirsOxyResult
|
||||
import com.medithings.vesiscan.ui.components.BladdyIdleRiveView
|
||||
import com.medithings.vesiscan.ui.theme.*
|
||||
import kotlin.random.Random
|
||||
|
||||
@Composable
|
||||
@@ -84,7 +84,7 @@ fun VivamyoMonitoringView(appState: AppState) {
|
||||
if (packet != null) {
|
||||
nirsManager.processMcjPacket(packet)
|
||||
} else {
|
||||
if (com.example.medilightv2android.BuildConfig.DEBUG) {
|
||||
if (com.medithings.vesiscan.BuildConfig.DEBUG) {
|
||||
android.util.Log.e("VivamyoMonitor", "NirsMcjPacket.parse returned null! data.size=${data.size}")
|
||||
}
|
||||
}
|
||||
+7
-7
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.ui.views.monitoring
|
||||
package com.medithings.vesiscan.ui.views.monitoring
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
@@ -20,12 +20,12 @@ import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.example.medilightv2android.R
|
||||
import com.example.medilightv2android.measure.VoidingRecord
|
||||
import com.example.medilightv2android.measure.VoidingRecordStore
|
||||
import com.example.medilightv2android.ui.theme.MlCardBackground
|
||||
import com.example.medilightv2android.ui.theme.MlPrimary
|
||||
import com.example.medilightv2android.ui.theme.MlSecondaryText
|
||||
import com.medithings.vesiscan.R
|
||||
import com.medithings.vesiscan.measure.VoidingRecord
|
||||
import com.medithings.vesiscan.measure.VoidingRecordStore
|
||||
import com.medithings.vesiscan.ui.theme.MlCardBackground
|
||||
import com.medithings.vesiscan.ui.theme.MlPrimary
|
||||
import com.medithings.vesiscan.ui.theme.MlSecondaryText
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
+5
-5
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.ui.views.onboarding
|
||||
package com.medithings.vesiscan.ui.views.onboarding
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
@@ -16,10 +16,10 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.example.medilightv2android.AppState
|
||||
import com.example.medilightv2android.R
|
||||
import com.example.medilightv2android.ui.components.BladdyIdleRiveView
|
||||
import com.example.medilightv2android.ui.theme.*
|
||||
import com.medithings.vesiscan.AppState
|
||||
import com.medithings.vesiscan.R
|
||||
import com.medithings.vesiscan.ui.components.BladdyIdleRiveView
|
||||
import com.medithings.vesiscan.ui.theme.*
|
||||
|
||||
@Composable
|
||||
fun OnboardingView(appState: AppState) {
|
||||
+8
-8
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.ui.views.personalization
|
||||
package com.medithings.vesiscan.ui.views.personalization
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
@@ -25,11 +25,11 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.example.medilightv2android.AppState
|
||||
import com.example.medilightv2android.R
|
||||
import com.example.medilightv2android.ble.BleManager
|
||||
import com.example.medilightv2android.ui.components.BladdyIdleRiveView
|
||||
import com.example.medilightv2android.ui.theme.*
|
||||
import com.medithings.vesiscan.AppState
|
||||
import com.medithings.vesiscan.R
|
||||
import com.medithings.vesiscan.ble.BleManager
|
||||
import com.medithings.vesiscan.ui.components.BladdyIdleRiveView
|
||||
import com.medithings.vesiscan.ui.theme.*
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
/**
|
||||
@@ -338,7 +338,7 @@ private fun WakeupAlarmCard() {
|
||||
val context = LocalContext.current
|
||||
var enabled by androidx.compose.runtime.remember {
|
||||
androidx.compose.runtime.mutableStateOf(
|
||||
com.example.medilightv2android.services.WakeupAlarmPrefs.isEnabled(context)
|
||||
com.medithings.vesiscan.services.WakeupAlarmPrefs.isEnabled(context)
|
||||
)
|
||||
}
|
||||
Card(
|
||||
@@ -370,7 +370,7 @@ private fun WakeupAlarmCard() {
|
||||
checked = enabled,
|
||||
onCheckedChange = {
|
||||
enabled = it
|
||||
com.example.medilightv2android.services.WakeupAlarmPrefs.setEnabled(context, it)
|
||||
com.medithings.vesiscan.services.WakeupAlarmPrefs.setEnabled(context, it)
|
||||
},
|
||||
colors = androidx.compose.material3.SwitchDefaults.colors(
|
||||
checkedTrackColor = Color(0xFFD32F2F)
|
||||
+5
-5
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.ui.views.pin
|
||||
package com.medithings.vesiscan.ui.views.pin
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
@@ -12,10 +12,10 @@ import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.example.medilightv2android.AppState
|
||||
import com.example.medilightv2android.services.UserStorage
|
||||
import com.example.medilightv2android.ui.components.BladdyIdleRiveView
|
||||
import com.example.medilightv2android.ui.theme.*
|
||||
import com.medithings.vesiscan.AppState
|
||||
import com.medithings.vesiscan.services.UserStorage
|
||||
import com.medithings.vesiscan.ui.components.BladdyIdleRiveView
|
||||
import com.medithings.vesiscan.ui.theme.*
|
||||
|
||||
enum class PinMode { SETUP, ENTER }
|
||||
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.ui.views.pin
|
||||
package com.medithings.vesiscan.ui.views.pin
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
@@ -20,8 +20,8 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.example.medilightv2android.R
|
||||
import com.example.medilightv2android.ui.theme.MlCardBackground
|
||||
import com.medithings.vesiscan.R
|
||||
import com.medithings.vesiscan.ui.theme.MlCardBackground
|
||||
|
||||
@Composable
|
||||
fun ShuffledKeypad(
|
||||
+6
-6
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.ui.views.registration
|
||||
package com.medithings.vesiscan.ui.views.registration
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
@@ -18,11 +18,11 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.example.medilightv2android.AppState
|
||||
import com.example.medilightv2android.R
|
||||
import com.example.medilightv2android.models.Sex
|
||||
import com.example.medilightv2android.ui.components.BladdyIdleRiveView
|
||||
import com.example.medilightv2android.ui.theme.*
|
||||
import com.medithings.vesiscan.AppState
|
||||
import com.medithings.vesiscan.R
|
||||
import com.medithings.vesiscan.models.Sex
|
||||
import com.medithings.vesiscan.ui.components.BladdyIdleRiveView
|
||||
import com.medithings.vesiscan.ui.theme.*
|
||||
|
||||
@Composable
|
||||
fun RegistrationView(appState: AppState) {
|
||||
+5
-5
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.ui.views.reminder
|
||||
package com.medithings.vesiscan.ui.views.reminder
|
||||
|
||||
import android.content.Intent
|
||||
import android.provider.Settings
|
||||
@@ -20,10 +20,10 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.example.medilightv2android.R
|
||||
import com.example.medilightv2android.services.ReminderService
|
||||
import com.example.medilightv2android.ui.components.LockableSlider
|
||||
import com.example.medilightv2android.ui.theme.*
|
||||
import com.medithings.vesiscan.R
|
||||
import com.medithings.vesiscan.services.ReminderService
|
||||
import com.medithings.vesiscan.ui.components.LockableSlider
|
||||
import com.medithings.vesiscan.ui.theme.*
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
+6
-6
@@ -1,4 +1,4 @@
|
||||
package com.example.medilightv2android.ui.views.sensorselect
|
||||
package com.medithings.vesiscan.ui.views.sensorselect
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
@@ -22,11 +22,11 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.example.medilightv2android.AppState
|
||||
import com.example.medilightv2android.R
|
||||
import com.example.medilightv2android.models.SensorMode
|
||||
import com.example.medilightv2android.ui.components.BladdyIdleRiveView
|
||||
import com.example.medilightv2android.ui.theme.*
|
||||
import com.medithings.vesiscan.AppState
|
||||
import com.medithings.vesiscan.R
|
||||
import com.medithings.vesiscan.models.SensorMode
|
||||
import com.medithings.vesiscan.ui.components.BladdyIdleRiveView
|
||||
import com.medithings.vesiscan.ui.theme.*
|
||||
|
||||
@Composable
|
||||
fun SensorSelectView(appState: AppState) {
|
||||
+2
-2
@@ -15,9 +15,9 @@
|
||||
* own anatomical gate already drops genuinely-bad detections. This layer
|
||||
* just surfaces "this channel's reading just jumped, double-check".
|
||||
*/
|
||||
package com.example.medilightv2android.walldetect
|
||||
package com.medithings.vesiscan.walldetect
|
||||
|
||||
import com.example.medilightv2android.walldetect.dto.ChannelResult
|
||||
import com.medithings.vesiscan.walldetect.dto.ChannelResult
|
||||
import kotlin.math.abs
|
||||
|
||||
class DetectionSanity(
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
* Project: CharlesKWONsLaw — wall-detect live compare
|
||||
* All rights reserved.
|
||||
*/
|
||||
package com.example.medilightv2android.walldetect
|
||||
package com.medithings.vesiscan.walldetect
|
||||
|
||||
object DetectorIds {
|
||||
const val V2 = "v2"
|
||||
+7
-7
@@ -13,14 +13,14 @@
|
||||
* 인터페이스는 WallDetector 와 무관 — alignment.py 가 channels[i].urine_len 만
|
||||
* 필요로 하므로 가벼운 단일-함수 API 로 유지.
|
||||
*/
|
||||
package com.example.medilightv2android.walldetect
|
||||
package com.medithings.vesiscan.walldetect
|
||||
|
||||
import com.example.medilightv2android.walldetect.algo.methodd.MethodDParams
|
||||
import com.example.medilightv2android.walldetect.algo.methodd.MethodDPreprocessing
|
||||
import com.example.medilightv2android.walldetect.algo.methodd.MethodDSpan
|
||||
import com.example.medilightv2android.walldetect.algo.methodd.MethodDWallSelect
|
||||
import com.example.medilightv2android.walldetect.algo.methodd.MethodDWallSelect.CType
|
||||
import com.example.medilightv2android.walldetect.algo.methodd.MethodDWallSelect.Side
|
||||
import com.medithings.vesiscan.walldetect.algo.methodd.MethodDParams
|
||||
import com.medithings.vesiscan.walldetect.algo.methodd.MethodDPreprocessing
|
||||
import com.medithings.vesiscan.walldetect.algo.methodd.MethodDSpan
|
||||
import com.medithings.vesiscan.walldetect.algo.methodd.MethodDWallSelect
|
||||
import com.medithings.vesiscan.walldetect.algo.methodd.MethodDWallSelect.CType
|
||||
import com.medithings.vesiscan.walldetect.algo.methodd.MethodDWallSelect.Side
|
||||
import kotlin.math.max
|
||||
|
||||
data class MethodDResult(
|
||||
+9
-9
@@ -18,16 +18,16 @@
|
||||
* 출력 컨트랙트: alignment.py 가 `dets[i].urine_len` 만 의존 →
|
||||
* MethodDResult.urineLen 또는 null 의 List 로 충분.
|
||||
*/
|
||||
package com.example.medilightv2android.walldetect
|
||||
package com.medithings.vesiscan.walldetect
|
||||
|
||||
import com.example.medilightv2android.managers.AlignmentConstants
|
||||
import com.example.medilightv2android.managers.PiezoHW
|
||||
import com.example.medilightv2android.walldetect.algo.methodd.MethodDParams
|
||||
import com.example.medilightv2android.walldetect.algo.methodd.MethodDPreprocessing
|
||||
import com.example.medilightv2android.walldetect.algo.methodd.MethodDTgc
|
||||
import com.example.medilightv2android.walldetect.algo.methodd.MethodDWallSelect
|
||||
import com.example.medilightv2android.walldetect.algo.methodd.MethodDWallSelect.CType
|
||||
import com.example.medilightv2android.walldetect.algo.methodd.MethodDWallSelect.Side
|
||||
import com.medithings.vesiscan.managers.AlignmentConstants
|
||||
import com.medithings.vesiscan.managers.PiezoHW
|
||||
import com.medithings.vesiscan.walldetect.algo.methodd.MethodDParams
|
||||
import com.medithings.vesiscan.walldetect.algo.methodd.MethodDPreprocessing
|
||||
import com.medithings.vesiscan.walldetect.algo.methodd.MethodDTgc
|
||||
import com.medithings.vesiscan.walldetect.algo.methodd.MethodDWallSelect
|
||||
import com.medithings.vesiscan.walldetect.algo.methodd.MethodDWallSelect.CType
|
||||
import com.medithings.vesiscan.walldetect.algo.methodd.MethodDWallSelect.Side
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.min as kmin
|
||||
+1
-1
@@ -32,7 +32,7 @@
|
||||
* The contract: "I either pass the live sample through unchanged,
|
||||
* or replace it with the temporal median of recent good values."
|
||||
*/
|
||||
package com.example.medilightv2android.walldetect
|
||||
package com.medithings.vesiscan.walldetect
|
||||
|
||||
import kotlin.math.abs
|
||||
|
||||
+8
-8
@@ -15,15 +15,15 @@
|
||||
* 6. post > POST_MAX_IDX → back-half retry
|
||||
* 7. urine_len ≥ 3 required
|
||||
*/
|
||||
package com.example.medilightv2android.walldetect
|
||||
package com.medithings.vesiscan.walldetect
|
||||
|
||||
import com.example.medilightv2android.walldetect.algo.DetectLumenFirst
|
||||
import com.example.medilightv2android.walldetect.algo.Geometry
|
||||
import com.example.medilightv2android.walldetect.algo.SubsampleRefine
|
||||
import com.example.medilightv2android.walldetect.dto.ChannelResult
|
||||
import com.example.medilightv2android.walldetect.dto.DetectionResult
|
||||
import com.example.medilightv2android.walldetect.dto.DetectionSummary
|
||||
import com.example.medilightv2android.walldetect.dto.SweepInput
|
||||
import com.medithings.vesiscan.walldetect.algo.DetectLumenFirst
|
||||
import com.medithings.vesiscan.walldetect.algo.Geometry
|
||||
import com.medithings.vesiscan.walldetect.algo.SubsampleRefine
|
||||
import com.medithings.vesiscan.walldetect.dto.ChannelResult
|
||||
import com.medithings.vesiscan.walldetect.dto.DetectionResult
|
||||
import com.medithings.vesiscan.walldetect.dto.DetectionSummary
|
||||
import com.medithings.vesiscan.walldetect.dto.SweepInput
|
||||
import kotlin.math.sqrt
|
||||
|
||||
class V2Detector : WallDetector {
|
||||
+27
-27
@@ -98,34 +98,34 @@
|
||||
* `docs/BV-CALCULATION-DESIGN.md`.
|
||||
* ═════════════════════════════════════════════════════════════════════════
|
||||
*/
|
||||
package com.example.medilightv2android.walldetect
|
||||
package com.medithings.vesiscan.walldetect
|
||||
|
||||
import com.example.medilightv2android.walldetect.algo.AnatomicalGate
|
||||
import com.example.medilightv2android.walldetect.algo.BModeScore
|
||||
import com.example.medilightv2android.walldetect.algo.BvEstimation
|
||||
import com.example.medilightv2android.walldetect.algo.BvFromSphere
|
||||
import com.example.medilightv2android.walldetect.algo.ChordConsensus
|
||||
import com.example.medilightv2android.walldetect.algo.Clipping
|
||||
import com.example.medilightv2android.walldetect.algo.ContrastAux
|
||||
import com.example.medilightv2android.walldetect.algo.DetectLumenFirst
|
||||
import com.example.medilightv2android.walldetect.algo.Geometry
|
||||
import com.example.medilightv2android.walldetect.algo.ImpulseReject
|
||||
import com.example.medilightv2android.walldetect.algo.PeakDetection
|
||||
import com.example.medilightv2android.walldetect.algo.SphereFit2Step
|
||||
import com.example.medilightv2android.walldetect.algo.SubsampleRefine
|
||||
import com.example.medilightv2android.walldetect.algo.WaveletDenoise
|
||||
import com.example.medilightv2android.walldetect.core.WdConfig
|
||||
import com.example.medilightv2android.walldetect.dto.ChannelResult
|
||||
import com.example.medilightv2android.walldetect.dto.DetectionResult
|
||||
import com.example.medilightv2android.walldetect.dto.DetectionSummary
|
||||
import com.example.medilightv2android.walldetect.dto.IntRange2
|
||||
import com.example.medilightv2android.walldetect.dto.ScoreSubscores
|
||||
import com.example.medilightv2android.walldetect.dto.SweepInput
|
||||
import com.example.medilightv2android.walldetect.dto.V41Diagnostics
|
||||
import com.example.medilightv2android.walldetect.dto.V41SphereFit
|
||||
import com.example.medilightv2android.walldetect.dto.Vec3
|
||||
import com.example.medilightv2android.walldetect.dto.WaveletCoefs
|
||||
import com.example.medilightv2android.walldetect.dto.WaveletEnergyRatio
|
||||
import com.medithings.vesiscan.walldetect.algo.AnatomicalGate
|
||||
import com.medithings.vesiscan.walldetect.algo.BModeScore
|
||||
import com.medithings.vesiscan.walldetect.algo.BvEstimation
|
||||
import com.medithings.vesiscan.walldetect.algo.BvFromSphere
|
||||
import com.medithings.vesiscan.walldetect.algo.ChordConsensus
|
||||
import com.medithings.vesiscan.walldetect.algo.Clipping
|
||||
import com.medithings.vesiscan.walldetect.algo.ContrastAux
|
||||
import com.medithings.vesiscan.walldetect.algo.DetectLumenFirst
|
||||
import com.medithings.vesiscan.walldetect.algo.Geometry
|
||||
import com.medithings.vesiscan.walldetect.algo.ImpulseReject
|
||||
import com.medithings.vesiscan.walldetect.algo.PeakDetection
|
||||
import com.medithings.vesiscan.walldetect.algo.SphereFit2Step
|
||||
import com.medithings.vesiscan.walldetect.algo.SubsampleRefine
|
||||
import com.medithings.vesiscan.walldetect.algo.WaveletDenoise
|
||||
import com.medithings.vesiscan.walldetect.core.WdConfig
|
||||
import com.medithings.vesiscan.walldetect.dto.ChannelResult
|
||||
import com.medithings.vesiscan.walldetect.dto.DetectionResult
|
||||
import com.medithings.vesiscan.walldetect.dto.DetectionSummary
|
||||
import com.medithings.vesiscan.walldetect.dto.IntRange2
|
||||
import com.medithings.vesiscan.walldetect.dto.ScoreSubscores
|
||||
import com.medithings.vesiscan.walldetect.dto.SweepInput
|
||||
import com.medithings.vesiscan.walldetect.dto.V41Diagnostics
|
||||
import com.medithings.vesiscan.walldetect.dto.V41SphereFit
|
||||
import com.medithings.vesiscan.walldetect.dto.Vec3
|
||||
import com.medithings.vesiscan.walldetect.dto.WaveletCoefs
|
||||
import com.medithings.vesiscan.walldetect.dto.WaveletEnergyRatio
|
||||
import kotlin.math.sqrt
|
||||
|
||||
class V41Detector(
|
||||
+3
-3
@@ -23,10 +23,10 @@
|
||||
* • Thread-safe: a single instance can be called from multiple coroutines
|
||||
* • `gainDb`: V2 scales LOW_ECHO_AMP by 10^(-gainDb/20); V4.1 ignores it (Q4)
|
||||
*/
|
||||
package com.example.medilightv2android.walldetect
|
||||
package com.medithings.vesiscan.walldetect
|
||||
|
||||
import com.example.medilightv2android.walldetect.dto.DetectionResult
|
||||
import com.example.medilightv2android.walldetect.dto.SweepInput
|
||||
import com.medithings.vesiscan.walldetect.dto.DetectionResult
|
||||
import com.medithings.vesiscan.walldetect.dto.SweepInput
|
||||
|
||||
interface WallDetector {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user