Skip to content

吸底跟随 ScrollDirection 语义反置:从历史拖回底部后自动跟随失效 #52

Description

@yunkst

问题lib/widgets/agent_chat/agent_chat_messages.dart:75-83_onUserScrollScrollDirection 的语义理解与 Flutter 实际约定相反。

Flutter 实际语义(默认非 reverse 垂直 ListView):

  • ScrollDirection.forward = offset 增大方向 = 用户手指上滑 / 内容上移 / 露出更新的(更靠后)消息;
  • ScrollDirection.reverse = offset 减小方向 = 用户手指下滑 / 内容下滑 / 露出更早的消息(翻历史)。

当前代码(行 70-83):注释与分支都把 forward 当作"翻回历史"(onForward → _followBottom = false 无条件),把 reverse 当作"朝最新消息方向滚"(onReverse → 到底才恢复跟随),与实际恰好相反。

触发场景:用户从历史拖回底部(手指向上滑,触发 ScrollDirection.forward)→ 命中 forward 分支 → _followBottom 被无条件置为 false。新消息到达时 ref.listen<AgentChatState> 看见 !_followBottom 直接 return,自动跟随失效,用户必须再次点击回底按钮才能恢复。这正是「吸底跟随」功能最关键、最容易出问题的回归路径。

影响:长对话场景下,吸底跟随的核心承诺("在底部时新内容自动追到最新")在用户主动回到底部后被破坏,回到底部之后必须再点一次回底按钮才能恢复。属于可观察的功能回归,非纯理论缺陷。

测试覆盖盲点test/unit/widgets/agent_chat/agent_chat_messages_test.dart:138-185 现有「吸底跟随」用例只走了 tester.drag(find.byType(ListView), const Offset(0, 200))(手指下滑、触发 reverse、翻历史)这一条路径,恰好与 buggy 分支吻合,所以测试通过但无法暴露本 bug。

修复建议(任选其一):

  1. if/else if 两个分支互换:forward 改为按 pixels >= maxScrollExtent - _bottomSlack 设置 _followBottomreverse 改为无条件 _followBottom = false
  2. 同时修正 70-74 行的注释("forward = 内容下滑、露出更早的消息"改为"forward = offset 增大、露出更晚的消息"),避免再次写反;
  3. 补一条「在历史中上滑拖回底部后,新消息应重新自动跟随」测试:构造一个 mid-list 起点,用 tester.drag(find.byType(ListView), const Offset(0, -200)) 向上拖回底部,再追加新消息并断言 pixels >= maxScrollExtent - 40

忽略指南:在 lib/widgets/agent_chat/agent_chat_messages.dart:76 添加注释 // cr-ignore <CR_IGNORE_IID_HASH>: <你的理由>,下次审查会自动关闭。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions