Transformar una pantalla estática en una dinámica es uno de los pasos más importantes cuando construyes aplicaciones en Flutter. Aquí se aborda cómo convertir un stateless widget en un stateful widget, crear un sistema completo de favoritos con su pestaña dedicada y conectar todo mediante un provider que gestiona las llamadas HTTP para agregar y eliminar recetas de la lista de favoritos.
¿Cómo crear la pestaña y pantalla de favoritos?
El primer paso consiste en agregar un nuevo tab en el archivo main. Se incluye un ícono y un texto representativo, y dentro del TabBarView se agrega la nueva pantalla de recetas favoritas [01:00].
La pantalla de favoritos inicialmente es una clase estática sencilla, con widgets básicos que permiten diferenciarla de la sección home. Lo importante es que esta estructura servirá como contenedor para listar dinámicamente las recetas marcadas como favoritas.
¿Cómo funciona el toggle de favoritos en el provider?
Dentro del provider se crea una función asíncrona llamada toggleFavoriteStatus que recibe una receta como parámetro [01:30]. Esta función determina si la receta ya es favorita mediante el método contains sobre la lista de recetas favoritas.
- Se define una variable
isFavorite que verifica si la receta existe en favoriteRecipes.
- Se configuran dos rutas HTTP: un post para agregar y un delete para eliminar de favoritos.
- La URL apunta al path de favoritos en lugar del de recetas.
El flujo condicional funciona así [03:15]:
- Si
isFavorite es true, se ejecuta un await http.delete enviando el id de la receta en el body como JSON.
- Si es
false, se ejecuta un await http.post enviando recipe.toJson() con toda la información de la receta.
Es fundamental que el modelo de receta incluya el campo id como string. Esto se agrega tanto en el constructor del modelo marcándolo como requerido, como en el método toJson [04:00].
¿Cómo se maneja la respuesta y los errores?
Se evalúa el response.statusCode. Si la respuesta es 200 (exitosa), se actualiza la lista: se remueve la receta si ya era favorita o se agrega si no lo era. Después se llama a notifyListeners() para que los widgets que escuchan el provider se actualicen [05:10].
El manejo de excepciones se implementa en el bloque catch, donde se imprime un mensaje descriptivo como "error al actualizar el estado de la receta" junto con el error capturado.
¿Cómo convertir el detalle de receta en un stateful widget?
Para soportar cambios de estado dinámicos, el detalle de recetas pasa de ser un stateless widget a un stateful widget [06:15]. La clase principal recibe el modelo de receta a través de su constructor con la propiedad recipesData marcada como requerida.
- Se crea la clase de estado correspondiente que contiene una variable booleana
isFavorite inicializada en false.
- En el método
didChangeDependencies se conecta con el provider usando Provider.of<RecipesProvider>(context, listen: false) para escuchar los cambios en favoriteRecipes [07:45].
- Se verifica si la receta actual está contenida en la lista de favoritos del provider.
¿Cómo implementar el botón de favoritos con IconButton?
En el AppBar del detalle se agrega un IconButton dentro de la propiedad actions [09:00]:
- Se usa una condicional ternaria sobre
isFavorite.
- Si es
true, se muestra Icons.favorite (corazón relleno).
- Si es
false, se muestra Icons.favorite_border (solo el borde).
El onPressed ejecuta una llamada asíncrona al provider:
dart
await Provider.of<RecipesProvider>(context, listen: false)
.toggleFavoriteStatus(widget.recipesData);
setState(() {
isFavorite = !isFavorite;
});
El setState actualiza la interfaz cambiando el estado del ícono cada vez que se presiona el botón [10:30].
¿Cómo listar las recetas favoritas con un ListView builder?
En la pantalla de favoritos se reemplaza el contenido estático por un Consumer del provider [12:00]. Se extrae la lista favoriteRecipes y se valida con isEmpty:
- Si está vacía, se muestra un texto indicando "no favorites recipes".
- Si contiene datos, se construye un
ListView.builder con itemCount igual a favoriteRecipes.length.
Cada elemento se renderiza con una tarjeta personalizada llamada FavoriteRecipesCard, un stateless widget que recibe la receta y muestra nombre y autor [13:30]. Al hacer tap sobre la tarjeta, un GestureDetector ejecuta Navigator.push hacia la pantalla de detalle pasando la receta correspondiente mediante MaterialPageRoute.
dart
ListView.builder(
itemCount: favoriteRecipes.length,
itemBuilder: (context, index) {
final recipe = favoriteRecipes[index];
return FavoriteRecipesCard(recipe: recipe);
},
);
Con esta implementación, la aplicación gestiona el estado de favoritos de forma reactiva: el provider centraliza la lógica de negocio, el stateful widget responde a los cambios y la lista se actualiza automáticamente. Si lograste implementar todo el flujo, comparte cómo personalizaste tus tarjetas de favoritos.