123 lines
4.7 KiB
Markdown
123 lines
4.7 KiB
Markdown
|
|
# Home 输入组件重做设计(HomeComposer Redesign)
|
|||
|
|
|
|||
|
|
## 1. 目标与范围
|
|||
|
|
|
|||
|
|
### 1.1 目标
|
|||
|
|
- 解决当前输入组件“质感弱、结构割裂、录音时布局漂移”的问题。
|
|||
|
|
- 统一 `+` 按钮、输入区、右侧动作图标到一个圆角矩形主容器内。
|
|||
|
|
- 保留并复用现有录音、转写、自动发送、停止生成、Toast 错误处理逻辑。
|
|||
|
|
|
|||
|
|
### 1.2 非目标
|
|||
|
|
- 不改动聊天流、消息发送后端协议、语音识别接口。
|
|||
|
|
- 不改动 `+` 按钮业务行为。
|
|||
|
|
- 不新增独立的页面级浮层录音面板。
|
|||
|
|
|
|||
|
|
## 2. 问题诊断(现状)
|
|||
|
|
|
|||
|
|
- 当前输入区由多个分离容器拼接,视觉上像“纸片贴上去”。
|
|||
|
|
- 输入框本体和右侧图标视觉上未合为一个整体容器。
|
|||
|
|
- “按住说话”提示与录音动画在主布局外追加,录音时造成结构上下跳动。
|
|||
|
|
|
|||
|
|
## 3. 方案对比
|
|||
|
|
|
|||
|
|
### 方案 A:单容器双模式(推荐)
|
|||
|
|
- 单一胶囊主容器承载三段:左操作、中间主内容、右操作。
|
|||
|
|
- 中间区域在文本模式与按住说话模式之间替换(`AnimatedSwitcher`)。
|
|||
|
|
- 录音动画仅在中间区域内部切换显示,不改变主容器高度。
|
|||
|
|
|
|||
|
|
优点:结构稳定、状态清晰、维护成本低。
|
|||
|
|
缺点:视觉表达自由度略低于 Overlay 方案。
|
|||
|
|
|
|||
|
|
### 方案 B:双容器交叉切换
|
|||
|
|
- 文本容器和语音容器完整分离,做交叉淡入。
|
|||
|
|
|
|||
|
|
优点:切换动效可做得更明显。
|
|||
|
|
缺点:状态同步复杂,容易再次出现错位与边界问题。
|
|||
|
|
|
|||
|
|
### 方案 C:Overlay 浮层
|
|||
|
|
- 保持输入容器不变,录音时叠加浮层。
|
|||
|
|
|
|||
|
|
优点:动画自由度高。
|
|||
|
|
缺点:与“整块替换”诉求不一致,事件命中与无障碍处理更复杂。
|
|||
|
|
|
|||
|
|
结论:采用方案 A。
|
|||
|
|
|
|||
|
|
## 4. 信息架构与组件边界
|
|||
|
|
|
|||
|
|
## 4.1 新组件
|
|||
|
|
- 新建 `HomeComposer`(从 `home_screen.dart` 抽离输入区渲染职责)。
|
|||
|
|
- `HomeScreen` 继续持有业务状态与行为方法,`HomeComposer` 负责展示与手势分发。
|
|||
|
|
|
|||
|
|
## 4.2 主容器结构
|
|||
|
|
- 一个圆角矩形主容器(轻拟物胶囊风格)。
|
|||
|
|
- 左侧:`+` 按钮(行为不变)。
|
|||
|
|
- 中间:
|
|||
|
|
- 文本模式:无边框输入区(文字垂直居中)。
|
|||
|
|
- 语音模式:按住说话按钮区。
|
|||
|
|
- 录音中/识别中:在语音模式内部替换状态内容。
|
|||
|
|
- 右侧:动作图标(声波/键盘/发送/停止)。
|
|||
|
|
|
|||
|
|
## 5. 状态机设计
|
|||
|
|
|
|||
|
|
## 5.1 状态定义
|
|||
|
|
- 模式层:`text` / `holdToSpeak`
|
|||
|
|
- 过程层:`idle` / `recording` / `transcribing`
|
|||
|
|
|
|||
|
|
## 5.2 核心约束
|
|||
|
|
- 主容器高度固定,状态变化不得引发外层布局高度变化。
|
|||
|
|
- `recording` 时禁止模式切换,避免状态错位。
|
|||
|
|
|
|||
|
|
## 5.3 右侧图标决策
|
|||
|
|
- Agent 等待中:停止图标。
|
|||
|
|
- 非等待:
|
|||
|
|
- 有文本:发送图标。
|
|||
|
|
- 无文本且 `text`:`LucideIcons.activity`。
|
|||
|
|
- 无文本且 `holdToSpeak`:`LucideIcons.keyboard`。
|
|||
|
|
|
|||
|
|
## 6. 交互与动画
|
|||
|
|
|
|||
|
|
## 6.1 长按语音流程
|
|||
|
|
1. `onLongPressStart`:触发 `HapticFeedback.lightImpact()`,开始录音。
|
|||
|
|
2. `onLongPressMoveUpdate`:上滑超过阈值,取消录音。
|
|||
|
|
3. `onLongPressEnd`:未取消则停止录音,转写并自动发送。
|
|||
|
|
|
|||
|
|
## 6.2 提示文案显示策略
|
|||
|
|
- “松开发送,上滑取消”仅在 `recording` 显示。
|
|||
|
|
- 空闲按住说话模式不显示该提示。
|
|||
|
|
|
|||
|
|
## 6.3 动画策略
|
|||
|
|
- 模式切换:短时 `AnimatedSwitcher`(淡入/轻位移)。
|
|||
|
|
- 录音波形:仅在 `recording` 驱动;停止后立刻回收。
|
|||
|
|
- 动画渲染在中间区域内部,不新增外部占位。
|
|||
|
|
|
|||
|
|
## 7. 视觉规范(Design Tokens)
|
|||
|
|
|
|||
|
|
- 严格使用 `apps/lib/core/theme/design_tokens.dart` 中的 `AppColors`、`AppSpacing`、`AppRadius`。
|
|||
|
|
- 禁止硬编码颜色、间距、圆角、尺寸、阴影。
|
|||
|
|
- 主容器采用白色底 + 细边 + 柔和阴影,形成轻拟物层次。
|
|||
|
|
- 输入区内部无额外边框,确保文字垂直居中和图标视觉对齐。
|
|||
|
|
|
|||
|
|
## 8. 验收标准
|
|||
|
|
|
|||
|
|
- 图标与输入区在同一圆角矩形中,不再分离。
|
|||
|
|
- 录音全流程不出现输入组件上移、下坠或高度抖动。
|
|||
|
|
- 提示文案仅在实际录音中显示。
|
|||
|
|
- 文本/语音模式切换平滑;`+` 与发送逻辑行为保持一致。
|
|||
|
|
|
|||
|
|
## 9. 风险与缓解
|
|||
|
|
|
|||
|
|
- 风险:重构过程中影响现有发送/停止生成分支。
|
|||
|
|
- 缓解:优先复用原有行为方法,仅调整 UI 结构与状态映射。
|
|||
|
|
- 风险:手势与模式切换并发导致状态错乱。
|
|||
|
|
- 缓解:录音期间加切换锁,结束后释放。
|
|||
|
|
|
|||
|
|
## 10. 验证计划
|
|||
|
|
|
|||
|
|
- 手工验证:
|
|||
|
|
- 文本发送、停止生成、`+` 弹层、语音长按录音、上滑取消、自动发送。
|
|||
|
|
- 文本模式与语音模式往返切换稳定性。
|
|||
|
|
- Widget 测试(建议新增):
|
|||
|
|
- 右侧图标状态映射测试。
|
|||
|
|
- 录音中提示文案显示条件测试。
|
|||
|
|
- 模式切换时主容器高度恒定测试。
|