feat(mobile): Adds visitors count.
This commit is contained in:
parent
abe2fa4dd4
commit
3c69645169
|
@ -8,12 +8,14 @@ import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
|
|||
import { RecordingLabel } from '../../../recording';
|
||||
import { openHighlightDialog } from '../../../recording/actions.native';
|
||||
import HighlightButton from '../../../recording/components/Recording/native/HighlightButton';
|
||||
import VisitorsCountLabel from '../../../visitors/components/native/VisitorsCountLabel';
|
||||
|
||||
import RaisedHandsCountLabel from './RaisedHandsCountLabel';
|
||||
import {
|
||||
LABEL_ID_RAISED_HANDS_COUNT,
|
||||
LABEL_ID_RECORDING,
|
||||
LABEL_ID_STREAMING,
|
||||
LABEL_ID_VISITORS_COUNT,
|
||||
LabelHitSlop
|
||||
} from './constants';
|
||||
|
||||
|
@ -51,6 +53,11 @@ const AlwaysOnLabels = ({ createOnPress }: Props) => {
|
|||
onPress = { createOnPress(LABEL_ID_RAISED_HANDS_COUNT) } >
|
||||
<RaisedHandsCountLabel />
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
hitSlop = { LabelHitSlop }
|
||||
onPress = { createOnPress(LABEL_ID_VISITORS_COUNT) } >
|
||||
<VisitorsCountLabel />
|
||||
</TouchableOpacity>
|
||||
</>);
|
||||
};
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ export const LABEL_ID_STREAMING = 'streaming';
|
|||
export const LABEL_ID_TRANSCRIBING = 'transcribing';
|
||||
export const LABEL_ID_INSECURE_ROOM_NAME = 'insecure-room-name';
|
||||
export const LABEL_ID_RAISED_HANDS_COUNT = 'raised-hands-count';
|
||||
export const LABEL_ID_VISITORS_COUNT = 'visitors-count';
|
||||
|
||||
/**
|
||||
* The {@code ExpandedLabel} components to be rendered for the individual
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import React, { PureComponent } from 'react';
|
||||
import { WithTranslation } from 'react-i18next';
|
||||
import { FlatList } from 'react-native';
|
||||
import { FlatList, Text } from 'react-native';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { translate } from '../../../base/i18n/functions';
|
||||
|
@ -68,6 +68,11 @@ type Props = WithTranslation & {
|
|||
*/
|
||||
_sortedRemoteParticipants: Map<string, string>;
|
||||
|
||||
/**
|
||||
* The current visitors count if any.
|
||||
*/
|
||||
_visitorsCount: number;
|
||||
|
||||
/**
|
||||
* List of breakout rooms that were created.
|
||||
*/
|
||||
|
@ -189,6 +194,7 @@ class MeetingParticipantList extends PureComponent<Props> {
|
|||
_participantsCount,
|
||||
_showInviteButton,
|
||||
_sortedRemoteParticipants,
|
||||
_visitorsCount,
|
||||
breakoutRooms,
|
||||
isLocalModerator,
|
||||
lobbyParticipants,
|
||||
|
@ -217,48 +223,54 @@ class MeetingParticipantList extends PureComponent<Props> {
|
|||
const finalContainerStyle
|
||||
= _participantsCount > 6 && containerStyle;
|
||||
const { color, shareDialogVisible } = _inviteOthersControl;
|
||||
const _visitorsLabelText = _visitorsCount > 0
|
||||
? t('participantsPane.headings.visitors', { count: _visitorsCount })
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<CollapsibleList
|
||||
containerStyle = { finalContainerStyle }
|
||||
title = { title } >
|
||||
{
|
||||
_showInviteButton
|
||||
&& <Button
|
||||
accessibilityLabel = 'participantsPane.actions.invite'
|
||||
disabled = { shareDialogVisible }
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
icon = { () => (
|
||||
<Icon
|
||||
color = { color }
|
||||
size = { 20 }
|
||||
src = { IconAddUser } />
|
||||
) }
|
||||
labelKey = 'participantsPane.actions.invite'
|
||||
onClick = { this._onInvite }
|
||||
style = { styles.inviteButton }
|
||||
type = { BUTTON_TYPES.PRIMARY } />
|
||||
<>
|
||||
{ _visitorsCount > 0 && <Text style = { styles.visitorsLabel }>{ _visitorsLabelText }</Text>
|
||||
}
|
||||
<Input
|
||||
clearable = { true }
|
||||
// @ts-ignore
|
||||
customStyles = {{
|
||||
container: styles.inputContainer,
|
||||
input: styles.centerInput }}
|
||||
onChange = { this._onSearchStringChange }
|
||||
placeholder = { t('participantsPane.search') }
|
||||
value = { this.props.searchString } />
|
||||
<FlatList
|
||||
bounces = { false }
|
||||
data = { [ _localParticipant?.id, ..._sortedRemoteParticipants ] }
|
||||
horizontal = { false }
|
||||
keyExtractor = { this._keyExtractor }
|
||||
renderItem = { this._renderParticipant }
|
||||
scrollEnabled = { true }
|
||||
showsHorizontalScrollIndicator = { false }
|
||||
windowSize = { 2 } />
|
||||
</CollapsibleList>
|
||||
);
|
||||
<CollapsibleList
|
||||
containerStyle = { finalContainerStyle }
|
||||
title = { title } >
|
||||
{
|
||||
_showInviteButton
|
||||
&& <Button
|
||||
accessibilityLabel = 'participantsPane.actions.invite'
|
||||
disabled = { shareDialogVisible }
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
icon = { () => (
|
||||
<Icon
|
||||
color = { color }
|
||||
size = { 20 }
|
||||
src = { IconAddUser } />
|
||||
) }
|
||||
labelKey = 'participantsPane.actions.invite'
|
||||
onClick = { this._onInvite }
|
||||
style = { styles.inviteButton }
|
||||
type = { BUTTON_TYPES.PRIMARY } />
|
||||
}
|
||||
<Input
|
||||
clearable = { true }
|
||||
// @ts-ignore
|
||||
customStyles = {{
|
||||
container: styles.inputContainer,
|
||||
input: styles.centerInput }}
|
||||
onChange = { this._onSearchStringChange }
|
||||
placeholder = { t('participantsPane.search') }
|
||||
value = { this.props.searchString } />
|
||||
<FlatList
|
||||
bounces = { false }
|
||||
data = { [ _localParticipant?.id, ..._sortedRemoteParticipants ] }
|
||||
horizontal = { false }
|
||||
keyExtractor = { this._keyExtractor }
|
||||
renderItem = { this._renderParticipant }
|
||||
scrollEnabled = { true }
|
||||
showsHorizontalScrollIndicator = { false }
|
||||
windowSize = { 2 } />
|
||||
</CollapsibleList>
|
||||
</>);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -287,7 +299,8 @@ function _mapStateToProps(state: IReduxState): Object {
|
|||
_showInviteButton,
|
||||
_sortedRemoteParticipants: remoteParticipants,
|
||||
_localParticipant: getLocalParticipant(state),
|
||||
_shareDialogVisible: shareDialogVisible
|
||||
_shareDialogVisible: shareDialogVisible,
|
||||
_visitorsCount: state['features/visitors'].count || 0
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -288,5 +288,11 @@ export default {
|
|||
centerInput: {
|
||||
paddingRight: BaseTheme.spacing[3],
|
||||
textAlign: 'center'
|
||||
},
|
||||
|
||||
visitorsLabel: {
|
||||
...BaseTheme.typography.heading6,
|
||||
color: BaseTheme.palette.warning02,
|
||||
marginLeft: BaseTheme.spacing[3]
|
||||
}
|
||||
};
|
||||
|
|
|
@ -48,6 +48,11 @@ type Props = {
|
|||
*/
|
||||
_visible: boolean,
|
||||
|
||||
/**
|
||||
* Whether we are in visitors mode.
|
||||
*/
|
||||
_visitorsModeEnabled: boolean,
|
||||
|
||||
/**
|
||||
* The width of the screen.
|
||||
*/
|
||||
|
@ -61,7 +66,7 @@ type Props = {
|
|||
* @returns {React$Element}.
|
||||
*/
|
||||
function Toolbox(props: Props) {
|
||||
const { _endConferenceSupported, _reactionsEnabled, _styles, _visible, _width } = props;
|
||||
const { _endConferenceSupported, _reactionsEnabled, _styles, _visible, _visitorsModeEnabled, _width } = props;
|
||||
|
||||
if (!_visible) {
|
||||
return null;
|
||||
|
@ -87,20 +92,22 @@ function Toolbox(props: Props) {
|
|||
edges = { [ bottomEdge && 'bottom' ].filter(Boolean) }
|
||||
pointerEvents = 'box-none'
|
||||
style = { styles.toolbox }>
|
||||
<AudioMuteButton
|
||||
{!_visitorsModeEnabled && <AudioMuteButton
|
||||
styles = { buttonStylesBorderless }
|
||||
toggledStyles = { toggledButtonStyles } />
|
||||
<VideoMuteButton
|
||||
}
|
||||
{!_visitorsModeEnabled && <VideoMuteButton
|
||||
styles = { buttonStylesBorderless }
|
||||
toggledStyles = { toggledButtonStyles } />
|
||||
{
|
||||
additionalButtons.has('chat')
|
||||
}
|
||||
{!_visitorsModeEnabled && additionalButtons.has('chat')
|
||||
&& <ChatButton
|
||||
styles = { buttonStylesBorderless }
|
||||
toggledStyles = { backgroundToggledStyle } />
|
||||
}
|
||||
{additionalButtons.has('screensharing') && <ScreenSharingButton styles = { buttonStylesBorderless } />}
|
||||
{ additionalButtons.has('raisehand') && (_reactionsEnabled
|
||||
{!_visitorsModeEnabled && additionalButtons.has('screensharing')
|
||||
&& <ScreenSharingButton styles = { buttonStylesBorderless } />}
|
||||
{ !_visitorsModeEnabled && additionalButtons.has('raisehand') && (_reactionsEnabled
|
||||
? <ReactionsMenuButton
|
||||
styles = { buttonStylesBorderless }
|
||||
toggledStyles = { backgroundToggledStyle } />
|
||||
|
@ -108,9 +115,10 @@ function Toolbox(props: Props) {
|
|||
styles = { buttonStylesBorderless }
|
||||
toggledStyles = { backgroundToggledStyle } />)}
|
||||
{additionalButtons.has('tileview') && <TileViewButton styles = { buttonStylesBorderless } />}
|
||||
<OverflowMenuButton
|
||||
{!_visitorsModeEnabled && <OverflowMenuButton
|
||||
styles = { buttonStylesBorderless }
|
||||
toggledStyles = { toggledButtonStyles } />
|
||||
}
|
||||
{ _endConferenceSupported
|
||||
? <HangupMenuButton
|
||||
styles = { hangupMenuButtonStyles }
|
||||
|
@ -140,6 +148,7 @@ function _mapStateToProps(state: Object): Object {
|
|||
_endConferenceSupported: Boolean(endConferenceSupported),
|
||||
_styles: ColorSchemeRegistry.get(state, 'Toolbox'),
|
||||
_visible: isToolboxVisible(state),
|
||||
_visitorsModeEnabled: state['features/visitors'].enabled,
|
||||
_width: state['features/base/responsive-ui'].clientWidth,
|
||||
_reactionsEnabled: isReactionsEnabled(state)
|
||||
};
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
import React from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { IconUsers } from '../../../base/icons/svg';
|
||||
// eslint-disable-next-line lines-around-comment
|
||||
// @ts-ignore
|
||||
import Label from '../../../base/label/components/native/Label';
|
||||
import BaseTheme from '../../../base/ui/components/BaseTheme.native';
|
||||
import { getVisitorsShortText } from '../../functions';
|
||||
|
||||
const styles = {
|
||||
raisedHandsCountLabel: {
|
||||
alignItems: 'center',
|
||||
backgroundColor: BaseTheme.palette.warning02,
|
||||
borderRadius: BaseTheme.shape.borderRadius,
|
||||
flexDirection: 'row',
|
||||
marginLeft: BaseTheme.spacing[0],
|
||||
marginBottom: BaseTheme.spacing[0]
|
||||
},
|
||||
|
||||
raisedHandsCountLabelText: {
|
||||
color: BaseTheme.palette.uiBackground,
|
||||
paddingLeft: BaseTheme.spacing[2]
|
||||
}
|
||||
};
|
||||
|
||||
const VisitorsCountLabel = () => {
|
||||
const visitorsMode = useSelector((state: IReduxState) => state['features/visitors'].enabled);
|
||||
const visitorsCount = useSelector((state: IReduxState) =>
|
||||
state['features/visitors'].count || 0);
|
||||
|
||||
return visitorsMode && (
|
||||
<Label
|
||||
icon = { IconUsers }
|
||||
iconColor = { BaseTheme.palette.uiBackground }
|
||||
style = { styles.raisedHandsCountLabel }
|
||||
text = { `${getVisitorsShortText(visitorsCount)}` }
|
||||
textStyle = { styles.raisedHandsCountLabelText } />
|
||||
);
|
||||
};
|
||||
|
||||
export default VisitorsCountLabel;
|
|
@ -9,6 +9,7 @@ import Label from '../../../base/label/components/web/Label';
|
|||
// eslint-disable-next-line lines-around-comment
|
||||
// @ts-ignore
|
||||
import { Tooltip } from '../../../base/tooltip';
|
||||
import { getVisitorsShortText } from '../../functions';
|
||||
|
||||
const useStyles = makeStyles()(theme => {
|
||||
return {
|
||||
|
@ -26,13 +27,6 @@ const VisitorsCountLabel = () => {
|
|||
state['features/visitors'].count || 0);
|
||||
const { t } = useTranslation();
|
||||
|
||||
let visitorsCountLabel = String(visitorsCount);
|
||||
|
||||
// over 100 we show numbers lik 0.2 K or 9.5 K.
|
||||
if (visitorsCount > 100) {
|
||||
visitorsCountLabel = `${Math.round(visitorsCount / 100) / 10} K`;
|
||||
}
|
||||
|
||||
return visitorsMode && (<Tooltip
|
||||
content = { t('visitorsLabel', { count: visitorsCount }) }
|
||||
position = { 'bottom' }>
|
||||
|
@ -41,7 +35,7 @@ const VisitorsCountLabel = () => {
|
|||
icon = { IconUsers }
|
||||
iconColor = { theme.palette.icon04 }
|
||||
id = 'visitorsCountLabel'
|
||||
text = { `${visitorsCountLabel}` } />
|
||||
text = { `${getVisitorsShortText(visitorsCount)}` } />
|
||||
</Tooltip>);
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
/**
|
||||
* A short string to represent the number of visitors.
|
||||
* Over 100 we show numbers like 0.2 K or 9.5 K.
|
||||
*
|
||||
* @param {number} visitorsCount - The number of visitors to shorten.
|
||||
*
|
||||
* @returns {string} Short string representing the number of visitors.
|
||||
*/
|
||||
export function getVisitorsShortText(visitorsCount: number) {
|
||||
return visitorsCount > 100 ? `${Math.round(visitorsCount / 100) / 10} K` : String(visitorsCount);
|
||||
}
|
Loading…
Reference in New Issue