import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../domain/game/game_state.dart'; import '../providers/game_provider.dart'; import '../providers/navigation_provider.dart'; import '../widgets/pokemon_image.dart'; class GuessPage extends ConsumerStatefulWidget { const GuessPage({Key? key}) : super(key: key); @override ConsumerState createState() => _GuessPageState(); } class _GuessPageState extends ConsumerState { final TextEditingController _guessController = TextEditingController(); bool _started = false; @override void initState() { super.initState(); // Démarre la partie après le premier frame (le provider est prêt). WidgetsBinding.instance.addPostFrameCallback((_) { if (!_started) { _started = true; ref.read(gameProvider.notifier).startNewGame(); } }); } @override void dispose() { _guessController.dispose(); super.dispose(); } Future _onGuess() async { final result = await ref.read(gameProvider.notifier).submitGuess(_guessController.text); if (!mounted) return; final state = ref.read(gameProvider); switch (result) { case GuessResult.correct: ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text(state.isShiny ? '✨ SHINY! You caught ${state.currentPokemon!.formatedName}! (+20 pts) ✨' : 'Correct! You caught ${state.currentPokemon!.formatedName}!'), backgroundColor: state.isShiny ? Colors.amber[800] : Colors.green, )); break; case GuessResult.wrong: ScaffoldMessenger.of(context).showSnackBar(const SnackBar( content: Text('Wrong guess! Try again.'), backgroundColor: Colors.orange)); break; case GuessResult.gameOver: await _showGameOver(); break; case GuessResult.invalid: break; } _guessController.clear(); } Future _showGameOver() async { final state = ref.read(gameProvider); final playAgain = await Navigator.pushNamed( context, '/game-over', arguments: { 'pokemonName': state.currentPokemon!.formatedName, 'score': state.currentScore, 'streak': state.sessionCorrectCount, 'pokemonImage': state.currentPokemon!.imageUrl, }, ) as bool?; if (!mounted) return; if (playAgain == true) { await ref.read(gameProvider.notifier).startNewGame(); } else if (playAgain == false) { ref.read(selectedTabProvider.notifier).set(0); // onglet LIST await ref.read(gameProvider.notifier).startNewGame(); } } @override Widget build(BuildContext context) { final state = ref.watch(gameProvider); if (state.status == GameStatus.loading) { return const Center(child: CircularProgressIndicator()); } if (state.currentPokemon == null || state.status == GameStatus.error) { return const Center(child: Text("Error loading Pokémon")); } final pokemon = state.currentPokemon!; final isGuessed = state.status == GameStatus.roundWon; return Container( decoration: const BoxDecoration(color: Color(0xFFC8D1D8)), 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), ), ), ), SingleChildScrollView( child: Column( children: [ // Silhouette screen Container( height: 250, width: double.infinity, margin: const EdgeInsets.all(16), decoration: BoxDecoration( color: const Color(0xFF3B6EE3), borderRadius: BorderRadius.circular(12), border: Border.all(color: const Color(0xFF1B2333), width: 8), ), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( child: Padding( padding: const EdgeInsets.all(16.0), child: isGuessed ? PokemonImage( imageUrl: state.isShiny ? pokemon.shinyImageUrl : pokemon.imageUrl, fallbackUrl: pokemon.imageUrl, fit: BoxFit.contain, ) : PokemonImage( imageUrl: state.isShiny ? pokemon.shinyImageUrl : pokemon.imageUrl, fallbackUrl: pokemon.imageUrl, fit: BoxFit.contain, color: state.isShiny ? Colors.yellow[700]! : Colors.black, colorBlendMode: BlendMode.srcIn, ), ), ), Container( color: const Color(0xFF1B2333), width: double.infinity, padding: const EdgeInsets.symmetric(vertical: 8), child: Text( state.isShiny ? "✨ SHINY POKÉMON DETECTED! ✨" : "WHO'S THAT POKÉMON?", textAlign: TextAlign.center, style: TextStyle( color: state.isShiny ? Colors.yellow[400] : Colors.white, fontSize: state.isShiny ? 18 : 22, fontWeight: FontWeight.bold, letterSpacing: 2, ), ), ) ], ), ), // Lives Row( mainAxisAlignment: MainAxisAlignment.center, children: List.generate(3, (index) { return Icon( index < state.lives ? Icons.favorite : Icons.favorite_border, color: Colors.red, size: 32, ); }), ), const SizedBox(height: 16), // Guess section Padding( padding: const EdgeInsets.symmetric(horizontal: 24.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text("IDENTIFICATION INPUT", style: TextStyle(color: Colors.black54, fontSize: 12, fontWeight: FontWeight.bold)), const SizedBox(height: 4), if (state.isHintUsed) Container( width: double.infinity, margin: const EdgeInsets.only(bottom: 12), padding: const EdgeInsets.symmetric(vertical: 12), decoration: BoxDecoration( color: Colors.amber[100], border: Border.all(color: Colors.amber[600]!, width: 2), borderRadius: BorderRadius.circular(8), ), child: Text( "HINT: ${pokemon.formatedName[0]}${List.filled(pokemon.formatedName.length - 2, '_').join()}${pokemon.formatedName[pokemon.formatedName.length - 1]}", textAlign: TextAlign.center, style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold, color: Colors.amber[900], letterSpacing: 4), ), ), Container( decoration: BoxDecoration( color: Colors.white, border: Border.all(color: Colors.grey[400]!), ), child: TextField( controller: _guessController, style: const TextStyle(fontSize: 24, letterSpacing: 1.5), decoration: const InputDecoration( contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 12), border: InputBorder.none, hintText: 'Enter Pokémon name...', ), onSubmitted: (_) => _onGuess(), ), ), const SizedBox(height: 16), if (isGuessed) SizedBox( width: double.infinity, height: 60, child: ElevatedButton( onPressed: () => ref.read(gameProvider.notifier).loadNextPokemon(), style: ElevatedButton.styleFrom( backgroundColor: Colors.green, shape: const RoundedRectangleBorder(borderRadius: BorderRadius.zero), ), child: const Text("CONTINUE", style: TextStyle(fontSize: 24, color: Colors.white, fontWeight: FontWeight.bold, letterSpacing: 2)), ), ) else ...[ SizedBox( width: double.infinity, height: 60, child: ElevatedButton( onPressed: _onGuess, style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF3B6EE3), shape: const RoundedRectangleBorder(borderRadius: BorderRadius.zero), ), child: const Text("GUESS!", style: TextStyle(fontSize: 24, color: Colors.white, fontWeight: FontWeight.bold, letterSpacing: 2)), ), ), const SizedBox(height: 16), Row( children: [ Expanded( child: ElevatedButton.icon( onPressed: (state.isHintUsed || state.hints <= 0) ? null : () => ref.read(gameProvider.notifier).useHint(), icon: const Icon(Icons.lightbulb, color: Colors.black87), label: Text("HINT (${state.hints})", style: const TextStyle(color: Colors.black87, fontWeight: FontWeight.bold, fontSize: 18)), style: ElevatedButton.styleFrom( backgroundColor: Colors.amber, padding: const EdgeInsets.symmetric(vertical: 16), shape: const RoundedRectangleBorder(borderRadius: BorderRadius.zero), ), ), ), const SizedBox(width: 8), Expanded( child: ElevatedButton.icon( onPressed: state.skips > 0 ? () => ref.read(gameProvider.notifier).useSkip() : null, icon: const Icon(Icons.skip_next, color: Colors.black87), label: Text("SKIP (${state.skips})", style: const TextStyle(color: Colors.black87, fontWeight: FontWeight.bold, fontSize: 18)), style: ElevatedButton.styleFrom( backgroundColor: Colors.grey[400], padding: const EdgeInsets.symmetric(vertical: 16), shape: const RoundedRectangleBorder(borderRadius: BorderRadius.zero), ), ), ), ], ), ], const SizedBox(height: 24), // Score Container( width: double.infinity, padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white.withAlpha(153), border: Border.all(color: Colors.black12), borderRadius: BorderRadius.circular(8), ), child: Column( children: [ const Text("CURRENT SCORE", style: TextStyle(color: Colors.black54, fontSize: 14, fontWeight: FontWeight.bold)), Text("${state.currentScore}", style: const TextStyle(fontSize: 32, fontWeight: FontWeight.bold, color: Color(0xFF3B6EE3))), const Divider(height: 24), Text("PERSONAL BEST: ${state.bestScore}", style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black87)), ], ), ), ], ), ), const SizedBox(height: 32), ], ), ), ], ), ); } }