Añadir filtros en listado SAIS y eliminar SAIS Disponibles

This commit is contained in:
2026-08-03 13:31:26 +02:00
parent 18328607d0
commit 7884b7e374
6 changed files with 41 additions and 148 deletions
@@ -36,29 +36,6 @@ class SaiRepository {
}
}
suspend fun getAvailable(): Result<List<Sai>> = withContext(Dispatchers.IO) {
val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error"))
try {
val sql = "SELECT id_sai, ns, modelo, estado FROM SAIs WHERE estado = 'Disponible'"
val statement = connection.prepareStatement(sql)
val resultSet = statement.executeQuery()
val sais = mutableListOf<Sai>()
while (resultSet.next()) {
sais.add(Sai(
id = resultSet.getInt("id_sai"),
ns = resultSet.getString("ns"),
modelo = resultSet.getString("modelo"),
estado = resultSet.getString("estado")
))
}
Result.success(sais)
} catch (e: SQLException) {
Result.failure(e)
} finally {
connection.close()
}
}
suspend fun isNsRegistered(ns: String): Result<Boolean> = withContext(Dispatchers.IO) {
val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error"))
try {
@@ -33,7 +33,6 @@ sealed class Screen(val route: String) {
object EditAssignment : Screen("edit_assignment/{assignmentId}") {
fun createRoute(id: Int) = "edit_assignment/$id"
}
object AvailableSaiList : Screen("available_sai_list")
object QuickInfo : Screen("quick_info")
}
@@ -48,7 +47,6 @@ fun AppNavigation() {
onNavigateToBatteries = { navController.navigate(Screen.BatteryList.route) },
onNavigateToPeople = { navController.navigate(Screen.PersonList.route) },
onNavigateToAssignments = { navController.navigate(Screen.AssignmentList.route) },
onNavigateToAvailableSais = { navController.navigate(Screen.AvailableSaiList.route) },
onNavigateToQuickInfo = { navController.navigate(Screen.QuickInfo.route) }
)
}
@@ -136,9 +134,6 @@ fun AppNavigation() {
val id = backStackEntry.arguments?.getInt("assignmentId") ?: 0
EditAssignmentScreen(assignmentId = id, onNavigateBack = { navController.popBackStack() })
}
composable(Screen.AvailableSaiList.route) {
AvailableSaiListScreen(onNavigateBack = { navController.popBackStack() })
}
composable(Screen.QuickInfo.route) {
QuickInfoScreen(onNavigateBack = { navController.popBackStack() })
}
@@ -1,97 +0,0 @@
package com.example.saipp.ui.management
import android.widget.Toast
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.example.saipp.R
import com.example.saipp.data.SaiRepository
import com.example.saipp.data.model.Sai
import com.example.saipp.ui.SearchBar
import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AvailableSaiListScreen(
onNavigateBack: () -> Unit
) {
val context = LocalContext.current
val scope = rememberCoroutineScope()
val repository = remember { SaiRepository() }
var sais by remember { mutableStateOf<List<Sai>>(emptyList()) }
var isLoading by remember { mutableStateOf(true) }
var searchQuery by remember { mutableStateOf("") }
fun loadSais() {
scope.launch {
isLoading = true
repository.getAvailable()
.onSuccess { sais = it }
.onFailure { Toast.makeText(context, "Error: ${it.message}", Toast.LENGTH_SHORT).show() }
isLoading = false
}
}
LaunchedEffect(Unit) {
loadSais()
}
val filteredSais = remember(sais, searchQuery) {
sais.filter {
it.ns.contains(searchQuery, ignoreCase = true) ||
(it.modelo?.contains(searchQuery, ignoreCase = true) ?: false)
}
}
Scaffold(
topBar = {
TopAppBar(
title = { Text(stringResource(R.string.menu_available_sais)) },
navigationIcon = {
IconButton(onClick = onNavigateBack) {
Icon(Icons.Default.ArrowBack, contentDescription = "Atrás")
}
}
)
}
) { padding ->
Column(modifier = Modifier.fillMaxSize().padding(padding)) {
SearchBar(
query = searchQuery,
onQueryChange = { searchQuery = it },
modifier = Modifier.padding(16.dp)
)
if (isLoading) {
Box(modifier = Modifier.weight(1f).fillMaxWidth(), contentAlignment = Alignment.Center) {
CircularProgressIndicator()
}
} else {
if (filteredSais.isEmpty()) {
Box(modifier = Modifier.weight(1f).fillMaxWidth(), contentAlignment = Alignment.Center) {
Text("No hay SAIs disponibles")
}
} else {
LazyColumn(modifier = Modifier.weight(1f).fillMaxWidth()) {
items(filteredSais) { sai ->
ListItem(
headlineContent = { Text("NS: ${sai.ns}") },
supportingContent = { Text("Modelo: ${sai.modelo ?: "N/A"}") }
)
HorizontalDivider()
}
}
}
}
}
}
}
@@ -23,7 +23,6 @@ fun HomeScreen(
onNavigateToBatteries: () -> Unit,
onNavigateToPeople: () -> Unit,
onNavigateToAssignments: () -> Unit,
onNavigateToAvailableSais: () -> Unit,
onNavigateToQuickInfo: () -> Unit
) {
var connectionStatus by remember { mutableStateOf<Result<Unit>?>(null) }
@@ -125,22 +124,6 @@ fun HomeScreen(
}
Spacer(modifier = Modifier.height(16.dp))
Button(
onClick = onNavigateToAvailableSais,
modifier = Modifier.fillMaxWidth().height(56.dp),
shape = MaterialTheme.shapes.medium,
colors = ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.secondaryContainer,
contentColor = MaterialTheme.colorScheme.onSecondaryContainer
)
) {
Icon(Icons.Default.CheckCircle, contentDescription = null)
Spacer(modifier = Modifier.width(8.dp))
Text(text = stringResource(R.string.menu_available_sais), style = MaterialTheme.typography.titleMedium)
}
Spacer(modifier = Modifier.height(16.dp))
}
}
}
@@ -1,9 +1,11 @@
package com.example.saipp.ui.management
import android.widget.Toast
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.rememberScrollState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.*
import androidx.compose.material3.*
@@ -12,12 +14,14 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.example.saipp.data.SaiRepository
import com.example.saipp.data.model.Sai
import com.example.saipp.ui.SearchBar
import com.example.saipp.ui.ScannerDialog
import com.example.saipp.ui.DeleteConfirmDialog
import com.example.saipp.R
import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterial3Api::class)
@@ -36,6 +40,9 @@ fun SaiListScreen(
var searchQuery by remember { mutableStateOf("") }
var showQuickScanner by remember { mutableStateOf(false) }
var selectedStatusFilter by remember { mutableStateOf("Todos") }
val statusOptions = listOf("Todos", "Disponible", "Asignado", "En reparación", "Baja")
var saiToDelete by remember { mutableStateOf<Sai?>(null) }
fun loadSais() {
@@ -52,10 +59,14 @@ fun SaiListScreen(
loadSais()
}
val filteredSais = remember(sais, searchQuery) {
sais.filter {
it.ns.contains(searchQuery, ignoreCase = true) ||
(it.modelo?.contains(searchQuery, ignoreCase = true) ?: false)
val filteredSais = remember(sais, searchQuery, selectedStatusFilter) {
sais.filter { sai ->
val matchesSearch = sai.ns.contains(searchQuery, ignoreCase = true) ||
(sai.modelo?.contains(searchQuery, ignoreCase = true) ?: false)
val matchesStatus = if (selectedStatusFilter == "Todos") true else sai.estado == selectedStatusFilter
matchesSearch && matchesStatus
}
}
@@ -80,10 +91,34 @@ fun SaiListScreen(
SearchBar(
query = searchQuery,
onQueryChange = { searchQuery = it },
modifier = Modifier.padding(16.dp),
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp),
onScanClick = { showQuickScanner = true }
)
// Status Filter Chips
Row(
modifier = Modifier
.fillMaxWidth()
.horizontalScroll(rememberScrollState())
.padding(horizontal = 16.dp, vertical = 4.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
statusOptions.forEach { status ->
FilterChip(
selected = selectedStatusFilter == status,
onClick = { selectedStatusFilter = status },
label = {
Text(
if (status == "Todos") stringResource(R.string.filter_all) else status
)
},
leadingIcon = if (selectedStatusFilter == status) {
{ Icon(Icons.Default.Check, contentDescription = null, modifier = Modifier.size(16.dp)) }
} else null
)
}
}
if (showQuickScanner) {
ScannerDialog(
onDismiss = { showQuickScanner = false },
+1 -1
View File
@@ -30,6 +30,7 @@
<string name="action_deactivate">Dar de Baja</string>
<string name="action_reactivate">Reactivar</string>
<string name="filter_hide_inactive">Ocultar personal de baja</string>
<string name="filter_all">Todos</string>
<string name="dashboard_title">Estado General</string>
<string name="stats_sais">SAIs</string>
@@ -53,7 +54,6 @@
<string name="menu_batteries">Gestión de Baterías</string>
<string name="menu_people">Gestión de Personas</string>
<string name="menu_assignments">Gestion SAI - Persona</string>
<string name="menu_available_sais">SAIs Disponibles</string>
<string name="label_person">Persona</string>
<string name="label_assigned_date">Fecha Asignación (DD-MM-AAAA)</string>