Files
VesiscanClinicalAndroid/app/src/main/java/com/example/medilightv2android/MainActivity.kt
T
dw.jang 82ba3bbcf6 UI 묶음 E: Auto Scan Interval 통합 + 0.5단위/sec·min 토글 우측 (회의 #8 #9 #10)
회의 #8 페이지 통합
  - 별도 화면(AUTO_SCAN_SETUP) 폐기 — Personalization 한 화면에 3카드:
    1) Max Capacity, 2) Catheter Threshold, 3) Auto Scan Interval
  - 캐릭터 작게 (220→120dp) + 카드 영역 verticalScroll
  - 'Scan Interval' → 'Auto Scan Interval' 이름 복귀
  - 한글 설명 제거
  - 흐름: PiezoPersonalization → PlacementGuide (AUTO_SCAN_SETUP 단계 없음)

회의 #9 새 형식 — 모든 위치에서 통일
  - 범위 0.5 ~ 10 (sec/min 모드 동일)
  - 0.5 단위 (이전 200ms/30s 단위)
  - sec/min 토글 숫자 우측에 위치
  - SEC 모드: ms = value × 1000 (예: 1.5sec = 1500ms)
  - MIN 모드: ms = value × 60000 (예: 1.5min = 90000ms)
  - 모드 전환 시 같은 숫자 값 유지 (1.5sec ↔ 1.5min)

회의 #10 in-monitoring settings 동일 적용
  PiezoMonitoringView 설정 페이지의 Auto Scan Interval 슬라이더도 새 형식으로 갱신.
  같은 로직 (unitMode + valueClamped + sec/min 토글 + 0.5 step).

정리:
  - AppState.AUTO_SCAN_SETUP enum value 제거
  - autoScanSetupComplete() 함수 제거 (호출처 없음)
  - backFromPlacementGuide() → PIEZO_PERSONALIZATION으로 (AUTO_SCAN_SETUP 단계 폐기)
  - MainActivity 라우팅/Back handler에서 AUTO_SCAN_SETUP 분기 제거
  - AutoScanIntervalSetupView.kt 파일 삭제

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-09 17:09:24 +09:00

176 lines
9.0 KiB
Kotlin

package com.example.medilightv2android
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.BackHandler
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.animation.Crossfade
import androidx.compose.animation.core.tween
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import app.rive.runtime.kotlin.core.Rive
import com.example.medilightv2android.services.KeychainService
import com.example.medilightv2android.services.NotificationService
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
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Initialize services
Rive.init(this)
KeychainService.init(this)
NotificationService.getInstance(this)
enableEdgeToEdge()
window.addFlags(android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
setContent {
Medilightv2androidTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
MedilightApp(modifier = Modifier.padding(innerPadding))
}
}
}
}
}
@Composable
fun MedilightApp(modifier: Modifier = Modifier) {
val context = LocalContext.current
val appState = remember { AppState(context) }
// HOME에서 뒤로가기 → 앱 종료 확인
var showExitDialog by remember { mutableStateOf(false) }
BackHandler(enabled = appState.currentScreen == AppScreen.HOME) {
showExitDialog = true
}
if (showExitDialog) {
androidx.compose.material3.AlertDialog(
onDismissRequest = { showExitDialog = false },
title = { androidx.compose.material3.Text("Exit App") },
text = { androidx.compose.material3.Text("Are you sure you want to exit?") },
confirmButton = {
androidx.compose.material3.TextButton(onClick = { (context as? android.app.Activity)?.finish() }) {
androidx.compose.material3.Text("Exit", color = Color.Red)
}
},
dismissButton = {
androidx.compose.material3.TextButton(onClick = { showExitDialog = false }) {
androidx.compose.material3.Text("Cancel")
}
}
)
}
// 다른 화면에서 뒤로가기 = 바로 전 화면
BackHandler(enabled = appState.currentScreen != AppScreen.HOME
&& appState.currentScreen != AppScreen.PIN_ENTRY) {
when (appState.currentScreen) {
// 메인 플로우: Home → DeviceScan → Personalization → Placement → Monitoring
// DeviceScan Back: 임상 흐름이면 ClinicalHome으로, 아니면 HOME
AppScreen.DEVICE_SCAN ->
appState.currentScreen =
if (com.example.medilightv2android.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)
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)
appState.currentScreen = AppScreen.CLINICAL_HOME
} else appState.currentScreen = AppScreen.PLACEMENT_GUIDE
AppScreen.CLINICAL_HOME -> {
com.example.medilightv2android.services.ClinicalSessionStore.inClinicalFlow = false
appState.currentScreen = AppScreen.HOME
}
AppScreen.CLINICAL_LIVE -> {
// 측정 폴더 finalize 후 ClinicalHome 복귀
com.example.medilightv2android.services.ClinicalSessionStore.endMeasurement(context)
appState.currentScreen = AppScreen.CLINICAL_HOME
}
// 모니터링 하위 화면 → 모니터링
AppScreen.MEASUREMENT_HISTORY -> appState.currentScreen = AppScreen.PIEZO_MONITORING
AppScreen.VOIDING_DIARY -> appState.currentScreen = AppScreen.PIEZO_MONITORING
AppScreen.REMINDER_SETTINGS -> appState.currentScreen = AppScreen.PIEZO_MONITORING
AppScreen.URINE_CAMERA -> appState.currentScreen = AppScreen.PIEZO_MONITORING
// 기타
AppScreen.SENSOR_SELECT -> appState.currentScreen = AppScreen.HOME
AppScreen.VIVAMYO_MONITORING -> appState.currentScreen = AppScreen.HOME
AppScreen.NIRS_CALIBRATION -> appState.currentScreen = AppScreen.DEVICE_SCAN
// 온보딩/등록 (뒤로가기 막지 않되 Home으로)
else -> appState.currentScreen = AppScreen.HOME
}
}
Crossfade(
targetState = appState.currentScreen,
animationSpec = tween(300),
modifier = modifier,
label = "screen"
) { screen ->
when (screen) {
AppScreen.ONBOARDING -> OnboardingView(appState)
AppScreen.CONSENT -> ConsentView(appState)
AppScreen.REGISTRATION -> RegistrationView(appState)
AppScreen.HOME -> HomeView(appState)
AppScreen.SENSOR_SELECT -> SensorSelectView(appState)
AppScreen.DEVICE_SCAN -> DeviceScanView(appState)
AppScreen.NIRS_CALIBRATION -> CalibrationView(appState)
AppScreen.PIEZO_PERSONALIZATION -> PiezoPersonalizationView(appState)
AppScreen.PLACEMENT_GUIDE -> PlacementGuideView(appState)
AppScreen.PIN_SETUP -> PinView(appState, PinMode.SETUP, context)
AppScreen.PIN_ENTRY -> PinView(appState, PinMode.ENTER, context)
AppScreen.VIVAMYO_MONITORING -> VivamyoMonitoringView(appState)
AppScreen.PIEZO_MONITORING -> PiezoMonitoringView(appState)
AppScreen.MEASUREMENT_HISTORY -> MeasurementHistoryView(appState)
AppScreen.VOIDING_DIARY -> VoidingDiaryView(onBack = { appState.currentScreen = AppScreen.HOME })
AppScreen.URINE_CAMERA -> UrineCameraScreen(
onDone = { volume ->
if (volume != null && volume > 0) appState.resetLevel()
appState.currentScreen = AppScreen.PIEZO_MONITORING
},
onCancel = { appState.currentScreen = AppScreen.PIEZO_MONITORING }
)
AppScreen.REMINDER_SETTINGS -> ReminderSettingsView(
onBack = { appState.backToMonitoring() }
)
AppScreen.CLINICAL_HOME -> ClinicalHomeView(appState)
AppScreen.CLINICAL_LIVE -> ClinicalLiveView(appState)
}
}
}