feat(filmstrip): reactify the filmstrip toggle button
This commit is contained in:
parent
c25d6eb9a8
commit
0fca0f392d
|
@ -24,6 +24,7 @@ import {
|
|||
import { destroyLocalTracks } from '../../react/features/base/tracks';
|
||||
import { openDisplayNamePrompt } from '../../react/features/display-name';
|
||||
import { setEtherpadHasInitialzied } from '../../react/features/etherpad';
|
||||
import { setFilmstripVisible } from '../../react/features/filmstrip';
|
||||
import {
|
||||
setNotificationsEnabled,
|
||||
showWarningNotification
|
||||
|
@ -93,7 +94,7 @@ const UIListeners = new Map([
|
|||
() => UI.toggleChat()
|
||||
], [
|
||||
UIEvents.TOGGLE_FILMSTRIP,
|
||||
() => UI.handleToggleFilmstrip()
|
||||
() => UI.toggleFilmstrip()
|
||||
], [
|
||||
UIEvents.FOLLOW_ME_ENABLED,
|
||||
enabled => followMeHandler && followMeHandler.enableFollowMe(enabled)
|
||||
|
@ -255,11 +256,6 @@ UI.initConference = function() {
|
|||
followMeHandler = new FollowMe(APP.conference, UI);
|
||||
};
|
||||
|
||||
/** *
|
||||
* Handler for toggling filmstrip
|
||||
*/
|
||||
UI.handleToggleFilmstrip = () => UI.toggleFilmstrip();
|
||||
|
||||
/**
|
||||
* Returns the shared document manager object.
|
||||
* @return {EtherpadManager} the shared document manager object
|
||||
|
@ -298,7 +294,6 @@ UI.start = function() {
|
|||
|
||||
if (interfaceConfig.filmStripOnly) {
|
||||
$('body').addClass('filmstrip-only');
|
||||
Filmstrip.setFilmstripOnly();
|
||||
APP.store.dispatch(setNotificationsEnabled(false));
|
||||
} else {
|
||||
// Initialize recording mode UI.
|
||||
|
@ -512,9 +507,9 @@ UI.toggleSmileys = () => Chat.toggleSmileys();
|
|||
* Toggles filmstrip.
|
||||
*/
|
||||
UI.toggleFilmstrip = function() {
|
||||
// eslint-disable-next-line prefer-rest-params
|
||||
Filmstrip.toggleFilmstrip(...arguments);
|
||||
VideoLayout.resizeVideoArea(true, false);
|
||||
const { visible } = APP.store.getState()['features/filmstrip'];
|
||||
|
||||
APP.store.dispatch(setFilmstripVisible(!visible));
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* global $, APP, interfaceConfig */
|
||||
|
||||
import { setFilmstripVisible } from '../../../react/features/filmstrip';
|
||||
import {
|
||||
LAYOUTS,
|
||||
getCurrentLayout,
|
||||
|
@ -9,188 +8,16 @@ import {
|
|||
shouldDisplayTileView
|
||||
} from '../../../react/features/video-layout';
|
||||
|
||||
import UIEvents from '../../../service/UI/UIEvents';
|
||||
import UIUtil from '../util/UIUtil';
|
||||
|
||||
import {
|
||||
createShortcutEvent,
|
||||
createToolbarEvent,
|
||||
sendAnalytics
|
||||
} from '../../../react/features/analytics';
|
||||
|
||||
const Filmstrip = {
|
||||
/**
|
||||
*
|
||||
* @param eventEmitter the {EventEmitter} through which {Filmstrip} is to
|
||||
* emit/fire {UIEvents} (such as {UIEvents.TOGGLED_FILMSTRIP}).
|
||||
* Caches jquery lookups of the filmstrip for future use.
|
||||
*/
|
||||
init(eventEmitter) {
|
||||
this.iconMenuDownClassName = 'icon-menu-down';
|
||||
this.iconMenuUpClassName = 'icon-menu-up';
|
||||
init() {
|
||||
this.filmstripContainerClassName = 'filmstrip';
|
||||
this.filmstrip = $('#remoteVideos');
|
||||
this.filmstripRemoteVideos = $('#filmstripRemoteVideosContainer');
|
||||
this.eventEmitter = eventEmitter;
|
||||
|
||||
// Show the toggle button and add event listeners only when out of
|
||||
// filmstrip only mode.
|
||||
if (!interfaceConfig.filmStripOnly) {
|
||||
this._initFilmstripToolbar();
|
||||
this.registerListeners();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Initializes the filmstrip toolbar.
|
||||
*/
|
||||
_initFilmstripToolbar() {
|
||||
const toolbarContainerHTML = this._generateToolbarHTML();
|
||||
const className = this.filmstripContainerClassName;
|
||||
const container = document.querySelector(`.${className}`);
|
||||
|
||||
UIUtil.prependChild(container, toolbarContainerHTML);
|
||||
|
||||
const iconSelector = '#toggleFilmstripButton i';
|
||||
|
||||
this.toggleFilmstripIcon = document.querySelector(iconSelector);
|
||||
},
|
||||
|
||||
/**
|
||||
* Generates HTML layout for filmstrip toggle button and wrapping container.
|
||||
* @returns {HTMLElement}
|
||||
* @private
|
||||
*/
|
||||
_generateToolbarHTML() {
|
||||
const container = document.createElement('div');
|
||||
const isVisible = this.isFilmstripVisible();
|
||||
|
||||
container.className = 'filmstrip__toolbar';
|
||||
container.innerHTML = `
|
||||
<button id="toggleFilmstripButton">
|
||||
<i class="icon-menu-${isVisible ? 'down' : 'up'}">
|
||||
</i>
|
||||
</button>
|
||||
`;
|
||||
|
||||
return container;
|
||||
},
|
||||
|
||||
/**
|
||||
* Attach 'click' listener to "hide filmstrip" button
|
||||
*/
|
||||
registerListeners() {
|
||||
// Important:
|
||||
// Firing the event instead of executing toggleFilmstrip method because
|
||||
// it's important to hide the filmstrip by UI.toggleFilmstrip in order
|
||||
// to correctly resize the video area.
|
||||
$('#toggleFilmstripButton').on(
|
||||
'click',
|
||||
() => {
|
||||
// The 'enable' parameter is set to true if the action results
|
||||
// in the filmstrip being hidden.
|
||||
sendAnalytics(createToolbarEvent(
|
||||
'toggle.filmstrip.button',
|
||||
{
|
||||
enable: this.isFilmstripVisible()
|
||||
}));
|
||||
this.eventEmitter.emit(UIEvents.TOGGLE_FILMSTRIP);
|
||||
});
|
||||
|
||||
this._registerToggleFilmstripShortcut();
|
||||
},
|
||||
|
||||
/**
|
||||
* Registering toggle filmstrip shortcut
|
||||
* @private
|
||||
*/
|
||||
_registerToggleFilmstripShortcut() {
|
||||
const shortcut = 'F';
|
||||
const shortcutAttr = 'filmstripPopover';
|
||||
const description = 'keyboardShortcuts.toggleFilmstrip';
|
||||
|
||||
// Important:
|
||||
// Firing the event instead of executing toggleFilmstrip method because
|
||||
// it's important to hide the filmstrip by UI.toggleFilmstrip in order
|
||||
// to correctly resize the video area.
|
||||
const handler = () => {
|
||||
sendAnalytics(createShortcutEvent(
|
||||
'toggle.filmstrip',
|
||||
{
|
||||
enable: this.isFilmstripVisible()
|
||||
}));
|
||||
this.eventEmitter.emit(UIEvents.TOGGLE_FILMSTRIP);
|
||||
};
|
||||
|
||||
APP.keyboardshortcut.registerShortcut(
|
||||
shortcut,
|
||||
shortcutAttr,
|
||||
handler,
|
||||
description
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Changes classes of icon for showing down state
|
||||
*/
|
||||
showMenuDownIcon() {
|
||||
const icon = this.toggleFilmstripIcon;
|
||||
|
||||
if (icon) {
|
||||
icon.classList.add(this.iconMenuDownClassName);
|
||||
icon.classList.remove(this.iconMenuUpClassName);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Changes classes of icon for showing up state
|
||||
*/
|
||||
showMenuUpIcon() {
|
||||
const icon = this.toggleFilmstripIcon;
|
||||
|
||||
if (icon) {
|
||||
icon.classList.add(this.iconMenuUpClassName);
|
||||
icon.classList.remove(this.iconMenuDownClassName);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggles the visibility of the filmstrip, or sets it to a specific value
|
||||
* if the 'visible' parameter is specified.
|
||||
*
|
||||
* @param visible optional {Boolean} which specifies the desired visibility
|
||||
* of the filmstrip. If not specified, the visibility will be flipped
|
||||
* (i.e. toggled); otherwise, the visibility will be set to the specified
|
||||
* value.
|
||||
*
|
||||
* Note:
|
||||
* This method shouldn't be executed directly to hide the filmstrip.
|
||||
* It's important to hide the filmstrip with UI.toggleFilmstrip in order
|
||||
* to correctly resize the video area.
|
||||
*/
|
||||
toggleFilmstrip(visible) {
|
||||
const wasFilmstripVisible = this.isFilmstripVisible();
|
||||
|
||||
// If 'visible' is defined and matches the current state, we have
|
||||
// nothing to do. Otherwise (regardless of whether 'visible' is defined)
|
||||
// we need to toggle the state.
|
||||
if (visible === wasFilmstripVisible) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.filmstrip.toggleClass('hidden');
|
||||
|
||||
if (wasFilmstripVisible) {
|
||||
this.showMenuUpIcon();
|
||||
} else {
|
||||
this.showMenuDownIcon();
|
||||
}
|
||||
|
||||
if (this.eventEmitter) {
|
||||
this.eventEmitter.emit(
|
||||
UIEvents.TOGGLED_FILMSTRIP,
|
||||
!wasFilmstripVisible);
|
||||
}
|
||||
APP.store.dispatch(setFilmstripVisible(!wasFilmstripVisible));
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -198,14 +25,7 @@ const Filmstrip = {
|
|||
* @returns {boolean}
|
||||
*/
|
||||
isFilmstripVisible() {
|
||||
return !this.filmstrip.hasClass('hidden');
|
||||
},
|
||||
|
||||
/**
|
||||
* Adjusts styles for filmstrip-only mode.
|
||||
*/
|
||||
setFilmstripOnly() {
|
||||
this.filmstrip.addClass('filmstrip__videos-filmstripOnly');
|
||||
return APP.store.getState()['features/filmstrip'].visible;
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,13 +4,19 @@ import _ from 'lodash';
|
|||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import {
|
||||
createShortcutEvent,
|
||||
createToolbarEvent,
|
||||
sendAnalytics
|
||||
} from '../../../analytics';
|
||||
import { dockToolbox } from '../../../toolbox';
|
||||
|
||||
import { setFilmstripHovered } from '../../actions';
|
||||
import { setFilmstripHovered, setFilmstripVisible } from '../../actions';
|
||||
import { shouldRemoteVideosBeVisible } from '../../functions';
|
||||
|
||||
import Toolbar from './Toolbar';
|
||||
|
||||
declare var APP: Object;
|
||||
declare var interfaceConfig: Object;
|
||||
|
||||
/**
|
||||
|
@ -34,6 +40,16 @@ type Props = {
|
|||
*/
|
||||
_hovered: boolean,
|
||||
|
||||
/**
|
||||
* Additional CSS class names to add to the container of all the thumbnails.
|
||||
*/
|
||||
_videosClassName: string,
|
||||
|
||||
/**
|
||||
* Whether or not the filmstrip videos should currently be displayed.
|
||||
*/
|
||||
_visible: boolean,
|
||||
|
||||
/**
|
||||
* The redux {@code dispatch} function.
|
||||
*/
|
||||
|
@ -79,6 +95,35 @@ class Filmstrip extends Component <Props> {
|
|||
// Bind event handlers so they are only bound once for every instance.
|
||||
this._onMouseOut = this._onMouseOut.bind(this);
|
||||
this._onMouseOver = this._onMouseOver.bind(this);
|
||||
this._onShortcutToggleFilmstrip
|
||||
= this._onShortcutToggleFilmstrip.bind(this);
|
||||
this._onToolbarToggleFilmstrip
|
||||
= this._onToolbarToggleFilmstrip.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#componentDidMount}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentDidMount() {
|
||||
if (!this.props._filmstripOnly) {
|
||||
APP.keyboardshortcut.registerShortcut(
|
||||
'F',
|
||||
'filmstripPopover',
|
||||
this._onShortcutToggleFilmstrip,
|
||||
'keyboardShortcuts.toggleFilmstrip'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#componentDidUpdate}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentWillUnmount() {
|
||||
APP.keyboardshortcut.unregisterShortcut('F');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -97,9 +142,10 @@ class Filmstrip extends Component <Props> {
|
|||
|
||||
return (
|
||||
<div className = { `filmstrip ${this.props._className}` }>
|
||||
{ this.props._filmstripOnly && <Toolbar /> }
|
||||
{ this.props._filmstripOnly
|
||||
? <Toolbar /> : this._renderToggleButton() }
|
||||
<div
|
||||
className = 'filmstrip__videos'
|
||||
className = { this.props._videosClassName }
|
||||
id = 'remoteVideos'>
|
||||
<div
|
||||
className = 'filmstrip__videos'
|
||||
|
@ -129,6 +175,16 @@ class Filmstrip extends Component <Props> {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches an action to change the visibility of the filmstrip.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_doToggleFilmstrip() {
|
||||
this.props.dispatch(setFilmstripVisible(!this.props._visible));
|
||||
}
|
||||
|
||||
/**
|
||||
* If the current hover state does not match the known hover state in redux,
|
||||
* dispatch an action to update the known hover state in redux.
|
||||
|
@ -166,6 +222,65 @@ class Filmstrip extends Component <Props> {
|
|||
this._isHovered = true;
|
||||
this._notifyOfHoveredStateUpdate();
|
||||
}
|
||||
|
||||
_onShortcutToggleFilmstrip: () => void;
|
||||
|
||||
/**
|
||||
* Creates an analytics keyboard shortcut event and dispatches an action for
|
||||
* toggling filmstrip visibility.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onShortcutToggleFilmstrip() {
|
||||
sendAnalytics(createShortcutEvent(
|
||||
'toggle.filmstrip',
|
||||
{
|
||||
enable: this.props._visible
|
||||
}));
|
||||
|
||||
this._doToggleFilmstrip();
|
||||
}
|
||||
|
||||
_onToolbarToggleFilmstrip: () => void;
|
||||
|
||||
/**
|
||||
* Creates an analytics toolbar event and dispatches an action for opening
|
||||
* the speaker stats modal.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onToolbarToggleFilmstrip() {
|
||||
sendAnalytics(createToolbarEvent(
|
||||
'toggle.filmstrip.button',
|
||||
{
|
||||
enable: this.props._visible
|
||||
}));
|
||||
|
||||
this._doToggleFilmstrip();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a React Element for changing the visibility of the filmstrip when
|
||||
* clicked.
|
||||
*
|
||||
* @private
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderToggleButton() {
|
||||
const icon = this.props._visible ? 'icon-menu-down' : 'icon-menu-up';
|
||||
|
||||
return (
|
||||
<div className = 'filmstrip__toolbar'>
|
||||
<button
|
||||
id = 'toggleFilmstripButton'
|
||||
onClick = { this._onToolbarToggleFilmstrip }>
|
||||
<i className = { icon } />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -175,12 +290,14 @@ class Filmstrip extends Component <Props> {
|
|||
* @private
|
||||
* @returns {{
|
||||
* _className: string,
|
||||
* _filmstripOnly: boolean,
|
||||
* _hovered: boolean,
|
||||
* _filmstripOnly: boolean
|
||||
* _videosClassName: string,
|
||||
* _visible: boolean
|
||||
* }}
|
||||
*/
|
||||
function _mapStateToProps(state) {
|
||||
const { hovered } = state['features/filmstrip'];
|
||||
const { hovered, visible } = state['features/filmstrip'];
|
||||
const isFilmstripOnly = Boolean(interfaceConfig.filmStripOnly);
|
||||
const reduceHeight = !isFilmstripOnly
|
||||
&& state['features/toolbox'].visible
|
||||
|
@ -188,11 +305,16 @@ function _mapStateToProps(state) {
|
|||
const remoteVideosVisible = shouldRemoteVideosBeVisible(state);
|
||||
const className = `${remoteVideosVisible ? '' : 'hide-videos'} ${
|
||||
reduceHeight ? 'reduce-height' : ''}`.trim();
|
||||
const videosClassName = `filmstrip__videos ${
|
||||
isFilmstripOnly ? 'filmstrip__videos-filmstripOnly' : ''} ${
|
||||
visible ? '' : 'hidden'}`;
|
||||
|
||||
return {
|
||||
_className: className,
|
||||
_filmstripOnly: isFilmstripOnly,
|
||||
_hovered: hovered
|
||||
_hovered: hovered,
|
||||
_videosClassName: videosClassName,
|
||||
_visible: visible
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ import {
|
|||
} from '../base/participants';
|
||||
import { MiddlewareRegistry } from '../base/redux';
|
||||
import { TRACK_ADDED } from '../base/tracks';
|
||||
import { SET_FILMSTRIP_VISIBLE } from '../filmstrip';
|
||||
|
||||
import { SET_TILE_VIEW } from './actionTypes';
|
||||
|
||||
|
@ -73,6 +74,11 @@ MiddlewareRegistry.register(store => next => action => {
|
|||
Boolean(action.participant.id));
|
||||
break;
|
||||
|
||||
case SET_FILMSTRIP_VISIBLE:
|
||||
VideoLayout.resizeVideoArea(true, false);
|
||||
APP.UI.emitEvent(UIEvents.TOGGLED_FILMSTRIP, action.visible);
|
||||
break;
|
||||
|
||||
case SET_TILE_VIEW:
|
||||
APP.UI.emitEvent(UIEvents.TOGGLED_TILE_VIEW, action.enabled);
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue