# DÍA 2, BASES DE DATOS CON ROOM
Como has visto en la clase anterior, lo que hicimos fue declarar en AppModule las clases que queremos que sean accesibles para nuestra aplicación en este caso, cronosDao y CronosDataBase.
Nos faltaría ir al mainActivity y declarar que es el EntryPoint. Justo antes del MainActivity, incluimos

Verás al incluirlo que nos dice que una clase del HILT que le indica cuál es la clase base. Ejecutamos la aplicación para ver si todo va ok por ahora y vemos que se descargan las librerías del Hilt.
Ahora creamos el repositorio y CronosRepository que es una clase Kotlin:

En esta clase comenzamos la inyección de dependencias. Lo que vamos a hacer es básicamente crear los métodos que se usarán en el viewModel.
```
class CronosRepository @Inject constructor(private val cronosDatabaseDao: CronosDatabaseDao) {
suspend fun addCrono(crono: Cronos)=cronosDatabaseDao.insert(crono)
suspend fun updateCrono(crono: Cronos)=cronosDatabaseDao.update(crono)
suspend fun deleteCrono(crono: Cronos)=cronosDatabaseDao.delete(crono)
fun getAllCronos(): Flow<List<Cronos>> = cronosDatabaseDao.getCronos().flowOn(Dispatchers.IO).conflate()
fun getCronoById(id:Long): Flow<Cronos> = cronosDatabaseDao.getCronosById(id).flowOn(Dispatchers.IO).conflate()
}
```
Esto es lo que debemos pasar al viewModel para empezar a hacer las vistas. Creamos el package "viewModels", creamos la clase "CronosViewModel". A partir de ahora tendremos que inyectar siempre las dependencias pero si es en un Viewmodel se usa una etiqueta especial @HiltViewModel así avisamos al hilt de que las dependencias a inyectar serán manejadas con el ViewModel.
Inyectamos lo primero el constructor del repositorio que acabamos de crear y voilá, ya podemos manejar nuestra base de datos desde el ViewModel.
La inyección de dependencias funciona en cadena así que si inyectamos el CronosRepository que a su vez tenía inyectada la CronosDatabaseDao, también quedará accesible desde el viewModel
```
@HiltViewModel
class CronosViewModel @Inject constructor(private val repository: CronosRepository):ViewModel() {
}
```
En el viewModel como sabes incluimos toda la comunicación entre el modelo de datos y las vistas así que declaramos lo primero la variable que contendrá la lista de cronos, será una lista y será un MutableStateFlow porque necesitamos que no bloquee la mainActivity(o sea que recupere los datos mediante una corrutina) y que además se pueda modificar en tiempo de ejecución.
```
@HiltViewModel
class CronosViewModel @Inject constructor(private val repository: CronosRepository):ViewModel() {
private val _cronosList = MutableStateFlow<List<Cronos>>(emptyList())
val cronosList=_cronosList.asStateFlow()
init {
viewModelScope.launch(Dispatchers.IO){
repository.getAllCronos().collect{
item->
if (item.isNullOrEmpty()){
_cronosList.value= emptyList()
} else {
_cronosList.value=item
}
}
}
}
fun addCrono (crono:Cronos)=viewModelScope.launch{repository.addCrono(crono)}
fun updateCrono (crono:Cronos)=viewModelScope.launch{repository.updateCrono(crono)}
fun deleteCrono (crono:Cronos)=viewModelScope.launch{repository.deleteCrono(crono)}
}
```
Como ves en el init llamamos al select para que muestre todos los registros, y creamos las funciones accesibles desde las views para cada acción que podemos hacer con los Cronos.
Con esto tenemos todo lo que nos va a permitir el trabajo con la base de datos, ahora nos dedicamos a las vistas y lo hemos dejado de tal manera que desde las vistas no nos tendremos que preocupar sino de llamar lo que nos proporciona el viewModel.
## NavManager
Creamos el package de "navigation" y dentro el NavManager.tk
Y...como ya hemos dado la navegación, pongo el código que necesitamos.
```
@Composable
fun NavManager(){
val navController = rememberNavController()
NavHost(navController = navController, startDestination = "Home"){
composable("Home"){
HomeView(navController)
}
composable("AddView"){
AddView(navController)
}
composable("EditView"){
EditView(navController)
}
}
}
```
Como ves, estamos declarando el navController y diciendo que empezamos en Home, ya sabemos que vamos a hacer tres vistas, el Home, el AddView y el EditView.
Creamos nuestro package "views", y de nuevo, como esto y ya lo hemos visto sólo tendrán que crear las distintas vistas (recomiendo repasar aunque no deberían tener problema con esta parte)

