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 { RecordingLabel } from '../../../recording';
|
||||||
import { openHighlightDialog } from '../../../recording/actions.native';
|
import { openHighlightDialog } from '../../../recording/actions.native';
|
||||||
import HighlightButton from '../../../recording/components/Recording/native/HighlightButton';
|
import HighlightButton from '../../../recording/components/Recording/native/HighlightButton';
|
||||||
|
import VisitorsCountLabel from '../../../visitors/components/native/VisitorsCountLabel';
|
||||||
|
|
||||||
import RaisedHandsCountLabel from './RaisedHandsCountLabel';
|
import RaisedHandsCountLabel from './RaisedHandsCountLabel';
|
||||||
import {
|
import {
|
||||||
LABEL_ID_RAISED_HANDS_COUNT,
|
LABEL_ID_RAISED_HANDS_COUNT,
|
||||||
LABEL_ID_RECORDING,
|
LABEL_ID_RECORDING,
|
||||||
LABEL_ID_STREAMING,
|
LABEL_ID_STREAMING,
|
||||||
|
LABEL_ID_VISITORS_COUNT,
|
||||||
LabelHitSlop
|
LabelHitSlop
|
||||||
} from './constants';
|
} from './constants';
|
||||||
|
|
||||||
|
@ -51,6 +53,11 @@ const AlwaysOnLabels = ({ createOnPress }: Props) => {
|
||||||
onPress = { createOnPress(LABEL_ID_RAISED_HANDS_COUNT) } >
|
onPress = { createOnPress(LABEL_ID_RAISED_HANDS_COUNT) } >
|
||||||
<RaisedHandsCountLabel />
|
<RaisedHandsCountLabel />
|
||||||
</TouchableOpacity>
|
</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_TRANSCRIBING = 'transcribing';
|
||||||
export const LABEL_ID_INSECURE_ROOM_NAME = 'insecure-room-name';
|
export const LABEL_ID_INSECURE_ROOM_NAME = 'insecure-room-name';
|
||||||
export const LABEL_ID_RAISED_HANDS_COUNT = 'raised-hands-count';
|
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
|
* The {@code ExpandedLabel} components to be rendered for the individual
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import { WithTranslation } from 'react-i18next';
|
import { WithTranslation } from 'react-i18next';
|
||||||
import { FlatList } from 'react-native';
|
import { FlatList, Text } from 'react-native';
|
||||||
|
|
||||||
import { IReduxState } from '../../../app/types';
|
import { IReduxState } from '../../../app/types';
|
||||||
import { translate } from '../../../base/i18n/functions';
|
import { translate } from '../../../base/i18n/functions';
|
||||||
|
@ -68,6 +68,11 @@ type Props = WithTranslation & {
|
||||||
*/
|
*/
|
||||||
_sortedRemoteParticipants: Map<string, string>;
|
_sortedRemoteParticipants: Map<string, string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current visitors count if any.
|
||||||
|
*/
|
||||||
|
_visitorsCount: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of breakout rooms that were created.
|
* List of breakout rooms that were created.
|
||||||
*/
|
*/
|
||||||
|
@ -189,6 +194,7 @@ class MeetingParticipantList extends PureComponent<Props> {
|
||||||
_participantsCount,
|
_participantsCount,
|
||||||
_showInviteButton,
|
_showInviteButton,
|
||||||
_sortedRemoteParticipants,
|
_sortedRemoteParticipants,
|
||||||
|
_visitorsCount,
|
||||||
breakoutRooms,
|
breakoutRooms,
|
||||||
isLocalModerator,
|
isLocalModerator,
|
||||||
lobbyParticipants,
|
lobbyParticipants,
|
||||||
|
@ -217,48 +223,54 @@ class MeetingParticipantList extends PureComponent<Props> {
|
||||||
const finalContainerStyle
|
const finalContainerStyle
|
||||||
= _participantsCount > 6 && containerStyle;
|
= _participantsCount > 6 && containerStyle;
|
||||||
const { color, shareDialogVisible } = _inviteOthersControl;
|
const { color, shareDialogVisible } = _inviteOthersControl;
|
||||||
|
const _visitorsLabelText = _visitorsCount > 0
|
||||||
|
? t('participantsPane.headings.visitors', { count: _visitorsCount })
|
||||||
|
: undefined;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CollapsibleList
|
<>
|
||||||
containerStyle = { finalContainerStyle }
|
{ _visitorsCount > 0 && <Text style = { styles.visitorsLabel }>{ _visitorsLabelText }</Text>
|
||||||
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
|
<CollapsibleList
|
||||||
clearable = { true }
|
containerStyle = { finalContainerStyle }
|
||||||
// @ts-ignore
|
title = { title } >
|
||||||
customStyles = {{
|
{
|
||||||
container: styles.inputContainer,
|
_showInviteButton
|
||||||
input: styles.centerInput }}
|
&& <Button
|
||||||
onChange = { this._onSearchStringChange }
|
accessibilityLabel = 'participantsPane.actions.invite'
|
||||||
placeholder = { t('participantsPane.search') }
|
disabled = { shareDialogVisible }
|
||||||
value = { this.props.searchString } />
|
// eslint-disable-next-line react/jsx-no-bind
|
||||||
<FlatList
|
icon = { () => (
|
||||||
bounces = { false }
|
<Icon
|
||||||
data = { [ _localParticipant?.id, ..._sortedRemoteParticipants ] }
|
color = { color }
|
||||||
horizontal = { false }
|
size = { 20 }
|
||||||
keyExtractor = { this._keyExtractor }
|
src = { IconAddUser } />
|
||||||
renderItem = { this._renderParticipant }
|
) }
|
||||||
scrollEnabled = { true }
|
labelKey = 'participantsPane.actions.invite'
|
||||||
showsHorizontalScrollIndicator = { false }
|
onClick = { this._onInvite }
|
||||||
windowSize = { 2 } />
|
style = { styles.inviteButton }
|
||||||
</CollapsibleList>
|
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,
|
_showInviteButton,
|
||||||
_sortedRemoteParticipants: remoteParticipants,
|
_sortedRemoteParticipants: remoteParticipants,
|
||||||
_localParticipant: getLocalParticipant(state),
|
_localParticipant: getLocalParticipant(state),
|
||||||
_shareDialogVisible: shareDialogVisible
|
_shareDialogVisible: shareDialogVisible,
|
||||||
|
_visitorsCount: state['features/visitors'].count || 0
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -288,5 +288,11 @@ export default {
|
||||||
centerInput: {
|
centerInput: {
|
||||||
paddingRight: BaseTheme.spacing[3],
|
paddingRight: BaseTheme.spacing[3],
|
||||||
textAlign: 'center'
|
textAlign: 'center'
|
||||||
|
},
|
||||||
|
|
||||||
|
visitorsLabel: {
|
||||||
|
...BaseTheme.typography.heading6,
|
||||||
|
color: BaseTheme.palette.warning02,
|
||||||
|
marginLeft: BaseTheme.spacing[3]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -48,6 +48,11 @@ type Props = {
|
||||||
*/
|
*/
|
||||||
_visible: boolean,
|
_visible: boolean,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether we are in visitors mode.
|
||||||
|
*/
|
||||||
|
_visitorsModeEnabled: boolean,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The width of the screen.
|
* The width of the screen.
|
||||||
*/
|
*/
|
||||||
|
@ -61,7 +66,7 @@ type Props = {
|
||||||
* @returns {React$Element}.
|
* @returns {React$Element}.
|
||||||
*/
|
*/
|
||||||
function Toolbox(props: Props) {
|
function Toolbox(props: Props) {
|
||||||
const { _endConferenceSupported, _reactionsEnabled, _styles, _visible, _width } = props;
|
const { _endConferenceSupported, _reactionsEnabled, _styles, _visible, _visitorsModeEnabled, _width } = props;
|
||||||
|
|
||||||
if (!_visible) {
|
if (!_visible) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -87,20 +92,22 @@ function Toolbox(props: Props) {
|
||||||
edges = { [ bottomEdge && 'bottom' ].filter(Boolean) }
|
edges = { [ bottomEdge && 'bottom' ].filter(Boolean) }
|
||||||
pointerEvents = 'box-none'
|
pointerEvents = 'box-none'
|
||||||
style = { styles.toolbox }>
|
style = { styles.toolbox }>
|
||||||
<AudioMuteButton
|
{!_visitorsModeEnabled && <AudioMuteButton
|
||||||
styles = { buttonStylesBorderless }
|
styles = { buttonStylesBorderless }
|
||||||
toggledStyles = { toggledButtonStyles } />
|
toggledStyles = { toggledButtonStyles } />
|
||||||
<VideoMuteButton
|
}
|
||||||
|
{!_visitorsModeEnabled && <VideoMuteButton
|
||||||
styles = { buttonStylesBorderless }
|
styles = { buttonStylesBorderless }
|
||||||
toggledStyles = { toggledButtonStyles } />
|
toggledStyles = { toggledButtonStyles } />
|
||||||
{
|
}
|
||||||
additionalButtons.has('chat')
|
{!_visitorsModeEnabled && additionalButtons.has('chat')
|
||||||
&& <ChatButton
|
&& <ChatButton
|
||||||
styles = { buttonStylesBorderless }
|
styles = { buttonStylesBorderless }
|
||||||
toggledStyles = { backgroundToggledStyle } />
|
toggledStyles = { backgroundToggledStyle } />
|
||||||
}
|
}
|
||||||
{additionalButtons.has('screensharing') && <ScreenSharingButton styles = { buttonStylesBorderless } />}
|
{!_visitorsModeEnabled && additionalButtons.has('screensharing')
|
||||||
{ additionalButtons.has('raisehand') && (_reactionsEnabled
|
&& <ScreenSharingButton styles = { buttonStylesBorderless } />}
|
||||||
|
{ !_visitorsModeEnabled && additionalButtons.has('raisehand') && (_reactionsEnabled
|
||||||
? <ReactionsMenuButton
|
? <ReactionsMenuButton
|
||||||
styles = { buttonStylesBorderless }
|
styles = { buttonStylesBorderless }
|
||||||
toggledStyles = { backgroundToggledStyle } />
|
toggledStyles = { backgroundToggledStyle } />
|
||||||
|
@ -108,9 +115,10 @@ function Toolbox(props: Props) {
|
||||||
styles = { buttonStylesBorderless }
|
styles = { buttonStylesBorderless }
|
||||||
toggledStyles = { backgroundToggledStyle } />)}
|
toggledStyles = { backgroundToggledStyle } />)}
|
||||||
{additionalButtons.has('tileview') && <TileViewButton styles = { buttonStylesBorderless } />}
|
{additionalButtons.has('tileview') && <TileViewButton styles = { buttonStylesBorderless } />}
|
||||||
<OverflowMenuButton
|
{!_visitorsModeEnabled && <OverflowMenuButton
|
||||||
styles = { buttonStylesBorderless }
|
styles = { buttonStylesBorderless }
|
||||||
toggledStyles = { toggledButtonStyles } />
|
toggledStyles = { toggledButtonStyles } />
|
||||||
|
}
|
||||||
{ _endConferenceSupported
|
{ _endConferenceSupported
|
||||||
? <HangupMenuButton
|
? <HangupMenuButton
|
||||||
styles = { hangupMenuButtonStyles }
|
styles = { hangupMenuButtonStyles }
|
||||||
|
@ -140,6 +148,7 @@ function _mapStateToProps(state: Object): Object {
|
||||||
_endConferenceSupported: Boolean(endConferenceSupported),
|
_endConferenceSupported: Boolean(endConferenceSupported),
|
||||||
_styles: ColorSchemeRegistry.get(state, 'Toolbox'),
|
_styles: ColorSchemeRegistry.get(state, 'Toolbox'),
|
||||||
_visible: isToolboxVisible(state),
|
_visible: isToolboxVisible(state),
|
||||||
|
_visitorsModeEnabled: state['features/visitors'].enabled,
|
||||||
_width: state['features/base/responsive-ui'].clientWidth,
|
_width: state['features/base/responsive-ui'].clientWidth,
|
||||||
_reactionsEnabled: isReactionsEnabled(state)
|
_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
|
// eslint-disable-next-line lines-around-comment
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { Tooltip } from '../../../base/tooltip';
|
import { Tooltip } from '../../../base/tooltip';
|
||||||
|
import { getVisitorsShortText } from '../../functions';
|
||||||
|
|
||||||
const useStyles = makeStyles()(theme => {
|
const useStyles = makeStyles()(theme => {
|
||||||
return {
|
return {
|
||||||
|
@ -26,13 +27,6 @@ const VisitorsCountLabel = () => {
|
||||||
state['features/visitors'].count || 0);
|
state['features/visitors'].count || 0);
|
||||||
const { t } = useTranslation();
|
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
|
return visitorsMode && (<Tooltip
|
||||||
content = { t('visitorsLabel', { count: visitorsCount }) }
|
content = { t('visitorsLabel', { count: visitorsCount }) }
|
||||||
position = { 'bottom' }>
|
position = { 'bottom' }>
|
||||||
|
@ -41,7 +35,7 @@ const VisitorsCountLabel = () => {
|
||||||
icon = { IconUsers }
|
icon = { IconUsers }
|
||||||
iconColor = { theme.palette.icon04 }
|
iconColor = { theme.palette.icon04 }
|
||||||
id = 'visitorsCountLabel'
|
id = 'visitorsCountLabel'
|
||||||
text = { `${visitorsCountLabel}` } />
|
text = { `${getVisitorsShortText(visitorsCount)}` } />
|
||||||
</Tooltip>);
|
</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