refactor(player): centralize chapter traversal

This commit is contained in:
edde746
2026-07-12 08:42:20 +02:00
parent 9da047de70
commit cdec9d1514
5 changed files with 69 additions and 54 deletions
@@ -1054,28 +1054,14 @@ class DesktopVideoControlsState extends State<DesktopVideoControls> {
/// Returns the label of the next chapter the user would seek to, or null.
String? _getNextChapterLabel(Duration position) {
if (widget.chapters.isEmpty) return null;
final currentPositionMs = position.inMilliseconds;
for (final chapter in widget.chapters) {
final chapterStart = chapter.startTimeOffset ?? 0;
if (chapterStart > currentPositionMs) {
return chapter.label;
}
}
return null;
final index = MediaChapter.seekTargetIndex(position, widget.chapters, forward: true);
return index == null ? null : widget.chapters[index].label;
}
/// Returns the label of the previous chapter the user would seek to, or null.
String? _getPreviousChapterLabel(Duration position) {
if (widget.chapters.isEmpty) return null;
final currentPositionMs = position.inMilliseconds;
for (int i = widget.chapters.length - 1; i >= 0; i--) {
final chapterStart = widget.chapters[i].startTimeOffset ?? 0;
if (currentPositionMs > chapterStart + 3000) {
return widget.chapters[i].label;
}
}
return null;
final index = MediaChapter.seekTargetIndex(position, widget.chapters, forward: false);
return index == null ? null : widget.chapters[index].label;
}
Widget _buildFocusableButton({
@@ -31,25 +31,10 @@ extension _PlexVideoControlsPlaybackInputMethods on _PlexVideoControlsState {
return;
}
final currentPositionMs = widget.player.state.position.inMilliseconds;
if (forward) {
for (final chapter in _chapters) {
final chapterStart = chapter.startTimeOffset ?? 0;
if (chapterStart > currentPositionMs) {
await _seekToPosition(Duration(milliseconds: chapterStart));
return;
}
}
} else {
for (int i = _chapters.length - 1; i >= 0; i--) {
final chapterStart = _chapters[i].startTimeOffset ?? 0;
if (currentPositionMs > chapterStart + 3000) {
// If more than 3 seconds into chapter, go to start of current chapter
await _seekToPosition(Duration(milliseconds: chapterStart));
return;
}
}
final targetIndex = MediaChapter.seekTargetIndex(widget.player.state.position, _chapters, forward: forward);
if (targetIndex != null) {
await _seekToPosition(_chapters[targetIndex].startTime);
} else if (!forward) {
await _seekToPosition(Duration.zero);
}
}
@@ -110,7 +110,7 @@ class ContentStripState extends State<ContentStrip> {
/// Request focus on the current chapter or queue item (called by parent when strip appears).
void requestInitialFocus() {
if (_activeTab == _StripTab.chapters && _chapterFocusNodes.isNotEmpty) {
final currentIndex = _getCurrentChapterIndex();
final currentIndex = MediaChapter.indexAtPosition(widget.player.state.position, widget.chapters);
final idx = (currentIndex ?? 0).clamp(0, _chapterFocusNodes.length - 1);
_chapterFocusNodes[idx].requestFocus();
_scrollToFocusedNode(_chapterFocusNodes[idx]);
@@ -122,21 +122,6 @@ class ContentStripState extends State<ContentStrip> {
}
}
int? _getCurrentChapterIndex() {
final currentPositionMs = widget.player.state.position.inMilliseconds;
for (int i = 0; i < widget.chapters.length; i++) {
final chapter = widget.chapters[i];
final startMs = chapter.startTimeOffset ?? 0;
final endMs =
chapter.endTimeOffset ??
(i < widget.chapters.length - 1 ? widget.chapters[i + 1].startTimeOffset ?? 0 : double.maxFinite.toInt());
if (currentPositionMs >= startMs && currentPositionMs < endMs) {
return i;
}
}
return null;
}
Future<void> _handleChapterTap(Duration position) async {
final clamped = clampSeekPosition(widget.player, position);
await (widget.onSeekRequested ?? widget.player.seek)(clamped);
@@ -226,7 +211,8 @@ class ContentStripState extends State<ContentStrip> {
});
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted && _chapterFocusNodes.isNotEmpty) {
final idx = (_getCurrentChapterIndex() ?? 0).clamp(0, _chapterFocusNodes.length - 1);
final currentIndex = MediaChapter.indexAtPosition(widget.player.state.position, widget.chapters);
final idx = (currentIndex ?? 0).clamp(0, _chapterFocusNodes.length - 1);
_chapterFocusNodes[idx].requestFocus();
_scrollToFocusedNode(_chapterFocusNodes[idx]);
}