浏览代码

feat(chat): Make chat push content to the side in large view

master
Mihai Uscat 5 年前
父节点
当前提交
5f5468995f

+ 1
- 6
css/_chat.scss 查看文件

4
     color: #FFF;
4
     color: #FFF;
5
     display: flex;
5
     display: flex;
6
     flex-direction: column;
6
     flex-direction: column;
7
-    /**
8
-     * Make the sidebar flush with the top of the toolbar. Take the size of
9
-     * the toolbar and subtract from 100%.
10
-     */
11
-    height: calc(100% - #{$newToolbarSizeWithPadding});
7
+    height: 100%;
12
     left: -$sidebarWidth;
8
     left: -$sidebarWidth;
13
     overflow: hidden;
9
     overflow: hidden;
14
     position: absolute;
10
     position: absolute;
15
     top: 0;
11
     top: 0;
16
-    transition: left 0.5s;
17
     width: $sidebarWidth;
12
     width: $sidebarWidth;
18
     z-index: $sideToolbarContainerZ;
13
     z-index: $sideToolbarContainerZ;
19
 
14
 

+ 5
- 0
css/_toolbars.scss 查看文件

42
         display: none;
42
         display: none;
43
     }
43
     }
44
 
44
 
45
+    &.shift-right {
46
+        margin-left: $sidebarWidth;
47
+        width: calc(100% - #{$sidebarWidth});
48
+    }
49
+
45
     .toolbox-background {
50
     .toolbox-background {
46
         background-image: linear-gradient(to top, rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0));
51
         background-image: linear-gradient(to top, rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0));
47
         transition: bottom .3s ease-in;
52
         transition: bottom .3s ease-in;

+ 7
- 0
css/_videolayout_default.scss 查看文件

181
         visibility: hidden;
181
         visibility: hidden;
182
         z-index: $zindex2;
182
         z-index: $zindex2;
183
     }
183
     }
184
+
185
+    &.shift-right {
186
+        &#largeVideoContainer {
187
+            margin-left: $sidebarWidth;
188
+            width: calc(100% - #{$sidebarWidth});
189
+        }
190
+    }
184
 }
191
 }
185
 
192
 
186
 #localVideoWrapper {
193
 #localVideoWrapper {

+ 13
- 1
modules/UI/videolayout/LargeVideoManager.js 查看文件

12
     JitsiParticipantConnectionStatus
12
     JitsiParticipantConnectionStatus
13
 } from '../../../react/features/base/lib-jitsi-meet';
13
 } from '../../../react/features/base/lib-jitsi-meet';
14
 import { VIDEO_TYPE } from '../../../react/features/base/media';
14
 import { VIDEO_TYPE } from '../../../react/features/base/media';
15
+import { CHAT_SIZE } from '../../../react/features/chat';
15
 import {
16
 import {
16
     updateKnownLargeVideoResolution
17
     updateKnownLargeVideoResolution
17
 } from '../../../react/features/large-video';
18
 } from '../../../react/features/large-video';
323
      * Update container size.
324
      * Update container size.
324
      */
325
      */
325
     updateContainerSize() {
326
     updateContainerSize() {
326
-        this.width = UIUtil.getAvailableVideoWidth();
327
+        let widthToUse = UIUtil.getAvailableVideoWidth();
328
+        const { isOpen } = APP.store.getState()['features/chat'];
329
+
330
+        if (isOpen) {
331
+            /**
332
+             * If chat state is open, we re-compute the container width
333
+             * by subtracting the default width of the chat.
334
+             */
335
+            widthToUse -= CHAT_SIZE;
336
+        }
337
+
338
+        this.width = widthToUse;
327
         this.height = window.innerHeight;
339
         this.height = window.innerHeight;
328
     }
340
     }
329
 
341
 

+ 8
- 6
react/features/chat/actions.js 查看文件

1
 // @flow
1
 // @flow
2
 
2
 
3
+import VideoLayout from '../../../modules/UI/videolayout/VideoLayout';
4
+
3
 import {
5
 import {
4
     ADD_MESSAGE,
6
     ADD_MESSAGE,
5
     CLEAR_MESSAGES,
7
     CLEAR_MESSAGES,
86
 }
88
 }
