import 'package:flutter/material.dart'; import 'package:nfc_manager/nfc_manager.dart'; import 'dart:typed_data'; // Pour convertir l'UID import 'google_sheets_api.dart'; // <-- ON IMPORTE NOTRE API import 'inscription_page.dart'; import 'sheet_view_page.dart'; void main() { WidgetsFlutterBinding.ensureInitialized(); runApp(const MaterialApp( debugShowCheckedModeBanner: false, home: SimpleNfcReader(), )); } class SimpleNfcReader extends StatefulWidget { const SimpleNfcReader({super.key}); @override State createState() => _SimpleNfcReaderState(); } class _SimpleNfcReaderState extends State { bool _isReading = false; String _status = 'Appuyez sur le bouton pour vérifier un étudiant'; // Instance de notre API Google Sheets final GoogleSheetsApi _sheetsApi = GoogleSheetsApi(); // Dernières informations lues (UID etc.) final Map _info = {}; Future _startNfc() async { bool available = await NfcManager.instance.isAvailable(); if (!available) { setState(() => _status = '❌ NFC non disponible sur cet appareil'); return; } setState(() { _isReading = true; _status = '🔄 Approchez une carte étudiant...'; }); NfcManager.instance.startSession( pollingOptions: { NfcPollingOption.iso14443, NfcPollingOption.iso15693, NfcPollingOption.iso18092, }, onDiscovered: (NfcTag tag) async { String? uid; try { // --- 1. Récupérer le numéro de série (UID) --- dynamic data; try { data = (tag as dynamic).data; } catch (_) {} final idBytes = _safeLookup(data, 'id'); if (idBytes != null) { uid = _bytesToHexString(idBytes); } if (uid == null) { setState(() => _status = '❌ Impossible de lire le N° de série.'); await NfcManager.instance.stopSession(); setState(() => _isReading = false); return; } // --- 2. Vérifier dans Google Sheets --- setState(() => _status = '🔄 N° de série: $uid\nVérification en cours...'); // On arrête le scan NFC pendant qu'on contacte la base de données await NfcManager.instance.stopSession(); // Appel de notre NOUVELLE fonction String? nomEtudiant = await _sheetsApi.findStudentNameByNfcUid(uid); // --- 3. Afficher le résultat final --- setState(() { if (nomEtudiant != null) { _status = '✅ Bienvenue, $nomEtudiant !'; } else { _status = '❌ Étudiant inexistant.\nN°: $uid'; } }); } catch (e) { setState(() { _status = 'Erreur: ${e.toString()}'; }); await NfcManager.instance.stopSession(); } // On a fini, on réactive le bouton setState(() => _isReading = false); }, ); } // --- Fonctions utilitaires (inchangées) --- String _bytesToHexString(dynamic maybeBytes) { try { Uint8List bytes; if (maybeBytes is Uint8List) bytes = maybeBytes; else if (maybeBytes is List) bytes = Uint8List.fromList(maybeBytes); else return maybeBytes.toString(); return bytes.map((b) => b.toRadixString(16).padLeft(2, '0').toUpperCase()).join(''); } catch (_) { return maybeBytes.toString(); } } dynamic _safeLookup(dynamic obj, String key) { if (obj == null) return null; try { if (obj is Map) { if (obj.containsKey(key)) return obj[key]; final lower = key.toLowerCase(); if (obj.containsKey(lower)) return obj[lower]; } } catch (_) {} try { return (obj as dynamic)[key]; } catch (_) {} try { if (key == 'id') return (obj as dynamic).id; } catch (_) {} return null; } /// L'interface utilisateur @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('📡 Lecteur NFC simple')), drawer: Drawer( child: SafeArea( child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ DrawerHeader( decoration: BoxDecoration(color: Theme.of(context).colorScheme.primaryContainer), child: const Center(child: Text('Menu', style: TextStyle(fontSize: 20))), ), ListTile( leading: const Icon(Icons.person_add), title: const Text('Inscription'), onTap: () async { Navigator.of(context).pop(); final prefMac = _info['Numéro de série'] ?? _info['UID brute']; await Navigator.of(context).push(MaterialPageRoute(builder: (_) => InscriptionPage(prefilledMac: prefMac))); }, ), ListTile( leading: const Icon(Icons.table_chart), title: const Text('Liste des données'), onTap: () async { Navigator.of(context).pop(); await Navigator.of(context).push(MaterialPageRoute(builder: (_) => const SheetViewPage())); }, ), const Divider(), ListTile( leading: const Icon(Icons.info_outline), title: const Text('A propos'), onTap: () => showAboutDialog( context: context, applicationName: 'NFC Reader', children: [const Text('Lecteur NFC et gestion des inscriptions')], ), ), ], ), ), ), body: Padding( padding: const EdgeInsets.all(20), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Icon( _isReading ? Icons.nfc : Icons.school, size: 100, color: Colors.blueAccent, ), const SizedBox(height: 30), Text( _status, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), textAlign: TextAlign.center, ), const Spacer(), Center( child: ElevatedButton.icon( onPressed: _isReading ? null : _startNfc, icon: _isReading ? const SizedBox( width: 20, height: 20, child: CircularProgressIndicator(color: Colors.white, strokeWidth: 2), ) : const Icon(Icons.nfc), label: Text(_isReading ? 'Lecture en cours...' : 'Vérifier la carte'), style: ElevatedButton.styleFrom( padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 15), ), ), ), const SizedBox(height: 10), ], ), ), ); } }