import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; class AppTheme { // Couleurs principales UnionFlow static const Color primaryColor = Color(0xFF2196F3); static const Color primaryLight = Color(0xFF64B5F6); static const Color primaryDark = Color(0xFF1976D2); static const Color secondaryColor = Color(0xFF4CAF50); static const Color secondaryLight = Color(0xFF81C784); static const Color secondaryDark = Color(0xFF388E3C); static const Color accentColor = Color(0xFFFF9800); static const Color errorColor = Color(0xFFE53935); static const Color warningColor = Color(0xFFFFC107); static const Color successColor = Color(0xFF4CAF50); static const Color infoColor = Color(0xFF2196F3); // Couleurs neutres static const Color backgroundLight = Color(0xFFFAFAFA); static const Color backgroundDark = Color(0xFF121212); static const Color surfaceLight = Color(0xFFFFFFFF); static const Color surfaceDark = Color(0xFF1E1E1E); static const Color textPrimary = Color(0xFF212121); static const Color textSecondary = Color(0xFF757575); static const Color textHint = Color(0xFFBDBDBD); static const Color textWhite = Color(0xFFFFFFFF); // Bordures et dividers static const Color borderColor = Color(0xFFE0E0E0); static const Color borderLight = Color(0xFFF5F5F5); static const Color dividerColor = Color(0xFFBDBDBD); // Couleurs Material 3 supplémentaires pour les composants unifiés static const Color outline = Color(0xFFE0E0E0); static const Color surfaceVariant = Color(0xFFF5F5F5); static const Color onSurfaceVariant = Color(0xFF757575); // Tokens de design unifiés static const double borderRadiusSmall = 8.0; static const double borderRadiusMedium = 12.0; static const double borderRadiusLarge = 16.0; static const double borderRadiusXLarge = 20.0; static const double spacingXSmall = 4.0; static const double spacingSmall = 8.0; static const double spacingMedium = 16.0; static const double spacingLarge = 24.0; static const double spacingXLarge = 32.0; static const double elevationSmall = 1.0; static const double elevationMedium = 2.0; static const double elevationLarge = 4.0; static const double elevationXLarge = 8.0; // Styles de texte unifiés static const TextStyle headlineSmall = TextStyle( fontSize: 18, fontWeight: FontWeight.w600, color: textPrimary, ); static const TextStyle titleMedium = TextStyle( fontSize: 14, fontWeight: FontWeight.w500, color: textPrimary, ); static const TextStyle bodyMedium = TextStyle( fontSize: 14, fontWeight: FontWeight.normal, color: textPrimary, ); static const TextStyle bodySmall = TextStyle( fontSize: 12, fontWeight: FontWeight.normal, color: textSecondary, ); static const TextStyle titleSmall = TextStyle( fontSize: 12, fontWeight: FontWeight.w500, color: textPrimary, ); static const TextStyle bodyLarge = TextStyle( fontSize: 16, fontWeight: FontWeight.normal, color: textPrimary, ); // Thème clair static ThemeData get lightTheme { return ThemeData( useMaterial3: true, brightness: Brightness.light, primarySwatch: _createMaterialColor(primaryColor), colorScheme: const ColorScheme.light( primary: primaryColor, onPrimary: textWhite, secondary: secondaryColor, onSecondary: textWhite, error: errorColor, onError: textWhite, surface: surfaceLight, onSurface: textPrimary, ), // AppBar appBarTheme: const AppBarTheme( elevation: 0, backgroundColor: primaryColor, foregroundColor: textWhite, centerTitle: true, systemOverlayStyle: SystemUiOverlayStyle.light, titleTextStyle: TextStyle( color: textWhite, fontSize: 20, fontWeight: FontWeight.w600, ), ), // Cards cardTheme: CardTheme( elevation: 2, shadowColor: Colors.black.withOpacity(0.1), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), color: surfaceLight, ), // Boutons elevatedButtonTheme: ElevatedButtonThemeData( style: ElevatedButton.styleFrom( backgroundColor: primaryColor, foregroundColor: textWhite, elevation: 2, padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), textStyle: const TextStyle( fontSize: 16, fontWeight: FontWeight.w600, ), ), ), outlinedButtonTheme: OutlinedButtonThemeData( style: OutlinedButton.styleFrom( foregroundColor: primaryColor, side: const BorderSide(color: primaryColor, width: 2), padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), textStyle: const TextStyle( fontSize: 16, fontWeight: FontWeight.w600, ), ), ), textButtonTheme: TextButtonThemeData( style: TextButton.styleFrom( foregroundColor: primaryColor, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), textStyle: const TextStyle( fontSize: 16, fontWeight: FontWeight.w600, ), ), ), // Champs de saisie inputDecorationTheme: InputDecorationTheme( filled: true, fillColor: surfaceLight, border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide(color: borderColor), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide(color: borderColor), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide(color: primaryColor, width: 2), ), errorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide(color: errorColor), ), contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16), hintStyle: const TextStyle(color: textHint), ), // Navigation bottom bottomNavigationBarTheme: const BottomNavigationBarThemeData( backgroundColor: surfaceLight, selectedItemColor: primaryColor, unselectedItemColor: textSecondary, type: BottomNavigationBarType.fixed, elevation: 8, ), // Chip chipTheme: ChipThemeData( backgroundColor: primaryLight.withOpacity(0.1), selectedColor: primaryColor, labelStyle: const TextStyle(color: textPrimary), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), ), ), // Divider dividerTheme: const DividerThemeData( color: dividerColor, thickness: 1, ), // Typography textTheme: _textTheme, ); } // Thème sombre (pour plus tard) static ThemeData get darkTheme { return lightTheme.copyWith( brightness: Brightness.dark, scaffoldBackgroundColor: backgroundDark, // TODO: Implémenter le thème sombre complet ); } // Création d'un MaterialColor à partir d'une Color static MaterialColor _createMaterialColor(Color color) { List strengths = [.05]; Map swatch = {}; final int r = color.red, g = color.green, b = color.blue; for (int i = 1; i < 10; i++) { strengths.add(0.1 * i); } for (var strength in strengths) { final double ds = 0.5 - strength; swatch[(strength * 1000).round()] = Color.fromRGBO( r + ((ds < 0 ? r : (255 - r)) * ds).round(), g + ((ds < 0 ? g : (255 - g)) * ds).round(), b + ((ds < 0 ? b : (255 - b)) * ds).round(), 1, ); } return MaterialColor(color.value, swatch); } // Typographie static const TextTheme _textTheme = TextTheme( displayLarge: TextStyle( fontSize: 32, fontWeight: FontWeight.bold, color: textPrimary, ), displayMedium: TextStyle( fontSize: 28, fontWeight: FontWeight.bold, color: textPrimary, ), displaySmall: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: textPrimary, ), headlineLarge: TextStyle( fontSize: 22, fontWeight: FontWeight.w600, color: textPrimary, ), headlineMedium: TextStyle( fontSize: 20, fontWeight: FontWeight.w600, color: textPrimary, ), headlineSmall: TextStyle( fontSize: 18, fontWeight: FontWeight.w600, color: textPrimary, ), titleLarge: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: textPrimary, ), titleMedium: TextStyle( fontSize: 14, fontWeight: FontWeight.w500, color: textPrimary, ), titleSmall: TextStyle( fontSize: 12, fontWeight: FontWeight.w500, color: textPrimary, ), bodyLarge: TextStyle( fontSize: 16, fontWeight: FontWeight.normal, color: textPrimary, ), bodyMedium: TextStyle( fontSize: 14, fontWeight: FontWeight.normal, color: textPrimary, ), bodySmall: TextStyle( fontSize: 12, fontWeight: FontWeight.normal, color: textSecondary, ), labelLarge: TextStyle( fontSize: 14, fontWeight: FontWeight.w500, color: textPrimary, ), labelMedium: TextStyle( fontSize: 12, fontWeight: FontWeight.w500, color: textSecondary, ), labelSmall: TextStyle( fontSize: 10, fontWeight: FontWeight.w500, color: textHint, ), ); } // Extensions pour faciliter l'utilisation extension ThemeExtension on BuildContext { ThemeData get theme => Theme.of(this); ColorScheme get colors => Theme.of(this).colorScheme; TextTheme get textTheme => Theme.of(this).textTheme; }