Flow, coding style

This commit is contained in:
Lyubo Marinov 2017-10-13 14:31:05 -05:00
parent 8a4e6a7ec0
commit 003eb68e28
15 changed files with 297 additions and 259 deletions

View File

@ -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();
},

View File

@ -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

View File

@ -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();

View File

@ -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);
};

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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';

View File

@ -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'] || []);
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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
});
};
}

View File

@ -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);
}

View File

@ -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}
*/

View File

@ -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);