Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions templates/clips/app/components/player/video-player.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,32 @@ describe("VideoPlayer playback", () => {
expect(video.paused).toBe(false);
});

it("replays from the start when the surface is clicked after the clip ended", () => {
const surface = getPlayerSurface();
const video = getVideo();

act(() => {
surface.click();
});
expect(video.paused).toBe(false);

// Reaching end of stream can fire "ended" while the browser leaves paused
// false (MSE end-of-stream / DB-duration mismatch). The play button must
// still restart from the beginning rather than pausing a finished clip.
video.currentTime = 10;
Object.defineProperty(video, "ended", { configurable: true, value: true });
act(() => {
video.dispatchEvent(new Event("ended"));
});

act(() => {
surface.click();
});

expect(video.currentTime).toBe(0);
expect(video.paused).toBe(false);
});

it("suppresses the synthetic click that follows a touch tap instead of double-toggling playback", () => {
const surface = getPlayerSurface();
const video = getVideo();
Expand Down
14 changes: 10 additions & 4 deletions templates/clips/app/components/player/video-player.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -598,17 +598,23 @@ export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
const togglePlayback = useCallback(() => {
const v = videoRef.current;
if (!v) return;
if (!v.paused || isPlaying) {
pauseVideo();
return;
}
// A finished clip must always replay from the start, even when the browser
// left `paused` false at end of stream (MSE end-of-stream / DB-duration
// mismatch) or `isPlaying` is stale — otherwise the toggle below would
// pause an already-ended element and the play button appears to do nothing.
if (v.ended) {
try {
v.currentTime = 0;
setCurrentMs(0);
} catch {
// Let the normal play attempt report a media error if the seek fails.
}
requestPlay();
return;
}
if (!v.paused || isPlaying) {
pauseVideo();
return;
}
requestPlay();
}, [isPlaying, pauseVideo, requestPlay]);
Expand Down
Loading