LCOV - code coverage report
Current view: top level - app\presentation\pages\favorites\favorites_page.dart - favorites_page.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 51 51 100.0 %
Date: Wed Aug 6 23:43:55 2025 Functions: 0 0 -

          Line data    Source code
       1             : import 'package:flutter/material.dart';
       2             : import 'package:provider/provider.dart';
       3             : 
       4             : import '../../providers/favorites_provider.dart';
       5             : import '../../widgets/movie_card.dart';
       6             : 
       7             : /// Displays the user's favorite movies in a grid layout.
       8             : ///
       9             : /// The `FavoritesPage` widget presents a list of movies that the user has marked as favorites.
      10             : /// It manages several UI states:
      11             : /// - **Loading**: Shows a loading indicator while favorites are being fetched.
      12             : /// - **Error**: Displays an error message and a retry button if loading fails.
      13             : /// - **Empty**: Informs the user when there are no favorites and encourages adding some.
      14             : /// - **Content**: Renders a grid of favorite movies using [MovieCard] widgets.
      15             : ///
      16             : /// The page also provides an option to clear all favorites via an AppBar action, which triggers a confirmation dialog.
      17             : ///
      18             : /// ### Getters and Setters
      19             : /// - The class itself does not define explicit getters/setters, but relies on [FavoritesProvider] for state management.
      20             : /// - UI state and favorite movies are accessed through the provider's properties:
      21             : ///   - `favoriteMovies`: List of favorite movies.
      22             : ///   - `isLoading`: Indicates if the favorites are loading.
      23             : ///   - `error`: Error message if loading fails.
      24             : ///   - `isEmpty`: True if there are no favorites.
      25             : ///
      26             : /// ### Methods
      27             : /// - [_showClearAllDialog]: Shows a confirmation dialog to clear all favorites.
      28             : /// - [build]: Builds the widget tree for the page, handling all UI states.
      29             : ///
      30             : /// ### Usage
      31             : /// Place this page in your navigation stack to allow users to view and manage their favorite movies.
      32             : class FavoritesPage extends StatelessWidget {
      33             :   /// Creates a `FavoritesPage` instance.
      34          14 :   const FavoritesPage({super.key});
      35             : 
      36           1 :   @override
      37             :   /// Builds the widget tree for the favorites page.
      38             :   ///
      39             :   /// **Parameters:**
      40             :   /// - `context` (BuildContext): The build context.
      41             :   ///
      42             :   /// **Returns:**
      43             :   /// - A `Widget` representing the favorites page.
      44             :   Widget build(BuildContext context) {
      45           1 :     return Scaffold(
      46           1 :       appBar: AppBar(
      47             :         title: const Text('Favoritos'),
      48             :         automaticallyImplyLeading: false,
      49           1 :         actions: [
      50           1 :           Consumer<FavoritesProvider>(
      51           1 :             builder: (context, favoritesProvider, child) {
      52           2 :               if (favoritesProvider.favoriteMovies.isNotEmpty) {
      53           1 :                 return IconButton(
      54             :                   icon: const Icon(Icons.delete_sweep),
      55           2 :                   onPressed: () => _showClearAllDialog(context),
      56             :                 );
      57             :               }
      58             :               return const SizedBox.shrink();
      59             :             },
      60             :           ),
      61             :         ],
      62             :       ),
      63           1 :       body: Consumer<FavoritesProvider>(
      64           1 :         builder: (context, favoritesProvider, child) {
      65             :           // Loading state
      66           1 :           if (favoritesProvider.isLoading) {
      67             :             return const Center(child: CircularProgressIndicator());
      68             :           }
      69             : 
      70             :           // Error state
      71           1 :           if (favoritesProvider.error != null) {
      72           1 :             return Center(
      73           1 :               child: Column(
      74             :                 mainAxisAlignment: MainAxisAlignment.center,
      75           1 :                 children: [
      76           2 :                   Icon(Icons.error_outline, size: 64, color: Colors.grey[400]),
      77             :                   const SizedBox(height: 16),
      78           1 :                   Text(
      79           1 :                     favoritesProvider.error!,
      80             :                     textAlign: TextAlign.center,
      81           3 :                     style: Theme.of(context).textTheme.bodyLarge,
      82             :                   ),
      83             :                   const SizedBox(height: 16),
      84           1 :                   ElevatedButton(
      85           1 :                     onPressed: () {
      86           1 :                       favoritesProvider.refreshFavorites();
      87             :                     },
      88             :                     child: const Text('Reintentar'),
      89             :                   ),
      90             :                 ],
      91             :               ),
      92             :             );
      93             :           }
      94             : 
      95             :           // Empty state
      96           1 :           if (favoritesProvider.isEmpty) {
      97           1 :             return Center(
      98           1 :               child: Column(
      99             :                 mainAxisAlignment: MainAxisAlignment.center,
     100           1 :                 children: [
     101           1 :                   Icon(
     102             :                     Icons.favorite_border,
     103             :                     size: 64,
     104           1 :                     color: Colors.grey[400],
     105             :                   ),
     106             :                   const SizedBox(height: 16),
     107           1 :                   Text(
     108             :                     'No tienes favoritos aún',
     109           1 :                     style: Theme.of(
     110             :                       context,
     111           4 :                     ).textTheme.titleLarge?.copyWith(color: Colors.grey[600]),
     112             :                   ),
     113             :                   const SizedBox(height: 8),
     114           1 :                   Text(
     115             :                     'Explora películas y agrega las que más te gusten',
     116             :                     textAlign: TextAlign.center,
     117           3 :                     style: Theme.of(context).textTheme.bodyMedium,
     118             :                   ),
     119             :                 ],
     120             :               ),
     121             :             );
     122             :           }
     123             : 
     124             :           // Favorites grid
     125           1 :           return GridView.builder(
     126             :             padding: const EdgeInsets.all(16),
     127             :             gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
     128             :               crossAxisCount: 2,
     129             :               childAspectRatio: 0.7,
     130             :               crossAxisSpacing: 16,
     131             :               mainAxisSpacing: 16,
     132             :             ),
     133           2 :             itemCount: favoritesProvider.favoriteMovies.length,
     134           1 :             itemBuilder: (context, index) {
     135           2 :               final movie = favoritesProvider.favoriteMovies[index];
     136           1 :               return MovieCard(movie: movie);
     137             :             },
     138             :           );
     139             :         },
     140             :       ),
     141             :     );
     142             :   }
     143             : 
     144           1 :   void _showClearAllDialog(BuildContext context) {
     145           1 :     showDialog(
     146             :       context: context,
     147           1 :       builder: (BuildContext context) {
     148           1 :         return AlertDialog(
     149             :           title: const Text('Limpiar favoritos'),
     150             :           content: const Text(
     151             :             '¿Estás seguro de que quieres eliminar todos los favoritos?',
     152             :           ),
     153           1 :           actions: [
     154           1 :             TextButton(
     155           3 :               onPressed: () => Navigator.of(context).pop(),
     156             :               child: const Text('Cancelar'),
     157             :             ),
     158           1 :             TextButton(
     159           1 :               onPressed: () {
     160           2 :                 context.read<FavoritesProvider>().clearAllFavorites();
     161           2 :                 Navigator.of(context).pop();
     162             :               },
     163             :               child: const Text('Eliminar'),
     164             :             ),
     165             :           ],
     166             :         );
     167             :       },
     168             :     );
     169             :   }
     170             : }

Generated by: LCOV version 1.15.alpha0w