Search: Fix offset avatars (#5362)

This commit is contained in:
zubiden 2024-12-29 11:59:08 +01:00 committed by Alexander Zinchuk
parent a46d03ad94
commit a9649de412
35 changed files with 147 additions and 142 deletions

View File

@ -1,12 +1,10 @@
.PickerSelectedItem {
.root {
display: flex;
align-items: center;
background: var(--color-chat-hover);
height: 2rem;
min-width: 2rem;
margin-bottom: 0.5rem;
margin-left: 0.25rem;
margin-right: 0.25rem;
margin-inline: 0.25rem;
padding-right: 1rem;
border-radius: 1rem;
cursor: var(--custom-cursor, pointer);
@ -28,48 +26,35 @@
&.closeable:hover {
background-color: rgba(var(--color-error-rgb), 0.16);
.item-remove {
.remove {
opacity: 1;
}
.Avatar,
.item-icon {
opacity: 0;
}
}
&.search-date {
.item-remove {
&.nonDestructive {
.remove {
background: var(--color-primary);
}
&:hover {
background: var(--color-chat-hover);
}
.item-name {
font-size: 0.875rem;
}
}
&.fluid {
max-width: unset;
}
.Avatar,
.item-icon {
.avatar,
.iconWrapper {
width: 2rem;
height: 2rem;
opacity: 1;
flex-shrink: 0;
transition: opacity 0.15s ease;
.icon {
font-size: 1rem;
}
}
.item-icon {
.iconWrapper {
display: flex;
align-items: center;
justify-content: center;
@ -85,13 +70,13 @@
}
}
.item-name {
.name {
margin-left: 0.5rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
.emoji.emoji-small {
:global(.emoji.emoji-small) {
width: 1.125rem;
height: 1.125rem;
background-size: 1.125rem;
@ -99,7 +84,7 @@
}
}
.item-remove {
.remove {
position: absolute;
left: 0;
top: 0;
@ -114,14 +99,15 @@
color: white;
opacity: 0;
transition: opacity 0.15s ease;
z-index: 1;
}
&.square-avatar {
&.squareAvatar {
border-start-start-radius: 0.625rem;
border-end-start-radius: 0.625rem;
--border-radius-forum-avatar: 0.625rem;
&.minimized, .item-remove {
&.minimized, .remove {
border-radius: 0.625rem;
}
}
@ -135,17 +121,12 @@
padding-left: 0;
}
.SearchInput & {
left: auto;
right: -0.125rem;
}
.item-name {
.name {
margin-left: 0;
margin-right: 0.5rem;
}
.item-remove {
.remove {
left: auto;
right: 0;
}

View File

@ -1,23 +1,24 @@
import type { TeactNode } from '../../../lib/teact/teact';
import React, { memo } from '../../../lib/teact/teact';
import { withGlobal } from '../../../global';
import type { TeactNode } from '../../lib/teact/teact';
import React, { memo } from '../../lib/teact/teact';
import { withGlobal } from '../../global';
import type { ApiPeer } from '../../../api/types';
import type { CustomPeer } from '../../../types';
import type { IconName } from '../../../types/icons';
import type { ApiPeer } from '../../api/types';
import type { CustomPeer } from '../../types';
import type { IconName } from '../../types/icons';
import { isApiPeerChat } from '../../../global/helpers/peers';
import { selectPeer, selectUser } from '../../../global/selectors';
import buildClassName from '../../../util/buildClassName';
import { getPeerColorClass } from '../helpers/peerColor';
import { getPeerTitle } from '../../global/helpers';
import { isApiPeerChat } from '../../global/helpers/peers';
import { selectPeer, selectUser } from '../../global/selectors';
import buildClassName from '../../util/buildClassName';
import { getPeerColorClass } from './helpers/peerColor';
import useOldLang from '../../../hooks/useOldLang';
import useOldLang from '../../hooks/useOldLang';
import Avatar from '../Avatar';
import FullNameTitle from '../FullNameTitle';
import Icon from '../icons/Icon';
import Avatar from './Avatar';
import FullNameTitle from './FullNameTitle';
import Icon from './icons/Icon';
import './PickerSelectedItem.scss';
import styles from './PeerChip.module.scss';
type OwnProps<T = undefined> = {
// eslint-disable-next-line react/no-unused-prop-types
@ -30,6 +31,7 @@ type OwnProps<T = undefined> = {
title?: string;
isMinimized?: boolean;
canClose?: boolean;
isCloseNonDestructive?: boolean;
className?: string;
fluid?: boolean;
withPeerColors?: boolean;
@ -43,11 +45,12 @@ type StateProps = {
};
// eslint-disable-next-line @typescript-eslint/comma-dangle
const PickerSelectedItem = <T,>({
const PeerChip = <T,>({
icon,
title,
isMinimized,
canClose,
isCloseNonDestructive,
clickArg,
peer,
mockPeer,
@ -66,36 +69,40 @@ const PickerSelectedItem = <T,>({
const chat = apiPeer && isApiPeerChat(apiPeer) ? apiPeer : undefined;
let iconElement: TeactNode | undefined;
let titleText: any;
let titleElement: TeactNode | undefined;
let titleText: string | undefined;
if (icon && title) {
iconElement = (
<div className="item-icon">
<Icon name={icon} />
<div className={styles.iconWrapper}>
<Icon name={icon} style={styles.icon} />
</div>
);
titleText = title;
titleElement = title;
} else if (anyPeer) {
iconElement = (
<Avatar
className={styles.avatar}
peer={anyPeer}
size="small"
isSavedMessages={isSavedMessages}
/>
);
titleText = title || <FullNameTitle peer={anyPeer} isSavedMessages={isSavedMessages} withEmojiStatus />;
titleText = getPeerTitle(lang, anyPeer) || title;
titleElement = title || <FullNameTitle peer={anyPeer} isSavedMessages={isSavedMessages} withEmojiStatus />;
}
const fullClassName = buildClassName(
'PickerSelectedItem',
className,
(chat?.isForum || customPeer?.isAvatarSquare) && 'square-avatar',
isMinimized && 'minimized',
canClose && 'closeable',
fluid && 'fluid',
styles.root,
(chat?.isForum || customPeer?.isAvatarSquare) && styles.squareAvatar,
isMinimized && styles.minimized,
canClose && styles.closeable,
isCloseNonDestructive && styles.nonDestructive,
fluid && styles.fluid,
withPeerColors && getPeerColorClass(customPeer || peer),
className,
);
return (
@ -107,12 +114,12 @@ const PickerSelectedItem = <T,>({
>
{iconElement}
{!isMinimized && (
<div className="item-name" dir="auto">
{titleText}
<div className={styles.name} dir="auto">
{titleElement}
</div>
)}
{canClose && (
<div className="item-remove">
<div className={styles.remove}>
<Icon name="close" />
</div>
)}
@ -135,4 +142,4 @@ export default memo(withGlobal<OwnProps>(
isSavedMessages,
};
},
)(PickerSelectedItem)) as typeof PickerSelectedItem;
)(PeerChip)) as typeof PeerChip;

View File

@ -14,7 +14,7 @@ import {
getMessageIsSpoiler,
getMessageMediaHash,
getMessageRoundVideo,
getSenderTitle,
getPeerTitle,
isActionMessage,
isChatChannel,
isChatGroup,
@ -120,10 +120,10 @@ const EmbeddedMessage: FC<OwnProps> = ({
const lang = useOldLang();
const senderTitle = sender ? getSenderTitle(lang, sender)
const senderTitle = sender ? getPeerTitle(lang, sender)
: (replyForwardInfo?.hiddenUserName || message?.forwardInfo?.hiddenUserName);
const senderChatTitle = senderChat ? getSenderTitle(lang, senderChat) : undefined;
const forwardSenderTitle = forwardSender ? getSenderTitle(lang, forwardSender)
const senderChatTitle = senderChat ? getPeerTitle(lang, senderChat) : undefined;
const forwardSenderTitle = forwardSender ? getPeerTitle(lang, forwardSender)
: message?.forwardInfo?.hiddenUserName;
const areSendersSame = sender && sender.id === forwardSender?.id;

View File

@ -6,7 +6,7 @@ import type { ApiPeer, ApiTypeStory } from '../../../api/types';
import type { ObserveFn } from '../../../hooks/useIntersectionObserver';
import {
getSenderTitle,
getPeerTitle,
getStoryMediaHash,
} from '../../../global/helpers';
import buildClassName from '../../../util/buildClassName';
@ -59,7 +59,7 @@ const EmbeddedStory: FC<OwnProps> = ({
const mediaThumbnail = isVideoStory ? story.content.video!.thumbnail?.dataUri : undefined;
const pictogramUrl = mediaBlobUrl || mediaThumbnail;
const senderTitle = sender ? getSenderTitle(lang, sender) : undefined;
const senderTitle = sender ? getPeerTitle(lang, sender) : undefined;
const handleFastClick = useLastCallback(() => {
if (story && !isExpiredStory) {
onClick();

View File

@ -10,7 +10,7 @@ import type {
import type { IconName } from '../../../types/icons';
import {
getSenderTitle,
getPeerTitle,
isUserId,
} from '../../../global/helpers';
import { selectPeer, selectPeerStory } from '../../../global/selectors';
@ -59,7 +59,7 @@ const EmbeddedStoryForward: FC<OwnProps & StateProps> = ({
}
}, [forwardInfo, story]);
const senderTitle = sender ? getSenderTitle(lang, sender) : forwardInfo.fromName;
const senderTitle = sender ? getPeerTitle(lang, sender) : forwardInfo.fromName;
const openOriginalStory = useLastCallback(() => {
const { fromPeerId, storyId } = forwardInfo;

View File

@ -26,8 +26,8 @@ import Radio from '../../ui/Radio';
import Avatar from '../Avatar';
import FullNameTitle from '../FullNameTitle';
import Icon from '../icons/Icon';
import PeerChip from '../PeerChip';
import PickerItem from './PickerItem';
import PickerSelectedItem from './PickerSelectedItem';
import styles from './PickerStyles.module.scss';
@ -335,7 +335,8 @@ const PeerPicker = ({
{isSearchable && (
<div className={buildClassName(styles.header, 'custom-scroll')} dir={lang.isRtl ? 'rtl' : undefined}>
{selectedCategories?.map((category) => (
<PickerSelectedItem
<PeerChip
className={styles.peerChip}
customPeer={categoriesByType[category]}
onClick={handleItemClick}
clickArg={category}
@ -343,7 +344,8 @@ const PeerPicker = ({
/>
))}
{lockedSelectedIds?.map((id, i) => (
<PickerSelectedItem
<PeerChip
className={styles.peerChip}
peerId={id}
isMinimized={shouldMinimize && i < selectedIds.length - ALWAYS_FULL_ITEMS_COUNT}
forceShowSelf={forceShowSelf}
@ -352,7 +354,8 @@ const PeerPicker = ({
/>
))}
{unlockedSelectedIds.map((id, i) => (
<PickerSelectedItem
<PeerChip
className={styles.peerChip}
peerId={id}
isMinimized={
shouldMinimize && i + (lockedSelectedIds?.length || 0) < selectedIds.length - ALWAYS_FULL_ITEMS_COUNT

View File

@ -43,6 +43,10 @@
}
}
.peerChip {
margin-bottom: 0.5rem;
}
.pickerList {
flex-grow: 1;
overflow-y: auto;

View File

@ -146,5 +146,10 @@
color: var(--color-text-secondary);
font-weight: var(--font-weight-medium);
padding-right: 0;
&[dir="rtl"] {
left: auto;
right: -0.125rem;
}
}
}

View File

@ -36,7 +36,7 @@ import useOldLang from '../../../hooks/useOldLang';
import { useFullscreenStatus } from '../../../hooks/window/useFullscreen';
import useLeftHeaderButtonRtlForumTransition from './hooks/useLeftHeaderButtonRtlForumTransition';
import PickerSelectedItem from '../../common/pickers/PickerSelectedItem';
import PeerChip from '../../common/PeerChip';
import StoryToggler from '../../story/StoryToggler';
import Button from '../../ui/Button';
import DropdownMenu from '../../ui/DropdownMenu';
@ -219,19 +219,20 @@ const LeftMainHeader: FC<OwnProps & StateProps> = ({
return (
<>
{selectedSearchDate && (
<PickerSelectedItem
<PeerChip
icon="calendar"
title={selectedSearchDate}
fluid
canClose
isMinimized={Boolean(globalSearchChatId)}
className="left-search-picker-item search-date"
className="left-search-picker-item"
onClick={setGlobalSearchDate}
isCloseNonDestructive
clickArg={CLEAR_DATE_SEARCH_PARAM}
/>
)}
{globalSearchChatId && (
<PickerSelectedItem
<PeerChip
className="left-search-picker-item"
peerId={globalSearchChatId}
onClick={setGlobalSearchChatId}

View File

@ -28,7 +28,7 @@ import useHorizontalScroll from '../../../hooks/useHorizontalScroll';
import useOldLang from '../../../hooks/useOldLang';
import NothingFound from '../../common/NothingFound';
import PickerSelectedItem from '../../common/pickers/PickerSelectedItem';
import PeerChip from '../../common/PeerChip';
import InfiniteScroll from '../../ui/InfiniteScroll';
import Link from '../../ui/Link';
import ChatMessage from './ChatMessage';
@ -266,8 +266,9 @@ const ChatResults: FC<OwnProps & StateProps> = ({
ref={chatSelectionRef}
>
{localResults.map((id) => (
<PickerSelectedItem
<PeerChip
peerId={id}
className="left-search-local-suggestion"
onClick={handlePickerItemClick}
clickArg={id}
/>

View File

@ -230,7 +230,8 @@
justify-content: space-between;
align-items: flex-end;
margin-bottom: 0.5rem;
padding-bottom: 0.5rem;
padding-inline: 0.25rem;
box-shadow: inset 0 -1px 0 0 var(--color-borders);
background-color: var(--color-background);
@ -238,7 +239,7 @@
overflow-x: auto;
overflow-y: hidden;
> .PickerSelectedItem {
.left-search-local-suggestion {
flex-shrink: 0;
}

View File

@ -3,7 +3,7 @@ import type { OldLangFn } from '../../../../hooks/useOldLang';
import {
getChatTitle,
getSenderTitle,
getPeerTitle,
isChatGroup,
isUserId,
} from '../../../../global/helpers';
@ -18,7 +18,7 @@ export function getSenderName(
const sender = isUserId(senderId) ? usersById[senderId] : chatsById[senderId];
let senderName = getSenderTitle(lang, sender);
let senderName = getPeerTitle(lang, sender);
const chat = chatsById[message.chatId];
if (chat) {

View File

@ -6,7 +6,7 @@ import type { ApiChat, ApiPeer } from '../../api/types';
import type { MediaViewerItem } from './helpers/getViewableMedia';
import {
getSenderTitle, isChatChannel, isChatGroup, isUserId,
getPeerTitle, isChatChannel, isChatGroup, isUserId,
} from '../../global/helpers';
import {
selectSender,
@ -107,7 +107,7 @@ const SenderInfo: FC<OwnProps & StateProps> = ({
return undefined;
}
const senderTitle = getSenderTitle(lang, owner);
const senderTitle = getPeerTitle(lang, owner);
return (
<div className="SenderInfo" onClick={handleFocusMessage}>

View File

@ -61,7 +61,6 @@
.peer {
background-color: var(--accent-background-color);
color: var(--accent-color);
margin: unset;
&:hover, &:active, &:focus {
background-color: var(--accent-background-active-color);

View File

@ -30,7 +30,7 @@ import useOldLang from '../../../hooks/useOldLang';
import AnimatedIconFromSticker from '../../common/AnimatedIconFromSticker';
import AnimatedIconWithPreview from '../../common/AnimatedIconWithPreview';
import PickerSelectedItem from '../../common/pickers/PickerSelectedItem';
import PeerChip from '../../common/PeerChip';
import Button from '../../ui/Button';
import ConfirmDialog from '../../ui/ConfirmDialog';
import Separator from '../../ui/Separator';
@ -160,7 +160,7 @@ const Giveaway = ({
</p>
<div className={styles.peers}>
{channelIds.map((peerId) => (
<PickerSelectedItem
<PeerChip
peerId={peerId}
forceShowSelf
fluid
@ -203,7 +203,7 @@ const Giveaway = ({
</strong>
<div className={styles.peers}>
{winnerIds.map((peerId) => (
<PickerSelectedItem
<PeerChip
peerId={peerId}
forceShowSelf
fluid

View File

@ -54,7 +54,7 @@ import {
getMessageHtmlId,
getMessageSingleCustomEmoji,
getMessageSingleRegularEmoji,
getSenderTitle,
getPeerTitle,
hasMessageText,
hasMessageTtl,
isAnonymousForwardsChat,
@ -844,7 +844,7 @@ const Message: FC<OwnProps & StateProps> = ({
scrollTargetPosition,
);
const viaBusinessBotTitle = viaBusinessBot ? getSenderTitle(lang, viaBusinessBot) : undefined;
const viaBusinessBotTitle = viaBusinessBot ? getPeerTitle(lang, viaBusinessBot) : undefined;
const canShowPostAuthor = !message.senderId;
const signature = viaBusinessBotTitle || (canShowPostAuthor && message.postAuthorTitle)
@ -1500,11 +1500,11 @@ const Message: FC<OwnProps & StateProps> = ({
let senderTitle;
let senderColor;
if (senderPeer && !(isCustomShape && viaBotId)) {
senderTitle = getSenderTitle(lang, senderPeer);
senderTitle = getPeerTitle(lang, senderPeer);
} else if (forwardInfo?.hiddenUserName) {
senderTitle = forwardInfo.hiddenUserName;
} else if (storyData && originSender) {
senderTitle = getSenderTitle(lang, originSender!);
senderTitle = getPeerTitle(lang, originSender!);
}
const senderEmojiStatus = senderPeer && 'emojiStatus' in senderPeer && senderPeer.emojiStatus;
const senderIsPremium = senderPeer && 'isPremium' in senderPeer && senderPeer.isPremium;

View File

@ -5,7 +5,7 @@ import type {
ApiMessage, ApiPeer, ApiTypeStory, ApiUser,
} from '../../../api/types';
import { getSenderTitle, getStoryMediaHash, getUserFirstOrLastName } from '../../../global/helpers';
import { getPeerTitle, getStoryMediaHash, getUserFirstOrLastName } from '../../../global/helpers';
import {
selectPeer,
selectPeerStories,
@ -69,7 +69,7 @@ function StoryMention({
return isDeleted
? lang('ExpiredStoryMention')
: lang('StoryMentionedTitle', getSenderTitle(lang, peer!));
: lang('StoryMentionedTitle', getPeerTitle(lang, peer!));
}
return (

View File

@ -9,7 +9,7 @@ import type {
import { PLAYBACK_RATE_FOR_AUDIO_MIN_DURATION } from '../../../config';
import {
getMediaDuration, getMessageContent, getMessageMediaHash, getSenderTitle, isMessageLocal,
getMediaDuration, getMessageContent, getMessageMediaHash, getPeerTitle, isMessageLocal,
} from '../../../global/helpers';
import {
selectChat, selectChatMessage, selectSender, selectTabState,
@ -98,7 +98,7 @@ const AudioPlayer: FC<OwnProps & StateProps> = ({
const { audio, voice, video } = renderingMessage ? getMessageContent(renderingMessage) : {} satisfies MediaContent;
const isVoice = Boolean(voice || video);
const shouldRenderPlaybackButton = isVoice || (audio?.duration || 0) > PLAYBACK_RATE_FOR_AUDIO_MIN_DURATION;
const senderName = sender ? getSenderTitle(lang, sender) : undefined;
const senderName = sender ? getPeerTitle(lang, sender) : undefined;
const mediaHash = renderingMessage && getMessageMediaHash(renderingMessage, 'inline');
const mediaData = mediaHash && mediaLoader.getFromMemory(mediaHash);

View File

@ -12,7 +12,7 @@ import {
getMessageMediaHash,
getMessageSingleInlineButton,
getMessageVideo,
getSenderTitle,
getPeerTitle,
} from '../../../global/helpers';
import {
selectAllowedMessageActionsSlow,
@ -110,7 +110,7 @@ const HeaderPinnedMessage = ({
? pinnedMessageIds.length : (pinnedMessageIds ? 1 : 0);
const pinnedMessageNumber = Math.max(pinnedMessagesCount - currentPinnedIndex, 1);
const topMessageTitle = topMessageSender ? getSenderTitle(lang, topMessageSender) : undefined;
const topMessageTitle = topMessageSender ? getPeerTitle(lang, topMessageSender) : undefined;
const video = pinnedMessage && getMessageVideo(pinnedMessage);
const gif = video?.isGif ? video : undefined;

View File

@ -51,7 +51,7 @@ import useOldLang from '../../../hooks/useOldLang';
import Avatar from '../../common/Avatar';
import Icon from '../../common/icons/Icon';
import PickerSelectedItem from '../../common/pickers/PickerSelectedItem';
import PeerChip from '../../common/PeerChip';
import Button from '../../ui/Button';
import InfiniteScroll from '../../ui/InfiniteScroll';
import SearchInput from '../../ui/SearchInput';
@ -519,7 +519,7 @@ const MiddleSearch: FC<StateProps> = ({
switch (type) {
case 'chat':
return (
<PickerSelectedItem
<PeerChip
className={buildClassName(styles.searchType, isSelected && styles.selectedType)}
fluid
peerId={chat?.id}
@ -530,7 +530,7 @@ const MiddleSearch: FC<StateProps> = ({
);
case 'myChats':
return (
<PickerSelectedItem
<PeerChip
className={buildClassName(styles.searchType, isSelected && styles.selectedType)}
fluid
peerId={currentUserId}
@ -542,7 +542,7 @@ const MiddleSearch: FC<StateProps> = ({
);
case 'channels':
return (
<PickerSelectedItem
<PeerChip
className={buildClassName(styles.searchType, isSelected && styles.selectedType)}
fluid
customPeer={CHANNELS_PEER}

View File

@ -21,7 +21,7 @@ import useOldLang from '../../../hooks/useOldLang';
import AnimatedIconWithPreview from '../../common/AnimatedIconWithPreview';
import Icon from '../../common/icons/Icon';
import PickerSelectedItem from '../../common/pickers/PickerSelectedItem';
import PeerChip from '../../common/PeerChip';
import Button from '../../ui/Button';
import Modal from '../../ui/Modal';
@ -123,7 +123,7 @@ const CollectibleInfoModal: FC<OwnProps & StateProps> = ({
<h3 className={styles.title}>
{title && renderText(title, ['simple_markdown'])}
</h3>
<PickerSelectedItem
<PeerChip
fluid
className={styles.chip}
peerId={modal?.peerId}

View File

@ -52,7 +52,6 @@
}
.chatItem {
margin: 0;
width: fit-content;
background-color: var(--color-background);
color: var(--color-primary);

View File

@ -9,7 +9,7 @@ import buildClassName from '../../../util/buildClassName';
import useLastCallback from '../../../hooks/useLastCallback';
import Avatar from '../../common/Avatar';
import PickerSelectedItem from '../../common/pickers/PickerSelectedItem';
import PeerChip from '../../common/PeerChip';
import Button from '../../ui/Button';
import Modal from '../../ui/Modal';
@ -71,7 +71,7 @@ const TableInfoModal = ({
{label && <div className={buildClassName(styles.cell, styles.title)}>{label}</div>}
<div className={buildClassName(styles.cell, styles.value, !label && styles.fullWidth)}>
{typeof value === 'object' && 'chatId' in value ? (
<PickerSelectedItem
<PeerChip
peerId={value.chatId}
className={styles.chatItem}
forceShowSelf

View File

@ -24,7 +24,7 @@ import usePrevious from '../../../hooks/usePrevious';
import Avatar from '../../common/Avatar';
import StarIcon from '../../common/icons/StarIcon';
import PeerBadge from '../../common/PeerBadge';
import PickerSelectedItem from '../../common/pickers/PickerSelectedItem';
import PeerChip from '../../common/PeerChip';
import SafeLink from '../../common/SafeLink';
import Button from '../../ui/Button';
import Modal from '../../ui/Modal';
@ -194,7 +194,7 @@ const StarPaymentModal = ({
<h2 className={styles.headerText}>
{inviteCustomPeer ? oldLang('StarsSubscribeTitle') : oldLang('StarsConfirmPurchaseTitle')}
</h2>
{canShowPeerItem && <PickerSelectedItem className={styles.botItem} peerId={form?.botId} />}
{canShowPeerItem && <PeerChip className={styles.botItem} peerId={form?.botId} />}
<div className={styles.description}>
{renderText(descriptionText, ['simple_markdown', 'emoji'])}
</div>

View File

@ -10,7 +10,7 @@ import type {
} from '../../../../api/types';
import type { TabState } from '../../../../global/types';
import { getSenderTitle } from '../../../../global/helpers';
import { getPeerTitle } from '../../../../global/helpers';
import {
selectUser,
} from '../../../../global/selectors';
@ -194,7 +194,7 @@ const StarsGiftModal: FC<OwnProps & StateProps> = ({
</h2>
<p className={styles.description}>
{user ? renderText(
oldLang('ActionGiftStarsSubtitle', getSenderTitle(oldLang, user)), ['simple_markdown'],
oldLang('ActionGiftStarsSubtitle', getPeerTitle(oldLang, user)), ['simple_markdown'],
) : oldLang('Stars.Purchase.GetStarsInfo')}
</p>
<div className={styles.section}>

View File

@ -6,7 +6,7 @@ import type {
} from '../../../../api/types';
import type { GlobalState } from '../../../../global/types';
import { getSenderTitle } from '../../../../global/helpers';
import { getPeerTitle } from '../../../../global/helpers';
import { selectPeer } from '../../../../global/selectors';
import { formatDateToString } from '../../../../util/dates/dateFormat';
import { formatInteger } from '../../../../util/textFormat';
@ -56,7 +56,7 @@ const StarsSubscriptionItem = ({ subscription }: OwnProps) => {
<StarIcon className={styles.subscriptionStar} type="gold" size="small" />
</div>
<div className={styles.info}>
<h3 className={styles.title}>{getSenderTitle(lang, peer)}</h3>
<h3 className={styles.title}>{getPeerTitle(lang, peer)}</h3>
{title && (
<p className={styles.subtitle}>
{photo && <Avatar webPhoto={photo} size="micro" />}

View File

@ -8,7 +8,7 @@ import type {
import type { GlobalState } from '../../../../global/types';
import type { CustomPeer } from '../../../../types';
import { getSenderTitle } from '../../../../global/helpers';
import { getPeerTitle } from '../../../../global/helpers';
import { buildStarsTransactionCustomPeer, formatStarsTransactionAmount } from '../../../../global/helpers/payments';
import { selectPeer } from '../../../../global/selectors';
import buildClassName from '../../../../util/buildClassName';
@ -62,7 +62,7 @@ const StarsTransactionItem = ({ transaction, className }: OwnProps) => {
let avatarPeer: ApiPeer | CustomPeer | undefined;
if (transaction.peer.type === 'peer') {
description = peer && getSenderTitle(oldLang, peer);
description = peer && getPeerTitle(oldLang, peer);
avatarPeer = peer || CUSTOM_PEER_PREMIUM;
} else {
const customPeer = buildStarsTransactionCustomPeer(transaction.peer);

View File

@ -15,7 +15,7 @@ import useLang from '../../../hooks/useLang';
import useLastCallback from '../../../hooks/useLastCallback';
import CustomEmoji from '../../common/CustomEmoji';
import PickerSelectedItem from '../../common/pickers/PickerSelectedItem';
import PeerChip from '../../common/PeerChip';
import Button from '../../ui/Button';
import Modal from '../../ui/Modal';
@ -121,7 +121,7 @@ const SuggestedStatusModal = ({ modal, currentUser, bot }: OwnProps & StateProps
<p className={styles.description}>{description}</p>
</div>
{mockPeerWithStatus && (
<PickerSelectedItem
<PeerChip
mockPeer={mockPeerWithStatus}
/>
)}

View File

@ -14,7 +14,7 @@ import type { Signal } from '../../util/signals';
import { MAIN_THREAD_ID } from '../../api/types';
import { EDITABLE_STORY_INPUT_CSS_SELECTOR, EDITABLE_STORY_INPUT_ID } from '../../config';
import { getSenderTitle, isChatChannel, isUserId } from '../../global/helpers';
import { getPeerTitle, isChatChannel, isUserId } from '../../global/helpers';
import {
selectChat,
selectIsCurrentUserPremium,
@ -199,7 +199,7 @@ function Story({
isOut && (story!.date + viewersExpirePeriod) < getServerTime(),
);
const forwardSenderTitle = forwardSender ? getSenderTitle(lang, forwardSender)
const forwardSenderTitle = forwardSender ? getPeerTitle(lang, forwardSender)
: (isLoadedStory && story.forwardInfo?.fromName);
const canCopyLink = Boolean(
@ -492,7 +492,7 @@ function Story({
: story.isForContacts ? 'contacts' : (story.isForCloseFriends ? 'closeFriends' : 'nobody');
let message;
const myName = getSenderTitle(lang, peer);
const myName = getPeerTitle(lang, peer);
switch (visibility) {
case 'nobody':
message = lang('StorySelectedContactsHint', myName);
@ -643,7 +643,7 @@ function Story({
/>
<div className={styles.senderMeta}>
<span onClick={handleOpenChat} className={styles.senderName}>
{renderText(getSenderTitle(lang, peer) || '')}
{renderText(getPeerTitle(lang, peer) || '')}
</span>
<div className={styles.storyMetaRow}>
{forwardSenderTitle && (
@ -668,7 +668,7 @@ function Story({
>
<Avatar peer={fromPeer} size="micro" />
<span className={styles.headerTitle}>
{renderText(getSenderTitle(lang, fromPeer) || '')}
{renderText(getPeerTitle(lang, fromPeer) || '')}
</span>
</span>
)}
@ -853,7 +853,7 @@ function Story({
withStory
storyViewerMode="disabled"
/>
<div className={styles.name}>{renderText(getSenderTitle(lang, peer) || '')}</div>
<div className={styles.name}>{renderText(getPeerTitle(lang, peer) || '')}</div>
</div>
</div>
)}

View File

@ -6,7 +6,7 @@ import type {
} from '../../api/types';
import type { StoryViewerOrigin } from '../../types';
import { getSenderTitle, getStoryMediaHash } from '../../global/helpers';
import { getPeerTitle, getStoryMediaHash } from '../../global/helpers';
import { selectTabState } from '../../global/selectors';
import renderText from '../common/helpers/renderText';
@ -86,7 +86,7 @@ function StoryPreview({
withStory
storyViewerMode="disabled"
/>
<div className={styles.name}>{renderText(getSenderTitle(lang, peer) || '')}</div>
<div className={styles.name}>{renderText(getPeerTitle(lang, peer) || '')}</div>
</div>
</div>
</div>

View File

@ -4,7 +4,7 @@ import { getActions } from '../../global';
import type { ApiPeer } from '../../api/types';
import { StoryViewerOrigin } from '../../types';
import { getSenderTitle, isUserId } from '../../global/helpers';
import { getPeerTitle, isUserId } from '../../global/helpers';
import buildClassName from '../../util/buildClassName';
import { preventMessageInputBlurWithBubbling } from '../middle/helpers/preventMessageInputBlur';
@ -101,7 +101,7 @@ function StoryRibbonButton({ peer, isArchived }: OwnProps) {
storyViewerMode="full"
/>
<div className={buildClassName(styles.name, peer.hasUnreadStories && styles.name_hasUnreadStory)}>
{isSelf ? lang('MyStory') : getSenderTitle(lang, peer)}
{isSelf ? lang('MyStory') : getPeerTitle(lang, peer)}
</div>
{contextMenuAnchor !== undefined && (
<Menu

View File

@ -8,7 +8,7 @@ import type {
} from '../../api/types';
import type { IconName } from '../../types/icons';
import { getSenderTitle, getUserFullName } from '../../global/helpers';
import { getPeerTitle, getUserFullName } from '../../global/helpers';
import { selectPeerStory, selectTabState } from '../../global/selectors';
import buildClassName from '../../util/buildClassName';
import stopEvent from '../../util/stopEvent';
@ -209,7 +209,7 @@ function StorySettings({
}
if (closeFriendIds.length === 1) {
return getSenderTitle(lang, usersById[closeFriendIds[0]]);
return getPeerTitle(lang, usersById[closeFriendIds[0]]);
}
return lang('StoryPrivacyOptionPeople', closeFriendIds.length, 'i');

View File

@ -29,7 +29,7 @@ import {
getMediaHash,
getMessageDownloadableMedia,
getMessageStatefulContent,
getSenderTitle,
getPeerTitle,
isChatChannel,
isJoinedChannelMessage,
} from '../../helpers';
@ -1022,7 +1022,7 @@ function copyTextForMessages(global: GlobalState, chatId: string, messageIds: nu
messages.forEach((message) => {
const sender = isChatChannel(chat) ? chat : selectSender(global, message);
const senderTitle = `> ${sender ? getSenderTitle(lang, sender) : message.forwardInfo?.hiddenUserName || ''}:`;
const senderTitle = `> ${sender ? getPeerTitle(lang, sender) : message.forwardInfo?.hiddenUserName || ''}:`;
const statefulContent = getMessageStatefulContent(global, message);
resultHtml.push(senderTitle);

View File

@ -10,7 +10,7 @@ import type {
ApiPoll, MediaContainer, MediaContent, StatefulMediaContent,
} from '../../api/types/messages';
import type { OldLangFn } from '../../hooks/useOldLang';
import type { ThreadId } from '../../types';
import type { CustomPeer, ThreadId } from '../../types';
import type { LangFn } from '../../util/localization';
import type { GlobalState } from '../types';
import { ApiMessageEntityTypes, MAIN_THREAD_ID } from '../../api/types';
@ -209,8 +209,12 @@ export function isAnonymousOwnMessage(message: ApiMessage) {
return Boolean(message.senderId) && !isUserId(message.senderId) && isOwnMessage(message);
}
export function getSenderTitle(lang: OldLangFn | LangFn, sender: ApiPeer) {
return isPeerUser(sender) ? getUserFullName(sender) : getChatTitle(lang, sender);
export function getPeerTitle(lang: OldLangFn | LangFn, peer: ApiPeer | CustomPeer) {
if ('isCustomPeer' in peer) {
// TODO: Remove any after full migration to new lang
return peer.titleKey ? lang(peer.titleKey as any) : peer.title;
}
return isPeerUser(peer) ? getUserFullName(peer) : getChatTitle(lang, peer);
}
export function getSendingState(message: ApiMessage) {

View File

@ -6,7 +6,7 @@ import type {
} from '../api/types';
import {
getAudioHasCover, getChatAvatarHash, getChatTitle, getMediaHash, getMessageContent, getSenderTitle,
getAudioHasCover, getChatAvatarHash, getChatTitle, getMediaHash, getMessageContent, getPeerTitle,
} from '../global/helpers';
import { resizeImage, scaleImage } from '../util/imageResize';
import { buildMediaMetadata } from '../util/mediaSession';
@ -28,7 +28,7 @@ const useMessageMediaMetadata = (
const { audio, voice } = message ? getMessageContent(message) : {} satisfies MediaContent;
const title = audio ? (audio.title || audio.fileName) : voice ? 'Voice message' : '';
const artist = audio?.performer || (sender && getSenderTitle(lang, sender));
const artist = audio?.performer || (sender && getPeerTitle(lang, sender));
const album = (chat && getChatTitle(lang, chat)) || 'Telegram';
const audioCoverHash = (audio && getAudioHasCover(audio) && getMediaHash(audio, 'pictogram'));