Refactor "Autoplay Next"

This commit is contained in:
infinite-persistence 2022-05-17 14:57:14 +08:00
parent 36ddc69c13
commit 535d02807a
No known key found for this signature in database
GPG key ID: B9C3252EDC3D0AA0
6 changed files with 90 additions and 58 deletions

View file

@ -1,33 +0,0 @@
// @flow
import type { Player } from './videojs';
import videojs from 'video.js';
class AutoplayNextButton extends videojs.getComponent('Button') {
constructor(player, options = {}, autoplayNext) {
super(player, options, autoplayNext);
const title = autoplayNext ? 'Autoplay Next On' : 'Autoplay Next Off';
this.controlText(title);
this.setAttribute('aria-label', title);
this.addClass('vjs-button--autoplay-next');
this.setAttribute('aria-checked', autoplayNext);
}
}
export function addAutoplayNextButton(player: Player, toggleAutoplayNext: () => void, autoplayNext: boolean) {
const controlBar = player.getChild('controlBar');
const autoplayButton = new AutoplayNextButton(
player,
{
name: 'AutoplayNextButton',
text: 'Autoplay Next',
clickHandler: () => {
toggleAutoplayNext();
},
},
autoplayNext
);
controlBar.addChild(autoplayButton);
}

View file

@ -0,0 +1,84 @@
/**
* Videojs "Autoplay Next" button.
*
* --- How to use ---
* Apply `useAutoplayNext` in your React component. It registers an effect that
* listens to the given Redux state, and returns a callback for you to mount the
* custom videojs component.
*
* --- Notes ---
* Usually, custom videojs components can just listen to videojs events, query
* states from `player` (e.g. player.paused()) and update accordingly. But since
* the state comes from Redux, there will be a need to listen and pass the info
* to videojs somehow.
*
* Instead of going through an 'effect->css->videojs' trip, we'll just listen to
* the Redux state through a normal effect to update the component.
*
* This file aims to encapsulate both the React and Videojs side of things
* through a single `useAutoplayNext` call.
*/
// @flow
import React from 'react';
import videojs from 'video.js';
import type { Player } from '../videojs';
// ****************************************************************************
// AutoplayNextButton
// ****************************************************************************
class AutoplayNextButton extends videojs.getComponent('Button') {
constructor(player, options = {}, autoplayNext) {
super(player, options, autoplayNext);
const title = __(autoplayNext ? 'Autoplay Next On' : 'Autoplay Next Off');
this.controlText(title);
this.addClass('vjs-button--autoplay-next');
this.setAttribute('aria-label', title);
this.setAttribute('aria-checked', autoplayNext);
}
}
function addAutoplayNextButton(player: Player, toggleAutoplayNext: () => void, autoplayNext: boolean) {
const controlBar = player.getChild('controlBar');
const autoplayButton = new AutoplayNextButton(
player,
{
name: 'AutoplayNextButton',
text: 'Autoplay Next',
clickHandler: () => {
toggleAutoplayNext();
},
},
autoplayNext
);
controlBar.addChild(autoplayButton);
}
// ****************************************************************************
// useAutoplayNext
// ****************************************************************************
export default function useAutoplayNext(playerRef: any, autoplayNext: boolean) {
React.useEffect(() => {
const player = playerRef.current;
if (player) {
const touchOverlay = player.getChild('TouchOverlay');
const controlBar = player.getChild('controlBar') || touchOverlay.getChild('controlBar');
const autoplayButton = controlBar.getChild('AutoplayNextButton');
if (autoplayButton) {
const title = autoplayNext ? __('Autoplay Next On') : __('Autoplay Next Off');
autoplayButton.controlText(title);
autoplayButton.setAttribute('aria-label', title);
autoplayButton.setAttribute('aria-checked', autoplayNext);
}
}
}, [autoplayNext]);
return addAutoplayNextButton;
}

View file

