From 92d9f0736c3e890af0e1eca37f95fbcee3cd39c3 Mon Sep 17 00:00:00 2001 From: Alexander Zinchuk Date: Wed, 23 Apr 2025 18:59:21 +0200 Subject: [PATCH] Support layer 201 (#5794) --- src/api/gramjs/apiBuilders/appConfig.ts | 6 + src/api/gramjs/apiBuilders/messageActions.ts | 21 ++ src/api/gramjs/methods/client.ts | 27 ++ src/api/gramjs/methods/messages.ts | 9 +- src/api/types/messageActions.ts | 14 +- src/api/types/misc.ts | 3 + src/api/types/updates.ts | 7 +- src/assets/font-icons/frozen-time.svg | 1 + src/assets/localization/fallback.strings | 19 + src/assets/tgs/BannedDuck.tgs | Bin 0 -> 8635 bytes src/bundles/extra.ts | 1 + src/components/common/Composer.tsx | 15 +- .../common/helpers/animatedAssets.ts | 2 + src/components/left/LeftColumn.tsx | 9 +- src/components/left/NewChatButton.tsx | 10 +- src/components/left/main/Chat.tsx | 21 ++ src/components/left/main/ChatFolders.tsx | 7 +- src/components/left/main/ChatList.tsx | 25 +- .../FrozenAccountNotification.module.scss | 25 ++ .../left/main/FrozenAccountNotification.tsx | 25 ++ src/components/left/main/LeftMain.tsx | 3 + src/components/left/main/StatusButton.tsx | 15 +- .../left/settings/SettingsPrivacy.tsx | 25 +- src/components/main/Main.tsx | 73 ++-- .../FrozenAccountPlaceholder.module.scss | 21 ++ .../middle/FrozenAccountPlaceholder.tsx | 29 ++ src/components/middle/HeaderActions.tsx | 10 + src/components/middle/HeaderMenuContainer.tsx | 128 +++++-- src/components/middle/MessageList.tsx | 15 +- src/components/middle/MiddleColumn.scss | 9 +- src/components/middle/MiddleColumn.tsx | 20 +- .../middle/message/ActionMessage.tsx | 8 +- .../middle/message/ActionMessageText.tsx | 25 ++ .../middle/message/CommentButton.tsx | 9 +- src/components/middle/message/Message.tsx | 12 +- .../middle/message/reactions/Reactions.tsx | 17 + src/components/modals/ModalContainer.tsx | 5 +- .../EmojiStatusAccessModal.tsx | 12 +- .../FrozenAccountModal.async.tsx | 18 + .../FrozenAccountModal.module.scss | 26 ++ .../frozenAccount/FrozenAccountModal.tsx | 143 ++++++++ src/components/story/Story.tsx | 7 +- src/global/actions/all.ts | 1 + src/global/actions/api/bots.ts | 21 ++ src/global/actions/api/chats.ts | 63 +++- src/global/actions/api/management.ts | 5 +- src/global/actions/api/messages.ts | 14 +- src/global/actions/api/payments.ts | 11 + src/global/actions/api/reactions.ts | 5 + src/global/actions/api/settings.ts | 8 +- src/global/actions/api/stories.ts | 7 + src/global/actions/api/symbols.ts | 12 +- src/global/actions/api/sync.ts | 5 +- src/global/actions/api/users.ts | 10 + src/global/actions/apiUpdaters/initial.ts | 13 + src/global/actions/ui/account.ts | 21 ++ src/global/actions/ui/calls.ts | 6 +- src/global/actions/ui/stars.ts | 9 +- src/global/actions/ui/users.ts | 11 + src/global/selectors/users.ts | 4 + src/global/types/actions.ts | 3 + src/global/types/globalState.ts | 2 + src/global/types/tabState.ts | 2 + src/lib/gramjs/tl/AllTLObjects.ts | 2 +- src/lib/gramjs/tl/api.d.ts | 194 +++++++++-- src/lib/gramjs/tl/apiTl.ts | 27 +- src/lib/gramjs/tl/static/api.tl | 37 +- src/styles/icons.scss | 328 +++++++++--------- src/styles/icons.woff | Bin 32676 -> 32860 bytes src/styles/icons.woff2 | Bin 27304 -> 27460 bytes src/types/icons/font.ts | 1 + src/types/language.d.ts | 30 ++ src/util/deepLinkParser.ts | 8 + 73 files changed, 1406 insertions(+), 331 deletions(-) create mode 100644 src/assets/font-icons/frozen-time.svg create mode 100644 src/assets/tgs/BannedDuck.tgs create mode 100644 src/components/left/main/FrozenAccountNotification.module.scss create mode 100644 src/components/left/main/FrozenAccountNotification.tsx create mode 100644 src/components/middle/FrozenAccountPlaceholder.module.scss create mode 100644 src/components/middle/FrozenAccountPlaceholder.tsx create mode 100644 src/components/modals/frozenAccount/FrozenAccountModal.async.tsx create mode 100644 src/components/modals/frozenAccount/FrozenAccountModal.module.scss create mode 100644 src/components/modals/frozenAccount/FrozenAccountModal.tsx create mode 100644 src/global/actions/ui/account.ts diff --git a/src/api/gramjs/apiBuilders/appConfig.ts b/src/api/gramjs/apiBuilders/appConfig.ts index ce6d6ffd7..c01a7cd04 100644 --- a/src/api/gramjs/apiBuilders/appConfig.ts +++ b/src/api/gramjs/apiBuilders/appConfig.ts @@ -92,6 +92,9 @@ export interface GramJsAppConfig extends LimitsConfig { stars_paid_message_commission_permille?: number; stars_paid_message_amount_max?: number; stargifts_pinned_to_top_limit?: number; + freeze_since_date?: number; + freeze_until_date?: number; + freeze_appeal_url?: string; } function buildEmojiSounds(appConfig: GramJsAppConfig) { @@ -185,5 +188,8 @@ export function buildAppConfig(json: GramJs.TypeJSONValue, hash: number): ApiApp starRefStartPrefixes: appConfig.starref_start_param_prefixes, tonExplorerUrl: appConfig.ton_blockchain_explorer_url, savedGiftPinLimit: appConfig.stargifts_pinned_to_top_limit, + freezeSinceDate: appConfig.freeze_since_date, + freezeUntilDate: appConfig.freeze_until_date, + freezeAppealUrl: appConfig.freeze_appeal_url, }; } diff --git a/src/api/gramjs/apiBuilders/messageActions.ts b/src/api/gramjs/apiBuilders/messageActions.ts index f624ccbc7..08b5df9fa 100644 --- a/src/api/gramjs/apiBuilders/messageActions.ts +++ b/src/api/gramjs/apiBuilders/messageActions.ts @@ -413,6 +413,27 @@ export function buildApiMessageAction(action: GramJs.TypeMessageAction): ApiMess savedId: savedId && buildApiPeerId(savedId, 'user'), }; } + if (action instanceof GramJs.MessageActionPaidMessagesPrice) { + const { + stars, + } = action; + return { + mediaType: 'action', + type: 'paidMessagesPrice', + stars: stars.toJSNumber(), + }; + } + if (action instanceof GramJs.MessageActionPaidMessagesRefunded) { + const { + stars, count, + } = action; + return { + mediaType: 'action', + type: 'paidMessagesRefunded', + stars: stars.toJSNumber(), + count, + }; + } return UNSUPPORTED_ACTION; } diff --git a/src/api/gramjs/methods/client.ts b/src/api/gramjs/methods/client.ts index 892c06f39..39bd33a04 100644 --- a/src/api/gramjs/methods/client.ts +++ b/src/api/gramjs/methods/client.ts @@ -307,6 +307,12 @@ export async function invokeRequest( console.error(err); } + const message = err instanceof RPCError ? err.errorMessage : err.message; + + if (message.includes('FROZEN_METHOD_INVALID')) { + dispatchNotSupportedInFrozenAccountUpdate(err, request); + } + if (shouldThrow) { throw err; } @@ -441,6 +447,27 @@ export function dispatchErrorUpdate(err: Error, req }); } +function dispatchNotSupportedInFrozenAccountUpdate(err: Error, request: T) { + if (!(err instanceof RPCError)) return; + const message = err.errorMessage; + + if ( + request instanceof GramJs.messages.GetPinnedDialogs + || request instanceof GramJs.phone.GetGroupParticipants + || request instanceof GramJs.channels.GetParticipant + || request instanceof GramJs.channels.GetParticipants + || request instanceof GramJs.channels.GetForumTopics) { + return; + } + + sendApiUpdate({ + '@type': 'notSupportedInFrozenAccount', + error: { + message, + }, + }); +} + async function handleTerminatedSession() { try { await invokeRequest(new GramJs.users.GetFullUser({ diff --git a/src/api/gramjs/methods/messages.ts b/src/api/gramjs/methods/messages.ts index 335105a67..dfabaaf2b 100644 --- a/src/api/gramjs/methods/messages.ts +++ b/src/api/gramjs/methods/messages.ts @@ -1775,20 +1775,17 @@ export async function fetchSponsoredMessages({ peer }: { peer: ApiPeer }) { }; } -export async function viewSponsoredMessage({ peer, random }: { peer: ApiPeer; random: string }) { +export async function viewSponsoredMessage({ random }: { random: string }) { await invokeRequest(new GramJs.messages.ViewSponsoredMessage({ - peer: buildInputPeer(peer.id, peer.accessHash), randomId: deserializeBytes(random), })); } export function clickSponsoredMessage({ - peer, random, isMedia, isFullscreen, }: { - peer: ApiPeer; random: string; isMedia?: boolean; isFullscreen?: boolean; @@ -1796,23 +1793,19 @@ export function clickSponsoredMessage({ return invokeRequest(new GramJs.messages.ClickSponsoredMessage({ media: isMedia || undefined, fullscreen: isFullscreen || undefined, - peer: buildInputPeer(peer.id, peer.accessHash), randomId: deserializeBytes(random), })); } export async function reportSponsoredMessage({ - peer, randomId, option, }: { - peer: ApiPeer; randomId: string; option: string; }) { try { const result = await invokeRequest(new GramJs.messages.ReportSponsoredMessage({ - peer: buildInputPeer(peer.id, peer.accessHash), randomId: deserializeBytes(randomId), option: deserializeBytes(option), }), { diff --git a/src/api/types/messageActions.ts b/src/api/types/messageActions.ts index aa9523152..9dc921f60 100644 --- a/src/api/types/messageActions.ts +++ b/src/api/types/messageActions.ts @@ -268,6 +268,17 @@ export interface ApiMessageActionExpiredContent extends ActionMediaType { isRoundVideo?: true; } +export interface ApiMessageActionPaidMessagesRefunded extends ActionMediaType { + type: 'paidMessagesRefunded'; + count:number; + stars:number; +} + +export interface ApiMessageActionPaidMessagesPrice extends ActionMediaType { + type: 'paidMessagesPrice'; + stars:number; +} + export interface ApiMessageActionUnsupported extends ActionMediaType { type: 'unsupported'; } @@ -284,4 +295,5 @@ export type ApiMessageAction = ApiMessageActionUnsupported | ApiMessageActionCha | ApiMessageActionTopicCreate | ApiMessageActionTopicEdit | ApiMessageActionSuggestProfilePhoto | ApiMessageActionChannelJoined | ApiMessageActionGiftCode | ApiMessageActionGiveawayLaunch | ApiMessageActionGiveawayResults | ApiMessageActionPaymentRefunded | ApiMessageActionGiftStars -| ApiMessageActionPrizeStars | ApiMessageActionStarGift | ApiMessageActionStarGiftUnique; +| ApiMessageActionPrizeStars | ApiMessageActionStarGift | ApiMessageActionStarGiftUnique +| ApiMessageActionPaidMessagesRefunded | ApiMessageActionPaidMessagesPrice; diff --git a/src/api/types/misc.ts b/src/api/types/misc.ts index 4ff505494..831e46a45 100644 --- a/src/api/types/misc.ts +++ b/src/api/types/misc.ts @@ -243,6 +243,9 @@ export interface ApiAppConfig { starRefStartPrefixes?: string[]; tonExplorerUrl?: string; savedGiftPinLimit?: number; + freezeSinceDate?: number; + freezeUntilDate?: number; + freezeAppealUrl?: string; } export interface ApiConfig { diff --git a/src/api/types/updates.ts b/src/api/types/updates.ts index 1e756fee6..06c50ff1d 100644 --- a/src/api/types/updates.ts +++ b/src/api/types/updates.ts @@ -463,6 +463,11 @@ export type ApiUpdateError = { error: ApiError; }; +export type ApiUpdateNotSupportedInFrozenAccountError = { + '@type': 'notSupportedInFrozenAccount'; + error: ApiError; +}; + export type ApiUpdateConfig = { '@type': 'updateConfig'; }; @@ -855,7 +860,7 @@ export type ApiUpdate = ( ApiUpdateDeleteSavedHistory | ApiUpdatePremiumFloodWait | ApiUpdateStarsBalance | ApiUpdateQuickReplyMessage | ApiUpdateQuickReplies | ApiDeleteQuickReply | ApiUpdateDeleteQuickReplyMessages | ApiUpdateDeleteProfilePhoto | ApiUpdateNewProfilePhoto | ApiUpdateEntities | ApiUpdatePaidReactionPrivacy | - ApiUpdateLangPackTooLong | ApiUpdateLangPack + ApiUpdateLangPackTooLong | ApiUpdateLangPack | ApiUpdateNotSupportedInFrozenAccountError ); export type OnApiUpdate = (update: ApiUpdate) => void; diff --git a/src/assets/font-icons/frozen-time.svg b/src/assets/font-icons/frozen-time.svg new file mode 100644 index 000000000..15a7c2b13 --- /dev/null +++ b/src/assets/font-icons/frozen-time.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/localization/fallback.strings b/src/assets/localization/fallback.strings index f44afd5ed..4401d5a6f 100644 --- a/src/assets/localization/fallback.strings +++ b/src/assets/localization/fallback.strings @@ -1902,6 +1902,25 @@ "PaidMessageTransaction_other" = "Fee for {count} Messages"; "PaidMessageTransactionDescription" = "You receive **{percent}** of the price that you charge for each incoming message."; "PaidMessageTransactionTotal" = "Total"; +"TitleFrozenAccount" = "Your account is frozen!"; +"SubtitleFrozenAccount" = "Tap to view details and submit an appeal."; +"ComposerTitleFrozenAccount" = "Your account is frozen"; +"ComposerSubtitleFrozenAccount" = "Tap to view details"; "DescriptionRestrictedMedia" = "Posting media content is not allowed in this group."; "DescriptionScheduledPaidMediaNotAllowed" = "Posting scheduled paid media content is not allowed"; "DescriptionScheduledPaidMessagesNotAllowed" = "Scheduled paid messages is not allowed"; +"FrozenAccountModalTitle" = "Your Account is Frozen"; +"FrozenAccountViolationTitle" = "Violation of Terms"; +"FrozenAccountViolationSubtitle" = "Your account was frozen for breaking Telegram's Terms and Conditions"; +"FrozenAccountReadOnlyTitle" = "Read-Only Mode"; +"FrozenAccountReadOnlySubtitle" = "You can access your account but can't send messages or take actions."; +"FrozenAccountAppealTitle" = "Appeal Before Deactivation"; +"FrozenAccountAppealSubtitle" = "Appeal via {botLink} before {date} or your account will be deleted."; +"ButtonAppeal" = "Submit an Appeal"; +"ButtonUnderstood" = "Understood"; +"ActionPaidMessageGroupPrice" = "Messages now cost **{stars}** in this group"; +"ActionPaidMessageGroupPriceFree" = "Messages are now free in this group"; +"ApiMessageActionPaidMessagesRefundedOutgoing" = "You refunded **{stars}** to {user}"; +"ApiMessageActionPaidMessagesRefundedIncoming" = "{user} refunded **{stars}** to you"; +"NotificationTitleNotSupportedInFrozenAccount" = "Your account is frozen"; +"NotificationMessageNotSupportedInFrozenAccount" = "This action is not available"; \ No newline at end of file diff --git a/src/assets/tgs/BannedDuck.tgs b/src/assets/tgs/BannedDuck.tgs new file mode 100644 index 0000000000000000000000000000000000000000..e0b883bf5a1209fe3270c2a500973f6b4f986d19 GIT binary patch literal 8635 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 N{|~&rqH=6d0RW)g)x`h+ literal 0 HcmV?d00001 diff --git a/src/bundles/extra.ts b/src/bundles/extra.ts index 9112a8352..93122c1b0 100644 --- a/src/bundles/extra.ts +++ b/src/bundles/extra.ts @@ -97,3 +97,4 @@ export { default as ReceiptModal } from '../components/payment/ReceiptModal'; export { default as InviteViaLinkModal } from '../components/modals/inviteViaLink/InviteViaLinkModal'; export { default as OneTimeMediaModal } from '../components/modals/oneTimeMedia/OneTimeMediaModal'; export { default as WebAppsCloseConfirmationModal } from '../components/main/WebAppsCloseConfirmationModal'; +export { default as FrozenAccountModal } from '../components/modals/frozenAccount/FrozenAccountModal'; diff --git a/src/components/common/Composer.tsx b/src/components/common/Composer.tsx index 0860990f9..2757c86ca 100644 --- a/src/components/common/Composer.tsx +++ b/src/components/common/Composer.tsx @@ -82,6 +82,7 @@ import { selectEditingMessage, selectEditingScheduledDraft, selectIsChatWithSelf, + selectIsCurrentUserFrozen, selectIsCurrentUserPremium, selectIsInSelectMode, selectIsPremiumPurchaseBlocked, @@ -291,6 +292,8 @@ type StateProps = isPaymentMessageConfirmDialogOpen: boolean; starsBalance: number; isStarsBalanceModalOpen: boolean; + isAccountFrozen?: boolean; + isAppConfigLoaded?: boolean; }; enum MainButtonState { @@ -411,6 +414,8 @@ const Composer: FC = ({ isPaymentMessageConfirmDialogOpen, starsBalance, isStarsBalanceModalOpen, + isAccountFrozen, + isAppConfigLoaded, }) => { const { sendMessage, @@ -499,10 +504,10 @@ const Composer: FC = ({ }, [chatId]); useEffect(() => { - if (chatId && isReady && !isInStoryViewer) { + if (isAppConfigLoaded && chatId && isReady && !isInStoryViewer) { loadScheduledHistory({ chatId }); } - }, [isReady, chatId, threadId, isInStoryViewer]); + }, [isReady, chatId, threadId, isInStoryViewer, isAppConfigLoaded]); useEffect(() => { const isChannelWithProfiles = isChannel && chat?.areProfilesShown; @@ -1960,7 +1965,7 @@ const Composer: FC = ({ )} )} - {((!isComposerBlocked || canSendGifs || canSendStickers) && !isNeedPremium) && ( + {((!isComposerBlocked || canSendGifs || canSendStickers) && !isNeedPremium && !isAccountFrozen) && ( ( const isForwarding = chatId === tabState.forwardMessages.toChatId; const starsBalance = global.stars?.balance.amount || 0; const isStarsBalanceModalOpen = Boolean(tabState.starsBalanceModal); + const isAccountFrozen = selectIsCurrentUserFrozen(global); + const isAppConfigLoaded = global.isAppConfigLoaded; return { availableReactions: global.reactions.availableReactions, @@ -2457,6 +2464,8 @@ export default memo(withGlobal( isPaymentMessageConfirmDialogOpen: tabState.isPaymentMessageConfirmDialogOpen, starsBalance, isStarsBalanceModalOpen, + isAccountFrozen, + isAppConfigLoaded, }; }, )(Composer)); diff --git a/src/components/common/helpers/animatedAssets.ts b/src/components/common/helpers/animatedAssets.ts index d368892db..27c949d81 100644 --- a/src/components/common/helpers/animatedAssets.ts +++ b/src/components/common/helpers/animatedAssets.ts @@ -1,4 +1,5 @@ import QrPlane from '../../../assets/tgs/auth/QrPlane.tgs'; +import BannedDuck from '../../../assets/tgs/BannedDuck.tgs'; import CameraFlip from '../../../assets/tgs/calls/CameraFlip.tgs'; import HandFilled from '../../../assets/tgs/calls/HandFilled.tgs'; import HandOutline from '../../../assets/tgs/calls/HandOutline.tgs'; @@ -66,4 +67,5 @@ export const LOCAL_TGS_URLS = { StarReaction, Report, SearchingDuck, + BannedDuck, }; diff --git a/src/components/left/LeftColumn.tsx b/src/components/left/LeftColumn.tsx index 119c916ae..08d428ff3 100644 --- a/src/components/left/LeftColumn.tsx +++ b/src/components/left/LeftColumn.tsx @@ -9,7 +9,9 @@ import type { FoldersActions } from '../../hooks/reducers/useFoldersReducer'; import type { ReducerAction } from '../../hooks/useReducer'; import { LeftColumnContent, SettingsScreens } from '../../types'; -import { selectCurrentChat, selectIsForumPanelOpen, selectTabState } from '../../global/selectors'; +import { + selectCurrentChat, selectIsCurrentUserFrozen, selectIsForumPanelOpen, selectTabState, +} from '../../global/selectors'; import { IS_APP, IS_FIREFOX, IS_MAC_OS, IS_TOUCH_ENV, LAYERS_ANIMATION_NAME, } from '../../util/browser/windowEnvironment'; @@ -52,6 +54,7 @@ type StateProps = { isClosingSearch?: boolean; archiveSettings: GlobalState['archiveSettings']; isArchivedStoryRibbonShown?: boolean; + isAccountFrozen?: boolean; }; enum ContentType { @@ -86,6 +89,7 @@ function LeftColumn({ isClosingSearch, archiveSettings, isArchivedStoryRibbonShown, + isAccountFrozen, }: OwnProps & StateProps) { const { setGlobalSearchQuery, @@ -545,6 +549,7 @@ function LeftColumn({ isElectronUpdateAvailable={isElectronUpdateAvailable} isForumPanelOpen={isForumPanelOpen} onTopicSearch={handleTopicSearch} + isAccountFrozen={isAccountFrozen} /> ); } @@ -598,6 +603,7 @@ export default memo(withGlobal( const isChatOpen = Boolean(currentChat?.id); const isForumPanelOpen = selectIsForumPanelOpen(global); const forumPanelChatId = tabState.forumPanelChatId; + const isAccountFrozen = selectIsCurrentUserFrozen(global); return { searchQuery: query, @@ -616,6 +622,7 @@ export default memo(withGlobal( isClosingSearch: tabState.globalSearch.isClosing, archiveSettings, isArchivedStoryRibbonShown: isArchivedRibbonShown, + isAccountFrozen, }; }, )(LeftColumn)); diff --git a/src/components/left/NewChatButton.tsx b/src/components/left/NewChatButton.tsx index 349a4975e..735f1a633 100644 --- a/src/components/left/NewChatButton.tsx +++ b/src/components/left/NewChatButton.tsx @@ -2,6 +2,7 @@ import type { FC } from '../../lib/teact/teact'; import React, { useCallback, useEffect, useMemo, useState, } from '../../lib/teact/teact'; +import { getActions } from '../../global'; import buildClassName from '../../util/buildClassName'; @@ -19,6 +20,7 @@ type OwnProps = { onNewPrivateChat: () => void; onNewChannel: () => void; onNewGroup: () => void; + isAccountFrozen?: boolean; }; const NewChatButton: FC = ({ @@ -26,8 +28,10 @@ const NewChatButton: FC = ({ onNewPrivateChat, onNewChannel, onNewGroup, + isAccountFrozen, }) => { const [isMenuOpen, setIsMenuOpen] = useState(false); + const { openFrozenAccountModal } = getActions(); useEffect(() => { if (!isShown) { @@ -44,8 +48,12 @@ const NewChatButton: FC = ({ ); const toggleIsMenuOpen = useCallback(() => { + if (isAccountFrozen) { + openFrozenAccountModal(); + return; + } setIsMenuOpen(!isMenuOpen); - }, [isMenuOpen]); + }, [isMenuOpen, isAccountFrozen]); const handleClose = useCallback(() => { setIsMenuOpen(false); diff --git a/src/components/left/main/Chat.tsx b/src/components/left/main/Chat.tsx index 508a60e91..2dbc8c06f 100644 --- a/src/components/left/main/Chat.tsx +++ b/src/components/left/main/Chat.tsx @@ -33,6 +33,7 @@ import { selectChatMessage, selectCurrentMessageList, selectDraft, + selectIsCurrentUserFrozen, selectIsForumPanelClosed, selectIsForumPanelOpen, selectNotifyDefaults, @@ -114,6 +115,7 @@ type StateProps = { lastMessage?: ApiMessage; currentUserId: string; isSynced?: boolean; + isAccountFrozen?: boolean; }; const Chat: FC = ({ @@ -151,6 +153,7 @@ const Chat: FC = ({ className, isSynced, onDragEnter, + isAccountFrozen, }) => { const { openChat, @@ -163,6 +166,7 @@ const Chat: FC = ({ closeForumPanel, setShouldCloseRightColumn, reportMessages, + openFrozenAccountModal, } = getActions(); const { isMobile } = useAppLayout(); @@ -248,11 +252,21 @@ const Chat: FC = ({ }); const handleDelete = useLastCallback(() => { + if (isAccountFrozen) { + openFrozenAccountModal(); + return; + } + markRenderDeleteModal(); openDeleteModal(); }); const handleMute = useLastCallback(() => { + if (isAccountFrozen) { + openFrozenAccountModal(); + return; + } + markRenderMuteModal(); openMuteModal(); }); @@ -263,6 +277,11 @@ const Chat: FC = ({ }); const handleReport = useLastCallback(() => { + if (isAccountFrozen) { + openFrozenAccountModal(); + return; + } + if (!chat) return; reportMessages({ chatId: chat.id, messageIds: [] }); }); @@ -468,6 +487,7 @@ export default memo(withGlobal( const storyData = lastMessage?.content.storyData; const lastMessageStory = storyData && selectPeerStory(global, storyData.peerId, storyData.id); + const isAccountFrozen = selectIsCurrentUserFrozen(global); return { chat, @@ -494,6 +514,7 @@ export default memo(withGlobal( topics: topicsInfo?.topicsById, isSynced: global.isSynced, lastMessageStory, + isAccountFrozen, }; }, )(Chat)); diff --git a/src/components/left/main/ChatFolders.tsx b/src/components/left/main/ChatFolders.tsx index b0ed9951c..9f5433289 100644 --- a/src/components/left/main/ChatFolders.tsx +++ b/src/components/left/main/ChatFolders.tsx @@ -13,7 +13,7 @@ import type { TabWithProperties } from '../../ui/TabList'; import { SettingsScreens } from '../../../types'; import { ALL_FOLDER_ID } from '../../../config'; -import { selectCanShareFolder, selectTabState } from '../../../global/selectors'; +import { selectCanShareFolder, selectIsCurrentUserFrozen, selectTabState } from '../../../global/selectors'; import { selectCurrentLimit } from '../../../global/selectors/limits'; import { IS_TOUCH_ENV } from '../../../util/browser/windowEnvironment'; import buildClassName from '../../../util/buildClassName'; @@ -60,6 +60,7 @@ type StateProps = { archiveSettings: GlobalState['archiveSettings']; isStoryRibbonShown?: boolean; sessions?: Record; + isAccountFrozen?: boolean; }; const SAVED_MESSAGES_HOTKEY = '0'; @@ -85,6 +86,7 @@ const ChatFolders: FC = ({ archiveSettings, isStoryRibbonShown, sessions, + isAccountFrozen, }) => { const { loadChatFolders, @@ -368,6 +370,7 @@ const ChatFolders: FC = ({ canDisplayArchive={(hasArchivedChats || hasArchivedStories) && !archiveSettings.isHidden} archiveSettings={archiveSettings} sessions={sessions} + isAccountFrozen={isAccountFrozen} /> ); } @@ -432,6 +435,7 @@ export default memo(withGlobal( } = global; const { shouldSkipHistoryAnimations, activeChatFolder } = selectTabState(global); const { storyViewer: { isRibbonShown: isStoryRibbonShown } } = selectTabState(global); + const isAccountFrozen = selectIsCurrentUserFrozen(global); return { chatFoldersById, @@ -448,6 +452,7 @@ export default memo(withGlobal( archiveSettings, isStoryRibbonShown, sessions, + isAccountFrozen, }; }, )(ChatFolders)); diff --git a/src/components/left/main/ChatList.tsx b/src/components/left/main/ChatList.tsx index d68633694..234e4aa55 100644 --- a/src/components/left/main/ChatList.tsx +++ b/src/components/left/main/ChatList.tsx @@ -39,6 +39,7 @@ import Loading from '../../ui/Loading'; import Archive from './Archive'; import Chat from './Chat'; import EmptyFolder from './EmptyFolder'; +import FrozenAccountNotification from './FrozenAccountNotification'; import UnconfirmedSession from './UnconfirmedSession'; type OwnProps = { @@ -53,6 +54,7 @@ type OwnProps = { foldersDispatch?: FolderEditDispatch; onSettingsScreenSelect?: (screen: SettingsScreens) => void; onLeftColumnContentChange?: (content: LeftColumnContent) => void; + isAccountFrozen?: boolean; }; const INTERSECTION_THROTTLE = 200; @@ -71,12 +73,14 @@ const ChatList: FC = ({ foldersDispatch, onSettingsScreenSelect, onLeftColumnContentChange, + isAccountFrozen, }) => { const { openChat, openNextChat, closeForumPanel, toggleStoryRibbon, + openFrozenAccountModal, } = getActions(); // eslint-disable-next-line no-null/no-null const containerRef = useRef(null); @@ -91,6 +95,7 @@ const ChatList: FC = ({ ); const shouldDisplayArchive = isAllFolder && canDisplayArchive && archiveSettings; + const shouldShowFrozenAccountNotification = isAccountFrozen && isAllFolder; const orderedIds = useFolderManagerForOrderedIds(resolvedFolderId); usePeerStoriesPolling(orderedIds); @@ -98,6 +103,7 @@ const ChatList: FC = ({ const chatsHeight = (orderedIds?.length || 0) * CHAT_HEIGHT_PX; const archiveHeight = shouldDisplayArchive ? archiveSettings?.isMinimized ? ARCHIVE_MINIMIZED_HEIGHT : CHAT_HEIGHT_PX : 0; + const frozenNotificationHeight = shouldShowFrozenAccountNotification ? 68 : 0; const { orderDiffById, getAnimationType } = useOrderDiff(orderedIds); @@ -108,8 +114,8 @@ const ChatList: FC = ({ const current = sessionsArray.find((session) => session.isCurrent); if (!current || getServerTime() - current.dateCreated < FRESH_AUTH_PERIOD) return false; - return isAllFolder && sessionsArray.some((session) => session.isUnconfirmed); - }, [isAllFolder, sessions]); + return !isAccountFrozen && isAllFolder && sessionsArray.some((session) => session.isUnconfirmed); + }, [isAllFolder, sessions, isAccountFrozen]); useEffect(() => { if (!shouldShowUnconfirmedSessions) setUnconfirmedSessionHeight(0); @@ -174,6 +180,10 @@ const ChatList: FC = ({ closeForumPanel(); }); + const handleFrozenAccountNotificationClick = useLastCallback(() => { + openFrozenAccountModal(); + }); + const handleArchivedDragEnter = useLastCallback(() => { if (shouldIgnoreDragRef.current) { shouldIgnoreDragRef.current = false; @@ -215,7 +225,8 @@ const ChatList: FC = ({ return viewportIds!.map((id, i) => { const isPinned = viewportOffset + i < pinnedCount; - const offsetTop = unconfirmedSessionHeight + archiveHeight + (viewportOffset + i) * CHAT_HEIGHT_PX; + const offsetTop = unconfirmedSessionHeight + archiveHeight + frozenNotificationHeight + + (viewportOffset + i) * CHAT_HEIGHT_PX; return ( = ({ preloadBackwards={CHAT_LIST_SLICE} withAbsolutePositioning beforeChildren={renderedOverflowTrigger} - maxHeight={chatsHeight + archiveHeight + unconfirmedSessionHeight} + maxHeight={chatsHeight + archiveHeight + frozenNotificationHeight + unconfirmedSessionHeight} onLoadMore={getMore} onDragLeave={handleDragLeave} > @@ -255,6 +266,12 @@ const ChatList: FC = ({ onHeightChange={setUnconfirmedSessionHeight} /> )} + {shouldShowFrozenAccountNotification && ( + + )} {shouldDisplayArchive && ( void; +}; + +const FrozenAccountNotification = ({ onClick }: OwnProps) => { + const lang = useLang(); + + return ( +
+
{lang('TitleFrozenAccount')}
+
{lang('SubtitleFrozenAccount')}
+
+ ); +}; + +export default memo(FrozenAccountNotification); diff --git a/src/components/left/main/LeftMain.tsx b/src/components/left/main/LeftMain.tsx index 2d19841d3..a9915ec3b 100644 --- a/src/components/left/main/LeftMain.tsx +++ b/src/components/left/main/LeftMain.tsx @@ -43,6 +43,7 @@ type OwnProps = { onContentChange: (content: LeftColumnContent) => void; onSettingsScreenSelect: (screen: SettingsScreens) => void; onTopicSearch: NoneToVoidFunction; + isAccountFrozen?: boolean; onReset: () => void; }; @@ -67,6 +68,7 @@ const LeftMain: FC = ({ onSettingsScreenSelect, onReset, onTopicSearch, + isAccountFrozen, }) => { const { closeForumPanel } = getActions(); const [isNewChatButtonShown, setIsNewChatButtonShown] = useState(IS_TOUCH_ENV); @@ -243,6 +245,7 @@ const LeftMain: FC = ({ onNewPrivateChat={handleSelectContacts} onNewChannel={handleSelectNewChannel} onNewGroup={handleSelectNewGroup} + isAccountFrozen={isAccountFrozen} /> ); diff --git a/src/components/left/main/StatusButton.tsx b/src/components/left/main/StatusButton.tsx index 55e35590e..61d04fec9 100644 --- a/src/components/left/main/StatusButton.tsx +++ b/src/components/left/main/StatusButton.tsx @@ -5,7 +5,7 @@ import { getActions, withGlobal } from '../../../global'; import type { ApiEmojiStatusCollectible, ApiEmojiStatusType, ApiSticker } from '../../../api/types'; import { EMOJI_STATUS_LOOP_LIMIT } from '../../../config'; -import { selectUser } from '../../../global/selectors'; +import { selectIsCurrentUserFrozen, selectUser } from '../../../global/selectors'; import { getServerTime } from '../../../util/serverTime'; import useTimeout from '../../../hooks/schedulers/useTimeout'; @@ -22,13 +22,14 @@ import StatusPickerMenu from './StatusPickerMenu.async'; interface StateProps { emojiStatus?: ApiEmojiStatusType; collectibleStatuses?: ApiEmojiStatusType[]; + isAccountFrozen?: boolean; } const EFFECT_DURATION_MS = 1500; const EMOJI_STATUS_SIZE = 24; -const StatusButton: FC = ({ emojiStatus, collectibleStatuses }) => { - const { setEmojiStatus, loadCurrentUser } = getActions(); +const StatusButton: FC = ({ emojiStatus, collectibleStatuses, isAccountFrozen }) => { + const { setEmojiStatus, loadCurrentUser, openFrozenAccountModal } = getActions(); // eslint-disable-next-line no-null/no-null const buttonRef = useRef(null); @@ -60,8 +61,12 @@ const StatusButton: FC = ({ emojiStatus, collectibleStatuses }) => { useTimeout(hideEffect, isEffectShown ? EFFECT_DURATION_MS : undefined); const handleEmojiStatusClick = useCallback(() => { + if (isAccountFrozen) { + openFrozenAccountModal(); + return; + } openStatusPicker(); - }, [openStatusPicker]); + }, [openStatusPicker, isAccountFrozen]); return (
@@ -105,9 +110,11 @@ export default memo(withGlobal((global): StateProps => { const { currentUserId } = global; const currentUser = currentUserId ? selectUser(global, currentUserId) : undefined; const collectibleStatuses = global.collectibleEmojiStatuses?.statuses; + const isAccountFrozen = selectIsCurrentUserFrozen(global); return { emojiStatus: currentUser?.emojiStatus, collectibleStatuses, + isAccountFrozen, }; })(StatusButton)); diff --git a/src/components/left/settings/SettingsPrivacy.tsx b/src/components/left/settings/SettingsPrivacy.tsx index 636e4b210..c5f2370e3 100644 --- a/src/components/left/settings/SettingsPrivacy.tsx +++ b/src/components/left/settings/SettingsPrivacy.tsx @@ -6,7 +6,10 @@ import type { ApiPrivacySettings } from '../../../api/types'; import type { GlobalState } from '../../../global/types'; import { SettingsScreens } from '../../../types'; -import { selectCanSetPasscode, selectIsCurrentUserPremium } from '../../../global/selectors'; +import { + selectCanSetPasscode, selectIsCurrentUserFrozen, + selectIsCurrentUserPremium, +} from '../../../global/selectors'; import { selectSharedSettings } from '../../../global/selectors/sharedState'; import useHistoryBack from '../../../hooks/useHistoryBack'; @@ -37,6 +40,7 @@ type StateProps = { shouldNewNonContactPeersRequirePremium?: boolean; shouldChargeForMessages: boolean; canDisplayChatInTitle?: boolean; + isCurrentUserFrozen?: boolean; privacy: GlobalState['settings']['privacy']; }; @@ -58,6 +62,7 @@ const SettingsPrivacy: FC = ({ privacy, onScreenSelect, onReset, + isCurrentUserFrozen, }) => { const { loadPrivacySettings, @@ -71,17 +76,19 @@ const SettingsPrivacy: FC = ({ } = getActions(); useEffect(() => { - loadBlockedUsers(); - loadPrivacySettings(); - loadContentSettings(); - loadWebAuthorizations(); - }, []); + if (!isCurrentUserFrozen) { + loadBlockedUsers(); + loadPrivacySettings(); + loadContentSettings(); + loadWebAuthorizations(); + } + }, [isCurrentUserFrozen]); useEffect(() => { - if (isActive) { + if (isActive && !isCurrentUserFrozen) { loadGlobalPrivacySettings(); } - }, [isActive, loadGlobalPrivacySettings]); + }, [isActive, isCurrentUserFrozen, loadGlobalPrivacySettings]); const oldLang = useOldLang(); const lang = useLang(); @@ -419,6 +426,7 @@ export default memo(withGlobal( const { canDisplayChatInTitle } = selectSharedSettings(global); const shouldChargeForMessages = Boolean(nonContactPeersPaidStars); + const isCurrentUserFrozen = selectIsCurrentUserFrozen(global); return { isCurrentUserPremium: selectIsCurrentUserPremium(global), @@ -435,6 +443,7 @@ export default memo(withGlobal( privacy, canDisplayChatInTitle, canSetPasscode: selectCanSetPasscode(global), + isCurrentUserFrozen, }; }, )(SettingsPrivacy)); diff --git a/src/components/main/Main.tsx b/src/components/main/Main.tsx index b51d7da29..33e745a9b 100644 --- a/src/components/main/Main.tsx +++ b/src/components/main/Main.tsx @@ -19,6 +19,7 @@ import { selectChatFolder, selectChatMessage, selectCurrentMessageList, + selectIsCurrentUserFrozen, selectIsCurrentUserPremium, selectIsForwardModalOpen, selectIsMediaViewerOpen, @@ -141,6 +142,8 @@ type StateProps = { noRightColumnAnimation?: boolean; withInterfaceAnimations?: boolean; isSynced?: boolean; + isAccountFrozen?: boolean; + isAppConfigLoaded?: boolean; }; const APP_OUTDATED_TIMEOUT_MS = 5 * 60 * 1000; // 5 min @@ -194,6 +197,8 @@ const Main = ({ noRightColumnAnimation, isSynced, currentUserId, + isAccountFrozen, + isAppConfigLoaded, }: OwnProps & StateProps) => { const { initMain, @@ -248,6 +253,10 @@ const Main = ({ loadTopBotApps, loadPaidReactionPrivacy, loadPasswordInfo, + loadBotFreezeAppeal, + loadAllChats, + loadAllStories, + loadAllHiddenStories, } = getActions(); if (DEBUG && !DEBUG_isLogged) { @@ -309,45 +318,54 @@ const Main = ({ loadAppConfig(); loadPeerColors(); initMain(); - loadAvailableReactions(); - loadAnimatedEmojis(); - loadNotificationSettings(); - loadNotificationExceptions(); - loadAttachBots(); loadContactList(); - loadDefaultTopicIcons(); checkAppVersion(); - loadTopReactions(); + loadAuthorizations(); + loadPasswordInfo(); + } + }, [isMasterTab, isSynced]); + + // Initial API calls + useEffect(() => { + if (isMasterTab && isSynced && isAppConfigLoaded && !isAccountFrozen) { + loadAllChats({ listType: 'saved' }); + loadAllStories(); + loadAllHiddenStories(); loadRecentReactions(); loadDefaultTagReactions(); - loadFeaturedEmojiStickers(); + loadAttachBots(); + loadNotificationSettings(); + loadNotificationExceptions(); loadTopInlineBots(); - loadEmojiKeywords({ language: BASE_EMOJI_KEYWORD_LANG }); - loadTimezones(); - loadQuickReplies(); + loadTopReactions(); loadStarStatus(); + loadEmojiKeywords({ language: BASE_EMOJI_KEYWORD_LANG }); + loadFeaturedEmojiStickers(); + loadSavedReactionTags(); + loadTopBotApps(); + loadPaidReactionPrivacy(); + loadDefaultTopicIcons(); + loadAnimatedEmojis(); + loadAvailableReactions(); + loadUserCollectibleStatuses(); + loadGenericEmojiEffects(); loadPremiumGifts(); loadStarGifts(); loadAvailableEffects(); loadBirthdayNumbersStickers(); loadRestrictedEmojiStickers(); - loadGenericEmojiEffects(); - loadSavedReactionTags(); - loadAuthorizations(); - loadTopBotApps(); - loadPaidReactionPrivacy(); - loadPasswordInfo(); - loadUserCollectibleStatuses(); + loadQuickReplies(); + loadTimezones(); } - }, [isMasterTab, isSynced]); + }, [isMasterTab, isSynced, isAppConfigLoaded, isAccountFrozen]); // Initial Premium API calls useEffect(() => { - if (isMasterTab && isCurrentUserPremium) { + if (isMasterTab && isCurrentUserPremium && isAppConfigLoaded && !isAccountFrozen) { loadDefaultStatusIcons(); loadRecentEmojiStatuses(); } - }, [isCurrentUserPremium, isMasterTab]); + }, [isCurrentUserPremium, isMasterTab, isAppConfigLoaded, isAccountFrozen]); // Language-based API calls useEffect(() => { @@ -357,8 +375,6 @@ const Main = ({ } loadCountryList({ langCode: lang.code }); - - loadAttachBots(); } }, [lang, isMasterTab]); @@ -374,7 +390,7 @@ const Main = ({ // Sticker sets useEffect(() => { - if (isMasterTab && isSynced) { + if (isMasterTab && isSynced && isAppConfigLoaded && !isAccountFrozen) { if (!addedSetIds || !addedCustomEmojiIds) { loadStickerSets(); loadFavoriteStickers(); @@ -384,7 +400,11 @@ const Main = ({ loadAddedStickers(); } } - }, [addedSetIds, addedCustomEmojiIds, isMasterTab, isSynced]); + }, [addedSetIds, addedCustomEmojiIds, isMasterTab, isSynced, isAppConfigLoaded, isAccountFrozen]); + + useEffect(() => { + loadBotFreezeAppeal(); + }, [isAppConfigLoaded]); // Check version when service chat is ready useEffect(() => { @@ -636,6 +656,7 @@ export default memo(withGlobal( || !selectCanAnimateInterface(global); const deleteFolderDialog = deleteFolderDialogModal ? selectChatFolder(global, deleteFolderDialogModal) : undefined; + const isAccountFrozen = selectIsCurrentUserFrozen(global); return { currentUserId, @@ -681,6 +702,8 @@ export default memo(withGlobal( requestedDraft, noRightColumnAnimation, isSynced: global.isSynced, + isAccountFrozen, + isAppConfigLoaded: global.isAppConfigLoaded, }; }, )(Main)); diff --git a/src/components/middle/FrozenAccountPlaceholder.module.scss b/src/components/middle/FrozenAccountPlaceholder.module.scss new file mode 100644 index 000000000..5381f422e --- /dev/null +++ b/src/components/middle/FrozenAccountPlaceholder.module.scss @@ -0,0 +1,21 @@ +.root { + cursor: pointer; + + &:hover { + opacity: 0.85; + } +} + +.title { + color: var(--color-error); + font-weight: var(--font-weight-medium); + font-size: 1rem; + line-height: 1rem; +} + +.subtitle { + color: var(--color-text-secondary); + font-size: 0.875rem; + margin-top: 0.25rem; + line-height: 1rem; +} diff --git a/src/components/middle/FrozenAccountPlaceholder.tsx b/src/components/middle/FrozenAccountPlaceholder.tsx new file mode 100644 index 000000000..7249ab4ba --- /dev/null +++ b/src/components/middle/FrozenAccountPlaceholder.tsx @@ -0,0 +1,29 @@ +import React, { memo } from '../../lib/teact/teact'; +import { getActions } from '../../global'; + +import useLang from '../../hooks/useLang'; +import useLastCallback from '../../hooks/useLastCallback'; + +import styles from './FrozenAccountPlaceholder.module.scss'; + +function FrozenAccountPlaceholder() { + const lang = useLang(); + + const { openFrozenAccountModal } = getActions(); + + const handleClick = useLastCallback(() => { + openFrozenAccountModal(); + }); + + return ( +
+
{lang('ComposerTitleFrozenAccount')}
+
{lang('ComposerSubtitleFrozenAccount')}
+
+ ); +} + +export default memo(FrozenAccountPlaceholder); diff --git a/src/components/middle/HeaderActions.tsx b/src/components/middle/HeaderActions.tsx index b6c166a2d..b726e7471 100644 --- a/src/components/middle/HeaderActions.tsx +++ b/src/components/middle/HeaderActions.tsx @@ -23,6 +23,7 @@ import { selectChatFullInfo, selectIsChatBotNotStarted, selectIsChatWithSelf, + selectIsCurrentUserFrozen, selectIsInSelectMode, selectIsRightColumnShown, selectIsUserBlocked, @@ -82,6 +83,7 @@ interface StateProps { language: string; detectedChatLanguage?: string; doNotTranslate: string[]; + isAccountFrozen?: boolean; } // Chrome breaks layout when focusing input during transition @@ -121,6 +123,7 @@ const HeaderActions: FC = ({ detectedChatLanguage, doNotTranslate, onTopicSearch, + isAccountFrozen, }) => { const { joinChannel, @@ -137,6 +140,7 @@ const HeaderActions: FC = ({ setSettingOption, unblockUser, setViewForumAsMessages, + openFrozenAccountModal, } = getActions(); // eslint-disable-next-line no-null/no-null const menuButtonRef = useRef(null); @@ -219,6 +223,10 @@ const HeaderActions: FC = ({ }); const handleRequestCall = useLastCallback(() => { + if (isAccountFrozen) { + openFrozenAccountModal(); + return; + } requestMasterAndRequestCall({ userId: chatId }); }); @@ -513,6 +521,7 @@ export default memo(withGlobal( const isTranslating = Boolean(selectRequestedChatTranslationLanguage(global, chatId)); const canTranslate = selectCanTranslateChat(global, chatId) && !fullInfo?.isTranslationDisabled; + const isAccountFrozen = selectIsCurrentUserFrozen(global); return { noMenu: false, @@ -542,6 +551,7 @@ export default memo(withGlobal( doNotTranslate, detectedChatLanguage: chat.detectedLanguage, canUnblock, + isAccountFrozen, }; }, )(HeaderActions)); diff --git a/src/components/middle/HeaderMenuContainer.tsx b/src/components/middle/HeaderMenuContainer.tsx index d068c5f0a..56bba3dac 100644 --- a/src/components/middle/HeaderMenuContainer.tsx +++ b/src/components/middle/HeaderMenuContainer.tsx @@ -31,6 +31,7 @@ import { selectChatFullInfo, selectCurrentMessageList, selectIsChatWithSelf, + selectIsCurrentUserFrozen, selectIsRightColumnShown, selectNotifyDefaults, selectNotifyException, @@ -122,6 +123,7 @@ type StateProps = { isBot?: boolean; isChatWithSelf?: boolean; savedDialog?: ApiChat; + isAccountFrozen?: boolean; }; const CLOSE_MENU_ANIMATION_DURATION = 200; @@ -176,6 +178,7 @@ const HeaderMenuContainer: FC = ({ onAsMessagesClick, onClose, onCloseAnimationEnd, + isAccountFrozen, }) => { const { updateChatMutedState, @@ -186,6 +189,7 @@ const HeaderMenuContainer: FC = ({ createGroupCall, openLinkedChat, openAddContactDialog, + openFrozenAccountModal, requestMasterAndRequestCall, toggleStatistics, openMonetizationStatistics, @@ -224,14 +228,23 @@ const HeaderMenuContainer: FC = ({ }); const handleReport = useLastCallback(() => { - setIsMenuOpen(false); - reportMessages({ chatId, messageIds: [] }); + if (isAccountFrozen) { + openFrozenAccountModal(); + } else { + setIsMenuOpen(false); + reportMessages({ chatId, messageIds: [] }); + } onClose(); }); const handleDelete = useLastCallback(() => { + if (isAccountFrozen) { + openFrozenAccountModal(); + onClose(); + } else { + setIsDeleteModalOpen(true); + } setIsMenuOpen(false); - setIsDeleteModalOpen(true); }); const closeMenu = useLastCallback(() => { @@ -251,39 +264,68 @@ const HeaderMenuContainer: FC = ({ }); const handleStartBot = useLastCallback(() => { - sendBotCommand({ command: '/start' }); + if (isAccountFrozen) { + openFrozenAccountModal(); + } else { + sendBotCommand({ command: '/start' }); + } }); const handleRestartBot = useLastCallback(() => { - restartBot({ chatId }); + if (isAccountFrozen) { + openFrozenAccountModal(); + } else { + restartBot({ chatId }); + } }); const handleUnmuteClick = useLastCallback(() => { - updateChatMutedState({ chatId, isMuted: false }); + if (isAccountFrozen) { + openFrozenAccountModal(); + } else { + updateChatMutedState({ chatId, isMuted: false }); + } closeMenu(); }); const handleMuteClick = useLastCallback(() => { - markRenderMuteModal(); - setIsMuteModalOpen(true); + if (isAccountFrozen) { + openFrozenAccountModal(); + closeMenu(); + } else { + markRenderMuteModal(); + setIsMuteModalOpen(true); + } setIsMenuOpen(false); }); const handleCreateTopicClick = useLastCallback(() => { - openCreateTopicPanel({ chatId }); - setShouldCloseFast(!isRightColumnShown); + if (isAccountFrozen) { + openFrozenAccountModal(); + } else { + openCreateTopicPanel({ chatId }); + setShouldCloseFast(!isRightColumnShown); + } closeMenu(); }); const handleEditClick = useLastCallback(() => { - toggleManagement({ force: true }); - setShouldCloseFast(!isRightColumnShown); + if (isAccountFrozen) { + openFrozenAccountModal(); + } else { + toggleManagement({ force: true }); + setShouldCloseFast(!isRightColumnShown); + } closeMenu(); }); const handleEditTopicClick = useLastCallback(() => { - openEditTopicPanel({ chatId, topicId: Number(threadId) }); - setShouldCloseFast(!isRightColumnShown); + if (isAccountFrozen) { + openFrozenAccountModal(); + } else { + openEditTopicPanel({ chatId, topicId: Number(threadId) }); + setShouldCloseFast(!isRightColumnShown); + } closeMenu(); }); @@ -294,7 +336,9 @@ const HeaderMenuContainer: FC = ({ }); const handleEnterVoiceChatClick = useLastCallback(() => { - if (canCreateVoiceChat) { + if (isAccountFrozen) { + openFrozenAccountModal(); + } else if (canCreateVoiceChat) { // TODO Show popup to schedule createGroupCall({ chatId, @@ -313,27 +357,47 @@ const HeaderMenuContainer: FC = ({ }); const handleGiftClick = useLastCallback(() => { - openGiftModal({ forUserId: chatId }); + if (isAccountFrozen) { + openFrozenAccountModal(); + } else { + openGiftModal({ forUserId: chatId }); + } closeMenu(); }); const handleAddContactClick = useLastCallback(() => { - openAddContactDialog({ userId: chatId }); + if (isAccountFrozen) { + openFrozenAccountModal(); + } else { + openAddContactDialog({ userId: chatId }); + } closeMenu(); }); const handleSubscribe = useLastCallback(() => { - onSubscribeChannel(); + if (isAccountFrozen) { + openFrozenAccountModal(); + } else { + onSubscribeChannel(); + } closeMenu(); }); const handleVideoCall = useLastCallback(() => { - requestMasterAndRequestCall({ userId: chatId, isVideo: true }); + if (isAccountFrozen) { + openFrozenAccountModal(); + } else { + requestMasterAndRequestCall({ userId: chatId, isVideo: true }); + } closeMenu(); }); const handleCall = useLastCallback(() => { - requestMasterAndRequestCall({ userId: chatId }); + if (isAccountFrozen) { + openFrozenAccountModal(); + } else { + requestMasterAndRequestCall({ userId: chatId }); + } closeMenu(); }); @@ -355,7 +419,9 @@ const HeaderMenuContainer: FC = ({ }); const handleBoostClick = useLastCallback(() => { - if (canViewBoosts) { + if (isAccountFrozen) { + openFrozenAccountModal(); + } else if (canViewBoosts) { openBoostStatistics({ chatId }); setShouldCloseFast(!isRightColumnShown); } else { @@ -370,7 +436,11 @@ const HeaderMenuContainer: FC = ({ }); const handleSelectMessages = useLastCallback(() => { - enterMessageSelectMode(); + if (isAccountFrozen) { + openFrozenAccountModal(); + } else { + enterMessageSelectMode(); + } closeMenu(); }); @@ -380,12 +450,20 @@ const HeaderMenuContainer: FC = ({ }); const handleBlock = useLastCallback(() => { - blockUser({ userId: chatId }); + if (isAccountFrozen) { + openFrozenAccountModal(); + } else { + blockUser({ userId: chatId }); + } closeMenu(); }); const handleUnblock = useLastCallback(() => { - unblockUser({ userId: chatId }); + if (isAccountFrozen) { + openFrozenAccountModal(); + } else { + unblockUser({ userId: chatId }); + } closeMenu(); }); @@ -756,6 +834,7 @@ export default memo(withGlobal( const isSavedDialog = getIsSavedDialog(chatId, threadId, global.currentUserId); const savedDialog = isSavedDialog ? selectChat(global, String(threadId)) : undefined; + const isAccountFrozen = selectIsCurrentUserFrozen(global); return { chat, @@ -782,6 +861,7 @@ export default memo(withGlobal( isBot: Boolean(chatBot), isChatWithSelf, savedDialog, + isAccountFrozen, }; }, )(HeaderMenuContainer)); diff --git a/src/components/middle/MessageList.tsx b/src/components/middle/MessageList.tsx index 1949e13fb..f95ba94d8 100644 --- a/src/components/middle/MessageList.tsx +++ b/src/components/middle/MessageList.tsx @@ -43,6 +43,7 @@ import { selectFocusedMessageId, selectIsChatProtected, selectIsChatWithSelf, + selectIsCurrentUserFrozen, selectIsCurrentUserPremium, selectIsInSelectMode, selectIsViewportNewest, @@ -130,10 +131,12 @@ type StateProps = { isEmptyThread?: boolean; isForum?: boolean; currentUserId: string; + isAccountFrozen?: boolean; areAdsEnabled?: boolean; channelJoinInfo?: ApiChatFullInfo['joinInfo']; isChatProtected?: boolean; hasCustomGreeting?: boolean; + isAppConfigLoaded?: boolean; }; const MESSAGE_REACTIONS_POLLING_INTERVAL = 20 * 1000; @@ -196,7 +199,9 @@ const MessageList: FC = ({ onIntersectPinnedMessage, onScrollDownToggle, onNotchToggle, + isAccountFrozen, hasCustomGreeting, + isAppConfigLoaded, }) => { const { loadViewportMessages, setScrollOffset, loadSponsoredMessages, loadMessageReactions, copyMessagesByIds, @@ -248,10 +253,10 @@ const MessageList: FC = ({ useEffect(() => { const canHaveAds = isChannelChat || isBot; - if (areAdsEnabled && canHaveAds && isSynced && isReady) { + if (areAdsEnabled && canHaveAds && isSynced && isReady && isAppConfigLoaded) { loadSponsoredMessages({ peerId: chatId }); } - }, [chatId, isSynced, isReady, isChannelChat, isBot, areAdsEnabled]); + }, [chatId, isSynced, isReady, isChannelChat, isBot, areAdsEnabled, isAppConfigLoaded]); // Updated only once when messages are loaded (as we want the unread divider to keep its position) useSyncEffect(() => { @@ -344,7 +349,7 @@ const MessageList: FC = ({ threadId, isChatWithSelf, channelJoinInfo]); useInterval(() => { - if (!messageIds || !messagesById || type === 'scheduled') return; + if (!messageIds || !messagesById || type === 'scheduled' || isAccountFrozen) return; if (!isChannelChat && !isGroupChat) return; const ids = messageIds.filter((id) => { @@ -796,8 +801,10 @@ export default memo(withGlobal( const isCurrentUserPremium = selectIsCurrentUserPremium(global); const areAdsEnabled = !isCurrentUserPremium || selectUserFullInfo(global, currentUserId)?.areAdsEnabled; + const isAccountFrozen = selectIsCurrentUserFrozen(global); const hasCustomGreeting = Boolean(userFullInfo?.businessIntro); + const isAppConfigLoaded = global.isAppConfigLoaded; return { areAdsEnabled, @@ -832,7 +839,9 @@ export default memo(withGlobal( currentUserId, isChatProtected: selectIsChatProtected(global, chatId), ...(withLastMessageWhenPreloading && { lastMessage }), + isAccountFrozen, hasCustomGreeting, + isAppConfigLoaded, }; }, )(MessageList)); diff --git a/src/components/middle/MiddleColumn.scss b/src/components/middle/MiddleColumn.scss index 1085de5db..fc7e50191 100644 --- a/src/components/middle/MiddleColumn.scss +++ b/src/components/middle/MiddleColumn.scss @@ -266,14 +266,19 @@ } .MessageSelectToolbar-inner, -.composer-button, -.messaging-disabled { +.composer-button { .mask-image-disabled & { box-shadow: 0 0.25rem 0.5rem 0.125rem var(--color-default-shadow); border-radius: var(--border-radius-messages); } } +.messaging-disabled { + .mask-image-disabled & { + border-radius: var(--border-radius-messages); + } +} + .middle-column-footer-button-container { width: 100%; display: flex; diff --git a/src/components/middle/MiddleColumn.tsx b/src/components/middle/MiddleColumn.tsx index b93308f81..38f4ae42a 100644 --- a/src/components/middle/MiddleColumn.tsx +++ b/src/components/middle/MiddleColumn.tsx @@ -47,6 +47,7 @@ import { selectCurrentMiddleSearch, selectDraft, selectIsChatBotNotStarted, + selectIsCurrentUserFrozen, selectIsInSelectMode, selectIsRightColumnShown, selectIsUserBlocked, @@ -93,6 +94,7 @@ import ChatLanguageModal from './ChatLanguageModal.async'; import { DropAreaState } from './composer/DropArea'; import EmojiInteractionAnimation from './EmojiInteractionAnimation.async'; import FloatingActionButtons from './FloatingActionButtons'; +import FrozenAccountPlaceholder from './FrozenAccountPlaceholder'; import MessageList from './MessageList'; import MessageSelectToolbar from './MessageSelectToolbar.async'; import MiddleHeader from './MiddleHeader'; @@ -156,6 +158,8 @@ type StateProps = { isContactRequirePremium?: boolean; topics?: Record; paidMessagesStars?: number; + isAccountFrozen?: boolean; + freezeAppealChat?: ApiChat; }; function isImage(item: DataTransferItem) { @@ -217,6 +221,8 @@ function MiddleColumn({ isContactRequirePremium, topics, paidMessagesStars, + isAccountFrozen, + freezeAppealChat, }: OwnProps & StateProps) { const { openChat, @@ -448,7 +454,8 @@ function MiddleColumn({ const composerRestrictionMessage = messageSendingRestrictionReason ?? forumComposerPlaceholder - ?? (isContactRequirePremium ? : undefined); + ?? (isContactRequirePremium ? : undefined) + ?? (isAccountFrozen && freezeAppealChat?.id !== chatId ? : undefined); // CSS Variables calculation doesn't work properly with transforms, so we calculate transform values in JS const { @@ -477,7 +484,7 @@ function MiddleColumn({ const isMessagingDisabled = Boolean( !isPinnedMessageList && !isSavedDialog && !renderingCanPost && !renderingCanRestartBot && !renderingCanStartBot && !renderingCanSubscribe && composerRestrictionMessage, - ); + ) || (isAccountFrozen && freezeAppealChat?.id !== chatId); const withMessageListBottomShift = Boolean( renderingCanRestartBot || renderingCanSubscribe || renderingShouldSendJoinRequest || renderingCanStartBot || (isPinnedMessageList && canUnpin) || canShowOpenChatButton || renderingCanUnblock, @@ -809,6 +816,10 @@ export default memo(withGlobal( const isContactRequirePremium = userFull?.isContactRequirePremium; const paidMessagesStars = selectPeerPaidMessagesStars(global, chatId); + const isAccountFrozen = selectIsCurrentUserFrozen(global); + const botFreezeAppealId = global.botFreezeAppealId; + const freezeAppealChat = botFreezeAppealId + ? selectChat(global, botFreezeAppealId) : undefined; return { ...state, @@ -826,7 +837,8 @@ export default memo(withGlobal( && !isBotNotStarted && !(shouldJoinToSend && chat?.isNotJoined) && !shouldBlockSendInForum - && !isSavedDialog, + && !isSavedDialog + && (!isAccountFrozen || freezeAppealChat?.id === chatId), isPinnedMessageList, currentUserBannedRights: chat?.currentUserBannedRights, defaultBannedRights: chat?.defaultBannedRights, @@ -847,6 +859,8 @@ export default memo(withGlobal( isContactRequirePremium, topics, paidMessagesStars, + isAccountFrozen, + freezeAppealChat, }; }, )(MiddleColumn)); diff --git a/src/components/middle/message/ActionMessage.tsx b/src/components/middle/message/ActionMessage.tsx index f6c32fb70..616cc8e1a 100644 --- a/src/components/middle/message/ActionMessage.tsx +++ b/src/components/middle/message/ActionMessage.tsx @@ -19,6 +19,7 @@ import { getMessageReplyInfo } from '../../../global/helpers/replies'; import { selectChat, selectChatMessage, + selectIsCurrentUserFrozen, selectIsCurrentUserPremium, selectIsInSelectMode, selectIsMessageFocused, @@ -86,6 +87,7 @@ type StateProps = { hasUnreadReaction?: boolean; isResizingContainer?: boolean; scrollTargetPosition?: ScrollTargetPosition; + isAccountFrozen?: boolean; }; const SINGLE_LINE_ACTIONS: Set = new Set([ @@ -121,6 +123,7 @@ const ActionMessage = ({ observeIntersectionForBottom, observeIntersectionForLoading, observeIntersectionForPlaying, + isAccountFrozen, }: OwnProps & StateProps) => { const { requestConfetti, @@ -189,7 +192,7 @@ const ActionMessage = ({ handleContextMenuClose, handleContextMenuHide, } = useContextMenuHandlers( ref, - isTouchScreen && isInSelectMode, + (isTouchScreen && isInSelectMode) || isAccountFrozen, !IS_ELECTRON, IS_ANDROID, getIsMessageListReady, @@ -448,6 +451,7 @@ const ActionMessage = ({ threadId={threadId} observeIntersection={observeIntersectionForPlaying} isCurrentUserPremium={isCurrentUserPremium} + isAccountFrozen /> )}
@@ -479,6 +483,7 @@ export default memo(withGlobal( const isCurrentUserPremium = selectIsCurrentUserPremium(global); const hasUnreadReaction = chat?.unreadReactions?.includes(message.id); + const isAccountFrozen = selectIsCurrentUserFrozen(global); return { sender, @@ -494,6 +499,7 @@ export default memo(withGlobal( hasUnreadReaction, isResizingContainer, scrollTargetPosition, + isAccountFrozen, }; }, )(ActionMessage)); diff --git a/src/components/middle/message/ActionMessageText.tsx b/src/components/middle/message/ActionMessageText.tsx index ee038e453..af06dcd24 100644 --- a/src/components/middle/message/ActionMessageText.tsx +++ b/src/components/middle/message/ActionMessageText.tsx @@ -699,6 +699,31 @@ const ActionMessageText = ({ case 'customAction': return action.message; + case 'paidMessagesPrice': { + const { stars } = action; + if (stars === 0) { + return lang('ActionPaidMessageGroupPriceFree'); + } + return lang('ActionPaidMessageGroupPrice', { + stars: formatStarsAsText(lang, stars), + }, { withNodes: true, withMarkdown: true }); + } + + case 'paidMessagesRefunded': { + const { stars } = action; + const user = selectPeer(global, chatId); + const userTitle = (user && getPeerTitle(lang, user)) || userFallbackText; + + const key = isOutgoing + ? 'ApiMessageActionPaidMessagesRefundedOutgoing' + : 'ApiMessageActionPaidMessagesRefundedIncoming'; + + return lang(key, { + stars: formatStarsAsText(lang, stars), + user: renderPeerLink(user?.id, userTitle), + }, { withNodes: true, withMarkdown: true }); + } + case 'phoneCall': // Rendered as a regular message, but considered an action for the summary return lang(getCallMessageKey(action, isOutgoing)); default: diff --git a/src/components/middle/message/CommentButton.tsx b/src/components/middle/message/CommentButton.tsx index 0d67c2b64..8b963b671 100644 --- a/src/components/middle/message/CommentButton.tsx +++ b/src/components/middle/message/CommentButton.tsx @@ -4,7 +4,7 @@ import { getActions, getGlobal } from '../../../global'; import type { ApiCommentsInfo } from '../../../api/types'; -import { selectPeer } from '../../../global/selectors'; +import { selectIsCurrentUserFrozen, selectPeer } from '../../../global/selectors'; import buildClassName from '../../../util/buildClassName'; import { formatIntegerCompact } from '../../../util/textFormat'; @@ -36,7 +36,7 @@ const CommentButton: FC = ({ isLoading, asActionButton, }) => { - const { openThread } = getActions(); + const { openThread, openFrozenAccountModal } = getActions(); const shouldRenderLoading = useAsyncRendering([isLoading], SHOW_LOADER_DELAY); @@ -46,6 +46,11 @@ const CommentButton: FC = ({ } = threadInfo; const handleClick = useLastCallback(() => { + const global = getGlobal(); + if (selectIsCurrentUserFrozen(global)) { + openFrozenAccountModal(); + return; + } openThread({ isComments: true, chatId, originMessageId, originChannelId, }); diff --git a/src/components/middle/message/Message.tsx b/src/components/middle/message/Message.tsx index d01282e86..43c6be536 100644 --- a/src/components/middle/message/Message.tsx +++ b/src/components/middle/message/Message.tsx @@ -85,6 +85,7 @@ import { selectForwardedSender, selectIsChatProtected, selectIsChatWithSelf, + selectIsCurrentUserFrozen, selectIsCurrentUserPremium, selectIsDocumentGroupSelected, selectIsInSelectMode, @@ -305,6 +306,7 @@ type StateProps = { lastPlaybackTimestamp?: number; paidMessageStars?: number; isChatWithUser?: boolean; + isAccountFrozen?: boolean; }; type MetaPosition = @@ -428,6 +430,7 @@ const Message: FC = ({ onIntersectPinnedMessage, paidMessageStars, isChatWithUser, + isAccountFrozen, }) => { const { toggleMessageSelection, @@ -465,7 +468,7 @@ const Message: FC = ({ handleContextMenuHide, } = useContextMenuHandlers( ref, - isTouchScreen && isInSelectMode, + (isTouchScreen && isInSelectMode) || isAccountFrozen, !IS_ELECTRON, IS_ANDROID, getIsMessageListReady, @@ -570,6 +573,7 @@ const Message: FC = ({ const hasSubheader = hasTopicChip || hasMessageReply || hasStoryReply || hasForwardedCustomShape; const selectMessage = useLastCallback((e?: React.MouseEvent, groupedId?: string) => { + if (isAccountFrozen) return; toggleMessageSelection({ messageId, groupedId, @@ -768,7 +772,7 @@ const Message: FC = ({ && !isInDocumentGroupNotLast && messageListType === 'thread' && !noComments; const withQuickReactionButton = !isTouchScreen && !phoneCall && !isInSelectMode && defaultReaction - && !isInDocumentGroupNotLast && !isStoryMention && !hasTtl; + && !isInDocumentGroupNotLast && !isStoryMention && !hasTtl && !isAccountFrozen; const hasOutsideReactions = !withVoiceTranscription && hasReactions && (isCustomShape || ((photo || video || storyData || (location?.mediaType === 'geo')) && !hasText)); @@ -1048,6 +1052,7 @@ const Message: FC = ({ noRecentReactors={isChannel} tags={tags} isCurrentUserPremium={isPremium} + isAccountFrozen /> ); } @@ -1699,6 +1704,7 @@ const Message: FC = ({ observeIntersection={observeIntersectionForPlaying} noRecentReactors={isChannel} tags={tags} + isAccountFrozen /> )} @@ -1858,6 +1864,7 @@ export default memo(withGlobal( const maxTimestamp = selectMessageTimestampableDuration(global, message); const lastPlaybackTimestamp = selectMessageLastPlaybackTimestamp(global, chatId, message.id); + const isAccountFrozen = selectIsCurrentUserFrozen(global); return { theme: selectTheme(global), @@ -1951,6 +1958,7 @@ export default memo(withGlobal( lastPlaybackTimestamp, paidMessageStars, isChatWithUser, + isAccountFrozen, }; }, )(Message)); diff --git a/src/components/middle/message/reactions/Reactions.tsx b/src/components/middle/message/reactions/Reactions.tsx index 143224f38..bc43e2286 100644 --- a/src/components/middle/message/reactions/Reactions.tsx +++ b/src/components/middle/message/reactions/Reactions.tsx @@ -36,6 +36,7 @@ type OwnProps = { isCurrentUserPremium?: boolean; observeIntersection?: ObserveFn; noRecentReactors?: boolean; + isAccountFrozen?: boolean; }; const MAX_RECENT_AVATARS = 3; @@ -51,6 +52,7 @@ const Reactions: FC = ({ noRecentReactors, isCurrentUserPremium, tags, + isAccountFrozen, }) => { const { toggleReaction, @@ -60,6 +62,7 @@ const Reactions: FC = ({ openPremiumModal, resetLocalPaidReactions, showNotification, + openFrozenAccountModal, } = getActions(); const lang = useOldLang(); @@ -107,6 +110,10 @@ const Reactions: FC = ({ }, [message, noRecentReactors, recentReactorsByReactionKey, results, areTags, tags, totalCount]); const handleClick = useLastCallback((reaction: ApiReaction) => { + if (isAccountFrozen) { + openFrozenAccountModal(); + return; + } if (areTags) { if (!isCurrentUserPremium) { openPremiumModal({ @@ -130,6 +137,11 @@ const Reactions: FC = ({ const paidLocalCount = useMemo(() => results.find((r) => r.reaction.type === 'paid')?.localAmount || 0, [results]); const handlePaidClick = useLastCallback((count: number) => { + if (isAccountFrozen) { + openFrozenAccountModal(); + return; + } + addLocalPaidReaction({ chatId: message.chatId, messageId: message.id, @@ -162,6 +174,11 @@ const Reactions: FC = ({ }, [lang, message, paidLocalCount]); const handleRemoveReaction = useLastCallback((reaction: ApiReaction) => { + if (isAccountFrozen) { + openFrozenAccountModal(); + return; + } + toggleReaction({ chatId: message.chatId, messageId: message.id, diff --git a/src/components/modals/ModalContainer.tsx b/src/components/modals/ModalContainer.tsx index 896deb95a..ace221a46 100644 --- a/src/components/modals/ModalContainer.tsx +++ b/src/components/modals/ModalContainer.tsx @@ -15,6 +15,7 @@ import ChatInviteModal from './chatInvite/ChatInviteModal.async'; import ChatlistModal from './chatlist/ChatlistModal.async'; import CollectibleInfoModal from './collectible/CollectibleInfoModal.async'; import EmojiStatusAccessModal from './emojiStatusAccess/EmojiStatusAccessModal.async'; +import FrozenAccountModal from './frozenAccount/FrozenAccountModal.async'; import PremiumGiftModal from './gift/GiftModal.async'; import GiftInfoModal from './gift/info/GiftInfoModal.async'; import GiftRecipientPicker from './gift/recipient/GiftRecipientPicker.async'; @@ -79,7 +80,8 @@ type ModalKey = keyof Pick; type StateProps = { @@ -130,6 +132,7 @@ const MODALS: ModalRegistry = { sharePreparedMessageModal: SharePreparedMessageModal, giftTransferModal: GiftTransferModal, chatRefundModal: ChatRefundModal, + isFrozenAccountModalOpen: FrozenAccountModal, }; const MODAL_KEYS = Object.keys(MODALS) as ModalKey[]; const MODAL_ENTRIES = Object.entries(MODALS) as Entries; diff --git a/src/components/modals/emojiStatusAccess/EmojiStatusAccessModal.tsx b/src/components/modals/emojiStatusAccess/EmojiStatusAccessModal.tsx index 9683b47b7..160a5778a 100644 --- a/src/components/modals/emojiStatusAccess/EmojiStatusAccessModal.tsx +++ b/src/components/modals/emojiStatusAccess/EmojiStatusAccessModal.tsx @@ -9,7 +9,9 @@ import type { ApiStickerSet, ApiUser } from '../../../api/types'; import type { TabState } from '../../../global/types'; import { getUserFullName } from '../../../global/helpers'; -import { selectIsCurrentUserPremium, selectStickerSet, selectUser } from '../../../global/selectors'; +import { + selectIsCurrentUserFrozen, selectIsCurrentUserPremium, selectStickerSet, selectUser, +} from '../../../global/selectors'; import buildClassName from '../../../util/buildClassName'; import useInterval from '../../../hooks/schedulers/useInterval'; @@ -31,6 +33,7 @@ export type StateProps = { currentUser?: ApiUser; stickerSet?: ApiStickerSet; isPremium?: boolean; + isAccountFrozen?: boolean; }; const INTERVAL = 3200; @@ -40,6 +43,7 @@ const EmojiStatusAccessModal: FC = ({ currentUser, stickerSet, isPremium, + isAccountFrozen, }) => { const { closeEmojiStatusAccessModal, @@ -60,10 +64,10 @@ const EmojiStatusAccessModal: FC = ({ const [currentStatusIndex, setCurrentStatusIndex] = useState(0); useEffect(() => { - if (isOpen && !stickerSet?.stickers) { + if (isOpen && !stickerSet?.stickers && !isAccountFrozen) { loadDefaultStatusIcons(); } - }, [isOpen, stickerSet]); + }, [isOpen, stickerSet, isAccountFrozen]); const mockPeerWithStatus = useMemo(() => { if (!currentUser || !stickerSet?.stickers) return undefined; @@ -195,11 +199,13 @@ export default memo(withGlobal( const currentUser = selectUser(global, global.currentUserId!); const isPremium = selectIsCurrentUserPremium(global); const stickerSet = global.defaultStatusIconsId ? selectStickerSet(global, global.defaultStatusIconsId) : undefined; + const isAccountFrozen = selectIsCurrentUserFrozen(global); return { currentUser, stickerSet, isPremium, + isAccountFrozen, }; }, )(EmojiStatusAccessModal)); diff --git a/src/components/modals/frozenAccount/FrozenAccountModal.async.tsx b/src/components/modals/frozenAccount/FrozenAccountModal.async.tsx new file mode 100644 index 000000000..175830983 --- /dev/null +++ b/src/components/modals/frozenAccount/FrozenAccountModal.async.tsx @@ -0,0 +1,18 @@ +import type { FC } from '../../../lib/teact/teact'; +import React from '../../../lib/teact/teact'; + +import type { OwnProps } from './FrozenAccountModal'; + +import { Bundles } from '../../../util/moduleLoader'; + +import useModuleLoader from '../../../hooks/useModuleLoader'; + +const FrozenAccountModalAsync: FC = (props) => { + const { modal } = props; + const FrozenAccountModal = useModuleLoader(Bundles.Extra, 'FrozenAccountModal', modal); + + // eslint-disable-next-line react/jsx-props-no-spreading + return FrozenAccountModal ? : undefined; +}; + +export default FrozenAccountModalAsync; diff --git a/src/components/modals/frozenAccount/FrozenAccountModal.module.scss b/src/components/modals/frozenAccount/FrozenAccountModal.module.scss new file mode 100644 index 000000000..b7c7c560c --- /dev/null +++ b/src/components/modals/frozenAccount/FrozenAccountModal.module.scss @@ -0,0 +1,26 @@ +.header { + margin-top: 0.5rem; + margin-bottom: 0.75rem; + display: flex; + flex-direction: column; + align-items: center; + width: 100%; +} + +.title { + font-weight: var(--font-weight-medium); + font-size: 1.25rem; + text-align: center; + padding-top: 0.5rem; +} + +.footer { + margin-top: 0.5rem; + display: flex; + align-self: stretch; + flex-direction: column; +} + +.buttonAppeal { + margin-bottom: 0.5rem; +} diff --git a/src/components/modals/frozenAccount/FrozenAccountModal.tsx b/src/components/modals/frozenAccount/FrozenAccountModal.tsx new file mode 100644 index 000000000..0654f688e --- /dev/null +++ b/src/components/modals/frozenAccount/FrozenAccountModal.tsx @@ -0,0 +1,143 @@ +import React, { memo, useMemo } from '../../../lib/teact/teact'; +import { getActions, withGlobal } from '../../../global'; + +import type { TabState } from '../../../global/types'; + +import { selectUser } from '../../../global/selectors'; +import { formatDateToString } from '../../../util/dates/dateFormat'; +import { LOCAL_TGS_URLS } from '../../common/helpers/animatedAssets'; +import formatUsername from '../../common/helpers/formatUsername'; + +import useLang from '../../../hooks/useLang'; +import useLastCallback from '../../../hooks/useLastCallback'; + +import AnimatedIconWithPreview from '../../common/AnimatedIconWithPreview'; +import Button from '../../ui/Button'; +import Link from '../../ui/Link'; +import TableAboutModal, { type TableAboutData } from '../common/TableAboutModal'; + +import styles from './FrozenAccountModal.module.scss'; + +export type OwnProps = { + modal: TabState['isFrozenAccountModalOpen']; +}; + +type StateProps = { + freezeAppealUrl?: string; + botFreezeAppealUsername?: string; + freezeUntilDate?: number; +}; + +const FrozenAccountModal = ({ + modal, + freezeUntilDate, + freezeAppealUrl, + botFreezeAppealUsername, +}: OwnProps & StateProps) => { + const { + closeFrozenAccountModal, + openUrl, + } = getActions(); + const lang = useLang(); + + const isOpen = Boolean(modal); + + const handleClose = useLastCallback(() => { + closeFrozenAccountModal(); + }); + + const handleAppeal = useLastCallback(() => { + closeFrozenAccountModal(); + if (freezeAppealUrl) { + openUrl({ url: freezeAppealUrl }); + } + }); + + const header = useMemo(() => { + return ( +
+ +
+ {lang('FrozenAccountModalTitle')} +
+
+ ); + }, [lang]); + + const footer = useMemo(() => { + if (!isOpen) return undefined; + return ( +
+ + +
+ ); + }, [lang, isOpen]); + + if (!freezeUntilDate || !botFreezeAppealUsername) return undefined; + + const date = new Date(freezeUntilDate * 1000); + + const botLink = ( + + {formatUsername(botFreezeAppealUsername)} + + ); + + const listItemData = [ + ['hand-stop', lang('FrozenAccountViolationTitle'), lang('FrozenAccountViolationSubtitle')], + ['lock', lang('FrozenAccountReadOnlyTitle'), lang('FrozenAccountReadOnlySubtitle')], + ['frozen-time', lang('FrozenAccountAppealTitle'), + lang('FrozenAccountAppealSubtitle', { + botLink, + date: formatDateToString(date, lang.code), + }, { + withNodes: true, + })], + ] satisfies TableAboutData; + + return ( + + ); +}; + +export default memo(withGlobal( + (global): StateProps => { + const freezeUntilDate = global.appConfig?.freezeUntilDate; + const freezeAppealUrl = global.appConfig?.freezeAppealUrl; + const botFreezeAppealId = global.botFreezeAppealId; + const botFreezeAppealUsername = botFreezeAppealId + ? selectUser(global, botFreezeAppealId)?.usernames?.[0]?.username : undefined; + + return { + freezeUntilDate, + freezeAppealUrl, + botFreezeAppealUsername, + }; + }, +)(FrozenAccountModal)); diff --git a/src/components/story/Story.tsx b/src/components/story/Story.tsx index ef73a238b..d24ab43aa 100644 --- a/src/components/story/Story.tsx +++ b/src/components/story/Story.tsx @@ -19,6 +19,7 @@ import { isChatChannel, isUserId } from '../../global/helpers'; import { getPeerTitle } from '../../global/helpers/peers'; import { selectChat, + selectIsCurrentUserFrozen, selectIsCurrentUserPremium, selectPeer, selectPeerPaidMessagesStars, @@ -104,6 +105,7 @@ interface StateProps { stealthMode: ApiStealthMode; withHeaderAnimation?: boolean; paidMessagesStars?: number; + isAccountFrozen?: boolean; } const VIDEO_MIN_READY_STATE = IS_SAFARI ? 4 : 3; @@ -137,6 +139,7 @@ function Story({ onClose, onReport, paidMessagesStars, + isAccountFrozen, }: OwnProps & StateProps) { const { viewStory, @@ -233,7 +236,7 @@ function Story({ ? story.content.video.duration : undefined; - const shouldShowComposer = !(isOut && isUserStory) && !isChangelog && !isChannelStory; + const shouldShowComposer = !(isOut && isUserStory) && !isChangelog && !isChannelStory && !isAccountFrozen; const shouldShowFooter = isLoadedStory && !shouldShowComposer && (isOut || isChannelStory); const headerAnimation = isMobile && withHeaderAnimation ? 'slideFade' : 'none'; @@ -965,6 +968,7 @@ export default memo(withGlobal((global, { const fromPeer = isLoadedStory && story.fromId ? selectPeer(global, story.fromId) : undefined; const paidMessagesStars = selectPeerPaidMessagesStars(global, peerId); + const isAccountFrozen = selectIsCurrentUserFrozen(global); return { peer: (user || chat)!, @@ -982,5 +986,6 @@ export default memo(withGlobal((global, { stealthMode: global.stories.stealthMode, withHeaderAnimation, paidMessagesStars, + isAccountFrozen, }; })(Story)); diff --git a/src/global/actions/all.ts b/src/global/actions/all.ts index d192c886e..e57ff5345 100644 --- a/src/global/actions/all.ts +++ b/src/global/actions/all.ts @@ -23,6 +23,7 @@ import './ui/messages'; import './ui/globalSearch'; import './ui/middleSearch'; import './ui/stickerSearch'; +import './ui/account'; import './ui/users'; import './ui/settings'; import './ui/misc'; diff --git a/src/global/actions/api/bots.ts b/src/global/actions/api/bots.ts index 83773450c..fcb61d1f6 100644 --- a/src/global/actions/api/bots.ts +++ b/src/global/actions/api/bots.ts @@ -16,6 +16,7 @@ import { ManagementProgress } from '../../../types'; import { BOT_FATHER_USERNAME, GENERAL_REFETCH_INTERVAL, PAID_SEND_DELAY } from '../../../config'; import { copyTextToClipboard } from '../../../util/clipboard'; +import { getUsernameFromDeepLink } from '../../../util/deepLinkParser'; import { getCurrentTabId } from '../../../util/establishMultitabRole'; import { getTranslationFn } from '../../../util/localization'; import { formatStarsAsText } from '../../../util/localization/format'; @@ -55,6 +56,7 @@ import { selectCurrentChat, selectCurrentMessageList, selectDraft, + selectIsCurrentUserFrozen, selectIsTrustedBot, selectMessageReplyInfo, selectPeer, @@ -681,6 +683,11 @@ addActionHandler('requestMainWebView', async (global, actions, payload): Promise tabId = getCurrentTabId(), } = payload; + if (selectIsCurrentUserFrozen(global)) { + actions.openFrozenAccountModal({ tabId }); + return; + } + if (checkIfOpenOrActivate(global, botId, tabId)) return; const bot = selectUser(global, botId); @@ -1423,3 +1430,17 @@ addActionHandler('startBotFatherConversation', async (global, actions, payload): actions.openChat({ id: botFatherId, tabId }); }); + +addActionHandler('loadBotFreezeAppeal', async (global): Promise => { + const botUrl = global.appConfig?.freezeAppealUrl; + if (!botUrl) return; + const botAppealUsername = botUrl ? getUsernameFromDeepLink(botUrl) : undefined; + if (!botAppealUsername) return; + const chat = await fetchChatByUsername(global, botAppealUsername); + global = getGlobal(); + global = { + ...global, + botFreezeAppealId: chat?.id, + }; + setGlobal(global); +}); diff --git a/src/global/actions/api/chats.ts b/src/global/actions/api/chats.ts index 23d1585a3..f1a2bc288 100644 --- a/src/global/actions/api/chats.ts +++ b/src/global/actions/api/chats.ts @@ -113,6 +113,7 @@ import { selectDraft, selectIsChatPinned, selectIsChatWithSelf, + selectIsCurrentUserFrozen, selectLastServiceNotification, selectPeer, selectSimilarChannelIds, @@ -366,10 +367,11 @@ addActionHandler('openThread', async (global, actions, payload): Promise = }); } - const result = await callApi('fetchDiscussionMessage', { - chat: selectChat(global, loadingChatId)!, - messageId: Number(loadingThreadId), - }); + const result = selectIsCurrentUserFrozen(global) ? undefined + : await callApi('fetchDiscussionMessage', { + chat: selectChat(global, loadingChatId)!, + messageId: Number(loadingThreadId), + }); global = getGlobal(); loadingThread = selectTabState(global, tabId).loadingThread; @@ -630,6 +632,11 @@ addActionHandler('updateChatMutedState', (global, actions, payload): ActionRetur const { chatId, isMuted } = payload; let { mutedUntil } = payload; + if (selectIsCurrentUserFrozen(global)) { + actions.openFrozenAccountModal({ tabId: getCurrentTabId() }); + return; + } + const chat = selectChat(global, chatId); if (!chat) { return; @@ -911,6 +918,11 @@ addActionHandler('createGroupChat', async (global, actions, payload): Promise { const { id, folderId, tabId = getCurrentTabId() } = payload; + + if (selectIsCurrentUserFrozen(global)) { + actions.openFrozenAccountModal({ tabId }); + return; + } const chat = selectChat(global, id); if (!chat) { return; @@ -958,6 +970,12 @@ addActionHandler('toggleChatPinned', (global, actions, payload): ActionReturnTyp addActionHandler('toggleChatArchived', (global, actions, payload): ActionReturnType => { const { id } = payload; + + if (selectIsCurrentUserFrozen(global)) { + actions.openFrozenAccountModal({ tabId: getCurrentTabId() }); + return; + } + const chat = selectChat(global, id); if (chat) { void callApi('toggleChatArchived', { @@ -969,6 +987,12 @@ addActionHandler('toggleChatArchived', (global, actions, payload): ActionReturnT addActionHandler('toggleSavedDialogPinned', (global, actions, payload): ActionReturnType => { const { id, tabId = getCurrentTabId() } = payload; + + if (selectIsCurrentUserFrozen(global)) { + actions.openFrozenAccountModal({ tabId }); + return; + } + const chat = selectChat(global, id); if (!chat) { return; @@ -1171,6 +1195,11 @@ addActionHandler('deleteChatFolder', async (global, actions, payload): Promise { const { id } = payload; + + if (selectIsCurrentUserFrozen(global)) { + actions.openFrozenAccountModal({ tabId: getCurrentTabId() }); + return; + } const chat = selectChat(global, id); if (!chat) return; void callApi('toggleDialogUnread', { @@ -1180,7 +1209,14 @@ addActionHandler('markChatUnread', (global, actions, payload): ActionReturnType }); addActionHandler('markChatMessagesRead', async (global, actions, payload): Promise => { + if (selectIsCurrentUserFrozen(global)) return; const { id } = payload; + + if (selectIsCurrentUserFrozen(global)) { + actions.openFrozenAccountModal({ tabId: getCurrentTabId() }); + return; + } + const chat = selectChat(global, id); if (!chat) return; if (!chat.isForum) { @@ -1229,6 +1265,7 @@ addActionHandler('markChatRead', (global, actions, payload): ActionReturnType => }); addActionHandler('markTopicRead', (global, actions, payload): ActionReturnType => { + if (selectIsCurrentUserFrozen(global)) return; const { chatId, topicId } = payload; const chat = selectChat(global, chatId); if (!chat) return; @@ -1784,6 +1821,8 @@ addActionHandler('updateChatMemberBannedRights', async (global, actions, payload }); addActionHandler('updateChatAdmin', async (global, actions, payload): Promise => { + if (selectIsCurrentUserFrozen(global)) return; + const { chatId, userId, adminRights, customTitle, tabId = getCurrentTabId(), @@ -1942,6 +1981,7 @@ addActionHandler('loadGroupsForDiscussion', async (global): Promise => { }); addActionHandler('linkDiscussionGroup', async (global, actions, payload): Promise => { + if (selectIsCurrentUserFrozen(global)) return; const { channelId, chatId, tabId = getCurrentTabId() } = payload || {}; const channel = selectChat(global, channelId); @@ -2023,6 +2063,7 @@ addActionHandler('resetOpenChatWithDraft', (global, actions, payload): ActionRet }); addActionHandler('loadMoreMembers', async (global, actions, payload): Promise => { + if (selectIsCurrentUserFrozen(global)) return; const { tabId = getCurrentTabId() } = payload || {}; const { chatId } = selectCurrentMessageList(global, tabId) || {}; const chat = chatId ? selectChat(global, chatId) : undefined; @@ -2211,7 +2252,11 @@ addActionHandler('processAttachBotParameters', async (global, actions, payload): }); addActionHandler('loadTopics', async (global, actions, payload): Promise => { + if (selectIsCurrentUserFrozen(global)) return; const { chatId, force } = payload; + if (selectIsCurrentUserFrozen(global)) { + return; + } const chat = selectChat(global, chatId); if (!chat) return; @@ -2780,6 +2825,8 @@ addActionHandler('setViewForumAsMessages', (global, actions, payload): ActionRet }); addActionHandler('loadChannelRecommendations', async (global, actions, payload): Promise => { + if (selectIsCurrentUserFrozen(global)) return; + const { chatId } = payload; const chat = chatId ? selectChat(global, chatId) : undefined; @@ -2810,6 +2857,8 @@ addActionHandler('loadChannelRecommendations', async (global, actions, payload): }); addActionHandler('loadBotRecommendations', async (global, actions, payload): Promise => { + if (selectIsCurrentUserFrozen(global)) return; + const { userId } = payload; const user = selectChat(global, userId); @@ -2915,20 +2964,21 @@ async function loadChats( const isFirstBatch = !shouldIgnorePagination && !offsetPeer && !offsetDate && !offsetId; const shouldReplaceStaleState = listType === 'active' && isFirstBatch; + const isAccountFreeze = selectIsCurrentUserFrozen(global); const result = listType === 'saved' ? await callApi('fetchSavedChats', { limit: CHAT_LIST_LOAD_SLICE, offsetDate, offsetId, offsetPeer, - withPinned: isFirstBatch, + withPinned: isFirstBatch && !isAccountFreeze, }) : await callApi('fetchChats', { limit: CHAT_LIST_LOAD_SLICE, offsetDate, offsetId, offsetPeer, archived: listType === 'archived', - withPinned: isFirstBatch, + withPinned: isFirstBatch && !isAccountFreeze, lastLocalServiceMessageId, }); @@ -3002,6 +3052,7 @@ async function loadChats( export async function loadFullChat( global: T, actions: RequiredGlobalActions, chat: ApiChat, ) { + if (selectIsCurrentUserFrozen(global)) return undefined; const result = await callApi('fetchFullChat', chat); if (!result) { return undefined; diff --git a/src/global/actions/api/management.ts b/src/global/actions/api/management.ts index 5577d5855..82b24ce5e 100644 --- a/src/global/actions/api/management.ts +++ b/src/global/actions/api/management.ts @@ -10,7 +10,8 @@ import { updateChat, updateChatFullInfo, updateManagement, updateManagementProgress, updateUserFullInfo, } from '../../reducers'; import { - selectChat, selectCurrentMessageList, selectTabState, selectUser, + selectChat, selectCurrentMessageList, selectIsCurrentUserFrozen, + selectTabState, selectUser, } from '../../selectors'; import { ensureIsSuperGroup } from './chats'; @@ -109,6 +110,8 @@ addActionHandler('setOpenedInviteInfo', (global, actions, payload): ActionReturn }); addActionHandler('loadExportedChatInvites', async (global, actions, payload): Promise => { + if (selectIsCurrentUserFrozen(global)) return; + const { chatId, adminId, isRevoked, limit, tabId = getCurrentTabId(), } = payload!; diff --git a/src/global/actions/api/messages.ts b/src/global/actions/api/messages.ts index 969de0723..df74ac92a 100644 --- a/src/global/actions/api/messages.ts +++ b/src/global/actions/api/messages.ts @@ -120,6 +120,7 @@ import { selectForwardsContainVoiceMessages, selectIsChatBotNotStarted, selectIsChatWithSelf, + selectIsCurrentUserFrozen, selectIsCurrentUserPremium, selectLanguageCode, selectListedIds, @@ -994,6 +995,7 @@ addActionHandler('reportChannelSpam', (global, actions, payload): ActionReturnTy }); addActionHandler('markMessageListRead', (global, actions, payload): ActionReturnType => { + if (selectIsCurrentUserFrozen(global)) return undefined; const { maxId, tabId = getCurrentTabId() } = payload!; const currentMessageList = selectCurrentMessageList(global, tabId); @@ -1177,6 +1179,8 @@ addActionHandler('loadExtendedMedia', (global, actions, payload): ActionReturnTy }); addActionHandler('loadScheduledHistory', async (global, actions, payload): Promise => { + if (selectIsCurrentUserFrozen(global)) return; + const { chatId } = payload; const chat = selectChat(global, chatId); if (!chat) { @@ -1852,6 +1856,8 @@ addActionHandler('loadSendPaidReactionsAs', async (global, actions, payload): Pr }); addActionHandler('loadSponsoredMessages', async (global, actions, payload): Promise => { + if (selectIsCurrentUserFrozen(global)) return; + const { peerId } = payload; const peer = selectPeer(global, peerId); if (!peer) { @@ -1880,7 +1886,7 @@ addActionHandler('viewSponsoredMessage', (global, actions, payload): ActionRetur return; } - void callApi('viewSponsoredMessage', { peer, random: message.randomId }); + void callApi('viewSponsoredMessage', { random: message.randomId }); }); addActionHandler('clickSponsoredMessage', (global, actions, payload): ActionReturnType => { @@ -1892,7 +1898,7 @@ addActionHandler('clickSponsoredMessage', (global, actions, payload): ActionRetu } void callApi('clickSponsoredMessage', { - peer, random: message.randomId, isMedia, isFullscreen, + random: message.randomId, isMedia, isFullscreen, }); }); @@ -1905,7 +1911,7 @@ addActionHandler('reportSponsoredMessage', async (global, actions, payload): Pro return; } - const result = await callApi('reportSponsoredMessage', { peer, randomId, option }); + const result = await callApi('reportSponsoredMessage', { randomId, option }); if (!result) return; @@ -2352,6 +2358,8 @@ addActionHandler('scheduleForViewsIncrement', (global, actions, payload): Action addActionHandler('loadMessageViews', async (global, actions, payload): Promise => { const { chatId, ids, shouldIncrement } = payload; + if (selectIsCurrentUserFrozen(global)) return; + const chat = selectChat(global, chatId); if (!chat) return; diff --git a/src/global/actions/api/payments.ts b/src/global/actions/api/payments.ts index 0dc75c6b3..e821e1a4e 100644 --- a/src/global/actions/api/payments.ts +++ b/src/global/actions/api/payments.ts @@ -40,6 +40,7 @@ import { updateTabState } from '../../reducers/tabs'; import { selectChat, selectChatFullInfo, + selectIsCurrentUserFrozen, selectPaymentInputInvoice, selectPaymentRequestId, selectProviderPublicToken, @@ -530,6 +531,11 @@ addActionHandler('openGiftModal', async (global, actions, payload): Promise => { + if (selectIsCurrentUserFrozen(global)) return; + const { chatId, messageId, reaction } = payload; const chat = selectChat(global, chatId); const message = selectChatMessage(global, chatId, messageId); @@ -418,6 +421,8 @@ addActionHandler('loadReactors', async (global, actions, payload): Promise }); addActionHandler('loadMessageReactions', (global, actions, payload): ActionReturnType => { + if (selectIsCurrentUserFrozen(global)) return; + const { ids, chatId } = payload; const chat = selectChat(global, chatId); diff --git a/src/global/actions/api/settings.ts b/src/global/actions/api/settings.ts index 4d65a05f7..1d7429693 100644 --- a/src/global/actions/api/settings.ts +++ b/src/global/actions/api/settings.ts @@ -22,7 +22,8 @@ import { } from '../../reducers'; import { updateTabState } from '../../reducers/tabs'; import { - selectChat, selectTabState, selectUser, + selectChat, selectIsCurrentUserFrozen, + selectTabState, selectUser, } from '../../selectors'; import { selectSharedSettings } from '../../selectors/sharedState'; @@ -390,6 +391,8 @@ addActionHandler('loadLanguages', async (global): Promise => { }); addActionHandler('loadPrivacySettings', async (global): Promise => { + if (selectIsCurrentUserFrozen(global)) return; + const result = await Promise.all([ callApi('fetchPrivacySettings', 'phoneNumber'), callApi('fetchPrivacySettings', 'addByPhone'), @@ -574,6 +577,8 @@ addActionHandler('updateIsOnline', (global, actions, payload): ActionReturnType }); addActionHandler('loadContentSettings', async (global): Promise => { + if (selectIsCurrentUserFrozen(global)) return; + const result = await callApi('fetchContentSettings'); if (!result) return; @@ -644,6 +649,7 @@ addActionHandler('loadAppConfig', async (global, actions, payload): Promise => { + if (selectIsCurrentUserFrozen(global)) return; + const { peerId } = payload; const peer = selectPeer(global, peerId); if (!peer) return; @@ -296,6 +299,8 @@ addActionHandler('loadPeerStories', async (global, actions, payload): Promise => { + if (selectIsCurrentUserFrozen(global)) return; + const { peerId, offsetId } = payload; const peer = selectPeer(global, peerId); let peerStories = selectPeerStories(global, peerId); @@ -320,6 +325,8 @@ addActionHandler('loadPeerProfileStories', async (global, actions, payload): Pro }); addActionHandler('loadStoriesArchive', async (global, actions, payload): Promise => { + if (selectIsCurrentUserFrozen(global)) return; + const { peerId, offsetId } = payload; const peer = selectPeer(global, peerId); let peerStories = selectPeerStories(global, peerId); diff --git a/src/global/actions/api/symbols.ts b/src/global/actions/api/symbols.ts index b58b2830d..3c1a3c9c7 100644 --- a/src/global/actions/api/symbols.ts +++ b/src/global/actions/api/symbols.ts @@ -29,7 +29,9 @@ import { updateStickersForEmoji, } from '../../reducers'; import { updateTabState } from '../../reducers/tabs'; -import { selectIsCurrentUserPremium, selectStickerSet, selectTabState } from '../../selectors'; +import { + selectIsCurrentUserFrozen, selectIsCurrentUserPremium, selectStickerSet, selectTabState, +} from '../../selectors'; import { selectCurrentLimit, selectPremiumLimit } from '../../selectors/limits'; const ADDED_SETS_THROTTLE = 200; @@ -128,6 +130,10 @@ addActionHandler('loadFavoriteStickers', async (global): Promise => { addActionHandler('loadPremiumStickers', async (global): Promise => { const { hash } = global.stickers.premium || {}; + if (selectIsCurrentUserFrozen(global)) { + return; + } + const result = await callApi('fetchStickersForEmoji', { emoji: '⭐️⭐️', hash }); if (!result) { return; @@ -151,6 +157,10 @@ addActionHandler('loadPremiumStickers', async (global): Promise => { addActionHandler('loadGreetingStickers', async (global): Promise => { const { hash } = global.stickers.greeting || {}; + if (selectIsCurrentUserFrozen(global)) { + return; + } + const greeting = await callApi('fetchStickersForEmoji', { emoji: '👋⭐️', hash }); if (!greeting) { return; diff --git a/src/global/actions/api/sync.ts b/src/global/actions/api/sync.ts index f1613601a..d3600d7af 100644 --- a/src/global/actions/api/sync.ts +++ b/src/global/actions/api/sync.ts @@ -66,7 +66,7 @@ addActionHandler('sync', (global, actions): ActionReturnType => { }, RELEASE_STATUS_TIMEOUT); const { - loadAllChats, preloadTopChatMessages, loadAllStories, loadAllHiddenStories, + loadAllChats, preloadTopChatMessages, } = actions; initFolderManager(); @@ -91,10 +91,7 @@ addActionHandler('sync', (global, actions): ActionReturnType => { } loadAllChats({ listType: 'archived' }); - loadAllChats({ listType: 'saved' }); preloadTopChatMessages(); - loadAllStories(); - loadAllHiddenStories(); }, }); }); diff --git a/src/global/actions/api/users.ts b/src/global/actions/api/users.ts index 2766b0434..75fcda4b1 100644 --- a/src/global/actions/api/users.ts +++ b/src/global/actions/api/users.ts @@ -30,6 +30,7 @@ import { updateTabState } from '../../reducers/tabs'; import { selectChat, selectChatFullInfo, + selectIsCurrentUserFrozen, selectIsCurrentUserPremium, selectPeer, selectPeerPhotos, @@ -159,6 +160,11 @@ addActionHandler('loadCurrentUser', (): ActionReturnType => { addActionHandler('loadCommonChats', async (global, actions, payload): Promise => { const { userId } = payload; + + if (selectIsCurrentUserFrozen(global)) { + return; + } + const user = selectUser(global, userId); const commonChats = selectUserCommonChats(global, userId); if (!user || isUserBot(user) || commonChats?.isFullyLoaded) { @@ -294,6 +300,8 @@ addActionHandler('deleteContact', async (global, actions, payload): Promise => { + if (selectIsCurrentUserFrozen(global)) return; + const { peerId, shouldInvalidateCache, isPreload } = payload; const isPrivate = isUserId(peerId); @@ -550,6 +558,8 @@ addActionHandler('openSuggestedStatusModal', async (global, actions, payload): P addActionHandler('loadPeerSettings', async (global, actions, payload): Promise => { const { peerId } = payload; + if (selectIsCurrentUserFrozen(global)) return; + const userFullInfo = selectUserFullInfo(global, peerId); if (!userFullInfo) { actions.loadFullUser({ userId: peerId }); diff --git a/src/global/actions/apiUpdaters/initial.ts b/src/global/actions/apiUpdaters/initial.ts index d3911c18e..ab38ad22d 100644 --- a/src/global/actions/apiUpdaters/initial.ts +++ b/src/global/actions/apiUpdaters/initial.ts @@ -95,6 +95,19 @@ addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => { break; } + + case 'notSupportedInFrozenAccount': { + actions.showNotification({ + title: { + key: 'NotificationTitleNotSupportedInFrozenAccount', + }, + message: { + key: 'NotificationMessageNotSupportedInFrozenAccount', + }, + tabId: getCurrentTabId(), + }); + break; + } } }); diff --git a/src/global/actions/ui/account.ts b/src/global/actions/ui/account.ts new file mode 100644 index 000000000..0760bcce3 --- /dev/null +++ b/src/global/actions/ui/account.ts @@ -0,0 +1,21 @@ +import type { ActionReturnType } from '../../types'; + +import { getCurrentTabId } from '../../../util/establishMultitabRole'; +import { addActionHandler } from '../..'; +import { updateTabState } from '../../reducers/tabs'; + +addActionHandler('openFrozenAccountModal', (global, actions, payload): ActionReturnType => { + const { tabId = getCurrentTabId() } = payload || {}; + + return updateTabState(global, { + isFrozenAccountModalOpen: true, + }, tabId); +}); + +addActionHandler('closeFrozenAccountModal', (global, actions, payload): ActionReturnType => { + const { tabId = getCurrentTabId() } = payload || {}; + + return updateTabState(global, { + isFrozenAccountModalOpen: false, + }, tabId); +}); diff --git a/src/global/actions/ui/calls.ts b/src/global/actions/ui/calls.ts index 31cba1356..326f07245 100644 --- a/src/global/actions/ui/calls.ts +++ b/src/global/actions/ui/calls.ts @@ -21,7 +21,8 @@ import { import { updateGroupCall } from '../../reducers/calls'; import { updateTabState } from '../../reducers/tabs'; import { - selectChat, selectChatFullInfo, selectTabState, selectUser, + selectChat, selectChatFullInfo, selectIsCurrentUserFrozen, + selectTabState, selectUser, } from '../../selectors'; import { selectActiveGroupCall, selectChatGroupCall, selectGroupCall } from '../../selectors/calls'; import { fetchChatByUsername, loadFullChat } from '../api/chats'; @@ -90,6 +91,7 @@ export function initializeSounds() { } async function fetchGroupCall(global: T, groupCall: Partial) { + if (selectIsCurrentUserFrozen(global)) return undefined; const result = await callApi('getGroupCall', { call: groupCall, }); @@ -130,6 +132,8 @@ addActionHandler('toggleGroupCallPanel', (global, actions, payload): ActionRetur }); addActionHandler('subscribeToGroupCallUpdates', async (global, actions, payload): Promise => { + if (selectIsCurrentUserFrozen(global)) return; + const { subscribed, id } = payload!; const groupCall = selectGroupCall(global, id); diff --git a/src/global/actions/ui/stars.ts b/src/global/actions/ui/stars.ts index dbb9a123c..ba391d40e 100644 --- a/src/global/actions/ui/stars.ts +++ b/src/global/actions/ui/stars.ts @@ -10,7 +10,9 @@ import { clearStarPayment, openStarsTransactionModal, } from '../../reducers'; import { updateTabState } from '../../reducers/tabs'; -import { selectChatMessage, selectStarsPayment, selectTabState } from '../../selectors'; +import { + selectChatMessage, selectIsCurrentUserFrozen, selectStarsPayment, selectTabState, +} from '../../selectors'; addActionHandler('processOriginStarsPayment', (global, actions, payload): ActionReturnType => { const { originData, status, tabId = getCurrentTabId() } = payload; @@ -59,6 +61,11 @@ addActionHandler('openGiftRecipientPicker', (global, actions, payload): ActionRe tabId = getCurrentTabId(), } = payload || {}; + if (selectIsCurrentUserFrozen(global)) { + actions.openFrozenAccountModal({ tabId }); + return global; + } + return updateTabState(global, { isGiftRecipientPickerOpen: true, }, tabId); diff --git a/src/global/actions/ui/users.ts b/src/global/actions/ui/users.ts index 7af3f6d93..da6006991 100644 --- a/src/global/actions/ui/users.ts +++ b/src/global/actions/ui/users.ts @@ -5,6 +5,7 @@ import { addTabStateResetterAction } from '../../helpers/meta'; import { addActionHandler } from '../../index'; import { closeNewContactDialog, updateUserSearch } from '../../reducers'; import { updateTabState } from '../../reducers/tabs'; +import { selectIsCurrentUserFrozen } from '../../selectors'; addActionHandler('setUserSearchQuery', (global, actions, payload): ActionReturnType => { const { @@ -23,6 +24,11 @@ addActionHandler('setUserSearchQuery', (global, actions, payload): ActionReturnT addActionHandler('openAddContactDialog', (global, actions, payload): ActionReturnType => { const { userId, tabId = getCurrentTabId() } = payload; + if (selectIsCurrentUserFrozen(global)) { + actions.openFrozenAccountModal({ tabId }); + return global; + } + return updateTabState(global, { newContact: { userId }, }, tabId); @@ -31,6 +37,11 @@ addActionHandler('openAddContactDialog', (global, actions, payload): ActionRetur addActionHandler('openNewContactDialog', (global, actions, payload): ActionReturnType => { const { tabId = getCurrentTabId() } = payload || {}; + if (selectIsCurrentUserFrozen(global)) { + actions.openFrozenAccountModal({ tabId }); + return global; + } + return updateTabState(global, { newContact: { isByPhoneNumber: true, diff --git a/src/global/selectors/users.ts b/src/global/selectors/users.ts index 3abccc6cd..fcaad9f1f 100644 --- a/src/global/selectors/users.ts +++ b/src/global/selectors/users.ts @@ -35,6 +35,10 @@ export function selectIsCurrentUserPremium(global: T) { return Boolean(global.users.byId[global.currentUserId].isPremium); } +export function selectIsCurrentUserFrozen(global: T) { + return Boolean(global.appConfig?.freezeUntilDate); +} + export function selectIsPremiumPurchaseBlocked(global: T) { return global.appConfig?.isPremiumPurchaseBlocked ?? true; } diff --git a/src/global/types/actions.ts b/src/global/types/actions.ts index b2e32eaa4..605c1bfe5 100644 --- a/src/global/types/actions.ts +++ b/src/global/types/actions.ts @@ -1026,6 +1026,8 @@ export interface ActionPayloads { changeSessionTtl: { days: number; }; + openFrozenAccountModal: WithTabId | undefined; + closeFrozenAccountModal: WithTabId | undefined; // Chats loadPeerSettings: { @@ -1713,6 +1715,7 @@ export interface ActionPayloads { startBotFatherConversation: { param: string; } & WithTabId; + loadBotFreezeAppeal: undefined; checkUsername: { username: string; } & WithTabId; diff --git a/src/global/types/globalState.ts b/src/global/types/globalState.ts index 4af463e25..027f59621 100644 --- a/src/global/types/globalState.ts +++ b/src/global/types/globalState.ts @@ -84,6 +84,7 @@ export type GlobalState = { connectionState?: ApiUpdateConnectionStateType; currentUserId?: string; isSyncing?: boolean; + isAppConfigLoaded?: boolean; isAppUpdateAvailable?: boolean; isElectronUpdateAvailable?: boolean; isSynced?: boolean; @@ -92,6 +93,7 @@ export type GlobalState = { lastIsChatInfoShown?: boolean; initialUnreadNotifications?: number; shouldShowContextMenuHint?: boolean; + botFreezeAppealId?: string; audioPlayer: { lastPlaybackRate: number; diff --git a/src/global/types/tabState.ts b/src/global/types/tabState.ts index 0fab521b5..0e121a98c 100644 --- a/src/global/types/tabState.ts +++ b/src/global/types/tabState.ts @@ -618,6 +618,8 @@ export type TabState = { isGiftRecipientPickerOpen?: boolean; + isFrozenAccountModalOpen?: boolean; + starsGiftingPickerModal?: { isOpen?: boolean; }; diff --git a/src/lib/gramjs/tl/AllTLObjects.ts b/src/lib/gramjs/tl/AllTLObjects.ts index 8dd05d2c2..cc0c1dcb4 100644 --- a/src/lib/gramjs/tl/AllTLObjects.ts +++ b/src/lib/gramjs/tl/AllTLObjects.ts @@ -12,5 +12,5 @@ for (const tl of Object.values(Api)) { } } -export const LAYER = 200; +export const LAYER = 201; export { tlobjects }; diff --git a/src/lib/gramjs/tl/api.d.ts b/src/lib/gramjs/tl/api.d.ts index 874a97aac..6aed48328 100644 --- a/src/lib/gramjs/tl/api.d.ts +++ b/src/lib/gramjs/tl/api.d.ts @@ -69,7 +69,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 | MessageMediaStory | MessageMediaGiveaway | MessageMediaGiveawayResults | MessageMediaPaidMedia; - 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 | MessageActionGiftPremium | MessageActionTopicCreate | MessageActionTopicEdit | MessageActionSuggestProfilePhoto | MessageActionRequestedPeer | MessageActionSetChatWallPaper | MessageActionGiftCode | MessageActionGiveawayLaunch | MessageActionGiveawayResults | MessageActionBoostApply | MessageActionRequestedPeerSentMe | MessageActionPaymentRefunded | MessageActionGiftStars | MessageActionPrizeStars | MessageActionStarGift | MessageActionStarGiftUnique; + 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 | MessageActionGiftPremium | MessageActionTopicCreate | MessageActionTopicEdit | MessageActionSuggestProfilePhoto | MessageActionRequestedPeer | MessageActionSetChatWallPaper | MessageActionGiftCode | MessageActionGiveawayLaunch | MessageActionGiveawayResults | MessageActionBoostApply | MessageActionRequestedPeerSentMe | MessageActionPaymentRefunded | MessageActionGiftStars | MessageActionPrizeStars | MessageActionStarGift | MessageActionStarGiftUnique | MessageActionPaidMessagesRefunded | MessageActionPaidMessagesPrice; export type TypeDialog = Dialog | DialogFolder; export type TypePhoto = PhotoEmpty | Photo; export type TypePhotoSize = PhotoSizeEmpty | PhotoSize | PhotoCachedSize | PhotoStrippedSize | PhotoSizeProgressive | PhotoPathSize; @@ -85,7 +85,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 | UpdateNewAuthorization | 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 | UpdateTranscribedAudio | UpdateReadFeaturedEmojiStickers | UpdateUserEmojiStatus | UpdateRecentEmojiStatuses | UpdateRecentReactions | UpdateMoveStickerSetToTop | UpdateMessageExtendedMedia | UpdateChannelPinnedTopic | UpdateChannelPinnedTopics | UpdateUser | UpdateAutoSaveSettings | UpdateStory | UpdateReadStories | UpdateStoryID | UpdateStoriesStealthMode | UpdateSentStoryReaction | UpdateBotChatBoost | UpdateChannelViewForumAsMessages | UpdatePeerWallpaper | UpdateBotMessageReaction | UpdateBotMessageReactions | UpdateSavedDialogPinned | UpdatePinnedSavedDialogs | UpdateSavedReactionTags | UpdateSmsJob | UpdateQuickReplies | UpdateNewQuickReply | UpdateDeleteQuickReply | UpdateQuickReplyMessage | UpdateDeleteQuickReplyMessages | UpdateBotBusinessConnect | UpdateBotNewBusinessMessage | UpdateBotEditBusinessMessage | UpdateBotDeleteBusinessMessage | UpdateNewStoryReaction | UpdateBroadcastRevenueTransactions | UpdateStarsBalance | UpdateBusinessBotCallbackQuery | UpdateStarsRevenueStatus | UpdateBotPurchasedPaidMedia | UpdatePaidReactionPrivacy; + export type TypeUpdate = UpdateNewMessage | UpdateMessageID | UpdateDeleteMessages | UpdateUserTyping | UpdateChatUserTyping | UpdateChatParticipants | UpdateUserStatus | UpdateUserName | UpdateNewAuthorization | 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 | UpdateTranscribedAudio | UpdateReadFeaturedEmojiStickers | UpdateUserEmojiStatus | UpdateRecentEmojiStatuses | UpdateRecentReactions | UpdateMoveStickerSetToTop | UpdateMessageExtendedMedia | UpdateChannelPinnedTopic | UpdateChannelPinnedTopics | UpdateUser | UpdateAutoSaveSettings | UpdateStory | UpdateReadStories | UpdateStoryID | UpdateStoriesStealthMode | UpdateSentStoryReaction | UpdateBotChatBoost | UpdateChannelViewForumAsMessages | UpdatePeerWallpaper | UpdateBotMessageReaction | UpdateBotMessageReactions | UpdateSavedDialogPinned | UpdatePinnedSavedDialogs | UpdateSavedReactionTags | UpdateSmsJob | UpdateQuickReplies | UpdateNewQuickReply | UpdateDeleteQuickReply | UpdateQuickReplyMessage | UpdateDeleteQuickReplyMessages | UpdateBotBusinessConnect | UpdateBotNewBusinessMessage | UpdateBotEditBusinessMessage | UpdateBotDeleteBusinessMessage | UpdateNewStoryReaction | UpdateBroadcastRevenueTransactions | UpdateStarsBalance | UpdateBusinessBotCallbackQuery | UpdateStarsRevenueStatus | UpdateBotPurchasedPaidMedia | UpdatePaidReactionPrivacy | UpdateSentPhoneCode; export type TypeUpdates = UpdatesTooLong | UpdateShortMessage | UpdateShortChatMessage | UpdateShort | UpdatesCombined | Updates | UpdateShortSentMessage; export type TypeDcOption = DcOption; export type TypeConfig = Config; @@ -144,7 +144,7 @@ namespace Api { export type TypeHighScore = HighScore; export type TypeRichText = TextEmpty | TextPlain | TextBold | TextItalic | TextUnderline | TextStrike | TextFixed | TextUrl | TextEmail | TextConcat | TextSubscript | TextSuperscript | TextMarked | TextPhone | TextImage | TextAnchor; export type TypePageBlock = PageBlockUnsupported | PageBlockTitle | PageBlockSubtitle | PageBlockAuthorDate | PageBlockHeader | PageBlockSubheader | PageBlockParagraph | PageBlockPreformatted | PageBlockFooter | PageBlockDivider | PageBlockAnchor | PageBlockList | PageBlockBlockquote | PageBlockPullquote | PageBlockPhoto | PageBlockVideo | PageBlockCover | PageBlockEmbed | PageBlockEmbedPost | PageBlockCollage | PageBlockSlideshow | PageBlockChannel | PageBlockAudio | PageBlockKicker | PageBlockTable | PageBlockOrderedList | PageBlockDetails | PageBlockRelatedArticles | PageBlockMap; - export type TypePhoneCallDiscardReason = PhoneCallDiscardReasonMissed | PhoneCallDiscardReasonDisconnect | PhoneCallDiscardReasonHangup | PhoneCallDiscardReasonBusy | PhoneCallDiscardReasonAllowGroupCall; + export type TypePhoneCallDiscardReason = PhoneCallDiscardReasonMissed | PhoneCallDiscardReasonDisconnect | PhoneCallDiscardReasonHangup | PhoneCallDiscardReasonBusy; export type TypeDataJSON = DataJSON; export type TypeLabeledPrice = LabeledPrice; export type TypeInvoice = Invoice; @@ -277,8 +277,8 @@ namespace Api { export type TypeBotMenuButton = BotMenuButtonDefault | BotMenuButtonCommands | BotMenuButton; export type TypeNotificationSound = NotificationSoundDefault | NotificationSoundNone | NotificationSoundLocal | NotificationSoundRingtone; export type TypeAttachMenuPeerType = AttachMenuPeerTypeSameBotPM | AttachMenuPeerTypeBotPM | AttachMenuPeerTypePM | AttachMenuPeerTypeChat | AttachMenuPeerTypeBroadcast; - export type TypeInputInvoice = InputInvoiceMessage | InputInvoiceSlug | InputInvoicePremiumGiftCode | InputInvoiceStars | InputInvoiceChatInviteSubscription | InputInvoiceStarGift | InputInvoiceStarGiftUpgrade | InputInvoiceStarGiftTransfer | InputInvoicePremiumGiftStars; - export type TypeInputStorePaymentPurpose = InputStorePaymentPremiumSubscription | InputStorePaymentGiftPremium | InputStorePaymentPremiumGiftCode | InputStorePaymentPremiumGiveaway | InputStorePaymentStarsTopup | InputStorePaymentStarsGift | InputStorePaymentStarsGiveaway; + export type TypeInputInvoice = InputInvoiceMessage | InputInvoiceSlug | InputInvoicePremiumGiftCode | InputInvoiceStars | InputInvoiceChatInviteSubscription | InputInvoiceStarGift | InputInvoiceStarGiftUpgrade | InputInvoiceStarGiftTransfer | InputInvoicePremiumGiftStars | InputInvoiceBusinessBotTransferStars; + export type TypeInputStorePaymentPurpose = InputStorePaymentPremiumSubscription | InputStorePaymentGiftPremium | InputStorePaymentPremiumGiftCode | InputStorePaymentPremiumGiveaway | InputStorePaymentStarsTopup | InputStorePaymentStarsGift | InputStorePaymentStarsGiveaway | InputStorePaymentAuthCode; export type TypePaymentFormMethod = PaymentFormMethod; export type TypeEmojiStatus = EmojiStatusEmpty | EmojiStatus | EmojiStatusCollectible | InputEmojiStatusCollectible; export type TypeReaction = ReactionEmpty | ReactionEmoji | ReactionCustomEmoji | ReactionPaid; @@ -389,6 +389,9 @@ namespace Api { export type TypeInputSavedStarGift = InputSavedStarGiftUser | InputSavedStarGiftChat; export type TypePaidReactionPrivacy = PaidReactionPrivacyDefault | PaidReactionPrivacyAnonymous | PaidReactionPrivacyPeer; export type TypeRequirementToContact = RequirementToContactEmpty | RequirementToContactPremium | RequirementToContactPaidMessages; + export type TypeBusinessBotRights = BusinessBotRights; + export type TypeDisallowedGiftsSettings = DisallowedGiftsSettings; + export type TypeSponsoredPeer = SponsoredPeer; export type TypeResPQ = ResPQ; export type TypeP_Q_inner_data = PQInnerData | PQInnerDataDc | PQInnerDataTemp | PQInnerDataTempDc; export type TypeServer_DH_Params = ServerDHParamsFail | ServerDHParamsOk; @@ -422,7 +425,7 @@ namespace Api { } export namespace auth { - export type TypeSentCode = auth.SentCode | auth.SentCodeSuccess; + export type TypeSentCode = auth.SentCode | auth.SentCodeSuccess | auth.SentCodePaymentRequired; export type TypeAuthorization = auth.Authorization | auth.AuthorizationSignUpRequired; export type TypeExportedAuthorization = auth.ExportedAuthorization; export type TypePasswordRecovery = auth.PasswordRecovery; @@ -440,6 +443,7 @@ namespace Api { export type TypeResolvedPeer = contacts.ResolvedPeer; export type TypeTopPeers = contacts.TopPeersNotModified | contacts.TopPeers | contacts.TopPeersDisabled; export type TypeContactBirthdays = contacts.ContactBirthdays; + export type TypeSponsoredPeers = contacts.SponsoredPeersEmpty | contacts.SponsoredPeers; } export namespace messages { @@ -2621,6 +2625,20 @@ namespace Api { savedId?: long; static fromReader(reader: Reader): MessageActionStarGiftUnique; } + export class MessageActionPaidMessagesRefunded extends VirtualClass<{ + count: int; + stars: long; + }> { + count: int; + stars: long; + static fromReader(reader: Reader): MessageActionPaidMessagesRefunded; + } + export class MessageActionPaidMessagesPrice extends VirtualClass<{ + stars: long; + }> { + stars: long; + static fromReader(reader: Reader): MessageActionPaidMessagesPrice; + } export class Dialog extends VirtualClass<{ // flags: Api.Type; pinned?: true; @@ -2988,6 +3006,7 @@ namespace Api { sponsoredEnabled?: true; canViewRevenue?: true; botCanManageEmojiStatus?: true; + displayGiftsButton?: true; id: long; about?: string; settings: Api.TypePeerSettings; @@ -3018,6 +3037,7 @@ namespace Api { starrefProgram?: Api.TypeStarRefProgram; botVerification?: Api.TypeBotVerification; sendPaidMessagesStars?: long; + disallowedGifts?: Api.TypeDisallowedGiftsSettings; }> { // flags: Api.Type; blocked?: true; @@ -3037,6 +3057,7 @@ namespace Api { sponsoredEnabled?: true; canViewRevenue?: true; botCanManageEmojiStatus?: true; + displayGiftsButton?: true; id: long; about?: string; settings: Api.TypePeerSettings; @@ -3067,6 +3088,7 @@ namespace Api { starrefProgram?: Api.TypeStarRefProgram; botVerification?: Api.TypeBotVerification; sendPaidMessagesStars?: long; + disallowedGifts?: Api.TypeDisallowedGiftsSettings; static fromReader(reader: Reader): UserFull; } export class Contact extends VirtualClass<{ @@ -4515,6 +4537,12 @@ namespace Api { private: Api.TypePaidReactionPrivacy; static fromReader(reader: Reader): UpdatePaidReactionPrivacy; } + export class UpdateSentPhoneCode extends VirtualClass<{ + sentCode: auth.TypeSentCode; + }> { + sentCode: auth.TypeSentCode; + static fromReader(reader: Reader): UpdateSentPhoneCode; + } export class UpdatesTooLong extends VirtualClass { static fromReader(reader: Reader): UpdatesTooLong; } @@ -7266,12 +7294,6 @@ namespace Api { export class PhoneCallDiscardReasonBusy extends VirtualClass { static fromReader(reader: Reader): PhoneCallDiscardReasonBusy; } - export class PhoneCallDiscardReasonAllowGroupCall extends VirtualClass<{ - encryptedKey: bytes; - }> { - encryptedKey: bytes; - static fromReader(reader: Reader): PhoneCallDiscardReasonAllowGroupCall; - } export class DataJSON extends VirtualClass<{ data: string; }> { @@ -9558,7 +9580,9 @@ namespace Api { keepArchivedFolders?: true; hideReadMarks?: true; newNoncontactPeersRequirePremium?: true; + displayGiftsButton?: true; noncontactPeersPaidStars?: long; + disallowedGifts?: Api.TypeDisallowedGiftsSettings; } | void> { // flags: Api.Type; archiveAndMuteNewNoncontactPeers?: true; @@ -9566,7 +9590,9 @@ namespace Api { keepArchivedFolders?: true; hideReadMarks?: true; newNoncontactPeersRequirePremium?: true; + displayGiftsButton?: true; noncontactPeersPaidStars?: long; + disallowedGifts?: Api.TypeDisallowedGiftsSettings; static fromReader(reader: Reader): GlobalPrivacySettings; } export class MessageViews extends VirtualClass<{ @@ -10209,6 +10235,14 @@ namespace Api { message?: Api.TypeTextWithEntities; static fromReader(reader: Reader): InputInvoicePremiumGiftStars; } + export class InputInvoiceBusinessBotTransferStars extends VirtualClass<{ + bot: Api.TypeInputUser; + stars: long; + }> { + bot: Api.TypeInputUser; + stars: long; + static fromReader(reader: Reader): InputInvoiceBusinessBotTransferStars; + } export class InputStorePaymentPremiumSubscription extends VirtualClass<{ // flags: Api.Type; restore?: true; @@ -10323,6 +10357,22 @@ namespace Api { users: int; static fromReader(reader: Reader): InputStorePaymentStarsGiveaway; } + export class InputStorePaymentAuthCode extends VirtualClass<{ + // flags: Api.Type; + restore?: true; + phoneNumber: string; + phoneCodeHash: string; + currency: string; + amount: long; + }> { + // flags: Api.Type; + restore?: true; + phoneNumber: string; + phoneCodeHash: string; + currency: string; + amount: long; + static fromReader(reader: Reader): InputStorePaymentAuthCode; + } export class PaymentFormMethod extends VirtualClass<{ url: string; title: string; @@ -11475,14 +11525,14 @@ namespace Api { } export class ConnectedBot extends VirtualClass<{ // flags: Api.Type; - canReply?: true; botId: long; recipients: Api.TypeBusinessBotRecipients; + rights: Api.TypeBusinessBotRights; }> { // flags: Api.Type; - canReply?: true; botId: long; recipients: Api.TypeBusinessBotRecipients; + rights: Api.TypeBusinessBotRights; static fromReader(reader: Reader): ConnectedBot; } export class Birthday extends VirtualClass<{ @@ -11499,20 +11549,20 @@ namespace Api { } export class BotBusinessConnection extends VirtualClass<{ // flags: Api.Type; - canReply?: true; disabled?: true; connectionId: string; userId: long; dcId: int; date: int; + rights?: Api.TypeBusinessBotRights; }> { // flags: Api.Type; - canReply?: true; disabled?: true; connectionId: string; userId: long; dcId: int; date: int; + rights?: Api.TypeBusinessBotRights; static fromReader(reader: Reader): BotBusinessConnection; } export class InputBusinessIntro extends VirtualClass<{ @@ -12355,6 +12405,68 @@ namespace Api { starsAmount: long; static fromReader(reader: Reader): RequirementToContactPaidMessages; } + export class BusinessBotRights extends VirtualClass<{ + // flags: Api.Type; + reply?: true; + readMessages?: true; + deleteSentMessages?: true; + deleteReceivedMessages?: true; + editName?: true; + editBio?: true; + editProfilePhoto?: true; + editUsername?: true; + viewGifts?: true; + sellGifts?: true; + changeGiftSettings?: true; + transferAndUpgradeGifts?: true; + transferStars?: true; + manageStories?: true; + } | void> { + // flags: Api.Type; + reply?: true; + readMessages?: true; + deleteSentMessages?: true; + deleteReceivedMessages?: true; + editName?: true; + editBio?: true; + editProfilePhoto?: true; + editUsername?: true; + viewGifts?: true; + sellGifts?: true; + changeGiftSettings?: true; + transferAndUpgradeGifts?: true; + transferStars?: true; + manageStories?: true; + static fromReader(reader: Reader): BusinessBotRights; + } + export class DisallowedGiftsSettings extends VirtualClass<{ + // flags: Api.Type; + disallowUnlimitedStargifts?: true; + disallowLimitedStargifts?: true; + disallowUniqueStargifts?: true; + disallowPremiumGifts?: true; + } | void> { + // flags: Api.Type; + disallowUnlimitedStargifts?: true; + disallowLimitedStargifts?: true; + disallowUniqueStargifts?: true; + disallowPremiumGifts?: true; + static fromReader(reader: Reader): DisallowedGiftsSettings; + } + export class SponsoredPeer extends VirtualClass<{ + // flags: Api.Type; + randomId: bytes; + peer: Api.TypePeer; + sponsorInfo?: string; + additionalInfo?: string; + }> { + // flags: Api.Type; + randomId: bytes; + peer: Api.TypePeer; + sponsorInfo?: string; + additionalInfo?: string; + static fromReader(reader: Reader): SponsoredPeer; + } export class ResPQ extends VirtualClass<{ nonce: int128; serverNonce: int128; @@ -12811,6 +12923,14 @@ namespace Api { authorization: auth.TypeAuthorization; static fromReader(reader: Reader): SentCodeSuccess; } + export class SentCodePaymentRequired extends VirtualClass<{ + storeProduct: string; + phoneCodeHash: string; + }> { + storeProduct: string; + phoneCodeHash: string; + static fromReader(reader: Reader): SentCodePaymentRequired; + } export class Authorization extends VirtualClass<{ // flags: Api.Type; setupPasswordRequired?: true; @@ -13092,6 +13212,19 @@ namespace Api { users: Api.TypeUser[]; static fromReader(reader: Reader): ContactBirthdays; } + export class SponsoredPeersEmpty extends VirtualClass { + static fromReader(reader: Reader): SponsoredPeersEmpty; + } + export class SponsoredPeers extends VirtualClass<{ + peers: Api.TypeSponsoredPeer[]; + chats: Api.TypeChat[]; + users: Api.TypeUser[]; + }> { + peers: Api.TypeSponsoredPeer[]; + chats: Api.TypeChat[]; + users: Api.TypeUser[]; + static fromReader(reader: Reader): SponsoredPeers; + } } export namespace messages { @@ -16644,14 +16777,14 @@ namespace Api { } export class UpdateConnectedBot extends Request, Api.TypeUpdates> { // flags: Api.Type; - canReply?: true; deleted?: true; + rights?: Api.TypeBusinessBotRights; bot: Api.TypeInputUser; recipients: Api.TypeInputBusinessBotRecipients; } @@ -16959,6 +17092,11 @@ namespace Api { limit: int; } export class GetBirthdays extends Request {} + export class GetSponsoredPeers extends Request, contacts.TypeSponsoredPeers> { + q: string; + } } export namespace messages { @@ -19128,31 +19266,25 @@ namespace Api { } export class GetPaidReactionPrivacy extends Request {} export class ViewSponsoredMessage extends Request, Bool> { - peer: Api.TypeInputPeer; randomId: bytes; } export class ClickSponsoredMessage extends Request, Bool> { // flags: Api.Type; media?: true; fullscreen?: true; - peer: Api.TypeInputPeer; randomId: bytes; } export class ReportSponsoredMessage extends Request, channels.TypeSponsoredMessageReportResult> { - peer: Api.TypeInputPeer; randomId: bytes; option: bytes; } @@ -20327,11 +20459,6 @@ namespace Api { receipt: Api.TypeDataJSON; purpose: Api.TypeInputStorePaymentPurpose; } - export class CanPurchasePremium extends Request, Bool> { - purpose: Api.TypeInputStorePaymentPurpose; - } export class GetPremiumGiftCodeOptions extends Request, Bool> { + purpose: Api.TypeInputStorePaymentPurpose; + } } export namespace stickers { @@ -21582,7 +21714,7 @@ namespace Api { | 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 | auth.ImportWebTokenAuthorization | auth.RequestFirebaseSms | auth.ResetLoginEmail | auth.ReportMissingCode | 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 | account.UpdateEmojiStatus | account.GetDefaultEmojiStatuses | account.GetRecentEmojiStatuses | account.ClearRecentEmojiStatuses | account.ReorderUsernames | account.ToggleUsername | account.GetDefaultProfilePhotoEmojis | account.GetDefaultGroupPhotoEmojis | account.GetAutoSaveSettings | account.SaveAutoSaveSettings | account.DeleteAutoSaveExceptions | account.InvalidateSignInCodes | account.UpdateColor | account.GetDefaultBackgroundEmojis | account.GetChannelDefaultEmojiStatuses | account.GetChannelRestrictedStatusEmojis | account.UpdateBusinessWorkHours | account.UpdateBusinessLocation | account.UpdateBusinessGreetingMessage | account.UpdateBusinessAwayMessage | account.UpdateConnectedBot | account.GetConnectedBots | account.GetBotBusinessConnection | account.UpdateBusinessIntro | account.ToggleConnectedBotPaused | account.DisablePeerConnectedBot | account.UpdateBirthday | account.CreateBusinessChatLink | account.EditBusinessChatLink | account.DeleteBusinessChatLink | account.GetBusinessChatLinks | account.ResolveBusinessChatLink | account.UpdatePersonalChannel | account.ToggleSponsoredMessages | account.GetReactionsNotifySettings | account.SetReactionsNotifySettings | account.GetCollectibleEmojiStatuses | account.AddNoPaidMessagesException | account.GetPaidMessagesRevenue | users.GetUsers | users.GetFullUser | users.SetSecureValueErrors | users.GetRequirementsToContact - | 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 | contacts.ExportContactToken | contacts.ImportContactToken | contacts.EditCloseFriends | contacts.SetBlocked | contacts.GetBirthdays + | 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 | contacts.ExportContactToken | contacts.ImportContactToken | contacts.EditCloseFriends | contacts.SetBlocked | contacts.GetBirthdays | contacts.GetSponsoredPeers | 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.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 | messages.TranscribeAudio | messages.RateTranscribedAudio | messages.GetCustomEmojiDocuments | messages.GetEmojiStickers | messages.GetFeaturedEmojiStickers | messages.ReportReaction | messages.GetTopReactions | messages.GetRecentReactions | messages.ClearRecentReactions | messages.GetExtendedMedia | messages.SetDefaultHistoryTTL | messages.GetDefaultHistoryTTL | messages.SendBotRequestedPeer | messages.GetEmojiGroups | messages.GetEmojiStatusGroups | messages.GetEmojiProfilePhotoGroups | messages.SearchCustomEmoji | messages.TogglePeerTranslations | messages.GetBotApp | messages.RequestAppWebView | messages.SetChatWallPaper | messages.SearchEmojiStickerSets | messages.GetSavedDialogs | messages.GetSavedHistory | messages.DeleteSavedHistory | messages.GetPinnedSavedDialogs | messages.ToggleSavedDialogPin | messages.ReorderPinnedSavedDialogs | messages.GetSavedReactionTags | messages.UpdateSavedReactionTag | messages.GetDefaultTagReactions | messages.GetOutboxReadDate | messages.GetQuickReplies | messages.ReorderQuickReplies | messages.CheckQuickReplyShortcut | messages.EditQuickReplyShortcut | messages.DeleteQuickReplyShortcut | messages.GetQuickReplyMessages | messages.SendQuickReplyMessages | messages.DeleteQuickReplyMessages | messages.ToggleDialogFilterTags | messages.GetMyStickers | messages.GetEmojiStickerGroups | messages.GetAvailableEffects | messages.EditFactCheck | messages.DeleteFactCheck | messages.GetFactCheck | messages.RequestMainWebView | messages.SendPaidReaction | messages.TogglePaidReactionPrivacy | messages.GetPaidReactionPrivacy | messages.ViewSponsoredMessage | messages.ClickSponsoredMessage | messages.ReportSponsoredMessage | messages.GetSponsoredMessages | messages.SavePreparedInlineMessage | messages.GetPreparedInlineMessage | messages.SearchStickers | messages.ReportMessagesDelivery | updates.GetState | updates.GetDifference | updates.GetChannelDifference | photos.UpdateProfilePhoto | photos.UploadProfilePhoto | photos.DeletePhotos | photos.GetUserPhotos | photos.UploadContactProfilePhoto @@ -21590,7 +21722,7 @@ namespace Api { | help.GetConfig | help.GetNearestDc | help.GetAppUpdate | help.GetInviteText | help.GetSupport | 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 | help.GetPeerColors | help.GetPeerProfileColors | help.GetTimezonesList | 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.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.UpdateColor | channels.ToggleViewForumAsMessages | channels.GetChannelRecommendations | channels.UpdateEmojiStatus | channels.SetBoostsToUnblockRestrictions | channels.SetEmojiStickers | channels.RestrictSponsoredMessages | channels.SearchPosts | channels.UpdatePaidMessagesPrice | 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 | bots.GetPopularAppBots | bots.AddPreviewMedia | bots.EditPreviewMedia | bots.DeletePreviewMedia | bots.ReorderPreviewMedias | bots.GetPreviewInfo | bots.GetPreviewMedias | bots.UpdateUserEmojiStatus | bots.ToggleUserEmojiStatusPermission | bots.CheckDownloadFileParams | bots.GetAdminedBots | bots.UpdateStarRefProgram | bots.SetCustomVerification | bots.GetBotRecommendations - | payments.GetPaymentForm | payments.GetPaymentReceipt | payments.ValidateRequestedInfo | payments.SendPaymentForm | payments.GetSavedInfo | payments.ClearSavedInfo | payments.GetBankCardData | payments.ExportInvoice | payments.AssignAppStoreTransaction | payments.AssignPlayMarketTransaction | payments.CanPurchasePremium | payments.GetPremiumGiftCodeOptions | payments.CheckGiftCode | payments.ApplyGiftCode | payments.GetGiveawayInfo | payments.LaunchPrepaidGiveaway | payments.GetStarsTopupOptions | payments.GetStarsStatus | payments.GetStarsTransactions | payments.SendStarsForm | payments.RefundStarsCharge | payments.GetStarsRevenueStats | payments.GetStarsRevenueWithdrawalUrl | payments.GetStarsRevenueAdsAccountUrl | payments.GetStarsTransactionsByID | payments.GetStarsGiftOptions | payments.GetStarsSubscriptions | payments.ChangeStarsSubscription | payments.FulfillStarsSubscription | payments.GetStarsGiveawayOptions | payments.GetStarGifts | payments.SaveStarGift | payments.ConvertStarGift | payments.BotCancelStarsSubscription | payments.GetConnectedStarRefBots | payments.GetConnectedStarRefBot | payments.GetSuggestedStarRefBots | payments.ConnectStarRefBot | payments.EditConnectedStarRefBot | payments.GetStarGiftUpgradePreview | payments.UpgradeStarGift | payments.TransferStarGift | payments.GetUniqueStarGift | payments.GetSavedStarGifts | payments.GetSavedStarGift | payments.GetStarGiftWithdrawalUrl | payments.ToggleChatStarGiftNotifications | payments.ToggleStarGiftsPinnedToTop + | payments.GetPaymentForm | payments.GetPaymentReceipt | payments.ValidateRequestedInfo | payments.SendPaymentForm | payments.GetSavedInfo | payments.ClearSavedInfo | payments.GetBankCardData | payments.ExportInvoice | payments.AssignAppStoreTransaction | payments.AssignPlayMarketTransaction | payments.GetPremiumGiftCodeOptions | payments.CheckGiftCode | payments.ApplyGiftCode | payments.GetGiveawayInfo | payments.LaunchPrepaidGiveaway | payments.GetStarsTopupOptions | payments.GetStarsStatus | payments.GetStarsTransactions | payments.SendStarsForm | payments.RefundStarsCharge | payments.GetStarsRevenueStats | payments.GetStarsRevenueWithdrawalUrl | payments.GetStarsRevenueAdsAccountUrl | payments.GetStarsTransactionsByID | payments.GetStarsGiftOptions | payments.GetStarsSubscriptions | payments.ChangeStarsSubscription | payments.FulfillStarsSubscription | payments.GetStarsGiveawayOptions | payments.GetStarGifts | payments.SaveStarGift | payments.ConvertStarGift | payments.BotCancelStarsSubscription | payments.GetConnectedStarRefBots | payments.GetConnectedStarRefBot | payments.GetSuggestedStarRefBots | payments.ConnectStarRefBot | payments.EditConnectedStarRefBot | payments.GetStarGiftUpgradePreview | payments.UpgradeStarGift | payments.TransferStarGift | payments.GetUniqueStarGift | payments.GetSavedStarGifts | payments.GetSavedStarGift | payments.GetStarGiftWithdrawalUrl | payments.ToggleChatStarGiftNotifications | payments.ToggleStarGiftsPinnedToTop | payments.CanPurchaseStore | stickers.CreateStickerSet | stickers.RemoveStickerFromSet | stickers.ChangeStickerPosition | stickers.AddStickerToSet | stickers.SetStickerSetThumb | stickers.CheckShortName | stickers.SuggestShortName | stickers.ChangeSticker | stickers.RenameStickerSet | stickers.DeleteStickerSet | stickers.ReplaceSticker | 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 | phone.CreateConferenceCall | langpack.GetLangPack | langpack.GetStrings | langpack.GetDifference | langpack.GetLanguages | langpack.GetLanguage diff --git a/src/lib/gramjs/tl/apiTl.ts b/src/lib/gramjs/tl/apiTl.ts index 7c94e636a..e8d4ee7df 100644 --- a/src/lib/gramjs/tl/apiTl.ts +++ b/src/lib/gramjs/tl/apiTl.ts @@ -159,6 +159,8 @@ messageActionGiftStars#45d5b021 flags:# currency:string amount:long stars:long c messageActionPrizeStars#b00c47a2 flags:# unclaimed:flags.0?true stars:long transaction_id:string boost_peer:Peer giveaway_msg_id:int = MessageAction; messageActionStarGift#4717e8a4 flags:# name_hidden:flags.0?true saved:flags.2?true converted:flags.3?true upgraded:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true gift:StarGift message:flags.1?TextWithEntities convert_stars:flags.4?long upgrade_msg_id:flags.5?int upgrade_stars:flags.8?long from_id:flags.11?Peer peer:flags.12?Peer saved_id:flags.12?long = MessageAction; messageActionStarGiftUnique#acdfcb81 flags:# upgrade:flags.0?true transferred:flags.1?true saved:flags.2?true refunded:flags.5?true gift:StarGift can_export_at:flags.3?int transfer_stars:flags.4?long from_id:flags.6?Peer peer:flags.7?Peer saved_id:flags.7?long = MessageAction; +messageActionPaidMessagesRefunded#ac1f1fcd count:int stars:long = MessageAction; +messageActionPaidMessagesPrice#bcd71419 stars:long = MessageAction; dialog#d58a08c6 flags:# pinned:flags.2?true unread_mark:flags.3?true view_forum_as_messages:flags.6?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 ttl_period:flags.5?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; @@ -173,6 +175,7 @@ geoPointEmpty#1117dd5f = GeoPoint; geoPoint#b2a2f663 flags:# long:double lat:double access_hash:long accuracy_radius:flags.0?int = GeoPoint; auth.sentCode#5e002502 flags:# type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int = auth.SentCode; auth.sentCodeSuccess#2390fe44 authorization:auth.Authorization = auth.SentCode; +auth.sentCodePaymentRequired#d7cef980 store_product:string phone_code_hash:string = auth.SentCode; auth.authorization#2ea2c0d4 flags:# setup_password_required:flags.1?true otherwise_relogin_days:flags.1?int tmp_sessions:flags.0?int future_auth_token:flags.2?bytes user:User = auth.Authorization; auth.authorizationSignUpRequired#44747e9a flags:# terms_of_service:flags.0?help.TermsOfService = auth.Authorization; auth.exportedAuthorization#b434e2b8 id:long bytes:bytes = auth.ExportedAuthorization; @@ -196,7 +199,7 @@ inputReportReasonGeoIrrelevant#dbd4feed = ReportReason; inputReportReasonFake#f5ddd6e7 = ReportReason; inputReportReasonIllegalDrugs#a8eb2be = ReportReason; inputReportReasonPersonalDetails#9ec7863d = ReportReason; -userFull#d2234ea0 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 voice_messages_forbidden:flags.20?true translations_disabled:flags.23?true stories_pinned_available:flags.26?true blocked_my_stories_from:flags.27?true wallpaper_overridden:flags.28?true contact_require_premium:flags.29?true read_dates_private:flags.30?true flags2:# sponsored_enabled:flags2.7?true can_view_revenue:flags2.9?true bot_can_manage_emoji_status:flags2.10?true id:long about:flags.1?string settings:PeerSettings personal_photo:flags.21?Photo profile_photo:flags.2?Photo fallback_photo:flags.22?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 wallpaper:flags.24?WallPaper stories:flags.25?PeerStories business_work_hours:flags2.0?BusinessWorkHours business_location:flags2.1?BusinessLocation business_greeting_message:flags2.2?BusinessGreetingMessage business_away_message:flags2.3?BusinessAwayMessage business_intro:flags2.4?BusinessIntro birthday:flags2.5?Birthday personal_channel_id:flags2.6?long personal_channel_message:flags2.6?int stargifts_count:flags2.8?int starref_program:flags2.11?StarRefProgram bot_verification:flags2.12?BotVerification send_paid_messages_stars:flags2.14?long = UserFull; +userFull#99e78045 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 voice_messages_forbidden:flags.20?true translations_disabled:flags.23?true stories_pinned_available:flags.26?true blocked_my_stories_from:flags.27?true wallpaper_overridden:flags.28?true contact_require_premium:flags.29?true read_dates_private:flags.30?true flags2:# sponsored_enabled:flags2.7?true can_view_revenue:flags2.9?true bot_can_manage_emoji_status:flags2.10?true display_gifts_button:flags2.16?true id:long about:flags.1?string settings:PeerSettings personal_photo:flags.21?Photo profile_photo:flags.2?Photo fallback_photo:flags.22?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 wallpaper:flags.24?WallPaper stories:flags.25?PeerStories business_work_hours:flags2.0?BusinessWorkHours business_location:flags2.1?BusinessLocation business_greeting_message:flags2.2?BusinessGreetingMessage business_away_message:flags2.3?BusinessAwayMessage business_intro:flags2.4?BusinessIntro birthday:flags2.5?Birthday personal_channel_id:flags2.6?long personal_channel_message:flags2.6?int stargifts_count:flags2.8?int starref_program:flags2.11?StarRefProgram bot_verification:flags2.12?BotVerification send_paid_messages_stars:flags2.14?long disallowed_gifts:flags2.15?DisallowedGiftsSettings = 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; @@ -374,6 +377,7 @@ updateBusinessBotCallbackQuery#1ea2fda7 flags:# query_id:long user_id:long conne updateStarsRevenueStatus#a584b019 peer:Peer status:StarsRevenueStatus = Update; updateBotPurchasedPaidMedia#283bd312 user_id:long payload:string qts:int = Update; updatePaidReactionPrivacy#8b725fce private:PaidReactionPrivacy = Update; +updateSentPhoneCode#504aa18f sent_code:auth.SentCode = 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 new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector state:updates.State = updates.Difference; @@ -746,7 +750,6 @@ phoneCallDiscardReasonMissed#85e42301 = PhoneCallDiscardReason; phoneCallDiscardReasonDisconnect#e095c1a0 = PhoneCallDiscardReason; phoneCallDiscardReasonHangup#57adc690 = PhoneCallDiscardReason; phoneCallDiscardReasonBusy#faf7e8c9 = PhoneCallDiscardReason; -phoneCallDiscardReasonAllowGroupCall#afe2b839 encrypted_key:bytes = PhoneCallDiscardReason; dataJSON#7d748d04 data:string = DataJSON; labeledPrice#cb296bf8 label:string amount:long = LabeledPrice; invoice#49ee584 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true phone_to_provider:flags.6?true email_to_provider:flags.7?true recurring:flags.9?true currency:string prices:Vector max_tip_amount:flags.8?long suggested_tip_amounts:flags.8?Vector terms_url:flags.10?string subscription_period:flags.11?int = Invoice; @@ -1025,7 +1028,7 @@ statsGroupTopPoster#9d04af9b user_id:long messages:int avg_chars:int = StatsGrou statsGroupTopAdmin#d7584c87 user_id:long deleted:int kicked:int banned:int = StatsGroupTopAdmin; statsGroupTopInviter#535f779d user_id:long invitations:int = StatsGroupTopInviter; stats.megagroupStats#ef7ff916 period:StatsDateRangeDays members:StatsAbsValueAndPrev messages:StatsAbsValueAndPrev viewers:StatsAbsValueAndPrev posters:StatsAbsValueAndPrev growth_graph:StatsGraph members_graph:StatsGraph new_members_by_source_graph:StatsGraph languages_graph:StatsGraph messages_graph:StatsGraph actions_graph:StatsGraph top_hours_graph:StatsGraph weekdays_graph:StatsGraph top_posters:Vector top_admins:Vector top_inviters:Vector users:Vector = stats.MegagroupStats; -globalPrivacySettings#c9d8df1c flags:# archive_and_mute_new_noncontact_peers:flags.0?true keep_archived_unmuted:flags.1?true keep_archived_folders:flags.2?true hide_read_marks:flags.3?true new_noncontact_peers_require_premium:flags.4?true noncontact_peers_paid_stars:flags.5?long = GlobalPrivacySettings; +globalPrivacySettings#fe41b34f flags:# archive_and_mute_new_noncontact_peers:flags.0?true keep_archived_unmuted:flags.1?true keep_archived_folders:flags.2?true hide_read_marks:flags.3?true new_noncontact_peers_require_premium:flags.4?true display_gifts_button:flags.7?true noncontact_peers_paid_stars:flags.5?long disallowed_gifts:flags.6?DisallowedGiftsSettings = GlobalPrivacySettings; help.countryCode#4203c5ef flags:# country_code:string prefixes:flags.0?Vector patterns:flags.1?Vector = help.CountryCode; help.country#c3878e23 flags:# hidden:flags.0?true iso2:string default_name:string name:flags.1?string country_codes:Vector = help.Country; help.countriesListNotModified#93cc1f32 = help.CountriesList; @@ -1130,6 +1133,7 @@ inputInvoiceStarGift#e8625e92 flags:# hide_name:flags.0?true include_upgrade:fla inputInvoiceStarGiftUpgrade#4d818d5d flags:# keep_original_details:flags.0?true stargift:InputSavedStarGift = InputInvoice; inputInvoiceStarGiftTransfer#4a5f5bd9 stargift:InputSavedStarGift to_id:InputPeer = InputInvoice; inputInvoicePremiumGiftStars#dabab2ef flags:# user_id:InputUser months:int message:flags.0?TextWithEntities = InputInvoice; +inputInvoiceBusinessBotTransferStars#f4997e42 bot:InputUser stars:long = InputInvoice; payments.exportedInvoice#aed0cbd9 url:string = payments.ExportedInvoice; messages.transcribedAudio#cfb9d957 flags:# pending:flags.0?true transcription_id:long text:string trial_remains_num:flags.1?int trial_remains_until_date:flags.1?int = messages.TranscribedAudio; help.premiumPromo#5334759c status_text:string status_entities:Vector video_sections:Vector videos:Vector period_options:Vector users:Vector = help.PremiumPromo; @@ -1140,6 +1144,7 @@ inputStorePaymentPremiumGiveaway#160544ca flags:# only_new_subscribers:flags.0?t inputStorePaymentStarsTopup#dddd0f56 stars:long currency:string amount:long = InputStorePaymentPurpose; inputStorePaymentStarsGift#1d741ef7 user_id:InputUser stars:long currency:string amount:long = InputStorePaymentPurpose; inputStorePaymentStarsGiveaway#751f08fa flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true stars:long boost_peer:InputPeer additional_peers:flags.1?Vector countries_iso2:flags.2?Vector prize_description:flags.4?string random_id:long until_date:int currency:string amount:long users:int = InputStorePaymentPurpose; +inputStorePaymentAuthCode#9bb2636d flags:# restore:flags.0?true phone_number:string phone_code_hash:string currency:string amount:long = InputStorePaymentPurpose; paymentFormMethod#88f8f21b url:string title:string = PaymentFormMethod; emojiStatusEmpty#2de11aae = EmojiStatus; emojiStatus#e7ff068a flags:# document_id:long until:flags.0?int = EmojiStatus; @@ -1298,11 +1303,11 @@ inputQuickReplyShortcut#24596d41 shortcut:string = InputQuickReplyShortcut; inputQuickReplyShortcutId#1190cf1 shortcut_id:int = InputQuickReplyShortcut; messages.quickReplies#c68d6695 quick_replies:Vector messages:Vector chats:Vector users:Vector = messages.QuickReplies; messages.quickRepliesNotModified#5f91eb5b = messages.QuickReplies; -connectedBot#bd068601 flags:# can_reply:flags.0?true bot_id:long recipients:BusinessBotRecipients = ConnectedBot; +connectedBot#cd64636c flags:# bot_id:long recipients:BusinessBotRecipients rights:BusinessBotRights = ConnectedBot; account.connectedBots#17d7f87b connected_bots:Vector users:Vector = account.ConnectedBots; messages.dialogFilters#2ad93719 flags:# tags_enabled:flags.0?true filters:Vector = messages.DialogFilters; birthday#6c8e1e06 flags:# day:int month:int year:flags.0?int = Birthday; -botBusinessConnection#896433b4 flags:# can_reply:flags.0?true disabled:flags.1?true connection_id:string user_id:long dc_id:int date:int = BotBusinessConnection; +botBusinessConnection#8f34b2f5 flags:# disabled:flags.1?true connection_id:string user_id:long dc_id:int date:int rights:flags.2?BusinessBotRights = BotBusinessConnection; inputBusinessIntro#9c469cd flags:# title:string description:string sticker:flags.0?InputDocument = InputBusinessIntro; businessIntro#5a0a066d flags:# title:string description:string sticker:flags.0?Document = BusinessIntro; messages.myStickers#faff629d count:int sets:Vector = messages.MyStickers; @@ -1409,6 +1414,11 @@ account.paidMessagesRevenue#1e109708 stars_amount:long = account.PaidMessagesRev requirementToContactEmpty#50a9839 = RequirementToContact; requirementToContactPremium#e581e4e9 = RequirementToContact; requirementToContactPaidMessages#b4f67e93 stars_amount:long = RequirementToContact; +businessBotRights#a0624cf7 flags:# reply:flags.0?true read_messages:flags.1?true delete_sent_messages:flags.2?true delete_received_messages:flags.3?true edit_name:flags.4?true edit_bio:flags.5?true edit_profile_photo:flags.6?true edit_username:flags.7?true view_gifts:flags.8?true sell_gifts:flags.9?true change_gift_settings:flags.10?true transfer_and_upgrade_gifts:flags.11?true transfer_stars:flags.12?true manage_stories:flags.13?true = BusinessBotRights; +disallowedGiftsSettings#71f276c4 flags:# disallow_unlimited_stargifts:flags.0?true disallow_limited_stargifts:flags.1?true disallow_unique_stargifts:flags.2?true disallow_premium_gifts:flags.3?true = DisallowedGiftsSettings; +sponsoredPeer#c69708d3 flags:# random_id:bytes peer:Peer sponsor_info:flags.0?string additional_info:flags.1?string = SponsoredPeer; +contacts.sponsoredPeersEmpty#ea32b4b1 = contacts.SponsoredPeers; +contacts.sponsoredPeers#eb032884 peers:Vector chats:Vector users:Vector = contacts.SponsoredPeers; ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; initConnection#c1cd5ea9 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy params:flags.1?JSONValue query:!X = X; @@ -1476,7 +1486,6 @@ account.addNoPaidMessagesException#6f688aa7 flags:# refund_charged:flags.0?true account.getPaidMessagesRevenue#f1266f38 user_id:InputUser = account.PaidMessagesRevenue; users.getUsers#d91a548 id:Vector = Vector; users.getFullUser#b60f5918 id:InputUser = users.UserFull; -users.getRequirementsToContact#d89a83a3 id:Vector = Vector; contacts.getContacts#5dd69e12 hash:long = contacts.Contacts; contacts.importContacts#2c800be5 contacts:Vector = contacts.ImportedContacts; contacts.deleteContacts#96a0e00 id:Vector = Updates; @@ -1629,9 +1638,9 @@ messages.getFactCheck#b9cdc5ee peer:InputPeer msg_id:Vector = Vector = Bool; diff --git a/src/lib/gramjs/tl/static/api.tl b/src/lib/gramjs/tl/static/api.tl index d4b7d4103..1a84527ac 100644 --- a/src/lib/gramjs/tl/static/api.tl +++ b/src/lib/gramjs/tl/static/api.tl @@ -185,6 +185,8 @@ messageActionGiftStars#45d5b021 flags:# currency:string amount:long stars:long c messageActionPrizeStars#b00c47a2 flags:# unclaimed:flags.0?true stars:long transaction_id:string boost_peer:Peer giveaway_msg_id:int = MessageAction; messageActionStarGift#4717e8a4 flags:# name_hidden:flags.0?true saved:flags.2?true converted:flags.3?true upgraded:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true gift:StarGift message:flags.1?TextWithEntities convert_stars:flags.4?long upgrade_msg_id:flags.5?int upgrade_stars:flags.8?long from_id:flags.11?Peer peer:flags.12?Peer saved_id:flags.12?long = MessageAction; messageActionStarGiftUnique#acdfcb81 flags:# upgrade:flags.0?true transferred:flags.1?true saved:flags.2?true refunded:flags.5?true gift:StarGift can_export_at:flags.3?int transfer_stars:flags.4?long from_id:flags.6?Peer peer:flags.7?Peer saved_id:flags.7?long = MessageAction; +messageActionPaidMessagesRefunded#ac1f1fcd count:int stars:long = MessageAction; +messageActionPaidMessagesPrice#bcd71419 stars:long = MessageAction; dialog#d58a08c6 flags:# pinned:flags.2?true unread_mark:flags.3?true view_forum_as_messages:flags.6?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 ttl_period:flags.5?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; @@ -204,6 +206,7 @@ geoPoint#b2a2f663 flags:# long:double lat:double access_hash:long accuracy_radiu auth.sentCode#5e002502 flags:# type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int = auth.SentCode; auth.sentCodeSuccess#2390fe44 authorization:auth.Authorization = auth.SentCode; +auth.sentCodePaymentRequired#d7cef980 store_product:string phone_code_hash:string = auth.SentCode; auth.authorization#2ea2c0d4 flags:# setup_password_required:flags.1?true otherwise_relogin_days:flags.1?int tmp_sessions:flags.0?int future_auth_token:flags.2?bytes user:User = auth.Authorization; auth.authorizationSignUpRequired#44747e9a flags:# terms_of_service:flags.0?help.TermsOfService = auth.Authorization; @@ -236,7 +239,7 @@ inputReportReasonFake#f5ddd6e7 = ReportReason; inputReportReasonIllegalDrugs#a8eb2be = ReportReason; inputReportReasonPersonalDetails#9ec7863d = ReportReason; -userFull#d2234ea0 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 voice_messages_forbidden:flags.20?true translations_disabled:flags.23?true stories_pinned_available:flags.26?true blocked_my_stories_from:flags.27?true wallpaper_overridden:flags.28?true contact_require_premium:flags.29?true read_dates_private:flags.30?true flags2:# sponsored_enabled:flags2.7?true can_view_revenue:flags2.9?true bot_can_manage_emoji_status:flags2.10?true id:long about:flags.1?string settings:PeerSettings personal_photo:flags.21?Photo profile_photo:flags.2?Photo fallback_photo:flags.22?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 wallpaper:flags.24?WallPaper stories:flags.25?PeerStories business_work_hours:flags2.0?BusinessWorkHours business_location:flags2.1?BusinessLocation business_greeting_message:flags2.2?BusinessGreetingMessage business_away_message:flags2.3?BusinessAwayMessage business_intro:flags2.4?BusinessIntro birthday:flags2.5?Birthday personal_channel_id:flags2.6?long personal_channel_message:flags2.6?int stargifts_count:flags2.8?int starref_program:flags2.11?StarRefProgram bot_verification:flags2.12?BotVerification send_paid_messages_stars:flags2.14?long = UserFull; +userFull#99e78045 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 voice_messages_forbidden:flags.20?true translations_disabled:flags.23?true stories_pinned_available:flags.26?true blocked_my_stories_from:flags.27?true wallpaper_overridden:flags.28?true contact_require_premium:flags.29?true read_dates_private:flags.30?true flags2:# sponsored_enabled:flags2.7?true can_view_revenue:flags2.9?true bot_can_manage_emoji_status:flags2.10?true display_gifts_button:flags2.16?true id:long about:flags.1?string settings:PeerSettings personal_photo:flags.21?Photo profile_photo:flags.2?Photo fallback_photo:flags.22?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 wallpaper:flags.24?WallPaper stories:flags.25?PeerStories business_work_hours:flags2.0?BusinessWorkHours business_location:flags2.1?BusinessLocation business_greeting_message:flags2.2?BusinessGreetingMessage business_away_message:flags2.3?BusinessAwayMessage business_intro:flags2.4?BusinessIntro birthday:flags2.5?Birthday personal_channel_id:flags2.6?long personal_channel_message:flags2.6?int stargifts_count:flags2.8?int starref_program:flags2.11?StarRefProgram bot_verification:flags2.12?BotVerification send_paid_messages_stars:flags2.14?long disallowed_gifts:flags2.15?DisallowedGiftsSettings = UserFull; contact#145ade0b user_id:long mutual:Bool = Contact; @@ -427,6 +430,7 @@ updateBusinessBotCallbackQuery#1ea2fda7 flags:# query_id:long user_id:long conne updateStarsRevenueStatus#a584b019 peer:Peer status:StarsRevenueStatus = Update; updateBotPurchasedPaidMedia#283bd312 user_id:long payload:string qts:int = Update; updatePaidReactionPrivacy#8b725fce private:PaidReactionPrivacy = Update; +updateSentPhoneCode#504aa18f sent_code:auth.SentCode = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; @@ -897,7 +901,6 @@ phoneCallDiscardReasonMissed#85e42301 = PhoneCallDiscardReason; phoneCallDiscardReasonDisconnect#e095c1a0 = PhoneCallDiscardReason; phoneCallDiscardReasonHangup#57adc690 = PhoneCallDiscardReason; phoneCallDiscardReasonBusy#faf7e8c9 = PhoneCallDiscardReason; -phoneCallDiscardReasonAllowGroupCall#afe2b839 encrypted_key:bytes = PhoneCallDiscardReason; dataJSON#7d748d04 data:string = DataJSON; @@ -1311,7 +1314,7 @@ statsGroupTopInviter#535f779d user_id:long invitations:int = StatsGroupTopInvite stats.megagroupStats#ef7ff916 period:StatsDateRangeDays members:StatsAbsValueAndPrev messages:StatsAbsValueAndPrev viewers:StatsAbsValueAndPrev posters:StatsAbsValueAndPrev growth_graph:StatsGraph members_graph:StatsGraph new_members_by_source_graph:StatsGraph languages_graph:StatsGraph messages_graph:StatsGraph actions_graph:StatsGraph top_hours_graph:StatsGraph weekdays_graph:StatsGraph top_posters:Vector top_admins:Vector top_inviters:Vector users:Vector = stats.MegagroupStats; -globalPrivacySettings#c9d8df1c flags:# archive_and_mute_new_noncontact_peers:flags.0?true keep_archived_unmuted:flags.1?true keep_archived_folders:flags.2?true hide_read_marks:flags.3?true new_noncontact_peers_require_premium:flags.4?true noncontact_peers_paid_stars:flags.5?long = GlobalPrivacySettings; +globalPrivacySettings#fe41b34f flags:# archive_and_mute_new_noncontact_peers:flags.0?true keep_archived_unmuted:flags.1?true keep_archived_folders:flags.2?true hide_read_marks:flags.3?true new_noncontact_peers_require_premium:flags.4?true display_gifts_button:flags.7?true noncontact_peers_paid_stars:flags.5?long disallowed_gifts:flags.6?DisallowedGiftsSettings = GlobalPrivacySettings; help.countryCode#4203c5ef flags:# country_code:string prefixes:flags.0?Vector patterns:flags.1?Vector = help.CountryCode; @@ -1481,6 +1484,7 @@ inputInvoiceStarGift#e8625e92 flags:# hide_name:flags.0?true include_upgrade:fla inputInvoiceStarGiftUpgrade#4d818d5d flags:# keep_original_details:flags.0?true stargift:InputSavedStarGift = InputInvoice; inputInvoiceStarGiftTransfer#4a5f5bd9 stargift:InputSavedStarGift to_id:InputPeer = InputInvoice; inputInvoicePremiumGiftStars#dabab2ef flags:# user_id:InputUser months:int message:flags.0?TextWithEntities = InputInvoice; +inputInvoiceBusinessBotTransferStars#f4997e42 bot:InputUser stars:long = InputInvoice; payments.exportedInvoice#aed0cbd9 url:string = payments.ExportedInvoice; @@ -1495,6 +1499,7 @@ inputStorePaymentPremiumGiveaway#160544ca flags:# only_new_subscribers:flags.0?t inputStorePaymentStarsTopup#dddd0f56 stars:long currency:string amount:long = InputStorePaymentPurpose; inputStorePaymentStarsGift#1d741ef7 user_id:InputUser stars:long currency:string amount:long = InputStorePaymentPurpose; inputStorePaymentStarsGiveaway#751f08fa flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true stars:long boost_peer:InputPeer additional_peers:flags.1?Vector countries_iso2:flags.2?Vector prize_description:flags.4?string random_id:long until_date:int currency:string amount:long users:int = InputStorePaymentPurpose; +inputStorePaymentAuthCode#9bb2636d flags:# restore:flags.0?true phone_number:string phone_code_hash:string currency:string amount:long = InputStorePaymentPurpose; paymentFormMethod#88f8f21b url:string title:string = PaymentFormMethod; @@ -1753,7 +1758,7 @@ inputQuickReplyShortcutId#1190cf1 shortcut_id:int = InputQuickReplyShortcut; messages.quickReplies#c68d6695 quick_replies:Vector messages:Vector chats:Vector users:Vector = messages.QuickReplies; messages.quickRepliesNotModified#5f91eb5b = messages.QuickReplies; -connectedBot#bd068601 flags:# can_reply:flags.0?true bot_id:long recipients:BusinessBotRecipients = ConnectedBot; +connectedBot#cd64636c flags:# bot_id:long recipients:BusinessBotRecipients rights:BusinessBotRights = ConnectedBot; account.connectedBots#17d7f87b connected_bots:Vector users:Vector = account.ConnectedBots; @@ -1761,7 +1766,7 @@ messages.dialogFilters#2ad93719 flags:# tags_enabled:flags.0?true filters:Vector birthday#6c8e1e06 flags:# day:int month:int year:flags.0?int = Birthday; -botBusinessConnection#896433b4 flags:# can_reply:flags.0?true disabled:flags.1?true connection_id:string user_id:long dc_id:int date:int = BotBusinessConnection; +botBusinessConnection#8f34b2f5 flags:# disabled:flags.1?true connection_id:string user_id:long dc_id:int date:int rights:flags.2?BusinessBotRights = BotBusinessConnection; inputBusinessIntro#9c469cd flags:# title:string description:string sticker:flags.0?InputDocument = InputBusinessIntro; @@ -1945,6 +1950,15 @@ requirementToContactEmpty#50a9839 = RequirementToContact; requirementToContactPremium#e581e4e9 = RequirementToContact; requirementToContactPaidMessages#b4f67e93 stars_amount:long = RequirementToContact; +businessBotRights#a0624cf7 flags:# reply:flags.0?true read_messages:flags.1?true delete_sent_messages:flags.2?true delete_received_messages:flags.3?true edit_name:flags.4?true edit_bio:flags.5?true edit_profile_photo:flags.6?true edit_username:flags.7?true view_gifts:flags.8?true sell_gifts:flags.9?true change_gift_settings:flags.10?true transfer_and_upgrade_gifts:flags.11?true transfer_stars:flags.12?true manage_stories:flags.13?true = BusinessBotRights; + +disallowedGiftsSettings#71f276c4 flags:# disallow_unlimited_stargifts:flags.0?true disallow_limited_stargifts:flags.1?true disallow_unique_stargifts:flags.2?true disallow_premium_gifts:flags.3?true = DisallowedGiftsSettings; + +sponsoredPeer#c69708d3 flags:# random_id:bytes peer:Peer sponsor_info:flags.0?string additional_info:flags.1?string = SponsoredPeer; + +contacts.sponsoredPeersEmpty#ea32b4b1 = contacts.SponsoredPeers; +contacts.sponsoredPeers#eb032884 peers:Vector chats:Vector users:Vector = contacts.SponsoredPeers; + ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; @@ -1956,7 +1970,7 @@ invokeWithMessagesRange#365275f2 {X:Type} range:MessageRange query:!X = X; invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X; invokeWithBusinessConnection#dd289f8e {X:Type} connection_id:string query:!X = X; invokeWithGooglePlayIntegrity#1df92984 {X:Type} nonce:string token:string query:!X = X; -invokeWithApnsSecret#dae54f8 {X:Type} nonce:string secret:string query:!X = X; +invokeWithApnsSecret#0dae54f8 {X:Type} nonce:string secret:string query:!X = X; invokeWithReCaptcha#adbb0f94 {X:Type} token:string query:!X = X; auth.sendCode#a677244f phone_number:string api_id:int api_hash:string settings:CodeSettings = auth.SentCode; @@ -2079,7 +2093,7 @@ account.updateBusinessWorkHours#4b00e066 flags:# business_work_hours:flags.0?Bus account.updateBusinessLocation#9e6b131a flags:# geo_point:flags.1?InputGeoPoint address:flags.0?string = Bool; account.updateBusinessGreetingMessage#66cdafc4 flags:# message:flags.0?InputBusinessGreetingMessage = Bool; account.updateBusinessAwayMessage#a26a7fa5 flags:# message:flags.0?InputBusinessAwayMessage = Bool; -account.updateConnectedBot#43d8521d flags:# can_reply:flags.0?true deleted:flags.1?true bot:InputUser recipients:InputBusinessBotRecipients = Updates; +account.updateConnectedBot#66a08c7e flags:# deleted:flags.1?true rights:flags.0?BusinessBotRights bot:InputUser recipients:InputBusinessBotRecipients = Updates; account.getConnectedBots#4ea4c80f = account.ConnectedBots; account.getBotBusinessConnection#76a86270 connection_id:string = Updates; account.updateBusinessIntro#a614d034 flags:# intro:flags.0?InputBusinessIntro = Bool; @@ -2130,6 +2144,7 @@ contacts.importContactToken#13005788 token:string = User; contacts.editCloseFriends#ba6705f0 id:Vector = Bool; contacts.setBlocked#94c65c76 flags:# my_stories_from:flags.0?true id:Vector limit:int = Bool; contacts.getBirthdays#daeda864 = contacts.ContactBirthdays; +contacts.getSponsoredPeers#b6c8c393 q:string = contacts.SponsoredPeers; messages.getMessages#63c66506 id:Vector = messages.Messages; messages.getDialogs#a0f4cb4f flags:# exclude_pinned:flags.0?true folder_id:flags.1?int offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:long = messages.Dialogs; @@ -2348,9 +2363,9 @@ messages.requestMainWebView#c9e01e7b flags:# compact:flags.7?true fullscreen:fla messages.sendPaidReaction#58bbcb50 flags:# peer:InputPeer msg_id:int count:int random_id:long private:flags.0?PaidReactionPrivacy = Updates; messages.togglePaidReactionPrivacy#435885b5 peer:InputPeer msg_id:int private:PaidReactionPrivacy = Bool; messages.getPaidReactionPrivacy#472455aa = Updates; -messages.viewSponsoredMessage#673ad8f1 peer:InputPeer random_id:bytes = Bool; -messages.clickSponsoredMessage#f093465 flags:# media:flags.0?true fullscreen:flags.1?true peer:InputPeer random_id:bytes = Bool; -messages.reportSponsoredMessage#1af3dbb8 peer:InputPeer random_id:bytes option:bytes = channels.SponsoredMessageReportResult; +messages.viewSponsoredMessage#269e3643 random_id:bytes = Bool; +messages.clickSponsoredMessage#8235057e flags:# media:flags.0?true fullscreen:flags.1?true random_id:bytes = Bool; +messages.reportSponsoredMessage#12cbf0c4 random_id:bytes option:bytes = channels.SponsoredMessageReportResult; messages.getSponsoredMessages#9bd2f439 peer:InputPeer = messages.SponsoredMessages; messages.savePreparedInlineMessage#f21f7f2f flags:# result:InputBotInlineResult user_id:InputUser peer_types:flags.0?Vector = messages.BotPreparedInlineMessage; messages.getPreparedInlineMessage#857ebdb8 bot:InputUser id:string = messages.PreparedInlineMessage; @@ -2506,7 +2521,6 @@ payments.getBankCardData#2e79d779 number:string = payments.BankCardData; payments.exportInvoice#f91b065 invoice_media:InputMedia = payments.ExportedInvoice; payments.assignAppStoreTransaction#80ed747d receipt:bytes purpose:InputStorePaymentPurpose = Updates; payments.assignPlayMarketTransaction#dffd50d3 receipt:DataJSON purpose:InputStorePaymentPurpose = Updates; -payments.canPurchasePremium#9fc19eb6 purpose:InputStorePaymentPurpose = Bool; payments.getPremiumGiftCodeOptions#2757ba54 flags:# boost_peer:flags.0?InputPeer = Vector; payments.checkGiftCode#8e51b4c1 slug:string = payments.CheckedGiftCode; payments.applyGiftCode#f6e26854 slug:string = Updates; @@ -2544,6 +2558,7 @@ payments.getSavedStarGift#b455a106 stargift:Vector = payment payments.getStarGiftWithdrawalUrl#d06e93a8 stargift:InputSavedStarGift password:InputCheckPasswordSRP = payments.StarGiftWithdrawalUrl; payments.toggleChatStarGiftNotifications#60eaefa1 flags:# enabled:flags.0?true peer:InputPeer = Bool; payments.toggleStarGiftsPinnedToTop#1513e7b0 peer:InputPeer stargift:Vector = Bool; +payments.canPurchaseStore#4fdc5ea7 purpose:InputStorePaymentPurpose = Bool; stickers.createStickerSet#9021ab67 flags:# masks:flags.0?true emojis:flags.5?true text_color:flags.6?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector software:flags.3?string = messages.StickerSet; stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; diff --git a/src/styles/icons.scss b/src/styles/icons.scss index 958982e5b..64149d8ae 100644 --- a/src/styles/icons.scss +++ b/src/styles/icons.scss @@ -127,168 +127,169 @@ $icons-map: ( "forums": "\f15a", "forward": "\f15b", "fragment": "\f15c", - "fullscreen": "\f15d", - "gifs": "\f15e", - "gift": "\f15f", - "group-filled": "\f160", - "group": "\f161", - "grouped-disable": "\f162", - "grouped": "\f163", - "hand-stop": "\f164", - "hashtag": "\f165", - "heart-outline": "\f166", - "heart": "\f167", - "help": "\f168", - "info-filled": "\f169", - "info": "\f16a", - "install": "\f16b", - "italic": "\f16c", - "key": "\f16d", - "keyboard": "\f16e", - "lamp": "\f16f", - "language": "\f170", - "large-pause": "\f171", - "large-play": "\f172", - "link-badge": "\f173", - "link-broken": "\f174", - "link": "\f175", - "location": "\f176", - "lock-badge": "\f177", - "lock": "\f178", - "logout": "\f179", - "loop": "\f17a", - "mention": "\f17b", - "message-failed": "\f17c", - "message-pending": "\f17d", - "message-read": "\f17e", - "message-succeeded": "\f17f", - "message": "\f180", - "microphone-alt": "\f181", - "microphone": "\f182", - "monospace": "\f183", - "more-circle": "\f184", - "more": "\f185", - "move-caption-down": "\f186", - "move-caption-up": "\f187", - "mute": "\f188", - "muted": "\f189", - "my-notes": "\f18a", - "new-chat-filled": "\f18b", - "next": "\f18c", - "nochannel": "\f18d", - "noise-suppression": "\f18e", - "non-contacts": "\f18f", - "one-filled": "\f190", - "open-in-new-tab": "\f191", - "password-off": "\f192", - "pause": "\f193", - "permissions": "\f194", - "phone-discard-outline": "\f195", - "phone-discard": "\f196", - "phone": "\f197", - "photo": "\f198", - "pin-badge": "\f199", - "pin-list": "\f19a", - "pin": "\f19b", - "pinned-chat": "\f19c", - "pinned-message": "\f19d", - "pip": "\f19e", - "play-story": "\f19f", - "play": "\f1a0", - "poll": "\f1a1", - "previous": "\f1a2", - "privacy-policy": "\f1a3", - "proof-of-ownership": "\f1a4", - "quote-text": "\f1a5", - "quote": "\f1a6", - "radial-badge": "\f1a7", - "readchats": "\f1a8", - "recent": "\f1a9", - "reload": "\f1aa", - "remove-quote": "\f1ab", - "remove": "\f1ac", - "reopen-topic": "\f1ad", - "replace": "\f1ae", - "replies": "\f1af", - "reply-filled": "\f1b0", - "reply": "\f1b1", - "revenue-split": "\f1b2", - "revote": "\f1b3", - "save-story": "\f1b4", - "saved-messages": "\f1b5", - "schedule": "\f1b6", - "search": "\f1b7", - "select": "\f1b8", - "send-outline": "\f1b9", - "send": "\f1ba", - "settings-filled": "\f1bb", - "settings": "\f1bc", - "share-filled": "\f1bd", - "share-screen-outlined": "\f1be", - "share-screen-stop": "\f1bf", - "share-screen": "\f1c0", - "show-message": "\f1c1", - "sidebar": "\f1c2", - "skip-next": "\f1c3", - "skip-previous": "\f1c4", - "smallscreen": "\f1c5", - "smile": "\f1c6", - "sort": "\f1c7", - "speaker-muted-story": "\f1c8", - "speaker-outline": "\f1c9", - "speaker-story": "\f1ca", - "speaker": "\f1cb", - "spoiler-disable": "\f1cc", - "spoiler": "\f1cd", - "sport": "\f1ce", - "star": "\f1cf", - "stars-lock": "\f1d0", - "stats": "\f1d1", - "stealth-future": "\f1d2", - "stealth-past": "\f1d3", - "stickers": "\f1d4", - "stop-raising-hand": "\f1d5", - "stop": "\f1d6", - "story-caption": "\f1d7", - "story-expired": "\f1d8", - "story-priority": "\f1d9", - "story-reply": "\f1da", - "strikethrough": "\f1db", - "tag-add": "\f1dc", - "tag-crossed": "\f1dd", - "tag-filter": "\f1de", - "tag-name": "\f1df", - "tag": "\f1e0", - "timer": "\f1e1", - "toncoin": "\f1e2", - "trade": "\f1e3", - "transcribe": "\f1e4", - "truck": "\f1e5", - "unarchive": "\f1e6", - "underlined": "\f1e7", - "unique-profile": "\f1e8", - "unlock-badge": "\f1e9", - "unlock": "\f1ea", - "unmute": "\f1eb", - "unpin": "\f1ec", - "unread": "\f1ed", - "up": "\f1ee", - "user-filled": "\f1ef", - "user-online": "\f1f0", - "user": "\f1f1", - "video-outlined": "\f1f2", - "video-stop": "\f1f3", - "video": "\f1f4", - "view-once": "\f1f5", - "voice-chat": "\f1f6", - "volume-1": "\f1f7", - "volume-2": "\f1f8", - "volume-3": "\f1f9", - "web": "\f1fa", - "webapp": "\f1fb", - "word-wrap": "\f1fc", - "zoom-in": "\f1fd", - "zoom-out": "\f1fe", + "frozen-time": "\f15d", + "fullscreen": "\f15e", + "gifs": "\f15f", + "gift": "\f160", + "group-filled": "\f161", + "group": "\f162", + "grouped-disable": "\f163", + "grouped": "\f164", + "hand-stop": "\f165", + "hashtag": "\f166", + "heart-outline": "\f167", + "heart": "\f168", + "help": "\f169", + "info-filled": "\f16a", + "info": "\f16b", + "install": "\f16c", + "italic": "\f16d", + "key": "\f16e", + "keyboard": "\f16f", + "lamp": "\f170", + "language": "\f171", + "large-pause": "\f172", + "large-play": "\f173", + "link-badge": "\f174", + "link-broken": "\f175", + "link": "\f176", + "location": "\f177", + "lock-badge": "\f178", + "lock": "\f179", + "logout": "\f17a", + "loop": "\f17b", + "mention": "\f17c", + "message-failed": "\f17d", + "message-pending": "\f17e", + "message-read": "\f17f", + "message-succeeded": "\f180", + "message": "\f181", + "microphone-alt": "\f182", + "microphone": "\f183", + "monospace": "\f184", + "more-circle": "\f185", + "more": "\f186", + "move-caption-down": "\f187", + "move-caption-up": "\f188", + "mute": "\f189", + "muted": "\f18a", + "my-notes": "\f18b", + "new-chat-filled": "\f18c", + "next": "\f18d", + "nochannel": "\f18e", + "noise-suppression": "\f18f", + "non-contacts": "\f190", + "one-filled": "\f191", + "open-in-new-tab": "\f192", + "password-off": "\f193", + "pause": "\f194", + "permissions": "\f195", + "phone-discard-outline": "\f196", + "phone-discard": "\f197", + "phone": "\f198", + "photo": "\f199", + "pin-badge": "\f19a", + "pin-list": "\f19b", + "pin": "\f19c", + "pinned-chat": "\f19d", + "pinned-message": "\f19e", + "pip": "\f19f", + "play-story": "\f1a0", + "play": "\f1a1", + "poll": "\f1a2", + "previous": "\f1a3", + "privacy-policy": "\f1a4", + "proof-of-ownership": "\f1a5", + "quote-text": "\f1a6", + "quote": "\f1a7", + "radial-badge": "\f1a8", + "readchats": "\f1a9", + "recent": "\f1aa", + "reload": "\f1ab", + "remove-quote": "\f1ac", + "remove": "\f1ad", + "reopen-topic": "\f1ae", + "replace": "\f1af", + "replies": "\f1b0", + "reply-filled": "\f1b1", + "reply": "\f1b2", + "revenue-split": "\f1b3", + "revote": "\f1b4", + "save-story": "\f1b5", + "saved-messages": "\f1b6", + "schedule": "\f1b7", + "search": "\f1b8", + "select": "\f1b9", + "send-outline": "\f1ba", + "send": "\f1bb", + "settings-filled": "\f1bc", + "settings": "\f1bd", + "share-filled": "\f1be", + "share-screen-outlined": "\f1bf", + "share-screen-stop": "\f1c0", + "share-screen": "\f1c1", + "show-message": "\f1c2", + "sidebar": "\f1c3", + "skip-next": "\f1c4", + "skip-previous": "\f1c5", + "smallscreen": "\f1c6", + "smile": "\f1c7", + "sort": "\f1c8", + "speaker-muted-story": "\f1c9", + "speaker-outline": "\f1ca", + "speaker-story": "\f1cb", + "speaker": "\f1cc", + "spoiler-disable": "\f1cd", + "spoiler": "\f1ce", + "sport": "\f1cf", + "star": "\f1d0", + "stars-lock": "\f1d1", + "stats": "\f1d2", + "stealth-future": "\f1d3", + "stealth-past": "\f1d4", + "stickers": "\f1d5", + "stop-raising-hand": "\f1d6", + "stop": "\f1d7", + "story-caption": "\f1d8", + "story-expired": "\f1d9", + "story-priority": "\f1da", + "story-reply": "\f1db", + "strikethrough": "\f1dc", + "tag-add": "\f1dd", + "tag-crossed": "\f1de", + "tag-filter": "\f1df", + "tag-name": "\f1e0", + "tag": "\f1e1", + "timer": "\f1e2", + "toncoin": "\f1e3", + "trade": "\f1e4", + "transcribe": "\f1e5", + "truck": "\f1e6", + "unarchive": "\f1e7", + "underlined": "\f1e8", + "unique-profile": "\f1e9", + "unlock-badge": "\f1ea", + "unlock": "\f1eb", + "unmute": "\f1ec", + "unpin": "\f1ed", + "unread": "\f1ee", + "up": "\f1ef", + "user-filled": "\f1f0", + "user-online": "\f1f1", + "user": "\f1f2", + "video-outlined": "\f1f3", + "video-stop": "\f1f4", + "video": "\f1f5", + "view-once": "\f1f6", + "voice-chat": "\f1f7", + "volume-1": "\f1f8", + "volume-2": "\f1f9", + "volume-3": "\f1fa", + "web": "\f1fb", + "webapp": "\f1fc", + "word-wrap": "\f1fd", + "zoom-in": "\f1fe", + "zoom-out": "\f1ff", ); .icon-active-sessions::before { @@ -567,6 +568,9 @@ $icons-map: ( .icon-fragment::before { content: map.get($icons-map, "fragment"); } +.icon-frozen-time::before { + content: map.get($icons-map, "frozen-time"); +} .icon-fullscreen::before { content: map.get($icons-map, "fullscreen"); } diff --git a/src/styles/icons.woff b/src/styles/icons.woff index 96d5a77a6c770884b11d0e7d7ad1da8f81216f85..0d883473095a0f6b568ea087508a988aecf1e956 100644 GIT binary patch delta 30911 zcmV)WK(4=}{{h^90u*;oMn(Vu00000fLs6z00000^Bj>BKYzJnZDDW#00D>q00fNy z01s3&22UOAQBKU zC~Ht?@USW&!6PD62=0c2??)th_czYCjMb78YDXv^$tANeUjK?+frA{3<<#VNrTl%y1;`I4_FLs`mEo(fc?5|#OyDpaK! z)u};EYVi%VsY6}re^H+XG^7!YX+l$)(VP~vq!q1cLtEO>o(^=R6P@WoSGv)i9`vLa zz3D?=`q7^Oe9J%vF_<9?Wf;R5!AM3inlX%J9OL?BvTGp|ie+~T3M*iSW{^D;ov6(Gw zWgFYs!A^Fun?3AhANx7LK@M@4BOK)z$2q}CPH~zuoaG$nxxhs(ahWSz$y!A)*) zn>*a)9`|{`Lmu&%Cp;yM zCW4_xG|gThf7CQZfk>vg3`926D25uBVi;;n)3*!6GSt|H8plxM8frX4 zjc=$43^k#leqyMJ3^lQ#CNb2chMLS!lN)LZLrrO@sSGu>p{6m^PYpG#p{6s`^oE+j zP(L%&jE0)YP%|6q=Z2caP_vr;V*}X?HM^naFw~ref11lsa~oSv%wWFbSGStq7+Qm@28frH~ z?QW<&47I1B_A=DohT6wa`xUV}Z!B8g}>Lf#*e{85z40WoZPBYZ+4fO{@{n1c=GSumY zI>S(B8tN=Voo%Rd40W!d&NI~chPuE|7aHm!LtSjBOAK|Xp)NDj<%YV#P*)o2DntF* zP=7JhUk&v)LtSmCYYcU*p{_I3^@h5^P=7bnjfVP%q5f&8e;MlEhPug6Hyi2}L)~hq zf7=XoyP@td)SZU9%TRY4>K;SgYpDASb-$q=Fw}#FddN@@8|o25J!+`O4E4C7o-ovt zhI-0SPaEnPLp^J#=M43{pK#M9 zYpC}O^}eA#Fw}>J`p8fp8|o87eQKxye?xs{sLu`cg`vJQ)K`Z3+ECvZ>RUs7XQ=ND z^@E}QW2heuHOvV67Z7CU<^TWyc$~Do3A7~FRUjB|k3BLXW63>#X8z3l|5w%D@@Hn1 zO7(wLNh&R6NhQgWO0q4lITWR}EPi)86ZlJvSVhVR|U-rxuskMi&CaFY!8PLaLwKABG7 zuCCoAak@K!t9W9JG zgs|9`!MH4x5(juF>*Aw6Q#PfxV*Uqokto}wy6zhBl&}OmO5sa+B|Kvc%Pm5y_)f~I zjOc%5!edXCE|jDfb5d1~f)9QXg73Zy-;MR~Bo?MAlDy{A`h9mV|Byame^q$-`QqhJ zpfIfL8{dGjJxY{u#JJUXgJJXs*z4Jlz<(I6EFYL%7{HMp8yuap~LA>riTNDIeVtQt`lKf2LwpDwzu4BLB-kiu@hE^3BSbs_7|xi7Q`uX62^T_Ab`( z$>KeEVHf_+C>Sgb14F3!Fq|W(&EQQLp)ocN3}d11?3cHznhdmBqV z3@~DY;W)1_nT}v6hS*megwfLnb&CY{6(_Lk2k$3Bk*ZKq)TE$%e_no1+-$BloAL7< zCnz}q@tsoObnYMu>s{xWQ44CXx1gz9x3^5nhGWFWo^cPfcyFKVwuqjdDXt7$4{9>P zj-Pg(2JZA=BV3w=pcGl@^bvh5!R=bsw!(8(Mg5HI4 z&GzHg@JJilXU9U-e{dz#l&z{#7yhjoSXN+qQFIGFzSa4MzGJ$)AlcpC7^ByE!xg*jC*fc~JXU~tAbqx)?2`mFw&WQZZN% zRKi%Ps3V2r2-%6?#FdDIn3BQ1{15Y@U-kHR-rE8T+mMd*D zIpawNH-6hRe`AwU^Kal+Q^A#~O6Ou&g`p4QWS1F*f2?f7sQIDgnen+2RN*4!4=cxa zR1gPMuj0WcX*OXvMS)8q!!;6P!#Hic2Ii`}N%9`YJ{iJ{wFnGC)*Vcy0DS{M!GIZB zxQb*3RpBayG25G8RNcW?qjIT7Y`lkvCLh1I$Gvj7f4A0+WB4?iYt80;!X(@@Et3=J zaM$-7zQQG=tQ3;4#Ffp>K?>j%Hp17#pZRp$)h~j>_cqrWq`BUB+H{zT zlCtCgq0DZzn>JhJfOx#Ydf#VwG2GhQ4%s;v|0D?zVoS{ue55j@9*bk7X53;tZ~PPE zH;msle|{Gr3|g+zY&vNX0HGvSdbz2dkJzJFY=f~Llug z$>!{|g|&x+38K0jkM(ASX>aE*{X_}D1-GaWe~O!ko090vxie9WMT<)zsS=V4VI?k; zJdupKB`1s+&VytL}Sn6DkqvIMP<6 zf8OoZm1VjvA*LmX=U2Czl*a;qp8{=ywZUnPlr0I%fiNnqvM_5sE*)1ASXRoi@hxE- zhwv6SA;PiLA<1MhBXhDZo z3=gpS45!09!8#caWtu730=(2B)4YHye`>t9NqPf-2tZJP7pDN%>)j;5Lxno-1;KoA zAy|#pv2c+R*ROBZ%RQgc2f1?Cug7_1SP6-WR)Y(|XX0+hp&M9ukW#-FH8yL+cL}}7 z9K{#(vJCA^j3KtP58$;)aLqz1klRAOY&?XME+9kb1_Cm41%OjcC)o(Vd(eXye^`l% zop(90Ow49-C28J8`rP6}rYzoSa2Vt26+lI%^G;WKN_{zS8m8q~buah`AfV(XsLcjg zjkTKa%xg$w!HkA_7#-cl7}}UY8^^}0jJu2r#;c8s#%qm7jK^VR<_j$=NIBqcTxlms z25WQHg;R*Idfk9%RuXV~PvP1cf5I|tQ(TjqFblBYrsHHs?Tt>6?VX|89`7V7f#V}j zIk8GCqPu1$GIrQ=R{&kxcxXQ50bAHbF8vJh=4gn3?sig{nUe8+WcnC1K$LLML4?%BQ<$YuZx?047gz_K7JMk1Bf)g$l21nGw3&P z8{OHqivp4F z4zW+jjKXbXqL43A1!+L~oxM!?O8;O0dE197&@8V0#r;V(;uP6!cu0J`~J0MHqyqNn}PG8~zekeH|KM%g+IBA7X{970CG zkBlhu*Cy*#IHMfT-gCf&WCy>j*8>W6x5vJX-!_Mn{tzq>-n32l6mVYy-ngUT{vPA4 zlR6PkAD6OhWWXH)?9)@g?@>0Oq)LCDm9i44R^MBx6DU2Jlc*7)0Sl8#5`GzzmY^s_ zQ^HG%Qi&`9JWHu6am^b@z>iOcli?CdBX#l$$mZlvbRMl(F1LviVUwfuz?-2^#OAJ5 zne*eu9~oZ-lTH&Nf4zM~$o->7kD4}deoB_@q@lzWq3W@podmRhz7K~&Mlt@L^nupy zXiC0`k}VJ}ppFIk0*Pb@GX+=ixAD8H$rgg@^tVjvr4{pn$zwlQDvtnH69*`12Nude)D^hISp!ZLN1e5~M ze+h`;(dCoRo8lp<2>-Zn7Nwb7)`R!DdUSKjoby-H`P=7Rgzr>c8Jrmm&b$f_d$5?A zoYR{afM8KR3)5*8_u=r1OqlHTg3FVf=LKUf5BA}AE3kr$>AVZ7H}4!y{RT>d{qkm1nM*b04t!7Pz6|QABKGM<7=9U=pR zDplZ8rf|d0*MAT75c{aKfQN^0HO)o{yHn)AfRj5wf3)^zS%>GzP1;Us9Gk^wec8wH|*}d1ulhNr{sLnjYu2*NZBJRFaM6EE5DY%q%(W#`Q7L7 zOTR?Fl6z&8DZT;!$We0CC>w3#h%wD|Kush}N02mW<>Ck>su>j@7GQX!T^2!F{NPiYOr7s5US7Wjx(O-P2q( zJ}UrbQE?|Brk^Mq8EDmr9|jBx1z^MDz>GU(e_M$g=u=Ai*2BPqiDLt}ulPFwjvF!E z)fLT~fI|U3l&mP>#htiL5`SGtDb`?JA3*&^`HU1p4#Z&?q_uK40q9jfLD(7O>g=27 z8|ra@)XFb60haKMw#ttSyTA%?>W>*uz!vWx*M-jIG{7lC7`REcN!~^Rx8VkwNiEqjuve*2jPq4ahS<9y zfg)$7=(~f>fxF5ru5S)tY!u$@qQXfG?10JuCC1IL5k-wI9zy7OwMtN;4`hCq2c^)B zT>^pub%FT9jQBv$ElUuuQmbifQrUmAu7^io z0CFqA@v+lTLCI&7ECoV~$xFJc4y?|JhI?(;$>ug4fYRv_b{gr1X;@w~toJ35`rIHT zaqtBnj{!pQB_#%5l;T(5p7#PApsWEi34SsFCJYV;eK13wD}T&qA4ItOc_{{cp$c8Z zQ4$+HkRSAloQ{@;Oj~Gh+{VM+qLGs!@_|q#L78t*=w<+UDy*xi|0v5Lb7rUlAk5~P z093ortVMqh(rQ)UQmhyDCoS04)DNApR5^yW!|W@Oz{#0VSt+*uow%^xiG52WY4u9Y zFl=`45SG%koqwj6@Og2a7k^&D8_(#mIKW%wNW%Re!XmEzkHVP3mHn{U#kawsnyw_t zN?ME)%rx*HTLo8{55W>M49IDU^QPo74}_zGCSr9}_gfkZ|5Har(2X>B0h(SaN6I;U z8V+UD^1pywQtYVRuxO3$Ac6Lzq^zQ}^bvdp4w0%xP=ED#Q5?$Gb^!jFbG%YF`o=Ni zjB%&&knv9Ay&x57wA(8t6A3x;mo3yffY5>b)hXyfhBG#v%IQ$*4nY@@|I%G7dZ*0* z)1~qdZGM2MkhbjNIy)fR9Impi8V$$_H1BfS%6O_;+A7jgsdx#e+;hJO*pRp;lj^^< z01FY{d4ItU{%J0}E64eJnZ{t z%Qa+sYvr@Pe~;3DKu}kXI`X%fzy;a%0QFu2+s-u*fkS46XC;f=F7upN0RLXfHGgw>c;WnRbqVjgz)8ODDoy-!8DXp3 zGC5a|&Y^IOHxQu})=DkU3>NT-7MC>V%LlE|{-~u7PxVjt`={@~1KL7MX(f!6<7v&}TT(k>oujeeWfxi{0z}o3) zT@j8su$Wt9PFRqvBBE2;s5Ko=weGAp$ba=F(4Pt5&%vJozh;GzIu!>Lpt8~sz3S*T z>wSpG-$Lna%GyJ8uxF{;m`NDPBJZ~>kXYm>3lhNiJu%o`At%*uu4w4(e3sk@q9iOM zc_T=|zeRb`R?qko;NLqy1#`cG!ptc_N*v~z3Xpl{Ci^*m1oC85Dwj)9oE=>h(|>Gb zWpiaEbHXqU!#}aDz^%joz_OQ$6|AzkQpYN3IFnmb;%m8eJQrM1TRj(D)0zK=p4Qyl zjZNIk2vZ(H-%}|ZJ*8bW@=Mu8$5dwQ0FgEYB{zIDH66LAAssUv%`Z`oH8}`CrkKGQ z%p73A2cT7jQC*vQHN<5IaeH%He~O-fcQqcp_7%zE($ZsdeK=9Zi-4<)>0qH( zM&UyWL zUTtpL#55UkPuwP$qOV~D6=wmbucZ-(3+UfOfljdhQ}UBtz&C8b_yL!Fcu((yOPFaA zd$UHdRN~elb2x$8#|+~Tji@1} zEFWqDG;5z0)OT9wZF9eXGAd(S+AFu5hQwK zWr5*eDk{U_uH}k(S#V$Uj2Wz8J3VOUhH=9(HQS`)!_@3*F6!|4Xt4Onrxz{10R$74 zqKW%{CIn0H6o^t@54zNTe$nWAIJ<=R4;|*~!T2itM}MDOXPI4Z;J&QwH)nBSz;RLj zi)*grXLl#OxzACRCUkigKf% zw0Wdn%GN3?DN8#jkCCVr0f%hDGxd~<`kPh=PNeSv)+a zovCvD@n6CJ640St<0c#fjV0z@RikWSt|-RhTh{n62XRcCfFpn8TNQs=@U!@R0xsC! zM!A?X^l_`8p0SUktd;(`+?dY^0LZW~T^^oIfE5w|{+#5xg+1-9GUk7K?WHE?W9`8* zLMjfoCd~N{*MGUT;5`Bo7+qrs(j)2va1}!{5XmUnQ-v;mSU5fG!`){mb529b!11=0wUUVTp;^=?DN;(n=%e&X_e8gQ;yC6L-7Mv(W1&Pit|g^MNwD4C zJGIwt@3rbjN~~;36VM?6NaYUjFbkiQ7D!wFU#yj*S7?fCzao=RA2=wSM9NhG^1LW9 zQLdO5eH0mS=|z$E6JELO9pS8d=L%!hY=g@U()nSNupcEX!i%0GlpVjDvh}{?H&7?#hsgv{|Bmqp586hBlA!0t(5QlEE;A;m>wj zxdZ@XJ(x^)@Jc$$#pj*D-t;)3zD3Y|l~_I;1GMupLd}5g02B%|nhBFzdBGyD584}l z)u`leo!YLoDxxWT)!XQt?5`aJz<~-^2IciF#uz7M3dqU_5b{l`|C##4g3G(W)eDQ` z+kx)puO}p`thWMQsn@n{9J%2d-1Ki+TfL!!`WFFba&zdG0U^j4Z>B&(jDRycrTO@o zJuxmM#KGQh=5(w@@ZorZS78lj^D3u*NO4yc-^u*e_$KMp@2WeJ+r_uBP~<>GsG`Tvl@bp?r)`95R& zocccHbyhsbX7Eb@AC-}=mw`|misZlmjPA0VHQbo)&i$(gy~~1IBSZqfj)#$d#l>5I zI|n2a0Pc;BE-c#ccnF3bWC90N%#HU`KUVRLf#AzWIy z+GdF+Y-yTyGWT031g@F?MlQU;;Rt+qnhNeoEPuO!0TEw3o4-eTTtK;)vmAzYfvQ~}ie}== zl5Su)$p6EfW?DGTa`dUm-zjn}XuXSz&s-O}ss(l507|5gvMj;cjr{`HPbx;DHCpQ++ipRx5Tnk(aFV;epogs*sh(DTw8{J%sL*hvrXzKi z>5INpZ&Ps$2iX_CdH0!>@^+Kn;tLw?hjed+)8_Vnv(sYddiy(flT4`*K-p!K#{dA5^)Bp?Bolc6LN7SijyuefAY{0QwM@M?~H=ixZ3cYTMG$|NBb zHsh{-ilIKI*`yXQt(^|=Rg1It1Ck{bf7=Pf`W|LU$_E3EB=YD{kbLtq5LAz@!OMU& z*%2#oN7)!(0O!&T)4(b761V35n7;$ED|(w8a$3!<+*Oq+R${%N&r>yN(rd}hir$AlqpLB=JVw2EwzRX zd=G;UwVU;GE8W-uAq+5_eGrUK95Z2Ead-;&ucOnw5<~tAy=o z(|2iO=nqXfJ3jX_Due7`lr_Jdqrf9De+y4$#Mwn`=>Zvk1r-Te7I~kJ#W-L9Q2?du zPtHUYfF?8>>QP+B@QZzbf9rjO=#4_i`QC!g(@&6NOS+t^6*Jk@s+<0|tnmn}J5wCT z)wi`Mk{`eBFqasVf7YTXc5LNKaWglP zB3rjfkYAu$Z9bd=-i0gL(vB=2T52&uS+Cg^;%dO#Koh$;8N<`^Cz z(BEYo1c4~xrHlif6Jbr+Hth?t$2-DhOhqpDx#O9p8)CE+5>$k1S4N5f*_53wL*c80 zF}BuFF&;}!y_CA4;%kHjq9px9KN)C7NJ#>u##mm<6W?aHav?a#FF|w`i&MaPsY-m z{kfjA?Qd%1T#AWZa!k0APe!>ECDoChE%+qWMWks`_!rprpXo^`)x7{t7RB}~{| zR)8iI@t8xz(S4YOoW{f8_Hv$TI37$6bO1rxrrPD649>*p7VOD8?ht}1MdCBCLM-(_ zmkKI9f7W>bR~q@n6Zd0`I%CIo3i1kmUqkFVNPS7<{U1GoVN$IV)90nJNt;U=*=AJli|P z;*ChbeUoR~sSF3eSz7>S@VSiah0R=U6cY2b+MnQ$1uz0m=W!yTbx@1F0h637F%?GO z3Z4&G$x>3{$6C=t_c!^#M*pmn;wwsjyIre6=*=)Rq!Is0{&iwv2cG>a79a!r7RPE( z`d;Mne+Bt{QdUi<@-B25jeio3RnPuO?Irpys87rWJ&()-{>|GNgWO&=Qs5qNb(7p6 zG6J}nXxTN%(2TY>IHYpV<@pitJfp+nZmxwvZfrMKO*C^Xsx6Ve4wuW<(#HgU8&Pgs z)IICcz+xjNtn_FXxyKNOQL7!eGU+i&tv6hyh;U?x^#XTE5fNUpZA(V_#3f~_-Y+c9 zMYE{@yS*Qf&0w;xvyc>;j4yDI8`&}K*n^^Z`R4hLV72_6H|H`raIPx)2ZaH{nE8t< zHmo3%Wh1FvU7wsk^JbVOI zQy-Btue>Yzo9IjXDzE1X<>Ebk@?xG=A^(7&r{Hs5>hqh?`MudX1e^;pK4uL; z;+^PF>_jgs3}+c>J=18aPcROj4nWew=wbA&2EKAfhbm3RS5P&*hdBp2n6P1$R9iMwmlTGfr+jhgkmxw&Od2bN`-iN#?c z6H8fuaD|ze!nxv3J7~h|Ox=0uDRgwMZd9uqzgc`&l{NI5O|ScQ5Waz;0xtjs;HnfW zZ167uZyRdQx^oMU=p|d@VW}tg?@fz@GYe5^rt9hDnhc=^2)(-iq`#`&Y)6RGhU$Np zcD37kE+BnggK!_$!DS@|2*PrAStx>cT*mJ{KCGoD{YKf>puQ9{5CdMm)p)h>J=cqD zps4N3gS;qA*gnmpxbjt-=(r5`j8wjE{etWbZ}gAhmgmv%q4)JD-wb;7X(LsN}(EWn#SC%RrB zEyB_us@2F!MZaDDNZ6_P)#aDxgi3@4h1_h5|Y3jGA zi%L8%wSlAvr=A6<1uA7VV4qCoBp#q7Mx)@Tg9y-+^Q7%Nj98Ilviq1F04g)>$od80 zVOkmC6E4o+h?u7(_jGiriwl3n{jWX2o*=ABkwviTAXT<(WrIB2h*dU~!F}MY8#=!4KwWgK9)w9RbuHg6d(jV+YVBIk+3FgG zDr69)?Lq@+BSxJ+@v?u`p{v@wH$}715*{98fO3#INoK0l{0=}Y66Nc>^ZYz_5Xf>H z&E{)uKc2+C&6RjosPik;sG0`P1}S{sVTx)T06JL5safZOm3v5=i^%hGxmxX4t6!3? zQm%x)pUP8Wea4a&e7J@%d+eyHcI1z%%E@3&S}FZ9svt+rY< z=J*ZuQ#GJPrvby=i~i%|VbbdkHvx?ek*v=cW)L7J;~C$Uv)DtlwYQn}lm=lAh6V7N zN`~6u97BFu1L_`a{X^|3}VBYxFd` z`PK(VmSm0?jjMmJ0wU{J9|W0Le#iA?mg6%8JBMVxDhE8A-Xr|*Giu`7|&hurK*_w4hZ2&I=;|g^e&pqDqRJgi@h1dHsHsfr>x`JL zyagzM6{o01_|tRH0`}f0)Lz$ zZmwB6&0rP1U-4qk!u&_X%CwY^1GaVyW9hu9rAz{FUZUZdpkQ7Y; z^MsFSu1%Zd*QO`|&0Hb0!i8oE_u=4Xd(tZHdnYWj>y4Wz!amZ-mN z-pEaMvRPxgNpVyz7fpJ9@f-baxhZEqt{U*;Oa8g&N8B@RdpXZ$x=DJ;JRukGL#ZtI za@p(Vwm{Td_p~ty$o&3Q&c%6*2>RFovUF|BDQ5&2ScF;EwBQJr6z4FNEL(qeGp@Gh z(J4P=x$vm3)gqS zu9>0_YfH-k16XLl#J`*e_VZ$14GOS;2a9}*APs(1=e;?MAaw95qLob~YhOaCBHD{k zPB^XSA=)eFk$hi~ws|?Xjgrf7nCnR}_lE=P`_=I7rQ|eukV2+rL0W$Y2neT$c21tA z`*f_c1c8K%eC$9ovkJ)2SVzz1oRgLc{#3c1EBz$s1M4mxV%lfcs-PRGX~i48a<+b= zMyQOX83KJQzuqpJ6}Q%ptjvpkZ=Of-Y_?wU{f8Jlt(XOjH}t7uD_I>RmG$gnHB^9v z#1shzEItmhLfNwVdy#*Ixgoql5B^mn&~e{;#wn2T?lvxJ+tRy?_ZvS@NPNq#rB}zN zEg7h%*JR=AT@yq-FATqv%3nct@dX{~r~?~c05NZhh4Wh8!+>faM?$MSR`Rp=a``r6}QSp#$JXW@T0hxz9)7su^6hDlO2 zPun%r`hjegi7tn;JkS_Tcbi1bQ!*B^sLnG4kKpnr2WhDqr2J%i1W2eVRTad+soGUj zkO^BrHwf!!v97~VDzG?Nfz@_$wN*-zQj4yhfU~b+pT7j~xYgv!1AN)sf|EBSjDlE` zwY03bl2RKTQ|W(foiqW0rp7&boeW1sSi+Iq`*fcF6euA`WGLNXpwv7iRc=er-pNJI zi$WKPC9S*8dOr=)tzW@a4_vuAk4^l5SMzPkOo2YtUNqG)1U8>EnMElfXG|{X4gn5? zE8?7Vfb#&J1g=OkUVnFObrUte=-h?@iv3oA)RVI;o-ltK-32C14lEE?H*)^{z!&jW ziv!>P{hW6uGv4JdjQ^z9%+;&on&^{vBOkPZhb!~ae-iw&$Riy(Eb!Ui82<&c-c56V z1O1xEeuVQM;g!?j%2k-dr7km_{gIwOxeALX*M6>l-OAqEgpz2wk#lkmEYngOH zs;*q5q=J9xQlIk%b+73SJ>gp1X|x-5GqCOE+A#3B>GAqEzx{uE^?}y}KEZOifXeyc`hxTFbhwnxt!nCxtI3x#9H}MNTFB0 zHo)#{m5lb@LM6q0oW?{RpKNwPG zS*$_1X|vfHN=aJu`<3-t0rTJ0y8PYgE9mJ&H*}3o|RM&nnEG!3%-a_Oj5v zSVK})BgWh>bj3Id^!ILm9mA2;XuD+?24o?B5Rb0gUVL$w!wj!|uzf1R-c zE%r6yGuk%x>0L(l&@Z=npLU9RbrY5!DK`_%1TxDbGs79vSLOz_v%6f%J@i~|>O>Gt zZfo9iW_K+cmQhAOy<|E}ddX;<^~Ng0kp1Mr%e%W*s?X}v2QZ>fFPz?TrtVyL>PHbwvnBkX5DMD1EC;}& z#5*gzzZ0s=w<8rm#Z@beLn~<|h3q6KAUw*+T$0E@&M%erk@nI+40bv+@_dlM%I*F^ z|08y2!zW0Rg$-00-_UuryLrTa;59r*>DpNE0|A>G*QRJ6kq!Na!~;e z53>^-qanu)fMWuXoX=s!_;=c`&6p*U&HXZqSi0p4*p(JxDe_K1&{D|`Zo{#qRz|n?3)>;g?kG6u+4zox%Q0<*hRhJ zs`l}i1y3b8)fwd)^#h%TV1{?pNpuFyJ;{1LP{pyX^1nZ8;ri#8uRFGl!CXaMBJMcN~ zMP^V6%;>GcO#4UsDW><|r~^#aH>&EztkcO3@bF0F9YCw0%LiV6bdM5QKTZ1?@}%|6 z7R&b&V6Dyil0R+U&ZCE0IsEpTHTdSO@xFNjX7cfW(em-6P$&+^g?H&3t+vU(5P`Nd ztpoAj$ain><@9f*FtwY($JYVgH}a&hpEs45EZf#{eaVi7q?vL6Xy-iJ9Q1K`ZKBs{ zo*;24>Fbj0zmyYyPp+b74;34a{Zm7w4t>=cRYds?B-ZlJS@N_f|1-Z~9IB1!gV+hY}sn6CkT~ zM99C2Q~j%0`XGwHA2Y?ncmjvt+F%)Pj^a#>PR9j@J7{hX<|?GeTjO8oomU^gJ1 zK-ZD+icHf8me#H^51B zjeV2>w1v8hSiK0DNb@`g{>)I2<-$Q>dscFj&Lg;g{~;Bo#kZwt%5CYtTR8yrrf^=Q z=$Bc^C=rrXsub86JmZR1|3dI9=ug(;urS$OH}6+sw($#h=KbCC})BLk%$qGU(~eEkvUz_jv+ z(gBg=-T~uqk<%eoq2CX8nw*#6&Hz<91k{*xBu2}aXow!6?g}H@ia0&JB7xGO6(6zQG(+ANkhz?H zV;S_B$rDaJ(mUg|6Vl+8D_+9GLvOalEnHrXN|_t**gN@f=pU^Q8%gaQE4F9-`;pDE z(&waXpr+y_JUsN~pOV13@m|!jGM?5#@-TCHDz4Y#n(7_P&@pDNgCWO=W8AMTQ^@~l z`&_X@3A#S*riJXfPj`z=btd`F7Q6X>*-Qtmw=h9xxcoh+ZK02WkOjyAsI4Z}F;^xR zo@7*S@&q`~w>XGSreKmv%FRG>i=f{-Ajq<7D;Ibq5W*uHt}9_W05L7AHXKZMQ#s4smg^@MSqXuJ4rcq}?30CxciFYN z_w+&C#FV5z9+HVV@H-w3S|MZg}u#w!vt=u{f0|)hj z#4pxgjT{3$r)3!9!&%j25jQS#&$Hg(^qr>%`tU($xG5PYo>%rhH7u?UPQS_ZIJ-}o zrn=9Mj76McS?d#T)cM~IsS<~W)$Kji%QL*FT+MYbb9B%*U%Z08=Xm&k+-&a#+q{(v z&i76r3r-b1fezn-vuZ280^P;K7k%e4*1YWaRglxkam@P-|8E#!#oL(3+xd-e03JGK z#K3cd)IQbmV3@a2&oo9jOm;KOs5;W&OuKV-Q+v8D@S4w!h*erPY{rUyAULSV@-7Ir+PEuzO! zA6o_?I++>97QeETo)gHKwx;C%ak<`qs&yMutNjPP^Dp2)h(Qv6{A4M?bg{uh?^oho zZ2VE7p2FUuCm2};`dr0igd`4t^M5)>lTuZfPX*}8W{g$VQm=TYq*+Q%wqffu~CPy=JoCDotoU8894I_)QNnranar%!v)^~{G z*)=;=iuU_dsnkk;S{258YO<7nf+^-RR%uiICfjpbb|=d^b_<>$X2b(^)HIKnzKGOC zHvys82eJx+aTO@552p!Wtwr28w!3DWFwUVDW?#!Rm}peRx!=1sCu&z$kjEEZb>G+Lqmb&YwCo3(i;L|s20#y%m`CtJ4PQ_fUyLYXrAA9_-a1^p1@vByQ1%gT|XjO>G&fj zI7xyZ7n68IC4X`}$jA$XHv{0HGa<<*OwsSq6)rkllI6Jnz(|3s0d6>v$2nPKL|nEq z4t1h%y@}noN@26G4ep|o{>GzgRFHOKPpUn#2FtUpDmE3|s>q51-z$ogXST#r`ZK7h zxaDy|=;)XduO@F+;*%p=Nx+f*(9z#}-v^5&#~uF>*7phR2fIs2iap-)?V~WQ3V zeFnA3tgGW<4=C`o(=jaS@!k+)>GIy?eSOpu+>GvzOvXJ;pA@qK{5`={@>rr6@Cihg zEbT~*QFX^KIM$PAMJj(syQY2X(BAN>_*Z+(*BEAn%*B=7tZFs=t3bu*H%J<_6>vacsB)oj1*Abd`%(F2zxbw|PjYd#0 zU+kucSp;UPn_)5S`L1+29&VbQr2AwmPeU{w?v3|g1ba#DuULfO1{6c9vbR3yD-aGi z6%`QFS|%`hjA|WJU zR6V@2=Wq@`_4FkU3#*qTWVh=_l5PBC96?!|b5Jbr8-|3^yO zCbKJ|&Mekg%eAT-4aTZ5A<_@=Wll)<7uaWKFhy(+!qV)(uWI z46A=2Xj$R}=NaaX=ZX>dIa87~U)r|zvj_I*l!@toOd?%{IiBTd&Kz5ML^{5(DA@%O zjshNLur^>dnWgp3^>zrP#P#5i40ez24wF2kT3BC~Nut(GR`%}o%B%qx{$BJ2pcb3S z+kZ_wwE35pZ2otCn)6R{+a}gqna$qHg#3S(QY`!Y2C(vu0oA{?$OpfiKVZp-hSYwj zmL12k<&&Y#!(N;$rx^H^7jkv4D41|ShUjsFUytgz1Ry)*d1ZL8I;)IH3E<>e#L6EK zKz#Dxjy<6U1+Lb+a9pixDDuYa6_KTzL_Kk}u7TOt=o<2MRw6y%fzBC^p|*0gvzveI z;DDe}bSK|KXoOc`iJt=KEVLymH$vwdHs$Up`$RiPVix9EaNBeYf==2?W~qk1i1Zn# z>g^yJ@eWdEpds0Z3Bu;=OXbvr>0jG{NY>H4e)=W3saN9Lb8F%DX(=?k0F{0}?hT>g& zQRR~QMC+!nt84#tJ3yT;$F#aIRW=En1KS72MCT8&;L9PwA1L^D4+`)1VCjn}1pc8C z`WrD>*)Nv>fl7gy9c5afPU#BTD+3q)op*7cdL0`K({P-bG`!NAfX%ow_kK?l=B{lV3|GHwF}VQ&+{C+rTByUK5b%2>l{^dQXU{ z)*>7M60B23ZRH8ero&OJ-5Q1?g)#a8)i2ip%{rNslf6qMe|fn{E9}IDZkd_&xW{=- z(ujNJyJ5PLiNj7XU1gx2?0yM1 zkpXP(+t1oToy+4IhmVhP^zy66zpZlwS%B)K%`0Qf_D1UQrmnPU0Ymbs1_zpOOuOLm zUxSxDQ)Cue(e6drm@oMeqrdo(Z{aQ8oEbH=`0#QLf8j!nbh?Z^g`34*-}f7c(77$0 zgmz0=w=M6{j%}IX&J{lGqP-QR;6>P8uDBWx0pBMv?#D;>=G%RfwkGa_Bn#q9Q^?~v zH6*bYhbzDatb}ohDRPs_m4;?Rb{iYL1b3+-sDL?+hq@OxdKpv=S2i|}>OFIKd2eA$ ziAkdIf7~|U?uWh;Jf{Q+B;IkFkW{$J{}!S_ z>_s$_xPeb>Vd6x+7rA3f|x)$0C2s5be=h0=cQSS-72@Um((fxaq@+(!{N35U zV#u5A0(_k_o-p2aZFVQMu%<3Db)#8ccDD+Lz6^H~yL#WDU9GO!Z7=zho?Ayzr0lWb9lGls^Bi}NxyjX)cNyQ ze`Xc&n2;4@%$$0Wu_z9jcFv=9fImC`;&RKfQ)irywCV< zl$VBsEjBn1yMX$&K{uWy5!)m~rFC~hz1I;M4D(8^6gi(uVEq4Wk3q&${n&Xb@2NpmoPyCVYQM4BV$In>FsX7?%E`4;dj{{c*VT*x? zFuv=pKxL(+N|tA9(Z!5#Uq?6~{TUR??XSww@-%CR+l?T5;lY&qtDfMpXc5mppQRLN+R4PYSrFcdV z%j3@o+u@#gBey(pNtC3x5lbh9^)-{xP%S{2w>GDn?La)kJsW=2v+fk|dr*F(@XqlY z;R5`qXU%QfM}f|r0hmE_Jl_-x@$x=d7)El&W^O&!ZtPcY2mTn7K2aF~(34nEA%B6- zpXa=djw#uaUIlIP*!Fvk$BpN7w2aiLuuzqh?dx2K>RV}A@?@FUXj;-&rfT`;euMFP zjSwr0Eh`Q!oucns=~%APvH%8h*eg=A9DJx8G8Xm$6`Hu|pXphp4}7O;7H-2&f9HCZ z|7#&fpM>YTYxUY zUoc%5lvAe!m9F`Pq*)E@FPxI{)EDev*^hTe`!X-Wc9%GfJn6-p=|yVZlLfn(6&!Ct z(m|@4ygBD6tBu*#D%$+0d5(jAyI!!JTS6TzHqY2*$OEf_w=9irEF6DPr+;4X&fSw3 z83s(!CLr}A1)bk!{DLs&`)6U!(e7c62^ppq9i>y;lxGVww{Fsd(rkmc(tc&FLbA0= zGdqoYy_}BxO6P^yhI6FUd{S?+NTSoYwae+OiK!_L??Y2H*7Yw^+=SukoyxLVcIrG{ zXgZj&|A)gD8+z-M6k7l*lz(4o&*~iVBz!xr=d&5Mq|NyPR*n+P?}@F@$q@(p6p5kc zFVLw9aP=^Y=a&*Sy}&G&hJ@Rm{5NO;{x{Nt;S8y3`6a3u<(p~gf4xG8W8JARQu+zz zxVWD!P%Cw(<&aCa5n{uM2}g3<8w%PC$PM>@!wgoY#Hz-Cx~ZRb5qmOn1*r z?{v@3%+Bmg&rI)d$>p`A%w38y<&Yv7U6v@4TA4B#E0&^!a;$?f1qn_pYwZLvlE8_8 zz))x#aS|i3ASXkC_AGh^ibD;-TbW4@ICkd$@xA+qY;ac+m27qq?<^ zLFltf6ptDkvxEU@Hmr^o7ASTI9SD4luXb^005k>xMya?kM@FF2y5PCS%1_nJ`Mc>~lFc~Ai z9!MdziwQ?Kl7T`dL17}HW=uyehMH4Ed!@ecT^E#G=~Mr9S42qdcj^KjmeDxq3CM3wa( z<4-!WY~yo`WwdLE>VAIT&Q0!_^bgP-K+iQwZfR%~%xPfiqZj;eVjw>4L(~$M$Ir&_ zkr-&rJ-02m0_onO$T5{9$gBbzm?J0JFcf1h2X?eKbALL9DiIZWQuQK{AVF3UsZ2>P zR79*)hq@8BhvIH^Bx=HGVYHywcnYW=(3L^NnWr)gpk&A@%=@qt1c8K8;6!@U*<382 z&4oFes`~6MXy*d8^DYb`aS-#YLlw^AGS%;!z$|+x3gJ-K!y{DpUt5atwSBm(^=pHE zT~yO__kUPm1{nA!&~N_M|AT&ww&jY+5^KCk4J?t3U%_x2L`0d-Fs5>5tVNqbw2uDA zF^2D((AOKrYcx^3U-_B3@rR^aY@*5yMRy*02|WbG5@Q?bWCa-{2&dmMj;0{2oKKIH zb1!~9^7|wO5y`i;lI%PJPs@~Kt`M*GXP`L!~KRX0{_pBOBs{p zFhMxUz>PP&e?}uhbh&bd`B3G|j5*gM==@NtLbkH*-PcG3fv*eib>g->%(uIN3lH}_ zV_?4(jN70WwOav|g^OPf?Qc)h9}U_Pv!j?7u#4oH+u!WCfsQaGY8Wsb`(VX#j6>oG zRDTAeg9>$bFLs$rbQF*xg%X7Q+skvitHg75oX4?sRM>^L{U}uv0a}kS^k7?oSbz7B z^_rO8#LFHTWTc|(+D{F2=a$bJ9)B2XFobu)R*La%y#C%C!v<4_j}`MO0jx>?s#(oep$3skjD0B6&@;77XVbCr zb@suw*~OUayFxQvd_rT28lpo=ra$JnpcO}W>^+?4pGGnMnF92FzQgD_?gvCn7=LTv z1KXERKR_k{##<*LLN_U<^QT>NbIPfX9zcKNvs^vLeO7{5QXpQ=4tLo(*2I2)$M}iI zZyf(Oo#nR;^LwbYlXGd4BU3;Z__3G8@*H53r z@SHh3Xvxhvjbh?8!EdFM8U z6~5r0;w!p?X8II$T}Hj>?!?EeUyvEA{nQOz_<2C$(!GPS`uB1ENwhniwtoP{gGWj7 z7VY~j-|yq17UlN;EsZ(uo+8wNSD-ZpDruM#Z4%!i+Q zYwUuW6ZU&f-?@nM(Q^~YT=iT#bRW!0!-9H*ddGko!*!3^aqOtlROZL!%_ND)gw)U^ zzDD>es9Y>(2B?(^!g3CS@P9^NN2EZitwM>&V71CfsA5ZfWSMLQl>dgo<=+!AMx+Di zfvn3d@+&+0tDr=C@uy-Bj7xP6?h*?%P#~x1t~9XqWnpamlA+04lxQ;)O}i)ONaA4D z>O;;`COZ7s5N=uX+~P-<>(krpHQ0Ev@~~PTEaFum#=ddRG=1J=X@C7YiC!w#bvgRF z!zc_m3|Ned?r78%TzGtKGFhV+yx8+3-&w`@x78g`vb2aj+M|lkwy{dLq3yGGf+?@k zJX6LI;tf_;d^QL5nuh1^Iv-LG+Gl*v58V@!Z?=%Ply4WUyIRE#Wt=ALcfJAx`hgaA zNp%1g<3FvrU(ONNlz+p+&U4Q5pz(h2&6UQj&8H^OU1~lUqc~Y=KZYH7u71G6c?Khf z-eg;vasC6B)<0)_Ou4;rk5$cU>(_`Y+}0;sE@GX_U3=%Deax;rrtfQTh9W07<%gcT zc4cxcm6SSNVzz9jCL!F|W=jnQ0i8zVKdw%vtBk_?G0_{1dVe@&LtV{jRY=f~;j8rl zbz9g@*v=XTK(1|b>3J;|ba(Sv6cid7?4RrhI6d?eekQpohaqCTnxgse?=aBx1!X%$ ze6dw*bELaXD2zh2j&}fK#AWBL&XWeS?`7xX&ZnHuIsec|wmswBn1jwTZ!jA6NYyz| z!cUjl1B_Y=kbl3W1mc@k)GaIX+ngMc(|bxeUZ|I|V|b-wE1l3Q^xDjo5_x{jm%7x9 z;?N_QmXWWK;kTVL1N?TxwfYQW7z~0i>e3*nV#?&c*@E_{w5!xHtouqoWBvUH($$f6 z=U}mWq3a0~RimFo3l@{jINl@TbGTH%i+lsIlDCy%!heZzj^7iQp$}FG*dSobjD9)~ z^rs^)btT;V_c5eV@Gs-jwfHy!VQX=OuvALU@KrqZEBMFNFIk*m=7t)6E_y!VWX)g? zyy>4XhN)|48Zn}L$-cpT2Q!YVynXE;79Zj}TmWn25zzDgyz{K{qVto^PdTqSzXz?l zk&taUxql^>a$bu~g&`Sc51xwO%07=UJ~O66GAo*ZkR{r!T50{7%{yeR7zB6A=94PlKT$@I@4%3Rn2s-N=rM5G zhiuLwR5EDaDz(>!hLA*@*vvZDW_x)ID;yX2JAc9xwEQb=laJDnJY||m6@*ajIO`vS z-2qjz0lidp?3uUlN1-Kw68s{*7`)>XbtWwsH6Hw2G~aR6Vjq3d%K8J79rLP%MVc5C zb-9CYDdk_YTbqnyI>|S2A^7ie1GUco8)9fLc&O+ofHB!%o`7K$5|!Xw&P5n24J7w1 ze1BAqa|%=L5L(n@H%AHJ{D#B{j+hyprs5t)a^vX{GThP0RFw^!;>1G39v_rwCC-<^ z2p$;3R62E}7(HA&!le1oLI&ET7y9QTHSyY!x z<`+>NEOI|?8w{TV3kWi#6})YP@E$*V0q5w6W`Vwh>?riIm+OLJD|$e)E|pr69#apR zUObbuMKIXpL_W4o;akRT%m;*X3N@rss=+>l>bVDN?H)yh0b}15`aZ+~p<~|I@qf;r zkiwZd=bd*iMJb^PyFzZs*Q~%)?j?0Ti^7>GGm|_q{;lz}=8`f=!v@S7Q6Fto!=vr> z&GmL@(j-*|t*d>$4a>~T42tkd)_-Sz3ko_%o>W0-N-6Cy;u48ozYc6ErMjR37SfQ+ z{HykQ8-8|l1b5kN?qqI_n~{E|pMRY>llA{)NC^BexEquj21kHCSi&D}=Fk}lm>u5ap%=I)``K4ei~kCk?wIVQ6gy(9|0G-}`F}%r*2W{8 z_jlM!b>6gnX94xN(O$z z%?>bMpjWsr>k8tFvOAdFJsXr; z-8IcSN+=j)DOhhbDr4m(Lw^_{x80b52?z=fnA{;4`FJe?dshIB<)Fg`7?;jCS#y|M?|NNc5bK#>Yz{H z&zGUo8}3|#pgt}QD!w{?c7cBGCOf?_KGPtRgN2fX7ld+Q{g56rK_hO=ta~gRuFu`dX<}D z`Yg^s;^7j{ttO~!@2oJUr`DNgK$y%GFy>uPhiN)IgNrojbk;kazbe$YJ=(GzArQ?n{}2jMjD6pMH8tVy%^fLY!l7VlY`o>SEq45B9I@WlBcuoIrOEM_V*=QQdTKdFyIyQto*Uod&cQ z7)}{FbwD+4fgF@fgJOJ6ar$FO3wU_6iyA*D+`>m@rHgRjU*m!2pQDR&K=OoWkVZUg zAqzanrC3R1suv!ZpTy%*hpZq-RR&`iB>@p&6+i(nKYs)bc=R+rl3dw$s;Y6s-xk=)mm{^2}l$iB`1=cpc z-3$zV#Zvex^{82Lv)trHFRDP78C;kroJ)QcYJq4?Se9 z7We6&HGfws-WEvFNkD>XJ|l`X&l^M(l*JHqlYLBI@>@H{6EQsOG8s$acU=yqxO>eX z`EYyQ+DjNk;9LWq3%&k-Ib-J-?9IoW=bVo?pLG6)^LLytJHKvy43>vrNXmob_C<0u zp2Czj%6x`YXGMi_w6BiF*7Z>D!hcX>3`>Slz~r^rNK31E9vx#85aO#3 z;QlyNj8AW&tpUH~+$4ilcSd|K6ZN#b1((f^#_wG3l@gTWR(PfmaU7?hnY49(gSMh` znAinFEQ}5uW4#oY!zUOc^|pT>hyZBXZAlfm%2p6yNua@qjS2p_p8^{edBVt6z49@F zjDG+y+*8nShQcM##$6UbyCA!#w%$D){!iL1)tQrQv%U-3o688) zI@r5nRe(;Xky0UmM=x(|_y&K>&gu3^&wp8W_MQ8jw_)UE2C`|$K-!u>nq7vdd9#Bm zh^w^OOcAj}za_#`S20}E$+5EWIW~3&r(SUQ--olOM-zH&5QDSads4wbaetU zQKL!NJ3mhH$zIph*fE4U0Sh34&(kiF3G*WEf+!9&b3eG=j(;Vk zJS@kcud^ALM`Fed&u_ZAxpQ_Ure1&*P)v3^{rxi;F?WLgcj`885h6*<)1yeJXHLJs zi(!#qK%7U?4v1X3hql}vj9RSWuKg}X@y)H|GqQ1Bqx2aFY%`H5F|yA{Qj&j%92%=>Okl7H|$%lk2Wx<2q(I4Nwo?E$I4`G|=m)nQ6b9Z{m* z?{Jf^(0BgGx#IkY^Ij8kyMBtl$^y>Ws;p)jhoqi`G_Wx>QjOuOuX&u||5#boVO^?a z=sGZt8?c$@DCkU~YdG8#$ZaY;krnr6fg6+|V_^v^*)G2EeMBgf(8Uyw65mfovEqiK73nYcLD;Au z0AcU#gIt5||DqQ~?I>EWZU&1DVvGP)+1q`?M{sNqpPhL%O<&Yu3-I5hr=D`gQd>e5 zPn#^qH%*n4mgCHF<7ZQ0x_SJ#hW@ z{bjOAIy$yx3&UAXOz9?_hf1(nr%+;0Zhwl#A2DSh_dKwFpbQlE&IcR@%5UM~%rD-> z5xR%(LV3}z+A@V#+3cVzPnVNUVv4n(Rf#zbhRu#?Qy(@=s};b|>3`N!(}Y*P$;OL4 zKUlP={p0EWqD_IOU$-eUF9}7BMP>|RLoIBl0A|JzMpMxyZ{UQ+FJm>TcHjjaY+0Sa z^YaIb93%T^J+}nXBIFG#x1fG_}UYCBv%dx-Z|h zgqQm)i22!_D#;E3<$9AgQPxTmCaphDc>%?jB9|G0Ibm5A?|;(L_qdoY%5o~W2c5Qk z`Enk(p{LL_X z5#sDkvYKM)Cm0)ocP%!{ws}Y@*aw6M1NW6Hf^$!NfQg5@-3F8L&zxN|vs4EM-F`~5 zvT96cH>ALI!+-oQKIhuy>d88ufYc!d-6zpt0n7Aa7sz}CXEP(G~4r1i=4X2BfTs>#wy+sehb>A^UMH z%ht8dMJnW#pSak$f~<}0Vf0maC;8QA*#6z!7lhw>VfRZ$rM33aS&~DkJnp>TdBOR( z^HbOdYJWjxjBlHa$t`R*21eMLRkDs9&zo-2_=U0kmzLpsGHu|(s_;S>Zb~&RZ@>HN zT#V3q9Hn3*VeG;X88V0Hsz91h>FX~DwzLU@fIr6z4zl_Jz8IG`hJZ#5BOCHSDm}hK$ep z-!!b2_XiXWpBb2y#kpq>7@>#gJ6?Ia(P4gM1xn{eO;R}=LXUNYWvRUPKnQt=uIGV; zw|^Qi^to3t3eI<&-06Z&Ymlqw<0F&VJu{Iq)$(YHki#{H*LVZNWLA z31|%uTI^;VJr>{vD86nbiD*3jCTaCxj(>4zX7qt(`|g+gw#r>%B3g7V+y1LH-a-86 zhAEi=riX2SXnD!kky6){3S~f6J>3uD&tu5TXQOaM`&VNBCA{)wFFwCv(4Gf^hjN3z zo9L9%M3W^9DBomaJw@Ro>x9Zb2pY}fI5$6f#W$4vEhk3PG*{;HUb0smUc066j z+}I-%pAN^0Q^zLu*x^9~ncjFi%cW`LX=$#EiMeu*m@DB6@vd`|bygl9l$dN=u209N z_GC;=Qn*w&wS_+Bd{zfQh+e>6(;)#{g_OxJ|27&s?qB9QqklW;@NYvW@X@or22Wc& z0iXY%eJH`lWA-k*2nn;541Q94?)LDD=#|ql>X|1h+GA|7`j2_wYeHM)=YPpn7cp`~ zCwYwDl}i3z;RS!Q#v}OeFe2Os^)kT#Ly3S;7#I{cLApwoZNwL_qid~yfCh4Clsx#4 z(<;A|jB>Ehq3cl^X6;x}u8U4vc`^mTi7o}^=MuEf)B7}t(V$C)ut)+0177HX^bKIZ zBADe60Ajh)|F%Mc zC7Z)68Kz*CM_+;(C+RS`9V{$rcZmKv+EZmRNR9@b&fo}E{?jrJY)&$;$sTr|zXRIP zDM;H(bY31@BzHy_ihoVWC~~)hv7XxjZ8qJ;JX2(qn9AFs4l%aXAm6spXZy0tZwodA z1;@J;P|*n{k#`@i&!Z{14f+rv+YK&mTlwPqVh*Vl);@(<)T>TrDQ*0bCg#M(o1jj1 z8`A1Z|5;|EHd)>kU9}zK7vZR-m77a!knbZ6S9C>DZL&P>UVku9hv^5arnt;GeeEM? z0p(H0!b(DM+`>kU^94esU#J_dy;93tgp zfiXC>nynv5pqb7gg z?y%GAgiv~~wTfa?6bKzYYH!4hCJZ`o)Zu}rYTriDc7M5HPq@@zeS?7qKcH#+G+qrO zY|ZDC8IIC3&e0pOlU5{Ib5pQb(3fnZ`>4g8@1>&>5#QH7LH`ZaAKD4&C20ylG<14=lS|N?^dn;LCe05L^Cx6ls@%d88FI}j`T`bH5g5lm z|6}H}uLu$Ia@K*jvh?+vj2wO8n`ik3_qF!_7<3nuN^S^cRNn8aRmT5NMpX2%jLgny zSMPCe{43pqRmsnBqQ%FgCh*pHtfN7E2u>CpDl5*njTg&W@V;<5M7#%4{6rtk=ybwi7E1_lPycY`Y$qfKklhs|xCCHcaiB{eL44 zEH}WeAHqk)pw8#NjtjDqxf_Yp?hfKBcLPmHyW_X~Y=GOJQSt<1&|u+1y4&F%}-??w2!b z-W?sPF@^{iQ|v_BxT^%gj`Y6p2lSYHd|XbZAX{-4?m_Mjv;<2zpNwJOOwP?g_{GC> zd)`cf(TLlm5Gp#`O*fM6*?*`YUbr_3qcjTrt!{bk5+R^G4$-gL>v1U8A8xfdOS2Xs zWtU!{u1hZ<$vk6e!g%{}x1}YAGgTB12&frRFU?Z6iWem*=&L1&7VBk+r% z;#>`j_05&;V9UknYaVZmw|Y?=MNiVAEDK6jk-47G9wvFlQR{7KyML9?H85F8($erE zIcn{@VDGhBpYq}S^dH2!l@K~Wvle!qjbqAM*)sQ##o&H}Y^U30I^7<*ywP`TPE6Ne zsh`S;87~n;%Ol#w6(ZCw2tYF%TD=3zZ<%pE1! z7!=_ugXY;Pkp_PK*nj7)BD{cBnp5ra-niGiEAl#I&T7q_BUKgN5t*QlS-upCqihP5 ziNNn>lTvlR ze`+MkC2l5ECZ;DkC$1g^Ft#xIF*Gq&F}5-aGD=`R2s}zX96dBWnmxQeNItMXAU|e6I6#g- z)IlUcs6oU+0z#fcP(y%2;zXK6_C>@+{6=0zmPXn~9!E$>07(EzFiDO|4oZeg97|A3 zVoP*O)=W4|ZcOk^bWRjbfKPHzpivl6a#8$JR#Nm+Xj8mYR#cQ#C{?&tz*l5ff4*2) zSm;@#T0~lyTJT#WTiRSGTyk90T@GF1UPxZjUm{<+U^ZY>V1!`!VM<}vVmM-sV;p0s zWA0>5WX@%jWx{3{W^`t}004NLV_;-p0HSLQ0t_I)1jJlG$iVO)%x3@q9=rkm004NL zU5>p@!!Q(uPx^;w5CS1Fo23g|hr? zMCfCHA!3Y>AjKGam|%*Nu#b~*0B6EMoPsmsEI2F9hO^@wI4919bK^WXFV2Va<9`CU zATERp<07~yE{2Qa63B2#Tnd-QsW=U%<1)A`E{DtG3b-P!ge&7JxGJuOtK%BDCa#5R z<2tx5u7~U62Dl+^gd5`~xG8Rio8uO^C2oaV<2JZ0Zin0B4!9%kggfIdxGV04yW<{U zn1LgQz#I!KA#qQvP@sf@MukH#uzzr39a7iD%*2cn+S6=i&Ky0bYm~ z;l+3fUW%9D<#+{NiC5v(cnw~Q*WvYe1Kx-?;mvpp-io*3?RW>?iFe`Mcz+Mxi}&IE z_y9hL58=c32tJCB;p6xOK8a7^)A$TNi_hWn_yWF&FX7Ah3ciZ3;p_MYzKL()+xQN? zi|^t4_yK;1AK}ON34V&7;pg}Teu-b<*Z2*7i{Ih*_yhikKjF{#3;v3~;qUkd{)vC# z-}n#yySuZCohjo^u0>{rwSQ78yT|f8(@JDBmM_HAv)T%i&1F%DJnndpK%eEMR4FS8 zy~%7P*lNg>ELmZbFgw5Agc-i{FK8CnKT3@*vyw?Q?JQ0QK5RMNX=vSCZ&b#m;e|+! zSz1_#xl0>p6o>J$mh&$?mHu8u#$$Ksoz0^9%SKhMu zNkcb+nV90SqV+|TQ(pF(Y_%SzEepzMvDfRM!9!ZT)GCj2&3|kE+HtPyS<$LJ@@~YP zFOi_wL?IG_gjw|Ic45Zia7CGG{2MgnfY?%mjJB5a(P|+*&K7WM?-8EP*_xtpbklLi z6XM-o<^@}f=cF+zzF-+NB%W)E7KM_ysY^SgX+tuI=Y}o3ODUDs5kZlYB`sJNh2=&F z6)oi4`oWDCMt|2;`|f@q(=gKRb7>jHW7zW1()(&D;lm}V%(2DZk}_~i@qtB4QBcjnbVQQUwqjhQr8Zr$L>}*#npzuYmET7wlj#YTx{Au$ ziM}85xZGw+J7K3vY(h)w;;F=8H&VJS<9(&26`|3YrfrWEt;Iia$i#Y5b(4Trj$+dKiGIjBJho+OY+_c)_!1qbb3_L(joS-M}@Sm zM;x>r%bCvkydQq8e7quW7Bsp9_sUlM|1K*iui;YdQw3@FxvTh2U;%Nq1dv zBTuGQI7dqC&V#t)W4mOgOXk6bH09hqpYNYw^`$yK-a>><$96|UD|0bpW@J~g%Dkxd z0)OgapISP-+kVlvB^66#=_oxA4tMH9L8XnW)6Uk3q~qb&Vaw<)O{yPM& z`h!XQU^8F4eS*$TtP@mU%WPh|+K6#SNxCj>PYt{89nB1rmco?zE){vpUU+*~T`i*~ zEse-04I_E^Ub{^j+T_(bBUi#Lsp~D4Lw{;>{-90$+_vz<s3?eXCdg3p)u>kOhelE>YT+SolUm6`Bqh?f@A~6f9qVL+hR_t6L#?QY zhV4k2U&x)3R3cTvZfU4qv}W+>SNOnaOA%M=m9R0wU%6jB8}I&pyMz*wIu_m mb>Q^gM$86uv8oz{#<4N18XnQ~^(IvuW_s7o&i?>5=1CVQ9thz8 delta 30612 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 diff --git a/src/styles/icons.woff2 b/src/styles/icons.woff2 index 7229d718ddcd48bd19547bb2cf14072cac079d2f..74d3ffb3c059ebba0c1bd79b2134c59f864621ba 100644 GIT binary patch literal 27460 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

+kP*8C2K!wnlu|0F8Q7$e$`eWjzkj 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 { @@ -2346,6 +2361,21 @@ export interface LangPairWithVariables { 'PaidMessageTransactionDescription': { 'percent': V; }; + 'FrozenAccountAppealSubtitle': { + 'botLink': V; + 'date': V; + }; + 'ActionPaidMessageGroupPrice': { + 'stars': V; + }; + 'ApiMessageActionPaidMessagesRefundedOutgoing': { + 'stars': V; + 'user': V; + }; + 'ApiMessageActionPaidMessagesRefundedIncoming': { + 'user': V; + 'stars': V; + }; } export interface LangPairPlural { diff --git a/src/util/deepLinkParser.ts b/src/util/deepLinkParser.ts index a029db832..f216dd8e5 100644 --- a/src/util/deepLinkParser.ts +++ b/src/util/deepLinkParser.ts @@ -147,6 +147,14 @@ export function tryParseDeepLink(link: string): DeepLink | undefined { } } +export function getUsernameFromDeepLink(url: string) { + const deepLink = tryParseDeepLink(url); + if (deepLink?.type === 'publicUsernameOrBotLink') { + return deepLink.username; + } + return undefined; +} + function parseDeepLink(url: string) { const correctUrl = ensureProtocol(url); if (!correctUrl) {