feat(branding): Add custom avatar backgrounds
This commit is contained in:
parent
c10805f81b
commit
2bac757ca6
|
@ -574,6 +574,12 @@ function initCommands() {
|
|||
});
|
||||
break;
|
||||
}
|
||||
case 'get-custom-avatar-backgrounds' : {
|
||||
callback({
|
||||
avatarBackgrounds: APP.store.getState()['features/dynamic-branding'].avatarBackgrounds
|
||||
});
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -769,6 +769,17 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
|||
return getCurrentDevices(this._transport);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns any custom avatars backgrounds.
|
||||
*
|
||||
* @returns {Promise} - Resolves with the list of custom avatar backgrounds.
|
||||
*/
|
||||
getCustomAvatarBackgrounds() {
|
||||
return this._transport.sendRequest({
|
||||
name: 'get-custom-avatar-backgrounds'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current livestream url.
|
||||
*
|
||||
|
|
|
@ -21,6 +21,7 @@ const TOOLBAR_TIMEOUT = 4000;
|
|||
*/
|
||||
type State = {
|
||||
avatarURL: string,
|
||||
customAvatarBackgrounds: Array<string>,
|
||||
displayName: string,
|
||||
formattedDisplayName: string,
|
||||
isVideoDisplayed: boolean,
|
||||
|
@ -48,6 +49,7 @@ export default class AlwaysOnTop extends Component<*, State> {
|
|||
|
||||
this.state = {
|
||||
avatarURL: '',
|
||||
customAvatarBackgrounds: [],
|
||||
displayName: '',
|
||||
formattedDisplayName: '',
|
||||
isVideoDisplayed: true,
|
||||
|
@ -178,7 +180,14 @@ export default class AlwaysOnTop extends Component<*, State> {
|
|||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderVideoNotAvailableScreen() {
|
||||
const { avatarURL, displayName, formattedDisplayName, isVideoDisplayed, userID } = this.state;
|
||||
const {
|
||||
avatarURL,
|
||||
customAvatarBackgrounds,
|
||||
displayName,
|
||||
formattedDisplayName,
|
||||
isVideoDisplayed,
|
||||
userID
|
||||
} = this.state;
|
||||
|
||||
if (isVideoDisplayed) {
|
||||
return null;
|
||||
|
@ -188,7 +197,7 @@ export default class AlwaysOnTop extends Component<*, State> {
|
|||
<div id = 'videoNotAvailableScreen'>
|
||||
<div id = 'avatarContainer'>
|
||||
<StatelessAvatar
|
||||
color = { getAvatarColor(userID) }
|
||||
color = { getAvatarColor(userID, customAvatarBackgrounds) }
|
||||
id = 'avatar'
|
||||
initials = { getInitials(displayName) }
|
||||
url = { avatarURL } />)
|
||||
|
@ -218,6 +227,12 @@ export default class AlwaysOnTop extends Component<*, State> {
|
|||
window.addEventListener('mousemove', this._mouseMove);
|
||||
|
||||
this._hideToolbarAfterTimeout();
|
||||
api.getCustomAvatarBackgrounds()
|
||||
.then(res =>
|
||||
this.setState({
|
||||
customAvatarBackgrounds: res.avatarBackgrounds || []
|
||||
}))
|
||||
.catch(console.error);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -10,6 +10,11 @@ import { StatelessAvatar } from '.';
|
|||
|
||||
export type Props = {
|
||||
|
||||
/**
|
||||
* Custom avatar backgrounds from branding.
|
||||
*/
|
||||
_customAvatarBackgrounds: Array<string>,
|
||||
|
||||
/**
|
||||
* The string we base the initials on (this is generated from a list of precedences).
|
||||
*/
|
||||
|
@ -133,6 +138,7 @@ class Avatar<P: Props> extends PureComponent<P, State> {
|
|||
*/
|
||||
render() {
|
||||
const {
|
||||
_customAvatarBackgrounds,
|
||||
_initialsBase,
|
||||
_loadableAvatarUrl,
|
||||
className,
|
||||
|
@ -172,7 +178,7 @@ class Avatar<P: Props> extends PureComponent<P, State> {
|
|||
|
||||
if (initials) {
|
||||
if (dynamicColor) {
|
||||
avatarProps.color = getAvatarColor(colorBase || _initialsBase);
|
||||
avatarProps.color = getAvatarColor(colorBase || _initialsBase, _customAvatarBackgrounds);
|
||||
}
|
||||
|
||||
avatarProps.initials = initials;
|
||||
|
@ -211,6 +217,7 @@ export function _mapStateToProps(state: Object, ownProps: Props) {
|
|||
const _initialsBase = _participant?.name ?? displayName;
|
||||
|
||||
return {
|
||||
_customAvatarBackgrounds: state['features/dynamic-branding'].avatarBackgrounds,
|
||||
_initialsBase,
|
||||
_loadableAvatarUrl: _participant?.loadableAvatarUrl,
|
||||
colorBase: !colorBase && _participant ? _participant.id : colorBase
|
||||
|
|
|
@ -125,7 +125,7 @@ export default class StatelessAvatar extends AbstractStatelessAvatar<Props> {
|
|||
const { size } = this.props;
|
||||
|
||||
return {
|
||||
backgroundColor: color || undefined,
|
||||
background: color || undefined,
|
||||
fontSize: size ? size * 0.5 : '180%',
|
||||
height: size || '100%',
|
||||
width: size || '100%'
|
||||
|
|
|
@ -16,9 +16,13 @@ const AVATAR_OPACITY = 0.4;
|
|||
* Generates the background color of an initials based avatar.
|
||||
*
|
||||
* @param {string?} initials - The initials of the avatar.
|
||||
* @param {Array<strig>} customAvatarBackgrounds - Custom avatar background values.
|
||||
* @returns {string}
|
||||
*/
|
||||
export function getAvatarColor(initials: ?string) {
|
||||
export function getAvatarColor(initials: ?string, customAvatarBackgrounds: Array<string>) {
|
||||
const hasCustomAvatarBackgronds = customAvatarBackgrounds && customAvatarBackgrounds.length;
|
||||
const colorsBase = hasCustomAvatarBackgronds ? customAvatarBackgrounds : AVATAR_COLORS;
|
||||
|
||||
let colorIndex = 0;
|
||||
|
||||
if (initials) {
|
||||
|
@ -28,10 +32,10 @@ export function getAvatarColor(initials: ?string) {
|
|||
nameHash += s.codePointAt(0);
|
||||
}
|
||||
|
||||
colorIndex = nameHash % AVATAR_COLORS.length;
|
||||
colorIndex = nameHash % colorsBase.length;
|
||||
}
|
||||
|
||||
return `rgba(${AVATAR_COLORS[colorIndex]}, ${AVATAR_OPACITY})`;
|
||||
return hasCustomAvatarBackgronds ? colorsBase[colorIndex] : `rgba(${colorsBase[colorIndex]}, ${AVATAR_OPACITY})`;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -15,6 +15,15 @@ import {
|
|||
const STORE_NAME = 'features/dynamic-branding';
|
||||
|
||||
const DEFAULT_STATE = {
|
||||
|
||||
/**
|
||||
* The pool of avatar backgrounds.
|
||||
*
|
||||
* @public
|
||||
* @type {Array<string>}
|
||||
*/
|
||||
avatarBackgrounds: [],
|
||||
|
||||
/**
|
||||
* The custom background color for the LargeVideo.
|
||||
*
|
||||
|
@ -112,10 +121,12 @@ ReducerRegistry.register(STORE_NAME, (state = DEFAULT_STATE, action) => {
|
|||
didPageUrl,
|
||||
inviteDomain,
|
||||
logoClickUrl,
|
||||
logoImageUrl
|
||||
logoImageUrl,
|
||||
avatarBackgrounds
|
||||
} = action.value;
|
||||
|
||||
return {
|
||||
avatarBackgrounds,
|
||||
backgroundColor,
|
||||
backgroundImageUrl,
|
||||
defaultBranding,
|
||||
|
|
Loading…
Reference in New Issue