init projet

This commit is contained in:
Guillaume Vern
2026-01-16 14:50:38 +01:00
parent 596870f278
commit 570df27bea
136 changed files with 5241 additions and 2 deletions
+79
View File
@@ -0,0 +1,79 @@
import 'package:flutter/material.dart';
import '../models/pokemon.dart';
import '../components/pokemon_type.dart';
// Vue détail d'un Pokémon. Elle est appelée par la route "/pokemon-detail". Elle prend en paramètre un Pokémon.
// Elle affiche l'image du Pokémon, son nom, son numéro et ses types. Elle permet également de passer en mode shiny.
// Elle hérite de la classe StatefulWidget car elle a besoin de gérer un état (le mode shiny).
class PokemonDetailPage extends StatefulWidget {
const PokemonDetailPage({Key? key}) : super(key: key);
@override
State<PokemonDetailPage> createState() => _PokemonDetailPageState();
}
// La classe _PokemonDetailPageState hérite de la classe State. Elle permet de gérer l'état de la page.
// Elle contient une variable _isShiny qui permet de savoir si le mode shiny est activé ou non.
class _PokemonDetailPageState extends State<PokemonDetailPage> {
// Variable qui permet de savoir si le mode shiny est activé ou non
bool _isShiny = false;
@override
Widget build(BuildContext context) {
// On récupère le Pokémon passé en paramètre de la route
final Pokemon pokemon = ModalRoute.of(context)!.settings.arguments as Pokemon;
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Le GestureDetector va permettre de détecter un tap sur l'image du Pokémon
GestureDetector(
// L'image du Pokémon est une image en ligne. On utilise donc Image.network
// On utilise la variable _isShiny pour savoir si on affiche l'image normale ou l'image shiny
child: Image.network(_isShiny ? pokemon.shinyImageUrl : pokemon.imageUrl, width: 200),
onTap:() {
// Lorsqu'on tap sur l'image, on change la valeur de la variable _isShiny
// Cela va permettre de changer l'image affichée
// On utilise la méthode setState pour dire à Flutter que la valeur de la variable a changé
setState(() {
_isShiny = !_isShiny;
});
},
),
const SizedBox(height: 20),
RichText(
text: TextSpan(
text: pokemon.formatedName, // formatedName est une propriété calculée du modèle Pokemon
style: const TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
color: Colors.black,
),
children: [
TextSpan(
text: " #${pokemon.id.toString().padLeft(4, "0")}",
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.normal,
color: Colors.black,
),
),
],
),
),
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
PokemonTypeWidget(pokemon.type1),
pokemon.type2 != null ? PokemonTypeWidget(pokemon.type2!) : Container(),
],
)
]
)
),
);
}
}
+69
View File
@@ -0,0 +1,69 @@
import 'package:flutter/material.dart';
import '../models/pokemon.dart';
import '../components/pokemon_tile.dart';
import 'package:flutter/foundation.dart' show kIsWeb; // Platform is not supported on web
// Page de la liste des pokémons. Elle est appelée par la route "/". Elle affiche la liste des 151 premiers pokémons.
// Elle hérite de la classe StatefulWidget car elle a besoin de gérer un état (la liste des pokémons).
class PokemonListPage extends StatefulWidget {
const PokemonListPage({Key? key}) : super(key: key);
@override
State<PokemonListPage> createState() => _PokemonListPageState();
}
class _PokemonListPageState extends State<PokemonListPage> {
Widget _buildPokemonTile(BuildContext context, int index) {
// On utilise un FutureBuilder pour afficher un pokémon à partir de son ID. L'index commençant à 0, on ajoute 1 pour le numéro du pokémon.
// Le FutureBuilder va permettre d'afficher un widget en fonction de l'état du Future
// Le FutureBuilder prend en paramètre un Future (ici Pokemon.fromID(index + 1))
// Il prend aussi en paramètre une fonction qui va permettre de construire le widget en fonction de l'état du Future : builder: (context, snapshot) {}
return FutureBuilder(
builder: (context, snapshot) {
if (snapshot.hasData) {
// Si le Future a réussi à récupérer les données, on affiche le widget PokemonTile
if (snapshot.data == null) {
return Text('Error while fetching pokemon #${index + 1}');
}
return PokemonTile(snapshot.data as Pokemon);
} else if (snapshot.hasError) {
// Si le Future a échoué à récupérer les données, on affiche un message d'erreur
print(snapshot.error);
return const Text('Erreur : ');
} else {
// Si le Future n'a pas encore récupéré les données, on affiche un widget de chargement
return Container(
alignment: Alignment.center,
padding: const EdgeInsets.all(10),
child: const CircularProgressIndicator(),
);
}
},
future: Pokemon.fromID(index + 1),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Liste des pokémons'),
),
body: Center(
child: GridView.builder(
// Le GridView permet d'afficher une liste de widgets sous forme de grille
// On utilise le constructeur GridView.builder pour construire la grille
// Le GridView.builder prend en paramètre un itemCount qui correspond au nombre d'éléments à afficher
// Il prend aussi en paramètre un itemBuilder qui va permettre de construire chaque élément de la grille
// Le GridView.builder prend aussi en paramètre un gridDelegate qui va permettre de définir le nombre de colonnes de la grille
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: kIsWeb ? 4 : 2, // On affiche 4 colonnes sur le web et 2 colonnes sur mobile
),
itemCount: 151, // On pourrait en mettre plus mais on va se limiter aux 151 premiers pokémons
itemBuilder: _buildPokemonTile,
)
),
);
}
}