458 lines
16 KiB
Dart
458 lines
16 KiB
Dart
/// Thème Sophistiqué UnionFlow
|
|
///
|
|
/// Implémentation complète du design system avec les dernières tendances UI/UX 2024-2025
|
|
/// Architecture modulaire et tokens de design cohérents
|
|
library app_theme_sophisticated;
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
import '../tokens/color_tokens.dart';
|
|
import '../tokens/typography_tokens.dart';
|
|
import '../tokens/spacing_tokens.dart';
|
|
|
|
/// Thème principal de l'application UnionFlow
|
|
class AppThemeSophisticated {
|
|
AppThemeSophisticated._();
|
|
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
// THÈME PRINCIPAL - Configuration complète
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
/// Thème clair principal
|
|
static ThemeData get lightTheme {
|
|
return ThemeData(
|
|
useMaterial3: true,
|
|
brightness: Brightness.light,
|
|
|
|
// Couleurs principales
|
|
colorScheme: _lightColorScheme,
|
|
|
|
// Typographie
|
|
textTheme: _textTheme,
|
|
|
|
// Configuration de l'AppBar
|
|
appBarTheme: _appBarTheme,
|
|
|
|
// Configuration des cartes
|
|
cardTheme: _cardTheme,
|
|
|
|
// Configuration des boutons
|
|
elevatedButtonTheme: _elevatedButtonTheme,
|
|
filledButtonTheme: _filledButtonTheme,
|
|
outlinedButtonTheme: _outlinedButtonTheme,
|
|
textButtonTheme: _textButtonTheme,
|
|
|
|
// Configuration des champs de saisie
|
|
inputDecorationTheme: _inputDecorationTheme,
|
|
|
|
// Configuration de la navigation
|
|
navigationBarTheme: _navigationBarTheme,
|
|
navigationDrawerTheme: _navigationDrawerTheme,
|
|
|
|
// Configuration des dialogues
|
|
dialogTheme: _dialogTheme,
|
|
|
|
// Configuration des snackbars
|
|
snackBarTheme: _snackBarTheme,
|
|
|
|
// Configuration des puces
|
|
chipTheme: _chipTheme,
|
|
|
|
// Configuration des listes
|
|
listTileTheme: _listTileTheme,
|
|
|
|
// Configuration des onglets
|
|
tabBarTheme: _tabBarTheme,
|
|
|
|
// Configuration des dividers
|
|
dividerTheme: _dividerTheme,
|
|
|
|
// Configuration des icônes
|
|
iconTheme: _iconTheme,
|
|
|
|
// Configuration des surfaces
|
|
scaffoldBackgroundColor: ColorTokens.surface,
|
|
canvasColor: ColorTokens.surface,
|
|
|
|
// Configuration des animations
|
|
pageTransitionsTheme: _pageTransitionsTheme,
|
|
|
|
// Configuration des extensions
|
|
extensions: const [
|
|
_customColors,
|
|
_customSpacing,
|
|
],
|
|
);
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
// SCHÉMA DE COULEURS
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
static const ColorScheme _lightColorScheme = ColorScheme.light(
|
|
// Couleurs primaires
|
|
primary: ColorTokens.primary,
|
|
onPrimary: ColorTokens.onPrimary,
|
|
primaryContainer: ColorTokens.primaryContainer,
|
|
onPrimaryContainer: ColorTokens.onPrimaryContainer,
|
|
|
|
// Couleurs secondaires
|
|
secondary: ColorTokens.secondary,
|
|
onSecondary: ColorTokens.onSecondary,
|
|
secondaryContainer: ColorTokens.secondaryContainer,
|
|
onSecondaryContainer: ColorTokens.onSecondaryContainer,
|
|
|
|
// Couleurs tertiaires
|
|
tertiary: ColorTokens.tertiary,
|
|
onTertiary: ColorTokens.onTertiary,
|
|
tertiaryContainer: ColorTokens.tertiaryContainer,
|
|
onTertiaryContainer: ColorTokens.onTertiaryContainer,
|
|
|
|
// Couleurs d'erreur
|
|
error: ColorTokens.error,
|
|
onError: ColorTokens.onError,
|
|
errorContainer: ColorTokens.errorContainer,
|
|
onErrorContainer: ColorTokens.onErrorContainer,
|
|
|
|
// Couleurs de surface
|
|
surface: ColorTokens.surface,
|
|
onSurface: ColorTokens.onSurface,
|
|
surfaceContainerHighest: ColorTokens.surfaceVariant,
|
|
onSurfaceVariant: ColorTokens.onSurfaceVariant,
|
|
|
|
// Couleurs de contour
|
|
outline: ColorTokens.outline,
|
|
outlineVariant: ColorTokens.outlineVariant,
|
|
|
|
// Couleurs d'ombre
|
|
shadow: ColorTokens.shadow,
|
|
scrim: ColorTokens.shadow,
|
|
|
|
// Couleurs d'inversion
|
|
inverseSurface: ColorTokens.onSurface,
|
|
onInverseSurface: ColorTokens.surface,
|
|
inversePrimary: ColorTokens.primaryLight,
|
|
);
|
|
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
// THÈME TYPOGRAPHIQUE
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
static const TextTheme _textTheme = TextTheme(
|
|
// Display styles
|
|
displayLarge: TypographyTokens.displayLarge,
|
|
displayMedium: TypographyTokens.displayMedium,
|
|
displaySmall: TypographyTokens.displaySmall,
|
|
|
|
// Headline styles
|
|
headlineLarge: TypographyTokens.headlineLarge,
|
|
headlineMedium: TypographyTokens.headlineMedium,
|
|
headlineSmall: TypographyTokens.headlineSmall,
|
|
|
|
// Title styles
|
|
titleLarge: TypographyTokens.titleLarge,
|
|
titleMedium: TypographyTokens.titleMedium,
|
|
titleSmall: TypographyTokens.titleSmall,
|
|
|
|
// Label styles
|
|
labelLarge: TypographyTokens.labelLarge,
|
|
labelMedium: TypographyTokens.labelMedium,
|
|
labelSmall: TypographyTokens.labelSmall,
|
|
|
|
// Body styles
|
|
bodyLarge: TypographyTokens.bodyLarge,
|
|
bodyMedium: TypographyTokens.bodyMedium,
|
|
bodySmall: TypographyTokens.bodySmall,
|
|
);
|
|
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
// THÈMES DE COMPOSANTS
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
/// Configuration AppBar moderne (sans AppBar traditionnelle)
|
|
static const AppBarTheme _appBarTheme = AppBarTheme(
|
|
elevation: 0,
|
|
scrolledUnderElevation: 0,
|
|
backgroundColor: Colors.transparent,
|
|
foregroundColor: ColorTokens.onSurface,
|
|
surfaceTintColor: Colors.transparent,
|
|
systemOverlayStyle: SystemUiOverlayStyle(
|
|
statusBarColor: Colors.transparent,
|
|
statusBarIconBrightness: Brightness.dark,
|
|
statusBarBrightness: Brightness.light,
|
|
),
|
|
);
|
|
|
|
/// Configuration des cartes sophistiquées
|
|
static final CardTheme _cardTheme = CardTheme(
|
|
elevation: SpacingTokens.elevationSm,
|
|
shadowColor: ColorTokens.shadow,
|
|
surfaceTintColor: ColorTokens.surfaceContainer,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(SpacingTokens.radiusLg),
|
|
),
|
|
margin: const EdgeInsets.all(SpacingTokens.cardMargin),
|
|
);
|
|
|
|
/// Configuration des boutons élevés
|
|
static final ElevatedButtonThemeData _elevatedButtonTheme = ElevatedButtonThemeData(
|
|
style: ElevatedButton.styleFrom(
|
|
elevation: SpacingTokens.elevationSm,
|
|
shadowColor: ColorTokens.shadow,
|
|
backgroundColor: ColorTokens.primary,
|
|
foregroundColor: ColorTokens.onPrimary,
|
|
textStyle: TypographyTokens.buttonMedium,
|
|
padding: const EdgeInsets.symmetric(
|
|
horizontal: SpacingTokens.buttonPaddingHorizontal,
|
|
vertical: SpacingTokens.buttonPaddingVertical,
|
|
),
|
|
minimumSize: const Size(
|
|
SpacingTokens.minButtonWidth,
|
|
SpacingTokens.buttonHeightMedium,
|
|
),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(SpacingTokens.radiusMd),
|
|
),
|
|
),
|
|
);
|
|
|
|
/// Configuration des boutons remplis
|
|
static final FilledButtonThemeData _filledButtonTheme = FilledButtonThemeData(
|
|
style: FilledButton.styleFrom(
|
|
backgroundColor: ColorTokens.primary,
|
|
foregroundColor: ColorTokens.onPrimary,
|
|
textStyle: TypographyTokens.buttonMedium,
|
|
padding: const EdgeInsets.symmetric(
|
|
horizontal: SpacingTokens.buttonPaddingHorizontal,
|
|
vertical: SpacingTokens.buttonPaddingVertical,
|
|
),
|
|
minimumSize: const Size(
|
|
SpacingTokens.minButtonWidth,
|
|
SpacingTokens.buttonHeightMedium,
|
|
),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(SpacingTokens.radiusMd),
|
|
),
|
|
),
|
|
);
|
|
|
|
/// Configuration des boutons avec contour
|
|
static final OutlinedButtonThemeData _outlinedButtonTheme = OutlinedButtonThemeData(
|
|
style: OutlinedButton.styleFrom(
|
|
foregroundColor: ColorTokens.primary,
|
|
textStyle: TypographyTokens.buttonMedium,
|
|
padding: const EdgeInsets.symmetric(
|
|
horizontal: SpacingTokens.buttonPaddingHorizontal,
|
|
vertical: SpacingTokens.buttonPaddingVertical,
|
|
),
|
|
minimumSize: const Size(
|
|
SpacingTokens.minButtonWidth,
|
|
SpacingTokens.buttonHeightMedium,
|
|
),
|
|
side: const BorderSide(
|
|
color: ColorTokens.outline,
|
|
width: 1.0,
|
|
),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(SpacingTokens.radiusMd),
|
|
),
|
|
),
|
|
);
|
|
|
|
/// Configuration des boutons texte
|
|
static final TextButtonThemeData _textButtonTheme = TextButtonThemeData(
|
|
style: TextButton.styleFrom(
|
|
foregroundColor: ColorTokens.primary,
|
|
textStyle: TypographyTokens.buttonMedium,
|
|
padding: const EdgeInsets.symmetric(
|
|
horizontal: SpacingTokens.buttonPaddingHorizontal,
|
|
vertical: SpacingTokens.buttonPaddingVertical,
|
|
),
|
|
minimumSize: const Size(
|
|
SpacingTokens.minButtonWidth,
|
|
SpacingTokens.buttonHeightMedium,
|
|
),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(SpacingTokens.radiusMd),
|
|
),
|
|
),
|
|
);
|
|
|
|
/// Configuration des champs de saisie
|
|
static final InputDecorationTheme _inputDecorationTheme = InputDecorationTheme(
|
|
filled: true,
|
|
fillColor: ColorTokens.surfaceContainer,
|
|
labelStyle: TypographyTokens.inputLabel,
|
|
hintStyle: TypographyTokens.inputHint,
|
|
border: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(SpacingTokens.radiusMd),
|
|
borderSide: const BorderSide(color: ColorTokens.outline),
|
|
),
|
|
enabledBorder: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(SpacingTokens.radiusMd),
|
|
borderSide: const BorderSide(color: ColorTokens.outline),
|
|
),
|
|
focusedBorder: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(SpacingTokens.radiusMd),
|
|
borderSide: const BorderSide(color: ColorTokens.primary, width: 2.0),
|
|
),
|
|
errorBorder: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(SpacingTokens.radiusMd),
|
|
borderSide: const BorderSide(color: ColorTokens.error),
|
|
),
|
|
contentPadding: const EdgeInsets.all(SpacingTokens.formPadding),
|
|
);
|
|
|
|
/// Configuration de la barre de navigation
|
|
static final NavigationBarThemeData _navigationBarTheme = NavigationBarThemeData(
|
|
backgroundColor: ColorTokens.navigationBackground,
|
|
indicatorColor: ColorTokens.navigationIndicator,
|
|
labelTextStyle: WidgetStateProperty.resolveWith((states) {
|
|
if (states.contains(WidgetState.selected)) {
|
|
return TypographyTokens.navigationLabelSelected;
|
|
}
|
|
return TypographyTokens.navigationLabel;
|
|
}),
|
|
iconTheme: WidgetStateProperty.resolveWith((states) {
|
|
if (states.contains(WidgetState.selected)) {
|
|
return const IconThemeData(color: ColorTokens.navigationSelected);
|
|
}
|
|
return const IconThemeData(color: ColorTokens.navigationUnselected);
|
|
}),
|
|
);
|
|
|
|
/// Configuration du drawer de navigation
|
|
static final NavigationDrawerThemeData _navigationDrawerTheme = NavigationDrawerThemeData(
|
|
backgroundColor: ColorTokens.surfaceContainer,
|
|
elevation: SpacingTokens.elevationMd,
|
|
shadowColor: ColorTokens.shadow,
|
|
surfaceTintColor: ColorTokens.surfaceContainer,
|
|
indicatorColor: ColorTokens.primaryContainer,
|
|
labelTextStyle: WidgetStateProperty.resolveWith((states) {
|
|
if (states.contains(WidgetState.selected)) {
|
|
return TypographyTokens.navigationLabelSelected;
|
|
}
|
|
return TypographyTokens.navigationLabel;
|
|
}),
|
|
);
|
|
|
|
/// Configuration des dialogues
|
|
static final DialogTheme _dialogTheme = DialogTheme(
|
|
backgroundColor: ColorTokens.surfaceContainer,
|
|
elevation: SpacingTokens.elevationLg,
|
|
shadowColor: ColorTokens.shadow,
|
|
surfaceTintColor: ColorTokens.surfaceContainer,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(SpacingTokens.radiusXl),
|
|
),
|
|
titleTextStyle: TypographyTokens.headlineSmall,
|
|
contentTextStyle: TypographyTokens.bodyMedium,
|
|
);
|
|
|
|
/// Configuration des snackbars
|
|
static final SnackBarThemeData _snackBarTheme = SnackBarThemeData(
|
|
backgroundColor: ColorTokens.onSurface,
|
|
contentTextStyle: TypographyTokens.bodyMedium.copyWith(
|
|
color: ColorTokens.surface,
|
|
),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(SpacingTokens.radiusMd),
|
|
),
|
|
behavior: SnackBarBehavior.floating,
|
|
);
|
|
|
|
/// Configuration des puces
|
|
static final ChipThemeData _chipTheme = ChipThemeData(
|
|
backgroundColor: ColorTokens.surfaceVariant,
|
|
selectedColor: ColorTokens.primaryContainer,
|
|
labelStyle: TypographyTokens.labelMedium,
|
|
padding: const EdgeInsets.symmetric(
|
|
horizontal: SpacingTokens.md,
|
|
vertical: SpacingTokens.sm,
|
|
),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(SpacingTokens.radiusMd),
|
|
),
|
|
);
|
|
|
|
/// Configuration des éléments de liste
|
|
static const ListTileThemeData _listTileTheme = ListTileThemeData(
|
|
contentPadding: EdgeInsets.symmetric(
|
|
horizontal: SpacingTokens.xl,
|
|
vertical: SpacingTokens.md,
|
|
),
|
|
titleTextStyle: TypographyTokens.titleMedium,
|
|
subtitleTextStyle: TypographyTokens.bodyMedium,
|
|
leadingAndTrailingTextStyle: TypographyTokens.labelMedium,
|
|
minVerticalPadding: SpacingTokens.md,
|
|
);
|
|
|
|
/// Configuration des onglets
|
|
static final TabBarTheme _tabBarTheme = TabBarTheme(
|
|
labelColor: ColorTokens.primary,
|
|
unselectedLabelColor: ColorTokens.onSurfaceVariant,
|
|
labelStyle: TypographyTokens.titleSmall,
|
|
unselectedLabelStyle: TypographyTokens.titleSmall,
|
|
indicator: UnderlineTabIndicator(
|
|
borderSide: const BorderSide(
|
|
color: ColorTokens.primary,
|
|
width: 2.0,
|
|
),
|
|
borderRadius: BorderRadius.circular(SpacingTokens.radiusXs),
|
|
),
|
|
);
|
|
|
|
/// Configuration des dividers
|
|
static const DividerThemeData _dividerTheme = DividerThemeData(
|
|
color: ColorTokens.outline,
|
|
thickness: 1.0,
|
|
space: SpacingTokens.md,
|
|
);
|
|
|
|
/// Configuration des icônes
|
|
static const IconThemeData _iconTheme = IconThemeData(
|
|
color: ColorTokens.onSurfaceVariant,
|
|
size: 24.0,
|
|
);
|
|
|
|
/// Configuration des transitions de page
|
|
static const PageTransitionsTheme _pageTransitionsTheme = PageTransitionsTheme(
|
|
builders: {
|
|
TargetPlatform.android: CupertinoPageTransitionsBuilder(),
|
|
TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
|
|
},
|
|
);
|
|
|
|
/// Extensions personnalisées - Couleurs
|
|
static const CustomColors _customColors = CustomColors();
|
|
|
|
/// Extensions personnalisées - Espacements
|
|
static const CustomSpacing _customSpacing = CustomSpacing();
|
|
}
|
|
|
|
/// Extension de couleurs personnalisées
|
|
class CustomColors extends ThemeExtension<CustomColors> {
|
|
const CustomColors();
|
|
|
|
@override
|
|
CustomColors copyWith() => const CustomColors();
|
|
|
|
@override
|
|
CustomColors lerp(ThemeExtension<CustomColors>? other, double t) {
|
|
return const CustomColors();
|
|
}
|
|
}
|
|
|
|
/// Extension d'espacements personnalisés
|
|
class CustomSpacing extends ThemeExtension<CustomSpacing> {
|
|
const CustomSpacing();
|
|
|
|
@override
|
|
CustomSpacing copyWith() => const CustomSpacing();
|
|
|
|
@override
|
|
CustomSpacing lerp(ThemeExtension<CustomSpacing>? other, double t) {
|
|
return const CustomSpacing();
|
|
}
|
|
}
|