Browse Source

fix(toolbar): Move buttons to overflow menu when the space isn't enough

j8
Hristo Terezov 6 years ago
parent
commit
a9d82a79ea

+ 8
- 0
css/_atlaskit_overrides.scss View File

40
 .videocontainer .tOoji {
40
 .videocontainer .tOoji {
41
     background: none;
41
     background: none;
42
 }
42
 }
43
+
44
+/**
45
+ * Override @atlaskit/InlineDialog styling for the overflowmenu so it displays
46
+ * with the correct height.
47
+ */
48
+.toolbox-button-wth-dialog .eYJELv {
49
+    max-height: initial;
50
+}

+ 8
- 0
css/_toolbars.scss View File

190
                     cursor: initial;
190
                     cursor: initial;
191
                     color: #3b475c;
191
                     color: #3b475c;
192
                 }
192
                 }
193
+
194
+                i.toggled {
195
+                    background: inherit;
196
+                }
197
+
198
+                i.toggled:hover {
199
+                    background: inherit;
200
+                }
193
             }
201
             }
194
 
202
 
195
             .beta-tag {
203
             .beta-tag {

+ 2
- 1
css/modals/invite/_info.scss View File

66
     }
66
     }
67
 
67
 
68
     .info-dialog-dial-in {
68
     .info-dialog-dial-in {
69
-        white-space: nowrap;
69
+        word-break: break-all;
70
 
70
 
71
         .conference-id,
71
         .conference-id,
72
         .phone-number {
72
         .phone-number {
77
     .info-dialog-icon {
77
     .info-dialog-icon {
78
         color: #6453C0;
78
         color: #6453C0;
79
         font-size: 16px;
79
         font-size: 16px;
80
+        min-width: 30px;
80
     }
81
     }
81
 
82
 
82
     .info-dialog-url-text,
83
     .info-dialog-url-text,

+ 13
- 2
lang/main.json View File

362
         "numbers": "Dial-in Numbers",
362
         "numbers": "Dial-in Numbers",
363
         "password": "Password:",
363
         "password": "Password:",
364
         "title": "Share",
364
         "title": "Share",
365
-        "tooltip": "Share link and dial-in info for this meeting"
365
+        "tooltip": "Share link and dial-in info for this meeting",
366
+        "label": "Meeting info"
366
     },
367
     },
367
     "inviteDialog": {
368
     "inviteDialog": {
368
         "alertOk": "Ok",
369
         "alertOk": "Ok",
631
         "callQuality": "Manage call quality",
632
         "callQuality": "Manage call quality",
632
         "cameraDisabled": "Camera is not available",
633
         "cameraDisabled": "Camera is not available",
633
         "chat": "Open / Close chat",
634
         "chat": "Open / Close chat",
635
+        "closeChat": "Close chat",
634
         "documentClose": "Close shared document",
636
         "documentClose": "Close shared document",
635
         "documentOpen": "Open shared document",
637
         "documentOpen": "Open shared document",
636
         "enterFullScreen": "View full screen",
638
         "enterFullScreen": "View full screen",
639
+        "enterTileView": "Enter tile view",
637
         "etherpad": "Open / Close shared document",
640
         "etherpad": "Open / Close shared document",
638
         "exitFullScreen": "Exit full screen",
641
         "exitFullScreen": "Exit full screen",
642
+        "exitTileView": "Exit tile view",
639
         "feedback": "Leave feedback",
643
         "feedback": "Leave feedback",
640
         "filmstrip": "Show / Hide videos",
644
         "filmstrip": "Show / Hide videos",
641
         "fullscreen": "View / Exit full screen",
645
         "fullscreen": "View / Exit full screen",
644
         "lock": "Lock / Unlock room",
648
         "lock": "Lock / Unlock room",
645
         "login": "Login",
649
         "login": "Login",
646
         "logout": "Logout",
650
         "logout": "Logout",
651
+        "lowerYourHand": "Lower your hand",
647
         "micDisabled": "Microphone is not available",
652
         "micDisabled": "Microphone is not available",
648
         "micMutedPopup": "Your microphone has been muted so that you would fully enjoy your shared video.",
653
         "micMutedPopup": "Your microphone has been muted so that you would fully enjoy your shared video.",
649
         "moreActions": "More actions",
654
         "moreActions": "More actions",
650
         "mute": "Mute / Unmute",
655
         "mute": "Mute / Unmute",
656
+        "openChat": "Open chat",
651
         "pip": "Enter Picture-in-Picture mode",
657
         "pip": "Enter Picture-in-Picture mode",
652
         "profile": "Edit your profile",
658
         "profile": "Edit your profile",
653
         "raiseHand": "Raise / Lower your hand",
659
         "raiseHand": "Raise / Lower your hand",
660
+        "raiseYourHand": "Raise your hand",
654
         "Settings": "Settings",
661
         "Settings": "Settings",
655
         "sharedvideo": "Share a YouTube video",
662
         "sharedvideo": "Share a YouTube video",
656
         "sharedVideoMutedPopup": "Your shared video has been muted so that you can talk to the other members.",
663
         "sharedVideoMutedPopup": "Your shared video has been muted so that you can talk to the other members.",
658
         "shortcuts": "View shortcuts",
665
         "shortcuts": "View shortcuts",
659
         "sip": "Call SIP number",
666
         "sip": "Call SIP number",
660
         "speakerStats": "Speaker stats",
667
         "speakerStats": "Speaker stats",
668
+        "startScreenSharing": "Start screen sharing",
669
+        "startSubtitles": "Start subtitles",
670
+        "stopScreenSharing": "Stop screen sharing",
671
+        "stopSubtitles": "Stop subtitles",
661
         "stopSharedVideo": "Stop YouTube video",
672
         "stopSharedVideo": "Stop YouTube video",
662
         "talkWhileMutedPopup": "Trying to speak? You are muted.",
673
         "talkWhileMutedPopup": "Trying to speak? You are muted.",
663
         "tileViewToggle": "Toggle tile view",
674
         "tileViewToggle": "Toggle tile view",
666
         "videomute": "Start / Stop camera"
677
         "videomute": "Start / Stop camera"
667
     },
678
     },
668
     "transcribing": {
679
     "transcribing": {
669
-        "ccButtonTooltip": "Start / Stop showing subtitles",
680
+        "ccButtonTooltip": "Start / Stop subtitles",
670
         "error": "Transcribing failed. Please try again.",
681
         "error": "Transcribing failed. Please try again.",
671
         "expandedLabel": "Transcribing is currently on",
682
         "expandedLabel": "Transcribing is currently on",
672
         "failedToStart": "Transcribing failed to start",
683
         "failedToStart": "Transcribing failed to start",

+ 3
- 2
react/features/base/toolbox/components/AbstractButton.js View File

160
      * @returns {string}
160
      * @returns {string}
161
      */
161
      */
162
     _getIconName() {
162
     _getIconName() {
163
-        return (this._isToggled() ? this.toggledIconName : this.iconName)
164
-            || this.iconName;
163
+        return (
164
+            this._isToggled() ? this.toggledIconName : this.iconName
165
+        ) || this.iconName;
165
     }
166
     }
166
 
167
 
167
     /**
168
     /**

+ 0
- 0
react/features/base/toolbox/components/OverflowMenuItem.native.js View File


react/features/toolbox/components/web/OverflowMenuItem.js → react/features/base/toolbox/components/OverflowMenuItem.web.js View File


+ 1
- 0
react/features/base/toolbox/components/index.js View File

5
 export type { Props as AbstractButtonProps } from './AbstractButton';
5
 export type { Props as AbstractButtonProps } from './AbstractButton';
6
 export { default as AbstractHangupButton } from './AbstractHangupButton';
6
 export { default as AbstractHangupButton } from './AbstractHangupButton';
7
 export { default as AbstractVideoMuteButton } from './AbstractVideoMuteButton';
7
 export { default as AbstractVideoMuteButton } from './AbstractVideoMuteButton';
8
+export { default as OverflowMenuItem } from './OverflowMenuItem';

+ 39
- 2
react/features/invite/components/InfoDialogButton.web.js View File

5
 import { connect } from 'react-redux';
5
 import { connect } from 'react-redux';
6
 
6
 
7
 import { createToolbarEvent, sendAnalytics } from '../../analytics';
7
 import { createToolbarEvent, sendAnalytics } from '../../analytics';
8
+import { openDialog } from '../../base/dialog';
8
 import { translate } from '../../base/i18n';
9
 import { translate } from '../../base/i18n';
9
 import { JitsiRecordingConstants } from '../../base/lib-jitsi-meet';
10
 import { JitsiRecordingConstants } from '../../base/lib-jitsi-meet';
10
 import { getParticipantCount } from '../../base/participants';
11
 import { getParticipantCount } from '../../base/participants';
12
+import { OverflowMenuItem } from '../../base/toolbox';
11
 import { getActiveSession } from '../../recording';
13
 import { getActiveSession } from '../../recording';
12
 import { ToolbarButton } from '../../toolbox';
14
 import { ToolbarButton } from '../../toolbox';
13
-
14
 import { updateDialInNumbers } from '../actions';
15
 import { updateDialInNumbers } from '../actions';
15
 
16
 
16
 import { InfoDialog } from './info-dialog';
17
 import { InfoDialog } from './info-dialog';
59
      */
60
      */
60
     dispatch: Dispatch<*>,
61
     dispatch: Dispatch<*>,
61
 
62
 
63
+    /**
64
+     * Whether to show the label or not.
65
+     */
66
+    showLabel: boolean,
67
+
62
     /**
68
     /**
63
      * Invoked to obtain translated strings.
69
      * Invoked to obtain translated strings.
64
      */
70
      */
122
         // Bind event handlers so they are only bound once for every instance.
128
         // Bind event handlers so they are only bound once for every instance.
123
         this._onDialogClose = this._onDialogClose.bind(this);
129
         this._onDialogClose = this._onDialogClose.bind(this);
124
         this._onDialogToggle = this._onDialogToggle.bind(this);
130
         this._onDialogToggle = this._onDialogToggle.bind(this);
131
+        this._onClickOverflowMenuButton
132
+            = this._onClickOverflowMenuButton.bind(this);
125
     }
133
     }
126
 
134
 
127
     /**
135
     /**
142
      * @returns {ReactElement}
150
      * @returns {ReactElement}
143
      */
151
      */
144
     render() {
152
     render() {
145
-        const { _dialIn, _liveStreamViewURL, t } = this.props;
153
+        const { _dialIn, _liveStreamViewURL, showLabel, t } = this.props;
146
         const { showDialog } = this.state;
154
         const { showDialog } = this.state;
147
         const iconClass = `icon-info ${showDialog ? 'toggled' : ''}`;
155
         const iconClass = `icon-info ${showDialog ? 'toggled' : ''}`;
148
 
156
 
157
+        if (showLabel) {
158
+            return (
159
+                <OverflowMenuItem
160
+                    accessibilityLabel = { t('info.accessibilityLabel') }
161
+                    icon = 'icon-info'
162
+                    key = 'info-button'
163
+                    onClick = { this._onClickOverflowMenuButton }
164
+                    text = { t('info.label') } />
165
+            );
166
+        }
167
+
149
         return (
168
         return (
150
             <div className = 'toolbox-button-wth-dialog'>
169
             <div className = 'toolbox-button-wth-dialog'>
151
                 <InlineDialog
170
                 <InlineDialog
152
                     content = {
171
                     content = {
153
                         <InfoDialog
172
                         <InfoDialog
154
                             dialIn = { _dialIn }
173
                             dialIn = { _dialIn }
174
+                            isInlineDialog = { true }
155
                             liveStreamViewURL = { _liveStreamViewURL }
175
                             liveStreamViewURL = { _liveStreamViewURL }
156
                             onClose = { this._onDialogClose } /> }
176
                             onClose = { this._onDialogClose } /> }
157
                     isOpen = { showDialog }
177
                     isOpen = { showDialog }
179
         this.setState({ showDialog: false });
199
         this.setState({ showDialog: false });
180
     }
200
     }
181
 
201
 
202
+    _onClickOverflowMenuButton: () => void;
203
+
204
+    /**
205
+     * Opens the Info dialog.
206
+     *
207
+     * @returns {void}
208
+     */
209
+    _onClickOverflowMenuButton() {
210
+        const { _dialIn, _liveStreamViewURL } = this.props;
211
+
212
+        this.props.dispatch(openDialog(InfoDialog, {
213
+            dialIn: _dialIn,
214
+            liveStreamViewURL: _liveStreamViewURL,
215
+            isInlineDialog: false
216
+        }));
217
+    }
218
+
182
     _onDialogToggle: () => void;
219
     _onDialogToggle: () => void;
183
 
220
 
184
     /**
221
     /**

+ 28
- 3
react/features/invite/components/info-dialog/InfoDialog.web.js View File

5
 
5
 
6
 import { setPassword } from '../../../base/conference';
6
 import { setPassword } from '../../../base/conference';
7
 import { getInviteURL } from '../../../base/connection';
7
 import { getInviteURL } from '../../../base/connection';
8
+import { Dialog } from '../../../base/dialog';
8
 import { translate } from '../../../base/i18n';
9
 import { translate } from '../../../base/i18n';
9
 import { isLocalParticipantModerator } from '../../../base/participants';
10
 import { isLocalParticipantModerator } from '../../../base/participants';
10
 
11
 
66
      */
67
      */
67
     dispatch: Dispatch<*>,
68
     dispatch: Dispatch<*>,
68
 
69
 
70
+    /**
71
+     * Whether is Atlaskit InlineDialog or a normal dialog.
72
+     */
73
+    isInlineDialog: boolean,
74
+
69
     /**
75
     /**
70
      * The current known URL for a live stream in progress.
76
      * The current known URL for a live stream in progress.
71
      */
77
      */
187
      * @returns {ReactElement}
193
      * @returns {ReactElement}
188
      */
194
      */
189
     render() {
195
     render() {
190
-        const { liveStreamViewURL, onMouseOver, t } = this.props;
191
-
192
-        return (
196
+        const {
197
+            isInlineDialog,
198
+            liveStreamViewURL,
199
+            onMouseOver,
200
+            t
201
+        } = this.props;
202
+
203
+        const inlineDialog = (
193
             <div
204
             <div
194
                 className = 'info-dialog'
205
                 className = 'info-dialog'
195
                 onMouseOver = { onMouseOver } >
206
                 onMouseOver = { onMouseOver } >
246
                     value = { this._getTextToCopy() } />
257
                     value = { this._getTextToCopy() } />
247
             </div>
258
             </div>
248
         );
259
         );
260
+
261
+        if (isInlineDialog) {
262
+            return inlineDialog;
263
+        }
264
+
265
+        return (
266
+            <Dialog
267
+                cancelTitleKey = 'dialog.close'
268
+                submitDisabled = { true }
269
+                titleKey = 'info.label'
270
+                width = 'small'>
271
+                { inlineDialog }
272
+            </Dialog>
273
+        );
249
     }
274
     }
250
 
275
 
251
     /**
276
     /**

+ 19
- 0
react/features/invite/components/info-dialog/PasswordForm.web.js View File

83
         this._onEnteredPasswordChange
83
         this._onEnteredPasswordChange
84
             = this._onEnteredPasswordChange.bind(this);
84
             = this._onEnteredPasswordChange.bind(this);
85
         this._onPasswordSubmit = this._onPasswordSubmit.bind(this);
85
         this._onPasswordSubmit = this._onPasswordSubmit.bind(this);
86
+        this._onKeyDown = this._onKeyDown.bind(this);
86
     }
87
     }
87
 
88
 
88
     /**
89
     /**
119
             return (
120
             return (
120
                 <form
121
                 <form
121
                     className = 'info-password-form'
122
                     className = 'info-password-form'
123
+                    onKeyDown = { this._onKeyDown }
122
                     onSubmit = { this._onPasswordSubmit }>
124
                     onSubmit = { this._onPasswordSubmit }>
123
                     <input
125
                     <input
124
                         autoFocus = { true }
126
                         autoFocus = { true }
175
      */
177
      */
176
     _onPasswordSubmit(event) {
178
     _onPasswordSubmit(event) {
177
         event.preventDefault();
179
         event.preventDefault();
180
+        event.stopPropagation();
178
 
181
 
179
         this.props.onSubmit(this.state.enteredPassword);
182
         this.props.onSubmit(this.state.enteredPassword);
180
     }
183
     }
184
+
185
+    _onKeyDown: (Object) => void;
186
+
187
+    /**
188
+     * Stops the the EnterKey for propagation in order to prevent the dialog
189
+     * to close.
190
+     *
191
+     * @param {Object} event - The key event.
192
+     * @private
193
+     * @returns {void}
194
+     */
195
+    _onKeyDown(event) {
196
+        if (event.key === 'Enter') {
197
+            event.stopPropagation();
198
+        }
199
+    }
181
 }
200
 }
182
 
201
 
183
 export default translate(PasswordForm);
202
 export default translate(PasswordForm);

+ 2
- 0
react/features/subtitles/components/ClosedCaptionButton.web.js View File

19
     iconName = 'icon-closed_caption';
19
     iconName = 'icon-closed_caption';
20
     toggledIconName = 'icon-closed_caption toggled';
20
     toggledIconName = 'icon-closed_caption toggled';
21
     tooltip = 'transcribing.ccButtonTooltip';
21
     tooltip = 'transcribing.ccButtonTooltip';
22
+    label = 'toolbar.startSubtitles';
23
+    toggledLabel = 'toolbar.stopSubtitles';
22
 }
24
 }
