Add three major UI components with animations and dark mode support: - PremiumRouteCard: Enhanced route cards with left accent bar, delivery count badge, animated hover effects (1.02x scale), and dynamic shadow elevation - DarkModeMapComponent: Google Maps integration with dark theme styling, custom info panels, navigation buttons, and delivery status indicators - DeliveryListItem: Animated list items with staggered entrance animations, status badges with icons, contact indicators, and hover states Updates: - RoutesPage: Now uses PremiumRouteCard with improved visual hierarchy - DeliveriesPage: Integrated DarkModeMapComponent and DeliveryListItem with proper theme awareness - Animation system: Leverages existing AppAnimations constants for 200ms fast interactions and easeOut curves Design philosophy: - Element separation through left accent bars (status-coded) - Elevation and shadow for depth (0.1-0.3 opacity) - Staggered animations for list items (50ms delays) - Dark mode optimized for evening use (reduced brightness) - Responsive hover states with tactile feedback Co-Authored-By: Claude <noreply@anthropic.com>
263 lines
7.8 KiB
Dart
263 lines
7.8 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'spacing_system.dart';
|
|
import 'border_system.dart';
|
|
import 'shadow_system.dart';
|
|
import 'size_system.dart';
|
|
|
|
/// Component Theme Data Builders
|
|
/// Centralized component theme definitions for consistent styling
|
|
class ComponentThemes {
|
|
static CardThemeData cardTheme(ColorScheme colorScheme) {
|
|
return CardThemeData(
|
|
elevation: AppShadow.cardElevation,
|
|
shadowColor: AppShadow.getShadowColor(colorScheme.brightness),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: AppBorders.circularMd,
|
|
),
|
|
clipBehavior: Clip.antiAlias,
|
|
color: colorScheme.surface,
|
|
);
|
|
}
|
|
|
|
static AppBarTheme appBarTheme(ColorScheme colorScheme) {
|
|
return AppBarTheme(
|
|
backgroundColor: colorScheme.surface,
|
|
foregroundColor: colorScheme.onSurface,
|
|
elevation: AppShadow.appBarElevation,
|
|
centerTitle: false,
|
|
iconTheme: IconThemeData(
|
|
color: colorScheme.onSurface,
|
|
size: AppSizes.iconMd,
|
|
),
|
|
titleTextStyle: TextStyle(
|
|
fontFamily: 'Montserrat',
|
|
fontWeight: FontWeight.w600,
|
|
fontSize: 20,
|
|
color: colorScheme.onSurface,
|
|
),
|
|
);
|
|
}
|
|
|
|
static FilledButtonThemeData filledButtonTheme(ColorScheme colorScheme) {
|
|
return FilledButtonThemeData(
|
|
style: FilledButton.styleFrom(
|
|
backgroundColor: colorScheme.primary,
|
|
foregroundColor: colorScheme.onPrimary,
|
|
elevation: AppShadow.elevationSm,
|
|
padding: AppSpacing.paddingButton,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: AppBorders.circularSm,
|
|
),
|
|
textStyle: const TextStyle(
|
|
fontFamily: 'Montserrat',
|
|
fontWeight: FontWeight.w500,
|
|
fontSize: 14,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
static ElevatedButtonThemeData elevatedButtonTheme(ColorScheme colorScheme) {
|
|
return ElevatedButtonThemeData(
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: colorScheme.primary,
|
|
foregroundColor: colorScheme.onPrimary,
|
|
elevation: AppShadow.elevationSm,
|
|
padding: AppSpacing.paddingButton,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: AppBorders.circularSm,
|
|
),
|
|
textStyle: const TextStyle(
|
|
fontFamily: 'Montserrat',
|
|
fontWeight: FontWeight.w500,
|
|
fontSize: 14,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
static OutlinedButtonThemeData outlinedButtonTheme(ColorScheme colorScheme) {
|
|
return OutlinedButtonThemeData(
|
|
style: OutlinedButton.styleFrom(
|
|
foregroundColor: colorScheme.primary,
|
|
side: BorderSide(color: colorScheme.outline),
|
|
padding: AppSpacing.paddingButton,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: AppBorders.circularSm,
|
|
),
|
|
textStyle: const TextStyle(
|
|
fontFamily: 'Montserrat',
|
|
fontWeight: FontWeight.w500,
|
|
fontSize: 14,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
static InputDecorationTheme inputDecorationTheme(ColorScheme colorScheme) {
|
|
return InputDecorationTheme(
|
|
filled: true,
|
|
fillColor: colorScheme.surfaceContainerHighest.withOpacity(0.5),
|
|
contentPadding: EdgeInsets.symmetric(
|
|
horizontal: AppSpacing.inputPadding,
|
|
vertical: AppSpacing.md,
|
|
),
|
|
border: OutlineInputBorder(
|
|
borderRadius: AppBorders.circularSm,
|
|
borderSide: BorderSide(
|
|
color: colorScheme.outline.withOpacity(0.3),
|
|
),
|
|
),
|
|
enabledBorder: OutlineInputBorder(
|
|
borderRadius: AppBorders.circularSm,
|
|
borderSide: BorderSide(
|
|
color: colorScheme.outline.withOpacity(0.3),
|
|
width: 1,
|
|
),
|
|
),
|
|
focusedBorder: OutlineInputBorder(
|
|
borderRadius: AppBorders.circularSm,
|
|
borderSide: BorderSide(
|
|
color: colorScheme.primary,
|
|
width: 2,
|
|
),
|
|
),
|
|
errorBorder: OutlineInputBorder(
|
|
borderRadius: AppBorders.circularSm,
|
|
borderSide: BorderSide(
|
|
color: colorScheme.error,
|
|
width: 1,
|
|
),
|
|
),
|
|
focusedErrorBorder: OutlineInputBorder(
|
|
borderRadius: AppBorders.circularSm,
|
|
borderSide: BorderSide(
|
|
color: colorScheme.error,
|
|
width: 2,
|
|
),
|
|
),
|
|
labelStyle: TextStyle(
|
|
fontFamily: 'Montserrat',
|
|
fontWeight: FontWeight.w500,
|
|
color: colorScheme.onSurfaceVariant,
|
|
),
|
|
hintStyle: TextStyle(
|
|
fontFamily: 'Montserrat',
|
|
fontWeight: FontWeight.w400,
|
|
color: colorScheme.onSurfaceVariant.withOpacity(0.6),
|
|
),
|
|
);
|
|
}
|
|
|
|
static SnackBarThemeData snackBarTheme(ColorScheme colorScheme) {
|
|
return SnackBarThemeData(
|
|
backgroundColor: colorScheme.inverseSurface,
|
|
contentTextStyle: TextStyle(
|
|
fontFamily: 'Montserrat',
|
|
color: colorScheme.onInverseSurface,
|
|
),
|
|
behavior: SnackBarBehavior.floating,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: AppBorders.circularSm,
|
|
),
|
|
);
|
|
}
|
|
|
|
static DialogThemeData dialogTheme(ColorScheme colorScheme) {
|
|
return DialogThemeData(
|
|
backgroundColor: colorScheme.surface,
|
|
elevation: AppShadow.dialogElevation,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: AppBorders.circularLg,
|
|
),
|
|
contentTextStyle: TextStyle(
|
|
fontFamily: 'Montserrat',
|
|
color: colorScheme.onSurface,
|
|
),
|
|
);
|
|
}
|
|
|
|
static BottomNavigationBarThemeData bottomNavigationBarTheme(
|
|
ColorScheme colorScheme,
|
|
) {
|
|
return BottomNavigationBarThemeData(
|
|
backgroundColor: colorScheme.surface,
|
|
selectedItemColor: colorScheme.primary,
|
|
unselectedItemColor: colorScheme.onSurfaceVariant,
|
|
showSelectedLabels: true,
|
|
showUnselectedLabels: true,
|
|
type: BottomNavigationBarType.fixed,
|
|
selectedLabelStyle: const TextStyle(
|
|
fontFamily: 'Montserrat',
|
|
fontWeight: FontWeight.w500,
|
|
fontSize: 12,
|
|
),
|
|
unselectedLabelStyle: const TextStyle(
|
|
fontFamily: 'Montserrat',
|
|
fontWeight: FontWeight.w400,
|
|
fontSize: 12,
|
|
),
|
|
);
|
|
}
|
|
|
|
static ChipThemeData chipTheme(ColorScheme colorScheme) {
|
|
return ChipThemeData(
|
|
backgroundColor: colorScheme.surfaceContainerHighest,
|
|
deleteIconColor: colorScheme.onSurfaceVariant,
|
|
disabledColor: colorScheme.surfaceContainerHighest.withOpacity(0.38),
|
|
padding: EdgeInsets.symmetric(
|
|
horizontal: AppSpacing.sm,
|
|
vertical: AppSpacing.xs,
|
|
),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: AppBorders.circularSm,
|
|
),
|
|
labelStyle: TextStyle(
|
|
fontFamily: 'Montserrat',
|
|
fontWeight: FontWeight.w500,
|
|
color: colorScheme.onSurfaceVariant,
|
|
),
|
|
secondaryLabelStyle: TextStyle(
|
|
fontFamily: 'Montserrat',
|
|
fontWeight: FontWeight.w500,
|
|
color: colorScheme.onSurfaceVariant,
|
|
),
|
|
brightness: colorScheme.brightness,
|
|
);
|
|
}
|
|
|
|
static ProgressIndicatorThemeData progressIndicatorTheme(
|
|
ColorScheme colorScheme,
|
|
) {
|
|
return ProgressIndicatorThemeData(
|
|
color: colorScheme.primary,
|
|
linearTrackColor: colorScheme.surfaceContainerHighest,
|
|
circularTrackColor: colorScheme.surfaceContainerHighest,
|
|
);
|
|
}
|
|
|
|
static FloatingActionButtonThemeData floatingActionButtonTheme(
|
|
ColorScheme colorScheme,
|
|
) {
|
|
return FloatingActionButtonThemeData(
|
|
backgroundColor: colorScheme.primary,
|
|
foregroundColor: colorScheme.onPrimary,
|
|
elevation: AppShadow.fabElevation,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: AppBorders.circularMd,
|
|
),
|
|
);
|
|
}
|
|
|
|
static SliderThemeData sliderTheme(ColorScheme colorScheme) {
|
|
return SliderThemeData(
|
|
trackHeight: 4.0,
|
|
activeTrackColor: colorScheme.primary,
|
|
inactiveTrackColor: colorScheme.surfaceContainerHighest,
|
|
thumbColor: colorScheme.primary,
|
|
overlayColor: colorScheme.primary.withOpacity(0.12),
|
|
valueIndicatorColor: colorScheme.primary,
|
|
);
|
|
}
|
|
}
|