fix(follow-me) Make follow me work with stage filmstrip (#11306)

On follow me enabled all participants will see the participants pinned by the moderator
Fix pinned indicator to work when stage filmstrip is disabled
Fix add participant on dominant speaker change: if the participant was already pinned keep it as pinned
Don’t add local participant on stage (on automatic selection)
This commit is contained in:
Robert Pintilii 2022-04-05 16:00:32 +03:00 committed by GitHub
parent ed9b85f287
commit d7c8164b74
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 55 additions and 8 deletions

View File

@ -5,7 +5,9 @@ import React from 'react';
import { useSelector } from 'react-redux';
import { IconPinParticipant } from '../../../base/icons';
import { getParticipantById } from '../../../base/participants';
import { BaseIndicator } from '../../../base/react';
import { getPinnedActiveParticipants, isStageFilmstripEnabled } from '../../functions.web';
/**
* The type of the React {@code Component} props of {@link PinnedIndicator}.
@ -52,11 +54,12 @@ const PinnedIndicator = ({
participantId,
tooltipPosition
}: Props) => {
const isPinned = useSelector(state => state['features/filmstrip'].activeParticipants)
.find(p => p.id === participantId && p.pinned);
const stageFilmstrip = useSelector(isStageFilmstripEnabled);
const pinned = useSelector(state => getParticipantById(state, participantId))?.pinned;
const isPinned = useSelector(getPinnedActiveParticipants).find(p => p.participantId === participantId);
const styles = useStyles();
if (!isPinned) {
if ((stageFilmstrip && !isPinned) || (!stageFilmstrip && !pinned)) {
return null;
}

View File

@ -670,6 +670,18 @@ export function getActiveParticipantsIds(state) {
return activeParticipants.map(p => p.participantId);
}
/**
* Gets the ids of the active participants.
*
* @param {Object} state - Redux state.
* @returns {Array<string>}
*/
export function getPinnedActiveParticipants(state) {
const { activeParticipants } = state['features/filmstrip'];
return activeParticipants.filter(p => p.pinned);
}
/**
* Get whether or not the stage filmstrip should be displayed.
*

View File

@ -36,7 +36,7 @@ import {
updateRemoteParticipantsOnLeave
} from './functions';
import './subscriber';
import { getActiveParticipantsIds, isStageFilmstripEnabled } from './functions.web';
import { getActiveParticipantsIds, getPinnedActiveParticipants, isStageFilmstripEnabled } from './functions.web';
/**
* Map of timers.
@ -187,9 +187,16 @@ MiddlewareRegistry.register(store => next => action => {
const state = store.getState();
const stageFilmstrip = isStageFilmstripEnabled(state);
const currentLayout = getCurrentLayout(state);
const local = getLocalParticipant(state);
if (id === local.id) {
break;
}
if (stageFilmstrip && currentLayout === LAYOUTS.VERTICAL_FILMSTRIP_VIEW) {
store.dispatch(addStageParticipant(id));
const isPinned = getPinnedActiveParticipants(state).some(p => p.participantId === id);
store.dispatch(addStageParticipant(id, Boolean(isPinned)));
}
break;
}

View File

@ -1,5 +1,7 @@
// @flow
import _ from 'lodash';
import { CONFERENCE_WILL_JOIN } from '../base/conference/actionTypes';
import {
getParticipantById,
@ -9,6 +11,7 @@ import {
} from '../base/participants';
import { MiddlewareRegistry } from '../base/redux';
import { setFilmstripVisible } from '../filmstrip';
import { addStageParticipant } from '../filmstrip/actions.web';
import { setTileView } from '../video-layout';
import {
@ -178,6 +181,14 @@ function _onFollowMeCommand(attributes = {}, id, store) {
} else if (typeof idOfParticipantToPin === 'undefined' && pinnedParticipant) {
store.dispatch(pinParticipant(null));
}
if (attributes.pinnedStageParticipants !== undefined) {
const stageParticipants = JSON.parse(attributes.pinnedStageParticipants);
if (!_.isEqual(stageParticipants, oldState.pinnedStageParticipants)) {
stageParticipants.forEach(p => store.dispatch(addStageParticipant(p.participantId, true)));
}
}
}
/**

View File

@ -6,6 +6,7 @@ import {
isLocalParticipantModerator
} from '../base/participants';
import { StateListenerRegistry } from '../base/redux';
import { getPinnedActiveParticipants, isStageFilmstripEnabled } from '../filmstrip/functions.web';
import { shouldDisplayTileView } from '../video-layout/functions';
import { FOLLOW_ME_COMMAND } from './constants';
@ -51,6 +52,16 @@ StateListenerRegistry.register(
/* selector */ state => state['features/filmstrip'].visible,
/* listener */ _sendFollowMeCommand);
/**
* Subscribes to changes to the stage filmstrip participants.
*/
StateListenerRegistry.register(
/* selector */ getPinnedActiveParticipants,
/* listener */ _sendFollowMeCommand,
{
deepEquals: true
});
/**
* Subscribes to changes to the tile view setting in the user interface of the
* local participant.
@ -68,10 +79,12 @@ StateListenerRegistry.register(
*/
function _getFollowMeState(state) {
const pinnedParticipant = getPinnedParticipant(state);
const stageFilmstrip = isStageFilmstripEnabled(state);
return {
filmstripVisible: state['features/filmstrip'].visible,
nextOnStage: pinnedParticipant && pinnedParticipant.id,
nextOnStage: stageFilmstrip ? undefined : pinnedParticipant && pinnedParticipant.id,
pinnedStageParticipants: stageFilmstrip ? JSON.stringify(getPinnedActiveParticipants(state)) : undefined,
sharedDocumentVisible: state['features/etherpad'].editing,
tileViewEnabled: shouldDisplayTileView(state)
};

View File

@ -98,10 +98,11 @@ StateListenerRegistry.register(
* Updates the receiver constraints when the stage participants change.
*/
StateListenerRegistry.register(
state => getActiveParticipantsIds(state).sort()
.join(),
state => getActiveParticipantsIds(state).sort(),
(_, store) => {
_updateReceiverVideoConstraints(store);
}, {
deepEquals: true
}
);