浏览代码

feat(participants-pane) context menu ui fixes

- Fixed background color for all participants context menus
- Removed connection status from ReactVideoMenu and added it for local participants
- Removed AVModeration comments on mobile
- Show on stage option visible only when participants pane is closed
master
Calinteodor 3 年前
父节点
当前提交
d22fc88ae3
没有帐户链接到提交者的电子邮件

+ 1
- 2
react/features/base/dialog/components/native/styles.js 查看文件

171
          */
171
          */
172
         labelStyle: {
172
         labelStyle: {
173
             ...brandedDialogLabelStyle,
173
             ...brandedDialogLabelStyle,
174
-            marginLeft: 32
174
+            marginLeft: 16
175
         },
175
         },
176
 
176
 
177
         /**
177
         /**
179
          */
179
          */
180
         style: {
180
         style: {
181
             ...brandedDialogItemContainerStyle,
181
             ...brandedDialogItemContainerStyle,
182
-            backgroundColor: ColorPalette.darkBackground,
183
             paddingHorizontal: MD_ITEM_MARGIN_PADDING
182
             paddingHorizontal: MD_ITEM_MARGIN_PADDING
184
         },
183
         },
185
 
184
 

+ 11
- 0
react/features/base/ui/Tokens.js 查看文件

18
     primary08: '#99BBF3',
18
     primary08: '#99BBF3',
19
     primary09: '#CCDDF9',
19
     primary09: '#CCDDF9',
20
 
20
 
21
+    surface00: '#111111',
21
     surface01: '#040404',
22
     surface01: '#040404',
22
     surface02: '#141414',
23
     surface02: '#141414',
23
     surface03: '#292929',
24
     surface03: '#292929',
29
     surface09: '#C2C2C2',
30
     surface09: '#C2C2C2',
30
     surface10: '#E0E0E0',
31
     surface10: '#E0E0E0',
31
     surface11: '#FFF',
32
     surface11: '#FFF',
33
+    surface12: '#AAAAAA',
32
 
34
 
33
     success04: '#189B55',
35
     success04: '#189B55',
34
     success05: '#1EC26A',
36
     success05: '#1EC26A',
109
     // Disabled state for danger buttons
111
     // Disabled state for danger buttons
110
     actionDangerDisabled: 'error03',
112
     actionDangerDisabled: 'error03',
111
 
113
 
114
+    // Bottom sheet background
115
+    bottomSheet: 'surface00',
116
+
112
     // Primary text – default color for body copy & headers
117
     // Primary text – default color for body copy & headers
113
     text01: 'surface11',
118
     text01: 'surface11',
114
 
119
 
118
     // Tertiary text with low contrast – placeholders, disabled actions, label for disabled buttons
123
     // Tertiary text with low contrast – placeholders, disabled actions, label for disabled buttons
119
     text03: 'surface07',
124
     text03: 'surface07',
120
 
125
 
126
+    // Text for bottom sheet items
127
+    text04: 'surface12',
128
+
121
     // error messages
129
     // error messages
122
     textError: 'error06',
130
     textError: 'error06',
123
 
131
 
149
     // Background for high-contrast input fields
157
     // Background for high-contrast input fields
150
     field02: 'surface11',
158
     field02: 'surface11',
151
 
159
 
160
+    // Color for the section divider
161
+    dividerColor: 'surface12',
162
+
152
     // Background for high-contrast input fields on hover
163
     // Background for high-contrast input fields on hover
153
     field02Hover: 'primary09',
164
     field02Hover: 'primary09',
154
 
165
 

+ 16
- 4
react/features/participants-pane/actions.native.js 查看文件

1
 // @flow
1
 // @flow
2
 
2
 
3
 import { openDialog } from '../base/dialog';
3
 import { openDialog } from '../base/dialog';
4
+import ConnectionStatusComponent
5
+    from '../video-menu/components/native/ConnectionStatusComponent';
6
+import RemoteVideoMenu from '../video-menu/components/native/RemoteVideoMenu';
4
 
7
 
5
 import { SET_VOLUME } from './actionTypes';
8
 import { SET_VOLUME } from './actionTypes';
6
 import {
9
 import {
7
-    ContextMenuMeetingParticipantDetails,
8
     ContextMenuLobbyParticipantReject
10
     ContextMenuLobbyParticipantReject
9
 } from './components/native';
11
 } from './components/native';
10
 export * from './actions.any';
12
 export * from './actions.any';
21
 
23
 
22
 
24
 
23
 /**
25
 /**
24
- * Displays the context menu for the selected meeting participant.
26
+ * Displays the connection status for the local meeting participant.
25
  *
27
  *
26
  * @param {string} participantID - The selected meeting participant id.
28
  * @param {string} participantID - The selected meeting participant id.
27
  * @returns {Function}
29
  * @returns {Function}
28
  */
30
  */
29
-export function showContextMenuDetails(participantID: String) {
30
-    return openDialog(ContextMenuMeetingParticipantDetails, { participantID });
31
+export function showConnectionStatus(participantID: String) {
32
+    return openDialog(ConnectionStatusComponent, { participantID });
33
+}
34
+
35
+/**
36
+ * Displays the context menu for the selected meeting participant.
37
+ *
38
+ * @param {Object} participant - The selected meeting participant.
39
+ * @returns {Function}
40
+ */
41
+export function showContextMenuDetails(participant: Object) {
42
+    return openDialog(RemoteVideoMenu, { participant });
31
 }
43
 }
32
 
44
 
33
 /**
45
 /**

+ 18
- 15
react/features/participants-pane/components/native/ContextMenuLobbyParticipantReject.js 查看文件

3
 import React, { useCallback } from 'react';
3
 import React, { useCallback } from 'react';
4
 import { useTranslation } from 'react-i18next';
4
 import { useTranslation } from 'react-i18next';
5
 import { TouchableOpacity, View } from 'react-native';
5
 import { TouchableOpacity, View } from 'react-native';
6
-import { Divider, Text } from 'react-native-paper';
6
+import { Text } from 'react-native-paper';
7
 import { useDispatch, useSelector } from 'react-redux';
7
 import { useDispatch, useSelector } from 'react-redux';
8
 
8
 
9
 import { Avatar } from '../../../base/avatar';
9
 import { Avatar } from '../../../base/avatar';
33
     const reject = useCallback(() => dispatch(setKnockingParticipantApproval(p.id, false), [ dispatch ]));
33
     const reject = useCallback(() => dispatch(setKnockingParticipantApproval(p.id, false), [ dispatch ]));
34
     const { t } = useTranslation();
34
     const { t } = useTranslation();
35
 
35
 
36
+    // eslint-disable-next-line react/no-multi-comp
37
+    const renderMenuHeader = () => (
38
+        <View
39
+            style = { styles.contextMenuItemSectionAvatar }>
40
+            <Avatar
41
+                className = 'participant-avatar'
42
+                participantId = { p.id }
43
+                size = { 24 } />
44
+            <Text style = { styles.contextMenuItemName }>
45
+                { displayName }
46
+            </Text>
47
+        </View>
48
+    );
49
+
36
     return (
50
     return (
37
         <BottomSheet
51
         <BottomSheet
38
             addScrollViewPadding = { false }
52
             addScrollViewPadding = { false }
39
             onCancel = { cancel }
53
             onCancel = { cancel }
54
+            /* eslint-disable-next-line react/jsx-no-bind */
55
+            renderHeader = { renderMenuHeader }
40
             showSlidingView = { Boolean(knockParticipantIsAvailable) }
56
             showSlidingView = { Boolean(knockParticipantIsAvailable) }
41
             style = { styles.contextMenuMore }>
57
             style = { styles.contextMenuMore }>
42
-            <View
43
-                style = { styles.contextMenuItemSectionAvatar }>
44
-                <Avatar
45
-                    className = 'participant-avatar'
46
-                    participantId = { p.id }
47
-                    size = { 20 } />
48
-                <View style = { styles.contextMenuItemAvatarText }>
49
-                    <Text style = { styles.contextMenuItemName }>
50
-                        { displayName }
51
-                    </Text>
52
-                </View>
53
-            </View>
54
-            <Divider style = { styles.divider } />
55
             <TouchableOpacity
58
             <TouchableOpacity
56
                 onPress = { reject }
59
                 onPress = { reject }
57
                 style = { styles.contextMenuItem }>
60
                 style = { styles.contextMenuItem }>
58
                 <Icon
61
                 <Icon
59
-                    size = { 20 }
62
+                    size = { 24 }
60
                     src = { IconClose } />
63
                     src = { IconClose } />
61
                 <Text style = { styles.contextMenuItemText }>{ t('lobby.reject') }</Text>
64
                 <Text style = { styles.contextMenuItemText }>{ t('lobby.reject') }</Text>
62
             </TouchableOpacity>
65
             </TouchableOpacity>

+ 0
- 264
react/features/participants-pane/components/native/ContextMenuMeetingParticipantDetails.js 查看文件

