Aplicacion terminada
This commit is contained in:
@@ -43,17 +43,29 @@ CREATE TABLE SAIs (
|
|||||||
);
|
);
|
||||||
|
|
||||||
-- Table for Batteries
|
-- Table for Batteries
|
||||||
CREATE TABLE baterias (
|
CREATE TABLE Bateria (
|
||||||
id_bateria INT AUTO_INCREMENT PRIMARY KEY,
|
id_bateria INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
modelo VARCHAR(255) NOT NULL,
|
id_sai INT,
|
||||||
estado VARCHAR(255) NOT NULL
|
marca VARCHAR(255),
|
||||||
|
fecha_instalacion DATETIME,
|
||||||
|
FOREIGN KEY (id_sai) REFERENCES SAIs(id_sai)
|
||||||
);
|
);
|
||||||
|
|
||||||
-- Table for People
|
-- Table for People
|
||||||
CREATE TABLE personas (
|
CREATE TABLE Persona (
|
||||||
id_persona INT AUTO_INCREMENT PRIMARY KEY,
|
id_persona INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
nombre VARCHAR(255) NOT NULL,
|
nombre VARCHAR(255) NOT NULL
|
||||||
puesto VARCHAR(255) NOT NULL
|
);
|
||||||
|
|
||||||
|
-- Table for Assignments
|
||||||
|
CREATE TABLE Asignado (
|
||||||
|
id_asignacion INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
id_sai INT,
|
||||||
|
id_persona INT,
|
||||||
|
fecha_asignado DATE,
|
||||||
|
fecha_devolucion DATE,
|
||||||
|
FOREIGN KEY (id_sai) REFERENCES SAIs(id_sai),
|
||||||
|
FOREIGN KEY (id_persona) REFERENCES Persona(id_persona)
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,120 @@
|
|||||||
|
package com.example.saipp.data
|
||||||
|
|
||||||
|
import com.example.saipp.data.model.Assignment
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import java.sql.SQLException
|
||||||
|
import java.sql.Types
|
||||||
|
|
||||||
|
class AssignmentRepository {
|
||||||
|
suspend fun getAll(): Result<List<Assignment>> = withContext(Dispatchers.IO) {
|
||||||
|
val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error"))
|
||||||
|
try {
|
||||||
|
val sql = """
|
||||||
|
SELECT a.id_asignacion, a.id_sai, a.id_persona, a.fecha_asignado, a.fecha_devolucion,
|
||||||
|
s.ns as sai_ns, p.nombre as person_name
|
||||||
|
FROM Asignado a
|
||||||
|
LEFT JOIN SAIs s ON a.id_sai = s.id_sai
|
||||||
|
LEFT JOIN Persona p ON a.id_persona = p.id_persona
|
||||||
|
""".trimIndent()
|
||||||
|
val statement = connection.prepareStatement(sql)
|
||||||
|
val resultSet = statement.executeQuery()
|
||||||
|
val items = mutableListOf<Assignment>()
|
||||||
|
while (resultSet.next()) {
|
||||||
|
items.add(Assignment(
|
||||||
|
id = resultSet.getInt("id_asignacion"),
|
||||||
|
idSai = resultSet.getInt("id_sai"),
|
||||||
|
idPersona = resultSet.getInt("id_persona"),
|
||||||
|
assignedDate = resultSet.getString("fecha_asignado"),
|
||||||
|
returnDate = resultSet.getString("fecha_devolucion"),
|
||||||
|
saiNs = resultSet.getString("sai_ns"),
|
||||||
|
personName = resultSet.getString("person_name")
|
||||||
|
))
|
||||||
|
}
|
||||||
|
Result.success(items)
|
||||||
|
} catch (e: SQLException) {
|
||||||
|
Result.failure(e)
|
||||||
|
} finally {
|
||||||
|
connection.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getById(id: Int): Result<Assignment> = withContext(Dispatchers.IO) {
|
||||||
|
val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error"))
|
||||||
|
try {
|
||||||
|
val sql = "SELECT id_asignacion, id_sai, id_persona, fecha_asignado, fecha_devolucion FROM Asignado WHERE id_asignacion = ?"
|
||||||
|
val statement = connection.prepareStatement(sql)
|
||||||
|
statement.setInt(1, id)
|
||||||
|
val resultSet = statement.executeQuery()
|
||||||
|
if (resultSet.next()) {
|
||||||
|
Result.success(Assignment(
|
||||||
|
id = resultSet.getInt("id_asignacion"),
|
||||||
|
idSai = resultSet.getInt("id_sai"),
|
||||||
|
idPersona = resultSet.getInt("id_persona"),
|
||||||
|
assignedDate = resultSet.getString("fecha_asignado"),
|
||||||
|
returnDate = resultSet.getString("fecha_devolucion")
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Result.failure(Exception("not_found"))
|
||||||
|
}
|
||||||
|
} catch (e: SQLException) {
|
||||||
|
Result.failure(e)
|
||||||
|
} finally {
|
||||||
|
connection.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun insert(item: Assignment): Result<Unit> = withContext(Dispatchers.IO) {
|
||||||
|
val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error"))
|
||||||
|
try {
|
||||||
|
val sql = "INSERT INTO Asignado (id_sai, id_persona, fecha_asignado, fecha_devolucion) VALUES (?, ?, ?, ?)"
|
||||||
|
val statement = connection.prepareStatement(sql)
|
||||||
|
statement.setInt(1, item.idSai)
|
||||||
|
statement.setInt(2, item.idPersona)
|
||||||
|
statement.setString(3, item.assignedDate)
|
||||||
|
statement.setString(4, item.returnDate)
|
||||||
|
|
||||||
|
if (statement.executeUpdate() > 0) Result.success(Unit)
|
||||||
|
else Result.failure(Exception("no_rows_inserted"))
|
||||||
|
} catch (e: SQLException) {
|
||||||
|
Result.failure(e)
|
||||||
|
} finally {
|
||||||
|
connection.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun update(item: Assignment): Result<Unit> = withContext(Dispatchers.IO) {
|
||||||
|
val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error"))
|
||||||
|
try {
|
||||||
|
val sql = "UPDATE Asignado SET id_sai = ?, id_persona = ?, fecha_asignado = ?, fecha_devolucion = ? WHERE id_asignacion = ?"
|
||||||
|
val statement = connection.prepareStatement(sql)
|
||||||
|
statement.setInt(1, item.idSai)
|
||||||
|
statement.setInt(2, item.idPersona)
|
||||||
|
statement.setString(3, item.assignedDate)
|
||||||
|
statement.setString(4, item.returnDate)
|
||||||
|
statement.setInt(5, item.id)
|
||||||
|
|
||||||
|
if (statement.executeUpdate() > 0) Result.success(Unit)
|
||||||
|
else Result.failure(Exception("update_failed"))
|
||||||
|
} catch (e: SQLException) {
|
||||||
|
Result.failure(e)
|
||||||
|
} finally {
|
||||||
|
connection.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun delete(id: Int): Result<Unit> = withContext(Dispatchers.IO) {
|
||||||
|
val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error"))
|
||||||
|
try {
|
||||||
|
val sql = "DELETE FROM Asignado WHERE id_asignacion = ?"
|
||||||
|
val statement = connection.prepareStatement(sql)
|
||||||
|
statement.setInt(1, id)
|
||||||
|
if (statement.executeUpdate() > 0) Result.success(Unit)
|
||||||
|
else Result.failure(Exception("delete_failed"))
|
||||||
|
} catch (e: SQLException) {
|
||||||
|
Result.failure(e)
|
||||||
|
} finally {
|
||||||
|
connection.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,20 +4,22 @@ import com.example.saipp.data.model.Battery
|
|||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.sql.SQLException
|
import java.sql.SQLException
|
||||||
|
import java.sql.Types
|
||||||
|
|
||||||
class BatteryRepository {
|
class BatteryRepository {
|
||||||
suspend fun getAll(): Result<List<Battery>> = withContext(Dispatchers.IO) {
|
suspend fun getAll(): Result<List<Battery>> = withContext(Dispatchers.IO) {
|
||||||
val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error"))
|
val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error"))
|
||||||
try {
|
try {
|
||||||
val sql = "SELECT id_bateria, modelo, estado FROM baterias"
|
val sql = "SELECT id_bateria, id_sai, marca, fecha_instalacion FROM Bateria"
|
||||||
val statement = connection.prepareStatement(sql)
|
val statement = connection.prepareStatement(sql)
|
||||||
val resultSet = statement.executeQuery()
|
val resultSet = statement.executeQuery()
|
||||||
val items = mutableListOf<Battery>()
|
val items = mutableListOf<Battery>()
|
||||||
while (resultSet.next()) {
|
while (resultSet.next()) {
|
||||||
items.add(Battery(
|
items.add(Battery(
|
||||||
id = resultSet.getInt("id_bateria"),
|
id = resultSet.getInt("id_bateria"),
|
||||||
model = resultSet.getString("modelo"),
|
idSai = resultSet.getInt("id_sai").takeIf { !resultSet.wasNull() },
|
||||||
status = resultSet.getString("estado")
|
brand = resultSet.getString("marca"),
|
||||||
|
installDate = resultSet.getString("fecha_instalacion")
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
Result.success(items)
|
Result.success(items)
|
||||||
@@ -31,10 +33,12 @@ class BatteryRepository {
|
|||||||
suspend fun insert(item: Battery): Result<Unit> = withContext(Dispatchers.IO) {
|
suspend fun insert(item: Battery): Result<Unit> = withContext(Dispatchers.IO) {
|
||||||
val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error"))
|
val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error"))
|
||||||
try {
|
try {
|
||||||
val sql = "INSERT INTO baterias (modelo, estado) VALUES (?, ?)"
|
val sql = "INSERT INTO Bateria (id_sai, marca, fecha_instalacion) VALUES (?, ?, ?)"
|
||||||
val statement = connection.prepareStatement(sql)
|
val statement = connection.prepareStatement(sql)
|
||||||
statement.setString(1, item.model)
|
if (item.idSai != null) statement.setInt(1, item.idSai) else statement.setNull(1, Types.INTEGER)
|
||||||
statement.setString(2, item.status)
|
statement.setString(2, item.brand)
|
||||||
|
statement.setString(3, item.installDate)
|
||||||
|
|
||||||
if (statement.executeUpdate() > 0) Result.success(Unit)
|
if (statement.executeUpdate() > 0) Result.success(Unit)
|
||||||
else Result.failure(Exception("no_rows_inserted"))
|
else Result.failure(Exception("no_rows_inserted"))
|
||||||
} catch (e: SQLException) {
|
} catch (e: SQLException) {
|
||||||
@@ -47,11 +51,13 @@ class BatteryRepository {
|
|||||||
suspend fun update(item: Battery): Result<Unit> = withContext(Dispatchers.IO) {
|
suspend fun update(item: Battery): Result<Unit> = withContext(Dispatchers.IO) {
|
||||||
val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error"))
|
val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error"))
|
||||||
try {
|
try {
|
||||||
val sql = "UPDATE baterias SET modelo = ?, estado = ? WHERE id_bateria = ?"
|
val sql = "UPDATE Bateria SET id_sai = ?, marca = ?, fecha_instalacion = ? WHERE id_bateria = ?"
|
||||||
val statement = connection.prepareStatement(sql)
|
val statement = connection.prepareStatement(sql)
|
||||||
statement.setString(1, item.model)
|
if (item.idSai != null) statement.setInt(1, item.idSai) else statement.setNull(1, Types.INTEGER)
|
||||||
statement.setString(2, item.status)
|
statement.setString(2, item.brand)
|
||||||
statement.setInt(3, item.id)
|
statement.setString(3, item.installDate)
|
||||||
|
statement.setInt(4, item.id)
|
||||||
|
|
||||||
if (statement.executeUpdate() > 0) Result.success(Unit)
|
if (statement.executeUpdate() > 0) Result.success(Unit)
|
||||||
else Result.failure(Exception("update_failed"))
|
else Result.failure(Exception("update_failed"))
|
||||||
} catch (e: SQLException) {
|
} catch (e: SQLException) {
|
||||||
@@ -64,7 +70,7 @@ class BatteryRepository {
|
|||||||
suspend fun delete(id: Int): Result<Unit> = withContext(Dispatchers.IO) {
|
suspend fun delete(id: Int): Result<Unit> = withContext(Dispatchers.IO) {
|
||||||
val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error"))
|
val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error"))
|
||||||
try {
|
try {
|
||||||
val sql = "DELETE FROM baterias WHERE id_bateria = ?"
|
val sql = "DELETE FROM Bateria WHERE id_bateria = ?"
|
||||||
val statement = connection.prepareStatement(sql)
|
val statement = connection.prepareStatement(sql)
|
||||||
statement.setInt(1, id)
|
statement.setInt(1, id)
|
||||||
if (statement.executeUpdate() > 0) Result.success(Unit)
|
if (statement.executeUpdate() > 0) Result.success(Unit)
|
||||||
@@ -75,4 +81,28 @@ class BatteryRepository {
|
|||||||
connection.close()
|
connection.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun getById(id: Int): Result<Battery> = withContext(Dispatchers.IO) {
|
||||||
|
val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error"))
|
||||||
|
try {
|
||||||
|
val sql = "SELECT id_bateria, id_sai, marca, fecha_instalacion FROM Bateria WHERE id_bateria = ?"
|
||||||
|
val statement = connection.prepareStatement(sql)
|
||||||
|
statement.setInt(1, id)
|
||||||
|
val resultSet = statement.executeQuery()
|
||||||
|
if (resultSet.next()) {
|
||||||
|
Result.success(Battery(
|
||||||
|
id = resultSet.getInt("id_bateria"),
|
||||||
|
idSai = resultSet.getInt("id_sai").takeIf { !resultSet.wasNull() },
|
||||||
|
brand = resultSet.getString("marca"),
|
||||||
|
installDate = resultSet.getString("fecha_instalacion")
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Result.failure(Exception("not_found"))
|
||||||
|
}
|
||||||
|
} catch (e: SQLException) {
|
||||||
|
Result.failure(e)
|
||||||
|
} finally {
|
||||||
|
connection.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,15 +9,14 @@ class PersonRepository {
|
|||||||
suspend fun getAll(): Result<List<Person>> = withContext(Dispatchers.IO) {
|
suspend fun getAll(): Result<List<Person>> = withContext(Dispatchers.IO) {
|
||||||
val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error"))
|
val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error"))
|
||||||
try {
|
try {
|
||||||
val sql = "SELECT id_persona, nombre, puesto FROM personas"
|
val sql = "SELECT id_persona, nombre FROM Persona"
|
||||||
val statement = connection.prepareStatement(sql)
|
val statement = connection.prepareStatement(sql)
|
||||||
val resultSet = statement.executeQuery()
|
val resultSet = statement.executeQuery()
|
||||||
val items = mutableListOf<Person>()
|
val items = mutableListOf<Person>()
|
||||||
while (resultSet.next()) {
|
while (resultSet.next()) {
|
||||||
items.add(Person(
|
items.add(Person(
|
||||||
id = resultSet.getInt("id_persona"),
|
id = resultSet.getInt("id_persona"),
|
||||||
name = resultSet.getString("nombre"),
|
name = resultSet.getString("nombre")
|
||||||
position = resultSet.getString("puesto")
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
Result.success(items)
|
Result.success(items)
|
||||||
@@ -31,10 +30,9 @@ class PersonRepository {
|
|||||||
suspend fun insert(item: Person): Result<Unit> = withContext(Dispatchers.IO) {
|
suspend fun insert(item: Person): Result<Unit> = withContext(Dispatchers.IO) {
|
||||||
val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error"))
|
val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error"))
|
||||||
try {
|
try {
|
||||||
val sql = "INSERT INTO personas (nombre, puesto) VALUES (?, ?)"
|
val sql = "INSERT INTO Persona (nombre) VALUES (?)"
|
||||||
val statement = connection.prepareStatement(sql)
|
val statement = connection.prepareStatement(sql)
|
||||||
statement.setString(1, item.name)
|
statement.setString(1, item.name)
|
||||||
statement.setString(2, item.position)
|
|
||||||
if (statement.executeUpdate() > 0) Result.success(Unit)
|
if (statement.executeUpdate() > 0) Result.success(Unit)
|
||||||
else Result.failure(Exception("no_rows_inserted"))
|
else Result.failure(Exception("no_rows_inserted"))
|
||||||
} catch (e: SQLException) {
|
} catch (e: SQLException) {
|
||||||
@@ -47,11 +45,10 @@ class PersonRepository {
|
|||||||
suspend fun update(item: Person): Result<Unit> = withContext(Dispatchers.IO) {
|
suspend fun update(item: Person): Result<Unit> = withContext(Dispatchers.IO) {
|
||||||
val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error"))
|
val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error"))
|
||||||
try {
|
try {
|
||||||
val sql = "UPDATE personas SET nombre = ?, puesto = ? WHERE id_persona = ?"
|
val sql = "UPDATE Persona SET nombre = ? WHERE id_persona = ?"
|
||||||
val statement = connection.prepareStatement(sql)
|
val statement = connection.prepareStatement(sql)
|
||||||
statement.setString(1, item.name)
|
statement.setString(1, item.name)
|
||||||
statement.setString(2, item.position)
|
statement.setInt(2, item.id)
|
||||||
statement.setInt(3, item.id)
|
|
||||||
if (statement.executeUpdate() > 0) Result.success(Unit)
|
if (statement.executeUpdate() > 0) Result.success(Unit)
|
||||||
else Result.failure(Exception("update_failed"))
|
else Result.failure(Exception("update_failed"))
|
||||||
} catch (e: SQLException) {
|
} catch (e: SQLException) {
|
||||||
@@ -64,7 +61,7 @@ class PersonRepository {
|
|||||||
suspend fun delete(id: Int): Result<Unit> = withContext(Dispatchers.IO) {
|
suspend fun delete(id: Int): Result<Unit> = withContext(Dispatchers.IO) {
|
||||||
val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error"))
|
val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error"))
|
||||||
try {
|
try {
|
||||||
val sql = "DELETE FROM personas WHERE id_persona = ?"
|
val sql = "DELETE FROM Persona WHERE id_persona = ?"
|
||||||
val statement = connection.prepareStatement(sql)
|
val statement = connection.prepareStatement(sql)
|
||||||
statement.setInt(1, id)
|
statement.setInt(1, id)
|
||||||
if (statement.executeUpdate() > 0) Result.success(Unit)
|
if (statement.executeUpdate() > 0) Result.success(Unit)
|
||||||
@@ -75,4 +72,26 @@ class PersonRepository {
|
|||||||
connection.close()
|
connection.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun getById(id: Int): Result<Person> = withContext(Dispatchers.IO) {
|
||||||
|
val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error"))
|
||||||
|
try {
|
||||||
|
val sql = "SELECT id_persona, nombre FROM Persona WHERE id_persona = ?"
|
||||||
|
val statement = connection.prepareStatement(sql)
|
||||||
|
statement.setInt(1, id)
|
||||||
|
val resultSet = statement.executeQuery()
|
||||||
|
if (resultSet.next()) {
|
||||||
|
Result.success(Person(
|
||||||
|
id = resultSet.getInt("id_persona"),
|
||||||
|
name = resultSet.getString("nombre")
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Result.failure(Exception("not_found"))
|
||||||
|
}
|
||||||
|
} catch (e: SQLException) {
|
||||||
|
Result.failure(e)
|
||||||
|
} finally {
|
||||||
|
connection.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,4 +74,23 @@ class SaiRepository {
|
|||||||
connection.close()
|
connection.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun getById(id: Int): Result<Sai> = withContext(Dispatchers.IO) {
|
||||||
|
val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error"))
|
||||||
|
try {
|
||||||
|
val sql = "SELECT id_sai, ns FROM SAIs WHERE id_sai = ?"
|
||||||
|
val statement = connection.prepareStatement(sql)
|
||||||
|
statement.setInt(1, id)
|
||||||
|
val resultSet = statement.executeQuery()
|
||||||
|
if (resultSet.next()) {
|
||||||
|
Result.success(Sai(id = resultSet.getInt("id_sai"), ns = resultSet.getString("ns")))
|
||||||
|
} else {
|
||||||
|
Result.failure(Exception("not_found"))
|
||||||
|
}
|
||||||
|
} catch (e: SQLException) {
|
||||||
|
Result.failure(e)
|
||||||
|
} finally {
|
||||||
|
connection.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.example.saipp.data.model
|
||||||
|
|
||||||
|
data class Assignment(
|
||||||
|
val id: Int = 0,
|
||||||
|
val idSai: Int,
|
||||||
|
val idPersona: Int,
|
||||||
|
val assignedDate: String? = null,
|
||||||
|
val returnDate: String? = null,
|
||||||
|
// Optional display fields for joining data
|
||||||
|
val saiNs: String? = null,
|
||||||
|
val personName: String? = null
|
||||||
|
)
|
||||||
@@ -2,6 +2,7 @@ package com.example.saipp.data.model
|
|||||||
|
|
||||||
data class Battery(
|
data class Battery(
|
||||||
val id: Int = 0,
|
val id: Int = 0,
|
||||||
val model: String,
|
val idSai: Int? = null,
|
||||||
val status: String
|
val brand: String? = null,
|
||||||
|
val installDate: String? = null
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,6 +2,5 @@ package com.example.saipp.data.model
|
|||||||
|
|
||||||
data class Person(
|
data class Person(
|
||||||
val id: Int = 0,
|
val id: Int = 0,
|
||||||
val name: String,
|
val name: String
|
||||||
val position: String
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,19 +1,35 @@
|
|||||||
package com.example.saipp.ui
|
package com.example.saipp.ui
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.navigation.NavType
|
||||||
import androidx.navigation.compose.NavHost
|
import androidx.navigation.compose.NavHost
|
||||||
import androidx.navigation.compose.composable
|
import androidx.navigation.compose.composable
|
||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
|
import androidx.navigation.navArgument
|
||||||
import com.example.saipp.ui.management.*
|
import com.example.saipp.ui.management.*
|
||||||
|
|
||||||
sealed class Screen(val route: String) {
|
sealed class Screen(val route: String) {
|
||||||
object Home : Screen("home")
|
object Home : Screen("home")
|
||||||
object SaiList : Screen("sai_list")
|
object SaiList : Screen("sai_list")
|
||||||
object SaiScanner : Screen("sai_scanner")
|
object SaiScanner : Screen("sai_scanner")
|
||||||
|
object EditSai : Screen("edit_sai/{saiId}") {
|
||||||
|
fun createRoute(id: Int) = "edit_sai/$id"
|
||||||
|
}
|
||||||
object BatteryList : Screen("battery_list")
|
object BatteryList : Screen("battery_list")
|
||||||
object AddBattery : Screen("add_battery")
|
object AddBattery : Screen("add_battery")
|
||||||
|
object EditBattery : Screen("edit_battery/{batteryId}") {
|
||||||
|
fun createRoute(id: Int) = "edit_battery/$id"
|
||||||
|
}
|
||||||
object PersonList : Screen("person_list")
|
object PersonList : Screen("person_list")
|
||||||
object AddPerson : Screen("add_person")
|
object AddPerson : Screen("add_person")
|
||||||
|
object EditPerson : Screen("edit_person/{personId}") {
|
||||||
|
fun createRoute(id: Int) = "edit_person/$id"
|
||||||
|
}
|
||||||
|
object AssignmentList : Screen("assignment_list")
|
||||||
|
object AddAssignment : Screen("add_assignment")
|
||||||
|
object EditAssignment : Screen("edit_assignment/{assignmentId}") {
|
||||||
|
fun createRoute(id: Int) = "edit_assignment/$id"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -25,13 +41,17 @@ fun AppNavigation() {
|
|||||||
HomeScreen(
|
HomeScreen(
|
||||||
onNavigateToSais = { navController.navigate(Screen.SaiList.route) },
|
onNavigateToSais = { navController.navigate(Screen.SaiList.route) },
|
||||||
onNavigateToBatteries = { navController.navigate(Screen.BatteryList.route) },
|
onNavigateToBatteries = { navController.navigate(Screen.BatteryList.route) },
|
||||||
onNavigateToPeople = { navController.navigate(Screen.PersonList.route) }
|
onNavigateToPeople = { navController.navigate(Screen.PersonList.route) },
|
||||||
|
onNavigateToAssignments = { navController.navigate(Screen.AssignmentList.route) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SAIs
|
||||||
composable(Screen.SaiList.route) {
|
composable(Screen.SaiList.route) {
|
||||||
SaiListScreen(
|
SaiListScreen(
|
||||||
onNavigateBack = { navController.popBackStack() },
|
onNavigateBack = { navController.popBackStack() },
|
||||||
onNavigateToScan = { navController.navigate(Screen.SaiScanner.route) }
|
onNavigateToScan = { navController.navigate(Screen.SaiScanner.route) },
|
||||||
|
onNavigateToEdit = { id -> navController.navigate(Screen.EditSai.createRoute(id)) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
composable(Screen.SaiScanner.route) {
|
composable(Screen.SaiScanner.route) {
|
||||||
@@ -39,27 +59,69 @@ fun AppNavigation() {
|
|||||||
onNavigateBack = { navController.popBackStack() }
|
onNavigateBack = { navController.popBackStack() }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
composable(
|
||||||
|
route = Screen.EditSai.route,
|
||||||
|
arguments = listOf(navArgument("saiId") { type = NavType.IntType })
|
||||||
|
) { backStackEntry ->
|
||||||
|
val id = backStackEntry.arguments?.getInt("saiId") ?: 0
|
||||||
|
EditSaiScreen(saiId = id, onNavigateBack = { navController.popBackStack() })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Batteries
|
||||||
composable(Screen.BatteryList.route) {
|
composable(Screen.BatteryList.route) {
|
||||||
BatteryListScreen(
|
BatteryListScreen(
|
||||||
onNavigateBack = { navController.popBackStack() },
|
onNavigateBack = { navController.popBackStack() },
|
||||||
onNavigateToAdd = { navController.navigate(Screen.AddBattery.route) }
|
onNavigateToAdd = { navController.navigate(Screen.AddBattery.route) },
|
||||||
|
onNavigateToEdit = { id -> navController.navigate(Screen.EditBattery.createRoute(id)) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
composable(Screen.AddBattery.route) {
|
composable(Screen.AddBattery.route) {
|
||||||
AddBatteryScreen(
|
AddBatteryScreen(onNavigateBack = { navController.popBackStack() })
|
||||||
onNavigateBack = { navController.popBackStack() }
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
composable(
|
||||||
|
route = Screen.EditBattery.route,
|
||||||
|
arguments = listOf(navArgument("batteryId") { type = NavType.IntType })
|
||||||
|
) { backStackEntry ->
|
||||||
|
val id = backStackEntry.arguments?.getInt("batteryId") ?: 0
|
||||||
|
EditBatteryScreen(batteryId = id, onNavigateBack = { navController.popBackStack() })
|
||||||
|
}
|
||||||
|
|
||||||
|
// People
|
||||||
composable(Screen.PersonList.route) {
|
composable(Screen.PersonList.route) {
|
||||||
PersonListScreen(
|
PersonListScreen(
|
||||||
onNavigateBack = { navController.popBackStack() },
|
onNavigateBack = { navController.popBackStack() },
|
||||||
onNavigateToAdd = { navController.navigate(Screen.AddPerson.route) }
|
onNavigateToAdd = { navController.navigate(Screen.AddPerson.route) },
|
||||||
|
onNavigateToEdit = { id -> navController.navigate(Screen.EditPerson.createRoute(id)) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
composable(Screen.AddPerson.route) {
|
composable(Screen.AddPerson.route) {
|
||||||
AddPersonScreen(
|
AddPersonScreen(onNavigateBack = { navController.popBackStack() })
|
||||||
onNavigateBack = { navController.popBackStack() }
|
}
|
||||||
|
composable(
|
||||||
|
route = Screen.EditPerson.route,
|
||||||
|
arguments = listOf(navArgument("personId") { type = NavType.IntType })
|
||||||
|
) { backStackEntry ->
|
||||||
|
val id = backStackEntry.arguments?.getInt("personId") ?: 0
|
||||||
|
EditPersonScreen(personId = id, onNavigateBack = { navController.popBackStack() })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assignments
|
||||||
|
composable(Screen.AssignmentList.route) {
|
||||||
|
AssignmentListScreen(
|
||||||
|
onNavigateBack = { navController.popBackStack() },
|
||||||
|
onNavigateToAdd = { navController.navigate(Screen.AddAssignment.route) },
|
||||||
|
onNavigateToEdit = { id -> navController.navigate(Screen.EditAssignment.createRoute(id)) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
composable(Screen.AddAssignment.route) {
|
||||||
|
AddAssignmentScreen(onNavigateBack = { navController.popBackStack() })
|
||||||
|
}
|
||||||
|
composable(
|
||||||
|
route = Screen.EditAssignment.route,
|
||||||
|
arguments = listOf(navArgument("assignmentId") { type = NavType.IntType })
|
||||||
|
) { backStackEntry ->
|
||||||
|
val id = backStackEntry.arguments?.getInt("assignmentId") ?: 0
|
||||||
|
EditAssignmentScreen(assignmentId = id, onNavigateBack = { navController.popBackStack() })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,179 @@
|
|||||||
|
package com.example.saipp.ui.management
|
||||||
|
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
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.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.AssignmentRepository
|
||||||
|
import com.example.saipp.data.PersonRepository
|
||||||
|
import com.example.saipp.data.SaiRepository
|
||||||
|
import com.example.saipp.data.model.Assignment
|
||||||
|
import com.example.saipp.data.model.Person
|
||||||
|
import com.example.saipp.data.model.Sai
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun AddAssignmentScreen(
|
||||||
|
onNavigateBack: () -> Unit
|
||||||
|
) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
val repository = remember { AssignmentRepository() }
|
||||||
|
val saiRepository = remember { SaiRepository() }
|
||||||
|
val personRepository = remember { PersonRepository() }
|
||||||
|
|
||||||
|
var selectedSaiId by remember { mutableStateOf<Int?>(null) }
|
||||||
|
var selectedPersonId by remember { mutableStateOf<Int?>(null) }
|
||||||
|
var assignedDate by remember { mutableStateOf("") }
|
||||||
|
var returnDate by remember { mutableStateOf("") }
|
||||||
|
|
||||||
|
var sais by remember { mutableStateOf<List<Sai>>(emptyList()) }
|
||||||
|
var people by remember { mutableStateOf<List<Person>>(emptyList()) }
|
||||||
|
var isSaving by remember { mutableStateOf(false) }
|
||||||
|
var saiExpanded by remember { mutableStateOf(false) }
|
||||||
|
var personExpanded by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
saiRepository.getAll().onSuccess { sais = it }
|
||||||
|
personRepository.getAll().onSuccess { people = it }
|
||||||
|
}
|
||||||
|
|
||||||
|
Scaffold(
|
||||||
|
topBar = {
|
||||||
|
TopAppBar(
|
||||||
|
title = { Text("Añadir Asignación") },
|
||||||
|
navigationIcon = {
|
||||||
|
IconButton(onClick = onNavigateBack) {
|
||||||
|
Icon(Icons.Default.ArrowBack, contentDescription = "Atrás")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) { padding ->
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(padding)
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
// SAI Selection
|
||||||
|
ExposedDropdownMenuBox(
|
||||||
|
expanded = saiExpanded,
|
||||||
|
onExpandedChange = { saiExpanded = !saiExpanded }
|
||||||
|
) {
|
||||||
|
val selectedSai = sais.find { it.id == selectedSaiId }
|
||||||
|
OutlinedTextField(
|
||||||
|
value = selectedSai?.ns ?: stringResource(R.string.select_sai),
|
||||||
|
onValueChange = {},
|
||||||
|
readOnly = true,
|
||||||
|
label = { Text(stringResource(R.string.label_sai)) },
|
||||||
|
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = saiExpanded) },
|
||||||
|
modifier = Modifier.menuAnchor().fillMaxWidth()
|
||||||
|
)
|
||||||
|
ExposedDropdownMenu(
|
||||||
|
expanded = saiExpanded,
|
||||||
|
onDismissRequest = { saiExpanded = false }
|
||||||
|
) {
|
||||||
|
sais.forEach { sai ->
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(sai.ns) },
|
||||||
|
onClick = {
|
||||||
|
selectedSaiId = sai.id
|
||||||
|
saiExpanded = false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
|
// Person Selection
|
||||||
|
ExposedDropdownMenuBox(
|
||||||
|
expanded = personExpanded,
|
||||||
|
onExpandedChange = { personExpanded = !personExpanded }
|
||||||
|
) {
|
||||||
|
val selectedPerson = people.find { it.id == selectedPersonId }
|
||||||
|
OutlinedTextField(
|
||||||
|
value = selectedPerson?.name ?: stringResource(R.string.select_person),
|
||||||
|
onValueChange = {},
|
||||||
|
readOnly = true,
|
||||||
|
label = { Text(stringResource(R.string.label_person)) },
|
||||||
|
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = personExpanded) },
|
||||||
|
modifier = Modifier.menuAnchor().fillMaxWidth()
|
||||||
|
)
|
||||||
|
ExposedDropdownMenu(
|
||||||
|
expanded = personExpanded,
|
||||||
|
onDismissRequest = { personExpanded = false }
|
||||||
|
) {
|
||||||
|
people.forEach { person ->
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(person.name) },
|
||||||
|
onClick = {
|
||||||
|
selectedPersonId = person.id
|
||||||
|
personExpanded = false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
|
OutlinedTextField(
|
||||||
|
value = assignedDate,
|
||||||
|
onValueChange = { assignedDate = it },
|
||||||
|
label = { Text(stringResource(R.string.label_assigned_date)) },
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
|
OutlinedTextField(
|
||||||
|
value = returnDate,
|
||||||
|
onValueChange = { returnDate = it },
|
||||||
|
label = { Text(stringResource(R.string.label_return_date)) },
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(32.dp))
|
||||||
|
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
if (selectedSaiId != null && selectedPersonId != null) {
|
||||||
|
isSaving = true
|
||||||
|
scope.launch {
|
||||||
|
repository.insert(
|
||||||
|
Assignment(
|
||||||
|
idSai = selectedSaiId!!,
|
||||||
|
idPersona = selectedPersonId!!,
|
||||||
|
assignedDate = assignedDate.takeIf { it.isNotBlank() },
|
||||||
|
returnDate = returnDate.takeIf { it.isNotBlank() }
|
||||||
|
)
|
||||||
|
).onSuccess {
|
||||||
|
Toast.makeText(context, "Asignación guardada", Toast.LENGTH_SHORT).show()
|
||||||
|
onNavigateBack()
|
||||||
|
}.onFailure {
|
||||||
|
Toast.makeText(context, "Error: ${it.message}", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
isSaving = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
enabled = !isSaving && selectedSaiId != null && selectedPersonId != null
|
||||||
|
) {
|
||||||
|
if (isSaving) CircularProgressIndicator(modifier = Modifier.size(24.dp))
|
||||||
|
else Text("Guardar")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,9 +8,13 @@ import androidx.compose.material3.*
|
|||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.example.saipp.R
|
||||||
import com.example.saipp.data.BatteryRepository
|
import com.example.saipp.data.BatteryRepository
|
||||||
|
import com.example.saipp.data.SaiRepository
|
||||||
import com.example.saipp.data.model.Battery
|
import com.example.saipp.data.model.Battery
|
||||||
|
import com.example.saipp.data.model.Sai
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@@ -20,11 +24,20 @@ fun AddBatteryScreen(
|
|||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
val repository = remember { BatteryRepository() }
|
val batteryRepository = remember { BatteryRepository() }
|
||||||
|
val saiRepository = remember { SaiRepository() }
|
||||||
|
|
||||||
var model by remember { mutableStateOf("") }
|
var brand by remember { mutableStateOf("") }
|
||||||
var status by remember { mutableStateOf("") }
|
var installDate by remember { mutableStateOf("") }
|
||||||
|
var selectedSaiId by remember { mutableStateOf<Int?>(null) }
|
||||||
|
|
||||||
|
var sais by remember { mutableStateOf<List<Sai>>(emptyList()) }
|
||||||
var isSaving by remember { mutableStateOf(false) }
|
var isSaving by remember { mutableStateOf(false) }
|
||||||
|
var expanded by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
saiRepository.getAll().onSuccess { sais = it }
|
||||||
|
}
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
@@ -44,33 +57,80 @@ fun AddBatteryScreen(
|
|||||||
.padding(padding)
|
.padding(padding)
|
||||||
.padding(16.dp)
|
.padding(16.dp)
|
||||||
) {
|
) {
|
||||||
OutlinedTextField(
|
// SAI Selection
|
||||||
value = model,
|
ExposedDropdownMenuBox(
|
||||||
onValueChange = { model = it },
|
expanded = expanded,
|
||||||
label = { Text("Modelo") },
|
onExpandedChange = { expanded = !expanded }
|
||||||
modifier = Modifier.fillMaxWidth()
|
) {
|
||||||
)
|
val selectedSai = sais.find { it.id == selectedSaiId }
|
||||||
|
OutlinedTextField(
|
||||||
|
value = selectedSai?.ns ?: stringResource(R.string.no_sai),
|
||||||
|
onValueChange = {},
|
||||||
|
readOnly = true,
|
||||||
|
label = { Text(stringResource(R.string.label_sai)) },
|
||||||
|
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
|
||||||
|
modifier = Modifier.menuAnchor().fillMaxWidth()
|
||||||
|
)
|
||||||
|
ExposedDropdownMenu(
|
||||||
|
expanded = expanded,
|
||||||
|
onDismissRequest = { expanded = false }
|
||||||
|
) {
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(stringResource(R.string.no_sai)) },
|
||||||
|
onClick = {
|
||||||
|
selectedSaiId = null
|
||||||
|
expanded = false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
sais.forEach { sai ->
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(sai.ns) },
|
||||||
|
onClick = {
|
||||||
|
selectedSaiId = sai.id
|
||||||
|
expanded = false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = status,
|
value = brand,
|
||||||
onValueChange = { status = it },
|
onValueChange = { brand = it },
|
||||||
label = { Text("Estado") },
|
label = { Text(stringResource(R.string.label_brand)) },
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
|
OutlinedTextField(
|
||||||
|
value = installDate,
|
||||||
|
onValueChange = { installDate = it },
|
||||||
|
label = { Text(stringResource(R.string.label_install_date)) },
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(32.dp))
|
Spacer(modifier = Modifier.height(32.dp))
|
||||||
|
|
||||||
Button(
|
Button(
|
||||||
onClick = {
|
onClick = {
|
||||||
if (model.isNotBlank() && status.isNotBlank()) {
|
isSaving = true
|
||||||
isSaving = true
|
scope.launch {
|
||||||
scope.launch {
|
batteryRepository.insert(
|
||||||
repository.insert(Battery(model = model, status = status))
|
Battery(
|
||||||
.onSuccess {
|
idSai = selectedSaiId,
|
||||||
Toast.makeText(context, "Batería añadida", Toast.LENGTH_SHORT).show()
|
brand = brand,
|
||||||
onNavigateBack()
|
installDate = installDate.takeIf { it.isNotBlank() }
|
||||||
}
|
)
|
||||||
.onFailure { Toast.makeText(context, "Error: ${it.message}", Toast.LENGTH_SHORT).show() }
|
).onSuccess {
|
||||||
isSaving = false
|
Toast.makeText(context, "Batería añadida", Toast.LENGTH_SHORT).show()
|
||||||
|
onNavigateBack()
|
||||||
|
}.onFailure {
|
||||||
|
Toast.makeText(context, "Error: ${it.message}", Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
|
isSaving = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ fun AddPersonScreen(
|
|||||||
val repository = remember { PersonRepository() }
|
val repository = remember { PersonRepository() }
|
||||||
|
|
||||||
var name by remember { mutableStateOf("") }
|
var name by remember { mutableStateOf("") }
|
||||||
var position by remember { mutableStateOf("") }
|
|
||||||
var isSaving by remember { mutableStateOf(false) }
|
var isSaving by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
@@ -50,20 +49,13 @@ fun AddPersonScreen(
|
|||||||
label = { Text("Nombre") },
|
label = { Text("Nombre") },
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
|
||||||
OutlinedTextField(
|
|
||||||
value = position,
|
|
||||||
onValueChange = { position = it },
|
|
||||||
label = { Text("Puesto") },
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(32.dp))
|
Spacer(modifier = Modifier.height(32.dp))
|
||||||
Button(
|
Button(
|
||||||
onClick = {
|
onClick = {
|
||||||
if (name.isNotBlank() && position.isNotBlank()) {
|
if (name.isNotBlank()) {
|
||||||
isSaving = true
|
isSaving = true
|
||||||
scope.launch {
|
scope.launch {
|
||||||
repository.insert(Person(name = name, position = position))
|
repository.insert(Person(name = name))
|
||||||
.onSuccess {
|
.onSuccess {
|
||||||
Toast.makeText(context, "Persona añadida", Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, "Persona añadida", Toast.LENGTH_SHORT).show()
|
||||||
onNavigateBack()
|
onNavigateBack()
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
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.Add
|
||||||
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
|
import androidx.compose.material.icons.filled.Delete
|
||||||
|
import androidx.compose.material.icons.filled.Edit
|
||||||
|
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.unit.dp
|
||||||
|
import com.example.saipp.data.AssignmentRepository
|
||||||
|
import com.example.saipp.data.model.Assignment
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun AssignmentListScreen(
|
||||||
|
onNavigateBack: () -> Unit,
|
||||||
|
onNavigateToAdd: () -> Unit,
|
||||||
|
onNavigateToEdit: (Int) -> Unit
|
||||||
|
) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
val repository = remember { AssignmentRepository() }
|
||||||
|
var items by remember { mutableStateOf<List<Assignment>>(emptyList()) }
|
||||||
|
var isLoading by remember { mutableStateOf(true) }
|
||||||
|
|
||||||
|
fun loadItems() {
|
||||||
|
scope.launch {
|
||||||
|
isLoading = true
|
||||||
|
repository.getAll()
|
||||||
|
.onSuccess { items = it }
|
||||||
|
.onFailure { Toast.makeText(context, "Error: ${it.message}", Toast.LENGTH_SHORT).show() }
|
||||||
|
isLoading = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
loadItems()
|
||||||
|
}
|
||||||
|
|
||||||
|
Scaffold(
|
||||||
|
topBar = {
|
||||||
|
TopAppBar(
|
||||||
|
title = { Text("Listado de Asignaciones") },
|
||||||
|
navigationIcon = {
|
||||||
|
IconButton(onClick = onNavigateBack) {
|
||||||
|
Icon(Icons.Default.ArrowBack, contentDescription = "Atrás")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
floatingActionButton = {
|
||||||
|
FloatingActionButton(onClick = onNavigateToAdd) {
|
||||||
|
Icon(Icons.Default.Add, contentDescription = "Añadir Asignación")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) { padding ->
|
||||||
|
if (isLoading) {
|
||||||
|
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
||||||
|
CircularProgressIndicator()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(padding)
|
||||||
|
) {
|
||||||
|
items(items) { item ->
|
||||||
|
ListItem(
|
||||||
|
headlineContent = { Text("${item.personName ?: "Persona desconocida"}") },
|
||||||
|
supportingContent = {
|
||||||
|
Column {
|
||||||
|
Text("SAI: ${item.saiNs ?: "N/A"}")
|
||||||
|
Text("Asignado: ${item.assignedDate ?: "N/A"}")
|
||||||
|
if (item.returnDate != null) {
|
||||||
|
Text("Devolución: ${item.returnDate}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trailingContent = {
|
||||||
|
Row {
|
||||||
|
IconButton(onClick = { onNavigateToEdit(item.id) }) {
|
||||||
|
Icon(Icons.Default.Edit, contentDescription = "Editar")
|
||||||
|
}
|
||||||
|
IconButton(onClick = {
|
||||||
|
scope.launch {
|
||||||
|
repository.delete(item.id).onSuccess { loadItems() }
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Icon(Icons.Default.Delete, contentDescription = "Eliminar")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
HorizontalDivider()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ import androidx.compose.material.icons.Icons
|
|||||||
import androidx.compose.material.icons.filled.Add
|
import androidx.compose.material.icons.filled.Add
|
||||||
import androidx.compose.material.icons.filled.ArrowBack
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
import androidx.compose.material.icons.filled.Delete
|
import androidx.compose.material.icons.filled.Delete
|
||||||
|
import androidx.compose.material.icons.filled.Edit
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
@@ -22,7 +23,8 @@ import kotlinx.coroutines.launch
|
|||||||
@Composable
|
@Composable
|
||||||
fun BatteryListScreen(
|
fun BatteryListScreen(
|
||||||
onNavigateBack: () -> Unit,
|
onNavigateBack: () -> Unit,
|
||||||
onNavigateToAdd: () -> Unit
|
onNavigateToAdd: () -> Unit,
|
||||||
|
onNavigateToEdit: (Int) -> Unit
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
@@ -73,15 +75,25 @@ fun BatteryListScreen(
|
|||||||
) {
|
) {
|
||||||
items(items) { item ->
|
items(items) { item ->
|
||||||
ListItem(
|
ListItem(
|
||||||
headlineContent = { Text("Modelo: ${item.model}") },
|
headlineContent = { Text("Marca: ${item.brand ?: "Desconocida"}") },
|
||||||
supportingContent = { Text("Estado: ${item.status}") },
|
supportingContent = {
|
||||||
|
Column {
|
||||||
|
Text("Instalación: ${item.installDate ?: "N/A"}")
|
||||||
|
item.idSai?.let { Text("SAI ID: $it") }
|
||||||
|
}
|
||||||
|
},
|
||||||
trailingContent = {
|
trailingContent = {
|
||||||
IconButton(onClick = {
|
Row {
|
||||||
scope.launch {
|
IconButton(onClick = { onNavigateToEdit(item.id) }) {
|
||||||
repository.delete(item.id).onSuccess { loadItems() }
|
Icon(Icons.Default.Edit, contentDescription = "Editar")
|
||||||
|
}
|
||||||
|
IconButton(onClick = {
|
||||||
|
scope.launch {
|
||||||
|
repository.delete(item.id).onSuccess { loadItems() }
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Icon(Icons.Default.Delete, contentDescription = "Eliminar")
|
||||||
}
|
}
|
||||||
}) {
|
|
||||||
Icon(Icons.Default.Delete, contentDescription = "Eliminar")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,203 @@
|
|||||||
|
package com.example.saipp.ui.management
|
||||||
|
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
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.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.AssignmentRepository
|
||||||
|
import com.example.saipp.data.PersonRepository
|
||||||
|
import com.example.saipp.data.SaiRepository
|
||||||
|
import com.example.saipp.data.model.Assignment
|
||||||
|
import com.example.saipp.data.model.Person
|
||||||
|
import com.example.saipp.data.model.Sai
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun EditAssignmentScreen(
|
||||||
|
assignmentId: Int,
|
||||||
|
onNavigateBack: () -> Unit
|
||||||
|
) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
val repository = remember { AssignmentRepository() }
|
||||||
|
val saiRepository = remember { SaiRepository() }
|
||||||
|
val personRepository = remember { PersonRepository() }
|
||||||
|
|
||||||
|
var selectedSaiId by remember { mutableStateOf<Int?>(null) }
|
||||||
|
var selectedPersonId by remember { mutableStateOf<Int?>(null) }
|
||||||
|
var assignedDate by remember { mutableStateOf("") }
|
||||||
|
var returnDate by remember { mutableStateOf("") }
|
||||||
|
|
||||||
|
var sais by remember { mutableStateOf<List<Sai>>(emptyList()) }
|
||||||
|
var people by remember { mutableStateOf<List<Person>>(emptyList()) }
|
||||||
|
var isLoading by remember { mutableStateOf(true) }
|
||||||
|
var isSaving by remember { mutableStateOf(false) }
|
||||||
|
var saiExpanded by remember { mutableStateOf(false) }
|
||||||
|
var personExpanded by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
LaunchedEffect(assignmentId) {
|
||||||
|
val assignmentResult = repository.getById(assignmentId)
|
||||||
|
val saisResult = saiRepository.getAll()
|
||||||
|
val peopleResult = personRepository.getAll()
|
||||||
|
|
||||||
|
if (assignmentResult.isSuccess) {
|
||||||
|
val item = assignmentResult.getOrNull()!!
|
||||||
|
selectedSaiId = item.idSai
|
||||||
|
selectedPersonId = item.idPersona
|
||||||
|
assignedDate = item.assignedDate ?: ""
|
||||||
|
returnDate = item.returnDate ?: ""
|
||||||
|
sais = saisResult.getOrDefault(emptyList())
|
||||||
|
people = peopleResult.getOrDefault(emptyList())
|
||||||
|
isLoading = false
|
||||||
|
} else {
|
||||||
|
Toast.makeText(context, "Error al cargar asignación", Toast.LENGTH_SHORT).show()
|
||||||
|
onNavigateBack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Scaffold(
|
||||||
|
topBar = {
|
||||||
|
TopAppBar(
|
||||||
|
title = { Text("Editar Asignación") },
|
||||||
|
navigationIcon = {
|
||||||
|
IconButton(onClick = onNavigateBack) {
|
||||||
|
Icon(Icons.Default.ArrowBack, contentDescription = "Atrás")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) { padding ->
|
||||||
|
if (isLoading) {
|
||||||
|
Box(modifier = Modifier.fillMaxSize().padding(padding), contentAlignment = androidx.compose.ui.Alignment.Center) {
|
||||||
|
CircularProgressIndicator()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(padding)
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
// SAI Selection
|
||||||
|
ExposedDropdownMenuBox(
|
||||||
|
expanded = saiExpanded,
|
||||||
|
onExpandedChange = { saiExpanded = !saiExpanded }
|
||||||
|
) {
|
||||||
|
val selectedSai = sais.find { it.id == selectedSaiId }
|
||||||
|
OutlinedTextField(
|
||||||
|
value = selectedSai?.ns ?: stringResource(R.string.select_sai),
|
||||||
|
onValueChange = {},
|
||||||
|
readOnly = true,
|
||||||
|
label = { Text(stringResource(R.string.label_sai)) },
|
||||||
|
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = saiExpanded) },
|
||||||
|
modifier = Modifier.menuAnchor().fillMaxWidth()
|
||||||
|
)
|
||||||
|
ExposedDropdownMenu(
|
||||||
|
expanded = saiExpanded,
|
||||||
|
onDismissRequest = { saiExpanded = false }
|
||||||
|
) {
|
||||||
|
sais.forEach { sai ->
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(sai.ns) },
|
||||||
|
onClick = {
|
||||||
|
selectedSaiId = sai.id
|
||||||
|
saiExpanded = false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
|
// Person Selection
|
||||||
|
ExposedDropdownMenuBox(
|
||||||
|
expanded = personExpanded,
|
||||||
|
onExpandedChange = { personExpanded = !personExpanded }
|
||||||
|
) {
|
||||||
|
val selectedPerson = people.find { it.id == selectedPersonId }
|
||||||
|
OutlinedTextField(
|
||||||
|
value = selectedPerson?.name ?: stringResource(R.string.select_person),
|
||||||
|
onValueChange = {},
|
||||||
|
readOnly = true,
|
||||||
|
label = { Text(stringResource(R.string.label_person)) },
|
||||||
|
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = personExpanded) },
|
||||||
|
modifier = Modifier.menuAnchor().fillMaxWidth()
|
||||||
|
)
|
||||||
|
ExposedDropdownMenu(
|
||||||
|
expanded = personExpanded,
|
||||||
|
onDismissRequest = { personExpanded = false }
|
||||||
|
) {
|
||||||
|
people.forEach { person ->
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(person.name) },
|
||||||
|
onClick = {
|
||||||
|
selectedPersonId = person.id
|
||||||
|
personExpanded = false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
|
OutlinedTextField(
|
||||||
|
value = assignedDate,
|
||||||
|
onValueChange = { assignedDate = it },
|
||||||
|
label = { Text(stringResource(R.string.label_assigned_date)) },
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
|
OutlinedTextField(
|
||||||
|
value = returnDate,
|
||||||
|
onValueChange = { returnDate = it },
|
||||||
|
label = { Text(stringResource(R.string.label_return_date)) },
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(32.dp))
|
||||||
|
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
if (selectedSaiId != null && selectedPersonId != null) {
|
||||||
|
isSaving = true
|
||||||
|
scope.launch {
|
||||||
|
repository.update(
|
||||||
|
Assignment(
|
||||||
|
id = assignmentId,
|
||||||
|
idSai = selectedSaiId!!,
|
||||||
|
idPersona = selectedPersonId!!,
|
||||||
|
assignedDate = assignedDate.takeIf { it.isNotBlank() },
|
||||||
|
returnDate = returnDate.takeIf { it.isNotBlank() }
|
||||||
|
)
|
||||||
|
).onSuccess {
|
||||||
|
Toast.makeText(context, "Asignación actualizada", Toast.LENGTH_SHORT).show()
|
||||||
|
onNavigateBack()
|
||||||
|
}.onFailure {
|
||||||
|
Toast.makeText(context, "Error: ${it.message}", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
isSaving = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
enabled = !isSaving && selectedSaiId != null && selectedPersonId != null
|
||||||
|
) {
|
||||||
|
if (isSaving) CircularProgressIndicator(modifier = Modifier.size(24.dp))
|
||||||
|
else Text("Guardar Cambios")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,166 @@
|
|||||||
|
package com.example.saipp.ui.management
|
||||||
|
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
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.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.BatteryRepository
|
||||||
|
import com.example.saipp.data.SaiRepository
|
||||||
|
import com.example.saipp.data.model.Battery
|
||||||
|
import com.example.saipp.data.model.Sai
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun EditBatteryScreen(
|
||||||
|
batteryId: Int,
|
||||||
|
onNavigateBack: () -> Unit
|
||||||
|
) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
val batteryRepository = remember { BatteryRepository() }
|
||||||
|
val saiRepository = remember { SaiRepository() }
|
||||||
|
|
||||||
|
var brand by remember { mutableStateOf("") }
|
||||||
|
var installDate by remember { mutableStateOf("") }
|
||||||
|
var selectedSaiId by remember { mutableStateOf<Int?>(null) }
|
||||||
|
|
||||||
|
var sais by remember { mutableStateOf<List<Sai>>(emptyList()) }
|
||||||
|
var isLoading by remember { mutableStateOf(true) }
|
||||||
|
var isSaving by remember { mutableStateOf(false) }
|
||||||
|
var expanded by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
LaunchedEffect(batteryId) {
|
||||||
|
val batteryResult = batteryRepository.getById(batteryId)
|
||||||
|
val saisResult = saiRepository.getAll()
|
||||||
|
|
||||||
|
if (batteryResult.isSuccess) {
|
||||||
|
val battery = batteryResult.getOrNull()!!
|
||||||
|
brand = battery.brand ?: ""
|
||||||
|
installDate = battery.installDate ?: ""
|
||||||
|
selectedSaiId = battery.idSai
|
||||||
|
sais = saisResult.getOrDefault(emptyList())
|
||||||
|
isLoading = false
|
||||||
|
} else {
|
||||||
|
Toast.makeText(context, "Error al cargar batería", Toast.LENGTH_SHORT).show()
|
||||||
|
onNavigateBack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Scaffold(
|
||||||
|
topBar = {
|
||||||
|
TopAppBar(
|
||||||
|
title = { Text("Editar Batería") },
|
||||||
|
navigationIcon = {
|
||||||
|
IconButton(onClick = onNavigateBack) {
|
||||||
|
Icon(Icons.Default.ArrowBack, contentDescription = "Atrás")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) { padding ->
|
||||||
|
if (isLoading) {
|
||||||
|
Box(modifier = Modifier.fillMaxSize().padding(padding), contentAlignment = androidx.compose.ui.Alignment.Center) {
|
||||||
|
CircularProgressIndicator()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(padding)
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
// SAI Selection
|
||||||
|
ExposedDropdownMenuBox(
|
||||||
|
expanded = expanded,
|
||||||
|
onExpandedChange = { expanded = !expanded }
|
||||||
|
) {
|
||||||
|
val selectedSai = sais.find { it.id == selectedSaiId }
|
||||||
|
OutlinedTextField(
|
||||||
|
value = selectedSai?.ns ?: stringResource(R.string.no_sai),
|
||||||
|
onValueChange = {},
|
||||||
|
readOnly = true,
|
||||||
|
label = { Text(stringResource(R.string.label_sai)) },
|
||||||
|
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
|
||||||
|
modifier = Modifier.menuAnchor().fillMaxWidth()
|
||||||
|
)
|
||||||
|
ExposedDropdownMenu(
|
||||||
|
expanded = expanded,
|
||||||
|
onDismissRequest = { expanded = false }
|
||||||
|
) {
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(stringResource(R.string.no_sai)) },
|
||||||
|
onClick = {
|
||||||
|
selectedSaiId = null
|
||||||
|
expanded = false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
sais.forEach { sai ->
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(sai.ns) },
|
||||||
|
onClick = {
|
||||||
|
selectedSaiId = sai.id
|
||||||
|
expanded = false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
|
OutlinedTextField(
|
||||||
|
value = brand,
|
||||||
|
onValueChange = { brand = it },
|
||||||
|
label = { Text(stringResource(R.string.label_brand)) },
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
|
OutlinedTextField(
|
||||||
|
value = installDate,
|
||||||
|
onValueChange = { installDate = it },
|
||||||
|
label = { Text(stringResource(R.string.label_install_date)) },
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(32.dp))
|
||||||
|
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
isSaving = true
|
||||||
|
scope.launch {
|
||||||
|
batteryRepository.update(
|
||||||
|
Battery(
|
||||||
|
id = batteryId,
|
||||||
|
idSai = selectedSaiId,
|
||||||
|
brand = brand,
|
||||||
|
installDate = installDate.takeIf { it.isNotBlank() }
|
||||||
|
)
|
||||||
|
).onSuccess {
|
||||||
|
Toast.makeText(context, "Batería actualizada", Toast.LENGTH_SHORT).show()
|
||||||
|
onNavigateBack()
|
||||||
|
}.onFailure {
|
||||||
|
Toast.makeText(context, "Error: ${it.message}", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
isSaving = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
enabled = !isSaving
|
||||||
|
) {
|
||||||
|
if (isSaving) CircularProgressIndicator(modifier = Modifier.size(24.dp))
|
||||||
|
else Text("Guardar Cambios")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
package com.example.saipp.ui.management
|
||||||
|
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
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.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.example.saipp.data.PersonRepository
|
||||||
|
import com.example.saipp.data.model.Person
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun EditPersonScreen(
|
||||||
|
personId: Int,
|
||||||
|
onNavigateBack: () -> Unit
|
||||||
|
) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
val repository = remember { PersonRepository() }
|
||||||
|
|
||||||
|
var name by remember { mutableStateOf("") }
|
||||||
|
var isLoading by remember { mutableStateOf(true) }
|
||||||
|
var isSaving by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
LaunchedEffect(personId) {
|
||||||
|
repository.getById(personId).onSuccess {
|
||||||
|
name = it.name
|
||||||
|
isLoading = false
|
||||||
|
}.onFailure {
|
||||||
|
Toast.makeText(context, "Error al cargar persona", Toast.LENGTH_SHORT).show()
|
||||||
|
onNavigateBack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Scaffold(
|
||||||
|
topBar = {
|
||||||
|
TopAppBar(
|
||||||
|
title = { Text("Editar Persona") },
|
||||||
|
navigationIcon = {
|
||||||
|
IconButton(onClick = onNavigateBack) {
|
||||||
|
Icon(Icons.Default.ArrowBack, contentDescription = "Atrás")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) { padding ->
|
||||||
|
if (isLoading) {
|
||||||
|
Box(modifier = Modifier.fillMaxSize().padding(padding), contentAlignment = androidx.compose.ui.Alignment.Center) {
|
||||||
|
CircularProgressIndicator()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(padding)
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
OutlinedTextField(
|
||||||
|
value = name,
|
||||||
|
onValueChange = { name = it },
|
||||||
|
label = { Text("Nombre") },
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(32.dp))
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
if (name.isNotBlank()) {
|
||||||
|
isSaving = true
|
||||||
|
scope.launch {
|
||||||
|
repository.update(Person(id = personId, name = name))
|
||||||
|
.onSuccess {
|
||||||
|
Toast.makeText(context, "Persona actualizada", Toast.LENGTH_SHORT).show()
|
||||||
|
onNavigateBack()
|
||||||
|
}
|
||||||
|
.onFailure { Toast.makeText(context, "Error: ${it.message}", Toast.LENGTH_SHORT).show() }
|
||||||
|
isSaving = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
enabled = !isSaving
|
||||||
|
) {
|
||||||
|
if (isSaving) CircularProgressIndicator(modifier = Modifier.size(24.dp))
|
||||||
|
else Text("Guardar Cambios")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
package com.example.saipp.ui.management
|
||||||
|
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
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.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.example.saipp.data.SaiRepository
|
||||||
|
import com.example.saipp.data.model.Sai
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun EditSaiScreen(
|
||||||
|
saiId: Int,
|
||||||
|
onNavigateBack: () -> Unit
|
||||||
|
) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
val repository = remember { SaiRepository() }
|
||||||
|
|
||||||
|
var ns by remember { mutableStateOf("") }
|
||||||
|
var isLoading by remember { mutableStateOf(true) }
|
||||||
|
var isSaving by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
LaunchedEffect(saiId) {
|
||||||
|
repository.getById(saiId).onSuccess {
|
||||||
|
ns = it.ns
|
||||||
|
isLoading = false
|
||||||
|
}.onFailure {
|
||||||
|
Toast.makeText(context, "Error al cargar SAI", Toast.LENGTH_SHORT).show()
|
||||||
|
onNavigateBack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Scaffold(
|
||||||
|
topBar = {
|
||||||
|
TopAppBar(
|
||||||
|
title = { Text("Editar SAI") },
|
||||||
|
navigationIcon = {
|
||||||
|
IconButton(onClick = onNavigateBack) {
|
||||||
|
Icon(Icons.Default.ArrowBack, contentDescription = "Atrás")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) { padding ->
|
||||||
|
if (isLoading) {
|
||||||
|
Box(modifier = Modifier.fillMaxSize().padding(padding), contentAlignment = androidx.compose.ui.Alignment.Center) {
|
||||||
|
CircularProgressIndicator()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(padding)
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
OutlinedTextField(
|
||||||
|
value = ns,
|
||||||
|
onValueChange = { ns = it },
|
||||||
|
label = { Text("Número de Serie") },
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(32.dp))
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
if (ns.isNotBlank()) {
|
||||||
|
isSaving = true
|
||||||
|
scope.launch {
|
||||||
|
repository.update(Sai(id = saiId, ns = ns))
|
||||||
|
.onSuccess {
|
||||||
|
Toast.makeText(context, "SAI actualizado", Toast.LENGTH_SHORT).show()
|
||||||
|
onNavigateBack()
|
||||||
|
}
|
||||||
|
.onFailure { Toast.makeText(context, "Error: ${it.message}", Toast.LENGTH_SHORT).show() }
|
||||||
|
isSaving = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
enabled = !isSaving
|
||||||
|
) {
|
||||||
|
if (isSaving) CircularProgressIndicator(modifier = Modifier.size(24.dp))
|
||||||
|
else Text("Guardar Cambios")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,7 +5,6 @@ import androidx.compose.material3.*
|
|||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.example.saipp.ui.ConnectionIndicator
|
import com.example.saipp.ui.ConnectionIndicator
|
||||||
@@ -17,7 +16,8 @@ import com.example.saipp.data.MariaDbConnection
|
|||||||
fun HomeScreen(
|
fun HomeScreen(
|
||||||
onNavigateToSais: () -> Unit,
|
onNavigateToSais: () -> Unit,
|
||||||
onNavigateToBatteries: () -> Unit,
|
onNavigateToBatteries: () -> Unit,
|
||||||
onNavigateToPeople: () -> Unit
|
onNavigateToPeople: () -> Unit,
|
||||||
|
onNavigateToAssignments: () -> Unit
|
||||||
) {
|
) {
|
||||||
var connectionStatus by remember { mutableStateOf<Result<Unit>?>(null) }
|
var connectionStatus by remember { mutableStateOf<Result<Unit>?>(null) }
|
||||||
var isCheckingConnection by remember { mutableStateOf(true) }
|
var isCheckingConnection by remember { mutableStateOf(true) }
|
||||||
@@ -49,7 +49,7 @@ fun HomeScreen(
|
|||||||
Spacer(modifier = Modifier.height(32.dp))
|
Spacer(modifier = Modifier.height(32.dp))
|
||||||
|
|
||||||
MenuButton(
|
MenuButton(
|
||||||
text = "Gestión de SAIs",
|
text = stringResource(R.string.menu_sais),
|
||||||
onClick = onNavigateToSais,
|
onClick = onNavigateToSais,
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
)
|
)
|
||||||
@@ -57,7 +57,7 @@ fun HomeScreen(
|
|||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
MenuButton(
|
MenuButton(
|
||||||
text = "Gestión de Baterías",
|
text = stringResource(R.string.menu_batteries),
|
||||||
onClick = onNavigateToBatteries,
|
onClick = onNavigateToBatteries,
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
)
|
)
|
||||||
@@ -65,10 +65,18 @@ fun HomeScreen(
|
|||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
MenuButton(
|
MenuButton(
|
||||||
text = "Gestión de Personas",
|
text = stringResource(R.string.menu_people),
|
||||||
onClick = onNavigateToPeople,
|
onClick = onNavigateToPeople,
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
|
MenuButton(
|
||||||
|
text = stringResource(R.string.menu_assignments),
|
||||||
|
onClick = onNavigateToAssignments,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import androidx.compose.material.icons.Icons
|
|||||||
import androidx.compose.material.icons.filled.Add
|
import androidx.compose.material.icons.filled.Add
|
||||||
import androidx.compose.material.icons.filled.ArrowBack
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
import androidx.compose.material.icons.filled.Delete
|
import androidx.compose.material.icons.filled.Delete
|
||||||
|
import androidx.compose.material.icons.filled.Edit
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
@@ -22,7 +23,8 @@ import kotlinx.coroutines.launch
|
|||||||
@Composable
|
@Composable
|
||||||
fun PersonListScreen(
|
fun PersonListScreen(
|
||||||
onNavigateBack: () -> Unit,
|
onNavigateBack: () -> Unit,
|
||||||
onNavigateToAdd: () -> Unit
|
onNavigateToAdd: () -> Unit,
|
||||||
|
onNavigateToEdit: (Int) -> Unit
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
@@ -74,14 +76,18 @@ fun PersonListScreen(
|
|||||||
items(items) { item ->
|
items(items) { item ->
|
||||||
ListItem(
|
ListItem(
|
||||||
headlineContent = { Text(item.name) },
|
headlineContent = { Text(item.name) },
|
||||||
supportingContent = { Text(item.position) },
|
|
||||||
trailingContent = {
|
trailingContent = {
|
||||||
IconButton(onClick = {
|
Row {
|
||||||
scope.launch {
|
IconButton(onClick = { onNavigateToEdit(item.id) }) {
|
||||||
repository.delete(item.id).onSuccess { loadItems() }
|
Icon(Icons.Default.Edit, contentDescription = "Editar")
|
||||||
|
}
|
||||||
|
IconButton(onClick = {
|
||||||
|
scope.launch {
|
||||||
|
repository.delete(item.id).onSuccess { loadItems() }
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Icon(Icons.Default.Delete, contentDescription = "Eliminar")
|
||||||
}
|
}
|
||||||
}) {
|
|
||||||
Icon(Icons.Default.Delete, contentDescription = "Eliminar")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import androidx.compose.material.icons.Icons
|
|||||||
import androidx.compose.material.icons.filled.Add
|
import androidx.compose.material.icons.filled.Add
|
||||||
import androidx.compose.material.icons.filled.ArrowBack
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
import androidx.compose.material.icons.filled.Delete
|
import androidx.compose.material.icons.filled.Delete
|
||||||
|
import androidx.compose.material.icons.filled.Edit
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
@@ -22,7 +23,8 @@ import kotlinx.coroutines.launch
|
|||||||
@Composable
|
@Composable
|
||||||
fun SaiListScreen(
|
fun SaiListScreen(
|
||||||
onNavigateBack: () -> Unit,
|
onNavigateBack: () -> Unit,
|
||||||
onNavigateToScan: () -> Unit
|
onNavigateToScan: () -> Unit,
|
||||||
|
onNavigateToEdit: (Int) -> Unit
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
@@ -75,12 +77,17 @@ fun SaiListScreen(
|
|||||||
ListItem(
|
ListItem(
|
||||||
headlineContent = { Text("NS: ${sai.ns}") },
|
headlineContent = { Text("NS: ${sai.ns}") },
|
||||||
trailingContent = {
|
trailingContent = {
|
||||||
IconButton(onClick = {
|
Row {
|
||||||
scope.launch {
|
IconButton(onClick = { onNavigateToEdit(sai.id) }) {
|
||||||
repository.delete(sai.id).onSuccess { loadSais() }
|
Icon(Icons.Default.Edit, contentDescription = "Editar")
|
||||||
|
}
|
||||||
|
IconButton(onClick = {
|
||||||
|
scope.launch {
|
||||||
|
repository.delete(sai.id).onSuccess { loadSais() }
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Icon(Icons.Default.Delete, contentDescription = "Eliminar")
|
||||||
}
|
}
|
||||||
}) {
|
|
||||||
Icon(Icons.Default.Delete, contentDescription = "Eliminar")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -13,4 +13,19 @@
|
|||||||
<string name="db_connection_failed">No se pudo establecer conexión con el servidor</string>
|
<string name="db_connection_failed">No se pudo establecer conexión con el servidor</string>
|
||||||
<string name="db_connection_error">Error de conexión a la base de datos</string>
|
<string name="db_connection_error">Error de conexión a la base de datos</string>
|
||||||
<string name="no_rows_inserted">No se insertaron filas en la base de datos</string>
|
<string name="no_rows_inserted">No se insertaron filas en la base de datos</string>
|
||||||
|
<string name="label_sai">SAI</string>
|
||||||
|
<string name="label_brand">Marca</string>
|
||||||
|
<string name="label_install_date">Fecha Instalación (AAAA-MM-DD HH:MM:SS)</string>
|
||||||
|
<string name="select_sai">Seleccionar SAI</string>
|
||||||
|
<string name="no_sai">Ninguno</string>
|
||||||
|
|
||||||
|
<string name="menu_sais">Gestión de SAIs</string>
|
||||||
|
<string name="menu_batteries">Gestión de Baterías</string>
|
||||||
|
<string name="menu_people">Gestión de Personas</string>
|
||||||
|
<string name="menu_assignments">Gestión de Asignaciones</string>
|
||||||
|
|
||||||
|
<string name="label_person">Persona</string>
|
||||||
|
<string name="label_assigned_date">Fecha Asignación (AAAA-MM-DD)</string>
|
||||||
|
<string name="label_return_date">Fecha Devolución (AAAA-MM-DD)</string>
|
||||||
|
<string name="select_person">Seleccionar Persona</string>
|
||||||
</resources>
|
</resources>
|
||||||
Reference in New Issue
Block a user