23
 
25
 
24
 export default translate(connect(_abstractMapStateToProps)(
26
 export default translate(connect(_abstractMapStateToProps)(

+ 254
- 20
react/features/toolbox/components/web/Toolbox.js View File

16
     getParticipants,
16
     getParticipants,
17
     participantUpdated
17
     participantUpdated
18
 } from '../../../base/participants';
18
 } from '../../../base/participants';
19
+import { OverflowMenuItem } from '../../../base/toolbox';
19
 import { getLocalVideoTrack, toggleScreensharing } from '../../../base/tracks';
20
 import { getLocalVideoTrack, toggleScreensharing } from '../../../base/tracks';
20
 import { ChatCounter, toggleChat } from '../../../chat';
21
 import { ChatCounter, toggleChat } from '../../../chat';
21
 import { toggleDocument } from '../../../etherpad';
22
 import { toggleDocument } from '../../../etherpad';
56
 import AudioMuteButton from '../AudioMuteButton';
57
 import AudioMuteButton from '../AudioMuteButton';
57
 import HangupButton from '../HangupButton';
58
 import HangupButton from '../HangupButton';
58
 import OverflowMenuButton from './OverflowMenuButton';
59
 import OverflowMenuButton from './OverflowMenuButton';
59
-import OverflowMenuItem from './OverflowMenuItem';
60
 import OverflowMenuProfileItem from './OverflowMenuProfileItem';
60
 import OverflowMenuProfileItem from './OverflowMenuProfileItem';
61
 import ToolbarButton from './ToolbarButton';
61
 import ToolbarButton from './ToolbarButton';
62
 import VideoMuteButton from '../VideoMuteButton';
62
 import VideoMuteButton from '../VideoMuteButton';
177
     t: Function
177
     t: Function
178
 };
178
 };
