import 'package:flutter/material.dart'; import '../../../../../shared/design_system/unionflow_design_system.dart'; /// Widget réutilisable pour les en-têtes de section /// /// Composant standardisé pour tous les titres de section dans les dashboards /// avec support pour actions, sous-titres et styles personnalisés. /// /// REFACTORISÉ pour utiliser le Design System UnionFlow. class SectionHeader extends StatelessWidget { /// Titre principal de la section final String title; /// Sous-titre optionnel final String? subtitle; /// Widget d'action à droite (bouton, icône, etc.) final Widget? action; /// Icône optionnelle à gauche du titre final IconData? icon; /// Couleur du titre et de l'icône (null = adaptatif selon le thème) final Color? color; /// Taille du titre final double? fontSize; /// Style de l'en-tête final SectionHeaderStyle style; /// Espacement en bas de l'en-tête final double bottomSpacing; const SectionHeader({ super.key, required this.title, this.subtitle, this.action, this.icon, this.color, this.fontSize, this.style = SectionHeaderStyle.normal, this.bottomSpacing = 12, }); /// Constructeur pour un en-tête principal const SectionHeader.primary({ super.key, required this.title, this.subtitle, this.action, this.icon, }) : color = ColorTokens.primary, fontSize = 16, style = SectionHeaderStyle.primary, bottomSpacing = 10; /// Constructeur pour un en-tête de section const SectionHeader.section({ super.key, required this.title, this.subtitle, this.action, this.icon, }) : color = ColorTokens.primary, fontSize = 13, style = SectionHeaderStyle.normal, bottomSpacing = 8; /// Constructeur pour un en-tête de sous-section (couleur adaptative) const SectionHeader.subsection({ super.key, required this.title, this.subtitle, this.action, this.icon, }) : color = null, // null → adaptatif via Theme.of(context).colorScheme.onSurface fontSize = 14, style = SectionHeaderStyle.minimal, bottomSpacing = 8; @override Widget build(BuildContext context) { return Padding( padding: EdgeInsets.only(bottom: bottomSpacing), child: _buildContent(context), ); } Widget _buildContent(BuildContext context) { switch (style) { case SectionHeaderStyle.primary: return _buildPrimaryHeader(context); case SectionHeaderStyle.normal: return _buildNormalHeader(context); case SectionHeaderStyle.minimal: return _buildMinimalHeader(context); case SectionHeaderStyle.card: return _buildCardHeader(context); } } /// En-tête principal avec fond coloré (gradient sur couleur thématique) /// Colors.white est correct ici : texte sur fond coloré opaque Widget _buildPrimaryHeader(BuildContext context) { final effectiveColor = color ?? ColorTokens.primary; return Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( gradient: LinearGradient( colors: [ effectiveColor, effectiveColor.withOpacity(0.8), ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(SpacingTokens.radiusLg), ), child: Row( children: [ if (icon != null) ...[ Container( padding: const EdgeInsets.all(6), decoration: BoxDecoration( color: Colors.white.withOpacity(0.2), borderRadius: BorderRadius.circular(6), ), child: Icon( icon, color: Colors.white, size: 16, ), ), const SizedBox(width: 12), ], Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: TextStyle( fontSize: fontSize ?? 16, fontWeight: FontWeight.bold, color: Colors.white, ), ), if (subtitle != null) ...[ const SizedBox(height: 4), Text( subtitle!, style: TextStyle( fontSize: 14, color: Colors.white.withOpacity(0.8), ), ), ], ], ), ), if (action != null) action!, ], ), ); } /// En-tête normal avec icône et action Widget _buildNormalHeader(BuildContext context) { final scheme = Theme.of(context).colorScheme; final effectiveColor = color ?? scheme.primary; return Row( children: [ if (icon != null) ...[ Icon( icon, color: effectiveColor, size: 20, ), const SizedBox(width: SpacingTokens.md), ], Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: TextStyle( fontSize: fontSize ?? 13, fontWeight: FontWeight.bold, color: effectiveColor, ), ), if (subtitle != null) ...[ const SizedBox(height: 2), Text( subtitle!, style: TextStyle( fontSize: 12, color: scheme.onSurfaceVariant, ), ), ], ], ), ), if (action != null) action!, ], ); } /// En-tête minimal simple — couleur totalement adaptative Widget _buildMinimalHeader(BuildContext context) { final scheme = Theme.of(context).colorScheme; final effectiveColor = color ?? scheme.onSurface; return Row( children: [ if (icon != null) ...[ Icon( icon, color: effectiveColor, size: 16, ), const SizedBox(width: 6), ], Expanded( child: Text( title, style: TextStyle( fontSize: fontSize ?? 14, fontWeight: FontWeight.w600, color: effectiveColor, ), ), ), if (action != null) action!, ], ); } /// En-tête avec fond de carte — surface theme-aware Widget _buildCardHeader(BuildContext context) { final scheme = Theme.of(context).colorScheme; final effectiveColor = color ?? scheme.primary; return Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: scheme.surface, borderRadius: BorderRadius.circular(8), border: Border.all(color: scheme.outline, width: 0.5), ), child: Row( children: [ if (icon != null) ...[ Icon( icon, color: effectiveColor, size: 20, ), const SizedBox(width: SpacingTokens.md), ], Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: TextStyle( fontSize: fontSize ?? 13, fontWeight: FontWeight.bold, color: effectiveColor, ), ), if (subtitle != null) ...[ const SizedBox(height: 2), Text( subtitle!, style: TextStyle( fontSize: 12, color: scheme.onSurfaceVariant, ), ), ], ], ), ), if (action != null) action!, ], ), ); } } /// Énumération des styles d'en-tête enum SectionHeaderStyle { primary, normal, minimal, card, }