diff --git a/lib/presentation/pages/pokemon_list.dart b/lib/presentation/pages/pokemon_list.dart index 6bd3dd4..a78b9e9 100644 --- a/lib/presentation/pages/pokemon_list.dart +++ b/lib/presentation/pages/pokemon_list.dart @@ -3,7 +3,11 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../domain/entities/pokemon.dart'; import '../providers/pokedex_provider.dart'; import '../widgets/pokemon_tile.dart'; +import '../widgets/scanline_overlay.dart'; +import '../widgets/list/pokedex_list_header.dart'; +import '../widgets/list/pokedex_count_bar.dart'; +/// Liste du Pokédex national avec filtre ALL / CAUGHT. class PokemonListPage extends ConsumerStatefulWidget { const PokemonListPage({Key? key}) : super(key: key); @@ -35,21 +39,7 @@ class _PokemonListPageState extends ConsumerState { decoration: const BoxDecoration(color: Color(0xFFC8D1D8)), child: Column( children: [ - // Header - Container( - padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 12.0), - color: const Color(0xFF90A4AE), - child: const Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Icon(Icons.menu, color: Colors.black87), - Text('LIST - NATIONAL', - style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold, letterSpacing: 2)), - Icon(Icons.search, color: Colors.black87), - ], - ), - ), - // Tabs + const PokedexListHeader(), Container( color: const Color(0xFF90A4AE), height: 40, @@ -60,62 +50,20 @@ class _PokemonListPageState extends ConsumerState { ], ), ), - // Caught Count Bar - Container( - padding: const EdgeInsets.symmetric(vertical: 12.0), - decoration: const BoxDecoration( - color: Color(0xFFB0BEC5), - border: Border(bottom: BorderSide(color: Color(0xFF78909C), width: 2)), - ), - child: Column( - children: [ - Text( - '${caughtCount.toString().padLeft(3, '0')} / ${pokedexAsync.valueOrNull?.length ?? 0}', - style: const TextStyle(fontSize: 32, fontWeight: FontWeight.bold), - ), - const Text('POKEMON DISCOVERED', - style: TextStyle(fontSize: 14, color: Colors.black54, letterSpacing: 1)), - ], - ), - ), - // The List + PokedexCountBar(caught: caughtCount, total: pokedexAsync.valueOrNull?.length ?? 0), Expanded( child: Stack( children: [ - Positioned.fill( - child: ListView.builder( - itemCount: 100, - physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, index) => Container( - height: 4, - margin: const EdgeInsets.only(bottom: 4), - color: Colors.black.withAlpha(2), - ), - ), - ), + const ScanlineOverlay(), pokedexAsync.when( loading: () => const Center(child: CircularProgressIndicator()), error: (e, _) => Center( child: Text('Erreur de chargement\n$e', - textAlign: TextAlign.center, - style: const TextStyle(color: Colors.black54)), + textAlign: TextAlign.center, style: const TextStyle(color: Colors.black54)), ), data: (all) { final filtered = _applyFilter(all); - if (filtered.isEmpty) { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Icon(Icons.search_off, size: 64, color: Colors.black26), - const SizedBox(height: 16), - Text('NO POKEMON FOUND IN $_filter', - style: const TextStyle( - color: Colors.black45, fontSize: 18, fontWeight: FontWeight.bold)), - ], - ), - ); - } + if (filtered.isEmpty) return _emptyState(); return ListView.builder( controller: _scrollController, padding: const EdgeInsets.all(12), @@ -127,7 +75,6 @@ class _PokemonListPageState extends ConsumerState { ], ), ), - // Footer Container( height: 24, color: const Color(0xFF1B2333), @@ -140,6 +87,20 @@ class _PokemonListPageState extends ConsumerState { ); } + Widget _emptyState() { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon(Icons.search_off, size: 64, color: Colors.black26), + const SizedBox(height: 16), + Text('NO POKEMON FOUND IN $_filter', + style: const TextStyle(color: Colors.black45, fontSize: 18, fontWeight: FontWeight.bold)), + ], + ), + ); + } + Widget _buildTab(String title, bool isSelected) { return Expanded( child: GestureDetector( @@ -159,9 +120,7 @@ class _PokemonListPageState extends ConsumerState { alignment: Alignment.center, child: Text(title, style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: isSelected ? Colors.black : Colors.black54)), + fontSize: 18, fontWeight: FontWeight.bold, color: isSelected ? Colors.black : Colors.black54)), ), ), ); diff --git a/lib/presentation/widgets/list/pokedex_count_bar.dart b/lib/presentation/widgets/list/pokedex_count_bar.dart new file mode 100644 index 0000000..6b50e04 --- /dev/null +++ b/lib/presentation/widgets/list/pokedex_count_bar.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; + +/// Bandeau affichant le nombre de Pokémon découverts sur le total. +class PokedexCountBar extends StatelessWidget { + final int caught; + final int total; + const PokedexCountBar({super.key, required this.caught, required this.total}); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.symmetric(vertical: 12.0), + decoration: const BoxDecoration( + color: Color(0xFFB0BEC5), + border: Border(bottom: BorderSide(color: Color(0xFF78909C), width: 2)), + ), + child: Column( + children: [ + Text( + '${caught.toString().padLeft(3, '0')} / $total', + style: const TextStyle(fontSize: 32, fontWeight: FontWeight.bold), + ), + const Text('POKEMON DISCOVERED', + style: TextStyle(fontSize: 14, color: Colors.black54, letterSpacing: 1)), + ], + ), + ); + } +} diff --git a/lib/presentation/widgets/list/pokedex_list_header.dart b/lib/presentation/widgets/list/pokedex_list_header.dart new file mode 100644 index 0000000..6a7ccde --- /dev/null +++ b/lib/presentation/widgets/list/pokedex_list_header.dart @@ -0,0 +1,23 @@ +import 'package:flutter/material.dart'; + +/// Barre de titre de la liste du Pokédex. +class PokedexListHeader extends StatelessWidget { + const PokedexListHeader({super.key}); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 12.0), + color: const Color(0xFF90A4AE), + child: const Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Icon(Icons.menu, color: Colors.black87), + Text('LIST - NATIONAL', + style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold, letterSpacing: 2)), + Icon(Icons.search, color: Colors.black87), + ], + ), + ); + } +}