import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'app_colors.dart'; /// ADHD-friendly Material 3 theme. /// /// Design principles: /// - Calming primary colors (teal / soft blue) — NO aggressive reds. /// - High-contrast text for readability. /// - Large touch targets (minimum 48 dp). /// - Rounded corners everywhere (16 dp radius). /// - Gentle animations, no jarring transitions. /// - Nunito for headers (friendly, rounded), Inter for body. /// - Subtle, soft card shadows. class AppTheme { AppTheme._(); static const double _borderRadius = 16.0; static final _roundedShape = RoundedRectangleBorder( borderRadius: BorderRadius.circular(_borderRadius), ); // ── Typography ─────────────────────────────────────────────────── static TextTheme _buildTextTheme(TextTheme base, Color primary, Color secondary) { final headlineFont = GoogleFonts.nunitoTextTheme(base); final bodyFont = GoogleFonts.interTextTheme(base); return bodyFont.copyWith( displayLarge: headlineFont.displayLarge?.copyWith(color: primary, fontWeight: FontWeight.w700), displayMedium: headlineFont.displayMedium?.copyWith(color: primary, fontWeight: FontWeight.w700), displaySmall: headlineFont.displaySmall?.copyWith(color: primary, fontWeight: FontWeight.w700), headlineLarge: headlineFont.headlineLarge?.copyWith(color: primary, fontWeight: FontWeight.w700), headlineMedium: headlineFont.headlineMedium?.copyWith(color: primary, fontWeight: FontWeight.w600), headlineSmall: headlineFont.headlineSmall?.copyWith(color: primary, fontWeight: FontWeight.w600), titleLarge: headlineFont.titleLarge?.copyWith(color: primary, fontWeight: FontWeight.w600), titleMedium: headlineFont.titleMedium?.copyWith(color: primary, fontWeight: FontWeight.w600), titleSmall: headlineFont.titleSmall?.copyWith(color: primary, fontWeight: FontWeight.w500), bodyLarge: bodyFont.bodyLarge?.copyWith(color: primary, fontSize: 16), bodyMedium: bodyFont.bodyMedium?.copyWith(color: secondary, fontSize: 14), bodySmall: bodyFont.bodySmall?.copyWith(color: secondary, fontSize: 12), labelLarge: bodyFont.labelLarge?.copyWith(color: primary, fontWeight: FontWeight.w600, fontSize: 16), labelMedium: bodyFont.labelMedium?.copyWith(color: secondary), labelSmall: bodyFont.labelSmall?.copyWith(color: secondary), ); } // ── Light theme ────────────────────────────────────────────────── static ThemeData get light { final colorScheme = ColorScheme.light( primary: AppColors.primary, onPrimary: Colors.white, primaryContainer: AppColors.primaryLight, onPrimaryContainer: AppColors.primaryDark, secondary: AppColors.secondary, onSecondary: Colors.white, secondaryContainer: AppColors.secondaryLight, onSecondaryContainer: AppColors.secondaryDark, tertiary: AppColors.tertiary, onTertiary: Colors.white, tertiaryContainer: AppColors.tertiaryLight, onTertiaryContainer: AppColors.tertiaryDark, surface: AppColors.surfaceLight, onSurface: AppColors.textPrimaryLight, surfaceContainerHighest: AppColors.surfaceVariantLight, onSurfaceVariant: AppColors.textSecondaryLight, error: AppColors.error, onError: Colors.white, ); final textTheme = _buildTextTheme( ThemeData.light().textTheme, AppColors.textPrimaryLight, AppColors.textSecondaryLight, ); return ThemeData( useMaterial3: true, colorScheme: colorScheme, scaffoldBackgroundColor: AppColors.backgroundLight, textTheme: textTheme, // AppBar appBarTheme: AppBarTheme( elevation: 0, scrolledUnderElevation: 1, backgroundColor: AppColors.backgroundLight, foregroundColor: AppColors.textPrimaryLight, titleTextStyle: textTheme.titleLarge, ), // Cards — subtle, soft shadows cardTheme: CardThemeData( elevation: 2, shadowColor: Colors.black.withAlpha(25), shape: _roundedShape, margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 6), ), // Elevated buttons — large touch targets elevatedButtonTheme: ElevatedButtonThemeData( style: ElevatedButton.styleFrom( minimumSize: const Size(double.infinity, 52), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(_borderRadius)), textStyle: textTheme.labelLarge, elevation: 2, shadowColor: Colors.black.withAlpha(25), ), ), // Filled buttons filledButtonTheme: FilledButtonThemeData( style: FilledButton.styleFrom( minimumSize: const Size(double.infinity, 52), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(_borderRadius)), textStyle: textTheme.labelLarge, ), ), // Outlined buttons outlinedButtonTheme: OutlinedButtonThemeData( style: OutlinedButton.styleFrom( minimumSize: const Size(double.infinity, 52), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(_borderRadius)), textStyle: textTheme.labelLarge, ), ), // Text buttons textButtonTheme: TextButtonThemeData( style: TextButton.styleFrom( minimumSize: const Size(48, 48), textStyle: textTheme.labelLarge, ), ), // Input decoration inputDecorationTheme: InputDecorationTheme( filled: true, fillColor: AppColors.surfaceVariantLight, contentPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 18), border: OutlineInputBorder( borderRadius: BorderRadius.circular(_borderRadius), borderSide: BorderSide.none, ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(_borderRadius), borderSide: BorderSide.none, ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(_borderRadius), borderSide: const BorderSide(color: AppColors.primary, width: 2), ), errorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(_borderRadius), borderSide: const BorderSide(color: AppColors.error, width: 1), ), labelStyle: textTheme.bodyMedium, hintStyle: textTheme.bodyMedium?.copyWith(color: AppColors.textSecondaryLight.withAlpha(150)), ), // FABs floatingActionButtonTheme: FloatingActionButtonThemeData( backgroundColor: AppColors.primary, foregroundColor: Colors.white, elevation: 4, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), ), // Chips chipTheme: ChipThemeData( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), ), // Bottom nav bottomNavigationBarTheme: BottomNavigationBarThemeData( elevation: 8, selectedItemColor: AppColors.primary, unselectedItemColor: AppColors.textSecondaryLight, type: BottomNavigationBarType.fixed, backgroundColor: AppColors.surfaceLight, ), // Snackbar snackBarTheme: SnackBarThemeData( behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), ), // Divider dividerTheme: const DividerThemeData( color: AppColors.dividerLight, thickness: 1, space: 1, ), // Page transitions — gentle pageTransitionsTheme: const PageTransitionsTheme( builders: { TargetPlatform.android: FadeUpwardsPageTransitionsBuilder(), TargetPlatform.iOS: CupertinoPageTransitionsBuilder(), }, ), ); } // ── Dark theme — true dark with muted accents ──────────────────── static ThemeData get dark { final colorScheme = ColorScheme.dark( primary: AppColors.primaryLight, onPrimary: AppColors.primaryDark, primaryContainer: AppColors.primaryDark, onPrimaryContainer: AppColors.primaryLight, secondary: AppColors.secondary, onSecondary: Colors.black, secondaryContainer: AppColors.secondaryDark, onSecondaryContainer: AppColors.secondaryLight, tertiary: AppColors.tertiaryLight, onTertiary: Colors.black, tertiaryContainer: AppColors.tertiaryDark, onTertiaryContainer: AppColors.tertiaryLight, surface: AppColors.surfaceDark, onSurface: AppColors.textPrimaryDark, surfaceContainerHighest: AppColors.surfaceVariantDark, onSurfaceVariant: AppColors.textSecondaryDark, error: AppColors.errorLight, onError: Colors.black, ); final textTheme = _buildTextTheme( ThemeData.dark().textTheme, AppColors.textPrimaryDark, AppColors.textSecondaryDark, ); return ThemeData( useMaterial3: true, colorScheme: colorScheme, scaffoldBackgroundColor: AppColors.backgroundDark, textTheme: textTheme, appBarTheme: AppBarTheme( elevation: 0, scrolledUnderElevation: 1, backgroundColor: AppColors.backgroundDark, foregroundColor: AppColors.textPrimaryDark, titleTextStyle: textTheme.titleLarge, ), cardTheme: CardThemeData( elevation: 2, shadowColor: Colors.black.withAlpha(60), shape: _roundedShape, color: AppColors.surfaceDark, margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 6), ), elevatedButtonTheme: ElevatedButtonThemeData( style: ElevatedButton.styleFrom( minimumSize: const Size(double.infinity, 52), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(_borderRadius)), textStyle: textTheme.labelLarge, elevation: 2, shadowColor: Colors.black.withAlpha(60), ), ), filledButtonTheme: FilledButtonThemeData( style: FilledButton.styleFrom( minimumSize: const Size(double.infinity, 52), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(_borderRadius)), textStyle: textTheme.labelLarge, ), ), outlinedButtonTheme: OutlinedButtonThemeData( style: OutlinedButton.styleFrom( minimumSize: const Size(double.infinity, 52), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(_borderRadius)), textStyle: textTheme.labelLarge, ), ), textButtonTheme: TextButtonThemeData( style: TextButton.styleFrom( minimumSize: const Size(48, 48), textStyle: textTheme.labelLarge, ), ), inputDecorationTheme: InputDecorationTheme( filled: true, fillColor: AppColors.surfaceVariantDark, contentPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 18), border: OutlineInputBorder( borderRadius: BorderRadius.circular(_borderRadius), borderSide: BorderSide.none, ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(_borderRadius), borderSide: BorderSide.none, ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(_borderRadius), borderSide: const BorderSide(color: AppColors.primaryLight, width: 2), ), errorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(_borderRadius), borderSide: const BorderSide(color: AppColors.errorLight, width: 1), ), labelStyle: textTheme.bodyMedium, hintStyle: textTheme.bodyMedium?.copyWith(color: AppColors.textSecondaryDark.withAlpha(150)), ), floatingActionButtonTheme: FloatingActionButtonThemeData( backgroundColor: AppColors.primaryLight, foregroundColor: AppColors.primaryDark, elevation: 4, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), ), chipTheme: ChipThemeData( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), ), bottomNavigationBarTheme: BottomNavigationBarThemeData( elevation: 8, selectedItemColor: AppColors.primaryLight, unselectedItemColor: AppColors.textSecondaryDark, type: BottomNavigationBarType.fixed, backgroundColor: AppColors.surfaceDark, ), snackBarTheme: SnackBarThemeData( behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), ), dividerTheme: const DividerThemeData( color: AppColors.dividerDark, thickness: 1, space: 1, ), pageTransitionsTheme: const PageTransitionsTheme( builders: { TargetPlatform.android: FadeUpwardsPageTransitionsBuilder(), TargetPlatform.iOS: CupertinoPageTransitionsBuilder(), }, ), ); } }