Files
geo/app/lib/core/theme/app_theme.dart
pierre b6584c83fa feat: Version 3.3.4 - Nouvelle architecture pages, optimisations widgets Flutter et API
- Mise à jour VERSION vers 3.3.4
- Optimisations et révisions architecture API (deploy-api.sh, scripts de migration)
- Ajout documentation Stripe Tap to Pay complète
- Migration vers polices Inter Variable pour Flutter
- Optimisations build Android et nettoyage fichiers temporaires
- Amélioration système de déploiement avec gestion backups
- Ajout scripts CRON et migrations base de données

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-05 20:11:15 +02:00

421 lines
14 KiB
Dart
Executable File

import 'package:flutter/material.dart';
class AppTheme {
// Breakpoints pour le responsive design
static const double breakpointMobileSmall = 360; // iPhone SE et petits Android
static const double breakpointMobile = 600; // Smartphones standards
static const double breakpointTablet = 900; // Tablettes
// Multiplicateurs de taille selon l'écran
static const double fontScaleExtraSmall = 0.85; // < 360px
static const double fontScaleSmall = 0.9; // 360-600px
static const double fontScaleMedium = 0.95; // 600-900px
static const double fontScaleLarge = 1.0; // > 900px
/// Calcule le multiplicateur de police selon la largeur d'écran
static double getFontScaleFactor(double screenWidth) {
if (screenWidth < breakpointMobileSmall) return fontScaleExtraSmall;
if (screenWidth < breakpointMobile) return fontScaleSmall;
if (screenWidth < breakpointTablet) return fontScaleMedium;
return fontScaleLarge;
}
/// Retourne une taille de police responsive
static double responsive(BuildContext context, double baseSize) {
final width = MediaQuery.of(context).size.width;
return baseSize * getFontScaleFactor(width);
}
/// Retourne une taille de police responsive (version courte)
static double r(BuildContext context, double baseSize) => responsive(context, baseSize);
// Couleurs du thème basées sur la maquette Figma
static const Color primaryColor = Color(0xFF20335E); // Bleu foncé
static const Color secondaryColor = Color(0xFF9DC7C8); // Bleu clair
static const Color accentColor = Color(0xFF00E09D); // Vert
static const Color errorColor = Color(0xFFE41B13); // Rouge
static const Color warningColor = Color(0xFFF7A278); // Orange
static const Color backgroundLightColor =
Color(0xFFF4F5F6); // Gris très clair
static const Color backgroundDarkColor = Color(0xFF111827);
static const Color textLightColor = Color(0xFF000000); // Noir
static const Color textDarkColor = Color(0xFFF9FAFB);
// Couleurs de texte supplémentaires
static const Color textSecondaryColor = Color(0xFF7F8C8D);
static const Color textLightSecondaryColor = Color(0xFFBDC3C7);
// Couleurs des boutons
static const Color buttonSuccessColor = Color(0xFF2ECC71);
static const Color buttonDangerColor = Color(0xFFE74C3C);
// Couleurs des charts
static const List<Color> chartColors = [
primaryColor,
accentColor,
errorColor,
warningColor,
secondaryColor,
Color(0xFF9B59B6),
Color(0xFF1ABC9C),
];
// Ombres
static List<BoxShadow> cardShadow = [
BoxShadow(
color: Colors.black.withValues(alpha: 0.05),
spreadRadius: 1,
blurRadius: 10,
offset: const Offset(0, 3),
),
];
static List<BoxShadow> buttonShadow = [
BoxShadow(
color: Colors.black.withValues(alpha: 0.1),
spreadRadius: 1,
blurRadius: 5,
offset: const Offset(0, 2),
),
];
// Rayons des bordures
static const double borderRadiusSmall = 4.0;
static const double borderRadiusMedium = 8.0;
static const double borderRadiusLarge = 12.0;
static const double borderRadiusXL = 16.0;
static const double borderRadiusRounded = 50.0;
// Espacement
static const double spacingXS = 4.0;
static const double spacingS = 8.0;
static const double spacingM = 16.0;
static const double spacingL = 24.0;
static const double spacingXL = 32.0;
static const double spacingXXL = 48.0;
// Thème clair
static ThemeData get lightTheme {
return ThemeData(
useMaterial3: true,
brightness: Brightness.light,
fontFamily: 'Inter',
colorScheme: const ColorScheme.light(
primary: primaryColor,
secondary: secondaryColor,
tertiary: accentColor,
surface: Colors.white,
onPrimary: Colors.white,
onSecondary: Colors.white,
onSurface: textLightColor,
error: errorColor,
),
scaffoldBackgroundColor: backgroundLightColor,
textTheme: _getTextTheme(textLightColor),
appBarTheme: const AppBarTheme(
backgroundColor: primaryColor,
foregroundColor: Colors.white,
elevation: 0,
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: primaryColor,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(
horizontal: spacingL, vertical: spacingM),
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(borderRadiusRounded),
),
textStyle: const TextStyle(
fontFamily: 'Inter',
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
),
outlinedButtonTheme: OutlinedButtonThemeData(
style: OutlinedButton.styleFrom(
foregroundColor: primaryColor,
side: const BorderSide(color: primaryColor),
padding: const EdgeInsets.symmetric(
horizontal: spacingL, vertical: spacingM),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(borderRadiusMedium),
),
),
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
foregroundColor: primaryColor,
padding: const EdgeInsets.symmetric(
horizontal: spacingM, vertical: spacingS),
),
),
inputDecorationTheme: InputDecorationTheme(
filled: true,
fillColor: backgroundLightColor,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(borderRadiusMedium),
borderSide: BorderSide(
color: textLightColor.withValues(alpha: 0.1),
width: 1,
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(borderRadiusMedium),
borderSide: BorderSide(
color: textLightColor.withValues(alpha: 0.1),
width: 1,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(borderRadiusMedium),
borderSide: const BorderSide(color: primaryColor, width: 2),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: spacingM, vertical: spacingM),
),
cardTheme: CardThemeData(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(borderRadiusXL),
),
color: Colors.white,
),
dividerTheme: const DividerThemeData(
color: Color(0xFFECF0F1),
thickness: 1,
space: spacingM,
),
);
}
// Thème sombre
static ThemeData get darkTheme {
return ThemeData(
useMaterial3: true,
brightness: Brightness.dark,
fontFamily: 'Inter',
colorScheme: const ColorScheme.dark(
primary: primaryColor,
secondary: secondaryColor,
tertiary: accentColor,
surface: Color(0xFF1F2937),
onPrimary: Colors.white,
onSecondary: Colors.white,
onSurface: textDarkColor,
error: errorColor,
),
scaffoldBackgroundColor: backgroundDarkColor,
textTheme: _getTextTheme(textDarkColor),
appBarTheme: const AppBarTheme(
backgroundColor: Color(0xFF1F2937),
foregroundColor: Colors.white,
elevation: 0,
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: primaryColor,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(
horizontal: spacingL, vertical: spacingM),
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(borderRadiusRounded),
),
textStyle: const TextStyle(
fontFamily: 'Inter',
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
),
outlinedButtonTheme: OutlinedButtonThemeData(
style: OutlinedButton.styleFrom(
foregroundColor: primaryColor,
side: const BorderSide(color: primaryColor),
padding: const EdgeInsets.symmetric(
horizontal: spacingL, vertical: spacingM),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(borderRadiusMedium),
),
),
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
foregroundColor: primaryColor,
padding: const EdgeInsets.symmetric(
horizontal: spacingM, vertical: spacingS),
),
),
inputDecorationTheme: InputDecorationTheme(
filled: true,
fillColor: const Color(0xFF374151),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(borderRadiusMedium),
borderSide: BorderSide(
color: textDarkColor.withValues(alpha: 0.1),
width: 1,
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(borderRadiusMedium),
borderSide: BorderSide(
color: textDarkColor.withValues(alpha: 0.1),
width: 1,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(borderRadiusMedium),
borderSide: const BorderSide(color: primaryColor, width: 2),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: spacingM, vertical: spacingM),
),
cardTheme: CardThemeData(
elevation: 4,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(borderRadiusXL),
),
color: const Color(0xFF1F2937),
),
dividerTheme: DividerThemeData(
color: textDarkColor.withValues(alpha: 0.1),
thickness: 1,
space: spacingM,
),
);
}
// Méthode helper pour générer le TextTheme responsive
static TextTheme getResponsiveTextTheme(BuildContext context, Color textColor) {
final scaleFactor = getFontScaleFactor(MediaQuery.of(context).size.width);
return TextTheme(
// Display styles (très grandes tailles)
displayLarge: TextStyle(
fontFamily: 'Inter',
color: textColor,
fontSize: 57 * scaleFactor, // Material 3 default
),
displayMedium: TextStyle(
fontFamily: 'Inter',
color: textColor,
fontSize: 45 * scaleFactor,
),
displaySmall: TextStyle(
fontFamily: 'Inter',
color: textColor,
fontSize: 36 * scaleFactor,
),
// Headline styles (titres principaux)
headlineLarge: TextStyle(
fontFamily: 'Inter',
color: textColor,
fontSize: 32 * scaleFactor,
),
headlineMedium: TextStyle(
fontFamily: 'Inter',
color: textColor,
fontSize: 28 * scaleFactor,
),
headlineSmall: TextStyle(
fontFamily: 'Inter',
color: textColor,
fontSize: 24 * scaleFactor,
),
// Title styles (sous-titres)
titleLarge: TextStyle(
fontFamily: 'Inter',
color: textColor,
fontSize: 22 * scaleFactor,
),
titleMedium: TextStyle(
fontFamily: 'Inter',
color: textColor,
fontSize: 16 * scaleFactor,
fontWeight: FontWeight.w600,
),
titleSmall: TextStyle(
fontFamily: 'Inter',
color: textColor,
fontSize: 14 * scaleFactor,
fontWeight: FontWeight.w600,
),
// Body styles (texte principal)
bodyLarge: TextStyle(
fontFamily: 'Inter',
color: textColor,
fontSize: 16 * scaleFactor,
fontWeight: FontWeight.w500,
),
bodyMedium: TextStyle(
fontFamily: 'Inter',
color: textColor,
fontSize: 14 * scaleFactor,
fontWeight: FontWeight.w500,
),
bodySmall: TextStyle(
fontFamily: 'Inter',
color: textColor.withValues(alpha: 0.7),
fontSize: 12 * scaleFactor,
),
// Label styles (petits textes, boutons)
labelLarge: TextStyle(
fontFamily: 'Inter',
color: textColor,
fontSize: 14 * scaleFactor,
fontWeight: FontWeight.w600,
),
labelMedium: TextStyle(
fontFamily: 'Inter',
color: textColor.withValues(alpha: 0.7),
fontSize: 12 * scaleFactor,
),
labelSmall: TextStyle(
fontFamily: 'Inter',
color: textColor.withValues(alpha: 0.7),
fontSize: 11 * scaleFactor,
),
);
}
// Version statique pour compatibilité (utilise les tailles par défaut)
static TextTheme _getTextTheme(Color textColor) {
return TextTheme(
displayLarge: TextStyle(fontFamily: 'Inter', color: textColor, fontSize: 57),
displayMedium: TextStyle(fontFamily: 'Inter', color: textColor, fontSize: 45),
displaySmall: TextStyle(fontFamily: 'Inter', color: textColor, fontSize: 36),
headlineLarge: TextStyle(fontFamily: 'Inter', color: textColor, fontSize: 32),
headlineMedium: TextStyle(fontFamily: 'Inter', color: textColor, fontSize: 28),
headlineSmall: TextStyle(fontFamily: 'Inter', color: textColor, fontSize: 24),
titleLarge: TextStyle(fontFamily: 'Inter', color: textColor, fontSize: 22),
titleMedium: TextStyle(fontFamily: 'Inter', color: textColor, fontSize: 16, fontWeight: FontWeight.w600),
titleSmall: TextStyle(fontFamily: 'Inter', color: textColor, fontSize: 14, fontWeight: FontWeight.w600),
bodyLarge: TextStyle(fontFamily: 'Inter', color: textColor, fontSize: 16, fontWeight: FontWeight.w500),
bodyMedium: TextStyle(fontFamily: 'Inter', color: textColor, fontSize: 14, fontWeight: FontWeight.w500),
bodySmall: TextStyle(fontFamily: 'Inter', color: textColor.withValues(alpha: 0.7), fontSize: 12),
labelLarge: TextStyle(fontFamily: 'Inter', color: textColor, fontSize: 14, fontWeight: FontWeight.w600),
labelMedium: TextStyle(fontFamily: 'Inter', color: textColor.withValues(alpha: 0.7), fontSize: 12),
labelSmall: TextStyle(fontFamily: 'Inter', color: textColor.withValues(alpha: 0.7), fontSize: 11),
);
}
/// Helper pour obtenir des espacements responsives
static double getResponsiveSpacing(double screenWidth, double baseSpacing) {
final scaleFactor = getFontScaleFactor(screenWidth);
return baseSpacing * scaleFactor;
}
/// Helper court pour espacements responsives
static double s(BuildContext context, double baseSpacing) {
final width = MediaQuery.of(context).size.width;
return getResponsiveSpacing(width, baseSpacing);
}
}