bharat_erp/lib/core/theme/app_theme.dart
SurendarSuri30 8f852ac4f6 Initial commit: Bharat ERP Flutter application.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-19 15:04:06 +05:30

230 lines
8.6 KiB
Dart

import 'package:flutter/material.dart';
import 'app_colors.dart';
import 'app_typography.dart';
import 'branding_config.dart';
class AppTheme {
AppTheme._();
static ThemeData light({BrandingConfig? branding}) {
final primary = branding?.primaryColor ?? AppColors.primary;
final secondary = branding?.secondaryColor ?? AppColors.secondary;
final colorScheme = ColorScheme.fromSeed(
seedColor: primary,
secondary: secondary,
brightness: Brightness.light,
surface: AppColors.lightSurface,
);
return _buildTheme(colorScheme, Brightness.light);
}
static ThemeData dark({BrandingConfig? branding}) {
final primary = branding?.primaryColor ?? AppColors.primary;
final secondary = branding?.secondaryColor ?? AppColors.secondary;
final colorScheme = ColorScheme.fromSeed(
seedColor: primary,
secondary: secondary,
brightness: Brightness.dark,
surface: AppColors.darkSurface,
);
return _buildTheme(colorScheme, Brightness.dark);
}
/// Theme for white cards, form fields, and picker sheets (unchanged in dark mode).
static ThemeData cardContentTheme(ThemeData theme) {
final scheme = theme.brightness == Brightness.light
? theme.colorScheme
: ColorScheme.fromSeed(
seedColor: theme.colorScheme.primary,
secondary: theme.colorScheme.secondary,
brightness: Brightness.light,
surface: AppColors.card,
);
final base = theme.brightness == Brightness.light
? theme
: theme.copyWith(
brightness: Brightness.light,
colorScheme: scheme,
textTheme: AppTypography.textTheme(scheme),
primaryTextTheme: AppTypography.textTheme(scheme),
);
return base.copyWith(
scaffoldBackgroundColor: AppColors.card,
inputDecorationTheme: whiteInputDecorationTheme(scheme),
bottomSheetTheme: const BottomSheetThemeData(
backgroundColor: AppColors.card,
surfaceTintColor: Colors.transparent,
dragHandleColor: Color(0xFFBDBDBD),
),
listTileTheme: ListTileThemeData(
tileColor: AppColors.card,
selectedTileColor: scheme.primary.withValues(alpha: 0.08),
textColor: scheme.onSurface,
iconColor: scheme.onSurfaceVariant,
),
dividerTheme: DividerThemeData(
color: scheme.outline.withValues(alpha: 0.15),
),
);
}
static InputDecorationTheme whiteInputDecorationTheme(ColorScheme scheme) {
final textTheme = AppTypography.textTheme(scheme);
return InputDecorationTheme(
filled: true,
fillColor: AppColors.card,
border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(color: scheme.outline.withValues(alpha: 0.35)),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(color: scheme.primary, width: 2),
),
disabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(color: scheme.outline.withValues(alpha: 0.2)),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(color: scheme.error),
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(color: scheme.error, width: 2),
),
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
labelStyle: textTheme.bodyMedium,
hintStyle: textTheme.bodyMedium?.copyWith(color: scheme.onSurfaceVariant),
helperStyle: textTheme.bodySmall,
errorStyle: textTheme.bodySmall?.copyWith(color: scheme.error),
);
}
static ThemeData _buildTheme(ColorScheme colorScheme, Brightness brightness) {
final isDark = brightness == Brightness.dark;
final textTheme = AppTypography.textTheme(colorScheme);
return ThemeData(
useMaterial3: true,
fontFamily: AppTypography.fontFamily,
colorScheme: colorScheme,
brightness: brightness,
textTheme: textTheme,
primaryTextTheme: textTheme,
scaffoldBackgroundColor:
isDark ? AppColors.darkBackground : AppColors.lightBackground,
appBarTheme: AppBarTheme(
centerTitle: false,
elevation: 0,
scrolledUnderElevation: 1,
backgroundColor: isDark ? AppColors.darkSurface : AppColors.lightSurface,
foregroundColor: isDark ? AppColors.textOnDark : AppColors.textPrimary,
titleTextStyle: textTheme.titleLarge,
toolbarTextStyle: textTheme.bodyLarge,
),
cardTheme: CardThemeData(
color: isDark ? AppColors.darkSurface : AppColors.lightSurface,
surfaceTintColor: Colors.transparent,
elevation: isDark ? 2 : 1,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
clipBehavior: Clip.antiAlias,
),
inputDecorationTheme: InputDecorationTheme(
filled: true,
fillColor: isDark
? colorScheme.surfaceContainerHighest
: colorScheme.surfaceContainerHighest.withValues(alpha: 0.5),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(color: colorScheme.outline.withValues(alpha: 0.5)),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(color: colorScheme.primary, width: 2),
),
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
labelStyle: textTheme.bodyMedium,
hintStyle: textTheme.bodyMedium?.copyWith(color: colorScheme.onSurfaceVariant),
helperStyle: textTheme.bodySmall,
errorStyle: textTheme.bodySmall?.copyWith(color: colorScheme.error),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
minimumSize: const Size(0, 48),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
textStyle: textTheme.labelLarge,
),
),
outlinedButtonTheme: OutlinedButtonThemeData(
style: OutlinedButton.styleFrom(
minimumSize: const Size(0, 48),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
textStyle: textTheme.labelLarge,
),
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
minimumSize: const Size(0, 48),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
textStyle: textTheme.labelLarge,
),
),
navigationRailTheme: NavigationRailThemeData(
backgroundColor: isDark ? AppColors.darkSurface : AppColors.lightSurface,
selectedIconTheme: IconThemeData(color: colorScheme.primary),
selectedLabelTextStyle: textTheme.labelMedium?.copyWith(color: colorScheme.primary),
unselectedLabelTextStyle: textTheme.labelMedium,
),
drawerTheme: DrawerThemeData(
backgroundColor: isDark ? AppColors.darkSurface : AppColors.lightSurface,
),
dividerTheme: DividerThemeData(
color: colorScheme.outline.withValues(alpha: 0.2),
),
snackBarTheme: SnackBarThemeData(
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
contentTextStyle: textTheme.bodyMedium?.copyWith(color: colorScheme.onInverseSurface),
),
dataTableTheme: DataTableThemeData(
headingRowColor: WidgetStateProperty.all(
colorScheme.surfaceContainerHighest.withValues(alpha: 0.5),
),
headingTextStyle: textTheme.labelLarge,
dataTextStyle: textTheme.bodyMedium,
),
chipTheme: ChipThemeData(
labelStyle: textTheme.labelSmall,
),
dialogTheme: DialogThemeData(
titleTextStyle: textTheme.titleLarge,
contentTextStyle: textTheme.bodyMedium,
),
listTileTheme: ListTileThemeData(
titleTextStyle: textTheme.bodyLarge,
subtitleTextStyle: textTheme.bodySmall,
),
bottomNavigationBarTheme: BottomNavigationBarThemeData(
selectedLabelStyle: textTheme.labelSmall,
unselectedLabelStyle: textTheme.labelSmall,
),
tabBarTheme: TabBarThemeData(
labelStyle: textTheme.labelLarge,
unselectedLabelStyle: textTheme.labelMedium,
),
);
}
}