您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

reducer.js 7.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. // @flow
  2. import { randomHexString } from 'js-utils/random';
  3. import { ReducerRegistry, set } from '../redux';
  4. import {
  5. DOMINANT_SPEAKER_CHANGED,
  6. PARTICIPANT_ID_CHANGED,
  7. PARTICIPANT_JOINED,
  8. PARTICIPANT_LEFT,
  9. PARTICIPANT_UPDATED,
  10. PIN_PARTICIPANT,
  11. SET_LOADABLE_AVATAR_URL
  12. } from './actionTypes';
  13. import { LOCAL_PARTICIPANT_DEFAULT_ID, PARTICIPANT_ROLE } from './constants';
  14. /**
  15. * Participant object.
  16. * @typedef {Object} Participant
  17. * @property {string} id - Participant ID.
  18. * @property {string} name - Participant name.
  19. * @property {string} avatar - Path to participant avatar if any.
  20. * @property {string} role - Participant role.
  21. * @property {boolean} local - If true, participant is local.
  22. * @property {boolean} pinned - If true, participant is currently a
  23. * "PINNED_ENDPOINT".
  24. * @property {boolean} dominantSpeaker - If this participant is the dominant
  25. * speaker in the (associated) conference, {@code true}; otherwise,
  26. * {@code false}.
  27. * @property {string} email - Participant email.
  28. */
  29. declare var APP: Object;
  30. /**
  31. * The participant properties which cannot be updated through
  32. * {@link PARTICIPANT_UPDATED}. They either identify the participant or can only
  33. * be modified through property-dedicated actions.
  34. *
  35. * @type {string[]}
  36. */
  37. const PARTICIPANT_PROPS_TO_OMIT_WHEN_UPDATE = [
  38. // The following properties identify the participant:
  39. 'conference',
  40. 'id',
  41. 'local',
  42. // The following properties can only be modified through property-dedicated
  43. // actions:
  44. 'dominantSpeaker',
  45. 'pinned'
  46. ];
  47. /**
  48. * Listen for actions which add, remove, or update the set of participants in
  49. * the conference.
  50. *
  51. * @param {Participant[]} state - List of participants to be modified.
  52. * @param {Object} action - Action object.
  53. * @param {string} action.type - Type of action.
  54. * @param {Participant} action.participant - Information about participant to be
  55. * added/removed/modified.
  56. * @returns {Participant[]}
  57. */
  58. ReducerRegistry.register('features/base/participants', (state = [], action) => {
  59. switch (action.type) {
  60. case SET_LOADABLE_AVATAR_URL:
  61. case DOMINANT_SPEAKER_CHANGED:
  62. case PARTICIPANT_ID_CHANGED:
  63. case PARTICIPANT_UPDATED:
  64. case PIN_PARTICIPANT:
  65. return state.map(p => _participant(p, action));
  66. case PARTICIPANT_JOINED:
  67. return [ ...state, _participantJoined(action) ];
  68. case PARTICIPANT_LEFT: {
  69. // XXX A remote participant is uniquely identified by their id in a
  70. // specific JitsiConference instance. The local participant is uniquely
  71. // identified by the very fact that there is only one local participant
  72. // (and the fact that the local participant "joins" at the beginning of
  73. // the app and "leaves" at the end of the app).
  74. const { conference, id } = action.participant;
  75. return state.filter(p =>
  76. !(
  77. p.id === id
  78. // XXX Do not allow collisions in the IDs of the local
  79. // participant and a remote participant cause the removal of
  80. // the local participant when the remote participant's
  81. // removal is requested.
  82. && p.conference === conference
  83. && (conference || p.local)));
  84. }
  85. }
  86. return state;
  87. });
  88. /**
  89. * Reducer function for a single participant.
  90. *
  91. * @param {Participant|undefined} state - Participant to be modified.
  92. * @param {Object} action - Action object.
  93. * @param {string} action.type - Type of action.
  94. * @param {Participant} action.participant - Information about participant to be
  95. * added/modified.
  96. * @param {JitsiConference} action.conference - Conference instance.
  97. * @private
  98. * @returns {Participant}
  99. */
  100. function _participant(state: Object = {}, action) {
  101. switch (action.type) {
  102. case DOMINANT_SPEAKER_CHANGED:
  103. // Only one dominant speaker is allowed.
  104. return (
  105. set(state, 'dominantSpeaker', state.id === action.participant.id));
  106. case PARTICIPANT_ID_CHANGED: {
  107. // A participant is identified by an id-conference pair. Only the local
  108. // participant is with an undefined conference.
  109. const { conference } = action;
  110. if (state.id === action.oldValue
  111. && state.conference === conference
  112. && (conference || state.local)) {
  113. return {
  114. ...state,
  115. id: action.newValue
  116. };
  117. }
  118. break;
  119. }
  120. case SET_LOADABLE_AVATAR_URL:
  121. case PARTICIPANT_UPDATED: {
  122. const { participant } = action; // eslint-disable-line no-shadow
  123. let { id } = participant;
  124. const { local } = participant;
  125. if (!id && local) {
  126. id = LOCAL_PARTICIPANT_DEFAULT_ID;
  127. }
  128. if (state.id === id) {
  129. const newState = { ...state };
  130. for (const key in participant) {
  131. if (participant.hasOwnProperty(key)
  132. && PARTICIPANT_PROPS_TO_OMIT_WHEN_UPDATE.indexOf(key)
  133. === -1) {
  134. newState[key] = participant[key];
  135. }
  136. }
  137. return newState;
  138. }
  139. break;
  140. }
  141. case PIN_PARTICIPANT:
  142. // Currently, only one pinned participant is allowed.
  143. return set(state, 'pinned', state.id === action.participant.id);
  144. }
  145. return state;
  146. }
  147. /**
  148. * Reduces a specific redux action of type {@link PARTICIPANT_JOINED} in the
  149. * feature base/participants.
  150. *
  151. * @param {Action} action - The redux action of type {@code PARTICIPANT_JOINED}
  152. * to reduce.
  153. * @private
  154. * @returns {Object} The new participant derived from the payload of the
  155. * specified {@code action} to be added into the redux state of the feature
  156. * base/participants after the reduction of the specified
  157. * {@code action}.
  158. */
  159. function _participantJoined({ participant }) {
  160. const {
  161. avatarURL,
  162. botType,
  163. connectionStatus,
  164. dominantSpeaker,
  165. email,
  166. isFakeParticipant,
  167. loadableAvatarUrl,
  168. local,
  169. name,
  170. pinned,
  171. presence,
  172. role
  173. } = participant;
  174. let { avatarID, conference, id } = participant;
  175. if (local) {
  176. // avatarID
  177. //
  178. // TODO Get the avatarID of the local participant from localStorage.
  179. avatarID || (avatarID = randomHexString(32));
  180. // conference
  181. //
  182. // XXX The local participant is not identified in association with a
  183. // JitsiConference because it is identified by the very fact that it is
  184. // the local participant.
  185. conference = undefined;
  186. // id
  187. id || (id = LOCAL_PARTICIPANT_DEFAULT_ID);
  188. }
  189. return {
  190. avatarID,
  191. avatarURL,
  192. botType,
  193. conference,
  194. connectionStatus,
  195. dominantSpeaker: dominantSpeaker || false,
  196. email,
  197. id,
  198. isFakeParticipant,
  199. loadableAvatarUrl,
  200. local: local || false,
  201. name,
  202. pinned: pinned || false,
  203. presence,
  204. role: role || PARTICIPANT_ROLE.NONE
  205. };
  206. }