import 'dart:convert'; import 'package:flutter/services.dart' show rootBundle; import 'package:googleapis_auth/auth_io.dart' as auth; import 'package:googleapis/sheets/v4.dart' as sheets; class GoogleSheetsApi { // 1. l'ID de feuille static const _spreadsheetId = '1tbWnNSx3J-OAM7rrAxU_YLM97z2zMFtV055nS66Ig3c'; // 2. Définir les permissions static const _scopes = [sheets.SheetsApi.spreadsheetsScope]; // 3. Fonction pour s'authentifier (utilise le fichier JSON) Future _getAuthClient() async { try { final jsonString = await rootBundle.loadString('assets/credentials.json'); final credentialsJson = json.decode(jsonString); final credentials = auth.ServiceAccountCredentials.fromJson(credentialsJson); final client = await auth.clientViaServiceAccount(credentials, _scopes); return client; } catch (e) { print('Erreur lors de l\'authentification : $e'); return null; } } // 4. Fonction pour ajouter une nouvelle ligne Future appendData(List rowData) async { final client = await _getAuthClient(); if (client == null) { print("Erreur d'authentification"); return false; } final api = sheets.SheetsApi(client); // Le nom de votre feuille (ex: 'Feuille1') final String range = 'données etudiants'; var values = sheets.ValueRange.fromJson({ 'values': [ rowData ] // Les données à ajouter }); try { await api.spreadsheets.values.append( values, _spreadsheetId, range, valueInputOption: 'RAW' ); print('Données ajoutées !'); client.close(); return true; } catch (e) { print('Erreur lors de l\'ajout des données : $e'); client.close(); return false; } } // 5. Fonction pour lire des données (exemple) Future>?> readData() async { final client = await _getAuthClient(); if (client == null) { print("Erreur d'authentification"); return null; } final api = sheets.SheetsApi(client); final String range = 'données etudiants!A1:C10'; try { final result = await api.spreadsheets.values.get( _spreadsheetId, range, ); print('Données lues : ${result.values}'); client.close(); return result.values; } catch (e) { print('Erreur lors de la lecture des données : $e'); client.close(); return null; } } // 6. NOUVELLE FONCTION : Lire toutes les valeurs d'une colonne Future> readColumn(String columnName) async { final client = await _getAuthClient(); if (client == null) { print("Erreur d'authentification"); return []; } final api = sheets.SheetsApi(client); final String range = 'données etudiants!$columnName:$columnName'; try { final result = await api.spreadsheets.values.get( _spreadsheetId, range, ); client.close(); if (result.values == null) { return []; // La colonne est vide } // Convertir la List> en une simple List List columnData = []; for (var row in result.values!) { if (row.isNotEmpty) { columnData.add(row[0].toString()); } } return columnData; } catch (e) { print('Erreur lors de la lecture de la colonne : $e'); client.close(); return []; } } // 7. FONCTION MODIFIÉE : Trouver un nom par l'UID (stocké en Colonne D) Future findStudentNameByNfcUid(String uidToCheck) async { final client = await _getAuthClient(); if (client == null) { print("Erreur d'authentification"); return null; } final api = sheets.SheetsApi(client); // On lit les colonnes Nom (C) et Mac (D). final String range = 'données etudiants!C:D'; try { final result = await api.spreadsheets.values.get( _spreadsheetId, range, ); client.close(); if (result.values == null) { print("La feuille est vide ou n'a pas pu être lue."); return null; } final uidUpper = uidToCheck.toUpperCase(); for (int i = 0; i < result.values!.length; i++) { final row = result.values![i]; if (row.length == 2 && row[1] != null) { String nfcUidFromSheet = row[1].toString().toUpperCase(); if (nfcUidFromSheet == uidUpper) { await updateLastScan(i + 2, "F"); return row[0].toString(); } } } print("UID non trouvé dans la feuille."); return null; } catch (e) { print('Erreur lors de la recherche de l\'UID : $e'); client.close(); return null; } } // 8. Récupérer la liste de présence par date (pour le PDF) Future>> getPresenceByDate(String date) async { final client = await _getAuthClient(); if (client == null) return []; final api = sheets.SheetsApi(client); final String range = 'données etudiants!A:F'; final result = await api.spreadsheets.values.get(_spreadsheetId, range); client.close(); if (result.values == null) return []; List> resultList = []; for (int i = 1; i < result.values!.length; i++) { final row = result.values![i]; final dateAjout = row.length > 5 ? row[5]?.toString() ?? "" : ""; if (dateAjout.startsWith(date)) { resultList.add({ 'N° Etudiant': row.length > 0 ? row[0]?.toString() ?? '' : '', 'Prénom': row.length > 1 ? row[1]?.toString() ?? '' : '', 'Nom': row.length > 2 ? row[2]?.toString() ?? '' : '', 'Mac NFC': row.length > 3 ? row[3]?.toString() ?? '' : '', 'QR': row.length > 4 ? row[4]?.toString() ?? '' : '', 'date_ajout': dateAjout, }); } } return resultList; } Future updateLastScan(int rowIndex, String columnLetter) async { final client = await _getAuthClient(); if (client == null) return; final api = sheets.SheetsApi(client); final now = DateTime.now().toIso8601String(); final range = 'données etudiants!$columnLetter$rowIndex'; final oldResult = await api.spreadsheets.values.get(_spreadsheetId, range); String newValue = now; if (oldResult.values != null && oldResult.values!.isNotEmpty && oldResult.values!.first.isNotEmpty) { final oldValue = oldResult.values!.first.first.toString().trim(); if (!oldValue.endsWith(now)) { newValue = "$oldValue;$now"; } else { newValue = oldValue; } } final values = sheets.ValueRange.fromJson({ "values": [[newValue]] }); await api.spreadsheets.values.update( values, _spreadsheetId, range, valueInputOption: "RAW", ); client.close(); } Future findStudentNameByQr(String qrValue) async { final client = await _getAuthClient(); if (client == null) { print("Erreur d'authentification"); return null; } final api = sheets.SheetsApi(client); final String range = 'données etudiants!A:F'; try { final result = await api.spreadsheets.values.get( _spreadsheetId, range, ); client.close(); if (result.values == null) { print("La feuille est vide ou n'a pas pu être lue."); return null; } // Parcourt chaque ligne for (int i = 0; i < result.values!.length; i++) { final row = result.values![i]; if (row.length > 4 && row[4] != null) { String qrFromSheet = row[4].toString(); if (qrFromSheet == qrValue) { await updateLastScan(i + 2, "F"); return row[2].toString(); } } } print("QR code non trouvé dans la feuille."); return null; } catch (e) { print('Erreur lors de la recherche du QR : $e'); client.close(); return null; } } Future findRowByStudentNumber(String studentNumber) async { final client = await _getAuthClient(); if (client == null) return null; final api = sheets.SheetsApi(client); final range = 'données etudiants!A:A'; final result = await api.spreadsheets.values.get( _spreadsheetId, range, ); client.close(); if (result.values == null) return null; for (int i = 0; i < result.values!.length; i++) { if (result.values![i].isNotEmpty && result.values![i][0].toString() == studentNumber) { return i + 1; // index réel Google Sheets } } return null; } Future updateStudentFields({ required int rowIndex, String? nfc, String? qr, }) async { final client = await _getAuthClient(); if (client == null) return false; final api = sheets.SheetsApi(client); List> updates = []; if (nfc != null && nfc.isNotEmpty) { updates.add(['D$rowIndex', nfc]); } if (qr != null && qr.isNotEmpty) { updates.add(['E$rowIndex', qr]); } for (var u in updates) { await api.spreadsheets.values.update( sheets.ValueRange.fromJson({'values': [[u[1]]]}), _spreadsheetId, 'données etudiants!${u[0]}', valueInputOption: 'USER_ENTERED', ); } client.close(); return true; } Future>> getAllPresences() async { final client = await _getAuthClient(); if (client == null) return []; final api = sheets.SheetsApi(client); final result = await api.spreadsheets.values.get( _spreadsheetId, 'données etudiants!A:F', ); client.close(); if (result.values == null || result.values!.length <= 1) return []; final rows = result.values!; final List> data = []; for (int i = 1; i < rows.length; i++) { // skip header final row = rows[i]; data.add({ 'N° Etudiant': row.length > 0 ? row[0].toString() : '', 'Prénom': row.length > 1 ? row[1].toString() : '', 'Nom': row.length > 2 ? row[2].toString() : '', 'Mac NFC': row.length > 3 ? row[3].toString() : '', 'QR': row.length > 4 ? row[4].toString() : '', 'date_ajout': row.length > 5 ? row[5].toString() : '', // LISTE DES DATES }); } return data; } }