android: agregar estado y operaciones de campo

This commit is contained in:
2026-09-06 16:38:52 -03:00
parent 216a813f50
commit 199129847e
@@ -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<VisitSummary> by mutableStateOf(emptyList())
private set
var visit: VisitDetail? by mutableStateOf(null)
private set
var inventory: List<FieldInventoryItem> by mutableStateOf(emptyList())
private set
var fieldTypes: List<FieldType> 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<String, Any?>,
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
}
}
}
}