87
 
89
 
88
 /**
90
 /**
89
- * Toggles display of the chat side panel.
91
+ * Toggles display of the chat side panel while also taking window
92
+ * resize into account.
90
  *
93
  *
91
- * @returns {{
92
- *     type: TOGGLE_CHAT
93
- * }}
94
+ * @returns {Function}
94
  */
95
  */
95
 export function toggleChat() {
96
 export function toggleChat() {
96
-    return {
97
-        type: TOGGLE_CHAT
97
+    return function(dispatch: (Object) => Object) {
98
+        dispatch({ type: TOGGLE_CHAT });
99
+        VideoLayout.onResize();
98
     };
100
     };
99
 }
101
 }

+ 10
- 18
react/features/chat/components/web/Chat.js 查看文件

1
 // @flow
1
 // @flow
2
 
2
 
3
 import React from 'react';
3
 import React from 'react';
4
-import Transition from 'react-transition-group/Transition';
5
 
4
 
6
 import { translate } from '../../../base/i18n';
5
 import { translate } from '../../../base/i18n';
7
 import { Icon, IconClose } from '../../../base/icons';
6
 import { Icon, IconClose } from '../../../base/icons';
84
      */
83
      */
85
     render() {
84
     render() {
86
         return (
85
         return (
87
-            <Transition
88
-                in = { this.props._isOpen }
89
-                timeout = { 500 }>
90
-                { this._renderPanelContent }
91
-            </Transition>
86
+            <>
87
+                { this._renderPanelContent() }
88
+            </>
92
         );
89
         );
93
     }
90
     }
94
 
91
 
145
         );
142
         );
146
     }
143
     }
147
 
144
 
148
-    _renderPanelContent: (string) => React$Node | null;
145
+    _renderPanelContent: () => React$Node | null;
149
 
146
 
150
     /**
147
     /**
151
-     * Renders the contents of the chat panel, depending on the current
152
-     * animation state provided by {@code Transition}.
148
+     * Renders the contents of the chat panel.
153
      *
149
      *
154
-     * @param {string} state - The current display transition state of the
155
-     * {@code Chat} component, as provided by {@code Transition}.
156
      * @private
150
      * @private
157
      * @returns {ReactElement | null}
151
      * @returns {ReactElement | null}
158
      */
152
      */
