456 lines
15 KiB
Dart
456 lines
15 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
|
|
// Full redesign note:
|
|
// - We keep the existing accessibility intent (larger sizes) but align visuals to a cohesive Material 3 scheme.
|
|
|
|
class AppTheme {
|
|
// ACCESSIBILITY: Larger font size multiplier for elderly users (50+)
|
|
static const double fontSizeMultiplier = 1.3; // 30% larger fonts
|
|
|
|
// Brand seed (used to generate cohesive ColorScheme)
|
|
static const Color seed = Color(0xFF0F766E); // teal (trust + finance)
|
|
static const Color accent = Color(0xFFF59E0B); // amber (celebratory, draws)
|
|
|
|
static ColorScheme _lightScheme() {
|
|
return ColorScheme.fromSeed(
|
|
seedColor: seed,
|
|
brightness: Brightness.light,
|
|
).copyWith(
|
|
tertiary: accent,
|
|
);
|
|
}
|
|
|
|
static ColorScheme _darkScheme() {
|
|
return ColorScheme.fromSeed(
|
|
seedColor: seed,
|
|
brightness: Brightness.dark,
|
|
).copyWith(
|
|
tertiary: accent,
|
|
);
|
|
}
|
|
|
|
static TextTheme _textTheme(ColorScheme scheme) {
|
|
// Use a tighter, modern scale; keep multiplier to respect original accessibility intent.
|
|
return TextTheme(
|
|
displaySmall: TextStyle(
|
|
fontSize: 34.sp * fontSizeMultiplier,
|
|
fontWeight: FontWeight.w700,
|
|
letterSpacing: -0.5,
|
|
color: scheme.onSurface,
|
|
),
|
|
headlineSmall: TextStyle(
|
|
fontSize: 22.sp * fontSizeMultiplier,
|
|
fontWeight: FontWeight.w700,
|
|
letterSpacing: -0.2,
|
|
color: scheme.onSurface,
|
|
),
|
|
titleLarge: TextStyle(
|
|
fontSize: 18.sp * fontSizeMultiplier,
|
|
fontWeight: FontWeight.w700,
|
|
color: scheme.onSurface,
|
|
),
|
|
titleMedium: TextStyle(
|
|
fontSize: 16.sp * fontSizeMultiplier,
|
|
fontWeight: FontWeight.w600,
|
|
color: scheme.onSurface,
|
|
),
|
|
bodyLarge: TextStyle(
|
|
fontSize: 15.sp * fontSizeMultiplier,
|
|
fontWeight: FontWeight.w500,
|
|
height: 1.35,
|
|
color: scheme.onSurface,
|
|
),
|
|
bodyMedium: TextStyle(
|
|
fontSize: 13.sp * fontSizeMultiplier,
|
|
fontWeight: FontWeight.w500,
|
|
height: 1.35,
|
|
color: scheme.onSurfaceVariant,
|
|
),
|
|
labelLarge: TextStyle(
|
|
fontSize: 13.sp * fontSizeMultiplier,
|
|
fontWeight: FontWeight.w600,
|
|
letterSpacing: 0.3,
|
|
color: scheme.onSurface,
|
|
),
|
|
);
|
|
}
|
|
|
|
/// Light Theme
|
|
static ThemeData get lightTheme {
|
|
final scheme = _lightScheme();
|
|
return ThemeData(
|
|
useMaterial3: true,
|
|
brightness: Brightness.light,
|
|
colorScheme: scheme,
|
|
scaffoldBackgroundColor: scheme.surface,
|
|
textTheme: _textTheme(scheme),
|
|
|
|
// AppBar Theme - Accessibility Enhanced
|
|
appBarTheme: AppBarTheme(
|
|
elevation: 0,
|
|
centerTitle: false,
|
|
backgroundColor: scheme.surface,
|
|
foregroundColor: scheme.onSurface,
|
|
titleTextStyle: _textTheme(scheme).titleLarge,
|
|
iconTheme: IconThemeData(
|
|
color: scheme.onSurface,
|
|
size: (24.w * fontSizeMultiplier),
|
|
),
|
|
),
|
|
|
|
cardTheme: CardTheme(
|
|
elevation: 0,
|
|
color: scheme.surfaceContainerHighest,
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(18.r)),
|
|
margin: EdgeInsets.zero,
|
|
),
|
|
|
|
// Elevated Button Theme - Accessibility Enhanced
|
|
elevatedButtonTheme: ElevatedButtonThemeData(
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: scheme.primary,
|
|
foregroundColor: scheme.onPrimary,
|
|
elevation: 0,
|
|
padding: EdgeInsets.symmetric(
|
|
horizontal: (20.w * fontSizeMultiplier),
|
|
vertical: (14.h * fontSizeMultiplier),
|
|
),
|
|
minimumSize: Size(0, (48.h * fontSizeMultiplier)),
|
|
textStyle: _textTheme(scheme).labelLarge,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(16.r),
|
|
),
|
|
),
|
|
),
|
|
|
|
// Outlined Button Theme - Accessibility Enhanced
|
|
outlinedButtonTheme: OutlinedButtonThemeData(
|
|
style: OutlinedButton.styleFrom(
|
|
foregroundColor: scheme.primary,
|
|
side: BorderSide(color: scheme.outline, width: 1.2),
|
|
padding: EdgeInsets.symmetric(
|
|
horizontal: (20.w * fontSizeMultiplier),
|
|
vertical: (14.h * fontSizeMultiplier),
|
|
),
|
|
minimumSize: Size(0, (48.h * fontSizeMultiplier)),
|
|
textStyle: _textTheme(scheme).labelLarge,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(16.r),
|
|
),
|
|
),
|
|
),
|
|
|
|
// Text Button Theme - Accessibility Enhanced
|
|
textButtonTheme: TextButtonThemeData(
|
|
style: TextButton.styleFrom(
|
|
foregroundColor: scheme.primary,
|
|
padding: EdgeInsets.symmetric(
|
|
horizontal: (16.w * fontSizeMultiplier),
|
|
vertical: (12.h * fontSizeMultiplier),
|
|
),
|
|
minimumSize: Size(0, (44.h * fontSizeMultiplier)),
|
|
textStyle: _textTheme(scheme).labelLarge,
|
|
),
|
|
),
|
|
|
|
// Input Decoration Theme - Accessibility Enhanced
|
|
inputDecorationTheme: InputDecorationTheme(
|
|
filled: true,
|
|
fillColor: scheme.surfaceContainerHighest,
|
|
border: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(16.r),
|
|
borderSide: BorderSide(color: scheme.outlineVariant),
|
|
),
|
|
enabledBorder: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(16.r),
|
|
borderSide: BorderSide(color: scheme.outlineVariant),
|
|
),
|
|
focusedBorder: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(16.r),
|
|
borderSide: BorderSide(color: scheme.primary, width: 2),
|
|
),
|
|
errorBorder: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(16.r),
|
|
borderSide: BorderSide(color: scheme.error, width: 2),
|
|
),
|
|
contentPadding: EdgeInsets.symmetric(
|
|
horizontal: (16.w * fontSizeMultiplier),
|
|
vertical: (14.h * fontSizeMultiplier),
|
|
),
|
|
labelStyle: _textTheme(scheme).bodyMedium,
|
|
hintStyle: _textTheme(scheme).bodyMedium,
|
|
),
|
|
|
|
// Icon Theme - Accessibility Enhanced
|
|
iconTheme: IconThemeData(
|
|
color: scheme.onSurfaceVariant,
|
|
size: (24.w * fontSizeMultiplier),
|
|
),
|
|
|
|
// Floating Action Button Theme
|
|
floatingActionButtonTheme: FloatingActionButtonThemeData(
|
|
backgroundColor: scheme.primary,
|
|
foregroundColor: scheme.onPrimary,
|
|
elevation: 0,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(16.r),
|
|
),
|
|
),
|
|
|
|
// Bottom Navigation Bar Theme - Accessibility Enhanced
|
|
bottomNavigationBarTheme: BottomNavigationBarThemeData(
|
|
backgroundColor: scheme.surface,
|
|
selectedItemColor: scheme.primary,
|
|
unselectedItemColor: scheme.onSurfaceVariant,
|
|
selectedLabelStyle: _textTheme(scheme).labelLarge,
|
|
unselectedLabelStyle: _textTheme(scheme).labelLarge!.copyWith(
|
|
color: scheme.onSurfaceVariant,
|
|
fontWeight: FontWeight.w600,
|
|
),
|
|
selectedIconTheme: IconThemeData(
|
|
size: (28.w * fontSizeMultiplier),
|
|
),
|
|
unselectedIconTheme: IconThemeData(
|
|
size: (24.w * fontSizeMultiplier),
|
|
),
|
|
type: BottomNavigationBarType.fixed,
|
|
elevation: 0,
|
|
),
|
|
|
|
// Divider Theme - Accessibility Enhanced
|
|
dividerTheme: DividerThemeData(
|
|
color: scheme.outlineVariant,
|
|
thickness: 1,
|
|
space: 1,
|
|
),
|
|
|
|
// Chip Theme - Accessibility Enhanced
|
|
chipTheme: ChipThemeData(
|
|
backgroundColor: scheme.surfaceContainerHighest,
|
|
selectedColor: scheme.primaryContainer,
|
|
labelStyle: _textTheme(scheme).labelLarge,
|
|
padding: EdgeInsets.symmetric(
|
|
horizontal: (14.w * fontSizeMultiplier),
|
|
vertical: (10.h * fontSizeMultiplier),
|
|
),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(20.r),
|
|
),
|
|
),
|
|
|
|
// Dialog Theme - Accessibility Enhanced
|
|
// dialogTheme: DialogThemeData(
|
|
// elevation: 8, // More elevation for better depth
|
|
// shape: RoundedRectangleBorder(
|
|
// borderRadius: BorderRadius.circular(20.r),
|
|
// ),
|
|
// titleTextStyle: TextStyle(
|
|
// fontSize: (22.sp * fontSizeMultiplier), // Larger titles
|
|
// fontWeight: FontWeight.bold,
|
|
// color: lightTextPrimary,
|
|
// ),
|
|
// contentTextStyle: TextStyle(
|
|
// fontSize: (17.sp * fontSizeMultiplier), // Larger content
|
|
// color: lightTextSecondary,
|
|
// height: 1.5, // Better line spacing
|
|
// ),
|
|
// ),
|
|
|
|
// Snackbar Theme - Accessibility Enhanced
|
|
snackBarTheme: SnackBarThemeData(
|
|
backgroundColor: scheme.inverseSurface,
|
|
contentTextStyle: _textTheme(scheme).bodyMedium!.copyWith(
|
|
color: scheme.onInverseSurface,
|
|
fontWeight: FontWeight.w600,
|
|
),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(16.r),
|
|
),
|
|
behavior: SnackBarBehavior.floating,
|
|
actionTextColor: scheme.tertiary,
|
|
),
|
|
);
|
|
}
|
|
|
|
/// Dark Theme
|
|
static ThemeData get darkTheme {
|
|
final scheme = _darkScheme();
|
|
return ThemeData(
|
|
useMaterial3: true,
|
|
brightness: Brightness.dark,
|
|
colorScheme: scheme,
|
|
scaffoldBackgroundColor: scheme.surface,
|
|
textTheme: _textTheme(scheme),
|
|
|
|
// AppBar Theme - Accessibility Enhanced
|
|
appBarTheme: AppBarTheme(
|
|
elevation: 0,
|
|
centerTitle: false,
|
|
backgroundColor: scheme.surface,
|
|
foregroundColor: scheme.onSurface,
|
|
titleTextStyle: _textTheme(scheme).titleLarge,
|
|
iconTheme: IconThemeData(
|
|
color: scheme.onSurface,
|
|
size: (24.w * fontSizeMultiplier),
|
|
),
|
|
),
|
|
|
|
cardTheme: CardTheme(
|
|
elevation: 0,
|
|
color: scheme.surfaceContainerHighest,
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(18.r)),
|
|
margin: EdgeInsets.zero,
|
|
),
|
|
|
|
// Elevated Button Theme - Accessibility Enhanced
|
|
elevatedButtonTheme: ElevatedButtonThemeData(
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: scheme.primary,
|
|
foregroundColor: scheme.onPrimary,
|
|
elevation: 0,
|
|
padding: EdgeInsets.symmetric(
|
|
horizontal: (20.w * fontSizeMultiplier),
|
|
vertical: (14.h * fontSizeMultiplier),
|
|
),
|
|
minimumSize: Size(0, (48.h * fontSizeMultiplier)),
|
|
textStyle: _textTheme(scheme).labelLarge,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(16.r),
|
|
),
|
|
),
|
|
),
|
|
|
|
// Outlined Button Theme - Accessibility Enhanced
|
|
outlinedButtonTheme: OutlinedButtonThemeData(
|
|
style: OutlinedButton.styleFrom(
|
|
foregroundColor: scheme.primary,
|
|
side: BorderSide(color: scheme.outline, width: 1.2),
|
|
padding: EdgeInsets.symmetric(
|
|
horizontal: (20.w * fontSizeMultiplier),
|
|
vertical: (14.h * fontSizeMultiplier),
|
|
),
|
|
minimumSize: Size(0, (48.h * fontSizeMultiplier)),
|
|
textStyle: _textTheme(scheme).labelLarge,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(16.r),
|
|
),
|
|
),
|
|
),
|
|
|
|
// Text Button Theme
|
|
textButtonTheme: TextButtonThemeData(
|
|
style: TextButton.styleFrom(
|
|
foregroundColor: scheme.primary,
|
|
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 10.h),
|
|
textStyle: _textTheme(scheme).labelLarge,
|
|
),
|
|
),
|
|
|
|
// Input Decoration Theme
|
|
inputDecorationTheme: InputDecorationTheme(
|
|
filled: true,
|
|
fillColor: scheme.surfaceContainerHighest,
|
|
border: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(16.r),
|
|
borderSide: BorderSide(color: scheme.outlineVariant),
|
|
),
|
|
enabledBorder: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(16.r),
|
|
borderSide: BorderSide(color: scheme.outlineVariant),
|
|
),
|
|
focusedBorder: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(16.r),
|
|
borderSide: BorderSide(color: scheme.primary, width: 2),
|
|
),
|
|
errorBorder: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(16.r),
|
|
borderSide: BorderSide(color: scheme.error, width: 2),
|
|
),
|
|
contentPadding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 14.h),
|
|
),
|
|
|
|
// Icon Theme
|
|
iconTheme: IconThemeData(
|
|
color: scheme.onSurfaceVariant,
|
|
size: 24.w,
|
|
),
|
|
|
|
// Floating Action Button Theme
|
|
floatingActionButtonTheme: FloatingActionButtonThemeData(
|
|
backgroundColor: scheme.primary,
|
|
foregroundColor: scheme.onPrimary,
|
|
elevation: 0,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(16.r),
|
|
),
|
|
),
|
|
|
|
// Bottom Navigation Bar Theme
|
|
bottomNavigationBarTheme: BottomNavigationBarThemeData(
|
|
backgroundColor: scheme.surface,
|
|
selectedItemColor: scheme.primary,
|
|
unselectedItemColor: scheme.onSurfaceVariant,
|
|
selectedLabelStyle: _textTheme(scheme).labelLarge,
|
|
unselectedLabelStyle: _textTheme(scheme).labelLarge!.copyWith(
|
|
color: scheme.onSurfaceVariant,
|
|
fontWeight: FontWeight.w600,
|
|
),
|
|
type: BottomNavigationBarType.fixed,
|
|
elevation: 0,
|
|
),
|
|
|
|
// Divider Theme
|
|
dividerTheme: DividerThemeData(
|
|
color: scheme.outlineVariant,
|
|
thickness: 1,
|
|
space: 1,
|
|
),
|
|
|
|
// Chip Theme
|
|
chipTheme: ChipThemeData(
|
|
backgroundColor: scheme.surfaceContainerHighest,
|
|
selectedColor: scheme.primaryContainer,
|
|
labelStyle: _textTheme(scheme).labelLarge,
|
|
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 8.h),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(16.r),
|
|
),
|
|
),
|
|
|
|
// Dialog Theme - Accessibility Enhanced
|
|
// dialogTheme: DialogThemeData(
|
|
// backgroundColor: darkSurface,
|
|
// elevation: 8, // More elevation
|
|
// shape: RoundedRectangleBorder(
|
|
// borderRadius: BorderRadius.circular(20.r),
|
|
// ),
|
|
// titleTextStyle: TextStyle(
|
|
// fontSize: (22.sp * fontSizeMultiplier),
|
|
// fontWeight: FontWeight.bold,
|
|
// color: darkTextPrimary,
|
|
// ),
|
|
// contentTextStyle: TextStyle(
|
|
// fontSize: (17.sp * fontSizeMultiplier),
|
|
// color: darkTextSecondary,
|
|
// height: 1.5,
|
|
// ),
|
|
// ),
|
|
|
|
// Snackbar Theme
|
|
snackBarTheme: SnackBarThemeData(
|
|
backgroundColor: scheme.inverseSurface,
|
|
contentTextStyle: _textTheme(scheme).bodyMedium!.copyWith(
|
|
color: scheme.onInverseSurface,
|
|
fontWeight: FontWeight.w600,
|
|
),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(12.r),
|
|
),
|
|
behavior: SnackBarBehavior.floating,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|