feat(chat): add scroll speed limit for streaming output and top positioning for non-streaming output (#1116) - #1120
Conversation
CATMIAOZHI
left a comment
There was a problem hiding this comment.
BLOCK:发现 3 项 P2,具体触发条件和修正建议见行内评论。
审计提交:df3b01da86bee4ceaf2a76c25fc6c55e9d5e271a。已完成独立工作树全 diff 与调用链审查、独立 agent 复核及 diff --check;审计前已请求 CATMIAOZHI review。
验证范围:当前上游仓库该 HEAD 的 check-runs 为 0,审计前无 review 线程。现有 PR workflow 仅匹配 development,而本 PR 目标为 dev;构建/测试 push workflow 匹配 main。已核对仓库 Actions Variables(GITEE_OWNER、GITEE_REPO)及工作流任务。已核实作者 fork 的 Android Build 对应本次 HEAD 且成功;该运行的步骤只执行构建,没有 JVM 单测执行步骤,因此不将其视为单测通过证明。遵守目标仓库 AGENTS.md,本次未运行本地编译、测试、Lint 或真机验证;未修改源码。
| } | ||
| val deltaDp = deltaPx / densityDpiRatio | ||
| val calculatedMs = ((deltaDp / maxSpeedDpPerSecond) * 1000f).toLong() | ||
| return calculatedMs.coerceIn(minDurationMs, maxDurationMs).toInt() |
There was a problem hiding this comment.
[P2] 不要用 1 秒时长上限突破用户设置的滚动速度
当流式输出积压 500 dp、用户选择 50 dp/s 时,计算需要 10 秒,但这里截成 1000 ms,后面的 LinearEasing 动画仍滚完全部距离,实际达到 500 dp/s。ChatArea 和 AIChatScreen 的追赶滚动都会走此函数,因此大块输出时恰好无法保持设置的上限。请保留满足限速所需的时长,或限制每段滚动位移。
| val isTargetAi = targetMessage?.sender == "ai" | ||
| val isNonStreamingAi = isTargetAi && | ||
| targetMessage?.contentStream == null && | ||
| targetMessage?.timestamp !in streamedAiMessageTimestamps |
There was a problem hiding this comment.
[P2] 根据实际输出模式识别非流式回复
普通聊天关闭 Waifu、开启“禁用流式输出”时,AIMessageManager 虽将 stream=false 传入请求,仍无条件调用 shareRevisable;MessageProcessingDelegate 随后把带 contentStream 的占位 AI 消息加入界面。下面的 effect 因此会将 timestamp 记入 streamedAiMessageTimestamps,完成后即使清掉 contentStream,该记录仍在,这里也不能进入顶部定位分支。请传递实际请求的流式模式,避免把 UI 使用共享流当成网络流式输出的证据。
| if (isNonStreamingAi && enableNonStreamingScrollToTop) { | ||
| val targetOffset = | ||
| targetAnchor.absoluteTopPx.roundToInt().coerceIn(0, scrollState.maxValue) | ||
| scrollState.animateScrollTo(targetOffset) |
There was a problem hiding this comment.
[P2] 保留用户显式“滚动到底部”的导航行为
默认启用该选项后,重开以长 AI 回答结尾的历史并向上拖动,再点击底部按钮:ChatScrollNavigator 先启动到底动画并设置 autoScroll=true;后者触发 ChatArea 上方 effect,将最新消息设为 pending。历史消息没有 contentStream,且本次进入的 streamed 集合为空,于是这里又启动到消息开头的动画,打断或覆盖用户的到底请求。请把新非流式回复的自动顶部定位与用户显式到底导航区分开。
变更说明 / Description
背景与动机 / Context and motivation
针对 Issue #1116 反映的两个对话阅读体验问题:
改动范围 / Changes
1. 流式输出滚动速度上限(21 档可调滑块)
将原先的二值开关(硬编码 800 dp/s)升级为连续可调滑块,共 21 档:
2. 非流式输出定位到消息开头
3. 核心文件改动
DisplayPreferencesManager.kt:原布尔键替换为int键stream_scroll_max_speed_dp,新增 21 档选项列表与"不限速"标记常量ChatScrollSpeedLimit.kt:参数从enableLimit: Boolean改为maxSpeedDpPerSecond: Int,传入不限速常量时走直通路径ChatArea.kt/AIChatScreen.kt:读取新的速度 Flow,流式时传速度上限值,非流式时传不限速GlobalDisplaySettingsScreen.kt:开关替换为 Slider,档位列表驱动,实时显示当前 dp/s 值(最后档显示"不设上限")strings.xml:旧开关文案替换为 title / description / value / unlimited 四条本地化字符串4. 明确不包含
兼容性与风险 / Compatibility and risks
关联 Issue / Related issue
Resolves #1116
验证方式 / Verification
ChatScrollSpeedLimitTest:6 组断言,覆盖比例计算、上下界 clamp、档位列表结构(21 档、首尾值、默认值可选)android-build.ymlassembleDebug:run 34031171863,结论 success检查清单 / Checklist
dev