159
-    _renderPanelContent(state) {
160
-        this._isExited = state === 'exited';
161
-
153
+    _renderPanelContent() {
162
         const { _isOpen, _showNamePrompt } = this.props;
154
         const { _isOpen, _showNamePrompt } = this.props;
163
-        const ComponentToRender = !_isOpen && state === 'exited'
164
-            ? null
165
-            : (
155
+        const ComponentToRender = _isOpen
156
+            ? (
166
                 <>
157
                 <>
167
                     { this._renderChatHeader() }
158
                     { this._renderChatHeader() }
168
                     { _showNamePrompt
159
                     { _showNamePrompt
169
                         ? <DisplayNameForm /> : this._renderChat() }
160
                         ? <DisplayNameForm /> : this._renderChat() }
170
                 </>
161
                 </>
171
-            );
162
+            )
163
+            : null;
172
         let className = '';
164
         let className = '';
173
 
165
 
174
         if (_isOpen) {
166
         if (_isOpen) {

+ 5
- 0
react/features/chat/constants.js 查看文件

2
 
2
 
3
 export const CHAT_VIEW_MODAL_ID = 'chatView';
3
 export const CHAT_VIEW_MODAL_ID = 'chatView';
4
 
4
 
5
+/**
6
+ * The size of the chat.
7
+ */
8
+export const CHAT_SIZE = 375;
9
+
5
 /**
10
 /**
6
  * The audio ID of the audio element for which the {@link playAudio} action is
11
  * The audio ID of the audio element for which the {@link playAudio} action is
7
  * triggered when new chat message is received.
12
  * triggered when new chat message is received.

+ 0
- 4
react/features/conference/components/web/Conference.js 查看文件

28
 } from '../AbstractConference';
28
 } from '../AbstractConference';
29
 import type { AbstractProps } from '../AbstractConference';
29
 import type { AbstractProps } from '../AbstractConference';
30
 
30
 
31
-import InviteMore from './InviteMore';
32
 import Labels from './Labels';
31
 import Labels from './Labels';
33
 import { default as Notice } from './Notice';
32
 import { default as Notice } from './Notice';
34
-import { default as Subject } from './Subject';
35
 
33
 
36
 declare var APP: Object;
34
 declare var APP: Object;
37
 declare var config: Object;
35
 declare var config: Object;
201
                 onMouseMove = { this._onShowToolbar }>
199
                 onMouseMove = { this._onShowToolbar }>
202
 
200
 
203
                 <Notice />
201
                 <Notice />
204
-                <Subject />
205
-                <InviteMore />
206
                 <div id = 'videospace'>
202
                 <div id = 'videospace'>
207
                     <LargeVideo />
203
                     <LargeVideo />
208
                     <KnockingParticipantList />
204
                     <KnockingParticipantList />

+ 2
- 0
react/features/conference/components/web/index.js 查看文件

3
 export { default as Conference } from './Conference';
3
 export { default as Conference } from './Conference';
4
 export { default as renderConferenceTimer } from './ConferenceTimerDisplay';
4
 export { default as renderConferenceTimer } from './ConferenceTimerDisplay';
5
 export { default as InsecureRoomNameLabel } from './InsecureRoomNameLabel';
5
 export { default as InsecureRoomNameLabel } from './InsecureRoomNameLabel';
6
+export { default as InviteMore } from './InviteMore';
7
+export { default as Subject } from './Subject';

+ 12
- 1
react/features/large-video/components/LargeVideo.web.js 查看文件

4
 
4
 
5
 import { Watermarks } from '../../base/react';
5
 import { Watermarks } from '../../base/react';
6
 import { connect } from '../../base/redux';
6
 import { connect } from '../../base/redux';
7
+import { InviteMore, Subject } from '../../conference';
7
 import { fetchCustomBrandingData } from '../../dynamic-branding';
8
 import { fetchCustomBrandingData } from '../../dynamic-branding';
8
 import { Captions } from '../../subtitles/';
9
 import { Captions } from '../../subtitles/';
9
 
10
 
26
      */
27
      */
27
     _fetchCustomBrandingData: Function,
28
     _fetchCustomBrandingData: Function,
28
 
29
 
30
+    /**
31
+     * Prop that indicates whether the chat is open.
32
+     */
33
+    _isChatOpen: boolean,
34
+
29
     /**
35
     /**
30
      * Used to determine the value of the autoplay attribute of the underlying
36
      * Used to determine the value of the autoplay attribute of the underlying
31
      * video element.
37
      * video element.
57
      */
63
      */
58
     render() {
64
     render() {
59
         const style = this._getCustomSyles();
65
         const style = this._getCustomSyles();
66
+        const className = `videocontainer${this.props._isChatOpen ? ' shift-right' : ''}`;
60
 
67
 
61
         return (
68
         return (
62
             <div
69
             <div
63
-                className = 'videocontainer'
70
+                className = { className }
64
                 id = 'largeVideoContainer'
71
                 id = 'largeVideoContainer'
65
                 style = { style }>
72
                 style = { style }>
73
+                <Subject />
74
+                <InviteMore />
66
                 <div id = 'sharedVideo'>
75
                 <div id = 'sharedVideo'>
67
                     <div id = 'sharedVideoIFrame' />
76
                     <div id = 'sharedVideoIFrame' />
68
                 </div>
77
                 </div>
133
 function _mapStateToProps(state) {
142
 function _mapStateToProps(state) {
134
     const testingConfig = state['features/base/config'].testing;
143
     const testingConfig = state['features/base/config'].testing;
135
     const { backgroundColor, backgroundImageUrl } = state['features/dynamic-branding'];
144
     const { backgroundColor, backgroundImageUrl } = state['features/dynamic-branding'];
145
+    const { isOpen: isChatOpen } = state['features/chat'];
136
 
146
 
137
     return {
147
     return {
138
         _customBackgroundColor: backgroundColor,
148
         _customBackgroundColor: backgroundColor,
139
         _customBackgroundImageUrl: backgroundImageUrl,
149
         _customBackgroundImageUrl: backgroundImageUrl,
150
+        _isChatOpen: isChatOpen,
140
         _noAutoPlayVideo: testingConfig?.noAutoPlayVideo
151
         _noAutoPlayVideo: testingConfig?.noAutoPlayVideo
141
     };
152
     };
142
 }
153
 }

+ 27
- 18
react/features/toolbox/components/web/Toolbox.js 查看文件

32
 import { OverflowMenuItem } from '../../../base/toolbox';
32
 import { OverflowMenuItem } from '../../../base/toolbox';
33
 import { getLocalVideoTrack, toggleScreensharing } from '../../../base/tracks';
33
 import { getLocalVideoTrack, toggleScreensharing } from '../../../base/tracks';
34
 import { VideoBlurButton } from '../../../blur';
34
 import { VideoBlurButton } from '../../../blur';
35
-import { ChatCounter, toggleChat } from '../../../chat';
35
+import { CHAT_SIZE, ChatCounter, toggleChat } from '../../../chat';
36
 import { SharedDocumentButton } from '../../../etherpad';
36
 import { SharedDocumentButton } from '../../../etherpad';
37
 import { openFeedbackDialog } from '../../../feedback';
37
 import { openFeedbackDialog } from '../../../feedback';
38
 import { beginAddPeople } from '../../../invite';
38
 import { beginAddPeople } from '../../../invite';
322
             this._onSetOverflowVisible(false);
322
             this._onSetOverflowVisible(false);
323
             this.props.dispatch(setToolbarHovered(false));
323
             this.props.dispatch(setToolbarHovered(false));
324
         }
324
         }
325
+
326
+        if (this.props._chatOpen !== prevProps._chatOpen) {
327
+            this._onResize();
328
+        }
325
     }
329
     }
326
 
330
 
327
     /**
331
     /**
344
      * @returns {ReactElement}
348
      * @returns {ReactElement}
345
      */
349
      */
346
     render() {
350
     render() {
347
-        const { _visible, _visibleButtons } = this.props;
351
+        const { _chatOpen, _visible, _visibleButtons } = this.props;
348
         const rootClassNames = `new-toolbox ${_visible ? 'visible' : ''} ${
352
         const rootClassNames = `new-toolbox ${_visible ? 'visible' : ''} ${
349
-            _visibleButtons.size ? '' : 'no-buttons'}`;
353
+            _visibleButtons.size ? '' : 'no-buttons'} ${_chatOpen ? 'shift-right' : ''}`;
350
 
354
 
351
         return (
355
         return (
352
             <div
356
             <div
534
      * @returns {void}
538
      * @returns {void}
535
      */
539
      */
536
     _onResize() {
540
     _onResize() {
537
-        const width = window.innerWidth;
541
+        let widthToUse = window.innerWidth;
542
+
543
+        // Take chat size into account when resizing toolbox.
544
+        if (this.props._chatOpen) {
545
+            widthToUse -= CHAT_SIZE;
546
+        }
538
 
547
 
539
-        if (this.state.windowWidth !== width) {
540
-            this.setState({ windowWidth: width });
548
+        if (this.state.windowWidth !== widthToUse) {
549
+            this.setState({ windowWidth: widthToUse });
541
         }
550
         }
542
     }
551
     }
543
 
552
 
1174
             / 2 // divide by the number of groups(left and right group)
1183
             / 2 // divide by the number of groups(left and right group)
1175
         );
1184
         );
1176
 
1185
 
1186
+        if (this._shouldShowButton('chat')) {
1187
+            buttonsLeft.push('chat');
1188
+        }
1177
         if (this._shouldShowButton('desktop')
1189
         if (this._shouldShowButton('desktop')
1178
                 && this._isDesktopSharingButtonVisible()) {
1190
                 && this._isDesktopSharingButtonVisible()) {
1179
             buttonsLeft.push('desktop');
1191
             buttonsLeft.push('desktop');
1181
         if (this._shouldShowButton('raisehand')) {
1193
         if (this._shouldShowButton('raisehand')) {
1182
             buttonsLeft.push('raisehand');
1194
             buttonsLeft.push('raisehand');
1183
         }
1195
         }
1184
-        if (this._shouldShowButton('chat')) {
1185
-            buttonsLeft.push('chat');
1186
-        }
1187
         if (this._shouldShowButton('closedcaptions')) {
1196
         if (this._shouldShowButton('closedcaptions')) {
1188
             buttonsLeft.push('closedcaptions');
1197
             buttonsLeft.push('closedcaptions');
1189
         }
1198
         }
1239
         return (
1248
         return (
1240
             <div className = 'toolbox-content'>
1249
             <div className = 'toolbox-content'>
1241
                 <div className = 'button-group-left'>
1250
                 <div className = 'button-group-left'>
1242
-                    { buttonsLeft.indexOf('desktop') !== -1
1243
-                        && this._renderDesktopSharingButton() }
1244
-                    { buttonsLeft.indexOf('raisehand') !== -1
1245
-                        && <ToolbarButton
1246
-                            accessibilityLabel = { t('toolbar.accessibilityLabel.raiseHand') }
1247
-                            icon = { IconRaisedHand }
1248
-                            onClick = { this._onToolbarToggleRaiseHand }
1249
-                            toggled = { _raisedHand }
1250
-                            tooltip = { t('toolbar.raiseHand') } /> }
1251
                     { buttonsLeft.indexOf('chat') !== -1
1251
                     { buttonsLeft.indexOf('chat') !== -1
1252
                         && <div className = 'toolbar-button-with-badge'>
1252
                         && <div className = 'toolbar-button-with-badge'>
1253
                             <ToolbarButton
1253
                             <ToolbarButton
1258
                                 tooltip = { t('toolbar.chat') } />
1258
                                 tooltip = { t('toolbar.chat') } />
1259
                             <ChatCounter />
1259
                             <ChatCounter />
1260
                         </div> }
1260
                         </div> }
1261
+                    { buttonsLeft.indexOf('desktop') !== -1
1262
+                        && this._renderDesktopSharingButton() }
1263
+                    { buttonsLeft.indexOf('raisehand') !== -1
1264
+                        && <ToolbarButton
1265
+                            accessibilityLabel = { t('toolbar.accessibilityLabel.raiseHand') }
1266
+                            icon = { IconRaisedHand }
1267
+                            onClick = { this._onToolbarToggleRaiseHand }
1268
+                            toggled = { _raisedHand }
1269
+                            tooltip = { t('toolbar.raiseHand') } /> }
1261
                     {
1270
                     {
1262
                         buttonsLeft.indexOf('closedcaptions') !== -1
1271
                         buttonsLeft.indexOf('closedcaptions') !== -1
1263
                             && <ClosedCaptionButton />
1272
                             && <ClosedCaptionButton />

+ 4
- 1
react/features/toolbox/functions.web.js 查看文件

1
 // @flow
1
 // @flow
2
 
2
 
3
 import { hasAvailableDevices } from '../base/devices';
3
 import { hasAvailableDevices } from '../base/devices';
4
+import { isMobileBrowser } from '../base/environment/utils';
4
 
5
 
5
 declare var interfaceConfig: Object;
6
 declare var interfaceConfig: Object;
6
 
7
 
43
         visible
44
         visible
44
     } = state['features/toolbox'];
45
     } = state['features/toolbox'];
45
     const { audioSettingsVisible, videoSettingsVisible } = state['features/settings'];
46
     const { audioSettingsVisible, videoSettingsVisible } = state['features/settings'];
47
+    const { isOpen } = state['features/chat'];
48
+    const isMobileChatOpen = isMobileBrowser() && isOpen;
46
 
49
 
47
-    return Boolean(!iAmSipGateway && (timeoutID || visible || alwaysVisible
50
+    return Boolean(!isMobileChatOpen && !iAmSipGateway && (timeoutID || visible || alwaysVisible
48
                                       || audioSettingsVisible || videoSettingsVisible));
51
                                       || audioSettingsVisible || videoSettingsVisible));
49
 }
52
 }
50
 
53
 

正在加载...
取消
保存