Files
worker/lib/core/theme/app_theme.dart
2025-11-20 10:44:51 +07:00

421 lines
15 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
/// Provides both light and dark theme variants
class AppTheme {
// Prevent instantiation
AppTheme._();
// ==================== Light Theme ====================
/// Light theme configuration
static ThemeData lightTheme() {
final ColorScheme colorScheme = ColorScheme.fromSeed(
seedColor: AppColors.primaryBlue,
brightness: Brightness.light,
primary: AppColors.primaryBlue,
secondary: AppColors.lightBlue,
tertiary: AppColors.accentCyan,
error: AppColors.danger,
surface: AppColors.white,
);
return ThemeData(
useMaterial3: true,
colorScheme: colorScheme,
fontFamily: AppTypography.fontFamily,
// ==================== App Bar Theme ====================
appBarTheme: AppBarTheme(
elevation: 0,
centerTitle: true,
backgroundColor: AppColors.primaryBlue,
foregroundColor: AppColors.white,
titleTextStyle: AppTypography.titleLarge.copyWith(
color: AppColors.white,
fontWeight: FontWeight.w600,
),
iconTheme: const IconThemeData(color: AppColors.white, size: 24),
systemOverlayStyle: SystemUiOverlayStyle.light,
),
// ==================== Card Theme ====================
cardTheme: const CardThemeData(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
),
clipBehavior: Clip.antiAlias,
color: AppColors.white,
margin: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
),
// ==================== Elevated Button Theme ====================
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.primaryBlue,
foregroundColor: AppColors.white,
elevation: 2,
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: AppColors.primaryBlue,
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: AppColors.primaryBlue,
side: const BorderSide(color: AppColors.primaryBlue, width: 1.5),
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: AppColors.white,
contentPadding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 16,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: AppColors.grey100, width: 1),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: AppColors.grey100, width: 1),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: AppColors.primaryBlue, width: 2),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: AppColors.danger, width: 1),
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: AppColors.danger, width: 2),
),
labelStyle: AppTypography.bodyMedium.copyWith(color: AppColors.grey500),
hintStyle: AppTypography.bodyMedium.copyWith(color: AppColors.grey500),
errorStyle: AppTypography.bodySmall.copyWith(color: AppColors.danger),
),
// ==================== Bottom Navigation Bar Theme ====================
bottomNavigationBarTheme: const BottomNavigationBarThemeData(
backgroundColor: AppColors.white,
selectedItemColor: AppColors.primaryBlue,
unselectedItemColor: AppColors.grey500,
selectedIconTheme: IconThemeData(
size: 28,
color: AppColors.primaryBlue,
),
unselectedIconTheme: IconThemeData(size: 24, color: AppColors.grey500),
selectedLabelStyle: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
fontFamily: AppTypography.fontFamily,
),
unselectedLabelStyle: TextStyle(
fontSize: 12,
fontWeight: FontWeight.normal,
fontFamily: AppTypography.fontFamily,
),
type: BottomNavigationBarType.fixed,
elevation: 8,
),
// ==================== Floating Action Button Theme ====================
floatingActionButtonTheme: const FloatingActionButtonThemeData(
backgroundColor: AppColors.accentCyan,
foregroundColor: AppColors.white,
elevation: 6,
shape: CircleBorder(),
iconSize: 24,
),
// ==================== Chip Theme ====================
chipTheme: ChipThemeData(
backgroundColor: AppColors.grey50,
selectedColor: AppColors.primaryBlue,
disabledColor: AppColors.grey100,
secondarySelectedColor: AppColors.lightBlue,
labelStyle: AppTypography.labelMedium,
secondaryLabelStyle: AppTypography.labelMedium.copyWith(
color: AppColors.white,
),
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
),
// ==================== Dialog Theme ====================
dialogTheme:
const DialogThemeData(
backgroundColor: AppColors.white,
elevation: 8,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(16)),
),
).copyWith(
titleTextStyle: AppTypography.headlineMedium.copyWith(
color: AppColors.grey900,
),
contentTextStyle: AppTypography.bodyLarge.copyWith(
color: AppColors.grey900,
),
),
// ==================== Snackbar Theme ====================
snackBarTheme: SnackBarThemeData(
backgroundColor: AppColors.grey900,
contentTextStyle: AppTypography.bodyMedium.copyWith(
color: AppColors.white,
),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
behavior: SnackBarBehavior.floating,
elevation: 4,
),
// ==================== Divider Theme ====================
dividerTheme: const DividerThemeData(
color: AppColors.grey100,
thickness: 1,
space: 1,
),
// ==================== Icon Theme ====================
iconTheme: const IconThemeData(color: AppColors.grey900, size: 24),
// ==================== List Tile Theme ====================
listTileTheme: ListTileThemeData(
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
titleTextStyle: AppTypography.titleMedium.copyWith(
color: AppColors.grey900,
),
subtitleTextStyle: AppTypography.bodyMedium.copyWith(
color: AppColors.grey500,
),
iconColor: AppColors.grey500,
),
// ==================== Switch Theme ====================
switchTheme: SwitchThemeData(
thumbColor: MaterialStateProperty.resolveWith((states) {
if (states.contains(MaterialState.selected)) {
return AppColors.primaryBlue;
}
return AppColors.grey500;
}),
trackColor: MaterialStateProperty.resolveWith((states) {
if (states.contains(MaterialState.selected)) {
return AppColors.lightBlue;
}
return AppColors.grey100;
}),
),
// ==================== Checkbox Theme ====================
checkboxTheme: CheckboxThemeData(
fillColor: MaterialStateProperty.resolveWith((states) {
if (states.contains(MaterialState.selected)) {
return AppColors.primaryBlue;
}
return AppColors.white;
}),
checkColor: MaterialStateProperty.all(AppColors.white),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)),
),
// ==================== Radio Theme ====================
radioTheme: RadioThemeData(
fillColor: MaterialStateProperty.resolveWith((states) {
if (states.contains(MaterialState.selected)) {
return AppColors.primaryBlue;
}
return AppColors.grey500;
}),
),
// ==================== Progress Indicator Theme ====================
progressIndicatorTheme: const ProgressIndicatorThemeData(
color: AppColors.primaryBlue,
linearTrackColor: AppColors.grey100,
circularTrackColor: AppColors.grey100,
),
// ==================== Badge Theme ====================
badgeTheme: const BadgeThemeData(
backgroundColor: AppColors.danger,
textColor: AppColors.white,
smallSize: 6,
largeSize: 16,
),
// ==================== Tab Bar Theme ====================
tabBarTheme:
const TabBarThemeData(
labelColor: AppColors.primaryBlue,
unselectedLabelColor: AppColors.grey500,
indicatorColor: AppColors.primaryBlue,
).copyWith(
labelStyle: AppTypography.labelLarge,
unselectedLabelStyle: AppTypography.labelLarge,
),
);
}
// ==================== Dark Theme ====================
/// Dark theme configuration
static ThemeData darkTheme() {
final ColorScheme colorScheme = ColorScheme.fromSeed(
seedColor: AppColors.primaryBlue,
brightness: Brightness.dark,
primary: AppColors.lightBlue,
secondary: AppColors.accentCyan,
tertiary: AppColors.primaryBlue,
error: AppColors.danger,
surface: const Color(0xFF1E1E1E),
);
return ThemeData(
useMaterial3: true,
colorScheme: colorScheme,
fontFamily: AppTypography.fontFamily,
// ==================== App Bar Theme ====================
appBarTheme: AppBarTheme(
elevation: 0,
centerTitle: true,
backgroundColor: const Color(0xFF1E1E1E),
foregroundColor: AppColors.white,
titleTextStyle: AppTypography.titleLarge.copyWith(
color: AppColors.white,
fontWeight: FontWeight.w600,
),
iconTheme: const IconThemeData(color: AppColors.white, size: 24),
systemOverlayStyle: SystemUiOverlayStyle.light,
),
// ==================== Card Theme ====================
cardTheme: const CardThemeData(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
),
clipBehavior: Clip.antiAlias,
color: Color(0xFF1E1E1E),
margin: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
),
// ==================== Elevated Button Theme ====================
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.lightBlue,
foregroundColor: AppColors.white,
elevation: 2,
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: const Color(0xFF2A2A2A),
contentPadding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 16,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: Color(0xFF3A3A3A), width: 1),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: Color(0xFF3A3A3A), width: 1),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: AppColors.lightBlue, width: 2),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: AppColors.danger, width: 1),
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: const BorderSide(color: AppColors.danger, width: 2),
),
labelStyle: AppTypography.bodyMedium.copyWith(color: AppColors.grey500),
hintStyle: AppTypography.bodyMedium.copyWith(color: AppColors.grey500),
errorStyle: AppTypography.bodySmall.copyWith(color: AppColors.danger),
),
// ==================== Bottom Navigation Bar Theme ====================
bottomNavigationBarTheme: const BottomNavigationBarThemeData(
backgroundColor: Color(0xFF1E1E1E),
selectedItemColor: AppColors.lightBlue,
unselectedItemColor: AppColors.grey500,
selectedIconTheme: IconThemeData(size: 28, color: AppColors.lightBlue),
unselectedIconTheme: IconThemeData(size: 24, color: AppColors.grey500),
selectedLabelStyle: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
fontFamily: AppTypography.fontFamily,
),
unselectedLabelStyle: TextStyle(
fontSize: 12,
fontWeight: FontWeight.normal,
fontFamily: AppTypography.fontFamily,
),
type: BottomNavigationBarType.fixed,
elevation: 8,
),
// ==================== Floating Action Button Theme ====================
floatingActionButtonTheme: const FloatingActionButtonThemeData(
backgroundColor: AppColors.accentCyan,
foregroundColor: AppColors.white,
elevation: 6,
shape: CircleBorder(),
iconSize: 24,
),
// ==================== Snackbar Theme ====================
snackBarTheme: SnackBarThemeData(
backgroundColor: const Color(0xFF2A2A2A),
contentTextStyle: AppTypography.bodyMedium.copyWith(
color: AppColors.white,
),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
behavior: SnackBarBehavior.floating,
elevation: 4,
),
);
}
}