1
-// @flow
2
-
3
-import React, { useCallback } from 'react';
4
-import { useTranslation } from 'react-i18next';
5
-import { TouchableOpacity, View } from 'react-native';
6
-import { Divider, Text } from 'react-native-paper';
7
-import { useDispatch } from 'react-redux';
8
-
9
-import { Avatar } from '../../../base/avatar';
10
-import { hideDialog, openDialog } from '../../../base/dialog/actions';
11
-import BottomSheet from '../../../base/dialog/components/native/BottomSheet';
12
-import {
13
-    Icon, IconCloseCircle, IconMessage,
14
-    IconMicrophoneEmptySlash,
15
-    IconMuteEveryoneElse, IconVideoOff
16
-} from '../../../base/icons';
17
-import {
18
-    getLocalParticipant,
19
-    getParticipantByIdOrUndefined,
20
-    getParticipantDisplayName, getRemoteParticipants,
21
-    isLocalParticipantModerator
22
-} from '../../../base/participants/functions';
23
-import { connect } from '../../../base/redux';
24
-import {
25
-    isParticipantAudioMuted,
26
-    isParticipantVideoMuted
27
-} from '../../../base/tracks/functions';
28
-import { openChat } from '../../../chat/actions.native';
29
-import {
30
-    KickRemoteParticipantDialog,
31
-    MuteEveryoneDialog,
32
-    MuteRemoteParticipantDialog,
33
-    MuteRemoteParticipantsVideoDialog
34
-} from '../../../video-menu';
35
-import VolumeSlider from '../../../video-menu/components/native/VolumeSlider';
36
-
37
-import styles from './styles';
38
-
39
-type Props = {
40
-
41
-    /**
42
-     * The display name of the participant.
43
-     */
44
-    _displayName: string,
45
-
46
-    /**
47
-     * True if the local participant is moderator and false otherwise.
48
-     */
49
-    _isLocalModerator: boolean,
50
-
51
-    /**
52
-     * True if the participant is moderator and false otherwise.
53
-     */
54
-    _isParticipantModerator: boolean,
55
-
56
-    /**
57
-     * True if the participant is video muted and false otherwise.
58
-     */
59
-    _isParticipantVideoMuted: boolean,
60
-
61
-    /**
62
-     * True if the participant is audio muted and false otherwise.
63
-     */
64
-    _isParticipantAudioMuted: boolean,
65
-
66
-    /**
67
-     * Whether the participant is present in the room or not.
68
-     */
69
-    _isParticipantIDAvailable?: boolean,
70
-
71
-    /**
72
-     * Participant reference
73
-     */
74
-    _participant: Object,
75
-
76
-    /**
77
-     * The ID of the participant.
78
-     */
79
-    participantID: string,
80
-};
81
-
82
-const ContextMenuMeetingParticipantDetails = (
83
-        {
84
-            _displayName,
85
-            _isLocalModerator,
86
-            _isParticipantVideoMuted,
87
-            _isParticipantAudioMuted,
88
-            _participant,
89
-            _isParticipantIDAvailable,
90
-            participantID
91
-        }: Props) => {
92
-    const dispatch = useDispatch();
93
-    const cancel = useCallback(() => dispatch(hideDialog()), [ dispatch ]);
94
-    const kickRemoteParticipant = useCallback(() => {
95
-        dispatch(openDialog(KickRemoteParticipantDialog, {
96
-            participantID
97
-        }));
98
-    }, [ dispatch, participantID ]);
99
-    const muteAudio = useCallback(() => {
100
-        dispatch(openDialog(MuteRemoteParticipantDialog, {
101
-            participantID
102
-        }));
103
-    }, [ dispatch, participantID ]);
104
-    const muteEveryoneElse = useCallback(() => {
105
-        dispatch(openDialog(MuteEveryoneDialog, {
106
-            exclude: [ participantID ]
107
-        }));
108
-    }, [ dispatch, participantID ]);
109
-    const muteVideo = useCallback(() => {
110
-        dispatch(openDialog(MuteRemoteParticipantsVideoDialog, {
111
-            participantID
112
-        }));
113
-    }, [ dispatch, participantID ]);
114
-
115
-    const sendPrivateMessage = useCallback(() => {
116
-        dispatch(hideDialog());
117
-        dispatch(openChat(_participant));
118
-    }, [ dispatch, _participant ]);
119
-    const { t } = useTranslation();
120
-
121
-    return (
122
-        <BottomSheet
123
-            addScrollViewPadding = { false }
124
-            onCancel = { cancel }
125
-            showSlidingView = { _isParticipantIDAvailable }
126
-            style = { styles.contextMenuMeetingParticipantDetails }>
127
-            <View
128
-                style = { styles.contextMenuItemSectionAvatar }>
129
-                <Avatar
130
-                    className = 'participant-avatar'
131
-                    participantId = { participantID }
132
-                    size = { 20 } />
133
-                <View style = { styles.contextMenuItemAvatarText }>
134
-                    <Text style = { styles.contextMenuItemName }>
135
-                        { _displayName }
136
-                    </Text>
137
-                </View>
138
-            </View>
139
-            <Divider style = { styles.divider } />
140
-            {
141
-                _isLocalModerator && (
142
-                    <>
143
-                        {
144
-                            !_isParticipantAudioMuted
145
-                            && <TouchableOpacity
146
-                                onPress = { muteAudio }
147
-                                style = { styles.contextMenuItem }>
148
-                                <Icon
149
-                                    size = { 20 }
150
-                                    src = { IconMicrophoneEmptySlash } />
151
-                                <Text style = { styles.contextMenuItemText }>
152
-                                    { t('participantsPane.actions.mute') }
153
-                                </Text>
154
-                            </TouchableOpacity>
155
-                        }
156
-
157
-                        <TouchableOpacity
158
-                            onPress = { muteEveryoneElse }
159
-                            style = { styles.contextMenuItem }>
160
-                            <Icon
161
-                                size = { 20 }
162
-                                src = { IconMuteEveryoneElse } />
163
-                            <Text style = { styles.contextMenuItemText }>
164
-                                { t('participantsPane.actions.muteEveryoneElse') }
165
-                            </Text>
166
-                        </TouchableOpacity>
167
-                    </>
168
-                )
169
-            }
170
-            <Divider style = { styles.divider } />
171
-            {
172
-                _isLocalModerator && (
173
-                    <>
174
-                        {
175
-                            !_isParticipantVideoMuted
176
-                            && <TouchableOpacity
177
-                                onPress = { muteVideo }
178
-                                style = { styles.contextMenuItemSection }>
179
-                                <Icon
180
-                                    size = { 20 }
181
-                                    src = { IconVideoOff } />
182
-                                <Text style = { styles.contextMenuItemText }>
183
-                                    { t('participantsPane.actions.stopVideo') }
184
-                                </Text>
185
-                            </TouchableOpacity>
186
-                        }
187
-
188
-                        <TouchableOpacity
189
-                            onPress = { kickRemoteParticipant }
190
-                            style = { styles.contextMenuItem }>
191
-                            <Icon
192
-                                size = { 20 }
193
-                                src = { IconCloseCircle } />
194
-                            <Text style = { styles.contextMenuItemText }>
195
-                                { t('videothumbnail.kick') }
196
-                            </Text>
197
-                        </TouchableOpacity>
198
-                    </>
199
-                )
200
-            }
201
-            <TouchableOpacity
202
-                onPress = { sendPrivateMessage }
203
-                style = { styles.contextMenuItem }>
204
-                <Icon
205
-                    size = { 20 }
206
-                    src = { IconMessage } />
207
-                <Text style = { styles.contextMenuItemText }>
208
-                    { t('toolbar.accessibilityLabel.privateMessage') }
209
-                </Text>
210
-            </TouchableOpacity>
211
-            {/* We need design specs for this*/}
212
-            {/* <TouchableOpacity*/}
213
-            {/*    style = { styles.contextMenuItemSection }>*/}
214
-            {/*    <Icon*/}
215
-            {/*        size = { 20 }*/}
216
-            {/*        src = { IconConnectionActive }*/}
217
-            {/*        style = { styles.contextMenuItemIcon } />*/}
218
-            {/*    <Text style = { styles.contextMenuItemText }>{ t('participantsPane.actions.networkStats') }</Text>*/}
219
-            {/* </TouchableOpacity>*/}
220
-            <Divider style = { styles.divider } />
221
-            <VolumeSlider participantID = { participantID } />
222
-        </BottomSheet>
223
-    );
224
-};
225
-
226
-
227
-/**
228
- * Maps (parts of) the redux state to the associated props for this component.
229
- *
230
- * @param {Object} state - The Redux state.
231
- * @param {Object} ownProps - The own props of the component.
232
- * @private
233
- * @returns {Props}
234
- */
235
-function _mapStateToProps(state, ownProps): Object {
236
-    const { participantID } = ownProps;
237
-    const participantIDS = [];
238
-
239
-    const participant = getParticipantByIdOrUndefined(state, participantID);
240
-    const _isLocalModerator = isLocalParticipantModerator(state);
241
-    const _isParticipantVideoMuted = isParticipantVideoMuted(participant, state);
242
-    const _isParticipantAudioMuted = isParticipantAudioMuted(participant, state);
243
-    const localParticipant = getLocalParticipant(state);
244
-    const remoteParticipants = getRemoteParticipants(state);
245
-
246
-    localParticipant && participantIDS.push(localParticipant?.id);
247
-
248
-    remoteParticipants.forEach(p => {
249
-        participantIDS.push(p?.id);
250
-    });
251
-
252
-    const isParticipantIDAvailable = participantIDS.find(partID => partID === participantID);
253
-
254
-    return {
255
-        _displayName: getParticipantDisplayName(state, participantID),
256
-        _isLocalModerator,
257
-        _isParticipantAudioMuted,
258
-        _isParticipantIDAvailable: Boolean(isParticipantIDAvailable),
259
-        _isParticipantVideoMuted,
260
-        _participant: participant
261
-    };
262
-}
263
-
264
-export default connect(_mapStateToProps)(ContextMenuMeetingParticipantDetails);

