Просмотр исходного кода

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
master
paweldomas 7 лет назад
Родитель
Сommit
8a4e6a7ec0

+ 27
- 42
conference.js Просмотреть файл

@@ -30,7 +30,8 @@ import {
30 30
     toggleAudioOnly,
31 31
     EMAIL_COMMAND,
32 32
     lockStateChanged,
33
-    p2pStatusChanged
33
+    p2pStatusChanged,
34
+    setLocalParticipantData
34 35
 } from './react/features/base/conference';
35 36
 import { updateDeviceList } from './react/features/base/devices';
36 37
 import {
@@ -55,6 +56,8 @@ import {
55 56
 } from './react/features/base/media';
56 57
 import {
57 58
     dominantSpeakerChanged,
59
+    getLocalParticipant,
60
+    getParticipantById,
58 61
     localParticipantConnectionStatusChanged,
59 62
     localParticipantRoleChanged,
60 63
     MAX_DISPLAY_NAME_LENGTH,
@@ -143,43 +146,15 @@ function sendData(command, value) {
143 146
     room.sendCommand(command, {value: value});
144 147
 }
145 148
 
146
-/**
147
- * Sets up initially the properties of the local participant - email, avatarID,
148
- * avatarURL, displayName, etc.
149
- */
150
-function _setupLocalParticipantProperties() {
151
-    const email = APP.settings.getEmail();
152
-    email && sendData(commands.EMAIL, email);
153
-
154
-    const avatarUrl = APP.settings.getAvatarUrl();
155
-    avatarUrl && sendData(commands.AVATAR_URL, avatarUrl);
156
-
157
-    if (!email && !avatarUrl) {
158
-        sendData(commands.AVATAR_ID, APP.settings.getAvatarId());
159
-    }
160
-
161
-    let nick = APP.settings.getDisplayName();
162
-    if (config.useNicks && !nick) {
163
-        nick = APP.UI.askForNickname();
164
-        APP.settings.setDisplayName(nick);
165
-    }
166
-    nick && room.setDisplayName(nick);
167
-}
168
-
169 149
 /**
170 150
  * Get user nickname by user id.
171 151
  * @param {string} id user id
172 152
  * @returns {string?} user nickname or undefined if user is unknown.
173 153
  */
174 154
 function getDisplayName(id) {
175
-    if (APP.conference.isLocalId(id)) {
176
-        return APP.settings.getDisplayName();
177
-    }
155
+    const participant = getParticipantById(APP.store.getState(), id);
178 156
 
179
-    let participant = room.getParticipantById(id);
180
-    if (participant && participant.getDisplayName()) {
181
-        return participant.getDisplayName();
182
-    }
157
+    return participant && participant.name;
183 158
 }
184 159
 
185 160
 /**
@@ -989,6 +964,13 @@ export default {
989 964
     isConnectionInterrupted() {
990 965
         return this._room.isConnectionInterrupted();
991 966
     },
967
+    /**
968
+     * Obtains the local display name.
969
+     * @returns {string|undefined}
970
+     */
971
+    getLocalDisplayName() {
972
+        return getDisplayName(this.getMyUserId());
973
+    },
992 974
     /**
993 975
      * Finds JitsiParticipant for given id.
994 976
      *
@@ -1162,7 +1144,7 @@ export default {
1162 1144
         this._setLocalAudioVideoStreams(localTracks);
1163 1145
         this._room = room; // FIXME do not use this
1164 1146
 
1165
-        _setupLocalParticipantProperties();
1147
+        setLocalParticipantData(room, APP.store.getState());
1166 1148
 
1167 1149
         this._setupListeners();
1168 1150
     },
@@ -2420,13 +2402,15 @@ export default {
2420 2402
      * @param email {string} the new email
2421 2403
      */
2422 2404
     changeLocalEmail(email = '') {
2405
+        const localParticipant = getLocalParticipant(APP.store.getState());
2406
+
2423 2407
         email = String(email).trim();
2424 2408
 
2425
-        if (email === APP.settings.getEmail()) {
2409
+        if (email === localParticipant.email) {
2426 2410
             return;
2427 2411
         }
2428 2412
 
2429
-        const localId = room ? room.myUserId() : undefined;
2413
+        const localId = localParticipant.id;
2430 2414
 
2431 2415
         APP.store.dispatch(participantUpdated({
2432 2416
             id: localId,
@@ -2444,22 +2428,22 @@ export default {
2444 2428
      * @param url {string} the new url
2445 2429
      */
2446 2430
     changeLocalAvatarUrl(url = '') {
2431
+        const { avatarURL, id } = getLocalParticipant(APP.store.getState());
2432
+
2447 2433
         url = String(url).trim();
2448 2434
 
2449
-        if (url === APP.settings.getAvatarUrl()) {
2435
+        if (url === avatarURL) {
2450 2436
             return;
2451 2437
         }
2452 2438
 
2453
-        const localId = room ? room.myUserId() : undefined;
2454
-
2455 2439
         APP.store.dispatch(participantUpdated({
2456
-            id: localId,
2440
+            id,
2457 2441
             local: true,
2458 2442
             avatarURL: url
2459 2443
         }));
2460 2444
 
2461 2445
         APP.settings.setAvatarUrl(url);
2462
-        APP.UI.setUserAvatarUrl(localId, url);
2446
+        APP.UI.setUserAvatarUrl(id, url);
2463 2447
         sendData(commands.AVATAR_URL, url);
2464 2448
     },
2465 2449
 
@@ -2501,13 +2485,14 @@ export default {
2501 2485
     changeLocalDisplayName(nickname = '') {
2502 2486
         const formattedNickname
2503 2487
             = nickname.trim().substr(0, MAX_DISPLAY_NAME_LENGTH);
2488
+        const { id, name } = getLocalParticipant(APP.store.getState());
2504 2489
 
2505
-        if (formattedNickname === APP.settings.getDisplayName()) {
2490
+        if (formattedNickname === name) {
2506 2491
             return;
2507 2492
         }
2508 2493
 
2509 2494
         APP.store.dispatch(participantUpdated({
2510
-            id: this.getMyUserId(),
2495
+            id,
2511 2496
             local: true,
2512 2497
             name: formattedNickname
2513 2498
         }));
@@ -2515,7 +2500,7 @@ export default {
2515 2500
         APP.settings.setDisplayName(formattedNickname);
2516 2501
         if (room) {
2517 2502
             room.setDisplayName(formattedNickname);
2518
-            APP.UI.changeDisplayName(this.getMyUserId(), formattedNickname);
2503
+            APP.UI.changeDisplayName(id, formattedNickname);
2519 2504
         }
2520 2505
     },
2521 2506
 

+ 8
- 6
modules/UI/UI.js Просмотреть файл

@@ -19,7 +19,6 @@ import VideoLayout from "./videolayout/VideoLayout";
19 19
 import Filmstrip from "./videolayout/Filmstrip";
20 20
 import SettingsMenu from "./side_pannels/settings/SettingsMenu";
21 21
 import Profile from "./side_pannels/profile/Profile";
22
-import Settings from "./../settings/Settings";
23 22
 
24 23
 import { updateDeviceList } from '../../react/features/base/devices';
25 24
 import { JitsiTrackErrors } from '../../react/features/base/lib-jitsi-meet';
@@ -42,6 +41,7 @@ import {
42 41
     maybeShowNotificationWithDoNotDisplay,
43 42
     setNotificationsEnabled
44 43
 } from '../../react/features/notifications';
44
+import { getLocalParticipant } from '../../react/features/base/participants';
45 45
 
46 46
 var EventEmitter = require("events");
47 47
 UI.messageHandler = messageHandler;
@@ -199,7 +199,8 @@ UI.setLocalRaisedHandStatus
199 199
  * Initialize conference UI.
200 200
  */
201 201
 UI.initConference = function () {
202
-    let id = APP.conference.getMyUserId();
202
+    const { id, avatarID, email, name }
203
+        = getLocalParticipant(APP.store.getState());
203 204
 
204 205
     // Update default button states before showing the toolbar
205 206
     // if local role changes buttons state will be again updated.
@@ -207,18 +208,17 @@ UI.initConference = function () {
207 208
 
208 209
     UI.showToolbar();
209 210
 
210
-    let displayName = config.displayJids ? id : Settings.getDisplayName();
211
+    let displayName = config.displayJids ? id : name;
211 212
 
212 213
     if (displayName) {
213 214
         UI.changeDisplayName('localVideoContainer', displayName);
214 215
     }
215 216
 
216 217
     // Make sure we configure our avatar id, before creating avatar for us
217
-    let email = Settings.getEmail();
218 218
     if (email) {
219 219
         UI.setUserEmail(id, email);
220 220
     } else {
221
-        UI.setUserAvatarID(id, Settings.getAvatarId());
221
+        UI.setUserAvatarID(id, avatarID);
222 222
     }
223 223
 
224 224
     APP.store.dispatch(checkAutoEnableDesktopSharing());
@@ -235,7 +235,9 @@ UI.mucJoined = function () {
235 235
 
236 236
     // Update local video now that a conference is joined a user ID should be
237 237
     // set.
238
-    UI.changeDisplayName('localVideoContainer', APP.settings.getDisplayName());
238
+    UI.changeDisplayName(
239
+        'localVideoContainer',
240
+        APP.conference.getLocalDisplayName());
239 241
 };
240 242
 
241 243
 /***

+ 2
- 2
modules/UI/side_pannels/chat/Chat.js Просмотреть файл

@@ -187,7 +187,7 @@ var Chat = {
187 187
      */
188 188
     init (eventEmitter) {
189 189
         initHTML();
190
-        if (APP.settings.getDisplayName()) {
190
+        if (APP.conference.getLocalDisplayName()) {
191 191
             Chat.setChatConversationMode(true);
192 192
         }
193 193
 
@@ -244,7 +244,7 @@ var Chat = {
244 244
 
245 245
                 // if we are in conversation mode focus on the text input
246 246
                 // if we are not, focus on the display name input
247
-                if (APP.settings.getDisplayName())
247
+                if (APP.conference.getLocalDisplayName())
248 248
                     deferredFocus('usermsg');
249 249
                 else
250 250
                     deferredFocus('nickinput');

+ 5
- 19
react/features/base/conference/actions.js Просмотреть файл

@@ -5,7 +5,6 @@ import { JitsiConferenceEvents } from '../lib-jitsi-meet';
5 5
 import { setAudioMuted, setVideoMuted } from '../media';
6 6
 import {
7 7
     dominantSpeakerChanged,
8
-    getLocalParticipant,
9 8
     participantConnectionStatusChanged,
10 9
     participantJoined,
11 10
     participantLeft,
@@ -36,7 +35,10 @@ import {
36 35
     EMAIL_COMMAND,
37 36
     JITSI_CONFERENCE_URL_KEY
38 37
 } from './constants';
39
-import { _addLocalTracksToConference } from './functions';
38
+import {
39
+    _addLocalTracksToConference,
40
+    setLocalParticipantData
41
+} from './functions';
40 42
 
41 43
 import type { Dispatch } from 'redux';
42 44
 
@@ -147,22 +149,6 @@ function _addConferenceListeners(conference, dispatch) {
147 149
         })));
148 150
 }
149 151
 
150
-/**
151
- * Sets the data for the local participant to the conference.
152
- *
153
- * @param {JitsiConference} conference - The JitsiConference instance.
154
- * @param {Object} state - The Redux state.
155
- * @returns {void}
156
- */
157
-function _setLocalParticipantData(conference, state) {
158
-    const { avatarID } = getLocalParticipant(state);
159
-
160
-    conference.removeCommand(AVATAR_ID_COMMAND);
161
-    conference.sendCommand(AVATAR_ID_COMMAND, {
162
-        value: avatarID
163
-    });
164
-}
165
-
166 152
 /**
167 153
  * Signals that a specific conference has failed.
168 154
  *
@@ -302,7 +288,7 @@ export function createConference() {
302 288
 
303 289
         _addConferenceListeners(conference, dispatch);
304 290
 
305
-        _setLocalParticipantData(conference, state);
291
+        setLocalParticipantData(conference, state);
306 292
 
307 293
         conference.join(password);
308 294
     };

+ 29
- 0
react/features/base/conference/functions.js Просмотреть файл

@@ -1,4 +1,10 @@
1
+import {
2
+    AVATAR_ID_COMMAND,
3
+    AVATAR_URL_COMMAND,
4
+    EMAIL_COMMAND
5
+} from './constants';
1 6
 import { JitsiTrackErrors } from '../lib-jitsi-meet';
7
+import { getLocalParticipant } from '../participants';
2 8
 import { toState } from '../redux';
3 9
 
4 10
 /**
@@ -121,3 +127,26 @@ function _reportError(msg, err) {
121 127
     // one.
122 128
     console.error(msg, err);
123 129
 }
130
+
131
+/**
132
+ * Sets the data like avatar URL, email and display name for the local
133
+ * participant to the conference.
134
+ *
135
+ * @param {JitsiConference} conference - The JitsiConference instance.
136
+ * @param {Object} state - The whole Redux state.
137
+ * @returns {void}
138
+ */
139
+export function setLocalParticipantData(conference, state) {
140
+    const { avatarID, avatarURL, email, name } = getLocalParticipant(state);
141
+
142
+    avatarID && conference.sendCommand(AVATAR_ID_COMMAND, {
143
+        value: avatarID
144
+    });
145
+    avatarURL && conference.sendCommand(AVATAR_URL_COMMAND, {
146
+        value: avatarURL
147
+    });
148
+    email && conference.sendCommand(EMAIL_COMMAND, {
149
+        value: email
150
+    });
151
+    conference.setDisplayName(name);
152
+}

+ 2
- 1
react/features/base/connection/actions.web.js Просмотреть файл

@@ -72,7 +72,8 @@ export function connect() {
72 72
 
73 73
             APP.keyboardshortcut.init();
74 74
 
75
-            if (config.requireDisplayName && !APP.settings.getDisplayName()) {
75
+            if (config.requireDisplayName
76
+                    && !APP.conference.getLocalDisplayName()) {
76 77
                 APP.UI.promptDisplayName();
77 78
             }
78 79
         })

+ 114
- 2
react/features/base/jwt/middleware.js Просмотреть файл

@@ -12,7 +12,9 @@ import { LIB_INIT_ERROR } from '../lib-jitsi-meet';
12 12
 import {
13 13
     getLocalParticipant,
14 14
     getParticipantCount,
15
-    PARTICIPANT_JOINED
15
+    LOCAL_PARTICIPANT_DEFAULT_NAME,
16
+    PARTICIPANT_JOINED,
17
+    participantUpdated
16 18
 } from '../participants';
17 19
 import { MiddlewareRegistry } from '../redux';
18 20
 
@@ -119,6 +121,103 @@ function _maybeSetCallOverlayVisible({ dispatch, getState }, next, action) {
119 121
     return result;
120 122
 }
121 123
 
124
+/**
125
+ * Converts 'context.user' JWT token structure to the format compatible with the
126
+ * corresponding fields overridden in base/participants.
127
+ *
128
+ * @param {Object} user - The 'jwt.context.user' structure parsed from the JWT
129
+ * token.
130
+ * @returns {({
131
+ *      avatarURL: string?,
132
+ *      email: string?,
133
+ *      name: string?
134
+ * })}
135
+ * @private
136
+ */
137
+function _normalizeCallerFields(user) {
138
+    const { avatar, avatarUrl, email, name } = user;
139
+    const caller = { };
140
+
141
+    if (typeof (avatarUrl || avatar) === 'string') {
142
+        caller.avatarURL = (avatarUrl || avatar).trim();
143
+    }
144
+    if (typeof email === 'string') {
145
+        caller.email = email.trim();
146
+    }
147
+    if (typeof name === 'string') {
148
+        caller.name = name.trim();
149
+    }
150
+
151
+    return Object.keys(caller).length ? caller : undefined;
152
+}
153
+
154
+/**
155
+ * Eventually overwrites 'avatarURL', 'email' and 'name' fields with the values
156
+ * from JWT token for the local participant stored in the 'base/participants'
157
+ * Redux store by dispatching the participant updated action.
158
+ *
159
+ * @param {Store} store - The redux store.
160
+ * @param {Object} caller - The "caller" structure parsed from 'context.user'
161
+ * part of the JWT token and then normalized using
162
+ * {@link _normalizeCallerFields}.
163
+ * @returns {void}
164
+ * @private
165
+ */
166
+function _overwriteLocalParticipant({ dispatch, getState }, caller) {
167
+    const { avatarURL, email, name } = caller;
168
+    const localParticipant = getLocalParticipant(getState());
169
+
170
+    if (localParticipant && (avatarURL || email || name)) {
171
+        const newProperties = { id: localParticipant.id };
172
+
173
+        if (avatarURL) {
174
+            newProperties.avatarURL = avatarURL;
175
+        }
176
+        if (email) {
177
+            newProperties.email = email;
178
+        }
179
+        if (name) {
180
+            newProperties.name = name;
181
+        }
182
+        dispatch(participantUpdated(newProperties));
183
+    }
184
+}
185
+
186
+/**
187
+ * Will reset the values overridden by {@link _overwriteLocalParticipant}
188
+ * by either clearing them or setting to default values. Only the values that
189
+ * have not changed since the override happened will be restored.
190
+ *
191
+ * NOTE Once there is the possibility to edit and save participant properties,
192
+ * this method should restore values from the storage instead.
193
+ *
194
+ * @param {Store} store - The Redux store.
195
+ * @param {Object} caller - The 'caller' part of the JWT Redux state which tells
196
+ * which local participant's fields's been overridden when the JWT token was
197
+ * set.
198
+ * @returns {void}
199
+ * @private
200
+ */
201
+function _resetLocalParticipantOverrides({ dispatch, getState }, caller) {
202
+    const { avatarURL, name, email } = caller;
203
+    const localParticipant = getLocalParticipant(getState());
204
+
205
+    if (localParticipant && (avatarURL || name || email)) {
206
+        const newProperties = { id: localParticipant.id };
207
+
208
+        if (avatarURL === localParticipant.avatarURL) {
209
+            newProperties.avatarURL = undefined;
210
+        }
211
+        if (name === localParticipant.name) {
212
+            newProperties.name = LOCAL_PARTICIPANT_DEFAULT_NAME;
213
+        }
214
+        if (email === localParticipant.email) {
215
+            newProperties.email = undefined;
216
+        }
217
+        dispatch(participantUpdated(newProperties));
218
+    }
219
+}
220
+
122 221
 /**
123 222
  * Notifies the feature jwt that the action {@link SET_CONFIG} or
124 223
  * {@link SET_LOCATION_URL} is being dispatched within a specific redux
@@ -183,11 +282,24 @@ function _setJWT(store, next, action) {
183 282
             action.issuer = iss;
184 283
             if (context) {
185 284
                 action.callee = context.callee;
186
-                action.caller = context.user;
285
+                action.caller = _normalizeCallerFields(context.user);
187 286
                 action.group = context.group;
188 287
                 action.server = context.server;
288
+
289
+                if (action.caller) {
290
+                    _overwriteLocalParticipant(store, action.caller);
291
+                }
189 292
             }
190 293
         }
294
+    } else if (!jwt && !Object.keys(actionPayload).length) {
295
+        const jwtState = store.getState()['features/base/jwt'];
296
+
297
+        // The logic of restoring JWT overrides make sense only on mobile. On
298
+        // web it should eventually be restored from storage, but there's no
299
+        // such use case yet.
300
+        if (jwtState.caller && typeof APP === 'undefined') {
301
+            _resetLocalParticipantOverrides(store, jwtState.caller);
302
+        }
191 303
     }
192 304
 
193 305
     return _maybeSetCallOverlayVisible(store, next, action);

+ 7
- 0
react/features/base/participants/constants.js Просмотреть файл

@@ -21,6 +21,13 @@ export const DEFAULT_AVATAR_RELATIVE_PATH = 'images/avatar.png';
21 21
  */
22 22
 export const LOCAL_PARTICIPANT_DEFAULT_ID = 'local';
23 23
 
24
+/**
25
+ * The default display name for the local participant.
26
+ * TODO Get the from config and/or localized.
27
+ * @type {string}
28
+ */
29
+export const LOCAL_PARTICIPANT_DEFAULT_NAME = 'me';
30
+
24 31
 /**
25 32
  * Max length of the display names.
26 33
  *

+ 7
- 1
react/features/base/participants/reducer.js Просмотреть файл

@@ -11,6 +11,7 @@ import {
11 11
 } from './actionTypes';
12 12
 import {
13 13
     LOCAL_PARTICIPANT_DEFAULT_ID,
14
+    LOCAL_PARTICIPANT_DEFAULT_NAME,
14 15
     PARTICIPANT_ROLE
15 16
 } from './constants';
16 17
 
@@ -99,7 +100,12 @@ function _participant(state, action) {
99 100
         // name
100 101
         if (!name) {
101 102
             // TODO Get the from config and/or localized.
102
-            name = local ? 'me' : 'Fellow Jitster';
103
+            // On web default value is handled in:
104
+            // conference.js getParticipantDisplayName
105
+            if (typeof APP === 'undefined') {
106
+                name
107
+                    = local ? LOCAL_PARTICIPANT_DEFAULT_NAME : 'Fellow Jitster';
108
+            }
103 109
         }
104 110
 
105 111
         return {

+ 0
- 21
react/features/conference/route.js Просмотреть файл

@@ -29,8 +29,6 @@ RouteRegistry.register({
29 29
  * @returns {void}
30 30
  */
31 31
 function _initConference() {
32
-    _setTokenData();
33
-
34 32
     // Initialize the conference URL handler
35 33
     APP.ConferenceUrl = new ConferenceUrl(window.location);
36 34
 }
@@ -102,22 +100,3 @@ function _obtainConfigHandler() {
102 100
     APP.connectionTimes['configuration.fetched'] = now;
103 101
     logger.log('(TIME) configuration fetched:\t', now);
104 102
 }
105
-
106
-/**
107
- * If JWT token data it will be used for local user settings.
108
- *
109
- * @private
110
- * @returns {void}
111
- */
112
-function _setTokenData() {
113
-    const state = APP.store.getState();
114
-    const { caller } = state['features/base/jwt'];
115
-
116
-    if (caller) {
117
-        const { avatarUrl, avatar, email, name } = caller;
118
-
119
-        APP.settings.setEmail((email || '').trim(), true);
120
-        APP.settings.setAvatarUrl((avatarUrl || avatar || '').trim());
121
-        APP.settings.setDisplayName((name || '').trim(), true);
122
-    }
123
-}

+ 3
- 3
react/features/filmstrip/functions.js Просмотреть файл

@@ -3,8 +3,7 @@
3 3
 declare var interfaceConfig: Object;
4 4
 
5 5
 import {
6
-    getPinnedParticipant,
7
-    getLocalParticipant
6
+    getPinnedParticipant
8 7
 } from '../base/participants';
9 8
 
10 9
 /**
@@ -17,6 +16,7 @@ import {
17 16
 export function shouldRemoteVideosBeVisible(state: Object) {
18 17
     const participants = state['features/base/participants'];
19 18
     const participantsCount = participants.length;
19
+    const pinnedParticipant = getPinnedParticipant(state);
20 20
 
21 21
     const shouldShowVideos
22 22
         = participantsCount > 2
@@ -27,7 +27,7 @@ export function shouldRemoteVideosBeVisible(state: Object) {
27 27
         || (participantsCount > 1
28 28
             && (state['features/filmstrip'].hovered
29 29
                 || state['features/toolbox'].visible
30
-                || getLocalParticipant(state) === getPinnedParticipant(state)))
30
+                || (pinnedParticipant && pinnedParticipant.local)))
31 31
 
32 32
         || interfaceConfig.filmStripOnly
33 33
 

+ 33
- 4
react/features/speaker-stats/components/SpeakerStats.js Просмотреть файл

@@ -1,11 +1,12 @@
1
-/* global APP, interfaceConfig */
1
+/* global interfaceConfig */
2 2
 
3 3
 import PropTypes from 'prop-types';
4 4
 import React, { Component } from 'react';
5
+import { connect } from 'react-redux';
5 6
 
6 7
 import { Dialog } from '../../base/dialog';
7 8
 import { translate } from '../../base/i18n';
8
-
9
+import { getLocalParticipant } from '../../base/participants';
9 10
 import SpeakerStatsItem from './SpeakerStatsItem';
10 11
 import SpeakerStatsLabels from './SpeakerStatsLabels';
11 12
 
@@ -21,6 +22,12 @@ class SpeakerStats extends Component {
21 22
      * @static
22 23
      */
23 24
     static propTypes = {
25
+        /**
26
+         * The display name for the local participant obtained from the Redux
27
+         * store.
28
+         */
29
+        _localDisplayName: PropTypes.string,
30
+
24 31
         /**
25 32
          * The JitsiConference from which stats will be pulled.
26 33
          */
@@ -130,7 +137,7 @@ class SpeakerStats extends Component {
130 137
             const { t } = this.props;
131 138
             const meString = t('me');
132 139
 
133
-            displayName = APP.settings.getDisplayName();
140
+            displayName = this.props._localDisplayName;
134 141
             displayName = displayName ? `${displayName} (${meString})`
135 142
                 : meString;
136 143
         } else {
@@ -149,4 +156,26 @@ class SpeakerStats extends Component {
149 156
     }
150 157
 }
151 158
 
152
-export default translate(SpeakerStats);
159
+/**
160
+ * Maps (parts of) the Redux state to the associated SpeakerStats's props.
161
+ *
162
+ * @param {Object} state - The Redux state.
163
+ * @private
164
+ * @returns {{
165
+ *     _localDisplayName: string?
166
+ * }}
167
+ */
168
+function _mapStateToProps(state) {
169
+    const localParticipant = getLocalParticipant(state);
170
+
171
+    return {
172
+        /**
173
+         * The local display name.
174
+         * @private
175
+         * @type {string|undefined}
176
+         */
177
+        _localDisplayName: localParticipant && localParticipant.name
178
+    };
179
+}
180
+
181
+export default translate(connect(_mapStateToProps)(SpeakerStats));

Загрузка…
Отмена
Сохранить