Para poder probar ponemos un texto simple en el HomeView y en el MainActivity sustitumos la llamada al Greetings() por una llamada a nuestro NavManager().
Debería cargarse el HomeView con el texto que le hayamos puesto.
Añadimos a los colores del tema un color que llamamos principal y seguimos.
Añadir en ui.theme->Color.tk esta linea:
`val Principal= Color(0xFFF4511E)`
En ui.theme->Theme.tk ponemos este color como primary en el tema claro.
## HomeView
Vamos a crear un package components y dentro un buttons.tk para poner los botones que vamos a usar.
```
@Composable
fun FloatButton(onClick: () -> Unit) {
FloatingActionButton(
onClick = onClick,
containerColor = MaterialTheme.colorScheme.primary,
contentColor = Color.White
) {
Icon(
imageVector = Icons.Default.Add,
contentDescription = "Agregar"
)
}
}
@Composable
fun MainIconButton(icon: ImageVector, onClick:() -> Unit){
IconButton(onClick = onClick) {
Icon(imageVector = icon, contentDescription = null, tint = Color.White)
}
}
```
También creamos un BodyComponents para los composables que usaremos en el body:
```
@Composable
fun MainTitle(title: String) {
Text(text = title, color = Color.White, fontWeight = FontWeight.Bold)
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MainTextField(value: String, onValueChange: (String) -> Unit, label: String) {
OutlinedTextField(
value = value,
onValueChange = onValueChange,
label = { Text(text = label) },
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 30.dp)
.padding(bottom = 15.dp)
)
}
```
Este es el botón que usaremos para navegar en nuestra típica estructura de scaffold, volvemos al homeView y hacemos la primera aproximación que simplemente nos mostrará el scaffold y el botón que nos deberá llevar a "AddView"
```
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun HomeView(navController: NavController) {
Scaffold(
topBar = {
CenterAlignedTopAppBar(title = { MainTitle(title = "Crono App")},
colors = TopAppBarDefaults.centerAlignedTopAppBarColors(
containerColor = MaterialTheme.colorScheme.primary
) )
},
floatingActionButton = {
FloatButton {
navController.navigate("AddView")
}
}
) {
ContentHomeView(it, navController)
}
}
@Composable
fun ContentHomeView(it:PaddingValues, navController: NavController){
Column(
modifier = Modifier.padding(it)
){
}
}
```
Dejamos la HomeView vacía porque sería donde tendríamos que mostrar los datos, pero no tenemos, así que nos concentramos en la pantalla de añadir datos!
## AddView
Empezamos con una estructura similar al HomeView pero sin el botón flotante que sustituimos por un botón que nos lleve a la pantalla anterior. Probar lo siguiente:
```
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AddView(navController: NavController) {
Scaffold(
topBar = {
CenterAlignedTopAppBar(title = { MainTitle(title = "Crono App") },
colors = TopAppBarDefaults.centerAlignedTopAppBarColors(
containerColor = MaterialTheme.colorScheme.primary
),
navigationIcon ={
MainIconButton(icon = Icons.Default.ArrowBack) {
navController.popBackStack()
}
}
)
}
) {
ContentAddView(it, navController)
}
}
@Composable
fun ContentAddView(it: PaddingValues, navController: NavController){
Column(
modifier = Modifier.padding(it)
){
}
}
```
Aquí mostraremos el cronómetro y debemos manejar el estado de funcionando, pausa, continuar...así que creamos un package donde meter los componentes que manejarán esos estados. Creamos el package "state" y dentro un data clas "CronoState"
```
data class CronoState(
val cronometroActivo: Boolean=false,
val showSaveButton: Boolean=false,
val showTextFile: Boolean=false,
val title: String=""
)
```
## ViewModel del Cronómetro
Para manejar estos estados necesitaremos otro viewModel, así que dentro de viewModels creamos la clase CronometroViewModel
```
class CronometroViewModel: ViewModel() {
var state by mutableStateOf(CronoState())
private set
var cronoJob by mutableStateOf<Job?>(null)
private set
var tiempo by mutableStateOf(0L)
private set
fun onValue(value:String){
state = state.copy(title = value)
}
}
```
Vemos que vamos a usar el concepto de job que es que lanzamos un proceso que puede estar corriendo, pausado o detenido, al igual que un crono, nos va a ayudar a controlar la pausa y la reproducción del crono.
Y on value va recoger en una cadena el estado en cada momento.
Ahora creamos los métodos que necesitamos para pausar, finalizar y guardar. También haremos la función cronos() que es la que realmente hará funcionar el cronómetro.
```
class CronometroViewModel: ViewModel() {
var state by mutableStateOf(CronoState())
private set
var cronoJob by mutableStateOf<Job?>(null)
private set
var tiempo by mutableStateOf(0L)
private set
fun onValue(value:String){
state = state.copy(title = value)
}
fun iniciar(){
state= state.copy(
cronometroActivo = true
)
}
fun pausar(){
state= state.copy(
cronometroActivo = false,
showSaveButton = true
)
}
fun detener(){
cronoJob?.cancel()
tiempo=0
state= state.copy(
cronometroActivo = false,
showSaveButton = false,
showTextFile = false
)
}
fun showTextFile(){
state=state.copy(
showTextFile=true
)
}
fun cronos(){
if(state.cronometroActivo){
cronoJob?.cancel()
cronoJob= viewModelScope.launch {
while (true){
delay(1000)
tiempo+=1000
}
}
}else{
cronoJob?.cancel()
}
}
}
```
## Formato para el cronómetro
Vamos al bodyComponent y creamos el composable al que le pasamos el tiempo y nos lo pasa a formato horas:Minutos:segundos.
```
@Composable
fun formatTiempo(tiempo:Long): String{
val segundos =(tiempo/1000)%60
val minutos =(tiempo/1000/60)%60
val horas=tiempo/1000/3600
return String.format("%02d:%02d:%02d",horas, minutos, segundos)
}
```
## Ejecutamos el cronómetro
Vamos a probar el cronómetro pero primero necesitamos ir al mainActivity para que utilice este nuevo viewModel. Añadimos justo antes del setContent:
` val cronometroVM: CronometroViewModel by viewModels()`
Lo tenemos que pasar como parámetro al NavMager para que a su vez se lo pueda pasar al AddView, añadimos el paso del parámetro donde haga falta y ya podemos ponernos a hacer el AddView.
Por ahora lo vamos a probar como sigue:
```
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AddView(navController: NavController, cronometroVM: CronometroViewModel) {
Scaffold(
topBar = {
CenterAlignedTopAppBar(title = { MainTitle(title = "Crono App") },
colors = TopAppBarDefaults.centerAlignedTopAppBarColors(
containerColor = MaterialTheme.colorScheme.primary
),
navigationIcon ={
MainIconButton(icon = Icons.Default.ArrowBack) {
navController.popBackStack()
}
}
)
}
) {
ContentAddView(it, navController, cronometroVM)
}
}
@Composable
fun ContentAddView(it: PaddingValues, navController: NavController, cronometroVM: CronometroViewModel){
val state=cronometroVM.state
//si el cronómetro está activo se lanza inmediatamente la función cronos que cuenta el tiempo
LaunchedEffect(state.cronometroActivo ){
cronometroVM.cronos()
}
Column(
modifier = Modifier
.padding(it)
.padding(top = 30.dp)
.fillMaxSize(),
horizontalAlignment =Alignment.CenterHorizontally
){
Text(text = formatTiempo(cronometroVM.tiempo),
fontSize = 50.sp,
fontWeight = FontWeight.Bold
)
Button(onClick ={cronometroVM.iniciar()}) {
Text(text = "iniciar")
}
}
}
```
Verás que tenemos un cronómetro simple que se va a actualizando a medida que pasan los segundos, pero ni podemos parar ni guardar por ahora.
Prueben a ir atrás y volver, verán que el cronómetro sigue ejecutándose y si en el emaulador abren otra aplicación (sin cerrar la nuestra)verán tampoco se para.
## Botones para el cronómetro
Vamos a crear unos botones para nuestro cronómetro, en buttons creamos:
```
@Composable
fun CircleButton(
icon: ImageVector,
enabled: Boolean= false,
onClick: () -> Unit
){
Button(onClick = onClick ,
shape= CircleShape,
contentPadding = PaddingValues(8.dp),
enabled = enabled,
modifier = Modifier.padding(horizontal=15.dp)
) {
Icon(imageVector = icon,
contentDescription = "",
modifier=Modifier.size(24.dp)
)
}
}
```
Y volvemos al addView para añadir nuestro botón
```
@Composable
fun ContentAddView(it: PaddingValues, navController: NavController, cronometroVM: CronometroViewModel){
val state=cronometroVM.state
//si el cronómetro está activo se lanza inmediatamente la función cronos que cuenta el tiempo
LaunchedEffect(state.cronometroActivo ){
cronometroVM.cronos()
}
Column(
modifier = Modifier
.padding(it)
.padding(top = 30.dp)
.fillMaxSize(),
horizontalAlignment =Alignment.CenterHorizontally
){
Text(text = formatTiempo(cronometroVM.tiempo),
fontSize = 50.sp,
fontWeight = FontWeight.Bold
)
Row(horizontalArrangement = Arrangement.Center,
modifier = Modifier.padding(vertical=16.dp)
) {
//iniciar
CircleButton(icon = Icons.Default.PlayArrow,
enabled=!state.cronometroActivo) {
cronometroVM.iniciar()
}
//pausar
CircleButton(icon = Icons.Default.Person,
enabled=state.cronometroActivo) {
cronometroVM.pausar()
}
//detener
CircleButton(icon = Icons.Default.ThumbUp,
enabled=!state.cronometroActivo) {
cronometroVM.detener()
}
//mostrar guardar
CircleButton(icon = Icons.Default.Done,
enabled=state.showSaveButton) {
cronometroVM.showTextFile()
}
}
}
}
```
Como ves vamos usando nuestros botones para activar y desactivar unos y otros. Hemos usado cualquier icono porque no hay iconos de parar o pausa. Vamos a solucionarlo!
## Agregar nuevos iconos
Vamos a "res" pulsamos con botón derecho "New->vector asset" pulsamos en clipart y buscamos por "pause". Elige cualquiera de los gráficos vectoriales.

Si le das a ok tendrás el gráfico en res->drawable, elige uno para pausa, otro para stop y el de guardar.
También nos hará falta uno de un cronómetro para la Home, elige uno adecuado.
Para poder usar estos nuevos iconos necesitamos ir a la definición del botón y cambiarla:
```
@Composable
fun CircleButton(
icon: Painter,
enabled: Boolean= false,
onClick: () -> Unit
){
Button(onClick = onClick ,
shape= CircleShape,
contentPadding = PaddingValues(8.dp),
enabled = enabled,
modifier = Modifier.padding(horizontal=15.dp)
) {
Icon(painter = icon,
contentDescription = "",
modifier=Modifier.size(24.dp)
)
}
}
```
En el addView también hay que cambiar cosas:
```
Row(horizontalArrangement = Arrangement.Center,
modifier = Modifier.padding(vertical=16.dp)
) {
//iniciar
CircleButton(icon = painterResource(id = R.drawable.play),
enabled=!state.cronometroActivo) {
cronometroVM.iniciar()
}
//pausar
CircleButton(icon = painterResource(id = R.drawable.pause),
enabled=state.cronometroActivo) {
cronometroVM.pausar()
}
//detener
CircleButton(icon =painterResource(id = R.drawable.stop),
enabled=!state.cronometroActivo) {
cronometroVM.detener()
}
//mostrar guardar
CircleButton(icon =painterResource(id = R.drawable.save),
enabled=state.showSaveButton) {
cronometroVM.showTextFile()
```
## Guardar en el Room
Tenemos el valor del time pero no el texfield con la descripción que lo acompaña, vamos a hacerlo.
Pero primero hay que tener en cuenta que al guardar se debe usar el CronosViewModel que es el único que puede acceder desde las views a los datos.
Así que modificamos el MainActivity y lo que sea necesario para incluirlo:
```
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val cronometroVM: CronometroViewModel by viewModels()
val cronosVM: CronosViewModel by viewModels()
setContent {
RoomCronoAppTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
NavManager(cronometroVM, cronosVM)
}
}
}
}
}
```
Una vez hecho esto volvemos al addView para seguir añadiendo nuestro nuevo registro, para lo que tenemos que incluir un campo de texto con un botón que llame al addCrono pasando el objeto con los atributos del texto introducido y el tiempo:
```
if (state.showTextFile){
MainTextField(value =state.title ,
onValueChange = {cronometroVM.onValue(it)},
label ="Title" )
Button(onClick = {
cronosVM.addCrono(
Cronos(
title=state.title,
crono=cronometroVM.tiempo
)
)
cronometroVM.detener()
navController.popBackStack()
}) {
Text(text = "Guardar")
}
```
Para saber si se están introduciendo correctamente, vamos a crear el mostrar datos.
## Mostrar datos
Los datos se mostrarán en el HomeView y ponemos lo siguiente para ver si se han guardado los datos anteriores(ten en cuenta que tendremos que incluir el parámetro cronosVM en donde corresponda):
```
@Composable
fun ContentHomeView(it:PaddingValues, navController: NavController, cronosVM: CronosViewModel){
Column(
modifier = Modifier.padding(it)
){
val cronosList by cronosVM.cronosList.collectAsState()
LazyColumn {
items(cronosList){item ->
Text(text=item.title)
}
}
}
}
```
Como ves metemos la lista de Cronos y los coleccionamos para mostrarlos en un LazyColumn.
Lo ejecutamos y vemos que efectivamente hay algún registro ya guardado y que podemos visualizarlos sin problemas. Vamos a darle formato.