179
 
179
 
180
+/**
181
+ * The type of the React {@code Component} state of {@link Toolbox}.
182
+ */
183
+type State = {
184
+
185
+    /**
186
+     * The width of the browser's window.
187
+     */
188
+    windowWidth: number
189
+};
190
+
180
 declare var APP: Object;
191
 declare var APP: Object;
181
 declare var interfaceConfig: Object;
192
 declare var interfaceConfig: Object;
182
 
193
 
185
  *
196
  *
186
  * @extends Component
197
  * @extends Component
187
  */
198
  */
188
-class Toolbox extends Component<Props> {
199
+class Toolbox extends Component<Props, State> {
189
     /**
200
     /**
190
      * Initializes a new {@code Toolbox} instance.
201
      * Initializes a new {@code Toolbox} instance.
191
      *
202
      *
198
         // Bind event handlers so they are only bound once per instance.
209
         // Bind event handlers so they are only bound once per instance.
199
         this._onMouseOut = this._onMouseOut.bind(this);
210
         this._onMouseOut = this._onMouseOut.bind(this);
200
         this._onMouseOver = this._onMouseOver.bind(this);
211
         this._onMouseOver = this._onMouseOver.bind(this);
212
+        this._onResize = this._onResize.bind(this);
201
         this._onSetOverflowVisible = this._onSetOverflowVisible.bind(this);
213
         this._onSetOverflowVisible = this._onSetOverflowVisible.bind(this);
202
 
214
 
203
         this._onShortcutToggleChat = this._onShortcutToggleChat.bind(this);
215
         this._onShortcutToggleChat = this._onShortcutToggleChat.bind(this);
232
             = this._onToolbarToggleSharedVideo.bind(this);
244
             = this._onToolbarToggleSharedVideo.bind(this);
233
         this._onToolbarOpenLocalRecordingInfoDialog
245
         this._onToolbarOpenLocalRecordingInfoDialog
234
             = this._onToolbarOpenLocalRecordingInfoDialog.bind(this);
246
             = this._onToolbarOpenLocalRecordingInfoDialog.bind(this);
247
+
248
+        this.state = {
249
+            windowWidth: window.innerWidth
250
+        };
235
     }
251
     }
236
 
252
 
237
     /**
253
     /**
273
                     shortcut.helpDescription);
289
                     shortcut.helpDescription);
274
             }
290
             }
275
         });
291
         });
292
+
293
+        window.addEventListener('resize', this._onResize);
276
     }
294
     }
277
 
295
 
278
     /**
296
     /**
303
     componentWillUnmount() {
321
     componentWillUnmount() {
304
         [ 'C', 'D', 'R', 'S' ].forEach(letter =>
322
         [ 'C', 'D', 'R', 'S' ].forEach(letter =>
305
             APP.keyboardshortcut.unregisterShortcut(letter));
323
             APP.keyboardshortcut.unregisterShortcut(letter));
324
+
325
+        window.removeEventListener('resize', this._onResize);
306
     }
326
     }
307
 
327
 
308
     /**
328
     /**
482
         this.props.dispatch(setToolbarHovered(true));
502
         this.props.dispatch(setToolbarHovered(true));
483
     }
503
     }
484
 
504
 
505
+    _onResize: () => void;
506
+
507
+    /**
508
+     * A window resize handler used to calculate the number of buttons we can
509
+     * fit in the toolbar.
510
+     *
511
+     * @private
512
+     * @returns {void}
513
+     */
514
+    _onResize() {
515
+        const width = window.innerWidth;
516
+
517
+        if (this.state.windowWidth !== width) {
518
+            this.setState({ windowWidth: width });
519
+        }
520
+    }
521
+
522
+
485
     _onSetOverflowVisible: (boolean) => void;
523
     _onSetOverflowVisible: (boolean) => void;
486
 
524
 
487
     /**
525
     /**
788
         this.props.dispatch(openDialog(LocalRecordingInfoDialog));
826
         this.props.dispatch(openDialog(LocalRecordingInfoDialog));
789
     }
827
     }
790
 
828
 
829
+    /**
830
+     * Returns true if the the desktop sharing button should be visible and
831
+     * false otherwise.
832
+     *
833
+     * @returns {boolean}
834
+     */
835
+    _isDesktopSharingButtonVisible() {
836
+        const {
837
+            _desktopSharingEnabled,
838
+            _desktopSharingDisabledTooltipKey
839
+        } = this.props;
840
+
841
+        return _desktopSharingEnabled || _desktopSharingDisabledTooltipKey;
842
+    }
843
+
791
     /**
844
     /**
792
      * Renders a button for toggleing screen sharing.
845
      * Renders a button for toggleing screen sharing.
793
      *
846
      *
794
      * @private
847
      * @private
848
+     * @param {boolean} isInOverflowMenu - True if the button is moved to the
849
+     * overflow menu.
795
      * @returns {ReactElement|null}
850
      * @returns {ReactElement|null}
796
      */
851
      */
797
-    _renderDesktopSharingButton() {
852
+    _renderDesktopSharingButton(isInOverflowMenu = false) {
798
         const {
853
         const {
799
             _desktopSharingEnabled,
854
             _desktopSharingEnabled,
800
             _desktopSharingDisabledTooltipKey,
855
             _desktopSharingDisabledTooltipKey,
802
             t
857
             t
803
         } = this.props;
858
         } = this.props;
804
 
859
 
805
-        const visible
806
-            = _desktopSharingEnabled || _desktopSharingDisabledTooltipKey;
807
-
808
-        if (!visible) {
860
+        if (!this._isDesktopSharingButtonVisible()) {
809
             return null;
861
             return null;
810
         }
862
         }
811
 
863
 
864
+        if (isInOverflowMenu) {
865
+            return (
866
+                <OverflowMenuItem
867
+                    accessibilityLabel
868
+                        = { t('toolbar.accessibilityLabel.shareYourScreen') }
869
+                    disabled = { _desktopSharingEnabled }
870
+                    icon = { 'icon-share-desktop' }
871
+                    key = 'desktop'
872
+                    onClick = { this._onToolbarToggleScreenshare }
873
+                    text = {
874
+                        t(`toolbar.${
875
+                            _screensharing
876
+                                ? 'stopScreenSharing' : 'startScreenSharing'}`
877
+                        )
878
+                    } />
879
+            );
880
+        }
881
+
812
         const classNames = `icon-share-desktop ${
882
         const classNames = `icon-share-desktop ${
813
             _screensharing ? 'toggled' : ''} ${
883
             _screensharing ? 'toggled' : ''} ${
814
             _desktopSharingEnabled ? '' : 'disabled'}`;
884
             _desktopSharingEnabled ? '' : 'disabled'}`;
826
         );
896
         );
827
     }
897
     }
