瀏覽代碼

feat(DominantSpeakerName): Implement

master
Mihai-Andrei Uscat 4 年之前
父節點
當前提交
7263829763

+ 7
- 3
css/_toolbars.scss 查看文件

105
     margin: 0 auto;
105
     margin: 0 auto;
106
     max-width: 100%;
106
     max-width: 100%;
107
     pointer-events: all;
107
     pointer-events: all;
108
-    background-color: #131519;
109
-    padding-bottom: env(safe-area-inset-bottom, 0);
110
-    box-shadow: 0px 2px 8px 4px rgba(0, 0, 0, 0.25), 0px 0px 0px 1px rgba(0, 0, 0, 0.15);
111
     border-radius: 6px;
108
     border-radius: 6px;
112
 }
109
 }
113
 
110
 
111
+.toolbox-content-wrapper::after {
112
+    content: '';
113
+    background: $newToolbarBackgroundColor;
114
+    padding-bottom: env(safe-area-inset-bottom, 0);
115
+}
116
+
114
 .toolbox-content-items {
117
 .toolbox-content-items {
115
     background: $newToolbarBackgroundColor;
118
     background: $newToolbarBackgroundColor;
116
     border-radius: 6px;
119
     border-radius: 6px;
118
     padding: 6px;
121
     padding: 6px;
119
     text-align: center;
122
     text-align: center;
120
     pointer-events: all;
123
     pointer-events: all;
124
+    box-shadow: 0px 2px 8px 4px rgba(0, 0, 0, 0.25), 0px 0px 0px 1px rgba(0, 0, 0, 0.15);
121
 
125
 
122
     >div {
126
     >div {
123
         margin-left: 8px;
127
         margin-left: 8px;

+ 2
- 2
css/_transcription-subtitles.scss 查看文件

16
     z-index: $subtitlesZ;
16
     z-index: $subtitlesZ;
17
 
17
 
18
     &.lifted {
18
     &.lifted {
19
-        // Lift subtitle above toolbar+invite box.
20
-        bottom: $newToolbarSize + 112px + 40px;
19
+        // Lift subtitle above toolbar+dominant speaker box.
20
+        bottom: $newToolbarSize + 36px + 40px;
21
     }
21
     }
22
 
22
 
23
     span {
23
     span {

+ 45
- 0
react/features/display-name/components/web/DisplayNameBadge.js 查看文件

1
+// @flow
2
+
3
+import { makeStyles } from '@material-ui/core/styles';
4
+import React from 'react';
5
+
6
+type Props = {
7
+
8
+    /**
9
+     * The name to be displayed within the badge.
10
+     */
11
+    name: string
12
+}
13
+
14
+const useStyles = makeStyles(theme => {
15
+    return {
16
+        badge: {
17
+            background: 'rgba(0, 0, 0, 0.6)',
18
+            borderRadius: '3px',
19
+            color: theme.palette.text01,
20
+            maxWidth: '50%',
21
+            overflow: 'hidden',
22
+            padding: '2px 16px',
23
+            textOverflow: 'ellipsis',
24
+            whiteSpace: 'nowrap'
25
+        }
26
+    };
27
+});
28
+
29
+/**
30
+ * Component that displays a name badge.
31
+ *
32
+ * @param {Props} props - The props of the component.
33
+ * @returns {ReactElement}
34
+ */
35
+const DisplayNameBadge = ({ name }: Props) => {
36
+    const classes = useStyles();
37
+
38
+    return (
39
+        <div className = { classes.badge }>
40
+            {name}
41
+        </div>
42
+    );
43
+};
44
+
45
+export default DisplayNameBadge;

+ 60
- 0
react/features/display-name/components/web/DominantSpeakerName.js 查看文件

1
+// @flow
2
+
3
+import { makeStyles } from '@material-ui/core/styles';
4
+import React from 'react';
5
+import { useSelector } from 'react-redux';
6
+
7
+import { getLocalParticipant } from '../../../base/participants';
8
+import { withPixelLineHeight } from '../../../base/styles/functions.web';
9
+import { getLargeVideoParticipant } from '../../../large-video/functions';
10
+import { isToolboxVisible } from '../../../toolbox/functions.web';
11
+import { isLayoutTileView } from '../../../video-layout';
12
+
13
+import DisplayNameBadge from './DisplayNameBadge';
14
+
15
+const useStyles = makeStyles(theme => {
16
+    return {
17
+        badgeContainer: {
18
+            ...withPixelLineHeight(theme.typography.bodyShortRegularLarge),
19
+            alignItems: 'center',
20
+            display: 'flex',
21
+            justifyContent: 'center',
22
+            marginBottom: theme.spacing(2),
23
+            transition: 'margin-bottom 0.3s'
24
+        },
25
+        containerElevated: {
26
+            marginBottom: theme.spacing(7)
27
+        }
28
+    };
29
+});
30
+
31
+/**
32
+ * Component that renders the dominant speaker's name as a badge above the toolbar in stage view.
33
+ *
34
+ * @returns {ReactElement|null}
35
+ */
36
+const DominantSpeakerName = () => {
37
+    const classes = useStyles();
38
+    const largeVideoParticipant = useSelector(getLargeVideoParticipant);
39
+    const nameToDisplay = largeVideoParticipant?.name;
40
+    const selectedId = largeVideoParticipant?.id;
41
+
42
+    const localParticipant = useSelector(getLocalParticipant);
43
+    const localId = localParticipant?.id;
44
+
45
+    const isTileView = useSelector(isLayoutTileView);
46
+    const toolboxVisible = useSelector(isToolboxVisible);
47
+
48
+    if (nameToDisplay && selectedId !== localId && !isTileView) {
49
+        return (
50
+            <div
51
+                className = { `${classes.badgeContainer}${toolboxVisible ? '' : ` ${classes.containerElevated}`}` }>
52
+                <DisplayNameBadge name = { nameToDisplay } />
53
+            </div>
54
+        );
55
+    }
56
+
57
+    return null;
58
+};
59
+
60
+export default DominantSpeakerName;

+ 1
- 0
react/features/display-name/components/web/index.js 查看文件

3
 export { default as DisplayName } from './DisplayName';
3
 export { default as DisplayName } from './DisplayName';
4
 export { default as DisplayNameLabel } from './DisplayNameLabel';
4
 export { default as DisplayNameLabel } from './DisplayNameLabel';
5
 export { default as DisplayNamePrompt } from './DisplayNamePrompt';
5
 export { default as DisplayNamePrompt } from './DisplayNamePrompt';
6
+export { default as DominantSpeakerName } from './DominantSpeakerName';

+ 15
- 0
react/features/large-video/functions.js 查看文件

1
+// @flow
2
+
3
+import { getParticipantById } from '../base/participants';
4
+
5
+/**
6
+ * Selector for the participant currently displaying on the large video.
7
+ *
8
+ * @param {Object} state - The redux state.
9
+ * @returns {Object}
10
+ */
11
+export function getLargeVideoParticipant(state: Object) {
12
+    const { participantId } = state['features/large-video'];
13
+
14
+    return getParticipantById(state, participantId);
15
+}

+ 8
- 2
react/features/subtitles/components/Captions.web.js 查看文件

2
 
2
 
3
 import React from 'react';
3
 import React from 'react';
4
 
4
 
5
-import { getParticipantCountWithFake } from '../../base/participants';
5
+import { getLocalParticipant } from '../../base/participants';
6
 import { connect } from '../../base/redux';
6
 import { connect } from '../../base/redux';
7
+import { getLargeVideoParticipant } from '../../large-video/functions';
8
+import { isLayoutTileView } from '../../video-layout';
7
 
9
 
8
 import {
10
 import {
9
     _abstractMapStateToProps,
11
     _abstractMapStateToProps,
74
  * @returns {Object}
76
  * @returns {Object}
75
  */
77
  */
76
 function mapStateToProps(state) {
78
 function mapStateToProps(state) {
79
+    const isTileView = isLayoutTileView(state);
80
+    const largeVideoParticipant = getLargeVideoParticipant(state);
81
+    const localParticipant = getLocalParticipant(state);
82
+
77
     return {
83
     return {
78
         ..._abstractMapStateToProps(state),
84
         ..._abstractMapStateToProps(state),
79
-        _isLifted: getParticipantCountWithFake(state) < 2
85
+        _isLifted: largeVideoParticipant && largeVideoParticipant?.id !== localParticipant?.id && !isTileView
80
     };
86
     };
81
 }
87
 }
82
 
88
 

+ 2
- 0
react/features/toolbox/components/web/Toolbox.js 查看文件

24
 import { getLocalVideoTrack } from '../../../base/tracks';
24
 import { getLocalVideoTrack } from '../../../base/tracks';
25
 import { toggleChat } from '../../../chat';
25
 import { toggleChat } from '../../../chat';
26
 import { ChatButton } from '../../../chat/components';
26
 import { ChatButton } from '../../../chat/components';
27
+import { DominantSpeakerName } from '../../../display-name';
27
 import { EmbedMeetingButton } from '../../../embed-meeting';
28
 import { EmbedMeetingButton } from '../../../embed-meeting';
28
 import { SharedDocumentButton } from '../../../etherpad';
29
 import { SharedDocumentButton } from '../../../etherpad';
29
 import { FeedbackButton } from '../../../feedback';
30
 import { FeedbackButton } from '../../../feedback';
1145
                     onFocus = { this._onTabIn }
1146
                     onFocus = { this._onTabIn }
1146
                     onMouseOut = { this._onMouseOut }
1147
                     onMouseOut = { this._onMouseOut }
1147
                     onMouseOver = { this._onMouseOver }>
1148
                     onMouseOver = { this._onMouseOver }>
1149
+                    <DominantSpeakerName />
1148
                     <div className = 'toolbox-content-items'>
1150
                     <div className = 'toolbox-content-items'>
1149
                         {mainMenuButtons.map(({ Content, key, ...rest }) => Content !== Separator && (
1151
                         {mainMenuButtons.map(({ Content, key, ...rest }) => Content !== Separator && (
1150
                             <Content
1152
                             <Content

+ 10
- 0
react/features/video-layout/functions.js 查看文件

208
         dispatch(pinParticipant(latestScreenShareParticipantId));
208
         dispatch(pinParticipant(latestScreenShareParticipantId));
209
     }
209
     }
210
 }
210
 }
211
+
212
+/**
213
+ * Selector for whether we are currently in tile view.
214
+ *
215
+ * @param {Object} state - The redux state.
216
+ * @returns {boolean}
217
+ */
218
+export function isLayoutTileView(state: Object) {
219
+    return getCurrentLayout(state) === LAYOUTS.TILE_VIEW;
220
+}

Loading…
取消
儲存