Просмотр исходного кода

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

master
Mihai Uscat 5 лет назад
Родитель
Сommit
5f5468995f

+ 1
- 6
css/_chat.scss Просмотреть файл

@@ -4,16 +4,11 @@
4 4
     color: #FFF;
5 5
     display: flex;
6 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 8
     left: -$sidebarWidth;
13 9
     overflow: hidden;
14 10
     position: absolute;
15 11
     top: 0;
16
-    transition: left 0.5s;
17 12
     width: $sidebarWidth;
18 13
     z-index: $sideToolbarContainerZ;
19 14
 

+ 5
- 0
css/_toolbars.scss Просмотреть файл

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

+ 7
- 0
css/_videolayout_default.scss Просмотреть файл

@@ -181,6 +181,13 @@
181 181
         visibility: hidden;
182 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 193
 #localVideoWrapper {

+ 13
- 1
modules/UI/videolayout/LargeVideoManager.js Просмотреть файл

@@ -12,6 +12,7 @@ import {
12 12
     JitsiParticipantConnectionStatus
13 13
 } from '../../../react/features/base/lib-jitsi-meet';
14 14
 import { VIDEO_TYPE } from '../../../react/features/base/media';
15
+import { CHAT_SIZE } from '../../../react/features/chat';
15 16
 import {
16 17
     updateKnownLargeVideoResolution
17 18
 } from '../../../react/features/large-video';
@@ -323,7 +324,18 @@ export default class LargeVideoManager {
323 324
      * Update container size.
324 325
      */
325 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 339
         this.height = window.innerHeight;
328 340
     }
329 341
 

+ 8
- 6
react/features/chat/actions.js Просмотреть файл

@@ -1,5 +1,7 @@
1 1
 // @flow
2 2
 
3
+import VideoLayout from '../../../modules/UI/videolayout/VideoLayout';
4
+
3 5
 import {
4 6
     ADD_MESSAGE,
5 7
     CLEAR_MESSAGES,
@@ -86,14 +88,14 @@ export function setPrivateMessageRecipient(participant: Object) {
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 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,7 +1,6 @@
1 1
 // @flow
2 2
 
3 3
 import React from 'react';
4
-import Transition from 'react-transition-group/Transition';
5 4
 
6 5
 import { translate } from '../../../base/i18n';
7 6
 import { Icon, IconClose } from '../../../base/icons';
@@ -84,11 +83,9 @@ class Chat extends AbstractChat<Props> {
84 83
      */
85 84
     render() {
86 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,30 +142,25 @@ class Chat extends AbstractChat<Props> {
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 150
      * @private
157 151
      * @returns {ReactElement | null}
158 152
      */
159
-    _renderPanelContent(state) {
160
-        this._isExited = state === 'exited';
161
-
153
+    _renderPanelContent() {
162 154
         const { _isOpen, _showNamePrompt } = this.props;
163
-        const ComponentToRender = !_isOpen && state === 'exited'
164
-            ? null
165
-            : (
155
+        const ComponentToRender = _isOpen
156
+            ? (
166 157
                 <>
167 158
                     { this._renderChatHeader() }
168 159
                     { _showNamePrompt
169 160
                         ? <DisplayNameForm /> : this._renderChat() }
170 161
                 </>
171
-            );
162
+            )
163
+            : null;
172 164
         let className = '';
173 165
 
174 166
         if (_isOpen) {

+ 5
- 0
react/features/chat/constants.js Просмотреть файл

@@ -2,6 +2,11 @@
2 2
 
3 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 11
  * The audio ID of the audio element for which the {@link playAudio} action is
7 12
  * triggered when new chat message is received.

+ 0
- 4
react/features/conference/components/web/Conference.js Просмотреть файл

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

+ 2
- 0
react/features/conference/components/web/index.js Просмотреть файл

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

+ 27
- 18
react/features/toolbox/components/web/Toolbox.js Просмотреть файл

@@ -32,7 +32,7 @@ import { connect, equals } from '../../../base/redux';
32 32
 import { OverflowMenuItem } from '../../../base/toolbox';
33 33
 import { getLocalVideoTrack, toggleScreensharing } from '../../../base/tracks';
34 34
 import { VideoBlurButton } from '../../../blur';
35
-import { ChatCounter, toggleChat } from '../../../chat';
35
+import { CHAT_SIZE, ChatCounter, toggleChat } from '../../../chat';
36 36
 import { SharedDocumentButton } from '../../../etherpad';
37 37
 import { openFeedbackDialog } from '../../../feedback';
38 38
 import { beginAddPeople } from '../../../invite';
@@ -322,6 +322,10 @@ class Toolbox extends Component<Props, State> {
322 322
             this._onSetOverflowVisible(false);
323 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,9 +348,9 @@ class Toolbox extends Component<Props, State> {
344 348
      * @returns {ReactElement}
345 349
      */
346 350
     render() {
347
-        const { _visible, _visibleButtons } = this.props;
351
+        const { _chatOpen, _visible, _visibleButtons } = this.props;
348 352
         const rootClassNames = `new-toolbox ${_visible ? 'visible' : ''} ${
349
-            _visibleButtons.size ? '' : 'no-buttons'}`;
353
+            _visibleButtons.size ? '' : 'no-buttons'} ${_chatOpen ? 'shift-right' : ''}`;
350 354
 
351 355
         return (
352 356
             <div
@@ -534,10 +538,15 @@ class Toolbox extends Component<Props, State> {
534 538
      * @returns {void}
535 539
      */
536 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,6 +1183,9 @@ class Toolbox extends Component<Props, State> {
1174 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 1189
         if (this._shouldShowButton('desktop')
1178 1190
                 && this._isDesktopSharingButtonVisible()) {
1179 1191
             buttonsLeft.push('desktop');
@@ -1181,9 +1193,6 @@ class Toolbox extends Component<Props, State> {
1181 1193
         if (this._shouldShowButton('raisehand')) {
1182 1194
             buttonsLeft.push('raisehand');
1183 1195
         }
1184
-        if (this._shouldShowButton('chat')) {
1185
-            buttonsLeft.push('chat');
1186
-        }
1187 1196
         if (this._shouldShowButton('closedcaptions')) {
1188 1197
             buttonsLeft.push('closedcaptions');
1189 1198
         }
@@ -1239,15 +1248,6 @@ class Toolbox extends Component<Props, State> {
1239 1248
         return (
1240 1249
             <div className = 'toolbox-content'>
1241 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 1251
                     { buttonsLeft.indexOf('chat') !== -1
1252 1252
                         && <div className = 'toolbar-button-with-badge'>
1253 1253
                             <ToolbarButton
@@ -1258,6 +1258,15 @@ class Toolbox extends Component<Props, State> {
1258 1258
                                 tooltip = { t('toolbar.chat') } />
1259 1259
                             <ChatCounter />
1260 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 1271
                         buttonsLeft.indexOf('closedcaptions') !== -1
1263 1272
                             && <ClosedCaptionButton />

+ 4
- 1
react/features/toolbox/functions.web.js Просмотреть файл

@@ -1,6 +1,7 @@
1 1
 // @flow
2 2
 
3 3
 import { hasAvailableDevices } from '../base/devices';
4
+import { isMobileBrowser } from '../base/environment/utils';
4 5
 
5 6
 declare var interfaceConfig: Object;
6 7
 
@@ -43,8 +44,10 @@ export function isToolboxVisible(state: Object) {
43 44
         visible
44 45
     } = state['features/toolbox'];
45 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 51
                                       || audioSettingsVisible || videoSettingsVisible));
49 52
 }
50 53
 

Загрузка…
Отмена
Сохранить