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 000000000..e0b883bf5 Binary files /dev/null and b/src/assets/tgs/BannedDuck.tgs differ 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 96d5a77a6..0d8834730 100644 Binary files a/src/styles/icons.woff and b/src/styles/icons.woff differ diff --git a/src/styles/icons.woff2 b/src/styles/icons.woff2 index 7229d718d..74d3ffb3c 100644 Binary files a/src/styles/icons.woff2 and b/src/styles/icons.woff2 differ diff --git a/src/types/icons/font.ts b/src/types/icons/font.ts index 14a126104..ee634a4da 100644 --- a/src/types/icons/font.ts +++ b/src/types/icons/font.ts @@ -91,6 +91,7 @@ export type FontIconName = | 'forums' | 'forward' | 'fragment' + | 'frozen-time' | 'fullscreen' | 'gifs' | 'gift' diff --git a/src/types/language.d.ts b/src/types/language.d.ts index ff9e763d1..e31839fe8 100644 --- a/src/types/language.d.ts +++ b/src/types/language.d.ts @@ -1458,9 +1458,24 @@ export interface LangPair { 'StoryTooltipReactionSent': undefined; 'StarsNeededTextSendPaidMessages': undefined; 'PaidMessageTransactionTotal': undefined; + 'TitleFrozenAccount': undefined; + 'SubtitleFrozenAccount': undefined; + 'ComposerTitleFrozenAccount': undefined; + 'ComposerSubtitleFrozenAccount': undefined; 'DescriptionRestrictedMedia': undefined; 'DescriptionScheduledPaidMediaNotAllowed': undefined; 'DescriptionScheduledPaidMessagesNotAllowed': undefined; + 'FrozenAccountModalTitle': undefined; + 'FrozenAccountViolationTitle': undefined; + 'FrozenAccountViolationSubtitle': undefined; + 'FrozenAccountReadOnlyTitle': undefined; + 'FrozenAccountReadOnlySubtitle': undefined; + 'FrozenAccountAppealTitle': undefined; + 'ButtonAppeal': undefined; + 'ButtonUnderstood': undefined; + 'ActionPaidMessageGroupPriceFree': undefined; + 'NotificationTitleNotSupportedInFrozenAccount': undefined; + 'NotificationMessageNotSupportedInFrozenAccount': undefined; } export interface LangPairWithVariables { @@ -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) {