Avatar: Finally remove animated avatars (#3061)

This commit is contained in:
Alexander Zinchuk 2023-04-25 17:24:08 +04:00
parent 920b046d2e
commit 27203e9976
34 changed files with 76 additions and 274 deletions

View File

@ -4,10 +4,10 @@ import type { FC } from '../../../lib/teact/teact';
import React, { memo, useMemo, useRef } from '../../../lib/teact/teact'; import React, { memo, useMemo, useRef } from '../../../lib/teact/teact';
import { withGlobal } from '../../../global'; import { withGlobal } from '../../../global';
import type { ApiChat, ApiPhoto, ApiUser } from '../../../api/types'; import type { ApiChat, ApiUser } from '../../../api/types';
import buildClassName from '../../../util/buildClassName'; import buildClassName from '../../../util/buildClassName';
import { selectChat, selectUser, selectUserPhotoFromFullInfo } from '../../../global/selectors'; import { selectChat, selectUser } from '../../../global/selectors';
import useLang from '../../../hooks/useLang'; import useLang from '../../../hooks/useLang';
import { GROUP_CALL_DEFAULT_VOLUME, GROUP_CALL_VOLUME_MULTIPLIER } from '../../../config'; import { GROUP_CALL_DEFAULT_VOLUME, GROUP_CALL_VOLUME_MULTIPLIER } from '../../../config';
@ -23,7 +23,6 @@ type OwnProps = {
type StateProps = { type StateProps = {
user?: ApiUser; user?: ApiUser;
userProfilePhoto?: ApiPhoto;
chat?: ApiChat; chat?: ApiChat;
}; };
@ -31,7 +30,6 @@ const GroupCallParticipant: FC<OwnProps & StateProps> = ({
openParticipantMenu, openParticipantMenu,
participant, participant,
user, user,
userProfilePhoto,
chat, chat,
}) => { }) => {
// eslint-disable-next-line no-null/no-null // eslint-disable-next-line no-null/no-null
@ -81,7 +79,7 @@ const GroupCallParticipant: FC<OwnProps & StateProps> = ({
onClick={handleOnClick} onClick={handleOnClick}
ref={anchorRef} ref={anchorRef}
> >
<Avatar user={user} chat={chat} userProfilePhoto={userProfilePhoto} size="medium" /> <Avatar user={user} chat={chat} size="medium" />
<div className="info"> <div className="info">
<span className="name">{name}</span> <span className="name">{name}</span>
<span className={buildClassName('about', aboutColor)}>{aboutText}</span> <span className={buildClassName('about', aboutColor)}>{aboutText}</span>
@ -98,7 +96,6 @@ export default memo(withGlobal<OwnProps>(
return { return {
user: participant.isUser ? selectUser(global, participant.id) : undefined, user: participant.isUser ? selectUser(global, participant.id) : undefined,
chat: !participant.isUser ? selectChat(global, participant.id) : undefined, chat: !participant.isUser ? selectChat(global, participant.id) : undefined,
userProfilePhoto: participant.isUser ? selectUserPhotoFromFullInfo(global, participant.id) : undefined,
}; };
}, },
)(GroupCallParticipant)); )(GroupCallParticipant));

View File

