mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-07-12 23:42:55 +01:00
feat(player): wire chapter UI into native player controls
Threads chapters + duration through Controls -> BottomControls so the ChapterTicks overlay, ChapterList modal and current-chapter label have the data they need. BottomControls - Memoizes chapterMarkerList (markers within the media duration) once per (chapters, durationMs) change and feeds it to ChapterTicks. - hasChapters gates the bookmark icon + list modal; nothing renders when chapters are missing or below two real markers. - Current chapter name shown as a small label below the title/year during playback; the same helper feeds the trickplay bubble while scrubbing. Both labels disappear gracefully when chapters are absent. useVideoSlider - Adds seekTo(value): a programmatic seek for non-gesture entry points (chapter list, hot-keys). Reads isPlaying directly instead of wasPlayingRef — which is only populated inside handleSliderStart, so a tap-to-seek on the chapter list previously either stranded paused playback or auto-resumed against a manual pause. TrickplayBubble - Adds an optional chapterName prop; renders a small left-aligned overlay inside the preview frame (Jellyfin web style) showing chapter name above the timestamp. Hides the chapter line entirely when null. - zIndex + elevation so the bubble lands in front of the title / surrounding overlays. - Slight reposition (bottom -20, paddingTop 12) brings the bubble closer to the slider. translations/en.json - chapters.title / chapters.chapter_number / chapters.open / chapters.close keys for the list modal and the bookmark a11y label.
This commit is contained in:
@@ -74,6 +74,21 @@ export function useVideoSlider({
|
||||
[seek, play, progress, isSeeking],
|
||||
);
|
||||
|
||||
// Programmatic seek (chapter list, hotkeys) that bypasses the slide gesture.
|
||||
// Reads `isPlaying` directly instead of `wasPlayingRef`, which is only set
|
||||
// during a real slide and would carry stale state on a tap-to-seek.
|
||||
const seekTo = useCallback(
|
||||
(value: number) => {
|
||||
const seekValue = Math.max(0, Math.floor(value));
|
||||
progress.value = seekValue;
|
||||
seek(seekValue);
|
||||
if (isPlaying) {
|
||||
play();
|
||||
}
|
||||
},
|
||||
[seek, play, progress, isPlaying],
|
||||
);
|
||||
|
||||
const handleSliderChange = useCallback(
|
||||
debounce((value: number) => {
|
||||
// Convert ms to ticks for trickplay
|
||||
@@ -96,5 +111,6 @@ export function useVideoSlider({
|
||||
handleTouchEnd,
|
||||
handleSliderComplete,
|
||||
handleSliderChange,
|
||||
seekTo,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user