Web:Common:Components:MediaViewer:Sub-Components:Added PlayerSpeedControl component

This commit is contained in:
Akmal Isomadinov 2023-03-17 23:56:36 +05:00
parent 23dce50628
commit 89f889e388
3 changed files with 237 additions and 0 deletions

View File

@ -0,0 +1,11 @@
export interface PlayerSpeedControlProps {
handleSpeedChange: (speed: number) => void;
onMouseLeave: VoidFunction;
src?: string;
}
export type SpeedType = ["X0.5", "X1", "X1.5", "X2"];
export type SpeedRecord<T extends SpeedType> = {
[Key in T[number]]: number;
};

View File

@ -0,0 +1,89 @@
import styled from "styled-components";
export const SpeedControlWrapper = styled.div`
position: relative;
display: flex;
justify-content: center;
align-items: center;
width: 48px;
height: 48px;
&:hover {
cursor: pointer;
}
svg {
path {
fill: #fff;
}
}
rect {
stroke: #fff;
}
`;
export const DropDown = styled.div`
display: flex;
flex-direction: column;
align-items: center;
height: 120px;
width: 48px;
padding: 4px 0px;
position: absolute;
bottom: 48px;
z-index: 50;
color: #fff;
background: #333;
text-align: center;
border-radius: 7px 7px 0px 0px;
`;
export const DropDownItem = styled.div`
display: flex;
align-items: center;
justify-content: center;
height: 30px;
width: 48px;
&:hover {
cursor: pointer;
background: #222;
}
`;
export const ToastSpeed = styled.div`
position: fixed;
top: 50%;
left: 50%;
display: flex;
justify-content: center;
align-items: center;
width: 72px;
height: 56px;
border-radius: 9px;
visibility: visible;
transform: translate(-50%, -50%);
background-color: rgba(51, 51, 51, 0.65);
svg {
width: 46px;
height: 46px;
path {
fill: #fff;
}
}
rect {
stroke: #fff;
}
`;

View File

@ -0,0 +1,137 @@
import React, { memo, useEffect, useRef, useState } from "react";
import { isMobileOnly } from "react-device-detect";
import {
DropDown,
DropDownItem,
SpeedControlWrapper,
ToastSpeed,
} from "./PlayerSpeedControl.styled";
import {
PlayerSpeedControlProps,
SpeedRecord,
SpeedType,
} from "./PlayerSpeedControl.props";
import Icon05x from "PUBLIC_DIR/images/media.viewer05x.react.svg";
import Icon1x from "PUBLIC_DIR/images/media.viewer1x.react.svg";
import Icon15x from "PUBLIC_DIR/images/media.viewer15x.react.svg";
import Icon2x from "PUBLIC_DIR/images/media.viewer2x.react.svg";
const speedIcons = [<Icon05x />, <Icon1x />, <Icon15x />, <Icon2x />];
const speeds: SpeedType = ["X0.5", "X1", "X1.5", "X2"];
const speedRecord: SpeedRecord<SpeedType> = {
"X0.5": 0.5,
X1: 1,
"X1.5": 1.5,
X2: 2,
};
const DefaultIndexSpeed = 1;
const MillisecondShowSpeedToast = 2000;
function PlayerSpeedControl({
handleSpeedChange,
onMouseLeave,
src,
}: PlayerSpeedControlProps) {
const ref = useRef<HTMLDivElement>(null);
const timerRef = useRef<NodeJS.Timeout>();
const [currentIndexSpeed, setCurrentIndexSpeed] = useState<number>(
DefaultIndexSpeed
);
const [isOpenSpeedContextMenu, setIsOpenSpeedContextMenu] = useState<boolean>(
false
);
const [speedToastVisible, setSpeedToastVisible] = useState<boolean>(false);
useEffect(() => {
setCurrentIndexSpeed(DefaultIndexSpeed);
}, [src]);
useEffect(() => {
const listener = (event: MouseEvent | TouchEvent) => {
if (!ref.current || ref.current.contains(event.target as Node)) {
return;
}
setIsOpenSpeedContextMenu(false);
};
document.addEventListener("mousedown", listener);
return () => {
document.removeEventListener("mousedown", listener);
clearTimeout(timerRef.current);
};
}, []);
const getNextIndexSpeed = (speed: number) => {
switch (speed) {
case 0:
return 2;
case 1:
return 0;
case 2:
return 3;
case 3:
return 1;
default:
return DefaultIndexSpeed;
}
};
const toggle = () => {
if (isMobileOnly) {
const nextIndexSpeed = getNextIndexSpeed(currentIndexSpeed);
setCurrentIndexSpeed(nextIndexSpeed);
const speed = speedRecord[speeds[nextIndexSpeed]];
handleSpeedChange(speed);
setSpeedToastVisible(true);
clearTimeout(timerRef.current);
timerRef.current = setTimeout(() => {
setSpeedToastVisible(false);
}, MillisecondShowSpeedToast);
} else {
setIsOpenSpeedContextMenu((prev) => !prev);
}
};
return (
<>
{speedToastVisible && (
<ToastSpeed>{speedIcons[currentIndexSpeed]}</ToastSpeed>
)}
<SpeedControlWrapper ref={ref} onClick={toggle}>
{speedIcons[currentIndexSpeed]}
{isOpenSpeedContextMenu && (
<DropDown onMouseLeave={onMouseLeave}>
{speeds.map((speed, index) => (
<DropDownItem
key={speed}
onClick={() => {
setCurrentIndexSpeed(index);
handleSpeedChange(speedRecord[speed]);
onMouseLeave();
}}
>
{speed}
</DropDownItem>
))}
</DropDown>
)}
</SpeedControlWrapper>
</>
);
}
export default memo(PlayerSpeedControl);