import 'package:flutter/material.dart'; import '../models/movie.dart'; import '../services/api_service.dart'; import 'movie_detail_page.dart'; import 'favorites_page.dart'; class HomePage extends StatefulWidget { const HomePage({super.key}); @override State createState() => _HomePageState(); } class _HomePageState extends State { List categories = [ const MovieCategory(name: "TOUS", isSelected: true), const MovieCategory(name: "POPULAIRES"), const MovieCategory(name: "MIEUX NOTÉS"), const MovieCategory(name: "EN COURS"), const MovieCategory(name: "PROCHAINEMENT"), ]; List movies = []; bool isLoading = true; String? errorMessage; int currentFeaturedIndex = 0; int _currentIndex = 1; @override void initState() { super.initState(); _loadMovies(); } Future _loadMovies() async { try { setState(() { isLoading = true; errorMessage = null; }); final popularMovies = await ApiService.getPopularMovies(); setState(() { movies = popularMovies; if (movies.isNotEmpty) { movies[0] = Movie( id: movies[0].id, title: movies[0].title, description: movies[0].description, imageUrl: movies[0].imageUrl, category: movies[0].category, director: movies[0].director, releaseDate: movies[0].releaseDate, isFeatured: true, rating: movies[0].rating, originalTitle: movies[0].originalTitle, ); } isLoading = false; }); } catch (e) { setState(() { errorMessage = e.toString(); isLoading = false; }); } } @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, home: Scaffold( backgroundColor: Colors.black, appBar: AppBar( backgroundColor: Colors.purple, centerTitle: true, toolbarHeight: 80, title: const Text( "MOVIES", style: TextStyle( fontSize: 32, fontWeight: FontWeight.bold, letterSpacing: 3, color: Colors.white, ), ), ), body: _getBody(), bottomNavigationBar: _buildBottomNav(), ), ); } Widget _buildBody() { if (isLoading) { return const Center( child: CircularProgressIndicator( color: Colors.purple, ), ); } if (errorMessage != null) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon( Icons.error_outline, color: Colors.red, size: 64, ), const SizedBox(height: 16), Text( 'Erreur de chargement', style: const TextStyle( color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 8), Text( errorMessage!, style: TextStyle( color: Colors.grey[400], fontSize: 14, ), textAlign: TextAlign.center, ), const SizedBox(height: 16), ElevatedButton( onPressed: _loadMovies, style: ElevatedButton.styleFrom( backgroundColor: Colors.purple, foregroundColor: Colors.white, ), child: const Text('Réessayer'), ), ], ), ); } return Column( children: [ _buildCategoryBar(), Expanded( child: ListView( children: [ if (movies.isNotEmpty) ...[ _buildFeaturedMovie(), _buildFeaturedIndicators(), ], ...movies.skip(5).map((movie) => _buildMovieItem(movie)), ], ), ), ], ); } Widget _buildCategoryBar() { return Container( height: 50, color: Colors.black, child: ListView.builder( scrollDirection: Axis.horizontal, itemCount: categories.length, itemBuilder: (context, index) { final isSelected = index == 0; return Container( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), child: Text( categories[index].name, style: TextStyle( color: isSelected ? Colors.white : Colors.grey, fontSize: 16, fontWeight: isSelected ? FontWeight.bold : FontWeight.normal, ), ), ); }, ), ); } Widget _getBody() { switch (_currentIndex) { case 0: return const FavoritesPage(); case 1: return _buildBody(); case 2: return _buildProfilePage(); default: return _buildBody(); } } Widget _buildProfilePage() { return Container( color: Colors.black, child: const Center( child: Text( 'Profil', style: TextStyle( color: Colors.white, fontSize: 24, fontWeight: FontWeight.bold, ), ), ), ); } Widget _buildBottomNav() { return BottomNavigationBar( backgroundColor: Colors.white, selectedItemColor: Colors.purple, unselectedItemColor: Colors.grey, currentIndex: _currentIndex, onTap: (index) { setState(() { _currentIndex = index; }); }, items: const [ BottomNavigationBarItem(icon: Icon(Icons.favorite), label: 'Favoris'), BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Accueil'), BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Profil'), ], ); } Widget _buildFeaturedMovie() { final featuredMovies = movies.take(5).toList(); return Container( height: 300, margin: const EdgeInsets.all(16), child: PageView.builder( onPageChanged: (index) { setState(() { currentFeaturedIndex = index; }); }, itemCount: featuredMovies.length, itemBuilder: (context, index) { final movie = featuredMovies[index]; return Container( margin: const EdgeInsets.symmetric(horizontal: 4), decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), color: Colors.grey[800], ), child: Stack( children: [ _buildMovieImage(movie.imageUrl, 12, movie: movie), _buildGradientOverlay(), _buildMovieDetails(movie), _buildPlayButton(50, 30), ], ), ); }, ), ); } Widget _buildMovieItem(Movie movie) { return Container( margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.grey[900], borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.grey[800]!, width: 1), ), child: Row( children: [ _buildMoviePoster(movie), const SizedBox(width: 16), Expanded(child: _buildMovieInfo(movie)), _buildSimplePlayButton(40, 24), ], ), ); } Widget _buildMoviePoster(Movie movie) { return Container( width: 80, height: 80, decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), color: Colors.grey[700], ), child: _buildMovieImage(movie.imageUrl, 8, movie: movie), ); } Widget _buildMovieInfo(Movie movie) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(movie.title, style: const TextStyle(color: Colors.white, fontSize: 16, fontWeight: FontWeight.bold)), const SizedBox(height: 4), Row( children: [ Icon(Icons.star, color: Colors.amber, size: 14), const SizedBox(width: 4), Text(movie.rating.toStringAsFixed(1), style: TextStyle(color: Colors.amber, fontSize: 12, fontWeight: FontWeight.w500)), const SizedBox(width: 8), Text(movie.category, style: TextStyle(color: Colors.purple[300], fontSize: 12, fontWeight: FontWeight.w500)), ], ), const SizedBox(height: 4), Text(movie.description, style: TextStyle(color: Colors.grey[400], fontSize: 12), maxLines: 2, overflow: TextOverflow.ellipsis), const SizedBox(height: 4), Text(movie.releaseDate, style: TextStyle(color: Colors.grey[500], fontSize: 10)), ], ); } Widget _buildMovieImage(String imageUrl, double radius, {Movie? movie}) { return GestureDetector( onTap: movie != null ? () => _navigateToMovieDetail(movie) : null, child: ClipRRect( borderRadius: BorderRadius.circular(radius), child: imageUrl.isNotEmpty ? Image.network( imageUrl, width: radius == 12 ? double.infinity : 80, height: radius == 12 ? double.infinity : 80, fit: BoxFit.cover, errorBuilder: (context, error, stackTrace) => _buildFallbackImage(radius), loadingBuilder: (context, child, loadingProgress) { if (loadingProgress == null) return child; return Container( width: radius == 12 ? double.infinity : 80, height: radius == 12 ? double.infinity : 80, decoration: BoxDecoration( borderRadius: BorderRadius.circular(radius), color: Colors.grey[800], ), child: const Center( child: CircularProgressIndicator( color: Colors.purple, strokeWidth: 2, ), ), ); }, ) : _buildFallbackImage(radius), ), ); } Widget _buildFallbackImage(double radius) { return Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(radius), gradient: LinearGradient( colors: radius == 12 ? [Colors.blue[900]!, Colors.purple[900]!] : [Colors.grey[600]!, Colors.grey[800]!], ), ), child: Center( child: Icon(Icons.movie, color: Colors.white, size: radius == 12 ? 50 : 30), ), ); } Widget _buildGradientOverlay() { return Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [Colors.transparent, Colors.black.withOpacity(0.7)], ), ), ); } Widget _buildMovieDetails(Movie movie) { return Positioned( left: 20, bottom: 20, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("FILM POPULAIRE", style: TextStyle(color: Colors.white.withOpacity(0.8), fontSize: 12)), const SizedBox(height: 4), Text(movie.category.toUpperCase(), style: TextStyle(color: Colors.purple[300], fontSize: 16, fontWeight: FontWeight.bold)), const SizedBox(height: 8), Text(movie.title, style: const TextStyle(color: Colors.white, fontSize: 32, fontWeight: FontWeight.bold)), Row( children: [ const Icon(Icons.star, color: Colors.amber, size: 16), const SizedBox(width: 4), Text("${movie.rating.toStringAsFixed(1)}/10", style: const TextStyle(color: Colors.white, fontSize: 16)), ], ), const SizedBox(height: 8), Text(movie.releaseDate, style: TextStyle(color: Colors.white.withOpacity(0.8), fontSize: 12)), ], ), ); } Widget _buildPlayButton(double size, double iconSize) { return Positioned( right: 20, bottom: 20, child: Container( width: size, height: size, decoration: const BoxDecoration(color: Colors.red, shape: BoxShape.circle), child: Icon(Icons.play_arrow, color: Colors.white, size: iconSize), ), ); } Widget _buildSimplePlayButton(double size, double iconSize) { return Container( width: size, height: size, decoration: const BoxDecoration(color: Colors.red, shape: BoxShape.circle), child: Icon(Icons.play_arrow, color: Colors.white, size: iconSize), ); } Widget _buildFeaturedIndicators() { final featuredCount = movies.take(5).length; return Container( height: 20, margin: const EdgeInsets.symmetric(vertical: 8), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: List.generate( featuredCount, (index) => Container( margin: const EdgeInsets.symmetric(horizontal: 4), width: 8, height: 8, decoration: BoxDecoration( shape: BoxShape.circle, color: index == currentFeaturedIndex ? Colors.purple : Colors.grey.withOpacity(0.5), ), ), ), ), ); } void _navigateToMovieDetail(Movie movie) { Navigator.push( context, MaterialPageRoute( builder: (context) => MovieDetailPage(movie: movie), ), ); } }