123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236 |
- // @flow
-
- import i18next from 'i18next';
- import _ from 'lodash';
- import type { Dispatch } from 'redux';
-
- import {
- conferenceLeft,
- conferenceWillLeave,
- createConference,
- getCurrentConference
- } from '../base/conference';
- import { setAudioMuted, setVideoMuted } from '../base/media';
- import { getRemoteParticipants } from '../base/participants';
- import { clearNotifications } from '../notifications';
-
- import {
- getBreakoutRooms,
- getMainRoom
- } from './functions';
- import logger from './logger';
-
- declare var APP: Object;
-
- /**
- * Action to create a breakout room.
- *
- * @param {string} name - Name / subject for the breakout room.
- * @returns {Function}
- */
- export function createBreakoutRoom(name?: string) {
- return (dispatch: Dispatch<any>, getState: Function) => {
- const rooms = getBreakoutRooms(getState);
-
- // TODO: remove this once we add UI to customize the name.
- const index = Object.keys(rooms).length;
- const subject = name || i18next.t('breakoutRooms.defaultName', { index });
-
- // $FlowExpectedError
- getCurrentConference(getState)?.getBreakoutRooms()
- ?.createBreakoutRoom(subject);
- };
- }
-
- /**
- * Action to close a room and send participants to the main room.
- *
- * @param {string} roomId - The id of the room to close.
- * @returns {Function}
- */
- export function closeBreakoutRoom(roomId: string) {
- return (dispatch: Dispatch<any>, getState: Function) => {
- const rooms = getBreakoutRooms(getState);
- const room = rooms[roomId];
- const mainRoom = getMainRoom(getState);
-
- if (room && mainRoom) {
- Object.values(room.participants).forEach(p => {
-
- // $FlowExpectedError
- dispatch(sendParticipantToRoom(p.jid, mainRoom.id));
- });
- }
- };
- }
-
- /**
- * Action to remove a breakout room.
- *
- * @param {string} breakoutRoomJid - The jid of the breakout room to remove.
- * @returns {Function}
- */
- export function removeBreakoutRoom(breakoutRoomJid: string) {
- return (dispatch: Dispatch<any>, getState: Function) => {
- // $FlowExpectedError
- getCurrentConference(getState)?.getBreakoutRooms()
- ?.removeBreakoutRoom(breakoutRoomJid);
- };
- }
-
- /**
- * Action to auto-assign the participants to breakout rooms.
- *
- * @returns {Function}
- */
- export function autoAssignToBreakoutRooms() {
- return (dispatch: Dispatch<any>, getState: Function) => {
- const rooms = getBreakoutRooms(getState);
- const breakoutRooms = _.filter(rooms, (room: Object) => !room.isMainRoom);
-
- if (breakoutRooms) {
- const participantIds = Array.from(getRemoteParticipants(getState).keys());
- const length = Math.ceil(participantIds.length / breakoutRooms.length);
-
- _.chunk(_.shuffle(participantIds), length).forEach((group, index) =>
- group.forEach(participantId => {
- dispatch(sendParticipantToRoom(participantId, breakoutRooms[index].id));
- })
- );
- }
- };
- }
-
- /**
- * Action to send a participant to a room.
- *
- * @param {string} participantId - The participant id.
- * @param {string} roomId - The room id.
- * @returns {Function}
- */
- export function sendParticipantToRoom(participantId: string, roomId: string) {
- return (dispatch: Dispatch<any>, getState: Function) => {
- const rooms = getBreakoutRooms(getState);
- const room = rooms[roomId];
-
- if (!room) {
- logger.warn(`Invalid room: ${roomId}`);
-
- return;
- }
-
- // Get the full JID of the participant. We could be getting the endpoint ID or
- // a participant JID. We want to find the connection JID.
- const participantJid = _findParticipantJid(getState, participantId);
-
- if (!participantJid) {
- logger.warn(`Could not find participant ${participantId}`);
-
- return;
- }
-
- // $FlowExpectedError
- getCurrentConference(getState)?.getBreakoutRooms()
- ?.sendParticipantToRoom(participantJid, room.jid);
- };
- }
-
- /**
- * Action to move to a room.
- *
- * @param {string} roomId - The room id to move to. If omitted move to the main room.
- * @returns {Function}
- */
- export function moveToRoom(roomId?: string) {
- return (dispatch: Dispatch<any>, getState: Function) => {
- let _roomId = roomId || getMainRoom(getState)?.id;
-
- // Check if we got a full JID.
- // $FlowExpectedError
- if (_roomId?.indexOf('@') !== -1) {
- // $FlowExpectedError
- const [ id, ...domainParts ] = _roomId.split('@');
-
- // On mobile we first store the room and the connection is created
- // later, so let's attach the domain to the room String object as
- // a little hack.
-
- // eslint-disable-next-line no-new-wrappers
- _roomId = new String(id);
-
- // $FlowExpectedError
- _roomId.domain = domainParts.join('@');
- }
-
- if (navigator.product === 'ReactNative') {
- const conference = getCurrentConference(getState);
- const { audio, video } = getState()['features/base/media'];
-
- dispatch(conferenceWillLeave(conference));
- conference.leave()
- .catch(error => {
- logger.warn(
- 'JitsiConference.leave() rejected with:',
- error);
-
- dispatch(conferenceLeft(conference));
- });
- dispatch(clearNotifications());
-
- // dispatch(setRoom(_roomId));
- dispatch(createConference(_roomId));
- dispatch(setAudioMuted(audio.muted));
- dispatch(setVideoMuted(video.muted));
- } else {
- APP.conference.leaveRoom()
- .finally(() => APP.conference.joinRoom(_roomId));
- }
- };
- }
-
- /**
- * Finds a participant's connection JID given its ID.
- *
- * @param {Function} getState - The redux store state getter.
- * @param {string} participantId - ID of the given participant.
- * @returns {string|undefined} - The participant connection JID if found.
- */
- function _findParticipantJid(getState: Function, participantId: string) {
- const conference = getCurrentConference(getState);
-
- if (!conference) {
- return;
- }
-
- // Get the full JID of the participant. We could be getting the endpoint ID or
- // a participant JID. We want to find the connection JID.
- let _participantId = participantId;
- let participantJid;
-
- if (!participantId.includes('@')) {
- const p = conference.getParticipantById(participantId);
-
- // $FlowExpectedError
- _participantId = p?.getJid(); // This will be the room JID.
- }
-
- if (_participantId) {
- const rooms = getBreakoutRooms(getState);
-
- for (const room of Object.values(rooms)) {
- // $FlowExpectedError
- const participants = room.participants || {};
- const p = participants[_participantId]
-
- // $FlowExpectedError
- || Object.values(participants).find(item => item.jid === _participantId);
-
- if (p) {
- participantJid = p.jid;
- break;
- }
- }
- }
-
- return participantJid;
- }
|