feat(android): completar alta de Inventario de campo en castellano
This commit is contained in:
@@ -262,7 +262,7 @@ private fun ModernChecklistCard(visit: VisitDetail) {
|
|||||||
val checklist = visit.checklist
|
val checklist = visit.checklist
|
||||||
ElevatedCard(Modifier.fillMaxWidth()) {
|
ElevatedCard(Modifier.fillMaxWidth()) {
|
||||||
Column(Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(6.dp)) {
|
Column(Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(6.dp)) {
|
||||||
Text("Antecedentes", fontWeight = FontWeight.Bold)
|
Text("Antecedentes y controles", fontWeight = FontWeight.Bold)
|
||||||
Text(
|
Text(
|
||||||
"${checklist.antecedents} antecedentes · ${checklist.upcomingControls} próximos controles",
|
"${checklist.antecedents} antecedentes · ${checklist.upcomingControls} próximos controles",
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
@@ -274,7 +274,7 @@ private fun ModernChecklistCard(visit: VisitDetail) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (checklist.stale) {
|
if (checklist.stale) {
|
||||||
Text("El checklist requiere actualización.", color = MaterialTheme.colorScheme.error)
|
Text("La lista de control requiere actualización.", color = MaterialTheme.colorScheme.error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -296,6 +296,8 @@ private fun ModernFieldInventoryScreen(model: MainViewModel, onBack: () -> Unit)
|
|||||||
var parentLabel by rememberSaveable(visit.id) { mutableStateOf("") }
|
var parentLabel by rememberSaveable(visit.id) { mutableStateOf("") }
|
||||||
var name by rememberSaveable(visit.id) { mutableStateOf("") }
|
var name by rememberSaveable(visit.id) { mutableStateOf("") }
|
||||||
var commonName by rememberSaveable(visit.id) { mutableStateOf("") }
|
var commonName by rememberSaveable(visit.id) { mutableStateOf("") }
|
||||||
|
var description by rememberSaveable(visit.id) { mutableStateOf("") }
|
||||||
|
var discoveryNotes by rememberSaveable(visit.id) { mutableStateOf("") }
|
||||||
var selectedTypeId by rememberSaveable(visit.id) { mutableStateOf<String?>(null) }
|
var selectedTypeId by rememberSaveable(visit.id) { mutableStateOf<String?>(null) }
|
||||||
var selectedFamilyId by rememberSaveable(visit.id) { mutableStateOf<String?>(null) }
|
var selectedFamilyId by rememberSaveable(visit.id) { mutableStateOf<String?>(null) }
|
||||||
var familySearch by rememberSaveable(visit.id) { mutableStateOf("") }
|
var familySearch by rememberSaveable(visit.id) { mutableStateOf("") }
|
||||||
@@ -311,6 +313,8 @@ private fun ModernFieldInventoryScreen(model: MainViewModel, onBack: () -> Unit)
|
|||||||
fun resetForm() {
|
fun resetForm() {
|
||||||
name = ""
|
name = ""
|
||||||
commonName = ""
|
commonName = ""
|
||||||
|
description = ""
|
||||||
|
discoveryNotes = ""
|
||||||
selectedTypeId = null
|
selectedTypeId = null
|
||||||
selectedFamilyId = null
|
selectedFamilyId = null
|
||||||
familySearch = ""
|
familySearch = ""
|
||||||
@@ -427,7 +431,7 @@ private fun ModernFieldInventoryScreen(model: MainViewModel, onBack: () -> Unit)
|
|||||||
pendingPhotoGeo = geo
|
pendingPhotoGeo = geo
|
||||||
takePicture.launch(uri)
|
takePicture.launch(uri)
|
||||||
}
|
}
|
||||||
.onFailure { localError = it.message ?: "No se pudo obtener el GPS para la fotografía." }
|
.onFailure { localError = it.message ?: "No se pudo obtener la ubicación para la fotografía." }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -444,13 +448,15 @@ private fun ModernFieldInventoryScreen(model: MainViewModel, onBack: () -> Unit)
|
|||||||
familyId = selectedFamilyId,
|
familyId = selectedFamilyId,
|
||||||
name = name,
|
name = name,
|
||||||
commonName = commonName,
|
commonName = commonName,
|
||||||
|
description = description,
|
||||||
|
discoveryNotes = discoveryNotes,
|
||||||
attributes = buildModernAttributes(type, attributeValues),
|
attributes = buildModernAttributes(type, attributeValues),
|
||||||
latitude = geo.latitude,
|
latitude = geo.latitude,
|
||||||
longitude = geo.longitude,
|
longitude = geo.longitude,
|
||||||
accuracyM = geo.accuracyM,
|
accuracyM = geo.accuracyM,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.onFailure { localError = it.message ?: "No se pudo capturar la ubicación GPS." }
|
.onFailure { localError = it.message ?: "No se pudo capturar la ubicación actual." }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -800,8 +806,8 @@ private fun ModernFieldInventoryScreen(model: MainViewModel, onBack: () -> Unit)
|
|||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = name,
|
value = name,
|
||||||
onValueChange = { name = it },
|
onValueChange = { name = it },
|
||||||
label = { Text("Nombre o código visible *") },
|
label = { Text("Nombre técnico / identificación *") },
|
||||||
supportingText = { Text("Usá lo que figura en placa o identifica el elemento en campo.") },
|
supportingText = { Text("Usá lo que figura en placa o identifica el elemento. El Código DH de campo se genera automáticamente.") },
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
)
|
)
|
||||||
@@ -812,6 +818,21 @@ private fun ModernFieldInventoryScreen(model: MainViewModel, onBack: () -> Unit)
|
|||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
)
|
)
|
||||||
|
OutlinedTextField(
|
||||||
|
value = description,
|
||||||
|
onValueChange = { description = it },
|
||||||
|
label = { Text("Descripción (opcional)") },
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
minLines = 2,
|
||||||
|
)
|
||||||
|
OutlinedTextField(
|
||||||
|
value = discoveryNotes,
|
||||||
|
onValueChange = { discoveryNotes = it },
|
||||||
|
label = { Text("Observaciones del alta (opcional)") },
|
||||||
|
supportingText = { Text("Anotá datos útiles para la revisión posterior en oficina.") },
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
minLines = 2,
|
||||||
|
)
|
||||||
|
|
||||||
selectedType?.attributes?.forEach { definition ->
|
selectedType?.attributes?.forEach { definition ->
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
@@ -830,12 +851,12 @@ private fun ModernFieldInventoryScreen(model: MainViewModel, onBack: () -> Unit)
|
|||||||
}
|
}
|
||||||
|
|
||||||
HorizontalDivider()
|
HorizontalDivider()
|
||||||
ModernStepHeader(if (isSubinstallation) 3 else 2, "GPS + foto")
|
ModernStepHeader(if (isSubinstallation) 3 else 2, "Ubicación y foto")
|
||||||
Surface(Modifier.fillMaxWidth(), shape = MaterialTheme.shapes.medium, color = MaterialTheme.colorScheme.secondaryContainer) {
|
Surface(Modifier.fillMaxWidth(), shape = MaterialTheme.shapes.medium, color = MaterialTheme.colorScheme.secondaryContainer) {
|
||||||
Row(Modifier.padding(14.dp), horizontalArrangement = Arrangement.spacedBy(10.dp), verticalAlignment = Alignment.CenterVertically) {
|
Row(Modifier.padding(14.dp), horizontalArrangement = Arrangement.spacedBy(10.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||||
Icon(Icons.Filled.CameraAlt, null, tint = MaterialTheme.colorScheme.secondary)
|
Icon(Icons.Filled.CameraAlt, null, tint = MaterialTheme.colorScheme.secondary)
|
||||||
Text(
|
Text(
|
||||||
"Al guardar capturamos el GPS y abrimos la cámara. La foto es obligatoria antes de registrar Hallazgos.",
|
"Al guardar capturamos la ubicación y abrimos la cámara. La foto es obligatoria antes de registrar Hallazgos.",
|
||||||
style = MaterialTheme.typography.bodySmall,
|
style = MaterialTheme.typography.bodySmall,
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
)
|
)
|
||||||
@@ -927,7 +948,7 @@ private fun ModernInventoryCard(item: FieldInventoryItem, onInspect: () -> Unit,
|
|||||||
}
|
}
|
||||||
item.commonName?.takeIf { it.isNotBlank() }?.let { Text(it, style = MaterialTheme.typography.bodySmall) }
|
item.commonName?.takeIf { it.isNotBlank() }?.let { Text(it, style = MaterialTheme.typography.bodySmall) }
|
||||||
Text(
|
Text(
|
||||||
if (item.readyForFinding) "Listo para Hallazgos" else "Falta GPS / foto",
|
if (item.readyForFinding) "Listo para Hallazgos" else "Falta ubicación / foto",
|
||||||
color = if (item.readyForFinding) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.error,
|
color = if (item.readyForFinding) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.error,
|
||||||
style = MaterialTheme.typography.bodySmall,
|
style = MaterialTheme.typography.bodySmall,
|
||||||
fontWeight = FontWeight.SemiBold,
|
fontWeight = FontWeight.SemiBold,
|
||||||
@@ -966,7 +987,7 @@ private fun ModernCaptureCard(
|
|||||||
IconButton(onClick = onClose) { Icon(Icons.Filled.Close, "Cerrar") }
|
IconButton(onClick = onClose) { Icon(Icons.Filled.Close, "Cerrar") }
|
||||||
}
|
}
|
||||||
Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) {
|
Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) {
|
||||||
Text(if (gps) "✓ GPS" else "GPS pendiente", color = if (gps) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.error)
|
Text(if (gps) "✓ Ubicación" else "Ubicación pendiente", color = if (gps) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.error)
|
||||||
Text("Fotos · $photos")
|
Text("Fotos · $photos")
|
||||||
}
|
}
|
||||||
if (!ready) {
|
if (!ready) {
|
||||||
@@ -1078,7 +1099,7 @@ private fun modernStatusLabel(status: String): String = when (status) {
|
|||||||
"IN_PROGRESS" -> "En curso"
|
"IN_PROGRESS" -> "En curso"
|
||||||
"CLOSED" -> "Cerrada"
|
"CLOSED" -> "Cerrada"
|
||||||
"CANCELLED" -> "Cancelada"
|
"CANCELLED" -> "Cancelada"
|
||||||
else -> status
|
else -> "Estado no reconocido"
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildModernAttributes(type: FieldType, values: Map<String, String>): Map<String, Any?> =
|
private fun buildModernAttributes(type: FieldType, values: Map<String, String>): Map<String, Any?> =
|
||||||
@@ -1112,7 +1133,7 @@ private suspend fun currentModernGeo(context: Context): ModernGeoSnapshot = susp
|
|||||||
client.getCurrentLocation(Priority.PRIORITY_HIGH_ACCURACY, source.token)
|
client.getCurrentLocation(Priority.PRIORITY_HIGH_ACCURACY, source.token)
|
||||||
.addOnSuccessListener { location ->
|
.addOnSuccessListener { location ->
|
||||||
if (!continuation.isActive) return@addOnSuccessListener
|
if (!continuation.isActive) return@addOnSuccessListener
|
||||||
if (location == null) continuation.resumeWithException(IllegalStateException("No se pudo obtener una ubicación GPS actual."))
|
if (location == null) continuation.resumeWithException(IllegalStateException("No se pudo obtener una ubicación actual."))
|
||||||
else continuation.resume(ModernGeoSnapshot(location.latitude, location.longitude, location.accuracy.toDouble()))
|
else continuation.resume(ModernGeoSnapshot(location.latitude, location.longitude, location.accuracy.toDouble()))
|
||||||
}
|
}
|
||||||
.addOnFailureListener { if (continuation.isActive) continuation.resumeWithException(it) }
|
.addOnFailureListener { if (continuation.isActive) continuation.resumeWithException(it) }
|
||||||
|
|||||||
Reference in New Issue
Block a user