Skip to content

fix(subtitle): 字幕列表打开时精准定位高亮——真实布局校正替代估算偏移 - #938

Open
TsangAsuna wants to merge 2 commits into
AimesSoft:mainfrom
TsangAsuna:pr/subtitle-list-precise-locate
Open

TsangAsuna wants to merge 2 commits into
AimesSoft:mainfrom
TsangAsuna:pr/subtitle-list-precise-locate

Conversation

@TsangAsuna

Copy link
Copy Markdown
Contributor

问题

字幕列表打开时高亮定位用「行高估算 + 首条 start >= pos」推导:

  1. 估算偏移随列表长度累积,长列表打开时高亮停在错误位置附近;
  2. 「第一条 start >= pos」会跳过正在播放的台词——间隙期(对白之间)打开列表定位到下一条,与播放器当前显示的字幕不一致。

方案

  • 用真实 RenderBox 布局信息计算目标行 offset,替代行高估算;
  • 定位语义改为:区间内(start <= pos < end)优先,否则取最后一个 start <= pos 的条目——与播放器当前显示的台词一致。

验证

  • flutter analyze 无新增问题(基线 24 issues,本分支同文件更少)
  • iPad 12.9 实测:间隙期打开列表高亮正是正在播放的台词

打开列表时定位偏差根因:_findNearestSubtitleIndex 返回首条
startTimeMs>=position 的字幕,正在播的那条(start<=position<=end)被跳过;
台词间隙大时(如乐器段19:00->21:00无对白)高亮跳到几分钟后。

- cupertino pane: 区间内优先命中,间隙取已开始(start<=position)的最后一条
- nipaplay menu: 区间检查已有,间隙的|start-position|绝对最近改为同一语义,
  两端主题行为对齐

Python 语义镜像 8/8 边界检查(subtitle_index_check.py)。
@TsangAsuna
TsangAsuna requested a review from a team as a code owner September 23, 2026 00:04

@FurudeRika123 FurudeRika123 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The RenderBox-based correction is the right idea, and the gap-semantics change in _findNearestSubtitleIndex (cupertino_subtitle_list_pane.dart:283-304, subtitle_list_menu.dart:412-437) is a genuine improvement over the old "first start >= position / absolute-nearest" logic - the parsers sort by start time, so the early return lastIndex short-circuit is safe.

One correctness gap blocks approval: the comments at cupertino_subtitle_list_pane.dart:332-334 and subtitle_list_menu.dart:501-503 state that Scrollable.ensureVisible "only scrolls when the item is not visible". That is not true - the default alignmentPolicy is ScrollPositionAlignmentPolicy.explicit, whose implementation unconditionally targets getOffsetToReveal(object, alignment) and re-aligns the item to 30% of the viewport on every call. The code being replaced was conditional (itemOffset < visibleStart || itemOffset > visibleEnd - estimated); the new block is not, so the list now re-animates on every cue change and snaps back while the user is browsing manually. Restore the condition (measure the item's RenderBox against the viewport rect before calling, or pass ScrollPositionAlignmentPolicy.keepVisibleAtStart), or document the new follow-playback behaviour as intentional.

Minor: cupertino_subtitle_list_pane.dart:197-199 does .clamp(0, _visibleEntries.length - 1); if _visibleEntries is ever empty this throws ArgumentError (num.clamp requires lowerLimit <= upperLimit). The nipaplay twin guards this at subtitle_list_menu.dart:289 - please add the same guard for parity. Also, the retry in step 3 (cupertino:231-243, nipaplay:322-334) has no further retry, so if the keyed item is still unbuilt the highlight can stay off-screen until the next window change, since the inline ensureVisible only fires when localIndex != _currentLocalIndex.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants