This commit is contained in:
Isra 2023-04-14 14:11:13 -05:00
parent c330112dbc
commit 41fd23cf20
5 changed files with 48 additions and 28 deletions

View File

@ -3,6 +3,9 @@ import { useTranslation } from "react-i18next";
import { useMediaPlaying } from "@/video/state/logic/mediaplaying"; import { useMediaPlaying } from "@/video/state/logic/mediaplaying";
import { useProgress } from "@/video/state/logic/progress"; import { useProgress } from "@/video/state/logic/progress";
import { useInterface } from "@/video/state/logic/interface"; import { useInterface } from "@/video/state/logic/interface";
import { VideoPlayerTimeFormat } from "@/video/state/types";
import { useIsMobile } from "@/hooks/useIsMobile";
import { useControls } from "@/video/state/logic/controls";
function durationExceedsHour(secs: number): boolean { function durationExceedsHour(secs: number): boolean {
return secs > 60 * 60; return secs > 60 * 60;
@ -40,19 +43,20 @@ export function TimeAction(props: Props) {
const videoTime = useProgress(descriptor); const videoTime = useProgress(descriptor);
const mediaPlaying = useMediaPlaying(descriptor); const mediaPlaying = useMediaPlaying(descriptor);
const { timeFormat, setTimeFormat } = useInterface(descriptor); const { timeFormat, setTimeFormat } = useInterface(descriptor);
const { isMobile } = useIsMobile();
const { t } = useTranslation(); const { t } = useTranslation();
const hasHours = durationExceedsHour(videoTime.duration); const hasHours = durationExceedsHour(videoTime.duration);
const time = formatSeconds(
const currentTime = formatSeconds(
mediaPlaying.isDragSeeking ? videoTime.draggingTime : videoTime.time, mediaPlaying.isDragSeeking ? videoTime.draggingTime : videoTime.time,
hasHours hasHours
); );
const duration = formatSeconds(videoTime.duration, hasHours); const duration = formatSeconds(videoTime.duration, hasHours);
const timeLeft = formatSeconds( const timeLeft = formatSeconds(
(videoTime.duration - videoTime.time) / mediaPlaying.playbackSpeed (videoTime.duration - videoTime.time) / mediaPlaying.playbackSpeed,
hasHours
); );
const timeFinished = new Date( const timeFinished = new Date(
new Date().getTime() + new Date().getTime() +
(videoTime.duration * 1000) / mediaPlaying.playbackSpeed (videoTime.duration * 1000) / mediaPlaying.playbackSpeed
@ -61,15 +65,38 @@ export function TimeAction(props: Props) {
minute: "numeric", minute: "numeric",
hour12: true, hour12: true,
}); });
const formattedTimeFinished = ` - ${t("videoPlayer.finishAt", {
timeFinished,
})}`;
let formattedTime: string;
if (timeFormat === VideoPlayerTimeFormat.REGULAR) {
formattedTime = `${currentTime} ${props.noDuration ? "" : `/ ${duration}`}`;
} else if (timeFormat === VideoPlayerTimeFormat.REMAINING) {
formattedTime = `${t("videoPlayer.timeLeft", {
timeLeft,
})}${
videoTime.time === videoTime.duration || isMobile
? ""
: formattedTimeFinished
} `;
} else {
formattedTime = "";
}
return ( return (
<button <button
type="button" type="button"
className={[ className={[
"group pointer-events-auto translate-x-[-16px] text-white transition-transform duration-100 active:scale-110", "group pointer-events-auto text-white transition-transform duration-100 active:scale-110",
].join(" ")} ].join(" ")}
onClick={() => { onClick={() => {
setTimeFormat(timeFormat === 0 ? 1 : 0); setTimeFormat(
timeFormat === VideoPlayerTimeFormat.REGULAR
? VideoPlayerTimeFormat.REMAINING
: VideoPlayerTimeFormat.REGULAR
);
}} }}
> >
<div <div
@ -78,20 +105,7 @@ export function TimeAction(props: Props) {
].join(" ")} ].join(" ")}
> >
<div className={props.className}> <div className={props.className}>
<p className="select-none text-white"> <p className="select-none text-white">{formattedTime}</p>
{/* {time} {props.noDuration ? "" : `/ ${duration}`} */}
{timeFormat === 0
? `${time} ${props.noDuration ? "" : `/ ${duration}`}`
: `${t("videoPlayer.timeLeft", {
timeLeft,
})}${
videoTime.time === videoTime.duration
? ""
: ` - ${t("videoPlayer.finishAt", {
timeFinished,
})}`
} `}
</p>
</div> </div>
</div> </div>
</button> </button>

View File

@ -1,7 +1,7 @@
import { updateInterface } from "@/video/state/logic/interface"; import { updateInterface } from "@/video/state/logic/interface";
import { updateMeta } from "@/video/state/logic/meta"; import { updateMeta } from "@/video/state/logic/meta";
import { updateProgress } from "@/video/state/logic/progress"; import { updateProgress } from "@/video/state/logic/progress";
import { VideoPlayerMeta } from "@/video/state/types"; import { VideoPlayerMeta, VideoPlayerTimeFormat } from "@/video/state/types";
import { getPlayerState } from "../cache"; import { getPlayerState } from "../cache";
import { VideoPlayerStateController } from "../providers/providerTypes"; import { VideoPlayerStateController } from "../providers/providerTypes";
@ -15,7 +15,7 @@ export type ControlMethods = {
setDraggingTime(num: number): void; setDraggingTime(num: number): void;
togglePictureInPicture(): void; togglePictureInPicture(): void;
setPlaybackSpeed(num: number): void; setPlaybackSpeed(num: number): void;
setTimeFormat(num: 0 | 1): void; setTimeFormat(num: VideoPlayerTimeFormat): void;
}; };
export function useControls( export function useControls(

View File

@ -1,7 +1,7 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { getPlayerState } from "../cache"; import { getPlayerState } from "../cache";
import { listenEvent, sendEvent, unlistenEvent } from "../events"; import { listenEvent, sendEvent, unlistenEvent } from "../events";
import { VideoPlayerState } from "../types"; import { VideoPlayerState, VideoPlayerTimeFormat } from "../types";
export type VideoInterfaceEvent = { export type VideoInterfaceEvent = {
popout: string | null; popout: string | null;
@ -9,8 +9,8 @@ export type VideoInterfaceEvent = {
isFocused: boolean; isFocused: boolean;
isFullscreen: boolean; isFullscreen: boolean;
popoutBounds: null | DOMRect; popoutBounds: null | DOMRect;
timeFormat: 0 | 1 | 2; timeFormat: VideoPlayerTimeFormat;
setTimeFormat(timeFormat: 0 | 1 | 2): void; setTimeFormat(timeFormat: VideoPlayerTimeFormat): void;
}; };
function getInterfaceFromState(state: VideoPlayerState): VideoInterfaceEvent { function getInterfaceFromState(state: VideoPlayerState): VideoInterfaceEvent {
@ -21,7 +21,7 @@ function getInterfaceFromState(state: VideoPlayerState): VideoInterfaceEvent {
isFullscreen: state.interface.isFullscreen, isFullscreen: state.interface.isFullscreen,
popoutBounds: state.interface.popoutBounds, popoutBounds: state.interface.popoutBounds,
timeFormat: state.interface.timeFormat, timeFormat: state.interface.timeFormat,
setTimeFormat(timeFormat: 0 | 1 | 2) { setTimeFormat(timeFormat: VideoPlayerTimeFormat) {
state.stateProvider?.setTimeFormat(timeFormat); state.stateProvider?.setTimeFormat(timeFormat);
}, },
}; };

View File

@ -1,4 +1,5 @@
import { MWStreamQuality, MWStreamType } from "@/backend/helpers/streams"; import { MWStreamQuality, MWStreamType } from "@/backend/helpers/streams";
import { VideoPlayerTimeFormat } from "@/video/state/types";
type VideoPlayerSource = { type VideoPlayerSource = {
source: string; source: string;
@ -23,7 +24,7 @@ export type VideoPlayerStateController = {
getId(): string; getId(): string;
togglePictureInPicture(): void; togglePictureInPicture(): void;
setPlaybackSpeed(num: number): void; setPlaybackSpeed(num: number): void;
setTimeFormat(format: 0 | 1 | 2): void; setTimeFormat(timeFormat: VideoPlayerTimeFormat): void;
}; };
export type VideoPlayerStateProvider = VideoPlayerStateController & { export type VideoPlayerStateProvider = VideoPlayerStateController & {

View File

@ -22,6 +22,11 @@ export type VideoPlayerMeta = {
}[]; }[];
}; };
export enum VideoPlayerTimeFormat {
REGULAR = 0,
REMAINING = 1,
}
export type VideoPlayerState = { export type VideoPlayerState = {
// state related to the user interface // state related to the user interface
interface: { interface: {
@ -30,7 +35,7 @@ export type VideoPlayerState = {
isFocused: boolean; // is the video player the users focus? (shortcuts only works when its focused) isFocused: boolean; // is the video player the users focus? (shortcuts only works when its focused)
leftControlHovering: boolean; // is the cursor hovered over the left side of player controls leftControlHovering: boolean; // is the cursor hovered over the left side of player controls
popoutBounds: null | DOMRect; // bounding box of current popout popoutBounds: null | DOMRect; // bounding box of current popout
timeFormat: 0 | 1 | 2; // Time format of the video player timeFormat: VideoPlayerTimeFormat; // Time format of the video player
}; };
// state related to the playing state of the media // state related to the playing state of the media