Time format

This commit is contained in:
Isra 2023-04-11 16:16:06 -05:00
parent 3decc9190c
commit 84b8a67cea
8 changed files with 65 additions and 5 deletions

View File

@ -1,6 +1,7 @@
import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useVideoPlayerDescriptor } from "@/video/state/hooks";
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";
function durationExceedsHour(secs: number): boolean { function durationExceedsHour(secs: number): boolean {
return secs > 60 * 60; return secs > 60 * 60;
@ -37,6 +38,7 @@ export function TimeAction(props: Props) {
const descriptor = useVideoPlayerDescriptor(); const descriptor = useVideoPlayerDescriptor();
const videoTime = useProgress(descriptor); const videoTime = useProgress(descriptor);
const mediaPlaying = useMediaPlaying(descriptor); const mediaPlaying = useMediaPlaying(descriptor);
const { timeFormat, setTimeFormat } = useInterface(descriptor);
const hasHours = durationExceedsHour(videoTime.duration); const hasHours = durationExceedsHour(videoTime.duration);
const time = formatSeconds( const time = formatSeconds(
@ -45,11 +47,47 @@ export function TimeAction(props: Props) {
); );
const duration = formatSeconds(videoTime.duration, hasHours); const duration = formatSeconds(videoTime.duration, hasHours);
const timeLeft = formatSeconds(
(videoTime.duration - videoTime.time) / mediaPlaying.playbackSpeed
);
const timeFinished = new Date(
new Date().getTime() +
(videoTime.duration * 1000) / mediaPlaying.playbackSpeed
).toLocaleTimeString("en-US", {
hour: "numeric",
minute: "numeric",
hour12: true,
});
return ( return (
<button
type="button"
className={[
"group pointer-events-auto translate-x-[-16px] text-white transition-transform duration-100 active:scale-110",
].join(" ")}
onClick={() => {
setTimeFormat(timeFormat === 0 ? 1 : 0);
}}
>
<div
className={[
"flex items-center justify-center rounded-full bg-denim-600 bg-opacity-0 p-2 transition-colors duration-100 group-hover:bg-opacity-50 group-active:bg-denim-500 group-active:bg-opacity-100 sm:px-4",
].join(" ")}
>
<div className={props.className}> <div className={props.className}>
<p className="select-none text-white"> <p className="select-none text-white">
{time} {props.noDuration ? "" : `/ ${duration}`} {/* {time} {props.noDuration ? "" : `/ ${duration}`} */}
{timeFormat === 0
? `${time} ${props.noDuration ? "" : `/ ${duration}`}`
: `${timeLeft} left${
videoTime.time === videoTime.duration
? ""
: ` - finish at ${timeFinished}`
} `}
</p> </p>
</div> </div>
</div>
</button>
); );
} }

View File

@ -32,6 +32,7 @@ function initPlayer(): VideoPlayerState {
isFocused: false, isFocused: false,
leftControlHovering: false, leftControlHovering: false,
popoutBounds: null, popoutBounds: null,
timeFormat: 0,
}, },
mediaPlaying: { mediaPlaying: {

View File

@ -15,6 +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;
}; };
export function useControls( export function useControls(
@ -110,5 +111,9 @@ export function useControls(
state.stateProvider?.setPlaybackSpeed(num); state.stateProvider?.setPlaybackSpeed(num);
updateInterface(descriptor, state); updateInterface(descriptor, state);
}, },
setTimeFormat(format) {
state.interface.timeFormat = format;
updateInterface(descriptor, state);
},
}; };
} }

View File

@ -9,6 +9,8 @@ export type VideoInterfaceEvent = {
isFocused: boolean; isFocused: boolean;
isFullscreen: boolean; isFullscreen: boolean;
popoutBounds: null | DOMRect; popoutBounds: null | DOMRect;
timeFormat: 0 | 1 | 2;
setTimeFormat(timeFormat: 0 | 1 | 2): void;
}; };
function getInterfaceFromState(state: VideoPlayerState): VideoInterfaceEvent { function getInterfaceFromState(state: VideoPlayerState): VideoInterfaceEvent {
@ -18,6 +20,10 @@ function getInterfaceFromState(state: VideoPlayerState): VideoInterfaceEvent {
isFocused: state.interface.isFocused, isFocused: state.interface.isFocused,
isFullscreen: state.interface.isFullscreen, isFullscreen: state.interface.isFullscreen,
popoutBounds: state.interface.popoutBounds, popoutBounds: state.interface.popoutBounds,
timeFormat: state.interface.timeFormat,
setTimeFormat(timeFormat: 0 | 1 | 2) {
state.stateProvider?.setTimeFormat(timeFormat);
},
}; };
} }

View File

@ -173,6 +173,10 @@ export function createCastingStateProvider(
updateSource(descriptor, state); updateSource(descriptor, state);
} }
}, },
setTimeFormat(format) {
state.interface.timeFormat = format;
updateInterface(descriptor, state);
},
providerStart() { providerStart() {
this.setVolume(getStoredVolume()); this.setVolume(getStoredVolume());

View File

@ -23,6 +23,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;
}; };
export type VideoPlayerStateProvider = VideoPlayerStateController & { export type VideoPlayerStateProvider = VideoPlayerStateController & {

View File

@ -133,6 +133,10 @@ export function createVideoStateProvider(
// update localstorage // update localstorage
setStoredVolume(volume); setStoredVolume(volume);
}, },
setTimeFormat(num) {
state.interface.timeFormat = num;
updateInterface(descriptor, state);
},
setSource(source) { setSource(source) {
if (!source) { if (!source) {
resetStateForSource(descriptor, state); resetStateForSource(descriptor, state);

View File

@ -30,6 +30,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
}; };
// state related to the playing state of the media // state related to the playing state of the media