diff --git a/conference.js b/conference.js index f6e10fa14..73a3efe83 100644 --- a/conference.js +++ b/conference.js @@ -1662,6 +1662,7 @@ export default { const displayName = user.getDisplayName(); APP.store.dispatch(participantJoined({ + botType: user.getBotType(), conference: room, id, name: displayName, @@ -1862,6 +1863,17 @@ export default { APP.UI.changeDisplayName(id, formattedDisplayName); } ); + room.on( + JitsiConferenceEvents.BOT_TYPE_CHANGED, + (id, botType) => { + + APP.store.dispatch(participantUpdated({ + conference: room, + id, + botType + })); + } + ); room.on( JitsiConferenceEvents.LOCK_STATE_CHANGED, diff --git a/css/ringing/_ringing.scss b/css/ringing/_ringing.scss index b04093a78..a0a1e4753 100644 --- a/css/ringing/_ringing.scss +++ b/css/ringing/_ringing.scss @@ -6,12 +6,10 @@ height: 100%; position: fixed; z-index: $ringingZ; - background: linear-gradient(transparent, #000); - opacity: 0.8; + @include transparentBg(#283447, 0.95); &.solidBG { background: $defaultBackground; - opacity: 1; } &__content { @@ -22,20 +20,26 @@ top: 50%; margin-left: -200px; margin-top: -125px; - font-weight: 400; - font-size: 14px; text-align: center; + font-weight: normal; + color: #FFFFFF; } &__avatar { - width: 100px; - height: 100px; + width: 128px; + height: 128px; border-radius: 50%; + border: 2px solid #1B2638; } - &__caller-info { - .mention { - color: #333; - } + &__status{ + margin-top: 15px; + font-size: 14px; + line-height: 20px; + } + + &__name { + font-size: 24px; + line-height: 32px; } } diff --git a/lang/main.json b/lang/main.json index c9d59f8f9..974d5f62d 100644 --- a/lang/main.json +++ b/lang/main.json @@ -632,12 +632,12 @@ }, "presenceStatus": { "invited": "Invited", - "ringing": "Ringing", - "calling": "Calling", - "initializingCall": "Initializing Call", + "ringing": "Ringing...", + "calling": "Calling...", + "initializingCall": "Initializing Call...", "connected": "Connected", - "connecting": "Connecting", - "connecting2": "Connecting*", + "connecting": "Connecting...", + "connecting2": "Connecting*...", "disconnected": "Disconnected", "busy": "Busy", "rejected": "Rejected", diff --git a/modules/API/API.js b/modules/API/API.js index 01b438af1..312567a10 100644 --- a/modules/API/API.js +++ b/modules/API/API.js @@ -113,8 +113,10 @@ function initCommands() { switch (name) { case 'invite': + // The store should be already available because API.init is called + // on appWillMount action. APP.store.dispatch( - invite(request.invitees)) + invite(request.invitees, true)) .then(failedInvitees => { let error; let result; diff --git a/modules/API/external/external_api.js b/modules/API/external/external_api.js index 69fe24daf..bd00355df 100644 --- a/modules/API/external/external_api.js +++ b/modules/API/external/external_api.js @@ -238,7 +238,7 @@ export default class JitsiMeetExternalAPI extends EventEmitter { } }) }); - this._invitees = invitees; + this.invite(invitees); this._isLargeVideoVisible = true; this._numberOfParticipants = 0; this._participants = {}; @@ -369,9 +369,6 @@ export default class JitsiMeetExternalAPI extends EventEmitter { switch (name) { case 'video-conference-joined': - if (this._invitees) { - this.invite(this._invitees); - } this._myUserID = userID; this._participants[userID] = { avatarURL: data.avatarURL diff --git a/modules/UI/UI.js b/modules/UI/UI.js index bc3e371c4..d5fd3c512 100644 --- a/modules/UI/UI.js +++ b/modules/UI/UI.js @@ -492,7 +492,10 @@ UI.updateUserRole = user => { * @param {string} status - The new status. */ UI.updateUserStatus = (user, status) => { - if (!status) { + const reduxState = APP.store.getState() || {}; + const { calleeInfoVisible } = reduxState['features/invite'] || {}; + + if (!status || calleeInfoVisible) { return; } diff --git a/modules/UI/videolayout/LargeVideoManager.js b/modules/UI/videolayout/LargeVideoManager.js index 40da7bbd7..0ca80102b 100644 --- a/modules/UI/videolayout/LargeVideoManager.js +++ b/modules/UI/videolayout/LargeVideoManager.js @@ -428,7 +428,12 @@ export default class LargeVideoManager { ReactDOM.render( - + , presenceLabelContainer.get(0)); diff --git a/modules/UI/videolayout/RemoteVideo.js b/modules/UI/videolayout/RemoteVideo.js index b99cf61fe..85645b504 100644 --- a/modules/UI/videolayout/RemoteVideo.js +++ b/modules/UI/videolayout/RemoteVideo.js @@ -573,7 +573,12 @@ RemoteVideo.prototype.addPresenceLabel = function() { ReactDOM.render( - + , presenceLabelContainer); diff --git a/react/features/base/conference/actions.js b/react/features/base/conference/actions.js index ff86b55cb..330168c27 100644 --- a/react/features/base/conference/actions.js +++ b/react/features/base/conference/actions.js @@ -144,6 +144,7 @@ function _addConferenceListeners(conference, dispatch) { conference.on( JitsiConferenceEvents.USER_JOINED, (id, user) => !user.isHidden() && dispatch(participantJoined({ + botType: user.getBotType(), conference, id, name: user.getDisplayName(), @@ -161,6 +162,14 @@ function _addConferenceListeners(conference, dispatch) { JitsiConferenceEvents.USER_STATUS_CHANGED, (...args) => dispatch(participantPresenceChanged(...args))); + conference.on( + JitsiConferenceEvents.BOT_TYPE_CHANGED, + (id, botType) => dispatch(participantUpdated({ + conference, + id, + botType + }))); + conference.addCommandListener( AVATAR_ID_COMMAND, (data, id) => dispatch(participantUpdated({ diff --git a/react/features/base/jwt/actionTypes.js b/react/features/base/jwt/actionTypes.js index dbc221df9..c95ee71c1 100644 --- a/react/features/base/jwt/actionTypes.js +++ b/react/features/base/jwt/actionTypes.js @@ -1,13 +1,3 @@ -/** - * The type of redux action which sets the visibility of {@code CalleeInfo}. - * - * { - * type: SET_CALLEE_INFO_VISIBLE, - * calleeInfoVisible: boolean - * } - */ -export const SET_CALLEE_INFO_VISIBLE = Symbol('SET_CALLEE_INFO_VISIBLE'); - /** * The type of redux action which stores a specific JSON Web Token (JWT) into * the redux store. diff --git a/react/features/base/jwt/actions.js b/react/features/base/jwt/actions.js index 99eb6116f..4067cf8c5 100644 --- a/react/features/base/jwt/actions.js +++ b/react/features/base/jwt/actions.js @@ -1,28 +1,6 @@ // @flow -import { SET_CALLEE_INFO_VISIBLE, SET_JWT } from './actionTypes'; - -/** - * Sets the visibility of {@code CalleeInfo}. - * - * @param {boolean|undefined} [calleeInfoVisible] - If {@code CalleeInfo} is - * to be displayed/visible, then {@code true}; otherwise, {@code false} or - * {@code undefined}. - * @returns {{ - * type: SET_CALLEE_INFO_VISIBLE, - * calleeInfoVisible: (boolean|undefined) - * }} - */ -export function setCalleeInfoVisible(calleeInfoVisible: ?boolean) { - return (dispatch: Dispatch<*>, getState: Function) => { - getState()['features/base/jwt'] - .calleeInfoVisible === calleeInfoVisible - || dispatch({ - type: SET_CALLEE_INFO_VISIBLE, - calleeInfoVisible - }); - }; -} +import { SET_JWT } from './actionTypes'; /** * Stores a specific JSON Web Token (JWT) into the redux store. diff --git a/react/features/base/jwt/components/CalleeInfo.js b/react/features/base/jwt/components/CalleeInfo.js deleted file mode 100644 index 199d9a725..000000000 --- a/react/features/base/jwt/components/CalleeInfo.js +++ /dev/null @@ -1,347 +0,0 @@ -// @flow - -import React, { Component } from 'react'; -import { connect } from 'react-redux'; - -import { Audio } from '../../media'; -import { Avatar } from '../../participants'; -import { Container, Text } from '../../react'; -import UIEvents from '../../../../../service/UI/UIEvents'; - -import styles from './styles'; - -declare var $: Object; -declare var APP: Object; -declare var interfaceConfig: Object; - -/** - * The type of the React {@code Component} props of {@link CalleeInfo}. - */ -type Props = { - - /** - * The callee's information such as avatar and display name. - */ - _callee: Object -}; - -/** - * The type of the React {@code Component} state of {@link CalleeInfo}. - */ -type State = { - - /** - * The CSS class (name), if any, to add to this {@code CalleeInfo}. - * - * @type {string} - */ - className: ?string, - - /** - * The indicator which determines whether this {@code CalleeInfo} - * should play/render audio to indicate the ringing phase of the - * call establishment between the local participant and the - * associated remote callee. - * - * @type {boolean} - */ - renderAudio: boolean, - - /** - * The indicator which determines whether this {@code CalleeInfo} - * is depicting the ringing phase of the call establishment between - * the local participant and the associated remote callee or the - * phase afterwards when the callee has not answered the call for a - * period of time and, consequently, is considered unavailable. - * - * @type {boolean} - */ - ringing: boolean -}; - -/** - * Implements a React {@link Component} which depicts the establishment of a - * call with a specific remote callee. - * - * @extends Component - */ -class CalleeInfo extends Component { - /** - * The (reference to the) {@link Audio} which plays/renders the audio - * depicting the ringing phase of the call establishment represented by this - * {@code CalleeInfo}. - */ - _audio: ?Audio; - - _onLargeVideoAvatarVisible: Function; - - _playAudioInterval: ?IntervalID; - - _ringingTimeout: ?TimeoutID; - - _setAudio: Function; - - /** - * Initializes a new {@code CalleeInfo} instance. - * - * @param {Object} props - The read-only React {@link Component} props with - * which the new instance is to be initialized. - */ - constructor(props) { - super(props); - - this.state = { - className: undefined, - renderAudio: - typeof interfaceConfig !== 'object' - || !interfaceConfig.DISABLE_RINGING, - ringing: true - }; - - this._onLargeVideoAvatarVisible - = this._onLargeVideoAvatarVisible.bind(this); - this._setAudio = this._setAudio.bind(this); - - if (typeof APP === 'object') { - APP.UI.addListener( - UIEvents.LARGE_VIDEO_AVATAR_VISIBLE, - this._onLargeVideoAvatarVisible); - } - } - - /** - * Sets up timeouts such as the timeout to end the ringing phase of the call - * establishment depicted by this {@code CalleeInfo}. - * - * @inheritdoc - */ - componentDidMount() { - // Set up the timeout to end the ringing phase of the call establishment - // depicted by this CalleeInfo. - if (this.state.ringing && !this._ringingTimeout) { - this._ringingTimeout - = setTimeout( - () => { - this._pauseAudio(); - - this._ringingTimeout = undefined; - this.setState({ - ringing: false - }); - }, - 30000); - } - - this._playAudio(); - } - - /** - * Cleans up before this {@code Calleverlay} is unmounted and destroyed. - * - * @inheritdoc - */ - componentWillUnmount() { - this._pauseAudio(); - - if (this._ringingTimeout) { - clearTimeout(this._ringingTimeout); - this._ringingTimeout = undefined; - } - - if (typeof APP === 'object') { - APP.UI.removeListener( - UIEvents.LARGE_VIDEO_AVATAR_VISIBLE, - this._onLargeVideoAvatarVisible); - } - } - - /** - * Implements React's {@link Component#render()}. - * - * @inheritdoc - * @returns {ReactElement} - */ - render() { - const { className, ringing } = this.state; - const { avatarUrl, avatar, name } = this.props._callee; - - return ( - - - - { ringing ? 'Calling...' : '' } - - - - - { name } - { ringing ? '' : ' isn\'t available' } - - - - { this._renderAudio() } - - ); - } - - /** - * Notifies this {@code CalleeInfo} that the visibility of the - * participant's avatar in the large video has changed. - * - * @param {boolean} largeVideoAvatarVisible - If the avatar in the large - * video (i.e. of the participant on the stage) is visible, then - * {@code true}; otherwise, {@code false}. - * @private - * @returns {void} - */ - _onLargeVideoAvatarVisible(largeVideoAvatarVisible: boolean) { - this.setState({ - className: largeVideoAvatarVisible ? 'solidBG' : undefined - }); - } - - /** - * Stops the playback of the audio which represents the ringing phase of the - * call establishment depicted by this {@code CalleeInfo}. - * - * @private - * @returns {void} - */ - _pauseAudio() { - const audio = this._audio; - - if (audio) { - audio.pause(); - } - if (this._playAudioInterval) { - clearInterval(this._playAudioInterval); - this._playAudioInterval = undefined; - } - } - - /** - * Starts the playback of the audio which represents the ringing phase of - * the call establishment depicted by this {@code CalleeInfo}. - * - * @private - * @returns {void} - */ - _playAudio() { - if (this._audio) { - this._audio.play(); - if (!this._playAudioInterval) { - this._playAudioInterval - = setInterval(() => this._playAudio(), 5000); - } - } - } - - /** - * Renders an audio element to represent the ringing phase of the call - * establishment represented by this {@code CalleeInfo}. - * - * @private - * @returns {ReactElement} - */ - _renderAudio() { - if (this.state.renderAudio && this.state.ringing) { - return ( -