@ -4,11 +4,11 @@ import type { FC } from '../../../lib/teact/teact';
import React, { memo, useCallback } from '../../../lib/teact/teact'; import React, { memo, useCallback } from '../../../lib/teact/teact';
import { withGlobal } from '../../../global'; import { withGlobal } from '../../../global';
import type { ApiChat, ApiPhoto, ApiUser } from '../../../api/types'; import type { ApiChat, ApiUser } from '../../../api/types';
import { GROUP_CALL_THUMB_VIDEO_DISABLED } from '../../../config'; import { GROUP_CALL_THUMB_VIDEO_DISABLED } from '../../../config';
import buildClassName from '../../../util/buildClassName'; import buildClassName from '../../../util/buildClassName';
import { selectChat, selectUser, selectUserPhotoFromFullInfo } from '../../../global/selectors'; import { selectChat, selectUser } from '../../../global/selectors';
import useLang from '../../../hooks/useLang'; import useLang from '../../../hooks/useLang';
import Avatar from '../../common/Avatar'; import Avatar from '../../common/Avatar';
@ -25,7 +25,6 @@ type OwnProps = {
type StateProps = { type StateProps = {
user?: ApiUser; user?: ApiUser;
chat?: ApiChat; chat?: ApiChat;
userProfilePhoto?: ApiPhoto;
currentUserId?: string; currentUserId?: string;
isActive?: boolean; isActive?: boolean;
}; };
@ -35,7 +34,6 @@ const GroupCallParticipantVideo: FC<OwnProps & StateProps> = ({
onClick, onClick,
user, user,
chat, chat,
userProfilePhoto,
isActive, isActive,
isFullscreen, isFullscreen,
}) => { }) => {
@ -62,7 +60,7 @@ const GroupCallParticipantVideo: FC<OwnProps & StateProps> = ({
{lang('Back')} {lang('Back')}
</button> </button>
)} )}
<Avatar user={user} chat={chat} userProfilePhoto={userProfilePhoto} className="thumbnail-avatar" /> <Avatar user={user} chat={chat} className="thumbnail-avatar" />
{!GROUP_CALL_THUMB_VIDEO_DISABLED && ( {!GROUP_CALL_THUMB_VIDEO_DISABLED && (
<div className="thumbnail-wrapper"> <div className="thumbnail-wrapper">
<video className="thumbnail" muted autoPlay playsInline srcObject={streams?.[type]} /> <video className="thumbnail" muted autoPlay playsInline srcObject={streams?.[type]} />
@ -84,7 +82,6 @@ export default memo(withGlobal<OwnProps>(
currentUserId: global.currentUserId, currentUserId: global.currentUserId,
user: participant.isUser ? selectUser(global, participant.id) : undefined, user: participant.isUser ? selectUser(global, participant.id) : undefined,
chat: !participant.isUser ? selectChat(global, participant.id) : undefined, chat: !participant.isUser ? selectChat(global, participant.id) : undefined,
userProfilePhoto: participant.isUser ? selectUserPhotoFromFullInfo(global, participant.id) : undefined,
isActive: (participant.amplitude || 0) > THRESHOLD, isActive: (participant.amplitude || 0) > THRESHOLD,
}; };
}, },

View File

@ -14,7 +14,6 @@ import useLang from '../../../hooks/useLang';
import Button from '../../ui/Button'; import Button from '../../ui/Button';
import Avatar from '../../common/Avatar'; import Avatar from '../../common/Avatar';
import UserAvatar from '../../common/UserAvatar';
import './GroupCallTopPane.scss'; import './GroupCallTopPane.scss';
@ -113,11 +112,14 @@ const GroupCallTopPane: FC<OwnProps & StateProps> = ({
<div className="avatars"> <div className="avatars">
{fetchedParticipants.map((p) => { {fetchedParticipants.map((p) => {
if (!p) return undefined; if (!p) return undefined;
if (p.user) { return (
return <UserAvatar key={p.user.id} user={p.user} />; <Avatar
} else { key={p.user ? p.user.id : p.chat.id}
return <Avatar key={p.chat.id} chat={p.chat} animationLevel={animationLevel} />; chat={p.chat}
} user={p.user}
animationLevel={animationLevel}
/>
);
})} })}
</div> </div>
<Button round className="join"> <Button round className="join">

View File

@ -5,7 +5,7 @@ import React, {
import { getActions, withGlobal } from '../../../global'; import { getActions, withGlobal } from '../../../global';
import '../../../global/actions/calls'; import '../../../global/actions/calls';
import type { ApiPhoneCall, ApiPhoto, ApiUser } from '../../../api/types'; import type { ApiPhoneCall, ApiUser } from '../../../api/types';
import type { AnimationLevel } from '../../../types'; import type { AnimationLevel } from '../../../types';
import { import {
@ -14,7 +14,7 @@ import {
IS_REQUEST_FULLSCREEN_SUPPORTED, IS_REQUEST_FULLSCREEN_SUPPORTED,
} from '../../../util/windowEnvironment'; } from '../../../util/windowEnvironment';
import { LOCAL_TGS_URLS } from '../../common/helpers/animatedAssets'; import { LOCAL_TGS_URLS } from '../../common/helpers/animatedAssets';
import { selectTabState, selectUserPhotoFromFullInfo } from '../../../global/selectors'; import { selectTabState } from '../../../global/selectors';
import buildClassName from '../../../util/buildClassName'; import buildClassName from '../../../util/buildClassName';
import { selectPhoneCallUser } from '../../../global/selectors/calls'; import { selectPhoneCallUser } from '../../../global/selectors/calls';
import useLang from '../../../hooks/useLang'; import useLang from '../../../hooks/useLang';
@ -39,7 +39,6 @@ import styles from './PhoneCall.module.scss';
type StateProps = { type StateProps = {
user?: ApiUser; user?: ApiUser;
phoneCall?: ApiPhoneCall; phoneCall?: ApiPhoneCall;
userProfilePhoto?: ApiPhoto;
isOutgoing: boolean; isOutgoing: boolean;
isCallPanelVisible?: boolean; isCallPanelVisible?: boolean;
animationLevel: AnimationLevel; animationLevel: AnimationLevel;
@ -47,7 +46,6 @@ type StateProps = {
const PhoneCall: FC<StateProps> = ({ const PhoneCall: FC<StateProps> = ({
user, user,
userProfilePhoto,
isOutgoing, isOutgoing,
phoneCall, phoneCall,
isCallPanelVisible, isCallPanelVisible,
@ -240,7 +238,6 @@ const PhoneCall: FC<StateProps> = ({
> >
<Avatar <Avatar
user={user} user={user}
userProfilePhoto={userProfilePhoto}
size="jumbo" size="jumbo"
className={hasVideo || hasPresentation ? styles.blurred : ''} className={hasVideo || hasPresentation ? styles.blurred : ''}
withVideo withVideo
@ -376,12 +373,10 @@ export default memo(withGlobal(
const { phoneCall, currentUserId } = global; const { phoneCall, currentUserId } = global;
const { isCallPanelVisible, isMasterTab } = selectTabState(global); const { isCallPanelVisible, isMasterTab } = selectTabState(global);
const user = selectPhoneCallUser(global); const user = selectPhoneCallUser(global);
const userProfilePhoto = user ? selectUserPhotoFromFullInfo(global, user.id) : undefined;
return { return {
isCallPanelVisible: Boolean(isCallPanelVisible), isCallPanelVisible: Boolean(isCallPanelVisible),
user, user,
userProfilePhoto,
isOutgoing: phoneCall?.adminId === currentUserId, isOutgoing: phoneCall?.adminId === currentUserId,
phoneCall: isMasterTab ? phoneCall : undefined, phoneCall: isMasterTab ? phoneCall : undefined,
animationLevel: global.settings.byKey.animationLevel, animationLevel: global.settings.byKey.animationLevel,

View File

@ -1,8 +1,7 @@
import type { MouseEvent as ReactMouseEvent } from 'react'; import type { MouseEvent as ReactMouseEvent } from 'react';
import React, { import React, {
memo, useCallback, useEffect, useMemo, useRef, memo, useCallback, useMemo, useRef,
} from '../../lib/teact/teact'; } from '../../lib/teact/teact';
import { getActions } from '../../global';
import type { FC, TeactNode } from '../../lib/teact/teact'; import type { FC, TeactNode } from '../../lib/teact/teact';
import type { import type {
@ -49,7 +48,6 @@ type OwnProps = {
chat?: ApiChat; chat?: ApiChat;
user?: ApiUser; user?: ApiUser;
photo?: ApiPhoto; photo?: ApiPhoto;
userProfilePhoto?: ApiPhoto;
userStatus?: ApiUserStatus; userStatus?: ApiUserStatus;
text?: string; text?: string;
isSavedMessages?: boolean; isSavedMessages?: boolean;
@ -70,7 +68,6 @@ const Avatar: FC<OwnProps> = ({
chat, chat,
user, user,
photo, photo,
userProfilePhoto,
userStatus, userStatus,
text, text,
isSavedMessages, isSavedMessages,
@ -84,7 +81,6 @@ const Avatar: FC<OwnProps> = ({
observeIntersection, observeIntersection,
onClick, onClick,
}) => { }) => {
const { loadFullUser } = getActions();
// eslint-disable-next-line no-null/no-null // eslint-disable-next-line no-null/no-null
const ref = useRef<HTMLDivElement>(null); const ref = useRef<HTMLDivElement>(null);
const videoLoopCountRef = useRef(0); const videoLoopCountRef = useRef(0);
@ -98,9 +94,8 @@ const Avatar: FC<OwnProps> = ({
withVideo && !VIDEO_AVATARS_DISABLED && animationLevel === ANIMATION_LEVEL_MAX withVideo && !VIDEO_AVATARS_DISABLED && animationLevel === ANIMATION_LEVEL_MAX
&& user?.isPremium && user?.hasVideoAvatar && user?.isPremium && user?.hasVideoAvatar
); );
const hasProfileVideo = userProfilePhoto?.isVideo;
const isIntersectingForVideo = useIsIntersecting( const isIntersectingForVideo = useIsIntersecting(
ref, canShowVideo && hasProfileVideo ? observeIntersection : undefined, ref, canShowVideo ? observeIntersection : undefined,
); );
const shouldLoadVideo = isIntersectingForVideo && (canShowVideo || (forceVideo && photo?.isVideo)); const shouldLoadVideo = isIntersectingForVideo && (canShowVideo || (forceVideo && photo?.isVideo));
@ -116,10 +111,6 @@ const Avatar: FC<OwnProps> = ({
videoHash = `videoAvatar${photo.id}?size=u`; videoHash = `videoAvatar${photo.id}?size=u`;
} }
} }
if (hasProfileVideo) {
videoHash = getChatAvatarHash(user!, undefined, 'video', undefined, userProfilePhoto);
}
} }
const imgBlobUrl = useMedia(imageHash, false, ApiMediaFormat.BlobUrl, lastSyncTime); const imgBlobUrl = useMedia(imageHash, false, ApiMediaFormat.BlobUrl, lastSyncTime);
@ -148,13 +139,6 @@ const Avatar: FC<OwnProps> = ({
} }
}, [loopIndefinitely, noLoop, videoBlobUrl]); }, [loopIndefinitely, noLoop, videoBlobUrl]);
const userId = user?.id;
useEffect(() => {
if (userId && canShowVideo && !userProfilePhoto) {
loadFullUser({ userId });
}
}, [loadFullUser, userProfilePhoto, userId, canShowVideo]);
const lang = useLang(); const lang = useLang();
let content: TeactNode | undefined; let content: TeactNode | undefined;

View File

@ -2,9 +2,9 @@ import React, { memo } from '../../lib/teact/teact';
import { withGlobal } from '../../global'; import { withGlobal } from '../../global';
import type { FC, TeactNode } from '../../lib/teact/teact'; import type { FC, TeactNode } from '../../lib/teact/teact';
import type { ApiChat, ApiPhoto, ApiUser } from '../../api/types'; import type { ApiChat, ApiUser } from '../../api/types';
import { selectChat, selectUser, selectUserPhotoFromFullInfo } from '../../global/selectors'; import { selectChat, selectUser } from '../../global/selectors';
import { getChatTitle, getUserFirstOrLastName, isUserId } from '../../global/helpers'; import { getChatTitle, getUserFirstOrLastName, isUserId } from '../../global/helpers';
import renderText from './helpers/renderText'; import renderText from './helpers/renderText';
import buildClassName from '../../util/buildClassName'; import buildClassName from '../../util/buildClassName';
@ -28,7 +28,6 @@ type OwnProps = {
type StateProps = { type StateProps = {
chat?: ApiChat; chat?: ApiChat;
user?: ApiUser; user?: ApiUser;
userProfilePhoto?: ApiPhoto;
currentUserId?: string; currentUserId?: string;
}; };
@ -40,7 +39,6 @@ const PickerSelectedItem: FC<OwnProps & StateProps> = ({
clickArg, clickArg,
chat, chat,
user, user,
userProfilePhoto,
className, className,
currentUserId, currentUserId,
onClick, onClick,
@ -63,7 +61,6 @@ const PickerSelectedItem: FC<OwnProps & StateProps> = ({
<Avatar <Avatar
chat={chat} chat={chat}
user={user} user={user}
userProfilePhoto={userProfilePhoto}
size="small" size="small"
isSavedMessages={user?.isSelf} isSavedMessages={user?.isSelf}
/> />
@ -114,12 +111,10 @@ export default memo(withGlobal<OwnProps>(
const chat = chatOrUserId ? selectChat(global, chatOrUserId) : undefined; const chat = chatOrUserId ? selectChat(global, chatOrUserId) : undefined;
const user = isUserId(chatOrUserId) ? selectUser(global, chatOrUserId) : undefined; const user = isUserId(chatOrUserId) ? selectUser(global, chatOrUserId) : undefined;
const userProfilePhoto = user ? selectUserPhotoFromFullInfo(global, user.id) : undefined;
return { return {
chat, chat,
user, user,
userProfilePhoto,
currentUserId: global.currentUserId, currentUserId: global.currentUserId,
}; };
}, },

View File

@ -5,15 +5,13 @@ import { getActions, withGlobal } from '../../global';
import type { FC } from '../../lib/teact/teact'; import type { FC } from '../../lib/teact/teact';
import type { import type {
ApiUser, ApiTypingStatus, ApiUserStatus, ApiChatMember, ApiPhoto, ApiUser, ApiTypingStatus, ApiUserStatus, ApiChatMember,
} from '../../api/types'; } from '../../api/types';
import type { GlobalState } from '../../global/types'; import type { GlobalState } from '../../global/types';
import type { AnimationLevel } from '../../types'; import type { AnimationLevel } from '../../types';
import { MediaViewerOrigin } from '../../types'; import { MediaViewerOrigin } from '../../types';
import { import { selectChatMessages, selectUser, selectUserStatus } from '../../global/selectors';
selectChatMessages, selectUser, selectUserPhotoFromFullInfo, selectUserStatus,
} from '../../global/selectors';
import { getMainUsername, getUserStatus, isUserOnline } from '../../global/helpers'; import { getMainUsername, getUserStatus, isUserOnline } from '../../global/helpers';
import buildClassName from '../../util/buildClassName'; import buildClassName from '../../util/buildClassName';
import renderText from './helpers/renderText'; import renderText from './helpers/renderText';
@ -47,7 +45,6 @@ type StateProps =
{ {
user?: ApiUser; user?: ApiUser;
userStatus?: ApiUserStatus; userStatus?: ApiUserStatus;
userProfilePhoto?: ApiPhoto;
isSavedMessages?: boolean; isSavedMessages?: boolean;
animationLevel: AnimationLevel; animationLevel: AnimationLevel;
areMessagesLoaded: boolean; areMessagesLoaded: boolean;
@ -69,7 +66,6 @@ const PrivateChatInfo: FC<OwnProps & StateProps> = ({
noRtl, noRtl,
user, user,
userStatus, userStatus,
userProfilePhoto,
isSavedMessages, isSavedMessages,
areMessagesLoaded, areMessagesLoaded,
animationLevel, animationLevel,
@ -175,7 +171,6 @@ const PrivateChatInfo: FC<OwnProps & StateProps> = ({
key={user.id} key={user.id}
size={avatarSize} size={avatarSize}
user={user} user={user}
userProfilePhoto={userProfilePhoto}
isSavedMessages={isSavedMessages} isSavedMessages={isSavedMessages}
onClick={withMediaViewer ? handleAvatarViewerOpen : undefined} onClick={withMediaViewer ? handleAvatarViewerOpen : undefined}
withVideo={withVideoAvatar} withVideo={withVideoAvatar}
@ -196,13 +191,11 @@ export default memo(withGlobal<OwnProps>(
const userStatus = selectUserStatus(global, userId); const userStatus = selectUserStatus(global, userId);
const isSavedMessages = !forceShowSelf && user && user.isSelf; const isSavedMessages = !forceShowSelf && user && user.isSelf;
const areMessagesLoaded = Boolean(selectChatMessages(global, userId)); const areMessagesLoaded = Boolean(selectChatMessages(global, userId));
const userProfilePhoto = user ? selectUserPhotoFromFullInfo(global, user.id) : undefined;
return { return {
lastSyncTime, lastSyncTime,
user, user,
userStatus, userStatus,
userProfilePhoto,
isSavedMessages, isSavedMessages,
areMessagesLoaded, areMessagesLoaded,
animationLevel: global.settings.byKey.animationLevel, animationLevel: global.settings.byKey.animationLevel,

View File

@ -59,7 +59,7 @@ const ProfilePhoto: FC<OwnProps> = ({
const canHaveMedia = userOrChat && !isSavedMessages && !isDeleted && !isRepliesChat; const canHaveMedia = userOrChat && !isSavedMessages && !isDeleted && !isRepliesChat;
const { isVideo } = photo || {}; const { isVideo } = photo || {};
const avatarHash = canHaveMedia && getChatAvatarHash(userOrChat, 'normal', 'photo'); const avatarHash = canHaveMedia && getChatAvatarHash(userOrChat, 'normal');
const avatarBlobUrl = useMedia(avatarHash, undefined, undefined, lastSyncTime); const avatarBlobUrl = useMedia(avatarHash, undefined, undefined, lastSyncTime);
const photoHash = canHaveMedia && photo && !isVideo && `photo${photo.id}?size=c`; const photoHash = canHaveMedia && photo && !isVideo && `photo${photo.id}?size=c`;

View File

@ -1,51 +0,0 @@
import React, { memo } from '../../lib/teact/teact';
import { withGlobal } from '../../global';
import type { FC } from '../../lib/teact/teact';
import type { ApiPhoto, ApiUser } from '../../api/types';
import type { AnimationLevel } from '../../types';
import { selectUserPhotoFromFullInfo } from '../../global/selectors';
import Avatar from './Avatar';
type OwnProps = {
user?: ApiUser;
withVideo?: boolean;
className?: string;
size?: 'micro' | 'tiny' | 'small' | 'medium' | 'large';
};
interface StateProps {
profilePhoto?: ApiPhoto;
animationLevel?: AnimationLevel;
}
const UserAvatar: FC<OwnProps & StateProps> = ({
user,
profilePhoto,
className,
animationLevel,
withVideo,
size,
}) => {
return (
<Avatar
user={user}
className={className}
userProfilePhoto={profilePhoto}
animationLevel={animationLevel}
withVideo={withVideo}
size={size}
/>
);
};
export default memo(withGlobal<OwnProps>(
(global, { user }): StateProps => {
return {
profilePhoto: user ? selectUserPhotoFromFullInfo(global, user.id) : undefined,
animationLevel: global.settings.byKey.animationLevel,
};
},
)(UserAvatar));

View File

@ -8,7 +8,6 @@ import type {
ApiFormattedText, ApiFormattedText,
ApiMessage, ApiMessage,
ApiMessageOutgoingStatus, ApiMessageOutgoingStatus,
ApiPhoto,
ApiTopic, ApiTopic,
ApiTypingStatus, ApiTypingStatus,
ApiUser, ApiUser,
@ -37,7 +36,6 @@ import {
selectThreadParam, selectThreadParam,
selectTopicFromMessage, selectTopicFromMessage,
selectUser, selectUser,
selectUserPhotoFromFullInfo,
selectUserStatus, selectUserStatus,
} from '../../../global/selectors'; } from '../../../global/selectors';
import buildClassName from '../../../util/buildClassName'; import buildClassName from '../../../util/buildClassName';
@ -78,7 +76,6 @@ type StateProps = {
isMuted?: boolean; isMuted?: boolean;
user?: ApiUser; user?: ApiUser;
userStatus?: ApiUserStatus; userStatus?: ApiUserStatus;
userProfilePhoto?: ApiPhoto;
actionTargetUserIds?: string[]; actionTargetUserIds?: string[];
actionTargetMessage?: ApiMessage; actionTargetMessage?: ApiMessage;
actionTargetChatId?: string; actionTargetChatId?: string;
@ -106,7 +103,6 @@ const Chat: FC<OwnProps & StateProps> = ({
isMuted, isMuted,
user, user,
userStatus, userStatus,
userProfilePhoto,
actionTargetUserIds, actionTargetUserIds,
lastMessageSender, lastMessageSender,
lastMessageOutgoingStatus, lastMessageOutgoingStatus,
@ -240,7 +236,6 @@ const Chat: FC<OwnProps & StateProps> = ({
<Avatar <Avatar
chat={chat} chat={chat}
user={user} user={user}
userProfilePhoto={userProfilePhoto}
userStatus={userStatus} userStatus={userStatus}
isSavedMessages={user?.isSelf} isSavedMessages={user?.isSelf}
lastSyncTime={lastSyncTime} lastSyncTime={lastSyncTime}
@ -330,7 +325,6 @@ export default memo(withGlobal<OwnProps>(
const user = privateChatUserId ? selectUser(global, privateChatUserId) : undefined; const user = privateChatUserId ? selectUser(global, privateChatUserId) : undefined;
const userStatus = privateChatUserId ? selectUserStatus(global, privateChatUserId) : undefined; const userStatus = privateChatUserId ? selectUserStatus(global, privateChatUserId) : undefined;
const userProfilePhoto = user ? selectUserPhotoFromFullInfo(global, user.id) : undefined;
const lastMessageTopic = chat.lastMessage && selectTopicFromMessage(global, chat.lastMessage); const lastMessageTopic = chat.lastMessage && selectTopicFromMessage(global, chat.lastMessage);
const typingStatus = selectThreadParam(global, chatId, MAIN_THREAD_ID, 'typingStatus'); const typingStatus = selectThreadParam(global, chatId, MAIN_THREAD_ID, 'typingStatus');
@ -354,7 +348,6 @@ export default memo(withGlobal<OwnProps>(
}), }),
user, user,
userStatus, userStatus,
userProfilePhoto,
lastMessageTopic, lastMessageTopic,
typingStatus, typingStatus,
}; };

View File

@ -3,7 +3,7 @@ import React, { memo, useCallback } from '../../../lib/teact/teact';
import { getActions, withGlobal } from '../../../global'; import { getActions, withGlobal } from '../../../global';
import type { import type {
ApiChat, ApiUser, ApiMessage, ApiMessageOutgoingStatus, ApiPhoto, ApiChat, ApiUser, ApiMessage, ApiMessageOutgoingStatus,
} from '../../../api/types'; } from '../../../api/types';
import type { AnimationLevel } from '../../../types'; import type { AnimationLevel } from '../../../types';
import type { LangFn } from '../../../hooks/useLang'; import type { LangFn } from '../../../hooks/useLang';
@ -17,7 +17,7 @@ import {
getMessageSticker, getMessageSticker,
getMessageIsSpoiler, getMessageIsSpoiler,
} from '../../../global/helpers'; } from '../../../global/helpers';
import { selectChat, selectUser, selectUserPhotoFromFullInfo } from '../../../global/selectors'; import { selectChat, selectUser } from '../../../global/selectors';
import buildClassName from '../../../util/buildClassName'; import buildClassName from '../../../util/buildClassName';
import { formatPastTimeShort } from '../../../util/dateFormat'; import { formatPastTimeShort } from '../../../util/dateFormat';
import { renderMessageSummary } from '../../common/helpers/renderMessageText'; import { renderMessageSummary } from '../../common/helpers/renderMessageText';
@ -43,7 +43,6 @@ type OwnProps = {
type StateProps = { type StateProps = {
chat?: ApiChat; chat?: ApiChat;
privateChatUser?: ApiUser; privateChatUser?: ApiUser;
userProfilePhoto?: ApiPhoto;
lastMessageOutgoingStatus?: ApiMessageOutgoingStatus; lastMessageOutgoingStatus?: ApiMessageOutgoingStatus;
lastSyncTime?: number; lastSyncTime?: number;
animationLevel?: AnimationLevel; animationLevel?: AnimationLevel;
@ -55,7 +54,6 @@ const ChatMessage: FC<OwnProps & StateProps> = ({
chatId, chatId,
chat, chat,
privateChatUser, privateChatUser,
userProfilePhoto,
animationLevel, animationLevel,
lastSyncTime, lastSyncTime,
}) => { }) => {
@ -88,7 +86,6 @@ const ChatMessage: FC<OwnProps & StateProps> = ({
<Avatar <Avatar
chat={chat} chat={chat}
user={privateChatUser} user={privateChatUser}
userProfilePhoto={userProfilePhoto}
isSavedMessages={privateChatUser?.isSelf} isSavedMessages={privateChatUser?.isSelf}
lastSyncTime={lastSyncTime} lastSyncTime={lastSyncTime}
withVideo withVideo
@ -151,16 +148,12 @@ export default memo(withGlobal<OwnProps>(
const privateChatUserId = getPrivateChatUserId(chat); const privateChatUserId = getPrivateChatUserId(chat);
const privateChatUser = privateChatUserId ? selectUser(global, privateChatUserId) : undefined; const privateChatUser = privateChatUserId ? selectUser(global, privateChatUserId) : undefined;
const userProfilePhoto = privateChatUser ? selectUserPhotoFromFullInfo(global, privateChatUser.id) : undefined;
return { return {
chat, chat,
lastSyncTime: global.lastSyncTime, lastSyncTime: global.lastSyncTime,
animationLevel: global.settings.byKey.animationLevel, animationLevel: global.settings.byKey.animationLevel,
...(privateChatUserId && { ...(privateChatUserId && { privateChatUser }),
privateChatUser,
userProfilePhoto,
}),
}; };
}, },
)(ChatMessage)); )(ChatMessage));

View File

@ -5,6 +5,7 @@ import React, {
import { getActions, withGlobal } from '../../../global'; import { getActions, withGlobal } from '../../../global';
import type { ApiUser } from '../../../api/types'; import type { ApiUser } from '../../../api/types';
import type { AnimationLevel } from '../../../types';
import { getUserFirstOrLastName } from '../../../global/helpers'; import { getUserFirstOrLastName } from '../../../global/helpers';
import renderText from '../../common/helpers/renderText'; import renderText from '../../common/helpers/renderText';
@ -14,7 +15,7 @@ import useLang from '../../../hooks/useLang';
import Button from '../../ui/Button'; import Button from '../../ui/Button';
import LeftSearchResultChat from './LeftSearchResultChat'; import LeftSearchResultChat from './LeftSearchResultChat';
import UserAvatar from '../../common/UserAvatar'; import Avatar from '../../common/Avatar';
import './RecentContacts.scss'; import './RecentContacts.scss';
@ -26,6 +27,7 @@ type StateProps = {
topUserIds?: string[]; topUserIds?: string[];
usersById: Record<string, ApiUser>; usersById: Record<string, ApiUser>;
recentlyFoundChatIds?: string[]; recentlyFoundChatIds?: string[];
animationLevel: AnimationLevel;
}; };
const SEARCH_CLOSE_TIMEOUT_MS = 250; const SEARCH_CLOSE_TIMEOUT_MS = 250;
@ -37,6 +39,7 @@ const RecentContacts: FC<OwnProps & StateProps> = ({
topUserIds, topUserIds,
usersById, usersById,
recentlyFoundChatIds, recentlyFoundChatIds,
animationLevel,
onReset, onReset,
}) => { }) => {
const { const {
@ -83,7 +86,7 @@ const RecentContacts: FC<OwnProps & StateProps> = ({
onClick={() => handleClick(userId)} onClick={() => handleClick(userId)}
dir={lang.isRtl ? 'rtl' : undefined} dir={lang.isRtl ? 'rtl' : undefined}
> >
<UserAvatar user={usersById[userId]} withVideo /> <Avatar user={usersById[userId]} animationLevel={animationLevel} withVideo />
<div className="top-peer-name">{renderText(getUserFirstOrLastName(usersById[userId]) || NBSP)}</div> <div className="top-peer-name">{renderText(getUserFirstOrLastName(usersById[userId]) || NBSP)}</div>
</div> </div>
))} ))}
@ -123,11 +126,13 @@ export default memo(withGlobal<OwnProps>(
const { userIds: topUserIds } = global.topPeers; const { userIds: topUserIds } = global.topPeers;
const usersById = global.users.byId; const usersById = global.users.byId;
const { recentlyFoundChatIds } = global; const { recentlyFoundChatIds } = global;
const { animationLevel } = global.settings.byKey;
return { return {
topUserIds, topUserIds,
usersById, usersById,
recentlyFoundChatIds, recentlyFoundChatIds,
animationLevel,
}; };
}, },
)(RecentContacts)); )(RecentContacts));

View File

@ -3,10 +3,9 @@ import { getActions, withGlobal } from '../../../global';
import type { FC } from '../../../lib/teact/teact'; import type { FC } from '../../../lib/teact/teact';
import type { AnimationLevel } from '../../../types'; import type { AnimationLevel } from '../../../types';
import type { ApiPhoto, ApiUser, ApiWebSession } from '../../../api/types'; import type { ApiUser, ApiWebSession } from '../../../api/types';
import buildClassName from '../../../util/buildClassName'; import buildClassName from '../../../util/buildClassName';
import { selectUserPhotoFromFullInfo } from '../../../global/selectors';
import useLang from '../../../hooks/useLang'; import useLang from '../../../hooks/useLang';
import useCurrentOrPrev from '../../../hooks/useCurrentOrPrev'; import useCurrentOrPrev from '../../../hooks/useCurrentOrPrev';
@ -27,7 +26,6 @@ type OwnProps = {
type StateProps = { type StateProps = {
session?: ApiWebSession; session?: ApiWebSession;
bot?: ApiUser; bot?: ApiUser;
botProfilePhoto?: ApiPhoto;
animationLevel: AnimationLevel; animationLevel: AnimationLevel;
}; };
@ -35,7 +33,6 @@ const SettingsActiveWebsite: FC<OwnProps & StateProps> = ({
isOpen, isOpen,
session, session,
bot, bot,
botProfilePhoto,
animationLevel, animationLevel,
onClose, onClose,
}) => { }) => {
@ -44,7 +41,6 @@ const SettingsActiveWebsite: FC<OwnProps & StateProps> = ({
const renderingSession = useCurrentOrPrev(session, true); const renderingSession = useCurrentOrPrev(session, true);
const renderingBot = useCurrentOrPrev(bot, true); const renderingBot = useCurrentOrPrev(bot, true);
const renderingBotProfilePhoto = useCurrentOrPrev(botProfilePhoto, true);
const handleTerminateSessionClick = useCallback(() => { const handleTerminateSessionClick = useCallback(() => {
terminateWebAuthorization({ hash: session!.hash }); terminateWebAuthorization({ hash: session!.hash });
@ -83,7 +79,6 @@ const SettingsActiveWebsite: FC<OwnProps & StateProps> = ({
<Avatar <Avatar
className={styles.avatar} className={styles.avatar}
user={renderingBot} user={renderingBot}
userProfilePhoto={renderingBotProfilePhoto}
size="large" size="large"
animationLevel={animationLevel} animationLevel={animationLevel}
withVideo withVideo
@ -113,12 +108,10 @@ const SettingsActiveWebsite: FC<OwnProps & StateProps> = ({
export default memo(withGlobal<OwnProps>((global, { hash }): StateProps => { export default memo(withGlobal<OwnProps>((global, { hash }): StateProps => {
const session = hash ? global.activeWebSessions.byHash[hash] : undefined; const session = hash ? global.activeWebSessions.byHash[hash] : undefined;
const bot = session ? global.users.byId[session.botId] : undefined; const bot = session ? global.users.byId[session.botId] : undefined;
const botProfilePhoto = bot ? selectUserPhotoFromFullInfo(global, bot.id) : undefined;
return { return {
session, session,
bot, bot,
botProfilePhoto,
animationLevel: global.settings.byKey.animationLevel, animationLevel: global.settings.byKey.animationLevel,
}; };
})(SettingsActiveWebsite)); })(SettingsActiveWebsite));

View File

@ -5,6 +5,7 @@ import { getActions, getGlobal, withGlobal } from '../../../global';
import type { FC } from '../../../lib/teact/teact'; import type { FC } from '../../../lib/teact/teact';
import type { ApiWebSession } from '../../../api/types'; import type { ApiWebSession } from '../../../api/types';
import type { AnimationLevel } from '../../../types';
import { formatPastTimeShort } from '../../../util/dateFormat'; import { formatPastTimeShort } from '../../../util/dateFormat';
import buildClassName from '../../../util/buildClassName'; import buildClassName from '../../../util/buildClassName';
@ -16,7 +17,7 @@ import useHistoryBack from '../../../hooks/useHistoryBack';
import ListItem from '../../ui/ListItem'; import ListItem from '../../ui/ListItem';
import ConfirmDialog from '../../ui/ConfirmDialog'; import ConfirmDialog from '../../ui/ConfirmDialog';
import SettingsActiveWebsite from './SettingsActiveWebsite'; import SettingsActiveWebsite from './SettingsActiveWebsite';
import UserAvatar from '../../common/UserAvatar'; import Avatar from '../../common/Avatar';
import FullNameTitle from '../../common/FullNameTitle'; import FullNameTitle from '../../common/FullNameTitle';
import styles from './SettingsActiveWebsites.module.scss'; import styles from './SettingsActiveWebsites.module.scss';
@ -29,12 +30,14 @@ type OwnProps = {
type StateProps = { type StateProps = {
byHash: Record<string, ApiWebSession>; byHash: Record<string, ApiWebSession>;
orderedHashes: string[]; orderedHashes: string[];
animationLevel: AnimationLevel;
}; };
const SettingsActiveWebsites: FC<OwnProps & StateProps> = ({ const SettingsActiveWebsites: FC<OwnProps & StateProps> = ({
isActive, isActive,
byHash, byHash,
orderedHashes, orderedHashes,
animationLevel,
onReset, onReset,
}) => { }) => {
const { const {
@ -110,7 +113,7 @@ const SettingsActiveWebsites: FC<OwnProps & StateProps> = ({
// eslint-disable-next-line react/jsx-no-bind // eslint-disable-next-line react/jsx-no-bind
onClick={() => handleOpenSessionModal(session.hash)} onClick={() => handleOpenSessionModal(session.hash)}
> >
<UserAvatar className={styles.avatar} user={bot} size="tiny" withVideo /> <Avatar className={styles.avatar} user={bot} size="tiny" withVideo animationLevel={animationLevel} />
<div className="multiline-menu-item full-size" dir="auto"> <div className="multiline-menu-item full-size" dir="auto">
<span className="date">{formatPastTimeShort(lang, session.dateActive * 1000)}</span> <span className="date">{formatPastTimeShort(lang, session.dateActive * 1000)}</span>
{bot && <FullNameTitle className={styles.title} peer={bot} />} {bot && <FullNameTitle className={styles.title} peer={bot} />}
@ -161,6 +164,7 @@ export default memo(withGlobal<OwnProps>(
return { return {
byHash, byHash,
orderedHashes, orderedHashes,
animationLevel: global.settings.byKey.animationLevel,
}; };
}, },
)(SettingsActiveWebsites)); )(SettingsActiveWebsites));

View File

@ -1,13 +1,12 @@
import type { FC } from '../../../lib/teact/teact'; import type { FC } from '../../../lib/teact/teact';
import React, { memo, useCallback, useMemo } from '../../../lib/teact/teact'; import React, { memo, useCallback, useMemo } from '../../../lib/teact/teact';
import { getActions, getGlobal, withGlobal } from '../../../global'; import { getActions, withGlobal } from '../../../global';
import type { ApiChat, ApiCountryCode, ApiUser } from '../../../api/types'; import type { ApiChat, ApiCountryCode, ApiUser } from '../../../api/types';
import { CHAT_HEIGHT_PX } from '../../../config'; import { CHAT_HEIGHT_PX } from '../../../config';
import { formatPhoneNumberWithCode } from '../../../util/phoneNumber'; import { formatPhoneNumberWithCode } from '../../../util/phoneNumber';
import { getMainUsername, isUserId } from '../../../global/helpers'; import { getMainUsername, isUserId } from '../../../global/helpers';
import { selectUserPhotoFromFullInfo } from '../../../global/selectors';
import buildClassName from '../../../util/buildClassName'; import buildClassName from '../../../util/buildClassName';
import useLang from '../../../hooks/useLang'; import useLang from '../../../hooks/useLang';
import useHistoryBack from '../../../hooks/useHistoryBack'; import useHistoryBack from '../../../hooks/useHistoryBack';
@ -99,7 +98,6 @@ const SettingsPrivacyBlockedUsers: FC<OwnProps & StateProps> = ({
size="medium" size="medium"
user={user} user={user}
chat={chat} chat={chat}
userProfilePhoto={user ? selectUserPhotoFromFullInfo(getGlobal(), user.id) : undefined}
/> />
<div className="contact-info" dir="auto"> <div className="contact-info" dir="auto">
{userOrChat && <FullNameTitle peer={userOrChat} />} {userOrChat && <FullNameTitle peer={userOrChat} />}

View File

@ -4,13 +4,11 @@ import React, {
} from '../../lib/teact/teact'; } from '../../lib/teact/teact';
import { getActions, withGlobal } from '../../global'; import { getActions, withGlobal } from '../../global';
import type { import type { ApiCountryCode, ApiUser, ApiUserStatus } from '../../api/types';
ApiCountryCode, ApiPhoto, ApiUser, ApiUserStatus,
} from '../../api/types';
import { IS_TOUCH_ENV } from '../../util/windowEnvironment'; import { IS_TOUCH_ENV } from '../../util/windowEnvironment';
import { getUserStatus } from '../../global/helpers'; import { getUserStatus } from '../../global/helpers';
import { selectUser, selectUserPhotoFromFullInfo, selectUserStatus } from '../../global/selectors'; import { selectUser, selectUserStatus } from '../../global/selectors';
import renderText from '../common/helpers/renderText'; import renderText from '../common/helpers/renderText';
import { formatPhoneNumberWithCode } from '../../util/phoneNumber'; import { formatPhoneNumberWithCode } from '../../util/phoneNumber';
import useLang from '../../hooks/useLang'; import useLang from '../../hooks/useLang';
@ -36,7 +34,6 @@ export type OwnProps = {
type StateProps = { type StateProps = {
user?: ApiUser; user?: ApiUser;
userStatus?: ApiUserStatus; userStatus?: ApiUserStatus;
userProfilePhoto?: ApiPhoto;
phoneCodeList: ApiCountryCode[]; phoneCodeList: ApiCountryCode[];
}; };
@ -46,14 +43,12 @@ const NewContactModal: FC<OwnProps & StateProps> = ({
isByPhoneNumber, isByPhoneNumber,
user, user,
userStatus, userStatus,
userProfilePhoto,
phoneCodeList, phoneCodeList,
}) => { }) => {
const { updateContact, importContact, closeNewContactDialog } = getActions(); const { updateContact, importContact, closeNewContactDialog } = getActions();
const lang = useLang(); const lang = useLang();
const renderingUser = useCurrentOrPrev(user); const renderingUser = useCurrentOrPrev(user);
const renderingUserProfilePhoto = useCurrentOrPrev(userProfilePhoto);
const renderingIsByPhoneNumber = useCurrentOrPrev(isByPhoneNumber); const renderingIsByPhoneNumber = useCurrentOrPrev(isByPhoneNumber);
// eslint-disable-next-line no-null/no-null // eslint-disable-next-line no-null/no-null
const inputRef = useRef<HTMLInputElement>(null); const inputRef = useRef<HTMLInputElement>(null);
@ -128,7 +123,6 @@ const NewContactModal: FC<OwnProps & StateProps> = ({
<Avatar <Avatar
size="jumbo" size="jumbo"
user={renderingUser} user={renderingUser}
userProfilePhoto={renderingUserProfilePhoto}
text={`${firstName} ${lastName}`} text={`${firstName} ${lastName}`}
/> />
<div className="NewContactModal__profile-info"> <div className="NewContactModal__profile-info">
@ -241,7 +235,6 @@ export default memo(withGlobal<OwnProps>(
return { return {
user, user,
userStatus: userId ? selectUserStatus(global, userId) : undefined, userStatus: userId ? selectUserStatus(global, userId) : undefined,
userProfilePhoto: user ? selectUserPhotoFromFullInfo(global, user.id) : undefined,
phoneCodeList: global.countryList.phoneCodes, phoneCodeList: global.countryList.phoneCodes,
}; };
}, },

View File

@ -4,7 +4,7 @@ import React, {
import { getActions, withGlobal } from '../../../global'; import { getActions, withGlobal } from '../../../global';
import type { FC } from '../../../lib/teact/teact'; import type { FC } from '../../../lib/teact/teact';
import type { ApiPhoto, ApiPremiumGiftOption, ApiUser } from '../../../api/types'; import type { ApiPremiumGiftOption, ApiUser } from '../../../api/types';
import type { AnimationLevel } from '../../../types'; import type { AnimationLevel } from '../../../types';
import { formatCurrency } from '../../../util/formatCurrency'; import { formatCurrency } from '../../../util/formatCurrency';
@ -14,7 +14,6 @@ import {
selectTabState, selectTabState,
selectUser, selectUser,
selectUserFullInfo, selectUserFullInfo,
selectUserPhotoFromFullInfo,
} from '../../../global/selectors'; } from '../../../global/selectors';
import useCurrentOrPrev from '../../../hooks/useCurrentOrPrev'; import useCurrentOrPrev from '../../../hooks/useCurrentOrPrev';
@ -34,7 +33,6 @@ export type OwnProps = {
type StateProps = { type StateProps = {
user?: ApiUser; user?: ApiUser;
userProfilePhoto?: ApiPhoto;
gifts?: ApiPremiumGiftOption[]; gifts?: ApiPremiumGiftOption[];
monthlyCurrency?: string; monthlyCurrency?: string;
monthlyAmount?: number; monthlyAmount?: number;
@ -44,7 +42,6 @@ type StateProps = {
const GiftPremiumModal: FC<OwnProps & StateProps> = ({ const GiftPremiumModal: FC<OwnProps & StateProps> = ({
isOpen, isOpen,
user, user,
userProfilePhoto,
gifts, gifts,
monthlyCurrency, monthlyCurrency,
monthlyAmount, monthlyAmount,
@ -54,7 +51,6 @@ const GiftPremiumModal: FC<OwnProps & StateProps> = ({
const lang = useLang(); const lang = useLang();
const renderedUser = useCurrentOrPrev(user, true); const renderedUser = useCurrentOrPrev(user, true);
const renderedUserProfilePhoto = useCurrentOrPrev(userProfilePhoto, true);
const renderedGifts = useCurrentOrPrev(gifts, true); const renderedGifts = useCurrentOrPrev(gifts, true);
const [selectedOption, setSelectedOption] = useState<number | undefined>(); const [selectedOption, setSelectedOption] = useState<number | undefined>();
const firstGift = renderedGifts?.[0]; const firstGift = renderedGifts?.[0];
@ -133,7 +129,6 @@ const GiftPremiumModal: FC<OwnProps & StateProps> = ({
</Button> </Button>
<Avatar <Avatar
user={renderedUser} user={renderedUser}
userProfilePhoto={renderedUserProfilePhoto}
size="jumbo" size="jumbo"
className={styles.avatar} className={styles.avatar}
animationLevel={animationLevel} animationLevel={animationLevel}
@ -177,12 +172,10 @@ const GiftPremiumModal: FC<OwnProps & StateProps> = ({
export default memo(withGlobal<OwnProps>((global): StateProps => { export default memo(withGlobal<OwnProps>((global): StateProps => {
const { forUserId, monthlyCurrency, monthlyAmount } = selectTabState(global).giftPremiumModal || {}; const { forUserId, monthlyCurrency, monthlyAmount } = selectTabState(global).giftPremiumModal || {};
const user = forUserId ? selectUser(global, forUserId) : undefined; const user = forUserId ? selectUser(global, forUserId) : undefined;
const userProfilePhoto = user ? selectUserPhotoFromFullInfo(global, user.id) : undefined;
const gifts = user ? selectUserFullInfo(global, user.id)?.premiumGifts : undefined; const gifts = user ? selectUserFullInfo(global, user.id)?.premiumGifts : undefined;
return { return {
user, user,
userProfilePhoto,
gifts, gifts,
monthlyCurrency, monthlyCurrency,
monthlyAmount: monthlyAmount ? Number(monthlyAmount) : undefined, monthlyAmount: monthlyAmount ? Number(monthlyAmount) : undefined,

View File

@ -18,7 +18,6 @@ import useLang from '../../hooks/useLang';
import useAppLayout from '../../hooks/useAppLayout'; import useAppLayout from '../../hooks/useAppLayout';
import Avatar from '../common/Avatar'; import Avatar from '../common/Avatar';
import UserAvatar from '../common/UserAvatar';
import './SenderInfo.scss'; import './SenderInfo.scss';
@ -80,7 +79,7 @@ const SenderInfo: FC<OwnProps & StateProps> = ({
return ( return (
<div className="SenderInfo" onClick={handleFocusMessage}> <div className="SenderInfo" onClick={handleFocusMessage}>
{isUserId(sender.id) ? ( {isUserId(sender.id) ? (
<UserAvatar key={sender.id} size="medium" user={sender as ApiUser} withVideo /> <Avatar key={sender.id} size="medium" user={sender as ApiUser} animationLevel={animationLevel} withVideo />
) : ( ) : (
<Avatar key={sender.id} size="medium" chat={sender as ApiChat} animationLevel={animationLevel} withVideo /> <Avatar key={sender.id} size="medium" chat={sender as ApiChat} animationLevel={animationLevel} withVideo />
)} )}

View File

@ -2,7 +2,7 @@ import type { FC } from '../../lib/teact/teact';
import React, { import React, {
memo, useEffect, useMemo, useRef, memo, useEffect, useMemo, useRef,
} from '../../lib/teact/teact'; } from '../../lib/teact/teact';
import { getActions, getGlobal, withGlobal } from '../../global'; import { getActions, withGlobal } from '../../global';
import type { import type {
ApiUser, ApiMessage, ApiChat, ApiSticker, ApiTopic, ApiUser, ApiMessage, ApiChat, ApiSticker, ApiTopic,
@ -53,6 +53,7 @@ type OwnProps = {
}; };
type StateProps = { type StateProps = {
usersById: Record<string, ApiUser>;
senderUser?: ApiUser; senderUser?: ApiUser;
senderChat?: ApiChat; senderChat?: ApiChat;
targetUserIds?: string[]; targetUserIds?: string[];
@ -73,6 +74,7 @@ const ActionMessage: FC<OwnProps & StateProps> = ({
appearanceOrder = 0, appearanceOrder = 0,
isJustAdded, isJustAdded,
isLastInList, isLastInList,
usersById,
senderUser, senderUser,
senderChat, senderChat,
targetUserIds, targetUserIds,
@ -138,8 +140,6 @@ const ActionMessage: FC<OwnProps & StateProps> = ({
const { transitionClassNames } = useShowTransition(isShown, undefined, noAppearanceAnimation, false); const { transitionClassNames } = useShowTransition(isShown, undefined, noAppearanceAnimation, false);
// No need for expensive global updates on users and chats, so we avoid them
const usersById = getGlobal().users.byId;
const targetUsers = useMemo(() => { const targetUsers = useMemo(() => {
return targetUserIds return targetUserIds
? targetUserIds.map((userId) => usersById?.[userId]).filter(Boolean) ? targetUserIds.map((userId) => usersById?.[userId]).filter(Boolean)
@ -256,6 +256,7 @@ export default memo(withGlobal<OwnProps>(
chatId, senderId, replyToMessageId, content, chatId, senderId, replyToMessageId, content,
} = message; } = message;
const { byId: usersById } = global.users;
const userId = senderId; const userId = senderId;
const { targetUserIds, targetChatId } = content.action || {}; const { targetUserIds, targetChatId } = content.action || {};
const targetMessageId = replyToMessageId; const targetMessageId = replyToMessageId;
@ -277,6 +278,7 @@ export default memo(withGlobal<OwnProps>(
const topic = selectTopicFromMessage(global, message); const topic = selectTopicFromMessage(global, message);
return { return {
usersById,
senderUser, senderUser,
senderChat, senderChat,
targetChatId, targetChatId,

View File

@ -5,6 +5,7 @@ import React, {
import { getActions, getGlobal, withGlobal } from '../../global'; import { getActions, getGlobal, withGlobal } from '../../global';
import type { ApiAvailableReaction, ApiMessage, ApiReaction } from '../../api/types'; import type { ApiAvailableReaction, ApiMessage, ApiReaction } from '../../api/types';
import type { AnimationLevel } from '../../types';
import { LoadMoreDirection } from '../../types'; import { LoadMoreDirection } from '../../types';
import { selectChatMessage, selectTabState } from '../../global/selectors'; import { selectChatMessage, selectTabState } from '../../global/selectors';
@ -20,7 +21,7 @@ import useFlag from '../../hooks/useFlag';
import InfiniteScroll from '../ui/InfiniteScroll'; import InfiniteScroll from '../ui/InfiniteScroll';
import Modal from '../ui/Modal'; import Modal from '../ui/Modal';
import Button from '../ui/Button'; import Button from '../ui/Button';
import UserAvatar from '../common/UserAvatar'; import Avatar from '../common/Avatar';
import ListItem from '../ui/ListItem'; import ListItem from '../ui/ListItem';
import ReactionStaticEmoji from '../common/ReactionStaticEmoji'; import ReactionStaticEmoji from '../common/ReactionStaticEmoji';
import Loading from '../ui/Loading'; import Loading from '../ui/Loading';
@ -38,6 +39,7 @@ export type StateProps = Pick<ApiMessage, 'reactors' | 'reactions' | 'seenByUser
chatId?: string; chatId?: string;
messageId?: number; messageId?: number;
availableReactions?: ApiAvailableReaction[]; availableReactions?: ApiAvailableReaction[];
animationLevel?: AnimationLevel;
}; };
const ReactorListModal: FC<OwnProps & StateProps> = ({ const ReactorListModal: FC<OwnProps & StateProps> = ({
@ -48,6 +50,7 @@ const ReactorListModal: FC<OwnProps & StateProps> = ({
messageId, messageId,
seenByUserIds, seenByUserIds,
availableReactions, availableReactions,
animationLevel,
}) => { }) => {
const { const {
loadReactors, loadReactors,
@ -191,7 +194,7 @@ const ReactorListModal: FC<OwnProps & StateProps> = ({
// eslint-disable-next-line react/jsx-no-bind // eslint-disable-next-line react/jsx-no-bind
onClick={() => handleClick(userId)} onClick={() => handleClick(userId)}
> >
<UserAvatar user={user} size="small" withVideo /> <Avatar user={user} size="small" withVideo animationLevel={animationLevel} />
<FullNameTitle peer={user} withEmojiStatus /> <FullNameTitle peer={user} withEmojiStatus />
{r.reaction && ( {r.reaction && (
<ReactionStaticEmoji <ReactionStaticEmoji
@ -232,6 +235,7 @@ export default memo(withGlobal<OwnProps>(
reactors: message?.reactors, reactors: message?.reactors,
seenByUserIds: message?.seenByUserIds, seenByUserIds: message?.seenByUserIds,
availableReactions: global.availableReactions, availableReactions: global.availableReactions,
animationLevel: global.settings.byKey.animationLevel,
}; };
}, },
)(ReactorListModal)); )(ReactorListModal));

View File

@ -24,7 +24,6 @@ import type {
ApiBotMenuButton, ApiBotMenuButton,
ApiAttachMenuPeerType, ApiAttachMenuPeerType,
ApiChatFullInfo, ApiChatFullInfo,
ApiPhoto,
} from '../../../api/types'; } from '../../../api/types';
import type { InlineBotSettings, ISettings } from '../../../types'; import type { InlineBotSettings, ISettings } from '../../../types';
@ -63,7 +62,7 @@ import {
selectTabState, selectTabState,
selectTheme, selectTheme,
selectUser, selectUser,
selectUserFullInfo, selectUserPhotoFromFullInfo, selectUserFullInfo,
} from '../../../global/selectors'; } from '../../../global/selectors';
import { import {
getAllowedAttachmentOptions, getAllowedAttachmentOptions,
@ -190,7 +189,6 @@ type StateProps =
chatBotCommands?: ApiBotCommand[]; chatBotCommands?: ApiBotCommand[];
sendAsUser?: ApiUser; sendAsUser?: ApiUser;
sendAsChat?: ApiChat; sendAsChat?: ApiChat;
sendAsUserProfilePhoto?: ApiPhoto;
sendAsId?: string; sendAsId?: string;
editingDraft?: ApiFormattedText; editingDraft?: ApiFormattedText;
requestedDraftText?: string; requestedDraftText?: string;
@ -277,7 +275,6 @@ const Composer: FC<OwnProps & StateProps> = ({
chatBotCommands, chatBotCommands,
sendAsUser, sendAsUser,
sendAsChat, sendAsChat,
sendAsUserProfilePhoto,
sendAsId, sendAsId,
editingDraft, editingDraft,
replyingToId, replyingToId,
@ -1373,7 +1370,6 @@ const Composer: FC<OwnProps & StateProps> = ({
<Avatar <Avatar
user={sendAsUser} user={sendAsUser}
chat={sendAsChat} chat={sendAsChat}
userProfilePhoto={sendAsUserProfilePhoto}
size="tiny" size="tiny"
/> />
</Button> </Button>
@ -1586,7 +1582,6 @@ export default memo(withGlobal<OwnProps>(
); );
const sendAsUser = sendAsId ? selectUser(global, sendAsId) : undefined; const sendAsUser = sendAsId ? selectUser(global, sendAsId) : undefined;
const sendAsChat = !sendAsUser && sendAsId ? selectChat(global, sendAsId) : undefined; const sendAsChat = !sendAsUser && sendAsId ? selectChat(global, sendAsId) : undefined;
const sendAsUserProfilePhoto = sendAsUser ? selectUserPhotoFromFullInfo(global, sendAsUser.id) : undefined;
const requestedDraftText = selectRequestedDraftText(global, chatId); const requestedDraftText = selectRequestedDraftText(global, chatId);
const requestedDraftFiles = selectRequestedDraftFiles(global, chatId); const requestedDraftFiles = selectRequestedDraftFiles(global, chatId);
const currentMessageList = selectCurrentMessageList(global); const currentMessageList = selectCurrentMessageList(global);
@ -1647,7 +1642,6 @@ export default memo(withGlobal<OwnProps>(
botMenuButton: chatBotFullInfo?.botInfo?.menuButton, botMenuButton: chatBotFullInfo?.botInfo?.menuButton,
sendAsUser, sendAsUser,
sendAsChat, sendAsChat,
sendAsUserProfilePhoto,
sendAsId, sendAsId,
editingDraft, editingDraft,
requestedDraftText, requestedDraftText,

View File

@ -16,7 +16,6 @@ import useLang from '../../../hooks/useLang';
import ListItem from '../../ui/ListItem'; import ListItem from '../../ui/ListItem';
import Avatar from '../../common/Avatar'; import Avatar from '../../common/Avatar';
import UserAvatar from '../../common/UserAvatar';
import Menu from '../../ui/Menu'; import Menu from '../../ui/Menu';
import FullNameTitle from '../../common/FullNameTitle'; import FullNameTitle from '../../common/FullNameTitle';
@ -127,19 +126,12 @@ const SendAsMenu: FC<OwnProps> = ({
rightElement={!isCurrentUserPremium && isPremium rightElement={!isCurrentUserPremium && isPremium
&& <i className="icon icon-lock-badge send-as-icon-locked" />} && <i className="icon icon-lock-badge send-as-icon-locked" />}
> >
{user ? ( <Avatar
<UserAvatar size="small"
user={user} chat={chat}
size="small" user={user}
className={avatarClassName} className={avatarClassName}
/> />
) : (
<Avatar
size="small"
chat={chat}
className={avatarClassName}
/>
)}
<div className="info"> <div className="info">
{userOrChat && <FullNameTitle peer={userOrChat} noFake />} {userOrChat && <FullNameTitle peer={userOrChat} noFake />}
<span className="subtitle">{user <span className="subtitle">{user

View File

@ -9,7 +9,6 @@ import type {
import { isUserId } from '../../../global/helpers'; import { isUserId } from '../../../global/helpers';
import { formatIntegerCompact } from '../../../util/textFormat'; import { formatIntegerCompact } from '../../../util/textFormat';
import buildClassName from '../../../util/buildClassName'; import buildClassName from '../../../util/buildClassName';
import { selectUserPhotoFromFullInfo } from '../../../global/selectors';
import useLang from '../../../hooks/useLang'; import useLang from '../../../hooks/useLang';
import Avatar from '../../common/Avatar'; import Avatar from '../../common/Avatar';
@ -63,7 +62,6 @@ const CommentButton: FC<OwnProps> = ({
key={user.id} key={user.id}
size="small" size="small"
user={isUserId(user.id) ? user as ApiUser : undefined} user={isUserId(user.id) ? user as ApiUser : undefined}
userProfilePhoto={isUserId(user.id) ? selectUserPhotoFromFullInfo(getGlobal(), user.id) : undefined}
chat={!isUserId(user.id) ? user as ApiChat : undefined} chat={!isUserId(user.id) ? user as ApiChat : undefined}
/> />
))} ))}

View File

@ -2,12 +2,10 @@ import type { FC } from '../../../lib/teact/teact';
import React, { useCallback } from '../../../lib/teact/teact'; import React, { useCallback } from '../../../lib/teact/teact';
import { getActions, withGlobal } from '../../../global'; import { getActions, withGlobal } from '../../../global';
import type { import type { ApiUser, ApiContact, ApiCountryCode } from '../../../api/types';
ApiUser, ApiContact, ApiCountryCode, ApiPhoto,
} from '../../../api/types';
import type { AnimationLevel } from '../../../types'; import type { AnimationLevel } from '../../../types';
import { selectUser, selectUserPhotoFromFullInfo } from '../../../global/selectors'; import { selectUser } from '../../../global/selectors';
import { formatPhoneNumberWithCode } from '../../../util/phoneNumber'; import { formatPhoneNumberWithCode } from '../../../util/phoneNumber';
import buildClassName from '../../../util/buildClassName'; import buildClassName from '../../../util/buildClassName';
@ -21,7 +19,6 @@ type OwnProps = {
type StateProps = { type StateProps = {
user?: ApiUser; user?: ApiUser;
userProfilePhoto?: ApiPhoto;
phoneCodeList: ApiCountryCode[]; phoneCodeList: ApiCountryCode[];
animationLevel: AnimationLevel; animationLevel: AnimationLevel;
}; };
@ -29,7 +26,7 @@ type StateProps = {
const UNREGISTERED_CONTACT_ID = '0'; const UNREGISTERED_CONTACT_ID = '0';
const Contact: FC<OwnProps & StateProps> = ({ const Contact: FC<OwnProps & StateProps> = ({
contact, user, userProfilePhoto, phoneCodeList, animationLevel, contact, user, phoneCodeList, animationLevel,
}) => { }) => {
const { openChat } = getActions(); const { openChat } = getActions();
@ -53,7 +50,6 @@ const Contact: FC<OwnProps & StateProps> = ({
<Avatar <Avatar
size="large" size="large"
user={user} user={user}
userProfilePhoto={userProfilePhoto}
text={firstName || lastName} text={firstName || lastName}
animationLevel={animationLevel} animationLevel={animationLevel}
withVideo withVideo
@ -70,11 +66,9 @@ export default withGlobal<OwnProps>(
(global, { contact }): StateProps => { (global, { contact }): StateProps => {
const { countryList: { phoneCodes: phoneCodeList } } = global; const { countryList: { phoneCodes: phoneCodeList } } = global;
const user = selectUser(global, contact.userId); const user = selectUser(global, contact.userId);
const userProfilePhoto = user ? selectUserPhotoFromFullInfo(global, user.id) : undefined;
return { return {
user, user,
userProfilePhoto,
phoneCodeList, phoneCodeList,
animationLevel: global.settings.byKey.animationLevel, animationLevel: global.settings.byKey.animationLevel,
}; };

View File

@ -5,9 +5,7 @@ import { requestMutation } from '../../../lib/fasterdom/fasterdom';
import { getActions } from '../../../global'; import { getActions } from '../../../global';
import type { FC } from '../../../lib/teact/teact'; import type { FC } from '../../../lib/teact/teact';
import type { import type { ApiChat, ApiMessage, ApiUser } from '../../../api/types';
ApiChat, ApiMessage, ApiPhoto, ApiUser,
} from '../../../api/types';
import type { ISettings } from '../../../types'; import type { ISettings } from '../../../types';
import { CUSTOM_APPENDIX_ATTRIBUTE, MESSAGE_CONTENT_SELECTOR } from '../../../config'; import { CUSTOM_APPENDIX_ATTRIBUTE, MESSAGE_CONTENT_SELECTOR } from '../../../config';
@ -55,7 +53,6 @@ const SVG_PIN = { __html: '<svg version="1.1" class="round-pin" xmlns="http://ww
type OwnProps = { type OwnProps = {
message: ApiMessage; message: ApiMessage;
peer?: ApiUser | ApiChat; peer?: ApiUser | ApiChat;
peerProfilePhoto?: ApiPhoto;
lastSyncTime?: number; lastSyncTime?: number;
isInSelectMode?: boolean; isInSelectMode?: boolean;
isSelected?: boolean; isSelected?: boolean;
@ -65,7 +62,6 @@ type OwnProps = {
const Location: FC<OwnProps> = ({ const Location: FC<OwnProps> = ({
message, message,
peer, peer,
peerProfilePhoto,
lastSyncTime, lastSyncTime,
isInSelectMode, isInSelectMode,
isSelected, isSelected,
@ -247,7 +243,7 @@ const Location: FC<OwnProps> = ({
if (type === 'geoLive') { if (type === 'geoLive') {
return ( return (
<div className={pinClassName} dangerouslySetInnerHTML={SVG_PIN}> <div className={pinClassName} dangerouslySetInnerHTML={SVG_PIN}>
<Avatar chat={avatarChat} user={avatarUser} userProfilePhoto={peerProfilePhoto} className="location-avatar" /> <Avatar chat={avatarChat} user={avatarUser} className="location-avatar" />
{location.heading !== undefined && ( {location.heading !== undefined && (
<div className="direction" style={`--direction: ${location.heading}deg`} /> <div className="direction" style={`--direction: ${location.heading}deg`} />
)} )}

View File

@ -24,7 +24,6 @@ import type {
ApiTopic, ApiTopic,
ApiReaction, ApiReaction,
ApiStickerSet, ApiStickerSet,
ApiPhoto,
} from '../../../api/types'; } from '../../../api/types';
import type { import type {
AnimationLevel, FocusDirection, IAlbum, ISettings, AnimationLevel, FocusDirection, IAlbum, ISettings,
@ -70,7 +69,6 @@ import {
selectChatTranslations, selectChatTranslations,
selectRequestedTranslationLanguage, selectRequestedTranslationLanguage,
selectChatFullInfo, selectChatFullInfo,
selectUserPhotoFromFullInfo,
} from '../../../global/selectors'; } from '../../../global/selectors';
import { import {
getMessageContent, getMessageContent,
@ -203,8 +201,6 @@ type StateProps = {
canShowSender: boolean; canShowSender: boolean;
originSender?: ApiUser | ApiChat; originSender?: ApiUser | ApiChat;
botSender?: ApiUser; botSender?: ApiUser;
senderUserProfilePhoto?: ApiPhoto;
originSenderUserProfilePhoto?: ApiPhoto;
isThreadTop?: boolean; isThreadTop?: boolean;
shouldHideReply?: boolean; shouldHideReply?: boolean;
replyMessage?: ApiMessage; replyMessage?: ApiMessage;
@ -313,8 +309,6 @@ const Message: FC<OwnProps & StateProps> = ({
canShowSender, canShowSender,
originSender, originSender,
botSender, botSender,
senderUserProfilePhoto,
originSenderUserProfilePhoto,
isThreadTop, isThreadTop,
shouldHideReply, shouldHideReply,
replyMessage, replyMessage,
@ -487,7 +481,6 @@ const Message: FC<OwnProps & StateProps> = ({
const shouldPreferOriginSender = forwardInfo && (isChatWithSelf || isRepliesChat || !messageSender); const shouldPreferOriginSender = forwardInfo && (isChatWithSelf || isRepliesChat || !messageSender);
const avatarPeer = shouldPreferOriginSender ? originSender : messageSender; const avatarPeer = shouldPreferOriginSender ? originSender : messageSender;
const senderPeer = forwardInfo ? originSender : messageSender; const senderPeer = forwardInfo ? originSender : messageSender;
const avatarUserProfilePhoto = shouldPreferOriginSender ? originSenderUserProfilePhoto : senderUserProfilePhoto;
const { const {
handleMouseDown, handleMouseDown,
@ -790,7 +783,6 @@ const Message: FC<OwnProps & StateProps> = ({
user={avatarUser} user={avatarUser}
chat={avatarChat} chat={avatarChat}
text={hiddenName} text={hiddenName}
userProfilePhoto={avatarUserProfilePhoto}
lastSyncTime={lastSyncTime} lastSyncTime={lastSyncTime}
onClick={(avatarUser || avatarChat) ? handleAvatarClick : undefined} onClick={(avatarUser || avatarChat) ? handleAvatarClick : undefined}
observeIntersection={observeIntersectionForLoading} observeIntersection={observeIntersectionForLoading}
@ -1137,7 +1129,6 @@ const Message: FC<OwnProps & StateProps> = ({
isSelected={isSelected} isSelected={isSelected}
theme={theme} theme={theme}
peer={sender} peer={sender}
peerProfilePhoto={senderUserProfilePhoto}
/> />
)} )}
</div> </div>
@ -1373,10 +1364,6 @@ export default memo(withGlobal<OwnProps>(
const senderAdminMember = sender?.id && isGroup const senderAdminMember = sender?.id && isGroup
? chatFullInfo?.adminMembersById?.[sender?.id] ? chatFullInfo?.adminMembersById?.[sender?.id]
: undefined; : undefined;
const senderUserProfilePhoto = canShowSender && sender && isUserId(sender.id)
? selectUserPhotoFromFullInfo(global, sender.id) : undefined;
const originSenderUserProfilePhoto = originSender && isUserId(originSender.id)
? selectUserPhotoFromFullInfo(global, originSender.id) : undefined;
const threadTopMessageId = threadId ? selectThreadTopMessageId(global, chatId, threadId) : undefined; const threadTopMessageId = threadId ? selectThreadTopMessageId(global, chatId, threadId) : undefined;
const isThreadTop = message.id === threadTopMessageId; const isThreadTop = message.id === threadTopMessageId;
@ -1443,8 +1430,6 @@ export default memo(withGlobal<OwnProps>(
canShowSender, canShowSender,
originSender, originSender,
botSender, botSender,
senderUserProfilePhoto,
originSenderUserProfilePhoto,
shouldHideReply: shouldHideReply || isReplyToTopicStart, shouldHideReply: shouldHideReply || isReplyToTopicStart,
isThreadTop, isThreadTop,
replyMessage, replyMessage,

View File

@ -1,7 +1,7 @@
import React, { import React, {
memo, useCallback, useEffect, useRef, memo, useCallback, useEffect, useRef,
} from '../../../lib/teact/teact'; } from '../../../lib/teact/teact';
import { getActions, getGlobal } from '../../../global'; import { getActions } from '../../../global';
import type { FC } from '../../../lib/teact/teact'; import type { FC } from '../../../lib/teact/teact';
import type { import type {
@ -21,7 +21,6 @@ import { getMessageCopyOptions } from './helpers/copyOptions';
import { disableScrolling, enableScrolling } from '../../../util/scrollLock'; import { disableScrolling, enableScrolling } from '../../../util/scrollLock';
import { getUserFullName } from '../../../global/helpers'; import { getUserFullName } from '../../../global/helpers';
import buildClassName from '../../../util/buildClassName'; import buildClassName from '../../../util/buildClassName';
import { selectUserPhotoFromFullInfo } from '../../../global/selectors';
import renderText from '../../common/helpers/renderText'; import renderText from '../../common/helpers/renderText';
import useFlag from '../../../hooks/useFlag'; import useFlag from '../../../hooks/useFlag';
@ -406,7 +405,6 @@ const MessageContextMenu: FC<OwnProps> = ({
<Avatar <Avatar
size="micro" size="micro"
user={user} user={user}
userProfilePhoto={selectUserPhotoFromFullInfo(getGlobal(), user.id)}
/> />
))} ))}
</div> </div>

View File

@ -7,7 +7,7 @@ import React, {
useMemo, useMemo,
useRef, useRef,
} from '../../../lib/teact/teact'; } from '../../../lib/teact/teact';
import { getActions, getGlobal, withGlobal } from '../../../global'; import { getActions, withGlobal } from '../../../global';
import type { import type {
ApiMessage, ApiPoll, ApiUser, ApiPollAnswer, ApiMessage, ApiPoll, ApiUser, ApiPollAnswer,
@ -19,7 +19,6 @@ import { formatMediaDuration } from '../../../util/dateFormat';
import type { LangFn } from '../../../hooks/useLang'; import type { LangFn } from '../../../hooks/useLang';
import useLang from '../../../hooks/useLang'; import useLang from '../../../hooks/useLang';
import { getServerTimeOffset } from '../../../util/serverTime'; import { getServerTimeOffset } from '../../../util/serverTime';
import { selectUserPhotoFromFullInfo } from '../../../global/selectors';
import CheckboxGroup from '../../ui/CheckboxGroup'; import CheckboxGroup from '../../ui/CheckboxGroup';
import RadioGroup from '../../ui/RadioGroup'; import RadioGroup from '../../ui/RadioGroup';
@ -235,7 +234,6 @@ const Poll: FC<OwnProps & StateProps> = ({
key={user.id} key={user.id}
size="micro" size="micro"
user={user} user={user}
userProfilePhoto={selectUserPhotoFromFullInfo(getGlobal(), user.id)}
/> />
))} ))}
</div> </div>

View File

@ -11,7 +11,6 @@ import type { ActiveReaction } from '../../../global/types';
import buildClassName from '../../../util/buildClassName'; import buildClassName from '../../../util/buildClassName';
import { formatIntegerCompact } from '../../../util/textFormat'; import { formatIntegerCompact } from '../../../util/textFormat';
import { isSameReaction, isReactionChosen } from '../../../global/helpers'; import { isSameReaction, isReactionChosen } from '../../../global/helpers';
import { selectUserPhotoFromFullInfo } from '../../../global/selectors';
import Button from '../../ui/Button'; import Button from '../../ui/Button';
import Avatar from '../../common/Avatar'; import Avatar from '../../common/Avatar';
@ -81,7 +80,6 @@ const ReactionButton: FC<{
<Avatar <Avatar
key={user.id} key={user.id}
user={user} user={user}
userProfilePhoto={selectUserPhotoFromFullInfo(getGlobal(), user.id)}
size="micro" size="micro"
/> />
))} ))}

View File

@ -4,9 +4,7 @@ import React, {
import { getActions, getGlobal, withGlobal } from '../../global'; import { getActions, getGlobal, withGlobal } from '../../global';
import type { FC } from '../../lib/teact/teact'; import type { FC } from '../../lib/teact/teact';
import type { import type { ApiMessage, ApiUser, ApiChat } from '../../api/types';
ApiMessage, ApiUser, ApiChat, ApiPhoto,
} from '../../api/types';
import type { AnimationLevel } from '../../types'; import type { AnimationLevel } from '../../types';
import { MEMO_EMPTY_ARRAY } from '../../util/memo'; import { MEMO_EMPTY_ARRAY } from '../../util/memo';
@ -15,11 +13,8 @@ import {
selectChatMessages, selectChatMessages,
selectChat, selectChat,
selectCurrentTextSearch, selectCurrentTextSearch,
selectUserPhotoFromFullInfo,
} from '../../global/selectors'; } from '../../global/selectors';
import { import { isChatChannel } from '../../global/helpers';
isChatChannel,
} from '../../global/helpers';
import { disableDirectTextInput, enableDirectTextInput } from '../../util/directInputManager'; import { disableDirectTextInput, enableDirectTextInput } from '../../util/directInputManager';
import { renderMessageSummary } from '../common/helpers/renderMessageText'; import { renderMessageSummary } from '../common/helpers/renderMessageText';
import useLang from '../../hooks/useLang'; import useLang from '../../hooks/useLang';
@ -105,7 +100,6 @@ const RightSearch: FC<OwnProps & StateProps> = ({
} }
const senderUser = message.senderId ? selectUser(getGlobal(), message.senderId) : undefined; const senderUser = message.senderId ? selectUser(getGlobal(), message.senderId) : undefined;
const senderUserProfilePhoto = senderUser ? selectUserPhotoFromFullInfo(getGlobal(), senderUser.id) : undefined;
let senderChat; let senderChat;
if (chat && isChatChannel(chat)) { if (chat && isChatChannel(chat)) {
@ -120,7 +114,6 @@ const RightSearch: FC<OwnProps & StateProps> = ({
return { return {
message, message,
senderUser, senderUser,
senderUserProfilePhoto,
senderChat, senderChat,
onClick: () => focusMessage({ chatId, threadId, messageId: id }), onClick: () => focusMessage({ chatId, threadId, messageId: id }),
}; };
@ -135,12 +128,11 @@ const RightSearch: FC<OwnProps & StateProps> = ({
}, '.ListItem-button', true); }, '.ListItem-button', true);
const renderSearchResult = ({ const renderSearchResult = ({
message, senderUser, senderChat, senderUserProfilePhoto, onClick, message, senderUser, senderChat, onClick,
}: { }: {
message: ApiMessage; message: ApiMessage;
senderUser?: ApiUser; senderUser?: ApiUser;
senderChat?: ApiChat; senderChat?: ApiChat;
senderUserProfilePhoto?: ApiPhoto;
onClick: NoneToVoidFunction; onClick: NoneToVoidFunction;
}) => { }) => {
const text = renderMessageSummary(lang, message, undefined, query); const text = renderMessageSummary(lang, message, undefined, query);
@ -155,7 +147,6 @@ const RightSearch: FC<OwnProps & StateProps> = ({
<Avatar <Avatar
chat={senderChat} chat={senderChat}
user={senderUser} user={senderUser}
userProfilePhoto={senderUserProfilePhoto}
animationLevel={animationLevel} animationLevel={animationLevel}
withVideo withVideo
/> />

View File

@ -3,11 +3,11 @@ import React, { memo, useCallback } from '../../../lib/teact/teact';
import { getActions, withGlobal } from '../../../global'; import { getActions, withGlobal } from '../../../global';
import type { AnimationLevel } from '../../../types'; import type { AnimationLevel } from '../../../types';
import type { ApiPhoto, ApiUser } from '../../../api/types'; import type { ApiUser } from '../../../api/types';
import useLang from '../../../hooks/useLang'; import useLang from '../../../hooks/useLang';
import { getUserFullName } from '../../../global/helpers'; import { getUserFullName } from '../../../global/helpers';
import { selectUser, selectUserPhotoFromFullInfo } from '../../../global/selectors'; import { selectUser } from '../../../global/selectors';
import { formatHumanDate, formatTime, isToday } from '../../../util/dateFormat'; import { formatHumanDate, formatTime, isToday } from '../../../util/dateFormat';
import { getServerTime } from '../../../util/serverTime'; import { getServerTime } from '../../../util/serverTime';
import { createClassNameBuilder } from '../../../util/buildClassName'; import { createClassNameBuilder } from '../../../util/buildClassName';
@ -27,7 +27,6 @@ type OwnProps = {
type StateProps = { type StateProps = {
user?: ApiUser; user?: ApiUser;
userProfilePhoto?: ApiPhoto;
isSavedMessages?: boolean; isSavedMessages?: boolean;
animationLevel: AnimationLevel; animationLevel: AnimationLevel;
}; };
@ -39,7 +38,6 @@ const JoinRequest: FC<OwnProps & StateProps> = ({
date, date,
isChannel, isChannel,
user, user,
userProfilePhoto,
animationLevel, animationLevel,
}) => { }) => {
const { openChat, hideChatJoinRequest } = getActions(); const { openChat, hideChatJoinRequest } = getActions();
@ -73,7 +71,6 @@ const JoinRequest: FC<OwnProps & StateProps> = ({
key={userId} key={userId}
size="medium" size="medium"
user={user} user={user}
userProfilePhoto={userProfilePhoto}
animationLevel={animationLevel} animationLevel={animationLevel}
withVideo withVideo
/> />
@ -102,7 +99,6 @@ export default memo(withGlobal<OwnProps>(
return { return {
user, user,
userProfilePhoto: user ? selectUserPhotoFromFullInfo(global, userId) : undefined,
animationLevel: global.settings.byKey.animationLevel, animationLevel: global.settings.byKey.animationLevel,
}; };
}, },

View File

@ -16,7 +16,6 @@ import {
selectTabState, selectTabState,
selectUser, selectUser,
selectUserFullInfo, selectUserFullInfo,
selectUserPhotoFromFullInfo,
} from '../../../global/selectors'; } from '../../../global/selectors';
import { isUserBot, selectIsChatMuted } from '../../../global/helpers'; import { isUserBot, selectIsChatMuted } from '../../../global/helpers';
import useFlag from '../../../hooks/useFlag'; import useFlag from '../../../hooks/useFlag';
@ -43,7 +42,6 @@ type OwnProps = {
type StateProps = { type StateProps = {
user?: ApiUser; user?: ApiUser;
userProfilePhoto?: ApiPhoto;
progress?: ManagementProgress; progress?: ManagementProgress;
isMuted?: boolean; isMuted?: boolean;
personalPhoto?: ApiPhoto; personalPhoto?: ApiPhoto;
@ -55,7 +53,6 @@ const ERROR_FIRST_NAME_MISSING = 'Please provide first name';
const ManageUser: FC<OwnProps & StateProps> = ({ const ManageUser: FC<OwnProps & StateProps> = ({
userId, userId,
user, user,
userProfilePhoto,
progress, progress,
isMuted, isMuted,
onClose, onClose,
@ -233,7 +230,6 @@ const ManageUser: FC<OwnProps & StateProps> = ({
photo={notPersonalPhoto} photo={notPersonalPhoto}
noPersonalPhoto noPersonalPhoto
user={user} user={user}
userProfilePhoto={userProfilePhoto}
size="mini" size="mini"
className="personal-photo" className="personal-photo"
/> />
@ -298,10 +294,9 @@ export default memo(withGlobal<OwnProps>(
const isMuted = chat && selectIsChatMuted(chat, selectNotifySettings(global), selectNotifyExceptions(global)); const isMuted = chat && selectIsChatMuted(chat, selectNotifySettings(global), selectNotifyExceptions(global));
const personalPhoto = userFullInfo?.personalPhoto; const personalPhoto = userFullInfo?.personalPhoto;
const notPersonalPhoto = userFullInfo?.profilePhoto || userFullInfo?.fallbackPhoto; const notPersonalPhoto = userFullInfo?.profilePhoto || userFullInfo?.fallbackPhoto;
const userProfilePhoto = user ? selectUserPhotoFromFullInfo(global, user.id) : undefined;
return { return {
user, progress, isMuted, personalPhoto, notPersonalPhoto, userProfilePhoto, user, progress, isMuted, personalPhoto, notPersonalPhoto,
}; };
}, },
)(ManageUser)); )(ManageUser));

View File

@ -5,7 +5,6 @@ import type {
ApiChatAdminRights, ApiChatAdminRights,
ApiChatFolder, ApiChatFolder,
ApiTopic, ApiTopic,
ApiPhoto,
} from '../../api/types'; } from '../../api/types';
import { import {
MAIN_THREAD_ID, MAIN_THREAD_ID,
@ -21,7 +20,6 @@ import { orderBy } from '../../util/iteratees';
import { getUserFirstOrLastName } from './users'; import { getUserFirstOrLastName } from './users';
import { formatDateToString, formatTime } from '../../util/dateFormat'; import { formatDateToString, formatTime } from '../../util/dateFormat';
import { prepareSearchWordsForNeedle } from '../../util/searchWords'; import { prepareSearchWordsForNeedle } from '../../util/searchWords';
import { getVideoAvatarMediaHash } from './media';
const FOREVER_BANNED_DATE = Date.now() / 1000 + 31622400; // 366 days const FOREVER_BANNED_DATE = Date.now() / 1000 + 31622400; // 366 days
@ -109,18 +107,12 @@ export function getTopicLink(chatId: string, chatUsername?: string, topicId?: nu
export function getChatAvatarHash( export function getChatAvatarHash(
owner: ApiChat | ApiUser, owner: ApiChat | ApiUser,
size: 'normal' | 'big' = 'normal', size: 'normal' | 'big' = 'normal',
type: 'photo' | 'video' = 'photo',
avatarHash = owner.avatarHash, avatarHash = owner.avatarHash,
profilePhoto?: ApiPhoto,
) { ) {
if (!avatarHash) { if (!avatarHash) {
return undefined; return undefined;
} }
if (type === 'video') {
return profilePhoto?.isVideo ? getVideoAvatarMediaHash(profilePhoto) : undefined;
}
switch (size) { switch (size) {
case 'big': case 'big':
return `profile${owner.id}?${avatarHash}`; return `profile${owner.id}?${avatarHash}`;

View File

@ -16,12 +16,6 @@ export function selectUserFullInfo<T extends GlobalState>(global: T, userId: str
return global.users.fullInfoById[userId]; return global.users.fullInfoById[userId];
} }
export function selectUserPhotoFromFullInfo<T extends GlobalState>(global: T, userId: string) {
const fullInfo = selectUserFullInfo(global, userId);
return fullInfo?.personalPhoto || fullInfo?.profilePhoto || fullInfo?.fallbackPhoto;
}
export function selectIsUserBlocked<T extends GlobalState>(global: T, userId: string) { export function selectIsUserBlocked<T extends GlobalState>(global: T, userId: string) {
return selectUserFullInfo(global, userId)?.isBlocked; return selectUserFullInfo(global, userId)?.isBlocked;
} }
@ -36,14 +30,6 @@ export function selectIsPremiumPurchaseBlocked<T extends GlobalState>(global: T)
return global.appConfig?.isPremiumPurchaseBlocked ?? true; return global.appConfig?.isPremiumPurchaseBlocked ?? true;
} }
// Slow, not to be used in `withGlobal`
export function selectUserByUsername<T extends GlobalState>(global: T, username: string) {
const usernameLowered = username.toLowerCase();
return Object.values(global.users.byId).find(
(user) => user.usernames?.some((u) => u.username.toLowerCase() === usernameLowered),
);
}
// Slow, not to be used in `withGlobal` // Slow, not to be used in `withGlobal`
export function selectUserByPhoneNumber<T extends GlobalState>(global: T, phoneNumber: string) { export function selectUserByPhoneNumber<T extends GlobalState>(global: T, phoneNumber: string) {
const phoneNumberCleaned = phoneNumber.replace(/[^0-9]/g, ''); const phoneNumberCleaned = phoneNumber.replace(/[^0-9]/g, '');