Message: Introduce Invoice Media (#2093)
This commit is contained in:
parent
58413c6c61
commit
6e8b920525
@ -1,7 +1,4 @@
|
||||
import { Api as GramJs } from '../../../lib/gramjs';
|
||||
import {
|
||||
ApiMessageEntityTypes,
|
||||
} from '../../types';
|
||||
import type {
|
||||
ApiMessage,
|
||||
ApiMessageForwardInfo,
|
||||
@ -36,6 +33,10 @@ import type {
|
||||
PhoneCallAction,
|
||||
ApiWebDocument,
|
||||
ApiMessageEntityDefault,
|
||||
ApiMessageExtendedMediaPreview,
|
||||
} from '../../types';
|
||||
import {
|
||||
ApiMessageEntityTypes,
|
||||
} from '../../types';
|
||||
|
||||
import {
|
||||
@ -161,16 +162,21 @@ export function buildApiMessageWithChatId(chatId: string, mtpMessage: UniversalM
|
||||
content.action = action;
|
||||
}
|
||||
|
||||
const isInvoiceMedia = mtpMessage.media instanceof GramJs.MessageMediaInvoice
|
||||
&& Boolean(mtpMessage.media.extendedMedia);
|
||||
|
||||
const { replyToMsgId, replyToTopId, replyToPeerId } = mtpMessage.replyTo || {};
|
||||
const isEdited = mtpMessage.editDate && !mtpMessage.editHide;
|
||||
const {
|
||||
inlineButtons, keyboardButtons, keyboardPlaceholder, isKeyboardSingleUse,
|
||||
} = buildReplyButtons(mtpMessage) || {};
|
||||
} = buildReplyButtons(mtpMessage, isInvoiceMedia) || {};
|
||||
const forwardInfo = mtpMessage.fwdFrom && buildApiMessageForwardInfo(mtpMessage.fwdFrom, isChatWithSelf);
|
||||
const { replies, mediaUnread: isMediaUnread, postAuthor } = mtpMessage;
|
||||
const groupedId = mtpMessage.groupedId && String(mtpMessage.groupedId);
|
||||
const isInAlbum = Boolean(groupedId) && !(content.document || content.audio || content.sticker);
|
||||
const shouldHideKeyboardButtons = mtpMessage.replyMarkup instanceof GramJs.ReplyKeyboardHide;
|
||||
const isProtected = mtpMessage.noforwards || isInvoiceMedia;
|
||||
const isForwardingAllowed = !mtpMessage.noforwards;
|
||||
const emojiOnlyCount = content.text && parseEmojiOnlyString(content.text.text);
|
||||
|
||||
return {
|
||||
@ -205,7 +211,8 @@ export function buildApiMessageWithChatId(chatId: string, mtpMessage: UniversalM
|
||||
...(mtpMessage.viaBotId && { viaBotId: buildApiPeerId(mtpMessage.viaBotId, 'user') }),
|
||||
...(replies?.comments && { threadInfo: buildThreadInfo(replies, mtpMessage.id, chatId) }),
|
||||
...(postAuthor && { adminTitle: postAuthor }),
|
||||
...(mtpMessage.noforwards && { isProtected: true }),
|
||||
isProtected,
|
||||
isForwardingAllowed,
|
||||
};
|
||||
}
|
||||
|
||||
@ -336,6 +343,10 @@ export function buildMessageMediaContent(media: GramJs.TypeMessageMedia): ApiMes
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if ('extendedMedia' in media && media.extendedMedia instanceof GramJs.MessageExtendedMedia) {
|
||||
return buildMessageMediaContent(media.extendedMedia.media);
|
||||
}
|
||||
|
||||
const sticker = buildSticker(media);
|
||||
if (sticker) return { sticker };
|
||||
|
||||
@ -748,9 +759,12 @@ export function buildPoll(poll: GramJs.Poll, pollResults: GramJs.PollResults): A
|
||||
|
||||
export function buildInvoice(media: GramJs.MessageMediaInvoice): ApiInvoice {
|
||||
const {
|
||||
description: text, title, photo, test, totalAmount, currency, receiptMsgId,
|
||||
description: text, title, photo, test, totalAmount, currency, receiptMsgId, extendedMedia,
|
||||
} = media;
|
||||
|
||||
const preview = extendedMedia instanceof GramJs.MessageExtendedMediaPreview
|
||||
? buildApiMessageExtendedMediaPreview(extendedMedia) : undefined;
|
||||
|
||||
return {
|
||||
title,
|
||||
text,
|
||||
@ -759,6 +773,7 @@ export function buildInvoice(media: GramJs.MessageMediaInvoice): ApiInvoice {
|
||||
amount: Number(totalAmount),
|
||||
currency,
|
||||
isTest: test,
|
||||
extendedMedia: preview,
|
||||
};
|
||||
}
|
||||
|
||||
@ -1007,7 +1022,7 @@ function buildAction(
|
||||
};
|
||||
}
|
||||
|
||||
function buildReplyButtons(message: UniversalMessage): ApiReplyKeyboard | undefined {
|
||||
function buildReplyButtons(message: UniversalMessage, shouldSkipBuyButton?: boolean): ApiReplyKeyboard | undefined {
|
||||
const { replyMarkup, media } = message;
|
||||
|
||||
// TODO Move to the proper button inside preview
|
||||
@ -1033,7 +1048,7 @@ function buildReplyButtons(message: UniversalMessage): ApiReplyKeyboard | undefi
|
||||
}
|
||||
|
||||
const markup = replyMarkup.rows.map(({ buttons }) => {
|
||||
return buttons.map((button): ApiKeyboardButton => {
|
||||
return buttons.map((button): ApiKeyboardButton | undefined => {
|
||||
const { text } = button;
|
||||
|
||||
if (button instanceof GramJs.KeyboardButton) {
|
||||
@ -1096,6 +1111,7 @@ function buildReplyButtons(message: UniversalMessage): ApiReplyKeyboard | undefi
|
||||
receiptMessageId: media.receiptMsgId,
|
||||
};
|
||||
}
|
||||
if (shouldSkipBuyButton) return undefined;
|
||||
return {
|
||||
type: 'buy',
|
||||
text,
|
||||
@ -1155,9 +1171,11 @@ function buildReplyButtons(message: UniversalMessage): ApiReplyKeyboard | undefi
|
||||
type: 'unsupported',
|
||||
text,
|
||||
};
|
||||
});
|
||||
}).filter(Boolean);
|
||||
});
|
||||
|
||||
if (markup.every((row) => !row.length)) return undefined;
|
||||
|
||||
return {
|
||||
[replyMarkup instanceof GramJs.ReplyKeyboardMarkup ? 'keyboardButtons' : 'inlineButtons']: markup,
|
||||
...(replyMarkup instanceof GramJs.ReplyKeyboardMarkup && {
|
||||
@ -1368,6 +1386,21 @@ function buildUploadingMedia(
|
||||
};
|
||||
}
|
||||
|
||||
export function buildApiMessageExtendedMediaPreview(
|
||||
preview: GramJs.MessageExtendedMediaPreview,
|
||||
): ApiMessageExtendedMediaPreview {
|
||||
const {
|
||||
w, h, thumb, videoDuration,
|
||||
} = preview;
|
||||
|
||||
return {
|
||||
width: w,
|
||||
height: h,
|
||||
duration: videoDuration,
|
||||
thumbnail: thumb ? buildApiThumbnailFromStripped([thumb]) : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
export function buildApiWebDocument(document?: GramJs.TypeWebDocument): ApiWebDocument | undefined {
|
||||
if (!document) return undefined;
|
||||
|
||||
|
||||
@ -353,7 +353,7 @@ export function isMessageWithMedia(message: GramJs.Message | GramJs.UpdateServic
|
||||
media instanceof GramJs.MessageMediaGame
|
||||
&& (media.game.document instanceof GramJs.Document || media.game.photo instanceof GramJs.Photo)
|
||||
) || (
|
||||
media instanceof GramJs.MessageMediaInvoice && media.photo
|
||||
media instanceof GramJs.MessageMediaInvoice && (media.photo || media.extendedMedia)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@ -26,37 +26,48 @@ export function resolveMessageApiChatId(mtpMessage: GramJs.TypeMessage) {
|
||||
|
||||
export function addMessageToLocalDb(message: GramJs.Message | GramJs.MessageService) {
|
||||
const messageFullId = `${resolveMessageApiChatId(message)}-${message.id}`;
|
||||
localDb.messages[messageFullId] = message;
|
||||
|
||||
if (message instanceof GramJs.Message) {
|
||||
if (message.media instanceof GramJs.MessageMediaDocument
|
||||
&& message.media.document instanceof GramJs.Document
|
||||
let mockMessage = message;
|
||||
if (message instanceof GramJs.Message
|
||||
&& message.media instanceof GramJs.MessageMediaInvoice
|
||||
&& message.media.extendedMedia instanceof GramJs.MessageExtendedMedia) {
|
||||
mockMessage = new GramJs.Message({
|
||||
...message,
|
||||
media: message.media.extendedMedia.media,
|
||||
});
|
||||
}
|
||||
|
||||
localDb.messages[messageFullId] = mockMessage;
|
||||
|
||||
if (mockMessage instanceof GramJs.Message) {
|
||||
if (mockMessage.media instanceof GramJs.MessageMediaDocument
|
||||
&& mockMessage.media.document instanceof GramJs.Document
|
||||
) {
|
||||
localDb.documents[String(message.media.document.id)] = message.media.document;
|
||||
localDb.documents[String(mockMessage.media.document.id)] = mockMessage.media.document;
|
||||
}
|
||||
|
||||
if (message.media instanceof GramJs.MessageMediaWebPage
|
||||
&& message.media.webpage instanceof GramJs.WebPage
|
||||
&& message.media.webpage.document instanceof GramJs.Document
|
||||
if (mockMessage.media instanceof GramJs.MessageMediaWebPage
|
||||
&& mockMessage.media.webpage instanceof GramJs.WebPage
|
||||
&& mockMessage.media.webpage.document instanceof GramJs.Document
|
||||
) {
|
||||
localDb.documents[String(message.media.webpage.document.id)] = message.media.webpage.document;
|
||||
localDb.documents[String(mockMessage.media.webpage.document.id)] = mockMessage.media.webpage.document;
|
||||
}
|
||||
|
||||
if (message.media instanceof GramJs.MessageMediaGame) {
|
||||
if (message.media.game.document instanceof GramJs.Document) {
|
||||
localDb.documents[String(message.media.game.document.id)] = message.media.game.document;
|
||||
if (mockMessage.media instanceof GramJs.MessageMediaGame) {
|
||||
if (mockMessage.media.game.document instanceof GramJs.Document) {
|
||||
localDb.documents[String(mockMessage.media.game.document.id)] = mockMessage.media.game.document;
|
||||
}
|
||||
addPhotoToLocalDb(message.media.game.photo);
|
||||
addPhotoToLocalDb(mockMessage.media.game.photo);
|
||||
}
|
||||
|
||||
if (message.media instanceof GramJs.MessageMediaInvoice
|
||||
&& message.media.photo) {
|
||||
localDb.webDocuments[String(message.media.photo.url)] = message.media.photo;
|
||||
if (mockMessage.media instanceof GramJs.MessageMediaInvoice
|
||||
&& mockMessage.media.photo) {
|
||||
localDb.webDocuments[String(mockMessage.media.photo.url)] = mockMessage.media.photo;
|
||||
}
|
||||
}
|
||||
|
||||
if (message instanceof GramJs.MessageService && 'photo' in message.action) {
|
||||
addPhotoToLocalDb(message.action.photo);
|
||||
if (mockMessage instanceof GramJs.MessageService && 'photo' in mockMessage.action) {
|
||||
addPhotoToLocalDb(mockMessage.action.photo);
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,6 +101,24 @@ export function addEntitiesWithPhotosToLocalDb(entities: (GramJs.TypeUser | Gram
|
||||
});
|
||||
}
|
||||
|
||||
export function swapLocalInvoiceMedia(
|
||||
chatId: string, messageId: number, extendedMedia: GramJs.TypeMessageExtendedMedia,
|
||||
) {
|
||||
const localMessage = localDb.messages[`${chatId}-${messageId}`];
|
||||
if (!(localMessage instanceof GramJs.Message) || !localMessage.media) return;
|
||||
|
||||
if (extendedMedia instanceof GramJs.MessageExtendedMediaPreview) {
|
||||
if (!(localMessage.media instanceof GramJs.MessageMediaInvoice)) {
|
||||
return;
|
||||
}
|
||||
localMessage.media.extendedMedia = extendedMedia;
|
||||
}
|
||||
|
||||
if (extendedMedia instanceof GramJs.MessageExtendedMedia) {
|
||||
localMessage.media = extendedMedia.media;
|
||||
}
|
||||
}
|
||||
|
||||
export function serializeBytes(value: Buffer) {
|
||||
return String.fromCharCode(...value);
|
||||
}
|
||||
|
||||
@ -29,7 +29,7 @@ export {
|
||||
fetchPinnedMessages, fetchScheduledHistory, sendScheduledMessages, rescheduleMessage, deleteScheduledMessages,
|
||||
reportMessages, sendMessageAction, fetchSeenBy, fetchSponsoredMessages, viewSponsoredMessage, fetchSendAs,
|
||||
saveDefaultSendAs, fetchUnreadReactions, readAllReactions, fetchUnreadMentions, readAllMentions, transcribeAudio,
|
||||
closePoll,
|
||||
closePoll, fetchExtendedMedia,
|
||||
} from './messages';
|
||||
|
||||
export {
|
||||
|
||||
@ -1122,6 +1122,18 @@ export async function loadPollOptionResults({
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchExtendedMedia({
|
||||
chat, ids,
|
||||
} : {
|
||||
chat: ApiChat;
|
||||
ids: number[];
|
||||
}) {
|
||||
await invokeRequest(new GramJs.messages.GetExtendedMedia({
|
||||
peer: buildInputPeer(chat.id, chat.accessHash),
|
||||
id: ids,
|
||||
}));
|
||||
}
|
||||
|
||||
export async function forwardMessages({
|
||||
fromChat,
|
||||
toChat,
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
import type { GroupCallConnectionData } from '../../lib/secret-sauce';
|
||||
import { Api as GramJs, connection } from '../../lib/gramjs';
|
||||
import type { ApiMessage, ApiUpdateConnectionStateType, OnApiUpdate } from '../types';
|
||||
import type {
|
||||
ApiMessage, ApiMessageExtendedMediaPreview, ApiUpdateConnectionStateType, OnApiUpdate,
|
||||
} from '../types';
|
||||
|
||||
import { pick } from '../../util/iteratees';
|
||||
import {
|
||||
@ -14,6 +16,7 @@ import {
|
||||
buildApiMessageFromNotification,
|
||||
buildMessageDraft,
|
||||
buildMessageReactions,
|
||||
buildApiMessageExtendedMediaPreview,
|
||||
} from './apiBuilders/messages';
|
||||
import {
|
||||
buildChatMember,
|
||||
@ -40,6 +43,7 @@ import {
|
||||
resolveMessageApiChatId,
|
||||
serializeBytes,
|
||||
log,
|
||||
swapLocalInvoiceMedia,
|
||||
} from './helpers';
|
||||
import { buildApiNotifyException, buildPrivacyKey, buildPrivacyRules } from './apiBuilders/misc';
|
||||
import { buildApiPhoto } from './apiBuilders/common';
|
||||
@ -309,6 +313,30 @@ export function updater(update: Update, originRequest?: GramJs.AnyRequest) {
|
||||
chatId: getApiChatIdFromMtpPeer(update.peer),
|
||||
reactions: buildMessageReactions(update.reactions),
|
||||
});
|
||||
} else if (update instanceof GramJs.UpdateMessageExtendedMedia) {
|
||||
let media: ApiMessage['content'] | undefined;
|
||||
if (update.extendedMedia instanceof GramJs.MessageExtendedMedia) {
|
||||
media = buildMessageMediaContent(update.extendedMedia.media);
|
||||
}
|
||||
|
||||
let preview: ApiMessageExtendedMediaPreview | undefined;
|
||||
if (update.extendedMedia instanceof GramJs.MessageExtendedMediaPreview) {
|
||||
preview = buildApiMessageExtendedMediaPreview(update.extendedMedia);
|
||||
}
|
||||
|
||||
if (!media && !preview) return;
|
||||
|
||||
const chatId = getApiChatIdFromMtpPeer(update.peer);
|
||||
|
||||
swapLocalInvoiceMedia(chatId, update.msgId, update.extendedMedia);
|
||||
|
||||
onUpdate({
|
||||
'@type': 'updateMessageExtendedMedia',
|
||||
id: update.msgId,
|
||||
chatId,
|
||||
media,
|
||||
preview,
|
||||
});
|
||||
} else if (update instanceof GramJs.UpdateDeleteMessages) {
|
||||
onUpdate({
|
||||
'@type': 'deleteMessages',
|
||||
|
||||
@ -187,10 +187,18 @@ export interface ApiInvoice {
|
||||
isTest?: boolean;
|
||||
isRecurring?: boolean;
|
||||
recurringTermsUrl?: string;
|
||||
extendedMedia?: ApiMessageExtendedMediaPreview;
|
||||
maxTipAmount?: number;
|
||||
suggestedTipAmounts?: number[];
|
||||
}
|
||||
|
||||
export interface ApiMessageExtendedMediaPreview {
|
||||
width?: number;
|
||||
height?: number;
|
||||
thumbnail?: ApiThumbnail;
|
||||
duration?: number;
|
||||
}
|
||||
|
||||
export interface ApiPaymentCredentials {
|
||||
id: string;
|
||||
title: string;
|
||||
@ -406,6 +414,7 @@ export interface ApiMessage {
|
||||
isSilent?: boolean;
|
||||
seenByUserIds?: string[];
|
||||
isProtected?: boolean;
|
||||
isForwardingAllowed?: boolean;
|
||||
transcriptionId?: string;
|
||||
isTranscriptionError?: boolean;
|
||||
emojiOnlyCount?: number;
|
||||
|
||||
@ -13,7 +13,14 @@ import type {
|
||||
ApiChatFolder,
|
||||
} from './chats';
|
||||
import type {
|
||||
ApiFormattedText, ApiMessage, ApiPhoto, ApiPoll, ApiReactions, ApiStickerSet, ApiThreadInfo,
|
||||
ApiFormattedText,
|
||||
ApiMessage,
|
||||
ApiMessageExtendedMediaPreview,
|
||||
ApiPhoto,
|
||||
ApiPoll,
|
||||
ApiReactions,
|
||||
ApiStickerSet,
|
||||
ApiThreadInfo,
|
||||
} from './messages';
|
||||
import type {
|
||||
ApiEmojiStatus, ApiUser, ApiUserFullInfo, ApiUserStatus,
|
||||
@ -309,6 +316,14 @@ export type ApiUpdateMessageReactions = {
|
||||
reactions: ApiReactions;
|
||||
};
|
||||
|
||||
export type ApiUpdateMessageExtendedMedia = {
|
||||
'@type': 'updateMessageExtendedMedia';
|
||||
id: number;
|
||||
chatId: string;
|
||||
media?: ApiMessage['content'];
|
||||
preview?: ApiMessageExtendedMediaPreview;
|
||||
};
|
||||
|
||||
export type ApiDeleteContact = {
|
||||
'@type': 'deleteContact';
|
||||
id: string;
|
||||
@ -556,7 +571,8 @@ export type ApiUpdate = (
|
||||
ApiUpdateGroupCallConnectionState | ApiUpdateGroupCallLeavePresentation | ApiUpdateGroupCallChatId |
|
||||
ApiUpdatePendingJoinRequests | ApiUpdatePaymentVerificationNeeded | ApiUpdatePaymentStateCompleted |
|
||||
ApiUpdatePhoneCall | ApiUpdatePhoneCallSignalingData | ApiUpdatePhoneCallMediaState |
|
||||
ApiUpdatePhoneCallConnectionState | ApiUpdateBotMenuButton | ApiUpdateTranscribedAudio | ApiUpdateUserEmojiStatus
|
||||
ApiUpdatePhoneCallConnectionState | ApiUpdateBotMenuButton | ApiUpdateTranscribedAudio | ApiUpdateUserEmojiStatus |
|
||||
ApiUpdateMessageExtendedMedia
|
||||
);
|
||||
|
||||
export type OnApiUpdate = (update: ApiUpdate) => void;
|
||||
|
||||
BIN
src/assets/turbulence.png
Normal file
BIN
src/assets/turbulence.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 39 KiB |
BIN
src/assets/turbulence_2x.png
Normal file
BIN
src/assets/turbulence_2x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
@ -81,7 +81,7 @@ function getAvailableHeight(isGif?: boolean, aspectRatio?: number) {
|
||||
return 27 * REM;
|
||||
}
|
||||
|
||||
function calculateDimensionsForMessageMedia({
|
||||
export function calculateDimensionsForMessageMedia({
|
||||
width,
|
||||
height,
|
||||
fromOwnMessage,
|
||||
|
||||
@ -320,7 +320,6 @@ const MediaViewer: FC<StateProps> = ({
|
||||
onForward={handleForward}
|
||||
zoomLevelChange={zoomLevelChange}
|
||||
setZoomLevelChange={setZoomLevelChange}
|
||||
isAvatar={Boolean(avatarOwner)}
|
||||
/>
|
||||
<ReportModal
|
||||
isOpen={isReportModalOpen}
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import type { FC } from '../../lib/teact/teact';
|
||||
import React, {
|
||||
memo,
|
||||
useCallback,
|
||||
@ -6,21 +5,27 @@ import React, {
|
||||
} from '../../lib/teact/teact';
|
||||
import { getActions, withGlobal } from '../../global';
|
||||
|
||||
import type { FC } from '../../lib/teact/teact';
|
||||
import type { ApiMessage } from '../../api/types';
|
||||
import type { MessageListType } from '../../global/types';
|
||||
import type { MenuItemProps } from '../ui/MenuItem';
|
||||
|
||||
import {
|
||||
selectIsDownloading,
|
||||
selectIsMessageProtected,
|
||||
selectAllowedMessageActions,
|
||||
selectCurrentMessageList,
|
||||
selectIsChatProtected,
|
||||
} from '../../global/selectors';
|
||||
import { IS_SINGLE_COLUMN_LAYOUT } from '../../util/environment';
|
||||
import { getMessageMediaFormat, getMessageMediaHash } from '../../global/helpers';
|
||||
|
||||
import useLang from '../../hooks/useLang';
|
||||
import useMediaWithLoadProgress from '../../hooks/useMediaWithLoadProgress';
|
||||
import useFlag from '../../hooks/useFlag';
|
||||
import {
|
||||
selectIsDownloading, selectIsMessageProtected, selectAllowedMessageActions, selectCurrentMessageList,
|
||||
} from '../../global/selectors';
|
||||
|
||||
import Button from '../ui/Button';
|
||||
import DropdownMenu from '../ui/DropdownMenu';
|
||||
import type { MenuItemProps } from '../ui/MenuItem';
|
||||
import MenuItem from '../ui/MenuItem';
|
||||
import ProgressSpinner from '../ui/ProgressSpinner';
|
||||
import DeleteMessageModal from '../common/DeleteMessageModal';
|
||||
@ -30,6 +35,7 @@ import './MediaViewerActions.scss';
|
||||
type StateProps = {
|
||||
isDownloading: boolean;
|
||||
isProtected?: boolean;
|
||||
isChatProtected?: boolean;
|
||||
canDelete?: boolean;
|
||||
messageListType?: MessageListType;
|
||||
};
|
||||
@ -40,7 +46,6 @@ type OwnProps = {
|
||||
zoomLevelChange: number;
|
||||
message?: ApiMessage;
|
||||
fileName?: string;
|
||||
isAvatar?: boolean;
|
||||
canReport?: boolean;
|
||||
onReport: NoneToVoidFunction;
|
||||
onCloseMediaViewer: NoneToVoidFunction;
|
||||
@ -53,17 +58,17 @@ const MediaViewerActions: FC<OwnProps & StateProps> = ({
|
||||
isVideo,
|
||||
message,
|
||||
fileName,
|
||||
isAvatar,
|
||||
isChatProtected,
|
||||
isDownloading,
|
||||
isProtected,
|
||||
canReport,
|
||||
zoomLevelChange,
|
||||
canDelete,
|
||||
messageListType,
|
||||
onReport,
|
||||
onCloseMediaViewer,
|
||||
zoomLevelChange,
|
||||
setZoomLevelChange,
|
||||
canDelete,
|
||||
onForward,
|
||||
messageListType,
|
||||
setZoomLevelChange,
|
||||
}) => {
|
||||
const [isDeleteModalOpen, openDeleteModal, closeDeleteModal] = useFlag(false);
|
||||
|
||||
@ -148,7 +153,7 @@ const MediaViewerActions: FC<OwnProps & StateProps> = ({
|
||||
|
||||
if (IS_SINGLE_COLUMN_LAYOUT) {
|
||||
const menuItems: MenuItemProps[] = [];
|
||||
if (!isAvatar && !isProtected) {
|
||||
if (!message?.isForwardingAllowed && !isChatProtected) {
|
||||
menuItems.push({
|
||||
icon: 'forward',
|
||||
onClick: onForward,
|
||||
@ -227,7 +232,7 @@ const MediaViewerActions: FC<OwnProps & StateProps> = ({
|
||||
|
||||
return (
|
||||
<div className="MediaViewerActions">
|
||||
{!isAvatar && !isProtected && (
|
||||
{message?.isForwardingAllowed && !isChatProtected && (
|
||||
<Button
|
||||
round
|
||||
size="smaller"
|
||||
@ -306,12 +311,14 @@ export default memo(withGlobal<OwnProps>(
|
||||
const { threadId } = selectCurrentMessageList(global) || {};
|
||||
const isDownloading = message ? selectIsDownloading(global, message) : false;
|
||||
const isProtected = selectIsMessageProtected(global, message);
|
||||
const isChatProtected = message && selectIsChatProtected(global, message?.chatId);
|
||||
const { canDelete } = (threadId && message && selectAllowedMessageActions(global, message, threadId)) || {};
|
||||
const messageListType = currentMessageList?.type;
|
||||
|
||||
return {
|
||||
isDownloading,
|
||||
isProtected,
|
||||
isChatProtected,
|
||||
canDelete,
|
||||
messageListType,
|
||||
};
|
||||
|
||||
@ -14,7 +14,7 @@ import {
|
||||
selectActiveDownloadIds,
|
||||
selectAllowedMessageActions,
|
||||
selectChat,
|
||||
selectCurrentMessageList, selectIsCurrentUserPremium,
|
||||
selectCurrentMessageList, selectIsChatProtected, selectIsCurrentUserPremium,
|
||||
selectIsMessageProtected,
|
||||
selectIsPremiumPurchaseBlocked,
|
||||
selectMessageCustomEmojiSets,
|
||||
@ -535,6 +535,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
&& !areReactionsEmpty(message.reactions) && message.reactions.canSeeList;
|
||||
const canRemoveReaction = isPrivate && message.reactions?.results?.some((l) => l.isChosen);
|
||||
const isProtected = selectIsMessageProtected(global, message);
|
||||
const isChatProtected = selectIsChatProtected(global, message.chatId);
|
||||
const canCopyNumber = Boolean(message.content.contact);
|
||||
const isCurrentUserPremium = selectIsCurrentUserPremium(global);
|
||||
|
||||
@ -554,11 +555,11 @@ export default memo(withGlobal<OwnProps>(
|
||||
canDelete,
|
||||
canReport,
|
||||
canEdit: !isPinned && canEdit,
|
||||
canForward: !isProtected && !isScheduled && canForward,
|
||||
canForward: message.isForwardingAllowed && !isChatProtected && !isScheduled && canForward,
|
||||
canFaveSticker: !isScheduled && canFaveSticker,
|
||||
canUnfaveSticker: !isScheduled && canUnfaveSticker,
|
||||
canCopy: canCopyNumber || (!isProtected && canCopy),
|
||||
canCopyLink: !isProtected && !isScheduled && canCopyLink,
|
||||
canCopyLink: !isScheduled && canCopyLink,
|
||||
canSelect,
|
||||
canDownload: !isProtected && canDownload,
|
||||
canSaveGif: !isProtected && canSaveGif,
|
||||
|
||||
117
src/components/middle/message/InvoiceMediaPreview.module.scss
Normal file
117
src/components/middle/message/InvoiceMediaPreview.module.scss
Normal file
@ -0,0 +1,117 @@
|
||||
.root {
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dots {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
--background-url: url('../../../assets/turbulence.png');
|
||||
--background-size: 256px;
|
||||
background: rgba(0, 0, 0, 0.3) var(--background-url);
|
||||
background-size: var(--background-size) var(--background-size);
|
||||
z-index: 1;
|
||||
|
||||
--x-direction: var(--background-size);
|
||||
--y-direction: 0;
|
||||
animation: 10s linear infinite dots;
|
||||
|
||||
&.highres {
|
||||
--background-url: url('../../../assets/turbulence_2x.png');
|
||||
--background-size: 128px;
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: var(--background-url);
|
||||
background-size: var(--background-size) var(--background-size);
|
||||
|
||||
--x-direction: 0;
|
||||
--y-direction: var(--background-size);
|
||||
animation: 10s linear -4s infinite dots;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: var(--background-url);
|
||||
background-size: var(--background-size) var(--background-size);
|
||||
|
||||
--x-direction: calc(-1 * var(--background-size));
|
||||
--y-direction: calc(-1 * var(--background-size));
|
||||
animation: 10s linear -8s infinite dots;
|
||||
}
|
||||
}
|
||||
|
||||
.duration {
|
||||
z-index: 2;
|
||||
position: absolute;
|
||||
top: 0.25rem;
|
||||
left: 0.25rem;
|
||||
|
||||
white-space: nowrap;
|
||||
font-size: 0.75rem;
|
||||
padding: 0 0.375rem;
|
||||
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
color: #FFFFFF;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.buy {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.375rem;
|
||||
|
||||
z-index: 2;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
padding: 0.375rem 0.625rem;
|
||||
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
color: #FFFFFF;
|
||||
border-radius: 1rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.lock {
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
|
||||
.canvas {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
@keyframes dots {
|
||||
0% {
|
||||
background-position: 0 0;
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.75;
|
||||
}
|
||||
100% {
|
||||
background-position: var(--x-direction) var(--y-direction);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
78
src/components/middle/message/InvoiceMediaPreview.tsx
Normal file
78
src/components/middle/message/InvoiceMediaPreview.tsx
Normal file
@ -0,0 +1,78 @@
|
||||
import React, { memo, useCallback } from '../../../lib/teact/teact';
|
||||
import { getActions } from '../../../global';
|
||||
|
||||
import type { FC } from '../../../lib/teact/teact';
|
||||
import type { ApiMessage } from '../../../api/types';
|
||||
|
||||
import { getMessageInvoice } from '../../../global/helpers';
|
||||
import { formatCurrency } from '../../../util/formatCurrency';
|
||||
import { formatMediaDuration } from '../../../util/dateFormat';
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
import { DPR } from '../../../util/environment';
|
||||
|
||||
import useLang from '../../../hooks/useLang';
|
||||
import useCanvasBlur from '../../../hooks/useCanvasBlur';
|
||||
import useInterval from '../../../hooks/useInterval';
|
||||
|
||||
import styles from './InvoiceMediaPreview.module.scss';
|
||||
|
||||
type OwnProps = {
|
||||
message: ApiMessage;
|
||||
lastSyncTime?: number;
|
||||
};
|
||||
|
||||
const POLLING_INTERVAL = 30000;
|
||||
const BLUR_RADIUS = 25;
|
||||
|
||||
const InvoiceMediaPreview: FC<OwnProps> = ({
|
||||
message,
|
||||
lastSyncTime,
|
||||
}) => {
|
||||
const { openInvoice, loadExtendedMedia } = getActions();
|
||||
const lang = useLang();
|
||||
const invoice = getMessageInvoice(message);
|
||||
|
||||
const { chatId, id } = message;
|
||||
|
||||
const refreshExtendedMedia = useCallback(() => {
|
||||
loadExtendedMedia({ chatId, ids: [id] });
|
||||
}, [chatId, id, loadExtendedMedia]);
|
||||
|
||||
useInterval(refreshExtendedMedia, lastSyncTime ? POLLING_INTERVAL : undefined);
|
||||
|
||||
const {
|
||||
amount,
|
||||
currency,
|
||||
extendedMedia,
|
||||
} = invoice!;
|
||||
|
||||
const {
|
||||
width, height, thumbnail, duration,
|
||||
} = extendedMedia!;
|
||||
|
||||
const canvasRef = useCanvasBlur(thumbnail?.dataUri, false, undefined, BLUR_RADIUS, width, height);
|
||||
|
||||
const handleClick = useCallback(() => {
|
||||
openInvoice({
|
||||
chatId,
|
||||
messageId: id,
|
||||
});
|
||||
}, [chatId, id, openInvoice]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={buildClassName(styles.root, 'media-inner')}
|
||||
onClick={handleClick}
|
||||
>
|
||||
<canvas ref={canvasRef} className={styles.canvas} width={width} height={height} />
|
||||
<div className={buildClassName(styles.dots, DPR > 1 && styles.highres)} />
|
||||
{Boolean(duration) && <div className={styles.duration}>{formatMediaDuration(duration)}</div>}
|
||||
<div className={styles.buy}>
|
||||
<i className={buildClassName('icon-lock', styles.lock)} />
|
||||
{lang('Checkout.PayPrice', formatCurrency(amount, currency))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(InvoiceMediaPreview);
|
||||
@ -56,6 +56,7 @@ import {
|
||||
selectAnimatedEmoji,
|
||||
selectLocalAnimatedEmoji,
|
||||
selectIsCurrentUserPremium,
|
||||
selectIsChatProtected,
|
||||
} from '../../../global/selectors';
|
||||
import {
|
||||
getMessageContent,
|
||||
@ -79,7 +80,7 @@ import buildClassName from '../../../util/buildClassName';
|
||||
import useEnsureMessage from '../../../hooks/useEnsureMessage';
|
||||
import useContextMenuHandlers from '../../../hooks/useContextMenuHandlers';
|
||||
import { renderMessageText } from '../../common/helpers/renderMessageText';
|
||||
import { ROUND_VIDEO_DIMENSIONS_PX } from '../../common/helpers/mediaDimensions';
|
||||
import { calculateDimensionsForMessageMedia, ROUND_VIDEO_DIMENSIONS_PX } from '../../common/helpers/mediaDimensions';
|
||||
import { buildContentClassName } from './helpers/buildContentClassName';
|
||||
import { getMinMediaWidth, calculateMediaDimensions } from './helpers/mediaDimensions';
|
||||
import { calculateAlbumLayout } from './helpers/calculateAlbumLayout';
|
||||
@ -113,6 +114,7 @@ import Contact from './Contact';
|
||||
import Poll from './Poll';
|
||||
import WebPage from './WebPage';
|
||||
import Invoice from './Invoice';
|
||||
import InvoiceMediaPreview from './InvoiceMediaPreview';
|
||||
import Location from './Location';
|
||||
import Game from './Game';
|
||||
import Album from './Album';
|
||||
@ -172,6 +174,7 @@ type StateProps = {
|
||||
uploadProgress?: number;
|
||||
isInDocumentGroup: boolean;
|
||||
isProtected?: boolean;
|
||||
isChatProtected?: boolean;
|
||||
isFocused?: boolean;
|
||||
focusDirection?: FocusDirection;
|
||||
noFocusHighlight?: boolean;
|
||||
@ -263,6 +266,7 @@ const Message: FC<OwnProps & StateProps> = ({
|
||||
uploadProgress,
|
||||
isInDocumentGroup,
|
||||
isProtected,
|
||||
isChatProtected,
|
||||
isFocused,
|
||||
focusDirection,
|
||||
noFocusHighlight,
|
||||
@ -371,7 +375,7 @@ const Message: FC<OwnProps & StateProps> = ({
|
||||
!(isContextMenuShown || isInSelectMode || isForwarding)
|
||||
&& !isInDocumentGroupNotLast
|
||||
);
|
||||
const canForward = isChannel && !isScheduled && !isProtected;
|
||||
const canForward = isChannel && !isScheduled && message.isForwardingAllowed && !isChatProtected;
|
||||
const canFocus = Boolean(isPinnedList
|
||||
|| (forwardInfo
|
||||
&& (forwardInfo.isChannelPost || (isChatWithSelf && !isOwn) || isRepliesChat)
|
||||
@ -579,7 +583,7 @@ const Message: FC<OwnProps & StateProps> = ({
|
||||
}, [isAlbum, isOwn, asForwarded, noAvatars, album]);
|
||||
|
||||
const extraPadding = asForwarded ? 28 : 0;
|
||||
if (!isAlbum && (photo || video)) {
|
||||
if (!isAlbum && (photo || video || invoice?.extendedMedia)) {
|
||||
let width: number | undefined;
|
||||
if (photo) {
|
||||
width = calculateMediaDimensions(message, noAvatars).width;
|
||||
@ -589,6 +593,17 @@ const Message: FC<OwnProps & StateProps> = ({
|
||||
} else {
|
||||
width = calculateMediaDimensions(message, noAvatars).width;
|
||||
}
|
||||
} else if (invoice?.extendedMedia && (
|
||||
invoice.extendedMedia.width && invoice.extendedMedia.height
|
||||
)) {
|
||||
const { width: previewWidth, height: previewHeight } = invoice.extendedMedia;
|
||||
width = calculateDimensionsForMessageMedia({
|
||||
width: previewWidth,
|
||||
height: previewHeight,
|
||||
fromOwnMessage: isOwn,
|
||||
isForwarded: isForwarding,
|
||||
noAvatars,
|
||||
}).width;
|
||||
}
|
||||
|
||||
if (width) {
|
||||
@ -840,6 +855,12 @@ const Message: FC<OwnProps & StateProps> = ({
|
||||
lastSyncTime={lastSyncTime}
|
||||
/>
|
||||
)}
|
||||
{invoice?.extendedMedia && (
|
||||
<InvoiceMediaPreview
|
||||
message={message}
|
||||
lastSyncTime={lastSyncTime}
|
||||
/>
|
||||
)}
|
||||
|
||||
{withVoiceTranscription && (
|
||||
<p
|
||||
@ -877,7 +898,7 @@ const Message: FC<OwnProps & StateProps> = ({
|
||||
theme={theme}
|
||||
/>
|
||||
)}
|
||||
{invoice && (
|
||||
{invoice && !invoice.extendedMedia && (
|
||||
<Invoice
|
||||
message={message}
|
||||
shouldAffectAppendix={hasCustomAppendix}
|
||||
@ -1176,6 +1197,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
replyMessageSender,
|
||||
isInDocumentGroup,
|
||||
isProtected: selectIsMessageProtected(global, message),
|
||||
isChatProtected: selectIsChatProtected(global, chatId),
|
||||
isFocused,
|
||||
isForwarding,
|
||||
reactionMessage,
|
||||
|
||||
@ -36,7 +36,7 @@ export function buildContentClassName(
|
||||
} = getMessageContent(message);
|
||||
|
||||
const classNames = ['message-content'];
|
||||
const isMedia = photo || video || location;
|
||||
const isMedia = photo || video || location || invoice?.extendedMedia;
|
||||
const hasText = text || location?.type === 'venue' || isGeoLiveActive;
|
||||
const isMediaWithNoText = isMedia && !hasText;
|
||||
const isViaBot = Boolean(message.viaBotId);
|
||||
@ -87,7 +87,7 @@ export function buildContentClassName(
|
||||
}
|
||||
}
|
||||
|
||||
if (invoice) {
|
||||
if (invoice && !invoice.extendedMedia) {
|
||||
classNames.push('invoice');
|
||||
}
|
||||
|
||||
|
||||
@ -608,6 +608,14 @@ addActionHandler('loadPollOptionResults', (global, actions, payload) => {
|
||||
void loadPollOptionResults(chat, messageId, option, offset, limit, shouldResetVoters);
|
||||
});
|
||||
|
||||
addActionHandler('loadExtendedMedia', (global, actions, payload) => {
|
||||
const { chatId, ids } = payload;
|
||||
const chat = selectChat(global, chatId);
|
||||
if (chat) {
|
||||
void callApi('fetchExtendedMedia', { chat, ids });
|
||||
}
|
||||
});
|
||||
|
||||
addActionHandler('forwardMessages', (global, action, payload) => {
|
||||
const {
|
||||
fromChatId, messageIds, toChatId, withMyScore, noAuthors, noCaptions,
|
||||
|
||||
@ -511,6 +511,37 @@ addActionHandler('apiUpdate', (global, actions, update) => {
|
||||
break;
|
||||
}
|
||||
|
||||
case 'updateMessageExtendedMedia': {
|
||||
const {
|
||||
chatId, id, media, preview,
|
||||
} = update;
|
||||
const message = selectChatMessage(global, chatId, id);
|
||||
const chat = selectChat(global, update.chatId);
|
||||
|
||||
if (!chat || !message) return;
|
||||
|
||||
if (preview) {
|
||||
if (!message.content.invoice) return;
|
||||
setGlobal(updateChatMessage(global, chatId, id, {
|
||||
content: {
|
||||
...message.content,
|
||||
invoice: {
|
||||
...message.content.invoice,
|
||||
extendedMedia: preview,
|
||||
},
|
||||
},
|
||||
}));
|
||||
} else if (media) {
|
||||
setGlobal(updateChatMessage(global, chatId, id, {
|
||||
content: {
|
||||
...media,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'updateTranscribedAudio': {
|
||||
const { transcriptionId, text, isPending } = update;
|
||||
|
||||
|
||||
@ -166,7 +166,7 @@ export function getMessageSummaryDescription(
|
||||
}
|
||||
|
||||
if (invoice) {
|
||||
summary = `${lang('PaymentInvoice')}: ${invoice.text}`;
|
||||
summary = invoice.extendedMedia ? invoice.title : `${lang('PaymentInvoice')}: ${invoice.text}`;
|
||||
}
|
||||
|
||||
if (text) {
|
||||
|
||||
@ -901,7 +901,11 @@ export function selectLastServiceNotification(global: GlobalState) {
|
||||
}
|
||||
|
||||
export function selectIsMessageProtected(global: GlobalState, message?: ApiMessage) {
|
||||
return message ? message.isProtected || selectChat(global, message.chatId)?.isProtected : false;
|
||||
return Boolean(message && (message.isProtected || selectIsChatProtected(global, message.chatId)));
|
||||
}
|
||||
|
||||
export function selectIsChatProtected(global: GlobalState, chatId: string) {
|
||||
return selectChat(global, chatId)?.isProtected || false;
|
||||
}
|
||||
|
||||
export function selectHasProtectedMessage(global: GlobalState, chatId: string, messageIds?: number[]) {
|
||||
|
||||
@ -790,6 +790,11 @@ export interface ActionPayloads {
|
||||
messageId: number;
|
||||
};
|
||||
|
||||
loadExtendedMedia: {
|
||||
chatId: string;
|
||||
ids: number[];
|
||||
};
|
||||
|
||||
// Media Viewer & Audio Player
|
||||
openMediaViewer: {
|
||||
chatId?: string;
|
||||
|
||||
@ -7,7 +7,14 @@ import { IS_CANVAS_FILTER_SUPPORTED } from '../util/environment';
|
||||
const RADIUS = 2;
|
||||
const ITERATIONS = 2;
|
||||
|
||||
export default function useCanvasBlur(dataUri?: string, isDisabled = false, withRaf?: boolean) {
|
||||
export default function useCanvasBlur(
|
||||
dataUri?: string,
|
||||
isDisabled = false,
|
||||
withRaf?: boolean,
|
||||
radius = RADIUS,
|
||||
preferredWidth?: number,
|
||||
preferredHeight?: number,
|
||||
) {
|
||||
// eslint-disable-next-line no-null/no-null
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||
const forceUpdate = useForceUpdate();
|
||||
@ -22,19 +29,19 @@ export default function useCanvasBlur(dataUri?: string, isDisabled = false, with
|
||||
const img = new Image();
|
||||
|
||||
const processBlur = () => {
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
canvas.width = preferredWidth || img.width;
|
||||
canvas.height = preferredHeight || img.height;
|
||||
|
||||
const ctx = canvas.getContext('2d', { alpha: false })!;
|
||||
|
||||
if (IS_CANVAS_FILTER_SUPPORTED) {
|
||||
ctx.filter = `blur(${RADIUS}px)`;
|
||||
ctx.filter = `blur(${radius}px)`;
|
||||
}
|
||||
|
||||
ctx.drawImage(img, -RADIUS * 2, -RADIUS * 2, canvas.width + RADIUS * 4, canvas.height + RADIUS * 4);
|
||||
ctx.drawImage(img, -radius * 2, -radius * 2, canvas.width + radius * 4, canvas.height + radius * 4);
|
||||
|
||||
if (!IS_CANVAS_FILTER_SUPPORTED) {
|
||||
fastBlur(ctx, 0, 0, canvas.width, canvas.height, RADIUS, ITERATIONS);
|
||||
fastBlur(ctx, 0, 0, canvas.width, canvas.height, radius, ITERATIONS);
|
||||
}
|
||||
};
|
||||
|
||||
@ -47,7 +54,7 @@ export default function useCanvasBlur(dataUri?: string, isDisabled = false, with
|
||||
};
|
||||
|
||||
img.src = dataUri;
|
||||
}, [canvasRef, dataUri, forceUpdate, isDisabled, withRaf]);
|
||||
}, [canvasRef, dataUri, forceUpdate, isDisabled, preferredHeight, preferredWidth, withRaf, radius]);
|
||||
|
||||
return canvasRef;
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
const api = require('./api');
|
||||
|
||||
const LAYER = 145;
|
||||
const LAYER = 146;
|
||||
const tlobjects = {};
|
||||
|
||||
for (const tl of Object.values(api)) {
|
||||
|
||||
43
src/lib/gramjs/tl/api.d.ts
vendored
43
src/lib/gramjs/tl/api.d.ts
vendored
File diff suppressed because one or more lines are too long
@ -29,7 +29,7 @@ inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string pro
|
||||
inputMediaPhotoExternal#e5bbfe1a flags:# url:string ttl_seconds:flags.0?int = InputMedia;
|
||||
inputMediaDocumentExternal#fb52dc99 flags:# url:string ttl_seconds:flags.0?int = InputMedia;
|
||||
inputMediaGame#d33f43f3 id:InputGame = InputMedia;
|
||||
inputMediaInvoice#d9799874 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:flags.1?string = InputMedia;
|
||||
inputMediaInvoice#8eb5a6d5 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:flags.1?string extended_media:flags.2?InputMedia = InputMedia;
|
||||
inputMediaGeoLive#971fa843 flags:# stopped:flags.0?true geo_point:InputGeoPoint heading:flags.2?int period:flags.1?int proximity_notification_radius:flags.3?int = InputMedia;
|
||||
inputMediaPoll#f94e5f1 flags:# poll:Poll correct_answers:flags.0?Vector<bytes> solution:flags.1?string solution_entities:flags.1?Vector<MessageEntity> = InputMedia;
|
||||
inputMediaDice#e66fbf7b emoticon:string = InputMedia;
|
||||
@ -99,7 +99,7 @@ messageMediaDocument#9cb070d7 flags:# nopremium:flags.3?true document:flags.0?Do
|
||||
messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia;
|
||||
messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia;
|
||||
messageMediaGame#fdb19008 game:Game = MessageMedia;
|
||||
messageMediaInvoice#84551347 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 = 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;
|
||||
@ -314,6 +314,7 @@ updateUserEmojiStatus#28373599 user_id:long emoji_status:EmojiStatus = Update;
|
||||
updateRecentEmojiStatuses#30f443db = Update;
|
||||
updateRecentReactions#6f7863f4 = Update;
|
||||
updateMoveStickerSetToTop#86fccf85 flags:# masks:flags.0?true emojis:flags.1?true stickerset:long = Update;
|
||||
updateMessageExtendedMedia#5a73a98c peer:Peer msg_id:int extended_media:MessageExtendedMedia = 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;
|
||||
@ -1042,6 +1043,8 @@ account.emailVerified#2b96cd1b email:string = account.EmailVerified;
|
||||
account.emailVerifiedLogin#e1bb0d61 email:string sent_code:auth.SentCode = account.EmailVerified;
|
||||
premiumSubscriptionOption#b6f11ebe flags:# current:flags.1?true can_purchase_upgrade:flags.2?true months:int currency:string amount:long bot_url:string store_product:flags.0?string = PremiumSubscriptionOption;
|
||||
sendAsPeer#b81c7034 flags:# premium_required:flags.0?true peer:Peer = SendAsPeer;
|
||||
messageExtendedMediaPreview#ad628cc8 flags:# w:flags.0?int h:flags.0?int thumb:flags.1?PhotoSize video_duration:flags.2?int = MessageExtendedMedia;
|
||||
messageExtendedMedia#ee479c64 media:MessageMedia = MessageExtendedMedia;
|
||||
---functions---
|
||||
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;
|
||||
invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X;
|
||||
@ -1223,6 +1226,7 @@ messages.transcribeAudio#269e9a49 peer:InputPeer msg_id:int = messages.Transcrib
|
||||
messages.getCustomEmojiDocuments#d9ab0f54 document_id:Vector<long> = Vector<Document>;
|
||||
messages.getEmojiStickers#fbfca18f hash:long = messages.AllStickers;
|
||||
messages.getFeaturedEmojiStickers#ecf6736 hash:long = messages.FeaturedStickers;
|
||||
messages.getExtendedMedia#84f80814 peer:InputPeer id:Vector<int> = Updates;
|
||||
updates.getState#edd4882a = updates.State;
|
||||
updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference;
|
||||
updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference;
|
||||
|
||||
@ -157,6 +157,7 @@
|
||||
"messages.hideAllChatJoinRequests",
|
||||
"messages.toggleNoForwards",
|
||||
"messages.saveDefaultSendAs",
|
||||
"messages.getExtendedMedia",
|
||||
"updates.getState",
|
||||
"updates.getDifference",
|
||||
"updates.getChannelDifference",
|
||||
|
||||
@ -38,7 +38,7 @@ inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string pro
|
||||
inputMediaPhotoExternal#e5bbfe1a flags:# url:string ttl_seconds:flags.0?int = InputMedia;
|
||||
inputMediaDocumentExternal#fb52dc99 flags:# url:string ttl_seconds:flags.0?int = InputMedia;
|
||||
inputMediaGame#d33f43f3 id:InputGame = InputMedia;
|
||||
inputMediaInvoice#d9799874 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:flags.1?string = InputMedia;
|
||||
inputMediaInvoice#8eb5a6d5 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:flags.1?string extended_media:flags.2?InputMedia = InputMedia;
|
||||
inputMediaGeoLive#971fa843 flags:# stopped:flags.0?true geo_point:InputGeoPoint heading:flags.2?int period:flags.1?int proximity_notification_radius:flags.3?int = InputMedia;
|
||||
inputMediaPoll#f94e5f1 flags:# poll:Poll correct_answers:flags.0?Vector<bytes> solution:flags.1?string solution_entities:flags.1?Vector<MessageEntity> = InputMedia;
|
||||
inputMediaDice#e66fbf7b emoticon:string = InputMedia;
|
||||
@ -124,7 +124,7 @@ messageMediaDocument#9cb070d7 flags:# nopremium:flags.3?true document:flags.0?Do
|
||||
messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia;
|
||||
messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia;
|
||||
messageMediaGame#fdb19008 game:Game = MessageMedia;
|
||||
messageMediaInvoice#84551347 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 = 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;
|
||||
@ -367,6 +367,7 @@ updateUserEmojiStatus#28373599 user_id:long emoji_status:EmojiStatus = Update;
|
||||
updateRecentEmojiStatuses#30f443db = Update;
|
||||
updateRecentReactions#6f7863f4 = Update;
|
||||
updateMoveStickerSetToTop#86fccf85 flags:# masks:flags.0?true emojis:flags.1?true stickerset:long = Update;
|
||||
updateMessageExtendedMedia#5a73a98c peer:Peer msg_id:int extended_media:MessageExtendedMedia = Update;
|
||||
|
||||
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
|
||||
|
||||
@ -1414,6 +1415,9 @@ premiumSubscriptionOption#b6f11ebe flags:# current:flags.1?true can_purchase_upg
|
||||
|
||||
sendAsPeer#b81c7034 flags:# premium_required:flags.0?true peer:Peer = SendAsPeer;
|
||||
|
||||
messageExtendedMediaPreview#ad628cc8 flags:# w:flags.0?int h:flags.0?int thumb:flags.1?PhotoSize video_duration:flags.2?int = MessageExtendedMedia;
|
||||
messageExtendedMedia#ee479c64 media:MessageMedia = MessageExtendedMedia;
|
||||
|
||||
---functions---
|
||||
|
||||
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
|
||||
@ -1727,6 +1731,7 @@ messages.reportReaction#3f64c076 peer:InputPeer id:int reaction_peer:InputPeer =
|
||||
messages.getTopReactions#bb8125ba limit:int hash:long = messages.Reactions;
|
||||
messages.getRecentReactions#39461db2 limit:int hash:long = messages.Reactions;
|
||||
messages.clearRecentReactions#9dfeefb4 = Bool;
|
||||
messages.getExtendedMedia#84f80814 peer:InputPeer id:Vector<int> = Updates;
|
||||
|
||||
updates.getState#edd4882a = updates.State;
|
||||
updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference;
|
||||
@ -1889,4 +1894,4 @@ stats.getMegagroupStats#dcdf8607 flags:# dark:flags.0?true channel:InputChannel
|
||||
stats.getMessagePublicForwards#5630281b channel:InputChannel msg_id:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
|
||||
stats.getMessageStats#b6e0a3f5 flags:# dark:flags.0?true channel:InputChannel msg_id:int = stats.MessageStats;
|
||||
|
||||
// LAYER 145
|
||||
// LAYER 146
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user