speed up fetching closed group's members avatar
parent
af75b6f0e2
commit
5ba7f20162
@ -1,59 +1,57 @@
|
||||
import React from 'react';
|
||||
import { useMembersAvatars } from '../../hooks/useMembersAvatars';
|
||||
import { Avatar, AvatarSize } from '../Avatar';
|
||||
import { ConversationAvatar } from '../session/usingClosedConversationDetails';
|
||||
|
||||
interface Props {
|
||||
type Props = {
|
||||
size: number;
|
||||
memberAvatars: Array<ConversationAvatar>; // this is added by usingClosedConversationDetails
|
||||
closedGroupId: string;
|
||||
onAvatarClick?: () => void;
|
||||
}
|
||||
};
|
||||
|
||||
export class ClosedGroupAvatar extends React.PureComponent<Props> {
|
||||
public getClosedGroupAvatarsSize(size: AvatarSize): AvatarSize {
|
||||
// Always use the size directly under the one requested
|
||||
switch (size) {
|
||||
case AvatarSize.S:
|
||||
return AvatarSize.XS;
|
||||
case AvatarSize.M:
|
||||
return AvatarSize.S;
|
||||
case AvatarSize.L:
|
||||
return AvatarSize.M;
|
||||
case AvatarSize.XL:
|
||||
return AvatarSize.L;
|
||||
case AvatarSize.HUGE:
|
||||
return AvatarSize.XL;
|
||||
default:
|
||||
throw new Error(`Invalid size request for closed group avatar: ${size}`);
|
||||
}
|
||||
function getClosedGroupAvatarsSize(size: AvatarSize): AvatarSize {
|
||||
// Always use the size directly under the one requested
|
||||
switch (size) {
|
||||
case AvatarSize.XS:
|
||||
return AvatarSize.XS;
|
||||
case AvatarSize.S:
|
||||
return AvatarSize.XS;
|
||||
case AvatarSize.M:
|
||||
return AvatarSize.S;
|
||||
case AvatarSize.L:
|
||||
return AvatarSize.M;
|
||||
case AvatarSize.XL:
|
||||
return AvatarSize.L;
|
||||
case AvatarSize.HUGE:
|
||||
return AvatarSize.XL;
|
||||
default:
|
||||
throw new Error(`Invalid size request for closed group avatar: ${size}`);
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
const { memberAvatars, size, onAvatarClick } = this.props;
|
||||
const avatarsDiameter = this.getClosedGroupAvatarsSize(size);
|
||||
export const ClosedGroupAvatar = (props: Props) => {
|
||||
const { closedGroupId, size, onAvatarClick } = props;
|
||||
|
||||
const conv1 = memberAvatars.length > 0 ? memberAvatars[0] : undefined;
|
||||
const conv2 = memberAvatars.length > 1 ? memberAvatars[1] : undefined;
|
||||
const name1 = conv1?.name || conv1?.id || undefined;
|
||||
const name2 = conv2?.name || conv2?.id || undefined;
|
||||
const memberAvatars = useMembersAvatars(closedGroupId);
|
||||
const avatarsDiameter = getClosedGroupAvatarsSize(size);
|
||||
const firstMember = memberAvatars?.[0];
|
||||
const secondMember = memberAvatars?.[1];
|
||||
|
||||
// use the 2 first members as group avatars
|
||||
return (
|
||||
<div className="module-avatar__icon-closed">
|
||||
<Avatar
|
||||
avatarPath={conv1?.avatarPath}
|
||||
name={name1}
|
||||
size={avatarsDiameter}
|
||||
pubkey={conv1?.id}
|
||||
onAvatarClick={onAvatarClick}
|
||||
/>
|
||||
<Avatar
|
||||
avatarPath={conv2?.avatarPath}
|
||||
name={name2}
|
||||
size={avatarsDiameter}
|
||||
pubkey={conv2?.id}
|
||||
onAvatarClick={onAvatarClick}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<div className="module-avatar__icon-closed">
|
||||
<Avatar
|
||||
avatarPath={firstMember?.avatarPath}
|
||||
name={firstMember?.name}
|
||||
size={avatarsDiameter}
|
||||
pubkey={firstMember?.id}
|
||||
onAvatarClick={onAvatarClick}
|
||||
/>
|
||||
<Avatar
|
||||
avatarPath={secondMember?.avatarPath}
|
||||
name={secondMember?.name}
|
||||
size={avatarsDiameter}
|
||||
pubkey={secondMember?.id}
|
||||
onAvatarClick={onAvatarClick}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -1,69 +0,0 @@
|
||||
import { GroupUtils, UserUtils } from '../../session/utils';
|
||||
import { PubKey } from '../../session/types';
|
||||
import React from 'react';
|
||||
import * as _ from 'lodash';
|
||||
import { getConversationController } from '../../session/conversations';
|
||||
|
||||
export type ConversationAvatar = {
|
||||
avatarPath?: string;
|
||||
id?: string; // member's pubkey
|
||||
name?: string;
|
||||
};
|
||||
|
||||
type State = {
|
||||
memberAvatars?: Array<ConversationAvatar>; // this is added by usingClosedConversationDetails
|
||||
};
|
||||
|
||||
export function usingClosedConversationDetails(WrappedComponent: any) {
|
||||
return class extends React.Component<any, State> {
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
this.state = {
|
||||
memberAvatars: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
this.fetchClosedConversationDetails();
|
||||
}
|
||||
|
||||
public componentWillReceiveProps() {
|
||||
this.fetchClosedConversationDetails();
|
||||
}
|
||||
|
||||
public render() {
|
||||
return <WrappedComponent memberAvatars={this.state.memberAvatars} {...this.props} />;
|
||||
}
|
||||
|
||||
private fetchClosedConversationDetails() {
|
||||
const { isPublic, type, conversationType, isGroup, id } = this.props;
|
||||
|
||||
if (!isPublic && (conversationType === 'group' || type === 'group' || isGroup)) {
|
||||
const groupId = id;
|
||||
const ourPrimary = UserUtils.getOurPubKeyFromCache();
|
||||
let members = GroupUtils.getGroupMembers(PubKey.cast(groupId));
|
||||
|
||||
const ourself = members.find(m => m.key !== ourPrimary.key);
|
||||
// add ourself back at the back, so it's shown only if only 1 member and we are still a member
|
||||
members = members.filter(m => m.key !== ourPrimary.key);
|
||||
members.sort((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0));
|
||||
if (ourself) {
|
||||
members.push(ourPrimary);
|
||||
}
|
||||
// no need to forward more than 2 conversations for rendering the group avatar
|
||||
members = members.slice(0, 2);
|
||||
const memberConvos = _.compact(members.map(m => getConversationController().get(m.key)));
|
||||
const memberAvatars = memberConvos.map(m => {
|
||||
return {
|
||||
avatarPath: m.getAvatarPath() || undefined,
|
||||
id: m.id,
|
||||
name: m.get('name') || m.get('profileName') || m.id,
|
||||
};
|
||||
});
|
||||
this.setState({ memberAvatars });
|
||||
} else {
|
||||
this.setState({ memberAvatars: undefined });
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
import _ from 'lodash';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { getConversationController } from '../session/conversations';
|
||||
import { UserUtils } from '../session/utils';
|
||||
import { ReduxConversationType } from '../state/ducks/conversations';
|
||||
|
||||
export function useMembersAvatars(conversation: ReduxConversationType | undefined) {
|
||||
const [membersAvatars, setMembersAvatars] = useState<
|
||||
| Array<{
|
||||
avatarPath: string | undefined;
|
||||
id: string;
|
||||
name: string;
|
||||
}>
|
||||
| undefined
|
||||
>(undefined);
|
||||
|
||||
useEffect(
|
||||
() => {
|
||||
if (!conversation) {
|
||||
setMembersAvatars(undefined);
|
||||
return;
|
||||
}
|
||||
const { isPublic, isGroup, members: convoMembers } = conversation;
|
||||
if (!isPublic && isGroup) {
|
||||
const ourPrimary = UserUtils.getOurPubKeyStrFromCache();
|
||||
|
||||
const ourself = convoMembers?.find(m => m !== ourPrimary) || undefined;
|
||||
// add ourself back at the back, so it's shown only if only 1 member and we are still a member
|
||||
let membersFiltered = convoMembers?.filter(m => m !== ourPrimary) || [];
|
||||
membersFiltered.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
||||
if (ourself) {
|
||||
membersFiltered.push(ourPrimary);
|
||||
}
|
||||
// no need to forward more than 2 conversations for rendering the group avatar
|
||||
membersFiltered = membersFiltered.slice(0, 2);
|
||||
const memberConvos = _.compact(
|
||||
membersFiltered.map(m => getConversationController().get(m))
|
||||
);
|
||||
const memberAvatars = memberConvos.map(m => {
|
||||
return {
|
||||
avatarPath: m.getAvatarPath() || undefined,
|
||||
id: m.id as string,
|
||||
name: (m.get('name') || m.get('profileName') || m.id) as string,
|
||||
};
|
||||
});
|
||||
setMembersAvatars(memberAvatars);
|
||||
} else {
|
||||
setMembersAvatars(undefined);
|
||||
}
|
||||
},
|
||||
conversation ? [conversation.members, conversation.id] : []
|
||||
);
|
||||
|
||||
return membersAvatars;
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
import { UserUtils } from '../session/utils';
|
||||
import * as _ from 'lodash';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { StateType } from '../state/reducer';
|
||||
|
||||
export type ConversationAvatar = {
|
||||
avatarPath?: string;
|
||||
id: string; // member's pubkey
|
||||
name: string;
|
||||
};
|
||||
|
||||
export function useMembersAvatars(closedGroupPubkey: string | undefined) {
|
||||
const ourPrimary = UserUtils.getOurPubKeyStrFromCache();
|
||||
|
||||
return useSelector((state: StateType): Array<ConversationAvatar> | undefined => {
|
||||
if (!closedGroupPubkey) {
|
||||
return undefined;
|
||||
}
|
||||
const groupConvo = state.conversations.conversationLookup[closedGroupPubkey];
|
||||
|
||||
if (groupConvo.isPrivate || groupConvo.isPublic || !groupConvo.isGroup) {
|
||||
return undefined;
|
||||
}
|
||||
// this must be a closed group
|
||||
const originalMembers = groupConvo.members;
|
||||
if (!originalMembers || originalMembers.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
const allMembersSorted = originalMembers.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
||||
|
||||
// no need to forward more than 2 conversations for rendering the group avatar
|
||||
const usAtTheEndMaxTwo = _.sortBy(allMembersSorted, a => (a === ourPrimary ? 1 : 0)).slice(
|
||||
0,
|
||||
2
|
||||
);
|
||||
const memberConvos = _.compact(
|
||||
usAtTheEndMaxTwo
|
||||
.map(m => state.conversations.conversationLookup[m])
|
||||
.map(m => {
|
||||
if (!m) {
|
||||
return undefined;
|
||||
}
|
||||
const userName = m.name || m.profileName || m.id;
|
||||
|
||||
return {
|
||||
avatarPath: m.avatarPath || undefined,
|
||||
id: m.id,
|
||||
name: userName,
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
return memberConvos && memberConvos.length ? memberConvos : undefined;
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue