feat(native-participants-pane) implemented review remarks pt.4

This commit is contained in:
Calin Chitu 2021-07-06 22:07:52 +03:00 committed by Hristo Terezov
parent eeddf6b350
commit b7389e1c31
9 changed files with 70 additions and 59 deletions

View File

@ -9,3 +9,16 @@
export function getLobbyState(state: any) { export function getLobbyState(state: any) {
return state['features/lobby']; return state['features/lobby'];
} }
/**
* Selector to return lobby state.
*
* @param {any} state - State object.
* @returns {Array}
*/
export function getKnockingParticipantsById(state: any) {
const { knockingParticipants } = state['features/lobby'];
return knockingParticipants.map(participant => participant.id);
}

View File

@ -4,7 +4,7 @@ import React, { useCallback } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { TouchableOpacity, View } from 'react-native'; import { TouchableOpacity, View } from 'react-native';
import { Divider, Text } from 'react-native-paper'; import { Divider, Text } from 'react-native-paper';
import { useDispatch } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { Avatar } from '../../../base/avatar'; import { Avatar } from '../../../base/avatar';
import { hideDialog } from '../../../base/dialog'; import { hideDialog } from '../../../base/dialog';
@ -13,6 +13,7 @@ import {
Icon, IconClose Icon, IconClose
} from '../../../base/icons'; } from '../../../base/icons';
import { setKnockingParticipantApproval } from '../../../lobby/actions.native'; import { setKnockingParticipantApproval } from '../../../lobby/actions.native';
import { getKnockingParticipantsById } from '../../../lobby/functions';
import styles from './styles'; import styles from './styles';
type Props = { type Props = {
@ -25,6 +26,8 @@ type Props = {
export const ContextMenuLobbyParticipantReject = ({ participant: p }: Props) => { export const ContextMenuLobbyParticipantReject = ({ participant: p }: Props) => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const knockParticipantsIDArr = useSelector(getKnockingParticipantsById);
const knockParticipantIsAvailable = knockParticipantsIDArr.find(knockPartId => knockPartId === p.id);
const cancel = useCallback(() => dispatch(hideDialog()), [ dispatch ]); const cancel = useCallback(() => dispatch(hideDialog()), [ dispatch ]);
const displayName = p.name; const displayName = p.name;
const reject = useCallback(() => dispatch(setKnockingParticipantApproval(p.id, false), [ dispatch ])); const reject = useCallback(() => dispatch(setKnockingParticipantApproval(p.id, false), [ dispatch ]));
@ -32,14 +35,16 @@ export const ContextMenuLobbyParticipantReject = ({ participant: p }: Props) =>
return ( return (
<BottomSheet <BottomSheet
addScrollViewPadding = { false }
onCancel = { cancel } onCancel = { cancel }
showSlidingView = { Boolean(knockParticipantIsAvailable) }
style = { styles.contextMenuMore }> style = { styles.contextMenuMore }>
<View <View
style = { styles.contextMenuItemSectionAvatar }> style = { styles.contextMenuItemSectionAvatar }>
<Avatar <Avatar
className = 'participant-avatar' className = 'participant-avatar'
participantId = { p.id } participantId = { p.id }
size = { 30 } /> size = { 20 } />
<View style = { styles.contextMenuItemAvatarText }> <View style = { styles.contextMenuItemAvatarText }>
<Text style = { styles.contextMenuItemName }> <Text style = { styles.contextMenuItemName }>
{ displayName } { displayName }
@ -51,9 +56,8 @@ export const ContextMenuLobbyParticipantReject = ({ participant: p }: Props) =>
onPress = { reject } onPress = { reject }
style = { styles.contextMenuItem }> style = { styles.contextMenuItem }>
<Icon <Icon
size = { 24 } size = { 20 }
src = { IconClose } src = { IconClose } />
style = { styles.contextMenuItemIcon } />
<Text style = { styles.contextMenuItemText }>{ t('lobby.reject') }</Text> <Text style = { styles.contextMenuItemText }>{ t('lobby.reject') }</Text>
</TouchableOpacity> </TouchableOpacity>
</BottomSheet> </BottomSheet>

View File

@ -15,6 +15,7 @@ import {
IconMuteEveryoneElse, IconVideoOff IconMuteEveryoneElse, IconVideoOff
} from '../../../base/icons'; } from '../../../base/icons';
import { import {
getParticipantsById,
isLocalParticipantModerator isLocalParticipantModerator
} from '../../../base/participants'; } from '../../../base/participants';
import { getIsParticipantVideoMuted } from '../../../base/tracks'; import { getIsParticipantVideoMuted } from '../../../base/tracks';
@ -39,11 +40,12 @@ type Props = {
export const ContextMenuMeetingParticipantDetails = ({ participant: p }: Props) => { export const ContextMenuMeetingParticipantDetails = ({ participant: p }: Props) => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const participantsIDArr = useSelector(getParticipantsById);
const participantIsAvailable = participantsIDArr.find(partId => partId === p.id);
const cancel = useCallback(() => dispatch(hideDialog()), [ dispatch ]); const cancel = useCallback(() => dispatch(hideDialog()), [ dispatch ]);
const displayName = p.name; const displayName = p.name;
const isLocalModerator = useSelector(isLocalParticipantModerator); const isLocalModerator = useSelector(isLocalParticipantModerator);
const isParticipantVideoMuted = useSelector(getIsParticipantVideoMuted(p)); const isParticipantVideoMuted = useSelector(getIsParticipantVideoMuted(p));
const kickRemoteParticipant = useCallback(() => { const kickRemoteParticipant = useCallback(() => {
dispatch(openDialog(KickRemoteParticipantDialog, { dispatch(openDialog(KickRemoteParticipantDialog, {
participantID: p.id participantID: p.id
@ -73,14 +75,16 @@ export const ContextMenuMeetingParticipantDetails = ({ participant: p }: Props)
return ( return (
<BottomSheet <BottomSheet
addScrollViewPadding = { false }
onCancel = { cancel } onCancel = { cancel }
showSlidingView = { Boolean(participantIsAvailable) }
style = { styles.contextMenuMeetingParticipantDetails }> style = { styles.contextMenuMeetingParticipantDetails }>
<View <View
style = { styles.contextMenuItemSectionAvatar }> style = { styles.contextMenuItemSectionAvatar }>
<Avatar <Avatar
className = 'participant-avatar' className = 'participant-avatar'
participantId = { p.id } participantId = { p.id }
size = { 30 } /> size = { 20 } />
<View style = { styles.contextMenuItemAvatarText }> <View style = { styles.contextMenuItemAvatarText }>
<Text style = { styles.contextMenuItemName }> <Text style = { styles.contextMenuItemName }>
{ displayName } { displayName }
@ -94,9 +98,8 @@ export const ContextMenuMeetingParticipantDetails = ({ participant: p }: Props)
onPress = { muteAudio } onPress = { muteAudio }
style = { styles.contextMenuItem }> style = { styles.contextMenuItem }>
<Icon <Icon
size = { 24 } size = { 20 }
src = { IconMicrophoneEmptySlash } src = { IconMicrophoneEmptySlash } />
style = { styles.contextMenuItemIcon } />
<Text style = { styles.contextMenuItemText }> <Text style = { styles.contextMenuItemText }>
{ t('participantsPane.actions.mute') } { t('participantsPane.actions.mute') }
</Text> </Text>
@ -108,9 +111,8 @@ export const ContextMenuMeetingParticipantDetails = ({ participant: p }: Props)
onPress = { muteEveryoneElse } onPress = { muteEveryoneElse }
style = { styles.contextMenuItem }> style = { styles.contextMenuItem }>
<Icon <Icon
size = { 24 } size = { 20 }
src = { IconMuteEveryoneElse } src = { IconMuteEveryoneElse } />
style = { styles.contextMenuItemIcon } />
<Text style = { styles.contextMenuItemText }> <Text style = { styles.contextMenuItemText }>
{ t('participantsPane.actions.muteEveryoneElse') } { t('participantsPane.actions.muteEveryoneElse') }
</Text> </Text>
@ -124,9 +126,8 @@ export const ContextMenuMeetingParticipantDetails = ({ participant: p }: Props)
onPress = { muteVideo } onPress = { muteVideo }
style = { styles.contextMenuItemSection }> style = { styles.contextMenuItemSection }>
<Icon <Icon
size = { 24 } size = { 20 }
src = { IconVideoOff } src = { IconVideoOff } />
style = { styles.contextMenuItemIcon } />
<Text style = { styles.contextMenuItemText }> <Text style = { styles.contextMenuItemText }>
{ t('participantsPane.actions.stopVideo') } { t('participantsPane.actions.stopVideo') }
</Text> </Text>
@ -139,9 +140,8 @@ export const ContextMenuMeetingParticipantDetails = ({ participant: p }: Props)
onPress = { kickRemoteParticipant } onPress = { kickRemoteParticipant }
style = { styles.contextMenuItem }> style = { styles.contextMenuItem }>
<Icon <Icon
size = { 24 } size = { 20 }
src = { IconCloseCircle } src = { IconCloseCircle } />
style = { styles.contextMenuItemIcon } />
<Text style = { styles.contextMenuItemText }> <Text style = { styles.contextMenuItemText }>
{ t('videothumbnail.kick') } { t('videothumbnail.kick') }
</Text> </Text>
@ -151,9 +151,8 @@ export const ContextMenuMeetingParticipantDetails = ({ participant: p }: Props)
onPress = { sendPrivateMessage } onPress = { sendPrivateMessage }
style = { styles.contextMenuItem }> style = { styles.contextMenuItem }>
<Icon <Icon
size = { 24 } size = { 20 }
src = { IconMessage } src = { IconMessage } />
style = { styles.contextMenuItemIcon } />
<Text style = { styles.contextMenuItemText }> <Text style = { styles.contextMenuItemText }>
{ t('toolbar.accessibilityLabel.privateMessage') } { t('toolbar.accessibilityLabel.privateMessage') }
</Text> </Text>

View File

@ -12,7 +12,10 @@ import {
Icon, IconMicDisabledHollow, Icon, IconMicDisabledHollow,
IconVideoOff IconVideoOff
} from '../../../base/icons'; } from '../../../base/icons';
import { getLocalParticipant } from '../../../base/participants'; import {
getLocalParticipant,
getParticipantCount, isEveryoneModerator
} from '../../../base/participants';
import { BlockAudioVideoDialog } from '../../../video-menu'; import { BlockAudioVideoDialog } from '../../../video-menu';
import MuteEveryonesVideoDialog import MuteEveryonesVideoDialog
from '../../../video-menu/components/native/MuteEveryonesVideoDialog'; from '../../../video-menu/components/native/MuteEveryonesVideoDialog';
@ -24,6 +27,9 @@ export const ContextMenuMore = () => {
const blockAudioVideo = useCallback(() => dispatch(openDialog(BlockAudioVideoDialog)), [ dispatch ]); const blockAudioVideo = useCallback(() => dispatch(openDialog(BlockAudioVideoDialog)), [ dispatch ]);
const cancel = useCallback(() => dispatch(hideDialog()), [ dispatch ]); const cancel = useCallback(() => dispatch(hideDialog()), [ dispatch ]);
const { id } = useSelector(getLocalParticipant); const { id } = useSelector(getLocalParticipant);
const everyoneModerator = useSelector(isEveryoneModerator);
const participantsCount = useSelector(getParticipantCount);
const showSlidingView = !everyoneModerator && participantsCount > 2;
const muteAllVideo = useCallback(() => const muteAllVideo = useCallback(() =>
dispatch(openDialog(MuteEveryonesVideoDialog, dispatch(openDialog(MuteEveryonesVideoDialog,
{ exclude: [ id ] })), { exclude: [ id ] })),
@ -32,13 +38,15 @@ export const ContextMenuMore = () => {
return ( return (
<BottomSheet <BottomSheet
addScrollViewPadding = { false }
onCancel = { cancel } onCancel = { cancel }
showSlidingView = { showSlidingView }
style = { styles.contextMenuMore }> style = { styles.contextMenuMore }>
<TouchableOpacity <TouchableOpacity
onPress = { muteAllVideo } onPress = { muteAllVideo }
style = { styles.contextMenuItem }> style = { styles.contextMenuItem }>
<Icon <Icon
size = { 24 } size = { 20 }
src = { IconVideoOff } /> src = { IconVideoOff } />
<Text style = { styles.contextMenuItemText }>{t('participantsPane.actions.stopEveryonesVideo')}</Text> <Text style = { styles.contextMenuItemText }>{t('participantsPane.actions.stopEveryonesVideo')}</Text>
</TouchableOpacity> </TouchableOpacity>
@ -46,7 +54,7 @@ export const ContextMenuMore = () => {
onPress = { blockAudioVideo } onPress = { blockAudioVideo }
style = { styles.contextMenuItem }> style = { styles.contextMenuItem }>
<Icon <Icon
size = { 24 } size = { 20 }
src = { IconMicDisabledHollow } src = { IconMicDisabledHollow }
style = { styles.contextMenuIcon } /> style = { styles.contextMenuIcon } />
<Text style = { styles.contextMenuItemText }> <Text style = { styles.contextMenuItemText }>

View File

@ -34,7 +34,7 @@ export const MeetingParticipantList = () => {
/* eslint-disable-next-line react/jsx-no-bind */ /* eslint-disable-next-line react/jsx-no-bind */
icon = { () => icon = { () =>
(<Icon (<Icon
size = { 24 } size = { 20 }
src = { IconInviteMore } />) src = { IconInviteMore } />)
} }
labelStyle = { styles.inviteLabel } labelStyle = { styles.inviteLabel }

View File

@ -49,7 +49,7 @@ const ParticipantsPane = () => {
/* eslint-disable-next-line react/jsx-no-bind */ /* eslint-disable-next-line react/jsx-no-bind */
icon = { () => icon = { () =>
(<Icon (<Icon
size = { 24 } size = { 20 }
src = { IconClose } />) src = { IconClose } />)
} }
labelStyle = { styles.closeIcon } labelStyle = { styles.closeIcon }
@ -76,7 +76,7 @@ const ParticipantsPane = () => {
/* eslint-disable-next-line react/jsx-no-bind */ /* eslint-disable-next-line react/jsx-no-bind */
icon = { () => icon = { () =>
(<Icon (<Icon
size = { 24 } size = { 20 }
src = { IconHorizontalPoints } />) src = { IconHorizontalPoints } />)
} }
labelStyle = { styles.moreIcon } labelStyle = { styles.moreIcon }

View File

@ -37,6 +37,8 @@ export const button = {
backgroundColor: BaseTheme.palette.action02, backgroundColor: BaseTheme.palette.action02,
borderRadius: BaseTheme.shape.borderRadius, borderRadius: BaseTheme.shape.borderRadius,
display: 'flex', display: 'flex',
flexDirection: 'row',
justifyContent: 'center',
minWidth: 0 minWidth: 0
}; };
@ -62,8 +64,9 @@ const muteAllButton = {
*/ */
const buttonContent = { const buttonContent = {
...BaseTheme.typography.labelButton, ...BaseTheme.typography.labelButton,
alignSelf: 'center', alignContent: 'center',
color: BaseTheme.palette.text01, color: BaseTheme.palette.text01,
display: 'flex',
justifyContent: 'center' justifyContent: 'center'
}; };
@ -71,9 +74,12 @@ const buttonContent = {
* The style of the context menu pane items. * The style of the context menu pane items.
*/ */
const contextMenuItem = { const contextMenuItem = {
alignItems: 'center',
display: 'flex',
flexDirection: 'row', flexDirection: 'row',
paddingBottom: 16, height: BaseTheme.spacing[7],
paddingTop: 16 marginLeft: BaseTheme.spacing[3],
marginTop: BaseTheme.spacing[2]
}; };
/** /**
@ -173,7 +179,7 @@ export default {
backgroundColor: BaseTheme.palette.warning02, backgroundColor: BaseTheme.palette.warning02,
borderRadius: BaseTheme.shape.borderRadius / 2, borderRadius: BaseTheme.shape.borderRadius / 2,
height: BaseTheme.spacing[4], height: BaseTheme.spacing[4],
marginLeft: BaseTheme.spacing[1], marginLeft: BaseTheme.spacing[2],
width: BaseTheme.spacing[4] width: BaseTheme.spacing[4]
}, },
@ -245,11 +251,7 @@ export default {
closeIcon: { closeIcon: {
...buttonContent, ...buttonContent,
height: BaseTheme.spacing[5], height: BaseTheme.spacing[5],
marginLeft: 'auto', marginLeft: 'auto'
paddingTop: 12,
paddingBottom: 12,
paddingRight: BaseTheme.spacing[3],
paddingLeft: BaseTheme.spacing[3]
}, },
inviteButton: { inviteButton: {
@ -271,11 +273,7 @@ export default {
moreIcon: { moreIcon: {
...buttonContent, ...buttonContent,
height: BaseTheme.spacing[5], height: BaseTheme.spacing[5],
marginLeft: 'auto', marginLeft: 'auto'
paddingTop: 12,
paddingBottom: 12,
paddingRight: BaseTheme.spacing[3],
paddingLeft: BaseTheme.spacing[3]
}, },
contextMenuMore: { contextMenuMore: {
@ -300,7 +298,6 @@ export default {
muteAllLabel: { muteAllLabel: {
...BaseTheme.typography.labelButtonLarge, ...BaseTheme.typography.labelButtonLarge,
color: BaseTheme.palette.text01, color: BaseTheme.palette.text01,
flexDirection: 'column',
height: BaseTheme.spacing[7], height: BaseTheme.spacing[7],
marginVertical: BaseTheme.spacing[0], marginVertical: BaseTheme.spacing[0],
marginHorizontal: BaseTheme.spacing[0], marginHorizontal: BaseTheme.spacing[0],
@ -322,12 +319,12 @@ export default {
contextMenuItemSectionAvatar: { contextMenuItemSectionAvatar: {
...contextMenuItem, ...contextMenuItem,
marginLeft: BaseTheme.spacing[1] marginLeft: BaseTheme.spacing[3]
}, },
contextMenuItemAvatarText: { contextMenuItemAvatarText: {
...contextMenuItemText, ...contextMenuItemText,
marginLeft: BaseTheme.spacing[2] marginLeft: BaseTheme.spacing[3]
}, },
contextMenuItemText: { contextMenuItemText: {
@ -335,10 +332,6 @@ export default {
marginLeft: BaseTheme.spacing[3] marginLeft: BaseTheme.spacing[3]
}, },
contextMenuItemIcon: {
marginLeft: BaseTheme.spacing[1]
},
contextMenuItemName: { contextMenuItemName: {
...BaseTheme.typography.bodyShortRegularLarge, ...BaseTheme.typography.bodyShortRegularLarge,
color: BaseTheme.palette.text01 color: BaseTheme.palette.text01

View File

@ -101,9 +101,8 @@ class VolumeSlider extends PureComponent<Props, State> {
return ( return (
<View style = { styles.volumeSliderContainer } > <View style = { styles.volumeSliderContainer } >
<Icon <Icon
size = { 24 } size = { 20 }
src = { IconVolumeEmpty } src = { IconVolumeEmpty } />
style = { styles.volumeIcon } />
<Slider <Slider
maximumTrackTintColor = { palette.field02 } maximumTrackTintColor = { palette.field02 }
maximumValue = { VOLUME_SLIDER_SCALE } maximumValue = { VOLUME_SLIDER_SCALE }

View File

@ -54,17 +54,12 @@ export default createStyleSheet({
volumeSliderContainer: { volumeSliderContainer: {
alignItems: 'center', alignItems: 'center',
flexDirection: 'row', flexDirection: 'row',
marginBottom: BaseTheme.spacing[3], marginLeft: BaseTheme.spacing[3],
marginTop: BaseTheme.spacing[3] marginTop: BaseTheme.spacing[3]
}, },
volumeIcon: {
marginLeft: BaseTheme.spacing[1],
minWidth: '5%'
},
sliderContainer: { sliderContainer: {
marginLeft: BaseTheme.spacing[3], marginLeft: BaseTheme.spacing[3],
minWidth: '90%' minWidth: '84%'
} }
}); });