Initial commit: VesiscanBasic Android app
Port of MedilightV2 iOS app to Android with Kotlin + Jetpack Compose. Includes BLE connectivity, NIRS/Piezo sensor modes, Rive animations, interactive measurement history charts, and foldable device support. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
package com.example.medilightv2android
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.runtime.getValue
|
||||
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.*
|
||||
|
||||
enum class AppScreen {
|
||||
ONBOARDING, REGISTRATION, HOME, SENSOR_SELECT, DEVICE_SCAN,
|
||||
NIRS_CALIBRATION, PIEZO_PERSONALIZATION, PIN_SETUP, PIN_ENTRY,
|
||||
VIVAMYO_MONITORING, PIEZO_MONITORING, MEASUREMENT_HISTORY
|
||||
}
|
||||
|
||||
class AppState(private val context: Context) {
|
||||
var currentScreen by mutableStateOf(AppScreen.ONBOARDING)
|
||||
var user by mutableStateOf(User())
|
||||
var sensorMode by mutableStateOf(SensorMode.PIEZO)
|
||||
var bladderLevel by mutableStateOf(BladderLevel())
|
||||
var isDeviceConnected by mutableStateOf(false)
|
||||
var piezoSettings by mutableStateOf(PiezoSettings())
|
||||
|
||||
private val storage = UserStorage.getInstance(context)
|
||||
private val historyStore = MeasurementHistoryStore.getInstance(context)
|
||||
private val notificationService = NotificationService.getInstance(context)
|
||||
private val bleManager = BleManager.getInstance(context)
|
||||
|
||||
init {
|
||||
loadState()
|
||||
}
|
||||
|
||||
fun loadState() {
|
||||
user = storage.user
|
||||
sensorMode = storage.sensorMode
|
||||
bladderLevel = bladderLevel.copy(
|
||||
currentLevel = storage.bladderLevel,
|
||||
catheterizationThreshold = storage.catheterizationLevel
|
||||
)
|
||||
piezoSettings = storage.piezoSettings
|
||||
|
||||
currentScreen = when {
|
||||
!storage.hasCompletedOnboarding -> AppScreen.ONBOARDING
|
||||
!storage.isRegistered -> AppScreen.REGISTRATION
|
||||
!storage.hasPin -> AppScreen.PIN_SETUP
|
||||
else -> AppScreen.PIN_ENTRY
|
||||
}
|
||||
}
|
||||
|
||||
fun completeOnboarding() {
|
||||
storage.hasCompletedOnboarding = true
|
||||
currentScreen = AppScreen.REGISTRATION
|
||||
}
|
||||
|
||||
fun completeRegistration() {
|
||||
storage.user = user
|
||||
storage.isRegistered = true
|
||||
currentScreen = AppScreen.PIN_SETUP
|
||||
}
|
||||
|
||||
fun goHome() {
|
||||
NirsManager.instance.stopStreaming()
|
||||
NirsManager.instance.reset()
|
||||
bleManager.disconnect()
|
||||
isDeviceConnected = false
|
||||
currentScreen = AppScreen.HOME
|
||||
}
|
||||
|
||||
fun startFromHome() {
|
||||
currentScreen = AppScreen.SENSOR_SELECT
|
||||
}
|
||||
|
||||
fun selectSensor(mode: SensorMode) {
|
||||
sensorMode = mode
|
||||
storage.sensorMode = mode
|
||||
currentScreen = AppScreen.DEVICE_SCAN
|
||||
}
|
||||
|
||||
fun backToSensorSelect() {
|
||||
currentScreen = AppScreen.SENSOR_SELECT
|
||||
}
|
||||
|
||||
fun deviceConnected() {
|
||||
isDeviceConnected = true
|
||||
currentScreen = if (sensorMode == SensorMode.NIRS) {
|
||||
AppScreen.NIRS_CALIBRATION
|
||||
} else {
|
||||
AppScreen.PIEZO_PERSONALIZATION
|
||||
}
|
||||
}
|
||||
|
||||
fun calibrationComplete() {
|
||||
currentScreen = AppScreen.VIVAMYO_MONITORING
|
||||
}
|
||||
|
||||
fun personalizationComplete() {
|
||||
storage.piezoSettings = piezoSettings
|
||||
currentScreen = AppScreen.PIEZO_MONITORING
|
||||
}
|
||||
|
||||
fun pinSet(pin: String) {
|
||||
storage.pin = pin
|
||||
storage.hasPin = true
|
||||
currentScreen = AppScreen.HOME
|
||||
}
|
||||
|
||||
fun pinVerified() {
|
||||
currentScreen = AppScreen.HOME
|
||||
}
|
||||
|
||||
fun incrementLevel() {
|
||||
val previousUrgency = bladderLevel.urgency
|
||||
val newLevel = bladderLevel.copy()
|
||||
newLevel.increment()
|
||||
bladderLevel = newLevel
|
||||
storage.bladderLevel = bladderLevel.currentLevel
|
||||
|
||||
val record = MeasurementRecord(
|
||||
eventType = MeasurementEventType.MEASUREMENT,
|
||||
level = bladderLevel.currentLevel,
|
||||
estimatedVolume = estimatedVolume,
|
||||
urgencyLevel = bladderLevel.urgency,
|
||||
fillPercentage = fillPercentage
|
||||
)
|
||||
historyStore.addRecord(record)
|
||||
|
||||
val newUrgency = bladderLevel.urgency
|
||||
if (newUrgency != previousUrgency) {
|
||||
notificationService.sendUrgencyNotification(newUrgency, estimatedVolume)
|
||||
}
|
||||
}
|
||||
|
||||
fun resetLevel() {
|
||||
val record = MeasurementRecord(
|
||||
eventType = MeasurementEventType.CATHETERIZATION,
|
||||
level = bladderLevel.currentLevel,
|
||||
estimatedVolume = estimatedVolume,
|
||||
urgencyLevel = bladderLevel.urgency,
|
||||
fillPercentage = fillPercentage
|
||||
)
|
||||
historyStore.addRecord(record)
|
||||
|
||||
val newLevel = bladderLevel.copy()
|
||||
newLevel.reset()
|
||||
bladderLevel = newLevel
|
||||
storage.bladderLevel = 0
|
||||
notificationService.cancelAll()
|
||||
}
|
||||
|
||||
fun showHistory() {
|
||||
currentScreen = AppScreen.MEASUREMENT_HISTORY
|
||||
}
|
||||
|
||||
fun backToMonitoring() {
|
||||
currentScreen = if (sensorMode == SensorMode.NIRS) AppScreen.VIVAMYO_MONITORING else AppScreen.PIEZO_MONITORING
|
||||
}
|
||||
|
||||
fun updateCatheterizationThreshold(threshold: Int) {
|
||||
bladderLevel = bladderLevel.copy(catheterizationThreshold = threshold)
|
||||
storage.catheterizationLevel = threshold
|
||||
}
|
||||
|
||||
val estimatedVolume: Int
|
||||
get() {
|
||||
if (BladderLevel.MAX_LEVEL <= 0) return 0
|
||||
return (bladderLevel.currentLevel.toDouble() / BladderLevel.MAX_LEVEL * piezoSettings.maxVolume).toInt()
|
||||
}
|
||||
|
||||
val fillPercentage: Double
|
||||
get() {
|
||||
if (BladderLevel.MAX_LEVEL <= 0) return 0.0
|
||||
return bladderLevel.currentLevel.toDouble() / BladderLevel.MAX_LEVEL * 100.0
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user