Message: Support summaries (#6585)
Co-authored-by: Dmitry Kabanov <dmitrykabanovdev@gmail.com>
This commit is contained in:
parent
1c602dddfa
commit
7ac577124e
@ -293,6 +293,7 @@ export function buildApiMessageWithChatId(
|
||||
reportDeliveryUntilDate: mtpMessage.reportDeliveryUntilDate,
|
||||
paidMessageStars: toJSNumber(mtpMessage.paidMessageStars),
|
||||
restrictionReasons,
|
||||
summaryLanguageCode: mtpMessage.summaryFromLanguage,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -2353,6 +2353,22 @@ export async function translateText(params: TranslateTextParams) {
|
||||
return formattedText;
|
||||
}
|
||||
|
||||
export async function fetchMessageSummary({
|
||||
chat, id, toLanguageCode,
|
||||
}: {
|
||||
chat: ApiChat; id: number; toLanguageCode?: string;
|
||||
}) {
|
||||
const result = await invokeRequest(new GramJs.messages.SummarizeText({
|
||||
peer: buildInputPeer(chat.id, chat.accessHash),
|
||||
id,
|
||||
toLang: toLanguageCode,
|
||||
}));
|
||||
|
||||
if (!result) return undefined;
|
||||
|
||||
return buildApiFormattedText(result);
|
||||
}
|
||||
|
||||
function handleMultipleLocalMessagesUpdate(
|
||||
localMessages: Record<string, ApiMessage>, update: GramJs.TypeUpdates,
|
||||
) {
|
||||
|
||||
@ -29,6 +29,7 @@ import {
|
||||
} from '../apiBuilders/chats';
|
||||
import {
|
||||
buildApiFormattedText,
|
||||
buildApiMessageEntity,
|
||||
buildApiPhoto, buildApiUsernames, buildPrivacyRules,
|
||||
} from '../apiBuilders/common';
|
||||
import { buildApiStarGiftAuctionUserState, buildApiTypeStarGiftAuctionState } from '../apiBuilders/gifts';
|
||||
@ -421,6 +422,7 @@ export function updater(update: Update) {
|
||||
'@type': 'error',
|
||||
error: {
|
||||
message: update.message,
|
||||
entities: update.entities.map(buildApiMessageEntity),
|
||||
},
|
||||
});
|
||||
} else {
|
||||
|
||||
@ -697,6 +697,7 @@ export interface ApiMessage {
|
||||
reportDeliveryUntilDate?: number;
|
||||
paidMessageStars?: number;
|
||||
restrictionReasons?: ApiRestrictionReason[];
|
||||
summaryLanguageCode?: string;
|
||||
|
||||
isTypingDraft?: boolean; // Local field
|
||||
}
|
||||
|
||||
@ -143,6 +143,7 @@ export type ApiNotification = {
|
||||
|
||||
export type ApiError = {
|
||||
message: string;
|
||||
entities?: ApiMessageEntity[];
|
||||
hasErrorKey?: boolean;
|
||||
isSlowMode?: boolean;
|
||||
textParams?: Record<string, string>;
|
||||
|
||||
@ -2591,6 +2591,10 @@
|
||||
"AttachmentSendFile_other" = "Send {count} Files";
|
||||
"AttachmentDragAddItems" = "Add Items";
|
||||
"AttachmentCaptionPlaceholder" = "Add a caption...";
|
||||
"MessageSummaryTitle" = "AI Summary";
|
||||
"MessageSummaryDescription" = "Show original text";
|
||||
"AriaShowSummary" = "Show AI Summary";
|
||||
"AriaHideSummary" = "Hide AI Summary";
|
||||
"SettingsDataClearMediaCache" = "Clear Media Cache";
|
||||
"SettingsDataClearMediaCacheDescription" = "Deletes locally cached media for this account";
|
||||
"SettingsDataClearMediaDone" = "Media cache cleared";
|
||||
|
||||
@ -30,7 +30,7 @@ import MessageText from './MessageText';
|
||||
|
||||
type OwnProps = {
|
||||
message: ApiMessage;
|
||||
translatedText?: ApiFormattedText;
|
||||
forcedText?: ApiFormattedText;
|
||||
noEmoji?: boolean;
|
||||
highlight?: string;
|
||||
truncateLength?: number;
|
||||
@ -49,7 +49,7 @@ type StateProps = {
|
||||
|
||||
function MessageSummary({
|
||||
message,
|
||||
translatedText,
|
||||
forcedText,
|
||||
noEmoji,
|
||||
highlight,
|
||||
truncateLength = TRUNCATED_SUMMARY_LENGTH,
|
||||
@ -70,7 +70,7 @@ function MessageSummary({
|
||||
const statefulContent = groupStatefulContent({ poll, story, webPage });
|
||||
|
||||
if (!extractedText && !hasPoll && !isAction) {
|
||||
const summaryText = translatedText?.text
|
||||
const summaryText = forcedText?.text
|
||||
|| getMessageSummaryText(lang, message, statefulContent, noEmoji, truncateLength);
|
||||
const trimmedText = trimText(summaryText, truncateLength);
|
||||
|
||||
@ -93,7 +93,7 @@ function MessageSummary({
|
||||
return (
|
||||
<MessageText
|
||||
messageOrStory={message}
|
||||
translatedText={translatedText}
|
||||
forcedText={forcedText}
|
||||
highlight={highlight}
|
||||
asPreview
|
||||
observeIntersectionForLoading={observeIntersectionForLoading}
|
||||
|
||||
@ -21,7 +21,7 @@ import TypingWrapper from './TypingWrapper';
|
||||
interface OwnProps {
|
||||
messageOrStory: ApiMessage | ApiStory;
|
||||
threadId?: ThreadId;
|
||||
translatedText?: ApiFormattedText;
|
||||
forcedText?: ApiFormattedText;
|
||||
isForAnimation?: boolean;
|
||||
emojiSize?: number;
|
||||
highlight?: string;
|
||||
@ -46,7 +46,7 @@ const MIN_CUSTOM_EMOJIS_FOR_SHARED_CANVAS = 3;
|
||||
|
||||
function MessageText({
|
||||
messageOrStory,
|
||||
translatedText,
|
||||
forcedText,
|
||||
isForAnimation,
|
||||
emojiSize,
|
||||
highlight,
|
||||
@ -74,7 +74,7 @@ function MessageText({
|
||||
|
||||
const lang = useLang();
|
||||
|
||||
const formattedText = translatedText || extractMessageText(messageOrStory, inChatList);
|
||||
const formattedText = forcedText || extractMessageText(messageOrStory, inChatList);
|
||||
const adaptedFormattedText = isForAnimation && formattedText ? stripCustomEmoji(formattedText) : formattedText;
|
||||
const { text, entities } = adaptedFormattedText || {};
|
||||
|
||||
|
||||
@ -208,7 +208,7 @@ const EmbeddedMessage: FC<OwnProps> = ({
|
||||
<MessageSummary
|
||||
message={message}
|
||||
noEmoji={Boolean(mediaThumbnail)}
|
||||
translatedText={translatedText}
|
||||
forcedText={translatedText}
|
||||
observeIntersectionForLoading={observeIntersectionForLoading}
|
||||
observeIntersectionForPlaying={observeIntersectionForPlaying}
|
||||
emojiSize={EMOJI_SIZE}
|
||||
|
||||
@ -8,7 +8,7 @@ import type { MessageList } from '../../types';
|
||||
|
||||
import { selectCurrentMessageList, selectTabState } from '../../global/selectors';
|
||||
import getReadableErrorText from '../../util/getReadableErrorText';
|
||||
import renderText from '../common/helpers/renderText';
|
||||
import { renderTextWithEntities } from '../common/helpers/renderTextWithEntities';
|
||||
|
||||
import useFlag from '../../hooks/useFlag';
|
||||
import useLang from '../../hooks/useLang';
|
||||
@ -91,7 +91,7 @@ const Dialogs = ({ dialogs, currentMessageList }: StateProps) => {
|
||||
title={getErrorHeader(error)}
|
||||
>
|
||||
{error.hasErrorKey ? getReadableErrorText(error)
|
||||
: renderText(error.message, ['simple_markdown', 'emoji', 'br'])}
|
||||
: renderTextWithEntities({ text: error.message, entities: error.entities })}
|
||||
<div className="dialog-buttons mt-2">
|
||||
<Button isText onClick={closeModal}>{lang('OK')}</Button>
|
||||
</div>
|
||||
|
||||
@ -709,10 +709,44 @@
|
||||
}
|
||||
}
|
||||
|
||||
.message-action-buttons {
|
||||
.message-summary {
|
||||
cursor: var(--custom-cursor, pointer);
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
padding-block: 0.1875rem;
|
||||
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.25;
|
||||
|
||||
&-title {
|
||||
font-weight: var(--font-weight-medium);
|
||||
}
|
||||
}
|
||||
|
||||
.message-action-buttons-container {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.message-action-buttons-sticky-zone {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.message-action-button-sticky {
|
||||
position: sticky;
|
||||
top: 0.5rem;
|
||||
}
|
||||
|
||||
.message-action-buttons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@ -729,9 +763,14 @@
|
||||
}
|
||||
|
||||
.message-action-button {
|
||||
overflow: visible;
|
||||
width: 2.25rem;
|
||||
height: 2.25rem;
|
||||
color: white;
|
||||
|
||||
&.action-summary .icon {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover,
|
||||
@ -745,11 +784,11 @@
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&.own .message-action-buttons {
|
||||
&.own .message-action-buttons-container {
|
||||
left: -3rem;
|
||||
}
|
||||
|
||||
&:not(.own) .message-action-buttons {
|
||||
&:not(.own) .message-action-buttons-container {
|
||||
right: -3rem;
|
||||
}
|
||||
|
||||
|
||||
@ -36,6 +36,7 @@ import type {
|
||||
IAlbum,
|
||||
MessageListType,
|
||||
ScrollTargetPosition,
|
||||
TextSummary,
|
||||
ThemeKey,
|
||||
ThreadId,
|
||||
} from '../../../types';
|
||||
@ -96,6 +97,7 @@ import {
|
||||
selectIsMessageProtected,
|
||||
selectIsMessageSelected,
|
||||
selectMessageIdsByGroupId,
|
||||
selectMessageSummary,
|
||||
selectOutgoingStatus,
|
||||
selectPeer,
|
||||
selectPeerStory,
|
||||
@ -141,6 +143,7 @@ import { calculateMediaDimensions, getMinMediaWidth, getMinMediaWidthWithText }
|
||||
|
||||
import useAppLayout from '../../../hooks/useAppLayout';
|
||||
import useContextMenuHandlers from '../../../hooks/useContextMenuHandlers';
|
||||
import useEffectWithPrevDeps from '../../../hooks/useEffectWithPrevDeps';
|
||||
import useEnsureMessage from '../../../hooks/useEnsureMessage';
|
||||
import useEnsureStory from '../../../hooks/useEnsureStory';
|
||||
import useFlag from '../../../hooks/useFlag';
|
||||
@ -169,7 +172,9 @@ import FakeIcon from '../../common/FakeIcon';
|
||||
import Icon from '../../common/icons/Icon';
|
||||
import StarIcon from '../../common/icons/StarIcon';
|
||||
import MessageText from '../../common/MessageText';
|
||||
import PeerColorWrapper from '../../common/PeerColorWrapper';
|
||||
import ReactionStaticEmoji from '../../common/reactions/ReactionStaticEmoji';
|
||||
import Sparkles from '../../common/Sparkles';
|
||||
import TopicChip from '../../common/TopicChip';
|
||||
import { animateSnap } from '../../main/visualEffects/SnapEffectContainer';
|
||||
import Button from '../../ui/Button';
|
||||
@ -324,6 +329,7 @@ type StateProps = {
|
||||
minFutureTime?: number;
|
||||
isMediaNsfw?: boolean;
|
||||
isReplyMediaNsfw?: boolean;
|
||||
summary?: TextSummary;
|
||||
};
|
||||
|
||||
type MetaPosition =
|
||||
@ -452,6 +458,7 @@ const Message = ({
|
||||
isAccountFrozen,
|
||||
minFutureTime,
|
||||
webPage,
|
||||
summary,
|
||||
onIntersectPinnedMessage,
|
||||
}: OwnProps & StateProps) => {
|
||||
const {
|
||||
@ -465,6 +472,7 @@ const Message = ({
|
||||
focusMessage,
|
||||
markMentionsRead,
|
||||
openThread,
|
||||
summarizeMessage,
|
||||
} = getActions();
|
||||
|
||||
const ref = useRef<HTMLDivElement>();
|
||||
@ -480,6 +488,7 @@ const Message = ({
|
||||
const [shouldPlayEffect, requestEffect, hideEffect] = useFlag();
|
||||
const [shouldPlayDiceEffect, requestDiceEffect, hideDiceEffect] = useFlag();
|
||||
const [isDeclineDialogOpen, openDeclineDialog, closeDeclineDialog] = useFlag();
|
||||
const [isShowingSummary, showSummary, hideSummary] = useFlag();
|
||||
const [declineReason, setDeclineReason] = useState('');
|
||||
const { isMobile, isTouchScreen } = useAppLayout();
|
||||
|
||||
@ -528,6 +537,7 @@ const Message = ({
|
||||
id: messageId, chatId, forwardInfo, viaBotId, isTranscriptionError, factCheck,
|
||||
isTypingDraft,
|
||||
} = message;
|
||||
const hasSummary = Boolean(message.summaryLanguageCode);
|
||||
|
||||
useUnmountCleanup(() => {
|
||||
if (message.isPinned) {
|
||||
@ -597,7 +607,8 @@ const Message = ({
|
||||
const hasFactCheck = Boolean(factCheck?.text);
|
||||
|
||||
const hasForwardedCustomShape = asForwarded && isCustomShape;
|
||||
const hasSubheader = hasTopicChip || hasMessageReply || hasStoryReply || hasForwardedCustomShape;
|
||||
const hasSubheader = hasTopicChip || hasMessageReply || hasStoryReply || hasForwardedCustomShape
|
||||
|| Boolean(isShowingSummary && summary?.text);
|
||||
|
||||
const selectMessage = useLastCallback((e?: React.MouseEvent<HTMLDivElement, MouseEvent>, groupedId?: string) => {
|
||||
if (isAccountFrozen) return;
|
||||
@ -695,6 +706,16 @@ const Message = ({
|
||||
lastPlaybackTimestamp,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (hasSummary && isShowingSummary && !summary) {
|
||||
summarizeMessage({
|
||||
chatId,
|
||||
id: message.id,
|
||||
toLanguageCode: requestedTranslationLanguage,
|
||||
});
|
||||
}
|
||||
}, [hasSummary, chatId, message.id, requestedTranslationLanguage, isShowingSummary, summary]);
|
||||
|
||||
const handleEffectClick = useLastCallback((e: React.MouseEvent<HTMLDivElement>) => {
|
||||
e.stopPropagation();
|
||||
|
||||
@ -706,6 +727,7 @@ const Message = ({
|
||||
chatId,
|
||||
threadId,
|
||||
messageId,
|
||||
scrollTargetPosition: 'start',
|
||||
noHighlight: true,
|
||||
});
|
||||
});
|
||||
@ -801,9 +823,17 @@ const Message = ({
|
||||
const { isPending: isTranslationPending, translatedText } = useMessageTranslation(
|
||||
chatTranslations, chatId, shouldTranslate ? messageId : undefined, requestedTranslationLanguage,
|
||||
);
|
||||
const isSummaryPending = Boolean(summary?.isPending);
|
||||
const isNewTextPending = isTranslationPending || isSummaryPending;
|
||||
// Used to display previous result while new one is loading
|
||||
const previousTranslatedText = usePreviousDeprecated(translatedText, Boolean(shouldTranslate));
|
||||
|
||||
useEffectWithPrevDeps(([prevIsShowingSummary]) => {
|
||||
if (summary?.text || (prevIsShowingSummary && !isShowingSummary)) {
|
||||
handleFocusSelf();
|
||||
}
|
||||
}, [isShowingSummary, summary?.text]);
|
||||
|
||||
const currentTranslatedText = translatedText || previousTranslatedText;
|
||||
|
||||
const phoneCall = action?.type === 'phoneCall' ? action : undefined;
|
||||
@ -1019,10 +1049,13 @@ const Message = ({
|
||||
|
||||
function renderMessageText(isForAnimation?: boolean) {
|
||||
if (!textMessage) return undefined;
|
||||
|
||||
const forcedText = (isShowingSummary && summary?.text)
|
||||
|| (requestedTranslationLanguage ? currentTranslatedText : undefined);
|
||||
return (
|
||||
<MessageText
|
||||
messageOrStory={textMessage}
|
||||
translatedText={requestedTranslationLanguage ? currentTranslatedText : undefined}
|
||||
forcedText={forcedText}
|
||||
isForAnimation={isForAnimation}
|
||||
focusedQuote={focusedQuote}
|
||||
focusedQuoteOffset={focusedQuoteOffset}
|
||||
@ -1041,6 +1074,16 @@ const Message = ({
|
||||
);
|
||||
}
|
||||
|
||||
function renderMessageTextAnimation() {
|
||||
return (
|
||||
<div className="translation-animation">
|
||||
<div className="text-loading">
|
||||
{renderMessageText(true)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const renderQuickReactionButton = useCallback(() => {
|
||||
if (!defaultReaction) return undefined;
|
||||
|
||||
@ -1174,6 +1217,20 @@ const Message = ({
|
||||
onClick={handleStoryClick}
|
||||
/>
|
||||
)}
|
||||
{hasSummary && isShowingSummary && !summary?.isPending && (
|
||||
<PeerColorWrapper
|
||||
className="message-summary"
|
||||
onClick={hideSummary}
|
||||
>
|
||||
<Sparkles preset="button" className="message-summary-sparkles" />
|
||||
<span className="message-summary-title">
|
||||
{lang('MessageSummaryTitle')}
|
||||
</span>
|
||||
<span className="message-summary-description">
|
||||
{lang('MessageSummaryDescription')}
|
||||
</span>
|
||||
</PeerColorWrapper>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{sticker && observeIntersectionForLoading && observeIntersectionForPlaying && (
|
||||
@ -1347,13 +1404,7 @@ const Message = ({
|
||||
{hasText && !hasAnimatedEmoji && (
|
||||
<div className={textContentClass} dir="auto">
|
||||
{renderMessageText()}
|
||||
{isTranslationPending && (
|
||||
<div className="translation-animation">
|
||||
<div className="text-loading">
|
||||
{renderMessageText(true)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{isNewTextPending && renderMessageTextAnimation()}
|
||||
{hasFactCheck && (
|
||||
<FactCheck factCheck={factCheck} isToggleDisabled={isInSelectMode} />
|
||||
)}
|
||||
@ -1409,13 +1460,7 @@ const Message = ({
|
||||
{hasText && !hasAnimatedEmoji && (
|
||||
<div className={textContentClass} dir="auto">
|
||||
{renderMessageText()}
|
||||
{isTranslationPending && (
|
||||
<div className="translation-animation">
|
||||
<div className="text-loading">
|
||||
{renderMessageText(true)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{isNewTextPending && renderMessageTextAnimation()}
|
||||
{!hasContentAfterText && isMetaInText && renderReactionsAndMeta()}
|
||||
</div>
|
||||
)}
|
||||
@ -1820,40 +1865,57 @@ const Message = ({
|
||||
{renderContent()}
|
||||
{!isInDocumentGroupNotLast && metaPosition === 'standalone' && !isStoryMention && renderReactionsAndMeta()}
|
||||
{canShowActionButton && (
|
||||
<div className={buildClassName(
|
||||
'message-action-buttons',
|
||||
isLoadingComments && 'message-action-buttons-shown',
|
||||
)}
|
||||
>
|
||||
{withCommentButton && isCustomShape && (
|
||||
<CommentButton
|
||||
threadInfo={commentsThreadInfo}
|
||||
disabled={noComments || !commentsThreadInfo}
|
||||
isLoading={isLoadingComments}
|
||||
isCustomShape
|
||||
asActionButton
|
||||
/>
|
||||
)}
|
||||
{canForward && (
|
||||
<Button
|
||||
className="message-action-button"
|
||||
color="translucent-white"
|
||||
round
|
||||
ariaLabel={oldLang('lng_context_forward_msg')}
|
||||
onClick={isLastInDocumentGroup ? handleGroupForward : handleForward}
|
||||
iconName="share-filled"
|
||||
/>
|
||||
)}
|
||||
{canFocus && (
|
||||
<Button
|
||||
className="message-action-button"
|
||||
color="translucent-white"
|
||||
round
|
||||
ariaLabel={lang('FocusMessage')}
|
||||
onClick={isPinnedList ? handleFocus : handleFocusForwarded}
|
||||
iconName="arrow-right"
|
||||
/>
|
||||
<div className="message-action-buttons-container">
|
||||
<div className="message-action-buttons-sticky-zone">
|
||||
<div className="message-action-buttons message-action-button-sticky">
|
||||
{hasSummary && (
|
||||
<Button
|
||||
className="message-action-button action-summary"
|
||||
color="translucent-white"
|
||||
round
|
||||
withSparkleEffect
|
||||
ariaLabel={isShowingSummary ? lang('AriaHideSummary') : lang('AriaShowSummary')}
|
||||
onClick={isShowingSummary ? hideSummary : showSummary}
|
||||
iconName={isShowingSummary ? 'expand' : 'collapse'}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className={buildClassName(
|
||||
'message-action-buttons',
|
||||
isLoadingComments && 'message-action-buttons-shown',
|
||||
)}
|
||||
>
|
||||
{withCommentButton && isCustomShape && (
|
||||
<CommentButton
|
||||
threadInfo={commentsThreadInfo}
|
||||
disabled={noComments || !commentsThreadInfo}
|
||||
isLoading={isLoadingComments}
|
||||
isCustomShape
|
||||
asActionButton
|
||||
/>
|
||||
)}
|
||||
{canForward && (
|
||||
<Button
|
||||
className="message-action-button"
|
||||
color="translucent-white"
|
||||
round
|
||||
ariaLabel={oldLang('lng_context_forward_msg')}
|
||||
onClick={isLastInDocumentGroup ? handleGroupForward : handleForward}
|
||||
iconName="share-filled"
|
||||
/>
|
||||
)}
|
||||
{canFocus && (
|
||||
<Button
|
||||
className="message-action-button"
|
||||
color="translucent-white"
|
||||
round
|
||||
ariaLabel={lang('FocusMessage')}
|
||||
onClick={isPinnedList ? handleFocus : handleFocusForwarded}
|
||||
iconName="arrow-right"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{withCommentButton && !isCustomShape && (
|
||||
@ -2076,6 +2138,8 @@ export default memo(withGlobal<OwnProps>(
|
||||
const isMediaNsfw = selectIsMediaNsfw(global, message);
|
||||
const isReplyMediaNsfw = replyMessage && selectIsMediaNsfw(global, replyMessage);
|
||||
|
||||
const summary = selectMessageSummary(global, chatId, message.id, requestedTranslationLanguage);
|
||||
|
||||
return {
|
||||
theme: selectTheme(global),
|
||||
forceSenderName,
|
||||
@ -2172,6 +2236,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
isMediaNsfw,
|
||||
isReplyMediaNsfw,
|
||||
webPage,
|
||||
summary,
|
||||
};
|
||||
},
|
||||
)(Message));
|
||||
|
||||
@ -16,6 +16,7 @@ import type {
|
||||
import type {
|
||||
ForwardMessagesParams,
|
||||
SendMessageParams,
|
||||
TextSummary,
|
||||
ThreadId,
|
||||
} from '../../../types';
|
||||
import type { MessageKey } from '../../../util/keys/messageKey';
|
||||
@ -77,6 +78,7 @@ import {
|
||||
import {
|
||||
addChatMessagesById,
|
||||
addUnreadMentions,
|
||||
clearMessageSummary,
|
||||
deleteSponsoredMessage,
|
||||
removeOutlyingList,
|
||||
removeRequestedMessageTranslation,
|
||||
@ -91,6 +93,7 @@ import {
|
||||
updateChatMessage,
|
||||
updateGlobalSearch,
|
||||
updateListedIds,
|
||||
updateMessageSummary,
|
||||
updateMessageTranslation,
|
||||
updateOutlyingLists,
|
||||
updatePeerFullInfo,
|
||||
@ -2711,6 +2714,39 @@ addActionHandler('translateMessages', (global, actions, payload): ActionReturnTy
|
||||
return global;
|
||||
});
|
||||
|
||||
addActionHandler('summarizeMessage', async (global, actions, payload): Promise<void> => {
|
||||
const { chatId, id, toLanguageCode } = payload;
|
||||
const chat = selectChat(global, chatId);
|
||||
if (!chat) return;
|
||||
|
||||
const placeholderSummary: TextSummary = {
|
||||
isPending: true,
|
||||
text: undefined,
|
||||
};
|
||||
|
||||
global = updateMessageSummary(global, chatId, id, placeholderSummary, toLanguageCode);
|
||||
setGlobal(global);
|
||||
|
||||
const result = await callApi('fetchMessageSummary', { chat, id, toLanguageCode });
|
||||
if (!result) {
|
||||
global = getGlobal();
|
||||
// Disable summary to prevent endless loading
|
||||
global = updateChatMessage(global, chatId, id, { summaryLanguageCode: undefined });
|
||||
global = clearMessageSummary(global, chatId, id);
|
||||
setGlobal(global);
|
||||
return;
|
||||
}
|
||||
|
||||
const summary: TextSummary = {
|
||||
isPending: false,
|
||||
text: result,
|
||||
};
|
||||
|
||||
global = getGlobal();
|
||||
global = updateMessageSummary(global, chatId, id, summary, toLanguageCode);
|
||||
setGlobal(global);
|
||||
});
|
||||
|
||||
// https://github.com/telegramdesktop/tdesktop/blob/11906297d82b6ff57b277da5251d2e6eb3d8b6d0/Telegram/SourceFiles/api/api_views.cpp#L22
|
||||
const SEND_VIEWS_TIMEOUT = 1000;
|
||||
let viewsIncrementTimeout: number | undefined;
|
||||
|
||||
@ -40,6 +40,7 @@ import {
|
||||
import {
|
||||
addMessages,
|
||||
addViewportId,
|
||||
clearMessageSummary,
|
||||
clearMessageTranslation,
|
||||
deleteChatMessages,
|
||||
deleteChatScheduledMessages,
|
||||
@ -358,6 +359,7 @@ addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => {
|
||||
|
||||
if (message.content?.text?.text !== currentMessage?.content?.text?.text) {
|
||||
global = clearMessageTranslation(global, chatId, id);
|
||||
global = clearMessageSummary(global, chatId, id);
|
||||
}
|
||||
|
||||
if (poll) {
|
||||
|
||||
@ -416,6 +416,7 @@ function reduceGlobal<T extends GlobalState>(global: T) {
|
||||
const reducedGlobal: GlobalState = {
|
||||
...INITIAL_GLOBAL_STATE,
|
||||
...pick(global, [
|
||||
'cacheVersion',
|
||||
'appConfig',
|
||||
'config',
|
||||
'auth',
|
||||
@ -722,6 +723,7 @@ function reduceMessages<T extends GlobalState>(global: T): GlobalState['messages
|
||||
byChatId[chatId] = {
|
||||
byId: cleanedById,
|
||||
threadsById,
|
||||
summaryById: {},
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@ -56,7 +56,7 @@ import {
|
||||
} from '../selectors';
|
||||
import { removeIdFromSearchResults } from './middleSearch';
|
||||
import { updateTabState } from './tabs';
|
||||
import { clearMessageTranslation } from './translations';
|
||||
import { clearMessageSummary, clearMessageTranslation } from './translations';
|
||||
|
||||
type MessageStoreSections = GlobalState['messages']['byChatId'][string];
|
||||
|
||||
@ -153,7 +153,8 @@ export function updateThread<T extends GlobalState>(
|
||||
export function updateMessageStore<T extends GlobalState>(
|
||||
global: T, chatId: string, update: Partial<MessageStoreSections>,
|
||||
): T {
|
||||
const current = global.messages.byChatId[chatId] || { byId: {}, threadsById: {} };
|
||||
const current = global.messages.byChatId[chatId]
|
||||
|| { byId: {}, threadsById: {}, summaryById: {} };
|
||||
|
||||
return {
|
||||
...global,
|
||||
@ -399,6 +400,7 @@ export function deleteChatMessages<T extends GlobalState>(
|
||||
threadMessages.push(messageId);
|
||||
updatedThreads.set(threadId, threadMessages);
|
||||
global = clearMessageTranslation(global, chatId, messageId);
|
||||
global = clearMessageSummary(global, chatId, messageId);
|
||||
});
|
||||
|
||||
const deletedForwardedPosts = Object.values(pickTruthy(byId, messageIds)).filter(
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import type { ApiFormattedText } from '../../api/types';
|
||||
import type { TranslatedMessage } from '../../types';
|
||||
import type { TextSummary, TranslatedMessage } from '../../types';
|
||||
import type { GlobalState, TabArgs } from '../types';
|
||||
|
||||
import { getCurrentTabId } from '../../util/establishMultitabRole';
|
||||
@ -162,3 +162,44 @@ export function removeRequestedMessageTranslation<T extends GlobalState>(
|
||||
|
||||
return global;
|
||||
}
|
||||
|
||||
export function updateMessageSummary<T extends GlobalState>(
|
||||
global: T, chatId: string, messageId: number, summary: TextSummary, toLanguageCode?: string,
|
||||
) {
|
||||
if (toLanguageCode) {
|
||||
return updateMessageTranslation(global, chatId, messageId, toLanguageCode, { summary });
|
||||
}
|
||||
|
||||
const chatSummaries = global.messages.byChatId[chatId]?.summaryById;
|
||||
return replaceGeneralSummaryStore(global, chatId, { ...chatSummaries, [messageId]: summary });
|
||||
}
|
||||
|
||||
export function clearMessageSummary<T extends GlobalState>(
|
||||
global: T, chatId: string, messageId: number,
|
||||
) {
|
||||
const chatSummaries = global.messages.byChatId[chatId]?.summaryById;
|
||||
if (!chatSummaries) return global;
|
||||
|
||||
const newSummaryById = omit(chatSummaries, [messageId]);
|
||||
return replaceGeneralSummaryStore(global, chatId, newSummaryById);
|
||||
}
|
||||
|
||||
function replaceGeneralSummaryStore<T extends GlobalState>(
|
||||
global: T, chatId: string, update: Record<number, TextSummary>,
|
||||
): T {
|
||||
if (!global.messages.byChatId[chatId]) return global; // Unloaded chats should not have summaries
|
||||
|
||||
return {
|
||||
...global,
|
||||
messages: {
|
||||
...global.messages,
|
||||
byChatId: {
|
||||
...global.messages.byChatId,
|
||||
[chatId]: {
|
||||
...global.messages.byChatId[chatId],
|
||||
summaryById: update,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@ -13,6 +13,7 @@ import type {
|
||||
ChatTranslatedMessages,
|
||||
MessageListType,
|
||||
TabThread,
|
||||
TextSummary,
|
||||
Thread,
|
||||
ThreadId,
|
||||
} from '../../types';
|
||||
@ -1464,6 +1465,20 @@ export function selectForwardsContainVoiceMessages<T extends GlobalState>(
|
||||
});
|
||||
}
|
||||
|
||||
export function selectMessageSummary<T extends GlobalState>(
|
||||
global: T, chatId: string, messageId: number, toLanguageCode?: string,
|
||||
): TextSummary | undefined {
|
||||
const message = selectChatMessage(global, chatId, messageId);
|
||||
if (!message?.summaryLanguageCode) return undefined;
|
||||
|
||||
if (toLanguageCode && toLanguageCode !== message.summaryLanguageCode) {
|
||||
const messageTranslations = selectMessageTranslations(global, chatId, toLanguageCode);
|
||||
return messageTranslations[messageId]?.summary;
|
||||
}
|
||||
|
||||
return global.messages.byChatId[chatId].summaryById[messageId];
|
||||
}
|
||||
|
||||
export function selectChatTranslations<T extends GlobalState>(
|
||||
global: T, chatId: string,
|
||||
): ChatTranslatedMessages {
|
||||
|
||||
@ -1515,6 +1515,11 @@ export interface ActionPayloads {
|
||||
messageIds: number[];
|
||||
toLanguageCode?: string;
|
||||
};
|
||||
summarizeMessage: {
|
||||
chatId: string;
|
||||
id: number;
|
||||
toLanguageCode?: string;
|
||||
};
|
||||
|
||||
// Reactions
|
||||
loadTopReactions: undefined;
|
||||
|
||||
@ -70,6 +70,7 @@ import type {
|
||||
StarGiftCategory,
|
||||
StarsSubscriptions,
|
||||
StarsTransactionHistory,
|
||||
TextSummary,
|
||||
ThemeKey,
|
||||
Thread,
|
||||
ThreadId,
|
||||
@ -245,6 +246,7 @@ export type GlobalState = {
|
||||
messages: {
|
||||
byChatId: Record<string, {
|
||||
byId: Record<number, ApiMessage>;
|
||||
summaryById: Record<number, TextSummary>;
|
||||
threadsById: Record<ThreadId, Thread>;
|
||||
}>;
|
||||
playbackByChatId: Record<string, {
|
||||
|
||||
@ -12,6 +12,6 @@ for (const tl of Object.values(Api)) {
|
||||
}
|
||||
}
|
||||
|
||||
export const LAYER = 220;
|
||||
export const LAYER = 221;
|
||||
|
||||
export { tlobjects };
|
||||
|
||||
107
src/lib/gramjs/tl/api.d.ts
vendored
107
src/lib/gramjs/tl/api.d.ts
vendored
File diff suppressed because one or more lines are too long
@ -38,6 +38,7 @@ inputMediaStory#89fdd778 peer:InputPeer id:int = InputMedia;
|
||||
inputMediaWebPage#c21b8849 flags:# force_large_media:flags.0?true force_small_media:flags.1?true optional:flags.2?true url:string = InputMedia;
|
||||
inputMediaPaidMedia#c4103386 flags:# stars_amount:long extended_media:Vector<InputMedia> payload:flags.0?string = InputMedia;
|
||||
inputMediaTodo#9fc55fde todo:TodoList = InputMedia;
|
||||
inputMediaStakeDice#f3a9244a game_hash:string ton_amount:long client_seed:bytes = InputMedia;
|
||||
inputChatPhotoEmpty#1ca48f57 = InputChatPhoto;
|
||||
inputChatUploadedPhoto#bdcdaec0 flags:# file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.3?VideoSize = InputChatPhoto;
|
||||
inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto;
|
||||
@ -93,7 +94,7 @@ chatParticipants#3cbc93f8 chat_id:long participants:Vector<ChatParticipant> vers
|
||||
chatPhotoEmpty#37c1011c = ChatPhoto;
|
||||
chatPhoto#1c6e1c11 flags:# has_video:flags.0?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = ChatPhoto;
|
||||
messageEmpty#90a6ca84 flags:# id:int peer_id:flags.0?Peer = Message;
|
||||
message#b92f76cf flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true noforwards:flags.26?true invert_media:flags.27?true flags2:# offline:flags2.1?true video_processing_pending:flags2.4?true paid_suggested_post_stars:flags2.8?true paid_suggested_post_ton:flags2.9?true id:int from_id:flags.8?Peer from_boosts_applied:flags.29?int peer_id:Peer saved_peer_id:flags.28?Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long via_business_bot_id:flags2.0?long reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long reactions:flags.20?MessageReactions restriction_reason:flags.22?Vector<RestrictionReason> ttl_period:flags.25?int quick_reply_shortcut_id:flags.30?int effect:flags2.2?long factcheck:flags2.3?FactCheck report_delivery_until_date:flags2.5?int paid_message_stars:flags2.6?long suggested_post:flags2.7?SuggestedPost schedule_repeat_period:flags2.10?int = Message;
|
||||
message#9cb490e9 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true noforwards:flags.26?true invert_media:flags.27?true flags2:# offline:flags2.1?true video_processing_pending:flags2.4?true paid_suggested_post_stars:flags2.8?true paid_suggested_post_ton:flags2.9?true id:int from_id:flags.8?Peer from_boosts_applied:flags.29?int peer_id:Peer saved_peer_id:flags.28?Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long via_business_bot_id:flags2.0?long reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long reactions:flags.20?MessageReactions restriction_reason:flags.22?Vector<RestrictionReason> ttl_period:flags.25?int quick_reply_shortcut_id:flags.30?int effect:flags2.2?long factcheck:flags2.3?FactCheck report_delivery_until_date:flags2.5?int paid_message_stars:flags2.6?long suggested_post:flags2.7?SuggestedPost schedule_repeat_period:flags2.10?int summary_from_language:flags2.11?string = Message;
|
||||
messageService#7a800e0a flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true reactions_are_possible:flags.9?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?Peer peer_id:Peer saved_peer_id:flags.28?Peer reply_to:flags.3?MessageReplyHeader date:int action:MessageAction reactions:flags.20?MessageReactions ttl_period:flags.25?int = Message;
|
||||
messageMediaEmpty#3ded6320 = MessageMedia;
|
||||
messageMediaPhoto#695150d7 flags:# spoiler:flags.3?true photo:flags.0?Photo ttl_seconds:flags.2?int = MessageMedia;
|
||||
@ -107,7 +108,7 @@ messageMediaGame#fdb19008 game:Game = MessageMedia;
|
||||
messageMediaInvoice#f6a548d3 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string extended_media:flags.4?MessageExtendedMedia = MessageMedia;
|
||||
messageMediaGeoLive#b940c666 flags:# geo:GeoPoint heading:flags.0?int period:int proximity_notification_radius:flags.1?int = MessageMedia;
|
||||
messageMediaPoll#4bd6e798 poll:Poll results:PollResults = MessageMedia;
|
||||
messageMediaDice#3f7ee58b value:int emoticon:string = MessageMedia;
|
||||
messageMediaDice#8cbec07 flags:# value:int emoticon:string game_outcome:flags.0?messages.EmojiGameOutcome = MessageMedia;
|
||||
messageMediaStory#68cb6283 flags:# via_mention:flags.1?true peer:Peer id:int story:flags.0?StoryItem = MessageMedia;
|
||||
messageMediaGiveaway#aa073beb flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.2?true channels:Vector<long> countries_iso2:flags.1?Vector<string> prize_description:flags.3?string quantity:int months:flags.4?int stars:flags.5?long until_date:int = MessageMedia;
|
||||
messageMediaGiveawayResults#ceaa3ea1 flags:# only_new_subscribers:flags.0?true refunded:flags.2?true channel_id:long additional_peers_count:flags.3?int launch_msg_id:int winners_count:int unclaimed_count:int winners:Vector<long> months:flags.4?int stars:flags.5?long prize_description:flags.1?string until_date:int = MessageMedia;
|
||||
@ -399,6 +400,7 @@ updatePinnedForumTopics#def143d0 flags:# peer:Peer order:flags.0?Vector<int> = U
|
||||
updateDeleteGroupCallMessages#3e85e92c call:InputGroupCall messages:Vector<int> = Update;
|
||||
updateStarGiftAuctionState#48e246c2 gift_id:long state:StarGiftAuctionState = Update;
|
||||
updateStarGiftAuctionUserState#dc58f31e gift_id:long user_state:StarGiftAuctionUserState = Update;
|
||||
updateEmojiGameInfo#fb9c547a info:messages.EmojiGameInfo = Update;
|
||||
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
|
||||
updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference;
|
||||
updates.difference#f49ca0 new_messages:Vector<Message> new_encrypted_messages:Vector<EncryptedMessage> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> state:updates.State = updates.Difference;
|
||||
@ -1520,10 +1522,14 @@ auth.passkeyLoginOptions#e2037789 options:DataJSON = auth.PasskeyLoginOptions;
|
||||
inputPasskeyResponseRegister#3e63935c client_data:DataJSON attestation_data:bytes = InputPasskeyResponse;
|
||||
inputPasskeyResponseLogin#c31fc14a client_data:DataJSON authenticator_data:bytes signature:bytes user_handle:string = InputPasskeyResponse;
|
||||
inputPasskeyCredentialPublicKey#3c27b78f id:string raw_id:string response:InputPasskeyResponse = InputPasskeyCredential;
|
||||
inputPasskeyCredentialFirebasePNV#5b1ccb28 pnv_token:string = InputPasskeyCredential;
|
||||
starGiftBackground#aff56398 center_color:int edge_color:int text_color:int = StarGiftBackground;
|
||||
starGiftAuctionRound#3aae0528 num:int duration:int = StarGiftAuctionRound;
|
||||
starGiftAuctionRoundExtendable#aa021e5 num:int duration:int extend_top:int extend_window:int = StarGiftAuctionRound;
|
||||
payments.starGiftUpgradeAttributes#46c6e36f attributes:Vector<StarGiftAttribute> = payments.StarGiftUpgradeAttributes;
|
||||
messages.emojiGameOutcome#da2ad647 seed:bytes stake_ton_amount:long ton_amount:long = messages.EmojiGameOutcome;
|
||||
messages.emojiGameUnavailable#59e65335 = messages.EmojiGameInfo;
|
||||
messages.emojiGameDiceInfo#44e56023 flags:# game_hash:string prev_stake:long current_streak:int params:Vector<int> plays_left:flags.0?int = messages.EmojiGameInfo;
|
||||
---functions---
|
||||
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
|
||||
initConnection#c1cd5ea9 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy params:flags.1?JSONValue query:!X = X;
|
||||
@ -1771,6 +1777,7 @@ messages.editForumTopic#cecc1134 flags:# peer:InputPeer topic_id:int title:flags
|
||||
messages.updatePinnedForumTopic#175df251 peer:InputPeer topic_id:int pinned:Bool = Updates;
|
||||
messages.createForumTopic#2f98c3d5 flags:# title_missing:flags.4?true peer:InputPeer title:string icon_color:flags.0?int icon_emoji_id:flags.3?long random_id:long send_as:flags.2?InputPeer = Updates;
|
||||
messages.deleteTopicHistory#d2816f10 peer:InputPeer top_msg_id:int = messages.AffectedHistory;
|
||||
messages.summarizeText#9d4104e2 flags:# peer:InputPeer id:int to_lang:flags.0?string = TextWithEntities;
|
||||
updates.getState#edd4882a = updates.State;
|
||||
updates.getDifference#19c2f763 flags:# pts:int pts_limit:flags.1?int pts_total_limit:flags.0?int date:int qts:int qts_limit:flags.2?int = updates.Difference;
|
||||
updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference;
|
||||
|
||||
@ -245,6 +245,7 @@
|
||||
"messages.deleteTopicHistory",
|
||||
"messages.toggleTodoCompleted",
|
||||
"messages.appendTodoList",
|
||||
"messages.summarizeText",
|
||||
"updates.getState",
|
||||
"updates.getDifference",
|
||||
"updates.getChannelDifference",
|
||||
|
||||
@ -47,6 +47,7 @@ inputMediaStory#89fdd778 peer:InputPeer id:int = InputMedia;
|
||||
inputMediaWebPage#c21b8849 flags:# force_large_media:flags.0?true force_small_media:flags.1?true optional:flags.2?true url:string = InputMedia;
|
||||
inputMediaPaidMedia#c4103386 flags:# stars_amount:long extended_media:Vector<InputMedia> payload:flags.0?string = InputMedia;
|
||||
inputMediaTodo#9fc55fde todo:TodoList = InputMedia;
|
||||
inputMediaStakeDice#f3a9244a game_hash:string ton_amount:long client_seed:bytes = InputMedia;
|
||||
|
||||
inputChatPhotoEmpty#1ca48f57 = InputChatPhoto;
|
||||
inputChatUploadedPhoto#bdcdaec0 flags:# file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.3?VideoSize = InputChatPhoto;
|
||||
@ -117,7 +118,7 @@ chatPhotoEmpty#37c1011c = ChatPhoto;
|
||||
chatPhoto#1c6e1c11 flags:# has_video:flags.0?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = ChatPhoto;
|
||||
|
||||
messageEmpty#90a6ca84 flags:# id:int peer_id:flags.0?Peer = Message;
|
||||
message#b92f76cf flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true noforwards:flags.26?true invert_media:flags.27?true flags2:# offline:flags2.1?true video_processing_pending:flags2.4?true paid_suggested_post_stars:flags2.8?true paid_suggested_post_ton:flags2.9?true id:int from_id:flags.8?Peer from_boosts_applied:flags.29?int peer_id:Peer saved_peer_id:flags.28?Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long via_business_bot_id:flags2.0?long reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long reactions:flags.20?MessageReactions restriction_reason:flags.22?Vector<RestrictionReason> ttl_period:flags.25?int quick_reply_shortcut_id:flags.30?int effect:flags2.2?long factcheck:flags2.3?FactCheck report_delivery_until_date:flags2.5?int paid_message_stars:flags2.6?long suggested_post:flags2.7?SuggestedPost schedule_repeat_period:flags2.10?int = Message;
|
||||
message#9cb490e9 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true noforwards:flags.26?true invert_media:flags.27?true flags2:# offline:flags2.1?true video_processing_pending:flags2.4?true paid_suggested_post_stars:flags2.8?true paid_suggested_post_ton:flags2.9?true id:int from_id:flags.8?Peer from_boosts_applied:flags.29?int peer_id:Peer saved_peer_id:flags.28?Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long via_business_bot_id:flags2.0?long reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long reactions:flags.20?MessageReactions restriction_reason:flags.22?Vector<RestrictionReason> ttl_period:flags.25?int quick_reply_shortcut_id:flags.30?int effect:flags2.2?long factcheck:flags2.3?FactCheck report_delivery_until_date:flags2.5?int paid_message_stars:flags2.6?long suggested_post:flags2.7?SuggestedPost schedule_repeat_period:flags2.10?int summary_from_language:flags2.11?string = Message;
|
||||
messageService#7a800e0a flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true reactions_are_possible:flags.9?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?Peer peer_id:Peer saved_peer_id:flags.28?Peer reply_to:flags.3?MessageReplyHeader date:int action:MessageAction reactions:flags.20?MessageReactions ttl_period:flags.25?int = Message;
|
||||
|
||||
messageMediaEmpty#3ded6320 = MessageMedia;
|
||||
@ -132,7 +133,7 @@ messageMediaGame#fdb19008 game:Game = MessageMedia;
|
||||
messageMediaInvoice#f6a548d3 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string extended_media:flags.4?MessageExtendedMedia = MessageMedia;
|
||||
messageMediaGeoLive#b940c666 flags:# geo:GeoPoint heading:flags.0?int period:int proximity_notification_radius:flags.1?int = MessageMedia;
|
||||
messageMediaPoll#4bd6e798 poll:Poll results:PollResults = MessageMedia;
|
||||
messageMediaDice#3f7ee58b value:int emoticon:string = MessageMedia;
|
||||
messageMediaDice#8cbec07 flags:# value:int emoticon:string game_outcome:flags.0?messages.EmojiGameOutcome = MessageMedia;
|
||||
messageMediaStory#68cb6283 flags:# via_mention:flags.1?true peer:Peer id:int story:flags.0?StoryItem = MessageMedia;
|
||||
messageMediaGiveaway#aa073beb flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.2?true channels:Vector<long> countries_iso2:flags.1?Vector<string> prize_description:flags.3?string quantity:int months:flags.4?int stars:flags.5?long until_date:int = MessageMedia;
|
||||
messageMediaGiveawayResults#ceaa3ea1 flags:# only_new_subscribers:flags.0?true refunded:flags.2?true channel_id:long additional_peers_count:flags.3?int launch_msg_id:int winners_count:int unclaimed_count:int winners:Vector<long> months:flags.4?int stars:flags.5?long prize_description:flags.1?string until_date:int = MessageMedia;
|
||||
@ -452,6 +453,7 @@ updatePinnedForumTopics#def143d0 flags:# peer:Peer order:flags.0?Vector<int> = U
|
||||
updateDeleteGroupCallMessages#3e85e92c call:InputGroupCall messages:Vector<int> = Update;
|
||||
updateStarGiftAuctionState#48e246c2 gift_id:long state:StarGiftAuctionState = Update;
|
||||
updateStarGiftAuctionUserState#dc58f31e gift_id:long user_state:StarGiftAuctionUserState = Update;
|
||||
updateEmojiGameInfo#fb9c547a info:messages.EmojiGameInfo = Update;
|
||||
|
||||
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
|
||||
|
||||
@ -2097,6 +2099,7 @@ inputPasskeyResponseRegister#3e63935c client_data:DataJSON attestation_data:byte
|
||||
inputPasskeyResponseLogin#c31fc14a client_data:DataJSON authenticator_data:bytes signature:bytes user_handle:string = InputPasskeyResponse;
|
||||
|
||||
inputPasskeyCredentialPublicKey#3c27b78f id:string raw_id:string response:InputPasskeyResponse = InputPasskeyCredential;
|
||||
inputPasskeyCredentialFirebasePNV#5b1ccb28 pnv_token:string = InputPasskeyCredential;
|
||||
|
||||
starGiftBackground#aff56398 center_color:int edge_color:int text_color:int = StarGiftBackground;
|
||||
|
||||
@ -2105,6 +2108,11 @@ starGiftAuctionRoundExtendable#aa021e5 num:int duration:int extend_top:int exten
|
||||
|
||||
payments.starGiftUpgradeAttributes#46c6e36f attributes:Vector<StarGiftAttribute> = payments.StarGiftUpgradeAttributes;
|
||||
|
||||
messages.emojiGameOutcome#da2ad647 seed:bytes stake_ton_amount:long ton_amount:long = messages.EmojiGameOutcome;
|
||||
|
||||
messages.emojiGameUnavailable#59e65335 = messages.EmojiGameInfo;
|
||||
messages.emojiGameDiceInfo#44e56023 flags:# game_hash:string prev_stake:long current_streak:int params:Vector<int> plays_left:flags.0?int = messages.EmojiGameInfo;
|
||||
|
||||
---functions---
|
||||
|
||||
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
|
||||
@ -2544,6 +2552,8 @@ messages.updatePinnedForumTopic#175df251 peer:InputPeer topic_id:int pinned:Bool
|
||||
messages.reorderPinnedForumTopics#e7841f0 flags:# force:flags.0?true peer:InputPeer order:Vector<int> = Updates;
|
||||
messages.createForumTopic#2f98c3d5 flags:# title_missing:flags.4?true peer:InputPeer title:string icon_color:flags.0?int icon_emoji_id:flags.3?long random_id:long send_as:flags.2?InputPeer = Updates;
|
||||
messages.deleteTopicHistory#d2816f10 peer:InputPeer top_msg_id:int = messages.AffectedHistory;
|
||||
messages.getEmojiGameInfo#fb7e8ca7 = messages.EmojiGameInfo;
|
||||
messages.summarizeText#9d4104e2 flags:# peer:InputPeer id:int to_lang:flags.0?string = TextWithEntities;
|
||||
|
||||
updates.getState#edd4882a = updates.State;
|
||||
updates.getDifference#19c2f763 flags:# pts:int pts_limit:flags.1?int pts_total_limit:flags.0?int date:int qts:int qts_limit:flags.2?int = updates.Difference;
|
||||
|
||||
@ -642,6 +642,15 @@ export interface TopicsInfo {
|
||||
export type TranslatedMessage = {
|
||||
isPending?: boolean;
|
||||
text?: ApiFormattedText;
|
||||
summary?: TextSummary;
|
||||
};
|
||||
|
||||
export type TextSummary = {
|
||||
isPending?: false;
|
||||
text: ApiFormattedText;
|
||||
} | {
|
||||
isPending: true;
|
||||
text?: undefined;
|
||||
};
|
||||
|
||||
export type ChatTranslatedMessages = {
|
||||
|
||||
4
src/types/language.d.ts
vendored
4
src/types/language.d.ts
vendored
@ -1901,6 +1901,10 @@ export interface LangPair {
|
||||
'AttachmentMenuDisableSpoiler': undefined;
|
||||
'AttachmentDragAddItems': undefined;
|
||||
'AttachmentCaptionPlaceholder': undefined;
|
||||
'MessageSummaryTitle': undefined;
|
||||
'MessageSummaryDescription': undefined;
|
||||
'AriaShowSummary': undefined;
|
||||
'AriaHideSummary': undefined;
|
||||
'SettingsDataClearMediaCache': undefined;
|
||||
'SettingsDataClearMediaCacheDescription': undefined;
|
||||
'SettingsDataClearMediaDone': undefined;
|
||||
|
||||
@ -10,7 +10,7 @@ import { isUsernameValid } from './entities/username';
|
||||
export type DeepLinkMethod = 'resolve' | 'login' | 'passport' | 'settings' | 'join' | 'addstickers' | 'addemoji' |
|
||||
'setlanguage' | 'addtheme' | 'confirmphone' | 'socks' | 'proxy' | 'privatepost' | 'bg' | 'share' | 'msg' | 'msg_url' |
|
||||
'invoice' | 'addlist' | 'boost' | 'giftcode' | 'message' | 'premium_offer' | 'premium_multigift' | 'stars_topup'
|
||||
| 'nft' | 'stars' | 'ton' | 'stargift_auction';
|
||||
| 'nft' | 'stars' | 'ton' | 'stargift_auction' | 'premium';
|
||||
|
||||
interface PublicMessageLink {
|
||||
type: 'publicMessageLink';
|
||||
@ -91,7 +91,7 @@ interface BusinessChatLink {
|
||||
|
||||
interface PremiumReferrerLink {
|
||||
type: 'premiumReferrerLink';
|
||||
referrer: string;
|
||||
ref?: string;
|
||||
}
|
||||
|
||||
interface PremiumMultigiftLink {
|
||||
@ -268,7 +268,7 @@ function parseTgLink(url: URL) {
|
||||
case 'businessChatLink':
|
||||
return buildBusinessChatLink({ slug: queryParams.slug });
|
||||
case 'premiumReferrerLink':
|
||||
return buildPremiumReferrerLink({ referrer: queryParams.ref });
|
||||
return buildPremiumReferrerLink({ ref: queryParams.ref });
|
||||
case 'premiumMultigiftLink':
|
||||
return buildPremiumMultigiftLink({ referrer: queryParams.ref });
|
||||
case 'chatBoostLink':
|
||||
@ -488,6 +488,7 @@ function getTgDeepLinkType(
|
||||
case 'message':
|
||||
return 'businessChatLink';
|
||||
case 'premium_offer':
|
||||
case 'premium':
|
||||
return 'premiumReferrerLink';
|
||||
case 'premium_multigift':
|
||||
return 'premiumMultigiftLink';
|
||||
@ -774,16 +775,12 @@ function buildSettingsScreenLink(params: BuilderParams<SettingsScreenLink>): Bui
|
||||
|
||||
function buildPremiumReferrerLink(params: BuilderParams<PremiumReferrerLink>): BuilderReturnType<PremiumReferrerLink> {
|
||||
const {
|
||||
referrer,
|
||||
ref,
|
||||
} = params;
|
||||
|
||||
if (!referrer) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'premiumReferrerLink',
|
||||
referrer,
|
||||
ref,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user