Newer
Older
import Spinner from '@atlaskit/spinner';
import type { Dispatch } from 'redux';
import { connect } from 'react-redux';
import { push } from 'react-router-redux';
import i18n from '../../../i18n';
import { getSetting, setEmail, setName } from '../../settings';
import { conferenceEnded, conferenceJoined } from '../actions';
import JitsiMeetExternalAPI from '../external_api';
import { LoadingIndicator, Wrapper } from '../styled';
/**
* Redux dispatch.
*/
dispatch: Dispatch<*>;
/**
* AlwaysOnTop Window Enabled.
*/
_alwaysOnTopWindowEnabled: boolean;
/**
* Email of user.
*/
_email: string;
/**
* Name of user.
*/
_name: string;
/**
* Default Jitsi Server URL.
*/
_serverURL: string;
/**
* Default Jitsi Server Timeout.
*/
_serverTimeout: number;
/**
* Start with Audio Muted.
*/
_startWithAudioMuted: boolean;
/**
* Start with Video Muted.
*/
_startWithVideoMuted: boolean;
type State = {
/**
* If the conference is loading or not.
*/
isLoading: boolean;
};
class Conference extends Component<Props, State> {
/**
* External API object.
*/
_api: Object;
/**
* Conference Object.
*/
_conference: Object;
/**
* Timer to cancel the joining if it takes too long.
*/
_loadTimer: ?TimeoutID;
/**
* Reference to the element of this component.
*/
_ref: Object;
* Initializes a new {@code Conference} instance.
*
* @inheritdoc
*/
constructor() {
super();
this.state = {
isLoading: true
};
this._onIframeLoad = this._onIframeLoad.bind(this);
this._onVideoConferenceEnded = this._onVideoConferenceEnded.bind(this);
}
/**
* Attach the script to this component.
*/
componentDidMount() {
const room = this.props.location.state.room;
const serverTimeout = this.props._serverTimeout || config.defaultServerTimeout;
const serverURL = this.props.location.state.serverURL
this._conference = {
room,
serverURL
};
// Set a timer for a timeout duration, if we haven't loaded the iframe by then,
// give up.
this._loadTimer = setTimeout(() => {
this._navigateToHome(
// $FlowFixMe
{
error: 'Loading error',
type: 'error'
},
room,
serverURL);
}
/**
* Keep profile settings in sync with Conference.
*
* @param {Props} prevProps - Component's prop values before update.
* @returns {void}
*/
componentDidUpdate(prevProps) {
const { props } = this;
if (props._email !== prevProps._email) {
this._setEmail(props._email);
}
if (props._name !== prevProps._name) {
this._setName(props._name);
}
}
if (this._loadTimer) {
clearTimeout(this._loadTimer);
}
if (this._api) {
this._api.dispose();
}
}
* Implements React's {@link Component#render()}.
return (
<Wrapper innerRef = { this._ref }>
{ this._maybeRenderLoadingIndicator() }
</Wrapper>
);
}
/**
* Load the conference by creating the iframe element in this component
* and attaching utils from jitsi-meet-electron-utils.
const url = new URL(this._conference.room, this._conference.serverURL);
const roomName = url.pathname.split('/').pop();
const host = this._conference.serverURL.replace(/https?:\/\//, '');
const searchParameters = Object.fromEntries(url.searchParams);
const locale = { lng: i18n.language };
const urlParameters = {
...searchParameters,
...locale
};
const configOverwrite = {
startWithAudioMuted: this.props._startWithAudioMuted,
startWithVideoMuted: this.props._startWithVideoMuted
};
onload: this._onIframeLoad,
roomName
};
this._api = new JitsiMeetExternalAPI(host, {
...options,
...urlParameters
this._api.on('suspendDetected', this._onVideoConferenceEnded);
this._api.on('readyToClose', this._onVideoConferenceEnded);
this._api.on('videoConferenceJoined',
(conferenceInfo: Object) => {
this.props.dispatch(conferenceJoined(this._conference));
this._onVideoConferenceJoined(conferenceInfo);
}
);
const { RemoteControl,
setupScreenSharingRender,
setupAlwaysOnTopRender,
initPopupsConfigurationRender,
setupWiFiStats,
setupPowerMonitorRender
} = window.jitsiNodeAPI.jitsiMeetElectronUtils;
setupScreenSharingRender(this._api);
new RemoteControl(iframe); // eslint-disable-line no-new
// Allow window to be on top if enabled in settings
if (this.props._alwaysOnTopWindowEnabled) {
setupAlwaysOnTopRender(this._api);
}
setupWiFiStats(iframe);
setupPowerMonitorRender(this._api);
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
/**
* It renders a loading indicator, if appropriate.
*
* @returns {?ReactElement}
*/
_maybeRenderLoadingIndicator() {
if (this.state.isLoading) {
return (
<LoadingIndicator>
<Spinner size = 'large' />
</LoadingIndicator>
);
}
}
/**
* Navigates to home screen (Welcome).
*
* @param {Event} event - Event by which the function is called.
* @param {string} room - Room name.
* @param {string} serverURL - Server URL.
* @returns {void}
*/
_navigateToHome(event: Event, room: ?string, serverURL: ?string) {
this.props.dispatch(push('/', {
error: event.type === 'error',
room,
serverURL
}));
}
_onVideoConferenceEnded: (*) => void;
/**
* Dispatches conference ended and navigates to home screen.
*
* @param {Event} event - Event by which the function is called.
* @returns {void}
* @private
*/
_onVideoConferenceEnded(event: Event) {
this.props.dispatch(conferenceEnded(this._conference));
this._navigateToHome(event);
}
/**
* Updates redux state's user name from conference.
*
* @param {Object} params - Returned object from event.
* @param {string} id - Local Participant ID.
* @returns {void}
*/
_onDisplayNameChange(params: Object, id: string) {
if (params.id === id) {
this.props.dispatch(setName(params.displayname));
}
/**
* Updates redux state's email from conference.
*
* @param {Object} params - Returned object from event.
* @param {string} id - Local Participant ID.
* @returns {void}
*/
_onEmailChange(params: Object, id: string) {
if (params.id === id) {
this.props.dispatch(setEmail(params.email));
}
}
_onIframeLoad: (*) => void;
* Sets state of loading to false when iframe has completely loaded.
*
* @returns {void}
*/
_onIframeLoad() {
if (this._loadTimer) {
clearTimeout(this._loadTimer);
this._loadTimer = null;
}
this.setState({
isLoading: false
});
/**
* Saves conference info on joining it.
*
* @param {Object} conferenceInfo - Contains information about the current
* conference.
* @returns {void}
*/
_onVideoConferenceJoined(conferenceInfo: Object) {
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
this._setEmail(this.props._email);
this._setName(this.props._name);
const { id } = conferenceInfo;
this._api.on('displayNameChange',
(params: Object) => this._onDisplayNameChange(params, id));
this._api.on('emailChange',
(params: Object) => this._onEmailChange(params, id));
}
/**
* Set email from settings to conference.
*
* @param {string} email - Email of user.
* @returns {void}
*/
_setEmail(email: string) {
this._api.executeCommand('email', email);
}
/**
* Set name from settings to conference.
*
* @param {string} name - Name of user.
* @returns {void}
*/
_setName(name: string) {
this._api.executeCommand('displayName', name);
}
}
/**
* Maps (parts of) the redux state to the React props.
*
* @param {Object} state - The redux state.
*/
function _mapStateToProps(state: Object) {
return {
_alwaysOnTopWindowEnabled: getSetting(state, 'alwaysOnTopWindowEnabled', true),
_email: state.settings.email,
_serverURL: state.settings.serverURL,
_serverTimeout: state.settings.serverTimeout,
_startWithAudioMuted: state.settings.startWithAudioMuted,
_startWithVideoMuted: state.settings.startWithVideoMuted
export default connect(_mapStateToProps)(Conference);