Flow, coding style
This commit is contained in:
parent
8a4e6a7ec0
commit
003eb68e28
|
@ -27,11 +27,11 @@ import {
|
|||
conferenceJoined,
|
||||
conferenceLeft,
|
||||
dataChannelOpened,
|
||||
toggleAudioOnly,
|
||||
EMAIL_COMMAND,
|
||||
lockStateChanged,
|
||||
p2pStatusChanged,
|
||||
setLocalParticipantData
|
||||
sendLocalParticipant,
|
||||
toggleAudioOnly
|
||||
} from './react/features/base/conference';
|
||||
import { updateDeviceList } from './react/features/base/devices';
|
||||
import {
|
||||
|
@ -1138,13 +1138,15 @@ export default {
|
|||
}
|
||||
},
|
||||
|
||||
_createRoom (localTracks) {
|
||||
room = connection.initJitsiConference(APP.conference.roomName,
|
||||
this._getConferenceOptions());
|
||||
_createRoom(localTracks) {
|
||||
room
|
||||
= connection.initJitsiConference(
|
||||
APP.conference.roomName,
|
||||
this._getConferenceOptions());
|
||||
this._setLocalAudioVideoStreams(localTracks);
|
||||
this._room = room; // FIXME do not use this
|
||||
|
||||
setLocalParticipantData(room, APP.store.getState());
|
||||
sendLocalParticipant(APP.store, room);
|
||||
|
||||
this._setupListeners();
|
||||
},
|
||||
|
|
|
@ -20,12 +20,17 @@ import Filmstrip from "./videolayout/Filmstrip";
|
|||
import SettingsMenu from "./side_pannels/settings/SettingsMenu";
|
||||
import Profile from "./side_pannels/profile/Profile";
|
||||
|
||||
import { updateDeviceList } from '../../react/features/base/devices';
|
||||
import { JitsiTrackErrors } from '../../react/features/base/lib-jitsi-meet';
|
||||
import {
|
||||
openDeviceSelectionDialog
|
||||
} from '../../react/features/device-selection';
|
||||
import { updateDeviceList } from '../../react/features/base/devices';
|
||||
import { JitsiTrackErrors } from '../../react/features/base/lib-jitsi-meet';
|
||||
import { getLocalParticipant } from '../../react/features/base/participants';
|
||||
import { openDisplayNamePrompt } from '../../react/features/display-name';
|
||||
import {
|
||||
maybeShowNotificationWithDoNotDisplay,
|
||||
setNotificationsEnabled
|
||||
} from '../../react/features/notifications';
|
||||
import {
|
||||
checkAutoEnableDesktopSharing,
|
||||
clearButtonPopup,
|
||||
|
@ -37,11 +42,6 @@ import {
|
|||
showSharedVideoButton,
|
||||
showToolbox
|
||||
} from '../../react/features/toolbox';
|
||||
import {
|
||||
maybeShowNotificationWithDoNotDisplay,
|
||||
setNotificationsEnabled
|
||||
} from '../../react/features/notifications';
|
||||
import { getLocalParticipant } from '../../react/features/base/participants';
|
||||
|
||||
var EventEmitter = require("events");
|
||||
UI.messageHandler = messageHandler;
|
||||
|
@ -199,8 +199,8 @@ UI.setLocalRaisedHandStatus
|
|||
* Initialize conference UI.
|
||||
*/
|
||||
UI.initConference = function () {
|
||||
const { id, avatarID, email, name }
|
||||
= getLocalParticipant(APP.store.getState());
|
||||
const { dispatch, getState } = APP.store;
|
||||
const { avatarID, email, id, name } = getLocalParticipant(getState);
|
||||
|
||||
// Update default button states before showing the toolbar
|
||||
// if local role changes buttons state will be again updated.
|
||||
|
@ -221,7 +221,7 @@ UI.initConference = function () {
|
|||
UI.setUserAvatarID(id, avatarID);
|
||||
}
|
||||
|
||||
APP.store.dispatch(checkAutoEnableDesktopSharing());
|
||||
dispatch(checkAutoEnableDesktopSharing());
|
||||
|
||||
// FollowMe attempts to copy certain aspects of the moderator's UI into the
|
||||
// other participants' UI. Consequently, it needs (1) read and write access
|
||||
|
|
|
@ -244,10 +244,10 @@ var Chat = {
|
|||
|
||||
// if we are in conversation mode focus on the text input
|
||||
// if we are not, focus on the display name input
|
||||
if (APP.conference.getLocalDisplayName())
|
||||
deferredFocus('usermsg');
|
||||
else
|
||||
deferredFocus('nickinput');
|
||||
deferredFocus(
|
||||
APP.conference.getLocalDisplayName()
|
||||
? 'usermsg'
|
||||
: 'nickinput');
|
||||
});
|
||||
|
||||
addSmileys();
|
||||
|
|
|
@ -37,7 +37,7 @@ import {
|
|||
} from './constants';
|
||||
import {
|
||||
_addLocalTracksToConference,
|
||||
setLocalParticipantData
|
||||
sendLocalParticipant
|
||||
} from './functions';
|
||||
|
||||
import type { Dispatch } from 'redux';
|
||||
|
@ -288,7 +288,7 @@ export function createConference() {
|
|||
|
||||
_addConferenceListeners(conference, dispatch);
|
||||
|
||||
setLocalParticipantData(conference, state);
|
||||
sendLocalParticipant(state, conference);
|
||||
|
||||
conference.join(password);
|
||||
};
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
// @flow
|
||||
|
||||
import { JitsiTrackErrors } from '../lib-jitsi-meet';
|
||||
import { getLocalParticipant } from '../participants';
|
||||
import { toState } from '../redux';
|
||||
|
||||
import {
|
||||
AVATAR_ID_COMMAND,
|
||||
AVATAR_URL_COMMAND,
|
||||
EMAIL_COMMAND
|
||||
} from './constants';
|
||||
import { JitsiTrackErrors } from '../lib-jitsi-meet';
|
||||
import { getLocalParticipant } from '../participants';
|
||||
import { toState } from '../redux';
|
||||
|
||||
/**
|
||||
* Attach a set of local tracks to a conference.
|
||||
|
@ -15,7 +18,9 @@ import { toState } from '../redux';
|
|||
* @protected
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function _addLocalTracksToConference(conference, localTracks) {
|
||||
export function _addLocalTracksToConference(
|
||||
conference: { addTrack: Function, getLocalTracks: Function },
|
||||
localTracks: Array<Object>) {
|
||||
const conferenceLocalTracks = conference.getLocalTracks();
|
||||
const promises = [];
|
||||
|
||||
|
@ -45,7 +50,7 @@ export function _addLocalTracksToConference(conference, localTracks) {
|
|||
* {@code getState} function.
|
||||
* @returns {JitsiConference|undefined}
|
||||
*/
|
||||
export function getCurrentConference(stateful) {
|
||||
export function getCurrentConference(stateful: Function | Object) {
|
||||
const { conference, joining, leaving }
|
||||
= toState(stateful)['features/base/conference'];
|
||||
|
||||
|
@ -64,7 +69,7 @@ export function getCurrentConference(stateful) {
|
|||
* @protected
|
||||
* @returns {void}
|
||||
*/
|
||||
export function _handleParticipantError(err) {
|
||||
export function _handleParticipantError(err: { message: ?string }) {
|
||||
// XXX DataChannels are initialized at some later point when the conference
|
||||
// has multiple participants, but code that pins or selects a participant
|
||||
// might be executed before. So here we're swallowing a particular error.
|
||||
|
@ -83,7 +88,7 @@ export function _handleParticipantError(err) {
|
|||
* @returns {boolean} If the specified room name is valid, then true; otherwise,
|
||||
* false.
|
||||
*/
|
||||
export function isRoomValid(room) {
|
||||
export function isRoomValid(room: ?string) {
|
||||
return typeof room === 'string' && room !== '';
|
||||
}
|
||||
|
||||
|
@ -95,7 +100,9 @@ export function isRoomValid(room) {
|
|||
* @protected
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function _removeLocalTracksFromConference(conference, localTracks) {
|
||||
export function _removeLocalTracksFromConference(
|
||||
conference: { removeTrack: Function },
|
||||
localTracks: Array<Object>) {
|
||||
return Promise.all(localTracks.map(track =>
|
||||
conference.removeTrack(track)
|
||||
.catch(err => {
|
||||
|
@ -129,15 +136,20 @@ function _reportError(msg, err) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the data like avatar URL, email and display name for the local
|
||||
* participant to the conference.
|
||||
* Sends a representation of the local participant such as her avatar (URL),
|
||||
* e-mail address, and display name to (the remote participants of) a specific
|
||||
* conference.
|
||||
*
|
||||
* @param {JitsiConference} conference - The JitsiConference instance.
|
||||
* @param {Object} state - The whole Redux state.
|
||||
* @param {Function|Object} stateful - The redux store, state, or
|
||||
* {@code getState} function.
|
||||
* @param {JitsiConference} conference - The {@code JitsiConference} to which
|
||||
* the representation of the local participant is to be sent.
|
||||
* @returns {void}
|
||||
*/
|
||||
export function setLocalParticipantData(conference, state) {
|
||||
const { avatarID, avatarURL, email, name } = getLocalParticipant(state);
|
||||
export function sendLocalParticipant(
|
||||
stateful: Function | Object,
|
||||
conference: { sendCommand: Function, setDisplayName: Function }) {
|
||||
const { avatarID, avatarURL, email, name } = getLocalParticipant(stateful);
|
||||
|
||||
avatarID && conference.sendCommand(AVATAR_ID_COMMAND, {
|
||||
value: avatarID
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
/* @flow */
|
||||
// @flow
|
||||
|
||||
import { SET_CALL_OVERLAY_VISIBLE, SET_JWT } from './actionTypes';
|
||||
|
||||
/**
|
||||
* Sets the visibility of {@code CallOverlay}.
|
||||
*
|
||||
* @param {boolean|undefined} callOverlayVisible - If {@code CallOverlay} is to
|
||||
* be displayed/visible, then {@code true}; otherwise, {@code false} or
|
||||
* @param {boolean|undefined} [callOverlayVisible] - If {@code CallOverlay} is
|
||||
* to be displayed/visible, then {@code true}; otherwise, {@code false} or
|
||||
* {@code undefined}.
|
||||
* @returns {{
|
||||
* type: SET_CALL_OVERLAY_VISIBLE,
|
||||
* callOverlayVisible: (boolean|undefined)
|
||||
* }}
|
||||
*/
|
||||
export function setCallOverlayVisible(callOverlayVisible: boolean) {
|
||||
export function setCallOverlayVisible(callOverlayVisible: ?boolean) {
|
||||
return (dispatch: Dispatch<*>, getState: Function) => {
|
||||
getState()['features/base/jwt']
|
||||
.callOverlayVisible === callOverlayVisible
|
||||
|
@ -27,13 +27,13 @@ export function setCallOverlayVisible(callOverlayVisible: boolean) {
|
|||
/**
|
||||
* Stores a specific JSON Web Token (JWT) into the redux store.
|
||||
*
|
||||
* @param {string} jwt - The JSON Web Token (JWT) to store.
|
||||
* @param {string} [jwt] - The JSON Web Token (JWT) to store.
|
||||
* @returns {{
|
||||
* type: SET_TOKEN_DATA,
|
||||
* jwt: string
|
||||
* jwt: (string|undefined)
|
||||
* }}
|
||||
*/
|
||||
export function setJWT(jwt: string) {
|
||||
export function setJWT(jwt: ?string) {
|
||||
return {
|
||||
type: SET_JWT,
|
||||
jwt
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// @flow
|
||||
|
||||
import jwtDecode from 'jwt-decode';
|
||||
|
||||
import {
|
||||
|
@ -22,6 +24,8 @@ import { setCallOverlayVisible, setJWT } from './actions';
|
|||
import { SET_JWT } from './actionTypes';
|
||||
import { parseJWTFromURLParams } from './functions';
|
||||
|
||||
declare var APP: Object;
|
||||
|
||||
/**
|
||||
* Middleware to parse token data upon setting a new room URL.
|
||||
*
|
||||
|
@ -80,8 +84,8 @@ function _maybeSetCallOverlayVisible({ dispatch, getState }, next, action) {
|
|||
if (stateFeaturesJWT.callee) {
|
||||
const { conference, leaving, room } = state['features/base/conference'];
|
||||
|
||||
// XXX The CallOverlay is to be displayed/visible as soon as
|
||||
// possible including even before the conference is joined.
|
||||
// XXX The CallOverlay is to be displayed/visible as soon as possible
|
||||
// including even before the conference is joined.
|
||||
if (room && (!conference || conference !== leaving)) {
|
||||
switch (action.type) {
|
||||
case CONFERENCE_FAILED:
|
||||
|
@ -100,10 +104,11 @@ function _maybeSetCallOverlayVisible({ dispatch, getState }, next, action) {
|
|||
break;
|
||||
|
||||
default: {
|
||||
// The CallOverlay it to no longer be displayed/visible as soon
|
||||
// The CallOverlay is to no longer be displayed/visible as soon
|
||||
// as another participant joins.
|
||||
callOverlayVisible = getParticipantCount(state) === 1
|
||||
&& Boolean(getLocalParticipant(state));
|
||||
callOverlayVisible
|
||||
= getParticipantCount(state) === 1
|
||||
&& Boolean(getLocalParticipant(state));
|
||||
|
||||
// However, the CallDialog is not to be displayed/visible again
|
||||
// after all remote participants leave.
|
||||
|
@ -122,53 +127,24 @@ function _maybeSetCallOverlayVisible({ dispatch, getState }, next, action) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Converts 'context.user' JWT token structure to the format compatible with the
|
||||
* corresponding fields overridden in base/participants.
|
||||
*
|
||||
* @param {Object} user - The 'jwt.context.user' structure parsed from the JWT
|
||||
* token.
|
||||
* @returns {({
|
||||
* avatarURL: string?,
|
||||
* email: string?,
|
||||
* name: string?
|
||||
* })}
|
||||
* @private
|
||||
*/
|
||||
function _normalizeCallerFields(user) {
|
||||
const { avatar, avatarUrl, email, name } = user;
|
||||
const caller = { };
|
||||
|
||||
if (typeof (avatarUrl || avatar) === 'string') {
|
||||
caller.avatarURL = (avatarUrl || avatar).trim();
|
||||
}
|
||||
if (typeof email === 'string') {
|
||||
caller.email = email.trim();
|
||||
}
|
||||
if (typeof name === 'string') {
|
||||
caller.name = name.trim();
|
||||
}
|
||||
|
||||
return Object.keys(caller).length ? caller : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Eventually overwrites 'avatarURL', 'email' and 'name' fields with the values
|
||||
* from JWT token for the local participant stored in the 'base/participants'
|
||||
* Redux store by dispatching the participant updated action.
|
||||
* Overwrites the properties {@code avatarURL}, {@code email}, and {@code name}
|
||||
* of the local participant stored in the redux state base/participants.
|
||||
*
|
||||
* @param {Store} store - The redux store.
|
||||
* @param {Object} caller - The "caller" structure parsed from 'context.user'
|
||||
* part of the JWT token and then normalized using
|
||||
* {@link _normalizeCallerFields}.
|
||||
* @returns {void}
|
||||
* @param {Object} localParticipant - The {@code Participant} structure to
|
||||
* overwrite the local participant stored in the redux store base/participants
|
||||
* with.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
function _overwriteLocalParticipant({ dispatch, getState }, caller) {
|
||||
const { avatarURL, email, name } = caller;
|
||||
const localParticipant = getLocalParticipant(getState());
|
||||
function _overwriteLocalParticipant(
|
||||
{ dispatch, getState },
|
||||
{ avatarURL, email, name }) {
|
||||
let localParticipant;
|
||||
|
||||
if (localParticipant && (avatarURL || email || name)) {
|
||||
const newProperties = { id: localParticipant.id };
|
||||
if ((avatarURL || email || name)
|
||||
&& (localParticipant = getLocalParticipant(getState))) {
|
||||
const newProperties: Object = { id: localParticipant.id };
|
||||
|
||||
if (avatarURL) {
|
||||
newProperties.avatarURL = avatarURL;
|
||||
|
@ -183,41 +159,6 @@ function _overwriteLocalParticipant({ dispatch, getState }, caller) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Will reset the values overridden by {@link _overwriteLocalParticipant}
|
||||
* by either clearing them or setting to default values. Only the values that
|
||||
* have not changed since the override happened will be restored.
|
||||
*
|
||||
* NOTE Once there is the possibility to edit and save participant properties,
|
||||
* this method should restore values from the storage instead.
|
||||
*
|
||||
* @param {Store} store - The Redux store.
|
||||
* @param {Object} caller - The 'caller' part of the JWT Redux state which tells
|
||||
* which local participant's fields's been overridden when the JWT token was
|
||||
* set.
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function _resetLocalParticipantOverrides({ dispatch, getState }, caller) {
|
||||
const { avatarURL, name, email } = caller;
|
||||
const localParticipant = getLocalParticipant(getState());
|
||||
|
||||
if (localParticipant && (avatarURL || name || email)) {
|
||||
const newProperties = { id: localParticipant.id };
|
||||
|
||||
if (avatarURL === localParticipant.avatarURL) {
|
||||
newProperties.avatarURL = undefined;
|
||||
}
|
||||
if (name === localParticipant.name) {
|
||||
newProperties.name = LOCAL_PARTICIPANT_DEFAULT_NAME;
|
||||
}
|
||||
if (email === localParticipant.email) {
|
||||
newProperties.email = undefined;
|
||||
}
|
||||
dispatch(participantUpdated(newProperties));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the feature jwt that the action {@link SET_CONFIG} or
|
||||
* {@link SET_LOCATION_URL} is being dispatched within a specific redux
|
||||
|
@ -266,41 +207,108 @@ function _setJWT(store, next, action) {
|
|||
// eslint-disable-next-line no-unused-vars
|
||||
const { jwt, type, ...actionPayload } = action;
|
||||
|
||||
if (jwt && !Object.keys(actionPayload).length) {
|
||||
const {
|
||||
enableUserRolesBasedOnToken
|
||||
} = store.getState()['features/base/config'];
|
||||
if (!Object.keys(actionPayload).length) {
|
||||
if (jwt) {
|
||||
const {
|
||||
enableUserRolesBasedOnToken
|
||||
} = store.getState()['features/base/config'];
|
||||
|
||||
action.isGuest = !enableUserRolesBasedOnToken;
|
||||
action.isGuest = !enableUserRolesBasedOnToken;
|
||||
|
||||
const jwtPayload = jwtDecode(jwt);
|
||||
const jwtPayload = jwtDecode(jwt);
|
||||
|
||||
if (jwtPayload) {
|
||||
const { context, iss } = jwtPayload;
|
||||
if (jwtPayload) {
|
||||
const { context, iss } = jwtPayload;
|
||||
|
||||
action.jwt = jwt;
|
||||
action.issuer = iss;
|
||||
if (context) {
|
||||
action.callee = context.callee;
|
||||
action.caller = _normalizeCallerFields(context.user);
|
||||
action.group = context.group;
|
||||
action.server = context.server;
|
||||
action.jwt = jwt;
|
||||
action.issuer = iss;
|
||||
if (context) {
|
||||
const user = _user2participant(context.user);
|
||||
|
||||
if (action.caller) {
|
||||
_overwriteLocalParticipant(store, action.caller);
|
||||
action.callee = context.callee;
|
||||
action.group = context.group;
|
||||
action.server = context.server;
|
||||
action.user = user;
|
||||
|
||||
user && _overwriteLocalParticipant(store, user);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (!jwt && !Object.keys(actionPayload).length) {
|
||||
const jwtState = store.getState()['features/base/jwt'];
|
||||
} else if (typeof APP === 'undefined') {
|
||||
// The logic of restoring JWT overrides make sense only on mobile.
|
||||
// On Web it should eventually be restored from storage, but there's
|
||||
// no such use case yet.
|
||||
|
||||
// The logic of restoring JWT overrides make sense only on mobile. On
|
||||
// web it should eventually be restored from storage, but there's no
|
||||
// such use case yet.
|
||||
if (jwtState.caller && typeof APP === 'undefined') {
|
||||
_resetLocalParticipantOverrides(store, jwtState.caller);
|
||||
const { user } = store.getState()['features/base/jwt'];
|
||||
|
||||
user && _undoOverwriteLocalParticipant(store, user);
|
||||
}
|
||||
}
|
||||
|
||||
return _maybeSetCallOverlayVisible(store, next, action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Undoes/resets the values overwritten by {@link _overwriteLocalParticipant}
|
||||
* by either clearing them or setting to default values. Only the values that
|
||||
* have not changed since the overwrite happened will be restored.
|
||||
*
|
||||
* NOTE Once it is possible to edit and save participant properties, this
|
||||
* function should restore values from the storage instead.
|
||||
*
|
||||
* @param {Store} store - The redux store.
|
||||
* @param {Object} localParticipant - The {@code Participant} structure used
|
||||
* previously to {@link _overwriteLocalParticipant}.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
function _undoOverwriteLocalParticipant(
|
||||
{ dispatch, getState },
|
||||
{ avatarURL, name, email }) {
|
||||
let localParticipant;
|
||||
|
||||
if ((avatarURL || name || email)
|
||||
&& (localParticipant = getLocalParticipant(getState))) {
|
||||
const newProperties: Object = { id: localParticipant.id };
|
||||
|
||||
if (avatarURL === localParticipant.avatarURL) {
|
||||
newProperties.avatarURL = undefined;
|
||||
}
|
||||
if (email === localParticipant.email) {
|
||||
newProperties.email = undefined;
|
||||
}
|
||||
if (name === localParticipant.name) {
|
||||
newProperties.name = LOCAL_PARTICIPANT_DEFAULT_NAME;
|
||||
}
|
||||
dispatch(participantUpdated(newProperties));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the JWT {@code context.user} structure to the {@code Participant}
|
||||
* structure stored in the redux state base/participants.
|
||||
*
|
||||
* @param {Object} user - The JWT {@code context.user} structure to convert.
|
||||
* @private
|
||||
* @returns {{
|
||||
* avatarURL: ?string,
|
||||
* email: ?string,
|
||||
* name: ?string
|
||||
* }}
|
||||
*/
|
||||
function _user2participant({ avatar, avatarUrl, email, name }) {
|
||||
const participant = {};
|
||||
|
||||
if (typeof avatarUrl === 'string') {
|
||||
participant.avatarURL = avatarUrl.trim();
|
||||
} else if (typeof avatar === 'string') {
|
||||
participant.avatarURL = avatar.trim();
|
||||
}
|
||||
if (typeof email === 'string') {
|
||||
participant.email = email.trim();
|
||||
}
|
||||
if (typeof name === 'string') {
|
||||
participant.name = name.trim();
|
||||
}
|
||||
|
||||
return Object.keys(participant).length ? participant : undefined;
|
||||
}
|
||||
|
|
|
@ -14,16 +14,18 @@
|
|||
export const DEFAULT_AVATAR_RELATIVE_PATH = 'images/avatar.png';
|
||||
|
||||
/**
|
||||
* Local participant might not have real ID until he joins a conference,
|
||||
* so use 'local' as its default ID.
|
||||
* The local participant might not have real ID until she joins a conference,
|
||||
* so use 'local' as her default ID.
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
export const LOCAL_PARTICIPANT_DEFAULT_ID = 'local';
|
||||
|
||||
/**
|
||||
* The default display name for the local participant.
|
||||
* TODO Get the from config and/or localized.
|
||||
* The default display name of the local participant.
|
||||
*
|
||||
* TODO Get the display name from config and/or localized.
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
export const LOCAL_PARTICIPANT_DEFAULT_NAME = 'me';
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* @flow */
|
||||
// @flow
|
||||
|
||||
import { toState } from '../redux';
|
||||
|
||||
|
@ -77,14 +77,14 @@ export function getAvatarURL({ avatarID, avatarURL, email, id }: {
|
|||
/**
|
||||
* Returns local participant from Redux state.
|
||||
*
|
||||
* @param {(Function|Object|Participant[])} stateOrGetState - The redux state
|
||||
* @param {(Function|Object|Participant[])} stateful - The redux state
|
||||
* features/base/participants, the (whole) redux state, or redux's
|
||||
* {@code getState} function to be used to retrieve the
|
||||
* features/base/participants state.
|
||||
* {@code getState} function to be used to retrieve the state
|
||||
* features/base/participants.
|
||||
* @returns {(Participant|undefined)}
|
||||
*/
|
||||
export function getLocalParticipant(stateOrGetState: Object | Function) {
|
||||
const participants = _getAllParticipants(stateOrGetState);
|
||||
export function getLocalParticipant(stateful: Object | Function) {
|
||||
const participants = _getAllParticipants(stateful);
|
||||
|
||||
return participants.find(p => p.local);
|
||||
}
|
||||
|
@ -92,18 +92,18 @@ export function getLocalParticipant(stateOrGetState: Object | Function) {
|
|||
/**
|
||||
* Returns participant by ID from Redux state.
|
||||
*
|
||||
* @param {(Function|Object|Participant[])} stateOrGetState - The redux state
|
||||
* @param {(Function|Object|Participant[])} stateful - The redux state
|
||||
* features/base/participants, the (whole) redux state, or redux's
|
||||
* {@code getState} function to be used to retrieve the
|
||||
* features/base/participants state.
|
||||
* {@code getState} function to be used to retrieve the state
|
||||
* features/base/participants.
|
||||
* @param {string} id - The ID of the participant to retrieve.
|
||||
* @private
|
||||
* @returns {(Participant|undefined)}
|
||||
*/
|
||||
export function getParticipantById(
|
||||
stateOrGetState: Object | Function,
|
||||
stateful: Object | Function,
|
||||
id: string) {
|
||||
const participants = _getAllParticipants(stateOrGetState);
|
||||
const participants = _getAllParticipants(stateful);
|
||||
|
||||
return participants.find(p => p.id === id);
|
||||
}
|
||||
|
@ -112,14 +112,14 @@ export function getParticipantById(
|
|||
* Returns a count of the known participants in the passed in redux state,
|
||||
* excluding any fake participants.
|
||||
*
|
||||
* @param {(Function|Object|Participant[])} stateOrGetState - The redux state
|
||||
* @param {(Function|Object|Participant[])} stateful - The redux state
|
||||
* features/base/participants, the (whole) redux state, or redux's
|
||||
* {@code getState} function to be used to retrieve the
|
||||
* features/base/participants state.
|
||||
* {@code getState} function to be used to retrieve the state
|
||||
* features/base/participants.
|
||||
* @returns {number}
|
||||
*/
|
||||
export function getParticipantCount(stateOrGetState: Object | Function) {
|
||||
return getParticipants(stateOrGetState).length;
|
||||
export function getParticipantCount(stateful: Object | Function) {
|
||||
return getParticipants(stateful).length;
|
||||
}
|
||||
|
||||
|
||||
|
@ -127,42 +127,42 @@ export function getParticipantCount(stateOrGetState: Object | Function) {
|
|||
* Selectors for getting all known participants with fake participants filtered
|
||||
* out.
|
||||
*
|
||||
* @param {(Function|Object|Participant[])} stateOrGetState - The redux state
|
||||
* @param {(Function|Object|Participant[])} stateful - The redux state
|
||||
* features/base/participants, the (whole) redux state, or redux's
|
||||
* {@code getState} function to be used to retrieve the
|
||||
* features/base/participants state.
|
||||
* {@code getState} function to be used to retrieve the state
|
||||
* features/base/participants.
|
||||
* @returns {Participant[]}
|
||||
*/
|
||||
export function getParticipants(stateOrGetState: Object | Function) {
|
||||
return _getAllParticipants(stateOrGetState).filter(p => !p.isBot);
|
||||
export function getParticipants(stateful: Object | Function) {
|
||||
return _getAllParticipants(stateful).filter(p => !p.isBot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the participant which has its pinned state set to truthy.
|
||||
*
|
||||
* @param {(Function|Object|Participant[])} stateOrGetState - The redux state
|
||||
* @param {(Function|Object|Participant[])} stateful - The redux state
|
||||
* features/base/participants, the (whole) redux state, or redux's
|
||||
* {@code getState} function to be used to retrieve the
|
||||
* features/base/participants state.
|
||||
* {@code getState} function to be used to retrieve the state
|
||||
* features/base/participants.
|
||||
* @returns {(Participant|undefined)}
|
||||
*/
|
||||
export function getPinnedParticipant(stateOrGetState: Object | Function) {
|
||||
return _getAllParticipants(stateOrGetState).find(p => p.pinned);
|
||||
export function getPinnedParticipant(stateful: Object | Function) {
|
||||
return _getAllParticipants(stateful).find(p => p.pinned);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array of participants from Redux state.
|
||||
*
|
||||
* @param {(Function|Object|Participant[])} stateOrGetState - The redux state
|
||||
* @param {(Function|Object|Participant[])} stateful - The redux state
|
||||
* features/base/participants, the (whole) redux state, or redux's
|
||||
* {@code getState} function to be used to retrieve the
|
||||
* features/base/participants state.
|
||||
* {@code getState} function to be used to retrieve the state
|
||||
* features/base/participants.
|
||||
* @private
|
||||
* @returns {Participant[]}
|
||||
*/
|
||||
function _getAllParticipants(stateOrGetState) {
|
||||
function _getAllParticipants(stateful) {
|
||||
return (
|
||||
Array.isArray(stateOrGetState)
|
||||
? stateOrGetState
|
||||
: toState(stateOrGetState)['features/base/participants'] || []);
|
||||
Array.isArray(stateful)
|
||||
? stateful
|
||||
: toState(stateful)['features/base/participants'] || []);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// @flow
|
||||
|
||||
import { ReducerRegistry, set } from '../redux';
|
||||
import { randomHexString } from '../util';
|
||||
|
||||
|
@ -31,6 +33,8 @@ import {
|
|||
* @property {string} email - Participant email.
|
||||
*/
|
||||
|
||||
declare var APP: Object;
|
||||
|
||||
/**
|
||||
* These properties should not be bulk assigned when updating a particular
|
||||
* @see Participant.
|
||||
|
@ -49,9 +53,9 @@ const PARTICIPANT_PROPS_TO_OMIT_WHEN_UPDATE
|
|||
* added/modified.
|
||||
* @param {JitsiConference} action.conference - Conference instance.
|
||||
* @private
|
||||
* @returns {Participant|undefined}
|
||||
* @returns {Participant}
|
||||
*/
|
||||
function _participant(state, action) {
|
||||
function _participant(state: Object = {}, action) {
|
||||
switch (action.type) {
|
||||
case DOMINANT_SPEAKER_CHANGED:
|
||||
// Only one dominant speaker is allowed.
|
||||
|
@ -99,9 +103,9 @@ function _participant(state, action) {
|
|||
|
||||
// name
|
||||
if (!name) {
|
||||
// TODO Get the from config and/or localized.
|
||||
// On web default value is handled in:
|
||||
// conference.js getParticipantDisplayName
|
||||
// TODO Get the display name from config and/or localized.
|
||||
// XXX On Web the default value is handled in conference.js by
|
||||
// getParticipantDisplayName.
|
||||
if (typeof APP === 'undefined') {
|
||||
name
|
||||
= local ? LOCAL_PARTICIPANT_DEFAULT_NAME : 'Fellow Jitster';
|
||||
|
@ -169,18 +173,18 @@ function _participant(state, action) {
|
|||
*/
|
||||
ReducerRegistry.register('features/base/participants', (state = [], action) => {
|
||||
switch (action.type) {
|
||||
case PARTICIPANT_JOINED:
|
||||
return [ ...state, _participant(undefined, action) ];
|
||||
|
||||
case PARTICIPANT_LEFT:
|
||||
return state.filter(p => p.id !== action.participant.id);
|
||||
|
||||
case DOMINANT_SPEAKER_CHANGED:
|
||||
case PARTICIPANT_ID_CHANGED:
|
||||
case PARTICIPANT_UPDATED:
|
||||
case PIN_PARTICIPANT:
|
||||
return state.map(p => _participant(p, action));
|
||||
|
||||
case PARTICIPANT_JOINED:
|
||||
return [ ...state, _participant(undefined, action) ];
|
||||
|
||||
case PARTICIPANT_LEFT:
|
||||
return state.filter(p => p.id !== action.participant.id);
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* global APP, config */
|
||||
// @flow
|
||||
|
||||
import ConferenceUrl from '../../../modules/URL/ConferenceUrl';
|
||||
|
||||
|
@ -7,6 +7,9 @@ import { RouteRegistry } from '../base/react';
|
|||
|
||||
import { Conference } from './components';
|
||||
|
||||
declare var APP: Object;
|
||||
declare var config: Object;
|
||||
|
||||
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||
|
||||
/**
|
||||
|
@ -29,7 +32,6 @@ RouteRegistry.register({
|
|||
* @returns {void}
|
||||
*/
|
||||
function _initConference() {
|
||||
// Initialize the conference URL handler
|
||||
APP.ConferenceUrl = new ConferenceUrl(window.location);
|
||||
}
|
||||
|
||||
|
@ -43,7 +45,7 @@ function _initConference() {
|
|||
* @private
|
||||
* @returns {Promise}
|
||||
*/
|
||||
function _obtainConfig(location, room) {
|
||||
function _obtainConfig(location: string, room: string) {
|
||||
return new Promise((resolve, reject) =>
|
||||
obtainConfig(location, room, (success, error) => {
|
||||
success ? resolve() : reject(error);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// @flow
|
||||
|
||||
import { openDialog } from '../../features/base/dialog';
|
||||
import { openDialog } from '../base/dialog';
|
||||
import { FEEDBACK_REQUEST_IN_PROGRESS } from '../../../modules/UI/UIErrors';
|
||||
|
||||
import { CANCEL_FEEDBACK, SUBMIT_FEEDBACK } from './actionTypes';
|
||||
|
@ -55,8 +55,8 @@ export function maybeOpenFeedbackDialog(conference: Object) {
|
|||
// Feedback has been submitted already.
|
||||
|
||||
return Promise.resolve({
|
||||
thankYouDialogVisible: true,
|
||||
feedbackSubmitted: true
|
||||
feedbackSubmitted: true,
|
||||
thankYouDialogVisible: true
|
||||
});
|
||||
} else if (conference.isCallstatsEnabled()) {
|
||||
return new Promise(resolve => {
|
||||
|
@ -71,12 +71,12 @@ export function maybeOpenFeedbackDialog(conference: Object) {
|
|||
});
|
||||
}
|
||||
|
||||
// If the feedback functionality isn't enabled we show a thank
|
||||
// you dialog. Signaling it (true), so the caller
|
||||
// of requestFeedback can act on it
|
||||
// If the feedback functionality isn't enabled we show a "thank you"
|
||||
// dialog. Signaling it (true), so the caller of requestFeedback can act
|
||||
// on it.
|
||||
return Promise.resolve({
|
||||
thankYouDialogVisible: true,
|
||||
feedbackSubmitted: false
|
||||
feedbackSubmitted: false,
|
||||
thankYouDialogVisible: true
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,37 +1,36 @@
|
|||
/* @flow */
|
||||
// @flow
|
||||
|
||||
import { getPinnedParticipant } from '../base/participants';
|
||||
|
||||
declare var interfaceConfig: Object;
|
||||
|
||||
import {
|
||||
getPinnedParticipant
|
||||
} from '../base/participants';
|
||||
|
||||
/**
|
||||
* A selector for determining whether or not remote video thumbnails should be
|
||||
* displayed in the filmstrip.
|
||||
* Determines whether the remote video thumbnails should be displayed/visible in
|
||||
* the filmstrip.
|
||||
*
|
||||
* @param {Object} state - The full redux state.
|
||||
* @returns {boolean} - True if remote video thumbnails should be displayed.
|
||||
* @returns {boolean} - If remote video thumbnails should be displayed/visible
|
||||
* in the filmstrip, then {@code true}; otherwise, {@code false}.
|
||||
*/
|
||||
export function shouldRemoteVideosBeVisible(state: Object) {
|
||||
const participants = state['features/base/participants'];
|
||||
const participantsCount = participants.length;
|
||||
const pinnedParticipant = getPinnedParticipant(state);
|
||||
const participantCount = participants.length;
|
||||
let pinnedParticipant;
|
||||
|
||||
const shouldShowVideos
|
||||
= participantsCount > 2
|
||||
return Boolean(
|
||||
participantCount > 2
|
||||
|
||||
// Always show the filmstrip when there is another participant to show
|
||||
// and the filmstrip is hovered, or local video is pinned, or the
|
||||
// toolbar is displayed.
|
||||
|| (participantsCount > 1
|
||||
&& (state['features/filmstrip'].hovered
|
||||
|| state['features/toolbox'].visible
|
||||
|| (pinnedParticipant && pinnedParticipant.local)))
|
||||
// Always show the filmstrip when there is another participant to
|
||||
// show and the filmstrip is hovered, or local video is pinned, or
|
||||
// the toolbar is displayed.
|
||||
|| (participantCount > 1
|
||||
&& (state['features/filmstrip'].hovered
|
||||
|| state['features/toolbox'].visible
|
||||
|| ((pinnedParticipant = getPinnedParticipant(participants))
|
||||
&& pinnedParticipant.local)))
|
||||
|
||||
|| interfaceConfig.filmStripOnly
|
||||
|| (typeof interfaceConfig === 'object'
|
||||
&& interfaceConfig.filmStripOnly)
|
||||
|
||||
|| state['features/base/config'].disable1On1Mode;
|
||||
|
||||
return Boolean(shouldShowVideos);
|
||||
|| state['features/base/config'].disable1On1Mode);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* global interfaceConfig */
|
||||
// @flow
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
|
@ -10,6 +10,8 @@ import { getLocalParticipant } from '../../base/participants';
|
|||
import SpeakerStatsItem from './SpeakerStatsItem';
|
||||
import SpeakerStatsLabels from './SpeakerStatsLabels';
|
||||
|
||||
declare var interfaceConfig: Object;
|
||||
|
||||
/**
|
||||
* React component for displaying a list of speaker stats.
|
||||
*
|
||||
|
@ -23,7 +25,7 @@ class SpeakerStats extends Component {
|
|||
*/
|
||||
static propTypes = {
|
||||
/**
|
||||
* The display name for the local participant obtained from the Redux
|
||||
* The display name for the local participant obtained from the redux
|
||||
* store.
|
||||
*/
|
||||
_localDisplayName: PropTypes.string,
|
||||
|
@ -39,6 +41,12 @@ class SpeakerStats extends Component {
|
|||
t: PropTypes.func
|
||||
};
|
||||
|
||||
state = {
|
||||
stats: {}
|
||||
};
|
||||
|
||||
_updateInterval: number;
|
||||
|
||||
/**
|
||||
* Initializes a new SpeakerStats instance.
|
||||
*
|
||||
|
@ -48,10 +56,7 @@ class SpeakerStats extends Component {
|
|||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
stats: {}
|
||||
};
|
||||
this._updateInterval = null;
|
||||
// Bind event handlers so they are only bound once per instance.
|
||||
this._updateStats = this._updateStats.bind(this);
|
||||
}
|
||||
|
||||
|
@ -100,18 +105,6 @@ class SpeakerStats extends Component {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the internal state with the latest speaker stats.
|
||||
*
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
_updateStats() {
|
||||
const stats = this.props.conference.getSpeakerStats();
|
||||
|
||||
this.setState({ stats });
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a SpeakerStatsItem instance for the passed in user id.
|
||||
*
|
||||
|
@ -131,18 +124,19 @@ class SpeakerStats extends Component {
|
|||
const dominantSpeakerTime = statsModel.getTotalDominantSpeakerTime();
|
||||
const hasLeft = statsModel.hasLeft();
|
||||
|
||||
let displayName = '';
|
||||
let displayName;
|
||||
|
||||
if (statsModel.isLocalStats()) {
|
||||
const { t } = this.props;
|
||||
const meString = t('me');
|
||||
|
||||
displayName = this.props._localDisplayName;
|
||||
displayName = displayName ? `${displayName} (${meString})`
|
||||
: meString;
|
||||
displayName
|
||||
= displayName ? `${displayName} (${meString})` : meString;
|
||||
} else {
|
||||
displayName = this.state.stats[userId].getDisplayName()
|
||||
|| interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME;
|
||||
displayName
|
||||
= this.state.stats[userId].getDisplayName()
|
||||
|| interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME;
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -154,15 +148,29 @@ class SpeakerStats extends Component {
|
|||
key = { userId } />
|
||||
);
|
||||
}
|
||||
|
||||
_updateStats: () => void;
|
||||
|
||||
/**
|
||||
* Update the internal state with the latest speaker stats.
|
||||
*
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
_updateStats() {
|
||||
const stats = this.props.conference.getSpeakerStats();
|
||||
|
||||
this.setState({ stats });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps (parts of) the Redux state to the associated SpeakerStats's props.
|
||||
* Maps (parts of) the redux state to the associated SpeakerStats's props.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @param {Object} state - The redux state.
|
||||
* @private
|
||||
* @returns {{
|
||||
* _localDisplayName: string?
|
||||
* _localDisplayName: ?string
|
||||
* }}
|
||||
*/
|
||||
function _mapStateToProps(state) {
|
||||
|
@ -171,6 +179,7 @@ function _mapStateToProps(state) {
|
|||
return {
|
||||
/**
|
||||
* The local display name.
|
||||
*
|
||||
* @private
|
||||
* @type {string|undefined}
|
||||
*/
|
||||
|
|
|
@ -31,7 +31,7 @@ class WelcomePage extends AbstractWelcomePage {
|
|||
interfaceConfig.GENERATE_ROOMNAMES_ON_WELCOME_PAGE
|
||||
};
|
||||
|
||||
// Bind event handlers so they are only bound once for every instance.
|
||||
// Bind event handlers so they are only bound once per instance.
|
||||
this._onDisableWelcomeChange = this._onDisableWelcomeChange.bind(this);
|
||||
this._onKeyDown = this._onKeyDown.bind(this);
|
||||
this._onRoomChange = this._onRoomChange.bind(this);
|
||||
|
|
Loading…
Reference in New Issue