feat: override email, display name and avatar on mobile
Will override email, display name and avatar URL with the values provided in 'context.user' structure of the JWT token. Settings will no longer be used to retrieve local display name, email and avatar URL. Now those values will be obtained from the /features/base/participants Redux state. fix(jwt/middleware): use const for default name fix: wrong default display name on web ref(base/participants): remove getDisplayName functions ref(jwt): do not accept unknown user fields
This commit is contained in:
parent
0eddef4d62
commit
8a4e6a7ec0
|
@ -30,7 +30,8 @@ import {
|
|||
toggleAudioOnly,
|
||||
EMAIL_COMMAND,
|
||||
lockStateChanged,
|
||||
p2pStatusChanged
|
||||
p2pStatusChanged,
|
||||
setLocalParticipantData
|
||||
} from './react/features/base/conference';
|
||||
import { updateDeviceList } from './react/features/base/devices';
|
||||
import {
|
||||
|
@ -55,6 +56,8 @@ import {
|
|||
} from './react/features/base/media';
|
||||
import {
|
||||
dominantSpeakerChanged,
|
||||
getLocalParticipant,
|
||||
getParticipantById,
|
||||
localParticipantConnectionStatusChanged,
|
||||
localParticipantRoleChanged,
|
||||
MAX_DISPLAY_NAME_LENGTH,
|
||||
|
@ -143,43 +146,15 @@ function sendData(command, value) {
|
|||
room.sendCommand(command, {value: value});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up initially the properties of the local participant - email, avatarID,
|
||||
* avatarURL, displayName, etc.
|
||||
*/
|
||||
function _setupLocalParticipantProperties() {
|
||||
const email = APP.settings.getEmail();
|
||||
email && sendData(commands.EMAIL, email);
|
||||
|
||||
const avatarUrl = APP.settings.getAvatarUrl();
|
||||
avatarUrl && sendData(commands.AVATAR_URL, avatarUrl);
|
||||
|
||||
if (!email && !avatarUrl) {
|
||||
sendData(commands.AVATAR_ID, APP.settings.getAvatarId());
|
||||
}
|
||||
|
||||
let nick = APP.settings.getDisplayName();
|
||||
if (config.useNicks && !nick) {
|
||||
nick = APP.UI.askForNickname();
|
||||
APP.settings.setDisplayName(nick);
|
||||
}
|
||||
nick && room.setDisplayName(nick);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user nickname by user id.
|
||||
* @param {string} id user id
|
||||
* @returns {string?} user nickname or undefined if user is unknown.
|
||||
*/
|
||||
function getDisplayName(id) {
|
||||
if (APP.conference.isLocalId(id)) {
|
||||
return APP.settings.getDisplayName();
|
||||
}
|
||||
const participant = getParticipantById(APP.store.getState(), id);
|
||||
|
||||
let participant = room.getParticipantById(id);
|
||||
if (participant && participant.getDisplayName()) {
|
||||
return participant.getDisplayName();
|
||||
}
|
||||
return participant && participant.name;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -989,6 +964,13 @@ export default {
|
|||
isConnectionInterrupted() {
|
||||
return this._room.isConnectionInterrupted();
|
||||
},
|
||||
/**
|
||||
* Obtains the local display name.
|
||||
* @returns {string|undefined}
|
||||
*/
|
||||
getLocalDisplayName() {
|
||||
return getDisplayName(this.getMyUserId());
|
||||
},
|
||||
/**
|
||||
* Finds JitsiParticipant for given id.
|
||||
*
|
||||
|
@ -1162,7 +1144,7 @@ export default {
|
|||
this._setLocalAudioVideoStreams(localTracks);
|
||||
this._room = room; // FIXME do not use this
|
||||
|
||||
_setupLocalParticipantProperties();
|
||||
setLocalParticipantData(room, APP.store.getState());
|
||||
|
||||
this._setupListeners();
|
||||
},
|
||||
|
@ -2420,13 +2402,15 @@ export default {
|
|||
* @param email {string} the new email
|
||||
*/
|
||||
changeLocalEmail(email = '') {
|
||||
const localParticipant = getLocalParticipant(APP.store.getState());
|
||||
|
||||
email = String(email).trim();
|
||||
|
||||
if (email === APP.settings.getEmail()) {
|
||||
if (email === localParticipant.email) {
|
||||
return;
|
||||
}
|
||||
|
||||
const localId = room ? room.myUserId() : undefined;
|
||||
const localId = localParticipant.id;
|
||||
|
||||
APP.store.dispatch(participantUpdated({
|
||||
id: localId,
|
||||
|
@ -2444,22 +2428,22 @@ export default {
|
|||
* @param url {string} the new url
|
||||
*/
|
||||
changeLocalAvatarUrl(url = '') {
|
||||
const { avatarURL, id } = getLocalParticipant(APP.store.getState());
|
||||
|
||||
url = String(url).trim();
|
||||
|
||||
if (url === APP.settings.getAvatarUrl()) {
|
||||
if (url === avatarURL) {
|
||||
return;
|
||||
}
|
||||
|
||||
const localId = room ? room.myUserId() : undefined;
|
||||
|
||||
APP.store.dispatch(participantUpdated({
|
||||
id: localId,
|
||||
id,
|
||||
local: true,
|
||||
avatarURL: url
|
||||
}));
|
||||
|
||||
APP.settings.setAvatarUrl(url);
|
||||
APP.UI.setUserAvatarUrl(localId, url);
|
||||
APP.UI.setUserAvatarUrl(id, url);
|
||||
sendData(commands.AVATAR_URL, url);
|
||||
},
|
||||
|
||||
|
@ -2501,13 +2485,14 @@ export default {
|
|||
changeLocalDisplayName(nickname = '') {
|
||||
const formattedNickname
|
||||
= nickname.trim().substr(0, MAX_DISPLAY_NAME_LENGTH);
|
||||
const { id, name } = getLocalParticipant(APP.store.getState());
|
||||
|
||||
if (formattedNickname === APP.settings.getDisplayName()) {
|
||||
if (formattedNickname === name) {
|
||||
return;
|
||||
}
|
||||
|
||||
APP.store.dispatch(participantUpdated({
|
||||
id: this.getMyUserId(),
|
||||
id,
|
||||
local: true,
|
||||
name: formattedNickname
|
||||
}));
|
||||
|
@ -2515,7 +2500,7 @@ export default {
|
|||
APP.settings.setDisplayName(formattedNickname);
|
||||
if (room) {
|
||||
room.setDisplayName(formattedNickname);
|
||||
APP.UI.changeDisplayName(this.getMyUserId(), formattedNickname);
|
||||
APP.UI.changeDisplayName(id, formattedNickname);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ import VideoLayout from "./videolayout/VideoLayout";
|
|||
import Filmstrip from "./videolayout/Filmstrip";
|
||||
import SettingsMenu from "./side_pannels/settings/SettingsMenu";
|
||||
import Profile from "./side_pannels/profile/Profile";
|
||||
import Settings from "./../settings/Settings";
|
||||
|
||||
import { updateDeviceList } from '../../react/features/base/devices';
|
||||
import { JitsiTrackErrors } from '../../react/features/base/lib-jitsi-meet';
|
||||
|
@ -42,6 +41,7 @@ import {
|
|||
maybeShowNotificationWithDoNotDisplay,
|
||||
setNotificationsEnabled
|
||||
} from '../../react/features/notifications';
|
||||
import { getLocalParticipant } from '../../react/features/base/participants';
|
||||
|
||||
var EventEmitter = require("events");
|
||||
UI.messageHandler = messageHandler;
|
||||
|
@ -199,7 +199,8 @@ UI.setLocalRaisedHandStatus
|
|||
* Initialize conference UI.
|
||||
*/
|
||||
UI.initConference = function () {
|
||||
let id = APP.conference.getMyUserId();
|
||||
const { id, avatarID, email, name }
|
||||
= getLocalParticipant(APP.store.getState());
|
||||
|
||||
// Update default button states before showing the toolbar
|
||||
// if local role changes buttons state will be again updated.
|
||||
|
@ -207,18 +208,17 @@ UI.initConference = function () {
|
|||
|
||||
UI.showToolbar();
|
||||
|
||||
let displayName = config.displayJids ? id : Settings.getDisplayName();
|
||||
let displayName = config.displayJids ? id : name;
|
||||
|
||||
if (displayName) {
|
||||
UI.changeDisplayName('localVideoContainer', displayName);
|
||||
}
|
||||
|
||||
// Make sure we configure our avatar id, before creating avatar for us
|
||||
let email = Settings.getEmail();
|
||||
if (email) {
|
||||
UI.setUserEmail(id, email);
|
||||
} else {
|
||||
UI.setUserAvatarID(id, Settings.getAvatarId());
|
||||
UI.setUserAvatarID(id, avatarID);
|
||||
}
|
||||
|
||||
APP.store.dispatch(checkAutoEnableDesktopSharing());
|
||||
|
@ -235,7 +235,9 @@ UI.mucJoined = function () {
|
|||
|
||||
// Update local video now that a conference is joined a user ID should be
|
||||
// set.
|
||||
UI.changeDisplayName('localVideoContainer', APP.settings.getDisplayName());
|
||||
UI.changeDisplayName(
|
||||
'localVideoContainer',
|
||||
APP.conference.getLocalDisplayName());
|
||||
};
|
||||
|
||||
/***
|
||||
|
|
|
@ -187,7 +187,7 @@ var Chat = {
|
|||
*/
|
||||
init (eventEmitter) {
|
||||
initHTML();
|
||||
if (APP.settings.getDisplayName()) {
|
||||
if (APP.conference.getLocalDisplayName()) {
|
||||
Chat.setChatConversationMode(true);
|
||||
}
|
||||
|
||||
|
@ -244,7 +244,7 @@ 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.settings.getDisplayName())
|
||||
if (APP.conference.getLocalDisplayName())
|
||||
deferredFocus('usermsg');
|
||||
else
|
||||
deferredFocus('nickinput');
|
||||
|
|
|
@ -5,7 +5,6 @@ import { JitsiConferenceEvents } from '../lib-jitsi-meet';
|
|||
import { setAudioMuted, setVideoMuted } from '../media';
|
||||
import {
|
||||
dominantSpeakerChanged,
|
||||
getLocalParticipant,
|
||||
participantConnectionStatusChanged,
|
||||
participantJoined,
|
||||
participantLeft,
|
||||
|
@ -36,7 +35,10 @@ import {
|
|||
EMAIL_COMMAND,
|
||||
JITSI_CONFERENCE_URL_KEY
|
||||
} from './constants';
|
||||
import { _addLocalTracksToConference } from './functions';
|
||||
import {
|
||||
_addLocalTracksToConference,
|
||||
setLocalParticipantData
|
||||
} from './functions';
|
||||
|
||||
import type { Dispatch } from 'redux';
|
||||
|
||||
|
@ -147,22 +149,6 @@ function _addConferenceListeners(conference, dispatch) {
|
|||
})));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data for the local participant to the conference.
|
||||
*
|
||||
* @param {JitsiConference} conference - The JitsiConference instance.
|
||||
* @param {Object} state - The Redux state.
|
||||
* @returns {void}
|
||||
*/
|
||||
function _setLocalParticipantData(conference, state) {
|
||||
const { avatarID } = getLocalParticipant(state);
|
||||
|
||||
conference.removeCommand(AVATAR_ID_COMMAND);
|
||||
conference.sendCommand(AVATAR_ID_COMMAND, {
|
||||
value: avatarID
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals that a specific conference has failed.
|
||||
*
|
||||
|
@ -302,7 +288,7 @@ export function createConference() {
|
|||
|
||||
_addConferenceListeners(conference, dispatch);
|
||||
|
||||
_setLocalParticipantData(conference, state);
|
||||
setLocalParticipantData(conference, state);
|
||||
|
||||
conference.join(password);
|
||||
};
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
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';
|
||||
|
||||
/**
|
||||
|
@ -121,3 +127,26 @@ function _reportError(msg, err) {
|
|||
// one.
|
||||
console.error(msg, err);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data like avatar URL, email and display name for the local
|
||||
* participant to the conference.
|
||||
*
|
||||
* @param {JitsiConference} conference - The JitsiConference instance.
|
||||
* @param {Object} state - The whole Redux state.
|
||||
* @returns {void}
|
||||
*/
|
||||
export function setLocalParticipantData(conference, state) {
|
||||
const { avatarID, avatarURL, email, name } = getLocalParticipant(state);
|
||||
|
||||
avatarID && conference.sendCommand(AVATAR_ID_COMMAND, {
|
||||
value: avatarID
|
||||
});
|
||||
avatarURL && conference.sendCommand(AVATAR_URL_COMMAND, {
|
||||
value: avatarURL
|
||||
});
|
||||
email && conference.sendCommand(EMAIL_COMMAND, {
|
||||
value: email
|
||||
});
|
||||
conference.setDisplayName(name);
|
||||
}
|
||||
|
|
|
@ -72,7 +72,8 @@ export function connect() {
|
|||
|
||||
APP.keyboardshortcut.init();
|
||||
|
||||
if (config.requireDisplayName && !APP.settings.getDisplayName()) {
|
||||
if (config.requireDisplayName
|
||||
&& !APP.conference.getLocalDisplayName()) {
|
||||
APP.UI.promptDisplayName();
|
||||
}
|
||||
})
|
||||
|
|
|
@ -12,7 +12,9 @@ import { LIB_INIT_ERROR } from '../lib-jitsi-meet';
|
|||
import {
|
||||
getLocalParticipant,
|
||||
getParticipantCount,
|
||||
PARTICIPANT_JOINED
|
||||
LOCAL_PARTICIPANT_DEFAULT_NAME,
|
||||
PARTICIPANT_JOINED,
|
||||
participantUpdated
|
||||
} from '../participants';
|
||||
import { MiddlewareRegistry } from '../redux';
|
||||
|
||||
|
@ -119,6 +121,103 @@ function _maybeSetCallOverlayVisible({ dispatch, getState }, next, action) {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @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}
|
||||
* @private
|
||||
*/
|
||||
function _overwriteLocalParticipant({ dispatch, getState }, caller) {
|
||||
const { avatarURL, email, name } = caller;
|
||||
const localParticipant = getLocalParticipant(getState());
|
||||
|
||||
if (localParticipant && (avatarURL || email || name)) {
|
||||
const newProperties = { id: localParticipant.id };
|
||||
|
||||
if (avatarURL) {
|
||||
newProperties.avatarURL = avatarURL;
|
||||
}
|
||||
if (email) {
|
||||
newProperties.email = email;
|
||||
}
|
||||
if (name) {
|
||||
newProperties.name = name;
|
||||
}
|
||||
dispatch(participantUpdated(newProperties));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -183,11 +282,24 @@ function _setJWT(store, next, action) {
|
|||
action.issuer = iss;
|
||||
if (context) {
|
||||
action.callee = context.callee;
|
||||
action.caller = context.user;
|
||||
action.caller = _normalizeCallerFields(context.user);
|
||||
action.group = context.group;
|
||||
action.server = context.server;
|
||||
|
||||
if (action.caller) {
|
||||
_overwriteLocalParticipant(store, action.caller);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (!jwt && !Object.keys(actionPayload).length) {
|
||||
const jwtState = store.getState()['features/base/jwt'];
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
return _maybeSetCallOverlayVisible(store, next, action);
|
||||
|
|
|
@ -21,6 +21,13 @@ export const DEFAULT_AVATAR_RELATIVE_PATH = 'images/avatar.png';
|
|||
*/
|
||||
export const LOCAL_PARTICIPANT_DEFAULT_ID = 'local';
|
||||
|
||||
/**
|
||||
* The default display name for the local participant.
|
||||
* TODO Get the from config and/or localized.
|
||||
* @type {string}
|
||||
*/
|
||||
export const LOCAL_PARTICIPANT_DEFAULT_NAME = 'me';
|
||||
|
||||
/**
|
||||
* Max length of the display names.
|
||||
*
|
||||
|
|
|
@ -11,6 +11,7 @@ import {
|
|||
} from './actionTypes';
|
||||
import {
|
||||
LOCAL_PARTICIPANT_DEFAULT_ID,
|
||||
LOCAL_PARTICIPANT_DEFAULT_NAME,
|
||||
PARTICIPANT_ROLE
|
||||
} from './constants';
|
||||
|
||||
|
@ -99,7 +100,12 @@ function _participant(state, action) {
|
|||
// name
|
||||
if (!name) {
|
||||
// TODO Get the from config and/or localized.
|
||||
name = local ? 'me' : 'Fellow Jitster';
|
||||
// On web default value is handled in:
|
||||
// conference.js getParticipantDisplayName
|
||||
if (typeof APP === 'undefined') {
|
||||
name
|
||||
= local ? LOCAL_PARTICIPANT_DEFAULT_NAME : 'Fellow Jitster';
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
@ -29,8 +29,6 @@ RouteRegistry.register({
|
|||
* @returns {void}
|
||||
*/
|
||||
function _initConference() {
|
||||
_setTokenData();
|
||||
|
||||
// Initialize the conference URL handler
|
||||
APP.ConferenceUrl = new ConferenceUrl(window.location);
|
||||
}
|
||||
|
@ -102,22 +100,3 @@ function _obtainConfigHandler() {
|
|||
APP.connectionTimes['configuration.fetched'] = now;
|
||||
logger.log('(TIME) configuration fetched:\t', now);
|
||||
}
|
||||
|
||||
/**
|
||||
* If JWT token data it will be used for local user settings.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
function _setTokenData() {
|
||||
const state = APP.store.getState();
|
||||
const { caller } = state['features/base/jwt'];
|
||||
|
||||
if (caller) {
|
||||
const { avatarUrl, avatar, email, name } = caller;
|
||||
|
||||
APP.settings.setEmail((email || '').trim(), true);
|
||||
APP.settings.setAvatarUrl((avatarUrl || avatar || '').trim());
|
||||
APP.settings.setDisplayName((name || '').trim(), true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
declare var interfaceConfig: Object;
|
||||
|
||||
import {
|
||||
getPinnedParticipant,
|
||||
getLocalParticipant
|
||||
getPinnedParticipant
|
||||
} from '../base/participants';
|
||||
|
||||
/**
|
||||
|
@ -17,6 +16,7 @@ import {
|
|||
export function shouldRemoteVideosBeVisible(state: Object) {
|
||||
const participants = state['features/base/participants'];
|
||||
const participantsCount = participants.length;
|
||||
const pinnedParticipant = getPinnedParticipant(state);
|
||||
|
||||
const shouldShowVideos
|
||||
= participantsCount > 2
|
||||
|
@ -27,7 +27,7 @@ export function shouldRemoteVideosBeVisible(state: Object) {
|
|||
|| (participantsCount > 1
|
||||
&& (state['features/filmstrip'].hovered
|
||||
|| state['features/toolbox'].visible
|
||||
|| getLocalParticipant(state) === getPinnedParticipant(state)))
|
||||
|| (pinnedParticipant && pinnedParticipant.local)))
|
||||
|
||||
|| interfaceConfig.filmStripOnly
|
||||
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
/* global APP, interfaceConfig */
|
||||
/* global interfaceConfig */
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { Dialog } from '../../base/dialog';
|
||||
import { translate } from '../../base/i18n';
|
||||
|
||||
import { getLocalParticipant } from '../../base/participants';
|
||||
import SpeakerStatsItem from './SpeakerStatsItem';
|
||||
import SpeakerStatsLabels from './SpeakerStatsLabels';
|
||||
|
||||
|
@ -21,6 +22,12 @@ class SpeakerStats extends Component {
|
|||
* @static
|
||||
*/
|
||||
static propTypes = {
|
||||
/**
|
||||
* The display name for the local participant obtained from the Redux
|
||||
* store.
|
||||
*/
|
||||
_localDisplayName: PropTypes.string,
|
||||
|
||||
/**
|
||||
* The JitsiConference from which stats will be pulled.
|
||||
*/
|
||||
|
@ -130,7 +137,7 @@ class SpeakerStats extends Component {
|
|||
const { t } = this.props;
|
||||
const meString = t('me');
|
||||
|
||||
displayName = APP.settings.getDisplayName();
|
||||
displayName = this.props._localDisplayName;
|
||||
displayName = displayName ? `${displayName} (${meString})`
|
||||
: meString;
|
||||
} else {
|
||||
|
@ -149,4 +156,26 @@ class SpeakerStats extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
export default translate(SpeakerStats);
|
||||
/**
|
||||
* Maps (parts of) the Redux state to the associated SpeakerStats's props.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @private
|
||||
* @returns {{
|
||||
* _localDisplayName: string?
|
||||
* }}
|
||||
*/
|
||||
function _mapStateToProps(state) {
|
||||
const localParticipant = getLocalParticipant(state);
|
||||
|
||||
return {
|
||||
/**
|
||||
* The local display name.
|
||||
* @private
|
||||
* @type {string|undefined}
|
||||
*/
|
||||
_localDisplayName: localParticipant && localParticipant.name
|
||||
};
|
||||
}
|
||||
|
||||
export default translate(connect(_mapStateToProps)(SpeakerStats));
|
||||
|
|
Loading…
Reference in New Issue