+ 2
- 15
react/features/participants-pane/components/native/ContextMenuMore.js 查看文件

9
 import { openDialog, hideDialog } from '../../../base/dialog/actions';
9
 import { openDialog, hideDialog } from '../../../base/dialog/actions';
10
 import BottomSheet from '../../../base/dialog/components/native/BottomSheet';
10
 import BottomSheet from '../../../base/dialog/components/native/BottomSheet';
11
 import {
11
 import {
12
-    Icon, IconMicDisabledHollow,
12
+    Icon,
13
     IconVideoOff
13
     IconVideoOff
14
 } from '../../../base/icons';
14
 } from '../../../base/icons';
15
 import {
15
 import {
16
     getLocalParticipant,
16
     getLocalParticipant,
17
     getParticipantCount
17
     getParticipantCount
18
 } from '../../../base/participants';
18
 } from '../../../base/participants';
19
-import { BlockAudioVideoDialog } from '../../../video-menu';
20
 import MuteEveryonesVideoDialog
19
 import MuteEveryonesVideoDialog
21
     from '../../../video-menu/components/native/MuteEveryonesVideoDialog';
20
     from '../../../video-menu/components/native/MuteEveryonesVideoDialog';
22
 
21
 
24
 
23
 
25
 export const ContextMenuMore = () => {
24
 export const ContextMenuMore = () => {
26
     const dispatch = useDispatch();
25
     const dispatch = useDispatch();
27
-    const blockAudioVideo = useCallback(() => dispatch(openDialog(BlockAudioVideoDialog)), [ dispatch ]);
28
     const cancel = useCallback(() => dispatch(hideDialog()), [ dispatch ]);
26
     const cancel = useCallback(() => dispatch(hideDialog()), [ dispatch ]);
29
     const { id } = useSelector(getLocalParticipant);
27
     const { id } = useSelector(getLocalParticipant);
30
     const participantsCount = useSelector(getParticipantCount);
28
     const participantsCount = useSelector(getParticipantCount);
45
                 onPress = { muteAllVideo }
43
                 onPress = { muteAllVideo }
46
                 style = { styles.contextMenuItem }>
44
                 style = { styles.contextMenuItem }>
47
                 <Icon
45
                 <Icon
48
-                    size = { 20 }
46
+                    size = { 24 }
49
                     src = { IconVideoOff } />
47
                     src = { IconVideoOff } />
50
                 <Text style = { styles.contextMenuItemText }>{t('participantsPane.actions.stopEveryonesVideo')}</Text>
48
                 <Text style = { styles.contextMenuItemText }>{t('participantsPane.actions.stopEveryonesVideo')}</Text>
51
             </TouchableOpacity>
49
             </TouchableOpacity>
52
-            <TouchableOpacity
53
-                onPress = { blockAudioVideo }
54
-                style = { styles.contextMenuItem }>
55
-                <Icon
56
-                    size = { 20 }
57
-                    src = { IconMicDisabledHollow }
58
-                    style = { styles.contextMenuIcon } />
59
-                <Text style = { styles.contextMenuItemText }>
60
-                    {t('participantsPane.actions.blockEveryoneMicCamera')}
61
-                </Text>
62
-            </TouchableOpacity>
63
         </BottomSheet>
50
         </BottomSheet>
64
     );
51
     );
65
 };
52
 };

+ 4
- 4
react/features/participants-pane/components/native/MeetingParticipantList.js 查看文件

13
     getRemoteParticipants
13
     getRemoteParticipants
14
 } from '../../../base/participants';
14
 } from '../../../base/participants';
15
 import { doInvitePeople } from '../../../invite/actions.native';
15
 import { doInvitePeople } from '../../../invite/actions.native';
16
-import { showContextMenuDetails } from '../../actions.native';
16
+import { showConnectionStatus, showContextMenuDetails } from '../../actions.native';
17
 import { shouldRenderInviteButton } from '../../functions';
17
 import { shouldRenderInviteButton } from '../../functions';
18
 
18
 
19
 import MeetingParticipantItem from './MeetingParticipantItem';
19
 import MeetingParticipantItem from './MeetingParticipantItem';
31
 
31
 
32
     // eslint-disable-next-line react/no-multi-comp
32
     // eslint-disable-next-line react/no-multi-comp
33
     const renderParticipant = p => (
33
     const renderParticipant = p => (
34
-
35
         <MeetingParticipantItem
34
         <MeetingParticipantItem
36
             key = { p.id }
35
             key = { p.id }
37
-            /* eslint-disable-next-line react/jsx-no-bind */
38
-            onPress = { () => !p.local && dispatch(showContextMenuDetails(p.id)) }
36
+            /* eslint-disable-next-line react/jsx-no-bind,no-confusing-arrow */
37
+            onPress = { () => p.local
38
+                ? dispatch(showConnectionStatus(p.id)) : dispatch(showContextMenuDetails(p)) }
39
             participantID = { p.id } />
39
             participantID = { p.id } />
40
     );
40
     );
41
 
41
 

+ 0
- 1
react/features/participants-pane/components/native/index.js 查看文件

3
 export { default as ParticipantsPane } from './ParticipantsPane';
3
 export { default as ParticipantsPane } from './ParticipantsPane';
4
 export { default as ParticipantsPaneButton } from './ParticipantsPaneButton';
4
 export { default as ParticipantsPaneButton } from './ParticipantsPaneButton';
5
 export { default as ContextMenuLobbyParticipantReject } from './ContextMenuLobbyParticipantReject';
5
 export { default as ContextMenuLobbyParticipantReject } from './ContextMenuLobbyParticipantReject';
6
-export { default as ContextMenuMeetingParticipantDetails } from './ContextMenuMeetingParticipantDetails';

+ 18
- 23
react/features/participants-pane/components/native/styles.js 查看文件

145
         display: 'flex',
145
         display: 'flex',
146
         flexDirection: 'row',
146
         flexDirection: 'row',
