runable
This commit is contained in:
460
lib/core/theme/app_theme.dart
Normal file
460
lib/core/theme/app_theme.dart
Normal file
@@ -0,0 +1,460 @@
|
||||
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,
|
||||
background: AppColors.grey50,
|
||||
);
|
||||
|
||||
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),
|
||||
background: const Color(0xFF121212),
|
||||
);
|
||||
|
||||
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,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user