From ca5dc4ed00b33429dd3d4d4da96325da9c33f762 Mon Sep 17 00:00:00 2001 From: Oluwaseun Jolaoso <37256277+sudhons@users.noreply.github.com> Date: Fri, 2 Aug 2024 19:50:23 +0100 Subject: [PATCH] Always show media player bottom controls (#139) Fixes https://github.com/Collaborne/backlog/issues/3032 --- .../__test__/MediaPlayer.spec.tsx | 311 ------------------ .../components/MediaPlayerControlButtons.tsx | 9 +- .../components/MediaPlayerControls.tsx | 6 - .../progress-bar/ProgressTimerDisplay.tsx | 24 +- 4 files changed, 12 insertions(+), 338 deletions(-) delete mode 100644 src/components/media-player/__test__/MediaPlayer.spec.tsx diff --git a/src/components/media-player/__test__/MediaPlayer.spec.tsx b/src/components/media-player/__test__/MediaPlayer.spec.tsx deleted file mode 100644 index 3d8dda5a..00000000 --- a/src/components/media-player/__test__/MediaPlayer.spec.tsx +++ /dev/null @@ -1,311 +0,0 @@ -/* eslint-disable max-lines */ -import { render, cleanup, act } from '@testing-library/react'; -import '@testing-library/jest-dom'; - -import { useMediaStore } from '../../../context/MediaProvider'; -import { MediaStore } from '../../../store/media-store'; -import { - BOTTOM_CONTROL_BUTTONS, - CENTERED_PLAY_BUTTON, - CONTROLS, - DEFAULT_EVENT_ANIMATION_DURATION, - FULLSCREEN_BUTTON, - MEDIA_CONTAINER, - OVERLAY_HIDE_DELAY, - PAUSE_ANIMATION, - PLAY_ANIMATION, - PLAY_PAUSE_REPLAY, - PROGRESS_BAR, - REACT_PLAYER, - sleep, - userEvent, -} from '../../../utils'; -import { MediaPlayer } from '../MediaPlayer'; - -// Start the playback. -global.window.HTMLMediaElement.prototype.play = async function playMock() { - this.dispatchEvent(new Event('play')); -}; - -// Pause the playback. -global.window.HTMLMediaElement.prototype.pause = async function playMock() { - this.dispatchEvent(new Event('pause')); -}; -const VIDEO_URL = 'video.mp4'; -const AUDIO_URL = 'audio.mp3'; - -// A test setup for MediaPlayer, that can access `MediaStore` from `MediaProvider` -const setupMediaPlayer = (url = VIDEO_URL) => { - const returnVal = {} as MediaStore; - function NullComponent() { - const mediaStore = useMediaStore(); - Object.assign(returnVal, mediaStore); - return null; - } - function TestComponent() { - return ( - - - - ); - } - return { ...render(), mediaStore: returnVal }; -}; - -describe('', () => { - afterEach(cleanup); - describe('initialization', () => { - it('media has not started before', async () => { - const { getByTestId, mediaStore } = setupMediaPlayer(); - // wait 1 ms to mount state and load initial data - await act(async () => await sleep(1)); - - const startBtn = getByTestId(CENTERED_PLAY_BUTTON); - - expect(mediaStore.hasPlayedOrSeeked).toBeFalsy(); - expect(startBtn).toBeInTheDocument(); - }); - describe('first time play', () => { - it('click on start playing', async () => { - const { getByTestId, mediaStore } = setupMediaPlayer(); - // wait 1 ms to mount state and load initial data - await act(async () => await sleep(1)); - - const startBtn = getByTestId(CENTERED_PLAY_BUTTON); - - await userEvent.click(startBtn); - - expect(startBtn).not.toBeInTheDocument(); - expect(mediaStore.isPlaying).toBeTruthy(); - expect(mediaStore.hasPlayedOrSeeked).toBeTruthy(); - }); - it('click on media-player layout start playing and hide and ', async () => { - const { getByTestId, mediaStore } = setupMediaPlayer(); - // wait 1 ms to mount state and load initial data - await act(async () => await sleep(1)); - - const mediaPlayerDiv = getByTestId(REACT_PLAYER); - const startBtn = getByTestId(CENTERED_PLAY_BUTTON); - - await userEvent.click(mediaPlayerDiv); - - expect(mediaStore.isPlaying).toBeTruthy(); - expect(mediaStore.hasPlayedOrSeeked).toBeTruthy(); - expect(startBtn).not.toBeInTheDocument(); - }); - }); - }); - describe('Play/Pause animation on triggered event', () => { - it('animation is absent for audio files', async () => { - const { getByTestId, queryByTestId } = setupMediaPlayer(AUDIO_URL); - // wait 1 ms to mount state and load initial data - await act(async () => await sleep(1)); - - await userEvent.click(getByTestId(PLAY_PAUSE_REPLAY)); - - expect(queryByTestId(PLAY_ANIMATION)).not.toBeInTheDocument(); - expect(queryByTestId(PAUSE_ANIMATION)).not.toBeInTheDocument(); - }); - it('play/pause animation on layout click', async () => { - const { getByTestId } = setupMediaPlayer(); - // wait 1 ms to mount state and load initial data - await act(async () => await sleep(1)); - - const mediaPlayerDiv = getByTestId(REACT_PLAYER); - const playEl = getByTestId(PLAY_ANIMATION); - const pauseEl = getByTestId(PAUSE_ANIMATION); - - // on first time play animation is not shown - await userEvent.click(mediaPlayerDiv); - expect(playEl.style.display).toBe('none'); - - // run pause animation - await userEvent.click(mediaPlayerDiv); - expect(pauseEl.style.display).toBe('block'); - - // wait until pause event was finished - await act(async () => await sleep(DEFAULT_EVENT_ANIMATION_DURATION)); - expect(pauseEl.style.display).toBe('none'); - - // run play animation - await userEvent.click(mediaPlayerDiv); - expect(playEl.style.display).toBe('block'); - expect(pauseEl.style.display).toBe('none'); - }); - it('play/pause animation on clicking ', async () => { - const { getByTestId } = setupMediaPlayer(); - // wait 1 ms to mount state and load initial data - await act(async () => await sleep(1)); - - const startBtn = getByTestId(CENTERED_PLAY_BUTTON); - const playEl = getByTestId(PLAY_ANIMATION); - const pauseEl = getByTestId(PAUSE_ANIMATION); - - // on first time play animation is not shown - await userEvent.click(startBtn); - expect(playEl.style.display).toBe('none'); - - const playPauseReplayBtn = getByTestId(PLAY_PAUSE_REPLAY); - // run pause animation - await userEvent.click(playPauseReplayBtn); - expect(pauseEl.style.display).toBe('block'); - - // wait until pause event was finished - await act(async () => await sleep(DEFAULT_EVENT_ANIMATION_DURATION)); - expect(pauseEl.style.display).toBe('none'); - - // run play animation - await userEvent.click(playPauseReplayBtn); - expect(playEl.style.display).toBe('block'); - expect(pauseEl.style.display).toBe('none'); - }); - }); - describe(': hovering player layout', () => { - it('do not display on first time play', async () => { - const { getByTestId, queryByTestId } = setupMediaPlayer(); - // wait 1 ms to mount state and load initial data - await act(async () => await sleep(1)); - - const startBtn = getByTestId(CENTERED_PLAY_BUTTON); - const bottomButtons = queryByTestId(BOTTOM_CONTROL_BUTTONS); - expect(bottomButtons).not.toBeInTheDocument(); - - await userEvent.click(startBtn); - expect(getByTestId(BOTTOM_CONTROL_BUTTONS)).toBeInTheDocument(); - }); - it('do not display when leaving ', async () => { - const { getByTestId, queryByTestId } = setupMediaPlayer(); - // wait 1 ms to mount state and load initial data - await act(async () => await sleep(1)); - - const startBtn = getByTestId(CENTERED_PLAY_BUTTON); - - await userEvent.click(startBtn); - expect(queryByTestId(BOTTOM_CONTROL_BUTTONS)).toBeInTheDocument(); - - await userEvent.unhover(getByTestId(MEDIA_CONTAINER)); - expect(queryByTestId(BOTTOM_CONTROL_BUTTONS)).not.toBeInTheDocument(); - }); - it(`do not display after ${OVERLAY_HIDE_DELAY}ms on hovered layout`, async () => { - const { getByTestId, queryByTestId } = setupMediaPlayer(); - // wait 1 ms to mount state and load initial data - await act(async () => await sleep(1)); - - const startBtn = getByTestId(CENTERED_PLAY_BUTTON); - - await userEvent.click(startBtn); - expect(queryByTestId(BOTTOM_CONTROL_BUTTONS)).toBeInTheDocument(); - - await userEvent.hover(getByTestId(MEDIA_CONTAINER)); - expect(queryByTestId(BOTTOM_CONTROL_BUTTONS)).toBeInTheDocument(); - // because onMouseEvent is throttled, hiding can occur for a upt to 1sec delay - await act(async () => await sleep(OVERLAY_HIDE_DELAY + 1000)); - expect(queryByTestId(BOTTOM_CONTROL_BUTTONS)).not.toBeInTheDocument(); - }); - it(`display when paused`, async () => { - const { getByTestId, queryByTestId, mediaStore } = setupMediaPlayer(); - // wait 1 ms to mount state and load initial data - await act(async () => await sleep(1)); - - const startBtn = getByTestId(CENTERED_PLAY_BUTTON); - - await userEvent.click(startBtn); - expect(queryByTestId(BOTTOM_CONTROL_BUTTONS)).toBeInTheDocument(); - - await userEvent.click(getByTestId(PLAY_PAUSE_REPLAY)); - expect(mediaStore.isPlaying).toBeFalsy(); - - await userEvent.unhover(getByTestId(MEDIA_CONTAINER)); - expect(queryByTestId(BOTTOM_CONTROL_BUTTONS)).toBeInTheDocument(); - }); - it(`always display when an button of is hovered`, async () => { - const { getByTestId, queryByTestId, mediaStore } = setupMediaPlayer(); - // wait 1 ms to mount state and load initial data - await act(async () => await sleep(1)); - - const startBtn = getByTestId(CENTERED_PLAY_BUTTON); - - await userEvent.click(startBtn); - expect(queryByTestId(BOTTOM_CONTROL_BUTTONS)).toBeInTheDocument(); - expect(mediaStore.isPlaying).toBeTruthy(); - - await userEvent.hover(getByTestId(PLAY_PAUSE_REPLAY)); - // add delay 1sec - for be certain sure that should wait enough - await act(async () => await sleep(OVERLAY_HIDE_DELAY + 1000)); - expect(queryByTestId(BOTTOM_CONTROL_BUTTONS)).toBeInTheDocument(); - }); - }); - describe('', () => { - it('do not display before first time play', async () => { - const { queryByTestId } = setupMediaPlayer(); - // wait 1 ms to mount state and load initial data - await act(async () => await sleep(1)); - expect(queryByTestId(PROGRESS_BAR)).not.toBeInTheDocument(); - }); - it('display it when are shown ', async () => { - const { getByTestId, queryByTestId } = setupMediaPlayer(); - // wait 1 ms to mount state and load initial data - await act(async () => await sleep(1)); - - const startBtn = getByTestId(CENTERED_PLAY_BUTTON); - await userEvent.click(startBtn); - expect(queryByTestId(BOTTOM_CONTROL_BUTTONS)).toBeInTheDocument(); - expect(queryByTestId(PROGRESS_BAR)).toBeInTheDocument(); - }); - it('display it when are hidden ', async () => { - const { getByTestId, queryByTestId } = setupMediaPlayer(); - // wait 1 ms to mount state and load initial data - await act(async () => await sleep(1)); - - const startBtn = getByTestId(CENTERED_PLAY_BUTTON); - await userEvent.click(startBtn); - - await userEvent.unhover(getByTestId(MEDIA_CONTAINER)); - expect(queryByTestId(BOTTOM_CONTROL_BUTTONS)).not.toBeInTheDocument(); - expect(queryByTestId(PROGRESS_BAR)).toBeInTheDocument(); - }); - }); - describe('Fullscreen API', () => { - it('FullscreenButton is not present for audio files', async () => { - const { getByTestId, queryByTestId } = setupMediaPlayer(AUDIO_URL); - // wait 1 ms to mount state and load initial data - await act(async () => await sleep(1)); - - const startBtn = getByTestId(PLAY_PAUSE_REPLAY); - await userEvent.click(startBtn); - expect(queryByTestId(FULLSCREEN_BUTTON)).not.toBeInTheDocument(); - }); - it('request/exit fullscreen by clicking on button', async () => { - const { getByTestId, mediaStore } = setupMediaPlayer(); - // wait 1 ms to mount state and load initial data - await act(async () => await sleep(1)); - - const startBtn = getByTestId(CENTERED_PLAY_BUTTON); - await userEvent.click(startBtn); - expect(mediaStore.isFullscreen).toBeFalsy(); - // enable fullscreen - await userEvent.click(getByTestId(FULLSCREEN_BUTTON)); - expect(mediaStore.isFullscreen).toBeTruthy(); - - // exit fullscreen - await userEvent.click(getByTestId(FULLSCREEN_BUTTON)); - expect(mediaStore.isFullscreen).toBeFalsy(); - }); - describe('audio player', () => { - it('controls visible on unhovering the audio player', async () => { - const { getByTestId } = setupMediaPlayer(AUDIO_URL); - // wait 1 ms to mount state and load initial data - await act(async () => await sleep(1)); - - const playBtn = getByTestId(PLAY_PAUSE_REPLAY); - await userEvent.click(playBtn); - const controls = getByTestId(CONTROLS); - expect(controls).toBeInTheDocument(); - - const mediaContainer = getByTestId(MEDIA_CONTAINER); - await userEvent.unhover(mediaContainer); - expect(controls).toBeInTheDocument(); - }); - }); - }); -}); diff --git a/src/components/media-player/components/MediaPlayerControlButtons.tsx b/src/components/media-player/components/MediaPlayerControlButtons.tsx index fbe62243..d0376448 100644 --- a/src/components/media-player/components/MediaPlayerControlButtons.tsx +++ b/src/components/media-player/components/MediaPlayerControlButtons.tsx @@ -1,7 +1,7 @@ import Grid from '@mui/material/Grid'; import { FC, memo, ReactNode } from 'react'; -import { useIsAudio, usePlayPauseReplayHook } from '../../../hooks'; +import { useIsAudio } from '../../../hooks'; import { BOTTOM_CONTROL_BUTTONS } from '../../../utils'; import { useBottomControlButtonsHook } from '../../bottom-control-buttons/useBottomControlButtonsHook'; import { useBottomControlButtonsStyles } from '../../bottom-control-buttons/useBottomControlButtonsStyles'; @@ -28,12 +28,9 @@ export const MediaPlayerControlButtons: FC = }) => { const isAudio = useIsAudio(); const { classes, cx } = useBottomControlButtonsStyles(); - const { hasStarted, showControls } = useBottomControlButtonsHook(); - const { isFinished } = usePlayPauseReplayHook(); + const { showControls } = useBottomControlButtonsHook(); - const hide = isCollapsed - ? !hasStarted || isFinished - : (!showControls || !hasStarted) && !isAudio; + const hide = !isCollapsed && !showControls && !isAudio; if (hide) { return null; diff --git a/src/components/media-player/components/MediaPlayerControls.tsx b/src/components/media-player/components/MediaPlayerControls.tsx index 306cc9c1..574b667a 100644 --- a/src/components/media-player/components/MediaPlayerControls.tsx +++ b/src/components/media-player/components/MediaPlayerControls.tsx @@ -14,8 +14,6 @@ import { } from '../../bottom-control-buttons'; import { CollapseIconButton } from '../../bottom-control-buttons/components/CollapseIconButton'; import { BottomControls } from '../../bottom-controls/BottomControls'; -import { CenteredPlayButton } from '../../centered-play-button/CenteredPlayButton'; -import { CenteredReplayButton } from '../../centered-replay-button/CenteredReplayButton'; import { useControlsStyles, Controls } from '../../controls'; import { PauseAnimation } from '../../play-pause-animation/PauseAnimation'; import { PlayAnimation } from '../../play-pause-animation/PlayAnimation'; @@ -70,10 +68,6 @@ export const MediaPlayerControls: FC = memo( )} - - - - diff --git a/src/components/progress-bar/ProgressTimerDisplay.tsx b/src/components/progress-bar/ProgressTimerDisplay.tsx index f12eb838..3b8ab0a8 100644 --- a/src/components/progress-bar/ProgressTimerDisplay.tsx +++ b/src/components/progress-bar/ProgressTimerDisplay.tsx @@ -35,17 +35,15 @@ export const ProgressTimerDisplay: FC = ({ classes: { timeStampText }, } = useTimeDisplayStyles(); - const [hasStarted, duration, setCurrentTime, isPip, currentTime] = - useMediaStore( - state => [ - state.hasPlayedOrSeeked, - state.duration, - state.setCurrentTime, - state.isPip, - state.currentTime, - ], - shallow, - ); + const [duration, setCurrentTime, isPip, currentTime] = useMediaStore( + state => [ + state.duration, + state.setCurrentTime, + state.isPip, + state.currentTime, + ], + shallow, + ); const onCurrentTimeUpdate = (e: Event, newValue: number | number[]) => { e.preventDefault(); @@ -62,10 +60,6 @@ export const ProgressTimerDisplay: FC = ({ cx, } = useProgressBarStyles({ isAudio, isPip }); - if (!hasStarted && !isAudio) { - return null; - } - return (