147
         overflow: 'hidden',
147
         overflow: 'hidden',
148
-        paddingLeft: BaseTheme.spacing[2],
148
+        paddingLeft: BaseTheme.spacing[3],
149
         width: '63%'
149
         width: '63%'
150
     },
150
     },
151
 
151
 
187
         ...flexContent,
187
         ...flexContent,
188
         top: BaseTheme.spacing[1]
188
         top: BaseTheme.spacing[1]
189
     },
189
     },
190
+
190
     lobbyList: {
191
     lobbyList: {
191
         position: 'relative'
192
         position: 'relative'
192
     },
193
     },
277
     },
278
     },
278
 
279
 
279
     contextMenuMore: {
280
     contextMenuMore: {
280
-        backgroundColor: BaseTheme.palette.action02,
281
-        borderRadius: BaseTheme.shape.borderRadius
282
-    },
283
-
284
-    contextMenuMeetingParticipantDetails: {
285
-        backgroundColor: BaseTheme.palette.action02,
281
+        backgroundColor: BaseTheme.palette.bottomSheet,
286
         borderRadius: BaseTheme.shape.borderRadius
282
         borderRadius: BaseTheme.shape.borderRadius
287
     },
283
     },
288
 
284
 
303
         marginHorizontal: BaseTheme.spacing[0],
299
         marginHorizontal: BaseTheme.spacing[0],
304
         paddingTop: 12,
300
         paddingTop: 12,
305
         paddingBottom: 12,
301
         paddingBottom: 12,
306
-        paddingRight: BaseTheme.spacing[3],
307
-        paddingLeft: BaseTheme.spacing[3],
308
         textTransform: 'capitalize',
302
         textTransform: 'capitalize',
309
         width: 94
303
         width: 94
310
     },
304
     },
318
     },
312
     },
319
 
313
 
320
     contextMenuItemSectionAvatar: {
314
     contextMenuItemSectionAvatar: {
321
-        ...contextMenuItem,
322
-        marginLeft: BaseTheme.spacing[3]
323
-    },
324
-
325
-    contextMenuItemAvatarText: {
326
-        ...contextMenuItemText,
327
-        marginLeft: BaseTheme.spacing[3]
315
+        alignItems: 'center',
316
+        backgroundColor: BaseTheme.palette.bottomSheet,
317
+        borderBottomColor: BaseTheme.palette.dividerColor,
318
+        borderBottomWidth: 1,
319
+        borderTopLeftRadius: BaseTheme.spacing[3],
320
+        borderTopRightRadius: BaseTheme.spacing[3],
321
+        flexDirection: 'row',
322
+        height: BaseTheme.spacing[7],
323
+        paddingLeft: BaseTheme.spacing[3]
328
     },
324
     },
329
 
325
 
330
     contextMenuItemText: {
326
     contextMenuItemText: {
333
     },
329
     },
334
 
330
 
335
     contextMenuItemName: {
331
     contextMenuItemName: {
336
-        ...BaseTheme.typography.bodyShortRegularLarge,
337
-        color: BaseTheme.palette.text01
338
-    },
339
-
340
-    contextMenuIcon: {
341
-        color: BaseTheme.palette.actionDanger
332
+        color: BaseTheme.palette.text04,
333
+        flexShrink: 1,
334
+        fontSize: BaseTheme.spacing[3],
335
+        marginLeft: BaseTheme.spacing[3],
336
+        opacity: 0.90
342
     },
337
     },
343
 
338
 
344
     divider: {
339
     divider: {
345
-        backgroundColor: BaseTheme.palette.section01
340
+        backgroundColor: BaseTheme.palette.dividerColor
346
     }
341
     }
347
 };
342
 };

+ 2
- 2
react/features/video-menu/components/AbstractKickButton.js 查看文件

1
 // @flow
1
 // @flow
2
 
2
 
3
 import { openDialog } from '../../base/dialog';
3
 import { openDialog } from '../../base/dialog';
4
-import { IconKick } from '../../base/icons';
4
+import { IconCloseCircle } from '../../base/icons';
5
 import { AbstractButton, type AbstractButtonProps } from '../../base/toolbox/components';
5
 import { AbstractButton, type AbstractButtonProps } from '../../base/toolbox/components';
6
 
6
 
7
 import { KickRemoteParticipantDialog } from '.';
7
 import { KickRemoteParticipantDialog } from '.';
29
  */
29
  */
30
 export default class AbstractKickButton extends AbstractButton<Props, *> {
30
 export default class AbstractKickButton extends AbstractButton<Props, *> {
31
     accessibilityLabel = 'toolbar.accessibilityLabel.kick';
31
     accessibilityLabel = 'toolbar.accessibilityLabel.kick';
32
-    icon = IconKick;
32
+    icon = IconCloseCircle;
33
     label = 'videothumbnail.kick';
33
     label = 'videothumbnail.kick';
34
 
34
 
35
     /**
35
     /**

+ 2
- 2
react/features/video-menu/components/AbstractMuteVideoButton.js 查看文件

5
     sendAnalytics
5
     sendAnalytics
6
 } from '../../analytics';
6
 } from '../../analytics';
7
 import { openDialog } from '../../base/dialog';
7
 import { openDialog } from '../../base/dialog';
8
-import { IconCameraDisabled } from '../../base/icons';
8
+import { IconVideoOff } from '../../base/icons';
9
 import { MEDIA_TYPE } from '../../base/media';
9
 import { MEDIA_TYPE } from '../../base/media';
10
 import { AbstractButton, type AbstractButtonProps } from '../../base/toolbox/components';
10
 import { AbstractButton, type AbstractButtonProps } from '../../base/toolbox/components';
11
 import { isRemoteTrackMuted } from '../../base/tracks';
11
 import { isRemoteTrackMuted } from '../../base/tracks';
42
  */
42
  */
43
 export default class AbstractMuteVideoButton extends AbstractButton<Props, *> {
43
 export default class AbstractMuteVideoButton extends AbstractButton<Props, *> {
44
     accessibilityLabel = 'toolbar.accessibilityLabel.remoteVideoMute';
44
     accessibilityLabel = 'toolbar.accessibilityLabel.remoteVideoMute';
45
-    icon = IconCameraDisabled;
45
+    icon = IconVideoOff;
46
     label = 'videothumbnail.domuteVideo';
46
     label = 'videothumbnail.domuteVideo';
47
     toggledLabel = 'videothumbnail.videoMuted';
47
     toggledLabel = 'videothumbnail.videoMuted';
48
 
48
 

+ 16
- 8
react/features/video-menu/components/native/ConnectionStatusComponent.js 查看文件

2
 
2
 
3
 import React, { Component } from 'react';
3
 import React, { Component } from 'react';
4
 import { Text, View } from 'react-native';
4
 import { Text, View } from 'react-native';
5
+import { withTheme } from 'react-native-paper';
6
+
5
 
7
 
6
 import { Avatar } from '../../../base/avatar';
8
 import { Avatar } from '../../../base/avatar';
7
 import { ColorSchemeRegistry } from '../../../base/color-scheme';
9
 import { ColorSchemeRegistry } from '../../../base/color-scheme';
11
 import { getParticipantDisplayName } from '../../../base/participants';
13
 import { getParticipantDisplayName } from '../../../base/participants';
12
 import { BaseIndicator } from '../../../base/react';
14
 import { BaseIndicator } from '../../../base/react';
13
 import { connect } from '../../../base/redux';
15
 import { connect } from '../../../base/redux';
14
-import { StyleType, ColorPalette } from '../../../base/styles';
16
+import { StyleType } from '../../../base/styles';
15
 import statsEmitter from '../../../connection-indicator/statsEmitter';
17
 import statsEmitter from '../../../connection-indicator/statsEmitter';
16
 
18
 
17
 import styles from './styles';
19
 import styles from './styles';
57
     /**
59
     /**
58
      * The function to be used to translate i18n labels.
60
      * The function to be used to translate i18n labels.
59
      */
61
      */
60
-    t: Function
62
+    t: Function,
63
+
64
+    /**
65
+     * Theme used for styles.
66
+     */
67
+    theme: Object
61
 }
68
 }
62
 
69
 
63
 /**
70
 /**
116
      * @returns {React$Node}
123
      * @returns {React$Node}
117
      */
124
      */
118
     render(): React$Node {
125
     render(): React$Node {
119
-        const { t } = this.props;
126
+        const { t, theme } = this.props;
127
+        const { palette } = theme;
120
 
128
 
121
         return (
129
         return (
122
             <BottomSheet
130
             <BottomSheet
138
                         <BaseIndicator
146
                         <BaseIndicator
139
                             icon = { IconArrowDownLarge }
147
                             icon = { IconArrowDownLarge }
140
                             iconStyle = {{
148
                             iconStyle = {{
141
-                                color: ColorPalette.darkGrey
149
+                                color: palette.icon03
142
                             }} />
150
                             }} />
143
                         <Text style = { styles.statsInfoText }>
151
                         <Text style = { styles.statsInfoText }>
144
                             { this.state.downloadString }
152
                             { this.state.downloadString }
146
                         <BaseIndicator
154
                         <BaseIndicator
147
                             icon = { IconArrowUpLarge }
155
                             icon = { IconArrowUpLarge }
148
                             iconStyle = {{
156
                             iconStyle = {{
149
-                                color: ColorPalette.darkGrey
157
+                                color: palette.icon03
150
                             }} />
158
                             }} />
151
                         <Text style = { styles.statsInfoText }>
159
                         <Text style = { styles.statsInfoText }>
152
                             { `${this.state.uploadString} Kbps` }
160
                             { `${this.state.uploadString} Kbps` }
159
                         <BaseIndicator
167
                         <BaseIndicator
160
                             icon = { IconArrowDownLarge }
168
                             icon = { IconArrowDownLarge }
161
                             iconStyle = {{
169
                             iconStyle = {{
162
-                                color: ColorPalette.darkGrey
170
+                                color: palette.icon03
163
                             }} />
171
                             }} />
164
                         <Text style = { styles.statsInfoText }>
172
                         <Text style = { styles.statsInfoText }>
165
                             { this.state.packetLostDownloadString }
173
                             { this.state.packetLostDownloadString }
167
                         <BaseIndicator
175
                         <BaseIndicator
168
                             icon = { IconArrowUpLarge }
176
                             icon = { IconArrowUpLarge }
169
                             iconStyle = {{
177
                             iconStyle = {{
170
-                                color: ColorPalette.darkGrey
178
+                                color: palette.icon03
171
                             }} />
179
                             }} />
172
                         <Text style = { styles.statsInfoText }>
180
                         <Text style = { styles.statsInfoText }>
173
                             { this.state.packetLostUploadString }
181
                             { this.state.packetLostUploadString }
426
     };
434
     };
427
 }
435
 }
428
 
436
 
429
-ConnectionStatusComponent_ = translate(connect(_mapStateToProps)(ConnectionStatusComponent));
437
+ConnectionStatusComponent_ = translate(connect(_mapStateToProps)(withTheme(ConnectionStatusComponent)));
430
 
438
 
431
 export default ConnectionStatusComponent_;
439
 export default ConnectionStatusComponent_;

+ 22
- 0
react/features/video-menu/components/native/MuteVideoButton.js 查看文件

1
+// @flow
2
+
3
+import { translate } from '../../../base/i18n';
4
+import { isLocalParticipantModerator } from '../../../base/participants';
5
+import { connect } from '../../../base/redux';
6
+import AbstractMuteVideoButton, { _mapStateToProps as _abstractMapStateToProps } from '../AbstractMuteVideoButton';
7
+
8
+/**
9
+ * Maps part of the Redux state to the props of this component.
10
+ *
11
+ * @param {Object} state - The Redux state.
12
+ * @param {Object} ownProps - Properties of component.
13
+ * @returns {Props}
14
+ */
15
+function _mapStateToProps(state, ownProps) {
16
+    return {
17
+        ..._abstractMapStateToProps(state, ownProps),
18
+        visible: isLocalParticipantModerator(state)
19
+    };
20
+}
21
+
22
+export default translate(connect(_mapStateToProps)(AbstractMuteVideoButton));

+ 3
- 1
react/features/video-menu/components/native/PinButton.js 查看文件

59
  * @returns {Props}
59
  * @returns {Props}
60
  */
60
  */
61
 function _mapStateToProps(state) {
61
 function _mapStateToProps(state) {
62
+    const { isOpen } = state['features/participants-pane'];
63
+
62
     return {
64
     return {
63
-        visible: shouldDisplayTileView(state)
65
+        visible: !isOpen && shouldDisplayTileView(state)
64
     };
66
     };
65
 }
67
 }
66
 
68
 

+ 40
- 8
react/features/video-menu/components/native/RemoteVideoMenu.js 查看文件

2
 
2
 
3
 import React, { PureComponent } from 'react';
3
 import React, { PureComponent } from 'react';
4
 import { Text, View } from 'react-native';
4
 import { Text, View } from 'react-native';
5
+import { Divider } from 'react-native-paper';
5
 
6
 
6
 import { Avatar } from '../../../base/avatar';
7
 import { Avatar } from '../../../base/avatar';
7
 import { ColorSchemeRegistry } from '../../../base/color-scheme';
8
 import { ColorSchemeRegistry } from '../../../base/color-scheme';
8
 import { BottomSheet, isDialogOpen } from '../../../base/dialog';
9
 import { BottomSheet, isDialogOpen } from '../../../base/dialog';
9
 import { KICK_OUT_ENABLED, getFeatureFlag } from '../../../base/flags';
10
 import { KICK_OUT_ENABLED, getFeatureFlag } from '../../../base/flags';
10
-import { getParticipantDisplayName } from '../../../base/participants';
11
+import {
12
+    getParticipantById,
13
+    getParticipantDisplayName
14
+} from '../../../base/participants';
11
 import { connect } from '../../../base/redux';
15
 import { connect } from '../../../base/redux';
12
 import { StyleType } from '../../../base/styles';
16
 import { StyleType } from '../../../base/styles';
13
 import { PrivateMessageButton } from '../../../chat';
17
 import { PrivateMessageButton } from '../../../chat';
14
 import { hideRemoteVideoMenu } from '../../actions.native';
18
 import { hideRemoteVideoMenu } from '../../actions.native';
19
+import ConnectionStatusButton from '../native/ConnectionStatusButton';
15
 
20
 
16
-import ConnectionStatusButton from './ConnectionStatusButton';
17
 import GrantModeratorButton from './GrantModeratorButton';
21
 import GrantModeratorButton from './GrantModeratorButton';
18
 import KickButton from './KickButton';
22
 import KickButton from './KickButton';
19
 import MuteButton from './MuteButton';
23
 import MuteButton from './MuteButton';
20
 import MuteEveryoneElseButton from './MuteEveryoneElseButton';
24
 import MuteEveryoneElseButton from './MuteEveryoneElseButton';
25
+import MuteVideoButton from './MuteVideoButton';
21
 import PinButton from './PinButton';
26
 import PinButton from './PinButton';
22
 import styles from './styles';
27
 import styles from './styles';
23
 
28
 
29
+// import VolumeSlider from './VolumeSlider';
30
+
31
+
24
 /**
32
 /**
25
  * Size of the rendered avatar in the menu.
33
  * Size of the rendered avatar in the menu.
26
  */
34
  */
27
-const AVATAR_SIZE = 25;
35
+const AVATAR_SIZE = 24;
28
 
36
 
29
 type Props = {
37
 type Props = {
30
 
38
 
63
      */
71
      */
64
     _isOpen: boolean,
72
     _isOpen: boolean,
65
 
73
 
74
+    /**
75
+     * Whether the participant is present in the room or not.
76
+     */
77
+    _isParticipantAvailable?: boolean,
78
+
66
     /**
79
     /**
67
      * Display name of the participant retrieved from Redux.
80
      * Display name of the participant retrieved from Redux.
68
      */
81
      */
69
-    _participantDisplayName: string
82
+    _participantDisplayName: string,
83
+
84
+    /**
85
+     * The ID of the participant.
86
+     */
87
+    _participantID: ?string,
70
 }
88
 }
71
 
89
 
72
 // eslint-disable-next-line prefer-const
90
 // eslint-disable-next-line prefer-const
94
      * @inheritdoc
112
      * @inheritdoc
95
      */
113
      */
96
     render() {
114
     render() {
97
-        const { _disableKick, _disableRemoteMute, _disableGrantModerator, participant } = this.props;
115
+        const {
116
+            _disableKick,
117
+            _disableRemoteMute,
118
+            _disableGrantModerator,
119
+            _isParticipantAvailable,
120
+            participant
121
+        } = this.props;
98
         const buttonProps = {
122
         const buttonProps = {
99
             afterClick: this._onCancel,
123
             afterClick: this._onCancel,
100
             showLabel: true,
124
             showLabel: true,
105
         return (
129
         return (
106
             <BottomSheet
130
             <BottomSheet
107
                 onCancel = { this._onCancel }
131
                 onCancel = { this._onCancel }
108
-                renderHeader = { this._renderMenuHeader }>
132
+                renderHeader = { this._renderMenuHeader }
133
+                showSlidingView = { _isParticipantAvailable }>
109
                 { !_disableRemoteMute && <MuteButton { ...buttonProps } /> }
134
                 { !_disableRemoteMute && <MuteButton { ...buttonProps } /> }
135
+                <MuteEveryoneElseButton { ...buttonProps } />
136
+                { !_disableRemoteMute && <MuteVideoButton { ...buttonProps } /> }
137
+                <Divider style = { styles.divider } />
110
                 { !_disableKick && <KickButton { ...buttonProps } /> }
138
                 { !_disableKick && <KickButton { ...buttonProps } /> }
111
                 { !_disableGrantModerator && <GrantModeratorButton { ...buttonProps } /> }
139
                 { !_disableGrantModerator && <GrantModeratorButton { ...buttonProps } /> }
112
                 <PinButton { ...buttonProps } />
140
                 <PinButton { ...buttonProps } />
113
                 <PrivateMessageButton { ...buttonProps } />
141
                 <PrivateMessageButton { ...buttonProps } />
114
-                <MuteEveryoneElseButton { ...buttonProps } />
115
                 <ConnectionStatusButton { ...buttonProps } />
142
                 <ConnectionStatusButton { ...buttonProps } />
143
+                {/* <Divider style = { styles.divider } />*/}
144
+                {/* <VolumeSlider participantID = { _participantID } />*/}
116
             </BottomSheet>
145
             </BottomSheet>
117
         );
146
         );
118
     }
147
     }
173
     const kickOutEnabled = getFeatureFlag(state, KICK_OUT_ENABLED, true);
202
     const kickOutEnabled = getFeatureFlag(state, KICK_OUT_ENABLED, true);
174
     const { participant } = ownProps;
203
     const { participant } = ownProps;
175
     const { remoteVideoMenu = {}, disableRemoteMute } = state['features/base/config'];
204
     const { remoteVideoMenu = {}, disableRemoteMute } = state['features/base/config'];
205
+    const isParticipantAvailable = getParticipantById(state, participant.id);
176
     let { disableKick } = remoteVideoMenu;
206
     let { disableKick } = remoteVideoMenu;
177
 
207
 
178
     disableKick = disableKick || !kickOutEnabled;
208
     disableKick = disableKick || !kickOutEnabled;
182
         _disableKick: Boolean(disableKick),
212
         _disableKick: Boolean(disableKick),
183
         _disableRemoteMute: Boolean(disableRemoteMute),
213
         _disableRemoteMute: Boolean(disableRemoteMute),
184
         _isOpen: isDialogOpen(state, RemoteVideoMenu_),
214
         _isOpen: isDialogOpen(state, RemoteVideoMenu_),
185
-        _participantDisplayName: getParticipantDisplayName(state, participant.id)
215
+        _isParticipantAvailable: Boolean(isParticipantAvailable),
216
+        _participantDisplayName: getParticipantDisplayName(state, participant.id),
217
+        _participantID: participant.id
186
     };
218
     };
187
 }
219
 }
