Refactor "Autoplay Next"
This commit is contained in:
parent
36ddc69c13
commit
535d02807a
6 changed files with 90 additions and 58 deletions
|
@ -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);
|
|
||||||
}
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -11,6 +11,9 @@
|
||||||
* For the case of 'MuteToggle', videojs changes the text at 'loadstart', so
|
* 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
|
* this event was chosen as the "lowest common denominator" to update the other
|
||||||
* static-text components.
|
* static-text components.
|
||||||
|
*
|
||||||
|
* --- Notes ---
|
||||||
|
* (1) 'AutoplayNextButton' handles i18n (among other things) on its own.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// @flow
|
// @flow
|
||||||
|
@ -58,7 +61,6 @@ function resolveCtrlText(e, player) {
|
||||||
setLabel(ctrlBar, 'PlayNextButton', __('Play Next (SHIFT+N)'));
|
setLabel(ctrlBar, 'PlayNextButton', __('Play Next (SHIFT+N)'));
|
||||||
setLabel(ctrlBar, 'PlayPreviousButton', __('Play Previous (SHIFT+P)'));
|
setLabel(ctrlBar, 'PlayPreviousButton', __('Play Previous (SHIFT+P)'));
|
||||||
setLabel(ctrlBar, 'TheaterModeButton', __('Toggle Theater Mode (t)'));
|
setLabel(ctrlBar, 'TheaterModeButton', __('Toggle Theater Mode (t)'));
|
||||||
setLabel(ctrlBar, 'AutoplayNextButton', __('Toggle Autoplay Next'));
|
|
||||||
ctrlBar
|
ctrlBar
|
||||||
.getChild('VolumePanel')
|
.getChild('VolumePanel')
|
||||||
.getChild('MuteToggle')
|
.getChild('MuteToggle')
|
||||||
|
|
|
@ -16,7 +16,6 @@ const VideoJsEvents = ({
|
||||||
setReload,
|
setReload,
|
||||||
videoTheaterMode,
|
videoTheaterMode,
|
||||||
playerRef,
|
playerRef,
|
||||||
autoplaySetting,
|
|
||||||
replay,
|
replay,
|
||||||
claimId,
|
claimId,
|
||||||
userId,
|
userId,
|
||||||
|
@ -33,7 +32,6 @@ const VideoJsEvents = ({
|
||||||
setReload: any, // react hook
|
setReload: any, // react hook
|
||||||
videoTheaterMode: any, // dispatch function
|
videoTheaterMode: any, // dispatch function
|
||||||
playerRef: any, // DOM element
|
playerRef: any, // DOM element
|
||||||
autoplaySetting: boolean,
|
|
||||||
replay: boolean,
|
replay: boolean,
|
||||||
claimId: ?string,
|
claimId: ?string,
|
||||||
userId: ?number,
|
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(() => {
|
useEffect(() => {
|
||||||
const player = playerRef.current;
|
const player = playerRef.current;
|
||||||
if (replay && player) {
|
if (replay && player) {
|
||||||
|
|
|
@ -74,7 +74,6 @@ type Props = {
|
||||||
adUrl: ?string,
|
adUrl: ?string,
|
||||||
allowPreRoll: ?boolean,
|
allowPreRoll: ?boolean,
|
||||||
autoplay: boolean,
|
autoplay: boolean,
|
||||||
autoplaySetting: boolean,
|
|
||||||
claimId: ?string,
|
claimId: ?string,
|
||||||
title: ?string,
|
title: ?string,
|
||||||
channelName: ?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
|
// adUrl, // TODO: this ad functionality isn't used, can be pulled out
|
||||||
// allowPreRoll,
|
// allowPreRoll,
|
||||||
autoplay,
|
autoplay,
|
||||||
autoplaySetting,
|
|
||||||
claimId,
|
claimId,
|
||||||
title,
|
title,
|
||||||
channelName,
|
channelName,
|
||||||
|
@ -202,7 +200,6 @@ export default React.memo<Props>(function VideoJs(props: Props) {
|
||||||
setReload,
|
setReload,
|
||||||
videoTheaterMode,
|
videoTheaterMode,
|
||||||
playerRef,
|
playerRef,
|
||||||
autoplaySetting,
|
|
||||||
replay,
|
replay,
|
||||||
claimValues,
|
claimValues,
|
||||||
userId,
|
userId,
|
||||||
|
|
|
@ -15,8 +15,8 @@ import AutoplayCountdown from 'component/autoplayCountdown';
|
||||||
import usePrevious from 'effects/use-previous';
|
import usePrevious from 'effects/use-previous';
|
||||||
import FileViewerEmbeddedEnded from 'web/component/fileViewerEmbeddedEnded';
|
import FileViewerEmbeddedEnded from 'web/component/fileViewerEmbeddedEnded';
|
||||||
import FileViewerEmbeddedTitle from 'component/fileViewerEmbeddedTitle';
|
import FileViewerEmbeddedTitle from 'component/fileViewerEmbeddedTitle';
|
||||||
|
import useAutoplayNext from './internal/effects/use-autoplay-next';
|
||||||
import { addTheaterModeButton } from './internal/theater-mode';
|
import { addTheaterModeButton } from './internal/theater-mode';
|
||||||
import { addAutoplayNextButton } from './internal/autoplay-next';
|
|
||||||
import { addPlayNextButton } from './internal/play-next';
|
import { addPlayNextButton } from './internal/play-next';
|
||||||
import { addPlayPreviousButton } from './internal/play-previous';
|
import { addPlayPreviousButton } from './internal/play-previous';
|
||||||
import { useGetAds } from 'effects/use-get-ads';
|
import { useGetAds } from 'effects/use-get-ads';
|
||||||
|
@ -154,6 +154,8 @@ function VideoViewer(props: Props) {
|
||||||
const isFirstRender = React.useRef(true);
|
const isFirstRender = React.useRef(true);
|
||||||
const playerRef = React.useRef(null);
|
const playerRef = React.useRef(null);
|
||||||
|
|
||||||
|
const addAutoplayNextButton = useAutoplayNext(playerRef, autoplayNext);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (isPlaying) {
|
if (isPlaying) {
|
||||||
doSetContentHistoryItem(claim.permanent_url);
|
doSetContentHistoryItem(claim.permanent_url);
|
||||||
|
@ -503,7 +505,6 @@ function VideoViewer(props: Props) {
|
||||||
startMuted={autoplayIfEmbedded}
|
startMuted={autoplayIfEmbedded}
|
||||||
toggleVideoTheaterMode={toggleVideoTheaterMode}
|
toggleVideoTheaterMode={toggleVideoTheaterMode}
|
||||||
autoplay={!embedded || autoplayIfEmbedded}
|
autoplay={!embedded || autoplayIfEmbedded}
|
||||||
autoplaySetting={localAutoplayNext}
|
|
||||||
claimId={claimId}
|
claimId={claimId}
|
||||||
title={claim && ((claim.value && claim.value.title) || claim.name)}
|
title={claim && ((claim.value && claim.value.title) || claim.name)}
|
||||||
channelName={channelName}
|
channelName={channelName}
|
||||||
|
|
Loading…
Add table
Reference in a new issue