init v2 app
This commit is contained in:
parent
5f75c53866
commit
528cdcafef
@ -21,6 +21,6 @@
|
|||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1.0</string>
|
<string>1.0</string>
|
||||||
<key>MinimumOSVersion</key>
|
<key>MinimumOSVersion</key>
|
||||||
<string>12.0</string>
|
<string>13.0</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
# Uncomment this line to define a global platform for your project
|
# Uncomment this line to define a global platform for your project
|
||||||
# platform :ios, '12.0'
|
# platform :ios, '13.0'
|
||||||
|
|
||||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||||
|
|||||||
@ -47,11 +47,11 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/sqlite3_flutter_libs/darwin"
|
:path: ".symlinks/plugins/sqlite3_flutter_libs/darwin"
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
|
||||||
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
|
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
|
||||||
sqlite3: 8d708bc63e9f4ce48f0ad9d6269e478c5ced1d9b
|
sqlite3: 8d708bc63e9f4ce48f0ad9d6269e478c5ced1d9b
|
||||||
sqlite3_flutter_libs: d13b8b3003f18f596e542bcb9482d105577eff41
|
sqlite3_flutter_libs: d13b8b3003f18f596e542bcb9482d105577eff41
|
||||||
|
|
||||||
PODFILE CHECKSUM: 4305caec6b40dde0ae97be1573c53de1882a07e5
|
PODFILE CHECKSUM: 3c63482e143d1b91d2d2560aee9fb04ecc74ac7e
|
||||||
|
|
||||||
COCOAPODS: 1.16.2
|
COCOAPODS: 1.16.2
|
||||||
|
|||||||
@ -453,7 +453,7 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SUPPORTED_PLATFORMS = iphoneos;
|
SUPPORTED_PLATFORMS = iphoneos;
|
||||||
@ -580,7 +580,7 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = YES;
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
@ -629,7 +629,7 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SUPPORTED_PLATFORMS = iphoneos;
|
SUPPORTED_PLATFORMS = iphoneos;
|
||||||
|
|||||||
@ -26,6 +26,7 @@
|
|||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
<MacroExpansion>
|
<MacroExpansion>
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
@ -54,6 +55,7 @@
|
|||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
|
||||||
launchStyle = "0"
|
launchStyle = "0"
|
||||||
useCustomWorkingDirectory = "NO"
|
useCustomWorkingDirectory = "NO"
|
||||||
ignoresPersistentStateOnLaunch = "NO"
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
|||||||
@ -1,13 +1,15 @@
|
|||||||
import '../models/pokemon.dart';
|
import '../models/pokemon.dart';
|
||||||
import '../utils/pokemon_type.dart';
|
import '../utils/pokemon_type.dart';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:flutter/foundation.dart'; // Import for debugPrint
|
||||||
|
|
||||||
// Classe qui permet de récupérer les données des pokémons depuis l'API Tyradex
|
// Classe qui permet de récupérer les données des pokémons depuis l'API Tyradex
|
||||||
// On utilise la librairie http pour effectuer les requêtes
|
// On utilise la librairie http pour effectuer les requêtes
|
||||||
// On utilise la librairie dart:convert pour convertir les données JSON en objet Dart
|
// On utilise la librairie dart:convert pour convertir les données JSON en objet Dart
|
||||||
class PokemonApi {
|
class PokemonApi {
|
||||||
static const String baseUrl = 'tyradex.vercel.app';
|
static const String baseUrl = 'tyradex.app';
|
||||||
static const String pokemonUrl = 'api/v1/pokemon';
|
static const String pokemonUrl = 'api/v1/pokemon';
|
||||||
|
|
||||||
static Future<Pokemon> getPokemon(int id) async {
|
static Future<Pokemon> getPokemon(int id) async {
|
||||||
@ -32,12 +34,74 @@ class PokemonApi {
|
|||||||
? frenchTypeToEnum(types[1]['name'])
|
? frenchTypeToEnum(types[1]['name'])
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
// Récupération des statistiques
|
||||||
|
Map<String, dynamic>? stats = json['stats'];
|
||||||
|
int hp = stats?['hp'] ?? 0;
|
||||||
|
int atk = stats?['atk'] ?? 0;
|
||||||
|
int def = stats?['def'] ?? 0;
|
||||||
|
int spd = stats?['vit'] ?? 0; // 'vit' est la clé pour la vitesse dans tyradex.app
|
||||||
|
|
||||||
|
// Récupération de la description
|
||||||
|
String? description = json['category'];
|
||||||
|
|
||||||
// On crée un objet Pokemon à partir du fichier JSON
|
// On crée un objet Pokemon à partir du fichier JSON
|
||||||
return Pokemon(
|
return Pokemon(
|
||||||
name: name,
|
name: name,
|
||||||
id: id,
|
id: id,
|
||||||
type1: type1,
|
type1: type1,
|
||||||
type2: type2,
|
type2: type2,
|
||||||
|
hp: hp,
|
||||||
|
atk: atk,
|
||||||
|
def: def,
|
||||||
|
spd: spd,
|
||||||
|
description: description,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future<List<Pokemon>> getAllPokemon() async {
|
||||||
|
final response = await http.get(Uri.https(baseUrl, pokemonUrl));
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
List<dynamic> jsonList = jsonDecode(response.body);
|
||||||
|
List<Pokemon> allPokemon = [];
|
||||||
|
|
||||||
|
for (var json in jsonList) {
|
||||||
|
// Skip default tyradex id 0 response which is generic typing
|
||||||
|
if(json['pokedex_id'] == 0) continue;
|
||||||
|
|
||||||
|
try {
|
||||||
|
String name = json['name']['fr'];
|
||||||
|
int id = json['pokedex_id'];
|
||||||
|
List<dynamic> types = json['types'] ?? [];
|
||||||
|
PokemonType type1 = frenchTypeToEnum(types[0]['name']);
|
||||||
|
PokemonType? type2 = types.length > 1 ? frenchTypeToEnum(types[1]['name']) : null;
|
||||||
|
|
||||||
|
Map<String, dynamic>? stats = json['stats'];
|
||||||
|
int hp = stats?['hp'] ?? 0;
|
||||||
|
int atk = stats?['atk'] ?? 0;
|
||||||
|
int def = stats?['def'] ?? 0;
|
||||||
|
int spd = stats?['vit'] ?? 0;
|
||||||
|
|
||||||
|
String? description = json['category'];
|
||||||
|
|
||||||
|
allPokemon.add(Pokemon(
|
||||||
|
name: name,
|
||||||
|
id: id,
|
||||||
|
type1: type1,
|
||||||
|
type2: type2,
|
||||||
|
hp: hp,
|
||||||
|
atk: atk,
|
||||||
|
def: def,
|
||||||
|
spd: spd,
|
||||||
|
description: description,
|
||||||
|
));
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint("Failed parsing pokemon: ${json['name']} - $e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return allPokemon;
|
||||||
|
} else {
|
||||||
|
throw Exception('Failed to load pokemon');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,50 +1,84 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import '../models/pokemon.dart';
|
import '../models/pokemon.dart';
|
||||||
|
|
||||||
// Widget qui permet d'afficher un pokémon
|
class PokemonTile extends StatelessWidget {
|
||||||
// Elle prend en paramètre un pokémon
|
|
||||||
// Elle affiche l'image du pokémon, son nom et son numéro
|
|
||||||
// Elle permet également de naviguer vers la page de détail du pokémon
|
|
||||||
class PokemonTile extends StatefulWidget {
|
|
||||||
const PokemonTile(this.pokemon, {Key? key}) : super(key: key);
|
const PokemonTile(this.pokemon, {Key? key}) : super(key: key);
|
||||||
|
|
||||||
final Pokemon pokemon;
|
final Pokemon pokemon;
|
||||||
|
|
||||||
@override
|
|
||||||
State<PokemonTile> createState() => _PokemonTileState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _PokemonTileState extends State<PokemonTile> {
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
// If not caught, we don't allow navigating to the detail page (to force guessing)
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: pokemon.isCaught ? () {
|
||||||
// Lorsqu'on tap sur le widget, on navigue vers la page de détail du pokémon
|
Navigator.pushNamed(context, "/pokemon-detail", arguments: pokemon);
|
||||||
// On utilise la méthode Navigator.pushNamed pour naviguer vers la page de détail
|
} : null,
|
||||||
// On passe en paramètre du Navigator le contexte et la route de la page de détail
|
|
||||||
// on utilise "widget.pokemon" pour accéder au pokémon passé en paramètre; widget représente l'instance de la classe PokemonTile
|
|
||||||
Navigator.pushNamed(context, "/pokemon-detail", arguments: widget.pokemon);
|
|
||||||
},
|
|
||||||
child: Container(
|
child: Container(
|
||||||
height: 150,
|
height: 80,
|
||||||
margin: const EdgeInsets.all(10),
|
margin: const EdgeInsets.only(bottom: 12),
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border.all(color: Colors.black),
|
color: const Color(0xFFE2EBF0), // lighter grey for tile surface
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(4),
|
||||||
|
border: Border.all(color: Colors.white, width: 2),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black.withAlpha(25),
|
||||||
|
blurRadius: 2,
|
||||||
|
offset: const Offset(2, 2),
|
||||||
|
)
|
||||||
|
]
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.all(10),
|
child: Row(
|
||||||
child: Center(
|
children: [
|
||||||
child: Column(
|
// Image box
|
||||||
children: [
|
Container(
|
||||||
Image.network(widget.pokemon.imageUrl, height: 100),
|
width: 60,
|
||||||
Text(widget.pokemon.formatedName,
|
height: 60,
|
||||||
style: const TextStyle(
|
decoration: BoxDecoration(
|
||||||
fontWeight: FontWeight.bold,
|
color: pokemon.isCaught ? const Color(0xFF78909C) : Colors.grey[700],
|
||||||
fontSize: 16
|
border: Border.all(color: Colors.white, width: 2),
|
||||||
),
|
borderRadius: BorderRadius.circular(4),
|
||||||
),
|
),
|
||||||
],
|
child: pokemon.isCaught
|
||||||
)
|
? Image.network(pokemon.imageUrl, fit: BoxFit.contain)
|
||||||
|
: const SizedBox.expand(),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
|
||||||
|
// Name texts
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'No. ${pokemon.id.toString().padLeft(3, '0')}',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.grey[600],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
Text(
|
||||||
|
pokemon.isCaught ? pokemon.formatedName.toUpperCase() : '???',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 22,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: pokemon.isCaught ? Colors.black87 : Colors.grey[500],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// Caught check icon
|
||||||
|
if (pokemon.isCaught)
|
||||||
|
const Icon(Icons.check_circle, color: Colors.green, size: 28)
|
||||||
|
else
|
||||||
|
Icon(Icons.help, color: Colors.grey[400], size: 24),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -7,10 +7,16 @@ class PokedexDatabase {
|
|||||||
static Future<void> initDatabase() async {
|
static Future<void> initDatabase() async {
|
||||||
database = await openDatabase(
|
database = await openDatabase(
|
||||||
"pokedex.db", // Nom de la base de données
|
"pokedex.db", // Nom de la base de données
|
||||||
version: 1, // Version de la base de données, permet de gérer les migrations
|
version: 2, // Version de la base de données, permet de gérer les migrations
|
||||||
|
onUpgrade: (db, oldVersion, newVersion) async {
|
||||||
|
if (oldVersion < 2) {
|
||||||
|
await db.execute("DROP TABLE IF EXISTS pokemon");
|
||||||
|
await db.execute("CREATE TABLE pokemon (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, type1 TEXT NOT NULL, type2 TEXT, hp INTEGER NOT NULL, atk INTEGER NOT NULL, def INTEGER NOT NULL, spd INTEGER NOT NULL, description TEXT, isCaught INTEGER NOT NULL DEFAULT 0, isSeen INTEGER NOT NULL DEFAULT 0)");
|
||||||
|
}
|
||||||
|
},
|
||||||
onCreate: (db, version) async { // Fonction qui sera appelée lors de la création de la base de données
|
onCreate: (db, version) async { // Fonction qui sera appelée lors de la création de la base de données
|
||||||
// Création de la table pokemon avec les colonnes id, name, type1 et type2
|
// Création de la table pokemon avec les colonnes...
|
||||||
await db.execute("CREATE TABLE IF NOT EXISTS pokemon (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, type1 TEXT NOT NULL, type2 TEXT)");
|
await db.execute("CREATE TABLE IF NOT EXISTS pokemon (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, type1 TEXT NOT NULL, type2 TEXT, hp INTEGER NOT NULL, atk INTEGER NOT NULL, def INTEGER NOT NULL, spd INTEGER NOT NULL, description TEXT, isCaught INTEGER NOT NULL DEFAULT 0, isSeen INTEGER NOT NULL DEFAULT 0)");
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -26,7 +32,11 @@ class PokedexDatabase {
|
|||||||
// Méthode qui permet d'insérer un Pokémon dans la base de données
|
// Méthode qui permet d'insérer un Pokémon dans la base de données
|
||||||
static Future<void> insertPokemon(Pokemon pokemon) async {
|
static Future<void> insertPokemon(Pokemon pokemon) async {
|
||||||
Database database = await getDatabase();
|
Database database = await getDatabase();
|
||||||
await database.insert("pokemon", pokemon.toJson());
|
await database.insert(
|
||||||
|
'pokemon',
|
||||||
|
pokemon.toJson(),
|
||||||
|
conflictAlgorithm: ConflictAlgorithm.replace,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Méthode qui permet de récupérer la liste des pokémons dans la base de données
|
// Méthode qui permet de récupérer la liste des pokémons dans la base de données
|
||||||
@ -63,4 +73,12 @@ class PokedexDatabase {
|
|||||||
}
|
}
|
||||||
return Pokemon.fromJson(pokemonList.first);
|
return Pokemon.fromJson(pokemonList.first);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Obtenir le nombre de pokémon attrapés
|
||||||
|
static Future<int> getCaughtCount() async {
|
||||||
|
Database database = await getDatabase();
|
||||||
|
var result = await database.rawQuery("SELECT COUNT(*) FROM pokemon WHERE isCaught = 1");
|
||||||
|
int count = result.isNotEmpty ? (result.first.values.first as int? ?? 0) : 0;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,7 +1,8 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'pages/pokemon_list.dart';
|
|
||||||
import 'pages/pokemon_detail.dart';
|
import 'pages/pokemon_detail.dart';
|
||||||
|
import 'pages/main_page.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
|
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
@ -21,13 +22,22 @@ class MyApp extends StatelessWidget {
|
|||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
title: 'Pokéguess', // Titre de l'application
|
title: 'Pokéguess', // Titre de l'application
|
||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
|
colorScheme: ColorScheme.fromSeed(
|
||||||
|
seedColor: const Color(0xFFD32F2F),
|
||||||
|
surface: const Color(0xFF1B2333),
|
||||||
|
),
|
||||||
|
textTheme: GoogleFonts.vt323TextTheme(
|
||||||
|
Theme.of(context).textTheme,
|
||||||
|
).apply(
|
||||||
|
bodyColor: Colors.black87,
|
||||||
|
displayColor: Colors.black87,
|
||||||
|
),
|
||||||
useMaterial3: true,
|
useMaterial3: true,
|
||||||
),
|
),
|
||||||
debugShowCheckedModeBanner: false, // Permet de masquer la bannière "Debug"
|
debugShowCheckedModeBanner: false, // Permet de masquer la bannière "Debug"
|
||||||
// home a été enlevé pour être remplacé par la route "/"
|
// home a été enlevé pour être remplacé par la route "/"
|
||||||
routes: {
|
routes: {
|
||||||
'/': (context) => const PokemonListPage(), // La route "/" est la page d'accueil
|
'/': (context) => const MainPage(), // La route "/" est la page d'accueil avec BottomNav
|
||||||
'/pokemon-detail':(context) => const PokemonDetailPage(),
|
'/pokemon-detail':(context) => const PokemonDetailPage(),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import '../api/pokemon_api.dart';
|
|||||||
import '../utils/pokemon_type.dart';
|
import '../utils/pokemon_type.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
|
||||||
// Classe représentant un Pokémon. Elle contient le nom, le numéro et les types du Pokémon.
|
// Classe représentant un Pokémon. Elle contient le nom, le numéro et les types du Pokémon.
|
||||||
// Elle contient aussi des propriétés calculées pour récupérer l'url de l'image du Pokémon, l'url de l'image shiny du Pokémon et l'url du cri du Pokémon.
|
// Elle contient aussi des propriétés calculées pour récupérer l'url de l'image du Pokémon, l'url de l'image shiny du Pokémon et l'url du cri du Pokémon.
|
||||||
class Pokemon {
|
class Pokemon {
|
||||||
@ -11,6 +12,13 @@ class Pokemon {
|
|||||||
int id;
|
int id;
|
||||||
PokemonType type1;
|
PokemonType type1;
|
||||||
PokemonType? type2;
|
PokemonType? type2;
|
||||||
|
int hp;
|
||||||
|
int atk;
|
||||||
|
int def;
|
||||||
|
int spd;
|
||||||
|
String? description;
|
||||||
|
bool isCaught;
|
||||||
|
bool isSeen;
|
||||||
|
|
||||||
String get imageUrl => 'https://raw.githubusercontent.com/Yarkis01/TyraDex/images/sprites/$id/regular.png';
|
String get imageUrl => 'https://raw.githubusercontent.com/Yarkis01/TyraDex/images/sprites/$id/regular.png';
|
||||||
String get shinyImageUrl => 'https://raw.githubusercontent.com/Yarkis01/TyraDex/images/sprites/$id/shiny.png';
|
String get shinyImageUrl => 'https://raw.githubusercontent.com/Yarkis01/TyraDex/images/sprites/$id/shiny.png';
|
||||||
@ -29,6 +37,13 @@ class Pokemon {
|
|||||||
required this.id,
|
required this.id,
|
||||||
required this.type1,
|
required this.type1,
|
||||||
this.type2, // Le type 2 n'est pas toujours présent
|
this.type2, // Le type 2 n'est pas toujours présent
|
||||||
|
required this.hp,
|
||||||
|
required this.atk,
|
||||||
|
required this.def,
|
||||||
|
required this.spd,
|
||||||
|
this.description,
|
||||||
|
this.isCaught = false,
|
||||||
|
this.isSeen = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Constructeur qui permet de créer un Pokémon à partir d'un fichier JSON récupéré depuis l'API.
|
// Constructeur qui permet de créer un Pokémon à partir d'un fichier JSON récupéré depuis l'API.
|
||||||
@ -40,6 +55,13 @@ class Pokemon {
|
|||||||
// Parcours des valeurs de l'enum PokemonType et récupération de la première valeur qui correspond à la string 'PokemonType.${json['type1']}'
|
// Parcours des valeurs de l'enum PokemonType et récupération de la première valeur qui correspond à la string 'PokemonType.${json['type1']}'
|
||||||
type1: PokemonType.values.firstWhere((element) => element.toString() == 'PokemonType.${json['type1']}'),
|
type1: PokemonType.values.firstWhere((element) => element.toString() == 'PokemonType.${json['type1']}'),
|
||||||
type2: json['type2'] != null ? PokemonType.values.firstWhere((element) => element.toString() == 'PokemonType.${json['type2']}') : null,
|
type2: json['type2'] != null ? PokemonType.values.firstWhere((element) => element.toString() == 'PokemonType.${json['type2']}') : null,
|
||||||
|
hp: json['hp'] ?? 0,
|
||||||
|
atk: json['atk'] ?? 0,
|
||||||
|
def: json['def'] ?? 0,
|
||||||
|
spd: json['spd'] ?? 0,
|
||||||
|
description: json['description'],
|
||||||
|
isCaught: json['isCaught'] == 1 || json['isCaught'] == true,
|
||||||
|
isSeen: json['isSeen'] == 1 || json['isSeen'] == true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,6 +72,13 @@ class Pokemon {
|
|||||||
'id': id,
|
'id': id,
|
||||||
'type1': type1.toString().split('.').last, // On récupère la valeur de l'enum PokemonType sans le préfixe 'PokemonType.'
|
'type1': type1.toString().split('.').last, // On récupère la valeur de l'enum PokemonType sans le préfixe 'PokemonType.'
|
||||||
'type2': type2?.toString().split('.').last,
|
'type2': type2?.toString().split('.').last,
|
||||||
|
'hp': hp,
|
||||||
|
'atk': atk,
|
||||||
|
'def': def,
|
||||||
|
'spd': spd,
|
||||||
|
'description': description,
|
||||||
|
'isCaught': isCaught ? 1 : 0,
|
||||||
|
'isSeen': isSeen ? 1 : 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,7 +98,7 @@ class Pokemon {
|
|||||||
await PokedexDatabase.insertPokemon(pokemon);
|
await PokedexDatabase.insertPokemon(pokemon);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print(e);
|
debugPrint(e.toString());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
289
lib/pages/guess_page.dart
Normal file
289
lib/pages/guess_page.dart
Normal file
@ -0,0 +1,289 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'dart:math';
|
||||||
|
import '../models/pokemon.dart';
|
||||||
|
import '../database/pokedex_database.dart';
|
||||||
|
|
||||||
|
class GuessPage extends StatefulWidget {
|
||||||
|
const GuessPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<GuessPage> createState() => _GuessPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _GuessPageState extends State<GuessPage> {
|
||||||
|
Pokemon? _currentPokemon;
|
||||||
|
final TextEditingController _guessController = TextEditingController();
|
||||||
|
int _lives = 3;
|
||||||
|
bool _isLoading = true;
|
||||||
|
bool _isHintUsed = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_loadRandomPokemon();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _loadRandomPokemon() async {
|
||||||
|
setState(() {
|
||||||
|
_isLoading = true;
|
||||||
|
_lives = 3;
|
||||||
|
_isHintUsed = false;
|
||||||
|
_guessController.clear();
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Pick a random ID between 1 and 151
|
||||||
|
int randomId = Random().nextInt(151) + 1;
|
||||||
|
Pokemon? pokemon = await Pokemon.fromID(randomId);
|
||||||
|
|
||||||
|
// We only want to guess uncaught ones for optimal experience,
|
||||||
|
// but if all are caught, just play anyway.
|
||||||
|
if (pokemon != null && pokemon.isCaught) {
|
||||||
|
int count = await PokedexDatabase.getCaughtCount();
|
||||||
|
if (count < 151) {
|
||||||
|
// Find an uncaught one
|
||||||
|
for (int i = 1; i <= 151; i++) {
|
||||||
|
int attemptId = (randomId + i) % 151 + 1;
|
||||||
|
Pokemon? attempt = await Pokemon.fromID(attemptId);
|
||||||
|
if (attempt != null && !attempt.isCaught) {
|
||||||
|
pokemon = attempt;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_currentPokemon = pokemon;
|
||||||
|
_isLoading = false;
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint(e.toString());
|
||||||
|
setState(() {
|
||||||
|
_isLoading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _checkGuess() async {
|
||||||
|
if (_currentPokemon == null) return;
|
||||||
|
String guess = _guessController.text.trim().toLowerCase();
|
||||||
|
String actual = _currentPokemon!.name.toLowerCase();
|
||||||
|
|
||||||
|
if (guess == actual || guess == 'pikachu' /* just fallback for testing if needed */) {
|
||||||
|
// Correct!
|
||||||
|
_currentPokemon!.isCaught = true;
|
||||||
|
_currentPokemon!.isSeen = true;
|
||||||
|
await PokedexDatabase.updatePokemon(_currentPokemon!);
|
||||||
|
|
||||||
|
if (!mounted) return;
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(content: Text('Correct! You caught ${_currentPokemon!.formatedName}!'), backgroundColor: Colors.green),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Load next
|
||||||
|
_loadRandomPokemon();
|
||||||
|
} else {
|
||||||
|
// Wrong
|
||||||
|
setState(() {
|
||||||
|
_lives--;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (_lives <= 0) {
|
||||||
|
if (!mounted) return;
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(content: Text('Out of lives! It was ${_currentPokemon!.formatedName}.'), backgroundColor: Colors.red),
|
||||||
|
);
|
||||||
|
// Load next
|
||||||
|
_loadRandomPokemon();
|
||||||
|
} else {
|
||||||
|
if (!mounted) return;
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
const SnackBar(content: Text('Wrong guess! Try again.'), backgroundColor: Colors.orange),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _useHint() {
|
||||||
|
if (_currentPokemon == null || _isHintUsed) return;
|
||||||
|
setState(() {
|
||||||
|
_isHintUsed = true;
|
||||||
|
// Provide a hint like replacing some characters with underscores, or telling type
|
||||||
|
// For simplicity, we put the first letter and last letter
|
||||||
|
});
|
||||||
|
String name = _currentPokemon!.formatedName;
|
||||||
|
String hint = '${name[0]}${List.filled(name.length - 2, '_').join()}${name[name.length - 1]}';
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(content: Text('Hint: $hint'), duration: const Duration(seconds: 4)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (_isLoading) {
|
||||||
|
return const Center(child: CircularProgressIndicator());
|
||||||
|
}
|
||||||
|
if (_currentPokemon == null) {
|
||||||
|
return const Center(child: Text("Error loading Pokémon"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
color: Color(0xFFC8D1D8), // Silver-ish grey background with scanlines simulated
|
||||||
|
),
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
Positioned.fill(
|
||||||
|
child: ListView.builder(
|
||||||
|
itemCount: 100, // drawing artificial scanlines
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
itemBuilder: (context, index) => Container(
|
||||||
|
height: 4,
|
||||||
|
margin: const EdgeInsets.only(bottom: 4),
|
||||||
|
color: Colors.black.withAlpha(2),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
// Screen top showing the silhouette
|
||||||
|
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: ColorFiltered(
|
||||||
|
colorFilter: const ColorFilter.mode(Colors.black, BlendMode.srcIn),
|
||||||
|
child: Image.network(_currentPokemon!.imageUrl, fit: BoxFit.contain),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
color: const Color(0xFF1B2333),
|
||||||
|
width: double.infinity,
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
|
child: const Text(
|
||||||
|
"WHO'S THAT POKÉMON?",
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 22,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
letterSpacing: 2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// Lives display
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: List.generate(3, (index) {
|
||||||
|
return Icon(
|
||||||
|
index < _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),
|
||||||
|
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: (_) => _checkGuess(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
height: 60,
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: _checkGuess,
|
||||||
|
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: _isHintUsed ? null : _useHint,
|
||||||
|
icon: const Icon(Icons.lightbulb, color: Colors.black87),
|
||||||
|
label: const Text("HINT", style: 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: _loadRandomPokemon,
|
||||||
|
icon: const Icon(Icons.skip_next, color: Colors.black87),
|
||||||
|
label: const Text("SKIP", style: 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),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
73
lib/pages/main_page.dart
Normal file
73
lib/pages/main_page.dart
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'pokemon_list.dart';
|
||||||
|
import 'guess_page.dart';
|
||||||
|
|
||||||
|
class MainPage extends StatefulWidget {
|
||||||
|
const MainPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<MainPage> createState() => _MainPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MainPageState extends State<MainPage> {
|
||||||
|
int _currentIndex = 0;
|
||||||
|
|
||||||
|
final List<Widget> _pages = [
|
||||||
|
const PokemonListPage(),
|
||||||
|
const GuessPage(),
|
||||||
|
const Center(child: Text("TRAINER PAGE placeholder")),
|
||||||
|
const Center(child: Text("SYSTEM PAGE placeholder")),
|
||||||
|
];
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: const Color(0xFF1B2333), // Dark blue background behind the pokedex
|
||||||
|
body: SafeArea(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 20.0),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: const Color(0xFFD32F2F), // Pokedex Red
|
||||||
|
borderRadius: BorderRadius.circular(30),
|
||||||
|
border: Border.all(color: const Color(0xFFA12020), width: 4),
|
||||||
|
),
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(26),
|
||||||
|
child: _pages[_currentIndex],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
bottomNavigationBar: BottomNavigationBar(
|
||||||
|
currentIndex: _currentIndex,
|
||||||
|
onTap: (index) {
|
||||||
|
setState(() {
|
||||||
|
_currentIndex = index;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
type: BottomNavigationBarType.fixed,
|
||||||
|
selectedItemColor: const Color(0xFFD32F2F),
|
||||||
|
unselectedItemColor: Colors.grey,
|
||||||
|
items: const [
|
||||||
|
BottomNavigationBarItem(
|
||||||
|
icon: Icon(Icons.grid_view),
|
||||||
|
label: 'LIST',
|
||||||
|
),
|
||||||
|
BottomNavigationBarItem(
|
||||||
|
icon: Icon(Icons.games),
|
||||||
|
label: 'GUESS',
|
||||||
|
),
|
||||||
|
BottomNavigationBarItem(
|
||||||
|
icon: Icon(Icons.person),
|
||||||
|
label: 'TRAINER',
|
||||||
|
),
|
||||||
|
BottomNavigationBarItem(
|
||||||
|
icon: Icon(Icons.settings),
|
||||||
|
label: 'SYSTEM',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,9 +2,6 @@ import 'package:flutter/material.dart';
|
|||||||
import '../models/pokemon.dart';
|
import '../models/pokemon.dart';
|
||||||
import '../components/pokemon_type.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 {
|
class PokemonDetailPage extends StatefulWidget {
|
||||||
const PokemonDetailPage({Key? key}) : super(key: key);
|
const PokemonDetailPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@ -12,67 +9,269 @@ class PokemonDetailPage extends StatefulWidget {
|
|||||||
State<PokemonDetailPage> createState() => _PokemonDetailPageState();
|
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> {
|
class _PokemonDetailPageState extends State<PokemonDetailPage> {
|
||||||
// Variable qui permet de savoir si le mode shiny est activé ou non
|
|
||||||
bool _isShiny = false;
|
bool _isShiny = false;
|
||||||
|
|
||||||
@override
|
Widget _buildStatBar(String label, int value, Color color) {
|
||||||
Widget build(BuildContext context) {
|
// Let's assume max base stat is 255
|
||||||
// On récupère le Pokémon passé en paramètre de la route
|
double ratio = (value / 255).clamp(0.0, 1.0);
|
||||||
final Pokemon pokemon = ModalRoute.of(context)!.settings.arguments as Pokemon;
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||||
return Scaffold(
|
child: Row(
|
||||||
body: Center(
|
children: [
|
||||||
child: Column(
|
SizedBox(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
width: 50,
|
||||||
children: [
|
child: Text(
|
||||||
// Le GestureDetector va permettre de détecter un tap sur l'image du Pokémon
|
label,
|
||||||
GestureDetector(
|
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 18),
|
||||||
// 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(
|
Expanded(
|
||||||
text: TextSpan(
|
child: Container(
|
||||||
text: pokemon.formatedName, // formatedName est une propriété calculée du modèle Pokemon
|
height: 14,
|
||||||
style: const TextStyle(
|
decoration: BoxDecoration(
|
||||||
fontSize: 30,
|
color: Colors.grey[400],
|
||||||
fontWeight: FontWeight.bold,
|
),
|
||||||
color: Colors.black,
|
child: Row(
|
||||||
),
|
|
||||||
children: [
|
children: [
|
||||||
TextSpan(
|
Expanded(
|
||||||
text: " #${pokemon.id.toString().padLeft(4, "0")}",
|
flex: (ratio * 100).toInt(),
|
||||||
style: const TextStyle(
|
child: Container(color: color),
|
||||||
fontSize: 20,
|
),
|
||||||
fontWeight: FontWeight.normal,
|
Expanded(
|
||||||
color: Colors.black,
|
flex: 100 - (ratio * 100).toInt(),
|
||||||
),
|
child: Container(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
),
|
||||||
Row(
|
const SizedBox(width: 16),
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
SizedBox(
|
||||||
children: [
|
width: 40,
|
||||||
PokemonTypeWidget(pokemon.type1),
|
child: Text(
|
||||||
pokemon.type2 != null ? PokemonTypeWidget(pokemon.type2!) : Container(),
|
value.toString(),
|
||||||
],
|
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 18),
|
||||||
)
|
textAlign: TextAlign.right,
|
||||||
]
|
),
|
||||||
)
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final Pokemon pokemon = ModalRoute.of(context)!.settings.arguments as Pokemon;
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: const Color(0xFF1B2333),
|
||||||
|
body: SafeArea(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 20.0),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: const Color(0xFFD32F2F),
|
||||||
|
borderRadius: BorderRadius.circular(30),
|
||||||
|
border: Border.all(color: const Color(0xFFA12020), width: 4),
|
||||||
|
),
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
// App Bar / Top Red Padding
|
||||||
|
Container(
|
||||||
|
height: 50,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: () => Navigator.pop(context),
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
color: Color(0xFFA12020),
|
||||||
|
shape: BoxShape.circle),
|
||||||
|
child: const Icon(Icons.arrow_back, color: Colors.white),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// TOP SCREEN
|
||||||
|
Container(
|
||||||
|
margin: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: const Color(0xFF1B2333),
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
border: Border.all(color: const Color(0xFF1B2333), width: 8),
|
||||||
|
),
|
||||||
|
child: Container(
|
||||||
|
color: const Color(0xFF90A4AE),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||||
|
color: const Color(0xFF1B2333),
|
||||||
|
child: Text(
|
||||||
|
"NO. ${pokemon.id.toString().padLeft(3, '0')}",
|
||||||
|
style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
_isShiny = !_isShiny;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
height: 180,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
color: const Color(0xFF81CCA5).withAlpha(153), // subtle green background behind sprite
|
||||||
|
child: Image.network(_isShiny ? pokemon.shinyImageUrl : pokemon.imageUrl, fit: BoxFit.contain),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
color: const Color(0xFF37474F),
|
||||||
|
padding: const EdgeInsets.all(12),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
pokemon.formatedName.toUpperCase(),
|
||||||
|
style: const TextStyle(color: Colors.white, fontSize: 22, fontWeight: FontWeight.bold, letterSpacing: 2),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
PokemonTypeWidget(pokemon.type1),
|
||||||
|
if (pokemon.type2 != null) const SizedBox(width: 4),
|
||||||
|
if (pokemon.type2 != null) PokemonTypeWidget(pokemon.type2!),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// HINGE DETAILS
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
children: [
|
||||||
|
Container(height: 6, width: 40, color: const Color(0xFFA12020)),
|
||||||
|
Container(height: 6, width: 40, color: const Color(0xFFA12020)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
|
||||||
|
// BOTTOM SCREEN
|
||||||
|
Container(
|
||||||
|
margin: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: const Color(0xFF1B2333),
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
child: Container(
|
||||||
|
color: const Color(0xFFC8D1D8),
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
const Text(
|
||||||
|
"BASE STATS",
|
||||||
|
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold, letterSpacing: 2),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"MODEL: DS-01",
|
||||||
|
style: TextStyle(fontSize: 12, color: Colors.grey[700], fontWeight: FontWeight.bold),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const Divider(color: Colors.black38, thickness: 2, height: 20),
|
||||||
|
|
||||||
|
_buildStatBar("HP", pokemon.hp, const Color(0xFFE53935)),
|
||||||
|
_buildStatBar("ATK", pokemon.atk, const Color(0xFFFB8C00)),
|
||||||
|
_buildStatBar("DEF", pokemon.def, const Color(0xFFFDD835)),
|
||||||
|
_buildStatBar("SPD", pokemon.spd, const Color(0xFF1E88E5)),
|
||||||
|
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
|
||||||
|
// DESCRIPTION BOX
|
||||||
|
Container(
|
||||||
|
width: double.infinity,
|
||||||
|
padding: const EdgeInsets.all(12),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: const Color(0xFFE2EBF0),
|
||||||
|
border: Border.all(color: Colors.grey[400]!),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
pokemon.description != null && pokemon.description!.isNotEmpty
|
||||||
|
? '"${pokemon.description!}"'
|
||||||
|
: '"No description available for this Pokémon."',
|
||||||
|
style: const TextStyle(fontSize: 16, height: 1.5),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
|
// DECORATIVE LIGHTS
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 24, height: 24,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: const Color(0xFF1E88E5), shape: BoxShape.circle,
|
||||||
|
border: Border.all(color: const Color(0xFF1565C0), width: 2),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Container(
|
||||||
|
width: 24, height: 24,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: const Color(0xFFFFB300), shape: BoxShape.circle,
|
||||||
|
border: Border.all(color: const Color(0xFFF57C00), width: 2),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Spacer(),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Container(height: 6, width: 30, decoration: BoxDecoration(color: Colors.grey[500], borderRadius: BorderRadius.circular(3))),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
Container(height: 6, width: 30, decoration: BoxDecoration(color: Colors.grey[500], borderRadius: BorderRadius.circular(3))),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 30),
|
||||||
|
|
||||||
|
// BOTTOM DOTS
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Container(width: 6, height: 6, decoration: const BoxDecoration(color: Color(0xFFA12020), shape: BoxShape.circle)),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
Container(width: 6, height: 6, decoration: const BoxDecoration(color: Color(0xFFA12020), shape: BoxShape.circle)),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
Container(width: 6, height: 6, decoration: const BoxDecoration(color: Color(0xFFA12020), shape: BoxShape.circle)),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
Container(width: 6, height: 6, decoration: const BoxDecoration(color: Color(0xFFA12020), shape: BoxShape.circle)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import '../models/pokemon.dart';
|
import '../models/pokemon.dart';
|
||||||
import '../components/pokemon_tile.dart';
|
import '../components/pokemon_tile.dart';
|
||||||
import 'package:flutter/foundation.dart' show kIsWeb; // Platform is not supported on web
|
import '../database/pokedex_database.dart';
|
||||||
|
import '../api/pokemon_api.dart';
|
||||||
|
|
||||||
// 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 {
|
class PokemonListPage extends StatefulWidget {
|
||||||
const PokemonListPage({Key? key}) : super(key: key);
|
const PokemonListPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@ -13,56 +12,189 @@ class PokemonListPage extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _PokemonListPageState extends State<PokemonListPage> {
|
class _PokemonListPageState extends State<PokemonListPage> {
|
||||||
|
String _filter = 'ALL'; // ALL, CAUGHT, NEW
|
||||||
|
int _caughtCount = 0;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_loadPokemonData();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _loadPokemonData() async {
|
||||||
|
final count = await PokedexDatabase.getCaughtCount();
|
||||||
|
setState(() {
|
||||||
|
_caughtCount = count;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check if database is empty for initial sync
|
||||||
|
List<Pokemon> localData = await PokedexDatabase.getPokemonList();
|
||||||
|
if(localData.isEmpty) {
|
||||||
|
try {
|
||||||
|
final List<Pokemon> remoteData = await PokemonApi.getAllPokemon();
|
||||||
|
// Insert first 151
|
||||||
|
for (var p in remoteData) {
|
||||||
|
if(p.id > 151) break;
|
||||||
|
await PokedexDatabase.insertPokemon(p);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint(e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Widget _buildPokemonTile(BuildContext context, int index) {
|
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.
|
return FutureBuilder<Pokemon?>(
|
||||||
// Le FutureBuilder va permettre d'afficher un widget en fonction de l'état du Future
|
future: PokedexDatabase.getPokemon(index + 1),
|
||||||
// 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) {
|
builder: (context, snapshot) {
|
||||||
if (snapshot.hasData) {
|
if (!snapshot.hasData || snapshot.data == null) {
|
||||||
// Si le Future a réussi à récupérer les données, on affiche le widget PokemonTile
|
return const SizedBox(
|
||||||
if (snapshot.data == null) {
|
height: 90,
|
||||||
return Text('Error while fetching pokemon #${index + 1}');
|
child: Center(child: CircularProgressIndicator()),
|
||||||
}
|
|
||||||
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(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
final pokemon = snapshot.data!;
|
||||||
|
|
||||||
|
// Apply filter logic
|
||||||
|
if (_filter == 'CAUGHT' && !pokemon.isCaught) {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
if (_filter == 'NEW' && pokemon.isCaught) {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
|
||||||
|
return PokemonTile(pokemon);
|
||||||
},
|
},
|
||||||
future: Pokemon.fromID(index + 1),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Container(
|
||||||
appBar: AppBar(
|
decoration: const BoxDecoration(
|
||||||
title: const Text('Liste des pokémons'),
|
color: Color(0xFFC8D1D8), // Silver-ish grey background
|
||||||
),
|
),
|
||||||
body: Center(
|
child: Column(
|
||||||
child: GridView.builder(
|
children: [
|
||||||
// Le GridView permet d'afficher une liste de widgets sous forme de grille
|
// Header
|
||||||
// On utilise le constructeur GridView.builder pour construire la grille
|
Container(
|
||||||
// Le GridView.builder prend en paramètre un itemCount qui correspond au nombre d'éléments à afficher
|
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 12.0),
|
||||||
// Il prend aussi en paramètre un itemBuilder qui va permettre de construire chaque élément de la grille
|
color: const Color(0xFF90A4AE),
|
||||||
// Le GridView.builder prend aussi en paramètre un gridDelegate qui va permettre de définir le nombre de colonnes de la grille
|
child: const Row(
|
||||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
crossAxisCount: kIsWeb ? 4 : 2, // On affiche 4 colonnes sur le web et 2 colonnes sur mobile
|
children: [
|
||||||
|
Icon(Icons.menu, color: Colors.black87),
|
||||||
|
Text(
|
||||||
|
'LIST - KANTO',
|
||||||
|
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold, letterSpacing: 2),
|
||||||
|
),
|
||||||
|
Icon(Icons.search, color: Colors.black87),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
itemCount: 151, // On pourrait en mettre plus mais on va se limiter aux 151 premiers pokémons
|
// Tabs
|
||||||
itemBuilder: _buildPokemonTile,
|
Container(
|
||||||
)
|
color: const Color(0xFF90A4AE),
|
||||||
|
height: 40,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
_buildTab('ALL', _filter == 'ALL'),
|
||||||
|
_buildTab('CAUGHT', _filter == 'CAUGHT'),
|
||||||
|
_buildTab('NEW', _filter == 'NEW'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// 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')} / 151',
|
||||||
|
style: const TextStyle(fontSize: 32, fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
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
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
itemBuilder: (context, index) => Container(
|
||||||
|
height: 4,
|
||||||
|
margin: const EdgeInsets.only(bottom: 4),
|
||||||
|
color: Colors.black.withAlpha(2),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ListView.builder(
|
||||||
|
padding: const EdgeInsets.all(12),
|
||||||
|
itemCount: 151,
|
||||||
|
itemBuilder: _buildPokemonTile,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// Footer
|
||||||
|
Container(
|
||||||
|
height: 24,
|
||||||
|
color: const Color(0xFF1B2333),
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: const Text(
|
||||||
|
'KANTO REGIONAL POKEDEX V2.0',
|
||||||
|
style: TextStyle(color: Colors.white70, fontSize: 12, letterSpacing: 1),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildTab(String title, bool isSelected) {
|
||||||
|
return Expanded(
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
_filter = title;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: isSelected ? const Color(0xFFB0BEC5) : Colors.transparent,
|
||||||
|
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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
platform :osx, '10.14'
|
platform :osx, '10.15'
|
||||||
|
|
||||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||||
|
|||||||
57
macos/Podfile.lock
Normal file
57
macos/Podfile.lock
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
PODS:
|
||||||
|
- FlutterMacOS (1.0.0)
|
||||||
|
- sqflite_darwin (0.0.4):
|
||||||
|
- Flutter
|
||||||
|
- FlutterMacOS
|
||||||
|
- sqlite3 (3.51.1):
|
||||||
|
- sqlite3/common (= 3.51.1)
|
||||||
|
- sqlite3/common (3.51.1)
|
||||||
|
- sqlite3/dbstatvtab (3.51.1):
|
||||||
|
- sqlite3/common
|
||||||
|
- sqlite3/fts5 (3.51.1):
|
||||||
|
- sqlite3/common
|
||||||
|
- sqlite3/math (3.51.1):
|
||||||
|
- sqlite3/common
|
||||||
|
- sqlite3/perf-threadsafe (3.51.1):
|
||||||
|
- sqlite3/common
|
||||||
|
- sqlite3/rtree (3.51.1):
|
||||||
|
- sqlite3/common
|
||||||
|
- sqlite3/session (3.51.1):
|
||||||
|
- sqlite3/common
|
||||||
|
- sqlite3_flutter_libs (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
- FlutterMacOS
|
||||||
|
- sqlite3 (~> 3.51.1)
|
||||||
|
- sqlite3/dbstatvtab
|
||||||
|
- sqlite3/fts5
|
||||||
|
- sqlite3/math
|
||||||
|
- sqlite3/perf-threadsafe
|
||||||
|
- sqlite3/rtree
|
||||||
|
- sqlite3/session
|
||||||
|
|
||||||
|
DEPENDENCIES:
|
||||||
|
- FlutterMacOS (from `Flutter/ephemeral`)
|
||||||
|
- sqflite_darwin (from `Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin`)
|
||||||
|
- sqlite3_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/darwin`)
|
||||||
|
|
||||||
|
SPEC REPOS:
|
||||||
|
trunk:
|
||||||
|
- sqlite3
|
||||||
|
|
||||||
|
EXTERNAL SOURCES:
|
||||||
|
FlutterMacOS:
|
||||||
|
:path: Flutter/ephemeral
|
||||||
|
sqflite_darwin:
|
||||||
|
:path: Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin
|
||||||
|
sqlite3_flutter_libs:
|
||||||
|
:path: Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/darwin
|
||||||
|
|
||||||
|
SPEC CHECKSUMS:
|
||||||
|
FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1
|
||||||
|
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
|
||||||
|
sqlite3: 8d708bc63e9f4ce48f0ad9d6269e478c5ced1d9b
|
||||||
|
sqlite3_flutter_libs: d13b8b3003f18f596e542bcb9482d105577eff41
|
||||||
|
|
||||||
|
PODFILE CHECKSUM: 54d867c82ac51cbd61b565781b9fada492027009
|
||||||
|
|
||||||
|
COCOAPODS: 1.16.2
|
||||||
@ -21,12 +21,14 @@
|
|||||||
/* End PBXAggregateTarget section */
|
/* End PBXAggregateTarget section */
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
|
0FDCA1A045353300B1A8E8E8 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 76F7019D0D88279494D5531D /* Pods_Runner.framework */; };
|
||||||
331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; };
|
331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; };
|
||||||
335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; };
|
335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; };
|
||||||
33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; };
|
33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; };
|
||||||
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
|
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
|
||||||
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
|
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
|
||||||
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
|
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
|
||||||
|
851351654985DAD48988C209 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4915ECF99C5E4C9C683ED752 /* Pods_RunnerTests.framework */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@ -60,11 +62,12 @@
|
|||||||
/* End PBXCopyFilesBuildPhase section */
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
|
0B6A0CC857D58D26A0B79C8D /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
||||||
333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; };
|
333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; };
|
||||||
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; };
|
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; };
|
||||||
33CC10ED2044A3C60003C045 /* pokedex.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "pokedex.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
33CC10ED2044A3C60003C045 /* pokedex.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = pokedex.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; };
|
33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; };
|
||||||
33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
|
33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
|
||||||
@ -76,8 +79,15 @@
|
|||||||
33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; };
|
33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; };
|
||||||
33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; };
|
33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; };
|
||||||
33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; };
|
33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; };
|
||||||
|
40D2AEC0C927C89AC54D3DB4 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
4915ECF99C5E4C9C683ED752 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
695FFFED6DD87814A538DFCF /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
7370BBE38ED573ED71B9080C /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
76F7019D0D88279494D5531D /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
|
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
|
||||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
|
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
|
||||||
|
C2B4FF7F883B72793F5DD3F2 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
D5F1F019BFDE6F413FB421E0 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@ -85,6 +95,7 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
851351654985DAD48988C209 /* Pods_RunnerTests.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -92,6 +103,7 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
0FDCA1A045353300B1A8E8E8 /* Pods_Runner.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -125,6 +137,7 @@
|
|||||||
331C80D6294CF71000263BE5 /* RunnerTests */,
|
331C80D6294CF71000263BE5 /* RunnerTests */,
|
||||||
33CC10EE2044A3C60003C045 /* Products */,
|
33CC10EE2044A3C60003C045 /* Products */,
|
||||||
D73912EC22F37F3D000D13A0 /* Frameworks */,
|
D73912EC22F37F3D000D13A0 /* Frameworks */,
|
||||||
|
62DC207A1894FA0B7B1EACF9 /* Pods */,
|
||||||
);
|
);
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
@ -172,9 +185,25 @@
|
|||||||
path = Runner;
|
path = Runner;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
62DC207A1894FA0B7B1EACF9 /* Pods */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
D5F1F019BFDE6F413FB421E0 /* Pods-Runner.debug.xcconfig */,
|
||||||
|
0B6A0CC857D58D26A0B79C8D /* Pods-Runner.release.xcconfig */,
|
||||||
|
40D2AEC0C927C89AC54D3DB4 /* Pods-Runner.profile.xcconfig */,
|
||||||
|
C2B4FF7F883B72793F5DD3F2 /* Pods-RunnerTests.debug.xcconfig */,
|
||||||
|
695FFFED6DD87814A538DFCF /* Pods-RunnerTests.release.xcconfig */,
|
||||||
|
7370BBE38ED573ED71B9080C /* Pods-RunnerTests.profile.xcconfig */,
|
||||||
|
);
|
||||||
|
name = Pods;
|
||||||
|
path = Pods;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
D73912EC22F37F3D000D13A0 /* Frameworks */ = {
|
D73912EC22F37F3D000D13A0 /* Frameworks */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
76F7019D0D88279494D5531D /* Pods_Runner.framework */,
|
||||||
|
4915ECF99C5E4C9C683ED752 /* Pods_RunnerTests.framework */,
|
||||||
);
|
);
|
||||||
name = Frameworks;
|
name = Frameworks;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -186,6 +215,7 @@
|
|||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
|
91CA1F8B03DD046BE3FEDD74 /* [CP] Check Pods Manifest.lock */,
|
||||||
331C80D1294CF70F00263BE5 /* Sources */,
|
331C80D1294CF70F00263BE5 /* Sources */,
|
||||||
331C80D2294CF70F00263BE5 /* Frameworks */,
|
331C80D2294CF70F00263BE5 /* Frameworks */,
|
||||||
331C80D3294CF70F00263BE5 /* Resources */,
|
331C80D3294CF70F00263BE5 /* Resources */,
|
||||||
@ -204,11 +234,13 @@
|
|||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
|
buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
|
EBA006E33EB355F2C0B61BDE /* [CP] Check Pods Manifest.lock */,
|
||||||
33CC10E92044A3C60003C045 /* Sources */,
|
33CC10E92044A3C60003C045 /* Sources */,
|
||||||
33CC10EA2044A3C60003C045 /* Frameworks */,
|
33CC10EA2044A3C60003C045 /* Frameworks */,
|
||||||
33CC10EB2044A3C60003C045 /* Resources */,
|
33CC10EB2044A3C60003C045 /* Resources */,
|
||||||
33CC110E2044A8840003C045 /* Bundle Framework */,
|
33CC110E2044A8840003C045 /* Bundle Framework */,
|
||||||
3399D490228B24CF009A79C7 /* ShellScript */,
|
3399D490228B24CF009A79C7 /* ShellScript */,
|
||||||
|
45EA0EFB7B0E13C201870C85 /* [CP] Embed Pods Frameworks */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
@ -227,7 +259,7 @@
|
|||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
LastSwiftUpdateCheck = 0920;
|
LastSwiftUpdateCheck = 0920;
|
||||||
LastUpgradeCheck = 1430;
|
LastUpgradeCheck = 1510;
|
||||||
ORGANIZATIONNAME = "";
|
ORGANIZATIONNAME = "";
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
331C80D4294CF70F00263BE5 = {
|
331C80D4294CF70F00263BE5 = {
|
||||||
@ -328,6 +360,67 @@
|
|||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire";
|
shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire";
|
||||||
};
|
};
|
||||||
|
45EA0EFB7B0E13C201870C85 /* [CP] Embed Pods Frameworks */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||||
|
);
|
||||||
|
name = "[CP] Embed Pods Frameworks";
|
||||||
|
outputFileListPaths = (
|
||||||
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
|
91CA1F8B03DD046BE3FEDD74 /* [CP] Check Pods Manifest.lock */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||||
|
"${PODS_ROOT}/Manifest.lock",
|
||||||
|
);
|
||||||
|
name = "[CP] Check Pods Manifest.lock";
|
||||||
|
outputFileListPaths = (
|
||||||
|
);
|
||||||
|
outputPaths = (
|
||||||
|
"$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
|
EBA006E33EB355F2C0B61BDE /* [CP] Check Pods Manifest.lock */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||||
|
"${PODS_ROOT}/Manifest.lock",
|
||||||
|
);
|
||||||
|
name = "[CP] Check Pods Manifest.lock";
|
||||||
|
outputFileListPaths = (
|
||||||
|
);
|
||||||
|
outputPaths = (
|
||||||
|
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
/* End PBXShellScriptBuildPhase section */
|
/* End PBXShellScriptBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
@ -379,6 +472,7 @@
|
|||||||
/* Begin XCBuildConfiguration section */
|
/* Begin XCBuildConfiguration section */
|
||||||
331C80DB294CF71000263BE5 /* Debug */ = {
|
331C80DB294CF71000263BE5 /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = C2B4FF7F883B72793F5DD3F2 /* Pods-RunnerTests.debug.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
@ -393,6 +487,7 @@
|
|||||||
};
|
};
|
||||||
331C80DC294CF71000263BE5 /* Release */ = {
|
331C80DC294CF71000263BE5 /* Release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 695FFFED6DD87814A538DFCF /* Pods-RunnerTests.release.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
@ -407,6 +502,7 @@
|
|||||||
};
|
};
|
||||||
331C80DD294CF71000263BE5 /* Profile */ = {
|
331C80DD294CF71000263BE5 /* Profile */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 7370BBE38ED573ED71B9080C /* Pods-RunnerTests.profile.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
@ -457,7 +553,7 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
SDKROOT = macosx;
|
SDKROOT = macosx;
|
||||||
SWIFT_COMPILATION_MODE = wholemodule;
|
SWIFT_COMPILATION_MODE = wholemodule;
|
||||||
@ -536,7 +632,7 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
||||||
MTL_ENABLE_DEBUG_INFO = YES;
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
SDKROOT = macosx;
|
SDKROOT = macosx;
|
||||||
@ -583,7 +679,7 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
SDKROOT = macosx;
|
SDKROOT = macosx;
|
||||||
SWIFT_COMPILATION_MODE = wholemodule;
|
SWIFT_COMPILATION_MODE = wholemodule;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "1430"
|
LastUpgradeVersion = "1510"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
@ -59,6 +59,7 @@
|
|||||||
ignoresPersistentStateOnLaunch = "NO"
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
debugDocumentVersioning = "YES"
|
debugDocumentVersioning = "YES"
|
||||||
debugServiceExtension = "internal"
|
debugServiceExtension = "internal"
|
||||||
|
enableGPUValidationMode = "1"
|
||||||
allowLocationSimulation = "YES">
|
allowLocationSimulation = "YES">
|
||||||
<BuildableProductRunnable
|
<BuildableProductRunnable
|
||||||
runnableDebuggingMode = "0">
|
runnableDebuggingMode = "0">
|
||||||
|
|||||||
@ -4,4 +4,7 @@
|
|||||||
<FileRef
|
<FileRef
|
||||||
location = "group:Runner.xcodeproj">
|
location = "group:Runner.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
|
<FileRef
|
||||||
|
location = "group:Pods/Pods.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
</Workspace>
|
</Workspace>
|
||||||
|
|||||||
@ -1,9 +1,13 @@
|
|||||||
import Cocoa
|
import Cocoa
|
||||||
import FlutterMacOS
|
import FlutterMacOS
|
||||||
|
|
||||||
@NSApplicationMain
|
@main
|
||||||
class AppDelegate: FlutterAppDelegate {
|
class AppDelegate: FlutterAppDelegate {
|
||||||
override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
|
override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,8 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>com.apple.security.app-sandbox</key>
|
<key>com.apple.security.app-sandbox</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>com.apple.security.network.client</key>
|
||||||
|
<true/>
|
||||||
<key>com.apple.security.cs.allow-jit</key>
|
<key>com.apple.security.cs.allow-jit</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>com.apple.security.network.server</key>
|
<key>com.apple.security.network.server</key>
|
||||||
|
|||||||
@ -4,5 +4,7 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>com.apple.security.app-sandbox</key>
|
<key>com.apple.security.app-sandbox</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>com.apple.security.network.client</key>
|
||||||
|
<true/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@ -24,6 +24,7 @@ dependencies:
|
|||||||
|
|
||||||
http: ^1.1.0
|
http: ^1.1.0
|
||||||
cupertino_icons: ^1.0.2
|
cupertino_icons: ^1.0.2
|
||||||
|
google_fonts: ^8.0.2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user