Update user avatars

This commit is contained in:
Robert Long 2021-12-20 09:12:28 -08:00
parent 61552af5fb
commit 493445a6b0
8 changed files with 66 additions and 17 deletions

View file

@ -7,6 +7,7 @@
pointer-events: none; pointer-events: none;
font-weight: 600; font-weight: 600;
overflow: hidden; overflow: hidden;
flex-shrink: 0;
} }
.avatar img { .avatar img {

View file

@ -7,7 +7,7 @@ import { ReactComponent as VideoIcon } from "./icons/Video.svg";
import styles from "./CallList.module.css"; import styles from "./CallList.module.css";
import { getRoomUrl } from "./ConferenceCallManagerHooks"; import { getRoomUrl } from "./ConferenceCallManagerHooks";
export function CallList({ title, rooms }) { export function CallList({ title, rooms, client }) {
return ( return (
<> <>
<h3>{title}</h3> <h3>{title}</h3>
@ -15,6 +15,7 @@ export function CallList({ title, rooms }) {
{rooms.map(({ roomId, roomName, avatarUrl, participants }) => ( {rooms.map(({ roomId, roomName, avatarUrl, participants }) => (
<CallTile <CallTile
key={roomId} key={roomId}
client={client}
name={roomName} name={roomName}
avatarUrl={avatarUrl} avatarUrl={avatarUrl}
roomId={roomId} roomId={roomId}
@ -26,7 +27,7 @@ export function CallList({ title, rooms }) {
); );
} }
function CallTile({ name, avatarUrl, roomId, participants }) { function CallTile({ name, avatarUrl, roomId, participants, client }) {
return ( return (
<div className={styles.callTile}> <div className={styles.callTile}>
<Link to={`/room/${roomId}`} className={styles.callTileLink}> <Link to={`/room/${roomId}`} className={styles.callTileLink}>
@ -40,7 +41,9 @@ function CallTile({ name, avatarUrl, roomId, participants }) {
<div className={styles.callInfo}> <div className={styles.callInfo}>
<h5>{name}</h5> <h5>{name}</h5>
<p>{getRoomUrl(roomId)}</p> <p>{getRoomUrl(roomId)}</p>
{participants && <Facepile participants={participants} />} {participants && (
<Facepile client={client} participants={participants} />
)}
</div> </div>
<div className={styles.copyButtonSpacer} /> <div className={styles.copyButtonSpacer} />
</Link> </Link>

View file

@ -624,7 +624,7 @@ export function getRoomUrl(roomId) {
} }
} }
function getAvatarUrl(client, mxcUrl, avatarSize = 96) { export function getAvatarUrl(client, mxcUrl, avatarSize = 96) {
const width = Math.floor(avatarSize * window.devicePixelRatio); const width = Math.floor(avatarSize * window.devicePixelRatio);
const height = Math.floor(avatarSize * window.devicePixelRatio); const height = Math.floor(avatarSize * window.devicePixelRatio);
return mxcUrl && client.mxcUrlToHttp(mxcUrl, width, height, "crop"); return mxcUrl && client.mxcUrlToHttp(mxcUrl, width, height, "crop");

View file

@ -2,23 +2,28 @@ import React from "react";
import styles from "./Facepile.module.css"; import styles from "./Facepile.module.css";
import classNames from "classnames"; import classNames from "classnames";
import { Avatar } from "./Avatar"; import { Avatar } from "./Avatar";
import { getAvatarUrl } from "./ConferenceCallManagerHooks";
export function Facepile({ className, participants, ...rest }) { export function Facepile({ className, client, participants, ...rest }) {
return ( return (
<div <div
className={classNames(styles.facepile, className)} className={classNames(styles.facepile, className)}
title={participants.map((member) => member.name).join(", ")} title={participants.map((member) => member.name).join(", ")}
{...rest} {...rest}
> >
{participants.slice(0, 3).map((member, i) => ( {participants.slice(0, 3).map((member, i) => {
<Avatar const avatarUrl = member.user?.avatarUrl;
key={member.userId} return (
size="xs" <Avatar
fallback={member.name.slice(0, 1).toUpperCase()} key={member.userId}
className={styles.avatar} size="xs"
style={{ left: i * 22 }} src={avatarUrl && getAvatarUrl(client, avatarUrl, 22)}
/> fallback={member.name.slice(0, 1).toUpperCase()}
))} className={styles.avatar}
style={{ left: i * 22 }}
/>
);
})}
{participants.length > 3 && ( {participants.length > 3 && (
<Avatar <Avatar
key="additional" key="additional"

View file

@ -330,10 +330,18 @@ function RegisteredView({
<div className={styles.right}> <div className={styles.right}>
<div className={styles.content}> <div className={styles.content}>
{publicRooms.length > 0 && ( {publicRooms.length > 0 && (
<CallList title="Public Calls" rooms={publicRooms} /> <CallList
title="Public Calls"
rooms={publicRooms}
client={client}
/>
)} )}
{recentRooms.length > 0 && ( {recentRooms.length > 0 && (
<CallList title="Recent Calls" rooms={recentRooms} /> <CallList
title="Recent Calls"
rooms={recentRooms}
client={client}
/>
)} )}
</div> </div>
</div> </div>

View file

@ -37,6 +37,7 @@ import { useGroupCall } from "matrix-react-sdk/src/hooks/useGroupCall";
import { useCallFeed } from "matrix-react-sdk/src/hooks/useCallFeed"; import { useCallFeed } from "matrix-react-sdk/src/hooks/useCallFeed";
import { useMediaStream } from "matrix-react-sdk/src/hooks/useMediaStream"; import { useMediaStream } from "matrix-react-sdk/src/hooks/useMediaStream";
import { import {
getAvatarUrl,
getRoomUrl, getRoomUrl,
useClient, useClient,
useLoadGroupCall, useLoadGroupCall,
@ -49,6 +50,7 @@ import { OverflowMenu } from "./OverflowMenu";
import { GridLayoutMenu } from "./GridLayoutMenu"; import { GridLayoutMenu } from "./GridLayoutMenu";
import { UserMenu } from "./UserMenu"; import { UserMenu } from "./UserMenu";
import classNames from "classnames"; import classNames from "classnames";
import { Avatar } from "./Avatar";
const canScreenshare = "getDisplayMedia" in navigator.mediaDevices; const canScreenshare = "getDisplayMedia" in navigator.mediaDevices;
// There is currently a bug in Safari our our code with cloning and sending MediaStreams // There is currently a bug in Safari our our code with cloning and sending MediaStreams
@ -445,6 +447,29 @@ function InRoomView({
[layout, setLayout] [layout, setLayout]
); );
const renderAvatar = useCallback(
(roomMember, width, height) => {
const avatarUrl = roomMember.user?.avatarUrl;
const size = Math.round(Math.min(width, height) / 2);
return (
<Avatar
key={roomMember.userId}
style={{
width: size,
height: size,
borderRadius: size,
fontSize: Math.round(size / 2),
}}
src={avatarUrl && getAvatarUrl(client, avatarUrl, 96)}
fallback={roomMember.name.slice(0, 1).toUpperCase()}
className={styles.avatar}
/>
);
},
[client]
);
return ( return (
<div className={classNames(styles.room, styles.inRoom)}> <div className={classNames(styles.room, styles.inRoom)}>
<Header> <Header>
@ -466,6 +491,7 @@ function InRoomView({
<VideoGrid <VideoGrid
items={items} items={items}
layout={layout} layout={layout}
getAvatar={renderAvatar}
onFocusTile={onFocusTile} onFocusTile={onFocusTile}
disableAnimations={isSafari} disableAnimations={isSafari}
/> />

View file

@ -195,6 +195,13 @@ limitations under the License.
max-width: 360px; max-width: 360px;
} }
.avatar {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
@media (min-width: 800px) { @media (min-width: 800px) {
.roomContainer { .roomContainer {
flex-direction: row; flex-direction: row;

View file

@ -93,7 +93,6 @@ export function UserMenu({ disableLogout }) {
size="sm" size="sm"
src={avatarUrl} src={avatarUrl}
fallback={(displayName || userName).slice(0, 1).toUpperCase()} fallback={(displayName || userName).slice(0, 1).toUpperCase()}
className={styles.avatar}
/> />
) : ( ) : (
<UserIcon /> <UserIcon />