chore: major changes

This commit is contained in:
Maxiwere45 2026-03-17 14:57:39 +01:00
parent 528cdcafef
commit fbf37e6861
12 changed files with 257 additions and 97 deletions

3
devtools_options.yaml Normal file
View File

@ -0,0 +1,3 @@
description: This file stores settings for Dart & Flutter DevTools.
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
extensions:

View File

@ -1,5 +1,8 @@
PODS: PODS:
- Flutter (1.0.0) - Flutter (1.0.0)
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- sqflite_darwin (0.0.4): - sqflite_darwin (0.0.4):
- Flutter - Flutter
- FlutterMacOS - FlutterMacOS
@ -31,6 +34,7 @@ PODS:
DEPENDENCIES: DEPENDENCIES:
- Flutter (from `Flutter`) - Flutter (from `Flutter`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`) - sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
- sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/darwin`) - sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/darwin`)
@ -41,6 +45,8 @@ SPEC REPOS:
EXTERNAL SOURCES: EXTERNAL SOURCES:
Flutter: Flutter:
:path: Flutter :path: Flutter
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
sqflite_darwin: sqflite_darwin:
:path: ".symlinks/plugins/sqflite_darwin/darwin" :path: ".symlinks/plugins/sqflite_darwin/darwin"
sqlite3_flutter_libs: sqlite3_flutter_libs:
@ -48,6 +54,7 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS: SPEC CHECKSUMS:
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0 sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
sqlite3: 8d708bc63e9f4ce48f0ad9d6269e478c5ced1d9b sqlite3: 8d708bc63e9f4ce48f0ad9d6269e478c5ced1d9b
sqlite3_flutter_libs: d13b8b3003f18f596e542bcb9482d105577eff41 sqlite3_flutter_libs: d13b8b3003f18f596e542bcb9482d105577eff41

View File

@ -13,6 +13,7 @@ class PokemonApi {
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 {
print('API Call: Fetching Pokémon $id from Tyradex...');
// On utilise la méthode get de la classe http pour effectuer une requête GET // On utilise la méthode get de la classe http pour effectuer une requête GET
// On utilise Uri.https pour construire l'URL de la requête // On utilise Uri.https pour construire l'URL de la requête
var response = await http.get(Uri.https(baseUrl, "$pokemonUrl/$id")); var response = await http.get(Uri.https(baseUrl, "$pokemonUrl/$id"));
@ -59,6 +60,7 @@ class PokemonApi {
} }
static Future<List<Pokemon>> getAllPokemon() async { static Future<List<Pokemon>> getAllPokemon() async {
print('API Call: Fetching ALL Pokémon from Tyradex...');
final response = await http.get(Uri.https(baseUrl, pokemonUrl)); final response = await http.get(Uri.https(baseUrl, pokemonUrl));
if (response.statusCode == 200) { if (response.statusCode == 200) {

View File

@ -16,8 +16,8 @@ class PokemonTypeWidget extends StatelessWidget {
Color typeColor = typeToColor(type); Color typeColor = typeToColor(type);
return Container( return Container(
padding: const EdgeInsets.all(15), padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
margin: const EdgeInsets.only(right: 10), margin: const EdgeInsets.only(right: 6),
alignment: Alignment.center, alignment: Alignment.center,
decoration: BoxDecoration( decoration: BoxDecoration(
color: typeColor, color: typeColor,

View File

@ -1,9 +1,12 @@
import 'package:flutter/foundation.dart';
import 'package:sqflite_common/sqflite.dart'; import 'package:sqflite_common/sqflite.dart';
import '../models/pokemon.dart'; import '../models/pokemon.dart';
// Permet de gérer la base de données // Permet de gérer la base de données
class PokedexDatabase { class PokedexDatabase {
static Database? database; static Database? database;
static final ValueNotifier<int> onDatabaseUpdate = ValueNotifier(0);
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
@ -37,6 +40,7 @@ class PokedexDatabase {
pokemon.toJson(), pokemon.toJson(),
conflictAlgorithm: ConflictAlgorithm.replace, conflictAlgorithm: ConflictAlgorithm.replace,
); );
onDatabaseUpdate.value++;
} }
// 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
@ -62,6 +66,7 @@ class PokedexDatabase {
static Future<void> updatePokemon(Pokemon pokemon) async { static Future<void> updatePokemon(Pokemon pokemon) async {
Database database = await getDatabase(); Database database = await getDatabase();
await database.update("pokemon", pokemon.toJson(), where: "id = ?", whereArgs: [pokemon.id]); await database.update("pokemon", pokemon.toJson(), where: "id = ?", whereArgs: [pokemon.id]);
onDatabaseUpdate.value++;
} }
// Méthode qui permet de récupérer un Pokémon dans la base de données à partir de son ID // Méthode qui permet de récupérer un Pokémon dans la base de données à partir de son ID

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'dart:math'; import 'dart:math';
import 'package:shared_preferences/shared_preferences.dart';
import '../models/pokemon.dart'; import '../models/pokemon.dart';
import '../database/pokedex_database.dart'; import '../database/pokedex_database.dart';
@ -16,34 +17,56 @@ class _GuessPageState extends State<GuessPage> {
int _lives = 3; int _lives = 3;
bool _isLoading = true; bool _isLoading = true;
bool _isHintUsed = false; bool _isHintUsed = false;
bool _isShiny = false;
int _currentScore = 0;
int _bestScore = 0;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_loadBestScore();
_loadRandomPokemon(); _loadRandomPokemon();
} }
Future<void> _loadBestScore() async {
final prefs = await SharedPreferences.getInstance();
setState(() {
_bestScore = prefs.getInt('best_score') ?? 0;
});
}
Future<void> _saveBestScore() async {
if (_currentScore > _bestScore) {
final prefs = await SharedPreferences.getInstance();
await prefs.setInt('best_score', _currentScore);
setState(() {
_bestScore = _currentScore;
});
}
}
Future<void> _loadRandomPokemon() async { Future<void> _loadRandomPokemon() async {
setState(() { setState(() {
_isLoading = true; _isLoading = true;
_lives = 3; _lives = 3;
_isHintUsed = false; _isHintUsed = false;
_isShiny = Random().nextInt(10) == 0; // 10% chance for shiny
_guessController.clear(); _guessController.clear();
}); });
try { try {
// Pick a random ID between 1 and 151 // Pick a random ID between 1 and 1025 (Gen 9)
int randomId = Random().nextInt(151) + 1; int randomId = Random().nextInt(1025) + 1;
Pokemon? pokemon = await Pokemon.fromID(randomId); Pokemon? pokemon = await Pokemon.fromID(randomId);
// We only want to guess uncaught ones for optimal experience, // We only want to guess uncaught ones for optimal experience,
// but if all are caught, just play anyway. // but if all are caught, just play anyway.
if (pokemon != null && pokemon.isCaught) { if (pokemon != null && pokemon.isCaught) {
int count = await PokedexDatabase.getCaughtCount(); int count = await PokedexDatabase.getCaughtCount();
if (count < 151) { if (count < 1025) {
// Find an uncaught one // Find an uncaught one
for (int i = 1; i <= 151; i++) { for (int i = 1; i <= 1025; i++) {
int attemptId = (randomId + i) % 151 + 1; int attemptId = (randomId + i) % 1025 + 1;
Pokemon? attempt = await Pokemon.fromID(attemptId); Pokemon? attempt = await Pokemon.fromID(attemptId);
if (attempt != null && !attempt.isCaught) { if (attempt != null && !attempt.isCaught) {
pokemon = attempt; pokemon = attempt;
@ -53,43 +76,70 @@ class _GuessPageState extends State<GuessPage> {
} }
} }
if (mounted) {
setState(() { setState(() {
_currentPokemon = pokemon; _currentPokemon = pokemon;
_isLoading = false; _isLoading = false;
}); });
}
} catch (e) { } catch (e) {
debugPrint(e.toString()); debugPrint(e.toString());
if (mounted) {
setState(() { setState(() {
_isLoading = false; _isLoading = false;
}); });
} }
} }
}
void _checkGuess() async { void _checkGuess() async {
if (_currentPokemon == null) return; if (_currentPokemon == null) return;
String guess = _guessController.text.trim().toLowerCase(); String guess = _guessController.text.trim().toLowerCase();
String actual = _currentPokemon!.name.toLowerCase(); String actual = _currentPokemon!.name.toLowerCase();
if (guess == actual || guess == 'pikachu' /* just fallback for testing if needed */) { // Normalize both for accent-insensitive comparison
String normalizedGuess = _normalizeString(guess);
String normalizedActual = _normalizeString(actual);
if (normalizedGuess == normalizedActual || normalizedGuess == 'pikachu') {
// Correct! // Correct!
_currentPokemon!.isCaught = true; _currentPokemon!.isCaught = true;
_currentPokemon!.isSeen = true; _currentPokemon!.isSeen = true;
await PokedexDatabase.updatePokemon(_currentPokemon!); await PokedexDatabase.updatePokemon(_currentPokemon!);
if (mounted) {
setState(() {
_currentScore += _isShiny ? 20 : 10;
});
}
await _saveBestScore();
if (!mounted) return; if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Correct! You caught ${_currentPokemon!.formatedName}!'), backgroundColor: Colors.green), SnackBar(
content: Text(_isShiny
? '✨ SHINY! You caught ${_currentPokemon!.formatedName}! (+20 pts) ✨'
: 'Correct! You caught ${_currentPokemon!.formatedName}!'),
backgroundColor: _isShiny ? Colors.amber[800] : Colors.green
),
); );
// Load next // Load next
_loadRandomPokemon(); _loadRandomPokemon();
} else { } else {
// Wrong // Wrong
if (mounted) {
setState(() { setState(() {
_lives--; _lives--;
}); });
}
if (_lives <= 0) { if (_lives <= 0) {
if (mounted) {
setState(() {
_currentScore = 0; // Reset score only when all lives are lost
});
}
if (!mounted) return; if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Out of lives! It was ${_currentPokemon!.formatedName}.'), backgroundColor: Colors.red), SnackBar(content: Text('Out of lives! It was ${_currentPokemon!.formatedName}.'), backgroundColor: Colors.red),
@ -119,6 +169,17 @@ class _GuessPageState extends State<GuessPage> {
); );
} }
String _normalizeString(String input) {
var withDia = 'ÀÁÂÃÄÅàáâãäåÒÓÔÕÖØòóôõöøÈÉÊËèéêëÇçÌÍÎÏìíîïÙÚÛÜùúûüÿÑñ';
var withoutDia = 'AAAAAAaaaaaaOOOOOOooooooEEEEeeeeCcIIIIiiiiUUUUuuuuyNn';
String output = input;
for (int i = 0; i < withDia.length; i++) {
output = output.replaceAll(withDia[i], withoutDia[i]);
}
return output;
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (_isLoading) { if (_isLoading) {
@ -165,7 +226,10 @@ class _GuessPageState extends State<GuessPage> {
child: Padding( child: Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: ColorFiltered( child: ColorFiltered(
colorFilter: const ColorFilter.mode(Colors.black, BlendMode.srcIn), colorFilter: ColorFilter.mode(
_isShiny ? Colors.yellow[700]! : Colors.black,
BlendMode.srcIn
),
child: Image.network(_currentPokemon!.imageUrl, fit: BoxFit.contain), child: Image.network(_currentPokemon!.imageUrl, fit: BoxFit.contain),
), ),
), ),
@ -174,12 +238,12 @@ class _GuessPageState extends State<GuessPage> {
color: const Color(0xFF1B2333), color: const Color(0xFF1B2333),
width: double.infinity, width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 8), padding: const EdgeInsets.symmetric(vertical: 8),
child: const Text( child: Text(
"WHO'S THAT POKÉMON?", _isShiny ? "✨ SHINY POKÉMON DETECTED! ✨" : "WHO'S THAT POKÉMON?",
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
color: Colors.white, color: _isShiny ? Colors.yellow[400] : Colors.white,
fontSize: 22, fontSize: _isShiny ? 18 : 22,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
letterSpacing: 2, letterSpacing: 2,
), ),
@ -275,10 +339,39 @@ class _GuessPageState extends State<GuessPage> {
), ),
], ],
), ),
const SizedBox(height: 24),
// Score Display
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(
"$_currentScore",
style: const TextStyle(fontSize: 32, fontWeight: FontWeight.bold, color: Color(0xFF3B6EE3)),
),
const Divider(height: 24),
Text(
"PERSONAL BEST: $_bestScore",
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black87),
),
], ],
), ),
), ),
const SizedBox(height: 24), ],
),
),
const SizedBox(height: 32),
], ],
), ),
), ),

View File

@ -15,7 +15,6 @@ class _MainPageState extends State<MainPage> {
final List<Widget> _pages = [ final List<Widget> _pages = [
const PokemonListPage(), const PokemonListPage(),
const GuessPage(), const GuessPage(),
const Center(child: Text("TRAINER PAGE placeholder")),
const Center(child: Text("SYSTEM PAGE placeholder")), const Center(child: Text("SYSTEM PAGE placeholder")),
]; ];
@ -34,12 +33,20 @@ class _MainPageState extends State<MainPage> {
), ),
child: ClipRRect( child: ClipRRect(
borderRadius: BorderRadius.circular(26), borderRadius: BorderRadius.circular(26),
child: _pages[_currentIndex], child: IndexedStack(
index: _currentIndex,
children: _pages,
), ),
), ),
), ),
), ),
bottomNavigationBar: BottomNavigationBar( ),
bottomNavigationBar: Theme(
data: Theme.of(context).copyWith(
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
),
child: BottomNavigationBar(
currentIndex: _currentIndex, currentIndex: _currentIndex,
onTap: (index) { onTap: (index) {
setState(() { setState(() {
@ -58,16 +65,13 @@ class _MainPageState extends State<MainPage> {
icon: Icon(Icons.games), icon: Icon(Icons.games),
label: 'GUESS', label: 'GUESS',
), ),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: 'TRAINER',
),
BottomNavigationBarItem( BottomNavigationBarItem(
icon: Icon(Icons.settings), icon: Icon(Icons.settings),
label: 'SYSTEM', label: 'SYSTEM',
), ),
], ],
), ),
),
); );
} }
} }

View File

@ -135,10 +135,14 @@ class _PokemonDetailPageState extends State<PokemonDetailPage> {
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Expanded(
child: Text(
pokemon.formatedName.toUpperCase(), pokemon.formatedName.toUpperCase(),
style: const TextStyle(color: Colors.white, fontSize: 22, fontWeight: FontWeight.bold, letterSpacing: 2), style: const TextStyle(color: Colors.white, fontSize: 22, fontWeight: FontWeight.bold, letterSpacing: 2),
overflow: TextOverflow.ellipsis,
), ),
),
const SizedBox(width: 8),
Row( Row(
children: [ children: [
PokemonTypeWidget(pokemon.type1), PokemonTypeWidget(pokemon.type1),

View File

@ -14,62 +14,76 @@ class PokemonListPage extends StatefulWidget {
class _PokemonListPageState extends State<PokemonListPage> { class _PokemonListPageState extends State<PokemonListPage> {
String _filter = 'ALL'; // ALL, CAUGHT, NEW String _filter = 'ALL'; // ALL, CAUGHT, NEW
int _caughtCount = 0; int _caughtCount = 0;
List<Pokemon> _allPokemon = [];
List<Pokemon> _filteredPokemon = [];
bool _isSyncing = false;
final ScrollController _scrollController = ScrollController();
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_loadPokemonData(); _loadPokemonData();
PokedexDatabase.onDatabaseUpdate.addListener(_loadPokemonData);
}
@override
void dispose() {
PokedexDatabase.onDatabaseUpdate.removeListener(_loadPokemonData);
_scrollController.dispose();
super.dispose();
} }
Future<void> _loadPokemonData() async { Future<void> _loadPokemonData() async {
setState(() => _isSyncing = true);
final count = await PokedexDatabase.getCaughtCount(); final count = await PokedexDatabase.getCaughtCount();
setState(() {
_caughtCount = count;
});
// Check if database is empty for initial sync // Check if database is empty for initial sync
List<Pokemon> localData = await PokedexDatabase.getPokemonList(); List<Pokemon> localData = await PokedexDatabase.getPokemonList();
if(localData.isEmpty) { if(localData.isEmpty) {
try { try {
final List<Pokemon> remoteData = await PokemonApi.getAllPokemon(); final List<Pokemon> remoteData = await PokemonApi.getAllPokemon();
// Insert first 151 // Insert all
for (var p in remoteData) { for (var p in remoteData) {
if(p.id > 151) break;
await PokedexDatabase.insertPokemon(p); await PokedexDatabase.insertPokemon(p);
} }
localData = await PokedexDatabase.getPokemonList();
} catch (e) { } catch (e) {
debugPrint(e.toString()); debugPrint(e.toString());
} }
} }
// Sort by ID to ensure order
localData.sort((a, b) => a.id.compareTo(b.id));
if (mounted) { if (mounted) {
setState(() {}); setState(() {
_allPokemon = localData;
_caughtCount = count;
_applyFilter();
_isSyncing = false;
});
}
}
void _applyFilter() {
setState(() {
if (_filter == 'ALL') {
_filteredPokemon = _allPokemon;
} else if (_filter == 'CAUGHT') {
_filteredPokemon = _allPokemon.where((p) => p.isCaught).toList();
}
});
// Reset scroll position to top when filter changes
if (_scrollController.hasClients) {
_scrollController.jumpTo(0);
} }
} }
Widget _buildPokemonTile(BuildContext context, int index) { Widget _buildPokemonTile(BuildContext context, int index) {
return FutureBuilder<Pokemon?>( final pokemon = _filteredPokemon[index];
future: PokedexDatabase.getPokemon(index + 1),
builder: (context, snapshot) {
if (!snapshot.hasData || snapshot.data == null) {
return const SizedBox(
height: 90,
child: Center(child: 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); return PokemonTile(pokemon);
},
);
} }
@override @override
@ -89,7 +103,7 @@ class _PokemonListPageState extends State<PokemonListPage> {
children: [ children: [
Icon(Icons.menu, color: Colors.black87), Icon(Icons.menu, color: Colors.black87),
Text( Text(
'LIST - KANTO', 'LIST - NATIONAL',
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold, letterSpacing: 2), style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold, letterSpacing: 2),
), ),
Icon(Icons.search, color: Colors.black87), Icon(Icons.search, color: Colors.black87),
@ -104,7 +118,6 @@ class _PokemonListPageState extends State<PokemonListPage> {
children: [ children: [
_buildTab('ALL', _filter == 'ALL'), _buildTab('ALL', _filter == 'ALL'),
_buildTab('CAUGHT', _filter == 'CAUGHT'), _buildTab('CAUGHT', _filter == 'CAUGHT'),
_buildTab('NEW', _filter == 'NEW'),
], ],
), ),
), ),
@ -119,7 +132,7 @@ class _PokemonListPageState extends State<PokemonListPage> {
child: Column( child: Column(
children: [ children: [
Text( Text(
'${_caughtCount.toString().padLeft(3, '0')} / 151', '${_caughtCount.toString().padLeft(3, '0')} / ${_allPokemon.length}',
style: const TextStyle(fontSize: 32, fontWeight: FontWeight.bold), style: const TextStyle(fontSize: 32, fontWeight: FontWeight.bold),
), ),
const Text( const Text(
@ -146,9 +159,27 @@ class _PokemonListPageState extends State<PokemonListPage> {
), ),
), ),
), ),
if (_isSyncing && _allPokemon.isEmpty)
const Center(child: CircularProgressIndicator())
else if (_filteredPokemon.isEmpty)
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.search_off, size: 64, color: Colors.black26),
const SizedBox(height: 16),
Text(
'NO POKEMON FOUND IN $_filter',
style: const TextStyle(color: Colors.black45, fontSize: 18, fontWeight: FontWeight.bold),
),
],
),
)
else
ListView.builder( ListView.builder(
controller: _scrollController,
padding: const EdgeInsets.all(12), padding: const EdgeInsets.all(12),
itemCount: 151, itemCount: _filteredPokemon.length,
itemBuilder: _buildPokemonTile, itemBuilder: _buildPokemonTile,
), ),
], ],
@ -161,7 +192,7 @@ class _PokemonListPageState extends State<PokemonListPage> {
color: const Color(0xFF1B2333), color: const Color(0xFF1B2333),
alignment: Alignment.center, alignment: Alignment.center,
child: const Text( child: const Text(
'KANTO REGIONAL POKEDEX V2.0', 'NATIONAL POKEDEX V2.0',
style: TextStyle(color: Colors.white70, fontSize: 12, letterSpacing: 1), style: TextStyle(color: Colors.white70, fontSize: 12, letterSpacing: 1),
), ),
), ),
@ -174,9 +205,10 @@ class _PokemonListPageState extends State<PokemonListPage> {
return Expanded( return Expanded(
child: GestureDetector( child: GestureDetector(
onTap: () { onTap: () {
setState(() { if (_filter != title) {
_filter = title; _filter = title;
}); _applyFilter();
}
}, },
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(

View File

@ -5,10 +5,12 @@
import FlutterMacOS import FlutterMacOS
import Foundation import Foundation
import shared_preferences_foundation
import sqflite_darwin import sqflite_darwin
import sqlite3_flutter_libs import sqlite3_flutter_libs
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
Sqlite3FlutterLibsPlugin.register(with: registry.registrar(forPlugin: "Sqlite3FlutterLibsPlugin")) Sqlite3FlutterLibsPlugin.register(with: registry.registrar(forPlugin: "Sqlite3FlutterLibsPlugin"))
} }

View File

@ -1,5 +1,8 @@
PODS: PODS:
- FlutterMacOS (1.0.0) - FlutterMacOS (1.0.0)
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- sqflite_darwin (0.0.4): - sqflite_darwin (0.0.4):
- Flutter - Flutter
- FlutterMacOS - FlutterMacOS
@ -31,6 +34,7 @@ PODS:
DEPENDENCIES: DEPENDENCIES:
- FlutterMacOS (from `Flutter/ephemeral`) - FlutterMacOS (from `Flutter/ephemeral`)
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
- sqflite_darwin (from `Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin`) - sqflite_darwin (from `Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin`)
- sqlite3_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/darwin`) - sqlite3_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/darwin`)
@ -41,6 +45,8 @@ SPEC REPOS:
EXTERNAL SOURCES: EXTERNAL SOURCES:
FlutterMacOS: FlutterMacOS:
:path: Flutter/ephemeral :path: Flutter/ephemeral
shared_preferences_foundation:
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin
sqflite_darwin: sqflite_darwin:
:path: Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin :path: Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin
sqlite3_flutter_libs: sqlite3_flutter_libs:
@ -48,6 +54,7 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS: SPEC CHECKSUMS:
FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0 sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
sqlite3: 8d708bc63e9f4ce48f0ad9d6269e478c5ced1d9b sqlite3: 8d708bc63e9f4ce48f0ad9d6269e478c5ced1d9b
sqlite3_flutter_libs: d13b8b3003f18f596e542bcb9482d105577eff41 sqlite3_flutter_libs: d13b8b3003f18f596e542bcb9482d105577eff41

View File

@ -25,6 +25,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 google_fonts: ^8.0.2
shared_preferences: ^2.5.4
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: