import 'package:flutter/material.dart'; import 'brand.dart'; /// Install with `MaterialApp(theme: SxchngeTheme.light(), /// darkTheme: SxchngeTheme.dark())`. abstract final class SxchngeTheme { static const packageName = 'sxchnge_theme'; static ThemeData light() => _build(Brightness.light); static ThemeData dark() => _build(Brightness.dark); static ThemeData _build(Brightness brightness) { final dark = brightness == Brightness.dark; // Seed supplies complete Material roles; explicit overrides preserve brand // colors and readable foregrounds rather than approximating the palette. final scheme = ColorScheme.fromSeed( seedColor: SxchngeBrand.forest, brightness: brightness, ).copyWith( primary: dark ? SxchngeBrand.mint : SxchngeBrand.ink, onPrimary: dark ? SxchngeBrand.ink : SxchngeBrand.mint, primaryContainer: SxchngeBrand.mint, onPrimaryContainer: SxchngeBrand.ink, secondary: dark ? SxchngeBrand.mint : SxchngeBrand.forest, onSecondary: dark ? SxchngeBrand.ink : SxchngeBrand.paper, secondaryContainer: dark ? SxchngeBrand.darkReceive : SxchngeBrand.sageSurface, onSecondaryContainer: dark ? SxchngeBrand.mint : SxchngeBrand.ink, tertiary: dark ? SxchngeBrand.lime : SxchngeBrand.forest, onTertiary: dark ? SxchngeBrand.ink : SxchngeBrand.paper, tertiaryContainer: SxchngeBrand.lime, onTertiaryContainer: SxchngeBrand.ink, surface: dark ? SxchngeBrand.ink : SxchngeBrand.paper, onSurface: dark ? SxchngeBrand.paper : SxchngeBrand.ink, onSurfaceVariant: dark ? const Color(0xFFB6C6B9) : SxchngeBrand.muted, surfaceContainerLowest: dark ? const Color(0xFF101B17) : Colors.white, surfaceContainerLow: dark ? const Color(0xFF1B2B23) : SxchngeBrand.paper, surfaceContainer: dark ? SxchngeBrand.darkField : SxchngeBrand.sageSurface, surfaceContainerHigh: dark ? SxchngeBrand.darkReceive : SxchngeBrand.line, surfaceContainerHighest: dark ? const Color(0xFF324A3C) : const Color(0xFFCFD9CE), outline: dark ? const Color(0xFF8CA291) : SxchngeBrand.muted, outlineVariant: dark ? const Color(0xFF405A48) : SxchngeBrand.line, inverseSurface: dark ? SxchngeBrand.paper : SxchngeBrand.ink, onInverseSurface: dark ? SxchngeBrand.ink : SxchngeBrand.paper, inversePrimary: dark ? SxchngeBrand.forest : SxchngeBrand.mint, surfaceTint: Colors.transparent, ); final base = ThemeData( useMaterial3: true, colorScheme: scheme, fontFamily: SxchngeBrand.fontFamily, package: packageName, scaffoldBackgroundColor: scheme.surface, visualDensity: VisualDensity.standard, materialTapTargetSize: MaterialTapTargetSize.padded, ); final text = base.textTheme.copyWith( displayLarge: base.textTheme.displayLarge!.copyWith( fontSize: 48, fontWeight: FontWeight.w600, letterSpacing: -2, height: 1.1, ), displayMedium: base.textTheme.displayMedium!.copyWith( fontSize: 40, fontWeight: FontWeight.w600, letterSpacing: -1.5, height: 1.15, ), displaySmall: base.textTheme.displaySmall!.copyWith( fontSize: 36, fontWeight: FontWeight.w600, letterSpacing: -1, height: 1.2, ), headlineLarge: base.textTheme.headlineLarge!.copyWith( fontWeight: FontWeight.w600, letterSpacing: -1, ), headlineMedium: base.textTheme.headlineMedium!.copyWith( fontWeight: FontWeight.w600, letterSpacing: -0.5, ), headlineSmall: base.textTheme.headlineSmall!.copyWith( fontWeight: FontWeight.w600, ), bodyLarge: base.textTheme.bodyLarge!.copyWith(fontSize: 16, height: 1.65), bodyMedium: base.textTheme.bodyMedium!.copyWith( fontSize: 16, height: 1.5, ), bodySmall: base.textTheme.bodySmall!.copyWith(fontSize: 14, height: 1.5), labelLarge: base.textTheme.labelLarge!.copyWith( fontSize: 16, fontWeight: FontWeight.w600, ), labelMedium: base.textTheme.labelMedium!.copyWith( fontSize: 14, fontWeight: FontWeight.w600, ), labelSmall: base.textTheme.labelSmall!.copyWith(fontSize: 14), ); final border = OutlineInputBorder( borderRadius: BorderRadius.circular(14), borderSide: BorderSide(color: scheme.outline), ); return base.copyWith( textTheme: text, appBarTheme: AppBarThemeData( backgroundColor: scheme.surface, foregroundColor: scheme.onSurface, surfaceTintColor: Colors.transparent, elevation: 0, centerTitle: false, titleTextStyle: text.titleLarge, ), cardTheme: CardThemeData( color: scheme.surfaceContainer, elevation: 0, margin: EdgeInsets.zero, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24)), ), filledButtonTheme: FilledButtonThemeData( style: FilledButton.styleFrom( minimumSize: const Size(64, 48), padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 14), shape: const StadiumBorder(), textStyle: text.labelLarge, ), ), elevatedButtonTheme: ElevatedButtonThemeData( style: ElevatedButton.styleFrom( minimumSize: const Size(64, 48), padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 14), shape: const StadiumBorder(), textStyle: text.labelLarge, elevation: 0, ), ), outlinedButtonTheme: OutlinedButtonThemeData( style: OutlinedButton.styleFrom( minimumSize: const Size(64, 48), padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 14), shape: const StadiumBorder(), textStyle: text.labelLarge, ), ), textButtonTheme: TextButtonThemeData( style: TextButton.styleFrom( minimumSize: const Size(48, 48), textStyle: text.labelLarge, ), ), inputDecorationTheme: InputDecorationThemeData( filled: true, fillColor: scheme.surfaceContainerLowest, contentPadding: const EdgeInsets.all(16), border: border, enabledBorder: border, focusedBorder: border.copyWith( borderSide: BorderSide( color: dark ? SxchngeBrand.mint : SxchngeBrand.focus, width: 2, ), ), errorBorder: border.copyWith( borderSide: BorderSide(color: scheme.error), ), focusedErrorBorder: border.copyWith( borderSide: BorderSide(color: scheme.error, width: 2), ), ), dialogTheme: DialogThemeData( backgroundColor: scheme.surface, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24)), ), dividerTheme: DividerThemeData( color: scheme.outlineVariant, thickness: 1, ), navigationBarTheme: NavigationBarThemeData( backgroundColor: scheme.surface, indicatorColor: scheme.primaryContainer, ), textSelectionTheme: TextSelectionThemeData( cursorColor: scheme.primary, selectionColor: SxchngeBrand.lime.withValues(alpha: dark ? 0.3 : 0.5), selectionHandleColor: scheme.primary, ), ); } }