- lib/presentation : pages legacy (explore/network, notifications) avec BLoC - lib/shared/design_system : UnionFlow Design System v2 (tokens, components) + MD3 tokens + module_colors par feature - lib/shared/widgets : widgets transversaux (core_card, core_shimmer, error_widget, loading_widget, powered_by_lions_dev, etc.) - lib/shared/constants + utils
659 lines
28 KiB
Dart
659 lines
28 KiB
Dart
/// 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<CustomColors> {
|
|
const CustomColors();
|
|
@override
|
|
CustomColors copyWith() => const CustomColors();
|
|
@override
|
|
CustomColors lerp(ThemeExtension<CustomColors>? other, double t) =>
|
|
const CustomColors();
|
|
}
|
|
|
|
class CustomSpacing extends ThemeExtension<CustomSpacing> {
|
|
const CustomSpacing();
|
|
@override
|
|
CustomSpacing copyWith() => const CustomSpacing();
|
|
@override
|
|
CustomSpacing lerp(ThemeExtension<CustomSpacing>? other, double t) =>
|
|
const CustomSpacing();
|
|
}
|