diff --git a/package-lock.json b/package-lock.json index de455fc2f..821a12e61 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9042,8 +9042,8 @@ } }, "lib-jitsi-meet": { - "version": "github:jitsi/lib-jitsi-meet#d9a5afe94bf525fe9b294ae0d5dfe2ad86838b45", - "from": "github:jitsi/lib-jitsi-meet#d9a5afe94bf525fe9b294ae0d5dfe2ad86838b45", + "version": "github:jitsi/lib-jitsi-meet#8a4d1f1b085131aca3cec5513fa7995cf7508fc2", + "from": "github:jitsi/lib-jitsi-meet#8a4d1f1b085131aca3cec5513fa7995cf7508fc2", "requires": { "@jitsi/sdp-interop": "0.1.14", "@jitsi/sdp-simulcast": "0.2.1", diff --git a/package.json b/package.json index 856cf7d8a..9258707ed 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "js-utils": "github:jitsi/js-utils#192b1c996e8c05530eb1f19e82a31069c3021e31", "jsrsasign": "8.0.12", "jwt-decode": "2.2.0", - "lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#d9a5afe94bf525fe9b294ae0d5dfe2ad86838b45", + "lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#8a4d1f1b085131aca3cec5513fa7995cf7508fc2", "libflacjs": "github:mmig/libflac.js#93d37e7f811f01cf7d8b6a603e38bd3c3810907d", "lodash": "4.17.11", "moment": "2.19.4", diff --git a/react/features/base/avatar/components/AbstractStatelessAvatar.js b/react/features/base/avatar/components/AbstractStatelessAvatar.js index 66d9d6786..e4ba7128c 100644 --- a/react/features/base/avatar/components/AbstractStatelessAvatar.js +++ b/react/features/base/avatar/components/AbstractStatelessAvatar.js @@ -34,4 +34,16 @@ export type Props = { * Implements an abstract stateless avatar component that renders an avatar purely from what gets passed through * props. */ -export default class AbstractStatelessAvatar extends PureComponent

{} +export default class AbstractStatelessAvatar extends PureComponent

{ + /** + * Parses an icon out of a specially constructed icon URL and returns the icon name. + * + * @param {string?} url - The url to parse. + * @returns {string?} + */ + _parseIconUrl(url: ?string): ?string { + const match = url && url.match(/icon:\/\/(.+)/i); + + return (match && match[1]) || undefined; + } +} diff --git a/react/features/base/avatar/components/Avatar.js b/react/features/base/avatar/components/Avatar.js index 5243d28c4..7ba5c6879 100644 --- a/react/features/base/avatar/components/Avatar.js +++ b/react/features/base/avatar/components/Avatar.js @@ -138,13 +138,13 @@ class Avatar extends PureComponent { if (effectiveURL) { avatarProps.onAvatarLoadError = this._onAvatarLoadError; avatarProps.url = effectiveURL; - } else { - const initials = getInitials(_initialsBase); + } - if (initials) { - avatarProps.color = getAvatarColor(colorBase || _initialsBase); - avatarProps.initials = initials; - } + const initials = getInitials(_initialsBase); + + if (initials) { + avatarProps.color = getAvatarColor(colorBase || _initialsBase); + avatarProps.initials = initials; } return ( @@ -175,14 +175,15 @@ class Avatar extends PureComponent { * @returns {Props} */ export function _mapStateToProps(state: Object, ownProps: Props) { - const { colorBase, displayName, participantId } = ownProps; + const { colorBase, displayName, participantId, url } = ownProps; const _participant = participantId && getParticipantById(state, participantId); const _initialsBase = (_participant && _participant.name) || displayName; return { _initialsBase, _loadableAvatarUrl: _participant && _participant.loadableAvatarUrl, - colorBase: !colorBase && _participant ? _participant.id : colorBase + colorBase: !colorBase && _participant ? _participant.id : colorBase, + url: !url && _participant && _participant.isJigasi ? 'icon://phone' : url }; } diff --git a/react/features/base/avatar/components/native/StatelessAvatar.js b/react/features/base/avatar/components/native/StatelessAvatar.js index 860e663b9..64975a632 100644 --- a/react/features/base/avatar/components/native/StatelessAvatar.js +++ b/react/features/base/avatar/components/native/StatelessAvatar.js @@ -8,6 +8,7 @@ import { type StyleType } from '../../../styles'; import AbstractStatelessAvatar, { type Props as AbstractProps } from '../AbstractStatelessAvatar'; import styles from './styles'; +import { Icon } from '../../../font-icons'; type Props = AbstractProps & { @@ -34,7 +35,11 @@ export default class StatelessAvatar extends AbstractStatelessAvatar { let avatar; - if (url) { + const icon = this._parseIconUrl(url); + + if (icon) { + avatar = this._renderIconAvatar(icon); + } else if (url) { avatar = this._renderURLAvatar(); } else if (initials) { avatar = this._renderInitialsAvatar(); @@ -53,6 +58,8 @@ export default class StatelessAvatar extends AbstractStatelessAvatar { ); } + _parseIconUrl: ?string => ?string + /** * Renders the default avatar. * @@ -71,6 +78,30 @@ export default class StatelessAvatar extends AbstractStatelessAvatar { ); } + /** + * Renders the initials-based avatar. + * + * @param {string} icon - The icon name to render. + * @returns {React$Element<*>} + */ + _renderIconAvatar(icon) { + const { color, size } = this.props; + + return ( + + + + ); + } + /** * Renders the initials-based avatar. * diff --git a/react/features/base/avatar/components/web/StatelessAvatar.js b/react/features/base/avatar/components/web/StatelessAvatar.js index 3ef7a7797..70d8163dc 100644 --- a/react/features/base/avatar/components/web/StatelessAvatar.js +++ b/react/features/base/avatar/components/web/StatelessAvatar.js @@ -34,6 +34,18 @@ export default class StatelessAvatar extends AbstractStatelessAvatar { */ render() { const { initials, url } = this.props; + const icon = this._parseIconUrl(url); + + if (icon) { + return ( +

+ +
+ ); + } if (url) { return ( @@ -106,4 +118,6 @@ export default class StatelessAvatar extends AbstractStatelessAvatar { _getAvatarClassName(additional) { return `avatar ${additional || ''} ${this.props.className || ''}`; } + + _parseIconUrl: ?string => ?string } diff --git a/react/features/base/participants/middleware.js b/react/features/base/participants/middleware.js index 70e84acc8..8c0ee2b87 100644 --- a/react/features/base/participants/middleware.js +++ b/react/features/base/participants/middleware.js @@ -196,6 +196,13 @@ StateListenerRegistry.register( JitsiConferenceEvents.PARTICIPANT_PROPERTY_CHANGED, (participant, propertyName, oldValue, newValue) => { switch (propertyName) { + case 'features_jigasi': + store.dispatch(participantUpdated({ + conference, + id: participant.getId(), + isJigasi: newValue + })); + break; case 'features_screen-sharing': store.dispatch(participantUpdated({ conference, diff --git a/react/features/base/participants/reducer.js b/react/features/base/participants/reducer.js index 80697708f..cf6438a19 100644 --- a/react/features/base/participants/reducer.js +++ b/react/features/base/participants/reducer.js @@ -188,6 +188,7 @@ function _participantJoined({ participant }) { dominantSpeaker, email, isFakeParticipant, + isJigasi, loadableAvatarUrl, local, name, @@ -219,6 +220,7 @@ function _participantJoined({ participant }) { email, id, isFakeParticipant, + isJigasi, loadableAvatarUrl, local: local || false, name, diff --git a/react/features/invite/components/add-people-dialog/native/AddPeopleDialog.js b/react/features/invite/components/add-people-dialog/native/AddPeopleDialog.js index c735f37fe..bd8ccf1b4 100644 --- a/react/features/invite/components/add-people-dialog/native/AddPeopleDialog.js +++ b/react/features/invite/components/add-people-dialog/native/AddPeopleDialog.js @@ -417,7 +417,7 @@ class AddPeopleDialog extends AbstractAddPeopleDialog { selected = inviteItems.find(_.matchesProperty('number', item.number)); renderableItem = { - avatar: 'phone', + avatar: 'icon://phone', key: item.number, title: item.number };