android-finalizer: apply final field flow and Spanish UX
This commit is contained in:
@@ -241,6 +241,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
|||||||
latitude: Double,
|
latitude: Double,
|
||||||
longitude: Double,
|
longitude: Double,
|
||||||
accuracyM: Double?,
|
accuracyM: Double?,
|
||||||
|
description: String? = null,
|
||||||
) {
|
) {
|
||||||
val visitId = visit?.id ?: return
|
val visitId = visit?.id ?: return
|
||||||
if (visit?.status != "IN_PROGRESS") {
|
if (visit?.status != "IN_PROGRESS") {
|
||||||
@@ -258,6 +259,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
|||||||
familyId = familyId,
|
familyId = familyId,
|
||||||
name = name.trim(),
|
name = name.trim(),
|
||||||
commonName = commonName?.trim()?.takeIf { it.isNotBlank() },
|
commonName = commonName?.trim()?.takeIf { it.isNotBlank() },
|
||||||
|
description = description?.trim()?.takeIf { it.isNotBlank() },
|
||||||
attributes = attributes,
|
attributes = attributes,
|
||||||
deviceLatitude = latitude,
|
deviceLatitude = latitude,
|
||||||
deviceLongitude = longitude,
|
deviceLongitude = longitude,
|
||||||
@@ -305,6 +307,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
|||||||
latitude: Double,
|
latitude: Double,
|
||||||
longitude: Double,
|
longitude: Double,
|
||||||
accuracyM: Double?,
|
accuracyM: Double?,
|
||||||
|
description: String? = null,
|
||||||
) {
|
) {
|
||||||
val visitId = visit?.id ?: return
|
val visitId = visit?.id ?: return
|
||||||
val asset = selectedFieldAsset?.asset ?: return
|
val asset = selectedFieldAsset?.asset ?: return
|
||||||
@@ -480,12 +483,12 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
|||||||
launchBusy {
|
launchBusy {
|
||||||
actClosure = actsRepository.lock(actId)
|
actClosure = actsRepository.lock(actId)
|
||||||
refreshSelectedActInternal(actId)
|
refreshSelectedActInternal(actId)
|
||||||
notice = "Acta bloqueada. Su contenido quedó inmutable; ahora deben resolverse las firmas y manifestaciones."
|
notice = "Acta cerrada y pendiente de firma. Su contenido quedó inmutable; las firmas y manifestaciones pueden completarse a continuación."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun reopenSelectedAct() {
|
fun reopenSelectedAct() {
|
||||||
error = "Un Acta bloqueada es inmutable y no puede volver a borrador."
|
error = "Un Acta pendiente de firma es inmutable y no puede volver a edición."
|
||||||
}
|
}
|
||||||
|
|
||||||
fun signSelectedActAsInspector(
|
fun signSelectedActAsInspector(
|
||||||
@@ -493,6 +496,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
|||||||
latitude: Double?,
|
latitude: Double?,
|
||||||
longitude: Double?,
|
longitude: Double?,
|
||||||
accuracyM: Double?,
|
accuracyM: Double?,
|
||||||
|
description: String? = null,
|
||||||
) {
|
) {
|
||||||
val actId = selectedAct?.id ?: return
|
val actId = selectedAct?.id ?: return
|
||||||
launchBusy {
|
launchBusy {
|
||||||
@@ -546,7 +550,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
|||||||
refreshSelectedActInternal(actId)
|
refreshSelectedActInternal(actId)
|
||||||
loadActsInternal(currentVisit.id, selectDraft = false)
|
loadActsInternal(currentVisit.id, selectDraft = false)
|
||||||
clearFindingState()
|
clearFindingState()
|
||||||
notice = "${selectedAct?.code ?: "Acta"} SELLADA e inmutable. Podés crear otra Acta o continuar hacia el cierre de la Inspección."
|
notice = "${selectedAct?.code ?: "Acta"} firmada y cerrada. Podés crear otra Acta o continuar hacia el cierre de la Inspección."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -555,7 +559,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
|||||||
launchBusy {
|
launchBusy {
|
||||||
visit = actsRepository.closeVisit(visitId)
|
visit = actsRepository.closeVisit(visitId)
|
||||||
loadVisitsInternal()
|
loadVisitsInternal()
|
||||||
notice = "Inspección cerrada. Todas sus Actas quedaron SELLADAS y disponibles para el circuito de oficina."
|
notice = "Inspección cerrada. Todas sus Actas quedaron firmadas y disponibles para el circuito de oficina."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ fun FieldFindingScreen(model: MainViewModel) {
|
|||||||
Card(Modifier.fillMaxWidth()) {
|
Card(Modifier.fillMaxWidth()) {
|
||||||
Column(Modifier.padding(10.dp), verticalArrangement = Arrangement.spacedBy(6.dp)) {
|
Column(Modifier.padding(10.dp), verticalArrangement = Arrangement.spacedBy(6.dp)) {
|
||||||
Text("${finding.code} · ${finding.title}", fontWeight = FontWeight.SemiBold)
|
Text("${finding.code} · ${finding.title}", fontWeight = FontWeight.SemiBold)
|
||||||
Text("Gravedad: ${finding.severity ?: "s/d"} · ${finding.status}", style = MaterialTheme.typography.bodySmall)
|
Text("Gravedad: ${finding.severity ?: "s/d"} · ${findingStatusLabelEs(finding.status)}", style = MaterialTheme.typography.bodySmall)
|
||||||
Text(
|
Text(
|
||||||
"Evidencias: ${evidence.size} · Fotos: ${evidence.count { it.kind == "PHOTO" }}",
|
"Evidencias: ${evidence.size} · Fotos: ${evidence.count { it.kind == "PHOTO" }}",
|
||||||
style = MaterialTheme.typography.bodySmall,
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
|||||||
@@ -3,11 +3,13 @@ package com.korexlabs.dhinspeccion.ui
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.biometric.BiometricManager
|
import androidx.biometric.BiometricManager
|
||||||
import androidx.biometric.BiometricPrompt
|
import androidx.biometric.BiometricPrompt
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Visibility
|
import androidx.compose.material.icons.filled.Visibility
|
||||||
@@ -29,7 +31,9 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
|||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||||
import androidx.compose.ui.text.input.VisualTransformation
|
import androidx.compose.ui.text.input.VisualTransformation
|
||||||
@@ -37,6 +41,7 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import com.korexlabs.dhinspeccion.MainViewModel
|
import com.korexlabs.dhinspeccion.MainViewModel
|
||||||
|
import com.korexlabs.dhinspeccion.R
|
||||||
|
|
||||||
private const val BIOMETRIC_PREFS = "dh_v2_biometric"
|
private const val BIOMETRIC_PREFS = "dh_v2_biometric"
|
||||||
private const val BIOMETRIC_ENABLED = "enabled"
|
private const val BIOMETRIC_ENABLED = "enabled"
|
||||||
@@ -105,7 +110,13 @@ private fun EnhancedLoginScreen(model: MainViewModel, onPasswordLogin: () -> Uni
|
|||||||
var passwordVisible by rememberSaveable { mutableStateOf(false) }
|
var passwordVisible by rememberSaveable { mutableStateOf(false) }
|
||||||
|
|
||||||
Box(Modifier.fillMaxSize().padding(24.dp), contentAlignment = Alignment.Center) {
|
Box(Modifier.fillMaxSize().padding(24.dp), contentAlignment = Alignment.Center) {
|
||||||
Column(Modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(14.dp)) {
|
Column(Modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(14.dp), horizontalAlignment = Alignment.CenterHorizontally) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(R.drawable.mendoza_logo),
|
||||||
|
contentDescription = "Gobierno de Mendoza",
|
||||||
|
modifier = Modifier.fillMaxWidth().height(170.dp),
|
||||||
|
contentScale = ContentScale.Fit,
|
||||||
|
)
|
||||||
Text("DH Inspección", style = MaterialTheme.typography.headlineMedium, fontWeight = FontWeight.Bold)
|
Text("DH Inspección", style = MaterialTheme.typography.headlineMedium, fontWeight = FontWeight.Bold)
|
||||||
Text("Aplicación de campo · Dirección de Hidrocarburos")
|
Text("Aplicación de campo · Dirección de Hidrocarburos")
|
||||||
model.error?.let { Text(it, color = MaterialTheme.colorScheme.error) }
|
model.error?.let { Text(it, color = MaterialTheme.colorScheme.error) }
|
||||||
@@ -113,7 +124,7 @@ private fun EnhancedLoginScreen(model: MainViewModel, onPasswordLogin: () -> Uni
|
|||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = identifier,
|
value = identifier,
|
||||||
onValueChange = { identifier = it },
|
onValueChange = { identifier = it },
|
||||||
label = { Text("Usuario o email") },
|
label = { Text("Usuario o correo electrónico") },
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
)
|
)
|
||||||
@@ -198,6 +209,12 @@ private fun BiometricUnlockScreen(
|
|||||||
verticalArrangement = Arrangement.spacedBy(14.dp),
|
verticalArrangement = Arrangement.spacedBy(14.dp),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
) {
|
) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(R.drawable.mendoza_logo),
|
||||||
|
contentDescription = "Gobierno de Mendoza",
|
||||||
|
modifier = Modifier.fillMaxWidth().height(140.dp),
|
||||||
|
contentScale = ContentScale.Fit,
|
||||||
|
)
|
||||||
Text("DH Inspección", style = MaterialTheme.typography.headlineMedium, fontWeight = FontWeight.Bold)
|
Text("DH Inspección", style = MaterialTheme.typography.headlineMedium, fontWeight = FontWeight.Bold)
|
||||||
Text("Ingresá con tu huella")
|
Text("Ingresá con tu huella")
|
||||||
error?.let { Text(it, color = MaterialTheme.colorScheme.error) }
|
error?.let { Text(it, color = MaterialTheme.colorScheme.error) }
|
||||||
|
|||||||
+16
-22
@@ -245,7 +245,7 @@ fun ModernMobileActsScreen(
|
|||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
if (newActUrgency == "URGENT") {
|
if (newActUrgency == "URGENT") {
|
||||||
"El plazo urgente se computará desde el Acta conforme a la política institucional vigente al bloquearla."
|
"El plazo urgente se computará desde el Acta conforme a la política institucional vigente al cerrar su contenido."
|
||||||
} else {
|
} else {
|
||||||
"El plazo no urgente comienza con la oficialización GEDO, no al crear el Acta."
|
"El plazo no urgente comienza con la oficialización GEDO, no al crear el Acta."
|
||||||
},
|
},
|
||||||
@@ -319,12 +319,12 @@ fun ModernMobileActsScreen(
|
|||||||
OutlinedTextField(fullName, { fullName = it }, label = { Text("Nombre y apellido *") }, modifier = Modifier.fillMaxWidth(), singleLine = true)
|
OutlinedTextField(fullName, { fullName = it }, label = { Text("Nombre y apellido *") }, modifier = Modifier.fillMaxWidth(), singleLine = true)
|
||||||
Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(6.dp)) {
|
Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(6.dp)) {
|
||||||
listOf("DNI", "CUIL", "PASSPORT", "OTHER").forEach { kind ->
|
listOf("DNI", "CUIL", "PASSPORT", "OTHER").forEach { kind ->
|
||||||
FilterChip(selected = documentType == kind, onClick = { documentType = kind }, label = { Text(kind) })
|
FilterChip(selected = documentType == kind, onClick = { documentType = kind }, label = { Text(documentTypeLabelEs(kind)) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OutlinedTextField(documentNumber, { documentNumber = it }, label = { Text("Documento *") }, modifier = Modifier.fillMaxWidth(), singleLine = true)
|
OutlinedTextField(documentNumber, { documentNumber = it }, label = { Text("Documento *") }, modifier = Modifier.fillMaxWidth(), singleLine = true)
|
||||||
OutlinedTextField(position, { position = it }, label = { Text("Cargo *") }, modifier = Modifier.fillMaxWidth(), singleLine = true)
|
OutlinedTextField(position, { position = it }, label = { Text("Cargo *") }, modifier = Modifier.fillMaxWidth(), singleLine = true)
|
||||||
OutlinedTextField(email, { email = it }, label = { Text("Email") }, modifier = Modifier.fillMaxWidth(), singleLine = true)
|
OutlinedTextField(email, { email = it }, label = { Text("Correo electrónico") }, modifier = Modifier.fillMaxWidth(), singleLine = true)
|
||||||
OutlinedTextField(phone, { phone = it }, label = { Text("Teléfono") }, modifier = Modifier.fillMaxWidth(), singleLine = true)
|
OutlinedTextField(phone, { phone = it }, label = { Text("Teléfono") }, modifier = Modifier.fillMaxWidth(), singleLine = true)
|
||||||
Button(
|
Button(
|
||||||
onClick = { model.setCompanyResponsiblePresent(fullName, documentType, documentNumber, position, email, phone) },
|
onClick = { model.setCompanyResponsiblePresent(fullName, documentType, documentNumber, position, email, phone) },
|
||||||
@@ -353,17 +353,17 @@ fun ModernMobileActsScreen(
|
|||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
Icon(Icons.Filled.Lock, null, tint = MaterialTheme.colorScheme.error)
|
Icon(Icons.Filled.Lock, null, tint = MaterialTheme.colorScheme.error)
|
||||||
Spacer(Modifier.width(8.dp))
|
Spacer(Modifier.width(8.dp))
|
||||||
Text("Finalizar contenido", style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold)
|
Text("Cerrar Acta", style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold)
|
||||||
}
|
}
|
||||||
Text(
|
Text(
|
||||||
"Al bloquear el Acta, su contenido y sus Hallazgos quedan inmutables.",
|
"Al cerrar el contenido, el Acta queda inmutable y pasa a Pendiente de firma. Podés firmarla ahora o continuar con otra Acta.",
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
)
|
)
|
||||||
Button(
|
Button(
|
||||||
onClick = { model.prepareSelectedAct() },
|
onClick = { model.prepareSelectedAct() },
|
||||||
enabled = !model.busy && closure?.responsible != null,
|
enabled = !model.busy && closure?.responsible != null,
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
) { Text("Finalizar y BLOQUEAR Acta") }
|
) { Text("Cerrar Acta y dejar pendiente de firma") }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -379,10 +379,10 @@ fun ModernMobileActsScreen(
|
|||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
Icon(Icons.Filled.Lock, null, tint = MaterialTheme.colorScheme.secondary)
|
Icon(Icons.Filled.Lock, null, tint = MaterialTheme.colorScheme.secondary)
|
||||||
Spacer(Modifier.width(8.dp))
|
Spacer(Modifier.width(8.dp))
|
||||||
Text("Acta BLOQUEADA", style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold)
|
Text("Acta pendiente de firma", style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold)
|
||||||
}
|
}
|
||||||
Text("El contenido ya es inmutable. Restan firmas y manifestaciones para poder sellarla.")
|
Text("El contenido ya está cerrado e inmutable. Completá la firma del inspector y la manifestación de la empresa cuando corresponda.")
|
||||||
closure?.closure?.preparedSha256?.let { Text("Hash · $it", style = MaterialTheme.typography.bodySmall) }
|
closure?.closure?.preparedSha256?.let { Text("Huella de integridad · $it", style = MaterialTheme.typography.bodySmall) }
|
||||||
|
|
||||||
HorizontalDivider()
|
HorizontalDivider()
|
||||||
Text("Firma del inspector", fontWeight = FontWeight.Bold)
|
Text("Firma del inspector", fontWeight = FontWeight.Bold)
|
||||||
@@ -403,7 +403,7 @@ fun ModernMobileActsScreen(
|
|||||||
val detail = when (companyOutcome.status) {
|
val detail = when (companyOutcome.status) {
|
||||||
"SIGNED" -> if (companyOutcome.companyManifestation == "DISSENT") "Firma en disidencia" else "Firma en conformidad"
|
"SIGNED" -> if (companyOutcome.companyManifestation == "DISSENT") "Firma en disidencia" else "Firma en conformidad"
|
||||||
"REFUSED" -> "Negativa a firmar"
|
"REFUSED" -> "Negativa a firmar"
|
||||||
else -> companyOutcome.status
|
else -> humanBackendLabelEs(companyOutcome.status)
|
||||||
}
|
}
|
||||||
SuccessLine(detail)
|
SuccessLine(detail)
|
||||||
companyOutcome.reason?.let { Text(it, style = MaterialTheme.typography.bodySmall) }
|
companyOutcome.reason?.let { Text(it, style = MaterialTheme.typography.bodySmall) }
|
||||||
@@ -462,7 +462,7 @@ fun ModernMobileActsScreen(
|
|||||||
) {
|
) {
|
||||||
Icon(Icons.Filled.CheckCircle, null)
|
Icon(Icons.Filled.CheckCircle, null)
|
||||||
Spacer(Modifier.width(6.dp))
|
Spacer(Modifier.width(6.dp))
|
||||||
Text("SELLAR Acta definitivamente")
|
Text("Firmar y cerrar Acta")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Text(
|
Text(
|
||||||
@@ -480,8 +480,8 @@ fun ModernMobileActsScreen(
|
|||||||
Row(Modifier.padding(18.dp), horizontalArrangement = Arrangement.spacedBy(10.dp), verticalAlignment = Alignment.Top) {
|
Row(Modifier.padding(18.dp), horizontalArrangement = Arrangement.spacedBy(10.dp), verticalAlignment = Alignment.Top) {
|
||||||
Icon(Icons.Filled.CheckCircle, null, tint = MaterialTheme.colorScheme.primary)
|
Icon(Icons.Filled.CheckCircle, null, tint = MaterialTheme.colorScheme.primary)
|
||||||
Column(Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(5.dp)) {
|
Column(Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(5.dp)) {
|
||||||
Text("Acta SELLADA e inmutable", fontWeight = FontWeight.Bold)
|
Text("Acta firmada y cerrada", fontWeight = FontWeight.Bold)
|
||||||
Text("Desde este sellado se genera el PDF del Acta y el INF Word editable para el Inspector.")
|
Text("Desde este cierre se genera el PDF del Acta y el informe INF editable (DOCX) para el Inspector.")
|
||||||
closure?.closure?.finalSha256?.let { Text("SHA-256 · $it", style = MaterialTheme.typography.bodySmall) }
|
closure?.closure?.finalSha256?.let { Text("SHA-256 · $it", style = MaterialTheme.typography.bodySmall) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -503,10 +503,10 @@ fun ModernMobileActsScreen(
|
|||||||
Column(Modifier.padding(18.dp), verticalArrangement = Arrangement.spacedBy(9.dp)) {
|
Column(Modifier.padding(18.dp), verticalArrangement = Arrangement.spacedBy(9.dp)) {
|
||||||
Text("Finalizar Inspección", style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold)
|
Text("Finalizar Inspección", style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold)
|
||||||
if (pendingActs.isEmpty()) {
|
if (pendingActs.isEmpty()) {
|
||||||
SuccessLine("Todas las Actas están SELLADAS")
|
SuccessLine("Todas las Actas están firmadas y cerradas")
|
||||||
} else {
|
} else {
|
||||||
Text(
|
Text(
|
||||||
"Falta SELLAR: ${pendingActs.joinToString { it.code }}",
|
"Falta firmar y cerrar: ${pendingActs.joinToString { it.code }}",
|
||||||
style = MaterialTheme.typography.bodySmall,
|
style = MaterialTheme.typography.bodySmall,
|
||||||
color = MaterialTheme.colorScheme.error,
|
color = MaterialTheme.colorScheme.error,
|
||||||
)
|
)
|
||||||
@@ -531,13 +531,7 @@ private fun SuccessLine(text: String) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun modernActStatusLabel(status: String): String = when (status) {
|
private fun modernActStatusLabel(status: String): String = actStatusLabelEs(status)
|
||||||
"DRAFT" -> "Borrador"
|
|
||||||
"LOCKED" -> "Bloqueada"
|
|
||||||
"SEALED" -> "Sellada"
|
|
||||||
"CANCELLED" -> "Cancelada"
|
|
||||||
else -> status
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun hasModernActLocation(context: Context): Boolean =
|
private fun hasModernActLocation(context: Context): Boolean =
|
||||||
ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED ||
|
ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED ||
|
||||||
|
|||||||
@@ -296,6 +296,7 @@ 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 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 +312,7 @@ private fun ModernFieldInventoryScreen(model: MainViewModel, onBack: () -> Unit)
|
|||||||
fun resetForm() {
|
fun resetForm() {
|
||||||
name = ""
|
name = ""
|
||||||
commonName = ""
|
commonName = ""
|
||||||
|
description = ""
|
||||||
selectedTypeId = null
|
selectedTypeId = null
|
||||||
selectedFamilyId = null
|
selectedFamilyId = null
|
||||||
familySearch = ""
|
familySearch = ""
|
||||||
@@ -444,6 +446,7 @@ private fun ModernFieldInventoryScreen(model: MainViewModel, onBack: () -> Unit)
|
|||||||
familyId = selectedFamilyId,
|
familyId = selectedFamilyId,
|
||||||
name = name,
|
name = name,
|
||||||
commonName = commonName,
|
commonName = commonName,
|
||||||
|
description = description,
|
||||||
attributes = buildModernAttributes(type, attributeValues),
|
attributes = buildModernAttributes(type, attributeValues),
|
||||||
latitude = geo.latitude,
|
latitude = geo.latitude,
|
||||||
longitude = geo.longitude,
|
longitude = geo.longitude,
|
||||||
@@ -800,18 +803,26 @@ 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 *") },
|
||||||
supportingText = { Text("Usá lo que figura en placa o identifica el elemento en campo.") },
|
supportingText = { Text("Usá la denominación técnica del elemento. El código DH se genera automáticamente.") },
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
)
|
)
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = commonName,
|
value = commonName,
|
||||||
onValueChange = { commonName = it },
|
onValueChange = { commonName = it },
|
||||||
label = { Text("Nombre habitual") },
|
label = { Text("Nombre habitual (opcional)") },
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
)
|
)
|
||||||
|
OutlinedTextField(
|
||||||
|
value = description,
|
||||||
|
onValueChange = { description = it },
|
||||||
|
label = { Text("Descripción (opcional)") },
|
||||||
|
supportingText = { Text("Dato equivalente al alta desde el Dashboard.") },
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
minLines = 2,
|
||||||
|
)
|
||||||
|
|
||||||
selectedType?.attributes?.forEach { definition ->
|
selectedType?.attributes?.forEach { definition ->
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
@@ -1073,13 +1084,7 @@ private fun modernNormalize(value: String): String = value.trim().lowercase()
|
|||||||
.replace('ó', 'o').replace('í', 'i').replace('á', 'a').replace('é', 'e').replace('ú', 'u')
|
.replace('ó', 'o').replace('í', 'i').replace('á', 'a').replace('é', 'e').replace('ú', 'u')
|
||||||
.replace("_", "").replace("-", "").replace(" ", "")
|
.replace("_", "").replace("-", "").replace(" ", "")
|
||||||
|
|
||||||
private fun modernStatusLabel(status: String): String = when (status) {
|
private fun modernStatusLabel(status: String): String = visitStatusLabelEs(status)
|
||||||
"PLANNED" -> "Planificada"
|
|
||||||
"IN_PROGRESS" -> "En curso"
|
|
||||||
"CLOSED" -> "Cerrada"
|
|
||||||
"CANCELLED" -> "Cancelada"
|
|
||||||
else -> status
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun buildModernAttributes(type: FieldType, values: Map<String, String>): Map<String, Any?> =
|
private fun buildModernAttributes(type: FieldType, values: Map<String, String>): Map<String, Any?> =
|
||||||
type.attributes.mapNotNull { definition ->
|
type.attributes.mapNotNull { definition ->
|
||||||
|
|||||||
Reference in New Issue
Block a user