feat(native-participants-pane) context menu for meeting participant

This commit is contained in:
Calin Chitu 2021-06-04 18:07:18 +03:00 committed by Hristo Terezov
parent 47be509d17
commit 0b3991d9e1
8 changed files with 143 additions and 24 deletions

View File

@ -1,13 +1,24 @@
import { openDialog } from '../base/dialog';
import { ContextMenuReject } from './components/native/ContextMenuReject';
import { ContextMenuLobbyParticipantReject, ContextMenuMeetingParticipantDetails } from './components/native';
/**
* Displays the context menu for the selected lobby participant.
*
* @param {string} participant - The selected participant's id.
* @param {Object} participant - The selected lobby participant.
* @returns {Function}
*/
export function showContextMenuReject(participant) {
return openDialog(ContextMenuReject, { participant });
return openDialog(ContextMenuLobbyParticipantReject, { participant });
}
/**
* Displays the context menu for the selected meeting participant.
*
* @param {Object} participant - The selected meeting participant.
* @returns {Function}
*/
export function showContextMenuDetails(participant) {
return openDialog(ContextMenuMeetingParticipantDetails, { participant });
}

View File

@ -23,7 +23,7 @@ type Props = {
participant: Object
};
export const ContextMenuReject = ({ participant: p }: Props) => {
export const ContextMenuLobbyParticipantReject = ({ participant: p }: Props) => {
const dispatch = useDispatch();
const cancel = useCallback(() => dispatch(hideDialog()), [ dispatch ]);
const displayName = p.name;
@ -35,23 +35,24 @@ export const ContextMenuReject = ({ participant: p }: Props) => {
onCancel = { cancel }
style = { styles.contextMenuMore }>
<View
style = { styles.contextMenuItemDetails }>
style = { styles.contextMenuItemSection }>
<Avatar
className = 'participant-avatar'
participantId = { p.id }
size = { 32 } />
<View style = { styles.contextMenuItemText }>
<Text style = { styles.contextMenuItemParticipantName }>
<Text style = { styles.contextMenuItemName }>
{ displayName }
</Text>
</View>
</View>
<TouchableOpacity
onPress = { reject }
style = { styles.contextMenuItemReject }>
style = { styles.contextMenuItem }>
<Icon
size = { 24 }
src = { IconClose } />
src = { IconClose }
style = { styles.contextMenuItemIcon } />
<Text style = { styles.contextMenuItemText }>{ t('lobby.reject') }</Text>
</TouchableOpacity>
</BottomSheet>

View File

@ -0,0 +1,105 @@
// @flow
import React, { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { TouchableOpacity, View } from 'react-native';
import { Text } from 'react-native-paper';
import { useDispatch } from 'react-redux';
import { Avatar } from '../../../base/avatar';
import { hideDialog } from '../../../base/dialog';
import BottomSheet from '../../../base/dialog/components/native/BottomSheet';
import {
Icon, IconCloseCircle, IconConnectionActive, IconMessage,
IconMicrophoneEmptySlash,
IconMuteEveryoneElse, IconVideoOff
} from '../../../base/icons';
import { MEDIA_TYPE } from '../../../base/media';
import { muteRemote } from '../../../video-menu/actions.any';
import styles from './styles';
type Props = {
/**
* Participant reference
*/
participant: Object
};
export const ContextMenuMeetingParticipantDetails = ({ participant: p }: Props) => {
const dispatch = useDispatch();
const cancel = useCallback(() => dispatch(hideDialog()), [ dispatch ]);
const displayName = p.name;
const muteAudio = useCallback(() => dispatch(muteRemote(p.id, MEDIA_TYPE.AUDIO)), [ dispatch ]);
const { t } = useTranslation();
return (
<BottomSheet
onCancel = { cancel }
style = { styles.contextMenuMore }>
<View
style = { styles.contextMenuItemSection }>
<Avatar
className = 'participant-avatar'
participantId = { p.id }
size = { 32 } />
<View style = { styles.contextMenuItemText }>
<Text style = { styles.contextMenuItemName }>
{ displayName }
</Text>
</View>
</View>
<TouchableOpacity
onPress = { muteAudio }
style = { styles.contextMenuItem }>
<Icon
size = { 24 }
src = { IconMicrophoneEmptySlash }
style = { styles.contextMenuItemIcon } />
<Text style = { styles.contextMenuItemText }>{ t('participantsPane.actions.mute') }</Text>
</TouchableOpacity>
<TouchableOpacity
onPress = { muteAudio }
style = { styles.contextMenuItem }>
<Icon
size = { 24 }
src = { IconMuteEveryoneElse }
style = { styles.contextMenuItemIcon } />
<Text style = { styles.contextMenuItemText }>{ t('participantsPane.actions.muteEveryoneElse') }</Text>
</TouchableOpacity>
<TouchableOpacity
style = { styles.contextMenuItemSection }>
<Icon
size = { 24 }
src = { IconVideoOff }
style = { styles.contextMenuItemIcon } />
<Text style = { styles.contextMenuItemText }>{ t('participantsPane.actions.stopVideo') }</Text>
</TouchableOpacity>
<TouchableOpacity
style = { styles.contextMenuItem }>
<Icon
size = { 24 }
src = { IconCloseCircle }
style = { styles.contextMenuItemIcon } />
<Text style = { styles.contextMenuItemText }>{ t('videothumbnail.kick') }</Text>
</TouchableOpacity>
<TouchableOpacity
style = { styles.contextMenuItem }>
<Icon
size = { 24 }
src = { IconMessage }
style = { styles.contextMenuItemIcon } />
<Text style = { styles.contextMenuItemText }>{ t('toolbar.accessibilityLabel.privateMessage') }</Text>
</TouchableOpacity>
<TouchableOpacity
style = { styles.contextMenuItemSection }>
<Icon
size = { 24 }
src = { IconConnectionActive }
style = { styles.contextMenuItemIcon } />
<Text style = { styles.contextMenuItemText }>{ t('participantsPane.actions.networkStats') }</Text>
</TouchableOpacity>
</BottomSheet>
);
};

View File

@ -41,14 +41,14 @@ export const ContextMenuMore = ({ exclude }: Props) => {
style = { styles.contextMenuMore }>
<TouchableOpacity
onPress = { muteEveryoneVideo }
style = { styles.contextMenuItemMuteVideo }>
style = { styles.contextMenuItem }>
<Icon
size = { 24 }
src = { IconVideoOff } />
<Text style = { styles.contextMenuItemText }>{t('participantsPane.actions.stopEveryonesVideo')}</Text>
</TouchableOpacity>
<TouchableOpacity
style = { styles.contextMenuItemDontAllowUnmute }>
style = { styles.contextMenuItem }>
<Icon
size = { 24 }
src = { IconMicDisabledHollow }

View File

@ -1,12 +1,13 @@
// @flow
import React from 'react';
import { useSelector } from 'react-redux';
import React, { useCallback } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import {
getIsParticipantAudioMuted,
getIsParticipantVideoMuted
} from '../../../base/tracks';
import { showContextMenuDetails } from '../../actions.native';
import { MediaState } from '../../constants';
import ParticipantItem from './ParticipantItem';
@ -21,13 +22,16 @@ type Props = {
};
export const MeetingParticipantItem = ({ participant: p }: Props) => {
const dispatch = useDispatch();
const isAudioMuted = useSelector(getIsParticipantAudioMuted(p));
const isVideoMuted = useSelector(getIsParticipantVideoMuted(p));
const openContextMenuDetails = useCallback(() => dispatch(showContextMenuDetails(p), [ dispatch ]));
return (
<ParticipantItem
audioMuteState = { isAudioMuted ? MediaState.Muted : MediaState.Unmuted }
name = { p.name }
onPress = { openContextMenuDetails }
participant = { p }
videoMuteState = { isVideoMuted ? MediaState.Muted : MediaState.Unmuted } />
);

View File

@ -2,3 +2,5 @@
export { default as ParticipantsPane } from './ParticipantsPane';
export { default as ParticipantsPaneButton } from './ParticipantsPaneButton';
export { ContextMenuLobbyParticipantReject } from './ContextMenuLobbyParticipantReject';
export { ContextMenuMeetingParticipantDetails } from './ContextMenuMeetingParticipantDetails';

View File

@ -287,33 +287,29 @@ export default {
textTransform: 'capitalize'
},
contextMenuItemMuteVideo: {
contextMenuItem: {
...contextMenuItem
},
contextMenuItemDontAllowUnmute: {
...contextMenuItem
},
contextMenuItemDetails: {
contextMenuItemSection: {
...contextMenuItem,
borderBottomColor: BaseTheme.palette.section01,
borderBottomWidth: 1
},
contextMenuItemReject: {
...contextMenuItem
},
contextMenuItemText: {
...BaseTheme.typography.bodyShortRegularLarge,
alignSelf: 'center',
color: BaseTheme.palette.text01,
flexDirection: 'row',
marginLeft: 8
marginLeft: BaseTheme.spacing[3]
},
contextMenuItemParticipantName: {
contextMenuItemIcon: {
marginLeft: BaseTheme.spacing[1]
},
contextMenuItemName: {
...BaseTheme.typography.bodyShortRegularLarge,
color: BaseTheme.palette.text01
},