2016-12-05 15:14:50 +00:00
|
|
|
import { ReducerRegistry, setStateProperty } from '../redux';
|
2017-02-28 23:12:02 +00:00
|
|
|
import { randomHexString } from '../util';
|
2016-10-05 14:36:59 +00:00
|
|
|
|
|
|
|
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".
|
2016-11-04 18:28:47 +00:00
|
|
|
* @property {boolean} dominantSpeaker - If this participant is the dominant
|
|
|
|
* speaker in the (associated) conference, <tt>true</tt>; otherwise,
|
|
|
|
* <tt>false</tt>.
|
2016-10-05 14:36:59 +00:00
|
|
|
* @property {string} email - Participant email.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* These properties should not be bulk assigned when updating a particular
|
|
|
|
* @see Participant.
|
|
|
|
* @type {string[]}
|
|
|
|
*/
|
|
|
|
const PARTICIPANT_PROPS_TO_OMIT_WHEN_UPDATE
|
2016-11-04 18:28:47 +00:00
|
|
|
= [ 'dominantSpeaker', 'id', 'local', 'pinned' ];
|
2016-10-05 14:36:59 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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.
|
2017-01-28 23:28:13 +00:00
|
|
|
* @private
|
2016-10-05 14:36:59 +00:00
|
|
|
* @returns {Participant|undefined}
|
|
|
|
*/
|
2017-01-28 23:28:13 +00:00
|
|
|
function _participant(state, action) {
|
2016-10-05 14:36:59 +00:00
|
|
|
switch (action.type) {
|
|
|
|
case DOMINANT_SPEAKER_CHANGED:
|
|
|
|
// Only one dominant speaker is allowed.
|
2016-11-04 18:28:47 +00:00
|
|
|
return (
|
2016-12-05 15:14:50 +00:00
|
|
|
setStateProperty(
|
2016-11-04 18:28:47 +00:00
|
|
|
state,
|
|
|
|
'dominantSpeaker',
|
|
|
|
state.id === action.participant.id));
|
2016-10-05 14:36:59 +00:00
|
|
|
|
|
|
|
case PARTICIPANT_ID_CHANGED:
|
|
|
|
if (state.id === action.oldValue) {
|
2017-02-28 23:12:02 +00:00
|
|
|
return {
|
2016-10-05 14:36:59 +00:00
|
|
|
...state,
|
2017-02-28 23:12:02 +00:00
|
|
|
id: action.newValue
|
2016-10-05 14:36:59 +00:00
|
|
|
};
|
|
|
|
}
|
2016-11-04 18:28:47 +00:00
|
|
|
break;
|
2016-10-05 14:36:59 +00:00
|
|
|
|
|
|
|
case PARTICIPANT_JOINED: {
|
|
|
|
const participant = action.participant; // eslint-disable-line no-shadow
|
2017-03-29 09:26:46 +00:00
|
|
|
const {
|
|
|
|
avatarURL,
|
2017-04-05 09:01:57 +00:00
|
|
|
connectionStatus,
|
2017-03-29 09:26:46 +00:00
|
|
|
dominantSpeaker,
|
|
|
|
email,
|
|
|
|
local,
|
|
|
|
pinned,
|
|
|
|
role
|
|
|
|
} = participant;
|
2017-02-28 23:12:02 +00:00
|
|
|
let { avatarID, id, name } = participant;
|
|
|
|
|
|
|
|
// avatarID
|
|
|
|
//
|
|
|
|
// TODO Get the avatarID of the local participant from localStorage.
|
|
|
|
if (!avatarID && local) {
|
|
|
|
avatarID = randomHexString(32);
|
|
|
|
}
|
2017-03-07 16:50:17 +00:00
|
|
|
|
|
|
|
// id
|
|
|
|
//
|
2016-10-05 14:36:59 +00:00
|
|
|
// XXX The situation of not having an ID for a remote participant should
|
|
|
|
// not happen. Maybe we should raise an error in this case or generate a
|
|
|
|
// random ID.
|
2017-03-07 16:50:17 +00:00
|
|
|
if (!id && local) {
|
|
|
|
id = LOCAL_PARTICIPANT_DEFAULT_ID;
|
|
|
|
}
|
|
|
|
|
|
|
|
// name
|
|
|
|
if (!name) {
|
|
|
|
// TODO Get the from config and/or localized.
|
|
|
|
name = local ? 'me' : 'Fellow Jitster';
|
|
|
|
}
|
|
|
|
|
2017-02-28 23:12:02 +00:00
|
|
|
return {
|
|
|
|
avatarID,
|
|
|
|
avatarURL,
|
2017-04-05 09:01:57 +00:00
|
|
|
connectionStatus,
|
2017-03-07 16:50:17 +00:00
|
|
|
dominantSpeaker: dominantSpeaker || false,
|
2017-02-27 21:42:28 +00:00
|
|
|
email,
|
2016-10-05 14:36:59 +00:00
|
|
|
id,
|
2017-03-07 16:50:17 +00:00
|
|
|
local: local || false,
|
2016-10-05 14:36:59 +00:00
|
|
|
name,
|
2017-03-07 16:50:17 +00:00
|
|
|
pinned: pinned || false,
|
|
|
|
role: role || PARTICIPANT_ROLE.NONE
|
2016-10-05 14:36:59 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2017-03-07 16:50:17 +00:00
|
|
|
case PARTICIPANT_UPDATED: {
|
|
|
|
const participant = action.participant; // eslint-disable-line no-shadow
|
2017-03-23 18:01:33 +00:00
|
|
|
const { local } = participant;
|
|
|
|
let { id } = participant;
|
|
|
|
|
|
|
|
if (!id && local) {
|
|
|
|
id = LOCAL_PARTICIPANT_DEFAULT_ID;
|
|
|
|
}
|
2017-03-07 16:50:17 +00:00
|
|
|
|
|
|
|
if (state.id === id) {
|
2016-10-05 14:36:59 +00:00
|
|
|
const newState = { ...state };
|
|
|
|
|
2017-03-07 16:50:17 +00:00
|
|
|
for (const key in participant) {
|
|
|
|
if (participant.hasOwnProperty(key)
|
2016-10-05 14:36:59 +00:00
|
|
|
&& PARTICIPANT_PROPS_TO_OMIT_WHEN_UPDATE.indexOf(key)
|
|
|
|
=== -1) {
|
2017-03-07 16:50:17 +00:00
|
|
|
newState[key] = participant[key];
|
2016-10-05 14:36:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return newState;
|
|
|
|
}
|
2016-11-04 18:28:47 +00:00
|
|
|
break;
|
2017-03-07 16:50:17 +00:00
|
|
|
}
|
2016-10-05 14:36:59 +00:00
|
|
|
|
|
|
|
case PIN_PARTICIPANT:
|
|
|
|
// Currently, only one pinned participant is allowed.
|
2016-11-04 18:28:47 +00:00
|
|
|
return (
|
2016-12-05 15:14:50 +00:00
|
|
|
setStateProperty(
|
2016-11-04 18:28:47 +00:00
|
|
|
state,
|
|
|
|
'pinned',
|
|
|
|
state.id === action.participant.id));
|
2016-10-05 14:36:59 +00:00
|
|
|
}
|
2016-11-04 18:28:47 +00:00
|
|
|
|
|
|
|
return state;
|
2016-10-05 14:36:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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 PARTICIPANT_JOINED:
|
2017-01-28 23:28:13 +00:00
|
|
|
return [ ...state, _participant(undefined, action) ];
|
2016-10-05 14:36:59 +00:00
|
|
|
|
|
|
|
case PARTICIPANT_LEFT:
|
|
|
|
return state.filter(p => p.id !== action.participant.id);
|
|
|
|
|
|
|
|
case DOMINANT_SPEAKER_CHANGED:
|
|
|
|
case PARTICIPANT_ID_CHANGED:
|
|
|
|
case PARTICIPANT_UPDATED:
|
|
|
|
case PIN_PARTICIPANT:
|
2017-01-28 23:28:13 +00:00
|
|
|
return state.map(p => _participant(p, action));
|
2016-10-05 14:36:59 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
return state;
|
|
|
|
}
|
|
|
|
});
|