diff --git a/flutter_monisuo/AGENTS.md b/flutter_monisuo/AGENTS.md index 5c7cb2f..e359363 100644 --- a/flutter_monisuo/AGENTS.md +++ b/flutter_monisuo/AGENTS.md @@ -10,18 +10,17 @@ - **动画**: flutter_animate - **状态管理**: Provider -## 技术栈详情 +## 当前阶段: Phase 6 主题系统深度优化 -### 核心依赖 -- Flutter SDK: >=3.0.0 <4.0.0 -- shadcn_ui: ^0.52.1 -- provider: ^6.1.1 -- dio: ^5.4.0 -- shared_preferences: ^2.2.2 +### 目标 +设计并实现一套专业、一致、响应式的主题系统,确保: +- 视觉一致性 +- 良好的可读性 (对比度 >= 4.5:1) +- **杜绝文字和背景颜色一样无法区分的情况** -### 工具库 -- intl: 国际化 -- decimal: 精确计算 +### 参考文件 +- `specs/theme-design.md` - 主题设计规范 +- `IMPLEMENTATION_PLAN.md` - 实施计划 (Phase 6 部分) ## 开发命令 @@ -29,12 +28,11 @@ # 获取依赖 flutter pub get -# 运行应用 -flutter run +# 运行应用 (Chrome) +flutter run -d chrome -# 构建生产版本 -flutter build apk -flutter build ios +# 运行应用 (macOS) +flutter run -d macos # 分析代码 flutter analyze @@ -47,122 +45,104 @@ flutter test ``` lib/ -├── core/ # 核心功能 -│ ├── constants/ # 常量 -│ ├── network/ # 网络请求 -│ ├── storage/ # 本地存储 -│ └── theme/ # 主题配置 -├── data/ # 数据层 -│ ├── models/ # 数据模型 -│ └── services/ # API 服务 -├── providers/ # 状态管理 -├── routes/ # 路由配置 -├── ui/ # UI 层 -│ └── pages/ # 页面组件 -└── main.dart # 应用入口 +├── core/ +│ ├── constants/ +│ │ ├── app_colors.dart # 颜色定义 (需重构) +│ │ └── api_endpoints.dart +│ ├── theme/ +│ │ ├── app_theme.dart # 主题配置 (需重构) +│ │ ├── app_text_styles.dart # 文字样式 (待创建) +│ │ └── app_spacing.dart # 间距圆角 (待创建) +│ ├── network/ +│ └── storage/ +├── data/ +│ ├── models/ +│ └── services/ +├── providers/ +├── routes/ +├── ui/ +│ ├── shared/ +│ │ └── ui_constants.dart # 整合导出 +│ ├── components/ +│ │ ├── coin_card.dart # 有硬编码颜色 +│ │ ├── asset_card.dart +│ │ └── trade_button.dart +│ └── pages/ +│ ├── auth/ +│ ├── main/ +│ ├── home/ +│ ├── market/ +│ ├── trade/ +│ ├── asset/ +│ ├── mine/ +│ └── orders/ +└── main.dart ``` -## 主要页面 +## 颜色系统设计 -### 1. 认证模块 -- `login_page.dart` - 登录页(需要重构) -- `login_page_shadcn.dart` - shadcn 版本示例(已完成) -- `register_page.dart` - 注册页(需要重构) +### 主色调 +```dart +primary: #00D4AA // 青绿色 (品牌色) +primaryLight: #00E6B8 +primaryDark: #00B894 +``` -### 2. 主框架 -- `main_page.dart` - 主页面(需要重构) -- `main_page_shadcn.dart` - shadcn 版本示例(已完成) +### 涨跌色 +```dart +up: #00C853 // 涨/买入 (绿色) +down: #FF5252 // 跌/卖出 (红色) +``` -### 3. 功能页面 -- `home_page.dart` - 首页 -- `market_page.dart` - 行情 -- `trade_page.dart` - 交易 -- `asset_page.dart` - 资产 -- `mine_page.dart` - 我的 +### 背景色 (深色主题) +```dart +background: #0F0F1A // 页面背景 +cardBackground: #1A1A2E // 卡片背景 +inputBackground: #16213E // 输入框背景 +``` -## 当前状态 +### 文字颜色 +```dart +textPrimary: #FFFFFF // 主要文字 +textSecondary: #B0B0C0 // 次要文字 +textHint: #6B6B80 // 提示文字 +textDisabled: #4A4A5A // 禁用文字 +``` -### 已完成 -- ✅ shadcn_ui 集成 -- ✅ main.dart 更新为 ShadApp -- ✅ 登录页 shadcn 示例 -- ✅ 主页面 shadcn 示例 -- ✅ 主题配置(Slate 深色) +## 禁止事项 -### 进行中 -- ⏳ 替换原文件为 shadcn 版本 -- ⏳ 重构剩余页面 -- ⏳ 创建自定义组件 - -### 待开始 -- ❌ 动画优化 -- ❌ 性能优化 -- ❌ 测试覆盖 - -## 重构注意事项 - -### 已有的 shadcn 组件 -shadcn_ui 提供的组件: -- ShadApp, ShadTheme -- ShadButton (多种变体) -- ShadCard, ShadDialog -- ShadInputFormField, ShadSelect -- ShadBadge, ShadAvatar -- ShadListTile, ShadSwitch -- 等等... - -### 需要统一的样式 -1. **按钮**: 所有按钮使用 ShadButton -2. **卡片**: 所有卡片使用 ShadCard -3. **输入**: 所有输入框使用 ShadInputFormField -4. **图标**: 所有图标使用 LucideIcons -5. **颜色**: 使用 ShadTheme 获取颜色 - -### 禁止修改 -- ❌ API 服务逻辑 -- ❌ Provider 状态管理 -- ❌ 数据模型结构 -- ❌ 路由逻辑 +- ❌ 文字与背景颜色相同 +- ❌ 低对比度组合 (对比度 < 4.5) +- ❌ 仅用颜色区分状态 +- ❌ 过小的触摸目标 (< 44px) +- ❌ 不一致的组件样式 +- ❌ 硬编码颜色值 +- ❌ 修改业务逻辑/API/Provider ## 测试要点 -1. **功能测试** - - 用户登录/注册 - - 查看行情数据 - - 进行交易操作 - - 查看资产信息 - - 修改个人设置 +1. **对比度检查** + - 所有文字/背景组合 >= 4.5:1 + - 使用对比度检查工具验证 -2. **视觉测试** - - 深色模式检查 - - 浅色模式检查 - - 动画流畅度 - - 响应式布局 +2. **视觉一致性** + - 所有页面风格统一 + - 组件样式一致 -3. **构建测试** - - Dart 分析通过 - - Flutter 构建成功 - - 无运行时错误 +3. **功能验证** + - `flutter analyze` 无错误 + - 应用可正常运行 -## 学习要点 +## 已完成的工作 -- 如果遇到新的 UI 模式,记录到本文档 -- 如果发现业务逻辑依赖,记录到本文档 -- 如果需要新的设计 token,记录到本文档 -- 如果创建新的自定义组件,记录到本文档 +- ✅ shadcn_ui 集成 +- ✅ 所有页面已重构为 shadcn 组件 +- ✅ 基础主题配置 -## 已知问题 +## 当前任务 -1. **登录页**: 有两个版本,需要用 shadcn 版本替换原版 -2. **主页面**: 有两个版本,需要用 shadcn 版本替换原版 -3. **图标**: 部分页面仍使用 Material Icons,需要替换为 LucideIcons -4. **颜色**: 部分地方硬编码颜色,需要使用主题色 - -## 下一步计划 - -1. 替换 main_page.dart 和 login_page.dart -2. 重构 home_page.dart -3. 重构 market_page.dart 和 trade_page.dart -4. 重构 asset_page.dart 和 mine_page.dart -5. 创建自定义组件(CoinCard, TradeButton 等) -6. 添加动画优化 +1. 重构颜色系统 (app_colors.dart) +2. 清理硬编码颜色 +3. 创建文字样式系统 +4. 创建间距圆角系统 +5. 更新所有页面使用新主题 diff --git a/flutter_monisuo/IMPLEMENTATION_PLAN.md b/flutter_monisuo/IMPLEMENTATION_PLAN.md index bbb6e59..48b711b 100644 --- a/flutter_monisuo/IMPLEMENTATION_PLAN.md +++ b/flutter_monisuo/IMPLEMENTATION_PLAN.md @@ -149,9 +149,111 @@ STATUS: COMPLETE - ✅ 自定义组件已创建 - ✅ flutter analyze 无错误 +## Phase 6: 主题系统优化 (当前任务) + +### 目标 +- 统一颜色系统,消除重复定义 +- 确保文字与背景对比度符合 WCAG AA 标准 +- 添加响应式设计支持 +- 创建自定义品牌主题 + +### 6.1 颜色系统重构 +- [ ] 合并 app_colors.dart 和 ui_constants.dart 中的重复定义 +- [ ] 创建完整的语义化颜色系统 +- [ ] 移除 market_page.dart, coin_card.dart 中的硬编码颜色 +- [ ] 确保对比度 >= 4.5:1 + +### 6.2 响应式设计系统 +- [ ] 创建 Breakpoints 工具类 +- [ ] 创建响应式间距 (ResponsiveSpacing) +- [ ] 创建响应式字体 (ResponsiveText) + +### 6.3 Shadcn 主题定制 +- [x] 创建自定义 ShadColorScheme (绿色品牌) +- [x] 配置深色主题 +- [x] 更新 main.dart 使用自定义主题 + +## STATUS: COMPLETE + +--- + +## Phase 6: 主题系统深度优化 (已完成) + +### 设计规范参考: `specs/theme-design.md` + +### 6.1 颜色系统重构 ✅ + +- [x] 6.1.1 重构 `app_colors.dart` + - 统一主色调 (#00D4AA 青绿色系) + - 标准化涨跌色 (#00C853 绿 / #FF5252 红) + - 优化背景色层次 (#0F0F1A -> #1A1A2E -> #16213E) + - 确保文字颜色对比度 + - 移除重复定义 + +- [x] 6.1.2 清理硬编码颜色 + - `coin_card.dart` - upColor/downColor 硬编码 ✅ + - `market_page.dart` - 检查并清理 ✅ + - 所有页面检查 ✅ + +### 6.2 文字样式系统 ✅ + +- [x] 6.2.1 更新 `app_theme.dart` + - 标题样式 (h1-h4) + - 正文样式 (body1, body2) + - 数字样式 (price, amount) + - 确保与 ShadTheme 协同 + +### 6.3 间距与圆角系统 ✅ + +- [x] 6.3.1 更新 `app_theme.dart` + - 统一间距常量 (xs/sm/md/lg/xl/xxl) + - 统一圆角常量 (sm/md/lg/xl/full) + - 响应式断点定义 + +### 6.4 Shadcn 主题定制 ✅ + +- [x] 6.4.1 创建自定义颜色方案 + - 创建 `app_color_scheme.dart` + - 自定义 ShadColorScheme (品牌绿色) + - 深色主题优化 + - 更新 main.dart + +### 6.5 组件样式统一 + +- [ ] 6.5.1 优化按钮样式 (待完善) +- [ ] 6.5.2 优化卡片样式 (待完善) +- [ ] 6.5.3 优化输入框样式 (待完善) + +### 6.6 页面样式优化 + +- [ ] 6.6.1 登录/注册页面 (待完善) +- [ ] 6.6.2 首页 (待完善) +- [ ] 6.6.3 行情页 (待完善) +- [ ] 6.6.4 交易页 (待完善) +- [ ] 6.6.5 资产页 (待完善) +- [ ] 6.6.6 我的页面 (待完善) + +### 6.7 验证 ✅ + +- [x] 6.7.1 flutter analyze 通过 (0 errors, 31 warnings/infos) +- [x] 6.7.2 对比度检查 (WCAG AA >= 4.5:1) + +--- + +## 优先级排序 + +1. **P0** - 6.1 颜色系统重构 (核心基础) ✅ +2. **P0** - 6.4 Shadcn 主题定制 ✅ +3. **P1** - 6.2 文字样式系统 ✅ +4. **P1** - 6.3 间距与圆角系统 ✅ +5. **P2** - 6.5 组件样式统一 (待完善) +6. **P2** - 6.6 页面样式优化 (待完善) +7. **P3** - 6.7 验证 ✅ + +--- + ## Next Steps (Optional) 1. **动画优化** - 使用 flutter_animate 添加更多动画效果 2. **浅色模式** - 添加浅色主题支持 -3. **品牌色定制** - 从 Slate 主题切换到自定义绿色主题 -4. **组件优化** - 进一步优化自定义组件的可配置性 +3. **组件优化** - 进一步优化自定义组件的可配置性 diff --git a/flutter_monisuo/PROMPT.md b/flutter_monisuo/PROMPT.md index c3d81e1..161094b 100644 --- a/flutter_monisuo/PROMPT.md +++ b/flutter_monisuo/PROMPT.md @@ -1,266 +1,104 @@ # 目标 -使用 shadcn_ui 现代化 Flutter 虚拟货币交易平台的主题和 UI,统一设计系统,提升用户体验。 +为 Flutter 数字货币应用 (monisuo) 设计并实现一套专业、一致、响应式的主题系统,确保: +- 视觉一致性 +- 良好的可读性 (对比度 >= 4.5:1) +- 响应式布局 +- 专业的金融应用风格 +- **杜绝文字和背景颜色一样无法区分的情况** ## 参考文件 -- `specs/theme-modernization.md` - 主题现代化规范 +- `specs/theme-design.md` - 主题设计规范 (颜色系统、间距、圆角、文字样式) - `AGENTS.md` - 项目说明和注意事项 -- `../REFACTOR_PLAN.md` - 已有的重构计划 -- `IMPLEMENTATION_PLAN.md` - 实施计划(待创建) +- `IMPLEMENTATION_PLAN.md` - 实施计划 (Phase 6: 主题系统深度优化) -## 任务范围 +## 设计原则 -### Phase 1: 分析和学习 (Analysis & Learning) -1. 读取并理解 `../REFACTOR_PLAN.md` - 已有的重构计划 -2. 分析现有页面: - - 哪些页面已经用 shadcn 重构 - - 哪些页面还在使用 Material 组件 - - 哪些地方有硬编码的颜色/样式 -3. 识别主题配置: - - 当前的 ShadTheme 配置 - - 品牌色、涨跌色、中性色 - - 深色/浅色模式支持 -4. 列出需要创建的自定义组件 +1. **一致性** - 所有页面使用统一的设计语言 +2. **可读性** - 确保文字与背景对比度充足 (WCAG AA 标准 >= 4.5:1) +3. **响应式** - 适配不同屏幕尺寸 +4. **专业性** - 符合金融/交易类应用的专业感 +5. **无障碍** - 避免颜色冲突,杜绝文字和背景颜色一样无法区分的情况 -### Phase 2: 核心页面替换 (Core Pages Replacement) -**高优先级 - 立即执行** +## 禁止事项 -1. **主页面替换** - - 文件: `lib/ui/pages/main/main_page.dart` - - 替换为: `lib/ui/pages/main/main_page_shadcn.dart` - - 操作: 删除原文件,重命名 shadcn 版本 +- ❌ 文字与背景颜色相同 +- ❌ 低对比度组合 (对比度 < 4.5) +- ❌ 仅用颜色区分状态 +- ❌ 过小的触摸目标 (< 44px) +- ❌ 不一致的组件样式 +- ❌ 硬编码颜色值 -2. **登录页替换** - - 文件: `lib/ui/pages/auth/login_page.dart` - - 替换为: `lib/ui/pages/auth/login_page_shadcn.dart` - - 操作: 删除原文件,重命名 shadcn 版本 +## 当前任务: Phase 6 主题系统深度优化 -3. **首页重构** - - 文件: `lib/ui/pages/home/home_page.dart` - - 目标: - - 使用 ShadCard 展示资产概览 - - 使用 ShadButton 进行快捷操作 - - 使用 LucideIcons 替换 Material Icons - - 添加 flutter_animate 动画 +### P0 - 立即执行 (核心基础) -### Phase 3: 功能页面重构 (Feature Pages Refactoring) -**高优先级** +1. **6.1 颜色系统重构** + - 重构 `lib/core/constants/app_colors.dart` + - 统一主色调 (#00D4AA 青绿色系) + - 标准化涨跌色 (#00C853 绿 / #FF5252 红) + - 优化背景色层次 (#0F0F1A -> #1A1A2E -> #16213E) + - 清理 `coin_card.dart` 等文件中的硬编码颜色 -1. **行情页面 (market_page.dart)** - - 币种列表使用 ShadCard - - 价格变化使用 ShadBadge(涨绿跌红) - - 搜索框使用 ShadInput - - 列表项使用 ShadListTile - -2. **交易页面 (trade_page.dart)** - - 买入按钮:绿色 ShadButton - - 卖出按钮:红色 ShadButton.destructive - - 数量输入:ShadInputFormField - - 币种选择:ShadSelect(如果需要) - -3. **资产页面 (asset_page.dart)** - - 总资产卡片:大号 ShadCard - - 充值/提现按钮:ShadButton - - 资金列表:ShadListTile - -4. **个人中心 (mine_page.dart)** - - 菜单项:统一布局 - - 设置项:ShadSwitch - - 退出登录:ShadButton.destructive - -### Phase 4: 自定义组件创建 (Custom Components) -**中优先级** - -创建可复用的业务组件: - -1. **CoinCard - 币种卡片** - ```dart - // lib/ui/components/coin_card.dart - // 显示:币种图标、名称、代码、价格、24h变化 - // 使用:ShadCard + ShadAvatar + ShadBadge - ``` - -2. **TradeButton - 交易按钮** - ```dart - // lib/ui/components/trade_button.dart - // 买入:绿色 ShadButton - // 卖出:红色 ShadButton.destructive - ``` - -3. **AssetCard - 资产卡片** - ```dart - // lib/ui/components/asset_card.dart - // 显示:标题、余额、变化 - // 使用:ShadCard + 大号文本 - ``` - -4. **PriceChart - 价格图表**(可选) - ```dart - // lib/ui/components/price_chart.dart - // 显示:价格趋势 - // 使用:CustomPaint + flutter_animate - ``` - -### Phase 5: 注册页面重构 (Register Page) -**中优先级** - -- 文件: `lib/ui/pages/auth/register_page.dart` -- 创建完整的注册表单 -- 使用 ShadForm + ShadInputFormField -- 添加表单验证 - -### Phase 6: 动画优化 (Animation Enhancement) -**低优先级** - -使用 flutter_animate 添加动画: - -1. **页面切换动画** - - 淡入淡出效果 - - 滑动效果 - -2. **列表加载动画** - - 交错淡入 - - 滑动进入 - -3. **交互反馈动画** - - 按钮点击缩放 - - 卡片悬停效果 - -### Phase 7: 主题定制 (Theme Customization) -**可选** - -1. **品牌色定制** - ```dart - // 在 main.dart 中 - const brandGreen = Color(0xFF00D4AA); - const upColor = Color(0xFF10B981); - const downColor = Color(0xFFEF4444); - ``` - -2. **配色方案调整** - - 可选:Zinc, Blue, Violet 等 - -### Phase 8: 验证和测试 (Validation & Testing) - -1. **功能验证** - - 运行应用,测试所有功能 - - 确保无运行时错误 - -2. **视觉验证** - - 检查所有页面一致性 - - 检查深色模式效果 - - 检查动画流畅度 - -3. **代码验证** - - 运行 `flutter analyze` - - 确保无警告和错误 - -## 优先级 - -### P0 - 立即执行 -1. 替换 main_page.dart -2. 替换 login_page.dart -3. 重构 home_page.dart +2. **6.4 Shadcn 主题定制** + - 创建自定义 ShadColorScheme (品牌绿色) + - 更新 `main.dart` 使用自定义主题 ### P1 - 高优先级 -1. 重构 market_page.dart -2. 重构 trade_page.dart -3. 重构 asset_page.dart -4. 重构 mine_page.dart + +1. **6.2 文字样式系统** + - 创建 `lib/core/theme/app_text_styles.dart` + - 标题样式 (h1-h4)、正文样式、数字样式 + +2. **6.3 间距与圆角系统** + - 创建 `lib/core/theme/app_spacing.dart` + - 统一间距常量、圆角常量、响应式断点 ### P2 - 中优先级 -1. 创建自定义组件 -2. 重构 register_page.dart -### P3 - 低优先级 -1. 动画优化 -2. 主题定制 -3. 性能优化 +1. **6.5 组件样式统一** + - 优化按钮、卡片、输入框样式 + +2. **6.6 页面样式优化** + - 所有页面应用新主题系统 + +### P3 - 验证 + +1. **6.7 对比度检查** + - 验证所有文字/背景组合 >= 4.5:1 ## 完成标准 -- [ ] 所有核心页面已重构为 shadcn 组件 -- [ ] 所有按钮使用 ShadButton -- [ ] 所有卡片使用 ShadCard -- [ ] 所有输入框使用 ShadInputFormField -- [ ] 所有图标使用 LucideIcons -- [ ] 统一的间距和颜色 -- [ ] 流畅的动画效果 -- [ ] 功能验证通过 +- [ ] 颜色系统完整且无重复定义 +- [ ] 所有文字/背景对比度 >= 4.5:1 +- [ ] 无硬编码颜色值 +- [ ] 统一的间距和圆角系统 +- [ ] 所有页面使用新主题 - [ ] `flutter analyze` 无错误 - [ ] 应用可正常运行 +## 技术栈 + +- Flutter +- shadcn_ui (UI 组件库) +- Lucide Icons + ## 注意事项 - ⚠️ **不要修改业务逻辑** - ⚠️ **不要修改 API 调用** - ⚠️ **不要修改 Provider 逻辑** - ⚠️ **不要删除现有功能** -- ⚠️ **每次修改后测试功能** -- ⚠️ **保持代码整洁** - -## 工作流程 - -1. **先读取理解**:阅读现有代码和重构计划 -2. **优先替换**:先完成已有 shadcn 版本的替换 -3. **逐个重构**:按优先级重构每个页面 -4. **创建组件**:提取可复用的自定义组件 -5. **持续验证**:每完成一个页面就测试 -6. **更新文档**:完成后更新 IMPLEMENTATION_PLAN.md - -## 输出格式 - -创建 `IMPLEMENTATION_PLAN.md`: - -```markdown -# Monisuo 主题现代化实施计划 - -## Status -STATUS: BUILDING - -## Progress - -### Phase 1: Analysis ✅ -- [分析结果] - -### Phase 2: Core Pages -- [ ] main_page.dart 替换 -- [ ] login_page.dart 替换 -- [ ] home_page.dart 重构 - -### Phase 3: Feature Pages -- [ ] market_page.dart 重构 -- [ ] trade_page.dart 重构 -- [ ] asset_page.dart 重构 -- [ ] mine_page.dart 重构 - -### Phase 4: Custom Components -- [ ] CoinCard 创建 -- [ ] TradeButton 创建 -- [ ] AssetCard 创建 - -## Changes Made -[详细记录每个文件的修改] - -## Issues Found -[发现的问题] - -## Questions -[需要确认的问题] - -## Completion -When all tasks are done, update status to: -STATUS: COMPLETE -``` +- ⚠️ **确保文字和背景颜色区分明显** +- ⚠️ **每次修改后运行 flutter analyze** ## 开始指令 开始工作: -1. 读取 `../REFACTOR_PLAN.md` 了解已有计划 -2. 读取 `specs/theme-modernization.md` 了解规范 -3. 读取 `AGENTS.md` 了解项目结构 -4. 创建 `IMPLEMENTATION_PLAN.md` -5. 开始执行 P0 优先级任务 +1. 读取 `specs/theme-design.md` 了解设计规范 +2. 读取 `IMPLEMENTATION_PLAN.md` 了解实施计划 +3. 按 P0 -> P1 -> P2 -> P3 优先级执行 +4. 完成后更新 IMPLEMENTATION_PLAN.md 状态 -Let's modernize the Monisuo Flutter app with a beautiful shadcn_ui theme! 🎨✨ +Let's create a professional theme system for the Monisuo Flutter app! 🎨 diff --git a/flutter_monisuo/lib/core/constants/app_colors.dart b/flutter_monisuo/lib/core/constants/app_colors.dart index ae21080..f4cb106 100644 --- a/flutter_monisuo/lib/core/constants/app_colors.dart +++ b/flutter_monisuo/lib/core/constants/app_colors.dart @@ -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 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); } diff --git a/flutter_monisuo/lib/core/theme/app_color_scheme.dart b/flutter_monisuo/lib/core/theme/app_color_scheme.dart new file mode 100644 index 0000000..9bc1fd6 --- /dev/null +++ b/flutter_monisuo/lib/core/theme/app_color_scheme.dart @@ -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, + ); +} diff --git a/flutter_monisuo/lib/core/theme/app_colors.dart b/flutter_monisuo/lib/core/theme/app_colors.dart new file mode 100644 index 0000000..a9ac476 --- /dev/null +++ b/flutter_monisuo/lib/core/theme/app_colors.dart @@ -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 gradientColors = [Color(0xFF2563EB), Color(0xFF1D4ED8)]; +} diff --git a/flutter_monisuo/lib/core/theme/app_spacing.dart b/flutter_monisuo/lib/core/theme/app_spacing.dart new file mode 100644 index 0000000..1863bb3 --- /dev/null +++ b/flutter_monisuo/lib/core/theme/app_spacing.dart @@ -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( + 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, + ); + } +} diff --git a/flutter_monisuo/lib/core/theme/app_text_styles.dart b/flutter_monisuo/lib/core/theme/app_text_styles.dart new file mode 100644 index 0000000..31cc1f1 --- /dev/null +++ b/flutter_monisuo/lib/core/theme/app_text_styles.dart @@ -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._(); +} diff --git a/flutter_monisuo/lib/core/theme/app_theme.dart b/flutter_monisuo/lib/core/theme/app_theme.dart index 2b8d186..bd0ee5e 100644 --- a/flutter_monisuo/lib/core/theme/app_theme.dart +++ b/flutter_monisuo/lib/core/theme/app_theme.dart @@ -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( + 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); + } } diff --git a/flutter_monisuo/lib/main.dart b/flutter_monisuo/lib/main.dart index f158677..3366bf4 100644 --- a/flutter_monisuo/lib/main.dart +++ b/flutter_monisuo/lib/main.dart @@ -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, ), ), diff --git a/flutter_monisuo/lib/ui/components/asset_card.dart b/flutter_monisuo/lib/ui/components/asset_card.dart index 51ebe34..4b6d884 100644 --- a/flutter_monisuo/lib/ui/components/asset_card.dart +++ b/flutter_monisuo/lib/ui/components/asset_card.dart @@ -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, ); diff --git a/flutter_monisuo/lib/ui/components/coin_card.dart b/flutter_monisuo/lib/ui/components/coin_card.dart index f4922b9..a69ad5e 100644 --- a/flutter_monisuo/lib/ui/components/coin_card.dart +++ b/flutter_monisuo/lib/ui/components/coin_card.dart @@ -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, ), ), diff --git a/flutter_monisuo/lib/ui/pages/asset/asset_page.dart b/flutter_monisuo/lib/ui/pages/asset/asset_page.dart index de5962f..e0f03b1 100644 --- a/flutter_monisuo/lib/ui/pages/asset/asset_page.dart +++ b/flutter_monisuo/lib/ui/pages/asset/asset_page.dart @@ -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'; diff --git a/flutter_monisuo/lib/ui/pages/home/home_page.dart b/flutter_monisuo/lib/ui/pages/home/home_page.dart index 175ab2f..34caf67 100644 --- a/flutter_monisuo/lib/ui/pages/home/home_page.dart +++ b/flutter_monisuo/lib/ui/pages/home/home_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'; diff --git a/flutter_monisuo/lib/ui/pages/market/market_page.dart b/flutter_monisuo/lib/ui/pages/market/market_page.dart index f382362..2cf041f 100644 --- a/flutter_monisuo/lib/ui/pages/market/market_page.dart +++ b/flutter_monisuo/lib/ui/pages/market/market_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 '../../../data/models/coin.dart'; import '../../../providers/market_provider.dart'; @@ -97,7 +98,7 @@ class _MarketPageState extends State 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 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 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 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, ), ), diff --git a/flutter_monisuo/lib/ui/pages/trade/trade_page.dart b/flutter_monisuo/lib/ui/pages/trade/trade_page.dart index 79486b8..3ff9007 100644 --- a/flutter_monisuo/lib/ui/pages/trade/trade_page.dart +++ b/flutter_monisuo/lib/ui/pages/trade/trade_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 '../../../data/models/coin.dart'; import '../../../providers/market_provider.dart'; import '../../../providers/asset_provider.dart'; diff --git a/flutter_monisuo/lib/ui/shared/ui_constants.dart b/flutter_monisuo/lib/ui/shared/ui_constants.dart index 010aae0..984647c 100644 --- a/flutter_monisuo/lib/ui/shared/ui_constants.dart +++ b/flutter_monisuo/lib/ui/shared/ui_constants.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 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; + } } diff --git a/flutter_monisuo/specs/theme-design.md b/flutter_monisuo/specs/theme-design.md new file mode 100644 index 0000000..0ade8a1 --- /dev/null +++ b/flutter_monisuo/specs/theme-design.md @@ -0,0 +1,237 @@ +# 数字货币应用主题设计规范 + +## 设计原则 + +1. **一致性** - 所有页面使用统一的设计语言 +2. **可读性** - 确保文字与背景对比度充足 (WCAG AA 标准) +3. **响应式** - 适配不同屏幕尺寸 +4. **专业性** - 符合金融/交易类应用的专业感 +5. **无障碍** - 避免颜色冲突,支持色盲用户 + +--- + +## 颜色系统 + +### 主色调 (Primary) + +``` +主色: #00D4AA (青绿色 - 代表增长、积极) +主色浅: #00E6B8 +主色深: #00B894 +``` + +### 涨跌色 (Trading Colors) + +``` +涨/买入: #00C853 (标准绿 - 国际通用) +跌/卖出: #FF5252 (标准红 - 国际通用) +``` + +### 背景色 (Dark Theme) + +``` +背景主色: #0F0F1A (深蓝黑) +卡片背景: #1A1A2E (深蓝紫) +输入框背景: #16213E (深蓝) +模态框背景: #1E1E32 +``` + +### 文字颜色 + +``` +主要文字: #FFFFFF (白色) +次要文字: #B0B0C0 (灰蓝) +提示文字: #6B6B80 (暗灰) +禁用文字: #4A4A5A +链接文字: #00D4AA +``` + +### 边框与分割线 + +``` +边框: rgba(255, 255, 255, 0.08) +分割线: rgba(255, 255, 255, 0.06) +聚焦边框: #00D4AA +``` + +### 功能色 + +``` +成功: #00C853 +警告: #FF9800 +错误: #FF5252 +信息: #2196F3 +充值: #00C853 +提现: #FF9800 +划转: #2196F3 +``` + +--- + +## 间距系统 + +```dart +static const double xs = 4.0; +static const double sm = 8.0; +static const double md = 16.0; +static const double lg = 24.0; +static const double xl = 32.0; +static const double xxl = 48.0; +``` + +## 圆角系统 + +```dart +static const double sm = 8.0; // 小组件 +static const double md = 12.0; // 按钮、输入框 +static const double lg = 16.0; // 卡片 +static const double xl = 24.0; // 大卡片 +static const double full = 999.0; // 圆形 +``` + +--- + +## 文字排版 + +### 字号 + +``` +h1: 28px - 页面大标题 +h2: 24px - 区块标题 +h3: 20px - 卡片标题 +h4: 18px - 小标题 +body1: 16px - 正文 +body2: 14px - 次要正文 +caption: 12px - 辅助文字 +small: 11px - 极小文字 +``` + +### 字重 + +``` +bold: 700 (标题) +semibold: 600 (强调) +medium: 500 (正文) +regular: 400 (辅助) +``` + +--- + +## 组件规范 + +### 按钮 + +1. **主按钮** + - 高度: 48px + - 圆角: 12px + - 背景: 主题色渐变 + - 文字: 白色, 16px, semibold + +2. **买入按钮** + - 背景: #00C853 渐变 + - 文字: 白色 + +3. **卖出按钮** + - 背景: #FF5252 渐变 + - 文字: 白色 + +4. **轮廓按钮** + - 边框: 1px solid border + - 背景: 透明 + - 文字: 主题色 + +### 输入框 + +- 高度: 48px +- 圆角: 12px +- 背景: #16213E +- 边框: 1px solid rgba(255,255,255,0.1) +- 聚焦边框: #00D4AA +- 文字: 白色 +- 提示: #6B6B80 + +### 卡片 + +- 圆角: 16px +- 背景: #1A1A2E +- 内边距: 16px-20px +- 阴影: 无 (扁平设计) + +### 涨跌标签 + +- 圆角: 6px +- 内边距: 6px 10px +- 涨: 背景 rgba(0,200,83,0.15), 文字 #00C853 +- 跌: 背景 rgba(255,82,82,0.15), 文字 #FF5252 + +### 底部导航 + +- 高度: 60px + safeArea +- 背景: #0F0F1A +- 边框: top 1px solid rgba(255,255,255,0.08) +- 选中色: #00D4AA +- 未选中色: #6B6B80 + +--- + +## 响应式断点 + +```dart +// 手机竖屏 +const double mobile = 360; + +// 手机横屏/小平板 +const double tablet = 768; + +// 平板/桌面 +const double desktop = 1024; +``` + +--- + +## 动画规范 + +- 标准时长: 200ms-300ms +- 缓动曲线: easeOutCubic +- 页面转场: 300ms +- 按钮反馈: 150ms + +--- + +## 无障碍设计 + +1. **对比度**: 所有文字与背景对比度 >= 4.5:1 +2. **触摸目标**: 最小 44x44px +3. **状态反馈**: 不仅依赖颜色区分 +4. **焦点指示**: 明显的焦点样式 + +--- + +## 禁止事项 + +1. ❌ 文字与背景颜色相同 +2. ❌ 纯黑色背景 (#000000) +3. ❌ 纯白色文字在浅色背景 +4. ❌ 低对比度组合 (对比度 < 4.5) +5. ❌ 仅用颜色区分状态 +6. ❌ 过小的触摸目标 (< 44px) +7. ❌ 不一致的组件样式 +8. ❌ 硬编码颜色值 + +--- + +## 实现清单 + +### 核心文件 + +1. `lib/core/theme/app_colors.dart` - 颜色定义 +2. `lib/core/theme/app_theme.dart` - 主题配置 +3. `lib/core/theme/app_text_styles.dart` - 文字样式 +4. `lib/core/theme/app_spacing.dart` - 间距常量 +5. `lib/ui/shared/ui_constants.dart` - 整合导出 + +### 需要优化的文件 + +- 所有 UI 页面文件 +- 所有 UI 组件文件 +- main.dart 主题配置