Files
social-app/docs/plans/2026-03-12-home-composer-redesign-implementation-plan.md
T
qzl 01c36eb32e refactor: 移除前端 Mock API,新增共享组件,优化认证流程
- 删除 mock_api_client、mock_calendar_service、mock_history_service
- 新增 fixed_length_code_input、link_button、message_composer 共享组件
- 优化登录/注册/密码重置页面使用新组件
- 简化 injection.dart 移除 mock 分支
- 更新 env.dart 配置(BACKEND_URL 替换 API_URL)
- 后端 agentscope 工具和测试更新
- 重构 AGENTS.md 文档结构
- 新增 deploy/ 目录和 protocol 文档
2026-03-12 16:41:45 +08:00

9.7 KiB
Raw Blame History

Home Composer Redesign Implementation Plan

For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

Goal: 重做 Home 输入组件,统一为单胶囊容器并稳定语音长按交互,消除布局漂移,同时保持 + 与发送等既有业务逻辑不变。

Architecture: 采用“单容器双模式”方案:HomeScreen 继续持有业务状态与动作,新增 HomeComposer 专注 UI 与手势分发;中间区域用受控状态在文本/按住说话/录音中/识别中之间切换,外层高度固定。录音提示与声波动画都内聚在主容器内部渲染,避免额外布局占位。

Tech Stack: Flutter, flutter_bloc, lucide_icons, design tokens (AppColors/AppSpacing/AppRadius), widget test


Task 1: 建立 HomeComposer 组件骨架与参数契约

Files:

  • Create: apps/lib/features/home/ui/widgets/home_composer.dart
  • Modify: apps/lib/features/home/ui/screens/home_screen.dart
  • Test: apps/test/features/home/ui/widgets/home_composer_test.dart

Step 1: 写失败测试(渲染结构)

testWidgets('renders one unified rounded composer container', (tester) async {
  // pump HomeComposer with minimum required callbacks/states
  // expect: one root container, plus button, center content slot, right action slot
});

Step 2: 运行测试确认失败

Run: flutter test test/features/home/ui/widgets/home_composer_test.dart --plain-name "renders one unified rounded composer container" Expected: FAILHomeComposer 未定义或结构不匹配)

Step 3: 写最小实现

class HomeComposer extends StatelessWidget {
  const HomeComposer({
    super.key,
    required this.isHoldToSpeakMode,
    required this.isRecording,
    required this.isTranscribing,
    required this.hasMessage,
    required this.isWaitingAgent,
    required this.onTapPlus,
    required this.onTapRightAction,
    required this.centerChild,
  });
  // unified capsule container with left/center/right slots
}

Step 4: 再跑测试确认通过

Run: flutter test test/features/home/ui/widgets/home_composer_test.dart --plain-name "renders one unified rounded composer container" Expected: PASS

Step 5: 小步提交(仅用户明确要求时)

git add apps/lib/features/home/ui/widgets/home_composer.dart apps/lib/features/home/ui/screens/home_screen.dart apps/test/features/home/ui/widgets/home_composer_test.dart
git commit -m "refactor: extract unified home composer container"

