2 Commits

Author SHA1 Message Date
SaidSoighiri94 1b6f859074 merge: responsable table scrollbars 2026-07-24 16:43:32 +02:00
SaidSoighiri94 d02d47fb87 fix(responsable): show horizontal table scrollbars 2026-07-24 16:40:08 +02:00
2 changed files with 227 additions and 188 deletions
+218 -187
View File
@@ -2238,6 +2238,57 @@ class _PanelEmptyState extends StatelessWidget {
}
}
class _TableauAvecDefilementHorizontal extends StatefulWidget {
const _TableauAvecDefilementHorizontal({
required this.largeurMinimale,
required this.child,
});
final double largeurMinimale;
final Widget child;
@override
State<_TableauAvecDefilementHorizontal> createState() =>
_TableauAvecDefilementHorizontalState();
}
class _TableauAvecDefilementHorizontalState
extends State<_TableauAvecDefilementHorizontal> {
final ScrollController _controleur = ScrollController();
@override
void dispose() {
_controleur.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Scrollbar(
controller: _controleur,
thumbVisibility: true,
trackVisibility: true,
interactive: true,
thickness: 8,
radius: const Radius.circular(4),
scrollbarOrientation: ScrollbarOrientation.bottom,
notificationPredicate: (notification) =>
notification.metrics.axis == Axis.horizontal,
child: SingleChildScrollView(
controller: _controleur,
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.only(bottom: 14),
child: ConstrainedBox(
constraints: BoxConstraints(minWidth: widget.largeurMinimale),
child: widget.child,
),
),
),
);
}
}
class _VueEmpruntsTableau extends StatelessWidget {
const _VueEmpruntsTableau({
required this.items,
@@ -2556,56 +2607,51 @@ class _VueEmpruntsTableau extends StatelessWidget {
color: Colors.white,
border: Border.all(color: EnsupColors.line),
),
child: SingleChildScrollView(
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: ConstrainedBox(
constraints: BoxConstraints(minWidth: largeurDisponible),
child: DataTable(
sortColumnIndex: _sortColumnIndex,
sortAscending: ordre == "asc",
headingRowColor: WidgetStatePropertyAll(
EnsupColors.soft.withValues(alpha: 0.8),
),
headingTextStyle: GoogleFonts.titilliumWeb(
fontSize: 12,
fontWeight: FontWeight.w700,
color: EnsupColors.text2,
),
dataTextStyle: GoogleFonts.titilliumWeb(
fontSize: 12,
color: EnsupColors.text,
),
columns: [
const DataColumn(label: Text("")),
DataColumn(
label: const Text("Matériel"),
onSort: (_, _) => onTri("materiel"),
),
DataColumn(
label: const Text("Étudiant"),
onSort: (_, _) => onTri("etudiant"),
),
DataColumn(
label: const Text("Date demprunt"),
onSort: (_, _) => onTri("dateEmprunt"),
),
DataColumn(
label: const Text("Retour prévu"),
onSort: (_, _) => onTri("dateRetourPrevue"),
),
DataColumn(
label: const Text("Retour réel"),
onSort: (_, _) => onTri("dateRetourReelle"),
),
DataColumn(
label: const Text("Statut"),
onSort: (_, _) => onTri("statut"),
),
],
rows: items.map(_ligneTableau).toList(),
),
child: _TableauAvecDefilementHorizontal(
largeurMinimale: largeurDisponible,
child: DataTable(
sortColumnIndex: _sortColumnIndex,
sortAscending: ordre == "asc",
headingRowColor: WidgetStatePropertyAll(
EnsupColors.soft.withValues(alpha: 0.8),
),
headingTextStyle: GoogleFonts.titilliumWeb(
fontSize: 12,
fontWeight: FontWeight.w700,
color: EnsupColors.text2,
),
dataTextStyle: GoogleFonts.titilliumWeb(
fontSize: 12,
color: EnsupColors.text,
),
columns: [
const DataColumn(label: Text("")),
DataColumn(
label: const Text("Matériel"),
onSort: (_, _) => onTri("materiel"),
),
DataColumn(
label: const Text("Étudiant"),
onSort: (_, _) => onTri("etudiant"),
),
DataColumn(
label: const Text("Date demprunt"),
onSort: (_, _) => onTri("dateEmprunt"),
),
DataColumn(
label: const Text("Retour prévu"),
onSort: (_, _) => onTri("dateRetourPrevue"),
),
DataColumn(
label: const Text("Retour réel"),
onSort: (_, _) => onTri("dateRetourReelle"),
),
DataColumn(
label: const Text("Statut"),
onSort: (_, _) => onTri("statut"),
),
],
rows: items.map(_ligneTableau).toList(),
),
),
),
@@ -3098,55 +3144,50 @@ class _VueMaterielsTableau extends StatelessWidget {
color: Colors.white,
border: Border.all(color: EnsupColors.line),
),
child: SingleChildScrollView(
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: ConstrainedBox(
constraints: BoxConstraints(minWidth: largeurDisponible),
child: DataTable(
sortColumnIndex: _sortColumnIndex,
sortAscending: ordre == "asc",
headingRowColor: WidgetStatePropertyAll(
EnsupColors.soft.withValues(alpha: 0.8),
),
headingTextStyle: GoogleFonts.titilliumWeb(
fontSize: 12,
fontWeight: FontWeight.w700,
color: EnsupColors.text2,
),
dataTextStyle: GoogleFonts.titilliumWeb(
fontSize: 12,
color: EnsupColors.text,
),
columns: [
DataColumn(
label: const Text("Référence"),
onSort: (_, _) => onTri("reference"),
),
DataColumn(
label: const Text("Matériel"),
onSort: (_, _) => onTri("nom"),
),
DataColumn(
label: const Text("Catégorie"),
onSort: (_, _) => onTri("categorie"),
),
DataColumn(
label: const Text("Marque / modèle"),
onSort: (_, _) => onTri("marque"),
),
DataColumn(
label: const Text("État"),
onSort: (_, _) => onTri("etatGeneral"),
),
DataColumn(
label: const Text("Statut"),
onSort: (_, _) => onTri("statut"),
),
],
rows: items.map(_ligneTableau).toList(),
),
child: _TableauAvecDefilementHorizontal(
largeurMinimale: largeurDisponible,
child: DataTable(
sortColumnIndex: _sortColumnIndex,
sortAscending: ordre == "asc",
headingRowColor: WidgetStatePropertyAll(
EnsupColors.soft.withValues(alpha: 0.8),
),
headingTextStyle: GoogleFonts.titilliumWeb(
fontSize: 12,
fontWeight: FontWeight.w700,
color: EnsupColors.text2,
),
dataTextStyle: GoogleFonts.titilliumWeb(
fontSize: 12,
color: EnsupColors.text,
),
columns: [
DataColumn(
label: const Text("Référence"),
onSort: (_, _) => onTri("reference"),
),
DataColumn(
label: const Text("Matériel"),
onSort: (_, _) => onTri("nom"),
),
DataColumn(
label: const Text("Catégorie"),
onSort: (_, _) => onTri("categorie"),
),
DataColumn(
label: const Text("Marque / modèle"),
onSort: (_, _) => onTri("marque"),
),
DataColumn(
label: const Text("État"),
onSort: (_, _) => onTri("etatGeneral"),
),
DataColumn(
label: const Text("Statut"),
onSort: (_, _) => onTri("statut"),
),
],
rows: items.map(_ligneTableau).toList(),
),
),
),
@@ -3626,52 +3667,47 @@ class _VueAnomaliesTableau extends StatelessWidget {
color: Colors.white,
border: Border.all(color: EnsupColors.line),
),
child: SingleChildScrollView(
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: ConstrainedBox(
constraints: BoxConstraints(minWidth: largeurDisponible),
child: DataTable(
sortColumnIndex: _sortColumnIndex,
sortAscending: ordre == "asc",
headingRowColor: WidgetStatePropertyAll(
EnsupColors.soft.withValues(alpha: 0.8),
),
headingTextStyle: GoogleFonts.titilliumWeb(
fontSize: 12,
fontWeight: FontWeight.w700,
color: EnsupColors.text2,
),
dataTextStyle: GoogleFonts.titilliumWeb(
fontSize: 12,
color: EnsupColors.text,
),
columns: [
DataColumn(
label: const Text("Détection"),
onSort: (_, _) => onTri("dateDetection"),
),
DataColumn(
label: const Text("Anomalie"),
onSort: (_, _) => onTri("type"),
),
DataColumn(
label: const Text("Matériel"),
onSort: (_, _) => onTri("materiel"),
),
DataColumn(
label: const Text("Étudiant"),
onSort: (_, _) => onTri("etudiant"),
),
DataColumn(
label: const Text("Statut"),
onSort: (_, _) => onTri("statut"),
),
const DataColumn(label: Text("Action")),
],
rows: items.map(_ligneTableau).toList(),
),
child: _TableauAvecDefilementHorizontal(
largeurMinimale: largeurDisponible,
child: DataTable(
sortColumnIndex: _sortColumnIndex,
sortAscending: ordre == "asc",
headingRowColor: WidgetStatePropertyAll(
EnsupColors.soft.withValues(alpha: 0.8),
),
headingTextStyle: GoogleFonts.titilliumWeb(
fontSize: 12,
fontWeight: FontWeight.w700,
color: EnsupColors.text2,
),
dataTextStyle: GoogleFonts.titilliumWeb(
fontSize: 12,
color: EnsupColors.text,
),
columns: [
DataColumn(
label: const Text("Détection"),
onSort: (_, _) => onTri("dateDetection"),
),
DataColumn(
label: const Text("Anomalie"),
onSort: (_, _) => onTri("type"),
),
DataColumn(
label: const Text("Matériel"),
onSort: (_, _) => onTri("materiel"),
),
DataColumn(
label: const Text("Étudiant"),
onSort: (_, _) => onTri("etudiant"),
),
DataColumn(
label: const Text("Statut"),
onSort: (_, _) => onTri("statut"),
),
const DataColumn(label: Text("Action")),
],
rows: items.map(_ligneTableau).toList(),
),
),
),
@@ -4250,52 +4286,47 @@ class _VueHistoriqueTableau extends StatelessWidget {
color: Colors.white,
border: Border.all(color: EnsupColors.line),
),
child: SingleChildScrollView(
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: ConstrainedBox(
constraints: BoxConstraints(minWidth: largeurDisponible),
child: DataTable(
sortColumnIndex: _sortColumnIndex,
sortAscending: ordre == "asc",
headingRowColor: WidgetStatePropertyAll(
EnsupColors.soft.withValues(alpha: 0.8),
),
headingTextStyle: GoogleFonts.titilliumWeb(
fontSize: 12,
fontWeight: FontWeight.w700,
color: EnsupColors.text2,
),
dataTextStyle: GoogleFonts.titilliumWeb(
fontSize: 12,
color: EnsupColors.text,
),
columns: [
DataColumn(
label: const Text("Date"),
onSort: (_, _) => onTri("dateAction"),
),
DataColumn(
label: const Text("Action"),
onSort: (_, _) => onTri("action"),
),
DataColumn(
label: const Text("Utilisateur"),
onSort: (_, _) => onTri("utilisateur"),
),
DataColumn(
label: const Text("Matériel"),
onSort: (_, _) => onTri("materiel"),
),
DataColumn(
label: const Text("Emprunt"),
onSort: (_, _) => onTri("emprunt"),
),
const DataColumn(label: Text("Point dopération")),
],
rows: items.map(_ligneTableau).toList(),
),
child: _TableauAvecDefilementHorizontal(
largeurMinimale: largeurDisponible,
child: DataTable(
sortColumnIndex: _sortColumnIndex,
sortAscending: ordre == "asc",
headingRowColor: WidgetStatePropertyAll(
EnsupColors.soft.withValues(alpha: 0.8),
),
headingTextStyle: GoogleFonts.titilliumWeb(
fontSize: 12,
fontWeight: FontWeight.w700,
color: EnsupColors.text2,
),
dataTextStyle: GoogleFonts.titilliumWeb(
fontSize: 12,
color: EnsupColors.text,
),
columns: [
DataColumn(
label: const Text("Date"),
onSort: (_, _) => onTri("dateAction"),
),
DataColumn(
label: const Text("Action"),
onSort: (_, _) => onTri("action"),
),
DataColumn(
label: const Text("Utilisateur"),
onSort: (_, _) => onTri("utilisateur"),
),
DataColumn(
label: const Text("Matériel"),
onSort: (_, _) => onTri("materiel"),
),
DataColumn(
label: const Text("Emprunt"),
onSort: (_, _) => onTri("emprunt"),
),
const DataColumn(label: Text("Point dopération")),
],
rows: items.map(_ligneTableau).toList(),
),
),
),
+9 -1
View File
@@ -525,6 +525,14 @@ En terminal interactif (VS Code), `migrate dev` fonctionne normalement (taper `y
- La confirmation reste enregistrée, le message de succès reste visible et les données de supervision sont rechargées normalement.
- Vérifications réussies : `dart analyze` sans erreur et serveur Flutter opérationnel sur le port 5000.
### Étape 55 — Défilement horizontal visible des tableaux responsable
- Les tableaux Emprunts, Stock matériel, Anomalies et Historique restent accessibles sur les écrans de largeur intermédiaire.
- Un composant partagé gère le défilement horizontal avec son propre contrôleur Flutter.
- La barre horizontale est visible, interactive et positionnée sous le contenu de chaque tableau.
- Les dernières colonnes, notamment les statuts et les actions, peuvent être atteintes sans modifier la disposition sur grand écran.
- Les listes compactes mobiles existantes sont conservées sous leurs seuils responsifs.
- Vérifications réussies : les quatre tableaux utilisent le composant partagé, `dart analyze` est sans erreur et le serveur Flutter répond sur le port 5000.
---
*Dernière mise à jour : 2026-07-24 — Rafraîchissement après décision responsable corrigé.*
*Dernière mise à jour : 2026-07-24 — Défilement horizontal des tableaux responsable ajouté.*