diff --git a/lib/presentation/pages/pokemon_list.dart b/lib/presentation/pages/pokemon_list.dart index adfe454..6bd3dd4 100644 --- a/lib/presentation/pages/pokemon_list.dart +++ b/lib/presentation/pages/pokemon_list.dart @@ -1,95 +1,38 @@ import 'package:flutter/material.dart'; -import '../models/pokemon.dart'; -import '../components/pokemon_tile.dart'; -import '../database/pokedex_database.dart'; -import '../api/pokemon_api.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import '../../domain/entities/pokemon.dart'; +import '../providers/pokedex_provider.dart'; +import '../widgets/pokemon_tile.dart'; -class PokemonListPage extends StatefulWidget { +class PokemonListPage extends ConsumerStatefulWidget { const PokemonListPage({Key? key}) : super(key: key); @override - State createState() => _PokemonListPageState(); + ConsumerState createState() => _PokemonListPageState(); } -class _PokemonListPageState extends State { - String _filter = 'ALL'; // ALL, CAUGHT, NEW - int _caughtCount = 0; - List _allPokemon = []; - List _filteredPokemon = []; - bool _isSyncing = false; +class _PokemonListPageState extends ConsumerState { + String _filter = 'ALL'; // ALL, CAUGHT final ScrollController _scrollController = ScrollController(); - @override - void initState() { - super.initState(); - _loadPokemonData(); - PokedexDatabase.onDatabaseUpdate.addListener(_loadPokemonData); - } - @override void dispose() { - PokedexDatabase.onDatabaseUpdate.removeListener(_loadPokemonData); _scrollController.dispose(); super.dispose(); } - Future _loadPokemonData() async { - setState(() => _isSyncing = true); - - final count = await PokedexDatabase.getCaughtCount(); - - // Check if database needs sync (less than 1025 pokemon) - List localData = await PokedexDatabase.getPokemonList(); - if (localData.length < 1025) { - try { - final List remoteData = await PokemonApi.getAllPokemon(); - // Insert all missing pokemon using batch for performance - await PokedexDatabase.batchInsertPokemon(remoteData); - localData = await PokedexDatabase.getPokemonList(); - } catch (e) { - debugPrint('Sync Error: $e'); - } - } - - // Sort by ID to ensure order - localData.sort((a, b) => a.id.compareTo(b.id)); - - if (mounted) { - setState(() { - _allPokemon = localData; - _caughtCount = count; - _applyFilter(); - _isSyncing = false; - }); - } - } - - void _applyFilter() { - setState(() { - if (_filter == 'ALL') { - _filteredPokemon = _allPokemon; - } else if (_filter == 'CAUGHT') { - _filteredPokemon = _allPokemon.where((p) => p.isCaught).toList(); - } - }); - - // Reset scroll position to top when filter changes - if (_scrollController.hasClients) { - _scrollController.jumpTo(0); - } - } - - Widget _buildPokemonTile(BuildContext context, int index) { - final pokemon = _filteredPokemon[index]; - return PokemonTile(pokemon); + List _applyFilter(List all) { + if (_filter == 'CAUGHT') return all.where((p) => p.isCaught).toList(); + return all; } @override Widget build(BuildContext context) { + final pokedexAsync = ref.watch(pokedexProvider); + final caughtCount = ref.watch(caughtCountProvider); + return Container( - decoration: const BoxDecoration( - color: Color(0xFFC8D1D8), // Silver-ish grey background - ), + decoration: const BoxDecoration(color: Color(0xFFC8D1D8)), child: Column( children: [ // Header @@ -100,10 +43,8 @@ class _PokemonListPageState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Icon(Icons.menu, color: Colors.black87), - Text( - 'LIST - NATIONAL', - style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold, letterSpacing: 2), - ), + Text('LIST - NATIONAL', + style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold, letterSpacing: 2)), Icon(Icons.search, color: Colors.black87), ], ), @@ -119,7 +60,6 @@ class _PokemonListPageState extends State { ], ), ), - // Caught Count Bar Container( padding: const EdgeInsets.symmetric(vertical: 12.0), @@ -130,25 +70,21 @@ class _PokemonListPageState extends State { child: Column( children: [ Text( - '${_caughtCount.toString().padLeft(3, '0')} / ${_allPokemon.length}', + '${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), - ), + const Text('POKEMON DISCOVERED', + style: TextStyle(fontSize: 14, color: Colors.black54, letterSpacing: 1)), ], ), ), - // The List Expanded( child: Stack( children: [ - // Scanlines effect Positioned.fill( child: ListView.builder( - itemCount: 100, // drawing artificial scanlines + itemCount: 100, physics: const NeverScrollableScrollPhysics(), itemBuilder: (context, index) => Container( height: 4, @@ -157,42 +93,47 @@ class _PokemonListPageState extends State { ), ), ), - if (_isSyncing && _allPokemon.isEmpty) - const Center(child: CircularProgressIndicator()) - else if (_filteredPokemon.isEmpty) - 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), - ), - ], - ), - ) - else - ListView.builder( - controller: _scrollController, - padding: const EdgeInsets.all(12), - itemCount: _filteredPokemon.length, - itemBuilder: _buildPokemonTile, + 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)), ), + 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)), + ], + ), + ); + } + return ListView.builder( + controller: _scrollController, + padding: const EdgeInsets.all(12), + itemCount: filtered.length, + itemBuilder: (context, index) => PokemonTile(filtered[index]), + ); + }, + ), ], ), ), - // Footer Container( height: 24, color: const Color(0xFF1B2333), alignment: Alignment.center, - child: const Text( - 'NATIONAL POKEDEX V2.0', - style: TextStyle(color: Colors.white70, fontSize: 12, letterSpacing: 1), - ), + child: const Text('NATIONAL POKEDEX V2.0', + style: TextStyle(color: Colors.white70, fontSize: 12, letterSpacing: 1)), ), ], ), @@ -204,26 +145,23 @@ class _PokemonListPageState extends State { child: GestureDetector( onTap: () { if (_filter != title) { - _filter = title; - _applyFilter(); + setState(() => _filter = title); + if (_scrollController.hasClients) _scrollController.jumpTo(0); } }, child: Container( decoration: BoxDecoration( color: isSelected ? const Color(0xFFB0BEC5) : Colors.transparent, - border: isSelected ? const Border( - bottom: BorderSide(color: Color(0xFFD32F2F), width: 3), - ) : null, + border: isSelected + ? const Border(bottom: BorderSide(color: Color(0xFFD32F2F), width: 3)) + : null, ), alignment: Alignment.center, - child: Text( - title, - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: isSelected ? Colors.black : Colors.black54, - ), - ), + child: Text(title, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: isSelected ? Colors.black : Colors.black54)), ), ), );