import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'app_colors.dart'; /// CEX App 主题配置 /// /// 字体:Inter(需在 assets/fonts/ 放置字体文件,pubspec.yaml 已配置) /// 数字区域必须叠加 FontFeature.tabularFigures(),见 AppTheme.numericStyle() abstract class AppTheme { // ── 等宽数字辅助 ───────────────────────────────────────────── /// 在行情列表、订单簿、资产金额等数字密集区域, /// 将此叠加到 TextStyle 上,防止数值跳动时宽度抖动。 /// /// 用法:style: AppTheme.numericStyle(base) static TextStyle numericStyle(TextStyle base) => base.copyWith( fontFeatures: const [FontFeature.tabularFigures()], ); // ── 深色主题(默认)────────────────────────────────────────── static ThemeData get dark { final base = ThemeData.dark(useMaterial3: true); return base.copyWith( scaffoldBackgroundColor: AppColors.darkBg, colorScheme: const ColorScheme.dark( primary: AppColors.brand, onPrimary: Colors.black, secondary: AppColors.brand, onSecondary: Colors.black, surface: AppColors.darkBgSecondary, onSurface: AppColors.darkTextPrimary, error: AppColors.error, onError: Colors.white, outline: AppColors.darkDivider, ), appBarTheme: const AppBarTheme( backgroundColor: AppColors.darkBg, foregroundColor: AppColors.darkTextPrimary, elevation: 0, scrolledUnderElevation: 0, systemOverlayStyle: SystemUiOverlayStyle( statusBarColor: Colors.transparent, statusBarIconBrightness: Brightness.light, ), titleTextStyle: TextStyle( fontFamily: 'Inter', color: AppColors.darkTextPrimary, fontSize: 16, fontWeight: FontWeight.w600, ), ), bottomNavigationBarTheme: const BottomNavigationBarThemeData( backgroundColor: AppColors.darkBgSecondary, selectedItemColor: AppColors.brand, unselectedItemColor: AppColors.darkTextSecondary, type: BottomNavigationBarType.fixed, elevation: 8, ), cardTheme: CardThemeData( color: AppColors.darkBgSecondary, elevation: 0, margin: EdgeInsets.zero, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), side: const BorderSide(color: AppColors.darkCardBorder, width: 0.5), ), ), inputDecorationTheme: InputDecorationTheme( filled: true, fillColor: AppColors.darkBgTertiary, border: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide.none, ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide.none, ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: const BorderSide(color: AppColors.darkTextPrimary), ), errorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: const BorderSide(color: AppColors.error), ), hintStyle: const TextStyle( fontFamily: 'Inter', color: AppColors.darkTextDisabled, ), contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), ), elevatedButtonTheme: ElevatedButtonThemeData( style: ElevatedButton.styleFrom( backgroundColor: AppColors.brand, foregroundColor: Colors.black, minimumSize: const Size(double.infinity, 48), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), textStyle: const TextStyle( fontFamily: 'Inter', fontSize: 16, fontWeight: FontWeight.w600, ), ), ), textButtonTheme: TextButtonThemeData( style: TextButton.styleFrom(foregroundColor: AppColors.brand), ), dividerTheme: const DividerThemeData( color: AppColors.darkDivider, thickness: 1, space: 1, ), tabBarTheme: const TabBarThemeData( labelColor: AppColors.brand, unselectedLabelColor: AppColors.darkTextSecondary, indicatorColor: AppColors.brand, dividerColor: Colors.transparent, labelStyle: TextStyle( fontFamily: 'Inter', fontSize: 14, fontWeight: FontWeight.w600, ), unselectedLabelStyle: TextStyle( fontFamily: 'Inter', fontSize: 14, fontWeight: FontWeight.w400, ), ), bottomSheetTheme: const BottomSheetThemeData( constraints: BoxConstraints(maxWidth: double.infinity), ), chipTheme: ChipThemeData( backgroundColor: AppColors.darkBgTertiary, selectedColor: AppColors.brand.withAlpha(30), labelStyle: const TextStyle( fontFamily: 'Inter', color: AppColors.darkTextPrimary, fontSize: 12, ), side: BorderSide.none, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)), ), // ── TextTheme(对应规范 2.6 节)────────────────────────── // xs=10 sm=12 base=14 lg=16 xl=18 2xl=20 3xl=24 4xl=28 5xl=32 textTheme: const TextTheme( // 页面主标题:18px w700 titleLarge: TextStyle( fontFamily: 'Inter', color: AppColors.darkTextPrimary, fontSize: 18, fontWeight: FontWeight.w700, ), // 区域标题 / AppBar:16px w600 titleMedium: TextStyle( fontFamily: 'Inter', color: AppColors.darkTextPrimary, fontSize: 16, fontWeight: FontWeight.w600, ), // 次级标题:14px w600 titleSmall: TextStyle( fontFamily: 'Inter', color: AppColors.darkTextPrimary, fontSize: 14, fontWeight: FontWeight.w600, ), // 正文主要:14px w400 bodyLarge: TextStyle( fontFamily: 'Inter', color: AppColors.darkTextPrimary, fontSize: 14, fontWeight: FontWeight.w400, ), // 正文次要:12px w400 bodyMedium: TextStyle( fontFamily: 'Inter', color: AppColors.darkTextPrimary, fontSize: 12, fontWeight: FontWeight.w400, ), // 辅助说明:10px w400 bodySmall: TextStyle( fontFamily: 'Inter', color: AppColors.darkTextSecondary, fontSize: 10, fontWeight: FontWeight.w400, ), // 按钮文字:16px w600 labelLarge: TextStyle( fontFamily: 'Inter', color: AppColors.darkTextPrimary, fontSize: 16, fontWeight: FontWeight.w600, ), labelMedium: TextStyle( fontFamily: 'Inter', color: AppColors.darkTextSecondary, fontSize: 12, fontWeight: FontWeight.w400, ), // 禁用文字 / 角标:12px w400 labelSmall: TextStyle( fontFamily: 'Inter', color: AppColors.darkTextDisabled, fontSize: 12, fontWeight: FontWeight.w400, ), ), ); } // ── 浅色主题 ────────────────────────────────────────────────── static ThemeData get light { final base = ThemeData.light(useMaterial3: true); return base.copyWith( scaffoldBackgroundColor: AppColors.lightBg, colorScheme: const ColorScheme.light( primary: AppColors.brand, onPrimary: Colors.black, secondary: AppColors.brand, onSecondary: Colors.black, surface: AppColors.lightBgSecondary, onSurface: AppColors.lightTextPrimary, error: AppColors.error, onError: Colors.white, outline: AppColors.lightDivider, ), appBarTheme: const AppBarTheme( backgroundColor: AppColors.lightBg, foregroundColor: AppColors.lightTextPrimary, elevation: 0, scrolledUnderElevation: 0, systemOverlayStyle: SystemUiOverlayStyle( statusBarColor: Colors.transparent, statusBarIconBrightness: Brightness.dark, ), titleTextStyle: TextStyle( fontFamily: 'Inter', color: AppColors.lightTextPrimary, fontSize: 16, fontWeight: FontWeight.w600, ), ), bottomNavigationBarTheme: const BottomNavigationBarThemeData( backgroundColor: AppColors.lightBg, selectedItemColor: AppColors.brand, unselectedItemColor: AppColors.lightTextSecondary, type: BottomNavigationBarType.fixed, elevation: 8, ), cardTheme: const CardThemeData( color: AppColors.lightBgSecondary, elevation: 0, margin: EdgeInsets.zero, ), inputDecorationTheme: InputDecorationTheme( filled: true, fillColor: AppColors.lightBgTertiary, border: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide.none, ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide.none, ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: const BorderSide(color: AppColors.lightTextPrimary), ), errorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: const BorderSide(color: AppColors.error), ), hintStyle: const TextStyle( fontFamily: 'Inter', color: AppColors.lightTextDisabled, ), contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), ), elevatedButtonTheme: ElevatedButtonThemeData( style: ElevatedButton.styleFrom( backgroundColor: AppColors.brand, foregroundColor: Colors.black, minimumSize: const Size(double.infinity, 48), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), textStyle: const TextStyle( fontFamily: 'Inter', fontSize: 16, fontWeight: FontWeight.w600, ), ), ), textButtonTheme: TextButtonThemeData( style: TextButton.styleFrom(foregroundColor: AppColors.brand), ), dividerTheme: const DividerThemeData( color: AppColors.lightDivider, thickness: 1, space: 1, ), tabBarTheme: const TabBarThemeData( labelColor: AppColors.brand, unselectedLabelColor: AppColors.lightTextSecondary, indicatorColor: AppColors.brand, dividerColor: Colors.transparent, labelStyle: TextStyle( fontFamily: 'Inter', fontSize: 14, fontWeight: FontWeight.w600, ), unselectedLabelStyle: TextStyle( fontFamily: 'Inter', fontSize: 14, fontWeight: FontWeight.w400, ), ), bottomSheetTheme: const BottomSheetThemeData( constraints: BoxConstraints(maxWidth: double.infinity), ), textTheme: const TextTheme( titleLarge: TextStyle( fontFamily: 'Inter', color: AppColors.lightTextPrimary, fontSize: 18, fontWeight: FontWeight.w700, ), titleMedium: TextStyle( fontFamily: 'Inter', color: AppColors.lightTextPrimary, fontSize: 16, fontWeight: FontWeight.w600, ), titleSmall: TextStyle( fontFamily: 'Inter', color: AppColors.lightTextPrimary, fontSize: 14, fontWeight: FontWeight.w600, ), bodyLarge: TextStyle( fontFamily: 'Inter', color: AppColors.lightTextPrimary, fontSize: 14, fontWeight: FontWeight.w400, ), bodyMedium: TextStyle( fontFamily: 'Inter', color: AppColors.lightTextPrimary, fontSize: 12, fontWeight: FontWeight.w400, ), bodySmall: TextStyle( fontFamily: 'Inter', color: AppColors.lightTextSecondary, fontSize: 10, fontWeight: FontWeight.w400, ), labelLarge: TextStyle( fontFamily: 'Inter', color: AppColors.lightTextPrimary, fontSize: 16, fontWeight: FontWeight.w600, ), labelMedium: TextStyle( fontFamily: 'Inter', color: AppColors.lightTextSecondary, fontSize: 12, fontWeight: FontWeight.w400, ), labelSmall: TextStyle( fontFamily: 'Inter', color: AppColors.lightTextDisabled, fontSize: 12, fontWeight: FontWeight.w400, ), ), ); } }