diff --git a/src/components/mindset/components/MediaPlayer/index.tsx b/src/components/mindset/components/MediaPlayer/index.tsx index 5e203d19e..e9c694746 100644 --- a/src/components/mindset/components/MediaPlayer/index.tsx +++ b/src/components/mindset/components/MediaPlayer/index.tsx @@ -66,6 +66,7 @@ const MediaPlayerComponent = ({ mediaUrl }: Props) => { setIsSeeking, setPlayerRef, playerRef, + playbackSpeed, } = usePlayerStore((s) => s) useEffect(() => () => resetPlayer(), [resetPlayer]) @@ -184,6 +185,7 @@ const MediaPlayerComponent = ({ mediaUrl }: Props) => { onPlay={handlePlay} onProgress={handleProgress} onReady={handleReady} + playbackRate={playbackSpeed} playing={isPlaying} url={mediaUrl || ''} volume={volume} diff --git a/src/components/mindset/components/PlayerContols/Controls/index.tsx b/src/components/mindset/components/PlayerContols/Controls/index.tsx index 2f454bc85..13911c345 100644 --- a/src/components/mindset/components/PlayerContols/Controls/index.tsx +++ b/src/components/mindset/components/PlayerContols/Controls/index.tsx @@ -1,16 +1,23 @@ import { IconButton } from '@mui/material' -import { memo } from 'react' +import { memo, useState } from 'react' import styled from 'styled-components' import PauseIcon from '~/components/Icons/PauseIcon' import PlayIcon from '~/components/Icons/PlayIcon' import { Flex } from '~/components/common/Flex' import { usePlayerStore } from '~/stores/usePlayerStore' import { colors } from '~/utils/colors' +import VolumeIcon from '~/components/Icons/VolumeIcon' +import MuteVolumeIcon from '~/components/Icons/MuteVolumeIcon' export const Controls = memo(() => { const isPlaying = usePlayerStore((s) => s.isPlaying) const setIsPlaying = usePlayerStore((s) => s.setIsPlaying) + const setVolume = usePlayerStore((s) => s.setVolume) + const setPlaybackSpeed = usePlayerStore((s) => s.setPlaybackSpeed) + const playbackSpeed = usePlayerStore((s) => s.playbackSpeed) const playerRef = usePlayerStore((s) => s.playerRef) + const [isMuted, setIsMuted] = useState(false) + const speedOptions = [0.5, 1, 1.5, 2] const handleRewind = () => { if (playerRef) { @@ -32,8 +39,30 @@ export const Controls = memo(() => { setIsPlaying(!isPlaying) } + const toggleMute = () => { + setIsMuted(!isMuted) + setVolume(isMuted ? 1 : 0) + } + + const cycleSpeed = () => { + const currentIndex = speedOptions.indexOf(playbackSpeed) + const nextIndex = (currentIndex + 1) % speedOptions.length + const newSpeed = speedOptions[nextIndex] + + setPlaybackSpeed(newSpeed) + + if (playerRef) { + const internalPlayer = playerRef.getInternalPlayer() as HTMLMediaElement + + if (internalPlayer && typeof internalPlayer.playbackRate !== 'undefined') { + internalPlayer.playbackRate = newSpeed + } + } + } + return ( + {isMuted ? : } @@ -43,6 +72,7 @@ export const Controls = memo(() => { + {playbackSpeed}x ) }) @@ -54,7 +84,7 @@ const Wrapper = styled(Flex).attrs({ align: 'center', justify: 'flex-start', })` - width: 142px; + width: 200px; height: 54px; background: ${colors.BG1}; border-radius: 40px; @@ -96,3 +126,38 @@ const ForwardIconWrapper = styled.div` height: auto; } ` + +const MuteWrapper = styled.div` + display: flex; + align-items: center; + justify-content: center; + width: 40px; + height: 40px; + cursor: pointer; + border-radius: 50%; + transition: background-color 0.3s ease; + color: ${colors.GRAY6}; + + svg { + margin-top: 3px; + width: 24px; + height: 24px; + } + + &:hover { + background-color: ${colors.DROPDOWN_BG}; + } +` + +const SpeedButton = styled.button` + margin-top: 4px; + background: ${colors.BG1}; + color: ${colors.GRAY6}; + border: none; + width: 8px; + border-radius: 20px; + padding: 8px 20px 8px 8px; + font-size: 14px; + cursor: pointer; + transition: background-color 0.3s ease; +` diff --git a/src/stores/usePlayerStore/index.ts b/src/stores/usePlayerStore/index.ts index aced28cba..f73f943fd 100644 --- a/src/stores/usePlayerStore/index.ts +++ b/src/stores/usePlayerStore/index.ts @@ -11,6 +11,7 @@ type PlayerStore = { playingTime: number duration: number volume: number + playbackSpeed: number playingNode: NodeExtended | null playerRef: ReactPlayer | null setPlayingTime: (time: number) => void @@ -24,6 +25,7 @@ type PlayerStore = { setPlayingNodeLink: (link: string) => void setIsSeeking: (isSeeking: boolean) => void setPlayerRef: (playerRef: ReactPlayer) => void + setPlaybackSpeed: (speed: number) => void } const defaultData: Omit< @@ -39,6 +41,7 @@ const defaultData: Omit< | 'setPlayingNodeLink' | 'setIsSeeking' | 'setPlayerRef' + | 'setPlaybackSpeed' > = { isPlaying: false, miniPlayerIsVisible: false, @@ -48,6 +51,7 @@ const defaultData: Omit< playingNode: null, duration: 0, volume: 0.5, + playbackSpeed: 1, playerRef: null, } @@ -95,5 +99,6 @@ export const usePlayerStore = create()( } }, resetPlayer: () => set({ duration: defaultData.duration, hasError: defaultData.hasError }), + setPlaybackSpeed: (speed) => set({ playbackSpeed: speed }), })), )