// Author: fruit.com.cn import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'app_colors.dart'; import 'app_dimens.dart'; /// K28-S 浅色暖橙主题。 abstract final class AppTheme { /// 页面顶部暖色到米白背景的渐变。 static const LinearGradient pageGradient = LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [AppColors.surfaceTop, AppColors.ink], stops: [0, 0.24], ); /// 卡片轻阴影。 static const BoxShadow cardShadow = BoxShadow( color: AppColors.cardShadow, blurRadius: AppDimens.cardShadowBlur, offset: Offset(0, AppDimens.cardShadowY), ); /// 全局浅色暖橙主题。 static ThemeData light() { const scheme = ColorScheme.light( primary: AppColors.blue, onPrimary: AppColors.onPrimary, secondary: AppColors.secondary, onSecondary: AppColors.onPrimary, primaryContainer: AppColors.surfaceTop, onPrimaryContainer: AppColors.onSurface, secondaryContainer: AppColors.badgePink, onSecondaryContainer: AppColors.badgePinkText, surface: AppColors.ink, onSurface: AppColors.onSurface, outline: AppColors.border, outlineVariant: AppColors.border, surfaceTint: AppColors.blue, inversePrimary: AppColors.bluePressed, ); final base = ThemeData( useMaterial3: true, brightness: Brightness.light, colorScheme: scheme, scaffoldBackgroundColor: AppColors.ink, fontFamily: 'PlusJakartaSans', progressIndicatorTheme: const ProgressIndicatorThemeData( color: AppColors.blue, ), sliderTheme: const SliderThemeData( activeTrackColor: AppColors.blue, inactiveTrackColor: AppColors.border, thumbColor: AppColors.onPrimary, ), tabBarTheme: const TabBarThemeData( labelColor: AppColors.blue, indicatorColor: AppColors.blue, unselectedLabelColor: AppColors.muted, ), textButtonTheme: TextButtonThemeData( style: TextButton.styleFrom(foregroundColor: AppColors.blue), ), filledButtonTheme: FilledButtonThemeData( style: ButtonStyle( backgroundColor: WidgetStateProperty.resolveWith(_buttonColor), foregroundColor: const WidgetStatePropertyAll(AppColors.onPrimary), minimumSize: const WidgetStatePropertyAll( Size(0, AppDimens.buttonHeight), ), shape: const WidgetStatePropertyAll(StadiumBorder()), ), ), outlinedButtonTheme: OutlinedButtonThemeData( style: ButtonStyle( foregroundColor: const WidgetStatePropertyAll(AppColors.blue), minimumSize: const WidgetStatePropertyAll( Size(0, AppDimens.buttonHeight), ), side: const WidgetStatePropertyAll( BorderSide(color: AppColors.border), ), shape: const WidgetStatePropertyAll(StadiumBorder()), ), ), appBarTheme: const AppBarTheme( backgroundColor: AppColors.ink, foregroundColor: AppColors.onSurface, elevation: 0, systemOverlayStyle: SystemUiOverlayStyle.dark, titleTextStyle: TextStyle( color: AppColors.onSurface, fontFamily: 'Outfit', fontSize: AppDimens.pageTitle, fontWeight: FontWeight.w800, ), ), iconTheme: const IconThemeData(color: AppColors.onSurface), dividerTheme: const DividerThemeData(color: AppColors.border), cardTheme: const CardThemeData( color: AppColors.card, elevation: 0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(AppDimens.cardRadius)), side: BorderSide(color: AppColors.border), ), ), bottomSheetTheme: const BottomSheetThemeData( backgroundColor: Colors.transparent, modalBackgroundColor: Colors.transparent, surfaceTintColor: Colors.transparent, ), switchTheme: SwitchThemeData( thumbColor: WidgetStateProperty.resolveWith( (states) => states.contains(WidgetState.selected) ? AppColors.onPrimary : null, ), trackColor: WidgetStateProperty.resolveWith( (states) => states.contains(WidgetState.selected) ? AppColors.blue : null, ), ), snackBarTheme: const SnackBarThemeData( backgroundColor: AppColors.onSurface, contentTextStyle: TextStyle(color: AppColors.onPrimary), ), ); final textTheme = base.textTheme .apply( fontFamily: 'PlusJakartaSans', bodyColor: AppColors.cream, displayColor: AppColors.onSurface, ) .copyWith( displayLarge: _display(base.textTheme.displayLarge), displayMedium: _display(base.textTheme.displayMedium), displaySmall: _display(base.textTheme.displaySmall), headlineLarge: _display(base.textTheme.headlineLarge), headlineMedium: _display(base.textTheme.headlineMedium), headlineSmall: _display(base.textTheme.headlineSmall), titleLarge: _display(base.textTheme.titleLarge), ); return base.copyWith(textTheme: textTheme); } static TextStyle? _display(TextStyle? style) => style?.copyWith(fontFamily: 'Outfit', color: AppColors.onSurface); static Color _buttonColor(Set states) { if (states.contains(WidgetState.pressed) || states.contains(WidgetState.hovered) || states.contains(WidgetState.focused)) { return AppColors.bluePressed; } return AppColors.blue; } }