/// Thème Sophistiqué UnionFlow — Material Design 3 /// /// Palette WCAG 2.1 validée : #2563EB (primary) + #7616E8 (accent) 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'; class AppThemeSophisticated { AppThemeSophisticated._(); // ═══════════════════════════════════════════════════════════════════════════ // THÈME CLAIR // ═══════════════════════════════════════════════════════════════════════════ static ThemeData get lightTheme { return ThemeData( useMaterial3: true, brightness: Brightness.light, colorScheme: _lightColorScheme, textTheme: _textTheme, appBarTheme: _appBarTheme, cardTheme: _cardTheme, elevatedButtonTheme: _elevatedButtonTheme, filledButtonTheme: _filledButtonTheme, outlinedButtonTheme: _outlinedButtonTheme, textButtonTheme: _textButtonTheme, inputDecorationTheme: _inputDecorationTheme, navigationBarTheme: _navigationBarTheme, navigationDrawerTheme: _navigationDrawerTheme, dialogTheme: _dialogTheme, snackBarTheme: _snackBarTheme, chipTheme: _chipTheme, listTileTheme: _listTileTheme, tabBarTheme: _tabBarTheme, dividerTheme: _dividerTheme, iconTheme: _iconTheme, scaffoldBackgroundColor: ColorTokens.background, canvasColor: ColorTokens.surface, pageTransitionsTheme: _pageTransitionsTheme, extensions: const [_customColors, _customSpacing], ); } // ═══════════════════════════════════════════════════════════════════════════ // THÈME SOMBRE — Navy Profond (#0A0D1A) // ═══════════════════════════════════════════════════════════════════════════ static ThemeData get darkTheme { return ThemeData( useMaterial3: true, brightness: Brightness.dark, colorScheme: _darkColorScheme, textTheme: _textThemeDark, scaffoldBackgroundColor: ColorTokens.backgroundDark, canvasColor: ColorTokens.surfaceDark, appBarTheme: const AppBarTheme( elevation: 0, scrolledUnderElevation: 0, backgroundColor: Colors.transparent, foregroundColor: ColorTokens.onSurfaceDark, surfaceTintColor: Colors.transparent, systemOverlayStyle: SystemUiOverlayStyle( statusBarColor: Colors.transparent, statusBarIconBrightness: Brightness.light, // icônes blanches en dark statusBarBrightness: Brightness.dark, // pour iOS systemNavigationBarColor: Colors.transparent, ), ), dividerTheme: const DividerThemeData( color: ColorTokens.outlineDark, thickness: 1.0, space: SpacingTokens.md, ), cardTheme: CardThemeData( color: ColorTokens.surfaceDark, elevation: 0, shadowColor: Colors.transparent, surfaceTintColor: Colors.transparent, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(SpacingTokens.radiusLg), side: const BorderSide(color: ColorTokens.outlineDark), ), margin: const EdgeInsets.all(SpacingTokens.cardMargin), ), elevatedButtonTheme: ElevatedButtonThemeData( style: ElevatedButton.styleFrom( elevation: SpacingTokens.elevationSm, backgroundColor: ColorTokens.primaryLight, foregroundColor: ColorTokens.onPrimaryContainer, 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), ), ), ), filledButtonTheme: FilledButtonThemeData( style: FilledButton.styleFrom( backgroundColor: ColorTokens.primaryLight, foregroundColor: ColorTokens.onPrimaryContainer, 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), ), ), ), outlinedButtonTheme: OutlinedButtonThemeData( style: OutlinedButton.styleFrom( foregroundColor: ColorTokens.primaryLight, 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.outlineDark), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(SpacingTokens.radiusMd), ), ), ), textButtonTheme: TextButtonThemeData( style: TextButton.styleFrom( foregroundColor: ColorTokens.primaryLight, 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), ), ), ), inputDecorationTheme: InputDecorationTheme( filled: true, fillColor: ColorTokens.surfaceContainerDark, labelStyle: TypographyTokens.inputLabel.copyWith( color: ColorTokens.onSurfaceVariantDark, ), hintStyle: TypographyTokens.inputHint.copyWith( color: ColorTokens.onSurfaceVariantDark, ), border: OutlineInputBorder( borderRadius: BorderRadius.circular(SpacingTokens.radiusMd), borderSide: const BorderSide(color: ColorTokens.outlineDark), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(SpacingTokens.radiusMd), borderSide: const BorderSide(color: ColorTokens.outlineDark), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(SpacingTokens.radiusMd), borderSide: const BorderSide(color: ColorTokens.primaryLight, width: 2.0), ), errorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(SpacingTokens.radiusMd), borderSide: const BorderSide(color: ColorTokens.error), ), contentPadding: const EdgeInsets.all(SpacingTokens.formPadding), ), navigationBarTheme: NavigationBarThemeData( backgroundColor: ColorTokens.navigationBackgroundDark, indicatorColor: ColorTokens.navigationIndicatorDark, labelTextStyle: WidgetStateProperty.resolveWith((states) { if (states.contains(WidgetState.selected)) { return TypographyTokens.navigationLabelSelected.copyWith( color: ColorTokens.navigationSelectedDark, ); } return TypographyTokens.navigationLabel.copyWith( color: ColorTokens.navigationUnselectedDark, ); }), iconTheme: WidgetStateProperty.resolveWith((states) { if (states.contains(WidgetState.selected)) { return const IconThemeData(color: ColorTokens.navigationSelectedDark); } return const IconThemeData(color: ColorTokens.navigationUnselectedDark); }), ), navigationDrawerTheme: NavigationDrawerThemeData( backgroundColor: ColorTokens.surfaceContainerDark, elevation: SpacingTokens.elevationMd, shadowColor: Colors.black, surfaceTintColor: Colors.transparent, indicatorColor: ColorTokens.navigationIndicatorDark, labelTextStyle: WidgetStateProperty.resolveWith((states) { if (states.contains(WidgetState.selected)) { return TypographyTokens.navigationLabelSelected.copyWith( color: ColorTokens.navigationSelectedDark, ); } return TypographyTokens.navigationLabel.copyWith( color: ColorTokens.navigationUnselectedDark, ); }), ), dialogTheme: DialogThemeData( backgroundColor: ColorTokens.surfaceDark, elevation: SpacingTokens.elevationLg, surfaceTintColor: Colors.transparent, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(SpacingTokens.radiusXl), ), titleTextStyle: TypographyTokens.headlineSmall.copyWith( color: ColorTokens.onSurfaceDark, ), contentTextStyle: TypographyTokens.bodyMedium.copyWith( color: ColorTokens.onSurfaceVariantDark, ), ), snackBarTheme: SnackBarThemeData( backgroundColor: ColorTokens.surfaceVariantDark, contentTextStyle: TypographyTokens.bodyMedium.copyWith( color: ColorTokens.onSurfaceDark, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(SpacingTokens.radiusMd), ), behavior: SnackBarBehavior.fixed, ), chipTheme: ChipThemeData( backgroundColor: ColorTokens.surfaceContainerDark, selectedColor: ColorTokens.navigationIndicatorDark, labelStyle: TypographyTokens.labelMedium.copyWith( color: ColorTokens.onSurfaceDark, ), padding: const EdgeInsets.symmetric( horizontal: SpacingTokens.md, vertical: SpacingTokens.sm, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(SpacingTokens.radiusMd), ), ), listTileTheme: ListTileThemeData( contentPadding: const EdgeInsets.symmetric( horizontal: SpacingTokens.xl, vertical: SpacingTokens.md, ), tileColor: ColorTokens.surfaceDark, titleTextStyle: TypographyTokens.titleMedium.copyWith( color: ColorTokens.onSurfaceDark, ), subtitleTextStyle: TypographyTokens.bodyMedium.copyWith( color: ColorTokens.onSurfaceVariantDark, ), minVerticalPadding: SpacingTokens.md, ), tabBarTheme: TabBarThemeData( labelColor: ColorTokens.primaryLight, unselectedLabelColor: ColorTokens.onSurfaceVariantDark, labelStyle: TypographyTokens.titleSmall, unselectedLabelStyle: TypographyTokens.titleSmall, indicator: UnderlineTabIndicator( borderSide: const BorderSide(color: ColorTokens.primaryLight, width: 2.0), borderRadius: BorderRadius.circular(SpacingTokens.radiusXs), ), ), iconTheme: const IconThemeData( color: ColorTokens.onSurfaceVariantDark, size: 24.0, ), pageTransitionsTheme: _pageTransitionsTheme, extensions: const [_customColors, _customSpacing], ); } // ═══════════════════════════════════════════════════════════════════════════ // COLOR SCHEME SOMBRE — Navy profond OLED // ═══════════════════════════════════════════════════════════════════════════ static const ColorScheme _darkColorScheme = ColorScheme.dark( primary: ColorTokens.primaryLight, // #60A5FA sur fond sombre onPrimary: ColorTokens.onPrimaryContainer, // #1E3A8A primaryContainer: ColorTokens.navigationIndicatorDark, // #1A2350 onPrimaryContainer: Color(0xFFD6E8FF), secondary: ColorTokens.secondaryLight, // #9B59F0 onSecondary: ColorTokens.onSecondaryContainer, // #2A006F secondaryContainer: Color(0xFF3B1F6A), onSecondaryContainer: Color(0xFFEAD5FF), surface: ColorTokens.surfaceDark, // #161B26 onSurface: ColorTokens.onSurfaceDark, // #F1F5FF surfaceContainerHighest: ColorTokens.surfaceVariantDark, // #1A1F2E onSurfaceVariant: ColorTokens.onSurfaceVariantDark, // #94A3B8 error: ColorTokens.error, onError: Colors.white, errorContainer: Color(0xFF5C1111), onErrorContainer: ColorTokens.errorLight, outline: ColorTokens.outlineDark, // #2D3554 outlineVariant: Color(0xFF1F2B3E), shadow: ColorTokens.backgroundDark, scrim: Colors.black, inverseSurface: ColorTokens.onSurfaceDark, onInverseSurface: ColorTokens.surfaceDark, inversePrimary: ColorTokens.primary, ); // ═══════════════════════════════════════════════════════════════════════════ // COLOR SCHEME CLAIR // ═══════════════════════════════════════════════════════════════════════════ static const ColorScheme _lightColorScheme = ColorScheme.light( primary: ColorTokens.primary, onPrimary: ColorTokens.onPrimary, primaryContainer: ColorTokens.primaryContainer, onPrimaryContainer: ColorTokens.onPrimaryContainer, secondary: ColorTokens.secondary, onSecondary: ColorTokens.onSecondary, secondaryContainer: ColorTokens.secondaryContainer, onSecondaryContainer: ColorTokens.onSecondaryContainer, tertiary: ColorTokens.tertiary, onTertiary: ColorTokens.onTertiary, tertiaryContainer: ColorTokens.tertiaryContainer, onTertiaryContainer: ColorTokens.onTertiaryContainer, error: ColorTokens.error, onError: ColorTokens.onError, errorContainer: ColorTokens.errorContainer, onErrorContainer: ColorTokens.onErrorContainer, surface: ColorTokens.surface, onSurface: ColorTokens.onSurface, surfaceContainerHighest: ColorTokens.surfaceVariant, onSurfaceVariant: ColorTokens.onSurfaceVariant, outline: ColorTokens.outline, outlineVariant: ColorTokens.outlineVariant, shadow: ColorTokens.shadow, scrim: ColorTokens.shadow, inverseSurface: ColorTokens.onSurface, onInverseSurface: ColorTokens.surface, inversePrimary: ColorTokens.primaryLight, ); // ═══════════════════════════════════════════════════════════════════════════ // TYPOGRAPHIE // ═══════════════════════════════════════════════════════════════════════════ static TextTheme get _textTheme => TextTheme( displayLarge: TypographyTokens.displayLarge, displayMedium: TypographyTokens.displayMedium, displaySmall: TypographyTokens.displaySmall, headlineLarge: TypographyTokens.headlineLarge, headlineMedium: TypographyTokens.headlineMedium, headlineSmall: TypographyTokens.headlineSmall, titleLarge: TypographyTokens.titleLarge, titleMedium: TypographyTokens.titleMedium, titleSmall: TypographyTokens.titleSmall, labelLarge: TypographyTokens.labelLarge, labelMedium: TypographyTokens.labelMedium, labelSmall: TypographyTokens.labelSmall, bodyLarge: TypographyTokens.bodyLarge, bodyMedium: TypographyTokens.bodyMedium, bodySmall: TypographyTokens.bodySmall, ); /// Thème typographique dark — même structure que _textTheme mais avec /// ColorTokens.onSurfaceDark (#F1F5FF) pour que le texte soit lisible /// sur les fonds sombres (#0A0D1A / #161B26). static TextTheme get _textThemeDark => TextTheme( displayLarge: TypographyTokens.displayLarge.copyWith(color: ColorTokens.onSurfaceDark), displayMedium: TypographyTokens.displayMedium.copyWith(color: ColorTokens.onSurfaceDark), displaySmall: TypographyTokens.displaySmall.copyWith(color: ColorTokens.onSurfaceDark), headlineLarge: TypographyTokens.headlineLarge.copyWith(color: ColorTokens.onSurfaceDark), headlineMedium: TypographyTokens.headlineMedium.copyWith(color: ColorTokens.onSurfaceDark), headlineSmall: TypographyTokens.headlineSmall.copyWith(color: ColorTokens.onSurfaceDark), titleLarge: TypographyTokens.titleLarge.copyWith(color: ColorTokens.onSurfaceDark), titleMedium: TypographyTokens.titleMedium.copyWith(color: ColorTokens.onSurfaceDark), titleSmall: TypographyTokens.titleSmall.copyWith(color: ColorTokens.onSurfaceDark), labelLarge: TypographyTokens.labelLarge.copyWith(color: ColorTokens.onSurfaceDark), labelMedium: TypographyTokens.labelMedium.copyWith(color: ColorTokens.onSurfaceDark), labelSmall: TypographyTokens.labelSmall.copyWith(color: ColorTokens.onSurfaceDark), bodyLarge: TypographyTokens.bodyLarge.copyWith(color: ColorTokens.onSurfaceDark), bodyMedium: TypographyTokens.bodyMedium.copyWith(color: ColorTokens.onSurfaceDark), bodySmall: TypographyTokens.bodySmall.copyWith(color: ColorTokens.onSurfaceDark), ); // ═══════════════════════════════════════════════════════════════════════════ // COMPOSANTS // ═══════════════════════════════════════════════════════════════════════════ 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, ), ); static final CardThemeData _cardTheme = CardThemeData( elevation: SpacingTokens.elevationSm, shadowColor: ColorTokens.shadow, surfaceTintColor: Colors.transparent, color: ColorTokens.surface, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(SpacingTokens.radiusLg), side: const BorderSide(color: ColorTokens.outline), ), margin: const EdgeInsets.all(SpacingTokens.cardMargin), ); 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), ), ), ); 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), ), ), ); 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), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(SpacingTokens.radiusMd), ), ), ); 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), ), ), ); 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), ); 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); }), ); static final NavigationDrawerThemeData _navigationDrawerTheme = NavigationDrawerThemeData( backgroundColor: ColorTokens.surfaceContainer, elevation: SpacingTokens.elevationMd, shadowColor: ColorTokens.shadow, surfaceTintColor: Colors.transparent, indicatorColor: ColorTokens.primaryContainer, labelTextStyle: WidgetStateProperty.resolveWith((states) { if (states.contains(WidgetState.selected)) { return TypographyTokens.navigationLabelSelected; } return TypographyTokens.navigationLabel; }), ); static final DialogThemeData _dialogTheme = DialogThemeData( backgroundColor: ColorTokens.surface, elevation: SpacingTokens.elevationLg, shadowColor: ColorTokens.shadow, surfaceTintColor: Colors.transparent, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(SpacingTokens.radiusXl), ), titleTextStyle: TypographyTokens.headlineSmall, contentTextStyle: TypographyTokens.bodyMedium, ); static final SnackBarThemeData _snackBarTheme = SnackBarThemeData( backgroundColor: ColorTokens.onSurface, contentTextStyle: TypographyTokens.bodyMedium.copyWith( color: ColorTokens.surface, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(SpacingTokens.radiusMd), ), behavior: SnackBarBehavior.fixed, ); 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), ), ); 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, ); static final TabBarThemeData _tabBarTheme = TabBarThemeData( 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), ), ); static const DividerThemeData _dividerTheme = DividerThemeData( color: ColorTokens.outline, thickness: 1.0, space: SpacingTokens.md, ); static const IconThemeData _iconTheme = IconThemeData( color: ColorTokens.onSurfaceVariant, size: 24.0, ); static const PageTransitionsTheme _pageTransitionsTheme = PageTransitionsTheme( builders: { TargetPlatform.android: CupertinoPageTransitionsBuilder(), TargetPlatform.iOS: CupertinoPageTransitionsBuilder(), }, ); static const CustomColors _customColors = CustomColors(); static const CustomSpacing _customSpacing = CustomSpacing(); } class CustomColors extends ThemeExtension { const CustomColors(); @override CustomColors copyWith() => const CustomColors(); @override CustomColors lerp(ThemeExtension? other, double t) => const CustomColors(); } class CustomSpacing extends ThemeExtension { const CustomSpacing(); @override CustomSpacing copyWith() => const CustomSpacing(); @override CustomSpacing lerp(ThemeExtension? other, double t) => const CustomSpacing(); }