This commit is contained in:
sjk
2025-11-17 14:09:17 +08:00
commit 31e46c5bf6
479 changed files with 109324 additions and 0 deletions

View File

@@ -0,0 +1,278 @@
import 'package:flutter/material.dart';
/// 应用颜色常量
class AppColors {
// 私有构造函数,防止实例化
AppColors._();
// ============ 浅色主题颜色 ============
/// 主色调
static const Color primary = Color(0xFF1976D2);
static const Color onPrimary = Color(0xFFFFFFFF);
static const Color primaryContainer = Color(0xFFBBDEFB);
static const Color onPrimaryContainer = Color(0xFF0D47A1);
/// 次要色调
static const Color secondary = Color(0xFF03DAC6);
static const Color onSecondary = Color(0xFF000000);
static const Color secondaryContainer = Color(0xFFB2DFDB);
static const Color onSecondaryContainer = Color(0xFF004D40);
/// 第三色调
static const Color tertiary = Color(0xFF9C27B0);
static const Color onTertiary = Color(0xFFFFFFFF);
static const Color tertiaryContainer = Color(0xFFE1BEE7);
static const Color onTertiaryContainer = Color(0xFF4A148C);
/// 错误色
static const Color error = Color(0xFFD32F2F);
static const Color onError = Color(0xFFFFFFFF);
static const Color errorContainer = Color(0xFFFFCDD2);
static const Color onErrorContainer = Color(0xFFB71C1C);
/// 背景颜色
static const Color background = Color(0xFFFFFBFE);
static const Color onBackground = Color(0xFF1C1B1F);
/// 表面色
static const Color surface = Color(0xFFFFFFFF);
static const Color onSurface = Color(0xFF1C1B1F);
static const Color surfaceTint = Color(0xFF1976D2);
/// 表面变体色
static const Color surfaceVariant = Color(0xFFF3F3F3);
static const Color onSurfaceVariant = Color(0xFF49454F);
/// 轮廓色
static const Color outline = Color(0xFF79747E);
static const Color outlineVariant = Color(0xFFCAC4D0);
/// 阴影颜色
static const Color shadow = Color(0xFF000000);
static const Color scrim = Color(0xFF000000);
/// 反转颜色
static const Color inverseSurface = Color(0xFF313033);
static const Color onInverseSurface = Color(0xFFF4EFF4);
static const Color inversePrimary = Color(0xFF90CAF9);
// ============ 深色主题颜色 ============
/// 主色调 - 深色
static const Color primaryDark = Color(0xFF90CAF9);
static const Color onPrimaryDark = Color(0xFF003C8F);
static const Color primaryContainerDark = Color(0xFF1565C0);
static const Color onPrimaryContainerDark = Color(0xFFE3F2FD);
/// 次要色调 - 深色
static const Color secondaryDark = Color(0xFF80CBC4);
static const Color onSecondaryDark = Color(0xFF00251A);
static const Color secondaryContainerDark = Color(0xFF00695C);
static const Color onSecondaryContainerDark = Color(0xFFE0F2F1);
/// 第三色调 - 深色
static const Color tertiaryDark = Color(0xFFCE93D8);
static const Color onTertiaryDark = Color(0xFF4A148C);
static const Color tertiaryContainerDark = Color(0xFF7B1FA2);
static const Color onTertiaryContainerDark = Color(0xFFF3E5F5);
/// 错误色 - 深色
static const Color errorDark = Color(0xFFEF5350);
static const Color onErrorDark = Color(0xFF690005);
static const Color errorContainerDark = Color(0xFFD32F2F);
static const Color onErrorContainerDark = Color(0xFFFFEBEE);
/// 背景颜色 - 深色
static const Color backgroundDark = Color(0xFF1C1B1F);
static const Color onBackgroundDark = Color(0xFFE6E1E5);
/// 表面色 - 深色
static const Color surfaceDark = Color(0xFF121212);
static const Color onSurfaceDark = Color(0xFFE6E1E5);
static const Color surfaceTintDark = Color(0xFF90CAF9);
/// 表面变体色 - 深色
static const Color surfaceVariantDark = Color(0xFF49454F);
static const Color onSurfaceVariantDark = Color(0xFFCAC4D0);
/// 轮廓色 - 深色
static const Color outlineDark = Color(0xFF938F99);
static const Color outlineVariantDark = Color(0xFF49454F);
/// 阴影颜色 - 深色
static const Color shadowDark = Color(0xFF000000);
static const Color scrimDark = Color(0xFF000000);
/// 反转色 - 深色
static const Color inverseSurfaceDark = Color(0xFFE6E1E5);
static const Color onInverseSurfaceDark = Color(0xFF313033);
static const Color inversePrimaryDark = Color(0xFF1976D2);
// ============ 功能性颜色 ============
/// 成功色
static const Color success = Color(0xFF4CAF50);
static const Color onSuccess = Color(0xFFFFFFFF);
static const Color successContainer = Color(0xFFE8F5E8);
static const Color onSuccessContainer = Color(0xFF1B5E20);
/// 警告色
static const Color warning = Color(0xFFFF9800);
static const Color onWarning = Color(0xFFFFFFFF);
static const Color warningContainer = Color(0xFFFFF3E0);
static const Color onWarningContainer = Color(0xFFE65100);
/// 信息色
static const Color info = Color(0xFF2196F3);
static const Color onInfo = Color(0xFFFFFFFF);
static const Color infoContainer = Color(0xFFE3F2FD);
static const Color onInfoContainer = Color(0xFF0D47A1);
// ============ 学习模块颜色 ============
/// 词汇学习
static const Color vocabulary = Color(0xFF9C27B0);
static const Color onVocabulary = Color(0xFFFFFFFF);
static const Color vocabularyContainer = Color(0xFFF3E5F5);
static const Color onVocabularyContainer = Color(0xFF4A148C);
static const Color vocabularyDark = Color(0xFFBA68C8);
/// 听力训练
static const Color listening = Color(0xFF00BCD4);
static const Color onListening = Color(0xFFFFFFFF);
static const Color listeningContainer = Color(0xFFE0F7FA);
static const Color onListeningContainer = Color(0xFF006064);
static const Color listeningDark = Color(0xFF4DD0E1);
/// 阅读理解
static const Color reading = Color(0xFF4CAF50);
static const Color onReading = Color(0xFFFFFFFF);
static const Color readingContainer = Color(0xFFE8F5E8);
static const Color onReadingContainer = Color(0xFF1B5E20);
static const Color readingDark = Color(0xFF81C784);
/// 写作练习
static const Color writing = Color(0xFFFF5722);
static const Color onWriting = Color(0xFFFFFFFF);
static const Color writingContainer = Color(0xFFFBE9E7);
static const Color onWritingContainer = Color(0xFFBF360C);
static const Color writingDark = Color(0xFFFF8A65);
/// 口语练习
static const Color speaking = Color(0xFFE91E63);
static const Color onSpeaking = Color(0xFFFFFFFF);
static const Color speakingContainer = Color(0xFFFCE4EC);
static const Color onSpeakingContainer = Color(0xFF880E4F);
static const Color speakingDark = Color(0xFFF06292);
// ============ 等级颜色 ============
/// 初级
static const Color beginner = Color(0xFF4CAF50);
static const Color onBeginner = Color(0xFFFFFFFF);
static const Color beginnerDark = Color(0xFF81C784);
/// 中级
static const Color intermediate = Color(0xFFFF9800);
static const Color onIntermediate = Color(0xFFFFFFFF);
static const Color intermediateDark = Color(0xFFFFB74D);
/// 高级
static const Color advanced = Color(0xFFF44336);
static const Color onAdvanced = Color(0xFFFFFFFF);
static const Color advancedDark = Color(0xFFEF5350);
// ============ 进度颜色 ============
/// 进度条背景
static const Color progressBackground = Color(0xFFE0E0E0);
/// 进度条前景
static const Color progressForeground = Color(0xFF2196F3);
/// 完成状态
static const Color completed = Color(0xFF4CAF50);
/// 进行中状态
static const Color inProgress = Color(0xFFFF9800);
/// 未开始状态
static const Color notStarted = Color(0xFFBDBDBD);
/// 进度等级颜色
static const Color progressLow = Color(0xFFF44336);
static const Color progressLowDark = Color(0xFFEF5350);
static const Color progressMedium = Color(0xFFFF9800);
static const Color progressMediumDark = Color(0xFFFFB74D);
static const Color progressHigh = Color(0xFF4CAF50);
static const Color progressHighDark = Color(0xFF81C784);
// ============ 特殊颜色 ============
/// 分割线
static const Color divider = Color(0xFFE0E0E0);
/// 禁用状态
static const Color disabled = Color(0xFFBDBDBD);
static const Color onDisabled = Color(0xFF757575);
/// 透明度变体
static Color get primaryWithOpacity => primary.withValues(alpha: 0.12);
static Color get secondaryWithOpacity => secondary.withValues(alpha: 0.12);
static Color get errorWithOpacity => error.withValues(alpha: 0.12);
static Color get successWithOpacity => success.withValues(alpha: 0.12);
static Color get warningWithOpacity => warning.withValues(alpha: 0.12);
static Color get infoWithOpacity => info.withValues(alpha: 0.12);
// ============ 渐变色 ============
/// 主要渐变
static const LinearGradient primaryGradient = LinearGradient(
colors: [Color(0xFF2196F3), Color(0xFF21CBF3)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
);
/// 次要渐变
static const LinearGradient secondaryGradient = LinearGradient(
colors: [Color(0xFF03DAC6), Color(0xFF00BCD4)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
);
/// 词汇渐变
static const LinearGradient vocabularyGradient = LinearGradient(
colors: [Color(0xFF9C27B0), Color(0xFFE91E63)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
);
/// 听力渐变
static const LinearGradient listeningGradient = LinearGradient(
colors: [Color(0xFF00BCD4), Color(0xFF2196F3)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
);
/// 阅读渐变
static const LinearGradient readingGradient = LinearGradient(
colors: [Color(0xFF4CAF50), Color(0xFF8BC34A)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
);
/// 写作渐变
static const LinearGradient writingGradient = LinearGradient(
colors: [Color(0xFFFF5722), Color(0xFFFF9800)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
);
/// 口语渐变
static const LinearGradient speakingGradient = LinearGradient(
colors: [Color(0xFFE91E63), Color(0xFF9C27B0)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
);
}

View File

@@ -0,0 +1,365 @@
/// 应用尺寸配置
class AppDimensions {
// 私有构造函数,防止实例化
AppDimensions._();
// ============ 间距 ============
/// 极小间距
static const double spacingXs = 4.0;
/// 小间距
static const double spacingSm = 8.0;
/// 中等间距
static const double spacingMd = 16.0;
/// 大间距
static const double spacingLg = 24.0;
/// 超大间距
static const double spacingXl = 32.0;
/// 超超大间距
static const double spacingXxl = 48.0;
// ============ 内边距 ============
/// 页面内边距
static const double pagePadding = spacingMd;
/// 卡片内边距
static const double cardPadding = spacingMd;
/// 按钮内边距
static const double buttonPadding = spacingMd;
/// 输入框内边距
static const double inputPadding = spacingMd;
/// 列表项内边距
static const double listItemPadding = spacingMd;
/// 对话框内边距
static const double dialogPadding = spacingLg;
/// 底部导航栏内边距
static const double bottomNavPadding = spacingSm;
/// AppBar内边距
static const double appBarPadding = spacingMd;
// ============ 外边距 ============
/// 页面外边距
static const double pageMargin = spacingMd;
/// 卡片外边距
static const double cardMargin = spacingSm;
/// 按钮外边距
static const double buttonMargin = spacingSm;
/// 输入框外边距
static const double inputMargin = spacingSm;
/// 列表项外边距
static const double listItemMargin = spacingXs;
/// 对话框外边距
static const double dialogMargin = spacingLg;
// ============ 圆角半径 ============
/// 极小圆角
static const double radiusXs = 4.0;
/// 小圆角
static const double radiusSm = 8.0;
/// 中等圆角
static const double radiusMd = 12.0;
/// 大圆角
static const double radiusLg = 16.0;
/// 超大圆角
static const double radiusXl = 20.0;
/// 圆形
static const double radiusCircle = 999.0;
// ============ 组件圆角 ============
/// 按钮圆角
static const double buttonRadius = radiusSm;
/// 卡片圆角
static const double cardRadius = radiusMd;
/// 输入框圆角
static const double inputRadius = radiusSm;
/// 对话框圆角
static const double dialogRadius = radiusLg;
/// 底部弹窗圆角
static const double bottomSheetRadius = radiusLg;
/// 芯片圆角
static const double chipRadius = radiusLg;
/// 头像圆角
static const double avatarRadius = radiusCircle;
/// 图片圆角
static const double imageRadius = radiusSm;
// ============ 高度 ============
/// AppBar高度
static const double appBarHeight = 56.0;
/// 底部导航栏高度
static const double bottomNavHeight = 80.0;
/// 标签栏高度
static const double tabBarHeight = 48.0;
/// 按钮高度
static const double buttonHeight = 48.0;
/// 小按钮高度
static const double buttonHeightSm = 36.0;
/// 大按钮高度
static const double buttonHeightLg = 56.0;
/// 输入框高度
static const double inputHeight = 56.0;
/// 列表项高度
static const double listItemHeight = 56.0;
/// 小列表项高度
static const double listItemHeightSm = 48.0;
/// 大列表项高度
static const double listItemHeightLg = 72.0;
/// 工具栏高度
static const double toolbarHeight = 56.0;
/// 搜索栏高度
static const double searchBarHeight = 48.0;
/// 进度条高度
static const double progressBarHeight = 4.0;
/// 分割线高度
static const double dividerHeight = 1.0;
// ============ 宽度 ============
/// 最小按钮宽度
static const double buttonMinWidth = 64.0;
/// 侧边栏宽度
static const double drawerWidth = 304.0;
/// 分割线宽度
static const double dividerWidth = 1.0;
/// 边框宽度
static const double borderWidth = 1.0;
/// 粗边框宽度
static const double borderWidthThick = 2.0;
// ============ 图标尺寸 ============
/// 极小图标
static const double iconXs = 16.0;
/// 小图标
static const double iconSm = 20.0;
/// 中等图标
static const double iconMd = 24.0;
/// 大图标
static const double iconLg = 32.0;
/// 超大图标
static const double iconXl = 48.0;
/// 超超大图标
static const double iconXxl = 64.0;
// ============ 头像尺寸 ============
/// 小头像
static const double avatarSm = 32.0;
/// 中等头像
static const double avatarMd = 48.0;
/// 大头像
static const double avatarLg = 64.0;
/// 超大头像
static const double avatarXl = 96.0;
// ============ 阴影 ============
/// 阴影偏移
static const double shadowOffset = 2.0;
/// 阴影模糊半径
static const double shadowBlurRadius = 8.0;
/// 阴影扩散半径
static const double shadowSpreadRadius = 0.0;
// ============ 动画持续时间 ============
/// 快速动画
static const Duration animationFast = Duration(milliseconds: 150);
/// 中等动画
static const Duration animationMedium = Duration(milliseconds: 300);
/// 慢速动画
static const Duration animationSlow = Duration(milliseconds: 500);
// ============ 学习相关尺寸 ============
/// 单词卡片高度
static const double wordCardHeight = 200.0;
/// 单词卡片宽度
static const double wordCardWidth = 300.0;
/// 进度圆环大小
static const double progressCircleSize = 120.0;
/// 等级徽章大小
static const double levelBadgeSize = 40.0;
/// 成就徽章大小
static const double achievementBadgeSize = 60.0;
/// 音频播放器高度
static const double audioPlayerHeight = 80.0;
/// 练习题选项高度
static const double exerciseOptionHeight = 48.0;
/// 学习统计卡片高度
static const double statsCardHeight = 120.0;
// ============ 响应式断点 ============
/// 手机断点
static const double mobileBreakpoint = 600.0;
/// 平板断点
static const double tabletBreakpoint = 900.0;
/// 桌面断点
static const double desktopBreakpoint = 1200.0;
// ============ 最大宽度 ============
/// 内容最大宽度
static const double maxContentWidth = 1200.0;
/// 对话框最大宽度
static const double maxDialogWidth = 560.0;
/// 卡片最大宽度
static const double maxCardWidth = 400.0;
// ============ 最小尺寸 ============
/// 最小触摸目标尺寸
static const double minTouchTarget = 48.0;
/// 最小按钮尺寸
static const double minButtonSize = 36.0;
// ============ 网格布局 ============
/// 网格间距
static const double gridSpacing = spacingSm;
/// 网格交叉轴间距
static const double gridCrossAxisSpacing = spacingSm;
/// 网格主轴间距
static const double gridMainAxisSpacing = spacingSm;
/// 网格子项宽高比
static const double gridChildAspectRatio = 1.0;
// ============ 列表布局 ============
/// 列表分割线缩进
static const double listDividerIndent = spacingMd;
/// 列表分割线结束缩进
static const double listDividerEndIndent = spacingMd;
// ============ 浮动操作按钮 ============
/// 浮动操作按钮大小
static const double fabSize = 56.0;
/// 小浮动操作按钮大小
static const double fabSizeSmall = 40.0;
/// 大浮动操作按钮大小
static const double fabSizeLarge = 96.0;
/// 浮动操作按钮边距
static const double fabMargin = spacingMd;
// ============ 辅助方法 ============
/// 根据屏幕宽度获取响应式间距
static double getResponsiveSpacing(double screenWidth) {
if (screenWidth < mobileBreakpoint) {
return spacingSm;
} else if (screenWidth < tabletBreakpoint) {
return spacingMd;
} else {
return spacingLg;
}
}
/// 根据屏幕宽度获取响应式内边距
static double getResponsivePadding(double screenWidth) {
if (screenWidth < mobileBreakpoint) {
return spacingMd;
} else if (screenWidth < tabletBreakpoint) {
return spacingLg;
} else {
return spacingXl;
}
}
/// 根据屏幕宽度判断是否为移动设备
static bool isMobile(double screenWidth) {
return screenWidth < mobileBreakpoint;
}
/// 根据屏幕宽度判断是否为平板设备
static bool isTablet(double screenWidth) {
return screenWidth >= mobileBreakpoint && screenWidth < desktopBreakpoint;
}
/// 根据屏幕宽度判断是否为桌面设备
static bool isDesktop(double screenWidth) {
return screenWidth >= desktopBreakpoint;
}
}

View File

@@ -0,0 +1,437 @@
import 'package:flutter/material.dart';
import 'app_colors.dart';
/// 应用文本样式配置
class AppTextStyles {
// 私有构造函数,防止实例化
AppTextStyles._();
// ============ 字体家族 ============
/// 默认字体 - 使用系统默认,不指定字体名称
static const String? defaultFontFamily = null;
/// 中文字体 - 使用系统默认,不指定字体名称
static const String? chineseFontFamily = null;
/// 等宽字体 - 使用系统默认,不指定字体名称
static const String? monospaceFontFamily = null;
// ============ 字体权重 ============
static const FontWeight light = FontWeight.w300;
static const FontWeight regular = FontWeight.w400;
static const FontWeight medium = FontWeight.w500;
static const FontWeight semiBold = FontWeight.w600;
static const FontWeight bold = FontWeight.w700;
static const FontWeight extraBold = FontWeight.w800;
// ============ 基础文本样式 ============
/// 标题样式
static const TextStyle displayLarge = TextStyle(
fontSize: 57,
fontWeight: bold,
letterSpacing: -0.25,
height: 1.12,
color: AppColors.onSurface,
);
static const TextStyle displayMedium = TextStyle(
fontSize: 45,
fontWeight: bold,
letterSpacing: 0,
height: 1.16,
color: AppColors.onSurface,
);
static const TextStyle displaySmall = TextStyle(
fontSize: 36,
fontWeight: bold,
letterSpacing: 0,
height: 1.22,
color: AppColors.onSurface,
);
/// 标题样式
static const TextStyle headlineLarge = TextStyle(
fontSize: 32,
fontWeight: bold,
letterSpacing: 0,
height: 1.25,
color: AppColors.onSurface,
);
static const TextStyle headlineMedium = TextStyle(
fontSize: 28,
fontWeight: semiBold,
letterSpacing: 0,
height: 1.29,
color: AppColors.onSurface,
);
static const TextStyle headlineSmall = TextStyle(
fontSize: 24,
fontWeight: semiBold,
letterSpacing: 0,
height: 1.33,
color: AppColors.onSurface,
);
/// 标题样式
static const TextStyle titleLarge = TextStyle(
fontSize: 22,
fontWeight: semiBold,
letterSpacing: 0,
height: 1.27,
color: AppColors.onSurface,
);
static const TextStyle titleMedium = TextStyle(
fontSize: 16,
fontWeight: medium,
letterSpacing: 0.15,
height: 1.50,
color: AppColors.onSurface,
);
static const TextStyle titleSmall = TextStyle(
fontSize: 14,
fontWeight: medium,
letterSpacing: 0.1,
height: 1.43,
color: AppColors.onSurface,
);
/// 标签样式
static const TextStyle labelLarge = TextStyle(
fontSize: 14,
fontWeight: medium,
letterSpacing: 0.1,
height: 1.43,
color: AppColors.onSurface,
);
static const TextStyle labelMedium = TextStyle(
fontSize: 12,
fontWeight: medium,
letterSpacing: 0.5,
height: 1.33,
color: AppColors.onSurface,
);
static const TextStyle labelSmall = TextStyle(
fontSize: 11,
fontWeight: medium,
letterSpacing: 0.5,
height: 1.45,
color: AppColors.onSurface,
);
/// 正文样式
static const TextStyle bodyLarge = TextStyle(
fontSize: 16,
fontWeight: regular,
letterSpacing: 0.5,
height: 1.50,
color: AppColors.onSurface,
);
static const TextStyle bodyMedium = TextStyle(
fontSize: 14,
fontWeight: regular,
letterSpacing: 0.25,
height: 1.43,
color: AppColors.onSurface,
);
static const TextStyle bodySmall = TextStyle(
fontSize: 12,
fontWeight: regular,
letterSpacing: 0.4,
height: 1.33,
color: AppColors.onSurfaceVariant,
);
// ============ 自定义文本样式 ============
/// 按钮文本样式
static const TextStyle buttonLarge = TextStyle(
fontSize: 16,
fontWeight: semiBold,
letterSpacing: 0.1,
height: 1.25,
color: AppColors.onPrimary,
);
static const TextStyle buttonMedium = TextStyle(
fontSize: 14,
fontWeight: semiBold,
letterSpacing: 0.1,
height: 1.29,
color: AppColors.onPrimary,
);
static const TextStyle buttonSmall = TextStyle(
fontSize: 12,
fontWeight: medium,
letterSpacing: 0.5,
height: 1.33,
color: AppColors.onPrimary,
);
/// 输入框文本样式
static const TextStyle inputText = TextStyle(
fontSize: 16,
fontWeight: regular,
letterSpacing: 0.5,
height: 1.50,
color: AppColors.onSurface,
);
static const TextStyle inputLabel = TextStyle(
fontSize: 16,
fontWeight: medium,
letterSpacing: 0.15,
height: 1.50,
color: AppColors.onSurfaceVariant,
);
static const TextStyle inputHint = TextStyle(
fontSize: 16,
fontWeight: regular,
letterSpacing: 0.5,
height: 1.50,
color: AppColors.onSurfaceVariant,
);
static const TextStyle inputError = TextStyle(
fontSize: 12,
fontWeight: regular,
letterSpacing: 0.4,
height: 1.33,
color: AppColors.error,
);
/// 导航文本样式
static const TextStyle navigationLabel = TextStyle(
fontSize: 12,
fontWeight: medium,
letterSpacing: 0.5,
height: 1.33,
color: AppColors.onSurface,
);
static const TextStyle tabLabel = TextStyle(
fontSize: 14,
fontWeight: medium,
letterSpacing: 0.1,
height: 1.43,
color: AppColors.onSurface,
);
/// 卡片文本样式
static const TextStyle cardTitle = TextStyle(
fontSize: 18,
fontWeight: semiBold,
letterSpacing: 0,
height: 1.33,
color: AppColors.onSurface,
);
static const TextStyle cardSubtitle = TextStyle(
fontSize: 14,
fontWeight: regular,
letterSpacing: 0.25,
height: 1.43,
color: AppColors.onSurfaceVariant,
);
static const TextStyle cardBody = TextStyle(
fontSize: 14,
fontWeight: regular,
letterSpacing: 0.25,
height: 1.43,
color: AppColors.onSurface,
);
/// 列表文本样式
static const TextStyle listTitle = TextStyle(
fontSize: 16,
fontWeight: medium,
letterSpacing: 0.15,
height: 1.50,
color: AppColors.onSurface,
);
static const TextStyle listSubtitle = TextStyle(
fontSize: 14,
fontWeight: regular,
letterSpacing: 0.25,
height: 1.43,
color: AppColors.onSurfaceVariant,
);
/// 学习相关文本样式
static const TextStyle wordText = TextStyle(
fontSize: 24,
fontWeight: semiBold,
letterSpacing: 0,
height: 1.33,
color: AppColors.onSurface,
);
static const TextStyle phoneticText = TextStyle(
fontSize: 16,
fontWeight: regular,
letterSpacing: 0.5,
height: 1.50,
color: AppColors.onSurfaceVariant,
fontFamily: monospaceFontFamily,
);
static const TextStyle definitionText = TextStyle(
fontSize: 16,
fontWeight: regular,
letterSpacing: 0.5,
height: 1.50,
color: AppColors.onSurface,
);
static const TextStyle exampleText = TextStyle(
fontSize: 14,
fontWeight: regular,
letterSpacing: 0.25,
height: 1.43,
color: AppColors.onSurfaceVariant,
fontStyle: FontStyle.italic,
);
/// 分数和统计文本样式
static const TextStyle scoreText = TextStyle(
fontSize: 32,
fontWeight: bold,
letterSpacing: 0,
height: 1.25,
color: AppColors.primary,
);
static const TextStyle statisticNumber = TextStyle(
fontSize: 24,
fontWeight: semiBold,
letterSpacing: 0,
height: 1.33,
color: AppColors.onSurface,
);
static const TextStyle statisticLabel = TextStyle(
fontSize: 12,
fontWeight: medium,
letterSpacing: 0.5,
height: 1.33,
color: AppColors.onSurfaceVariant,
);
/// 状态文本样式
static const TextStyle successText = TextStyle(
fontSize: 14,
fontWeight: medium,
letterSpacing: 0.1,
height: 1.43,
color: AppColors.success,
);
static const TextStyle warningText = TextStyle(
fontSize: 14,
fontWeight: medium,
letterSpacing: 0.1,
height: 1.43,
color: AppColors.warning,
);
static const TextStyle errorText = TextStyle(
fontSize: 14,
fontWeight: medium,
letterSpacing: 0.1,
height: 1.43,
color: AppColors.error,
);
static const TextStyle infoText = TextStyle(
fontSize: 14,
fontWeight: medium,
letterSpacing: 0.1,
height: 1.43,
color: AppColors.info,
);
// ============ Material 3 文本主题 ============
/// Material 3 文本主题
static const TextTheme textTheme = TextTheme(
displayLarge: displayLarge,
displayMedium: displayMedium,
displaySmall: displaySmall,
headlineLarge: headlineLarge,
headlineMedium: headlineMedium,
headlineSmall: headlineSmall,
titleLarge: titleLarge,
titleMedium: titleMedium,
titleSmall: titleSmall,
labelLarge: labelLarge,
labelMedium: labelMedium,
labelSmall: labelSmall,
bodyLarge: bodyLarge,
bodyMedium: bodyMedium,
bodySmall: bodySmall,
);
// ============ 辅助方法 ============
/// 根据主题亮度调整文本颜色
static TextStyle adaptiveTextStyle(TextStyle style, Brightness brightness) {
if (brightness == Brightness.dark) {
return style.copyWith(
color: _adaptColorForDarkTheme(style.color ?? AppColors.onSurface),
);
}
return style;
}
/// 为深色主题调整颜色
static Color _adaptColorForDarkTheme(Color color) {
if (color == AppColors.onSurface) {
return AppColors.onSurfaceDark;
} else if (color == AppColors.onSurfaceVariant) {
return AppColors.onSurfaceVariantDark;
} else if (color == AppColors.primary) {
return AppColors.primaryDark;
}
return color;
}
/// 创建带有特定颜色的文本样式
static TextStyle withColor(TextStyle style, Color color) {
return style.copyWith(color: color);
}
/// 创建带有特定字体大小的文本样式
static TextStyle withFontSize(TextStyle style, double fontSize) {
return style.copyWith(fontSize: fontSize);
}
/// 创建带有特定字体权重的文本样式
static TextStyle withFontWeight(TextStyle style, FontWeight fontWeight) {
return style.copyWith(fontWeight: fontWeight);
}
/// 创建带有特定行高的文本样式
static TextStyle withHeight(TextStyle style, double height) {
return style.copyWith(height: height);
}
/// 创建带有特定字母间距的文本样式
static TextStyle withLetterSpacing(TextStyle style, double letterSpacing) {
return style.copyWith(letterSpacing: letterSpacing);
}
}

View File

@@ -0,0 +1,424 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'app_colors.dart';
import 'app_text_styles.dart';
import 'app_dimensions.dart';
/// 应用主题配置
class AppTheme {
// 私有构造函数,防止实例化
AppTheme._();
// ============ 亮色主题 ============
static ThemeData get lightTheme {
return ThemeData(
useMaterial3: true,
brightness: Brightness.light,
// 禁用Google Fonts使用系统默认字体
fontFamily: null, // 不指定字体,使用系统默认
// 颜色方案
colorScheme: const ColorScheme.light(
primary: AppColors.primary,
onPrimary: AppColors.onPrimary,
primaryContainer: AppColors.primaryContainer,
onPrimaryContainer: AppColors.onPrimaryContainer,
secondary: AppColors.secondary,
onSecondary: AppColors.onSecondary,
secondaryContainer: AppColors.secondaryContainer,
onSecondaryContainer: AppColors.onSecondaryContainer,
tertiary: AppColors.tertiary,
onTertiary: AppColors.onTertiary,
tertiaryContainer: AppColors.tertiaryContainer,
onTertiaryContainer: AppColors.onTertiaryContainer,
error: AppColors.error,
onError: AppColors.onError,
errorContainer: AppColors.errorContainer,
onErrorContainer: AppColors.onErrorContainer,
surface: AppColors.surface,
onSurface: AppColors.onSurface,
surfaceContainerHighest: AppColors.surfaceVariant,
onSurfaceVariant: AppColors.onSurfaceVariant,
outline: AppColors.outline,
outlineVariant: AppColors.outlineVariant,
shadow: AppColors.shadow,
scrim: AppColors.scrim,
inverseSurface: AppColors.inverseSurface,
onInverseSurface: AppColors.onInverseSurface,
inversePrimary: AppColors.inversePrimary,
surfaceTint: AppColors.surfaceTint,
),
// 文本主题
textTheme: AppTextStyles.textTheme,
// AppBar主题
appBarTheme: AppBarTheme(
backgroundColor: AppColors.surface,
foregroundColor: AppColors.onSurface,
elevation: 0,
scrolledUnderElevation: 1,
centerTitle: true,
titleTextStyle: AppTextStyles.titleLarge,
toolbarHeight: AppDimensions.appBarHeight,
systemOverlayStyle: const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarIconBrightness: Brightness.dark,
statusBarBrightness: Brightness.light,
),
),
// 按钮主题
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.primary,
foregroundColor: AppColors.onPrimary,
textStyle: AppTextStyles.buttonMedium,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppDimensions.buttonRadius),
),
minimumSize: const Size(AppDimensions.buttonMinWidth, AppDimensions.buttonHeight),
padding: const EdgeInsets.symmetric(
horizontal: AppDimensions.buttonPadding,
vertical: AppDimensions.spacingSm,
),
),
),
filledButtonTheme: FilledButtonThemeData(
style: FilledButton.styleFrom(
backgroundColor: AppColors.primary,
foregroundColor: AppColors.onPrimary,
textStyle: AppTextStyles.buttonMedium,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppDimensions.buttonRadius),
),
minimumSize: const Size(AppDimensions.buttonMinWidth, AppDimensions.buttonHeight),
),
),
outlinedButtonTheme: OutlinedButtonThemeData(
style: OutlinedButton.styleFrom(
foregroundColor: AppColors.primary,
textStyle: AppTextStyles.buttonMedium,
side: const BorderSide(color: AppColors.outline),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppDimensions.buttonRadius),
),
minimumSize: const Size(AppDimensions.buttonMinWidth, AppDimensions.buttonHeight),
),
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
foregroundColor: AppColors.primary,
textStyle: AppTextStyles.buttonMedium,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppDimensions.buttonRadius),
),
minimumSize: const Size(AppDimensions.buttonMinWidth, AppDimensions.buttonHeight),
),
),
// 输入框主题
inputDecorationTheme: InputDecorationTheme(
filled: true,
fillColor: AppColors.surfaceVariant,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(AppDimensions.inputRadius),
borderSide: const BorderSide(color: AppColors.outline),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(AppDimensions.inputRadius),
borderSide: const BorderSide(color: AppColors.outline),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(AppDimensions.inputRadius),
borderSide: const BorderSide(color: AppColors.primary, width: 2),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(AppDimensions.inputRadius),
borderSide: const BorderSide(color: AppColors.error),
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(AppDimensions.inputRadius),
borderSide: const BorderSide(color: AppColors.error, width: 2),
),
labelStyle: AppTextStyles.inputLabel,
hintStyle: AppTextStyles.inputHint,
errorStyle: AppTextStyles.inputError,
contentPadding: const EdgeInsets.all(AppDimensions.inputPadding),
),
// 卡片主题
cardTheme: CardThemeData(
color: AppColors.surface,
elevation: 1,
shadowColor: AppColors.shadow,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppDimensions.cardRadius),
),
margin: const EdgeInsets.all(AppDimensions.cardMargin),
),
// 底部导航栏主题
bottomNavigationBarTheme: const BottomNavigationBarThemeData(
backgroundColor: AppColors.surface,
selectedItemColor: AppColors.primary,
unselectedItemColor: AppColors.onSurfaceVariant,
selectedLabelStyle: AppTextStyles.navigationLabel,
unselectedLabelStyle: AppTextStyles.navigationLabel,
type: BottomNavigationBarType.fixed,
elevation: 8,
),
// 标签栏主题
tabBarTheme: TabBarThemeData(
labelColor: AppColors.primary,
unselectedLabelColor: AppColors.onSurfaceVariant,
labelStyle: AppTextStyles.tabLabel,
unselectedLabelStyle: AppTextStyles.tabLabel,
indicator: const UnderlineTabIndicator(
borderSide: BorderSide(color: AppColors.primary, width: 2),
),
),
// 芯片主题
chipTheme: ChipThemeData(
backgroundColor: AppColors.surfaceVariant,
selectedColor: AppColors.primaryContainer,
disabledColor: AppColors.surfaceVariant.withValues(alpha: 0.5),
labelStyle: AppTextStyles.labelMedium,
secondaryLabelStyle: AppTextStyles.labelMedium,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppDimensions.chipRadius),
),
padding: const EdgeInsets.symmetric(
horizontal: AppDimensions.spacingSm,
vertical: AppDimensions.spacingXs,
),
),
// 对话框主题
dialogTheme: DialogThemeData(
backgroundColor: AppColors.surface,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppDimensions.dialogRadius),
),
titleTextStyle: AppTextStyles.headlineSmall,
contentTextStyle: AppTextStyles.bodyMedium,
),
// 提示条主题
snackBarTheme: SnackBarThemeData(
backgroundColor: AppColors.inverseSurface,
contentTextStyle: AppTextStyles.bodyMedium.copyWith(
color: AppColors.onInverseSurface,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppDimensions.radiusSm),
),
behavior: SnackBarBehavior.floating,
),
// 浮动操作按钮主题
floatingActionButtonTheme: const FloatingActionButtonThemeData(
backgroundColor: AppColors.primary,
foregroundColor: AppColors.onPrimary,
elevation: 6,
focusElevation: 8,
hoverElevation: 8,
highlightElevation: 12,
),
// 分割线主题
dividerTheme: const DividerThemeData(
color: AppColors.outline,
thickness: AppDimensions.dividerHeight,
space: AppDimensions.dividerHeight,
),
// 列表项主题
listTileTheme: ListTileThemeData(
contentPadding: const EdgeInsets.symmetric(
horizontal: AppDimensions.listItemPadding,
vertical: AppDimensions.spacingXs,
),
titleTextStyle: AppTextStyles.listTitle,
subtitleTextStyle: AppTextStyles.listSubtitle,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppDimensions.radiusSm),
),
),
// 开关主题
switchTheme: SwitchThemeData(
thumbColor: WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.selected)) {
return AppColors.onPrimary;
}
return AppColors.outline;
}),
trackColor: WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.selected)) {
return AppColors.primary;
}
return AppColors.surfaceVariant;
}),
),
// 复选框主题
checkboxTheme: CheckboxThemeData(
fillColor: WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.selected)) {
return AppColors.primary;
}
return Colors.transparent;
}),
checkColor: WidgetStateProperty.all(AppColors.onPrimary),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppDimensions.radiusXs),
),
),
// 单选按钮主题
radioTheme: RadioThemeData(
fillColor: WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.selected)) {
return AppColors.primary;
}
return AppColors.onSurfaceVariant;
}),
),
// 滑块主题
sliderTheme: const SliderThemeData(
activeTrackColor: AppColors.primary,
inactiveTrackColor: AppColors.surfaceVariant,
thumbColor: AppColors.primary,
overlayColor: AppColors.primaryContainer,
valueIndicatorColor: AppColors.primary,
),
// 进度指示器主题
progressIndicatorTheme: const ProgressIndicatorThemeData(
color: AppColors.primary,
linearTrackColor: AppColors.surfaceVariant,
circularTrackColor: AppColors.surfaceVariant,
),
);
}
// ============ 深色主题 ============
static ThemeData get darkTheme {
return ThemeData(
useMaterial3: true,
brightness: Brightness.dark,
// 禁用Google Fonts使用系统默认字体
fontFamily: null, // 不指定字体,使用系统默认
// 颜色方案
colorScheme: const ColorScheme.dark(
primary: AppColors.primaryDark,
onPrimary: AppColors.onPrimaryDark,
primaryContainer: AppColors.primaryContainerDark,
onPrimaryContainer: AppColors.onPrimaryContainerDark,
secondary: AppColors.secondaryDark,
onSecondary: AppColors.onSecondaryDark,
secondaryContainer: AppColors.secondaryContainerDark,
onSecondaryContainer: AppColors.onSecondaryContainerDark,
tertiary: AppColors.tertiaryDark,
onTertiary: AppColors.onTertiaryDark,
tertiaryContainer: AppColors.tertiaryContainerDark,
onTertiaryContainer: AppColors.onTertiaryContainerDark,
error: AppColors.errorDark,
onError: AppColors.onErrorDark,
errorContainer: AppColors.errorContainerDark,
onErrorContainer: AppColors.onErrorContainerDark,
surface: AppColors.surfaceDark,
onSurface: AppColors.onSurfaceDark,
surfaceContainerHighest: AppColors.surfaceVariantDark,
onSurfaceVariant: AppColors.onSurfaceVariantDark,
outline: AppColors.outlineDark,
outlineVariant: AppColors.outlineVariantDark,
shadow: AppColors.shadowDark,
scrim: AppColors.scrimDark,
inverseSurface: AppColors.inverseSurfaceDark,
onInverseSurface: AppColors.onInverseSurfaceDark,
inversePrimary: AppColors.inversePrimaryDark,
surfaceTint: AppColors.surfaceTintDark,
),
// 文本主题(深色适配)
textTheme: AppTextStyles.textTheme.apply(
bodyColor: AppColors.onSurfaceDark,
displayColor: AppColors.onSurfaceDark,
),
// AppBar主题
appBarTheme: AppBarTheme(
backgroundColor: AppColors.surfaceDark,
foregroundColor: AppColors.onSurfaceDark,
elevation: 0,
scrolledUnderElevation: 1,
centerTitle: true,
titleTextStyle: AppTextStyles.titleLarge.copyWith(
color: AppColors.onSurfaceDark,
),
toolbarHeight: AppDimensions.appBarHeight,
systemOverlayStyle: const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarIconBrightness: Brightness.light,
statusBarBrightness: Brightness.dark,
),
),
// 其他组件主题配置与亮色主题类似,但使用深色颜色
// 为了简洁,这里省略了重复的配置
// 实际项目中应该完整配置所有组件的深色主题
);
}
// ============ 主题扩展 ============
/// 获取当前主题的学习模块颜色
static Map<String, Color> getLearningColors(BuildContext context) {
final isDark = Theme.of(context).brightness == Brightness.dark;
return {
'vocabulary': isDark ? AppColors.vocabularyDark : AppColors.vocabulary,
'listening': isDark ? AppColors.listeningDark : AppColors.listening,
'reading': isDark ? AppColors.readingDark : AppColors.reading,
'writing': isDark ? AppColors.writingDark : AppColors.writing,
'speaking': isDark ? AppColors.speakingDark : AppColors.speaking,
};
}
/// 获取等级颜色
static Color getLevelColor(String level, {bool isDark = false}) {
switch (level.toLowerCase()) {
case 'beginner':
return isDark ? AppColors.beginnerDark : AppColors.beginner;
case 'intermediate':
return isDark ? AppColors.intermediateDark : AppColors.intermediate;
case 'advanced':
return isDark ? AppColors.advancedDark : AppColors.advanced;
default:
return isDark ? AppColors.primaryDark : AppColors.primary;
}
}
/// 获取进度颜色
static Color getProgressColor(double progress, {bool isDark = false}) {
if (progress < 0.3) {
return isDark ? AppColors.progressLowDark : AppColors.progressLow;
} else if (progress < 0.7) {
return isDark ? AppColors.progressMediumDark : AppColors.progressMedium;
} else {
return isDark ? AppColors.progressHighDark : AppColors.progressHigh;
}
}
}