From 199129847e19f359387e968723d9c5ab80af0ddd Mon Sep 17 00:00:00 2001 From: enlineawork Date: Sun, 6 Sep 2026 16:38:52 -0300 Subject: [PATCH] android: agregar estado y operaciones de campo --- .../korexlabs/dhinspeccion/MainViewModel.kt | 209 ++++++++++++++++++ 1 file changed, 209 insertions(+) create mode 100644 android-app/app/src/main/java/com/korexlabs/dhinspeccion/MainViewModel.kt diff --git a/android-app/app/src/main/java/com/korexlabs/dhinspeccion/MainViewModel.kt b/android-app/app/src/main/java/com/korexlabs/dhinspeccion/MainViewModel.kt new file mode 100644 index 0000000..b65f958 --- /dev/null +++ b/android-app/app/src/main/java/com/korexlabs/dhinspeccion/MainViewModel.kt @@ -0,0 +1,209 @@ +package com.korexlabs.dhinspeccion + +import android.app.Application +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.viewModelScope +import com.korexlabs.dhinspeccion.data.CreateFieldInventoryRequest +import com.korexlabs.dhinspeccion.data.DhRepository +import com.korexlabs.dhinspeccion.data.FieldAssetDetail +import com.korexlabs.dhinspeccion.data.FieldInventoryItem +import com.korexlabs.dhinspeccion.data.FieldType +import com.korexlabs.dhinspeccion.data.StoredSession +import com.korexlabs.dhinspeccion.data.VisitDetail +import com.korexlabs.dhinspeccion.data.VisitSummary +import kotlinx.coroutines.launch +import java.io.File +import java.time.Instant + +class MainViewModel(application: Application) : AndroidViewModel(application) { + private val repository = DhRepository(application) + + var session: StoredSession? by mutableStateOf(repository.currentSession()) + private set + var busy by mutableStateOf(false) + private set + var error: String? by mutableStateOf(null) + private set + var notice: String? by mutableStateOf(null) + private set + + var visits: List by mutableStateOf(emptyList()) + private set + var visit: VisitDetail? by mutableStateOf(null) + private set + + var inventory: List by mutableStateOf(emptyList()) + private set + var fieldTypes: List by mutableStateOf(emptyList()) + private set + var selectedFieldAsset: FieldAssetDetail? by mutableStateOf(null) + private set + + init { + if (session != null) loadVisits() + } + + fun clearMessages() { + error = null + notice = null + } + + fun login(identifier: String, password: String) { + if (identifier.isBlank() || password.isBlank()) { + error = "Ingresá usuario y contraseña." + return + } + launchBusy { + session = repository.login(identifier, password) + notice = "Sesión iniciada." + loadVisitsInternal() + } + } + + fun logout() { + viewModelScope.launch { + runCatching { repository.logout() } + session = null + visits = emptyList() + visit = null + inventory = emptyList() + fieldTypes = emptyList() + selectedFieldAsset = null + } + } + + fun loadVisits() = launchBusy { loadVisitsInternal() } + + private suspend fun loadVisitsInternal() { + visits = repository.visits().data + } + + fun openVisit(id: String) = launchBusy { + visit = repository.visit(id) + inventory = emptyList() + fieldTypes = emptyList() + selectedFieldAsset = null + } + + fun closeVisitView() { + visit = null + inventory = emptyList() + fieldTypes = emptyList() + selectedFieldAsset = null + loadVisits() + } + + fun startVisit() { + val id = visit?.id ?: return + launchBusy { + visit = repository.startVisit(id) + notice = "Inspección iniciada." + loadVisitsInternal() + } + } + + fun searchInventory(search: String, parentId: String? = null) { + val id = visit?.id ?: return + launchBusy { + inventory = repository.fieldInventory(id, search, parentId).data + } + } + + fun loadFieldTypes(parentId: String? = null) { + val id = visit?.id ?: return + launchBusy { + fieldTypes = repository.fieldTypes(id, parentId).data + } + } + + fun selectExisting(item: FieldInventoryItem) { + val visitId = visit?.id ?: return + launchBusy { + selectedFieldAsset = repository.selectFieldAsset(visitId, item.id) + notice = "Inventario agregado a la inspección." + inventory = repository.fieldInventory(visitId, null, null).data + } + } + + fun createFieldAsset( + type: FieldType, + parentId: String?, + name: String, + commonName: String?, + attributes: Map, + latitude: Double, + longitude: Double, + accuracyM: Double?, + ) { + val visitId = visit?.id ?: return + if (visit?.status != "IN_PROGRESS") { + error = "La inspección debe estar en curso para dar de alta Inventario." + return + } + launchBusy { + val request = CreateFieldInventoryRequest( + typeId = type.id, + parentId = parentId, + name = name.trim(), + commonName = commonName?.trim()?.takeIf { it.isNotBlank() }, + attributes = attributes, + deviceLatitude = latitude, + deviceLongitude = longitude, + deviceAccuracyM = accuracyM, + deviceCapturedAt = Instant.now().toString(), + ) + selectedFieldAsset = repository.createFieldAsset(visitId, request) + notice = "Inventario creado con GPS. Falta la fotografía obligatoria." + inventory = repository.fieldInventory(visitId, null, null).data + } + } + + fun uploadFieldPhoto( + file: File, + latitude: Double, + longitude: Double, + accuracyM: Double?, + ) { + val visitId = visit?.id ?: return + val asset = selectedFieldAsset?.asset ?: return + launchBusy { + val response = repository.uploadFieldPhoto( + visitId = visitId, + assetId = asset.id, + file = file, + latitude = latitude, + longitude = longitude, + accuracyM = accuracyM, + ) + selectedFieldAsset = selectedFieldAsset?.copy(capture = response.capture) + notice = if (response.capture.readyForFinding) { + "Captura completa: GPS y fotografía registrados." + } else { + "Fotografía registrada." + } + inventory = repository.fieldInventory(visitId, null, null).data + } + } + + fun clearSelectedFieldAsset() { + selectedFieldAsset = null + } + + private fun launchBusy(block: suspend () -> Unit) { + viewModelScope.launch { + busy = true + error = null + try { + block() + } catch (throwable: Throwable) { + error = DhRepository.humanError(throwable) + if (repository.currentSession() == null) session = null + } finally { + busy = false + } + } + } +}