Files
worker/lib/core/theme/app_theme.dart
2025-12-01 15:28:07 +07:00

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