Task 2: 完成右侧图标状态映射(activity/keyboard/send/stop

Files:

  • Modify: apps/lib/features/home/ui/widgets/home_composer.dart
  • Modify: apps/lib/features/home/ui/screens/home_screen.dart
  • Test: apps/test/features/home/ui/widgets/home_composer_test.dart

Step 1: 写失败测试(图标状态机)

testWidgets('right action icon follows state priority', (tester) async {
  // waiting > hasMessage > holdToSpeakMode > textMode
  // expect LucideIcons.square/send/keyboard/activity respectively
});

Step 2: 运行测试确认失败

Run: flutter test test/features/home/ui/widgets/home_composer_test.dart --plain-name "right action icon follows state priority" Expected: FAIL(图标选择逻辑尚未完整实现)

Step 3: 最小实现图标决策

IconData resolveRightIcon(...) {
  if (isWaitingAgent) return LucideIcons.square;
  if (hasMessage) return LucideIcons.send;
  return isHoldToSpeakMode ? LucideIcons.keyboard : LucideIcons.activity;
}

Step 4: 再跑测试确认通过

Run: flutter test test/features/home/ui/widgets/home_composer_test.dart --plain-name "right action icon follows state priority" Expected: PASS

Step 5: 小步提交(仅用户明确要求时)

git add apps/lib/features/home/ui/widgets/home_composer.dart apps/lib/features/home/ui/screens/home_screen.dart apps/test/features/home/ui/widgets/home_composer_test.dart
git commit -m "refactor: stabilize composer right action icon mapping"

Task 3: 实现中间区域双模式替换并固定高度

Files:

  • Modify: apps/lib/features/home/ui/widgets/home_composer.dart
  • Modify: apps/lib/features/home/ui/screens/home_screen.dart
  • Test: apps/test/features/home/ui/widgets/home_composer_test.dart

Step 1: 写失败测试(模式切换不改变高度)

testWidgets('composer height remains stable across mode switches', (tester) async {
  // measure size in text mode and hold-to-speak mode
  // expect equal heights
});

Step 2: 运行测试确认失败

Run: flutter test test/features/home/ui/widgets/home_composer_test.dart --plain-name "composer height remains stable across mode switches" Expected: FAIL(当前结构切换时高度波动)

Step 3: 最小实现(AnimatedSwitcher + fixed constraints

SizedBox(
  height: composerHeight,
  child: AnimatedSwitcher(
    duration: switchDuration,
    child: isHoldToSpeakMode ? holdToSpeakChild : textInputChild,
  ),
)

Step 4: 再跑测试确认通过

Run: flutter test test/features/home/ui/widgets/home_composer_test.dart --plain-name "composer height remains stable across mode switches" Expected: PASS

Step 5: 小步提交(仅用户明确要求时)

git add apps/lib/features/home/ui/widgets/home_composer.dart apps/lib/features/home/ui/screens/home_screen.dart apps/test/features/home/ui/widgets/home_composer_test.dart
git commit -m "refactor: keep composer layout stable during mode switch"

Task 4: 实现长按录音交互(开始/上滑取消/松开发送)

Files:

  • Modify: apps/lib/features/home/ui/screens/home_screen.dart
  • Modify: apps/lib/features/home/ui/widgets/home_composer.dart
  • Test: apps/test/features/home/ui/widgets/home_composer_test.dart

Step 1: 写失败测试(录音提示只在 recording)

testWidgets('recording hint appears only while recording', (tester) async {
  // idle hold-to-speak: no hint
  // recording: show "松开发送,上滑取消"
});

Step 2: 运行测试确认失败

Run: flutter test test/features/home/ui/widgets/home_composer_test.dart --plain-name "recording hint appears only while recording" Expected: FAIL

Step 3: 最小实现录音流程映射

onLongPressStart => HapticFeedback.lightImpact() + onHoldStart();
onLongPressMoveUpdate => if (dy < threshold) onHoldCancel();
onLongPressEnd => onHoldEnd(autoSend: true);

Step 4: 再跑测试确认通过

Run: flutter test test/features/home/ui/widgets/home_composer_test.dart --plain-name "recording hint appears only while recording" Expected: PASS

Step 5: 小步提交(仅用户明确要求时)

git add apps/lib/features/home/ui/widgets/home_composer.dart apps/lib/features/home/ui/screens/home_screen.dart apps/test/features/home/ui/widgets/home_composer_test.dart
git commit -m "feat: rework hold-to-speak interaction with stable recording state"

Task 5: 视觉重构为轻拟物胶囊(仅 tokens)

Files:

  • Modify: apps/lib/features/home/ui/widgets/home_composer.dart
  • Modify: apps/lib/core/theme/design_tokens.dart(仅当现有 token 不足时新增)
  • Test: apps/test/features/home/ui/widgets/home_composer_test.dart

Step 1: 写失败测试(主容器统一性)

testWidgets('plus, center and right action are inside same capsule', (tester) async {
  // find one capsule host and verify children are descendants
});

Step 2: 运行测试确认失败

Run: flutter test test/features/home/ui/widgets/home_composer_test.dart --plain-name "plus, center and right action are inside same capsule" Expected: FAIL

Step 3: 最小视觉实现(不硬编码)

// use AppColors/AppSpacing/AppRadius and existing shadow tokens
// no hardcoded color/spacing/radius/size

Step 4: 再跑测试确认通过

Run: flutter test test/features/home/ui/widgets/home_composer_test.dart --plain-name "plus, center and right action are inside same capsule" Expected: PASS

Step 5: 小步提交(仅用户明确要求时)

git add apps/lib/features/home/ui/widgets/home_composer.dart apps/lib/core/theme/design_tokens.dart apps/test/features/home/ui/widgets/home_composer_test.dart
git commit -m "refactor: redesign home composer with neumorphic capsule style"

Task 6: 集成回归与文档同步

Files:

  • Modify: apps/lib/features/home/ui/screens/home_screen.dart
  • Modify: docs/runtime/runtime-route.md(若交互说明有变化)

Step 1: 运行目标测试文件

Run: flutter test test/features/home/ui/widgets/home_composer_test.dart Expected: PASS

Step 2: 运行 Home 相关回归测试(若新增)

Run: flutter test test/features/home Expected: PASS(若目录存在)

Step 3: 运行应用侧基础回归

Run: flutter test Expected: PASS 或仅存在与本改动无关的已知失败

Step 4: 记录验证结论

- 输入组件统一容器:通过
- 模式切换稳定:通过
- 录音提示条件:通过
- + 按钮/发送逻辑:通过

Step 5: 小步提交(仅用户明确要求时)

git add apps/lib/features/home/ui/screens/home_screen.dart apps/lib/features/home/ui/widgets/home_composer.dart apps/test/features/home/ui/widgets/home_composer_test.dart docs/runtime/runtime-route.md
git commit -m "test: add regression coverage for home composer redesign"

实施注意事项

  • 保持 HomeScreen 作为业务状态单一来源,避免在 HomeComposer 内部复制业务状态。
  • 录音中 (recording) 禁止触发模式切换,防止并发手势引发错位。
  • 严格遵守 apps/AGENTS.md:不硬编码视觉值,必须使用 design tokens。
  • 用户反馈统一使用 Toast.show(...),不得引入 SnackBar