From d22fc88ae3e7500500f3c943530c3a2001f4155c Mon Sep 17 00:00:00 2001 From: Calinteodor Date: Fri, 30 Jul 2021 12:46:49 +0300 Subject: [PATCH] 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 --- .../base/dialog/components/native/styles.js | 3 +- react/features/base/ui/Tokens.js | 11 + .../participants-pane/actions.native.js | 20 +- .../ContextMenuLobbyParticipantReject.js | 33 ++- .../ContextMenuMeetingParticipantDetails.js | 264 ------------------ .../components/native/ContextMenuMore.js | 17 +- .../native/MeetingParticipantList.js | 8 +- .../components/native/index.js | 1 - .../components/native/styles.js | 41 ++- .../components/AbstractKickButton.js | 4 +- .../components/AbstractMuteVideoButton.js | 4 +- .../native/ConnectionStatusComponent.js | 24 +- .../components/native/MuteVideoButton.js | 22 ++ .../video-menu/components/native/PinButton.js | 4 +- .../components/native/RemoteVideoMenu.js | 48 +++- .../components/native/VolumeSlider.js | 7 +- .../video-menu/components/native/styles.js | 18 +- 17 files changed, 169 insertions(+), 360 deletions(-) delete mode 100644 react/features/participants-pane/components/native/ContextMenuMeetingParticipantDetails.js create mode 100644 react/features/video-menu/components/native/MuteVideoButton.js diff --git a/react/features/base/dialog/components/native/styles.js b/react/features/base/dialog/components/native/styles.js index 769891f15..7a59d038e 100644 --- a/react/features/base/dialog/components/native/styles.js +++ b/react/features/base/dialog/components/native/styles.js @@ -171,7 +171,7 @@ ColorSchemeRegistry.register('BottomSheet', { */ labelStyle: { ...brandedDialogLabelStyle, - marginLeft: 32 + marginLeft: 16 }, /** @@ -179,7 +179,6 @@ ColorSchemeRegistry.register('BottomSheet', { */ style: { ...brandedDialogItemContainerStyle, - backgroundColor: ColorPalette.darkBackground, paddingHorizontal: MD_ITEM_MARGIN_PADDING }, diff --git a/react/features/base/ui/Tokens.js b/react/features/base/ui/Tokens.js index 8e54420ce..a9eb6e083 100644 --- a/react/features/base/ui/Tokens.js +++ b/react/features/base/ui/Tokens.js @@ -18,6 +18,7 @@ export const colors = { primary08: '#99BBF3', primary09: '#CCDDF9', + surface00: '#111111', surface01: '#040404', surface02: '#141414', surface03: '#292929', @@ -29,6 +30,7 @@ export const colors = { surface09: '#C2C2C2', surface10: '#E0E0E0', surface11: '#FFF', + surface12: '#AAAAAA', success04: '#189B55', success05: '#1EC26A', @@ -109,6 +111,9 @@ export const colorMap = { // Disabled state for danger buttons actionDangerDisabled: 'error03', + // Bottom sheet background + bottomSheet: 'surface00', + // Primary text – default color for body copy & headers text01: 'surface11', @@ -118,6 +123,9 @@ export const colorMap = { // Tertiary text with low contrast – placeholders, disabled actions, label for disabled buttons text03: 'surface07', + // Text for bottom sheet items + text04: 'surface12', + // error messages textError: 'error06', @@ -149,6 +157,9 @@ export const colorMap = { // Background for high-contrast input fields field02: 'surface11', + // Color for the section divider + dividerColor: 'surface12', + // Background for high-contrast input fields on hover field02Hover: 'primary09', diff --git a/react/features/participants-pane/actions.native.js b/react/features/participants-pane/actions.native.js index aa6a653ad..e24d7cb70 100644 --- a/react/features/participants-pane/actions.native.js +++ b/react/features/participants-pane/actions.native.js @@ -1,10 +1,12 @@ // @flow import { openDialog } from '../base/dialog'; +import ConnectionStatusComponent + from '../video-menu/components/native/ConnectionStatusComponent'; +import RemoteVideoMenu from '../video-menu/components/native/RemoteVideoMenu'; import { SET_VOLUME } from './actionTypes'; import { - ContextMenuMeetingParticipantDetails, ContextMenuLobbyParticipantReject } from './components/native'; export * from './actions.any'; @@ -21,13 +23,23 @@ export function showContextMenuReject(participant: Object) { /** - * Displays the context menu for the selected meeting participant. + * Displays the connection status for the local meeting participant. * * @param {string} participantID - The selected meeting participant id. * @returns {Function} */ -export function showContextMenuDetails(participantID: String) { - return openDialog(ContextMenuMeetingParticipantDetails, { participantID }); +export function showConnectionStatus(participantID: String) { + return openDialog(ConnectionStatusComponent, { participantID }); +} + +/** + * Displays the context menu for the selected meeting participant. + * + * @param {Object} participant - The selected meeting participant. + * @returns {Function} + */ +export function showContextMenuDetails(participant: Object) { + return openDialog(RemoteVideoMenu, { participant }); } /** diff --git a/react/features/participants-pane/components/native/ContextMenuLobbyParticipantReject.js b/react/features/participants-pane/components/native/ContextMenuLobbyParticipantReject.js index 438824dd1..dde6c0747 100644 --- a/react/features/participants-pane/components/native/ContextMenuLobbyParticipantReject.js +++ b/react/features/participants-pane/components/native/ContextMenuLobbyParticipantReject.js @@ -3,7 +3,7 @@ import React, { useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { TouchableOpacity, View } from 'react-native'; -import { Divider, Text } from 'react-native-paper'; +import { Text } from 'react-native-paper'; import { useDispatch, useSelector } from 'react-redux'; import { Avatar } from '../../../base/avatar'; @@ -33,30 +33,33 @@ const ContextMenuLobbyParticipantReject = ({ participant: p }: Props) => { const reject = useCallback(() => dispatch(setKnockingParticipantApproval(p.id, false), [ dispatch ])); const { t } = useTranslation(); + // eslint-disable-next-line react/no-multi-comp + const renderMenuHeader = () => ( + + + + { displayName } + + + ); + return ( - - - - - { displayName } - - - - { t('lobby.reject') } diff --git a/react/features/participants-pane/components/native/ContextMenuMeetingParticipantDetails.js b/react/features/participants-pane/components/native/ContextMenuMeetingParticipantDetails.js deleted file mode 100644 index 8ef0c2d4b..000000000 --- a/react/features/participants-pane/components/native/ContextMenuMeetingParticipantDetails.js +++ /dev/null @@ -1,264 +0,0 @@ -// @flow - -import React, { useCallback } from 'react'; -import { useTranslation } from 'react-i18next'; -import { TouchableOpacity, View } from 'react-native'; -import { Divider, Text } from 'react-native-paper'; -import { useDispatch } from 'react-redux'; - -import { Avatar } from '../../../base/avatar'; -import { hideDialog, openDialog } from '../../../base/dialog/actions'; -import BottomSheet from '../../../base/dialog/components/native/BottomSheet'; -import { - Icon, IconCloseCircle, IconMessage, - IconMicrophoneEmptySlash, - IconMuteEveryoneElse, IconVideoOff -} from '../../../base/icons'; -import { - getLocalParticipant, - getParticipantByIdOrUndefined, - getParticipantDisplayName, getRemoteParticipants, - isLocalParticipantModerator -} from '../../../base/participants/functions'; -import { connect } from '../../../base/redux'; -import { - isParticipantAudioMuted, - isParticipantVideoMuted -} from '../../../base/tracks/functions'; -import { openChat } from '../../../chat/actions.native'; -import { - KickRemoteParticipantDialog, - MuteEveryoneDialog, - MuteRemoteParticipantDialog, - MuteRemoteParticipantsVideoDialog -} from '../../../video-menu'; -import VolumeSlider from '../../../video-menu/components/native/VolumeSlider'; - -import styles from './styles'; - -type Props = { - - /** - * The display name of the participant. - */ - _displayName: string, - - /** - * True if the local participant is moderator and false otherwise. - */ - _isLocalModerator: boolean, - - /** - * True if the participant is moderator and false otherwise. - */ - _isParticipantModerator: boolean, - - /** - * True if the participant is video muted and false otherwise. - */ - _isParticipantVideoMuted: boolean, - - /** - * True if the participant is audio muted and false otherwise. - */ - _isParticipantAudioMuted: boolean, - - /** - * Whether the participant is present in the room or not. - */ - _isParticipantIDAvailable?: boolean, - - /** - * Participant reference - */ - _participant: Object, - - /** - * The ID of the participant. - */ - participantID: string, -}; - -const ContextMenuMeetingParticipantDetails = ( - { - _displayName, - _isLocalModerator, - _isParticipantVideoMuted, - _isParticipantAudioMuted, - _participant, - _isParticipantIDAvailable, - participantID - }: Props) => { - const dispatch = useDispatch(); - const cancel = useCallback(() => dispatch(hideDialog()), [ dispatch ]); - const kickRemoteParticipant = useCallback(() => { - dispatch(openDialog(KickRemoteParticipantDialog, { - participantID - })); - }, [ dispatch, participantID ]); - const muteAudio = useCallback(() => { - dispatch(openDialog(MuteRemoteParticipantDialog, { - participantID - })); - }, [ dispatch, participantID ]); - const muteEveryoneElse = useCallback(() => { - dispatch(openDialog(MuteEveryoneDialog, { - exclude: [ participantID ] - })); - }, [ dispatch, participantID ]); - const muteVideo = useCallback(() => { - dispatch(openDialog(MuteRemoteParticipantsVideoDialog, { - participantID - })); - }, [ dispatch, participantID ]); - - const sendPrivateMessage = useCallback(() => { - dispatch(hideDialog()); - dispatch(openChat(_participant)); - }, [ dispatch, _participant ]); - const { t } = useTranslation(); - - return ( - - - - - - { _displayName } - - - - - { - _isLocalModerator && ( - <> - { - !_isParticipantAudioMuted - && - - - { t('participantsPane.actions.mute') } - - - } - - - - - { t('participantsPane.actions.muteEveryoneElse') } - - - - ) - } - - { - _isLocalModerator && ( - <> - { - !_isParticipantVideoMuted - && - - - { t('participantsPane.actions.stopVideo') } - - - } - - - - - { t('videothumbnail.kick') } - - - - ) - } - - - - { t('toolbar.accessibilityLabel.privateMessage') } - - - {/* We need design specs for this*/} - {/* */} - {/* */} - {/* { t('participantsPane.actions.networkStats') }*/} - {/* */} - - - - ); -}; - - -/** - * Maps (parts of) the redux state to the associated props for this component. - * - * @param {Object} state - The Redux state. - * @param {Object} ownProps - The own props of the component. - * @private - * @returns {Props} - */ -function _mapStateToProps(state, ownProps): Object { - const { participantID } = ownProps; - const participantIDS = []; - - const participant = getParticipantByIdOrUndefined(state, participantID); - const _isLocalModerator = isLocalParticipantModerator(state); - const _isParticipantVideoMuted = isParticipantVideoMuted(participant, state); - const _isParticipantAudioMuted = isParticipantAudioMuted(participant, state); - const localParticipant = getLocalParticipant(state); - const remoteParticipants = getRemoteParticipants(state); - - localParticipant && participantIDS.push(localParticipant?.id); - - remoteParticipants.forEach(p => { - participantIDS.push(p?.id); - }); - - const isParticipantIDAvailable = participantIDS.find(partID => partID === participantID); - - return { - _displayName: getParticipantDisplayName(state, participantID), - _isLocalModerator, - _isParticipantAudioMuted, - _isParticipantIDAvailable: Boolean(isParticipantIDAvailable), - _isParticipantVideoMuted, - _participant: participant - }; -} - -export default connect(_mapStateToProps)(ContextMenuMeetingParticipantDetails); diff --git a/react/features/participants-pane/components/native/ContextMenuMore.js b/react/features/participants-pane/components/native/ContextMenuMore.js index f2636be4c..ba3ed8eaf 100644 --- a/react/features/participants-pane/components/native/ContextMenuMore.js +++ b/react/features/participants-pane/components/native/ContextMenuMore.js @@ -9,14 +9,13 @@ import { useDispatch, useSelector } from 'react-redux'; import { openDialog, hideDialog } from '../../../base/dialog/actions'; import BottomSheet from '../../../base/dialog/components/native/BottomSheet'; import { - Icon, IconMicDisabledHollow, + Icon, IconVideoOff } from '../../../base/icons'; import { getLocalParticipant, getParticipantCount } from '../../../base/participants'; -import { BlockAudioVideoDialog } from '../../../video-menu'; import MuteEveryonesVideoDialog from '../../../video-menu/components/native/MuteEveryonesVideoDialog'; @@ -24,7 +23,6 @@ import styles from './styles'; export const ContextMenuMore = () => { const dispatch = useDispatch(); - const blockAudioVideo = useCallback(() => dispatch(openDialog(BlockAudioVideoDialog)), [ dispatch ]); const cancel = useCallback(() => dispatch(hideDialog()), [ dispatch ]); const { id } = useSelector(getLocalParticipant); const participantsCount = useSelector(getParticipantCount); @@ -45,21 +43,10 @@ export const ContextMenuMore = () => { onPress = { muteAllVideo } style = { styles.contextMenuItem }> {t('participantsPane.actions.stopEveryonesVideo')} - - - - {t('participantsPane.actions.blockEveryoneMicCamera')} - - ); }; diff --git a/react/features/participants-pane/components/native/MeetingParticipantList.js b/react/features/participants-pane/components/native/MeetingParticipantList.js index f3ad6995c..94de39c2d 100644 --- a/react/features/participants-pane/components/native/MeetingParticipantList.js +++ b/react/features/participants-pane/components/native/MeetingParticipantList.js @@ -13,7 +13,7 @@ import { getRemoteParticipants } from '../../../base/participants'; import { doInvitePeople } from '../../../invite/actions.native'; -import { showContextMenuDetails } from '../../actions.native'; +import { showConnectionStatus, showContextMenuDetails } from '../../actions.native'; import { shouldRenderInviteButton } from '../../functions'; import MeetingParticipantItem from './MeetingParticipantItem'; @@ -31,11 +31,11 @@ export const MeetingParticipantList = () => { // eslint-disable-next-line react/no-multi-comp const renderParticipant = p => ( - !p.local && dispatch(showContextMenuDetails(p.id)) } + /* eslint-disable-next-line react/jsx-no-bind,no-confusing-arrow */ + onPress = { () => p.local + ? dispatch(showConnectionStatus(p.id)) : dispatch(showContextMenuDetails(p)) } participantID = { p.id } /> ); diff --git a/react/features/participants-pane/components/native/index.js b/react/features/participants-pane/components/native/index.js index 425247373..88a90cb8a 100644 --- a/react/features/participants-pane/components/native/index.js +++ b/react/features/participants-pane/components/native/index.js @@ -3,4 +3,3 @@ export { default as ParticipantsPane } from './ParticipantsPane'; export { default as ParticipantsPaneButton } from './ParticipantsPaneButton'; export { default as ContextMenuLobbyParticipantReject } from './ContextMenuLobbyParticipantReject'; -export { default as ContextMenuMeetingParticipantDetails } from './ContextMenuMeetingParticipantDetails'; diff --git a/react/features/participants-pane/components/native/styles.js b/react/features/participants-pane/components/native/styles.js index 6a66daa9b..2ae30d177 100644 --- a/react/features/participants-pane/components/native/styles.js +++ b/react/features/participants-pane/components/native/styles.js @@ -145,7 +145,7 @@ export default { display: 'flex', flexDirection: 'row', overflow: 'hidden', - paddingLeft: BaseTheme.spacing[2], + paddingLeft: BaseTheme.spacing[3], width: '63%' }, @@ -187,6 +187,7 @@ export default { ...flexContent, top: BaseTheme.spacing[1] }, + lobbyList: { position: 'relative' }, @@ -277,12 +278,7 @@ export default { }, contextMenuMore: { - backgroundColor: BaseTheme.palette.action02, - borderRadius: BaseTheme.shape.borderRadius - }, - - contextMenuMeetingParticipantDetails: { - backgroundColor: BaseTheme.palette.action02, + backgroundColor: BaseTheme.palette.bottomSheet, borderRadius: BaseTheme.shape.borderRadius }, @@ -303,8 +299,6 @@ export default { marginHorizontal: BaseTheme.spacing[0], paddingTop: 12, paddingBottom: 12, - paddingRight: BaseTheme.spacing[3], - paddingLeft: BaseTheme.spacing[3], textTransform: 'capitalize', width: 94 }, @@ -318,13 +312,15 @@ export default { }, contextMenuItemSectionAvatar: { - ...contextMenuItem, - marginLeft: BaseTheme.spacing[3] - }, - - contextMenuItemAvatarText: { - ...contextMenuItemText, - marginLeft: BaseTheme.spacing[3] + alignItems: 'center', + backgroundColor: BaseTheme.palette.bottomSheet, + borderBottomColor: BaseTheme.palette.dividerColor, + borderBottomWidth: 1, + borderTopLeftRadius: BaseTheme.spacing[3], + borderTopRightRadius: BaseTheme.spacing[3], + flexDirection: 'row', + height: BaseTheme.spacing[7], + paddingLeft: BaseTheme.spacing[3] }, contextMenuItemText: { @@ -333,15 +329,14 @@ export default { }, contextMenuItemName: { - ...BaseTheme.typography.bodyShortRegularLarge, - color: BaseTheme.palette.text01 - }, - - contextMenuIcon: { - color: BaseTheme.palette.actionDanger + color: BaseTheme.palette.text04, + flexShrink: 1, + fontSize: BaseTheme.spacing[3], + marginLeft: BaseTheme.spacing[3], + opacity: 0.90 }, divider: { - backgroundColor: BaseTheme.palette.section01 + backgroundColor: BaseTheme.palette.dividerColor } }; diff --git a/react/features/video-menu/components/AbstractKickButton.js b/react/features/video-menu/components/AbstractKickButton.js index 51701e00e..10c475e26 100644 --- a/react/features/video-menu/components/AbstractKickButton.js +++ b/react/features/video-menu/components/AbstractKickButton.js @@ -1,7 +1,7 @@ // @flow import { openDialog } from '../../base/dialog'; -import { IconKick } from '../../base/icons'; +import { IconCloseCircle } from '../../base/icons'; import { AbstractButton, type AbstractButtonProps } from '../../base/toolbox/components'; import { KickRemoteParticipantDialog } from '.'; @@ -29,7 +29,7 @@ export type Props = AbstractButtonProps & { */ export default class AbstractKickButton extends AbstractButton { accessibilityLabel = 'toolbar.accessibilityLabel.kick'; - icon = IconKick; + icon = IconCloseCircle; label = 'videothumbnail.kick'; /** diff --git a/react/features/video-menu/components/AbstractMuteVideoButton.js b/react/features/video-menu/components/AbstractMuteVideoButton.js index 1b72a2383..151865cbb 100644 --- a/react/features/video-menu/components/AbstractMuteVideoButton.js +++ b/react/features/video-menu/components/AbstractMuteVideoButton.js @@ -5,7 +5,7 @@ import { sendAnalytics } from '../../analytics'; import { openDialog } from '../../base/dialog'; -import { IconCameraDisabled } from '../../base/icons'; +import { IconVideoOff } from '../../base/icons'; import { MEDIA_TYPE } from '../../base/media'; import { AbstractButton, type AbstractButtonProps } from '../../base/toolbox/components'; import { isRemoteTrackMuted } from '../../base/tracks'; @@ -42,7 +42,7 @@ export type Props = AbstractButtonProps & { */ export default class AbstractMuteVideoButton extends AbstractButton { accessibilityLabel = 'toolbar.accessibilityLabel.remoteVideoMute'; - icon = IconCameraDisabled; + icon = IconVideoOff; label = 'videothumbnail.domuteVideo'; toggledLabel = 'videothumbnail.videoMuted'; diff --git a/react/features/video-menu/components/native/ConnectionStatusComponent.js b/react/features/video-menu/components/native/ConnectionStatusComponent.js index 4396f552c..494950912 100644 --- a/react/features/video-menu/components/native/ConnectionStatusComponent.js +++ b/react/features/video-menu/components/native/ConnectionStatusComponent.js @@ -2,6 +2,8 @@ import React, { Component } from 'react'; import { Text, View } from 'react-native'; +import { withTheme } from 'react-native-paper'; + import { Avatar } from '../../../base/avatar'; import { ColorSchemeRegistry } from '../../../base/color-scheme'; @@ -11,7 +13,7 @@ import { IconArrowDownLarge, IconArrowUpLarge } from '../../../base/icons'; import { getParticipantDisplayName } from '../../../base/participants'; import { BaseIndicator } from '../../../base/react'; import { connect } from '../../../base/redux'; -import { StyleType, ColorPalette } from '../../../base/styles'; +import { StyleType } from '../../../base/styles'; import statsEmitter from '../../../connection-indicator/statsEmitter'; import styles from './styles'; @@ -57,7 +59,12 @@ export type Props = { /** * The function to be used to translate i18n labels. */ - t: Function + t: Function, + + /** + * Theme used for styles. + */ + theme: Object } /** @@ -116,7 +123,8 @@ class ConnectionStatusComponent extends Component { * @returns {React$Node} */ render(): React$Node { - const { t } = this.props; + const { t, theme } = this.props; + const { palette } = theme; return ( { { this.state.downloadString } @@ -146,7 +154,7 @@ class ConnectionStatusComponent extends Component { { `${this.state.uploadString} Kbps` } @@ -159,7 +167,7 @@ class ConnectionStatusComponent extends Component { { this.state.packetLostDownloadString } @@ -167,7 +175,7 @@ class ConnectionStatusComponent extends Component { { this.state.packetLostUploadString } @@ -426,6 +434,6 @@ function _mapStateToProps(state, ownProps) { }; } -ConnectionStatusComponent_ = translate(connect(_mapStateToProps)(ConnectionStatusComponent)); +ConnectionStatusComponent_ = translate(connect(_mapStateToProps)(withTheme(ConnectionStatusComponent))); export default ConnectionStatusComponent_; diff --git a/react/features/video-menu/components/native/MuteVideoButton.js b/react/features/video-menu/components/native/MuteVideoButton.js new file mode 100644 index 000000000..ab78d33c2 --- /dev/null +++ b/react/features/video-menu/components/native/MuteVideoButton.js @@ -0,0 +1,22 @@ +// @flow + +import { translate } from '../../../base/i18n'; +import { isLocalParticipantModerator } from '../../../base/participants'; +import { connect } from '../../../base/redux'; +import AbstractMuteVideoButton, { _mapStateToProps as _abstractMapStateToProps } from '../AbstractMuteVideoButton'; + +/** + * Maps part of the Redux state to the props of this component. + * + * @param {Object} state - The Redux state. + * @param {Object} ownProps - Properties of component. + * @returns {Props} + */ +function _mapStateToProps(state, ownProps) { + return { + ..._abstractMapStateToProps(state, ownProps), + visible: isLocalParticipantModerator(state) + }; +} + +export default translate(connect(_mapStateToProps)(AbstractMuteVideoButton)); diff --git a/react/features/video-menu/components/native/PinButton.js b/react/features/video-menu/components/native/PinButton.js index 17b6d1ab6..fd3935e9a 100644 --- a/react/features/video-menu/components/native/PinButton.js +++ b/react/features/video-menu/components/native/PinButton.js @@ -59,8 +59,10 @@ class PinButton extends AbstractButton { * @returns {Props} */ function _mapStateToProps(state) { + const { isOpen } = state['features/participants-pane']; + return { - visible: shouldDisplayTileView(state) + visible: !isOpen && shouldDisplayTileView(state) }; } diff --git a/react/features/video-menu/components/native/RemoteVideoMenu.js b/react/features/video-menu/components/native/RemoteVideoMenu.js index 786ba0b4c..84bfa9237 100644 --- a/react/features/video-menu/components/native/RemoteVideoMenu.js +++ b/react/features/video-menu/components/native/RemoteVideoMenu.js @@ -2,29 +2,37 @@ import React, { PureComponent } from 'react'; import { Text, View } from 'react-native'; +import { Divider } from 'react-native-paper'; import { Avatar } from '../../../base/avatar'; import { ColorSchemeRegistry } from '../../../base/color-scheme'; import { BottomSheet, isDialogOpen } from '../../../base/dialog'; import { KICK_OUT_ENABLED, getFeatureFlag } from '../../../base/flags'; -import { getParticipantDisplayName } from '../../../base/participants'; +import { + getParticipantById, + getParticipantDisplayName +} from '../../../base/participants'; import { connect } from '../../../base/redux'; import { StyleType } from '../../../base/styles'; import { PrivateMessageButton } from '../../../chat'; import { hideRemoteVideoMenu } from '../../actions.native'; +import ConnectionStatusButton from '../native/ConnectionStatusButton'; -import ConnectionStatusButton from './ConnectionStatusButton'; import GrantModeratorButton from './GrantModeratorButton'; import KickButton from './KickButton'; import MuteButton from './MuteButton'; import MuteEveryoneElseButton from './MuteEveryoneElseButton'; +import MuteVideoButton from './MuteVideoButton'; import PinButton from './PinButton'; import styles from './styles'; +// import VolumeSlider from './VolumeSlider'; + + /** * Size of the rendered avatar in the menu. */ -const AVATAR_SIZE = 25; +const AVATAR_SIZE = 24; type Props = { @@ -63,10 +71,20 @@ type Props = { */ _isOpen: boolean, + /** + * Whether the participant is present in the room or not. + */ + _isParticipantAvailable?: boolean, + /** * Display name of the participant retrieved from Redux. */ - _participantDisplayName: string + _participantDisplayName: string, + + /** + * The ID of the participant. + */ + _participantID: ?string, } // eslint-disable-next-line prefer-const @@ -94,7 +112,13 @@ class RemoteVideoMenu extends PureComponent { * @inheritdoc */ render() { - const { _disableKick, _disableRemoteMute, _disableGrantModerator, participant } = this.props; + const { + _disableKick, + _disableRemoteMute, + _disableGrantModerator, + _isParticipantAvailable, + participant + } = this.props; const buttonProps = { afterClick: this._onCancel, showLabel: true, @@ -105,14 +129,19 @@ class RemoteVideoMenu extends PureComponent { return ( + renderHeader = { this._renderMenuHeader } + showSlidingView = { _isParticipantAvailable }> { !_disableRemoteMute && } + + { !_disableRemoteMute && } + { !_disableKick && } { !_disableGrantModerator && } - + {/* */} + {/* */} ); } @@ -173,6 +202,7 @@ function _mapStateToProps(state, ownProps) { const kickOutEnabled = getFeatureFlag(state, KICK_OUT_ENABLED, true); const { participant } = ownProps; const { remoteVideoMenu = {}, disableRemoteMute } = state['features/base/config']; + const isParticipantAvailable = getParticipantById(state, participant.id); let { disableKick } = remoteVideoMenu; disableKick = disableKick || !kickOutEnabled; @@ -182,7 +212,9 @@ function _mapStateToProps(state, ownProps) { _disableKick: Boolean(disableKick), _disableRemoteMute: Boolean(disableRemoteMute), _isOpen: isDialogOpen(state, RemoteVideoMenu_), - _participantDisplayName: getParticipantDisplayName(state, participant.id) + _isParticipantAvailable: Boolean(isParticipantAvailable), + _participantDisplayName: getParticipantDisplayName(state, participant.id), + _participantID: participant.id }; } diff --git a/react/features/video-menu/components/native/VolumeSlider.js b/react/features/video-menu/components/native/VolumeSlider.js index 3f875e527..239173b68 100644 --- a/react/features/video-menu/components/native/VolumeSlider.js +++ b/react/features/video-menu/components/native/VolumeSlider.js @@ -7,7 +7,6 @@ import { View } from 'react-native'; import { withTheme } from 'react-native-paper'; import { Icon, IconVolumeEmpty } from '../../../base/icons'; -import { getLocalParticipant } from '../../../base/participants'; import { connect } from '../../../base/redux'; import { setVolume } from '../../../participants-pane/actions.native'; import { VOLUME_SLIDER_SCALE } from '../../constants'; @@ -102,7 +101,7 @@ class VolumeSlider extends PureComponent { return (