Skip to content

Commit

Permalink
Merge pull request #1317 from dennis531/jump-segment
Browse files Browse the repository at this point in the history
Controls to jump to next or previous segment
  • Loading branch information
lkiesow authored May 6, 2024
2 parents ffbcbe0 + eefde50 commit fbae57c
Show file tree
Hide file tree
Showing 9 changed files with 209 additions and 8 deletions.
8 changes: 8 additions & 0 deletions src/globalKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ export const KEYMAP: IKeyMap = {
name: "keyboardControls.videoPlayButton",
key: "Shift+Alt+Space, Space",
},
previous: {
name: "video.previousButton",
key: "Shift+Alt+Left",
},
next: {
name: "video.nextButton",
key: "Shift+Alt+Right",
},
preview: {
name: "video.previewButton",
key: "Shift+Alt+p",
Expand Down
4 changes: 4 additions & 0 deletions src/i18n/locales/de-DE.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@
"previewButton-aria": "Vorschaumodus aktivieren oder deaktivieren. Hotkey: {{hotkeyName}}.",
"playButton-tooltip": "Video wiedergeben",
"pauseButton-tooltip": "Video pausieren",
"previousButton": "Zurück",
"previousButton-tooltip": "Zurück. Hotkey: {{hotkeyName}}.",
"nextButton": "Weiter",
"nextButton-tooltip": "Weiter. Hotkey: {{hotkeyName}}.",
"current-time-tooltip": "Aktuelle Zeit",
"time-duration-tooltip": "Videodauer",
"duration-aria": "Dauer",
Expand Down
4 changes: 4 additions & 0 deletions src/i18n/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@
"previewButton-aria": "Enable or disable preview mode. Hotkey: {{hotkeyName}}.",
"playButton-tooltip": "Play video",
"pauseButton-tooltip": "Pause video",
"previousButton": "Back",
"previousButton-tooltip": "Back. Hotkey: {{hotkeyName}}.",
"nextButton": "Forward",
"nextButton-tooltip": "Forward. Hotkey: {{hotkeyName}}.",
"current-time-tooltip": "Current time",
"time-duration-tooltip": "Video duration",
"duration-aria": "Duration",
Expand Down
4 changes: 4 additions & 0 deletions src/main/Cutting.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import {
setIsMuted,
setVolume,
setIsPlayPreview,
jumpToPreviousSegment,
jumpToNextSegment,
} from "../redux/videoSlice";
import { useTranslation } from "react-i18next";
import { useAppDispatch, useAppSelector } from "../redux/store";
Expand Down Expand Up @@ -108,6 +110,8 @@ const Cutting: React.FC = () => {
setIsMuted={setIsMuted}
setVolume={setVolume}
setIsPlayPreview={setIsPlayPreview}
jumpToPreviousSegment={jumpToPreviousSegment}
jumpToNextSegment={jumpToNextSegment}
/>
</div>
</div>
Expand Down
12 changes: 11 additions & 1 deletion src/main/SubtitleVideoArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,15 @@ import {
setIsPlayPreview,
setCurrentlyAtAndTriggerPreview,
} from "../redux/subtitleSlice";
import { selectIsMuted, selectVideos, selectVolume, setIsMuted, setVolume } from "../redux/videoSlice";
import {
selectIsMuted,
selectVideos,
selectVolume,
selectJumpTriggered,
setIsMuted,
setVolume,
setJumpTriggered,
} from "../redux/videoSlice";
import { Flavor } from "../types";
import { settings } from "../config";
import { useTranslation } from "react-i18next";
Expand Down Expand Up @@ -128,11 +136,13 @@ const SubtitleVideoArea: React.FC = () => {
selectCurrentlyAtInSeconds={selectCurrentlyAtInSeconds}
selectPreviewTriggered={selectPreviewTriggered}
selectClickTriggered={selectClickTriggered}
selectJumpTriggered={selectJumpTriggered}
selectAspectRatio={selectAspectRatio}
setIsPlaying={setIsPlaying}
selectVolume={selectVolume}
setPreviewTriggered={setPreviewTriggered}
setClickTriggered={setClickTriggered}
setJumpTriggered={setJumpTriggered}
setCurrentlyAt={setCurrentlyAtAndTriggerPreview}
setAspectRatio={setAspectRatio}
/>
Expand Down
4 changes: 4 additions & 0 deletions src/main/Thumbnail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ import {
setIsMuted,
setVolume,
setCurrentlyAt,
jumpToPreviousSegment,
jumpToNextSegment,
} from "../redux/videoSlice";
import { ThemedTooltip } from "./Tooltip";
import VideoPlayers, { VideoPlayerForwardRef } from "./VideoPlayers";
Expand Down Expand Up @@ -149,6 +151,8 @@ const Thumbnail: React.FC = () => {
setIsMuted={setIsMuted}
setVolume={setVolume}
setIsPlayPreview={setIsPlayPreview}
jumpToPreviousSegment={jumpToPreviousSegment}
jumpToNextSegment={jumpToNextSegment}
/>
</div>
</div>
Expand Down
101 changes: 99 additions & 2 deletions src/main/VideoControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import React from "react";
import { css } from "@emotion/react";

import { FaToggleOn, FaToggleOff } from "react-icons/fa";
import { LuPlay, LuPause, LuVolume2, LuVolumeX } from "react-icons/lu";
import { LuPlay, LuPause, LuVolume2, LuVolumeX, LuSkipBack, LuSkipForward } from "react-icons/lu";

import { useAppDispatch, useAppSelector } from "../redux/store";
import {
Expand All @@ -17,7 +17,7 @@ import { KEYMAP, rewriteKeys } from "../globalKeys";
import { useTranslation } from "react-i18next";

import { RootState } from "../redux/store";
import { ActionCreatorWithPayload } from "@reduxjs/toolkit";
import { ActionCreatorWithoutPayload, ActionCreatorWithPayload } from "@reduxjs/toolkit";

import { ThemedTooltip } from "./Tooltip";
import { Theme, useTheme } from "../themes";
Expand All @@ -38,6 +38,8 @@ const VideoControls: React.FC<{
setIsMuted: ActionCreatorWithPayload<boolean, string>,
setVolume: ActionCreatorWithPayload<number, string>,
setIsPlayPreview: ActionCreatorWithPayload<boolean, string>,
jumpToPreviousSegment?: ActionCreatorWithoutPayload<string>,
jumpToNextSegment?: ActionCreatorWithoutPayload<string>,
}> = ({
selectCurrentlyAt,
selectIsPlaying,
Expand All @@ -48,6 +50,8 @@ const VideoControls: React.FC<{
setIsMuted,
setVolume,
setIsPlayPreview,
jumpToPreviousSegment = undefined,
jumpToNextSegment = undefined,
}) => {

const theme = useTheme();
Expand All @@ -71,10 +75,20 @@ const VideoControls: React.FC<{
<TimeDisplay
selectCurrentlyAt={selectCurrentlyAt}
/>
{jumpToPreviousSegment && (
<PreviousButton
jumpToPreviousSegment={jumpToPreviousSegment}
/>
)}
<PlayButton
selectIsPlaying={selectIsPlaying}
setIsPlaying={setIsPlaying}
/>
{jumpToNextSegment && (
<NextButton
jumpToNextSegment={jumpToNextSegment}
/>
)}
<VolumeSlider
selectIsMuted={selectIsMuted}
setIsMuted={setIsMuted}
Expand Down Expand Up @@ -234,6 +248,89 @@ const PlayButton: React.FC<{
);
};

/**
* Jump to previous segment
*/
const PreviousButton: React.FC<{
jumpToPreviousSegment: ActionCreatorWithoutPayload<string>,
}> = ({
jumpToPreviousSegment,
}) => {

const { t } = useTranslation();

const dispatch = useAppDispatch();
const theme = useTheme();

const jumpToPrevious = () => {
dispatch(jumpToPreviousSegment());
};

useHotkeys(KEYMAP.videoPlayer.previous.key, () => jumpToPrevious(), { preventDefault: true });

const previousIconStyle = css({
fontSize: 24,
});

return (
<ThemedTooltip title={t("video.previousButton-tooltip", {
hotkeyName: rewriteKeys(KEYMAP.videoPlayer.previous.key),
})}>
<div css={[basicButtonStyle(theme)]}
role="button" tabIndex={0} aria-hidden={false}
aria-label={t("video.previousButton-tooltip", { hotkeyName: rewriteKeys(KEYMAP.videoPlayer.previous.key) })}
onClick={jumpToPrevious}
onKeyDown={(event: React.KeyboardEvent) => {
if (event.key === "Enter") {
jumpToPrevious();
}
}}>
<LuSkipBack css={previousIconStyle} />
</div>
</ThemedTooltip>
);
};

/**
* Jump to next segment
*/
const NextButton: React.FC<{
jumpToNextSegment: ActionCreatorWithoutPayload<string>,
}> = ({
jumpToNextSegment,
}) => {
const { t } = useTranslation();

const dispatch = useAppDispatch();
const theme = useTheme();

const jumpToNext = () => {
dispatch(jumpToNextSegment());
};

useHotkeys(KEYMAP.videoPlayer.next.key, () => jumpToNext(), { preventDefault: true });

const nextIconStyle = css({
fontSize: 24,
});

return (
<ThemedTooltip title={t("video.nextButton-tooltip", { hotkeyName: rewriteKeys(KEYMAP.videoPlayer.next.key) })}>
<div css={[basicButtonStyle(theme)]}
role="button" tabIndex={0} aria-hidden={false}
aria-label={t("video.nextButton-tooltip", { hotkeyName: rewriteKeys(KEYMAP.videoPlayer.next.key) })}
onClick={jumpToNext}
onKeyDown={(event: React.KeyboardEvent) => {
if (event.key === "Enter") {
jumpToNext();
}
}}>
<LuSkipForward css={nextIconStyle} />
</div>
</ThemedTooltip>
);
};

/**
* Live update for the current time
*/
Expand Down
12 changes: 12 additions & 0 deletions src/main/VideoPlayers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import {
selectAspectRatio,
setClickTriggered,
selectClickTriggered,
setJumpTriggered,
selectJumpTriggered,
setCurrentlyAt,
} from "../redux/videoSlice";

Expand Down Expand Up @@ -80,10 +82,12 @@ const VideoPlayers: React.FC<{
selectCurrentlyAtInSeconds={selectCurrentlyAtInSeconds}
selectPreviewTriggered={selectPreviewTriggered}
selectClickTriggered={selectClickTriggered}
selectJumpTriggered={selectJumpTriggered}
selectAspectRatio={selectAspectRatio}
setIsPlaying={setIsPlaying}
setPreviewTriggered={setPreviewTriggered}
setClickTriggered={setClickTriggered}
setJumpTriggered={setJumpTriggered}
setCurrentlyAt={setCurrentlyAt}
setAspectRatio={setAspectRatio}
ref={el => {
Expand Down Expand Up @@ -119,10 +123,12 @@ interface VideoPlayerProps {
selectCurrentlyAtInSeconds: (state: RootState) => number,
selectPreviewTriggered: (state: RootState) => boolean,
selectClickTriggered: (state: RootState) => boolean,
selectJumpTriggered: (state: RootState) => boolean,
selectAspectRatio: (state: RootState) => number,
setIsPlaying: ActionCreatorWithPayload<boolean, string>,
setPreviewTriggered: ActionCreatorWithPayload<boolean, string>,
setClickTriggered: ActionCreatorWithPayload<boolean, string>,
setJumpTriggered: ActionCreatorWithPayload<boolean, string>,
setCurrentlyAt: ActionCreatorWithPayload<number, string> | AsyncThunk<void, number, AsyncThunkConfig>,
setAspectRatio: ActionCreatorWithPayload<{ dataKey: number; } & { width: number, height: number; }, string>,
}
Expand All @@ -147,6 +153,7 @@ export const VideoPlayer = React.forwardRef<VideoPlayerForwardRef, VideoPlayerPr
selectCurrentlyAtInSeconds,
selectPreviewTriggered,
selectClickTriggered,
selectJumpTriggered,
selectAspectRatio,
setIsPlaying,
setPreviewTriggered,
Expand All @@ -166,6 +173,7 @@ export const VideoPlayer = React.forwardRef<VideoPlayerForwardRef, VideoPlayerPr
const duration = useAppSelector(selectDurationInSeconds);
const previewTriggered = useAppSelector(selectPreviewTriggered);
const clickTriggered = useAppSelector(selectClickTriggered);
const jumpTriggered = useAppSelector(selectJumpTriggered);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const aspectRatio = useAppSelector(selectAspectRatio);
const theme = useTheme();
Expand Down Expand Up @@ -247,6 +255,10 @@ export const VideoPlayer = React.forwardRef<VideoPlayerForwardRef, VideoPlayerPr
ref.current.seekTo(currentlyAt, "seconds");
dispatch(setClickTriggered(false));
}
if (jumpTriggered && ref.current && ready) {
ref.current.seekTo(currentlyAt, "seconds");
dispatch(setJumpTriggered(false));
}
});

useEffect(() => {
Expand Down
Loading

0 comments on commit fbae57c

Please sign in to comment.