Files
unionflow-mobile-apps/lib/shared/design_system/theme/app_theme_sophisticated.dart
dahoud 7cd7c6fc9e feat(shared): legacy presentation/ + shared design system + widgets
- 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
2026-04-15 20:27:23 +00:00

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();
}