188
 
220
 

+ 2
- 5
react/features/video-menu/components/native/VolumeSlider.js 查看文件

7
 import { withTheme } from 'react-native-paper';
7
 import { withTheme } from 'react-native-paper';
8
 
8
 
9
 import { Icon, IconVolumeEmpty } from '../../../base/icons';
9
 import { Icon, IconVolumeEmpty } from '../../../base/icons';
10
-import { getLocalParticipant } from '../../../base/participants';
11
 import { connect } from '../../../base/redux';
10
 import { connect } from '../../../base/redux';
12
 import { setVolume } from '../../../participants-pane/actions.native';
11
 import { setVolume } from '../../../participants-pane/actions.native';
13
 import { VOLUME_SLIDER_SCALE } from '../../constants';
12
 import { VOLUME_SLIDER_SCALE } from '../../constants';
102
         return (
101
         return (
103
             <View style = { styles.volumeSliderContainer } >
102
             <View style = { styles.volumeSliderContainer } >
104
                 <Icon
103
                 <Icon
105
-                    size = { 20 }
104
+                    size = { 24 }
106
                     src = { IconVolumeEmpty } />
105
                     src = { IconVolumeEmpty } />
107
                 <Slider
106
                 <Slider
108
                     maximumTrackTintColor = { palette.field02 }
107
                     maximumTrackTintColor = { palette.field02 }
145
     const { participantID } = ownProps;
144
     const { participantID } = ownProps;
146
     const { participantsVolume } = state['features/participants-pane'];
145
     const { participantsVolume } = state['features/participants-pane'];
147
     const { startSilent } = state['features/base/config'];
146
     const { startSilent } = state['features/base/config'];
148
-    const localParticipant = getLocalParticipant(state);
149
 
147
 
150
     return {
148
     return {
151
         _startSilent: Boolean(startSilent),
149
         _startSilent: Boolean(startSilent),
152
-        _volume: localParticipant ? undefined : participantID
153
-            ? participantsVolume[participantID] : undefined
150
+        _volume: participantID && participantsVolume[participantID]
154
     };
151
     };
155
 }
152
 }
