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

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