feat(avatar) add ability to customize Gravatar base URL
Also, default to libravatar. Closes: https://github.com/jitsi/jitsi-meet/issues/4927
This commit is contained in:
parent
696ec36c8c
commit
a7de8be0aa
|
@ -393,6 +393,9 @@ var config = {
|
||||||
// Document should be focused for this option to work
|
// Document should be focused for this option to work
|
||||||
// enableAutomaticUrlCopy: false,
|
// enableAutomaticUrlCopy: false,
|
||||||
|
|
||||||
|
// Base URL for a Gravatar-compatible service. Defaults to libravatar.
|
||||||
|
// gravatarBaseURL: 'https://seccdn.libravatar.org/avatar/';
|
||||||
|
|
||||||
// Stats
|
// Stats
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
|
@ -3302,9 +3302,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@jitsi/js-utils": {
|
"@jitsi/js-utils": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@jitsi/js-utils/-/js-utils-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@jitsi/js-utils/-/js-utils-1.0.3.tgz",
|
||||||
"integrity": "sha512-ls+X9tn9EemUQwPEBr7Z0UD4sjRtwcu1Bh4MUo0Hv4arp0KVzcCYCW+mofsvuZvHg8xJX12LLNVgUKi1X5XTGg==",
|
"integrity": "sha512-m6mZz7R716mHP21lTKQffyM0nNFu3Fe/EHCaOVLFY/vdPsaUl9DhypJqtPIYzRUfPnmnugdaxcxrUeSZQXQzVA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"bowser": "2.7.0",
|
"bowser": "2.7.0",
|
||||||
"js-md5": "0.7.3"
|
"js-md5": "0.7.3"
|
||||||
|
@ -10792,6 +10792,20 @@
|
||||||
"webrtc-adapter": "7.5.0"
|
"webrtc-adapter": "7.5.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@jitsi/js-utils": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@jitsi/js-utils/-/js-utils-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-ls+X9tn9EemUQwPEBr7Z0UD4sjRtwcu1Bh4MUo0Hv4arp0KVzcCYCW+mofsvuZvHg8xJX12LLNVgUKi1X5XTGg==",
|
||||||
|
"requires": {
|
||||||
|
"bowser": "2.7.0",
|
||||||
|
"js-md5": "0.7.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"js-md5": {
|
||||||
|
"version": "0.7.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/js-md5/-/js-md5-0.7.3.tgz",
|
||||||
|
"integrity": "sha512-ZC41vPSTLKGwIRjqDh8DfXoCrdQIyBgspJVPXHBGu4nZlAEvG3nf+jO9avM9RmLiGakg7vz974ms99nEV0tmTQ=="
|
||||||
|
},
|
||||||
"uuid": {
|
"uuid": {
|
||||||
"version": "8.1.0",
|
"version": "8.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.1.0.tgz",
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
"@atlaskit/theme": "7.0.2",
|
"@atlaskit/theme": "7.0.2",
|
||||||
"@atlaskit/toggle": "5.0.14",
|
"@atlaskit/toggle": "5.0.14",
|
||||||
"@atlaskit/tooltip": "12.1.13",
|
"@atlaskit/tooltip": "12.1.13",
|
||||||
"@jitsi/js-utils": "1.0.2",
|
"@jitsi/js-utils": "1.0.3",
|
||||||
"@microsoft/microsoft-graph-client": "1.1.0",
|
"@microsoft/microsoft-graph-client": "1.1.0",
|
||||||
"@react-native-community/async-storage": "1.3.4",
|
"@react-native-community/async-storage": "1.3.4",
|
||||||
"@react-native-community/google-signin": "3.0.1",
|
"@react-native-community/google-signin": "3.0.1",
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import { getGravatarURL } from '@jitsi/js-utils/avatar';
|
import { getGravatarURL } from '@jitsi/js-utils/avatar';
|
||||||
|
import type { Store } from 'redux';
|
||||||
|
|
||||||
import { JitsiParticipantConnectionStatus } from '../lib-jitsi-meet';
|
import { JitsiParticipantConnectionStatus } from '../lib-jitsi-meet';
|
||||||
import { MEDIA_TYPE, shouldRenderVideoTrack } from '../media';
|
import { MEDIA_TYPE, shouldRenderVideoTrack } from '../media';
|
||||||
|
@ -23,30 +24,35 @@ declare var interfaceConfig: Object;
|
||||||
*/
|
*/
|
||||||
const AVATAR_QUEUE = [];
|
const AVATAR_QUEUE = [];
|
||||||
const AVATAR_CHECKED_URLS = new Map();
|
const AVATAR_CHECKED_URLS = new Map();
|
||||||
/* eslint-disable arrow-body-style */
|
/* eslint-disable arrow-body-style, no-unused-vars */
|
||||||
const AVATAR_CHECKER_FUNCTIONS = [
|
const AVATAR_CHECKER_FUNCTIONS = [
|
||||||
participant => {
|
(participant, _) => {
|
||||||
return participant && participant.isJigasi ? JIGASI_PARTICIPANT_ICON : null;
|
return participant && participant.isJigasi ? JIGASI_PARTICIPANT_ICON : null;
|
||||||
},
|
},
|
||||||
participant => {
|
(participant, _) => {
|
||||||
return participant && participant.avatarURL ? participant.avatarURL : null;
|
return participant && participant.avatarURL ? participant.avatarURL : null;
|
||||||
},
|
},
|
||||||
participant => {
|
(participant, store) => {
|
||||||
return participant && participant.email ? getGravatarURL(participant.email) : null;
|
if (participant && participant.email) {
|
||||||
|
return getGravatarURL(participant.email, store.getState()['features/base/config'].gravatarBaseURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
/* eslint-enable arrow-body-style */
|
/* eslint-enable arrow-body-style, no-unused-vars */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves the first loadable avatar URL for a participant.
|
* Resolves the first loadable avatar URL for a participant.
|
||||||
*
|
*
|
||||||
* @param {Object} participant - The participant to resolve avatars for.
|
* @param {Object} participant - The participant to resolve avatars for.
|
||||||
|
* @param {Store} store - Redux store.
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
export function getFirstLoadableAvatarUrl(participant: Object) {
|
export function getFirstLoadableAvatarUrl(participant: Object, store: Store<any, any>) {
|
||||||
const deferred = createDeferred();
|
const deferred = createDeferred();
|
||||||
const fullPromise = deferred.promise
|
const fullPromise = deferred.promise
|
||||||
.then(() => _getFirstLoadableAvatarUrl(participant))
|
.then(() => _getFirstLoadableAvatarUrl(participant, store))
|
||||||
.then(src => {
|
.then(src => {
|
||||||
|
|
||||||
if (AVATAR_QUEUE.length) {
|
if (AVATAR_QUEUE.length) {
|
||||||
|
@ -402,11 +408,12 @@ export function figureOutMutedWhileDisconnectedStatus(
|
||||||
* Resolves the first loadable avatar URL for a participant.
|
* Resolves the first loadable avatar URL for a participant.
|
||||||
*
|
*
|
||||||
* @param {Object} participant - The participant to resolve avatars for.
|
* @param {Object} participant - The participant to resolve avatars for.
|
||||||
|
* @param {Store} store - Redux store.
|
||||||
* @returns {?string}
|
* @returns {?string}
|
||||||
*/
|
*/
|
||||||
async function _getFirstLoadableAvatarUrl(participant) {
|
async function _getFirstLoadableAvatarUrl(participant, store) {
|
||||||
for (let i = 0; i < AVATAR_CHECKER_FUNCTIONS.length; i++) {
|
for (let i = 0; i < AVATAR_CHECKER_FUNCTIONS.length; i++) {
|
||||||
const url = AVATAR_CHECKER_FUNCTIONS[i](participant);
|
const url = AVATAR_CHECKER_FUNCTIONS[i](participant, store);
|
||||||
|
|
||||||
if (url) {
|
if (url) {
|
||||||
if (AVATAR_CHECKED_URLS.has(url)) {
|
if (AVATAR_CHECKED_URLS.has(url)) {
|
||||||
|
|
|
@ -365,7 +365,8 @@ function _maybePlaySounds({ getState, dispatch }, action) {
|
||||||
* @private
|
* @private
|
||||||
* @returns {Object} The value returned by {@code next(action)}.
|
* @returns {Object} The value returned by {@code next(action)}.
|
||||||
*/
|
*/
|
||||||
function _participantJoinedOrUpdated({ dispatch, getState }, next, action) {
|
function _participantJoinedOrUpdated(store, next, action) {
|
||||||
|
const { dispatch, getState } = store;
|
||||||
const { participant: { avatarURL, e2eeEnabled, email, id, local, name, raisedHand } } = action;
|
const { participant: { avatarURL, e2eeEnabled, email, id, local, name, raisedHand } } = action;
|
||||||
|
|
||||||
// Send an external update of the local participant's raised hand state
|
// Send an external update of the local participant's raised hand state
|
||||||
|
@ -401,7 +402,7 @@ function _participantJoinedOrUpdated({ dispatch, getState }, next, action) {
|
||||||
const participantId = !id && local ? getLocalParticipant(getState()).id : id;
|
const participantId = !id && local ? getLocalParticipant(getState()).id : id;
|
||||||
const updatedParticipant = getParticipantById(getState(), participantId);
|
const updatedParticipant = getParticipantById(getState(), participantId);
|
||||||
|
|
||||||
getFirstLoadableAvatarUrl(updatedParticipant)
|
getFirstLoadableAvatarUrl(updatedParticipant, store)
|
||||||
.then(url => {
|
.then(url => {
|
||||||
dispatch(setLoadableAvatarUrl(participantId, url));
|
dispatch(setLoadableAvatarUrl(participantId, url));
|
||||||
});
|
});
|
||||||
|
|
|
@ -144,12 +144,13 @@ function _conferenceJoined({ dispatch }, next, action) {
|
||||||
* @param {Object} participant - The knocking participant.
|
* @param {Object} participant - The knocking participant.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
function _findLoadableAvatarForKnockingParticipant({ dispatch, getState }, { id }) {
|
function _findLoadableAvatarForKnockingParticipant(store, { id }) {
|
||||||
|
const { dispatch, getState } = store;
|
||||||
const updatedParticipant = getState()['features/lobby'].knockingParticipants.find(p => p.id === id);
|
const updatedParticipant = getState()['features/lobby'].knockingParticipants.find(p => p.id === id);
|
||||||
const { disableThirdPartyRequests } = getState()['features/base/config'];
|
const { disableThirdPartyRequests } = getState()['features/base/config'];
|
||||||
|
|
||||||
if (!disableThirdPartyRequests && updatedParticipant && !updatedParticipant.loadableAvatarUrl) {
|
if (!disableThirdPartyRequests && updatedParticipant && !updatedParticipant.loadableAvatarUrl) {
|
||||||
getFirstLoadableAvatarUrl(updatedParticipant).then(loadableAvatarUrl => {
|
getFirstLoadableAvatarUrl(updatedParticipant, store).then(loadableAvatarUrl => {
|
||||||
if (loadableAvatarUrl) {
|
if (loadableAvatarUrl) {
|
||||||
dispatch(participantIsKnockingOrUpdated({
|
dispatch(participantIsKnockingOrUpdated({
|
||||||
loadableAvatarUrl,
|
loadableAvatarUrl,
|
||||||
|
|
Loading…
Reference in New Issue