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

actions.js 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. /* global interfaceConfig */
  2. import throttle from 'lodash/throttle';
  3. import { set } from '../redux';
  4. import { showNotification } from '../../notifications';
  5. import {
  6. DOMINANT_SPEAKER_CHANGED,
  7. KICK_PARTICIPANT,
  8. MUTE_REMOTE_PARTICIPANT,
  9. PARTICIPANT_DISPLAY_NAME_CHANGED,
  10. PARTICIPANT_ID_CHANGED,
  11. PARTICIPANT_JOINED,
  12. PARTICIPANT_LEFT,
  13. PARTICIPANT_UPDATED,
  14. PIN_PARTICIPANT
  15. } from './actionTypes';
  16. import { MAX_DISPLAY_NAME_LENGTH } from './constants';
  17. import { getLocalParticipant } from './functions';
  18. /**
  19. * Create an action for when dominant speaker changes.
  20. *
  21. * @param {string} id - Participant's ID.
  22. * @param {JitsiConference} conference - The {@code JitsiConference} associated
  23. * with the participant identified by the specified {@code id}. Only the local
  24. * participant is allowed to not specify an associated {@code JitsiConference}
  25. * instance.
  26. * @returns {{
  27. * type: DOMINANT_SPEAKER_CHANGED,
  28. * participant: {
  29. * conference: JitsiConference,
  30. * id: string
  31. * }
  32. * }}
  33. */
  34. export function dominantSpeakerChanged(id, conference) {
  35. return {
  36. type: DOMINANT_SPEAKER_CHANGED,
  37. participant: {
  38. conference,
  39. id
  40. }
  41. };
  42. }
  43. /**
  44. * Create an action for removing a participant from the conference.
  45. *
  46. * @param {string} id - Participant's ID.
  47. * @returns {{
  48. * type: KICK_PARTICIPANT,
  49. * id: string
  50. * }}
  51. */
  52. export function kickParticipant(id) {
  53. return {
  54. type: KICK_PARTICIPANT,
  55. id
  56. };
  57. }
  58. /**
  59. * Creates an action to signal the connection status of the local participant
  60. * has changed.
  61. *
  62. * @param {string} connectionStatus - The current connection status of the local
  63. * participant, as enumerated by the library's participantConnectionStatus
  64. * constants.
  65. * @returns {Function}
  66. */
  67. export function localParticipantConnectionStatusChanged(connectionStatus) {
  68. return (dispatch, getState) => {
  69. const participant = getLocalParticipant(getState);
  70. if (participant) {
  71. return dispatch(participantConnectionStatusChanged(
  72. participant.id,
  73. connectionStatus));
  74. }
  75. };
  76. }
  77. /**
  78. * Action to signal that the ID of local participant has changed. It happens
  79. * when the local participant joins a new conference or leaves an existing
  80. * conference.
  81. *
  82. * @param {string} id - New ID for local participant.
  83. * @returns {Function}
  84. */
  85. export function localParticipantIdChanged(id) {
  86. return (dispatch, getState) => {
  87. const participant = getLocalParticipant(getState);
  88. if (participant) {
  89. return dispatch({
  90. type: PARTICIPANT_ID_CHANGED,
  91. // XXX A participant is identified by an id-conference pair.
  92. // Only the local participant is with an undefined conference.
  93. conference: undefined,
  94. newValue: id,
  95. oldValue: participant.id
  96. });
  97. }
  98. };
  99. }
  100. /**
  101. * Action to signal that a local participant has joined.
  102. *
  103. * @param {Participant} participant={} - Information about participant.
  104. * @returns {{
  105. * type: PARTICIPANT_JOINED,
  106. * participant: Participant
  107. * }}
  108. */
  109. export function localParticipantJoined(participant = {}) {
  110. return participantJoined(set(participant, 'local', true));
  111. }
  112. /**
  113. * Action to remove a local participant.
  114. *
  115. * @returns {Function}
  116. */
  117. export function localParticipantLeft() {
  118. return (dispatch, getState) => {
  119. const participant = getLocalParticipant(getState);
  120. if (participant) {
  121. return (
  122. dispatch(
  123. participantLeft(
  124. participant.id,
  125. // XXX Only the local participant is allowed to leave
  126. // without stating the JitsiConference instance because
  127. // the local participant is uniquely identified by the
  128. // very fact that there is only one local participant
  129. // (and the fact that the local participant "joins" at
  130. // the beginning of the app and "leaves" at the end of
  131. // the app).
  132. undefined)));
  133. }
  134. };
  135. }
  136. /**
  137. * Action to signal the role of the local participant has changed. It can happen
  138. * when the participant has joined a conference, even before a non-default local
  139. * id has been set, or after a moderator leaves.
  140. *
  141. * @param {string} role - The new role of the local participant.
  142. * @returns {Function}
  143. */
  144. export function localParticipantRoleChanged(role) {
  145. return (dispatch, getState) => {
  146. const participant = getLocalParticipant(getState);
  147. if (participant) {
  148. return dispatch(participantRoleChanged(participant.id, role));
  149. }
  150. };
  151. }
  152. /**
  153. * Create an action for muting another participant in the conference.
  154. *
  155. * @param {string} id - Participant's ID.
  156. * @returns {{
  157. * type: MUTE_REMOTE_PARTICIPANT,
  158. * id: string
  159. * }}
  160. */
  161. export function muteRemoteParticipant(id) {
  162. return {
  163. type: MUTE_REMOTE_PARTICIPANT,
  164. id
  165. };
  166. }
  167. /**
  168. * Action to update a participant's connection status.
  169. *
  170. * @param {string} id - Participant's ID.
  171. * @param {string} connectionStatus - The new connection status of the
  172. * participant.
  173. * @returns {{
  174. * type: PARTICIPANT_UPDATED,
  175. * participant: {
  176. * connectionStatus: string,
  177. * id: string
  178. * }
  179. * }}
  180. */
  181. export function participantConnectionStatusChanged(id, connectionStatus) {
  182. return {
  183. type: PARTICIPANT_UPDATED,
  184. participant: {
  185. connectionStatus,
  186. id
  187. }
  188. };
  189. }
  190. /**
  191. * Action to signal that a participant's display name has changed.
  192. *
  193. * @param {string} id - The id of the participant being changed.
  194. * @param {string} displayName - The new display name.
  195. * @returns {{
  196. * type: PARTICIPANT_DISPLAY_NAME_CHANGED,
  197. * id: string,
  198. * name: string
  199. * }}
  200. */
  201. export function participantDisplayNameChanged(id, displayName = '') {
  202. // FIXME Do not use this action over participantUpdated. This action exists
  203. // as a a bridge for local name updates. Once other components responsible
  204. // for updating the local user's display name are in react/redux, this
  205. // action should be replaceable with the participantUpdated action.
  206. return {
  207. type: PARTICIPANT_DISPLAY_NAME_CHANGED,
  208. id,
  209. name: displayName.substr(0, MAX_DISPLAY_NAME_LENGTH)
  210. };
  211. }
  212. /**
  213. * Action to signal that a participant has joined.
  214. *
  215. * @param {Participant} participant - Information about participant.
  216. * @returns {{
  217. * type: PARTICIPANT_JOINED,
  218. * participant: Participant
  219. * }}
  220. */
  221. export function participantJoined(participant) {
  222. // Only the local participant is not identified with an id-conference pair.
  223. if (participant.local) {
  224. return {
  225. type: PARTICIPANT_JOINED,
  226. participant
  227. };
  228. }
  229. // In other words, a remote participant is identified with an id-conference
  230. // pair.
  231. const { conference } = participant;
  232. if (!conference) {
  233. throw Error(
  234. 'A remote participant must be associated with a JitsiConference!');
  235. }
  236. return (dispatch, getState) => {
  237. // A remote participant is only expected to join in a joined or joining
  238. // conference. The following check is really necessary because a
  239. // JitsiConference may have moved into leaving but may still manage to
  240. // sneak a PARTICIPANT_JOINED in if its leave is delayed for any purpose
  241. // (which is not outragous given that leaving involves network
  242. // requests.)
  243. const stateFeaturesBaseConference
  244. = getState()['features/base/conference'];
  245. if (conference === stateFeaturesBaseConference.conference
  246. || conference === stateFeaturesBaseConference.joining) {
  247. return dispatch({
  248. type: PARTICIPANT_JOINED,
  249. participant
  250. });
  251. }
  252. };
  253. }
  254. /**
  255. * Action to signal that a participant has left.
  256. *
  257. * @param {string} id - Participant's ID.
  258. * @param {JitsiConference} conference - The {@code JitsiConference} associated
  259. * with the participant identified by the specified {@code id}. Only the local
  260. * participant is allowed to not specify an associated {@code JitsiConference}
  261. * instance.
  262. * @returns {{
  263. * type: PARTICIPANT_LEFT,
  264. * participant: {
  265. * conference: JitsiConference,
  266. * id: string
  267. * }
  268. * }}
  269. */
  270. export function participantLeft(id, conference) {
  271. return {
  272. type: PARTICIPANT_LEFT,
  273. participant: {
  274. conference,
  275. id
  276. }
  277. };
  278. }
  279. /**
  280. * Action to signal that a participant's presence status has changed.
  281. *
  282. * @param {string} id - Participant's ID.
  283. * @param {string} presence - Participant's new presence status.
  284. * @returns {{
  285. * type: PARTICIPANT_UPDATED,
  286. * participant: {
  287. * id: string,
  288. * presence: string
  289. * }
  290. * }}
  291. */
  292. export function participantPresenceChanged(id, presence) {
  293. return participantUpdated({
  294. id,
  295. presence
  296. });
  297. }
  298. /**
  299. * Action to signal that a participant's role has changed.
  300. *
  301. * @param {string} id - Participant's ID.
  302. * @param {PARTICIPANT_ROLE} role - Participant's new role.
  303. * @returns {{
  304. * type: PARTICIPANT_UPDATED,
  305. * participant: {
  306. * id: string,
  307. * role: PARTICIPANT_ROLE
  308. * }
  309. * }}
  310. */
  311. export function participantRoleChanged(id, role) {
  312. return participantUpdated({
  313. id,
  314. role
  315. });
  316. }
  317. /**
  318. * Action to signal that some of participant properties has been changed.
  319. *
  320. * @param {Participant} participant={} - Information about participant. To
  321. * identify the participant the object should contain either property id with
  322. * value the id of the participant or property local with value true (if the
  323. * local participant hasn't joined the conference yet).
  324. * @returns {{
  325. * type: PARTICIPANT_UPDATED,
  326. * participant: Participant
  327. * }}
  328. */
  329. export function participantUpdated(participant = {}) {
  330. return {
  331. type: PARTICIPANT_UPDATED,
  332. participant
  333. };
  334. }
  335. /**
  336. * Create an action which pins a conference participant.
  337. *
  338. * @param {string|null} id - The ID of the conference participant to pin or null
  339. * if none of the conference's participants are to be pinned.
  340. * @returns {{
  341. * type: PIN_PARTICIPANT,
  342. * participant: {
  343. * id: string
  344. * }
  345. * }}
  346. */
  347. export function pinParticipant(id) {
  348. return {
  349. type: PIN_PARTICIPANT,
  350. participant: {
  351. id
  352. }
  353. };
  354. }
  355. /**
  356. * An array of names of participants that have joined the conference. The array
  357. * is replaced with an empty array as notifications are displayed.
  358. *
  359. * @private
  360. * @type {string[]}
  361. */
  362. let joinedParticipantsNames = [];
  363. /**
  364. * A throttled internal function that takes the internal list of participant
  365. * names, {@code joinedParticipantsNames}, and triggers the display of a
  366. * notification informing of their joining.
  367. *
  368. * @private
  369. * @type {Function}
  370. */
  371. const _throttledNotifyParticipantConnected = throttle(dispatch => {
  372. const joinedParticipantsCount = joinedParticipantsNames.length;
  373. let notificationProps;
  374. if (joinedParticipantsCount >= 3) {
  375. notificationProps = {
  376. titleArguments: {
  377. name: joinedParticipantsNames[0],
  378. count: joinedParticipantsCount - 1
  379. },
  380. titleKey: 'notify.connectedThreePlusMembers'
  381. };
  382. } else if (joinedParticipantsCount === 2) {
  383. notificationProps = {
  384. titleArguments: {
  385. first: joinedParticipantsNames[0],
  386. second: joinedParticipantsNames[1]
  387. },
  388. titleKey: 'notify.connectedTwoMembers'
  389. };
  390. } else if (joinedParticipantsCount) {
  391. notificationProps = {
  392. titleArguments: {
  393. name: joinedParticipantsNames[0]
  394. },
  395. titleKey: 'notify.connectedOneMember'
  396. };
  397. }
  398. if (notificationProps) {
  399. dispatch(
  400. showNotification(notificationProps, 2500));
  401. }
  402. joinedParticipantsNames = [];
  403. }, 500, { leading: false });
  404. /**
  405. * Queues the display of a notification of a participant having connected to
  406. * the meeting. The notifications are batched so that quick consecutive
  407. * connection events are shown in one notification.
  408. *
  409. * @param {string} displayName - The name of the participant that connected.
  410. * @returns {Function}
  411. */
  412. export function showParticipantJoinedNotification(displayName) {
  413. joinedParticipantsNames.push(
  414. displayName || interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME);
  415. return dispatch => _throttledNotifyParticipantConnected(dispatch);
  416. }