Newer
Older
import 'package:nfc_google_sheet/components/selection_indicator.dart';
import 'package:nfc_google_sheet/components/student_form.dart';
import 'package:nfc_google_sheet/components/wide_button.dart';
import 'package:flutter_nfc_kit/flutter_nfc_kit.dart';
import 'package:nfc_google_sheet/context/app_colors.dart';
import 'package:nfc_google_sheet/database/student_dao.dart';
import 'package:nfc_google_sheet/database/attendance_dao.dart';
import 'package:nfc_google_sheet/pages/sheet_page.dart';
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
class _HomePageState extends State<HomePage> {
String nfcData = "Appuyez sur une carte NFC";
ScanStatus _scanStatus = ScanStatus.idle;
void _handleAttendanceResult(AttendanceResult result, String promotion) {
switch (result) {
case AttendanceResult.success:
setState(() {
nfcData = "Émargement enregistré !";
_scanStatus = ScanStatus.success;
});
case AttendanceResult.alreadyScanned:
setState(() {
nfcData = "Cet étudiant a déjà émargé pour cet examen.";
_scanStatus = ScanStatus.error;
});
case AttendanceResult.wrongPromotion:
setState(() {
nfcData = "Mauvaise promotion : $promotion (attendu : ${SheetPage.selectedProgram})";
_scanStatus = ScanStatus.error;
});
}
}
if (SheetPage.selectedProgram == null || SheetPage.selectedSubject == null) {
setState(() {
nfcData = "Veuillez d'abord sélectionner une filière et une matière.";
_scanStatus = ScanStatus.error;
});
return;
}
try {
var availability = await FlutterNfcKit.nfcAvailability;
if (availability != NFCAvailability.available) {
setState(() {
nfcData = "NFC non disponible ou désactivé.";
_scanStatus = ScanStatus.error;
});
return;
}
nfcData = "En attente d'une carte NFC...";
_scanStatus = ScanStatus.scanning;
NFCTag tag = await FlutterNfcKit.poll(timeout: Duration(seconds: 15));
final cardId = tag.id;
final existingStudent = await StudentDao.instance.getByCardId(cardId);
if (existingStudent != null) {
final result = await AttendanceDao.instance.register(
cardId, existingStudent.promotion, SheetPage.selectedProgram!, SheetPage.selectedSubject!,
);
_handleAttendanceResult(result, existingStudent.promotion);
nfcData = "Nouvel étudiant détecté";
if (!mounted) return;
showDialog(
context: context,
builder: (BuildContext context) {
return StudentForm(
cardId: cardId,
onStudentSaved: (student) async {
final result = await AttendanceDao.instance.register(
cardId, student.promotion, SheetPage.selectedProgram!, SheetPage.selectedSubject!,
);
_handleAttendanceResult(result, student.promotion);
},
);
},
);
}
} catch (e) {
setState(() {
nfcData = "Erreur ou scan annulé.";
_scanStatus = ScanStatus.error;
});
} finally {
await FlutterNfcKit.finish();
if (_scanStatus == ScanStatus.scanning) {
setState(() {
_scanStatus = ScanStatus.idle;
nfcData = "Appuyez sur une carte NFC";
});
}
}
Widget _buildStatusIcon() {
switch (_scanStatus) {
case ScanStatus.scanning:
return SizedBox(
width: 120,
height: 120,
child: CircularProgressIndicator(
color: AppColors.selected,
strokeWidth: 6,
),
);
case ScanStatus.success:
return Icon(Icons.check_circle_outline, color: AppColors.selected, size: 120);
return Icon(Icons.error_outline, color: Colors.red.shade400, size: 120);
return Icon(Icons.nfc, color: AppColors.unselected.withValues(alpha: 0.7), size: 120);
}
}
Widget _buildStatusText() {
Color textColor;
switch (_scanStatus) {
case ScanStatus.success:
textColor = AppColors.selected;
case ScanStatus.error:
textColor = Colors.red.shade400;
default:
textColor = AppColors.unselected;
}
return Container(
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 12),
decoration: BoxDecoration(
color: AppColors.subtitle.withValues(alpha: 0.5),
borderRadius: BorderRadius.circular(12),
),
child: Text(
nfcData,
textAlign: TextAlign.center,
style: TextStyle(color: textColor, fontSize: 16, fontWeight: FontWeight.w500),
@override
Widget build(BuildContext context) {
bool isScanning = _scanStatus == ScanStatus.scanning;
backgroundColor: AppColors.background,
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
children: [
TitleCustom(content: 'ENREGISTREZ - VOUS'),
SizedBox(height: 12),
SelectionIndicator(),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_buildStatusIcon(),
SizedBox(height: 30),
_buildStatusText(),
],
),
),
WideButton(
onPressed: isScanning ? null : startNFC,
icon: Icons.nfc,
label: isScanning ? "SCAN EN COURS..." : "ENREGISTRER SA CARTE",
backgroundColor: AppColors.selected,
foregroundColor: AppColors.background,
disabledBackgroundColor: AppColors.selected.withValues(alpha: 0.5),
letterSpacing: 1.1,
}
enum ScanStatus {
idle,
scanning,
success,
error,