156
 
153
 

+ 12
- 6
react/features/video-menu/components/native/styles.js 查看文件

11
 export default createStyleSheet({
11
 export default createStyleSheet({
12
     participantNameContainer: {
12
     participantNameContainer: {
13
         alignItems: 'center',
13
         alignItems: 'center',
14
-        borderBottomColor: ColorPalette.lightGrey,
15
-        borderBottomWidth: 1,
14
+        borderBottomColor: BaseTheme.palette.dividerColor,
15
+        borderBottomWidth: 0.4,
16
         borderTopLeftRadius: 16,
16
         borderTopLeftRadius: 16,
17
         borderTopRightRadius: 16,
17
         borderTopRightRadius: 16,
18
         flexDirection: 'row',
18
         flexDirection: 'row',
29
     },
29
     },
30
 
30
 
31
     statsTitleText: {
31
     statsTitleText: {
32
+        color: BaseTheme.palette.text01,
32
         fontSize: 16,
33
         fontSize: 16,
33
         fontWeight: 'bold',
34
         fontWeight: 'bold',
34
         marginRight: 3
35
         marginRight: 3
35
     },
36
     },
36
 
37
 
37
     statsInfoText: {
38
     statsInfoText: {
39
+        color: BaseTheme.palette.text01,
38
         fontSize: 16,
40
         fontSize: 16,
39
         marginRight: 2,
41
         marginRight: 2,
40
         marginLeft: 2
42
         marginLeft: 2
48
     },
50
     },
49
 
51
 
50
     statsWrapper: {
52
     statsWrapper: {
51
-        marginVertical: 10
53
+        margin: BaseTheme.spacing[3]
52
     },
54
     },
53
 
55
 
54
     volumeSliderContainer: {
56
     volumeSliderContainer: {
55
         alignItems: 'center',
57
         alignItems: 'center',
56
         flexDirection: 'row',
58
         flexDirection: 'row',
57
-        marginLeft: BaseTheme.spacing[3],
58
-        marginTop: BaseTheme.spacing[3]
59
+        marginHorizontal: BaseTheme.spacing[3],
60
+        marginVertical: BaseTheme.spacing[2]
59
     },
61
     },
60
 
62
 
61
     sliderContainer: {
63
     sliderContainer: {
62
         marginLeft: BaseTheme.spacing[3],
64
         marginLeft: BaseTheme.spacing[3],
63
-        minWidth: '84%'
65
+        minWidth: '80%'
66
+    },
67
+
68
+    divider: {
69
+        backgroundColor: BaseTheme.palette.dividerColor
64
     }
70
     }
65
 });
71
 });

正在加载...
取消
保存