Introduce Web Bots (#1813)
This commit is contained in:
parent
14b603991f
commit
7b253a4103
@ -1,12 +1,24 @@
|
||||
import { Api as GramJs } from '../../../lib/gramjs';
|
||||
import {
|
||||
ApiBotInlineMediaResult, ApiBotInlineResult, ApiBotInlineSwitchPm, ApiInlineResultType, ApiWebDocument,
|
||||
ApiAttachMenuBot,
|
||||
ApiAttachMenuBotIcon,
|
||||
ApiBotCommand,
|
||||
ApiBotInfo,
|
||||
ApiBotInlineMediaResult,
|
||||
ApiBotInlineResult,
|
||||
ApiBotInlineSwitchPm,
|
||||
ApiBotMenuButton,
|
||||
ApiInlineResultType,
|
||||
ApiWebDocument,
|
||||
} from '../../types';
|
||||
|
||||
import { pick } from '../../../util/iteratees';
|
||||
import { buildApiPhoto, buildApiThumbnailFromStripped } from './common';
|
||||
import { buildVideoFromDocument } from './messages';
|
||||
import { buildApiDocument, buildVideoFromDocument } from './messages';
|
||||
import { buildStickerFromDocument } from './symbols';
|
||||
import localDb from '../localDb';
|
||||
import { buildApiPeerId } from './peers';
|
||||
import { omitVirtualClassFields } from './helpers';
|
||||
|
||||
export function buildApiBotInlineResult(result: GramJs.BotInlineResult, queryId: string): ApiBotInlineResult {
|
||||
const {
|
||||
@ -50,6 +62,66 @@ export function buildBotSwitchPm(switchPm?: GramJs.InlineBotSwitchPM) {
|
||||
return switchPm ? pick(switchPm, ['text', 'startParam']) as ApiBotInlineSwitchPm : undefined;
|
||||
}
|
||||
|
||||
export function buildApiAttachMenuBot(bot: GramJs.AttachMenuBot): ApiAttachMenuBot {
|
||||
return {
|
||||
id: bot.botId.toString(),
|
||||
shortName: bot.shortName,
|
||||
icons: bot.icons.map(buildApiAttachMenuIcon).filter(Boolean),
|
||||
};
|
||||
}
|
||||
|
||||
function buildApiAttachMenuIcon(icon: GramJs.AttachMenuBotIcon): ApiAttachMenuBotIcon | undefined {
|
||||
if (!(icon.icon instanceof GramJs.Document)) return undefined;
|
||||
|
||||
const document = buildApiDocument(icon.icon);
|
||||
|
||||
if (!document) return undefined;
|
||||
|
||||
localDb.documents[String(icon.icon.id)] = icon.icon;
|
||||
|
||||
return {
|
||||
name: icon.name,
|
||||
document,
|
||||
};
|
||||
}
|
||||
|
||||
function buildApiWebDocument(document?: GramJs.TypeWebDocument): ApiWebDocument | undefined {
|
||||
return document ? pick(document, ['url', 'mimeType']) : undefined;
|
||||
}
|
||||
|
||||
export function buildApiBotInfo(botInfo: GramJs.BotInfo): ApiBotInfo {
|
||||
const {
|
||||
description, userId, commands, menuButton,
|
||||
} = botInfo;
|
||||
|
||||
const botId = buildApiPeerId(userId, 'user');
|
||||
const commandsArray = commands.map((command) => buildApiBotCommand(botId, command));
|
||||
|
||||
return {
|
||||
botId,
|
||||
description,
|
||||
menuButton: buildApiBotMenuButton(menuButton),
|
||||
commands: commandsArray.length ? commandsArray : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
function buildApiBotCommand(botId: string, command: GramJs.BotCommand): ApiBotCommand {
|
||||
return {
|
||||
botId,
|
||||
...omitVirtualClassFields(command),
|
||||
};
|
||||
}
|
||||
|
||||
export function buildApiBotMenuButton(menuButton: GramJs.TypeBotMenuButton): ApiBotMenuButton {
|
||||
if (menuButton instanceof GramJs.BotMenuButton) {
|
||||
return {
|
||||
type: 'webApp',
|
||||
text: menuButton.text,
|
||||
url: menuButton.url,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'commands',
|
||||
};
|
||||
}
|
||||
|
||||
@ -149,7 +149,6 @@ function buildApiChatRestrictions(peerEntity: GramJs.TypeUser | GramJs.TypeChat)
|
||||
if (peerEntity instanceof GramJs.Chat) {
|
||||
Object.assign(restrictions, {
|
||||
isNotJoined: peerEntity.left,
|
||||
isForbidden: peerEntity.kicked,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -924,6 +924,9 @@ function buildAction(
|
||||
text = senderId === currentUserId ? 'ActionYouScoredInGame' : 'ActionUserScoredInGame';
|
||||
translationValues.push('%score%');
|
||||
score = action.score;
|
||||
} else if (action instanceof GramJs.MessageActionWebViewDataSent) {
|
||||
text = 'Notification.WebAppSentData';
|
||||
translationValues.push(action.text);
|
||||
} else {
|
||||
text = 'ChatList.UnsupportedMessage';
|
||||
}
|
||||
@ -1067,6 +1070,22 @@ function buildReplyButtons(message: UniversalMessage): ApiReplyKeyboard | undefi
|
||||
};
|
||||
}
|
||||
|
||||
if (button instanceof GramJs.KeyboardButtonSimpleWebView) {
|
||||
return {
|
||||
type: 'simpleWebView',
|
||||
text,
|
||||
url: button.url,
|
||||
};
|
||||
}
|
||||
|
||||
if (button instanceof GramJs.KeyboardButtonWebView) {
|
||||
return {
|
||||
type: 'webView',
|
||||
text,
|
||||
url: button.url,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'unsupported',
|
||||
text,
|
||||
|
||||
@ -105,13 +105,15 @@ export function buildApiNotifyException(
|
||||
notifySettings: GramJs.TypePeerNotifySettings, peer: GramJs.TypePeer, serverTimeOffset: number,
|
||||
) {
|
||||
const {
|
||||
silent, muteUntil, showPreviews, sound,
|
||||
silent, muteUntil, showPreviews, otherSound,
|
||||
} = notifySettings;
|
||||
|
||||
const hasSound = Boolean(otherSound && !(otherSound instanceof GramJs.NotificationSoundNone));
|
||||
|
||||
return {
|
||||
chatId: getApiChatIdFromMtpPeer(peer),
|
||||
isMuted: silent || (typeof muteUntil === 'number' && getServerTime(serverTimeOffset) < muteUntil),
|
||||
...(sound === '' && { isSilent: true }),
|
||||
...(!hasSound && { isSilent: true }),
|
||||
...(showPreviews !== undefined && { shouldShowPreviews: Boolean(showPreviews) }),
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
import { Api as GramJs } from '../../../lib/gramjs';
|
||||
import {
|
||||
ApiBotCommand, ApiUser, ApiUserStatus, ApiUserType,
|
||||
ApiUser, ApiUserStatus, ApiUserType,
|
||||
} from '../../types';
|
||||
import { buildApiPeerId } from './peers';
|
||||
import { buildApiBotInfo } from './bots';
|
||||
|
||||
export function buildApiUserFromFull(mtpUserFull: GramJs.users.UserFull): ApiUser {
|
||||
const {
|
||||
@ -21,8 +22,7 @@ export function buildApiUserFromFull(mtpUserFull: GramJs.users.UserFull): ApiUse
|
||||
commonChatsCount,
|
||||
pinnedMessageId: pinnedMsgId,
|
||||
isBlocked: Boolean(blocked),
|
||||
...(botInfo && { botDescription: botInfo.description }),
|
||||
...(botInfo && botInfo.commands.length && { botCommands: buildApiBotCommands(user.id, botInfo) }),
|
||||
...(botInfo && { botInfo: buildApiBotInfo(botInfo) }),
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -57,6 +57,7 @@ export function buildApiUser(mtpUser: GramJs.TypeUser): ApiUser | undefined {
|
||||
...(mtpUser.accessHash && { accessHash: String(mtpUser.accessHash) }),
|
||||
...(avatarHash && { avatarHash }),
|
||||
...(mtpUser.bot && mtpUser.botInlinePlaceholder && { botPlaceholder: mtpUser.botInlinePlaceholder }),
|
||||
...(mtpUser.bot && mtpUser.botAttachMenu && { isAttachMenuBot: mtpUser.botAttachMenu }),
|
||||
};
|
||||
}
|
||||
|
||||
@ -87,14 +88,6 @@ export function buildApiUserStatus(mtpStatus?: GramJs.TypeUserStatus): ApiUserSt
|
||||
}
|
||||
}
|
||||
|
||||
function buildApiBotCommands(botId: string, botInfo: GramJs.BotInfo) {
|
||||
return botInfo.commands.map(({ command, description }) => ({
|
||||
botId,
|
||||
command,
|
||||
description,
|
||||
})) as ApiBotCommand[];
|
||||
}
|
||||
|
||||
export function buildApiUsersAndStatuses(mtpUsers: GramJs.TypeUser[]) {
|
||||
const userStatusesById: Record<string, ApiUserStatus> = {};
|
||||
const users: ApiUser[] = [];
|
||||
|
||||
@ -18,6 +18,7 @@ import {
|
||||
ApiSendMessageAction,
|
||||
ApiSticker,
|
||||
ApiVideo,
|
||||
ApiThemeParameters,
|
||||
} from '../../types';
|
||||
import localDb from '../localDb';
|
||||
import { pick } from '../../../util/iteratees';
|
||||
@ -466,6 +467,12 @@ export function buildSendMessageAction(action: ApiSendMessageAction) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function buildInputThemeParams(params: ApiThemeParameters) {
|
||||
return new GramJs.DataJSON({
|
||||
data: JSON.stringify(params),
|
||||
});
|
||||
}
|
||||
|
||||
export function buildMtpPeerId(id: string, type: 'user' | 'chat' | 'channel') {
|
||||
// Workaround for old-fashioned IDs stored locally
|
||||
if (typeof id === 'number') {
|
||||
|
||||
@ -1,16 +1,19 @@
|
||||
import BigInt from 'big-integer';
|
||||
import { Api as GramJs } from '../../../lib/gramjs';
|
||||
|
||||
import { ApiChat, ApiUser } from '../../types';
|
||||
import { ApiChat, ApiThemeParameters, ApiUser } from '../../types';
|
||||
|
||||
import localDb from '../localDb';
|
||||
import { invokeRequest } from './client';
|
||||
import { buildInputPeer, generateRandomBigInt } from '../gramjsBuilders';
|
||||
import { buildInputPeer, buildInputThemeParams, generateRandomBigInt } from '../gramjsBuilders';
|
||||
import { buildApiUser } from '../apiBuilders/users';
|
||||
import { buildApiBotInlineMediaResult, buildApiBotInlineResult, buildBotSwitchPm } from '../apiBuilders/bots';
|
||||
import {
|
||||
buildApiAttachMenuBot, buildApiBotInlineMediaResult, buildApiBotInlineResult, buildBotSwitchPm,
|
||||
} from '../apiBuilders/bots';
|
||||
import { buildApiChatFromPreview } from '../apiBuilders/chats';
|
||||
import { addEntitiesWithPhotosToLocalDb, addUserToLocalDb, deserializeBytes } from '../helpers';
|
||||
import { omitVirtualClassFields } from '../apiBuilders/helpers';
|
||||
import { buildCollectionByKey } from '../../../util/iteratees';
|
||||
|
||||
export function init() {
|
||||
}
|
||||
@ -140,6 +143,132 @@ export async function startBot({
|
||||
}), true);
|
||||
}
|
||||
|
||||
export async function requestWebView({
|
||||
isSilent,
|
||||
peer,
|
||||
bot,
|
||||
url,
|
||||
startParam,
|
||||
replyToMessageId,
|
||||
theme,
|
||||
isFromBotMenu,
|
||||
}: {
|
||||
isSilent?: boolean;
|
||||
peer: ApiChat | ApiUser;
|
||||
bot: ApiUser;
|
||||
url?: string;
|
||||
startParam?: string;
|
||||
replyToMessageId?: number;
|
||||
theme?: ApiThemeParameters;
|
||||
isFromBotMenu?: boolean;
|
||||
}) {
|
||||
const result = await invokeRequest(new GramJs.messages.RequestWebView({
|
||||
silent: isSilent || undefined,
|
||||
peer: buildInputPeer(peer.id, peer.accessHash),
|
||||
bot: buildInputPeer(bot.id, bot.accessHash),
|
||||
replyToMsgId: replyToMessageId,
|
||||
url,
|
||||
startParam,
|
||||
themeParams: theme ? buildInputThemeParams(theme) : undefined,
|
||||
fromBotMenu: isFromBotMenu || undefined,
|
||||
}));
|
||||
|
||||
if (result instanceof GramJs.WebViewResultUrl) {
|
||||
return {
|
||||
url: result.url,
|
||||
queryId: result.queryId.toString(),
|
||||
};
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export async function requestSimpleWebView({
|
||||
bot, url, theme,
|
||||
}: {
|
||||
bot: ApiUser;
|
||||
url: string;
|
||||
theme?: ApiThemeParameters;
|
||||
}) {
|
||||
const result = await invokeRequest(new GramJs.messages.RequestSimpleWebView({
|
||||
url,
|
||||
bot: buildInputPeer(bot.id, bot.accessHash),
|
||||
themeParams: theme ? buildInputThemeParams(theme) : undefined,
|
||||
}));
|
||||
|
||||
return result?.url;
|
||||
}
|
||||
|
||||
export function prolongWebView({
|
||||
isSilent,
|
||||
peer,
|
||||
bot,
|
||||
queryId,
|
||||
replyToMessageId,
|
||||
}: {
|
||||
isSilent?: boolean;
|
||||
peer: ApiChat | ApiUser;
|
||||
bot: ApiUser;
|
||||
queryId: string;
|
||||
replyToMessageId?: number;
|
||||
}) {
|
||||
return invokeRequest(new GramJs.messages.ProlongWebView({
|
||||
silent: isSilent || undefined,
|
||||
peer: buildInputPeer(peer.id, peer.accessHash),
|
||||
bot: buildInputPeer(bot.id, bot.accessHash),
|
||||
queryId: BigInt(queryId),
|
||||
replyToMsgId: replyToMessageId,
|
||||
}));
|
||||
}
|
||||
|
||||
export async function sendWebViewData({
|
||||
bot, buttonText, data,
|
||||
}: {
|
||||
bot: ApiUser;
|
||||
buttonText: string;
|
||||
data: string;
|
||||
}) {
|
||||
const randomId = generateRandomBigInt();
|
||||
await invokeRequest(new GramJs.messages.SendWebViewData({
|
||||
bot: buildInputPeer(bot.id, bot.accessHash),
|
||||
buttonText,
|
||||
data,
|
||||
randomId,
|
||||
}), true);
|
||||
}
|
||||
|
||||
export async function loadAttachMenuBots({
|
||||
hash,
|
||||
}: {
|
||||
hash?: string;
|
||||
}) {
|
||||
const result = await invokeRequest(new GramJs.messages.GetAttachMenuBots({
|
||||
hash: hash ? BigInt(hash) : undefined,
|
||||
}));
|
||||
|
||||
if (result instanceof GramJs.AttachMenuBots) {
|
||||
addEntitiesWithPhotosToLocalDb(result.users);
|
||||
return {
|
||||
hash: result.hash.toString(),
|
||||
bots: buildCollectionByKey(result.bots.map(buildApiAttachMenuBot), 'id'),
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function toggleBotInAttachMenu({
|
||||
bot,
|
||||
isEnabled,
|
||||
}: {
|
||||
bot: ApiUser;
|
||||
isEnabled: boolean;
|
||||
}) {
|
||||
return invokeRequest(new GramJs.messages.ToggleBotInAttachMenu({
|
||||
bot: buildInputPeer(bot.id, bot.accessHash),
|
||||
enabled: isEnabled,
|
||||
}));
|
||||
}
|
||||
|
||||
function processInlineBotResult(queryId: string, results: GramJs.TypeBotInlineResult[]) {
|
||||
return results.map((result) => {
|
||||
if (result instanceof GramJs.BotInlineMediaResult) {
|
||||
|
||||
@ -64,6 +64,7 @@ export {
|
||||
|
||||
export {
|
||||
answerCallbackButton, fetchTopInlineBots, fetchInlineBot, fetchInlineBotResults, sendInlineBotResult, startBot,
|
||||
requestWebView, requestSimpleWebView, sendWebViewData, prolongWebView, loadAttachMenuBots, toggleBotInAttachMenu,
|
||||
} from './bots';
|
||||
|
||||
export {
|
||||
|
||||
@ -248,6 +248,9 @@ async function parseMedia(
|
||||
case ApiMediaFormat.Lottie: {
|
||||
return new Blob([data], { type: mimeType });
|
||||
}
|
||||
case ApiMediaFormat.Text: {
|
||||
return data.toString();
|
||||
}
|
||||
case ApiMediaFormat.Progressive: {
|
||||
return data.buffer;
|
||||
}
|
||||
|
||||
@ -34,7 +34,7 @@ import { buildApiConfig } from '../apiBuilders/appConfig';
|
||||
import { addEntitiesWithPhotosToLocalDb } from '../helpers';
|
||||
|
||||
const MAX_INT_32 = 2 ** 31 - 1;
|
||||
const BETA_LANG_CODES = ['ar', 'fa', 'id', 'ko', 'uz'];
|
||||
const BETA_LANG_CODES = ['ar', 'fa', 'id', 'ko', 'uz', 'en'];
|
||||
|
||||
export function updateProfile({
|
||||
firstName,
|
||||
|
||||
@ -44,11 +44,13 @@ import { buildApiNotifyException, buildPrivacyKey, buildPrivacyRules } from './a
|
||||
import { buildApiPhoto } from './apiBuilders/common';
|
||||
import {
|
||||
buildApiGroupCall,
|
||||
buildApiGroupCallParticipant, buildPhoneCall,
|
||||
buildApiGroupCallParticipant,
|
||||
buildPhoneCall,
|
||||
getGroupCallId,
|
||||
} from './apiBuilders/calls';
|
||||
import { buildApiPeerId, getApiChatIdFromMtpPeer } from './apiBuilders/peers';
|
||||
import { buildApiEmojiInteraction } from './apiBuilders/symbols';
|
||||
import { buildApiBotMenuButton } from './apiBuilders/bots';
|
||||
|
||||
type Update = (
|
||||
(GramJs.TypeUpdate | GramJs.TypeUpdates) & { _entities?: (GramJs.TypeUser | GramJs.TypeChat)[] }
|
||||
@ -915,6 +917,23 @@ export function updater(update: Update, originRequest?: GramJs.AnyRequest) {
|
||||
callId: update.phoneCallId.toString(),
|
||||
data: Array.from(update.data),
|
||||
});
|
||||
} else if (update instanceof GramJs.UpdateWebViewResultSent) {
|
||||
const { queryId } = update;
|
||||
|
||||
onUpdate({
|
||||
'@type': 'updateWebViewResultSent',
|
||||
queryId: queryId.toString(),
|
||||
});
|
||||
} else if (update instanceof GramJs.UpdateBotMenuButton) {
|
||||
const { botId, button } = update;
|
||||
|
||||
const id = buildApiPeerId(botId, 'user');
|
||||
|
||||
onUpdate({
|
||||
'@type': 'updateBotMenuButton',
|
||||
botId: id,
|
||||
button: buildApiBotMenuButton(button),
|
||||
});
|
||||
} else if (DEBUG) {
|
||||
const params = typeof update === 'object' && 'className' in update ? update.className : update;
|
||||
// eslint-disable-next-line no-console
|
||||
|
||||
@ -44,3 +44,22 @@ export interface ApiBotCommand {
|
||||
command: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
type ApiBotMenuButtonCommands = {
|
||||
type: 'commands';
|
||||
};
|
||||
|
||||
type ApiBotMenuButtonWebApp = {
|
||||
type: 'webApp';
|
||||
text: string;
|
||||
url: string;
|
||||
};
|
||||
|
||||
export type ApiBotMenuButton = ApiBotMenuButtonWebApp | ApiBotMenuButtonCommands;
|
||||
|
||||
export interface ApiBotInfo {
|
||||
botId: string;
|
||||
commands?: ApiBotCommand[];
|
||||
description: string;
|
||||
menuButton: ApiBotMenuButton;
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ export enum ApiMediaFormat {
|
||||
Lottie,
|
||||
Progressive,
|
||||
Stream,
|
||||
Text,
|
||||
}
|
||||
|
||||
export type ApiParsedMedia = string | Blob | ArrayBuffer;
|
||||
|
||||
@ -395,6 +395,18 @@ interface ApiKeyboardButtonUrl {
|
||||
url: string;
|
||||
}
|
||||
|
||||
interface ApiKeyboardButtonSimpleWebView {
|
||||
type: 'simpleWebView';
|
||||
text: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
interface ApiKeyboardButtonWebView {
|
||||
type: 'webView';
|
||||
text: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
interface ApiKeyboardButtonCallback {
|
||||
type: 'callback';
|
||||
text: string;
|
||||
@ -407,7 +419,7 @@ interface ApiKeyboardButtonRequestPoll {
|
||||
isQuiz?: boolean;
|
||||
}
|
||||
|
||||
interface ApiKeyboardButtonSwitchInline {
|
||||
interface ApiKeyboardButtonSwitchBotInline {
|
||||
type: 'switchBotInline';
|
||||
text: string;
|
||||
query: string;
|
||||
@ -426,8 +438,10 @@ export type ApiKeyboardButton = (
|
||||
| ApiKeyboardButtonUrl
|
||||
| ApiKeyboardButtonCallback
|
||||
| ApiKeyboardButtonRequestPoll
|
||||
| ApiKeyboardButtonSwitchInline
|
||||
| ApiKeyboardButtonSwitchBotInline
|
||||
| ApiKeyboardButtonUserProfile
|
||||
| ApiKeyboardButtonWebView
|
||||
| ApiKeyboardButtonSimpleWebView
|
||||
);
|
||||
|
||||
export type ApiKeyboardButtons = ApiKeyboardButton[][];
|
||||
@ -448,6 +462,15 @@ export type ApiSendMessageAction = {
|
||||
type: 'cancel' | 'typing' | 'recordAudio' | 'chooseSticker' | 'playingGame';
|
||||
};
|
||||
|
||||
export type ApiThemeParameters = {
|
||||
bg_color: string;
|
||||
text_color: string;
|
||||
hint_color: string;
|
||||
link_color: string;
|
||||
button_color: string;
|
||||
button_text_color: string;
|
||||
};
|
||||
|
||||
export const MAIN_THREAD_ID = -1;
|
||||
|
||||
// `Symbol` can not be transferred from worker
|
||||
|
||||
@ -22,6 +22,7 @@ import {
|
||||
import {
|
||||
ApiGroupCall, ApiPhoneCall,
|
||||
} from './calls';
|
||||
import { ApiBotMenuButton } from './bots';
|
||||
|
||||
export type ApiUpdateReady = {
|
||||
'@type': 'updateApiReady';
|
||||
@ -486,6 +487,17 @@ export type ApiUpdatePhoneCallConnectionState = {
|
||||
connectionState: RTCPeerConnectionState;
|
||||
};
|
||||
|
||||
export type ApiUpdateWebViewResultSent = {
|
||||
'@type': 'updateWebViewResultSent';
|
||||
queryId: string;
|
||||
};
|
||||
|
||||
export type ApiUpdateBotMenuButton = {
|
||||
'@type': 'updateBotMenuButton';
|
||||
botId: string;
|
||||
button: ApiBotMenuButton;
|
||||
};
|
||||
|
||||
export type ApiUpdate = (
|
||||
ApiUpdateReady | ApiUpdateSession |
|
||||
ApiUpdateAuthorizationState | ApiUpdateAuthorizationError | ApiUpdateConnectionState | ApiUpdateCurrentUser |
|
||||
@ -501,14 +513,14 @@ export type ApiUpdate = (
|
||||
ApiUpdateFavoriteStickers | ApiUpdateStickerSet |
|
||||
ApiUpdateNewScheduledMessage | ApiUpdateScheduledMessageSendSucceeded | ApiUpdateScheduledMessage |
|
||||
ApiUpdateDeleteScheduledMessages | ApiUpdateResetMessages |
|
||||
ApiUpdateTwoFaError | ApiUpdateTwoFaStateWaitCode |
|
||||
ApiUpdateTwoFaError | ApiUpdateTwoFaStateWaitCode | ApiUpdateWebViewResultSent |
|
||||
ApiUpdateNotifySettings | ApiUpdateNotifyExceptions | ApiUpdatePeerBlocked | ApiUpdatePrivacy |
|
||||
ApiUpdateServerTimeOffset | ApiUpdateShowInvite | ApiUpdateMessageReactions |
|
||||
ApiUpdateGroupCallParticipants | ApiUpdateGroupCallConnection | ApiUpdateGroupCall | ApiUpdateGroupCallStreams |
|
||||
ApiUpdateGroupCallConnectionState | ApiUpdateGroupCallLeavePresentation | ApiUpdateGroupCallChatId |
|
||||
ApiUpdatePendingJoinRequests | ApiUpdatePaymentVerificationNeeded | ApiUpdatePaymentStateCompleted |
|
||||
ApiUpdatePhoneCall | ApiUpdatePhoneCallSignalingData | ApiUpdatePhoneCallMediaState |
|
||||
ApiUpdatePhoneCallConnectionState
|
||||
ApiUpdatePhoneCallConnectionState | ApiUpdateBotMenuButton
|
||||
);
|
||||
|
||||
export type OnApiUpdate = (update: ApiUpdate) => void;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { ApiPhoto } from './messages';
|
||||
import { ApiBotCommand } from './bots';
|
||||
import { ApiDocument, ApiPhoto } from './messages';
|
||||
import { ApiBotInfo } from './bots';
|
||||
|
||||
export interface ApiUser {
|
||||
id: string;
|
||||
@ -24,6 +24,7 @@ export interface ApiUser {
|
||||
isFullyLoaded: boolean;
|
||||
};
|
||||
fakeType?: ApiFakeType;
|
||||
isAttachMenuBot?: boolean;
|
||||
|
||||
// Obtained from GetFullUser / UserFullInfo
|
||||
fullInfo?: ApiUserFullInfo;
|
||||
@ -33,9 +34,8 @@ export interface ApiUserFullInfo {
|
||||
isBlocked?: boolean;
|
||||
bio?: string;
|
||||
commonChatsCount?: number;
|
||||
botDescription?: string;
|
||||
pinnedMessageId?: number;
|
||||
botCommands?: ApiBotCommand[];
|
||||
botInfo?: ApiBotInfo;
|
||||
}
|
||||
|
||||
export type ApiFakeType = 'fake' | 'scam';
|
||||
@ -50,3 +50,14 @@ export interface ApiUserStatus {
|
||||
wasOnline?: number;
|
||||
expires?: number;
|
||||
}
|
||||
|
||||
export interface ApiAttachMenuBot {
|
||||
id: string;
|
||||
shortName: string;
|
||||
icons: ApiAttachMenuBotIcon[];
|
||||
}
|
||||
|
||||
export interface ApiAttachMenuBotIcon {
|
||||
name: string;
|
||||
document: ApiDocument;
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@ -6,6 +6,9 @@ export { default as Notifications } from '../components/main/Notifications';
|
||||
export { default as SafeLinkModal } from '../components/main/SafeLinkModal';
|
||||
export { default as HistoryCalendar } from '../components/main/HistoryCalendar';
|
||||
export { default as NewContactModal } from '../components/main/NewContactModal';
|
||||
export { default as WebAppModal } from '../components/main/WebAppModal';
|
||||
export { default as BotTrustModal } from '../components/main/BotTrustModal';
|
||||
export { default as BotAttachModal } from '../components/main/BotAttachModal';
|
||||
|
||||
export { default as CalendarModal } from '../components/common/CalendarModal';
|
||||
export { default as DeleteMessageModal } from '../components/common/DeleteMessageModal';
|
||||
|
||||
@ -54,7 +54,7 @@ const EmbeddedMessage: FC<OwnProps> = ({
|
||||
|
||||
const lang = useLang();
|
||||
|
||||
const senderTitle = message?.forwardInfo?.hiddenUserName || (sender && getSenderTitle(lang, sender));
|
||||
const senderTitle = sender ? getSenderTitle(lang, sender) : message?.forwardInfo?.hiddenUserName;
|
||||
|
||||
return (
|
||||
<div
|
||||
|
||||
16
src/components/main/BotAttachModal.async.tsx
Normal file
16
src/components/main/BotAttachModal.async.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import React, { FC, memo } from '../../lib/teact/teact';
|
||||
import { Bundles } from '../../util/moduleLoader';
|
||||
|
||||
import { OwnProps } from './BotAttachModal';
|
||||
|
||||
import useModuleLoader from '../../hooks/useModuleLoader';
|
||||
|
||||
const BotAttachModalAsync: FC<OwnProps> = (props) => {
|
||||
const { bot } = props;
|
||||
const BotAttachModal = useModuleLoader(Bundles.Extra, 'BotAttachModal', !bot);
|
||||
|
||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||
return BotAttachModal ? <BotAttachModal {...props} /> : undefined;
|
||||
};
|
||||
|
||||
export default memo(BotAttachModalAsync);
|
||||
34
src/components/main/BotAttachModal.tsx
Normal file
34
src/components/main/BotAttachModal.tsx
Normal file
@ -0,0 +1,34 @@
|
||||
import React, { FC } from '../../lib/teact/teact';
|
||||
import { getActions } from '../../global';
|
||||
|
||||
import { ApiUser } from '../../api/types';
|
||||
|
||||
import useLang from '../../hooks/useLang';
|
||||
|
||||
import ConfirmDialog from '../ui/ConfirmDialog';
|
||||
|
||||
export type OwnProps = {
|
||||
bot?: ApiUser;
|
||||
};
|
||||
|
||||
const BotAttachModal: FC<OwnProps> = ({
|
||||
bot,
|
||||
}) => {
|
||||
const { closeBotAttachRequestModal, confirmBotAttachRequest } = getActions();
|
||||
|
||||
const lang = useLang();
|
||||
|
||||
const name = bot?.firstName;
|
||||
|
||||
return (
|
||||
<ConfirmDialog
|
||||
isOpen={Boolean(bot)}
|
||||
onClose={closeBotAttachRequestModal}
|
||||
confirmHandler={confirmBotAttachRequest}
|
||||
title={name}
|
||||
textParts={lang('WebApp.AddToAttachmentText', name)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default BotAttachModal;
|
||||
16
src/components/main/BotTrustModal.async.tsx
Normal file
16
src/components/main/BotTrustModal.async.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import React, { FC, memo } from '../../lib/teact/teact';
|
||||
import { Bundles } from '../../util/moduleLoader';
|
||||
|
||||
import { OwnProps } from './BotTrustModal';
|
||||
|
||||
import useModuleLoader from '../../hooks/useModuleLoader';
|
||||
|
||||
const BotTrustModalAsync: FC<OwnProps> = (props) => {
|
||||
const { bot } = props;
|
||||
const BotTrustModal = useModuleLoader(Bundles.Extra, 'BotTrustModal', !bot);
|
||||
|
||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||
return BotTrustModal ? <BotTrustModal {...props} /> : undefined;
|
||||
};
|
||||
|
||||
export default memo(BotTrustModalAsync);
|
||||
47
src/components/main/BotTrustModal.tsx
Normal file
47
src/components/main/BotTrustModal.tsx
Normal file
@ -0,0 +1,47 @@
|
||||
import React, { FC, memo, useCallback } from '../../lib/teact/teact';
|
||||
import { getActions } from '../../global';
|
||||
|
||||
import { ApiUser } from '../../api/types';
|
||||
|
||||
import { getUserFullName } from '../../global/helpers';
|
||||
import renderText from '../common/helpers/renderText';
|
||||
|
||||
import useLang from '../../hooks/useLang';
|
||||
import usePrevious from '../../hooks/usePrevious';
|
||||
|
||||
import ConfirmDialog from '../ui/ConfirmDialog';
|
||||
|
||||
export type OwnProps = {
|
||||
bot?: ApiUser;
|
||||
type?: 'game' | 'webApp';
|
||||
};
|
||||
|
||||
const BotTrustModal: FC<OwnProps> = ({ bot, type }) => {
|
||||
const { cancelBotTrustRequest, markBotTrusted } = getActions();
|
||||
const lang = useLang();
|
||||
// Keep props a little bit longer, to show correct text on closing animation
|
||||
const previousBot = usePrevious(bot, false);
|
||||
const previousType = usePrevious(type, false);
|
||||
const currentBot = bot || previousBot;
|
||||
const currentType = type || previousType;
|
||||
|
||||
const handleBotTrustAccept = useCallback(() => {
|
||||
markBotTrusted({ botId: bot!.id });
|
||||
}, [markBotTrusted, bot]);
|
||||
|
||||
const title = currentType === 'game' ? lang('AppName') : lang('BotOpenPageTitle');
|
||||
const text = currentType === 'game' ? lang('BotPermissionGameAlert', getUserFullName(currentBot))
|
||||
: lang('BotOpenPageMessage', getUserFullName(currentBot));
|
||||
|
||||
return (
|
||||
<ConfirmDialog
|
||||
isOpen={Boolean(bot)}
|
||||
onClose={cancelBotTrustRequest}
|
||||
confirmHandler={handleBotTrustAccept}
|
||||
title={title}
|
||||
textParts={renderText(text, ['br', 'simple_markdown'])}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(BotTrustModal);
|
||||
@ -4,7 +4,9 @@ import React, {
|
||||
import { getActions, withGlobal } from '../../global';
|
||||
|
||||
import { LangCode } from '../../types';
|
||||
import { ApiMessage, ApiUpdateAuthorizationStateType, ApiUpdateConnectionStateType } from '../../api/types';
|
||||
import {
|
||||
ApiChat, ApiMessage, ApiUpdateAuthorizationStateType, ApiUpdateConnectionStateType,
|
||||
} from '../../api/types';
|
||||
import { GlobalState } from '../../global/types';
|
||||
|
||||
import '../../global/actions/all';
|
||||
@ -54,10 +56,14 @@ import ActiveCallHeader from '../calls/ActiveCallHeader.async';
|
||||
import PhoneCall from '../calls/phone/PhoneCall.async';
|
||||
import NewContactModal from './NewContactModal.async';
|
||||
import RatePhoneCallModal from '../calls/phone/RatePhoneCallModal.async';
|
||||
import WebAppModal from './WebAppModal.async';
|
||||
import BotTrustModal from './BotTrustModal.async';
|
||||
import BotAttachModal from './BotAttachModal.async';
|
||||
|
||||
import './Main.scss';
|
||||
|
||||
type StateProps = {
|
||||
chat?: ApiChat;
|
||||
connectionState?: ApiUpdateConnectionStateType;
|
||||
authState?: ApiUpdateAuthorizationStateType;
|
||||
lastSyncTime?: number;
|
||||
@ -84,6 +90,9 @@ type StateProps = {
|
||||
openedGame?: GlobalState['openedGame'];
|
||||
gameTitle?: string;
|
||||
isRatePhoneCallModalOpen?: boolean;
|
||||
webApp?: GlobalState['webApp'];
|
||||
botTrustRequest?: GlobalState['botTrustRequest'];
|
||||
botAttachRequest?: GlobalState['botAttachRequest'];
|
||||
};
|
||||
|
||||
const NOTIFICATION_INTERVAL = 1000;
|
||||
@ -120,6 +129,9 @@ const Main: FC<StateProps> = ({
|
||||
openedGame,
|
||||
gameTitle,
|
||||
isRatePhoneCallModalOpen,
|
||||
botTrustRequest,
|
||||
botAttachRequest,
|
||||
webApp,
|
||||
}) => {
|
||||
const {
|
||||
sync,
|
||||
@ -138,6 +150,7 @@ const Main: FC<StateProps> = ({
|
||||
openStickerSetShortName,
|
||||
checkVersionNotification,
|
||||
loadAppConfig,
|
||||
loadAttachMenuBots,
|
||||
} = getActions();
|
||||
|
||||
if (DEBUG && !DEBUG_isLogged) {
|
||||
@ -163,10 +176,11 @@ const Main: FC<StateProps> = ({
|
||||
loadNotificationExceptions();
|
||||
loadTopInlineBots();
|
||||
loadEmojiKeywords({ language: BASE_EMOJI_KEYWORD_LANG });
|
||||
loadAttachMenuBots();
|
||||
}
|
||||
}, [
|
||||
lastSyncTime, loadAnimatedEmojis, loadEmojiKeywords, loadNotificationExceptions, loadNotificationSettings,
|
||||
loadTopInlineBots, updateIsOnline, loadAvailableReactions, loadAppConfig,
|
||||
loadTopInlineBots, updateIsOnline, loadAvailableReactions, loadAppConfig, loadAttachMenuBots,
|
||||
]);
|
||||
|
||||
// Language-based API calls
|
||||
@ -366,10 +380,13 @@ const Main: FC<StateProps> = ({
|
||||
isByPhoneNumber={newContactByPhoneNumber}
|
||||
/>
|
||||
<GameModal openedGame={openedGame} gameTitle={gameTitle} />
|
||||
<WebAppModal webApp={webApp} />
|
||||
<DownloadManager />
|
||||
<PhoneCall isActive={isPhoneCallActive} />
|
||||
<UnreadCount isForAppBadge />
|
||||
<RatePhoneCallModal isOpen={isRatePhoneCallModalOpen} />
|
||||
<BotTrustModal bot={botTrustRequest?.bot} type={botTrustRequest?.type} />
|
||||
<BotAttachModal bot={botAttachRequest?.bot} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@ -433,6 +450,9 @@ export default memo(withGlobal(
|
||||
openedGame,
|
||||
gameTitle,
|
||||
isRatePhoneCallModalOpen: Boolean(global.ratingPhoneCall),
|
||||
botTrustRequest: global.botTrustRequest,
|
||||
botAttachRequest: global.botAttachRequest,
|
||||
webApp: global.webApp,
|
||||
};
|
||||
},
|
||||
)(Main));
|
||||
|
||||
16
src/components/main/WebAppModal.async.tsx
Normal file
16
src/components/main/WebAppModal.async.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import React, { FC, memo } from '../../lib/teact/teact';
|
||||
import { Bundles } from '../../util/moduleLoader';
|
||||
|
||||
import { OwnProps } from './WebAppModal';
|
||||
|
||||
import useModuleLoader from '../../hooks/useModuleLoader';
|
||||
|
||||
const WebAppModalAsync: FC<OwnProps> = (props) => {
|
||||
const { webApp } = props;
|
||||
const WebAppModal = useModuleLoader(Bundles.Extra, 'WebAppModal', !webApp);
|
||||
|
||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||
return WebAppModal ? <WebAppModal {...props} /> : undefined;
|
||||
};
|
||||
|
||||
export default memo(WebAppModalAsync);
|
||||
69
src/components/main/WebAppModal.scss
Normal file
69
src/components/main/WebAppModal.scss
Normal file
@ -0,0 +1,69 @@
|
||||
.WebAppModal {
|
||||
.modal-header {
|
||||
border-bottom: 1px solid var(--color-dividers);
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.modal-dialog {
|
||||
height: 75%;
|
||||
justify-content: center;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
border-bottom-right-radius: var(--border-radius-default);
|
||||
border-bottom-left-radius: var(--border-radius-default);
|
||||
}
|
||||
|
||||
.web-app-frame {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 0;
|
||||
|
||||
&.with-button {
|
||||
height: calc(100% - 56px);
|
||||
}
|
||||
}
|
||||
|
||||
.web-app-button {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
border-radius: 0;
|
||||
transform: translateY(100%);
|
||||
transition: 0.25s ease-in-out transform;
|
||||
|
||||
&.visible {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
&.hidden {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.Spinner {
|
||||
position: absolute;
|
||||
right: 1rem;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.modal-dialog {
|
||||
background-color: var(--color-background);
|
||||
border-radius: 0;
|
||||
height: 100%;
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
max-height: none;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
292
src/components/main/WebAppModal.tsx
Normal file
292
src/components/main/WebAppModal.tsx
Normal file
@ -0,0 +1,292 @@
|
||||
import React, {
|
||||
FC, memo, useCallback, useEffect, useMemo, useRef, useState,
|
||||
} from '../../lib/teact/teact';
|
||||
import { getActions, withGlobal } from '../../global';
|
||||
|
||||
import { ApiChat } from '../../api/types';
|
||||
import { GlobalState } from '../../global/types';
|
||||
import { ThemeKey } from '../../types';
|
||||
|
||||
import windowSize from '../../util/windowSize';
|
||||
import { IS_SINGLE_COLUMN_LAYOUT } from '../../util/environment';
|
||||
import { selectCurrentChat, selectTheme } from '../../global/selectors';
|
||||
import buildClassName from '../../util/buildClassName';
|
||||
import { extractCurrentThemeParams, validateHexColor } from '../../util/themeStyle';
|
||||
|
||||
import useInterval from '../../hooks/useInterval';
|
||||
import useLang from '../../hooks/useLang';
|
||||
import useOnChange from '../../hooks/useOnChange';
|
||||
import useWebAppFrame, { WebAppInboundEvent } from './hooks/useWebAppFrame';
|
||||
import usePrevious from '../../hooks/usePrevious';
|
||||
|
||||
import Modal from '../ui/Modal';
|
||||
import Button from '../ui/Button';
|
||||
import DropdownMenu from '../ui/DropdownMenu';
|
||||
import MenuItem from '../ui/MenuItem';
|
||||
import Spinner from '../ui/Spinner';
|
||||
|
||||
import './WebAppModal.scss';
|
||||
|
||||
type WebAppButton = {
|
||||
isVisible: boolean;
|
||||
isActive: boolean;
|
||||
text: string;
|
||||
color: string;
|
||||
textColor: string;
|
||||
isProgressVisible: boolean;
|
||||
};
|
||||
|
||||
export type OwnProps = {
|
||||
webApp?: GlobalState['webApp'];
|
||||
};
|
||||
|
||||
type StateProps = {
|
||||
isInstalled?: boolean;
|
||||
chat?: ApiChat;
|
||||
theme?: ThemeKey;
|
||||
};
|
||||
|
||||
const MAIN_BUTTON_ANIMATION_TIME = 250;
|
||||
const PROLONG_INTERVAL = 45000; // 45s
|
||||
const ANIMATION_WAIT = 400;
|
||||
|
||||
const WebAppModal: FC<OwnProps & StateProps> = ({
|
||||
webApp,
|
||||
chat,
|
||||
isInstalled,
|
||||
theme,
|
||||
}) => {
|
||||
const {
|
||||
closeWebApp, sendWebViewData, prolongWebView, toggleBotInAttachMenu,
|
||||
} = getActions();
|
||||
const [mainButton, setMainButton] = useState<WebAppButton | undefined>();
|
||||
const lang = useLang();
|
||||
const {
|
||||
url, bot, buttonText, queryId,
|
||||
} = webApp || {};
|
||||
const isOpen = Boolean(url);
|
||||
const isSimple = !queryId;
|
||||
|
||||
const handleEvent = useCallback((event: WebAppInboundEvent) => {
|
||||
const { eventType } = event;
|
||||
if (eventType === 'web_app_close') {
|
||||
closeWebApp();
|
||||
}
|
||||
|
||||
if (eventType === 'web_app_data_send') {
|
||||
const { eventData } = event;
|
||||
closeWebApp();
|
||||
sendWebViewData({
|
||||
bot: bot!,
|
||||
buttonText: buttonText!,
|
||||
data: eventData.data,
|
||||
});
|
||||
}
|
||||
|
||||
if (eventType === 'web_app_setup_main_button') {
|
||||
const { eventData } = event;
|
||||
const themeParams = extractCurrentThemeParams();
|
||||
// Validate colors if they are present
|
||||
const color = !eventData.color || validateHexColor(eventData.color) ? eventData.color
|
||||
: themeParams.button_color;
|
||||
const textColor = !eventData.text_color || validateHexColor(eventData.text_color) ? eventData.text_color
|
||||
: themeParams.text_color;
|
||||
setMainButton({
|
||||
isVisible: eventData.is_visible && Boolean(eventData.text?.trim().length),
|
||||
isActive: eventData.is_active,
|
||||
text: eventData.text || '',
|
||||
color,
|
||||
textColor,
|
||||
isProgressVisible: eventData.is_progress_visible,
|
||||
});
|
||||
}
|
||||
}, [bot, buttonText, closeWebApp, sendWebViewData]);
|
||||
|
||||
const {
|
||||
ref, reloadFrame, sendEvent, sendViewport, sendTheme,
|
||||
} = useWebAppFrame(isOpen, isSimple, handleEvent);
|
||||
|
||||
const shouldShowMainButton = mainButton?.isVisible && mainButton.text.trim().length > 0;
|
||||
|
||||
useInterval(() => {
|
||||
prolongWebView({
|
||||
bot: bot!,
|
||||
queryId: queryId!,
|
||||
peer: chat!,
|
||||
});
|
||||
}, queryId ? PROLONG_INTERVAL : undefined, true);
|
||||
|
||||
const handleMainButtonClick = useCallback(() => {
|
||||
sendEvent({
|
||||
eventType: 'main_button_pressed',
|
||||
});
|
||||
}, [sendEvent]);
|
||||
|
||||
const handleRefreshClick = useCallback(() => {
|
||||
reloadFrame(webApp!.url);
|
||||
}, [reloadFrame, webApp]);
|
||||
|
||||
// Notify view that height changed
|
||||
useOnChange(() => {
|
||||
setTimeout(() => {
|
||||
sendViewport();
|
||||
}, ANIMATION_WAIT);
|
||||
}, [mainButton?.isVisible, sendViewport]);
|
||||
|
||||
// Notify view that theme changed
|
||||
useOnChange(() => {
|
||||
setTimeout(() => {
|
||||
sendTheme();
|
||||
}, ANIMATION_WAIT);
|
||||
}, [theme, sendTheme]);
|
||||
|
||||
// Prevent refresh when rotating device
|
||||
useEffect(() => {
|
||||
if (!isOpen) return undefined;
|
||||
windowSize.disableRefresh();
|
||||
|
||||
return () => {
|
||||
windowSize.enableRefresh();
|
||||
};
|
||||
}, [isOpen]);
|
||||
|
||||
const handleToggleClick = useCallback(() => {
|
||||
toggleBotInAttachMenu({
|
||||
botId: bot!.id,
|
||||
isEnabled: !isInstalled,
|
||||
});
|
||||
}, [bot, isInstalled, toggleBotInAttachMenu]);
|
||||
|
||||
const MoreMenuButton: FC<{ onTrigger: () => void; isOpen?: boolean }> = useMemo(() => {
|
||||
return ({ onTrigger, isOpen: isMenuOpen }) => (
|
||||
<Button
|
||||
round
|
||||
ripple={!IS_SINGLE_COLUMN_LAYOUT}
|
||||
size="smaller"
|
||||
color="translucent"
|
||||
className={isMenuOpen ? 'active' : ''}
|
||||
onClick={onTrigger}
|
||||
ariaLabel="More actions"
|
||||
>
|
||||
<i className="icon-more" />
|
||||
</Button>
|
||||
);
|
||||
}, []);
|
||||
|
||||
const header = useMemo(() => {
|
||||
return (
|
||||
<div className="modal-header">
|
||||
<Button
|
||||
round
|
||||
color="translucent"
|
||||
size="smaller"
|
||||
ariaLabel={lang('Close')}
|
||||
onClick={closeWebApp}
|
||||
>
|
||||
<i className="icon-close" />
|
||||
</Button>
|
||||
<div className="modal-title">{bot?.firstName}</div>
|
||||
<DropdownMenu
|
||||
className="web-app-more-menu"
|
||||
trigger={MoreMenuButton}
|
||||
positionX="right"
|
||||
>
|
||||
<MenuItem icon="reload" onClick={handleRefreshClick}>{lang('WebApp.ReloadPage')}</MenuItem>
|
||||
{bot?.isAttachMenuBot && (
|
||||
<MenuItem icon={isInstalled ? 'stop' : 'install'} onClick={handleToggleClick} destructive={isInstalled}>
|
||||
{lang(isInstalled ? 'WebApp.RemoveBot' : 'WebApp.AddToAttachmentAdd')}
|
||||
</MenuItem>
|
||||
)}
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
);
|
||||
}, [
|
||||
MoreMenuButton, bot, closeWebApp, handleRefreshClick, handleToggleClick, lang, isInstalled,
|
||||
]);
|
||||
|
||||
const prevMainButtonColor = usePrevious(mainButton?.color, true);
|
||||
const prevMainButtonTextColor = usePrevious(mainButton?.textColor, true);
|
||||
const prevMainButtonIsActive = usePrevious(mainButton && Boolean(mainButton.isActive), true);
|
||||
const prevMainButtonText = usePrevious(mainButton?.text, true);
|
||||
|
||||
const mainButtonCurrentColor = mainButton?.color || prevMainButtonColor;
|
||||
const mainButtonCurrentTextColor = mainButton?.textColor || prevMainButtonTextColor;
|
||||
const mainButtonCurrentIsActive = mainButton?.isActive !== undefined ? mainButton.isActive : prevMainButtonIsActive;
|
||||
const mainButtonCurrentText = mainButton?.text || prevMainButtonText;
|
||||
|
||||
useEffect(() => {
|
||||
if (!isOpen) setMainButton(undefined);
|
||||
}, [isOpen]);
|
||||
|
||||
const [shouldDecreaseWebFrameSize, setShouldDecreaseWebFrameSize] = useState(false);
|
||||
const [shouldHideButton, setShouldHideButton] = useState(true);
|
||||
|
||||
const buttonChangeTimeout = useRef<ReturnType<typeof setTimeout>>();
|
||||
|
||||
useEffect(() => {
|
||||
if (buttonChangeTimeout.current) clearTimeout(buttonChangeTimeout.current);
|
||||
if (!shouldShowMainButton) {
|
||||
setShouldDecreaseWebFrameSize(false);
|
||||
buttonChangeTimeout.current = setTimeout(() => {
|
||||
setShouldHideButton(true);
|
||||
}, MAIN_BUTTON_ANIMATION_TIME);
|
||||
} else {
|
||||
setShouldHideButton(false);
|
||||
buttonChangeTimeout.current = setTimeout(() => {
|
||||
setShouldDecreaseWebFrameSize(true);
|
||||
}, MAIN_BUTTON_ANIMATION_TIME);
|
||||
}
|
||||
}, [setShouldDecreaseWebFrameSize, shouldShowMainButton]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
className="WebAppModal"
|
||||
isOpen={isOpen}
|
||||
onClose={closeWebApp}
|
||||
header={header}
|
||||
hasCloseButton
|
||||
>
|
||||
{isOpen && (
|
||||
<>
|
||||
<iframe
|
||||
ref={ref}
|
||||
className={buildClassName('web-app-frame', shouldDecreaseWebFrameSize && 'with-button')}
|
||||
src={url}
|
||||
title={`${bot?.firstName} Web App`}
|
||||
sandbox="allow-scripts allow-same-origin allow-popups allow-forms"
|
||||
allow="camera; microphone; geolocation;"
|
||||
allowFullScreen
|
||||
/>
|
||||
<Button
|
||||
className={buildClassName(
|
||||
'web-app-button',
|
||||
shouldShowMainButton && 'visible',
|
||||
shouldHideButton && 'hidden',
|
||||
)}
|
||||
style={`background-color: ${mainButtonCurrentColor}; color: ${mainButtonCurrentTextColor}`}
|
||||
disabled={!mainButtonCurrentIsActive}
|
||||
onClick={handleMainButtonClick}
|
||||
>
|
||||
{mainButtonCurrentText}
|
||||
{mainButton?.isProgressVisible && <Spinner color="white" />}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(withGlobal<OwnProps>(
|
||||
(global, { webApp }): StateProps => {
|
||||
const { bot } = webApp || {};
|
||||
const isInstalled = Boolean(bot && global.attachMenu.bots[bot.id]);
|
||||
const chat = selectCurrentChat(global);
|
||||
const theme = selectTheme(global);
|
||||
|
||||
return {
|
||||
isInstalled,
|
||||
chat,
|
||||
theme,
|
||||
};
|
||||
},
|
||||
)(WebAppModal));
|
||||
148
src/components/main/hooks/useWebAppFrame.ts
Normal file
148
src/components/main/hooks/useWebAppFrame.ts
Normal file
@ -0,0 +1,148 @@
|
||||
import useWindowSize from '../../../hooks/useWindowSize';
|
||||
import { useCallback, useEffect, useRef } from '../../../lib/teact/teact';
|
||||
import { extractCurrentThemeParams } from '../../../util/themeStyle';
|
||||
|
||||
export type WebAppInboundEvent = {
|
||||
eventType: 'web_app_data_send';
|
||||
eventData: {
|
||||
data: string;
|
||||
};
|
||||
} | {
|
||||
eventType: 'web_app_setup_main_button';
|
||||
eventData: {
|
||||
is_visible: boolean;
|
||||
is_active: boolean;
|
||||
text: string;
|
||||
color: string;
|
||||
text_color: string;
|
||||
is_progress_visible: boolean;
|
||||
};
|
||||
} | {
|
||||
eventType: 'web_app_request_viewport';
|
||||
} | {
|
||||
eventType: 'web_app_request_theme';
|
||||
} | {
|
||||
eventType: 'web_app_ready';
|
||||
} | {
|
||||
eventType: 'web_app_expand';
|
||||
} | {
|
||||
eventType: 'web_app_close';
|
||||
};
|
||||
|
||||
type WebAppOutboundEvent = {
|
||||
eventType: 'viewport_changed';
|
||||
eventData: {
|
||||
height: number;
|
||||
width?: number;
|
||||
is_expanded?: boolean;
|
||||
};
|
||||
} | {
|
||||
eventType: 'theme_changed';
|
||||
eventData: {
|
||||
theme_params: {
|
||||
bg_color: string;
|
||||
text_color: string;
|
||||
hint_color: string;
|
||||
link_color: string;
|
||||
button_color: string;
|
||||
button_text_color: string;
|
||||
};
|
||||
};
|
||||
} | {
|
||||
eventType: 'main_button_pressed';
|
||||
};
|
||||
|
||||
const useWebAppFrame = (isOpen: boolean, isSimpleView: boolean, onEvent: (event: WebAppInboundEvent) => void) => {
|
||||
// eslint-disable-next-line no-null/no-null
|
||||
const ref = useRef<HTMLIFrameElement>(null);
|
||||
const ignoreEventsRef = useRef<boolean>(false);
|
||||
const windowSize = useWindowSize();
|
||||
|
||||
const reloadFrame = useCallback((url: string) => {
|
||||
if (!ref.current) return;
|
||||
const frame = ref.current;
|
||||
frame.src = 'about:blank';
|
||||
frame.addEventListener('load', () => {
|
||||
frame.src = url;
|
||||
}, { once: true });
|
||||
}, []);
|
||||
|
||||
const sendEvent = useCallback((event: WebAppOutboundEvent) => {
|
||||
if (!ref.current?.contentWindow) return;
|
||||
ref.current.contentWindow.postMessage(JSON.stringify(event), '*');
|
||||
}, []);
|
||||
|
||||
const sendViewport = useCallback(() => {
|
||||
if (!ref.current) {
|
||||
return;
|
||||
}
|
||||
const { width, height } = ref.current.getBoundingClientRect();
|
||||
sendEvent({
|
||||
eventType: 'viewport_changed',
|
||||
eventData: {
|
||||
width,
|
||||
height,
|
||||
is_expanded: true,
|
||||
},
|
||||
});
|
||||
}, [sendEvent]);
|
||||
|
||||
const sendTheme = useCallback(() => {
|
||||
sendEvent({
|
||||
eventType: 'theme_changed',
|
||||
eventData: {
|
||||
theme_params: extractCurrentThemeParams(),
|
||||
},
|
||||
});
|
||||
}, [sendEvent]);
|
||||
|
||||
const handleMessage = useCallback((event: MessageEvent<string>) => {
|
||||
if (ignoreEventsRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const data = JSON.parse(event.data) as WebAppInboundEvent;
|
||||
// Handle some app requests here to simplify hook usage
|
||||
if (data.eventType === 'web_app_request_viewport') {
|
||||
sendViewport();
|
||||
}
|
||||
|
||||
if (data.eventType === 'web_app_request_theme') {
|
||||
sendTheme();
|
||||
}
|
||||
|
||||
if (data.eventType === 'web_app_data_send') {
|
||||
if (!isSimpleView) return; // Allowed only in simple view
|
||||
ignoreEventsRef.current = true;
|
||||
}
|
||||
onEvent(data);
|
||||
} catch (err) {
|
||||
// Ignore other messages
|
||||
}
|
||||
}, [isSimpleView, onEvent, sendTheme, sendViewport]);
|
||||
|
||||
useEffect(() => {
|
||||
if (windowSize) {
|
||||
sendViewport();
|
||||
}
|
||||
}, [sendViewport, windowSize]);
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('message', handleMessage);
|
||||
return () => window.removeEventListener('message', handleMessage);
|
||||
}, [handleMessage]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen && ref.current?.contentWindow) {
|
||||
sendViewport();
|
||||
ignoreEventsRef.current = false;
|
||||
}
|
||||
}, [isOpen, sendViewport]);
|
||||
|
||||
return {
|
||||
ref, sendEvent, reloadFrame, sendViewport, sendTheme,
|
||||
};
|
||||
};
|
||||
|
||||
export default useWebAppFrame;
|
||||
@ -208,7 +208,7 @@ const AudioPlayer: FC<OwnProps & StateProps> = ({
|
||||
color="translucent"
|
||||
size="smaller"
|
||||
ariaLabel="Volume"
|
||||
withClickPropagation
|
||||
noPreventDefault
|
||||
>
|
||||
<i className={volumeIcon} onClick={handleVolumeClick} />
|
||||
{!IS_IOS && (
|
||||
|
||||
@ -410,7 +410,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
canReportChat,
|
||||
canDeleteChat: getCanDeleteChat(chat),
|
||||
hasLinkedChat: Boolean(chat?.fullInfo?.linkedChatId),
|
||||
botCommands: chatBot?.fullInfo?.botCommands,
|
||||
botCommands: chatBot?.fullInfo?.botInfo?.commands,
|
||||
};
|
||||
},
|
||||
)(HeaderMenuContainer));
|
||||
|
||||
@ -1,20 +1,22 @@
|
||||
import React, { FC, memo, useCallback } from '../../lib/teact/teact';
|
||||
import { getActions } from '../../global';
|
||||
|
||||
import { ApiMessage } from '../../api/types';
|
||||
|
||||
import { getPictogramDimensions } from '../common/helpers/mediaDimensions';
|
||||
import { getMessageMediaHash } from '../../global/helpers';
|
||||
import { getMessageMediaHash, getMessageSingleInlineButton } from '../../global/helpers';
|
||||
import { renderMessageSummary } from '../common/helpers/renderMessageText';
|
||||
import buildClassName from '../../util/buildClassName';
|
||||
import { IS_TOUCH_ENV } from '../../util/environment';
|
||||
|
||||
import useMedia from '../../hooks/useMedia';
|
||||
import useWebpThumbnail from '../../hooks/useWebpThumbnail';
|
||||
|
||||
import ConfirmDialog from '../ui/ConfirmDialog';
|
||||
import Button from '../ui/Button';
|
||||
import RippleEffect from '../ui/RippleEffect';
|
||||
import buildClassName from '../../util/buildClassName';
|
||||
import useFlag from '../../hooks/useFlag';
|
||||
import useLang from '../../hooks/useLang';
|
||||
import { renderMessageSummary } from '../common/helpers/renderMessageText';
|
||||
|
||||
import RippleEffect from '../ui/RippleEffect';
|
||||
import ConfirmDialog from '../ui/ConfirmDialog';
|
||||
import Button from '../ui/Button';
|
||||
import PinnedMessageNavigation from './PinnedMessageNavigation';
|
||||
|
||||
type OwnProps = {
|
||||
@ -31,6 +33,7 @@ type OwnProps = {
|
||||
const HeaderPinnedMessage: FC<OwnProps> = ({
|
||||
message, count, index, customTitle, className, onUnpinMessage, onClick, onAllPinnedClick,
|
||||
}) => {
|
||||
const { clickBotInlineButton } = getActions();
|
||||
const lang = useLang();
|
||||
const mediaThumbnail = useWebpThumbnail(message);
|
||||
const mediaBlobUrl = useMedia(getMessageMediaHash(message, 'pictogram'));
|
||||
@ -46,6 +49,16 @@ const HeaderPinnedMessage: FC<OwnProps> = ({
|
||||
}
|
||||
}, [closeUnpinDialog, onUnpinMessage, message.id]);
|
||||
|
||||
const inlineButton = getMessageSingleInlineButton(message);
|
||||
|
||||
const handleInlineButtonClick = useCallback(() => {
|
||||
if (inlineButton) {
|
||||
clickBotInlineButton({ messageId: message.id, button: inlineButton });
|
||||
}
|
||||
}, [clickBotInlineButton, inlineButton, message.id]);
|
||||
|
||||
const [noHoverColor, markNoHoverColor, unmarkNoHoverColor] = useFlag();
|
||||
|
||||
return (
|
||||
<div className={buildClassName('HeaderPinnedMessage-wrapper', className)}>
|
||||
{count > 1 && (
|
||||
@ -79,7 +92,11 @@ const HeaderPinnedMessage: FC<OwnProps> = ({
|
||||
confirmLabel="Unpin"
|
||||
confirmHandler={handleUnpinMessage}
|
||||
/>
|
||||
<div className="HeaderPinnedMessage" onClick={onClick} dir={lang.isRtl ? 'rtl' : undefined}>
|
||||
<div
|
||||
className={buildClassName('HeaderPinnedMessage', noHoverColor && 'no-hover')}
|
||||
onClick={onClick}
|
||||
dir={lang.isRtl ? 'rtl' : undefined}
|
||||
>
|
||||
<PinnedMessageNavigation
|
||||
count={count}
|
||||
index={index}
|
||||
@ -90,9 +107,20 @@ const HeaderPinnedMessage: FC<OwnProps> = ({
|
||||
{customTitle || `${lang('PinnedMessage')} ${index > 0 ? `#${count - index}` : ''}`}
|
||||
</div>
|
||||
<p dir="auto">{text}</p>
|
||||
<RippleEffect />
|
||||
</div>
|
||||
|
||||
<RippleEffect />
|
||||
{inlineButton && (
|
||||
<Button
|
||||
size="tiny"
|
||||
className="inline-button"
|
||||
onClick={handleInlineButtonClick}
|
||||
shouldStopPropagation
|
||||
onMouseEnter={!IS_TOUCH_ENV ? markNoHoverColor : undefined}
|
||||
onMouseLeave={!IS_TOUCH_ENV ? unmarkNoHoverColor : undefined}
|
||||
>
|
||||
{inlineButton.text}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -591,7 +591,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
let botDescription: string | undefined;
|
||||
if (selectIsChatBotNotStarted(global, chatId)) {
|
||||
if (chatBot.fullInfo) {
|
||||
botDescription = chatBot.fullInfo.botDescription || 'NoMessages';
|
||||
botDescription = chatBot.fullInfo.botInfo?.description || 'NoMessages';
|
||||
} else {
|
||||
botDescription = 'Updating bot info...';
|
||||
}
|
||||
|
||||
@ -421,8 +421,9 @@
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
|
||||
&:hover {
|
||||
&:hover:not(.no-hover) {
|
||||
background-color: var(--color-interactive-element-hover);
|
||||
}
|
||||
|
||||
@ -465,6 +466,8 @@
|
||||
margin-inline-start: 0.375rem;
|
||||
margin-top: 0.125rem;
|
||||
max-width: 15rem;
|
||||
min-width: 8rem;
|
||||
flex-grow: 1;
|
||||
|
||||
@media (min-width: 1440px) and (max-width: 1500px) {
|
||||
max-width: 14rem;
|
||||
@ -500,6 +503,21 @@
|
||||
}
|
||||
}
|
||||
|
||||
.inline-button {
|
||||
display: block;
|
||||
width: auto;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
border-radius: 1.5rem;
|
||||
padding: 0 0.75rem;
|
||||
font-weight: 500;
|
||||
text-transform: none;
|
||||
height: 2rem;
|
||||
max-width: 10rem;
|
||||
flex-shrink: 1;
|
||||
}
|
||||
|
||||
.emoji-small {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
|
||||
@ -15,6 +15,11 @@
|
||||
top: -2.875rem;
|
||||
}
|
||||
|
||||
.bubble {
|
||||
max-height: 20rem;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.is-pointer-env & {
|
||||
> .backdrop {
|
||||
position: absolute;
|
||||
@ -31,3 +36,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bot-attach-context-menu {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
@ -2,9 +2,13 @@ import React, {
|
||||
FC, memo, useCallback, useEffect,
|
||||
} from '../../../lib/teact/teact';
|
||||
|
||||
import { GlobalState } from '../../../global/types';
|
||||
import { ISettings } from '../../../types';
|
||||
|
||||
import { CONTENT_TYPES_WITH_PREVIEW } from '../../../config';
|
||||
import { IS_TOUCH_ENV } from '../../../util/environment';
|
||||
import { openSystemFilesDialog } from '../../../util/systemFilesDialog';
|
||||
|
||||
import useMouseInside from '../../../hooks/useMouseInside';
|
||||
import useLang from '../../../hooks/useLang';
|
||||
import useFlag from '../../../hooks/useFlag';
|
||||
@ -12,23 +16,39 @@ import useFlag from '../../../hooks/useFlag';
|
||||
import ResponsiveHoverButton from '../../ui/ResponsiveHoverButton';
|
||||
import Menu from '../../ui/Menu';
|
||||
import MenuItem from '../../ui/MenuItem';
|
||||
import AttachmentMenuBotItem from './AttachmentMenuBotItem';
|
||||
|
||||
import './AttachMenu.scss';
|
||||
|
||||
export type OwnProps = {
|
||||
chatId: string;
|
||||
isButtonVisible: boolean;
|
||||
canAttachMedia: boolean;
|
||||
canAttachPolls: boolean;
|
||||
isScheduled?: boolean;
|
||||
isPrivateChat?: boolean;
|
||||
attachMenuBots: GlobalState['attachMenu']['bots'];
|
||||
onFileSelect: (files: File[], isQuick: boolean) => void;
|
||||
onPollCreate: () => void;
|
||||
theme: ISettings['theme'];
|
||||
};
|
||||
|
||||
const AttachMenu: FC<OwnProps> = ({
|
||||
isButtonVisible, canAttachMedia, canAttachPolls, onFileSelect, onPollCreate,
|
||||
chatId,
|
||||
isButtonVisible,
|
||||
canAttachMedia,
|
||||
canAttachPolls,
|
||||
attachMenuBots,
|
||||
isScheduled,
|
||||
isPrivateChat,
|
||||
onFileSelect,
|
||||
onPollCreate,
|
||||
theme,
|
||||
}) => {
|
||||
const [isAttachMenuOpen, openAttachMenu, closeAttachMenu] = useFlag();
|
||||
const [handleMouseEnter, handleMouseLeave, markMouseInside] = useMouseInside(isAttachMenuOpen, closeAttachMenu);
|
||||
|
||||
const [isAttachmentBotMenuOpen, markAttachmentBotMenuOpen, unmarkAttachmentBotMenuOpen] = useFlag();
|
||||
useEffect(() => {
|
||||
if (isAttachMenuOpen) {
|
||||
markMouseInside();
|
||||
@ -84,7 +104,7 @@ const AttachMenu: FC<OwnProps> = ({
|
||||
</ResponsiveHoverButton>
|
||||
<Menu
|
||||
id="attach-menu-controls"
|
||||
isOpen={isAttachMenuOpen}
|
||||
isOpen={isAttachMenuOpen || isAttachmentBotMenuOpen}
|
||||
autoClose
|
||||
positionX="right"
|
||||
positionY="bottom"
|
||||
@ -105,15 +125,23 @@ const AttachMenu: FC<OwnProps> = ({
|
||||
)}
|
||||
{canAttachMedia && (
|
||||
<>
|
||||
<MenuItem icon="photo" onClick={handleQuickSelect}>
|
||||
{lang('AttachmentMenu.PhotoOrVideo')}
|
||||
</MenuItem>
|
||||
<MenuItem icon="photo" onClick={handleQuickSelect}>{lang('AttachmentMenu.PhotoOrVideo')}</MenuItem>
|
||||
<MenuItem icon="document" onClick={handleDocumentSelect}>{lang('AttachDocument')}</MenuItem>
|
||||
</>
|
||||
)}
|
||||
{canAttachPolls && (
|
||||
<MenuItem icon="poll" onClick={onPollCreate}>{lang('Poll')}</MenuItem>
|
||||
)}
|
||||
|
||||
{canAttachMedia && !isScheduled && isPrivateChat && Object.values(attachMenuBots).map((bot) => (
|
||||
<AttachmentMenuBotItem
|
||||
bot={bot}
|
||||
chatId={chatId}
|
||||
theme={theme}
|
||||
onMenuOpened={markAttachmentBotMenuOpen}
|
||||
onMenuClosed={unmarkAttachmentBotMenuOpen}
|
||||
/>
|
||||
))}
|
||||
</Menu>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
.root {
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&.compact {
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
.image {
|
||||
width: 1.75rem;
|
||||
position: absolute;
|
||||
|
||||
&.compact {
|
||||
width: 1.5rem;
|
||||
}
|
||||
}
|
||||
49
src/components/middle/composer/AttachmentMenuBotIcon.tsx
Normal file
49
src/components/middle/composer/AttachmentMenuBotIcon.tsx
Normal file
@ -0,0 +1,49 @@
|
||||
import React, { FC, memo, useMemo } from '../../../lib/teact/teact';
|
||||
|
||||
import { ISettings } from '../../../types';
|
||||
import { ApiDocument, ApiMediaFormat } from '../../../api/types';
|
||||
|
||||
import { IS_COMPACT_MENU } from '../../../util/environment';
|
||||
import useMedia from '../../../hooks/useMedia';
|
||||
import { getDocumentMediaHash } from '../../../global/helpers';
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
|
||||
import styles from './AttachmentMenuBotIcon.module.scss';
|
||||
|
||||
type OwnProps = {
|
||||
icon: ApiDocument;
|
||||
theme: ISettings['theme'];
|
||||
};
|
||||
|
||||
const ADDITIONAL_STROKE_WIDTH = '0.5px';
|
||||
const DARK_THEME_COLOR = 'rgb(170, 170, 170)';
|
||||
const LIGHT_THEME_COLOR = 'rgb(112, 117, 121)';
|
||||
const COLOR_REPLACE_PATTERN = /#fff/gi;
|
||||
|
||||
const AttachmentMenuBotIcon: FC<OwnProps> = ({
|
||||
icon, theme,
|
||||
}) => {
|
||||
const mediaData = useMedia(getDocumentMediaHash(icon), false, ApiMediaFormat.Text);
|
||||
|
||||
const iconSvg = useMemo(() => {
|
||||
if (!mediaData) return '';
|
||||
const color = theme === 'dark' ? DARK_THEME_COLOR : LIGHT_THEME_COLOR;
|
||||
|
||||
const mediaDataWithReplacedColors = mediaData.replace(COLOR_REPLACE_PATTERN, color);
|
||||
const doc = new DOMParser().parseFromString(mediaDataWithReplacedColors, 'image/svg+xml');
|
||||
doc.querySelectorAll('path').forEach((l) => {
|
||||
l.style.stroke = color;
|
||||
l.style.strokeWidth = ADDITIONAL_STROKE_WIDTH;
|
||||
});
|
||||
|
||||
return `data:image/svg+xml;utf8,${doc.documentElement.outerHTML}`;
|
||||
}, [mediaData, theme]);
|
||||
|
||||
return (
|
||||
<i className={buildClassName(styles.root, IS_COMPACT_MENU && styles.compact)}>
|
||||
<img src={iconSvg} alt="" className={buildClassName(styles.image, IS_COMPACT_MENU && styles.compact)} />
|
||||
</i>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(AttachmentMenuBotIcon);
|
||||
100
src/components/middle/composer/AttachmentMenuBotItem.tsx
Normal file
100
src/components/middle/composer/AttachmentMenuBotItem.tsx
Normal file
@ -0,0 +1,100 @@
|
||||
import React, {
|
||||
FC, memo, useCallback, useMemo, useState,
|
||||
} from '../../../lib/teact/teact';
|
||||
import { getActions } from '../../../global';
|
||||
|
||||
import { IAnchorPosition, ISettings } from '../../../types';
|
||||
import { ApiAttachMenuBot } from '../../../api/types';
|
||||
|
||||
import useFlag from '../../../hooks/useFlag';
|
||||
import useLang from '../../../hooks/useLang';
|
||||
|
||||
import Portal from '../../ui/Portal';
|
||||
import Menu from '../../ui/Menu';
|
||||
import MenuItem from '../../ui/MenuItem';
|
||||
import AttachmentMenuBotIcon from './AttachmentMenuBotIcon';
|
||||
|
||||
type OwnProps = {
|
||||
bot: ApiAttachMenuBot;
|
||||
theme: ISettings['theme'];
|
||||
chatId: string;
|
||||
onMenuOpened: VoidFunction;
|
||||
onMenuClosed: VoidFunction;
|
||||
};
|
||||
|
||||
const AttachmentMenuBotItem: FC<OwnProps> = ({
|
||||
bot,
|
||||
theme,
|
||||
chatId,
|
||||
onMenuOpened,
|
||||
onMenuClosed,
|
||||
}) => {
|
||||
const { callAttachMenuBot, toggleBotInAttachMenu } = getActions();
|
||||
|
||||
const lang = useLang();
|
||||
|
||||
const icon = useMemo(() => {
|
||||
return bot.icons.find(({ name }) => name === 'default_static')?.document;
|
||||
}, [bot.icons]);
|
||||
|
||||
const [isMenuOpen, openMenu, closeMenu] = useFlag();
|
||||
const [menuPosition, setMenuPosition] = useState<IAnchorPosition | undefined>(undefined);
|
||||
|
||||
const handleContextMenu = useCallback((e: React.UIEvent) => {
|
||||
e.preventDefault();
|
||||
const rect = e.currentTarget.getBoundingClientRect();
|
||||
setMenuPosition({ x: rect.right, y: rect.bottom });
|
||||
onMenuOpened();
|
||||
openMenu();
|
||||
}, [onMenuOpened, openMenu]);
|
||||
|
||||
const handleCloseMenu = useCallback(() => {
|
||||
closeMenu();
|
||||
onMenuClosed();
|
||||
}, [closeMenu, onMenuClosed]);
|
||||
|
||||
const handleCloseAnimationEnd = useCallback(() => {
|
||||
setMenuPosition(undefined);
|
||||
}, []);
|
||||
|
||||
const handleRemoveBot = useCallback(() => {
|
||||
toggleBotInAttachMenu({
|
||||
botId: bot.id,
|
||||
isEnabled: false,
|
||||
});
|
||||
}, [bot.id, toggleBotInAttachMenu]);
|
||||
|
||||
return (
|
||||
<MenuItem
|
||||
key={bot.id}
|
||||
customIcon={icon && <AttachmentMenuBotIcon icon={icon} theme={theme} />}
|
||||
icon={!icon ? 'bots' : undefined}
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={() => callAttachMenuBot({
|
||||
botId: bot.id,
|
||||
chatId,
|
||||
})}
|
||||
onContextMenu={handleContextMenu}
|
||||
>
|
||||
{bot.shortName}
|
||||
{menuPosition && (
|
||||
<Portal>
|
||||
<Menu
|
||||
isOpen={isMenuOpen}
|
||||
positionX="right"
|
||||
style={`left: ${menuPosition.x}px;top: ${menuPosition.y}px;`}
|
||||
className="bot-attach-context-menu"
|
||||
autoClose
|
||||
onClose={handleCloseMenu}
|
||||
onCloseAnimationEnd={handleCloseAnimationEnd}
|
||||
>
|
||||
<MenuItem icon="stop" destructive onClick={handleRemoveBot}>{lang('WebApp.RemoveBot')}</MenuItem>
|
||||
</Menu>
|
||||
</Portal>
|
||||
)}
|
||||
|
||||
</MenuItem>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(AttachmentMenuBotItem);
|
||||
61
src/components/middle/composer/BotMenuButton.tsx
Normal file
61
src/components/middle/composer/BotMenuButton.tsx
Normal file
@ -0,0 +1,61 @@
|
||||
import React, {
|
||||
FC, memo, useEffect, useRef,
|
||||
} from '../../../lib/teact/teact';
|
||||
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
|
||||
import Button from '../../ui/Button';
|
||||
|
||||
type OwnProps = {
|
||||
isOpen?: boolean;
|
||||
onClick: VoidFunction;
|
||||
text: string;
|
||||
isDisabled?: boolean;
|
||||
};
|
||||
|
||||
const BotMenuButton: FC<OwnProps> = ({
|
||||
isOpen,
|
||||
onClick,
|
||||
text,
|
||||
isDisabled,
|
||||
}) => {
|
||||
// eslint-disable-next-line no-null/no-null
|
||||
const textRef = useRef<HTMLSpanElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const textEl = textRef.current;
|
||||
if (!textEl) return;
|
||||
|
||||
const width = textEl.scrollWidth + 1; // Make width slightly bigger prevent ellipsis in some cases
|
||||
|
||||
const composerEl = textEl.closest('.Composer') as HTMLElement;
|
||||
composerEl.style.setProperty('--bot-menu-text-width', `${width}px`);
|
||||
}, [isOpen, text]);
|
||||
|
||||
useEffect(() => {
|
||||
const textEl = textRef.current;
|
||||
if (!textEl) return undefined;
|
||||
|
||||
const composerEl = textEl.closest('.Composer') as HTMLElement;
|
||||
|
||||
return () => {
|
||||
composerEl.style.removeProperty('--bot-menu-text-width');
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Button
|
||||
className={buildClassName('bot-menu', isOpen && 'open')}
|
||||
round
|
||||
color="translucent"
|
||||
disabled={isDisabled}
|
||||
onClick={onClick}
|
||||
ariaLabel="Open bot command keyboard"
|
||||
>
|
||||
<i className={buildClassName('bot-menu-icon', 'icon-webapp', isOpen && 'open')} />
|
||||
<span ref={textRef} className="bot-menu-text">{text}</span>
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(BotMenuButton);
|
||||
@ -277,6 +277,53 @@
|
||||
}
|
||||
}
|
||||
|
||||
&.bot-menu {
|
||||
--icon-width: 1.25rem;
|
||||
--icon-gap: 0.25rem;
|
||||
--padding-sides: 0.5rem;
|
||||
background: var(--color-primary) !important;
|
||||
height: 2rem;
|
||||
margin: 0 0.5rem 0.75rem;
|
||||
color: white !important;
|
||||
text-transform: none;
|
||||
display: inline-flex;
|
||||
padding: 0 var(--padding-sides);
|
||||
width: 2rem;
|
||||
max-width: clamp(0px, 12rem, 25vw);
|
||||
/* stylelint-disable-next-line plugin/no-low-performance-animation-properties */
|
||||
transition: 0.25s ease-out width, 0.25s ease-out border-radius;
|
||||
border-radius: 0.5rem;
|
||||
justify-content: flex-start;
|
||||
|
||||
&.open {
|
||||
width: calc(var(--bot-menu-text-width) + var(--padding-sides) * 2 + var(--icon-gap) + var(--icon-width));
|
||||
border-radius: 1rem;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
margin-bottom: 0.4375rem;
|
||||
}
|
||||
}
|
||||
|
||||
.bot-menu-icon {
|
||||
font-size: 1.25rem;
|
||||
margin-right: var(--icon-gap);
|
||||
transition: 0.25s ease-out transform;
|
||||
transform: translateX(-0.15rem);
|
||||
|
||||
&.open {
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
.bot-menu-text {
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&.bot-commands {
|
||||
color: var(--color-primary) !important;
|
||||
|
||||
|
||||
@ -18,11 +18,15 @@ import {
|
||||
ApiUser,
|
||||
MAIN_THREAD_ID,
|
||||
ApiBotCommand,
|
||||
ApiBotMenuButton,
|
||||
} from '../../../api/types';
|
||||
import { InlineBotSettings } from '../../../types';
|
||||
import { InlineBotSettings, ISettings } from '../../../types';
|
||||
|
||||
import {
|
||||
BASE_EMOJI_KEYWORD_LANG, EDITABLE_INPUT_ID, REPLIES_USER_ID, SEND_MESSAGE_ACTION_INTERVAL,
|
||||
BASE_EMOJI_KEYWORD_LANG,
|
||||
EDITABLE_INPUT_ID,
|
||||
REPLIES_USER_ID,
|
||||
SEND_MESSAGE_ACTION_INTERVAL,
|
||||
EDITABLE_INPUT_CSS_SELECTOR,
|
||||
} from '../../../config';
|
||||
import { IS_VOICE_RECORDING_SUPPORTED, IS_SINGLE_COLUMN_LAYOUT, IS_IOS } from '../../../util/environment';
|
||||
@ -43,6 +47,7 @@ import {
|
||||
selectEditingScheduledDraft,
|
||||
selectEditingDraft,
|
||||
selectRequestedText,
|
||||
selectTheme,
|
||||
} from '../../../global/selectors';
|
||||
import {
|
||||
getAllowedAttachmentOptions,
|
||||
@ -105,6 +110,7 @@ import PollModal from './PollModal.async';
|
||||
import DropArea, { DropAreaState } from './DropArea.async';
|
||||
import WebPagePreview from './WebPagePreview';
|
||||
import SendAsMenu from './SendAsMenu.async';
|
||||
import BotMenuButton from './BotMenuButton';
|
||||
|
||||
import './Composer.scss';
|
||||
|
||||
@ -147,12 +153,16 @@ type StateProps =
|
||||
isInlineBotLoading: boolean;
|
||||
inlineBots?: Record<string, false | InlineBotSettings>;
|
||||
botCommands?: ApiBotCommand[] | false;
|
||||
botMenuButton?: ApiBotMenuButton;
|
||||
chatBotCommands?: ApiBotCommand[];
|
||||
sendAsUser?: ApiUser;
|
||||
sendAsChat?: ApiChat;
|
||||
sendAsId?: string;
|
||||
editingDraft?: ApiFormattedText;
|
||||
requestedText?: string;
|
||||
attachMenuBots: GlobalState['attachMenu']['bots'];
|
||||
isPrivateChat?: boolean;
|
||||
theme: ISettings['theme'];
|
||||
}
|
||||
& Pick<GlobalState, 'connectionState'>;
|
||||
|
||||
@ -221,6 +231,10 @@ const Composer: FC<OwnProps & StateProps> = ({
|
||||
sendAsId,
|
||||
editingDraft,
|
||||
requestedText,
|
||||
botMenuButton,
|
||||
attachMenuBots,
|
||||
isPrivateChat,
|
||||
theme,
|
||||
}) => {
|
||||
const {
|
||||
sendMessage,
|
||||
@ -238,6 +252,7 @@ const Composer: FC<OwnProps & StateProps> = ({
|
||||
loadSendAs,
|
||||
loadFullChat,
|
||||
resetOpenChatWithText,
|
||||
callAttachMenuBot,
|
||||
} = getActions();
|
||||
const lang = useLang();
|
||||
|
||||
@ -616,6 +631,13 @@ const Composer: FC<OwnProps & StateProps> = ({
|
||||
resetComposer, stopRecordingVoice, showDialog, slowMode, isAdmin, sendMessage, forwardMessages, lang, htmlRef,
|
||||
]);
|
||||
|
||||
const handleClickBotMenu = useCallback(() => {
|
||||
if (botMenuButton?.type !== 'webApp') return;
|
||||
callAttachMenuBot({
|
||||
botId: chatId, chatId, isFromBotMenu: true, url: botMenuButton.url,
|
||||
});
|
||||
}, [botMenuButton, callAttachMenuBot, chatId]);
|
||||
|
||||
const handleActivateBotCommandMenu = useCallback(() => {
|
||||
closeSymbolMenu();
|
||||
openBotCommandMenu();
|
||||
@ -927,6 +949,8 @@ const Composer: FC<OwnProps & StateProps> = ({
|
||||
: mainButtonState === MainButtonState.Schedule ? handleSendScheduled
|
||||
: handleSend;
|
||||
|
||||
const isBotMenuButtonCommands = botMenuButton && botMenuButton?.type === 'commands';
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
{canAttachMedia && isReady && (
|
||||
@ -1016,7 +1040,17 @@ const Composer: FC<OwnProps & StateProps> = ({
|
||||
disabled={!canAttachEmbedLinks}
|
||||
/>
|
||||
<div className="message-input-wrapper">
|
||||
{isChatWithBot && botCommands !== false && !activeVoiceRecording && !editingMessage && (
|
||||
{isChatWithBot && botMenuButton && botMenuButton.type === 'webApp' && !editingMessage
|
||||
&& (
|
||||
<BotMenuButton
|
||||
isOpen={!html && !activeVoiceRecording}
|
||||
onClick={handleClickBotMenu}
|
||||
text={botMenuButton.text}
|
||||
isDisabled={Boolean(activeVoiceRecording)}
|
||||
/>
|
||||
)}
|
||||
{isChatWithBot && isBotMenuButtonCommands && botCommands !== false && !activeVoiceRecording
|
||||
&& !editingMessage && (
|
||||
<ResponsiveHoverButton
|
||||
className={buildClassName('bot-commands', isBotCommandMenuOpen && 'activated')}
|
||||
round
|
||||
@ -1129,11 +1163,16 @@ const Composer: FC<OwnProps & StateProps> = ({
|
||||
addRecentEmoji={addRecentEmoji}
|
||||
/>
|
||||
<AttachMenu
|
||||
chatId={chatId}
|
||||
isButtonVisible={!activeVoiceRecording && !editingMessage}
|
||||
canAttachMedia={canAttachMedia}
|
||||
canAttachPolls={canAttachPolls}
|
||||
onFileSelect={handleFileSelect}
|
||||
onPollCreate={openPollModal}
|
||||
isScheduled={shouldSchedule}
|
||||
isPrivateChat={isPrivateChat}
|
||||
attachMenuBots={attachMenuBots}
|
||||
theme={theme}
|
||||
/>
|
||||
{botKeyboardMessageId && (
|
||||
<BotKeyboardMenu
|
||||
@ -1215,6 +1254,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
const chatBot = chatId !== REPLIES_USER_ID ? selectChatBot(global, chatId) : undefined;
|
||||
const isChatWithBot = Boolean(chatBot);
|
||||
const isChatWithSelf = selectIsChatWithSelf(global, chatId);
|
||||
const isPrivateChat = Boolean(selectUser(global, chatId));
|
||||
const messageWithActualBotKeyboard = isChatWithBot && selectNewestMessageWithBotKeyboardButtons(global, chatId);
|
||||
const scheduledIds = selectScheduledIds(global, chatId);
|
||||
const { language, shouldSuggestStickers } = global.settings.byKey;
|
||||
@ -1242,6 +1282,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
chat,
|
||||
isChatWithBot,
|
||||
isChatWithSelf,
|
||||
isPrivateChat,
|
||||
canScheduleUntilOnline: selectCanScheduleUntilOnline(global, chatId),
|
||||
isChannel: chat ? isChatChannel(chat) : undefined,
|
||||
isRightColumnShown: selectIsRightColumnShown(global),
|
||||
@ -1268,13 +1309,16 @@ export default memo(withGlobal<OwnProps>(
|
||||
emojiKeywords: emojiKeywords?.keywords,
|
||||
inlineBots: global.inlineBots.byUsername,
|
||||
isInlineBotLoading: global.inlineBots.isLoading,
|
||||
chatBotCommands: chat?.fullInfo?.botCommands,
|
||||
botCommands: chatBot?.fullInfo ? (chatBot.fullInfo.botCommands || false) : undefined,
|
||||
chatBotCommands: chat?.fullInfo && chat.fullInfo.botCommands,
|
||||
botCommands: chatBot?.fullInfo ? (chatBot.fullInfo.botInfo?.commands || false) : undefined,
|
||||
botMenuButton: chatBot?.fullInfo?.botInfo?.menuButton,
|
||||
sendAsUser,
|
||||
sendAsChat,
|
||||
sendAsId,
|
||||
editingDraft,
|
||||
requestedText,
|
||||
attachMenuBots: global.attachMenu.bots,
|
||||
theme: selectTheme(global),
|
||||
};
|
||||
},
|
||||
)(Composer));
|
||||
|
||||
@ -96,6 +96,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Remove this monster with context menu refactor
|
||||
.Button.bot-menu:not(.open) ~ &,
|
||||
.Button.bot-commands ~ &,
|
||||
.Button.send-as-button ~ & {
|
||||
.is-pointer-env & > .backdrop {
|
||||
@ -104,6 +106,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
.Button.bot-menu.open ~ & {
|
||||
.is-pointer-env & > .backdrop {
|
||||
left: calc(var(--bot-menu-text-width, 0) + 3rem);
|
||||
}
|
||||
}
|
||||
|
||||
.bubble {
|
||||
width: calc(var(--symbol-menu-width) + 0.25rem); // Reserve width for scrollbar
|
||||
padding: 0;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
.InlineButtons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-width: var(--max-width);
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
@ -63,6 +64,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
.inline-button-text {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.row:first-of-type .Button {
|
||||
margin-top: 0.25rem !important;
|
||||
}
|
||||
|
||||
@ -29,10 +29,11 @@ const InlineButtons: FC<OwnProps> = ({ message, onClick }) => {
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={() => onClick({ messageId: message.id, button })}
|
||||
>
|
||||
{renderText(lang(button.text))}
|
||||
<span className="inline-button-text">{renderText(lang(button.text))}</span>
|
||||
{['buy', 'receipt'].includes(button.type) && <i className="icon-card" />}
|
||||
{button.type === 'url' && !RE_TME_LINK.test(button.url) && <i className="icon-arrow-right" />}
|
||||
{button.type === 'switchBotInline' && <i className="icon-share-filled" />}
|
||||
{['webView', 'simpleWebView'].includes(button.type) && <i className="icon-webapp" />}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@ -53,6 +53,7 @@ import {
|
||||
selectIsMessageProtected,
|
||||
selectLocalAnimatedEmojiEffect,
|
||||
selectDefaultReaction,
|
||||
selectReplySender,
|
||||
} from '../../../global/selectors';
|
||||
import {
|
||||
getMessageContent,
|
||||
@ -992,7 +993,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
message, album, withSenderName, withAvatar, threadId, messageListType, isLastInDocumentGroup,
|
||||
} = ownProps;
|
||||
const {
|
||||
id, chatId, viaBotId, replyToChatId, replyToMessageId, isOutgoing, threadInfo,
|
||||
id, chatId, viaBotId, replyToChatId, replyToMessageId, isOutgoing, threadInfo, forwardInfo,
|
||||
} = message;
|
||||
|
||||
const chat = selectChat(global, chatId);
|
||||
@ -1014,7 +1015,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
const replyMessage = replyToMessageId && !shouldHideReply
|
||||
? selectChatMessage(global, isRepliesChat && replyToChatId ? replyToChatId : chatId, replyToMessageId)
|
||||
: undefined;
|
||||
const replyMessageSender = replyMessage && selectSender(global, replyMessage);
|
||||
const replyMessageSender = replyMessage && selectReplySender(global, replyMessage, Boolean(forwardInfo));
|
||||
|
||||
const uploadProgress = selectUploadProgress(global, message);
|
||||
const isFocused = messageListType === 'thread' && (
|
||||
|
||||
@ -37,7 +37,9 @@ export type OwnProps = {
|
||||
faded?: boolean;
|
||||
tabIndex?: number;
|
||||
isRtl?: boolean;
|
||||
withClickPropagation?: boolean;
|
||||
noPreventDefault?: boolean;
|
||||
shouldStopPropagation?: boolean;
|
||||
style?: string;
|
||||
onClick?: (e: ReactMouseEvent<HTMLButtonElement, MouseEvent>) => void;
|
||||
onContextMenu?: (e: ReactMouseEvent<HTMLButtonElement, MouseEvent>) => void;
|
||||
onMouseDown?: (e: ReactMouseEvent<HTMLButtonElement>) => void;
|
||||
@ -79,7 +81,9 @@ const Button: FC<OwnProps> = ({
|
||||
faded,
|
||||
tabIndex,
|
||||
isRtl,
|
||||
withClickPropagation,
|
||||
noPreventDefault,
|
||||
shouldStopPropagation,
|
||||
style,
|
||||
}) => {
|
||||
// eslint-disable-next-line no-null/no-null
|
||||
let elementRef = useRef<HTMLButtonElement | HTMLAnchorElement>(null);
|
||||
@ -111,18 +115,21 @@ const Button: FC<OwnProps> = ({
|
||||
onClick(e);
|
||||
}
|
||||
|
||||
if (shouldStopPropagation) e.stopPropagation();
|
||||
|
||||
setIsClicked(true);
|
||||
setTimeout(() => {
|
||||
setIsClicked(false);
|
||||
}, CLICKED_TIMEOUT);
|
||||
}, [disabled, onClick]);
|
||||
}, [disabled, onClick, shouldStopPropagation]);
|
||||
|
||||
const handleMouseDown = useCallback((e: ReactMouseEvent<HTMLButtonElement>) => {
|
||||
if (!withClickPropagation) e.preventDefault();
|
||||
if (!noPreventDefault) e.preventDefault();
|
||||
|
||||
if (!disabled && onMouseDown) {
|
||||
onMouseDown(e);
|
||||
}
|
||||
}, [onMouseDown, disabled, withClickPropagation]);
|
||||
}, [disabled, noPreventDefault, onMouseDown]);
|
||||
|
||||
if (href) {
|
||||
return (
|
||||
@ -137,6 +144,7 @@ const Button: FC<OwnProps> = ({
|
||||
dir={isRtl ? 'rtl' : undefined}
|
||||
aria-label={ariaLabel}
|
||||
aria-controls={ariaControls}
|
||||
style={style}
|
||||
>
|
||||
{children}
|
||||
{!disabled && ripple && (
|
||||
@ -164,7 +172,7 @@ const Button: FC<OwnProps> = ({
|
||||
title={ariaLabel}
|
||||
tabIndex={tabIndex}
|
||||
dir={isRtl ? 'rtl' : undefined}
|
||||
style={backgroundImage ? `background-image: url(${backgroundImage})` : undefined}
|
||||
style={backgroundImage ? `background-image: url(${backgroundImage})` : style}
|
||||
>
|
||||
{isLoading ? (
|
||||
<div>
|
||||
|
||||
@ -67,7 +67,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
body.has-open-dialog &:not(.CustomSendMenu) .bubble {
|
||||
body.has-open-dialog &:not(.CustomSendMenu):not(.web-app-more-menu) .bubble {
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
|
||||
@ -10,9 +10,11 @@ type OnClickHandler = (e: React.SyntheticEvent<HTMLDivElement | HTMLAnchorElemen
|
||||
|
||||
type OwnProps = {
|
||||
icon?: string;
|
||||
customIcon?: React.ReactNode;
|
||||
className?: string;
|
||||
children: React.ReactNode;
|
||||
onClick?: OnClickHandler;
|
||||
onContextMenu?: (e: React.UIEvent) => void;
|
||||
href?: string;
|
||||
download?: string;
|
||||
disabled?: boolean;
|
||||
@ -23,6 +25,7 @@ type OwnProps = {
|
||||
const MenuItem: FC<OwnProps> = (props) => {
|
||||
const {
|
||||
icon,
|
||||
customIcon,
|
||||
className,
|
||||
children,
|
||||
onClick,
|
||||
@ -31,6 +34,7 @@ const MenuItem: FC<OwnProps> = (props) => {
|
||||
disabled,
|
||||
destructive,
|
||||
ariaLabel,
|
||||
onContextMenu,
|
||||
} = props;
|
||||
|
||||
const lang = useLang();
|
||||
@ -70,9 +74,10 @@ const MenuItem: FC<OwnProps> = (props) => {
|
||||
|
||||
const content = (
|
||||
<>
|
||||
{icon && (
|
||||
{!customIcon && icon && (
|
||||
<i className={`icon-${icon}`} data-char={icon.startsWith('char-') ? icon.replace('char-', '') : undefined} />
|
||||
)}
|
||||
{customIcon}
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
@ -103,6 +108,7 @@ const MenuItem: FC<OwnProps> = (props) => {
|
||||
className={fullClassName}
|
||||
onClick={handleClick}
|
||||
onKeyDown={handleKeyDown}
|
||||
onContextMenu={onContextMenu}
|
||||
aria-label={ariaLabel}
|
||||
title={ariaLabel}
|
||||
dir={lang.isRtl ? 'rtl' : undefined}
|
||||
|
||||
@ -35,7 +35,7 @@ export const MEDIA_PROGRESSIVE_CACHE_DISABLED = false;
|
||||
export const MEDIA_PROGRESSIVE_CACHE_NAME = 'tt-media-progressive';
|
||||
export const MEDIA_CACHE_MAX_BYTES = 512 * 1024; // 512 KB
|
||||
export const CUSTOM_BG_CACHE_NAME = 'tt-custom-bg';
|
||||
export const LANG_CACHE_NAME = 'tt-lang-packs-v8';
|
||||
export const LANG_CACHE_NAME = 'tt-lang-packs-v9';
|
||||
export const ASSET_CACHE_NAME = 'tt-assets';
|
||||
export const AUTODOWNLOAD_FILESIZE_MB_LIMITS = [1, 5, 10, 50, 100, 500];
|
||||
|
||||
|
||||
@ -11,13 +11,14 @@ import {
|
||||
import { callApi } from '../../../api/gramjs';
|
||||
import {
|
||||
selectChat, selectChatBot, selectChatMessage, selectCurrentChat, selectCurrentMessageList,
|
||||
selectReplyingToId, selectSendAs, selectUser,
|
||||
selectIsTrustedBot, selectReplyingToId, selectSendAs, selectUser,
|
||||
} from '../../selectors';
|
||||
import { addChats, addUsers, removeBlockedContact } from '../../reducers';
|
||||
import { buildCollectionByKey } from '../../../util/iteratees';
|
||||
import { debounce } from '../../../util/schedulers';
|
||||
import { replaceInlineBotSettings, replaceInlineBotsIsLoading } from '../../reducers/bots';
|
||||
import { getServerTime } from '../../../util/serverTime';
|
||||
import { extractCurrentThemeParams } from '../../../util/themeStyle';
|
||||
import PopupManager from '../../../util/PopupManager';
|
||||
|
||||
const GAMEE_URL = 'https://prizes.gamee.com/';
|
||||
@ -107,6 +108,51 @@ addActionHandler('clickBotInlineButton', (global, actions, payload) => {
|
||||
actions.openChatWithInfo({ id: userId });
|
||||
break;
|
||||
}
|
||||
|
||||
case 'simpleWebView': {
|
||||
const { url } = button;
|
||||
const { chatId } = selectCurrentMessageList(global) || {};
|
||||
if (!chatId) {
|
||||
return;
|
||||
}
|
||||
const bot = selectChatBot(global, chatId);
|
||||
if (!bot) {
|
||||
return;
|
||||
}
|
||||
const theme = extractCurrentThemeParams();
|
||||
actions.requestSimpleWebView({
|
||||
url, bot, theme, buttonText: button.text,
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case 'webView': {
|
||||
const { url } = button;
|
||||
const chat = selectCurrentChat(global);
|
||||
if (!chat) {
|
||||
return;
|
||||
}
|
||||
const message = selectChatMessage(global, chat.id, messageId);
|
||||
if (!message) {
|
||||
return;
|
||||
}
|
||||
if (!message.viaBotId && !message.senderId) {
|
||||
return;
|
||||
}
|
||||
const bot = selectChatBot(global, message.viaBotId! || message.senderId!);
|
||||
if (!bot) {
|
||||
return;
|
||||
}
|
||||
const theme = extractCurrentThemeParams();
|
||||
actions.requestWebView({
|
||||
url,
|
||||
bot,
|
||||
peer: chat,
|
||||
theme,
|
||||
buttonText: button.text,
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -322,6 +368,252 @@ addActionHandler('startBot', async (global, actions, payload) => {
|
||||
});
|
||||
});
|
||||
|
||||
addActionHandler('requestSimpleWebView', async (global, actions, payload) => {
|
||||
const {
|
||||
url, bot, theme, buttonText,
|
||||
} = payload;
|
||||
|
||||
if (!selectIsTrustedBot(global, bot)) {
|
||||
setGlobal({
|
||||
...global,
|
||||
botTrustRequest: {
|
||||
bot,
|
||||
type: 'webApp',
|
||||
onConfirm: {
|
||||
action: 'requestSimpleWebView',
|
||||
payload,
|
||||
},
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const webViewUrl = await callApi('requestSimpleWebView', { url, bot, theme });
|
||||
if (!webViewUrl) {
|
||||
return;
|
||||
}
|
||||
|
||||
global = getGlobal();
|
||||
setGlobal({
|
||||
...global,
|
||||
webApp: {
|
||||
url: webViewUrl,
|
||||
bot,
|
||||
buttonText,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
addActionHandler('requestWebView', async (global, actions, payload) => {
|
||||
const {
|
||||
url, bot, peer, theme, isSilent, buttonText, isFromBotMenu, startParam,
|
||||
} = payload;
|
||||
|
||||
if (!selectIsTrustedBot(global, bot)) {
|
||||
setGlobal({
|
||||
...global,
|
||||
botTrustRequest: {
|
||||
bot,
|
||||
type: 'webApp',
|
||||
onConfirm: {
|
||||
action: 'requestWebView',
|
||||
payload,
|
||||
},
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const currentMessageList = selectCurrentMessageList(global);
|
||||
if (!currentMessageList) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { chatId, threadId } = currentMessageList;
|
||||
const reply = chatId && selectReplyingToId(global, chatId, threadId);
|
||||
const result = await callApi('requestWebView', {
|
||||
url,
|
||||
bot,
|
||||
peer,
|
||||
theme,
|
||||
isSilent,
|
||||
replyToMessageId: reply || undefined,
|
||||
isFromBotMenu,
|
||||
startParam,
|
||||
});
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { url: webViewUrl, queryId } = result;
|
||||
|
||||
global = getGlobal();
|
||||
setGlobal({
|
||||
...global,
|
||||
webApp: {
|
||||
url: webViewUrl,
|
||||
bot,
|
||||
queryId,
|
||||
buttonText,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
addActionHandler('prolongWebView', (global, actions, payload) => {
|
||||
const {
|
||||
bot, peer, isSilent, replyToMessageId, queryId,
|
||||
} = payload;
|
||||
|
||||
const result = callApi('prolongWebView', {
|
||||
bot,
|
||||
peer,
|
||||
isSilent,
|
||||
replyToMessageId,
|
||||
queryId,
|
||||
});
|
||||
|
||||
if (!result) {
|
||||
actions.closeWebApp();
|
||||
}
|
||||
});
|
||||
|
||||
addActionHandler('sendWebViewData', (global, actions, payload) => {
|
||||
const {
|
||||
bot, data, buttonText,
|
||||
} = payload;
|
||||
|
||||
callApi('sendWebViewData', {
|
||||
bot,
|
||||
data,
|
||||
buttonText,
|
||||
});
|
||||
});
|
||||
|
||||
addActionHandler('closeWebApp', (global) => {
|
||||
return {
|
||||
...global,
|
||||
webApp: undefined,
|
||||
};
|
||||
});
|
||||
|
||||
addActionHandler('cancelBotTrustRequest', (global) => {
|
||||
return {
|
||||
...global,
|
||||
botTrustRequest: undefined,
|
||||
};
|
||||
});
|
||||
|
||||
addActionHandler('markBotTrusted', (global, actions, payload) => {
|
||||
const { botId } = payload;
|
||||
const { trustedBotIds } = global;
|
||||
|
||||
const newTrustedBotIds = new Set(trustedBotIds);
|
||||
newTrustedBotIds.add(botId);
|
||||
setGlobal({
|
||||
...global,
|
||||
botTrustRequest: undefined,
|
||||
trustedBotIds: Array.from(newTrustedBotIds),
|
||||
});
|
||||
|
||||
if (global.botTrustRequest?.onConfirm) {
|
||||
const { action, payload: callbackPayload } = global.botTrustRequest.onConfirm;
|
||||
actions[action](callbackPayload);
|
||||
}
|
||||
});
|
||||
|
||||
addActionHandler('loadAttachMenuBots', async (global, actions, payload) => {
|
||||
const { hash } = payload || {};
|
||||
await loadAttachMenuBots(hash);
|
||||
});
|
||||
|
||||
addActionHandler('toggleBotInAttachMenu', async (global, actions, payload) => {
|
||||
const { botId, isEnabled } = payload;
|
||||
|
||||
const bot = selectUser(global, botId);
|
||||
|
||||
if (!bot) return;
|
||||
|
||||
await toggleBotInAttachMenu(bot, isEnabled);
|
||||
});
|
||||
|
||||
async function toggleBotInAttachMenu(bot: ApiUser, isEnabled: boolean) {
|
||||
await callApi('toggleBotInAttachMenu', { bot, isEnabled });
|
||||
await loadAttachMenuBots();
|
||||
}
|
||||
|
||||
async function loadAttachMenuBots(hash?: string) {
|
||||
const result = await callApi('loadAttachMenuBots', { hash });
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
const global = getGlobal();
|
||||
setGlobal({
|
||||
...global,
|
||||
attachMenu: {
|
||||
hash: result.hash,
|
||||
bots: result.bots,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
addActionHandler('callAttachMenuBot', (global, actions, payload) => {
|
||||
const {
|
||||
chatId, botId, isFromBotMenu, url, startParam,
|
||||
} = payload;
|
||||
const chat = selectChat(global, chatId);
|
||||
const bot = selectChatBot(global, botId);
|
||||
if (!chat || !bot) {
|
||||
return undefined;
|
||||
}
|
||||
const { attachMenu: { bots } } = global;
|
||||
if (!isFromBotMenu && !bots[botId]) {
|
||||
return {
|
||||
...global,
|
||||
botAttachRequest: {
|
||||
bot,
|
||||
chatId,
|
||||
startParam,
|
||||
},
|
||||
};
|
||||
}
|
||||
const theme = extractCurrentThemeParams();
|
||||
actions.requestWebView({
|
||||
url,
|
||||
peer: chat,
|
||||
bot,
|
||||
theme,
|
||||
buttonText: '',
|
||||
isFromBotMenu,
|
||||
startParam,
|
||||
});
|
||||
|
||||
return undefined;
|
||||
});
|
||||
|
||||
addActionHandler('confirmBotAttachRequest', async (global, actions) => {
|
||||
const { botAttachRequest } = global;
|
||||
if (!botAttachRequest) return;
|
||||
|
||||
const { bot, chatId, startParam } = botAttachRequest;
|
||||
|
||||
setGlobal({
|
||||
...global,
|
||||
botAttachRequest: undefined,
|
||||
});
|
||||
|
||||
await toggleBotInAttachMenu(bot, true);
|
||||
|
||||
actions.callAttachMenuBot({ chatId, botId: bot.id, startParam });
|
||||
});
|
||||
|
||||
addActionHandler('closeBotAttachRequestModal', (global) => {
|
||||
return {
|
||||
...global,
|
||||
botAttachRequest: undefined,
|
||||
};
|
||||
});
|
||||
|
||||
async function searchInlineBot({
|
||||
username,
|
||||
inlineBotData,
|
||||
|
||||
@ -34,7 +34,7 @@ import {
|
||||
import { buildCollectionByKey, omit } from '../../../util/iteratees';
|
||||
import { debounce, pause, throttle } from '../../../util/schedulers';
|
||||
import {
|
||||
isChatSummaryOnly, isChatArchived, isChatBasicGroup,
|
||||
isChatSummaryOnly, isChatArchived, isChatBasicGroup, isUserBot,
|
||||
} from '../../helpers';
|
||||
import { processDeepLink } from '../../../util/deeplink';
|
||||
import { updateGroupCall } from '../../reducers/calls';
|
||||
@ -509,7 +509,7 @@ addActionHandler('openChatByInvite', async (global, actions, payload) => {
|
||||
});
|
||||
|
||||
addActionHandler('openChatByPhoneNumber', async (global, actions, payload) => {
|
||||
const { phoneNumber } = payload!;
|
||||
const { phoneNumber, startAttach, attach } = payload!;
|
||||
|
||||
// Open temporary empty chat to make the click response feel faster
|
||||
actions.openChat({ id: TMP_CHAT_ID });
|
||||
@ -524,6 +524,10 @@ addActionHandler('openChatByPhoneNumber', async (global, actions, payload) => {
|
||||
}
|
||||
|
||||
actions.openChat({ id: chat.id });
|
||||
|
||||
if (attach) {
|
||||
openAttachMenuFromLink(actions, chat.id, attach, startAttach);
|
||||
}
|
||||
});
|
||||
|
||||
addActionHandler('openTelegramLink', (global, actions, payload) => {
|
||||
@ -542,8 +546,14 @@ addActionHandler('openTelegramLink', (global, actions, payload) => {
|
||||
hash = part2;
|
||||
}
|
||||
|
||||
const startAttach = params.hasOwnProperty('startattach') && !params.startattach ? true : params.startattach;
|
||||
|
||||
if (part1.match(/^\+([0-9]+)(\?|$)/)) {
|
||||
actions.openChatByPhoneNumber({ phoneNumber: part1.substr(1, part1.length - 1) });
|
||||
actions.openChatByPhoneNumber({
|
||||
phoneNumber: part1.substr(1, part1.length - 1),
|
||||
startAttach,
|
||||
attach: params.attach,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@ -590,6 +600,8 @@ addActionHandler('openTelegramLink', (global, actions, payload) => {
|
||||
messageId: messageId || Number(chatOrChannelPostId),
|
||||
commentId,
|
||||
startParam: params.start,
|
||||
startAttach,
|
||||
attach: params.attach,
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -606,7 +618,7 @@ addActionHandler('acceptInviteConfirmation', async (global, actions, payload) =>
|
||||
|
||||
addActionHandler('openChatByUsername', async (global, actions, payload) => {
|
||||
const {
|
||||
username, messageId, commentId, startParam,
|
||||
username, messageId, commentId, startParam, startAttach, attach,
|
||||
} = payload!;
|
||||
|
||||
const chat = selectCurrentChat(global);
|
||||
@ -616,7 +628,7 @@ addActionHandler('openChatByUsername', async (global, actions, payload) => {
|
||||
actions.focusMessage({ chatId: chat.id, messageId });
|
||||
return;
|
||||
}
|
||||
await openChatByUsername(actions, username, messageId, startParam);
|
||||
await openChatByUsername(actions, username, messageId, startParam, startAttach, attach);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1330,7 +1342,35 @@ async function openChatByUsername(
|
||||
username: string,
|
||||
channelPostId?: number,
|
||||
startParam?: string,
|
||||
startAttach?: string | boolean,
|
||||
attach?: string,
|
||||
) {
|
||||
// Attach in the current chat
|
||||
if (startAttach && !attach) {
|
||||
const chat = await fetchChatByUsername(username);
|
||||
|
||||
if (!chat) return;
|
||||
const global = getGlobal();
|
||||
const user = selectUser(global, chat.id);
|
||||
if (!user) return;
|
||||
const isBot = isUserBot(user);
|
||||
if (!isBot || !user.isAttachMenuBot) {
|
||||
actions.showNotification({ message: langProvider.getTranslation('WebApp.AddToAttachmentUnavailableError') });
|
||||
return;
|
||||
}
|
||||
|
||||
const currentChat = selectCurrentChat(global);
|
||||
|
||||
if (!currentChat) return;
|
||||
|
||||
actions.callAttachMenuBot({
|
||||
botId: user.id,
|
||||
chatId: currentChat.id,
|
||||
...(typeof startAttach === 'string' && { startParam: startAttach }),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Open temporary empty chat to make the click response feel faster
|
||||
actions.openChat({ id: TMP_CHAT_ID });
|
||||
|
||||
@ -1350,6 +1390,29 @@ async function openChatByUsername(
|
||||
if (startParam) {
|
||||
actions.startBot({ botId: chat.id, param: startParam });
|
||||
}
|
||||
|
||||
if (attach) {
|
||||
openAttachMenuFromLink(actions, chat.id, attach, startAttach);
|
||||
}
|
||||
}
|
||||
|
||||
async function openAttachMenuFromLink(
|
||||
actions: GlobalActions,
|
||||
chatId: string, attach: string, startAttach?: string | boolean,
|
||||
) {
|
||||
const botChat = await fetchChatByUsername(attach);
|
||||
if (!botChat) return;
|
||||
const botUser = selectUser(getGlobal(), botChat.id);
|
||||
if (!botUser || !botUser.isAttachMenuBot) {
|
||||
actions.showNotification({ message: langProvider.getTranslation('WebApp.AddToAttachmentUnavailableError') });
|
||||
return;
|
||||
}
|
||||
|
||||
actions.callAttachMenuBot({
|
||||
botId: botUser.id,
|
||||
chatId,
|
||||
...(typeof startAttach === 'string' && { startParam: startAttach }),
|
||||
});
|
||||
}
|
||||
|
||||
async function openCommentsByUsername(
|
||||
|
||||
@ -37,6 +37,13 @@ addActionHandler('apiUpdate', (global, actions, update) => {
|
||||
global = setPaymentStep(global, PaymentStep.ConfirmPayment);
|
||||
setGlobal(global);
|
||||
break;
|
||||
|
||||
case 'updateWebViewResultSent':
|
||||
if (global.webApp?.queryId === update.queryId) {
|
||||
actions.setReplyingToId({ messageId: undefined });
|
||||
actions.closeWebApp();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
|
||||
@ -4,6 +4,7 @@ import { ApiUserStatus } from '../../../api/types';
|
||||
|
||||
import { deleteContact, replaceUserStatuses, updateUser } from '../../reducers';
|
||||
import { throttle } from '../../../util/schedulers';
|
||||
import { selectUser } from '../../selectors';
|
||||
|
||||
const STATUS_UPDATE_THROTTLE = 3000;
|
||||
|
||||
@ -57,6 +58,25 @@ addActionHandler('apiUpdate', (global, actions, update) => {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
case 'updateBotMenuButton': {
|
||||
const { botId, button } = update;
|
||||
|
||||
const targetUser = selectUser(global, botId);
|
||||
if (!targetUser?.fullInfo?.botInfo) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return updateUser(global, botId, {
|
||||
fullInfo: {
|
||||
...targetUser.fullInfo,
|
||||
botInfo: {
|
||||
...targetUser.fullInfo.botInfo,
|
||||
menuButton: button,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
import { addActionHandler } from '../../index';
|
||||
import { addActionHandler, setGlobal } from '../../index';
|
||||
|
||||
import { ApiError } from '../../../api/types';
|
||||
|
||||
import { IS_SINGLE_COLUMN_LAYOUT, IS_TABLET_COLUMN_LAYOUT } from '../../../util/environment';
|
||||
import getReadableErrorText from '../../../util/getReadableErrorText';
|
||||
import { selectCurrentMessageList } from '../../selectors';
|
||||
import {
|
||||
selectChatBot, selectChatMessage, selectCurrentMessageList, selectIsTrustedBot,
|
||||
} from '../../selectors';
|
||||
import generateIdFor from '../../../util/generateIdFor';
|
||||
|
||||
const MAX_STORED_EMOJIS = 18; // Represents two rows of recent emojis
|
||||
@ -264,14 +266,37 @@ addActionHandler('closeHistoryCalendar', (global) => {
|
||||
|
||||
addActionHandler('openGame', (global, actions, payload) => {
|
||||
const { url, chatId, messageId } = payload;
|
||||
return {
|
||||
|
||||
const message = selectChatMessage(global, chatId, messageId);
|
||||
if (!message) return;
|
||||
|
||||
const botId = message.viaBotId || message.senderId;
|
||||
const bot = botId && selectChatBot(global, botId);
|
||||
if (!bot) return;
|
||||
|
||||
if (!selectIsTrustedBot(global, bot)) {
|
||||
setGlobal({
|
||||
...global,
|
||||
botTrustRequest: {
|
||||
bot,
|
||||
type: 'game',
|
||||
onConfirm: {
|
||||
action: 'openGame',
|
||||
payload,
|
||||
},
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
setGlobal({
|
||||
...global,
|
||||
openedGame: {
|
||||
url,
|
||||
chatId,
|
||||
messageId,
|
||||
},
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
addActionHandler('closeGame', (global) => {
|
||||
|
||||
@ -225,6 +225,16 @@ function migrateCache(cached: GlobalState, initialState: GlobalState) {
|
||||
isOpen: false,
|
||||
};
|
||||
}
|
||||
|
||||
if (!cached.attachMenu) {
|
||||
cached.attachMenu = {
|
||||
bots: {},
|
||||
};
|
||||
}
|
||||
|
||||
if (!cached.trustedBotIds) {
|
||||
cached.trustedBotIds = [];
|
||||
}
|
||||
}
|
||||
|
||||
function updateCache() {
|
||||
@ -277,6 +287,7 @@ function updateCache() {
|
||||
groupCalls: reduceGroupCalls(global),
|
||||
availableReactions: reduceAvailableReactions(global),
|
||||
isCallPanelVisible: undefined,
|
||||
trustedBotIds: global.trustedBotIds,
|
||||
};
|
||||
|
||||
const json = JSON.stringify(reducedGlobal);
|
||||
|
||||
@ -1,5 +1,14 @@
|
||||
import {
|
||||
ApiAudio, ApiMediaFormat, ApiMessage, ApiMessageSearchType, ApiPhoto, ApiVideo, ApiDimensions, ApiLocation, ApiGame,
|
||||
ApiAudio,
|
||||
ApiMediaFormat,
|
||||
ApiMessage,
|
||||
ApiMessageSearchType,
|
||||
ApiPhoto,
|
||||
ApiVideo,
|
||||
ApiDimensions,
|
||||
ApiLocation,
|
||||
ApiGame,
|
||||
ApiDocument,
|
||||
} from '../../api/types';
|
||||
|
||||
import { IS_OPUS_SUPPORTED, IS_PROGRESSIVE_SUPPORTED, IS_SAFARI } from '../../util/environment';
|
||||
@ -127,6 +136,10 @@ export function getMessageMediaThumbDataUri(message: ApiMessage) {
|
||||
return getMessageMediaThumbnail(message)?.dataUri;
|
||||
}
|
||||
|
||||
export function getDocumentMediaHash(document: ApiDocument) {
|
||||
return `document${document.id}`;
|
||||
}
|
||||
|
||||
export function buildStaticMapHash(
|
||||
geo: ApiLocation['geo'],
|
||||
width: number,
|
||||
|
||||
@ -227,3 +227,9 @@ export function isGeoLiveExpired(message: ApiMessage, timestamp = Date.now() / 1
|
||||
if (location?.type !== 'geoLive') return false;
|
||||
return (timestamp - (message.date || 0) >= location.period);
|
||||
}
|
||||
|
||||
export function getMessageSingleInlineButton(message: ApiMessage) {
|
||||
return message.inlineButtons?.length === 1
|
||||
&& message.inlineButtons[0].length === 1
|
||||
&& message.inlineButtons[0][0];
|
||||
}
|
||||
|
||||
@ -206,4 +206,10 @@ export const INITIAL_STATE: GlobalState = {
|
||||
pollModal: {
|
||||
isOpen: false,
|
||||
},
|
||||
|
||||
trustedBotIds: [],
|
||||
|
||||
attachMenu: {
|
||||
bots: {},
|
||||
},
|
||||
};
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { ApiChat, MAIN_THREAD_ID } from '../../api/types';
|
||||
import { ApiChat, ApiUser, MAIN_THREAD_ID } from '../../api/types';
|
||||
import { GlobalState } from '../types';
|
||||
|
||||
import {
|
||||
@ -68,6 +68,10 @@ export function selectChatBot(global: GlobalState, chatId: string) {
|
||||
return user;
|
||||
}
|
||||
|
||||
export function selectIsTrustedBot(global: GlobalState, bot: ApiUser) {
|
||||
return bot.isVerified || global.trustedBotIds.includes(bot.id);
|
||||
}
|
||||
|
||||
export function selectIsChatBotNotStarted(global: GlobalState, chatId: string) {
|
||||
const chat = selectChat(global, chatId);
|
||||
const bot = selectChatBot(global, chatId);
|
||||
|
||||
@ -335,6 +335,23 @@ export function selectSender(global: GlobalState, message: ApiMessage): ApiUser
|
||||
return isUserId(senderId) ? selectUser(global, senderId) : selectChat(global, senderId);
|
||||
}
|
||||
|
||||
export function selectReplySender(global: GlobalState, message: ApiMessage, isForwarded = false) {
|
||||
if (isForwarded) {
|
||||
const { senderUserId, hiddenUserName } = message.forwardInfo || {};
|
||||
if (senderUserId) {
|
||||
return isUserId(senderUserId) ? selectUser(global, senderUserId) : selectChat(global, senderUserId);
|
||||
}
|
||||
if (hiddenUserName) return undefined;
|
||||
}
|
||||
|
||||
const { senderId } = message;
|
||||
if (!senderId) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return isUserId(senderId) ? selectUser(global, senderId) : selectChat(global, senderId);
|
||||
}
|
||||
|
||||
export function selectForwardedSender(global: GlobalState, message: ApiMessage): ApiUser | ApiChat | undefined {
|
||||
const { forwardInfo } = message;
|
||||
if (!forwardInfo) {
|
||||
|
||||
@ -33,6 +33,8 @@ import {
|
||||
ApiReportReason,
|
||||
ApiPhoto,
|
||||
ApiKeyboardButton,
|
||||
ApiThemeParameters,
|
||||
ApiAttachMenuBot,
|
||||
ApiPhoneCall,
|
||||
} from '../api/types';
|
||||
import {
|
||||
@ -543,6 +545,33 @@ export type GlobalState = {
|
||||
isOpen: boolean;
|
||||
isQuiz?: boolean;
|
||||
};
|
||||
|
||||
webApp?: {
|
||||
url: string;
|
||||
bot: ApiUser;
|
||||
buttonText: string;
|
||||
queryId?: string;
|
||||
};
|
||||
|
||||
trustedBotIds: string[];
|
||||
botTrustRequest?: {
|
||||
bot: ApiUser;
|
||||
type: 'game' | 'webApp';
|
||||
onConfirm?: {
|
||||
action: keyof GlobalActions;
|
||||
payload: any; // TODO add TS support
|
||||
};
|
||||
};
|
||||
botAttachRequest?: {
|
||||
bot: ApiUser;
|
||||
chatId: string;
|
||||
startParam?: string;
|
||||
};
|
||||
|
||||
attachMenu: {
|
||||
hash?: string;
|
||||
bots: Record<string, ApiAttachMenuBot>;
|
||||
};
|
||||
};
|
||||
|
||||
export type CallSound = (
|
||||
@ -682,7 +711,6 @@ export interface ActionPayloads {
|
||||
|
||||
resetSwitchBotInline: {};
|
||||
|
||||
// Misc
|
||||
openGame: {
|
||||
url: string;
|
||||
chatId: string;
|
||||
@ -690,6 +718,64 @@ export interface ActionPayloads {
|
||||
};
|
||||
closeGame: {};
|
||||
|
||||
requestWebView: {
|
||||
url?: string;
|
||||
bot: ApiUser;
|
||||
peer: ApiChat | ApiUser;
|
||||
theme?: ApiThemeParameters;
|
||||
isSilent?: boolean;
|
||||
buttonText: string;
|
||||
isFromBotMenu?: boolean;
|
||||
startParam?: string;
|
||||
};
|
||||
prolongWebView: {
|
||||
bot: ApiUser;
|
||||
peer: ApiChat | ApiUser;
|
||||
queryId: string;
|
||||
isSilent?: boolean;
|
||||
replyToMessageId?: number;
|
||||
};
|
||||
requestSimpleWebView: {
|
||||
url: string;
|
||||
bot: ApiUser;
|
||||
buttonText: string;
|
||||
theme?: ApiThemeParameters;
|
||||
};
|
||||
closeWebApp: {};
|
||||
|
||||
cancelBotTrustRequest: {};
|
||||
markBotTrusted: {
|
||||
botId: string;
|
||||
};
|
||||
|
||||
closeBotAttachRequestModal: never;
|
||||
confirmBotAttachRequest: never;
|
||||
|
||||
sendWebViewData: {
|
||||
bot: ApiUser;
|
||||
data: string;
|
||||
buttonText: string;
|
||||
};
|
||||
|
||||
loadAttachMenuBots: {
|
||||
hash?: string;
|
||||
};
|
||||
|
||||
toggleBotInAttachMenu: {
|
||||
botId: string;
|
||||
isEnabled: boolean;
|
||||
};
|
||||
|
||||
callAttachMenuBot: {
|
||||
chatId: string;
|
||||
botId: string;
|
||||
isFromBotMenu?: boolean;
|
||||
url?: string;
|
||||
startParam?: string;
|
||||
};
|
||||
|
||||
// Misc
|
||||
|
||||
openPollModal: {
|
||||
isQuiz?: boolean;
|
||||
};
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
const api = require('./api');
|
||||
|
||||
const LAYER = 139;
|
||||
const LAYER = 140;
|
||||
const tlobjects = {};
|
||||
|
||||
for (const tl of Object.values(api)) {
|
||||
|
||||
325
src/lib/gramjs/tl/api.d.ts
vendored
325
src/lib/gramjs/tl/api.d.ts
vendored
@ -70,7 +70,7 @@ namespace Api {
|
||||
export type TypeChatPhoto = ChatPhotoEmpty | ChatPhoto;
|
||||
export type TypeMessage = MessageEmpty | Message | MessageService;
|
||||
export type TypeMessageMedia = MessageMediaEmpty | MessageMediaPhoto | MessageMediaGeo | MessageMediaContact | MessageMediaUnsupported | MessageMediaDocument | MessageMediaWebPage | MessageMediaVenue | MessageMediaGame | MessageMediaInvoice | MessageMediaGeoLive | MessageMediaPoll | MessageMediaDice;
|
||||
export type TypeMessageAction = MessageActionEmpty | MessageActionChatCreate | MessageActionChatEditTitle | MessageActionChatEditPhoto | MessageActionChatDeletePhoto | MessageActionChatAddUser | MessageActionChatDeleteUser | MessageActionChatJoinedByLink | MessageActionChannelCreate | MessageActionChatMigrateTo | MessageActionChannelMigrateFrom | MessageActionPinMessage | MessageActionHistoryClear | MessageActionGameScore | MessageActionPaymentSentMe | MessageActionPaymentSent | MessageActionPhoneCall | MessageActionScreenshotTaken | MessageActionCustomAction | MessageActionBotAllowed | MessageActionSecureValuesSentMe | MessageActionSecureValuesSent | MessageActionContactSignUp | MessageActionGeoProximityReached | MessageActionGroupCall | MessageActionInviteToGroupCall | MessageActionSetMessagesTTL | MessageActionGroupCallScheduled | MessageActionSetChatTheme | MessageActionChatJoinedByRequest;
|
||||
export type TypeMessageAction = MessageActionEmpty | MessageActionChatCreate | MessageActionChatEditTitle | MessageActionChatEditPhoto | MessageActionChatDeletePhoto | MessageActionChatAddUser | MessageActionChatDeleteUser | MessageActionChatJoinedByLink | MessageActionChannelCreate | MessageActionChatMigrateTo | MessageActionChannelMigrateFrom | MessageActionPinMessage | MessageActionHistoryClear | MessageActionGameScore | MessageActionPaymentSentMe | MessageActionPaymentSent | MessageActionPhoneCall | MessageActionScreenshotTaken | MessageActionCustomAction | MessageActionBotAllowed | MessageActionSecureValuesSentMe | MessageActionSecureValuesSent | MessageActionContactSignUp | MessageActionGeoProximityReached | MessageActionGroupCall | MessageActionInviteToGroupCall | MessageActionSetMessagesTTL | MessageActionGroupCallScheduled | MessageActionSetChatTheme | MessageActionChatJoinedByRequest | MessageActionWebViewDataSentMe | MessageActionWebViewDataSent;
|
||||
export type TypeDialog = Dialog | DialogFolder;
|
||||
export type TypePhoto = PhotoEmpty | Photo;
|
||||
export type TypePhotoSize = PhotoSizeEmpty | PhotoSize | PhotoCachedSize | PhotoStrippedSize | PhotoSizeProgressive | PhotoPathSize;
|
||||
@ -86,7 +86,7 @@ namespace Api {
|
||||
export type TypeImportedContact = ImportedContact;
|
||||
export type TypeContactStatus = ContactStatus;
|
||||
export type TypeMessagesFilter = InputMessagesFilterEmpty | InputMessagesFilterPhotos | InputMessagesFilterVideo | InputMessagesFilterPhotoVideo | InputMessagesFilterDocument | InputMessagesFilterUrl | InputMessagesFilterGif | InputMessagesFilterVoice | InputMessagesFilterMusic | InputMessagesFilterChatPhotos | InputMessagesFilterPhoneCalls | InputMessagesFilterRoundVoice | InputMessagesFilterRoundVideo | InputMessagesFilterMyMentions | InputMessagesFilterGeo | InputMessagesFilterContacts | InputMessagesFilterPinned;
|
||||
export type TypeUpdate = UpdateNewMessage | UpdateMessageID | UpdateDeleteMessages | UpdateUserTyping | UpdateChatUserTyping | UpdateChatParticipants | UpdateUserStatus | UpdateUserName | UpdateUserPhoto | UpdateNewEncryptedMessage | UpdateEncryptedChatTyping | UpdateEncryption | UpdateEncryptedMessagesRead | UpdateChatParticipantAdd | UpdateChatParticipantDelete | UpdateDcOptions | UpdateNotifySettings | UpdateServiceNotification | UpdatePrivacy | UpdateUserPhone | UpdateReadHistoryInbox | UpdateReadHistoryOutbox | UpdateWebPage | UpdateReadMessagesContents | UpdateChannelTooLong | UpdateChannel | UpdateNewChannelMessage | UpdateReadChannelInbox | UpdateDeleteChannelMessages | UpdateChannelMessageViews | UpdateChatParticipantAdmin | UpdateNewStickerSet | UpdateStickerSetsOrder | UpdateStickerSets | UpdateSavedGifs | UpdateBotInlineQuery | UpdateBotInlineSend | UpdateEditChannelMessage | UpdateBotCallbackQuery | UpdateEditMessage | UpdateInlineBotCallbackQuery | UpdateReadChannelOutbox | UpdateDraftMessage | UpdateReadFeaturedStickers | UpdateRecentStickers | UpdateConfig | UpdatePtsChanged | UpdateChannelWebPage | UpdateDialogPinned | UpdatePinnedDialogs | UpdateBotWebhookJSON | UpdateBotWebhookJSONQuery | UpdateBotShippingQuery | UpdateBotPrecheckoutQuery | UpdatePhoneCall | UpdateLangPackTooLong | UpdateLangPack | UpdateFavedStickers | UpdateChannelReadMessagesContents | UpdateContactsReset | UpdateChannelAvailableMessages | UpdateDialogUnreadMark | UpdateMessagePoll | UpdateChatDefaultBannedRights | UpdateFolderPeers | UpdatePeerSettings | UpdatePeerLocated | UpdateNewScheduledMessage | UpdateDeleteScheduledMessages | UpdateTheme | UpdateGeoLiveViewed | UpdateLoginToken | UpdateMessagePollVote | UpdateDialogFilter | UpdateDialogFilterOrder | UpdateDialogFilters | UpdatePhoneCallSignalingData | UpdateChannelMessageForwards | UpdateReadChannelDiscussionInbox | UpdateReadChannelDiscussionOutbox | UpdatePeerBlocked | UpdateChannelUserTyping | UpdatePinnedMessages | UpdatePinnedChannelMessages | UpdateChat | UpdateGroupCallParticipants | UpdateGroupCall | UpdatePeerHistoryTTL | UpdateChatParticipant | UpdateChannelParticipant | UpdateBotStopped | UpdateGroupCallConnection | UpdateBotCommands | UpdatePendingJoinRequests | UpdateBotChatInviteRequester | UpdateMessageReactions;
|
||||
export type TypeUpdate = UpdateNewMessage | UpdateMessageID | UpdateDeleteMessages | UpdateUserTyping | UpdateChatUserTyping | UpdateChatParticipants | UpdateUserStatus | UpdateUserName | UpdateUserPhoto | UpdateNewEncryptedMessage | UpdateEncryptedChatTyping | UpdateEncryption | UpdateEncryptedMessagesRead | UpdateChatParticipantAdd | UpdateChatParticipantDelete | UpdateDcOptions | UpdateNotifySettings | UpdateServiceNotification | UpdatePrivacy | UpdateUserPhone | UpdateReadHistoryInbox | UpdateReadHistoryOutbox | UpdateWebPage | UpdateReadMessagesContents | UpdateChannelTooLong | UpdateChannel | UpdateNewChannelMessage | UpdateReadChannelInbox | UpdateDeleteChannelMessages | UpdateChannelMessageViews | UpdateChatParticipantAdmin | UpdateNewStickerSet | UpdateStickerSetsOrder | UpdateStickerSets | UpdateSavedGifs | UpdateBotInlineQuery | UpdateBotInlineSend | UpdateEditChannelMessage | UpdateBotCallbackQuery | UpdateEditMessage | UpdateInlineBotCallbackQuery | UpdateReadChannelOutbox | UpdateDraftMessage | UpdateReadFeaturedStickers | UpdateRecentStickers | UpdateConfig | UpdatePtsChanged | UpdateChannelWebPage | UpdateDialogPinned | UpdatePinnedDialogs | UpdateBotWebhookJSON | UpdateBotWebhookJSONQuery | UpdateBotShippingQuery | UpdateBotPrecheckoutQuery | UpdatePhoneCall | UpdateLangPackTooLong | UpdateLangPack | UpdateFavedStickers | UpdateChannelReadMessagesContents | UpdateContactsReset | UpdateChannelAvailableMessages | UpdateDialogUnreadMark | UpdateMessagePoll | UpdateChatDefaultBannedRights | UpdateFolderPeers | UpdatePeerSettings | UpdatePeerLocated | UpdateNewScheduledMessage | UpdateDeleteScheduledMessages | UpdateTheme | UpdateGeoLiveViewed | UpdateLoginToken | UpdateMessagePollVote | UpdateDialogFilter | UpdateDialogFilterOrder | UpdateDialogFilters | UpdatePhoneCallSignalingData | UpdateChannelMessageForwards | UpdateReadChannelDiscussionInbox | UpdateReadChannelDiscussionOutbox | UpdatePeerBlocked | UpdateChannelUserTyping | UpdatePinnedMessages | UpdatePinnedChannelMessages | UpdateChat | UpdateGroupCallParticipants | UpdateGroupCall | UpdatePeerHistoryTTL | UpdateChatParticipant | UpdateChannelParticipant | UpdateBotStopped | UpdateGroupCallConnection | UpdateBotCommands | UpdatePendingJoinRequests | UpdateBotChatInviteRequester | UpdateMessageReactions | UpdateAttachMenuBots | UpdateWebViewResultSent | UpdateBotMenuButton | UpdateSavedRingtones;
|
||||
export type TypeUpdates = UpdatesTooLong | UpdateShortMessage | UpdateShortChatMessage | UpdateShort | UpdatesCombined | Updates | UpdateShortSentMessage;
|
||||
export type TypeDcOption = DcOption;
|
||||
export type TypeConfig = Config;
|
||||
@ -116,7 +116,7 @@ namespace Api {
|
||||
export type TypeStickerSet = StickerSet;
|
||||
export type TypeBotCommand = BotCommand;
|
||||
export type TypeBotInfo = BotInfo;
|
||||
export type TypeKeyboardButton = KeyboardButton | KeyboardButtonUrl | KeyboardButtonCallback | KeyboardButtonRequestPhone | KeyboardButtonRequestGeoLocation | KeyboardButtonSwitchInline | KeyboardButtonGame | KeyboardButtonBuy | KeyboardButtonUrlAuth | InputKeyboardButtonUrlAuth | KeyboardButtonRequestPoll | InputKeyboardButtonUserProfile | KeyboardButtonUserProfile;
|
||||
export type TypeKeyboardButton = KeyboardButton | KeyboardButtonUrl | KeyboardButtonCallback | KeyboardButtonRequestPhone | KeyboardButtonRequestGeoLocation | KeyboardButtonSwitchInline | KeyboardButtonGame | KeyboardButtonBuy | KeyboardButtonUrlAuth | InputKeyboardButtonUrlAuth | KeyboardButtonRequestPoll | InputKeyboardButtonUserProfile | KeyboardButtonUserProfile | KeyboardButtonWebView | KeyboardButtonSimpleWebView;
|
||||
export type TypeKeyboardButtonRow = KeyboardButtonRow;
|
||||
export type TypeReplyMarkup = ReplyKeyboardHide | ReplyKeyboardForceReply | ReplyKeyboardMarkup | ReplyInlineMarkup;
|
||||
export type TypeMessageEntity = MessageEntityUnknown | MessageEntityMention | MessageEntityHashtag | MessageEntityBotCommand | MessageEntityUrl | MessageEntityEmail | MessageEntityBold | MessageEntityItalic | MessageEntityCode | MessageEntityPre | MessageEntityTextUrl | MessageEntityMentionName | InputMessageEntityMentionName | MessageEntityPhone | MessageEntityCashtag | MessageEntityUnderline | MessageEntityStrike | MessageEntityBlockquote | MessageEntityBankCard | MessageEntitySpoiler;
|
||||
@ -270,6 +270,16 @@ namespace Api {
|
||||
export type TypeAvailableReaction = AvailableReaction;
|
||||
export type TypeMessagePeerReaction = MessagePeerReaction;
|
||||
export type TypeGroupCallStreamChannel = GroupCallStreamChannel;
|
||||
export type TypeAttachMenuBotIconColor = AttachMenuBotIconColor;
|
||||
export type TypeAttachMenuBotIcon = AttachMenuBotIcon;
|
||||
export type TypeAttachMenuBot = AttachMenuBot;
|
||||
export type TypeAttachMenuBots = AttachMenuBotsNotModified | AttachMenuBots;
|
||||
export type TypeAttachMenuBotsBot = AttachMenuBotsBot;
|
||||
export type TypeWebViewResult = WebViewResultUrl;
|
||||
export type TypeSimpleWebViewResult = SimpleWebViewResultUrl;
|
||||
export type TypeWebViewMessageSent = WebViewMessageSent;
|
||||
export type TypeBotMenuButton = BotMenuButtonDefault | BotMenuButtonCommands | BotMenuButton;
|
||||
export type TypeNotificationSound = NotificationSoundDefault | NotificationSoundNone | NotificationSoundLocal | NotificationSoundRingtone;
|
||||
export type TypeResPQ = ResPQ;
|
||||
export type TypeP_Q_inner_data = PQInnerData | PQInnerDataDc | PQInnerDataTemp | PQInnerDataTempDc;
|
||||
export type TypeServer_DH_Params = ServerDHParamsFail | ServerDHParamsOk;
|
||||
@ -419,6 +429,8 @@ namespace Api {
|
||||
export type TypeThemes = account.ThemesNotModified | account.Themes;
|
||||
export type TypeContentSettings = account.ContentSettings;
|
||||
export type TypeResetPasswordResult = account.ResetPasswordFailedWait | account.ResetPasswordRequestedWait | account.ResetPasswordOk;
|
||||
export type TypeSavedRingtones = account.SavedRingtonesNotModified | account.SavedRingtones;
|
||||
export type TypeSavedRingtone = account.SavedRingtone | account.SavedRingtoneConverted;
|
||||
}
|
||||
|
||||
export namespace channels {
|
||||
@ -882,6 +894,7 @@ namespace Api {
|
||||
scam?: true;
|
||||
applyMinPhoto?: true;
|
||||
fake?: true;
|
||||
botAttachMenu?: true;
|
||||
id: long;
|
||||
accessHash?: long;
|
||||
firstName?: string;
|
||||
@ -911,6 +924,7 @@ namespace Api {
|
||||
scam?: true;
|
||||
applyMinPhoto?: true;
|
||||
fake?: true;
|
||||
botAttachMenu?: true;
|
||||
id: long;
|
||||
accessHash?: long;
|
||||
firstName?: string;
|
||||
@ -960,7 +974,6 @@ namespace Api {
|
||||
export class Chat extends VirtualClass<{
|
||||
// flags: undefined;
|
||||
creator?: true;
|
||||
kicked?: true;
|
||||
left?: true;
|
||||
deactivated?: true;
|
||||
callActive?: true;
|
||||
@ -978,7 +991,6 @@ namespace Api {
|
||||
}> {
|
||||
// flags: undefined;
|
||||
creator?: true;
|
||||
kicked?: true;
|
||||
left?: true;
|
||||
deactivated?: true;
|
||||
callActive?: true;
|
||||
@ -1130,6 +1142,8 @@ namespace Api {
|
||||
hasScheduled?: true;
|
||||
canViewStats?: true;
|
||||
blocked?: true;
|
||||
// flags2: undefined;
|
||||
canDeleteChannel?: true;
|
||||
id: long;
|
||||
about: string;
|
||||
participantsCount?: int;
|
||||
@ -1175,6 +1189,8 @@ namespace Api {
|
||||
hasScheduled?: true;
|
||||
canViewStats?: true;
|
||||
blocked?: true;
|
||||
// flags2: undefined;
|
||||
canDeleteChannel?: true;
|
||||
id: long;
|
||||
about: string;
|
||||
participantsCount?: int;
|
||||
@ -1648,6 +1664,18 @@ namespace Api {
|
||||
emoticon: string;
|
||||
};
|
||||
export class MessageActionChatJoinedByRequest extends VirtualClass<void> {};
|
||||
export class MessageActionWebViewDataSentMe extends VirtualClass<{
|
||||
text: string;
|
||||
data: string;
|
||||
}> {
|
||||
text: string;
|
||||
data: string;
|
||||
};
|
||||
export class MessageActionWebViewDataSent extends VirtualClass<{
|
||||
text: string;
|
||||
}> {
|
||||
text: string;
|
||||
};
|
||||
export class Dialog extends VirtualClass<{
|
||||
// flags: undefined;
|
||||
pinned?: true;
|
||||
@ -1805,26 +1833,30 @@ namespace Api {
|
||||
showPreviews?: Bool;
|
||||
silent?: Bool;
|
||||
muteUntil?: int;
|
||||
sound?: string;
|
||||
sound?: Api.TypeNotificationSound;
|
||||
} | void> {
|
||||
// flags: undefined;
|
||||
showPreviews?: Bool;
|
||||
silent?: Bool;
|
||||
muteUntil?: int;
|
||||
sound?: string;
|
||||
sound?: Api.TypeNotificationSound;
|
||||
};
|
||||
export class PeerNotifySettings extends VirtualClass<{
|
||||
// flags: undefined;
|
||||
showPreviews?: Bool;
|
||||
silent?: Bool;
|
||||
muteUntil?: int;
|
||||
sound?: string;
|
||||
iosSound?: Api.TypeNotificationSound;
|
||||
androidSound?: Api.TypeNotificationSound;
|
||||
otherSound?: Api.TypeNotificationSound;
|
||||
} | void> {
|
||||
// flags: undefined;
|
||||
showPreviews?: Bool;
|
||||
silent?: Bool;
|
||||
muteUntil?: int;
|
||||
sound?: string;
|
||||
iosSound?: Api.TypeNotificationSound;
|
||||
androidSound?: Api.TypeNotificationSound;
|
||||
otherSound?: Api.TypeNotificationSound;
|
||||
};
|
||||
export class PeerSettings extends VirtualClass<{
|
||||
// flags: undefined;
|
||||
@ -1921,6 +1953,8 @@ namespace Api {
|
||||
ttlPeriod?: int;
|
||||
themeEmoticon?: string;
|
||||
privateForwardName?: string;
|
||||
botGroupAdminRights?: Api.TypeChatAdminRights;
|
||||
botBroadcastAdminRights?: Api.TypeChatAdminRights;
|
||||
}> {
|
||||
// flags: undefined;
|
||||
blocked?: true;
|
||||
@ -1941,6 +1975,8 @@ namespace Api {
|
||||
ttlPeriod?: int;
|
||||
themeEmoticon?: string;
|
||||
privateForwardName?: string;
|
||||
botGroupAdminRights?: Api.TypeChatAdminRights;
|
||||
botBroadcastAdminRights?: Api.TypeChatAdminRights;
|
||||
};
|
||||
export class Contact extends VirtualClass<{
|
||||
userId: long;
|
||||
@ -2820,6 +2856,20 @@ namespace Api {
|
||||
msgId: int;
|
||||
reactions: Api.TypeMessageReactions;
|
||||
};
|
||||
export class UpdateAttachMenuBots extends VirtualClass<void> {};
|
||||
export class UpdateWebViewResultSent extends VirtualClass<{
|
||||
queryId: long;
|
||||
}> {
|
||||
queryId: long;
|
||||
};
|
||||
export class UpdateBotMenuButton extends VirtualClass<{
|
||||
botId: long;
|
||||
button: Api.TypeBotMenuButton;
|
||||
}> {
|
||||
botId: long;
|
||||
button: Api.TypeBotMenuButton;
|
||||
};
|
||||
export class UpdateSavedRingtones extends VirtualClass<void> {};
|
||||
export class UpdatesTooLong extends VirtualClass<void> {};
|
||||
export class UpdateShortMessage extends VirtualClass<{
|
||||
// flags: undefined;
|
||||
@ -3697,10 +3747,12 @@ namespace Api {
|
||||
userId: long;
|
||||
description: string;
|
||||
commands: Api.TypeBotCommand[];
|
||||
menuButton: Api.TypeBotMenuButton;
|
||||
}> {
|
||||
userId: long;
|
||||
description: string;
|
||||
commands: Api.TypeBotCommand[];
|
||||
menuButton: Api.TypeBotMenuButton;
|
||||
};
|
||||
export class KeyboardButton extends VirtualClass<{
|
||||
text: string;
|
||||
@ -3807,6 +3859,20 @@ namespace Api {
|
||||
text: string;
|
||||
userId: long;
|
||||
};
|
||||
export class KeyboardButtonWebView extends VirtualClass<{
|
||||
text: string;
|
||||
url: string;
|
||||
}> {
|
||||
text: string;
|
||||
url: string;
|
||||
};
|
||||
export class KeyboardButtonSimpleWebView extends VirtualClass<{
|
||||
text: string;
|
||||
url: string;
|
||||
}> {
|
||||
text: string;
|
||||
url: string;
|
||||
};
|
||||
export class KeyboardButtonRow extends VirtualClass<{
|
||||
buttons: Api.TypeKeyboardButton[];
|
||||
}> {
|
||||
@ -7071,6 +7137,96 @@ namespace Api {
|
||||
scale: int;
|
||||
lastTimestampMs: long;
|
||||
};
|
||||
export class AttachMenuBotIconColor extends VirtualClass<{
|
||||
name: string;
|
||||
color: int;
|
||||
}> {
|
||||
name: string;
|
||||
color: int;
|
||||
};
|
||||
export class AttachMenuBotIcon extends VirtualClass<{
|
||||
// flags: undefined;
|
||||
name: string;
|
||||
icon: Api.TypeDocument;
|
||||
colors?: Api.TypeAttachMenuBotIconColor[];
|
||||
}> {
|
||||
// flags: undefined;
|
||||
name: string;
|
||||
icon: Api.TypeDocument;
|
||||
colors?: Api.TypeAttachMenuBotIconColor[];
|
||||
};
|
||||
export class AttachMenuBot extends VirtualClass<{
|
||||
// flags: undefined;
|
||||
inactive?: true;
|
||||
botId: long;
|
||||
shortName: string;
|
||||
icons: Api.TypeAttachMenuBotIcon[];
|
||||
}> {
|
||||
// flags: undefined;
|
||||
inactive?: true;
|
||||
botId: long;
|
||||
shortName: string;
|
||||
icons: Api.TypeAttachMenuBotIcon[];
|
||||
};
|
||||
export class AttachMenuBotsNotModified extends VirtualClass<void> {};
|
||||
export class AttachMenuBots extends VirtualClass<{
|
||||
hash: long;
|
||||
bots: Api.TypeAttachMenuBot[];
|
||||
users: Api.TypeUser[];
|
||||
}> {
|
||||
hash: long;
|
||||
bots: Api.TypeAttachMenuBot[];
|
||||
users: Api.TypeUser[];
|
||||
};
|
||||
export class AttachMenuBotsBot extends VirtualClass<{
|
||||
bot: Api.TypeAttachMenuBot;
|
||||
users: Api.TypeUser[];
|
||||
}> {
|
||||
bot: Api.TypeAttachMenuBot;
|
||||
users: Api.TypeUser[];
|
||||
};
|
||||
export class WebViewResultUrl extends VirtualClass<{
|
||||
queryId: long;
|
||||
url: string;
|
||||
}> {
|
||||
queryId: long;
|
||||
url: string;
|
||||
};
|
||||
export class SimpleWebViewResultUrl extends VirtualClass<{
|
||||
url: string;
|
||||
}> {
|
||||
url: string;
|
||||
};
|
||||
export class WebViewMessageSent extends VirtualClass<{
|
||||
// flags: undefined;
|
||||
msgId?: Api.TypeInputBotInlineMessageID;
|
||||
} | void> {
|
||||
// flags: undefined;
|
||||
msgId?: Api.TypeInputBotInlineMessageID;
|
||||
};
|
||||
export class BotMenuButtonDefault extends VirtualClass<void> {};
|
||||
export class BotMenuButtonCommands extends VirtualClass<void> {};
|
||||
export class BotMenuButton extends VirtualClass<{
|
||||
text: string;
|
||||
url: string;
|
||||
}> {
|
||||
text: string;
|
||||
url: string;
|
||||
};
|
||||
export class NotificationSoundDefault extends VirtualClass<void> {};
|
||||
export class NotificationSoundNone extends VirtualClass<void> {};
|
||||
export class NotificationSoundLocal extends VirtualClass<{
|
||||
title: string;
|
||||
data: string;
|
||||
}> {
|
||||
title: string;
|
||||
data: string;
|
||||
};
|
||||
export class NotificationSoundRingtone extends VirtualClass<{
|
||||
id: long;
|
||||
}> {
|
||||
id: long;
|
||||
};
|
||||
export class ResPQ extends VirtualClass<{
|
||||
nonce: int128;
|
||||
serverNonce: int128;
|
||||
@ -8643,6 +8799,20 @@ namespace Api {
|
||||
untilDate: int;
|
||||
};
|
||||
export class ResetPasswordOk extends VirtualClass<void> {};
|
||||
export class SavedRingtonesNotModified extends VirtualClass<void> {};
|
||||
export class SavedRingtones extends VirtualClass<{
|
||||
hash: long;
|
||||
ringtones: Api.TypeDocument[];
|
||||
}> {
|
||||
hash: long;
|
||||
ringtones: Api.TypeDocument[];
|
||||
};
|
||||
export class SavedRingtone extends VirtualClass<void> {};
|
||||
export class SavedRingtoneConverted extends VirtualClass<{
|
||||
document: Api.TypeDocument;
|
||||
}> {
|
||||
document: Api.TypeDocument;
|
||||
};
|
||||
}
|
||||
|
||||
export namespace channels {
|
||||
@ -9673,6 +9843,27 @@ namespace Api {
|
||||
encryptedRequestsDisabled?: Bool;
|
||||
callRequestsDisabled?: Bool;
|
||||
};
|
||||
export class GetSavedRingtones extends Request<Partial<{
|
||||
hash: long;
|
||||
}>, account.TypeSavedRingtones> {
|
||||
hash: long;
|
||||
};
|
||||
export class SaveRingtone extends Request<Partial<{
|
||||
id: Api.TypeInputDocument;
|
||||
unsave: Bool;
|
||||
}>, account.TypeSavedRingtone> {
|
||||
id: Api.TypeInputDocument;
|
||||
unsave: Bool;
|
||||
};
|
||||
export class UploadRingtone extends Request<Partial<{
|
||||
file: Api.TypeInputFile;
|
||||
fileName: string;
|
||||
mimeType: string;
|
||||
}>, Api.TypeDocument> {
|
||||
file: Api.TypeInputFile;
|
||||
fileName: string;
|
||||
mimeType: string;
|
||||
};
|
||||
}
|
||||
|
||||
export namespace users {
|
||||
@ -11365,6 +11556,88 @@ namespace Api {
|
||||
filter: Api.TypeMessagesFilter;
|
||||
limit: int;
|
||||
};
|
||||
export class GetAttachMenuBots extends Request<Partial<{
|
||||
hash: long;
|
||||
}>, Api.TypeAttachMenuBots> {
|
||||
hash: long;
|
||||
};
|
||||
export class GetAttachMenuBot extends Request<Partial<{
|
||||
bot: Api.TypeInputUser;
|
||||
}>, Api.TypeAttachMenuBotsBot> {
|
||||
bot: Api.TypeInputUser;
|
||||
};
|
||||
export class ToggleBotInAttachMenu extends Request<Partial<{
|
||||
bot: Api.TypeInputUser;
|
||||
enabled: Bool;
|
||||
}>, Bool> {
|
||||
bot: Api.TypeInputUser;
|
||||
enabled: Bool;
|
||||
};
|
||||
export class RequestWebView extends Request<Partial<{
|
||||
// flags: undefined;
|
||||
fromBotMenu?: true;
|
||||
silent?: true;
|
||||
peer: Api.TypeInputPeer;
|
||||
bot: Api.TypeInputUser;
|
||||
url?: string;
|
||||
startParam?: string;
|
||||
themeParams?: Api.TypeDataJSON;
|
||||
replyToMsgId?: int;
|
||||
}>, Api.TypeWebViewResult> {
|
||||
// flags: undefined;
|
||||
fromBotMenu?: true;
|
||||
silent?: true;
|
||||
peer: Api.TypeInputPeer;
|
||||
bot: Api.TypeInputUser;
|
||||
url?: string;
|
||||
startParam?: string;
|
||||
themeParams?: Api.TypeDataJSON;
|
||||
replyToMsgId?: int;
|
||||
};
|
||||
export class ProlongWebView extends Request<Partial<{
|
||||
// flags: undefined;
|
||||
silent?: true;
|
||||
peer: Api.TypeInputPeer;
|
||||
bot: Api.TypeInputUser;
|
||||
queryId: long;
|
||||
replyToMsgId?: int;
|
||||
}>, Bool> {
|
||||
// flags: undefined;
|
||||
silent?: true;
|
||||
peer: Api.TypeInputPeer;
|
||||
bot: Api.TypeInputUser;
|
||||
queryId: long;
|
||||
replyToMsgId?: int;
|
||||
};
|
||||
export class RequestSimpleWebView extends Request<Partial<{
|
||||
// flags: undefined;
|
||||
bot: Api.TypeInputUser;
|
||||
url: string;
|
||||
themeParams?: Api.TypeDataJSON;
|
||||
}>, Api.TypeSimpleWebViewResult> {
|
||||
// flags: undefined;
|
||||
bot: Api.TypeInputUser;
|
||||
url: string;
|
||||
themeParams?: Api.TypeDataJSON;
|
||||
};
|
||||
export class SendWebViewResultMessage extends Request<Partial<{
|
||||
botQueryId: string;
|
||||
result: Api.TypeInputBotInlineResult;
|
||||
}>, Api.TypeWebViewMessageSent> {
|
||||
botQueryId: string;
|
||||
result: Api.TypeInputBotInlineResult;
|
||||
};
|
||||
export class SendWebViewData extends Request<Partial<{
|
||||
bot: Api.TypeInputUser;
|
||||
randomId: long;
|
||||
buttonText: string;
|
||||
data: string;
|
||||
}>, Api.TypeUpdates> {
|
||||
bot: Api.TypeInputUser;
|
||||
randomId: long;
|
||||
buttonText: string;
|
||||
data: string;
|
||||
};
|
||||
}
|
||||
|
||||
export namespace updates {
|
||||
@ -11811,9 +12084,13 @@ namespace Api {
|
||||
id: int[];
|
||||
};
|
||||
export class DeleteHistory extends Request<Partial<{
|
||||
// flags: undefined;
|
||||
forEveryone?: true;
|
||||
channel: Api.TypeInputChannel;
|
||||
maxId: int;
|
||||
}>, Bool> {
|
||||
}>, Api.TypeUpdates> {
|
||||
// flags: undefined;
|
||||
forEveryone?: true;
|
||||
channel: Api.TypeInputChannel;
|
||||
maxId: int;
|
||||
};
|
||||
@ -11932,6 +12209,28 @@ namespace Api {
|
||||
scope: Api.TypeBotCommandScope;
|
||||
langCode: string;
|
||||
};
|
||||
export class SetBotMenuButton extends Request<Partial<{
|
||||
userId: Api.TypeInputUser;
|
||||
button: Api.TypeBotMenuButton;
|
||||
}>, Bool> {
|
||||
userId: Api.TypeInputUser;
|
||||
button: Api.TypeBotMenuButton;
|
||||
};
|
||||
export class GetBotMenuButton extends Request<Partial<{
|
||||
userId: Api.TypeInputUser;
|
||||
}>, Api.TypeBotMenuButton> {
|
||||
userId: Api.TypeInputUser;
|
||||
};
|
||||
export class SetBotBroadcastDefaultAdminRights extends Request<Partial<{
|
||||
adminRights: Api.TypeChatAdminRights;
|
||||
}>, Bool> {
|
||||
adminRights: Api.TypeChatAdminRights;
|
||||
};
|
||||
export class SetBotGroupDefaultAdminRights extends Request<Partial<{
|
||||
adminRights: Api.TypeChatAdminRights;
|
||||
}>, Bool> {
|
||||
adminRights: Api.TypeChatAdminRights;
|
||||
};
|
||||
}
|
||||
|
||||
export namespace payments {
|
||||
@ -12450,16 +12749,16 @@ namespace Api {
|
||||
|
||||
export type AnyRequest = InvokeAfterMsg | InvokeAfterMsgs | InitConnection | InvokeWithLayer | InvokeWithoutUpdates | InvokeWithMessagesRange | InvokeWithTakeout | ReqPq | ReqPqMulti | ReqPqMultiNew | ReqDHParams | SetClientDHParams | DestroyAuthKey | RpcDropAnswer | GetFutureSalts | Ping | PingDelayDisconnect | DestroySession
|
||||
| auth.SendCode | auth.SignUp | auth.SignIn | auth.LogOut | auth.ResetAuthorizations | auth.ExportAuthorization | auth.ImportAuthorization | auth.BindTempAuthKey | auth.ImportBotAuthorization | auth.CheckPassword | auth.RequestPasswordRecovery | auth.RecoverPassword | auth.ResendCode | auth.CancelCode | auth.DropTempAuthKeys | auth.ExportLoginToken | auth.ImportLoginToken | auth.AcceptLoginToken | auth.CheckRecoveryPassword
|
||||
| account.RegisterDevice | account.UnregisterDevice | account.UpdateNotifySettings | account.GetNotifySettings | account.ResetNotifySettings | account.UpdateProfile | account.UpdateStatus | account.GetWallPapers | account.ReportPeer | account.CheckUsername | account.UpdateUsername | account.GetPrivacy | account.SetPrivacy | account.DeleteAccount | account.GetAccountTTL | account.SetAccountTTL | account.SendChangePhoneCode | account.ChangePhone | account.UpdateDeviceLocked | account.GetAuthorizations | account.ResetAuthorization | account.GetPassword | account.GetPasswordSettings | account.UpdatePasswordSettings | account.SendConfirmPhoneCode | account.ConfirmPhone | account.GetTmpPassword | account.GetWebAuthorizations | account.ResetWebAuthorization | account.ResetWebAuthorizations | account.GetAllSecureValues | account.GetSecureValue | account.SaveSecureValue | account.DeleteSecureValue | account.GetAuthorizationForm | account.AcceptAuthorization | account.SendVerifyPhoneCode | account.VerifyPhone | account.SendVerifyEmailCode | account.VerifyEmail | account.InitTakeoutSession | account.FinishTakeoutSession | account.ConfirmPasswordEmail | account.ResendPasswordEmail | account.CancelPasswordEmail | account.GetContactSignUpNotification | account.SetContactSignUpNotification | account.GetNotifyExceptions | account.GetWallPaper | account.UploadWallPaper | account.SaveWallPaper | account.InstallWallPaper | account.ResetWallPapers | account.GetAutoDownloadSettings | account.SaveAutoDownloadSettings | account.UploadTheme | account.CreateTheme | account.UpdateTheme | account.SaveTheme | account.InstallTheme | account.GetTheme | account.GetThemes | account.SetContentSettings | account.GetContentSettings | account.GetMultiWallPapers | account.GetGlobalPrivacySettings | account.SetGlobalPrivacySettings | account.ReportProfilePhoto | account.ResetPassword | account.DeclinePasswordReset | account.GetChatThemes | account.SetAuthorizationTTL | account.ChangeAuthorizationSettings
|
||||
| account.RegisterDevice | account.UnregisterDevice | account.UpdateNotifySettings | account.GetNotifySettings | account.ResetNotifySettings | account.UpdateProfile | account.UpdateStatus | account.GetWallPapers | account.ReportPeer | account.CheckUsername | account.UpdateUsername | account.GetPrivacy | account.SetPrivacy | account.DeleteAccount | account.GetAccountTTL | account.SetAccountTTL | account.SendChangePhoneCode | account.ChangePhone | account.UpdateDeviceLocked | account.GetAuthorizations | account.ResetAuthorization | account.GetPassword | account.GetPasswordSettings | account.UpdatePasswordSettings | account.SendConfirmPhoneCode | account.ConfirmPhone | account.GetTmpPassword | account.GetWebAuthorizations | account.ResetWebAuthorization | account.ResetWebAuthorizations | account.GetAllSecureValues | account.GetSecureValue | account.SaveSecureValue | account.DeleteSecureValue | account.GetAuthorizationForm | account.AcceptAuthorization | account.SendVerifyPhoneCode | account.VerifyPhone | account.SendVerifyEmailCode | account.VerifyEmail | account.InitTakeoutSession | account.FinishTakeoutSession | account.ConfirmPasswordEmail | account.ResendPasswordEmail | account.CancelPasswordEmail | account.GetContactSignUpNotification | account.SetContactSignUpNotification | account.GetNotifyExceptions | account.GetWallPaper | account.UploadWallPaper | account.SaveWallPaper | account.InstallWallPaper | account.ResetWallPapers | account.GetAutoDownloadSettings | account.SaveAutoDownloadSettings | account.UploadTheme | account.CreateTheme | account.UpdateTheme | account.SaveTheme | account.InstallTheme | account.GetTheme | account.GetThemes | account.SetContentSettings | account.GetContentSettings | account.GetMultiWallPapers | account.GetGlobalPrivacySettings | account.SetGlobalPrivacySettings | account.ReportProfilePhoto | account.ResetPassword | account.DeclinePasswordReset | account.GetChatThemes | account.SetAuthorizationTTL | account.ChangeAuthorizationSettings | account.GetSavedRingtones | account.SaveRingtone | account.UploadRingtone
|
||||
| users.GetUsers | users.GetFullUser | users.SetSecureValueErrors
|
||||
| contacts.GetContactIDs | contacts.GetStatuses | contacts.GetContacts | contacts.ImportContacts | contacts.DeleteContacts | contacts.DeleteByPhones | contacts.Block | contacts.Unblock | contacts.GetBlocked | contacts.Search | contacts.ResolveUsername | contacts.GetTopPeers | contacts.ResetTopPeerRating | contacts.ResetSaved | contacts.GetSaved | contacts.ToggleTopPeers | contacts.AddContact | contacts.AcceptContact | contacts.GetLocated | contacts.BlockFromReplies | contacts.ResolvePhone
|
||||
| messages.GetMessages | messages.GetDialogs | messages.GetHistory | messages.Search | messages.ReadHistory | messages.DeleteHistory | messages.DeleteMessages | messages.ReceivedMessages | messages.SetTyping | messages.SendMessage | messages.SendMedia | messages.ForwardMessages | messages.ReportSpam | messages.GetPeerSettings | messages.Report | messages.GetChats | messages.GetFullChat | messages.EditChatTitle | messages.EditChatPhoto | messages.AddChatUser | messages.DeleteChatUser | messages.CreateChat | messages.GetDhConfig | messages.RequestEncryption | messages.AcceptEncryption | messages.DiscardEncryption | messages.SetEncryptedTyping | messages.ReadEncryptedHistory | messages.SendEncrypted | messages.SendEncryptedFile | messages.SendEncryptedService | messages.ReceivedQueue | messages.ReportEncryptedSpam | messages.ReadMessageContents | messages.GetStickers | messages.GetAllStickers | messages.GetWebPagePreview | messages.ExportChatInvite | messages.CheckChatInvite | messages.ImportChatInvite | messages.GetStickerSet | messages.InstallStickerSet | messages.UninstallStickerSet | messages.StartBot | messages.GetMessagesViews | messages.EditChatAdmin | messages.MigrateChat | messages.SearchGlobal | messages.ReorderStickerSets | messages.GetDocumentByHash | messages.GetSavedGifs | messages.SaveGif | messages.GetInlineBotResults | messages.SetInlineBotResults | messages.SendInlineBotResult | messages.GetMessageEditData | messages.EditMessage | messages.EditInlineBotMessage | messages.GetBotCallbackAnswer | messages.SetBotCallbackAnswer | messages.GetPeerDialogs | messages.SaveDraft | messages.GetAllDrafts | messages.GetFeaturedStickers | messages.ReadFeaturedStickers | messages.GetRecentStickers | messages.SaveRecentSticker | messages.ClearRecentStickers | messages.GetArchivedStickers | messages.GetMaskStickers | messages.GetAttachedStickers | messages.SetGameScore | messages.SetInlineGameScore | messages.GetGameHighScores | messages.GetInlineGameHighScores | messages.GetCommonChats | messages.GetAllChats | messages.GetWebPage | messages.ToggleDialogPin | messages.ReorderPinnedDialogs | messages.GetPinnedDialogs | messages.SetBotShippingResults | messages.SetBotPrecheckoutResults | messages.UploadMedia | messages.SendScreenshotNotification | messages.GetFavedStickers | messages.FaveSticker | messages.GetUnreadMentions | messages.ReadMentions | messages.GetRecentLocations | messages.SendMultiMedia | messages.UploadEncryptedFile | messages.SearchStickerSets | messages.GetSplitRanges | messages.MarkDialogUnread | messages.GetDialogUnreadMarks | messages.ClearAllDrafts | messages.UpdatePinnedMessage | messages.SendVote | messages.GetPollResults | messages.GetOnlines | messages.EditChatAbout | messages.EditChatDefaultBannedRights | messages.GetEmojiKeywords | messages.GetEmojiKeywordsDifference | messages.GetEmojiKeywordsLanguages | messages.GetEmojiURL | messages.GetSearchCounters | messages.RequestUrlAuth | messages.AcceptUrlAuth | messages.HidePeerSettingsBar | messages.GetScheduledHistory | messages.GetScheduledMessages | messages.SendScheduledMessages | messages.DeleteScheduledMessages | messages.GetPollVotes | messages.ToggleStickerSets | messages.GetDialogFilters | messages.GetSuggestedDialogFilters | messages.UpdateDialogFilter | messages.UpdateDialogFiltersOrder | messages.GetOldFeaturedStickers | messages.GetReplies | messages.GetDiscussionMessage | messages.ReadDiscussion | messages.UnpinAllMessages | messages.DeleteChat | messages.DeletePhoneCallHistory | messages.CheckHistoryImport | messages.InitHistoryImport | messages.UploadImportedMedia | messages.StartHistoryImport | messages.GetExportedChatInvites | messages.GetExportedChatInvite | messages.EditExportedChatInvite | messages.DeleteRevokedExportedChatInvites | messages.DeleteExportedChatInvite | messages.GetAdminsWithInvites | messages.GetChatInviteImporters | messages.SetHistoryTTL | messages.CheckHistoryImportPeer | messages.SetChatTheme | messages.GetMessageReadParticipants | messages.GetSearchResultsCalendar | messages.GetSearchResultsPositions | messages.HideChatJoinRequest | messages.HideAllChatJoinRequests | messages.ToggleNoForwards | messages.SaveDefaultSendAs | messages.SendReaction | messages.GetMessagesReactions | messages.GetMessageReactionsList | messages.SetChatAvailableReactions | messages.GetAvailableReactions | messages.SetDefaultReaction | messages.TranslateText | messages.GetUnreadReactions | messages.ReadReactions | messages.SearchSentMedia
|
||||
| messages.GetMessages | messages.GetDialogs | messages.GetHistory | messages.Search | messages.ReadHistory | messages.DeleteHistory | messages.DeleteMessages | messages.ReceivedMessages | messages.SetTyping | messages.SendMessage | messages.SendMedia | messages.ForwardMessages | messages.ReportSpam | messages.GetPeerSettings | messages.Report | messages.GetChats | messages.GetFullChat | messages.EditChatTitle | messages.EditChatPhoto | messages.AddChatUser | messages.DeleteChatUser | messages.CreateChat | messages.GetDhConfig | messages.RequestEncryption | messages.AcceptEncryption | messages.DiscardEncryption | messages.SetEncryptedTyping | messages.ReadEncryptedHistory | messages.SendEncrypted | messages.SendEncryptedFile | messages.SendEncryptedService | messages.ReceivedQueue | messages.ReportEncryptedSpam | messages.ReadMessageContents | messages.GetStickers | messages.GetAllStickers | messages.GetWebPagePreview | messages.ExportChatInvite | messages.CheckChatInvite | messages.ImportChatInvite | messages.GetStickerSet | messages.InstallStickerSet | messages.UninstallStickerSet | messages.StartBot | messages.GetMessagesViews | messages.EditChatAdmin | messages.MigrateChat | messages.SearchGlobal | messages.ReorderStickerSets | messages.GetDocumentByHash | messages.GetSavedGifs | messages.SaveGif | messages.GetInlineBotResults | messages.SetInlineBotResults | messages.SendInlineBotResult | messages.GetMessageEditData | messages.EditMessage | messages.EditInlineBotMessage | messages.GetBotCallbackAnswer | messages.SetBotCallbackAnswer | messages.GetPeerDialogs | messages.SaveDraft | messages.GetAllDrafts | messages.GetFeaturedStickers | messages.ReadFeaturedStickers | messages.GetRecentStickers | messages.SaveRecentSticker | messages.ClearRecentStickers | messages.GetArchivedStickers | messages.GetMaskStickers | messages.GetAttachedStickers | messages.SetGameScore | messages.SetInlineGameScore | messages.GetGameHighScores | messages.GetInlineGameHighScores | messages.GetCommonChats | messages.GetAllChats | messages.GetWebPage | messages.ToggleDialogPin | messages.ReorderPinnedDialogs | messages.GetPinnedDialogs | messages.SetBotShippingResults | messages.SetBotPrecheckoutResults | messages.UploadMedia | messages.SendScreenshotNotification | messages.GetFavedStickers | messages.FaveSticker | messages.GetUnreadMentions | messages.ReadMentions | messages.GetRecentLocations | messages.SendMultiMedia | messages.UploadEncryptedFile | messages.SearchStickerSets | messages.GetSplitRanges | messages.MarkDialogUnread | messages.GetDialogUnreadMarks | messages.ClearAllDrafts | messages.UpdatePinnedMessage | messages.SendVote | messages.GetPollResults | messages.GetOnlines | messages.EditChatAbout | messages.EditChatDefaultBannedRights | messages.GetEmojiKeywords | messages.GetEmojiKeywordsDifference | messages.GetEmojiKeywordsLanguages | messages.GetEmojiURL | messages.GetSearchCounters | messages.RequestUrlAuth | messages.AcceptUrlAuth | messages.HidePeerSettingsBar | messages.GetScheduledHistory | messages.GetScheduledMessages | messages.SendScheduledMessages | messages.DeleteScheduledMessages | messages.GetPollVotes | messages.ToggleStickerSets | messages.GetDialogFilters | messages.GetSuggestedDialogFilters | messages.UpdateDialogFilter | messages.UpdateDialogFiltersOrder | messages.GetOldFeaturedStickers | messages.GetReplies | messages.GetDiscussionMessage | messages.ReadDiscussion | messages.UnpinAllMessages | messages.DeleteChat | messages.DeletePhoneCallHistory | messages.CheckHistoryImport | messages.InitHistoryImport | messages.UploadImportedMedia | messages.StartHistoryImport | messages.GetExportedChatInvites | messages.GetExportedChatInvite | messages.EditExportedChatInvite | messages.DeleteRevokedExportedChatInvites | messages.DeleteExportedChatInvite | messages.GetAdminsWithInvites | messages.GetChatInviteImporters | messages.SetHistoryTTL | messages.CheckHistoryImportPeer | messages.SetChatTheme | messages.GetMessageReadParticipants | messages.GetSearchResultsCalendar | messages.GetSearchResultsPositions | messages.HideChatJoinRequest | messages.HideAllChatJoinRequests | messages.ToggleNoForwards | messages.SaveDefaultSendAs | messages.SendReaction | messages.GetMessagesReactions | messages.GetMessageReactionsList | messages.SetChatAvailableReactions | messages.GetAvailableReactions | messages.SetDefaultReaction | messages.TranslateText | messages.GetUnreadReactions | messages.ReadReactions | messages.SearchSentMedia | messages.GetAttachMenuBots | messages.GetAttachMenuBot | messages.ToggleBotInAttachMenu | messages.RequestWebView | messages.ProlongWebView | messages.RequestSimpleWebView | messages.SendWebViewResultMessage | messages.SendWebViewData
|
||||
| updates.GetState | updates.GetDifference | updates.GetChannelDifference
|
||||
| photos.UpdateProfilePhoto | photos.UploadProfilePhoto | photos.DeletePhotos | photos.GetUserPhotos
|
||||
| upload.SaveFilePart | upload.GetFile | upload.SaveBigFilePart | upload.GetWebFile | upload.GetCdnFile | upload.ReuploadCdnFile | upload.GetCdnFileHashes | upload.GetFileHashes
|
||||
| help.GetConfig | help.GetNearestDc | help.GetAppUpdate | help.GetInviteText | help.GetSupport | help.GetAppChangelog | help.SetBotUpdatesStatus | help.GetCdnConfig | help.GetRecentMeUrls | help.GetTermsOfServiceUpdate | help.AcceptTermsOfService | help.GetDeepLinkInfo | help.GetAppConfig | help.SaveAppLog | help.GetPassportConfig | help.GetSupportName | help.GetUserInfo | help.EditUserInfo | help.GetPromoData | help.HidePromoData | help.DismissSuggestion | help.GetCountriesList
|
||||
| channels.ReadHistory | channels.DeleteMessages | channels.ReportSpam | channels.GetMessages | channels.GetParticipants | channels.GetParticipant | channels.GetChannels | channels.GetFullChannel | channels.CreateChannel | channels.EditAdmin | channels.EditTitle | channels.EditPhoto | channels.CheckUsername | channels.UpdateUsername | channels.JoinChannel | channels.LeaveChannel | channels.InviteToChannel | channels.DeleteChannel | channels.ExportMessageLink | channels.ToggleSignatures | channels.GetAdminedPublicChannels | channels.EditBanned | channels.GetAdminLog | channels.SetStickers | channels.ReadMessageContents | channels.DeleteHistory | channels.TogglePreHistoryHidden | channels.GetLeftChannels | channels.GetGroupsForDiscussion | channels.SetDiscussionGroup | channels.EditCreator | channels.EditLocation | channels.ToggleSlowMode | channels.GetInactiveChannels | channels.ConvertToGigagroup | channels.ViewSponsoredMessage | channels.GetSponsoredMessages | channels.GetSendAs | channels.DeleteParticipantHistory
|
||||
| bots.SendCustomRequest | bots.AnswerWebhookJSONQuery | bots.SetBotCommands | bots.ResetBotCommands | bots.GetBotCommands
|
||||
| bots.SendCustomRequest | bots.AnswerWebhookJSONQuery | bots.SetBotCommands | bots.ResetBotCommands | bots.GetBotCommands | bots.SetBotMenuButton | bots.GetBotMenuButton | bots.SetBotBroadcastDefaultAdminRights | bots.SetBotGroupDefaultAdminRights
|
||||
| payments.GetPaymentForm | payments.GetPaymentReceipt | payments.ValidateRequestedInfo | payments.SendPaymentForm | payments.GetSavedInfo | payments.ClearSavedInfo | payments.GetBankCardData
|
||||
| stickers.CreateStickerSet | stickers.RemoveStickerFromSet | stickers.ChangeStickerPosition | stickers.AddStickerToSet | stickers.SetStickerSetThumb | stickers.CheckShortName | stickers.SuggestShortName
|
||||
| phone.GetCallConfig | phone.RequestCall | phone.AcceptCall | phone.ConfirmCall | phone.ReceivedCall | phone.DiscardCall | phone.SetCallRating | phone.SaveCallDebug | phone.SendSignalingData | phone.CreateGroupCall | phone.JoinGroupCall | phone.LeaveGroupCall | phone.InviteToGroupCall | phone.DiscardGroupCall | phone.ToggleGroupCallSettings | phone.GetGroupCall | phone.GetGroupParticipants | phone.CheckGroupCall | phone.ToggleGroupCallRecord | phone.EditGroupCallParticipant | phone.EditGroupCallTitle | phone.GetGroupCallJoinAs | phone.ExportGroupCallInvite | phone.ToggleGroupCallStartSubscription | phone.StartScheduledGroupCall | phone.SaveDefaultGroupCallJoinAs | phone.JoinGroupCallPresentation | phone.LeaveGroupCallPresentation | phone.GetGroupCallStreamChannels | phone.GetGroupCallStreamRtmpUrl
|
||||
|
||||
@ -259,11 +259,13 @@ function createClasses(classesType, params) {
|
||||
if (argsConfig.hasOwnProperty(argName)) {
|
||||
const arg = argsConfig[argName];
|
||||
if (arg.isFlag) {
|
||||
const flagValue = arg.flagIndex > 30
|
||||
? args.flags2 & (1 << (arg.flagIndex - 31)) : args.flags & (1 << arg.flagIndex);
|
||||
if (arg.type === 'true') {
|
||||
args[argName] = Boolean(args.flags & (1 << arg.flagIndex));
|
||||
args[argName] = Boolean(flagValue);
|
||||
continue;
|
||||
}
|
||||
if (args.flags & (1 << arg.flagIndex)) {
|
||||
if (flagValue) {
|
||||
args[argName] = getArgFromReader(reader, arg);
|
||||
} else {
|
||||
args[argName] = undefined;
|
||||
|
||||
@ -64,7 +64,7 @@ storage.fileMov#4b09ebbc = storage.FileType;
|
||||
storage.fileMp4#b3cea0e4 = storage.FileType;
|
||||
storage.fileWebp#1081464c = storage.FileType;
|
||||
userEmpty#d3bc4b7a id:long = User;
|
||||
user#3ff6ecb0 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true scam:flags.24?true apply_min_photo:flags.25?true fake:flags.26?true id:long access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?Vector<RestrictionReason> bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User;
|
||||
user#3ff6ecb0 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true scam:flags.24?true apply_min_photo:flags.25?true fake:flags.26?true bot_attach_menu:flags.27?true id:long access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?Vector<RestrictionReason> bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User;
|
||||
userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto;
|
||||
userProfilePhoto#82d1f706 flags:# has_video:flags.0?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = UserProfilePhoto;
|
||||
userStatusEmpty#9d05049 = UserStatus;
|
||||
@ -74,12 +74,12 @@ userStatusRecently#e26f42f1 = UserStatus;
|
||||
userStatusLastWeek#7bf09fc = UserStatus;
|
||||
userStatusLastMonth#77ebc742 = UserStatus;
|
||||
chatEmpty#29562865 id:long = Chat;
|
||||
chat#41cbf256 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true deactivated:flags.5?true call_active:flags.23?true call_not_empty:flags.24?true noforwards:flags.25?true id:long title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat;
|
||||
chat#41cbf256 flags:# creator:flags.0?true left:flags.2?true deactivated:flags.5?true call_active:flags.23?true call_not_empty:flags.24?true noforwards:flags.25?true id:long title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat;
|
||||
chatForbidden#6592a1a7 id:long title:string = Chat;
|
||||
channel#8261ac61 flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true gigagroup:flags.26?true noforwards:flags.27?true id:long access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int restriction_reason:flags.9?Vector<RestrictionReason> admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int = Chat;
|
||||
channelForbidden#17d493d5 flags:# broadcast:flags.5?true megagroup:flags.8?true id:long access_hash:long title:string until_date:flags.16?int = Chat;
|
||||
chatFull#d18ee226 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true id:long about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string requests_pending:flags.17?int recent_requesters:flags.17?Vector<long> available_reactions:flags.18?Vector<string> = ChatFull;
|
||||
channelFull#e13c3d20 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector<string> groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector<long> default_send_as:flags.29?Peer available_reactions:flags.30?Vector<string> = ChatFull;
|
||||
channelFull#ea68a619 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags.31?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector<string> groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector<long> default_send_as:flags.29?Peer available_reactions:flags.30?Vector<string> = ChatFull;
|
||||
chatParticipant#c02d4007 user_id:long inviter_id:long date:int = ChatParticipant;
|
||||
chatParticipantCreator#e46bcee4 user_id:long = ChatParticipant;
|
||||
chatParticipantAdmin#a0933f5b user_id:long inviter_id:long date:int = ChatParticipant;
|
||||
@ -133,6 +133,8 @@ messageActionSetMessagesTTL#aa1afbfd period:int = MessageAction;
|
||||
messageActionGroupCallScheduled#b3a07661 call:InputGroupCall schedule_date:int = MessageAction;
|
||||
messageActionSetChatTheme#aa786345 emoticon:string = MessageAction;
|
||||
messageActionChatJoinedByRequest#ebbca3cb = MessageAction;
|
||||
messageActionWebViewDataSentMe#47dd8079 text:string data:string = MessageAction;
|
||||
messageActionWebViewDataSent#b4c38cb5 text:string = MessageAction;
|
||||
dialog#a8edd0f5 flags:# pinned:flags.2?true unread_mark:flags.3?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int = Dialog;
|
||||
dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog;
|
||||
photoEmpty#2331b22d id:long = Photo;
|
||||
@ -153,8 +155,8 @@ inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer;
|
||||
inputNotifyUsers#193b4417 = InputNotifyPeer;
|
||||
inputNotifyChats#4a95e84e = InputNotifyPeer;
|
||||
inputNotifyBroadcasts#b1db7c7e = InputNotifyPeer;
|
||||
inputPeerNotifySettings#9c3d198e flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?string = InputPeerNotifySettings;
|
||||
peerNotifySettings#af509d20 flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?string = PeerNotifySettings;
|
||||
inputPeerNotifySettings#df1f002b flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?NotificationSound = InputPeerNotifySettings;
|
||||
peerNotifySettings#a83b0426 flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int ios_sound:flags.3?NotificationSound android_sound:flags.4?NotificationSound other_sound:flags.5?NotificationSound = PeerNotifySettings;
|
||||
peerSettings#a518110d flags:# report_spam:flags.0?true add_contact:flags.1?true block_contact:flags.2?true share_contact:flags.3?true need_contacts_exception:flags.4?true report_geo:flags.5?true autoarchived:flags.7?true invite_members:flags.8?true request_chat_broadcast:flags.10?true geo_distance:flags.6?int request_chat_title:flags.9?string request_chat_date:flags.9?int = PeerSettings;
|
||||
wallPaper#a437c3ed id:long flags:# creator:flags.0?true default:flags.1?true pattern:flags.3?true dark:flags.4?true access_hash:long slug:string document:Document settings:flags.2?WallPaperSettings = WallPaper;
|
||||
wallPaperNoFile#e0804116 id:long flags:# default:flags.1?true dark:flags.4?true settings:flags.2?WallPaperSettings = WallPaper;
|
||||
@ -168,7 +170,7 @@ inputReportReasonGeoIrrelevant#dbd4feed = ReportReason;
|
||||
inputReportReasonFake#f5ddd6e7 = ReportReason;
|
||||
inputReportReasonIllegalDrugs#a8eb2be = ReportReason;
|
||||
inputReportReasonPersonalDetails#9ec7863d = ReportReason;
|
||||
userFull#cf366521 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true id:long about:flags.1?string settings:PeerSettings profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme_emoticon:flags.15?string private_forward_name:flags.16?string = UserFull;
|
||||
userFull#8c72ea81 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true id:long about:flags.1?string settings:PeerSettings profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme_emoticon:flags.15?string private_forward_name:flags.16?string bot_group_admin_rights:flags.17?ChatAdminRights bot_broadcast_admin_rights:flags.18?ChatAdminRights = UserFull;
|
||||
contact#145ade0b user_id:long mutual:Bool = Contact;
|
||||
importedContact#c13e3c50 user_id:long client_id:long = ImportedContact;
|
||||
contactStatus#16d9703b user_id:long status:UserStatus = ContactStatus;
|
||||
@ -301,6 +303,10 @@ updateBotCommands#4d712f2e peer:Peer bot_id:long commands:Vector<BotCommand> = U
|
||||
updatePendingJoinRequests#7063c3db peer:Peer requests_pending:int recent_requesters:Vector<long> = Update;
|
||||
updateBotChatInviteRequester#11dfa986 peer:Peer date:int user_id:long about:string invite:ExportedChatInvite qts:int = Update;
|
||||
updateMessageReactions#154798c3 peer:Peer msg_id:int reactions:MessageReactions = Update;
|
||||
updateAttachMenuBots#17b7a20b = Update;
|
||||
updateWebViewResultSent#1592b79d query_id:long = Update;
|
||||
updateBotMenuButton#14b85813 bot_id:long button:BotMenuButton = Update;
|
||||
updateSavedRingtones#74d8be99 = 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;
|
||||
@ -442,7 +448,7 @@ stickerSet#d7df217a flags:# archived:flags.1?true official:flags.2?true masks:fl
|
||||
messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet;
|
||||
messages.stickerSetNotModified#d3f924eb = messages.StickerSet;
|
||||
botCommand#c27ac8c7 command:string description:string = BotCommand;
|
||||
botInfo#1b74b335 user_id:long description:string commands:Vector<BotCommand> = BotInfo;
|
||||
botInfo#e4169b5d user_id:long description:string commands:Vector<BotCommand> menu_button:BotMenuButton = BotInfo;
|
||||
keyboardButton#a2fa4880 text:string = KeyboardButton;
|
||||
keyboardButtonUrl#258aff05 text:string url:string = KeyboardButton;
|
||||
keyboardButtonCallback#35bbdb6b flags:# requires_password:flags.0?true text:string data:bytes = KeyboardButton;
|
||||
@ -456,6 +462,8 @@ inputKeyboardButtonUrlAuth#d02e7fd4 flags:# request_write_access:flags.0?true te
|
||||
keyboardButtonRequestPoll#bbc7515d flags:# quiz:flags.0?Bool text:string = KeyboardButton;
|
||||
inputKeyboardButtonUserProfile#e988037b text:string user_id:InputUser = KeyboardButton;
|
||||
keyboardButtonUserProfile#308660c1 text:string user_id:long = KeyboardButton;
|
||||
keyboardButtonWebView#13767230 text:string url:string = KeyboardButton;
|
||||
keyboardButtonSimpleWebView#a0c0505c text:string url:string = KeyboardButton;
|
||||
keyboardButtonRow#77608b83 buttons:Vector<KeyboardButton> = KeyboardButtonRow;
|
||||
replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup;
|
||||
replyKeyboardForceReply#86b40b08 flags:# single_use:flags.1?true selective:flags.2?true placeholder:flags.3?string = ReplyMarkup;
|
||||
@ -957,6 +965,26 @@ messagePeerReaction#51b67eff flags:# big:flags.0?true unread:flags.1?true peer_i
|
||||
groupCallStreamChannel#80eb48af channel:int scale:int last_timestamp_ms:long = GroupCallStreamChannel;
|
||||
phone.groupCallStreamChannels#d0e482b2 channels:Vector<GroupCallStreamChannel> = phone.GroupCallStreamChannels;
|
||||
phone.groupCallStreamRtmpUrl#2dbf3432 url:string key:string = phone.GroupCallStreamRtmpUrl;
|
||||
attachMenuBotIconColor#4576f3f0 name:string color:int = AttachMenuBotIconColor;
|
||||
attachMenuBotIcon#b2a7386b flags:# name:string icon:Document colors:flags.0?Vector<AttachMenuBotIconColor> = AttachMenuBotIcon;
|
||||
attachMenuBot#e93cb772 flags:# inactive:flags.0?true bot_id:long short_name:string icons:Vector<AttachMenuBotIcon> = AttachMenuBot;
|
||||
attachMenuBotsNotModified#f1d88a5c = AttachMenuBots;
|
||||
attachMenuBots#3c4301c0 hash:long bots:Vector<AttachMenuBot> users:Vector<User> = AttachMenuBots;
|
||||
attachMenuBotsBot#93bf667f bot:AttachMenuBot users:Vector<User> = AttachMenuBotsBot;
|
||||
webViewResultUrl#c14557c query_id:long url:string = WebViewResult;
|
||||
simpleWebViewResultUrl#882f76bb url:string = SimpleWebViewResult;
|
||||
webViewMessageSent#c94511c flags:# msg_id:flags.0?InputBotInlineMessageID = WebViewMessageSent;
|
||||
botMenuButtonDefault#7533a588 = BotMenuButton;
|
||||
botMenuButtonCommands#4258c205 = BotMenuButton;
|
||||
botMenuButton#c7b57ce6 text:string url:string = BotMenuButton;
|
||||
account.savedRingtonesNotModified#fbf6e8b1 = account.SavedRingtones;
|
||||
account.savedRingtones#c1e92cc5 hash:long ringtones:Vector<Document> = account.SavedRingtones;
|
||||
notificationSoundDefault#97e8bebe = NotificationSound;
|
||||
notificationSoundNone#6f0c34df = NotificationSound;
|
||||
notificationSoundLocal#830b9ae4 title:string data:string = NotificationSound;
|
||||
notificationSoundRingtone#ff6c8049 id:long = NotificationSound;
|
||||
account.savedRingtone#b7263f6d = account.SavedRingtone;
|
||||
account.savedRingtoneConverted#1f307eb7 document:Document = account.SavedRingtone;
|
||||
---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;
|
||||
@ -1110,6 +1138,14 @@ messages.getMessageReactionsList#e0ee6b77 flags:# peer:InputPeer id:int reaction
|
||||
messages.setChatAvailableReactions#14050ea6 peer:InputPeer available_reactions:Vector<string> = Updates;
|
||||
messages.getAvailableReactions#18dea0ac hash:int = messages.AvailableReactions;
|
||||
messages.setDefaultReaction#d960c4d4 reaction:string = Bool;
|
||||
messages.getAttachMenuBots#16fcc2cb hash:long = AttachMenuBots;
|
||||
messages.getAttachMenuBot#77216192 bot:InputUser = AttachMenuBotsBot;
|
||||
messages.toggleBotInAttachMenu#1aee33af bot:InputUser enabled:Bool = Bool;
|
||||
messages.requestWebView#fa04dff flags:# from_bot_menu:flags.4?true silent:flags.5?true peer:InputPeer bot:InputUser url:flags.1?string start_param:flags.3?string theme_params:flags.2?DataJSON reply_to_msg_id:flags.0?int = WebViewResult;
|
||||
messages.prolongWebView#d22ad148 flags:# silent:flags.5?true peer:InputPeer bot:InputUser query_id:long reply_to_msg_id:flags.0?int = Bool;
|
||||
messages.requestSimpleWebView#6abb2f73 flags:# bot:InputUser url:string theme_params:flags.0?DataJSON = SimpleWebViewResult;
|
||||
messages.sendWebViewResultMessage#a4314f5 bot_query_id:string result:InputBotInlineResult = WebViewMessageSent;
|
||||
messages.sendWebViewData#dc0242c8 bot:InputUser random_id:long button_text:string data:string = 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;
|
||||
|
||||
@ -222,5 +222,13 @@
|
||||
"help.getAppConfig",
|
||||
"stats.getBroadcastStats",
|
||||
"stats.getMegagroupStats",
|
||||
"stats.loadAsyncGraph"
|
||||
"stats.loadAsyncGraph",
|
||||
"messages.getAttachMenuBots",
|
||||
"messages.getAttachMenuBot",
|
||||
"messages.toggleBotInAttachMenu",
|
||||
"messages.requestWebView",
|
||||
"messages.prolongWebView",
|
||||
"messages.requestSimpleWebView",
|
||||
"messages.sendWebViewResultMessage",
|
||||
"messages.sendWebViewData"
|
||||
]
|
||||
|
||||
@ -1,33 +1,3 @@
|
||||
///////////////////////////////
|
||||
/////////////////// Layer cons
|
||||
///////////////////////////////
|
||||
|
||||
//invokeAfterMsg#cb9f372d msg_id:long query:!X = X;
|
||||
//invokeAfterMsgs#3dc4b4f0 msg_ids:Vector<long> query:!X = X;
|
||||
//invokeWithLayer1#53835315 query:!X = X;
|
||||
//invokeWithLayer2#289dd1f6 query:!X = X;
|
||||
//invokeWithLayer3#b7475268 query:!X = X;
|
||||
//invokeWithLayer4#dea0d430 query:!X = X;
|
||||
//invokeWithLayer5#417a57ae query:!X = X;
|
||||
//invokeWithLayer6#3a64d54d query:!X = X;
|
||||
//invokeWithLayer7#a5be56d3 query:!X = X;
|
||||
//invokeWithLayer8#e9abd9fd query:!X = X;
|
||||
//invokeWithLayer9#76715a63 query:!X = X;
|
||||
//invokeWithLayer10#39620c41 query:!X = X;
|
||||
//invokeWithLayer11#a6b88fdf query:!X = X;
|
||||
//invokeWithLayer12#dda60d3c query:!X = X;
|
||||
//invokeWithLayer13#427c8ea2 query:!X = X;
|
||||
//invokeWithLayer14#2b9b08fa query:!X = X;
|
||||
//invokeWithLayer15#b4418b64 query:!X = X;
|
||||
//invokeWithLayer16#cf5f0987 query:!X = X;
|
||||
//invokeWithLayer17#50858a19 query:!X = X;
|
||||
//invokeWithLayer18#1c900537 query:!X = X;
|
||||
//invokeWithLayer#da9b0d0d layer:int query:!X = X; // after 18 layer
|
||||
|
||||
///////////////////////////////
|
||||
///////// Main application API
|
||||
///////////////////////////////
|
||||
|
||||
boolFalse#bc799737 = Bool;
|
||||
boolTrue#997275b5 = Bool;
|
||||
|
||||
@ -110,7 +80,7 @@ storage.fileMp4#b3cea0e4 = storage.FileType;
|
||||
storage.fileWebp#1081464c = storage.FileType;
|
||||
|
||||
userEmpty#d3bc4b7a id:long = User;
|
||||
user#3ff6ecb0 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true scam:flags.24?true apply_min_photo:flags.25?true fake:flags.26?true id:long access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?Vector<RestrictionReason> bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User;
|
||||
user#3ff6ecb0 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true scam:flags.24?true apply_min_photo:flags.25?true fake:flags.26?true bot_attach_menu:flags.27?true id:long access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?Vector<RestrictionReason> bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User;
|
||||
|
||||
userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto;
|
||||
userProfilePhoto#82d1f706 flags:# has_video:flags.0?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = UserProfilePhoto;
|
||||
@ -123,13 +93,13 @@ userStatusLastWeek#7bf09fc = UserStatus;
|
||||
userStatusLastMonth#77ebc742 = UserStatus;
|
||||
|
||||
chatEmpty#29562865 id:long = Chat;
|
||||
chat#41cbf256 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true deactivated:flags.5?true call_active:flags.23?true call_not_empty:flags.24?true noforwards:flags.25?true id:long title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat;
|
||||
chat#41cbf256 flags:# creator:flags.0?true left:flags.2?true deactivated:flags.5?true call_active:flags.23?true call_not_empty:flags.24?true noforwards:flags.25?true id:long title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat;
|
||||
chatForbidden#6592a1a7 id:long title:string = Chat;
|
||||
channel#8261ac61 flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true gigagroup:flags.26?true noforwards:flags.27?true id:long access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int restriction_reason:flags.9?Vector<RestrictionReason> admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int = Chat;
|
||||
channelForbidden#17d493d5 flags:# broadcast:flags.5?true megagroup:flags.8?true id:long access_hash:long title:string until_date:flags.16?int = Chat;
|
||||
|
||||
chatFull#d18ee226 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true id:long about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string requests_pending:flags.17?int recent_requesters:flags.17?Vector<long> available_reactions:flags.18?Vector<string> = ChatFull;
|
||||
channelFull#e13c3d20 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector<string> groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector<long> default_send_as:flags.29?Peer available_reactions:flags.30?Vector<string> = ChatFull;
|
||||
channelFull#ea68a619 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags.31?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector<string> groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector<long> default_send_as:flags.29?Peer available_reactions:flags.30?Vector<string> = ChatFull;
|
||||
|
||||
chatParticipant#c02d4007 user_id:long inviter_id:long date:int = ChatParticipant;
|
||||
chatParticipantCreator#e46bcee4 user_id:long = ChatParticipant;
|
||||
@ -189,6 +159,8 @@ messageActionSetMessagesTTL#aa1afbfd period:int = MessageAction;
|
||||
messageActionGroupCallScheduled#b3a07661 call:InputGroupCall schedule_date:int = MessageAction;
|
||||
messageActionSetChatTheme#aa786345 emoticon:string = MessageAction;
|
||||
messageActionChatJoinedByRequest#ebbca3cb = MessageAction;
|
||||
messageActionWebViewDataSentMe#47dd8079 text:string data:string = MessageAction;
|
||||
messageActionWebViewDataSent#b4c38cb5 text:string = MessageAction;
|
||||
|
||||
dialog#a8edd0f5 flags:# pinned:flags.2?true unread_mark:flags.3?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int = Dialog;
|
||||
dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog;
|
||||
@ -218,9 +190,9 @@ inputNotifyUsers#193b4417 = InputNotifyPeer;
|
||||
inputNotifyChats#4a95e84e = InputNotifyPeer;
|
||||
inputNotifyBroadcasts#b1db7c7e = InputNotifyPeer;
|
||||
|
||||
inputPeerNotifySettings#9c3d198e flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?string = InputPeerNotifySettings;
|
||||
inputPeerNotifySettings#df1f002b flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?NotificationSound = InputPeerNotifySettings;
|
||||
|
||||
peerNotifySettings#af509d20 flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?string = PeerNotifySettings;
|
||||
peerNotifySettings#a83b0426 flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int ios_sound:flags.3?NotificationSound android_sound:flags.4?NotificationSound other_sound:flags.5?NotificationSound = PeerNotifySettings;
|
||||
|
||||
peerSettings#a518110d flags:# report_spam:flags.0?true add_contact:flags.1?true block_contact:flags.2?true share_contact:flags.3?true need_contacts_exception:flags.4?true report_geo:flags.5?true autoarchived:flags.7?true invite_members:flags.8?true request_chat_broadcast:flags.10?true geo_distance:flags.6?int request_chat_title:flags.9?string request_chat_date:flags.9?int = PeerSettings;
|
||||
|
||||
@ -238,7 +210,7 @@ inputReportReasonFake#f5ddd6e7 = ReportReason;
|
||||
inputReportReasonIllegalDrugs#a8eb2be = ReportReason;
|
||||
inputReportReasonPersonalDetails#9ec7863d = ReportReason;
|
||||
|
||||
userFull#cf366521 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true id:long about:flags.1?string settings:PeerSettings profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme_emoticon:flags.15?string private_forward_name:flags.16?string = UserFull;
|
||||
userFull#8c72ea81 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true id:long about:flags.1?string settings:PeerSettings profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme_emoticon:flags.15?string private_forward_name:flags.16?string bot_group_admin_rights:flags.17?ChatAdminRights bot_broadcast_admin_rights:flags.18?ChatAdminRights = UserFull;
|
||||
|
||||
contact#145ade0b user_id:long mutual:Bool = Contact;
|
||||
|
||||
@ -384,6 +356,10 @@ updateBotCommands#4d712f2e peer:Peer bot_id:long commands:Vector<BotCommand> = U
|
||||
updatePendingJoinRequests#7063c3db peer:Peer requests_pending:int recent_requesters:Vector<long> = Update;
|
||||
updateBotChatInviteRequester#11dfa986 peer:Peer date:int user_id:long about:string invite:ExportedChatInvite qts:int = Update;
|
||||
updateMessageReactions#154798c3 peer:Peer msg_id:int reactions:MessageReactions = Update;
|
||||
updateAttachMenuBots#17b7a20b = Update;
|
||||
updateWebViewResultSent#1592b79d query_id:long = Update;
|
||||
updateBotMenuButton#14b85813 bot_id:long button:BotMenuButton = Update;
|
||||
updateSavedRingtones#74d8be99 = Update;
|
||||
|
||||
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
|
||||
|
||||
@ -575,7 +551,7 @@ messages.stickerSetNotModified#d3f924eb = messages.StickerSet;
|
||||
|
||||
botCommand#c27ac8c7 command:string description:string = BotCommand;
|
||||
|
||||
botInfo#1b74b335 user_id:long description:string commands:Vector<BotCommand> = BotInfo;
|
||||
botInfo#e4169b5d user_id:long description:string commands:Vector<BotCommand> menu_button:BotMenuButton = BotInfo;
|
||||
|
||||
keyboardButton#a2fa4880 text:string = KeyboardButton;
|
||||
keyboardButtonUrl#258aff05 text:string url:string = KeyboardButton;
|
||||
@ -590,6 +566,8 @@ inputKeyboardButtonUrlAuth#d02e7fd4 flags:# request_write_access:flags.0?true te
|
||||
keyboardButtonRequestPoll#bbc7515d flags:# quiz:flags.0?Bool text:string = KeyboardButton;
|
||||
inputKeyboardButtonUserProfile#e988037b text:string user_id:InputUser = KeyboardButton;
|
||||
keyboardButtonUserProfile#308660c1 text:string user_id:long = KeyboardButton;
|
||||
keyboardButtonWebView#13767230 text:string url:string = KeyboardButton;
|
||||
keyboardButtonSimpleWebView#a0c0505c text:string url:string = KeyboardButton;
|
||||
|
||||
keyboardButtonRow#77608b83 buttons:Vector<KeyboardButton> = KeyboardButtonRow;
|
||||
|
||||
@ -1329,6 +1307,38 @@ phone.groupCallStreamChannels#d0e482b2 channels:Vector<GroupCallStreamChannel> =
|
||||
|
||||
phone.groupCallStreamRtmpUrl#2dbf3432 url:string key:string = phone.GroupCallStreamRtmpUrl;
|
||||
|
||||
attachMenuBotIconColor#4576f3f0 name:string color:int = AttachMenuBotIconColor;
|
||||
|
||||
attachMenuBotIcon#b2a7386b flags:# name:string icon:Document colors:flags.0?Vector<AttachMenuBotIconColor> = AttachMenuBotIcon;
|
||||
|
||||
attachMenuBot#e93cb772 flags:# inactive:flags.0?true bot_id:long short_name:string icons:Vector<AttachMenuBotIcon> = AttachMenuBot;
|
||||
|
||||
attachMenuBotsNotModified#f1d88a5c = AttachMenuBots;
|
||||
attachMenuBots#3c4301c0 hash:long bots:Vector<AttachMenuBot> users:Vector<User> = AttachMenuBots;
|
||||
|
||||
attachMenuBotsBot#93bf667f bot:AttachMenuBot users:Vector<User> = AttachMenuBotsBot;
|
||||
|
||||
webViewResultUrl#c14557c query_id:long url:string = WebViewResult;
|
||||
|
||||
simpleWebViewResultUrl#882f76bb url:string = SimpleWebViewResult;
|
||||
|
||||
webViewMessageSent#c94511c flags:# msg_id:flags.0?InputBotInlineMessageID = WebViewMessageSent;
|
||||
|
||||
botMenuButtonDefault#7533a588 = BotMenuButton;
|
||||
botMenuButtonCommands#4258c205 = BotMenuButton;
|
||||
botMenuButton#c7b57ce6 text:string url:string = BotMenuButton;
|
||||
|
||||
account.savedRingtonesNotModified#fbf6e8b1 = account.SavedRingtones;
|
||||
account.savedRingtones#c1e92cc5 hash:long ringtones:Vector<Document> = account.SavedRingtones;
|
||||
|
||||
notificationSoundDefault#97e8bebe = NotificationSound;
|
||||
notificationSoundNone#6f0c34df = NotificationSound;
|
||||
notificationSoundLocal#830b9ae4 title:string data:string = NotificationSound;
|
||||
notificationSoundRingtone#ff6c8049 id:long = NotificationSound;
|
||||
|
||||
account.savedRingtone#b7263f6d = account.SavedRingtone;
|
||||
account.savedRingtoneConverted#1f307eb7 document:Document = account.SavedRingtone;
|
||||
|
||||
---functions---
|
||||
|
||||
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
|
||||
@ -1432,6 +1442,9 @@ account.declinePasswordReset#4c9409f6 = Bool;
|
||||
account.getChatThemes#d638de89 hash:long = account.Themes;
|
||||
account.setAuthorizationTTL#bf899aa0 authorization_ttl_days:int = Bool;
|
||||
account.changeAuthorizationSettings#40f48462 flags:# hash:long encrypted_requests_disabled:flags.0?Bool call_requests_disabled:flags.1?Bool = Bool;
|
||||
account.getSavedRingtones#e1902288 hash:long = account.SavedRingtones;
|
||||
account.saveRingtone#3dea5b03 id:InputDocument unsave:Bool = account.SavedRingtone;
|
||||
account.uploadRingtone#831a83a2 file:InputFile file_name:string mime_type:string = Document;
|
||||
|
||||
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
|
||||
users.getFullUser#b60f5918 id:InputUser = users.UserFull;
|
||||
@ -1618,6 +1631,14 @@ messages.translateText#24ce6dee flags:# peer:flags.0?InputPeer msg_id:flags.0?in
|
||||
messages.getUnreadReactions#e85bae1a peer:InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages;
|
||||
messages.readReactions#82e251d7 peer:InputPeer = messages.AffectedHistory;
|
||||
messages.searchSentMedia#107e31a0 q:string filter:MessagesFilter limit:int = messages.Messages;
|
||||
messages.getAttachMenuBots#16fcc2cb hash:long = AttachMenuBots;
|
||||
messages.getAttachMenuBot#77216192 bot:InputUser = AttachMenuBotsBot;
|
||||
messages.toggleBotInAttachMenu#1aee33af bot:InputUser enabled:Bool = Bool;
|
||||
messages.requestWebView#fa04dff flags:# from_bot_menu:flags.4?true silent:flags.5?true peer:InputPeer bot:InputUser url:flags.1?string start_param:flags.3?string theme_params:flags.2?DataJSON reply_to_msg_id:flags.0?int = WebViewResult;
|
||||
messages.prolongWebView#d22ad148 flags:# silent:flags.5?true peer:InputPeer bot:InputUser query_id:long reply_to_msg_id:flags.0?int = Bool;
|
||||
messages.requestSimpleWebView#6abb2f73 flags:# bot:InputUser url:string theme_params:flags.0?DataJSON = SimpleWebViewResult;
|
||||
messages.sendWebViewResultMessage#a4314f5 bot_query_id:string result:InputBotInlineResult = WebViewMessageSent;
|
||||
messages.sendWebViewData#dc0242c8 bot:InputUser random_id:long button_text:string data:string = Updates;
|
||||
|
||||
updates.getState#edd4882a = updates.State;
|
||||
updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference;
|
||||
@ -1685,7 +1706,7 @@ channels.editBanned#96e6cd81 channel:InputChannel participant:InputPeer banned_r
|
||||
channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector<InputUser> max_id:long min_id:long limit:int = channels.AdminLogResults;
|
||||
channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool;
|
||||
channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector<int> = Bool;
|
||||
channels.deleteHistory#af369d42 channel:InputChannel max_id:int = Bool;
|
||||
channels.deleteHistory#9baa9647 flags:# for_everyone:flags.0?true channel:InputChannel max_id:int = Updates;
|
||||
channels.togglePreHistoryHidden#eabbb94c channel:InputChannel enabled:Bool = Updates;
|
||||
channels.getLeftChannels#8341ecc0 offset:int = messages.Chats;
|
||||
channels.getGroupsForDiscussion#f5dad378 = messages.Chats;
|
||||
@ -1705,6 +1726,10 @@ bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool;
|
||||
bots.setBotCommands#517165a scope:BotCommandScope lang_code:string commands:Vector<BotCommand> = Bool;
|
||||
bots.resetBotCommands#3d8de0f9 scope:BotCommandScope lang_code:string = Bool;
|
||||
bots.getBotCommands#e34c0dd6 scope:BotCommandScope lang_code:string = Vector<BotCommand>;
|
||||
bots.setBotMenuButton#4504d54f user_id:InputUser button:BotMenuButton = Bool;
|
||||
bots.getBotMenuButton#9c60eb28 user_id:InputUser = BotMenuButton;
|
||||
bots.setBotBroadcastDefaultAdminRights#788464e1 admin_rights:ChatAdminRights = Bool;
|
||||
bots.setBotGroupDefaultAdminRights#925ec9ea admin_rights:ChatAdminRights = Bool;
|
||||
|
||||
payments.getPaymentForm#8a333c8d flags:# peer:InputPeer msg_id:int theme_params:flags.0?DataJSON = payments.PaymentForm;
|
||||
payments.getPaymentReceipt#2478d1cc peer:InputPeer msg_id:int = payments.PaymentReceipt;
|
||||
@ -1768,4 +1793,3 @@ 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 139
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Not sure what they are for.
|
||||
const RAW_TYPES = new Set(['Bool', 'X'])
|
||||
const FLAGS = ['flags', 'flags2'];
|
||||
|
||||
module.exports = ({ types, constructors, functions }) => {
|
||||
function groupByKey(collection, key) {
|
||||
@ -32,7 +33,7 @@ module.exports = ({ types, constructors, functions }) => {
|
||||
return `export class ${upperFirst(name)} extends VirtualClass<void> {};`
|
||||
}
|
||||
|
||||
let hasRequiredArgs = argKeys.some((argName) => argName !== 'flags' && !argsConfig[argName].isFlag)
|
||||
let hasRequiredArgs = argKeys.some((argName) => !FLAGS.includes(argName) && !argsConfig[argName].isFlag)
|
||||
|
||||
return `
|
||||
export class ${upperFirst(name)} extends VirtualClass<{
|
||||
@ -61,7 +62,7 @@ ${indent}};`.trim()
|
||||
return `export class ${upperFirst(name)} extends Request<void, ${renderedResult}> {};`
|
||||
}
|
||||
|
||||
let hasRequiredArgs = argKeys.some((argName) => argName !== 'flags' && !argsConfig[argName].isFlag)
|
||||
let hasRequiredArgs = argKeys.some((argName) => !FLAGS.includes(argName) && !argsConfig[argName].isFlag)
|
||||
|
||||
return `
|
||||
export class ${upperFirst(name)} extends Request<Partial<{
|
||||
@ -95,7 +96,7 @@ ${indent}};`.trim()
|
||||
|
||||
const valueType = renderValueType(type, isVector, !skipConstructorId)
|
||||
|
||||
return `${argName === 'flags' ? '// ' : ''}${argName}${isFlag ? '?' : ''}: ${valueType}`
|
||||
return `${FLAGS.includes(argName) ? '// ' : ''}${argName}${isFlag ? '?' : ''}: ${valueType}`
|
||||
}
|
||||
|
||||
function renderValueType(type, isVector, isTlType) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -51,6 +51,21 @@
|
||||
.icon-volume-3:before {
|
||||
content: "\e991";
|
||||
}
|
||||
.icon-reactions:before {
|
||||
content: "\e99a";
|
||||
}
|
||||
.icon-reaction-filled:before {
|
||||
content: "\e99b";
|
||||
}
|
||||
.icon-webapp:before {
|
||||
content: "\e993";
|
||||
}
|
||||
.icon-reload:before {
|
||||
content: "\e994";
|
||||
}
|
||||
.icon-install:before {
|
||||
content: "\e999";
|
||||
}
|
||||
.icon-favorite-filled:before {
|
||||
content: "\e998";
|
||||
}
|
||||
@ -66,12 +81,6 @@
|
||||
.icon-copy-media:before {
|
||||
content: "\e995";
|
||||
}
|
||||
.icon-reaction-filled:before {
|
||||
content: "\e994";
|
||||
}
|
||||
.icon-reactions:before {
|
||||
content: "\e993";
|
||||
}
|
||||
.icon-sidebar:before {
|
||||
content: "\e992";
|
||||
}
|
||||
|
||||
@ -30,9 +30,11 @@ export const processDeepLink = (url: string) => {
|
||||
switch (method) {
|
||||
case 'resolve': {
|
||||
const {
|
||||
domain, phone, post, comment, voicechat, livestream, start,
|
||||
domain, phone, post, comment, voicechat, livestream, start, startattach, attach,
|
||||
} = params;
|
||||
|
||||
const startAttach = params.hasOwnProperty('startattach') && !startattach ? true : startattach;
|
||||
|
||||
if (domain !== 'telegrampassport') {
|
||||
if (params.hasOwnProperty('voicechat') || params.hasOwnProperty('livestream')) {
|
||||
joinVoiceChatByLink({
|
||||
@ -40,13 +42,15 @@ export const processDeepLink = (url: string) => {
|
||||
inviteHash: voicechat || livestream,
|
||||
});
|
||||
} else if (phone) {
|
||||
openChatByPhoneNumber({ phone });
|
||||
openChatByPhoneNumber({ phone, startAttach, attach });
|
||||
} else {
|
||||
openChatByUsername({
|
||||
username: domain,
|
||||
messageId: Number(post),
|
||||
commentId: Number(comment),
|
||||
startParam: start,
|
||||
startAttach,
|
||||
attach,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,6 +18,7 @@ import { webpToPng } from './webpToPng';
|
||||
const asCacheApiType = {
|
||||
[ApiMediaFormat.BlobUrl]: cacheApi.Type.Blob,
|
||||
[ApiMediaFormat.Lottie]: cacheApi.Type.Blob,
|
||||
[ApiMediaFormat.Text]: cacheApi.Type.Text,
|
||||
[ApiMediaFormat.Progressive]: undefined,
|
||||
[ApiMediaFormat.Stream]: undefined,
|
||||
};
|
||||
|
||||
39
src/util/themeStyle.ts
Normal file
39
src/util/themeStyle.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import { ApiThemeParameters } from '../api/types';
|
||||
|
||||
export function extractCurrentThemeParams(): ApiThemeParameters {
|
||||
const style = getComputedStyle(document.documentElement);
|
||||
const backgroundColor = getPropertyWrapped(style, '--color-background');
|
||||
const textColor = getPropertyWrapped(style, '--color-text');
|
||||
const buttonColor = getPropertyWrapped(style, '--color-primary');
|
||||
const buttonTextColor = getPropertyWrapped(style, '--color-white');
|
||||
const linkColor = getPropertyWrapped(style, '--color-links');
|
||||
const hintColor = getPropertyWrapped(style, '--color-text-secondary');
|
||||
return {
|
||||
bg_color: backgroundColor,
|
||||
text_color: textColor,
|
||||
hint_color: hintColor,
|
||||
link_color: linkColor,
|
||||
button_color: buttonColor,
|
||||
button_text_color: buttonTextColor,
|
||||
};
|
||||
}
|
||||
|
||||
export function validateHexColor(color: string) {
|
||||
return /^#[0-9A-F]{6}$/i.test(color);
|
||||
}
|
||||
|
||||
function getPropertyWrapped(style: CSSStyleDeclaration, property: string) {
|
||||
const value = style.getPropertyValue(property);
|
||||
return wrapColor(value.trim());
|
||||
}
|
||||
|
||||
function wrapColor(color: string) {
|
||||
if (validateHexColor(color)) return color;
|
||||
return `#${color.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+\.{0,1}\d*))?\)$/)!
|
||||
.slice(1)
|
||||
.map((n: string, i: number) => (i === 3 ? Math.round(parseFloat(n) * 255) : parseFloat(n))
|
||||
.toString(16)
|
||||
.padStart(2, '0')
|
||||
.replace('NaN', ''))
|
||||
.join('')}`;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user