Update user avatars
This commit is contained in:
parent
61552af5fb
commit
493445a6b0
8 changed files with 66 additions and 17 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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"
|
||||||
|
|
12
src/Home.jsx
12
src/Home.jsx
|
@ -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>
|
||||||
|
|
26
src/Room.jsx
26
src/Room.jsx
|
@ -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}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 />
|
||||||
|
|
Loading…
Reference in a new issue