Selaa lähdekoodia

feat(filmstrip): reactify the filmstrip toggle button

j8
Leonard Kim 7 vuotta sitten
vanhempi
commit
0fca0f392d

+ 5
- 10
modules/UI/UI.js Näytä tiedosto

@@ -24,6 +24,7 @@ import {
24 24
 import { destroyLocalTracks } from '../../react/features/base/tracks';
25 25
 import { openDisplayNamePrompt } from '../../react/features/display-name';
26 26
 import { setEtherpadHasInitialzied } from '../../react/features/etherpad';
27
+import { setFilmstripVisible } from '../../react/features/filmstrip';
27 28
 import {
28 29
     setNotificationsEnabled,
29 30
     showWarningNotification
@@ -93,7 +94,7 @@ const UIListeners = new Map([
93 94
         () => UI.toggleChat()
94 95
     ], [
95 96
         UIEvents.TOGGLE_FILMSTRIP,
96
-        () => UI.handleToggleFilmstrip()
97
+        () => UI.toggleFilmstrip()
97 98
     ], [
98 99
         UIEvents.FOLLOW_ME_ENABLED,
99 100
         enabled => followMeHandler && followMeHandler.enableFollowMe(enabled)
@@ -255,11 +256,6 @@ UI.initConference = function() {
255 256
     followMeHandler = new FollowMe(APP.conference, UI);
256 257
 };
257 258
 
258
-/** *
259
- * Handler for toggling filmstrip
260
- */
261
-UI.handleToggleFilmstrip = () => UI.toggleFilmstrip();
262
-
263 259
 /**
264 260
  * Returns the shared document manager object.
265 261
  * @return {EtherpadManager} the shared document manager object
@@ -298,7 +294,6 @@ UI.start = function() {
298 294
 
299 295
     if (interfaceConfig.filmStripOnly) {
300 296
         $('body').addClass('filmstrip-only');
301
-        Filmstrip.setFilmstripOnly();
302 297
         APP.store.dispatch(setNotificationsEnabled(false));
303 298
     } else {
304 299
         // Initialize recording mode UI.
@@ -512,9 +507,9 @@ UI.toggleSmileys = () => Chat.toggleSmileys();
512 507
  * Toggles filmstrip.
513 508
  */
514 509
 UI.toggleFilmstrip = function() {
515
-    // eslint-disable-next-line prefer-rest-params
516
-    Filmstrip.toggleFilmstrip(...arguments);
517
-    VideoLayout.resizeVideoArea(true, false);
510
+    const { visible } = APP.store.getState()['features/filmstrip'];
511
+
512
+    APP.store.dispatch(setFilmstripVisible(!visible));
518 513
 };
519 514
 
520 515
 /**

+ 3
- 183
modules/UI/videolayout/Filmstrip.js Näytä tiedosto

@@ -1,6 +1,5 @@
1 1
 /* global $, APP, interfaceConfig */
2 2
 
3
-import { setFilmstripVisible } from '../../../react/features/filmstrip';
4 3
 import {
5 4
     LAYOUTS,
6 5
     getCurrentLayout,
@@ -9,188 +8,16 @@ import {
9 8
     shouldDisplayTileView
10 9
 } from '../../../react/features/video-layout';
11 10
 
12
-import UIEvents from '../../../service/UI/UIEvents';
13 11
 import UIUtil from '../util/UIUtil';
14 12
 
15
-import {
16
-    createShortcutEvent,
17
-    createToolbarEvent,
18
-    sendAnalytics
19
-} from '../../../react/features/analytics';
20
-
21 13
 const Filmstrip = {
22 14
     /**
23
-     *
24
-     * @param eventEmitter the {EventEmitter} through which {Filmstrip} is to
25
-     * emit/fire {UIEvents} (such as {UIEvents.TOGGLED_FILMSTRIP}).
15
+     * Caches jquery lookups of the filmstrip for future use.
26 16
      */
27
-    init(eventEmitter) {
28
-        this.iconMenuDownClassName = 'icon-menu-down';
29
-        this.iconMenuUpClassName = 'icon-menu-up';
17
+    init() {
30 18
         this.filmstripContainerClassName = 'filmstrip';
31 19
         this.filmstrip = $('#remoteVideos');
32 20
         this.filmstripRemoteVideos = $('#filmstripRemoteVideosContainer');
33
-        this.eventEmitter = eventEmitter;
34
-
35
-        // Show the toggle button and add event listeners only when out of
36
-        // filmstrip only mode.
37
-        if (!interfaceConfig.filmStripOnly) {
38
-            this._initFilmstripToolbar();
39
-            this.registerListeners();
40
-        }
41
-    },
42
-
43
-    /**
44
-     * Initializes the filmstrip toolbar.
45
-     */
46
-    _initFilmstripToolbar() {
47
-        const toolbarContainerHTML = this._generateToolbarHTML();
48
-        const className = this.filmstripContainerClassName;
49
-        const container = document.querySelector(`.${className}`);
50
-
51
-        UIUtil.prependChild(container, toolbarContainerHTML);
52
-
53
-        const iconSelector = '#toggleFilmstripButton i';
54
-
55
-        this.toggleFilmstripIcon = document.querySelector(iconSelector);
56
-    },
57
-
58
-    /**
59
-     * Generates HTML layout for filmstrip toggle button and wrapping container.
60
-     * @returns {HTMLElement}
61
-     * @private
62
-     */
63
-    _generateToolbarHTML() {
64
-        const container = document.createElement('div');
65
-        const isVisible = this.isFilmstripVisible();
66
-
67
-        container.className = 'filmstrip__toolbar';
68
-        container.innerHTML = `
69
-            <button id="toggleFilmstripButton">
70
-                <i class="icon-menu-${isVisible ? 'down' : 'up'}">
71
-                </i>
72
-            </button>
73
-        `;
74
-
75
-        return container;
76
-    },
77
-
78
-    /**
79
-     * Attach 'click' listener to "hide filmstrip" button
80
-     */
81
-    registerListeners() {
82
-        // Important:
83
-        // Firing the event instead of executing toggleFilmstrip method because
84
-        // it's important to hide the filmstrip by UI.toggleFilmstrip in order
85
-        // to correctly resize the video area.
86
-        $('#toggleFilmstripButton').on(
87
-            'click',
88
-            () => {
89
-                // The 'enable' parameter is set to true if the action results
90
-                // in the filmstrip being hidden.
91
-                sendAnalytics(createToolbarEvent(
92
-                    'toggle.filmstrip.button',
93
-                    {
94
-                        enable: this.isFilmstripVisible()
95
-                    }));
96
-                this.eventEmitter.emit(UIEvents.TOGGLE_FILMSTRIP);
97
-            });
98
-
99
-        this._registerToggleFilmstripShortcut();
100
-    },
101
-
102
-    /**
103
-     * Registering toggle filmstrip shortcut
104
-     * @private
105
-     */
106
-    _registerToggleFilmstripShortcut() {
107
-        const shortcut = 'F';
108
-        const shortcutAttr = 'filmstripPopover';
109
-        const description = 'keyboardShortcuts.toggleFilmstrip';
110
-
111
-        // Important:
112
-        // Firing the event instead of executing toggleFilmstrip method because
113
-        // it's important to hide the filmstrip by UI.toggleFilmstrip in order
114
-        // to correctly resize the video area.
115
-        const handler = () => {
116
-            sendAnalytics(createShortcutEvent(
117
-                'toggle.filmstrip',
118
-                {
119
-                    enable: this.isFilmstripVisible()
120
-                }));
121
-            this.eventEmitter.emit(UIEvents.TOGGLE_FILMSTRIP);
122
-        };
123
-
124
-        APP.keyboardshortcut.registerShortcut(
125
-            shortcut,
126
-            shortcutAttr,
127
-            handler,
128
-            description
129
-        );
130
-    },
131
-
132
-    /**
133
-     * Changes classes of icon for showing down state
134
-     */
135
-    showMenuDownIcon() {
136
-        const icon = this.toggleFilmstripIcon;
137
-
138
-        if (icon) {
139
-            icon.classList.add(this.iconMenuDownClassName);
140
-            icon.classList.remove(this.iconMenuUpClassName);
141
-        }
142
-    },
143
-
144
-    /**
145
-     * Changes classes of icon for showing up state
146
-     */
147
-    showMenuUpIcon() {
148
-        const icon = this.toggleFilmstripIcon;
149
-
150
-        if (icon) {
151
-            icon.classList.add(this.iconMenuUpClassName);
152
-            icon.classList.remove(this.iconMenuDownClassName);
153
-        }
154
-    },
155
-
156
-    /**
157
-     * Toggles the visibility of the filmstrip, or sets it to a specific value
158
-     * if the 'visible' parameter is specified.
159
-     *
160
-     * @param visible optional {Boolean} which specifies the desired visibility
161
-     * of the filmstrip. If not specified, the visibility will be flipped
162
-     * (i.e. toggled); otherwise, the visibility will be set to the specified
163
-     * value.
164
-     *
165
-     * Note:
166
-     * This method shouldn't be executed directly to hide the filmstrip.
167
-     * It's important to hide the filmstrip with UI.toggleFilmstrip in order
168
-     * to correctly resize the video area.
169
-     */
170
-    toggleFilmstrip(visible) {
171
-        const wasFilmstripVisible = this.isFilmstripVisible();
172
-
173
-        // If 'visible' is defined and matches the current state, we have
174
-        // nothing to do. Otherwise (regardless of whether 'visible' is defined)
175
-        // we need to toggle the state.
176
-        if (visible === wasFilmstripVisible) {
177
-            return;
178
-        }
179
-
180
-        this.filmstrip.toggleClass('hidden');
181
-
182
-        if (wasFilmstripVisible) {
183
-            this.showMenuUpIcon();
184
-        } else {
185
-            this.showMenuDownIcon();
186
-        }
187
-
188
-        if (this.eventEmitter) {
189
-            this.eventEmitter.emit(
190
-                UIEvents.TOGGLED_FILMSTRIP,
191
-                !wasFilmstripVisible);
192
-        }
193
-        APP.store.dispatch(setFilmstripVisible(!wasFilmstripVisible));
194 21
     },
195 22
 
196 23
     /**
@@ -198,14 +25,7 @@ const Filmstrip = {
198 25
      * @returns {boolean}
199 26
      */
200 27
     isFilmstripVisible() {
201
-        return !this.filmstrip.hasClass('hidden');
202
-    },
203
-
204
-    /**
205
-     * Adjusts styles for filmstrip-only mode.
206
-     */
207
-    setFilmstripOnly() {
208
-        this.filmstrip.addClass('filmstrip__videos-filmstripOnly');
28
+        return APP.store.getState()['features/filmstrip'].visible;
209 29
     },
210 30
 
211 31
     /**

+ 128
- 6
react/features/filmstrip/components/web/Filmstrip.js Näytä tiedosto

@@ -4,13 +4,19 @@ import _ from 'lodash';
4 4
 import React, { Component } from 'react';
5 5
 import { connect } from 'react-redux';
6 6
 
7
+import {
8
+    createShortcutEvent,
9
+    createToolbarEvent,
10
+    sendAnalytics
11
+} from '../../../analytics';
7 12
 import { dockToolbox } from '../../../toolbox';
8 13
 
9
-import { setFilmstripHovered } from '../../actions';
14
+import { setFilmstripHovered, setFilmstripVisible } from '../../actions';
10 15
 import { shouldRemoteVideosBeVisible } from '../../functions';
11 16
 
12 17
 import Toolbar from './Toolbar';
13 18
 
19
+declare var APP: Object;
14 20
 declare var interfaceConfig: Object;
15 21
 
16 22
 /**
@@ -34,6 +40,16 @@ type Props = {
34 40
      */
35 41
     _hovered: boolean,
36 42
 
43
+    /**
44
+     * Additional CSS class names to add to the container of all the thumbnails.
45
+     */
46
+    _videosClassName: string,
47
+
48
+    /**
49
+     * Whether or not the filmstrip videos should currently be displayed.
50
+     */
51
+    _visible: boolean,
52
+
37 53
     /**
38 54
      * The redux {@code dispatch} function.
39 55
      */
@@ -79,6 +95,35 @@ class Filmstrip extends Component <Props> {
79 95
         // Bind event handlers so they are only bound once for every instance.
80 96
         this._onMouseOut = this._onMouseOut.bind(this);
81 97
         this._onMouseOver = this._onMouseOver.bind(this);
98
+        this._onShortcutToggleFilmstrip
99
+            = this._onShortcutToggleFilmstrip.bind(this);
100
+        this._onToolbarToggleFilmstrip
101
+            = this._onToolbarToggleFilmstrip.bind(this);
102
+    }
103
+
104
+    /**
105
+     * Implements React's {@link Component#componentDidMount}.
106
+     *
107
+     * @inheritdoc
108
+     */
109
+    componentDidMount() {
110
+        if (!this.props._filmstripOnly) {
111
+            APP.keyboardshortcut.registerShortcut(
112
+                'F',
113
+                'filmstripPopover',
114
+                this._onShortcutToggleFilmstrip,
115
+                'keyboardShortcuts.toggleFilmstrip'
116
+            );
117
+        }
118
+    }
119
+
120
+    /**
121
+     * Implements React's {@link Component#componentDidUpdate}.
122
+     *
123
+     * @inheritdoc
124
+     */
125
+    componentWillUnmount() {
126
+        APP.keyboardshortcut.unregisterShortcut('F');
82 127
     }
83 128
 
84 129
     /**
@@ -97,9 +142,10 @@ class Filmstrip extends Component <Props> {
97 142
 
98 143
         return (
99 144
             <div className = { `filmstrip ${this.props._className}` }>
100
-                { this.props._filmstripOnly && <Toolbar /> }
145
+                { this.props._filmstripOnly
146
+                    ? <Toolbar /> : this._renderToggleButton() }
101 147
                 <div
102
-                    className = 'filmstrip__videos'
148
+                    className = { this.props._videosClassName }
103 149
                     id = 'remoteVideos'>
104 150
                     <div
105 151
                         className = 'filmstrip__videos'
@@ -129,6 +175,16 @@ class Filmstrip extends Component <Props> {
129 175
         );
130 176
     }
131 177
 
178
+    /**
179
+     * Dispatches an action to change the visibility of the filmstrip.
180
+     *
181
+     * @private
182
+     * @returns {void}
183
+     */
184
+    _doToggleFilmstrip() {
185
+        this.props.dispatch(setFilmstripVisible(!this.props._visible));
186
+    }
187
+
132 188
     /**
133 189
      * If the current hover state does not match the known hover state in redux,
134 190
      * dispatch an action to update the known hover state in redux.
@@ -166,6 +222,65 @@ class Filmstrip extends Component <Props> {
166 222
         this._isHovered = true;
167 223
         this._notifyOfHoveredStateUpdate();
168 224
     }
225
+
226
+    _onShortcutToggleFilmstrip: () => void;
227
+
228
+    /**
229
+     * Creates an analytics keyboard shortcut event and dispatches an action for
230
+     * toggling filmstrip visibility.
231
+     *
232
+     * @private
233
+     * @returns {void}
234
+     */
235
+    _onShortcutToggleFilmstrip() {
236
+        sendAnalytics(createShortcutEvent(
237
+            'toggle.filmstrip',
238
+            {
239
+                enable: this.props._visible
240
+            }));
241
+
242
+        this._doToggleFilmstrip();
243
+    }
244
+
245
+    _onToolbarToggleFilmstrip: () => void;
246
+
247
+    /**
248
+     * Creates an analytics toolbar event and dispatches an action for opening
249
+     * the speaker stats modal.
250
+     *
251
+     * @private
252
+     * @returns {void}
253
+     */
254
+    _onToolbarToggleFilmstrip() {
255
+        sendAnalytics(createToolbarEvent(
256
+            'toggle.filmstrip.button',
257
+            {
258
+                enable: this.props._visible
259
+            }));
260
+
261
+        this._doToggleFilmstrip();
262
+    }
263
+
264
+    /**
265
+     * Creates a React Element for changing the visibility of the filmstrip when
266
+     * clicked.
267
+     *
268
+     * @private
269
+     * @returns {ReactElement}
270
+     */
271
+    _renderToggleButton() {
272
+        const icon = this.props._visible ? 'icon-menu-down' : 'icon-menu-up';
273
+
274
+        return (
275
+            <div className = 'filmstrip__toolbar'>
276
+                <button
277
+                    id = 'toggleFilmstripButton'
278
+                    onClick = { this._onToolbarToggleFilmstrip }>
279
+                    <i className = { icon } />
280
+                </button>
281
+            </div>
282
+        );
283
+    }
169 284
 }
170 285
 
171 286
 /**
@@ -175,12 +290,14 @@ class Filmstrip extends Component <Props> {
175 290
  * @private
176 291
  * @returns {{
177 292
  *     _className: string,
293
+ *     _filmstripOnly: boolean,
178 294
  *     _hovered: boolean,
179
- *     _filmstripOnly: boolean
295
+ *     _videosClassName: string,
296
+ *     _visible: boolean
180 297
  * }}
181 298
  */
182 299
 function _mapStateToProps(state) {
183
-    const { hovered } = state['features/filmstrip'];
300
+    const { hovered, visible } = state['features/filmstrip'];
184 301
     const isFilmstripOnly = Boolean(interfaceConfig.filmStripOnly);
185 302
     const reduceHeight = !isFilmstripOnly
186 303
         && state['features/toolbox'].visible
@@ -188,11 +305,16 @@ function _mapStateToProps(state) {
188 305
     const remoteVideosVisible = shouldRemoteVideosBeVisible(state);
189 306
     const className = `${remoteVideosVisible ? '' : 'hide-videos'} ${
190 307
         reduceHeight ? 'reduce-height' : ''}`.trim();
308
+    const videosClassName = `filmstrip__videos ${
309
+        isFilmstripOnly ? 'filmstrip__videos-filmstripOnly' : ''} ${
310
+        visible ? '' : 'hidden'}`;
191 311
 
192 312
     return {
193 313
         _className: className,
194 314
         _filmstripOnly: isFilmstripOnly,
195
-        _hovered: hovered
315
+        _hovered: hovered,
316
+        _videosClassName: videosClassName,
317
+        _visible: visible
196 318
     };
197 319
 }
198 320
 

+ 6
- 0
react/features/video-layout/middleware.web.js Näytä tiedosto

@@ -14,6 +14,7 @@ import {
14 14
 } from '../base/participants';
15 15
 import { MiddlewareRegistry } from '../base/redux';
16 16
 import { TRACK_ADDED } from '../base/tracks';
17
+import { SET_FILMSTRIP_VISIBLE } from '../filmstrip';
17 18
 
18 19
 import { SET_TILE_VIEW } from './actionTypes';
19 20
 
@@ -73,6 +74,11 @@ MiddlewareRegistry.register(store => next => action => {
73 74
             Boolean(action.participant.id));
74 75
         break;
75 76
 
77
+    case SET_FILMSTRIP_VISIBLE:
78
+        VideoLayout.resizeVideoArea(true, false);
79
+        APP.UI.emitEvent(UIEvents.TOGGLED_FILMSTRIP, action.visible);
80
+        break;
81
+
76 82
     case SET_TILE_VIEW:
77 83
         APP.UI.emitEvent(UIEvents.TOGGLED_TILE_VIEW, action.enabled);
78 84
         break;

Loading…
Peruuta
Tallenna