mirror of
https://github.com/danog/telegram-tt.git
synced 2024-12-04 10:40:09 +01:00
1 line
901 KiB
Plaintext
1 line
901 KiB
Plaintext
{"version":3,"sources":["webpack:///./src/modules/actions/ui/localSearch.ts","webpack:///./src/modules/actions/ui/chats.ts","webpack:///./src/modules/actions/ui/messages.ts","webpack:///./src/modules/actions/ui/globalSearch.ts","webpack:///./src/modules/actions/ui/stickerSearch.ts","webpack:///./src/modules/actions/ui/users.ts","webpack:///./src/modules/actions/ui/misc.ts","webpack:///./src/modules/actions/ui/payments.ts","webpack:///./src/modules/actions/api/chats.ts","webpack:///./src/modules/actions/api/messages.ts","webpack:///./src/modules/actions/api/symbols.ts","webpack:///./src/modules/actions/api/globalSearch.ts","webpack:///./src/modules/actions/api/sync.ts","webpack:///./src/modules/actions/api/localSearch.ts","webpack:///./src/modules/actions/api/management.ts","webpack:///./src/modules/actions/api/users.ts","webpack:///./src/modules/reducers/bots.ts","webpack:///./src/modules/actions/api/bots.ts","webpack:///./src/modules/actions/api/twoFaSettings.ts","webpack:///./src/modules/actions/api/payments.ts","webpack:///./src/util/requestQuery.ts","webpack:///./src/modules/actions/apiUpdaters/chats.ts","webpack:///./src/modules/actions/apiUpdaters/messages.ts","webpack:///./src/modules/actions/apiUpdaters/users.ts","webpack:///./src/modules/actions/apiUpdaters/symbols.ts","webpack:///./src/modules/actions/apiUpdaters/misc.ts","webpack:///./src/modules/actions/apiUpdaters/settings.ts","webpack:///./src/modules/actions/apiUpdaters/twoFaSettings.ts","webpack:///./src/hooks/useBeforeUnload.ts","webpack:///./src/components/ui/Switcher.tsx","webpack:///./src/components/left/main/LeftMainHeader.tsx","webpack:///./src/components/left/ConnectionState.tsx","webpack:///./src/hooks/useThrottledMemo.ts","webpack:///./src/hooks/useThrottle.ts","webpack:///./src/components/left/main/ChatFolders.tsx","webpack:///./src/components/left/search/LeftSearch.async.tsx","webpack:///./src/components/left/main/ContactList.async.tsx","webpack:///./src/components/left/NewChatButton.tsx","webpack:///./src/components/left/main/LeftMain.tsx","webpack:///./src/hooks/useBrowserOnline.ts","webpack:///./src/components/left/settings/Settings.async.tsx","webpack:///./src/components/left/newChat/NewChat.async.tsx","webpack:///./src/components/left/ArchivedChats.async.tsx","webpack:///./src/components/left/LeftColumn.tsx","webpack:///./src/hooks/useWindowSize.ts","webpack:///./src/components/middle/helpers/calculateMiddleFooterTransforms.ts","webpack:///./src/util/routing.ts","webpack:///./src/components/middle/HeaderMenuContainer.async.tsx","webpack:///./src/components/middle/HeaderActions.tsx","webpack:///./src/hooks/useWebpThumbnail.ts","webpack:///./src/components/middle/PinnedMessageNavigation.tsx","webpack:///./src/components/middle/HeaderPinnedMessage.tsx","webpack:///./src/components/middle/AudioPlayer.tsx","webpack:///./src/components/middle/MiddleHeader.tsx","webpack:///./src/components/middle/helpers/groupMessages.ts","webpack:///./src/components/middle/helpers/preventMessageInputBlur.ts","webpack:///./src/components/middle/hooks/useStickyDates.ts","webpack:///./src/hooks/useDebounce.ts","webpack:///./src/components/middle/hooks/useMessageObservers.ts","webpack:///./src/components/middle/message/helpers/buildContentClassName.ts","webpack:///./src/components/middle/message/helpers/mediaDimensions.ts","webpack:///./src/components/middle/message/helpers/calculateAlbumLayout.ts","webpack:///./src/components/middle/message/helpers/calculateAuthorWidth.ts","webpack:///./src/components/middle/message/hooks/useFocusMessage.ts","webpack:///./src/components/middle/message/ContextMenuContainer.async.tsx","webpack:///./src/components/middle/ActionMessage.tsx","webpack:///./src/components/common/EmbeddedMessage.tsx","webpack:///./src/components/middle/message/MessageMeta.tsx","webpack:///./src/components/middle/message/Sticker.tsx","webpack:///./src/components/middle/message/hooks/useBlurredMediaThumbRef.ts","webpack:///./src/components/middle/message/helpers/getCustomAppendixBg.ts","webpack:///./src/components/middle/message/Photo.tsx","webpack:///./src/hooks/useHeavyAnimationCheckForVideo.ts","webpack:///./src/components/middle/message/hooks/usePauseOnInactive.ts","webpack:///./src/components/middle/message/Video.tsx","webpack:///./src/components/middle/message/Contact.tsx","webpack:///./src/components/ui/CheckboxGroup.tsx","webpack:///./src/components/middle/message/PollOption.tsx","webpack:///./src/components/middle/message/Poll.tsx","webpack:///./src/components/middle/message/WebPage.tsx","webpack:///./src/components/middle/message/Invoice.tsx","webpack:///./src/components/middle/message/hocs/withSelectControl.tsx","webpack:///./src/components/middle/message/Album.tsx","webpack:///./src/components/middle/message/RoundVideo.tsx","webpack:///./src/components/middle/message/InlineButtons.tsx","webpack:///./src/components/middle/message/CommentButton.tsx","webpack:///./src/components/middle/message/Message.tsx","webpack:///./src/components/middle/MessageListContent.tsx","webpack:///./src/components/middle/hooks/useScrollHooks.ts","webpack:///./src/components/middle/MessageList.tsx","webpack:///./src/components/middle/ScrollDownButton.tsx","webpack:///./src/components/middle/composer/helpers/buildAttachment.ts","webpack:///./src/components/middle/composer/helpers/applyIosAutoCapitalizationFix.ts","webpack:///./node_modules/opus-recorder/dist/encoderWorker.min.js","webpack:///./src/util/voiceRecording.ts","webpack:///./src/components/middle/composer/hooks/useClipboardPaste.ts","webpack:///./src/components/middle/composer/helpers/getMessageTextAsHtml.ts","webpack:///./src/components/middle/composer/hooks/useDraft.ts","webpack:///./src/components/middle/composer/hooks/useInlineBotTooltip.ts","webpack:///./src/components/common/DeleteMessageModal.async.tsx","webpack:///./src/components/ui/ResponsiveHoverButton.tsx","webpack:///./src/components/middle/composer/AttachMenu.async.tsx","webpack:///./src/components/middle/composer/SymbolMenu.async.tsx","webpack:///./src/components/middle/composer/InlineBotTooltip.async.tsx","webpack:///./src/components/middle/composer/MentionTooltip.async.tsx","webpack:///./src/components/middle/composer/CustomSendMenu.async.tsx","webpack:///./src/components/middle/composer/StickerTooltip.async.tsx","webpack:///./src/components/middle/composer/BotKeyboardMenu.async.tsx","webpack:///./src/components/middle/composer/ComposerEmbeddedMessage.tsx","webpack:///./src/components/middle/composer/AttachmentModal.async.tsx","webpack:///./src/components/middle/composer/PollModal.async.tsx","webpack:///./src/components/middle/composer/DropArea.async.tsx","webpack:///./src/components/middle/composer/WebPagePreview.tsx","webpack:///./src/components/common/CalendarModal.async.tsx","webpack:///./src/components/payment/PaymentModal.async.tsx","webpack:///./src/components/payment/ReceiptModal.async.tsx","webpack:///./src/components/middle/composer/Composer.tsx","webpack:///./src/components/middle/composer/hooks/useVoiceRecording.ts","webpack:///./src/components/middle/composer/hooks/useStickerTooltip.ts","webpack:///./src/util/insertHtmlInSelection.ts","webpack:///./src/util/deleteLastCharacterOutsideSelection.ts","webpack:///./src/components/middle/composer/hooks/useEditing.ts","webpack:///./src/components/middle/MobileSearch.async.tsx","webpack:///./src/components/middle/MessageSelectToolbar.async.tsx","webpack:///./src/components/common/UnpinAllMessagesModal.async.tsx","webpack:///./src/components/middle/MiddleColumn.tsx","webpack:///./src/hooks/useCustomBackground.ts","webpack:///./src/components/right/RightHeader.tsx","webpack:///./src/components/right/hooks/useProfileViewportIds.ts","webpack:///./src/components/right/hooks/useProfileState.ts","webpack:///./src/components/right/ProfilePhoto.tsx","webpack:///./src/components/right/ProfileInfo.tsx","webpack:///./src/components/right/hooks/usePhotosPreload.ts","webpack:///./src/components/right/ChatExtra.tsx","webpack:///./src/components/right/DeleteMemberModal.tsx","webpack:///./src/components/right/Profile.tsx","webpack:///./src/components/right/hooks/useTransitionFixes.ts","webpack:///./src/hooks/useCacheBuster.ts","webpack:///./src/components/right/RightSearch.async.tsx","webpack:///./src/components/right/management/Management.async.tsx","webpack:///./src/components/right/StickerSearch.async.tsx","webpack:///./src/components/right/GifSearch.async.tsx","webpack:///./src/components/right/PollResults.async.tsx","webpack:///./src/components/right/AddChatMembers.tsx","webpack:///./src/components/right/RightColumn.tsx","webpack:///./src/components/mediaViewer/MediaViewer.async.tsx","webpack:///./src/components/main/Notifications.async.tsx","webpack:///./src/components/main/Dialogs.async.tsx","webpack:///./src/components/main/ForwardPicker.async.tsx","webpack:///./src/components/main/SafeLinkModal.async.tsx","webpack:///./src/components/main/HistoryCalendar.async.tsx","webpack:///./src/components/main/Main.tsx","webpack:///./src/bundles/main.ts"],"names":["closeLocalTextSearch","global","chatId","threadId","selectCurrentMessageList","updateLocalTextSearch","replaceLocalTextSearchResults","undefined","addReducer","actions","payload","query","chatThreadKey","buildChatThreadKey","currentQuery","localTextSearch","byChatThreadKey","MEMO_EMPTY_ARRAY","mediaType","updateLocalMediaSearchType","id","type","shouldReplaceHistory","currentMessageList","replaceThreadParam","exitMessageSelectMode","messages","contentToBeScheduled","forwardMessages","toChatId","setGlobal","updateCurrentMessageList","isChatInfoShown","openChat","chatCreation","newChatMembersProgress","targetIndexDelta","orderedIds","position","indexOf","nextId","FOCUS_NO_HIGHLIGHT_DURATION","FAST_SMOOTH_MAX_DURATION","ANIMATION_END_DELAY","blurTimeout","scrollOffset","messageId","paramName","chatMessages","selectChatMessages","viewportIds","selectViewportIds","lastOwnEditableMessageId","findLast","Boolean","selectAllowedMessageActions","canEdit","replyingToId","selectReplyingToId","selectIsViewportNewest","chatMessageKeys","Object","keys","newIndex","toString","length","Number","MAIN_THREAD_ID","chat","selectChat","lastMessage","threadInfo","selectThreadInfo","lastMessageId","setReplyingToId","focusMessage","avatarOwnerId","profilePhotoIndex","origin","mediaViewer","audioPlayer","selectIsRightColumnShown","pollResults","voters","window","setTimeout","newGlobal","getGlobal","noHighlight","replyStack","selectReplyStack","pop","focusLastMessage","messageListType","groupedId","groupedChatId","replyMessageId","ids","selectForwardedMessageIdsByGroupId","shouldSwitchChat","clearTimeout","updateFocusedMessage","updateFocusDirection","FocusDirection","Static","includes","direction","Down","Up","loadViewportMessages","fromChatId","messageIds","groupedMessageIds","selectMessageIdsByGroupId","isModalShown","closeMediaViewer","selectedMessages","openForwardMenu","selectCurrentChat","enterMessageSelectMode","childMessageIds","withShift","toggleMessageSelection","shouldShowContextMenuHint","disableContextMenuHint","showNotification","message","IS_TOUCH_ENV","isPollModalOpen","globalSearch","updateGlobalSearch","globalResults","localResults","resultsByType","fetchingStatus","chats","recentlyFoundChatIds","newRecentIds","filter","unshift","content","updateGlobalSearchContent","stickers","search","resultIds","gifs","offsetId","results","updateSelectedUserId","updateUserSearch","globalUserIds","localUserIds","management","byChatId","isActive","IS_SINGLE_COLUMN_LAYOUT","IS_TABLET_COLUMN_LAYOUT","isLeftColumnShown","messageLists","action","emoji","recentEmojis","newEmojis","e","sticker","recent","hash","newStickers","s","notification","newNotifications","notifications","existingNotificationIndex","findIndex","n","splice","push","data","hasErrorKey","getReadableErrorText","newDialogs","dialogs","existingErrorIndex","err","url","safeLinkModalUrl","selectedAt","historyCalendarSelectedAt","payment","isPaymentModalOpen","clearPayment","closeInvoice","runThrottledForLoadChats","throttle","cb","runThrottledForLoadTopChats","runDebouncedForLoadFullChat","debounce","async","loadChats","listType","offsetDate","result","callApi","limit","CHAT_LIST_LOAD_SLICE","archived","withPinned","orderedPinnedIds","serverTimeOffset","chatIds","shift","addUsers","buildCollectionByKey","users","updateChats","updateChatListIds","updateChatListSecondaryInfo","draftsById","map","forEach","replyingToById","isFullyLoaded","loadFullChat","fullInfo","updateChat","openChatByUsername","username","channelPostId","localChat","selectChatByUsername","isMin","previousChat","preloadedChatIds","i","TOP_CHAT_MESSAGES_PRELOAD_LIMIT","pause","byId","listIds","active","currentChatId","pinnedChats","otherChats","prepareChatList","chatToPreload","find","currentUserId","hasUnreadMark","toggleChatUnread","isChatSummaryOnly","requestChatUpdate","user","selectUser","selectThreadTopMessageId","requestThreadInfoUpdate","selectSupportChat","langCode","usernamePostfix","LOCALIZED_TIPS","toUpperCase","TIPS_USERNAME","oldestChat","selectIsChatPinned","sort","chat1","chat2","date","force","isMuted","title","about","photo","memberIds","progress","ChatCreationProgress","InProgress","createdChannel","channelId","accessHash","Complete","Error","getDispatch","createChannel","userId","activeChat","activeChannel","createdChat","createGroupChat","folderId","folder","selectChatFolder","shouldBePinned","pinnedChatIds","includedChatIds","newPinnedIds","pinnedId","newIncludedChatIds","folderUpdate","selectChatListType","isPinned","ARCHIVED_FOLDER_ID","isChatArchived","chatFolders","loadChatFolders","recommendedChatFolders","recommended","loadRecommendedChatFolders","emoticon","maxId","recommendedId","description","newFolder","createChatFolder","Math","max","apply","deleteChatFolder","unreadCount","match","RE_TME_INVITE_LINK","exec","RE_TME_LINK","chatOrChannelPostId","isEnabled","isChatBasicGroup","bannedRights","chatAfterUpdate","members","kickedMembers","isBanned","viewMessages","isUnblocked","m","adminRights","customTitle","adminMembers","isDismissed","updateManagementProgress","ManagementProgress","Promise","all","groups","addedById","reduce","group","addChats","forDiscussionIds","channel","fullChat","isPreHistoryHidden","linkedChatId","activeChatFolder","offset","setNewChatMembersDialogState","NewChatMembersProgress","Loading","Closed","uploadProgressCallbacks","Map","runThrottledForMarkRead","isOutlying","isBudgetPreload","addOffset","LoadMoreDirection","Backwards","Around","round","MESSAGE_LIST_SLICE","Forwards","selectThreadOriginChat","threadInfos","addChatMessagesById","updateOutlyingIds","updateListedIds","updateThreadInfos","listedIds","selectListedIds","outlyingIds","selectOutlyingIds","areSortedArraysIntersecting","historyIds","newViewportIds","getViewportSlice","safeReplaceViewportIds","sourceIds","index","findClosestIndex","indexForDirection","from","to","slice","areSomeLocal","areAllLocal","sendMessage","params","localId","progressCallback","attachment","messageLocalId","has","set","fileUploads","byMessageLocalId","replyingTo","IS_IOS","rafPromise","delete","isRestricted","resolve","loadWithBudget","selectFocusedMessageId","selectRealLastReadId","replyOriginForId","MESSAGE_DELETED","replyMessage","selectChatMessage","updateChatMessage","replyToMessageId","loadMessage","scheduledAt","clearWebPagePreview","value","noWebPage","selectNoWebPage","isSingle","attachments","isGrouped","restParams","text","entities","commonParams","groupedAttachments","split","MAX_MEDIA_FILES_FOR_ALBUM","firstAttachment","restAttachments","Date","now","selectEditingMessage","setEditingId","get","previousLocalId","cancelApiProgress","apiUpdate","draft","replyToMsgId","draftDate","localOnly","selectDraft","isUnpin","isOneSide","isSilent","unpinAllMessages","shouldDeleteForAll","editingId","selectEditingId","selectEditingScheduledId","reason","peer","webPagePreview","loadWebPagePreview","options","option","shouldResetVoters","v","a","offsets","nextOffset","loadPollOptionResults","fromChat","toChat","b","scheduledMessages","historyHash","replaceScheduledMessages","loadScheduledHistory","selectScheduledMessage","loadPinnedMessages","searchThrottled","searchGifs","updateGifSearch","added","addedStickers","updateStickerSets","sets","loadStickerSets","setIds","addedSetIds","loadStickers","stickerSetId","recentStickers","loadRecentStickers","favorite","favoriteStickers","loadFavoriteStickers","featured","featuredStickers","loadFeaturedStickers","stickerSetAccessHash","stickerSet","selectStickerSet","packs","updateStickerSet","currentEmoji","forEmoji","rebuildStickersForEmoji","replaceAnimatedEmojis","loadAnimatedEmojis","saved","savedGifs","loadSavedGifs","unfave","unfaveSticker","installedDate","language","currentEmojiKeywords","emojiKeywords","isLoading","fromVersion","version","keywords","setsById","searchWords","searchStickers","updateStickersForEmoji","loadStickersForEmoji","searchMessagesGlobal","offsetRate","maxDate","minDate","localResult","chatOrUser","GLOBAL_SEARCH_SLICE","totalCount","nextOffsetId","nextRate","currentSearchQuery","selectCurrentGlobalSearchQuery","updateGlobalSearchFetchingStatus","addMessages","updateGlobalSearchResults","loadAndReplaceArchivedChats","updateUsers","replaceChatListIds","loadAndUpdateUsers","userIds","contactIds","contactList","updatedUsers","loadTopMessages","lastReadInboxMessageId","localChats","localUsers","globalChats","globalUsers","searchChats","timestampPlusDay","foundIds","currentSearch","selectCurrentTextSearch","topMessageId","MESSAGE_SEARCH_SLICE","newFoundIds","updateLocalTextSearchResults","searchTextMessages","peerId","selectCurrentMediaSearchPeerId","selectCurrentMediaSearch","currentType","currentResults","SHARED_MEDIA_SLICE","updateLocalMediaSearchResults","searchSharedMedia","timestamp","searchMessagesByDate","updateManagement","isUsernameAvailable","afterSyncCallback","DEBUG","console","log","savedUsers","savedPrivateChatIds","savedChats","selectedChat","isChatPrivate","selectedChatUser","replaceChats","loadAndReplaceChats","areMessagesLoaded","currentThreadId","draftsByChatId","acc","newCurrentChatId","currentMessageListInfo","threadsById","originChannelId","currentMessageListInfoOrigin","resultOrigin","byIdOrigin","listedIdsOrigin","Array","prototype","concat","replaceUsers","audioChatId","audioMessageId","closeAudioPlayer","loadAndReplaceMessages","lastSyncTime","sync","afterSync","runDebouncedForFetchFullUser","runThrottledForSearch","replaceInlineBotSettings","inlineBotSettings","inlineBots","byUsername","replaceInlineBotsIsLoading","topPeers","lastRequestedAt","usersHash","loadTopUsers","getCompareString","lastName","firstName","collator","Intl","Collator","sortedUsers","compare","isSelf","loadContactList","updateChatMutedState","phone","phoneNumber","updateUser","updateContact","deleteUser","profileId","isPrivate","photos","userSearch","updateUserSearchFetchingStatus","searchUsers","runDebouncedForSearch","sendBotCommand","command","button","openTelegramLink","toggleSafeLinkModal","alert","isError","showDialog","answerCallbackButton","openPollModal","getReceipt","receiptMessageId","getPaymentForm","setInvoiceMessageInfo","openPaymentModal","bot","selectChatBot","removeBlockedContact","topInlineBots","newHash","inlineBotData","inlineBot","switchPm","canLoadMore","shouldReplaceSettings","newInlineBotData","currentIds","Set","newResults","help","isGallery","searchInlineBot","queryId","resultId","replaceSettings","hasPassword","updateTwoFaSettings","hint","currentPassword","onSuccess","error","isSuccess","password","email","waitingEmailCodeLength","code","requestInfo","saveInfo","selectPaymentMessageId","shouldSave","shippingOptions","setRequestInfoId","updateShippingOptions","setPaymentStep","PaymentStep","Shipping","PaymentInfo","validateRequestedInfo","setPaymentForm","step","invoice","shippingAddressRequested","nameRequested","phoneRequested","emailRequested","ShippingInfo","setReceipt","receipt","publishableKey","selectProviderPublishableKey","credentials","k","join","buildQueryString","cardNumber","expiryMonth","expiryYear","cvv","zip","country","response","fetch","method","headers","Authorization","json","getStripeError","setStripeCardInfo","Checkout","sendStipeCredentials","shippingOptionId","saveCredentials","requestInfoId","selectPaymentRequestId","stripeCredentials","selectStripeCredentials","requestedInfoId","sendPaymentForm","save","runThrottledForUpdateAppBadge","update","noTopChatsRequest","selectIsChatListed","loadTopChats","newProfilePhoto","selectCountNotMutedUnread","updateAppBadge","isNotJoined","listId","typingStatus","senderId","isFromScheduled","isActiveChat","hasUnreadMention","unreadMentionsCount","showNewMessageNotification","messageUpdate","selectCommonBoxChatId","targetChat","newOrderedPinnedIds","MAX_ACTIVE_PINNED_CHATS","updateChatListType","chatFoldersById","newChatFoldersById","pick","newOrderedIds","orderedId","folders","replacedMembers","addedMember","deletedMemberId","shouldUpdate","some","deleteIndex","isOwner","isAdmin","membersCount","formattedText","updateWithLocalMedia","isScheduled","currentMessage","video","document","getMessageContent","blobUrl","thumbnail","isPreloadedGlobally","previewBlobUrl","updateScheduledMessage","updateListedAndViewportIds","firstMessageId","selectThreadByMessage","isUnreadChatNotLoaded","isMessageLocal","addViewportId","messagesCount","firstUnreadId","selectFirstUnreadId","updateChatLastMessage","currentLastMessage","findLastMessage","isDeleting","deleteMessages","newLastMessage","threadIdsToUpdate","deleteChatMessages","unique","chatsIdsToUpdate","commonBoxChatId","updateThreadInfo","newMessage","isMessageInCurrentMessageList","isOutgoing","scheduledIds","selectScheduledIds","selectScheduledMessages","deleteChatScheduledMessages","thread","markMessageListRead","currentPinnedIds","selectPinnedIds","newTheadInfo","messagesById","deleteScheduledMessages","pollId","pollUpdate","selectChatMessageByPollId","poll","updatedPoll","updatedResults","isChosen","chosenAnswers","chosenAnswer","chosenAnswerIndex","recentVoterIds","totalVoters","newRecentVoterIds","newTotalVoters","targetOption","targetOptionIndex","updatedOption","votersCount","flushStatusUpdatesThrottled","pendingStatusUpdates","statusUpdate","status","targetUser","isBlocked","addBlockedContact","settings","privacy","key","rules","updateNotifySettings","peerType","shouldShowPreviews","addNotifyException","twoFaSettings","useBeforeUnload","callback","useEffect","onBeforeUnload","memo","name","label","checked","disabled","inactive","noAnimation","onChange","onCheck","handleChange","useCallback","currentTarget","className","buildClassName","ANIMATION_LEVEL_OPTIONS","withGlobal","searchQuery","chatsById","animationLevel","byKey","globalSearchChatId","searchDate","theme","selectTheme","contactsFilter","onSearchQuery","onSelectSettings","onSelectContacts","onSelectArchived","setGlobalSearchChatId","onReset","shouldSkipTransition","openTipsChat","setGlobalSearchDate","setSettingOption","lang","useLang","hasMenu","LeftColumnContent","ChatList","clearedDateSearchParam","clearedChatSearchParam","selectedSearchDate","useMemo","formatDateToString","archivedUnreadChatsCount","values","total","withOtherVersions","location","hostname","MainButton","onTrigger","isOpen","Button","ripple","size","color","onClick","ariaLabel","handleSearchFocus","handleSelectSaved","handleDarkModeToggle","stopPropagation","newTheme","shouldUseSystemTheme","switchTheme","ANIMATION_LEVEL_MAX","handleAnimationLevelChange","newLevel","_","body","classList","toggle","isSearchFocused","GlobalSearch","Contacts","searchInputPlaceholder","DropdownMenu","trigger","footer","APP_NAME","APP_VERSION","MenuItem","icon","toLowerCase","href","FEEDBACK_URL","localStorage","setItem","JSON","stringify","disableHistoryBack","SearchInput","inputId","parentContainerClassName","focused","placeholder","autoComplete","canClose","onFocus","PickerSelectedItem","isMinimized","clickArg","chatOrUserId","dir","isRtl","Spinner","resolverFn","ms","dependencies","runThrottled","noFirst","useThrottle","setValue","useState","isFrozen","freeze","unfreeze","useFlag","useHeavyAnimationCheck","useOnChange","usersById","orderedFolderIds","notifySettings","selectNotifySettings","notifyExceptions","selectNotifyExceptions","setActiveChatFolder","transitionRef","useRef","displayedFolders","folderCountersById","useThrottledMemo","counters","unreadDialogsCount","hasActiveDialogs","getFolderUnreadDialogs","badgeCount","isBadgeActive","folderTabs","handleSwitchTab","current","captureEvents","onSwipe","SwipeDirection","Left","min","Right","isNotInAllTabRef","captureEscKeyListener","useHistoryBack","handleKeyDown","ctrlKey","shiftKey","startsWith","digit","preventDefault","addEventListener","removeEventListener","shouldRender","shouldRenderPlaceholder","transitionClassNames","useShowTransition","renderCurrentTab","activeFolder","folderType","noChatsText","TabList","tabs","activeTab","onSwitchTab","Transition","ref","activeKey","renderCount","props","LeftSearch","useModuleLoader","Bundles","Extra","ContactList","closeTimeout","isShown","onNewPrivateChat","onNewChannel","onNewGroup","isMenuOpen","setIsMenuOpen","fabClassName","handleMouseEnter","handleMouseLeave","onMouseEnter","onMouseLeave","tabIndex","Menu","positionX","positionY","autoClose","onClose","TRANSITION_RENDER_COUNT","onContentChange","connectionState","isNewChatButtonShown","setIsNewChatButtonShown","isConnecting","isOnline","setIsOnline","navigator","onLine","useBrowserOnline","isMouseInside","handleSelectSettings","Settings","handleSelectContacts","handleSelectNewChannel","NewChannelStep1","handleSelectNewGroup","NewGroupStep1","handleSelectArchived","Archived","autoCloseTimeout","shouldRenderUpdateButton","updateButtonClassNames","handleUpdateClick","isAppOutdated","markIsAppOutdated","timeout","reload","useAppOutdatedCheck","ShowTransition","isCustom","shouldCleanup","cleanupExceptionKey","fluid","pill","NewChat","ContentType","ArchivedChats","RENDER_COUNT","shouldSkipHistoryAnimations","setGlobalSearchQuery","resetChatCreation","loadPasswordInfo","clearTwoFaError","setContent","settingsScreen","setSettingsScreen","SettingsScreens","Main","setContactsFilter","lastResetTime","setLastResetTime","contentType","NewChannelStep2","NewChannel","NewGroupStep2","NewGroup","handleReset","forceReturnToChatList","pickerSearchInput","getElementById","blur","EditProfile","Folders","General","Notifications","Privacy","Language","GeneralChatBackground","GeneralChatBackgroundColor","PrivacyPhoneNumber","PrivacyLastSeen","PrivacyProfilePhoto","PrivacyForwarding","PrivacyGroupChats","PrivacyActiveSessions","PrivacyBlockedUsers","TwoFaDisabled","TwoFaEnabled","TwoFaCongratulations","PrivacyPhoneNumberAllowedContacts","PrivacyPhoneNumberDeniedContacts","PrivacyLastSeenAllowedContacts","PrivacyLastSeenDeniedContacts","PrivacyProfilePhotoAllowedContacts","PrivacyProfilePhotoDeniedContacts","PrivacyForwardingAllowedContacts","PrivacyForwardingDeniedContacts","PrivacyGroupChatsAllowedContacts","PrivacyGroupChatsDeniedContacts","TwoFaNewPassword","TwoFaNewPasswordConfirm","TwoFaNewPasswordHint","TwoFaNewPasswordEmail","TwoFaNewPasswordEmailCode","TwoFaChangePasswordCurrent","TwoFaTurnOff","TwoFaRecoveryEmailCurrentPassword","TwoFaChangePasswordNew","TwoFaChangePasswordConfirm","TwoFaChangePasswordHint","TwoFaRecoveryEmail","TwoFaRecoveryEmailCode","FoldersCreateFolder","FoldersEditFolder","handleSearchQuery","handleSettingsScreenSelect","screen","LAYERS_ANIMATION_NAME","currentScreen","onScreenSelect","isChannel","setSize","windowSize","handleResize","calculateMiddleFooterTransforms","windowWidth","canPost","sidePadding","MOBILE_SCREEN_MAX_WIDTH","messageListWidth","MIN_SCREEN_WIDTH_FOR_STATIC_RIGHT_COLUMN","leftColumnWidth","rightColumnWidth","MIN_SCREEN_WIDTH_FOR_STATIC_LEFT_COLUMN","getMessageListWidth","sendButtonWidth","composerWidth","toolbarWidth","composerHiddenScale","toolbarHiddenScale","composerTranslateX","toolbarTranslateX","unpinHiddenScale","toolbarForUnpinHiddenScale","createMessageHash","messageList","HeaderMenuContainer","isChatChannel","noMenu","isChatWithSelf","selectIsChatWithSelf","isMainThread","isDiscussionThread","isRightColumnShown","canRestartBot","selectIsUserBlocked","canStartBot","selectIsChatBotNotStarted","canSubscribe","isChatSuperGroup","canSearch","canMute","canSelect","selectIsInSelectMode","canLeave","joinChannel","openLocalTextSearch","restartBot","menuButtonRef","menuPosition","setMenuPosition","handleHeaderMenuOpen","rect","getBoundingClientRect","x","right","y","bottom","handleHeaderMenuClose","handleHeaderMenuHide","handleSubscribeClick","handleStartBot","handleRestartBot","handleSearchClick","querySelector","focus","searchInput","anchor","onSubscribeChannel","onSearchClick","onCloseAnimationEnd","useWebpThumbnail","getMessageMediaThumbDataUri","shouldDecodeThumbnail","isWebpSupported","thumbnailDecoded","setThumbnailDecoded","EMPTY_IMAGE_DATA_URI","useLayoutEffect","webpToPngBase64","then","catch","drawRect","width","height","radius","count","containerRef","markupParams","reverseIndex","barHeight","getBarHeight","markHeight","getMarkHeight","trackHeight","getTrackHeight","clipPathId","clipPath","d","getClipPath","markTranslateY","getMarkTranslateY","trackTranslateY","getTrackTranslateY","calculateMarkup","firstChild","firstElementChild","currentElement","style","transform","svg","div","defs","innerHTML","onUnpinMessage","onAllPinnedClick","mediaThumbnail","mediaBlobUrl","useMedia","getMessageMediaHash","getMessageSummaryText","isUnpinDialogOpen","openUnpinDialog","closeUnpinDialog","handleUnpinMessage","ConfirmDialog","confirmLabel","confirmHandler","thumbDataUri","getPictogramDimensions","src","alt","renderPictogram","renderText","RippleEffect","sender","selectSender","noUi","senderName","getSenderTitle","mediaData","mediaLoader","playPause","isPlaying","useAudioPlayer","getMessageKey","getMediaDuration","handleClick","handleClose","audio","getMessageAudio","performer","fileName","renderAudio","subtitle","renderVoice","audioMessage","pinnedIds","state","isSelectModeActive","isChatWithBot","selectIsChatWithBot","currentTransitionKey","assign","pinnedMessageId","topMessageSender","selectForwardedSender","pinnedMessageIds","canUnpin","firstPinnedMessage","isReady","openChatWithInfo","pinMessage","openPreviousChat","toggleLeftColumn","pinnedMessageIndex","setPinnedMessageIndex","isArray","pinnedMessage","pinnedMessagesCount","chatTitleLength","getChatTitle","topMessageTitle","useEnsureMessage","useWindowSize","isLeftColumnHideable","shouldShowCloseButton","componentRef","shouldAnimateTools","handleHeaderClick","handlePinnedMessageClick","cycleRestrict","handleAllPinnedClick","handleBackClick","messageInput","EDITABLE_INPUT_ID","currentChat","selectIsChatMuted","canToolsCollideWithChatInfo","SAFE_SCREEN_WIDTH_FOR_CHAT_INFO","shouldUseStackedToolsClass","SAFE_SCREEN_WIDTH_FOR_STATIC_RIGHT_COLUMN","shouldRenderAudioPlayer","audioPlayerClassNames","renderingAudioMessage","useCurrentOrPrev","shouldRenderPinnedMessage","pinnedMessageClassNames","renderingPinnedMessage","renderingPinnedMessageTitle","canRevealTools","renderInfo","renderBackButton","PrivateChatInfo","withFullInfo","withMediaViewer","withUpdatingStatus","noRtl","GroupChatInfo","asClose","unreadCountInfo","formatIntegerCompact","componentEl","add","remove","isAlbum","messageOrAlbum","groupMessages","currentAlbum","currentSenderGroup","currentDateGroup","originalDate","datetime","getDayStart","senderGroups","dateGroups","isInAlbum","mainMessage","albumId","nextMessage","nextMessageDayStartsAt","isActionMessage","forwardInfo","senderUserId","hiddenUserName","inlineButtons","preventMessageInputBlur","activeElement","target","useStickyDates","isScrolled","markIsScrolled","runDebounced","shouldRunFirst","shouldRunLast","updateStickyDates","container","hasTools","contains","fastRaf","currentStuck","stuckDateEl","allElements","querySelectorAll","containerTop","scrollTop","el","offsetTop","offsetHeight","top","findStuckDate","INTERSECTION_THROTTLE_FOR_MEDIA","IS_ANDROID","INTERSECTION_MARGIN_FOR_MEDIA","isEmojiOnlyMessage","customShape","getMinMediaWidth","hasText","hasCommentButton","calculateMediaDimensions","noAvatars","isOwn","isOwnMessage","isForwarded","isForwardedMessage","getMessagePhoto","getMessageWebPagePhoto","getMessageVideo","isWebPagePhoto","calculateInlineImageDimensions","calculateVideoDimensions","minMediaWidth","getMessageText","stretchFactor","finalWidth","finalHeight","isSmall","AlbumRectPart","accumulate","list","initValue","accumulator","item","clamp","num","low","high","calculateContainerSize","layout","styles","dimensions","sides","calculateAlbumLayout","album","ratios","proportions","ratio","getProportions","averageRatio","getAverageRatio","albumCount","forceCalc","maxWidth","getAvailableWidth","REM","minWidth","maxHeight","spacing","originalRatios","cropRatios","attempts","pushAttempt","lineCounts","heights","currentCount","attemptCount","sum","multiHeight","first","second","third","fourth","optimalAttempt","optimalDiff","lineCount","totalHeight","bad1","bad2","line","diff","abs","optimalCounts","optimalHeights","rowCount","row","colCount","lineHeight","col","layoutWithComplexLayouter","layoutTwoTopBottom","layoutTwoLeftRightEqual","minimalWidth","secondWidth","firstWidth","layoutTwoLeftRight","layoutTwo","firstHeight","thirdHeight","secondHeight","rightWidth","leftWidth","layoutThreeLeftAndOther","layoutThreeTopAndOther","layoutThree","w","h0","h","w0","w2","w1","h1","layoutFourTopAndOther","h2","layoutFourLeftAndOther","layoutFour","containerStyle","element","calculateAuthorWidth","createElement","font","whiteSpace","left","opacity","appendChild","offsetWidth","useFocusMessage","elementRef","isFocused","focusDirection","noFocusHighlight","messagesContainer","closest","fastSmoothScroll","ContextMenuContainer","targetUserIds","targetChatId","targetMessageId","targetMessage","selectIsMessageFocused","focusedMessage","observeIntersection","isEmbedded","appearanceOrder","isLastInList","useOnIntersect","noAppearanceAnimation","markShown","targetUsers","renderActionMessageText","asPlain","isContextMenuOpen","contextMenuPosition","handleBeforeContextMenu","handleContextMenu","handleContextMenuClose","handleContextMenuHide","useContextMenuHandlers","isContextMenuShown","data-message-id","onMouseDown","onContextMenu","EmbeddedMessage","customText","isIntersecting","useIsIntersecting","pictogramId","isRoundVideo","getMessageRoundVideo","senderTitle","outgoingStatus","signature","views","isEdited","formatTime","MessageOutgoingStatus","Sticker","observeIntersectionForPlaying","shouldLoop","isModalOpen","openModal","closeModal","isAnimated","isMemojiSticker","MEMOJI_STICKER_ID","shouldLoad","shouldPlay","mediaHash","getMessageMediaFormat","isMediaLoaded","isAnimationLoaded","markAnimationLoaded","isMediaReady","shouldRenderFullMedia","useTransitionForMedia","getStickerDimensions","thumbClassName","stickerClassName","AnimatedSticker","animationData","play","noLoop","onLoad","fromSticker","useBlurredMediaThumbRef","fullMediaData","useCanvasBlur","IS_CANVAS_FILTER_SUPPORTED","SELECTED_APPENDIX_BACKGROUND","getCustomAppendixBg","inSelectMode","isSelected","img","Image","onload","canvas","ctx","getContext","drawImage","getImageData","getAppendixColorFromImage","Photo","shouldAutoLoad","isInSelectMode","uploadProgress","nonInteractive","shouldAffectAppendix","onCancelUpload","localBlobUrl","isDownloadAllowed","setIsDownloadAllowed","shouldDownload","downloadProgress","useMediaWithDownloadProgress","thumbRef","isUploading","isTransferring","transferProgress","getMediaTransferState","wasDownloadDisabled","usePrevious","shouldRenderSpinner","spinnerClassNames","shouldRenderThumb","isAllowed","contentEl","appendixBg","setProperty","setAttribute","ProgressSpinner","useHeavyAnimationCheckForVideo","playerRef","shouldPlayRef","safePlay","isPlayAllowed","wasPlaying","freezePlaying","paused","unfreezePlaying","unfreezePlayingOnRaf","hasFocus","useBackgroundMode","Video","shouldAutoPlay","videoRef","getMessageWebPageVideo","setIsPlayAllowed","isInline","isBuffered","bufferingHandlers","useBuffering","playProgress","setPlayProgress","handleTimeUpdate","currentTime","duration","usePauseOnInactive","useVideoCleanup","videoClassName","autoPlay","muted","loop","playsInline","onTimeUpdate","isGif","formatMediaDuration","contact","openUserInfo","Avatar","formatPhoneNumberWithCode","selected","loadingOptions","setValues","event","newValues","Checkbox","subLabel","getPercentage","toFixed","PollOption","answer","voteResults","maxVotersCount","correctResults","shouldAnimate","r","correctAnswer","showIcon","answerPercent","finalPercent","setFinalPercent","lineRef","lineWidth","isAnimationDoesNotStart","lineEl","svgEl","lineStyle","onSendVote","openPollResults","summary","isSubmitting","setIsSubmitting","chosenOptions","setChosenOptions","isSolutionShown","setIsSolutionShown","wasSubmitted","setWasSubmitted","closePeriod","setClosePeriod","closed","closeDate","floor","countdownRef","hasVoted","canVote","canViewResult","isPublic","isMultiple","multipleChoice","answers","isCorrect","hidden","quiz","countdownEl","circumference","PI","lastElementChild","timerEl","strokeDashOffset","textContent","timer","recentVoters","handleRadioChange","handleCheckboxChange","handleVoteClick","handleViewResultsClick","handleSolutionShow","handleSolutionHide","solution","Notification","renderTextWithEntities","solutionEntities","onDismiss","containerId","question","getPollTypeString","RadioGroup","loadingOption","isQuiz","getReadableVotersCount","isText","inPreview","onMediaClick","onCancelMediaTransfer","webPage","getMessageWebPage","isSquarePhoto","handleMediaClick","siteName","displayUrl","isMediaInteractive","truncatedDescription","trimText","data-initial","SafeLink","getMessageInvoice","photoUrl","withSelectControl","WrappedComponent","ownProps","selectIsMessageSelected","handleMessageSelect","newProps","PhotoWithSelect","VideoWithSelect","uploadsById","hasCustomAppendix","albumLayout","cancelSendingMessage","mediaCount","handleCancelUpload","containerWidth","containerHeight","fileUpload","currentOnRelease","RoundVideo","playingProgressRef","shouldSpinnerRender","isActivated","setIsActivated","setProgress","playerEl","playingProgressEl","stopPlaying","capturePlaying","onRelease","ROUND_VIDEO_DIMENSIONS","onEnded","InlineButtons","shouldRequestThreadUpdate","recentReplierIds","recentRepliers","hasUnread","data-cnt","handleDocumentGroupMouseEnter","lastGroupElement","getLastElementInDocumentGroup","handleDocumentGroupMouseLeave","removeAttribute","nextElementSibling","withSenderName","withAvatar","viaBotId","chatUsername","forceSenderName","isAnonymousOwnMessage","originSender","botSender","threadTopMessageId","isThreadTop","shouldHideReply","replyMessageSender","selectUploadProgress","isForwarding","highlight","singleEmoji","getMessageSingleEmoji","every","isSingleEmoji","animatedEmoji","selectAnimatedEmoji","isGroupSelected","selectIsDocumentGroupSelected","isPinnedList","shouldAutoLoadMedia","selectShouldAutoLoadMedia","shouldAutoPlayMedia","selectShouldAutoPlayMedia","shouldLoopStickers","selectShouldLoopStickers","selectOutgoingStatus","observeIntersectionForBottom","observeIntersectionForMedia","observeIntersectionForAnimatedStickers","noComments","isFirstInGroup","isLastInGroup","isFirstInDocumentGroup","isLastInDocumentGroup","openMediaViewer","openAudioPlayer","markMessagesRead","sendPollVote","clickInlineButton","bottomMarkerRef","appendixRef","isLocal","hasReply","isReplyMessage","hasThread","asForwarded","isLinkedChannelPost","isInDocumentGroup","voice","getMessageCustomShape","textParts","renderMessageText","adminTitle","metaSafeAuthorWidth","canShowActionButton","canForward","canFocus","isChannelPost","fromMessageId","avatarPeer","senderPeer","containerClassName","contentClassName","hasComments","classNames","isMedia","isMediaWithNoText","isViaBot","isRound","buildContentClassName","withCommentButton","withAppendix","handleGroupDocumentMessagesSelect","handleContainerDoubleClick","handleContentDoubleClick","handleAvatarClick","handleSenderClick","handleViaBotClick","handleReplyClick","MediaViewerOrigin","ScheduledInline","Inline","handleAudioPlay","handleAlbumMediaClick","albumMessageId","ScheduledAlbum","Album","getIsKeyboardVisible","handleReadMedia","handleVoteSend","handleGroupForward","handleForward","handleFocus","handleFocusForwarded","calculatedWidth","noMediaCorners","extraPadding","onDoubleClick","data-last-message-id","data-has-unread-mention","isAvatarPeerUser","avatarUser","avatarChat","hiddenName","renderAvatar","shouldInlineMeta","senderColor","getUserColorKey","renderSenderName","AnimatedEmoji","forceLoadPreview","Audio","isSelectable","onPlay","onReadMedia","Document","renderContent","messageGroups","isViewportNewest","isUnread","withUsers","anchorIdRef","memoFirstUnreadIdRef","hasLinkedChat","isSchedule","onFabToggle","onNotchToggle","openHistoryCalendar","observeIntersectionForReading","observe","useIntersectionObserver","rootRef","throttleMs","margin","freezeForReading","unfreezeForReading","entries","mentionIds","entry","dataset","useMessageObservers","backwardsTriggerRef","forwardsTriggerRef","fabTriggerRef","loadMoreBackwards","loadMoreForwards","toggleScrollTools","scrollHeight","scrollBottom","isAtBottom","MESSAGE_LIST_SENSITIVE_AREA","triggerEntry","resetScroll","observeIntersectionForFab","freezeForFab","unfreezeForFab","observeIntersectionForNotch","freezeForNotch","unfreezeForNotch","useScrollHooks","unreadDivider","messageCountToAnimate","messageGroup","flatten","appearanceIndex","dateGroup","dateGroupIndex","dateGroupsArray","senderGroup","senderGroupIndex","senderGroupsArray","compact","currentDocumentGroupId","messageIndex","isMessageAlbum","documentGroupId","nextDocumentGroupId","originalId","getMessageOriginalId","teactFastList","SCHEDULED_WHEN_ONLINE","formatHumanDate","runDebouncedForScroll","selectCurrentMessageIds","restrictionReason","focusingId","hasFocusHighlight","withLastMessageWhenPreloading","botDescription","chatBot","isChatLoaded","isChannelChat","threadFirstMessageId","selectFirstMessageId","setScrollOffset","scrollOffsetRef","selectScrollOffset","anchorTopRef","listItemElementsRef","memoUnreadDividerBeforeIdRef","memoFocusingIdRef","isScrollTopJustUpdatedRef","shouldAnimateAppearanceRef","setContainerHeight","onTickEnd","listedMessages","orderBy","loadMoreAround","handleScroll","parentElement","observer","ResizeObserver","offsetParent","contentRect","disconnect","windowHeight","normalHeight","String","clientHeight","preservedItemElements","useLayoutEffectWithPrevDeps","prevMessageIds","prevIsViewportNewest","prevContainerHeight","shouldForceScroll","lastItemElement","lastItemHeight","newScrollTop","hasFirstMessageChanged","hasLastMessageChanged","isAlreadyFocusing","isResized","isAnimatingScroll","useEffectWithPrevDeps","prevIsSelectModeActive","dispatchHeavyAnimationEvent","onScroll","focusNextReply","messageElements","lastMessageElement","buildAttachment","filename","blob","isQuick","URL","createObjectURL","mimeType","quick","preloadImage","newBlob","toBlob","squeezeImage","revokeObjectURL","videoWidth","videoHeight","preloadVideo","createPosterForVideo","resetInput","applyIosAutoCapitalizationFix","inputEl","POLYFILL_OPTIONS","encoderPath","reuseWorker","BLOB_PARAMS","opusRecorderPromise","OpusRecorder","mediaRecorder","init","default","start","analyzerCallback","startMediaRecorder","startedAt","pausedAt","chunks","waveform","ondataavailable","typedArray","releaseAnalyzer","recorder","source","sourceNode","analyser","context","createAnalyser","fftSize","connect","dataLength","frequencyBinCount","dataArray","Uint8Array","isDestroyed","tick","getByteFrequencyData","volume","requestAnimationFrame","subscribeToAnalyzer","stop","reject","onstop","Blob","onerror","delayStop","CLIPBOARD_ACCEPTED_TYPES","getMessageTextAsHtml","tempEl","INLINE_BOT_QUERY_REGEXP","HAS_NEW_LINE","useInlineBotTooltip","html","markIsOpen","unmarkIsOpen","replace","innerText","getPlainText","queryInlineBot","resetInlineBot","canShowHelp","parseStartWithUsernameString","usernameLowered","prevQuery","prevUsername","botId","loadMore","closeTooltip","DeleteMessageModal","openTimeout","isFirstTimeActivation","onActivate","buttonProps","AttachMenu","SymbolMenu","InlineBotTooltip","MentionTooltip","CustomSend","StickerTooltipAsync","StickerTooltip","BotKeyboardMenu","forwardMessageIds","forwardedMessagesCount","exitForwardMode","canAnimate","useAsyncRendering","clearEmbedded","handleMessageClick","AttachmentModal","PollModal","DropArea","RE_LINK","RegExp","RE_LINK_TEMPLATE","messageText","toggleMessageWebPage","link","parseMessageInput","linkEntity","ApiMessageEntityTypes","TextUrl","textMatch","renderingWebPage","webPageWithoutPhoto","messageStub","CalendarModal","PaymentModal","MainButtonState","ReceiptModal","chatUser","selectChatUser","messageWithActualBotKeyboard","selectNewestMessageWithBotKeyboardButtons","baseEmojiKeywords","BASE_EMOJI_KEYWORD_LANG","editingMessage","canScheduleUntilOnline","wasOnline","withScheduledButton","shouldSchedule","botKeyboardMessageId","stickersForEmoji","groupChatMembers","topInlineBotIds","isReceiptModalOpen","shouldSuggestStickers","isInlineBotLoading","dropAreaState","onDropHide","editMessage","saveDraft","clearDraft","setStickerSearchQuery","setGifSearchQuery","closePollModal","closePaymentModal","clearReceipt","addRecentEmoji","sendInlineBotResult","setHtml","lastMessageSendTimeSeconds","prevDropAreaState","isCalendarOpen","openCalendar","closeCalendar","scheduledMessageArgs","setScheduledMessageArgs","htmlRef","setAttachments","isBotKeyboardOpen","openBotKeyboard","closeBotKeyboard","isAttachMenuOpen","openAttachMenu","closeAttachMenu","isSymbolMenuOpen","openSymbolMenu","closeSymbolMenu","isDeleteModalOpen","openDeleteModal","closeDeleteModal","isSymbolMenuLoaded","onSymbolMenuLoadingComplete","isHoverDisabled","disableHover","enableHover","startRecordingVoice","stopRecordingVoice","pauseRecordingVoice","activeVoiceRecording","currentRecordTime","recordButtonRef","mainButtonRef","startRecordTimeRef","setActiveVoiceRecording","setCurrentRecordTime","IS_VOICE_RECORDING_SUPPORTED","voiceRecording","tickVolume","boxShadow","useVoiceRecording","mainButtonState","Edit","Send","Record","canShowCustomSendMenu","isMentionTooltipOpen","mentionFilter","closeMentionTooltip","insertMention","mentionFilteredUsers","useMentionTooltip","isInlineBotTooltipOpen","inlineBotId","isInlineBotTooltipGallery","inlineBotSwitchPm","inlineBotResults","closeInlineBotTooltip","inlineBotHelp","loadMoreForInlineBot","isCustomSendMenuOpen","allowedAttachmentOptions","getAllowedAttachmentOptions","isChatAdmin","slowMode","getChatSlowModeOptions","isStickerTooltipOpen","closeStickerTooltip","isDisabled","clearStickersForEmoji","IS_EMOJI_SUPPORTED","parseEmojiOnlyString","hasStickers","useStickerTooltip","canSendStickers","isEmojiTooltipOpen","closeEmojiTooltip","filteredEmojis","insertEmoji","useEmojiTooltip","insertTextAndUpdateCursor","selection","getSelection","newHtml","rangeCount","selectionRange","getRangeAt","isSelectionInsideInput","range","deleteContents","fragment","createContextualFragment","lastInsertedNode","lastChild","insertNode","setStartAfter","setEndAfter","collapse","removeAllRanges","addRange","insertHtmlInSelection","dispatchEvent","Event","bubbles","focusEditableElement","removeSymbol","execCommand","tempInput","contentEditable","textLength","createRange","setStart","setEnd","removeChild","deleteLastCharacterOutsideSelection","resetComposer","shouldPreserveInput","prevChatId","handleEditComplete","editedMessage","hasMessageMedia","useEditing","updateDraft","draftChatId","draftThreadId","runDebouncedForSaveDraft","DRAFT_DEBOUNCE","prevThreadId","prevHtml","handleBlur","useDraft","handlePaste","clipboardData","input","EDITABLE_INPUT_MODAL_ID","items","media","file","getAsFile","pastedText","getData","substring","useClipboardPaste","handleFileSelect","files","handleAppendFiles","handleClearAttachment","handleSend","currentAttachments","record","extraLength","textParams","nowSeconds","secondsSinceLastMessage","nextSendDateNotReached","nextSendDate","seconds","secondsRemaining","isSlowMode","handleStickerSelect","handleGifSelect","gif","handleInlineBotSelect","inlineResult","handlePollSend","handleSilentSend","handleMessageSchedule","isWhenOnline","restArgs","getTime","handleMessageScheduleUntilOnline","handleCloseCalendar","handleSearchOpen","handleSymbolMenuOpen","handleAllScheduledClick","mainButtonHandler","areVoiceMessagesNotAllowed","canAttachMedia","prevEditedMessage","renderedEditedMessage","scheduledDefaultDate","setSeconds","setMilliseconds","scheduledMaxDate","setFullYear","getFullYear","sendButtonAriaLabel","symbolMenuButtonClassName","onSend","Portal","DropAreaState","None","withQuick","QuickFile","onHide","onFileSelect","caption","onCaptionUpdate","onFileAppend","onClear","onInsertUserName","filteredUsers","onSelectResult","canAttachEmbedLinks","faded","MessageInput","forcedPlaceholder","shouldSetFocus","shouldSuppressFocus","shouldSuppressTextFormatter","onUpdate","onSuppressedFocus","formatVoiceRecordDuration","onStickerSelect","emojis","onEmojiSelect","onPollCreate","onGifSelect","onRemoveSymbol","onSearchOpen","onSilentSend","onScheduleSend","withTimePicker","maxAt","getDayStartAt","isFutureMode","secondButtonLabel","onSubmit","onSecondButtonClick","MobileSearch","MessageSelectToolbar","UnpinAllMessagesModal","CLOSE_ANIMATION_DURATION","canBeQuicklyUploaded","kind","CONTENT_TYPES_FOR_QUICK_UPLOAD","isBlurred","isBackgroundBlurred","background","customBackground","backgroundColor","patternColor","themes","isMobileSearchActive","getCanPostInChat","isBotNotStarted","isPinnedMessageList","isScheduledMessageList","currentUserBannedRights","defaultBannedRights","hasPinnedOrAudioMessage","loadUser","setDropAreaState","isFabShown","setIsFabShown","isNotchShown","setIsNotchShown","isUnpinModalOpen","setIsUnpinModalOpen","setIsReady","ANIMATION_LEVEL_MIN","renderingChatId","usePrevDuringAnimation","renderingThreadId","renderingMessageListType","renderingCanPost","renderingHasTools","renderingIsFabShown","handleDragEnter","dataTransfer","shouldDrawQuick","handleHideDropArea","handleOpenUnpinModal","closeUnpinModal","handleUnpinAllMessages","handleTabletFocus","customBackgroundValue","settingValue","cacheApi","CUSTOM_BG_CACHE_NAME","useCustomBackground","MASK_IMAGE_DISABLED","messagingDisabledClassName","messageSendingRestrictionReason","getMessageSendingRestrictionReason","footerClassName","onTransitionEnd","propertyName","DARK_THEME_BG_COLOR","LIGHT_THEME_BG_COLOR","onDragEnter","onUnpin","HeaderContent","isProfile","isManagement","messageSearchQuery","stickerSearchQuery","selectCurrentStickerSearch","gifSearchQuery","selectCurrentGifSearch","canManage","isCreator","isColumnOpen","isSearch","isStickerSearch","isGifSearch","isPollResults","isAddingChatMembers","profileState","managementScreen","setLocalTextSearchQuery","searchTextMessagesLocal","toggleManagement","shouldSkipAnimation","backButtonRef","handleMessageSearchQueryChange","handleStickerSearchQueryChange","handleGifSearchQueryChange","setShouldSkipTransition","contentKey","ProfileState","Profile","SharedMedia","MemberList","Search","PollResults","StickerSearch","GifSearch","AddingMembers","ManagementScreens","Initial","ManageInitial","ChatPrivacyType","ManageChatPrivacyType","Discussion","ManageDiscussion","ChannelSubscribers","ManageChannelSubscribers","GroupPermissions","ManageGroupPermissions","ChatAdministrators","ManageChatAdministrators","GroupRemovedUsers","ManageGroupRemovedUsers","GroupUserPermissionsCreate","ManageGroupUserPermissionsCreate","GroupUserPermissions","ManageGroupUserPermissions","GroupRecentActions","ManageGroupRecentActions","ChatAdminRights","ManageGroupAdminRights","GroupMembers","ManageGroupMembers","renderingContentKey","renderHeaderContent","isBackButton","buttonClassName","useProfileViewportIds","loadMoreMembers","searchMessages","tabType","mediaSearchType","resultType","sortUserIds","memberViewportIds","getMoreMembers","noProfileInfoForMembers","currentResultType","handleLoadMore","getMore","useInfiniteScroll","MEMBERS_SLICE","isOnTop","useInfiniteScrollForMembers","mediaViewportIds","getMoreMedia","noProfileInfoForMedia","useInfiniteScrollForSharedMedia","documentViewportIds","getMoreDocuments","noProfileInfoForDocuments","linkViewportIds","getMoreLinks","noProfileInfoForLinks","audioViewportIds","getMoreAudio","noProfileInfoForAudio","noProfileInfo","forSharedMediaType","messageIdsRef","getMessageContentIds","reverse","runThrottledForScroll","isScrollingProgrammatically","isFirstPhoto","isSavedMessages","isDeleted","isDeletedUser","getMediaHash","forceAvatar","getChatAvatarHash","imageHash","ApiMediaFormat","BlobUrl","avatarThumbnailData","useBlurSync","dataUri","imageSrc","prevImageSrc","decoding","userFullName","getUserFullName","getFirstLetters","fullClassName","forceShowSelf","loadFullUser","fullName","slideAnimation","currentPhotoIndex","setCurrentPhotoIndex","isFirst","isLast","profile","currentIndex","usePhotosPreload","handleProfilePhotoClick","ProfileAvatar","selectPreviousMedia","selectNextMedia","renderPhoto","isVerifiedIconShown","isVerified","renderPhotoTabs","aria-label","VerifiedIcon","isUserOnline","getUserStatus","canInviteUsers","isUserRightBanned","getHasAdminRight","handleNotificationChange","copy","entity","copyTextToClipboard","formattedNumber","getChatLink","bio","getChatDescription","ListItem","multiline","narrow","isStatic","contactName","getUserFirstOrLastName","deleteChatMember","handleDeleteChatMember","Modal","onEnter","TABS","buildInfiniteScrollItemSelector","isGroup","isChatGroup","hasMembersTab","areMembersHidden","canViewMembers","canAddMembers","canDeleteMembers","resolvedUserId","onProfileStateChange","setLocalMediaSearchType","searchMediaMessagesLocal","loadProfilePhotos","setActiveTab","deletingUserId","setDeletingUserId","prevTabType","tabsEl","prevProfileState","tabListEl","determineProfileState","useProfileState","applyTransitionFix","releaseTransitionFix","transitionElSelector","setMinHeight","transitionEl","minHeight","overflowY","scrollBarWidth","clientWidth","marginRight","useTransitionFixes","cacheBuster","resetCacheBuster","setCacheBuster","useCacheBuster","handleTransitionStop","handleNewMemberDialogOpen","handleSelectMedia","handlePlayAudio","handleMemberClick","handleMessageFocus","handleDeleteMembersModalClose","renderingDelay","isFirstTab","SLIDE_TRANSITION_DURATION","canRenderContents","getMemberContextAction","handler","renderSharedMedia","noSpinner","NothingFound","Media","withDate","smaller","onDateClick","WebLink","onMessageClick","teactOrderKey","contextActions","InfiniteScroll","itemSelector","sensitiveArea","PROFILE_SENSITIVE_AREA","preloadBackwards","noScrollRestoreOnTop","noFastList","onLoadMore","renderProfileInfo","shouldRestoreHeight","onStart","onStop","big","FloatingActionButton","RightSearch","Management","localContactIds","isSearching","onNextStep","setUserSearchQuery","selectedMemberIds","setSelectedMemberIds","noPickerScrollRestore","member","handleFilterChange","displayedIds","sortChatIds","foundContactIds","contactId","isUserBot","canBeInvitedToGroup","handleNextStep","Picker","itemIds","selectedIds","filterValue","filterPlaceholder","searchInputId","onSelectedIdsChange","onFilterChange","noScrollRestore","MAIN_SCREENS_COUNT","RightColumnContent","MANAGEMENT_SCREENS_COUNT","blurSearchInput","areActiveChatsLoaded","selectAreActiveChatsLoaded","selectRightColumnContentKey","currentProfileUserId","selectedId","isChatSelected","toggleChatInfo","closePollResults","addChatMembers","setProfileState","setManagementScreen","selectedChatMemberId","setSelectedChatMemberId","isPromotedByCurrentUser","setIsPromotedByCurrentUser","isScrolledDown","ChatInfo","UserInfo","isOverlaying","close","shouldScrollUp","GroupType","handleSelectChatMember","memberId","isPromoted","handleAppendingChatMembers","onChatMemberSelect","prevContentKey","MediaViewer","Dialogs","ForwardPicker","SafeLinkModal","HistoryCalendar","notificationInterval","DEBUG_isLogged","updateIcon","asUnread","updatePageTitle","nextTitle","isMediaViewerOpen","selectIsMediaViewerOpen","isForwardModalOpen","selectIsForwardModalOpen","hasNotifications","hasDialogs","isHistoryCalendarOpen","loadNotificationSettings","loadNotificationExceptions","updateIsOnline","loadTopInlineBots","loadEmojiKeywords","middleColumnTransitionClassNames","rightColumnTransitionClassNames","prevIsLeftColumnShown","dispatchHeavyAnimationEnd","waitForTransitionEnd","prevIsRightColumnShown","initialUnread","clearInterval","setInterval","INACTIVE_MARKER","newUnread","PAGE_TITLE","stopEvent","onDrop","onDragOver","initApi"],"mappings":"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","file":"4.8f9749ecd5124aef108a.js","sourcesContent":["import { addReducer } from '../../../lib/teact/teactn';\n\nimport {\n updateLocalTextSearch,\n replaceLocalTextSearchResults,\n updateLocalMediaSearchType,\n} from '../../reducers';\nimport { MEMO_EMPTY_ARRAY } from '../../../util/memo';\nimport { selectCurrentMessageList } from '../../selectors';\nimport { buildChatThreadKey } from '../../helpers';\nimport { GlobalState } from '../../../global/types';\n\naddReducer('openLocalTextSearch', (global) => {\n const { chatId, threadId } = selectCurrentMessageList(global) || {};\n if (!chatId || !threadId) {\n return undefined;\n }\n\n return updateLocalTextSearch(global, chatId, threadId, true);\n});\n\naddReducer('closeLocalTextSearch', closeLocalTextSearch);\n\naddReducer('setLocalTextSearchQuery', (global, actions, payload) => {\n const { chatId, threadId } = selectCurrentMessageList(global) || {};\n if (!chatId || !threadId) {\n return undefined;\n }\n\n const { query } = payload!;\n const chatThreadKey = buildChatThreadKey(chatId, threadId);\n const { query: currentQuery } = global.localTextSearch.byChatThreadKey[chatThreadKey] || {};\n\n if (query !== currentQuery) {\n global = replaceLocalTextSearchResults(global, chatId, threadId, MEMO_EMPTY_ARRAY);\n }\n\n global = updateLocalTextSearch(global, chatId, threadId, true, query);\n\n return global;\n});\n\naddReducer('setLocalMediaSearchType', (global, actions, payload) => {\n const { chatId } = selectCurrentMessageList(global) || {};\n if (!chatId) {\n return undefined;\n }\n\n const { mediaType } = payload!;\n return updateLocalMediaSearchType(global, chatId, mediaType);\n});\n\nexport function closeLocalTextSearch(global: GlobalState): GlobalState {\n const { chatId, threadId } = selectCurrentMessageList(global) || {};\n if (!chatId || !threadId) {\n return global;\n }\n\n global = updateLocalTextSearch(global, chatId, threadId, false);\n global = replaceLocalTextSearchResults(global, chatId, threadId, undefined);\n return global;\n}\n","import { addReducer, setGlobal } from '../../../lib/teact/teactn';\n\nimport {\n exitMessageSelectMode, replaceThreadParam, updateCurrentMessageList,\n} from '../../reducers';\nimport { selectCurrentMessageList } from '../../selectors';\nimport { closeLocalTextSearch } from './localSearch';\n\naddReducer('openChat', (global, actions, payload) => {\n const {\n id, threadId = -1, type = 'thread', shouldReplaceHistory = false,\n } = payload!;\n\n const currentMessageList = selectCurrentMessageList(global);\n\n if (!currentMessageList\n || (\n currentMessageList.chatId !== id\n || currentMessageList.threadId !== threadId\n || currentMessageList.type !== type\n )) {\n global = replaceThreadParam(global, id, threadId, 'replyStack', []);\n global = exitMessageSelectMode(global);\n global = closeLocalTextSearch(global);\n\n global = {\n ...global,\n messages: {\n ...global.messages,\n contentToBeScheduled: undefined,\n },\n ...(id !== global.forwardMessages.toChatId && {\n forwardMessages: {},\n }),\n };\n\n setGlobal(global);\n }\n\n return updateCurrentMessageList(global, id, threadId, type, shouldReplaceHistory);\n});\n\naddReducer('openPreviousChat', (global) => {\n return updateCurrentMessageList(global, undefined);\n});\n\naddReducer('openChatWithInfo', (global, actions, payload) => {\n setGlobal({\n ...global,\n isChatInfoShown: true,\n });\n\n actions.openChat(payload);\n});\n\naddReducer('resetChatCreation', (global) => {\n return {\n ...global,\n chatCreation: undefined,\n };\n});\n\naddReducer('setNewChatMembersDialogState', (global, actions, payload) => {\n return {\n ...global,\n newChatMembersProgress: payload,\n };\n});\n\naddReducer('openNextChat', (global, actions, payload) => {\n const { targetIndexDelta, orderedIds } = payload;\n\n const { chatId } = selectCurrentMessageList(global) || {};\n\n if (!chatId) {\n actions.openChat({ id: orderedIds[0] });\n return;\n }\n\n const position = orderedIds.indexOf(chatId);\n\n if (position === -1) {\n return;\n }\n const nextId = orderedIds[position + targetIndexDelta];\n\n actions.openChat({ id: nextId, shouldReplaceHistory: true });\n});\n","import { addReducer, getGlobal, setGlobal } from '../../../lib/teact/teactn';\n\nimport { MAIN_THREAD_ID } from '../../../api/types';\nimport { FocusDirection } from '../../../types';\n\nimport { ANIMATION_END_DELAY, FAST_SMOOTH_MAX_DURATION } from '../../../config';\nimport { IS_TOUCH_ENV } from '../../../util/environment';\nimport {\n enterMessageSelectMode,\n toggleMessageSelection,\n exitMessageSelectMode,\n replaceThreadParam,\n updateFocusDirection,\n updateFocusedMessage,\n} from '../../reducers';\nimport {\n selectCurrentChat,\n selectViewportIds,\n selectIsRightColumnShown,\n selectCurrentMessageList,\n selectChat,\n selectThreadInfo,\n selectChatMessages,\n selectAllowedMessageActions,\n selectMessageIdsByGroupId,\n selectForwardedMessageIdsByGroupId,\n selectIsViewportNewest,\n selectReplyingToId,\n selectReplyStack,\n} from '../../selectors';\nimport { findLast } from '../../../util/iteratees';\n\nconst FOCUS_DURATION = 1500;\nconst FOCUS_NO_HIGHLIGHT_DURATION = FAST_SMOOTH_MAX_DURATION + ANIMATION_END_DELAY;\nconst POLL_RESULT_OPEN_DELAY_MS = 450;\n\nlet blurTimeout: number | undefined;\n\naddReducer('setScrollOffset', (global, actions, payload) => {\n const { chatId, threadId, scrollOffset } = payload!;\n\n return replaceThreadParam(global, chatId, threadId, 'scrollOffset', scrollOffset);\n});\n\naddReducer('setReplyingToId', (global, actions, payload) => {\n const { messageId } = payload!;\n const currentMessageList = selectCurrentMessageList(global);\n if (!currentMessageList) {\n return undefined;\n }\n const { chatId, threadId } = currentMessageList;\n\n return replaceThreadParam(global, chatId, threadId, 'replyingToId', messageId);\n});\n\naddReducer('setEditingId', (global, actions, payload) => {\n const { messageId } = payload!;\n const currentMessageList = selectCurrentMessageList(global);\n if (!currentMessageList) {\n return undefined;\n }\n\n const { chatId, threadId, type } = currentMessageList;\n const paramName = type === 'scheduled' ? 'editingScheduledId' : 'editingId';\n\n return replaceThreadParam(global, chatId, threadId, paramName, messageId);\n});\n\naddReducer('editLastMessage', (global) => {\n const { chatId, threadId } = selectCurrentMessageList(global) || {};\n if (!chatId || !threadId) {\n return undefined;\n }\n\n const chatMessages = selectChatMessages(global, chatId);\n const viewportIds = selectViewportIds(global, chatId, threadId);\n if (!chatMessages || !viewportIds) {\n return undefined;\n }\n\n const lastOwnEditableMessageId = findLast(viewportIds, (id) => {\n return Boolean(chatMessages[id] && selectAllowedMessageActions(global, chatMessages[id], threadId).canEdit);\n });\n\n if (!lastOwnEditableMessageId) {\n return undefined;\n }\n\n return replaceThreadParam(global, chatId, threadId, 'editingId', lastOwnEditableMessageId);\n});\n\naddReducer('replyToNextMessage', (global, actions, payload) => {\n const { targetIndexDelta } = payload;\n const { chatId, threadId } = selectCurrentMessageList(global) || {};\n if (!chatId || !threadId) {\n return;\n }\n\n const chatMessages = selectChatMessages(global, chatId);\n const viewportIds = selectViewportIds(global, chatId, threadId);\n if (!chatMessages || !viewportIds) {\n return;\n }\n\n const replyingToId = selectReplyingToId(global, chatId, threadId);\n const isLatest = selectIsViewportNewest(global, chatId, threadId);\n\n let messageId: number | undefined;\n\n if (!isLatest || !replyingToId) {\n if (threadId === MAIN_THREAD_ID) {\n const chat = selectChat(global, chatId);\n\n messageId = chat && chat.lastMessage ? chat.lastMessage.id : undefined;\n } else {\n const threadInfo = selectThreadInfo(global, chatId, threadId);\n\n messageId = threadInfo ? threadInfo.lastMessageId : undefined;\n }\n } else {\n const chatMessageKeys = Object.keys(chatMessages);\n const indexOfCurrent = chatMessageKeys.indexOf(replyingToId.toString());\n const newIndex = indexOfCurrent + targetIndexDelta;\n messageId = newIndex <= chatMessageKeys.length + 1 && newIndex >= 0\n ? Number(chatMessageKeys[newIndex])\n : undefined;\n }\n actions.setReplyingToId({ messageId });\n actions.focusMessage({\n chatId, threadId, messageId,\n });\n});\n\naddReducer('openMediaViewer', (global, actions, payload) => {\n const {\n chatId, threadId, messageId, avatarOwnerId, profilePhotoIndex, origin,\n } = payload!;\n\n return {\n ...global,\n mediaViewer: {\n chatId,\n threadId,\n messageId,\n avatarOwnerId,\n profilePhotoIndex,\n origin,\n },\n forwardMessages: {},\n };\n});\n\naddReducer('closeMediaViewer', (global) => {\n return {\n ...global,\n mediaViewer: {},\n };\n});\n\naddReducer('openAudioPlayer', (global, actions, payload) => {\n const {\n chatId, threadId, messageId,\n } = payload!;\n\n return {\n ...global,\n audioPlayer: {\n chatId,\n threadId,\n messageId,\n },\n };\n});\n\naddReducer('closeAudioPlayer', (global) => {\n return {\n ...global,\n audioPlayer: {},\n };\n});\n\naddReducer('openPollResults', (global, actions, payload) => {\n const { chatId, messageId } = payload!;\n\n const shouldOpenInstantly = selectIsRightColumnShown(global);\n\n if (!shouldOpenInstantly) {\n window.setTimeout(() => {\n const newGlobal = getGlobal();\n\n setGlobal({\n ...newGlobal,\n pollResults: {\n chatId,\n messageId,\n voters: {},\n },\n });\n }, POLL_RESULT_OPEN_DELAY_MS);\n } else if (chatId !== global.pollResults.chatId || messageId !== global.pollResults.messageId) {\n setGlobal({\n ...global,\n pollResults: {\n chatId,\n messageId,\n voters: {},\n },\n });\n }\n});\n\naddReducer('closePollResults', (global) => {\n setGlobal({\n ...global,\n pollResults: {},\n });\n});\n\naddReducer('focusLastMessage', (global, actions) => {\n const currentMessageList = selectCurrentMessageList(global);\n if (!currentMessageList) {\n return;\n }\n\n const { chatId, threadId } = currentMessageList;\n\n let lastMessageId: number | undefined;\n if (threadId === MAIN_THREAD_ID) {\n const chat = selectChat(global, chatId);\n\n lastMessageId = chat && chat.lastMessage ? chat.lastMessage.id : undefined;\n } else {\n const threadInfo = selectThreadInfo(global, chatId, threadId);\n\n lastMessageId = threadInfo ? threadInfo.lastMessageId : undefined;\n }\n\n if (!lastMessageId) {\n return;\n }\n\n actions.focusMessage({\n chatId, threadId, messageId: lastMessageId, noHighlight: true,\n });\n});\n\naddReducer('focusNextReply', (global, actions) => {\n const currentMessageList = selectCurrentMessageList(global);\n if (!currentMessageList) {\n return undefined;\n }\n\n const { chatId, threadId } = currentMessageList;\n\n const replyStack = selectReplyStack(global, chatId, threadId);\n\n if (!replyStack || replyStack.length === 0) {\n actions.focusLastMessage();\n } else {\n const messageId = replyStack.pop();\n\n global = replaceThreadParam(global, chatId, threadId, 'replyStack', [...replyStack]);\n\n setGlobal(global);\n\n actions.focusMessage({\n chatId,\n threadId,\n messageId,\n });\n }\n\n return undefined;\n});\n\naddReducer('focusMessage', (global, actions, payload) => {\n const {\n chatId, threadId = MAIN_THREAD_ID, messageListType = 'thread', noHighlight, groupedId, groupedChatId,\n replyMessageId,\n } = payload!;\n\n let { messageId } = payload!;\n\n if (groupedId !== undefined) {\n const ids = selectForwardedMessageIdsByGroupId(global, groupedChatId, groupedId);\n if (ids && ids.length) {\n ([messageId] = ids);\n }\n }\n\n const currentMessageList = selectCurrentMessageList(global);\n const shouldSwitchChat = !currentMessageList || (\n chatId !== currentMessageList.chatId\n || threadId !== currentMessageList.threadId\n || messageListType !== currentMessageList.type\n );\n\n if (blurTimeout) {\n clearTimeout(blurTimeout);\n blurTimeout = undefined;\n }\n blurTimeout = window.setTimeout(() => {\n let newGlobal = getGlobal();\n newGlobal = updateFocusedMessage(newGlobal);\n newGlobal = updateFocusDirection(newGlobal);\n setGlobal(newGlobal);\n }, noHighlight ? FOCUS_NO_HIGHLIGHT_DURATION : FOCUS_DURATION);\n\n global = updateFocusedMessage(global, chatId, messageId, noHighlight);\n global = updateFocusDirection(global, undefined);\n\n if (replyMessageId) {\n const replyStack = selectReplyStack(global, chatId, threadId) || [];\n global = replaceThreadParam(global, chatId, threadId, 'replyStack', [...replyStack, replyMessageId]);\n }\n\n if (shouldSwitchChat) {\n global = updateFocusDirection(global, FocusDirection.Static);\n }\n\n const viewportIds = selectViewportIds(global, chatId, threadId);\n if (viewportIds && viewportIds.includes(messageId)) {\n setGlobal(global);\n actions.openChat({ id: chatId, threadId });\n return undefined;\n }\n\n if (shouldSwitchChat) {\n global = replaceThreadParam(global, chatId, threadId, 'viewportIds', undefined);\n }\n\n global = replaceThreadParam(global, chatId, threadId, 'outlyingIds', undefined);\n\n if (viewportIds && !shouldSwitchChat) {\n const direction = messageId > viewportIds[0] ? FocusDirection.Down : FocusDirection.Up;\n global = updateFocusDirection(global, direction);\n }\n\n setGlobal(global);\n\n actions.openChat({ id: chatId, threadId });\n actions.loadViewportMessages();\n return undefined;\n});\n\naddReducer('openForwardMenu', (global, actions, payload) => {\n const { fromChatId, messageIds, groupedId } = payload!;\n let groupedMessageIds;\n if (groupedId) {\n groupedMessageIds = selectMessageIdsByGroupId(global, fromChatId, groupedId);\n }\n return {\n ...global,\n forwardMessages: {\n fromChatId,\n messageIds: groupedMessageIds || messageIds,\n isModalShown: true,\n },\n };\n});\n\naddReducer('exitForwardMode', (global) => {\n setGlobal({\n ...global,\n forwardMessages: {},\n });\n});\n\naddReducer('setForwardChatId', (global, actions, payload) => {\n const { id } = payload!;\n\n setGlobal({\n ...global,\n forwardMessages: {\n ...global.forwardMessages,\n toChatId: id,\n isModalShown: false,\n },\n });\n\n actions.openChat({ id });\n actions.closeMediaViewer();\n actions.exitMessageSelectMode();\n});\n\naddReducer('openForwardMenuForSelectedMessages', (global, actions) => {\n if (!global.selectedMessages) {\n return;\n }\n\n const { chatId: fromChatId, messageIds } = global.selectedMessages;\n\n actions.openForwardMenu({ fromChatId, messageIds });\n});\n\naddReducer('enterMessageSelectMode', (global, actions, payload) => {\n const { messageId } = payload || {};\n const openChat = selectCurrentChat(global);\n if (!openChat) {\n return global;\n }\n\n return enterMessageSelectMode(global, openChat.id, messageId);\n});\n\naddReducer('toggleMessageSelection', (global, actions, payload) => {\n const {\n messageId,\n groupedId,\n childMessageIds,\n withShift,\n } = payload!;\n const currentMessageList = selectCurrentMessageList(global);\n if (!currentMessageList) {\n return;\n }\n\n const { chatId, threadId, type: messageListType } = currentMessageList;\n\n global = toggleMessageSelection(\n global, chatId, threadId, messageListType, messageId, groupedId, childMessageIds, withShift,\n );\n\n setGlobal(global);\n\n if (global.shouldShowContextMenuHint) {\n actions.disableContextMenuHint();\n actions.showNotification({\n // eslint-disable-next-line max-len\n message: `To **edit** or **reply**, close this menu. Then ${IS_TOUCH_ENV ? 'long tap' : 'right click'} on a message.`,\n });\n }\n});\n\naddReducer('disableContextMenuHint', (global) => {\n if (!global.shouldShowContextMenuHint) {\n return undefined;\n }\n\n return {\n ...global,\n shouldShowContextMenuHint: false,\n };\n});\n\naddReducer('exitMessageSelectMode', exitMessageSelectMode);\n\naddReducer('openPollModal', (global) => {\n return {\n ...global,\n isPollModalOpen: true,\n };\n});\n\naddReducer('closePollModal', (global) => {\n return {\n ...global,\n isPollModalOpen: false,\n };\n});\n","import { addReducer } from '../../../lib/teact/teactn';\n\nimport { updateGlobalSearch, updateGlobalSearchContent } from '../../reducers';\n\nconst MAX_RECENTLY_FOUND_IDS = 10;\n\naddReducer('setGlobalSearchQuery', (global, actions, payload) => {\n const { query } = payload!;\n const { chatId } = global.globalSearch;\n\n return updateGlobalSearch(global, {\n globalResults: {},\n localResults: {},\n resultsByType: undefined,\n ...(query ? { fetchingStatus: { chats: !chatId, messages: true } } : { fetchingStatus: undefined }),\n query,\n });\n});\n\naddReducer('addRecentlyFoundChatId', (global, actions, payload) => {\n const { id } = payload!;\n const { recentlyFoundChatIds } = global.globalSearch;\n\n if (!recentlyFoundChatIds) {\n return updateGlobalSearch(global, { recentlyFoundChatIds: [id] });\n }\n\n const newRecentIds = recentlyFoundChatIds.filter((chatId) => chatId !== id);\n newRecentIds.unshift(id);\n if (newRecentIds.length > MAX_RECENTLY_FOUND_IDS) {\n newRecentIds.pop();\n }\n\n return updateGlobalSearch(global, { recentlyFoundChatIds: newRecentIds });\n});\n\naddReducer('clearRecentlyFoundChats', (global) => {\n return updateGlobalSearch(global, { recentlyFoundChatIds: undefined });\n});\n\naddReducer('setGlobalSearchContent', (global, actions, payload) => {\n const { content } = payload!;\n\n return updateGlobalSearchContent(global, content);\n});\n\naddReducer('setGlobalSearchChatId', (global, actions, payload) => {\n const { id } = payload!;\n\n return updateGlobalSearch(global, { chatId: id, query: undefined, resultsByType: undefined });\n});\n","import { addReducer } from '../../../lib/teact/teactn';\n\naddReducer('setStickerSearchQuery', (global, actions, payload) => {\n const { query } = payload!;\n\n return {\n ...global,\n stickers: {\n ...global.stickers,\n search: {\n query,\n resultIds: undefined,\n },\n },\n };\n});\n\naddReducer('setGifSearchQuery', (global, actions, payload) => {\n const { query } = payload!;\n\n return {\n ...global,\n gifs: {\n ...global.gifs,\n search: {\n query,\n offsetId: undefined,\n results: undefined,\n },\n },\n };\n});\n","import { addReducer } from '../../../lib/teact/teactn';\n\nimport { GlobalState } from '../../../global/types';\n\nimport { updateSelectedUserId, updateUserSearch } from '../../reducers';\n\naddReducer('openUserInfo', (global, actions, payload) => {\n const { id } = payload!;\n\n actions.openChat({ id });\n});\n\nconst clearSelectedUserId = (global: GlobalState) => updateSelectedUserId(global, undefined);\n\naddReducer('openChat', clearSelectedUserId);\n\naddReducer('setUserSearchQuery', (global, actions, payload) => {\n const { query } = payload!;\n\n return updateUserSearch(global, {\n globalUserIds: undefined,\n localUserIds: undefined,\n fetchingStatus: Boolean(query),\n query,\n });\n});\n","import { addReducer } from '../../../lib/teact/teactn';\n\nimport { GlobalState } from '../../../global/types';\n\nimport { IS_SINGLE_COLUMN_LAYOUT, IS_TABLET_COLUMN_LAYOUT } from '../../../util/environment';\nimport getReadableErrorText from '../../../util/getReadableErrorText';\nimport { selectCurrentMessageList } from '../../selectors';\nimport { ApiError } from '../../../api/types';\n\nconst MAX_STORED_EMOJIS = 18; // Represents two rows of recent emojis\n\naddReducer('toggleChatInfo', (global) => {\n return {\n ...global,\n isChatInfoShown: !global.isChatInfoShown,\n };\n});\n\naddReducer('toggleManagement', (global): GlobalState | undefined => {\n const { chatId } = selectCurrentMessageList(global) || {};\n\n if (!chatId) {\n return undefined;\n }\n\n return {\n ...global,\n management: {\n byChatId: {\n ...global.management.byChatId,\n [chatId]: {\n ...global.management.byChatId[chatId],\n isActive: !(global.management.byChatId[chatId] || {}).isActive,\n },\n },\n },\n };\n});\n\naddReducer('closeManagement', (global): GlobalState | undefined => {\n const { chatId } = selectCurrentMessageList(global) || {};\n\n if (!chatId) {\n return undefined;\n }\n\n return {\n ...global,\n management: {\n byChatId: {\n ...global.management.byChatId,\n [chatId]: {\n ...global.management.byChatId[chatId],\n isActive: false,\n },\n },\n },\n };\n});\n\naddReducer('openChat', (global) => {\n if (!IS_SINGLE_COLUMN_LAYOUT && !IS_TABLET_COLUMN_LAYOUT) {\n return undefined;\n }\n\n return {\n ...global,\n isLeftColumnShown: global.messages.messageLists.length === 0,\n };\n});\n\naddReducer('toggleLeftColumn', (global) => {\n return {\n ...global,\n isLeftColumnShown: !global.isLeftColumnShown,\n };\n});\n\naddReducer('addRecentEmoji', (global, action, payload) => {\n const { emoji } = payload!;\n const { recentEmojis } = global;\n if (!recentEmojis) {\n return {\n ...global,\n recentEmojis: [emoji],\n };\n }\n\n const newEmojis = recentEmojis.filter((e) => e !== emoji);\n newEmojis.unshift(emoji);\n if (newEmojis.length > MAX_STORED_EMOJIS) {\n newEmojis.pop();\n }\n\n return {\n ...global,\n recentEmojis: newEmojis,\n };\n});\n\naddReducer('addRecentSticker', (global, action, payload) => {\n const { sticker } = payload!;\n const { recent } = global.stickers;\n if (!recent) {\n return {\n ...global,\n stickers: {\n ...global.stickers,\n recent: {\n hash: 0,\n stickers: [sticker],\n },\n },\n };\n }\n\n const newStickers = recent.stickers.filter((s) => s.id !== sticker.id);\n newStickers.unshift(sticker);\n\n return {\n ...global,\n stickers: {\n ...global.stickers,\n recent: {\n ...recent,\n stickers: newStickers,\n },\n },\n };\n});\n\naddReducer('showNotification', (global, actions, payload) => {\n const notification = payload!;\n\n const newNotifications = [...global.notifications];\n const existingNotificationIndex = newNotifications.findIndex((n) => n.message === notification.message);\n if (existingNotificationIndex !== -1) {\n newNotifications.splice(existingNotificationIndex, 1);\n }\n\n newNotifications.push(notification);\n\n return {\n ...global,\n notifications: newNotifications,\n };\n});\n\naddReducer('dismissNotification', (global) => {\n const newNotifications = [...global.notifications];\n\n newNotifications.pop();\n\n return {\n ...global,\n notifications: newNotifications,\n };\n});\n\naddReducer('showDialog', (global, actions, payload) => {\n const { data } = payload!;\n\n // Filter out errors that we don't want to show to the user\n if ('message' in data && data.hasErrorKey && !getReadableErrorText(data)) {\n return global;\n }\n\n const newDialogs = [...global.dialogs];\n if ('message' in data) {\n const existingErrorIndex = newDialogs.findIndex((err) => (err as ApiError).message === data.message);\n if (existingErrorIndex !== -1) {\n newDialogs.splice(existingErrorIndex, 1);\n }\n }\n\n newDialogs.push(data);\n\n return {\n ...global,\n dialogs: newDialogs,\n };\n});\n\naddReducer('dismissDialog', (global) => {\n const newDialogs = [...global.dialogs];\n\n newDialogs.pop();\n\n return {\n ...global,\n dialogs: newDialogs,\n };\n});\n\naddReducer('toggleSafeLinkModal', (global, actions, payload) => {\n const { url: safeLinkModalUrl } = payload;\n\n return {\n ...global,\n safeLinkModalUrl,\n };\n});\n\naddReducer('openHistoryCalendar', (global, actions, payload) => {\n const { selectedAt } = payload;\n\n return {\n ...global,\n historyCalendarSelectedAt: selectedAt,\n };\n});\n\naddReducer('closeHistoryCalendar', (global) => {\n return {\n ...global,\n historyCalendarSelectedAt: undefined,\n };\n});\n","import { addReducer } from '../../../lib/teact/teactn';\nimport {\n clearPayment, closeInvoice,\n} from '../../reducers';\n\naddReducer('openPaymentModal', (global, actions, payload) => {\n const { messageId } = payload;\n return {\n ...global,\n payment: {\n ...global.payment,\n messageId,\n isPaymentModalOpen: true,\n },\n };\n});\n\naddReducer('closePaymentModal', (global) => {\n const newGlobal = clearPayment(global);\n return closeInvoice(newGlobal);\n});\n","import {\n addReducer, getDispatch, getGlobal, setGlobal,\n} from '../../../lib/teact/teactn';\n\nimport {\n ApiChat, ApiUser, ApiChatFolder, MAIN_THREAD_ID,\n} from '../../../api/types';\nimport { NewChatMembersProgress, ChatCreationProgress, ManagementProgress } from '../../../types';\nimport { GlobalActions } from '../../../global/types';\n\nimport {\n ARCHIVED_FOLDER_ID,\n TOP_CHAT_MESSAGES_PRELOAD_LIMIT,\n CHAT_LIST_LOAD_SLICE,\n RE_TME_INVITE_LINK,\n RE_TME_LINK,\n TIPS_USERNAME,\n LOCALIZED_TIPS,\n} from '../../../config';\nimport { callApi } from '../../../api/gramjs';\nimport {\n addChats,\n addUsers,\n replaceThreadParam,\n updateChatListIds,\n updateChats,\n updateChat,\n updateChatListSecondaryInfo,\n updateManagementProgress,\n} from '../../reducers';\nimport {\n selectChat,\n selectCurrentChat,\n selectUser,\n selectChatListType,\n selectIsChatPinned,\n selectChatFolder,\n selectSupportChat,\n selectChatByUsername,\n selectThreadTopMessageId,\n selectCurrentMessageList,\n} from '../../selectors';\nimport { buildCollectionByKey } from '../../../util/iteratees';\nimport { debounce, pause, throttle } from '../../../util/schedulers';\nimport {\n isChatSummaryOnly, isChatArchived, prepareChatList, isChatBasicGroup,\n} from '../../helpers';\n\nconst TOP_CHATS_PRELOAD_PAUSE = 100;\n// We expect this ID does not exist\nconst TMP_CHAT_ID = -1;\n\nconst runThrottledForLoadChats = throttle((cb) => cb(), 1000, true);\nconst runThrottledForLoadTopChats = throttle((cb) => cb(), 3000, true);\nconst runDebouncedForLoadFullChat = debounce((cb) => cb(), 500, false, true);\n\naddReducer('preloadTopChatMessages', (global, actions) => {\n (async () => {\n const preloadedChatIds: number[] = [];\n\n for (let i = 0; i < TOP_CHAT_MESSAGES_PRELOAD_LIMIT; i++) {\n await pause(TOP_CHATS_PRELOAD_PAUSE);\n\n const {\n byId,\n listIds: { active: listIds },\n orderedPinnedIds: { active: orderedPinnedIds },\n } = getGlobal().chats;\n if (!listIds) {\n return;\n }\n\n const { chatId: currentChatId } = selectCurrentMessageList(global) || {};\n const { pinnedChats, otherChats } = prepareChatList(byId, listIds, orderedPinnedIds);\n const topChats = [...pinnedChats, ...otherChats];\n const chatToPreload = topChats.find(({ id }) => id !== currentChatId && !preloadedChatIds.includes(id));\n if (!chatToPreload) {\n return;\n }\n\n preloadedChatIds.push(chatToPreload.id);\n\n actions.loadViewportMessages({ chatId: chatToPreload.id, threadId: MAIN_THREAD_ID });\n }\n })();\n});\n\naddReducer('openChat', (global, actions, payload) => {\n const { id, threadId } = payload!;\n const { currentUserId } = global;\n const chat = selectChat(global, id);\n\n if (chat && chat.hasUnreadMark) {\n actions.toggleChatUnread({ id });\n }\n\n if (!chat) {\n if (id === currentUserId) {\n void callApi('fetchChat', { type: 'self' });\n } else {\n const user = selectUser(global, id);\n if (user) {\n void callApi('fetchChat', { type: 'user', user });\n }\n }\n } else if (isChatSummaryOnly(chat) && !chat.isMin) {\n actions.requestChatUpdate({ chatId: id });\n }\n\n if (threadId !== MAIN_THREAD_ID) {\n const topMessageId = selectThreadTopMessageId(global, id, threadId);\n if (!topMessageId) {\n actions.requestThreadInfoUpdate({ chatId: id, threadId });\n }\n }\n});\n\naddReducer('openSupportChat', (global, actions) => {\n const chat = selectSupportChat(global);\n\n actions.openChat({ id: chat ? chat.id : TMP_CHAT_ID });\n\n if (chat) {\n return;\n }\n\n (async () => {\n const result = await callApi('fetchChat', { type: 'support' });\n if (result) {\n actions.openChat({ id: result.chatId });\n }\n })();\n});\n\naddReducer('openTipsChat', (global, actions, payload) => {\n const { langCode } = payload;\n\n const usernamePostfix = langCode === 'pt-br'\n ? 'BR'\n : LOCALIZED_TIPS.includes(langCode) ? (langCode as string).toUpperCase() : '';\n\n actions.openChatByUsername({ username: `${TIPS_USERNAME}${usernamePostfix}` });\n});\n\naddReducer('loadMoreChats', (global, actions, payload) => {\n const { listType = 'active' } = payload!;\n const listIds = global.chats.listIds[listType as ('active' | 'archived')];\n const isFullyLoaded = global.chats.isFullyLoaded[listType as ('active' | 'archived')];\n\n if (isFullyLoaded) {\n return;\n }\n\n const oldestChat = listIds\n ? listIds\n .map((id) => global.chats.byId[id])\n .filter((chat) => Boolean(chat && chat.lastMessage) && !selectIsChatPinned(global, chat.id))\n .sort((chat1, chat2) => (chat1.lastMessage!.date - chat2.lastMessage!.date))[0]\n : undefined;\n\n if (oldestChat) {\n runThrottledForLoadChats(() => loadChats(listType, oldestChat.id, oldestChat.lastMessage!.date));\n } else {\n runThrottledForLoadChats(() => loadChats(listType));\n }\n});\n\naddReducer('loadFullChat', (global, actions, payload) => {\n const { chatId, force } = payload!;\n const chat = selectChat(global, chatId);\n if (!chat) {\n return;\n }\n\n if (force) {\n loadFullChat(chat);\n } else {\n runDebouncedForLoadFullChat(() => loadFullChat(chat));\n }\n});\n\naddReducer('loadTopChats', () => {\n runThrottledForLoadTopChats(() => loadChats('active'));\n});\n\naddReducer('requestChatUpdate', (global, actions, payload) => {\n const { serverTimeOffset } = global;\n const { chatId } = payload!;\n const chat = selectChat(global, chatId);\n if (!chat) {\n return;\n }\n\n void callApi('requestChatUpdate', {\n chat,\n serverTimeOffset,\n });\n});\n\naddReducer('updateChatMutedState', (global, actions, payload) => {\n const { serverTimeOffset } = global;\n const { chatId, isMuted } = payload!;\n const chat = selectChat(global, chatId);\n if (!chat) {\n return;\n }\n\n setGlobal(updateChat(global, chatId, { isMuted }));\n void callApi('updateChatMutedState', { chat, isMuted, serverTimeOffset });\n});\n\naddReducer('createChannel', (global, actions, payload) => {\n const {\n title, about, photo, memberIds,\n } = payload!;\n\n const members = (memberIds as number[])\n .map((id: number) => selectUser(global, id))\n .filter<ApiUser>(Boolean as any);\n\n void createChannel(title, members, about, photo);\n});\n\naddReducer('joinChannel', (global, actions, payload) => {\n const { chatId } = payload!;\n const chat = selectChat(global, chatId);\n if (!chat) {\n return;\n }\n\n const { id: channelId, accessHash } = chat;\n\n if (channelId && accessHash) {\n void callApi('joinChannel', { channelId, accessHash });\n }\n});\n\naddReducer('deleteChatUser', (global, actions, payload) => {\n (async () => {\n const { chatId, userId } : {chatId: number; userId: number} = payload!;\n const chat = selectChat(global, chatId);\n const user = selectUser(global, userId);\n if (!chat || !user) {\n return;\n }\n await callApi('deleteChatUser', { chat, user });\n\n const activeChat = selectCurrentMessageList(global);\n if (activeChat && activeChat.chatId === chatId && global.currentUserId === userId) {\n actions.openChat({ id: undefined });\n }\n })();\n});\n\naddReducer('deleteChat', (global, actions, payload) => {\n (async () => {\n const { chatId } : {chatId: number } = payload!;\n const chat = selectChat(global, chatId);\n if (!chat) {\n return;\n }\n await callApi('deleteChat', { chatId: chat.id });\n\n const activeChat = selectCurrentMessageList(global);\n if (activeChat && activeChat.chatId === chatId) {\n actions.openChat({ id: undefined });\n }\n })();\n});\n\naddReducer('leaveChannel', (global, actions, payload) => {\n (async () => {\n const { chatId } = payload!;\n const chat = selectChat(global, chatId);\n if (!chat) {\n return;\n }\n\n const { id: channelId, accessHash } = chat;\n\n if (channelId && accessHash) {\n await callApi('leaveChannel', { channelId, accessHash });\n }\n\n const activeChannel = selectCurrentMessageList(global);\n if (activeChannel && activeChannel.chatId === chatId) {\n actions.openChat({ id: undefined });\n }\n })();\n});\n\naddReducer('deleteChannel', (global, actions, payload) => {\n (async () => {\n const { chatId } = payload!;\n const chat = selectChat(global, chatId);\n if (!chat) {\n return;\n }\n\n const { id: channelId, accessHash } = chat;\n\n if (channelId && accessHash) {\n await callApi('deleteChannel', { channelId, accessHash });\n }\n\n const activeChannel = selectCurrentMessageList(global);\n if (activeChannel && activeChannel.chatId === chatId) {\n actions.openChat({ id: undefined });\n }\n })();\n});\n\naddReducer('createGroupChat', (global, actions, payload) => {\n const { title, memberIds, photo } = payload!;\n const members = (memberIds as number[])\n .map((id: number) => selectUser(global, id))\n .filter<ApiUser>(Boolean as any);\n\n void createGroupChat(title, members, photo);\n});\n\naddReducer('toggleChatPinned', (global, actions, payload) => {\n const { id, folderId } = payload!;\n const chat = selectChat(global, id);\n if (!chat) {\n return;\n }\n\n if (folderId) {\n const folder = selectChatFolder(global, folderId);\n if (folder) {\n const shouldBePinned = !selectIsChatPinned(global, id, folderId);\n\n const { pinnedChatIds, includedChatIds } = folder;\n const newPinnedIds = shouldBePinned\n ? [id, ...(pinnedChatIds || [])]\n : (pinnedChatIds || []).filter((pinnedId) => pinnedId !== id);\n\n // With both Pin and Unpin we need to re-add a user to the included group\n const newIncludedChatIds = [id, ...includedChatIds];\n\n void callApi('editChatFolder', {\n id: folderId,\n folderUpdate: {\n ...folder,\n pinnedChatIds: newPinnedIds,\n includedChatIds: newIncludedChatIds,\n },\n });\n }\n } else {\n const listType = selectChatListType(global, id);\n const isPinned = selectIsChatPinned(global, id, listType === 'archived' ? ARCHIVED_FOLDER_ID : undefined);\n void callApi('toggleChatPinned', { chat, shouldBePinned: !isPinned });\n }\n});\n\naddReducer('toggleChatArchived', (global, actions, payload) => {\n const { id } = payload!;\n const chat = selectChat(global, id);\n if (chat) {\n void callApi('toggleChatArchived', {\n chat,\n folderId: isChatArchived(chat) ? 0 : ARCHIVED_FOLDER_ID,\n });\n }\n});\n\naddReducer('loadChatFolders', () => {\n void loadChatFolders();\n});\n\naddReducer('loadRecommendedChatFolders', () => {\n void loadRecommendedChatFolders();\n});\n\naddReducer('editChatFolder', (global, actions, payload) => {\n const { id, folderUpdate } = payload!;\n const folder = selectChatFolder(global, id);\n\n if (folder) {\n void callApi('editChatFolder', {\n id,\n folderUpdate: {\n id,\n emoticon: folder.emoticon,\n pinnedChatIds: folder.pinnedChatIds,\n ...folderUpdate,\n },\n });\n }\n});\n\naddReducer('addChatFolder', (global, actions, payload) => {\n const { folder } = payload!;\n const { orderedIds } = global.chatFolders;\n const maxId = orderedIds && orderedIds.length ? Math.max.apply(Math.max, orderedIds) : ARCHIVED_FOLDER_ID;\n\n void createChatFolder(folder, maxId);\n});\n\naddReducer('deleteChatFolder', (global, actions, payload) => {\n const { id } = payload!;\n const folder = selectChatFolder(global, id);\n\n if (folder) {\n void deleteChatFolder(id);\n }\n});\n\naddReducer('toggleChatUnread', (global, actions, payload) => {\n const { id } = payload!;\n const { serverTimeOffset } = global;\n const chat = selectChat(global, id);\n if (chat) {\n if (chat.unreadCount) {\n void callApi('markMessageListRead', { serverTimeOffset, chat, threadId: MAIN_THREAD_ID });\n } else {\n void callApi('toggleDialogUnread', {\n chat,\n hasUnreadMark: !chat.hasUnreadMark,\n });\n }\n }\n});\n\naddReducer('openTelegramLink', (global, actions, payload) => {\n const { url } = payload!;\n let match = RE_TME_INVITE_LINK.exec(url);\n\n if (match) {\n const hash = match[1];\n\n (async () => {\n const result = await callApi('openChatByInvite', hash);\n if (!result) {\n return;\n }\n\n actions.openChat({ id: result.chatId });\n })();\n } else {\n match = RE_TME_LINK.exec(url)!;\n\n const username = match[1];\n const chatOrChannelPostId = match[2] ? Number(match[2]) : undefined;\n const messageId = match[3] ? Number(match[3]) : undefined;\n\n // Open message in private chat\n if (username === 'c' && chatOrChannelPostId && messageId) {\n actions.focusMessage({ chatId: -chatOrChannelPostId, messageId });\n } else {\n void openChatByUsername(actions, username, chatOrChannelPostId);\n }\n }\n});\n\naddReducer('acceptInviteConfirmation', (global, actions, payload) => {\n const { hash } = payload!;\n (async () => {\n const result = await callApi('importChatInvite', { hash });\n if (!result) {\n return;\n }\n\n actions.openChat({ id: result.id });\n })();\n});\n\naddReducer('openChatByUsername', (global, actions, payload) => {\n const { username } = payload!;\n\n void openChatByUsername(actions, username);\n});\n\naddReducer('togglePreHistoryHidden', (global, actions, payload) => {\n const { chatId, isEnabled } = payload!;\n let chat = selectChat(global, chatId);\n\n if (!chat) {\n return;\n }\n\n (async () => {\n if (isChatBasicGroup(chat)) {\n chat = await callApi('migrateChat', chat);\n\n if (!chat) {\n return;\n }\n\n actions.openChat({ id: chat.id });\n }\n\n void callApi('togglePreHistoryHidden', { chat, isEnabled });\n })();\n});\n\naddReducer('updateChatDefaultBannedRights', (global, actions, payload) => {\n const { chatId, bannedRights } = payload!;\n const chat = selectChat(global, chatId);\n\n if (!chat) {\n return;\n }\n\n void callApi('updateChatDefaultBannedRights', { chat, bannedRights });\n});\n\naddReducer('updateChatMemberBannedRights', (global, actions, payload) => {\n const { chatId, userId, bannedRights } = payload!;\n let chat = selectChat(global, chatId);\n const user = selectUser(global, userId);\n\n if (!chat || !user) {\n return;\n }\n\n (async () => {\n if (isChatBasicGroup(chat)) {\n chat = await callApi('migrateChat', chat);\n\n if (!chat) {\n return;\n }\n\n actions.openChat({ id: chat.id });\n }\n\n await callApi('updateChatMemberBannedRights', { chat, user, bannedRights });\n\n const newGlobal = getGlobal();\n const chatAfterUpdate = selectChat(newGlobal, chatId);\n\n if (!chatAfterUpdate || !chatAfterUpdate.fullInfo) {\n return;\n }\n\n const { members, kickedMembers } = chatAfterUpdate.fullInfo;\n\n const isBanned = !!bannedRights.viewMessages;\n const isUnblocked = !Object.keys(bannedRights).length;\n\n setGlobal(updateChat(newGlobal, chatId, {\n fullInfo: {\n ...chatAfterUpdate.fullInfo,\n ...(members && isBanned && {\n members: members.filter((m) => m.userId !== userId),\n }),\n ...(members && !isBanned && {\n members: members.map((m) => (\n m.userId === userId\n ? { ...m, bannedRights }\n : m\n )),\n }),\n ...(isUnblocked && kickedMembers && {\n kickedMembers: kickedMembers.filter((m) => m.userId !== userId),\n }),\n },\n }));\n })();\n});\n\naddReducer('updateChatAdmin', (global, actions, payload) => {\n const {\n chatId, userId, adminRights, customTitle,\n } = payload!;\n let chat = selectChat(global, chatId);\n const user = selectUser(global, userId);\n\n if (!chat || !user) {\n return;\n }\n\n (async () => {\n if (isChatBasicGroup(chat)) {\n chat = await callApi('migrateChat', chat);\n\n if (!chat) {\n return;\n }\n\n actions.openChat({ id: chat.id });\n }\n\n await callApi('updateChatAdmin', {\n chat, user, adminRights, customTitle,\n });\n\n const newGlobal = getGlobal();\n const chatAfterUpdate = selectChat(newGlobal, chatId);\n\n if (!chatAfterUpdate || !chatAfterUpdate.fullInfo) {\n return;\n }\n\n const { adminMembers } = chatAfterUpdate.fullInfo;\n\n const isDismissed = !Object.keys(adminRights).length;\n\n setGlobal(updateChat(newGlobal, chatId, {\n fullInfo: {\n ...chatAfterUpdate.fullInfo,\n ...(adminMembers && isDismissed && {\n adminMembers: adminMembers.filter((m) => m.userId !== userId),\n }),\n ...(adminMembers && !isDismissed && {\n adminMembers: adminMembers.map((m) => (\n m.userId === userId\n ? { ...m, adminRights, customTitle }\n : m\n )),\n }),\n },\n }));\n })();\n});\n\naddReducer('updateChat', (global, actions, payload) => {\n const {\n chatId, title, about, photo,\n } = payload!;\n\n const chat = selectChat(global, chatId);\n if (!chat) {\n return;\n }\n\n (async () => {\n setGlobal(updateManagementProgress(getGlobal(), ManagementProgress.InProgress));\n\n await Promise.all([\n chat.title !== title\n ? callApi('updateChatTitle', chat, title)\n : undefined,\n chat.fullInfo && chat.fullInfo.about !== about\n ? callApi('updateChatAbout', chat, about)\n : undefined,\n photo\n ? callApi('editChatPhoto', { chatId, accessHash: chat.accessHash, photo })\n : undefined,\n ]);\n\n setGlobal(updateManagementProgress(getGlobal(), ManagementProgress.Complete));\n })();\n});\n\naddReducer('toggleSignatures', (global, actions, payload) => {\n const { chatId, isEnabled } = payload!;\n const chat = selectChat(global, chatId);\n\n if (!chat) {\n return;\n }\n\n void callApi('toggleSignatures', { chat, isEnabled });\n});\n\naddReducer('loadGroupsForDiscussion', () => {\n (async () => {\n const groups = await callApi('fetchGroupsForDiscussion');\n if (!groups) {\n return;\n }\n\n const addedById = groups.reduce((result, group) => {\n if (group) {\n result[group.id] = group;\n }\n\n return result;\n }, {} as Record<number, ApiChat>);\n\n const global = addChats(getGlobal(), addedById);\n setGlobal({\n ...global,\n chats: {\n ...global.chats,\n forDiscussionIds: Object.keys(addedById).map(Number),\n },\n });\n })();\n});\n\naddReducer('linkDiscussionGroup', (global, actions, payload) => {\n const { channelId, chatId } = payload!;\n\n const channel = selectChat(global, channelId);\n let chat = selectChat(global, chatId);\n if (!channel || !chat) {\n return;\n }\n\n (async () => {\n if (isChatBasicGroup(chat)) {\n chat = await callApi('migrateChat', chat);\n\n if (!chat) {\n return;\n }\n\n actions.openChat({ id: chat.id });\n }\n\n let { fullInfo } = chat;\n if (!fullInfo) {\n const fullChat = await callApi('fetchFullChat', chat);\n if (!fullChat) {\n return;\n }\n\n fullInfo = fullChat.fullInfo;\n }\n\n if (fullInfo.isPreHistoryHidden) {\n await callApi('togglePreHistoryHidden', { chat, isEnabled: false });\n }\n\n void callApi('setDiscussionGroup', { channel, chat });\n })();\n});\n\naddReducer('unlinkDiscussionGroup', (global, actions, payload) => {\n const { channelId } = payload!;\n\n const channel = selectChat(global, channelId);\n if (!channel) {\n return;\n }\n\n let chat: ApiChat | undefined;\n if (channel.fullInfo && channel.fullInfo.linkedChatId) {\n chat = selectChat(global, channel.fullInfo.linkedChatId);\n }\n\n (async () => {\n await callApi('setDiscussionGroup', { channel });\n if (chat) {\n loadFullChat(chat);\n }\n })();\n});\n\n\naddReducer('setActiveChatFolder', (global, actions, payload) => {\n return {\n ...global,\n chatFolders: {\n ...global.chatFolders,\n activeChatFolder: payload,\n },\n };\n});\n\naddReducer('loadMoreMembers', (global) => {\n (async () => {\n const { chatId } = selectCurrentMessageList(global) || {};\n const chat = chatId ? selectChat(global, chatId) : undefined;\n if (!chat || isChatBasicGroup(chat)) {\n return;\n }\n\n const offset = (chat.fullInfo && chat.fullInfo.members && chat.fullInfo.members.length) || undefined;\n const result = await callApi('fetchMembers', chat.id, chat.accessHash!, 'recent', offset);\n if (!result) {\n return;\n }\n\n const { members, users } = result;\n if (!members || !members.length) {\n return;\n }\n\n global = getGlobal();\n global = addUsers(global, buildCollectionByKey(users, 'id'));\n global = updateChat(global, chat.id, {\n fullInfo: {\n ...chat.fullInfo,\n members: [\n ...((chat.fullInfo || {}).members || []),\n ...(members || []),\n ],\n },\n });\n setGlobal(global);\n })();\n});\n\naddReducer('addChatMembers', (global, actions, payload) => {\n const { chatId, memberIds } = payload;\n const chat = selectChat(global, chatId);\n const users = (memberIds as number[]).map((userId) => selectUser(global, userId)).filter<ApiUser>(Boolean as any);\n\n if (!chat || !users.length) {\n return;\n }\n\n actions.setNewChatMembersDialogState(NewChatMembersProgress.Loading);\n (async () => {\n await callApi('addChatMembers', chat, users);\n actions.setNewChatMembersDialogState(NewChatMembersProgress.Closed);\n loadFullChat(chat);\n })();\n});\n\naddReducer('deleteChatMember', (global, actions, payload) => {\n const { chatId, userId } = payload;\n const chat = selectChat(global, chatId);\n const user = selectUser(global, userId);\n\n if (!chat || !user) {\n return;\n }\n\n (async () => {\n await callApi('deleteChatMember', chat, user);\n loadFullChat(chat);\n })();\n});\n\nasync function loadChats(listType: 'active' | 'archived', offsetId?: number, offsetDate?: number) {\n const result = await callApi('fetchChats', {\n limit: CHAT_LIST_LOAD_SLICE,\n offsetDate,\n archived: listType === 'archived',\n withPinned: getGlobal().chats.orderedPinnedIds[listType] === undefined,\n serverTimeOffset: getGlobal().serverTimeOffset,\n });\n\n if (!result) {\n return;\n }\n\n const { chatIds } = result;\n\n if (chatIds.length > 0 && chatIds[0] === offsetId) {\n chatIds.shift();\n }\n\n let global = getGlobal();\n\n global = addUsers(global, buildCollectionByKey(result.users, 'id'));\n global = updateChats(global, buildCollectionByKey(result.chats, 'id'));\n global = updateChatListIds(global, listType, chatIds);\n global = updateChatListSecondaryInfo(global, listType, result);\n\n Object.keys(result.draftsById).map(Number).forEach((chatId) => {\n global = replaceThreadParam(\n global, chatId, MAIN_THREAD_ID, 'draft', result.draftsById[chatId],\n );\n });\n\n Object.keys(result.replyingToById).map(Number).forEach((chatId) => {\n global = replaceThreadParam(\n global, chatId, MAIN_THREAD_ID, 'replyingToId', result.replyingToById[chatId],\n );\n });\n\n\n if (chatIds.length === 0 && !global.chats.isFullyLoaded[listType]) {\n global = {\n ...global,\n chats: {\n ...global.chats,\n isFullyLoaded: {\n ...global.chats.isFullyLoaded,\n [listType]: true,\n },\n },\n };\n }\n\n setGlobal(global);\n}\n\nasync function loadFullChat(chat: ApiChat) {\n const result = await callApi('fetchFullChat', chat);\n if (!result) {\n return;\n }\n\n const { users, fullInfo } = result;\n\n let global = getGlobal();\n if (users) {\n global = addUsers(global, buildCollectionByKey(users, 'id'));\n }\n global = updateChat(global, chat.id, { fullInfo });\n\n setGlobal(global);\n}\n\nasync function createChannel(title: string, users: ApiUser[], about?: string, photo?: File) {\n setGlobal({\n ...getGlobal(),\n chatCreation: {\n progress: ChatCreationProgress.InProgress,\n },\n });\n\n const createdChannel = await callApi('createChannel', { title, about, users });\n if (!createdChannel) {\n return;\n }\n\n const { id: channelId, accessHash } = createdChannel;\n\n let global = getGlobal();\n global = updateChat(global, channelId, createdChannel);\n global = {\n ...global,\n chatCreation: {\n ...global.chatCreation,\n progress: createdChannel ? ChatCreationProgress.Complete : ChatCreationProgress.Error,\n },\n };\n setGlobal(global);\n getDispatch().openChat({ id: channelId });\n\n if (channelId && accessHash && photo) {\n await callApi('editChatPhoto', { chatId: channelId, accessHash, photo });\n }\n}\n\nasync function createGroupChat(title: string, users: ApiUser[], photo?: File) {\n setGlobal({\n ...getGlobal(),\n chatCreation: {\n progress: ChatCreationProgress.InProgress,\n },\n });\n\n const createdChat = await callApi('createGroupChat', { title, users });\n if (!createdChat) {\n return;\n }\n\n const { id: chatId } = createdChat;\n\n let global = getGlobal();\n global = updateChat(global, chatId, createdChat);\n global = {\n ...global,\n chatCreation: {\n ...global.chatCreation,\n progress: createdChat ? ChatCreationProgress.Complete : ChatCreationProgress.Error,\n },\n };\n setGlobal(global);\n getDispatch().openChat({ id: chatId });\n\n if (chatId && photo) {\n await callApi('editChatPhoto', { chatId, photo });\n }\n}\n\nasync function loadChatFolders() {\n const chatFolders = await callApi('fetchChatFolders');\n\n if (chatFolders) {\n const global = getGlobal();\n\n setGlobal({\n ...global,\n chatFolders: {\n ...global.chatFolders,\n ...chatFolders,\n },\n });\n }\n}\n\nasync function loadRecommendedChatFolders() {\n const recommendedChatFolders = await callApi('fetchRecommendedChatFolders');\n\n if (recommendedChatFolders) {\n const global = getGlobal();\n\n setGlobal({\n ...global,\n chatFolders: {\n ...global.chatFolders,\n recommended: recommendedChatFolders,\n },\n });\n }\n}\n\nasync function createChatFolder(folder: ApiChatFolder, maxId: number) {\n // Clear fields from recommended folders\n const { id: recommendedId, description, ...newFolder } = folder;\n\n await callApi('editChatFolder', {\n id: maxId + 1,\n folderUpdate: {\n id: maxId + 1,\n ...newFolder,\n },\n });\n\n if (!description) {\n return;\n }\n\n const global = getGlobal();\n const { recommended } = global.chatFolders;\n\n if (recommended) {\n setGlobal({\n ...global,\n chatFolders: {\n ...global.chatFolders,\n recommended: recommended.filter(({ id }) => id !== recommendedId),\n },\n });\n }\n}\n\nasync function deleteChatFolder(id: number) {\n await callApi('deleteChatFolder', id);\n}\n\nasync function openChatByUsername(\n actions: GlobalActions,\n username: string,\n channelPostId?: number,\n) {\n const global = getGlobal();\n const localChat = selectChatByUsername(global, username);\n if (localChat && !localChat.isMin) {\n if (channelPostId) {\n actions.focusMessage({ chatId: localChat.id, messageId: channelPostId });\n } else {\n actions.openChat({ id: localChat.id });\n }\n return;\n }\n\n const previousChat = selectCurrentChat(global);\n // Open temporary empty chat to make the click response feel faster\n actions.openChat({ id: TMP_CHAT_ID });\n\n const chat = await callApi('getChatByUsername', username);\n if (!chat) {\n if (previousChat) {\n actions.openChat({ id: previousChat.id });\n }\n\n actions.showNotification({ message: 'User does not exist' });\n\n return;\n }\n\n setGlobal(updateChat(getGlobal(), chat.id, chat));\n\n if (channelPostId) {\n actions.focusMessage({ chatId: chat.id, messageId: channelPostId });\n } else {\n actions.openChat({ id: chat.id });\n }\n}\n","import { addReducer, getGlobal, setGlobal } from '../../../lib/teact/teactn';\n\nimport { GlobalActions } from '../../../global/types';\nimport {\n ApiAttachment,\n ApiChat,\n ApiMessage,\n ApiMessageEntity,\n ApiNewPoll,\n ApiOnProgress,\n ApiSticker,\n ApiVideo,\n MAIN_THREAD_ID,\n MESSAGE_DELETED,\n} from '../../../api/types';\nimport { LoadMoreDirection } from '../../../types';\n\nimport { MAX_MEDIA_FILES_FOR_ALBUM, MESSAGE_LIST_SLICE } from '../../../config';\nimport { callApi, cancelApiProgress } from '../../../api/gramjs';\nimport { areSortedArraysIntersecting, buildCollectionByKey, split } from '../../../util/iteratees';\nimport {\n addUsers,\n addChatMessagesById,\n replaceThreadParam,\n safeReplaceViewportIds,\n updateChatMessage,\n addChats,\n updateListedIds,\n updateOutlyingIds,\n replaceScheduledMessages,\n updateThreadInfos,\n updateChat,\n} from '../../reducers';\nimport {\n selectChat,\n selectChatMessage,\n selectCurrentMessageList,\n selectFocusedMessageId,\n selectCurrentChat,\n selectListedIds,\n selectOutlyingIds,\n selectViewportIds,\n selectRealLastReadId,\n selectReplyingToId,\n selectEditingId,\n selectDraft,\n selectThreadOriginChat,\n selectThreadTopMessageId,\n selectEditingScheduledId,\n selectEditingMessage,\n selectScheduledMessage,\n selectNoWebPage,\n} from '../../selectors';\nimport { rafPromise, throttle } from '../../../util/schedulers';\nimport { IS_IOS } from '../../../util/environment';\n\nconst uploadProgressCallbacks = new Map<number, ApiOnProgress>();\n\nconst runThrottledForMarkRead = throttle((cb) => cb(), 1000, true);\n\naddReducer('loadViewportMessages', (global, actions, payload) => {\n const {\n direction = LoadMoreDirection.Around,\n isBudgetPreload = false,\n } = payload || {};\n\n let { chatId, threadId } = payload || {};\n\n if (!chatId) {\n const currentMessageList = selectCurrentMessageList(global);\n if (!currentMessageList) {\n return undefined;\n }\n\n chatId = currentMessageList.chatId;\n threadId = currentMessageList.threadId;\n }\n\n const chat = selectChat(global, chatId);\n // TODO Revise if `chat.isRestricted` check is needed\n if (!chat || chat.isRestricted) {\n return undefined;\n }\n\n const viewportIds = selectViewportIds(global, chatId, threadId);\n const listedIds = selectListedIds(global, chatId, threadId);\n const outlyingIds = selectOutlyingIds(global, chatId, threadId);\n\n if (!viewportIds || !viewportIds.length || direction === LoadMoreDirection.Around) {\n const offsetId = selectFocusedMessageId(global, chatId) || selectRealLastReadId(global, chatId, threadId);\n const isOutlying = Boolean(offsetId && listedIds && !listedIds.includes(offsetId));\n const historyIds = (isOutlying ? outlyingIds : listedIds) || [];\n const {\n newViewportIds, areSomeLocal, areAllLocal,\n } = getViewportSlice(historyIds, offsetId, LoadMoreDirection.Around);\n\n if (areSomeLocal && newViewportIds.length >= MESSAGE_LIST_SLICE) {\n global = safeReplaceViewportIds(global, chatId, threadId, newViewportIds);\n }\n\n if (!areAllLocal) {\n void loadViewportMessages(chat, threadId, offsetId, LoadMoreDirection.Around, isOutlying, isBudgetPreload);\n }\n } else {\n const offsetId = direction === LoadMoreDirection.Backwards ? viewportIds[0] : viewportIds[viewportIds.length - 1];\n const isOutlying = Boolean(outlyingIds);\n const historyIds = (isOutlying ? outlyingIds : listedIds)!;\n const {\n newViewportIds, areSomeLocal, areAllLocal,\n } = getViewportSlice(historyIds, offsetId, direction);\n\n if (areSomeLocal) {\n global = safeReplaceViewportIds(global, chatId, threadId, newViewportIds);\n }\n\n void loadWithBudget(actions, areAllLocal, isOutlying, isBudgetPreload, chat, threadId, direction, offsetId);\n\n if (isBudgetPreload) {\n return undefined;\n }\n }\n\n return global;\n});\n\nasync function loadWithBudget(\n actions: GlobalActions,\n areAllLocal: boolean, isOutlying: boolean, isBudgetPreload: boolean,\n chat: ApiChat, threadId: number, direction: LoadMoreDirection, offsetId?: number,\n) {\n if (!areAllLocal) {\n await loadViewportMessages(\n chat, threadId, offsetId, direction, isOutlying, isBudgetPreload,\n );\n }\n\n if (!isBudgetPreload) {\n // Let reducer return and update global\n await Promise.resolve();\n actions.loadViewportMessages({\n chatId: chat.id, threadId, direction, isBudgetPreload: true,\n });\n }\n}\n\naddReducer('loadMessage', (global, actions, payload) => {\n const { chatId, messageId, replyOriginForId } = payload!;\n const chat = selectChat(global, chatId);\n\n if (!chat) {\n return;\n }\n\n void loadMessage(chat, messageId, replyOriginForId);\n});\n\naddReducer('sendMessage', (global, actions, payload) => {\n const currentMessageList = selectCurrentMessageList(global);\n if (!currentMessageList) {\n return undefined;\n }\n\n const { chatId, threadId, type } = currentMessageList;\n\n if (type === 'scheduled' && !payload.scheduledAt) {\n return {\n ...global,\n messages: {\n ...global.messages,\n contentToBeScheduled: payload,\n },\n };\n }\n\n const chat = selectChat(global, chatId)!;\n\n actions.setReplyingToId({ messageId: undefined });\n actions.clearWebPagePreview({ chatId, threadId, value: false });\n\n const params = {\n ...payload,\n chat,\n replyingTo: selectReplyingToId(global, chatId, threadId),\n noWebPage: selectNoWebPage(global, chatId, threadId),\n };\n\n const isSingle = !payload.attachments || payload.attachments.length <= 1;\n const isGrouped = !isSingle && payload.attachments && payload.attachments.length > 1;\n\n if (isSingle) {\n const { attachments, ...restParams } = params;\n sendMessage({\n ...restParams,\n attachment: attachments ? attachments[0] : undefined,\n });\n } else if (isGrouped) {\n const {\n text, entities, attachments, ...commonParams\n } = params;\n const groupedAttachments = split(attachments, MAX_MEDIA_FILES_FOR_ALBUM);\n for (let i = 0; i < groupedAttachments.length; i++) {\n const [firstAttachment, ...restAttachments] = groupedAttachments[i];\n const groupedId = `${Date.now()}${i}`;\n\n sendMessage({\n ...commonParams,\n text: i === 0 ? text : undefined,\n entities: i === 0 ? entities : undefined,\n attachment: firstAttachment,\n groupedId: restAttachments.length > 0 ? groupedId : undefined,\n });\n\n restAttachments.forEach((attachment: ApiAttachment) => {\n sendMessage({\n ...commonParams,\n attachment,\n groupedId,\n });\n });\n }\n } else {\n const {\n text, entities, attachments, replyingTo, ...commonParams\n } = params;\n\n if (text) {\n sendMessage({\n ...commonParams,\n text,\n entities,\n replyingTo,\n });\n }\n\n attachments.forEach((attachment: ApiAttachment) => {\n sendMessage({\n ...commonParams,\n attachment,\n });\n });\n }\n\n return undefined;\n});\n\naddReducer('editMessage', (global, actions, payload) => {\n const { serverTimeOffset } = global;\n const { text, entities } = payload!;\n\n const currentMessageList = selectCurrentMessageList(global);\n if (!currentMessageList) {\n return;\n }\n\n const { chatId, threadId, type: messageListType } = currentMessageList;\n const chat = selectChat(global, chatId);\n const message = selectEditingMessage(global, chatId, threadId, messageListType);\n if (!chat || !message) {\n return;\n }\n\n void callApi('editMessage', {\n chat, message, text, entities, noWebPage: selectNoWebPage(global, chatId, threadId), serverTimeOffset,\n });\n\n actions.setEditingId({ messageId: undefined });\n});\n\naddReducer('cancelSendingMessage', (global, actions, payload) => {\n const { chatId, messageId } = payload!;\n const message = selectChatMessage(global, chatId, messageId);\n const progressCallback = message && uploadProgressCallbacks.get(message.previousLocalId || message.id);\n if (progressCallback) {\n cancelApiProgress(progressCallback);\n }\n\n actions.apiUpdate({\n '@type': 'deleteMessages',\n ids: [messageId],\n chatId,\n });\n});\n\naddReducer('saveDraft', (global, actions, payload) => {\n const { chatId, threadId, draft } = payload!;\n if (!draft) {\n return undefined;\n }\n\n const { text, entities } = draft;\n const chat = selectChat(global, chatId)!;\n\n if (threadId === MAIN_THREAD_ID) {\n void callApi('saveDraft', {\n chat,\n text,\n entities,\n replyToMsgId: selectReplyingToId(global, chatId, threadId),\n });\n }\n\n global = replaceThreadParam(global, chatId, threadId, 'draft', draft);\n global = updateChat(global, chatId, { draftDate: Math.round(Date.now() / 1000) });\n\n return global;\n});\n\naddReducer('clearDraft', (global, actions, payload) => {\n const { chatId, threadId, localOnly } = payload!;\n if (!selectDraft(global, chatId, threadId)) {\n return undefined;\n }\n\n const chat = selectChat(global, chatId)!;\n\n if (!localOnly && threadId === MAIN_THREAD_ID) {\n void callApi('clearDraft', chat);\n }\n\n global = replaceThreadParam(global, chatId, threadId, 'draft', undefined);\n global = updateChat(global, chatId, { draftDate: undefined });\n\n return global;\n});\n\naddReducer('toggleMessageWebPage', (global, actions, payload) => {\n const { chatId, threadId, noWebPage } = payload!;\n\n return replaceThreadParam(global, chatId, threadId, 'noWebPage', noWebPage);\n});\n\naddReducer('pinMessage', (global, actions, payload) => {\n const chat = selectCurrentChat(global);\n if (!chat) {\n return;\n }\n\n const {\n messageId, isUnpin, isOneSide, isSilent,\n } = payload!;\n\n void callApi('pinMessage', {\n chat, messageId, isUnpin, isOneSide, isSilent,\n });\n});\n\naddReducer('unpinAllMessages', (global, actions, payload) => {\n const chat = selectChat(global, payload.chatId);\n if (!chat) {\n return;\n }\n\n void unpinAllMessages(chat);\n});\n\nasync function unpinAllMessages(chat: ApiChat) {\n await callApi('unpinAllMessages', { chat });\n let global = getGlobal();\n global = replaceThreadParam(global, chat.id, MAIN_THREAD_ID, 'pinnedIds', []);\n setGlobal(global);\n}\n\naddReducer('deleteMessages', (global, actions, payload) => {\n const { messageIds, shouldDeleteForAll } = payload!;\n const currentMessageList = selectCurrentMessageList(global);\n if (!currentMessageList) {\n return;\n }\n const { chatId, threadId } = currentMessageList;\n const chat = selectChat(global, chatId)!;\n\n void callApi('deleteMessages', { chat, messageIds, shouldDeleteForAll });\n\n const editingId = selectEditingId(global, chatId, threadId);\n if (messageIds.includes(editingId)) {\n actions.setEditingId({ messageId: undefined });\n }\n});\n\naddReducer('deleteScheduledMessages', (global, actions, payload) => {\n const { messageIds } = payload!;\n const currentMessageList = selectCurrentMessageList(global);\n if (!currentMessageList) {\n return;\n }\n\n const { chatId } = currentMessageList;\n const chat = selectChat(global, chatId)!;\n\n void callApi('deleteScheduledMessages', { chat, messageIds });\n\n const editingId = selectEditingScheduledId(global, chatId);\n if (messageIds.includes(editingId)) {\n actions.setEditingId({ messageId: undefined });\n }\n});\n\naddReducer('deleteHistory', (global, actions, payload) => {\n (async () => {\n const { chatId, shouldDeleteForAll } = payload!;\n const chat = selectChat(global, chatId);\n if (!chat) {\n return;\n }\n\n const maxId = chat.lastMessage && chat.lastMessage.id;\n\n await callApi('deleteHistory', { chat, shouldDeleteForAll, maxId });\n\n const activeChat = selectCurrentMessageList(global);\n if (activeChat && activeChat.chatId === chatId) {\n actions.openChat({ id: undefined });\n }\n })();\n});\n\naddReducer('reportMessages', (global, actions, payload) => {\n (async () => {\n const {\n messageIds, reason, description,\n } = payload!;\n const currentMessageList = selectCurrentMessageList(global);\n if (!currentMessageList) {\n return;\n }\n\n const { chatId } = currentMessageList;\n const chat = selectChat(global, chatId)!;\n\n const result = await callApi('reportMessages', {\n peer: chat, messageIds, reason, description,\n });\n\n actions.showNotification({\n message: result\n ? 'Thank you! Your report will be reviewed by our team.'\n : 'Error occured while submiting report. Please, try again later.',\n });\n })();\n});\n\naddReducer('markMessageListRead', (global, actions, payload) => {\n const { serverTimeOffset } = global;\n const currentMessageList = selectCurrentMessageList(global);\n if (!currentMessageList) {\n return;\n }\n\n const { chatId, threadId } = currentMessageList;\n const chat = selectThreadOriginChat(global, chatId, threadId);\n if (!chat) {\n return;\n }\n\n const { maxId } = payload!;\n\n runThrottledForMarkRead(() => {\n void callApi('markMessageListRead', {\n serverTimeOffset, chat, threadId, maxId,\n });\n });\n});\n\naddReducer('markMessagesRead', (global, actions, payload) => {\n const chat = selectCurrentChat(global);\n if (!chat) {\n return;\n }\n\n const { messageIds } = payload!;\n\n void callApi('markMessagesRead', { chat, messageIds });\n});\n\naddReducer('loadWebPagePreview', (global, actions, payload) => {\n const { text } = payload!;\n void loadWebPagePreview(text);\n});\n\naddReducer('clearWebPagePreview', (global) => {\n if (!global.webPagePreview) {\n return undefined;\n }\n\n return {\n ...global,\n webPagePreview: undefined,\n };\n});\n\naddReducer('sendPollVote', (global, actions, payload) => {\n const { chatId, messageId, options } = payload!;\n const chat = selectChat(global, chatId);\n\n if (chat) {\n void callApi('sendPollVote', { chat, messageId, options });\n }\n});\n\naddReducer('loadPollOptionResults', (global, actions, payload) => {\n const {\n chat, messageId, option, offset, limit, shouldResetVoters,\n } = payload!;\n\n void loadPollOptionResults(chat, messageId, option, offset, limit, shouldResetVoters);\n});\n\naddReducer('forwardMessages', (global) => {\n const { fromChatId, messageIds, toChatId } = global.forwardMessages;\n const fromChat = fromChatId ? selectChat(global, fromChatId) : undefined;\n const toChat = toChatId ? selectChat(global, toChatId) : undefined;\n const messages = fromChatId && messageIds\n ? messageIds\n .sort((a, b) => a - b)\n .map((id) => selectChatMessage(global, fromChatId, id)).filter<ApiMessage>(Boolean as any)\n : undefined;\n\n if (fromChat && toChat && messages && messages.length) {\n void forwardMessages(fromChat, toChat, messages);\n }\n});\n\naddReducer('loadScheduledHistory', (global) => {\n const chat = selectCurrentChat(global);\n if (!chat) {\n return;\n }\n\n const { hash } = global.scheduledMessages.byChatId[chat.id] || {};\n\n void loadScheduledHistory(chat, hash);\n});\n\naddReducer('sendScheduledMessages', (global, actions, payload) => {\n const {\n chatId, id,\n } = payload!;\n\n const chat = selectChat(global, chatId);\n\n if (!chat) {\n return;\n }\n\n void callApi('sendScheduledMessages', {\n chat,\n ids: [id],\n });\n});\n\naddReducer('rescheduleMessage', (global, actions, payload) => {\n const {\n chatId, messageId, scheduledAt,\n } = payload!;\n\n const chat = selectChat(global, chatId);\n const message = chat && selectScheduledMessage(global, chat.id, messageId);\n if (!chat || !message) {\n return;\n }\n\n void callApi('rescheduleMessage', {\n chat,\n message,\n scheduledAt,\n });\n});\n\naddReducer('requestThreadInfoUpdate', (global, actions, payload) => {\n const { chatId, threadId } = payload;\n const chat = selectThreadOriginChat(global, chatId, threadId);\n if (!chat) {\n return;\n }\n\n void callApi('requestThreadInfoUpdate', { chat, threadId });\n});\n\nasync function loadWebPagePreview(message: string) {\n const webPagePreview = await callApi('fetchWebPagePreview', { message });\n\n setGlobal({\n ...getGlobal(),\n webPagePreview,\n });\n}\n\nasync function loadViewportMessages(\n chat: ApiChat,\n threadId: number,\n offsetId: number | undefined,\n direction: LoadMoreDirection,\n isOutlying = false,\n isBudgetPreload = false,\n) {\n const chatId = chat.id;\n\n let addOffset: number | undefined;\n switch (direction) {\n case LoadMoreDirection.Backwards:\n addOffset = undefined;\n break;\n case LoadMoreDirection.Around:\n addOffset = -(Math.round(MESSAGE_LIST_SLICE / 2) + 1);\n break;\n case LoadMoreDirection.Forwards:\n addOffset = -(MESSAGE_LIST_SLICE + 1);\n break;\n }\n\n const result = await callApi('fetchMessages', {\n chat: selectThreadOriginChat(getGlobal(), chatId, threadId)!,\n offsetId,\n addOffset,\n limit: MESSAGE_LIST_SLICE,\n threadId,\n });\n\n if (!result) {\n return;\n }\n\n const {\n messages, users, chats, threadInfos,\n } = result;\n\n const byId = buildCollectionByKey(messages, 'id');\n const ids = Object.keys(byId).map(Number);\n\n let global = getGlobal();\n\n global = addChatMessagesById(global, chatId, byId);\n global = isOutlying\n ? updateOutlyingIds(global, chatId, threadId, ids)\n : updateListedIds(global, chatId, threadId, ids);\n global = addUsers(global, buildCollectionByKey(users, 'id'));\n global = addChats(global, buildCollectionByKey(chats, 'id'));\n global = updateThreadInfos(global, chatId, threadInfos);\n\n let listedIds = selectListedIds(global, chatId, threadId);\n const outlyingIds = selectOutlyingIds(global, chatId, threadId);\n\n if (isOutlying && listedIds && outlyingIds) {\n if (areSortedArraysIntersecting(listedIds, outlyingIds)) {\n global = updateListedIds(global, chatId, threadId, outlyingIds);\n listedIds = selectListedIds(global, chatId, threadId);\n global = replaceThreadParam(global, chatId, threadId, 'outlyingIds', undefined);\n isOutlying = false;\n }\n }\n\n if (!isBudgetPreload) {\n const historyIds = isOutlying ? outlyingIds! : listedIds!;\n const { newViewportIds } = getViewportSlice(historyIds, offsetId, direction);\n global = safeReplaceViewportIds(global, chatId, threadId, newViewportIds!);\n }\n\n setGlobal(global);\n}\n\nasync function loadMessage(chat: ApiChat, messageId: number, replyOriginForId: number) {\n const result = await callApi('fetchMessage', { chat, messageId });\n if (!result) {\n return;\n }\n\n if (result === MESSAGE_DELETED) {\n if (replyOriginForId) {\n let global = getGlobal();\n const replyMessage = selectChatMessage(global, chat.id, replyOriginForId);\n global = updateChatMessage(global, chat.id, replyOriginForId, {\n ...replyMessage,\n replyToMessageId: undefined,\n });\n setGlobal(global);\n }\n\n return;\n }\n\n let global = getGlobal();\n global = updateChatMessage(global, chat.id, messageId, result.message);\n global = addUsers(global, buildCollectionByKey(result.users, 'id'));\n setGlobal(global);\n}\n\nfunction findClosestIndex(sourceIds: number[], offsetId: number) {\n if (offsetId < sourceIds[0]) {\n return 0;\n }\n\n if (offsetId > sourceIds[sourceIds.length - 1]) {\n return sourceIds.length - 1;\n }\n\n return sourceIds.findIndex((id, i) => (\n id === offsetId\n || (id < offsetId && sourceIds[i + 1] > offsetId)\n ));\n}\n\nfunction getViewportSlice(\n sourceIds: number[],\n offsetId: number | undefined,\n direction: LoadMoreDirection,\n) {\n const { length } = sourceIds;\n const index = offsetId ? findClosestIndex(sourceIds, offsetId) : -1;\n const isBackwards = direction === LoadMoreDirection.Backwards;\n const indexForDirection = isBackwards ? index : (index + 1) || length;\n const from = indexForDirection - MESSAGE_LIST_SLICE;\n const to = indexForDirection + MESSAGE_LIST_SLICE - 1;\n const newViewportIds = sourceIds.slice(Math.max(0, from), to + 1);\n\n let areSomeLocal;\n let areAllLocal;\n switch (direction) {\n case LoadMoreDirection.Backwards:\n areSomeLocal = indexForDirection > 0;\n areAllLocal = from >= 0;\n break;\n case LoadMoreDirection.Forwards:\n areSomeLocal = indexForDirection < length;\n areAllLocal = to <= length - 1;\n break;\n case LoadMoreDirection.Around:\n default:\n areSomeLocal = newViewportIds.length > 0;\n areAllLocal = newViewportIds.length === MESSAGE_LIST_SLICE;\n break;\n }\n\n return { newViewportIds, areSomeLocal, areAllLocal };\n}\n\nasync function sendMessage(params: {\n chat: ApiChat;\n text: string;\n entities: ApiMessageEntity[];\n replyingTo: number;\n attachment: ApiAttachment;\n sticker: ApiSticker;\n gif: ApiVideo;\n poll: ApiNewPoll;\n serverTimeOffset?: number;\n}) {\n let localId: number | undefined;\n const progressCallback = params.attachment ? (progress: number, messageLocalId: number) => {\n if (!uploadProgressCallbacks.has(messageLocalId)) {\n localId = messageLocalId;\n uploadProgressCallbacks.set(messageLocalId, progressCallback!);\n }\n\n const global = getGlobal();\n\n setGlobal({\n ...global,\n fileUploads: {\n byMessageLocalId: {\n ...global.fileUploads.byMessageLocalId,\n [messageLocalId]: { progress },\n },\n },\n });\n } : undefined;\n\n // @optimization\n if (params.replyingTo || IS_IOS) {\n await rafPromise();\n }\n\n const global = getGlobal();\n params.serverTimeOffset = global.serverTimeOffset;\n const currentMessageList = selectCurrentMessageList(global);\n if (!currentMessageList) {\n return;\n }\n const { threadId } = currentMessageList;\n\n if (!params.replyingTo && threadId !== MAIN_THREAD_ID) {\n params.replyingTo = selectThreadTopMessageId(global, params.chat.id, threadId)!;\n }\n\n await callApi('sendMessage', params, progressCallback);\n\n if (progressCallback && localId) {\n uploadProgressCallbacks.delete(localId);\n }\n}\n\nfunction forwardMessages(\n fromChat: ApiChat,\n toChat: ApiChat,\n messages: ApiMessage[],\n) {\n callApi('forwardMessages', {\n fromChat,\n toChat,\n messages,\n serverTimeOffset: getGlobal().serverTimeOffset,\n });\n\n setGlobal({\n ...getGlobal(),\n forwardMessages: {},\n });\n}\n\nasync function loadPollOptionResults(\n chat: ApiChat,\n messageId: number,\n option: string,\n offset?: string,\n limit?: number,\n shouldResetVoters?: boolean,\n) {\n const result = await callApi('loadPollOptionResults', {\n chat, messageId, option, offset, limit,\n });\n\n if (!result) {\n return;\n }\n\n const isUnique = (v: number, i: number, a: number[]) => a.indexOf(v) === i;\n let global = getGlobal();\n\n global = addUsers(global, buildCollectionByKey(result.users, 'id'));\n const { voters } = global.pollResults;\n\n setGlobal({\n ...global,\n pollResults: {\n ...global.pollResults,\n voters: {\n ...voters,\n [option]: [\n ...(!shouldResetVoters && voters && voters[option] ? voters[option] : []),\n ...(result && result.users.map((user) => user.id)),\n ].filter(isUnique),\n },\n offsets: {\n ...(global.pollResults.offsets ? global.pollResults.offsets : {}),\n [option]: result.nextOffset || '',\n },\n },\n });\n}\n\naddReducer('loadPinnedMessages', (global, actions, payload) => {\n const { chatId } = payload;\n const chat = selectChat(global, chatId);\n if (!chat) {\n return;\n }\n\n void loadPinnedMessages(chat);\n});\n\nasync function loadPinnedMessages(chat: ApiChat) {\n const result = await callApi('fetchPinnedMessages', { chat });\n if (!result) {\n return;\n }\n\n const { messages, chats, users } = result;\n\n const byId = buildCollectionByKey(messages, 'id');\n const ids = Object.keys(byId).map(Number).sort((a, b) => b - a);\n\n let global = getGlobal();\n global = addChatMessagesById(global, chat.id, byId);\n global = replaceThreadParam(global, chat.id, MAIN_THREAD_ID, 'pinnedIds', ids);\n global = addUsers(global, buildCollectionByKey(users, 'id'));\n global = addChats(global, buildCollectionByKey(chats, 'id'));\n setGlobal(global);\n}\n\nasync function loadScheduledHistory(chat: ApiChat, historyHash?: number) {\n const result = await callApi('fetchScheduledHistory', { chat, hash: historyHash });\n if (!result) {\n return;\n }\n\n const { hash, messages } = result;\n\n const byId = buildCollectionByKey(messages, 'id');\n const ids = Object.keys(byId).map(Number).sort((a, b) => b - a);\n\n let global = getGlobal();\n global = replaceScheduledMessages(global, chat.id, byId, hash);\n global = replaceThreadParam(global, chat.id, MAIN_THREAD_ID, 'scheduledIds', ids);\n setGlobal(global);\n}\n","import { addReducer, getGlobal, setGlobal } from '../../../lib/teact/teactn';\n\nimport { ApiSticker } from '../../../api/types';\nimport { LangCode } from '../../../types';\nimport { callApi } from '../../../api/gramjs';\nimport { pause, throttle } from '../../../util/schedulers';\nimport {\n updateStickerSets,\n updateStickerSet,\n replaceAnimatedEmojis,\n updateGifSearch,\n updateStickersForEmoji,\n rebuildStickersForEmoji,\n} from '../../reducers';\nimport searchWords from '../../../util/searchWords';\nimport { selectStickerSet } from '../../selectors';\n\nconst ADDED_SETS_THROTTLE = 500;\nconst ADDED_SETS_THROTTLE_CHUNK = 50;\n\nconst searchThrottled = throttle((cb) => cb(), 500, false);\n\naddReducer('loadStickerSets', (global) => {\n const { hash } = global.stickers.added || {};\n void loadStickerSets(hash);\n});\n\naddReducer('loadAddedStickers', (global, actions) => {\n const { setIds: addedSetIds } = global.stickers.added;\n if (!addedSetIds || !addedSetIds.length) {\n return;\n }\n\n (async () => {\n for (let i = 0; i < addedSetIds.length; i++) {\n actions.loadStickers({ stickerSetId: addedSetIds[i] });\n\n if (i % ADDED_SETS_THROTTLE_CHUNK === 0 && i > 0) {\n await pause(ADDED_SETS_THROTTLE);\n }\n }\n })();\n});\n\naddReducer('loadRecentStickers', (global) => {\n const { hash } = global.stickers.recent || {};\n void loadRecentStickers(hash);\n});\n\naddReducer('loadFavoriteStickers', (global) => {\n const { hash } = global.stickers.favorite || {};\n void loadFavoriteStickers(hash);\n});\n\naddReducer('loadFeaturedStickers', (global) => {\n const { hash } = global.stickers.featured || {};\n void loadFeaturedStickers(hash);\n});\n\naddReducer('loadStickers', (global, actions, payload) => {\n const { stickerSetId } = payload!;\n let { stickerSetAccessHash } = payload!;\n\n if (!stickerSetAccessHash) {\n const stickerSet = selectStickerSet(global, stickerSetId);\n if (!stickerSet) {\n return;\n }\n\n stickerSetAccessHash = stickerSet.accessHash;\n }\n\n void loadStickers(stickerSetId, stickerSetAccessHash);\n});\n\naddReducer('loadAnimatedEmojis', () => {\n void loadAnimatedEmojis();\n});\n\naddReducer('loadSavedGifs', (global) => {\n const { hash } = global.gifs.saved;\n void loadSavedGifs(hash);\n});\n\naddReducer('faveSticker', (global, actions, payload) => {\n const { sticker } = payload!;\n\n if (sticker) {\n void callApi('faveSticker', { sticker });\n }\n});\n\naddReducer('unfaveSticker', (global, actions, payload) => {\n const { sticker } = payload!;\n\n if (sticker) {\n void unfaveSticker(sticker);\n }\n});\n\naddReducer('toggleStickerSet', (global, actions, payload) => {\n const { stickerSetId } = payload!;\n const stickerSet = selectStickerSet(global, stickerSetId);\n if (!stickerSet) {\n return;\n }\n\n const { accessHash, installedDate } = stickerSet;\n\n void callApi(!installedDate ? 'installStickerSet' : 'uninstallStickerSet', { stickerSetId, accessHash });\n});\n\naddReducer('loadEmojiKeywords', (global, actions, payload: { language: LangCode }) => {\n const { language } = payload;\n\n let currentEmojiKeywords = global.emojiKeywords[language];\n if (currentEmojiKeywords && currentEmojiKeywords.isLoading) {\n return;\n }\n\n setGlobal({\n ...global,\n emojiKeywords: {\n ...global.emojiKeywords,\n [language]: {\n ...currentEmojiKeywords,\n isLoading: true,\n },\n },\n });\n\n (async () => {\n const emojiKeywords = await callApi('fetchEmojiKeywords', {\n language,\n fromVersion: currentEmojiKeywords ? currentEmojiKeywords.version : 0,\n });\n\n global = getGlobal();\n currentEmojiKeywords = global.emojiKeywords[language];\n\n if (!emojiKeywords) {\n setGlobal({\n ...global,\n emojiKeywords: {\n ...global.emojiKeywords,\n [language]: {\n ...currentEmojiKeywords,\n isLoading: false,\n },\n },\n });\n\n return;\n }\n\n setGlobal({\n ...global,\n emojiKeywords: {\n ...global.emojiKeywords,\n [language]: {\n isLoading: false,\n version: emojiKeywords.version,\n keywords: {\n ...(currentEmojiKeywords && currentEmojiKeywords.keywords),\n ...emojiKeywords.keywords,\n },\n },\n },\n });\n })();\n});\n\nasync function loadStickerSets(hash = 0) {\n const addedStickers = await callApi('fetchStickerSets', { hash });\n if (!addedStickers) {\n return;\n }\n\n setGlobal(updateStickerSets(\n getGlobal(),\n 'added',\n addedStickers.hash,\n addedStickers.sets,\n ));\n}\n\nasync function loadRecentStickers(hash = 0) {\n const recentStickers = await callApi('fetchRecentStickers', { hash });\n if (!recentStickers) {\n return;\n }\n\n const global = getGlobal();\n\n setGlobal({\n ...global,\n stickers: {\n ...global.stickers,\n recent: recentStickers,\n },\n });\n}\n\nasync function loadFavoriteStickers(hash = 0) {\n const favoriteStickers = await callApi('fetchFavoriteStickers', { hash });\n if (!favoriteStickers) {\n return;\n }\n\n const global = getGlobal();\n\n setGlobal({\n ...global,\n stickers: {\n ...global.stickers,\n favorite: favoriteStickers,\n },\n });\n}\n\nasync function loadFeaturedStickers(hash = 0) {\n const featuredStickers = await callApi('fetchFeaturedStickers', { hash });\n if (!featuredStickers) {\n return;\n }\n\n setGlobal(updateStickerSets(\n getGlobal(),\n 'featured',\n featuredStickers.hash,\n featuredStickers.sets,\n ));\n}\n\nasync function loadStickers(stickerSetId: string, accessHash: string) {\n const stickerSet = await callApi('fetchStickers', { stickerSetId, accessHash });\n if (!stickerSet) {\n return;\n }\n\n const { set, stickers, packs } = stickerSet;\n\n let global = getGlobal();\n\n global = updateStickerSet(global, set.id, { ...set, stickers, packs });\n\n const currentEmoji = global.stickers.forEmoji.emoji;\n if (currentEmoji && packs[currentEmoji]) {\n global = rebuildStickersForEmoji(global);\n }\n\n setGlobal(global);\n}\n\nasync function loadAnimatedEmojis() {\n const stickerSet = await callApi('fetchAnimatedEmojis');\n if (!stickerSet) {\n return;\n }\n\n const { set, stickers } = stickerSet;\n\n setGlobal(replaceAnimatedEmojis(getGlobal(), { ...set, stickers }));\n}\n\nfunction unfaveSticker(sticker: ApiSticker) {\n const global = getGlobal();\n\n // Remove sticker preemptively to get instant feedback when user removes sticker\n // from favorites while in Sticker Picker\n setGlobal({\n ...global,\n stickers: {\n ...global.stickers,\n favorite: {\n ...global.stickers.favorite,\n stickers: global.stickers.favorite.stickers.filter(({ id }) => id !== sticker.id),\n },\n },\n });\n\n void callApi('faveSticker', { sticker, unfave: true });\n}\n\naddReducer('setStickerSearchQuery', (global, actions, payload) => {\n const { query } = payload!;\n\n if (query) {\n void searchThrottled(() => {\n searchStickers(query);\n });\n }\n});\n\naddReducer('setGifSearchQuery', (global, actions, payload) => {\n const { query } = payload!;\n\n if (typeof query === 'string') {\n void searchThrottled(() => {\n searchGifs(query);\n });\n }\n});\n\naddReducer('searchMoreGifs', (global) => {\n const { query, offset } = global.gifs.search;\n\n if (typeof query === 'string') {\n void searchThrottled(() => {\n searchGifs(query, offset);\n });\n }\n});\n\naddReducer('loadStickersForEmoji', (global, actions, payload) => {\n const { emoji } = payload!;\n const { hash } = global.stickers.forEmoji;\n\n void searchThrottled(() => {\n loadStickersForEmoji(emoji, hash);\n });\n});\n\naddReducer('clearStickersForEmoji', (global) => {\n return {\n ...global,\n stickers: {\n ...global.stickers,\n forEmoji: {},\n },\n };\n});\n\nasync function searchStickers(query: string, hash = 0) {\n const result = await callApi('searchStickers', { query, hash });\n\n if (!result) {\n return;\n }\n\n const global = getGlobal();\n const { setsById, added } = global.stickers;\n\n const resultIds = result.sets.map(({ id }) => id);\n\n if (added.setIds) {\n added.setIds.forEach((id) => {\n if (!resultIds.includes(id)) {\n const { title } = setsById[id] || {};\n if (title && searchWords(title, query)) {\n resultIds.unshift(id);\n }\n }\n });\n }\n\n setGlobal(updateStickerSets(\n global,\n 'search',\n result.hash,\n result.sets,\n resultIds,\n ));\n}\n\nasync function searchGifs(query: string, offset?: string) {\n const result = await callApi('searchGifs', { query, offset });\n if (!result) {\n return;\n }\n\n setGlobal(updateGifSearch(getGlobal(), !offset, result.gifs, result.nextOffset));\n}\n\nasync function loadSavedGifs(hash = 0) {\n const savedGifs = await callApi('fetchSavedGifs', { hash });\n if (!savedGifs) {\n return;\n }\n\n const global = getGlobal();\n\n setGlobal({\n ...global,\n gifs: {\n ...global.gifs,\n saved: savedGifs,\n },\n });\n}\n\nasync function loadStickersForEmoji(emoji: string, hash = 0) {\n let global = getGlobal();\n setGlobal({\n ...global,\n stickers: {\n ...global.stickers,\n forEmoji: {\n ...global.stickers.forEmoji,\n emoji,\n },\n },\n });\n\n const result = await callApi('fetchStickersForEmoji', { emoji, hash });\n\n global = getGlobal();\n\n if (!result || global.stickers.forEmoji.emoji !== emoji) {\n return;\n }\n\n global = updateStickersForEmoji(global, emoji, result.stickers, result.hash);\n\n setGlobal(global);\n}\n","import { addReducer, getGlobal, setGlobal } from '../../../lib/teact/teactn';\n\nimport { callApi } from '../../../api/gramjs';\nimport { ApiChat, ApiGlobalMessageSearchType } from '../../../api/types';\n\nimport {\n addChats,\n addMessages,\n addUsers,\n updateGlobalSearch,\n updateGlobalSearchFetchingStatus,\n updateGlobalSearchResults,\n} from '../../reducers';\nimport { throttle } from '../../../util/schedulers';\nimport { selectChat, selectCurrentGlobalSearchQuery } from '../../selectors';\nimport { buildCollectionByKey } from '../../../util/iteratees';\nimport { GLOBAL_SEARCH_SLICE } from '../../../config';\nimport { timestampPlusDay } from '../../../util/dateFormat';\n\nconst searchThrottled = throttle((cb) => cb(), 500, false);\n\naddReducer('setGlobalSearchQuery', (global, actions, payload) => {\n const { chatId } = global.globalSearch;\n const { query } = payload!;\n\n if (query && !chatId) {\n void searchThrottled(() => {\n searchChats(query);\n });\n }\n});\n\naddReducer('setGlobalSearchDate', (global, actions, payload) => {\n const { date } = payload!;\n const maxDate = date ? timestampPlusDay(date) : date;\n const newGlobal = updateGlobalSearch(global, {\n date,\n query: '',\n resultsByType: {\n ...global.globalSearch.resultsByType,\n text: {\n totalCount: undefined,\n foundIds: [],\n nextOffsetId: 0,\n },\n },\n });\n setGlobal(newGlobal);\n const { chatId } = global.globalSearch;\n const chat = chatId ? selectChat(global, chatId) : undefined;\n searchMessagesGlobal('', 'text', undefined, chat, maxDate, date);\n});\n\naddReducer('searchMessagesGlobal', (global, actions, payload) => {\n const {\n query, resultsByType, chatId, date,\n } = global.globalSearch;\n const maxDate = date ? timestampPlusDay(date) : date;\n const { type } = payload;\n const { nextOffsetId } = (resultsByType && resultsByType[type as ApiGlobalMessageSearchType]) || {};\n\n const chat = chatId ? selectChat(global, chatId) : undefined;\n\n searchMessagesGlobal(query, type, nextOffsetId, chat, maxDate, date);\n});\n\nasync function searchChats(query: string) {\n const result = await callApi('searchChats', { query });\n\n let global = getGlobal();\n const currentSearchQuery = selectCurrentGlobalSearchQuery(global);\n if (!result || !currentSearchQuery || (query !== currentSearchQuery)) {\n setGlobal(updateGlobalSearchFetchingStatus(global, { chats: false }));\n return;\n }\n\n const {\n localChats, localUsers, globalChats, globalUsers,\n } = result;\n\n if (localChats.length || globalChats.length) {\n global = addChats(global, buildCollectionByKey([...localChats, ...globalChats], 'id'));\n }\n\n if (localUsers.length || globalUsers.length) {\n global = addUsers(global, buildCollectionByKey([...localUsers, ...globalUsers], 'id'));\n }\n\n global = updateGlobalSearchFetchingStatus(global, { chats: false });\n global = updateGlobalSearch(global, {\n localResults: {\n chatIds: localChats.map(({ id }) => id),\n userIds: localUsers.map(({ id }) => id),\n },\n globalResults: {\n ...global.globalSearch.globalResults,\n chatIds: globalUsers.map(({ id }) => id),\n userIds: globalChats.map(({ id }) => id),\n },\n });\n\n setGlobal(global);\n}\n\nasync function searchMessagesGlobal(\n query = '', type: ApiGlobalMessageSearchType, offsetRate?: number, chat?: ApiChat, maxDate?: number, minDate?: number,\n) {\n let result;\n\n if (chat) {\n const localResult = await callApi('searchMessagesLocal', {\n chatOrUser: chat,\n query,\n type,\n limit: GLOBAL_SEARCH_SLICE,\n offsetId: offsetRate,\n minDate,\n maxDate,\n });\n\n if (localResult) {\n const {\n messages, users, totalCount, nextOffsetId,\n } = localResult;\n\n result = {\n messages,\n users,\n chats: [],\n totalCount,\n nextRate: nextOffsetId,\n };\n }\n } else {\n result = await callApi('searchMessagesGlobal', {\n query,\n offsetRate,\n limit: GLOBAL_SEARCH_SLICE,\n type,\n maxDate,\n minDate,\n });\n }\n\n let global = getGlobal();\n const currentSearchQuery = selectCurrentGlobalSearchQuery(global);\n if (!result || (query !== '' && query !== currentSearchQuery)) {\n setGlobal(updateGlobalSearchFetchingStatus(global, { messages: false }));\n return;\n }\n\n const {\n messages, users, chats, totalCount, nextRate,\n } = result;\n\n if (chats.length) {\n global = addChats(global, buildCollectionByKey(chats, 'id'));\n }\n\n if (users.length) {\n global = addUsers(global, buildCollectionByKey(users, 'id'));\n }\n\n if (messages.length) {\n global = addMessages(global, messages);\n }\n\n global = updateGlobalSearchResults(\n global,\n messages,\n totalCount,\n type,\n nextRate,\n );\n\n setGlobal(global);\n}\n","import {\n addReducer, getGlobal, setGlobal, getDispatch,\n} from '../../../lib/teact/teactn';\n\nimport {\n ApiChat, ApiFormattedText, ApiUser, MAIN_THREAD_ID,\n} from '../../../api/types';\nimport { GlobalActions } from '../../../global/types';\n\nimport {\n CHAT_LIST_LOAD_SLICE, DEBUG, MESSAGE_LIST_SLICE,\n} from '../../../config';\nimport { callApi } from '../../../api/gramjs';\nimport { buildCollectionByKey } from '../../../util/iteratees';\nimport {\n replaceChatListIds,\n replaceChats,\n replaceUsers,\n updateUsers,\n updateChats,\n updateChatListSecondaryInfo,\n updateThreadInfos,\n replaceThreadParam,\n} from '../../reducers';\nimport {\n selectUser, selectChat, selectCurrentMessageList, selectDraft, selectChatMessage, selectThreadInfo,\n} from '../../selectors';\nimport { isChatPrivate } from '../../helpers';\n\naddReducer('sync', (global, actions) => {\n void sync(actions.afterSync);\n});\n\naddReducer('afterSync', (global, actions) => {\n void afterSync(actions);\n});\n\nasync function sync(afterSyncCallback: () => void) {\n if (DEBUG) {\n // eslint-disable-next-line no-console\n console.log('>>> START SYNC');\n }\n\n await callApi('fetchCurrentUser');\n\n // This fetches only active chats and clears archived chats, which will be fetched in `afterSync`\n const savedUsers = await loadAndReplaceChats();\n await loadAndReplaceMessages(savedUsers);\n\n setGlobal({\n ...getGlobal(),\n lastSyncTime: Date.now(),\n });\n\n if (DEBUG) {\n // eslint-disable-next-line no-console\n console.log('>>> FINISH SYNC');\n }\n\n afterSyncCallback();\n}\n\nasync function afterSync(actions: GlobalActions) {\n if (DEBUG) {\n // eslint-disable-next-line no-console\n console.log('>>> START AFTER-SYNC');\n }\n\n actions.loadFavoriteStickers();\n\n await Promise.all([\n loadAndUpdateUsers(),\n loadAndReplaceArchivedChats(),\n ]);\n\n await callApi('fetchCurrentUser');\n\n if (DEBUG) {\n // eslint-disable-next-line no-console\n console.log('>>> FINISH AFTER-SYNC');\n }\n}\n\nasync function loadAndReplaceChats() {\n const result = await callApi('fetchChats', {\n limit: CHAT_LIST_LOAD_SLICE,\n withPinned: true,\n serverTimeOffset: getGlobal().serverTimeOffset,\n });\n if (!result) {\n return undefined;\n }\n\n let global = getGlobal();\n\n const { recentlyFoundChatIds } = global.globalSearch;\n const { userIds: contactIds } = global.contactList || {};\n const { currentUserId } = global;\n\n const savedPrivateChatIds = [\n ...(recentlyFoundChatIds || []),\n ...(contactIds || []),\n ...(currentUserId ? [currentUserId] : []),\n ];\n\n const savedUsers = savedPrivateChatIds\n .map((id) => selectUser(global, id))\n .filter<ApiUser>(Boolean as any);\n\n const savedChats = savedPrivateChatIds\n .map((id) => selectChat(global, id))\n .filter<ApiChat>(Boolean as any);\n\n const { chatId: currentChatId } = selectCurrentMessageList(global) || {};\n if (currentChatId) {\n const selectedChat = selectChat(global, currentChatId);\n if (selectedChat && !savedPrivateChatIds.includes(currentChatId)) {\n savedChats.push(selectedChat);\n }\n\n if (isChatPrivate(currentChatId)) {\n const selectedChatUser = selectUser(global, currentChatId);\n if (selectedChatUser && !savedPrivateChatIds.includes(currentChatId)) {\n savedUsers.push(selectedChatUser);\n }\n }\n }\n\n savedUsers.push(...result.users);\n savedChats.push(...result.chats);\n\n global = replaceChats(global, buildCollectionByKey(savedChats, 'id'));\n global = replaceChatListIds(global, 'active', result.chatIds);\n\n global = {\n ...global,\n chats: {\n ...global.chats,\n },\n };\n\n global = updateChatListSecondaryInfo(global, 'active', result);\n\n Object.keys(result.draftsById).map(Number).forEach((chatId) => {\n global = replaceThreadParam(global, chatId, MAIN_THREAD_ID, 'draft', result.draftsById[chatId]);\n });\n\n Object.keys(result.replyingToById).map(Number).forEach((chatId) => {\n global = replaceThreadParam(\n global, chatId, MAIN_THREAD_ID, 'replyingToId', result.replyingToById[chatId],\n );\n });\n\n setGlobal(global);\n\n if (currentChatId && !global.chats.byId[currentChatId]) {\n getDispatch().openChat({ id: undefined });\n }\n\n return savedUsers;\n}\n\nasync function loadAndReplaceArchivedChats() {\n const result = await callApi('fetchChats', {\n limit: CHAT_LIST_LOAD_SLICE,\n archived: true,\n withPinned: true,\n serverTimeOffset: getGlobal().serverTimeOffset,\n });\n\n if (!result) {\n return;\n }\n\n let global = getGlobal();\n global = updateUsers(global, buildCollectionByKey(result.users, 'id'));\n global = updateChats(global, buildCollectionByKey(result.chats, 'id'));\n global = replaceChatListIds(global, 'archived', result.chatIds);\n global = updateChatListSecondaryInfo(global, 'archived', result);\n setGlobal(global);\n}\n\nasync function loadAndReplaceMessages(savedUsers?: ApiUser[]) {\n let areMessagesLoaded = false;\n let users = savedUsers || [];\n\n let global = getGlobal();\n const { chatId: currentChatId, threadId: currentThreadId } = selectCurrentMessageList(global) || {};\n\n // Memoize drafts\n const draftChatIds = Object.keys(global.messages.byChatId).map(Number);\n const draftsByChatId = draftChatIds.reduce<Record<number, ApiFormattedText>>((acc, chatId) => {\n const draft = selectDraft(global, chatId, MAIN_THREAD_ID);\n return draft ? { ...acc, [chatId]: draft } : acc;\n }, {});\n\n if (currentChatId) {\n const result = await loadTopMessages(global.chats.byId[currentChatId]);\n global = getGlobal();\n const { chatId: newCurrentChatId } = selectCurrentMessageList(global) || {};\n const threadInfo = currentThreadId && selectThreadInfo(global, currentChatId, currentThreadId);\n\n if (result && newCurrentChatId === currentChatId) {\n const currentMessageListInfo = global.messages.byChatId[currentChatId];\n const byId = buildCollectionByKey(result.messages, 'id');\n const listedIds = Object.keys(byId).map(Number);\n\n global = {\n ...global,\n messages: {\n ...global.messages,\n byChatId: {\n [currentChatId]: {\n byId,\n threadsById: {\n [MAIN_THREAD_ID]: {\n ...(currentMessageListInfo && currentMessageListInfo.threadsById[MAIN_THREAD_ID]),\n listedIds,\n viewportIds: listedIds,\n outlyingIds: undefined,\n },\n },\n },\n },\n },\n };\n\n if (currentThreadId && threadInfo && threadInfo.originChannelId) {\n const { originChannelId } = threadInfo;\n const currentMessageListInfoOrigin = global.messages.byChatId[originChannelId];\n const resultOrigin = await loadTopMessages(global.chats.byId[originChannelId]);\n if (resultOrigin) {\n const byIdOrigin = buildCollectionByKey(resultOrigin.messages, 'id');\n const listedIdsOrigin = Object.keys(byIdOrigin)\n .map(Number);\n\n global = {\n ...global,\n messages: {\n ...global.messages,\n byChatId: {\n ...global.messages.byChatId,\n [threadInfo.originChannelId]: {\n byId: byIdOrigin,\n threadsById: {\n [MAIN_THREAD_ID]: {\n ...(currentMessageListInfoOrigin && currentMessageListInfoOrigin.threadsById[MAIN_THREAD_ID]),\n listedIds: listedIdsOrigin,\n viewportIds: listedIdsOrigin,\n outlyingIds: undefined,\n },\n },\n },\n [currentChatId]: {\n ...global.messages.byChatId[currentChatId],\n threadsById: {\n ...global.messages.byChatId[currentChatId].threadsById,\n [currentThreadId]: {\n ...(currentMessageListInfo && currentMessageListInfo.threadsById[currentThreadId]),\n outlyingIds: undefined,\n },\n },\n },\n },\n },\n };\n }\n }\n global = updateChats(global, buildCollectionByKey(result.chats, 'id'));\n global = updateThreadInfos(global, currentChatId, result.threadInfos);\n\n areMessagesLoaded = true;\n users = Array.prototype.concat(users, result.users);\n }\n }\n\n if (!areMessagesLoaded) {\n global = {\n ...global,\n messages: {\n ...global.messages,\n byChatId: {},\n },\n };\n }\n\n // Restore drafts\n Object.keys(draftsByChatId).map(Number).forEach((chatId) => {\n global = replaceThreadParam(global, chatId, MAIN_THREAD_ID, 'draft', draftsByChatId[chatId]);\n });\n\n if (savedUsers) {\n global = replaceUsers(global, buildCollectionByKey(users, 'id'));\n } else if (users) {\n // If `fetchChats` has failed for some reason, we don't have saved chats, thus we can not replace\n global = updateUsers(global, buildCollectionByKey(users, 'id'));\n }\n\n setGlobal(global);\n\n const { chatId: audioChatId, messageId: audioMessageId } = global.audioPlayer;\n if (audioChatId && audioMessageId && !selectChatMessage(global, audioChatId, audioMessageId)) {\n getDispatch().closeAudioPlayer();\n }\n}\n\nasync function loadAndUpdateUsers() {\n let global = getGlobal();\n const { recentlyFoundChatIds } = global.globalSearch;\n const { userIds: contactIds } = global.contactList || {};\n if (\n (!contactIds || !contactIds.length)\n && (!recentlyFoundChatIds || !recentlyFoundChatIds.length)\n ) {\n return;\n }\n\n const users = [\n ...(recentlyFoundChatIds || []),\n ...(contactIds || []),\n ].map((id) => selectUser(global, id)).filter<ApiUser>(Boolean as any);\n\n const updatedUsers = await callApi('fetchUsers', { users });\n if (!updatedUsers) {\n return;\n }\n\n global = getGlobal();\n global = updateUsers(global, buildCollectionByKey(updatedUsers, 'id'));\n setGlobal(global);\n}\n\nfunction loadTopMessages(chat: ApiChat) {\n return callApi('fetchMessages', {\n chat,\n threadId: MAIN_THREAD_ID,\n offsetId: chat.lastReadInboxMessageId,\n addOffset: -(Math.round(MESSAGE_LIST_SLICE / 2) + 1),\n limit: MESSAGE_LIST_SLICE,\n });\n}\n","import {\n addReducer, getDispatch, getGlobal, setGlobal,\n} from '../../../lib/teact/teactn';\n\nimport { ApiChat, ApiUser, MAIN_THREAD_ID } from '../../../api/types';\n\nimport { MESSAGE_SEARCH_SLICE, SHARED_MEDIA_SLICE } from '../../../config';\nimport { callApi } from '../../../api/gramjs';\nimport {\n selectCurrentTextSearch,\n selectCurrentMediaSearchPeerId,\n selectCurrentMediaSearch, selectCurrentMessageList, selectChat, selectThreadInfo,\n} from '../../selectors';\nimport { buildCollectionByKey } from '../../../util/iteratees';\nimport {\n addChatMessagesById,\n addUsers,\n updateLocalMediaSearchResults,\n updateLocalTextSearchResults,\n} from '../../reducers';\nimport { SharedMediaType } from '../../../types';\n\naddReducer('searchTextMessagesLocal', (global) => {\n const { chatId, threadId } = selectCurrentMessageList(global) || {};\n const chat = chatId ? selectChat(global, chatId) : undefined;\n const currentSearch = selectCurrentTextSearch(global);\n if (!chat || !currentSearch || !threadId) {\n return;\n }\n\n const { query, results } = currentSearch;\n const offsetId = results ? results.nextOffsetId : undefined;\n\n let topMessageId: number | undefined;\n if (threadId !== MAIN_THREAD_ID) {\n const threadInfo = selectThreadInfo(global, chatId!, threadId);\n topMessageId = threadInfo ? threadInfo.topMessageId : undefined;\n }\n\n void searchTextMessages(chat, threadId, topMessageId, query, offsetId);\n});\n\naddReducer('searchMediaMessagesLocal', (global) => {\n const peerId = selectCurrentMediaSearchPeerId(global);\n const chatOrUser = peerId\n ? global.users.byId[peerId] || global.chats.byId[peerId]\n : undefined;\n const currentSearch = selectCurrentMediaSearch(global);\n\n if (!chatOrUser || !currentSearch) {\n return;\n }\n\n const { currentType: type, resultsByType } = currentSearch;\n const currentResults = type && resultsByType && resultsByType[type];\n const offsetId = currentResults ? currentResults.nextOffsetId : undefined;\n\n if (!type) {\n return;\n }\n\n void searchSharedMedia(chatOrUser, type, offsetId);\n});\n\naddReducer('searchMessagesByDate', (global, actions, payload) => {\n const { timestamp } = payload!;\n\n const { chatId } = selectCurrentMessageList(global) || {};\n if (!chatId) {\n return;\n }\n\n const chat = selectChat(global, chatId);\n if (!chat) {\n return;\n }\n\n void searchMessagesByDate(chat, timestamp);\n});\n\nasync function searchTextMessages(\n chatOrUser: ApiChat,\n threadId: number,\n topMessageId?: number,\n query?: string,\n offsetId?: number,\n) {\n const result = await callApi('searchMessagesLocal', {\n chatOrUser,\n type: 'text',\n query,\n topMessageId,\n limit: MESSAGE_SEARCH_SLICE,\n offsetId,\n });\n\n if (!result) {\n return;\n }\n\n const {\n messages, users, totalCount, nextOffsetId,\n } = result;\n\n const byId = buildCollectionByKey(messages, 'id');\n const newFoundIds = Object.keys(byId).map(Number);\n\n let global = getGlobal();\n\n const currentSearch = selectCurrentTextSearch(global);\n if (!currentSearch || (query && query !== currentSearch.query)) {\n return;\n }\n\n global = addChatMessagesById(global, chatOrUser.id, byId);\n global = addUsers(global, buildCollectionByKey(users, 'id'));\n global = updateLocalTextSearchResults(global, chatOrUser.id, threadId, newFoundIds, totalCount, nextOffsetId);\n setGlobal(global);\n}\n\nasync function searchSharedMedia(\n chatOrUser: ApiChat | ApiUser,\n type: SharedMediaType,\n offsetId?: number,\n) {\n const result = await callApi('searchMessagesLocal', {\n chatOrUser,\n type,\n limit: SHARED_MEDIA_SLICE,\n offsetId,\n });\n\n if (!result) {\n return;\n }\n\n const {\n messages, users, totalCount, nextOffsetId,\n } = result;\n\n const byId = buildCollectionByKey(messages, 'id');\n const newFoundIds = Object.keys(byId).map(Number);\n\n let global = getGlobal();\n\n const currentSearch = selectCurrentMediaSearch(global);\n if (!currentSearch) {\n return;\n }\n\n global = addChatMessagesById(global, chatOrUser.id, byId);\n global = addUsers(global, buildCollectionByKey(users, 'id'));\n global = updateLocalMediaSearchResults(global, chatOrUser.id, type, newFoundIds, totalCount, nextOffsetId);\n setGlobal(global);\n}\n\n/**\n * @param timestamp start of target date in seconds\n */\nasync function searchMessagesByDate(chat: ApiChat, timestamp: number) {\n const messageId = await callApi('findFirstMessageIdAfterDate', {\n chat,\n timestamp,\n });\n\n if (!messageId) {\n return;\n }\n\n getDispatch().focusMessage({\n chatId: chat.id,\n messageId,\n });\n}\n","import { addReducer, getGlobal, setGlobal } from '../../../lib/teact/teactn';\n\nimport { ManagementProgress } from '../../../types';\nimport { callApi } from '../../../api/gramjs';\nimport { updateManagement, updateManagementProgress } from '../../reducers';\nimport { selectChat, selectCurrentMessageList } from '../../selectors';\nimport { isChatBasicGroup } from '../../helpers';\n\naddReducer('checkPublicLink', (global, actions, payload) => {\n const { chatId } = selectCurrentMessageList(global) || {};\n if (!chatId) {\n return;\n }\n\n // No need to check the username if already in progress\n if (global.management.progress === ManagementProgress.InProgress) {\n return;\n }\n\n const { username } = payload!;\n\n (async () => {\n global = updateManagementProgress(global, ManagementProgress.InProgress);\n global = updateManagement(global, chatId, { isUsernameAvailable: undefined });\n setGlobal(global);\n\n const isUsernameAvailable = await callApi('checkChatUsername', { username })!;\n\n global = getGlobal();\n global = updateManagementProgress(\n global, isUsernameAvailable ? ManagementProgress.Complete : ManagementProgress.Error,\n );\n global = updateManagement(global, chatId, { isUsernameAvailable });\n setGlobal(global);\n })();\n});\n\naddReducer('updatePublicLink', (global, actions, payload) => {\n const { chatId } = selectCurrentMessageList(global) || {};\n let chat = chatId && selectChat(global, chatId);\n if (!chatId || !chat) {\n return;\n }\n\n const { username } = payload!;\n\n (async () => {\n global = updateManagementProgress(global, ManagementProgress.InProgress);\n setGlobal(global);\n\n if (isChatBasicGroup(chat)) {\n chat = await callApi('migrateChat', chat);\n\n if (!chat) {\n return;\n }\n\n actions.openChat({ id: chat.id });\n }\n\n const result = await callApi('setChatUsername', { chat, username });\n\n global = getGlobal();\n global = updateManagementProgress(global, result ? ManagementProgress.Complete : ManagementProgress.Error);\n global = updateManagement(global, chatId, { isUsernameAvailable: undefined });\n setGlobal(global);\n })();\n});\n\naddReducer('updatePrivateLink', (global) => {\n const { chatId } = selectCurrentMessageList(global) || {};\n const chat = chatId && selectChat(global, chatId);\n if (!chatId || !chat) {\n return;\n }\n\n callApi('updatePrivateLink', { chat });\n});\n","import {\n addReducer, getDispatch, getGlobal, setGlobal,\n} from '../../../lib/teact/teactn';\n\nimport { ApiUser } from '../../../api/types';\nimport { ManagementProgress } from '../../../types';\n\nimport { debounce, throttle } from '../../../util/schedulers';\nimport { buildCollectionByKey } from '../../../util/iteratees';\nimport { isChatPrivate } from '../../helpers';\nimport { callApi } from '../../../api/gramjs';\nimport { selectChat, selectUser } from '../../selectors';\nimport {\n addChats, addUsers, updateChat, updateManagementProgress, updateUser, updateUsers,\n updateUserSearch, updateUserSearchFetchingStatus,\n} from '../../reducers';\n\nconst runDebouncedForFetchFullUser = debounce((cb) => cb(), 500, false, true);\nconst TOP_PEERS_REQUEST_COOLDOWN = 60; // 1 min\nconst runThrottledForSearch = throttle((cb) => cb(), 500, false);\n\naddReducer('loadFullUser', (global, actions, payload) => {\n const { userId } = payload!;\n const user = selectUser(global, userId);\n if (!user) {\n return;\n }\n\n const { id, accessHash } = user;\n\n runDebouncedForFetchFullUser(() => callApi('fetchFullUser', { id, accessHash }));\n});\n\naddReducer('loadUser', (global, actions, payload) => {\n const { userId } = payload!;\n const user = selectUser(global, userId);\n if (!user) {\n return;\n }\n\n (async () => {\n const updatedUsers = await callApi('fetchUsers', { users: [user] });\n if (!updatedUsers) {\n return;\n }\n\n global = getGlobal();\n global = updateUsers(global, buildCollectionByKey(updatedUsers, 'id'));\n setGlobal(global);\n })();\n});\n\naddReducer('loadTopUsers', (global) => {\n const {\n serverTimeOffset,\n topPeers: {\n hash, lastRequestedAt,\n },\n } = global;\n\n if (!lastRequestedAt || Date.now() / 1000 + serverTimeOffset - lastRequestedAt > TOP_PEERS_REQUEST_COOLDOWN) {\n void loadTopUsers(hash);\n }\n});\n\naddReducer('loadContactList', (global) => {\n const { hash } = global.contactList || {};\n void loadContactList(hash);\n});\n\naddReducer('loadCurrentUser', () => {\n void callApi('fetchCurrentUser');\n});\n\naddReducer('updateContact', (global, actions, payload) => {\n const {\n userId, isMuted, firstName, lastName,\n } = payload!;\n\n void updateContact(userId, isMuted, firstName, lastName);\n});\n\naddReducer('deleteUser', (global, actions, payload) => {\n const { userId } = payload!;\n\n void deleteUser(userId);\n});\n\nasync function loadTopUsers(usersHash?: number) {\n const result = await callApi('fetchTopUsers', { hash: usersHash });\n if (!result) {\n return;\n }\n\n const { hash, ids, users } = result;\n\n let global = getGlobal();\n global = addUsers(global, buildCollectionByKey(users, 'id'));\n global = {\n ...global,\n topPeers: {\n ...global.topPeers,\n hash,\n userIds: ids,\n lastRequestedAt: Date.now() / 1000 + global.serverTimeOffset,\n },\n };\n setGlobal(global);\n}\n\nasync function loadContactList(hash?: number) {\n const contactList = await callApi('fetchContactList', { hash });\n if (!contactList) {\n return;\n }\n\n let global = addUsers(getGlobal(), buildCollectionByKey(contactList.users, 'id'));\n global = addChats(global, buildCollectionByKey(contactList.chats, 'id'));\n\n // Sort contact list by Last Name (or First Name), with latin names being placed first\n const getCompareString = (user: ApiUser) => (user.lastName || user.firstName || '');\n const collator = new Intl.Collator('en-US');\n\n const sortedUsers = contactList.users.sort((a, b) => (\n collator.compare(getCompareString(a), getCompareString(b))\n )).filter((user) => !user.isSelf);\n\n setGlobal({\n ...global,\n contactList: {\n hash: contactList.hash,\n userIds: sortedUsers.map((user) => user.id),\n },\n });\n}\n\nasync function updateContact(\n userId: number,\n isMuted: boolean,\n firstName: string,\n lastName?: string,\n) {\n const global = getGlobal();\n const user = selectUser(global, userId);\n if (!user) {\n return;\n }\n\n getDispatch().updateChatMutedState({ chatId: userId, isMuted });\n\n setGlobal(updateManagementProgress(getGlobal(), ManagementProgress.InProgress));\n\n const result = await callApi('updateContact', { phone: user.phoneNumber, firstName, lastName });\n\n if (result) {\n setGlobal(updateUser(\n getGlobal(),\n user.id,\n {\n firstName,\n lastName,\n },\n ));\n }\n\n setGlobal(updateManagementProgress(getGlobal(), ManagementProgress.Complete));\n}\n\nasync function deleteUser(userId: number) {\n const global = getGlobal();\n const user = selectUser(global, userId);\n\n if (!user) {\n return;\n }\n\n const { id, accessHash } = user;\n\n await callApi('deleteUser', { id, accessHash });\n}\n\naddReducer('loadProfilePhotos', (global, actions, payload) => {\n const { profileId } = payload!;\n const isPrivate = isChatPrivate(profileId);\n const user = isPrivate ? selectUser(global, profileId) : undefined;\n const chat = !isPrivate ? selectChat(global, profileId) : undefined;\n\n (async () => {\n const result = await callApi('fetchProfilePhotos', user, chat);\n if (!result || !result.photos) {\n return;\n }\n\n let newGlobal = getGlobal();\n if (isPrivate) {\n newGlobal = updateUser(newGlobal, profileId, { photos: result.photos });\n } else {\n newGlobal = addUsers(newGlobal, buildCollectionByKey(result.users!, 'id'));\n newGlobal = updateChat(newGlobal, profileId, { photos: result.photos });\n }\n\n setGlobal(newGlobal);\n })();\n});\n\n\naddReducer('setUserSearchQuery', (global, actions, payload) => {\n const { query } = payload!;\n\n if (!query) return;\n\n void runThrottledForSearch(() => {\n searchUsers(query);\n });\n});\n\nasync function searchUsers(query: string) {\n const result = await callApi('searchChats', { query });\n\n let global = getGlobal();\n const currentSearchQuery = global.userSearch.query;\n\n if (!result || !currentSearchQuery || (query !== currentSearchQuery)) {\n setGlobal(updateUserSearchFetchingStatus(global, false));\n return;\n }\n\n const { localUsers, globalUsers } = result;\n\n let localUserIds;\n let globalUserIds;\n if (localUsers.length) {\n global = addUsers(global, buildCollectionByKey(localUsers, 'id'));\n localUserIds = localUsers.map(({ id }) => id);\n }\n if (globalUsers.length) {\n global = addUsers(global, buildCollectionByKey(globalUsers, 'id'));\n globalUserIds = globalUsers.map(({ id }) => id);\n }\n\n global = updateUserSearchFetchingStatus(global, false);\n global = updateUserSearch(global, { localUserIds, globalUserIds });\n\n setGlobal(global);\n}\n","import { GlobalState } from '../../global/types';\nimport { InlineBotSettings } from '../../types';\n\n\nexport function replaceInlineBotSettings(\n global: GlobalState, username: string, inlineBotSettings: InlineBotSettings | false,\n): GlobalState {\n return {\n ...global,\n inlineBots: {\n ...global.inlineBots,\n byUsername: {\n ...global.inlineBots.byUsername,\n [username]: inlineBotSettings,\n },\n },\n };\n}\n\nexport function replaceInlineBotsIsLoading(global: GlobalState, isLoading: boolean): GlobalState {\n return {\n ...global,\n inlineBots: {\n ...global.inlineBots,\n isLoading,\n },\n };\n}\n","import {\n addReducer, getDispatch, getGlobal, setGlobal,\n} from '../../../lib/teact/teactn';\n\nimport { ApiChat } from '../../../api/types';\nimport { InlineBotSettings } from '../../../types';\n\nimport { RE_TME_INVITE_LINK, RE_TME_LINK } from '../../../config';\nimport { callApi } from '../../../api/gramjs';\nimport {\n selectChat, selectChatBot, selectChatMessage, selectCurrentChat, selectCurrentMessageList,\n selectReplyingToId, selectUser,\n} from '../../selectors';\nimport { addChats, addUsers, removeBlockedContact } from '../../reducers';\nimport { buildCollectionByKey } from '../../../util/iteratees';\nimport { debounce } from '../../../util/schedulers';\nimport { replaceInlineBotSettings, replaceInlineBotsIsLoading } from '../../reducers/bots';\n\nconst TOP_PEERS_REQUEST_COOLDOWN = 60000; // 1 min\nconst runDebouncedForSearch = debounce((cb) => cb(), 500, false);\n\naddReducer('clickInlineButton', (global, actions, payload) => {\n const { button } = payload;\n\n switch (button.type) {\n case 'command':\n actions.sendBotCommand({ command: button.value });\n break;\n case 'url':\n if (button.value.match(RE_TME_INVITE_LINK) || button.value.match(RE_TME_LINK)) {\n actions.openTelegramLink({ url: button.value });\n } else {\n actions.toggleSafeLinkModal({ url: button.value });\n }\n break;\n case 'callback': {\n const chat = selectCurrentChat(global);\n if (!chat) {\n return;\n }\n\n void answerCallbackButton(chat, button.messageId, button.value);\n break;\n }\n case 'requestPoll':\n actions.openPollModal();\n break;\n case 'buy': {\n const chat = selectCurrentChat(global);\n const { messageId, value } = button;\n if (!chat) {\n return;\n }\n\n if (value) {\n actions.getReceipt({ receiptMessageId: value, chatId: chat.id, messageId });\n } else {\n actions.getPaymentForm({ messageId });\n actions.setInvoiceMessageInfo(selectChatMessage(global, chat.id, messageId));\n actions.openPaymentModal({ messageId });\n }\n break;\n }\n }\n});\n\naddReducer('sendBotCommand', (global, actions, payload) => {\n const { command, chatId } = payload;\n const { currentUserId } = global;\n const chat = chatId ? selectChat(global, chatId) : selectCurrentChat(global);\n if (!currentUserId || !chat) {\n return;\n }\n\n void sendBotCommand(chat, currentUserId, command);\n});\n\naddReducer('restartBot', (global, actions, payload) => {\n const { chatId } = payload;\n const { currentUserId } = global;\n const chat = selectCurrentChat(global);\n const bot = currentUserId && selectChatBot(global, chatId);\n if (!currentUserId || !chat || !bot) {\n return;\n }\n\n (async () => {\n const result = await callApi('unblockContact', bot.id, bot.accessHash);\n if (!result) {\n return;\n }\n\n setGlobal(removeBlockedContact(getGlobal(), bot.id));\n void sendBotCommand(chat, currentUserId, '/start');\n })();\n});\n\naddReducer('loadTopInlineBots', (global) => {\n const { serverTimeOffset } = global;\n const { hash, lastRequestedAt } = global.topInlineBots;\n\n if (lastRequestedAt && Date.now() + serverTimeOffset - lastRequestedAt < TOP_PEERS_REQUEST_COOLDOWN) {\n return;\n }\n\n (async () => {\n const result = await callApi('fetchTopInlineBots', { hash });\n if (!result) {\n return;\n }\n\n const { hash: newHash, ids, users } = result;\n\n let newGlobal = getGlobal();\n newGlobal = addUsers(newGlobal, buildCollectionByKey(users, 'id'));\n newGlobal = {\n ...newGlobal,\n topInlineBots: {\n ...newGlobal.topInlineBots,\n hash: newHash,\n userIds: ids,\n lastRequestedAt: Date.now(),\n },\n };\n setGlobal(newGlobal);\n })();\n});\n\naddReducer('queryInlineBot', ((global, actions, payload) => {\n const {\n chatId, username, query, offset,\n } = payload;\n\n (async () => {\n let inlineBotData = global.inlineBots.byUsername[username];\n\n if (inlineBotData === false) {\n return;\n }\n\n if (inlineBotData === undefined) {\n const { user: inlineBot, chat } = await callApi('fetchInlineBot', { username }) || {};\n global = getGlobal();\n if (!inlineBot || !chat) {\n setGlobal(replaceInlineBotSettings(global, username, false));\n return;\n }\n\n global = addUsers(global, { [inlineBot.id]: inlineBot });\n global = addChats(global, { [chat.id]: chat });\n inlineBotData = {\n id: inlineBot.id,\n query: '',\n offset: '',\n switchPm: undefined,\n canLoadMore: true,\n results: [],\n };\n\n global = replaceInlineBotSettings(global, username, inlineBotData);\n setGlobal(global);\n }\n\n if (query === inlineBotData.query && !inlineBotData.canLoadMore) {\n return;\n }\n\n void runDebouncedForSearch(() => {\n searchInlineBot({\n username,\n inlineBotData: inlineBotData as InlineBotSettings,\n chatId,\n query,\n offset,\n });\n });\n })();\n}));\n\naddReducer('sendInlineBotResult', (global, actions, payload) => {\n const { id, queryId } = payload;\n const currentMessageList = selectCurrentMessageList(global);\n\n if (!currentMessageList || !id) {\n return;\n }\n\n const { chatId, threadId } = currentMessageList;\n\n const chat = selectChat(global, chatId)!;\n\n actions.setReplyingToId({ messageId: undefined });\n actions.clearWebPagePreview({ chatId, threadId, value: false });\n\n void callApi('sendInlineBotResult', {\n chat,\n resultId: id,\n queryId,\n replyingTo: selectReplyingToId(global, chatId, threadId),\n });\n});\n\naddReducer('resetInlineBot', ((global, actions, payload) => {\n const { username } = payload;\n\n let inlineBotData = global.inlineBots.byUsername[username];\n\n if (!inlineBotData) {\n return;\n }\n\n inlineBotData = {\n id: inlineBotData.id,\n query: '',\n offset: '',\n switchPm: undefined,\n canLoadMore: true,\n results: [],\n };\n\n setGlobal(replaceInlineBotSettings(global, username, inlineBotData));\n}));\n\nasync function searchInlineBot({\n username,\n inlineBotData,\n chatId,\n query,\n offset,\n} : {\n username: string;\n inlineBotData: InlineBotSettings;\n chatId: number;\n query: string;\n offset?: string;\n}) {\n let global = getGlobal();\n const bot = selectUser(global, inlineBotData.id);\n const chat = selectChat(global, chatId);\n if (!bot || !chat) {\n return;\n }\n\n const shouldReplaceSettings = inlineBotData.query !== query;\n global = replaceInlineBotsIsLoading(global, true);\n global = replaceInlineBotSettings(global, username, {\n ...inlineBotData,\n query,\n ...(shouldReplaceSettings && { offset: undefined, results: [] }),\n });\n setGlobal(global);\n\n const result = await callApi('fetchInlineBotResults', {\n bot,\n chat,\n query,\n offset: shouldReplaceSettings ? undefined : offset,\n });\n\n const newInlineBotData = global.inlineBots.byUsername[username];\n global = replaceInlineBotsIsLoading(getGlobal(), false);\n if (!result || !newInlineBotData || query !== newInlineBotData.query) {\n setGlobal(global);\n return;\n }\n\n const currentIds = new Set((newInlineBotData.results || []).map((data) => data.id));\n const newResults = result.results.filter((data) => !currentIds.has(data.id));\n\n global = replaceInlineBotSettings(global, username, {\n ...newInlineBotData,\n help: result.help,\n ...(newResults.length && { isGallery: result.isGallery }),\n ...(result.switchPm && { switchPm: result.switchPm }),\n canLoadMore: result.results.length > 0 && Boolean(result.nextOffset),\n results: newInlineBotData.offset === '' || newInlineBotData.offset === result.nextOffset\n ? result.results\n : (newInlineBotData.results || []).concat(newResults),\n offset: newResults.length ? result.nextOffset : '',\n });\n\n setGlobal(global);\n}\n\nasync function sendBotCommand(chat: ApiChat, currentUserId: number, command: string) {\n await callApi('sendMessage', {\n chat,\n text: command,\n });\n}\n\nasync function answerCallbackButton(chat: ApiChat, messageId: number, data: string) {\n const result = await callApi('answerCallbackButton', {\n chatId: chat.id,\n accessHash: chat.accessHash,\n messageId,\n data,\n });\n\n if (!result || !result.message) {\n return;\n }\n\n const { message, alert: isError } = result;\n\n if (isError) {\n getDispatch().showDialog({ data: { message } });\n } else {\n getDispatch().showNotification({ message });\n }\n}\n","import { addReducer, getGlobal, setGlobal } from '../../../lib/teact/teactn';\n\nimport { callApi } from '../../../api/gramjs';\nimport { replaceSettings, updateTwoFaSettings } from '../../reducers';\n\naddReducer('loadPasswordInfo', () => {\n (async () => {\n const result = await callApi('getPasswordInfo');\n if (!result) {\n return;\n }\n\n let global = getGlobal();\n global = replaceSettings(global, { hasPassword: result.hasPassword });\n global = updateTwoFaSettings(global, { hint: result.hint });\n setGlobal(global);\n })();\n});\n\naddReducer('checkPassword', (global, actions, payload) => {\n const { currentPassword, onSuccess } = payload;\n\n setGlobal(updateTwoFaSettings(global, { isLoading: true, error: undefined }));\n\n (async () => {\n const isSuccess = await callApi('checkPassword', currentPassword);\n\n setGlobal(updateTwoFaSettings(getGlobal(), { isLoading: false }));\n\n if (isSuccess) {\n onSuccess();\n }\n })();\n});\n\naddReducer('clearPassword', (global, actions, payload) => {\n const { currentPassword, onSuccess } = payload;\n\n setGlobal(updateTwoFaSettings(global, { isLoading: true, error: undefined }));\n\n (async () => {\n const isSuccess = await callApi('clearPassword', currentPassword);\n\n setGlobal(updateTwoFaSettings(getGlobal(), { isLoading: false }));\n\n if (isSuccess) {\n onSuccess();\n }\n })();\n});\n\naddReducer('updatePassword', (global, actions, payload) => {\n const {\n currentPassword, password, hint, email, onSuccess,\n } = payload;\n\n setGlobal(updateTwoFaSettings(global, { isLoading: true, error: undefined }));\n\n (async () => {\n const isSuccess = await callApi('updatePassword', currentPassword, password, hint, email);\n\n setGlobal(updateTwoFaSettings(getGlobal(), { isLoading: false }));\n\n if (isSuccess) {\n onSuccess();\n }\n })();\n});\n\naddReducer('updateRecoveryEmail', (global, actions, payload) => {\n const {\n currentPassword, email, onSuccess,\n } = payload;\n\n setGlobal(updateTwoFaSettings(global, { isLoading: true, error: undefined }));\n\n (async () => {\n const isSuccess = await callApi('updateRecoveryEmail', currentPassword, email);\n\n setGlobal(updateTwoFaSettings(getGlobal(), { isLoading: false, waitingEmailCodeLength: undefined }));\n\n if (isSuccess) {\n onSuccess();\n }\n })();\n});\n\naddReducer('provideTwoFaEmailCode', (global, actions, payload) => {\n const { code } = payload;\n\n void callApi('provideRecoveryEmailCode', code);\n});\n\naddReducer('clearTwoFaError', (global) => {\n return updateTwoFaSettings(global, { error: undefined });\n});\n","import { addReducer, getGlobal, setGlobal } from '../../../lib/teact/teactn';\n\nimport { PaymentStep } from '../../../types/index';\nimport { callApi } from '../../../api/gramjs';\nimport {\n selectPaymentMessageId,\n selectPaymentRequestId,\n selectProviderPublishableKey,\n selectStripeCredentials,\n selectChatMessage,\n} from '../../selectors';\n\nimport { getStripeError } from '../../helpers/payments';\nimport { buildQueryString } from '../../../util/requestQuery';\n\nimport {\n updateShippingOptions,\n setPaymentStep,\n setRequestInfoId,\n setPaymentForm,\n setStripeCardInfo,\n setInvoiceMessageInfo,\n setReceipt,\n clearPayment,\n closeInvoice,\n} from '../../reducers';\n\naddReducer('validateRequestedInfo', (global, actions, payload) => {\n const { requestInfo, saveInfo } = payload;\n const messageId = selectPaymentMessageId(global);\n if (!messageId) {\n return;\n }\n validateRequestedInfo(messageId, requestInfo, saveInfo);\n});\n\nasync function validateRequestedInfo(messageId: number, requestInfo: any, shouldSave?: true) {\n const result = await callApi('validateRequestedInfo', { messageId, requestInfo, shouldSave });\n if (!result) {\n return;\n }\n const { id, shippingOptions } = result;\n if (!id) {\n return;\n }\n let global = setRequestInfoId(getGlobal(), id);\n if (shippingOptions) {\n global = updateShippingOptions(global, shippingOptions);\n global = setPaymentStep(global, PaymentStep.Shipping);\n } else {\n global = setPaymentStep(global, PaymentStep.PaymentInfo);\n }\n setGlobal(global);\n}\n\naddReducer('getPaymentForm', (global, actions, payload) => {\n const { messageId } = payload;\n if (!messageId) {\n return;\n }\n getPaymentForm(messageId);\n});\n\n\nasync function getPaymentForm(messageId: number) {\n const result = await callApi('getPaymentForm', { messageId });\n if (!result) {\n return;\n }\n let global = setPaymentForm(getGlobal(), result);\n let step = PaymentStep.PaymentInfo;\n if (global.payment.invoice\n && (global.payment.invoice.shippingAddressRequested\n || global.payment.invoice.nameRequested\n || global.payment.invoice.phoneRequested\n || global.payment.invoice.emailRequested)) {\n step = PaymentStep.ShippingInfo;\n }\n global = setPaymentStep(global, step);\n setGlobal(global);\n}\n\naddReducer('getReceipt', (global, actions, payload) => {\n const { receiptMessageId, chatId, messageId } = payload;\n if (!messageId || !receiptMessageId || !chatId) {\n return;\n }\n getReceipt(messageId, receiptMessageId, chatId);\n});\n\nasync function getReceipt(messageId: number, receiptMessageId: number, chatId: number) {\n const result = await callApi('getReceipt', receiptMessageId);\n if (!result) {\n return;\n }\n let global = getGlobal();\n const message = selectChatMessage(global, chatId, messageId);\n global = setReceipt(global, result, message);\n setGlobal(global);\n}\n\naddReducer('clearPaymentError', (global) => {\n setGlobal({\n ...global,\n payment: {\n ...global.payment,\n error: undefined,\n },\n });\n});\n\naddReducer('clearReceipt', (global) => {\n setGlobal({\n ...global,\n payment: {\n ...global.payment,\n receipt: undefined,\n },\n });\n});\n\naddReducer('sendCredentialsInfo', (global, actions, payload) => {\n const publishableKey = selectProviderPublishableKey(global);\n if (!publishableKey) {\n return;\n }\n const { credentials } = payload;\n const { data } = credentials;\n sendStipeCredentials(data, publishableKey);\n});\n\naddReducer('sendPaymentForm', (global, actions, payload) => {\n const { shippingOptionId, saveCredentials } = payload;\n const messageId = selectPaymentMessageId(global);\n const requestInfoId = selectPaymentRequestId(global);\n const publishableKey = selectProviderPublishableKey(global);\n const stripeCredentials = selectStripeCredentials(global);\n if (!messageId || !publishableKey) {\n return;\n }\n sendPaymentForm(messageId, {\n save: saveCredentials,\n data: stripeCredentials,\n }, requestInfoId, shippingOptionId);\n});\n\nasync function sendStipeCredentials(data: {\n cardNumber: string;\n cardholder?: string;\n expiryMonth: string;\n expiryYear: string;\n cvv: string;\n country: string;\n zip: string;\n},\npublishableKey: string) {\n const query = buildQueryString({\n 'card[number]': data.cardNumber,\n 'card[exp_month]': data.expiryMonth,\n 'card[exp_year]': data.expiryYear,\n 'card[cvc]': data.cvv,\n 'card[address_zip]': data.zip,\n 'card[address_country]': data.country,\n });\n\n const response = await fetch(`https://api.stripe.com/v1/tokens${query}`, {\n method: 'POST',\n credentials: 'same-origin',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Authorization: `Bearer ${publishableKey}`,\n },\n });\n const result = await response.json();\n if (result.error) {\n const error = getStripeError(result.error);\n const global = getGlobal();\n setGlobal({\n ...global,\n payment: {\n ...global.payment,\n error: {\n ...error,\n },\n },\n });\n return;\n }\n let global = setStripeCardInfo(getGlobal(), {\n type: result.type,\n id: result.id,\n });\n global = setPaymentStep(global, PaymentStep.Checkout);\n setGlobal(global);\n}\n\nasync function sendPaymentForm(\n messageId: number,\n credentials: any,\n requestedInfoId?: string,\n shippingOptionId?: string,\n) {\n const result = await callApi('sendPaymentForm', {\n messageId, credentials, requestedInfoId, shippingOptionId,\n });\n if (result) {\n const global = clearPayment(getGlobal());\n setGlobal(closeInvoice(global));\n }\n}\n\naddReducer('setPaymentStep', (global, actions, payload = {}) => {\n return setPaymentStep(global, payload.step || PaymentStep.ShippingInfo);\n});\n\naddReducer('setInvoiceMessageInfo', (global, actions, payload) => {\n return setInvoiceMessageInfo(global, payload);\n});\n","export function buildQueryString(data: Record<string, string>) {\n const query = Object.keys(data).map((k) => `${k}=${data[k]}`).join('&');\n return query.length > 0 ? `?${query}` : '';\n}\n","import { addReducer, getGlobal, setGlobal } from '../../../lib/teact/teactn';\n\nimport { ApiUpdate, MAIN_THREAD_ID } from '../../../api/types';\n\nimport { ARCHIVED_FOLDER_ID, MAX_ACTIVE_PINNED_CHATS } from '../../../config';\nimport { pick } from '../../../util/iteratees';\nimport { showNewMessageNotification } from '../../../util/notifications';\nimport { updateAppBadge } from '../../../util/appBadge';\nimport {\n updateChat,\n replaceChatListIds,\n updateChatListIds,\n updateChatListType,\n replaceThreadParam,\n} from '../../reducers';\nimport {\n selectChat,\n selectCommonBoxChatId,\n selectIsChatListed,\n selectChatListType,\n selectCurrentMessageList,\n selectCountNotMutedUnread,\n} from '../../selectors';\nimport { throttle } from '../../../util/schedulers';\n\nconst TYPING_STATUS_CLEAR_DELAY = 6000; // 6 seconds\n\n// Enough to animate and mark as read in Message List\nconst CURRENT_CHAT_UNREAD_DELAY = 1000;\nconst runThrottledForUpdateAppBadge = throttle((cb) => cb(), CURRENT_CHAT_UNREAD_DELAY, true);\n\naddReducer('apiUpdate', (global, actions, update: ApiUpdate) => {\n switch (update['@type']) {\n case 'updateChat': {\n if (!update.noTopChatsRequest && !selectIsChatListed(global, update.id)) {\n // Chat can appear in dialogs list.\n actions.loadTopChats();\n }\n\n const newGlobal = updateChat(global, update.id, update.chat, update.newProfilePhoto);\n setGlobal(newGlobal);\n\n const unreadCount = selectCountNotMutedUnread(newGlobal);\n runThrottledForUpdateAppBadge(() => updateAppBadge(unreadCount));\n break;\n }\n\n case 'updateChatJoin': {\n const listType = selectChatListType(global, update.id);\n if (!listType) {\n break;\n }\n\n global = updateChatListIds(global, listType, [update.id]);\n global = updateChat(global, update.id, { isNotJoined: false });\n setGlobal(global);\n\n const chat = selectChat(global, update.id);\n if (chat) {\n actions.requestChatUpdate({ chatId: chat.id });\n }\n break;\n }\n\n case 'updateChatLeave': {\n const listType = selectChatListType(global, update.id);\n if (!listType) {\n break;\n }\n\n const { [listType]: listIds } = global.chats.listIds;\n\n if (listIds) {\n global = replaceChatListIds(global, listType, listIds.filter((listId) => listId !== update.id));\n }\n\n global = updateChat(global, update.id, { isNotJoined: true });\n setGlobal(global);\n\n break;\n }\n\n case 'updateChatInbox': {\n setGlobal(updateChat(global, update.id, update.chat));\n\n break;\n }\n\n case 'updateChatTypingStatus': {\n const { id, typingStatus } = update;\n setGlobal(updateChat(global, id, { typingStatus }));\n\n setTimeout(() => {\n const newGlobal = getGlobal();\n const chat = selectChat(newGlobal, id);\n if (chat && typingStatus && chat.typingStatus && chat.typingStatus.timestamp === typingStatus.timestamp) {\n setGlobal(updateChat(newGlobal, id, { typingStatus: undefined }));\n }\n }, TYPING_STATUS_CLEAR_DELAY);\n\n break;\n }\n\n case 'newMessage': {\n const { message } = update;\n const { chatId: currentChatId, threadId, type: messageListType } = selectCurrentMessageList(global) || {};\n\n if (message.senderId === global.currentUserId && !message.isFromScheduled) {\n return;\n }\n\n const chat = selectChat(global, update.chatId);\n if (!chat) {\n return;\n }\n\n const isActiveChat = (\n messageListType === 'thread'\n && threadId === MAIN_THREAD_ID\n && update.chatId === currentChatId\n );\n\n if (isActiveChat) {\n setTimeout(() => {\n actions.requestChatUpdate({ chatId: update.chatId });\n }, CURRENT_CHAT_UNREAD_DELAY);\n } else {\n setGlobal(updateChat(global, update.chatId, {\n unreadCount: chat.unreadCount ? chat.unreadCount + 1 : 1,\n ...(update.message.hasUnreadMention && {\n unreadMentionsCount: chat.unreadMentionsCount ? chat.unreadMentionsCount + 1 : 1,\n }),\n }));\n }\n\n const unreadCount = selectCountNotMutedUnread(getGlobal());\n updateAppBadge(unreadCount);\n showNewMessageNotification({ chat, message, isActiveChat });\n\n break;\n }\n\n case 'updateCommonBoxMessages':\n case 'updateChannelMessages': {\n const { ids, messageUpdate } = update;\n if (messageUpdate.hasUnreadMention !== false) {\n return;\n }\n\n ids.forEach((id) => {\n const chatId = 'channelId' in update ? update.channelId : selectCommonBoxChatId(global, id);\n const chat = selectChat(global, chatId);\n if (chat && chat.unreadMentionsCount) {\n global = updateChat(global, chatId, {\n unreadMentionsCount: chat.unreadMentionsCount - 1,\n });\n }\n });\n\n setGlobal(global);\n\n break;\n }\n\n case 'updateChatFullInfo': {\n const { fullInfo } = update;\n const targetChat = global.chats.byId[update.id];\n if (!targetChat) {\n return;\n }\n\n setGlobal(updateChat(global, update.id, {\n fullInfo: {\n ...targetChat.fullInfo,\n ...fullInfo,\n },\n }));\n\n break;\n }\n\n case 'updatePinnedChatIds': {\n const { ids, folderId } = update;\n\n const listType = folderId === ARCHIVED_FOLDER_ID ? 'archived' : 'active';\n\n global = {\n ...global,\n chats: {\n ...global.chats,\n orderedPinnedIds: {\n ...global.chats.orderedPinnedIds,\n [listType]: ids.length ? ids : undefined,\n },\n },\n };\n\n setGlobal(global);\n\n break;\n }\n\n case 'updateChatPinned': {\n const { id, isPinned } = update;\n const listType = selectChatListType(global, id);\n if (listType) {\n const { [listType]: orderedPinnedIds } = global.chats.orderedPinnedIds;\n\n let newOrderedPinnedIds = orderedPinnedIds || [];\n if (!isPinned) {\n newOrderedPinnedIds = newOrderedPinnedIds.filter((pinnedId) => pinnedId !== id);\n } else if (!newOrderedPinnedIds.includes(id)) {\n // When moving pinned chats to archive, active ordered pinned ids don't get updated\n // (to preserve chat pinned state when it returns from archive)\n // If user already has max pinned chats, we should check for orderedIds\n // that don't point to listed chats\n if (listType === 'active' && newOrderedPinnedIds.length >= MAX_ACTIVE_PINNED_CHATS) {\n const listIds = global.chats.listIds.active;\n newOrderedPinnedIds = newOrderedPinnedIds.filter((pinnedId) => listIds && listIds.includes(pinnedId));\n }\n\n newOrderedPinnedIds = [id, ...newOrderedPinnedIds];\n }\n\n global = {\n ...global,\n chats: {\n ...global.chats,\n orderedPinnedIds: {\n ...global.chats.orderedPinnedIds,\n [listType]: newOrderedPinnedIds.length ? newOrderedPinnedIds : undefined,\n },\n },\n };\n }\n\n setGlobal(global);\n\n break;\n }\n\n case 'updateChatListType': {\n const { id, folderId } = update;\n\n setGlobal(updateChatListType(global, id, folderId));\n\n break;\n }\n\n case 'updateChatFolder': {\n const { id, folder } = update;\n const { byId: chatFoldersById, orderedIds } = global.chatFolders;\n\n const newChatFoldersById = folder\n ? { ...chatFoldersById, [id]: folder }\n : pick(\n chatFoldersById,\n Object.keys(chatFoldersById).map(Number).filter((folderId) => folderId !== id),\n );\n\n const newOrderedIds = folder\n ? orderedIds && orderedIds.includes(id) ? orderedIds : [...(orderedIds || []), id]\n : orderedIds ? orderedIds.filter((orderedId) => orderedId !== id) : undefined;\n\n setGlobal({\n ...global,\n chatFolders: {\n ...global.chatFolders,\n byId: newChatFoldersById,\n orderedIds: newOrderedIds,\n },\n });\n\n break;\n }\n\n case 'updateChatFoldersOrder': {\n const { orderedIds } = update;\n\n setGlobal({\n ...global,\n chatFolders: {\n ...global.chatFolders,\n orderedIds,\n },\n });\n\n break;\n }\n\n case 'updateRecommendedChatFolders': {\n const { folders } = update;\n\n setGlobal({\n ...global,\n chatFolders: {\n ...global.chatFolders,\n recommended: folders,\n },\n });\n\n break;\n }\n\n case 'updateChatMembers': {\n const targetChat = global.chats.byId[update.id];\n const { replacedMembers, addedMember, deletedMemberId } = update;\n if (!targetChat) {\n return;\n }\n\n let shouldUpdate = false;\n let members = targetChat.fullInfo && targetChat.fullInfo.members\n ? [...targetChat.fullInfo.members]\n : [];\n\n if (replacedMembers) {\n members = replacedMembers;\n shouldUpdate = true;\n } else if (addedMember) {\n if (\n !members.length\n || !members.some((m) => m.userId === addedMember.userId)\n ) {\n members.push(addedMember);\n shouldUpdate = true;\n }\n } else if (members.length && deletedMemberId) {\n const deleteIndex = members.findIndex((m) => m.userId === deletedMemberId);\n if (deleteIndex > -1) {\n members.slice(deleteIndex, 1);\n shouldUpdate = true;\n }\n }\n\n if (shouldUpdate) {\n const adminMembers = members.filter(({ isOwner, isAdmin }) => isOwner || isAdmin);\n // TODO Kicked members?\n\n setGlobal(updateChat(global, update.id, {\n membersCount: members.length,\n fullInfo: {\n ...targetChat.fullInfo,\n members,\n adminMembers,\n },\n }));\n }\n\n break;\n }\n\n case 'deleteProfilePhotos': {\n const { chatId, ids } = update;\n const chat = global.chats.byId[chatId];\n\n if (chat && chat.photos) {\n setGlobal(updateChat(global, chatId, {\n photos: chat.photos.filter((photo) => !ids.includes(photo.id)),\n }));\n }\n break;\n }\n\n case 'draftMessage': {\n const {\n chatId, formattedText, date, replyingToId,\n } = update;\n const chat = global.chats.byId[chatId];\n\n if (chat) {\n global = replaceThreadParam(global, chatId, MAIN_THREAD_ID, 'draft', formattedText);\n global = replaceThreadParam(global, chatId, MAIN_THREAD_ID, 'replyingToId', replyingToId);\n global = updateChat(global, chatId, { draftDate: date });\n\n setGlobal(global);\n }\n break;\n }\n\n case 'showInvite': {\n const { data } = update;\n\n actions.showDialog({ data });\n break;\n }\n }\n});\n","import { addReducer, getGlobal, setGlobal } from '../../../lib/teact/teactn';\n\nimport {\n ApiUpdate, ApiMessage, ApiPollResult, ApiThreadInfo, MAIN_THREAD_ID,\n} from '../../../api/types';\n\nimport { unique } from '../../../util/iteratees';\nimport {\n updateChat,\n deleteChatMessages,\n updateChatMessage,\n updateListedIds,\n addViewportId,\n updateThreadInfo,\n replaceThreadParam,\n updateScheduledMessage,\n deleteChatScheduledMessages,\n} from '../../reducers';\nimport { GlobalActions, GlobalState } from '../../../global/types';\nimport {\n selectChatMessage,\n selectChatMessages,\n selectIsViewportNewest,\n selectListedIds,\n selectChatMessageByPollId,\n selectCommonBoxChatId,\n selectIsChatListed,\n selectThreadInfo,\n selectThreadByMessage,\n selectPinnedIds,\n selectScheduledMessage,\n selectScheduledMessages,\n isMessageInCurrentMessageList,\n selectScheduledIds,\n selectCurrentMessageList,\n selectViewportIds,\n selectFirstUnreadId,\n selectChat,\n} from '../../selectors';\nimport { getMessageContent, isChatPrivate, isMessageLocal } from '../../helpers';\n\nconst ANIMATION_DELAY = 350;\n\naddReducer('apiUpdate', (global, actions, update: ApiUpdate) => {\n switch (update['@type']) {\n case 'newMessage': {\n const { chatId, id, message } = update;\n global = updateWithLocalMedia(global, chatId, id, message);\n global = updateListedAndViewportIds(global, message as ApiMessage);\n\n if (message.threadInfo) {\n global = updateThreadInfo(\n global,\n message.threadInfo.chatId,\n message.threadInfo.threadId,\n message.threadInfo,\n );\n }\n\n setGlobal(global);\n\n const newMessage = selectChatMessage(global, chatId, id)!;\n\n if (isMessageInCurrentMessageList(global, chatId, message as ApiMessage)) {\n if (message.isOutgoing && !(message.content && message.content.action)) {\n const currentMessageList = selectCurrentMessageList(global);\n if (currentMessageList) {\n // We do not use `actions.focusLastMessage` as it may be set with a delay (see below)\n actions.focusMessage({\n chatId,\n threadId: currentMessageList.threadId,\n messageId: message.id,\n noHighlight: true,\n });\n }\n }\n\n const { threadInfo } = selectThreadByMessage(global, chatId, message as ApiMessage) || {};\n if (threadInfo) {\n actions.requestThreadInfoUpdate({ chatId, threadId: threadInfo.threadId });\n }\n\n // @perf Wait until scroll animation finishes or simply rely on delivery status update (which is itself delayed)\n if (!isMessageLocal(message as ApiMessage)) {\n setTimeout(() => {\n setGlobal(updateChatLastMessage(getGlobal(), chatId, newMessage));\n }, ANIMATION_DELAY);\n }\n } else {\n setGlobal(updateChatLastMessage(getGlobal(), chatId, newMessage));\n }\n\n // Edge case: New message in an old (not loaded) chat.\n if (!selectIsChatListed(global, chatId)) {\n actions.loadTopChats();\n }\n\n break;\n }\n\n case 'newScheduledMessage': {\n const { chatId, id, message } = update;\n\n global = updateWithLocalMedia(global, chatId, id, message, true);\n\n const scheduledIds = selectScheduledIds(global, chatId) || [];\n global = replaceThreadParam(global, chatId, MAIN_THREAD_ID, 'scheduledIds', unique([...scheduledIds, id]));\n\n setGlobal(global);\n\n break;\n }\n\n case 'updateMessage': {\n const { chatId, id, message } = update;\n\n const currentMessage = selectChatMessage(global, chatId, id);\n if (!currentMessage) {\n return;\n }\n\n global = updateWithLocalMedia(global, chatId, id, message);\n\n const newMessage = selectChatMessage(global, chatId, id)!;\n if (message.threadInfo) {\n global = updateThreadInfo(\n global,\n message.threadInfo.chatId,\n message.threadInfo.threadId,\n message.threadInfo,\n );\n }\n global = updateChatLastMessage(global, chatId, newMessage);\n\n setGlobal(global);\n\n break;\n }\n\n case 'updateScheduledMessage': {\n const { chatId, id, message } = update;\n\n const currentMessage = selectScheduledMessage(global, chatId, id);\n if (!currentMessage) {\n return;\n }\n\n global = updateWithLocalMedia(global, chatId, id, message, true);\n const ids = Object.keys(selectScheduledMessages(global, chatId) || {}).map(Number).sort((a, b) => b - a);\n global = replaceThreadParam(global, chatId, MAIN_THREAD_ID, 'scheduledIds', ids);\n setGlobal(global);\n\n break;\n }\n\n case 'updateMessageSendSucceeded': {\n const { chatId, localId, message } = update;\n\n global = updateListedAndViewportIds(global, message as ApiMessage);\n\n const currentMessage = selectChatMessage(global, chatId, localId);\n\n global = deleteChatMessages(global, chatId, [localId]);\n\n // Edge case for \"Send When Online\"\n if (message.isScheduled) {\n global = deleteChatScheduledMessages(global, chatId, [localId]);\n }\n\n global = updateChatMessage(global, chatId, message.id, {\n ...currentMessage,\n ...message,\n previousLocalId: localId,\n });\n\n const newMessage = selectChatMessage(global, chatId, message.id)!;\n global = updateChatLastMessage(global, chatId, newMessage);\n\n const thread = selectThreadByMessage(global, chatId, message);\n // For some reason Telegram requires to manually mark outgoing thread messages read\n // For some reason Telegram requires to manually mark outgoing thread messages read\n if (thread && thread.threadInfo) {\n actions.markMessageListRead({ maxId: message.id });\n\n global = replaceThreadParam(global, chatId, thread.threadInfo.threadId, 'threadInfo', {\n ...thread.threadInfo,\n lastMessageId: message.id,\n lastReadInboxMessageId: message.id,\n });\n }\n\n setGlobal(global);\n\n break;\n }\n\n case 'updateScheduledMessageSendSucceeded': {\n const { chatId, localId, message } = update;\n const scheduledIds = selectScheduledIds(global, chatId) || [];\n global = replaceThreadParam(global, chatId, MAIN_THREAD_ID, 'scheduledIds', [...scheduledIds, message.id]);\n\n const currentMessage = selectScheduledMessage(global, chatId, localId);\n\n global = deleteChatScheduledMessages(global, chatId, [localId]);\n global = updateScheduledMessage(global, chatId, message.id, {\n ...currentMessage,\n ...message,\n previousLocalId: localId,\n });\n\n setGlobal(global);\n break;\n }\n\n case 'updatePinnedIds': {\n const { chatId, isPinned, messageIds } = update;\n\n const currentPinnedIds = selectPinnedIds(global, chatId) || [];\n const newPinnedIds = isPinned\n ? [...currentPinnedIds, ...messageIds].sort((a, b) => b - a)\n : currentPinnedIds.filter((id) => !messageIds.includes(id));\n\n setGlobal(replaceThreadParam(global, chatId, MAIN_THREAD_ID, 'pinnedIds', newPinnedIds));\n\n break;\n }\n\n case 'updateThreadInfo': {\n const {\n chatId, threadId, threadInfo, firstMessageId,\n } = update;\n\n const currentThreadInfo = selectThreadInfo(global, chatId, threadId);\n const newTheadInfo = {\n ...currentThreadInfo,\n ...threadInfo,\n };\n\n if (!newTheadInfo.threadId) {\n return;\n }\n\n global = updateThreadInfo(global, chatId, threadId, newTheadInfo as ApiThreadInfo);\n\n if (firstMessageId) {\n global = replaceThreadParam(global, chatId, threadId, 'firstMessageId', firstMessageId);\n }\n\n setGlobal(global);\n\n break;\n }\n\n case 'resetMessages': {\n const { id: chatId } = update;\n const messagesById = selectChatMessages(global, chatId);\n\n if (messagesById && !isChatPrivate(chatId)) {\n global = deleteChatMessages(global, chatId, Object.keys(messagesById).map(Number));\n setGlobal(global);\n actions.loadFullChat({ chatId, force: true });\n }\n\n break;\n }\n\n case 'deleteMessages': {\n const { ids, chatId } = update;\n\n deleteMessages(chatId, ids, actions, global);\n break;\n }\n\n case 'deleteScheduledMessages': {\n const { ids, chatId } = update;\n\n deleteScheduledMessages(chatId, ids, actions, global);\n break;\n }\n\n case 'deleteHistory': {\n const { chatId } = update;\n const chatMessages = global.messages.byChatId[chatId];\n if (chatMessages) {\n const ids = Object.keys(chatMessages.byId).map(Number);\n deleteMessages(chatId, ids, actions, global);\n } else {\n actions.requestChatUpdate({ chatId });\n }\n\n break;\n }\n\n case 'updateCommonBoxMessages': {\n const { ids, messageUpdate } = update;\n\n ids.forEach((id) => {\n const chatId = selectCommonBoxChatId(global, id);\n if (chatId) {\n global = updateChatMessage(global, chatId, id, messageUpdate);\n }\n });\n\n setGlobal(global);\n\n break;\n }\n\n case 'updateChannelMessages': {\n const { channelId, ids, messageUpdate } = update;\n\n ids.forEach((id) => {\n global = updateChatMessage(global, channelId, id, messageUpdate);\n });\n\n setGlobal(global);\n\n break;\n }\n\n case 'updateMessagePoll': {\n const { pollId, pollUpdate } = update;\n\n const message = selectChatMessageByPollId(global, pollId);\n\n if (message && message.content.poll) {\n const updatedPoll = { ...message.content.poll, ...pollUpdate };\n\n // Workaround for poll update bug: `chosen` option gets reset when someone votes after current user\n const { results: updatedResults } = updatedPoll.results || {};\n if (updatedResults && !updatedResults.some(((result) => result.isChosen))) {\n const { results } = message.content.poll.results;\n const chosenAnswers = results && results.filter((result) => result.isChosen);\n if (chosenAnswers) {\n chosenAnswers.forEach((chosenAnswer) => {\n const chosenAnswerIndex = updatedResults.findIndex((result) => result.option === chosenAnswer.option);\n if (chosenAnswerIndex >= 0) {\n updatedPoll.results.results![chosenAnswerIndex].isChosen = true;\n }\n });\n }\n }\n\n setGlobal(updateChatMessage(\n global,\n message.chatId,\n message.id,\n {\n content: {\n ...message.content,\n poll: updatedPoll,\n },\n },\n ));\n }\n break;\n }\n\n case 'updateMessagePollVote': {\n const { pollId, userId, options } = update;\n const message = selectChatMessageByPollId(global, pollId);\n if (!message || !message.content.poll || !message.content.poll.results) {\n break;\n }\n\n const { poll } = message.content;\n\n const { recentVoterIds, totalVoters, results } = poll.results;\n const newRecentVoterIds = recentVoterIds ? [...recentVoterIds] : [];\n const newTotalVoters = totalVoters ? totalVoters + 1 : 1;\n const newResults = results ? [...results] : [];\n\n newRecentVoterIds.push(userId);\n\n options.forEach((option) => {\n const targetOption = newResults.find((result) => result.option === option);\n const targetOptionIndex = newResults.findIndex((result) => result.option === option);\n const updatedOption: ApiPollResult = targetOption ? { ...targetOption } : { option, votersCount: 0 };\n\n updatedOption.votersCount += 1;\n if (userId === global.currentUserId) {\n updatedOption.isChosen = true;\n }\n\n if (targetOptionIndex) {\n newResults[targetOptionIndex] = updatedOption;\n } else {\n newResults.push(updatedOption);\n }\n });\n\n setGlobal(updateChatMessage(\n global,\n message.chatId,\n message.id,\n {\n content: {\n ...message.content,\n poll: {\n ...poll,\n results: {\n ...poll.results,\n recentVoterIds: newRecentVoterIds,\n totalVoters: newTotalVoters,\n results: newResults,\n },\n },\n },\n },\n ));\n\n break;\n }\n }\n});\n\nfunction updateWithLocalMedia(\n global: GlobalState, chatId: number, id: number, message: Partial<ApiMessage>, isScheduled = false,\n) {\n // Preserve locally uploaded media.\n const currentMessage = isScheduled\n ? selectScheduledMessage(global, chatId, id)\n : selectChatMessage(global, chatId, id);\n if (currentMessage && message.content) {\n const {\n photo, video, sticker, document,\n } = getMessageContent(currentMessage);\n if (photo && message.content.photo) {\n message.content.photo.blobUrl = photo.blobUrl;\n message.content.photo.thumbnail = photo.thumbnail;\n } else if (video && message.content.video) {\n message.content.video.blobUrl = video.blobUrl;\n } else if (sticker && message.content.sticker) {\n message.content.sticker.isPreloadedGlobally = sticker.isPreloadedGlobally;\n } else if (document && message.content.document) {\n message.content.document.previewBlobUrl = document.previewBlobUrl;\n }\n }\n\n return isScheduled\n ? updateScheduledMessage(global, chatId, id, message)\n : updateChatMessage(global, chatId, id, message);\n}\n\nfunction updateListedAndViewportIds(global: GlobalState, message: ApiMessage) {\n const { id, chatId } = message;\n\n const { threadInfo, firstMessageId } = selectThreadByMessage(global, chatId, message) || {};\n\n const chat = selectChat(global, chatId);\n const isUnreadChatNotLoaded = chat && chat.unreadCount && !selectListedIds(global, chatId, MAIN_THREAD_ID);\n\n if (threadInfo) {\n if (firstMessageId || !isMessageLocal(message)) {\n global = updateListedIds(global, chatId, threadInfo.threadId, [id]);\n\n if (selectIsViewportNewest(global, chatId, threadInfo.threadId)) {\n global = addViewportId(global, chatId, threadInfo.threadId, id);\n\n if (!firstMessageId) {\n global = replaceThreadParam(global, chatId, threadInfo.threadId, 'firstMessageId', message.id);\n }\n }\n }\n\n global = replaceThreadParam(global, chatId, threadInfo.threadId, 'threadInfo', {\n ...threadInfo,\n lastMessageId: message.id,\n messagesCount: threadInfo.messagesCount + 1,\n });\n }\n\n if (isUnreadChatNotLoaded) {\n return global;\n }\n\n global = updateListedIds(global, chatId, MAIN_THREAD_ID, [id]);\n\n if (selectIsViewportNewest(global, chatId, MAIN_THREAD_ID)) {\n // Always keep the first unread message in the viewport list\n const firstUnreadId = selectFirstUnreadId(global, chatId, MAIN_THREAD_ID);\n const newGlobal = addViewportId(global, chatId, MAIN_THREAD_ID, id);\n const newViewportIds = selectViewportIds(newGlobal, chatId, MAIN_THREAD_ID);\n\n if (!firstUnreadId || newViewportIds!.includes(firstUnreadId)) {\n global = newGlobal;\n }\n }\n\n return global;\n}\n\nfunction updateChatLastMessage(\n global: GlobalState,\n chatId: number,\n message: ApiMessage,\n force = false,\n) {\n const { chats } = global;\n const currentLastMessage = chats.byId[chatId] && chats.byId[chatId].lastMessage;\n\n if (currentLastMessage && !force) {\n const isSameOrNewer = (\n currentLastMessage.id === message.id || currentLastMessage.id === message.previousLocalId\n ) || message.id > currentLastMessage.id;\n\n if (!isSameOrNewer) {\n return global;\n }\n }\n\n return updateChat(global, chatId, { lastMessage: message });\n}\n\nfunction findLastMessage(global: GlobalState, chatId: number) {\n const byId = selectChatMessages(global, chatId);\n const listedIds = selectListedIds(global, chatId, MAIN_THREAD_ID);\n\n if (!byId || !listedIds) {\n return undefined;\n }\n\n let i = listedIds.length;\n while (i--) {\n const message = byId[listedIds[i]];\n if (!message.isDeleting) {\n return message;\n }\n }\n\n return undefined;\n}\n\nfunction deleteMessages(chatId: number | undefined, ids: number[], actions: GlobalActions, global: GlobalState) {\n // Channel update\n\n if (chatId) {\n ids.forEach((id) => {\n global = updateChatMessage(global, chatId, id, {\n isDeleting: true,\n });\n\n const newLastMessage = findLastMessage(global, chatId);\n if (newLastMessage) {\n global = updateChatLastMessage(global, chatId, newLastMessage, true);\n }\n });\n\n setGlobal(global);\n\n actions.requestChatUpdate({ chatId });\n\n const threadIdsToUpdate: number[] = [];\n\n ids.forEach((id) => {\n const message = selectChatMessage(global, chatId, id);\n if (!message) {\n return;\n }\n\n const { threadInfo } = selectThreadByMessage(global, chatId, message) || {};\n if (threadInfo) {\n threadIdsToUpdate.push(threadInfo.threadId);\n }\n });\n\n setTimeout(() => {\n setGlobal(deleteChatMessages(getGlobal(), chatId, ids));\n\n unique(threadIdsToUpdate).forEach((threadId) => {\n actions.requestThreadInfoUpdate({ chatId, threadId });\n });\n }, ANIMATION_DELAY);\n\n return;\n }\n\n // Common box update\n\n const chatsIdsToUpdate: number[] = [];\n\n ids.forEach((id) => {\n const commonBoxChatId = selectCommonBoxChatId(global, id);\n if (commonBoxChatId) {\n chatsIdsToUpdate.push(commonBoxChatId);\n\n global = updateChatMessage(global, commonBoxChatId, id, {\n isDeleting: true,\n });\n\n const newLastMessage = findLastMessage(global, commonBoxChatId);\n if (newLastMessage) {\n global = updateChatLastMessage(global, commonBoxChatId, newLastMessage, true);\n }\n\n setTimeout(() => {\n setGlobal(deleteChatMessages(getGlobal(), commonBoxChatId, [id]));\n }, ANIMATION_DELAY);\n }\n });\n\n setGlobal(global);\n\n unique(chatsIdsToUpdate).forEach((id) => {\n actions.requestChatUpdate({ chatId: id });\n });\n}\n\nfunction deleteScheduledMessages(\n chatId: number | undefined, ids: number[], actions: GlobalActions, global: GlobalState,\n) {\n if (!chatId) {\n return;\n }\n\n ids.forEach((id) => {\n global = updateScheduledMessage(global, chatId, id, {\n isDeleting: true,\n });\n });\n\n setGlobal(global);\n\n setTimeout(() => {\n global = deleteChatScheduledMessages(getGlobal(), chatId, ids);\n const scheduledMessages = selectScheduledMessages(global, chatId);\n global = replaceThreadParam(\n global, chatId, MAIN_THREAD_ID, 'scheduledIds', Object.keys(scheduledMessages || {}).map(Number),\n );\n setGlobal(global);\n }, ANIMATION_DELAY);\n}\n","import { addReducer, getGlobal, setGlobal } from '../../../lib/teact/teactn';\n\nimport { ApiUpdate, ApiUserStatus } from '../../../api/types';\n\nimport { deleteUser, updateUser } from '../../reducers';\nimport { throttle } from '../../../util/schedulers';\n\nconst STATUS_UPDATE_THROTTLE = 3000;\n\nconst flushStatusUpdatesThrottled = throttle(flushStatusUpdates, STATUS_UPDATE_THROTTLE, true);\n\nlet pendingStatusUpdates: [number, ApiUserStatus][] = [];\n\nfunction scheduleStatusUpdate(userId: number, statusUpdate: ApiUserStatus) {\n pendingStatusUpdates.push([userId, statusUpdate]);\n flushStatusUpdatesThrottled();\n}\n\nfunction flushStatusUpdates() {\n let global = getGlobal();\n pendingStatusUpdates.forEach(([userId, statusUpdate]) => {\n global = updateUser(global, userId, {\n status: statusUpdate,\n });\n });\n setGlobal(global);\n\n pendingStatusUpdates = [];\n}\n\naddReducer('apiUpdate', (global, actions, update: ApiUpdate) => {\n switch (update['@type']) {\n case 'deleteUser': {\n return deleteUser(global, update.id);\n }\n\n case 'updateUser': {\n return updateUser(global, update.id, update.user);\n }\n\n case 'updateUserStatus': {\n // Status updates come very often so we throttle them\n scheduleStatusUpdate(update.userId, update.status);\n return undefined;\n }\n\n case 'updateUserFullInfo': {\n const { id, fullInfo } = update;\n const targetUser = global.users.byId[id];\n if (!targetUser) {\n return undefined;\n }\n\n return updateUser(global, id, {\n fullInfo: {\n ...targetUser.fullInfo,\n ...fullInfo,\n },\n });\n }\n }\n\n return undefined;\n});\n","import { addReducer } from '../../../lib/teact/teactn';\n\nimport { ApiUpdate } from '../../../api/types';\n\nimport { updateStickerSet } from '../../reducers';\n\naddReducer('apiUpdate', (global, actions, update: ApiUpdate) => {\n switch (update['@type']) {\n case 'updateStickerSet': {\n return updateStickerSet(global, update.id, update.stickerSet);\n }\n }\n\n return undefined;\n});\n","import {\n addReducer, getGlobal, setGlobal,\n} from '../../../lib/teact/teactn';\n\nimport { ApiUpdate } from '../../../api/types';\nimport { ApiPrivacyKey } from '../../../types';\n\nimport { addBlockedContact, removeBlockedContact } from '../../reducers';\n\naddReducer('apiUpdate', (global, actions, update: ApiUpdate) => {\n switch (update['@type']) {\n case 'updatePeerBlocked':\n if (update.isBlocked) {\n return addBlockedContact(getGlobal(), update.id);\n } else {\n return removeBlockedContact(getGlobal(), update.id);\n }\n\n case 'updateResetContactList':\n setGlobal({\n ...getGlobal(),\n contactList: {\n hash: 0,\n userIds: [],\n },\n });\n break;\n\n case 'updateFavoriteStickers':\n actions.loadFavoriteStickers();\n break;\n\n case 'updatePrivacy':\n global.settings.privacy[update.key as ApiPrivacyKey] = update.rules;\n break;\n }\n\n return undefined;\n});\n","import { addReducer, setGlobal } from '../../../lib/teact/teactn';\n\nimport { ApiUpdate } from '../../../api/types';\nimport { GlobalState } from '../../../global/types';\nimport { addNotifyException, updateChat, updateNotifySettings } from '../../reducers';\n\naddReducer('apiUpdate', (global, actions, update: ApiUpdate): GlobalState | undefined => {\n switch (update['@type']) {\n case 'updateNotifySettings': {\n return updateNotifySettings(global, update.peerType, update.isSilent, update.shouldShowPreviews);\n }\n\n case 'updateNotifyExceptions': {\n const {\n chatId, isMuted, isSilent, shouldShowPreviews,\n } = update;\n const chat = global.chats.byId[chatId];\n\n if (chat) {\n global = updateChat(global, chatId, { isMuted });\n }\n\n setGlobal(addNotifyException(global, chatId, { isMuted, isSilent, shouldShowPreviews }));\n break;\n }\n }\n\n return undefined;\n});\n","import { addReducer } from '../../../lib/teact/teactn';\n\nimport { ApiUpdate } from '../../../api/types';\nimport { GlobalState } from '../../../global/types';\n\naddReducer('apiUpdate', (global, actions, update: ApiUpdate): GlobalState | undefined => {\n switch (update['@type']) {\n case 'updateTwoFaStateWaitCode': {\n return {\n ...global,\n twoFaSettings: {\n ...global.twoFaSettings,\n isLoading: false,\n waitingEmailCodeLength: update.length,\n },\n };\n }\n\n case 'updateTwoFaError': {\n return {\n ...global,\n twoFaSettings: {\n ...global.twoFaSettings,\n error: update.message,\n },\n };\n }\n }\n\n return undefined;\n});\n","import { useEffect } from '../lib/teact/teact';\n\nimport { onBeforeUnload } from '../util/schedulers';\n\nexport default function useBeforeUnload(callback: AnyToVoidFunction) {\n useEffect(() => {\n return onBeforeUnload(callback);\n }, [callback]);\n}\n","import { ChangeEvent } from 'react';\nimport React, { FC, memo, useCallback } from '../../lib/teact/teact';\n\nimport buildClassName from '../../util/buildClassName';\n\nimport './Switcher.scss';\n\ntype OwnProps = {\n id?: string;\n name?: string;\n value?: string;\n label: string;\n checked?: boolean;\n disabled?: boolean;\n inactive?: boolean;\n noAnimation?: boolean;\n onChange?: (e: ChangeEvent<HTMLInputElement>) => void;\n onCheck?: (isChecked: boolean) => void;\n};\n\nconst Switcher: FC<OwnProps> = ({\n id,\n name,\n value,\n label,\n checked = false,\n disabled,\n inactive,\n noAnimation,\n onChange,\n onCheck,\n}) => {\n const handleChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {\n if (onChange) {\n onChange(e);\n }\n\n if (onCheck) {\n onCheck(e.currentTarget.checked);\n }\n }, [onChange, onCheck]);\n\n const className = buildClassName(\n 'Switcher',\n disabled && 'disabled',\n inactive && 'inactive',\n noAnimation && 'no-animation',\n );\n\n return (\n <label className={className} title={label}>\n <input\n type=\"checkbox\"\n id={id}\n name={name}\n value={value}\n checked={checked}\n disabled={disabled}\n onChange={handleChange}\n />\n <span className=\"widget\" />\n </label>\n );\n};\n\nexport default memo(Switcher);\n","import React, {\n FC, useCallback, useMemo, memo,\n} from '../../../lib/teact/teact';\nimport { withGlobal } from '../../../lib/teact/teactn';\n\nimport { GlobalActions } from '../../../global/types';\nimport { LeftColumnContent, ISettings } from '../../../types';\nimport { ApiChat } from '../../../api/types';\n\nimport {\n ANIMATION_LEVEL_MAX, APP_NAME, APP_VERSION, FEEDBACK_URL,\n} from '../../../config';\nimport { IS_SINGLE_COLUMN_LAYOUT } from '../../../util/environment';\nimport buildClassName from '../../../util/buildClassName';\nimport { pick } from '../../../util/iteratees';\nimport { isChatArchived } from '../../../modules/helpers';\nimport { formatDateToString } from '../../../util/dateFormat';\nimport { selectTheme } from '../../../modules/selectors';\nimport switchTheme from '../../../util/switchTheme';\nimport useLang from '../../../hooks/useLang';\nimport { disableHistoryBack } from '../../../hooks/useHistoryBack';\n\nimport DropdownMenu from '../../ui/DropdownMenu';\nimport MenuItem from '../../ui/MenuItem';\nimport Button from '../../ui/Button';\nimport SearchInput from '../../ui/SearchInput';\nimport PickerSelectedItem from '../../common/PickerSelectedItem';\nimport Switcher from '../../ui/Switcher';\n\nimport './LeftMainHeader.scss';\n\ntype OwnProps = {\n content: LeftColumnContent;\n contactsFilter: string;\n shouldSkipTransition?: boolean;\n onSearchQuery: (query: string) => void;\n onSelectSettings: () => void;\n onSelectContacts: () => void;\n onSelectArchived: () => void;\n onReset: () => void;\n};\n\ntype StateProps = {\n searchQuery?: string;\n isLoading: boolean;\n currentUserId?: number;\n globalSearchChatId?: number;\n searchDate?: number;\n theme: ISettings['theme'];\n animationLevel: 0 | 1 | 2;\n chatsById?: Record<number, ApiChat>;\n};\n\ntype DispatchProps = Pick<GlobalActions, (\n 'openChat' | 'openTipsChat' | 'setGlobalSearchDate' | 'setGlobalSearchChatId' | 'setSettingOption'\n)>;\n\nconst ANIMATION_LEVEL_OPTIONS = [0, 1, 2];\n\nconst PRODUCTION_HOSTNAME = 'web.telegram.org';\nconst LEGACY_VERSION_URL = 'https://web.telegram.org/?legacy=1';\nconst WEBK_VERSION_URL = 'https://web.telegram.org/k/';\nconst PERMANENT_VERSION_KEY = 'kz_version';\n\nconst LeftMainHeader: FC<OwnProps & StateProps & DispatchProps> = ({\n content,\n contactsFilter,\n onSearchQuery,\n onSelectSettings,\n onSelectContacts,\n onSelectArchived,\n setGlobalSearchChatId,\n onReset,\n searchQuery,\n isLoading,\n shouldSkipTransition,\n currentUserId,\n globalSearchChatId,\n searchDate,\n theme,\n animationLevel,\n chatsById,\n openChat,\n openTipsChat,\n setGlobalSearchDate,\n setSettingOption,\n}) => {\n const lang = useLang();\n const hasMenu = content === LeftColumnContent.ChatList;\n const clearedDateSearchParam = { date: undefined };\n const clearedChatSearchParam = { id: undefined };\n const selectedSearchDate = useMemo(() => {\n return searchDate\n ? formatDateToString(new Date(searchDate * 1000))\n : undefined;\n }, [searchDate]);\n const archivedUnreadChatsCount = useMemo(() => {\n if (!hasMenu || !chatsById) {\n return 0;\n }\n\n return Object.values(chatsById).reduce((total, chat) => {\n if (!isChatArchived(chat)) {\n return total;\n }\n\n return chat.unreadCount ? total + 1 : total;\n }, 0);\n }, [hasMenu, chatsById]);\n\n const withOtherVersions = window.location.hostname === PRODUCTION_HOSTNAME;\n\n const MainButton: FC<{ onTrigger: () => void; isOpen?: boolean }> = useMemo(() => {\n return ({ onTrigger, isOpen }) => (\n <Button\n round\n ripple={hasMenu && !IS_SINGLE_COLUMN_LAYOUT}\n size=\"smaller\"\n color=\"translucent\"\n className={isOpen ? 'active' : ''}\n onClick={hasMenu ? onTrigger : () => onReset()}\n ariaLabel={hasMenu ? lang('AccDescrOpenMenu2') : 'Return to chat list'}\n >\n <div className={buildClassName(\n 'animated-menu-icon',\n !hasMenu && 'state-back',\n shouldSkipTransition && 'no-animation',\n )}\n />\n </Button>\n );\n }, [hasMenu, lang, onReset, shouldSkipTransition]);\n\n const handleSearchFocus = useCallback(() => {\n if (!searchQuery) {\n onSearchQuery('');\n }\n }, [searchQuery, onSearchQuery]);\n\n const handleSelectSaved = useCallback(() => {\n openChat({ id: currentUserId, shouldReplaceHistory: true });\n }, [currentUserId, openChat]);\n\n const handleDarkModeToggle = useCallback((e: React.SyntheticEvent<HTMLElement>) => {\n e.stopPropagation();\n const newTheme = theme === 'light' ? 'dark' : 'light';\n\n setSettingOption({ theme: newTheme });\n setSettingOption({ shouldUseSystemTheme: false });\n switchTheme(newTheme, animationLevel === ANIMATION_LEVEL_MAX);\n }, [animationLevel, setSettingOption, theme]);\n\n const handleAnimationLevelChange = useCallback((e: React.SyntheticEvent<HTMLElement>) => {\n e.stopPropagation();\n\n const newLevel = animationLevel === 0 ? 2 : 0;\n ANIMATION_LEVEL_OPTIONS.forEach((_, i) => {\n document.body.classList.toggle(`animation-level-${i}`, newLevel === i);\n });\n\n setSettingOption({ animationLevel: newLevel });\n }, [animationLevel, setSettingOption]);\n\n const handleSwitchToWebK = () => {\n localStorage.setItem(PERMANENT_VERSION_KEY, JSON.stringify('K'));\n disableHistoryBack();\n };\n\n const handleOpenTipsChat = () => {\n openTipsChat({ langCode: lang.code });\n };\n\n const isSearchFocused = (\n Boolean(globalSearchChatId)\n || content === LeftColumnContent.GlobalSearch\n || content === LeftColumnContent.Contacts\n );\n\n const searchInputPlaceholder = content === LeftColumnContent.Contacts\n ? lang('SearchFriends')\n : lang('Search');\n\n return (\n <div className=\"LeftMainHeader\">\n <div id=\"LeftMainHeader\" className=\"left-header\">\n <DropdownMenu\n trigger={MainButton}\n footer={`${APP_NAME} alpha ${APP_VERSION}`}\n >\n <MenuItem\n icon=\"saved-messages\"\n onClick={handleSelectSaved}\n >\n {lang('SavedMessages')}\n </MenuItem>\n <MenuItem\n icon=\"archive\"\n onClick={onSelectArchived}\n >\n <span className=\"menu-item-name\">{lang('ArchivedChats')}</span>\n {archivedUnreadChatsCount > 0 && (\n <div className=\"archived-badge\">{archivedUnreadChatsCount}</div>\n )}\n </MenuItem>\n <MenuItem\n icon=\"user\"\n onClick={onSelectContacts}\n >\n {lang('Contacts')}\n </MenuItem>\n <MenuItem\n icon=\"settings\"\n onClick={onSelectSettings}\n >\n {lang('Settings')}\n </MenuItem>\n <MenuItem\n icon=\"darkmode\"\n onClick={handleDarkModeToggle}\n >\n <span className=\"menu-item-name\">{lang('lng_menu_night_mode')}</span>\n <Switcher\n id=\"darkmode\"\n label={lang(theme === 'dark' ? 'lng_settings_disable_night_theme' : 'lng_settings_enable_night_theme')}\n checked={theme === 'dark'}\n noAnimation\n />\n </MenuItem>\n <MenuItem\n icon=\"animations\"\n onClick={handleAnimationLevelChange}\n >\n <span className=\"menu-item-name capitalize\">{lang('Appearance.Animations').toLowerCase()}</span>\n <Switcher\n id=\"animations\"\n label=\"Toggle Animations\"\n checked={animationLevel > 0}\n />\n </MenuItem>\n <MenuItem\n icon=\"help\"\n onClick={handleOpenTipsChat}\n >\n {lang('TelegramFeatures')}\n </MenuItem>\n <MenuItem\n icon=\"bug\"\n href={FEEDBACK_URL}\n >\n Report Bug\n </MenuItem>\n {withOtherVersions && (\n <>\n <MenuItem\n icon=\"char-K\"\n href={WEBK_VERSION_URL}\n onClick={handleSwitchToWebK}\n >\n Switch to K Version\n </MenuItem>\n <MenuItem\n icon=\"char-W\"\n href={LEGACY_VERSION_URL}\n onClick={disableHistoryBack}\n >\n Switch to Old Version\n </MenuItem>\n </>\n )}\n </DropdownMenu>\n <SearchInput\n inputId=\"telegram-search-input\"\n parentContainerClassName=\"LeftSearch\"\n className={globalSearchChatId || searchDate ? 'with-picker-item' : ''}\n value={contactsFilter || searchQuery}\n focused={isSearchFocused}\n isLoading={isLoading}\n placeholder={searchInputPlaceholder}\n autoComplete=\"off\"\n canClose={Boolean(globalSearchChatId || searchDate)}\n onChange={onSearchQuery}\n onReset={onReset}\n onFocus={handleSearchFocus}\n >\n {selectedSearchDate && (\n <PickerSelectedItem\n icon=\"calendar\"\n title={selectedSearchDate}\n canClose\n isMinimized={Boolean(globalSearchChatId)}\n className=\"search-date\"\n onClick={setGlobalSearchDate}\n clickArg={clearedDateSearchParam}\n />\n )}\n {globalSearchChatId && (\n <PickerSelectedItem\n chatOrUserId={globalSearchChatId}\n onClick={setGlobalSearchChatId}\n canClose\n clickArg={clearedChatSearchParam}\n />\n )}\n </SearchInput>\n </div>\n </div>\n );\n};\n\nexport default memo(withGlobal<OwnProps>(\n (global): StateProps => {\n const {\n query: searchQuery, fetchingStatus, chatId, date,\n } = global.globalSearch;\n const { currentUserId } = global;\n const { byId: chatsById } = global.chats;\n const { animationLevel } = global.settings.byKey;\n\n return {\n searchQuery,\n isLoading: fetchingStatus ? Boolean(fetchingStatus.chats || fetchingStatus.messages) : false,\n currentUserId,\n chatsById,\n globalSearchChatId: chatId,\n searchDate: date,\n theme: selectTheme(global),\n animationLevel,\n };\n },\n (setGlobal, actions): DispatchProps => pick(actions, [\n 'openChat',\n 'openTipsChat',\n 'setGlobalSearchDate',\n 'setGlobalSearchChatId',\n 'setSettingOption',\n ]),\n)(LeftMainHeader));\n","import React, { memo, FC } from '../../lib/teact/teact';\n\nimport { GlobalState } from '../../global/types';\n\nimport useLang from '../../hooks/useLang';\n\nimport Spinner from '../ui/Spinner';\n\nimport './ConnectionState.scss';\n\ntype StateProps = Pick<GlobalState, 'connectionState'>;\n\nconst ConnectionState: FC<StateProps> = () => {\n const lang = useLang();\n\n return (\n <div id=\"ConnectionState\" dir={lang.isRtl ? 'rtl' : undefined}>\n <Spinner color=\"black\" />\n <div className=\"state-text\">{lang('WaitingForNetwork')}</div>\n </div>\n );\n};\n\nexport default memo(ConnectionState);\n","import { useState } from '../lib/teact/teact';\n\nimport useThrottle from './useThrottle';\nimport useOnChange from './useOnChange';\nimport useHeavyAnimationCheck from './useHeavyAnimationCheck';\nimport useFlag from './useFlag';\n\nexport default <R extends any, D extends any[]>(resolverFn: () => R, ms: number, dependencies: D) => {\n const runThrottled = useThrottle(ms, true);\n const [value, setValue] = useState<R>();\n const [isFrozen, freeze, unfreeze] = useFlag();\n\n useHeavyAnimationCheck(freeze, unfreeze);\n\n useOnChange(() => {\n if (isFrozen) {\n return;\n }\n\n runThrottled(() => {\n setValue(resolverFn());\n });\n }, dependencies.concat([isFrozen]));\n\n return value;\n};\n","import { useMemo } from '../lib/teact/teact';\n\nimport { throttle } from '../util/schedulers';\n\nexport default (ms: number, noFirst = false) => {\n return useMemo(() => {\n return throttle((cb) => cb(), ms, !noFirst);\n }, [ms, noFirst]);\n};\n","import React, {\n FC, memo, useCallback, useEffect, useMemo, useRef,\n} from '../../../lib/teact/teact';\nimport { withGlobal } from '../../../lib/teact/teactn';\n\nimport { ApiChat, ApiChatFolder, ApiUser } from '../../../api/types';\nimport { GlobalActions } from '../../../global/types';\nimport { NotifyException, NotifySettings } from '../../../types';\n\nimport { IS_TOUCH_ENV } from '../../../util/environment';\nimport { buildCollectionByKey, pick } from '../../../util/iteratees';\nimport { captureEvents, SwipeDirection } from '../../../util/captureEvents';\nimport { getFolderUnreadDialogs } from '../../../modules/helpers';\nimport { selectNotifyExceptions, selectNotifySettings } from '../../../modules/selectors';\nimport useShowTransition from '../../../hooks/useShowTransition';\nimport buildClassName from '../../../util/buildClassName';\nimport useThrottledMemo from '../../../hooks/useThrottledMemo';\nimport useLang from '../../../hooks/useLang';\nimport useHistoryBack from '../../../hooks/useHistoryBack';\nimport captureEscKeyListener from '../../../util/captureEscKeyListener';\n\nimport Transition from '../../ui/Transition';\nimport TabList from '../../ui/TabList';\nimport ChatList from './ChatList';\n\ntype StateProps = {\n chatsById: Record<number, ApiChat>;\n usersById: Record<number, ApiUser>;\n chatFoldersById: Record<number, ApiChatFolder>;\n notifySettings: NotifySettings;\n notifyExceptions?: Record<number, NotifyException>;\n orderedFolderIds?: number[];\n activeChatFolder: number;\n currentUserId?: number;\n lastSyncTime?: number;\n};\n\ntype DispatchProps = Pick<GlobalActions, 'loadChatFolders' | 'setActiveChatFolder' | 'openChat'>;\n\nconst INFO_THROTTLE = 3000;\nconst SAVED_MESSAGES_HOTKEY = '0';\n\nconst ChatFolders: FC<StateProps & DispatchProps> = ({\n chatsById,\n usersById,\n chatFoldersById,\n notifySettings,\n notifyExceptions,\n orderedFolderIds,\n activeChatFolder,\n currentUserId,\n lastSyncTime,\n loadChatFolders,\n setActiveChatFolder,\n openChat,\n}) => {\n // eslint-disable-next-line no-null/no-null\n const transitionRef = useRef<HTMLDivElement>(null);\n\n const lang = useLang();\n\n useEffect(() => {\n if (lastSyncTime) {\n loadChatFolders();\n }\n }, [lastSyncTime, loadChatFolders]);\n\n const displayedFolders = useMemo(() => {\n return orderedFolderIds\n ? orderedFolderIds.map((id) => chatFoldersById[id] || {}).filter(Boolean)\n : undefined;\n }, [chatFoldersById, orderedFolderIds]);\n\n const folderCountersById = useThrottledMemo(() => {\n if (!displayedFolders || !displayedFolders.length) {\n return undefined;\n }\n\n const chatIds = Object.keys(chatsById).map(Number);\n const counters = displayedFolders.map((folder) => {\n const {\n unreadDialogsCount, hasActiveDialogs,\n } = getFolderUnreadDialogs(chatsById, usersById, folder, chatIds, notifySettings, notifyExceptions) || {};\n\n return {\n id: folder.id,\n badgeCount: unreadDialogsCount,\n isBadgeActive: hasActiveDialogs,\n };\n });\n\n return buildCollectionByKey(counters, 'id');\n }, INFO_THROTTLE, [displayedFolders, chatsById, usersById, notifySettings, notifyExceptions]);\n\n const folderTabs = useMemo(() => {\n if (!displayedFolders || !displayedFolders.length) {\n return undefined;\n }\n\n return [\n { title: lang.code === 'en' ? 'All' : lang('FilterAllChats') },\n ...displayedFolders.map((folder) => ({\n title: folder.title,\n ...(folderCountersById && folderCountersById[folder.id]),\n })),\n ];\n }, [displayedFolders, folderCountersById, lang]);\n\n const handleSwitchTab = useCallback((index: number) => {\n setActiveChatFolder(index);\n }, [setActiveChatFolder]);\n\n // Prevent `activeTab` pointing at non-existing folder after update\n useEffect(() => {\n if (!folderTabs || !folderTabs.length) {\n return;\n }\n\n if (activeChatFolder >= folderTabs.length) {\n setActiveChatFolder(0);\n }\n }, [activeChatFolder, folderTabs, setActiveChatFolder]);\n\n useEffect(() => {\n if (!transitionRef.current || !IS_TOUCH_ENV || !folderTabs || !folderTabs.length) {\n return undefined;\n }\n\n return captureEvents(transitionRef.current, {\n onSwipe: ((e, direction) => {\n if (direction === SwipeDirection.Left) {\n setActiveChatFolder(Math.min(activeChatFolder + 1, folderTabs.length - 1));\n } else if (direction === SwipeDirection.Right) {\n setActiveChatFolder(Math.max(0, activeChatFolder - 1));\n }\n }),\n });\n }, [activeChatFolder, folderTabs, setActiveChatFolder]);\n\n const isNotInAllTabRef = useRef();\n isNotInAllTabRef.current = activeChatFolder !== 0;\n useEffect(() => (isNotInAllTabRef.current ? captureEscKeyListener(() => {\n if (isNotInAllTabRef.current) {\n setActiveChatFolder(0);\n }\n }) : undefined), [activeChatFolder, setActiveChatFolder]);\n\n useHistoryBack(activeChatFolder !== 0, () => setActiveChatFolder(0));\n\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.ctrlKey && e.shiftKey && e.code.startsWith('Digit') && folderTabs) {\n const [, digit] = e.code.match(/Digit(\\d)/) || [];\n if (!digit) return;\n\n if (digit === SAVED_MESSAGES_HOTKEY) {\n openChat({ id: currentUserId, shouldReplaceHistory: true });\n return;\n }\n\n const folder = Number(digit) - 1;\n if (folder > folderTabs.length - 1) return;\n\n setActiveChatFolder(folder);\n e.preventDefault();\n }\n };\n\n document.addEventListener('keydown', handleKeyDown, true);\n\n return () => {\n document.removeEventListener('keydown', handleKeyDown, true);\n };\n });\n\n const {\n shouldRender: shouldRenderPlaceholder, transitionClassNames,\n } = useShowTransition(!orderedFolderIds, undefined, true);\n\n function renderCurrentTab(isActive: boolean) {\n const activeFolder = Object.values(chatFoldersById)\n .find(({ title }) => title === folderTabs![activeChatFolder].title);\n\n if (!activeFolder || activeChatFolder === 0) {\n return <ChatList folderType=\"all\" isActive={isActive} />;\n }\n\n return (\n <ChatList\n folderType=\"folder\"\n folderId={activeFolder.id}\n noChatsText={lang('FilterNoChatsToDisplay')}\n isActive={isActive}\n />\n );\n }\n\n return (\n <div className=\"ChatFolders\">\n {folderTabs && folderTabs.length ? (\n <TabList tabs={folderTabs} activeTab={activeChatFolder} onSwitchTab={handleSwitchTab} />\n ) : shouldRenderPlaceholder ? (\n <div className={buildClassName('tabs-placeholder', transitionClassNames)} />\n ) : undefined}\n <Transition\n ref={transitionRef}\n name={lang.isRtl ? 'slide-reversed' : 'slide'}\n activeKey={activeChatFolder}\n renderCount={folderTabs ? folderTabs.length : undefined}\n >\n {renderCurrentTab}\n </Transition>\n </div>\n );\n};\n\nexport default memo(withGlobal(\n (global): StateProps => {\n const {\n chats: { byId: chatsById },\n users: { byId: usersById },\n chatFolders: {\n byId: chatFoldersById,\n orderedIds: orderedFolderIds,\n activeChatFolder,\n },\n currentUserId,\n lastSyncTime,\n } = global;\n\n return {\n chatsById,\n usersById,\n chatFoldersById,\n orderedFolderIds,\n lastSyncTime,\n notifySettings: selectNotifySettings(global),\n notifyExceptions: selectNotifyExceptions(global),\n activeChatFolder,\n currentUserId,\n };\n },\n (setGlobal, actions): DispatchProps => pick(actions, [\n 'loadChatFolders',\n 'setActiveChatFolder',\n 'openChat',\n ]),\n)(ChatFolders));\n","import React, { FC, memo } from '../../../lib/teact/teact';\nimport { Bundles } from '../../../util/moduleLoader';\nimport { OwnProps } from './LeftSearch';\n\nimport useModuleLoader from '../../../hooks/useModuleLoader';\nimport Loading from '../../ui/Loading';\n\nconst LeftSearchAsync: FC<OwnProps> = (props) => {\n const LeftSearch = useModuleLoader(Bundles.Extra, 'LeftSearch');\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return LeftSearch ? <LeftSearch {...props} /> : <Loading />;\n};\n\nexport default memo(LeftSearchAsync);\n","import React, { FC, memo } from '../../../lib/teact/teact';\nimport { Bundles } from '../../../util/moduleLoader';\nimport { OwnProps } from './ContactList';\n\nimport useModuleLoader from '../../../hooks/useModuleLoader';\nimport Loading from '../../ui/Loading';\n\nconst ContactListAsync: FC<OwnProps> = (props) => {\n const ContactList = useModuleLoader(Bundles.Extra, 'ContactList');\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return ContactList ? <ContactList {...props} /> : <Loading />;\n};\n\nexport default memo(ContactListAsync);\n","import React, {\n FC, useCallback, useState, useEffect, memo,\n} from '../../lib/teact/teact';\n\nimport buildClassName from '../../util/buildClassName';\nimport useLang from '../../hooks/useLang';\n\nimport Button from '../ui/Button';\nimport Menu from '../ui/Menu';\nimport MenuItem from '../ui/MenuItem';\n\nimport './NewChatButton.scss';\n\nconst MENU_CLOSE_DELAY_MS = 750;\nlet closeTimeout: number | undefined;\n\ntype OwnProps = {\n isShown: boolean;\n onNewPrivateChat: () => void;\n onNewChannel: () => void;\n onNewGroup: () => void;\n};\n\nconst NewChatButton: FC<OwnProps> = ({\n isShown,\n onNewPrivateChat,\n onNewChannel,\n onNewGroup,\n}) => {\n const [isMenuOpen, setIsMenuOpen] = useState(false);\n\n useEffect(() => {\n if (!isShown) {\n setIsMenuOpen(false);\n }\n }, [isShown]);\n\n const lang = useLang();\n\n const fabClassName = buildClassName(\n 'NewChatButton',\n isShown && 'revealed',\n isMenuOpen && 'menu-is-open',\n );\n\n const toggleIsMenuOpen = () => {\n setIsMenuOpen(!isMenuOpen);\n };\n\n const handleClose = () => {\n setIsMenuOpen(false);\n };\n\n const handleMouseEnter = useCallback(() => {\n if (closeTimeout) {\n clearTimeout(closeTimeout);\n closeTimeout = undefined;\n }\n }, []);\n\n const handleMouseLeave = useCallback(() => {\n if (closeTimeout) {\n clearTimeout(closeTimeout);\n closeTimeout = undefined;\n }\n\n closeTimeout = window.setTimeout(() => {\n setIsMenuOpen(false);\n }, MENU_CLOSE_DELAY_MS);\n }, []);\n\n return (\n <div\n className={fabClassName}\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n >\n <Button\n round\n color=\"primary\"\n className={isMenuOpen ? 'active' : ''}\n onClick={toggleIsMenuOpen}\n ariaLabel={lang(isMenuOpen ? 'Close' : 'NewMessageTitle')}\n tabIndex={-1}\n >\n <i className=\"icon-new-chat-filled\" />\n <i className=\"icon-close\" />\n </Button>\n <Menu\n isOpen={isMenuOpen}\n positionX=\"right\"\n positionY=\"bottom\"\n autoClose\n onClose={handleClose}\n >\n <MenuItem icon=\"channel\" onClick={onNewChannel}>{lang('NewChannel')}</MenuItem>\n <MenuItem icon=\"group\" onClick={onNewGroup}>{lang('NewGroup')}</MenuItem>\n <MenuItem icon=\"user\" onClick={onNewPrivateChat}>{lang('NewMessageTitle')}</MenuItem>\n </Menu>\n </div>\n );\n};\n\nexport default memo(NewChatButton);\n","import React, {\n FC, useState, useRef, useCallback, useEffect,\n} from '../../../lib/teact/teact';\nimport { withGlobal } from '../../../lib/teact/teactn';\n\nimport { GlobalState } from '../../../global/types';\nimport { LeftColumnContent } from '../../../types';\n\nimport { IS_TOUCH_ENV } from '../../../util/environment';\nimport { pick } from '../../../util/iteratees';\nimport buildClassName from '../../../util/buildClassName';\nimport useBrowserOnline from '../../../hooks/useBrowserOnline';\nimport useFlag from '../../../hooks/useFlag';\nimport useShowTransition from '../../../hooks/useShowTransition';\nimport useLang from '../../../hooks/useLang';\n\nimport Transition from '../../ui/Transition';\nimport LeftMainHeader from './LeftMainHeader';\nimport ConnectionState from '../ConnectionState';\nimport ChatFolders from './ChatFolders';\nimport LeftSearch from '../search/LeftSearch.async';\nimport ContactList from './ContactList.async';\nimport NewChatButton from '../NewChatButton';\nimport ShowTransition from '../../ui/ShowTransition';\nimport Button from '../../ui/Button';\n\nimport './LeftMain.scss';\n\ntype OwnProps = {\n content: LeftColumnContent;\n searchQuery?: string;\n searchDate?: number;\n contactsFilter: string;\n shouldSkipTransition?: boolean;\n onSearchQuery: (query: string) => void;\n onContentChange: (content: LeftColumnContent) => void;\n onReset: () => void;\n};\n\ntype StateProps = Pick<GlobalState, 'connectionState'>;\n\nconst TRANSITION_RENDER_COUNT = Object.keys(LeftColumnContent).length / 2;\nconst BUTTON_CLOSE_DELAY_MS = 250;\nconst APP_OUTDATED_TIMEOUT = 3 * 24 * 60 * 60 * 1000; // 3 days\n\nlet closeTimeout: number | undefined;\n\nconst LeftMain: FC<OwnProps & StateProps> = ({\n content,\n searchQuery,\n searchDate,\n contactsFilter,\n shouldSkipTransition,\n onSearchQuery,\n onContentChange,\n onReset,\n connectionState,\n}) => {\n const [isNewChatButtonShown, setIsNewChatButtonShown] = useState(IS_TOUCH_ENV);\n\n const isBrowserOnline = useBrowserOnline();\n const isConnecting = !isBrowserOnline || connectionState === 'connectionStateConnecting';\n\n const isMouseInside = useRef(false);\n\n const handleSelectSettings = useCallback(() => {\n onContentChange(LeftColumnContent.Settings);\n }, [onContentChange]);\n\n const handleSelectContacts = useCallback(() => {\n onContentChange(LeftColumnContent.Contacts);\n }, [onContentChange]);\n\n const handleSelectNewChannel = useCallback(() => {\n onContentChange(LeftColumnContent.NewChannelStep1);\n }, [onContentChange]);\n\n const handleSelectNewGroup = useCallback(() => {\n onContentChange(LeftColumnContent.NewGroupStep1);\n }, [onContentChange]);\n\n const handleSelectArchived = useCallback(() => {\n onContentChange(LeftColumnContent.Archived);\n }, [onContentChange]);\n\n const handleMouseEnter = useCallback(() => {\n if (content !== LeftColumnContent.ChatList) {\n return;\n }\n isMouseInside.current = true;\n setIsNewChatButtonShown(true);\n }, [content]);\n\n const handleMouseLeave = useCallback(() => {\n isMouseInside.current = false;\n\n if (closeTimeout) {\n clearTimeout(closeTimeout);\n closeTimeout = undefined;\n }\n\n closeTimeout = window.setTimeout(() => {\n if (!isMouseInside.current) {\n setIsNewChatButtonShown(false);\n }\n }, BUTTON_CLOSE_DELAY_MS);\n }, []);\n\n useEffect(() => {\n let autoCloseTimeout: number | undefined;\n if (content !== LeftColumnContent.ChatList) {\n autoCloseTimeout = window.setTimeout(() => {\n setIsNewChatButtonShown(false);\n }, BUTTON_CLOSE_DELAY_MS);\n } else if (isMouseInside.current || IS_TOUCH_ENV) {\n setIsNewChatButtonShown(true);\n }\n\n return () => {\n if (autoCloseTimeout) {\n clearTimeout(autoCloseTimeout);\n autoCloseTimeout = undefined;\n }\n };\n }, [content]);\n\n const [shouldRenderUpdateButton, updateButtonClassNames, handleUpdateClick] = useAppOutdatedCheck();\n\n const lang = useLang();\n\n return (\n <div\n id=\"LeftColumn-main\"\n onMouseEnter={!IS_TOUCH_ENV ? handleMouseEnter : undefined}\n onMouseLeave={!IS_TOUCH_ENV ? handleMouseLeave : undefined}\n >\n <LeftMainHeader\n content={content}\n contactsFilter={contactsFilter}\n onSearchQuery={onSearchQuery}\n onSelectSettings={handleSelectSettings}\n onSelectContacts={handleSelectContacts}\n onSelectArchived={handleSelectArchived}\n onReset={onReset}\n shouldSkipTransition={shouldSkipTransition}\n />\n <ShowTransition isOpen={isConnecting} isCustom className=\"connection-state-wrapper opacity-transition slow\">\n {() => <ConnectionState />}\n </ShowTransition>\n <Transition\n name={shouldSkipTransition ? 'none' : 'zoom-fade'}\n renderCount={TRANSITION_RENDER_COUNT}\n activeKey={content}\n shouldCleanup\n cleanupExceptionKey={LeftColumnContent.ChatList}\n className={isConnecting ? 'pull-down' : undefined}\n >\n {(isActive) => {\n switch (content) {\n case LeftColumnContent.ChatList:\n return <ChatFolders />;\n case LeftColumnContent.GlobalSearch:\n return (\n <LeftSearch\n searchQuery={searchQuery}\n searchDate={searchDate}\n isActive={isActive}\n onReset={onReset}\n />\n );\n case LeftColumnContent.Contacts:\n return <ContactList filter={contactsFilter} isActive={isActive} onReset={onReset} />;\n default:\n return undefined;\n }\n }}\n </Transition>\n {shouldRenderUpdateButton && (\n <Button\n fluid\n pill\n className={buildClassName('btn-update', updateButtonClassNames)}\n onClick={handleUpdateClick}\n >\n {lang('lng_update_telegram')}\n </Button>\n )}\n <NewChatButton\n isShown={isNewChatButtonShown}\n onNewPrivateChat={handleSelectContacts}\n onNewChannel={handleSelectNewChannel}\n onNewGroup={handleSelectNewGroup}\n />\n </div>\n );\n};\n\nfunction useAppOutdatedCheck() {\n const [isAppOutdated, markIsAppOutdated] = useFlag(false);\n\n useEffect(() => {\n const timeout = window.setTimeout(markIsAppOutdated, APP_OUTDATED_TIMEOUT);\n\n return () => {\n clearTimeout(timeout);\n };\n }, [markIsAppOutdated]);\n\n const { shouldRender, transitionClassNames } = useShowTransition(isAppOutdated);\n\n const handleUpdateClick = () => {\n window.location.reload();\n };\n\n return [shouldRender, transitionClassNames, handleUpdateClick] as const;\n}\n\nexport default withGlobal<OwnProps>(\n (global): StateProps => pick(global, ['connectionState']),\n)(LeftMain);\n","import { useEffect, useState } from '../lib/teact/teact';\n\nexport default function useBrowserOnline() {\n const [isOnline, setIsOnline] = useState(window.navigator.onLine);\n\n useEffect(() => {\n function handleChange() {\n setIsOnline(window.navigator.onLine);\n }\n\n window.addEventListener('online', handleChange);\n window.addEventListener('offline', handleChange);\n\n return () => {\n window.removeEventListener('offline', handleChange);\n window.removeEventListener('online', handleChange);\n };\n }, []);\n\n return isOnline;\n}\n","import React, { FC, memo } from '../../../lib/teact/teact';\nimport { Bundles } from '../../../util/moduleLoader';\n\nimport { OwnProps } from './Settings';\n\nimport useModuleLoader from '../../../hooks/useModuleLoader';\nimport Loading from '../../ui/Loading';\n\nconst SettingsAsync: FC<OwnProps> = (props) => {\n const Settings = useModuleLoader(Bundles.Extra, 'Settings');\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return Settings ? <Settings {...props} /> : <Loading />;\n};\n\nexport default memo(SettingsAsync);\n","import React, { FC, memo } from '../../../lib/teact/teact';\nimport { Bundles } from '../../../util/moduleLoader';\n\nimport { OwnProps } from './NewChat';\n\nimport useModuleLoader from '../../../hooks/useModuleLoader';\nimport Loading from '../../ui/Loading';\n\nconst NewChatAsync: FC<OwnProps> = (props) => {\n const NewChat = useModuleLoader(Bundles.Extra, 'NewChat');\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return NewChat ? <NewChat {...props} /> : <Loading />;\n};\n\nexport default memo(NewChatAsync);\n","import React, { FC, memo } from '../../lib/teact/teact';\nimport { OwnProps } from './ArchivedChats';\nimport { Bundles } from '../../util/moduleLoader';\n\nimport useModuleLoader from '../../hooks/useModuleLoader';\nimport Loading from '../ui/Loading';\n\nconst ArchivedChatsAsync: FC<OwnProps> = (props) => {\n const ArchivedChats = useModuleLoader(Bundles.Extra, 'ArchivedChats');\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return ArchivedChats ? <ArchivedChats {...props} /> : <Loading />;\n};\n\nexport default memo(ArchivedChatsAsync);\n","import React, {\n FC, memo, useCallback, useEffect, useState,\n} from '../../lib/teact/teact';\nimport { withGlobal } from '../../lib/teact/teactn';\n\nimport { GlobalActions } from '../../global/types';\nimport { LeftColumnContent, SettingsScreens } from '../../types';\n\nimport { LAYERS_ANIMATION_NAME } from '../../util/environment';\nimport captureEscKeyListener from '../../util/captureEscKeyListener';\nimport { pick } from '../../util/iteratees';\n\nimport Transition from '../ui/Transition';\nimport LeftMain from './main/LeftMain';\nimport Settings from './settings/Settings.async';\nimport NewChat from './newChat/NewChat.async';\nimport ArchivedChats from './ArchivedChats.async';\n\nimport './LeftColumn.scss';\n\ntype StateProps = {\n searchQuery?: string;\n searchDate?: number;\n activeChatFolder: number;\n shouldSkipHistoryAnimations?: boolean;\n};\n\ntype DispatchProps = Pick<GlobalActions, (\n 'setGlobalSearchQuery' | 'setGlobalSearchChatId' | 'resetChatCreation' | 'setGlobalSearchDate' |\n 'loadPasswordInfo' | 'clearTwoFaError'\n)>;\n\nenum ContentType {\n Main,\n // eslint-disable-next-line no-shadow\n Settings,\n Archived,\n // eslint-disable-next-line no-shadow\n NewGroup,\n // eslint-disable-next-line no-shadow\n NewChannel\n}\n\nconst RENDER_COUNT = Object.keys(ContentType).length / 2;\nconst RESET_TRANSITION_DELAY_MS = 250;\n\nconst LeftColumn: FC<StateProps & DispatchProps> = ({\n searchQuery,\n searchDate,\n activeChatFolder,\n shouldSkipHistoryAnimations,\n setGlobalSearchQuery,\n setGlobalSearchChatId,\n resetChatCreation,\n setGlobalSearchDate,\n loadPasswordInfo,\n clearTwoFaError,\n}) => {\n const [content, setContent] = useState<LeftColumnContent>(LeftColumnContent.ChatList);\n const [settingsScreen, setSettingsScreen] = useState(SettingsScreens.Main);\n const [contactsFilter, setContactsFilter] = useState<string>('');\n\n // Used to reset child components in background.\n const [lastResetTime, setLastResetTime] = useState<number>(0);\n\n let contentType: ContentType = ContentType.Main;\n switch (content) {\n case LeftColumnContent.Archived:\n contentType = ContentType.Archived;\n break;\n case LeftColumnContent.Settings:\n contentType = ContentType.Settings;\n break;\n case LeftColumnContent.NewChannelStep1:\n case LeftColumnContent.NewChannelStep2:\n contentType = ContentType.NewChannel;\n break;\n case LeftColumnContent.NewGroupStep1:\n case LeftColumnContent.NewGroupStep2:\n contentType = ContentType.NewGroup;\n break;\n }\n\n const handleReset = useCallback((forceReturnToChatList?: boolean) => {\n if (content === LeftColumnContent.NewGroupStep2\n && !forceReturnToChatList\n ) {\n setContent(LeftColumnContent.NewGroupStep1);\n return;\n }\n\n if (content === LeftColumnContent.NewChannelStep2\n && !forceReturnToChatList\n ) {\n setContent(LeftColumnContent.NewChannelStep1);\n return;\n }\n\n if (content === LeftColumnContent.NewGroupStep1) {\n const pickerSearchInput = document.getElementById('new-group-picker-search');\n if (pickerSearchInput) {\n pickerSearchInput.blur();\n }\n }\n\n if (content === LeftColumnContent.Settings) {\n switch (settingsScreen) {\n case SettingsScreens.EditProfile:\n case SettingsScreens.Folders:\n case SettingsScreens.General:\n case SettingsScreens.Notifications:\n case SettingsScreens.Privacy:\n case SettingsScreens.Language:\n setSettingsScreen(SettingsScreens.Main);\n return;\n\n case SettingsScreens.GeneralChatBackground:\n setSettingsScreen(SettingsScreens.General);\n return;\n case SettingsScreens.GeneralChatBackgroundColor:\n setSettingsScreen(SettingsScreens.GeneralChatBackground);\n return;\n\n case SettingsScreens.PrivacyPhoneNumber:\n case SettingsScreens.PrivacyLastSeen:\n case SettingsScreens.PrivacyProfilePhoto:\n case SettingsScreens.PrivacyForwarding:\n case SettingsScreens.PrivacyGroupChats:\n case SettingsScreens.PrivacyActiveSessions:\n case SettingsScreens.PrivacyBlockedUsers:\n case SettingsScreens.TwoFaDisabled:\n case SettingsScreens.TwoFaEnabled:\n case SettingsScreens.TwoFaCongratulations:\n setSettingsScreen(SettingsScreens.Privacy);\n return;\n case SettingsScreens.PrivacyPhoneNumberAllowedContacts:\n case SettingsScreens.PrivacyPhoneNumberDeniedContacts:\n setSettingsScreen(SettingsScreens.PrivacyPhoneNumber);\n return;\n case SettingsScreens.PrivacyLastSeenAllowedContacts:\n case SettingsScreens.PrivacyLastSeenDeniedContacts:\n setSettingsScreen(SettingsScreens.PrivacyLastSeen);\n return;\n case SettingsScreens.PrivacyProfilePhotoAllowedContacts:\n case SettingsScreens.PrivacyProfilePhotoDeniedContacts:\n setSettingsScreen(SettingsScreens.PrivacyProfilePhoto);\n return;\n case SettingsScreens.PrivacyForwardingAllowedContacts:\n case SettingsScreens.PrivacyForwardingDeniedContacts:\n setSettingsScreen(SettingsScreens.PrivacyForwarding);\n return;\n case SettingsScreens.PrivacyGroupChatsAllowedContacts:\n case SettingsScreens.PrivacyGroupChatsDeniedContacts:\n setSettingsScreen(SettingsScreens.PrivacyGroupChats);\n return;\n case SettingsScreens.TwoFaNewPassword:\n setSettingsScreen(SettingsScreens.TwoFaDisabled);\n return;\n case SettingsScreens.TwoFaNewPasswordConfirm:\n setSettingsScreen(SettingsScreens.TwoFaNewPassword);\n return;\n case SettingsScreens.TwoFaNewPasswordHint:\n setSettingsScreen(SettingsScreens.TwoFaNewPasswordConfirm);\n return;\n case SettingsScreens.TwoFaNewPasswordEmail:\n setSettingsScreen(SettingsScreens.TwoFaNewPasswordHint);\n return;\n case SettingsScreens.TwoFaNewPasswordEmailCode:\n setSettingsScreen(SettingsScreens.TwoFaNewPasswordEmail);\n return;\n case SettingsScreens.TwoFaChangePasswordCurrent:\n case SettingsScreens.TwoFaTurnOff:\n case SettingsScreens.TwoFaRecoveryEmailCurrentPassword:\n setSettingsScreen(SettingsScreens.TwoFaEnabled);\n return;\n case SettingsScreens.TwoFaChangePasswordNew:\n setSettingsScreen(SettingsScreens.TwoFaChangePasswordCurrent);\n return;\n case SettingsScreens.TwoFaChangePasswordConfirm:\n setSettingsScreen(SettingsScreens.TwoFaChangePasswordNew);\n return;\n case SettingsScreens.TwoFaChangePasswordHint:\n setSettingsScreen(SettingsScreens.TwoFaChangePasswordConfirm);\n return;\n case SettingsScreens.TwoFaRecoveryEmail:\n setSettingsScreen(SettingsScreens.TwoFaRecoveryEmailCurrentPassword);\n return;\n case SettingsScreens.TwoFaRecoveryEmailCode:\n setSettingsScreen(SettingsScreens.TwoFaRecoveryEmail);\n return;\n\n case SettingsScreens.FoldersCreateFolder:\n case SettingsScreens.FoldersEditFolder:\n setSettingsScreen(SettingsScreens.Folders);\n return;\n default:\n break;\n }\n }\n\n if (content === LeftColumnContent.ChatList && activeChatFolder === 0) {\n setContent(LeftColumnContent.GlobalSearch);\n return;\n }\n\n setContent(LeftColumnContent.ChatList);\n setContactsFilter('');\n setGlobalSearchQuery({ query: '' });\n setGlobalSearchDate({ date: undefined });\n setGlobalSearchChatId({ id: undefined });\n resetChatCreation();\n setTimeout(() => {\n setLastResetTime(Date.now());\n }, RESET_TRANSITION_DELAY_MS);\n }, [\n content, activeChatFolder, settingsScreen, setGlobalSearchQuery, setGlobalSearchDate, setGlobalSearchChatId,\n resetChatCreation,\n ]);\n\n const handleSearchQuery = useCallback((query: string) => {\n if (content === LeftColumnContent.Contacts) {\n setContactsFilter(query);\n return;\n }\n\n setContent(LeftColumnContent.GlobalSearch);\n\n if (query !== searchQuery) {\n setGlobalSearchQuery({ query });\n }\n }, [content, searchQuery, setGlobalSearchQuery]);\n\n useEffect(\n () => (content !== LeftColumnContent.ChatList || activeChatFolder === 0\n ? captureEscKeyListener(() => handleReset())\n : undefined),\n [activeChatFolder, content, handleReset],\n );\n\n useEffect(() => {\n clearTwoFaError();\n\n if (settingsScreen === SettingsScreens.Privacy) {\n loadPasswordInfo();\n }\n }, [clearTwoFaError, loadPasswordInfo, settingsScreen]);\n\n const handleSettingsScreenSelect = (screen: SettingsScreens) => {\n setContent(LeftColumnContent.Settings);\n setSettingsScreen(screen);\n };\n\n return (\n <Transition\n id=\"LeftColumn\"\n name={shouldSkipHistoryAnimations ? 'none' : LAYERS_ANIMATION_NAME}\n renderCount={RENDER_COUNT}\n activeKey={contentType}\n shouldCleanup\n cleanupExceptionKey={ContentType.Main}\n >\n {(isActive) => {\n switch (contentType) {\n case ContentType.Archived:\n return (\n <ArchivedChats\n isActive={isActive}\n onReset={handleReset}\n onContentChange={setContent}\n />\n );\n case ContentType.Settings:\n return (\n <Settings\n isActive={isActive}\n currentScreen={settingsScreen}\n onScreenSelect={handleSettingsScreenSelect}\n onReset={handleReset}\n shouldSkipTransition={shouldSkipHistoryAnimations}\n />\n );\n case ContentType.NewChannel:\n return (\n <NewChat\n key={lastResetTime}\n isActive={isActive}\n isChannel\n content={content}\n onContentChange={setContent}\n onReset={handleReset}\n />\n );\n case ContentType.NewGroup:\n return (\n <NewChat\n key={lastResetTime}\n isActive={isActive}\n content={content}\n onContentChange={setContent}\n onReset={handleReset}\n />\n );\n default:\n return (\n <LeftMain\n content={content}\n searchQuery={searchQuery}\n searchDate={searchDate}\n contactsFilter={contactsFilter}\n onContentChange={setContent}\n onSearchQuery={handleSearchQuery}\n onReset={handleReset}\n shouldSkipTransition={shouldSkipHistoryAnimations}\n />\n );\n }\n }}\n </Transition>\n );\n};\n\nexport default memo(withGlobal(\n (global): StateProps => {\n const {\n globalSearch: {\n query,\n date,\n },\n chatFolders: {\n activeChatFolder,\n },\n shouldSkipHistoryAnimations,\n } = global;\n return {\n searchQuery: query, searchDate: date, activeChatFolder, shouldSkipHistoryAnimations,\n };\n },\n (setGlobal, actions): DispatchProps => pick(actions, [\n 'setGlobalSearchQuery', 'setGlobalSearchChatId', 'resetChatCreation', 'setGlobalSearchDate',\n 'loadPasswordInfo', 'clearTwoFaError',\n ]),\n)(LeftColumn));\n","import { useEffect, useState } from '../lib/teact/teact';\n\nimport { throttle } from '../util/schedulers';\nimport windowSize from '../util/windowSize';\nimport { ApiDimensions } from '../api/types';\n\nconst THROTTLE = 250;\n\nexport default () => {\n const [size, setSize] = useState<ApiDimensions>(windowSize.get());\n\n useEffect(() => {\n const handleResize = throttle(() => {\n setSize(windowSize.get());\n }, THROTTLE, false);\n\n window.addEventListener('resize', handleResize);\n\n return () => {\n window.removeEventListener('resize', handleResize);\n };\n }, []);\n\n return size;\n};\n","import {\n MIN_SCREEN_WIDTH_FOR_STATIC_LEFT_COLUMN,\n MIN_SCREEN_WIDTH_FOR_STATIC_RIGHT_COLUMN,\n MOBILE_SCREEN_MAX_WIDTH,\n} from '../../../config';\n\nconst REM = 16; // px\nconst MAX_TOOLBAR_WIDTH = 32 * REM;\nconst MAX_MESSAGES_LIST_WIDTH = 45.5 * REM;\nconst SIDE_COLUMN_MAX_WIDTH = 26.5 * REM;\nconst MIN_LEFT_COLUMN_WIDTH = 18 * REM;\nconst UNPIN_BUTTON_WIDTH = 16.125 * REM;\n\nexport default function calculateMiddleFooterTransforms(windowWidth: number, canPost?: boolean) {\n const sidePadding = windowWidth <= MOBILE_SCREEN_MAX_WIDTH\n ? REM\n : 2 * REM;\n const messageListWidth = getMessageListWidth(windowWidth);\n const sendButtonWidth = windowWidth <= MOBILE_SCREEN_MAX_WIDTH\n ? 3.375 * REM\n : 4 * REM;\n\n const composerWidth = canPost\n ? messageListWidth - sidePadding - sendButtonWidth\n : messageListWidth - sidePadding;\n const toolbarWidth = windowWidth > MOBILE_SCREEN_MAX_WIDTH\n ? Math.min(messageListWidth - sidePadding, MAX_TOOLBAR_WIDTH)\n : messageListWidth - sidePadding;\n\n const composerHiddenScale = toolbarWidth / composerWidth;\n const toolbarHiddenScale = composerWidth / toolbarWidth;\n const unpinHiddenScale = toolbarWidth / UNPIN_BUTTON_WIDTH;\n const toolbarForUnpinHiddenScale = UNPIN_BUTTON_WIDTH / toolbarWidth;\n\n const composerTranslateX = canPost\n ? (sendButtonWidth / 2) * toolbarHiddenScale\n : 0;\n\n const toolbarTranslateX = canPost\n ? (sendButtonWidth / 2) * -1 * composerHiddenScale\n : 0;\n\n return {\n composerHiddenScale,\n toolbarHiddenScale,\n composerTranslateX,\n toolbarTranslateX,\n unpinHiddenScale,\n toolbarForUnpinHiddenScale,\n };\n}\n\nfunction getMessageListWidth(windowWidth: number) {\n if (windowWidth > MIN_SCREEN_WIDTH_FOR_STATIC_RIGHT_COLUMN) {\n const leftColumnWidth = Math.min(\n Math.max(windowWidth * 0.25, MIN_LEFT_COLUMN_WIDTH),\n SIDE_COLUMN_MAX_WIDTH,\n );\n\n const rightColumnWidth = Math.min(\n windowWidth * 0.25,\n SIDE_COLUMN_MAX_WIDTH,\n );\n\n return Math.min(\n windowWidth - leftColumnWidth - rightColumnWidth,\n MAX_MESSAGES_LIST_WIDTH,\n );\n }\n\n if (windowWidth > MIN_SCREEN_WIDTH_FOR_STATIC_LEFT_COLUMN) {\n const leftColumnWidth = Math.min(\n Math.max(windowWidth * 0.4, MIN_LEFT_COLUMN_WIDTH),\n SIDE_COLUMN_MAX_WIDTH,\n );\n\n return Math.min(\n windowWidth - leftColumnWidth,\n MAX_MESSAGES_LIST_WIDTH,\n );\n }\n\n if (windowWidth > MAX_MESSAGES_LIST_WIDTH) {\n return MAX_MESSAGES_LIST_WIDTH;\n }\n\n return windowWidth;\n}\n","import { MessageList, MessageListType } from '../global/types';\nimport { MAIN_THREAD_ID } from '../api/types';\n\nexport const createMessageHash = (messageList: MessageList): string => (\n messageList.chatId.toString()\n + (messageList.type !== 'thread' ? `_${messageList.type}`\n : (messageList.threadId !== -1 ? `_${messageList.threadId}` : ''))\n);\n\nexport const parseMessageHash = (value: string): MessageList => {\n const [chatId, typeOrThreadId] = value.split('_');\n const isType = ['thread', 'pinned', 'scheduled'].includes(typeOrThreadId);\n\n return {\n chatId: Number(chatId),\n type: !!typeOrThreadId && isType ? (typeOrThreadId as MessageListType) : 'thread',\n threadId: !!typeOrThreadId && !isType ? Number(typeOrThreadId) : MAIN_THREAD_ID,\n };\n};\n","import React, { FC, memo } from '../../lib/teact/teact';\nimport { OwnProps } from './HeaderMenuContainer';\nimport { Bundles } from '../../util/moduleLoader';\n\nimport useModuleLoader from '../../hooks/useModuleLoader';\n\nconst HeaderMenuContainerAsync: FC<OwnProps> = (props) => {\n const { isOpen } = props;\n const HeaderMenuContainer = useModuleLoader(Bundles.Extra, 'HeaderMenuContainer', !isOpen);\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return HeaderMenuContainer ? <HeaderMenuContainer {...props} /> : undefined;\n};\n\nexport default memo(HeaderMenuContainerAsync);\n","import React, {\n FC,\n memo,\n useRef,\n useCallback,\n useState,\n} from '../../lib/teact/teact';\nimport { withGlobal } from '../../lib/teact/teactn';\n\nimport { GlobalActions, MessageListType } from '../../global/types';\nimport { MAIN_THREAD_ID } from '../../api/types';\nimport { IAnchorPosition } from '../../types';\n\nimport { IS_SINGLE_COLUMN_LAYOUT } from '../../util/environment';\nimport { pick } from '../../util/iteratees';\nimport { isChatChannel, isChatSuperGroup } from '../../modules/helpers';\nimport {\n selectChat,\n selectChatBot,\n selectIsUserBlocked,\n selectIsChatBotNotStarted,\n selectIsChatWithSelf,\n selectIsInSelectMode,\n selectIsRightColumnShown,\n} from '../../modules/selectors';\nimport useLang from '../../hooks/useLang';\n\nimport Button from '../ui/Button';\nimport HeaderMenuContainer from './HeaderMenuContainer.async';\n\ninterface OwnProps {\n chatId: number;\n threadId: number;\n messageListType: MessageListType;\n}\n\ninterface StateProps {\n noMenu?: boolean;\n isChannel?: boolean;\n isRightColumnShown?: boolean;\n canStartBot?: boolean;\n canRestartBot?: boolean;\n canSubscribe?: boolean;\n canSearch?: boolean;\n canMute?: boolean;\n canSelect?: boolean;\n canLeave?: boolean;\n}\n\ntype DispatchProps = Pick<GlobalActions, 'joinChannel' | 'sendBotCommand' | 'openLocalTextSearch' | 'restartBot'>;\n\n// Chrome breaks layout when focusing input during transition\nconst SEARCH_FOCUS_DELAY_MS = 400;\n\nconst HeaderActions: FC<OwnProps & StateProps & DispatchProps> = ({\n chatId,\n threadId,\n noMenu,\n isChannel,\n canStartBot,\n canRestartBot,\n canSubscribe,\n canSearch,\n canMute,\n canSelect,\n canLeave,\n isRightColumnShown,\n joinChannel,\n sendBotCommand,\n openLocalTextSearch,\n restartBot,\n}) => {\n // eslint-disable-next-line no-null/no-null\n const menuButtonRef = useRef<HTMLButtonElement>(null);\n const [isMenuOpen, setIsMenuOpen] = useState(false);\n const [menuPosition, setMenuPosition] = useState<IAnchorPosition | undefined>(undefined);\n\n const handleHeaderMenuOpen = useCallback(() => {\n setIsMenuOpen(true);\n const rect = menuButtonRef.current!.getBoundingClientRect();\n setMenuPosition({ x: rect.right, y: rect.bottom });\n }, []);\n\n const handleHeaderMenuClose = useCallback(() => {\n setIsMenuOpen(false);\n }, []);\n\n const handleHeaderMenuHide = useCallback(() => {\n setMenuPosition(undefined);\n }, []);\n\n const handleSubscribeClick = useCallback(() => {\n joinChannel({ chatId });\n }, [joinChannel, chatId]);\n\n const handleStartBot = useCallback(() => {\n sendBotCommand({ command: '/start' });\n }, [sendBotCommand]);\n\n const handleRestartBot = useCallback(() => {\n restartBot({ chatId });\n }, [chatId, restartBot]);\n\n const handleSearchClick = useCallback(() => {\n openLocalTextSearch();\n\n if (IS_SINGLE_COLUMN_LAYOUT) {\n // iOS requires synchronous focus on user event.\n const searchInput = document.querySelector<HTMLInputElement>('#MobileSearch input')!;\n searchInput.focus();\n } else {\n setTimeout(() => {\n const searchInput = document.querySelector<HTMLInputElement>('.RightHeader .SearchInput input');\n if (searchInput) {\n searchInput.focus();\n }\n }, SEARCH_FOCUS_DELAY_MS);\n }\n }, [openLocalTextSearch]);\n\n const lang = useLang();\n\n return (\n <div className=\"HeaderActions\">\n {!IS_SINGLE_COLUMN_LAYOUT && canSubscribe && (\n <Button\n size=\"tiny\"\n ripple\n fluid\n onClick={handleSubscribeClick}\n >\n {lang(isChannel ? 'Subscribe' : 'Join Group')}\n </Button>\n )}\n {!IS_SINGLE_COLUMN_LAYOUT && canStartBot && (\n <Button\n size=\"tiny\"\n ripple\n fluid\n onClick={handleStartBot}\n >\n {lang('BotStart')}\n </Button>\n )}\n {!IS_SINGLE_COLUMN_LAYOUT && canRestartBot && (\n <Button\n size=\"tiny\"\n ripple\n fluid\n onClick={handleRestartBot}\n >\n {lang('BotRestart')}\n </Button>\n )}\n {!IS_SINGLE_COLUMN_LAYOUT && canSearch && (\n <Button\n round\n ripple={isRightColumnShown}\n color=\"translucent\"\n size=\"smaller\"\n onClick={handleSearchClick}\n ariaLabel=\"Search in this chat\"\n >\n <i className=\"icon-search\" />\n </Button>\n )}\n {(IS_SINGLE_COLUMN_LAYOUT || !canSubscribe) && (\n <Button\n ref={menuButtonRef}\n className={isMenuOpen ? 'active' : ''}\n round\n ripple={!IS_SINGLE_COLUMN_LAYOUT}\n size=\"smaller\"\n color=\"translucent\"\n disabled={noMenu}\n ariaLabel=\"More actions\"\n onClick={handleHeaderMenuOpen}\n >\n <i className=\"icon-more\" />\n </Button>\n )}\n {menuPosition && (\n <HeaderMenuContainer\n chatId={chatId}\n threadId={threadId}\n isOpen={isMenuOpen}\n anchor={menuPosition}\n isChannel={isChannel}\n canStartBot={canStartBot}\n canRestartBot={canRestartBot}\n canSubscribe={canSubscribe}\n canSearch={canSearch}\n canMute={canMute}\n canSelect={canSelect}\n canLeave={canLeave}\n onSubscribeChannel={handleSubscribeClick}\n onSearchClick={handleSearchClick}\n onClose={handleHeaderMenuClose}\n onCloseAnimationEnd={handleHeaderMenuHide}\n />\n )}\n </div>\n );\n};\n\nexport default memo(withGlobal<OwnProps>(\n (global, { chatId, threadId, messageListType }): StateProps => {\n const chat = selectChat(global, chatId);\n const isChannel = Boolean(chat && isChatChannel(chat));\n\n if (chat && chat.isRestricted) {\n return {\n noMenu: true,\n };\n }\n\n const bot = selectChatBot(global, chatId);\n const isChatWithSelf = selectIsChatWithSelf(global, chatId);\n const isMainThread = messageListType === 'thread' && threadId === MAIN_THREAD_ID;\n const isDiscussionThread = messageListType === 'thread' && threadId !== MAIN_THREAD_ID;\n const isRightColumnShown = selectIsRightColumnShown(global);\n\n const canRestartBot = Boolean(bot && selectIsUserBlocked(global, bot.id));\n const canStartBot = !canRestartBot && Boolean(selectIsChatBotNotStarted(global, chatId));\n const canSubscribe = Boolean(\n isMainThread && chat && (isChannel || isChatSuperGroup(chat)) && chat.isNotJoined,\n );\n const canSearch = isMainThread || isDiscussionThread;\n const canMute = isMainThread && !isChatWithSelf && !canSubscribe;\n const canSelect = !selectIsInSelectMode(global);\n const canLeave = isMainThread && !canSubscribe;\n\n const noMenu = !(\n (IS_SINGLE_COLUMN_LAYOUT && canSubscribe)\n || (IS_SINGLE_COLUMN_LAYOUT && canSearch)\n || canMute\n || canSelect\n || canLeave\n );\n\n return {\n noMenu,\n isChannel,\n isRightColumnShown,\n canStartBot,\n canRestartBot,\n canSubscribe,\n canSearch,\n canMute,\n canSelect,\n canLeave,\n };\n },\n (setGlobal, actions): DispatchProps => pick(actions, [\n 'joinChannel', 'sendBotCommand', 'openLocalTextSearch', 'restartBot',\n ]),\n)(HeaderActions));\n","import { useLayoutEffect, useState } from '../lib/teact/teact';\n\nimport { ApiMessage } from '../api/types';\n\nimport { DEBUG } from '../config';\nimport { isWebpSupported } from '../util/environment';\nimport { EMPTY_IMAGE_DATA_URI, webpToPngBase64 } from '../util/webpToPng';\nimport { getMessageMediaThumbDataUri } from '../modules/helpers';\n\nexport default function useWebpThumbnail(message?: ApiMessage) {\n const thumbnail = message && getMessageMediaThumbDataUri(message);\n const { sticker } = (message && message.content) || {};\n const shouldDecodeThumbnail = thumbnail && sticker && !isWebpSupported() && thumbnail.includes('image/webp');\n const [thumbnailDecoded, setThumbnailDecoded] = useState(EMPTY_IMAGE_DATA_URI);\n const messageId = message && message.id;\n\n useLayoutEffect(() => {\n if (!shouldDecodeThumbnail) {\n return;\n }\n\n webpToPngBase64(`b64-${messageId}`, thumbnail!)\n .then(setThumbnailDecoded)\n .catch((err) => {\n if (DEBUG) {\n // eslint-disable-next-line no-console\n console.error(err);\n }\n });\n }, [messageId, shouldDecodeThumbnail, thumbnail]);\n\n return shouldDecodeThumbnail ? thumbnailDecoded : thumbnail;\n}\n","import React, {\n FC,\n useRef,\n useEffect,\n useMemo,\n memo,\n} from '../../lib/teact/teact';\n\nimport buildClassName from '../../util/buildClassName';\n\ntype OwnProps = {\n count: number;\n index: number;\n};\n\nconst BORDER_MASK_LEVEL = 4;\n\nconst PinnedMessageNavigation: FC<OwnProps> = ({\n count, index,\n}) => {\n // eslint-disable-next-line no-null/no-null\n const containerRef = useRef<HTMLDivElement>(null);\n\n const markupParams = useMemo(() => {\n return calculateMarkup(count, index);\n }, [count, index]);\n\n useEffect(() => {\n if (!containerRef.current) {\n return;\n }\n\n const {\n trackHeight,\n trackTranslateY,\n markHeight,\n markTranslateY,\n clipPathId,\n clipPath,\n } = markupParams;\n\n const firstChild = containerRef.current.firstElementChild;\n if (containerRef && containerRef.current) {\n const currentElement = containerRef.current;\n const { style } = currentElement;\n style.height = `${trackHeight}px`;\n style.transform = `translateY(-${trackTranslateY}px)`;\n style.clipPath = `url(\"#${clipPathId}\")`;\n const svg = currentElement.querySelector('svg');\n const div = currentElement.querySelector('div');\n const defs = currentElement.querySelector('defs');\n if (!svg) {\n if (firstChild) {\n firstChild.innerHTML = `<svg height=\"0\" width=\"0\"><defs> ${clipPath} </defs></svg>`;\n }\n }\n if (defs) {\n defs.innerHTML = clipPath;\n }\n if (div) {\n div.style.height = `${markHeight}px`;\n div.style.transform = `translateY(${markTranslateY}px)`;\n }\n }\n }, [markupParams]);\n\n if (count === 1) {\n return (\n <div className=\"pinned-message-border\">\n <div\n className=\"pinned-message-border-wrapper-1\"\n ref={containerRef}\n />\n </div>\n );\n }\n\n const {\n trackHeight, trackTranslateY, markHeight, markTranslateY, clipPathId,\n } = markupParams;\n\n return (\n <div className={buildClassName('pinned-message-border', count > BORDER_MASK_LEVEL && 'pinned-message-border-mask')}>\n <div\n className=\"pinned-message-border-wrapper\"\n ref={containerRef}\n // @ts-ignore\n style={\n `clip-path: url(\"#${clipPathId}\"); width: 2px;\n height: ${trackHeight}px; transform: translateY(-${trackTranslateY}px);`\n }\n >\n <span />\n <div\n className=\"pinned-message-border-mark\"\n // @ts-ignore\n style={`height: ${markHeight}px; transform: translateY(${markTranslateY}px);`}\n />\n </div>\n </div>\n );\n};\n\nfunction calculateMarkup(count: number, index: number) {\n const reverseIndex = count - index - 1;\n const barHeight = getBarHeight(count);\n const markHeight = getMarkHeight(count, reverseIndex);\n const trackHeight = getTrackHeight(count, barHeight);\n\n const clipPathId = `clipPath${count}`;\n const clipPath = getClipPath(clipPathId, barHeight, count);\n\n const markTranslateY = getMarkTranslateY(reverseIndex, barHeight, count);\n const trackTranslateY = getTrackTranslateY(reverseIndex, count, barHeight, trackHeight);\n return {\n markHeight,\n clipPath,\n markTranslateY,\n trackTranslateY,\n trackHeight,\n clipPathId,\n };\n}\n\nfunction getBarHeight(count: number): number {\n let barHeight = 8;\n if (count === 1) {\n barHeight = 36;\n } else if (count === 2) {\n barHeight = 17;\n } else if (count === 3) {\n barHeight = 11;\n } else if (count === 4) {\n barHeight = 7.5;\n } else if (count > 3) {\n barHeight = 7.5;\n }\n\n return barHeight;\n}\n\nfunction getMarkHeight(count: number, index: number) {\n let barHeight = 36;\n if (count === 1) {\n barHeight = 36;\n } else if (count === 2) {\n barHeight = 17;\n } else if (count === 3) {\n barHeight = index === 1 ? 12 : 11;\n } else if (count === 4) {\n barHeight = 7.5;\n } else if (count > 3) {\n barHeight = 7.5;\n }\n\n return barHeight;\n}\n\nfunction getTrackHeight(count: number, barHeight: number) {\n return count <= 3 ? 36 : barHeight * count + 2 * (count - 1);\n}\n\nfunction getClipPath(id: string, barHeight: number, count: number) {\n const radius = 1;\n\n let d = '';\n if (count === 3) {\n d = drawRect(0, 0, 2, barHeight, radius)\n + drawRect(0, 12, 2, barHeight + 1, radius)\n + drawRect(0, 25, 2, barHeight, radius);\n } else {\n for (let i = 0; i < count; i++) {\n d += drawRect(0, (barHeight + 2) * i, 2, barHeight, radius);\n }\n }\n\n return (\n `<clipPath id=\"${id}\">\n <path d=\"${d}\" />\n </clipPath>`\n );\n}\n\nfunction drawRect(x: number, y: number, width: number, height: number, radius: number) {\n return `M${x},${y + radius}a${radius},${radius},0,0,1,\n ${width},0v${height - 2 * radius}a${radius},${radius},0,0,1,${-width},0Z`;\n}\n\nfunction getMarkTranslateY(index: number, barHeight: number, count: number) {\n if (count === 1) {\n return 0;\n } else if (count === 2) {\n return index === 0 ? 0 : barHeight + 2;\n }\n\n if (count === 3) {\n if (index === 0) {\n return 0;\n } else if (index === 1) {\n return 12;\n }\n\n return 25;\n } else {\n return (barHeight + 2) * index;\n }\n}\n\nfunction getTrackTranslateY(index: number, count: number, barHeight: number, trackHeight: number) {\n if (count <= 4) {\n return 0;\n }\n\n if (index <= 1) {\n return 0;\n } else if (index >= count - 2) {\n return trackHeight - 36;\n }\n\n return (barHeight + 4) / 2 + (index - 2) * (barHeight + 2);\n}\n\nexport default memo(PinnedMessageNavigation);\n","import React, { FC, memo, useCallback } from '../../lib/teact/teact';\n\nimport { ApiMessage } from '../../api/types';\n\nimport { getPictogramDimensions } from '../common/helpers/mediaDimensions';\nimport { getMessageMediaHash, getMessageSummaryText } from '../../modules/helpers';\nimport renderText from '../common/helpers/renderText';\nimport useMedia from '../../hooks/useMedia';\nimport useWebpThumbnail from '../../hooks/useWebpThumbnail';\n\nimport ConfirmDialog from '../ui/ConfirmDialog';\nimport Button from '../ui/Button';\nimport RippleEffect from '../ui/RippleEffect';\nimport buildClassName from '../../util/buildClassName';\nimport useFlag from '../../hooks/useFlag';\nimport useLang from '../../hooks/useLang';\n\nimport PinnedMessageNavigation from './PinnedMessageNavigation';\n\ntype OwnProps = {\n message: ApiMessage;\n index: number;\n count: number;\n customTitle?: string;\n className?: string;\n onUnpinMessage?: (id: number) => void;\n onClick?: () => void;\n onAllPinnedClick?: () => void;\n};\n\nconst HeaderPinnedMessage: FC<OwnProps> = ({\n message, count, index, customTitle, className, onUnpinMessage, onClick, onAllPinnedClick,\n}) => {\n const lang = useLang();\n const mediaThumbnail = useWebpThumbnail(message);\n const mediaBlobUrl = useMedia(getMessageMediaHash(message, 'pictogram'));\n\n const text = getMessageSummaryText(lang, message, Boolean(mediaThumbnail));\n const [isUnpinDialogOpen, openUnpinDialog, closeUnpinDialog] = useFlag();\n\n const handleUnpinMessage = useCallback(() => {\n closeUnpinDialog();\n\n if (onUnpinMessage) {\n onUnpinMessage(message.id);\n }\n }, [closeUnpinDialog, onUnpinMessage, message.id]);\n\n return (\n <div className={buildClassName('HeaderPinnedMessage-wrapper', className)}>\n {count > 1 && (\n <Button\n round\n size=\"smaller\"\n color=\"translucent\"\n className=\"pin-list-button\"\n ariaLabel={lang('EventLogFilterPinnedMessages')}\n onClick={onAllPinnedClick}\n >\n <i className=\"icon-pin-list\" />\n </Button>\n )}\n {onUnpinMessage && (\n <Button\n round\n size=\"smaller\"\n color=\"translucent\"\n ariaLabel={lang('UnpinMessageAlertTitle')}\n className=\"unpin-button\"\n onClick={openUnpinDialog}\n >\n <i className=\"icon-close\" />\n </Button>\n )}\n <ConfirmDialog\n isOpen={isUnpinDialogOpen}\n onClose={closeUnpinDialog}\n text=\"Would you like to unpin this message?\"\n confirmLabel=\"Unpin\"\n confirmHandler={handleUnpinMessage}\n />\n <div className=\"HeaderPinnedMessage\" onClick={onClick} dir={lang.isRtl ? 'rtl' : undefined}>\n <PinnedMessageNavigation\n count={count}\n index={index}\n />\n {mediaThumbnail && renderPictogram(mediaThumbnail, mediaBlobUrl)}\n <div className=\"message-text\">\n <div className=\"title\" dir=\"auto\">\n {customTitle || `${lang('PinnedMessage')} ${index > 0 ? `#${count - index}` : ''}`}\n </div>\n <p dir=\"auto\">{renderText(text)}</p>\n </div>\n\n <RippleEffect />\n </div>\n </div>\n );\n};\n\nfunction renderPictogram(thumbDataUri: string, blobUrl?: string) {\n const { width, height } = getPictogramDimensions();\n\n return (\n <img src={blobUrl || thumbDataUri} width={width} height={height} alt=\"\" />\n );\n}\n\nexport default memo(HeaderPinnedMessage);\n","import React, { FC, useCallback } from '../../lib/teact/teact';\nimport { withGlobal } from '../../lib/teact/teactn';\n\nimport { GlobalActions } from '../../global/types';\nimport {\n ApiAudio, ApiChat, ApiMessage, ApiUser,\n} from '../../api/types';\n\nimport { IS_SINGLE_COLUMN_LAYOUT } from '../../util/environment';\nimport * as mediaLoader from '../../util/mediaLoader';\nimport {\n getMediaDuration, getMessageAudio, getMessageKey, getMessageMediaHash, getSenderTitle,\n} from '../../modules/helpers';\nimport { selectSender } from '../../modules/selectors';\nimport { pick } from '../../util/iteratees';\nimport renderText from '../common/helpers/renderText';\nimport useAudioPlayer from '../../hooks/useAudioPlayer';\nimport buildClassName from '../../util/buildClassName';\nimport useLang from '../../hooks/useLang';\n\nimport RippleEffect from '../ui/RippleEffect';\nimport Button from '../ui/Button';\n\nimport './AudioPlayer.scss';\n\ntype OwnProps = {\n message: ApiMessage;\n className?: string;\n noUi?: boolean;\n};\n\ntype StateProps = {\n sender?: ApiChat | ApiUser;\n};\n\ntype DispatchProps = Pick<GlobalActions, 'focusMessage' | 'closeAudioPlayer'>;\n\nconst AudioPlayer: FC<OwnProps & StateProps & DispatchProps> = ({\n message, className, noUi, sender, focusMessage, closeAudioPlayer,\n}) => {\n const lang = useLang();\n\n const senderName = sender ? getSenderTitle(lang, sender) : undefined;\n const mediaData = mediaLoader.getFromMemory(getMessageMediaHash(message, 'inline')!) as (string | undefined);\n const { playPause, isPlaying } = useAudioPlayer(\n getMessageKey(message), getMediaDuration(message)!, mediaData, undefined, undefined, true,\n );\n\n const handleClick = useCallback(() => {\n focusMessage({ chatId: message.chatId, messageId: message.id });\n }, [focusMessage, message.chatId, message.id]);\n\n const handleClose = useCallback(() => {\n if (isPlaying) {\n playPause();\n }\n closeAudioPlayer();\n }, [closeAudioPlayer, isPlaying, playPause]);\n\n if (noUi) {\n return undefined;\n }\n\n const audio = getMessageAudio(message);\n\n return (\n <div className={buildClassName('AudioPlayer', className)} dir={lang.isRtl ? 'rtl' : undefined}>\n <Button\n round\n ripple={!IS_SINGLE_COLUMN_LAYOUT}\n color=\"translucent\"\n size=\"smaller\"\n className={buildClassName('toggle-play', isPlaying ? 'pause' : 'play')}\n onClick={playPause}\n ariaLabel={isPlaying ? 'Pause audio' : 'Play audio'}\n >\n <i className=\"icon-play\" />\n <i className=\"icon-pause\" />\n </Button>\n\n <div className=\"AudioPlayer-content\" onClick={handleClick}>\n {audio ? renderAudio(audio) : renderVoice(lang('AttachAudio'), senderName)}\n <RippleEffect />\n </div>\n\n <Button\n round\n className=\"player-close\"\n color=\"translucent\"\n size=\"smaller\"\n onClick={handleClose}\n ariaLabel=\"Close player\"\n >\n <i className=\"icon-close\" />\n </Button>\n </div>\n );\n};\n\nfunction renderAudio(audio: ApiAudio) {\n const { title, performer, fileName } = audio;\n\n return (\n <>\n <div className=\"title\" dir=\"auto\">{renderText(title || fileName)}</div>\n {performer && (\n <div className=\"subtitle\" dir=\"auto\">{renderText(performer)}</div>\n )}\n </>\n );\n}\n\nfunction renderVoice(subtitle: string, senderName?: string) {\n return (\n <>\n <div className=\"title\" dir=\"auto\">{senderName && renderText(senderName)}</div>\n <div className=\"subtitle\" dir=\"auto\">{subtitle}</div>\n </>\n );\n}\n\nexport default withGlobal<OwnProps>(\n (global, { message }): StateProps => {\n const sender = selectSender(global, message);\n\n return { sender };\n },\n (setGlobal, actions): DispatchProps => pick(actions, ['focusMessage', 'closeAudioPlayer']),\n)(AudioPlayer);\n","import React, {\n FC, useCallback, useMemo, memo, useEffect, useRef, useState,\n} from '../../lib/teact/teact';\nimport { withGlobal } from '../../lib/teact/teactn';\nimport cycleRestrict from '../../util/cycleRestrict';\n\nimport { GlobalActions, MessageListType } from '../../global/types';\nimport {\n ApiMessage,\n ApiChat,\n ApiTypingStatus,\n MAIN_THREAD_ID, ApiUser,\n} from '../../api/types';\nimport { NotifyException, NotifySettings } from '../../types';\n\nimport {\n MIN_SCREEN_WIDTH_FOR_STATIC_LEFT_COLUMN,\n MOBILE_SCREEN_MAX_WIDTH,\n EDITABLE_INPUT_ID,\n MIN_SCREEN_WIDTH_FOR_STATIC_RIGHT_COLUMN,\n SAFE_SCREEN_WIDTH_FOR_STATIC_RIGHT_COLUMN,\n SAFE_SCREEN_WIDTH_FOR_CHAT_INFO,\n} from '../../config';\nimport { IS_SINGLE_COLUMN_LAYOUT, IS_TABLET_COLUMN_LAYOUT } from '../../util/environment';\nimport {\n isChatPrivate,\n isChatArchived,\n getMessageKey,\n getChatTitle,\n getSenderTitle,\n selectIsChatMuted,\n} from '../../modules/helpers';\nimport {\n selectChat,\n selectChatMessage,\n selectAllowedMessageActions,\n selectIsRightColumnShown,\n selectThreadTopMessageId,\n selectThreadInfo,\n selectChatMessages,\n selectPinnedIds,\n selectIsChatWithSelf,\n selectForwardedSender,\n selectScheduledIds,\n selectIsInSelectMode,\n selectIsChatWithBot,\n selectNotifySettings,\n selectNotifyExceptions,\n} from '../../modules/selectors';\nimport useEnsureMessage from '../../hooks/useEnsureMessage';\nimport useWindowSize from '../../hooks/useWindowSize';\nimport useShowTransition from '../../hooks/useShowTransition';\nimport useCurrentOrPrev from '../../hooks/useCurrentOrPrev';\nimport { pick } from '../../util/iteratees';\nimport { formatIntegerCompact } from '../../util/textFormat';\nimport buildClassName from '../../util/buildClassName';\nimport useLang from '../../hooks/useLang';\n\nimport PrivateChatInfo from '../common/PrivateChatInfo';\nimport GroupChatInfo from '../common/GroupChatInfo';\nimport Transition from '../ui/Transition';\nimport Button from '../ui/Button';\nimport HeaderActions from './HeaderActions';\nimport HeaderPinnedMessage from './HeaderPinnedMessage';\nimport AudioPlayer from './AudioPlayer';\n\nimport './MiddleHeader.scss';\n\nconst ANIMATION_DURATION = 350;\n\ntype OwnProps = {\n chatId: number;\n threadId: number;\n messageListType: MessageListType;\n isReady?: boolean;\n};\n\ntype StateProps = {\n chat?: ApiChat;\n pinnedMessageIds?: number[] | number;\n messagesById?: Record<number, ApiMessage>;\n canUnpin?: boolean;\n topMessageSender?: ApiChat | ApiUser;\n typingStatus?: ApiTypingStatus;\n isSelectModeActive?: boolean;\n isLeftColumnShown?: boolean;\n isRightColumnShown?: boolean;\n audioMessage?: ApiMessage;\n chatsById?: Record<number, ApiChat>;\n messagesCount?: number;\n isChatWithSelf?: boolean;\n isChatWithBot?: boolean;\n lastSyncTime?: number;\n notifySettings: NotifySettings;\n notifyExceptions?: Record<number, NotifyException>;\n shouldSkipHistoryAnimations?: boolean;\n currentTransitionKey: number;\n};\n\ntype DispatchProps = Pick<GlobalActions, (\n 'openChatWithInfo' | 'pinMessage' | 'focusMessage' | 'openChat' | 'openPreviousChat' | 'loadPinnedMessages' |\n 'toggleLeftColumn' | 'exitMessageSelectMode'\n)>;\n\nconst MiddleHeader: FC<OwnProps & StateProps & DispatchProps> = ({\n chatId,\n threadId,\n messageListType,\n isReady,\n pinnedMessageIds,\n messagesById,\n canUnpin,\n topMessageSender,\n typingStatus,\n isSelectModeActive,\n isLeftColumnShown,\n isRightColumnShown,\n audioMessage,\n chat,\n chatsById,\n messagesCount,\n isChatWithSelf,\n isChatWithBot,\n lastSyncTime,\n notifySettings,\n notifyExceptions,\n shouldSkipHistoryAnimations,\n currentTransitionKey,\n openChatWithInfo,\n pinMessage,\n focusMessage,\n openChat,\n openPreviousChat,\n loadPinnedMessages,\n toggleLeftColumn,\n exitMessageSelectMode,\n}) => {\n const lang = useLang();\n\n const [pinnedMessageIndex, setPinnedMessageIndex] = useState(0);\n const pinnedMessageId = Array.isArray(pinnedMessageIds) ? pinnedMessageIds[pinnedMessageIndex] : pinnedMessageIds;\n const pinnedMessage = messagesById && pinnedMessageId ? messagesById[pinnedMessageId] : undefined;\n const pinnedMessagesCount = Array.isArray(pinnedMessageIds) ? pinnedMessageIds.length : (pinnedMessageIds ? 1 : 0);\n const chatTitleLength = chat && getChatTitle(lang, chat).length;\n const topMessageTitle = topMessageSender ? getSenderTitle(lang, topMessageSender) : undefined;\n\n useEffect(() => {\n if (threadId === MAIN_THREAD_ID && lastSyncTime && isReady) {\n loadPinnedMessages({ chatId });\n }\n }, [chatId, loadPinnedMessages, lastSyncTime, threadId, isReady]);\n\n // Reset pinned index when switching chats and pinning/unpinning\n useEffect(() => {\n setPinnedMessageIndex(0);\n }, [pinnedMessageIds]);\n\n useEnsureMessage(chatId, pinnedMessageId, pinnedMessage);\n\n const { width: windowWidth } = useWindowSize();\n\n const isLeftColumnHideable = windowWidth <= MIN_SCREEN_WIDTH_FOR_STATIC_LEFT_COLUMN;\n const shouldShowCloseButton = IS_TABLET_COLUMN_LAYOUT && isLeftColumnShown;\n\n // eslint-disable-next-line no-null/no-null\n const componentRef = useRef<HTMLDivElement>(null);\n const shouldAnimateTools = useRef<boolean>(true);\n\n const handleHeaderClick = useCallback(() => {\n openChatWithInfo({ id: chatId });\n }, [openChatWithInfo, chatId]);\n\n const handleUnpinMessage = useCallback((messageId: number) => {\n pinMessage({ chatId, messageId, isUnpin: true });\n }, [pinMessage, chatId]);\n\n const handlePinnedMessageClick = useCallback((): void => {\n if (pinnedMessage) {\n focusMessage({ chatId: pinnedMessage.chatId, threadId, messageId: pinnedMessage.id });\n\n const newIndex = cycleRestrict(pinnedMessagesCount, pinnedMessageIndex + 1);\n setPinnedMessageIndex(newIndex);\n }\n }, [pinnedMessage, focusMessage, threadId, pinnedMessagesCount, pinnedMessageIndex]);\n\n const handleAllPinnedClick = useCallback(() => {\n openChat({ id: chatId, threadId: MAIN_THREAD_ID, type: 'pinned' });\n }, [openChat, chatId]);\n\n const handleBackClick = useCallback((e: React.MouseEvent<HTMLElement, MouseEvent>) => {\n if (IS_SINGLE_COLUMN_LAYOUT) {\n const messageInput = document.getElementById(EDITABLE_INPUT_ID);\n if (messageInput) {\n messageInput.blur();\n }\n }\n\n if (threadId === MAIN_THREAD_ID && messageListType === 'thread' && currentTransitionKey === 0) {\n if (IS_SINGLE_COLUMN_LAYOUT || shouldShowCloseButton) {\n e.stopPropagation(); // Stop propagation to prevent chat re-opening on tablets\n openChat({ id: undefined });\n } else {\n toggleLeftColumn();\n }\n\n return;\n }\n\n if (messageListType === 'scheduled' && isSelectModeActive) {\n exitMessageSelectMode();\n }\n\n openPreviousChat();\n }, [\n threadId, messageListType, currentTransitionKey, isSelectModeActive, openPreviousChat, shouldShowCloseButton,\n openChat, toggleLeftColumn, exitMessageSelectMode,\n ]);\n\n const unreadCount = useMemo(() => {\n if (!isLeftColumnHideable || !chatsById) {\n return undefined;\n }\n\n let isActive = false;\n\n const totalCount = Object.values(chatsById).reduce((total, currentChat) => {\n if (isChatArchived(currentChat)) {\n return total;\n }\n\n const count = currentChat.unreadCount || 0;\n if (\n count && (!selectIsChatMuted(currentChat, notifySettings, notifyExceptions) || currentChat.unreadMentionsCount)\n ) {\n isActive = true;\n }\n\n return total + count;\n }, 0);\n\n if (!totalCount) {\n return undefined;\n }\n\n return {\n isActive,\n totalCount,\n };\n }, [isLeftColumnHideable, chatsById, notifySettings, notifyExceptions]);\n\n const canToolsCollideWithChatInfo = (\n windowWidth >= MIN_SCREEN_WIDTH_FOR_STATIC_LEFT_COLUMN\n && windowWidth < SAFE_SCREEN_WIDTH_FOR_CHAT_INFO\n ) || (\n windowWidth > MOBILE_SCREEN_MAX_WIDTH\n && windowWidth < MIN_SCREEN_WIDTH_FOR_STATIC_LEFT_COLUMN\n && (!chatTitleLength || chatTitleLength > 30)\n );\n const shouldUseStackedToolsClass = canToolsCollideWithChatInfo || (\n windowWidth > MIN_SCREEN_WIDTH_FOR_STATIC_RIGHT_COLUMN\n && windowWidth < SAFE_SCREEN_WIDTH_FOR_STATIC_RIGHT_COLUMN\n );\n\n const {\n shouldRender: shouldRenderAudioPlayer,\n transitionClassNames: audioPlayerClassNames,\n } = useShowTransition(Boolean(audioMessage));\n\n const renderingAudioMessage = useCurrentOrPrev(audioMessage);\n\n const {\n shouldRender: shouldRenderPinnedMessage,\n transitionClassNames: pinnedMessageClassNames,\n } = useShowTransition(pinnedMessage && !shouldRenderAudioPlayer);\n\n const renderingPinnedMessage = useCurrentOrPrev(pinnedMessage);\n const renderingPinnedMessageTitle = useCurrentOrPrev(topMessageTitle);\n\n const canRevealTools = (shouldRenderPinnedMessage && renderingPinnedMessage)\n || (shouldRenderAudioPlayer && renderingAudioMessage);\n\n // Logic for transition to and from custom display of AudioPlayer/PinnedMessage on smaller screens\n useEffect(() => {\n const componentEl = componentRef.current;\n if (!componentEl) {\n return;\n }\n\n if (!shouldUseStackedToolsClass || !canRevealTools) {\n componentEl.classList.remove('tools-stacked', 'animated');\n shouldAnimateTools.current = true;\n return;\n }\n\n if (isRightColumnShown || canToolsCollideWithChatInfo) {\n if (shouldAnimateTools.current) {\n componentEl.classList.add('tools-stacked', 'animated');\n shouldAnimateTools.current = false;\n }\n\n // Remove animation class to prevent it messing up the show transitions\n setTimeout(() => {\n componentEl.classList.remove('animated');\n }, ANIMATION_DURATION);\n } else {\n componentEl.classList.remove('tools-stacked');\n shouldAnimateTools.current = true;\n }\n }, [shouldUseStackedToolsClass, canRevealTools, canToolsCollideWithChatInfo, isRightColumnShown]);\n\n function renderInfo() {\n return (\n messageListType === 'thread' && threadId === MAIN_THREAD_ID ? (\n renderMainThreadInfo()\n ) : messageListType === 'thread' ? (\n <>\n {renderBackButton()}\n <h3>\n {lang('CommentsCount', messagesCount)}\n </h3>\n </>\n ) : messageListType === 'pinned' ? (\n <>\n {renderBackButton()}\n <h3>\n {lang('PinnedMessagesCount', messagesCount)}\n </h3>\n </>\n ) : messageListType === 'scheduled' ? (\n <>\n {renderBackButton()}\n <h3>\n {isChatWithSelf ? lang('Reminders') : lang('messages', messagesCount)}\n </h3>\n </>\n ) : undefined\n );\n }\n\n function renderMainThreadInfo() {\n return (\n <>\n {(isLeftColumnHideable || currentTransitionKey > 0) && renderBackButton(shouldShowCloseButton, unreadCount)}\n <div className=\"chat-info-wrapper\" onClick={handleHeaderClick}>\n {isChatPrivate(chatId) ? (\n <PrivateChatInfo\n userId={chatId}\n typingStatus={typingStatus}\n withFullInfo={isChatWithBot}\n withMediaViewer\n withUpdatingStatus\n noRtl\n />\n ) : (\n <GroupChatInfo\n chatId={chatId}\n typingStatus={typingStatus}\n noRtl\n withMediaViewer\n withFullInfo\n withUpdatingStatus\n />\n )}\n </div>\n </>\n );\n }\n\n function renderBackButton(asClose = false, unreadCountInfo?: typeof unreadCount) {\n return (\n <div className=\"back-button\">\n <Button\n round\n size=\"smaller\"\n color=\"translucent\"\n onClick={handleBackClick}\n ariaLabel={asClose ? 'Close' : 'Back'}\n >\n <div className={buildClassName('animated-close-icon', !asClose && 'state-back')} />\n </Button>\n {unreadCountInfo && (\n <div className={`unread-count ${unreadCountInfo.isActive ? 'active' : ''}`}>\n {formatIntegerCompact(unreadCountInfo.totalCount)}\n </div>\n )}\n </div>\n );\n }\n\n return (\n <div className=\"MiddleHeader\" ref={componentRef}>\n <Transition\n name={shouldSkipHistoryAnimations ? 'none' : 'slide-fade'}\n activeKey={currentTransitionKey}\n >\n {renderInfo}\n </Transition>\n\n <div className=\"header-tools\">\n {shouldRenderPinnedMessage && renderingPinnedMessage && !shouldRenderAudioPlayer && (\n <HeaderPinnedMessage\n key={chatId}\n message={renderingPinnedMessage}\n count={pinnedMessagesCount}\n index={pinnedMessageIndex}\n customTitle={renderingPinnedMessageTitle}\n className={pinnedMessageClassNames}\n onUnpinMessage={canUnpin ? handleUnpinMessage : undefined}\n onClick={handlePinnedMessageClick}\n onAllPinnedClick={handleAllPinnedClick}\n />\n )}\n {shouldRenderAudioPlayer && renderingAudioMessage && (\n <AudioPlayer\n key={getMessageKey(renderingAudioMessage)}\n message={renderingAudioMessage!}\n className={audioPlayerClassNames}\n />\n )}\n <HeaderActions\n chatId={chatId}\n threadId={threadId}\n messageListType={messageListType}\n />\n </div>\n </div>\n );\n};\n\nexport default memo(withGlobal<OwnProps>(\n (global, { chatId, threadId, messageListType }): StateProps => {\n const { isLeftColumnShown, lastSyncTime, shouldSkipHistoryAnimations } = global;\n const { byId: chatsById } = global.chats;\n const chat = selectChat(global, chatId);\n\n const { typingStatus } = chat || {};\n\n const { chatId: audioChatId, messageId: audioMessageId } = global.audioPlayer;\n const audioMessage = audioChatId && audioMessageId\n ? selectChatMessage(global, audioChatId, audioMessageId)\n : undefined;\n\n let messagesCount: number | undefined;\n if (messageListType === 'pinned') {\n const pinnedIds = selectPinnedIds(global, chatId);\n messagesCount = pinnedIds && pinnedIds.length;\n } else if (messageListType === 'scheduled') {\n const scheduledIds = selectScheduledIds(global, chatId);\n messagesCount = scheduledIds && scheduledIds.length;\n } else if (messageListType === 'thread' && threadId !== MAIN_THREAD_ID) {\n const threadInfo = selectThreadInfo(global, chatId, threadId);\n if (threadInfo) {\n messagesCount = threadInfo.messagesCount;\n }\n }\n\n const state: StateProps = {\n typingStatus,\n isLeftColumnShown,\n isRightColumnShown: selectIsRightColumnShown(global),\n isSelectModeActive: selectIsInSelectMode(global),\n audioMessage,\n chat,\n chatsById,\n messagesCount,\n isChatWithSelf: selectIsChatWithSelf(global, chatId),\n isChatWithBot: chat && selectIsChatWithBot(global, chat),\n lastSyncTime,\n notifySettings: selectNotifySettings(global),\n notifyExceptions: selectNotifyExceptions(global),\n shouldSkipHistoryAnimations,\n currentTransitionKey: Math.max(0, global.messages.messageLists.length - 1),\n };\n\n const messagesById = selectChatMessages(global, chatId);\n if (messageListType !== 'thread' || !messagesById) {\n return state;\n }\n\n Object.assign(state, { messagesById });\n\n if (threadId !== MAIN_THREAD_ID) {\n const pinnedMessageId = selectThreadTopMessageId(global, chatId, threadId);\n const message = pinnedMessageId ? selectChatMessage(global, chatId, pinnedMessageId) : undefined;\n const topMessageSender = message ? selectForwardedSender(global, message) : undefined;\n\n return {\n ...state,\n pinnedMessageIds: pinnedMessageId,\n canUnpin: false,\n topMessageSender,\n };\n }\n\n const pinnedMessageIds = selectPinnedIds(global, chatId);\n if (pinnedMessageIds && pinnedMessageIds.length) {\n const firstPinnedMessage = messagesById[pinnedMessageIds[0]];\n const {\n canUnpin,\n } = (firstPinnedMessage && selectAllowedMessageActions(global, firstPinnedMessage, threadId)) || {};\n\n return {\n ...state,\n pinnedMessageIds,\n canUnpin,\n };\n }\n\n return state;\n },\n (setGlobal, actions): DispatchProps => pick(actions, [\n 'openChatWithInfo',\n 'pinMessage',\n 'focusMessage',\n 'openChat',\n 'openPreviousChat',\n 'loadPinnedMessages',\n 'toggleLeftColumn',\n 'exitMessageSelectMode',\n ]),\n)(MiddleHeader));\n","import { ApiMessage } from '../../../api/types';\nimport { IAlbum } from '../../../types';\n\nimport { getDayStart } from '../../../util/dateFormat';\nimport { isActionMessage } from '../../../modules/helpers';\n\ntype SenderGroup = (ApiMessage | IAlbum)[];\n\nconst GROUP_INTERVAL_SECONDS = 600; // 10 minutes\n\nexport type MessageDateGroup = {\n originalDate: number;\n datetime: number;\n senderGroups: SenderGroup[];\n};\n\nexport function isAlbum(messageOrAlbum: ApiMessage | IAlbum): messageOrAlbum is IAlbum {\n return 'albumId' in messageOrAlbum;\n}\n\nexport function groupMessages(messages: ApiMessage[], firstUnreadId?: number) {\n let currentSenderGroup: SenderGroup = [];\n let currentDateGroup = {\n originalDate: messages[0].date,\n datetime: Number(getDayStart(messages[0].date * 1000)),\n senderGroups: [currentSenderGroup],\n };\n let currentAlbum: IAlbum | undefined;\n\n const dateGroups: MessageDateGroup[] = [currentDateGroup];\n\n messages.forEach((message, index) => {\n if (message.isInAlbum) {\n if (!currentAlbum) {\n currentAlbum = {\n albumId: message.groupedId!,\n messages: [message],\n mainMessage: message,\n };\n } else {\n currentAlbum.messages.push(message);\n if (message.content.text) {\n currentAlbum.mainMessage = message;\n }\n }\n } else {\n currentSenderGroup.push(message);\n }\n\n const nextMessage = messages[index + 1];\n\n if (\n currentAlbum\n && (!nextMessage || !nextMessage.groupedId || nextMessage.groupedId !== currentAlbum.albumId)\n ) {\n currentSenderGroup.push(currentAlbum);\n currentAlbum = undefined;\n }\n if (nextMessage) {\n const nextMessageDayStartsAt = Number(getDayStart(nextMessage.date * 1000));\n if (currentDateGroup.datetime !== nextMessageDayStartsAt) {\n currentDateGroup = {\n originalDate: nextMessage.date,\n datetime: nextMessageDayStartsAt,\n senderGroups: [],\n };\n dateGroups.push(currentDateGroup);\n\n currentSenderGroup = [];\n currentDateGroup.senderGroups.push(currentSenderGroup);\n } else if (\n nextMessage.id === firstUnreadId\n || message.senderId !== nextMessage.senderId\n || message.isOutgoing !== nextMessage.isOutgoing\n || isActionMessage(message)\n || isActionMessage(nextMessage)\n || (\n message.forwardInfo && nextMessage.forwardInfo\n && (\n message.forwardInfo.senderUserId !== nextMessage.forwardInfo.senderUserId\n || message.forwardInfo.fromChatId !== nextMessage.forwardInfo.fromChatId\n || message.forwardInfo.hiddenUserName !== nextMessage.forwardInfo.hiddenUserName\n )\n )\n || message.inlineButtons\n || nextMessage.inlineButtons\n || (nextMessage.date - message.date) > GROUP_INTERVAL_SECONDS\n ) {\n currentSenderGroup = [];\n currentDateGroup.senderGroups.push(currentSenderGroup);\n }\n }\n });\n\n return dateGroups;\n}\n","import React from '../../../lib/teact/teact';\n\nimport { EDITABLE_INPUT_ID } from '../../../config';\nimport { IS_SINGLE_COLUMN_LAYOUT } from '../../../util/environment';\n\nexport function preventMessageInputBlur(e: React.MouseEvent<HTMLElement>) {\n if (\n IS_SINGLE_COLUMN_LAYOUT\n || !document.activeElement\n || document.activeElement.id !== EDITABLE_INPUT_ID\n || e.target !== e.currentTarget\n ) {\n return;\n }\n\n e.preventDefault();\n}\n","import { useCallback } from '../../../lib/teact/teact';\n\nimport { fastRaf } from '../../../util/schedulers';\nimport useDebounce from '../../../hooks/useDebounce';\nimport useFlag from '../../../hooks/useFlag';\n\nconst DEBOUNCE = 1000;\nconst STICKY_TOP = 10;\nconst STICKY_TOP_WITH_TOOLS = 60;\n\nexport default function useStickyDates() {\n // For some reason we can not synchronously hide a sticky element (from `useLayoutEffect`) when chat opens\n // so we will add `position: sticky` only after first scroll. There would be no animation on the first show though.\n const [isScrolled, markIsScrolled] = useFlag(false);\n\n const runDebounced = useDebounce(DEBOUNCE, false);\n\n const updateStickyDates = useCallback((container: HTMLDivElement, hasTools?: boolean) => {\n markIsScrolled();\n\n if (!document.body.classList.contains('is-scrolling-messages')) {\n fastRaf(() => {\n document.body.classList.add('is-scrolling-messages');\n });\n }\n\n runDebounced(() => {\n fastRaf(() => {\n const currentStuck = document.querySelector('.stuck');\n if (currentStuck) {\n currentStuck.classList.remove('stuck');\n }\n\n const stuckDateEl = findStuckDate(container, hasTools);\n if (stuckDateEl) {\n stuckDateEl.classList.add('stuck');\n }\n\n document.body.classList.remove('is-scrolling-messages');\n });\n });\n }, [markIsScrolled, runDebounced]);\n\n return {\n isScrolled,\n updateStickyDates,\n };\n}\n\nfunction findStuckDate(container: HTMLElement, hasTools?: boolean) {\n const allElements = container.querySelectorAll<HTMLDivElement>('.sticky-date');\n const containerTop = container.scrollTop;\n\n return Array.from(allElements).find((el) => {\n const { offsetTop, offsetHeight } = el;\n const top = offsetTop - containerTop;\n return -offsetHeight <= top && top <= (hasTools ? STICKY_TOP_WITH_TOOLS : STICKY_TOP);\n });\n}\n","import { useMemo } from '../lib/teact/teact';\n\nimport { debounce } from '../util/schedulers';\n\nexport default function useDebounce(ms: number, shouldRunFirst?: boolean, shouldRunLast?: boolean) {\n return useMemo(() => {\n return debounce((cb) => cb(), ms, shouldRunFirst, shouldRunLast);\n }, [ms, shouldRunFirst, shouldRunLast]);\n}\n","import { RefObject } from 'react';\nimport { getDispatch } from '../../../lib/teact/teactn';\n\nimport { MessageListType } from '../../../global/types';\n\nimport { IS_ANDROID, IS_SINGLE_COLUMN_LAYOUT } from '../../../util/environment';\nimport { useIntersectionObserver } from '../../../hooks/useIntersectionObserver';\nimport useBackgroundMode from '../../../hooks/useBackgroundMode';\n\nconst INTERSECTION_THROTTLE_FOR_MEDIA = IS_ANDROID ? 1000 : 350;\nconst INTERSECTION_MARGIN_FOR_MEDIA = IS_SINGLE_COLUMN_LAYOUT ? 300 : 500;\n\nexport default function useMessageObservers(\n type: MessageListType,\n containerRef: RefObject<HTMLDivElement>,\n memoFirstUnreadIdRef: { current: number | undefined },\n) {\n const { markMessageListRead, markMessagesRead } = getDispatch();\n\n const {\n observe: observeIntersectionForMedia,\n } = useIntersectionObserver({\n rootRef: containerRef,\n throttleMs: INTERSECTION_THROTTLE_FOR_MEDIA,\n margin: INTERSECTION_MARGIN_FOR_MEDIA,\n });\n\n const {\n observe: observeIntersectionForReading, freeze: freezeForReading, unfreeze: unfreezeForReading,\n } = useIntersectionObserver({\n rootRef: containerRef,\n }, (entries) => {\n if (type !== 'thread') {\n return;\n }\n\n let maxId = 0;\n const mentionIds: number[] = [];\n\n entries.forEach((entry) => {\n const { isIntersecting, target } = entry;\n\n if (!isIntersecting) {\n return;\n }\n\n const { dataset } = target as HTMLDivElement;\n\n const messageId = Number(dataset.lastMessageId || dataset.messageId);\n if (messageId > maxId) {\n maxId = messageId;\n }\n\n if (dataset.hasUnreadMention) {\n mentionIds.push(messageId);\n }\n });\n\n if (memoFirstUnreadIdRef.current && maxId >= memoFirstUnreadIdRef.current) {\n markMessageListRead({ maxId });\n }\n\n if (mentionIds.length) {\n markMessagesRead({ messageIds: mentionIds });\n }\n });\n\n useBackgroundMode(freezeForReading, unfreezeForReading);\n\n const { observe: observeIntersectionForAnimatedStickers } = useIntersectionObserver({\n rootRef: containerRef,\n throttleMs: INTERSECTION_THROTTLE_FOR_MEDIA,\n });\n\n return {\n observeIntersectionForMedia,\n observeIntersectionForReading,\n observeIntersectionForAnimatedStickers,\n };\n}\n","import { ApiMessage } from '../../../../api/types';\n\nimport { getMessageContent } from '../../../../modules/helpers';\n\nexport function isEmojiOnlyMessage(customShape?: boolean | number) {\n return typeof customShape === 'number';\n}\n\nexport function buildContentClassName(\n message: ApiMessage,\n {\n hasReply,\n customShape,\n isLastInGroup,\n asForwarded,\n hasThread,\n forceSenderName,\n hasComments,\n }: {\n hasReply?: boolean;\n customShape?: boolean | number;\n isLastInGroup?: boolean;\n asForwarded?: boolean;\n hasThread?: boolean;\n forceSenderName?: boolean;\n hasComments?: boolean;\n } = {},\n) {\n const {\n text, photo, video, audio, voice, document, poll, webPage, contact,\n } = getMessageContent(message);\n\n const classNames = ['message-content'];\n const isMedia = photo || video;\n const isMediaWithNoText = isMedia && !text;\n const isViaBot = Boolean(message.viaBotId);\n\n if (isEmojiOnlyMessage(customShape)) {\n classNames.push(`emoji-only emoji-only-${customShape}`);\n } else if (text) {\n classNames.push('text');\n }\n\n if (customShape) {\n classNames.push('custom-shape');\n if (video && video.isRound) {\n classNames.push('round');\n }\n\n if (hasComments) {\n classNames.push('has-comments');\n }\n }\n if (photo || video) {\n classNames.push('media');\n } else if (audio) {\n classNames.push('audio');\n } else if (voice) {\n classNames.push('voice');\n } else if (document) {\n classNames.push('document');\n } else if (contact) {\n classNames.push('contact');\n } else if (poll) {\n classNames.push('poll');\n } else if (webPage) {\n classNames.push('web-page');\n\n if (webPage.photo || webPage.video) {\n classNames.push('media');\n }\n }\n\n if (asForwarded && !customShape) {\n classNames.push('is-forwarded');\n }\n\n if (hasReply) {\n classNames.push('is-reply');\n }\n\n if (hasThread) {\n classNames.push('has-replies');\n }\n\n if (isViaBot) {\n classNames.push('is-via-bot');\n }\n\n if (forceSenderName) {\n classNames.push('force-sender-name');\n }\n\n if (!customShape) {\n classNames.push('has-shadow');\n\n if (isMedia && hasComments) {\n classNames.push('has-background');\n }\n\n if (hasReply || asForwarded || !isMediaWithNoText || isViaBot || forceSenderName) {\n classNames.push('has-solid-background');\n }\n\n if (isLastInGroup && (photo || !isMediaWithNoText)) {\n classNames.push('has-appendix');\n }\n }\n\n return classNames.join(' ');\n}\n","import { ApiMessage } from '../../../../api/types';\nimport { calculateInlineImageDimensions, calculateVideoDimensions } from '../../../common/helpers/mediaDimensions';\nimport {\n getMessageText,\n getMessagePhoto,\n getMessageWebPagePhoto,\n isForwardedMessage,\n isOwnMessage,\n getMessageVideo,\n} from '../../../../modules/helpers';\n\nconst MIN_MEDIA_WIDTH = 100;\nconst MIN_MEDIA_WIDTH_WITH_COMMENTS = 238;\nconst MIN_MEDIA_WIDTH_WITH_TEXT = 175;\nconst MIN_MEDIA_WIDTH_WITH_TEXT_AND_COMMENTS = 238;\nconst MIN_MEDIA_HEIGHT = 90;\nconst SMALL_IMAGE_THRESHOLD = 12;\n\nexport function getMinMediaWidth(hasText?: boolean, hasCommentButton?: boolean) {\n return hasText\n ? (hasCommentButton ? MIN_MEDIA_WIDTH_WITH_TEXT_AND_COMMENTS : MIN_MEDIA_WIDTH_WITH_TEXT)\n : (hasCommentButton ? MIN_MEDIA_WIDTH_WITH_COMMENTS : MIN_MEDIA_WIDTH);\n}\n\nexport function calculateMediaDimensions(message: ApiMessage, noAvatars?: boolean) {\n const isOwn = isOwnMessage(message);\n const isForwarded = isForwardedMessage(message);\n const photo = getMessagePhoto(message) || getMessageWebPagePhoto(message);\n const video = getMessageVideo(message);\n\n const isWebPagePhoto = Boolean(getMessageWebPagePhoto(message));\n const { width, height } = photo\n ? calculateInlineImageDimensions(photo, isOwn, isForwarded, isWebPagePhoto, noAvatars)\n : calculateVideoDimensions(video!, isOwn, isForwarded, noAvatars);\n\n const hasText = Boolean(getMessageText(message));\n const minMediaWidth = getMinMediaWidth(hasText);\n\n let stretchFactor = 1;\n if (width < minMediaWidth && minMediaWidth - width < SMALL_IMAGE_THRESHOLD) {\n stretchFactor = minMediaWidth / width;\n }\n if (height * stretchFactor < MIN_MEDIA_HEIGHT && MIN_MEDIA_HEIGHT - height * stretchFactor < SMALL_IMAGE_THRESHOLD) {\n stretchFactor = MIN_MEDIA_HEIGHT / height;\n }\n\n const finalWidth = Math.round(width * stretchFactor);\n const finalHeight = Math.round(height * stretchFactor);\n\n return {\n width: finalWidth,\n height: finalHeight,\n isSmall: finalWidth < minMediaWidth || finalHeight < MIN_MEDIA_HEIGHT,\n };\n}\n","/* eslint-disable no-bitwise */\n// Based on\n// https://github.com/telegramdesktop/tdesktop/blob/dev/Telegram/SourceFiles/ui/grouped_layout.cpp\n// https://github.com/overtake/TelegramSwift/blob/master/Telegram-Mac/GroupedLayout.swift#L83\n\nimport { IAlbum } from '../../../../types';\nimport { ApiMessage, ApiDimensions } from '../../../../api/types';\n\nimport { getAvailableWidth, REM } from '../../../common/helpers/mediaDimensions';\nimport { calculateMediaDimensions } from './mediaDimensions';\n\nexport const AlbumRectPart = {\n None: 0,\n Top: 1,\n Right: 2,\n Bottom: 4,\n Left: 8,\n};\n\ntype IAttempt = {\n lineCounts: number[];\n heights: number[];\n};\nexport type IMediaDimensions = {\n width: number;\n height: number;\n x: number;\n y: number;\n};\ntype IMediaLayout = {\n dimensions: IMediaDimensions;\n sides: number;\n};\ntype ILayoutParams = {\n ratios: number[];\n proportions: string;\n averageRatio: number;\n maxWidth: number;\n minWidth: number;\n maxHeight: number;\n spacing: number;\n};\nexport type IAlbumLayout = {\n layout: IMediaLayout[];\n containerStyle: ApiDimensions;\n};\n\nfunction getRatios(messages: ApiMessage[]) {\n return messages.map(\n (message) => {\n const dimensions = calculateMediaDimensions(message) as ApiDimensions;\n\n return dimensions.width / dimensions.height;\n },\n );\n}\n\nfunction getProportions(ratios: number[]) {\n return ratios.map((ratio) => (ratio > 1.2 ? 'w' : (ratio < 0.8 ? 'n' : 'q'))).join('');\n}\n\nfunction getAverageRatio(ratios: number[]) {\n return ratios.reduce((result, ratio) => ratio + result, 1) / ratios.length;\n}\n\nfunction accumulate(list: number[], initValue: number) {\n return list.reduce((accumulator, item) => accumulator + item, initValue);\n}\n\nfunction clamp(num: number, low: number, high: number) {\n return num < low ? low : (num > high ? high : num);\n}\n\nfunction cropRatios(ratios: number[], averageRatio: number) {\n return ratios.map((ratio) => (averageRatio > 1.1 ? clamp(ratio, 1, 2.75) : clamp(ratio, 0.6667, 1)));\n}\n\nfunction calculateContainerSize(layout: IMediaLayout[]) {\n const styles: ApiDimensions = { width: 0, height: 0 };\n layout.forEach(({\n dimensions,\n sides,\n }) => {\n if (sides & AlbumRectPart.Right) {\n styles.width = dimensions.width + dimensions.x;\n }\n if (sides & AlbumRectPart.Bottom) {\n styles.height = dimensions.height + dimensions.y;\n }\n });\n\n return styles;\n}\n\nexport function calculateAlbumLayout(\n isOwn: boolean,\n isForwarded: boolean,\n noAvatars: boolean,\n album: IAlbum,\n): IAlbumLayout {\n const spacing = 2;\n const ratios = getRatios(album.messages);\n const proportions = getProportions(ratios);\n const averageRatio = getAverageRatio(ratios);\n const albumCount = ratios.length;\n const forceCalc = ratios.some((ratio) => ratio > 2);\n const maxWidth = getAvailableWidth(isOwn, isForwarded, false, noAvatars) - (isForwarded ? 2.5 : 0) * REM;\n const maxHeight = maxWidth;\n\n let layout;\n\n const params = {\n ratios,\n proportions,\n averageRatio,\n maxWidth,\n minWidth: 100,\n maxHeight,\n spacing,\n };\n\n if (albumCount >= 5 || forceCalc) {\n layout = layoutWithComplexLayouter(params);\n } else if (albumCount === 2) {\n layout = layoutTwo(params);\n } else if (albumCount === 3) {\n layout = layoutThree(params);\n } else {\n layout = layoutFour(params);\n }\n\n return {\n layout,\n containerStyle: calculateContainerSize(layout),\n };\n}\n\nfunction layoutWithComplexLayouter({\n ratios: originalRatios,\n averageRatio,\n maxWidth,\n minWidth,\n spacing,\n maxHeight = (4 * maxWidth) / 3,\n}: ILayoutParams) {\n const ratios = cropRatios(originalRatios, averageRatio);\n const count = originalRatios.length;\n const result = new Array(count);\n const attempts: IAttempt[] = [];\n\n const multiHeight = (offset: number, attemptCount: number) => {\n const attemptRatios = ratios.slice(offset, offset + attemptCount);\n const sum = accumulate(attemptRatios, 0);\n\n return (maxWidth - (attemptCount - 1) * spacing) / sum;\n };\n\n const pushAttempt = (lineCounts: number[]) => {\n const heights: number[] = [];\n let offset = 0;\n lineCounts.forEach((currentCount) => {\n heights.push(multiHeight(offset, currentCount));\n offset += currentCount;\n });\n\n attempts.push({\n lineCounts,\n heights,\n });\n };\n\n for (let first = 1; first !== count; ++first) {\n const second = count - first;\n if (first <= 3 && second <= 3) {\n pushAttempt([first, second]);\n }\n }\n\n for (let first = 1; first !== count - 1; ++first) {\n for (let second = 1; second !== count - first; ++second) {\n const third = count - first - second;\n if (first <= 3 && second <= (averageRatio < 0.85 ? 4 : 3) && third <= 3) {\n pushAttempt([first, second, third]);\n }\n }\n }\n\n for (let first = 1; first !== count - 1; ++first) {\n for (let second = 1; second !== count - first; ++second) {\n for (let third = 1; third !== count - first - second; ++third) {\n const fourth = count - first - second - third;\n if (first <= 3 && second <= 3 && third <= 3 && fourth <= 4) {\n pushAttempt([first, second, third, fourth]);\n }\n }\n }\n }\n\n let optimalAttempt: IAttempt | undefined;\n let optimalDiff = 0;\n for (let i = 0; i < attempts.length; i++) {\n const {\n heights,\n lineCounts,\n } = attempts[i];\n const lineCount = lineCounts.length;\n const totalHeight = accumulate(heights, 0) + spacing * (lineCount - 1);\n const minLineHeight = Math.min(...heights);\n const bad1 = minLineHeight < minWidth ? 1.5 : 1;\n const bad2 = (() => {\n for (let line = 1; line !== lineCount; ++line) {\n if (lineCounts[line - 1] > lineCounts[line]) {\n return 1.5;\n }\n }\n\n return 1;\n })();\n const diff = Math.abs(totalHeight - maxHeight) * bad1 * bad2;\n\n if (!optimalAttempt || diff < optimalDiff) {\n optimalAttempt = attempts[i];\n optimalDiff = diff;\n }\n }\n\n const optimalCounts = optimalAttempt!.lineCounts;\n const optimalHeights = optimalAttempt!.heights;\n const rowCount = optimalCounts.length;\n let index = 0;\n let y = 0;\n for (let row = 0; row !== rowCount; ++row) {\n const colCount = optimalCounts[row];\n const lineHeight = optimalHeights[row];\n const height = Math.round(lineHeight);\n let x = 0;\n\n for (let col = 0; col !== colCount; ++col) {\n const sides = AlbumRectPart.None\n | (row === 0 ? AlbumRectPart.Top : AlbumRectPart.None)\n | (row === rowCount - 1 ? AlbumRectPart.Bottom : AlbumRectPart.None)\n | (col === 0 ? AlbumRectPart.Left : AlbumRectPart.None)\n | (col === colCount - 1 ? AlbumRectPart.Right : AlbumRectPart.None);\n const ratio = ratios[index];\n const width = col === colCount - 1 ? maxWidth - x : Math.round(ratio * lineHeight);\n result[index] = {\n dimensions: {\n x,\n y,\n width,\n height,\n },\n sides,\n };\n x += width + spacing;\n ++index;\n }\n y += height + spacing;\n }\n\n return result;\n}\n\n\nfunction layoutTwo(params: ILayoutParams) {\n const {\n ratios,\n proportions,\n averageRatio,\n } = params;\n return proportions === 'ww' && averageRatio > 1.4 && ratios[1] - ratios[0] < 0.2\n ? layoutTwoTopBottom(params)\n : proportions === 'ww' || proportions === 'qq'\n ? layoutTwoLeftRightEqual(params)\n : layoutTwoLeftRight(params);\n}\n\nfunction layoutTwoTopBottom(params: ILayoutParams) {\n const {\n ratios,\n maxWidth,\n spacing,\n maxHeight,\n } = params;\n const height = Math.round(Math.min(maxWidth / ratios[0], Math.min(maxWidth / ratios[1], (maxHeight - spacing) / 2)));\n\n return [{\n dimensions: {\n x: 0,\n y: 0,\n width: maxWidth,\n height,\n },\n sides: AlbumRectPart.Left | AlbumRectPart.Top | AlbumRectPart.Right,\n }, {\n dimensions: {\n x: 0,\n y: height + spacing,\n width: maxWidth,\n height,\n },\n sides: AlbumRectPart.Left | AlbumRectPart.Bottom | AlbumRectPart.Right,\n }];\n}\n\nfunction layoutTwoLeftRightEqual(params: ILayoutParams) {\n const {\n ratios,\n maxWidth,\n spacing,\n maxHeight,\n } = params;\n const width = (maxWidth - spacing) / 2;\n const height = Math.round(Math.min(width / ratios[0], Math.min(width / ratios[1], maxHeight)));\n return [{\n dimensions: {\n x: 0,\n y: 0,\n width,\n height,\n },\n sides: AlbumRectPart.Top | AlbumRectPart.Left | AlbumRectPart.Bottom,\n }, {\n dimensions: {\n x: width + spacing,\n y: 0,\n width,\n height,\n },\n sides: AlbumRectPart.Top | AlbumRectPart.Right | AlbumRectPart.Bottom,\n }];\n}\n\nfunction layoutTwoLeftRight(params: ILayoutParams) {\n const {\n ratios,\n minWidth,\n maxWidth,\n spacing,\n maxHeight,\n } = params;\n const minimalWidth = Math.round(1.5 * minWidth);\n const secondWidth = Math.min(\n Math.round(\n Math.max(\n 0.4 * (maxWidth - spacing),\n (maxWidth - spacing) / ratios[0] / (1 / ratios[0] + 1 / ratios[1]),\n ),\n ),\n maxWidth - spacing - minimalWidth,\n );\n const firstWidth = maxWidth - secondWidth - spacing;\n const height = Math.min(maxHeight, Math.round(Math.min(firstWidth / ratios[0], secondWidth / ratios[1])));\n\n return [{\n dimensions: {\n x: 0,\n y: 0,\n width: firstWidth,\n height,\n },\n sides: AlbumRectPart.Top | AlbumRectPart.Left | AlbumRectPart.Bottom,\n }, {\n dimensions: {\n x: firstWidth + spacing,\n y: 0,\n width: secondWidth,\n height,\n },\n sides: AlbumRectPart.Top | AlbumRectPart.Right | AlbumRectPart.Bottom,\n }];\n}\n\nfunction layoutThree(params: ILayoutParams) {\n const { proportions } = params;\n\n return proportions[0] === 'n'\n ? layoutThreeLeftAndOther(params)\n : layoutThreeTopAndOther(params);\n}\n\nfunction layoutThreeLeftAndOther(params: ILayoutParams) {\n const {\n maxHeight,\n spacing,\n ratios,\n maxWidth,\n minWidth,\n } = params;\n const firstHeight = maxHeight;\n const thirdHeight = Math.round(\n Math.min(\n (maxHeight - spacing) / 2,\n (ratios[1] * (maxWidth - spacing)) / (ratios[2] + ratios[1]),\n ),\n );\n const secondHeight = firstHeight - thirdHeight - spacing;\n const rightWidth = Math.max(\n minWidth,\n Math.round(\n Math.min(\n (maxWidth - spacing) / 2,\n Math.min(\n thirdHeight * ratios[2],\n secondHeight * ratios[1],\n ),\n ),\n ),\n );\n const leftWidth = Math.min(Math.round(firstHeight * ratios[0]), maxWidth - spacing - rightWidth);\n\n return [{\n dimensions: {\n x: 0,\n y: 0,\n width: leftWidth,\n height: firstHeight,\n },\n sides: AlbumRectPart.Top | AlbumRectPart.Left | AlbumRectPart.Bottom,\n }, {\n dimensions: {\n x: leftWidth + spacing,\n y: 0,\n width: rightWidth,\n height: secondHeight,\n },\n sides: AlbumRectPart.Top | AlbumRectPart.Right,\n }, {\n dimensions: {\n x: leftWidth + spacing,\n y: secondHeight + spacing,\n width: rightWidth,\n height: thirdHeight,\n },\n sides: AlbumRectPart.Bottom | AlbumRectPart.Right,\n }];\n}\n\nfunction layoutThreeTopAndOther(params: ILayoutParams) {\n const {\n maxWidth,\n ratios,\n maxHeight,\n spacing,\n } = params;\n const firstWidth = maxWidth;\n const firstHeight = Math.round(Math.min(firstWidth / ratios[0], 0.66 * (maxHeight - spacing)));\n const secondWidth = (maxWidth - spacing) / 2;\n const secondHeight = Math.min(\n maxHeight - firstHeight - spacing,\n Math.round(Math.min(\n secondWidth / ratios[1],\n secondWidth / ratios[2],\n )),\n );\n const thirdWidth = firstWidth - secondWidth - spacing;\n\n return [{\n dimensions: {\n x: 0,\n y: 0,\n width: firstWidth,\n height: firstHeight,\n },\n sides: AlbumRectPart.Left | AlbumRectPart.Top | AlbumRectPart.Right,\n }, {\n dimensions: {\n x: 0,\n y: firstHeight + spacing,\n width: secondWidth,\n height: secondHeight,\n },\n sides: AlbumRectPart.Bottom | AlbumRectPart.Left,\n }, {\n dimensions: {\n x: secondWidth + spacing,\n y: firstHeight + spacing,\n width: thirdWidth,\n height: secondHeight,\n },\n sides: AlbumRectPart.Bottom | AlbumRectPart.Right,\n }];\n}\n\nfunction layoutFour(params: ILayoutParams) {\n const { proportions } = params;\n\n return proportions[0] === 'w'\n ? layoutFourTopAndOther(params)\n : layoutFourLeftAndOther(params);\n}\n\nfunction layoutFourTopAndOther({\n maxWidth,\n ratios,\n spacing,\n maxHeight,\n minWidth,\n}: ILayoutParams) {\n const w = maxWidth;\n const h0 = Math.round(Math.min(w / ratios[0], 0.66 * (maxHeight - spacing)));\n const h = Math.round((maxWidth - 2 * spacing) / (ratios[1] + ratios[2] + ratios[3]));\n const w0 = Math.max(minWidth, Math.round(Math.min(0.4 * (maxWidth - 2 * spacing), h * ratios[1])));\n const w2 = Math.round(Math.max(Math.max(minWidth, 0.33 * (maxWidth - 2 * spacing)), h * ratios[3]));\n const w1 = w - w0 - w2 - 2 * spacing;\n const h1 = Math.min(maxHeight - h0 - spacing, h);\n\n return [{\n dimensions: {\n x: 0,\n y: 0,\n width: w,\n height: h0,\n },\n sides: AlbumRectPart.Left | AlbumRectPart.Top | AlbumRectPart.Right,\n }, {\n dimensions: {\n x: 0,\n y: h0 + spacing,\n width: w0,\n height: h1,\n },\n sides: AlbumRectPart.Bottom | AlbumRectPart.Left,\n }, {\n dimensions: {\n x: w0 + spacing,\n y: h0 + spacing,\n width: w1,\n height: h1,\n },\n sides: AlbumRectPart.Bottom,\n }, {\n dimensions: {\n x: w0 + spacing + w1 + spacing,\n y: h0 + spacing,\n width: w2,\n height: h1,\n },\n sides: AlbumRectPart.Right | AlbumRectPart.Bottom,\n }];\n}\n\nfunction layoutFourLeftAndOther({\n maxHeight,\n ratios,\n maxWidth,\n spacing,\n minWidth,\n}: ILayoutParams) {\n const h = maxHeight;\n const w0 = Math.round(Math.min(h * ratios[0], 0.6 * (maxWidth - spacing)));\n const w = Math.round((maxHeight - 2 * spacing) / (1 / ratios[1] + 1 / ratios[2] + 1 / ratios[3]));\n const h0 = Math.round(w / ratios[1]);\n const h1 = Math.round(w / ratios[2]);\n const h2 = h - h0 - h1 - 2 * spacing;\n const w1 = Math.max(minWidth, Math.min(maxWidth - w0 - spacing, w));\n\n return [{\n dimensions: {\n x: 0,\n y: 0,\n width: w0,\n height: h,\n },\n sides: AlbumRectPart.Top | AlbumRectPart.Left | AlbumRectPart.Bottom,\n }, {\n dimensions: {\n x: w0 + spacing,\n y: 0,\n width: w1,\n height: h0,\n },\n sides: AlbumRectPart.Top | AlbumRectPart.Right,\n }, {\n dimensions: {\n x: w0 + spacing,\n y: h0 + spacing,\n width: w1,\n height: h1,\n },\n sides: AlbumRectPart.Right,\n }, {\n dimensions: {\n x: w0 + spacing,\n y: h0 + h1 + 2 * spacing,\n width: w1,\n height: h2,\n },\n sides: AlbumRectPart.Bottom | AlbumRectPart.Right,\n }];\n}\n","import { IS_IOS } from '../../../../util/environment';\n\nlet element: HTMLSpanElement | undefined;\n\nexport default function calculateAuthorWidth(text: string) {\n if (!element) {\n element = document.createElement('span');\n // eslint-disable-next-line max-len\n element.style.font = IS_IOS\n // eslint-disable-next-line max-len\n ? '400 12px system-ui, -apple-system, BlinkMacSystemFont, \"Roboto\", \"Apple Color Emoji\", \"Helvetica Neue\", sans-serif'\n : '400 12px \"Roboto\", -apple-system, \"Apple Color Emoji\", BlinkMacSystemFont, \"Helvetica Neue\", sans-serif';\n element.style.whiteSpace = 'nowrap';\n element.style.position = 'absolute';\n element.style.left = '-999px';\n element.style.opacity = '.01';\n document.body.appendChild(element);\n }\n\n element.innerHTML = text;\n\n return element.offsetWidth;\n}\n","import { FocusDirection } from '../../../../types';\n\nimport { useLayoutEffect } from '../../../../lib/teact/teact';\nimport fastSmoothScroll from '../../../../util/fastSmoothScroll';\n\n// This is used when the viewport was replaced.\nconst RELOCATED_FOCUS_OFFSET = 1000;\nconst FOCUS_MARGIN = 20;\n\nexport default function useFocusMessage(\n elementRef: { current: HTMLDivElement | null },\n chatId: number,\n isFocused?: boolean,\n focusDirection?: FocusDirection,\n noFocusHighlight?: boolean,\n) {\n useLayoutEffect(() => {\n if (isFocused && elementRef.current) {\n const messagesContainer = elementRef.current.closest<HTMLDivElement>('.MessageList')!;\n\n fastSmoothScroll(\n messagesContainer,\n elementRef.current,\n // `noFocusHighlight` always called from “scroll-to-bottom” buttons\n noFocusHighlight ? 'end' : 'centerOrTop',\n FOCUS_MARGIN,\n focusDirection !== undefined ? RELOCATED_FOCUS_OFFSET : undefined,\n focusDirection,\n );\n }\n }, [elementRef, chatId, isFocused, focusDirection, noFocusHighlight]);\n}\n","import React, { FC, memo } from '../../../lib/teact/teact';\nimport { OwnProps } from './ContextMenuContainer';\nimport { Bundles } from '../../../util/moduleLoader';\n\nimport useModuleLoader from '../../../hooks/useModuleLoader';\n\nconst ContextMenuContainerAsync: FC<OwnProps> = (props) => {\n const { isOpen } = props;\n const ContextMenuContainer = useModuleLoader(Bundles.Extra, 'ContextMenuContainer', !isOpen);\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return ContextMenuContainer ? <ContextMenuContainer {...props} /> : undefined;\n};\n\nexport default memo(ContextMenuContainerAsync);\n","import React, {\n FC, memo, useEffect, useMemo, useRef,\n} from '../../lib/teact/teact';\nimport { withGlobal } from '../../lib/teact/teactn';\n\nimport { ApiUser, ApiMessage, ApiChat } from '../../api/types';\nimport { FocusDirection } from '../../types';\n\nimport {\n selectUser,\n selectChatMessage,\n selectIsMessageFocused,\n selectChat,\n} from '../../modules/selectors';\nimport { isChatChannel } from '../../modules/helpers';\nimport buildClassName from '../../util/buildClassName';\nimport renderText from '../common/helpers/renderText';\nimport { renderActionMessageText } from '../common/helpers/renderActionMessageText';\nimport useEnsureMessage from '../../hooks/useEnsureMessage';\nimport useContextMenuHandlers from '../../hooks/useContextMenuHandlers';\nimport { ObserveFn, useOnIntersect } from '../../hooks/useIntersectionObserver';\nimport useFocusMessage from './message/hooks/useFocusMessage';\nimport useLang from '../../hooks/useLang';\n\nimport ContextMenuContainer from './message/ContextMenuContainer.async';\nimport useFlag from '../../hooks/useFlag';\nimport useShowTransition from '../../hooks/useShowTransition';\nimport { preventMessageInputBlur } from './helpers/preventMessageInputBlur';\n\ntype OwnProps = {\n message: ApiMessage;\n observeIntersection?: ObserveFn;\n isEmbedded?: boolean;\n appearanceOrder?: number;\n isLastInList?: boolean;\n};\n\ntype StateProps = {\n usersById: Record<number, ApiUser>;\n sender?: ApiUser | ApiChat;\n targetUserIds?: number[];\n targetMessage?: ApiMessage;\n targetChatId?: number;\n isFocused: boolean;\n focusDirection?: FocusDirection;\n noFocusHighlight?: boolean;\n};\n\nconst APPEARANCE_DELAY = 10;\n\nconst ActionMessage: FC<OwnProps & StateProps> = ({\n message,\n observeIntersection,\n isEmbedded,\n appearanceOrder = 0,\n isLastInList,\n usersById,\n sender,\n targetUserIds,\n targetMessage,\n targetChatId,\n isFocused,\n focusDirection,\n noFocusHighlight,\n}) => {\n // eslint-disable-next-line no-null/no-null\n const ref = useRef<HTMLDivElement>(null);\n\n useOnIntersect(ref, observeIntersection);\n useEnsureMessage(message.chatId, message.replyToMessageId, targetMessage);\n useFocusMessage(ref, message.chatId, isFocused, focusDirection, noFocusHighlight);\n\n const lang = useLang();\n\n const noAppearanceAnimation = appearanceOrder <= 0;\n const [isShown, markShown] = useFlag(noAppearanceAnimation);\n useEffect(() => {\n if (noAppearanceAnimation) {\n return;\n }\n\n setTimeout(markShown, appearanceOrder * APPEARANCE_DELAY);\n }, [appearanceOrder, markShown, noAppearanceAnimation]);\n const { transitionClassNames } = useShowTransition(isShown, undefined, noAppearanceAnimation, false);\n\n const targetUsers = useMemo(() => {\n return targetUserIds\n ? targetUserIds.map((userId) => usersById && usersById[userId]).filter<ApiUser>(Boolean as any)\n : undefined;\n }, [targetUserIds, usersById]);\n\n const content = renderActionMessageText(\n lang,\n message,\n sender,\n targetUsers,\n targetMessage,\n targetChatId,\n isEmbedded ? { isEmbedded: true, asPlain: true } : undefined,\n );\n const {\n isContextMenuOpen, contextMenuPosition,\n handleBeforeContextMenu, handleContextMenu,\n handleContextMenuClose, handleContextMenuHide,\n } = useContextMenuHandlers(ref);\n const isContextMenuShown = contextMenuPosition !== undefined;\n\n const handleMouseDown = (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {\n preventMessageInputBlur(e);\n handleBeforeContextMenu(e);\n };\n\n if (isEmbedded) {\n return <span className=\"embedded-action-message\">{renderText(content as string)}</span>;\n }\n\n const className = buildClassName(\n 'ActionMessage message-list-item',\n isFocused && !noFocusHighlight && 'focused',\n isContextMenuShown && 'has-menu-open',\n isLastInList && 'last-in-list',\n transitionClassNames,\n );\n\n return (\n <div\n ref={ref}\n id={`message${message.id}`}\n className={className}\n data-message-id={message.id}\n onMouseDown={handleMouseDown}\n onContextMenu={handleContextMenu}\n >\n <span>{content}</span>\n {contextMenuPosition && (\n <ContextMenuContainer\n isOpen={isContextMenuOpen}\n anchor={contextMenuPosition}\n message={message}\n messageListType=\"thread\"\n onClose={handleContextMenuClose}\n onCloseAnimationEnd={handleContextMenuHide}\n />\n )}\n </div>\n );\n};\n\nexport default memo(withGlobal<OwnProps>(\n (global, { message }): StateProps => {\n const { byId: usersById } = global.users;\n const userId = message.senderId;\n const { targetUserIds, targetChatId } = message.content.action || {};\n const targetMessageId = message.replyToMessageId;\n const targetMessage = targetMessageId\n ? selectChatMessage(global, message.chatId, targetMessageId)\n : undefined;\n\n const isFocused = selectIsMessageFocused(global, message);\n const { direction: focusDirection, noHighlight: noFocusHighlight } = (isFocused && global.focusedMessage) || {};\n\n const chat = selectChat(global, message.chatId);\n const sender = chat && (isChatChannel(chat) || userId === message.chatId)\n ? chat\n : userId ? selectUser(global, userId) : undefined;\n\n return {\n usersById,\n sender,\n targetChatId,\n targetUserIds,\n targetMessage,\n isFocused,\n ...(isFocused && { focusDirection, noFocusHighlight }),\n };\n },\n)(ActionMessage));\n","import React, { FC, useRef } from '../../lib/teact/teact';\n\nimport { ApiUser, ApiMessage, ApiChat } from '../../api/types';\n\nimport {\n getMessageMediaHash,\n isActionMessage,\n getMessageSummaryText,\n getSenderTitle,\n getMessageRoundVideo,\n} from '../../modules/helpers';\nimport renderText from './helpers/renderText';\nimport { getPictogramDimensions } from './helpers/mediaDimensions';\nimport buildClassName from '../../util/buildClassName';\nimport { ObserveFn, useIsIntersecting } from '../../hooks/useIntersectionObserver';\nimport useMedia from '../../hooks/useMedia';\nimport useWebpThumbnail from '../../hooks/useWebpThumbnail';\nimport useLang from '../../hooks/useLang';\n\nimport ActionMessage from '../middle/ActionMessage';\n\nimport './EmbeddedMessage.scss';\n\ntype OwnProps = {\n observeIntersection?: ObserveFn;\n className?: string;\n message?: ApiMessage;\n sender?: ApiUser | ApiChat;\n title?: string;\n customText?: string;\n onClick: NoneToVoidFunction;\n};\n\nconst NBSP = '\\u00A0';\n\nconst EmbeddedMessage: FC<OwnProps> = ({\n className,\n message,\n sender,\n title,\n customText,\n observeIntersection,\n onClick,\n}) => {\n // eslint-disable-next-line no-null/no-null\n const ref = useRef<HTMLDivElement>(null);\n const isIntersecting = useIsIntersecting(ref, observeIntersection);\n\n const mediaBlobUrl = useMedia(message && getMessageMediaHash(message, 'pictogram'), !isIntersecting);\n const pictogramId = message && `sticker-reply-thumb${message.id}`;\n const mediaThumbnail = useWebpThumbnail(message);\n const isRoundVideo = Boolean(message && getMessageRoundVideo(message));\n\n const lang = useLang();\n\n const senderTitle = sender && getSenderTitle(lang, sender);\n\n return (\n <div\n ref={ref}\n className={buildClassName('EmbeddedMessage', className)}\n onClick={message ? onClick : undefined}\n >\n {mediaThumbnail && renderPictogram(pictogramId, mediaThumbnail, mediaBlobUrl, isRoundVideo)}\n <div className=\"message-text\">\n <p dir=\"auto\">\n {!message ? (\n customText || NBSP\n ) : isActionMessage(message) ? (\n <ActionMessage message={message} isEmbedded />\n ) : (\n renderText(getMessageSummaryText(lang, message, Boolean(mediaThumbnail)))\n )}\n </p>\n <div className=\"message-title\" dir=\"auto\">{renderText(senderTitle || title || NBSP)}</div>\n </div>\n </div>\n );\n};\n\nfunction renderPictogram(\n id: string | undefined,\n thumbDataUri: string,\n blobUrl?: string,\n isRoundVideo?: boolean,\n) {\n const { width, height } = getPictogramDimensions();\n\n return (\n <img\n id={id}\n src={blobUrl || thumbDataUri}\n width={width}\n height={height}\n alt=\"\"\n className={isRoundVideo ? 'round' : ''}\n />\n );\n}\n\nexport default EmbeddedMessage;\n","import React, { FC, memo } from '../../../lib/teact/teact';\n\nimport { ApiMessage, ApiMessageOutgoingStatus } from '../../../api/types';\n\nimport { formatTime } from '../../../util/dateFormat';\nimport { formatIntegerCompact } from '../../../util/textFormat';\n\nimport MessageOutgoingStatus from '../../common/MessageOutgoingStatus';\nimport renderText from '../../common/helpers/renderText';\nimport useLang from '../../../hooks/useLang';\n\nimport './MessageMeta.scss';\n\ntype OwnProps = {\n message: ApiMessage;\n outgoingStatus?: ApiMessageOutgoingStatus;\n signature?: string;\n onClick: () => void;\n};\n\nconst MessageMeta: FC<OwnProps> = ({\n message, outgoingStatus, signature, onClick,\n}) => {\n const lang = useLang();\n\n return (\n <span className=\"MessageMeta\" dir={lang.isRtl ? 'rtl' : 'ltr'} onClick={onClick}>\n {Boolean(message.views) && (\n <>\n <span className=\"message-views\">\n {formatIntegerCompact(message.views!)}\n </span>\n <i className=\"icon-channelviews\" />\n </>\n )}\n {signature && (\n <span className=\"message-signature\">{renderText(signature)}</span>\n )}\n <span className=\"message-time\">\n {message.isEdited && `${lang('EditedMessage')} `}\n {formatTime(message.date * 1000)}\n </span>\n {outgoingStatus && (\n <MessageOutgoingStatus status={outgoingStatus} />\n )}\n </span>\n );\n};\n\nexport default memo(MessageMeta);\n","import React, { FC, useRef } from '../../../lib/teact/teact';\n\nimport { ApiMessage } from '../../../api/types';\n\nimport { MEMOJI_STICKER_ID } from '../../../config';\nimport { getStickerDimensions } from '../../common/helpers/mediaDimensions';\nimport { getMessageMediaFormat, getMessageMediaHash } from '../../../modules/helpers';\nimport useMedia from '../../../hooks/useMedia';\nimport useTransitionForMedia from '../../../hooks/useTransitionForMedia';\nimport buildClassName from '../../../util/buildClassName';\nimport { ObserveFn, useIsIntersecting } from '../../../hooks/useIntersectionObserver';\nimport useFlag from '../../../hooks/useFlag';\nimport useWebpThumbnail from '../../../hooks/useWebpThumbnail';\n\nimport AnimatedSticker from '../../common/AnimatedSticker';\nimport StickerSetModal from '../../common/StickerSetModal.async';\n\nimport './Sticker.scss';\n\ntype OwnProps = {\n message: ApiMessage;\n observeIntersection: ObserveFn;\n observeIntersectionForPlaying: ObserveFn;\n shouldLoop?: boolean;\n lastSyncTime?: number;\n};\n\nconst Sticker: FC<OwnProps> = ({\n message, observeIntersection, observeIntersectionForPlaying, shouldLoop, lastSyncTime,\n}) => {\n // eslint-disable-next-line no-null/no-null\n const ref = useRef<HTMLDivElement>(null);\n\n const [isModalOpen, openModal, closeModal] = useFlag();\n\n const sticker = message.content.sticker!;\n const { isAnimated, stickerSetId } = sticker;\n const isMemojiSticker = stickerSetId === MEMOJI_STICKER_ID;\n\n const shouldLoad = useIsIntersecting(ref, observeIntersection);\n const shouldPlay = useIsIntersecting(ref, observeIntersectionForPlaying);\n\n const mediaHash = sticker.isPreloadedGlobally ? `sticker${sticker.id}` : getMessageMediaHash(message, 'inline')!;\n const thumbDataUri = useWebpThumbnail(message);\n const mediaData = useMedia(\n mediaHash,\n !shouldLoad,\n getMessageMediaFormat(message, 'inline', true),\n lastSyncTime,\n );\n\n const isMediaLoaded = Boolean(mediaData);\n const [isAnimationLoaded, markAnimationLoaded] = useFlag(isMediaLoaded);\n const isMediaReady = isAnimated ? isAnimationLoaded : isMediaLoaded;\n const { shouldRenderFullMedia, transitionClassNames } = useTransitionForMedia(isMediaReady, 'slow');\n\n const { width, height } = getStickerDimensions(sticker);\n const thumbClassName = buildClassName('thumbnail', !thumbDataUri && 'empty');\n\n const stickerClassName = buildClassName(\n 'Sticker media-inner',\n isMemojiSticker && 'inactive',\n );\n\n return (\n <div ref={ref} className={stickerClassName} onClick={!isMemojiSticker ? openModal : undefined}>\n {!isMediaReady && (\n <img\n id={`sticker-thumb-${message.id}`}\n src={thumbDataUri}\n width={width}\n height={height}\n alt=\"\"\n className={thumbClassName}\n />\n )}\n {!isAnimated && shouldRenderFullMedia && (\n <img\n id={`sticker-${message.id}`}\n src={mediaData as string}\n width={width}\n height={height}\n alt=\"\"\n className={buildClassName('full-media', transitionClassNames)}\n />\n )}\n {isAnimated && isMediaLoaded && (\n <AnimatedSticker\n key={mediaHash}\n className={buildClassName('full-media', transitionClassNames)}\n id={mediaHash}\n animationData={mediaData as AnyLiteral}\n size={width}\n play={shouldPlay}\n noLoop={!shouldLoop}\n onLoad={markAnimationLoaded}\n />\n )}\n <StickerSetModal\n isOpen={isModalOpen}\n fromSticker={sticker}\n onClose={closeModal}\n />\n </div>\n );\n};\n\nexport default Sticker;\n","import { ApiMessage } from '../../../../api/types';\n\nimport { IS_CANVAS_FILTER_SUPPORTED, IS_SINGLE_COLUMN_LAYOUT } from '../../../../util/environment';\nimport { getMessageMediaThumbDataUri } from '../../../../modules/helpers';\nimport useCanvasBlur from '../../../../hooks/useCanvasBlur';\n\nexport default function useBlurredMediaThumbRef(message: ApiMessage, fullMediaData?: string) {\n return useCanvasBlur(\n getMessageMediaThumbDataUri(message),\n Boolean(fullMediaData),\n IS_SINGLE_COLUMN_LAYOUT && !IS_CANVAS_FILTER_SUPPORTED,\n );\n}\n","const SELECTED_APPENDIX_BACKGROUND = Promise.resolve('rgba(255,255,255,1)');\n\nexport default function getCustomAppendixBg(src: string, isOwn: boolean, inSelectMode?: boolean, isSelected?: boolean) {\n return isSelected ? SELECTED_APPENDIX_BACKGROUND : getAppendixColorFromImage(src, isOwn);\n}\n\nasync function getAppendixColorFromImage(src: string, isOwn: boolean) {\n const img = new Image();\n img.src = src;\n\n if (!img.width) {\n await new Promise((resolve) => {\n img.onload = resolve;\n });\n }\n\n const canvas = document.createElement('canvas');\n const ctx = canvas.getContext('2d')!;\n\n canvas.width = img.width;\n canvas.height = img.height;\n\n ctx.drawImage(img, 0, 0, img.width, img.height);\n\n const x = isOwn ? img.width - 1 : 0;\n const y = img.height - 1;\n\n const pixel = Array.from(ctx.getImageData(x, y, 1, 1).data);\n return `rgba(${pixel.join(',')})`;\n}\n","import React, {\n FC, useCallback, useLayoutEffect, useRef, useState,\n} from '../../../lib/teact/teact';\n\nimport { ApiMessage } from '../../../api/types';\nimport { IMediaDimensions } from './helpers/calculateAlbumLayout';\n\nimport {\n getMessagePhoto,\n getMessageWebPagePhoto,\n getMessageMediaHash,\n getMediaTransferState,\n isOwnMessage,\n} from '../../../modules/helpers';\nimport { ObserveFn, useIsIntersecting } from '../../../hooks/useIntersectionObserver';\nimport useMediaWithDownloadProgress from '../../../hooks/useMediaWithDownloadProgress';\nimport useTransitionForMedia from '../../../hooks/useTransitionForMedia';\nimport useShowTransition from '../../../hooks/useShowTransition';\nimport useBlurredMediaThumbRef from './hooks/useBlurredMediaThumbRef';\nimport usePrevious from '../../../hooks/usePrevious';\nimport buildClassName from '../../../util/buildClassName';\nimport getCustomAppendixBg from './helpers/getCustomAppendixBg';\nimport { calculateMediaDimensions } from './helpers/mediaDimensions';\n\nimport ProgressSpinner from '../../ui/ProgressSpinner';\n\nexport type OwnProps = {\n id?: string;\n message: ApiMessage;\n observeIntersection?: ObserveFn;\n noAvatars?: boolean;\n shouldAutoLoad?: boolean;\n isInSelectMode?: boolean;\n isSelected?: boolean;\n uploadProgress?: number;\n size?: 'inline' | 'pictogram';\n shouldAffectAppendix?: boolean;\n dimensions?: IMediaDimensions & { isSmall?: boolean };\n nonInteractive?: boolean;\n onClick?: (id: number) => void;\n onCancelUpload?: (message: ApiMessage) => void;\n};\n\nconst CUSTOM_APPENDIX_ATTRIBUTE = 'data-has-custom-appendix';\n\nconst Photo: FC<OwnProps> = ({\n id,\n message,\n observeIntersection,\n noAvatars,\n shouldAutoLoad,\n isInSelectMode,\n isSelected,\n uploadProgress,\n size = 'inline',\n dimensions,\n nonInteractive,\n shouldAffectAppendix,\n onClick,\n onCancelUpload,\n}) => {\n // eslint-disable-next-line no-null/no-null\n const ref = useRef<HTMLDivElement>(null);\n\n const photo = (getMessagePhoto(message) || getMessageWebPagePhoto(message))!;\n const localBlobUrl = photo.blobUrl;\n\n const isIntersecting = useIsIntersecting(ref, observeIntersection);\n\n const [isDownloadAllowed, setIsDownloadAllowed] = useState(shouldAutoLoad);\n const shouldDownload = isDownloadAllowed && isIntersecting;\n const {\n mediaData, downloadProgress,\n } = useMediaWithDownloadProgress(getMessageMediaHash(message, size), !shouldDownload);\n const fullMediaData = localBlobUrl || mediaData;\n const thumbRef = useBlurredMediaThumbRef(message, fullMediaData);\n\n const {\n isUploading, isTransferring, transferProgress,\n } = getMediaTransferState(message, uploadProgress || downloadProgress, shouldDownload && !fullMediaData);\n const wasDownloadDisabled = usePrevious(isDownloadAllowed) === false;\n const {\n shouldRender: shouldRenderSpinner,\n transitionClassNames: spinnerClassNames,\n } = useShowTransition(isTransferring, undefined, wasDownloadDisabled, 'slow');\n const {\n shouldRenderThumb, shouldRenderFullMedia, transitionClassNames,\n } = useTransitionForMedia(fullMediaData, 'slow');\n\n const handleClick = useCallback(() => {\n if (isUploading) {\n if (onCancelUpload) {\n onCancelUpload(message);\n }\n } else if (!fullMediaData) {\n setIsDownloadAllowed((isAllowed) => !isAllowed);\n } else if (onClick) {\n onClick(message.id);\n }\n }, [fullMediaData, isUploading, message, onCancelUpload, onClick]);\n\n const isOwn = isOwnMessage(message);\n useLayoutEffect(() => {\n if (!shouldAffectAppendix) {\n return;\n }\n\n const contentEl = ref.current!.closest<HTMLDivElement>('.message-content')!;\n\n if (fullMediaData) {\n getCustomAppendixBg(fullMediaData, isOwn, isInSelectMode, isSelected).then((appendixBg) => {\n contentEl.style.setProperty('--appendix-bg', appendixBg);\n contentEl.setAttribute(CUSTOM_APPENDIX_ATTRIBUTE, '');\n });\n } else {\n contentEl.classList.add('has-appendix-thumb');\n }\n }, [fullMediaData, isOwn, shouldAffectAppendix, isInSelectMode, isSelected]);\n\n const { width, height, isSmall } = dimensions || calculateMediaDimensions(message, noAvatars);\n\n const className = buildClassName(\n 'media-inner',\n !isUploading && !nonInteractive && 'interactive',\n isSmall && 'small-image',\n width === height && 'square-image',\n );\n\n const style = dimensions\n ? `width: ${width}px; height: ${height}px; left: ${dimensions.x}px; top: ${dimensions.y}px;`\n : '';\n\n return (\n <div\n id={id}\n ref={ref}\n className={className}\n // @ts-ignore teact feature\n style={style}\n onClick={isUploading ? undefined : handleClick}\n >\n {shouldRenderThumb && (\n <canvas\n ref={thumbRef}\n className=\"thumbnail\"\n // @ts-ignore teact feature\n style={`width: ${width}px; height: ${height}px`}\n />\n )}\n {shouldRenderFullMedia && (\n <img\n src={fullMediaData}\n className={`full-media ${transitionClassNames}`}\n width={width}\n height={height}\n alt=\"\"\n />\n )}\n {shouldRenderSpinner && (\n <div className={`media-loading ${spinnerClassNames}`}>\n <ProgressSpinner progress={transferProgress} onClick={isUploading ? handleClick : undefined} />\n </div>\n )}\n {!fullMediaData && !isDownloadAllowed && (\n <i className=\"icon-download\" />\n )}\n {isTransferring && (\n <span className=\"message-upload-progress\">{Math.round(transferProgress * 100)}%</span>\n )}\n </div>\n );\n};\n\nexport default Photo;\n","import { RefObject } from 'react';\nimport { useCallback, useRef } from '../lib/teact/teact';\n\nimport useHeavyAnimationCheck from './useHeavyAnimationCheck';\nimport safePlay from '../util/safePlay';\n\nexport default function useHeavyAnimationCheckForVideo(playerRef: RefObject<HTMLVideoElement>, shouldPlay: boolean) {\n const shouldPlayRef = useRef();\n shouldPlayRef.current = shouldPlay;\n\n const pause = useCallback(() => {\n if (playerRef.current) {\n playerRef.current.pause();\n }\n }, [playerRef]);\n\n const play = useCallback(() => {\n if (playerRef.current && shouldPlayRef.current) {\n safePlay(playerRef.current);\n }\n }, [playerRef]);\n\n useHeavyAnimationCheck(pause, play);\n}\n","import { useCallback, useRef } from '../../../../lib/teact/teact';\nimport { fastRaf } from '../../../../util/schedulers';\nimport useBackgroundMode from '../../../../hooks/useBackgroundMode';\nimport safePlay from '../../../../util/safePlay';\n\nexport default (playerRef: { current: HTMLVideoElement | null }, isPlayAllowed = false) => {\n const wasPlaying = useRef(false);\n const isFrozen = useRef(false);\n\n const freezePlaying = useCallback(() => {\n isFrozen.current = true;\n\n if (!isPlayAllowed || !playerRef.current) {\n return;\n }\n\n if (!wasPlaying.current) {\n wasPlaying.current = !playerRef.current.paused;\n }\n\n playerRef.current.pause();\n }, [isPlayAllowed, playerRef]);\n\n const unfreezePlaying = useCallback(() => {\n // At this point HTMLVideoElement can be unmounted from the DOM\n if (isPlayAllowed && playerRef.current && wasPlaying.current && document.body.contains(playerRef.current)) {\n safePlay(playerRef.current);\n }\n\n wasPlaying.current = false;\n isFrozen.current = false;\n }, [isPlayAllowed, playerRef]);\n\n const unfreezePlayingOnRaf = useCallback(() => {\n fastRaf(unfreezePlaying);\n }, [unfreezePlaying]);\n\n if (!document.hasFocus()) {\n freezePlaying();\n }\n\n useBackgroundMode(freezePlaying, unfreezePlayingOnRaf);\n};\n","import React, {\n FC, useCallback, useRef, useState,\n} from '../../../lib/teact/teact';\n\nimport { ApiMessage } from '../../../api/types';\nimport { IMediaDimensions } from './helpers/calculateAlbumLayout';\n\nimport { formatMediaDuration } from '../../../util/dateFormat';\nimport buildClassName from '../../../util/buildClassName';\nimport { calculateVideoDimensions } from '../../common/helpers/mediaDimensions';\nimport {\n getMediaTransferState,\n getMessageMediaFormat,\n getMessageMediaHash,\n getMessageVideo,\n getMessageWebPageVideo,\n isForwardedMessage,\n isOwnMessage,\n} from '../../../modules/helpers';\nimport { ObserveFn, useIsIntersecting } from '../../../hooks/useIntersectionObserver';\nimport useMediaWithDownloadProgress from '../../../hooks/useMediaWithDownloadProgress';\nimport useMedia from '../../../hooks/useMedia';\nimport useShowTransition from '../../../hooks/useShowTransition';\nimport useTransitionForMedia from '../../../hooks/useTransitionForMedia';\nimport usePrevious from '../../../hooks/usePrevious';\nimport useBuffering from '../../../hooks/useBuffering';\nimport useHeavyAnimationCheckForVideo from '../../../hooks/useHeavyAnimationCheckForVideo';\nimport useVideoCleanup from '../../../hooks/useVideoCleanup';\nimport usePauseOnInactive from './hooks/usePauseOnInactive';\nimport useBlurredMediaThumbRef from './hooks/useBlurredMediaThumbRef';\n\nimport ProgressSpinner from '../../ui/ProgressSpinner';\n\nexport type OwnProps = {\n id?: string;\n message: ApiMessage;\n observeIntersection: ObserveFn;\n noAvatars?: boolean;\n shouldAutoLoad?: boolean;\n shouldAutoPlay?: boolean;\n uploadProgress?: number;\n dimensions?: IMediaDimensions;\n lastSyncTime?: number;\n onClick?: (id: number) => void;\n onCancelUpload?: (message: ApiMessage) => void;\n};\n\nconst Video: FC<OwnProps> = ({\n id,\n message,\n observeIntersection,\n noAvatars,\n shouldAutoLoad,\n shouldAutoPlay,\n uploadProgress,\n lastSyncTime,\n dimensions,\n onClick,\n onCancelUpload,\n}) => {\n // eslint-disable-next-line no-null/no-null\n const ref = useRef<HTMLDivElement>(null);\n // eslint-disable-next-line no-null/no-null\n const videoRef = useRef<HTMLVideoElement>(null);\n\n const video = (getMessageVideo(message) || getMessageWebPageVideo(message))!;\n const localBlobUrl = video.blobUrl;\n\n const isIntersecting = useIsIntersecting(ref, observeIntersection);\n\n const [isDownloadAllowed, setIsDownloadAllowed] = useState(shouldAutoLoad);\n const shouldDownload = Boolean(isDownloadAllowed && isIntersecting && lastSyncTime);\n const [isPlayAllowed, setIsPlayAllowed] = useState(shouldAutoPlay);\n\n const previewBlobUrl = useMedia(\n getMessageMediaHash(message, 'pictogram'),\n !(isIntersecting && lastSyncTime),\n getMessageMediaFormat(message, 'pictogram'),\n lastSyncTime,\n );\n const { mediaData, downloadProgress } = useMediaWithDownloadProgress(\n getMessageMediaHash(message, 'inline'),\n !shouldDownload,\n getMessageMediaFormat(message, 'inline'),\n lastSyncTime,\n );\n const fullMediaData = localBlobUrl || mediaData;\n const isInline = Boolean(isIntersecting && fullMediaData);\n // Thumbnail is always rendered so we can only disable blur if we have preview\n const thumbRef = useBlurredMediaThumbRef(message, previewBlobUrl);\n\n const { isBuffered, bufferingHandlers } = useBuffering(!shouldAutoLoad);\n const { isUploading, isTransferring, transferProgress } = getMediaTransferState(\n message,\n uploadProgress || downloadProgress,\n shouldDownload && !isBuffered,\n );\n const wasDownloadDisabled = usePrevious(isDownloadAllowed) === false;\n const {\n shouldRender: shouldRenderSpinner,\n transitionClassNames: spinnerClassNames,\n } = useShowTransition(isTransferring, undefined, wasDownloadDisabled);\n const { transitionClassNames } = useTransitionForMedia(fullMediaData, 'slow');\n\n const [playProgress, setPlayProgress] = useState<number>(0);\n const handleTimeUpdate = useCallback((e: React.SyntheticEvent<HTMLVideoElement>) => {\n setPlayProgress(Math.max(0, e.currentTarget.currentTime - 1));\n }, []);\n\n const duration = (videoRef.current && videoRef.current.duration) || video.duration || 0;\n\n const isOwn = isOwnMessage(message);\n const isForwarded = isForwardedMessage(message);\n const { width, height } = dimensions || calculateVideoDimensions(video, isOwn, isForwarded, noAvatars);\n\n useHeavyAnimationCheckForVideo(videoRef, Boolean(isInline && shouldAutoPlay));\n usePauseOnInactive(videoRef, isPlayAllowed);\n useVideoCleanup(videoRef, [isInline]);\n\n const handleClick = useCallback(() => {\n if (isUploading) {\n if (onCancelUpload) {\n onCancelUpload(message);\n }\n } else if (!fullMediaData) {\n setIsDownloadAllowed((isAllowed) => !isAllowed);\n } else if (fullMediaData && !isPlayAllowed) {\n setIsPlayAllowed(true);\n videoRef.current!.play();\n } else if (onClick) {\n onClick(message.id);\n }\n }, [isUploading, fullMediaData, isPlayAllowed, onClick, onCancelUpload, message]);\n\n const className = buildClassName('media-inner dark', !isUploading && 'interactive');\n const videoClassName = buildClassName('full-media', transitionClassNames);\n\n const style = dimensions\n ? `width: ${width}px; height: ${height}px; left: ${dimensions.x}px; top: ${dimensions.y}px;`\n : '';\n\n return (\n <div\n ref={ref}\n id={id}\n className={className}\n // @ts-ignore teact feature\n style={style}\n onClick={isUploading ? undefined : handleClick}\n >\n {!previewBlobUrl && (\n <canvas\n ref={thumbRef}\n className=\"thumbnail\"\n // @ts-ignore teact feature\n style={`width: ${width}px; height: ${height}px;`}\n />\n )}\n {previewBlobUrl && (\n <img\n src={previewBlobUrl}\n className=\"thumbnail\"\n // @ts-ignore teact feature\n style={`width: ${width}px; height: ${height}px;`}\n alt=\"\"\n />\n )}\n {isInline && (\n <video\n ref={videoRef}\n className={videoClassName}\n width={width}\n height={height}\n autoPlay={isPlayAllowed}\n muted\n loop\n playsInline\n // eslint-disable-next-line react/jsx-props-no-spreading\n {...bufferingHandlers}\n onTimeUpdate={handleTimeUpdate}\n >\n <source src={fullMediaData} />\n </video>\n )}\n {(isDownloadAllowed && !isPlayAllowed && !shouldRenderSpinner) && (\n <i className=\"icon-large-play\" />\n )}\n {shouldRenderSpinner && (\n <div className={`media-loading ${spinnerClassNames}`}>\n <ProgressSpinner progress={transferProgress} onClick={isUploading ? handleClick : undefined} />\n </div>\n )}\n {!isDownloadAllowed && (\n <i className=\"icon-download\" />\n )}\n {isTransferring ? (\n <span className=\"message-upload-progress\">...</span>\n ) : (\n <div className=\"message-media-duration\">\n {video.isGif ? 'GIF' : formatMediaDuration(Math.max(duration - playProgress, 0))}\n </div>\n )}\n </div>\n );\n};\n\nexport default Video;\n","import React, { FC, useCallback } from '../../../lib/teact/teact';\nimport { withGlobal } from '../../../lib/teact/teactn';\n\nimport { GlobalActions } from '../../../global/types';\nimport { ApiUser, ApiContact } from '../../../api/types';\n\nimport { selectUser } from '../../../modules/selectors';\nimport { formatPhoneNumberWithCode } from '../../../util/phoneNumber';\n\nimport Avatar from '../../common/Avatar';\n\nimport './Contact.scss';\nimport { pick } from '../../../util/iteratees';\nimport buildClassName from '../../../util/buildClassName';\n\ntype OwnProps = {\n contact: ApiContact;\n};\n\ntype StateProps = {\n user?: ApiUser;\n};\n\ntype DispatchProps = Pick<GlobalActions, 'openUserInfo'>;\n\nconst Contact: FC<OwnProps & StateProps & DispatchProps> = ({\n contact, user, openUserInfo,\n}) => {\n const {\n firstName,\n lastName,\n phoneNumber,\n userId,\n } = contact;\n\n const handleClick = useCallback(() => {\n openUserInfo({ id: userId });\n }, [openUserInfo, userId]);\n\n return (\n <div\n className={buildClassName('Contact', Boolean(userId) && 'interactive')}\n onClick={userId ? handleClick : undefined}\n >\n <Avatar size=\"large\" user={user} text={firstName || lastName} />\n <div className=\"contact-info\">\n <div className=\"contact-name\">{firstName} {lastName}</div>\n <div className=\"contact-phone\">{formatPhoneNumberWithCode(phoneNumber)}</div>\n </div>\n </div>\n );\n};\n\nexport default withGlobal<OwnProps>(\n (global, { contact }): StateProps => {\n return {\n user: selectUser(global, contact.userId),\n };\n },\n (setGlobal, actions): DispatchProps => pick(actions, [\n 'openUserInfo',\n ]),\n)(Contact);\n","import { ChangeEvent } from 'react';\nimport React, {\n FC, useCallback, memo, useState,\n} from '../../lib/teact/teact';\n\nimport Checkbox from './Checkbox';\n\ntype IRadioOption = {\n label: string;\n subLabel?: string;\n value: string;\n};\n\ntype OwnProps = {\n id?: string;\n options: IRadioOption[];\n selected?: string[];\n disabled?: boolean;\n round?: boolean;\n loadingOptions?: string[];\n onChange: (value: string[]) => void;\n};\n\nconst CheckboxGroup: FC<OwnProps> = ({\n id,\n options,\n selected = [],\n disabled,\n round,\n loadingOptions,\n onChange,\n}) => {\n const [values, setValues] = useState<string[]>([]);\n\n const handleChange = useCallback((event: ChangeEvent<HTMLInputElement>) => {\n const { value, checked } = event.currentTarget;\n let newValues: string[];\n if (checked) {\n newValues = [...values, value];\n } else {\n newValues = values.filter((v) => v !== value);\n }\n\n setValues(newValues);\n onChange(newValues);\n }, [onChange, values]);\n\n return (\n <div id={id} className=\"radio-group\">\n {options.map((option) => (\n <Checkbox\n label={option.label}\n subLabel={option.subLabel}\n value={option.value}\n checked={selected.indexOf(option.value) !== -1}\n disabled={disabled}\n round={round}\n isLoading={loadingOptions ? loadingOptions.indexOf(option.value) !== -1 : undefined}\n onChange={handleChange}\n />\n ))}\n </div>\n );\n};\n\nexport default memo(CheckboxGroup);\n","import React, {\n FC, useState, useEffect, useRef,\n} from '../../../lib/teact/teact';\n\nimport { ApiPollAnswer, ApiPollResult } from '../../../api/types';\n\nimport buildClassName from '../../../util/buildClassName';\nimport renderText from '../../common/helpers/renderText';\n\nimport './PollOption.scss';\n\ntype OwnProps = {\n answer: ApiPollAnswer;\n voteResults?: ApiPollResult[];\n totalVoters?: number;\n maxVotersCount?: number;\n correctResults: string[];\n shouldAnimate: boolean;\n};\n\nconst PollOption: FC<OwnProps> = ({\n answer,\n voteResults,\n totalVoters,\n maxVotersCount,\n correctResults,\n shouldAnimate,\n}) => {\n const result = voteResults && voteResults.find((r) => r.option === answer.option);\n const correctAnswer = correctResults.length === 0 || correctResults.indexOf(answer.option) !== -1;\n const showIcon = (correctResults.length > 0 && correctAnswer) || (result && result.isChosen);\n const answerPercent = result ? getPercentage(result.votersCount, totalVoters || 0) : 0;\n const [finalPercent, setFinalPercent] = useState(shouldAnimate ? 0 : answerPercent);\n // eslint-disable-next-line no-null/no-null\n const lineRef = useRef<HTMLDivElement>(null);\n const lineWidth = result ? getPercentage(result.votersCount, maxVotersCount || 0) : 0;\n const isAnimationDoesNotStart = finalPercent < answerPercent;\n\n useEffect(() => {\n if (shouldAnimate) {\n setFinalPercent(answerPercent);\n }\n }, [shouldAnimate, answerPercent]);\n\n useEffect(() => {\n const lineEl = lineRef.current;\n\n if (lineEl && shouldAnimate) {\n const svgEl = lineEl.firstElementChild;\n\n const style = isAnimationDoesNotStart ? '' : 'stroke-dasharray: 100% 200%; stroke-dashoffset: -44';\n if (!svgEl) {\n lineEl.innerHTML = `\n <svg class=\"poll-line\" xmlns=\"http://www.w3.org/2000/svg\" style=\"${style}\">\n <path d=\"M4.47 5.33v13.6a9 9 0 009 9h13\"/>\n </svg>`;\n } else {\n svgEl.setAttribute('style', style);\n }\n }\n }, [isAnimationDoesNotStart, shouldAnimate]);\n\n if (!voteResults || !result) {\n return undefined;\n }\n\n const lineStyle = `width: ${lineWidth}%; transform:scaleX(${isAnimationDoesNotStart ? 0 : 1})`;\n\n return (\n <div className=\"PollOption\" dir=\"ltr\">\n <div className={`poll-option-share ${answerPercent === '100' ? 'limit-width' : ''}`}>\n {answerPercent}%\n {showIcon && (\n <span className={buildClassName(\n 'poll-option-chosen',\n !correctAnswer && 'wrong',\n shouldAnimate && 'animate',\n )}\n >\n <i className={correctAnswer ? 'icon-check' : 'icon-close'} />\n </span>\n )}\n </div>\n <div className=\"poll-option-right\">\n <div className=\"poll-option-text\" dir=\"auto\">\n {renderText(answer.text)}\n </div>\n <div className={buildClassName('poll-option-answer', showIcon && !correctAnswer && 'wrong')}>\n <div className=\"poll-option-corner\" ref={lineRef} />\n <div\n className=\"poll-option-line\"\n // @ts-ignore\n style={lineStyle}\n />\n </div>\n </div>\n </div>\n );\n};\n\nfunction getPercentage(value: number, total: number) {\n return total > 0 ? ((value / total) * 100).toFixed() : 0;\n}\n\nexport default PollOption;\n","import React, {\n FC,\n useCallback,\n useEffect,\n useState,\n memo,\n useMemo,\n useRef,\n} from '../../../lib/teact/teact';\nimport { withGlobal } from '../../../lib/teact/teactn';\n\nimport { GlobalActions } from '../../../global/types';\nimport {\n ApiMessage, ApiPoll, ApiUser, ApiPollAnswer,\n} from '../../../api/types';\n\nimport { pick } from '../../../util/iteratees';\nimport renderText from '../../common/helpers/renderText';\nimport { renderTextWithEntities } from '../../common/helpers/renderMessageText';\nimport { formatMediaDuration } from '../../../util/dateFormat';\nimport useLang, { LangFn } from '../../../hooks/useLang';\n\nimport CheckboxGroup from '../../ui/CheckboxGroup';\nimport RadioGroup from '../../ui/RadioGroup';\nimport Avatar from '../../common/Avatar';\nimport Button from '../../ui/Button';\nimport Notification from '../../ui/Notification';\nimport PollOption from './PollOption';\n\nimport './Poll.scss';\n\ntype OwnProps = {\n message: ApiMessage;\n poll: ApiPoll;\n onSendVote: (options: string[]) => void;\n};\n\ntype StateProps = {\n recentVoterIds?: number[];\n usersById: Record<number, ApiUser>;\n serverTimeOffset: number;\n};\n\ntype DispatchProps = Pick<GlobalActions, ('loadMessage' | 'openPollResults')>;\n\nconst SOLUTION_CONTAINER_ID = '#middle-column-portals';\nconst SOLUTION_DURATION = 5000;\nconst NBSP = '\\u00A0';\n\nconst Poll: FC<OwnProps & StateProps & DispatchProps> = ({\n message,\n poll,\n recentVoterIds,\n usersById,\n loadMessage,\n onSendVote,\n openPollResults,\n serverTimeOffset,\n}) => {\n const { id: messageId, chatId } = message;\n const { summary, results } = poll;\n const [isSubmitting, setIsSubmitting] = useState<boolean>(false);\n const [chosenOptions, setChosenOptions] = useState<string[]>([]);\n const [isSolutionShown, setIsSolutionShown] = useState<boolean>(false);\n const [wasSubmitted, setWasSubmitted] = useState<boolean>(false);\n const [closePeriod, setClosePeriod] = useState<number>(\n !summary.closed && summary.closeDate && summary.closeDate > 0\n ? Math.min(summary.closeDate - Math.floor(Date.now() / 1000) + serverTimeOffset, summary.closePeriod!)\n : 0,\n );\n // eslint-disable-next-line no-null/no-null\n const countdownRef = useRef<HTMLDivElement>(null);\n const { results: voteResults, totalVoters } = results;\n const hasVoted = voteResults && voteResults.some((r) => r.isChosen);\n const canVote = !summary.closed && !hasVoted;\n const canViewResult = !canVote && summary.isPublic && Number(results.totalVoters) > 0;\n const isMultiple = canVote && summary.multipleChoice;\n const maxVotersCount = voteResults ? Math.max(...voteResults.map((r) => r.votersCount)) : totalVoters;\n const correctResults = voteResults ? voteResults.reduce((answers: string[], r) => {\n if (r.isCorrect) {\n answers.push(r.option);\n }\n\n return answers;\n }, []) : [];\n const answers = summary.answers.map((a) => ({\n label: a.text,\n value: a.option,\n hidden: Boolean(summary.quiz && summary.closePeriod && closePeriod <= 0),\n }));\n\n useEffect(() => {\n if (\n isSubmitting\n && poll.results.results\n && poll.results.results.some((result) => result.isChosen)\n ) {\n setIsSubmitting(false);\n }\n }, [isSubmitting, poll.results.results]);\n\n useEffect(() => {\n if (closePeriod > 0) {\n setTimeout(() => setClosePeriod(closePeriod - 1), 1000);\n }\n\n const countdownEl = countdownRef.current;\n\n if (countdownEl) {\n const circumference = 6 * 2 * Math.PI;\n const svgEl = countdownEl.lastElementChild;\n const timerEl = countdownEl.firstElementChild;\n if (closePeriod <= 5) {\n countdownEl.classList.add('hurry-up');\n }\n\n if (!svgEl || !timerEl) {\n countdownEl.innerHTML = `\n <span>${formatMediaDuration(closePeriod)}</span>\n <svg width=\"16px\" height=\"16px\">\n <circle cx=\"8\" cy=\"8\" r=\"6\" class=\"poll-countdown-progress\" transform=\"rotate(-90, 8, 8)\"\n stroke-dasharray=\"${circumference} ${circumference}\"\n stroke-dashoffset=\"0\"\n />\n </svg>`;\n } else {\n const strokeDashOffset = ((summary.closePeriod! - closePeriod) / summary.closePeriod!) * circumference;\n timerEl.textContent = formatMediaDuration(closePeriod);\n (svgEl.firstElementChild as SVGElement).setAttribute('stroke-dashoffset', `-${strokeDashOffset}`);\n }\n }\n }, [closePeriod, summary.closePeriod]);\n\n useEffect(() => {\n if (summary.quiz && (closePeriod <= 0 || (hasVoted && !summary.closed))) {\n loadMessage({ chatId, messageId });\n }\n }, [chatId, closePeriod, hasVoted, loadMessage, messageId, summary.closed, summary.quiz]);\n\n // If the client time is not synchronized, the poll must be updated after the closePeriod time has expired.\n useEffect(() => {\n let timer: number | undefined;\n\n if (summary.quiz && !summary.closed && summary.closePeriod && summary.closePeriod > 0) {\n timer = window.setTimeout(() => {\n loadMessage({ chatId, messageId });\n }, summary.closePeriod * 1000);\n }\n\n return () => {\n if (timer) {\n window.clearTimeout(timer);\n }\n };\n }, [canVote, chatId, loadMessage, messageId, summary.closePeriod, summary.closed, summary.quiz]);\n\n const recentVoters = useMemo(() => {\n return recentVoterIds ? recentVoterIds.reduce((result: ApiUser[], id) => {\n const user = usersById[id];\n if (user) {\n result.push(user);\n }\n\n return result;\n }, []) : [];\n }, [usersById, recentVoterIds]);\n\n const handleRadioChange = useCallback(\n (option: string) => {\n setChosenOptions([option]);\n setIsSubmitting(true);\n setWasSubmitted(true);\n onSendVote([option]);\n }, [onSendVote],\n );\n\n const handleCheckboxChange = useCallback(\n (options: string[]) => {\n setChosenOptions(options);\n }, [],\n );\n\n const handleVoteClick = useCallback(\n () => {\n setIsSubmitting(true);\n setWasSubmitted(true);\n onSendVote(chosenOptions);\n }, [onSendVote, chosenOptions],\n );\n\n const handleViewResultsClick = useCallback(\n () => {\n openPollResults({ chatId, messageId });\n }, [chatId, messageId, openPollResults],\n );\n\n const handleSolutionShow = useCallback(() => {\n setIsSolutionShown(true);\n }, []);\n\n const handleSolutionHide = useCallback(() => {\n setIsSolutionShown(false);\n setWasSubmitted(false);\n }, []);\n\n // Show the solution to quiz if the answer was incorrect\n useEffect(() => {\n if (wasSubmitted && hasVoted && summary.quiz && results.results && poll.results.solution) {\n const correctResult = results.results.find((r) => r.isChosen && r.isCorrect);\n if (!correctResult) {\n setIsSolutionShown(true);\n }\n }\n }, [hasVoted, wasSubmitted, results.results, summary.quiz, poll.results.solution]);\n\n const lang = useLang();\n\n function renderResultOption(answer: ApiPollAnswer) {\n return (\n <PollOption\n key={answer.option}\n shouldAnimate={wasSubmitted}\n answer={answer}\n voteResults={voteResults}\n totalVoters={totalVoters}\n maxVotersCount={maxVotersCount}\n correctResults={correctResults}\n />\n );\n }\n\n function renderRecentVoters() {\n return (\n recentVoters.length > 0 && (\n <div className=\"poll-recent-voters\">\n {recentVoters.map((user) => (\n <Avatar\n size=\"micro\"\n user={user}\n />\n ))}\n </div>\n )\n );\n }\n\n function renderSolution() {\n return (\n isSolutionShown && poll.results.solution && (\n <Notification\n message={renderTextWithEntities(poll.results.solution, poll.results.solutionEntities)}\n duration={SOLUTION_DURATION}\n onDismiss={handleSolutionHide}\n containerId={SOLUTION_CONTAINER_ID}\n />\n )\n );\n }\n\n return (\n <div className=\"Poll\" dir={lang.isRtl ? 'auto' : 'ltr'}>\n {renderSolution()}\n <div className=\"poll-question\">{renderText(summary.question)}</div>\n <div className=\"poll-type\">\n {lang(getPollTypeString(summary))}\n {renderRecentVoters()}\n {closePeriod > 0 && canVote && <div ref={countdownRef} className=\"poll-countdown\" />}\n {summary.quiz && poll.results.solution && !canVote && (\n <Button\n round\n size=\"tiny\"\n color=\"translucent\"\n className=\"poll-quiz-help\"\n disabled={isSolutionShown}\n onClick={handleSolutionShow}\n ariaLabel=\"Show Solution\"\n >\n <i className=\"icon-lamp\" />\n </Button>\n )}\n </div>\n {canVote && (\n <div className=\"poll-answers\">\n {isMultiple\n ? (\n <CheckboxGroup\n options={answers}\n onChange={handleCheckboxChange}\n disabled={message.isScheduled || isSubmitting}\n loadingOptions={isSubmitting ? chosenOptions : undefined}\n round\n />\n )\n : (\n <RadioGroup\n name={`poll-${messageId}`}\n options={answers}\n onChange={handleRadioChange}\n disabled={message.isScheduled || isSubmitting}\n loadingOption={isSubmitting ? chosenOptions[0] : undefined}\n />\n )}\n </div>\n )}\n {!canVote && (\n <div className=\"poll-results\">\n {summary.answers.map(renderResultOption)}\n </div>\n )}\n {!canViewResult && !isMultiple && (\n <div className=\"poll-voters-count\">{getReadableVotersCount(lang, summary.quiz, results.totalVoters)}</div>\n )}\n {isMultiple && (\n <Button\n isText\n disabled={chosenOptions.length === 0}\n size=\"tiny\"\n onClick={handleVoteClick}\n >\n {lang('PollSubmitVotes')}\n </Button>\n )}\n {canViewResult && (\n <Button\n isText\n size=\"tiny\"\n onClick={handleViewResultsClick}\n >\n {lang('PollViewResults')}\n </Button>\n )}\n </div>\n );\n};\n\nfunction getPollTypeString(summary: ApiPoll['summary']) {\n // When we just created the poll, some properties don't exist.\n if (typeof summary.isPublic === 'undefined') {\n return NBSP;\n }\n\n if (summary.quiz) {\n return summary.isPublic ? 'QuizPoll' : 'AnonymousQuizPoll';\n }\n\n if (summary.closed) {\n return 'FinalResults';\n }\n\n return summary.isPublic ? 'PublicPoll' : 'AnonymousPoll';\n}\n\nfunction getReadableVotersCount(lang: LangFn, isQuiz: true | undefined, count?: number) {\n if (!count) {\n return lang(isQuiz ? 'Chat.Quiz.TotalVotesEmpty' : 'Chat.Poll.TotalVotesResultEmpty');\n }\n\n return lang(isQuiz ? 'Answer' : 'Vote', count, 'i');\n}\n\nexport default memo(withGlobal<OwnProps>(\n (global, { poll }) => {\n const { recentVoterIds } = poll.results;\n const { serverTimeOffset, users: { byId: usersById } } = global;\n if (!recentVoterIds || recentVoterIds.length === 0) {\n return {};\n }\n\n return {\n recentVoterIds,\n usersById,\n serverTimeOffset,\n };\n },\n (setGlobal, actions): DispatchProps => pick(actions, ['loadMessage', 'openPollResults']),\n)(Poll));\n","import React, { FC, memo, useCallback } from '../../../lib/teact/teact';\n\nimport { ApiMessage } from '../../../api/types';\nimport { ObserveFn } from '../../../hooks/useIntersectionObserver';\n\nimport { getMessageWebPage } from '../../../modules/helpers';\nimport { calculateMediaDimensions } from './helpers/mediaDimensions';\nimport renderText from '../../common/helpers/renderText';\nimport trimText from '../../../util/trimText';\nimport buildClassName from '../../../util/buildClassName';\n\nimport SafeLink from '../../common/SafeLink';\nimport Photo from './Photo';\nimport Video from './Video';\n\nimport './WebPage.scss';\n\nconst MAX_TEXT_LENGTH = 170; // symbols\n\ntype OwnProps = {\n message: ApiMessage;\n observeIntersection?: ObserveFn;\n noAvatars?: boolean;\n shouldAutoLoad?: boolean;\n shouldAutoPlay?: boolean;\n inPreview?: boolean;\n lastSyncTime?: number;\n onMediaClick?: () => void;\n onCancelMediaTransfer?: () => void;\n};\n\nconst WebPage: FC<OwnProps> = ({\n message,\n observeIntersection,\n noAvatars,\n shouldAutoLoad,\n shouldAutoPlay,\n inPreview,\n lastSyncTime,\n onMediaClick,\n onCancelMediaTransfer,\n}) => {\n const webPage = getMessageWebPage(message);\n\n let isSquarePhoto = false;\n if (webPage && webPage.photo && !webPage.video) {\n const { width, height } = calculateMediaDimensions(message);\n isSquarePhoto = width === height;\n }\n\n const handleMediaClick = useCallback(() => {\n onMediaClick!();\n }, [onMediaClick]);\n\n if (!webPage) {\n return undefined;\n }\n\n const {\n siteName,\n url,\n displayUrl,\n title,\n description,\n photo,\n video,\n } = webPage;\n const isMediaInteractive = (photo || video) && onMediaClick && !isSquarePhoto;\n const truncatedDescription = trimText(description, MAX_TEXT_LENGTH);\n\n const className = buildClassName(\n 'WebPage',\n isSquarePhoto && 'with-square-photo',\n !photo && !video && !inPreview && 'without-media',\n video && 'with-video',\n );\n\n return (\n <div\n className={className}\n data-initial={(siteName || displayUrl)[0]}\n dir=\"auto\"\n >\n {photo && !video && (\n <Photo\n message={message}\n observeIntersection={observeIntersection}\n noAvatars={noAvatars}\n shouldAutoLoad={shouldAutoLoad}\n size={isSquarePhoto ? 'pictogram' : 'inline'}\n nonInteractive={!isMediaInteractive}\n onClick={isMediaInteractive ? handleMediaClick : undefined}\n onCancelUpload={onCancelMediaTransfer}\n />\n )}\n <div className=\"WebPage-text\">\n <SafeLink className=\"site-name\" url={url} text={siteName || displayUrl} />\n {!inPreview && title && (\n <p className=\"site-title\">{renderText(title)}</p>\n )}\n {truncatedDescription && (\n <p className=\"site-description\">{renderText(truncatedDescription, ['emoji', 'br'])}</p>\n )}\n </div>\n {!inPreview && video && (\n <Video\n message={message}\n observeIntersection={observeIntersection!}\n noAvatars={noAvatars}\n shouldAutoLoad={shouldAutoLoad}\n shouldAutoPlay={shouldAutoPlay}\n lastSyncTime={lastSyncTime}\n onClick={isMediaInteractive ? handleMediaClick : undefined}\n onCancelUpload={onCancelMediaTransfer}\n />\n )}\n </div>\n );\n};\n\nexport default memo(WebPage);\n","import React, { FC, memo } from '../../../lib/teact/teact';\n\nimport { ApiMessage } from '../../../api/types';\n\nimport { getMessageInvoice } from '../../../modules/helpers';\nimport renderText from '../../common/helpers/renderText';\n\nimport './Invoice.scss';\n\ntype OwnProps = {\n message: ApiMessage;\n};\n\nconst Invoice: FC<OwnProps> = ({\n message,\n}) => {\n const invoice = getMessageInvoice(message);\n\n const {\n title,\n text,\n description,\n photoUrl,\n } = invoice!;\n\n return (\n <div\n className=\"Invoice\"\n >\n {title && (\n <p className=\"title\">{renderText(title)}</p>\n )}\n {text && (\n <p>{renderText(text, ['emoji', 'br'])}</p>\n )}\n <div className={`description ${photoUrl ? 'has-image' : ''}`}>\n {photoUrl && (\n <img\n className=\"invoice-image\"\n src={photoUrl}\n alt=\"\"\n />\n )}\n {description && (\n <p className=\"description-text\">{renderText(description, ['emoji', 'br'])}</p>\n )}\n </div>\n </div>\n );\n};\n\nexport default memo(Invoice);\n","import { MouseEvent as ReactMouseEvent } from 'react';\nimport React, {\n FC,\n useCallback,\n useMemo,\n memo,\n} from '../../../../lib/teact/teact';\nimport { withGlobal } from '../../../../lib/teact/teactn';\n\nimport { OwnProps as PhotoProps } from '../Photo';\nimport { OwnProps as VideoProps } from '../Video';\n\nimport buildClassName from '../../../../util/buildClassName';\nimport { GlobalActions } from '../../../../global/types';\nimport {\n selectIsInSelectMode,\n selectIsMessageSelected,\n} from '../../../../modules/selectors';\n\nimport { pick } from '../../../../util/iteratees';\n\ntype OwnProps = PhotoProps & VideoProps;\n\ntype StateProps = {\n isInSelectMode?: boolean;\n isSelected?: boolean;\n};\n\ntype DispatchProps = Pick<GlobalActions, ('toggleMessageSelection')>;\n\nexport default function withSelectControl(WrappedComponent: FC) {\n const ComponentWithSelectControl: FC<OwnProps & StateProps & DispatchProps> = (props) => {\n const {\n isInSelectMode,\n isSelected,\n message,\n toggleMessageSelection,\n dimensions,\n } = props;\n\n const handleMessageSelect = useCallback((e: ReactMouseEvent<HTMLDivElement, MouseEvent>) => {\n e.stopPropagation();\n toggleMessageSelection({ messageId: message.id, withShift: e && e.shiftKey });\n }, [toggleMessageSelection, message]);\n\n const newProps = useMemo(() => {\n return {\n ...props,\n isInSelectMode,\n isSelected,\n dimensions: {\n ...props.dimensions,\n x: 0,\n y: 0,\n },\n onClick: isInSelectMode ? undefined : props.onClick,\n };\n }, [props, isInSelectMode, isSelected]);\n\n return (\n <div\n className={\n buildClassName(\n 'album-item-select-wrapper',\n isSelected && 'is-selected',\n )\n }\n // @ts-ignore\n style={dimensions ? `left: ${dimensions.x}px; top: ${dimensions.y}px;` : ''}\n onClick={isInSelectMode ? handleMessageSelect : undefined}\n >\n {isInSelectMode && (\n <div className=\"message-select-control\">\n {isSelected && (\n <i className=\"icon-select\" />\n )}\n </div>\n )}\n {/* eslint-disable-next-line react/jsx-props-no-spreading */}\n <WrappedComponent {...newProps} />\n </div>\n );\n };\n\n return memo(withGlobal<OwnProps>(\n (global, ownProps) => {\n const { message } = ownProps;\n return {\n isInSelectMode: selectIsInSelectMode(global),\n isSelected: selectIsMessageSelected(global, message.id),\n };\n },\n (setGlobal, actions) => pick(actions, [\n 'toggleMessageSelection',\n ]),\n )(ComponentWithSelectControl));\n}\n","import React, { FC, useCallback } from '../../../lib/teact/teact';\n\nimport { GlobalActions, GlobalState } from '../../../global/types';\nimport { ApiMessage } from '../../../api/types';\nimport { IAlbum } from '../../../types';\nimport { AlbumRectPart, IAlbumLayout } from './helpers/calculateAlbumLayout';\n\nimport { getMessageContent } from '../../../modules/helpers';\nimport { withGlobal } from '../../../lib/teact/teactn';\nimport { pick } from '../../../util/iteratees';\nimport withSelectControl from './hocs/withSelectControl';\nimport { ObserveFn } from '../../../hooks/useIntersectionObserver';\n\nimport Photo from './Photo';\nimport Video from './Video';\n\nimport './Album.scss';\n\nconst PhotoWithSelect = withSelectControl(Photo);\nconst VideoWithSelect = withSelectControl(Video);\n\ntype OwnProps = {\n album: IAlbum;\n observeIntersection: ObserveFn;\n shouldAutoLoad?: boolean;\n shouldAutoPlay?: boolean;\n hasCustomAppendix?: boolean;\n lastSyncTime?: number;\n isOwn: boolean;\n albumLayout: IAlbumLayout;\n onMediaClick: (messageId: number) => void;\n};\n\ntype StateProps = {\n uploadsById: GlobalState['fileUploads']['byMessageLocalId'];\n};\n\ntype DispatchProps = Pick<GlobalActions, 'cancelSendingMessage'>;\n\nconst Album: FC<OwnProps & StateProps & DispatchProps> = ({\n album,\n observeIntersection,\n shouldAutoLoad,\n shouldAutoPlay,\n hasCustomAppendix,\n lastSyncTime,\n isOwn,\n albumLayout,\n onMediaClick,\n uploadsById,\n cancelSendingMessage,\n}) => {\n const mediaCount = album.messages.length;\n\n const handleCancelUpload = useCallback((message: ApiMessage) => {\n cancelSendingMessage({ chatId: message.chatId, messageId: message.id });\n }, [cancelSendingMessage]);\n\n function renderAlbumMessage(message: ApiMessage, index: number) {\n const { photo, video } = getMessageContent(message);\n const fileUpload = uploadsById[message.previousLocalId || message.id];\n const uploadProgress = fileUpload ? fileUpload.progress : undefined;\n const { dimensions, sides } = albumLayout.layout[index];\n\n if (photo) {\n const shouldAffectAppendix = hasCustomAppendix && (\n // eslint-disable-next-line no-bitwise\n isOwn ? index === mediaCount - 1 : Boolean(sides & AlbumRectPart.Left && sides & AlbumRectPart.Bottom)\n );\n\n return (\n <PhotoWithSelect\n id={`album-media-${message.id}`}\n message={message}\n observeIntersection={observeIntersection}\n shouldAutoLoad={shouldAutoLoad}\n shouldAffectAppendix={shouldAffectAppendix}\n uploadProgress={uploadProgress}\n dimensions={dimensions}\n onClick={onMediaClick}\n onCancelUpload={handleCancelUpload}\n />\n );\n } else if (video) {\n return (\n <VideoWithSelect\n id={`album-media-${message.id}`}\n message={message}\n observeIntersection={observeIntersection}\n shouldAutoLoad={shouldAutoLoad}\n shouldAutoPlay={shouldAutoPlay}\n uploadProgress={uploadProgress}\n lastSyncTime={lastSyncTime}\n dimensions={dimensions}\n onClick={onMediaClick}\n onCancelUpload={handleCancelUpload}\n />\n );\n }\n\n return undefined;\n }\n\n const { width: containerWidth, height: containerHeight } = albumLayout.containerStyle;\n\n return (\n <div\n className=\"Album\"\n // @ts-ignore\n style={`width: ${containerWidth}px; height: ${containerHeight}px;`}\n >\n {album.messages.map(renderAlbumMessage)}\n </div>\n );\n};\n\nexport default withGlobal<OwnProps>(\n (global): StateProps => {\n return {\n uploadsById: global.fileUploads.byMessageLocalId,\n };\n },\n (setGlobal, actions): DispatchProps => pick(actions, [\n 'cancelSendingMessage',\n ]),\n)(Album);\n","import React, {\n FC,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from '../../../lib/teact/teact';\n\nimport { ApiMessage } from '../../../api/types';\n\nimport { ROUND_VIDEO_DIMENSIONS } from '../../common/helpers/mediaDimensions';\nimport { formatMediaDuration } from '../../../util/dateFormat';\nimport { getMessageMediaFormat, getMessageMediaHash } from '../../../modules/helpers';\nimport { ObserveFn, useIsIntersecting } from '../../../hooks/useIntersectionObserver';\nimport useMediaWithDownloadProgress from '../../../hooks/useMediaWithDownloadProgress';\nimport useShowTransition from '../../../hooks/useShowTransition';\nimport useTransitionForMedia from '../../../hooks/useTransitionForMedia';\nimport usePrevious from '../../../hooks/usePrevious';\nimport useBuffering from '../../../hooks/useBuffering';\nimport buildClassName from '../../../util/buildClassName';\nimport useHeavyAnimationCheckForVideo from '../../../hooks/useHeavyAnimationCheckForVideo';\nimport useVideoCleanup from '../../../hooks/useVideoCleanup';\nimport usePauseOnInactive from './hooks/usePauseOnInactive';\nimport useBlurredMediaThumbRef from './hooks/useBlurredMediaThumbRef';\nimport safePlay from '../../../util/safePlay';\nimport { fastRaf } from '../../../util/schedulers';\n\nimport ProgressSpinner from '../../ui/ProgressSpinner';\n\nimport './RoundVideo.scss';\n\ntype OwnProps = {\n message: ApiMessage;\n observeIntersection: ObserveFn;\n shouldAutoLoad?: boolean;\n shouldAutoPlay?: boolean;\n lastSyncTime?: number;\n};\n\nlet currentOnRelease: NoneToVoidFunction;\n\nfunction createCapture(onRelease: NoneToVoidFunction) {\n return () => {\n if (currentOnRelease) {\n currentOnRelease();\n }\n\n currentOnRelease = onRelease;\n };\n}\n\nconst RoundVideo: FC<OwnProps> = ({\n message,\n observeIntersection,\n shouldAutoLoad,\n shouldAutoPlay,\n lastSyncTime,\n}) => {\n // eslint-disable-next-line no-null/no-null\n const ref = useRef<HTMLDivElement>(null);\n // eslint-disable-next-line no-null/no-null\n const playingProgressRef = useRef<HTMLDivElement>(null);\n // eslint-disable-next-line no-null/no-null\n const playerRef = useRef<HTMLVideoElement>(null);\n\n const video = message.content.video!;\n\n const isIntersecting = useIsIntersecting(ref, observeIntersection);\n\n const [isDownloadAllowed, setIsDownloadAllowed] = useState(shouldAutoLoad && shouldAutoPlay);\n const shouldDownload = Boolean(isDownloadAllowed && isIntersecting && lastSyncTime);\n const { mediaData, downloadProgress } = useMediaWithDownloadProgress(\n getMessageMediaHash(message, 'inline'),\n !shouldDownload,\n getMessageMediaFormat(message, 'inline'),\n lastSyncTime,\n );\n const thumbRef = useBlurredMediaThumbRef(message, mediaData);\n\n const { isBuffered, bufferingHandlers } = useBuffering();\n const isTransferring = isDownloadAllowed && !isBuffered;\n const wasDownloadDisabled = usePrevious(isDownloadAllowed) === false;\n const {\n shouldRender: shouldSpinnerRender,\n transitionClassNames: spinnerClassNames,\n } = useShowTransition(isTransferring || !isBuffered, undefined, wasDownloadDisabled);\n const { shouldRenderThumb, transitionClassNames } = useTransitionForMedia(mediaData, 'slow');\n\n const [isActivated, setIsActivated] = useState<boolean>(false);\n const [progress, setProgress] = useState<number>(0);\n\n useEffect(() => {\n if (!isActivated) {\n return;\n }\n\n const circumference = 94 * 2 * Math.PI;\n const strokeDashOffset = circumference - progress * circumference;\n\n const playerEl = playerRef.current!;\n const playingProgressEl = playingProgressRef.current!;\n const svgEl = playingProgressEl.firstElementChild;\n\n if (!svgEl) {\n playingProgressEl.innerHTML = `<svg width=\"200px\" height=\"200px\">\n <circle cx=\"100\" cy=\"100\" r=\"94\" class=\"progress-circle\" transform=\"rotate(-90, 100, 100)\"\n stroke-dasharray=\"${circumference} ${circumference}\"\n stroke-dashoffset=\"${circumference}\"\n />\n </svg>`;\n } else {\n (svgEl.firstElementChild as SVGElement).setAttribute('stroke-dashoffset', strokeDashOffset.toString());\n }\n\n setProgress(playerEl.currentTime / playerEl.duration);\n }, [isActivated, progress]);\n\n const shouldPlay = Boolean(mediaData && isIntersecting);\n\n const stopPlaying = () => {\n setIsActivated(false);\n setProgress(0);\n safePlay(playerRef.current!);\n\n fastRaf(() => {\n playingProgressRef.current!.innerHTML = '';\n });\n };\n\n const capturePlaying = createCapture(stopPlaying);\n\n useEffect(() => {\n if (!playerRef.current) {\n return;\n }\n\n if (shouldPlay) {\n safePlay(playerRef.current);\n } else {\n playerRef.current.pause();\n }\n }, [shouldPlay]);\n\n useHeavyAnimationCheckForVideo(playerRef, shouldPlay);\n usePauseOnInactive(playerRef, Boolean(mediaData));\n useVideoCleanup(playerRef, [mediaData]);\n\n const handleClick = useCallback(() => {\n if (!mediaData) {\n setIsDownloadAllowed((isAllowed) => !isAllowed);\n\n return;\n }\n\n const playerEl = playerRef.current!;\n if (isActivated) {\n if (playerEl.paused) {\n safePlay(playerEl);\n } else {\n playerEl.pause();\n }\n } else {\n capturePlaying();\n // Pause is a workaround for iOS Safari – otherwise it stops video after several frames\n playerEl.pause();\n playerEl.currentTime = 0;\n safePlay(playerEl);\n\n setIsActivated(true);\n }\n }, [capturePlaying, isActivated, mediaData]);\n\n const handleTimeUpdate = useCallback((e: React.UIEvent<HTMLVideoElement>) => {\n const playerEl = e.currentTarget;\n\n setProgress(playerEl.currentTime / playerEl.duration);\n }, []);\n\n const videoClassName = buildClassName('full-media', transitionClassNames);\n\n return (\n <div\n ref={ref}\n className=\"RoundVideo media-inner\"\n onClick={handleClick}\n >\n {(shouldRenderThumb || mediaData) && (\n <div className=\"thumbnail-wrapper\">\n <canvas\n ref={thumbRef}\n className=\"thumbnail\"\n // @ts-ignore teact feature\n style={`width: ${ROUND_VIDEO_DIMENSIONS}px; height: ${ROUND_VIDEO_DIMENSIONS}px`}\n />\n </div>\n )}\n {mediaData && (\n <div className=\"video-wrapper\">\n {/* eslint-disable-next-line jsx-a11y/media-has-caption */}\n <video\n ref={playerRef}\n className={videoClassName}\n width={ROUND_VIDEO_DIMENSIONS}\n height={ROUND_VIDEO_DIMENSIONS}\n autoPlay\n muted={!isActivated}\n loop={!isActivated}\n playsInline\n onEnded={isActivated ? stopPlaying : undefined}\n // eslint-disable-next-line react/jsx-props-no-spreading\n {...bufferingHandlers}\n onTimeUpdate={isActivated ? handleTimeUpdate : undefined}\n >\n <source src={mediaData} />\n </video>\n </div>\n )}\n <div className=\"progress\" ref={playingProgressRef} />\n {shouldSpinnerRender && (\n <div className={`media-loading ${spinnerClassNames}`}>\n <ProgressSpinner progress={downloadProgress} />\n </div>\n )}\n {!mediaData && !isDownloadAllowed && (\n <i className=\"icon-large-play\" />\n )}\n <div className=\"message-media-duration\">\n {isActivated ? formatMediaDuration(playerRef.current!.currentTime) : formatMediaDuration(video.duration)}\n {(!isActivated || playerRef.current!.paused) && <i className=\"icon-muted-chat\" />}\n </div>\n </div>\n );\n};\n\nexport default RoundVideo;\n","import React, { FC } from '../../../lib/teact/teact';\n\nimport { ApiKeyboardButton, ApiMessage } from '../../../api/types';\n\nimport { RE_TME_LINK } from '../../../config';\nimport renderText from '../../common/helpers/renderText';\n\nimport Button from '../../ui/Button';\n\nimport './InlineButtons.scss';\n\ntype OwnProps = {\n message: ApiMessage;\n onClick: ({ button }: { button: ApiKeyboardButton }) => void;\n};\n\nconst InlineButtons: FC<OwnProps> = ({ message, onClick }) => {\n return (\n <div className=\"InlineButtons\">\n {message.inlineButtons!.map((row) => (\n <div className=\"row\">\n {row.map((button) => (\n <Button\n size=\"tiny\"\n ripple\n disabled={button.type === 'NOT_SUPPORTED'}\n onClick={() => onClick({ button })}\n >\n {renderText(button.text)}\n {button.type === 'url' && !button.value!.match(RE_TME_LINK) && <i className=\"icon-arrow-right\" />}\n </Button>\n ))}\n </div>\n ))}\n </div>\n );\n};\n\nexport default InlineButtons;\n","import React, {\n FC, memo, useCallback, useEffect,\n} from '../../../lib/teact/teact';\nimport { withGlobal } from '../../../lib/teact/teactn';\n\nimport {\n ApiChat, ApiMessage, ApiThreadInfo, ApiUser,\n} from '../../../api/types';\nimport { GlobalActions } from '../../../global/types';\n\nimport { pick } from '../../../util/iteratees';\nimport { isChatPrivate } from '../../../modules/helpers';\nimport { formatIntegerCompact } from '../../../util/textFormat';\nimport buildClassName from '../../../util/buildClassName';\nimport { selectThreadInfo, selectThreadOriginChat } from '../../../modules/selectors';\nimport useLang from '../../../hooks/useLang';\n\nimport Avatar from '../../common/Avatar';\n\nimport './CommentButton.scss';\n\ntype OwnProps = {\n message: ApiMessage;\n disabled?: boolean;\n};\n\ntype StateProps = {\n threadInfo: ApiThreadInfo;\n usersById?: Record<number, ApiUser>;\n chatsById?: Record<number, ApiChat>;\n shouldRequestThreadUpdate: boolean;\n};\n\ntype DispatchProps = Pick<GlobalActions, 'openChat' | 'requestThreadInfoUpdate'>;\n\nconst CommentButton: FC<OwnProps & StateProps & DispatchProps> = ({\n disabled,\n threadInfo,\n usersById,\n chatsById,\n shouldRequestThreadUpdate,\n openChat,\n requestThreadInfoUpdate,\n}) => {\n const lang = useLang();\n const {\n threadId, chatId, messagesCount, lastMessageId, lastReadInboxMessageId, recentReplierIds,\n } = threadInfo;\n\n const handleClick = useCallback(() => {\n openChat({ id: chatId, threadId });\n }, [openChat, chatId, threadId]);\n\n\n useEffect(() => {\n if (shouldRequestThreadUpdate) {\n requestThreadInfoUpdate({ chatId, threadId });\n }\n }, [chatId, requestThreadInfoUpdate, shouldRequestThreadUpdate, threadId]);\n\n if (messagesCount === undefined) {\n return undefined;\n }\n\n const recentRepliers = recentReplierIds && recentReplierIds.map((peerId) => {\n return isChatPrivate(peerId) ? usersById![peerId] : chatsById![peerId];\n }).filter(Boolean);\n\n function renderRecentRepliers() {\n return (\n recentRepliers && recentRepliers.length > 0 && (\n <div className=\"recent-repliers\" dir={lang.isRtl ? 'rtl' : 'ltr'}>\n {recentRepliers.map((user) => (\n <Avatar\n key={user.id}\n size=\"small\"\n user={isChatPrivate(user.id) ? user as ApiUser : undefined}\n chat={!isChatPrivate(user.id) ? user as ApiChat : undefined}\n />\n ))}\n </div>\n )\n );\n }\n\n const hasUnread = Boolean(lastReadInboxMessageId && lastMessageId && lastReadInboxMessageId < lastMessageId);\n\n return (\n <div\n data-cnt={formatIntegerCompact(messagesCount)}\n className={buildClassName('CommentButton', hasUnread && 'has-unread', disabled && 'disabled')}\n dir={lang.isRtl ? 'rtl' : 'ltr'}\n onClick={handleClick}\n >\n <i className=\"icon-comments-sticker\" />\n {(!recentRepliers || recentRepliers.length === 0) && <i className=\"icon-comments\" />}\n {renderRecentRepliers()}\n <div className=\"label\" dir=\"auto\">\n {messagesCount ? lang('Comments', messagesCount, 'i') : lang('LeaveAComment')}\n </div>\n <i className=\"icon-next\" />\n </div>\n );\n};\n\nexport default memo(withGlobal<OwnProps>(\n (global, { message }) => {\n const { threadId, chatId } = message.threadInfo!;\n\n const threadInfo = selectThreadInfo(global, chatId, threadId) || message.threadInfo!;\n const chat = selectThreadOriginChat(global, chatId, threadId);\n const { byId: usersById } = global.users;\n const { byId: chatsById } = global.chats;\n\n return {\n threadInfo,\n usersById,\n chatsById,\n shouldRequestThreadUpdate: !!chat && !threadInfo.topMessageId,\n };\n },\n (setGlobal, actions): DispatchProps => pick(actions, [\n 'openChat',\n 'requestThreadInfoUpdate',\n ]),\n)(CommentButton));\n","import React, {\n FC,\n memo,\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n} from '../../../lib/teact/teact';\nimport { withGlobal } from '../../../lib/teact/teactn';\n\nimport { GlobalActions, MessageListType } from '../../../global/types';\nimport {\n ApiMessage,\n ApiMessageOutgoingStatus,\n ApiUser,\n ApiChat,\n ApiSticker,\n MAIN_THREAD_ID,\n} from '../../../api/types';\nimport {\n FocusDirection, IAlbum, ISettings, MediaViewerOrigin,\n} from '../../../types';\n\nimport { IS_ANDROID, IS_TOUCH_ENV } from '../../../util/environment';\nimport { pick } from '../../../util/iteratees';\nimport {\n selectChat,\n selectChatMessage,\n selectUploadProgress,\n selectIsChatWithSelf,\n selectOutgoingStatus,\n selectUser,\n selectIsMessageFocused,\n selectCurrentTextSearch,\n selectAnimatedEmoji,\n selectIsInSelectMode,\n selectIsMessageSelected,\n selectIsDocumentGroupSelected,\n selectSender,\n selectForwardedSender,\n selectThreadTopMessageId,\n selectShouldAutoLoadMedia,\n selectShouldAutoPlayMedia,\n selectShouldLoopStickers,\n selectTheme,\n} from '../../../modules/selectors';\nimport {\n getMessageContent,\n isOwnMessage,\n isReplyMessage,\n isAnonymousOwnMessage,\n isMessageLocal,\n isChatPrivate,\n getMessageCustomShape,\n isChatChannel,\n getMessageSingleEmoji,\n getSenderTitle,\n getUserColorKey,\n} from '../../../modules/helpers';\nimport buildClassName from '../../../util/buildClassName';\nimport windowSize from '../../../util/windowSize';\nimport useEnsureMessage from '../../../hooks/useEnsureMessage';\nimport useContextMenuHandlers from '../../../hooks/useContextMenuHandlers';\nimport { renderMessageText } from '../../common/helpers/renderMessageText';\nimport { ROUND_VIDEO_DIMENSIONS } from '../../common/helpers/mediaDimensions';\nimport { buildContentClassName, isEmojiOnlyMessage } from './helpers/buildContentClassName';\nimport { getMinMediaWidth, calculateMediaDimensions } from './helpers/mediaDimensions';\nimport { calculateAlbumLayout } from './helpers/calculateAlbumLayout';\nimport { preventMessageInputBlur } from '../helpers/preventMessageInputBlur';\nimport renderText from '../../common/helpers/renderText';\nimport calculateAuthorWidth from './helpers/calculateAuthorWidth';\nimport { ObserveFn, useOnIntersect } from '../../../hooks/useIntersectionObserver';\nimport useFocusMessage from './hooks/useFocusMessage';\nimport useLang from '../../../hooks/useLang';\nimport useShowTransition from '../../../hooks/useShowTransition';\nimport useFlag from '../../../hooks/useFlag';\n\nimport Button from '../../ui/Button';\nimport Avatar from '../../common/Avatar';\nimport EmbeddedMessage from '../../common/EmbeddedMessage';\nimport Document from '../../common/Document';\nimport Audio from '../../common/Audio';\nimport MessageMeta from './MessageMeta';\nimport ContextMenuContainer from './ContextMenuContainer.async';\nimport Sticker from './Sticker';\nimport AnimatedEmoji from '../../common/AnimatedEmoji';\nimport Photo from './Photo';\nimport Video from './Video';\nimport Contact from './Contact';\nimport Poll from './Poll';\nimport WebPage from './WebPage';\nimport Invoice from './Invoice';\nimport Album from './Album';\nimport RoundVideo from './RoundVideo';\nimport InlineButtons from './InlineButtons';\nimport CommentButton from './CommentButton';\n\nimport './Message.scss';\n\ntype MessagePositionProperties = {\n isFirstInGroup: boolean;\n isLastInGroup: boolean;\n isFirstInDocumentGroup: boolean;\n isLastInDocumentGroup: boolean;\n isLastInList: boolean;\n};\n\ntype OwnProps = {\n message: ApiMessage;\n observeIntersectionForBottom: ObserveFn;\n observeIntersectionForMedia: ObserveFn;\n observeIntersectionForAnimatedStickers: ObserveFn;\n album?: IAlbum;\n noAvatars?: boolean;\n withAvatar?: boolean;\n withSenderName?: boolean;\n threadId: number;\n messageListType: MessageListType;\n noComments: boolean;\n appearanceOrder: number;\n} & MessagePositionProperties;\n\ntype StateProps = {\n theme: ISettings['theme'];\n forceSenderName?: boolean;\n chatUsername?: string;\n sender?: ApiUser | ApiChat;\n originSender?: ApiUser | ApiChat;\n botSender?: ApiUser;\n isThreadTop?: boolean;\n shouldHideReply?: boolean;\n replyMessage?: ApiMessage;\n replyMessageSender?: ApiUser | ApiChat;\n outgoingStatus?: ApiMessageOutgoingStatus;\n uploadProgress?: number;\n isFocused?: boolean;\n focusDirection?: FocusDirection;\n noFocusHighlight?: boolean;\n isForwarding?: boolean;\n isChatWithSelf?: boolean;\n isChannel?: boolean;\n lastSyncTime?: number;\n highlight?: string;\n isSingleEmoji?: boolean;\n animatedEmoji?: ApiSticker;\n isInSelectMode?: boolean;\n isSelected?: boolean;\n isGroupSelected?: boolean;\n threadId?: number;\n isPinnedList?: boolean;\n shouldAutoLoadMedia?: boolean;\n shouldAutoPlayMedia?: boolean;\n shouldLoopStickers?: boolean;\n};\n\ntype DispatchProps = Pick<GlobalActions, (\n 'focusMessage' | 'openMediaViewer' | 'openAudioPlayer' |\n 'openUserInfo' | 'openChat' |\n 'cancelSendingMessage' | 'markMessagesRead' |\n 'sendPollVote' | 'toggleMessageSelection' | 'setReplyingToId' | 'openForwardMenu' |\n 'clickInlineButton' | 'disableContextMenuHint' | 'showNotification'\n)>;\n\nconst NBSP = '\\u00A0';\nconst GROUP_MESSAGE_HOVER_ATTRIBUTE = 'data-is-document-group-hover';\n// eslint-disable-next-line max-len\nconst APPENDIX_OWN = '<svg width=\"9\" height=\"20\" xmlns=\"http://www.w3.org/2000/svg\"><defs><filter x=\"-50%\" y=\"-14.7%\" width=\"200%\" height=\"141.2%\" filterUnits=\"objectBoundingBox\" id=\"a\"><feOffset dy=\"1\" in=\"SourceAlpha\" result=\"shadowOffsetOuter1\"/><feGaussianBlur stdDeviation=\"1\" in=\"shadowOffsetOuter1\" result=\"shadowBlurOuter1\"/><feColorMatrix values=\"0 0 0 0 0.0621962482 0 0 0 0 0.138574144 0 0 0 0 0.185037364 0 0 0 0.15 0\" in=\"shadowBlurOuter1\"/></filter></defs><g fill=\"none\" fill-rule=\"evenodd\"><path d=\"M6 17H0V0c.193 2.84.876 5.767 2.05 8.782.904 2.325 2.446 4.485 4.625 6.48A1 1 0 016 17z\" fill=\"#000\" filter=\"url(#a)\"/><path d=\"M6 17H0V0c.193 2.84.876 5.767 2.05 8.782.904 2.325 2.446 4.485 4.625 6.48A1 1 0 016 17z\" fill=\"#EEFFDE\" class=\"corner\"/></g></svg>';\n// eslint-disable-next-line max-len\nconst APPENDIX_NOT_OWN = '<svg width=\"9\" height=\"20\" xmlns=\"http://www.w3.org/2000/svg\"><defs><filter x=\"-50%\" y=\"-14.7%\" width=\"200%\" height=\"141.2%\" filterUnits=\"objectBoundingBox\" id=\"a\"><feOffset dy=\"1\" in=\"SourceAlpha\" result=\"shadowOffsetOuter1\"/><feGaussianBlur stdDeviation=\"1\" in=\"shadowOffsetOuter1\" result=\"shadowBlurOuter1\"/><feColorMatrix values=\"0 0 0 0 0.0621962482 0 0 0 0 0.138574144 0 0 0 0 0.185037364 0 0 0 0.15 0\" in=\"shadowBlurOuter1\"/></filter></defs><g fill=\"none\" fill-rule=\"evenodd\"><path d=\"M3 17h6V0c-.193 2.84-.876 5.767-2.05 8.782-.904 2.325-2.446 4.485-4.625 6.48A1 1 0 003 17z\" fill=\"#000\" filter=\"url(#a)\"/><path d=\"M3 17h6V0c-.193 2.84-.876 5.767-2.05 8.782-.904 2.325-2.446 4.485-4.625 6.48A1 1 0 003 17z\" fill=\"#FFF\" class=\"corner\"/></g></svg>';\nconst APPEARANCE_DELAY = 10;\nconst NO_MEDIA_CORNERS_THRESHOLD = 18;\nconst ANDROID_KEYBOARD_HIDE_DELAY_MS = 350;\n\nconst Message: FC<OwnProps & StateProps & DispatchProps> = ({\n message,\n chatUsername,\n observeIntersectionForBottom,\n observeIntersectionForMedia,\n observeIntersectionForAnimatedStickers,\n album,\n noAvatars,\n withAvatar,\n withSenderName,\n noComments,\n appearanceOrder,\n isFirstInGroup,\n isLastInGroup,\n isFirstInDocumentGroup,\n isLastInDocumentGroup,\n isLastInList,\n theme,\n forceSenderName,\n sender,\n originSender,\n botSender,\n isThreadTop,\n shouldHideReply,\n replyMessage,\n replyMessageSender,\n outgoingStatus,\n uploadProgress,\n isFocused,\n focusDirection,\n noFocusHighlight,\n isForwarding,\n isChatWithSelf,\n isChannel,\n lastSyncTime,\n highlight,\n animatedEmoji,\n isInSelectMode,\n isSelected,\n isGroupSelected,\n threadId,\n messageListType,\n isPinnedList,\n shouldAutoLoadMedia,\n shouldAutoPlayMedia,\n shouldLoopStickers,\n focusMessage,\n openMediaViewer,\n openAudioPlayer,\n openUserInfo,\n openChat,\n cancelSendingMessage,\n markMessagesRead,\n sendPollVote,\n toggleMessageSelection,\n setReplyingToId,\n openForwardMenu,\n clickInlineButton,\n disableContextMenuHint,\n showNotification,\n}) => {\n // eslint-disable-next-line no-null/no-null\n const ref = useRef<HTMLDivElement>(null);\n // eslint-disable-next-line no-null/no-null\n const bottomMarkerRef = useRef<HTMLDivElement>(null);\n // eslint-disable-next-line no-null/no-null\n const appendixRef = useRef<HTMLDivElement>(null);\n const lang = useLang();\n\n\n useOnIntersect(bottomMarkerRef, observeIntersectionForBottom);\n\n const {\n isContextMenuOpen, contextMenuPosition,\n handleBeforeContextMenu, handleContextMenu: onContextMenu,\n handleContextMenuClose, handleContextMenuHide,\n } = useContextMenuHandlers(ref, IS_TOUCH_ENV && isInSelectMode, true, IS_ANDROID);\n\n useEffect(() => {\n if (isContextMenuOpen) {\n disableContextMenuHint();\n }\n }, [isContextMenuOpen, disableContextMenuHint]);\n\n const noAppearanceAnimation = appearanceOrder <= 0;\n const [isShown, markShown] = useFlag(noAppearanceAnimation);\n useEffect(() => {\n if (noAppearanceAnimation) {\n return;\n }\n\n setTimeout(markShown, appearanceOrder * APPEARANCE_DELAY);\n }, [appearanceOrder, markShown, noAppearanceAnimation]);\n const { transitionClassNames } = useShowTransition(isShown, undefined, noAppearanceAnimation, false);\n\n const { chatId, id: messageId, threadInfo } = message;\n\n const isLocal = isMessageLocal(message);\n const isOwn = isOwnMessage(message);\n const isScheduled = messageListType === 'scheduled' || message.isScheduled;\n const hasReply = isReplyMessage(message) && !shouldHideReply;\n const hasThread = Boolean(threadInfo) && messageListType === 'thread';\n const { forwardInfo, viaBotId } = message;\n const asForwarded = forwardInfo && !isChatWithSelf && !forwardInfo.isLinkedChannelPost;\n const isInDocumentGroup = !!message.groupedId && !message.isInAlbum;\n const isAlbum = Boolean(album) && album!.messages.length > 1;\n const {\n text, photo, video, audio, voice, document, sticker, contact, poll, webPage, invoice,\n } = getMessageContent(message);\n const customShape = getMessageCustomShape(message);\n const textParts = renderMessageText(message, highlight, isEmojiOnlyMessage(customShape));\n const isContextMenuShown = contextMenuPosition !== undefined;\n const signature = (\n (isChannel && message.adminTitle) || (forwardInfo && !asForwarded && forwardInfo.adminTitle) || undefined\n );\n const metaSafeAuthorWidth = useMemo(() => {\n return signature ? calculateAuthorWidth(signature) : undefined;\n }, [signature]);\n const canShowActionButton = (\n !(isContextMenuShown || isInSelectMode || isForwarding)\n && (!isInDocumentGroup || isLastInDocumentGroup)\n );\n const canForward = canShowActionButton && isChannel && !isScheduled;\n const canFocus = Boolean(canShowActionButton && (\n (forwardInfo && (forwardInfo.isChannelPost || (isChatWithSelf && !isOwn)) && forwardInfo.fromMessageId)\n || isPinnedList\n ));\n const avatarPeer = forwardInfo && (isChatWithSelf || !sender) ? originSender : sender;\n const senderPeer = forwardInfo ? originSender : sender;\n\n const containerClassName = buildClassName(\n 'Message message-list-item',\n isFirstInGroup && 'first-in-group',\n isLastInGroup && 'last-in-group',\n isFirstInDocumentGroup && 'first-in-document-group',\n isLastInDocumentGroup && 'last-in-document-group',\n isLastInList && 'last-in-list',\n isOwn && 'own',\n Boolean(message.views) && 'has-views',\n message.isEdited && 'was-edited',\n hasReply && 'has-reply',\n isContextMenuShown && 'has-menu-open',\n isFocused && !noFocusHighlight && 'focused',\n isForwarding && 'is-forwarding',\n message.isDeleting && 'is-deleting',\n isInDocumentGroup && 'is-in-document-group',\n isAlbum && 'is-album',\n message.hasUnreadMention && 'has-unread-mention',\n isSelected && 'is-selected',\n isInSelectMode && 'is-in-selection-mode',\n isThreadTop && 'is-thread-top',\n Boolean(message.inlineButtons) && 'has-inline-buttons',\n transitionClassNames,\n );\n const contentClassName = buildContentClassName(message, {\n hasReply,\n customShape,\n isLastInGroup,\n asForwarded,\n hasThread,\n forceSenderName,\n hasComments: message.threadInfo && message.threadInfo.messagesCount > 0,\n });\n const withCommentButton = message.threadInfo && (!isInDocumentGroup || isLastInDocumentGroup)\n && messageListType === 'thread' && !noComments;\n const withAppendix = contentClassName.includes('has-appendix');\n\n useEnsureMessage(chatId, hasReply ? message.replyToMessageId : undefined, replyMessage, message.id);\n useFocusMessage(ref, chatId, isFocused, focusDirection, noFocusHighlight);\n useLayoutEffect(() => {\n if (!appendixRef.current) {\n return;\n }\n\n appendixRef.current.innerHTML = isOwn ? APPENDIX_OWN : APPENDIX_NOT_OWN;\n }, [isOwn, withAppendix]);\n\n const handleGroupDocumentMessagesSelect = useCallback((e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {\n e.stopPropagation();\n\n toggleMessageSelection({\n messageId,\n groupedId: message.groupedId,\n });\n }, [messageId, message.groupedId, toggleMessageSelection]);\n\n const handleMessageSelect = useCallback((e?: React.MouseEvent<HTMLDivElement, MouseEvent>) => {\n if (isLocal) {\n return;\n }\n\n const params = isAlbum && album && album.messages\n ? {\n messageId,\n childMessageIds: album.messages.map(({ id }) => id),\n withShift: e && e.shiftKey,\n }\n : { messageId, withShift: e && e.shiftKey };\n toggleMessageSelection(params);\n }, [isLocal, isAlbum, album, messageId, toggleMessageSelection]);\n\n const handleContainerDoubleClick = useCallback(() => {\n setReplyingToId({ messageId });\n }, [setReplyingToId, messageId]);\n\n const handleContentDoubleClick = useCallback((e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {\n e.stopPropagation();\n }, []);\n\n const handleMouseDown = (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {\n preventMessageInputBlur(e);\n\n if (!isLocal) {\n handleBeforeContextMenu(e);\n }\n };\n\n const handleAvatarClick = useCallback(() => {\n if (!avatarPeer) {\n return;\n }\n\n if (isChatPrivate(avatarPeer.id)) {\n openUserInfo({ id: avatarPeer.id });\n } else {\n openChat({ id: avatarPeer.id });\n }\n }, [avatarPeer, openUserInfo, openChat]);\n\n const handleSenderClick = useCallback(() => {\n if (!senderPeer) {\n showNotification({ message: lang('HidAccount') });\n\n return;\n }\n\n if (isChatPrivate(senderPeer.id)) {\n openUserInfo({ id: senderPeer.id });\n } else {\n openChat({ id: senderPeer.id });\n }\n }, [senderPeer, showNotification, lang, openUserInfo, openChat]);\n\n const handleViaBotClick = useCallback(() => {\n if (!botSender) {\n return;\n }\n\n openUserInfo({ id: botSender.id });\n }, [botSender, openUserInfo]);\n\n const handleReplyClick = useCallback((): void => {\n focusMessage({\n chatId, threadId, messageId: message.replyToMessageId, replyMessageId: messageId,\n });\n }, [focusMessage, chatId, threadId, message.replyToMessageId, messageId]);\n\n const handleMediaClick = useCallback((): void => {\n openMediaViewer({\n chatId, threadId, messageId, origin: isScheduled ? MediaViewerOrigin.ScheduledInline : MediaViewerOrigin.Inline,\n });\n }, [chatId, threadId, messageId, openMediaViewer, isScheduled]);\n\n const handleAudioPlay = useCallback((): void => {\n openAudioPlayer({ chatId, messageId });\n }, [chatId, messageId, openAudioPlayer]);\n\n const handleAlbumMediaClick = useCallback((albumMessageId: number): void => {\n openMediaViewer({\n chatId,\n threadId,\n messageId: albumMessageId,\n origin: isScheduled ? MediaViewerOrigin.ScheduledAlbum : MediaViewerOrigin.Album,\n });\n }, [chatId, threadId, openMediaViewer, isScheduled]);\n\n const handleClick = useCallback((e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {\n const target = e.target as HTMLDivElement;\n if (!target.classList.contains('text-content') && !target.classList.contains('Message')) {\n return;\n }\n\n if (IS_ANDROID) {\n if (windowSize.getIsKeyboardVisible()) {\n setTimeout(() => { onContextMenu(e); }, ANDROID_KEYBOARD_HIDE_DELAY_MS);\n } else {\n onContextMenu(e);\n }\n } else {\n onContextMenu(e);\n }\n }, [onContextMenu]);\n\n const handleContextMenu = useCallback((e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {\n if (IS_ANDROID) {\n handleMessageSelect(e);\n } else {\n onContextMenu(e);\n }\n }, [onContextMenu, handleMessageSelect]);\n\n const handleReadMedia = useCallback((): void => {\n markMessagesRead({ messageIds: [messageId] });\n }, [messageId, markMessagesRead]);\n\n const handleCancelUpload = useCallback(() => {\n cancelSendingMessage({ chatId, messageId });\n }, [cancelSendingMessage, chatId, messageId]);\n\n const handleVoteSend = useCallback((options: string[]) => {\n sendPollVote({ chatId, messageId, options });\n }, [chatId, messageId, sendPollVote]);\n\n const handleGroupForward = useCallback(() => {\n openForwardMenu({ fromChatId: chatId, groupedId: message.groupedId });\n }, [openForwardMenu, chatId, message.groupedId]);\n\n const handleForward = useCallback(() => {\n if (album && album.messages) {\n const messageIds = album.messages.map(({ id }) => id);\n openForwardMenu({ fromChatId: chatId, messageIds });\n } else {\n openForwardMenu({ fromChatId: chatId, messageIds: [messageId] });\n }\n }, [album, openForwardMenu, chatId, messageId]);\n\n const handleFocus = useCallback(() => {\n focusMessage({\n chatId, threadId: MAIN_THREAD_ID, messageId,\n });\n }, [focusMessage, chatId, messageId]);\n\n const handleFocusForwarded = useCallback(() => {\n if (isInDocumentGroup) {\n focusMessage({\n chatId: forwardInfo!.fromChatId, groupedId: message.groupedId, groupedChatId: chatId,\n });\n return;\n }\n focusMessage({\n chatId: forwardInfo!.fromChatId, messageId: forwardInfo!.fromMessageId,\n });\n }, [focusMessage, forwardInfo, message, chatId, isInDocumentGroup]);\n\n let style = '';\n let calculatedWidth;\n let noMediaCorners = false;\n const albumLayout = useMemo(() => {\n return isAlbum ? calculateAlbumLayout(isOwn, Boolean(asForwarded), Boolean(noAvatars), album!) : undefined;\n }, [isAlbum, isOwn, asForwarded, noAvatars, album]);\n\n const extraPadding = asForwarded ? 28 : 0;\n if (!isAlbum && (photo || video)) {\n let width: number | undefined;\n if (photo) {\n width = calculateMediaDimensions(message, noAvatars).width;\n } else if (video) {\n if (video.isRound) {\n width = ROUND_VIDEO_DIMENSIONS;\n } else {\n width = calculateMediaDimensions(message, noAvatars).width;\n }\n }\n\n if (width) {\n calculatedWidth = Math.max(getMinMediaWidth(Boolean(text), withCommentButton), width);\n if (calculatedWidth - width > NO_MEDIA_CORNERS_THRESHOLD) {\n noMediaCorners = true;\n }\n }\n } else if (albumLayout) {\n calculatedWidth = Math.max(getMinMediaWidth(Boolean(text), withCommentButton), albumLayout.containerStyle.width);\n if (calculatedWidth - albumLayout.containerStyle.width > NO_MEDIA_CORNERS_THRESHOLD) {\n noMediaCorners = true;\n }\n }\n\n if (calculatedWidth) {\n style = `width: ${calculatedWidth + extraPadding}px`;\n }\n\n function renderAvatar() {\n const isAvatarPeerUser = avatarPeer && isChatPrivate(avatarPeer.id);\n const avatarUser = avatarPeer && isAvatarPeerUser ? avatarPeer as ApiUser : undefined;\n const avatarChat = avatarPeer && !isAvatarPeerUser ? avatarPeer as ApiChat : undefined;\n const hiddenName = !avatarPeer && forwardInfo ? forwardInfo.hiddenUserName : undefined;\n\n return (\n <Avatar\n size=\"small\"\n user={avatarUser}\n chat={avatarChat}\n text={hiddenName}\n lastSyncTime={lastSyncTime}\n onClick={(avatarUser || avatarChat) ? handleAvatarClick : undefined}\n />\n );\n }\n\n function renderContent() {\n const className = buildClassName(\n 'content-inner',\n asForwarded && !customShape && 'forwarded-message',\n hasReply && 'reply-message',\n noMediaCorners && 'no-media-corners',\n );\n const hasCustomAppendix = isLastInGroup && !textParts && !asForwarded && !hasThread;\n const shouldInlineMeta = !webPage && !animatedEmoji && textParts;\n\n return (\n <div className={className} onDoubleClick={handleContentDoubleClick} dir=\"auto\">\n {renderSenderName()}\n {hasReply && (\n <EmbeddedMessage\n message={replyMessage}\n sender={replyMessageSender}\n observeIntersection={observeIntersectionForMedia}\n onClick={handleReplyClick}\n />\n )}\n {sticker && (\n <Sticker\n message={message}\n observeIntersection={observeIntersectionForMedia}\n observeIntersectionForPlaying={observeIntersectionForAnimatedStickers}\n shouldLoop={shouldLoopStickers}\n lastSyncTime={lastSyncTime}\n />\n )}\n {animatedEmoji && (\n <AnimatedEmoji\n isInline\n sticker={animatedEmoji}\n observeIntersection={observeIntersectionForMedia}\n lastSyncTime={lastSyncTime}\n forceLoadPreview={isLocal}\n />\n )}\n {isAlbum && (\n <Album\n album={album!}\n albumLayout={albumLayout!}\n observeIntersection={observeIntersectionForMedia}\n shouldAutoLoad={shouldAutoLoadMedia}\n shouldAutoPlay={shouldAutoPlayMedia}\n isOwn={isOwn}\n hasCustomAppendix={hasCustomAppendix}\n lastSyncTime={lastSyncTime}\n onMediaClick={handleAlbumMediaClick}\n />\n )}\n {!isAlbum && photo && (\n <Photo\n message={message}\n observeIntersection={observeIntersectionForMedia}\n noAvatars={noAvatars}\n shouldAutoLoad={shouldAutoLoadMedia}\n uploadProgress={uploadProgress}\n shouldAffectAppendix={hasCustomAppendix}\n onClick={handleMediaClick}\n onCancelUpload={handleCancelUpload}\n />\n )}\n {!isAlbum && video && video.isRound && (\n <RoundVideo\n message={message}\n observeIntersection={observeIntersectionForMedia}\n shouldAutoLoad={shouldAutoLoadMedia}\n shouldAutoPlay={shouldAutoPlayMedia}\n lastSyncTime={lastSyncTime}\n />\n )}\n {!isAlbum && video && !video.isRound && (\n <Video\n message={message}\n observeIntersection={observeIntersectionForMedia}\n noAvatars={noAvatars}\n shouldAutoLoad={shouldAutoLoadMedia}\n shouldAutoPlay={shouldAutoPlayMedia}\n uploadProgress={uploadProgress}\n lastSyncTime={lastSyncTime}\n onClick={handleMediaClick}\n onCancelUpload={handleCancelUpload}\n />\n )}\n {(audio || voice) && (\n <Audio\n theme={theme}\n message={message}\n uploadProgress={uploadProgress}\n lastSyncTime={lastSyncTime}\n isSelectable={isInDocumentGroup}\n isSelected={isSelected}\n onPlay={handleAudioPlay}\n onReadMedia={voice && (!isOwn || isChatWithSelf) ? handleReadMedia : undefined}\n onCancelUpload={handleCancelUpload}\n />\n )}\n {document && (\n <Document\n message={message}\n observeIntersection={observeIntersectionForMedia}\n uploadProgress={uploadProgress}\n isSelectable={isInDocumentGroup}\n isSelected={isSelected}\n onMediaClick={handleMediaClick}\n onCancelUpload={handleCancelUpload}\n />\n )}\n {contact && (\n <Contact contact={contact} />\n )}\n {poll && (\n <Poll message={message} poll={poll} onSendVote={handleVoteSend} />\n )}\n {!animatedEmoji && textParts && (\n <p className={`text-content ${shouldInlineMeta ? 'with-meta' : ''}`} dir=\"auto\">\n {textParts}\n {shouldInlineMeta && (\n <MessageMeta\n message={message}\n outgoingStatus={outgoingStatus}\n signature={signature}\n onClick={handleMessageSelect}\n />\n )}\n </p>\n )}\n {webPage && (\n <WebPage\n message={message}\n observeIntersection={observeIntersectionForMedia}\n noAvatars={noAvatars}\n shouldAutoLoad={shouldAutoLoadMedia}\n shouldAutoPlay={shouldAutoPlayMedia}\n lastSyncTime={lastSyncTime}\n onMediaClick={handleMediaClick}\n onCancelMediaTransfer={handleCancelUpload}\n />\n )}\n {invoice && (\n <Invoice\n message={message}\n />\n )}\n </div>\n );\n }\n\n function renderSenderName() {\n const shouldRender = !(customShape && !viaBotId) && (\n (withSenderName && !photo && !video) || asForwarded || viaBotId || forceSenderName\n ) && (!isInDocumentGroup || isFirstInDocumentGroup);\n\n if (!shouldRender) {\n return undefined;\n }\n\n let senderTitle;\n let senderColor;\n if (senderPeer && !(customShape && viaBotId)) {\n senderTitle = getSenderTitle(lang, senderPeer);\n\n if (!asForwarded) {\n senderColor = `color-${getUserColorKey(senderPeer)}`;\n }\n } else if (forwardInfo && forwardInfo.hiddenUserName) {\n senderTitle = forwardInfo.hiddenUserName;\n }\n\n return (\n <div className=\"message-title\" dir=\"ltr\">\n {senderTitle ? (\n <span\n className={buildClassName('interactive', senderColor)}\n onClick={handleSenderClick}\n dir=\"auto\"\n >\n {renderText(senderTitle)}\n </span>\n ) : !botSender ? (\n NBSP\n ) : undefined}\n {botSender && (\n <>\n <span className=\"via\">{lang('ViaBot')}</span>\n <span\n className=\"interactive\"\n onClick={handleViaBotClick}\n >\n {renderText(`@${botSender.username}`)}\n </span>\n </>\n )}\n {forwardInfo && forwardInfo.isLinkedChannelPost ? (\n <span className=\"admin-title\" dir=\"auto\">{lang('DiscussChannel')}</span>\n ) : message.adminTitle && !isChannel ? (\n <span className=\"admin-title\" dir=\"auto\">{message.adminTitle}</span>\n ) : undefined}\n </div>\n );\n }\n\n return (\n <div\n ref={ref}\n id={`message${messageId}`}\n className={containerClassName}\n // @ts-ignore teact feature\n style={metaSafeAuthorWidth ? `--meta-safe-author-width: ${metaSafeAuthorWidth}px` : undefined}\n data-message-id={messageId}\n onClick={isInSelectMode ? handleMessageSelect : IS_ANDROID ? handleClick : undefined}\n onDoubleClick={!isInSelectMode ? handleContainerDoubleClick : undefined}\n onMouseDown={!isInSelectMode ? handleMouseDown : undefined}\n onContextMenu={!isInSelectMode && !isLocal ? handleContextMenu : undefined}\n onMouseEnter={isInDocumentGroup && !isLastInDocumentGroup ? handleDocumentGroupMouseEnter : undefined}\n onMouseLeave={isInDocumentGroup && !isLastInDocumentGroup ? handleDocumentGroupMouseLeave : undefined}\n >\n <div\n ref={bottomMarkerRef}\n className=\"bottom-marker\"\n data-message-id={messageId}\n data-last-message-id={album ? album.messages[album.messages.length - 1].id : undefined}\n data-has-unread-mention={message.hasUnreadMention}\n />\n {!isLocal && !isInDocumentGroup && (\n <div className=\"message-select-control\">\n {isSelected && <i className=\"icon-select\" />}\n </div>\n )}\n {!isLocal && isLastInDocumentGroup && (\n <div\n className={buildClassName('message-select-control group-select', isGroupSelected && 'is-selected')}\n onClick={handleGroupDocumentMessagesSelect}\n >\n {isGroupSelected && (\n <i className=\"icon-select\" />\n )}\n </div>\n )}\n {withAvatar && renderAvatar()}\n <div\n className={buildClassName('message-content-wrapper', contentClassName.includes('text') && 'can-select-text')}\n onClick={isInSelectMode && isInDocumentGroup ? handleMessageSelect : undefined}\n >\n <div\n className={contentClassName}\n // @ts-ignore\n style={style}\n dir=\"auto\"\n >\n {asForwarded && !customShape && (!isInDocumentGroup || isFirstInDocumentGroup) && (\n <div className=\"message-title\">{lang('ForwardedMessage')}</div>\n )}\n {renderContent()}\n {(!isInDocumentGroup || isLastInDocumentGroup) && !(!webPage && !animatedEmoji && textParts) && (\n <MessageMeta\n message={message}\n outgoingStatus={outgoingStatus}\n signature={signature}\n onClick={handleMessageSelect}\n />\n )}\n {canForward ? (\n <Button\n className=\"message-action-button\"\n color=\"translucent-white\"\n round\n size=\"tiny\"\n ariaLabel={lang('lng_context_forward_msg')}\n onClick={isLastInDocumentGroup ? handleGroupForward : handleForward}\n >\n <i className=\"icon-share-filled\" />\n </Button>\n ) : canFocus ? (\n <Button\n className=\"message-action-button\"\n color=\"translucent-white\"\n round\n size=\"tiny\"\n ariaLabel=\"Focus message\"\n onClick={isPinnedList ? handleFocus : handleFocusForwarded}\n >\n <i className=\"icon-arrow-right\" />\n </Button>\n ) : undefined}\n {withCommentButton && <CommentButton message={message} disabled={noComments} />}\n {withAppendix && <div className=\"svg-appendix\" ref={appendixRef} />}\n </div>\n {message.inlineButtons && (\n <InlineButtons message={message} onClick={clickInlineButton} />\n )}\n </div>\n {contextMenuPosition && (\n <ContextMenuContainer\n isOpen={isContextMenuOpen}\n anchor={contextMenuPosition}\n message={message}\n album={album}\n chatUsername={chatUsername}\n messageListType={messageListType}\n onClose={handleContextMenuClose}\n onCloseAnimationEnd={handleContextMenuHide}\n />\n )}\n </div>\n );\n};\n\nfunction handleDocumentGroupMouseEnter(e: React.MouseEvent<HTMLDivElement>) {\n const lastGroupElement = getLastElementInDocumentGroup(e.currentTarget);\n if (lastGroupElement) {\n lastGroupElement.setAttribute(GROUP_MESSAGE_HOVER_ATTRIBUTE, '');\n }\n}\n\nfunction handleDocumentGroupMouseLeave(e: React.MouseEvent<HTMLDivElement>) {\n const lastGroupElement = getLastElementInDocumentGroup(e.currentTarget);\n if (lastGroupElement) {\n lastGroupElement.removeAttribute(GROUP_MESSAGE_HOVER_ATTRIBUTE);\n }\n}\n\nfunction getLastElementInDocumentGroup(element: Element) {\n let current: Element | null = element;\n\n do {\n current = current.nextElementSibling;\n } while (current && !current.classList.contains('last-in-document-group'));\n\n return current;\n}\n\nexport default memo(withGlobal<OwnProps>(\n (global, ownProps): StateProps => {\n const { focusedMessage, forwardMessages, lastSyncTime } = global;\n const {\n message, album, withSenderName, withAvatar, threadId, messageListType,\n } = ownProps;\n const {\n id, chatId, viaBotId, replyToMessageId, isOutgoing,\n } = message;\n\n const chat = selectChat(global, chatId);\n const isChatWithSelf = selectIsChatWithSelf(global, chatId);\n const isChannel = chat && isChatChannel(chat);\n const chatUsername = chat && chat.username;\n\n const forceSenderName = !isChatWithSelf && isAnonymousOwnMessage(message);\n const canShowSender = withSenderName || withAvatar || forceSenderName;\n const sender = canShowSender ? selectSender(global, message) : undefined;\n const originSender = selectForwardedSender(global, message);\n const botSender = viaBotId ? selectUser(global, viaBotId) : undefined;\n\n const threadTopMessageId = threadId ? selectThreadTopMessageId(global, chatId, threadId) : undefined;\n const isThreadTop = message.id === threadTopMessageId;\n\n const shouldHideReply = replyToMessageId === threadTopMessageId;\n const replyMessage = replyToMessageId && !shouldHideReply\n ? selectChatMessage(global, chatId, replyToMessageId)\n : undefined;\n const replyMessageSender = replyMessage && selectSender(global, replyMessage);\n\n const uploadProgress = selectUploadProgress(global, message);\n const isFocused = messageListType === 'thread' && (\n album\n ? album.messages.some((m) => selectIsMessageFocused(global, m))\n : selectIsMessageFocused(global, message)\n );\n\n const { direction: focusDirection, noHighlight: noFocusHighlight } = (isFocused && focusedMessage) || {};\n\n const isForwarding = forwardMessages.messageIds && forwardMessages.messageIds.includes(id);\n\n const { query: highlight } = selectCurrentTextSearch(global) || {};\n\n const singleEmoji = getMessageSingleEmoji(message);\n let isSelected: boolean;\n\n if (album && album.messages) {\n isSelected = album.messages.every(({ id: messageId }) => selectIsMessageSelected(global, messageId));\n } else {\n isSelected = selectIsMessageSelected(global, id);\n }\n\n return {\n theme: selectTheme(global),\n chatUsername,\n forceSenderName,\n sender,\n originSender,\n botSender,\n shouldHideReply,\n isThreadTop,\n replyMessage,\n replyMessageSender,\n isFocused,\n isForwarding,\n isChatWithSelf,\n isChannel,\n lastSyncTime,\n highlight,\n isSingleEmoji: Boolean(singleEmoji),\n animatedEmoji: singleEmoji ? selectAnimatedEmoji(global, singleEmoji) : undefined,\n isInSelectMode: selectIsInSelectMode(global),\n isSelected,\n isGroupSelected: (\n !!message.groupedId && !message.isInAlbum && selectIsDocumentGroupSelected(global, chatId, message.groupedId)\n ),\n threadId,\n isPinnedList: messageListType === 'pinned',\n shouldAutoLoadMedia: chat ? selectShouldAutoLoadMedia(global, message, chat, sender) : undefined,\n shouldAutoPlayMedia: selectShouldAutoPlayMedia(global, message),\n shouldLoopStickers: selectShouldLoopStickers(global),\n ...(isOutgoing && { outgoingStatus: selectOutgoingStatus(global, message, messageListType === 'scheduled') }),\n ...(typeof uploadProgress === 'number' && { uploadProgress }),\n ...(isFocused && { focusDirection, noFocusHighlight }),\n };\n },\n (setGlobal, actions): DispatchProps => pick(actions, [\n 'focusMessage',\n 'openMediaViewer',\n 'openAudioPlayer',\n 'cancelSendingMessage',\n 'openUserInfo',\n 'openChat',\n 'markMessagesRead',\n 'sendPollVote',\n 'toggleMessageSelection',\n 'setReplyingToId',\n 'openForwardMenu',\n 'clickInlineButton',\n 'disableContextMenuHint',\n 'showNotification',\n ]),\n)(Message));\n","import { RefObject } from 'react';\nimport React, { FC, memo } from '../../lib/teact/teact';\n\nimport { MessageListType } from '../../global/types';\n\nimport { SCHEDULED_WHEN_ONLINE } from '../../config';\nimport buildClassName from '../../util/buildClassName';\nimport { compact, flatten } from '../../util/iteratees';\nimport { formatHumanDate } from '../../util/dateFormat';\nimport { getMessageOriginalId, isActionMessage, isOwnMessage } from '../../modules/helpers';\nimport useLang from '../../hooks/useLang';\nimport { isAlbum, MessageDateGroup } from './helpers/groupMessages';\nimport { preventMessageInputBlur } from './helpers/preventMessageInputBlur';\nimport useScrollHooks from './hooks/useScrollHooks';\nimport useMessageObservers from './hooks/useMessageObservers';\n\nimport Message from './message/Message';\nimport ActionMessage from './ActionMessage';\n\ninterface OwnProps {\n messageIds: number[];\n messageGroups: MessageDateGroup[];\n isViewportNewest: boolean;\n isUnread: boolean;\n withUsers: boolean;\n noAvatars: boolean;\n containerRef: RefObject<HTMLDivElement>;\n anchorIdRef: { current: string | undefined };\n memoFirstUnreadIdRef: { current: number | undefined };\n threadId: number;\n type: MessageListType;\n threadTopMessageId: number | undefined;\n hasLinkedChat: boolean | undefined;\n isSchedule: boolean;\n noAppearanceAnimation: boolean;\n onFabToggle: AnyToVoidFunction;\n onNotchToggle: AnyToVoidFunction;\n openHistoryCalendar: Function;\n}\n\nconst UNREAD_DIVIDER_CLASS = 'unread-divider';\n\nconst MessageListContent: FC<OwnProps> = ({\n messageIds,\n messageGroups,\n isViewportNewest,\n isUnread,\n withUsers,\n noAvatars,\n containerRef,\n anchorIdRef,\n memoFirstUnreadIdRef,\n threadId,\n type,\n threadTopMessageId,\n hasLinkedChat,\n isSchedule,\n noAppearanceAnimation,\n onFabToggle,\n onNotchToggle,\n openHistoryCalendar,\n}) => {\n const {\n observeIntersectionForMedia,\n observeIntersectionForReading,\n observeIntersectionForAnimatedStickers,\n } = useMessageObservers(type, containerRef, memoFirstUnreadIdRef);\n\n const {\n backwardsTriggerRef,\n forwardsTriggerRef,\n fabTriggerRef,\n } = useScrollHooks(\n type,\n containerRef,\n messageIds,\n isViewportNewest,\n isUnread,\n onFabToggle,\n onNotchToggle,\n );\n\n const lang = useLang();\n\n const unreadDivider = (\n <div className={buildClassName(UNREAD_DIVIDER_CLASS, 'local-action-message')} key=\"unread-messages\">\n <span>{lang('UnreadMessages')}</span>\n </div>\n );\n\n const messageCountToAnimate = noAppearanceAnimation ? 0 : messageGroups.reduce((acc, messageGroup) => {\n return acc + flatten(messageGroup.senderGroups).length;\n }, 0);\n let appearanceIndex = 0;\n\n const dateGroups = messageGroups.map((\n dateGroup: MessageDateGroup,\n dateGroupIndex: number,\n dateGroupsArray: MessageDateGroup[],\n ) => {\n const senderGroups = dateGroup.senderGroups.map((\n senderGroup,\n senderGroupIndex,\n senderGroupsArray,\n ) => {\n if (senderGroup.length === 1 && !isAlbum(senderGroup[0]) && isActionMessage(senderGroup[0])) {\n const message = senderGroup[0];\n const isLastInList = (\n senderGroupIndex === senderGroupsArray.length - 1\n && dateGroupIndex === dateGroupsArray.length - 1\n );\n\n return compact([\n message.id === memoFirstUnreadIdRef.current && unreadDivider,\n <ActionMessage\n key={message.id}\n message={message}\n observeIntersection={observeIntersectionForReading}\n appearanceOrder={messageCountToAnimate - ++appearanceIndex}\n isLastInList={isLastInList}\n />,\n ]);\n }\n\n let currentDocumentGroupId: string | undefined;\n\n return flatten(senderGroup.map((\n messageOrAlbum,\n messageIndex,\n ) => {\n const message = isAlbum(messageOrAlbum) ? messageOrAlbum.mainMessage : messageOrAlbum;\n const album = isAlbum(messageOrAlbum) ? messageOrAlbum : undefined;\n const isOwn = isOwnMessage(message);\n const isMessageAlbum = isAlbum(messageOrAlbum);\n const nextMessage = senderGroup[messageIndex + 1];\n\n if (message.previousLocalId && anchorIdRef.current === `message${message.previousLocalId}`) {\n anchorIdRef.current = `message${message.id}`;\n }\n\n const documentGroupId = !isMessageAlbum && message.groupedId ? message.groupedId : undefined;\n const nextDocumentGroupId = nextMessage && !isAlbum(nextMessage) ? nextMessage.groupedId : undefined;\n\n const position = {\n isFirstInGroup: messageIndex === 0,\n isLastInGroup: messageIndex === senderGroup.length - 1,\n isFirstInDocumentGroup: Boolean(documentGroupId && documentGroupId !== currentDocumentGroupId),\n isLastInDocumentGroup: Boolean(documentGroupId && documentGroupId !== nextDocumentGroupId),\n isLastInList: (\n messageIndex === senderGroup.length - 1\n && senderGroupIndex === senderGroupsArray.length - 1\n && dateGroupIndex === dateGroupsArray.length - 1\n ),\n };\n\n currentDocumentGroupId = documentGroupId;\n\n const originalId = getMessageOriginalId(message);\n // Scheduled messages can have local IDs in the middle of the list,\n // and keys should be ordered, so we prefix it with a date.\n // However, this may lead to issues if server date is not synchronized with the local one.\n const key = type !== 'scheduled' ? originalId : `${message.date}_${originalId}`;\n\n return compact([\n message.id === memoFirstUnreadIdRef.current ? unreadDivider : undefined,\n <Message\n key={key}\n message={message}\n observeIntersectionForBottom={observeIntersectionForReading}\n observeIntersectionForMedia={observeIntersectionForMedia}\n observeIntersectionForAnimatedStickers={observeIntersectionForAnimatedStickers}\n album={album}\n noAvatars={noAvatars}\n withAvatar={position.isLastInGroup && withUsers && !isOwn && !(message.id === threadTopMessageId)}\n withSenderName={position.isFirstInGroup && withUsers && !isOwn}\n threadId={threadId}\n messageListType={type}\n noComments={hasLinkedChat === false}\n appearanceOrder={messageCountToAnimate - ++appearanceIndex}\n isFirstInGroup={position.isFirstInGroup}\n isLastInGroup={position.isLastInGroup}\n isFirstInDocumentGroup={position.isFirstInDocumentGroup}\n isLastInDocumentGroup={position.isLastInDocumentGroup}\n isLastInList={position.isLastInList}\n />,\n message.id === threadTopMessageId && (\n <div className=\"local-action-message\" key=\"discussion-started\">\n <span>{lang('DiscussionStarted')}</span>\n </div>\n ),\n ]);\n }));\n });\n\n return (\n <div\n className=\"message-date-group\"\n key={dateGroup.datetime}\n onMouseDown={preventMessageInputBlur}\n teactFastList\n >\n <div\n className={buildClassName('sticky-date', !isSchedule && 'interactive')}\n key=\"date-header\"\n onMouseDown={preventMessageInputBlur}\n onClick={!isSchedule ? () => openHistoryCalendar({ selectedAt: dateGroup.datetime }) : undefined}\n >\n <span dir=\"auto\">\n {isSchedule && dateGroup.originalDate === SCHEDULED_WHEN_ONLINE && (\n lang('MessageScheduledUntilOnline')\n )}\n {isSchedule && dateGroup.originalDate !== SCHEDULED_WHEN_ONLINE && (\n lang('MessageScheduledOn', formatHumanDate(lang, dateGroup.datetime, undefined, true))\n )}\n {!isSchedule && formatHumanDate(lang, dateGroup.datetime)}\n </span>\n </div>\n {flatten(senderGroups)}\n </div>\n );\n });\n\n return (\n <div className=\"messages-container\" teactFastList>\n <div ref={backwardsTriggerRef} key=\"backwards-trigger\" className=\"backwards-trigger\" />\n {flatten(dateGroups)}\n <div\n ref={forwardsTriggerRef}\n key=\"forwards-trigger\"\n className=\"forwards-trigger\"\n />\n <div\n ref={fabTriggerRef}\n key=\"fab-trigger\"\n className=\"fab-trigger\"\n />\n </div>\n );\n};\n\nexport default memo(MessageListContent);\n","import { RefObject } from 'react';\nimport { getDispatch } from '../../../lib/teact/teactn';\nimport { useCallback, useMemo, useRef } from '../../../lib/teact/teact';\n\nimport { LoadMoreDirection } from '../../../types';\nimport { MessageListType } from '../../../global/types';\n\nimport { debounce } from '../../../util/schedulers';\nimport { useIntersectionObserver, useOnIntersect } from '../../../hooks/useIntersectionObserver';\nimport { MESSAGE_LIST_SENSITIVE_AREA } from '../../../config';\nimport resetScroll from '../../../util/resetScroll';\nimport useOnChange from '../../../hooks/useOnChange';\n\nconst FAB_THRESHOLD = 50;\nconst TOOLS_FREEZE_TIMEOUT = 100;\n\nexport default function useScrollHooks(\n type: MessageListType,\n containerRef: RefObject<HTMLDivElement>,\n messageIds: number[],\n isViewportNewest: boolean,\n isUnread: boolean,\n onFabToggle: AnyToVoidFunction,\n onNotchToggle: AnyToVoidFunction,\n) {\n const { loadViewportMessages } = getDispatch();\n\n const [loadMoreBackwards, loadMoreForwards] = useMemo(\n () => (type === 'thread' ? [\n debounce(() => loadViewportMessages({ direction: LoadMoreDirection.Backwards }), 1000, true, false),\n debounce(() => loadViewportMessages({ direction: LoadMoreDirection.Forwards }), 1000, true, false),\n ] : []),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [loadViewportMessages, messageIds],\n );\n\n // eslint-disable-next-line no-null/no-null\n const backwardsTriggerRef = useRef<HTMLDivElement>(null);\n // eslint-disable-next-line no-null/no-null\n const forwardsTriggerRef = useRef<HTMLDivElement>(null);\n // eslint-disable-next-line no-null/no-null\n const fabTriggerRef = useRef<HTMLDivElement>(null);\n\n const toggleScrollTools = useCallback(() => {\n if (!messageIds || !messageIds.length) {\n onFabToggle(false);\n onNotchToggle(false);\n return;\n }\n\n if (!isViewportNewest) {\n onFabToggle(true);\n onNotchToggle(true);\n return;\n }\n\n const { offsetHeight, scrollHeight, scrollTop } = containerRef.current!;\n const scrollBottom = scrollHeight - scrollTop - offsetHeight;\n const isNearBottom = scrollBottom <= FAB_THRESHOLD;\n const isAtBottom = scrollBottom <= 0;\n\n onFabToggle(isUnread ? !isAtBottom : !isNearBottom);\n onNotchToggle(!isAtBottom);\n }, [messageIds, isViewportNewest, containerRef, onFabToggle, isUnread, onNotchToggle]);\n\n const {\n observe: observeIntersection,\n } = useIntersectionObserver({\n rootRef: containerRef,\n margin: MESSAGE_LIST_SENSITIVE_AREA,\n }, (entries) => {\n if (!loadMoreForwards || !loadMoreBackwards) {\n return;\n }\n\n const triggerEntry = entries.find(({ isIntersecting }) => isIntersecting);\n if (!triggerEntry) {\n return;\n }\n\n const { target } = triggerEntry;\n\n if (target.className === 'backwards-trigger') {\n resetScroll(containerRef.current!);\n loadMoreBackwards();\n } else if (target.className === 'forwards-trigger') {\n resetScroll(containerRef.current!);\n loadMoreForwards();\n }\n });\n\n useOnIntersect(backwardsTriggerRef, observeIntersection);\n useOnIntersect(forwardsTriggerRef, observeIntersection);\n\n const {\n observe: observeIntersectionForFab,\n freeze: freezeForFab,\n unfreeze: unfreezeForFab,\n } = useIntersectionObserver({\n rootRef: containerRef,\n margin: FAB_THRESHOLD,\n }, toggleScrollTools);\n\n useOnIntersect(fabTriggerRef, observeIntersectionForFab);\n\n const {\n observe: observeIntersectionForNotch,\n freeze: freezeForNotch,\n unfreeze: unfreezeForNotch,\n } = useIntersectionObserver({\n rootRef: containerRef,\n }, toggleScrollTools);\n\n useOnIntersect(fabTriggerRef, observeIntersectionForNotch);\n\n // Workaround for FAB and notch flickering with tall incoming message\n useOnChange(() => {\n freezeForFab();\n freezeForNotch();\n\n setTimeout(() => {\n unfreezeForNotch();\n unfreezeForFab();\n }, TOOLS_FREEZE_TIMEOUT);\n }, [messageIds]);\n\n return { backwardsTriggerRef, forwardsTriggerRef, fabTriggerRef };\n}\n","import React, {\n FC, memo, useCallback, useEffect, useMemo, useRef, useState,\n} from '../../lib/teact/teact';\nimport { getGlobal, withGlobal } from '../../lib/teact/teactn';\n\nimport { ApiMessage, ApiRestrictionReason, MAIN_THREAD_ID } from '../../api/types';\nimport { GlobalActions, MessageListType } from '../../global/types';\nimport { LoadMoreDirection } from '../../types';\n\nimport { ANIMATION_END_DELAY, MESSAGE_LIST_SLICE } from '../../config';\nimport {\n selectChatMessages,\n selectIsViewportNewest,\n selectFirstUnreadId,\n selectFocusedMessageId,\n selectChat,\n selectIsInSelectMode,\n selectIsChatWithSelf,\n selectChatBot,\n selectIsChatBotNotStarted,\n selectScrollOffset,\n selectThreadTopMessageId,\n selectFirstMessageId,\n selectScheduledMessages,\n selectCurrentMessageIds,\n} from '../../modules/selectors';\nimport { isChatChannel, isChatPrivate } from '../../modules/helpers';\nimport { orderBy, pick } from '../../util/iteratees';\nimport { fastRaf, debounce, onTickEnd } from '../../util/schedulers';\nimport useLayoutEffectWithPrevDeps from '../../hooks/useLayoutEffectWithPrevDeps';\nimport useEffectWithPrevDeps from '../../hooks/useEffectWithPrevDeps';\nimport buildClassName from '../../util/buildClassName';\nimport { groupMessages } from './helpers/groupMessages';\nimport { preventMessageInputBlur } from './helpers/preventMessageInputBlur';\nimport useOnChange from '../../hooks/useOnChange';\nimport useStickyDates from './hooks/useStickyDates';\nimport { dispatchHeavyAnimationEvent } from '../../hooks/useHeavyAnimationCheck';\nimport resetScroll from '../../util/resetScroll';\nimport fastSmoothScroll, { isAnimatingScroll } from '../../util/fastSmoothScroll';\nimport renderText from '../common/helpers/renderText';\nimport useLang from '../../hooks/useLang';\nimport useWindowSize from '../../hooks/useWindowSize';\n\nimport Loading from '../ui/Loading';\nimport MessageListContent from './MessageListContent';\n\nimport './MessageList.scss';\n\ntype OwnProps = {\n chatId: number;\n threadId: number;\n type: MessageListType;\n canPost: boolean;\n isReady: boolean;\n onFabToggle: (shouldShow: boolean) => void;\n onNotchToggle: (shouldShow: boolean) => void;\n hasTools?: boolean;\n};\n\ntype StateProps = {\n isChatLoaded?: boolean;\n isChannelChat?: boolean;\n isChatWithSelf?: boolean;\n messageIds?: number[];\n messagesById?: Record<number, ApiMessage>;\n firstUnreadId?: number;\n isViewportNewest?: boolean;\n isRestricted?: boolean;\n restrictionReason?: ApiRestrictionReason;\n focusingId?: number;\n hasFocusHighlight?: boolean;\n isSelectModeActive?: boolean;\n animationLevel?: number;\n lastMessage?: ApiMessage;\n botDescription?: string;\n threadTopMessageId?: number;\n threadFirstMessageId?: number;\n hasLinkedChat?: boolean;\n};\n\ntype DispatchProps = Pick<GlobalActions, 'loadViewportMessages' | 'setScrollOffset' | 'openHistoryCalendar'>;\n\nconst BOTTOM_THRESHOLD = 100;\nconst UNREAD_DIVIDER_TOP = 10;\nconst UNREAD_DIVIDER_TOP_WITH_TOOLS = 60;\nconst SCROLL_DEBOUNCE = 200;\nconst FOCUSING_DURATION = 1000;\nconst BOTTOM_FOCUS_MARGIN = 20;\nconst SELECT_MODE_ANIMATION_DURATION = 200;\nconst UNREAD_DIVIDER_CLASS = 'unread-divider';\n\nconst runDebouncedForScroll = debounce((cb) => cb(), SCROLL_DEBOUNCE, false);\n\nconst MessageList: FC<OwnProps & StateProps & DispatchProps> = ({\n chatId,\n threadId,\n type,\n hasTools,\n onFabToggle,\n onNotchToggle,\n isChatLoaded,\n isChannelChat,\n canPost,\n isReady,\n isChatWithSelf,\n messageIds,\n messagesById,\n firstUnreadId,\n isViewportNewest,\n threadFirstMessageId,\n isRestricted,\n restrictionReason,\n focusingId,\n hasFocusHighlight,\n isSelectModeActive,\n loadViewportMessages,\n setScrollOffset,\n lastMessage,\n botDescription,\n threadTopMessageId,\n hasLinkedChat,\n openHistoryCalendar,\n}) => {\n // eslint-disable-next-line no-null/no-null\n const containerRef = useRef<HTMLDivElement>(null);\n\n // We update local cached `scrollOffsetRef` when opening chat.\n // Then we update global version every second on scrolling.\n const scrollOffsetRef = useRef<number>((type === 'thread' && selectScrollOffset(getGlobal(), chatId, threadId)) || 0);\n const anchorIdRef = useRef<string>();\n const anchorTopRef = useRef<number>();\n const listItemElementsRef = useRef<HTMLDivElement[]>();\n const memoUnreadDividerBeforeIdRef = useRef<number | undefined>();\n // Updated every time (to be used from intersection callback closure)\n const memoFirstUnreadIdRef = useRef<number>();\n const memoFocusingIdRef = useRef<number>();\n const isScrollTopJustUpdatedRef = useRef(false);\n const shouldAnimateAppearanceRef = useRef(Boolean(lastMessage));\n\n const [containerHeight, setContainerHeight] = useState<number | undefined>();\n\n const areMessagesLoaded = Boolean(messageIds);\n\n useOnChange(() => {\n // We only need it first time when message list appears\n if (areMessagesLoaded) {\n onTickEnd(() => {\n shouldAnimateAppearanceRef.current = false;\n });\n }\n }, [areMessagesLoaded]);\n\n useOnChange(() => {\n memoFirstUnreadIdRef.current = firstUnreadId;\n\n // Updated only once (to preserve divider even after messages are read)\n if (!memoUnreadDividerBeforeIdRef.current) {\n memoUnreadDividerBeforeIdRef.current = firstUnreadId;\n }\n }, [firstUnreadId]);\n\n useOnChange(() => {\n memoFocusingIdRef.current = focusingId;\n }, [focusingId]);\n\n const messageGroups = useMemo(() => {\n if (!messageIds || !messagesById) {\n return undefined;\n }\n\n const viewportIds = threadTopMessageId && (!messageIds[0] || threadFirstMessageId === messageIds[0])\n ? [threadTopMessageId, ...messageIds]\n : messageIds;\n\n if (!viewportIds.length) {\n return undefined;\n }\n\n const listedMessages = viewportIds.map((id) => messagesById[id]).filter(Boolean);\n return groupMessages(orderBy(listedMessages, ['date', 'id']), memoUnreadDividerBeforeIdRef.current);\n }, [messageIds, messagesById, threadFirstMessageId, threadTopMessageId]);\n\n const loadMoreAround = useMemo(() => {\n if (type !== 'thread') {\n return undefined;\n }\n\n return debounce(() => loadViewportMessages({ direction: LoadMoreDirection.Around }), 1000, true, false);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [loadViewportMessages, messageIds]);\n\n const { isScrolled, updateStickyDates } = useStickyDates();\n\n const handleScroll = useCallback(() => {\n if (isScrollTopJustUpdatedRef.current) {\n isScrollTopJustUpdatedRef.current = false;\n return;\n }\n\n const container = containerRef.current!;\n\n if (!memoFocusingIdRef.current) {\n updateStickyDates(container, hasTools);\n }\n\n runDebouncedForScroll(() => {\n fastRaf(() => {\n if (!container.parentElement) {\n return;\n }\n\n scrollOffsetRef.current = container.scrollHeight - container.scrollTop;\n\n if (type === 'thread') {\n setScrollOffset({ chatId, threadId, scrollOffset: scrollOffsetRef.current });\n }\n });\n });\n }, [updateStickyDates, hasTools, type, setScrollOffset, chatId, threadId]);\n\n // Container resize observer (caused by Composer reply/webpage panels)\n useEffect(() => {\n if (!('ResizeObserver' in window) || process.env.APP_ENV === 'perf') {\n return undefined;\n }\n\n const observer = new ResizeObserver(([entry]) => {\n // During animation\n if (!(entry.target as HTMLDivElement).offsetParent) {\n return;\n }\n\n setContainerHeight(entry.contentRect.height);\n });\n\n observer.observe(containerRef.current!);\n\n return () => {\n observer.disconnect();\n };\n }, []);\n\n // Memorize height for scroll animation\n const { height: windowHeight } = useWindowSize();\n\n useEffect(() => {\n if (isReady) {\n containerRef.current!.dataset.normalHeight = String(containerRef.current!.offsetHeight);\n }\n }, [windowHeight, isReady]);\n\n // Initial message loading\n useEffect(() => {\n if (!loadMoreAround || !isChatLoaded || isRestricted || focusingId) {\n return;\n }\n\n const container = containerRef.current!;\n\n if (!messageIds || (\n messageIds.length < MESSAGE_LIST_SLICE / 2\n && (container.firstElementChild as HTMLDivElement).clientHeight <= container.offsetHeight\n )) {\n loadMoreAround();\n }\n }, [isChatLoaded, messageIds, loadMoreAround, focusingId, isRestricted]);\n\n // Remember scroll position before repositioning it\n useOnChange(() => {\n if (!messageIds || !listItemElementsRef.current || !isReady) {\n return;\n }\n\n const preservedItemElements = listItemElementsRef.current\n .filter((element) => messageIds.includes(Number(element.dataset.messageId)));\n\n // We avoid the very first item as it may be a partly-loaded album\n // and also because it may be removed when messages limit is reached\n const anchor = preservedItemElements[1] || preservedItemElements[0];\n if (!anchor) {\n return;\n }\n\n anchorIdRef.current = anchor.id;\n anchorTopRef.current = anchor.getBoundingClientRect().top;\n // This should match deps for `useLayoutEffectWithPrevDeps` below\n }, [messageIds, isViewportNewest, containerHeight, hasTools, isReady]);\n\n // Handles updated message list, takes care of scroll repositioning\n useLayoutEffectWithPrevDeps(([\n prevMessageIds, prevIsViewportNewest, prevContainerHeight,\n ]: [\n typeof messageIds, typeof isViewportNewest, typeof containerHeight\n ]) => {\n const container = containerRef.current!;\n listItemElementsRef.current = Array.from(container.querySelectorAll<HTMLDivElement>('.message-list-item'));\n\n // During animation\n if (!container.offsetParent) {\n return;\n }\n\n // Add extra height when few messages to allow smooth scroll animation. Uses assumption that `parentElement`\n // is a Transition slide and its CSS class can not be reset in a declarative way.\n const shouldForceScroll = (\n isViewportNewest\n && (messageIds && messageIds.length < MESSAGE_LIST_SLICE / 2)\n && !container.parentElement!.classList.contains('force-messages-scroll')\n && (container.firstElementChild as HTMLDivElement)!.clientHeight <= container.offsetHeight * 2\n );\n\n if (shouldForceScroll) {\n container.parentElement!.classList.add('force-messages-scroll');\n\n setTimeout(() => {\n if (container.parentElement) {\n container.parentElement.classList.remove('force-messages-scroll');\n }\n }, FOCUSING_DURATION);\n }\n\n const { scrollTop, scrollHeight, offsetHeight } = container;\n const scrollOffset = scrollOffsetRef.current!;\n const lastItemElement = listItemElementsRef.current[listItemElementsRef.current.length - 1];\n\n // If two messages come at once (e.g. via Quiz Bot) then the first message will update `scrollOffset`\n // right away (before animation) which creates inconsistency until the animation completes.\n // To workaround that, we calculate `isAtBottom` with a \"buffer\" of the latest message height (this is approximate).\n const lastItemHeight = lastItemElement ? lastItemElement.offsetHeight : 0;\n const isAtBottom = isViewportNewest && prevIsViewportNewest && (\n scrollOffset - (prevContainerHeight || offsetHeight) - lastItemHeight <= BOTTOM_THRESHOLD\n );\n\n let newScrollTop!: number;\n\n const hasFirstMessageChanged = messageIds && prevMessageIds && messageIds[0] !== prevMessageIds[0];\n const hasLastMessageChanged = (\n messageIds && prevMessageIds && messageIds[messageIds.length - 1] !== prevMessageIds[prevMessageIds.length - 1]\n );\n const isAlreadyFocusing = messageIds && memoFocusingIdRef.current === messageIds[messageIds.length - 1];\n\n if (isAtBottom && hasLastMessageChanged && !hasFirstMessageChanged && !isAlreadyFocusing) {\n if (lastItemElement) {\n fastRaf(() => {\n fastSmoothScroll(\n container,\n lastItemElement,\n 'end',\n BOTTOM_FOCUS_MARGIN,\n undefined,\n undefined,\n undefined,\n true,\n );\n });\n }\n\n newScrollTop = scrollHeight - offsetHeight;\n scrollOffsetRef.current = Math.max(scrollHeight - newScrollTop, offsetHeight);\n\n // Scroll still needs to be restored after container resize\n if (!shouldForceScroll) {\n return;\n }\n }\n\n if (process.env.APP_ENV === 'perf') {\n // eslint-disable-next-line no-console\n console.time('scrollTop');\n }\n\n const isResized = prevContainerHeight !== undefined && prevContainerHeight !== containerHeight;\n const anchor = anchorIdRef.current && container.querySelector(`#${anchorIdRef.current}`);\n const unreadDivider = (\n !anchor\n && memoUnreadDividerBeforeIdRef.current\n && container.querySelector<HTMLDivElement>(`.${UNREAD_DIVIDER_CLASS}`)\n );\n\n if (isAtBottom && isResized) {\n if (isAnimatingScroll()) {\n return;\n }\n\n newScrollTop = scrollHeight - offsetHeight;\n } else if (anchor) {\n const newAnchorTop = anchor.getBoundingClientRect().top;\n newScrollTop = scrollTop + (newAnchorTop - (anchorTopRef.current || 0));\n } else if (unreadDivider) {\n newScrollTop = Math.min(\n unreadDivider.offsetTop - (hasTools ? UNREAD_DIVIDER_TOP_WITH_TOOLS : UNREAD_DIVIDER_TOP),\n scrollHeight - scrollOffset,\n );\n } else {\n newScrollTop = scrollHeight - scrollOffset;\n }\n\n resetScroll(container, newScrollTop);\n\n if (!memoFocusingIdRef.current) {\n isScrollTopJustUpdatedRef.current = true;\n fastRaf(() => {\n isScrollTopJustUpdatedRef.current = false;\n });\n }\n\n scrollOffsetRef.current = Math.max(scrollHeight - newScrollTop, offsetHeight);\n\n if (process.env.APP_ENV === 'perf') {\n // eslint-disable-next-line no-console\n console.timeEnd('scrollTop');\n }\n // This should match deps for `useOnChange` above\n }, [messageIds, isViewportNewest, containerHeight, hasTools]);\n\n useEffectWithPrevDeps(([prevIsSelectModeActive]) => {\n if (prevIsSelectModeActive !== undefined) {\n dispatchHeavyAnimationEvent(SELECT_MODE_ANIMATION_DURATION + ANIMATION_END_DELAY);\n }\n }, [isSelectModeActive]);\n\n const lang = useLang();\n\n const isPrivate = Boolean(chatId && isChatPrivate(chatId));\n const withUsers = Boolean((!isPrivate && !isChannelChat) || isChatWithSelf);\n const noAvatars = Boolean(!withUsers || isChannelChat);\n\n const className = buildClassName(\n 'MessageList custom-scroll',\n noAvatars && 'no-avatars',\n !canPost && 'no-composer',\n type === 'pinned' && 'type-pinned',\n hasFocusHighlight && 'has-focus-highlight',\n isSelectModeActive && 'select-mode-active',\n isScrolled && 'scrolled',\n !isReady && 'is-animating',\n );\n\n return (\n <div\n ref={containerRef}\n className={className}\n onScroll={handleScroll}\n onMouseDown={preventMessageInputBlur}\n >\n {isRestricted ? (\n <div className=\"empty\">\n <span>\n {restrictionReason ? restrictionReason.text : `This is a private ${isChannelChat ? 'channel' : 'chat'}`}\n </span>\n </div>\n ) : botDescription ? (\n <div className=\"empty rich\"><span>{renderText(lang(botDescription), ['br', 'emoji', 'links'])}</span></div>\n ) : messageIds && !messageGroups ? (\n <div className=\"empty\"><span>{lang('NoMessages')}</span></div>\n ) : ((messageIds && messageGroups) || lastMessage) ? (\n <MessageListContent\n messageIds={messageIds || [lastMessage!.id]}\n messageGroups={messageGroups || groupMessages([lastMessage!])}\n isViewportNewest={Boolean(isViewportNewest)}\n isUnread={Boolean(firstUnreadId)}\n withUsers={withUsers}\n noAvatars={noAvatars}\n containerRef={containerRef}\n anchorIdRef={anchorIdRef}\n memoFirstUnreadIdRef={memoUnreadDividerBeforeIdRef}\n threadId={threadId}\n type={type}\n threadTopMessageId={threadTopMessageId}\n hasLinkedChat={hasLinkedChat}\n isSchedule={messageGroups ? type === 'scheduled' : false}\n noAppearanceAnimation={!messageGroups || !shouldAnimateAppearanceRef.current}\n onFabToggle={onFabToggle}\n onNotchToggle={onNotchToggle}\n openHistoryCalendar={openHistoryCalendar}\n />\n ) : (\n <Loading color=\"white\" />\n )}\n </div>\n );\n};\n\nexport default memo(withGlobal<OwnProps>(\n (global, { chatId, threadId, type }): StateProps => {\n const chat = selectChat(global, chatId);\n if (!chat) {\n return {};\n }\n\n const messageIds = selectCurrentMessageIds(global, chatId, threadId, type);\n const messagesById = type === 'scheduled'\n ? selectScheduledMessages(global, chatId)\n : selectChatMessages(global, chatId);\n const threadTopMessageId = selectThreadTopMessageId(global, chatId, threadId);\n\n if (\n threadId !== MAIN_THREAD_ID\n && !(messagesById && threadTopMessageId && messagesById[threadTopMessageId])\n ) {\n return {};\n }\n\n const { isRestricted, restrictionReason, lastMessage } = chat;\n const focusingId = selectFocusedMessageId(global, chatId);\n const hasFocusHighlight = focusingId ? !global.focusedMessage!.noHighlight : undefined;\n\n const withLastMessageWhenPreloading = (\n threadId === MAIN_THREAD_ID\n && !messageIds && !chat.unreadCount && !focusingId && lastMessage && !lastMessage.groupedId\n );\n\n let botDescription: string | undefined;\n if (selectIsChatBotNotStarted(global, chatId)) {\n const chatBot = selectChatBot(global, chatId)!;\n if (chatBot.fullInfo) {\n botDescription = chatBot.fullInfo.botDescription || 'NoMessages';\n } else {\n botDescription = 'Updating bot info...';\n }\n }\n\n return {\n isChatLoaded: true,\n isRestricted,\n restrictionReason,\n isChannelChat: isChatChannel(chat),\n isChatWithSelf: selectIsChatWithSelf(global, chatId),\n messageIds,\n messagesById,\n firstUnreadId: selectFirstUnreadId(global, chatId, threadId),\n isViewportNewest: type !== 'thread' || selectIsViewportNewest(global, chatId, threadId),\n threadFirstMessageId: selectFirstMessageId(global, chatId, threadId),\n focusingId,\n hasFocusHighlight,\n isSelectModeActive: selectIsInSelectMode(global),\n botDescription,\n threadTopMessageId,\n hasLinkedChat: chat.fullInfo && ('linkedChatId' in chat.fullInfo)\n ? Boolean(chat.fullInfo.linkedChatId)\n : undefined,\n ...(withLastMessageWhenPreloading && { lastMessage }),\n };\n },\n (setGlobal, actions): DispatchProps => pick(actions, [\n 'loadViewportMessages',\n 'setScrollOffset',\n 'openHistoryCalendar',\n ]),\n)(MessageList));\n","import React, {\n FC, useCallback, memo, useRef,\n} from '../../lib/teact/teact';\nimport { withGlobal } from '../../lib/teact/teactn';\n\nimport { GlobalActions, MessageListType } from '../../global/types';\nimport { MAIN_THREAD_ID } from '../../api/types';\n\nimport { selectChat, selectCurrentMessageList } from '../../modules/selectors';\nimport { formatIntegerCompact } from '../../util/textFormat';\nimport buildClassName from '../../util/buildClassName';\nimport { pick } from '../../util/iteratees';\nimport fastSmoothScroll from '../../util/fastSmoothScroll';\nimport useLang from '../../hooks/useLang';\n\nimport Button from '../ui/Button';\n\nimport './ScrollDownButton.scss';\n\ntype OwnProps = {\n isShown: boolean;\n canPost?: boolean;\n};\n\ntype StateProps = {\n messageListType?: MessageListType;\n unreadCount?: number;\n};\n\ntype DispatchProps = Pick<GlobalActions, 'focusNextReply'>;\n\nconst FOCUS_MARGIN = 20;\n\nconst ScrollDownButton: FC<OwnProps & StateProps & DispatchProps> = ({\n isShown,\n canPost,\n messageListType,\n unreadCount,\n focusNextReply,\n}) => {\n const lang = useLang();\n // eslint-disable-next-line no-null/no-null\n const elementRef = useRef<HTMLDivElement>(null);\n\n const handleClick = useCallback(() => {\n if (!isShown) {\n return;\n }\n\n if (messageListType === 'thread') {\n focusNextReply();\n } else {\n const messagesContainer = elementRef.current!.parentElement!.querySelector<HTMLDivElement>('.MessageList')!;\n const messageElements = messagesContainer.querySelectorAll<HTMLDivElement>('.message-list-item');\n const lastMessageElement = messageElements[messageElements.length - 1];\n if (!lastMessageElement) {\n return;\n }\n\n fastSmoothScroll(messagesContainer, lastMessageElement, 'end', FOCUS_MARGIN);\n }\n }, [isShown, messageListType, focusNextReply]);\n\n const fabClassName = buildClassName(\n 'ScrollDownButton',\n isShown && 'revealed',\n !canPost && 'no-composer',\n );\n\n return (\n <div ref={elementRef} className={fabClassName}>\n <div className=\"ScrollDownButton-inner\">\n <Button\n color=\"secondary\"\n round\n onClick={handleClick}\n ariaLabel={lang('AccDescrPageDown')}\n >\n <i className=\"icon-arrow-down\" />\n </Button>\n {Boolean(unreadCount) && (\n <div className=\"unread-count\">{formatIntegerCompact(unreadCount!)}</div>\n )}\n </div>\n </div>\n );\n};\n\nexport default memo(withGlobal<OwnProps>(\n (global): StateProps => {\n const currentMessageList = selectCurrentMessageList(global);\n if (!currentMessageList) {\n return {};\n }\n\n const { chatId, threadId, type: messageListType } = currentMessageList;\n const chat = selectChat(global, chatId);\n\n return {\n messageListType,\n unreadCount: chat && threadId === MAIN_THREAD_ID && messageListType === 'thread' ? chat.unreadCount : undefined,\n };\n },\n (setGlobal, actions): DispatchProps => pick(actions, ['focusNextReply']),\n)(ScrollDownButton));\n","import { ApiAttachment } from '../../../../api/types';\nimport { preloadImage, preloadVideo, createPosterForVideo } from '../../../../util/files';\n\nconst MAX_QUICK_VIDEO_SIZE = 10 * 1024 ** 2; // 10 MB\nconst MAX_QUICK_IMG_SIZE = 1280; // px\n\nexport default async function buildAttachment(\n filename: string, blob: Blob, isQuick: boolean, options?: Partial<ApiAttachment>,\n): Promise<ApiAttachment> {\n const blobUrl = URL.createObjectURL(blob);\n const { type: mimeType, size } = blob;\n let quick;\n let previewBlobUrl;\n\n if (mimeType.startsWith('image/')) {\n if (isQuick) {\n const img = await preloadImage(blobUrl);\n const { width, height } = img;\n\n if (width > MAX_QUICK_IMG_SIZE || height > MAX_QUICK_IMG_SIZE || mimeType !== 'image/jpeg') {\n const newBlob = await squeezeImage(img);\n if (newBlob) {\n URL.revokeObjectURL(blobUrl);\n return buildAttachment(filename, newBlob, true, options);\n } else {\n return buildAttachment(filename, blob, false, options);\n }\n }\n\n quick = { width, height };\n } else {\n previewBlobUrl = blobUrl;\n }\n } else if (mimeType.startsWith('video/')) {\n // Videos < 10 MB are always sent in quick mode (in other clients).\n // Quick mode for videos > 10 MB is not supported until client-side video squeezing is implemented.\n if (size < MAX_QUICK_VIDEO_SIZE) {\n const { videoWidth: width, videoHeight: height, duration } = await preloadVideo(blobUrl);\n quick = { width, height, duration };\n }\n\n previewBlobUrl = await createPosterForVideo(blobUrl);\n }\n\n return {\n blobUrl,\n filename,\n mimeType,\n size,\n quick,\n previewBlobUrl,\n ...options,\n };\n}\n\nfunction squeezeImage(img: HTMLImageElement): Promise<Blob | null> {\n return new Promise((resolve) => {\n const canvas = document.createElement('canvas');\n const ctx = canvas.getContext('2d')!;\n\n let { width, height } = img;\n\n if (width > MAX_QUICK_IMG_SIZE || height > MAX_QUICK_IMG_SIZE) {\n if (width >= height) {\n height *= MAX_QUICK_IMG_SIZE / width;\n width = MAX_QUICK_IMG_SIZE;\n } else {\n width *= MAX_QUICK_IMG_SIZE / height;\n height = MAX_QUICK_IMG_SIZE;\n }\n }\n\n canvas.width = width;\n canvas.height = height;\n\n ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, width, height);\n canvas.toBlob(resolve, 'image/jpeg', 100);\n });\n}\n","import { IS_IOS } from '../../../../util/environment';\n\nlet resetInput: HTMLInputElement;\n\nif (IS_IOS) {\n resetInput = document.createElement('input');\n resetInput.classList.add('for-ios-autocapitalization-fix');\n document.body.appendChild(resetInput);\n}\n\n// https://stackoverflow.com/a/55652503\nexport default function applyIosAutoCapitalizationFix(inputEl: HTMLElement) {\n resetInput.focus();\n inputEl.focus();\n}\n","export default __webpack_public_path__ + \"c0155344d336103c2b6a0b28cc510750.js\";","// @ts-ignore\nimport encoderPath from 'file-loader!opus-recorder/dist/encoderWorker.min';\n\nexport type Result = { blob: Blob; duration: number; waveform: number[] };\n\ninterface OpusRecorder extends Omit<MediaRecorder, 'start' | 'ondataavailable'> {\n new(options: AnyLiteral): OpusRecorder;\n\n start(stream?: MediaStreamAudioSourceNode): void;\n\n sourceNode: MediaStreamAudioSourceNode;\n\n ondataavailable: (typedArray: Uint8Array) => void;\n}\n\nconst MIN_RECORDING_TIME = 1000;\nconst POLYFILL_OPTIONS = { encoderPath, reuseWorker: true };\nconst BLOB_PARAMS = { type: 'audio/ogg' };\nconst FFT_SIZE = 64;\nconst MIN_VOLUME = 0.1;\n\nlet opusRecorderPromise: Promise<{ default: OpusRecorder }>;\nlet OpusRecorder: OpusRecorder;\nlet mediaRecorder: OpusRecorder;\n\nexport async function init() {\n if (!opusRecorderPromise) {\n // @ts-ignore\n opusRecorderPromise = import('opus-recorder');\n OpusRecorder = (await opusRecorderPromise).default;\n mediaRecorder = new OpusRecorder(POLYFILL_OPTIONS);\n }\n\n return opusRecorderPromise;\n}\n\nexport async function start(analyzerCallback: Function) {\n await startMediaRecorder();\n\n const startedAt = Date.now();\n let pausedAt: number;\n const chunks: Uint8Array[] = [];\n const waveform: number[] = [];\n\n mediaRecorder.ondataavailable = (typedArray) => {\n chunks.push(typedArray);\n };\n\n const releaseAnalyzer = subscribeToAnalyzer(mediaRecorder, (volume: number) => {\n waveform.push(volume * 255);\n analyzerCallback(volume);\n });\n\n return {\n stop: () => new Promise<Result>((resolve, reject) => {\n mediaRecorder.onstop = () => {\n resolve({\n blob: new Blob(chunks, BLOB_PARAMS),\n duration: Math.round(((pausedAt || Date.now()) - startedAt) / 1000),\n waveform,\n });\n };\n mediaRecorder.onerror = reject;\n\n const delayStop = Math.max(0, startedAt + MIN_RECORDING_TIME - Date.now());\n setTimeout(() => {\n mediaRecorder.stop();\n releaseAnalyzer();\n }, delayStop);\n }),\n pause: () => {\n const delayStop = Math.max(0, startedAt + MIN_RECORDING_TIME - Date.now());\n setTimeout(() => {\n mediaRecorder.pause();\n pausedAt = Date.now();\n releaseAnalyzer();\n }, delayStop);\n },\n };\n}\n\nasync function startMediaRecorder() {\n await init();\n await mediaRecorder.start();\n}\n\nfunction subscribeToAnalyzer(recorder: OpusRecorder, cb: Function) {\n const source = recorder.sourceNode;\n const analyser = source.context.createAnalyser();\n analyser.fftSize = FFT_SIZE;\n source.connect(analyser);\n\n const dataLength = analyser.frequencyBinCount;\n const dataArray = new Uint8Array(dataLength);\n let isDestroyed = false;\n\n function tick() {\n if (isDestroyed) {\n return;\n }\n\n analyser.getByteFrequencyData(dataArray);\n\n const sum = dataArray.reduce((acc, current) => acc + current, 0);\n const mean = (sum / dataLength);\n const volume = mean / 255;\n\n cb(volume < MIN_VOLUME ? 0 : volume);\n\n requestAnimationFrame(tick);\n }\n\n tick();\n\n return () => {\n isDestroyed = true;\n };\n}\n","import { StateHookSetter, useEffect } from '../../../../lib/teact/teact';\nimport { ApiAttachment, ApiMessage } from '../../../../api/types';\n\nimport buildAttachment from '../helpers/buildAttachment';\nimport { EDITABLE_INPUT_ID, EDITABLE_INPUT_MODAL_ID } from '../../../../config';\n\nconst CLIPBOARD_ACCEPTED_TYPES = ['image/png', 'image/jpeg', 'image/gif'];\nconst MAX_MESSAGE_LENGTH = 4096;\n\nexport default (\n insertTextAndUpdateCursor: (text: string, inputId?: string) => void,\n setAttachments: StateHookSetter<ApiAttachment[]>,\n editedMessage: ApiMessage | undefined,\n) => {\n useEffect(() => {\n async function handlePaste(e: ClipboardEvent) {\n if (!e.clipboardData) {\n return;\n }\n\n const input = document.activeElement;\n if (input && ![EDITABLE_INPUT_ID, EDITABLE_INPUT_MODAL_ID].includes(input.id)) {\n return;\n }\n\n const { items } = e.clipboardData;\n const media = Array.from(items).find((item) => CLIPBOARD_ACCEPTED_TYPES.includes(item.type));\n const file = media && media.getAsFile();\n const pastedText = e.clipboardData.getData('text').substring(0, MAX_MESSAGE_LENGTH);\n\n if (!file && !pastedText) {\n return;\n }\n\n e.preventDefault();\n\n if (file && !editedMessage) {\n const attachment = await buildAttachment(file.name, file, true);\n setAttachments((attachments) => [\n ...attachments,\n attachment,\n ]);\n }\n\n if (pastedText) {\n insertTextAndUpdateCursor(pastedText, input ? input.id : undefined);\n }\n }\n\n document.addEventListener('paste', handlePaste, false);\n\n return () => {\n document.removeEventListener('paste', handlePaste, false);\n };\n }, [insertTextAndUpdateCursor, editedMessage, setAttachments]);\n};\n","import { ApiFormattedText } from '../../../../api/types';\nimport { renderTextWithEntities } from '../../../common/helpers/renderMessageText';\n\nexport default function getMessageTextAsHtml(formattedText?: ApiFormattedText) {\n const { text, entities } = formattedText || {};\n if (!text) {\n return '';\n }\n\n const result = renderTextWithEntities(\n text,\n entities,\n undefined,\n undefined,\n true,\n );\n\n if (Array.isArray(result)) {\n return result.join('');\n }\n\n return result;\n}\n","import { useCallback, useEffect, useMemo } from '../../../../lib/teact/teact';\n\nimport { ApiFormattedText, ApiMessage } from '../../../../api/types';\nimport { GlobalActions } from '../../../../global/types';\n\nimport { DRAFT_DEBOUNCE, EDITABLE_INPUT_ID } from '../../../../config';\nimport usePrevious from '../../../../hooks/usePrevious';\nimport { debounce } from '../../../../util/schedulers';\nimport focusEditableElement from '../../../../util/focusEditableElement';\nimport parseMessageInput from '../helpers/parseMessageInput';\nimport getMessageTextAsHtml from '../helpers/getMessageTextAsHtml';\nimport useBackgroundMode from '../../../../hooks/useBackgroundMode';\nimport useBeforeUnload from '../../../../hooks/useBeforeUnload';\nimport { IS_TOUCH_ENV } from '../../../../util/environment';\n\n// Used to avoid running debounced callbacks when chat changes.\nlet currentChatId: number | undefined;\nlet currentThreadId: number | undefined;\n\nexport default (\n draft: ApiFormattedText | undefined,\n chatId: number,\n threadId: number,\n html: string,\n htmlRef: { current: string },\n setHtml: (html: string) => void,\n editedMessage: ApiMessage | undefined,\n saveDraft: GlobalActions['saveDraft'],\n clearDraft: GlobalActions['clearDraft'],\n) => {\n const updateDraft = useCallback((draftChatId: number, draftThreadId: number) => {\n if (htmlRef.current.length && !editedMessage) {\n saveDraft({ chatId: draftChatId, threadId: draftThreadId, draft: parseMessageInput(htmlRef.current!) });\n } else {\n clearDraft({ chatId: draftChatId, threadId: draftThreadId });\n }\n }, [clearDraft, editedMessage, htmlRef, saveDraft]);\n\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const runDebouncedForSaveDraft = useMemo(() => debounce((cb) => cb(), DRAFT_DEBOUNCE, false), [chatId]);\n\n const prevChatId = usePrevious(chatId);\n const prevThreadId = usePrevious(threadId);\n\n // Save draft on chat change\n useEffect(() => {\n currentChatId = chatId;\n currentThreadId = threadId;\n\n return () => {\n currentChatId = undefined;\n currentThreadId = undefined;\n\n updateDraft(chatId, threadId);\n };\n }, [chatId, threadId, updateDraft]);\n\n // Restore draft on chat change\n useEffect(() => {\n if (chatId === prevChatId && threadId === prevThreadId) {\n return;\n }\n\n if (!draft) {\n return;\n }\n\n setHtml(getMessageTextAsHtml(draft));\n\n if (!IS_TOUCH_ENV) {\n requestAnimationFrame(() => {\n const messageInput = document.getElementById(EDITABLE_INPUT_ID)!;\n focusEditableElement(messageInput, true);\n });\n }\n }, [chatId, threadId, draft, setHtml, updateDraft, prevChatId, prevThreadId]);\n\n // Update draft when input changes\n const prevHtml = usePrevious(html);\n useEffect(() => {\n if (!chatId || !threadId || prevChatId !== chatId || prevThreadId !== threadId || prevHtml === html) {\n return;\n }\n\n if (html.length) {\n runDebouncedForSaveDraft(() => {\n if (currentChatId !== chatId || currentThreadId !== threadId) {\n return;\n }\n\n updateDraft(chatId, threadId);\n });\n } else {\n updateDraft(chatId, threadId);\n }\n }, [chatId, html, prevChatId, prevHtml, prevThreadId, runDebouncedForSaveDraft, threadId, updateDraft]);\n\n const handleBlur = useCallback(() => {\n if (chatId && threadId) {\n updateDraft(chatId, threadId);\n }\n }, [chatId, threadId, updateDraft]);\n\n useBackgroundMode(handleBlur);\n useBeforeUnload(handleBlur);\n};\n","import { useCallback, useEffect } from '../../../../lib/teact/teact';\nimport { getDispatch } from '../../../../lib/teact/teactn';\nimport { InlineBotSettings } from '../../../../types';\nimport useFlag from '../../../../hooks/useFlag';\nimport usePrevious from '../../../../hooks/usePrevious';\n\nconst tempEl = document.createElement('div');\nconst INLINE_BOT_QUERY_REGEXP = /^@([a-z0-9_]{1,32})[\\u00A0\\u0020]+(.*)/i;\nconst HAS_NEW_LINE = /^@([a-z0-9_]{1,32})[\\u00A0\\u0020]+\\n{2,}/i;\n\nexport default function useInlineBotTooltip(\n isAllowed: boolean,\n chatId: number,\n html: string,\n inlineBots?: Record<string, false | InlineBotSettings>,\n) {\n const [isOpen, markIsOpen, unmarkIsOpen] = useFlag();\n const text = getPlainText(html);\n const { queryInlineBot, resetInlineBot } = getDispatch();\n const { username, query, canShowHelp } = parseStartWithUsernameString(text);\n const usernameLowered = username.toLowerCase();\n const prevQuery = usePrevious(query);\n const prevUsername = usePrevious(username);\n const inlineBotData = inlineBots && inlineBots[usernameLowered];\n const {\n id: botId,\n switchPm,\n offset,\n results,\n isGallery,\n help,\n } = inlineBotData || {};\n\n useEffect(() => {\n if (prevQuery !== query) {\n unmarkIsOpen();\n }\n }, [prevQuery, query, unmarkIsOpen]);\n\n useEffect(() => {\n if (isAllowed && usernameLowered && chatId) {\n queryInlineBot({ chatId, username: usernameLowered, query });\n }\n }, [query, isAllowed, queryInlineBot, chatId, usernameLowered]);\n\n const loadMore = useCallback(() => {\n queryInlineBot({\n chatId, username: usernameLowered, query, offset,\n });\n }, [offset, chatId, query, queryInlineBot, usernameLowered]);\n\n useEffect(() => {\n if (isAllowed && botId && (switchPm || (results && results.length))) {\n markIsOpen();\n } else {\n unmarkIsOpen();\n }\n }, [botId, isAllowed, markIsOpen, results, switchPm, unmarkIsOpen]);\n\n if (prevUsername !== username) {\n resetInlineBot({ username: prevUsername });\n }\n\n return {\n isOpen,\n closeTooltip: unmarkIsOpen,\n loadMore,\n username,\n id: botId,\n isGallery,\n switchPm,\n results,\n help: canShowHelp && help ? `@${username} ${help}` : undefined,\n };\n}\n\nfunction getPlainText(html: string) {\n tempEl.innerHTML = html.replace(/<br>/g, '\\n');\n\n return tempEl.innerText;\n}\n\nfunction parseStartWithUsernameString(text: string) {\n const result = text.match(INLINE_BOT_QUERY_REGEXP);\n if (!result) {\n return { username: '', query: '', canShowHelp: false };\n }\n\n return {\n username: result[1],\n query: result[2],\n canShowHelp: result[2] === '' && !text.match(HAS_NEW_LINE),\n };\n}\n","import React, { FC, memo } from '../../lib/teact/teact';\nimport { OwnProps } from './DeleteMessageModal';\nimport { Bundles } from '../../util/moduleLoader';\n\nimport useModuleLoader from '../../hooks/useModuleLoader';\n\nconst DeleteMessageModalAsync: FC<OwnProps> = (props) => {\n const { isOpen } = props;\n const DeleteMessageModal = useModuleLoader(Bundles.Extra, 'DeleteMessageModal', !isOpen);\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return DeleteMessageModal ? <DeleteMessageModal {...props} /> : undefined;\n};\n\nexport default memo(DeleteMessageModalAsync);\n","import React, {\n FC, useRef, useCallback, memo,\n} from '../../lib/teact/teact';\n\nimport { IS_TOUCH_ENV } from '../../util/environment';\n\nimport Button, { OwnProps as ButtonProps } from './Button';\n\ntype OwnProps = {\n onActivate: NoneToVoidFunction;\n} & Omit<ButtonProps, (\n 'onClick' | 'onMouseDown' |\n 'onMouseEnter' | 'onMouseLeave' |\n 'onFocus'\n)>;\n\nconst BUTTON_ACTIVATE_DELAY = 200;\nlet openTimeout: number | undefined;\nlet isFirstTimeActivation = true;\n\nconst ResponsiveHoverButton: FC<OwnProps> = ({ onActivate, ...buttonProps }) => {\n const isMouseInside = useRef(false);\n\n const handleMouseEnter = useCallback(() => {\n isMouseInside.current = true;\n\n // This is used to counter additional delay caused by asynchronous module loading\n if (isFirstTimeActivation) {\n isFirstTimeActivation = false;\n onActivate();\n return;\n }\n\n if (openTimeout) {\n clearTimeout(openTimeout);\n openTimeout = undefined;\n }\n openTimeout = window.setTimeout(() => {\n if (isMouseInside.current) {\n onActivate();\n }\n }, BUTTON_ACTIVATE_DELAY);\n }, [onActivate]);\n\n const handleMouseLeave = useCallback(() => {\n isMouseInside.current = false;\n }, []);\n\n return (\n <Button\n // eslint-disable-next-line react/jsx-props-no-spreading\n {...buttonProps}\n onMouseEnter={!IS_TOUCH_ENV ? handleMouseEnter : undefined}\n onMouseLeave={!IS_TOUCH_ENV ? handleMouseLeave : undefined}\n onClick={IS_TOUCH_ENV ? onActivate : undefined}\n />\n );\n};\n\nexport default memo(ResponsiveHoverButton);\n","import React, { FC, memo } from '../../../lib/teact/teact';\nimport { OwnProps } from './AttachMenu';\nimport { Bundles } from '../../../util/moduleLoader';\n\nimport useModuleLoader from '../../../hooks/useModuleLoader';\n\nconst AttachMenuAsync: FC<OwnProps> = (props) => {\n const { isOpen } = props;\n const AttachMenu = useModuleLoader(Bundles.Extra, 'AttachMenu', !isOpen);\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return AttachMenu ? <AttachMenu {...props} /> : undefined;\n};\n\nexport default memo(AttachMenuAsync);\n","import React, { FC, memo } from '../../../lib/teact/teact';\nimport { OwnProps } from './SymbolMenu';\nimport { Bundles } from '../../../util/moduleLoader';\n\nimport useModuleLoader from '../../../hooks/useModuleLoader';\n\nconst SymbolMenuAsync: FC<OwnProps> = (props) => {\n const { isOpen } = props;\n const SymbolMenu = useModuleLoader(Bundles.Extra, 'SymbolMenu', !isOpen);\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return SymbolMenu ? <SymbolMenu {...props} /> : undefined;\n};\n\nexport default memo(SymbolMenuAsync);\n","import React, { FC, memo } from '../../../lib/teact/teact';\nimport { OwnProps } from './InlineBotTooltip';\nimport { Bundles } from '../../../util/moduleLoader';\n\nimport useModuleLoader from '../../../hooks/useModuleLoader';\n\nconst InlineBotTooltipAsync: FC<OwnProps> = (props) => {\n const { isOpen } = props;\n const InlineBotTooltip = useModuleLoader(Bundles.Extra, 'InlineBotTooltip', !isOpen);\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return InlineBotTooltip ? <InlineBotTooltip {...props} /> : undefined;\n};\n\nexport default memo(InlineBotTooltipAsync);\n","import React, { FC, memo } from '../../../lib/teact/teact';\nimport { OwnProps } from './MentionTooltip';\nimport { Bundles } from '../../../util/moduleLoader';\n\nimport useModuleLoader from '../../../hooks/useModuleLoader';\n\nconst MentionTooltipAsync: FC<OwnProps> = (props) => {\n const { isOpen } = props;\n const MentionTooltip = useModuleLoader(Bundles.Extra, 'MentionTooltip', !isOpen);\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return MentionTooltip ? <MentionTooltip {...props} /> : undefined;\n};\n\nexport default memo(MentionTooltipAsync);\n","import React, { FC, memo } from '../../../lib/teact/teact';\nimport { OwnProps } from './CustomSendMenu';\nimport { Bundles } from '../../../util/moduleLoader';\n\nimport useModuleLoader from '../../../hooks/useModuleLoader';\n\nconst CustomSendMenuAsync: FC<OwnProps> = (props) => {\n const { isOpen } = props;\n const CustomSend = useModuleLoader(Bundles.Extra, 'CustomSendMenu', !isOpen);\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return CustomSend ? <CustomSend {...props} /> : undefined;\n};\n\nexport default memo(CustomSendMenuAsync);\n","import React, { FC } from '../../../lib/teact/teact';\nimport { OwnProps } from './StickerTooltip';\nimport { Bundles } from '../../../util/moduleLoader';\n\nimport useModuleLoader from '../../../hooks/useModuleLoader';\n\nconst StickerTooltipAsync: FC<OwnProps> = (props) => {\n const { isOpen } = props;\n const StickerTooltip = useModuleLoader(Bundles.Extra, 'StickerTooltip', !isOpen);\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return StickerTooltip ? <StickerTooltip {...props} /> : undefined;\n};\n\nexport default StickerTooltipAsync;\n","import React, { FC, memo } from '../../../lib/teact/teact';\nimport { OwnProps } from './BotKeyboardMenu';\nimport { Bundles } from '../../../util/moduleLoader';\n\nimport useModuleLoader from '../../../hooks/useModuleLoader';\n\nconst BotKeyboardMenuAsync: FC<OwnProps> = (props) => {\n const { isOpen } = props;\n const BotKeyboardMenu = useModuleLoader(Bundles.Extra, 'BotKeyboardMenu', !isOpen);\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return BotKeyboardMenu ? <BotKeyboardMenu {...props} /> : undefined;\n};\n\nexport default memo(BotKeyboardMenuAsync);\n","import React, {\n FC, memo, useCallback, useEffect,\n} from '../../../lib/teact/teact';\nimport { withGlobal } from '../../../lib/teact/teactn';\n\nimport { GlobalActions } from '../../../global/types';\nimport { ApiChat, ApiMessage, ApiUser } from '../../../api/types';\n\nimport {\n selectChat,\n selectChatMessage,\n selectSender,\n selectForwardedSender,\n selectUser,\n selectCurrentMessageList,\n selectReplyingToId,\n selectEditingId,\n selectEditingScheduledId,\n selectEditingMessage,\n} from '../../../modules/selectors';\nimport captureEscKeyListener from '../../../util/captureEscKeyListener';\nimport { pick } from '../../../util/iteratees';\nimport useAsyncRendering from '../../right/hooks/useAsyncRendering';\nimport useShowTransition from '../../../hooks/useShowTransition';\nimport buildClassName from '../../../util/buildClassName';\nimport { isChatPrivate } from '../../../modules/helpers';\n\nimport Button from '../../ui/Button';\nimport EmbeddedMessage from '../../common/EmbeddedMessage';\n\nimport './ComposerEmbeddedMessage.scss';\n\ntype StateProps = {\n replyingToId?: number;\n editingId?: number;\n message?: ApiMessage;\n sender?: ApiUser | ApiChat;\n shouldAnimate?: boolean;\n forwardedMessagesCount?: number;\n};\n\ntype DispatchProps = Pick<GlobalActions, 'setReplyingToId' | 'setEditingId' | 'focusMessage' | 'exitForwardMode'>;\n\nconst FORWARD_RENDERING_DELAY = 300;\n\nconst ComposerEmbeddedMessage: FC<StateProps & DispatchProps> = ({\n replyingToId,\n editingId,\n message,\n sender,\n shouldAnimate,\n forwardedMessagesCount,\n setReplyingToId,\n setEditingId,\n focusMessage,\n exitForwardMode,\n}) => {\n const isShown = Boolean(\n ((replyingToId || editingId) && message)\n || (sender && forwardedMessagesCount),\n );\n const canAnimate = useAsyncRendering(\n [forwardedMessagesCount],\n forwardedMessagesCount ? FORWARD_RENDERING_DELAY : undefined,\n );\n\n const {\n shouldRender, transitionClassNames,\n } = useShowTransition(canAnimate && isShown, undefined, !shouldAnimate, undefined, !shouldAnimate);\n\n const clearEmbedded = useCallback(() => {\n if (replyingToId) {\n setReplyingToId({ messageId: undefined });\n } else if (editingId) {\n setEditingId({ messageId: undefined });\n } else if (forwardedMessagesCount) {\n exitForwardMode();\n }\n }, [replyingToId, editingId, forwardedMessagesCount, setReplyingToId, setEditingId, exitForwardMode]);\n\n useEffect(() => (isShown ? captureEscKeyListener(clearEmbedded) : undefined), [isShown, clearEmbedded]);\n\n const handleMessageClick = useCallback((): void => {\n focusMessage({ chatId: message!.chatId, messageId: message!.id });\n }, [focusMessage, message]);\n\n const className = buildClassName('ComposerEmbeddedMessage', transitionClassNames);\n\n const customText = forwardedMessagesCount && forwardedMessagesCount > 1\n ? `${forwardedMessagesCount} forwarded messages`\n : undefined;\n\n if (!shouldRender) {\n return undefined;\n }\n\n return (\n <div className={className}>\n <div>\n <Button round color=\"translucent\" ariaLabel=\"Cancel replying\" onClick={clearEmbedded}>\n <i className=\"icon-close\" />\n </Button>\n <EmbeddedMessage\n className=\"inside-input\"\n message={message}\n sender={sender}\n customText={customText}\n title={editingId ? 'Edit Message' : undefined}\n onClick={handleMessageClick}\n />\n </div>\n </div>\n );\n};\n\nexport default memo(withGlobal(\n (global): StateProps => {\n const { chatId, threadId, type: messageListType } = selectCurrentMessageList(global) || {};\n if (!chatId || !threadId || !messageListType) {\n return {};\n }\n\n const {\n currentUserId,\n forwardMessages: { fromChatId, toChatId, messageIds: forwardMessageIds },\n } = global;\n\n const replyingToId = selectReplyingToId(global, chatId, threadId);\n const editingId = messageListType === 'scheduled'\n ? selectEditingScheduledId(global, chatId)\n : selectEditingId(global, chatId, threadId);\n const shouldAnimate = global.settings.byKey.animationLevel >= 1;\n const isForwarding = toChatId === chatId;\n\n let message;\n if (replyingToId) {\n message = selectChatMessage(global, chatId, replyingToId);\n } else if (editingId) {\n message = selectEditingMessage(global, chatId, threadId, messageListType);\n } else if (isForwarding && forwardMessageIds!.length === 1) {\n message = selectChatMessage(global, fromChatId!, forwardMessageIds![0]);\n }\n\n let sender: ApiChat | ApiUser | undefined;\n if (replyingToId && message) {\n const { forwardInfo } = message;\n const isChatWithSelf = chatId === currentUserId;\n\n if (forwardInfo && (forwardInfo.isChannelPost || isChatWithSelf)) {\n sender = selectForwardedSender(global, message);\n }\n\n if (!sender) {\n sender = selectSender(global, message);\n }\n } else if (isForwarding) {\n sender = isChatPrivate(fromChatId!) ? selectUser(global, fromChatId!) : selectChat(global, fromChatId!);\n }\n\n return {\n replyingToId,\n editingId,\n message,\n sender,\n shouldAnimate,\n forwardedMessagesCount: isForwarding ? forwardMessageIds!.length : undefined,\n };\n },\n (setGlobal, actions): DispatchProps => pick(actions, [\n 'setReplyingToId',\n 'setEditingId',\n 'focusMessage',\n 'exitForwardMode',\n ]),\n)(ComposerEmbeddedMessage));\n","import React, { FC, memo } from '../../../lib/teact/teact';\nimport { OwnProps } from './AttachmentModal';\nimport { Bundles } from '../../../util/moduleLoader';\n\nimport useModuleLoader from '../../../hooks/useModuleLoader';\n\nconst AttachmentModalAsync: FC<OwnProps> = (props) => {\n const { attachments } = props;\n const AttachmentModal = useModuleLoader(Bundles.Extra, 'AttachmentModal', !attachments.length);\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return AttachmentModal ? <AttachmentModal {...props} /> : undefined;\n};\n\nexport default memo(AttachmentModalAsync);\n","import React, { FC, memo } from '../../../lib/teact/teact';\nimport { OwnProps } from './PollModal';\nimport { Bundles } from '../../../util/moduleLoader';\n\nimport useModuleLoader from '../../../hooks/useModuleLoader';\n\nconst PollModalAsync: FC<OwnProps> = (props) => {\n const { isOpen } = props;\n const PollModal = useModuleLoader(Bundles.Extra, 'PollModal', !isOpen);\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return PollModal ? <PollModal {...props} /> : undefined;\n};\n\nexport default memo(PollModalAsync);\n","import React, { FC, memo } from '../../../lib/teact/teact';\nimport { OwnProps } from './DropArea';\nimport { Bundles } from '../../../util/moduleLoader';\n\nimport useModuleLoader from '../../../hooks/useModuleLoader';\n\nconst DropAreaAsync: FC<OwnProps> = (props) => {\n const { isOpen } = props;\n const DropArea = useModuleLoader(Bundles.Extra, 'DropArea', !isOpen);\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return DropArea ? <DropArea {...props} /> : undefined;\n};\n\nexport default memo(DropAreaAsync);\nexport { DropAreaState } from './DropArea';\n","import React, {\n FC, memo, useEffect, useMemo,\n} from '../../../lib/teact/teact';\nimport { withGlobal } from '../../../lib/teact/teactn';\n\nimport { GlobalActions } from '../../../global/types';\nimport { ApiMessage, ApiMessageEntityTypes, ApiWebPage } from '../../../api/types';\n\nimport { RE_LINK_TEMPLATE } from '../../../config';\nimport { selectNoWebPage } from '../../../modules/selectors';\nimport { pick } from '../../../util/iteratees';\nimport parseMessageInput from './helpers/parseMessageInput';\nimport useOnChange from '../../../hooks/useOnChange';\nimport useShowTransition from '../../../hooks/useShowTransition';\nimport useCurrentOrPrev from '../../../hooks/useCurrentOrPrev';\nimport buildClassName from '../../../util/buildClassName';\n\nimport WebPage from '../message/WebPage';\nimport Button from '../../ui/Button';\n\nimport './WebPagePreview.scss';\n\ntype OwnProps = {\n chatId: number;\n threadId: number;\n messageText: string;\n disabled?: boolean;\n};\n\ntype StateProps = {\n webPagePreview?: ApiWebPage;\n noWebPage?: boolean;\n};\ntype DispatchProps = Pick<GlobalActions, 'loadWebPagePreview' | 'clearWebPagePreview' | 'toggleMessageWebPage'>;\n\nconst RE_LINK = new RegExp(RE_LINK_TEMPLATE, 'i');\n\nconst WebPagePreview: FC<OwnProps & StateProps & DispatchProps> = ({\n chatId,\n threadId,\n messageText,\n disabled,\n webPagePreview,\n noWebPage,\n loadWebPagePreview,\n clearWebPagePreview,\n toggleMessageWebPage,\n}) => {\n const link = useMemo(() => {\n const { text, entities } = parseMessageInput(messageText);\n\n const linkEntity = entities && entities.find(({ type }) => type === ApiMessageEntityTypes.TextUrl);\n if (linkEntity) {\n return linkEntity.url;\n }\n\n const textMatch = text.match(RE_LINK);\n if (textMatch) {\n return textMatch[0];\n }\n\n return undefined;\n }, [messageText]);\n\n useEffect(() => {\n if (link) {\n loadWebPagePreview({ text: link });\n } else {\n clearWebPagePreview();\n toggleMessageWebPage({ chatId, threadId });\n }\n }, [chatId, toggleMessageWebPage, clearWebPagePreview, link, loadWebPagePreview, threadId]);\n\n useOnChange(() => {\n clearWebPagePreview();\n toggleMessageWebPage({ chatId, threadId });\n }, [chatId]);\n\n const isShown = Boolean(webPagePreview && messageText.length && !noWebPage && !disabled);\n const { shouldRender, transitionClassNames } = useShowTransition(isShown);\n\n const renderingWebPage = useCurrentOrPrev(webPagePreview);\n\n if (!shouldRender || !renderingWebPage) {\n return undefined;\n }\n\n const handleClearWebpagePreview = () => {\n toggleMessageWebPage({ chatId, threadId, noWebPage: true });\n };\n\n // TODO Refactor so `WebPage` can be used without message\n const { photo, ...webPageWithoutPhoto } = renderingWebPage;\n const messageStub = {\n content: {\n webPage: webPageWithoutPhoto,\n },\n } as ApiMessage;\n\n return (\n <div className={buildClassName('WebPagePreview', transitionClassNames)}>\n <div>\n <Button round color=\"translucent\" ariaLabel=\"Clear Webpage Preview\" onClick={handleClearWebpagePreview}>\n <i className=\"icon-close\" />\n </Button>\n <WebPage message={messageStub} inPreview />\n </div>\n </div>\n );\n};\n\nexport default memo(withGlobal<OwnProps>(\n (global, { chatId, threadId }): StateProps => {\n const noWebPage = selectNoWebPage(global, chatId, threadId);\n return {\n webPagePreview: global.webPagePreview,\n noWebPage,\n };\n },\n (setGlobal, actions): DispatchProps => pick(actions, [\n 'loadWebPagePreview', 'clearWebPagePreview', 'toggleMessageWebPage',\n ]),\n)(WebPagePreview));\n","import React, { FC, memo } from '../../lib/teact/teact';\nimport { OwnProps } from './CalendarModal';\nimport { Bundles } from '../../util/moduleLoader';\n\nimport useModuleLoader from '../../hooks/useModuleLoader';\n\nconst CalendarModalAsync: FC<OwnProps> = (props) => {\n const { isOpen } = props;\n const CalendarModal = useModuleLoader(Bundles.Extra, 'CalendarModal', !isOpen);\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return CalendarModal ? <CalendarModal {...props} /> : undefined;\n};\n\nexport default memo(CalendarModalAsync);\n","import React, { FC, memo } from '../../lib/teact/teact';\nimport { OwnProps } from './PaymentModal';\nimport { Bundles } from '../../util/moduleLoader';\n\nimport useModuleLoader from '../../hooks/useModuleLoader';\n\nconst PaymentModalAsync: FC<OwnProps> = (props) => {\n const { isOpen } = props;\n const PaymentModal = useModuleLoader(Bundles.Extra, 'PaymentModal', !isOpen);\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return PaymentModal ? <PaymentModal {...props} /> : undefined;\n};\n\nexport default memo(PaymentModalAsync);\n","import React, { FC, memo } from '../../lib/teact/teact';\nimport { OwnProps } from './ReceiptModal';\nimport { Bundles } from '../../util/moduleLoader';\n\nimport useModuleLoader from '../../hooks/useModuleLoader';\n\nconst ReceiptModalAsync: FC<OwnProps> = (props) => {\n const { isOpen } = props;\n const ReceiptModal = useModuleLoader(Bundles.Extra, 'ReceiptModal', !isOpen);\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return ReceiptModal ? <ReceiptModal {...props} /> : undefined;\n};\n\nexport default memo(ReceiptModalAsync);\n","import React, {\n FC, memo, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState,\n} from '../../../lib/teact/teact';\nimport { withGlobal } from '../../../lib/teact/teactn';\n\nimport { GlobalActions, GlobalState, MessageListType } from '../../../global/types';\nimport {\n ApiAttachment,\n ApiBotInlineResult,\n ApiBotInlineMediaResult,\n ApiSticker,\n ApiVideo,\n ApiNewPoll,\n ApiMessage,\n ApiFormattedText,\n ApiChat,\n ApiChatMember,\n ApiUser,\n MAIN_THREAD_ID,\n} from '../../../api/types';\nimport { InlineBotSettings } from '../../../types';\n\nimport { BASE_EMOJI_KEYWORD_LANG, EDITABLE_INPUT_ID, SCHEDULED_WHEN_ONLINE } from '../../../config';\nimport { IS_VOICE_RECORDING_SUPPORTED, IS_SINGLE_COLUMN_LAYOUT, IS_IOS } from '../../../util/environment';\nimport {\n selectChat,\n selectIsChatWithBot,\n selectIsRightColumnShown,\n selectIsInSelectMode,\n selectNewestMessageWithBotKeyboardButtons,\n selectDraft,\n selectScheduledIds,\n selectEditingMessage,\n selectIsChatWithSelf,\n selectChatUser,\n} from '../../../modules/selectors';\nimport {\n getAllowedAttachmentOptions,\n getChatSlowModeOptions,\n isChatPrivate,\n isChatAdmin,\n} from '../../../modules/helpers';\nimport { formatMediaDuration, formatVoiceRecordDuration, getDayStartAt } from '../../../util/dateFormat';\nimport focusEditableElement from '../../../util/focusEditableElement';\nimport parseMessageInput from './helpers/parseMessageInput';\nimport buildAttachment from './helpers/buildAttachment';\nimport renderText from '../../common/helpers/renderText';\nimport insertHtmlInSelection from '../../../util/insertHtmlInSelection';\nimport deleteLastCharacterOutsideSelection from '../../../util/deleteLastCharacterOutsideSelection';\nimport { pick } from '../../../util/iteratees';\nimport buildClassName from '../../../util/buildClassName';\nimport { isSelectionInsideInput } from './helpers/selection';\nimport applyIosAutoCapitalizationFix from './helpers/applyIosAutoCapitalizationFix';\n\nimport useFlag from '../../../hooks/useFlag';\nimport useVoiceRecording from './hooks/useVoiceRecording';\nimport useClipboardPaste from './hooks/useClipboardPaste';\nimport useDraft from './hooks/useDraft';\nimport useEditing from './hooks/useEditing';\nimport usePrevious from '../../../hooks/usePrevious';\nimport useStickerTooltip from './hooks/useStickerTooltip';\nimport useEmojiTooltip from './hooks/useEmojiTooltip';\nimport useMentionTooltip from './hooks/useMentionTooltip';\nimport useContextMenuHandlers from '../../../hooks/useContextMenuHandlers';\nimport useLang from '../../../hooks/useLang';\nimport useInlineBotTooltip from './hooks/useInlineBotTooltip';\nimport windowSize from '../../../util/windowSize';\n\nimport DeleteMessageModal from '../../common/DeleteMessageModal.async';\nimport Button from '../../ui/Button';\nimport ResponsiveHoverButton from '../../ui/ResponsiveHoverButton';\nimport Spinner from '../../ui/Spinner';\nimport AttachMenu from './AttachMenu.async';\nimport SymbolMenu from './SymbolMenu.async';\nimport InlineBotTooltip from './InlineBotTooltip.async';\nimport MentionTooltip from './MentionTooltip.async';\nimport CustomSendMenu from './CustomSendMenu.async';\nimport StickerTooltip from './StickerTooltip.async';\nimport EmojiTooltip from './EmojiTooltip.async';\nimport BotKeyboardMenu from './BotKeyboardMenu.async';\nimport MessageInput from './MessageInput';\nimport ComposerEmbeddedMessage from './ComposerEmbeddedMessage';\nimport AttachmentModal from './AttachmentModal.async';\nimport PollModal from './PollModal.async';\nimport DropArea, { DropAreaState } from './DropArea.async';\nimport WebPagePreview from './WebPagePreview';\nimport Portal from '../../ui/Portal';\nimport CalendarModal from '../../common/CalendarModal.async';\nimport PaymentModal from '../../payment/PaymentModal.async';\nimport ReceiptModal from '../../payment/ReceiptModal.async';\n\nimport './Composer.scss';\n\ntype OwnProps = {\n chatId: number;\n threadId: number;\n messageListType: MessageListType;\n dropAreaState: string;\n isReady: boolean;\n onDropHide: NoneToVoidFunction;\n};\n\ntype StateProps = {\n editingMessage?: ApiMessage;\n chat?: ApiChat;\n draft?: ApiFormattedText;\n isChatWithBot?: boolean;\n isChatWithSelf?: boolean;\n isRightColumnShown?: boolean;\n isSelectModeActive?: boolean;\n isForwarding?: boolean;\n isPollModalOpen?: boolean;\n isPaymentModalOpen?: boolean;\n isReceiptModalOpen?: boolean;\n botKeyboardMessageId?: number;\n withScheduledButton?: boolean;\n shouldSchedule?: boolean;\n canScheduleUntilOnline?: boolean;\n stickersForEmoji?: ApiSticker[];\n groupChatMembers?: ApiChatMember[];\n currentUserId?: number;\n usersById?: Record<number, ApiUser>;\n recentEmojis: string[];\n lastSyncTime?: number;\n contentToBeScheduled?: GlobalState['messages']['contentToBeScheduled'];\n shouldSuggestStickers?: boolean;\n baseEmojiKeywords?: Record<string, string[]>;\n emojiKeywords?: Record<string, string[]>;\n serverTimeOffset: number;\n topInlineBotIds?: number[];\n isInlineBotLoading: boolean;\n inlineBots?: Record<string, false | InlineBotSettings>;\n} & Pick<GlobalState, 'connectionState'>;\n\ntype DispatchProps = Pick<GlobalActions, (\n 'sendMessage' | 'editMessage' | 'saveDraft' | 'forwardMessages' |\n 'clearDraft' | 'showDialog' | 'setStickerSearchQuery' | 'setGifSearchQuery' |\n 'openPollModal' | 'closePollModal' | 'loadScheduledHistory' | 'openChat' | 'closePaymentModal' |\n 'clearReceipt' | 'addRecentEmoji' | 'sendInlineBotResult'\n)>;\n\nenum MainButtonState {\n Send = 'send',\n Record = 'record',\n Edit = 'edit',\n}\n\nconst VOICE_RECORDING_FILENAME = 'wonderful-voice-message.ogg';\n// When voice recording is active, composer placeholder will hide to prevent overlapping\nconst SCREEN_WIDTH_TO_HIDE_PLACEHOLDER = 600; // px\n\nconst MOBILE_KEYBOARD_HIDE_DELAY_MS = 100;\nconst SELECT_MODE_TRANSITION_MS = 200;\nconst CAPTION_MAX_LENGTH = 1024;\nconst SENDING_ANIMATION_DURATION = 350;\n// eslint-disable-next-line max-len\nconst APPENDIX = '<svg width=\"9\" height=\"20\" xmlns=\"http://www.w3.org/2000/svg\"><defs><filter x=\"-50%\" y=\"-14.7%\" width=\"200%\" height=\"141.2%\" filterUnits=\"objectBoundingBox\" id=\"a\"><feOffset dy=\"1\" in=\"SourceAlpha\" result=\"shadowOffsetOuter1\"/><feGaussianBlur stdDeviation=\"1\" in=\"shadowOffsetOuter1\" result=\"shadowBlurOuter1\"/><feColorMatrix values=\"0 0 0 0 0.0621962482 0 0 0 0 0.138574144 0 0 0 0 0.185037364 0 0 0 0.15 0\" in=\"shadowBlurOuter1\"/></filter></defs><g fill=\"none\" fill-rule=\"evenodd\"><path d=\"M6 17H0V0c.193 2.84.876 5.767 2.05 8.782.904 2.325 2.446 4.485 4.625 6.48A1 1 0 016 17z\" fill=\"#000\" filter=\"url(#a)\"/><path d=\"M6 17H0V0c.193 2.84.876 5.767 2.05 8.782.904 2.325 2.446 4.485 4.625 6.48A1 1 0 016 17z\" fill=\"#FFF\" class=\"corner\"/></g></svg>';\n\nconst Composer: FC<OwnProps & StateProps & DispatchProps> = ({\n dropAreaState,\n shouldSchedule,\n canScheduleUntilOnline,\n isReady,\n onDropHide,\n editingMessage,\n chatId,\n threadId,\n messageListType,\n draft,\n chat,\n connectionState,\n isChatWithBot,\n isChatWithSelf,\n isRightColumnShown,\n isSelectModeActive,\n isForwarding,\n isPollModalOpen,\n isPaymentModalOpen,\n isReceiptModalOpen,\n botKeyboardMessageId,\n withScheduledButton,\n stickersForEmoji,\n groupChatMembers,\n topInlineBotIds,\n currentUserId,\n usersById,\n lastSyncTime,\n contentToBeScheduled,\n shouldSuggestStickers,\n baseEmojiKeywords,\n emojiKeywords,\n serverTimeOffset,\n recentEmojis,\n inlineBots,\n isInlineBotLoading,\n sendMessage,\n editMessage,\n saveDraft,\n clearDraft,\n showDialog,\n setStickerSearchQuery,\n setGifSearchQuery,\n forwardMessages,\n openPollModal,\n closePollModal,\n loadScheduledHistory,\n closePaymentModal,\n openChat,\n clearReceipt,\n addRecentEmoji,\n sendInlineBotResult,\n}) => {\n const lang = useLang();\n\n // eslint-disable-next-line no-null/no-null\n const appendixRef = useRef<HTMLDivElement>(null);\n const [html, setHtml] = useState<string>('');\n const lastMessageSendTimeSeconds = useRef<number>();\n const prevDropAreaState = usePrevious(dropAreaState);\n const [isCalendarOpen, openCalendar, closeCalendar] = useFlag();\n const [\n scheduledMessageArgs, setScheduledMessageArgs,\n ] = useState<GlobalState['messages']['contentToBeScheduled'] | undefined>();\n const { width: windowWidth } = windowSize.get();\n\n // Cache for frequently updated state\n const htmlRef = useRef<string>(html);\n useEffect(() => {\n htmlRef.current = html;\n }, [html]);\n\n useEffect(() => {\n lastMessageSendTimeSeconds.current = undefined;\n }, [chatId]);\n\n useEffect(() => {\n if (chatId && lastSyncTime && threadId === MAIN_THREAD_ID && isReady) {\n loadScheduledHistory();\n }\n }, [isReady, chatId, loadScheduledHistory, lastSyncTime, threadId]);\n\n useLayoutEffect(() => {\n if (!appendixRef.current) return;\n\n appendixRef.current.innerHTML = APPENDIX;\n }, []);\n\n useEffect(() => {\n if (contentToBeScheduled) {\n setScheduledMessageArgs(contentToBeScheduled);\n openCalendar();\n }\n }, [contentToBeScheduled, openCalendar]);\n\n const [attachments, setAttachments] = useState<ApiAttachment[]>([]);\n\n const [isBotKeyboardOpen, openBotKeyboard, closeBotKeyboard] = useFlag();\n const [isAttachMenuOpen, openAttachMenu, closeAttachMenu] = useFlag();\n const [isSymbolMenuOpen, openSymbolMenu, closeSymbolMenu] = useFlag();\n const [isDeleteModalOpen, openDeleteModal, closeDeleteModal] = useFlag();\n const [isSymbolMenuLoaded, onSymbolMenuLoadingComplete] = useFlag();\n const [isHoverDisabled, disableHover, enableHover] = useFlag();\n\n const {\n startRecordingVoice,\n stopRecordingVoice,\n pauseRecordingVoice,\n activeVoiceRecording,\n currentRecordTime,\n recordButtonRef: mainButtonRef,\n startRecordTimeRef,\n } = useVoiceRecording();\n\n const mainButtonState = editingMessage\n ? MainButtonState.Edit\n : !IS_VOICE_RECORDING_SUPPORTED || activeVoiceRecording || (html && !attachments.length) || isForwarding\n ? MainButtonState.Send\n : MainButtonState.Record;\n const canShowCustomSendMenu = !shouldSchedule;\n\n const {\n isMentionTooltipOpen, mentionFilter,\n closeMentionTooltip, insertMention,\n mentionFilteredUsers,\n } = useMentionTooltip(\n !attachments.length,\n html,\n setHtml,\n undefined,\n groupChatMembers,\n topInlineBotIds,\n currentUserId,\n usersById,\n );\n\n const {\n isOpen: isInlineBotTooltipOpen,\n id: inlineBotId,\n isGallery: isInlineBotTooltipGallery,\n switchPm: inlineBotSwitchPm,\n results: inlineBotResults,\n closeTooltip: closeInlineBotTooltip,\n help: inlineBotHelp,\n loadMore: loadMoreForInlineBot,\n } = useInlineBotTooltip(\n Boolean(!attachments.length && lastSyncTime),\n chatId,\n html,\n inlineBots,\n );\n\n const {\n isContextMenuOpen: isCustomSendMenuOpen,\n handleContextMenu,\n handleContextMenuClose,\n handleContextMenuHide,\n } = useContextMenuHandlers(mainButtonRef, !(mainButtonState === MainButtonState.Send && canShowCustomSendMenu));\n\n const allowedAttachmentOptions = useMemo(() => {\n return getAllowedAttachmentOptions(chat, isChatWithBot);\n }, [chat, isChatWithBot]);\n\n const isAdmin = chat && isChatAdmin(chat);\n const slowMode = getChatSlowModeOptions(chat);\n\n const { isStickerTooltipOpen, closeStickerTooltip } = useStickerTooltip(\n Boolean(shouldSuggestStickers && allowedAttachmentOptions.canSendStickers && !attachments.length),\n html,\n stickersForEmoji,\n !isReady,\n );\n const {\n isEmojiTooltipOpen, closeEmojiTooltip, filteredEmojis, insertEmoji,\n } = useEmojiTooltip(\n Boolean(shouldSuggestStickers && allowedAttachmentOptions.canSendStickers && !attachments.length),\n html,\n recentEmojis,\n undefined,\n setHtml,\n baseEmojiKeywords,\n emojiKeywords,\n !isReady,\n );\n\n const insertTextAndUpdateCursor = useCallback((text: string, inputId: string = EDITABLE_INPUT_ID) => {\n const selection = window.getSelection()!;\n const messageInput = document.getElementById(inputId)!;\n const newHtml = renderText(text, ['escape_html', 'emoji_html', 'br_html'])\n .join('')\n .replace(/\\u200b+/g, '\\u200b');\n\n if (selection.rangeCount) {\n const selectionRange = selection.getRangeAt(0);\n if (isSelectionInsideInput(selectionRange, inputId)) {\n insertHtmlInSelection(newHtml);\n messageInput.dispatchEvent(new Event('input', { bubbles: true }));\n return;\n }\n }\n\n setHtml(`${htmlRef.current!}${newHtml}`);\n\n // If selection is outside of input, set cursor at the end of input\n requestAnimationFrame(() => {\n focusEditableElement(messageInput);\n });\n }, []);\n\n const removeSymbol = useCallback(() => {\n const selection = window.getSelection()!;\n\n if (selection.rangeCount) {\n const selectionRange = selection.getRangeAt(0);\n if (isSelectionInsideInput(selectionRange, EDITABLE_INPUT_ID)) {\n document.execCommand('delete', false);\n return;\n }\n }\n\n setHtml(deleteLastCharacterOutsideSelection(htmlRef.current!));\n }, []);\n\n const resetComposer = useCallback((shouldPreserveInput = false) => {\n if (!shouldPreserveInput) {\n setHtml('');\n }\n setAttachments([]);\n closeStickerTooltip();\n closeCalendar();\n setScheduledMessageArgs(undefined);\n closeMentionTooltip();\n closeEmojiTooltip();\n\n if (IS_SINGLE_COLUMN_LAYOUT) {\n // @perf\n setTimeout(() => closeSymbolMenu(), SENDING_ANIMATION_DURATION);\n } else {\n closeSymbolMenu();\n }\n }, [closeStickerTooltip, closeCalendar, closeMentionTooltip, closeEmojiTooltip, closeSymbolMenu]);\n\n // Handle chat change\n const prevChatId = usePrevious(chatId);\n useEffect(() => {\n if (!prevChatId || chatId === prevChatId) {\n return;\n }\n\n stopRecordingVoice();\n resetComposer();\n }, [chatId, prevChatId, resetComposer, stopRecordingVoice]);\n\n const handleEditComplete = useEditing(htmlRef, setHtml, editingMessage, resetComposer, openDeleteModal, editMessage);\n useDraft(draft, chatId, threadId, html, htmlRef, setHtml, editingMessage, saveDraft, clearDraft);\n useClipboardPaste(insertTextAndUpdateCursor, setAttachments, editingMessage);\n\n const handleFileSelect = useCallback(async (files: File[], isQuick: boolean) => {\n setAttachments(await Promise.all(files.map((file) => buildAttachment(file.name, file, isQuick))));\n }, []);\n\n const handleAppendFiles = useCallback(async (files: File[], isQuick: boolean) => {\n setAttachments([\n ...attachments,\n ...await Promise.all(files.map((file) => buildAttachment(file.name, file, isQuick))),\n ]);\n }, [attachments]);\n\n const handleClearAttachment = useCallback(() => {\n setAttachments([]);\n }, []);\n\n const handleSend = useCallback(async (isSilent = false, scheduledAt?: number) => {\n if (connectionState !== 'connectionStateReady') {\n return;\n }\n\n let currentAttachments = attachments;\n\n if (activeVoiceRecording) {\n const record = await stopRecordingVoice();\n if (record) {\n const { blob, duration, waveform } = record;\n currentAttachments = [await buildAttachment(\n VOICE_RECORDING_FILENAME,\n blob,\n false,\n { voice: { duration, waveform } },\n )];\n }\n }\n\n const { text, entities } = parseMessageInput(htmlRef.current!);\n if (!currentAttachments.length && !text && !isForwarding) {\n return;\n }\n\n if (currentAttachments.length && text && text.length > CAPTION_MAX_LENGTH) {\n const extraLength = text.length - CAPTION_MAX_LENGTH;\n showDialog({\n data: {\n message: 'CAPTION_TOO_LONG_PLEASE_REMOVE_CHARACTERS',\n textParams: {\n '{EXTRA_CHARS_COUNT}': extraLength,\n '{PLURAL_S}': extraLength > 1 ? 's' : '',\n },\n hasErrorKey: true,\n },\n });\n return;\n }\n\n const messageInput = document.getElementById(EDITABLE_INPUT_ID)!;\n\n if (currentAttachments.length || text) {\n if (slowMode && !isAdmin) {\n const nowSeconds = Math.floor(Date.now() / 1000) + serverTimeOffset;\n const secondsSinceLastMessage = lastMessageSendTimeSeconds.current\n && Math.floor(nowSeconds - lastMessageSendTimeSeconds.current);\n const nextSendDateNotReached = slowMode.nextSendDate && slowMode.nextSendDate > nowSeconds;\n\n if (\n (secondsSinceLastMessage && secondsSinceLastMessage < slowMode.seconds)\n || nextSendDateNotReached\n ) {\n const secondsRemaining = nextSendDateNotReached\n ? slowMode.nextSendDate! - nowSeconds\n : slowMode.seconds - secondsSinceLastMessage!;\n showDialog({\n data: {\n message: lang('SlowModeHint', formatMediaDuration(secondsRemaining)),\n isSlowMode: true,\n hasErrorKey: false,\n },\n });\n\n messageInput.blur();\n\n return;\n }\n }\n\n sendMessage({\n text,\n entities,\n attachments: currentAttachments,\n scheduledAt,\n isSilent,\n });\n }\n if (isForwarding) {\n forwardMessages();\n }\n\n lastMessageSendTimeSeconds.current = Math.floor(Date.now() / 1000) + serverTimeOffset;\n\n clearDraft({ chatId, localOnly: true });\n\n if (IS_IOS && messageInput === document.activeElement) {\n applyIosAutoCapitalizationFix(messageInput);\n }\n\n // Wait until message animation starts\n requestAnimationFrame(() => {\n resetComposer();\n });\n }, [\n connectionState, attachments, activeVoiceRecording, isForwarding, serverTimeOffset, clearDraft, chatId,\n resetComposer, stopRecordingVoice, showDialog, slowMode, isAdmin, sendMessage, forwardMessages, lang,\n ]);\n\n const handleStickerSelect = useCallback((sticker: ApiSticker, shouldPreserveInput = false) => {\n sticker = {\n ...sticker,\n isPreloadedGlobally: true,\n };\n\n if (shouldSchedule) {\n setScheduledMessageArgs({ sticker });\n openCalendar();\n } else {\n sendMessage({ sticker });\n requestAnimationFrame(() => {\n resetComposer(shouldPreserveInput);\n });\n }\n }, [shouldSchedule, openCalendar, sendMessage, resetComposer]);\n\n const handleGifSelect = useCallback((gif: ApiVideo) => {\n if (shouldSchedule) {\n setScheduledMessageArgs({ gif });\n openCalendar();\n } else {\n sendMessage({ gif });\n requestAnimationFrame(() => {\n resetComposer(true);\n });\n }\n }, [shouldSchedule, openCalendar, sendMessage, resetComposer]);\n\n const handleInlineBotSelect = useCallback((inlineResult: ApiBotInlineResult | ApiBotInlineMediaResult) => {\n if (connectionState !== 'connectionStateReady') {\n return;\n }\n\n sendInlineBotResult({\n id: inlineResult.id,\n queryId: inlineResult.queryId,\n });\n\n const messageInput = document.getElementById(EDITABLE_INPUT_ID)!;\n if (IS_IOS && messageInput === document.activeElement) {\n applyIosAutoCapitalizationFix(messageInput);\n }\n\n clearDraft({ chatId, localOnly: true });\n requestAnimationFrame(() => {\n resetComposer();\n });\n }, [chatId, clearDraft, connectionState, resetComposer, sendInlineBotResult]);\n\n const handlePollSend = useCallback((poll: ApiNewPoll) => {\n if (shouldSchedule) {\n setScheduledMessageArgs({ poll });\n closePollModal();\n openCalendar();\n } else {\n sendMessage({ poll });\n closePollModal();\n }\n }, [closePollModal, openCalendar, sendMessage, shouldSchedule]);\n\n const handleSilentSend = useCallback(() => {\n if (shouldSchedule) {\n setScheduledMessageArgs({ isSilent: true });\n openCalendar();\n } else {\n handleSend(true);\n }\n }, [handleSend, openCalendar, shouldSchedule]);\n\n const handleMessageSchedule = useCallback((date: Date, isWhenOnline = false) => {\n const { isSilent, ...restArgs } = scheduledMessageArgs || {};\n\n // Scheduled time can not be less than 10 seconds in future\n const scheduledAt = Math.round(Math.max(date.getTime(), Date.now() + 60 * 1000) / 1000)\n + (isWhenOnline ? 0 : serverTimeOffset);\n\n if (!scheduledMessageArgs || Object.keys(restArgs).length === 0) {\n handleSend(!!isSilent, scheduledAt);\n } else {\n sendMessage({\n ...scheduledMessageArgs,\n scheduledAt,\n });\n requestAnimationFrame(() => {\n resetComposer();\n });\n }\n closeCalendar();\n }, [closeCalendar, handleSend, resetComposer, scheduledMessageArgs, sendMessage, serverTimeOffset]);\n\n const handleMessageScheduleUntilOnline = useCallback(() => {\n handleMessageSchedule(new Date(SCHEDULED_WHEN_ONLINE * 1000), true);\n }, [handleMessageSchedule]);\n\n const handleCloseCalendar = useCallback(() => {\n closeCalendar();\n setScheduledMessageArgs(undefined);\n }, [closeCalendar]);\n\n const handleSearchOpen = useCallback((type: 'stickers' | 'gifs') => {\n if (type === 'stickers') {\n setStickerSearchQuery({ query: '' });\n setGifSearchQuery({ query: undefined });\n } else {\n setGifSearchQuery({ query: '' });\n setStickerSearchQuery({ query: undefined });\n }\n }, [setStickerSearchQuery, setGifSearchQuery]);\n\n const handleSymbolMenuOpen = useCallback(() => {\n const messageInput = document.getElementById(EDITABLE_INPUT_ID)!;\n\n if (!IS_SINGLE_COLUMN_LAYOUT || messageInput !== document.activeElement) {\n openSymbolMenu();\n return;\n }\n\n messageInput.blur();\n setTimeout(() => {\n openSymbolMenu();\n }, MOBILE_KEYBOARD_HIDE_DELAY_MS);\n }, [openSymbolMenu]);\n\n const handleAllScheduledClick = useCallback(() => {\n openChat({ id: chatId, threadId, type: 'scheduled' });\n }, [openChat, chatId, threadId]);\n\n useEffect(() => {\n if (isRightColumnShown && IS_SINGLE_COLUMN_LAYOUT) {\n closeSymbolMenu();\n }\n }, [isRightColumnShown, closeSymbolMenu]);\n\n useEffect(() => {\n if (!isReady) return;\n\n if (isSelectModeActive) {\n disableHover();\n } else {\n setTimeout(() => {\n enableHover();\n }, SELECT_MODE_TRANSITION_MS);\n }\n }, [isSelectModeActive, enableHover, disableHover, isReady]);\n\n const mainButtonHandler = useCallback(() => {\n switch (mainButtonState) {\n case MainButtonState.Send:\n if (shouldSchedule) {\n if (activeVoiceRecording) {\n pauseRecordingVoice();\n }\n openCalendar();\n } else {\n handleSend();\n requestAnimationFrame(() => {\n resetComposer();\n });\n }\n break;\n case MainButtonState.Record:\n startRecordingVoice();\n break;\n case MainButtonState.Edit:\n handleEditComplete();\n break;\n default:\n break;\n }\n }, [\n mainButtonState, resetComposer, shouldSchedule, startRecordingVoice, handleEditComplete,\n activeVoiceRecording, openCalendar, pauseRecordingVoice, handleSend,\n ]);\n\n const areVoiceMessagesNotAllowed = mainButtonState === MainButtonState.Record\n && !allowedAttachmentOptions.canAttachMedia;\n\n const prevEditedMessage = usePrevious(editingMessage, true);\n const renderedEditedMessage = editingMessage || prevEditedMessage;\n\n const scheduledDefaultDate = new Date();\n scheduledDefaultDate.setSeconds(0);\n scheduledDefaultDate.setMilliseconds(0);\n\n const scheduledMaxDate = new Date();\n scheduledMaxDate.setFullYear(scheduledMaxDate.getFullYear() + 1);\n\n let sendButtonAriaLabel = 'SendMessage';\n switch (mainButtonState) {\n case MainButtonState.Edit:\n sendButtonAriaLabel = 'Save edited message';\n break;\n case MainButtonState.Record:\n sendButtonAriaLabel = areVoiceMessagesNotAllowed\n ? 'Conversation.DefaultRestrictedMedia'\n : 'AccDescrVoiceMessage';\n }\n\n const className = buildClassName(\n 'Composer',\n !isSelectModeActive && 'shown',\n isHoverDisabled && 'hover-disabled',\n );\n\n const symbolMenuButtonClassName = buildClassName(\n 'mobile-symbol-menu-button',\n !isReady && 'not-ready',\n isSymbolMenuLoaded\n ? (isSymbolMenuOpen && 'menu-opened')\n : (isSymbolMenuOpen && 'is-loading'),\n );\n\n const onSend = mainButtonState === MainButtonState.Edit\n ? handleEditComplete\n : (shouldSchedule ? openCalendar : handleSend);\n\n return (\n <div className={className}>\n {allowedAttachmentOptions.canAttachMedia && isReady && (\n <Portal containerId=\"#middle-column-portals\">\n <DropArea\n isOpen={dropAreaState !== DropAreaState.None}\n withQuick={[dropAreaState, prevDropAreaState].includes(DropAreaState.QuickFile)}\n onHide={onDropHide}\n onFileSelect={handleFileSelect}\n />\n </Portal>\n )}\n <AttachmentModal\n attachments={attachments}\n caption={attachments.length ? html : ''}\n groupChatMembers={groupChatMembers}\n currentUserId={currentUserId}\n usersById={usersById}\n recentEmojis={recentEmojis}\n isReady={isReady}\n onCaptionUpdate={setHtml}\n baseEmojiKeywords={baseEmojiKeywords}\n emojiKeywords={emojiKeywords}\n addRecentEmoji={addRecentEmoji}\n onSend={shouldSchedule ? openCalendar : handleSend}\n onFileAppend={handleAppendFiles}\n onClear={handleClearAttachment}\n />\n <PollModal\n isOpen={Boolean(isPollModalOpen)}\n onClear={closePollModal}\n onSend={handlePollSend}\n />\n <PaymentModal\n isOpen={Boolean(isPaymentModalOpen)}\n onClose={closePaymentModal}\n />\n <ReceiptModal\n isOpen={Boolean(isReceiptModalOpen)}\n onClose={clearReceipt}\n />\n {renderedEditedMessage && (\n <DeleteMessageModal\n isOpen={isDeleteModalOpen}\n isSchedule={messageListType === 'scheduled'}\n onClose={closeDeleteModal}\n message={renderedEditedMessage}\n />\n )}\n <MentionTooltip\n isOpen={isMentionTooltipOpen}\n filter={mentionFilter}\n onClose={closeMentionTooltip}\n onInsertUserName={insertMention}\n filteredUsers={mentionFilteredUsers}\n usersById={usersById}\n />\n <InlineBotTooltip\n isOpen={isInlineBotTooltipOpen}\n botId={inlineBotId}\n allowedAttachmentOptions={allowedAttachmentOptions}\n isGallery={isInlineBotTooltipGallery}\n inlineBotResults={inlineBotResults}\n switchPm={inlineBotSwitchPm}\n onSelectResult={handleInlineBotSelect}\n loadMore={loadMoreForInlineBot}\n onClose={closeInlineBotTooltip}\n />\n <div id=\"message-compose\">\n <div className=\"svg-appendix\" ref={appendixRef} />\n <ComposerEmbeddedMessage />\n <WebPagePreview\n chatId={chatId}\n threadId={threadId}\n messageText={!attachments.length ? html : ''}\n disabled={!allowedAttachmentOptions.canAttachEmbedLinks}\n />\n <div className=\"message-input-wrapper\">\n {IS_SINGLE_COLUMN_LAYOUT ? (\n <Button\n className={symbolMenuButtonClassName}\n round\n color=\"translucent\"\n onClick={isSymbolMenuOpen ? closeSymbolMenu : handleSymbolMenuOpen}\n ariaLabel=\"Choose emoji, sticker or GIF\"\n >\n <i className=\"icon-smile\" />\n <i className=\"icon-keyboard\" />\n {isSymbolMenuOpen && !isSymbolMenuLoaded && <Spinner color=\"gray\" />}\n </Button>\n ) : (\n <ResponsiveHoverButton\n className={`${isSymbolMenuOpen ? 'activated' : ''}`}\n round\n faded\n color=\"translucent\"\n onActivate={openSymbolMenu}\n ariaLabel=\"Choose emoji, sticker or GIF\"\n >\n <i className=\"icon-smile\" />\n </ResponsiveHoverButton>\n )}\n <MessageInput\n id=\"message-input-text\"\n html={!attachments.length ? html : ''}\n placeholder={\n activeVoiceRecording && windowWidth <= SCREEN_WIDTH_TO_HIDE_PLACEHOLDER ? '' : lang('Message')\n }\n forcedPlaceholder={inlineBotHelp}\n shouldSetFocus={isSymbolMenuOpen}\n shouldSuppressFocus={IS_SINGLE_COLUMN_LAYOUT && isSymbolMenuOpen}\n shouldSuppressTextFormatter={isEmojiTooltipOpen || isMentionTooltipOpen || isInlineBotTooltipOpen}\n onUpdate={setHtml}\n onSend={onSend}\n onSuppressedFocus={closeSymbolMenu}\n />\n {isInlineBotLoading && Boolean(inlineBotId) && (\n <Spinner color=\"gray\" />\n )}\n {withScheduledButton && (\n <Button\n round\n faded\n className=\"scheduled-button\"\n color=\"translucent\"\n onClick={handleAllScheduledClick}\n ariaLabel=\"Open scheduled messages\"\n >\n <i className=\"icon-schedule\" />\n </Button>\n )}\n {botKeyboardMessageId && !activeVoiceRecording && !editingMessage && (\n <ResponsiveHoverButton\n className={`${isBotKeyboardOpen ? 'activated' : ''}`}\n round\n faded\n color=\"translucent\"\n onActivate={openBotKeyboard}\n ariaLabel=\"Open bot command keyboard\"\n >\n <i className=\"icon-bot-command\" />\n </ResponsiveHoverButton>\n )}\n {!activeVoiceRecording && !editingMessage && (\n <ResponsiveHoverButton\n className={`${isAttachMenuOpen ? 'activated' : ''}`}\n round\n faded\n color=\"translucent\"\n onActivate={openAttachMenu}\n ariaLabel=\"Add an attachment\"\n >\n <i className=\"icon-attach\" />\n </ResponsiveHoverButton>\n )}\n {activeVoiceRecording && currentRecordTime && (\n <span className=\"recording-state\">\n {formatVoiceRecordDuration(currentRecordTime - startRecordTimeRef.current!)}\n </span>\n )}\n <StickerTooltip\n isOpen={isStickerTooltipOpen}\n onStickerSelect={handleStickerSelect}\n />\n <EmojiTooltip\n isOpen={isEmojiTooltipOpen}\n emojis={filteredEmojis}\n onClose={closeEmojiTooltip}\n onEmojiSelect={insertEmoji}\n addRecentEmoji={addRecentEmoji}\n />\n <AttachMenu\n isOpen={isAttachMenuOpen}\n allowedAttachmentOptions={allowedAttachmentOptions}\n onFileSelect={handleFileSelect}\n onPollCreate={openPollModal}\n onClose={closeAttachMenu}\n />\n {botKeyboardMessageId && (\n <BotKeyboardMenu\n messageId={botKeyboardMessageId}\n isOpen={isBotKeyboardOpen}\n onClose={closeBotKeyboard}\n />\n )}\n <SymbolMenu\n isOpen={isSymbolMenuOpen}\n allowedAttachmentOptions={allowedAttachmentOptions}\n onLoad={onSymbolMenuLoadingComplete}\n onClose={closeSymbolMenu}\n onEmojiSelect={insertTextAndUpdateCursor}\n onStickerSelect={handleStickerSelect}\n onGifSelect={handleGifSelect}\n onRemoveSymbol={removeSymbol}\n onSearchOpen={handleSearchOpen}\n addRecentEmoji={addRecentEmoji}\n />\n </div>\n </div>\n {activeVoiceRecording && (\n <Button\n round\n color=\"danger\"\n className=\"cancel\"\n onClick={stopRecordingVoice}\n ariaLabel=\"Cancel voice recording\"\n >\n <i className=\"icon-delete\" />\n </Button>\n )}\n <Button\n ref={mainButtonRef}\n round\n color=\"secondary\"\n className={buildClassName(mainButtonState, !isReady && 'not-ready', activeVoiceRecording && 'recording')}\n disabled={areVoiceMessagesNotAllowed}\n ariaLabel={lang(sendButtonAriaLabel)}\n onClick={mainButtonHandler}\n onContextMenu={\n mainButtonState === MainButtonState.Send && canShowCustomSendMenu ? handleContextMenu : undefined\n }\n >\n <i className=\"icon-send\" />\n <i className=\"icon-microphone-alt\" />\n <i className=\"icon-check\" />\n </Button>\n {canShowCustomSendMenu && (\n <CustomSendMenu\n isOpen={isCustomSendMenuOpen}\n onSilentSend={!isChatWithSelf ? handleSilentSend : undefined}\n onScheduleSend={!shouldSchedule ? openCalendar : undefined}\n onClose={handleContextMenuClose}\n onCloseAnimationEnd={handleContextMenuHide}\n />\n )}\n <CalendarModal\n isOpen={isCalendarOpen}\n withTimePicker\n selectedAt={scheduledDefaultDate.getTime()}\n maxAt={getDayStartAt(scheduledMaxDate)}\n isFutureMode\n secondButtonLabel={canScheduleUntilOnline ? 'Send When Online' : undefined}\n onClose={handleCloseCalendar}\n onSubmit={handleMessageSchedule}\n onSecondButtonClick={canScheduleUntilOnline ? handleMessageScheduleUntilOnline : undefined}\n />\n </div>\n );\n};\n\nexport default memo(withGlobal<OwnProps>(\n (global, { chatId, threadId, messageListType }): StateProps => {\n const chat = selectChat(global, chatId);\n const chatUser = chat && selectChatUser(global, chat);\n const isChatWithBot = chat ? selectIsChatWithBot(global, chat) : undefined;\n const isChatWithSelf = selectIsChatWithSelf(global, chatId);\n const messageWithActualBotKeyboard = isChatWithBot && selectNewestMessageWithBotKeyboardButtons(global, chatId);\n const scheduledIds = selectScheduledIds(global, chatId);\n const { language } = global.settings.byKey;\n const baseEmojiKeywords = global.emojiKeywords[BASE_EMOJI_KEYWORD_LANG];\n const emojiKeywords = language !== BASE_EMOJI_KEYWORD_LANG ? global.emojiKeywords[language] : undefined;\n\n return {\n editingMessage: selectEditingMessage(global, chatId, threadId, messageListType),\n connectionState: global.connectionState,\n draft: selectDraft(global, chatId, threadId),\n chat,\n isChatWithBot,\n isChatWithSelf,\n canScheduleUntilOnline: (\n !isChatWithSelf && !isChatWithBot\n && (chat && chatUser && isChatPrivate(chatId) && chatUser.status && Boolean(chatUser.status.wasOnline))\n ),\n isRightColumnShown: selectIsRightColumnShown(global),\n isSelectModeActive: selectIsInSelectMode(global),\n withScheduledButton: (\n threadId === MAIN_THREAD_ID\n && messageListType === 'thread'\n && Boolean(scheduledIds && scheduledIds.length)\n ),\n shouldSchedule: messageListType === 'scheduled',\n botKeyboardMessageId: messageWithActualBotKeyboard ? messageWithActualBotKeyboard.id : undefined,\n isForwarding: chatId === global.forwardMessages.toChatId,\n isPollModalOpen: global.isPollModalOpen,\n stickersForEmoji: global.stickers.forEmoji.stickers,\n groupChatMembers: chat && chat.fullInfo && chat.fullInfo.members,\n topInlineBotIds: global.topInlineBots && global.topInlineBots.userIds,\n currentUserId: global.currentUserId,\n usersById: global.users.byId,\n lastSyncTime: global.lastSyncTime,\n contentToBeScheduled: global.messages.contentToBeScheduled,\n isPaymentModalOpen: global.payment.isPaymentModalOpen,\n isReceiptModalOpen: Boolean(global.payment.receipt),\n shouldSuggestStickers: global.settings.byKey.shouldSuggestStickers,\n recentEmojis: global.recentEmojis,\n baseEmojiKeywords: baseEmojiKeywords ? baseEmojiKeywords.keywords : undefined,\n emojiKeywords: emojiKeywords ? emojiKeywords.keywords : undefined,\n serverTimeOffset: global.serverTimeOffset,\n inlineBots: global.inlineBots.byUsername,\n isInlineBotLoading: global.inlineBots.isLoading,\n };\n },\n (setGlobal, actions): DispatchProps => pick(actions, [\n 'sendMessage',\n 'editMessage',\n 'saveDraft',\n 'clearDraft',\n 'showDialog',\n 'setStickerSearchQuery',\n 'setGifSearchQuery',\n 'forwardMessages',\n 'openPollModal',\n 'closePollModal',\n 'closePaymentModal',\n 'clearReceipt',\n 'loadScheduledHistory',\n 'openChat',\n 'addRecentEmoji',\n 'sendInlineBotResult',\n ]),\n)(Composer));\n","import {\n useCallback, useEffect, useRef, useState,\n} from '../../../../lib/teact/teact';\n\nimport { IS_IOS, IS_VOICE_RECORDING_SUPPORTED } from '../../../../util/environment';\nimport * as voiceRecording from '../../../../util/voiceRecording';\nimport captureEscKeyListener from '../../../../util/captureEscKeyListener';\n\ntype ActiveVoiceRecording = { stop: () => Promise<voiceRecording.Result>; pause: NoneToVoidFunction } | undefined;\n\nexport default () => {\n // eslint-disable-next-line no-null/no-null\n const recordButtonRef = useRef<HTMLButtonElement>(null);\n const [activeVoiceRecording, setActiveVoiceRecording] = useState<ActiveVoiceRecording>();\n const startRecordTimeRef = useRef<number>();\n const [currentRecordTime, setCurrentRecordTime] = useState<number | undefined>();\n\n useEffect(() => {\n // Preloading worker fixes silent first record on iOS\n if (IS_IOS && IS_VOICE_RECORDING_SUPPORTED) {\n void voiceRecording.init();\n }\n }, []);\n\n const startRecordingVoice = useCallback(async () => {\n try {\n const { stop, pause } = await voiceRecording.start((tickVolume: number) => {\n if (recordButtonRef.current) {\n if (startRecordTimeRef.current && Date.now() % 4 === 0) {\n recordButtonRef.current.style.boxShadow = `0 0 0 ${(tickVolume || 0) * 50}px rgba(0,0,0,.15)`;\n }\n setCurrentRecordTime(Date.now());\n }\n });\n startRecordTimeRef.current = Date.now();\n setCurrentRecordTime(Date.now());\n\n setActiveVoiceRecording({ stop, pause });\n } catch (err) {\n // eslint-disable-next-line no-console\n console.error(err);\n }\n }, []);\n\n const pauseRecordingVoice = useCallback(() => {\n if (!activeVoiceRecording) {\n return undefined;\n }\n\n if (recordButtonRef.current) {\n recordButtonRef.current.style.boxShadow = 'none';\n }\n\n try {\n return activeVoiceRecording!.pause();\n } catch (err) {\n // eslint-disable-next-line no-console\n console.error(err);\n return undefined;\n }\n }, [activeVoiceRecording]);\n\n const stopRecordingVoice = useCallback(() => {\n if (!activeVoiceRecording) {\n return undefined;\n }\n\n setActiveVoiceRecording(undefined);\n startRecordTimeRef.current = undefined;\n setCurrentRecordTime(undefined);\n if (recordButtonRef.current) {\n recordButtonRef.current.style.boxShadow = 'none';\n }\n try {\n return activeVoiceRecording!.stop();\n } catch (err) {\n // eslint-disable-next-line no-console\n console.error(err);\n return undefined;\n }\n }, [activeVoiceRecording]);\n\n useEffect(() => {\n return activeVoiceRecording ? captureEscKeyListener(stopRecordingVoice) : undefined;\n }, [activeVoiceRecording, stopRecordingVoice]);\n\n return {\n startRecordingVoice,\n pauseRecordingVoice,\n stopRecordingVoice,\n activeVoiceRecording,\n currentRecordTime,\n recordButtonRef,\n startRecordTimeRef,\n };\n};\n","import { useEffect } from '../../../../lib/teact/teact';\nimport { getDispatch } from '../../../../lib/teact/teactn';\n\nimport { ApiSticker } from '../../../../api/types';\n\nimport { IS_EMOJI_SUPPORTED } from '../../../../util/environment';\n\nimport parseEmojiOnlyString from '../../../common/helpers/parseEmojiOnlyString';\n\nexport default function useStickerTooltip(\n isAllowed: boolean,\n html: string,\n stickers?: ApiSticker[],\n isDisabled = false,\n) {\n const { loadStickersForEmoji, clearStickersForEmoji } = getDispatch();\n const isSingleEmoji = (\n (IS_EMOJI_SUPPORTED && parseEmojiOnlyString(html) === 1)\n || (!IS_EMOJI_SUPPORTED && Boolean(html.match(/^<img.[^>]*?>$/g)))\n );\n const hasStickers = Boolean(stickers) && isSingleEmoji;\n\n useEffect(() => {\n if (isDisabled) return;\n\n if (isAllowed && isSingleEmoji) {\n loadStickersForEmoji({ emoji: html });\n } else if (hasStickers || !isSingleEmoji) {\n clearStickersForEmoji();\n }\n // We omit `hasStickers` here to prevent re-fetching after manually closing tooltip (via <Esc>).\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [html, isSingleEmoji, clearStickersForEmoji, loadStickersForEmoji, isAllowed, isDisabled]);\n\n return {\n isStickerTooltipOpen: hasStickers,\n closeStickerTooltip: clearStickersForEmoji,\n };\n}\n","export default function insertHtmlInSelection(html: string) {\n const selection = window.getSelection();\n\n if (selection && selection.getRangeAt && selection.rangeCount) {\n const range = selection.getRangeAt(0);\n range.deleteContents();\n\n const fragment = range.createContextualFragment(html);\n const lastInsertedNode = fragment.lastChild;\n range.insertNode(fragment);\n if (lastInsertedNode) {\n range.setStartAfter(lastInsertedNode);\n range.setEndAfter(lastInsertedNode);\n } else {\n range.collapse(false);\n }\n selection.removeAllRanges();\n selection.addRange(range);\n }\n}\n","export default function deleteLastCharacterOutsideSelection(html: string) {\n const tempInput = document.createElement('div');\n tempInput.contentEditable = 'true';\n tempInput.style.position = 'absolute';\n tempInput.style.left = '-10000px';\n tempInput.style.top = '-10000px';\n tempInput.innerHTML = html;\n document.body.appendChild(tempInput);\n let element = tempInput.lastChild!;\n\n if (element.lastChild) {\n // Selects the last and the deepest child of the element.\n while (element.lastChild) {\n element = element.lastChild;\n }\n }\n\n // Gets length of the element's content.\n const textLength = element.textContent!.length;\n const range = document.createRange();\n const selection = window.getSelection()!;\n\n // Sets selection position to the end of the element.\n range.setStart(element, textLength);\n range.setEnd(element, textLength);\n selection.removeAllRanges();\n selection.addRange(range);\n document.execCommand('delete', false);\n\n const result = tempInput.innerHTML;\n document.body.removeChild(tempInput);\n\n return result;\n}\n","import { useCallback, useEffect } from '../../../../lib/teact/teact';\n\nimport { ApiMessage } from '../../../../api/types';\nimport { GlobalActions } from '../../../../global/types';\n\nimport { EDITABLE_INPUT_ID } from '../../../../config';\nimport parseMessageInput from '../helpers/parseMessageInput';\nimport getMessageTextAsHtml from '../helpers/getMessageTextAsHtml';\nimport focusEditableElement from '../../../../util/focusEditableElement';\nimport { hasMessageMedia } from '../../../../modules/helpers';\n\nexport default (\n htmlRef: { current: string },\n setHtml: (html: string) => void,\n editedMessage: ApiMessage | undefined,\n resetComposer: () => void,\n openDeleteModal: () => void,\n editMessage: GlobalActions['editMessage'],\n) => {\n // TODO useOnChange\n // Handle editing message\n useEffect(() => {\n if (!editedMessage) {\n setHtml('');\n return;\n }\n\n setHtml(getMessageTextAsHtml(editedMessage.content.text));\n\n requestAnimationFrame(() => {\n const messageInput = document.getElementById(EDITABLE_INPUT_ID)!;\n focusEditableElement(messageInput, true);\n });\n }, [editedMessage, setHtml]);\n\n const handleEditComplete = useCallback(() => {\n const { text, entities } = parseMessageInput(htmlRef.current!);\n\n if (!editedMessage) {\n return;\n }\n\n if (!text && !hasMessageMedia(editedMessage)) {\n openDeleteModal();\n return;\n }\n\n editMessage({\n messageId: editedMessage.id,\n text,\n entities,\n });\n\n resetComposer();\n }, [editMessage, editedMessage, htmlRef, openDeleteModal, resetComposer]);\n\n return handleEditComplete;\n};\n","import React, { FC, memo } from '../../lib/teact/teact';\nimport { OwnProps } from './MobileSearch';\nimport { Bundles } from '../../util/moduleLoader';\n\nimport useModuleLoader from '../../hooks/useModuleLoader';\n\nconst MobileSearchAsync: FC<OwnProps> = (props) => {\n const { isActive } = props;\n const MobileSearch = useModuleLoader(Bundles.Extra, 'MobileSearch', !isActive, true);\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return MobileSearch ? <MobileSearch {...props} /> : undefined;\n};\n\nexport default memo(MobileSearchAsync);\n","import React, { FC, memo } from '../../lib/teact/teact';\nimport { Bundles } from '../../util/moduleLoader';\nimport { OwnProps } from './MessageSelectToolbar';\n\nimport useModuleLoader from '../../hooks/useModuleLoader';\n\nconst MessageSelectToolbarAsync: FC<OwnProps> = (props) => {\n const { isActive } = props;\n const MessageSelectToolbar = useModuleLoader(Bundles.Extra, 'MessageSelectToolbar', !isActive);\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return MessageSelectToolbar ? <MessageSelectToolbar {...props} /> : undefined;\n};\n\nexport default memo(MessageSelectToolbarAsync);\n","import React, { FC, memo } from '../../lib/teact/teact';\nimport { OwnProps } from './UnpinAllMessagesModal';\nimport { Bundles } from '../../util/moduleLoader';\n\nimport useModuleLoader from '../../hooks/useModuleLoader';\n\nconst UnpinAllMessagesModalAsync: FC<OwnProps> = (props) => {\n const { isOpen } = props;\n const UnpinAllMessagesModal = useModuleLoader(Bundles.Extra, 'UnpinAllMessagesModal', !isOpen);\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return UnpinAllMessagesModal ? <UnpinAllMessagesModal {...props} /> : undefined;\n};\n\nexport default memo(UnpinAllMessagesModalAsync);\n","import React, {\n FC, useEffect, useState, memo, useMemo, useCallback,\n} from '../../lib/teact/teact';\nimport { withGlobal } from '../../lib/teact/teactn';\n\nimport { ApiChatBannedRights, MAIN_THREAD_ID } from '../../api/types';\nimport { GlobalActions, MessageListType, MessageList as GlobalMessageList } from '../../global/types';\nimport { ThemeKey } from '../../types';\n\nimport {\n MIN_SCREEN_WIDTH_FOR_STATIC_LEFT_COLUMN,\n MOBILE_SCREEN_MAX_WIDTH,\n MIN_SCREEN_WIDTH_FOR_STATIC_RIGHT_COLUMN,\n SAFE_SCREEN_WIDTH_FOR_STATIC_RIGHT_COLUMN,\n SAFE_SCREEN_WIDTH_FOR_CHAT_INFO,\n CONTENT_TYPES_FOR_QUICK_UPLOAD,\n ANIMATION_LEVEL_MAX,\n ANIMATION_END_DELAY,\n DARK_THEME_BG_COLOR,\n LIGHT_THEME_BG_COLOR,\n ANIMATION_LEVEL_MIN,\n} from '../../config';\nimport {\n IS_SINGLE_COLUMN_LAYOUT,\n IS_TABLET_COLUMN_LAYOUT,\n IS_TOUCH_ENV,\n MASK_IMAGE_DISABLED,\n} from '../../util/environment';\nimport { DropAreaState } from './composer/DropArea';\nimport {\n selectChat,\n selectCurrentMessageList,\n selectCurrentTextSearch,\n selectIsChatBotNotStarted,\n selectIsInSelectMode,\n selectIsRightColumnShown,\n selectPinnedIds,\n selectTheme,\n} from '../../modules/selectors';\nimport { getCanPostInChat, getMessageSendingRestrictionReason, isChatPrivate } from '../../modules/helpers';\nimport captureEscKeyListener from '../../util/captureEscKeyListener';\nimport { pick } from '../../util/iteratees';\nimport buildClassName from '../../util/buildClassName';\nimport useCustomBackground from '../../hooks/useCustomBackground';\nimport useWindowSize from '../../hooks/useWindowSize';\nimport usePrevDuringAnimation from '../../hooks/usePrevDuringAnimation';\nimport calculateMiddleFooterTransforms from './helpers/calculateMiddleFooterTransforms';\nimport useLang from '../../hooks/useLang';\nimport useHistoryBack from '../../hooks/useHistoryBack';\nimport { createMessageHash } from '../../util/routing';\n\nimport Transition from '../ui/Transition';\nimport MiddleHeader from './MiddleHeader';\nimport MessageList from './MessageList';\nimport ScrollDownButton from './ScrollDownButton';\nimport Composer from './composer/Composer';\nimport Button from '../ui/Button';\nimport MobileSearch from './MobileSearch.async';\nimport MessageSelectToolbar from './MessageSelectToolbar.async';\nimport UnpinAllMessagesModal from '../common/UnpinAllMessagesModal.async';\n\nimport './MiddleColumn.scss';\n\ntype StateProps = {\n chatId?: number;\n threadId?: number;\n messageListType?: MessageListType;\n isPrivate?: boolean;\n isPinnedMessageList?: boolean;\n isScheduledMessageList?: boolean;\n canPost?: boolean;\n currentUserBannedRights?: ApiChatBannedRights;\n defaultBannedRights?: ApiChatBannedRights;\n hasPinnedOrAudioMessage?: boolean;\n pinnedMessagesCount?: number;\n theme: ThemeKey;\n customBackground?: string;\n backgroundColor?: string;\n patternColor?: string;\n isLeftColumnShown?: boolean;\n isRightColumnShown?: boolean;\n isBackgroundBlurred?: boolean;\n isMobileSearchActive?: boolean;\n isSelectModeActive?: boolean;\n animationLevel?: number;\n shouldSkipHistoryAnimations?: boolean;\n currentTransitionKey: number;\n messageLists?: GlobalMessageList[];\n};\n\ntype DispatchProps = Pick<GlobalActions, (\n 'openChat' | 'unpinAllMessages' | 'loadUser' | 'closeLocalTextSearch' | 'exitMessageSelectMode'\n)>;\n\nconst CLOSE_ANIMATION_DURATION = IS_SINGLE_COLUMN_LAYOUT ? 450 + ANIMATION_END_DELAY : undefined;\n\nfunction canBeQuicklyUploaded(item: DataTransferItem) {\n return item.kind === 'file' && item.type && CONTENT_TYPES_FOR_QUICK_UPLOAD.has(item.type);\n}\n\nconst MiddleColumn: FC<StateProps & DispatchProps> = ({\n chatId,\n threadId,\n messageListType,\n isPrivate,\n isPinnedMessageList,\n messageLists,\n canPost,\n currentUserBannedRights,\n defaultBannedRights,\n hasPinnedOrAudioMessage,\n pinnedMessagesCount,\n customBackground,\n theme,\n backgroundColor,\n patternColor,\n isLeftColumnShown,\n isRightColumnShown,\n isBackgroundBlurred,\n isMobileSearchActive,\n isSelectModeActive,\n animationLevel,\n shouldSkipHistoryAnimations,\n currentTransitionKey,\n openChat,\n unpinAllMessages,\n loadUser,\n closeLocalTextSearch,\n exitMessageSelectMode,\n}) => {\n const { width: windowWidth } = useWindowSize();\n\n const lang = useLang();\n const [dropAreaState, setDropAreaState] = useState(DropAreaState.None);\n const [isFabShown, setIsFabShown] = useState<boolean | undefined>();\n const [isNotchShown, setIsNotchShown] = useState<boolean | undefined>();\n const [isUnpinModalOpen, setIsUnpinModalOpen] = useState(false);\n const [isReady, setIsReady] = useState(!IS_SINGLE_COLUMN_LAYOUT || animationLevel === ANIMATION_LEVEL_MIN);\n\n const hasTools = hasPinnedOrAudioMessage && (\n windowWidth < MOBILE_SCREEN_MAX_WIDTH\n || (\n isRightColumnShown && windowWidth > MIN_SCREEN_WIDTH_FOR_STATIC_RIGHT_COLUMN\n && windowWidth < SAFE_SCREEN_WIDTH_FOR_STATIC_RIGHT_COLUMN\n ) || (\n windowWidth >= MIN_SCREEN_WIDTH_FOR_STATIC_LEFT_COLUMN\n && windowWidth < SAFE_SCREEN_WIDTH_FOR_CHAT_INFO\n )\n );\n\n const renderingChatId = usePrevDuringAnimation(chatId, CLOSE_ANIMATION_DURATION);\n const renderingThreadId = usePrevDuringAnimation(threadId, CLOSE_ANIMATION_DURATION);\n const renderingMessageListType = usePrevDuringAnimation(messageListType, CLOSE_ANIMATION_DURATION);\n const renderingCanPost = usePrevDuringAnimation(canPost, CLOSE_ANIMATION_DURATION);\n const renderingHasTools = usePrevDuringAnimation(hasTools, CLOSE_ANIMATION_DURATION);\n const renderingIsFabShown = usePrevDuringAnimation(isFabShown, CLOSE_ANIMATION_DURATION);\n\n useEffect(() => {\n return chatId\n ? captureEscKeyListener(() => {\n openChat({ id: undefined });\n })\n : undefined;\n }, [chatId, openChat]);\n\n useEffect(() => {\n setDropAreaState(DropAreaState.None);\n setIsFabShown(undefined);\n setIsNotchShown(undefined);\n }, [chatId]);\n\n useEffect(() => {\n if (animationLevel === ANIMATION_LEVEL_MIN) {\n setIsReady(true);\n }\n }, [animationLevel]);\n\n const handleTransitionEnd = (e: React.TransitionEvent<HTMLDivElement>) => {\n if (e.propertyName === 'transform' && e.target === e.currentTarget) {\n setIsReady(Boolean(chatId));\n }\n };\n\n useEffect(() => {\n if (isPrivate) {\n loadUser({ userId: chatId });\n }\n }, [chatId, isPrivate, loadUser]);\n\n const handleDragEnter = useCallback((e: React.DragEvent<HTMLDivElement>) => {\n if (IS_TOUCH_ENV) {\n return;\n }\n\n const { items } = e.dataTransfer || {};\n const shouldDrawQuick = items && Array.from(items)\n // Filter unnecessary element for drag and drop images in Firefox (https://github.com/Ajaxy/telegram-tt/issues/49)\n // https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/Recommended_drag_types#image\n .filter((item) => item.type !== 'text/uri-list')\n .every(canBeQuicklyUploaded);\n\n setDropAreaState(shouldDrawQuick ? DropAreaState.QuickFile : DropAreaState.Document);\n }, []);\n\n const handleHideDropArea = useCallback(() => {\n setDropAreaState(DropAreaState.None);\n }, []);\n\n const handleOpenUnpinModal = useCallback(() => {\n setIsUnpinModalOpen(true);\n }, []);\n\n const closeUnpinModal = useCallback(() => {\n setIsUnpinModalOpen(false);\n }, []);\n\n const handleUnpinAllMessages = useCallback(() => {\n unpinAllMessages({ chatId });\n closeUnpinModal();\n openChat({ id: chatId });\n }, [unpinAllMessages, openChat, closeUnpinModal, chatId]);\n\n const handleTabletFocus = useCallback(() => {\n openChat({ id: chatId });\n }, [openChat, chatId]);\n\n const customBackgroundValue = useCustomBackground(theme, customBackground);\n\n const className = buildClassName(\n renderingHasTools && 'has-header-tools',\n customBackground && 'custom-bg-image',\n backgroundColor && 'custom-bg-color',\n customBackground && isBackgroundBlurred && 'blurred',\n MASK_IMAGE_DISABLED ? 'mask-image-disabled' : 'mask-image-enabled',\n );\n\n const messagingDisabledClassName = buildClassName(\n 'messaging-disabled',\n !isSelectModeActive && 'shown',\n );\n\n\n const messageSendingRestrictionReason = getMessageSendingRestrictionReason(\n lang, currentUserBannedRights, defaultBannedRights,\n );\n\n // CSS Variables calculation doesn't work properly with transforms, so we calculate transform values in JS\n const {\n composerHiddenScale, toolbarHiddenScale,\n composerTranslateX, toolbarTranslateX,\n unpinHiddenScale, toolbarForUnpinHiddenScale,\n } = useMemo(\n () => calculateMiddleFooterTransforms(windowWidth, renderingCanPost),\n [renderingCanPost, windowWidth],\n );\n\n const footerClassName = buildClassName(\n 'middle-column-footer',\n !renderingCanPost && 'no-composer',\n renderingCanPost && isNotchShown && !isSelectModeActive && 'with-notch',\n );\n\n const closeChat = () => {\n openChat({ id: undefined }, true);\n };\n\n useHistoryBack(renderingChatId && renderingThreadId,\n closeChat, undefined, undefined, undefined,\n messageLists ? messageLists.map(createMessageHash) : []);\n\n useHistoryBack(isMobileSearchActive, closeLocalTextSearch);\n useHistoryBack(isSelectModeActive, exitMessageSelectMode);\n\n return (\n <div\n id=\"MiddleColumn\"\n className={className}\n onTransitionEnd={handleTransitionEnd}\n // @ts-ignore teact-feature\n style={`\n --composer-hidden-scale: ${composerHiddenScale};\n --toolbar-hidden-scale: ${toolbarHiddenScale};\n --unpin-hidden-scale: ${unpinHiddenScale};\n --toolbar-unpin-hidden-scale: ${toolbarForUnpinHiddenScale};\n --composer-translate-x: ${composerTranslateX}px;\n --toolbar-translate-x: ${toolbarTranslateX}px;\n --pattern-color: ${patternColor};\n --theme-background-color:\n ${backgroundColor || (theme === 'dark' ? DARK_THEME_BG_COLOR : LIGHT_THEME_BG_COLOR)};\n `}\n onClick={(IS_TABLET_COLUMN_LAYOUT && isLeftColumnShown) ? handleTabletFocus : undefined}\n >\n <div\n id=\"middle-column-bg\"\n // @ts-ignore\n style={customBackgroundValue ? `--custom-background: ${customBackgroundValue}` : undefined}\n />\n <div id=\"middle-column-portals\" />\n {renderingChatId && renderingThreadId && (\n <>\n <div className=\"messages-layout\" onDragEnter={renderingCanPost ? handleDragEnter : undefined}>\n <MiddleHeader\n chatId={renderingChatId}\n threadId={renderingThreadId}\n messageListType={renderingMessageListType}\n isReady={isReady}\n />\n <Transition\n name={shouldSkipHistoryAnimations ? 'none' : animationLevel === ANIMATION_LEVEL_MAX ? 'slide' : 'fade'}\n activeKey={currentTransitionKey}\n shouldCleanup\n >\n {() => (\n <>\n <MessageList\n key={`${renderingChatId}-${renderingThreadId}-${renderingMessageListType}`}\n chatId={renderingChatId}\n threadId={renderingThreadId}\n type={renderingMessageListType}\n canPost={renderingCanPost}\n hasTools={renderingHasTools}\n onFabToggle={setIsFabShown}\n onNotchToggle={setIsNotchShown}\n isReady={isReady}\n />\n <div className={footerClassName}>\n {renderingCanPost && (\n <Composer\n chatId={renderingChatId}\n threadId={renderingThreadId}\n messageListType={renderingMessageListType}\n dropAreaState={dropAreaState}\n onDropHide={handleHideDropArea}\n isReady={isReady}\n />\n )}\n {isPinnedMessageList && (\n <div className=\"unpin-button-container\" dir={lang.isRtl ? 'rtl' : undefined}>\n <Button\n size=\"tiny\"\n fluid\n color=\"secondary\"\n className=\"unpin-all-button\"\n onClick={handleOpenUnpinModal}\n >\n <i className=\"icon-unpin\" />\n <span>{lang('Chat.Pinned.UnpinAll', pinnedMessagesCount, 'i')}</span>\n </Button>\n </div>\n )}\n {!isPinnedMessageList && !renderingCanPost && messageSendingRestrictionReason && (\n <div className={messagingDisabledClassName}>\n <div className=\"messaging-disabled-inner\">\n <span>\n {messageSendingRestrictionReason}\n </span>\n </div>\n </div>\n )}\n <MessageSelectToolbar\n messageListType={renderingMessageListType}\n isActive={isSelectModeActive}\n canPost={renderingCanPost}\n />\n </div>\n </>\n )}\n </Transition>\n\n <ScrollDownButton\n isShown={renderingIsFabShown}\n canPost={renderingCanPost}\n />\n </div>\n {IS_SINGLE_COLUMN_LAYOUT && <MobileSearch isActive={Boolean(isMobileSearchActive)} />}\n </>\n )}\n {chatId && (\n <UnpinAllMessagesModal\n isOpen={isUnpinModalOpen}\n chatId={chatId}\n pinnedMessagesCount={pinnedMessagesCount}\n onClose={closeUnpinModal}\n onUnpin={handleUnpinAllMessages}\n />\n )}\n </div>\n );\n};\n\nexport default memo(withGlobal(\n (global): StateProps => {\n const theme = selectTheme(global);\n const {\n isBlurred: isBackgroundBlurred, background: customBackground, backgroundColor, patternColor,\n } = global.settings.themes[theme] || {};\n\n const { messageLists } = global.messages;\n const currentMessageList = selectCurrentMessageList(global);\n const { isLeftColumnShown, chats: { listIds } } = global;\n\n const state: StateProps = {\n theme,\n customBackground,\n backgroundColor,\n patternColor,\n isLeftColumnShown,\n isRightColumnShown: selectIsRightColumnShown(global),\n isBackgroundBlurred,\n isMobileSearchActive: Boolean(IS_SINGLE_COLUMN_LAYOUT && selectCurrentTextSearch(global)),\n isSelectModeActive: selectIsInSelectMode(global),\n animationLevel: global.settings.byKey.animationLevel,\n currentTransitionKey: Math.max(0, global.messages.messageLists.length - 1),\n };\n\n if (!currentMessageList || !listIds.active) {\n return state;\n }\n\n const { chatId, threadId, type: messageListType } = currentMessageList;\n const chat = selectChat(global, chatId);\n const pinnedIds = selectPinnedIds(global, chatId);\n const { chatId: audioChatId, messageId: audioMessageId } = global.audioPlayer;\n\n const canPost = chat && getCanPostInChat(chat, threadId);\n const isBotNotStarted = selectIsChatBotNotStarted(global, chatId);\n const isPinnedMessageList = messageListType === 'pinned';\n const isScheduledMessageList = messageListType === 'scheduled';\n\n return {\n ...state,\n chatId,\n threadId,\n messageListType,\n isPrivate: isChatPrivate(chatId),\n canPost: !isPinnedMessageList && (!chat || canPost) && !isBotNotStarted,\n isPinnedMessageList,\n isScheduledMessageList,\n currentUserBannedRights: chat && chat.currentUserBannedRights,\n defaultBannedRights: chat && chat.defaultBannedRights,\n hasPinnedOrAudioMessage: (\n threadId !== MAIN_THREAD_ID\n || Boolean(pinnedIds && pinnedIds.length)\n || Boolean(audioChatId && audioMessageId)\n ),\n pinnedMessagesCount: pinnedIds ? pinnedIds.length : 0,\n shouldSkipHistoryAnimations: global.shouldSkipHistoryAnimations,\n messageLists,\n };\n },\n (setGlobal, actions): DispatchProps => pick(actions, [\n 'openChat', 'unpinAllMessages', 'loadUser', 'closeLocalTextSearch', 'exitMessageSelectMode',\n ]),\n)(MiddleColumn));\n","import { useEffect, useState } from '../lib/teact/teact';\n\nimport { ThemeKey } from '../types';\n\nimport { CUSTOM_BG_CACHE_NAME } from '../config';\nimport * as cacheApi from '../util/cacheApi';\nimport { preloadImage } from '../util/files';\n\nexport default (theme: ThemeKey, settingValue?: string) => {\n const [value, setValue] = useState(settingValue);\n\n useEffect(() => {\n if (!settingValue) {\n return;\n }\n\n if (settingValue.startsWith('#')) {\n setValue(settingValue);\n } else {\n cacheApi.fetch(CUSTOM_BG_CACHE_NAME, theme, cacheApi.Type.Blob)\n .then((blob) => {\n const url = URL.createObjectURL(blob);\n preloadImage(url)\n .then(() => {\n setValue(`url(${url})`);\n });\n });\n }\n }, [settingValue, theme]);\n\n return settingValue ? value : undefined;\n};\n","import React, {\n FC, memo, useCallback, useEffect, useRef, useState,\n} from '../../lib/teact/teact';\nimport { withGlobal } from '../../lib/teact/teactn';\n\nimport { GlobalActions } from '../../global/types';\nimport { ManagementScreens, ProfileState } from '../../types';\n\nimport { IS_SINGLE_COLUMN_LAYOUT } from '../../util/environment';\nimport { debounce } from '../../util/schedulers';\nimport { pick } from '../../util/iteratees';\nimport buildClassName from '../../util/buildClassName';\nimport {\n selectChat,\n selectCurrentGifSearch,\n selectCurrentStickerSearch,\n selectCurrentTextSearch,\n selectIsChatWithSelf,\n} from '../../modules/selectors';\nimport { isChatAdmin, isChatChannel, isChatPrivate } from '../../modules/helpers';\nimport useCurrentOrPrev from '../../hooks/useCurrentOrPrev';\nimport useLang from '../../hooks/useLang';\n\nimport SearchInput from '../ui/SearchInput';\nimport Button from '../ui/Button';\nimport Transition from '../ui/Transition';\nimport './RightHeader.scss';\nimport { getDayStartAt } from '../../util/dateFormat';\n\ntype OwnProps = {\n chatId?: number;\n isColumnOpen?: boolean;\n isProfile?: boolean;\n isSearch?: boolean;\n isManagement?: boolean;\n isStickerSearch?: boolean;\n isGifSearch?: boolean;\n isPollResults?: boolean;\n isAddingChatMembers?: boolean;\n shouldSkipAnimation?: boolean;\n profileState?: ProfileState;\n managementScreen?: ManagementScreens;\n onClose: () => void;\n};\n\ntype StateProps = {\n canManage?: boolean;\n isChannel?: boolean;\n messageSearchQuery?: string;\n stickerSearchQuery?: string;\n gifSearchQuery?: string;\n};\n\ntype DispatchProps = Pick<GlobalActions, (\n 'setLocalTextSearchQuery' | 'setStickerSearchQuery' | 'setGifSearchQuery' |\n 'searchTextMessagesLocal' | 'toggleManagement' | 'openHistoryCalendar'\n)>;\n\nconst COLUMN_CLOSE_DELAY_MS = 300;\nconst runDebouncedForSearch = debounce((cb) => cb(), 200, false);\n\nenum HeaderContent {\n Profile,\n MemberList,\n SharedMedia,\n Search,\n Management,\n ManageInitial,\n ManageChannelSubscribers,\n ManageChatAdministrators,\n ManageChatPrivacyType,\n ManageDiscussion,\n ManageGroupPermissions,\n ManageGroupRemovedUsers,\n ManageGroupUserPermissionsCreate,\n ManageGroupUserPermissions,\n ManageGroupRecentActions,\n ManageGroupAdminRights,\n ManageGroupMembers,\n StickerSearch,\n GifSearch,\n PollResults,\n AddingMembers,\n}\n\nconst RightHeader: FC<OwnProps & StateProps & DispatchProps> = ({\n isColumnOpen,\n isProfile,\n isSearch,\n isManagement,\n isStickerSearch,\n isGifSearch,\n isPollResults,\n isAddingChatMembers,\n profileState,\n managementScreen,\n canManage,\n isChannel,\n onClose,\n messageSearchQuery,\n stickerSearchQuery,\n gifSearchQuery,\n setLocalTextSearchQuery,\n setStickerSearchQuery,\n setGifSearchQuery,\n searchTextMessagesLocal,\n toggleManagement,\n openHistoryCalendar,\n shouldSkipAnimation,\n}) => {\n // eslint-disable-next-line no-null/no-null\n const backButtonRef = useRef<HTMLDivElement>(null);\n\n const handleMessageSearchQueryChange = useCallback((query: string) => {\n setLocalTextSearchQuery({ query });\n\n if (query.length) {\n runDebouncedForSearch(searchTextMessagesLocal);\n }\n }, [searchTextMessagesLocal, setLocalTextSearchQuery]);\n\n const handleStickerSearchQueryChange = useCallback((query: string) => {\n setStickerSearchQuery({ query });\n }, [setStickerSearchQuery]);\n\n const handleGifSearchQueryChange = useCallback((query: string) => {\n setGifSearchQuery({ query });\n }, [setGifSearchQuery]);\n\n const [shouldSkipTransition, setShouldSkipTransition] = useState(!isColumnOpen);\n\n useEffect(() => {\n setTimeout(() => {\n setShouldSkipTransition(!isColumnOpen);\n }, COLUMN_CLOSE_DELAY_MS);\n }, [isColumnOpen]);\n\n const lang = useLang();\n const contentKey = isProfile ? (\n profileState === ProfileState.Profile ? (\n HeaderContent.Profile\n ) : profileState === ProfileState.SharedMedia ? (\n HeaderContent.SharedMedia\n ) : profileState === ProfileState.MemberList ? (\n HeaderContent.MemberList\n ) : -1 // Never reached\n ) : isSearch ? (\n HeaderContent.Search\n ) : isPollResults ? (\n HeaderContent.PollResults\n ) : isStickerSearch ? (\n HeaderContent.StickerSearch\n ) : isGifSearch ? (\n HeaderContent.GifSearch\n ) : isAddingChatMembers ? (\n HeaderContent.AddingMembers\n ) : isManagement ? (\n managementScreen === ManagementScreens.Initial ? (\n HeaderContent.ManageInitial\n ) : managementScreen === ManagementScreens.ChatPrivacyType ? (\n HeaderContent.ManageChatPrivacyType\n ) : managementScreen === ManagementScreens.Discussion ? (\n HeaderContent.ManageDiscussion\n ) : managementScreen === ManagementScreens.ChannelSubscribers ? (\n HeaderContent.ManageChannelSubscribers\n ) : managementScreen === ManagementScreens.GroupPermissions ? (\n HeaderContent.ManageGroupPermissions\n ) : managementScreen === ManagementScreens.ChatAdministrators ? (\n HeaderContent.ManageChatAdministrators\n ) : managementScreen === ManagementScreens.GroupRemovedUsers ? (\n HeaderContent.ManageGroupRemovedUsers\n ) : managementScreen === ManagementScreens.GroupUserPermissionsCreate ? (\n HeaderContent.ManageGroupUserPermissionsCreate\n ) : managementScreen === ManagementScreens.GroupUserPermissions ? (\n HeaderContent.ManageGroupUserPermissions\n ) : managementScreen === ManagementScreens.GroupRecentActions ? (\n HeaderContent.ManageGroupRecentActions\n ) : managementScreen === ManagementScreens.ChatAdminRights ? (\n HeaderContent.ManageGroupAdminRights\n ) : managementScreen === ManagementScreens.GroupMembers ? (\n HeaderContent.ManageGroupMembers\n ) : undefined // Never reached\n ) : undefined; // When column is closed\n\n const renderingContentKey = useCurrentOrPrev(contentKey, true) ?? -1;\n\n function renderHeaderContent() {\n if (renderingContentKey === -1) {\n return undefined;\n }\n\n switch (renderingContentKey) {\n case HeaderContent.PollResults:\n return <h3>{lang('PollResults')}</h3>;\n case HeaderContent.Search:\n return (\n <>\n <SearchInput\n parentContainerClassName=\"RightSearch\"\n value={messageSearchQuery}\n onChange={handleMessageSearchQueryChange}\n />\n <Button\n round\n size=\"smaller\"\n color=\"translucent\"\n onClick={() => openHistoryCalendar({ selectedAt: getDayStartAt(Date.now()) })}\n ariaLabel=\"Search messages by date\"\n >\n <i className=\"icon-calendar\" />\n </Button>\n </>\n );\n case HeaderContent.AddingMembers:\n return <h3>{lang('GroupAddMembers')}</h3>;\n case HeaderContent.ManageInitial:\n return <h3>{lang('Edit')}</h3>;\n case HeaderContent.ManageChatPrivacyType:\n return <h3>{lang(isChannel ? 'ChannelTypeHeader' : 'GroupTypeHeader')}</h3>;\n case HeaderContent.ManageDiscussion:\n return <h3>{lang('Discussion')}</h3>;\n case HeaderContent.ManageChatAdministrators:\n return <h3>{lang('ChannelAdministrators')}</h3>;\n case HeaderContent.ManageGroupRecentActions:\n return <h3>{lang('Group.Info.AdminLog')}</h3>;\n case HeaderContent.ManageGroupAdminRights:\n return <h3>{lang('EditAdminRights')}</h3>;\n case HeaderContent.ManageGroupPermissions:\n return <h3>{lang('ChannelPermissions')}</h3>;\n case HeaderContent.ManageGroupRemovedUsers:\n return <h3>{lang('ChannelBlockedUsers')}</h3>;\n case HeaderContent.ManageGroupUserPermissionsCreate:\n return <h3>{lang('ChannelAddException')}</h3>;\n case HeaderContent.ManageGroupUserPermissions:\n return <h3>{lang('UserRestrictions')}</h3>;\n case HeaderContent.StickerSearch:\n return (\n <SearchInput\n value={stickerSearchQuery}\n placeholder={lang('SearchStickersHint')}\n onChange={handleStickerSearchQueryChange}\n />\n );\n case HeaderContent.GifSearch:\n return (\n <SearchInput\n value={gifSearchQuery}\n placeholder={lang('SearchGifsTitle')}\n onChange={handleGifSearchQueryChange}\n />\n );\n case HeaderContent.SharedMedia:\n return <h3>{lang('SharedMedia')}</h3>;\n case HeaderContent.ManageChannelSubscribers:\n return <h3>{lang('ChannelSubscribers')}</h3>;\n case HeaderContent.MemberList:\n case HeaderContent.ManageGroupMembers:\n return <h3>{lang('GroupMembers')}</h3>;\n default:\n return (\n <>\n <h3>Profile</h3>\n <section className=\"tools\">\n {canManage && (\n <Button\n round\n color=\"translucent\"\n size=\"smaller\"\n ariaLabel={lang('Edit')}\n onClick={toggleManagement}\n >\n <i className=\"icon-edit\" />\n </Button>\n )}\n </section>\n </>\n );\n }\n }\n\n const isBackButton = (\n IS_SINGLE_COLUMN_LAYOUT\n || contentKey === HeaderContent.SharedMedia\n || contentKey === HeaderContent.MemberList\n || contentKey === HeaderContent.AddingMembers\n || isManagement\n );\n\n const buttonClassName = buildClassName(\n 'animated-close-icon',\n (shouldSkipTransition || shouldSkipAnimation) && 'no-transition',\n );\n\n // Add class in the next AF to synchronize with animation with Transition components\n useEffect(() => {\n backButtonRef.current!.classList.toggle('state-back', isBackButton);\n }, [isBackButton]);\n\n return (\n <div className=\"RightHeader\">\n <Button\n className=\"close-button\"\n round\n color=\"translucent\"\n size=\"smaller\"\n onClick={onClose}\n ariaLabel={isBackButton ? lang('Common.Back') : lang('Common.Close')}\n >\n <div ref={backButtonRef} className={buttonClassName} />\n </Button>\n <Transition\n name={(shouldSkipTransition || shouldSkipAnimation) ? 'none' : 'slide-fade'}\n activeKey={renderingContentKey}\n >\n {renderHeaderContent}\n </Transition>\n </div>\n );\n};\n\nexport default memo(withGlobal<OwnProps>(\n (global, { chatId, isProfile, isManagement }): StateProps => {\n const { query: messageSearchQuery } = selectCurrentTextSearch(global) || {};\n const { query: stickerSearchQuery } = selectCurrentStickerSearch(global) || {};\n const { query: gifSearchQuery } = selectCurrentGifSearch(global) || {};\n const chat = chatId ? selectChat(global, chatId) : undefined;\n const isChannel = chat && isChatChannel(chat);\n\n const canManage = Boolean(\n !isManagement\n && isProfile\n && chat\n && !selectIsChatWithSelf(global, chat.id)\n // chat.isCreator is for Basic Groups\n && (isChatPrivate(chat.id) || ((isChatAdmin(chat) || chat.isCreator) && !chat.isNotJoined)),\n );\n\n return {\n canManage,\n isChannel,\n messageSearchQuery,\n stickerSearchQuery,\n gifSearchQuery,\n };\n },\n (setGlobal, actions): DispatchProps => pick(actions, [\n 'setLocalTextSearchQuery',\n 'setStickerSearchQuery',\n 'setGifSearchQuery',\n 'searchTextMessagesLocal',\n 'toggleManagement',\n 'openHistoryCalendar',\n ]),\n)(RightHeader));\n","import { useMemo, useRef } from '../../../lib/teact/teact';\n\nimport { ApiChatMember, ApiMessage, ApiUser } from '../../../api/types';\nimport { ProfileTabType, SharedMediaType } from '../../../types';\n\nimport { MEMBERS_SLICE, MESSAGE_SEARCH_SLICE, SHARED_MEDIA_SLICE } from '../../../config';\nimport { getMessageContentIds, sortUserIds } from '../../../modules/helpers';\nimport useOnChange from '../../../hooks/useOnChange';\nimport useInfiniteScroll from '../../../hooks/useInfiniteScroll';\n\nexport default function useProfileViewportIds(\n isRightColumnShown: boolean,\n loadMoreMembers: AnyToVoidFunction,\n searchMessages: AnyToVoidFunction,\n tabType: ProfileTabType,\n mediaSearchType?: SharedMediaType,\n groupChatMembers?: ApiChatMember[],\n usersById?: Record<number, ApiUser>,\n chatMessages?: Record<number, ApiMessage>,\n foundIds?: number[],\n chatId?: number,\n lastSyncTime?: number,\n serverTimeOffset = 0,\n) {\n const resultType = tabType === 'members' || !mediaSearchType ? tabType : mediaSearchType;\n\n const memberIds = useMemo(() => {\n if (!groupChatMembers || !usersById) {\n return undefined;\n }\n\n return sortUserIds(groupChatMembers.map(({ userId }) => userId), usersById, undefined, serverTimeOffset);\n }, [groupChatMembers, serverTimeOffset, usersById]);\n\n const [memberViewportIds, getMoreMembers, noProfileInfoForMembers] = useInfiniteScrollForMembers(\n resultType, loadMoreMembers, lastSyncTime, memberIds,\n );\n\n const [mediaViewportIds, getMoreMedia, noProfileInfoForMedia] = useInfiniteScrollForSharedMedia(\n 'media', resultType, searchMessages, lastSyncTime, chatMessages, foundIds,\n );\n\n const [documentViewportIds, getMoreDocuments, noProfileInfoForDocuments] = useInfiniteScrollForSharedMedia(\n 'documents', resultType, searchMessages, lastSyncTime, chatMessages, foundIds,\n );\n\n const [linkViewportIds, getMoreLinks, noProfileInfoForLinks] = useInfiniteScrollForSharedMedia(\n 'links', resultType, searchMessages, lastSyncTime, chatMessages, foundIds,\n );\n\n const [audioViewportIds, getMoreAudio, noProfileInfoForAudio] = useInfiniteScrollForSharedMedia(\n 'audio', resultType, searchMessages, lastSyncTime, chatMessages, foundIds,\n );\n\n let viewportIds: number[] | undefined;\n let getMore: AnyToVoidFunction | undefined;\n let noProfileInfo = false;\n\n switch (resultType) {\n case 'members':\n viewportIds = memberViewportIds;\n getMore = getMoreMembers;\n noProfileInfo = noProfileInfoForMembers;\n break;\n case 'media':\n viewportIds = mediaViewportIds;\n getMore = getMoreMedia;\n noProfileInfo = noProfileInfoForMedia;\n break;\n case 'documents':\n viewportIds = documentViewportIds;\n getMore = getMoreDocuments;\n noProfileInfo = noProfileInfoForDocuments;\n break;\n case 'links':\n viewportIds = linkViewportIds;\n getMore = getMoreLinks;\n noProfileInfo = noProfileInfoForLinks;\n break;\n case 'audio':\n viewportIds = audioViewportIds;\n getMore = getMoreAudio;\n noProfileInfo = noProfileInfoForAudio;\n break;\n }\n\n return [resultType, viewportIds, getMore, noProfileInfo] as const;\n}\n\nfunction useInfiniteScrollForMembers(\n currentResultType?: ProfileTabType,\n handleLoadMore?: AnyToVoidFunction,\n lastSyncTime?: number,\n memberIds?: number[],\n) {\n const [viewportIds, getMore] = useInfiniteScroll(\n lastSyncTime ? handleLoadMore : undefined,\n memberIds,\n undefined,\n MEMBERS_SLICE,\n );\n\n const isOnTop = !viewportIds || !memberIds || viewportIds[0] === memberIds[0];\n\n return [viewportIds, getMore, !isOnTop] as const;\n}\n\nfunction useInfiniteScrollForSharedMedia(\n forSharedMediaType: SharedMediaType,\n currentResultType?: ProfileTabType,\n handleLoadMore?: AnyToVoidFunction,\n lastSyncTime?: number,\n chatMessages?: Record<number, ApiMessage>,\n foundIds?: number[],\n) {\n const messageIdsRef = useRef<number[]>();\n\n useOnChange(() => {\n if (currentResultType === forSharedMediaType && chatMessages && foundIds) {\n messageIdsRef.current = getMessageContentIds(\n chatMessages,\n foundIds,\n forSharedMediaType,\n ).reverse();\n }\n }, [chatMessages, foundIds, currentResultType, forSharedMediaType]);\n\n const [viewportIds, getMore] = useInfiniteScroll(\n lastSyncTime ? handleLoadMore : undefined,\n messageIdsRef.current,\n undefined,\n forSharedMediaType === 'media' ? SHARED_MEDIA_SLICE : MESSAGE_SEARCH_SLICE,\n );\n\n const isOnTop = !viewportIds || !messageIdsRef.current || viewportIds[0] === messageIdsRef.current[0];\n\n return [viewportIds, getMore, !isOnTop] as const;\n}\n","import { useCallback, useEffect } from '../../../lib/teact/teact';\n\nimport { ProfileState } from '../../../types';\n\nimport fastSmoothScroll from '../../../util/fastSmoothScroll';\nimport { throttle } from '../../../util/schedulers';\nimport useEffectWithPrevDeps from '../../../hooks/useEffectWithPrevDeps';\n\nconst TRANSITION_DURATION = 300;\nconst PROGRAMMATIC_SCROLL_TIMEOUT_MS = 350;\n\nconst runThrottledForScroll = throttle((cb) => cb(), 250, false);\n\nlet isScrollingProgrammatically = false;\n\nexport default function useProfileState(\n containerRef: { current: HTMLDivElement | null },\n tabType: string,\n profileState: ProfileState,\n onProfileStateChange: (state: ProfileState) => void,\n) {\n // Scroll to tabs if needed\n useEffectWithPrevDeps(([prevTabType]) => {\n if (prevTabType && prevTabType !== tabType) {\n const container = containerRef.current!;\n const tabsEl = container.querySelector<HTMLDivElement>('.TabList')!;\n if (container.scrollTop < tabsEl.offsetTop) {\n onProfileStateChange(tabType === 'members' ? ProfileState.MemberList : ProfileState.SharedMedia);\n isScrollingProgrammatically = true;\n fastSmoothScroll(container, tabsEl, 'start', undefined, undefined, undefined, TRANSITION_DURATION);\n setTimeout(() => {\n isScrollingProgrammatically = false;\n }, PROGRAMMATIC_SCROLL_TIMEOUT_MS);\n }\n }\n }, [tabType, onProfileStateChange]);\n\n // Scroll to top\n useEffectWithPrevDeps(([prevProfileState]) => {\n if (profileState !== ProfileState.Profile || profileState === prevProfileState) {\n return;\n }\n\n const container = containerRef.current;\n if (!container) {\n return;\n }\n\n const tabListEl = container.querySelector<HTMLDivElement>('.TabList');\n if (!tabListEl || tabListEl.offsetTop > container.scrollTop) {\n return;\n }\n\n isScrollingProgrammatically = true;\n fastSmoothScroll(\n container,\n container.firstElementChild as HTMLElement,\n 'start',\n undefined,\n container.offsetHeight * 2,\n );\n\n setTimeout(() => {\n isScrollingProgrammatically = false;\n }, PROGRAMMATIC_SCROLL_TIMEOUT_MS);\n\n onProfileStateChange(profileState);\n }, [profileState]);\n\n const determineProfileState = useCallback(() => {\n const container = containerRef.current;\n if (!container) {\n return;\n }\n\n const tabListEl = container.querySelector<HTMLDivElement>('.TabList');\n if (!tabListEl) {\n return;\n }\n\n let state: ProfileState = ProfileState.Profile;\n if (container.scrollTop >= tabListEl.offsetTop) {\n state = tabType === 'members'\n ? ProfileState.MemberList\n : ProfileState.SharedMedia;\n }\n\n onProfileStateChange(state);\n }, [containerRef, onProfileStateChange, tabType]);\n\n // Determine profile state when switching tabs\n useEffect(() => {\n if (isScrollingProgrammatically) {\n return;\n }\n\n determineProfileState();\n }, [determineProfileState, tabType]);\n\n // Determine profile state when scrolling\n const handleScroll = useCallback(() => {\n if (isScrollingProgrammatically) {\n return;\n }\n\n runThrottledForScroll(determineProfileState);\n }, [determineProfileState]);\n\n return { handleScroll };\n}\n","import React, { FC, memo } from '../../lib/teact/teact';\n\nimport {\n ApiUser, ApiChat, ApiMediaFormat, ApiPhoto,\n} from '../../api/types';\n\nimport {\n getChatAvatarHash, isDeletedUser, getUserColorKey, getChatTitle, isChatPrivate, getUserFullName,\n} from '../../modules/helpers';\nimport renderText from '../common/helpers/renderText';\nimport buildClassName from '../../util/buildClassName';\nimport { getFirstLetters } from '../../util/textFormat';\nimport useMedia from '../../hooks/useMedia';\nimport useBlurSync from '../../hooks/useBlurSync';\nimport usePrevious from '../../hooks/usePrevious';\nimport useLang from '../../hooks/useLang';\n\nimport Spinner from '../ui/Spinner';\n\nimport './ProfilePhoto.scss';\n\ntype OwnProps = {\n chat?: ApiChat;\n user?: ApiUser;\n isFirstPhoto?: boolean;\n isSavedMessages?: boolean;\n photo?: ApiPhoto;\n lastSyncTime?: number;\n onClick: NoneToVoidFunction;\n};\n\nconst ProfilePhoto: FC<OwnProps> = ({\n chat,\n user,\n photo,\n isFirstPhoto,\n isSavedMessages,\n lastSyncTime,\n onClick,\n}) => {\n const lang = useLang();\n const isDeleted = user && isDeletedUser(user);\n\n function getMediaHash(size: 'normal' | 'big' = 'big', forceAvatar?: boolean) {\n if (photo && !forceAvatar) {\n return `photo${photo.id}?size=c`;\n }\n\n let hash: string | undefined;\n if (!isSavedMessages && !isDeleted) {\n if (user) {\n hash = getChatAvatarHash(user, size);\n } else if (chat) {\n hash = getChatAvatarHash(chat, size);\n }\n }\n\n return hash;\n }\n\n const imageHash = getMediaHash();\n const fullMediaData = useMedia(imageHash, false, ApiMediaFormat.BlobUrl, lastSyncTime);\n const avatarThumbnailData = useMedia(\n !fullMediaData && isFirstPhoto ? getMediaHash('normal', true) : undefined,\n false,\n ApiMediaFormat.BlobUrl,\n lastSyncTime,\n );\n const thumbDataUri = useBlurSync(!fullMediaData && photo && photo.thumbnail && photo.thumbnail.dataUri);\n const imageSrc = fullMediaData || avatarThumbnailData || thumbDataUri;\n const prevImageSrc = usePrevious(imageSrc);\n\n let content: string | undefined = '';\n\n if (isSavedMessages) {\n content = <i className=\"icon-avatar-saved-messages\" />;\n } else if (isDeleted) {\n content = <i className=\"icon-avatar-deleted-account\" />;\n } else if (imageSrc) {\n content = <img src={imageSrc} className=\"avatar-media\" alt=\"\" decoding=\"async\" />;\n } else if (!imageSrc && user) {\n const userFullName = getUserFullName(user);\n content = userFullName ? getFirstLetters(userFullName, 2) : undefined;\n } else if (!imageSrc && chat) {\n const title = getChatTitle(lang, chat);\n content = title && getFirstLetters(title, isChatPrivate(chat.id) ? 2 : 1);\n } else {\n content = (\n <div className=\"spinner-wrapper\">\n <Spinner color=\"white\" />\n </div>\n );\n }\n\n const fullClassName = buildClassName(\n 'ProfilePhoto',\n `color-bg-${getUserColorKey(user || chat)}`,\n isSavedMessages && 'saved-messages',\n isDeleted && 'deleted-account',\n (!isSavedMessages && !(imageSrc)) && 'no-photo',\n );\n\n return (\n <div className={fullClassName} onClick={imageSrc ? onClick : undefined}>\n {prevImageSrc && imageSrc && prevImageSrc !== imageSrc && (\n <img src={prevImageSrc} className=\"prev-avatar-media\" alt=\"\" decoding=\"async\" />\n )}\n {typeof content === 'string' ? renderText(content, ['hq_emoji']) : content}\n </div>\n );\n};\n\nexport default memo(ProfilePhoto);\n","import React, {\n FC, useEffect, useCallback, memo, useState,\n} from '../../lib/teact/teact';\nimport { withGlobal } from '../../lib/teact/teactn';\n\nimport { ApiUser, ApiChat } from '../../api/types';\nimport { GlobalActions, GlobalState } from '../../global/types';\nimport { MediaViewerOrigin } from '../../types';\n\nimport { IS_TOUCH_ENV } from '../../util/environment';\nimport { selectChat, selectUser } from '../../modules/selectors';\nimport {\n getUserFullName, getUserStatus, isChatChannel, isUserOnline,\n} from '../../modules/helpers';\nimport renderText from '../common/helpers/renderText';\nimport { pick } from '../../util/iteratees';\nimport { captureEvents, SwipeDirection } from '../../util/captureEvents';\nimport usePhotosPreload from './hooks/usePhotosPreload';\nimport useLang from '../../hooks/useLang';\n\nimport VerifiedIcon from '../common/VerifiedIcon';\nimport ProfilePhoto from './ProfilePhoto';\nimport Transition from '../ui/Transition';\n\nimport './ProfileInfo.scss';\n\ntype OwnProps = {\n userId: number;\n forceShowSelf?: boolean;\n};\n\ntype StateProps = {\n user?: ApiUser;\n chat?: ApiChat;\n isSavedMessages?: boolean;\n animationLevel: 0 | 1 | 2;\n serverTimeOffset: number;\n} & Pick<GlobalState, 'lastSyncTime'>;\n\ntype DispatchProps = Pick<GlobalActions, 'loadFullUser' | 'openMediaViewer'>;\n\nconst PrivateChatInfo: FC<OwnProps & StateProps & DispatchProps> = ({\n user,\n chat,\n isSavedMessages,\n lastSyncTime,\n animationLevel,\n loadFullUser,\n openMediaViewer,\n serverTimeOffset,\n}) => {\n const { id: userId } = user || {};\n const { id: chatId } = chat || {};\n const fullName = user ? getUserFullName(user) : (chat ? chat.title : '');\n const photos = (user ? user.photos : (chat ? chat.photos : undefined)) || [];\n const slideAnimation = animationLevel >= 1 ? 'slide' : 'none';\n\n const [currentPhotoIndex, setCurrentPhotoIndex] = useState(0);\n const isFirst = isSavedMessages || photos.length <= 1 || currentPhotoIndex === 0;\n const isLast = isSavedMessages || photos.length <= 1 || currentPhotoIndex === photos.length - 1;\n\n // Deleting the last profile photo may result in an error\n useEffect(() => {\n if (currentPhotoIndex > photos.length) {\n setCurrentPhotoIndex(Math.max(0, photos.length - 1));\n }\n }, [currentPhotoIndex, photos.length]);\n\n const lang = useLang();\n\n useEffect(() => {\n if (lastSyncTime && userId) {\n loadFullUser({ userId });\n }\n }, [userId, loadFullUser, lastSyncTime]);\n\n usePhotosPreload(user || chat, photos, currentPhotoIndex);\n\n const handleProfilePhotoClick = useCallback(() => {\n openMediaViewer({\n avatarOwnerId: userId || chatId,\n profilePhotoIndex: currentPhotoIndex,\n origin: MediaViewerOrigin.ProfileAvatar,\n });\n }, [openMediaViewer, userId, chatId, currentPhotoIndex]);\n\n const selectPreviousMedia = useCallback(() => {\n if (isFirst) {\n return;\n }\n\n setCurrentPhotoIndex(currentPhotoIndex - 1);\n }, [currentPhotoIndex, isFirst]);\n\n const selectNextMedia = useCallback(() => {\n if (isLast) {\n return;\n }\n\n setCurrentPhotoIndex(currentPhotoIndex + 1);\n }, [currentPhotoIndex, isLast]);\n\n // Support for swipe gestures and closing on click\n useEffect(() => {\n const element = document.querySelector<HTMLDivElement>('.photo-wrapper');\n if (!element) {\n return undefined;\n }\n\n return captureEvents(element, {\n onSwipe: IS_TOUCH_ENV ? (e, direction) => {\n if (direction === SwipeDirection.Right) {\n selectPreviousMedia();\n } else if (direction === SwipeDirection.Left) {\n selectNextMedia();\n }\n } : undefined,\n });\n }, [selectNextMedia, selectPreviousMedia]);\n\n if (!user && !chat) {\n return undefined;\n }\n\n function renderPhotoTabs() {\n if (isSavedMessages || !photos || photos.length <= 1) {\n return undefined;\n }\n\n return (\n <div className=\"photo-dashes\">\n {photos.map((_, i) => (\n <span className={`photo-dash ${i === currentPhotoIndex ? 'current' : ''}`} />\n ))}\n </div>\n );\n }\n\n function renderPhoto() {\n const photo = !isSavedMessages && photos && photos.length > 0 ? photos[currentPhotoIndex] : undefined;\n\n return (\n <ProfilePhoto\n key={currentPhotoIndex}\n user={user}\n chat={chat}\n photo={photo}\n isSavedMessages={isSavedMessages}\n isFirstPhoto={isFirst}\n onClick={handleProfilePhotoClick}\n />\n );\n }\n\n function renderStatus() {\n if (user) {\n return (\n <div className={`status ${isUserOnline(user) ? 'online' : ''}`}>\n <span className=\"user-status\" dir=\"auto\">{getUserStatus(lang, user, serverTimeOffset)}</span>\n </div>\n );\n }\n\n return (\n <span className=\"status\" dir=\"auto\">{\n isChatChannel(chat!)\n ? lang('Subscribers', chat!.membersCount, 'i')\n : lang('Members', chat!.membersCount, 'i')\n }\n </span>\n );\n }\n\n const isVerifiedIconShown = (user && user.isVerified) || (chat && chat.isVerified);\n\n return (\n <div className=\"ProfileInfo\" dir={lang.isRtl ? 'rtl' : undefined}>\n <div className=\"photo-wrapper\">\n {renderPhotoTabs()}\n <Transition activeKey={currentPhotoIndex} name={slideAnimation} className=\"profile-slide-container\">\n {renderPhoto}\n </Transition>\n\n {!isFirst && (\n <button\n type=\"button\"\n className=\"navigation prev\"\n aria-label={lang('AccDescrPrevious')}\n onClick={selectPreviousMedia}\n />\n )}\n {!isLast && (\n <button\n type=\"button\"\n className=\"navigation next\"\n aria-label={lang('Next')}\n onClick={selectNextMedia}\n />\n )}\n </div>\n\n <div className=\"info\" dir={lang.isRtl ? 'rtl' : 'auto'}>\n {isSavedMessages ? (\n <div className=\"title\">\n <h3 dir=\"auto\">{lang('SavedMessages')}</h3>\n </div>\n ) : (\n <div className=\"title\">\n <h3 dir=\"auto\">{fullName && renderText(fullName)}</h3>\n {isVerifiedIconShown && <VerifiedIcon />}\n </div>\n )}\n {!isSavedMessages && renderStatus()}\n </div>\n </div>\n );\n};\n\nexport default memo(withGlobal<OwnProps>(\n (global, { userId, forceShowSelf }): StateProps => {\n const { lastSyncTime, serverTimeOffset } = global;\n const user = selectUser(global, userId);\n const chat = selectChat(global, userId);\n const isSavedMessages = !forceShowSelf && user && user.isSelf;\n const { animationLevel } = global.settings.byKey;\n\n return {\n lastSyncTime, user, chat, isSavedMessages, animationLevel, serverTimeOffset,\n };\n },\n (setGlobal, actions): DispatchProps => pick(actions, ['loadFullUser', 'openMediaViewer']),\n)(PrivateChatInfo));\n","import {\n ApiChat, ApiMediaFormat, ApiPhoto, ApiUser,\n} from '../../../api/types';\nimport { useEffect } from '../../../lib/teact/teact';\nimport * as mediaLoader from '../../../util/mediaLoader';\n\nconst PHOTOS_TO_PRELOAD = 4;\n\nexport default function usePhotosPreload(\n profile: ApiUser | ApiChat | undefined,\n photos: ApiPhoto[],\n currentIndex: number,\n) {\n useEffect(() => {\n photos.slice(currentIndex, currentIndex + PHOTOS_TO_PRELOAD).forEach((photo) => {\n const mediaData = mediaLoader.getFromMemory(`photo${photo.id}?size=c`);\n if (!mediaData) {\n mediaLoader.fetch(`photo${photo.id}?size=c`, ApiMediaFormat.BlobUrl);\n }\n });\n }, [currentIndex, photos]);\n}\n","import React, {\n FC, memo, useCallback, useEffect,\n} from '../../lib/teact/teact';\nimport { withGlobal } from '../../lib/teact/teactn';\n\nimport { GlobalActions, GlobalState } from '../../global/types';\nimport { ApiChat, ApiUser } from '../../api/types';\n\nimport {\n selectChat, selectNotifyExceptions, selectNotifySettings, selectUser,\n} from '../../modules/selectors';\nimport {\n getChatDescription, getChatLink, getHasAdminRight, isChatChannel, isChatPrivate, isUserRightBanned, selectIsChatMuted,\n} from '../../modules/helpers';\nimport renderText from '../common/helpers/renderText';\nimport { pick } from '../../util/iteratees';\nimport { copyTextToClipboard } from '../../util/clipboard';\nimport { formatPhoneNumberWithCode } from '../../util/phoneNumber';\nimport useLang from '../../hooks/useLang';\n\nimport ListItem from '../ui/ListItem';\nimport Switcher from '../ui/Switcher';\n\ntype OwnProps = {\n chatOrUserId: number;\n forceShowSelf?: boolean;\n};\n\ntype StateProps = {\n user?: ApiUser;\n chat?: ApiChat;\n canInviteUsers?: boolean;\n isMuted?: boolean;\n} & Pick<GlobalState, 'lastSyncTime'>;\n\ntype DispatchProps = Pick<GlobalActions, 'loadFullUser' | 'updateChatMutedState' | 'showNotification'>;\n\nconst ChatExtra: FC<OwnProps & StateProps & DispatchProps> = ({\n lastSyncTime,\n user,\n chat,\n forceShowSelf,\n canInviteUsers,\n isMuted,\n loadFullUser,\n showNotification,\n updateChatMutedState,\n}) => {\n const {\n id: userId,\n fullInfo,\n username,\n phoneNumber,\n isSelf,\n } = user || {};\n const { id: chatId } = chat || {};\n const lang = useLang();\n\n useEffect(() => {\n if (lastSyncTime && userId) {\n loadFullUser({ userId });\n }\n }, [loadFullUser, userId, lastSyncTime]);\n\n const handleNotificationChange = useCallback(() => {\n updateChatMutedState({ chatId, isMuted: !isMuted });\n }, [chatId, isMuted, updateChatMutedState]);\n\n if (!chat || chat.isRestricted || (isSelf && !forceShowSelf)) {\n return undefined;\n }\n\n function copy(text: string, entity: string) {\n copyTextToClipboard(text);\n showNotification({ message: `${entity} was copied` });\n }\n\n const formattedNumber = phoneNumber && formatPhoneNumberWithCode(phoneNumber);\n const link = getChatLink(chat);\n const description = (fullInfo && fullInfo.bio) || getChatDescription(chat);\n\n return (\n <div className=\"ChatExtra\">\n {formattedNumber && !!formattedNumber.length && (\n <ListItem icon=\"phone\" multiline narrow ripple onClick={() => copy(formattedNumber, lang('Phone'))}>\n <span className=\"title\" dir=\"auto\">{formattedNumber}</span>\n <span className=\"subtitle\">{lang('Phone')}</span>\n </ListItem>\n )}\n {username && (\n <ListItem\n icon=\"mention\"\n multiline\n narrow\n ripple\n onClick={() => copy(`@${username}`, lang('Username'))}\n >\n <span className=\"title\" dir=\"auto\">{renderText(username)}</span>\n <span className=\"subtitle\">{lang('Username')}</span>\n </ListItem>\n )}\n {description && !!description.length && (\n <ListItem\n icon=\"info\"\n multiline\n narrow\n isStatic\n >\n <span className=\"title\" dir=\"auto\">\n {renderText(description, ['br', 'links', 'emoji'])}\n </span>\n <span className=\"subtitle\">{lang(userId ? 'UserBio' : 'Info')}</span>\n </ListItem>\n )}\n {(canInviteUsers || !username) && link && (\n <ListItem icon=\"mention\" multiline narrow ripple onClick={() => copy(link, lang('SetUrlPlaceholder'))}>\n <div className=\"title\">{link}</div>\n <span className=\"subtitle\">{lang('SetUrlPlaceholder')}</span>\n </ListItem>\n )}\n <ListItem icon=\"unmute\" ripple onClick={handleNotificationChange}>\n <span>{lang('Notifications')}</span>\n <Switcher\n id=\"group-notifications\"\n label={userId ? 'Toggle User Notifications' : 'Toggle Chat Notifications'}\n checked={!isMuted}\n inactive\n />\n </ListItem>\n </div>\n );\n};\n\nexport default memo(withGlobal<OwnProps>(\n (global, { chatOrUserId }): StateProps => {\n const { lastSyncTime } = global;\n\n const chat = chatOrUserId ? selectChat(global, chatOrUserId) : undefined;\n const user = isChatPrivate(chatOrUserId) ? selectUser(global, chatOrUserId) : undefined;\n const isMuted = chat && selectIsChatMuted(chat, selectNotifySettings(global), selectNotifyExceptions(global));\n\n const canInviteUsers = chat && !user && (\n (!isChatChannel(chat) && !isUserRightBanned(chat, 'inviteUsers'))\n || getHasAdminRight(chat, 'inviteUsers')\n );\n\n return {\n lastSyncTime, chat, user, canInviteUsers, isMuted,\n };\n },\n (setGlobal, actions): DispatchProps => pick(actions, [\n 'loadFullUser', 'updateChatMutedState', 'showNotification',\n ]),\n)(ChatExtra));\n","import React, { FC, useCallback, memo } from '../../lib/teact/teact';\nimport { withGlobal } from '../../lib/teact/teactn';\n\nimport { GlobalActions } from '../../global/types';\nimport { ApiChat } from '../../api/types';\n\nimport { pick } from '../../util/iteratees';\nimport { selectCurrentChat, selectUser } from '../../modules/selectors';\nimport { getUserFirstOrLastName } from '../../modules/helpers';\nimport renderText from '../common/helpers/renderText';\nimport useLang from '../../hooks/useLang';\n\nimport Modal from '../ui/Modal';\nimport Button from '../ui/Button';\n\nexport type OwnProps = {\n isOpen: boolean;\n userId?: number;\n onClose: () => void;\n};\n\ntype StateProps = {\n chat?: ApiChat;\n contactName?: string;\n};\n\ntype DispatchProps = Pick<GlobalActions, 'deleteChatMember'>;\n\nconst DeleteMemberModal: FC<OwnProps & StateProps & DispatchProps> = ({\n isOpen,\n chat,\n userId,\n contactName,\n onClose,\n deleteChatMember,\n}) => {\n const lang = useLang();\n\n const handleDeleteChatMember = useCallback(() => {\n deleteChatMember({ chatId: chat!.id, userId });\n onClose();\n }, [chat, deleteChatMember, onClose, userId]);\n\n if (!chat || !userId) {\n return undefined;\n }\n\n return (\n <Modal\n isOpen={isOpen}\n onClose={onClose}\n onEnter={handleDeleteChatMember}\n className=\"delete\"\n title={lang('GroupRemoved.Remove')}\n >\n <p>{renderText(lang('PeerInfo.Confirm.RemovePeer', contactName))}</p>\n <Button color=\"danger\" className=\"confirm-dialog-button\" isText onClick={handleDeleteChatMember}>\n {lang('lng_box_remove')}\n </Button>\n <Button className=\"confirm-dialog-button\" isText onClick={onClose}>{lang('Cancel')}</Button>\n </Modal>\n );\n};\n\nexport default memo(withGlobal<OwnProps>(\n (global, { userId }): StateProps => {\n const chat = selectCurrentChat(global);\n const user = userId && selectUser(global, userId);\n const contactName = user ? getUserFirstOrLastName(user) : undefined;\n\n return {\n chat,\n contactName,\n };\n },\n (setGlobal, actions): DispatchProps => pick(actions, ['deleteChatMember']),\n)(DeleteMemberModal));\n","import React, {\n FC, useCallback, useEffect, useMemo, useRef, useState, memo,\n} from '../../lib/teact/teact';\nimport { withGlobal } from '../../lib/teact/teactn';\n\nimport {\n ApiMessage,\n ApiChatMember,\n ApiUser,\n MAIN_THREAD_ID,\n} from '../../api/types';\nimport { GlobalActions } from '../../global/types';\nimport {\n NewChatMembersProgress, ISettings, MediaViewerOrigin, ProfileState, ProfileTabType, SharedMediaType,\n} from '../../types';\n\nimport {\n MEMBERS_SLICE,\n PROFILE_SENSITIVE_AREA,\n SHARED_MEDIA_SLICE,\n SLIDE_TRANSITION_DURATION,\n} from '../../config';\nimport { IS_TOUCH_ENV } from '../../util/environment';\nimport {\n getHasAdminRight, isChatAdmin, isChatChannel, isChatGroup, isChatPrivate,\n} from '../../modules/helpers';\nimport {\n selectChatMessages,\n selectChat,\n selectCurrentMediaSearch,\n selectIsRightColumnShown,\n selectTheme,\n} from '../../modules/selectors';\nimport { pick } from '../../util/iteratees';\nimport { captureEvents, SwipeDirection } from '../../util/captureEvents';\nimport useCacheBuster from '../../hooks/useCacheBuster';\nimport useProfileViewportIds from './hooks/useProfileViewportIds';\nimport useProfileState from './hooks/useProfileState';\nimport useTransitionFixes from './hooks/useTransitionFixes';\nimport useAsyncRendering from './hooks/useAsyncRendering';\nimport useLang from '../../hooks/useLang';\n\nimport Transition from '../ui/Transition';\nimport InfiniteScroll from '../ui/InfiniteScroll';\nimport TabList from '../ui/TabList';\nimport Spinner from '../ui/Spinner';\nimport ListItem from '../ui/ListItem';\nimport PrivateChatInfo from '../common/PrivateChatInfo';\nimport ProfileInfo from './ProfileInfo';\nimport Document from '../common/Document';\nimport Audio from '../common/Audio';\nimport ChatExtra from './ChatExtra';\nimport Media from '../common/Media';\nimport WebLink from '../common/WebLink';\nimport NothingFound from '../common/NothingFound';\nimport FloatingActionButton from '../ui/FloatingActionButton';\nimport DeleteMemberModal from './DeleteMemberModal';\n\nimport './Profile.scss';\n\ntype OwnProps = {\n chatId: number;\n userId?: number;\n profileState: ProfileState;\n onProfileStateChange: (state: ProfileState) => void;\n};\n\ntype StateProps = {\n theme: ISettings['theme'];\n isChannel?: boolean;\n currentUserId?: number;\n resolvedUserId?: number;\n chatMessages?: Record<number, ApiMessage>;\n foundIds?: number[];\n mediaSearchType?: SharedMediaType;\n hasMembersTab?: boolean;\n areMembersHidden?: boolean;\n canAddMembers?: boolean;\n canDeleteMembers?: boolean;\n members?: ApiChatMember[];\n usersById?: Record<number, ApiUser>;\n isRightColumnShown: boolean;\n isRestricted?: boolean;\n lastSyncTime?: number;\n serverTimeOffset: number;\n};\n\ntype DispatchProps = Pick<GlobalActions, (\n 'setLocalMediaSearchType' | 'loadMoreMembers' | 'searchMediaMessagesLocal' | 'openMediaViewer' |\n 'openAudioPlayer' | 'openUserInfo' | 'focusMessage' | 'loadProfilePhotos' | 'setNewChatMembersDialogState'\n)>;\n\nconst TABS = [\n { type: 'media', title: 'SharedMediaTab2' },\n { type: 'documents', title: 'SharedFilesTab2' },\n { type: 'links', title: 'SharedLinksTab2' },\n { type: 'audio', title: 'SharedMusicTab2' },\n];\n\nconst HIDDEN_RENDER_DELAY = 1000;\n\nconst Profile: FC<OwnProps & StateProps & DispatchProps> = ({\n chatId,\n profileState,\n onProfileStateChange,\n theme,\n isChannel,\n resolvedUserId,\n currentUserId,\n chatMessages,\n foundIds,\n mediaSearchType,\n hasMembersTab,\n areMembersHidden,\n canAddMembers,\n canDeleteMembers,\n members,\n usersById,\n isRightColumnShown,\n isRestricted,\n lastSyncTime,\n setLocalMediaSearchType,\n loadMoreMembers,\n searchMediaMessagesLocal,\n openMediaViewer,\n openAudioPlayer,\n openUserInfo,\n focusMessage,\n loadProfilePhotos,\n setNewChatMembersDialogState,\n serverTimeOffset,\n}) => {\n // eslint-disable-next-line no-null/no-null\n const containerRef = useRef<HTMLDivElement>(null);\n // eslint-disable-next-line no-null/no-null\n const transitionRef = useRef<HTMLDivElement>(null);\n const lang = useLang();\n const [activeTab, setActiveTab] = useState(0);\n const [deletingUserId, setDeletingUserId] = useState<number | undefined>();\n\n const tabs = useMemo(() => ([\n ...(hasMembersTab ? [{\n type: 'members', title: isChannel ? 'ChannelSubscribers' : 'GroupMembers',\n }] : []),\n ...TABS,\n ]), [hasMembersTab, isChannel]);\n const tabType = tabs[activeTab].type as ProfileTabType;\n\n const [resultType, viewportIds, getMore, noProfileInfo] = useProfileViewportIds(\n isRightColumnShown, loadMoreMembers, searchMediaMessagesLocal, tabType, mediaSearchType, members,\n usersById, chatMessages, foundIds, chatId, lastSyncTime, serverTimeOffset,\n );\n const activeKey = tabs.findIndex(({ type }) => type === resultType);\n\n const { handleScroll } = useProfileState(containerRef, tabType, profileState, onProfileStateChange);\n\n const { applyTransitionFix, releaseTransitionFix } = useTransitionFixes(containerRef);\n\n const [cacheBuster, resetCacheBuster] = useCacheBuster();\n\n const handleTransitionStop = useCallback(() => {\n releaseTransitionFix();\n resetCacheBuster();\n }, [releaseTransitionFix, resetCacheBuster]);\n\n const handleNewMemberDialogOpen = useCallback(() => {\n setNewChatMembersDialogState(NewChatMembersProgress.InProgress);\n }, [setNewChatMembersDialogState]);\n\n // Update search type when switching tabs\n useEffect(() => {\n setLocalMediaSearchType({ mediaType: tabType });\n }, [setLocalMediaSearchType, tabType]);\n\n const profileId = resolvedUserId || chatId;\n\n useEffect(() => {\n if (lastSyncTime) {\n loadProfilePhotos({ profileId });\n }\n }, [loadProfilePhotos, profileId, lastSyncTime]);\n\n const handleSelectMedia = useCallback((messageId: number) => {\n openMediaViewer({\n chatId: profileId,\n threadId: MAIN_THREAD_ID,\n messageId,\n origin: MediaViewerOrigin.SharedMedia,\n });\n }, [profileId, openMediaViewer]);\n\n const handlePlayAudio = useCallback((messageId: number) => {\n openAudioPlayer({ chatId: profileId, messageId });\n }, [profileId, openAudioPlayer]);\n\n const handleMemberClick = useCallback((id: number) => {\n openUserInfo({ id });\n }, [openUserInfo]);\n\n const handleMessageFocus = useCallback((messageId: number) => {\n focusMessage({ chatId: profileId, messageId });\n }, [profileId, focusMessage]);\n\n const handleDeleteMembersModalClose = useCallback(() => {\n setDeletingUserId(undefined);\n }, []);\n\n useEffect(() => {\n if (!transitionRef.current || !IS_TOUCH_ENV) {\n return undefined;\n }\n\n return captureEvents(transitionRef.current, {\n onSwipe: ((e, direction) => {\n if (direction === SwipeDirection.Left) {\n setActiveTab(Math.min(activeTab + 1, tabs.length - 1));\n } else if (direction === SwipeDirection.Right) {\n setActiveTab(Math.max(0, activeTab - 1));\n }\n }),\n });\n }, [activeTab, tabs.length]);\n\n let renderingDelay;\n const isFirstTab = resultType === 'members' || (!hasMembersTab && resultType === 'media');\n // @optimization Used to unparallelize rendering of message list and profile media\n if (isFirstTab) {\n renderingDelay = !isRightColumnShown ? HIDDEN_RENDER_DELAY : 0;\n // @optimization Used to delay first render of secondary tabs while animating\n } else if (!viewportIds) {\n renderingDelay = SLIDE_TRANSITION_DURATION;\n }\n const canRenderContents = useAsyncRendering([chatId, resultType], renderingDelay);\n\n function getMemberContextAction(id: number) {\n return id === currentUserId || !canDeleteMembers ? undefined : [{\n title: lang('lng_context_remove_from_group'),\n icon: 'stop',\n handler: () => {\n setDeletingUserId(id);\n },\n }];\n }\n\n function renderSharedMedia() {\n if (!viewportIds || !canRenderContents || !chatMessages) {\n // This is just a single-frame delay, so we do not show spinner\n const noSpinner = isFirstTab && viewportIds && !canRenderContents;\n\n return (\n <div className=\"content empty-list\">\n {!noSpinner && <Spinner />}\n </div>\n );\n }\n\n if (!viewportIds.length) {\n let text: string;\n\n switch (resultType) {\n case 'members':\n text = areMembersHidden ? 'You have no access to group members list.' : 'No members found';\n break;\n case 'documents':\n text = lang('lng_media_file_empty_search');\n break;\n case 'links':\n text = lang('lng_media_link_empty_search');\n break;\n case 'audio':\n text = lang('lng_media_song_empty_search');\n break;\n default:\n text = lang('SharedMedia.EmptyTitle');\n }\n\n return (\n <div className=\"content empty-list\">\n <NothingFound text={text} />\n </div>\n );\n }\n\n return (\n <div\n className={`content ${resultType}-list`}\n dir={lang.isRtl && resultType === 'media' ? 'rtl' : undefined}\n teactFastList\n >\n {resultType === 'media' ? (\n viewportIds!.map((id) => chatMessages[id] && (\n <Media\n key={id}\n message={chatMessages[id]}\n onClick={handleSelectMedia}\n />\n ))\n ) : resultType === 'documents' ? (\n viewportIds!.map((id) => chatMessages[id] && (\n <Document\n key={id}\n message={chatMessages[id]}\n withDate\n smaller\n className=\"scroll-item\"\n onDateClick={handleMessageFocus}\n />\n ))\n ) : resultType === 'links' ? (\n viewportIds!.map((id) => chatMessages[id] && (\n <WebLink\n key={id}\n message={chatMessages[id]}\n onMessageClick={handleMessageFocus}\n />\n ))\n ) : resultType === 'audio' ? (\n viewportIds!.map((id) => chatMessages[id] && (\n <Audio\n key={id}\n theme={theme}\n message={chatMessages[id]}\n target=\"sharedMedia\"\n date={chatMessages[id].date}\n lastSyncTime={lastSyncTime}\n className=\"scroll-item\"\n onPlay={handlePlayAudio}\n onDateClick={handleMessageFocus}\n />\n ))\n ) : resultType === 'members' ? (\n viewportIds!.map((id, i) => (\n <ListItem\n key={id}\n teactOrderKey={i}\n className=\"chat-item-clickable scroll-item\"\n onClick={() => handleMemberClick(id)}\n contextActions={getMemberContextAction(id)}\n >\n <PrivateChatInfo userId={id} forceShowSelf />\n </ListItem>\n ))\n ) : undefined}\n </div>\n );\n }\n\n return (\n <InfiniteScroll\n ref={containerRef}\n className=\"Profile custom-scroll\"\n itemSelector={buildInfiniteScrollItemSelector(resultType)}\n items={canRenderContents ? viewportIds : undefined}\n cacheBuster={cacheBuster}\n sensitiveArea={PROFILE_SENSITIVE_AREA}\n preloadBackwards={canRenderContents ? (resultType === 'members' ? MEMBERS_SLICE : SHARED_MEDIA_SLICE) : 0}\n // To prevent scroll jumps caused by reordering member list\n noScrollRestoreOnTop\n noFastList\n onLoadMore={getMore}\n onScroll={handleScroll}\n >\n {!noProfileInfo && renderProfileInfo(chatId, resolvedUserId)}\n {!isRestricted && (\n <div\n className=\"shared-media\"\n >\n <Transition\n ref={transitionRef}\n name={lang.isRtl ? 'slide-reversed' : 'slide'}\n activeKey={activeKey}\n renderCount={tabs.length}\n shouldRestoreHeight\n className=\"shared-media-transition\"\n onStart={applyTransitionFix}\n onStop={handleTransitionStop}\n >\n {renderSharedMedia}\n </Transition>\n <TabList big activeTab={activeTab} tabs={tabs} onSwitchTab={setActiveTab} />\n\n </div>\n )}\n\n {canAddMembers && (\n <FloatingActionButton\n isShown={resultType === 'members'}\n onClick={handleNewMemberDialogOpen}\n ariaLabel={lang('lng_channel_add_users')}\n >\n <i className=\"icon-add-user-filled\" />\n </FloatingActionButton>\n )}\n {canDeleteMembers && (\n <DeleteMemberModal\n isOpen={Boolean(deletingUserId)}\n userId={deletingUserId}\n onClose={handleDeleteMembersModalClose}\n />\n )}\n </InfiniteScroll>\n );\n};\n\nfunction renderProfileInfo(chatId: number, resolvedUserId?: number) {\n return (\n <div className=\"profile-info\">\n <ProfileInfo\n userId={resolvedUserId || chatId}\n forceShowSelf={resolvedUserId !== chatId}\n />\n <ChatExtra chatOrUserId={resolvedUserId || chatId} forceShowSelf={resolvedUserId !== chatId} />\n </div>\n );\n}\n\nfunction buildInfiniteScrollItemSelector(resultType: string) {\n return [\n // Used on first render\n `.shared-media-transition > div:only-child > .${resultType}-list > .scroll-item`,\n // Used after transition\n `.shared-media-transition > div.active > .${resultType}-list > .scroll-item`,\n ].join(', ');\n}\n\nexport default memo(withGlobal<OwnProps>(\n (global, { chatId, userId }): StateProps => {\n const chat = selectChat(global, chatId);\n\n const chatMessages = selectChatMessages(global, userId || chatId);\n const { currentType: mediaSearchType, resultsByType } = selectCurrentMediaSearch(global) || {};\n const { foundIds } = (resultsByType && mediaSearchType && resultsByType[mediaSearchType]) || {};\n\n const { byId: usersById } = global.users;\n\n const isGroup = chat && isChatGroup(chat);\n const isChannel = chat && isChatChannel(chat);\n const hasMembersTab = isGroup || (isChannel && isChatAdmin(chat!));\n const members = chat && chat.fullInfo && chat.fullInfo.members;\n const areMembersHidden = hasMembersTab && chat && chat.fullInfo && !chat.fullInfo.canViewMembers;\n const canAddMembers = hasMembersTab && chat && (getHasAdminRight(chat, 'inviteUsers') || chat.isCreator);\n const canDeleteMembers = hasMembersTab && chat && (getHasAdminRight(chat, 'banUsers') || chat.isCreator);\n\n let resolvedUserId;\n if (userId) {\n resolvedUserId = userId;\n } else if (isChatPrivate(chatId)) {\n resolvedUserId = chatId;\n }\n\n return {\n theme: selectTheme(global),\n isChannel,\n resolvedUserId,\n chatMessages,\n foundIds,\n mediaSearchType,\n hasMembersTab,\n areMembersHidden,\n canAddMembers,\n canDeleteMembers,\n currentUserId: global.currentUserId,\n isRightColumnShown: selectIsRightColumnShown(global),\n isRestricted: chat && chat.isRestricted,\n lastSyncTime: global.lastSyncTime,\n serverTimeOffset: global.serverTimeOffset,\n ...(hasMembersTab && members && {\n members,\n usersById,\n }),\n };\n },\n (setGlobal, actions): DispatchProps => pick(actions, [\n 'setLocalMediaSearchType',\n 'loadMoreMembers',\n 'searchMediaMessagesLocal',\n 'openMediaViewer',\n 'openAudioPlayer',\n 'openUserInfo',\n 'focusMessage',\n 'loadProfilePhotos',\n 'setNewChatMembersDialogState',\n ]),\n)(Profile));\n","import { useCallback, useEffect } from '../../../lib/teact/teact';\n\nexport default function useTransitionFixes(\n containerRef: { current: HTMLDivElement | null },\n transitionElSelector = '.Transition.shared-media-transition',\n) {\n // Set `min-height` for shared media container to prevent jumping when switching tabs\n useEffect(() => {\n function setMinHeight() {\n const container = containerRef.current!;\n const transitionEl = container.querySelector<HTMLDivElement>(transitionElSelector);\n const tabsEl = container.querySelector<HTMLDivElement>('.TabList');\n if (transitionEl && tabsEl) {\n transitionEl.style.minHeight = `${container.offsetHeight - tabsEl.offsetHeight}px`;\n }\n }\n\n setMinHeight();\n\n window.addEventListener('resize', setMinHeight, false);\n\n return () => {\n window.removeEventListener('resize', setMinHeight, false);\n };\n }, [containerRef, transitionElSelector]);\n\n // Workaround for scrollable content flickering during animation.\n const applyTransitionFix = useCallback(() => {\n const container = containerRef.current!;\n if (container.style.overflowY !== 'hidden') {\n const scrollBarWidth = container.offsetWidth - container.clientWidth;\n container.style.overflowY = 'hidden';\n container.style.marginRight = `${scrollBarWidth}px`;\n }\n }, [containerRef]);\n\n const releaseTransitionFix = useCallback(() => {\n const container = containerRef.current!;\n container.style.overflowY = 'scroll';\n container.style.marginRight = '0';\n }, [containerRef]);\n\n return { applyTransitionFix, releaseTransitionFix };\n}\n","import { useCallback, useState } from '../lib/teact/teact';\n\nexport default () => {\n const [cacheBuster, setCacheBuster] = useState<boolean>(false);\n\n const updateCacheBuster = useCallback(() => {\n setCacheBuster((current) => !current);\n }, []);\n\n return [cacheBuster, updateCacheBuster] as const;\n};\n","import React, { FC, memo } from '../../lib/teact/teact';\nimport { OwnProps } from './RightSearch';\nimport { Bundles } from '../../util/moduleLoader';\n\nimport useModuleLoader from '../../hooks/useModuleLoader';\nimport Loading from '../ui/Loading';\n\nconst RightSearchAsync: FC<OwnProps> = (props) => {\n const RightSearch = useModuleLoader(Bundles.Extra, 'RightSearch');\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return RightSearch ? <RightSearch {...props} /> : <Loading />;\n};\n\nexport default memo(RightSearchAsync);\n","import React, { FC, memo } from '../../../lib/teact/teact';\nimport { Bundles } from '../../../util/moduleLoader';\n\nimport { OwnProps } from './Management';\n\nimport useModuleLoader from '../../../hooks/useModuleLoader';\n\nimport Loading from '../../ui/Loading';\n\nconst ManagementAsync: FC<OwnProps> = (props) => {\n const Management = useModuleLoader(Bundles.Extra, 'Management');\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return Management ? <Management {...props} /> : <Loading />;\n};\n\nexport default memo(ManagementAsync);\n","import React, { FC, memo } from '../../lib/teact/teact';\nimport { Bundles } from '../../util/moduleLoader';\n\nimport useModuleLoader from '../../hooks/useModuleLoader';\nimport Loading from '../ui/Loading';\n\nconst StickerSearchAsync: FC = () => {\n const StickerSearch = useModuleLoader(Bundles.Extra, 'StickerSearch');\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return StickerSearch ? <StickerSearch /> : <Loading />;\n};\n\nexport default memo(StickerSearchAsync);\n","import React, { FC, memo } from '../../lib/teact/teact';\nimport { Bundles } from '../../util/moduleLoader';\n\nimport useModuleLoader from '../../hooks/useModuleLoader';\nimport Loading from '../ui/Loading';\n\nconst GifSearchAsync: FC = () => {\n const GifSearch = useModuleLoader(Bundles.Extra, 'GifSearch');\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return GifSearch ? <GifSearch /> : <Loading />;\n};\n\nexport default memo(GifSearchAsync);\n","import React, { FC, memo } from '../../lib/teact/teact';\nimport { Bundles } from '../../util/moduleLoader';\n\nimport useModuleLoader from '../../hooks/useModuleLoader';\nimport Loading from '../ui/Loading';\n\nconst PollResultsAsync: FC = () => {\n const PollResults = useModuleLoader(Bundles.Extra, 'PollResults');\n\n return PollResults ? <PollResults /> : <Loading />;\n};\n\nexport default memo(PollResultsAsync);\n","import React, {\n FC, useCallback, useMemo, memo, useState, useEffect,\n} from '../../lib/teact/teact';\nimport { withGlobal } from '../../lib/teact/teactn';\n\nimport { GlobalActions } from '../../global/types';\nimport {\n ApiChat, ApiChatMember, ApiUpdateConnectionStateType, ApiUser,\n} from '../../api/types';\nimport { NewChatMembersProgress } from '../../types';\n\nimport { pick, unique } from '../../util/iteratees';\nimport { selectChat } from '../../modules/selectors';\nimport searchWords from '../../util/searchWords';\nimport {\n getUserFullName, isChatChannel, isUserBot, sortChatIds,\n} from '../../modules/helpers';\nimport useLang from '../../hooks/useLang';\nimport usePrevious from '../../hooks/usePrevious';\nimport useHistoryBack from '../../hooks/useHistoryBack';\n\nimport Picker from '../common/Picker';\nimport FloatingActionButton from '../ui/FloatingActionButton';\nimport Spinner from '../ui/Spinner';\n\nimport './AddChatMembers.scss';\n\nexport type OwnProps = {\n chatId: number;\n isActive: boolean;\n onNextStep: (memberIds: number[]) => void;\n onClose: NoneToVoidFunction;\n};\n\ntype StateProps = {\n connectionState?: ApiUpdateConnectionStateType;\n isChannel?: boolean;\n members?: ApiChatMember[];\n currentUserId?: number;\n usersById: Record<number, ApiUser>;\n chatsById: Record<number, ApiChat>;\n localContactIds?: number[];\n searchQuery?: string;\n isLoading: boolean;\n isSearching?: boolean;\n localUserIds?: number[];\n globalUserIds?: number[];\n};\n\ntype DispatchProps = Pick<GlobalActions, 'loadContactList' | 'setUserSearchQuery'>;\n\nconst AddChatMembers: FC<OwnProps & StateProps & DispatchProps> = ({\n isChannel,\n connectionState,\n members,\n onNextStep,\n currentUserId,\n usersById,\n chatsById,\n localContactIds,\n isLoading,\n searchQuery,\n isSearching,\n localUserIds,\n globalUserIds,\n setUserSearchQuery,\n onClose,\n isActive,\n loadContactList,\n}) => {\n const lang = useLang();\n const [selectedMemberIds, setSelectedMemberIds] = useState<number[]>([]);\n const prevSelectedMemberIds = usePrevious(selectedMemberIds);\n const noPickerScrollRestore = prevSelectedMemberIds === selectedMemberIds;\n\n useEffect(() => {\n if (isActive && connectionState === 'connectionStateReady') {\n loadContactList();\n }\n }, [connectionState, isActive, loadContactList]);\n\n useHistoryBack(isActive, onClose);\n\n const memberIds = useMemo(() => {\n return members ? members.map((member) => member.userId) : [];\n }, [members]);\n\n const handleFilterChange = useCallback((query: string) => {\n setUserSearchQuery({ query });\n }, [setUserSearchQuery]);\n\n const displayedIds = useMemo(() => {\n const contactIds = localContactIds\n ? sortChatIds(localContactIds.filter((id) => id !== currentUserId), chatsById)\n : [];\n\n if (!searchQuery) {\n return contactIds.filter((id) => !memberIds.includes(id));\n }\n\n const foundContactIds = contactIds.filter((id) => {\n const user = usersById[id];\n if (!user) {\n return false;\n }\n const fullName = getUserFullName(user);\n return fullName && searchWords(fullName, searchQuery);\n });\n\n return sortChatIds(\n unique([\n ...foundContactIds,\n ...(localUserIds || []),\n ...(globalUserIds || []),\n ]).filter((contactId) => {\n const user = usersById[contactId];\n\n // The user can be added to the chat if the following conditions are met:\n // the user has not yet been added to the current chat\n // AND (it is not found (user from global search) OR it is not a bot OR it is a bot,\n // but the current chat is not a channel AND the appropriate permission is set).\n return !memberIds.includes(contactId)\n && (!user || !isUserBot(user) || (!isChannel && user.canBeInvitedToGroup));\n }),\n chatsById,\n );\n }, [\n localContactIds, chatsById, searchQuery, localUserIds, globalUserIds,\n currentUserId, usersById, memberIds, isChannel,\n ]);\n\n const handleNextStep = useCallback(() => {\n if (selectedMemberIds.length) {\n setUserSearchQuery({ query: '' });\n onNextStep(selectedMemberIds);\n }\n }, [selectedMemberIds, setUserSearchQuery, onNextStep]);\n\n return (\n <div className=\"AddChatMembers\">\n <div className=\"AddChatMembers-inner\">\n <Picker\n itemIds={displayedIds}\n selectedIds={selectedMemberIds}\n filterValue={searchQuery}\n filterPlaceholder={lang('lng_channel_add_users')}\n searchInputId=\"new-members-picker-search\"\n isLoading={isSearching}\n onSelectedIdsChange={setSelectedMemberIds}\n onFilterChange={handleFilterChange}\n noScrollRestore={noPickerScrollRestore}\n />\n\n <FloatingActionButton\n isShown={Boolean(selectedMemberIds.length)}\n disabled={isLoading}\n ariaLabel={lang('lng_channel_add_users')}\n onClick={handleNextStep}\n >\n {isLoading ? (\n <Spinner color=\"white\" />\n ) : (\n <i className=\"icon-arrow-right\" />\n )}\n </FloatingActionButton>\n </div>\n </div>\n );\n};\n\nexport default memo(withGlobal<OwnProps>(\n (global, { chatId }): StateProps => {\n const chat = selectChat(global, chatId);\n const { userIds: localContactIds } = global.contactList || {};\n const { byId: usersById } = global.users;\n const { byId: chatsById } = global.chats;\n const { currentUserId, newChatMembersProgress, connectionState } = global;\n const isChannel = chat && isChatChannel(chat);\n\n const {\n query: searchQuery,\n fetchingStatus,\n globalUserIds,\n localUserIds,\n } = global.userSearch;\n\n return {\n isChannel,\n members: chat && chat.fullInfo ? chat.fullInfo.members : undefined,\n currentUserId,\n usersById,\n chatsById,\n localContactIds,\n searchQuery,\n isSearching: fetchingStatus,\n isLoading: newChatMembersProgress === NewChatMembersProgress.Loading,\n globalUserIds,\n localUserIds,\n connectionState,\n };\n },\n (setGlobal, actions): DispatchProps => pick(actions, ['loadContactList', 'setUserSearchQuery']),\n)(AddChatMembers));\n","import React, {\n FC, memo, useCallback, useEffect, useState,\n} from '../../lib/teact/teact';\nimport { withGlobal } from '../../lib/teact/teactn';\n\nimport { GlobalActions } from '../../global/types';\nimport {\n ManagementScreens, NewChatMembersProgress, ProfileState, RightColumnContent,\n} from '../../types';\n\nimport { MIN_SCREEN_WIDTH_FOR_STATIC_RIGHT_COLUMN } from '../../config';\nimport captureEscKeyListener from '../../util/captureEscKeyListener';\nimport { pick } from '../../util/iteratees';\nimport {\n selectAreActiveChatsLoaded,\n selectCurrentMessageList,\n selectRightColumnContentKey,\n} from '../../modules/selectors';\nimport useLayoutEffectWithPrevDeps from '../../hooks/useLayoutEffectWithPrevDeps';\nimport useWindowSize from '../../hooks/useWindowSize';\nimport useCurrentOrPrev from '../../hooks/useCurrentOrPrev';\nimport useHistoryBack from '../../hooks/useHistoryBack';\n\nimport RightHeader from './RightHeader';\nimport Profile from './Profile';\nimport Transition from '../ui/Transition';\nimport RightSearch from './RightSearch.async';\nimport Management from './management/Management.async';\nimport StickerSearch from './StickerSearch.async';\nimport GifSearch from './GifSearch.async';\nimport PollResults from './PollResults.async';\nimport AddChatMembers from './AddChatMembers';\n\nimport './RightColumn.scss';\n\ntype StateProps = {\n contentKey?: RightColumnContent;\n chatId?: number;\n threadId?: number;\n currentProfileUserId?: number;\n isChatSelected: boolean;\n shouldSkipHistoryAnimations?: boolean;\n};\n\ntype DispatchProps = Pick<GlobalActions, (\n 'toggleChatInfo' | 'toggleManagement' | 'openUserInfo' | 'setNewChatMembersDialogState' |\n 'closeLocalTextSearch' | 'closePollResults' | 'addChatMembers' |\n 'setStickerSearchQuery' | 'setGifSearchQuery'\n)>;\n\nconst COLUMN_CLOSE_DELAY_MS = 300;\nconst MAIN_SCREENS_COUNT = Object.keys(RightColumnContent).length / 2;\nconst MANAGEMENT_SCREENS_COUNT = Object.keys(ManagementScreens).length / 2;\n\nfunction blurSearchInput() {\n const searchInput = document.querySelector('.RightHeader .SearchInput input') as HTMLInputElement;\n if (searchInput) {\n searchInput.blur();\n }\n}\n\nconst RightColumn: FC<StateProps & DispatchProps> = ({\n contentKey,\n chatId,\n threadId,\n currentProfileUserId,\n isChatSelected,\n toggleChatInfo,\n toggleManagement,\n openUserInfo,\n closeLocalTextSearch,\n setStickerSearchQuery,\n setGifSearchQuery,\n closePollResults,\n addChatMembers,\n setNewChatMembersDialogState,\n shouldSkipHistoryAnimations,\n}) => {\n const { width: windowWidth } = useWindowSize();\n const [profileState, setProfileState] = useState<ProfileState>(ProfileState.Profile);\n const [managementScreen, setManagementScreen] = useState<ManagementScreens>(ManagementScreens.Initial);\n const [selectedChatMemberId, setSelectedChatMemberId] = useState<number | undefined>();\n const [isPromotedByCurrentUser, setIsPromotedByCurrentUser] = useState<boolean | undefined>();\n const isScrolledDown = profileState !== ProfileState.Profile;\n\n const isOpen = contentKey !== undefined;\n const isProfile = contentKey === RightColumnContent.ChatInfo || contentKey === RightColumnContent.UserInfo;\n const isSearch = contentKey === RightColumnContent.Search;\n const isManagement = contentKey === RightColumnContent.Management;\n const isStickerSearch = contentKey === RightColumnContent.StickerSearch;\n const isGifSearch = contentKey === RightColumnContent.GifSearch;\n const isPollResults = contentKey === RightColumnContent.PollResults;\n const isAddingChatMembers = contentKey === RightColumnContent.AddingMembers;\n const isOverlaying = windowWidth <= MIN_SCREEN_WIDTH_FOR_STATIC_RIGHT_COLUMN;\n\n const [shouldSkipTransition, setShouldSkipTransition] = useState(!isOpen);\n\n const renderingContentKey = useCurrentOrPrev(contentKey, true, !isChatSelected) ?? -1;\n\n const close = useCallback((shouldScrollUp = true) => {\n switch (contentKey) {\n case RightColumnContent.AddingMembers:\n setNewChatMembersDialogState(NewChatMembersProgress.Closed);\n break;\n case RightColumnContent.ChatInfo:\n if (isScrolledDown && shouldScrollUp) {\n setProfileState(ProfileState.Profile);\n break;\n }\n toggleChatInfo(undefined, true);\n break;\n case RightColumnContent.UserInfo:\n if (isScrolledDown && shouldScrollUp) {\n setProfileState(ProfileState.Profile);\n break;\n }\n openUserInfo({ id: undefined }, true);\n break;\n case RightColumnContent.Management: {\n switch (managementScreen) {\n case ManagementScreens.Initial:\n toggleManagement();\n break;\n case ManagementScreens.ChatPrivacyType:\n case ManagementScreens.Discussion:\n case ManagementScreens.GroupPermissions:\n case ManagementScreens.GroupType:\n case ManagementScreens.ChatAdministrators:\n case ManagementScreens.ChannelSubscribers:\n case ManagementScreens.GroupMembers:\n setManagementScreen(ManagementScreens.Initial);\n break;\n case ManagementScreens.GroupUserPermissionsCreate:\n case ManagementScreens.GroupRemovedUsers:\n case ManagementScreens.GroupUserPermissions:\n setManagementScreen(ManagementScreens.GroupPermissions);\n setSelectedChatMemberId(undefined);\n setIsPromotedByCurrentUser(undefined);\n break;\n case ManagementScreens.ChatAdminRights:\n case ManagementScreens.GroupRecentActions:\n setManagementScreen(ManagementScreens.ChatAdministrators);\n break;\n }\n\n break;\n }\n case RightColumnContent.Search: {\n blurSearchInput();\n closeLocalTextSearch();\n break;\n }\n case RightColumnContent.StickerSearch:\n blurSearchInput();\n setStickerSearchQuery({ query: undefined });\n break;\n case RightColumnContent.GifSearch: {\n blurSearchInput();\n setGifSearchQuery({ query: undefined });\n break;\n }\n case RightColumnContent.PollResults:\n closePollResults();\n break;\n }\n }, [\n contentKey, isScrolledDown, toggleChatInfo, openUserInfo, closePollResults, setNewChatMembersDialogState,\n managementScreen, toggleManagement, closeLocalTextSearch, setStickerSearchQuery, setGifSearchQuery,\n ]);\n\n const handleSelectChatMember = useCallback((memberId, isPromoted) => {\n setSelectedChatMemberId(memberId);\n setIsPromotedByCurrentUser(isPromoted);\n }, []);\n\n const handleAppendingChatMembers = useCallback((memberIds: number[]) => {\n addChatMembers({ chatId, memberIds });\n }, [addChatMembers, chatId]);\n\n useEffect(() => (isOpen ? captureEscKeyListener(close) : undefined), [isOpen, close]);\n\n useEffect(() => {\n setTimeout(() => {\n setShouldSkipTransition(!isOpen);\n }, COLUMN_CLOSE_DELAY_MS);\n }, [isOpen]);\n\n // Close Right Column when it transforms into overlayed state on screen resize\n useEffect(() => {\n if (isOpen && isOverlaying) {\n close();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isOverlaying]);\n\n // We need to clear profile state and management screen state, when changing chats\n useLayoutEffectWithPrevDeps(([prevContentKey, prevChatId]) => {\n if (\n (prevContentKey === RightColumnContent.ChatInfo && contentKey === RightColumnContent.UserInfo)\n || (prevContentKey === RightColumnContent.UserInfo && contentKey === RightColumnContent.ChatInfo)\n || (prevChatId !== chatId)\n ) {\n setProfileState(ProfileState.Profile);\n setManagementScreen(ManagementScreens.Initial);\n }\n }, [contentKey, chatId]);\n\n\n useHistoryBack(isChatSelected && (contentKey === RightColumnContent.ChatInfo\n || contentKey === RightColumnContent.UserInfo || contentKey === RightColumnContent.Management\n || contentKey === RightColumnContent.AddingMembers),\n () => close(false), toggleChatInfo);\n\n // eslint-disable-next-line consistent-return\n function renderContent(isActive: boolean) {\n if (renderingContentKey === -1) {\n return undefined;\n }\n\n switch (renderingContentKey) {\n case RightColumnContent.AddingMembers:\n return (\n <AddChatMembers\n chatId={chatId!}\n onNextStep={handleAppendingChatMembers}\n isActive={isOpen && isActive}\n onClose={close}\n />\n );\n case RightColumnContent.ChatInfo:\n case RightColumnContent.UserInfo:\n return (\n <Profile\n key={currentProfileUserId || chatId!}\n chatId={chatId!}\n userId={currentProfileUserId}\n profileState={profileState}\n onProfileStateChange={setProfileState}\n />\n );\n case RightColumnContent.Search:\n return <RightSearch chatId={chatId!} threadId={threadId!} onClose={close} isActive={isOpen && isActive} />;\n case RightColumnContent.Management:\n return (\n <Management\n chatId={chatId!}\n currentScreen={managementScreen}\n isPromotedByCurrentUser={isPromotedByCurrentUser}\n selectedChatMemberId={selectedChatMemberId}\n onScreenSelect={setManagementScreen}\n onChatMemberSelect={handleSelectChatMember}\n isActive={isOpen && isActive}\n onClose={close}\n />\n );\n\n case RightColumnContent.StickerSearch:\n return <StickerSearch onClose={close} isActive={isOpen && isActive} />;\n case RightColumnContent.GifSearch:\n return <GifSearch onClose={close} isActive={isOpen && isActive} />;\n case RightColumnContent.PollResults:\n return <PollResults onClose={close} isActive={isOpen && isActive} />;\n }\n }\n\n return (\n <div\n id=\"RightColumn-wrapper\"\n className={!isChatSelected ? 'is-hidden' : undefined}\n >\n {isOverlaying && (\n <div className=\"overlay-backdrop\" onClick={close} />\n )}\n <div id=\"RightColumn\">\n <RightHeader\n chatId={chatId}\n isColumnOpen={isOpen}\n isProfile={isProfile}\n isSearch={isSearch}\n isManagement={isManagement}\n isStickerSearch={isStickerSearch}\n isGifSearch={isGifSearch}\n isPollResults={isPollResults}\n isAddingChatMembers={isAddingChatMembers}\n profileState={profileState}\n managementScreen={managementScreen}\n onClose={close}\n shouldSkipAnimation={shouldSkipTransition || shouldSkipHistoryAnimations}\n />\n <Transition\n name={(shouldSkipTransition || shouldSkipHistoryAnimations) ? 'none' : 'zoom-fade'}\n renderCount={MAIN_SCREENS_COUNT + MANAGEMENT_SCREENS_COUNT}\n activeKey={isManagement ? MAIN_SCREENS_COUNT + managementScreen : renderingContentKey}\n shouldCleanup\n cleanupExceptionKey={RightColumnContent.ChatInfo}\n >\n {renderContent}\n </Transition>\n </div>\n </div>\n );\n};\n\nexport default memo(withGlobal(\n (global): StateProps => {\n const { chatId, threadId } = selectCurrentMessageList(global) || {};\n const areActiveChatsLoaded = selectAreActiveChatsLoaded(global);\n\n return {\n contentKey: selectRightColumnContentKey(global),\n chatId,\n threadId,\n currentProfileUserId: global.users.selectedId,\n isChatSelected: Boolean(chatId && areActiveChatsLoaded),\n shouldSkipHistoryAnimations: global.shouldSkipHistoryAnimations,\n };\n },\n (setGlobal, actions): DispatchProps => pick(actions, [\n 'openUserInfo',\n 'toggleChatInfo',\n 'toggleManagement',\n 'closeLocalTextSearch',\n 'setStickerSearchQuery',\n 'setGifSearchQuery',\n 'closePollResults',\n 'addChatMembers',\n 'setNewChatMembersDialogState',\n ]),\n)(RightColumn));\n","import React, { FC, memo } from '../../lib/teact/teact';\n\nimport { Bundles } from '../../util/moduleLoader';\nimport useModuleLoader from '../../hooks/useModuleLoader';\n\ninterface OwnProps {\n isOpen: boolean;\n}\n\nconst MediaViewerAsync: FC<OwnProps> = ({ isOpen }) => {\n const MediaViewer = useModuleLoader(Bundles.Extra, 'MediaViewer', !isOpen);\n\n return MediaViewer ? <MediaViewer /> : undefined;\n};\n\nexport default memo(MediaViewerAsync);\n","import React, { FC, memo } from '../../lib/teact/teact';\nimport { Bundles } from '../../util/moduleLoader';\n\nimport useModuleLoader from '../../hooks/useModuleLoader';\n\nconst NotificationsAsync: FC = ({ isOpen }) => {\n const Notifications = useModuleLoader(Bundles.Extra, 'Notifications', !isOpen);\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return Notifications ? <Notifications /> : undefined;\n};\n\nexport default memo(NotificationsAsync);\n","import React, { FC, memo } from '../../lib/teact/teact';\nimport { Bundles } from '../../util/moduleLoader';\n\nimport useModuleLoader from '../../hooks/useModuleLoader';\n\nconst DialogsAsync: FC = ({ isOpen }) => {\n const Dialogs = useModuleLoader(Bundles.Extra, 'Dialogs', !isOpen);\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return Dialogs ? <Dialogs /> : undefined;\n};\n\nexport default memo(DialogsAsync);\n","import React, { FC, memo } from '../../lib/teact/teact';\nimport { Bundles } from '../../util/moduleLoader';\nimport { OwnProps } from './ForwardPicker';\n\nimport useModuleLoader from '../../hooks/useModuleLoader';\n\nconst ForwardPickerAsync: FC<OwnProps> = (props) => {\n const { isOpen } = props;\n const ForwardPicker = useModuleLoader(Bundles.Extra, 'ForwardPicker', !isOpen);\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return ForwardPicker ? <ForwardPicker {...props} /> : undefined;\n};\n\nexport default memo(ForwardPickerAsync);\n","import React, { FC, memo } from '../../lib/teact/teact';\nimport { Bundles } from '../../util/moduleLoader';\n\nimport { OwnProps } from './SafeLinkModal';\n\nimport useModuleLoader from '../../hooks/useModuleLoader';\n\nconst SafeLinkModalAsync: FC<OwnProps> = (props) => {\n const { url } = props;\n const SafeLinkModal = useModuleLoader(Bundles.Extra, 'SafeLinkModal', !url);\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return SafeLinkModal ? <SafeLinkModal {...props} /> : undefined;\n};\n\nexport default memo(SafeLinkModalAsync);\n","import React, { FC, memo } from '../../lib/teact/teact';\nimport { Bundles } from '../../util/moduleLoader';\n\nimport { OwnProps } from './HistoryCalendar';\n\nimport useModuleLoader from '../../hooks/useModuleLoader';\n\nconst HistoryCalendarAsync: FC<OwnProps> = (props) => {\n const { isOpen } = props;\n const HistoryCalendar = useModuleLoader(Bundles.Extra, 'HistoryCalendar', !isOpen);\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return HistoryCalendar ? <HistoryCalendar {...props} /> : undefined;\n};\n\nexport default memo(HistoryCalendarAsync);\n","import React, {\n FC, useEffect, memo, useCallback,\n} from '../../lib/teact/teact';\nimport { getGlobal, withGlobal } from '../../lib/teact/teactn';\n\nimport { GlobalActions } from '../../global/types';\nimport { ApiMessage } from '../../api/types';\nimport { LangCode } from '../../types';\n\nimport '../../modules/actions/all';\nimport {\n BASE_EMOJI_KEYWORD_LANG, DEBUG, INACTIVE_MARKER, PAGE_TITLE,\n} from '../../config';\nimport { pick } from '../../util/iteratees';\nimport {\n selectChatMessage,\n selectCountNotMutedUnread,\n selectIsForwardModalOpen,\n selectIsMediaViewerOpen,\n selectIsRightColumnShown,\n} from '../../modules/selectors';\nimport { dispatchHeavyAnimationEvent } from '../../hooks/useHeavyAnimationCheck';\nimport buildClassName from '../../util/buildClassName';\nimport { fastRaf } from '../../util/schedulers';\nimport { waitForTransitionEnd } from '../../util/cssAnimationEndListeners';\nimport useShowTransition from '../../hooks/useShowTransition';\nimport useBackgroundMode from '../../hooks/useBackgroundMode';\nimport useBeforeUnload from '../../hooks/useBeforeUnload';\nimport useOnChange from '../../hooks/useOnChange';\n\nimport LeftColumn from '../left/LeftColumn';\nimport MiddleColumn from '../middle/MiddleColumn';\nimport RightColumn from '../right/RightColumn';\nimport MediaViewer from '../mediaViewer/MediaViewer.async';\nimport AudioPlayer from '../middle/AudioPlayer';\nimport Notifications from './Notifications.async';\nimport Dialogs from './Dialogs.async';\nimport ForwardPicker from './ForwardPicker.async';\nimport SafeLinkModal from './SafeLinkModal.async';\nimport HistoryCalendar from './HistoryCalendar.async';\n\nimport './Main.scss';\n\ntype StateProps = {\n animationLevel: number;\n lastSyncTime?: number;\n isLeftColumnShown: boolean;\n isRightColumnShown: boolean;\n isMediaViewerOpen: boolean;\n isForwardModalOpen: boolean;\n hasNotifications: boolean;\n hasDialogs: boolean;\n audioMessage?: ApiMessage;\n safeLinkModalUrl?: string;\n isHistoryCalendarOpen: boolean;\n shouldSkipHistoryAnimations?: boolean;\n language?: LangCode;\n};\n\ntype DispatchProps = Pick<GlobalActions, (\n 'loadAnimatedEmojis' | 'loadNotificationSettings' | 'loadNotificationExceptions' | 'updateIsOnline' |\n 'loadTopInlineBots' | 'loadEmojiKeywords'\n)>;\n\nconst NOTIFICATION_INTERVAL = 1000;\n\nlet notificationInterval: number | undefined;\n\nlet DEBUG_isLogged = false;\n\nconst Main: FC<StateProps & DispatchProps> = ({\n lastSyncTime,\n isLeftColumnShown,\n isRightColumnShown,\n isMediaViewerOpen,\n isForwardModalOpen,\n animationLevel,\n hasNotifications,\n hasDialogs,\n audioMessage,\n safeLinkModalUrl,\n isHistoryCalendarOpen,\n shouldSkipHistoryAnimations,\n language,\n loadAnimatedEmojis,\n loadNotificationSettings,\n loadNotificationExceptions,\n updateIsOnline,\n loadTopInlineBots,\n loadEmojiKeywords,\n}) => {\n if (DEBUG && !DEBUG_isLogged) {\n DEBUG_isLogged = true;\n // eslint-disable-next-line no-console\n console.log('>>> RENDER MAIN');\n }\n\n // Initial API calls\n useEffect(() => {\n if (lastSyncTime) {\n updateIsOnline(true);\n loadAnimatedEmojis();\n loadNotificationSettings();\n loadNotificationExceptions();\n loadTopInlineBots();\n\n loadEmojiKeywords({ language: BASE_EMOJI_KEYWORD_LANG });\n if (language !== BASE_EMOJI_KEYWORD_LANG) {\n loadEmojiKeywords({ language });\n }\n }\n }, [\n lastSyncTime, loadAnimatedEmojis, loadNotificationExceptions, loadNotificationSettings, updateIsOnline,\n loadTopInlineBots, loadEmojiKeywords, language,\n ]);\n\n const {\n transitionClassNames: middleColumnTransitionClassNames,\n } = useShowTransition(!isLeftColumnShown, undefined, true, undefined, shouldSkipHistoryAnimations);\n\n const {\n transitionClassNames: rightColumnTransitionClassNames,\n } = useShowTransition(isRightColumnShown, undefined, true, undefined, shouldSkipHistoryAnimations);\n\n\n const className = buildClassName(\n middleColumnTransitionClassNames.replace(/([\\w-]+)/g, 'middle-column-$1'),\n rightColumnTransitionClassNames.replace(/([\\w-]+)/g, 'right-column-$1'),\n shouldSkipHistoryAnimations && 'history-animation-disabled',\n );\n\n // Dispatch heavy transition event when opening middle column\n useOnChange(([prevIsLeftColumnShown]) => {\n if (prevIsLeftColumnShown === undefined || animationLevel === 0) {\n return;\n }\n\n const dispatchHeavyAnimationEnd = dispatchHeavyAnimationEvent();\n\n waitForTransitionEnd(document.getElementById('MiddleColumn')!, dispatchHeavyAnimationEnd);\n }, [isLeftColumnShown]);\n\n // Dispatch heavy transition event and add body class when opening right column\n useOnChange(([prevIsRightColumnShown]) => {\n if (prevIsRightColumnShown === undefined || animationLevel === 0) {\n return;\n }\n\n fastRaf(() => {\n document.body.classList.add('animating-right-column');\n });\n\n const dispatchHeavyAnimationEnd = dispatchHeavyAnimationEvent();\n\n waitForTransitionEnd(document.getElementById('RightColumn')!, () => {\n dispatchHeavyAnimationEnd();\n\n fastRaf(() => {\n document.body.classList.remove('animating-right-column');\n });\n });\n }, [isRightColumnShown]);\n\n const handleBlur = useCallback(() => {\n updateIsOnline(false);\n\n const initialUnread = selectCountNotMutedUnread(getGlobal());\n let index = 0;\n\n clearInterval(notificationInterval);\n notificationInterval = window.setInterval(() => {\n if (document.title.includes(INACTIVE_MARKER)) {\n updateIcon(false);\n return;\n }\n\n if (index % 2 === 0) {\n const newUnread = selectCountNotMutedUnread(getGlobal()) - initialUnread;\n if (newUnread > 0) {\n updatePageTitle(`${newUnread} notification${newUnread > 1 ? 's' : ''}`);\n updateIcon(true);\n }\n } else {\n updatePageTitle(PAGE_TITLE);\n updateIcon(false);\n }\n\n index++;\n }, NOTIFICATION_INTERVAL);\n }, [updateIsOnline]);\n\n const handleFocus = useCallback(() => {\n updateIsOnline(true);\n\n clearInterval(notificationInterval);\n notificationInterval = undefined;\n\n if (!document.title.includes(INACTIVE_MARKER)) {\n updatePageTitle(PAGE_TITLE);\n }\n\n updateIcon(false);\n }, [updateIsOnline]);\n\n // Online status and browser tab indicators\n useBackgroundMode(handleBlur, handleFocus);\n useBeforeUnload(handleBlur);\n\n function stopEvent(e: React.MouseEvent<HTMLDivElement, MouseEvent>) {\n e.preventDefault();\n e.stopPropagation();\n }\n\n return (\n <div id=\"Main\" className={className} onDrop={stopEvent} onDragOver={stopEvent}>\n <LeftColumn />\n <MiddleColumn />\n <RightColumn />\n <MediaViewer isOpen={isMediaViewerOpen} />\n <ForwardPicker isOpen={isForwardModalOpen} />\n <Notifications isOpen={hasNotifications} />\n <Dialogs isOpen={hasDialogs} />\n {audioMessage && <AudioPlayer key={audioMessage.id} message={audioMessage} noUi />}\n <SafeLinkModal url={safeLinkModalUrl} />\n <HistoryCalendar isOpen={isHistoryCalendarOpen} />\n </div>\n );\n};\n\nfunction updateIcon(asUnread: boolean) {\n document.querySelectorAll<HTMLLinkElement>('link[rel=\"icon\"]')\n .forEach((link) => {\n if (asUnread) {\n if (!link.href.includes('favicon-unread')) {\n link.href = link.href.replace('favicon', 'favicon-unread');\n }\n } else {\n link.href = link.href.replace('favicon-unread', 'favicon');\n }\n });\n}\n\n// For some reason setting `document.title` to the same value\n// causes increment of Chrome Dev Tools > Performance Monitor > DOM Nodes counter\nfunction updatePageTitle(nextTitle: string) {\n if (document.title !== nextTitle) {\n document.title = nextTitle;\n }\n}\n\nexport default memo(withGlobal(\n (global): StateProps => {\n const { chatId: audioChatId, messageId: audioMessageId } = global.audioPlayer;\n const audioMessage = audioChatId && audioMessageId\n ? selectChatMessage(global, audioChatId, audioMessageId)\n : undefined;\n\n return {\n animationLevel: global.settings.byKey.animationLevel,\n lastSyncTime: global.lastSyncTime,\n isLeftColumnShown: global.isLeftColumnShown,\n isRightColumnShown: selectIsRightColumnShown(global),\n isMediaViewerOpen: selectIsMediaViewerOpen(global),\n isForwardModalOpen: selectIsForwardModalOpen(global),\n hasNotifications: Boolean(global.notifications.length),\n hasDialogs: Boolean(global.dialogs.length),\n audioMessage,\n safeLinkModalUrl: global.safeLinkModalUrl,\n isHistoryCalendarOpen: Boolean(global.historyCalendarSelectedAt),\n shouldSkipHistoryAnimations: global.shouldSkipHistoryAnimations,\n language: global.settings.byKey.language,\n };\n },\n (setGlobal, actions): DispatchProps => pick(actions, [\n 'loadAnimatedEmojis', 'loadNotificationSettings', 'loadNotificationExceptions', 'updateIsOnline',\n 'loadTopInlineBots', 'loadEmojiKeywords',\n ]),\n)(Main));\n","import { getDispatch, getGlobal } from '../lib/teact/teactn';\n\nimport { DEBUG } from '../config';\n\nexport { default as Main } from '../components/main/Main';\n\nif (DEBUG) {\n // eslint-disable-next-line no-console\n console.log('>>> FINISH LOAD MAIN BUNDLE');\n}\n\nif (!getGlobal().connectionState) {\n getDispatch().initApi();\n}\n"],"sourceRoot":""} |