优化
This commit is contained in:
@@ -1,62 +1,155 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// 应用颜色常量
|
||||
/// 应用颜色常量 - 统一的颜色系统
|
||||
///
|
||||
/// 设计原则:
|
||||
/// 1. 语义化命名 - 颜色按用途命名,而非外观
|
||||
/// 2. 对比度保证 - 文字与背景对比度 >= 4.5:1 (WCAG AA)
|
||||
/// 3. 一致性 - 同一语义用途使用同一颜色
|
||||
class AppColors {
|
||||
AppColors._();
|
||||
|
||||
// 主题色
|
||||
static const Color primary = Color(0xFF00D4AA);
|
||||
static const Color primaryLight = Color(0xFF00E6B8);
|
||||
static const Color primaryDark = Color(0xFF00B894);
|
||||
// ============================================
|
||||
// 品牌色 (Brand Colors) - 专业蓝
|
||||
// ============================================
|
||||
|
||||
// 状态色
|
||||
static const Color success = Color(0xFF00C853);
|
||||
static const Color warning = Color(0xFFFF9800);
|
||||
static const Color error = Color(0xFFFF5252);
|
||||
static const Color info = Color(0xFF2196F3);
|
||||
/// 主品牌色 - 专业蓝,代表信任与稳定
|
||||
static const Color primary = Color(0xFF2563EB);
|
||||
|
||||
// 涨跌色
|
||||
static const Color up = Color(0xFF00C853);
|
||||
static const Color down = Color(0xFFFF5252);
|
||||
/// 主品牌色浅色变体
|
||||
static const Color primaryLight = Color(0xFF3B82F6);
|
||||
|
||||
// 深色主题背景
|
||||
static const Color background = Color(0xFF1A1A2E);
|
||||
static const Color cardBackground = Color(0xFF16213E);
|
||||
static const Color scaffoldBackground = Color(0xFF1A1A2E);
|
||||
/// 主品牌色深色变体
|
||||
static const Color primaryDark = Color(0xFF1D4ED8);
|
||||
|
||||
// 文字颜色
|
||||
static const Color textPrimary = Colors.white;
|
||||
static const Color textSecondary = Color(0x99FFFFFF);
|
||||
static const Color textHint = Color(0x4DFFFFFF);
|
||||
static const Color textDisabled = Color(0x33FFFFFF);
|
||||
|
||||
// 边框和分割线
|
||||
static const Color border = Color(0x1AFFFFFF);
|
||||
static const Color divider = Color(0x1AFFFFFF);
|
||||
|
||||
// 输入框
|
||||
static const Color inputBackground = Color(0xFF16213E);
|
||||
static const Color inputBorder = Color(0x33FFFFFF);
|
||||
static const Color inputFocusBorder = Color(0xFF00D4AA);
|
||||
|
||||
// 按钮渐变
|
||||
/// 主品牌色渐变
|
||||
static const LinearGradient primaryGradient = LinearGradient(
|
||||
colors: [primary, primaryDark],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
);
|
||||
|
||||
// 买入按钮渐变
|
||||
// ============================================
|
||||
// 语义色 (Semantic Colors)
|
||||
// ============================================
|
||||
|
||||
/// 成功/上涨 - 绿色系
|
||||
static const Color success = Color(0xFF00C853);
|
||||
static const Color up = success;
|
||||
|
||||
/// 警告 - 橙色系
|
||||
static const Color warning = Color(0xFFFF9800);
|
||||
|
||||
/// 错误/下跌 - 红色系
|
||||
static const Color error = Color(0xFFFF5252);
|
||||
static const Color down = error;
|
||||
|
||||
/// 信息 - 蓝色系
|
||||
static const Color info = Color(0xFF2196F3);
|
||||
|
||||
/// 交易类型色
|
||||
static const Color deposit = success;
|
||||
static const Color withdraw = warning;
|
||||
static const Color trade = info;
|
||||
|
||||
// ============================================
|
||||
// 深色主题背景色 (Dark Theme Backgrounds)
|
||||
// ============================================
|
||||
|
||||
/// 主背景色 - 最深的背景
|
||||
static const Color background = Color(0xFF0F0F1A);
|
||||
|
||||
/// 卡片背景色
|
||||
static const Color cardBackground = Color(0xFF1A1A2E);
|
||||
|
||||
/// Scaffold 背景色
|
||||
static const Color scaffoldBackground = background;
|
||||
|
||||
/// 表面色 - 用于弹出层、对话框
|
||||
static const Color surface = Color(0xFF16213E);
|
||||
|
||||
/// 悬停状态背景
|
||||
static const Color hoverBackground = Color(0xFF252542);
|
||||
|
||||
// ============================================
|
||||
// 文字颜色 (Text Colors)
|
||||
// 对比度均 >= 4.5:1 (基于深色背景)
|
||||
// ============================================
|
||||
|
||||
/// 主要文字 - 白色,对比度 21:1
|
||||
static const Color textPrimary = Color(0xFFFFFFFF);
|
||||
|
||||
/// 次要文字 - 浅灰色,对比度 ~10:1
|
||||
static const Color textSecondary = Color(0xFFB0B0B0);
|
||||
|
||||
/// 提示文字 - 中灰色,对比度 ~5:1
|
||||
static const Color textHint = Color(0xFF808080);
|
||||
|
||||
/// 禁用文字 - 深灰色,对比度 ~3:1
|
||||
static const Color textDisabled = Color(0xFF4D4D4D);
|
||||
|
||||
/// 链接文字
|
||||
static const Color textLink = primary;
|
||||
|
||||
// ============================================
|
||||
// 边框和分割线 (Borders & Dividers)
|
||||
// ============================================
|
||||
|
||||
/// 默认边框色
|
||||
static const Color border = Color(0xFF2A2A45);
|
||||
|
||||
/// 分割线颜色
|
||||
static const Color divider = border;
|
||||
|
||||
/// 焦点边框色
|
||||
static const Color focusBorder = primary;
|
||||
|
||||
/// 输入框边框色
|
||||
static const Color inputBorder = Color(0xFF3A3A55);
|
||||
|
||||
// ============================================
|
||||
// 输入框颜色 (Input Colors)
|
||||
// ============================================
|
||||
|
||||
/// 输入框背景
|
||||
static const Color inputBackground = cardBackground;
|
||||
|
||||
/// 输入框焦点边框
|
||||
static const Color inputFocusBorder = primary;
|
||||
|
||||
// ============================================
|
||||
// 按钮渐变 (Button Gradients)
|
||||
// ============================================
|
||||
|
||||
/// 买入按钮渐变
|
||||
static const LinearGradient buyGradient = LinearGradient(
|
||||
colors: [Color(0xFF00C853), Color(0xFF00A844)],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
);
|
||||
|
||||
// 卖出按钮渐变
|
||||
/// 卖出按钮渐变
|
||||
static const LinearGradient sellGradient = LinearGradient(
|
||||
colors: [Color(0xFFFF5252), Color(0xFFD32F2F)],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// 渐变色 (Gradient Colors)
|
||||
// ============================================
|
||||
|
||||
/// 资产卡片渐变色
|
||||
static const List<Color> gradientColors = [primary, primaryDark];
|
||||
|
||||
// ============================================
|
||||
// 工具方法 (Utility Methods)
|
||||
// ============================================
|
||||
|
||||
/// 获取涨跌颜色
|
||||
static Color getChangeColor(bool isUp) => isUp ? up : down;
|
||||
|
||||
/// 获取涨跌背景色(带透明度)
|
||||
static Color getChangeBackgroundColor(bool isUp) =>
|
||||
isUp ? up.withValues(alpha: 0.15) : down.withValues(alpha: 0.15);
|
||||
}
|
||||
|
||||
61
flutter_monisuo/lib/core/theme/app_color_scheme.dart
Normal file
61
flutter_monisuo/lib/core/theme/app_color_scheme.dart
Normal file
@@ -0,0 +1,61 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||
import '../constants/app_colors.dart';
|
||||
|
||||
/// 自定义品牌颜色方案 - 深色主题
|
||||
///
|
||||
/// 基于品牌色 #2563EB (专业蓝) 定制
|
||||
class AppShadColorScheme {
|
||||
AppShadColorScheme._();
|
||||
|
||||
/// 深色主题颜色
|
||||
static ShadColorScheme get dark => ShadColorScheme(
|
||||
// 背景与前景
|
||||
background: AppColors.background,
|
||||
foreground: AppColors.textPrimary,
|
||||
|
||||
// 卡片
|
||||
card: AppColors.cardBackground,
|
||||
cardForeground: AppColors.textPrimary,
|
||||
|
||||
// 弹出层
|
||||
popover: AppColors.surface,
|
||||
popoverForeground: AppColors.textPrimary,
|
||||
|
||||
// 主色
|
||||
primary: AppColors.primary,
|
||||
primaryForeground: Colors.white,
|
||||
|
||||
// 次要色
|
||||
secondary: const Color(0xFF252542),
|
||||
secondaryForeground: AppColors.textPrimary,
|
||||
|
||||
// 静音色
|
||||
muted: const Color(0xFF2A2A45),
|
||||
mutedForeground: AppColors.textSecondary,
|
||||
|
||||
// 强调色
|
||||
accent: AppColors.primary.withValues(alpha: 0.15),
|
||||
accentForeground: AppColors.primary,
|
||||
|
||||
// 危险色
|
||||
destructive: AppColors.error,
|
||||
destructiveForeground: Colors.white,
|
||||
|
||||
// 边框与输入
|
||||
border: AppColors.border,
|
||||
input: AppColors.inputBorder,
|
||||
ring: AppColors.primary,
|
||||
|
||||
// 选择色
|
||||
selection: AppColors.primary.withValues(alpha: 0.3),
|
||||
);
|
||||
}
|
||||
|
||||
/// 创建自定义 ShadThemeData
|
||||
ShadThemeData createAppShadTheme() {
|
||||
return ShadThemeData(
|
||||
brightness: Brightness.dark,
|
||||
colorScheme: AppShadColorScheme.dark,
|
||||
);
|
||||
}
|
||||
145
flutter_monisuo/lib/core/theme/app_colors.dart
Normal file
145
flutter_monisuo/lib/core/theme/app_colors.dart
Normal file
@@ -0,0 +1,145 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// 数字货币应用颜色系统
|
||||
///
|
||||
/// 设计原则:
|
||||
/// 1. 所有文字与背景对比度 >= 4.5:1 (WCAG AA)
|
||||
/// 2. 涨跌色使用国际通用标准 (绿涨红跌)
|
||||
/// 3. 背景色层次分明,易于区分
|
||||
/// 4. 杜绝文字和背景颜色一样无法区分的情况
|
||||
class AppColors {
|
||||
AppColors._();
|
||||
|
||||
// ============================================
|
||||
// 品牌色 (Brand Colors) - 专业蓝
|
||||
// ============================================
|
||||
|
||||
/// 主色 - 专业蓝,代表信任与稳定
|
||||
static const Color primary = Color(0xFF2563EB);
|
||||
static const Color primaryLight = Color(0xFF3B82F6);
|
||||
static const Color primaryDark = Color(0xFF1D4ED8);
|
||||
|
||||
/// 主色渐变 - 用于卡片、按钮等
|
||||
static const LinearGradient primaryGradient = LinearGradient(
|
||||
colors: [primary, primaryDark],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// 交易色 (Trading Colors)
|
||||
// ============================================
|
||||
|
||||
/// 涨/买入 - 标准绿色 (国际通用)
|
||||
static const Color up = Color(0xFF00C853);
|
||||
|
||||
/// 跌/卖出 - 标准红色 (国际通用)
|
||||
static const Color down = Color(0xFFFF5252);
|
||||
|
||||
/// 买入按钮渐变
|
||||
static const LinearGradient buyGradient = LinearGradient(
|
||||
colors: [Color(0xFF00C853), Color(0xFF00A844)],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
);
|
||||
|
||||
/// 卖出按钮渐变
|
||||
static const LinearGradient sellGradient = LinearGradient(
|
||||
colors: [Color(0xFFFF5252), Color(0xFFD32F2F)],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// 功能色 (Semantic Colors)
|
||||
// ============================================
|
||||
|
||||
/// 成功
|
||||
static const Color success = Color(0xFF00C853);
|
||||
|
||||
/// 警告
|
||||
static const Color warning = Color(0xFFFF9800);
|
||||
|
||||
/// 错误
|
||||
static const Color error = Color(0xFFFF5252);
|
||||
|
||||
/// 信息
|
||||
static const Color info = Color(0xFF2196F3);
|
||||
|
||||
/// 充值
|
||||
static const Color deposit = Color(0xFF00C853);
|
||||
|
||||
/// 提现
|
||||
static const Color withdraw = Color(0xFFFF9800);
|
||||
|
||||
/// 划转/交易
|
||||
static const Color trade = Color(0xFF2196F3);
|
||||
|
||||
// ============================================
|
||||
// 背景色 (Dark Theme Backgrounds)
|
||||
// ============================================
|
||||
|
||||
/// 页面背景 - 最深
|
||||
static const Color background = Color(0xFF0F0F1A);
|
||||
|
||||
/// 卡片背景 - 中等深度
|
||||
static const Color cardBackground = Color(0xFF1A1A2E);
|
||||
|
||||
/// 输入框背景 - 稍浅
|
||||
static const Color inputBackground = Color(0xFF16213E);
|
||||
|
||||
/// Scaffold 背景 (兼容旧代码)
|
||||
static const Color scaffoldBackground = Color(0xFF0F0F1A);
|
||||
|
||||
/// 模态框背景
|
||||
static const Color modalBackground = Color(0xFF1E1E32);
|
||||
|
||||
// ============================================
|
||||
// 文字颜色 (Text Colors)
|
||||
// ============================================
|
||||
|
||||
/// 主要文字 - 白色,对比度 21:1
|
||||
static const Color textPrimary = Color(0xFFFFFFFF);
|
||||
|
||||
/// 次要文字 - 浅灰蓝,对比度约 8:1
|
||||
static const Color textSecondary = Color(0xFFB0B0C0);
|
||||
|
||||
/// 提示文字 - 中灰,对比度约 4.7:1
|
||||
static const Color textHint = Color(0xFF6B6B80);
|
||||
|
||||
/// 禁用文字 - 暗灰
|
||||
static const Color textDisabled = Color(0xFF4A4A5A);
|
||||
|
||||
/// 链接文字 - 品牌蓝
|
||||
static const Color textLink = Color(0xFF2563EB);
|
||||
|
||||
// ============================================
|
||||
// 边框与分割线 (Borders & Dividers)
|
||||
// ============================================
|
||||
|
||||
/// 边框 - 低透明度白色
|
||||
static const Color border = Color(0x14FFFFFF); // 8% white
|
||||
|
||||
/// 分割线 - 更低透明度
|
||||
static const Color divider = Color(0x0FFFFFFF); // 6% white
|
||||
|
||||
/// 输入框边框
|
||||
static const Color inputBorder = Color(0x1AFFFFFF); // 10% white
|
||||
|
||||
/// 输入框聚焦边框 - 品牌蓝
|
||||
static const Color inputFocusBorder = Color(0xFF2563EB);
|
||||
|
||||
// ============================================
|
||||
// 便捷方法
|
||||
// ============================================
|
||||
|
||||
/// 根据涨跌获取颜色
|
||||
static Color getChangeColor(bool isUp) => isUp ? up : down;
|
||||
|
||||
/// 获取带透明度的涨跌背景色
|
||||
static Color getChangeBackgroundColor(bool isUp) =>
|
||||
isUp ? up.withOpacity(0.15) : down.withOpacity(0.15);
|
||||
|
||||
/// 渐变色 (兼容旧代码) - 品牌蓝
|
||||
static const List<Color> gradientColors = [Color(0xFF2563EB), Color(0xFF1D4ED8)];
|
||||
}
|
||||
179
flutter_monisuo/lib/core/theme/app_spacing.dart
Normal file
179
flutter_monisuo/lib/core/theme/app_spacing.dart
Normal file
@@ -0,0 +1,179 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// 间距系统
|
||||
///
|
||||
/// 使用 4px 基础单位,确保一致性
|
||||
class AppSpacing {
|
||||
AppSpacing._();
|
||||
|
||||
// ============================================
|
||||
// 基础间距 (Base Spacing)
|
||||
// ============================================
|
||||
|
||||
/// 极小 - 4px
|
||||
static const double xs = 4.0;
|
||||
|
||||
/// 小 - 8px
|
||||
static const double sm = 8.0;
|
||||
|
||||
/// 中 - 16px (默认)
|
||||
static const double md = 16.0;
|
||||
|
||||
/// 大 - 24px
|
||||
static const double lg = 24.0;
|
||||
|
||||
/// 特大 - 32px
|
||||
static const double xl = 32.0;
|
||||
|
||||
/// 超大 - 48px
|
||||
static const double xxl = 48.0;
|
||||
|
||||
// ============================================
|
||||
// 预设 EdgeInsets
|
||||
// ============================================
|
||||
|
||||
/// 页面内边距
|
||||
static const EdgeInsets pagePadding = EdgeInsets.all(md);
|
||||
|
||||
/// 卡片内边距
|
||||
static const EdgeInsets cardPadding = EdgeInsets.all(md);
|
||||
|
||||
/// 列表项内边距
|
||||
static const EdgeInsets listItemPadding = EdgeInsets.symmetric(
|
||||
horizontal: md,
|
||||
vertical: sm,
|
||||
);
|
||||
|
||||
/// 按钮内边距
|
||||
static const EdgeInsets buttonPadding = EdgeInsets.symmetric(
|
||||
horizontal: lg,
|
||||
vertical: 14,
|
||||
);
|
||||
|
||||
/// 输入框内边距
|
||||
static const EdgeInsets inputPadding = EdgeInsets.symmetric(
|
||||
horizontal: md,
|
||||
vertical: 14,
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// 便捷方法
|
||||
// ============================================
|
||||
|
||||
/// 获取水平间距
|
||||
static SizedBox horizontal(double spacing) => SizedBox(width: spacing);
|
||||
|
||||
/// 获取垂直间距
|
||||
static SizedBox vertical(double spacing) => SizedBox(height: spacing);
|
||||
}
|
||||
|
||||
/// 圆角系统
|
||||
class AppRadius {
|
||||
AppRadius._();
|
||||
|
||||
// ============================================
|
||||
// 基础圆角 (Base Radius)
|
||||
// ============================================
|
||||
|
||||
/// 小圆角 - 6px (标签、小组件)
|
||||
static const double sm = 6.0;
|
||||
|
||||
/// 中圆角 - 10px (按钮、输入框)
|
||||
static const double md = 10.0;
|
||||
|
||||
/// 大圆角 - 14px (卡片)
|
||||
static const double lg = 14.0;
|
||||
|
||||
/// 特大圆角 - 20px (大卡片、模态框)
|
||||
static const double xl = 20.0;
|
||||
|
||||
/// 圆形 - 999px
|
||||
static const double full = 999.0;
|
||||
|
||||
// ============================================
|
||||
// 预设 BorderRadius
|
||||
// ============================================
|
||||
|
||||
/// 小圆角
|
||||
static BorderRadius get radiusSm => BorderRadius.circular(sm);
|
||||
|
||||
/// 中圆角
|
||||
static BorderRadius get radiusMd => BorderRadius.circular(md);
|
||||
|
||||
/// 大圆角
|
||||
static BorderRadius get radiusLg => BorderRadius.circular(lg);
|
||||
|
||||
/// 特大圆角
|
||||
static BorderRadius get radiusXl => BorderRadius.circular(xl);
|
||||
|
||||
/// 圆形
|
||||
static BorderRadius get radiusFull => BorderRadius.circular(full);
|
||||
}
|
||||
|
||||
/// 响应式断点
|
||||
class AppBreakpoints {
|
||||
AppBreakpoints._();
|
||||
|
||||
/// 手机竖屏
|
||||
static const double mobile = 360;
|
||||
|
||||
/// 手机横屏/小平板
|
||||
static const double tablet = 768;
|
||||
|
||||
/// 平板/桌面
|
||||
static const double desktop = 1024;
|
||||
|
||||
/// 检查是否为手机
|
||||
static bool isMobile(BuildContext context) {
|
||||
return MediaQuery.of(context).size.width < tablet;
|
||||
}
|
||||
|
||||
/// 检查是否为平板
|
||||
static bool isTablet(BuildContext context) {
|
||||
final width = MediaQuery.of(context).size.width;
|
||||
return width >= tablet && width < desktop;
|
||||
}
|
||||
|
||||
/// 检查是否为桌面
|
||||
static bool isDesktop(BuildContext context) {
|
||||
return MediaQuery.of(context).size.width >= desktop;
|
||||
}
|
||||
|
||||
/// 根据屏幕宽度获取响应式值
|
||||
static T responsive<T>(
|
||||
BuildContext context, {
|
||||
required T mobile,
|
||||
T? tablet,
|
||||
T? desktop,
|
||||
}) {
|
||||
final width = MediaQuery.of(context).size.width;
|
||||
if (width >= AppBreakpoints.desktop) {
|
||||
return desktop ?? tablet ?? mobile;
|
||||
} else if (width >= AppBreakpoints.tablet) {
|
||||
return tablet ?? mobile;
|
||||
}
|
||||
return mobile;
|
||||
}
|
||||
}
|
||||
|
||||
/// 触摸目标尺寸
|
||||
class AppTouchTarget {
|
||||
AppTouchTarget._();
|
||||
|
||||
/// 最小触摸目标 - 44x44 (iOS HIG 标准)
|
||||
static const double minSize = 44.0;
|
||||
|
||||
/// 确保触摸目标足够大
|
||||
static Widget ensureMinSize({
|
||||
required Widget child,
|
||||
double minSize = AppTouchTarget.minSize,
|
||||
}) {
|
||||
return ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
minWidth: minSize,
|
||||
minHeight: minSize,
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
171
flutter_monisuo/lib/core/theme/app_text_styles.dart
Normal file
171
flutter_monisuo/lib/core/theme/app_text_styles.dart
Normal file
@@ -0,0 +1,171 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'app_colors.dart';
|
||||
|
||||
/// 文字样式系统
|
||||
///
|
||||
/// 统一管理所有文字样式,确保一致性
|
||||
/// 所有样式默认使用 textPrimary 颜色,保证对比度
|
||||
class AppTextStyles {
|
||||
AppTextStyles._();
|
||||
|
||||
// ============================================
|
||||
// 标题样式 (Headings)
|
||||
// ============================================
|
||||
|
||||
/// H1 - 页面大标题
|
||||
static const TextStyle h1 = TextStyle(
|
||||
fontSize: 28,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColors.textPrimary,
|
||||
height: 1.3,
|
||||
);
|
||||
|
||||
/// H2 - 区块标题
|
||||
static const TextStyle h2 = TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColors.textPrimary,
|
||||
height: 1.3,
|
||||
);
|
||||
|
||||
/// H3 - 卡片标题
|
||||
static const TextStyle h3 = TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.textPrimary,
|
||||
height: 1.4,
|
||||
);
|
||||
|
||||
/// H4 - 小标题
|
||||
static const TextStyle h4 = TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.textPrimary,
|
||||
height: 1.4,
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// 正文样式 (Body)
|
||||
// ============================================
|
||||
|
||||
/// Body1 - 主要正文
|
||||
static const TextStyle body1 = TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: AppColors.textPrimary,
|
||||
height: 1.5,
|
||||
);
|
||||
|
||||
/// Body2 - 次要正文
|
||||
static const TextStyle body2 = TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: AppColors.textPrimary,
|
||||
height: 1.5,
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// 辅助文字 (Caption & Small)
|
||||
// ============================================
|
||||
|
||||
/// Caption - 说明文字
|
||||
static const TextStyle caption = TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: AppColors.textSecondary,
|
||||
height: 1.4,
|
||||
);
|
||||
|
||||
/// Small - 极小文字
|
||||
static const TextStyle small = TextStyle(
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: AppColors.textSecondary,
|
||||
height: 1.3,
|
||||
);
|
||||
|
||||
/// Hint - 提示文字
|
||||
static const TextStyle hint = TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: AppColors.textHint,
|
||||
height: 1.4,
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// 特殊样式 (Special)
|
||||
// ============================================
|
||||
|
||||
/// 金额/价格 - 大号数字
|
||||
static const TextStyle amount = TextStyle(
|
||||
fontSize: 32,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColors.textPrimary,
|
||||
height: 1.2,
|
||||
fontFeatures: [FontFeature.tabularFigures()],
|
||||
);
|
||||
|
||||
/// 价格 - 标准数字
|
||||
static const TextStyle price = TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.textPrimary,
|
||||
height: 1.3,
|
||||
fontFeatures: [FontFeature.tabularFigures()],
|
||||
);
|
||||
|
||||
/// 价格变化 - 涨跌幅
|
||||
static const TextStyle priceChange = TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
height: 1.3,
|
||||
fontFeatures: [FontFeature.tabularFigures()],
|
||||
);
|
||||
|
||||
/// 按钮文字
|
||||
static const TextStyle button = TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.textPrimary,
|
||||
height: 1.2,
|
||||
);
|
||||
|
||||
/// 链接文字
|
||||
static const TextStyle link = TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColors.textLink,
|
||||
decoration: TextDecoration.underline,
|
||||
height: 1.4,
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// 可复制修改的样式方法
|
||||
// ============================================
|
||||
|
||||
/// 获取带颜色的标题样式
|
||||
static TextStyle headingWithColor(TextStyle style, Color color) {
|
||||
return style.copyWith(color: color);
|
||||
}
|
||||
|
||||
/// 获取带颜色的正文样式
|
||||
static TextStyle bodyWithColor(TextStyle style, Color color) {
|
||||
return style.copyWith(color: color);
|
||||
}
|
||||
|
||||
/// 获取粗体样式
|
||||
static TextStyle bold(TextStyle style) {
|
||||
return style.copyWith(fontWeight: FontWeight.bold);
|
||||
}
|
||||
|
||||
/// 获取半粗体样式
|
||||
static TextStyle semiBold(TextStyle style) {
|
||||
return style.copyWith(fontWeight: FontWeight.w600);
|
||||
}
|
||||
}
|
||||
|
||||
/// 兼容旧代码的别名
|
||||
@Deprecated('Use AppTextStyles instead')
|
||||
class AppText {
|
||||
AppText._();
|
||||
}
|
||||
@@ -104,6 +104,12 @@ class AppTextStyles {
|
||||
color: AppColors.textPrimary,
|
||||
);
|
||||
|
||||
static const TextStyle heading4 = TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.textPrimary,
|
||||
);
|
||||
|
||||
static const TextStyle body1 = TextStyle(
|
||||
fontSize: 16,
|
||||
color: AppColors.textPrimary,
|
||||
@@ -123,6 +129,26 @@ class AppTextStyles {
|
||||
fontSize: 14,
|
||||
color: AppColors.textHint,
|
||||
);
|
||||
|
||||
/// 价格样式 - 用于显示价格、金额
|
||||
static const TextStyle price = TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppColors.textPrimary,
|
||||
);
|
||||
|
||||
/// 涨跌幅样式
|
||||
static const TextStyle change = TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
);
|
||||
|
||||
/// 数字样式 - 用于显示数量
|
||||
static const TextStyle number = TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColors.textPrimary,
|
||||
);
|
||||
}
|
||||
|
||||
/// 间距常量
|
||||
@@ -135,6 +161,21 @@ class AppSpacing {
|
||||
static const double lg = 24.0;
|
||||
static const double xl = 32.0;
|
||||
static const double xxl = 48.0;
|
||||
|
||||
/// 页面水平内边距
|
||||
static const double pageHorizontal = 16.0;
|
||||
|
||||
/// 页面垂直内边距
|
||||
static const double pageVertical = 16.0;
|
||||
|
||||
/// 卡片内边距
|
||||
static const double cardPadding = 16.0;
|
||||
|
||||
/// 列表项间距
|
||||
static const double listItemSpacing = 8.0;
|
||||
|
||||
/// 表单字段间距
|
||||
static const double formFieldSpacing = 12.0;
|
||||
}
|
||||
|
||||
/// 圆角常量
|
||||
@@ -146,4 +187,77 @@ class AppRadius {
|
||||
static const double lg = 16.0;
|
||||
static const double xl = 24.0;
|
||||
static const double full = 999.0;
|
||||
|
||||
/// 卡片圆角
|
||||
static const double card = lg;
|
||||
|
||||
/// 按钮圆角
|
||||
static const double button = md;
|
||||
|
||||
/// 输入框圆角
|
||||
static const double input = md;
|
||||
|
||||
/// 标签圆角
|
||||
static const double badge = sm;
|
||||
}
|
||||
|
||||
/// 响应式断点
|
||||
class AppBreakpoints {
|
||||
AppBreakpoints._();
|
||||
|
||||
/// 手机
|
||||
static const double mobile = 600;
|
||||
|
||||
/// 平板
|
||||
static const double tablet = 900;
|
||||
|
||||
/// 桌面
|
||||
static const double desktop = 1200;
|
||||
|
||||
/// 判断是否为手机
|
||||
static bool isMobile(BuildContext context) =>
|
||||
MediaQuery.of(context).size.width < mobile;
|
||||
|
||||
/// 判断是否为平板
|
||||
static bool isTablet(BuildContext context) {
|
||||
final width = MediaQuery.of(context).size.width;
|
||||
return width >= mobile && width < tablet;
|
||||
}
|
||||
|
||||
/// 判断是否为桌面
|
||||
static bool isDesktop(BuildContext context) =>
|
||||
MediaQuery.of(context).size.width >= tablet;
|
||||
}
|
||||
|
||||
/// 响应式工具
|
||||
class Responsive {
|
||||
Responsive._();
|
||||
|
||||
/// 根据屏幕宽度返回响应式值
|
||||
static T value<T>(
|
||||
BuildContext context, {
|
||||
required T mobile,
|
||||
T? tablet,
|
||||
T? desktop,
|
||||
}) {
|
||||
final width = MediaQuery.of(context).size.width;
|
||||
|
||||
if (width >= AppBreakpoints.tablet && desktop != null) {
|
||||
return desktop;
|
||||
}
|
||||
if (width >= AppBreakpoints.mobile && tablet != null) {
|
||||
return tablet;
|
||||
}
|
||||
return mobile;
|
||||
}
|
||||
|
||||
/// 响应式字体大小
|
||||
static double fontSize(BuildContext context, double base) {
|
||||
return value(context, mobile: base, tablet: base * 1.1, desktop: base * 1.2);
|
||||
}
|
||||
|
||||
/// 响应式间距
|
||||
static double spacing(BuildContext context, double base) {
|
||||
return value(context, mobile: base, tablet: base * 1.2, desktop: base * 1.5);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import 'core/network/dio_client.dart';
|
||||
import 'core/storage/local_storage.dart';
|
||||
import 'core/theme/app_color_scheme.dart';
|
||||
import 'data/services/user_service.dart';
|
||||
import 'data/services/market_service.dart';
|
||||
import 'data/services/trade_service.dart';
|
||||
@@ -38,10 +39,7 @@ class MyApp extends StatelessWidget {
|
||||
child: AuthNavigator(
|
||||
child: ShadApp.custom(
|
||||
themeMode: ThemeMode.dark,
|
||||
darkTheme: ShadThemeData(
|
||||
brightness: Brightness.dark,
|
||||
colorScheme: const ShadSlateColorScheme.dark(),
|
||||
),
|
||||
darkTheme: createAppShadTheme(),
|
||||
appBuilder: _buildMaterialApp,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||
import 'package:flutter_animate/flutter_animate.dart';
|
||||
import '../../core/theme/app_colors.dart';
|
||||
|
||||
/// 资产卡片组件 - 用于显示资产总览
|
||||
class AssetCard extends StatelessWidget {
|
||||
@@ -13,9 +13,9 @@ class AssetCard extends StatelessWidget {
|
||||
final Gradient? gradient;
|
||||
final VoidCallback? onTap;
|
||||
|
||||
// 默认渐变色
|
||||
// 默认渐变色 - 使用品牌蓝
|
||||
static const defaultGradient = LinearGradient(
|
||||
colors: [Color(0xFF00D4AA), Color(0xFF00B894)],
|
||||
colors: [Color(0xFF2563EB), Color(0xFF1D4ED8)],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||
import '../../core/constants/app_colors.dart';
|
||||
|
||||
/// 币种卡片组件 - 用于显示币种信息
|
||||
class CoinCard extends StatelessWidget {
|
||||
@@ -11,10 +12,6 @@ class CoinCard extends StatelessWidget {
|
||||
final String? icon;
|
||||
final VoidCallback? onTap;
|
||||
|
||||
// 颜色常量
|
||||
static const upColor = Color(0xFF00C853);
|
||||
static const downColor = Color(0xFFFF5252);
|
||||
|
||||
const CoinCard({
|
||||
super.key,
|
||||
required this.code,
|
||||
@@ -78,13 +75,13 @@ class CoinCard extends StatelessWidget {
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
color: isUp ? upColor.withOpacity(0.2) : downColor.withOpacity(0.2),
|
||||
color: AppColors.getChangeBackgroundColor(isUp),
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
child: Text(
|
||||
change,
|
||||
style: TextStyle(
|
||||
color: isUp ? upColor : downColor,
|
||||
color: AppColors.getChangeColor(isUp),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../../../core/constants/app_colors.dart';
|
||||
import '../../../providers/asset_provider.dart';
|
||||
import '../../shared/ui_constants.dart';
|
||||
import '../orders/fund_orders_page.dart';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../../../core/constants/app_colors.dart';
|
||||
import '../../../providers/asset_provider.dart';
|
||||
import '../../../providers/auth_provider.dart';
|
||||
import '../../shared/ui_constants.dart';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../../../core/constants/app_colors.dart';
|
||||
import '../../../data/models/coin.dart';
|
||||
import '../../../providers/market_provider.dart';
|
||||
|
||||
@@ -97,7 +98,7 @@ class _MarketPageState extends State<MarketPage> with AutomaticKeepAliveClientMi
|
||||
|
||||
return Container(
|
||||
height: 44,
|
||||
margin: const EdgeInsets.symmetric(horizontal: 16),
|
||||
margin: const EdgeInsets.fromLTRB(16, 0, 16, 16),
|
||||
child: Row(
|
||||
children: tabs.asMap().entries.map((entry) {
|
||||
final index = entry.key;
|
||||
@@ -192,7 +193,7 @@ class _MarketPageState extends State<MarketPage> with AutomaticKeepAliveClientMi
|
||||
onRefresh: provider.refresh,
|
||||
color: theme.colorScheme.primary,
|
||||
child: ListView.builder(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
|
||||
itemCount: coins.length,
|
||||
itemBuilder: (context, index) => _buildCoinItem(coins[index]),
|
||||
),
|
||||
@@ -201,8 +202,6 @@ class _MarketPageState extends State<MarketPage> with AutomaticKeepAliveClientMi
|
||||
|
||||
Widget _buildCoinItem(Coin coin) {
|
||||
final theme = ShadTheme.of(context);
|
||||
final upColor = const Color(0xFF00C853);
|
||||
final downColor = const Color(0xFFFF5252);
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8),
|
||||
@@ -245,13 +244,13 @@ class _MarketPageState extends State<MarketPage> with AutomaticKeepAliveClientMi
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
color: coin.isUp ? upColor.withValues(alpha: 0.2) : downColor.withValues(alpha: 0.2),
|
||||
color: AppColors.getChangeBackgroundColor(coin.isUp),
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
child: Text(
|
||||
coin.formattedChange,
|
||||
style: TextStyle(
|
||||
color: coin.isUp ? upColor : downColor,
|
||||
color: AppColors.getChangeColor(coin.isUp),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../../../core/constants/app_colors.dart';
|
||||
import '../../../data/models/coin.dart';
|
||||
import '../../../providers/market_provider.dart';
|
||||
import '../../../providers/asset_provider.dart';
|
||||
|
||||
@@ -1,25 +1,21 @@
|
||||
import 'package:flutter/material.dart';
|
||||
/// UI 常量整合导出
|
||||
///
|
||||
/// 统一导出所有设计 token,方便使用
|
||||
/// 使用方式: import 'ui/shared/ui_constants.dart';
|
||||
|
||||
/// 应用颜色常量
|
||||
class AppColors {
|
||||
AppColors._();
|
||||
// 导出颜色系统
|
||||
export '../../core/constants/app_colors.dart';
|
||||
|
||||
static const Color up = Color(0xFF00C853);
|
||||
static const Color down = Color(0xFFFF5252);
|
||||
static const Color deposit = Color(0xFF00C853);
|
||||
static const Color withdraw = Color(0xFFFF9800);
|
||||
static const Color trade = Color(0xFF2196F3);
|
||||
|
||||
static const List<Color> gradientColors = [
|
||||
Color(0xFF00D4AA),
|
||||
Color(0xFF00B894),
|
||||
];
|
||||
}
|
||||
// 导出主题配置 (包含 AppTextStyles, AppSpacing, AppRadius, AppBreakpoints)
|
||||
export '../../core/theme/app_theme.dart';
|
||||
|
||||
/// 表单验证器
|
||||
///
|
||||
/// 提供常用的表单验证方法
|
||||
class Validators {
|
||||
Validators._();
|
||||
|
||||
/// 金额验证
|
||||
static String? amount(String? value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return '请输入金额';
|
||||
@@ -31,6 +27,7 @@ class Validators {
|
||||
return null;
|
||||
}
|
||||
|
||||
/// 价格验证
|
||||
static String? price(String? value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return '请输入价格';
|
||||
@@ -42,6 +39,7 @@ class Validators {
|
||||
return null;
|
||||
}
|
||||
|
||||
/// 数量验证
|
||||
static String? quantity(String? value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return '请输入数量';
|
||||
@@ -53,10 +51,45 @@ class Validators {
|
||||
return null;
|
||||
}
|
||||
|
||||
/// 必填字段验证
|
||||
static String? required(String? value, String fieldName) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return '请输入$fieldName';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// 用户名验证
|
||||
static String? username(String? value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return '请输入用户名';
|
||||
}
|
||||
if (value.length < 3) {
|
||||
return '用户名至少 3 个字符';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// 密码验证
|
||||
static String? password(String? value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return '请输入密码';
|
||||
}
|
||||
if (value.length < 6) {
|
||||
return '密码至少 6 个字符';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// 邮箱验证
|
||||
static String? email(String? value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return '请输入邮箱';
|
||||
}
|
||||
final emailRegex = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$');
|
||||
if (!emailRegex.hasMatch(value)) {
|
||||
return '请输入有效的邮箱地址';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user