Files
EME_APP/eme-frontend/lib/widgets/etat_checklist.dart
T
2026-07-07 13:22:53 +02:00

227 lines
6.3 KiB
Dart

import "package:flutter/material.dart";
import "package:google_fonts/google_fonts.dart";
import "../theme/ensup_colors.dart";
/// État possible d'un élément de checklist (départ ou retour).
enum EtatChecklist { present, absent, deteriore }
/// Case cliquable colorée selon l'état sélectionné (vert / rouge / jaune).
class EtatBox extends StatelessWidget {
const EtatBox({
super.key,
required this.type,
required this.selected,
required this.onTap,
});
final EtatChecklist type;
final bool selected;
final VoidCallback onTap;
@override
Widget build(BuildContext context) {
var background = Colors.white;
var border = EnsupColors.line;
Widget? contenu;
if (selected) {
switch (type) {
case EtatChecklist.present:
background = const Color(0xFFF0FDF4);
border = const Color(0xFF86EFAC);
contenu = const Icon(Icons.check, size: 16, color: Color(0xFF16A34A));
case EtatChecklist.absent:
background = const Color(0xFFFEF2F2);
border = const Color(0xFFFCA5A5);
contenu = const Icon(Icons.close, size: 16, color: EnsupColors.red);
case EtatChecklist.deteriore:
background = const Color(0xFFFFFBEB);
border = const Color(0xFFFDE68A);
contenu = const Icon(Icons.priority_high, size: 16, color: Color(0xFFD97706));
}
}
return InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(8),
child: Container(
width: 36,
height: 36,
decoration: BoxDecoration(
color: background,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: border, width: 2),
),
child: contenu,
),
);
}
}
/// Tableau de checklist : une ligne par accessoire avec les 3 états possibles.
class ChecklistTableau extends StatelessWidget {
const ChecklistTableau({
super.key,
required this.accessoires,
required this.etats,
required this.onChanged,
});
final List<String> accessoires;
final List<EtatChecklist> etats;
final void Function(int index, EtatChecklist etat) onChanged;
@override
Widget build(BuildContext context) {
return Column(
children: [
_entete(),
for (var i = 0; i < accessoires.length; i++) _ligne(i),
],
);
}
Widget _entete() {
return Container(
padding: const EdgeInsets.symmetric(vertical: 10),
decoration: const BoxDecoration(
border: Border(bottom: BorderSide(color: EnsupColors.line, width: 2)),
),
child: Row(
children: [
Expanded(child: _texteEntete("ÉLÉMENT")),
_colonneEntete("PRÉSENT"),
_colonneEntete("ABSENT"),
_colonneEntete("DÉTÉRIORÉ"),
],
),
);
}
Widget _texteEntete(String label) {
return Text(
label,
style: GoogleFonts.darkerGrotesque(
fontSize: 12,
fontWeight: FontWeight.w700,
color: EnsupColors.muted,
letterSpacing: 0.6,
),
);
}
Widget _colonneEntete(String label) {
return SizedBox(width: 72, child: Center(child: _texteEntete(label)));
}
Widget _ligne(int index) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 10),
decoration: const BoxDecoration(
border: Border(bottom: BorderSide(color: EnsupColors.line)),
),
child: Row(
children: [
Expanded(
child: Text(
accessoires[index],
style: GoogleFonts.titilliumWeb(fontSize: 14, color: EnsupColors.text2),
),
),
_case(index, EtatChecklist.present),
_case(index, EtatChecklist.absent),
_case(index, EtatChecklist.deteriore),
],
),
);
}
Widget _case(int index, EtatChecklist type) {
return SizedBox(
width: 72,
child: Center(
child: EtatBox(
type: type,
selected: etats[index] == type,
onTap: () => onChanged(index, type),
),
),
);
}
}
/// Encadré d'instructions / rappel à côté d'une checklist.
class ChecklistInstructions extends StatelessWidget {
const ChecklistInstructions({super.key, required this.titre, required this.texte});
final String titre;
final String texte;
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: EnsupColors.blue2.withValues(alpha: 0.05),
borderRadius: BorderRadius.circular(10),
border: Border.all(color: EnsupColors.blue2.withValues(alpha: 0.15), width: 1.5),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
titre.toUpperCase(),
style: GoogleFonts.darkerGrotesque(
fontSize: 12,
fontWeight: FontWeight.w700,
color: EnsupColors.muted,
letterSpacing: 0.6,
),
),
const SizedBox(height: 8),
Text(
texte,
style: GoogleFonts.titilliumWeb(fontSize: 13, color: EnsupColors.text2, height: 1.6),
),
],
),
);
}
}
/// Zone de commentaire optionnel sous une checklist.
class ChecklistCommentaire extends StatelessWidget {
const ChecklistCommentaire({
super.key,
this.controller,
this.hint = "Commentaire ou observation optionnelle...",
});
final TextEditingController? controller;
final String hint;
@override
Widget build(BuildContext context) {
return TextField(
controller: controller,
maxLines: 4,
style: GoogleFonts.titilliumWeb(fontSize: 13, color: EnsupColors.text),
decoration: InputDecoration(
hintText: hint,
hintStyle: GoogleFonts.titilliumWeb(fontSize: 13, color: EnsupColors.muted),
filled: true,
fillColor: Colors.white,
contentPadding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(9),
borderSide: const BorderSide(color: EnsupColors.line, width: 1.5),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(9),
borderSide: const BorderSide(color: EnsupColors.cyan, width: 1.5),
),
),
);
}
}