From 89f889e3882b55178a48876a61a212f227f9577d Mon Sep 17 00:00:00 2001 From: Akmal Isomadinov Date: Fri, 17 Mar 2023 23:56:36 +0500 Subject: [PATCH] Web:Common:Components:MediaViewer:Sub-Components:Added PlayerSpeedControl component --- .../PlayerSpeedControl.props.ts | 11 ++ .../PlayerSpeedControl.styled.ts | 89 ++++++++++++ .../PlayerSpeedControl/index.tsx | 137 ++++++++++++++++++ 3 files changed, 237 insertions(+) create mode 100644 packages/common/components/MediaViewer/sub-components/PlayerSpeedControl/PlayerSpeedControl.props.ts create mode 100644 packages/common/components/MediaViewer/sub-components/PlayerSpeedControl/PlayerSpeedControl.styled.ts create mode 100644 packages/common/components/MediaViewer/sub-components/PlayerSpeedControl/index.tsx diff --git a/packages/common/components/MediaViewer/sub-components/PlayerSpeedControl/PlayerSpeedControl.props.ts b/packages/common/components/MediaViewer/sub-components/PlayerSpeedControl/PlayerSpeedControl.props.ts new file mode 100644 index 0000000000..fde6f3072a --- /dev/null +++ b/packages/common/components/MediaViewer/sub-components/PlayerSpeedControl/PlayerSpeedControl.props.ts @@ -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 = { + [Key in T[number]]: number; +}; diff --git a/packages/common/components/MediaViewer/sub-components/PlayerSpeedControl/PlayerSpeedControl.styled.ts b/packages/common/components/MediaViewer/sub-components/PlayerSpeedControl/PlayerSpeedControl.styled.ts new file mode 100644 index 0000000000..2942f3325b --- /dev/null +++ b/packages/common/components/MediaViewer/sub-components/PlayerSpeedControl/PlayerSpeedControl.styled.ts @@ -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; + } +`; diff --git a/packages/common/components/MediaViewer/sub-components/PlayerSpeedControl/index.tsx b/packages/common/components/MediaViewer/sub-components/PlayerSpeedControl/index.tsx new file mode 100644 index 0000000000..d4521643ef --- /dev/null +++ b/packages/common/components/MediaViewer/sub-components/PlayerSpeedControl/index.tsx @@ -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 = [, , , ]; + +const speeds: SpeedType = ["X0.5", "X1", "X1.5", "X2"]; + +const speedRecord: SpeedRecord = { + "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(null); + + const timerRef = useRef(); + + const [currentIndexSpeed, setCurrentIndexSpeed] = useState( + DefaultIndexSpeed + ); + const [isOpenSpeedContextMenu, setIsOpenSpeedContextMenu] = useState( + false + ); + const [speedToastVisible, setSpeedToastVisible] = useState(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 && ( + {speedIcons[currentIndexSpeed]} + )} + + {speedIcons[currentIndexSpeed]} + + {isOpenSpeedContextMenu && ( + + {speeds.map((speed, index) => ( + { + setCurrentIndexSpeed(index); + handleSpeedChange(speedRecord[speed]); + onMouseLeave(); + }} + > + {speed} + + ))} + + )} + + + ); +} + +export default memo(PlayerSpeedControl);