## Card para mostrar datos
Vamos a bodyComponents y creamo un composable con la card para mostrar los datos.
```
@Composable
fun CronCard(titulo:String, crono: String, onClick:()->Unit){
Box(
modifier= Modifier
.fillMaxWidth()
.padding(horizontal = 10.dp)
.clickable { onClick() }
){
Column (modifier=Modifier
.padding(15.dp)) {
Text(text = titulo,
fontSize = 20.sp,
fontWeight = FontWeight.Bold
)
Row {
Icon(painter = painterResource(R.drawable.crono),
contentDescription ="",
tint=Color.Gray
)
Text(text=crono, fontSize=20.sp)
}
Divider(
modifier=Modifier
.fillMaxWidth()
.height(1.dp),
color= MaterialTheme.colorScheme.primary
)
}
}
}
```
Incluimos el CronCard y el ContentHomeView quedaría como sigue.
```
@Composable
fun ContentHomeView(it:PaddingValues, navController: NavController, cronosVM: CronosViewModel){
Column(
modifier = Modifier.padding(it)
){
val cronosList by cronosVM.cronosList.collectAsState()
LazyColumn {
items(cronosList){item ->
CronCard( item.title, formatTiempo(item.crono ) ){
}
}
}
}
}
```
Fíjense que cada línea es clickable para poder modificarla o continuar el crono en el futuro.
Veamos por lo pronto cómo borrar haciendo swipe.
## Eliminar con Swipe
El swipe hacia los lados muestra un menú que nos permite operar con la fila concreta.
En el listado que pusimos al principio de dependencias se incluyó esta linea:
` // Swipe
implementation ("me.saket.swipe:swipe:1.1.1")
`
Es lo que vamos a usar, aunque si miras en la documentación esto ya ha quedado obsoleto y han actualizado todo en octubre y la parte avanzada de los gestos hace unos días "i can´t with my life!" así que lo dejamos como está:
https://developer.android.com/jetpack/compose/touch-input/pointer-input?hl=en
En la vista necesitamos crear una variable para ejecutar la acción.
Esa variable tiene que estar dentro del items para poder pasar como parámetro la variable que queremos borrar.
Metemos nuestra CronCard dentro de un Composable que es SwipeableActionBox, para configurar ese composable tenemos que tener en cuenta lo siguiente:
```
@Composable
fun ContentHomeView(it:PaddingValues, navController: NavController, cronosVM: CronosViewModel){
Column(
modifier = Modifier.padding(it)
){
val cronosList by cronosVM.cronosList.collectAsState()
LazyColumn {
items(cronosList){item ->
val delete= SwipeAction(
icon= rememberVectorPainter(Icons.Default.Delete),
background = Color.Red,
onSwipe = {cronosVM.deleteCrono(item)}
)
SwipeableActionsBox(endActions = listOf(delete),
swipeThreshold = 270.dp) {
CronCard( item.title, formatTiempo(item.crono ) ){
//navController.navigate("EditView/${item.id}")
}
}
}
}
}
}
```
Prueben para que lo vean, hemos puesto el swipeThreshold más ancho para que tengas que ir hasta la mitad de la pantalla para borrar pero supongo que te das cuenta de lo fácil que es borrar por error.
Ejecuta y borra.

