Web Apps: Support new event types (#3818)
This commit is contained in:
parent
e2aa5197d1
commit
c59d468c73
@ -426,6 +426,8 @@ function buildAction(
|
||||
if (action.domain) {
|
||||
text = 'ActionBotAllowed';
|
||||
translationValues.push(action.domain);
|
||||
} else if (action.fromRequest) {
|
||||
text = 'lng_action_webapp_bot_allowed';
|
||||
} else {
|
||||
text = 'ActionAttachMenuBotAllowed';
|
||||
}
|
||||
|
||||
@ -468,6 +468,55 @@ export async function acceptLinkUrlAuth({ url, isWriteAllowed }: { url: string;
|
||||
return authResult;
|
||||
}
|
||||
|
||||
export function fetchBotCanSendMessage({ bot } : { bot: ApiUser }) {
|
||||
return invokeRequest(new GramJs.bots.CanSendMessage({
|
||||
bot: buildInputEntity(bot.id, bot.accessHash) as GramJs.InputUser,
|
||||
}));
|
||||
}
|
||||
|
||||
export function allowBotSendMessages({ bot } : { bot: ApiUser }) {
|
||||
return invokeRequest(new GramJs.bots.AllowSendMessage({
|
||||
bot: buildInputEntity(bot.id, bot.accessHash) as GramJs.InputUser,
|
||||
}), {
|
||||
shouldReturnTrue: true,
|
||||
});
|
||||
}
|
||||
|
||||
export async function invokeWebViewCustomMethod({
|
||||
bot,
|
||||
customMethod,
|
||||
parameters,
|
||||
}: {
|
||||
bot: ApiUser;
|
||||
customMethod: string;
|
||||
parameters: string;
|
||||
}): Promise<{
|
||||
result: object;
|
||||
} | {
|
||||
error: string;
|
||||
}> {
|
||||
try {
|
||||
const result = await invokeRequest(new GramJs.bots.InvokeWebViewCustomMethod({
|
||||
bot: buildInputPeer(bot.id, bot.accessHash),
|
||||
params: new GramJs.DataJSON({
|
||||
data: parameters,
|
||||
}),
|
||||
customMethod,
|
||||
}), {
|
||||
shouldThrow: true,
|
||||
});
|
||||
|
||||
return {
|
||||
result: JSON.parse(result!.data),
|
||||
};
|
||||
} catch (e) {
|
||||
const error = e as Error;
|
||||
return {
|
||||
error: error.message,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function processInlineBotResult(queryId: string, results: GramJs.TypeBotInlineResult[]) {
|
||||
return results.map((result) => {
|
||||
if (result instanceof GramJs.BotInlineMediaResult) {
|
||||
|
||||
@ -77,6 +77,7 @@ export {
|
||||
answerCallbackButton, fetchTopInlineBots, fetchInlineBot, fetchInlineBotResults, sendInlineBotResult, startBot,
|
||||
requestWebView, requestSimpleWebView, sendWebViewData, prolongWebView, loadAttachBots, toggleAttachBot, fetchBotApp,
|
||||
requestBotUrlAuth, requestLinkUrlAuth, acceptBotUrlAuth, acceptLinkUrlAuth, loadAttachBot, requestAppWebView,
|
||||
allowBotSendMessages, fetchBotCanSendMessage, invokeWebViewCustomMethod,
|
||||
} from './bots';
|
||||
|
||||
export {
|
||||
|
||||
@ -7,13 +7,13 @@ export { default as AttachBotRecipientPicker } from '../components/main/AttachBo
|
||||
export { default as Dialogs } from '../components/main/Dialogs';
|
||||
export { default as Notifications } from '../components/main/Notifications';
|
||||
export { default as SafeLinkModal } from '../components/main/SafeLinkModal';
|
||||
export { default as MapModal } from '../components/modals/mapModal/MapModal';
|
||||
export { default as UrlAuthModal } from '../components/main/UrlAuthModal';
|
||||
export { default as MapModal } from '../components/modals/map/MapModal';
|
||||
export { default as UrlAuthModal } from '../components/modals/urlAuth/UrlAuthModal';
|
||||
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 WebAppModal } from '../components/modals/webApp/WebAppModal';
|
||||
export { default as BotTrustModal } from '../components/main/BotTrustModal';
|
||||
export { default as AttachBotInstallModal } from '../components/main/AttachBotInstallModal';
|
||||
export { default as AttachBotInstallModal } from '../components/modals/attachBotInstall/AttachBotInstallModal';
|
||||
export { default as DeleteFolderDialog } from '../components/main/DeleteFolderDialog';
|
||||
export { default as PremiumMainModal } from '../components/main/premium/PremiumMainModal';
|
||||
export { default as GiftPremiumModal } from '../components/main/premium/GiftPremiumModal';
|
||||
|
||||
@ -80,11 +80,11 @@ import PhoneCall from '../calls/phone/PhoneCall.async';
|
||||
import MessageListHistoryHandler from '../middle/MessageListHistoryHandler';
|
||||
import NewContactModal from './NewContactModal.async';
|
||||
import RatePhoneCallModal from '../calls/phone/RatePhoneCallModal.async';
|
||||
import WebAppModal from './WebAppModal.async';
|
||||
import WebAppModal from '../modals/webApp/WebAppModal.async';
|
||||
import BotTrustModal from './BotTrustModal.async';
|
||||
import AttachBotInstallModal from './AttachBotInstallModal.async';
|
||||
import AttachBotInstallModal from '../modals/attachBotInstall/AttachBotInstallModal.async';
|
||||
import ConfettiContainer from './ConfettiContainer';
|
||||
import UrlAuthModal from './UrlAuthModal.async';
|
||||
import UrlAuthModal from '../modals/urlAuth/UrlAuthModal.async';
|
||||
import PremiumMainModal from './premium/PremiumMainModal.async';
|
||||
import PaymentModal from '../payment/PaymentModal.async';
|
||||
import ReceiptModal from '../payment/ReceiptModal.async';
|
||||
@ -96,7 +96,7 @@ import AttachBotRecipientPicker from './AttachBotRecipientPicker.async';
|
||||
import ReactionPicker from '../middle/message/ReactionPicker.async';
|
||||
import ChatlistModal from '../modals/chatlist/ChatlistModal.async';
|
||||
import StoryViewer from '../story/StoryViewer.async';
|
||||
import MapModal from '../modals/mapModal/MapModal.async';
|
||||
import MapModal from '../modals/map/MapModal.async';
|
||||
|
||||
import './Main.scss';
|
||||
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import type { FC } from '../../lib/teact/teact';
|
||||
import React from '../../lib/teact/teact';
|
||||
import { Bundles } from '../../util/moduleLoader';
|
||||
import type { FC } from '../../../lib/teact/teact';
|
||||
import React from '../../../lib/teact/teact';
|
||||
import { Bundles } from '../../../util/moduleLoader';
|
||||
|
||||
import type { OwnProps } from './AttachBotInstallModal';
|
||||
|
||||
import useModuleLoader from '../../hooks/useModuleLoader';
|
||||
import useModuleLoader from '../../../hooks/useModuleLoader';
|
||||
|
||||
const AttachBotInstallModalAsync: FC<OwnProps> = (props) => {
|
||||
const { bot } = props;
|
||||
@ -1,18 +1,18 @@
|
||||
import React, {
|
||||
memo, useCallback, useEffect, useState,
|
||||
} from '../../lib/teact/teact';
|
||||
import { getActions } from '../../global';
|
||||
} from '../../../lib/teact/teact';
|
||||
import { getActions } from '../../../global';
|
||||
|
||||
import type { FC } from '../../lib/teact/teact';
|
||||
import type { ApiAttachBot } from '../../api/types';
|
||||
import type { FC } from '../../../lib/teact/teact';
|
||||
import type { ApiAttachBot } from '../../../api/types';
|
||||
|
||||
import renderText from '../common/helpers/renderText';
|
||||
import renderText from '../../common/helpers/renderText';
|
||||
|
||||
import useLang from '../../hooks/useLang';
|
||||
import usePrevious from '../../hooks/usePrevious';
|
||||
import useLang from '../../../hooks/useLang';
|
||||
import usePrevious from '../../../hooks/usePrevious';
|
||||
|
||||
import ConfirmDialog from '../ui/ConfirmDialog';
|
||||
import Checkbox from '../ui/Checkbox';
|
||||
import ConfirmDialog from '../../ui/ConfirmDialog';
|
||||
import Checkbox from '../../ui/Checkbox';
|
||||
|
||||
export type OwnProps = {
|
||||
bot?: ApiAttachBot;
|
||||
@ -1,9 +1,9 @@
|
||||
import type { FC } from '../../lib/teact/teact';
|
||||
import React from '../../lib/teact/teact';
|
||||
import { Bundles } from '../../util/moduleLoader';
|
||||
import type { FC } from '../../../lib/teact/teact';
|
||||
import React from '../../../lib/teact/teact';
|
||||
import { Bundles } from '../../../util/moduleLoader';
|
||||
import type { OwnProps } from './UrlAuthModal';
|
||||
|
||||
import useModuleLoader from '../../hooks/useModuleLoader';
|
||||
import useModuleLoader from '../../../hooks/useModuleLoader';
|
||||
|
||||
const UrlAuthModalAsync: FC<OwnProps> = (props) => {
|
||||
const { urlAuth } = props;
|
||||
@ -1,20 +1,20 @@
|
||||
import React, {
|
||||
memo, useCallback, useEffect, useState,
|
||||
} from '../../lib/teact/teact';
|
||||
import { getActions, getGlobal } from '../../global';
|
||||
} from '../../../lib/teact/teact';
|
||||
import { getActions, getGlobal } from '../../../global';
|
||||
|
||||
import type { FC } from '../../lib/teact/teact';
|
||||
import type { TabState } from '../../global/types';
|
||||
import type { FC } from '../../../lib/teact/teact';
|
||||
import type { TabState } from '../../../global/types';
|
||||
|
||||
import { ensureProtocol } from '../../util/ensureProtocol';
|
||||
import renderText from '../common/helpers/renderText';
|
||||
import { getUserFullName } from '../../global/helpers';
|
||||
import { ensureProtocol } from '../../../util/ensureProtocol';
|
||||
import renderText from '../../common/helpers/renderText';
|
||||
import { getUserFullName } from '../../../global/helpers';
|
||||
|
||||
import useLang from '../../hooks/useLang';
|
||||
import useCurrentOrPrev from '../../hooks/useCurrentOrPrev';
|
||||
import useLang from '../../../hooks/useLang';
|
||||
import useCurrentOrPrev from '../../../hooks/useCurrentOrPrev';
|
||||
|
||||
import ConfirmDialog from '../ui/ConfirmDialog';
|
||||
import Checkbox from '../ui/Checkbox';
|
||||
import ConfirmDialog from '../../ui/ConfirmDialog';
|
||||
import Checkbox from '../../ui/Checkbox';
|
||||
|
||||
import styles from './UrlAuthModal.module.scss';
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import type { FC } from '../../lib/teact/teact';
|
||||
import React from '../../lib/teact/teact';
|
||||
import { Bundles } from '../../util/moduleLoader';
|
||||
import type { FC } from '../../../lib/teact/teact';
|
||||
import React from '../../../lib/teact/teact';
|
||||
import { Bundles } from '../../../util/moduleLoader';
|
||||
|
||||
import type { OwnProps } from './WebAppModal';
|
||||
|
||||
import useModuleLoader from '../../hooks/useModuleLoader';
|
||||
import useModuleLoader from '../../../hooks/useModuleLoader';
|
||||
|
||||
const WebAppModalAsync: FC<OwnProps> = (props) => {
|
||||
const { webApp } = props;
|
||||
@ -1,36 +1,39 @@
|
||||
import React, {
|
||||
memo, useCallback, useEffect, useMemo, useRef, useState,
|
||||
} from '../../lib/teact/teact';
|
||||
import { getActions, withGlobal } from '../../global';
|
||||
memo, useEffect, useMemo, useRef, useState,
|
||||
} from '../../../lib/teact/teact';
|
||||
import { getActions, withGlobal } from '../../../global';
|
||||
|
||||
import type { FC } from '../../lib/teact/teact';
|
||||
import type { ApiAttachBot, ApiChat, ApiUser } from '../../api/types';
|
||||
import type { TabState } from '../../global/types';
|
||||
import type { ThemeKey } from '../../types';
|
||||
import type { PopupOptions, WebAppInboundEvent } from './hooks/useWebAppFrame';
|
||||
import type { FC } from '../../../lib/teact/teact';
|
||||
import type { ApiAttachBot, ApiChat, ApiUser } from '../../../api/types';
|
||||
import type { TabState } from '../../../global/types';
|
||||
import type { ThemeKey } from '../../../types';
|
||||
import type { PopupOptions, WebAppInboundEvent } from '../../../types/webapp';
|
||||
|
||||
import { TME_LINK_PREFIX } from '../../config';
|
||||
import { callApi } from '../../../api/gramjs';
|
||||
import { TME_LINK_PREFIX } from '../../../config';
|
||||
import {
|
||||
selectCurrentChat, selectTabState, selectTheme, selectUser,
|
||||
} from '../../global/selectors';
|
||||
import buildClassName from '../../util/buildClassName';
|
||||
import { extractCurrentThemeParams, validateHexColor } from '../../util/themeStyle';
|
||||
import { convertToApiChatType } from '../../global/helpers';
|
||||
} from '../../../global/selectors';
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
import { extractCurrentThemeParams, validateHexColor } from '../../../util/themeStyle';
|
||||
import { convertToApiChatType } from '../../../global/helpers';
|
||||
|
||||
import useInterval from '../../hooks/useInterval';
|
||||
import useLang from '../../hooks/useLang';
|
||||
import useSyncEffect from '../../hooks/useSyncEffect';
|
||||
import useInterval from '../../../hooks/useInterval';
|
||||
import useLang from '../../../hooks/useLang';
|
||||
import useSyncEffect from '../../../hooks/useSyncEffect';
|
||||
import useWebAppFrame from './hooks/useWebAppFrame';
|
||||
import usePrevious from '../../hooks/usePrevious';
|
||||
import useFlag from '../../hooks/useFlag';
|
||||
import useAppLayout from '../../hooks/useAppLayout';
|
||||
import usePrevious from '../../../hooks/usePrevious';
|
||||
import useFlag from '../../../hooks/useFlag';
|
||||
import useAppLayout from '../../../hooks/useAppLayout';
|
||||
import useLastCallback from '../../../hooks/useLastCallback';
|
||||
import usePopupLimit from './hooks/usePopupLimit';
|
||||
|
||||
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 ConfirmDialog from '../ui/ConfirmDialog';
|
||||
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 ConfirmDialog from '../../ui/ConfirmDialog';
|
||||
|
||||
import styles from './WebAppModal.module.scss';
|
||||
|
||||
@ -61,6 +64,8 @@ const NBSP = '\u00A0';
|
||||
const MAIN_BUTTON_ANIMATION_TIME = 250;
|
||||
const PROLONG_INTERVAL = 45000; // 45s
|
||||
const ANIMATION_WAIT = 400;
|
||||
const POPUP_SEQUENTIAL_LIMIT = 3;
|
||||
const POPUP_RESET_DELAY = 2000; // 2s
|
||||
const SANDBOX_ATTRIBUTES = [
|
||||
'allow-scripts',
|
||||
'allow-same-origin',
|
||||
@ -92,22 +97,29 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
|
||||
toggleAttachBot,
|
||||
openTelegramLink,
|
||||
openChat,
|
||||
openInvoice,
|
||||
setWebAppPaymentSlug,
|
||||
showNotification,
|
||||
switchBotInline,
|
||||
sharePhoneWithBot,
|
||||
} = getActions();
|
||||
const [mainButton, setMainButton] = useState<WebAppButton | undefined>();
|
||||
const [isBackButtonVisible, setIsBackButtonVisible] = useState(false);
|
||||
|
||||
const [backgroundColor, setBackgroundColor] = useState<string>();
|
||||
const [headerColor, setHeaderColor] = useState<string>();
|
||||
const [confirmClose, setConfirmClose] = useState(false);
|
||||
const [isCloseModalOpen, openCloseModal, closeModal] = useFlag(false);
|
||||
|
||||
const [shouldConfirmClosing, setShouldConfirmClosing] = useState(false);
|
||||
const [isCloseModalOpen, openCloseModal, hideCloseModal] = useFlag(false);
|
||||
|
||||
const [isLoaded, markLoaded, markUnloaded] = useFlag(false);
|
||||
const [popupParams, setPopupParams] = useState<PopupOptions | undefined>();
|
||||
|
||||
const [popupParameters, setPopupParameters] = useState<PopupOptions | undefined>();
|
||||
const [isRequestingPhone, setIsRequestingPhone] = useState(false);
|
||||
const [isRequesingWriteAccess, setIsRequestingWriteAccess] = useState(false);
|
||||
const {
|
||||
unlockPopupsAt, handlePopupOpened, handlePopupClosed,
|
||||
} = usePopupLimit(POPUP_SEQUENTIAL_LIMIT, POPUP_RESET_DELAY);
|
||||
|
||||
const { isMobile } = useAppLayout();
|
||||
const prevPopupParams = usePrevious(popupParams);
|
||||
const renderingPopupParams = popupParams || prevPopupParams;
|
||||
|
||||
useEffect(() => {
|
||||
const themeParams = extractCurrentThemeParams();
|
||||
@ -125,32 +137,224 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
|
||||
const isOpen = Boolean(url);
|
||||
const isSimple = Boolean(buttonText);
|
||||
|
||||
const handleEvent = useCallback((event: WebAppInboundEvent) => {
|
||||
const { eventType, eventData } = event;
|
||||
if (eventType === 'web_app_close') {
|
||||
const {
|
||||
reloadFrame, sendEvent, sendViewport, sendTheme,
|
||||
} = useWebAppFrame(frameRef, isOpen, isSimple, handleEvent, markLoaded);
|
||||
|
||||
const shouldShowMainButton = mainButton?.isVisible && mainButton.text.trim().length > 0;
|
||||
|
||||
useInterval(() => {
|
||||
prolongWebView({
|
||||
botId: bot!.id,
|
||||
queryId: queryId!,
|
||||
peerId: chat!.id,
|
||||
replyToMessageId,
|
||||
threadId,
|
||||
});
|
||||
}, queryId ? PROLONG_INTERVAL : undefined, true);
|
||||
|
||||
const handleMainButtonClick = useLastCallback(() => {
|
||||
sendEvent({
|
||||
eventType: 'main_button_pressed',
|
||||
});
|
||||
});
|
||||
|
||||
const handleSettingsButtonClick = useLastCallback(() => {
|
||||
sendEvent({
|
||||
eventType: 'settings_button_pressed',
|
||||
});
|
||||
});
|
||||
|
||||
const handleRefreshClick = useLastCallback(() => {
|
||||
reloadFrame(webApp!.url);
|
||||
});
|
||||
|
||||
const handleClose = useLastCallback(() => {
|
||||
if (shouldConfirmClosing) {
|
||||
openCloseModal();
|
||||
} else {
|
||||
closeWebApp();
|
||||
}
|
||||
});
|
||||
|
||||
if (eventType === 'web_app_open_invoice') {
|
||||
setWebAppPaymentSlug({
|
||||
slug: eventData.slug,
|
||||
const handleAppPopupClose = useLastCallback((buttonId?: string) => {
|
||||
setPopupParameters(undefined);
|
||||
handlePopupClosed();
|
||||
sendEvent({
|
||||
eventType: 'popup_closed',
|
||||
eventData: {
|
||||
button_id: buttonId,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
const handleAppPopupModalClose = useLastCallback(() => {
|
||||
handleAppPopupClose();
|
||||
});
|
||||
|
||||
// Notify view that height changed
|
||||
useSyncEffect(() => {
|
||||
setTimeout(() => {
|
||||
sendViewport();
|
||||
}, ANIMATION_WAIT);
|
||||
}, [mainButton?.isVisible, sendViewport]);
|
||||
|
||||
// Notify view that theme changed
|
||||
useSyncEffect(() => {
|
||||
setTimeout(() => {
|
||||
sendTheme();
|
||||
}, ANIMATION_WAIT);
|
||||
}, [theme, sendTheme]);
|
||||
|
||||
useSyncEffect(([prevIsPaymentModalOpen]) => {
|
||||
if (isPaymentModalOpen === prevIsPaymentModalOpen) return;
|
||||
if (webApp?.slug && !isPaymentModalOpen && paymentStatus) {
|
||||
sendEvent({
|
||||
eventType: 'invoice_closed',
|
||||
eventData: {
|
||||
slug: webApp.slug,
|
||||
status: paymentStatus,
|
||||
},
|
||||
});
|
||||
openInvoice({
|
||||
slug: eventData.slug,
|
||||
setWebAppPaymentSlug({
|
||||
slug: undefined,
|
||||
});
|
||||
}
|
||||
}, [isPaymentModalOpen, paymentStatus, sendEvent, setWebAppPaymentSlug, webApp]);
|
||||
|
||||
const handleToggleClick = useLastCallback(() => {
|
||||
toggleAttachBot({
|
||||
botId: bot!.id,
|
||||
isEnabled: !attachBot,
|
||||
});
|
||||
});
|
||||
|
||||
const handleBackClick = useLastCallback(() => {
|
||||
if (isBackButtonVisible) {
|
||||
sendEvent({
|
||||
eventType: 'back_button_pressed',
|
||||
});
|
||||
} else {
|
||||
handleClose();
|
||||
}
|
||||
});
|
||||
|
||||
const handleRejectPhone = useLastCallback(() => {
|
||||
setIsRequestingPhone(false);
|
||||
handlePopupClosed();
|
||||
sendEvent({
|
||||
eventType: 'phone_requested',
|
||||
eventData: {
|
||||
status: 'cancelled',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
const handleAcceptPhone = useLastCallback(() => {
|
||||
sharePhoneWithBot({ botId: bot!.id });
|
||||
setIsRequestingPhone(false);
|
||||
handlePopupClosed();
|
||||
sendEvent({
|
||||
eventType: 'phone_requested',
|
||||
eventData: {
|
||||
status: 'sent',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
const handleRejectWriteAccess = useLastCallback(() => {
|
||||
sendEvent({
|
||||
eventType: 'write_access_requested',
|
||||
eventData: {
|
||||
status: 'cancelled',
|
||||
},
|
||||
});
|
||||
setIsRequestingWriteAccess(false);
|
||||
handlePopupClosed();
|
||||
});
|
||||
|
||||
const handleAcceptWriteAccess = useLastCallback(async () => {
|
||||
const result = await callApi('allowBotSendMessages', { bot: bot! });
|
||||
if (!result) {
|
||||
handleRejectWriteAccess();
|
||||
return;
|
||||
}
|
||||
|
||||
sendEvent({
|
||||
eventType: 'write_access_requested',
|
||||
eventData: {
|
||||
status: 'allowed',
|
||||
},
|
||||
});
|
||||
setIsRequestingWriteAccess(false);
|
||||
handlePopupClosed();
|
||||
});
|
||||
|
||||
async function handleRequestWriteAccess() {
|
||||
const canWrite = await callApi('fetchBotCanSendMessage', {
|
||||
bot: bot!,
|
||||
});
|
||||
|
||||
if (canWrite) {
|
||||
sendEvent({
|
||||
eventType: 'write_access_requested',
|
||||
eventData: {
|
||||
status: 'allowed',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
setIsRequestingWriteAccess(!canWrite);
|
||||
}
|
||||
|
||||
async function handleInvokeCustomMethod(requestId: string, method: string, parameters: string) {
|
||||
const result = await callApi('invokeWebViewCustomMethod', {
|
||||
bot: bot!,
|
||||
customMethod: method,
|
||||
parameters,
|
||||
});
|
||||
|
||||
sendEvent({
|
||||
eventType: 'custom_method_invoked',
|
||||
eventData: {
|
||||
req_id: requestId,
|
||||
...result,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const openBotChat = useLastCallback(() => {
|
||||
openChat({
|
||||
id: bot!.id,
|
||||
});
|
||||
closeWebApp();
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!isOpen) {
|
||||
const themeParams = extractCurrentThemeParams();
|
||||
|
||||
setShouldConfirmClosing(false);
|
||||
hideCloseModal();
|
||||
setPopupParameters(undefined);
|
||||
setIsRequestingPhone(false);
|
||||
setIsRequestingWriteAccess(false);
|
||||
setMainButton(undefined);
|
||||
setIsBackButtonVisible(false);
|
||||
setBackgroundColor(themeParams.bg_color);
|
||||
setHeaderColor(themeParams.bg_color);
|
||||
markUnloaded();
|
||||
}
|
||||
}, [hideCloseModal, isOpen, markUnloaded]);
|
||||
|
||||
function handleEvent(event: WebAppInboundEvent) {
|
||||
const { eventType, eventData } = event;
|
||||
if (eventType === 'web_app_open_tg_link' && !isPaymentModalOpen) {
|
||||
const linkUrl = TME_LINK_PREFIX + eventData.path_full;
|
||||
openTelegramLink({ url: linkUrl });
|
||||
closeWebApp();
|
||||
}
|
||||
|
||||
if (eventType === 'web_app_open_link') {
|
||||
const linkUrl = eventData.url;
|
||||
window.open(linkUrl, '_blank', 'noreferrer');
|
||||
}
|
||||
|
||||
if (eventType === 'web_app_setup_back_button') {
|
||||
setIsBackButtonVisible(eventData.is_visible);
|
||||
}
|
||||
@ -193,18 +397,19 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
|
||||
}
|
||||
|
||||
if (eventType === 'web_app_setup_closing_behavior') {
|
||||
setConfirmClose(eventData.need_confirmation);
|
||||
setShouldConfirmClosing(eventData.need_confirmation);
|
||||
}
|
||||
|
||||
if (eventType === 'web_app_open_popup') {
|
||||
if (!eventData.message.trim().length || !eventData.buttons?.length || eventData.buttons.length > 3) return;
|
||||
setPopupParams(eventData);
|
||||
}
|
||||
if (popupParameters || !eventData.message.trim().length || !eventData.buttons?.length
|
||||
|| eventData.buttons.length > 3 || isRequestingPhone || isRequesingWriteAccess
|
||||
|| unlockPopupsAt > Date.now()) {
|
||||
handleAppPopupClose(undefined);
|
||||
return;
|
||||
}
|
||||
|
||||
if (eventType === 'web_app_open_scan_qr_popup') {
|
||||
showNotification({
|
||||
message: 'Scan QR code is not supported in this client yet',
|
||||
});
|
||||
setPopupParameters(eventData);
|
||||
handlePopupOpened();
|
||||
}
|
||||
|
||||
if (eventType === 'web_app_switch_inline_query') {
|
||||
@ -220,127 +425,32 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
|
||||
|
||||
closeWebApp();
|
||||
}
|
||||
}, [
|
||||
bot, buttonText, closeWebApp, openInvoice, openTelegramLink, sendWebViewData, setWebAppPaymentSlug,
|
||||
isPaymentModalOpen, showNotification,
|
||||
]);
|
||||
|
||||
const {
|
||||
reloadFrame, sendEvent, sendViewport, sendTheme,
|
||||
} = useWebAppFrame(frameRef, isOpen, isSimple, handleEvent, markLoaded);
|
||||
if (eventType === 'web_app_request_phone') {
|
||||
if (popupParameters || isRequesingWriteAccess || unlockPopupsAt > Date.now()) {
|
||||
handleRejectPhone();
|
||||
return;
|
||||
}
|
||||
|
||||
const shouldShowMainButton = mainButton?.isVisible && mainButton.text.trim().length > 0;
|
||||
|
||||
useInterval(() => {
|
||||
prolongWebView({
|
||||
botId: bot!.id,
|
||||
queryId: queryId!,
|
||||
peerId: chat!.id,
|
||||
replyToMessageId,
|
||||
threadId,
|
||||
});
|
||||
}, queryId ? PROLONG_INTERVAL : undefined, true);
|
||||
|
||||
const handleMainButtonClick = useCallback(() => {
|
||||
sendEvent({
|
||||
eventType: 'main_button_pressed',
|
||||
});
|
||||
}, [sendEvent]);
|
||||
|
||||
const handleSettingsButtonClick = useCallback(() => {
|
||||
sendEvent({
|
||||
eventType: 'settings_button_pressed',
|
||||
});
|
||||
}, [sendEvent]);
|
||||
|
||||
const handleRefreshClick = useCallback(() => {
|
||||
reloadFrame(webApp!.url);
|
||||
}, [reloadFrame, webApp]);
|
||||
|
||||
const handleClose = useCallback(() => {
|
||||
if (confirmClose) {
|
||||
openCloseModal();
|
||||
} else {
|
||||
closeWebApp();
|
||||
setIsRequestingPhone(true);
|
||||
handlePopupOpened();
|
||||
}
|
||||
}, [confirmClose, openCloseModal, closeWebApp]);
|
||||
|
||||
const handlePopupClose = useCallback((buttonId?: string) => {
|
||||
setPopupParams(undefined);
|
||||
sendEvent({
|
||||
eventType: 'popup_closed',
|
||||
eventData: {
|
||||
button_id: buttonId,
|
||||
},
|
||||
});
|
||||
}, [sendEvent]);
|
||||
if (eventType === 'web_app_request_write_access') {
|
||||
if (popupParameters || isRequestingPhone || unlockPopupsAt > Date.now()) {
|
||||
handleRejectWriteAccess();
|
||||
return;
|
||||
}
|
||||
|
||||
const handlePopupModalClose = useCallback(() => {
|
||||
handlePopupClose();
|
||||
}, [handlePopupClose]);
|
||||
|
||||
// Notify view that height changed
|
||||
useSyncEffect(() => {
|
||||
setTimeout(() => {
|
||||
sendViewport();
|
||||
}, ANIMATION_WAIT);
|
||||
}, [mainButton?.isVisible, sendViewport]);
|
||||
|
||||
// Notify view that theme changed
|
||||
useSyncEffect(() => {
|
||||
setTimeout(() => {
|
||||
sendTheme();
|
||||
}, ANIMATION_WAIT);
|
||||
}, [theme, sendTheme]);
|
||||
|
||||
useSyncEffect(([prevIsPaymentModalOpen]) => {
|
||||
if (isPaymentModalOpen === prevIsPaymentModalOpen) return;
|
||||
if (webApp?.slug && !isPaymentModalOpen && paymentStatus) {
|
||||
sendEvent({
|
||||
eventType: 'invoice_closed',
|
||||
eventData: {
|
||||
slug: webApp.slug,
|
||||
status: paymentStatus,
|
||||
},
|
||||
});
|
||||
setWebAppPaymentSlug({
|
||||
slug: undefined,
|
||||
});
|
||||
handleRequestWriteAccess();
|
||||
handlePopupOpened();
|
||||
}
|
||||
}, [isPaymentModalOpen, paymentStatus, sendEvent, setWebAppPaymentSlug, webApp]);
|
||||
|
||||
const handleToggleClick = useCallback(() => {
|
||||
toggleAttachBot({
|
||||
botId: bot!.id,
|
||||
isEnabled: !attachBot,
|
||||
});
|
||||
}, [bot, attachBot, toggleAttachBot]);
|
||||
|
||||
const handleBackClick = useCallback(() => {
|
||||
if (isBackButtonVisible) {
|
||||
sendEvent({
|
||||
eventType: 'back_button_pressed',
|
||||
});
|
||||
} else {
|
||||
handleClose();
|
||||
if (eventType === 'web_app_invoke_custom_method') {
|
||||
const { method, params, req_id: requestId } = eventData;
|
||||
handleInvokeCustomMethod(requestId, method, JSON.stringify(params));
|
||||
}
|
||||
}, [handleClose, isBackButtonVisible, sendEvent]);
|
||||
|
||||
const openBotChat = useCallback(() => {
|
||||
openChat({
|
||||
id: bot!.id,
|
||||
});
|
||||
closeWebApp();
|
||||
}, [bot, closeWebApp, openChat]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isOpen) {
|
||||
setConfirmClose(false);
|
||||
closeModal();
|
||||
setPopupParams(undefined);
|
||||
markUnloaded();
|
||||
}
|
||||
}, [closeModal, isOpen, markUnloaded]);
|
||||
}
|
||||
|
||||
const MoreMenuButton: FC<{ onTrigger: () => void; isOpen?: boolean }> = useMemo(() => {
|
||||
return ({ onTrigger, isOpen: isMenuOpen }) => (
|
||||
@ -414,16 +524,6 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
|
||||
const mainButtonCurrentIsActive = mainButton?.isActive !== undefined ? mainButton.isActive : prevMainButtonIsActive;
|
||||
const mainButtonCurrentText = mainButton?.text || prevMainButtonText;
|
||||
|
||||
useEffect(() => {
|
||||
if (!isOpen) {
|
||||
const themeParams = extractCurrentThemeParams();
|
||||
setMainButton(undefined);
|
||||
setIsBackButtonVisible(false);
|
||||
setBackgroundColor(themeParams.bg_color);
|
||||
setHeaderColor(themeParams.bg_color);
|
||||
}
|
||||
}, [isOpen]);
|
||||
|
||||
const [shouldDecreaseWebFrameSize, setShouldDecreaseWebFrameSize] = useState(false);
|
||||
const [shouldHideButton, setShouldHideButton] = useState(true);
|
||||
|
||||
@ -479,30 +579,35 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
{confirmClose && (
|
||||
<ConfirmDialog
|
||||
isOpen={isCloseModalOpen}
|
||||
onClose={closeModal}
|
||||
title={lang('lng_bot_close_warning_title')}
|
||||
text={lang('lng_bot_close_warning')}
|
||||
confirmHandler={closeWebApp}
|
||||
confirmIsDestructive
|
||||
confirmLabel={lang('lng_bot_close_warning_sure')}
|
||||
/>
|
||||
)}
|
||||
{renderingPopupParams && (
|
||||
<ConfirmDialog
|
||||
isOpen={isRequestingPhone}
|
||||
onClose={handleRejectPhone}
|
||||
title={lang('ShareYouPhoneNumberTitle')}
|
||||
text={lang('AreYouSureShareMyContactInfoBot')}
|
||||
confirmHandler={handleAcceptPhone}
|
||||
confirmLabel={lang('ContactShare')}
|
||||
/>
|
||||
<ConfirmDialog
|
||||
isOpen={isRequesingWriteAccess}
|
||||
onClose={handleRejectWriteAccess}
|
||||
title={lang('lng_bot_allow_write_title')}
|
||||
text={lang('lng_bot_allow_write')}
|
||||
confirmHandler={handleAcceptWriteAccess}
|
||||
confirmLabel={lang('lng_bot_allow_write_confirm')}
|
||||
/>
|
||||
{popupParameters && (
|
||||
<Modal
|
||||
isOpen={Boolean(popupParams)}
|
||||
title={renderingPopupParams.title || NBSP}
|
||||
onClose={handlePopupModalClose}
|
||||
isOpen={Boolean(popupParameters)}
|
||||
title={popupParameters.title || NBSP}
|
||||
onClose={handleAppPopupModalClose}
|
||||
hasCloseButton
|
||||
className={
|
||||
buildClassName(styles.webAppPopup, !renderingPopupParams.title?.trim().length && styles.withoutTitle)
|
||||
buildClassName(styles.webAppPopup, !popupParameters.title?.trim().length && styles.withoutTitle)
|
||||
}
|
||||
>
|
||||
{renderingPopupParams.message}
|
||||
{popupParameters.message}
|
||||
<div className="dialog-buttons mt-2">
|
||||
{renderingPopupParams.buttons.map((button) => (
|
||||
{popupParameters.buttons.map((button) => (
|
||||
<Button
|
||||
key={button.id || button.type}
|
||||
className="confirm-dialog-button"
|
||||
@ -510,7 +615,7 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
|
||||
isText
|
||||
size="smaller"
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={() => handlePopupClose(button.id)}
|
||||
onClick={() => handleAppPopupClose(button.id)}
|
||||
>
|
||||
{button.text || lang(DEFAULT_BUTTON_TEXT[button.type])}
|
||||
</Button>
|
||||
@ -518,6 +623,16 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
|
||||
</div>
|
||||
</Modal>
|
||||
)}
|
||||
|
||||
<ConfirmDialog
|
||||
isOpen={isCloseModalOpen}
|
||||
onClose={hideCloseModal}
|
||||
title={lang('lng_bot_close_warning_title')}
|
||||
text={lang('lng_bot_close_warning')}
|
||||
confirmHandler={closeWebApp}
|
||||
confirmIsDestructive
|
||||
confirmLabel={lang('lng_bot_close_warning_sure')}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
34
src/components/modals/webApp/hooks/usePopupLimit.ts
Normal file
34
src/components/modals/webApp/hooks/usePopupLimit.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { useRef, useState } from '../../../../lib/teact/teact';
|
||||
import useLastCallback from '../../../../hooks/useLastCallback';
|
||||
|
||||
export default function usePopupLimit(sequentialLimit: number, resetAfter: number) {
|
||||
const [unlockPopupsAt, setUnlockPopupsAt] = useState(0);
|
||||
const sequentialCalls = useRef(0);
|
||||
const lastClosedDate = useRef(0);
|
||||
|
||||
const handlePopupOpened = useLastCallback(() => {
|
||||
const now = Date.now();
|
||||
|
||||
if (now - lastClosedDate.current > resetAfter) {
|
||||
sequentialCalls.current = 0;
|
||||
}
|
||||
|
||||
sequentialCalls.current += 1;
|
||||
|
||||
if (sequentialCalls.current >= sequentialLimit) {
|
||||
setUnlockPopupsAt(now + resetAfter);
|
||||
}
|
||||
});
|
||||
|
||||
const handlePopupClosed = useLastCallback(() => {
|
||||
if (unlockPopupsAt < Date.now()) { // Prevent confused user from extending lock time
|
||||
lastClosedDate.current = Date.now();
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
unlockPopupsAt,
|
||||
handlePopupOpened,
|
||||
handlePopupClosed,
|
||||
};
|
||||
}
|
||||
@ -1,155 +1,11 @@
|
||||
import { useCallback, useEffect, useRef } from '../../../lib/teact/teact';
|
||||
import { getActions } from '../../../lib/teact/teactn';
|
||||
import { extractCurrentThemeParams } from '../../../util/themeStyle';
|
||||
import useWindowSize from '../../../hooks/useWindowSize';
|
||||
import { useCallback, useEffect, useRef } from '../../../../lib/teact/teact';
|
||||
import { getActions } from '../../../../global';
|
||||
|
||||
export type PopupOptions = {
|
||||
title: string;
|
||||
message: string;
|
||||
buttons: {
|
||||
id: string;
|
||||
type: 'default' | 'ok' | 'close' | 'cancel' | 'destructive';
|
||||
text: string;
|
||||
}[];
|
||||
};
|
||||
import type { WebAppInboundEvent, WebAppOutboundEvent } from '../../../../types/webapp';
|
||||
|
||||
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_setup_back_button';
|
||||
eventData: {
|
||||
is_visible: boolean;
|
||||
};
|
||||
} | {
|
||||
eventType: 'web_app_open_link';
|
||||
eventData: {
|
||||
url: string;
|
||||
try_instant_view?: boolean;
|
||||
};
|
||||
} | {
|
||||
eventType: 'web_app_open_tg_link';
|
||||
eventData: {
|
||||
path_full: string;
|
||||
};
|
||||
} | {
|
||||
eventType: 'web_app_open_invoice';
|
||||
eventData: {
|
||||
slug: string;
|
||||
};
|
||||
} | {
|
||||
eventType: 'web_app_trigger_haptic_feedback';
|
||||
eventData: {
|
||||
type: 'impact' | 'notification' | 'selection_change';
|
||||
impact_style?: 'light' | 'medium' | 'heavy';
|
||||
notification_type?: 'error' | 'success' | 'warning';
|
||||
};
|
||||
} | {
|
||||
eventType: 'web_app_set_background_color';
|
||||
eventData: {
|
||||
color: string;
|
||||
};
|
||||
} | {
|
||||
eventType: 'web_app_set_header_color';
|
||||
eventData: {
|
||||
color_key: 'bg_color' | 'secondary_bg_color';
|
||||
};
|
||||
} | {
|
||||
eventType: 'web_app_open_popup';
|
||||
eventData: PopupOptions;
|
||||
} | {
|
||||
eventType: 'web_app_setup_closing_behavior';
|
||||
eventData: {
|
||||
need_confirmation: boolean;
|
||||
};
|
||||
} | {
|
||||
eventType: 'web_app_open_scan_qr_popup';
|
||||
eventData: {
|
||||
text?: string;
|
||||
};
|
||||
} | {
|
||||
eventType: 'web_app_read_text_from_clipboard';
|
||||
eventData: {
|
||||
req_id: string;
|
||||
};
|
||||
} | {
|
||||
eventType: 'web_app_switch_inline_query';
|
||||
eventData: {
|
||||
query: string;
|
||||
chat_types: ('users' | 'bots' | 'groups' | 'channels')[];
|
||||
};
|
||||
} | {
|
||||
eventType: 'web_app_request_viewport' | 'web_app_request_theme' | 'web_app_ready' | 'web_app_expand'
|
||||
| 'web_app_request_phone' | 'web_app_close' | 'iframe_ready' | 'web_app_close_scan_qr_popup';
|
||||
eventData: null;
|
||||
};
|
||||
import { extractCurrentThemeParams } from '../../../../util/themeStyle';
|
||||
|
||||
type WebAppOutboundEvent = {
|
||||
eventType: 'viewport_changed';
|
||||
eventData: {
|
||||
height: number;
|
||||
width?: number;
|
||||
is_expanded?: boolean;
|
||||
is_state_stable?: 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;
|
||||
secondary_bg_color: string;
|
||||
};
|
||||
};
|
||||
} | {
|
||||
eventType: 'set_custom_style';
|
||||
eventData: string;
|
||||
} | {
|
||||
eventType: 'invoice_closed';
|
||||
eventData: {
|
||||
slug: string;
|
||||
status: 'paid' | 'cancelled' | 'pending' | 'failed';
|
||||
};
|
||||
} | {
|
||||
eventType: 'phone_requested';
|
||||
eventData: {
|
||||
phone_number: string;
|
||||
};
|
||||
} | {
|
||||
eventType: 'popup_closed';
|
||||
eventData: {
|
||||
button_id?: string;
|
||||
};
|
||||
} | {
|
||||
eventType: 'qr_text_received';
|
||||
eventData: {
|
||||
data: string;
|
||||
};
|
||||
} | {
|
||||
eventType: 'clipboard_text_received';
|
||||
eventData: {
|
||||
req_id: string;
|
||||
data: string | null;
|
||||
};
|
||||
} | {
|
||||
eventType: 'main_button_pressed' | 'back_button_pressed' | 'settings_button_pressed' | 'scan_qr_popup_closed';
|
||||
};
|
||||
import useWindowSize from '../../../../hooks/useWindowSize';
|
||||
|
||||
const SCROLLBAR_STYLE = `* {
|
||||
scrollbar-width: thin;
|
||||
@ -180,6 +36,9 @@ const useWebAppFrame = (
|
||||
) => {
|
||||
const {
|
||||
showNotification,
|
||||
setWebAppPaymentSlug,
|
||||
openInvoice,
|
||||
closeWebApp,
|
||||
} = getActions();
|
||||
|
||||
const ignoreEventsRef = useRef<boolean>(false);
|
||||
@ -253,34 +112,40 @@ const useWebAppFrame = (
|
||||
|
||||
try {
|
||||
const data = JSON.parse(event.data) as WebAppInboundEvent;
|
||||
const { eventType, eventData } = data;
|
||||
// Handle some app requests here to simplify hook usage
|
||||
if (data.eventType === 'web_app_ready') {
|
||||
if (eventType === 'web_app_ready') {
|
||||
onLoad?.();
|
||||
}
|
||||
|
||||
if (data.eventType === 'web_app_request_viewport') {
|
||||
if (eventType === 'web_app_close') {
|
||||
closeWebApp();
|
||||
}
|
||||
|
||||
if (eventType === 'web_app_request_viewport') {
|
||||
sendViewport(windowSize.isResizing);
|
||||
}
|
||||
|
||||
if (data.eventType === 'web_app_request_theme') {
|
||||
if (eventType === 'web_app_request_theme') {
|
||||
sendTheme();
|
||||
}
|
||||
|
||||
if (data.eventType === 'iframe_ready') {
|
||||
if (eventType === 'iframe_ready') {
|
||||
const scrollbarColor = getComputedStyle(document.body).getPropertyValue('--color-scrollbar');
|
||||
sendCustomStyle(SCROLLBAR_STYLE.replace(/%SCROLLBAR_COLOR%/g, scrollbarColor));
|
||||
}
|
||||
|
||||
if (data.eventType === 'web_app_data_send') {
|
||||
if (eventType === 'web_app_data_send') {
|
||||
if (!isSimpleView) return; // Allowed only in simple view
|
||||
ignoreEventsRef.current = true;
|
||||
}
|
||||
|
||||
if (data.eventType === 'web_app_read_text_from_clipboard') {
|
||||
// Clipboard access temporarily disabled to address security concerns
|
||||
if (eventType === 'web_app_read_text_from_clipboard') {
|
||||
sendEvent({
|
||||
eventType: 'clipboard_text_received',
|
||||
eventData: {
|
||||
req_id: data.eventData.req_id,
|
||||
req_id: eventData.req_id,
|
||||
// eslint-disable-next-line no-null/no-null
|
||||
data: null,
|
||||
},
|
||||
@ -290,6 +155,27 @@ const useWebAppFrame = (
|
||||
message: 'Clipboard access is not supported in this client yet',
|
||||
});
|
||||
}
|
||||
|
||||
if (eventType === 'web_app_open_scan_qr_popup') {
|
||||
showNotification({
|
||||
message: 'Scanning QR code is not supported in this client yet',
|
||||
});
|
||||
}
|
||||
|
||||
if (eventType === 'web_app_open_invoice') {
|
||||
setWebAppPaymentSlug({
|
||||
slug: eventData.slug,
|
||||
});
|
||||
openInvoice({
|
||||
slug: eventData.slug,
|
||||
});
|
||||
}
|
||||
|
||||
if (eventType === 'web_app_open_link') {
|
||||
const linkUrl = eventData.url;
|
||||
window.open(linkUrl, '_blank', 'noreferrer');
|
||||
}
|
||||
|
||||
onEvent(data);
|
||||
} catch (err) {
|
||||
// Ignore other messages
|
||||
@ -49,7 +49,7 @@ export const CUSTOM_EMOJI_PREVIEW_CACHE_DISABLED = false;
|
||||
export const CUSTOM_EMOJI_PREVIEW_CACHE_NAME = 'tt-custom-emoji-preview';
|
||||
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-v21';
|
||||
export const LANG_CACHE_NAME = 'tt-lang-packs-v22';
|
||||
export const ASSET_CACHE_NAME = 'tt-assets';
|
||||
export const AUTODOWNLOAD_FILESIZE_MB_LIMITS = [1, 5, 10, 50, 100, 500];
|
||||
export const DATA_BROADCAST_CHANNEL_NAME = 'tt-global';
|
||||
|
||||
@ -417,6 +417,40 @@ addActionHandler('startBot', async (global, actions, payload): Promise<void> =>
|
||||
});
|
||||
});
|
||||
|
||||
addActionHandler('sharePhoneWithBot', async (global, actions, payload): Promise<void> => {
|
||||
const { botId } = payload;
|
||||
const bot = selectUser(global, botId);
|
||||
if (!bot) {
|
||||
return;
|
||||
}
|
||||
|
||||
let fullInfo = selectUserFullInfo(global, botId);
|
||||
if (!fullInfo) {
|
||||
const result = await callApi('fetchFullUser', { id: bot.id, accessHash: bot.accessHash });
|
||||
fullInfo = result?.fullInfo;
|
||||
}
|
||||
|
||||
if (fullInfo?.isBlocked) {
|
||||
await callApi('unblockUser', { user: bot });
|
||||
}
|
||||
|
||||
global = getGlobal();
|
||||
const chat = selectChat(global, botId);
|
||||
const currentUser = selectUser(global, global.currentUserId!)!;
|
||||
|
||||
if (!chat) return;
|
||||
|
||||
await callApi('sendMessage', {
|
||||
chat,
|
||||
contact: {
|
||||
firstName: currentUser.firstName || '',
|
||||
lastName: currentUser.lastName || '',
|
||||
phoneNumber: currentUser.phoneNumber || '',
|
||||
userId: currentUser.id,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
addActionHandler('requestSimpleWebView', async (global, actions, payload): Promise<void> => {
|
||||
const {
|
||||
url, botId, theme, buttonText,
|
||||
|
||||
@ -529,6 +529,7 @@ export type TabState = {
|
||||
slug?: string;
|
||||
replyToMessageId?: number;
|
||||
threadId?: number;
|
||||
canSendMessages?: boolean;
|
||||
};
|
||||
|
||||
botTrustRequest?: {
|
||||
@ -2304,6 +2305,9 @@ export interface ActionPayloads {
|
||||
restartBot: {
|
||||
chatId: string;
|
||||
} & WithTabId;
|
||||
sharePhoneWithBot: {
|
||||
botId: string;
|
||||
};
|
||||
|
||||
clickBotInlineButton: {
|
||||
messageId: number;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
const api = require('./api');
|
||||
|
||||
const LAYER = 161;
|
||||
const LAYER = 162;
|
||||
const tlobjects = {};
|
||||
|
||||
for (const tl of Object.values(api)) {
|
||||
|
||||
34
src/lib/gramjs/tl/api.d.ts
vendored
34
src/lib/gramjs/tl/api.d.ts
vendored
@ -1775,11 +1775,13 @@ namespace Api {
|
||||
export class MessageActionBotAllowed extends VirtualClass<{
|
||||
// flags: undefined;
|
||||
attachMenu?: true;
|
||||
fromRequest?: true;
|
||||
domain?: string;
|
||||
app?: Api.TypeBotApp;
|
||||
} | void> {
|
||||
// flags: undefined;
|
||||
attachMenu?: true;
|
||||
fromRequest?: true;
|
||||
domain?: string;
|
||||
app?: Api.TypeBotApp;
|
||||
};
|
||||
@ -4092,6 +4094,9 @@ namespace Api {
|
||||
public?: true;
|
||||
megagroup?: true;
|
||||
requestNeeded?: true;
|
||||
verified?: true;
|
||||
scam?: true;
|
||||
fake?: true;
|
||||
title: string;
|
||||
about?: string;
|
||||
photo: Api.TypePhoto;
|
||||
@ -4104,6 +4109,9 @@ namespace Api {
|
||||
public?: true;
|
||||
megagroup?: true;
|
||||
requestNeeded?: true;
|
||||
verified?: true;
|
||||
scam?: true;
|
||||
fake?: true;
|
||||
title: string;
|
||||
about?: string;
|
||||
photo: Api.TypePhoto;
|
||||
@ -8311,11 +8319,13 @@ namespace Api {
|
||||
};
|
||||
export class StoryViews extends VirtualClass<{
|
||||
// flags: undefined;
|
||||
hasViewers?: true;
|
||||
viewsCount: int;
|
||||
reactionsCount: int;
|
||||
recentViewers?: long[];
|
||||
}> {
|
||||
// flags: undefined;
|
||||
hasViewers?: true;
|
||||
viewsCount: int;
|
||||
reactionsCount: int;
|
||||
recentViewers?: long[];
|
||||
@ -14410,6 +14420,25 @@ namespace Api {
|
||||
username: string;
|
||||
active: Bool;
|
||||
};
|
||||
export class CanSendMessage extends Request<Partial<{
|
||||
bot: Api.TypeInputUser;
|
||||
}>, Bool> {
|
||||
bot: Api.TypeInputUser;
|
||||
};
|
||||
export class AllowSendMessage extends Request<Partial<{
|
||||
bot: Api.TypeInputUser;
|
||||
}>, Api.TypeUpdates> {
|
||||
bot: Api.TypeInputUser;
|
||||
};
|
||||
export class InvokeWebViewCustomMethod extends Request<Partial<{
|
||||
bot: Api.TypeInputUser;
|
||||
customMethod: string;
|
||||
params: Api.TypeDataJSON;
|
||||
}>, Api.TypeDataJSON> {
|
||||
bot: Api.TypeInputUser;
|
||||
customMethod: string;
|
||||
params: Api.TypeDataJSON;
|
||||
};
|
||||
}
|
||||
|
||||
export namespace payments {
|
||||
@ -15058,6 +15087,7 @@ namespace Api {
|
||||
}
|
||||
|
||||
export namespace stories {
|
||||
export class CanSendStory extends Request<void, Bool> {};
|
||||
export class SendStory extends Request<Partial<{
|
||||
// flags: undefined;
|
||||
pinned?: true;
|
||||
@ -15244,7 +15274,7 @@ namespace Api {
|
||||
| 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 | help.GetPremiumPromo
|
||||
| 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 | channels.ToggleJoinToSend | channels.ToggleJoinRequest | channels.ReorderUsernames | channels.ToggleUsername | channels.DeactivateAllUsernames | channels.ToggleForum | channels.CreateForumTopic | channels.GetForumTopics | channels.GetForumTopicsByID | channels.EditForumTopic | channels.UpdatePinnedForumTopic | channels.DeleteTopicHistory | channels.ReorderPinnedForumTopics | channels.ToggleAntiSpam | channels.ReportAntiSpamFalsePositive | channels.ToggleParticipantsHidden | channels.ClickSponsoredMessage
|
||||
| bots.SendCustomRequest | bots.AnswerWebhookJSONQuery | bots.SetBotCommands | bots.ResetBotCommands | bots.GetBotCommands | bots.SetBotMenuButton | bots.GetBotMenuButton | bots.SetBotBroadcastDefaultAdminRights | bots.SetBotGroupDefaultAdminRights | bots.SetBotInfo | bots.GetBotInfo | bots.ReorderUsernames | bots.ToggleUsername
|
||||
| bots.SendCustomRequest | bots.AnswerWebhookJSONQuery | bots.SetBotCommands | bots.ResetBotCommands | bots.GetBotCommands | bots.SetBotMenuButton | bots.GetBotMenuButton | bots.SetBotBroadcastDefaultAdminRights | bots.SetBotGroupDefaultAdminRights | bots.SetBotInfo | bots.GetBotInfo | bots.ReorderUsernames | bots.ToggleUsername | bots.CanSendMessage | bots.AllowSendMessage | bots.InvokeWebViewCustomMethod
|
||||
| payments.GetPaymentForm | payments.GetPaymentReceipt | payments.ValidateRequestedInfo | payments.SendPaymentForm | payments.GetSavedInfo | payments.ClearSavedInfo | payments.GetBankCardData | payments.ExportInvoice | payments.AssignAppStoreTransaction | payments.AssignPlayMarketTransaction | payments.CanPurchasePremium
|
||||
| stickers.CreateStickerSet | stickers.RemoveStickerFromSet | stickers.ChangeStickerPosition | stickers.AddStickerToSet | stickers.SetStickerSetThumb | stickers.CheckShortName | stickers.SuggestShortName | stickers.ChangeSticker | stickers.RenameStickerSet | stickers.DeleteStickerSet
|
||||
| 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 | phone.SaveCallLog
|
||||
@ -15252,6 +15282,6 @@ namespace Api {
|
||||
| folders.EditPeerFolders
|
||||
| stats.GetBroadcastStats | stats.LoadAsyncGraph | stats.GetMegagroupStats | stats.GetMessagePublicForwards | stats.GetMessageStats
|
||||
| chatlists.ExportChatlistInvite | chatlists.DeleteExportedInvite | chatlists.EditExportedInvite | chatlists.GetExportedInvites | chatlists.CheckChatlistInvite | chatlists.JoinChatlistInvite | chatlists.GetChatlistUpdates | chatlists.JoinChatlistUpdates | chatlists.HideChatlistUpdates | chatlists.GetLeaveChatlistSuggestions | chatlists.LeaveChatlist
|
||||
| stories.SendStory | stories.EditStory | stories.DeleteStories | stories.TogglePinned | stories.GetAllStories | stories.GetUserStories | stories.GetPinnedStories | stories.GetStoriesArchive | stories.GetStoriesByID | stories.ToggleAllStoriesHidden | stories.GetAllReadUserStories | stories.ReadStories | stories.IncrementStoryViews | stories.GetStoryViewsList | stories.GetStoriesViews | stories.ExportStoryLink | stories.Report | stories.ActivateStealthMode | stories.SendReaction;
|
||||
| stories.CanSendStory | stories.SendStory | stories.EditStory | stories.DeleteStories | stories.TogglePinned | stories.GetAllStories | stories.GetUserStories | stories.GetPinnedStories | stories.GetStoriesArchive | stories.GetStoriesByID | stories.ToggleAllStoriesHidden | stories.GetAllReadUserStories | stories.ReadStories | stories.IncrementStoryViews | stories.GetStoryViewsList | stories.GetStoriesViews | stories.ExportStoryLink | stories.Report | stories.ActivateStealthMode | stories.SendReaction;
|
||||
|
||||
}
|
||||
|
||||
@ -124,7 +124,7 @@ messageActionPaymentSent#96163f56 flags:# recurring_init:flags.2?true recurring_
|
||||
messageActionPhoneCall#80e11a7f flags:# video:flags.2?true call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction;
|
||||
messageActionScreenshotTaken#4792929b = MessageAction;
|
||||
messageActionCustomAction#fae69f56 message:string = MessageAction;
|
||||
messageActionBotAllowed#c516d679 flags:# attach_menu:flags.1?true domain:flags.0?string app:flags.2?BotApp = MessageAction;
|
||||
messageActionBotAllowed#c516d679 flags:# attach_menu:flags.1?true from_request:flags.3?true domain:flags.0?string app:flags.2?BotApp = MessageAction;
|
||||
messageActionSecureValuesSentMe#1b287353 values:Vector<SecureValue> credentials:SecureCredentialsEncrypted = MessageAction;
|
||||
messageActionSecureValuesSent#d95c6154 types:Vector<SecureValueType> = MessageAction;
|
||||
messageActionContactSignUp#f3f25f76 = MessageAction;
|
||||
@ -472,7 +472,7 @@ receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage;
|
||||
chatInviteExported#ab4a819 flags:# revoked:flags.0?true permanent:flags.5?true request_needed:flags.6?true link:string admin_id:long date:int start_date:flags.4?int expire_date:flags.1?int usage_limit:flags.2?int usage:flags.3?int requested:flags.7?int title:flags.8?string = ExportedChatInvite;
|
||||
chatInvitePublicJoinRequests#ed107ab7 = ExportedChatInvite;
|
||||
chatInviteAlready#5a686d7c chat:Chat = ChatInvite;
|
||||
chatInvite#300c44c1 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true request_needed:flags.6?true title:string about:flags.5?string photo:Photo participants_count:int participants:flags.4?Vector<User> = ChatInvite;
|
||||
chatInvite#300c44c1 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true request_needed:flags.6?true verified:flags.7?true scam:flags.8?true fake:flags.9?true title:string about:flags.5?string photo:Photo participants_count:int participants:flags.4?Vector<User> = ChatInvite;
|
||||
chatInvitePeek#61695cb0 chat:Chat expires:int = ChatInvite;
|
||||
inputStickerSetEmpty#ffb62b95 = InputStickerSet;
|
||||
inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet;
|
||||
@ -1126,7 +1126,7 @@ messagePeerVote#b6cc2d5c peer:Peer option:bytes date:int = MessagePeerVote;
|
||||
messagePeerVoteInputOption#74cda504 peer:Peer date:int = MessagePeerVote;
|
||||
messagePeerVoteMultiple#4628f6e6 peer:Peer options:Vector<bytes> date:int = MessagePeerVote;
|
||||
sponsoredWebPage#3db8ec63 flags:# url:string site_name:string photo:flags.0?Photo = SponsoredWebPage;
|
||||
storyViews#c64c0b97 flags:# views_count:int reactions_count:int recent_viewers:flags.0?Vector<long> = StoryViews;
|
||||
storyViews#c64c0b97 flags:# has_viewers:flags.1?true views_count:int reactions_count:int recent_viewers:flags.0?Vector<long> = StoryViews;
|
||||
storyItemDeleted#51e6ee4f id:int = StoryItem;
|
||||
storyItemSkipped#ffadc913 flags:# close_friends:flags.8?true id:int date:int expire_date:int = StoryItem;
|
||||
storyItem#44c457ce flags:# pinned:flags.5?true public:flags.7?true close_friends:flags.8?true min:flags.9?true noforwards:flags.10?true edited:flags.11?true contacts:flags.12?true selected_contacts:flags.13?true id:int date:int expire_date:int caption:flags.0?string entities:flags.1?Vector<MessageEntity> media:MessageMedia media_areas:flags.14?Vector<MediaArea> privacy:flags.2?Vector<PrivacyRule> views:flags.3?StoryViews sent_reaction:flags.15?Reaction = StoryItem;
|
||||
@ -1403,6 +1403,9 @@ channels.editForumTopic#f4dfa185 flags:# channel:InputChannel topic_id:int title
|
||||
channels.updatePinnedForumTopic#6c2d9026 channel:InputChannel topic_id:int pinned:Bool = Updates;
|
||||
channels.deleteTopicHistory#34435f2d channel:InputChannel top_msg_id:int = messages.AffectedHistory;
|
||||
channels.toggleParticipantsHidden#6a6e7854 channel:InputChannel enabled:Bool = Updates;
|
||||
bots.canSendMessage#1359f4e6 bot:InputUser = Bool;
|
||||
bots.allowSendMessage#f132e3ef bot:InputUser = Updates;
|
||||
bots.invokeWebViewCustomMethod#87fc5e7 bot:InputUser custom_method:string params:DataJSON = DataJSON;
|
||||
payments.getPaymentForm#37148dbb flags:# invoice:InputInvoice theme_params:flags.0?DataJSON = payments.PaymentForm;
|
||||
payments.getPaymentReceipt#2478d1cc peer:InputPeer msg_id:int = payments.PaymentReceipt;
|
||||
payments.validateRequestedInfo#b6c8f12b flags:# save:flags.0?true invoice:InputInvoice info:PaymentRequestedInfo = payments.ValidatedRequestedInfo;
|
||||
|
||||
@ -216,6 +216,9 @@
|
||||
"channels.toggleUsername",
|
||||
"channels.viewSponsoredMessage",
|
||||
"channels.getSponsoredMessages",
|
||||
"bots.canSendMessage",
|
||||
"bots.allowSendMessage",
|
||||
"bots.invokeWebViewCustomMethod",
|
||||
"payments.getPaymentForm",
|
||||
"payments.getPaymentReceipt",
|
||||
"payments.validateRequestedInfo",
|
||||
|
||||
@ -150,7 +150,7 @@ messageActionPaymentSent#96163f56 flags:# recurring_init:flags.2?true recurring_
|
||||
messageActionPhoneCall#80e11a7f flags:# video:flags.2?true call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction;
|
||||
messageActionScreenshotTaken#4792929b = MessageAction;
|
||||
messageActionCustomAction#fae69f56 message:string = MessageAction;
|
||||
messageActionBotAllowed#c516d679 flags:# attach_menu:flags.1?true domain:flags.0?string app:flags.2?BotApp = MessageAction;
|
||||
messageActionBotAllowed#c516d679 flags:# attach_menu:flags.1?true from_request:flags.3?true domain:flags.0?string app:flags.2?BotApp = MessageAction;
|
||||
messageActionSecureValuesSentMe#1b287353 values:Vector<SecureValue> credentials:SecureCredentialsEncrypted = MessageAction;
|
||||
messageActionSecureValuesSent#d95c6154 types:Vector<SecureValueType> = MessageAction;
|
||||
messageActionContactSignUp#f3f25f76 = MessageAction;
|
||||
@ -570,7 +570,7 @@ chatInviteExported#ab4a819 flags:# revoked:flags.0?true permanent:flags.5?true r
|
||||
chatInvitePublicJoinRequests#ed107ab7 = ExportedChatInvite;
|
||||
|
||||
chatInviteAlready#5a686d7c chat:Chat = ChatInvite;
|
||||
chatInvite#300c44c1 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true request_needed:flags.6?true title:string about:flags.5?string photo:Photo participants_count:int participants:flags.4?Vector<User> = ChatInvite;
|
||||
chatInvite#300c44c1 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true request_needed:flags.6?true verified:flags.7?true scam:flags.8?true fake:flags.9?true title:string about:flags.5?string photo:Photo participants_count:int participants:flags.4?Vector<User> = ChatInvite;
|
||||
chatInvitePeek#61695cb0 chat:Chat expires:int = ChatInvite;
|
||||
|
||||
inputStickerSetEmpty#ffb62b95 = InputStickerSet;
|
||||
@ -1528,7 +1528,7 @@ messagePeerVoteMultiple#4628f6e6 peer:Peer options:Vector<bytes> date:int = Mess
|
||||
|
||||
sponsoredWebPage#3db8ec63 flags:# url:string site_name:string photo:flags.0?Photo = SponsoredWebPage;
|
||||
|
||||
storyViews#c64c0b97 flags:# views_count:int reactions_count:int recent_viewers:flags.0?Vector<long> = StoryViews;
|
||||
storyViews#c64c0b97 flags:# has_viewers:flags.1?true views_count:int reactions_count:int recent_viewers:flags.0?Vector<long> = StoryViews;
|
||||
|
||||
storyItemDeleted#51e6ee4f id:int = StoryItem;
|
||||
storyItemSkipped#ffadc913 flags:# close_friends:flags.8?true id:int date:int expire_date:int = StoryItem;
|
||||
@ -2017,6 +2017,9 @@ bots.setBotInfo#10cf3123 flags:# bot:flags.2?InputUser lang_code:string name:fla
|
||||
bots.getBotInfo#dcd914fd flags:# bot:flags.0?InputUser lang_code:string = bots.BotInfo;
|
||||
bots.reorderUsernames#9709b1c2 bot:InputUser order:Vector<string> = Bool;
|
||||
bots.toggleUsername#53ca973 bot:InputUser username:string active:Bool = Bool;
|
||||
bots.canSendMessage#1359f4e6 bot:InputUser = Bool;
|
||||
bots.allowSendMessage#f132e3ef bot:InputUser = Updates;
|
||||
bots.invokeWebViewCustomMethod#87fc5e7 bot:InputUser custom_method:string params:DataJSON = DataJSON;
|
||||
|
||||
payments.getPaymentForm#37148dbb flags:# invoice:InputInvoice theme_params:flags.0?DataJSON = payments.PaymentForm;
|
||||
payments.getPaymentReceipt#2478d1cc peer:InputPeer msg_id:int = payments.PaymentReceipt;
|
||||
@ -2099,6 +2102,7 @@ chatlists.hideChatlistUpdates#66e486fb chatlist:InputChatlist = Bool;
|
||||
chatlists.getLeaveChatlistSuggestions#fdbcd714 chatlist:InputChatlist = Vector<Peer>;
|
||||
chatlists.leaveChatlist#74fae13a chatlist:InputChatlist peers:Vector<InputPeer> = Updates;
|
||||
|
||||
stories.canSendStory#b100d45d = Bool;
|
||||
stories.sendStory#d455fcec flags:# pinned:flags.2?true noforwards:flags.4?true media:InputMedia media_areas:flags.5?Vector<MediaArea> caption:flags.0?string entities:flags.1?Vector<MessageEntity> privacy_rules:Vector<InputPrivacyRule> random_id:long period:flags.3?int = Updates;
|
||||
stories.editStory#a9b91ae4 flags:# id:int media:flags.0?InputMedia media_areas:flags.3?Vector<MediaArea> caption:flags.1?string entities:flags.1?Vector<MessageEntity> privacy_rules:flags.2?Vector<InputPrivacyRule> = Updates;
|
||||
stories.deleteStories#b5d501d7 id:Vector<int> = Vector<int>;
|
||||
@ -2117,4 +2121,4 @@ stories.getStoriesViews#9a75d6a6 id:Vector<int> = stories.StoryViews;
|
||||
stories.exportStoryLink#16e443ce user_id:InputUser id:int = ExportedStoryLink;
|
||||
stories.report#c95be06a user_id:InputUser id:Vector<int> reason:ReportReason message:string = Bool;
|
||||
stories.activateStealthMode#57bbd166 flags:# past:flags.0?true future:flags.1?true = Updates;
|
||||
stories.sendReaction#49aaa9b3 flags:# add_to_recent:flags.0?true user_id:InputUser story_id:int reaction:Reaction = Updates;
|
||||
stories.sendReaction#49aaa9b3 flags:# add_to_recent:flags.0?true user_id:InputUser story_id:int reaction:Reaction = Updates;
|
||||
174
src/types/webapp.ts
Normal file
174
src/types/webapp.ts
Normal file
@ -0,0 +1,174 @@
|
||||
export type PopupOptions = {
|
||||
title: string;
|
||||
message: string;
|
||||
buttons: {
|
||||
id: string;
|
||||
type: 'default' | 'ok' | 'close' | 'cancel' | 'destructive';
|
||||
text: string;
|
||||
}[];
|
||||
};
|
||||
|
||||
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_setup_back_button';
|
||||
eventData: {
|
||||
is_visible: boolean;
|
||||
};
|
||||
} | {
|
||||
eventType: 'web_app_open_link';
|
||||
eventData: {
|
||||
url: string;
|
||||
try_instant_view?: boolean;
|
||||
};
|
||||
} | {
|
||||
eventType: 'web_app_open_tg_link';
|
||||
eventData: {
|
||||
path_full: string;
|
||||
};
|
||||
} | {
|
||||
eventType: 'web_app_open_invoice';
|
||||
eventData: {
|
||||
slug: string;
|
||||
};
|
||||
} | {
|
||||
eventType: 'web_app_trigger_haptic_feedback';
|
||||
eventData: {
|
||||
type: 'impact' | 'notification' | 'selection_change';
|
||||
impact_style?: 'light' | 'medium' | 'heavy';
|
||||
notification_type?: 'error' | 'success' | 'warning';
|
||||
};
|
||||
} | {
|
||||
eventType: 'web_app_set_background_color';
|
||||
eventData: {
|
||||
color: string;
|
||||
};
|
||||
} | {
|
||||
eventType: 'web_app_set_header_color';
|
||||
eventData: {
|
||||
color_key: 'bg_color' | 'secondary_bg_color';
|
||||
};
|
||||
} | {
|
||||
eventType: 'web_app_open_popup';
|
||||
eventData: PopupOptions;
|
||||
} | {
|
||||
eventType: 'web_app_setup_closing_behavior';
|
||||
eventData: {
|
||||
need_confirmation: boolean;
|
||||
};
|
||||
} | {
|
||||
eventType: 'web_app_open_scan_qr_popup';
|
||||
eventData: {
|
||||
text?: string;
|
||||
};
|
||||
} | {
|
||||
eventType: 'web_app_read_text_from_clipboard';
|
||||
eventData: {
|
||||
req_id: string;
|
||||
};
|
||||
} | {
|
||||
eventType: 'web_app_switch_inline_query';
|
||||
eventData: {
|
||||
query: string;
|
||||
chat_types: ('users' | 'bots' | 'groups' | 'channels')[];
|
||||
};
|
||||
} | {
|
||||
eventType: 'web_app_invoke_custom_method';
|
||||
eventData: {
|
||||
req_id: string;
|
||||
method: string;
|
||||
params: object;
|
||||
};
|
||||
} | {
|
||||
eventType: 'web_app_request_viewport' | 'web_app_request_theme' | 'web_app_ready' | 'web_app_expand'
|
||||
| 'web_app_request_phone' | 'web_app_close' | 'iframe_ready' | 'web_app_close_scan_qr_popup'
|
||||
| 'web_app_request_write_access' | 'web_app_request_phone';
|
||||
eventData: null;
|
||||
};
|
||||
|
||||
export type WebAppOutboundEvent = {
|
||||
eventType: 'viewport_changed';
|
||||
eventData: {
|
||||
height: number;
|
||||
width?: number;
|
||||
is_expanded?: boolean;
|
||||
is_state_stable?: 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;
|
||||
secondary_bg_color: string;
|
||||
};
|
||||
};
|
||||
} | {
|
||||
eventType: 'set_custom_style';
|
||||
eventData: string;
|
||||
} | {
|
||||
eventType: 'invoice_closed';
|
||||
eventData: {
|
||||
slug: string;
|
||||
status: 'paid' | 'cancelled' | 'pending' | 'failed';
|
||||
};
|
||||
} | {
|
||||
eventType: 'phone_requested';
|
||||
eventData: {
|
||||
phone_number: string;
|
||||
};
|
||||
} | {
|
||||
eventType: 'popup_closed';
|
||||
eventData: {
|
||||
button_id?: string;
|
||||
};
|
||||
} | {
|
||||
eventType: 'qr_text_received';
|
||||
eventData: {
|
||||
data: string;
|
||||
};
|
||||
} | {
|
||||
eventType: 'clipboard_text_received';
|
||||
eventData: {
|
||||
req_id: string;
|
||||
data: string | null;
|
||||
};
|
||||
} | {
|
||||
eventType: 'write_access_requested';
|
||||
eventData: {
|
||||
status: 'allowed' | 'cancelled';
|
||||
};
|
||||
} | {
|
||||
eventType: 'phone_requested';
|
||||
eventData: {
|
||||
status: 'sent' | 'cancelled';
|
||||
};
|
||||
} | {
|
||||
eventType: 'custom_method_invoked';
|
||||
eventData: {
|
||||
req_id: string;
|
||||
} & ({
|
||||
result: object;
|
||||
} | {
|
||||
error: string;
|
||||
});
|
||||
} | {
|
||||
eventType: 'main_button_pressed' | 'back_button_pressed' | 'settings_button_pressed' | 'scan_qr_popup_closed';
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user