diff --git a/react/features/participants-pane/actions.native.js b/react/features/participants-pane/actions.native.js
index 3812e6951..187217d6a 100644
--- a/react/features/participants-pane/actions.native.js
+++ b/react/features/participants-pane/actions.native.js
@@ -29,28 +29,28 @@ export function showContextMenuReject(participant: Object) {
* @param {string} participantID - The selected meeting participant id.
* @returns {Function}
*/
-export function showConnectionStatus(participantID: String) {
+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.
+ * @param {string} participantId - The ID of the selected meeting participant.
* @returns {Function}
*/
-export function showContextMenuDetails(participant: Object) {
- return openDialog(RemoteVideoMenu, { participant });
+export function showContextMenuDetails(participantId: string) {
+ return openDialog(RemoteVideoMenu, { participantId });
}
/**
* Displays the shared video menu.
*
- * @param {Object} participant - The selected meeting participant.
+ * @param {string} participantId - The ID of the selected meeting participant.
* @returns {Function}
*/
-export function showSharedVideoMenu(participant: Object) {
- return openDialog(SharedVideoMenu, { participant });
+export function showSharedVideoMenu(participantId: string) {
+ return openDialog(SharedVideoMenu, { participantId });
}
/**
diff --git a/react/features/participants-pane/components/native/LobbyParticipantList.js b/react/features/participants-pane/components/native/LobbyParticipantList.js
index 7b9948da8..5bde465d8 100644
--- a/react/features/participants-pane/components/native/LobbyParticipantList.js
+++ b/react/features/participants-pane/components/native/LobbyParticipantList.js
@@ -2,7 +2,7 @@
import React, { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
-import { Text, View } from 'react-native';
+import { ScrollView, Text, View } from 'react-native';
import { Button, withTheme } from 'react-native-paper';
import { useDispatch, useSelector } from 'react-redux';
@@ -54,13 +54,15 @@ const LobbyParticipantList = ({ theme }: Props) => {
)
}
- {
- participants.map(p => (
- )
- )
- }
+
+ {
+ participants.map(p => (
+ )
+ )
+ }
+
);
};
diff --git a/react/features/participants-pane/components/native/MeetingParticipantItem.js b/react/features/participants-pane/components/native/MeetingParticipantItem.js
index 86f660d0e..f90ee2f7f 100644
--- a/react/features/participants-pane/components/native/MeetingParticipantItem.js
+++ b/react/features/participants-pane/components/native/MeetingParticipantItem.js
@@ -1,9 +1,10 @@
// @flow
-import React from 'react';
+import React, { PureComponent } from 'react';
import { translate } from '../../../base/i18n';
import {
+ getLocalParticipant,
getParticipantByIdOrUndefined,
getParticipantDisplayName
} from '../../../base/participants';
@@ -12,6 +13,7 @@ import {
isParticipantAudioMuted,
isParticipantVideoMuted
} from '../../../base/tracks';
+import { showConnectionStatus, showContextMenuDetails, showSharedVideoMenu } from '../../actions.native';
import { MEDIA_STATE } from '../../constants';
import type { MediaState } from '../../constants';
import { getParticipantAudioMediaState } from '../../functions';
@@ -31,6 +33,11 @@ type Props = {
*/
_displayName: string,
+ /**
+ * True if the participant is fake.
+ */
+ _isFakeParticipant: boolean,
+
/**
* True if the participant is video muted.
*/
@@ -41,6 +48,11 @@ type Props = {
*/
_local: boolean,
+ /**
+ * Shared video local participant owner.
+ */
+ _localVideoOwner: boolean,
+
/**
* The participant ID.
*/
@@ -52,9 +64,9 @@ type Props = {
_raisedHand: boolean,
/**
- * Callback to invoke when item is pressed.
+ * The redux dispatch function.
*/
- onPress: Function,
+ dispatch: Function,
/**
* The ID of the participant.
@@ -64,30 +76,75 @@ type Props = {
/**
* Implements the MeetingParticipantItem component.
- *
- * @param {Props} props - The props of the component.
- * @returns {ReactElement}
*/
-function MeetingParticipantItem({
- _audioMediaState,
- _displayName,
- _isVideoMuted,
- _local,
- _participantID,
- _raisedHand,
- onPress
-}: Props) {
- return (
-
- );
+class MeetingParticipantItem extends PureComponent {
+
+ /**
+ * Creates new MeetingParticipantItem instance.
+ *
+ * @param {Props} props - The props of the component.
+ */
+ constructor(props: Props) {
+ super(props);
+
+ this._onPress = this._onPress.bind(this);
+ }
+
+ _onPress: () => void;
+
+ /**
+ * Handles MeetingParticipantItem press events.
+ *
+ * @returns {void}
+ */
+ _onPress() {
+ const {
+ _local,
+ _localVideoOwner,
+ _isFakeParticipant,
+ _participantID,
+ dispatch
+ } = this.props;
+
+ if (_isFakeParticipant && _localVideoOwner) {
+ dispatch(showSharedVideoMenu(_participantID));
+ } else if (!_isFakeParticipant) {
+ if (_local) {
+ dispatch(showConnectionStatus(_participantID));
+ } else {
+ dispatch(showContextMenuDetails(_participantID));
+ }
+ } // else no-op
+ }
+
+ /**
+ * Implements React's {@link Component#render()}.
+ *
+ * @inheritdoc
+ * @returns {ReactElement}
+ */
+ render() {
+ const {
+ _audioMediaState,
+ _displayName,
+ _isVideoMuted,
+ _local,
+ _participantID,
+ _raisedHand
+ } = this.props;
+
+ return (
+
+ );
+ }
}
/**
@@ -100,19 +157,21 @@ function MeetingParticipantItem({
*/
function mapStateToProps(state, ownProps): Object {
const { participantID } = ownProps;
+ const { ownerId } = state['features/shared-video'];
+ const localParticipantId = getLocalParticipant(state).id;
const participant = getParticipantByIdOrUndefined(state, participantID);
const _isAudioMuted = isParticipantAudioMuted(participant, state);
const isVideoMuted = isParticipantVideoMuted(participant, state);
- const audioMediaState = getParticipantAudioMediaState(
- participant, _isAudioMuted, state
- );
+ const audioMediaState = getParticipantAudioMediaState(participant, _isAudioMuted, state);
return {
_audioMediaState: audioMediaState,
_displayName: getParticipantDisplayName(state, participant?.id),
_isAudioMuted,
+ _isFakeParticipant: Boolean(participant?.isFakeParticipant),
_isVideoMuted: isVideoMuted,
_local: Boolean(participant?.local),
+ _localVideoOwner: Boolean(ownerId === localParticipantId),
_participantID: participant?.id,
_raisedHand: Boolean(participant?.raisedHand)
};
diff --git a/react/features/participants-pane/components/native/MeetingParticipantList.js b/react/features/participants-pane/components/native/MeetingParticipantList.js
index 78cace350..80dea4b75 100644
--- a/react/features/participants-pane/components/native/MeetingParticipantList.js
+++ b/react/features/participants-pane/components/native/MeetingParticipantList.js
@@ -1,25 +1,14 @@
// @flow
-import React, { useCallback } from 'react';
-import { useTranslation } from 'react-i18next';
-import { Text, View } from 'react-native';
+import React, { PureComponent } from 'react';
+import { FlatList, Text, View } from 'react-native';
import { Button } from 'react-native-paper';
-import { useDispatch, useSelector } from 'react-redux';
-
+import { translate } from '../../../base/i18n';
import { Icon, IconInviteMore } from '../../../base/icons';
-import {
- getLocalParticipant,
- getParticipantCountWithFake,
- getSortedParticipants
-} from '../../../base/participants';
+import { getLocalParticipant, getParticipantCountWithFake } from '../../../base/participants';
import { connect } from '../../../base/redux';
import { doInvitePeople } from '../../../invite/actions.native';
-import {
- showConnectionStatus,
- showContextMenuDetails,
- showSharedVideoMenu
-} from '../../actions.native';
import { shouldRenderInviteButton } from '../../functions';
import MeetingParticipantItem from './MeetingParticipantItem';
@@ -28,74 +17,150 @@ import styles from './styles';
type Props = {
/**
- * Shared video local participant owner.
+ * The ID of the local participant.
*/
- _localVideoOwner: boolean
+ _localParticipantId: string,
+
+ /**
+ * The number of participants in the conference.
+ */
+ _participantsCount: number,
+
+ /**
+ * Whether or not to show the invite button.
+ */
+ _showInviteButton: boolean,
+
+ /**
+ * The remote participants.
+ */
+ _sortedRemoteParticipants: Map,
+
+ /**
+ * The redux dispatch function.
+ */
+ dispatch: Function,
+
+ /**
+ * Translation function.
+ */
+ t: Function
}
-const MeetingParticipantList = ({ _localVideoOwner }: Props) => {
- const dispatch = useDispatch();
- const onInvite = useCallback(() => dispatch(doInvitePeople()), [ dispatch ]);
- const participantsCount = useSelector(getParticipantCountWithFake);
- const sortedParticipants = useSelector(getSortedParticipants);
- const showInviteButton = useSelector(shouldRenderInviteButton);
- const { t } = useTranslation();
+/**
+ * The meeting participant list component.
+ */
+class MeetingParticipantList extends PureComponent {
- // eslint-disable-next-line react/no-multi-comp
- const renderParticipant = p => {
- if (p.isFakeParticipant) {
- if (_localVideoOwner) {
- return (
- dispatch(showSharedVideoMenu(p)) }
- participantID = { p.id } />
- );
- }
+ /**
+ * Creates new MeetingParticipantList instance.
+ *
+ * @param {Props} props - The props of the component.
+ */
+ constructor(props: Props) {
+ super(props);
- return (
-
- );
- }
+ this._keyExtractor = this._keyExtractor.bind(this);
+ this._onInvite = this._onInvite.bind(this);
+ this._renderParticipant = this._renderParticipant.bind(this);
+ }
+ _keyExtractor: Function;
+
+ /**
+ * Returns a key for a passed item of the list.
+ *
+ * @param {string} item - The user ID.
+ * @returns {string} - The user ID.
+ */
+ _keyExtractor(item) {
+ return item;
+ }
+
+ _onInvite: () => void;
+
+ /**
+ * Handles ivite button presses.
+ *
+ * @returns {void}
+ */
+ _onInvite() {
+ this.props.dispatch(doInvitePeople());
+ }
+
+ /**
+ * Renders the "invite more" icon.
+ *
+ * @returns {ReactElement}
+ */
+ _renderInviteMoreIcon() {
+ return (
+
+ );
+ }
+
+ _renderParticipant: Object => Object;
+
+ /**
+ * Renders a participant.
+ *
+ * @param {Object} flatListItem - Information about the item to be rendered.
+ * @param {string} flatListItem.item - The ID of the participant.
+ * @returns {ReactElement}
+ */
+ _renderParticipant({ item/* , index, separators */ }) {
return (
p.local
- ? dispatch(showConnectionStatus(p.id)) : dispatch(showContextMenuDetails(p)) }
- participantID = { p.id } />
+ key = { item }
+ participantID = { item } />
);
- };
+ }
- return (
-
-
- {t('participantsPane.headings.participantsList',
- { count: participantsCount })}
-
- {
- showInviteButton
- &&
- );
-};
+ /**
+ * Implements React's {@link Component#render()}.
+ *
+ * @inheritdoc
+ * @returns {ReactElement}
+ */
+ render() {
+ const {
+ _localParticipantId,
+ _participantsCount,
+ _showInviteButton,
+ _sortedRemoteParticipants,
+ t
+ } = this.props;
+
+ return (
+
+
+ {t('participantsPane.headings.participantsList',
+ { count: _participantsCount })}
+
+ {
+ _showInviteButton
+ &&
+ }
+
+
+ );
+ }
+}
/**
* Maps (parts of) the redux state to the associated props for this component.
@@ -105,12 +170,16 @@ const MeetingParticipantList = ({ _localVideoOwner }: Props) => {
* @returns {Props}
*/
function _mapStateToProps(state): Object {
- const { ownerId } = state['features/shared-video'];
- const localParticipantId = getLocalParticipant(state).id;
+ const _participantsCount = getParticipantCountWithFake(state);
+ const { remoteParticipants } = state['features/filmstrip'];
+ const _showInviteButton = shouldRenderInviteButton(state);
return {
- _localVideoOwner: Boolean(ownerId === localParticipantId)
+ _participantsCount,
+ _showInviteButton,
+ _sortedRemoteParticipants: remoteParticipants,
+ _localParticipantId: getLocalParticipant(state)?.id
};
}
-export default connect(_mapStateToProps)(MeetingParticipantList);
+export default translate(connect(_mapStateToProps)(MeetingParticipantList));
diff --git a/react/features/participants-pane/components/native/ParticipantsPane.js b/react/features/participants-pane/components/native/ParticipantsPane.js
index e61715947..106a245ad 100644
--- a/react/features/participants-pane/components/native/ParticipantsPane.js
+++ b/react/features/participants-pane/components/native/ParticipantsPane.js
@@ -2,7 +2,7 @@
import React, { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
-import { ScrollView, View } from 'react-native';
+import { View } from 'react-native';
import { Button } from 'react-native-paper';
import { useDispatch, useSelector } from 'react-redux';
@@ -45,10 +45,8 @@ const ParticipantsPane = () => {
}}
onClose = { closePane }
style = { styles.participantsPane }>
-
-
-
-
+
+
{
isLocalModerator
&&