fix(participants) sort participants alphabetically (#9741)

This commit is contained in:
Avram Tudor 2021-08-18 14:29:41 +03:00 committed by GitHub
parent 9914a5d14a
commit 595df524b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 76 additions and 47 deletions

View File

@ -443,3 +443,45 @@ async function _getFirstLoadableAvatarUrl(participant, store) {
return undefined; return undefined;
} }
/**
* Selector for retrieving sorted participants by display name.
*
* @param {(Function|Object)} stateful - The (whole) redux state, or redux's
* {@code getState} function to be used to retrieve the state
* features/base/participants.
* @returns {Array<Object>}
*/
export function getSortedParticipants(stateful: Object | Function) {
const localParticipant = getLocalParticipant(stateful);
const remoteParticipants = getRemoteParticipants(stateful);
const items = [];
remoteParticipants.forEach(p => {
items.push(p);
});
items.sort((a, b) =>
getParticipantDisplayName(stateful, a.id).localeCompare(getParticipantDisplayName(stateful, b.id))
);
items.unshift(localParticipant);
return items;
}
/**
* Selector for retrieving ids of alphabetically sorted participants by name.
*
* @param {(Function|Object)} stateful - The (whole) redux state, or redux's
* {@code getState} function to be used to retrieve the state
* features/base/participants.
* @returns {Array<string>}
*/
export function getSortedParticipantIds(stateful: Object | Function): Array<string> {
const participantIds = getSortedParticipants(stateful).map((p): Object => p.id);
return participantIds;
}

View File

