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 13KB

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