379 lines
13 KiB
Dart
379 lines
13 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
|
|
import 'package:worker/core/theme/colors.dart';
|
|
import 'package:worker/core/theme/typography.dart';
|
|
|
|
/// App theme configuration for Material 3 design system
|
|
/// Uses ColorScheme.fromSeed() to auto-generate harmonious colors from brand seed color
|
|
class AppTheme {
|
|
AppTheme._();
|
|
|
|
// ==================== Light Theme ====================
|
|
|
|
/// Light theme configuration
|
|
/// [seedColor] - Optional custom seed color, defaults to AppColors.defaultSeedColor
|
|
static ThemeData lightTheme([Color? seedColor]) {
|
|
final seed = seedColor ?? AppColors.defaultSeedColor;
|
|
final ColorScheme colorScheme = ColorScheme.fromSeed(
|
|
seedColor: seed,
|
|
brightness: Brightness.light,
|
|
).copyWith(primary: seed);
|
|
|
|
return ThemeData(
|
|
useMaterial3: true,
|
|
colorScheme: colorScheme,
|
|
fontFamily: AppTypography.fontFamily,
|
|
|
|
// AppBar uses colorScheme colors
|
|
appBarTheme: AppBarTheme(
|
|
elevation: 0,
|
|
centerTitle: false,
|
|
backgroundColor: colorScheme.surface,
|
|
foregroundColor: colorScheme.onSurface,
|
|
titleTextStyle: AppTypography.titleLarge.copyWith(
|
|
color: colorScheme.onSurface,
|
|
fontWeight: FontWeight.w600,
|
|
),
|
|
iconTheme: IconThemeData(color: colorScheme.onSurface, size: 24),
|
|
systemOverlayStyle: SystemUiOverlayStyle.dark,
|
|
),
|
|
|
|
// Card Theme
|
|
cardTheme: CardThemeData(
|
|
elevation: 1,
|
|
shape: const RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.all(Radius.circular(12)),
|
|
),
|
|
clipBehavior: Clip.antiAlias,
|
|
color: colorScheme.surface,
|
|
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
|
),
|
|
|
|
// Elevated Button Theme
|
|
elevatedButtonTheme: ElevatedButtonThemeData(
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: colorScheme.primary,
|
|
foregroundColor: colorScheme.onPrimary,
|
|
elevation: 1,
|
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
|
textStyle: AppTypography.buttonText,
|
|
minimumSize: const Size(64, 48),
|
|
),
|
|
),
|
|
|
|
// Text Button Theme
|
|
textButtonTheme: TextButtonThemeData(
|
|
style: TextButton.styleFrom(
|
|
foregroundColor: colorScheme.primary,
|
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
|
textStyle: AppTypography.buttonText,
|
|
),
|
|
),
|
|
|
|
// Outlined Button Theme
|
|
outlinedButtonTheme: OutlinedButtonThemeData(
|
|
style: OutlinedButton.styleFrom(
|
|
foregroundColor: colorScheme.primary,
|
|
side: BorderSide(color: colorScheme.outline, width: 1),
|
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
|
textStyle: AppTypography.buttonText,
|
|
minimumSize: const Size(64, 48),
|
|
),
|
|
),
|
|
|
|
// Input Decoration Theme
|
|
inputDecorationTheme: InputDecorationTheme(
|
|
filled: true,
|
|
fillColor: colorScheme.surfaceContainerLowest,
|
|
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
|
|
border: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(8),
|
|
borderSide: BorderSide(color: colorScheme.outline, width: 1),
|
|
),
|
|
enabledBorder: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(8),
|
|
borderSide: BorderSide(color: colorScheme.outline, width: 1),
|
|
),
|
|
focusedBorder: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(8),
|
|
borderSide: BorderSide(color: colorScheme.primary, width: 2),
|
|
),
|
|
errorBorder: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(8),
|
|
borderSide: BorderSide(color: colorScheme.error, width: 1),
|
|
),
|
|
focusedErrorBorder: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(8),
|
|
borderSide: BorderSide(color: colorScheme.error, width: 2),
|
|
),
|
|
labelStyle: AppTypography.bodyMedium.copyWith(
|
|
color: colorScheme.onSurfaceVariant,
|
|
),
|
|
hintStyle: AppTypography.bodyMedium.copyWith(
|
|
color: colorScheme.onSurfaceVariant,
|
|
),
|
|
errorStyle: AppTypography.bodySmall.copyWith(color: colorScheme.error),
|
|
),
|
|
|
|
// Bottom Navigation Bar Theme
|
|
bottomNavigationBarTheme: BottomNavigationBarThemeData(
|
|
backgroundColor: colorScheme.surface,
|
|
selectedItemColor: colorScheme.primary,
|
|
unselectedItemColor: colorScheme.onSurfaceVariant,
|
|
selectedIconTheme: IconThemeData(size: 28, color: colorScheme.primary),
|
|
unselectedIconTheme: IconThemeData(
|
|
size: 24,
|
|
color: colorScheme.onSurfaceVariant,
|
|
),
|
|
selectedLabelStyle: const TextStyle(
|
|
fontSize: 12,
|
|
fontWeight: FontWeight.w600,
|
|
fontFamily: AppTypography.fontFamily,
|
|
),
|
|
unselectedLabelStyle: const TextStyle(
|
|
fontSize: 12,
|
|
fontWeight: FontWeight.normal,
|
|
fontFamily: AppTypography.fontFamily,
|
|
),
|
|
type: BottomNavigationBarType.fixed,
|
|
elevation: 3,
|
|
),
|
|
|
|
// Floating Action Button Theme
|
|
floatingActionButtonTheme: FloatingActionButtonThemeData(
|
|
backgroundColor: colorScheme.primaryContainer,
|
|
foregroundColor: colorScheme.onPrimaryContainer,
|
|
elevation: 3,
|
|
shape: const CircleBorder(),
|
|
),
|
|
|
|
// Chip Theme
|
|
chipTheme: ChipThemeData(
|
|
backgroundColor: colorScheme.surfaceContainerLow,
|
|
selectedColor: colorScheme.primaryContainer,
|
|
disabledColor: colorScheme.surfaceContainerLowest,
|
|
labelStyle: AppTypography.labelMedium,
|
|
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
|
),
|
|
|
|
// Dialog Theme
|
|
dialogTheme: DialogThemeData(
|
|
backgroundColor: colorScheme.surface,
|
|
elevation: 3,
|
|
shape: const RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.all(Radius.circular(16)),
|
|
),
|
|
titleTextStyle: AppTypography.headlineMedium.copyWith(
|
|
color: colorScheme.onSurface,
|
|
),
|
|
contentTextStyle: AppTypography.bodyLarge.copyWith(
|
|
color: colorScheme.onSurfaceVariant,
|
|
),
|
|
),
|
|
|
|
// Snackbar Theme
|
|
snackBarTheme: SnackBarThemeData(
|
|
backgroundColor: colorScheme.inverseSurface,
|
|
contentTextStyle: AppTypography.bodyMedium.copyWith(
|
|
color: colorScheme.onInverseSurface,
|
|
),
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
|
behavior: SnackBarBehavior.floating,
|
|
elevation: 3,
|
|
),
|
|
|
|
// Divider Theme
|
|
dividerTheme: DividerThemeData(
|
|
color: colorScheme.outlineVariant,
|
|
thickness: 1,
|
|
space: 1,
|
|
),
|
|
|
|
// Icon Theme
|
|
iconTheme: IconThemeData(color: colorScheme.onSurface, size: 24),
|
|
|
|
// List Tile Theme
|
|
listTileTheme: ListTileThemeData(
|
|
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
|
titleTextStyle: AppTypography.titleMedium.copyWith(
|
|
color: colorScheme.onSurface,
|
|
),
|
|
subtitleTextStyle: AppTypography.bodyMedium.copyWith(
|
|
color: colorScheme.onSurfaceVariant,
|
|
),
|
|
iconColor: colorScheme.onSurfaceVariant,
|
|
),
|
|
|
|
// Progress Indicator Theme
|
|
progressIndicatorTheme: ProgressIndicatorThemeData(
|
|
color: colorScheme.primary,
|
|
linearTrackColor: colorScheme.surfaceContainerHighest,
|
|
circularTrackColor: colorScheme.surfaceContainerHighest,
|
|
),
|
|
|
|
// Badge Theme
|
|
badgeTheme: const BadgeThemeData(
|
|
backgroundColor: AppColors.danger,
|
|
textColor: Colors.white,
|
|
smallSize: 6,
|
|
largeSize: 16,
|
|
),
|
|
|
|
// Tab Bar Theme
|
|
tabBarTheme: TabBarThemeData(
|
|
labelColor: colorScheme.primary,
|
|
unselectedLabelColor: colorScheme.onSurfaceVariant,
|
|
indicatorColor: colorScheme.primary,
|
|
labelStyle: AppTypography.labelLarge,
|
|
unselectedLabelStyle: AppTypography.labelLarge,
|
|
),
|
|
);
|
|
}
|
|
|
|
// ==================== Dark Theme ====================
|
|
|
|
/// Dark theme configuration
|
|
/// [seedColor] - Optional custom seed color, defaults to AppColors.defaultSeedColor
|
|
static ThemeData darkTheme([Color? seedColor]) {
|
|
final seed = seedColor ?? AppColors.defaultSeedColor;
|
|
final ColorScheme colorScheme = ColorScheme.fromSeed(
|
|
seedColor: seed,
|
|
brightness: Brightness.dark,
|
|
).copyWith(primary: seed);
|
|
|
|
return ThemeData(
|
|
useMaterial3: true,
|
|
colorScheme: colorScheme,
|
|
fontFamily: AppTypography.fontFamily,
|
|
|
|
// AppBar Theme
|
|
appBarTheme: AppBarTheme(
|
|
elevation: 0,
|
|
centerTitle: false,
|
|
backgroundColor: colorScheme.surface,
|
|
foregroundColor: colorScheme.onSurface,
|
|
titleTextStyle: AppTypography.titleLarge.copyWith(
|
|
color: colorScheme.onSurface,
|
|
fontWeight: FontWeight.w600,
|
|
),
|
|
iconTheme: IconThemeData(color: colorScheme.onSurface, size: 24),
|
|
systemOverlayStyle: SystemUiOverlayStyle.light,
|
|
),
|
|
|
|
// Card Theme
|
|
cardTheme: CardThemeData(
|
|
elevation: 1,
|
|
shape: const RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.all(Radius.circular(12)),
|
|
),
|
|
clipBehavior: Clip.antiAlias,
|
|
color: colorScheme.surfaceContainer,
|
|
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
|
),
|
|
|
|
// Elevated Button Theme
|
|
elevatedButtonTheme: ElevatedButtonThemeData(
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: colorScheme.primary,
|
|
foregroundColor: colorScheme.onPrimary,
|
|
elevation: 1,
|
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
|
textStyle: AppTypography.buttonText,
|
|
minimumSize: const Size(64, 48),
|
|
),
|
|
),
|
|
|
|
// Input Decoration Theme
|
|
inputDecorationTheme: InputDecorationTheme(
|
|
filled: true,
|
|
fillColor: colorScheme.surfaceContainerHighest,
|
|
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
|
|
border: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(8),
|
|
borderSide: BorderSide(color: colorScheme.outline, width: 1),
|
|
),
|
|
enabledBorder: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(8),
|
|
borderSide: BorderSide(color: colorScheme.outline, width: 1),
|
|
),
|
|
focusedBorder: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(8),
|
|
borderSide: BorderSide(color: colorScheme.primary, width: 2),
|
|
),
|
|
errorBorder: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(8),
|
|
borderSide: BorderSide(color: colorScheme.error, width: 1),
|
|
),
|
|
focusedErrorBorder: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(8),
|
|
borderSide: BorderSide(color: colorScheme.error, width: 2),
|
|
),
|
|
labelStyle: AppTypography.bodyMedium.copyWith(
|
|
color: colorScheme.onSurfaceVariant,
|
|
),
|
|
hintStyle: AppTypography.bodyMedium.copyWith(
|
|
color: colorScheme.onSurfaceVariant,
|
|
),
|
|
errorStyle: AppTypography.bodySmall.copyWith(color: colorScheme.error),
|
|
),
|
|
|
|
// Bottom Navigation Bar Theme
|
|
bottomNavigationBarTheme: BottomNavigationBarThemeData(
|
|
backgroundColor: colorScheme.surface,
|
|
selectedItemColor: colorScheme.primary,
|
|
unselectedItemColor: colorScheme.onSurfaceVariant,
|
|
selectedIconTheme: IconThemeData(size: 28, color: colorScheme.primary),
|
|
unselectedIconTheme: IconThemeData(
|
|
size: 24,
|
|
color: colorScheme.onSurfaceVariant,
|
|
),
|
|
selectedLabelStyle: const TextStyle(
|
|
fontSize: 12,
|
|
fontWeight: FontWeight.w600,
|
|
fontFamily: AppTypography.fontFamily,
|
|
),
|
|
unselectedLabelStyle: const TextStyle(
|
|
fontSize: 12,
|
|
fontWeight: FontWeight.normal,
|
|
fontFamily: AppTypography.fontFamily,
|
|
),
|
|
type: BottomNavigationBarType.fixed,
|
|
elevation: 3,
|
|
),
|
|
|
|
// Floating Action Button Theme
|
|
floatingActionButtonTheme: FloatingActionButtonThemeData(
|
|
backgroundColor: colorScheme.primaryContainer,
|
|
foregroundColor: colorScheme.onPrimaryContainer,
|
|
elevation: 3,
|
|
shape: const CircleBorder(),
|
|
),
|
|
|
|
// Snackbar Theme
|
|
snackBarTheme: SnackBarThemeData(
|
|
backgroundColor: colorScheme.inverseSurface,
|
|
contentTextStyle: AppTypography.bodyMedium.copyWith(
|
|
color: colorScheme.onInverseSurface,
|
|
),
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
|
behavior: SnackBarBehavior.floating,
|
|
elevation: 3,
|
|
),
|
|
|
|
// Badge Theme
|
|
badgeTheme: const BadgeThemeData(
|
|
backgroundColor: AppColors.danger,
|
|
textColor: Colors.white,
|
|
smallSize: 6,
|
|
largeSize: 16,
|
|
),
|
|
);
|
|
}
|
|
}
|