Line data Source code
1 : import 'package:flutter/material.dart'; 2 : import 'package:provider/provider.dart'; 3 : 4 : import '../../providers/movies_provider.dart'; 5 : import '../../widgets/movie_card.dart'; 6 : import '../../widgets/loading_grid.dart'; 7 : 8 : /// Displays a grid of popular movies fetched from the API. 9 : /// 10 : /// The `HomePage` widget presents a list of popular movies in a grid format. 11 : /// It manages several UI states: 12 : /// - **Loading**: Shows a loading grid while movies are being fetched. 13 : /// - **Error**: Displays an error message and a retry button if loading fails. 14 : /// - **Empty**: Informs the user when no popular movies are found. 15 : /// - **Content**: Renders a grid of movies using [MovieCard] widgets, with pull-to-refresh support. 16 : /// 17 : /// The page interacts with [MoviesProvider] to manage state and fetch data: 18 : /// - `popularMovies`: List of popular movies. 19 : /// - `isLoadingPopular`: Indicates if movies are loading. 20 : /// - `popularError`: Error message if loading fails. 21 : /// 22 : /// ### Getters and Setters 23 : /// - No explicit getters/setters in this class; state is accessed via [MoviesProvider]. 24 : /// 25 : /// ### Methods 26 : /// - [build]: Builds the widget tree for the page, handling all UI states. 27 : /// - Refresh: Uses [RefreshIndicator] to allow users to refresh the movie list. 28 : /// 29 : /// ### Usage 30 : /// Place this page in your navigation stack to display and interact with popular movies. 31 : class HomePage extends StatelessWidget { 32 : /// Creates a `HomePage` instance. 33 14 : const HomePage({super.key}); 34 : 35 1 : @override 36 : /// Builds the widget tree for the home page. 37 : /// 38 : /// **Parameters:** 39 : /// - `context` (BuildContext): The build context. 40 : /// 41 : /// **Returns:** 42 : /// - A `Widget` representing the home page. 43 : Widget build(BuildContext context) { 44 1 : return Scaffold( 45 1 : appBar: AppBar( 46 : title: const Text('PelĂculas Populares'), 47 : automaticallyImplyLeading: false, 48 : ), 49 1 : body: Consumer<MoviesProvider>( 50 1 : builder: (context, moviesProvider, child) { 51 : // Loading state 52 1 : if (moviesProvider.isLoadingPopular) { 53 : return const LoadingGrid(); 54 : } 55 : 56 : // Error state 57 1 : if (moviesProvider.popularError != null) { 58 1 : return Center( 59 1 : child: Column( 60 : mainAxisAlignment: MainAxisAlignment.center, 61 1 : children: [ 62 2 : Icon(Icons.error_outline, size: 64, color: Colors.grey[400]), 63 : const SizedBox(height: 16), 64 1 : Text( 65 1 : moviesProvider.popularError!, 66 : textAlign: TextAlign.center, 67 3 : style: Theme.of(context).textTheme.bodyLarge, 68 : ), 69 : const SizedBox(height: 16), 70 1 : ElevatedButton( 71 1 : onPressed: () { 72 1 : moviesProvider.fetchPopularMovies(); 73 : }, 74 : child: const Text('Reintentar'), 75 : ), 76 : ], 77 : ), 78 : ); 79 : } 80 : 81 : // Empty state 82 2 : if (moviesProvider.popularMovies.isEmpty) { 83 : return const Center( 84 : child: Text('No se encontraron pelĂculas populares'), 85 : ); 86 : } 87 : 88 : // Movies grid 89 1 : return RefreshIndicator( 90 2 : onRefresh: () => moviesProvider.refreshPopularMovies(), 91 1 : child: GridView.builder( 92 : padding: const EdgeInsets.all(16), 93 : gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( 94 : crossAxisCount: 2, 95 : childAspectRatio: 0.7, 96 : crossAxisSpacing: 16, 97 : mainAxisSpacing: 16, 98 : ), 99 2 : itemCount: moviesProvider.popularMovies.length, 100 1 : itemBuilder: (context, index) { 101 2 : final movie = moviesProvider.popularMovies[index]; 102 1 : return MovieCard(movie: movie); 103 : }, 104 : ), 105 : ); 106 : }, 107 : ), 108 : ); 109 : } 110 : }