Преглед на файлове

feat(filmstrip): reactify the filmstrip toggle button

master
Leonard Kim преди 7 години
родител
ревизия
0fca0f392d
променени са 4 файла, в които са добавени 142 реда и са изтрити 199 реда
  1. 5
    10
      modules/UI/UI.js
  2. 3
    183
      modules/UI/videolayout/Filmstrip.js
  3. 128
    6
      react/features/filmstrip/components/web/Filmstrip.js
  4. 6
    0
      react/features/video-layout/middleware.web.js

+ 5
- 10
modules/UI/UI.js Целия файл

24
 import { destroyLocalTracks } from '../../react/features/base/tracks';
24
 import { destroyLocalTracks } from '../../react/features/base/tracks';
25
 import { openDisplayNamePrompt } from '../../react/features/display-name';
25
 import { openDisplayNamePrompt } from '../../react/features/display-name';
26
 import { setEtherpadHasInitialzied } from '../../react/features/etherpad';
26
 import { setEtherpadHasInitialzied } from '../../react/features/etherpad';
27
+import { setFilmstripVisible } from '../../react/features/filmstrip';
27
 import {
28
 import {
28
     setNotificationsEnabled,
29
     setNotificationsEnabled,
29
     showWarningNotification
30
     showWarningNotification
93
         () => UI.toggleChat()
94
         () => UI.toggleChat()
94
     ], [
95
     ], [
95
         UIEvents.TOGGLE_FILMSTRIP,
96
         UIEvents.TOGGLE_FILMSTRIP,
96
-        () => UI.handleToggleFilmstrip()
97
+        () => UI.toggleFilmstrip()
97
     ], [
98
     ], [
98
         UIEvents.FOLLOW_ME_ENABLED,
99
         UIEvents.FOLLOW_ME_ENABLED,
99
         enabled => followMeHandler && followMeHandler.enableFollowMe(enabled)
100
         enabled => followMeHandler && followMeHandler.enableFollowMe(enabled)
255
     followMeHandler = new FollowMe(APP.conference, UI);
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
  * Returns the shared document manager object.
260
  * Returns the shared document manager object.
265
  * @return {EtherpadManager} the shared document manager object
261
  * @return {EtherpadManager} the shared document manager object
298
 
294
 
299
     if (interfaceConfig.filmStripOnly) {
295
     if (interfaceConfig.filmStripOnly) {
300
         $('body').addClass('filmstrip-only');
296
         $('body').addClass('filmstrip-only');
301
-        Filmstrip.setFilmstripOnly();
302
         APP.store.dispatch(setNotificationsEnabled(false));
297
         APP.store.dispatch(setNotificationsEnabled(false));
303
     } else {
298
     } else {
304
         // Initialize recording mode UI.
299
         // Initialize recording mode UI.
512
  * Toggles filmstrip.
507
  * Toggles filmstrip.
513
  */
508
  */
514
 UI.toggleFilmstrip = function() {
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 Целия файл

1
 /* global $, APP, interfaceConfig */
1
 /* global $, APP, interfaceConfig */
2
 
2
 
3
-import { setFilmstripVisible } from '../../../react/features/filmstrip';
4
 import {
3
 import {
5
     LAYOUTS,
4
     LAYOUTS,
6
     getCurrentLayout,
5
     getCurrentLayout,
9
     shouldDisplayTileView
8
     shouldDisplayTileView
10
 } from '../../../react/features/video-layout';
9
 } from '../../../react/features/video-layout';
11
 
10
 
12
-import UIEvents from '../../../service/UI/UIEvents';
13
 import UIUtil from '../util/UIUtil';
11
 import UIUtil from '../util/UIUtil';
14
 
12
 
15
-import {
16
-    createShortcutEvent,
17
-    createToolbarEvent,
18
-    sendAnalytics
19
-} from '../../../react/features/analytics';
20
-
21
 const Filmstrip = {
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
         this.filmstripContainerClassName = 'filmstrip';
18
         this.filmstripContainerClassName = 'filmstrip';
31
         this.filmstrip = $('#remoteVideos');
19
         this.filmstrip = $('#remoteVideos');
32
         this.filmstripRemoteVideos = $('#filmstripRemoteVideosContainer');
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
      * @returns {boolean}
25
      * @returns {boolean}
199
      */
26
      */
200
     isFilmstripVisible() {
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 Целия файл

4
 import React, { Component } from 'react';
4
 import React, { Component } from 'react';
5
 import { connect } from 'react-redux';
5
 import { connect } from 'react-redux';
6
 
6
 
7
+import {
8
+    createShortcutEvent,
9
+    createToolbarEvent,
10
+    sendAnalytics
11
+} from '../../../analytics';
7
 import { dockToolbox } from '../../../toolbox';
12
 import { dockToolbox } from '../../../toolbox';
8
 
13
 
9
-import { setFilmstripHovered } from '../../actions';
14
+import { setFilmstripHovered, setFilmstripVisible } from '../../actions';
10
 import { shouldRemoteVideosBeVisible } from '../../functions';
15
 import { shouldRemoteVideosBeVisible } from '../../functions';
11
 
16
 
12
 import Toolbar from './Toolbar';
17
 import Toolbar from './Toolbar';
13
 
18
 
19
+declare var APP: Object;
14
 declare var interfaceConfig: Object;
20
 declare var interfaceConfig: Object;
15
 
21
 
16
 /**
22
 /**
34
      */
40
      */
35
     _hovered: boolean,
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
      * The redux {@code dispatch} function.
54
      * The redux {@code dispatch} function.
39
      */
55
      */
79
         // Bind event handlers so they are only bound once for every instance.
95
         // Bind event handlers so they are only bound once for every instance.
80
         this._onMouseOut = this._onMouseOut.bind(this);
96
         this._onMouseOut = this._onMouseOut.bind(this);
81
         this._onMouseOver = this._onMouseOver.bind(this);
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
 
142
 
98
         return (
143
         return (
99
             <div className = { `filmstrip ${this.props._className}` }>
144
             <div className = { `filmstrip ${this.props._className}` }>
100
-                { this.props._filmstripOnly && <Toolbar /> }
145
+                { this.props._filmstripOnly
146
+                    ? <Toolbar /> : this._renderToggleButton() }
101
                 <div
147
                 <div
102
-                    className = 'filmstrip__videos'
148
+                    className = { this.props._videosClassName }
103
                     id = 'remoteVideos'>
149
                     id = 'remoteVideos'>
104
                     <div
150
                     <div
105
                         className = 'filmstrip__videos'
151
                         className = 'filmstrip__videos'
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
      * If the current hover state does not match the known hover state in redux,
189
      * If the current hover state does not match the known hover state in redux,
134
      * dispatch an action to update the known hover state in redux.
190
      * dispatch an action to update the known hover state in redux.
166
         this._isHovered = true;
222
         this._isHovered = true;
167
         this._notifyOfHoveredStateUpdate();
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
  * @private
290
  * @private
176
  * @returns {{
291
  * @returns {{
177
  *     _className: string,
292
  *     _className: string,
293
+ *     _filmstripOnly: boolean,
178
  *     _hovered: boolean,
294
  *     _hovered: boolean,
179
- *     _filmstripOnly: boolean
295
+ *     _videosClassName: string,
296
+ *     _visible: boolean
180
  * }}
297
  * }}
181
  */
298
  */
182
 function _mapStateToProps(state) {
299
 function _mapStateToProps(state) {
183
-    const { hovered } = state['features/filmstrip'];
300
+    const { hovered, visible } = state['features/filmstrip'];
184
     const isFilmstripOnly = Boolean(interfaceConfig.filmStripOnly);
301
     const isFilmstripOnly = Boolean(interfaceConfig.filmStripOnly);
185
     const reduceHeight = !isFilmstripOnly
302
     const reduceHeight = !isFilmstripOnly
186
         && state['features/toolbox'].visible
303
         && state['features/toolbox'].visible
188
     const remoteVideosVisible = shouldRemoteVideosBeVisible(state);
305
     const remoteVideosVisible = shouldRemoteVideosBeVisible(state);
189
     const className = `${remoteVideosVisible ? '' : 'hide-videos'} ${
306
     const className = `${remoteVideosVisible ? '' : 'hide-videos'} ${
190
         reduceHeight ? 'reduce-height' : ''}`.trim();
307
         reduceHeight ? 'reduce-height' : ''}`.trim();
308
+    const videosClassName = `filmstrip__videos ${
309
+        isFilmstripOnly ? 'filmstrip__videos-filmstripOnly' : ''} ${
310
+        visible ? '' : 'hidden'}`;
191
 
311
 
192
     return {
312
     return {
193
         _className: className,
313
         _className: className,
194
         _filmstripOnly: isFilmstripOnly,
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 Целия файл

14
 } from '../base/participants';
14
 } from '../base/participants';
15
 import { MiddlewareRegistry } from '../base/redux';
15
 import { MiddlewareRegistry } from '../base/redux';
16
 import { TRACK_ADDED } from '../base/tracks';
16
 import { TRACK_ADDED } from '../base/tracks';
17
+import { SET_FILMSTRIP_VISIBLE } from '../filmstrip';
17
 
18
 
18
 import { SET_TILE_VIEW } from './actionTypes';
19
 import { SET_TILE_VIEW } from './actionTypes';
19
 
20
 
73
             Boolean(action.participant.id));
74
             Boolean(action.participant.id));
74
         break;
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
     case SET_TILE_VIEW:
82
     case SET_TILE_VIEW:
77
         APP.UI.emitEvent(UIEvents.TOGGLED_TILE_VIEW, action.enabled);
83
         APP.UI.emitEvent(UIEvents.TOGGLED_TILE_VIEW, action.enabled);
78
         break;
84
         break;

Loading…
Отказ
Запис