231 lines
6.8 KiB
JavaScript
231 lines
6.8 KiB
JavaScript
// @flow
|
|
|
|
import { randomHexString } from 'js-utils/random';
|
|
|
|
import { ReducerRegistry, set } from '../redux';
|
|
|
|
import {
|
|
DOMINANT_SPEAKER_CHANGED,
|
|
PARTICIPANT_ID_CHANGED,
|
|
PARTICIPANT_JOINED,
|
|
PARTICIPANT_LEFT,
|
|
PARTICIPANT_UPDATED,
|
|
PIN_PARTICIPANT
|
|
} from './actionTypes';
|
|
import { LOCAL_PARTICIPANT_DEFAULT_ID, PARTICIPANT_ROLE } from './constants';
|
|
|
|
/**
|
|
* Participant object.
|
|
* @typedef {Object} Participant
|
|
* @property {string} id - Participant ID.
|
|
* @property {string} name - Participant name.
|
|
* @property {string} avatar - Path to participant avatar if any.
|
|
* @property {string} role - Participant role.
|
|
* @property {boolean} local - If true, participant is local.
|
|
* @property {boolean} pinned - If true, participant is currently a
|
|
* "PINNED_ENDPOINT".
|
|
* @property {boolean} dominantSpeaker - If this participant is the dominant
|
|
* speaker in the (associated) conference, {@code true}; otherwise,
|
|
* {@code false}.
|
|
* @property {string} email - Participant email.
|
|
*/
|
|
|
|
declare var APP: Object;
|
|
|
|
/**
|
|
* The participant properties which cannot be updated through
|
|
* {@link PARTICIPANT_UPDATED}. They either identify the participant or can only
|
|
* be modified through property-dedicated actions.
|
|
*
|
|
* @type {string[]}
|
|
*/
|
|
const PARTICIPANT_PROPS_TO_OMIT_WHEN_UPDATE = [
|
|
|
|
// The following properties identify the participant:
|
|
'conference',
|
|
'id',
|
|
'local',
|
|
|
|
// The following properties can only be modified through property-dedicated
|
|
// actions:
|
|
'dominantSpeaker',
|
|
'pinned'
|
|
];
|
|
|
|
/**
|
|
* Listen for actions which add, remove, or update the set of participants in
|
|
* the conference.
|
|
*
|
|
* @param {Participant[]} state - List of participants to be modified.
|
|
* @param {Object} action - Action object.
|
|
* @param {string} action.type - Type of action.
|
|
* @param {Participant} action.participant - Information about participant to be
|
|
* added/removed/modified.
|
|
* @returns {Participant[]}
|
|
*/
|
|
ReducerRegistry.register('features/base/participants', (state = [], action) => {
|
|
switch (action.type) {
|
|
case DOMINANT_SPEAKER_CHANGED:
|
|
case PARTICIPANT_ID_CHANGED:
|
|
case PARTICIPANT_UPDATED:
|
|
case PIN_PARTICIPANT:
|
|
return state.map(p => _participant(p, action));
|
|
|
|
case PARTICIPANT_JOINED:
|
|
return [ ...state, _participantJoined(action) ];
|
|
|
|
case PARTICIPANT_LEFT: {
|
|
// XXX A remote participant is uniquely identified by their id in a
|
|
// specific JitsiConference instance. The local participant is uniquely
|
|
// identified by the very fact that there is only one local participant
|
|
// (and the fact that the local participant "joins" at the beginning of
|
|
// the app and "leaves" at the end of the app).
|
|
const { conference, id } = action.participant;
|
|
|
|
return state.filter(p =>
|
|
!(
|
|
p.id === id
|
|
|
|
// XXX Do not allow collisions in the IDs of the local
|
|
// participant and a remote participant cause the removal of
|
|
// the local participant when the remote participant's
|
|
// removal is requested.
|
|
&& p.conference === conference
|
|
&& (conference || p.local)));
|
|
}
|
|
}
|
|
|
|
return state;
|
|
});
|
|
|
|
/**
|
|
* Reducer function for a single participant.
|
|
*
|
|
* @param {Participant|undefined} state - Participant to be modified.
|
|
* @param {Object} action - Action object.
|
|
* @param {string} action.type - Type of action.
|
|
* @param {Participant} action.participant - Information about participant to be
|
|
* added/modified.
|
|
* @param {JitsiConference} action.conference - Conference instance.
|
|
* @private
|
|
* @returns {Participant}
|
|
*/
|
|
function _participant(state: Object = {}, action) {
|
|
switch (action.type) {
|
|
case DOMINANT_SPEAKER_CHANGED:
|
|
// Only one dominant speaker is allowed.
|
|
return (
|
|
set(state, 'dominantSpeaker', state.id === action.participant.id));
|
|
|
|
case PARTICIPANT_ID_CHANGED: {
|
|
// A participant is identified by an id-conference pair. Only the local
|
|
// participant is with an undefined conference.
|
|
const { conference } = action;
|
|
|
|
if (state.id === action.oldValue
|
|
&& state.conference === conference
|
|
&& (conference || state.local)) {
|
|
return {
|
|
...state,
|
|
id: action.newValue
|
|
};
|
|
}
|
|
break;
|
|
}
|
|
|
|
case PARTICIPANT_UPDATED: {
|
|
const { participant } = action; // eslint-disable-line no-shadow
|
|
let { id } = participant;
|
|
const { local } = participant;
|
|
|
|
if (!id && local) {
|
|
id = LOCAL_PARTICIPANT_DEFAULT_ID;
|
|
}
|
|
|
|
if (state.id === id) {
|
|
const newState = { ...state };
|
|
|
|
for (const key in participant) {
|
|
if (participant.hasOwnProperty(key)
|
|
&& PARTICIPANT_PROPS_TO_OMIT_WHEN_UPDATE.indexOf(key)
|
|
=== -1) {
|
|
newState[key] = participant[key];
|
|
}
|
|
}
|
|
|
|
return newState;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case PIN_PARTICIPANT:
|
|
// Currently, only one pinned participant is allowed.
|
|
return set(state, 'pinned', state.id === action.participant.id);
|
|
}
|
|
|
|
return state;
|
|
}
|
|
|
|
/**
|
|
* Reduces a specific redux action of type {@link PARTICIPANT_JOINED} in the
|
|
* feature base/participants.
|
|
*
|
|
* @param {Action} action - The redux action of type {@code PARTICIPANT_JOINED}
|
|
* to reduce.
|
|
* @private
|
|
* @returns {Object} The new participant derived from the payload of the
|
|
* specified {@code action} to be added into the redux state of the feature
|
|
* base/participants after the reduction of the specified
|
|
* {@code action}.
|
|
*/
|
|
function _participantJoined({ participant }) {
|
|
const {
|
|
avatarURL,
|
|
botType,
|
|
connectionStatus,
|
|
dominantSpeaker,
|
|
email,
|
|
isFakeParticipant,
|
|
local,
|
|
name,
|
|
pinned,
|
|
presence,
|
|
role
|
|
} = participant;
|
|
let { avatarID, conference, id } = participant;
|
|
|
|
if (local) {
|
|
// avatarID
|
|
//
|
|
// TODO Get the avatarID of the local participant from localStorage.
|
|
avatarID || (avatarID = randomHexString(32));
|
|
|
|
// conference
|
|
//
|
|
// XXX The local participant is not identified in association with a
|
|
// JitsiConference because it is identified by the very fact that it is
|
|
// the local participant.
|
|
conference = undefined;
|
|
|
|
// id
|
|
id || (id = LOCAL_PARTICIPANT_DEFAULT_ID);
|
|
}
|
|
|
|
return {
|
|
avatarID,
|
|
avatarURL,
|
|
botType,
|
|
conference,
|
|
connectionStatus,
|
|
dominantSpeaker: dominantSpeaker || false,
|
|
email,
|
|
id,
|
|
isFakeParticipant,
|
|
local: local || false,
|
|
name,
|
|
pinned: pinned || false,
|
|
presence,
|
|
role: role || PARTICIPANT_ROLE.NONE
|
|
};
|
|
}
|