828
 
898
 
899
+    /**
900
+     * Returns true if the profile button is visible and false otherwise.
901
+     *
902
+     * @returns {boolean}
903
+     */
904
+    _isProfileVisible() {
905
+        return this.props._isGuest && this._shouldShowButton('profile');
906
+    }
907
+
829
     /**
908
     /**
830
      * Renders the list elements of the overflow menu.
909
      * Renders the list elements of the overflow menu.
831
      *
910
      *
838
             _etherpadInitialized,
917
             _etherpadInitialized,
839
             _feedbackConfigured,
918
             _feedbackConfigured,
840
             _fullScreen,
919
             _fullScreen,
841
-            _isGuest,
842
             _sharingVideo,
920
             _sharingVideo,
843
             t
921
             t
844
         } = this.props;
922
         } = this.props;
845
 
923
 
846
         return [
924
         return [
847
-            _isGuest
848
-                && this._shouldShowButton('profile')
925
+            this._isProfileVisible()
849
                 && <OverflowMenuProfileItem
926
                 && <OverflowMenuProfileItem
850
                     key = 'profile'
927
                     key = 'profile'
851
                     onClick = { this._onToolbarToggleProfile } />,
928
                     onClick = { this._onToolbarToggleProfile } />,
924
         ];
1001
         ];
925
     }
1002
     }
926
 
1003
 
1004
+    /**
1005
+     * Renders a list of buttons that are moved to the overflow menu.
1006
+     *
1007
+     * @private
1008
+     * @param {Array<string>} movedButtons - The names of the buttons to be
1009
+     * moved.
1010
+     * @returns {Array<ReactElement>}
1011
+     */
1012
+    _renderMovedButtons(movedButtons) {
1013
+        const {
1014
+            _chatOpen,
1015
+            _raisedHand,
1016
+            t
1017
+        } = this.props;
1018
+
1019
+        return movedButtons.map(buttonName => {
1020
+            switch (buttonName) {
1021
+            case 'desktop':
1022
+                return this._renderDesktopSharingButton(true);
1023
+            case 'raisehand':
1024
+                return (
1025
+                    <OverflowMenuItem
1026
+                        accessibilityLabel =
1027
+                            { t('toolbar.accessibilityLabel.raiseHand') }
1028
+                        icon = { 'icon-raised-hand' }
1029
+                        key = 'raisedHand'
1030
+                        onClick = { this._onToolbarToggleRaiseHand }
1031
+                        text = {
1032
+                            t(`toolbar.${
1033
+                                _raisedHand
1034
+                                    ? 'lowerYourHand' : 'raiseYourHand'}`
1035
+                            )
1036
+                        } />
1037
+                );
1038
+            case 'chat':
1039
+                return (
1040
+                    <OverflowMenuItem
1041
+                        accessibilityLabel =
1042
+                            { t('toolbar.accessibilityLabel.chat') }
1043
+                        icon = { 'icon-chat' }
1044
+                        key = 'chat'
1045
+                        onClick = { this._onToolbarToggleChat }
1046
+                        text = {
1047
+                            t(`toolbar.${
1048
+                                _chatOpen ? 'closeChat' : 'openChat'}`
1049
+                            )
1050
+                        } />
1051
+                );
1052
+            case 'closedcaptions':
1053
+                return <ClosedCaptionButton showLabel = { true } />;
1054
+            case 'info':
1055
+                return <InfoDialogButton showLabel = { true } />;
1056
+            case 'invite':
1057
+                return (
1058
+                    <OverflowMenuItem
1059
+                        accessibilityLabel =
1060
+                            { t('toolbar.accessibilityLabel.invite') }
1061
+                        icon = 'icon-invite'
1062
+                        key = 'invite'
1063
+                        onClick = { this._onToolbarOpenInvite }
1064
+                        text = { t('toolbar.invite') } />
1065
+                );
1066
+            case 'tileview':
1067
+                return <TileViewButton showLabel = { true } />;
1068
+            case 'localrecording':
1069
+                return (
1070
+                    <OverflowMenuItem
1071
+                        accessibilityLabel
1072
+                            = { t('toolbar.accessibilityLabel.localRecording') }
1073
+                        icon = { 'icon-thumb-menu icon-rec' }
1074
+                        key = 'localrecording'
1075
+                        onClick = {
1076
+                            this._onToolbarOpenLocalRecordingInfoDialog
1077
+                        }
1078
+                        text = { t('localRecording.dialogTitle') } />
1079
+                );
1080
+            default:
1081
+                return null;
1082
+            }
1083
+        });
1084
+    }
1085
+
927
     /**
1086
     /**
928
      * Renders the toolbox content.
1087
      * Renders the toolbox content.
929
      *
1088
      *
941
         const overflowHasItems = Boolean(overflowMenuContent.filter(
1100
         const overflowHasItems = Boolean(overflowMenuContent.filter(
942
             child => child).length);
1101
             child => child).length);
943
         const toolbarAccLabel = 'toolbar.accessibilityLabel.moreActionsMenu';
1102
         const toolbarAccLabel = 'toolbar.accessibilityLabel.moreActionsMenu';
1103
+        const buttonsLeft = [];
1104
+        const buttonsRight = [];
1105
+
1106
+        const maxNumberOfButtonsPerGroup = Math.floor(
1107
+            (
1108
+                this.state.windowWidth
1109
+                    - 168 // the width of the central group by design
1110
+                    - 48 // the minimum space between the button groups
1111
+            )
1112
+            / 56 // the width + padding of a button
1113
+            / 2 // divide by the number of groups(left and right group)
1114
+        );
1115
+
1116
+        if (this._shouldShowButton('desktop')
1117
+                && this._isDesktopSharingButtonVisible()) {
1118
+            buttonsLeft.push('desktop');
1119
+        }
1120
+        if (this._shouldShowButton('raisehand')) {
1121
+            buttonsLeft.push('raisehand');
1122
+        }
1123
+        if (this._shouldShowButton('chat')) {
1124
+            buttonsLeft.push('chat');
1125
+        }
1126
+        if (this._shouldShowButton('closedcaptions')) {
1127
+            buttonsLeft.push('closedcaptions');
1128
+        }
1129
+        if (overflowHasItems) {
1130
+            buttonsRight.push('overflowmenu');
1131
+        }
1132
+        if (this._shouldShowButton('info')) {
1133
+            buttonsRight.push('info');
1134
+        }
1135
+        if (this._shouldShowButton('invite') && !_hideInviteButton) {
1136
+            buttonsRight.push('invite');
1137
+        }
1138
+        if (this._shouldShowButton('tileview')) {
1139
+            buttonsRight.push('tileview');
1140
+        }
1141
+        if (this._shouldShowButton('localrecording')) {
1142
+            buttonsRight.push('localrecording');
1143
+        }
1144
+
1145
+        const movedButtons = [];
1146
+
1147
+        if (buttonsLeft.length > maxNumberOfButtonsPerGroup) {
1148
+            movedButtons.push(...buttonsLeft.splice(
1149
+                maxNumberOfButtonsPerGroup,
1150
+                buttonsLeft.length - maxNumberOfButtonsPerGroup));
1151
+            if (buttonsRight.indexOf('overflowmenu') === -1) {
1152
+                buttonsRight.unshift('overflowmenu');
1153
+            }
1154
+        }
1155
+
1156
+        if (buttonsRight.length > maxNumberOfButtonsPerGroup) {
1157
+            if (buttonsRight.indexOf('overflowmenu') === -1) {
1158
+                buttonsRight.unshift('overflowmenu');
1159
+            }
1160
+
1161
+            let numberOfButtons = maxNumberOfButtonsPerGroup;
1162
+
1163
+            // make sure the more button will be displayed when we move buttons.
1164
+            if (numberOfButtons === 0) {
1165
+                numberOfButtons++;
1166
+            }
1167
+
1168
+            movedButtons.push(...buttonsRight.splice(
1169
+                numberOfButtons,
1170
+                buttonsRight.length - numberOfButtons));
1171
+
1172
+        }
1173
+
1174
+        overflowMenuContent.splice(
1175
+            1, 0, ...this._renderMovedButtons(movedButtons));
944
 
1176
 
945
         return (
1177
         return (
946
             <div className = 'toolbox-content'>
1178
             <div className = 'toolbox-content'>
947
                 <div className = 'button-group-left'>
1179
                 <div className = 'button-group-left'>
948
-                    { this._shouldShowButton('desktop')
1180
+                    { buttonsLeft.indexOf('desktop') !== -1
949
                         && this._renderDesktopSharingButton() }
1181
                         && this._renderDesktopSharingButton() }
950
-                    { this._shouldShowButton('raisehand')
1182
+                    { buttonsLeft.indexOf('raisehand') !== -1
951
                         && <ToolbarButton
1183
                         && <ToolbarButton
952
                             accessibilityLabel =
1184
                             accessibilityLabel =
953
                                 {
1185
                                 {
958
                                 : 'icon-raised-hand' }
1190
                                 : 'icon-raised-hand' }
959
                             onClick = { this._onToolbarToggleRaiseHand }
1191
                             onClick = { this._onToolbarToggleRaiseHand }
960
                             tooltip = { t('toolbar.raiseHand') } /> }
1192
                             tooltip = { t('toolbar.raiseHand') } /> }
961
-                    { this._shouldShowButton('chat')
1193
+                    { buttonsLeft.indexOf('chat') !== -1
962
                         && <div className = 'toolbar-button-with-badge'>
1194
                         && <div className = 'toolbar-button-with-badge'>
963
                             <ToolbarButton
1195
                             <ToolbarButton
964
                                 accessibilityLabel =
1196
                                 accessibilityLabel =
971
                             <ChatCounter />
1203
                             <ChatCounter />
972
                         </div> }
1204
                         </div> }
973
                     {
1205
                     {
974
-                        this._shouldShowButton('closedcaptions')
1206
+                        buttonsLeft.indexOf('closedcaptions') !== -1
975
                             && <ClosedCaptionButton />
1207
                             && <ClosedCaptionButton />
976
                     }
1208
                     }
977
                 </div>
1209
                 </div>
984
                         visible = { this._shouldShowButton('camera') } />
1216
                         visible = { this._shouldShowButton('camera') } />
985
                 </div>
1217
                 </div>
986
                 <div className = 'button-group-right'>
1218
                 <div className = 'button-group-right'>
987
-                    { this._shouldShowButton('localrecording')
1219
+                    { buttonsRight.indexOf('localrecording') !== -1
988
                         && <LocalRecordingButton
1220
                         && <LocalRecordingButton
989
                             onClick = {
1221
                             onClick = {
990
                                 this._onToolbarOpenLocalRecordingInfoDialog
1222
                                 this._onToolbarOpenLocalRecordingInfoDialog
991
                             } />
1223
                             } />
992
                     }
1224
                     }
993
-                    { this._shouldShowButton('tileview')
1225
+                    { buttonsRight.indexOf('tileview') !== -1
994
                         && <TileViewButton /> }
1226
                         && <TileViewButton /> }
995
-                    { this._shouldShowButton('invite')
996
-                        && !_hideInviteButton
1227
+                    { buttonsRight.indexOf('invite') !== -1
997
                         && <ToolbarButton
1228
                         && <ToolbarButton
998
                             accessibilityLabel =
1229
                             accessibilityLabel =
999
                                 { t('toolbar.accessibilityLabel.invite') }
1230
                                 { t('toolbar.accessibilityLabel.invite') }
1000
                             iconName = 'icon-invite'
1231
                             iconName = 'icon-invite'
1001
                             onClick = { this._onToolbarOpenInvite }
1232
                             onClick = { this._onToolbarOpenInvite }
1002
                             tooltip = { t('toolbar.invite') } /> }
1233
                             tooltip = { t('toolbar.invite') } /> }
1003
-                    { this._shouldShowButton('info') && <InfoDialogButton /> }
1004
-                    { overflowHasItems
1234
+                    {
1235
+                        buttonsRight.indexOf('info') !== -1
1236
+                            && <InfoDialogButton />
1237
+                    }
1238
+                    { buttonsRight.indexOf('overflowmenu') !== -1
1005
                         && <OverflowMenuButton
1239
                         && <OverflowMenuButton
1006
                             isOpen = { _overflowMenuVisible }
1240
                             isOpen = { _overflowMenuVisible }
1007
                             onVisibilityChange = { this._onSetOverflowVisible }>
1241
                             onVisibilityChange = { this._onSetOverflowVisible }>

+ 2
- 1
react/features/video-layout/components/TileViewButton.js View File

38
 class TileViewButton<P: Props> extends AbstractButton<P, *> {
38
 class TileViewButton<P: Props> extends AbstractButton<P, *> {
39
     accessibilityLabel = 'toolbar.accessibilityLabel.tileView';
39
     accessibilityLabel = 'toolbar.accessibilityLabel.tileView';
40
     iconName = 'icon-tiles-many';
40
     iconName = 'icon-tiles-many';
41
-    label = 'toolbar.tileViewToggle';
41
+    label = 'toolbar.enterTileView';
42
+    toggledLabel = 'toolbar.exitTileView';
42
     toggledIconName = 'icon-tiles-many toggled';
43
     toggledIconName = 'icon-tiles-many toggled';
43
     tooltip = 'toolbar.tileViewToggle';
44
     tooltip = 'toolbar.tileViewToggle';
44
 
45
 

Loading…
Cancel
Save