Files
patbond-doc/docs/development/iterations/iteration-1/08-flutter-theme-report.md
T
lixi 209021e7d2 docs: 迁入第一迭代过程报告并建立进展看板
- 新增 development/iterations/iteration-1/:15 份角色报告 + 进展看板(已完成/未闭环/下一步),作为双人协作的进度事实来源
- 新增 ADR-006:测试与交付容器化策略(Testcontainers / 交付 Docker 包 / 本机库仅个人联调)
- Git 工作流规范补充:敏感信息只进忽略文件或 sample、测试数据不入库、测试代码限标准测试目录
- 门禁:mkdocs build --strict 通过(零警告)
2026-09-04 10:45:05 +08:00

109 lines
6.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 08 · Flutter 主题迁移与登录组件实现报告
> 作者:Frontend Developer
> 日期:2026-09-03
> 依据:ADR-005patbond-doc/docs/architecture/decisions.md)、04-ui-login-design-spec.md
## 1. 完成内容
1. `lib/core/theme/app_theme.dart` 重写为语义 token 组织(`AppColors` + 新增 `AppRadius`),落地珊瑚橙正典色板;补齐 `filledButtonTheme`(高 52、圆角 16、`primaryStrong` 填充、显式 disabled 色)、`errorBorder` / `focusedErrorBorder` / `errorStyle``colorScheme.error` 覆盖。主题仍集中在单一文件。
2. 五个 Tab 页面及公共组件逐处替换旧靛蓝/冷灰硬编码色值为语义 token,仅换色、未动布局。
3. 新建 5 个可复用组件于 `lib/core/widgets/``BrandMark``AppTextField``PrimaryButton`(含 isLoading)、`InlineErrorBanner``AuthScaffold`。本次未建登录页面(等后端契约冻结)。
4.`PrimaryButton``AppTextField` 各写 3 个 widget 测试。
## 2. Token 映射表(旧 → 新)
### 2.1 AppColors 字段值变化(字段名不变,引用处无需改)
| Token | 旧值(脚手架靛蓝) | 新值(珊瑚橙正典) |
| --- | --- | --- |
| `primary` | `#4F46E5` | `#FF6F4C`(仅装饰/图标,不承载实心填充上的文字) |
| `canvas` | `#F8FAFC` | `#FFF7ED` 奶油底 |
| `ink` | `#0F172A` | `#3E2A1F` |
| `muted` | `#64748B` | `#9C8977` |
| `border` | `#E2E8F0` | `#F0DCC8` |
| `success` | `#10B981` | `#7FA88A` sage |
| `warning` | `#F59E0B` | `#F59E0B`(不变) |
### 2.2 新增 token
| Token | 值 | 用途 |
| --- | --- | --- |
| `primaryStrong` | `#D6431A` | 实心按钮填充、可点击文字链接(白字 ≈4.5:1,WCAG AA |
| `primaryDark` | `#7A2E12` | 浅色底上的强调文字 |
| `accent` / `accentDark` | `#FFB648` / `#7A4B0A` | 渐变终点、徽章 / amber 底文字 |
| `surface` | `#FFFFFF` | 卡片、输入框背景(原为字面量 `Colors.white` |
| `surfaceTint` | `#FFE8D6` peach | 图标底、占位块、选中指示 |
| `successInk` / `successSurface` | `#3F5744` / `#E8F0E8` | 成功提示的文字 / 底色 |
| `error` | `#D0342C` | 错误文字、错误描边(白底 ≈5.4:1,AA) |
| `brandGradient` | 135° `#FF6F4C → #FFB648` | 品牌渐变(装饰,不承载正文文字) |
| `AppRadius.sm/md/lg/xl/pill` | 12 / 16 / 18 / 24 / 999 | 圆角刻度(§1.3 |
### 2.3 页面内硬编码旧色值 → token
| 旧硬编码 | 新写法 | 位置 |
| --- | --- | --- |
| `#F1F5F9`(图片占位底) | `AppColors.surfaceTint` | common.dart ×2 |
| `#EEF2FF`indigo-50 图标底) | `AppColors.surfaceTint` | home ×2、profile |
| `#E0E7FF`(导航指示/渐变上副文字) | `AppColors.surfaceTint` / `Colors.white` | 主题、home 促销卡 |
| `[#4F46E5→#8B5CF6]``[primary→#7C3AED]` 渐变 | `AppColors.brandGradient` | home 故事环、促销卡 |
| `#ECFDF5→#FFF7ED` 问候卡渐变 | `surfaceTint → canvas` | home |
| `0x224F46E5` 装饰爪印 | `primary.withAlpha(34)` | home |
| `#475569`slate 次级文字/阴天色) | `AppColors.primaryDark` / `AppColors.ink` | home |
| `#64748B``#F59E0B`(多云/晴天) | `AppColors.muted` / `AppColors.warning` | home 天气色 |
| `0xCC0F172A` 图片压暗渐变 | `ink.withAlpha(204)` | create |
| `#E2E8F0`(scrim 上副文字/进度轨道) | `Colors.white70` / `AppColors.border` | create、pets |
| `#ECFDF5` / `#A7F3D0` / `#047857` 健康提醒卡 | `successSurface` / `success.withAlpha(140)` / `successInk` | pets |
| `#A5B4FC` / `#334155` / `#94A3B8`(深色卡上) | `AppColors.accent` / `Colors.white24` / `Colors.white70` | profile |
| 促销卡反白按钮前景 `primary` | `primaryStrong`AA | home |
| 导航选中 label `primary` | `primaryStrong`11px 文字保 AA | 主题 |
保留未动:天气雨/雪的功能性蓝色(`#0284C7``#0891B2`,非旧品牌色)、点赞红、卡片主题 `#F1F5F9` 描边改为 `AppColors.border`
## 3. 改动文件清单
修改(7):
- `patbond-flutter/lib/core/theme/app_theme.dart`(重写)
- `patbond-flutter/lib/widgets/common.dart`
- `patbond-flutter/lib/features/home/home_page.dart`
- `patbond-flutter/lib/features/create/create_page.dart`
- `patbond-flutter/lib/features/pets/pets_page.dart`
- `patbond-flutter/lib/features/profile/profile_page.dart`
- services / post_detail / main_shell 仅引用 token 字段,值随主题自动切换,无需改动)
新增(7):
- `patbond-flutter/lib/core/widgets/brand_mark.dart`
- `patbond-flutter/lib/core/widgets/app_text_field.dart`
- `patbond-flutter/lib/core/widgets/primary_button.dart`
- `patbond-flutter/lib/core/widgets/inline_error_banner.dart`
- `patbond-flutter/lib/core/widgets/auth_scaffold.dart`
- `patbond-flutter/test/core/widgets/primary_button_test.dart`
- `patbond-flutter/test/core/widgets/app_text_field_test.dart`
## 4. 验收命令输出摘要
```text
$ dart format --output=none --set-exit-if-changed lib test
Formatted 22 files (0 changed) in 0.15 seconds. # exit 0
$ flutter analyze
Analyzing patbond-flutter...
No issues found! (ran in 0.7s) # 无 error、无 warning
$ flutter test
00:01 +7: All tests passed! # 含原有导航冒烟测试,未改断言
```
## 5. 实现说明与遗留问题
1. **filledButtonTheme 的 minimumSize 用了 `Size(64, 52)` 而非规范建议的 `Size.fromHeight(52)`**:后者会给所有 FilledButton 无限最小宽度,令 Row 内既有按钮(首页促销卡「去使用」、服务页「立即预约」、对话框「确认恢复」)布局异常。改为仅约束高度 52;登录页的全宽由 `PrimaryButton` 自身 `width: double.infinity` 保证。副作用:既有小按钮从默认 40 高变为 52 高,视觉更厚重但协调,未破坏布局。
2. **PrimaryButton 的 loading 态**通过 `disabledBackgroundColor: primaryStrong` 保持珊瑚填充(规范 §4.3/§4.4:loading 不是置灰禁用态),已有测试锁定该行为。
3. **`ColorScheme.fromSeed` 仍以 `#FF6F4C` 为种子**Material 组件(Chip、SegmentedButton、tonal 按钮等)使用生成的暖色调色板,与正典色板协调但非逐一指定;`error` 已显式覆盖为 `#D0342C`。若后续设计对某组件色不满意,在主题内补对应 componentTheme 即可。
4. **天气语义色**:雨 `#0284C7`、雪 `#0891B2` 为功能色保留硬编码;阴天映射为 `ink`、多云映射为 `muted`,如需更细的天气色阶可后续补 token。
5. **品牌字体(Baloo 2 / 圆润中文标题体)未引入**,规范允许后置;`BrandMark` 字标暂用系统字体 32/w700。
6. **成功色 sage `#7FA88A` 作 11px TagPill 文字对比度偏弱**(约 2.4:1,沿用既有 TagPill 模式);正文类成功文字请用 `successInk`。此为设计规范自带取舍,未在本次擅改。
7. Splash / 登录 / 注册页、认证状态机、flutter_secure_storage 依赖均未实现,按计划等后端契约冻结后进行。
---
**Frontend Developer** · 2026-09-03