Composer Embedded Message: Support multi senders title in forward (#5898)
This commit is contained in:
parent
a8ab4942d0
commit
5c2e5dfcb4
@ -1953,4 +1953,5 @@
|
|||||||
"ApiMessageActionPaidMessagesRefundedIncoming" = "{user} refunded **{stars}** to you";
|
"ApiMessageActionPaidMessagesRefundedIncoming" = "{user} refunded **{stars}** to you";
|
||||||
"NotificationTitleNotSupportedInFrozenAccount" = "Your account is frozen";
|
"NotificationTitleNotSupportedInFrozenAccount" = "Your account is frozen";
|
||||||
"NotificationMessageNotSupportedInFrozenAccount" = "This action is not available";
|
"NotificationMessageNotSupportedInFrozenAccount" = "This action is not available";
|
||||||
|
"ComposerTitleForwardFrom" = "From: **{users}**";
|
||||||
"ContextMenuItemMention" = "Mention";
|
"ContextMenuItemMention" = "Mention";
|
||||||
|
|||||||
@ -233,4 +233,10 @@
|
|||||||
color: var(--accent-color);
|
color: var(--accent-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.is-input-forward {
|
||||||
|
.message-title {
|
||||||
|
font-weight: var(--font-weight-normal);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,6 +29,7 @@ import { renderTextWithEntities } from '../helpers/renderTextWithEntities';
|
|||||||
|
|
||||||
import { useFastClick } from '../../../hooks/useFastClick';
|
import { useFastClick } from '../../../hooks/useFastClick';
|
||||||
import { useIsIntersecting } from '../../../hooks/useIntersectionObserver';
|
import { useIsIntersecting } from '../../../hooks/useIntersectionObserver';
|
||||||
|
import useLang from '../../../hooks/useLang';
|
||||||
import useMedia from '../../../hooks/useMedia';
|
import useMedia from '../../../hooks/useMedia';
|
||||||
import useOldLang from '../../../hooks/useOldLang';
|
import useOldLang from '../../../hooks/useOldLang';
|
||||||
import useThumbnail from '../../../hooks/useThumbnail';
|
import useThumbnail from '../../../hooks/useThumbnail';
|
||||||
@ -49,6 +50,7 @@ type OwnProps = {
|
|||||||
sender?: ApiPeer;
|
sender?: ApiPeer;
|
||||||
senderChat?: ApiChat;
|
senderChat?: ApiChat;
|
||||||
forwardSender?: ApiPeer;
|
forwardSender?: ApiPeer;
|
||||||
|
composerForwardSenders?: ApiPeer[];
|
||||||
title?: string;
|
title?: string;
|
||||||
customText?: string;
|
customText?: string;
|
||||||
noUserColors?: boolean;
|
noUserColors?: boolean;
|
||||||
@ -72,6 +74,7 @@ const EmbeddedMessage: FC<OwnProps> = ({
|
|||||||
sender,
|
sender,
|
||||||
senderChat,
|
senderChat,
|
||||||
forwardSender,
|
forwardSender,
|
||||||
|
composerForwardSenders,
|
||||||
title,
|
title,
|
||||||
customText,
|
customText,
|
||||||
isProtected,
|
isProtected,
|
||||||
@ -115,12 +118,21 @@ const EmbeddedMessage: FC<OwnProps> = ({
|
|||||||
chatTranslations, message?.chatId, shouldTranslate ? message?.id : undefined, requestedChatTranslationLanguage,
|
chatTranslations, message?.chatId, shouldTranslate ? message?.id : undefined, requestedChatTranslationLanguage,
|
||||||
);
|
);
|
||||||
|
|
||||||
const lang = useOldLang();
|
const oldLang = useOldLang();
|
||||||
|
const lang = useLang();
|
||||||
|
|
||||||
const senderTitle = sender ? getPeerTitle(lang, sender)
|
const senderTitle = sender ? getPeerTitle(oldLang, sender)
|
||||||
: (replyForwardInfo?.hiddenUserName || message?.forwardInfo?.hiddenUserName);
|
: (replyForwardInfo?.hiddenUserName || message?.forwardInfo?.hiddenUserName);
|
||||||
const senderChatTitle = senderChat ? getPeerTitle(lang, senderChat) : undefined;
|
|
||||||
const forwardSenderTitle = forwardSender ? getPeerTitle(lang, forwardSender)
|
const forwardSendersTitle = useMemo(() => {
|
||||||
|
if (!composerForwardSenders) return undefined;
|
||||||
|
|
||||||
|
const peerTitles = composerForwardSenders.map((peer) => getPeerTitle(lang, peer)).filter(Boolean);
|
||||||
|
return lang.conjunction(peerTitles);
|
||||||
|
}, [composerForwardSenders, lang]);
|
||||||
|
|
||||||
|
const senderChatTitle = senderChat ? getPeerTitle(oldLang, senderChat) : undefined;
|
||||||
|
const forwardSenderTitle = forwardSender ? getPeerTitle(oldLang, forwardSender)
|
||||||
: message?.forwardInfo?.hiddenUserName;
|
: message?.forwardInfo?.hiddenUserName;
|
||||||
const areSendersSame = sender && sender.id === forwardSender?.id;
|
const areSendersSame = sender && sender.id === forwardSender?.id;
|
||||||
|
|
||||||
@ -154,7 +166,7 @@ const EmbeddedMessage: FC<OwnProps> = ({
|
|||||||
|
|
||||||
function renderMediaContentType(media?: MediaContainer) {
|
function renderMediaContentType(media?: MediaContainer) {
|
||||||
if (!media || media.content.text) return NBSP;
|
if (!media || media.content.text) return NBSP;
|
||||||
const description = getMediaContentTypeDescription(lang, media.content, {});
|
const description = getMediaContentTypeDescription(oldLang, media.content, {});
|
||||||
if (!description || description === CONTENT_NOT_SUPPORTED) return NBSP;
|
if (!description || description === CONTENT_NOT_SUPPORTED) return NBSP;
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
@ -174,7 +186,7 @@ const EmbeddedMessage: FC<OwnProps> = ({
|
|||||||
return renderText(title);
|
return renderText(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!senderTitle) {
|
if (!senderTitle && !forwardSendersTitle) {
|
||||||
return NBSP;
|
return NBSP;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,7 +207,14 @@ const EmbeddedMessage: FC<OwnProps> = ({
|
|||||||
<span className="embedded-sender-wrapper">
|
<span className="embedded-sender-wrapper">
|
||||||
{checkShouldRenderSenderTitle() && (
|
{checkShouldRenderSenderTitle() && (
|
||||||
<span className="embedded-sender">
|
<span className="embedded-sender">
|
||||||
{renderText(isReplyToQuote ? lang('ReplyToQuote', senderTitle) : senderTitle)}
|
{!composerForwardSenders && senderTitle
|
||||||
|
&& renderText(isReplyToQuote ? oldLang('ReplyToQuote', senderTitle) : senderTitle)}
|
||||||
|
{forwardSendersTitle && renderText(lang('ComposerTitleForwardFrom', {
|
||||||
|
users: forwardSendersTitle,
|
||||||
|
}, {
|
||||||
|
withNodes: true,
|
||||||
|
withMarkdown: true,
|
||||||
|
}))}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{icon && <Icon name={icon} className="embedded-chat-icon" />}
|
{icon && <Icon name={icon} className="embedded-chat-icon" />}
|
||||||
@ -232,6 +251,7 @@ const EmbeddedMessage: FC<OwnProps> = ({
|
|||||||
isQuote && 'is-quote',
|
isQuote && 'is-quote',
|
||||||
mediaThumbnail && 'with-thumb',
|
mediaThumbnail && 'with-thumb',
|
||||||
'no-selection',
|
'no-selection',
|
||||||
|
composerForwardSenders && 'is-input-forward',
|
||||||
)}
|
)}
|
||||||
dir={lang.isRtl ? 'rtl' : undefined}
|
dir={lang.isRtl ? 'rtl' : undefined}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
|
|||||||
@ -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, withGlobal } from '../../../global';
|
import { getActions, getGlobal, withGlobal } from '../../../global';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ApiChat, ApiInputMessageReplyInfo, ApiMessage, ApiPeer,
|
ApiChat, ApiInputMessageReplyInfo, ApiMessage, ApiPeer,
|
||||||
@ -21,12 +21,12 @@ import {
|
|||||||
selectForwardedSender,
|
selectForwardedSender,
|
||||||
selectIsChatWithSelf,
|
selectIsChatWithSelf,
|
||||||
selectIsCurrentUserPremium,
|
selectIsCurrentUserPremium,
|
||||||
selectPeer,
|
|
||||||
selectSender,
|
selectSender,
|
||||||
selectTabState,
|
selectTabState,
|
||||||
} from '../../../global/selectors';
|
} from '../../../global/selectors';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import captureEscKeyListener from '../../../util/captureEscKeyListener';
|
import captureEscKeyListener from '../../../util/captureEscKeyListener';
|
||||||
|
import { unique } from '../../../util/iteratees';
|
||||||
import { getPeerColorClass } from '../../common/helpers/peerColor';
|
import { getPeerColorClass } from '../../common/helpers/peerColor';
|
||||||
|
|
||||||
import useContextMenuHandlers from '../../../hooks/useContextMenuHandlers';
|
import useContextMenuHandlers from '../../../hooks/useContextMenuHandlers';
|
||||||
@ -63,6 +63,8 @@ type StateProps = {
|
|||||||
senderChat?: ApiChat;
|
senderChat?: ApiChat;
|
||||||
isSenderChannel?: boolean;
|
isSenderChannel?: boolean;
|
||||||
currentUserId?: string;
|
currentUserId?: string;
|
||||||
|
forwardMessageIds?: number[];
|
||||||
|
fromChatId?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
@ -96,6 +98,8 @@ const ComposerEmbeddedMessage: FC<OwnProps & StateProps> = ({
|
|||||||
chatId,
|
chatId,
|
||||||
currentUserId,
|
currentUserId,
|
||||||
isSenderChannel,
|
isSenderChannel,
|
||||||
|
forwardMessageIds,
|
||||||
|
fromChatId,
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
resetDraftReplyInfo,
|
resetDraftReplyInfo,
|
||||||
@ -120,10 +124,27 @@ const ComposerEmbeddedMessage: FC<OwnProps & StateProps> = ({
|
|||||||
|
|
||||||
const isForwarding = Boolean(forwardedMessagesCount);
|
const isForwarding = Boolean(forwardedMessagesCount);
|
||||||
|
|
||||||
|
const selectSenderFromForwardedMessage = useLastCallback((forwardedMessage: ApiMessage) => {
|
||||||
|
const global = getGlobal();
|
||||||
|
sender = selectForwardedSender(global, forwardedMessage);
|
||||||
|
if (!sender) {
|
||||||
|
sender = selectSender(global, forwardedMessage);
|
||||||
|
}
|
||||||
|
return sender;
|
||||||
|
});
|
||||||
|
|
||||||
|
const forwardSenders = useMemo(() => {
|
||||||
|
if (!isForwarding) return undefined;
|
||||||
|
const forwardedMessages = forwardMessageIds?.map((id) => selectChatMessage(getGlobal(), fromChatId!, id))
|
||||||
|
.filter(Boolean);
|
||||||
|
const senders = forwardedMessages?.map((m) => selectSenderFromForwardedMessage(m)).filter(Boolean);
|
||||||
|
return senders ? unique(senders) : undefined;
|
||||||
|
}, [isForwarding, forwardMessageIds, fromChatId]);
|
||||||
|
|
||||||
const isShown = (() => {
|
const isShown = (() => {
|
||||||
if (isInChangingRecipientMode) return false;
|
if (isInChangingRecipientMode) return false;
|
||||||
if (message && (replyInfo || editingId)) return true;
|
if (message && (replyInfo || editingId)) return true;
|
||||||
if (sender && isForwarding) return true;
|
if (forwardSenders && isForwarding) return true;
|
||||||
return false;
|
return false;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
@ -266,6 +287,7 @@ const ComposerEmbeddedMessage: FC<OwnProps & StateProps> = ({
|
|||||||
isInComposer
|
isInComposer
|
||||||
message={strippedMessage}
|
message={strippedMessage}
|
||||||
sender={!noAuthors ? sender : undefined}
|
sender={!noAuthors ? sender : undefined}
|
||||||
|
composerForwardSenders={forwardSenders}
|
||||||
customText={customText}
|
customText={customText}
|
||||||
title={(editingId && !isShowingReply) ? oldLang('EditMessage')
|
title={(editingId && !isShowingReply) ? oldLang('EditMessage')
|
||||||
: noAuthors ? oldLang('HiddenSendersNameDescription') : undefined}
|
: noAuthors ? oldLang('HiddenSendersNameDescription') : undefined}
|
||||||
@ -417,18 +439,20 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
|
|
||||||
let sender: ApiPeer | undefined;
|
let sender: ApiPeer | undefined;
|
||||||
|
|
||||||
|
const selectSenderFromForwardedMessage = (forwardedMessage: ApiMessage) => {
|
||||||
|
sender = selectForwardedSender(global, forwardedMessage);
|
||||||
|
if (!sender) {
|
||||||
|
sender = selectSender(global, forwardedMessage);
|
||||||
|
}
|
||||||
|
return sender;
|
||||||
|
};
|
||||||
|
|
||||||
if (editingId && message) {
|
if (editingId && message) {
|
||||||
sender = selectSender(global, message);
|
sender = selectSender(global, message);
|
||||||
} else if (isForwarding) {
|
} else if (isForwarding) {
|
||||||
if (message) {
|
let forwardSenders = forwardedMessages?.map((m) => selectSenderFromForwardedMessage(m)).filter(Boolean);
|
||||||
sender = selectForwardedSender(global, message);
|
forwardSenders = forwardSenders ? unique(forwardSenders) : undefined;
|
||||||
if (!sender) {
|
sender = forwardSenders?.length === 1 ? forwardSenders?.[0] : undefined;
|
||||||
sender = selectSender(global, message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!sender) {
|
|
||||||
sender = selectPeer(global, fromChatId!);
|
|
||||||
}
|
|
||||||
} else if (replyInfo && message && !shouldForceShowEditing) {
|
} else if (replyInfo && message && !shouldForceShowEditing) {
|
||||||
const { forwardInfo } = message;
|
const { forwardInfo } = message;
|
||||||
const isChatWithSelf = selectIsChatWithSelf(global, chatId);
|
const isChatWithSelf = selectIsChatWithSelf(global, chatId);
|
||||||
@ -471,6 +495,8 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
senderChat,
|
senderChat,
|
||||||
currentUserId: global.currentUserId,
|
currentUserId: global.currentUserId,
|
||||||
isSenderChannel,
|
isSenderChannel,
|
||||||
|
forwardMessageIds,
|
||||||
|
fromChatId,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
)(ComposerEmbeddedMessage));
|
)(ComposerEmbeddedMessage));
|
||||||
|
|||||||
3
src/types/language.d.ts
vendored
3
src/types/language.d.ts
vendored
@ -2411,6 +2411,9 @@ export interface LangPairWithVariables<V extends unknown = LangVariable> {
|
|||||||
'user': V;
|
'user': V;
|
||||||
'stars': V;
|
'stars': V;
|
||||||
};
|
};
|
||||||
|
'ComposerTitleForwardFrom': {
|
||||||
|
'users': V;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LangPairPlural {
|
export interface LangPairPlural {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user