Verás que dentro del CronCard he puesto un navControler comentado para que nos lleve al edit al pulsar (el elemento era clickable!)
Vamos a ver el editar, el único problema es pasarle el id del Crono que queremos editar...seguimos.
## Enviar parámetro para editar
Vamos al navManager e incluimos los componentes que nos hacen falta para la edición y el parámetro en la ruta.
```
composable("EditView/{id}", arguments = listOf(navArgument("id"){type= NavType.LongType})){
val id=it.arguments?.getLong("id")?:0
EditView(navController, cronometroVM,cronosVM, id)
}
```
Al EditView le tenemos que pasar ese id al igual que al resto de componentes que lo requieren.
Para poder recuperar los valores del crono recuperado necesitamos ir al CronometroViewModel e injectar el repository.
Inyectamos el repository y creamos una nueva función, getCronoById:
```
@HiltViewModel
class CronometroViewModel @Inject constructor (private val repository: CronosRepository): ViewModel() {
var state by mutableStateOf(CronoState())
private set
var cronoJob by mutableStateOf<Job?>(null)
private set
var tiempo by mutableStateOf(0L)
private set
fun getCronoById(id:Long){
viewModelScope.launch (Dispatchers.IO) {
repository.getCronoById(id).collect{ item->
tiempo=item.crono
state=state.copy(title=item.title)
}
}
}
```
Y modificamos el EditView como sigue:
```
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun EditView(navController: NavController,
cronometroVM: CronometroViewModel,
cronosVM: CronosViewModel,
id: Long ) {
Scaffold(
topBar = {
CenterAlignedTopAppBar(title = { MainTitle(title = "Edit App") },
colors = TopAppBarDefaults.centerAlignedTopAppBarColors(
containerColor = MaterialTheme.colorScheme.primary
),
navigationIcon ={
MainIconButton(icon = Icons.Default.ArrowBack) {
navController.popBackStack()
}
}
)
}
) {
ContentEditView(it, navController, cronometroVM,cronosVM, id)
}
}
@Composable
fun ContentEditView(it: PaddingValues, navController: NavController,
cronometroVM: CronometroViewModel,
cronosVM: CronosViewModel,
id: Long
){
val state=cronometroVM.state
//si el cronómetro está activo se lanza inmediatamente la función cronos que cuenta el tiempo
LaunchedEffect(state.cronometroActivo ){
cronometroVM.cronos()
}
//en el edit tenemos que hacer que recupere los datos del Crono elegido en el Home
LaunchedEffect(Unit){
cronometroVM.getCronoById(id)
}
Column(
modifier = Modifier
.padding(it)
.padding(top = 30.dp)
.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally
){
Text(text = formatTiempo(cronometroVM.tiempo),
fontSize = 50.sp,
fontWeight = FontWeight.Bold
)
Text(text = id.toString())
Row(horizontalArrangement = Arrangement.Center,
modifier = Modifier.padding(vertical=16.dp)
) {
//iniciar
CircleButton(icon = painterResource(id = R.drawable.play),
enabled=!state.cronometroActivo) {
cronometroVM.iniciar()
}
//pausar
CircleButton(icon = painterResource(id = R.drawable.pause),
enabled=state.cronometroActivo) {
cronometroVM.pausar()
}
}
MainTextField(value =state.title ,
onValueChange = {cronometroVM.onValue(it)},
label ="Title" )
Button(onClick = {
cronosVM.updateCrono(
Cronos(
id=id,
title=state.title,
crono=cronometroVM.tiempo
)
)
navController.popBackStack()
}) {
Text(text = "Editar")
}
DisposableEffect(Unit){
onDispose {
cronometroVM.detener()
}
}
}
}
```