You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

actions.js 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  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. newValue: id,
  92. oldValue: participant.id
  93. });
  94. }
  95. };
  96. }
  97. /**
  98. * Action to signal that a local participant has joined.
  99. *
  100. * @param {Participant} participant={} - Information about participant.
  101. * @returns {{
  102. * type: PARTICIPANT_JOINED,
  103. * participant: Participant
  104. * }}
  105. */
  106. export function localParticipantJoined(participant = {}) {
  107. return participantJoined(set(participant, 'local', true));
  108. }
  109. /**
  110. * Action to remove a local participant.
  111. *
  112. * @returns {Function}
  113. */
  114. export function localParticipantLeft() {
  115. return (dispatch, getState) => {
  116. const participant = getLocalParticipant(getState);
  117. if (participant) {
  118. return (
  119. dispatch(
  120. participantLeft(
  121. participant.id,
  122. // XXX Only the local participant is allowed to leave
  123. // without stating the JitsiConference instance because
  124. // the local participant is uniquely identified by the
  125. // very fact that there is only one local participant
  126. // (and the fact that the local participant "joins" at
  127. // the beginning of the app and "leaves" at the end of
  128. // the app).
  129. undefined)));
  130. }
  131. };
  132. }
  133. /**
  134. * Action to signal the role of the local participant has changed. It can happen
  135. * when the participant has joined a conference, even before a non-default local
  136. * id has been set, or after a moderator leaves.
  137. *
  138. * @param {string} role - The new role of the local participant.
  139. * @returns {Function}
  140. */
  141. export function localParticipantRoleChanged(role) {
  142. return (dispatch, getState) => {
  143. const participant = getLocalParticipant(getState);
  144. if (participant) {
  145. return dispatch(participantRoleChanged(participant.id, role));
  146. }
  147. };
  148. }
  149. /**
  150. * Create an action for muting another participant in the conference.
  151. *
  152. * @param {string} id - Participant's ID.
  153. * @returns {{
  154. * type: MUTE_REMOTE_PARTICIPANT,
  155. * id: string
  156. * }}
  157. */
  158. export function muteRemoteParticipant(id) {
  159. return {
  160. type: MUTE_REMOTE_PARTICIPANT,
  161. id
  162. };
  163. }
  164. /**
  165. * Action to update a participant's connection status.
  166. *
  167. * @param {string} id - Participant's ID.
  168. * @param {string} connectionStatus - The new connection status of the
  169. * participant.
  170. * @returns {{
  171. * type: PARTICIPANT_UPDATED,
  172. * participant: {
  173. * connectionStatus: string,
  174. * id: string
  175. * }
  176. * }}
  177. */
  178. export function participantConnectionStatusChanged(id, connectionStatus) {
  179. return {
  180. type: PARTICIPANT_UPDATED,
  181. participant: {
  182. connectionStatus,
  183. id
  184. }
  185. };
  186. }
  187. /**
  188. * Action to signal that a participant's display name has changed.
  189. *
  190. * @param {string} id - The id of the participant being changed.
  191. * @param {string} displayName - The new display name.
  192. * @returns {{
  193. * type: PARTICIPANT_DISPLAY_NAME_CHANGED,
  194. * id: string,
  195. * name: string
  196. * }}
  197. */
  198. export function participantDisplayNameChanged(id, displayName = '') {
  199. // FIXME Do not use this action over participantUpdated. This action exists
  200. // as a a bridge for local name updates. Once other components responsible
  201. // for updating the local user's display name are in react/redux, this
  202. // action should be replaceable with the participantUpdated action.
  203. return {
  204. type: PARTICIPANT_DISPLAY_NAME_CHANGED,
  205. id,
  206. name: displayName.substr(0, MAX_DISPLAY_NAME_LENGTH)
  207. };
  208. }
  209. /**
  210. * Action to signal that a participant has joined.
  211. *
  212. * @param {Participant} participant - Information about participant.
  213. * @returns {{
  214. * type: PARTICIPANT_JOINED,
  215. * participant: Participant
  216. * }}
  217. */
  218. export function participantJoined(participant) {
  219. if (!participant.local && !participant.conference) {
  220. throw Error(
  221. 'A remote participant must be associated with a JitsiConference!');
  222. }
  223. return {
  224. type: PARTICIPANT_JOINED,
  225. participant
  226. };
  227. }
  228. /**
  229. * Action to signal that a participant has left.
  230. *
  231. * @param {string} id - Participant's ID.
  232. * @param {JitsiConference} conference - The {@code JitsiConference} associated
  233. * with the participant identified by the specified {@code id}. Only the local
  234. * participant is allowed to not specify an associated {@code JitsiConference}
  235. * instance.
  236. * @returns {{
  237. * type: PARTICIPANT_LEFT,
  238. * participant: {
  239. * conference: JitsiConference,
  240. * id: string
  241. * }
  242. * }}
  243. */
  244. export function participantLeft(id, conference) {
  245. return {
  246. type: PARTICIPANT_LEFT,
  247. participant: {
  248. conference,
  249. id
  250. }
  251. };
  252. }
  253. /**
  254. * Action to signal that a participant's presence status has changed.
  255. *
  256. * @param {string} id - Participant's ID.
  257. * @param {string} presence - Participant's new presence status.
  258. * @returns {{
  259. * type: PARTICIPANT_UPDATED,
  260. * participant: {
  261. * id: string,
  262. * presence: string
  263. * }
  264. * }}
  265. */
  266. export function participantPresenceChanged(id, presence) {
  267. return participantUpdated({
  268. id,
  269. presence
  270. });
  271. }
  272. /**
  273. * Action to signal that a participant's role has changed.
  274. *
  275. * @param {string} id - Participant's ID.
  276. * @param {PARTICIPANT_ROLE} role - Participant's new role.
  277. * @returns {{
  278. * type: PARTICIPANT_UPDATED,
  279. * participant: {
  280. * id: string,
  281. * role: PARTICIPANT_ROLE
  282. * }
  283. * }}
  284. */
  285. export function participantRoleChanged(id, role) {
  286. return participantUpdated({
  287. id,
  288. role
  289. });
  290. }
  291. /**
  292. * Action to signal that some of participant properties has been changed.
  293. *
  294. * @param {Participant} participant={} - Information about participant. To
  295. * identify the participant the object should contain either property id with
  296. * value the id of the participant or property local with value true (if the
  297. * local participant hasn't joined the conference yet).
  298. * @returns {{
  299. * type: PARTICIPANT_UPDATED,
  300. * participant: Participant
  301. * }}
  302. */
  303. export function participantUpdated(participant = {}) {
  304. return {
  305. type: PARTICIPANT_UPDATED,
  306. participant
  307. };
  308. }
  309. /**
  310. * Create an action which pins a conference participant.
  311. *
  312. * @param {string|null} id - The ID of the conference participant to pin or null
  313. * if none of the conference's participants are to be pinned.
  314. * @returns {{
  315. * type: PIN_PARTICIPANT,
  316. * participant: {
  317. * id: string
  318. * }
  319. * }}
  320. */
  321. export function pinParticipant(id) {
  322. return {
  323. type: PIN_PARTICIPANT,
  324. participant: {
  325. id
  326. }
  327. };
  328. }
  329. /**
  330. * An array of names of participants that have joined the conference. The array
  331. * is replaced with an empty array as notifications are displayed.
  332. *
  333. * @private
  334. * @type {string[]}
  335. */
  336. let joinedParticipantsNames = [];
  337. /**
  338. * A throttled internal function that takes the internal list of participant
  339. * names, {@code joinedParticipantsNames}, and triggers the display of a
  340. * notification informing of their joining.
  341. *
  342. * @private
  343. * @type {Function}
  344. */
  345. const _throttledNotifyParticipantConnected = throttle(dispatch => {
  346. const joinedParticipantsCount = joinedParticipantsNames.length;
  347. let notificationProps;
  348. if (joinedParticipantsCount >= 3) {
  349. notificationProps = {
  350. titleArguments: {
  351. name: joinedParticipantsNames[0],
  352. count: joinedParticipantsCount - 1
  353. },
  354. titleKey: 'notify.connectedThreePlusMembers'
  355. };
  356. } else if (joinedParticipantsCount === 2) {
  357. notificationProps = {
  358. titleArguments: {
  359. first: joinedParticipantsNames[0],
  360. second: joinedParticipantsNames[1]
  361. },
  362. titleKey: 'notify.connectedTwoMembers'
  363. };
  364. } else if (joinedParticipantsCount) {
  365. notificationProps = {
  366. titleArguments: {
  367. name: joinedParticipantsNames[0]
  368. },
  369. titleKey: 'notify.connectedOneMember'
  370. };
  371. }
  372. if (notificationProps) {
  373. dispatch(
  374. showNotification(notificationProps, 2500));
  375. }
  376. joinedParticipantsNames = [];
  377. }, 500, { leading: false });
  378. /**
  379. * Queues the display of a notification of a participant having connected to
  380. * the meeting. The notifications are batched so that quick consecutive
  381. * connection events are shown in one notification.
  382. *
  383. * @param {string} displayName - The name of the participant that connected.
  384. * @returns {Function}
  385. */
  386. export function showParticipantJoinedNotification(displayName) {
  387. joinedParticipantsNames.push(
  388. displayName || interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME);
  389. return dispatch => _throttledNotifyParticipantConnected(dispatch);
  390. }