mirror of
https://github.com/danog/telegram-tt.git
synced 2024-12-02 17:48:34 +01:00
1 line
381 KiB
Plaintext
1 line
381 KiB
Plaintext
{"version":3,"sources":["webpack:///./src/components/ui/ListItem.tsx","webpack:///./src/hooks/useIntersectionObserver.ts","webpack:///./src/hooks/useMedia.ts","webpack:///./src/components/common/PrivateChatInfo.tsx","webpack:///./src/components/ui/Modal.tsx","webpack:///./src/util/trapFocus.ts","webpack:///./src/components/ui/Transition.tsx","webpack:///./src/components/common/Avatar.tsx","webpack:///./src/components/ui/InfiniteScroll.tsx","webpack:///./src/hooks/useTransitionForMedia.ts","webpack:///./src/components/common/helpers/mediaDimensions.ts","webpack:///./src/components/common/AnimatedSticker.tsx","webpack:///./src/components/ui/ConfirmDialog.tsx","webpack:///./src/components/common/NothingFound.tsx","webpack:///./src/components/right/hooks/useAsyncRendering.ts","webpack:///./src/hooks/useMediaWithDownloadProgress.ts","webpack:///./src/components/ui/ProgressSpinner.tsx","webpack:///./src/components/ui/Portal.ts","webpack:///./src/components/common/GroupChatInfo.tsx","webpack:///./src/util/fastSmoothScroll.ts","webpack:///./src/components/ui/Radio.tsx","webpack:///./src/components/ui/RadioGroup.tsx","webpack:///./src/hooks/useBackgroundMode.ts","webpack:///./src/hooks/useInfiniteScroll.ts","webpack:///./src/components/common/AnimatedEmoji.tsx","webpack:///./src/util/focusEditableElement.ts","webpack:///./src/util/captureEvents.ts","webpack:///./src/components/common/VerifiedIcon.tsx","webpack:///./src/util/cycleRestrict.ts","webpack:///./src/hooks/useCurrentOrPrev.ts","webpack:///./src/util/safePlay.ts","webpack:///./src/hooks/useBuffering.ts","webpack:///./src/components/middle/composer/helpers/parseMessageInput.ts","webpack:///./src/components/middle/composer/DropTarget.tsx","webpack:///./src/components/middle/composer/DropArea.tsx","webpack:///./src/components/common/PickerSelectedItem.tsx","webpack:///./src/util/fastSmoothScrollHorizontal.ts","webpack:///./src/hooks/useHorizontalScroll.ts","webpack:///./src/hooks/useEnsureMessage.ts","webpack:///./src/hooks/useContextMenuHandlers.ts","webpack:///./src/components/common/helpers/renderMessageText.tsx","webpack:///./src/hooks/useVideoCleanup.ts","webpack:///./src/util/clipboard.ts","webpack:///./src/components/ui/SearchInput.tsx","webpack:///./src/util/resetScroll.ts","webpack:///./src/components/common/TypingStatus.tsx","webpack:///./src/components/common/DeleteChatModal.tsx","webpack:///./src/components/ui/ShowTransition.tsx","webpack:///./src/util/patchSafariProgressiveAudio.ts","webpack:///./src/hooks/useLayoutEffectWithPrevDeps.ts","webpack:///./src/components/common/Document.tsx","webpack:///./src/components/common/StickerSetModal.async.tsx","webpack:///./src/hooks/useCanvasBlur.ts","webpack:///./src/lib/fastBlur.js","webpack:///./src/components/middle/composer/TextFormatter.tsx","webpack:///./src/components/common/Media.tsx","webpack:///./src/components/common/Audio.tsx","webpack:///./src/util/waveform.ts","webpack:///./src/components/common/helpers/waveform.ts","webpack:///./src/components/ui/Tab.tsx","webpack:///./src/components/ui/TabList.tsx","webpack:///./src/util/getReadableErrorText.ts","webpack:///./src/hooks/useChatContextActions.ts","webpack:///./src/components/common/LastMessageMeta.tsx","webpack:///./src/components/common/MessageOutgoingStatus.tsx","webpack:///./src/hooks/useContextMenuPosition.ts","webpack:///./src/hooks/usePrevDuringAnimation.ts","webpack:///./src/hooks/useAudioPlayer.ts","webpack:///./src/util/audioPlayer.ts","webpack:///./src/util/download.ts","webpack:///./src/components/common/File.tsx","webpack:///./src/hooks/useMediaDownload.ts","webpack:///./src/components/ui/Notification.tsx","webpack:///./src/components/middle/composer/helpers/selection.ts","webpack:///./src/components/middle/composer/hooks/useEmojiTooltip.ts","webpack:///./src/components/middle/composer/EmojiTooltip.async.tsx","webpack:///./src/components/middle/composer/MessageInput.tsx","webpack:///./src/components/common/WebLink.tsx","webpack:///./src/components/left/main/hooks/useChatAnimationType.ts","webpack:///./src/components/left/main/Badge.tsx","webpack:///./src/components/left/main/Chat.tsx","webpack:///./src/components/left/main/ChatList.tsx","webpack:///./src/components/middle/composer/hooks/useMentionTooltip.ts","webpack:///./src/components/middle/composer/helpers/searchUserName.ts","webpack:///./src/hooks/useBlur.ts","webpack:///./src/hooks/useBlurSync.ts"],"names":["ListItem","props","ref","buttonRef","icon","className","style","children","disabled","ripple","narrow","inactive","focus","destructive","multiline","isStatic","contextActions","onClick","containerRef","useRef","isContextMenuOpen","contextMenuPosition","handleBeforeContextMenu","handleContextMenu","handleContextMenuClose","handleContextMenuHide","useContextMenuHandlers","getTriggerElement","useCallback","current","getRootElement","closest","getMenuElement","querySelector","positionX","positionY","menuStyle","useContextMenuPosition","handleClick","e","handleMouseDown","IS_TOUCH_ENV","button","lang","useLang","fullClassName","buildClassName","dir","isRtl","undefined","role","tabIndex","onMouseDown","onContextMenu","isOpen","autoClose","onClose","onCloseAnimationEnd","map","action","key","title","handler","useIntersectionObserver","rootRef","throttleMs","debounceMs","shouldSkipFirst","margin","threshold","isDisabled","rootCallback","controllerRef","rootCallbackRef","freezeFlagsRef","onUnfreezeRef","freeze","unfreeze","useHeavyAnimationCheck","useEffect","observer","disconnect","callbacks","clear","observe","target","targetCallback","Map","entriesAccumulator","observerCallbackSync","entries","Array","from","values","forEach","entry","callback","get","scheduler","throttle","debounce","observerCallback","IntersectionObserver","set","root","rootMargin","initController","controller","delete","unobserve","useOnIntersect","targetRef","useIsIntersecting","isIntersecting","setIsIntersecting","useState","mediaHash","noLoad","mediaFormat","ApiMediaFormat","BlobUrl","cacheBuster","delay","mediaData","mediaLoader","forceUpdate","useForceUpdate","startedAt","Date","now","then","spentTime","setTimeout","memo","withGlobal","global","userId","forceShowSelf","lastSyncTime","serverTimeOffset","user","selectUser","isSavedMessages","isSelf","areMessagesLoaded","Boolean","selectChatMessages","setGlobal","actions","pick","typingStatus","avatarSize","status","withMediaViewer","withUsername","withFullInfo","withUpdatingStatus","noStatusOrTyping","noRtl","loadFullUser","openMediaViewer","id","fullName","getUserFullName","handleAvatarViewerOpen","hasPhoto","stopPropagation","avatarOwnerId","origin","MediaViewerOrigin","ProfileAvatar","MiddleHeaderAvatar","size","renderText","isVerified","isUserOnline","username","getUserStatus","Modal","header","hasCloseButton","noBackdrop","onEnter","shouldRender","transitionClassNames","useShowTransition","modalRef","captureKeyboardListeners","onEsc","element","handleKeyDown","preventDefault","focusableElements","querySelectorAll","length","currentFocusedIndex","findIndex","em","isSameNode","document","activeElement","newFocusedIndex","shiftKey","addEventListener","removeEventListener","trapFocus","useEffectWithPrevDeps","prevIsOpen","body","classList","toggle","dispatchHeavyAnimationEvent","remove","Portal","Button","round","color","ariaLabel","ANIMATION_DURATION","slide","fade","IS_SINGLE_COLUMN_LAYOUT","reveal","CLEANED_UP","Symbol","Transition","activeKey","name","direction","renderCount","shouldRestoreHeight","shouldCleanup","cleanupExceptionKey","onStart","onStop","animationLevel","getGlobal","settings","byKey","rendersRef","prevActiveKey","usePrevious","activateTimeoutRef","activeKeyChanged","useLayoutEffect","cleanup","container","childElements","add","childNodes","clearTimeout","isBackwards","keys","Object","Number","prevActiveIndex","indexOf","activeIndex","node","i","HTMLElement","width","offsetWidth","scrollBy","left","behavior","ANIMATION_END_DELAY","requestAnimationFrame","window","scrollLeft","height","clientHeight","flexBasis","renders","contents","fill","render","chat","text","withOnlineStatus","isDeleted","isDeletedUser","imageHash","getChatAvatarHash","dataUri","useMedia","DataUri","shouldRenderFullMedia","useTransitionForMedia","content","src","alt","decoding","userFullName","getFirstLetters","getChatTitle","isChatPrivate","isOnline","getUserColorKey","senderId","data-test-sender-id","IS_TEST","InfiniteScroll","onLoadMore","onScroll","onKeyDown","items","itemSelector","preloadBackwards","sensitiveArea","noScrollRestore","noScrollRestoreOnTop","noFastList","stateRef","loadMoreBackwards","loadMoreForwards","useMemo","noScroll","LoadMoreDirection","Backwards","Forwards","scrollHeight","state","newScrollTop","listItemElements","currentAnchor","includes","scrollTop","getBoundingClientRect","top","currentAnchorTop","nextAnchor","resetScroll","isScrollTopJustUpdated","handleScroll","listLength","offsetHeight","isNearTop","offsetTop","isNearBottom","isUpdated","nextAnchorTop","newAnchorTop","offsetParent","teactFastList","SPEED","fast","slow","speed","noAnimate","isMediaLoaded","willAnimate","shouldRenderThumb","setShouldRenderThumb","MEDIA_VIEWER_MEDIA_QUERY","REM","parseInt","getComputedStyle","documentElement","fontSize","ROUND_VIDEO_DIMENSIONS","AVATAR_FULL_DIMENSIONS","DEFAULT_MEDIA_DIMENSIONS","LIKE_STICKER_ID","cachedMaxWidth","getAvailableWidth","fromOwnMessage","isForwarded","isWebPagePhoto","extraPaddingRem","regularMaxWidth","Math","min","floor","innerWidth","getMaxMessageWidthRem","calculateDimensionsForMessageMedia","isGif","aspectRatio","calculateDimensions","getAvailableHeight","getMediaViewerAvailableDimensions","withFooter","isVideo","mql","matchMedia","windowWidth","windowHeight","windowSize","occupiedHeightRem","matches","calculateInlineImageDimensions","photo","getPhotoInlineDimensions","calculateVideoDimensions","video","getVideoDimensions","getPictogramDimensions","getDocumentThumbnailDimensions","smaller","getStickerDimensions","sticker","baseWidth","STICKER_SIZE_INLINE_MOBILE_FACTOR","STICKER_SIZE_INLINE_DESKTOP_FACTOR","calculatedHeight","calculateMediaViewerDimensions","availableWidth","availableHeight","mediaWidth","mediaHeight","calculatedWidth","lottiePromise","RLottie","async","ensureLottie","default","animationData","play","playSegment","noLoop","quality","isLowPriority","onLoad","animation","setAnimation","wasPlaying","isFrozen","playRef","playSegmentRef","exec","newAnimation","setSpeed","fastRaf","destroy","playAnimation","shouldRestart","goToAndPlay","pauseAnimation","pause","freezeAnimation","isPlaying","unfreezeAnimation","unfreezeAnimationOnRaf","useBackgroundMode","textParts","confirmLabel","confirmHandler","confirmIsDestructive","isButtonsInOneRow","split","textPart","isText","description","useAsyncRendering","dependencies","shouldRenderRef","timeoutRef","useOnChange","isStreaming","Stream","IS_PROGRESSIVE_SUPPORTED","Progressive","downloadProgress","setDownloadProgress","startedAtRef","handleProgress","progress","RADIUSES","s","m","l","xl","square","transparent","noCross","radius","circleRadius","STROKE_WIDTH","borderRadius","circumference","PI","svg","firstElementChild","strokeDashOffset","max","setAttribute","toString","innerHTML","containerId","elementRef","createElement","appendChild","TeactDOM","removeChild","chatId","selectChat","onlineCount","selectChatOnlineCount","withChatType","loadFullChat","isSuperGroup","isChatSuperGroup","isMin","isRestricted","getChatTypeString","handle","groupStatus","chatTypeString","membersCount","getGroupStatus","onlineStatus","renderStatusOrTyping","isAnimating","fastSmoothScroll","position","maxDistance","forceDirection","forceDuration","forceCurrentContainerHeight","FocusDirection","Static","block","scrollIntoView","offset","Up","Down","elementTop","elementHeight","containerHeight","targetContainerHeight","dataset","normalHeight","path","remainingPath","duration","abs","startAt","animateSingle","t","currentPath","transition","scrollWithJs","isAnimatingScroll","label","subLabel","value","checked","hidden","isLoading","onChange","type","Spinner","options","selected","loadingOption","handleChange","event","currentTarget","option","onBlur","onFocus","hasFocus","getViewportSlice","sourceIds","offsetId","listSlice","index","indexForDirection","to","newViewportIds","slice","areSomeLocal","areAllLocal","listIds","forceFullPreload","lastParamsRef","viewportIdsRef","prevListIds","prevIsDisabled","areSortedArraysEqual","viewportIds","getMore","AnimatedEmoji","isInline","observeIntersection","forceLoadPreview","isAnimationLoaded","markAnimationLoaded","useFlag","localMediaHash","thumbDataUri","thumbnail","previewBlobUrl","Lottie","playKey","setPlayKey","String","random","STICKER_SIZE_TWO_FA","focusEditableElement","force","selection","getSelection","range","createRange","lastChild","nodeValue","setStart","removeAllRanges","addRange","SwipeDirection","captureEvents","captureEvent","currentSwipeAxis","hasMoved","onCapture","excludedClosestSelector","onMove","onRelease","pageX","touches","pageY","withCursor","dragOffsetX","dragOffsetY","onDrag","onSwipe","xAbs","yAbs","Left","Right","processSwipe","passive","VerifiedIcon","cycleRestrict","useCurrentOrPrev","shouldSkipUndefined","shouldForceCurrent","prev","mediaEl","catch","err","DEBUG","console","warn","noInitiallyBuffered","isBuffered","setIsBuffered","bufferedProgress","setBufferedProgress","setIsBufferedDebounced","handleBuffering","media","isSafariPatchInProgress","buffered","end","readyState","currentTime","bufferingHandlers","onLoadedData","onPlaying","onLoadStart","onPause","onTimeUpdate","onProgress","checkBuffering","ENTITY_CLASS_BY_NODE_NAME","B","ApiMessageEntityTypes","Bold","STRONG","I","Italic","EM","U","Underline","S","Strike","STRIKE","DEL","CODE","Code","PRE","Pre","BLOCKQUOTE","Blockquote","parseMessageInput","html","fragment","parsedHtml","IS_EMOJI_SUPPORTED","replace","parseMarkdown","innerText","trim","textIndex","recursionDeepness","entities","addEntity","entity","rawText","nodeName","anchor","entityType","MentionName","Url","href","startsWith","Email","Phone","textContent","TextUrl","getEntityTypeFromNode","rawIndex","substring","url","getEntityDataFromNode","push","hasChildNodes","isQuick","onFileSelect","isHovered","markHovered","unmarkHovered","onDrop","onDragEnter","onDragLeave","relatedTarget","toTarget","DropAreaState","withQuick","onHide","hideTimeoutRef","prevWithQuick","captureEscKeyListener","handleFilesDrop","dataTransfer","dt","files","handleQuickFilesDrop","handleDragLeave","fromTarget","onDragOver","chatOrUserId","isMinimized","canClose","clickArg","iconElement","titleText","getUserFirstOrLastName","fastSmoothScrollHorizontal","IS_IOS","containerWidth","scrollWidth","animate","scrollTo","deltaX","deltaY","messageId","message","replyOriginForId","loadMessage","getDispatch","loadMessageThrottled","throttled","contextMenuCounter","isMenuDisabled","shouldDisableOnLink","setIsContextMenuOpen","setContextMenuPosition","x","clientX","y","clientY","timer","clearLongPressTimer","startLongPressTimer","contains","originalEvent","cancelClickOnce","stopImmediatePropagation","emulateContextMenuEvent","renderMessageText","highlight","shouldRenderHqEmoji","formattedText","getMessageText","renderTextWithEntities","organizeEntities","organizedEntityIndexes","Set","organizedEntities","has","organizedEntity","organizeEntity","organizedIndexes","nestedEntities","filter","organizedIndex","shouldRenderAsHtml","renderMessagePart","result","deleteLineBreakAfterPre","organizedEntites","renderEntity","textPartStart","textPartEnd","isLastEntity","renderResult","textBefore","textBeforeLength","substr","entityStartIndex","entityEndIndex","entityContent","nestedEntityContent","nestedIndex","nestedEntity","nestedEntityIndex","nestedResult","nestedEntityEndIndex","newEntity","rawEntityText","renderedContent","join","getLinkUrl","processEntityAsHtml","entityText","BotCommand","handleBotCommandClick","Hashtag","Cashtag","handleHashtagClick","rel","Mention","processEntity","isArray","textAfter","arrayIndex","c","emojiFilter","sendBotCommand","command","setLocalTextSearchQuery","query","searchTextMessagesLocal","useVideoCleanup","videoRef","videoEl","load","CLIPBOARD_ITEM_SUPPORTED","navigator","clipboard","ClipboardItem","textCopyEl","copyTextToClipboard","str","rangeToRestore","rangeCount","getRangeAt","select","execCommand","copyImageToClipboard","imageUrl","canvas","ctx","getContext","imageEl","Image","onload","img","drawImage","toBlob","copyBlobToClipboard","pngBlob","write","error","parentContainerClassName","inputId","focused","placeholder","autoComplete","onReset","inputRef","isInputFocused","markInputFocused","unmarkInputFocused","blur","overflow","typingUser","typingUserName","isPrivateChat","isChatWithSelf","selectIsChatWithSelf","canDeleteForAll","contactName","getPrivateChatUserId","isChannel","isChatChannel","isBasicGroup","isChatBasicGroup","leaveChannel","deleteHistory","deleteChannel","chatTitle","handleDeleteMessageForAll","shouldDeleteForAll","handleDeleteChat","isCreator","ShowTransition","isCustom","prevChildren","fromChildrenRef","patchSafariProgressiveAudio","audioEl","patchedForSafari","patchForSafariInProgress","paused","once","cb","prevDeps","uploadProgress","withDate","datetime","sender","isSelected","isSelectable","onCancelUpload","onDateClick","extension","getDocumentExtension","fileName","timestamp","isDownloadAllowed","setIsDownloadAllowed","useMediaWithDownloadProgress","getMessageMediaHash","isUploading","isTransferring","transferProgress","getMediaTransferState","hasPreview","getDocumentHasPreview","getMessageMediaThumbDataUri","localBlobUrl","previewData","isAllowed","handleDateClick","download","thumbnailDataUri","StickerSetModal","useModuleLoader","Bundles","Extra","useCanvasBlur","withRaf","canvasRef","processBlur","alpha","IS_CANVAS_FILTER_SUPPORTED","RADIUS","fastBlur","mul_table","shg_table","boxBlurCanvasRGB","context","top_x","top_y","iterations","isNaN","imageData","getImageData","pixels","data","rsum","gsum","bsum","p","p1","p2","yp","yi","yw","wm","hm","rad1","r","g","b","mul_sum","shg_sum","vmin","vmax","putImageData","TEXT_FORMAT_BY_TAG_NAME","anchorPosition","selectedRange","linkUrlInputRef","isLinkControlOpen","openLinkControl","closeLinkControl","linkUrl","setLinkUrl","isEditingLink","setIsEditingLink","inputClassName","setInputClassName","selectedTextFormats","setSelectedTextFormats","useVirtualBackdrop","selectedFormats","parentElement","commonAncestorContainer","EDITABLE_INPUT_ID","textFormat","tagName","getSelectedText","getSelectedElement","updateInputStyles","input","getFormatButtonClassName","some","fKey","monospace","strikethrough","handleBoldText","bold","handleItalicText","italic","handleUnderlineText","underline","handleStrikethroughText","replaceWith","handleMonospaceText","handleLinkUrlConfirm","formattedLinkUrl","restoreSelection","KeyK","KeyB","KeyU","KeyI","KeyM","KeyS","code","altKey","ctrlKey","metaKey","linkUrlConfirmClassName","inputMode","idPrefix","mediaBlobUrl","getMessageVideo","formatMediaDuration","MIN_SPIKES","MAX_SPIKES","renderSeekline","playProgress","handleStartSeek","handleSeek","handleStopSeek","onMouseMove","onMouseUp","theme","senderTitle","date","onPlay","onReadMedia","audio","voice","isMediaUnread","isVoice","isSeeking","isActivated","setIsActivated","shouldDownload","getMessageMediaFormat","useBuffering","playPause","setCurrentTime","useAudioPlayer","getMessageKey","getMediaDuration","isMessageLocal","isDownloadStarted","directDownloadProgress","handleDownloadClick","useMediaDownload","getMessageAudioCaption","isLoadingForPlaying","shouldRenderSpinner","spinnerClassNames","handleButtonClick","seekBar","seekHandlers","isOwn","isOwnMessage","renderedWaveform","waveform","fillColor","fillOwnColor","progressFillColor","progressFillOwnColor","durationFactor","spikesCount","decodedWaveform","encoded5bit","bitsCount","valuesCount","bitsData","byteIndex","bitShift","lastByteIndex","lastBitShift","lastValue","decodeWaveform","Uint8Array","spikes","peak","fitCount","newData","springFactor","leftFiller","rightFiller","idx","val","interpolateArray","fillStyle","progressFillStyle","scale","item","globalAlpha","spikeHeight","beginPath","moveTo","arcTo","closePath","roundedRectangle","toDataURL","renderWaveformToDataUri","draggable","renderWaveform","buttonClassNames","showSeekline","contentClassName","ProgressSpinner","getFirstLine","Link","formatPastTimeShort","performer","getSecondLine","formatMediaDateTime","renderAudio","renderVoice","active","badgeCount","isBadgeActive","previousActiveTab","tabRef","tab","indicator","currentIndicator","shiftLeft","offsetLeft","scaleFactor","clientWidth","transform","tabs","activeTab","big","onSwitchTab","useHorizontalScroll","activeTabElement","newLeft","READABLE_ERROR_MESSAGES","CHAT_RESTRICTED","CHAT_WRITE_FORBIDDEN","CHAT_SEND_POLL_FORBIDDEN","CHAT_SEND_STICKERS_FORBIDDEN","CHAT_SEND_GIFS_FORBIDDEN","CHAT_SEND_MEDIA_FORBIDDEN","CHAT_LINK_EXISTS","SLOWMODE_WAIT_X","USER_BANNED_IN_CHANNEL","USER_IS_BLOCKED","YOU_BLOCKED_USER","IMAGE_PROCESS_FAILED","MEDIA_EMPTY","MEDIA_INVALID","PHOTO_EXT_INVALID","PHOTO_INVALID_DIMENSIONS","PHOTO_SAVE_FILE_INVALID","MESSAGE_DELETE_FORBIDDEN","MESSAGE_POLL_CLOSED","MESSAGE_EDIT_TIME_EXPIRED","CHAT_ADMIN_REQUIRED","PINNED_DIALOGS_TOO_MUCH","DIALOG_FILTERS_TOO_MUCH","CHANNEL_PRIVATE","MEDIA_CAPTION_TOO_LONG","ADDRESS_STREET_LINE1_INVALID","ADDRESS_STREET_LINE2_INVALID","ADDRESS_CITY_INVALID","ADDRESS_COUNTRY_INVALID","ADDRESS_POSTCODE_INVALID","ADDRESS_STATE_INVALID","REQ_INFO_NAME_INVALID","REQ_INFO_PHONE_INVALID","REQ_INFO_EMAIL_INVALID","LINK_NOT_MODIFIED","SERVICE_WORKER_DISABLED","CAPTION_TOO_LONG_PLEASE_REMOVE_CHARACTERS","FRESH_RESET_AUTHORISATION_FORBIDDEN","BOTS_TOO_MUCH","BOT_GROUPS_BLOCKED","USERS_TOO_MUCH","USER_CHANNELS_TOO_MUCH","USER_KICKED","USER_NOT_MUTUAL_CONTACT","USER_PRIVACY_RESTRICTED","INVITE_HASH_EMPTY","INVITE_HASH_EXPIRED","INVITE_HASH_INVALID","CHANNELS_TOO_MUCH","USER_ALREADY_PARTICIPANT","getReadableErrorText","isSlowMode","textParams","extraPartIndex","errorMessage","reduce","acc","privateChatUser","handleDelete","folderId","isPinned","isMuted","toggleChatPinned","updateChatMutedState","toggleChatArchived","toggleChatUnread","actionUnreadMark","unreadCount","hasUnreadMark","actionPin","actionMute","actionArchive","isChatArchived","getCanDeleteChat","outgoingStatus","Keys","extraPaddingX","extraTopPadding","setPositionX","setPositionY","setStyle","triggerEl","emptyRect","menuEl","rootEl","triggerRect","menuRect","rootRect","usePrevDuringAnimation","isCurrentPresent","isPrevPresent","trackId","originalDuration","handlers","onInit","shouldPlay","onForcePlay","noPlaylist","setIsPlaying","isPlayingSync","setPlayProgress","register","eventName","proxy","isFinite","prevShouldPlay","prevSrc","audioProxy","tracks","currentTrackId","queue","stopCurrentAudio","currentTrack","Audio","handleEvent","nextTrackId","openAudioPlayer","parseMessageKey","nextTrack","safePlay","Proxy","createAudio","preload","IS_SAFARI","time","shouldRemoveFromQueue","track","h","filename","link","click","shouldSpinnerRender","getColorFromExtension","sizeString","getFileSizeString","setIsDownloadStarted","onDismiss","setIsOpen","timerRef","closeAndDismiss","handleMouseEnter","handleMouseLeave","onMouseEnter","onMouseLeave","isSelectionInsideInput","selectionRange","parentNode","emojiDataPromise","emojiRawData","emojiData","RE_NOT_EMOJI_SEARCH","RegExp","useEmojiTooltip","recentEmojiIds","onUpdateHtml","baseEmojiKeywords","emojiKeywords","markIsOpen","unmarkIsOpen","byId","setById","keywords","setKeywords","byKeyword","setByKeyword","names","setNames","byName","setByName","filteredEmojis","setFilteredEmojis","recentEmojis","pickTruthy","emojis","uncompressEmoji","ensureEmojiData","byNative","buildCollectionByKey","baseEmojisByKeyword","mapValues","natives","emojisByKeyword","emojisByName","emoji","tempEl","lastSymbol","lastWord","pop","test","toLowerCase","getEmojiCode","matched","matchedKeywords","keyword","sort","concat","flatten","matchedNames","unique","insertEmoji","textEmoji","atIndex","lastIndexOf","messageInput","getElementById","isEmojiTooltipOpen","closeEmojiTooltip","EmojiTooltip","MAX_INPUT_HEIGHT","currentChatId","threadId","selectCurrentMessageList","messageSendKeyCombo","replyingToId","selectReplyingToId","noTabCapture","isPollModalOpen","payment","isPaymentModalOpen","editableInputId","shouldSetFocus","shouldSupressFocus","shouldSupressTextFormatter","onUpdate","onSupressedFocus","onSend","editLastMessage","replyToNextMessage","cloneRef","isContextMenuOpenRef","isTextFormatterOpen","openTextFormatter","closeTextFormatter","textFormatterAnchorPosition","setTextFormatterAnchorPosition","setSelectedRange","updateInputHeight","useLayoutEffectWithPrevDeps","prevHtml","focusInput","handleCloseTextFormatter","empty","clearSelection","checkSelection","selectedText","parseEmojiOnlyString","START_TO_END","selectionRect","inputRect","willSend","clone","currentHeight","newHeight","transitionDuration","log","captureFirstTab","onTab","supressFocus","contentEditable","targetIndexDelta","handleKeyUp","IS_ANDROID","closeContextMenuMouseListener","closeContextMenuKeyListener","handleMouseUp","onTouchCancel","onMessageClick","linkData","getMessageWebPage","getFirstLinkInMessage","domain","messageText","getMessageSummaryText","siteName","handleMessageClick","displayUrl","truncatedDescription","trimText","data-initial","ChatAnimationTypes","isShown","renderContent","unreadMentionsCount","formatIntegerCompact","FolderTypeToListType","lastMessage","replyToMessageId","isOutgoing","lastMessageSender","lastMessageAction","getMessageAction","actionTargetMessage","selectChatMessage","targetUserId","actionTargetUserId","targetChatId","actionTargetChatId","privateChatUserId","messageListType","selectIsChatMuted","selectNotifySettings","selectNotifyExceptions","lastMessageOutgoingStatus","selectOutgoingStatus","actionTargetUser","draft","selectDraft","MAIN_THREAD_ID","orderDiff","animationType","openChat","focusLastMessage","isDeleteModalOpen","openDeleteModal","closeDeleteModal","shouldRenderDeleteModal","markRenderDeleteModal","unmarkRenderDeleteModal","isAction","isActionMessage","useEnsureMessage","mediaThumbnail","getMessageSticker","isRoundVideo","getMessageRoundVideo","Opacity","opacity","Move","useChatContextActions","Avatar","LastMessageMeta","TypingStatus","actionOrigin","renderActionMessageText","asPlain","senderName","getMessageSenderName","blobUrl","renderMessageSummary","renderLastMessageOrTyping","DeleteChatModal","folderType","chats","chatsById","orderedPinnedIds","users","usersById","currentThreadId","listType","chatFolder","selectChatFolder","isInDiscussionThread","notifySettings","notifyExceptions","noChatsText","isActive","loadMoreChats","preloadTopChatMessages","currentListIds","currentPinnedIds","prepareFolderListIds","orderById","orderedIds","newChatArrays","prepareChatList","singleList","pinnedChats","otherChats","newOrderedIds","prevOrderById","orderDiffById","order","Infinity","loadMoreOfType","useInfiniteScroll","CHAT_LIST_SLICE","ALL_CHATS_PRELOAD_DISABLED","chatArrays","getAnimationType","movesUp","movesDown","orderDiffIds","numberOfUp","numberOfDown","None","useChatAnimationType","digit","match","nextId","viewportOffset","pinnedOffset","CHAT_HEIGHT_PX","teactOrderKey","getChatOrder","renderChats","Loading","RE_NOT_USERNAME_SEARCH","useMentionTooltip","canSuggestMembers","groupChatMembers","currentUserId","currentFilter","setCurrentFilter","filteredMembers","setFilteredMembers","getFilteredMembers","usernameLowered","fullNameLowered","filterLowered","searchWords","searchUserName","usernameFilter","getUsernameFilter","membersToMention","insertMention","forceFocus","insertedHtml","isMentionTooltipOpen","mentionFilter","closeMentionTooltip","mentionFilteredMembers","cache","useBlurSync","blurredRef","isChanged","imgToCanvas","blurredAsync","blurredDataUri","useBlur"],"mappings":"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IAAK,IAAK,IAAK,GAAI,IAAK,IAAK,GAAI,IAAK,IAAK,GAAI,GAAI,IAAK,IAAK,IAAK,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,GAAI,IAAK,IAAK,IAAK,GAAI,GAAI,IAAK,IAAK,IAAK,GAAI,IAAK,IAAK,GAAI,IAAK,IAAK,IAAK,IAAK,GAAI,IAAK,IAAK,IAAK,IAAK,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAI,IAAK,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAI,GAAI,IAAK,IAAK,GAAI,IAAK,IAAK,EAAG,GAAI,IAAK,GAAI,IAAK,IAAK,GAAI,GAAI,IAAK,GAAI,IAAK,GAAI,IAAK,IAAK,GAAI,IAAK,IAAK,IAAK,IAAK,GAAI,IAAK,IAAK,IAAK,GAAI,IAAK,GAAI,IAAK,GAE5qCC,EAAY,CAAC,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GA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","file":"0.f9589de93ccf198a3f55.js","sourcesContent":["import { RefObject } from 'react';\nimport React, { FC, useRef, useCallback } from '../../lib/teact/teact';\n\nimport { IS_TOUCH_ENV } from '../../util/environment';\nimport buildClassName from '../../util/buildClassName';\nimport useContextMenuHandlers from '../../hooks/useContextMenuHandlers';\nimport useContextMenuPosition from '../../hooks/useContextMenuPosition';\nimport useLang from '../../hooks/useLang';\n\nimport RippleEffect from './RippleEffect';\nimport Menu from './Menu';\nimport MenuItem from './MenuItem';\n\nimport './ListItem.scss';\n\ntype OnClickHandler = (e: React.MouseEvent<HTMLDivElement>) => void;\n\ntype MenuItemContextAction = {\n title: string;\n icon: string;\n destructive?: boolean;\n handler?: () => void;\n};\n\ntype OwnProps = {\n ref?: RefObject<HTMLDivElement>;\n buttonRef?: RefObject<HTMLDivElement>;\n icon?: string;\n className?: string;\n style?: string;\n children: any;\n disabled?: boolean;\n ripple?: boolean;\n narrow?: boolean;\n inactive?: boolean;\n focus?: boolean;\n destructive?: boolean;\n multiline?: boolean;\n isStatic?: boolean;\n contextActions?: MenuItemContextAction[];\n onClick?: OnClickHandler;\n};\n\nconst ListItem: FC<OwnProps> = (props) => {\n const {\n ref,\n buttonRef,\n icon,\n className,\n style,\n children,\n disabled,\n ripple,\n narrow,\n inactive,\n focus,\n destructive,\n multiline,\n isStatic,\n contextActions,\n onClick,\n } = props;\n\n // eslint-disable-next-line no-null/no-null\n let containerRef = useRef<HTMLDivElement>(null);\n if (ref) {\n containerRef = ref;\n }\n\n const {\n isContextMenuOpen, contextMenuPosition,\n handleBeforeContextMenu, handleContextMenu,\n handleContextMenuClose, handleContextMenuHide,\n } = useContextMenuHandlers(containerRef, !contextActions);\n\n const getTriggerElement = useCallback(() => containerRef.current, []);\n\n const getRootElement = useCallback(\n () => containerRef.current!.closest('.custom-scroll'),\n [],\n );\n\n const getMenuElement = useCallback(\n () => containerRef.current!.querySelector('.ListItem-context-menu .bubble'),\n [],\n );\n\n const { positionX, positionY, style: menuStyle } = useContextMenuPosition(\n contextMenuPosition,\n getTriggerElement,\n getRootElement,\n getMenuElement,\n );\n\n const handleClick = useCallback((e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {\n if (disabled || !onClick) {\n return;\n }\n onClick(e);\n }, [disabled, onClick]);\n\n const handleMouseDown = useCallback((e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {\n if (inactive || IS_TOUCH_ENV) {\n return;\n }\n if (contextActions && (e.button === 2 || !onClick)) {\n handleBeforeContextMenu(e);\n }\n if (e.button === 0) {\n if (!onClick) {\n handleContextMenu(e);\n } else {\n handleClick(e);\n }\n }\n }, [inactive, contextActions, onClick, handleBeforeContextMenu, handleContextMenu, handleClick]);\n\n const lang = useLang();\n\n const fullClassName = buildClassName(\n 'ListItem',\n className,\n !isStatic && 'no-selection',\n ripple && 'has-ripple',\n narrow && 'narrow',\n disabled && 'disabled',\n inactive && 'inactive',\n contextMenuPosition && 'has-menu-open',\n focus && 'focus',\n destructive && 'destructive',\n multiline && 'multiline',\n isStatic && 'is-static',\n );\n\n return (\n <div\n ref={containerRef}\n className={fullClassName}\n dir={lang.isRtl ? 'rtl' : undefined}\n // @ts-ignore\n style={style}\n >\n <div\n className=\"ListItem-button\"\n role=\"button\"\n ref={buttonRef}\n tabIndex={0}\n onClick={!inactive && IS_TOUCH_ENV ? handleClick : undefined}\n onMouseDown={handleMouseDown}\n onContextMenu={!inactive && contextActions ? handleContextMenu : undefined}\n >\n {icon && (\n <i className={`icon-${icon}`} />\n )}\n {multiline && (<div className=\"multiline-item\">{children}</div>)}\n {!multiline && children}\n {!disabled && !inactive && ripple && (\n <RippleEffect />\n )}\n </div>\n {contextActions && contextMenuPosition !== undefined && (\n <Menu\n isOpen={isContextMenuOpen}\n positionX={positionX}\n positionY={positionY}\n style={menuStyle}\n className=\"ListItem-context-menu\"\n autoClose\n onClose={handleContextMenuClose}\n onCloseAnimationEnd={handleContextMenuHide}\n >\n {contextActions.map((action) => (\n <MenuItem\n key={action.title}\n icon={action.icon}\n destructive={action.destructive}\n disabled={!action.handler}\n onClick={action.handler}\n >\n {action.title}\n </MenuItem>\n ))}\n </Menu>\n )}\n </div>\n );\n};\n\nexport default ListItem;\n","import { RefObject } from 'react';\nimport {\n useEffect, useRef, useCallback, useState,\n} from '../lib/teact/teact';\n\nimport { throttle, debounce } from '../util/schedulers';\nimport useHeavyAnimationCheck from './useHeavyAnimationCheck';\n\ntype TargetCallback = (entry: IntersectionObserverEntry) => void;\ntype RootCallback = (entries: IntersectionObserverEntry[]) => void;\ntype ObserveCleanup = NoneToVoidFunction;\nexport type ObserveFn = (target: HTMLElement, targetCallback?: TargetCallback) => ObserveCleanup;\n\ninterface IntersectionController {\n observer: IntersectionObserver;\n callbacks: Map<HTMLElement, TargetCallback>;\n}\n\ninterface Response {\n observe: ObserveFn;\n freeze: NoneToVoidFunction;\n unfreeze: NoneToVoidFunction;\n}\n\nexport function useIntersectionObserver({\n rootRef,\n throttleMs,\n debounceMs,\n shouldSkipFirst,\n margin,\n threshold,\n isDisabled,\n}: {\n rootRef: RefObject<HTMLDivElement>;\n throttleMs?: number;\n debounceMs?: number;\n shouldSkipFirst?: boolean;\n margin?: number;\n threshold?: number | number[];\n isDisabled?: boolean;\n}, rootCallback?: RootCallback): Response {\n const controllerRef = useRef<IntersectionController>();\n const rootCallbackRef = useRef<RootCallback>();\n const freezeFlagsRef = useRef(0);\n const onUnfreezeRef = useRef<NoneToVoidFunction>();\n\n rootCallbackRef.current = rootCallback;\n\n const freeze = useCallback(() => {\n freezeFlagsRef.current++;\n }, []);\n\n const unfreeze = useCallback(() => {\n if (!freezeFlagsRef.current) {\n return;\n }\n\n freezeFlagsRef.current--;\n\n if (!freezeFlagsRef.current && onUnfreezeRef.current) {\n onUnfreezeRef.current();\n onUnfreezeRef.current = undefined;\n }\n }, []);\n\n useHeavyAnimationCheck(freeze, unfreeze);\n\n useEffect(() => {\n if (isDisabled) {\n return undefined;\n }\n\n return () => {\n if (controllerRef.current) {\n controllerRef.current.observer.disconnect();\n controllerRef.current.callbacks.clear();\n controllerRef.current = undefined;\n }\n };\n }, [isDisabled]);\n\n function initController() {\n const callbacks = new Map();\n const entriesAccumulator = new Map<Element, IntersectionObserverEntry>();\n const observerCallbackSync = () => {\n const entries = Array.from(entriesAccumulator.values());\n\n entries.forEach((entry: IntersectionObserverEntry) => {\n const callback = callbacks.get(entry.target);\n if (callback) {\n callback!(entry, entries);\n }\n });\n\n if (rootCallbackRef.current) {\n rootCallbackRef.current(entries);\n }\n\n entriesAccumulator.clear();\n };\n const scheduler = throttleMs ? throttle : debounceMs ? debounce : undefined;\n const observerCallback = scheduler\n ? scheduler(observerCallbackSync, (throttleMs || debounceMs)!, !shouldSkipFirst)\n : observerCallbackSync;\n const observer = new IntersectionObserver(\n (entries) => {\n entries.forEach((entry) => {\n entriesAccumulator.set(entry.target, entry);\n });\n\n if (freezeFlagsRef.current) {\n onUnfreezeRef.current = () => {\n observerCallback();\n };\n } else {\n observerCallback();\n }\n },\n {\n root: rootRef.current,\n rootMargin: margin ? `${margin}px` : undefined,\n threshold,\n },\n );\n\n controllerRef.current = { observer, callbacks };\n }\n\n const observe = useCallback((target, targetCallback) => {\n if (!controllerRef.current) {\n initController();\n }\n\n const controller = controllerRef.current!;\n controller.observer.observe(target);\n\n if (targetCallback) {\n controller.callbacks.set(target, targetCallback);\n }\n\n return () => {\n if (targetCallback) {\n controller.callbacks.delete(target);\n }\n\n controller.observer.unobserve(target);\n };\n // Arguments should never change\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isDisabled]);\n\n return { observe, freeze, unfreeze };\n}\n\nexport function useOnIntersect(\n targetRef: RefObject<HTMLDivElement>, observe?: ObserveFn, callback?: TargetCallback,\n) {\n useEffect(() => {\n return observe ? observe(targetRef.current!, callback) : undefined;\n // Arguments should never change\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n}\n\nexport function useIsIntersecting(\n targetRef: RefObject<HTMLDivElement>, observe?: ObserveFn, callback?: TargetCallback,\n) {\n const [isIntersecting, setIsIntersecting] = useState(!observe);\n\n useOnIntersect(targetRef, observe, (entry) => {\n setIsIntersecting(entry.isIntersecting);\n\n if (callback) {\n callback(entry);\n }\n });\n\n return isIntersecting;\n}\n","import { useEffect } from '../lib/teact/teact';\n\nimport { ApiMediaFormat } from '../api/types';\n\nimport * as mediaLoader from '../util/mediaLoader';\nimport useForceUpdate from './useForceUpdate';\n\nexport default <T extends ApiMediaFormat = ApiMediaFormat.BlobUrl>(\n mediaHash: string | false | undefined,\n noLoad = false,\n // @ts-ignore (workaround for \"could be instantiated with a different subtype\" issue)\n mediaFormat: T = ApiMediaFormat.BlobUrl,\n cacheBuster?: number,\n delay?: number | false,\n) => {\n const mediaData = mediaHash ? mediaLoader.getFromMemory<T>(mediaHash) : undefined;\n const forceUpdate = useForceUpdate();\n\n useEffect(() => {\n if (!noLoad && mediaHash && !mediaData) {\n const startedAt = Date.now();\n\n mediaLoader.fetch(mediaHash, mediaFormat).then(() => {\n const spentTime = Date.now() - startedAt;\n if (!delay || spentTime >= delay) {\n forceUpdate();\n } else {\n setTimeout(forceUpdate, delay - spentTime);\n }\n });\n }\n }, [noLoad, mediaHash, mediaData, mediaFormat, cacheBuster, forceUpdate, delay]);\n\n return mediaData;\n};\n","import { MouseEvent as ReactMouseEvent } from 'react';\nimport React, {\n FC, useEffect, useCallback, memo,\n} from '../../lib/teact/teact';\nimport { withGlobal } from '../../lib/teact/teactn';\n\nimport { ApiUser, ApiTypingStatus } from '../../api/types';\nimport { GlobalActions, GlobalState } from '../../global/types';\nimport { MediaViewerOrigin } from '../../types';\n\nimport { selectChatMessages, selectUser } from '../../modules/selectors';\nimport { getUserFullName, getUserStatus, isUserOnline } from '../../modules/helpers';\nimport renderText from './helpers/renderText';\nimport { pick } from '../../util/iteratees';\nimport useLang from '../../hooks/useLang';\n\nimport Avatar from './Avatar';\nimport VerifiedIcon from './VerifiedIcon';\nimport TypingStatus from './TypingStatus';\n\ntype OwnProps = {\n userId: number;\n typingStatus?: ApiTypingStatus;\n avatarSize?: 'tiny' | 'small' | 'medium' | 'large' | 'jumbo';\n forceShowSelf?: boolean;\n status?: string;\n withMediaViewer?: boolean;\n withUsername?: boolean;\n withFullInfo?: boolean;\n withUpdatingStatus?: boolean;\n noStatusOrTyping?: boolean;\n noRtl?: boolean;\n};\n\ntype StateProps = {\n user?: ApiUser;\n isSavedMessages?: boolean;\n areMessagesLoaded: boolean;\n serverTimeOffset: number;\n} & Pick<GlobalState, 'lastSyncTime'>;\n\ntype DispatchProps = Pick<GlobalActions, 'loadFullUser' | 'openMediaViewer'>;\n\nconst PrivateChatInfo: FC<OwnProps & StateProps & DispatchProps> = ({\n typingStatus,\n avatarSize = 'medium',\n status,\n withMediaViewer,\n withUsername,\n withFullInfo,\n withUpdatingStatus,\n noStatusOrTyping,\n noRtl,\n user,\n isSavedMessages,\n areMessagesLoaded,\n lastSyncTime,\n loadFullUser,\n openMediaViewer,\n serverTimeOffset,\n}) => {\n const { id: userId } = user || {};\n const fullName = getUserFullName(user);\n\n useEffect(() => {\n if (withFullInfo && lastSyncTime && userId) {\n loadFullUser({ userId });\n }\n }, [userId, loadFullUser, lastSyncTime, withFullInfo]);\n\n const handleAvatarViewerOpen = useCallback((e: ReactMouseEvent<HTMLDivElement, MouseEvent>, hasPhoto: boolean) => {\n if (user && hasPhoto) {\n e.stopPropagation();\n openMediaViewer({\n avatarOwnerId: user.id,\n origin: avatarSize === 'jumbo' ? MediaViewerOrigin.ProfileAvatar : MediaViewerOrigin.MiddleHeaderAvatar,\n });\n }\n }, [user, avatarSize, openMediaViewer]);\n\n const lang = useLang();\n\n if (!user) {\n return undefined;\n }\n\n function renderStatusOrTyping() {\n if (status) {\n return (\n <span className=\"status\" dir=\"auto\">{status}</span>\n );\n }\n\n if (withUpdatingStatus && !areMessagesLoaded) {\n return (\n <span className=\"status\" dir=\"auto\">{lang('Updating')}</span>\n );\n }\n\n if (!user) {\n return undefined;\n }\n\n if (typingStatus) {\n return <TypingStatus typingStatus={typingStatus} />;\n }\n\n return (\n <div className={`status ${isUserOnline(user) ? 'online' : ''}`}>\n {withUsername && user.username && <span className=\"handle\">{user.username}</span>}\n <span className=\"user-status\" dir=\"auto\">{getUserStatus(lang, user, serverTimeOffset)}</span>\n </div>\n );\n }\n\n return (\n <div className=\"ChatInfo\" dir={!noRtl && lang.isRtl ? 'rtl' : undefined}>\n <Avatar\n key={user.id}\n size={avatarSize}\n user={user}\n isSavedMessages={isSavedMessages}\n onClick={withMediaViewer ? handleAvatarViewerOpen : undefined}\n />\n <div className=\"info\">\n {isSavedMessages ? (\n <div className=\"title\">\n <h3>{lang('SavedMessages')}</h3>\n </div>\n ) : (\n <div className=\"title\">\n <h3 dir=\"auto\">{fullName && renderText(fullName)}</h3>\n {user && user.isVerified && <VerifiedIcon />}\n </div>\n )}\n {(status || (!isSavedMessages && !noStatusOrTyping)) && renderStatusOrTyping()}\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 isSavedMessages = !forceShowSelf && user && user.isSelf;\n const areMessagesLoaded = Boolean(selectChatMessages(global, userId));\n\n return {\n lastSyncTime, user, isSavedMessages, areMessagesLoaded, serverTimeOffset,\n };\n },\n (setGlobal, actions): DispatchProps => pick(actions, ['loadFullUser', 'openMediaViewer']),\n)(PrivateChatInfo));\n","import React, { FC, useEffect, useRef } from '../../lib/teact/teact';\n\nimport captureKeyboardListeners from '../../util/captureKeyboardListeners';\nimport trapFocus from '../../util/trapFocus';\nimport buildClassName from '../../util/buildClassName';\nimport { dispatchHeavyAnimationEvent } from '../../hooks/useHeavyAnimationCheck';\nimport useShowTransition from '../../hooks/useShowTransition';\nimport useEffectWithPrevDeps from '../../hooks/useEffectWithPrevDeps';\nimport useLang from '../../hooks/useLang';\n\nimport Button from './Button';\nimport Portal from './Portal';\n\nimport './Modal.scss';\n\nconst ANIMATION_DURATION = 200;\n\ntype OwnProps = {\n title?: string;\n className?: string;\n isOpen?: boolean;\n header?: FC;\n hasCloseButton?: boolean;\n noBackdrop?: boolean;\n children: any;\n onClose: () => void;\n onCloseAnimationEnd?: () => void;\n onEnter?: () => void;\n};\n\nconst Modal: FC<OwnProps> = (props) => {\n const {\n title,\n className,\n isOpen,\n header,\n hasCloseButton,\n noBackdrop,\n children,\n onClose,\n onCloseAnimationEnd,\n onEnter,\n } = props;\n const { shouldRender, transitionClassNames } = useShowTransition(isOpen, onCloseAnimationEnd);\n // eslint-disable-next-line no-null/no-null\n const modalRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => (isOpen\n ? captureKeyboardListeners({ onEsc: onClose, onEnter })\n : undefined), [isOpen, onClose, onEnter]);\n useEffect(() => (isOpen && modalRef.current ? trapFocus(modalRef.current) : undefined), [isOpen]);\n\n useEffectWithPrevDeps(([prevIsOpen]) => {\n document.body.classList.toggle('has-open-dialog', isOpen);\n\n if (isOpen || (!isOpen && prevIsOpen !== undefined)) {\n dispatchHeavyAnimationEvent(ANIMATION_DURATION);\n }\n\n return () => {\n document.body.classList.remove('has-open-dialog');\n };\n }, [isOpen]);\n\n const lang = useLang();\n\n if (!shouldRender) {\n return undefined;\n }\n\n function renderHeader() {\n if (header) {\n return header;\n }\n\n if (!title) {\n return undefined;\n }\n\n return (\n <div className=\"modal-header\">\n {hasCloseButton && (\n <Button\n round\n color=\"translucent\"\n size=\"smaller\"\n ariaLabel={lang('Close')}\n onClick={onClose}\n >\n <i className=\"icon-close\" />\n </Button>\n )}\n <div className=\"modal-title\">{title}</div>\n </div>\n );\n }\n\n const fullClassName = buildClassName(\n 'Modal',\n className,\n transitionClassNames,\n noBackdrop && 'transparent-backdrop',\n );\n\n return (\n <Portal>\n <div\n ref={modalRef}\n className={fullClassName}\n tabIndex={-1}\n role=\"dialog\"\n >\n <div className=\"modal-container\">\n <div className=\"modal-backdrop\" onClick={onClose} />\n <div className=\"modal-dialog\">\n {renderHeader()}\n <div className=\"modal-content custom-scroll\">\n {children}\n </div>\n </div>\n </div>\n </div>\n </Portal>\n );\n};\n\nexport default Modal;\n","export default function trapFocus(element: HTMLElement) {\n function handleKeyDown(e: KeyboardEvent) {\n if (e.key !== 'Tab') {\n return;\n }\n\n e.preventDefault();\n e.stopPropagation();\n\n const focusableElements = Array.from(\n element.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])'),\n ) as HTMLElement[];\n if (!focusableElements.length) {\n return;\n }\n\n const currentFocusedIndex = focusableElements.findIndex((em) => em.isSameNode(document.activeElement));\n let newFocusedIndex = 0;\n if (currentFocusedIndex >= 0) {\n if (e.shiftKey) {\n newFocusedIndex = currentFocusedIndex > 0\n ? currentFocusedIndex - 1\n : focusableElements.length - 1;\n } else {\n newFocusedIndex = currentFocusedIndex < focusableElements.length - 1\n ? currentFocusedIndex + 1\n : 0;\n }\n }\n\n focusableElements[newFocusedIndex].focus();\n }\n\n document.addEventListener('keydown', handleKeyDown, false);\n\n return () => {\n document.removeEventListener('keydown', handleKeyDown, false);\n };\n}\n","import { RefObject } from 'react';\nimport React, {\n FC, useLayoutEffect, useRef,\n} from '../../lib/teact/teact';\nimport { getGlobal } from '../../lib/teact/teactn';\n\nimport { ANIMATION_END_DELAY } from '../../config';\nimport { IS_SINGLE_COLUMN_LAYOUT } from '../../util/environment';\nimport useForceUpdate from '../../hooks/useForceUpdate';\nimport usePrevious from '../../hooks/usePrevious';\nimport buildClassName from '../../util/buildClassName';\nimport { dispatchHeavyAnimationEvent } from '../../hooks/useHeavyAnimationCheck';\n\nimport './Transition.scss';\n\ntype ChildrenFn = (isActive: boolean, isFrom: boolean) => any;\ntype OwnProps = {\n ref?: RefObject<HTMLDivElement>;\n activeKey: number;\n name: (\n 'none' | 'slide' | 'slide-reversed' | 'mv-slide' | 'slide-fade' | 'zoom-fade' | 'scroll-slide' | 'slide-layers'\n | 'fade' | 'push-slide' | 'reveal'\n );\n direction?: 'auto' | 'inverse' | 1 | -1;\n renderCount?: number;\n shouldRestoreHeight?: boolean;\n shouldCleanup?: boolean;\n cleanupExceptionKey?: number;\n id?: string;\n className?: string;\n onStart?: () => void;\n onStop?: () => void;\n children: ChildrenFn;\n};\n\nconst ANIMATION_DURATION = {\n slide: 450,\n 'slide-reversed': 450,\n 'mv-slide': 400,\n 'slide-fade': 400,\n 'zoom-fade': 150,\n 'scroll-slide': 500,\n fade: 150,\n 'slide-layers': IS_SINGLE_COLUMN_LAYOUT ? 450 : 300,\n 'push-slide': 300,\n reveal: 350,\n};\n\nconst CLEANED_UP = Symbol('CLEANED_UP');\n\nconst Transition: FC<OwnProps> = ({\n ref,\n activeKey,\n name,\n direction = 'auto',\n renderCount,\n shouldRestoreHeight,\n shouldCleanup,\n cleanupExceptionKey,\n id,\n className,\n onStart,\n onStop,\n children,\n}) => {\n // No need for a container to update on change\n const { animationLevel } = getGlobal().settings.byKey;\n\n // eslint-disable-next-line no-null/no-null\n let containerRef = useRef<HTMLDivElement>(null);\n if (ref) {\n containerRef = ref;\n }\n\n const rendersRef = useRef<Record<number, ChildrenFn | typeof CLEANED_UP>>({});\n const prevActiveKey = usePrevious<any>(activeKey);\n const activateTimeoutRef = useRef<number>();\n const forceUpdate = useForceUpdate();\n\n const activeKeyChanged = prevActiveKey !== undefined && activeKey !== prevActiveKey;\n\n if (!renderCount && activeKeyChanged) {\n rendersRef.current = { [prevActiveKey]: rendersRef.current[prevActiveKey] };\n }\n\n rendersRef.current[activeKey] = children;\n\n useLayoutEffect(() => {\n function cleanup() {\n if (!shouldCleanup || (cleanupExceptionKey !== undefined && cleanupExceptionKey === prevActiveKey)) {\n return;\n }\n\n rendersRef.current = { [prevActiveKey]: CLEANED_UP };\n forceUpdate();\n }\n\n const container = containerRef.current!;\n\n const childElements = container.children;\n if (childElements.length === 1 && !activeKeyChanged) {\n childElements[0].classList.add('active');\n\n return;\n }\n\n const childNodes = Array.from(container.childNodes);\n\n if (!activeKeyChanged || !childNodes.length) {\n return;\n }\n\n if (activateTimeoutRef.current) {\n clearTimeout(activateTimeoutRef.current);\n activateTimeoutRef.current = undefined;\n }\n\n const isBackwards = (\n direction === -1\n || (direction === 'auto' && prevActiveKey > activeKey)\n || (direction === 'inverse' && prevActiveKey < activeKey)\n );\n\n container.classList.remove('animating');\n container.classList.toggle('backwards', isBackwards);\n\n const keys = Object.keys(rendersRef.current).map(Number);\n const prevActiveIndex = renderCount ? prevActiveKey : keys.indexOf(prevActiveKey);\n const activeIndex = renderCount ? activeKey : keys.indexOf(activeKey);\n\n if (name === 'none' || animationLevel === 0) {\n childNodes.forEach((node, i) => {\n if (node instanceof HTMLElement) {\n node.classList.remove('from', 'through', 'to');\n node.classList.toggle('active', i === activeIndex);\n }\n });\n\n cleanup();\n\n return;\n }\n\n childNodes.forEach((node, i) => {\n if (node instanceof HTMLElement) {\n node.classList.remove('active');\n node.classList.toggle('from', i === prevActiveIndex);\n node.classList.toggle('through', (\n (i > prevActiveIndex && i < activeIndex) || (i < prevActiveIndex && i > activeIndex)\n ));\n node.classList.toggle('to', i === activeIndex);\n }\n });\n\n if (name === 'scroll-slide') {\n const width = container.offsetWidth;\n container.scrollBy({\n left: activeIndex > prevActiveIndex ? width : -width,\n behavior: 'smooth',\n });\n }\n\n if (animationLevel > 0) {\n dispatchHeavyAnimationEvent(ANIMATION_DURATION[name] + ANIMATION_END_DELAY);\n }\n\n requestAnimationFrame(() => {\n container.classList.add('animating');\n\n activateTimeoutRef.current = window.setTimeout(() => {\n requestAnimationFrame(() => {\n container.classList.remove('animating', 'backwards');\n\n childNodes.forEach((node, i) => {\n if (node instanceof HTMLElement) {\n node.classList.remove('from', 'through', 'to');\n node.classList.toggle('active', i === activeIndex);\n }\n });\n\n if (name === 'scroll-slide') {\n container.scrollLeft = activeKey * container.offsetWidth;\n }\n\n if (shouldRestoreHeight) {\n const activeElement = container.querySelector<HTMLDivElement>('.active');\n\n if (activeElement) {\n activeElement.style.height = 'auto';\n container.style.height = `${activeElement.clientHeight}px`;\n }\n }\n\n cleanup();\n\n if (onStop) {\n onStop();\n }\n });\n }, ANIMATION_DURATION[name] + ANIMATION_END_DELAY);\n\n if (onStart) {\n onStart();\n }\n });\n }, [\n activeKey,\n prevActiveKey,\n activeKeyChanged,\n direction,\n name,\n onStart,\n onStop,\n renderCount,\n shouldRestoreHeight,\n shouldCleanup,\n cleanupExceptionKey,\n animationLevel,\n forceUpdate,\n ]);\n\n useLayoutEffect(() => {\n if (shouldRestoreHeight) {\n const container = containerRef.current!;\n const activeElement = container.querySelector<HTMLDivElement>('.active')\n || container.querySelector<HTMLDivElement>('.from');\n\n if (activeElement) {\n activeElement.style.height = 'auto';\n container.style.height = `${activeElement.clientHeight}px`;\n container.style.flexBasis = `${activeElement.clientHeight}px`;\n }\n }\n }, [shouldRestoreHeight, children]);\n\n const renders = rendersRef.current;\n const collection = Object.keys(renderCount ? new Array(renderCount).fill(undefined) : renders).map(Number);\n const contents = collection.map((key) => {\n const render = renders[key];\n\n return (\n typeof render === 'function' ? <div key={key}>{render(key === activeKey, key === prevActiveKey)}</div> : undefined\n );\n });\n\n const fullClassName = buildClassName(\n 'Transition',\n className,\n animationLevel === 0 && name === 'scroll-slide' ? 'slide' : name,\n );\n\n return (\n <div ref={containerRef} id={id} className={fullClassName}>\n {contents}\n </div>\n );\n};\n\nexport default Transition;\n","import { MouseEvent as ReactMouseEvent } from 'react';\nimport React, { FC, useCallback, memo } from '../../lib/teact/teact';\n\nimport { ApiUser, ApiChat, ApiMediaFormat } from '../../api/types';\n\nimport { IS_TEST } from '../../config';\nimport {\n getChatAvatarHash, getChatTitle, isChatPrivate,\n getUserFullName, isUserOnline, isDeletedUser, getUserColorKey,\n} from '../../modules/helpers';\nimport { getFirstLetters } from '../../util/textFormat';\nimport buildClassName from '../../util/buildClassName';\nimport renderText from './helpers/renderText';\nimport useMedia from '../../hooks/useMedia';\nimport useTransitionForMedia from '../../hooks/useTransitionForMedia';\nimport useLang from '../../hooks/useLang';\n\nimport './Avatar.scss';\n\ntype OwnProps = {\n className?: string;\n size?: 'micro' | 'tiny' | 'small' | 'medium' | 'large' | 'jumbo';\n withOnlineStatus?: boolean;\n chat?: ApiChat;\n user?: ApiUser;\n text?: string;\n isSavedMessages?: boolean;\n lastSyncTime?: number;\n onClick?: (e: ReactMouseEvent<HTMLDivElement, MouseEvent>, hasPhoto: boolean) => void;\n};\n\nconst Avatar: FC<OwnProps> = ({\n className,\n size = 'large',\n chat,\n user,\n text,\n withOnlineStatus,\n isSavedMessages,\n lastSyncTime,\n onClick,\n}) => {\n const isDeleted = user && isDeletedUser(user);\n let imageHash: string | undefined;\n\n if (!isSavedMessages && !isDeleted) {\n if (user) {\n imageHash = getChatAvatarHash(user);\n } else if (chat) {\n imageHash = getChatAvatarHash(chat);\n }\n }\n\n const dataUri = useMedia(imageHash, false, ApiMediaFormat.DataUri, lastSyncTime);\n const { shouldRenderFullMedia, transitionClassNames } = useTransitionForMedia(dataUri, 'slow');\n\n const lang = useLang();\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 (shouldRenderFullMedia) {\n content = <img src={dataUri} className={`${transitionClassNames} avatar-media`} alt=\"\" decoding=\"async\" />;\n } else if (user) {\n const userFullName = getUserFullName(user);\n content = userFullName ? getFirstLetters(userFullName, 2) : undefined;\n } else if (chat) {\n const title = getChatTitle(lang, chat);\n content = title && getFirstLetters(title, isChatPrivate(chat.id) ? 2 : 1);\n } else if (text) {\n content = getFirstLetters(text, 2);\n }\n\n const isOnline = !isSavedMessages && user && isUserOnline(user);\n const fullClassName = buildClassName(\n `Avatar size-${size}`,\n className,\n `color-bg-${getUserColorKey(user || chat)}`,\n isSavedMessages && 'saved-messages',\n isDeleted && 'deleted-account',\n withOnlineStatus && isOnline && 'online',\n onClick && 'interactive',\n (!isSavedMessages && !shouldRenderFullMedia) && 'no-photo',\n );\n\n const handleClick = useCallback((e: ReactMouseEvent<HTMLDivElement, MouseEvent>) => {\n if (onClick) {\n onClick(e, isSavedMessages || shouldRenderFullMedia);\n }\n }, [onClick, isSavedMessages, shouldRenderFullMedia]);\n\n const senderId = (user || chat) && (user || chat)!.id;\n\n return (\n <div className={fullClassName} onClick={handleClick} data-test-sender-id={IS_TEST ? senderId : undefined}>\n {typeof content === 'string' ? renderText(content, [size === 'jumbo' ? 'hq_emoji' : 'emoji']) : content}\n </div>\n );\n};\n\nexport default memo(Avatar);\n","import { RefObject, UIEvent } from 'react';\nimport { LoadMoreDirection } from '../../types';\n\nimport React, {\n FC, useCallback, useEffect, useLayoutEffect, useMemo, useRef,\n} from '../../lib/teact/teact';\n\nimport { debounce } from '../../util/schedulers';\nimport resetScroll from '../../util/resetScroll';\n\ntype OwnProps = {\n ref?: RefObject<HTMLDivElement>;\n className?: string;\n onLoadMore?: ({ direction }: { direction: LoadMoreDirection; noScroll?: boolean }) => void;\n onScroll?: (e: UIEvent<HTMLDivElement>) => void;\n onKeyDown?: (e: React.KeyboardEvent<any>) => void;\n items?: any[];\n itemSelector?: string;\n preloadBackwards?: number;\n sensitiveArea?: number;\n noScrollRestore?: boolean;\n noScrollRestoreOnTop?: boolean;\n noFastList?: boolean;\n cacheBuster?: any;\n children: any;\n};\n\nconst DEFAULT_LIST_SELECTOR = '.ListItem';\nconst DEFAULT_PRELOAD_BACKWARDS = 20;\nconst DEFAULT_SENSITIVE_AREA = 800;\n\nconst InfiniteScroll: FC<OwnProps> = ({\n ref,\n className,\n onLoadMore,\n onScroll,\n onKeyDown,\n items,\n itemSelector = DEFAULT_LIST_SELECTOR,\n preloadBackwards = DEFAULT_PRELOAD_BACKWARDS,\n sensitiveArea = DEFAULT_SENSITIVE_AREA,\n // Used to turn off restoring scroll position (e.g. for frequently re-ordered chat or user lists)\n noScrollRestore = false,\n noScrollRestoreOnTop = false,\n noFastList,\n // Used to re-query `listItemElements` if rendering is delayed by transition\n cacheBuster,\n children,\n}: OwnProps) => {\n // eslint-disable-next-line no-null/no-null\n let containerRef = useRef<HTMLDivElement>(null);\n if (ref) {\n containerRef = ref;\n }\n\n const stateRef = useRef<{\n listItemElements: NodeListOf<HTMLDivElement>;\n isScrollTopJustUpdated: boolean;\n currentAnchor: HTMLDivElement | undefined;\n currentAnchorTop: number;\n }>({} as any);\n\n const [loadMoreBackwards, loadMoreForwards] = useMemo(() => {\n if (!onLoadMore) {\n return [];\n }\n\n return [\n debounce((noScroll = false) => {\n onLoadMore({ direction: LoadMoreDirection.Backwards, noScroll });\n }, 1000, true, false),\n debounce(() => {\n onLoadMore({ direction: LoadMoreDirection.Forwards });\n }, 1000, true, false),\n ];\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [onLoadMore, items]);\n\n // Initial preload\n useEffect(() => {\n if (!loadMoreBackwards) {\n return;\n }\n\n if (preloadBackwards > 0 && (!items || items.length < preloadBackwards)) {\n loadMoreBackwards(true);\n return;\n }\n\n const { scrollHeight, clientHeight } = containerRef.current!;\n if (clientHeight && scrollHeight <= clientHeight) {\n loadMoreBackwards();\n }\n }, [items, loadMoreBackwards, preloadBackwards]);\n\n // Restore `scrollTop` after adding items\n useLayoutEffect(() => {\n const container = containerRef.current!;\n const state = stateRef.current;\n\n state.listItemElements = container.querySelectorAll<HTMLDivElement>(itemSelector);\n\n let newScrollTop;\n\n if (state.currentAnchor && Array.from(state.listItemElements).includes(state.currentAnchor)) {\n const { scrollTop } = container;\n const newAnchorTop = state.currentAnchor.getBoundingClientRect().top;\n newScrollTop = scrollTop + (newAnchorTop - state.currentAnchorTop);\n } else {\n const nextAnchor = state.listItemElements[0];\n if (nextAnchor) {\n state.currentAnchor = nextAnchor;\n state.currentAnchorTop = nextAnchor.getBoundingClientRect().top;\n }\n }\n\n if (noScrollRestore) {\n return;\n }\n\n if (noScrollRestoreOnTop && container.scrollTop === 0) {\n return;\n }\n\n resetScroll(container, newScrollTop);\n\n state.isScrollTopJustUpdated = true;\n }, [items, itemSelector, noScrollRestore, noScrollRestoreOnTop, cacheBuster]);\n\n const handleScroll = useCallback((e: UIEvent<HTMLDivElement>) => {\n if (loadMoreForwards && loadMoreBackwards) {\n const {\n listItemElements, isScrollTopJustUpdated, currentAnchor, currentAnchorTop,\n } = stateRef.current;\n\n if (isScrollTopJustUpdated) {\n stateRef.current.isScrollTopJustUpdated = false;\n return;\n }\n\n const listLength = listItemElements.length;\n const container = containerRef.current!;\n const { scrollTop, scrollHeight, offsetHeight } = container;\n const top = listLength ? listItemElements[0].offsetTop : 0;\n const isNearTop = scrollTop <= top + sensitiveArea;\n const bottom = listLength\n ? listItemElements[listLength - 1].offsetTop + listItemElements[listLength - 1].offsetHeight\n : scrollHeight;\n const isNearBottom = bottom - (scrollTop + offsetHeight) <= sensitiveArea;\n let isUpdated = false;\n\n if (isNearTop) {\n const nextAnchor = listItemElements[0];\n if (nextAnchor) {\n const nextAnchorTop = nextAnchor.getBoundingClientRect().top;\n const newAnchorTop = currentAnchor && currentAnchor.offsetParent && currentAnchor !== nextAnchor\n ? currentAnchor.getBoundingClientRect().top\n : nextAnchorTop;\n const isMovingUp = (\n currentAnchor && currentAnchorTop !== undefined && newAnchorTop > currentAnchorTop\n );\n\n if (isMovingUp) {\n stateRef.current.currentAnchor = nextAnchor;\n stateRef.current.currentAnchorTop = nextAnchorTop;\n isUpdated = true;\n resetScroll(container);\n loadMoreForwards();\n }\n }\n }\n\n if (isNearBottom) {\n const nextAnchor = listItemElements[listLength - 1];\n if (nextAnchor) {\n const nextAnchorTop = nextAnchor.getBoundingClientRect().top;\n const newAnchorTop = currentAnchor && currentAnchor.offsetParent && currentAnchor !== nextAnchor\n ? currentAnchor.getBoundingClientRect().top\n : nextAnchorTop;\n const isMovingDown = (\n currentAnchor && currentAnchorTop !== undefined && newAnchorTop < currentAnchorTop\n );\n\n if (isMovingDown) {\n stateRef.current.currentAnchor = nextAnchor;\n stateRef.current.currentAnchorTop = nextAnchorTop;\n isUpdated = true;\n resetScroll(container);\n loadMoreBackwards();\n }\n }\n }\n\n if (!isUpdated) {\n if (currentAnchor && currentAnchor.offsetParent) {\n stateRef.current.currentAnchorTop = currentAnchor.getBoundingClientRect().top;\n } else {\n const nextAnchor = listItemElements[0];\n\n if (nextAnchor) {\n stateRef.current.currentAnchor = nextAnchor;\n stateRef.current.currentAnchorTop = nextAnchor.getBoundingClientRect().top;\n }\n }\n }\n }\n\n if (onScroll) {\n onScroll(e);\n }\n }, [loadMoreBackwards, loadMoreForwards, onScroll, sensitiveArea]);\n\n return (\n <div\n ref={containerRef}\n className={className}\n onScroll={handleScroll}\n teactFastList={!noFastList}\n onKeyDown={onKeyDown}\n >\n {children}\n </div>\n );\n};\n\nexport default InfiniteScroll;\n","import { useEffect, useRef, useState } from '../lib/teact/teact';\n\nimport useShowTransition from './useShowTransition';\n\nconst SPEED = {\n fast: 200,\n slow: 350,\n};\n\nexport default (mediaData?: any, speed: keyof typeof SPEED = 'fast', noAnimate = false) => {\n const isMediaLoaded = Boolean(mediaData);\n const willAnimate = !useRef(isMediaLoaded).current && !noAnimate;\n const [shouldRenderThumb, setShouldRenderThumb] = useState(!isMediaLoaded);\n\n const {\n shouldRender: shouldRenderFullMedia,\n transitionClassNames,\n } = useShowTransition(isMediaLoaded, undefined, !willAnimate, speed);\n\n useEffect(() => {\n if (shouldRenderFullMedia) {\n if (willAnimate) {\n setTimeout(() => {\n setShouldRenderThumb(false);\n }, SPEED[speed]);\n } else {\n setShouldRenderThumb(false);\n }\n }\n }, [willAnimate, shouldRenderFullMedia, speed]);\n\n return {\n shouldRenderThumb,\n shouldRenderFullMedia,\n transitionClassNames,\n };\n};\n","import { ApiPhoto, ApiVideo, ApiSticker } from '../../../api/types';\nimport { getPhotoInlineDimensions, getVideoDimensions, IDimensions } from '../../../modules/helpers';\nimport windowSize from '../../../util/windowSize';\nimport { IS_SINGLE_COLUMN_LAYOUT } from '../../../util/environment';\nimport { STICKER_SIZE_INLINE_DESKTOP_FACTOR, STICKER_SIZE_INLINE_MOBILE_FACTOR } from '../../../config';\n\nexport const MEDIA_VIEWER_MEDIA_QUERY = '(max-height: 640px)';\nexport const REM = parseInt(getComputedStyle(document.documentElement).fontSize, 10);\nexport const ROUND_VIDEO_DIMENSIONS = 200;\nexport const AVATAR_FULL_DIMENSIONS = { width: 640, height: 640 };\n\nconst DEFAULT_MEDIA_DIMENSIONS: IDimensions = { width: 100, height: 100 };\nexport const LIKE_STICKER_ID = '1258816259753933';\nconst MOBILE_SCREEN_MAX_MESSAGE_SCREEN_WIDTH = 0.69;\n\nlet cachedMaxWidth: number | undefined;\n\nfunction getMaxMessageWidthRem(fromOwnMessage: boolean) {\n const regularMaxWidth = fromOwnMessage ? 30 : 29;\n if (!IS_SINGLE_COLUMN_LAYOUT) {\n return regularMaxWidth;\n }\n\n // @optimization Limitation: changing device screen width not supported\n if (!cachedMaxWidth) {\n cachedMaxWidth = Math.min(\n regularMaxWidth,\n Math.floor(window.innerWidth * MOBILE_SCREEN_MAX_MESSAGE_SCREEN_WIDTH) / REM,\n );\n }\n\n return cachedMaxWidth;\n}\n\nfunction getAvailableWidth(\n fromOwnMessage: boolean,\n isForwarded?: boolean,\n isWebPagePhoto?: boolean,\n) {\n const extraPaddingRem = isForwarded || isWebPagePhoto ? 1.625 : 0;\n const availableWidthRem = getMaxMessageWidthRem(fromOwnMessage) - extraPaddingRem;\n\n return availableWidthRem * REM;\n}\n\nfunction getAvailableHeight(isGif?: boolean, aspectRatio?: number) {\n if (\n isGif && aspectRatio\n && aspectRatio >= 0.75 && aspectRatio <= 1.25\n ) {\n return 20 * REM;\n }\n\n return 27 * REM;\n}\n\nfunction calculateDimensionsForMessageMedia({\n width,\n height,\n fromOwnMessage,\n isForwarded,\n isWebPagePhoto,\n isGif,\n}: {\n width: number;\n height: number;\n fromOwnMessage: boolean;\n isForwarded?: boolean;\n isWebPagePhoto?: boolean;\n isGif?: boolean;\n}): IDimensions {\n const aspectRatio = height / width;\n const availableWidth = getAvailableWidth(fromOwnMessage, isForwarded, isWebPagePhoto);\n const availableHeight = getAvailableHeight(isGif, aspectRatio);\n\n return calculateDimensions(availableWidth, availableHeight, width, height);\n}\n\nexport function getMediaViewerAvailableDimensions(withFooter: boolean, isVideo: boolean): IDimensions {\n const mql = window.matchMedia(MEDIA_VIEWER_MEDIA_QUERY);\n const { width: windowWidth, height: windowHeight } = windowSize.get();\n let occupiedHeightRem = isVideo && mql.matches ? 10 : 8.25;\n if (withFooter) {\n occupiedHeightRem = mql.matches ? 10 : 15;\n }\n\n return {\n width: windowWidth,\n height: windowHeight - occupiedHeightRem * REM,\n };\n}\n\nexport function calculateInlineImageDimensions(\n photo: ApiPhoto,\n fromOwnMessage: boolean,\n isForwarded?: boolean,\n isWebPagePhoto?: boolean,\n) {\n const { width, height } = getPhotoInlineDimensions(photo) || DEFAULT_MEDIA_DIMENSIONS;\n\n return calculateDimensionsForMessageMedia({\n width,\n height,\n fromOwnMessage,\n isForwarded,\n isWebPagePhoto,\n });\n}\n\nexport function calculateVideoDimensions(\n video: ApiVideo,\n fromOwnMessage: boolean,\n isForwarded?: boolean,\n) {\n const { width, height } = getVideoDimensions(video) || DEFAULT_MEDIA_DIMENSIONS;\n\n return calculateDimensionsForMessageMedia({\n width,\n height,\n fromOwnMessage,\n isForwarded,\n isGif: video.isGif,\n });\n}\n\nexport function getPictogramDimensions(): IDimensions {\n return {\n width: 2 * REM,\n height: 2 * REM,\n };\n}\n\nexport function getDocumentThumbnailDimensions(smaller?: boolean): IDimensions {\n if (smaller) {\n return {\n width: 3 * REM,\n height: 3 * REM,\n };\n }\n\n return {\n width: 3.375 * REM,\n height: 3.375 * REM,\n };\n}\n\nexport function getStickerDimensions(sticker: ApiSticker): IDimensions {\n const { width } = sticker;\n let { height } = sticker;\n\n // For some reason this sticker has some weird `height` value\n if (sticker.id === LIKE_STICKER_ID) {\n height = width;\n }\n\n const aspectRatio = (height && width) && height / width;\n const baseWidth = REM * (\n IS_SINGLE_COLUMN_LAYOUT\n ? STICKER_SIZE_INLINE_MOBILE_FACTOR\n : STICKER_SIZE_INLINE_DESKTOP_FACTOR\n );\n const calculatedHeight = aspectRatio ? baseWidth * aspectRatio : baseWidth;\n\n if (aspectRatio && calculatedHeight > baseWidth) {\n return {\n width: Math.round(baseWidth / aspectRatio),\n height: baseWidth,\n };\n }\n\n return {\n width: baseWidth,\n height: calculatedHeight,\n };\n}\n\nexport function calculateMediaViewerDimensions(\n { width, height }: IDimensions, withFooter: boolean, isVideo: boolean = false,\n): IDimensions {\n const { width: availableWidth, height: availableHeight } = getMediaViewerAvailableDimensions(withFooter, isVideo);\n\n return calculateDimensions(availableWidth, availableHeight, width, height);\n}\n\nexport function calculateDimensions(\n availableWidth: number,\n availableHeight: number,\n mediaWidth: number,\n mediaHeight: number,\n): IDimensions {\n const aspectRatio = mediaHeight / mediaWidth;\n const calculatedWidth = Math.min(mediaWidth, availableWidth);\n const calculatedHeight = Math.round(calculatedWidth * aspectRatio);\n\n if (calculatedHeight > availableHeight) {\n return {\n width: Math.round(availableHeight / aspectRatio),\n height: availableHeight,\n };\n }\n\n return {\n width: calculatedWidth,\n height: Math.round(calculatedWidth * aspectRatio),\n };\n}\n","import React, {\n FC, useEffect, useRef, memo, useCallback, useState,\n} from '../../lib/teact/teact';\n\nimport { fastRaf } from '../../util/schedulers';\nimport buildClassName from '../../util/buildClassName';\nimport useHeavyAnimationCheck from '../../hooks/useHeavyAnimationCheck';\nimport useBackgroundMode from '../../hooks/useBackgroundMode';\n\ntype OwnProps = {\n className?: string;\n id: string;\n animationData: AnyLiteral;\n play?: boolean | string;\n playSegment?: [number, number];\n speed?: number;\n noLoop?: boolean;\n size: number;\n quality?: number;\n isLowPriority?: boolean;\n onLoad?: NoneToVoidFunction;\n};\n\ntype RLottieClass = typeof import('../../lib/rlottie/RLottie').default;\ntype RLottieInstance = import('../../lib/rlottie/RLottie').default;\nlet lottiePromise: Promise<RLottieClass>;\nlet RLottie: RLottieClass;\n\n// Time supposed for judges to measure \"Transferred Size\" in Dev Tools\nconst LOTTIE_LOAD_DELAY = 5000;\n\nasync function ensureLottie() {\n if (!lottiePromise) {\n lottiePromise = import('../../lib/rlottie/RLottie') as unknown as Promise<RLottieClass>;\n RLottie = (await lottiePromise as any).default;\n }\n\n return lottiePromise;\n}\n\nsetTimeout(ensureLottie, LOTTIE_LOAD_DELAY);\n\nconst AnimatedSticker: FC<OwnProps> = ({\n className,\n id,\n animationData,\n play,\n playSegment,\n speed,\n noLoop,\n size,\n quality,\n isLowPriority,\n onLoad,\n}) => {\n const [animation, setAnimation] = useState<RLottieInstance>();\n // eslint-disable-next-line no-null/no-null\n const container = useRef<HTMLDivElement>(null);\n const wasPlaying = useRef(false);\n const isFrozen = useRef(false);\n\n const playRef = useRef();\n playRef.current = play;\n const playSegmentRef = useRef<[number, number]>();\n playSegmentRef.current = playSegment;\n\n useEffect(() => {\n if (animation || !animationData) {\n return;\n }\n\n const exec = () => {\n if (!container.current) {\n return;\n }\n\n const newAnimation = new RLottie(\n id,\n container.current,\n animationData,\n {\n noLoop,\n size,\n quality,\n isLowPriority,\n },\n onLoad,\n );\n\n if (speed) {\n newAnimation.setSpeed(speed);\n }\n\n setAnimation(newAnimation);\n };\n\n if (RLottie) {\n exec();\n } else {\n ensureLottie().then(() => {\n fastRaf(() => {\n if (container.current) {\n exec();\n }\n });\n });\n }\n }, [animation, animationData, id, isLowPriority, noLoop, onLoad, quality, size, speed]);\n\n useEffect(() => {\n return () => {\n if (animation) {\n animation.destroy();\n }\n };\n }, [animation]);\n\n const playAnimation = useCallback((shouldRestart = false) => {\n if (animation && (playRef.current || playSegmentRef.current)) {\n if (playSegmentRef.current) {\n animation.playSegment(playSegmentRef.current);\n } else if (shouldRestart) {\n animation.goToAndPlay(0);\n } else {\n animation.play();\n }\n }\n }, [animation]);\n\n const pauseAnimation = useCallback(() => {\n if (!animation) {\n return;\n }\n\n animation.pause();\n }, [animation]);\n\n const freezeAnimation = useCallback(() => {\n isFrozen.current = true;\n\n if (!animation) {\n return;\n }\n\n if (!wasPlaying.current) {\n wasPlaying.current = animation.isPlaying();\n }\n\n pauseAnimation();\n }, [animation, pauseAnimation]);\n\n const unfreezeAnimation = useCallback(() => {\n if (wasPlaying.current) {\n playAnimation();\n }\n\n wasPlaying.current = false;\n isFrozen.current = false;\n }, [playAnimation]);\n\n const unfreezeAnimationOnRaf = useCallback(() => {\n fastRaf(unfreezeAnimation);\n }, [unfreezeAnimation]);\n\n useEffect(() => {\n if (!animation) {\n return;\n }\n\n if (play || playSegment) {\n if (isFrozen.current) {\n wasPlaying.current = true;\n } else {\n playAnimation(noLoop);\n }\n } else {\n // eslint-disable-next-line no-lonely-if\n if (isFrozen.current) {\n wasPlaying.current = false;\n } else {\n pauseAnimation();\n }\n }\n }, [animation, play, playSegment, noLoop, playAnimation, pauseAnimation]);\n\n useHeavyAnimationCheck(freezeAnimation, unfreezeAnimation);\n // Pausing frame may not happen in background\n // so we need to make sure it happens right after focusing,\n // then we can play again.\n useBackgroundMode(freezeAnimation, unfreezeAnimationOnRaf);\n\n const fullClassName = buildClassName('AnimatedSticker', className);\n\n const style = size ? `width: ${size}px; height: ${size}px;` : undefined;\n\n return (\n <div\n ref={container}\n className={fullClassName}\n // @ts-ignore\n style={style}\n />\n );\n};\n\nexport default memo(AnimatedSticker);\n","import React, { FC, memo } from '../../lib/teact/teact';\n\nimport useLang from '../../hooks/useLang';\nimport { TextPart } from '../common/helpers/renderMessageText';\n\nimport Modal from './Modal';\nimport Button from './Button';\n\ntype OwnProps = {\n isOpen: boolean;\n onClose: () => void;\n onCloseAnimationEnd?: () => void;\n title?: string;\n header?: FC;\n textParts?: TextPart[];\n text?: string;\n confirmLabel?: string;\n confirmHandler: () => void;\n confirmIsDestructive?: boolean;\n isButtonsInOneRow?: boolean;\n};\n\nconst ConfirmDialog: FC<OwnProps> = ({\n isOpen,\n onClose,\n onCloseAnimationEnd,\n title,\n header,\n text,\n textParts,\n confirmLabel = 'Confirm',\n confirmHandler,\n confirmIsDestructive,\n isButtonsInOneRow,\n}) => {\n const lang = useLang();\n\n return (\n <Modal\n className=\"confirm\"\n title={title}\n header={header}\n isOpen={isOpen}\n onClose={onClose}\n onCloseAnimationEnd={onCloseAnimationEnd}\n onEnter={confirmHandler}\n >\n {text && text.split('\\\\n').map((textPart) => (\n <p>{textPart}</p>\n ))}\n {textParts}\n <div className={isButtonsInOneRow ? 'dialog-buttons mt-2' : ''}>\n <Button\n className=\"confirm-dialog-button\"\n isText\n onClick={confirmHandler}\n color={confirmIsDestructive ? 'danger' : 'primary'}\n >\n {confirmLabel}\n </Button>\n <Button className=\"confirm-dialog-button\" isText onClick={onClose}>{lang('Cancel')}</Button>\n </div>\n </Modal>\n );\n};\n\nexport default memo(ConfirmDialog);\n","import React, { FC, memo } from '../../lib/teact/teact';\n\nimport buildClassName from '../../util/buildClassName';\nimport useShowTransition from '../../hooks/useShowTransition';\nimport renderText from './helpers/renderText';\nimport useLang from '../../hooks/useLang';\n\nimport './NothingFound.scss';\n\ninterface OwnProps {\n text?: string;\n description?: string;\n}\n\nconst DEFAULT_TEXT = 'Nothing found.';\n\nconst NothingFound: FC<OwnProps> = ({ text = DEFAULT_TEXT, description }) => {\n const lang = useLang();\n const { transitionClassNames } = useShowTransition(true);\n\n return (\n <div className={buildClassName('NothingFound', transitionClassNames, description && 'with-description')}>\n {text}\n {description && <p className=\"description\">{renderText(lang(description), ['br'])}</p>}\n </div>\n );\n};\n\nexport default memo(NothingFound);\n","import { useEffect, useRef } from '../../../lib/teact/teact';\n\nimport useOnChange from '../../../hooks/useOnChange';\nimport useForceUpdate from '../../../hooks/useForceUpdate';\n\nexport default function useAsyncRendering<T extends any[]>(dependencies: T, delay?: number) {\n const isDisabled = delay === undefined;\n const shouldRenderRef = useRef(isDisabled);\n const timeoutRef = useRef<number>();\n const forceUpdate = useForceUpdate();\n\n useOnChange(() => {\n if (isDisabled) {\n return;\n }\n\n shouldRenderRef.current = false;\n\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = undefined;\n }\n }, dependencies);\n\n useEffect(() => {\n if (isDisabled || shouldRenderRef.current) {\n return;\n }\n\n const exec = () => {\n shouldRenderRef.current = true;\n forceUpdate();\n };\n\n if (delay! > 0) {\n timeoutRef.current = window.setTimeout(exec, delay);\n } else {\n exec();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, dependencies);\n\n return shouldRenderRef.current;\n}\n","import {\n useEffect, useMemo, useRef, useState,\n} from '../lib/teact/teact';\n\nimport { IS_PROGRESSIVE_SUPPORTED } from '../util/environment';\nimport { ApiMediaFormat } from '../api/types';\nimport { throttle } from '../util/schedulers';\nimport * as mediaLoader from '../util/mediaLoader';\nimport useForceUpdate from './useForceUpdate';\n\nconst STREAMING_PROGRESS = 0.75;\nconst STREAMING_TIMEOUT = 1500;\nconst PROGRESS_THROTTLE = 500;\n\nexport default <T extends ApiMediaFormat = ApiMediaFormat.BlobUrl>(\n mediaHash: string | undefined,\n noLoad = false,\n // @ts-ignore (workaround for \"could be instantiated with a different subtype\" issue)\n mediaFormat: T = ApiMediaFormat.BlobUrl,\n cacheBuster?: number,\n delay?: number | false,\n) => {\n const mediaData = mediaHash ? mediaLoader.getFromMemory<T>(mediaHash) : undefined;\n const isStreaming = mediaFormat === ApiMediaFormat.Stream || (\n IS_PROGRESSIVE_SUPPORTED && mediaFormat === ApiMediaFormat.Progressive\n );\n const forceUpdate = useForceUpdate();\n const [downloadProgress, setDownloadProgress] = useState(mediaData && !isStreaming ? 1 : 0);\n const startedAtRef = useRef<number>();\n\n const handleProgress = useMemo(() => {\n return throttle((progress: number) => {\n if (!delay || (Date.now() - startedAtRef.current! > delay)) {\n setDownloadProgress(progress);\n }\n }, PROGRESS_THROTTLE, true);\n }, [delay]);\n\n useEffect(() => {\n if (!noLoad && mediaHash) {\n if (!mediaData) {\n setDownloadProgress(0);\n\n if (startedAtRef.current) {\n mediaLoader.cancelProgress(handleProgress);\n }\n\n startedAtRef.current = Date.now();\n\n mediaLoader.fetch(mediaHash, mediaFormat, handleProgress).then(() => {\n const spentTime = Date.now() - startedAtRef.current!;\n startedAtRef.current = undefined;\n\n if (!delay || spentTime >= delay) {\n forceUpdate();\n } else {\n setTimeout(forceUpdate, delay - spentTime);\n }\n });\n } else if (isStreaming) {\n setTimeout(() => {\n setDownloadProgress(STREAMING_PROGRESS);\n }, STREAMING_TIMEOUT);\n }\n }\n }, [noLoad, mediaHash, mediaData, mediaFormat, cacheBuster, forceUpdate, isStreaming, delay, handleProgress]);\n\n useEffect(() => {\n if (noLoad && startedAtRef.current) {\n mediaLoader.cancelProgress(handleProgress);\n setDownloadProgress(0);\n }\n }, [handleProgress, noLoad]);\n\n return { mediaData, downloadProgress };\n};\n","import React, {\n FC, useEffect, useRef, memo,\n} from '../../lib/teact/teact';\n\nimport buildClassName from '../../util/buildClassName';\n\nimport './ProgressSpinner.scss';\n\nconst RADIUSES = {\n s: 22, m: 25, l: 28, xl: 20,\n};\nconst STROKE_WIDTH = 2;\nconst MIN_PROGRESS = 0.05;\nconst MAX_PROGRESS = 1;\n\nconst ProgressSpinner: FC<{\n progress?: number;\n size?: 's' | 'm' | 'l' | 'xl';\n square?: boolean;\n transparent?: boolean;\n noCross?: boolean;\n onClick?: (e: React.MouseEvent<HTMLElement, MouseEvent>) => void;\n}> = ({\n progress = 0,\n size = 'l',\n square,\n transparent,\n noCross,\n onClick,\n}) => {\n const radius = RADIUSES[size];\n const circleRadius = radius - STROKE_WIDTH * 2;\n const borderRadius = radius - 1;\n const circumference = circleRadius * 2 * Math.PI;\n // eslint-disable-next-line no-null/no-null\n const container = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (!container.current) {\n return;\n }\n\n const svg = container.current.firstElementChild;\n const strokeDashOffset = circumference - Math.min(Math.max(MIN_PROGRESS, progress), MAX_PROGRESS) * circumference;\n\n if (!svg) {\n container.current.innerHTML = `<svg\n viewBox=\"0 0 ${borderRadius * 2} ${borderRadius * 2}\"\n height=\"${borderRadius * 2}\"\n width=\"${borderRadius * 2}\"\n >\n <circle\n stroke=\"white\"\n fill=\"transparent\"\n stroke-width=${STROKE_WIDTH}\n stroke-dasharray=\"${circumference} ${circumference}\"}\n stroke-dashoffset=\"${strokeDashOffset}\"\n stroke-linecap=\"round\"\n r=${circleRadius}\n cx=${borderRadius}\n cy=${borderRadius}\n />\n </svg>`;\n } else {\n (svg.firstElementChild as SVGElement).setAttribute('stroke-dashoffset', strokeDashOffset.toString());\n }\n }, [container, circumference, borderRadius, circleRadius, progress]);\n\n const className = buildClassName(\n `ProgressSpinner size-${size}`,\n transparent && 'transparent',\n square && 'square',\n noCross && 'no-cross',\n );\n\n return (\n <div\n ref={container}\n className={className}\n onClick={onClick}\n />\n );\n};\n\nexport default memo(ProgressSpinner);\n","import { FC, useRef, useLayoutEffect } from '../../lib/teact/teact';\nimport TeactDOM from '../../lib/teact/teact-dom';\n\ntype OwnProps = {\n containerId?: string;\n className?: string;\n children: any;\n};\n\nconst Portal: FC<OwnProps> = ({ containerId, className, children }) => {\n const elementRef = useRef(document.createElement('div'));\n\n useLayoutEffect(() => {\n const container = document.querySelector<HTMLDivElement>(containerId || '#portals');\n if (!container) {\n return undefined;\n }\n\n const element = elementRef.current;\n if (className) {\n element.classList.add(className);\n }\n\n container.appendChild(element);\n\n return () => {\n TeactDOM.render(undefined, element);\n container.removeChild(element);\n };\n }, [className, containerId]);\n\n return TeactDOM.render(children, elementRef.current);\n};\n\nexport default Portal;\n","import { MouseEvent as ReactMouseEvent } from 'react';\nimport React, {\n FC, useEffect, useCallback, memo,\n} from '../../lib/teact/teact';\nimport { withGlobal } from '../../lib/teact/teactn';\n\nimport { ApiChat, ApiTypingStatus } from '../../api/types';\nimport { GlobalActions, GlobalState } from '../../global/types';\nimport { MediaViewerOrigin } from '../../types';\n\nimport {\n getChatTypeString,\n getChatTitle,\n isChatSuperGroup,\n} from '../../modules/helpers';\nimport { selectChat, selectChatMessages, selectChatOnlineCount } from '../../modules/selectors';\nimport renderText from './helpers/renderText';\nimport { pick } from '../../util/iteratees';\nimport useLang, { LangFn } from '../../hooks/useLang';\n\nimport Avatar from './Avatar';\nimport VerifiedIcon from './VerifiedIcon';\nimport TypingStatus from './TypingStatus';\n\ntype OwnProps = {\n chatId: number;\n typingStatus?: ApiTypingStatus;\n avatarSize?: 'small' | 'medium' | 'large' | 'jumbo';\n withMediaViewer?: boolean;\n withUsername?: boolean;\n withFullInfo?: boolean;\n withUpdatingStatus?: boolean;\n withChatType?: boolean;\n noRtl?: boolean;\n};\n\ntype StateProps = {\n chat?: ApiChat;\n onlineCount?: number;\n areMessagesLoaded: boolean;\n} & Pick<GlobalState, 'lastSyncTime'>;\n\ntype DispatchProps = Pick<GlobalActions, 'loadFullChat' | 'openMediaViewer'>;\n\nconst GroupChatInfo: FC<OwnProps & StateProps & DispatchProps> = ({\n typingStatus,\n avatarSize = 'medium',\n withMediaViewer,\n withUsername,\n withFullInfo,\n withUpdatingStatus,\n withChatType,\n noRtl,\n chat,\n onlineCount,\n areMessagesLoaded,\n lastSyncTime,\n loadFullChat,\n openMediaViewer,\n}) => {\n const isSuperGroup = chat && isChatSuperGroup(chat);\n const { id: chatId, isMin, isRestricted } = chat || {};\n\n useEffect(() => {\n if (chatId && !isMin && withFullInfo && lastSyncTime) {\n loadFullChat({ chatId });\n }\n }, [chatId, isMin, lastSyncTime, withFullInfo, loadFullChat, isSuperGroup]);\n\n const handleAvatarViewerOpen = useCallback((e: ReactMouseEvent<HTMLDivElement, MouseEvent>, hasPhoto: boolean) => {\n if (chat && hasPhoto) {\n e.stopPropagation();\n openMediaViewer({\n avatarOwnerId: chat.id,\n origin: avatarSize === 'jumbo' ? MediaViewerOrigin.ProfileAvatar : MediaViewerOrigin.MiddleHeaderAvatar,\n });\n }\n }, [chat, avatarSize, openMediaViewer]);\n\n const lang = useLang();\n\n if (!chat) {\n return undefined;\n }\n\n function renderStatusOrTyping() {\n if (withUpdatingStatus && !areMessagesLoaded && !isRestricted) {\n return (\n <span className=\"status\" dir=\"auto\">{lang('Updating')}</span>\n );\n }\n\n if (!chat) {\n return undefined;\n }\n\n if (typingStatus) {\n return <TypingStatus typingStatus={typingStatus} />;\n }\n\n if (withChatType) {\n return (\n <div className=\"status\" dir=\"auto\">{lang(getChatTypeString(chat))}</div>\n );\n }\n\n const handle = withUsername ? chat.username : undefined;\n const groupStatus = getGroupStatus(lang, chat);\n const onlineStatus = onlineCount ? `, ${lang('OnlineCount', onlineCount, 'i')}` : undefined;\n\n return (\n <div className=\"status\">\n {handle && <span className=\"handle\">{handle}</span>}\n <span className=\"group-status\">{groupStatus}</span>\n {onlineStatus && <span className=\"online-status\">{onlineStatus}</span>}\n </div>\n );\n }\n\n return (\n <div className=\"ChatInfo\" dir={!noRtl && lang.isRtl ? 'rtl' : undefined}>\n <Avatar\n key={chat.id}\n size={avatarSize}\n chat={chat}\n onClick={withMediaViewer ? handleAvatarViewerOpen : undefined}\n />\n <div className=\"info\">\n <div className=\"title\">\n <h3 dir=\"auto\">{renderText(getChatTitle(lang, chat))}</h3>\n {chat.isVerified && <VerifiedIcon />}\n </div>\n {renderStatusOrTyping()}\n </div>\n </div>\n );\n};\n\nfunction getGroupStatus(lang: LangFn, chat: ApiChat) {\n const chatTypeString = lang(getChatTypeString(chat));\n const { membersCount } = chat;\n\n if (chat.isRestricted) {\n return chatTypeString === 'Channel' ? 'channel is inaccessible' : 'group is inaccessible';\n }\n\n if (!membersCount) {\n return chatTypeString;\n }\n\n return chatTypeString === 'Channel'\n ? lang('Subscribers', membersCount, 'i')\n : lang('Members', membersCount, 'i');\n}\n\nexport default memo(withGlobal<OwnProps>(\n (global, { chatId }): StateProps => {\n const { lastSyncTime } = global;\n const chat = selectChat(global, chatId);\n const onlineCount = chat ? selectChatOnlineCount(global, chat) : undefined;\n const areMessagesLoaded = Boolean(selectChatMessages(global, chatId));\n\n return {\n lastSyncTime, chat, onlineCount, areMessagesLoaded,\n };\n },\n (setGlobal, actions): DispatchProps => pick(actions, ['loadFullChat', 'openMediaViewer']),\n)(GroupChatInfo));\n","import { FocusDirection } from '../types';\n\nimport { dispatchHeavyAnimationEvent } from '../hooks/useHeavyAnimationCheck';\nimport { fastRaf } from './schedulers';\nimport { animateSingle } from './animation';\n\nconst MAX_DISTANCE = 1500;\nconst MIN_JS_DURATION = 250;\nconst MAX_JS_DURATION = 600;\n\nlet isAnimating = false;\n\nexport default function fastSmoothScroll(\n container: HTMLElement,\n element: HTMLElement,\n position: ScrollLogicalPosition | 'centerOrTop',\n margin = 0,\n maxDistance = MAX_DISTANCE,\n forceDirection?: FocusDirection,\n forceDuration?: number,\n forceCurrentContainerHeight?: boolean,\n) {\n if (forceDirection === FocusDirection.Static) {\n let block!: ScrollLogicalPosition;\n\n if (position === 'centerOrTop') {\n block = element.offsetHeight < container.offsetHeight ? 'center' : 'start';\n } else {\n block = position;\n }\n\n element.scrollIntoView({ block });\n\n return;\n }\n\n const { offsetTop } = element;\n\n if (forceDirection === undefined) {\n const offset = offsetTop - container.scrollTop;\n\n if (offset < -maxDistance) {\n container.scrollTop += (offset + maxDistance);\n } else if (offset > maxDistance) {\n container.scrollTop += (offset - maxDistance);\n }\n } else if (forceDirection === FocusDirection.Up) {\n container.scrollTop = offsetTop + maxDistance;\n } else if (forceDirection === FocusDirection.Down) {\n container.scrollTop = Math.max(0, offsetTop - maxDistance);\n }\n\n isAnimating = true;\n fastRaf(() => {\n scrollWithJs(container, element, position, margin, forceDuration, forceCurrentContainerHeight);\n });\n}\n\nexport function isAnimatingScroll() {\n return isAnimating;\n}\n\nfunction scrollWithJs(\n container: HTMLElement,\n element: HTMLElement,\n position: ScrollLogicalPosition | 'centerOrTop',\n margin = 0,\n forceDuration?: number,\n forceCurrentContainerHeight?: boolean,\n) {\n const { offsetTop: elementTop, offsetHeight: elementHeight } = element;\n const { scrollTop, offsetHeight: containerHeight, scrollHeight } = container;\n const targetContainerHeight = !forceCurrentContainerHeight && container.dataset.normalHeight\n ? Number(container.dataset.normalHeight)\n : containerHeight;\n\n let path!: number;\n\n switch (position) {\n case 'start':\n path = (elementTop - margin) - scrollTop;\n break;\n case 'end':\n path = (elementTop + elementHeight + margin) - (scrollTop + targetContainerHeight);\n break;\n // 'nearest' is not supported yet\n case 'nearest':\n case 'center':\n case 'centerOrTop':\n path = elementHeight < targetContainerHeight\n ? (elementTop + elementHeight / 2) - (scrollTop + targetContainerHeight / 2)\n : (elementTop - margin) - scrollTop;\n break;\n }\n\n if (path < 0) {\n const remainingPath = -scrollTop;\n path = Math.max(path, remainingPath);\n } else if (path > 0) {\n const remainingPath = scrollHeight - (scrollTop + targetContainerHeight);\n path = Math.min(path, remainingPath);\n }\n\n const target = container.scrollTop + path;\n const duration = forceDuration || (\n MIN_JS_DURATION + (Math.abs(path) / MAX_DISTANCE) * (MAX_JS_DURATION - MIN_JS_DURATION)\n );\n const startAt = Date.now();\n\n dispatchHeavyAnimationEvent(duration);\n animateSingle(() => {\n const t = Math.min((Date.now() - startAt) / duration, 1);\n\n const currentPath = path * (1 - transition(t));\n container.scrollTop = Math.round(target - currentPath);\n\n isAnimating = t < 1;\n\n return isAnimating;\n });\n}\n\nfunction transition(t: number) {\n return 1 - ((1 - t) ** 3.5);\n}\n","import { ChangeEvent } from 'react';\nimport React, { FC, memo } from '../../lib/teact/teact';\n\nimport buildClassName from '../../util/buildClassName';\nimport useLang from '../../hooks/useLang';\n\nimport Spinner from './Spinner';\n\nimport './Radio.scss';\n\ntype OwnProps = {\n id?: string;\n name: string;\n label: string;\n subLabel?: string;\n value: string;\n checked: boolean;\n disabled?: boolean;\n hidden?: boolean;\n isLoading?: boolean;\n onChange: (e: ChangeEvent<HTMLInputElement>) => void;\n};\n\nconst Radio: FC<OwnProps> = ({\n id,\n label,\n subLabel,\n value,\n name,\n checked,\n disabled,\n hidden,\n isLoading,\n onChange,\n}) => {\n const lang = useLang();\n const className = buildClassName(\n 'Radio',\n disabled && 'disabled',\n hidden && 'hidden-widget',\n isLoading && 'loading',\n );\n\n return (\n <label className={className} dir={lang.isRtl ? 'rtl' : undefined}>\n <input\n type=\"radio\"\n name={name}\n value={value}\n id={id}\n checked={checked}\n onChange={onChange}\n disabled={disabled || hidden}\n />\n <div className=\"Radio-main\">\n <span className=\"label\" dir={lang.isRtl ? 'auto' : undefined}>{label}</span>\n {subLabel && <span className=\"subLabel\" dir={lang.isRtl ? 'auto' : undefined}>{subLabel}</span>}\n </div>\n {isLoading && <Spinner />}\n </label>\n );\n};\n\nexport default memo(Radio);\n","import { ChangeEvent } from 'react';\nimport React, { FC, useCallback, memo } from '../../lib/teact/teact';\n\nimport Radio from './Radio';\n\ntype IRadioOption = {\n label: string;\n subLabel?: string;\n value: string;\n hidden?: boolean;\n};\n\ntype OwnProps = {\n id?: string;\n name: string;\n options: IRadioOption[];\n selected?: string;\n disabled?: boolean;\n loadingOption?: string;\n onChange: (value: string) => void;\n};\n\nconst RadioGroup: FC<OwnProps> = ({\n id,\n name,\n options,\n selected,\n disabled,\n loadingOption,\n onChange,\n}) => {\n const handleChange = useCallback((event: ChangeEvent<HTMLInputElement>) => {\n const { value } = event.currentTarget;\n onChange(value);\n }, [onChange]);\n\n return (\n <div id={id} className=\"radio-group\">\n {options.map((option) => (\n <Radio\n name={name}\n label={option.label}\n subLabel={option.subLabel}\n value={option.value}\n checked={option.value === selected}\n hidden={option.hidden}\n disabled={disabled}\n isLoading={loadingOption ? loadingOption === option.value : undefined}\n onChange={handleChange}\n />\n ))}\n </div>\n );\n};\n\nexport default memo(RadioGroup);\n","import { useEffect } from '../lib/teact/teact';\n\nexport default function useBackgroundMode(\n onBlur: AnyToVoidFunction,\n onFocus: AnyToVoidFunction,\n) {\n useEffect(() => {\n if (!document.hasFocus()) {\n onBlur();\n }\n\n window.addEventListener('blur', onBlur);\n window.addEventListener('focus', onFocus);\n\n return () => {\n window.removeEventListener('focus', onFocus);\n window.removeEventListener('blur', onBlur);\n };\n }, [onBlur, onFocus]);\n}\n","import { useCallback, useEffect, useRef } from '../lib/teact/teact';\nimport { LoadMoreDirection } from '../types';\n\nimport { areSortedArraysEqual } from '../util/iteratees';\nimport useForceUpdate from './useForceUpdate';\nimport usePrevious from './usePrevious';\n\ntype GetMore = (args: { direction: LoadMoreDirection }) => void;\ntype LoadMoreBackwards = (args: { offsetId?: number }) => void;\n\nconst DEFAULT_LIST_SLICE = 30;\n\nexport default (\n loadMoreBackwards?: LoadMoreBackwards,\n listIds?: number[],\n isDisabled = false,\n listSlice = DEFAULT_LIST_SLICE,\n forceFullPreload = false,\n): [number[]?, GetMore?] => {\n const lastParamsRef = useRef<{\n direction?: LoadMoreDirection;\n offsetId?: number;\n }>();\n\n const viewportIdsRef = useRef<number[] | undefined>((() => {\n // Only run once to initialize\n if (!listIds || lastParamsRef.current) {\n return undefined;\n }\n\n const { newViewportIds } = getViewportSlice(listIds, listIds[0], LoadMoreDirection.Forwards, listSlice);\n return newViewportIds;\n })());\n\n const forceUpdate = useForceUpdate();\n\n const prevListIds = usePrevious(listIds);\n const prevIsDisabled = usePrevious(isDisabled);\n if (listIds && !isDisabled && (listIds !== prevListIds || isDisabled !== prevIsDisabled)) {\n const { offsetId = listIds[0], direction = LoadMoreDirection.Forwards } = lastParamsRef.current || {};\n const { newViewportIds } = getViewportSlice(listIds, offsetId, direction, listSlice);\n\n if (!viewportIdsRef.current || !areSortedArraysEqual(viewportIdsRef.current, newViewportIds)) {\n viewportIdsRef.current = newViewportIds;\n }\n }\n\n useEffect(() => {\n if (listIds && !isDisabled && loadMoreBackwards && forceFullPreload) {\n const viewportIds = viewportIdsRef.current!;\n loadMoreBackwards({ offsetId: viewportIds[viewportIds.length - 1] });\n }\n }, [listIds, isDisabled, loadMoreBackwards, forceFullPreload]);\n\n const getMore: GetMore = useCallback(({\n direction,\n noScroll,\n }: { direction: LoadMoreDirection; noScroll?: boolean }) => {\n const viewportIds = viewportIdsRef.current;\n\n const offsetId = viewportIds\n ? direction === LoadMoreDirection.Backwards ? viewportIds[viewportIds.length - 1] : viewportIds[0]\n : undefined;\n\n if (!listIds) {\n if (loadMoreBackwards) {\n loadMoreBackwards({ offsetId });\n }\n\n return;\n }\n\n if (!noScroll) {\n lastParamsRef.current = { ...lastParamsRef.current, direction, offsetId };\n }\n\n const {\n newViewportIds, areSomeLocal, areAllLocal,\n } = getViewportSlice(listIds, offsetId, direction, listSlice);\n\n if (areSomeLocal && !(viewportIds && areSortedArraysEqual(viewportIds, newViewportIds))) {\n viewportIdsRef.current = newViewportIds;\n forceUpdate();\n }\n\n if (!areAllLocal && loadMoreBackwards) {\n loadMoreBackwards({ offsetId });\n }\n }, [listIds, listSlice, loadMoreBackwards, forceUpdate]);\n\n return isDisabled ? [listIds] : [viewportIdsRef.current, getMore];\n};\n\nfunction getViewportSlice(\n sourceIds: number[],\n offsetId = 0,\n direction: LoadMoreDirection,\n listSlice: number,\n) {\n const { length } = sourceIds;\n const index = sourceIds.indexOf(offsetId);\n const isForwards = direction === LoadMoreDirection.Forwards;\n const indexForDirection = isForwards ? index : (index + 1) || length;\n const from = Math.max(0, indexForDirection - listSlice);\n const to = indexForDirection + listSlice - 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.Forwards:\n areSomeLocal = indexForDirection > 0;\n areAllLocal = from >= 0;\n break;\n case LoadMoreDirection.Backwards:\n areSomeLocal = indexForDirection < length;\n areAllLocal = to <= length - 1;\n break;\n }\n\n return { newViewportIds, areSomeLocal, areAllLocal };\n}\n","import React, {\n FC, useCallback, useRef, useState,\n} from '../../lib/teact/teact';\n\nimport { ApiMediaFormat, ApiSticker } from '../../api/types';\n\nimport { STICKER_SIZE_TWO_FA } from '../../config';\nimport { getStickerDimensions, LIKE_STICKER_ID } from './helpers/mediaDimensions';\nimport { ObserveFn, useIsIntersecting } from '../../hooks/useIntersectionObserver';\nimport useMedia from '../../hooks/useMedia';\nimport useTransitionForMedia from '../../hooks/useTransitionForMedia';\nimport useFlag from '../../hooks/useFlag';\n\nimport AnimatedSticker from './AnimatedSticker';\n\nimport './AnimatedEmoji.scss';\n\ntype OwnProps = {\n sticker: ApiSticker;\n observeIntersection?: ObserveFn;\n isInline?: boolean;\n lastSyncTime?: number;\n forceLoadPreview?: boolean;\n};\n\nconst QUALITY = 1;\nconst RESIZE_FACTOR = 0.5;\n\nconst AnimatedEmoji: FC<OwnProps> = ({\n sticker, isInline = false, observeIntersection, lastSyncTime, forceLoadPreview,\n}) => {\n // eslint-disable-next-line no-null/no-null\n const ref = useRef<HTMLDivElement>(null);\n\n const [isAnimationLoaded, markAnimationLoaded] = useFlag();\n const localMediaHash = `sticker${sticker.id}`;\n\n const isIntersecting = useIsIntersecting(ref, observeIntersection);\n\n const thumbDataUri = sticker.thumbnail && sticker.thumbnail.dataUri;\n const previewBlobUrl = useMedia(\n `${localMediaHash}?size=m`,\n !isIntersecting && !forceLoadPreview,\n ApiMediaFormat.BlobUrl,\n lastSyncTime,\n );\n const { transitionClassNames } = useTransitionForMedia(previewBlobUrl, 'slow');\n\n const mediaData = useMedia(localMediaHash, !isIntersecting, ApiMediaFormat.Lottie, lastSyncTime);\n const isMediaLoaded = Boolean(mediaData);\n\n const [playKey, setPlayKey] = useState(String(Math.random()));\n const handleClick = useCallback(() => {\n setPlayKey(String(Math.random()));\n }, []);\n\n let width: number;\n if (isInline) {\n width = getStickerDimensions(sticker).width * RESIZE_FACTOR;\n } else {\n width = STICKER_SIZE_TWO_FA;\n }\n\n const style = `width: ${width}px; height: ${width}px;`;\n\n return (\n <div\n ref={ref}\n className=\"AnimatedEmoji media-inner\"\n // @ts-ignore\n style={style}\n onClick={handleClick}\n >\n {!isAnimationLoaded && thumbDataUri && (\n <img src={thumbDataUri} className={sticker.id === LIKE_STICKER_ID ? 'like-sticker-thumb' : undefined} alt=\"\" />\n )}\n {!isAnimationLoaded && previewBlobUrl && (\n <img src={previewBlobUrl} className={transitionClassNames} alt=\"\" />\n )}\n {isMediaLoaded && (\n <AnimatedSticker\n key={localMediaHash}\n id={localMediaHash}\n animationData={mediaData as AnyLiteral}\n size={width}\n quality={QUALITY}\n play={isIntersecting && playKey}\n noLoop\n onLoad={markAnimationLoaded}\n />\n )}\n </div>\n );\n};\n\nexport default AnimatedEmoji;\n","export default function focusEditableElement(element: HTMLElement, force?: boolean) {\n if (!force && element === document.activeElement) {\n return;\n }\n const selection = window.getSelection()!;\n const range = document.createRange();\n\n if (!element.lastChild || !element.lastChild.nodeValue) {\n element.focus();\n return;\n }\n\n range.setStart(element.lastChild, element.lastChild.nodeValue.length);\n selection.removeAllRanges();\n selection.addRange(range);\n}\n","export enum SwipeDirection {\n Up,\n Down,\n Left,\n Right,\n}\n\ninterface CaptureOptions {\n onCapture?: (e: MouseEvent | TouchEvent) => void;\n onRelease?: (e: MouseEvent | TouchEvent) => void;\n onDrag?: (\n e: MouseEvent | TouchEvent,\n captureEvent: MouseEvent | TouchEvent,\n params: {\n dragOffsetX: number;\n dragOffsetY: number;\n },\n ) => void;\n onSwipe?: (e: Event, direction: SwipeDirection) => void;\n onClick?: (e: MouseEvent | TouchEvent) => void;\n excludedClosestSelector?: string;\n withCursor?: boolean;\n}\n\n// https://stackoverflow.com/questions/11287877/how-can-i-get-e-offsetx-on-mobile-ipad\n// Android does not have this value, and iOS has it but as read-only\nexport interface RealTouchEvent extends TouchEvent {\n pageX?: number;\n pageY?: number;\n}\n\ntype TSwipeAxis = 'x' | 'y' | undefined;\n\nconst MOVED_THRESHOLD = 15;\nconst SWIPE_THRESHOLD = 50;\n\nexport function captureEvents(element: HTMLElement, options: CaptureOptions) {\n let captureEvent: MouseEvent | RealTouchEvent | undefined;\n let hasMoved = false;\n let currentSwipeAxis: TSwipeAxis;\n\n function onCapture(e: MouseEvent | RealTouchEvent) {\n if (options.excludedClosestSelector && (\n (e.target as HTMLElement).matches(options.excludedClosestSelector)\n || (e.target as HTMLElement).closest(options.excludedClosestSelector)\n )) {\n return;\n }\n\n captureEvent = e;\n\n if (e.type === 'mousedown') {\n document.addEventListener('mousemove', onMove);\n document.addEventListener('mouseup', onRelease);\n } else if (e.type === 'touchstart') {\n document.addEventListener('touchmove', onMove);\n document.addEventListener('touchend', onRelease);\n document.addEventListener('touchcancel', onRelease);\n\n if ('touches' in e) {\n if (e.pageX === undefined) {\n e.pageX = e.touches[0].pageX;\n }\n\n if (e.pageY === undefined) {\n e.pageY = e.touches[0].pageY;\n }\n }\n }\n\n document.body.classList.add('no-selection');\n if (options.withCursor) {\n document.body.classList.add('cursor-grabbing');\n }\n\n if (options.onCapture) {\n options.onCapture(e);\n }\n }\n\n function onRelease(e: MouseEvent | TouchEvent) {\n if (captureEvent) {\n if (options.withCursor) {\n document.body.classList.remove('cursor-grabbing');\n }\n document.body.classList.remove('no-selection');\n\n document.removeEventListener('mouseup', onRelease);\n document.removeEventListener('mousemove', onMove);\n document.removeEventListener('touchcancel', onRelease);\n document.removeEventListener('touchend', onRelease);\n document.removeEventListener('touchmove', onMove);\n\n captureEvent = undefined;\n\n if (hasMoved) {\n if (options.onRelease) {\n options.onRelease(e);\n }\n } else if (options.onClick && (!('button' in e) || e.button === 0)) {\n options.onClick(e);\n }\n }\n\n hasMoved = false;\n currentSwipeAxis = undefined;\n }\n\n function onMove(e: MouseEvent | RealTouchEvent) {\n if (captureEvent) {\n if (e.type === 'touchmove' && ('touches' in e)) {\n if (e.pageX === undefined) {\n e.pageX = e.touches[0].pageX;\n }\n\n if (e.pageY === undefined) {\n e.pageY = e.touches[0].pageY;\n }\n }\n\n const dragOffsetX = e.pageX! - captureEvent.pageX!;\n const dragOffsetY = e.pageY! - captureEvent.pageY!;\n\n if (Math.abs(dragOffsetX) >= MOVED_THRESHOLD || Math.abs(dragOffsetY) >= MOVED_THRESHOLD) {\n hasMoved = true;\n }\n\n if (options.onDrag) {\n e.preventDefault();\n options.onDrag(e, captureEvent, { dragOffsetX, dragOffsetY });\n }\n\n if (options.onSwipe) {\n onSwipe(e, dragOffsetX, dragOffsetY);\n }\n }\n }\n\n function onSwipe(e: Event, dragOffsetX: number, dragOffsetY: number) {\n if (!currentSwipeAxis) {\n const xAbs = Math.abs(dragOffsetX);\n const yAbs = Math.abs(dragOffsetY);\n\n if (dragOffsetX && dragOffsetY) {\n const ratio = Math.max(xAbs, yAbs) / Math.min(xAbs, yAbs);\n // Diagonal swipe\n if (ratio < 2) {\n return;\n }\n }\n\n if (xAbs >= SWIPE_THRESHOLD) {\n currentSwipeAxis = 'x';\n } else if (yAbs >= SWIPE_THRESHOLD) {\n currentSwipeAxis = 'y';\n }\n }\n\n processSwipe(e, currentSwipeAxis, dragOffsetX, dragOffsetY, options.onSwipe!);\n }\n\n element.addEventListener('mousedown', onCapture);\n element.addEventListener('touchstart', onCapture, { passive: true });\n\n return () => {\n element.removeEventListener('mousedown', onCapture);\n element.removeEventListener('touchstart', onCapture);\n };\n}\n\nfunction processSwipe(\n e: Event,\n currentSwipeAxis:TSwipeAxis,\n dragOffsetX: number,\n dragOffsetY: number,\n onSwipe: (e: Event, direction: SwipeDirection) => void,\n) {\n if (currentSwipeAxis === 'x') {\n if (dragOffsetX < 0) {\n onSwipe(e, SwipeDirection.Left);\n } else {\n onSwipe(e, SwipeDirection.Right);\n }\n } else if (currentSwipeAxis === 'y') {\n if (dragOffsetY < 0) {\n onSwipe(e, SwipeDirection.Up);\n } else {\n onSwipe(e, SwipeDirection.Down);\n }\n }\n}\n","import React, { FC } from '../../lib/teact/teact';\n\nimport './VerifiedIcon.scss';\n\nconst VerifiedIcon: FC = () => {\n return (\n <span className=\"VerifiedIcon\" />\n );\n};\n\nexport default VerifiedIcon;\n","export default function cycleRestrict(length: number, index: number) {\n return index - Math.floor(index / length) * length;\n}\n","import usePrevious from './usePrevious';\n\nexport default function useCurrentOrPrev<T extends any>(\n current: T, shouldSkipUndefined = false, shouldForceCurrent = false,\n): T | undefined {\n const prev = usePrevious(current, shouldSkipUndefined);\n\n // eslint-disable-next-line no-null/no-null\n return shouldForceCurrent || (current !== null && current !== undefined) ? current : prev;\n}\n","import { DEBUG } from '../config';\n\nexport default (mediaEl: HTMLMediaElement) => {\n mediaEl.play().catch((err) => {\n if (DEBUG) {\n // eslint-disable-next-line no-console\n console.warn(err);\n }\n });\n};\n","import React, { useCallback, useMemo, useState } from '../lib/teact/teact';\nimport { debounce } from '../util/schedulers';\nimport { isSafariPatchInProgress } from '../util/patchSafariProgressiveAudio';\n\ntype BufferingEvent = (e: Event | React.SyntheticEvent<HTMLMediaElement>) => void;\n\nconst MIN_READY_STATE = 3;\n// Avoid flickering when re-mounting previously buffered video\nconst DEBOUNCE = 200;\n\nexport default (noInitiallyBuffered = false) => {\n const [isBuffered, setIsBuffered] = useState(!noInitiallyBuffered);\n const [bufferedProgress, setBufferedProgress] = useState(0);\n\n const setIsBufferedDebounced = useMemo(() => {\n return debounce(setIsBuffered, DEBOUNCE, false, true);\n }, []);\n\n const handleBuffering = useCallback<BufferingEvent>((e) => {\n const media = e.currentTarget as HTMLMediaElement;\n\n if (!isSafariPatchInProgress(media)) {\n if (media.buffered.length) {\n setBufferedProgress(media.buffered.end(0) / media.duration);\n }\n\n setIsBufferedDebounced(media.readyState >= MIN_READY_STATE || media.currentTime > 0);\n }\n }, [setIsBufferedDebounced]);\n\n const bufferingHandlers = {\n onLoadedData: handleBuffering,\n onPlaying: handleBuffering,\n onLoadStart: handleBuffering, // Needed for Safari to start\n onPause: handleBuffering, // Needed for Chrome when seeking\n onTimeUpdate: handleBuffering, // Needed for audio buffering progress\n onProgress: handleBuffering, // Needed for video buffering progress\n };\n\n return {\n isBuffered,\n bufferedProgress,\n bufferingHandlers,\n checkBuffering(element: HTMLMediaElement) {\n setIsBufferedDebounced(element.readyState >= MIN_READY_STATE);\n },\n };\n};\n","import { ApiMessageEntity, ApiMessageEntityTypes, ApiFormattedText } from '../../../../api/types';\nimport { IS_EMOJI_SUPPORTED } from '../../../../util/environment';\n\nconst ENTITY_CLASS_BY_NODE_NAME: Record<string, string> = {\n B: ApiMessageEntityTypes.Bold,\n STRONG: ApiMessageEntityTypes.Bold,\n I: ApiMessageEntityTypes.Italic,\n EM: ApiMessageEntityTypes.Italic,\n U: ApiMessageEntityTypes.Underline,\n S: ApiMessageEntityTypes.Strike,\n STRIKE: ApiMessageEntityTypes.Strike,\n DEL: ApiMessageEntityTypes.Strike,\n CODE: ApiMessageEntityTypes.Code,\n PRE: ApiMessageEntityTypes.Pre,\n BLOCKQUOTE: ApiMessageEntityTypes.Blockquote,\n};\n\nconst MAX_TAG_DEEPNESS = 3;\nconst MAX_MESSAGE_LENGTH = 4096;\n\nexport default function parseMessageInput(html: string): ApiFormattedText {\n const fragment = document.createElement('div');\n fragment.innerHTML = parseMarkdown(html);\n const text = fragment.innerText.trim().replace(/\\u200b+/g, '').slice(0, MAX_MESSAGE_LENGTH);\n let textIndex = 0;\n let recursionDeepness = 0;\n const entities: ApiMessageEntity[] = [];\n\n function addEntity(node: ChildNode) {\n const { index, entity } = getEntityDataFromNode(node, text, textIndex);\n\n if (entity) {\n textIndex = index;\n entities.push(entity);\n } else if (node.textContent) {\n textIndex += node.textContent.length;\n }\n\n if (node.hasChildNodes() && recursionDeepness <= MAX_TAG_DEEPNESS) {\n recursionDeepness += 1;\n Array.from(node.childNodes).forEach(addEntity);\n }\n }\n\n Array.from(fragment.childNodes).forEach((node) => {\n recursionDeepness = 1;\n addEntity(node);\n });\n\n return {\n text,\n entities: entities.length ? entities : undefined,\n };\n}\n\nfunction parseMarkdown(html: string) {\n let parsedHtml = html.slice(0);\n\n if (!IS_EMOJI_SUPPORTED) {\n // Emojis\n parsedHtml = parsedHtml.replace(/<img[^>]+alt=\"([^\"]+)\"[^>]*>/gm, '$1');\n }\n\n // Strip redundant <span> tags\n parsedHtml = parsedHtml.replace(/<\\/?span([^>]*)?>/g, '');\n\n // Strip redundant nbsp's\n parsedHtml = parsedHtml.replace(/ /g, ' ');\n\n // Replace <br> with newline\n parsedHtml = parsedHtml.replace(/<br([^>]*)?>/g, '\\n');\n\n // Strip redundant <div> tags\n parsedHtml = parsedHtml.replace(/<\\/div>(\\s*)<div>/g, '\\n');\n parsedHtml = parsedHtml.replace(/<div>/g, '\\n');\n parsedHtml = parsedHtml.replace(/<\\/div>/g, '');\n\n // Pre\n parsedHtml = parsedHtml.replace(/^`{3}(.*[\\n\\r][^]*?^)`{3}/gm, '<pre>$1</pre>');\n parsedHtml = parsedHtml.replace(/[`]{3}([^`]+)[`]{3}/g, '<pre>$1</pre>');\n\n // Code\n parsedHtml = parsedHtml.replace(/[`]{1}([^`\\n]+)[`]{1}/g, '<code>$1</code>');\n\n // Other simple markdown\n parsedHtml = parsedHtml.replace(/[*]{2}([^*\\n]+)[*]{2}/g, '<b>$1</b>');\n parsedHtml = parsedHtml.replace(/[_]{2}([^*\\n]+)[_]{2}/g, '<i>$1</i>');\n parsedHtml = parsedHtml.replace(/[~]{2}([^~\\n]+)[~]{2}/g, '<s>$1</s>');\n\n return parsedHtml;\n}\n\nfunction getEntityDataFromNode(\n node: ChildNode,\n rawText: string,\n textIndex: number,\n): { index: number; entity?: ApiMessageEntity } {\n const type = getEntityTypeFromNode(node);\n if (!type || !node.textContent) {\n return {\n index: textIndex,\n entity: undefined,\n };\n }\n\n const rawIndex = rawText.indexOf(node.textContent, textIndex);\n // In some cases, last text entity ends with a newline (which gets trimmed from `rawText`).\n // In this case, `rawIndex` would return `-1`, so we use `textIndex` instead.\n const index = rawIndex >= 0 ? rawIndex : textIndex;\n const offset = rawText.substring(0, index).length;\n const { length } = rawText.substring(index, index + node.textContent.length);\n\n let url: string | undefined;\n let userId: number | undefined;\n if (type === ApiMessageEntityTypes.TextUrl) {\n url = (node as HTMLAnchorElement).href;\n }\n if (type === ApiMessageEntityTypes.MentionName) {\n userId = Number((node as HTMLAnchorElement).dataset.userId);\n }\n\n return {\n index,\n entity: {\n type,\n offset,\n length,\n ...(url && { url }),\n ...(userId && { userId }),\n },\n };\n}\n\nfunction getEntityTypeFromNode(node: ChildNode) {\n if (ENTITY_CLASS_BY_NODE_NAME[node.nodeName]) {\n return ENTITY_CLASS_BY_NODE_NAME[node.nodeName];\n }\n\n if (node.nodeName === 'A') {\n const anchor = node as HTMLAnchorElement;\n if (anchor.dataset.entityType === ApiMessageEntityTypes.MentionName) {\n return ApiMessageEntityTypes.MentionName;\n }\n if (anchor.dataset.entityType === ApiMessageEntityTypes.Url) {\n return ApiMessageEntityTypes.Url;\n }\n if (anchor.href.startsWith('mailto:')) {\n return ApiMessageEntityTypes.Email;\n }\n if (anchor.href.startsWith('tel:')) {\n return ApiMessageEntityTypes.Phone;\n }\n if (anchor.href !== anchor.textContent) {\n return ApiMessageEntityTypes.TextUrl;\n }\n\n return ApiMessageEntityTypes.Url;\n }\n\n if (node.nodeName === 'SPAN') {\n return (node as HTMLElement).dataset.entityType;\n }\n\n return undefined;\n}\n","import React, { FC, memo } from '../../../lib/teact/teact';\n\nimport useFlag from '../../../hooks/useFlag';\nimport buildClassName from '../../../util/buildClassName';\n\nimport './DropTarget.scss';\n\nexport type OwnProps = {\n isQuick?: boolean;\n onFileSelect: (e: React.DragEvent<HTMLDivElement>) => void;\n};\n\nconst DropTarget: FC<OwnProps> = ({ isQuick, onFileSelect }) => {\n const [isHovered, markHovered, unmarkHovered] = useFlag();\n\n const handleDragEnter = () => { markHovered(); };\n const handleDragLeave = (e: React.DragEvent<HTMLDivElement>) => {\n const { relatedTarget: toTarget } = e;\n\n if (toTarget) {\n e.stopPropagation();\n }\n\n unmarkHovered();\n };\n\n const className = buildClassName(\n 'DropTarget',\n isHovered && 'hovered',\n );\n\n return (\n <div\n className={className}\n onDrop={onFileSelect}\n onDragEnter={handleDragEnter}\n onDragLeave={handleDragLeave}\n >\n <div className=\"target-content\">\n <div className={`icon icon-${isQuick ? 'photo' : 'document'}`} />\n <div className=\"title\">Drop files here to send them</div>\n <div className=\"description\">{isQuick ? 'in a quick way' : 'without compression'}</div>\n </div>\n </div>\n );\n};\n\nexport default memo(DropTarget);\n","import React, {\n FC, memo, useCallback, useEffect, useRef,\n} from '../../../lib/teact/teact';\n\nimport useShowTransition from '../../../hooks/useShowTransition';\nimport buildClassName from '../../../util/buildClassName';\n\nimport captureEscKeyListener from '../../../util/captureEscKeyListener';\nimport usePrevious from '../../../hooks/usePrevious';\n\nimport DropTarget from './DropTarget';\n\nimport './DropArea.scss';\n\nexport type OwnProps = {\n isOpen: boolean;\n withQuick?: boolean;\n onHide: NoneToVoidFunction;\n onFileSelect: (files: File[], isQuick: boolean) => void;\n};\n\nexport enum DropAreaState {\n None = 'none',\n Document = 'document',\n QuickFile = 'quick_file',\n}\n\nconst DROP_LEAVE_TIMEOUT_MS = 150;\n\nconst DropArea: FC<OwnProps> = ({\n isOpen, withQuick, onHide, onFileSelect,\n}) => {\n // eslint-disable-next-line no-null/no-null\n const hideTimeoutRef = useRef<number>(null);\n const prevWithQuick = usePrevious(withQuick);\n const { shouldRender, transitionClassNames } = useShowTransition(isOpen);\n\n useEffect(() => (isOpen ? captureEscKeyListener(onHide) : undefined), [isOpen, onHide]);\n\n const handleFilesDrop = useCallback((e: React.DragEvent<HTMLDivElement>) => {\n const { dataTransfer: dt } = e;\n\n if (dt.files && dt.files.length > 0) {\n onHide();\n onFileSelect(Array.from(dt.files), false);\n }\n }, [onFileSelect, onHide]);\n\n const handleQuickFilesDrop = useCallback((e: React.DragEvent<HTMLDivElement>) => {\n const { dataTransfer: dt } = e;\n\n if (dt.files && dt.files.length > 0) {\n onHide();\n onFileSelect(Array.from(dt.files), true);\n }\n }, [onFileSelect, onHide]);\n\n const handleDragLeave = useCallback((e: React.DragEvent<HTMLDivElement>) => {\n e.stopPropagation();\n\n const { target: fromTarget, relatedTarget: toTarget } = e;\n\n // Esc button pressed during drag event\n if ((fromTarget as HTMLDivElement).matches('.DropTarget, .DropArea') && !toTarget) {\n hideTimeoutRef.current = window.setTimeout(() => {\n onHide();\n }, DROP_LEAVE_TIMEOUT_MS);\n }\n }, [onHide]);\n\n const handleDragOver = () => {\n if (hideTimeoutRef.current) {\n window.clearTimeout(hideTimeoutRef.current);\n }\n };\n\n if (!shouldRender) {\n return undefined;\n }\n\n const className = buildClassName(\n 'DropArea',\n transitionClassNames,\n );\n\n return (\n <div className={className} onDragLeave={handleDragLeave} onDragOver={handleDragOver} onDrop={onHide}>\n <DropTarget onFileSelect={handleFilesDrop} />\n {(withQuick || prevWithQuick) && <DropTarget onFileSelect={handleQuickFilesDrop} isQuick />}\n </div>\n );\n};\n\nexport default memo(DropArea);\n","import React, { FC, memo } from '../../lib/teact/teact';\nimport { withGlobal } from '../../lib/teact/teactn';\n\nimport { ApiChat, ApiUser } from '../../api/types';\n\nimport { selectChat, selectUser } from '../../modules/selectors';\nimport { getChatTitle, getUserFirstOrLastName, isChatPrivate } from '../../modules/helpers';\nimport renderText from './helpers/renderText';\nimport buildClassName from '../../util/buildClassName';\nimport useLang from '../../hooks/useLang';\n\nimport Avatar from './Avatar';\n\nimport './PickerSelectedItem.scss';\n\ntype OwnProps = {\n chatOrUserId?: number;\n icon?: string;\n title?: string;\n isMinimized?: boolean;\n canClose?: boolean;\n onClick: (arg: any) => void;\n clickArg: any;\n className?: string;\n};\n\ntype StateProps = {\n chat?: ApiChat;\n user?: ApiUser;\n};\n\nconst PickerSelectedItem: FC<OwnProps & StateProps> = ({\n icon,\n title,\n isMinimized,\n canClose,\n onClick,\n clickArg,\n chat,\n user,\n className,\n}) => {\n const lang = useLang();\n\n let iconElement: any;\n let titleText: any;\n\n if (icon && title) {\n iconElement = (\n <div className=\"item-icon\">\n <i className={`icon-${icon}`} />\n </div>\n );\n\n titleText = title;\n } else if (chat || user) {\n iconElement = (\n <Avatar\n chat={chat}\n user={user}\n size=\"small\"\n isSavedMessages={user && user.isSelf}\n />\n );\n\n const name = !chat || (user && !user.isSelf)\n ? getUserFirstOrLastName(user)\n : getChatTitle(lang, chat, user);\n\n titleText = name ? renderText(name) : undefined;\n }\n\n const fullClassName = buildClassName(\n 'PickerSelectedItem',\n className,\n isMinimized && 'minimized',\n canClose && 'closeable',\n );\n\n return (\n <div\n className={fullClassName}\n onClick={() => onClick(clickArg)}\n title={isMinimized ? titleText : undefined}\n dir={lang.isRtl ? 'rtl' : undefined}\n >\n {iconElement}\n {!isMinimized && (\n <div className=\"item-name\" dir=\"auto\">\n {titleText}\n </div>\n )}\n {canClose && (\n <div className=\"item-remove\">\n <i className=\"icon-close\" />\n </div>\n )}\n </div>\n );\n};\n\nexport default memo(withGlobal<OwnProps>(\n (global, { chatOrUserId }): StateProps => {\n if (!chatOrUserId) {\n return {};\n }\n\n const chat = chatOrUserId ? selectChat(global, chatOrUserId) : undefined;\n const user = isChatPrivate(chatOrUserId) ? selectUser(global, chatOrUserId) : undefined;\n\n return {\n chat,\n user,\n };\n },\n)(PickerSelectedItem));\n","import { fastRaf } from './schedulers';\nimport { animate } from './animation';\nimport { IS_IOS } from './environment';\n\nconst DURATION = 450;\n\nexport default function fastSmoothScrollHorizontal(container: HTMLElement, left: number) {\n // Native way seems to be smoother in Chrome\n if (!IS_IOS) {\n container.scrollTo({ left, behavior: 'smooth' });\n } else {\n fastRaf(() => {\n scrollWithJs(container, left);\n });\n }\n}\n\nfunction scrollWithJs(container: HTMLElement, left: number) {\n const { scrollLeft, offsetWidth: containerWidth, scrollWidth } = container;\n let path = left - scrollLeft;\n\n if (path < 0) {\n const remainingPath = -scrollLeft;\n path = Math.max(path, remainingPath);\n } else if (path > 0) {\n const remainingPath = scrollWidth - (scrollLeft + containerWidth);\n path = Math.min(path, remainingPath);\n }\n\n const target = container.scrollLeft + path;\n const startAt = Date.now();\n\n animate(() => {\n const t = Math.min((Date.now() - startAt) / DURATION, 1);\n\n const currentPath = path * (1 - transition(t));\n container.scrollLeft = Math.round(target - currentPath);\n\n return t < 1;\n });\n}\n\nfunction transition(t: number) {\n return 1 - ((1 - t) ** 3.5);\n}\n","import { useEffect } from '../lib/teact/teact';\n\nexport default (container: HTMLElement | null, isDisabled?: boolean) => {\n useEffect(() => {\n if (!container) {\n return undefined;\n }\n\n function handleScroll(e: WheelEvent) {\n // Ignore horizontal scroll and let it work natively (e.g. on touchpad)\n if (!e.deltaX) {\n container!.scrollLeft += e.deltaY / 4;\n }\n }\n\n container.addEventListener('wheel', handleScroll, { passive: true });\n\n return () => {\n container.removeEventListener('wheel', handleScroll);\n };\n }, [container, isDisabled]);\n};\n","import { useEffect, useMemo } from '../lib/teact/teact';\nimport { getDispatch } from '../lib/teact/teactn';\n\nimport { ApiMessage } from '../api/types';\n\nimport { throttle } from '../util/schedulers';\n\nexport default (\n chatId: number,\n messageId?: number,\n message?: ApiMessage,\n replyOriginForId?: number,\n) => {\n const { loadMessage } = getDispatch();\n const loadMessageThrottled = useMemo(() => {\n const throttled = throttle(loadMessage, 500, true);\n return () => {\n throttled({ chatId, messageId, replyOriginForId });\n };\n }, [loadMessage, chatId, messageId, replyOriginForId]);\n\n useEffect(() => {\n if (messageId && !message) {\n loadMessageThrottled();\n }\n });\n};\n","import { RefObject } from 'react';\nimport { useState, useEffect, useCallback } from '../lib/teact/teact';\n\nimport { IAnchorPosition } from '../types';\nimport { IS_TOUCH_ENV, IS_SINGLE_COLUMN_LAYOUT } from '../util/environment';\n\nconst LONG_TAP_DURATION_MS = 250;\nconst SELECTION_ANIMATION_DURATION_MS = 200;\n\nlet contextMenuCounter = 0;\n\nfunction checkIsDisabledForMobile() {\n return IS_SINGLE_COLUMN_LAYOUT\n && window.document.body.classList.contains('enable-symbol-menu-transforms');\n}\n\nexport default (\n elementRef: RefObject<HTMLElement>,\n isMenuDisabled?: boolean,\n shouldDisableOnLink?: boolean,\n) => {\n const [isContextMenuOpen, setIsContextMenuOpen] = useState(false);\n const [contextMenuPosition, setContextMenuPosition] = useState<IAnchorPosition | undefined>(undefined);\n\n const handleBeforeContextMenu = useCallback((e: React.MouseEvent) => {\n if (!isMenuDisabled && e.button === 2) {\n document.body.classList.add('no-selection');\n }\n }, [isMenuDisabled]);\n\n const handleContextMenu = useCallback((e: React.MouseEvent) => {\n document.body.classList.remove('no-selection');\n\n if (isMenuDisabled || (shouldDisableOnLink && (e.target as HTMLElement).matches('a.text-entity-link[href]'))) {\n return;\n }\n e.preventDefault();\n\n if (contextMenuPosition) {\n return;\n }\n document.body.classList.remove('no-selection');\n if (contextMenuCounter === 0) {\n document.body.classList.add('has-context-menu');\n }\n contextMenuCounter++;\n\n setIsContextMenuOpen(true);\n setContextMenuPosition({ x: e.clientX, y: e.clientY });\n }, [isMenuDisabled, shouldDisableOnLink, contextMenuPosition]);\n\n const handleContextMenuClose = useCallback(() => {\n setIsContextMenuOpen(false);\n }, []);\n\n const handleContextMenuHide = useCallback(() => {\n setContextMenuPosition(undefined);\n document.body.classList.remove('no-selection');\n\n setTimeout(() => {\n contextMenuCounter--;\n if (contextMenuCounter === 0) {\n document.body.classList.remove('has-context-menu');\n }\n }, SELECTION_ANIMATION_DURATION_MS);\n }, []);\n\n // Support context menu on touch-devices\n useEffect(() => {\n if (isMenuDisabled || !IS_TOUCH_ENV) {\n return undefined;\n }\n\n const element = elementRef.current;\n if (!element) {\n return undefined;\n }\n\n let timer: number | undefined;\n\n const clearLongPressTimer = () => {\n if (timer) {\n clearTimeout(timer);\n timer = undefined;\n }\n };\n\n const emulateContextMenuEvent = (originalEvent: TouchEvent) => {\n clearLongPressTimer();\n\n const { clientX, clientY } = originalEvent.touches[0];\n\n if (contextMenuPosition) {\n return;\n }\n\n // temporarily intercept and clear the next click\n element.addEventListener('touchend', function cancelClickOnce(e) {\n element.removeEventListener('touchend', cancelClickOnce, true);\n e.stopImmediatePropagation();\n e.preventDefault();\n e.stopPropagation();\n }, true);\n\n document.body.classList.add('no-selection');\n setIsContextMenuOpen(true);\n setContextMenuPosition({ x: clientX, y: clientY });\n };\n\n const startLongPressTimer = (e: TouchEvent) => {\n if (isMenuDisabled || checkIsDisabledForMobile()) {\n return;\n }\n clearLongPressTimer();\n\n timer = window.setTimeout(() => emulateContextMenuEvent(e), LONG_TAP_DURATION_MS);\n };\n\n // @perf Consider event delegation\n element.addEventListener('touchstart', startLongPressTimer, { passive: true });\n element.addEventListener('touchcancel', clearLongPressTimer, true);\n element.addEventListener('touchend', clearLongPressTimer, true);\n element.addEventListener('touchmove', clearLongPressTimer, { passive: true });\n\n return () => {\n clearLongPressTimer();\n element.removeEventListener('touchstart', startLongPressTimer);\n element.removeEventListener('touchcancel', clearLongPressTimer, true);\n element.removeEventListener('touchend', clearLongPressTimer, true);\n element.removeEventListener('touchmove', clearLongPressTimer);\n };\n }, [contextMenuPosition, isMenuDisabled, elementRef]);\n\n return {\n isContextMenuOpen,\n contextMenuPosition,\n handleBeforeContextMenu,\n handleContextMenu,\n handleContextMenuClose,\n handleContextMenuHide,\n };\n};\n","import { MouseEvent } from 'react';\nimport React from '../../../lib/teact/teact';\nimport { getDispatch } from '../../../lib/teact/teactn';\n\nimport { ApiMessageEntity, ApiMessageEntityTypes, ApiMessage } from '../../../api/types';\n\nimport { getMessageText } from '../../../modules/helpers';\nimport renderText from './renderText';\n\nimport MentionLink from '../../middle/message/MentionLink';\nimport SafeLink from '../SafeLink';\n\nexport type TextPart = string | Element;\n\nexport function renderMessageText(message: ApiMessage, highlight?: string, shouldRenderHqEmoji?: boolean) {\n const formattedText = message.content.text;\n\n if (!formattedText || !formattedText.text) {\n const rawText = getMessageText(message);\n return rawText ? [rawText] : undefined;\n }\n const { text, entities } = formattedText;\n\n return renderTextWithEntities(text, entities, highlight, shouldRenderHqEmoji);\n}\n\ninterface IOrganizedEntity {\n entity: ApiMessageEntity;\n organizedIndexes: Set<number>;\n nestedEntities: IOrganizedEntity[];\n}\n\nfunction organizeEntity(\n entity: ApiMessageEntity,\n index: number,\n entities: ApiMessageEntity[],\n organizedEntityIndexes: Set<number>,\n): IOrganizedEntity | undefined {\n const { offset, length } = entity;\n const organizedIndexes = new Set([index]);\n\n if (organizedEntityIndexes.has(index)) {\n return undefined;\n }\n\n // Determine any nested entities inside current entity\n const nestedEntities = entities\n .filter((e, i) => i > index && e.offset >= offset && e.offset < offset + length)\n .map((e) => organizeEntity(e, entities.indexOf(e), entities, organizedEntityIndexes))\n .filter<IOrganizedEntity>(Boolean as any);\n\n nestedEntities.forEach((e) => e.organizedIndexes.forEach((i) => organizedIndexes.add(i)));\n\n return {\n entity,\n organizedIndexes,\n nestedEntities,\n };\n}\n\n// Organize entities in a tree-like structure to better represent how the text will be displayed\nfunction organizeEntities(entities: ApiMessageEntity[]) {\n const organizedEntityIndexes: Set<number> = new Set();\n const organizedEntities: IOrganizedEntity[] = [];\n\n entities.forEach((entity, index) => {\n if (organizedEntityIndexes.has(index)) {\n return;\n }\n\n const organizedEntity = organizeEntity(entity, index, entities, organizedEntityIndexes);\n if (organizedEntity) {\n organizedEntity.organizedIndexes.forEach((organizedIndex) => {\n organizedEntityIndexes.add(organizedIndex);\n });\n\n organizedEntities.push(organizedEntity);\n }\n });\n\n return organizedEntities;\n}\n\nexport function renderTextWithEntities(\n text: string,\n entities?: ApiMessageEntity[],\n highlight?: string,\n shouldRenderHqEmoji?: boolean,\n shouldRenderAsHtml?: boolean,\n) {\n if (!entities || !entities.length) {\n return renderMessagePart(text, highlight, shouldRenderHqEmoji, shouldRenderAsHtml);\n }\n\n const result: TextPart[] = [];\n let deleteLineBreakAfterPre = false;\n\n const organizedEntites = organizeEntities(entities);\n\n // Recursive function to render regular and nested entities\n function renderEntity(\n textPartStart: number,\n textPartEnd: number,\n organizedEntity: IOrganizedEntity,\n isLastEntity: boolean,\n ) {\n const renderResult: TextPart[] = [];\n const { entity, nestedEntities } = organizedEntity;\n const { offset, length, type } = entity;\n\n // Render text before the entity\n let textBefore = text.substring(textPartStart, offset);\n const textBeforeLength = textBefore.length;\n if (textBefore) {\n if (deleteLineBreakAfterPre && textBefore.length > 0 && textBefore[0] === '\\n') {\n textBefore = textBefore.substr(1);\n deleteLineBreakAfterPre = false;\n }\n if (textBefore) {\n renderResult.push(...renderMessagePart(\n textBefore, highlight, shouldRenderHqEmoji, shouldRenderAsHtml,\n ) as TextPart[]);\n }\n }\n\n const entityStartIndex = textPartStart + textBeforeLength;\n const entityEndIndex = entityStartIndex + length;\n\n let entityContent: TextPart = text.substring(offset, offset + length);\n const nestedEntityContent: TextPart[] = [];\n\n if (deleteLineBreakAfterPre && entityContent.length > 0 && entityContent[0] === '\\n') {\n entityContent = entityContent.substr(1);\n deleteLineBreakAfterPre = false;\n }\n\n if (type === ApiMessageEntityTypes.Pre) {\n deleteLineBreakAfterPre = true;\n }\n\n // Render nested entities, if any\n if (nestedEntities.length) {\n let nestedIndex = entityStartIndex;\n\n nestedEntities.forEach((nestedEntity, nestedEntityIndex) => {\n const {\n renderResult: nestedResult,\n entityEndIndex: nestedEntityEndIndex,\n } = renderEntity(\n nestedIndex,\n entityEndIndex,\n nestedEntity,\n nestedEntityIndex === nestedEntities.length - 1,\n );\n\n nestedEntityContent.push(...nestedResult);\n nestedIndex = nestedEntityEndIndex;\n });\n }\n\n // Render the entity itself\n const newEntity = shouldRenderAsHtml\n ? processEntityAsHtml(entity, entityContent, nestedEntityContent)\n : processEntity(entity, entityContent, nestedEntityContent);\n\n if (Array.isArray(newEntity)) {\n renderResult.push(...newEntity);\n } else {\n renderResult.push(newEntity);\n }\n\n // Render text after the entity, if it is the last entity in the text,\n // or the last nested entity inside of another entity\n if (isLastEntity && entityEndIndex < textPartEnd) {\n let textAfter = text.substring(entityEndIndex, textPartEnd);\n if (deleteLineBreakAfterPre && textAfter.length > 0 && textAfter[0] === '\\n') {\n textAfter = textAfter.substring(1);\n }\n if (textAfter) {\n renderResult.push(...renderMessagePart(\n textAfter, highlight, shouldRenderHqEmoji, shouldRenderAsHtml,\n ) as TextPart[]);\n }\n }\n\n return {\n renderResult,\n entityEndIndex,\n };\n }\n\n // Process highest-level entities\n let index = 0;\n\n organizedEntites.forEach((entity, arrayIndex) => {\n const { renderResult, entityEndIndex } = renderEntity(\n index,\n text.length,\n entity,\n arrayIndex === organizedEntites.length - 1,\n );\n\n result.push(...renderResult);\n index = entityEndIndex;\n });\n\n return result;\n}\n\nfunction processEntity(\n entity: ApiMessageEntity,\n entityContent: TextPart,\n nestedEntityContent: TextPart[],\n) {\n const entityText = typeof entityContent === 'string' && entityContent;\n const renderedContent = nestedEntityContent.length ? nestedEntityContent : entityContent;\n\n if (!entityText) {\n return renderMessagePart(renderedContent);\n }\n\n switch (entity.type) {\n case ApiMessageEntityTypes.Bold:\n return <strong>{renderMessagePart(renderedContent)}</strong>;\n case ApiMessageEntityTypes.Blockquote:\n return <blockquote>{renderMessagePart(renderedContent)}</blockquote>;\n case ApiMessageEntityTypes.BotCommand:\n return (\n <a\n onClick={handleBotCommandClick}\n className=\"text-entity-link\"\n dir=\"auto\"\n >\n {renderMessagePart(renderedContent)}\n </a>\n );\n case ApiMessageEntityTypes.Hashtag:\n return (\n <a\n onClick={handleHashtagClick}\n className=\"text-entity-link\"\n dir=\"auto\"\n >\n {renderMessagePart(renderedContent)}\n </a>\n );\n case ApiMessageEntityTypes.Cashtag:\n return (\n <a\n onClick={handleHashtagClick}\n className=\"text-entity-link\"\n dir=\"auto\"\n >\n {renderMessagePart(renderedContent)}\n </a>\n );\n case ApiMessageEntityTypes.Code:\n return <code className=\"text-entity-code\">{renderMessagePart(renderedContent)}</code>;\n case ApiMessageEntityTypes.Email:\n return (\n <a\n href={`mailto:${entityText}`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-entity-link\"\n dir=\"auto\"\n >\n {renderMessagePart(renderedContent)}\n </a>\n );\n case ApiMessageEntityTypes.Italic:\n return <em>{renderMessagePart(renderedContent)}</em>;\n case ApiMessageEntityTypes.MentionName:\n return (\n <MentionLink userId={entity.userId}>\n {renderMessagePart(renderedContent)}\n </MentionLink>\n );\n case ApiMessageEntityTypes.Mention:\n return (\n <MentionLink username={entityText}>\n {renderMessagePart(renderedContent)}\n </MentionLink>\n );\n case ApiMessageEntityTypes.Phone:\n return (\n <a\n href={`tel:${entityText}`}\n className=\"text-entity-link\"\n dir=\"auto\"\n >\n {renderMessagePart(renderedContent)}\n </a>\n );\n case ApiMessageEntityTypes.Pre:\n return <pre className=\"text-entity-pre\">{renderMessagePart(renderedContent)}</pre>;\n case ApiMessageEntityTypes.Strike:\n return <del>{renderMessagePart(renderedContent)}</del>;\n case ApiMessageEntityTypes.TextUrl:\n case ApiMessageEntityTypes.Url:\n return (\n <SafeLink\n url={getLinkUrl(entityText, entity)}\n text={entityText}\n >\n {renderMessagePart(renderedContent)}\n </SafeLink>\n );\n case ApiMessageEntityTypes.Underline:\n return <ins>{renderMessagePart(renderedContent)}</ins>;\n default:\n return renderMessagePart(renderedContent);\n }\n}\n\nfunction renderMessagePart(\n content: TextPart | TextPart[],\n highlight?: string,\n shouldRenderHqEmoji?: boolean,\n shouldRenderAsHtml?: boolean,\n) {\n if (Array.isArray(content)) {\n const result: TextPart[] = [];\n\n content.forEach((c) => {\n result.push(...renderMessagePart(c, highlight, shouldRenderHqEmoji, shouldRenderAsHtml));\n });\n\n return result;\n }\n\n if (shouldRenderAsHtml) {\n return renderText(content, ['escape_html', 'emoji_html', 'br_html']);\n }\n\n const emojiFilter = shouldRenderHqEmoji ? 'hq_emoji' : 'emoji';\n\n if (highlight) {\n return renderText(content, [emojiFilter, 'br', 'highlight'], { highlight });\n } else {\n return renderText(content, [emojiFilter, 'br']);\n }\n}\n\nfunction getLinkUrl(entityContent: string, entity: ApiMessageEntity) {\n const { type, url } = entity;\n return type === ApiMessageEntityTypes.TextUrl && url ? url : entityContent;\n}\n\nfunction handleBotCommandClick(e: MouseEvent<HTMLAnchorElement>) {\n getDispatch().sendBotCommand({ command: e.currentTarget.innerText });\n}\n\nfunction handleHashtagClick(e: MouseEvent<HTMLAnchorElement>) {\n getDispatch().setLocalTextSearchQuery({ query: e.currentTarget.innerText });\n getDispatch().searchTextMessagesLocal();\n}\n\nfunction processEntityAsHtml(\n entity: ApiMessageEntity,\n entityContent: TextPart,\n nestedEntityContent: TextPart[],\n) {\n const rawEntityText = typeof entityContent === 'string' && entityContent;\n\n const renderedContent = nestedEntityContent.length\n ? nestedEntityContent.join('')\n : renderText(entityContent, ['emoji_html', 'br_html']).join('');\n\n if (!rawEntityText) {\n return renderedContent;\n }\n\n switch (entity.type) {\n case ApiMessageEntityTypes.Bold:\n return `<b>${renderedContent}</b>`;\n case ApiMessageEntityTypes.Italic:\n return `<i>${renderedContent}</i>`;\n case ApiMessageEntityTypes.Underline:\n return `<u>${renderedContent}</u>`;\n case ApiMessageEntityTypes.Code:\n return `<code class=\"text-entity-code\">${renderedContent}</code>`;\n case ApiMessageEntityTypes.Pre:\n return `\\`\\`\\`<br/>${renderedContent}<br/>\\`\\`\\``;\n case ApiMessageEntityTypes.Strike:\n return `<del>${renderedContent}</del>`;\n case ApiMessageEntityTypes.MentionName:\n return `<a\n class=\"text-entity-link\"\n data-entity-type=\"${ApiMessageEntityTypes.MentionName}\"\n data-user-id=\"${entity.userId}\"\n contenteditable=\"false\"\n dir=\"auto\"\n >${renderedContent}</a>`;\n case ApiMessageEntityTypes.Url:\n case ApiMessageEntityTypes.TextUrl:\n return `<a\n class=\"text-entity-link\"\n href=${getLinkUrl(rawEntityText, entity)}\n data-entity-type=\"${entity.type}\"\n dir=\"auto\"\n >${renderedContent}</a>`;\n default:\n return renderedContent;\n }\n}\n","import { RefObject } from 'react';\nimport { useEffect } from '../lib/teact/teact';\nimport { fastRaf } from '../util/schedulers';\n\n// Fix for memory leak when unmounting video element\nexport default function useVideoCleanup(videoRef: RefObject<HTMLVideoElement>, dependencies: any[]) {\n useEffect(() => {\n const videoEl = videoRef.current;\n\n return () => {\n if (videoEl) {\n fastRaf(() => {\n videoEl.pause();\n videoEl.src = '';\n videoEl.load();\n });\n }\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, dependencies);\n}\n","import { DEBUG } from '../config';\n\nexport const CLIPBOARD_ITEM_SUPPORTED = navigator.clipboard && window.ClipboardItem;\n\nconst textCopyEl = document.createElement('textarea');\ntextCopyEl.setAttribute('readonly', '');\ntextCopyEl.tabIndex = -1;\ntextCopyEl.className = 'visually-hidden';\n\nexport const copyTextToClipboard = (str: string): void => {\n textCopyEl.value = str;\n document.body.appendChild(textCopyEl);\n const selection = document.getSelection();\n\n if (selection) {\n // Store previous selection\n const rangeToRestore = selection.rangeCount > 0 && selection.getRangeAt(0);\n textCopyEl.select();\n document.execCommand('copy');\n // Restore the original selection\n if (rangeToRestore) {\n selection.removeAllRanges();\n selection.addRange(rangeToRestore);\n }\n }\n\n document.body.removeChild(textCopyEl);\n};\n\nexport const copyImageToClipboard = (imageUrl: string) => {\n const canvas = document.createElement('canvas');\n const ctx = canvas.getContext('2d');\n const imageEl = new Image();\n imageEl.onload = (e: Event) => {\n if (ctx && e.currentTarget) {\n const img = e.currentTarget as HTMLImageElement;\n canvas.width = img.width;\n canvas.height = img.height;\n ctx.drawImage(img, 0, 0, img.width, img.height);\n canvas.toBlob(copyBlobToClipboard, 'image/png', 1);\n }\n };\n\n imageEl.src = imageUrl;\n};\n\nasync function copyBlobToClipboard(pngBlob: Blob | null) {\n if (!pngBlob || !CLIPBOARD_ITEM_SUPPORTED) {\n return;\n }\n\n try {\n await navigator.clipboard.write([\n new window.ClipboardItem({\n [pngBlob.type]: pngBlob,\n }),\n ]);\n } catch (error) {\n if (DEBUG) {\n // eslint-disable-next-line no-console\n console.error(error);\n }\n }\n}\n","import { RefObject } from 'react';\nimport React, {\n FC, useRef, useEffect, memo, useCallback,\n} from '../../lib/teact/teact';\n\nimport buildClassName from '../../util/buildClassName';\nimport useFlag from '../../hooks/useFlag';\nimport useLang from '../../hooks/useLang';\n\nimport Loading from './Loading';\nimport Button from './Button';\n\nimport './SearchInput.scss';\n\ntype OwnProps = {\n ref?: RefObject<HTMLInputElement>;\n children?: any;\n parentContainerClassName?: string;\n className?: string;\n inputId?: string;\n value?: string;\n focused?: boolean;\n isLoading?: boolean;\n placeholder?: string;\n disabled?: boolean;\n autoComplete?: string;\n canClose?: boolean;\n onChange: (value: string) => void;\n onReset?: NoneToVoidFunction;\n onFocus?: NoneToVoidFunction;\n onBlur?: NoneToVoidFunction;\n};\n\nconst SearchInput: FC<OwnProps> = ({\n ref,\n children,\n parentContainerClassName,\n value,\n inputId,\n className,\n focused,\n isLoading,\n placeholder,\n disabled,\n autoComplete,\n canClose,\n onChange,\n onReset,\n onFocus,\n onBlur,\n}) => {\n // eslint-disable-next-line no-null/no-null\n let inputRef = useRef<HTMLInputElement>(null);\n if (ref) {\n inputRef = ref;\n }\n\n const [isInputFocused, markInputFocused, unmarkInputFocused] = useFlag(focused);\n\n useEffect(() => {\n if (!inputRef.current) {\n return;\n }\n\n if (focused) {\n inputRef.current.focus();\n } else {\n inputRef.current.blur();\n }\n }, [focused, placeholder]); // Trick for setting focus when selecting a contact to search for\n\n const lang = useLang();\n\n function handleChange(event: React.ChangeEvent<HTMLInputElement>) {\n const { currentTarget } = event;\n onChange(currentTarget.value);\n }\n\n function handleFocus() {\n markInputFocused();\n if (onFocus) {\n onFocus();\n }\n }\n\n function handleBlur() {\n unmarkInputFocused();\n if (onBlur) {\n onBlur();\n }\n }\n\n const handleKeyDown = useCallback((e: React.KeyboardEvent) => {\n if (e.key === 'ArrowDown') {\n const element = document.querySelector(`.${parentContainerClassName} .ListItem-button`) as HTMLElement;\n if (element) {\n element.focus();\n }\n }\n }, [parentContainerClassName]);\n\n return (\n <div\n className={buildClassName('SearchInput', className, isInputFocused && 'has-focus')}\n dir={lang.isRtl ? 'rtl' : undefined}\n >\n {children}\n <input\n ref={inputRef}\n id={inputId}\n type=\"text\"\n dir=\"auto\"\n placeholder={placeholder || lang('Search')}\n className=\"form-control\"\n value={value}\n disabled={disabled}\n autoComplete={autoComplete}\n onChange={handleChange}\n onFocus={handleFocus}\n onBlur={handleBlur}\n onKeyDown={handleKeyDown}\n />\n <i className=\"icon-search\" />\n {isLoading && (\n <Loading />\n )}\n {!isLoading && (value || canClose) && onReset && (\n <Button\n round\n size=\"tiny\"\n color=\"translucent\"\n onClick={onReset}\n >\n <span className=\"icon-close\" />\n </Button>\n )}\n </div>\n );\n};\n\nexport default memo(SearchInput);\n","import { IS_IOS } from './environment';\n\nexport default (container: HTMLDivElement, scrollTop?: number) => {\n if (IS_IOS) {\n container.style.overflow = 'hidden';\n }\n\n if (scrollTop !== undefined) {\n container.scrollTop = scrollTop;\n }\n\n if (IS_IOS) {\n container.style.overflow = '';\n }\n};\n","import React, { FC, memo } from '../../lib/teact/teact';\nimport { withGlobal } from '../../lib/teact/teactn';\n\nimport { ApiUser, ApiTypingStatus } from '../../api/types';\n\nimport { selectUser } from '../../modules/selectors';\nimport { getUserFirstOrLastName } from '../../modules/helpers';\nimport renderText from './helpers/renderText';\nimport useLang from '../../hooks/useLang';\n\nimport './TypingStatus.scss';\n\ntype OwnProps = {\n typingStatus: ApiTypingStatus;\n};\n\ntype StateProps = {\n typingUser?: ApiUser;\n};\n\nconst TypingStatus: FC<OwnProps & StateProps> = ({ typingStatus, typingUser }) => {\n const lang = useLang();\n const typingUserName = typingUser && !typingUser.isSelf && getUserFirstOrLastName(typingUser);\n\n return (\n <p className=\"typing-status\" dir={lang.isRtl ? 'rtl' : 'auto'}>\n {typingUserName && (\n <span className=\"sender-name\" dir=\"auto\">{renderText(typingUserName)}</span>\n )}\n {/* fix for translation \"username _is_ typing\" */}\n {lang(typingStatus.action).replace('{user}', '').trim()}\n <span className=\"ellipsis\" />\n </p>\n );\n};\n\nexport default memo(withGlobal<OwnProps>(\n (global, { typingStatus }): StateProps => {\n if (!typingStatus.userId) {\n return {};\n }\n\n const typingUser = selectUser(global, typingStatus.userId);\n\n return { typingUser };\n },\n)(TypingStatus));\n","import React, { FC, useCallback, memo } from '../../lib/teact/teact';\nimport { withGlobal } from '../../lib/teact/teactn';\n\nimport { ApiChat } from '../../api/types';\nimport { GlobalActions } from '../../global/types';\n\nimport { selectIsChatWithSelf, selectUser } from '../../modules/selectors';\nimport {\n isChatPrivate,\n getUserFirstOrLastName,\n getPrivateChatUserId,\n isChatBasicGroup,\n isChatSuperGroup,\n isChatChannel,\n getChatTitle,\n} from '../../modules/helpers';\nimport { pick } from '../../util/iteratees';\nimport useLang from '../../hooks/useLang';\nimport renderText from './helpers/renderText';\n\nimport Avatar from './Avatar';\nimport Modal from '../ui/Modal';\nimport Button from '../ui/Button';\n\nimport './DeleteChatModal.scss';\n\nexport type OwnProps = {\n isOpen: boolean;\n chat: ApiChat;\n onClose: () => void;\n onCloseAnimationEnd?: () => void;\n};\n\ntype StateProps = {\n isChannel: boolean;\n isChatWithSelf?: boolean;\n isPrivateChat: boolean;\n isBasicGroup: boolean;\n isSuperGroup: boolean;\n canDeleteForAll?: boolean;\n contactName?: string;\n};\n\ntype DispatchProps = Pick<GlobalActions, 'leaveChannel' | 'deleteHistory' | 'deleteChannel'>;\n\nconst DeleteChatModal: FC<OwnProps & StateProps & DispatchProps> = ({\n isOpen,\n chat,\n isChannel,\n isPrivateChat,\n isChatWithSelf,\n isBasicGroup,\n isSuperGroup,\n canDeleteForAll,\n contactName,\n onClose,\n onCloseAnimationEnd,\n leaveChannel,\n deleteHistory,\n deleteChannel,\n}) => {\n const lang = useLang();\n const chatTitle = getChatTitle(lang, chat);\n\n const handleDeleteMessageForAll = useCallback(() => {\n deleteHistory({ chatId: chat.id, shouldDeleteForAll: true });\n\n onClose();\n }, [deleteHistory, chat.id, onClose]);\n\n const handleDeleteChat = useCallback(() => {\n if (isPrivateChat || isBasicGroup) {\n deleteHistory({ chatId: chat.id, shouldDeleteForAll: false });\n } else if ((isChannel || isSuperGroup) && !chat.isCreator) {\n leaveChannel({ chatId: chat.id });\n } else if ((isChannel || isSuperGroup) && chat.isCreator) {\n deleteChannel({ chatId: chat.id });\n }\n onClose();\n }, [\n isPrivateChat,\n isBasicGroup,\n isChannel,\n isSuperGroup,\n chat.isCreator,\n chat.id,\n onClose,\n deleteHistory,\n leaveChannel,\n deleteChannel,\n ]);\n\n function renderHeader() {\n return (\n <div className=\"modal-header\" dir={lang.isRtl ? 'rtl' : undefined}>\n <Avatar\n size=\"tiny\"\n chat={chat}\n isSavedMessages={isChatWithSelf}\n />\n <h3 className=\"modal-title\">{lang(renderTitle())}</h3>\n </div>\n );\n }\n\n function renderTitle() {\n if (isChannel && !chat.isCreator) {\n return 'LeaveChannel';\n }\n\n if (isChannel && chat.isCreator) {\n return 'ChannelDelete';\n }\n\n if (isBasicGroup || isSuperGroup) {\n return 'Group.LeaveGroup';\n }\n\n return 'DeleteChatUser';\n }\n\n function renderMessage() {\n if (isChannel && chat.isCreator) {\n return <p>{renderText(lang('ChatList.DeleteAndLeaveGroupConfirmation', chatTitle), ['simple_markdown'])}</p>;\n }\n\n if ((isChannel && !chat.isCreator) || isBasicGroup || isSuperGroup) {\n return <p>{renderText(lang('ChannelLeaveAlertWithName', chatTitle), ['simple_markdown'])}</p>;\n }\n\n return <p>{renderText(lang('ChatList.DeleteChatConfirmation', contactName), ['simple_markdown'])}</p>;\n }\n\n function renderActionText() {\n if (isChannel && !chat.isCreator) {\n return 'LeaveChannel';\n }\n if (isChannel && chat.isCreator) {\n return 'Chat.Input.Delete';\n }\n\n if (isBasicGroup || isSuperGroup) {\n return 'Group.LeaveGroup';\n }\n\n return canDeleteForAll ? 'ChatList.DeleteForCurrentUser' : 'Delete';\n }\n\n return (\n <Modal\n isOpen={isOpen}\n className=\"DeleteChatModal\"\n header={renderHeader()}\n onClose={onClose}\n onCloseAnimationEnd={onCloseAnimationEnd}\n >\n {renderMessage()}\n {canDeleteForAll && (\n <Button color=\"danger\" className=\"confirm-dialog-button\" isText onClick={handleDeleteMessageForAll}>\n {contactName ? lang('ChatList.DeleteForEveryone', contactName) : lang('DeleteForAll')}\n </Button>\n )}\n <Button color=\"danger\" className=\"confirm-dialog-button\" isText onClick={handleDeleteChat}>\n {lang(renderActionText())}\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, { chat }): StateProps => {\n const isPrivateChat = isChatPrivate(chat.id);\n const isChatWithSelf = selectIsChatWithSelf(global, chat.id);\n const canDeleteForAll = (isPrivateChat && !isChatWithSelf);\n const contactName = chat && isChatPrivate(chat.id)\n ? getUserFirstOrLastName(selectUser(global, getPrivateChatUserId(chat)!))\n : undefined;\n\n return {\n isPrivateChat,\n isChatWithSelf,\n isChannel: isChatChannel(chat),\n isBasicGroup: isChatBasicGroup(chat),\n isSuperGroup: isChatSuperGroup(chat),\n canDeleteForAll,\n contactName,\n };\n },\n (setGlobal, actions): DispatchProps => pick(actions, ['leaveChannel', 'deleteHistory', 'deleteChannel']),\n)(DeleteChatModal));\n","import React, { FC, useRef } from '../../lib/teact/teact';\n\nimport useShowTransition from '../../hooks/useShowTransition';\nimport usePrevious from '../../hooks/usePrevious';\nimport buildClassName from '../../util/buildClassName';\n\ntype ChildrenFn = () => any;\n\ntype OwnProps = {\n isOpen: boolean;\n isCustom?: boolean;\n id?: string;\n className?: string;\n onClick?: (e: React.MouseEvent<HTMLElement, MouseEvent>) => void;\n children: ChildrenFn;\n};\n\nconst ShowTransition: FC<OwnProps> = ({\n isOpen, isCustom, id, className, onClick, children,\n}) => {\n const { shouldRender, transitionClassNames } = useShowTransition(\n isOpen, undefined, undefined, isCustom ? false : undefined,\n );\n const prevIsOpen = usePrevious(isOpen);\n const prevChildren = usePrevious(children);\n const fromChildrenRef = useRef<ChildrenFn>();\n\n if (prevIsOpen && !isOpen) {\n fromChildrenRef.current = prevChildren;\n }\n\n return (\n shouldRender && (\n <div id={id} className={buildClassName(className, transitionClassNames)} onClick={onClick}>\n {isOpen ? children() : fromChildrenRef.current!()}\n </div>\n )\n );\n};\n\nexport default ShowTransition;\n","/*\n * Thanks to Ace Monkey for this mind-blowing patch.\n */\n\nexport function patchSafariProgressiveAudio(audioEl: HTMLAudioElement) {\n if (audioEl.dataset.patchedForSafari) {\n return;\n }\n\n audioEl.addEventListener('play', () => {\n const t = audioEl.currentTime;\n\n function onProgress() {\n if (!audioEl.buffered.length) {\n return;\n }\n\n audioEl.dataset.patchForSafariInProgress = 'true';\n audioEl.currentTime = audioEl.duration - 1;\n audioEl.addEventListener('progress', () => {\n delete audioEl.dataset.patchForSafariInProgress;\n audioEl.currentTime = t;\n if (audioEl.paused) {\n audioEl.play();\n }\n }, { once: true });\n\n audioEl.removeEventListener('progress', onProgress);\n }\n\n audioEl.addEventListener('progress', onProgress);\n }, { once: true });\n\n audioEl.dataset.patchedForSafari = 'true';\n}\n\nexport function isSafariPatchInProgress(audioEl: HTMLAudioElement) {\n return Boolean(audioEl.dataset.patchForSafariInProgress);\n}\n","import { useLayoutEffect } from '../lib/teact/teact';\nimport usePrevious from './usePrevious';\n\nexport default <T extends any[], PT = T>(cb: (args: PT) => void, dependencies: T) => {\n const prevDeps = usePrevious<T>(dependencies);\n return useLayoutEffect(() => {\n // @ts-ignore (workaround for \"could be instantiated with a different subtype\" issue)\n cb(prevDeps || []);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, dependencies);\n};\n","import React, {\n FC, useCallback, useEffect, useState, memo, useRef,\n} from '../../lib/teact/teact';\n\nimport { ApiMessage } from '../../api/types';\n\nimport { getDocumentExtension, getDocumentHasPreview } from './helpers/documentInfo';\nimport { getMediaTransferState, getMessageMediaHash, getMessageMediaThumbDataUri } from '../../modules/helpers';\nimport { ObserveFn, useIsIntersecting } from '../../hooks/useIntersectionObserver';\nimport useMediaWithDownloadProgress from '../../hooks/useMediaWithDownloadProgress';\nimport useMedia from '../../hooks/useMedia';\nimport download from '../../util/download';\n\nimport File from './File';\n\ntype OwnProps = {\n message: ApiMessage;\n observeIntersection?: ObserveFn;\n smaller?: boolean;\n isSelected?: boolean;\n isSelectable?: boolean;\n uploadProgress?: number;\n withDate?: boolean;\n datetime?: number;\n className?: string;\n sender?: string;\n onCancelUpload?: () => void;\n onDateClick?: (messageId: number, chatId: number) => void;\n};\n\nconst Document: FC<OwnProps> = ({\n message,\n observeIntersection,\n smaller,\n uploadProgress,\n withDate,\n datetime,\n className,\n sender,\n isSelected,\n isSelectable,\n onCancelUpload,\n onDateClick,\n}) => {\n // eslint-disable-next-line no-null/no-null\n const ref = useRef<HTMLDivElement>(null);\n\n const document = message.content.document!;\n const extension = getDocumentExtension(document) || '';\n const { fileName, size, timestamp } = document;\n\n const isIntersecting = useIsIntersecting(ref, observeIntersection);\n\n const [isDownloadAllowed, setIsDownloadAllowed] = useState(false);\n const {\n mediaData, downloadProgress,\n } = useMediaWithDownloadProgress(getMessageMediaHash(message, 'download'), !isDownloadAllowed);\n const {\n isUploading, isTransferring, transferProgress,\n } = getMediaTransferState(message, uploadProgress || downloadProgress, isDownloadAllowed);\n\n const hasPreview = getDocumentHasPreview(document);\n const thumbDataUri = hasPreview ? getMessageMediaThumbDataUri(message) : undefined;\n const localBlobUrl = hasPreview ? document.previewBlobUrl : undefined;\n const previewData = useMedia(getMessageMediaHash(message, 'pictogram'), !isIntersecting);\n\n const handleClick = useCallback(() => {\n if (isUploading) {\n if (onCancelUpload) {\n onCancelUpload();\n }\n } else {\n setIsDownloadAllowed((isAllowed) => !isAllowed);\n }\n }, [isUploading, onCancelUpload]);\n\n const handleDateClick = useCallback(() => {\n onDateClick!(message.id, message.chatId);\n }, [onDateClick, message.id, message.chatId]);\n\n useEffect(() => {\n if (isDownloadAllowed && mediaData) {\n download(mediaData, fileName);\n setIsDownloadAllowed(false);\n }\n }, [fileName, mediaData, isDownloadAllowed]);\n\n return (\n <File\n ref={ref}\n name={fileName}\n extension={extension}\n size={size}\n timestamp={withDate ? datetime || timestamp : undefined}\n thumbnailDataUri={thumbDataUri}\n previewData={localBlobUrl || previewData}\n smaller={smaller}\n isTransferring={isTransferring}\n isUploading={isUploading}\n transferProgress={transferProgress}\n className={className}\n sender={sender}\n isSelectable={isSelectable}\n isSelected={isSelected}\n onClick={handleClick}\n onDateClick={onDateClick ? handleDateClick : undefined}\n />\n );\n};\n\nexport default memo(Document);\n","import React, { FC, memo } from '../../lib/teact/teact';\nimport { OwnProps } from './StickerSetModal';\nimport { Bundles } from '../../util/moduleLoader';\n\nimport useModuleLoader from '../../hooks/useModuleLoader';\n\nconst StickerSetModalAsync: FC<OwnProps> = (props) => {\n const { isOpen } = props;\n const StickerSetModal = useModuleLoader(Bundles.Extra, 'StickerSetModal', !isOpen);\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return StickerSetModal ? <StickerSetModal {...props} /> : undefined;\n};\n\nexport default memo(StickerSetModalAsync);\n","import { useEffect, useRef } from '../lib/teact/teact';\n\nimport fastBlur from '../lib/fastBlur';\nimport useForceUpdate from './useForceUpdate';\nimport { IS_CANVAS_FILTER_SUPPORTED } from '../util/environment';\n\nconst RADIUS = 2;\nconst ITERATIONS = 2;\n\nexport default function useCanvasBlur(dataUri?: string, isDisabled = false, withRaf?: boolean) {\n // eslint-disable-next-line no-null/no-null\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const forceUpdate = useForceUpdate();\n\n useEffect(() => {\n const canvas = canvasRef.current;\n\n if (!dataUri || !canvas || isDisabled) {\n return;\n }\n\n const img = new Image();\n\n const processBlur = () => {\n canvas.width = img.width;\n canvas.height = img.height;\n\n const ctx = canvas.getContext('2d', { alpha: false })!;\n\n if (IS_CANVAS_FILTER_SUPPORTED) {\n ctx.filter = `blur(${RADIUS}px)`;\n }\n\n ctx.drawImage(img, -RADIUS * 2, -RADIUS * 2, canvas.width + RADIUS * 4, canvas.height + RADIUS * 4);\n\n if (!IS_CANVAS_FILTER_SUPPORTED) {\n fastBlur(ctx, 0, 0, canvas.width, canvas.height, RADIUS, ITERATIONS);\n }\n };\n\n img.onload = () => {\n if (withRaf) {\n requestAnimationFrame(processBlur);\n } else {\n processBlur();\n }\n };\n\n img.src = dataUri;\n }, [canvasRef, dataUri, forceUpdate, isDisabled, withRaf]);\n\n return canvasRef;\n}\n","/* eslint-disable no-nested-ternary */\n/* eslint-disable no-bitwise */\n/* eslint-disable no-multi-assign */\n/* eslint-disable no-cond-assign */\n/* eslint-disable no-param-reassign */\n/* eslint-disable prefer-const */\n/* eslint-disable eqeqeq */\n\n/*\nSuperfast Blur - a fast Box Blur For Canvas\n\nVersion: 0.5\nAuthor: Mario Klingemann\nContact: mario@quasimondo.com\nWebsite: http://www.quasimondo.com/BoxBlurForCanvas\nTwitter: @quasimondo\n\nIn case you find this class useful - especially in commercial projects -\nI am not totally unhappy for a small donation to my PayPal account\nmario@quasimondo.de\n\nOr support me on flattr:\nhttps://flattr.com/thing/140066/Superfast-Blur-a-pretty-fast-Box-Blur-Effect-for-CanvasJavascript\n\nCopyright (c) 2011 Mario Klingemann\n\nPermission is hereby granted, free of charge, to any person\nobtaining a copy of this software and associated documentation\nfiles (the \"Software\"), to deal in the Software without\nrestriction, including without limitation the rights to use,\ncopy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following\nconditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\nOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\nHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE.\n*/\n\n// eslint-disable-next-line max-len\nconst mul_table = [1, 57, 41, 21, 203, 34, 97, 73, 227, 91, 149, 62, 105, 45, 39, 137, 241, 107, 3, 173, 39, 71, 65, 238, 219, 101, 187, 87, 81, 151, 141, 133, 249, 117, 221, 209, 197, 187, 177, 169, 5, 153, 73, 139, 133, 127, 243, 233, 223, 107, 103, 99, 191, 23, 177, 171, 165, 159, 77, 149, 9, 139, 135, 131, 253, 245, 119, 231, 224, 109, 211, 103, 25, 195, 189, 23, 45, 175, 171, 83, 81, 79, 155, 151, 147, 9, 141, 137, 67, 131, 129, 251, 123, 30, 235, 115, 113, 221, 217, 53, 13, 51, 50, 49, 193, 189, 185, 91, 179, 175, 43, 169, 83, 163, 5, 79, 155, 19, 75, 147, 145, 143, 35, 69, 17, 67, 33, 65, 255, 251, 247, 243, 239, 59, 29, 229, 113, 111, 219, 27, 213, 105, 207, 51, 201, 199, 49, 193, 191, 47, 93, 183, 181, 179, 11, 87, 43, 85, 167, 165, 163, 161, 159, 157, 155, 77, 19, 75, 37, 73, 145, 143, 141, 35, 138, 137, 135, 67, 33, 131, 129, 255, 63, 250, 247, 61, 121, 239, 237, 117, 29, 229, 227, 225, 111, 55, 109, 216, 213, 211, 209, 207, 205, 203, 201, 199, 197, 195, 193, 48, 190, 47, 93, 185, 183, 181, 179, 178, 176, 175, 173, 171, 85, 21, 167, 165, 41, 163, 161, 5, 79, 157, 78, 154, 153, 19, 75, 149, 74, 147, 73, 144, 143, 71, 141, 140, 139, 137, 17, 135, 134, 133, 66, 131, 65, 129, 1];\n// eslint-disable-next-line max-len\nconst shg_table = [0, 9, 10, 10, 14, 12, 14, 14, 16, 15, 16, 15, 16, 15, 15, 17, 18, 17, 12, 18, 16, 17, 17, 19, 19, 18, 19, 18, 18, 19, 19, 19, 20, 19, 20, 20, 20, 20, 20, 20, 15, 20, 19, 20, 20, 20, 21, 21, 21, 20, 20, 20, 21, 18, 21, 21, 21, 21, 20, 21, 17, 21, 21, 21, 22, 22, 21, 22, 22, 21, 22, 21, 19, 22, 22, 19, 20, 22, 22, 21, 21, 21, 22, 22, 22, 18, 22, 22, 21, 22, 22, 23, 22, 20, 23, 22, 22, 23, 23, 21, 19, 21, 21, 21, 23, 23, 23, 22, 23, 23, 21, 23, 22, 23, 18, 22, 23, 20, 22, 23, 23, 23, 21, 22, 20, 22, 21, 22, 24, 24, 24, 24, 24, 22, 21, 24, 23, 23, 24, 21, 24, 23, 24, 22, 24, 24, 22, 24, 24, 22, 23, 24, 24, 24, 20, 23, 22, 23, 24, 24, 24, 24, 24, 24, 24, 23, 21, 23, 22, 23, 24, 24, 24, 22, 24, 24, 24, 23, 22, 24, 24, 25, 23, 25, 25, 23, 24, 25, 25, 24, 22, 25, 25, 25, 24, 23, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 23, 25, 23, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 24, 22, 25, 25, 23, 25, 25, 20, 24, 25, 24, 25, 25, 22, 24, 25, 24, 25, 24, 25, 25, 24, 25, 25, 25, 25, 22, 25, 25, 25, 24, 25, 24, 25, 18];\n\nexport default function boxBlurCanvasRGB(context, top_x, top_y, width, height, radius, iterations) {\n if (Number.isNaN(radius) || radius < 1) return;\n\n radius |= 0;\n\n if (Number.isNaN(iterations)) iterations = 1;\n iterations |= 0;\n if (iterations > 3) iterations = 3;\n if (iterations < 1) iterations = 1;\n\n const imageData = context.getImageData(top_x, top_y, width, height);\n\n const pixels = imageData.data;\n\n let rsum;\n let gsum;\n let bsum;\n let x;\n let y;\n let i;\n let p;\n let p1;\n let p2;\n let yp;\n let yi;\n let yw;\n let wm = width - 1;\n let hm = height - 1;\n let rad1 = radius + 1;\n\n let r = [];\n let g = [];\n let b = [];\n\n let mul_sum = mul_table[radius];\n let shg_sum = shg_table[radius];\n\n let vmin = [];\n let vmax = [];\n\n while (iterations-- > 0) {\n yw = yi = 0;\n\n for (y = 0; y < height; y++) {\n rsum = pixels[yw] * rad1;\n gsum = pixels[yw + 1] * rad1;\n bsum = pixels[yw + 2] * rad1;\n\n for (i = 1; i <= radius; i++) {\n p = yw + (((i > wm ? wm : i)) << 2);\n rsum += pixels[p++];\n gsum += pixels[p++];\n bsum += pixels[p++];\n }\n\n for (x = 0; x < width; x++) {\n r[yi] = rsum;\n g[yi] = gsum;\n b[yi] = bsum;\n\n if (y == 0) {\n vmin[x] = ((p = x + rad1) < wm ? p : wm) << 2;\n vmax[x] = ((p = x - radius) > 0 ? p << 2 : 0);\n }\n\n p1 = yw + vmin[x];\n p2 = yw + vmax[x];\n\n rsum += pixels[p1++] - pixels[p2++];\n gsum += pixels[p1++] - pixels[p2++];\n bsum += pixels[p1++] - pixels[p2++];\n\n yi++;\n }\n yw += (width << 2);\n }\n\n for (x = 0; x < width; x++) {\n yp = x;\n rsum = r[yp] * rad1;\n gsum = g[yp] * rad1;\n bsum = b[yp] * rad1;\n\n for (i = 1; i <= radius; i++) {\n yp += (i > hm ? 0 : width);\n rsum += r[yp];\n gsum += g[yp];\n bsum += b[yp];\n }\n\n yi = x << 2;\n for (y = 0; y < height; y++) {\n pixels[yi] = (rsum * mul_sum) >>> shg_sum;\n pixels[yi + 1] = (gsum * mul_sum) >>> shg_sum;\n pixels[yi + 2] = (bsum * mul_sum) >>> shg_sum;\n\n if (x == 0) {\n vmin[y] = ((p = y + rad1) < hm ? p : hm) * width;\n vmax[y] = ((p = y - radius) > 0 ? p * width : 0);\n }\n\n p1 = x + vmin[y];\n p2 = x + vmax[y];\n\n rsum += r[p1] - r[p2];\n gsum += g[p1] - g[p2];\n bsum += b[p1] - b[p2];\n\n yi += width << 2;\n }\n }\n }\n\n context.putImageData(imageData, top_x, top_y);\n}\n","import React, {\n FC, memo, useCallback, useEffect, useRef, useState,\n} from '../../../lib/teact/teact';\n\nimport { IAnchorPosition } from '../../../types';\n\nimport { EDITABLE_INPUT_ID } from '../../../config';\nimport buildClassName from '../../../util/buildClassName';\nimport captureEscKeyListener from '../../../util/captureEscKeyListener';\nimport useShowTransition from '../../../hooks/useShowTransition';\nimport useVirtualBackdrop from '../../../hooks/useVirtualBackdrop';\nimport useFlag from '../../../hooks/useFlag';\nimport useLang from '../../../hooks/useLang';\n\nimport Button from '../../ui/Button';\n\nimport './TextFormatter.scss';\n\nexport type OwnProps = {\n isOpen: boolean;\n anchorPosition?: IAnchorPosition;\n selectedRange?: Range;\n onClose: () => void;\n};\n\ninterface ISelectedTextFormats {\n bold?: boolean;\n italic?: boolean;\n underline?: boolean;\n strikethrough?: boolean;\n monospace?: boolean;\n}\n\nconst TEXT_FORMAT_BY_TAG_NAME: Record<string, keyof ISelectedTextFormats> = {\n B: 'bold',\n STRONG: 'bold',\n I: 'italic',\n EM: 'italic',\n U: 'underline',\n DEL: 'strikethrough',\n CODE: 'monospace',\n};\n\nconst TextFormatter: FC<OwnProps> = ({\n isOpen,\n anchorPosition,\n selectedRange,\n onClose,\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 linkUrlInputRef = useRef<HTMLInputElement>(null);\n const { shouldRender, transitionClassNames } = useShowTransition(isOpen);\n const [isLinkControlOpen, openLinkControl, closeLinkControl] = useFlag();\n const [linkUrl, setLinkUrl] = useState('');\n const [isEditingLink, setIsEditingLink] = useState(false);\n const [inputClassName, setInputClassName] = useState<string | undefined>();\n const [selectedTextFormats, setSelectedTextFormats] = useState<ISelectedTextFormats>({});\n\n useEffect(() => (isOpen ? captureEscKeyListener(onClose) : undefined), [isOpen, onClose]);\n useVirtualBackdrop(\n isOpen,\n containerRef,\n onClose,\n );\n\n useEffect(() => {\n if (isLinkControlOpen) {\n linkUrlInputRef.current!.focus();\n } else {\n setLinkUrl('');\n setIsEditingLink(false);\n }\n }, [isLinkControlOpen]);\n\n useEffect(() => {\n if (!shouldRender) {\n closeLinkControl();\n setSelectedTextFormats({});\n setInputClassName(undefined);\n }\n }, [closeLinkControl, shouldRender]);\n\n useEffect(() => {\n if (!isOpen || !selectedRange) {\n return;\n }\n\n const selectedFormats: ISelectedTextFormats = {};\n let { parentElement } = selectedRange.commonAncestorContainer;\n while (parentElement && parentElement.id !== EDITABLE_INPUT_ID) {\n const textFormat = TEXT_FORMAT_BY_TAG_NAME[parentElement.tagName];\n if (textFormat) {\n selectedFormats[textFormat] = true;\n }\n\n parentElement = parentElement.parentElement;\n }\n\n setSelectedTextFormats(selectedFormats);\n }, [isOpen, selectedRange, openLinkControl]);\n\n function restoreSelection() {\n if (!selectedRange) {\n return;\n }\n\n const selection = window.getSelection();\n if (selection) {\n selection.removeAllRanges();\n selection.addRange(selectedRange);\n }\n }\n\n const getSelectedText = useCallback(() => {\n if (!selectedRange) {\n return undefined;\n }\n\n return selectedRange.toString();\n }, [selectedRange]);\n\n const getSelectedElement = useCallback(() => {\n if (!selectedRange) {\n return undefined;\n }\n\n return selectedRange.commonAncestorContainer.parentElement;\n }, [selectedRange]);\n\n function updateInputStyles() {\n const input = linkUrlInputRef.current;\n if (!input) {\n return;\n }\n\n const { offsetWidth, scrollWidth, scrollLeft } = input;\n if (scrollWidth <= offsetWidth) {\n setInputClassName(undefined);\n return;\n }\n\n let className = '';\n if (scrollLeft < scrollWidth - offsetWidth) {\n className = 'mask-right';\n }\n if (scrollLeft > 0) {\n className += ' mask-left';\n }\n\n setInputClassName(className);\n }\n\n function handleLinkUrlChange(e: React.ChangeEvent<HTMLInputElement>) {\n setLinkUrl(e.target.value);\n updateInputStyles();\n }\n\n function getFormatButtonClassName(key: keyof ISelectedTextFormats) {\n if (selectedTextFormats[key]) {\n return 'active';\n }\n\n if (key === 'monospace' || key === 'strikethrough') {\n if (Object.keys(selectedTextFormats).some(\n (fKey) => fKey !== key && !!selectedTextFormats[fKey as keyof ISelectedTextFormats],\n )) {\n return 'disabled';\n }\n } else if (selectedTextFormats.monospace || selectedTextFormats.strikethrough) {\n return 'disabled';\n }\n\n return undefined;\n }\n\n const handleBoldText = useCallback(() => {\n setSelectedTextFormats((selectedFormats) => {\n // Somehow re-applying 'bold' command to already bold text doesn't work\n document.execCommand(selectedFormats.bold ? 'removeFormat' : 'bold');\n Object.keys(selectedFormats).forEach((key) => {\n if ((key === 'italic' || key === 'underline') && !!selectedFormats[key]) {\n document.execCommand(key);\n }\n });\n\n return {\n ...selectedFormats,\n bold: !selectedFormats.bold,\n };\n });\n }, []);\n\n const handleItalicText = useCallback(() => {\n document.execCommand('italic');\n setSelectedTextFormats((selectedFormats) => ({\n ...selectedFormats,\n italic: !selectedFormats.italic,\n }));\n }, []);\n\n const handleUnderlineText = useCallback(() => {\n document.execCommand('underline');\n setSelectedTextFormats((selectedFormats) => ({\n ...selectedFormats,\n underline: !selectedFormats.underline,\n }));\n }, []);\n\n const handleStrikethroughText = useCallback(() => {\n if (selectedTextFormats.strikethrough) {\n const element = getSelectedElement();\n if (\n !selectedRange\n || !element\n || element.tagName !== 'DEL'\n || !element.textContent\n ) {\n return;\n }\n\n element.replaceWith(element.textContent);\n setSelectedTextFormats((selectedFormats) => ({\n ...selectedFormats,\n strikethrough: false,\n }));\n\n return;\n }\n\n const text = getSelectedText();\n document.execCommand('insertHTML', false, `<del>${text}</del>`);\n onClose();\n }, [\n getSelectedElement, getSelectedText, onClose,\n selectedRange, selectedTextFormats.strikethrough,\n ]);\n\n const handleMonospaceText = useCallback(() => {\n if (selectedTextFormats.monospace) {\n const element = getSelectedElement();\n if (\n !selectedRange\n || !element\n || element.tagName !== 'CODE'\n || !element.textContent\n ) {\n return;\n }\n\n element.replaceWith(element.textContent);\n setSelectedTextFormats((selectedFormats) => ({\n ...selectedFormats,\n monospace: false,\n }));\n return;\n }\n\n const text = getSelectedText();\n document.execCommand('insertHTML', false, `<code class=\"text-entity-code\" dir=\"auto\">${text}</code>`);\n onClose();\n }, [\n getSelectedElement, getSelectedText, onClose,\n selectedRange, selectedTextFormats.monospace,\n ]);\n\n function handleLinkUrlConfirm() {\n const formattedLinkUrl = linkUrl.includes('://') ? linkUrl : `http://${linkUrl}`;\n\n if (isEditingLink) {\n const element = getSelectedElement();\n if (!element || element.tagName !== 'A') {\n return;\n }\n\n (element as HTMLAnchorElement).href = formattedLinkUrl;\n\n onClose();\n return;\n }\n\n const text = getSelectedText();\n restoreSelection();\n document.execCommand(\n 'insertHTML',\n false,\n `<a href=${formattedLinkUrl} class=\"text-entity-link\" dir=\"auto\">${text}</a>`,\n );\n onClose();\n }\n\n const handleKeyDown = useCallback((e: KeyboardEvent) => {\n const HANDLERS_BY_KEY_CODE: Record<string, AnyToVoidFunction> = {\n KeyK: openLinkControl,\n KeyB: handleBoldText,\n KeyU: handleUnderlineText,\n KeyI: handleItalicText,\n KeyM: handleMonospaceText,\n KeyS: handleStrikethroughText,\n };\n\n const handler = HANDLERS_BY_KEY_CODE[e.code];\n\n if (\n e.altKey\n || !(e.ctrlKey || e.metaKey)\n || !handler\n ) {\n return;\n }\n\n e.preventDefault();\n e.stopPropagation();\n handler();\n }, [\n handleBoldText, handleItalicText, handleUnderlineText,\n handleMonospaceText, handleStrikethroughText,\n openLinkControl,\n ]);\n\n useEffect(() => {\n if (isOpen) {\n document.addEventListener('keydown', handleKeyDown);\n }\n\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [isOpen, handleKeyDown]);\n\n const lang = useLang();\n\n function handleContainerKeyDown(e: React.KeyboardEvent<HTMLDivElement>) {\n if (e.key === 'Enter' && isLinkControlOpen) {\n handleLinkUrlConfirm();\n e.preventDefault();\n }\n }\n\n if (!shouldRender) {\n return undefined;\n }\n\n const className = buildClassName(\n 'TextFormatter',\n transitionClassNames,\n isLinkControlOpen && 'link-control-shown',\n );\n\n const linkUrlConfirmClassName = buildClassName(\n 'TextFormatter-link-url-confirm',\n !!linkUrl.length && 'shown',\n );\n\n const style = anchorPosition\n ? `left: ${anchorPosition.x}px; top: ${anchorPosition.y}px;--text-formatter-left: ${anchorPosition.x}px;`\n : '';\n\n return (\n <div\n ref={containerRef}\n className={className}\n // @ts-ignore Teact feature\n style={style}\n onKeyDown={handleContainerKeyDown}\n >\n <div className=\"TextFormatter-buttons\">\n <Button\n color=\"translucent\"\n ariaLabel=\"Bold text\"\n className={getFormatButtonClassName('bold')}\n onClick={handleBoldText}\n >\n <i className=\"icon-bold\" />\n </Button>\n <Button\n color=\"translucent\"\n ariaLabel=\"Italic text\"\n className={getFormatButtonClassName('italic')}\n onClick={handleItalicText}\n >\n <i className=\"icon-italic\" />\n </Button>\n <Button\n color=\"translucent\"\n ariaLabel=\"Underlined text\"\n className={getFormatButtonClassName('underline')}\n onClick={handleUnderlineText}\n >\n <i className=\"icon-underlined\" />\n </Button>\n <Button\n color=\"translucent\"\n ariaLabel=\"Strikethrough text\"\n className={getFormatButtonClassName('strikethrough')}\n onClick={handleStrikethroughText}\n >\n <i className=\"icon-strikethrough\" />\n </Button>\n <Button\n color=\"translucent\"\n ariaLabel=\"Monospace text\"\n className={getFormatButtonClassName('monospace')}\n onClick={handleMonospaceText}\n >\n <i className=\"icon-monospace\" />\n </Button>\n <div className=\"TextFormatter-divider\" />\n <Button color=\"translucent\" ariaLabel={lang('TextFormat.AddLinkTitle')} onClick={openLinkControl}>\n <i className=\"icon-link\" />\n </Button>\n </div>\n\n <div className=\"TextFormatter-link-control\">\n <div className=\"TextFormatter-buttons\">\n <Button color=\"translucent\" ariaLabel={lang('Cancel')} onClick={closeLinkControl}>\n <i className=\"icon-arrow-left\" />\n </Button>\n <div className=\"TextFormatter-divider\" />\n\n <div\n className={buildClassName('TextFormatter-link-url-input-wrapper', inputClassName)}\n >\n <input\n ref={linkUrlInputRef}\n className=\"TextFormatter-link-url-input\"\n type=\"text\"\n value={linkUrl}\n placeholder=\"Enter URL...\"\n autoComplete=\"off\"\n inputMode=\"url\"\n dir=\"auto\"\n onChange={handleLinkUrlChange}\n onScroll={updateInputStyles}\n />\n </div>\n\n <div className={linkUrlConfirmClassName}>\n <div className=\"TextFormatter-divider\" />\n <Button\n color=\"translucent\"\n ariaLabel={lang('Save')}\n className=\"color-primary\"\n onClick={handleLinkUrlConfirm}\n >\n <i className=\"icon-check\" />\n </Button>\n </div>\n </div>\n </div>\n </div>\n );\n};\n\nexport default memo(TextFormatter);\n","import React, { FC, memo, useCallback } from '../../lib/teact/teact';\n\nimport { ApiMessage } from '../../api/types';\n\nimport { formatMediaDuration } from '../../util/dateFormat';\nimport {\n getMessageMediaHash,\n getMessageMediaThumbDataUri,\n getMessageVideo,\n} from '../../modules/helpers';\nimport useMedia from '../../hooks/useMedia';\nimport useTransitionForMedia from '../../hooks/useTransitionForMedia';\n\nimport './Media.scss';\n\ntype OwnProps = {\n message: ApiMessage;\n idPrefix?: string;\n onClick?: (messageId: number, chatId: number) => void;\n};\n\nconst Media: FC<OwnProps> = ({ message, idPrefix = 'shared-media', onClick }) => {\n const handleClick = useCallback(() => {\n onClick!(message.id, message.chatId);\n }, [message.id, message.chatId, onClick]);\n\n const thumbDataUri = getMessageMediaThumbDataUri(message);\n const mediaBlobUrl = useMedia(getMessageMediaHash(message, 'pictogram'));\n const {\n shouldRenderThumb, shouldRenderFullMedia, transitionClassNames,\n } = useTransitionForMedia(mediaBlobUrl, 'slow');\n\n const video = getMessageVideo(message);\n\n return (\n <div id={`${idPrefix}${message.id}`} className=\"Media scroll-item\" onClick={onClick ? handleClick : undefined}>\n {shouldRenderThumb && (\n <img src={thumbDataUri} alt=\"\" />\n )}\n {shouldRenderFullMedia && (\n <img src={mediaBlobUrl} className={`${transitionClassNames} full-media`} alt=\"\" />\n )}\n {video && <span className=\"video-duration\">{video.isGif ? 'GIF' : formatMediaDuration(video.duration)}</span>}\n </div>\n );\n};\n\nexport default memo(Media);\n","import React, {\n FC, memo, useCallback, useEffect, useMemo, useRef, useState,\n} from '../../lib/teact/teact';\n\nimport {\n ApiAudio, ApiMessage, ApiVoice,\n} from '../../api/types';\nimport { ISettings } from '../../types';\n\nimport { IS_SINGLE_COLUMN_LAYOUT } from '../../util/environment';\nimport { formatMediaDateTime, formatMediaDuration, formatPastTimeShort } from '../../util/dateFormat';\nimport {\n getMediaDuration,\n getMediaTransferState,\n getMessageAudioCaption,\n getMessageKey,\n getMessageMediaFormat,\n getMessageMediaHash,\n isMessageLocal,\n isOwnMessage,\n} from '../../modules/helpers';\nimport { renderWaveformToDataUri } from './helpers/waveform';\nimport buildClassName from '../../util/buildClassName';\nimport renderText from './helpers/renderText';\nimport { decodeWaveform, interpolateArray } from '../../util/waveform';\nimport useMediaWithDownloadProgress from '../../hooks/useMediaWithDownloadProgress';\nimport useShowTransition from '../../hooks/useShowTransition';\nimport useBuffering from '../../hooks/useBuffering';\nimport useAudioPlayer from '../../hooks/useAudioPlayer';\nimport useMediaDownload from '../../hooks/useMediaDownload';\nimport useLang, { LangFn } from '../../hooks/useLang';\n\nimport Button from '../ui/Button';\nimport ProgressSpinner from '../ui/ProgressSpinner';\nimport Link from '../ui/Link';\n\nimport './Audio.scss';\n\ntype OwnProps = {\n theme: ISettings['theme'];\n message: ApiMessage;\n senderTitle?: string;\n uploadProgress?: number;\n target?: 'searchResult' | 'sharedMedia';\n date?: number;\n lastSyncTime?: number;\n className?: string;\n isSelectable?: boolean;\n isSelected?: boolean;\n onPlay: (messageId: number, chatId: number) => void;\n onReadMedia?: () => void;\n onCancelUpload?: () => void;\n onDateClick?: (messageId: number, chatId: number) => void;\n};\n\ninterface ISeekMethods {\n handleStartSeek: (e: React.MouseEvent<HTMLElement>) => void;\n handleSeek: (e: React.MouseEvent<HTMLElement>) => void;\n handleStopSeek: () => void;\n}\n\nconst AVG_VOICE_DURATION = 30;\nconst MIN_SPIKES = IS_SINGLE_COLUMN_LAYOUT ? 20 : 25;\nconst MAX_SPIKES = IS_SINGLE_COLUMN_LAYOUT ? 50 : 75;\n// This is needed for browsers requiring user interaction before playing.\nconst PRELOAD = true;\n\nconst Audio: FC<OwnProps> = ({\n theme,\n message,\n senderTitle,\n uploadProgress,\n target,\n date,\n lastSyncTime,\n className,\n isSelectable,\n isSelected,\n onPlay,\n onReadMedia,\n onCancelUpload,\n onDateClick,\n}) => {\n const { content: { audio, voice }, isMediaUnread } = message;\n const isVoice = Boolean(voice);\n const isSeeking = useRef<boolean>(false);\n const lang = useLang();\n\n const [isActivated, setIsActivated] = useState(false);\n const shouldDownload = (isActivated || PRELOAD) && lastSyncTime;\n\n const { mediaData, downloadProgress } = useMediaWithDownloadProgress(\n getMessageMediaHash(message, 'inline'),\n !shouldDownload,\n getMessageMediaFormat(message, 'inline'),\n );\n\n function handleForcePlay() {\n setIsActivated(true);\n onPlay(message.id, message.chatId);\n }\n\n const {\n isBuffered, bufferedProgress, bufferingHandlers, checkBuffering,\n } = useBuffering();\n\n const {\n isPlaying, playProgress, playPause, setCurrentTime, duration,\n } = useAudioPlayer(\n getMessageKey(message),\n getMediaDuration(message)!,\n mediaData,\n bufferingHandlers,\n checkBuffering,\n isActivated,\n handleForcePlay,\n isMessageLocal(message),\n );\n\n useEffect(() => {\n setIsActivated(isPlaying);\n }, [isPlaying]);\n\n const {\n isDownloadStarted,\n downloadProgress: directDownloadProgress,\n handleDownloadClick,\n } = useMediaDownload(getMessageMediaHash(message, 'download'), getMessageAudioCaption(message));\n\n const isLoadingForPlaying = isActivated && !isBuffered;\n\n const {\n isUploading, isTransferring, transferProgress,\n } = getMediaTransferState(\n message,\n isDownloadStarted ? directDownloadProgress : (uploadProgress || downloadProgress),\n isLoadingForPlaying || isDownloadStarted,\n );\n\n const {\n shouldRender: shouldRenderSpinner,\n transitionClassNames: spinnerClassNames,\n } = useShowTransition(isTransferring);\n\n const handleButtonClick = useCallback(() => {\n if (isUploading) {\n if (onCancelUpload) {\n onCancelUpload();\n }\n\n return;\n }\n\n if (!isPlaying) {\n onPlay(message.id, message.chatId);\n }\n\n setIsActivated(!isActivated);\n playPause();\n }, [isPlaying, isUploading, message.id, message.chatId, onCancelUpload, onPlay, playPause, isActivated]);\n\n useEffect(() => {\n if (isPlaying && onReadMedia && isMediaUnread) {\n onReadMedia();\n }\n }, [isPlaying, isMediaUnread, onReadMedia]);\n\n const handleSeek = useCallback((e: React.MouseEvent<HTMLElement>) => {\n if (isSeeking.current) {\n const seekBar = e.currentTarget.closest('.seekline,.waveform');\n if (seekBar) {\n const { width, left } = seekBar.getBoundingClientRect();\n setCurrentTime(duration * ((e.clientX - left) / width));\n }\n }\n }, [duration, setCurrentTime]);\n\n const handleStartSeek = useCallback((e: React.MouseEvent<HTMLElement>) => {\n isSeeking.current = true;\n handleSeek(e);\n }, [handleSeek]);\n\n const handleStopSeek = useCallback(() => {\n isSeeking.current = false;\n }, []);\n\n const handleDateClick = useCallback(() => {\n onDateClick!(message.id, message.chatId);\n }, [onDateClick, message.id, message.chatId]);\n\n function getFirstLine() {\n if (isVoice) {\n return senderTitle || 'Voice';\n }\n\n const { title, fileName } = audio!;\n\n return title || fileName;\n }\n\n function getSecondLine() {\n if (isVoice) {\n return formatMediaDuration(voice!.duration);\n }\n\n const { performer } = audio!;\n\n return (\n <>\n {performer && renderText(performer)}\n {performer && senderTitle && <span>•</span>}\n {senderTitle && renderText(senderTitle)}\n </>\n );\n }\n\n const seekHandlers = { handleStartSeek, handleSeek, handleStopSeek };\n const isOwn = isOwnMessage(message);\n const renderedWaveform = useMemo(\n () => voice && renderWaveform(voice, playProgress, isOwn, seekHandlers, theme),\n [voice, playProgress, isOwn, seekHandlers, theme],\n );\n\n const fullClassName = buildClassName(\n 'Audio media-inner',\n className,\n isOwn && !target && 'own',\n target && 'bigger',\n isSelected && 'audio-is-selected',\n );\n\n const buttonClassNames = ['toggle-play'];\n if (isLoadingForPlaying) {\n buttonClassNames.push('loading');\n } else if (isPlaying) {\n buttonClassNames.push('pause');\n } else if (!isPlaying) {\n buttonClassNames.push('play');\n }\n\n const showSeekline = isPlaying || (playProgress > 0 && playProgress < 1);\n const contentClassName = buildClassName('content', showSeekline && 'with-seekline');\n\n function renderSearchResult() {\n return (\n <>\n <div className={contentClassName}>\n <div className=\"content-row\">\n <p className=\"title\" dir=\"auto\">{renderText(getFirstLine())}</p>\n\n <div className=\"message-date\">\n {date && (\n <Link\n className=\"date\"\n onClick={handleDateClick}\n >\n {formatPastTimeShort(lang, date * 1000)}\n </Link>\n )}\n </div>\n </div>\n\n {showSeekline && renderSeekline(playProgress, bufferedProgress, seekHandlers)}\n {!showSeekline && (\n <p className=\"duration\" dir=\"auto\">\n {playProgress > 0 ? `${formatMediaDuration(duration * playProgress)} / ` : undefined}\n {getSecondLine()}\n </p>\n )}\n </div>\n </>\n );\n }\n\n return (\n <div className={fullClassName} dir={lang.isRtl ? 'rtl' : undefined}>\n {isSelectable && (\n <div className=\"message-select-control\">\n {isSelected && <i className=\"icon-select\" />}\n </div>\n )}\n <Button\n round\n ripple={!IS_SINGLE_COLUMN_LAYOUT}\n size={target ? 'smaller' : 'tiny'}\n className={buttonClassNames.join(' ')}\n ariaLabel={isPlaying ? 'Pause audio' : 'Play audio'}\n onClick={handleButtonClick}\n isRtl={lang.isRtl}\n >\n <i className=\"icon-play\" />\n <i className=\"icon-pause\" />\n </Button>\n {shouldRenderSpinner && (\n <div className={buildClassName('media-loading', spinnerClassNames, isLoadingForPlaying && 'interactive')}>\n <ProgressSpinner\n progress={transferProgress}\n transparent\n size={target ? 'm' : 's'}\n onClick={isLoadingForPlaying ? handleButtonClick : undefined}\n noCross={!isLoadingForPlaying}\n />\n </div>\n )}\n {audio && (\n <Button\n round\n size=\"tiny\"\n className=\"download-button\"\n ariaLabel={isDownloadStarted ? 'Cancel download' : 'Download'}\n onClick={handleDownloadClick}\n >\n <i className={isDownloadStarted ? 'icon-close' : 'icon-arrow-down'} />\n </Button>\n )}\n {target === 'searchResult' && renderSearchResult()}\n {target !== 'searchResult' && audio && renderAudio(\n lang, audio, isPlaying, playProgress, bufferedProgress, seekHandlers, date,\n onDateClick ? handleDateClick : undefined,\n )}\n {target !== 'searchResult' && voice && renderVoice(voice, renderedWaveform, isMediaUnread)}\n </div>\n );\n};\n\nfunction renderAudio(\n lang: LangFn,\n audio: ApiAudio,\n isPlaying: boolean,\n playProgress: number,\n bufferedProgress: number,\n seekHandlers: ISeekMethods,\n date?: number,\n handleDateClick?: NoneToVoidFunction,\n) {\n const {\n title, performer, duration, fileName,\n } = audio;\n const showSeekline = isPlaying || (playProgress > 0 && playProgress < 1);\n\n return (\n <div className=\"content\">\n <p className=\"title\" dir=\"auto\">{renderText(title || fileName)}</p>\n {showSeekline && renderSeekline(playProgress, bufferedProgress, seekHandlers)}\n {!showSeekline && (\n <div className=\"meta\" dir=\"auto\">\n <span className=\"performer\">{renderText(performer || 'Unknown')}</span>\n {date && (\n <>\n {' '}\n •\n {' '}\n <Link className=\"date\" onClick={handleDateClick}>{formatMediaDateTime(lang, date * 1000)}</Link>\n </>\n )}\n </div>\n )}\n <p className=\"duration\" dir=\"auto\">\n {playProgress > 0 ? `${formatMediaDuration(duration * playProgress)} / ` : undefined}\n {formatMediaDuration(duration)}\n </p>\n </div>\n );\n}\n\nfunction renderVoice(voice: ApiVoice, renderedWaveform: any, isMediaUnread?: boolean) {\n return (\n <div className=\"content\">\n {renderedWaveform}\n <p className=\"voice-duration\" dir=\"auto\">\n {formatMediaDuration(voice.duration)}\n {isMediaUnread && <span>•</span>}\n </p>\n </div>\n );\n}\n\nfunction renderWaveform(\n voice: ApiVoice,\n playProgress = 0,\n isOwn = false,\n { handleStartSeek, handleSeek, handleStopSeek }: ISeekMethods,\n theme: ISettings['theme'],\n) {\n const { waveform, duration } = voice;\n\n if (!waveform) {\n return undefined;\n }\n\n const fillColor = theme === 'dark' ? '#494B75' : '#CBCBCB';\n const fillOwnColor = theme === 'dark' ? '#C0BBED' : '#B0DEA6';\n const progressFillColor = theme === 'dark' ? '#868DF5' : '#54a3e6';\n const progressFillOwnColor = theme === 'dark' ? '#FFFFFF' : '#53ad53';\n const durationFactor = Math.min(duration / AVG_VOICE_DURATION, 1);\n const spikesCount = Math.round(MIN_SPIKES + (MAX_SPIKES - MIN_SPIKES) * durationFactor);\n const decodedWaveform = decodeWaveform(new Uint8Array(waveform));\n const { data: spikes, peak } = interpolateArray(decodedWaveform, spikesCount);\n const { src, width, height } = renderWaveformToDataUri(spikes, playProgress, {\n peak,\n fillStyle: isOwn ? fillOwnColor : fillColor,\n progressFillStyle: isOwn ? progressFillOwnColor : progressFillColor,\n });\n\n return (\n // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions\n <img\n src={src}\n alt=\"\"\n width={width}\n height={height}\n className=\"waveform\"\n draggable={false}\n onMouseDown={handleStartSeek}\n onMouseMove={handleSeek}\n onMouseUp={handleStopSeek}\n />\n );\n}\n\nfunction renderSeekline(\n playProgress: number,\n bufferedProgress: number,\n { handleStartSeek, handleSeek, handleStopSeek }: ISeekMethods,\n) {\n return (\n <div\n className=\"seekline no-selection\"\n onMouseDown={handleStartSeek}\n onMouseMove={handleSeek}\n onMouseUp={handleStopSeek}\n >\n <span className=\"seekline-buffered-progress\">\n <i\n // @ts-ignore\n style={`transform: translateX(${bufferedProgress * 100}%)`}\n />\n </span>\n <span className=\"seekline-play-progress\">\n <i\n // @ts-ignore\n style={`transform: translateX(${playProgress * 100}%)`}\n />\n </span>\n <span className=\"seekline-thumb\">\n <i\n // @ts-ignore\n style={`transform: translateX(${playProgress * 100}%)`}\n />\n </span>\n </div>\n );\n}\n\nexport default memo(Audio);\n","/* eslint-disable no-bitwise */\n\n// eslint-disable-next-line max-len\n// Ref: https://github.com/telegramdesktop/tdesktop/blob/0743e71ab6b928d2ee5bae1aed991849b1e2b291/Telegram/SourceFiles/data/data_document.cpp#L1018\nexport function decodeWaveform(encoded5bit: Uint8Array) {\n const bitsCount = encoded5bit.length * 8;\n const valuesCount = Math.floor(bitsCount / 5);\n if (!valuesCount) {\n return [];\n }\n\n // Read each 5 bit of encoded5bit as 0-31 unsigned char.\n // We count the index of the byte in which the desired 5-bit sequence starts.\n // And then we read a uint16 starting from that byte to guarantee to get all of those 5 bits.\n //\n // BUT! if it is the last byte we have, we're not allowed to read a uint16 starting with it.\n // Because it will be an overflow (we'll access one byte after the available memory).\n // We see, that only the last 5 bits could start in the last available byte and be problematic.\n // So we read in a general way all the entries in a general way except the last one.\n const result = Array(valuesCount);\n const bitsData = encoded5bit;\n for (let i = 0, l = valuesCount - 1; i !== l; ++i) {\n const byteIndex = Math.floor((i * 5) / 8);\n const bitShift = Math.floor((i * 5) % 8);\n const value = bitsData[byteIndex] + (bitsData[byteIndex + 1] << 8);\n result[i] = ((value >> bitShift) & 0x1F);\n }\n const lastByteIndex = Math.floor(((valuesCount - 1) * 5) / 8);\n const lastBitShift = Math.floor(((valuesCount - 1) * 5) % 8);\n const lastValue = bitsData[lastByteIndex] + (bitsData[lastByteIndex + 1] << 8);\n result[valuesCount - 1] = (lastValue >> lastBitShift) & 0x1F;\n\n return result;\n}\n\nexport function interpolateArray(data: number[], fitCount: number) {\n let peak = 0;\n const newData = new Array(fitCount);\n const springFactor = data.length / fitCount;\n const leftFiller = data[0];\n const rightFiller = data[data.length - 1];\n for (let i = 0; i < fitCount; i++) {\n const idx = Math.floor(i * springFactor);\n const val = ((data[idx - 1] ?? leftFiller) + (data[idx] ?? leftFiller) + (data[idx + 1] ?? rightFiller)) / 3;\n newData[i] = val;\n if (peak < val) {\n peak = val;\n }\n }\n return { data: newData, peak };\n}\n","type IWaveformProps = {\n peak: number;\n fillStyle: string;\n progressFillStyle: string;\n};\n\nconst SPIKE_WIDTH = 2;\nconst SPIKE_STEP = 4;\nconst SPIKE_RADIUS = 1;\nconst HEIGHT = 23;\n\nexport function renderWaveformToDataUri(\n spikes: number[],\n progress: number,\n {\n peak, fillStyle, progressFillStyle,\n }: IWaveformProps,\n) {\n const width = spikes.length * SPIKE_STEP;\n const height = HEIGHT;\n\n const canvas = document.createElement('canvas');\n canvas.width = width * 2;\n canvas.height = height * 2;\n canvas.style.width = `${width}px`;\n canvas.style.height = `${height}px`;\n\n const ctx = canvas.getContext('2d')!;\n ctx.scale(2, 2);\n\n spikes.forEach((item, i) => {\n ctx.globalAlpha = (i / spikes.length >= progress) ? 0.5 : 1;\n ctx.fillStyle = progress > i / spikes.length ? progressFillStyle : fillStyle;\n const spikeHeight = Math.max(2, HEIGHT * (item / Math.max(1, peak)));\n roundedRectangle(ctx, i * SPIKE_STEP, height, SPIKE_WIDTH, spikeHeight, SPIKE_RADIUS);\n ctx.fill();\n });\n\n return {\n src: canvas.toDataURL(),\n width,\n height,\n };\n}\n\nfunction roundedRectangle(\n ctx: CanvasRenderingContext2D, x: number, y: number, width: number, height: number, radius: number,\n) {\n if (width < 2 * radius) {\n radius = width / 2;\n }\n if (height < 2 * radius) {\n radius = height / 2;\n }\n\n ctx.beginPath();\n ctx.moveTo(x + radius, y);\n ctx.arcTo(x + width, y, x + width, y - height, radius);\n ctx.arcTo(x + width, y - height, x, y - height, radius);\n ctx.arcTo(x, y - height, x, y, radius);\n ctx.arcTo(x, y, x + width, y, radius);\n ctx.closePath();\n}\n","import React, {\n FC, useLayoutEffect, useRef, memo,\n} from '../../lib/teact/teact';\n\nimport buildClassName from '../../util/buildClassName';\nimport renderText from '../common/helpers/renderText';\n\nimport './Tab.scss';\n\ntype OwnProps = {\n className?: string;\n title: string;\n active?: boolean;\n badgeCount?: number;\n isBadgeActive?: boolean;\n previousActiveTab?: number;\n onClick: (arg: number) => void;\n clickArg: number;\n};\n\nconst Tab: FC<OwnProps> = ({\n className,\n title,\n active,\n badgeCount,\n isBadgeActive,\n previousActiveTab,\n onClick,\n clickArg,\n}) => {\n // eslint-disable-next-line no-null/no-null\n const tabRef = useRef<HTMLButtonElement>(null);\n\n useLayoutEffect(() => {\n if (!active || previousActiveTab === undefined) {\n return;\n }\n\n const tab = tabRef.current!;\n const indicator = tab.querySelector('i')!;\n const currentIndicator = tab.parentElement!.children[previousActiveTab].querySelector('i')!;\n\n currentIndicator.classList.remove('animate');\n indicator.classList.remove('animate');\n\n // We move and resize our indicator so it repeats the position and size of the previous one.\n const shiftLeft = currentIndicator.parentElement!.offsetLeft - indicator.parentElement!.offsetLeft;\n const scaleFactor = currentIndicator.clientWidth / indicator.clientWidth;\n indicator.style.transform = `translate3d(${shiftLeft}px, 0, 0) scale3d(${scaleFactor}, 1, 1)`;\n\n // 3 AFs needed here to synchronize animations with Transition component\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n // Now we remove the transform to let it animate to its own position and size.\n indicator.classList.add('animate');\n indicator.style.transform = 'none';\n });\n });\n });\n }, [active, previousActiveTab]);\n\n return (\n <button\n type=\"button\"\n className={buildClassName('Tab', className, active && 'active')}\n onClick={() => onClick(clickArg)}\n ref={tabRef}\n >\n <span>\n {renderText(title)}\n {!!badgeCount && (\n <span className={buildClassName('badge', isBadgeActive && 'active')}>{badgeCount}</span>\n )}\n <i />\n </span>\n </button>\n );\n};\n\nexport default memo(Tab);\n","import React, {\n FC, memo, useRef, useEffect,\n} from '../../lib/teact/teact';\n\nimport fastSmoothScrollHorizontal from '../../util/fastSmoothScrollHorizontal';\nimport usePrevious from '../../hooks/usePrevious';\nimport useHorizontalScroll from '../../hooks/useHorizontalScroll';\nimport useLang from '../../hooks/useLang';\n\nimport Tab from './Tab';\n\nimport './TabList.scss';\n\nexport type TabWithProperties = {\n title: string;\n badgeCount?: number;\n isBadgeActive?: boolean;\n};\n\ntype OwnProps = {\n tabs: readonly TabWithProperties[];\n activeTab: number;\n big?: boolean;\n onSwitchTab: (index: number) => void;\n};\n\nconst TAB_SCROLL_THRESHOLD_PX = 16;\n\nconst TabList: FC<OwnProps> = ({\n tabs, activeTab, big, onSwitchTab,\n}) => {\n // eslint-disable-next-line no-null/no-null\n const containerRef = useRef<HTMLDivElement>(null);\n const previousActiveTab = usePrevious(activeTab);\n\n useHorizontalScroll(containerRef.current);\n\n // Scroll container to place active tab in the center\n useEffect(() => {\n const container = containerRef.current!;\n if (container.scrollWidth <= container.offsetWidth) {\n return;\n }\n\n const activeTabElement = container.querySelector('.Tab.active') as HTMLElement | null;\n if (activeTabElement) {\n const newLeft = activeTabElement.offsetLeft - (container.offsetWidth / 2) + (activeTabElement.offsetWidth / 2);\n\n // Prevent scrolling by only a couple of pixels, which doesn't look smooth\n if (Math.abs(newLeft - container.scrollLeft) < TAB_SCROLL_THRESHOLD_PX) {\n return;\n }\n\n fastSmoothScrollHorizontal(container, newLeft);\n }\n }, [activeTab]);\n\n const lang = useLang();\n\n return (\n <div\n className={`TabList no-selection no-scrollbar ${big ? 'big' : ''}`}\n ref={containerRef}\n dir={lang.isRtl ? 'rtl' : undefined}\n >\n {tabs.map((tab, i) => (\n <Tab\n key={tab.title}\n title={lang(tab.title)}\n active={i === activeTab}\n badgeCount={tab.badgeCount}\n isBadgeActive={tab.isBadgeActive}\n previousActiveTab={previousActiveTab}\n onClick={onSwitchTab}\n clickArg={i}\n />\n ))}\n </div>\n );\n};\n\nexport default memo(TabList);\n","import { ApiError } from '../api/types';\n\nconst READABLE_ERROR_MESSAGES: Record<string, string> = {\n CHAT_RESTRICTED: 'You can\\'t send messages in this chat, you were restricted',\n CHAT_WRITE_FORBIDDEN: 'You can\\'t write in this chat',\n CHAT_SEND_POLL_FORBIDDEN: 'You can\\'t create polls in this chat',\n CHAT_SEND_STICKERS_FORBIDDEN: 'You can\\'t send stickers in this chat',\n CHAT_SEND_GIFS_FORBIDDEN: 'You can\\'t send gifs in this chat',\n CHAT_SEND_MEDIA_FORBIDDEN: 'You can\\'t send media in this chat',\n CHAT_LINK_EXISTS: 'The chat is public, you can\\'t hide the history to new users',\n // eslint-disable-next-line max-len\n SLOWMODE_WAIT_X: 'Slowmode is enabled in this chat: you must wait for the specified number of seconds before sending another message to the chat.',\n USER_BANNED_IN_CHANNEL: 'You\\'re banned from sending messages in supergroups / channels',\n USER_IS_BLOCKED: 'You were blocked by this user',\n YOU_BLOCKED_USER: 'You blocked this user',\n IMAGE_PROCESS_FAILED: 'Failure while processing image',\n MEDIA_EMPTY: 'The provided media object is invalid',\n MEDIA_INVALID: 'Media invalid',\n PHOTO_EXT_INVALID: 'The extension of the photo is invalid',\n PHOTO_INVALID_DIMENSIONS: 'The photo dimensions are invalid',\n PHOTO_SAVE_FILE_INVALID: 'Internal issues, try again later',\n // eslint-disable-next-line max-len\n MESSAGE_DELETE_FORBIDDEN: 'You can\\'t delete one of the messages you tried to delete, most likely because it is a service message.',\n MESSAGE_POLL_CLOSED: 'Poll closed',\n MESSAGE_EDIT_TIME_EXPIRED: 'You can\\'t edit this message anymore.',\n CHAT_ADMIN_REQUIRED: 'You must be an admin in this chat to do this',\n PINNED_DIALOGS_TOO_MUCH: 'Sorry, you can only pin 5 chats to the top',\n DIALOG_FILTERS_TOO_MUCH: 'Sorry, you can\\'t have more than 10 folders',\n CHANNEL_PRIVATE: 'This channel is private',\n MEDIA_CAPTION_TOO_LONG: 'The provided caption is too long',\n ADDRESS_STREET_LINE1_INVALID: 'The address you provided is not valid',\n ADDRESS_STREET_LINE2_INVALID: 'The address you provided is not valid',\n ADDRESS_CITY_INVALID: 'The city you provided is not valid',\n ADDRESS_COUNTRY_INVALID: 'The country you provided is not valid',\n ADDRESS_POSTCODE_INVALID: 'The postcode you provided is not valid',\n ADDRESS_STATE_INVALID: 'The state you provided is not valid',\n REQ_INFO_NAME_INVALID: 'The name you provided is not valid',\n REQ_INFO_PHONE_INVALID: 'The phone you provided is not valid',\n REQ_INFO_EMAIL_INVALID: 'The email you provided is not valid',\n // TODO Bring back after fixing the weird bug\n // CHANNEL_INVALID: 'An error occurred. Please try again later',\n LINK_NOT_MODIFIED: 'This discussion is already linked to the channel',\n\n // Non-API errors\n SERVICE_WORKER_DISABLED: 'Service Worker is disabled. Please reload the page without holding <Shift> key.',\n // eslint-disable-next-line max-len\n CAPTION_TOO_LONG_PLEASE_REMOVE_CHARACTERS: 'The provided caption is too long. Please remove {EXTRA_CHARS_COUNT} character{PLURAL_S}.',\n // eslint-disable-next-line max-len\n FRESH_RESET_AUTHORISATION_FORBIDDEN: 'You can’t logout other sessions if less than 24 hours have passed since you logged on the current session',\n\n BOTS_TOO_MUCH: 'There are too many bots in this chat/channel',\n BOT_GROUPS_BLOCKED: 'This bot can\\'t be added to groups',\n USERS_TOO_MUCH: 'The maximum number of users has been exceeded',\n USER_CHANNELS_TOO_MUCH: 'One of the users you tried to add is already in too many channels/supergroups',\n USER_KICKED: 'This user was kicked from this supergroup/channel',\n USER_NOT_MUTUAL_CONTACT: 'The provided user is not a mutual contact',\n USER_PRIVACY_RESTRICTED: 'The user\\'s privacy settings do not allow you to do this',\n INVITE_HASH_EMPTY: 'The invite hash is empty',\n INVITE_HASH_EXPIRED: 'The invite link has expired',\n INVITE_HASH_INVALID: 'The invite hash is invalid',\n CHANNELS_TOO_MUCH: 'You have joined too many channels/supergroups',\n USER_ALREADY_PARTICIPANT: 'You already in the group',\n};\n\nexport default function getReadableErrorText(error: ApiError) {\n const { message, isSlowMode, textParams } = error;\n // Currently Telegram API doesn't return `SLOWMODE_WAIT_X` error as described in the docs\n if (isSlowMode) {\n const extraPartIndex = message.indexOf(' (caused by');\n return extraPartIndex > 0 ? message.substring(0, extraPartIndex) : message;\n }\n let errorMessage = READABLE_ERROR_MESSAGES[message];\n if (errorMessage && textParams) {\n errorMessage = Object.keys(textParams).reduce((acc, current) => {\n return acc.replace(current, textParams[current]);\n }, errorMessage as string);\n }\n return errorMessage;\n}\n","import { useMemo } from '../lib/teact/teact';\nimport { getDispatch } from '../lib/teact/teactn';\n\nimport { ApiChat, ApiUser } from '../api/types';\n\nimport {\n isChatArchived, getCanDeleteChat, isChatPrivate, isChatChannel,\n} from '../modules/helpers';\nimport useLang from './useLang';\n\nexport default ({\n chat,\n privateChatUser,\n handleDelete,\n folderId,\n isPinned,\n isMuted,\n}: {\n chat: ApiChat | undefined;\n privateChatUser: ApiUser | undefined;\n handleDelete: () => void;\n folderId?: number;\n isPinned?: boolean;\n isMuted?: boolean;\n}) => {\n const lang = useLang();\n\n const {\n toggleChatPinned,\n updateChatMutedState,\n toggleChatArchived,\n toggleChatUnread,\n } = getDispatch();\n\n return useMemo(() => {\n if (!chat) {\n return undefined;\n }\n\n const isChatWithSelf = privateChatUser && privateChatUser.isSelf;\n\n const actionUnreadMark = chat.unreadCount || chat.hasUnreadMark\n ? { title: lang('MarkAsRead'), icon: 'readchats', handler: () => toggleChatUnread({ id: chat.id }) }\n : { title: lang('MarkAsUnread'), icon: 'unread', handler: () => toggleChatUnread({ id: chat.id }) };\n\n const actionPin = isPinned\n ? {\n title: lang('UnpinFromTop'),\n icon: 'unpin',\n handler: () => toggleChatPinned({ id: chat.id, folderId }),\n }\n : { title: lang('PinToTop'), icon: 'pin', handler: () => toggleChatPinned({ id: chat.id, folderId }) };\n\n const actionMute = isMuted\n ? {\n title: lang('ChatList.Unmute'),\n icon: 'unmute',\n handler: () => updateChatMutedState({ chatId: chat.id, isMuted: false }),\n }\n : {\n title: lang('ChatList.Mute'),\n icon: 'mute',\n handler: () => updateChatMutedState({ chatId: chat.id, isMuted: true }),\n };\n\n const actionArchive = isChatArchived(chat)\n ? { title: lang('Unarchive'), icon: 'unarchive', handler: () => toggleChatArchived({ id: chat.id }) }\n : { title: lang('Archive'), icon: 'archive', handler: () => toggleChatArchived({ id: chat.id }) };\n\n const actionDelete = {\n title: isChatPrivate(chat.id)\n ? lang('Delete')\n : lang(getCanDeleteChat(chat)\n ? 'DeleteChat'\n : (isChatChannel(chat) ? 'LeaveChannel' : 'Group.LeaveGroup')),\n icon: 'delete',\n destructive: true,\n handler: handleDelete,\n };\n\n return [\n actionUnreadMark,\n actionPin,\n ...(!isChatWithSelf ? [\n actionMute,\n actionArchive,\n ] : []),\n actionDelete,\n ];\n }, [\n chat, privateChatUser, lang, isPinned, handleDelete, toggleChatUnread, toggleChatPinned, folderId,\n updateChatMutedState, toggleChatArchived, isMuted,\n ]);\n};\n","import React, { FC, memo } from '../../lib/teact/teact';\n\nimport { ApiMessage, ApiMessageOutgoingStatus } from '../../api/types';\n\nimport { formatPastTimeShort } from '../../util/dateFormat';\nimport useLang from '../../hooks/useLang';\n\nimport MessageOutgoingStatus from './MessageOutgoingStatus';\n\nimport './LastMessageMeta.scss';\n\ntype OwnProps = {\n message: ApiMessage;\n outgoingStatus?: ApiMessageOutgoingStatus;\n};\n\nconst LastMessageMeta: FC<OwnProps> = ({ message, outgoingStatus }) => {\n const lang = useLang();\n return (\n <div className=\"LastMessageMeta\">\n {outgoingStatus && (\n <MessageOutgoingStatus status={outgoingStatus} />\n )}\n <span className=\"time\">{formatPastTimeShort(lang, message.date * 1000)}</span>\n </div>\n );\n};\n\nexport default memo(LastMessageMeta);\n","import React, { FC, memo } from '../../lib/teact/teact';\n\nimport { ApiMessageOutgoingStatus } from '../../api/types';\n\nimport Transition from '../ui/Transition';\n\nimport './MessageOutgoingStatus.scss';\n\ntype OwnProps = {\n status: ApiMessageOutgoingStatus;\n};\n\nenum Keys {\n failed, pending, succeeded, read,\n}\n\nconst MessageOutgoingStatus: FC<OwnProps> = ({ status }) => {\n return (\n <div className=\"MessageOutgoingStatus\">\n <Transition name=\"reveal\" activeKey={Keys[status]}>\n {() => (\n <i className={`icon-message-${status}`} />\n )}\n </Transition>\n </div>\n );\n};\n\nexport default memo(MessageOutgoingStatus);\n","import { useState, useEffect } from '../lib/teact/teact';\nimport { IAnchorPosition } from '../types';\n\nexport default (\n anchor: IAnchorPosition | undefined,\n getTriggerElement: () => HTMLElement | null,\n getRootElement: () => HTMLElement | null,\n getMenuElement: () => HTMLElement | null,\n extraPaddingX = 0,\n extraTopPadding = 0,\n) => {\n const [positionX, setPositionX] = useState<'right' | 'left'>('right');\n const [positionY, setPositionY] = useState<'top' | 'bottom'>('bottom');\n const [style, setStyle] = useState('');\n\n useEffect(() => {\n const triggerEl = getTriggerElement();\n if (!anchor || !triggerEl) {\n return;\n }\n\n let { x, y } = anchor;\n const emptyRect = {\n width: 0, left: 0, height: 0, top: 0,\n };\n\n const menuEl = getMenuElement();\n const rootEl = getRootElement();\n\n const triggerRect = triggerEl.getBoundingClientRect();\n const menuRect = menuEl ? { width: menuEl.offsetWidth, height: menuEl.offsetHeight } : emptyRect;\n const rootRect = rootEl ? rootEl.getBoundingClientRect() : emptyRect;\n\n if (x + menuRect.width + extraPaddingX < rootRect.width + rootRect.left) {\n setPositionX('left');\n x += 3;\n } else if (x - menuRect.width > 0) {\n setPositionX('right');\n x -= 3;\n } else {\n setPositionX('left');\n x = 16;\n }\n\n if (y + menuRect.height < rootRect.height + rootRect.top) {\n setPositionY('top');\n } else {\n setPositionY('bottom');\n\n if (y - menuRect.height < rootRect.top + extraTopPadding) {\n y = rootRect.top + extraTopPadding + menuRect.height;\n }\n }\n\n setStyle(`left: ${x - triggerRect.left}px; top: ${y - triggerRect.top}px;`);\n }, [\n anchor, extraPaddingX, extraTopPadding,\n getMenuElement, getRootElement, getTriggerElement,\n ]);\n\n return {\n positionX,\n positionY,\n style,\n };\n};\n","import { useRef } from '../lib/teact/teact';\n\nimport usePrevious from './usePrevious';\nimport useForceUpdate from './useForceUpdate';\nimport useOnChange from './useOnChange';\n\nexport default function usePrevDuringAnimation(current: any, duration?: number) {\n const prev = usePrevious(current, true);\n const timeoutRef = useRef<number>();\n const forceUpdate = useForceUpdate();\n // eslint-disable-next-line no-null/no-null\n const isCurrentPresent = current !== undefined && current !== null;\n // eslint-disable-next-line no-null/no-null\n const isPrevPresent = prev !== undefined && prev !== null;\n\n if (isCurrentPresent && timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = undefined;\n }\n\n useOnChange(() => {\n // When `current` becomes empty\n if (duration && !isCurrentPresent && isPrevPresent && !timeoutRef.current) {\n timeoutRef.current = window.setTimeout(() => {\n timeoutRef.current = undefined;\n forceUpdate();\n }, duration);\n }\n }, [current]);\n\n return !timeoutRef.current || !duration || isCurrentPresent ? current : prev;\n}\n","import {\n useCallback, useEffect, useRef, useState,\n} from '../lib/teact/teact';\n\nimport { register } from '../util/audioPlayer';\nimport useEffectWithPrevDeps from './useEffectWithPrevDeps';\nimport { isSafariPatchInProgress } from '../util/patchSafariProgressiveAudio';\nimport useOnChange from './useOnChange';\n\ntype Handler = (e: Event) => void;\n\nexport default (\n trackId: string,\n originalDuration: number, // Sometimes incorrect for voice messages\n src?: string,\n handlers?: Record<string, Handler>,\n onInit?: (element: HTMLAudioElement) => void,\n shouldPlay = false,\n onForcePlay?: NoneToVoidFunction,\n noPlaylist = false,\n) => {\n // eslint-disable-next-line no-null/no-null\n const controllerRef = useRef<ReturnType<typeof register>>(null);\n\n const [isPlaying, setIsPlaying] = useState(false);\n let isPlayingSync = isPlaying;\n\n const [playProgress, setPlayProgress] = useState<number>(0);\n\n useOnChange(() => {\n controllerRef.current = register(trackId, (eventName, e) => {\n switch (eventName) {\n case 'onPlay':\n setIsPlaying(true);\n break;\n case 'onPause':\n setIsPlaying(false);\n break;\n case 'onTimeUpdate': {\n const { proxy } = controllerRef.current!;\n const duration = proxy.duration && Number.isFinite(proxy.duration) ? proxy.duration : originalDuration;\n setPlayProgress(proxy.currentTime / duration);\n break;\n }\n }\n\n if (handlers && handlers[eventName]) {\n handlers[eventName](e);\n }\n }, onForcePlay);\n\n const { proxy } = controllerRef.current!;\n\n if (!isPlaying && !proxy.paused) {\n setIsPlaying(true);\n isPlayingSync = true;\n }\n\n if (onInit) {\n onInit(proxy);\n }\n }, [trackId]);\n\n const {\n play, pause, setCurrentTime, proxy, destroy,\n } = controllerRef.current!;\n const duration = proxy.duration && Number.isFinite(proxy.duration) ? proxy.duration : originalDuration;\n\n // RAF progress\n useEffect(() => {\n if (duration && !isSafariPatchInProgress(proxy)) {\n setPlayProgress(proxy.currentTime / duration);\n }\n }, [duration, playProgress, proxy]);\n\n // Cleanup\n useEffect(() => () => {\n destroy(noPlaylist);\n }, [destroy, noPlaylist]);\n\n // Autoplay once `src` is present\n useEffectWithPrevDeps(([prevShouldPlay, prevSrc]) => {\n if (prevShouldPlay === shouldPlay && src === prevSrc) {\n return;\n }\n\n // When paused by another player\n if (proxy.src && proxy.paused) {\n return;\n }\n\n if (shouldPlay && src && !isPlaying) {\n play(src);\n }\n }, [shouldPlay, src, isPlaying, play, proxy.src, proxy.paused]);\n\n const playPause = useCallback(() => {\n if (isPlaying) {\n pause();\n } else if (src) {\n play(src);\n }\n }, [src, pause, play, isPlaying]);\n\n return {\n isPlaying: isPlayingSync,\n playProgress,\n playPause,\n setCurrentTime,\n audioProxy: proxy,\n duration,\n };\n};\n","import { IS_SAFARI } from './environment';\nimport safePlay from './safePlay';\nimport { patchSafariProgressiveAudio, isSafariPatchInProgress } from './patchSafariProgressiveAudio';\nimport { getDispatch } from '../lib/teact/teactn';\nimport { parseMessageKey } from '../modules/helpers';\n\ntype Handler = (eventName: string, e: Event) => void;\n\ninterface Track {\n audio: HTMLAudioElement;\n proxy: HTMLAudioElement;\n handlers: Handler[];\n onForcePlay?: NoneToVoidFunction;\n}\n\nconst tracks = new Map<string, Track>();\nlet queue: string[] = [];\n\nlet currentTrackId: string | undefined;\n\nfunction createAudio(trackId: string, onForcePlay?: NoneToVoidFunction) {\n const audio = new Audio();\n\n function handleEvent(eventName: string) {\n return (e: Event) => {\n if (!tracks.has(trackId)) {\n return;\n }\n\n if (isSafariPatchInProgress(audio)) {\n return;\n }\n\n tracks.get(trackId)!.handlers.forEach((handler) => {\n handler(eventName, e);\n });\n };\n }\n\n audio.addEventListener('timeupdate', handleEvent('onTimeUpdate'));\n audio.addEventListener('play', handleEvent('onPlay'));\n audio.addEventListener('pause', handleEvent('onPause'));\n audio.addEventListener('loadstart', handleEvent('onLoadStart'));\n audio.addEventListener('loadeddata', handleEvent('onLoadedData'));\n audio.addEventListener('playing', handleEvent('onPlaying'));\n audio.addEventListener('ended', () => {\n if (isSafariPatchInProgress(audio)) {\n return;\n }\n\n const nextTrackId = queue[queue.indexOf(trackId) + 1];\n if (!nextTrackId) {\n return;\n }\n\n if (!tracks.has(nextTrackId)) {\n // A bit hacky way to continue playlist when switching chat\n getDispatch().openAudioPlayer(parseMessageKey(nextTrackId));\n\n return;\n }\n\n const nextTrack = tracks.get(nextTrackId)!;\n\n if (nextTrack.onForcePlay) {\n nextTrack.onForcePlay();\n }\n\n currentTrackId = nextTrackId;\n\n if (nextTrack.audio.src) {\n safePlay(nextTrack.audio);\n }\n });\n\n return {\n audio,\n proxy: new Proxy(audio, {\n get: (origin, key: keyof HTMLAudioElement) => origin[key],\n }),\n handlers: [],\n onForcePlay,\n };\n}\n\nexport function stopCurrentAudio() {\n const currentTrack = currentTrackId && tracks.get(currentTrackId);\n if (currentTrack) {\n currentTrack.audio.pause();\n }\n}\n\nexport function register(trackId: string, handler: Handler, onForcePlay?: NoneToVoidFunction) {\n if (!tracks.has(trackId)) {\n tracks.set(trackId, createAudio(trackId, onForcePlay));\n\n if (!queue.includes(trackId)) {\n queue.push(trackId);\n }\n }\n\n const { audio, proxy, handlers } = tracks.get(trackId)!;\n\n handlers.push(handler);\n\n return {\n play(src: string) {\n if (currentTrackId && currentTrackId !== trackId) {\n tracks.get(currentTrackId)!.audio.pause();\n }\n\n currentTrackId = trackId;\n\n if (!audio.src) {\n audio.src = src;\n audio.preload = 'auto';\n\n if (src.includes('/progressive/') && IS_SAFARI) {\n patchSafariProgressiveAudio(audio);\n }\n }\n\n safePlay(audio);\n },\n\n pause() {\n if (currentTrackId === trackId) {\n audio.pause();\n }\n },\n\n setCurrentTime(time: number) {\n if (currentTrackId === trackId) {\n audio.currentTime = time;\n }\n },\n\n proxy,\n\n destroy(shouldRemoveFromQueue = false) {\n const track = tracks.get(trackId);\n if (!track) {\n return;\n }\n\n track.handlers = track.handlers.filter((h) => h !== handler);\n\n if (!track.handlers.length) {\n track.audio.pause();\n tracks.delete(trackId);\n\n if (shouldRemoveFromQueue) {\n queue = queue.filter((id) => id !== trackId);\n }\n\n if (trackId === currentTrackId) {\n currentTrackId = undefined;\n }\n }\n },\n };\n}\n","export default function download(url: string, filename: string) {\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n link.click();\n}\n","import { RefObject } from 'react';\nimport React, { FC, memo, useRef } from '../../lib/teact/teact';\n\nimport useShowTransition from '../../hooks/useShowTransition';\nimport useTransitionForMedia from '../../hooks/useTransitionForMedia';\nimport buildClassName from '../../util/buildClassName';\nimport { formatMediaDateTime, formatPastTimeShort } from '../../util/dateFormat';\nimport { getColorFromExtension, getFileSizeString } from './helpers/documentInfo';\nimport { getDocumentThumbnailDimensions } from './helpers/mediaDimensions';\nimport renderText from './helpers/renderText';\nimport useLang from '../../hooks/useLang';\n\nimport ProgressSpinner from '../ui/ProgressSpinner';\nimport Link from '../ui/Link';\n\nimport './File.scss';\n\ntype OwnProps = {\n ref?: RefObject<HTMLDivElement>;\n name: string;\n extension?: string;\n size: number;\n timestamp?: number;\n sender?: string;\n thumbnailDataUri?: string;\n previewData?: string;\n className?: string;\n smaller?: boolean;\n isTransferring?: boolean;\n isUploading?: boolean;\n isSelectable?: boolean;\n isSelected?: boolean;\n transferProgress?: number;\n onClick?: () => void;\n onDateClick?: (e: React.MouseEvent<HTMLAnchorElement>) => void;\n};\n\nconst File: FC<OwnProps> = ({\n ref,\n name,\n size,\n extension = '',\n timestamp,\n sender,\n thumbnailDataUri,\n previewData,\n className,\n smaller,\n isTransferring,\n isUploading,\n isSelectable,\n isSelected,\n transferProgress,\n onClick,\n onDateClick,\n}) => {\n const lang = useLang();\n // eslint-disable-next-line no-null/no-null\n let elementRef = useRef<HTMLDivElement>(null);\n if (ref) {\n elementRef = ref;\n }\n\n const {\n shouldRender: shouldSpinnerRender,\n transitionClassNames: spinnerClassNames,\n } = useShowTransition(isTransferring, undefined, true);\n const color = getColorFromExtension(extension);\n const sizeString = getFileSizeString(size);\n\n const {\n shouldRenderThumb, shouldRenderFullMedia, transitionClassNames,\n } = useTransitionForMedia(previewData, 'slow');\n const { width, height } = getDocumentThumbnailDimensions(smaller);\n\n const fullClassName = buildClassName(\n 'File',\n className,\n smaller && 'smaller',\n onClick && !isUploading && 'interactive',\n isSelected && 'file-is-selected',\n );\n\n return (\n <div ref={elementRef} className={fullClassName} dir={lang.isRtl ? 'rtl' : undefined}>\n {isSelectable && (\n <div className=\"message-select-control\">\n {isSelected && <i className=\"icon-select\" />}\n </div>\n )}\n <div className=\"file-icon-container\" onClick={isUploading ? undefined : onClick}>\n {thumbnailDataUri || previewData ? (\n <div className=\"file-preview media-inner\">\n {shouldRenderThumb && (\n <img\n src={thumbnailDataUri}\n width={width}\n height={height}\n className=\"thumbnail\"\n alt=\"\"\n />\n )}\n {shouldRenderFullMedia && (\n <img\n src={previewData}\n className={`full-media ${transitionClassNames}`}\n width={width}\n height={height}\n alt=\"\"\n />\n )}\n </div>\n ) : (\n <div className={`file-icon ${color}`}>\n {extension.length <= 4 && (\n <span className=\"file-ext\" dir=\"auto\">{extension}</span>\n )}\n </div>\n )}\n {shouldSpinnerRender && (\n <div className={buildClassName('file-progress', color, spinnerClassNames)}>\n <ProgressSpinner\n progress={transferProgress}\n size={smaller ? 's' : 'm'}\n onClick={isUploading ? onClick : undefined}\n />\n </div>\n )}\n {onClick && <i className={buildClassName('icon-download', shouldSpinnerRender && 'hidden')} />}\n </div>\n <div className=\"file-info\">\n <div className=\"file-title\" dir=\"auto\">{renderText(name)}</div>\n <div className=\"file-subtitle\" dir=\"auto\">\n <span>\n {isTransferring && transferProgress ? `${Math.round(transferProgress * 100)}%` : sizeString}\n </span>\n {sender && <span className=\"file-sender\">{renderText(sender)}</span>}\n {!sender && timestamp && (\n <>\n {' '}\n <Link onClick={onDateClick}>{formatMediaDateTime(lang, timestamp * 1000)}</Link>\n </>\n )}\n </div>\n </div>\n {sender && timestamp && (\n <Link onClick={onDateClick}>{formatPastTimeShort(lang, timestamp * 1000)}</Link>\n )}\n </div>\n );\n};\n\nexport default memo(File);\n","import React, { useCallback, useEffect, useState } from '../lib/teact/teact';\n\nimport useMediaWithDownloadProgress from './useMediaWithDownloadProgress';\nimport download from '../util/download';\n\nexport default function useMediaDownload(\n mediaHash?: string,\n fileName?: string,\n) {\n const [isDownloadStarted, setIsDownloadStarted] = useState(false);\n\n const { mediaData, downloadProgress } = useMediaWithDownloadProgress(mediaHash, !isDownloadStarted);\n\n // Download with browser when fully loaded\n useEffect(() => {\n if (isDownloadStarted && mediaData) {\n download(mediaData, fileName!);\n setIsDownloadStarted(false);\n }\n }, [fileName, mediaData, isDownloadStarted]);\n\n // Cancel download on source change\n useEffect(() => {\n setIsDownloadStarted(false);\n }, [mediaHash]);\n\n const handleDownloadClick = useCallback((e: React.SyntheticEvent<HTMLElement>) => {\n e.stopPropagation();\n setIsDownloadStarted((isAllowed) => !isAllowed);\n }, []);\n\n return {\n isDownloadStarted,\n downloadProgress,\n handleDownloadClick,\n };\n}\n","import React, {\n FC,\n memo,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from '../../lib/teact/teact';\n\nimport { ANIMATION_END_DELAY } from '../../config';\nimport useShowTransition from '../../hooks/useShowTransition';\nimport { TextPart } from '../common/helpers/renderMessageText';\nimport buildClassName from '../../util/buildClassName';\nimport captureEscKeyListener from '../../util/captureEscKeyListener';\n\nimport Portal from './Portal';\n\nimport './Notification.scss';\n\ntype OwnProps = {\n containerId?: string;\n message: TextPart[];\n duration?: number;\n onDismiss: () => void;\n};\n\nconst DEFAULT_DURATION = 3000;\nconst ANIMATION_DURATION = 150;\n\nconst Notification: FC<OwnProps> = ({\n message, duration = DEFAULT_DURATION, containerId, onDismiss,\n}) => {\n const [isOpen, setIsOpen] = useState(true);\n // eslint-disable-next-line no-null/no-null\n const timerRef = useRef<number | undefined>(null);\n\n const { transitionClassNames } = useShowTransition(isOpen);\n\n const closeAndDismiss = useCallback(() => {\n setIsOpen(false);\n setTimeout(onDismiss, ANIMATION_DURATION + ANIMATION_END_DELAY);\n }, [onDismiss]);\n\n useEffect(() => (isOpen ? captureEscKeyListener(closeAndDismiss) : undefined), [isOpen, closeAndDismiss]);\n\n useEffect(() => {\n timerRef.current = window.setTimeout(closeAndDismiss, duration);\n\n return () => {\n if (timerRef.current) {\n clearTimeout(timerRef.current);\n timerRef.current = undefined;\n }\n };\n }, [duration, closeAndDismiss]);\n\n const handleMouseEnter = useCallback(() => {\n if (timerRef.current) {\n clearTimeout(timerRef.current);\n timerRef.current = undefined;\n }\n }, []);\n\n const handleMouseLeave = useCallback(() => {\n timerRef.current = window.setTimeout(closeAndDismiss, duration);\n }, [duration, closeAndDismiss]);\n\n return (\n <Portal className=\"Notification-container\" containerId={containerId}>\n <div\n className={buildClassName('Notification', transitionClassNames)}\n onClick={closeAndDismiss}\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n >\n <div className=\"content\">\n {message}\n </div>\n </div>\n </Portal>\n );\n};\n\nexport default memo(Notification);\n","const MAX_NESTING_PARENTS = 5;\n\nexport function isSelectionInsideInput(selectionRange: Range, inputId: string) {\n const { commonAncestorContainer } = selectionRange;\n let parentNode: HTMLElement | null = commonAncestorContainer as HTMLElement;\n let iterations = 1;\n while (parentNode && parentNode.id !== inputId && iterations < MAX_NESTING_PARENTS) {\n parentNode = parentNode.parentElement;\n iterations++;\n }\n\n return Boolean(parentNode && parentNode.id === inputId);\n}\n","import {\n useCallback, useEffect, useMemo, useState,\n} from '../../../../lib/teact/teact';\n\nimport { EDITABLE_INPUT_ID } from '../../../../config';\nimport { IS_SINGLE_COLUMN_LAYOUT } from '../../../../util/environment';\nimport {\n EmojiData, EmojiModule, EmojiRawData, uncompressEmoji,\n} from '../../../../util/emoji';\nimport focusEditableElement from '../../../../util/focusEditableElement';\nimport {\n buildCollectionByKey, flatten, mapValues, pickTruthy, unique,\n} from '../../../../util/iteratees';\nimport useFlag from '../../../../hooks/useFlag';\n\nlet emojiDataPromise: Promise<EmojiModule>;\nlet emojiRawData: EmojiRawData;\nlet emojiData: EmojiData;\n\nlet RE_NOT_EMOJI_SEARCH: RegExp;\nconst EMOJIS_LIMIT = 36;\nconst FILTER_MIN_LENGTH = 2;\n\ntry {\n RE_NOT_EMOJI_SEARCH = new RegExp('[^-_:\\\\p{L}\\\\p{N}]+', 'iu');\n} catch (e) {\n // Support for older versions of firefox\n RE_NOT_EMOJI_SEARCH = new RegExp('[^-_:\\\\d\\\\wа-яё]+', 'i');\n}\n\nexport default function useEmojiTooltip(\n isAllowed: boolean,\n html: string,\n recentEmojiIds: string[],\n inputId = EDITABLE_INPUT_ID,\n onUpdateHtml: (html: string) => void,\n baseEmojiKeywords?: Record<string, string[]>,\n emojiKeywords?: Record<string, string[]>,\n) {\n const [isOpen, markIsOpen, unmarkIsOpen] = useFlag();\n\n const [byId, setById] = useState<Record<string, Emoji> | undefined>();\n const [keywords, setKeywords] = useState<string[]>();\n const [byKeyword, setByKeyword] = useState<Record<string, Emoji[]>>({});\n const [names, setNames] = useState<string[]>();\n const [byName, setByName] = useState<Record<string, Emoji[]>>({});\n\n const [filteredEmojis, setFilteredEmojis] = useState<Emoji[]>([]);\n\n const recentEmojis = useMemo(\n () => {\n if (!byId || !recentEmojiIds.length) {\n return [];\n }\n\n return Object.values(pickTruthy(byId, recentEmojiIds));\n },\n [byId, recentEmojiIds],\n );\n\n // Initialize data on first render.\n useEffect(() => {\n const exec = () => {\n setById(emojiData.emojis);\n };\n\n if (emojiData) {\n exec();\n } else {\n ensureEmojiData()\n .then(exec);\n }\n }, []);\n\n useEffect(() => {\n if (!byId) {\n return;\n }\n\n const emojis = Object.values(byId);\n\n const byNative = buildCollectionByKey(emojis, 'native');\n const baseEmojisByKeyword = baseEmojiKeywords\n ? mapValues(baseEmojiKeywords, (natives) => {\n return Object.values(pickTruthy(byNative, natives));\n })\n : {};\n const emojisByKeyword = emojiKeywords\n ? mapValues(emojiKeywords, (natives) => {\n return Object.values(pickTruthy(byNative, natives));\n })\n : {};\n\n setByKeyword({ ...baseEmojisByKeyword, ...emojisByKeyword });\n setKeywords([...Object.keys(baseEmojisByKeyword), ...Object.keys(emojisByKeyword)]);\n\n const emojisByName = emojis.reduce((result, emoji) => {\n emoji.names.forEach((name) => {\n if (!result[name]) {\n result[name] = [];\n }\n\n result[name].push(emoji);\n });\n\n return result;\n }, {} as Record<string, Emoji[]>);\n setByName(emojisByName);\n setNames(Object.keys(emojisByName));\n }, [baseEmojiKeywords, byId, emojiKeywords]);\n\n useEffect(() => {\n if (!isAllowed || !html || !byId || !keywords || !keywords.length) {\n unmarkIsOpen();\n return;\n }\n\n const code = getEmojiCode(html);\n if (!code) {\n setFilteredEmojis([]);\n unmarkIsOpen();\n return;\n }\n\n const filter = code.substr(1);\n let matched: Emoji[] = [];\n\n if (!filter) {\n matched = recentEmojis;\n } else if (filter.length >= FILTER_MIN_LENGTH) {\n const matchedKeywords = keywords.filter((keyword) => keyword.startsWith(filter)).sort();\n matched = matched.concat(flatten(Object.values(pickTruthy(byKeyword, matchedKeywords))));\n\n // Also search by names, which is useful for non-English languages\n const matchedNames = names.filter((name) => name.startsWith(filter));\n matched = matched.concat(flatten(Object.values(pickTruthy(byName, matchedNames))));\n\n matched = unique(matched);\n }\n\n if (matched.length) {\n markIsOpen();\n setFilteredEmojis(matched.slice(0, EMOJIS_LIMIT));\n } else {\n unmarkIsOpen();\n }\n }, [\n byId, byKeyword, keywords, byName, names,\n html, isAllowed, markIsOpen, recentEmojis, unmarkIsOpen,\n ]);\n\n const insertEmoji = useCallback((textEmoji: string) => {\n const atIndex = html.lastIndexOf(':');\n if (atIndex !== -1) {\n onUpdateHtml(`${html.substr(0, atIndex)}${textEmoji}`);\n const messageInput = document.getElementById(inputId)!;\n if (!IS_SINGLE_COLUMN_LAYOUT) {\n requestAnimationFrame(() => {\n focusEditableElement(messageInput, true);\n });\n }\n }\n\n unmarkIsOpen();\n }, [html, inputId, onUpdateHtml, unmarkIsOpen]);\n\n return {\n isEmojiTooltipOpen: isOpen,\n closeEmojiTooltip: unmarkIsOpen,\n filteredEmojis,\n insertEmoji,\n };\n}\n\nfunction getEmojiCode(html: string) {\n const tempEl = document.createElement('div');\n tempEl.innerHTML = html.replace('<br>', '\\n');\n const text = tempEl.innerText.replace(/\\n$/i, '');\n\n const lastSymbol = text[text.length - 1];\n const lastWord = text.split(RE_NOT_EMOJI_SEARCH).pop();\n\n if (\n !text.length || RE_NOT_EMOJI_SEARCH.test(lastSymbol)\n || !lastWord || !lastWord.startsWith(':')\n ) {\n return undefined;\n }\n\n return lastWord.toLowerCase();\n}\n\nasync function ensureEmojiData() {\n if (!emojiDataPromise) {\n emojiDataPromise = import('emoji-data-ios/emoji-data.json') as unknown as Promise<EmojiModule>;\n emojiRawData = (await emojiDataPromise).default;\n\n emojiData = uncompressEmoji(emojiRawData);\n }\n\n return emojiDataPromise;\n}\n","import React, { FC, memo } from '../../../lib/teact/teact';\nimport { OwnProps } from './EmojiTooltip';\nimport { Bundles } from '../../../util/moduleLoader';\n\nimport useModuleLoader from '../../../hooks/useModuleLoader';\n\nconst EmojiTooltipAsync: FC<OwnProps> = (props) => {\n const { isOpen } = props;\n const EmojiTooltip = useModuleLoader(Bundles.Extra, 'EmojiTooltip', !isOpen);\n\n // eslint-disable-next-line react/jsx-props-no-spreading\n return EmojiTooltip ? <EmojiTooltip {...props} /> : undefined;\n};\n\nexport default memo(EmojiTooltipAsync);\n","import { ChangeEvent } from 'react';\nimport React, {\n FC, useEffect, useRef, memo, useState, useCallback,\n} from '../../../lib/teact/teact';\nimport { withGlobal } from '../../../lib/teact/teactn';\n\nimport { GlobalActions } from '../../../global/types';\nimport { IAnchorPosition, ISettings } from '../../../types';\n\nimport { EDITABLE_INPUT_ID } from '../../../config';\nimport { selectCurrentMessageList, selectReplyingToId } from '../../../modules/selectors';\nimport { debounce } from '../../../util/schedulers';\nimport focusEditableElement from '../../../util/focusEditableElement';\nimport buildClassName from '../../../util/buildClassName';\nimport { pick } from '../../../util/iteratees';\nimport {\n IS_ANDROID, IS_IOS, IS_SINGLE_COLUMN_LAYOUT, IS_TOUCH_ENV,\n} from '../../../util/environment';\nimport captureKeyboardListeners from '../../../util/captureKeyboardListeners';\nimport useLayoutEffectWithPrevDeps from '../../../hooks/useLayoutEffectWithPrevDeps';\nimport useFlag from '../../../hooks/useFlag';\nimport parseEmojiOnlyString from '../../common/helpers/parseEmojiOnlyString';\nimport { isSelectionInsideInput } from './helpers/selection';\nimport useLang from '../../../hooks/useLang';\n\nimport TextFormatter from './TextFormatter';\n\nconst CONTEXT_MENU_CLOSE_DELAY_MS = 100;\n// Focus slows down animation, also it breaks transition layout in Chrome\nconst FOCUS_DELAY_MS = 350;\nconst TRANSITION_DURATION_FACTOR = 50;\n\ntype OwnProps = {\n id: string;\n editableInputId?: string;\n html: string;\n placeholder: string;\n shouldSetFocus: boolean;\n shouldSupressFocus?: boolean;\n shouldSupressTextFormatter?: boolean;\n onUpdate: (html: string) => void;\n onSupressedFocus?: () => void;\n onSend: () => void;\n};\n\ntype StateProps = {\n currentChatId?: number;\n replyingToId?: number;\n noTabCapture?: boolean;\n messageSendKeyCombo?: ISettings['messageSendKeyCombo'];\n};\n\ntype DispatchProps = Pick<GlobalActions, 'editLastMessage' | 'replyToNextMessage'>;\n\nconst MAX_INPUT_HEIGHT = IS_SINGLE_COLUMN_LAYOUT ? 256 : 416;\nconst TAB_INDEX_PRIORITY_TIMEOUT = 2000;\nconst TEXT_FORMATTER_SAFE_AREA_PX = 90;\n// For some reason Safari inserts `<br>` after user removes text from input\nconst SAFARI_BR = '<br>';\n\nfunction clearSelection() {\n const selection = window.getSelection();\n if (!selection) {\n return;\n }\n\n if (selection.removeAllRanges) {\n selection.removeAllRanges();\n } else if (selection.empty) {\n selection.empty();\n }\n}\n\nconst MessageInput: FC<OwnProps & StateProps & DispatchProps> = ({\n id,\n editableInputId,\n html,\n placeholder,\n shouldSetFocus,\n shouldSupressFocus,\n shouldSupressTextFormatter,\n onUpdate,\n onSupressedFocus,\n onSend,\n currentChatId,\n replyingToId,\n noTabCapture,\n messageSendKeyCombo,\n editLastMessage,\n replyToNextMessage,\n}) => {\n // eslint-disable-next-line no-null/no-null\n const inputRef = useRef<HTMLDivElement>(null);\n // eslint-disable-next-line no-null/no-null\n const cloneRef = useRef<HTMLDivElement>(null);\n\n const lang = useLang();\n const isContextMenuOpenRef = useRef(false);\n const [isTextFormatterOpen, openTextFormatter, closeTextFormatter] = useFlag();\n const [textFormatterAnchorPosition, setTextFormatterAnchorPosition] = useState<IAnchorPosition>();\n const [selectedRange, setSelectedRange] = useState<Range>();\n\n useEffect(() => {\n updateInputHeight(false);\n }, []);\n\n useLayoutEffectWithPrevDeps(([prevHtml]) => {\n if (html !== inputRef.current!.innerHTML) {\n inputRef.current!.innerHTML = html;\n }\n\n if (html !== cloneRef.current!.innerHTML) {\n cloneRef.current!.innerHTML = html;\n }\n\n if (prevHtml !== undefined && prevHtml !== html) {\n updateInputHeight(!html.length);\n }\n }, [html]);\n\n const focusInput = useCallback(() => {\n // Avoid focusing during animation\n if (inputRef.current!.closest('.from, .to')) {\n setTimeout(focusInput, FOCUS_DELAY_MS);\n return;\n }\n\n focusEditableElement(inputRef.current!);\n }, []);\n\n const handleCloseTextFormatter = useCallback(() => {\n closeTextFormatter();\n clearSelection();\n }, [closeTextFormatter]);\n\n function checkSelection() {\n // Disable the formatter on iOS devices for now.\n if (IS_IOS) {\n return;\n }\n\n const selection = window.getSelection();\n if (!selection || !selection.rangeCount || isContextMenuOpenRef.current) {\n closeTextFormatter();\n return;\n }\n\n const selectionRange = selection.getRangeAt(0);\n const selectedText = selectionRange.toString().trim();\n if (\n shouldSupressTextFormatter\n || !isSelectionInsideInput(selectionRange, editableInputId || EDITABLE_INPUT_ID)\n || !selectedText\n || parseEmojiOnlyString(selectedText)\n || !selectionRange.START_TO_END\n ) {\n closeTextFormatter();\n return;\n }\n\n const selectionRect = selectionRange.getBoundingClientRect();\n const inputRect = inputRef.current!.getBoundingClientRect();\n\n let x = (selectionRect.left + selectionRect.width / 2) - inputRect.left;\n\n if (x < TEXT_FORMATTER_SAFE_AREA_PX) {\n x = TEXT_FORMATTER_SAFE_AREA_PX;\n } else if (x > inputRect.width - TEXT_FORMATTER_SAFE_AREA_PX) {\n x = inputRect.width - TEXT_FORMATTER_SAFE_AREA_PX;\n }\n\n setTextFormatterAnchorPosition({\n x,\n y: selectionRect.top - inputRect.top,\n });\n\n setSelectedRange(selectionRange);\n openTextFormatter();\n }\n\n function handleMouseDown(event: React.MouseEvent<HTMLDivElement, MouseEvent>) {\n function handleMouseUp() {\n checkSelection();\n\n event.target.removeEventListener('mouseup', handleMouseUp);\n }\n\n if (event.button !== 2) {\n event.target.addEventListener('mouseup', handleMouseUp);\n return;\n }\n\n if (isContextMenuOpenRef.current === true) {\n return;\n }\n\n isContextMenuOpenRef.current = true;\n\n function closeContextMenuMouseListener() {\n setTimeout(() => {\n isContextMenuOpenRef.current = false;\n }, CONTEXT_MENU_CLOSE_DELAY_MS);\n\n window.removeEventListener('mouseup', closeContextMenuMouseListener);\n }\n\n function closeContextMenuKeyListener(e: KeyboardEvent) {\n if (e.key !== 'Esc' && e.key !== 'Escape') {\n return;\n }\n\n setTimeout(() => {\n isContextMenuOpenRef.current = false;\n }, CONTEXT_MENU_CLOSE_DELAY_MS);\n\n window.removeEventListener('keydown', closeContextMenuKeyListener);\n }\n\n document.addEventListener('mousedown', closeContextMenuMouseListener);\n document.addEventListener('keydown', closeContextMenuKeyListener);\n }\n\n function handleKeyDown(e: React.KeyboardEvent<HTMLDivElement>) {\n function handleKeyUp() {\n checkSelection();\n\n e.target.removeEventListener('keyup', handleKeyUp);\n }\n\n if (e.metaKey) {\n const targetIndexDelta = e.key === 'ArrowDown' ? 1 : e.key === 'ArrowUp' ? -1 : undefined;\n if (targetIndexDelta) {\n e.preventDefault();\n\n replyToNextMessage({ targetIndexDelta });\n return;\n }\n }\n\n if (e.key === 'Enter' && !e.shiftKey) {\n if (\n !(IS_IOS || IS_ANDROID)\n && (\n (messageSendKeyCombo === 'enter' && !e.shiftKey)\n || (messageSendKeyCombo === 'ctrl-enter' && (e.ctrlKey || e.metaKey))\n )\n ) {\n e.preventDefault();\n\n closeTextFormatter();\n onSend();\n }\n } else if (e.key === 'ArrowUp' && !html.length && !e.metaKey) {\n e.preventDefault();\n editLastMessage();\n } else {\n e.target.addEventListener('keyup', handleKeyUp);\n }\n }\n\n function handleTouchSelection() {\n if (!IS_ANDROID) {\n return;\n }\n\n checkSelection();\n }\n\n function handleChange(e: ChangeEvent<HTMLDivElement>) {\n const { innerHTML, textContent } = e.currentTarget;\n\n onUpdate(innerHTML === SAFARI_BR ? '' : innerHTML);\n\n // Reset focus on the input to remove any active styling when input is cleared\n if (!IS_TOUCH_ENV && (!textContent || !textContent.length)) {\n const selection = window.getSelection()!;\n if (selection) {\n inputRef.current!.blur();\n selection.removeAllRanges();\n focusEditableElement(inputRef.current!, true);\n }\n }\n }\n\n function stopEvent(e: React.MouseEvent<HTMLDivElement, MouseEvent>) {\n if (!IS_ANDROID) {\n return;\n }\n\n e.preventDefault();\n e.stopPropagation();\n }\n\n function updateInputHeight(willSend = false) {\n const input = inputRef.current!;\n const clone = cloneRef.current!;\n const currentHeight = Number(input.style.height.replace('px', ''));\n const newHeight = Math.min(clone.scrollHeight, MAX_INPUT_HEIGHT);\n if (newHeight === currentHeight) {\n return;\n }\n\n const transitionDuration = Math.round(\n TRANSITION_DURATION_FACTOR * Math.log(Math.abs(newHeight - currentHeight)),\n );\n\n const exec = () => {\n input.style.height = `${newHeight}px`;\n input.style.transitionDuration = `${transitionDuration}ms`;\n input.classList.toggle('overflown', clone.scrollHeight > MAX_INPUT_HEIGHT);\n };\n\n if (willSend) {\n // Sync with sending animation\n requestAnimationFrame(exec);\n } else {\n exec();\n }\n }\n\n useEffect(() => {\n if (IS_TOUCH_ENV) {\n return;\n }\n\n focusInput();\n }, [currentChatId, focusInput, replyingToId, shouldSetFocus]);\n\n useEffect(() => {\n if (noTabCapture) {\n return undefined;\n }\n\n const captureFirstTab = debounce((e: KeyboardEvent) => {\n if (e.key === 'Tab') {\n e.preventDefault();\n requestAnimationFrame(focusInput);\n }\n }, TAB_INDEX_PRIORITY_TIMEOUT, true, false);\n\n return captureKeyboardListeners({ onTab: captureFirstTab });\n }, [focusInput, noTabCapture]);\n\n useEffect(() => {\n const input = inputRef.current!;\n\n function supressFocus() {\n input.blur();\n }\n\n if (shouldSupressFocus) {\n input.addEventListener('focus', supressFocus);\n }\n\n return () => {\n input.removeEventListener('focus', supressFocus);\n };\n }, [shouldSupressFocus]);\n\n const className = buildClassName(\n 'form-control custom-scroll',\n html.length > 0 && 'touched',\n shouldSupressFocus && 'focus-disabled',\n );\n\n return (\n <div id={id} onClick={shouldSupressFocus ? onSupressedFocus : undefined} dir={lang.isRtl ? 'rtl' : undefined}>\n <div\n ref={inputRef}\n id={editableInputId || EDITABLE_INPUT_ID}\n className={className}\n contentEditable\n dir=\"auto\"\n onClick={focusInput}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n onMouseDown={handleMouseDown}\n onContextMenu={stopEvent}\n onTouchCancel={handleTouchSelection}\n />\n <div ref={cloneRef} className={buildClassName(className, 'clone')} dir=\"auto\" />\n <span className=\"placeholder-text\" dir=\"auto\">{placeholder}</span>\n <TextFormatter\n isOpen={isTextFormatterOpen}\n anchorPosition={textFormatterAnchorPosition}\n selectedRange={selectedRange}\n onClose={handleCloseTextFormatter}\n />\n </div>\n );\n};\n\nexport default memo(withGlobal<OwnProps>(\n (global): StateProps => {\n const { chatId: currentChatId, threadId } = selectCurrentMessageList(global) || {};\n const { messageSendKeyCombo } = global.settings.byKey;\n\n return {\n currentChatId,\n messageSendKeyCombo,\n replyingToId: currentChatId && threadId ? selectReplyingToId(global, currentChatId, threadId) : undefined,\n noTabCapture: global.isPollModalOpen || global.payment.isPaymentModalOpen,\n };\n },\n (setGlobal, actions): DispatchProps => pick(actions, ['editLastMessage', 'replyToNextMessage']),\n)(MessageInput));\n","import React, { FC, memo, useCallback } from '../../lib/teact/teact';\n\nimport { ApiMessage, ApiWebPage } from '../../api/types';\n\nimport { getFirstLinkInMessage, getMessageSummaryText, getMessageWebPage } from '../../modules/helpers';\nimport buildClassName from '../../util/buildClassName';\nimport trimText from '../../util/trimText';\nimport renderText from './helpers/renderText';\nimport { formatPastTimeShort } from '../../util/dateFormat';\nimport useLang from '../../hooks/useLang';\n\nimport Media from './Media';\nimport Link from '../ui/Link';\nimport SafeLink from './SafeLink';\n\nimport './WebLink.scss';\n\nconst MAX_TEXT_LENGTH = 170; // symbols\n\ntype OwnProps = {\n message: ApiMessage;\n senderTitle?: string;\n onMessageClick: (messageId: number, chatId: number) => void;\n};\n\nconst WebLink: FC<OwnProps> = ({ message, senderTitle, onMessageClick }) => {\n const lang = useLang();\n\n let linkData: ApiWebPage | undefined = getMessageWebPage(message);\n\n if (!linkData) {\n const link = getFirstLinkInMessage(message);\n if (link) {\n const { url, domain } = link;\n const messageText = getMessageSummaryText(lang, message);\n\n linkData = {\n siteName: domain.replace(/^www./, ''),\n url: url.includes('://') ? url : url.includes('@') ? `mailto:${url}` : `http://${url}`,\n description: messageText !== url ? messageText : undefined,\n } as ApiWebPage;\n }\n }\n\n const handleMessageClick = useCallback(() => {\n onMessageClick(message.id, message.chatId);\n }, [onMessageClick, message.id, message.chatId]);\n\n if (!linkData) {\n return undefined;\n }\n\n const {\n siteName,\n url,\n displayUrl,\n title,\n description,\n photo,\n } = linkData;\n\n const truncatedDescription = !senderTitle && trimText(description, MAX_TEXT_LENGTH);\n\n const className = buildClassName(\n 'WebLink scroll-item',\n !photo && 'without-photo',\n );\n\n return (\n <div\n className={className}\n data-initial={(siteName || displayUrl)[0]}\n dir={lang.isRtl ? 'rtl' : undefined}\n >\n {photo && (\n <Media message={message} />\n )}\n <div className=\"content\">\n <Link isRtl={lang.isRtl} className=\"site-title\" onClick={handleMessageClick}>\n {renderText(title || siteName || displayUrl)}\n </Link>\n {truncatedDescription && (\n <Link isRtl={lang.isRtl} className=\"site-description\" onClick={handleMessageClick}>\n {renderText(truncatedDescription)}\n </Link>\n )}\n <SafeLink\n url={url}\n className=\"site-name\"\n text=\"\"\n isRtl={lang.isRtl}\n >\n {url.replace('mailto:', '') || displayUrl}\n </SafeLink>\n {senderTitle && <div className=\"sender-name\">{renderText(senderTitle)}</div>}\n </div>\n {senderTitle && (\n <div className=\"message-date\">\n <Link\n className=\"date\"\n onClick={handleMessageClick}\n isRtl={lang.isRtl}\n >\n {formatPastTimeShort(lang, message.date * 1000)}\n </Link>\n </div>\n )}\n </div>\n );\n};\n\nexport default memo(WebLink);\n","import { useCallback } from '../../../../lib/teact/teact';\n\nexport enum ChatAnimationTypes {\n Move,\n Opacity,\n None,\n}\n\nexport function useChatAnimationType(orderDiffById: Record<number, number>) {\n const movesUp = useCallback((id: number) => orderDiffById[id] < 0, [orderDiffById]);\n const movesDown = useCallback((id: number) => orderDiffById[id] > 0, [orderDiffById]);\n\n const orderDiffIds = Object.keys(orderDiffById).map(Number);\n const numberOfUp = orderDiffIds.filter(movesUp).length;\n const numberOfDown = orderDiffIds.filter(movesDown).length;\n\n return useCallback((chatId: number): ChatAnimationTypes => {\n const orderDiff = orderDiffById[chatId];\n\n if (orderDiff === 0) {\n return ChatAnimationTypes.None;\n }\n\n if (\n orderDiff === Infinity\n || orderDiff === -Infinity\n || (movesUp(chatId) && numberOfUp <= numberOfDown)\n || (movesDown(chatId) && numberOfDown < numberOfUp)\n ) {\n return ChatAnimationTypes.Opacity;\n }\n\n return ChatAnimationTypes.Move;\n }, [movesDown, movesUp, numberOfDown, numberOfUp, orderDiffById]);\n}\n","import React, { FC, memo } from '../../../lib/teact/teact';\n\nimport { ApiChat } from '../../../api/types';\n\nimport { formatIntegerCompact } from '../../../util/textFormat';\nimport buildClassName from '../../../util/buildClassName';\n\nimport ShowTransition from '../../ui/ShowTransition';\n\nimport './Badge.scss';\n\ntype OwnProps = {\n chat: ApiChat;\n isPinned?: boolean;\n isMuted?: boolean;\n};\n\nconst Badge: FC<OwnProps> = ({ chat, isPinned, isMuted }) => {\n const isShown = Boolean(chat.unreadCount || chat.hasUnreadMark || isPinned);\n const className = buildClassName(\n 'Badge',\n isMuted && 'muted',\n isPinned && 'pinned',\n Boolean(chat.unreadCount || chat.hasUnreadMark) && 'unread',\n );\n\n function renderContent() {\n if (chat.unreadCount) {\n if (chat.unreadMentionsCount) {\n return (\n <div className=\"Badge-wrapper\">\n <div className=\"Badge mention\">\n <i className=\"icon-mention\" />\n </div>\n <div className={className}>\n {formatIntegerCompact(chat.unreadCount)}\n </div>\n </div>\n );\n }\n\n return (\n <div className={className}>\n {formatIntegerCompact(chat.unreadCount)}\n </div>\n );\n } else if (chat.hasUnreadMark) {\n return (\n <div className={className} />\n );\n } else if (isPinned) {\n return (\n <div className={className}>\n <i className=\"icon-pinned-chat\" />\n </div>\n );\n }\n\n return undefined;\n }\n\n return (\n <ShowTransition isCustom className=\"Badge-transition\" isOpen={isShown}>\n {renderContent}\n </ShowTransition>\n );\n};\n\nexport default memo(Badge);\n","import React, {\n FC, memo, useCallback, useLayoutEffect, useRef,\n} from '../../../lib/teact/teact';\nimport { withGlobal } from '../../../lib/teact/teactn';\n\nimport useLang, { LangFn } from '../../../hooks/useLang';\n\nimport { GlobalActions, MessageListType } from '../../../global/types';\nimport {\n ApiChat, ApiUser, ApiMessage, ApiMessageOutgoingStatus, ApiFormattedText, MAIN_THREAD_ID,\n} from '../../../api/types';\n\nimport { ANIMATION_END_DELAY } from '../../../config';\nimport { IS_SINGLE_COLUMN_LAYOUT } from '../../../util/environment';\nimport {\n getChatTitle,\n isChatPrivate,\n isActionMessage,\n getPrivateChatUserId,\n getMessageAction,\n getMessageSenderName,\n isChatChannel,\n getMessageMediaHash,\n getMessageSummaryText,\n getMessageMediaThumbDataUri,\n getMessageVideo,\n getMessageSticker,\n selectIsChatMuted,\n getMessageRoundVideo,\n} from '../../../modules/helpers';\nimport {\n selectChat, selectUser, selectChatMessage, selectOutgoingStatus, selectDraft, selectCurrentMessageList,\n selectNotifySettings, selectNotifyExceptions,\n} from '../../../modules/selectors';\nimport { renderActionMessageText } from '../../common/helpers/renderActionMessageText';\nimport renderText from '../../common/helpers/renderText';\nimport { fastRaf } from '../../../util/schedulers';\nimport buildClassName from '../../../util/buildClassName';\nimport { pick } from '../../../util/iteratees';\nimport useEnsureMessage from '../../../hooks/useEnsureMessage';\nimport useChatContextActions from '../../../hooks/useChatContextActions';\nimport useFlag from '../../../hooks/useFlag';\nimport useMedia from '../../../hooks/useMedia';\nimport { ChatAnimationTypes } from './hooks';\n\nimport Avatar from '../../common/Avatar';\nimport VerifiedIcon from '../../common/VerifiedIcon';\nimport TypingStatus from '../../common/TypingStatus';\nimport LastMessageMeta from '../../common/LastMessageMeta';\nimport DeleteChatModal from '../../common/DeleteChatModal';\nimport ListItem from '../../ui/ListItem';\nimport Badge from './Badge';\n\nimport './Chat.scss';\n\ntype OwnProps = {\n style?: string;\n chatId: number;\n folderId?: number;\n orderDiff: number;\n animationType: ChatAnimationTypes;\n isSelected: boolean;\n isPinned?: boolean;\n};\n\ntype StateProps = {\n chat?: ApiChat;\n isMuted?: boolean;\n privateChatUser?: ApiUser;\n actionTargetUser?: ApiUser;\n actionTargetMessage?: ApiMessage;\n actionTargetChatId?: number;\n lastMessageSender?: ApiUser;\n lastMessageOutgoingStatus?: ApiMessageOutgoingStatus;\n draft?: ApiFormattedText;\n messageListType?: MessageListType;\n animationLevel?: number;\n lastSyncTime?: number;\n};\n\ntype DispatchProps = Pick<GlobalActions, 'openChat' | 'focusLastMessage'>;\n\nconst ANIMATION_DURATION = 200;\n\nconst Chat: FC<OwnProps & StateProps & DispatchProps> = ({\n style,\n chatId,\n folderId,\n orderDiff,\n animationType,\n isSelected,\n isPinned,\n chat,\n isMuted,\n privateChatUser,\n actionTargetUser,\n lastMessageSender,\n lastMessageOutgoingStatus,\n actionTargetMessage,\n actionTargetChatId,\n draft,\n messageListType,\n animationLevel,\n lastSyncTime,\n openChat,\n focusLastMessage,\n}) => {\n // eslint-disable-next-line no-null/no-null\n const ref = useRef<HTMLDivElement>(null);\n\n const [isDeleteModalOpen, openDeleteModal, closeDeleteModal] = useFlag();\n const [shouldRenderDeleteModal, markRenderDeleteModal, unmarkRenderDeleteModal] = useFlag();\n\n const { lastMessage, typingStatus } = chat || {};\n const isAction = lastMessage && isActionMessage(lastMessage);\n\n useEnsureMessage(chatId, isAction ? lastMessage!.replyToMessageId : undefined, actionTargetMessage);\n\n const mediaThumbnail = lastMessage && !getMessageSticker(lastMessage)\n ? getMessageMediaThumbDataUri(lastMessage)\n : undefined;\n const mediaBlobUrl = useMedia(lastMessage ? getMessageMediaHash(lastMessage, 'micro') : undefined);\n const isRoundVideo = Boolean(lastMessage && getMessageRoundVideo(lastMessage));\n\n // Sets animation excess values when `orderDiff` changes and then resets excess values to animate.\n useLayoutEffect(() => {\n const element = ref.current;\n\n if (animationLevel === 0 || !element) {\n return;\n }\n\n // TODO Refactor animation: create `useListAnimation` that owns `orderDiff` and `animationType`\n if (animationType === ChatAnimationTypes.Opacity) {\n element.style.opacity = '0';\n\n fastRaf(() => {\n element.classList.add('animate-opacity');\n element.style.opacity = '1';\n });\n } else if (animationType === ChatAnimationTypes.Move) {\n element.style.transform = `translate3d(0, ${-orderDiff * 100}%, 0)`;\n\n fastRaf(() => {\n element.classList.add('animate-transform');\n element.style.transform = '';\n });\n } else {\n return;\n }\n\n setTimeout(() => {\n fastRaf(() => {\n element.classList.remove('animate-opacity', 'animate-transform');\n element.style.opacity = '';\n element.style.transform = '';\n });\n }, ANIMATION_DURATION + ANIMATION_END_DELAY);\n }, [animationLevel, orderDiff, animationType]);\n\n const handleClick = useCallback(() => {\n openChat({ id: chatId });\n\n if (isSelected && messageListType === 'thread') {\n focusLastMessage();\n }\n }, [\n isSelected,\n messageListType,\n openChat,\n chatId,\n focusLastMessage,\n ]);\n\n function handleDelete() {\n markRenderDeleteModal();\n openDeleteModal();\n }\n\n const contextActions = useChatContextActions({\n chat,\n privateChatUser,\n handleDelete,\n folderId,\n isPinned,\n isMuted,\n });\n\n const lang = useLang();\n\n if (!chat) {\n return undefined;\n }\n\n function renderLastMessageOrTyping() {\n if (typingStatus && lastMessage && typingStatus.timestamp > lastMessage.date * 1000) {\n return <TypingStatus typingStatus={typingStatus} />;\n }\n\n if (draft && draft.text.length) {\n return (\n <p className=\"last-message\" dir={lang.isRtl ? 'auto' : 'ltr'}>\n <span className=\"draft\">{lang('Draft')}</span>\n {renderText(draft.text)}\n </p>\n );\n }\n\n if (!lastMessage) {\n return undefined;\n }\n\n if (isAction) {\n const actionOrigin = chat && (isChatChannel(chat) || lastMessage.senderId === lastMessage.chatId)\n ? chat\n : lastMessageSender;\n\n return (\n <p className=\"last-message\" dir={lang.isRtl ? 'auto' : 'ltr'}>\n {renderText(renderActionMessageText(\n lang,\n lastMessage,\n actionOrigin,\n actionTargetUser,\n actionTargetMessage,\n actionTargetChatId,\n { asPlain: true },\n ) as string)}\n </p>\n );\n }\n\n const senderName = getMessageSenderName(lang, chatId, lastMessageSender);\n\n return (\n <p className=\"last-message\" dir={lang.isRtl ? 'auto' : 'ltr'}>\n {senderName && (\n <>\n <span className=\"sender-name\">{renderText(senderName)}</span>\n <span className=\"colon\">:</span>\n </>\n )}\n {renderMessageSummary(lang, lastMessage!, mediaBlobUrl || mediaThumbnail, isRoundVideo)}\n </p>\n );\n }\n\n const className = buildClassName(\n 'Chat chat-item-clickable',\n isChatPrivate(chatId) ? 'private' : 'group',\n isSelected && !IS_SINGLE_COLUMN_LAYOUT && 'selected',\n );\n\n return (\n <ListItem\n ref={ref}\n className={className}\n style={style}\n ripple={!IS_SINGLE_COLUMN_LAYOUT}\n contextActions={contextActions}\n onClick={handleClick}\n >\n <div className=\"status\">\n <Avatar\n chat={chat}\n user={privateChatUser}\n withOnlineStatus\n isSavedMessages={privateChatUser && privateChatUser.isSelf}\n lastSyncTime={lastSyncTime}\n />\n </div>\n <div className=\"info\">\n <div className=\"title\">\n <h3>{renderText(getChatTitle(lang, chat, privateChatUser))}</h3>\n {chat.isVerified && <VerifiedIcon />}\n {isMuted && <i className=\"icon-muted-chat\" />}\n {chat.lastMessage && (\n <LastMessageMeta message={chat.lastMessage} outgoingStatus={lastMessageOutgoingStatus} />\n )}\n </div>\n <div className=\"subtitle\">\n {renderLastMessageOrTyping()}\n <Badge chat={chat} isPinned={isPinned} isMuted={isMuted} />\n </div>\n </div>\n {shouldRenderDeleteModal && (\n <DeleteChatModal\n isOpen={isDeleteModalOpen}\n onClose={closeDeleteModal}\n onCloseAnimationEnd={unmarkRenderDeleteModal}\n chat={chat}\n />\n )}\n </ListItem>\n );\n};\n\nfunction renderMessageSummary(lang: LangFn, message: ApiMessage, blobUrl?: string, isRoundVideo?: boolean) {\n if (!blobUrl) {\n return renderText(getMessageSummaryText(lang, message));\n }\n\n return (\n <span className=\"media-preview\">\n <img src={blobUrl} alt=\"\" className={isRoundVideo ? 'round' : undefined} />\n {getMessageVideo(message) && <i className=\"icon-play\" />}\n {renderText(getMessageSummaryText(lang, message, true))}\n </span>\n );\n}\n\nexport default memo(withGlobal<OwnProps>(\n (global, { chatId }): StateProps => {\n const chat = selectChat(global, chatId);\n if (!chat || !chat.lastMessage) {\n return {};\n }\n\n const { senderId, replyToMessageId, isOutgoing } = chat.lastMessage;\n const lastMessageSender = senderId ? selectUser(global, senderId) : undefined;\n const lastMessageAction = getMessageAction(chat.lastMessage);\n const actionTargetMessage = lastMessageAction && replyToMessageId\n ? selectChatMessage(global, chat.id, replyToMessageId)\n : undefined;\n const { targetUserId: actionTargetUserId, targetChatId: actionTargetChatId } = lastMessageAction || {};\n const privateChatUserId = getPrivateChatUserId(chat);\n const { type: messageListType } = selectCurrentMessageList(global) || {};\n\n return {\n chat,\n isMuted: selectIsChatMuted(chat, selectNotifySettings(global), selectNotifyExceptions(global)),\n lastMessageSender,\n ...(isOutgoing && { lastMessageOutgoingStatus: selectOutgoingStatus(global, chat.lastMessage) }),\n ...(privateChatUserId && { privateChatUser: selectUser(global, privateChatUserId) }),\n ...(actionTargetUserId && { actionTargetUser: selectUser(global, actionTargetUserId) }),\n actionTargetChatId,\n actionTargetMessage,\n draft: selectDraft(global, chatId, MAIN_THREAD_ID),\n messageListType,\n animationLevel: global.settings.byKey.animationLevel,\n lastSyncTime: global.lastSyncTime,\n };\n },\n (setGlobal, actions): DispatchProps => pick(actions, [\n 'openChat',\n 'focusLastMessage',\n ]),\n)(Chat));\n","import React, {\n FC, memo, useMemo, useCallback, useEffect,\n} from '../../../lib/teact/teact';\nimport { withGlobal } from '../../../lib/teact/teactn';\n\nimport { GlobalActions } from '../../../global/types';\nimport {\n ApiChat, ApiChatFolder, ApiUser, MAIN_THREAD_ID,\n} from '../../../api/types';\nimport { NotifyException, NotifySettings } from '../../../types';\n\nimport { ALL_CHATS_PRELOAD_DISABLED, CHAT_HEIGHT_PX, CHAT_LIST_SLICE } from '../../../config';\nimport { IS_ANDROID } from '../../../util/environment';\nimport usePrevious from '../../../hooks/usePrevious';\nimport { mapValues, pick } from '../../../util/iteratees';\nimport { getChatOrder, prepareChatList, prepareFolderListIds } from '../../../modules/helpers';\nimport {\n selectChatFolder, selectCurrentMessageList, selectNotifyExceptions, selectNotifySettings,\n} from '../../../modules/selectors';\nimport useInfiniteScroll from '../../../hooks/useInfiniteScroll';\nimport { useChatAnimationType } from './hooks';\n\nimport InfiniteScroll from '../../ui/InfiniteScroll';\nimport Loading from '../../ui/Loading';\nimport Chat from './Chat';\n\ntype OwnProps = {\n folderType: 'all' | 'archived' | 'folder';\n folderId?: number;\n noChatsText?: string;\n isActive: boolean;\n};\n\ntype StateProps = {\n chatsById: Record<number, ApiChat>;\n usersById: Record<number, ApiUser>;\n chatFolder?: ApiChatFolder;\n listIds?: number[];\n currentChatId?: number;\n orderedPinnedIds?: number[];\n lastSyncTime?: number;\n isInDiscussionThread?: boolean;\n notifySettings: NotifySettings;\n notifyExceptions?: Record<number, NotifyException>;\n};\n\ntype DispatchProps = Pick<GlobalActions, 'loadMoreChats' | 'preloadTopChatMessages' | 'openChat'>;\n\nenum FolderTypeToListType {\n 'all' = 'active',\n 'archived' = 'archived'\n}\n\nconst ChatList: FC<OwnProps & StateProps & DispatchProps> = ({\n folderType,\n folderId,\n noChatsText = 'Chat list is empty.',\n isActive,\n chatFolder,\n chatsById,\n usersById,\n listIds,\n currentChatId,\n orderedPinnedIds,\n lastSyncTime,\n isInDiscussionThread,\n notifySettings,\n notifyExceptions,\n loadMoreChats,\n preloadTopChatMessages,\n openChat,\n}) => {\n const [currentListIds, currentPinnedIds] = useMemo(() => {\n return folderType === 'folder' && chatFolder\n ? prepareFolderListIds(chatsById, usersById, chatFolder, notifySettings, notifyExceptions)\n : [listIds, orderedPinnedIds];\n }, [folderType, chatFolder, chatsById, usersById, notifySettings, notifyExceptions, listIds, orderedPinnedIds]);\n\n const [orderById, orderedIds] = useMemo(() => {\n if (!currentListIds || (folderType === 'folder' && !chatFolder)) {\n return [];\n }\n const newChatArrays = prepareChatList(chatsById, currentListIds, currentPinnedIds, folderType);\n const singleList = [...newChatArrays.pinnedChats, ...newChatArrays.otherChats];\n const newOrderedIds = singleList.map(({ id }) => id);\n const newOrderById = singleList.reduce((acc, chat, i) => {\n acc[chat.id] = i;\n return acc;\n }, {} as Record<string, number>);\n\n return [newOrderById, newOrderedIds];\n }, [currentListIds, currentPinnedIds, folderType, chatFolder, chatsById]);\n\n const prevOrderById = usePrevious(orderById);\n\n const orderDiffById = orderById && prevOrderById\n ? mapValues(orderById, (order, id) => {\n return order - (prevOrderById[id] !== undefined ? prevOrderById[id] : Infinity);\n })\n : {};\n\n const loadMoreOfType = useCallback(() => {\n loadMoreChats({ listType: folderType === 'archived' ? 'archived' : 'active' });\n }, [loadMoreChats, folderType]);\n\n const [viewportIds, getMore] = useInfiniteScroll(\n lastSyncTime ? loadMoreOfType : undefined,\n orderedIds,\n undefined,\n CHAT_LIST_SLICE,\n folderType === 'all' && !ALL_CHATS_PRELOAD_DISABLED,\n );\n\n // TODO Refactor to not call `prepareChatList` twice\n const chatArrays = viewportIds && prepareChatList(chatsById, viewportIds, currentPinnedIds, folderType);\n\n useEffect(() => {\n if (lastSyncTime && folderType === 'all') {\n preloadTopChatMessages();\n }\n }, [lastSyncTime, folderType, preloadTopChatMessages]);\n\n const getAnimationType = useChatAnimationType(orderDiffById);\n\n function renderChats() {\n const viewportOffset = orderedIds!.indexOf(viewportIds![0]);\n const pinnedOffset = viewportOffset + chatArrays!.pinnedChats.length;\n\n return (\n <div\n className=\"scroll-container\"\n // @ts-ignore\n style={IS_ANDROID ? `height: ${orderedIds!.length * CHAT_HEIGHT_PX}px` : undefined}\n teactFastList\n >\n {chatArrays!.pinnedChats.map(({ id }, i) => (\n <Chat\n key={id}\n teactOrderKey={i}\n chatId={id}\n isPinned\n folderId={folderId}\n isSelected={id === currentChatId && !isInDiscussionThread}\n animationType={getAnimationType(id)}\n orderDiff={orderDiffById[id]}\n // @ts-ignore\n style={`top: ${(viewportOffset + i) * CHAT_HEIGHT_PX}px;`}\n />\n ))}\n {chatArrays!.otherChats.map((chat, i) => (\n <Chat\n key={chat.id}\n teactOrderKey={getChatOrder(chat)}\n chatId={chat.id}\n folderId={folderId}\n isSelected={chat.id === currentChatId && !isInDiscussionThread}\n animationType={getAnimationType(chat.id)}\n orderDiff={orderDiffById[chat.id]}\n // @ts-ignore\n style={`top: ${(pinnedOffset + i) * CHAT_HEIGHT_PX}px;`}\n />\n ))}\n </div>\n );\n }\n\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (isActive && orderedIds) {\n if (e.ctrlKey && e.code.startsWith('Digit')) {\n const [, digit] = e.code.match(/Digit(\\d)/) || [];\n if (!digit) return;\n\n const position = Number(digit) - 1;\n if (position > orderedIds.length - 1) return;\n\n openChat({ id: orderedIds[position] });\n }\n\n if (e.altKey) {\n const targetIndexDelta = e.key === 'ArrowDown' ? 1 : e.key === 'ArrowUp' ? -1 : undefined;\n if (!targetIndexDelta) return;\n\n if (!currentChatId) {\n e.preventDefault();\n openChat({ id: orderedIds[0] });\n return;\n }\n\n const position = orderedIds.indexOf(currentChatId);\n\n if (position === -1) {\n return;\n }\n const nextId = orderedIds[position + targetIndexDelta];\n\n e.preventDefault();\n openChat({ id: nextId });\n }\n }\n };\n\n document.addEventListener('keydown', handleKeyDown, false);\n\n return () => {\n document.removeEventListener('keydown', handleKeyDown, false);\n };\n });\n\n return (\n <InfiniteScroll\n className=\"chat-list custom-scroll\"\n items={viewportIds}\n onLoadMore={getMore}\n preloadBackwards={CHAT_LIST_SLICE}\n noFastList\n noScrollRestore\n >\n {viewportIds && viewportIds.length && chatArrays ? (\n renderChats()\n ) : viewportIds && !viewportIds.length ? (\n <div className=\"no-results\">{noChatsText}</div>\n ) : (\n <Loading key=\"loading\" />\n )}\n </InfiniteScroll>\n );\n};\n\nexport default memo(withGlobal<OwnProps>(\n (global, { folderType, folderId }): StateProps => {\n const {\n chats: {\n listIds,\n byId: chatsById,\n orderedPinnedIds,\n },\n users: { byId: usersById },\n lastSyncTime,\n } = global;\n const { chatId: currentChatId, threadId: currentThreadId } = selectCurrentMessageList(global) || {};\n\n const listType = folderType !== 'folder' ? FolderTypeToListType[folderType] : undefined;\n const chatFolder = folderId ? selectChatFolder(global, folderId) : undefined;\n\n return {\n chatsById,\n usersById,\n currentChatId,\n lastSyncTime,\n ...(listType ? {\n listIds: listIds[listType],\n orderedPinnedIds: orderedPinnedIds[listType],\n } : {\n chatFolder,\n }),\n isInDiscussionThread: currentThreadId !== MAIN_THREAD_ID,\n notifySettings: selectNotifySettings(global),\n notifyExceptions: selectNotifyExceptions(global),\n };\n },\n (setGlobal, actions): DispatchProps => pick(actions, [\n 'loadMoreChats',\n 'preloadTopChatMessages',\n 'openChat',\n ]),\n)(ChatList));\n","import { useCallback, useEffect, useState } from '../../../../lib/teact/teact';\n\nimport { ApiMessageEntityTypes, ApiChatMember, ApiUser } from '../../../../api/types';\nimport { EDITABLE_INPUT_ID } from '../../../../config';\nimport { getUserFirstOrLastName } from '../../../../modules/helpers';\nimport searchUserName from '../helpers/searchUserName';\nimport { IS_SINGLE_COLUMN_LAYOUT } from '../../../../util/environment';\nimport focusEditableElement from '../../../../util/focusEditableElement';\nimport useFlag from '../../../../hooks/useFlag';\n\nconst RE_NOT_USERNAME_SEARCH = /[^@_\\d\\wа-яё]+/i;\n\nexport default function useMentionTooltip(\n canSuggestMembers: boolean | undefined,\n html: string,\n onUpdateHtml: (html: string) => void,\n inputId: string = EDITABLE_INPUT_ID,\n groupChatMembers?: ApiChatMember[],\n currentUserId?: number,\n usersById?: Record<number, ApiUser>,\n) {\n const [isOpen, markIsOpen, unmarkIsOpen] = useFlag();\n const [currentFilter, setCurrentFilter] = useState('');\n const [filteredMembers, setFilteredMembers] = useState<ApiChatMember[]>([]);\n\n const getFilteredMembers = useCallback((filter) => {\n if (!groupChatMembers || !usersById) {\n return undefined;\n }\n\n return groupChatMembers.filter(({ userId }) => {\n const user = usersById[userId];\n if (userId === currentUserId || !user) {\n return false;\n }\n\n return !filter || searchUserName(filter, user);\n });\n }, [groupChatMembers, currentUserId, usersById]);\n\n useEffect(() => {\n if (!canSuggestMembers || !html.length) {\n unmarkIsOpen();\n return;\n }\n\n const usernameFilter = getUsernameFilter(html);\n\n if (usernameFilter) {\n const filter = usernameFilter ? usernameFilter.substr(1) : '';\n const membersToMention = getFilteredMembers(filter);\n if (membersToMention && membersToMention.length) {\n markIsOpen();\n setCurrentFilter(filter);\n setFilteredMembers(membersToMention);\n } else {\n unmarkIsOpen();\n }\n } else {\n unmarkIsOpen();\n }\n }, [canSuggestMembers, html, getFilteredMembers, markIsOpen, unmarkIsOpen]);\n\n const insertMention = useCallback((user: ApiUser, forceFocus = false) => {\n if (!user.username && !getUserFirstOrLastName(user)) {\n return;\n }\n\n const insertedHtml = user.username\n ? `@${user.username}`\n : `<a\n class=\"text-entity-link\"\n data-entity-type=\"${ApiMessageEntityTypes.MentionName}\"\n data-user-id=\"${user.id}\"\n contenteditable=\"false\"\n dir=\"auto\"\n >${getUserFirstOrLastName(user)}</a>`;\n\n const atIndex = html.lastIndexOf('@');\n if (atIndex !== -1) {\n onUpdateHtml(`${html.substr(0, atIndex)}${insertedHtml} `);\n const messageInput = document.getElementById(inputId)!;\n if (!IS_SINGLE_COLUMN_LAYOUT) {\n requestAnimationFrame(() => {\n focusEditableElement(messageInput, forceFocus);\n });\n }\n }\n\n unmarkIsOpen();\n }, [html, inputId, onUpdateHtml, unmarkIsOpen]);\n\n return {\n isMentionTooltipOpen: isOpen,\n mentionFilter: currentFilter,\n closeMentionTooltip: unmarkIsOpen,\n insertMention,\n mentionFilteredMembers: filteredMembers,\n };\n}\n\nfunction getUsernameFilter(html: string) {\n const tempEl = document.createElement('div');\n tempEl.innerHTML = html;\n const text = tempEl.innerText.replace(/\\n$/i, '');\n\n const lastSymbol = text[text.length - 1];\n const lastWord = text.split(RE_NOT_USERNAME_SEARCH).pop();\n\n if (\n !text.length || RE_NOT_USERNAME_SEARCH.test(lastSymbol)\n || !lastWord || !lastWord.startsWith('@')\n ) {\n return undefined;\n }\n\n return lastWord;\n}\n","import { ApiUser } from '../../../../api/types';\nimport { getUserFullName } from '../../../../modules/helpers';\nimport searchWords from '../../../../util/searchWords';\n\n// TODO: Support cyrillic translit search\nexport default function searchUserName(filter: string, user: ApiUser) {\n const usernameLowered = user.username.toLowerCase();\n const fullName = getUserFullName(user);\n const fullNameLowered = fullName && fullName.toLowerCase();\n const filterLowered = filter.toLowerCase();\n\n return usernameLowered.startsWith(filterLowered) || (\n fullNameLowered && searchWords(fullNameLowered, filterLowered)\n );\n}\n","import { useEffect, useRef } from '../lib/teact/teact';\n\nimport fastBlur from '../lib/fastBlur';\nimport { imgToCanvas } from '../util/files';\nimport useForceUpdate from './useForceUpdate';\n\nconst RADIUS = 2;\nconst ITERATIONS = 2;\nconst MAX_CACHE_SIZE = 1000;\n\nconst cache = new Map<string, string>();\n\nexport default function useBlur(dataUri?: string, isDisabled = false, delay?: number) {\n const blurredRef = useRef<string | undefined>(dataUri ? cache.get(dataUri) : undefined);\n const timeoutRef = useRef<number>();\n const forceUpdate = useForceUpdate();\n\n if (timeoutRef.current && isDisabled) {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = undefined;\n }\n\n useEffect(() => {\n if (!dataUri || blurredRef.current || isDisabled) {\n return;\n }\n\n const img = new Image();\n\n img.onload = () => {\n const canvas = imgToCanvas(img);\n fastBlur(canvas.getContext('2d'), 0, 0, canvas.width, canvas.height, RADIUS, ITERATIONS);\n const blurredDataUri = canvas.toDataURL();\n\n blurredRef.current = blurredDataUri;\n forceUpdate();\n\n if (cache.size >= MAX_CACHE_SIZE) {\n cache.clear();\n }\n cache.set(dataUri, blurredDataUri);\n };\n\n if (delay) {\n timeoutRef.current = window.setTimeout(() => {\n img.src = dataUri;\n }, delay);\n } else {\n img.src = dataUri;\n }\n }, [dataUri, delay, forceUpdate, isDisabled]);\n\n return blurredRef.current;\n}\n","import { useRef } from '../lib/teact/teact';\n\nimport fastBlur from '../lib/fastBlur';\nimport useOnChange from './useOnChange';\nimport useBlur from './useBlur';\nimport { imgToCanvas } from '../util/files';\n\nconst RADIUS = 2;\nconst ITERATIONS = 2;\n\nexport default function useBlurSync(dataUri: string | false | undefined) {\n const blurredRef = useRef<string>();\n\n let isChanged = false;\n\n useOnChange(() => {\n isChanged = true;\n\n blurredRef.current = undefined;\n\n if (!dataUri) {\n return;\n }\n\n const img = new Image();\n img.src = dataUri;\n if (!img.width) {\n return;\n }\n\n const canvas = imgToCanvas(img);\n fastBlur(canvas.getContext('2d'), 0, 0, canvas.width, canvas.height, RADIUS, ITERATIONS);\n\n blurredRef.current = canvas.toDataURL();\n }, [dataUri]);\n\n // Sometimes `Image` do not manage to load synchronously,\n // so we fall back the non-blurred variant and prepare the async one at least for the next time\n const blurredAsync = useBlur(dataUri || undefined, Boolean(blurredRef.current));\n\n return blurredRef.current || (!isChanged && blurredAsync) || dataUri || undefined;\n}\n"],"sourceRoot":""} |