@ -30,8 +30,6 @@ import { isParticipantModerator } from './functions';
* @property {string} email - Participant email. * @property {string} email - Participant email.
*/ */
declare var APP: Object;
/** /**
* The participant properties which cannot be updated through * The participant properties which cannot be updated through
* {@link PARTICIPANT_UPDATED}. They either identify the participant or can only * {@link PARTICIPANT_UPDATED}. They either identify the participant or can only

View File

@ -4,7 +4,7 @@ import { PureComponent } from 'react';
import { isLocalParticipantModerator } from '../../base/participants'; import { isLocalParticipantModerator } from '../../base/participants';
import { setKnockingParticipantApproval } from '../actions'; import { setKnockingParticipantApproval } from '../actions';
import { getLobbyState } from '../functions'; import { getKnockingParticipants, getLobbyEnabled } from '../functions';
export type Props = { export type Props = {
@ -67,7 +67,8 @@ export default class AbstractKnockingParticipantList<P: Props = Props> extends P
* @returns {Props} * @returns {Props}
*/ */
export function mapStateToProps(state: Object): $Shape<Props> { export function mapStateToProps(state: Object): $Shape<Props> {
const { knockingParticipants, lobbyEnabled } = getLobbyState(state); const lobbyEnabled = getLobbyEnabled(state);
const knockingParticipants = getKnockingParticipants(state);
return { return {
_participants: knockingParticipants, _participants: knockingParticipants,

View File

@ -1,15 +1,24 @@
// @flow // @flow
/** /**
* Selector to return lobby state. * Selector to return lobby enable state.
* *
* @param {any} state - State object. * @param {any} state - State object.
* @returns {any} * @returns {boolean}
*/ */
export function getLobbyState(state: any) { export function getLobbyEnabled(state: any) {
return state['features/lobby']; return state['features/lobby'].lobbyEnabled;
} }
/**
* Selector to return a list of knocking participants.
*
* @param {any} state - State object.
* @returns {Array<Object>}
*/
export function getKnockingParticipants(state: any) {
return state['features/lobby'].knockingParticipants;
}
/** /**
* Selector to return array with knocking participant ids. * Selector to return array with knocking participant ids.
@ -18,7 +27,5 @@ export function getLobbyState(state: any) {
* @returns {Array} * @returns {Array}
*/ */
export function getKnockingParticipantsById(state: any) { export function getKnockingParticipantsById(state: any) {
const { knockingParticipants } = state['features/lobby']; return getKnockingParticipants(state).map(participant => participant.id);
return knockingParticipants.map(participant => participant.id);
} }

View File

@ -7,7 +7,7 @@ import { Button, withTheme } from 'react-native-paper';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { admitMultiple } from '../../../lobby/actions.native'; import { admitMultiple } from '../../../lobby/actions.native';
import { getLobbyState } from '../../../lobby/functions'; import { getKnockingParticipants, getLobbyEnabled } from '../../../lobby/functions';
import { LobbyParticipantItem } from './LobbyParticipantItem'; import { LobbyParticipantItem } from './LobbyParticipantItem';
import styles from './styles'; import styles from './styles';
@ -21,10 +21,9 @@ type Props = {
}; };
const LobbyParticipantList = ({ theme }: Props) => { const LobbyParticipantList = ({ theme }: Props) => {
const { const lobbyEnabled = useSelector(getLobbyEnabled);
lobbyEnabled, const participants = useSelector(getKnockingParticipants);
knockingParticipants: participants
} = useSelector(getLobbyState);
const dispatch = useDispatch(); const dispatch = useDispatch();
const admitAll = useCallback(() => const admitAll = useCallback(() =>
dispatch(admitMultiple(participants)), dispatch(admitMultiple(participants)),

View File

@ -11,7 +11,7 @@ import { Icon, IconInviteMore } from '../../../base/icons';
import { import {
getLocalParticipant, getLocalParticipant,
getParticipantCountWithFake, getParticipantCountWithFake,
getRemoteParticipants getSortedParticipants
} from '../../../base/participants'; } from '../../../base/participants';
import { connect } from '../../../base/redux'; import { connect } from '../../../base/redux';
import { doInvitePeople } from '../../../invite/actions.native'; import { doInvitePeople } from '../../../invite/actions.native';
@ -35,11 +35,9 @@ type Props = {
const MeetingParticipantList = ({ _localVideoOwner }: Props) => { const MeetingParticipantList = ({ _localVideoOwner }: Props) => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const items = [];
const localParticipant = useSelector(getLocalParticipant);
const onInvite = useCallback(() => dispatch(doInvitePeople()), [ dispatch ]); const onInvite = useCallback(() => dispatch(doInvitePeople()), [ dispatch ]);
const participants = useSelector(getRemoteParticipants);
const participantsCount = useSelector(getParticipantCountWithFake); const participantsCount = useSelector(getParticipantCountWithFake);
const sortedParticipants = useSelector(getSortedParticipants);
const showInviteButton = useSelector(shouldRenderInviteButton); const showInviteButton = useSelector(shouldRenderInviteButton);
const { t } = useTranslation(); const { t } = useTranslation();
@ -73,12 +71,6 @@ const MeetingParticipantList = ({ _localVideoOwner }: Props) => {
); );
}; };
items.push(renderParticipant(localParticipant));
participants.forEach(p => {
items.push(renderParticipant(p));
});
return ( return (
<View style = { styles.meetingList }> <View style = { styles.meetingList }>
<Text style = { styles.meetingListDescription }> <Text style = { styles.meetingListDescription }>
@ -100,7 +92,7 @@ const MeetingParticipantList = ({ _localVideoOwner }: Props) => {
onPress = { onInvite } onPress = { onInvite }
style = { styles.inviteButton } /> style = { styles.inviteButton } />
} }
{ items } { sortedParticipants.map(renderParticipant) }
</View> </View>
); );
}; };

View File

@ -7,7 +7,7 @@ import { useSelector, useDispatch } from 'react-redux';
import { withPixelLineHeight } from '../../../base/styles/functions.web'; import { withPixelLineHeight } from '../../../base/styles/functions.web';
import { admitMultiple } from '../../../lobby/actions.web'; import { admitMultiple } from '../../../lobby/actions.web';
import { getLobbyState } from '../../../lobby/functions'; import { getKnockingParticipants, getLobbyEnabled } from '../../../lobby/functions';
import { LobbyParticipantItem } from './LobbyParticipantItem'; import { LobbyParticipantItem } from './LobbyParticipantItem';
@ -32,10 +32,9 @@ const useStyles = makeStyles(theme => {
export const LobbyParticipantList = () => { export const LobbyParticipantList = () => {
const { const lobbyEnabled = useSelector(getLobbyEnabled);
lobbyEnabled, const participants = useSelector(getKnockingParticipants);
knockingParticipants: participants
} = useSelector(getLobbyState);
const { t } = useTranslation(); const { t } = useTranslation();
const classes = useStyles(); const classes = useStyles();
const dispatch = useDispatch(); const dispatch = useDispatch();

View File

@ -6,9 +6,8 @@ import { useSelector, useDispatch } from 'react-redux';
import { openDialog } from '../../../base/dialog'; import { openDialog } from '../../../base/dialog';
import { import {
getLocalParticipant,
getParticipantCountWithFake, getParticipantCountWithFake,
getRemoteParticipants getSortedParticipantIds
} from '../../../base/participants'; } from '../../../base/participants';
import MuteRemoteParticipantDialog from '../../../video-menu/components/web/MuteRemoteParticipantDialog'; import MuteRemoteParticipantDialog from '../../../video-menu/components/web/MuteRemoteParticipantDialog';
import { findStyledAncestor, shouldRenderInviteButton } from '../../functions'; import { findStyledAncestor, shouldRenderInviteButton } from '../../functions';
@ -46,8 +45,7 @@ const initialState = Object.freeze(Object.create(null));
export function MeetingParticipantList() { export function MeetingParticipantList() {
const dispatch = useDispatch(); const dispatch = useDispatch();
const isMouseOverMenu = useRef(false); const isMouseOverMenu = useRef(false);
const participants = useSelector(getRemoteParticipants); const sortedParticipantIds = useSelector(getSortedParticipantIds);
const localParticipant = useSelector(getLocalParticipant);
// This is very important as getRemoteParticipants is not changing its reference object // This is very important as getRemoteParticipants is not changing its reference object
// and we will not re-render on change, but if count changes we will do // and we will not re-render on change, but if count changes we will do
@ -130,19 +128,12 @@ export function MeetingParticipantList() {
youText = { youText } /> youText = { youText } />
); );
const items = [];
localParticipant && items.push(renderParticipant(localParticipant?.id));
participants.forEach(p => {
items.push(renderParticipant(p?.id));
});
return ( return (
<> <>
<Heading>{t('participantsPane.headings.participantsList', { count: participantsCount })}</Heading> <Heading>{t('participantsPane.headings.participantsList', { count: participantsCount })}</Heading>
{showInviteButton && <InviteButton />} {showInviteButton && <InviteButton />}
<div> <div>
{ items } {sortedParticipantIds.map(renderParticipant)}
</div> </div>
<MeetingParticipantContextMenu <MeetingParticipantContextMenu
muteAudio = { muteAudio } muteAudio = { muteAudio }