feat(filmstrip): reactify the filmstrip toggle button

This commit is contained in:
Leonard Kim 2018-09-10 15:10:45 -07:00 committed by yanas
parent c25d6eb9a8
commit 0fca0f392d
4 changed files with 142 additions and 199 deletions

View File

@ -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));
};
/**

View File

@ -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;
},
/**

View File

@ -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
};
}

View File

@ -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;