@ -11,6 +11,9 @@
* For the case of 'MuteToggle', videojs changes the text at 'loadstart', so
* this event was chosen as the "lowest common denominator" to update the other
* static-text components.
*
* --- Notes ---
* (1) 'AutoplayNextButton' handles i18n (among other things) on its own.
*/
// @flow
@ -58,7 +61,6 @@ function resolveCtrlText(e, player) {
setLabel(ctrlBar, 'PlayNextButton', __('Play Next (SHIFT+N)'));
setLabel(ctrlBar, 'PlayPreviousButton', __('Play Previous (SHIFT+P)'));
setLabel(ctrlBar, 'TheaterModeButton', __('Toggle Theater Mode (t)'));
setLabel(ctrlBar, 'AutoplayNextButton', __('Toggle Autoplay Next'));
ctrlBar
.getChild('VolumePanel')
.getChild('MuteToggle')

View file

@ -16,7 +16,6 @@ const VideoJsEvents = ({
setReload,
videoTheaterMode,
playerRef,
autoplaySetting,
replay,
claimId,
userId,
@ -33,7 +32,6 @@ const VideoJsEvents = ({
setReload: any, // react hook
videoTheaterMode: any, // dispatch function
playerRef: any, // DOM element
autoplaySetting: boolean,
replay: boolean,
claimId: ?string,
userId: ?number,
@ -191,23 +189,6 @@ const VideoJsEvents = ({
}
}
useEffect(() => {
const player = playerRef.current;
if (player) {
const touchOverlay = player.getChild('TouchOverlay');
const controlBar = player.getChild('controlBar') || touchOverlay.getChild('controlBar');
const autoplayButton = controlBar.getChild('AutoplayNextButton');
if (autoplayButton) {
const title = autoplaySetting ? __('Autoplay Next On') : __('Autoplay Next Off');
autoplayButton.controlText(title);
autoplayButton.setAttribute('aria-label', title);
autoplayButton.setAttribute('aria-checked', autoplaySetting);
}
}
}, [autoplaySetting]);
useEffect(() => {
const player = playerRef.current;
if (replay && player) {

View file

@ -74,7 +74,6 @@ type Props = {
adUrl: ?string,
allowPreRoll: ?boolean,
autoplay: boolean,
autoplaySetting: boolean,
claimId: ?string,
title: ?string,
channelName: ?string,
@ -133,7 +132,6 @@ export default React.memo<Props>(function VideoJs(props: Props) {
// adUrl, // TODO: this ad functionality isn't used, can be pulled out
// allowPreRoll,
autoplay,
autoplaySetting,
claimId,
title,
channelName,
@ -202,7 +200,6 @@ export default React.memo<Props>(function VideoJs(props: Props) {
setReload,
videoTheaterMode,
playerRef,
autoplaySetting,
replay,
claimValues,
userId,

View file

@ -15,8 +15,8 @@ import AutoplayCountdown from 'component/autoplayCountdown';
import usePrevious from 'effects/use-previous';
import FileViewerEmbeddedEnded from 'web/component/fileViewerEmbeddedEnded';
import FileViewerEmbeddedTitle from 'component/fileViewerEmbeddedTitle';
import useAutoplayNext from './internal/effects/use-autoplay-next';
import { addTheaterModeButton } from './internal/theater-mode';
import { addAutoplayNextButton } from './internal/autoplay-next';
import { addPlayNextButton } from './internal/play-next';
import { addPlayPreviousButton } from './internal/play-previous';
import { useGetAds } from 'effects/use-get-ads';
@ -154,6 +154,8 @@ function VideoViewer(props: Props) {
const isFirstRender = React.useRef(true);
const playerRef = React.useRef(null);
const addAutoplayNextButton = useAutoplayNext(playerRef, autoplayNext);
React.useEffect(() => {
if (isPlaying) {
doSetContentHistoryItem(claim.permanent_url);
@ -503,7 +505,6 @@ function VideoViewer(props: Props) {
startMuted={autoplayIfEmbedded}
toggleVideoTheaterMode={toggleVideoTheaterMode}
autoplay={!embedded || autoplayIfEmbedded}
autoplaySetting={localAutoplayNext}
claimId={claimId}
title={claim && ((claim.value && claim.value.title) || claim.name)}
channelName={channelName}