tweb/public/13.234dc6639cd6dd1f11ca.chu...

1 line
2.8 MiB
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{"version":3,"sources":["webpack:///./src/components/passwordInputField.ts","webpack:///./src/helpers/bytes/bytesCmp.ts","webpack:///./src/helpers/dom/placeCaretAtEnd.ts","webpack:///./src/components/monkeys/password.ts","webpack:///./src/components/monkeys/tracking.ts","webpack:///./src/components/codeInputField.ts","webpack:///./src/components/telInputField.ts","webpack:///./src/environment/mediaMimeTypesSupport.ts","webpack:///./src/helpers/filterChatPhotosMessages.ts","webpack:///./src/helpers/listLoader.ts","webpack:///./src/helpers/searchListLoader.ts","webpack:///./src/components/appSearch.ts","webpack:///./src/components/inputSearch.ts","webpack:///./src/components/buttonIcon.ts","webpack:///./src/components/sliderTab.ts","webpack:///./src/components/slider.ts","webpack:///./src/components/avatarEdit.ts","webpack:///./src/components/buttonCorner.ts","webpack:///./src/components/sidebarLeft/tabs/newGroup.ts","webpack:///./src/components/appMediaPlaybackController.ts","webpack:///./src/helpers/schedulers/throttleWithRaf.ts","webpack:///./src/helpers/schedulers/throttleWith.ts","webpack:///./src/helpers/formatBytes.ts","webpack:///./src/helpers/string/toHHMMSS.ts","webpack:///./src/helpers/dom/attachGrabListeners.ts","webpack:///./src/components/rangeSelector.ts","webpack:///./src/components/mediaProgressLine.ts","webpack:///./src/components/audio.ts","webpack:///./src/components/divAndCaption.ts","webpack:///./src/components/chat/replyContainer.ts","webpack:///./src/helpers/array/accumulate.ts","webpack:///./src/components/groupedLayout.ts","webpack:///./src/components/editPeer.ts","webpack:///./src/components/radioForm.ts","webpack:///./src/components/row.ts","webpack:///./src/helpers/clipboard.ts","webpack:///./src/components/radioField.ts","webpack:///./src/components/toast.ts","webpack:///./src/components/usernameInputField.ts","webpack:///./src/components/popups/peer.ts","webpack:///./src/components/sidebarRight/tabs/chatType.ts","webpack:///./src/helpers/scrollableLoader.ts","webpack:///./src/components/appSelectPeers.ts","webpack:///./src/components/popups/pickUser.ts","webpack:///./src/components/sidebarRight/tabs/userPermissions.ts","webpack:///./src/components/sidebarRight/tabs/groupPermissions.ts","webpack:///./src/components/popups/deleteDialog.ts","webpack:///./src/components/sidebarRight/tabs/chatReactions.ts","webpack:///./src/components/sidebarRight/tabs/editChat.ts","webpack:///./src/components/sidebarRight/tabs/editContact.ts","webpack:///./src/components/sidebarLeft/tabs/addMembers.ts","webpack:///./src/environment/parallaxSupport.ts","webpack:///./src/components/generateFakeIcon.ts","webpack:///./src/components/generateTitleIcons.ts","webpack:///./src/components/generateVerifiedIcon.ts","webpack:///./src/components/swipeHandler.ts","webpack:///./src/components/peerProfileAvatars.ts","webpack:///./src/components/peerProfile.ts","webpack:///./src/components/sidebarRight/tabs/sharedMedia.ts","webpack:///./src/components/sidebarRight/index.ts","webpack:///./src/components/sidebarRight/tabs/pollResults.ts","webpack:///./src/components/stackedAvatars.ts","webpack:///./src/components/poll.ts","webpack:///./src/helpers/dom/createVideo.ts","webpack:///./src/components/wrappers.ts","webpack:///./src/helpers/dom/positionElementByIndex.ts","webpack:///./src/helpers/sortedList.ts","webpack:///./src/components/sortedUserList.ts","webpack:///./src/helpers/dom/handleHorizontalSwipe.ts","webpack:///./src/helpers/dom/handleTabSwipe.ts","webpack:///./src/components/buttonMenu.ts","webpack:///./src/components/popups/forward.ts","webpack:///./src/components/popups/deleteMessages.ts","webpack:///./src/components/popups/sendNow.ts","webpack:///./src/helpers/dom/cancelSelection.ts","webpack:///./src/components/chat/selection.ts","webpack:///./src/helpers/dom/getSelectedText.ts","webpack:///./src/components/appSearchSuper..ts","webpack:///./src/helpers/dom/lockTouchScroll.ts","webpack:///./src/components/buttonMenuToggle.ts","webpack:///./src/lib/appManagers/appPrivacyManager.ts","webpack:///./src/components/privacySection.ts","webpack:///./src/components/sidebarLeft/tabs/privacy/phoneNumber.ts","webpack:///./src/helpers/dom/anchorCopy.ts","webpack:///./src/components/sidebarLeft/tabs/2fa/passwordSet.ts","webpack:///./src/helpers/dom/canFocus.ts","webpack:///./src/components/sidebarLeft/tabs/2fa/emailConfirmation.ts","webpack:///./src/components/sidebarLeft/tabs/2fa/email.ts","webpack:///./src/components/sidebarLeft/tabs/2fa/hint.ts","webpack:///./src/components/sidebarLeft/tabs/2fa/reEnterPassword.ts","webpack:///./src/components/sidebarLeft/tabs/2fa/enterPassword.ts","webpack:///./src/components/sidebarLeft/tabs/2fa/index.ts","webpack:///./src/components/sidebarLeft/tabs/privacy/lastSeen.ts","webpack:///./src/components/sidebarLeft/tabs/privacy/profilePhoto.ts","webpack:///./src/components/sidebarLeft/tabs/privacy/forwardMessages.ts","webpack:///./src/components/sidebarLeft/tabs/privacy/addToGroups.ts","webpack:///./src/components/sidebarLeft/tabs/privacy/calls.ts","webpack:///./src/components/sidebarLeft/tabs/activeSessions.ts","webpack:///./src/components/sidebarLeft/tabs/blockedUsers.ts","webpack:///./src/helpers/string/convertKeyToInputKey.ts","webpack:///./src/components/sidebarLeft/tabs/privacyAndSecurity.ts","webpack:///./src/helpers/averageColor.ts","webpack:///./src/helpers/color.ts","webpack:///./src/helpers/highlightningColor.ts","webpack:///./src/components/chat/gradientRenderer.ts","webpack:///./src/components/colorPicker.ts","webpack:///./src/components/sidebarLeft/tabs/backgroundColor.ts","webpack:///./src/components/sidebarLeft/tabs/background.ts","webpack:///./src/components/popups/stickers.ts","webpack:///./src/helpers/eachMinute.ts","webpack:///./src/helpers/eachTimeout.ts","webpack:///./src/environment/geolocationSupport.ts","webpack:///./src/components/sidebarLeft/tabs/quickReaction.ts","webpack:///./src/components/sidebarLeft/tabs/generalSettings.ts","webpack:///./src/components/sidebarLeft/tabs/editProfile.ts","webpack:///./src/components/sidebarLeft/tabs/includedChats.ts","webpack:///./src/components/sidebarLeft/tabs/editFolder.ts","webpack:///./src/components/sidebarLeft/tabs/chatFolders.ts","webpack:///./src/components/sidebarLeft/tabs/notifications.ts","webpack:///./src/components/sidebarLeft/tabs/language.ts","webpack:///./src/components/confirmationPopup.ts","webpack:///./src/components/sidebarLeft/tabs/autoDownload/photo.ts","webpack:///./src/components/sidebarLeft/tabs/autoDownload/file.ts","webpack:///./src/components/sidebarLeft/tabs/autoDownload/video.ts","webpack:///./src/components/sidebarLeft/tabs/dataAndStorage.ts","webpack:///./src/components/sidebarLeft/tabs/settings.ts","webpack:///./src/components/sidebarLeft/tabs/newChannel.ts","webpack:///./src/components/popups/createContact.ts","webpack:///./src/components/sidebarLeft/tabs/contacts.ts","webpack:///./src/components/sidebarLeft/tabs/archivedTab.ts","webpack:///./src/components/sidebarLeft/tabs/peopleNearby.ts","webpack:///./src/helpers/number/formatNumber.ts","webpack:///./src/components/sidebarLeft/index.ts","webpack:///./src/components/chat/bubbleGroups.ts","webpack:///./src/components/popups/datePicker.ts","webpack:///./src/components/stickyIntersector.ts","webpack:///./src/components/chat/reaction.ts","webpack:///./src/components/chat/reactions.ts","webpack:///./src/components/chat/replies.ts","webpack:///./src/components/chat/messageRender.ts","webpack:///./src/helpers/dom/getElementByPoint.ts","webpack:///./src/helpers/dom/reflowScrollableElement.ts","webpack:///./src/lib/appManagers/appEmojiManager.ts","webpack:///./src/components/emoticonsDropdown/tabs/emoji.ts","webpack:///./src/components/gifsMasonry.ts","webpack:///./src/components/emoticonsDropdown/tabs/gifs.ts","webpack:///./src/components/emoticonsDropdown/tabs/stickers.ts","webpack:///./src/lib/appManagers/appInlineBotsManager.ts","webpack:///./src/components/sidebarRight/tabs/gifs.ts","webpack:///./src/components/sidebarRight/tabs/stickers.ts","webpack:///./src/helpers/dropdownHover.ts","webpack:///./src/components/emoticonsDropdown/index.ts","webpack:///./src/environment/webrtcSupport.ts","webpack:///./src/environment/callSupport.ts","webpack:///./src/helpers/dom/getVisibleRect.ts","webpack:///./src/lib/appManagers/internalLink.ts","webpack:///./src/components/popups/joinChatInvite.ts","webpack:///./src/helpers/scrollSaver.ts","webpack:///./src/helpers/dom/superIntersectionObserver.ts","webpack:///./src/components/chat/bubbles.ts","webpack:///./src/helpers/dom/copyFromElement.ts","webpack:///./src/lib/mtproto/constants.ts","webpack:///./src/helpers/dom/getViewportSlice.ts","webpack:///./src/components/popups/unpinMessage.ts","webpack:///./src/helpers/dom/isSelectionEmpty.ts","webpack:///./src/components/popups/reportMessagesConfirm.ts","webpack:///./src/components/popups/reportMessages.ts","webpack:///./src/components/popups/sponsored.ts","webpack:///./src/components/popups/reactedList.ts","webpack:///./src/components/chat/reactionsMenu.ts","webpack:///./src/components/chat/contextMenu.ts","webpack:///./src/components/chat/sendContextMenu.ts","webpack:///./src/components/popups/createPoll.ts","webpack:///./src/helpers/getGifDuration.ts","webpack:///./src/components/popups/newMedia.ts","webpack:///./src/helpers/dom/attachListNavigation.ts","webpack:///./src/components/chat/autocompleteHelper.ts","webpack:///./src/components/chat/stickersHelper.ts","webpack:///./src/components/popups/schedule.ts","webpack:///./src/helpers/dom/getRichValueWithCaret.ts","webpack:///./src/components/chat/emojiHelper.ts","webpack:///./src/components/chat/autocompletePeerHelper.ts","webpack:///./src/components/chat/commandsHelper.ts","webpack:///./src/components/chat/autocompleteHelperController.ts","webpack:///./src/components/chat/mentionsHelper.ts","webpack:///./src/components/chat/replyKeyboard.ts","webpack:///./src/components/chat/inlineHelper.ts","webpack:///./src/components/chat/botCommands.ts","webpack:///./src/components/chat/input.ts","webpack:///./src/helpers/dom/setCaretAt.ts","webpack:///./src/components/chat/pinnedContainer.ts","webpack:///./src/components/volumeSelector.ts","webpack:///./src/components/chat/audio.ts","webpack:///./src/components/chat/pinnedMessageBorder.ts","webpack:///./src/components/chat/pinnedMessage.ts","webpack:///./src/helpers/dom/handleScrollSideEvent.ts","webpack:///./src/environment/groupCallSupport.ts","webpack:///./src/components/popups/mute.ts","webpack:///./src/components/chat/topbar.ts","webpack:///./src/components/sidebarRight/tabs/search.ts","webpack:///./src/components/chat/search.ts","webpack:///./src/components/chat/patternRenderer.ts","webpack:///./src/components/chat/chat.ts","webpack:///./src/helpers/autoDownload.ts","webpack:///./src/components/chat/markupTooltip.ts","webpack:///./src/helpers/dom/getSelectedNodes.ts","webpack:///./src/helpers/generatePathData.ts","webpack:///./src/components/chat/dragAndDrop.ts","webpack:///./src/helpers/dom/disableTransition.ts","webpack:///./src/components/lineBlobDrawable.ts","webpack:///./src/components/topbarWeave.ts","webpack:///./src/helpers/dom/customProperties.ts","webpack:///./src/lib/rlottie/rlottieIcon.ts","webpack:///./src/components/superIcon.ts","webpack:///./src/components/groupCall/microphoneIcon.ts","webpack:///./src/components/groupCall/participantMutedIcon.ts","webpack:///./src/components/groupCall/index.ts","webpack:///./src/components/groupCall/participantStatus.ts","webpack:///./src/components/groupCall/participantsList.ts","webpack:///./src/helpers/dom/controlsHover.ts","webpack:///./src/components/call/videoCanvasBlur.ts","webpack:///./src/components/groupCall/participantVideo.ts","webpack:///./src/components/groupCall/participantVideos.ts","webpack:///./src/components/groupCall/participants.ts","webpack:///./src/components/groupCall/description.ts","webpack:///./src/components/groupCall/title.ts","webpack:///./src/environment/screenSharingSupport.ts","webpack:///./src/components/call/button.ts","webpack:///./src/components/movableElement.ts","webpack:///./src/helpers/movablePanel.ts","webpack:///./src/helpers/toggleClassName.ts","webpack:///./src/lib/calls/callState.ts","webpack:///./src/components/call/description.ts","webpack:///./src/components/groupCall/microphoneIconMini.ts","webpack:///./src/components/call/index.ts","webpack:///./src/lib/calls/helpers/parseSignalingData.ts","webpack:///./src/lib/calls/callConnectionInstance.ts","webpack:///./src/lib/crypto/subtle.ts","webpack:///./src/lib/crypto/utils/sha256.ts","webpack:///./src/helpers/bytes/convertToUint8Array.ts","webpack:///./src/lib/calls/p2P/p2PEncryptor.ts","webpack:///./src/lib/calls/p2P/chromeP2PSdpBuilder.ts","webpack:///./src/lib/calls/p2P/firefoxP2PSdpBuilder.js","webpack:///./src/lib/calls/p2P/safariP2PSdpBuilder.js","webpack:///./src/lib/calls/p2P/p2PSdpBuilder.js","webpack:///./src/lib/calls/callInstance.ts","webpack:///./src/lib/calls/p2P/getCallProtocol.ts","webpack:///./src/lib/calls/p2P/getRtcConfiguration.ts","webpack:///./src/components/topbarCall.ts","webpack:///./src/lib/appManagers/appCallsManager.ts","webpack:///./src/lib/appManagers/appImManager.ts","webpack:///./src/lib/mediaPlayer.ts","webpack:///./src/components/appMediaViewerBase.ts","webpack:///./src/helpers/fillPropertyValue.ts","webpack:///./src/components/appMediaViewer.ts","webpack:///./src/helpers/avatarListLoader.ts","webpack:///./src/components/appMediaViewerAvatar.ts","webpack:///./src/components/avatar.ts","webpack:///./src/components/dialogsContextMenu.ts","webpack:///./src/lib/mtproto/connectionStatus.ts","webpack:///./src/components/sendingStatus.ts","webpack:///./src/components/connectionStatus.ts","webpack:///./src/helpers/roundRect.ts","webpack:///./src/components/groupCallActiveIcon.ts","webpack:///./src/helpers/easing/easeInOutSine.ts","webpack:///./src/lib/appManagers/appDialogsManager.ts","webpack:///./public/recorder.min.js","webpack:///./src/components/scrollable.ts","webpack:///./src/components/checkboxField.ts","webpack:///./src/helpers/dom/toggleDisability.ts","webpack:///./src/helpers/dom/findUpTag.ts","webpack:///./src/lib/mtproto/passwordManager.ts","webpack:///./src/helpers/array/randomize.ts"],"names":["PasswordInputField","options","super","plainText","passwordVisible","onVisibilityClick","e","this","toggleVisible","classList","toggle","input","type","onVisibilityClickAdditional","setAttribute","name","autocomplete","stealthy","document","createElement","add","tabIndex","parentElement","prepend","insertBefore","cloneNode","nextSibling","container","append","addEventListener","bytesCmp","bytes1","bytes2","len","length","i","placeCaretAtEnd","el","ignoreTouchCheck","activeElement","focus","window","getSelection","createRange","range","selectNodeContents","collapse","sel","removeAllRanges","addRange","body","createTextRange","textRange","moveToElementText","select","PasswordMonkey","passwordInputField","size","needFrame","loadPromise","loadAnimationAsAsset","loop","autoplay","width","height","noCache","then","_animation","animation","currentFrame","direction","setSpeed","pause","setDirection","curFrame","play","waitForFirstFrame","remove","TrackingMonkey","inputField","max","playAnimation","value","frame","Math","min","round","idleAnimation","stop","canvas","style","display","Promise","all","CodeInputField","lastLength","setLabel","replace","slice","setValueSilently","onFill","TelInputField","label","pasted","lastValue","telEl","HTMLInputElement","inputMode","pixelRatio","devicePixelRatio","letterSpacing","setProperty","originalFunc","bind","formattedPhoneNumber","abs","formatted","country","countryCode","leftPattern","code","dataset","onInput","key","test","metaKey","ctrlKey","shiftKey","preventDefault","concat","Set","filterChatPhotosMessages","forEachReverse","history","message","idx","arr","action","photo","splice","undefined","count","previous","next","reverse","loadCount","loadWhenLeft","loadedAllUp","loadedAllDown","safeAssign","loadedAll","current","setLoaded","dispatchJump","items","item","pop","unshift","push","shift","load","onJump","toPrevious","leftLength","go","down","loadPromiseDown","loadPromiseUp","older","resolve","anchor","promise","loadMore","result","forEach","processed","processItem","onLoadedMore","backLimit","maxId","mid","searchContext","incrementMessageId","getSearch","peerId","limit","inputFilter","_","next_rate","nextRate","filterMids","onHistoryDelete","msgs","shouldBeDeleted","has","filter","onEmptied","onHistoryMultiappend","obj","folderId","mids","sorted","Array","from","sort","a","b","targets","map","Boolean","onMessageSent","rootScope","isInner","otherSideLoader","storage","isScheduled","getScheduledMessagesStorage","getMessagesStorage","filterMessagesByInputFilterFromStorage","context","useSearch","setSearchContext","reset","ret","goUnsafe","goToOtherEnd","unsetCurrent","changed","removeEventListener","cleanup","clearable","className","clickable","autonomous","onFound","list","createChatList","nameEl","setListClickListener","innerHTML","childElementCount","setActive","clear","searchInput","searchGroups","onSearch","minMsgId","loadedCount","foundCount","searchPromise","searchTimeout","query","listsContainer","threadId","scrollable","messages","setVirtualContainer","onChange","searchMore","onScrolledBottom","trim","setTimeout","res","searchGroup","fromId","addDialogAndSetLastMessage","drawStatus","avatarSize","meAsSaved","err","console","error","replaceContent","catch","placeholder","prevValue","timeout","clearTimeout","onClearClick","onClear","searchIcon","clearBtn","icon","slider","destroyable","_constructor","header","closeBtn","noRipple","title","content","addTab","listenerSetter","closeTab","args","init","selectTab","tabs","delete","removeAll","eventListener","dispatchEvent","onCloseAfterTimeout","historyTabIds","canHideFirst","onCloseBtnClick","appNavigationController","findItemByType","navigationType","back","id","animate","isNavigation","closingId","onCloseTab","tab","_selectTab","Map","tabsContainer","sidebarEl","querySelector","querySelectorAll","get","onOpen","onOpenAfterTimeout","pushItem","onPop","canAnimate","indexOfAndSplice","tabConstructor","preserveTab","removeTabFromHistory","find","t","getTab","removeByType","onClose","open","getContext","clearRect","uploadAvatar","isGeoChat","setTitle","avatarEdit","_upload","section","inputWrapper","groupNameInputField","maxLength","groupLocationInputField","canBeEdited","valueCheck","contains","userLocationCoords","userLocationAddress","nextBtn","createChannel","about","geo_point","address","megagroup","chatId","inputFile","editPhoto","peerIds","inviteToChannel","disabled","createChat","toUserId","chatsSection","nameArgs","new","format","startLocating","userId","dom","addDialogNew","dialog","rippleEnabled","lastMessageSpan","getUserStatusString","navigator","geolocation","getCurrentPosition","location","lat","coords","latitude","long","longitude","uri","fetch","response","json","display_name","GeolocationPositionError","SHOULD_USE_SAFARI_FIX","userAgent","match","appMediaPlaybackController","media","scheduled","mediaDetails","waitingMediaForLoad","waitingScheduledMediaForLoad","waitingDocumentsForLoad","playbackRates","voice","video","audio","seekBackward","details","playingMedia","currentTime","seekOffset","seekForward","duration","seekTo","seekTime","onMediaDocumentLoad","doc","getDoc","docId","supportsStreaming","handleSafariStreamable","cacheContext","appDownloadManager","getCacheContext","src","url","playbackRate","set","onPlay","target","pip","getMessageByMedia","setMedia","verify","element","listLoader","getCurrent","getPrevious","jumpLength","findIndex","getNext","setTargets","getPlayingDetails","onPause","onEnded","isTrusted","lockedSwitchers","paused","clean","s","playingMediaType","playItem","getMedia","resolveWaitingForLoadMedia","goRound","browserPlay","bindBrowserCallback","browserPause","browserStop","browserSeekBackward","browserSeekForward","browserSeekTo","browserNext","browserPrevious","seekToStart","cssText","mediaSession","actions","seekbackward","seekforward","seekto","previoustrack","nexttrack","setActionHandler","warn","properties","_key","dispatchPlaybackParams","Object","defineProperties","getPlaybackParams","volume","muted","params","_volume","_muted","_playbackRate","_loop","_round","autoload","pFlags","is_scheduled","getMediaFromMessage","media_unread","myId","readMessages","once","deferred","w","waitingStorage","downloadDoc","safariBuffering","pictureInPictureElement","artwork","isVoice","artist","thumbs","bytes","sizes","h","preloadPhoto","setNewMediadata","peerPhoto","getPeerPhoto","loadAvatar","cached","getPeerTitle","attribute","attributes","file_name","performer","metadata","MediaMetadata","getScheduledMessageByPeer","getMessageByPeer","playbackParams","cb","willBePlayedMedia","deepEqual","copy","prev","addMedia","mediaType","getPlaybackMediaTypeFromMessage","wasPlaying","willBePlayed","toggleSwitchers","playPaused","enabled","throttleWithRaf","fn","schedulerFn","waiting","_args","throttleWith","formatBytes","decimals","dm","floor","log","parseFloat","pow","toFixed","toHHMMSS","str","leadZero","sec_num","parseInt","hours","minutes","seconds","attachGrabListeners","onStart","onMove","onEnd","onMouseMove","event","x","pageX","y","pageY","onMouseUp","onMouseDown","button","onTouchMove","touches","clientX","clientY","isTouch","onTouchEnd","onTouchStart","passive","mousedown","events","withTransition","useTransform","vertical","scrub","rect","getBoundingClientRect","seek","setFilled","onScrub","filled","step","setProgress","stepStr","index","indexOf","_removeListeners","percents","clamp","transform","rectMax","offsetAxisValue","bottom","left","streamable","progressRAF","onLoadedData","r","requestAnimationFrame","cancelAnimationFrame","setLoadProgress","onTimeUpdate","onProgress","removeListeners","filledLoad","setSeekMax","setListeners","setHandlers","scrubTime","isSafariBuffering","buf","buffered","numRanges","nearestStart","end","start","wrapVoiceMessage","audioEl","out","waveform","Uint8Array","valueCount","dataView","DataView","buffer","byteIndex","bitShift","getUint16","decodeWaveform","svg","svgContainer","availW","barHeightMax","mediaSizes","isMobile","minW","maxW","createElementNS","setAttributeNS","normValue","wfSize","barCount","maxValue","maxDelta","html","barX","sumI","bar_value","barWidth","insertAdjacentHTML","createWaveformBars","fakeSvgContainer","waveformContainer","timeDiv","progress","throttledTimeUpdate","addAudioListener","readyPromise","mousemove","offsetX","MouseEvent","targetTouches","cancelEvent","noop","constructDownloadPreloader","tryAgainOnFail","preloader","cancelable","construct","circle","totalLength","attr","elem","findMediaTargets","anchorMid","isBubbles","findUpClassName","justAudioSelector","selectors","matches","prefix","selector","join","elements","mediaItems","toPeerId","HTMLElement","withTime","voiceAsMusic","showSender","isRealVoice","isOutgoing","is_outgoing","uploading","durationStr","firstElementChild","downloadDiv","onTypeLoad","descriptionEl","audioAttribute","parts","wrapEmojiText","date","wrapSenderToPeer","titleEl","middleEllipsisEl","fontWeight","sizeType","setInnerHTML","wrapSentTime","subtitleDiv","launched","progressLine","lastChild","replaceWith","wrapAudio","audioTimeDiv","onLoad","readyState","HAVE_CURRENT_DATA","onTypeDisconnect","getTimeStr","innerText","togglePlay","hadSearchContext","imgs","wrapped","wrapPhoto","boxWidth","boxHeight","loadPromises","withoutPreloader","lazyLoadQueue","images","thumb","full","img","attach","autoDownload","shouldPlay","onDownloadInit","pauseListener","notifyAll","done","total","cancel","Error","reject","playListener","download","setDownloadFunction","capture","isConnected","customElements","define","DivAndCaption","fill","border","subtitle","wrapReplyDivAndCaption","subtitleEl","mediaEl","limitSymbols","isRound","mediaChildren","children","middleware","textContent","wrapMessageForReply","webpage","chat","bubbles","getMiddleware","wrapSticker","div","group","CHAT_ANIMATION_GROUP","choosePhotoSize","noBlur","child","isMediaSet","accumulate","initialValue","reduce","acc","RectPart","maxWidth","minWidth","spacing","maxHeight","ratios","countRatios","proportions","countProportions","averageRatio","maxSizeRatio","layout","layoutTwo","layoutThree","layoutFour","layoutTwoTopBottom","layoutTwoLeftRightEqual","layoutTwoLeftRight","layoutThreeLeftAndOther","layoutThreeTopAndOther","layoutFourTopAndOther","layoutFourLeftAndOther","geometry","sides","minimalWidth","secondWidth","firstWidth","firstHeight","thirdHeight","secondHeight","rightWidth","leftWidth","thirdWidth","h0","w0","w2","w1","h1","h2","ratio","cropRatios","attempts","multiHeight","offset","sum","pushAttempt","lineCounts","heights","first","second","third","fourth","optimalAttempt","optimalDiff","attempt","counts","lineCount","totalHeight","minLineHeight","bad1","bad2","line","diff","optimalCounts","optimalHeights","rowCount","row","colCount","lineHeight","col","_disabled","isChanged","changedLength","requiredLength","requiredValidLength","inputFields","isValid","required","handleChange","toggleAttribute","withoutAvatar","avatarElem","updateWithOptions","doNotEditAvatar","unlockOnSuccess","RadioForm","radios","form","checked","freezed","radioField","checkboxField","subtitleLangKey","subtitleLangArgs","havePadding","isToggle","titleRight","noCheckboxSubtitle","titleLangKey","c","titleRightSecondary","titleRightEl","navigationTab","ripple","RadioFormFromRows","rows","copyTextToClipboard","text","clipboard","writeText","textArea","top","position","appendChild","execCommand","removeChild","fallbackCopyTextToClipboard","alignRight","stateKey","appStateManager","getState","state","getDeepProperty","setByKey","main","langKey","Event","toastEl","toast","toastNew","langPackKey","langPackArguments","checkUsernameDebounced","debounce","checkUsername","getValue","originalValue","setState","Neutral","isUsernameValid","setError","invalidText","head","username","checkUsernamePromise","invokeApi","channel","getChannelInput","toChatId","available","Valid","availableText","takenText","isValidToChange","buttons","overlayClosable","avatarEl","isDialog","noTitle","titleLangArgs","fragment","createDocumentFragment","descriptionLangKey","description","p","descriptionLangArgs","checkboxes","o","withRipple","callback","original","nextElementSibling","isBroadcast","random","privateRow","publicRow","privateSection","publicSection","getChat","linkRow","chatFull","exported_invite","link","btnRevoke","getChatInviteLink","show","caption","noDelimiter","linkInputField","applyBtn","migrateChat","channelId","updateUsername","close","setOriginalValue","toggleDisability","toggleNoForwards","onChatUpdate","noforwards","loading","loaded","getPromise","checkForTriggers","chatsContainer","selected","offsetIndex","loadedWhat","renderedPeerIds","peerType","multiSelect","exceptSelf","tempIds","selfPresence","needSwitchList","includes","cachedContacts","getMoreResults","f","renderResultsFunc","renderResults","splitUp","notRendered","filterPeerTypeBy","isPeerId","getPeer","deleted","method","innerContainer","topContainer","selectedContainer","selectedScrollable","li","click","sectionNameLangPackKey","noShadow","findUpAttribute","checkbox","debouncedInput","generateDelimiter","appendTo","getResultsPromise","onFirstRender","testSelfSearch","dialogs","archived","pageCount","windowSize","tempId","getTempId","getConversations","newOffsetIndex","findAndSplice","d","chatRightsAction","filterByRights","renderSaved","isEnd","getMoreDialogs","contacts","getMoreContacts","isUser","canSendToUser","hasRights","isGlobalSearch","getContactsPeerIds","searchContacts","searchResult","resultPeerIds","my_results","results","filterUnique","channelParticipants","getChannelParticipants","q","participants","participant","getParticipantPeerId","promises","getMoreChannelParticipants","isNonContactUser","containerEl","isAnyChat","getChatMembersString","scroll","insertAdjacentElement","scrollIntoViewNew","offsetWidth","onAnimationEnd","settings","animationsEnabled","values","forceDirection","Static","closable","getSelected","onSelect","hide","peerTypes","destroyListener","rights","takeOut","banned_rights","editBanned","btnDeleteException","clearChannelParticipantBannedRights","btnDelete","kickFromChannel","v","flags","exceptionText","toggleWith","defaultBannedRights","default_banned_rights","combineParticipantBannedRights","restrictionText","info","mainFlag","restriction","until_date","flag","chatPermissions","editChatDefaultBannedRights","addExceptionRow","openPermissions","getChannelParticipant","generateContentElement","findUpTag","setSubtitle","bannedRights","cantWhat","getPeerId","peer","listEl","update","needAdd","new_participant","view_messages","user_id","prev_participant","exceptionsCount","setLength","loader","setLoader","isChannel","migrateFrom","migrateTo","onScroll","getDialogType","peerTitleElement","callbackLeave","flush","leave","finally","flushHistory","callbackDelete","descriptionArgs","deleteChannel","isDanger","textArgs","availableReactions","getActiveAvailableReactions","getChatFull","originalReactions","available_reactions","enabledReactions","toggleSection","toggleCheckboxField","toggleRow","reactionsSection","checkboxFields","availableReaction","reaction","saveReactionsDebounced","wrapStickerToRow","static_icon","every","saveReactions","newReactions","getCachedFullChat","setChatAvailableReactions","chatUpdateListeners","addChatUpdateListener","canChangeType","canChangePermissions","chatNameInputField","descriptionInputField","editPeer","chatTypeRow","setChatTypeSubtitle","reactionsRow","setReactionsLength","availableReactionsLength","getAvailableReactions","inactive","reactions","permissionsRow","setPermissionsLength","editTitle","editAbout","race","removeAttribute","signMessagesCheckboxField","signatures","toggleSignatures","showChatHistoryCheckboxField","togglePreHistoryHidden","hidden_prehistory","_init","isNew","isContact","nameInputField","lastNameInputField","user","getUser","setDraftValue","first_name","last_name","notificationsCheckboxField","togglePeerMute","isMuted","notify_settings","profileNameDiv","profileSubtitleDiv","phoneRow","phone","formatUserPhone","notificationsRow","isPeerLocalMuted","addContact","deleteContacts","skippable","attachToPromise","removeLoader","isPrivacy","selectedPeerIds","addInitial","generateFakeIcon","isScam","span","generateTitleIcons","verified","use","use2","generateVerifiedIcon","fake","scam","getEvent","attachGlobalListenerTo","RESET_GLOBAL","visible","cursor","listenerOptions","hadMove","xDown","yDown","handleMove","setCursorTo","onReset","handleStart","_e","verifyTouchTarget","xUp","yUp","xDiff","yDiff","onFirstSwipe","onSwipeResult","onSwipe","photoId","avatar","BASE_CLASS","getPhoto","Image","draggable","loadCallback","putAvatar","avatars","intersectionObserver","observe","loadCallbacks","gradient","arrowPrevious","arrowNext","checkScrollTop","scrollTop","freeze","clickX","prevTargets","nextTargets","openAvatarViewer","toRight","right","distance","offsetLeft","cancelNextClick","lastDiffX","minX","swipeHandler","lastX","SCALE","TRANSLATE_TEMPLATE","addIndex","ceil","IntersectionObserver","entries","entry","isIntersecting","loadNearestToTarget","getUserPhotos","photos","Number","MAX_SAFE_INTEGER","m","chat_photo","generateFakeAvatarMessage","activeTab","photo_id","unobserve","setText","setPeerStatus","needClear","attachClickEvent","bio","tagName","getProfileByPeerId","notifications","setMoreDetails","fillUsername","self","fillUserPhone","setAvatar","setPeerStatusInterval","setInterval","setMoreDetailsTimeout","canBeDetailed","oldAvatars","setPeer","getPeerUsername","fillNotifications","cleaned","cleanupHTML","fillRows","override","isRestricted","callbackify","peerFull","wrapRichText","exportedInvite","historiesStorage","newCloseBtn","animatedCloseIcon","transitionContainer","transitionFirstItem","editBtn","transitionLastItem","secondTitle","profile","onAdditionalScroll","searchSuper","nav","setIsSharedMedia","isSharedMedia","transition","cleanScrollPositions","isHeavyAnimationInProgress","toggleEditBtn","msgIdsByPeer","renderNewMessages","deleteDeletedMessages","mediaTabs","onChangeTab","mediaTab","btnAddMembers","scrollStartCallback","showConfirmation","onError","addChatUser","filtered","filterMessagesByType","usedFromHistory","performSearchResult","selection","isSelecting","toggleByElement","canViewMembers","loadMutex","peerChanged","setQuery","historyStorage","fillProfileElements","single","justLoad","getElementById","isColumnProportionSet","to","medium","mobile","toggleSidebar","setColumnProportion","sharedMediaTab","proportion","scrollWidth","previousElementSibling","documentElement","enable","active","willChange","animationPromise","appSidebarRight","resultsDiv","poll","getPoll","quiz","question","voters","total_voters","roundPercents","hr","answer","answers","answerEl","answerTitle","answerPercents","minHeight","getVotes","option","votesList","votes","vote","showMore","lastElementChild","next_offset","avatarContainer","AVATAR_CLASS_NAME","CLASS_NAME","updateOptions","parentNode","lineTotalLength","minIndex","minRemainder","k","remainder","maxRemainder","pollElement","isClosed","closed","performResults","chosenIndexes","prevQuizHint","hideQuizHint","prevQuizHintOnHide","prevQuizHintTimeout","setMaxLength","resizePolls","onHide","isQuiz","isRetracted","isPublic","isMultiple","chosingIndexes","sentVote","MAX_LENGTH","MAX_OFFSET","svgLines","setLineProgress","getTotalLength","pollId","descKey","public_voters","multiple_choice","multipleSelect","descDiv","typeDiv","avatarsDiv","close_period","close_date","timeLeftDiv","quizTimer","strokeWidth","radius","circumference","PI","period","closeTime","serverTimeOffset","quizInterval","time","Date","now","timeLeft","color","stroke","strokeDashoffset","strokeDasharray","clearInterval","getResults","answerDivs","numberDivs","footerDiv","viewResults","votersCountDiv","isTabExists","sendVoteBtn","sendVotes","canVote","setVotersCount","clickHandler","solution","solution_entities","toggleHint","textEl","entities","bubblesContainer","setQuizHint","correctResult","correct","chosen","answerIndex","foundIndex","indexes","sendVotePromise","sendVote","initQuizHint","timeEl","setResults","recent_voters","stackedAvatars","render","isVoted","hideSendVoteBtn","hideViewResultsBtn","maxPercents","getPercentValue","iterate","fullTime","votersCount","multiplier","createVideo","disablePictureInPicture","roundVideoCircumference","wrapVideo","withTail","isOut","noInfo","onlyPreview","noPlayButton","autoDownloadSize","noAutoDownload","isAlbumItem","canAutoplay","autoPlay","gifs","videos","spanTime","spanPlay","needPlayButton","mime_type","photoRes","divRound","halfSize","ctx","globalVideo","setPeerPromise","isInDOM","onPaused","onFrame","drawImage","onClick","detached","foreignObject","getAttributeNS","gotThumb","getThumb","poster","aspecter","isUpload","downloaded","attachMethod","renderDeferred","detach","isFulfilled","animationIntersector","addAnimation","videoWidth","sequentialDom","mutateElement","loadPhotoThumbFunc","loadFunc","setManual","queueId","renderImageFromUrl","wrapDocument","audioElement","extSplitted","split","ext","isArray","toLowerCase","docDiv","icoDiv","fileName","wrapPlainText","descriptionParts","nameDiv","_downloadDiv","save","canOpenAfter","downloading","saveDocFile","noThumb","noFadeIn","blurAfter","setAttachmentSize","regular","thumbImage","image","isFit","loadThumbPromise","isGif","photoSize","getStrippedThumbIfNeeded","needFadeIn","renderOnLoad","renderImageWithFadeIn","toDataURL","canAttachPreloader","renderPromise","mutate","wrapStickerAnimation","side","skipRatio","animationDiv","stickerPromise","withThumb","assumeType","frameNo","maxFrame","vibrate","generateRandomSigned","randomOffsetX","randomOffsetY","stableOffsetX","setPosition","emojiAnimationContainer","onlyThumb","emoji","needUpscale","static","asStatic","stickerType","sticker","loadLottieWorkers","toneIndex","isAnimated","isThumbNeededForType","haveThumbCached","stickerCachedThumbs","afterRender","getPathFromPhotoPathSize","path","stickerThumbConverted","getPreviewURLFromThumb","webpWorkerController","convert","getThumbURL","blob","loadAnimationWorker","animationData","saveLottiePreview","data","sendInteractionThrottled","preloadAnimatedEmojiStickerAnimation","getAnimation","getAnimatedEmojiSoundDocument","restart","getAnimatedEmojiSticker","bubble","throttle","firstTime","setTyping","msg_id","getServerMessageId","emoticon","interaction","JSON","stringify","isSavingLottiePreview","wrapStickerSetThumb","downloadOptions","getStickerSetThumbDownloadOptions","animated","lottieLoader","URL","createObjectURL","getStickerSet","stickerSet","documents","previousMedia","createMedia","_size","wrapReply","replyContainer","prepareAlbum","widthItem","heightItem","borderTopLeftRadius","borderBottomLeftRadius","borderTopRightRadius","borderBottomRightRadius","forMedia","mediaDiv","wrapAlbum","groupId","attachmentDiv","getMidsByAlbum","getMessage","album","positionElementByIndex","pos","prevPos","whichChild","updateElementWith","updateListWith","onSort","canUpdate","_updateList","batch","updateBatch","base","onElementCreate","noScheduler","onDelete","getIndex","onUpdate","insertInDescendSortedArray","getUserStatusForSort","onListLengthChange","status","willChangeLength","createChatListOptions","doTimeout","updateList","good","SORT_INTERVAL","handleHorizontalSwipe","cancelY","isSwipingBackSafari","handleTabSwipe","ButtonMenuItem","noCheckboxClickListener","textElement","regularText","keepOpen","peerIdMids","overrideOnSelect","setInnerPeer","initMessagesForward","onConfirm","revoke","deleteScheduledMessages","deleteMessages","titleArgs","isMegagroup","canRevoke","sendScheduledMessages","cancelSelection","empty","accumulateMapSet","selectedMids","doNotAnimate","onCancelSelection","toggleSelection","listenElement","selectedText","toString","verifyTouchLongPress","getElementFromTarget","getElementsBetween","last","firstRect","lastRect","isHigher","parent","lookupBetweenParentClassName","lookupBetweenElementsQuery","firstIndex","lastIndex","targetLookupClassName","verifyTarget","seen","selecting","firstTarget","processElement","checkBetween","seenSet","isSelected","isMidSelected","seenLength","findUpAsChild","elementsBetween","toggleByMid","canceledSelection","verifyMouseMoveTarget","removeManual","documentListenerOptions","hasCheckbox","getCheckboxInputFromElement","isElementShouldBeSelected","appendCheckbox","forceSelection","cantForward","cantDelete","cantSend","appMessagesManager","getMessageFromStorage","canForward","canDeleteMessage","onUpdateContainer","toggleCheckboxes","wasSelecting","blurActiveElement","forwards","onToggleSelection","updateContainer","toggleElementCheckbox","unselect","config","forwarded_count_max","toggleMid","updateElementSelection","contentTab","selectionCountEl","selectionGotoBtn","selectionForwardBtn","selectionDeleteBtn","navScrollableContainer","selectionContainer","btnCancel","attachClickOptions","keys","fromPeerId","isPrivate","transitionElement","opacity","recording","canSelectBubble","isGroupedBubbleSelected","getMidsByMid","getBubbleGroupedItems","groupContainer","isGroupedSelected","isGroupedMidsSelected","mounted","getMountedBubble","needTranslateX","widthFrom","widthTo","center","selectionInputWrapper","selectionSendNowBtn","selectionLeft","selectionRight","translateButtonsX","inputContainer","isGrouped","groupedCheckboxInput","attachTo","onGotoClick","onForwardClick","onSelectClick","onClearSelectionClick","onDeleteClick","onContextMenu","cancelBubble","withSelection","prevTabId","urlsToRevoke","nextRates","loadedChats","firstLoad","logger","monthContainers","mediaTabsMap","asChatList","groupByMonth","hideEmptyTabs","onTransitionStart","onTransitionEnd","searchContextMenu","navScrollable","tabsMenu","menuTab","unlockScroll","prevId","lockers","lockTouchScroll","searchGroupMedia","horizontalMenu","tabContent","skipScroll","startCallback","newMediaTab","fromMediaTab","offsetTop","scrollHeight","rect2","onMediaClick","targetClassName","copySearchContext","openMedia","inputMessagesFilterPhotoVideo","inputMessagesFilterDocument","useHeavyAnimationCheck","lock","unlockAndRefresh","filterMessagesByInputFilter","setLastMessage","elemsToAppend","entity","totalEntities","display_url","sliced","matchUrl","same","hostname","hash","previewDiv","getAbbreviation","wrapTitle","subtitleFragment","wrapDescription","htmlToDocumentFragment","HTMLAnchorElement","decodeURIComponent","href","firstChild","sharedMediaDiv","processCallback","processEmptyFilter","processPhotoVideoFilter","processDocumentFilter","processUrlFilter","monthContainer","getMonthContainerByTimestamp","afterPerforming","inputMessagesFilterEmpty","showMembersCount","participants_count","regExp","RegExp","escapeRegExp","cleanSearchText","titleSpan","formatPhoneNumber","arg","globalContacts","intlElement","IntlElement","isShort","minDate","renderRecentSearch","recent","recentSearch","getTopPeers","peers","people","onlyFirstName","renderParticipants","membersList","LOAD_COUNT","loadMembers","loadChats","logStr","used","slicedLength","ids","filters","counters","getSearchCounters","firstMediaTab","counter","membersTab","toLoad","loadType","timestamp","setHours","setDate","dateTimestamp","getTime","containers","month","getFullYear","year","dateElement","IntlDateElement","haveTimestamps","getObjectKeysAndSort","goFirst","revokeObjectURL","newInputFilter","maxDate","ButtonMenuToggleHandler","openedMenu","PrivacyType","asDiv","btnMenu","appPrivacyManager","privacy","addMultipleEventsListeners","updatePrivacy","rules","inputKey","privacyRules","saveApiUsers","users","saveApiChats","chats","apiUpdatesManager","processLocalUpdate","convertInputKeyToKey","inputRule","rule","assign","privacyKey","types","allowPeers","disallowPeers","onRadioChange","captions","captionElement","radioSection","exceptions","Everybody","Nobody","radioRows","Contacts","skipTypes","noExceptions","generateSection","exceptionTexts","exception","_peerIds","newPeerIds","generateStr","splitPeersByType","getPrivacy","getPrivacyRulesDetails","setRadio","chatKey","usersKey","splitted","getUserInput","setPrivacy","captionEl","mePath","anchorCopy","phoneSection","stickerContainer","inputContent","btnReturn","sliceTabsUntilTab","canFocus","isFirstInput","isFirst","email","codeInputField","passwordManager","confirmPasswordEmail","goNext","btnChange","btnResend","disable","cancelPasswordEmail","resendPasswordEmail","onContinueClick","btnContinue","btnSkip","matchEmail","toggleButtons","updateSettings","hint","currentPassword","plainPassword","newPassword","symbols","isCancel","onSkipClick","saveHint","monkey","verifyInput","has_password","labelText","getStateInterval","_state","check","auth","btnChangePassword","btnDisablePassword","btnSetRecoveryEmail","has_recovery","btnSetPassword","Session","app_name","app_version","ip","date_active","date_created","midtitle","device_model","system_version","platform","authorizations","session","btnTerminate","otherSection","onTerminateClick","menuElement","btnAdd","toggleBlock","bot","blocked","getBlocked","convertKeyToInputKey","toUpperCase","blockedPeerIds","blockedUsersRow","passwordState","twoFactorRow","email_unconfirmed_pattern","activeSessionsRow","updateActiveSessions","setBlockedCount","updateBlocked","rowsByKeys","numberVisibilityRow","lastSeenTimeRow","photoVisibilityRow","callRow","linkAccountRow","groupChatsAddRow","updatePrivacyRow","disallowLength","allowLength","sensitive_can_change","sensitive_enabled","sensitiveRow","_enabled","deleteButton","clearAllDrafts","auths","averageColorFromCanvas","pixel","pixels","getImageData","pixelsLength","outPixel","Uint8ClampedArray","rgbaToHsla","g","l","hslaToRgba","hue2rgb","hexaToRgba","hexa","hexToRgb","hex","rgbaToHexa","rgba","hslaStringToHexa","hsla","alpha","val","endsWith","hslaStringToRgba","highlightningColor","_width","_height","_tails","_scrollTails","_curve","_positions","_phases","onWheel","_animatingToNextPosition","_scrollDelta","deltaY","_onWheelRAF","drawOnWheel","changeTail","curPos","curPosition","_phase","_tail","drawGradient","drawNextPositionAnimated","frames","_frames","drawImageData","_incrementalCurve","positions","phase","curveMax","curve","getPositions","distances","nextPos","tail","getNextPositions","_hctx","createImageData","centerDistanceY","centerDistanceY2","centerDistanceX","swirlFactor","sqrt","theta","sinTheta","sin","cosTheta","cos","pixelX","pixelY","distanceSum","_colors","distanceX","distanceY","putImageData","_ctx","_hc","getGradientImageData","colors","getAttribute","_canvas","fillStyle","fillRect","tails","nextPhaseOnIdx","inc","curves","_addedScrollListener","scrollAnimate","createCanvas","gradientRenderer","hue","saturation","lightness","onGrabStart","boxDragger","onGrabEnd","box","sliders","hueDragger","hexInputField","rgbInputField","inputs","valid","setColor","rgbRegExp","attachBoxListeners","attachHueListeners","boxRect","saturationHandler","hueRect","hueHandler","updateHexInput","updateRgbInput","hexaToHsla","rgb","boxX","percentY","boxY","percentHue","hueX","updatePicker","rgbaArray","hsl","getCurrentColor","maxX","maxY","posX","posY","lightnessX","lightnessY","_applyColor","updateColorPicker","colorPicker","background","theme","intensity","slug","pushToState","applyCurrentTheme","onColorChange","applyColor","getTheme","gridSection","grid","backgroundColor","isColored","uploadTempId","clicked","wallpapersByElement","elementsByKey","onUploadClick","file","access_hash","dc_id","file_reference","saveDoc","wallpaper","upload","addNotifyListener","_wallpaper","newDoc","newCacheContext","setBackgroundDocument","getWallpaperKey","addWallPaper","onResetClick","defaultTheme","themes","blurCheckboxField","blur","onGridClick","saveToCache","cacheStorage","_tempId","onReady","getPixelPromise","imageUrl","naturalWidth","naturalHeight","averageColor","create","getColorsFromWallpaper","getWallpaperKeyFromTheme","uploadButton","colorButton","resetButton","pattern","invokeApiHashable","accountWallpapers","wallpapers","gridContainer","background_color","second_background_color","third_background_color","fourth_background_color","hasFile","isDark","dark","webkitMaskImage","stickerSetInput","onStickersClick","fileId","sendMessageWithDocument","h6","setOnlyOnePlayableGroup","stickersDiv","stickersFooter","btn","loadStickerSet","installed_date","toggleStickerSet","esgSticker","eachMinute","runFirst","getNextTimeout","_callback","run","eachTimeout","getSeconds","getQuickReaction","quickReaction","setDefaultReaction","minValue","writeValue","valueDiv","valueContainer","messagesTextSize","chatBackgroundButton","animationsCheckboxField","enterRow","ctrlEnterRow","kilometersRow","milesRow","formats","toLocaleTimeString","hour","minute","suggestCheckboxField","bigCheckboxField","renderQuickReaction","loopCheckboxField","stickerSets","stickersContent","renderStickerSet","getAllStickers","allStickers","sets","firstNameInputField","bioInputField","usernameInputField","setProfileUrl","profileUrlContainer","profileUrlAnchor","updateProfile","uploadProfilePhoto","getSelf","userFull","getProfile","getContacts","foundInFilters","dialogsByFilters","onSelectChange","confirmBtn","cmp","pinnedPeerIds","pinned_peers","other","otherLegacy","getInputPeerById","editFolderTab","setFilter","filtersStorage","getDialogFilters","dialogsStorage","getFolderDialogs","categoriesSection","exclude_muted","ico","exclude_archived","exclude_read","non_contacts","groups","broadcasts","bots","selectedPeers","includePeerIds","excludePeerIds","addedInitial","_add","hasOwnProperty","originalFilter","deleteFolderButton","updateDialogFilter","bool","menuBtn","inputSection","generateList","h2Text","categories","includedFlagsContainer","excludedFlagsContainer","include","include_peers","createDialogFilter","editCheckForChange","reloadMissingPromises","reloadMissingPeerIds","loadAnimationPromise","player","documentFragmentToHTML","wrapDraftText","ul","getDialogOnly","hasPeer","renderMore","_length","onEditOpen","exclude_peers","onCreateOpen","filtersRendered","dialogFilter","folder","channels","isAnyGroup","filterId","getFilter","orderIndex","createFolderBtn","foldersSection","suggestedSection","onFiltersContainerUpdate","renderFolder","getSuggestedFilters","order","suggestedFilters","NotifySection","enabledRow","typeText","previewEnabledRow","inputNotifyPeer","getNotifySettings","notifySettings","applySettings","show_previews","mute","showPreviews","inputSettings","mute_until","updateNotifySettings","contactsSignUpRow","soundRow","sound","getContactSignUpNotification","setContactSignUpNotification","invokeApiCacheable","lang_pack","languages","language","lang_code","native_name","getLangPack","getCacheLangPack","langPack","confirmationPopup","autoDownloadPeerTypeSection","contactsCheckboxField","privateCheckboxField","groupsCheckboxField","channelsCheckboxField","debouncedSave","sizeMax","autoDownloadNew","file_size_max","MAX","upTo","compareAndUpdate","AUTO_DOWNLOAD_FOR_KEYS","private","autoCheckboxField","setSubtitles","setAutoDownloadSubtitle","photoRow","videoRow","fileRow","openTab","onDisabledChange","gifsCheckboxField","videosCheckboxField","peerKeys","enabledKeys","isAll","logOut","edit","changeAvatarBtn","updateChangeAvatarBtn","buttonsDiv","devicesRow","languageRow","buttonsSection","overwrite","getAuthorizationsPromise","getAuthorizations","channelNameInputField","channelDescriptionInputField","onLengthChange","broadcast","withConfirm","btnConfirm","importContact","telInputField","lockWithPromise","peerTitle","validate","country_code","inputSearch","openContacts","sortedUserList","createList","renderPage","sortedLists","chatList","generateScrollable","scrollables","wasFilterId","setFilterId","onTabChange","isLocationWatched","errorCategory","retryBtn","locatedPeers","dialogSize","parseDistance","peopleSection","sortedList","btnMakeVisible","makeButton","btnMakeInvisible","btnCreateGroup","startWatching","stopWatching","distanceUnit","latestLocationSaved","accuracy","getLocated","updates","orderedPeers","groupsCounter","usersCounter","watchPosition","isLongitudeDifferent","isLatitudeDifferent","distanceCheck","calculateDistance","lat1","long1","lat2","long2","asin","formatNumber","fakeGradientDelimiter","delimiter","appSidebarLeft","sidebarHeader","onContactsClick","backBtn","btnArchive","isDialogsLoaded","themeCheckboxField","filteredButtons","openUrl","sessionStorage","kz_version","isMainDomain","toolsBtn","btnMenuFooter","rel","stopPropagation","suffix","versionFull","newBtnMenu","updateBtn","reload","initSearch","archivedCount","unreadDialogsCount","navigationItem","noHistory","requestPeer","checkUpdateInterval","cache","ok","hasUpdate","searchContainer","pickedElements","selectedPeerId","selectedMinDate","selectedMaxDate","updatePicked","removeProperty","helper","unselectEntity","renderEntity","dates","dateData","peopleContainer","hideNewBtnMenuTimeout","onFocus","clearRecentSearchBtn","releaseSinglePeer","detailsMap","newGroupDiff","updateGroup","viaBotId","fwdFromId","removeBubble","insertObject","foundBubble","foundAtIndex","foundMidOnSameTimestamp","_timestamp","_mid","bubbleGroup","insertIndex","initDate","onPick","noButtons","selectedDate","onPrevClick","selectedMonth","setMonth","getMonth","minMonth","prevBtn","onNextClick","maxMonth","onDateClick","selectedEl","setTimeTitle","setFullYear","getDate","controlsDiv","monthTitle","monthsContainer","handleTimeInput","onOverflow","maxString","hoursInputField","minutesInputField","number","setMinutes","getMinutes","getHours","popupCenterer","timeOptions","sendDate","dateOptions","day","weekday","firstDate","weekStartDate","getDay","renderElement","dayIndex","clonedDate","showOverflowMonths","lines","StickyIntersector","handler","observeHeaders","observeElements","headersObserver","targetInfo","boundingClientRect","stickyTarget","rootBoundsInfo","rootBounds","threshold","root","elementsObserver","sentinel","headerSentinel","addSentinel","disconnect","_reactionCount","reactionCount","canRenderAvatars","doNotRenderSticker","hadStickerContainer","getReaction","center_icon","wrapPromise","wrapStickerPromise","displayOn","recentReactions","peer_id","isChosen","REACTION_INLINE_SIZE","REACTION_BLOCK_SIZE","around_animation","iconPlayer","aroundPlayer","REACTIONS_ELEMENTS","onConnectCallback","reactionElement","isPlaceholder","disconnectedCallback","connectedCallback","changedResults","hasReactions","availableReactionsResult","isReactionActive","some","totalReactions","can_see_list","reactionElementIdx","recent_reactions","setCanRenderAvatars","renderCounter","renderAvatars","setIsChosen","handleChangedResults","childNodes","timeSpan","fireAroundAnimation","updated","postKey","replies","leftPart","recent_repliers","isUnread","read_max_id","max_id","textSpan","iconSpan","rippleContainer","subscribeRepliesThread","updateMessage","makeEdited","edited","makeSponsored","MessageRender","setTime","chatType","editedSpan","sponsoredSpan","reactionsElement","reactionsMessage","isSponsored","sponsored","isMessage","views","postAuthor","post_author","fwd_from","postViewsSpan","channelViews","edit_date","edit_hide","pinned","getGroupsFirstMessage","inner","clonedArgs","_reactionsElement","renderReplies","bubbleContainer","messageDiv","isFooter","repliesFooter","setReply","isReplacing","currentReplyDiv","reply_to_mid","replyToPeerId","reply_to","reply_to_peer_id","appPeersManager","originalPeerTitle","originalMessage","wrapSingleMessage","needUpdate","replyMid","getElementByPoint","verticalSide","horizontalSide","elementFromPoint","reflowScrollableElement","EMOJI_LANG_PACK","keywords","version","langCode","langPackCode","keywordLangPacks","indexedLangPacks","getKeywordsPromises","storageKey","stateStorage","pack","isObject","validateInitObject","from_version","keywordsDifference","packKeywords","keyword","emoticons","getEmojiKeywords","lastRequestedLangCode","getRecentEmojis","indexObject","emojis","indexEmojis","search","POPULAR_EMOJI","getRecentEmojisPromise","recentEmoji","fixEmoji","appEmojiManager","loadedURLs","appendEmoji","unify","spanEmoji","kek","wrapSingleEmoji","getEmojiFromElement","nodeType","nodeValue","closeScrollTop","onContentClick","onEmojiSelected","divs","category","titleDiv","itemsDiv","unified","menu","emojiScroll","hasRecent","activeId","menuOnClick","stickyIntersector","setMenuActive","recentItemsDiv","observeStickyHeaderChanges","scrollPromise","processInvisibleDiv","intersector","isVisible","getAnimations","checkAnimation","processVisibleDiv","gifWidth","gifHeight","willUseWidth","calcImageInBox","gifsContainer","masonry","EMOTICONSSTICKERGROUP","addLazyLoadQueueRepeat","regularLazyLoadQueue","animatedDivs","checkAnimationContainer","renderSticker","observeAnimatedDiv","recentStickers","queueCategoryPush","categoryDiv","categoryTitle","superStickerRenderer","recentDiv","stickers","categoryPush","menuWrapper","menuScroll","getRecentStickers","pushRecentSticker","inlineResults","setHash","geo","accuracy_radius","botId","getGeoInput","stopTime","noErrorBox","botResults","queryId","query_id","savePhoto","generateQId","resultId","topPeers","botPeerId","topPeer","rating","setKeyValueToStorage","startParam","startBot","bot_inline_placeholder","peerData","setDraft","callbackAnswer","noLinks","noLinebreaks","queryAndResultIds","inlineResult","pushPopularBot","queryID","resultID","send_message","reply_markup","replyMarkup","sendText","inputMedia","sendMessage","getMediaInput","geoPoint","provider","venue_id","venue_type","phone_number","vcard","percent","sendOther","appInlineBotsManager","nextOffset","onGifsClick","gifsDiv","checkAnimations","newSearch","gifBotPeerId","resolveUsername","getInlineResults","setsDiv","countDiv","stickerDiv","renderFeatured","getFeaturedStickers","coveredSets","filterRendered","renderSet","covered","searchStickerSets","forceClose","inited","onMouseOut","displayTimeout","isActive","toElement","willBeActive","dispatchResultableEvent","onmouseout","onmouseover","tabId","onSelectTabClick","searchButton","deleteBtn","checkRights","tabsEl","tabsElements","canSendStickers","canSendToPeer","canSendGifs","chatInput","savedRange","getGoodRange","lockIntersectionGroup","unlockIntersectionGroup","unlock","refresh","emojiTab","stickersTab","gifsTab","0","1","2","messageInput","HIDE_EMOJI_TAB","INIT_TAB_ID","getVisible","clearVisible","rangeCount","getRangeAt","jumpedTo","stuck","which","scrollLeft","clearDraft","emoticonsDropdown","getVisibleRect","overflowElement","lookForSticky","overflowRect","overflowTop","overflowRight","overflowBottom","overflowLeft","sticky","overflow","horizontal","visualViewport","windowWidth","innerWidth","windowHeight","innerHeight","INTERNAL_LINK_TYPE","chatInvite","request_needed","processUpdateMessage","putPhoto","peopleCount","numberThousandSplitter","clientHeight","scrollHeightMinusTop","useReflow","previousScrollHeightMinusTop","newScrollTop","setScrollTopSilently","SuperIntersectionObserver","observing","observingQueue","freezedObservingNew","observer","callbacks","queue","IGNORE_ACTIONS","SERVICE_AS_REGULAR","TEST_SCROLL","appStickersManager","appUsersManager","appPhotosManager","appProfileManager","appDraftsManager","appMessagesIdsManager","appChatsManager","appReactionsManager","appWebPagesManager","unreadOut","skippedMids","dateMessages","scrolledDown","isScrollingTimeout","unreaded","unreadedSeen","messagesQueuePromise","messagesQueue","messagesQueueOnRender","messagesQueueOnRenderAdditional","firstUnreadBubble","replyFollowHistory","isFirstLoad","passEntities","viewsMids","isTopPaddingSet","unreadedObserverCallback","onUnreadedInViewport","viewsObserverCallback","sendViewCountersDebounced","sponsoredMessage","random_id","apiManager","invokeApiSingle","onBubblesMouseMove","unhoverPrevious","hoverBubble","hoverReaction","setHoverVisible","stickerWrapper","getAvailableReactionsByMessage","select_animation","sendReaction","onBubblesClick","chatInner","onDatePick","contactDiv","appImManager","callDiv","callUser","spoiler","showDuration","useRafs","spoilerTimeout","getReactionCount","bubbleMid","reply_to_top_id","lastMsgId","saved_from_msg_id","openThread","filterMessages","getDiscussionMessage","channel_id","via","peerIdStr","savedFrom","messageId","documentDiv","groupedItem","SINGLE_MEDIA_CLASSNAME","isSingleMedia","isMediaCompatibleForDocumentViewer","parents","hasAspecter","albumItem","getMidsByMessage","isReplyClick","replyToMid","reply_to_msg_id","ignoreHeavyAnimation","scrollDimensions","sliceViewportDebounced","topbar","pinnedMessage","setCorrectIndexThrottled","lastScrollDirection","setStickyDateManually","distanceToEnd","getDistanceToEnd","requestHistory","setMessageId","setScroll","bubbleGroups","changeBubbleMid","setBubblePosition","scrollingToBubble","scrollToEnd","deleteMessagesByIds","tempMessage","reactionsElements","changeMessage","repliesElement","newDiv","grouped_id","newPoll","safeRenderMessage","scrollToBubbleIfLast","getGroupedBubble","updatePosition","scrollSaver","restore","deleteEmptyDateGroups","getBubbleByMessage","appendReactionsElementToBubble","deletedMids","renderedId","renderMaxId","groupedMessagesStorage","replyAfter","shouldReply","canSend","_target","initMessageReply","highlightBubble","dateMessage","dateBubble","previousStickyDate","sliceViewport","renderNewMessagesByIds","toNextPosition","msgIds","setUnreadCount","updateUnreadByDialog","finishPeerChange","isScrolledDown","setMessagesQueuePromise","performHistoryResult","postViewsElements","different","postViews","toggleObservingNew","incrementMessageViews","resizeObserver","wasHeight","resizing","skip","scrolled","part","rAF","onResizeEnd","offsetHeight","setEndRAF","ResizeObserver","contentRect","realDiff","_part","needScrollTop","readUnreaded","readPromise","idle","focusPromise","bubblesMaxId","getHistoryStorage","readContents","isMentionUnread","readHistory","bad","grouped","getHistoryTopPromise","getHistoryBottomPromise","getHistory","onScrolledTop","loadMoreHistory","readMaxId","readOutboxMaxId","msgId","permanent","ignoreOnScroll","emptyPlaceholderMid","ignoreNextScrollEvent","deleteSelectedMids","setPaddingTo","isPaddingNeeded","paddingTop","unsetPadding","replyTo","getLastBubble","setTopPadding","scrollToBubbleEnd","lastDateGroup","getLastDateGroup","forceDuration","fallbackToElementStartWhenCentering","isChangingHeight","margin","axis","getNormalSize","dimensions","lastScrollPosition","scrollToBubble","lastElem","lastTime","firstTimestamp","datasetKey","today","bubbleContent","serviceMsg","createDateBubble","fakeBubble","bubblesToo","attachedUnreadBubble","fetchNewPromise","getSponsoredMessagePromise","onAnimateLadder","resolveLadderAnimation","cancelMeasure","samePeer","topMessage","pinnedMessages","isTarget","followingUnread","savedPosition","overrideAdditionMsgId","getChatSavedPosition","getReadMaxIdIfUnread","unread_count","foundSlice","findSliceOffset","Bottom","isJump","setStartParam","setQueueId","messageEntityBotCommand","isBot","additionMsgId","maxBubbleId","getBubbleByPoint","destroyResizeObserver","oldChatInner","haveToScrollToBubble","fromUp","scrollFromDown","scrollFromUp","willScrollOnLoad","lockGroup","unlockGroup","mountedByLastMsgId","findNextMountedBubbleByMsgId","lastBubble","onRenderScrollSet","afterSetPromise","fetchReactions","getMessagesReactions","needFetchInterval","isFetchIntervalNeeded","getNewHistory","isBottomEnd","onScrolledAllDown","unread_mark","markDialogUnread","canWrite","createResizeObserver","setUnreadDelimiter","local","getDateContainerByMessage","STICKY_OFFSET","addBubble","additionalCallback","multipleRender","albumMustBeRenderedFull","our","contentWrapper","wasClassNames","classNames","transitionDelay","originalMid","unread","chat_id","wrapMessageActionTextNew","renderMessagesQueue","is_single","messageMessage","messageMedia","getAlbumText","richText","canHaveTail","isStandaloneMedia","needToSetHTML","emojiEntities","strLength","curr","big","forward","containerDiv","rowDiv","buttonEl","same_peer","checkSwitchReturn","switchInlineQuery","column","callbackButtonClick","messageWithReplies","getMessageWithReplies","withReplies","fwdFrom","nameContainer","canHideNameIfMedia","processingWebPage","previewResizer","preview","quote","quoteTextDiv","mediaSize","site_name","strong","textDiv","isSquare","emojiSticker","animatedSticker","staticSticker","newNameContainer","wrapper","wrapGroupedDocuments","lastContainer","formatCallDuration","reason","contact","contactDetails","contactNameDiv","contactNumberDiv","wrapPoll","needName","titleVia","isForwardFromChannel","from_id","isHidden","from_name","getPeerColorById","goto","generateTail","documentContainer","documentMessageDiv","renderMessage","isBackLimit","hadScroll","getRenderedLength","viewportSlice","getViewportSlice","deleteViewportSlice","saved","getSaved","needReflowScroll","processLocalMessageRender","firstSlice","lastSlice","Top","getScheduledMessages","additionMsgIds","isAdditionRender","animateAsLadder","targetMid","sortedMids","topIds","middleIds","bottomIds","setBubbles","delay","lastMsDelay","topRes","middleRes","bottomRes","delays","listElements","getRestrictionReasonText","getGreetingSticker","renderEmptyPlaceholder","channel_post","generateMessageId","start_param","chat_invite","chat_invite_hash","JOIN_CHAT","invite","processInternalLink","creator","addOffset","service","generateLocalMessageId","getOutputPeer","saveMessages","extraSize","invisibleTop","invisibleBottom","foundVisible","visibleRect","array","minTop","maxBottom","ignoreScrollSaving","invisible","checkPlaceholders","cacheSeconds","sponsoredMessages","generateLocalFirstMessage","bot_info","checkIfEmptyPlaceholderNeeded","Both","resultPromise","isFirstMessageRender","processResult","historyResult","serviceStartMessageId","threadsServiceMessagesIdsStorage","sup","processPromise","waitPromise","times","mustBeCount","unpin","canUnpin","canPinMessage","oneSide","silent","unpinAllMessages","hidePinnedMessages","updatePinnedMessage","buttonText","pinButtonText","isSelectionEmpty","selectionRange","START_TO_END","reportMessages","STICKER_EMOJI","preloadStickerPromise","preloadAnimatedEmojiSticker","buttonsEl","marginTop","canViewReadParticipants","canViewMessageReadParticipants","newMessage","btnClose","loaders","hasAllReactions","createFakeReaction","hasReadParticipants","readUserIds","getMessageReadParticipants","chatlist","skipReadParticipants","skipReactionsList","getMessageReactionsListAndReadParticipants","combined","getReactionCached","allReactionsSticker","REACTION_CLASS_NAME","REACTIONS_CLASS_NAME","CAN_USE_TRANSFORM","reactionsMap","players","onScrollProcessItem","reactionDiv","appear","widthContainer","reactionsContainer","reactionsScrollable","animationGroup","setOverrideIdleGroup","renderReaction","setVisible","scaleContainer","appearWrapper","selectWrapper","canUseAnimations","appear_animation","selectLoadPromise","selectPlayer","REACTION_SIZE","appPollsManager","appDocsManager","isSelectable","isTextSelected","isAnchorTarget","isUsernameTarget","selectedMid","isOverBubble","isTargetAGroupedItem","noForwards","viewerPeerId","canOpenReactedList","initResult","destroy","menuPadding","onSendScheduledClick","onReplyClick","onEditClick","initMessageEditing","onCopyClick","onCopyAnchorLinkClick","onCopyLinkClick","threadMessage","onPinClick","onUnpinClick","onRetractVote","onStopPoll","stopPoll","closest","reactionsMenu","hasAttribute","notDirect","scheduleSending","editMessage","scheduleDate","canEditMessage","hasTarget","isGoodType","setButtons","filterButtons","viewsButton","isViewingReactions","participantsCount","reactedLength","i18nElem","fakeText","MAX_AVATARS","PADDING_PER_AVATAR","visibility","paddingRight","reactionsCount","fakeElem","readParticipants","isFull","totalSize","sendMenuButtons","onSilentClick","onScheduleClick","sendMenu","openSide","onContextElement","onSubmitClick","send","radioLabel","isEmpty","isInputEmpty","questions","appendMoreField","correctAnswers","optionInputFields","labelOptions","weakMap","questionInputField","sendSilent","setPeerId","dd","settingsCaption","anonymousCheckboxField","multipleCheckboxField","quizCheckboxField","quizSolutionField","quizElements","quizSolutionCaption","quizHr","quizSolutionContainer","quizSolutionSubtitle","onEscape","getFilledAnswers","getRichValue","quizSolution","force","quizSolutionEntities","inputMediaPoll","getInputMediaPoll","getMessageSendingParams","helperType","clearHelper","questionField","getGifDuration","arrayBuffer","currentPopup","getCurrentNewMediaPopup","files","willAttachType","confirmShortcutIsSendShortcut","onKeyDown","attachFile","willAttach","shouldCompress","itemDiv","attachMedia","attachDocument","sendFileDetails","mediaContainer","caption_length_max","wasInputValue","messageInputField","attachFiles","groupCheckboxField","mediaCheckboxField","toPush","_file","lastModified","isMedia","sendingParams","sendAlbum","replyToMsgId","startsWith","source","objectURL","controls","videoHeight","audioDecodedByteCount","webkitAudioDecodedByteCount","noSound","onload","isPhoto","isAudio","finish","onerror","mimeType","foundPhotos","foundVideos","foundFiles","n","firstType","appendGroupCheckboxField","appendMediaCheckboxField","albumContainer","appendMediaToContainer","onRender","AXIS_Y_KEYS","AXIS_X_KEYS","attachListNavigation","waitForKey","waitForKeySet","keyNames","getCurrentTarget","setCurrentTarget","scrollTo","hadTarget","fastSmoothScroll","getNextTargetX","currentTarget","isNext","nextTarget","handleArrowKey","property","endProperty","currentRect","targetRect","getNextTargetY","fireSelect","canContinue","attached","resetTarget","_onKeyDown","hidden","onVisible","listType","noBlurOnPop","removeItem","attachNavigation","controller","addHelper","fromController","skipAnimation","hideOtherHelpers","onChangeScreen","getStickersByEmoticon","ready","getMinDate","getMaxDate","canSendWhenOnline","btnSendWhenOnline","getRichValueWithCaret","field","withEntities","selNode","selOffset","startOffset","startContainer","endContainer","endOffset","possibleChildrenFocusOffset","node","alt","getRichElementValue","caretPos","substr","combineSameEntities","firstChar","getBothEmojiKeywords","searchEmojis","doNotShow","listElement","BASE","BASE_CLASS_LIST_ELEMENT","processPeerFullForCommands","botInfos","ignoreCase","commands","botInfo","botCommand","command","found","getReadyToSend","helpers","toggleListNavigation","preserveHelper","insertAtCaret","topMsgId","trimmed","getMentions","onBodyTouchStart","btnHover","attachButtonListener","checkAvailability","checkForceReply","touchListener","sendContact","getReplyMarkup","sendInlineResult","_checkQuery","gifsMasonry","isGallery","gallery","noCommands","separator","dcId","readBlobAsDataURL","dataURL","switch_pm","btnSwitchToPM","switchToPM","checkQuery","serverTimeManager","appNotificationsManager","lastUrl","lastTimeType","replyElements","willSendWebPage","recordCanceled","recordStartTime","lockRedo","canRedoFromHTML","undoHistory","executedHistory","canUndoFromHTML","onCancelRecordClick","recorder","opusDecodeController","setKeepAlive","onEmoticonsOpen","toggleClass","btnToggleEmoticons","onEmoticonsClose","isUserOnlineVisible","openScheduled","prepareDocumentExecute","undoRedo","needHTML","sameHTMLTimes","currentHTML","handleMarkdownShortcut","formatKeys","markupTooltip","applyMarkdown","showLinkEditor","onMessageInput","richValue","markdownEntities","parseMarkdown","mergeEntities","parseEntities","urlEntities","getWebPagePromise","webPage","saveWebPage","setTopInfo","noWebPage","onHelperCancel","helperFunc","resetCurrentFormatting","botCommands","updateBotCommandsToggle","editMsgId","saveDraftDebounced","checkAutocomplete","updateSendBtn","getEmojiEntityFromEmoji","onBtnSendClick","forwarding","releaseMediaPlayback","setSingleMedia","setRecording","showDiscardPopup","btnCancelRecord","recordingOverlayListener","recordingNavigationItem","sourceNode","analyser","createAnalyser","connect","fftSize","frequencyData","frequencyBinCount","getByteFrequencyData","recordRippleEl","ms","recordTimeEl","needReturn","onHelperClick","forwardElements","rowsWrapperWrapper","rowsWrapper","fakeRowsWrapper","fakeSelectionWrapper","goDownBtn","onGoDownClick","controlContainer","iconBtn","cancelBtn","onHideAuthorClick","isChangingAuthor","canToggleHideAuthor","onHideCaptionClick","forwardButtons","hideSender","showCaption","hideCaption","changePeer","changeForwardRecipient","forwardBtnMenu","forwardWasDroppingAuthor","replyTitle","forwardHover","modifyArgs","newMessageWrapper","sendAsContainer","sendAsCloseBtn","sendAsButtons","previousAvatar","onSendAsMenuToggle","sendAsAvatar","sendAsBtnMenu","inputMessageContainer","goDownUnreadBadge","goMentionBtn","goMentionUnreadBadge","goToNextMention","btnScheduled","btnToggleReplyMarkup","replyKeyboard","botCommandsToggle","scaler","botCommandsIcon","setUserId","attachMenuButtons","fileInput","accept","attachMenu","multiple","autocompleteHelperController","stickersHelper","emojiHelper","commandsHelper","mentionsHelper","inlineHelper","btnSendContainer","btnSend","attachMessageInputField","previousQuery","onFakeInput","draft","saveDraft","updateSendAs","encoderSampleRate","monitorGain","numberOfChannels","recordingGain","reuseWorker","touchMouseDown","onstop","ondataavailable","typedArray","dataBlob","Blob","decode","sendFile","isVoiceMessage","botStartBtn","toggleBotStartBtnDisability","pinnedControlBtn","originalChat","pinnedMessageContainer","neededFakeContainer","getNeededFakeContainer","fakeWrapperTo","oldFakeWrapperTo","borderRadius","fakeSelectionRect","fakeRowsRect","scale","initTranslateX","br","isStartButtonNeeded","hasMentions","unread_mentions_count","no_webpage","syncDraft","helperToo","clearInput","fromUpdate","getDraft","rMessage","setInputValue","inputFake","updateOffset","hasBotCommands","getUserFullResult","updateBotCommands","sendAsPeerId","updatingSendAsPromise","updateMessageInput","currentPeerId","channelFull","default_send_as","updateSendAsAvatar","updateMessageInputPlaceholder","executeButtonsUpdate","sendAsPeerIds","updateSendAsButtons","send_as","getChannelFull","getDefaultSendAs","updateSendAsResult","getSendAs","isAnonymousSending","oldInputField","attachMessageInputListeners","fixSafariStickyInputFocusing","isSendShortcutPressed","setStart","readAllHistory","commandsMap","bold","italic","underline","strikethrough","monospace","saveExecuted","executed","haveThisType","isCollapsed","tag","commonAncestorContainer","setActiveMarkupButton","insertText","insertEntity","isHelper","fullValue","AUTO_COMPLETE_REG_EXP","matchIndex","newValue","hadEntities","insertLength","addEntities","caretEntity","insertCaretAtIndex","caret","originalNode","previousSibling","newNode","createTextNode","setStartAfter","insertNode","setCaretAt","_value","foundHelper","suggest","checkEmoticon","checkInlineAutocomplete","needPlaceholder","inlineMatch","btnPreloader","inlinePlaceholder","helperWaitingForward","canSetDraft","fireEvent","clearValue","fixSafariStickyInput","clearReply","unicode","pushRecentEmoji","forwardMessages","dropAuthor","dropCaptions","isDroppingCaptions","hideCaptionCheckboxField","replyFragment","fromPeerIdsMids","fromPeerIds","smth","messagesWithCaptionsLength","peerTitles","titleKey","senderTitles","firstMessage","usingFullAlbum","albumMids","newReply","intl","peerTitleEl","_message","callerFunc","replyParent","oldReply","haveReply","floating","divAndCaption","CLASSNAME_BASE","wrapperUtils","attachOnCloseEvent","needClose","isFloating","setFloating","setUtilsWidth","onMuteClick","setVolume","iconIndex","ICONS","onPlaybackParams","fasterEl","repeatEl","toggleEl","onStop","onMediaPlay","isMusic","fromName","volumeSelector","prevEl","nextEl","attachClick","volumeProgressLineContainer","tunnel","progressWrapper","playingDetails","BAR_HEIGHTS","PinnedMessageBorder","drawRect","getClipPath","barHeight","GAP","clipPath","getBarHeight","ONE","TWO","THREE","FOUR","MORE","getMarkHeight","markHeight","getMarkTranslateY","getTrackTranslateY","trackHeight","getTrackHeight","clipPathId","markTranslateY","trackTranslateY","defs","mark","AnimatedSuper","animateFirst","currentIndex","clearRow","DURATION","reflow","clearRows","previousIndex","fromTop","ignorePrevious","setNewRow","previousRow","AnimatedCounter","previousNumber","animatedSuper","decimal","previousDecimalNumber","getRow","EMPTY_INDEX","previousByDecimal","decimalNumber","getDecimal","hideLeft","pinnedMaxMid","pinnedMid","pinnedIndex","wasPinnedIndex","wasPinnedMediaIndex","locked","waitForScrollBottom","loadedBottom","loadedTop","scrollDownListenerSetter","getCurrentIndexPromise","isStatic","debug","dAC","pinnedMessageBorder","animatedSubtitle","animatedMedia","animatedCounter","btnOpen","openPinned","setCorrectIndex","setPinnedMessage","_setPinnedMessage","unsetScrollDownListener","testMid","isNeededMore","getCurrentIndex","LOAD_OFFSET","correctAfter","gotRest","getPinnedMessage","backLimited","offset_id_offset","lastY","isDown","handleScrollSideEvent","refreshPosition","setScrollDownListener","handleFollowingPinnedMessage","isLast","setCount","writeTo","writeMediaTo","mutePeer","tsNow","ONE_HOUR","radioForm","appGroupCallsManager","verifyButtons","isMenuOpen","btnMore","menuButtons","getDeleteButtonText","buttonsToVerify","verifyVideoChatButton","currentGroupCall","groupCall","getChatTyped","call_active","verifyCallButton","getCachedFullUser","phone_calls_available","video_calls_available","onJoinGroupCallClick","joinGroupCall","onResize","resize","setUtilsRAF","chatUtils","chatAudio","btnBack","chatInfoContainer","chatInfo","person","avatarElement","btnJoin","btnPinned","btnCall","btnGroupCall","btnMute","btnSearch","pushButtonToVerify","followPinnedMessage","getSearchContext","activeScreen","onBtnBackClick","isFirstChat","linked_chat_id","onCallClick","chatContextMenuHintWasShown","contactPeerId","joinChannel","setMutedState","isTopMessage","hiddenPinnedMessages","byCurrent","wasPeerId","newPinnedMessage","appSearch","beginSearch","btnPickDate","selectedIndex","onResultsClick","selectResult","onFooterClick","onUpClick","onDownClick","foundCountEl","upBtn","downBtn","footer","dateBtn","renderedCount","canvases","instance","INSTANCES","fillCanvas","renderImageFromUrlPromise","crossOrigin","objectUrl","CanvasPattern","imageWidth","imageHeight","mask","globalCompositeOperation","large","setCanvasDimensions","renderToCanvas","backgroundEl","Log","Warn","Debug","backgroundTempId","patternRenderer","gradientCanvas","previousGradientRenderer","previousPatternRenderer","previousPatternCanvas","patternCanvas","isDarkPattern","getInstance","_gradientRenderer","setBackgroundPromise","contextMenu","constructUtils","constructPeerHelpers","constructPinnedHelpers","constructDiscussionHelpers","constructScheduledHelpers","setReactionsHoverListeners","cleanupBackground","searchTab","setAutoDownloadMedia","setLoadMutex","loadSidebarMedia","photoSizeMax","videoSizeMax","fileSizeMax","photo_size_max","video_size_max","getAutoDownloadSettingsByPeerId","setPrefix","wasAlreadyUsed","addedListener","waitingForMouseUp","mouseUpCounter","onMouseUpSingle","resetSelection","tools1","tools2","cancelClosening","linkBackButton","linkInput","applyLink","isLinkValid","setTooltipPosition","linkApplyButton","applyDiv","delimiter1","delimiter2","delimiter3","matchUrlProtocol","hideTimeout","nodes","getSelectedNodes","currentMarkups","activeButtons","getActiveMarkupButton","isLinkToggle","bodyRect","selectionRect","inputRect","selectionTop","sizesRect","containerRect","isFirstShow","setMouseUpEvent","arcParameter","rx","ry","xAxisRotation","largeArcFlag","sweepFlag","generatePathData","tl","tr","bl","dropIcon","onDragOver","onDragLeave","onDrop","outlineWrapper","dropHeader","dropSubtitle","headerArgs","disableTransition","LineBlobDrawable","maxRadius","minRadius","N","radiusNext","speed","generateBlob","radDif","amplitude","speedScale","paint","pinnedTop","progressToPinned","beginPath","moveTo","lineTo","r1","progressNext","x1","x2","cx","y1","y2","bezierCurveTo","closePath","stateId","createGradient","shader","getGradientFromType","x0","y0","createLinearGradient","MUTED_BY_ADMIN","addColorStop","UNMUTED","MUTED","CONNECTING","dt","handleDevicePixelRatioChanged","setSize","forceUpdate","handleResize","resizeHandler","resizeCanvas","invokeDraw","handleFocus","focused","handleBlur","raf","draw","lbd","lbd1","lbd2","currentState","previousState","progressToState","lastUpdateTime","animateToAmplitude","animateAmplitudeDiff","amplitude2","animateAmplitudeDiff2","top1","top2","paint1","globalAlpha","setCurrentState","states","matchMedia","setAmplitude","setCanvasSize","computedStyle","getProperty","getComputedStyle","getPropertyValue","playPart","createPart","initFrame","skipFirstFrameRendering","inverseColor","onLoadForColor","onLoadForPart","getPart","startFrame","endFrame","frameCount","partState","colorState","getColor","partCallback","changedPartState","changedColorState","setPartState","setColorState","prevState","renderIfPaused","getItem","invoke","GROUP_CALL_MICROPHONE_BUTTON_STATE","partName","HAND","colored","GROUP_CALL_PARTICIPANT_MUTED_STATE","colorStr","MUTED_FOR_ME","propertyValue","getColorByMutedState","generateEqualParts","clearMutedStateModifier","withIcons","icons","iconClassName","element2","actionClassName","onElementDestroy","getGroupCallParticipantMutedState","mutedIcon","mutedState","hideControls","setHideTimeout","hideControlsTimeout","isShown","controlsLocked","canHideControls","showControls","toggleControls","ignoreClickClassName","relatedTarget","showOnLeaveToClassName","callVideoCanvasBlur","renderFrame","groupCallParticipantMutedIcon","groupCallParticipantStatus","updateParticipant","participantsElements","groupCallId","setElementDisplay","pinnedSource","pinSource","unpinAll","setInstance","setup","displayPinned","shouldDisplay","shouldDisplayElement","isPinned","setPinned","hasAnyVideo","participantElements","participantVideo","getVideoElementFromParticipantByType","setParticipant","_onLengthChange","onOpenProfileClick","popup","getPopups","targetPeerId","toggleParticipantMuted","editParticipant","canManageCall","can_self_unmute","muted_by_you","kickFromChat","getParticipantByPeerId","getContainer","groupCallParticipantsVideo","getGroupCallParticipants","descriptionIntl","mediaDevices","_className","buttonDiv","isConfirm","fixDimensions","fixPosition","addResizeHandlers","setSwipeHandler","handlers","resizeHandlerClassName","startTop","startLeft","startWidth","startHeight","resizingSide","isEnlarging","resizeDiff","maxPossible","setCursor","toggleMovable","movable","movableOptions","setPositionToCenter","destroyElements","toggleClassName","raise_hand_rating","withoutOverlay","onFullScreenClick","onToggleControls","buttonsContainer","onVideoClick","btnVideo","toggleVideoSharing","onScreenClick","btnScreen","toggleScreenSharing","toggleMuted","changeRaiseHand","onLeaveClick","hangUp","discard","onFullScreenChange","toggleBigLayout","btnFullScreen","btnExitFullScreen","wasFullScreen","setThemeColor","movablePanel","isBig","videosCount","wasBig","btnInvite","btnShowColumn","toggleRightColumn","btnFullScreen2","headerInfo","newHeader","newHeaderInfo","newHeaderTitle","btnHideColumn","videosScrollable","groupCallTitle","groupCallDescription","groupCallBodyHeaderDescription","constructButtons","groupCallParticipants","updateInstance","setHasPinned","groupCallMicrophoneIcon","_makeButton","microphoneIcon","btnLeave","CLOSED","setDescription","microphoneButtonState","getGroupCallMicrophoneButtonState","micState","CALL_STATE","interval","connectionState","CONNECTED","PENDING","REQUESTING","EXCHANGING_KEYS","connectedAt","INIT_STATE","resizeVideoContainers","videoContainers","interlocutorUserId","emojisSubtitle","partyStates","partyMutedState","stateText","constructFirstButtons","constructSecondButtons","wasTryingToJoin","movableElement","controlsHover","firstButtonsRow","muteI18nElement","secondButtonsRow","declineI18nElement","btnDecline","btnAccept","acceptCall","isPendingIncoming","isSharingVideo","isSharingScreen","outputState","getMediaState","oldContainers","mediaState","getVideoElement","hasFrame","hasPromise","videoState","screencastState","videoContainer","createVideoContainer","output","getEmojisFingerprint","popupWidth","MAX_WIDTH_PX","MAX_HEIGHT_PX","isVertical","MAX_SIZE","biggestSideSize","widthRatio","heightRatio","parseSignalingData","sdp","parseMediaSectionInfo","fingerprints","fingerprint","ufrag","pwd","screencast","convertNumber","isSending","codec","ssrc","sourceGroups","ssrcGroups","sourceGroup","semantics","ssrcs","sources","rtpExtensions","payloadTypesMap","getPayloadType","payloadType","clockrate","feedbackTypes","subtype","parameters","payloadTypes","connection","call","localDescription","remoteDescription","descriptionInit","offerReceived","createAnswer","setLocalDescription","offer","createOffer","offerSent","initialSetup","sendCallSignalingData","crypto","subtle","sha256","digest","TextEncoder","encode","convertToUint8Array","p2pKey","seqMap","bufferConcats","msgKeyLarge","concatSHA256","subarray","msgKey","aesKeyIv","prepareAesKeyIv","aesProcessCtr","seq","ArrayBuffer","setUint32","encryptPrepared","sha256a","sha256b","iv","encryptedData","dataSize","encrypt","cryptoKey","importKey","msgKeyEquals","encryptedDataSize","decryptionBuffer","constTimeIsDifferent","getUint32","stringBuilder","streamName","addExtmap","addPayloadTypes","addSsrc","addDataChannel","finalize","dir","isFirefox","isSafari","extmap","j","fmtp","getOwnPropertyNames","pName","ssrcGroup","sdpString","sdpMLineIndex","sdpMid","foundation","component","protocol","priority","relAddress","generation","tcpType","networkId","networkCost","candidate","generateOffer","generateAnswer","udp_p2p","udp_reflector","min_layer","max_layer","library_versions","createdAt","decryptQueue","candidates","streamManager","canCreateConferenceEntry","lowBattery","videoRotation","Proxy","setMediaState","sendMediaState","mediaStates","_sendMediaState","_connectionState","connectionInstance","iceConnectionState","findEntry","recvEntry","wasStartingScreen","wasStartingVideo","requestScreen","stopVideoSharing","startScreenSharingInternal","requestInputSource","track","inputStream","getVideoTracks","stopTrack","appendToConference","startVideoSharingInternal","isSharingVideoType","audioTrack","getAudioTracks","CLOSING","clearHangUpTimeout","hangUpTimeout","phoneCall","canAccept","isClosing","overrideConnectionState","g_a_hash","appCallsManager","generateDh","dh","g_b","g_a","g_b_hash","getCallInput","phonePhoneCall","savePhonePhoneCall","encryptionKey","configuration","iceServers","connections","ipv6","port","password","urls","turn","stun","credential","iceTransportPolicy","p2p_allowed","getRtcConfiguration","bindPrefix","createPeerConnection","negotiate","sendIceCandidate","onTrack","createDescription","encryptor","decryptor","appendStreamToConference","createDataChannel","processDecryptQueue","dataChannelEntry","createEntry","sendEntry","dataChannel","negotiated","applyDataChannelData","parse","sendDataChannelData","encryptRawPacket","iceCandidate","parsed","p2pParseCandidate","key_fingerprint","computeKey","joinCall","emojisFingerprint","getEmojisFingerprintPromise","invokeCrypto","codePoints","getTransceivers","transceiver","getEntryByMid","bundle","sdpDescription","generateSdp","isAnswer","setRemoteDescription","unlockStreamManager","stream","onInputStream","videoTrack","onMutedChange","requestAudioSource","setMuted","discardReason","discardedByOtherParty","closeConnectionAndStream","hasVideo","discardCall","_codec","setData","transport","performCodec","vp8PayloadType","rtxIdx","apt","filterNotVP8","setDataToDescription","performSsrcGroups","getEntryBySource","sendRecvEntry","findFreeSendRecvEntry","setEntrySource","createDataChannelEntry","tryToReleaseCandidates","doTheMagic","generateCandidate","RTCIceCandidate","addIceCandidate","decryptedData","decryptRawPacket","TextDecoder","signalingData","applyCallSignalingData","appAvatarsManager","onState","amplitudes","weave","currentDescription","instanceListenerSetter","isChangingInstance","clearCurrentInstance","callDescription","convertCallStateToGroupState","componentDidMount","componentWillUnmount","groupCallMicrophoneIconMini","throttledMuteClick","getCallInstance","weaveContainer","calls","instances","sortedInstances","updatePhoneCall","saveCall","phone_call","confirmCall","createCallInstance","admin_id","setPhoneCall","setHangUpTimeout","g_a_or_b","updatePhoneCallSignalingData","phone_call_id","onUpdatePhoneCallSignalingData","audioAsset","callId","isDiscarded","oldCall","safeReplaceObject","getCall","currentCall","hasConnected","playSound","stopSound","playSoundIfDifferent","hasCurrent","random_length","dhConfig","isVideo","fullInfo","participant_id","myVersion","compareVersion","connection_id","FOCUS_EVENT_NAME","columnEl","offline","updateStatusInterval","onHashChange","parseUriParams","tgaddr","replaceState","onclick","wrapUrl","postId","post","openUsername","userName","setSettings","chatsSelectTabDebounced","setLoop","setTimeFormat","timeFormat","toggleChatGradientAnimation","onDocumentPaste","attachType","newMediaPopup","canDrag","DragEvent","_types","dataTransfer","addFiles","backgroundPromises","isIDLE","updateStatus","appendEmojiAnimationContainer","createNewChat","chatsSelectTab","oldVersion","deleteFilesIterative","headers","resizeInstances","saveChatPosition","choosing","setChoosingStickerTyping","typings","overlaysActive","typing","singleInstance","activateInstance","setToCache","topbarCall","discardCurrentCall","setAuthorized","telegramMeWebManager","addAnchorListener","uriParams","hashtag","pathnameParams","STICKER_SET","makeLink","VOICE_CHAT","PHONE_NUMBER_REG_EXP","USER_PHONE_NUMBER","PRIVATE_POST","thread","comment","MESSAGE","domain","attachKeydownListener","timeoutOperation","perf","performance","requests","request","isBad","activatingChat","screen","IGNORE_KEYS","isOverlayActive","altKey","goodMid","nextDialog","newEvent","KeyboardEvent","commentId","resolveChannel","saveApiChat","resolvePhone","wrappedUrl","noPathnameParams","pathname","noUriParams","openComment","generateThreadServiceStartMessage","getCallByUserId","phone_calls_private","startCallInternal","ignoreGroupCall","ignoreCall","discardGroupCallConfirmation","discardCallConfirmation","getGroupCallFull","saveGroupCall","createGroupCall","broadcastEvent","STATE_INIT","getBackground","setBackground","setCurrentBackground","getFile","lastBackgroundUrl","chatBubbles","chatPositions","getFromCache","themeColor","hslaStringToHex","backgroundUrl","applyHighlightningColor","setTheme","prevTab","prevIdx","attachDragAndDropListeners","handleSelection","drops","mediaDrops","mount","isFiles","_dropsContainer","mediaDropsContainer","dropsContainer","_drops","foundMedia","appendDrops","drop","setPath","transitionTime","setUserStatus","fromIndex","justReturn","spliced","chatFrom","beforeDestroy","chatIndex","spliceChats","existingIndex","oldChat","setType","dot","eye","getPeerTypings","langPackKeys","multi","mapa","typingElement","getTypingElement","htmlToSpan","descriptionElement","ignoreSelf","getPeerTyping","onlines","getOnlines","useWhitespace","typingContainer","getPeerStatus","onPlaybackRackMenuToggle","onPip","onPipClose","playbackRateButton","skin","stylePlayer","setBtnMenuToggle","initDuration","buildControls","timeDuration","pipButton","fullScreenButton","timeElapsed","leftControls","requestPictureInPicture","debounceTime","debouncedPip","listener","toggleFullScreen","nextIdx","PLAYBACK_RATES","onFullScreen","setPlaybackRateIcon","pictureInPictureEnabled","rate","PLAYBACK_RATES_ICONS","webkitEnterFullscreen","enterFullscreen","topButtons","author","preloaderStreamable","isFirstOpen","pageEl","zoomElements","zoomSwipeStartX","zoomSwipeStartY","zoomSwipeX","zoomSwipeY","setZoomValue","rangeSelector","moversContainer","btnOut","btnIn","toggleZoom","setMoverAnimationPromise","highlightSwitchersTimeout","wholeDiv","isZooming","mover","ctrlKeyDown","changeZoom","onKeyUp","scrollingUp","MEDIA_VIEWER_CLASSNAME","overlaysDiv","mainDiv","topbarLeft","onlyMobile","authorRight","zoom","setNewMover","onDownloadClick","moveLength","setMoverPromise","evt","zoomValue","videoPlayer","lockControls","zoomSwipeHandler","lastDiffY","addProgress","btnMenuToggle","setMoverToTarget","appMediaViewer","removeGlobalListeners","toggleOverlay","setGlobalListeners","closing","fromRight","removeCenterFromMover","wasActive","realParent","SVGImageElement","SVGForeignObjectElement","needOpacity","HTMLImageElement","HTMLVideoElement","setFullAspect","scaleX","scaleY","brSplitted","fillPropertyValue","willBeLeft","willBeTop","isRejected","SVGSVGElement","sizeTailPath","toggleWholeActive","mediaElement","clipId","newClipId","newSvg","outerHTML","SVGUseElement","sX","sY","upscale","_br","toLeft","windowW","newTransform","p1","newMover","oldAvatar","replaceChild","setAuthorInfo","isDocument","useContainerAsTarget","moveTheMover","padding","windowH","thumbPromise","useController","moverVideo","canPlayThrough","createPlayer","ckin","overlay","otherMediaViewer","releaseSingleMedia","toggleGlobalListeners","setPictureInPicture","HAVE_FUTURE_DATA","attachCanPlay","networkState","NETWORK_LOADING","isntEnoughData","updateMediaSource","cancellablePromise","attachPromise","haveImage","captionTimeout","isForDocument","onAuthorClick","savePhotoFile","setCaptionTimeout","btnMenuForward","btnMenuDownload","btnMenuDelete","onCaptionClick","cantForwardMessage","cantDownloadMessage","setCaption","_openMedia","onAvatarUpdate","removeFromAvatarsCache","getFullPhoto","getTarget","hadMessage","isAvatarCached","believeMe","addedToQueue","newPeerId","getPeerMigratedTo","onArchiveClick","selectedId","editPeerFolders","folder_id","toggleDialogPin","pinned_dialogs_count_max","onUnmuteClick","onUnreadClick","top_message","isDialogUnread","ConnectionStatus","SENDING_STATUS","hadConnect","connecting","timedOut","updating","setConnectionStatus","baseDcId","setFirstConnectionTimeout","connectionStatus","online","Connected","forceGetDifference","TimedOut","retryAt","setStatusText","currentLangPackKey","statusEl","statusPreloader","CHANGE_STATE_DELAY","getA","forceReconnect","timerSpan","forceReconnectTimeout","setStateTimeout","statusContainer","constructContainer","roundRect","defaultRadius","quadraticCurveTo","DPR","SIZE","MARGIN","RADIUS","groupCallActiveIcon","START_X","startTime","wasMounted","itemProgress","startAnimation","indexKey","appDialogsManager","addListDialog","isBatch","folders","menuScrollContainer","lastActiveElements","offsets","initedListeners","loadedDialogsAtLeastOnce","loadDialogsPromise","onChatsScroll","_onListLengthChange","checkIfPlaceholderNeeded","hasContacts","removeContactsPlaceholder","updateContactsLength","loadContacts","verifyPeerIdForContacts","processContact","added","onChatsRegularScroll","sliceTimeout","scrollTopWas","rectContainer","rectTarget","firstY","firstElement","lastElement","elementOverflow","sliceFromStart","sliceFromEnd","deleteDialog","setOffsets","onChatsScrollTop","loadDialogs","chatsPreloader","allUnreadCount","bottomPart","allChatsIntlElement","addFilter","onStateLoaded","foldersScrollable","filtersNavigationItem","spliceItems","setPlaybackParams","changeFiltersAllChatsKey","getDialogIndexKey","hasClassName","getDialogDom","setOnlineStatus","processDialogForCallStatus","setFilterUnreadCount","validateDialogForFilter","setFiltersUnreadCount","updateDialog","setUnreadMessages","setDialogActive","getCachedDialogs","validateListForFilter","onFiltersLengthChange","containerToAppend","renderedFilter","unsetTyping","dialogDom","callIcon","savePeerSettings","getNotifyPeerTypeSettings","initListeners","renderFiltersPromise","showFiltersPromise","storagesResults","addMissedDialogs","fillConversations","migratedTo","testDialogForFilter","topOffset","getOffsetIndex","bottomOffset","isDialogMustBeInViewport","unreadSpan","getFolder","foundUnmuted","getAll","sortedDialogList","clientWidth","wasShowing","currentOffsetIndex","needIndex","getConversationsResult","isTopEnd","cccc","offsetDialog","classNameType","subtitleArgs","placeholderContainer","generateEmptyPlaceholder","wrapLocalSticker","emptyDialogsPlaceholderSubtitle","usersLength","placeholderType","updatePartClassName","updateContactsLengthPromise","firstDialog","getDialogFromElement","lastDialog","withContext","openInner","lastActiveListElement","setPeerFunc","sameElement","getDialogByPeerId","lastMessage","highlightWord","setUnread","draftMessage","lastTimeSpan","videoTypes","playIcon","withoutMediaType","sender","senderBold","setStatusMessage","disableAnimationIfRippleFound","setSendingStatus","statusSpan","hasUnreadBadge","isUnreadBadgeMounted","unreadBadge","hasMentionsBadge","isMentionBadgeMounted","mentionsBadge","transitionDuration","isMention","originalDialog","getDialog","setCallStatus","call_not_empty","getMessageSenderPeerIdOrName","addDialog","_dialog","captionDiv","titleSpanContainer","titleP","rightSpan","oldTypingElement","newTypingElement","module","exports","defineProperty","enumerable","Symbol","toStringTag","__esModule","default","prototype","AudioContext","webkitAudioContext","isRecordingSupported","bufferLength","encoderApplication","encoderFrameSize","encoderPath","maxFramesPerPage","mediaTrackConstraints","resampleQuality","streamPages","wavBitDepth","encodedSamplePosition","getUserMedia","WebAssembly","clearStream","getTracks","audioContext","closeAudioContext","encodeBuffers","getChannelData","encoder","postMessage","buffers","initAudioContext","initAudioGraph","scriptProcessorNode","createScriptProcessor","destination","onaudioprocess","inputBuffer","monitorGainNode","createGain","setMonitorGain","recordingGainNode","setRecordingGain","initSourceNode","createMediaStreamSource","loadWorker","Worker","initWorker","streamPage","storePage","recordedPages","samplePosition","page","originalSampleRate","sampleRate","wavSampleRate","onpause","resume","onresume","gain","setTargetAtTime","onstart","destroyWorker","Function","ScrollableBase","logPrefix","onScrollMeasure","needCheckAfterAnimation","scrollPosition","scrollProperty","addedScrollListener","removeHeavyAnimationListener","addScrollListener","removeScrollListener","Scrollable","onScrollOffset","withPaddingContainer","maxScrollTop","ScrollableX","splitCount","scrollHorizontally","deltaX","CheckboxField","stateValue","stateValues","checkSvg","bg","withHover","currentHashPromise","newHashPromise","new_settings","newAlgo","new_algo","salt1","getRandomValues","randomize","hashes","new_password_hash","inputCheckPassword","setUser"],"mappings":"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","file":"13.234dc6639cd6dd1f11ca.chunk.js","sourcesContent":["/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\n// import { IS_MOBILE_SAFARI, IS_SAFARI } from \"../environment/userAgent\";\r\nimport cancelEvent from \"../helpers/dom/cancelEvent\";\r\nimport InputField, { InputFieldOptions } from \"./inputField\";\r\n\r\nexport default class PasswordInputField extends InputField {\r\n public passwordVisible = false;\r\n public toggleVisible: HTMLElement;\r\n public onVisibilityClickAdditional: () => void;\r\n\r\n constructor(options: InputFieldOptions = {}) {\r\n super({\r\n plainText: true,\r\n ...options\r\n });\r\n\r\n const input = this.input as HTMLInputElement;\r\n input.type = 'password';\r\n input.setAttribute('required', '');\r\n input.name = 'notsearch_password';\r\n input.autocomplete = 'off';\r\n\r\n /* if(IS_SAFARI && !IS_MOBILE_SAFARI) {\r\n input.setAttribute('readonly', '');\r\n input.addEventListener('focus', () => {\r\n input.removeAttribute('readonly');\r\n }, {once: true});\r\n } */\r\n\r\n // * https://stackoverflow.com/a/35949954/6758968\r\n const stealthy = document.createElement('input');\r\n stealthy.classList.add('stealthy');\r\n stealthy.tabIndex = -1;\r\n stealthy.type = 'password';\r\n input.parentElement.prepend(stealthy);\r\n input.parentElement.insertBefore(stealthy.cloneNode(), input.nextSibling);\r\n\r\n const toggleVisible = this.toggleVisible = document.createElement('span');\r\n toggleVisible.classList.add('toggle-visible', 'tgico');\r\n\r\n this.container.classList.add('input-field-password');\r\n this.container.append(toggleVisible);\r\n\r\n toggleVisible.addEventListener('click', this.onVisibilityClick);\r\n toggleVisible.addEventListener('touchend', this.onVisibilityClick);\r\n }\r\n\r\n public onVisibilityClick = (e: Event) => {\r\n cancelEvent(e);\r\n this.passwordVisible = !this.passwordVisible;\r\n\r\n this.toggleVisible.classList.toggle('eye-hidden', this.passwordVisible);\r\n (this.input as HTMLInputElement).type = this.passwordVisible ? 'text' : 'password';\r\n this.onVisibilityClickAdditional && this.onVisibilityClickAdditional();\r\n };\r\n}\r\n","export default function bytesCmp(bytes1: number[] | Uint8Array, bytes2: number[] | Uint8Array) {\n const len = bytes1.length;\n if(len !== bytes2.length) {\n return false;\n }\n\n for(let i = 0; i < len; ++i) {\n if(bytes1[i] !== bytes2[i]) {\n return false;\n }\n }\n\n return true;\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n * \r\n * Originally from:\r\n * https://github.com/zhukov/webogram\r\n * Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>\r\n * https://github.com/zhukov/webogram/blob/master/LICENSE\r\n */\r\n\r\nimport { IS_TOUCH_SUPPORTED } from \"../../environment/touchSupport\";\r\n\r\nexport default function placeCaretAtEnd(el: HTMLElement, ignoreTouchCheck = false) {\r\n if(IS_TOUCH_SUPPORTED && (!ignoreTouchCheck || document.activeElement !== el)) {\r\n return;\r\n }\r\n \r\n el.focus();\r\n if(typeof window.getSelection !== \"undefined\" && typeof document.createRange !== \"undefined\") {\r\n var range = document.createRange();\r\n range.selectNodeContents(el);\r\n range.collapse(false);\r\n var sel = window.getSelection();\r\n sel.removeAllRanges();\r\n sel.addRange(range);\r\n // @ts-ignore\r\n } else if(typeof document.body.createTextRange !== \"undefined\") {\r\n // @ts-ignore\r\n var textRange = document.body.createTextRange();\r\n textRange.moveToElementText(el);\r\n textRange.collapse(false);\r\n textRange.select();\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport lottieLoader, { LottieLoader } from \"../../lib/rlottie/lottieLoader\";\r\nimport RLottiePlayer from \"../../lib/rlottie/rlottiePlayer\";\r\nimport PasswordInputField from \"../passwordInputField\";\r\n\r\nexport default class PasswordMonkey {\r\n public container: HTMLElement;\r\n public animation: RLottiePlayer;\r\n public needFrame = 0;\r\n protected loadPromise: ReturnType<LottieLoader['waitForFirstFrame']>;\r\n\r\n constructor(protected passwordInputField: PasswordInputField, protected size: number) {\r\n this.container = document.createElement('div');\r\n this.container.classList.add('media-sticker-wrapper');\r\n }\r\n\r\n public load() {\r\n if(this.loadPromise) return this.loadPromise;\r\n return this.loadPromise = lottieLoader.loadAnimationAsAsset({\r\n container: this.container,\r\n loop: false,\r\n autoplay: false,\r\n width: this.size,\r\n height: this.size,\r\n noCache: true\r\n //}, 'assets/img/TwoFactorSetupMonkeyClose.tgs').then(_animation => {\r\n }, 'TwoFactorSetupMonkeyPeek').then(_animation => {\r\n //return;\r\n this.animation = _animation;\r\n this.animation.addEventListener('enterFrame', currentFrame => {\r\n //console.log('enterFrame', currentFrame, this.needFrame);\r\n\r\n if((this.animation.direction === 1 && currentFrame >= this.needFrame) ||\r\n (this.animation.direction === -1 && currentFrame <= this.needFrame)) {\r\n this.animation.setSpeed(1);\r\n this.animation.pause();\r\n } \r\n });\r\n\r\n this.passwordInputField.onVisibilityClickAdditional = () => {\r\n if(this.passwordInputField.passwordVisible) {\r\n this.animation.setDirection(1);\r\n this.animation.curFrame = 0;\r\n this.needFrame = 16;\r\n this.animation.play();\r\n } else {\r\n this.animation.setDirection(-1);\r\n this.animation.curFrame = 16;\r\n this.needFrame = 0;\r\n this.animation.play();\r\n }\r\n };\r\n\r\n return lottieLoader.waitForFirstFrame(_animation);\r\n });\r\n }\r\n\r\n public remove() {\r\n if(this.animation) {\r\n this.animation.remove();\r\n }\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport InputField from \"../inputField\";\r\nimport lottieLoader from \"../../lib/rlottie/lottieLoader\";\r\nimport RLottiePlayer from \"../../lib/rlottie/rlottiePlayer\";\r\n\r\nexport default class TrackingMonkey {\r\n public container: HTMLElement;\r\n\r\n protected max = 45;\r\n protected needFrame = 0;\r\n\r\n protected animation: RLottiePlayer;\r\n protected idleAnimation: RLottiePlayer;\r\n\r\n protected loadPromise: Promise<any>;\r\n\r\n constructor(protected inputField: InputField, protected size: number) {\r\n this.container = document.createElement('div');\r\n this.container.classList.add('media-sticker-wrapper');\r\n\r\n const input = inputField.input;\r\n\r\n input.addEventListener('blur', () => {\r\n this.playAnimation(0);\r\n });\r\n\r\n input.addEventListener('input', (e) => {\r\n this.playAnimation(inputField.value.length);\r\n });\r\n\r\n /* codeInput.addEventListener('focus', () => {\r\n playAnimation(Math.max(codeInput.value.length, 1));\r\n }); */\r\n }\r\n\r\n // 1st symbol = frame 15\r\n // end symbol = frame 165\r\n public playAnimation(length: number) {\r\n if(!this.animation) return;\r\n\r\n length = Math.min(length, 30);\r\n let frame: number;\r\n if(length) {\r\n frame = Math.round(Math.min(this.max, length) * (165 / this.max) + 11.33);\r\n\r\n if(this.idleAnimation) {\r\n this.idleAnimation.stop(true);\r\n this.idleAnimation.canvas.style.display = 'none';\r\n }\r\n \r\n this.animation.canvas.style.display = '';\r\n } else {\r\n /* const cb = (frameNo: number) => {\r\n if(frameNo <= 1) { */\r\n /* idleAnimation.play();\r\n idleAnimation.canvas.style.display = '';\r\n animation.canvas.style.display = 'none'; */\r\n /* animation.removeListener('enterFrame', cb);\r\n }\r\n };\r\n animation.addListener('enterFrame', cb); */\r\n \r\n frame = 0;\r\n }\r\n //animation.playSegments([1, 2]);\r\n\r\n const direction = this.needFrame > frame ? -1 : 1;\r\n //console.log('keydown', length, frame, direction);\r\n\r\n this.animation.setDirection(direction);\r\n if(this.needFrame !== 0 && frame === 0) {\r\n this.animation.setSpeed(7);\r\n }\r\n /* let diff = Math.abs(needFrame - frame * direction);\r\n if((diff / 20) > 1) animation.setSpeed(diff / 20 | 0); */\r\n this.needFrame = frame;\r\n \r\n this.animation.play();\r\n\r\n /* animation.goToAndStop(15, true); */\r\n //animation.goToAndStop(length / max * );\r\n }\r\n\r\n public load() {\r\n if(this.loadPromise) return this.loadPromise;\r\n return this.loadPromise = Promise.all([\r\n lottieLoader.loadAnimationAsAsset({\r\n container: this.container,\r\n loop: true,\r\n autoplay: true,\r\n width: this.size,\r\n height: this.size\r\n }, 'TwoFactorSetupMonkeyIdle').then(animation => {\r\n this.idleAnimation = animation;\r\n\r\n // ! animationIntersector will stop animation instantly\r\n if(!this.inputField.value.length) {\r\n animation.play();\r\n }\r\n\r\n return lottieLoader.waitForFirstFrame(animation);\r\n }),\r\n\r\n lottieLoader.loadAnimationAsAsset({\r\n container: this.container,\r\n loop: false,\r\n autoplay: false,\r\n width: this.size,\r\n height: this.size\r\n }, 'TwoFactorSetupMonkeyTracking').then(_animation => {\r\n this.animation = _animation;\r\n\r\n if(!this.inputField.value.length) {\r\n this.animation.canvas.style.display = 'none';\r\n }\r\n\r\n this.animation.addEventListener('enterFrame', currentFrame => {\r\n //console.log('enterFrame', currentFrame, needFrame);\r\n //let currentFrame = Math.round(e.currentTime);\r\n \r\n if((this.animation.direction === 1 && currentFrame >= this.needFrame) ||\r\n (this.animation.direction === -1 && currentFrame <= this.needFrame)) {\r\n this.animation.setSpeed(1);\r\n this.animation.pause();\r\n }\r\n\r\n if(currentFrame === 0 && this.needFrame === 0) {\r\n //animation.curFrame = 0;\r\n \r\n if(this.idleAnimation) {\r\n this.idleAnimation.canvas.style.display = '';\r\n this.idleAnimation.play();\r\n this.animation.canvas.style.display = 'none';\r\n }\r\n }\r\n });\r\n //console.log(animation.getDuration(), animation.getDuration(true));\r\n\r\n return lottieLoader.waitForFirstFrame(_animation);\r\n })\r\n ]);\r\n }\r\n\r\n public remove() {\r\n if(this.animation) this.animation.remove();\r\n if(this.idleAnimation) this.idleAnimation.remove();\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport InputField, { InputFieldOptions } from \"./inputField\";\r\n\r\nexport default class CodeInputField extends InputField {\r\n constructor(options: InputFieldOptions & {\r\n length: number,\r\n onFill: (code: string) => void\r\n }) {\r\n super({\r\n plainText: true,\r\n ...options\r\n });\r\n\r\n const input = this.input as HTMLInputElement;\r\n input.type = 'tel';\r\n input.setAttribute('required', '');\r\n input.autocomplete = 'off';\r\n\r\n let lastLength = 0;\r\n this.input.addEventListener('input', (e) => {\r\n this.input.classList.remove('error');\r\n this.setLabel();\r\n \r\n const value = this.value.replace(/\\D/g, '').slice(0, options.length);\r\n this.setValueSilently(value);\r\n \r\n const length = this.value.length;\r\n if(length === options.length) { // submit code\r\n options.onFill(this.value);\r\n } else if(length === lastLength) {\r\n return;\r\n }\r\n \r\n lastLength = length;\r\n });\r\n }\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport placeCaretAtEnd from \"../helpers/dom/placeCaretAtEnd\";\nimport { formatPhoneNumber } from \"../helpers/formatPhoneNumber\";\nimport { IS_APPLE, IS_ANDROID, IS_APPLE_MOBILE } from \"../environment/userAgent\";\nimport { HelpCountry, HelpCountryCode } from \"../layer\";\nimport InputField, { InputFieldOptions } from \"./inputField\";\n\nexport default class TelInputField extends InputField {\n private pasted = false;\n public lastValue = '';\n \n constructor(options: InputFieldOptions & {\n onInput?: (formatted: ReturnType<typeof formatPhoneNumber>) => void\n } = {}) {\n super({\n label: 'Contacts.PhoneNumber.Placeholder',\n //plainText: true,\n name: 'phone',\n ...options\n });\n\n this.container.classList.add('input-field-phone');\n\n let telEl = this.input;\n if(telEl instanceof HTMLInputElement) {\n telEl.type = 'tel';\n telEl.autocomplete = 'rr55RandomRR55';\n } else {\n telEl.inputMode = 'decimal';\n\n const pixelRatio = window.devicePixelRatio;\n if(pixelRatio > 1) {\n let letterSpacing: number;\n if(IS_APPLE) {\n letterSpacing = pixelRatio * -.16;\n } else if(IS_ANDROID) {\n letterSpacing = 0;\n }\n\n telEl.style.setProperty('--letter-spacing', letterSpacing + 'px');\n }\n\n const originalFunc = this.setValueSilently.bind(this);\n this.setValueSilently = (value) => {\n originalFunc(value);\n placeCaretAtEnd(this.input, true);\n };\n }\n\n telEl.addEventListener('input', () => {\n //console.log('input', this.value);\n telEl.classList.remove('error');\n \n const value = this.value;\n const diff = Math.abs(value.length - this.lastValue.length);\n if(diff > 1 && !this.pasted && IS_APPLE_MOBILE) {\n this.setValueSilently(this.lastValue + value);\n }\n \n this.pasted = false;\n \n this.setLabel();\n \n let formattedPhoneNumber: ReturnType<typeof formatPhoneNumber>;\n let formatted: string, country: HelpCountry, countryCode: HelpCountryCode, leftPattern = '';\n if(this.value.replace(/\\++/, '+') === '+') {\n this.setValueSilently('+');\n } else {\n formattedPhoneNumber = formatPhoneNumber(this.value);\n formatted = formattedPhoneNumber.formatted;\n country = formattedPhoneNumber.country;\n leftPattern = formattedPhoneNumber.leftPattern;\n countryCode = formattedPhoneNumber.code;\n this.setValueSilently(this.lastValue = formatted ? '+' + formatted : '');\n }\n \n telEl.dataset.leftPattern = leftPattern/* .replace(/X/g, '0') */;\n \n //console.log(formatted, country);\n\n options.onInput && options.onInput(formattedPhoneNumber);\n });\n \n telEl.addEventListener('paste', () => {\n this.pasted = true;\n //console.log('paste', telEl.value);\n });\n \n /* telEl.addEventListener('change', (e) => {\n console.log('change', telEl.value);\n }); */\n \n telEl.addEventListener('keypress', (e) => {\n //console.log('keypress', this.value);\n const key = e.key;\n if(/\\D/.test(key) && !(e.metaKey || e.ctrlKey) && key !== 'Backspace' && !(key === '+' && e.shiftKey/* && !this.value */)) {\n e.preventDefault();\n return false;\n }\n });\n \n /* telEl.addEventListener('focus', function(this: typeof telEl, e) {\n this.removeAttribute('readonly'); // fix autocomplete\n });*/\n }\n}\n","import IMAGE_MIME_TYPES_SUPPORTED from \"./imageMimeTypesSupport\";\nimport VIDEO_MIME_TYPES_SUPPORTED from \"./videoMimeTypesSupport\";\n\nconst arr = [...IMAGE_MIME_TYPES_SUPPORTED].concat([...VIDEO_MIME_TYPES_SUPPORTED]);\n\nconst MEDIA_MIME_TYPES_SUPPORTED = new Set(arr);\n\nexport default MEDIA_MIME_TYPES_SUPPORTED;\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport type { Message, MessageAction } from \"../layer\";\nimport type { MyMessage } from \"../lib/appManagers/appMessagesManager\";\nimport forEachReverse from \"./array/forEachReverse\";\n\nexport default function filterChatPhotosMessages(value: {\n count: number;\n next_rate: number;\n offset_id_offset: number;\n history: MyMessage[];\n}) {\n forEachReverse(value.history, (message, idx, arr) => {\n if(!((message as Message.messageService).action as MessageAction.messageActionChatEditPhoto).photo) {\n arr.splice(idx, 1);\n if(value.count !== undefined) {\n --value.count;\n }\n }\n });\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport forEachReverse from \"./array/forEachReverse\";\nimport safeAssign from \"./object/safeAssign\";\n\nexport type ListLoaderOptions<T extends {}, P extends {}> = {\n loadMore: ListLoader<T, P>['loadMore'],\n loadCount?: ListLoader<T, P>['loadCount'],\n loadWhenLeft?: ListLoader<T, P>['loadWhenLeft'],\n processItem?: ListLoader<T, P>['processItem'],\n onJump?: ListLoader<T, P>['onJump'],\n onLoadedMore?: ListLoader<T, P>['onLoadedMore']\n};\n\nexport type ListLoaderResult<T extends {}> = {count: number, items: any[]};\nexport default class ListLoader<T extends {}, P extends {}> {\n public current: T;\n public previous: T[] = [];\n public next: T[] = [];\n public count: number;\n public reverse = false; // reverse means next = higher msgid\n\n protected loadMore: (anchor: T, older: boolean, loadCount: number) => Promise<ListLoaderResult<T>>;\n protected processItem: (item: P) => T;\n protected loadCount = 50;\n protected loadWhenLeft = 20;\n \n public onJump: (item: T, older: boolean) => void;\n public onLoadedMore: () => void;\n\n protected loadedAllUp = false;\n protected loadedAllDown = false;\n protected loadPromiseUp: Promise<void>;\n protected loadPromiseDown: Promise<void>;\n\n constructor(options: ListLoaderOptions<T, P>) {\n safeAssign(this, options);\n }\n\n public setTargets(previous: T[], next: T[], reverse: boolean) {\n this.previous = previous;\n this.next = next;\n this.reverse = reverse;\n }\n\n public get index() {\n return this.count !== undefined ? this.previous.length : -1;\n }\n\n /* public filter(callback: (item: T, idx: number, arr: T[]) => boolean) {\n const filter = (item: T, idx: number, arr: T[]) => {\n if(!callback(item, idx, arr)) {\n arr.splice(idx, 1);\n }\n };\n\n forEachReverse(this.previous, filter);\n forEachReverse(this.next, filter);\n } */\n\n public reset(loadedAll = false) {\n this.current = undefined;\n this.previous = [];\n this.next = [];\n this.setLoaded(true, loadedAll);\n this.setLoaded(false, loadedAll);\n }\n\n public go(length: number, dispatchJump = true) {\n let items: T[], item: T;\n if(length > 0) {\n items = this.next.splice(0, length);\n item = items.pop();\n if(!item) {\n return;\n }\n\n if(this.current !== undefined) items.unshift(this.current);\n this.previous.push(...items);\n } else {\n items = this.previous.splice(Math.max(0, this.previous.length + length), -length);\n item = items.shift();\n if(!item) {\n return;\n }\n\n if(this.current !== undefined) items.push(this.current);\n this.next.unshift(...items);\n }\n\n if(this.next.length < this.loadWhenLeft) {\n this.load(!this.reverse);\n }\n\n if(this.previous.length < this.loadWhenLeft) {\n this.load(this.reverse);\n }\n\n this.current = item;\n dispatchJump && this.onJump && this.onJump(item, length > 0);\n return this.current;\n }\n\n protected unsetCurrent(toPrevious: boolean) {\n if(toPrevious) this.previous.push(this.current);\n else this.next.unshift(this.current);\n\n this.current = undefined;\n }\n\n public goUnsafe(length: number, dispatchJump?: boolean) {\n const leftLength = length > 0 ? Math.max(0, length - this.next.length) : Math.min(0, length + this.previous.length);\n const item = this.go(length, leftLength ? false : dispatchJump);\n\n /* if(length > 0 ? this.loadedAllUp : this.loadedAllDown) {\n this.unsetCurrent(length > 0);\n } */\n \n return {\n item: !leftLength ? item : undefined,\n leftLength\n };\n }\n\n protected setLoaded(down: boolean, value: boolean) {\n const isChanged = (down ? this.loadedAllDown : this.loadedAllUp) !== value;\n if(!isChanged) {\n return false;\n }\n\n if(down) this.loadedAllDown = value;\n else this.loadedAllUp = value;\n\n if(!value) {\n if(down) this.loadPromiseDown = null;\n else this.loadPromiseUp = null;\n }\n\n return true;\n }\n\n // нет смысла делать проверку для reverse и loadMediaPromise\n public load(older: boolean) {\n if(older ? this.loadedAllDown : this.loadedAllUp) return Promise.resolve();\n\n let promise = older ? this.loadPromiseDown : this.loadPromiseUp;\n if(promise) return promise;\n\n let anchor: T;\n if(older) {\n anchor = this.reverse ? this.previous[0] : this.next[this.next.length - 1];\n } else {\n anchor = this.reverse ? this.next[this.next.length - 1] : this.previous[0];\n }\n\n anchor ??= this.current;\n promise = this.loadMore(anchor, older, this.loadCount).then(result => {\n if((older ? this.loadPromiseDown : this.loadPromiseUp) !== promise) {\n return;\n }\n\n if(result.items.length < this.loadCount) {\n this.setLoaded(older, true);\n }\n\n if(this.count === undefined) {\n this.count = result.count || result.items.length;\n }\n\n const method = older ? result.items.forEach.bind(result.items) : forEachReverse.bind(null, result.items);\n method((item: any) => {\n const processed = this.processItem ? this.processItem(item) : item;\n\n if(!processed) return;\n\n if(older) {\n if(this.reverse) this.previous.unshift(processed);\n else this.next.push(processed);\n } else {\n if(this.reverse) this.next.push(processed);\n else this.previous.unshift(processed);\n }\n });\n\n this.onLoadedMore && this.onLoadedMore();\n }, () => {}).then(() => {\n if(older) this.loadPromiseDown = null;\n else this.loadPromiseUp = null;\n });\n\n if(older) this.loadPromiseDown = promise;\n else this.loadPromiseUp = promise;\n\n return promise;\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport type { MediaSearchContext } from \"../components/appMediaPlaybackController\";\nimport type { SearchSuperContext } from \"../components/appSearchSuper.\";\nimport type { Message } from \"../layer\";\nimport appMessagesIdsManager from \"../lib/appManagers/appMessagesIdsManager\";\nimport appMessagesManager, { MyMessage } from \"../lib/appManagers/appMessagesManager\";\nimport rootScope from \"../lib/rootScope\";\nimport forEachReverse from \"./array/forEachReverse\";\nimport filterChatPhotosMessages from \"./filterChatPhotosMessages\";\nimport ListLoader, { ListLoaderOptions } from \"./listLoader\";\n\nexport default class SearchListLoader<Item extends {mid: number, peerId: PeerId}> extends ListLoader<Item, Message.message> {\n public searchContext: MediaSearchContext;\n public onEmptied: () => void;\n\n private otherSideLoader: SearchListLoader<Item>;\n\n constructor(options: Omit<ListLoaderOptions<Item, Message.message>, 'loadMore'> & {onEmptied?: () => void, isInner?: boolean} = {}) {\n super({\n ...options,\n loadMore: (anchor, older, loadCount) => {\n const backLimit = older ? 0 : loadCount;\n let maxId = anchor?.mid;\n\n if(maxId === undefined) maxId = this.searchContext.maxId;\n if(!older) maxId = appMessagesIdsManager.incrementMessageId(maxId, 1);\n\n return appMessagesManager.getSearch({\n ...this.searchContext,\n peerId: this.searchContext.peerId || anchor?.peerId,\n maxId,\n limit: backLimit ? 0 : loadCount,\n backLimit\n }).then(value => {\n /* if(DEBUG) {\n this.log('loaded more media by maxId:', maxId, value, older, this.reverse);\n } */\n\n if(this.searchContext.inputFilter._ === 'inputMessagesFilterChatPhotos') {\n filterChatPhotosMessages(value);\n }\n\n if(value.next_rate) {\n this.searchContext.nextRate = value.next_rate;\n }\n\n return {count: value.count, items: value.history};\n });\n },\n processItem: (message) => {\n const filtered = this.filterMids([message.mid]);\n if(!filtered.length) {\n return;\n }\n\n return options.processItem(message);\n }\n });\n\n rootScope.addEventListener('history_delete', this.onHistoryDelete);\n rootScope.addEventListener('history_multiappend', this.onHistoryMultiappend);\n rootScope.addEventListener('message_sent', this.onMessageSent);\n\n if(!options.isInner) {\n this.otherSideLoader = new SearchListLoader({\n ...options, \n isInner: true\n });\n\n // this.otherSideLoader.onLoadedMore = () => {\n \n // };\n }\n }\n\n protected filterMids(mids: number[]) {\n const storage = this.searchContext.isScheduled ? \n appMessagesManager.getScheduledMessagesStorage(this.searchContext.peerId) : \n appMessagesManager.getMessagesStorage(this.searchContext.peerId);\n const filtered = appMessagesManager.filterMessagesByInputFilterFromStorage(this.searchContext.inputFilter._, mids, storage, mids.length) as Message.message[];\n return filtered;\n }\n\n protected onHistoryDelete = ({peerId, msgs}: {peerId: PeerId, msgs: Set<number>}) => {\n const shouldBeDeleted = (item: Item) => item.peerId === peerId && msgs.has(item.mid);\n const filter = (item: Item, idx: number, arr: Item[]) => {\n if(shouldBeDeleted(item)) {\n arr.splice(idx, 1);\n }\n };\n\n forEachReverse(this.previous, filter);\n forEachReverse(this.next, filter);\n\n if(this.current && shouldBeDeleted(this.current)) {\n this.current = undefined;\n /* if(this.go(1)) {\n this.previous.splice(this.previous.length - 1, 1);\n } else if(this.go(-1)) {\n this.next.splice(0, 1);\n } else */if(this.onEmptied) {\n this.onEmptied();\n }\n }\n };\n\n protected onHistoryMultiappend = (obj: {\n [peerId: string]: Set<number>;\n }) => {\n if(this.searchContext.folderId !== undefined) {\n return;\n }\n\n // because it's reversed\n if(!this.loadedAllUp || this.loadPromiseUp) {\n return;\n }\n\n const mids = obj[this.searchContext.peerId];\n if(!mids) {\n return;\n }\n\n const sorted = Array.from(mids).sort((a, b) => a - b);\n const filtered = this.filterMids(sorted);\n const targets = filtered.map(message => this.processItem(message)).filter(Boolean);\n if(targets.length) {\n /* const {previous, current, next} = this;\n const targets = previous.concat(current, next);\n const currentIdx = targets.length;\n const mid = targets[0].mid;\n let i = 0, length = targets.length;\n for(; i < length; ++i) {\n const target = targets[i];\n if(!target || mid < target.mid) {\n break;\n }\n }\n\n if(i < currentIdx) previous.push(...targets);\n else next. */\n\n if(!this.current) {\n this.previous.push(...targets);\n } else {\n this.next.push(...targets);\n }\n }\n };\n\n protected onMessageSent = ({message}: {message: MyMessage}) => {\n this.onHistoryMultiappend({\n [message.peerId]: new Set([message.mid])\n });\n };\n\n public setSearchContext(context: SearchSuperContext) {\n this.searchContext = context;\n\n if(this.searchContext.folderId !== undefined) {\n this.loadedAllUp = true;\n\n if(this.searchContext.nextRate === undefined) {\n this.loadedAllDown = true;\n }\n }\n\n if(this.searchContext.inputFilter._ === 'inputMessagesFilterChatPhotos') {\n this.loadedAllUp = true;\n }\n\n if(this.searchContext.useSearch === false) {\n this.loadedAllDown = this.loadedAllUp = true;\n }\n\n if(this.otherSideLoader) {\n this.otherSideLoader.setSearchContext(context);\n }\n }\n\n public reset() {\n super.reset();\n this.searchContext = undefined;\n\n if(this.otherSideLoader) {\n this.otherSideLoader.reset();\n }\n }\n\n public getPrevious() {\n let previous = this.previous;\n\n if(this.otherSideLoader) {\n previous = previous.concat(this.otherSideLoader.previous);\n }\n\n return previous;\n }\n\n public getNext() {\n let next = this.next;\n\n if(this.otherSideLoader) {\n next = next.concat(this.otherSideLoader.next);\n }\n\n return next;\n }\n\n public getCurrent() {\n return this.current || this.otherSideLoader?.current;\n }\n\n private goToOtherEnd(length: number) {\n if(length > 0) return this.go(-this.previous.length);\n else return this.go(this.next.length);\n }\n\n public goRound(length: number, dispatchJump?: boolean) {\n let ret: ReturnType<SearchListLoader<Item>['goUnsafe']>;\n\n if(this.otherSideLoader?.current) {\n ret = this.otherSideLoader.goUnsafe(length, dispatchJump);\n if(ret.item) {\n return ret.item;\n }\n\n length = ret.leftLength;\n if(!(length > 0 ? this.otherSideLoader.next : this.otherSideLoader.previous).length) {\n const loaded = length > 0 ? this.otherSideLoader.loadedAllUp : this.otherSideLoader.loadedAllDown;\n if(!loaded) { // do not reset anything until it's loaded\n return;\n }\n\n // if other side is loaded too will start from its begin\n if((length > 0 && (this.otherSideLoader.searchContext.maxId === 1 || this.otherSideLoader.loadedAllDown)) ||\n (length < 0 && (this.otherSideLoader.searchContext.maxId === 0 || this.otherSideLoader.loadedAllUp))) {\n return this.otherSideLoader.goToOtherEnd(length);\n }\n\n this.otherSideLoader.unsetCurrent(length > 0);\n }\n }\n\n ret = this.goUnsafe(length, dispatchJump);\n if(!ret.item) {\n if(this.loadedAllUp && this.loadedAllDown) { // just use the same loader if the list is too short\n return this.goToOtherEnd(length);\n } else if(this.otherSideLoader) {\n length = ret.leftLength;\n ret = this.otherSideLoader.goUnsafe(length, dispatchJump);\n \n if(ret.item) {\n this.unsetCurrent(length > 0);\n }\n }\n }\n\n return ret?.item;\n }\n\n // public setTargets(previous: Item[], next: Item[], reverse: boolean) {\n // super.setTargets(previous, next, reverse);\n // }\n\n protected setLoaded(down: boolean, value: boolean) {\n const changed = super.setLoaded(down, value);\n\n if(changed && \n this.otherSideLoader && \n value && \n this.searchContext?.useSearch !== false/* && \n (this.reverse ? this.loadedAllUp : this.loadedAllDown) */) {\n const reverse = this.loadedAllUp;\n this.otherSideLoader.setSearchContext({\n ...this.searchContext,\n maxId: reverse ? 1 : 0\n });\n\n // these 'reverse' are different, not a mistake here.\n this.otherSideLoader.reverse = this.reverse;\n this.otherSideLoader.setLoaded(reverse, true);\n this.otherSideLoader.load(!reverse);\n }\n\n return changed;\n }\n\n public cleanup() {\n this.reset();\n rootScope.removeEventListener('history_delete', this.onHistoryDelete);\n rootScope.removeEventListener('history_multiappend', this.onHistoryMultiappend);\n rootScope.removeEventListener('message_sent', this.onMessageSent);\n this.onEmptied = undefined;\n\n if(this.otherSideLoader) {\n this.otherSideLoader.cleanup();\n this.otherSideLoader = undefined;\n }\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport appDialogsManager from \"../lib/appManagers/appDialogsManager\";\r\nimport Scrollable from \"./scrollable\";\r\nimport appMessagesManager from \"../lib/appManagers/appMessagesManager\";\r\nimport InputSearch from \"./inputSearch\";\r\nimport replaceContent from \"../helpers/dom/replaceContent\";\r\nimport { i18n, LangPackKey } from \"../lib/langPack\";\r\n\r\nexport class SearchGroup {\r\n container: HTMLDivElement;\r\n nameEl: HTMLDivElement;\r\n list: HTMLUListElement;\r\n\r\n constructor(public name: LangPackKey | boolean, public type: string, private clearable = true, className?: string, clickable = true, public autonomous = true, public onFound?: () => void) {\r\n this.list = appDialogsManager.createChatList();\r\n this.container = document.createElement('div');\r\n if(className) this.container.className = className;\r\n \r\n if(name) {\r\n this.nameEl = document.createElement('div');\r\n this.nameEl.classList.add('search-group__name');\r\n if(typeof(name) === 'string') {\r\n this.nameEl.append(i18n(name));\r\n }\r\n this.container.append(this.nameEl);\r\n }\r\n \r\n this.container.classList.add('search-group', 'search-group-' + type);\r\n this.container.append(this.list);\r\n this.container.style.display = 'none';\r\n\r\n if(clickable) {\r\n appDialogsManager.setListClickListener(this.list, onFound, undefined, autonomous);\r\n }\r\n }\r\n\r\n clear() {\r\n this.container.style.display = 'none';\r\n\r\n if(this.clearable) {\r\n this.list.innerHTML = '';\r\n }\r\n }\r\n\r\n setActive() {\r\n this.container.style.display = '';\r\n }\r\n\r\n toggle() {\r\n if(this.list.childElementCount) {\r\n this.setActive();\r\n } else {\r\n this.clear();\r\n }\r\n }\r\n}\r\n\r\nexport type SearchGroupType = 'contacts' | 'globalContacts' | 'messages' | string;\r\n\r\nexport default class AppSearch {\r\n private minMsgId = 0;\r\n private loadedCount = -1;\r\n private foundCount = -1;\r\n\r\n private searchPromise: Promise<void> = null;\r\n private searchTimeout: number = 0;\r\n\r\n private query = '';\r\n\r\n private listsContainer: HTMLDivElement = null;\r\n\r\n private peerId: PeerId; // 0 - means global\r\n private threadId = 0;\r\n\r\n private scrollable: Scrollable;\r\n\r\n constructor(public container: HTMLElement, public searchInput: InputSearch, public searchGroups: {[group in SearchGroupType]: SearchGroup}, public onSearch?: (count: number) => void) {\r\n this.scrollable = new Scrollable(this.container);\r\n this.listsContainer = this.scrollable.container as HTMLDivElement;\r\n for(let i in this.searchGroups) {\r\n this.listsContainer.append(this.searchGroups[i as SearchGroupType].container);\r\n }\r\n\r\n if(this.searchGroups.messages) {\r\n this.scrollable.setVirtualContainer(this.searchGroups.messages.list);\r\n }\r\n\r\n this.searchInput.onChange = (value) => {\r\n /* if(!value.trim()) {\r\n //this.peerId = 0;\r\n return;\r\n } */\r\n \r\n this.query = value;\r\n this.reset(false);\r\n this.searchMore();\r\n };\r\n\r\n this.scrollable.onScrolledBottom = () => {\r\n if(!this.query.trim()) return;\r\n \r\n if(!this.searchTimeout) {\r\n this.searchTimeout = window.setTimeout(() => {\r\n this.searchMore();\r\n this.searchTimeout = 0;\r\n }, 0);\r\n }\r\n };\r\n }\r\n\r\n public reset(all = true) {\r\n if(all) {\r\n this.searchInput.value = '';\r\n this.query = '';\r\n this.peerId = undefined;\r\n this.threadId = 0;\r\n }\r\n\r\n this.minMsgId = 0;\r\n this.loadedCount = -1;\r\n this.foundCount = -1;\r\n\r\n for(let i in this.searchGroups) {\r\n this.searchGroups[i as SearchGroupType].clear();\r\n }\r\n \r\n this.searchPromise = null;\r\n }\r\n\r\n public beginSearch(peerId?: PeerId, threadId = 0, query = '') {\r\n this.peerId = peerId;\r\n this.threadId = threadId;\r\n\r\n if(this.query !== query) {\r\n this.searchInput.inputField.value = query;\r\n }\r\n\r\n this.searchInput.input.focus();\r\n }\r\n\r\n public searchMore() {\r\n if(this.searchPromise) return this.searchPromise;\r\n \r\n const query = this.query;\r\n \r\n if(!query.trim()) {\r\n this.onSearch && this.onSearch(0);\r\n return;\r\n }\r\n \r\n if(this.foundCount !== -1 && this.loadedCount >= this.foundCount) {\r\n return Promise.resolve();\r\n }\r\n \r\n const maxId = this.minMsgId || 0;\r\n\r\n return this.searchPromise = appMessagesManager.getSearch({\r\n peerId: this.peerId, \r\n query, \r\n inputFilter: {_: 'inputMessagesFilterEmpty'}, \r\n maxId, \r\n limit: 20,\r\n threadId: this.threadId\r\n }).then(res => {\r\n this.searchPromise = null;\r\n \r\n if(this.searchInput.value !== query) {\r\n return;\r\n }\r\n \r\n //console.log('input search result:', this.peerId, query, null, maxId, 20, res);\r\n \r\n const {count, history} = res;\r\n \r\n if(history.length && history[0].mid === this.minMsgId) {\r\n history.shift();\r\n }\r\n \r\n const searchGroup = this.searchGroups.messages;\r\n\r\n history.forEach((message) => {\r\n try {\r\n const peerId = this.peerId ? message.fromId : message.peerId;\r\n appDialogsManager.addDialogAndSetLastMessage({\r\n peerId, \r\n container: this.scrollable/* searchGroup.list */, \r\n drawStatus: false,\r\n avatarSize: 54,\r\n meAsSaved: false,\r\n message,\r\n query\r\n });\r\n } catch(err) {\r\n console.error('[appSearch] render search result', err);\r\n }\r\n });\r\n\r\n searchGroup.toggle();\r\n \r\n this.minMsgId = history.length && history[history.length - 1].mid;\r\n \r\n if(this.loadedCount === -1) {\r\n this.loadedCount = 0;\r\n }\r\n this.loadedCount += history.length;\r\n \r\n if(this.foundCount === -1) {\r\n this.foundCount = count;\r\n\r\n if(searchGroup.nameEl) {\r\n replaceContent(searchGroup.nameEl, i18n(count ? 'Chat.Search.MessagesFound' : 'Chat.Search.NoMessagesFound', [count]));\r\n }\r\n \r\n this.onSearch && this.onSearch(this.foundCount);\r\n }\r\n }).catch(err => {\r\n console.error('search error', err);\r\n this.searchPromise = null;\r\n });\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\n//import { getRichValue } from \"../helpers/dom\";\r\nimport { LangPackKey } from \"../lib/langPack\";\r\nimport InputField from \"./inputField\";\r\n\r\nexport default class InputSearch {\r\n public container: HTMLElement;\r\n public input: HTMLElement;\r\n public inputField: InputField;\r\n public clearBtn: HTMLElement;\r\n\r\n public prevValue = '';\r\n public timeout = 0;\r\n public onChange: (value: string) => void;\r\n public onClear: () => void;\r\n\r\n constructor(placeholder: LangPackKey, onChange?: (value: string) => void) {\r\n this.inputField = new InputField({\r\n placeholder,\r\n plainText: true\r\n });\r\n\r\n this.container = this.inputField.container;\r\n this.container.classList.remove('input-field');\r\n this.container.classList.add('input-search');\r\n\r\n this.onChange = onChange;\r\n\r\n this.input = this.inputField.input;\r\n this.input.classList.add('input-search-input');\r\n\r\n const searchIcon = document.createElement('i');\r\n searchIcon.classList.add('tgico', 'tgico-search');\r\n\r\n this.clearBtn = document.createElement('i');\r\n this.clearBtn.classList.add('tgico', 'btn-icon', 'tgico-close');\r\n\r\n this.input.addEventListener('input', this.onInput);\r\n this.clearBtn.addEventListener('click', this.onClearClick);\r\n\r\n this.container.append(searchIcon, this.clearBtn);\r\n }\r\n \r\n onInput = () => {\r\n if(!this.onChange) return;\r\n\r\n let value = this.value;\r\n\r\n //this.input.classList.toggle('is-empty', !value.trim());\r\n\r\n if(value !== this.prevValue) {\r\n this.prevValue = value;\r\n clearTimeout(this.timeout);\r\n this.timeout = window.setTimeout(() => {\r\n this.onChange(value);\r\n }, 200);\r\n }\r\n };\r\n\r\n onClearClick = () => {\r\n this.value = '';\r\n this.onChange && this.onChange('');\r\n this.onClear && this.onClear();\r\n };\r\n\r\n get value() {\r\n return this.inputField.value;\r\n }\r\n\r\n set value(value: string) {\r\n this.prevValue = value;\r\n clearTimeout(this.timeout);\r\n this.inputField.value = value;\r\n }\r\n\r\n public remove() {\r\n clearTimeout(this.timeout);\r\n this.input.removeEventListener('input', this.onInput);\r\n this.clearBtn.removeEventListener('click', this.onClearClick);\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport Button from \"./button\";\r\n\r\nconst ButtonIcon = (className?: string, options: Partial<{noRipple: true, onlyMobile: true, asDiv: boolean}> = {}) => {\r\n const button = Button('btn-icon', {\r\n icon: className || undefined, \r\n ...options\r\n });\r\n\r\n return button;\r\n};\r\n\r\nexport default ButtonIcon;\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport EventListenerBase from \"../helpers/eventListenerBase\";\r\nimport ListenerSetter from \"../helpers/listenerSetter\";\r\nimport { i18n, LangPackKey } from \"../lib/langPack\";\r\nimport ButtonIcon from \"./buttonIcon\";\r\nimport Scrollable from \"./scrollable\";\r\nimport SidebarSlider from \"./slider\";\r\n\r\nexport interface SliderTab {\r\n onOpen?: () => void,\r\n onOpenAfterTimeout?: () => void,\r\n onClose?: () => void,\r\n onCloseAfterTimeout?: () => void\r\n}\r\n\r\nexport interface SliderSuperTabConstructable {\r\n new(slider: SidebarSlider, destroyable: boolean): SliderSuperTab;\r\n}\r\n\r\nexport interface SliderSuperTabEventableConstructable {\r\n new(slider: SidebarSlider, destroyable: boolean): SliderSuperTabEventable;\r\n}\r\n\r\nexport default class SliderSuperTab implements SliderTab {\r\n public container: HTMLElement;\r\n\r\n public header: HTMLElement;\r\n public closeBtn: HTMLElement;\r\n public title: HTMLElement;\r\n\r\n public content: HTMLElement;\r\n public scrollable: Scrollable;\r\n\r\n public slider: SidebarSlider;\r\n public destroyable: boolean;\r\n public listenerSetter: ListenerSetter;\r\n\r\n constructor(slider: SidebarSlider, destroyable?: boolean) {\r\n this._constructor(slider, destroyable);\r\n }\r\n\r\n public _constructor(slider: SidebarSlider, destroyable = true): any {\r\n this.slider = slider;\r\n this.destroyable = destroyable;\r\n\r\n this.container = document.createElement('div');\r\n this.container.classList.add('tabs-tab', 'sidebar-slider-item');\r\n\r\n // * Header\r\n this.header = document.createElement('div');\r\n this.header.classList.add('sidebar-header');\r\n\r\n this.closeBtn = ButtonIcon('left sidebar-close-button', {noRipple: true});\r\n this.title = document.createElement('div');\r\n this.title.classList.add('sidebar-header__title');\r\n this.header.append(this.closeBtn, this.title);\r\n\r\n // * Content\r\n this.content = document.createElement('div');\r\n this.content.classList.add('sidebar-content');\r\n\r\n this.scrollable = new Scrollable(this.content, undefined, undefined, true);\r\n\r\n this.container.append(this.header, this.content);\r\n\r\n this.slider.addTab(this);\r\n \r\n this.listenerSetter = new ListenerSetter();\r\n }\r\n\r\n public close() {\r\n return this.slider.closeTab(this);\r\n }\r\n\r\n public async open(...args: any[]) {\r\n if(this.init) {\r\n try {\r\n const result = this.init();\r\n this.init = null;\r\n\r\n if(result instanceof Promise) {\r\n await result;\r\n }\r\n } catch(err) {\r\n console.error('open tab error', err);\r\n }\r\n }\r\n\r\n this.slider.selectTab(this);\r\n }\r\n\r\n protected init(): Promise<any> | any {\r\n\r\n }\r\n\r\n public onCloseAfterTimeout() {\r\n if(this.destroyable) { // ! WARNING, пока что это будет работать только с самой последней внутренней вкладкой !\r\n this.slider.tabs.delete(this);\r\n this.container.remove();\r\n }\r\n\r\n if(this.listenerSetter) {\r\n this.listenerSetter.removeAll();\r\n }\r\n }\r\n\r\n protected setTitle(key: LangPackKey) {\r\n this.title.innerHTML = '';\r\n this.title.append(i18n(key));\r\n }\r\n}\r\n\r\nexport class SliderSuperTabEventable extends SliderSuperTab {\r\n public eventListener: EventListenerBase<{\r\n destroy: () => void\r\n }>;\r\n\r\n constructor(slider: SidebarSlider) {\r\n super(slider);\r\n this.eventListener = new EventListenerBase();\r\n }\r\n\r\n onCloseAfterTimeout() {\r\n this.eventListener.dispatchEvent('destroy');\r\n this.eventListener.cleanup();\r\n return super.onCloseAfterTimeout();\r\n }\r\n}\r\n\r\n/* // @ts-ignore\r\ninterface SliderSuperEventsTab extends SliderSuperTab, EventListenerBase<{}> {\r\n superConstructor: (...args: any[]) => any;\r\n}\r\nclass SliderSuperEventsTab implements SliderSuperEventsTab {\r\n constructor(slider: SidebarSlider) {\r\n this.superConstructor([slider, true]);\r\n }\r\n}\r\napplyMixins(SliderSuperEventsTab, [SliderSuperTab, EventListenerBase]);\r\n\r\n(window as any).lol = SliderSuperEventsTab\r\n\r\nexport {SliderSuperEventsTab}; */\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { horizontalMenu } from \"./horizontalMenu\";\r\nimport { TransitionSlider } from \"./transition\";\r\nimport appNavigationController, { NavigationItem } from \"./appNavigationController\";\r\nimport SliderSuperTab, { SliderSuperTabConstructable, SliderTab } from \"./sliderTab\";\r\nimport { attachClickEvent } from \"../helpers/dom/clickEvent\";\r\nimport indexOfAndSplice from \"../helpers/array/indexOfAndSplice\";\r\nimport safeAssign from \"../helpers/object/safeAssign\";\r\n\r\nconst TRANSITION_TIME = 250;\r\n\r\nexport type {SliderTab};\r\nexport {SliderSuperTab};\r\n\r\nexport default class SidebarSlider {\r\n protected _selectTab: ReturnType<typeof horizontalMenu>;\r\n public historyTabIds: (number | SliderSuperTab)[] = []; // * key is any, since right sidebar is ugly nowz\r\n public tabsContainer: HTMLElement;\r\n public sidebarEl: HTMLElement;\r\n public tabs: Map<any, SliderTab>; // * key is any, since right sidebar is ugly now\r\n private canHideFirst = false;\r\n private navigationType: NavigationItem['type']\r\n\r\n constructor(options: {\r\n sidebarEl: SidebarSlider['sidebarEl'],\r\n tabs?: SidebarSlider['tabs'],\r\n canHideFirst?: SidebarSlider['canHideFirst'],\r\n navigationType: SidebarSlider['navigationType']\r\n }) {\r\n safeAssign(this, options);\r\n\r\n if(!this.tabs) {\r\n this.tabs = new Map();\r\n }\r\n\r\n this.tabsContainer = this.sidebarEl.querySelector('.sidebar-slider');\r\n this._selectTab = TransitionSlider(this.tabsContainer, 'navigation', TRANSITION_TIME);\r\n if(!this.canHideFirst) {\r\n this._selectTab(0);\r\n }\r\n\r\n Array.from(this.sidebarEl.querySelectorAll('.sidebar-close-button') as any as HTMLElement[]).forEach(el => {\r\n attachClickEvent(el, this.onCloseBtnClick);\r\n });\r\n }\r\n\r\n public onCloseBtnClick = () => {\r\n const item = appNavigationController.findItemByType(this.navigationType);\r\n if(item) {\r\n appNavigationController.back(this.navigationType);\r\n } else if(this.historyTabIds.length) {\r\n this.closeTab(this.historyTabIds[this.historyTabIds.length - 1]);\r\n }\r\n // this.closeTab();\r\n };\r\n\r\n public closeTab = (id?: number | SliderSuperTab, animate?: boolean, isNavigation?: boolean) => {\r\n if(id !== undefined && this.historyTabIds[this.historyTabIds.length - 1] !== id) {\r\n return false;\r\n }\r\n\r\n //console.log('sidebar-close-button click:', this.historyTabIDs);\r\n const closingId = this.historyTabIds.pop(); // pop current\r\n this.onCloseTab(closingId, animate, isNavigation);\r\n\r\n const tab = this.historyTabIds[this.historyTabIds.length - 1];\r\n this._selectTab(tab !== undefined ? (tab instanceof SliderSuperTab ? tab.container : tab) : (this.canHideFirst ? -1 : 0), animate);\r\n return true;\r\n };\r\n\r\n public selectTab(id: number | SliderSuperTab): boolean {\r\n /* if(id instanceof SliderSuperTab) {\r\n id = id.id;\r\n } */\r\n\r\n if(this.historyTabIds[this.historyTabIds.length - 1] === id) {\r\n return false;\r\n }\r\n\r\n const tab: SliderTab = id instanceof SliderSuperTab ? id : this.tabs.get(id);\r\n if(tab) {\r\n if(tab.onOpen) {\r\n tab.onOpen();\r\n }\r\n \r\n if(tab.onOpenAfterTimeout) {\r\n setTimeout(() => {\r\n tab.onOpenAfterTimeout();\r\n }, TRANSITION_TIME);\r\n }\r\n }\r\n\r\n //if(!this.canHideFirst || this.historyTabIds.length) {\r\n appNavigationController.pushItem({\r\n type: this.navigationType, \r\n onPop: (canAnimate) => {\r\n this.closeTab(undefined, canAnimate, true);\r\n return true;\r\n }\r\n });\r\n //}\r\n \r\n this.historyTabIds.push(id);\r\n this._selectTab(id instanceof SliderSuperTab ? id.container : id);\r\n return true;\r\n }\r\n\r\n public removeTabFromHistory(id: number | SliderSuperTab) {\r\n indexOfAndSplice(this.historyTabIds, id);\r\n this.onCloseTab(id, undefined);\r\n }\r\n\r\n public sliceTabsUntilTab(tabConstructor: SliderSuperTabConstructable, preserveTab: SliderSuperTab) {\r\n for(let i = this.historyTabIds.length - 1; i >= 0; --i) {\r\n const tab = this.historyTabIds[i];\r\n if(tab === preserveTab) continue;\r\n else if(tab instanceof tabConstructor) {\r\n break;\r\n }\r\n\r\n this.removeTabFromHistory(tab);\r\n //appNavigationController.removeByType(this.navigationType, true);\r\n }\r\n }\r\n\r\n public getTab(tabConstructor: SliderSuperTabConstructable) {\r\n return this.historyTabIds.find(t => t instanceof tabConstructor) as SliderSuperTab;\r\n }\r\n\r\n public isTabExists(tabConstructor: SliderSuperTabConstructable) {\r\n return !!this.getTab(tabConstructor);\r\n }\r\n\r\n protected onCloseTab(id: number | SliderSuperTab, animate: boolean, isNavigation?: boolean) {\r\n if(!isNavigation) {\r\n appNavigationController.removeByType(this.navigationType, true);\r\n }\r\n\r\n const tab: SliderTab = id instanceof SliderSuperTab ? id : this.tabs.get(id);\r\n if(tab) {\r\n if(tab.onClose) {\r\n tab.onClose();\r\n }\r\n\r\n if(tab.onCloseAfterTimeout) {\r\n setTimeout(() => {\r\n tab.onCloseAfterTimeout();\r\n }, TRANSITION_TIME);\r\n }\r\n }\r\n }\r\n\r\n public addTab(tab: SliderSuperTab) {\r\n if(!tab.container.parentElement) {\r\n this.tabsContainer.append(tab.container);\r\n\r\n if(tab.closeBtn) {\r\n tab.closeBtn.addEventListener('click', this.onCloseBtnClick);\r\n }\r\n }\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport type { CancellablePromise } from \"../helpers/cancellablePromise\";\r\nimport { attachClickEvent } from \"../helpers/dom/clickEvent\";\r\nimport type { InputFile } from \"../layer\";\r\nimport PopupAvatar from \"./popups/avatar\";\r\n\r\nexport default class AvatarEdit {\r\n public container: HTMLElement;\r\n private canvas: HTMLCanvasElement;\r\n private icon: HTMLSpanElement;\r\n\r\n constructor(onChange: (uploadAvatar: () => CancellablePromise<InputFile>) => void) {\r\n this.container = document.createElement('div');\r\n this.container.classList.add('avatar-edit');\r\n\r\n this.canvas = document.createElement('canvas');\r\n this.canvas.classList.add('avatar-edit-canvas');\r\n\r\n this.icon = document.createElement('span');\r\n this.icon.classList.add('tgico', 'tgico-cameraadd');\r\n\r\n this.container.append(this.canvas, this.icon);\r\n\r\n attachClickEvent(this.container, () => {\r\n new PopupAvatar().open(this.canvas, onChange);\r\n });\r\n }\r\n\r\n public clear() {\r\n const ctx = this.canvas.getContext('2d');\r\n ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport Button from \"./button\";\r\n\r\nconst ButtonCorner = (options: Partial<{className: string, icon: string, noRipple: true, onlyMobile: true, asDiv: boolean}> = {}) => {\r\n const button = Button('btn-circle btn-corner z-depth-1' + (options.className ? ' ' + options.className : ''), options);\r\n return button;\r\n};\r\n\r\nexport default ButtonCorner;\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport appSidebarLeft, { SettingSection } from \"..\";\r\nimport { InputFile } from \"../../../layer\";\r\nimport appChatsManager from \"../../../lib/appManagers/appChatsManager\";\r\nimport appDialogsManager from \"../../../lib/appManagers/appDialogsManager\";\r\nimport appUsersManager from \"../../../lib/appManagers/appUsersManager\";\r\nimport InputField from \"../../inputField\";\r\nimport { SliderSuperTab } from \"../../slider\";\r\nimport AvatarEdit from \"../../avatarEdit\";\r\nimport I18n from \"../../../lib/langPack\";\r\nimport ButtonCorner from \"../../buttonCorner\";\r\n\r\ninterface OpenStreetMapInterface {\r\n place_id?: number;\r\n license?: string;\r\n osm_type?: string;\r\n osm_id?: number;\r\n lat?: string;\r\n lon?: string;\r\n display_name: string;\r\n address?: object;\r\n boundingbox?: object;\r\n}\r\n\r\nexport default class AppNewGroupTab extends SliderSuperTab {\r\n private avatarEdit: AvatarEdit;\r\n private uploadAvatar: () => Promise<InputFile> = null;\r\n private peerIds: PeerId[];\r\n private isGeoChat: boolean = false;\r\n private nextBtn: HTMLButtonElement;\r\n private groupNameInputField: InputField;\r\n private list: HTMLUListElement;\r\n private groupLocationInputField: InputField;\r\n private userLocationCoords: {lat: number, long: number};\r\n private userLocationAddress: string;\r\n\r\n protected init() {\r\n this.container.classList.add('new-group-container');\r\n this.setTitle('NewGroup');\r\n\r\n this.avatarEdit = new AvatarEdit((_upload) => {\r\n this.uploadAvatar = _upload;\r\n });\r\n\r\n const section = new SettingSection({});\r\n\r\n const inputWrapper = document.createElement('div');\r\n inputWrapper.classList.add('input-wrapper');\r\n\r\n this.groupNameInputField = new InputField({\r\n label: 'CreateGroup.NameHolder',\r\n maxLength: 128\r\n });\r\n\r\n this.groupLocationInputField = new InputField({\r\n label: 'ChatLocation',\r\n name: 'location',\r\n canBeEdited: false\r\n });\r\n\r\n inputWrapper.append(\r\n this.groupNameInputField.container,\r\n this.groupLocationInputField.container\r\n );\r\n\r\n this.groupNameInputField.input.addEventListener('input', () => {\r\n const value = this.groupNameInputField.value;\r\n let valueCheck = !!value.length && !this.groupNameInputField.input.classList.contains('error');\r\n if(this.isGeoChat) valueCheck = valueCheck && !!this.userLocationCoords && !!this.userLocationAddress;\r\n this.nextBtn.classList.toggle('is-visible', !!valueCheck);\r\n });\r\n\r\n this.nextBtn = ButtonCorner({icon: 'arrow_next'});\r\n\r\n this.nextBtn.addEventListener('click', () => {\r\n const title = this.groupNameInputField.value;\r\n\r\n if(this.isGeoChat){\r\n if(!this.userLocationAddress || !this.userLocationCoords) return;\r\n appChatsManager.createChannel({\r\n title, \r\n about: '', \r\n geo_point: {\r\n _: 'inputGeoPoint',\r\n ...this.userLocationCoords, \r\n },\r\n address: this.userLocationAddress,\r\n megagroup: true\r\n }).then((chatId) => {\r\n if(this.uploadAvatar) {\r\n this.uploadAvatar().then((inputFile) => {\r\n appChatsManager.editPhoto(chatId, inputFile);\r\n });\r\n }\r\n\r\n if(this.peerIds.length){\r\n appChatsManager.inviteToChannel(chatId, this.peerIds);\r\n }\r\n \r\n appSidebarLeft.removeTabFromHistory(this);\r\n appSidebarLeft.selectTab(0);\r\n });\r\n } else {\r\n this.nextBtn.disabled = true;\r\n appChatsManager.createChat(title, this.peerIds.map(peerId => peerId.toUserId())).then((chatId) => {\r\n if(this.uploadAvatar) {\r\n this.uploadAvatar().then((inputFile) => {\r\n appChatsManager.editPhoto(chatId, inputFile);\r\n });\r\n }\r\n \r\n appSidebarLeft.removeTabFromHistory(this);\r\n appSidebarLeft.selectTab(0);\r\n });\r\n }\r\n });\r\n\r\n const chatsSection = new SettingSection({\r\n name: 'Members',\r\n nameArgs: [this.peerIds.length]\r\n });\r\n\r\n const list = this.list = appDialogsManager.createChatList({\r\n new: true\r\n });\r\n\r\n chatsSection.content.append(list);\r\n\r\n section.content.append(this.avatarEdit.container, inputWrapper);\r\n\r\n this.content.append(this.nextBtn);\r\n this.scrollable.append(section.container, chatsSection.container);\r\n }\r\n\r\n public onCloseAfterTimeout() {\r\n this.avatarEdit.clear();\r\n this.uploadAvatar = null;\r\n this.groupNameInputField.value = '';\r\n this.groupLocationInputField.container.classList.add('hide');\r\n this.nextBtn.disabled = false;\r\n }\r\n\r\n public open(peerIds: PeerId[], isGeoChat: boolean = false) {\r\n this.isGeoChat = isGeoChat;\r\n this.peerIds = peerIds;\r\n const result = super.open();\r\n result.then(() => {\r\n if(isGeoChat) {\r\n this.setTitle('NearbyCreateGroup');\r\n this.groupLocationInputField.container.classList.remove('hide');\r\n this.groupLocationInputField.setValueSilently(I18n.format('Loading', true));\r\n this.startLocating();\r\n } else {\r\n this.groupLocationInputField.container.classList.add('hide');\r\n }\r\n\r\n this.peerIds.forEach(userId => {\r\n const {dom} = appDialogsManager.addDialogNew({\r\n dialog: userId,\r\n container: this.list,\r\n drawStatus: false,\r\n rippleEnabled: false,\r\n avatarSize: 48\r\n });\r\n\r\n dom.lastMessageSpan.append(appUsersManager.getUserStatusString(userId));\r\n });\r\n });\r\n \r\n return result;\r\n }\r\n\r\n private startLocating(){\r\n navigator.geolocation.getCurrentPosition((location) => {\r\n this.userLocationCoords = {\r\n lat: location.coords.latitude,\r\n long: location.coords.longitude\r\n };\r\n\r\n let uri = \"https://nominatim.openstreetmap.org/reverse\";\r\n uri += \"?lat=\"+location.coords.latitude;\r\n uri += \"&lon=\"+location.coords.longitude;\r\n uri += \"&format=json\";\r\n uri += \"&addressdetails=1\";\r\n uri += \"&accept-language=en\";\r\n fetch(uri)\r\n .then((response) => response.json())\r\n .then((response: OpenStreetMapInterface) => {\r\n this.userLocationAddress = response.display_name;\r\n this.groupLocationInputField.setValueSilently(response.display_name);\r\n });\r\n }, (error) => {\r\n if(error instanceof GeolocationPositionError) {\r\n this.groupLocationInputField.setValueSilently('Location permission denied. Please retry later.');\r\n } else {\r\n this.groupLocationInputField.setValueSilently('An error has occurred. Please retry later.');\r\n }\r\n });\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport rootScope from \"../lib/rootScope\";\r\nimport appMessagesManager from \"../lib/appManagers/appMessagesManager\";\r\nimport appDocsManager, {MyDocument} from \"../lib/appManagers/appDocsManager\";\r\nimport deferredPromise, { CancellablePromise } from \"../helpers/cancellablePromise\";\r\nimport { IS_APPLE, IS_SAFARI } from \"../environment/userAgent\";\r\nimport { MOUNT_CLASS_TO } from \"../config/debug\";\r\nimport appDownloadManager from \"../lib/appManagers/appDownloadManager\";\r\nimport simulateEvent from \"../helpers/dom/dispatchEvent\";\r\nimport type { SearchSuperContext } from \"./appSearchSuper.\";\r\nimport { DocumentAttribute, Message, PhotoSize } from \"../layer\";\r\nimport appPhotosManager from \"../lib/appManagers/appPhotosManager\";\r\nimport { IS_TOUCH_SUPPORTED } from \"../environment/touchSupport\";\r\nimport appAvatarsManager from \"../lib/appManagers/appAvatarsManager\";\r\nimport appPeersManager from \"../lib/appManagers/appPeersManager\";\r\nimport I18n from \"../lib/langPack\";\r\nimport SearchListLoader from \"../helpers/searchListLoader\";\r\nimport { onMediaLoad } from \"../helpers/files\";\r\nimport copy from \"../helpers/object/copy\";\r\nimport deepEqual from \"../helpers/object/deepEqual\";\r\nimport ListenerSetter from \"../helpers/listenerSetter\";\r\n\r\n// TODO: Safari: проверить стрим, включить его и сразу попробовать включить видео или другую песню\r\n// TODO: Safari: попробовать замаскировать подгрузку последнего чанка\r\n// TODO: Safari: пофиксить момент, когда заканчивается песня и пытаешься включить её заново - прогресс сразу в конце\r\n\r\nexport type MediaItem = {mid: number, peerId: PeerId};\r\n\r\ntype HTMLMediaElement = HTMLAudioElement | HTMLVideoElement;\r\n\r\nconst SHOULD_USE_SAFARI_FIX = (() => {\r\n try {\r\n return IS_SAFARI && +navigator.userAgent.match(/ Version\\/(\\d+)/)[1] < 14;\r\n } catch(err) {\r\n return false;\r\n }\r\n})();\r\n\r\nconst SEEK_OFFSET = 10;\r\n\r\nexport type MediaSearchContext = SearchSuperContext & Partial<{\r\n isScheduled: boolean,\r\n useSearch: boolean\r\n}>;\r\n\r\ntype MediaDetails = {\r\n peerId: PeerId, \r\n mid: number, \r\n docId: DocId, \r\n clean?: boolean,\r\n isScheduled?: boolean, \r\n isSingle?: boolean\r\n};\r\n\r\nexport type PlaybackMediaType = 'voice' | 'video' | 'audio';\r\n\r\nexport class AppMediaPlaybackController {\r\n private container: HTMLElement;\r\n private media: Map<PeerId, Map<number, HTMLMediaElement>> = new Map();\r\n private scheduled: AppMediaPlaybackController['media'] = new Map();\r\n private mediaDetails: Map<HTMLMediaElement, MediaDetails> = new Map();\r\n private playingMedia: HTMLMediaElement;\r\n private playingMediaType: PlaybackMediaType;\r\n\r\n private waitingMediaForLoad: Map<PeerId, Map<number, CancellablePromise<void>>> = new Map();\r\n private waitingScheduledMediaForLoad: AppMediaPlaybackController['waitingMediaForLoad'] = new Map();\r\n private waitingDocumentsForLoad: {[docId: string]: Set<HTMLMediaElement>} = {};\r\n \r\n public willBePlayedMedia: HTMLMediaElement;\r\n private searchContext: MediaSearchContext;\r\n\r\n private listLoader: SearchListLoader<MediaItem>;\r\n\r\n public volume: number;\r\n public muted: boolean;\r\n public playbackRate: number;\r\n public loop: boolean;\r\n public round: boolean;\r\n private _volume: number;\r\n private _muted: boolean;\r\n private _playbackRate: number;\r\n private _loop: boolean;\r\n private _round: boolean;\r\n private lockedSwitchers: boolean;\r\n private playbackRates: Record<PlaybackMediaType, number> = {\r\n voice: 1,\r\n video: 1,\r\n audio: 1\r\n };\r\n\r\n private pip: HTMLVideoElement;\r\n\r\n constructor() {\r\n this.container = document.createElement('div');\r\n //this.container.style.cssText = 'position: absolute; top: -10000px; left: -10000px;';\r\n this.container.style.cssText = 'display: none;';\r\n document.body.append(this.container);\r\n\r\n if(navigator.mediaSession) {\r\n const actions: {[action in MediaSessionAction]?: MediaSessionActionHandler} = {\r\n play: this.browserPlay,\r\n pause: this.browserPause,\r\n stop: this.browserStop,\r\n seekbackward: this.browserSeekBackward,\r\n seekforward: this.browserSeekForward,\r\n seekto: this.browserSeekTo,\r\n previoustrack: this.browserPrevious,\r\n nexttrack: this.browserNext\r\n };\r\n\r\n for(const action in actions) {\r\n try {\r\n navigator.mediaSession.setActionHandler(action as MediaSessionAction, actions[action as MediaSessionAction]);\r\n } catch(err) {\r\n console.warn('MediaSession action is not supported:', action);\r\n }\r\n }\r\n }\r\n\r\n rootScope.addEventListener('document_downloaded', (doc) => {\r\n const set = this.waitingDocumentsForLoad[doc.id];\r\n if(set) {\r\n for(const media of set) {\r\n this.onMediaDocumentLoad(media);\r\n }\r\n }\r\n });\r\n\r\n const properties: {[key: PropertyKey]: PropertyDescriptor} = {};\r\n const keys = [\r\n 'volume' as const, \r\n 'muted' as const, \r\n 'playbackRate' as const,\r\n 'loop' as const,\r\n 'round' as const\r\n ];\r\n keys.forEach(key => {\r\n const _key = ('_' + key) as `_${typeof key}`;\r\n properties[key] = {\r\n get: () => this[_key],\r\n set: (value: number | boolean) => {\r\n if(this[_key] === value) {\r\n return;\r\n }\r\n\r\n // @ts-ignore\r\n this[_key] = value;\r\n if(this.playingMedia && (key !== 'loop' || this.playingMediaType === 'audio') && key !== 'round') {\r\n // @ts-ignore\r\n this.playingMedia[key] = value;\r\n }\r\n\r\n if(key === 'playbackRate' && this.playingMediaType !== undefined) {\r\n this.playbackRates[this.playingMediaType] = value as number;\r\n }\r\n\r\n this.dispatchPlaybackParams();\r\n }\r\n };\r\n });\r\n Object.defineProperties(this, properties);\r\n }\r\n\r\n private dispatchPlaybackParams() {\r\n rootScope.dispatchEvent('media_playback_params', this.getPlaybackParams());\r\n }\r\n\r\n public getPlaybackParams() {\r\n const {volume, muted, playbackRate, playbackRates, loop, round} = this;\r\n return {\r\n volume, \r\n muted, \r\n playbackRate,\r\n playbackRates,\r\n loop,\r\n round\r\n };\r\n }\r\n\r\n public setPlaybackParams(params: ReturnType<AppMediaPlaybackController['getPlaybackParams']>) {\r\n this.playbackRates = params.playbackRates;\r\n this._volume = params.volume;\r\n this._muted = params.muted;\r\n this._playbackRate = params.playbackRate;\r\n this._loop = params.loop;\r\n this._round = params.round;\r\n }\r\n \r\n public seekBackward = (details: MediaSessionActionDetails, media = this.playingMedia) => {\r\n if(media) {\r\n media.currentTime = Math.max(0, media.currentTime - (details.seekOffset || SEEK_OFFSET));\r\n }\r\n };\r\n\r\n public seekForward = (details: MediaSessionActionDetails, media = this.playingMedia) => {\r\n if(media) {\r\n media.currentTime = Math.min(media.duration, media.currentTime + (details.seekOffset || SEEK_OFFSET));\r\n }\r\n };\r\n\r\n public seekTo = (details: MediaSessionActionDetails, media = this.playingMedia) => {\r\n if(media) {\r\n media.currentTime = details.seekTime;\r\n }\r\n };\r\n\r\n public addMedia(message: Message.message, autoload: boolean, clean?: boolean): HTMLMediaElement {\r\n const {peerId, mid} = message;\r\n\r\n const isScheduled = !!message.pFlags.is_scheduled;\r\n const s = isScheduled ? this.scheduled : this.media;\r\n let storage = s.get(message.peerId);\r\n if(!storage) {\r\n s.set(message.peerId, storage = new Map());\r\n }\r\n\r\n let media = storage.get(mid);\r\n if(media) {\r\n return media;\r\n }\r\n\r\n const doc: MyDocument = appMessagesManager.getMediaFromMessage(message);\r\n storage.set(mid, media = document.createElement(doc.type === 'round' || doc.type === 'video' ? 'video' : 'audio'));\r\n //const source = document.createElement('source');\r\n //source.type = doc.type === 'voice' && !opusDecodeController.isPlaySupported() ? 'audio/wav' : doc.mime_type;\r\n\r\n if(doc.type === 'round') {\r\n media.setAttribute('playsinline', 'true');\r\n //media.muted = true;\r\n }\r\n\r\n const details: MediaDetails = {\r\n peerId,\r\n mid,\r\n docId: doc.id,\r\n clean,\r\n isScheduled: message.pFlags.is_scheduled\r\n };\r\n\r\n this.mediaDetails.set(media, details);\r\n\r\n //media.autoplay = true;\r\n media.volume = 1;\r\n //media.append(source);\r\n\r\n this.container.append(media);\r\n\r\n media.addEventListener('play', this.onPlay);\r\n media.addEventListener('pause', this.onPause);\r\n media.addEventListener('ended', this.onEnded);\r\n\r\n if(doc.type !== 'audio' && message?.pFlags.media_unread && message.fromId !== rootScope.myId) {\r\n media.addEventListener('timeupdate', () => {\r\n appMessagesManager.readMessages(peerId, [mid]);\r\n }, {once: true});\r\n }\r\n \r\n /* const onError = (e: Event) => {\r\n //console.log('appMediaPlaybackController: video onError', e);\r\n\r\n if(this.nextMid === mid) {\r\n this.loadSiblingsMedia(peerId, doc.type as MediaType, mid).then(() => {\r\n if(this.nextMid && storage[this.nextMid]) {\r\n storage[this.nextMid].play();\r\n }\r\n });\r\n }\r\n };\r\n\r\n media.addEventListener('error', onError); */\r\n\r\n const deferred = deferredPromise<void>();\r\n if(autoload) {\r\n deferred.resolve();\r\n } else {\r\n const w = message.pFlags.is_scheduled ? this.waitingScheduledMediaForLoad : this.waitingMediaForLoad;\r\n let waitingStorage = w.get(peerId);\r\n if(!waitingStorage) {\r\n w.set(peerId, waitingStorage = new Map());\r\n }\r\n\r\n waitingStorage.set(mid, deferred);\r\n }\r\n\r\n deferred.then(() => {\r\n //media.autoplay = true;\r\n //console.log('will set media url:', media, doc, doc.type, doc.url);\r\n\r\n const cacheContext = appDownloadManager.getCacheContext(doc);\r\n if(doc.supportsStreaming || cacheContext.url) {\r\n this.onMediaDocumentLoad(media);\r\n } else {\r\n let set = this.waitingDocumentsForLoad[doc.id];\r\n if(!set) {\r\n set = this.waitingDocumentsForLoad[doc.id] = new Set();\r\n }\r\n\r\n set.add(media);\r\n appDocsManager.downloadDoc(doc);\r\n }\r\n }/* , onError */);\r\n \r\n return media;\r\n }\r\n\r\n public getMedia(peerId: PeerId, mid: number, isScheduled?: boolean) {\r\n const s = (isScheduled ? this.scheduled : this.media).get(peerId);\r\n return s?.get(mid);\r\n }\r\n\r\n private onMediaDocumentLoad = (media: HTMLMediaElement) => {\r\n const details = this.mediaDetails.get(media);\r\n const doc = appDocsManager.getDoc(details.docId);\r\n if(doc.type === 'audio' && doc.supportsStreaming && SHOULD_USE_SAFARI_FIX) {\r\n this.handleSafariStreamable(media);\r\n }\r\n\r\n // setTimeout(() => {\r\n const cacheContext = appDownloadManager.getCacheContext(doc);\r\n media.src = cacheContext.url;\r\n\r\n if(this.playingMedia === media) {\r\n media.playbackRate = this.playbackRate;\r\n\r\n if(doc.type === 'audio') {\r\n media.loop = this.loop;\r\n }\r\n }\r\n // }, doc.supportsStreaming ? 500e3 : 0);\r\n\r\n const set = this.waitingDocumentsForLoad[doc.id];\r\n if(set) {\r\n set.delete(media);\r\n\r\n if(!set.size) {\r\n delete this.waitingDocumentsForLoad[doc.id];\r\n }\r\n }\r\n };\r\n\r\n // safari подгрузит последний чанк и песня включится,\r\n // при этом этот чанк нельзя руками отдать из SW, потому что браузер тогда теряется\r\n private handleSafariStreamable(media: HTMLMediaElement) {\r\n media.addEventListener('play', () => {\r\n /* if(media.readyState === 4) { // https://developer.mozilla.org/ru/docs/Web/API/XMLHttpRequest/readyState\r\n return;\r\n } */\r\n\r\n //media.volume = 0;\r\n const currentTime = media.currentTime;\r\n //this.setSafariBuffering(media, true);\r\n\r\n media.addEventListener('progress', () => {\r\n media.currentTime = media.duration - 1;\r\n\r\n media.addEventListener('progress', () => {\r\n media.currentTime = currentTime;\r\n //media.volume = 1;\r\n //this.setSafariBuffering(media, false);\r\n\r\n if(!media.paused) {\r\n media.play()/* .catch(() => {}) */;\r\n }\r\n }, {once: true});\r\n }, {once: true});\r\n }/* , {once: true} */);\r\n }\r\n\r\n public resolveWaitingForLoadMedia(peerId: PeerId, mid: number, isScheduled?: boolean) {\r\n const w = isScheduled ? this.waitingScheduledMediaForLoad : this.waitingMediaForLoad;\r\n const storage = w.get(peerId);\r\n if(!storage) {\r\n return;\r\n }\r\n\r\n const promise = storage.get(mid);\r\n if(promise) {\r\n promise.resolve();\r\n storage.delete(mid);\r\n\r\n if(!storage.size) {\r\n w.delete(peerId);\r\n }\r\n }\r\n }\r\n \r\n /**\r\n * Only for audio\r\n */\r\n public isSafariBuffering(media: HTMLMediaElement) {\r\n /// @ts-ignore\r\n return !!media.safariBuffering;\r\n }\r\n\r\n private setSafariBuffering(media: HTMLMediaElement, value: boolean) {\r\n // @ts-ignore\r\n media.safariBuffering = value;\r\n }\r\n\r\n private async setNewMediadata(message: Message.message, playingMedia = this.playingMedia) {\r\n if(document.pictureInPictureElement) {\r\n return;\r\n }\r\n\r\n await onMediaLoad(playingMedia, undefined, false); // have to wait for load, otherwise on macOS won't set\r\n\r\n const doc = appMessagesManager.getMediaFromMessage(message) as MyDocument;\r\n \r\n const artwork: MediaImage[] = [];\r\n\r\n const isVoice = doc.type === 'voice' || doc.type === 'round';\r\n let title = '', artist = '';\r\n\r\n if(doc.thumbs?.length) {\r\n const size = doc.thumbs[doc.thumbs.length - 1];\r\n if(!(size as PhotoSize.photoStrippedSize).bytes) {\r\n const cacheContext = appDownloadManager.getCacheContext(doc, size.type);\r\n\r\n if(cacheContext.url) {\r\n artwork.push({\r\n src: cacheContext.url,\r\n sizes: `${(size as PhotoSize.photoSize).w}x${(size as PhotoSize.photoSize).h}`,\r\n type: 'image/jpeg'\r\n });\r\n } else {\r\n const download = appPhotosManager.preloadPhoto(doc, size);\r\n download.then(() => {\r\n if(this.playingMedia !== playingMedia || !cacheContext.url) {\r\n return;\r\n }\r\n\r\n this.setNewMediadata(message);\r\n });\r\n }\r\n }\r\n } else if(isVoice) {\r\n const peerId = message.fromId || message.peerId;\r\n const peerPhoto = appPeersManager.getPeerPhoto(peerId);\r\n if(peerPhoto) {\r\n const result = appAvatarsManager.loadAvatar(peerId, peerPhoto, 'photo_small');\r\n if(result.cached) {\r\n const url = await result.loadPromise;\r\n artwork.push({\r\n src: url,\r\n sizes: '160x160',\r\n type: 'image/jpeg'\r\n });\r\n } else {\r\n result.loadPromise.then((url) => {\r\n if(this.playingMedia !== playingMedia || !url) {\r\n return;\r\n }\r\n \r\n this.setNewMediadata(message);\r\n });\r\n }\r\n }\r\n\r\n title = appPeersManager.getPeerTitle(peerId, true, false);\r\n artist = I18n.format(doc.type === 'voice' ? 'AttachAudio' : 'AttachRound', true);\r\n }\r\n\r\n if(!isVoice) {\r\n const attribute = doc.attributes.find(attribute => attribute._ === 'documentAttributeAudio') as DocumentAttribute.documentAttributeAudio;\r\n title = attribute?.title ?? doc.file_name;\r\n artist = attribute?.performer;\r\n }\r\n\r\n if(!artwork.length) {\r\n if(IS_APPLE) {\r\n if(IS_TOUCH_SUPPORTED) {\r\n artwork.push({\r\n src: `assets/img/apple-touch-icon-precomposed.png`,\r\n sizes: '180x180',\r\n type: 'image/png'\r\n });\r\n } else {\r\n artwork.push({\r\n src: `assets/img/apple-touch-icon.png`,\r\n sizes: '180x180',\r\n type: 'image/png'\r\n });\r\n }\r\n } else {\r\n [72, 96, 144, 192, 256, 384, 512].forEach(size => {\r\n const sizes = `${size}x${size}`;\r\n artwork.push({\r\n src: `assets/img/android-chrome-${sizes}.png`,\r\n sizes,\r\n type: 'image/png'\r\n });\r\n });\r\n }\r\n }\r\n\r\n const metadata = new MediaMetadata({\r\n title,\r\n artist,\r\n artwork\r\n });\r\n\r\n navigator.mediaSession.metadata = metadata;\r\n }\r\n\r\n public setCurrentMediadata() {\r\n const {playingMedia} = this;\r\n if(!playingMedia) return;\r\n const message = this.getMessageByMedia(playingMedia);\r\n this.setNewMediadata(message, playingMedia);\r\n }\r\n\r\n private getMessageByMedia(media: HTMLMediaElement): Message.message {\r\n const details = this.mediaDetails.get(media);\r\n const {peerId, mid} = details;\r\n const message = details.isScheduled ? appMessagesManager.getScheduledMessageByPeer(peerId, mid) : appMessagesManager.getMessageByPeer(peerId, mid);\r\n return message;\r\n }\r\n\r\n public getPlayingDetails() {\r\n const {playingMedia} = this;\r\n if(!playingMedia) {\r\n return;\r\n }\r\n\r\n const message = this.getMessageByMedia(playingMedia);\r\n return {\r\n doc: appMessagesManager.getMediaFromMessage(message) as MyDocument,\r\n message,\r\n media: playingMedia,\r\n playbackParams: this.getPlaybackParams()\r\n };\r\n }\r\n\r\n private onPlay = (e?: Event) => {\r\n const media = e.target as HTMLMediaElement;\r\n const details = this.mediaDetails.get(media);\r\n const {peerId, mid} = details;\r\n\r\n //console.log('appMediaPlaybackController: video playing', this.currentPeerId, this.playingMedia, media);\r\n\r\n const pip = this.pip;\r\n if(pip) {\r\n pip.pause();\r\n }\r\n\r\n const message = this.getMessageByMedia(media);\r\n\r\n const previousMedia = this.playingMedia;\r\n if(previousMedia !== media) {\r\n this.stop();\r\n this.setMedia(media, message);\r\n\r\n const verify = (element: MediaItem) => element.mid === mid && element.peerId === peerId;\r\n const listLoader = this.listLoader;\r\n const current = listLoader.getCurrent();\r\n if(!current || !verify(current)) {\r\n const previous = listLoader.getPrevious();\r\n\r\n let idx = previous.findIndex(verify);\r\n let jumpLength: number;\r\n if(idx !== -1) {\r\n jumpLength = -(previous.length - idx);\r\n } else {\r\n idx = listLoader.getNext().findIndex(verify);\r\n if(idx !== -1) {\r\n jumpLength = idx + 1;\r\n }\r\n }\r\n \r\n if(idx !== -1) {\r\n if(jumpLength) {\r\n this.go(jumpLength, false);\r\n }\r\n } else {\r\n this.setTargets({peerId, mid});\r\n }\r\n }\r\n }\r\n\r\n // audio_pause не успеет сработать без таймаута\r\n setTimeout(() => {\r\n if(this.playingMedia !== media) {\r\n return;\r\n }\r\n\r\n rootScope.dispatchEvent('media_play', this.getPlayingDetails());\r\n }, 0);\r\n };\r\n\r\n private onPause = (e?: Event) => {\r\n /* const target = e.target as HTMLMediaElement;\r\n if(!isInDOM(target)) {\r\n this.container.append(target);\r\n target.play();\r\n return;\r\n } */\r\n\r\n // if(this.pip) {\r\n // this.pip.play();\r\n // }\r\n\r\n rootScope.dispatchEvent('media_pause');\r\n };\r\n\r\n private onEnded = (e?: Event) => {\r\n if(!e.isTrusted) {\r\n return;\r\n }\r\n\r\n this.onPause(e);\r\n\r\n //console.log('on media end');\r\n\r\n const listLoader = this.listLoader;\r\n if(this.lockedSwitchers || \r\n (!this.round && listLoader.current && !listLoader.next.length) || \r\n !listLoader.getNext().length || \r\n !this.next()) {\r\n this.stop();\r\n rootScope.dispatchEvent('media_stop');\r\n }\r\n };\r\n\r\n // public get pip() {\r\n // return document.pictureInPictureElement as HTMLVideoElement;\r\n // }\r\n\r\n public toggle(play?: boolean, media = this.playingMedia) {\r\n if(!media) {\r\n return false;\r\n }\r\n\r\n if(play === undefined) {\r\n play = media.paused;\r\n }\r\n\r\n if(media.paused !== play) {\r\n return false;\r\n }\r\n\r\n if(play) {\r\n media.play();\r\n } else {\r\n media.pause();\r\n }\r\n\r\n return true;\r\n }\r\n\r\n public play = () => {\r\n return this.toggle(true);\r\n };\r\n\r\n public pause = () => {\r\n return this.toggle(false);\r\n };\r\n\r\n public stop = (media = this.playingMedia) => {\r\n if(!media) {\r\n return false;\r\n }\r\n\r\n if(!media.paused) {\r\n media.pause();\r\n }\r\n\r\n media.currentTime = 0;\r\n simulateEvent(media, 'ended');\r\n\r\n if(media === this.playingMedia) {\r\n const details = this.mediaDetails.get(media);\r\n if(details?.clean) {\r\n media.src = '';\r\n const peerId = details.peerId;\r\n const s = details.isScheduled ? this.scheduled : this.media;\r\n const storage = s.get(peerId);\r\n if(storage) {\r\n storage.delete(details.mid);\r\n \r\n if(!storage.size) {\r\n s.delete(peerId);\r\n }\r\n }\r\n \r\n media.remove();\r\n \r\n this.mediaDetails.delete(media);\r\n }\r\n \r\n this.playingMedia = undefined;\r\n this.playingMediaType = undefined;\r\n }\r\n\r\n return true;\r\n };\r\n\r\n public playItem = (item: MediaItem) => {\r\n const {peerId, mid} = item;\r\n const isScheduled = this.searchContext.isScheduled;\r\n const media = this.getMedia(peerId, mid, isScheduled);\r\n\r\n /* if(isSafari) {\r\n media.autoplay = true;\r\n } */\r\n\r\n media.play();\r\n \r\n setTimeout(() => {\r\n this.resolveWaitingForLoadMedia(peerId, mid, isScheduled);\r\n }, 0);\r\n };\r\n\r\n public go = (length: number, dispatchJump?: boolean) => {\r\n const listLoader = this.listLoader;\r\n if(this.lockedSwitchers || !listLoader) {\r\n return;\r\n }\r\n\r\n if(this.playingMediaType === 'audio') {\r\n return listLoader.goRound(length, dispatchJump);\r\n } else {\r\n return listLoader.go(length, dispatchJump);\r\n }\r\n };\r\n\r\n private bindBrowserCallback(cb: (video: HTMLVideoElement, details: MediaSessionActionDetails) => void) {\r\n const handler: MediaSessionActionHandler = (details) => {\r\n cb(this.pip, details);\r\n };\r\n\r\n return handler;\r\n }\r\n\r\n public browserPlay = this.bindBrowserCallback((video) => this.toggle(true, video));\r\n public browserPause = this.bindBrowserCallback((video) => this.toggle(false, video));\r\n public browserStop = this.bindBrowserCallback((video) => this.stop(video));\r\n public browserSeekBackward = this.bindBrowserCallback((video, details) => this.seekBackward(details, video));\r\n public browserSeekForward = this.bindBrowserCallback((video, details) => this.seekForward(details, video));\r\n public browserSeekTo = this.bindBrowserCallback((video, details) => this.seekTo(details, video));\r\n public browserNext = this.bindBrowserCallback((video) => video || this.next());\r\n public browserPrevious = this.bindBrowserCallback((video) => video ? this.seekToStart(video) : this.previous());\r\n\r\n public next = () => {\r\n return this.go(1);\r\n };\r\n\r\n public previous = () => {\r\n if(this.seekToStart(this.playingMedia)) {\r\n return;\r\n }\r\n\r\n return this.go(-1);\r\n };\r\n\r\n public seekToStart(media: HTMLMediaElement) {\r\n if(media?.currentTime > 5) {\r\n media.currentTime = 0;\r\n this.toggle(true, media);\r\n return true;\r\n }\r\n\r\n return false;\r\n }\r\n\r\n public willBePlayed(media: HTMLMediaElement) {\r\n this.willBePlayedMedia = media;\r\n }\r\n\r\n public setSearchContext(context: MediaSearchContext) {\r\n if(deepEqual(this.searchContext, context)) {\r\n return false;\r\n }\r\n\r\n this.searchContext = copy(context); // {_: type === 'audio' ? 'inputMessagesFilterMusic' : 'inputMessagesFilterRoundVoice'}\r\n return true;\r\n }\r\n\r\n public getSearchContext() {\r\n return this.searchContext;\r\n }\r\n\r\n public setTargets(current: MediaItem, prev?: MediaItem[], next?: MediaItem[]) {\r\n let listLoader = this.listLoader;\r\n if(!listLoader) {\r\n listLoader = this.listLoader = new SearchListLoader({\r\n loadCount: 10,\r\n loadWhenLeft: 5,\r\n processItem: (message: Message.message) => {\r\n this.addMedia(message, false);\r\n return {peerId: message.peerId, mid: message.mid};\r\n },\r\n onJump: (item, older) => {\r\n this.playItem(item);\r\n },\r\n onEmptied: () => {\r\n rootScope.dispatchEvent('media_stop');\r\n this.stop();\r\n }\r\n });\r\n } else {\r\n listLoader.reset();\r\n }\r\n\r\n const reverse = this.searchContext.folderId !== undefined ? false : true;\r\n if(prev) {\r\n listLoader.setTargets(prev, next, reverse);\r\n } else {\r\n listLoader.reverse = reverse;\r\n }\r\n\r\n listLoader.setSearchContext(this.searchContext);\r\n listLoader.current = current;\r\n\r\n listLoader.load(true);\r\n listLoader.load(false);\r\n }\r\n\r\n private getPlaybackMediaTypeFromMessage(message: Message.message) {\r\n const doc = appMessagesManager.getMediaFromMessage(message) as MyDocument;\r\n let mediaType: PlaybackMediaType = 'audio';\r\n if(doc?.type) {\r\n if(doc.type === 'voice' || doc.type === 'round') {\r\n mediaType = 'voice';\r\n } else if(doc.type === 'video') {\r\n mediaType = 'video';\r\n }\r\n }\r\n\r\n return mediaType;\r\n }\r\n\r\n public setMedia(media: HTMLMediaElement, message: Message.message) {\r\n const mediaType = this.getPlaybackMediaTypeFromMessage(message);\r\n\r\n this._playbackRate = this.playbackRates[mediaType];\r\n\r\n this.playingMedia = media;\r\n this.playingMediaType = mediaType;\r\n this.playingMedia.volume = this.volume;\r\n this.playingMedia.muted = this.muted;\r\n this.playingMedia.playbackRate = this.playbackRate;\r\n\r\n if(mediaType === 'audio') {\r\n this.playingMedia.loop = this.loop;\r\n }\r\n\r\n if('mediaSession' in navigator) {\r\n this.setNewMediadata(message);\r\n }\r\n }\r\n\r\n public setSingleMedia(media?: HTMLMediaElement, message?: Message.message) {\r\n const playingMedia = this.playingMedia;\r\n\r\n const wasPlaying = this.pause();\r\n\r\n let onPlay: () => void;\r\n if(media) {\r\n onPlay = () => {\r\n const pip = this.pip;\r\n if(pip) {\r\n pip.pause();\r\n }\r\n };\r\n \r\n if(!media.paused) {\r\n onPlay();\r\n }\r\n \r\n media.addEventListener('play', onPlay);\r\n }\r\n\r\n this.willBePlayed(undefined);\r\n if(media) this.setMedia(media, message);\r\n else this.playingMedia = undefined;\r\n this.toggleSwitchers(false);\r\n\r\n return (playPaused = wasPlaying) => {\r\n this.toggleSwitchers(true);\r\n\r\n if(playingMedia) {\r\n if(this.mediaDetails.get(playingMedia)) {\r\n this.setMedia(playingMedia, this.getMessageByMedia(playingMedia));\r\n } else {\r\n this.next() || this.previous();\r\n }\r\n }\r\n \r\n // If it's still not cleaned\r\n if(this.playingMedia === media) {\r\n this.playingMedia = undefined;\r\n this.playingMediaType = undefined;\r\n }\r\n\r\n if(media) {\r\n media.removeEventListener('play', onPlay);\r\n }\r\n\r\n // I don't remember what it was for\r\n // if(media && this.playingMedia === media) {\r\n // this.stop();\r\n // }\r\n\r\n if(playPaused) {\r\n this.play();\r\n }\r\n };\r\n }\r\n\r\n public toggleSwitchers(enabled: boolean) {\r\n this.lockedSwitchers = !enabled;\r\n }\r\n\r\n public setPictureInPicture(video: HTMLVideoElement) {\r\n this.pip = video;\r\n\r\n // let wasPlaying = this.pause();\r\n\r\n const listenerSetter = new ListenerSetter();\r\n listenerSetter.add(video)('leavepictureinpicture', () => {\r\n if(this.pip !== video) {\r\n return;\r\n }\r\n\r\n this.pip = undefined;\r\n // if(wasPlaying) {\r\n // this.play();\r\n // }\r\n\r\n listenerSetter.removeAll();\r\n }, {once: true});\r\n\r\n listenerSetter.add(video)('play', (e) => {\r\n if(this.playingMedia !== video) {\r\n this.pause();\r\n }\r\n // if(this.pause()) {\r\n // listenerSetter.add(video)('pause', () => {\r\n // this.play();\r\n // }, {once: true});\r\n // }\r\n });\r\n }\r\n}\r\n\r\nconst appMediaPlaybackController = new AppMediaPlaybackController();\r\nMOUNT_CLASS_TO.appMediaPlaybackController = appMediaPlaybackController;\r\nexport default appMediaPlaybackController;\r\n","// * Jolly Cobra's schedulers\n\nimport { AnyToVoidFunction } from \"../../types\";\nimport { fastRaf } from \"../schedulers\";\nimport throttleWith from \"./throttleWith\";\n\nexport default function throttleWithRaf<F extends AnyToVoidFunction>(fn: F) {\n return throttleWith(fastRaf, fn);\n}\n","// * Jolly Cobra's schedulers\n\nimport { AnyToVoidFunction } from \"../../types\";\n\nexport default function throttleWith<F extends AnyToVoidFunction>(schedulerFn: AnyToVoidFunction, fn: F) {\n let waiting = false;\n let args: Parameters<F>;\n\n return (..._args: Parameters<F>) => {\n args = _args;\n\n if (!waiting) {\n waiting = true;\n\n schedulerFn(() => {\n waiting = false;\n // @ts-ignore\n fn(...args);\n });\n }\n };\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { i18n, LangPackKey } from \"../lib/langPack\";\n\nexport default function formatBytes(bytes: number, decimals = 2) {\n if(bytes === 0) return i18n('FileSize.B', [0]);\n\n const k = 1024;\n const dm = decimals < 0 ? 0 : decimals;\n const sizes: LangPackKey[] = ['FileSize.B', 'FileSize.KB', 'FileSize.MB', 'FileSize.GB'];\n\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n\n return i18n(sizes[i], [parseFloat((bytes / Math.pow(k, i)).toFixed(dm))]);\n}\n","export default function toHHMMSS(str: string | number, leadZero = false) {\n const sec_num = parseInt(str + '', 10);\n const hours = Math.floor(sec_num / 3600);\n let minutes: any = Math.floor((sec_num - (hours * 3600)) / 60);\n let seconds: any = sec_num - (hours * 3600) - (minutes * 60);\n \n if(hours) leadZero = true;\n if(minutes < 10) minutes = leadZero ? \"0\" + minutes : minutes;\n if(seconds < 10) seconds = \"0\" + seconds;\n return (hours ? /* ('0' + hours).slice(-2) */hours + ':' : '') + minutes + ':' + seconds;\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nexport type GrabEvent = {x: number, y: number, isTouch?: boolean, event: TouchEvent | MouseEvent};\r\n\r\nexport default function attachGrabListeners(element: HTMLElement, \r\n onStart: (position: GrabEvent) => void, \r\n onMove: (position: GrabEvent) => void, \r\n onEnd?: (position: GrabEvent) => void) {\r\n // * Mouse\r\n const onMouseMove = (event: MouseEvent) => {\r\n onMove({x: event.pageX, y: event.pageY, event});\r\n };\r\n\r\n const onMouseUp = (event: MouseEvent) => {\r\n document.removeEventListener('mousemove', onMouseMove);\r\n element.addEventListener('mousedown', onMouseDown, {once: true});\r\n onEnd && onEnd({x: event.pageX, y: event.pageY, event});\r\n };\r\n\r\n const onMouseDown = (event: MouseEvent) => {\r\n if(event.button !== 0) {\r\n element.addEventListener('mousedown', onMouseDown, {once: true});\r\n return;\r\n }\r\n\r\n onStart({x: event.pageX, y: event.pageY, event});\r\n onMouseMove(event);\r\n\r\n document.addEventListener('mousemove', onMouseMove);\r\n document.addEventListener('mouseup', onMouseUp, {once: true});\r\n };\r\n\r\n element.addEventListener('mousedown', onMouseDown, {once: true});\r\n\r\n // * Touch\r\n const onTouchMove = (event: TouchEvent) => {\r\n event.preventDefault();\r\n onMove({x: event.touches[0].clientX, y: event.touches[0].clientY, isTouch: true, event});\r\n };\r\n\r\n const onTouchEnd = (event: TouchEvent) => {\r\n document.removeEventListener('touchmove', onTouchMove);\r\n element.addEventListener('touchstart', onTouchStart, {passive: false, once: true});\r\n onEnd && onEnd({x: event.touches[0].clientX, y: event.touches[0].clientY, isTouch: true, event});\r\n };\r\n\r\n const onTouchStart = (event: TouchEvent) => {\r\n onStart({x: event.touches[0].clientX, y: event.touches[0].clientY, isTouch: true, event});\r\n onTouchMove(event);\r\n\r\n document.addEventListener('touchmove', onTouchMove, {passive: false});\r\n document.addEventListener('touchend', onTouchEnd, {passive: false, once: true});\r\n };\r\n\r\n element.addEventListener('touchstart', onTouchStart, {passive: false, once: true});\r\n\r\n return () => {\r\n element.removeEventListener('mousedown', onMouseDown);\r\n document.removeEventListener('mousemove', onMouseMove);\r\n document.removeEventListener('mouseup', onMouseUp);\r\n\r\n element.removeEventListener('touchstart', onTouchStart);\r\n document.removeEventListener('touchmove', onTouchMove);\r\n document.removeEventListener('touchend', onTouchEnd);\r\n };\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport attachGrabListeners, { GrabEvent } from \"../helpers/dom/attachGrabListeners\";\r\nimport clamp from \"../helpers/number/clamp\";\r\nimport safeAssign from \"../helpers/object/safeAssign\";\r\n\r\nexport default class RangeSelector {\r\n public container: HTMLDivElement;\r\n protected filled: HTMLDivElement;\r\n protected seek: HTMLInputElement;\r\n\r\n public mousedown = false;\r\n protected rect: DOMRect;\r\n protected _removeListeners: () => void;\r\n\r\n private events: Partial<{\r\n //onMouseMove: ProgressLine['onMouseMove'],\r\n onMouseDown: RangeSelector['onMouseDown'],\r\n onMouseUp: RangeSelector['onMouseUp'],\r\n onScrub: (value: number) => void\r\n }> = {};\r\n\r\n protected decimals: number;\r\n\r\n protected step: number;\r\n protected min: number;\r\n protected max: number;\r\n protected withTransition = false;\r\n protected useTransform = false;\r\n protected vertical = false;\r\n\r\n constructor(\r\n options: {\r\n step: RangeSelector['step'],\r\n min: RangeSelector['min'],\r\n max: RangeSelector['max'],\r\n withTransition?: RangeSelector['withTransition'],\r\n useTransform?: RangeSelector['useTransform'],\r\n vertical?: RangeSelector['vertical']\r\n }, \r\n value = 0\r\n ) {\r\n safeAssign(this, options);\r\n\r\n this.container = document.createElement('div');\r\n this.container.classList.add('progress-line');\r\n\r\n // there is no sense in using transition with transform, because it is updating every frame\r\n if(this.useTransform) {\r\n this.container.classList.add('use-transform');\r\n } else if(this.withTransition) {\r\n this.container.classList.add('with-transition');\r\n }\r\n\r\n this.filled = document.createElement('div');\r\n this.filled.classList.add('progress-line__filled');\r\n\r\n const seek = this.seek = document.createElement('input');\r\n seek.classList.add('progress-line__seek');\r\n //seek.setAttribute('max', '0');\r\n seek.type = 'range';\r\n seek.step = '' + this.step;\r\n seek.min = '' + this.min;\r\n seek.max = '' + this.max;\r\n seek.value = '' + value;\r\n\r\n if(value) {\r\n this.setProgress(value);\r\n }\r\n\r\n const stepStr = '' + this.step;\r\n const index = stepStr.indexOf('.');\r\n this.decimals = index === -1 ? 0 : stepStr.length - index - 1;\r\n\r\n //this.setListeners();\r\n\r\n this.container.append(this.filled, seek);\r\n }\r\n\r\n get value() {\r\n return +this.seek.value;\r\n }\r\n\r\n public setHandlers(events: RangeSelector['events']) {\r\n this.events = events;\r\n }\r\n\r\n protected onMouseMove = (event: GrabEvent) => {\r\n this.scrub(event);\r\n };\r\n\r\n protected onMouseDown = (event: GrabEvent) => {\r\n this.rect = this.container.getBoundingClientRect();\r\n this.mousedown = true;\r\n this.scrub(event);\r\n this.container.classList.add('is-focused');\r\n this.events?.onMouseDown && this.events.onMouseDown(event);\r\n };\r\n\r\n protected onMouseUp = (event: GrabEvent) => {\r\n this.mousedown = false;\r\n this.container.classList.remove('is-focused');\r\n this.events?.onMouseUp && this.events.onMouseUp(event);\r\n };\r\n\r\n public setListeners() {\r\n this.seek.addEventListener('input', this.onInput);\r\n this._removeListeners = attachGrabListeners(this.container, this.onMouseDown, this.onMouseMove, this.onMouseUp);\r\n }\r\n\r\n public onInput = () => {\r\n const value = +this.seek.value;\r\n this.setFilled(value);\r\n this.events?.onScrub && this.events.onScrub(value);\r\n };\r\n\r\n public setProgress(value: number) {\r\n this.seek.value = '' + value;\r\n this.setFilled(+this.seek.value); // clamp\r\n }\r\n\r\n public addProgress(value: number) {\r\n this.seek.value = '' + (+this.seek.value + value);\r\n this.setFilled(+this.seek.value); // clamp\r\n }\r\n\r\n public setFilled(value: number) {\r\n let percents = (value - this.min) / (this.max - this.min);\r\n percents = clamp(percents, 0, 1);\r\n \r\n // using scaleX and width even with vertical because it will be rotated\r\n if(this.useTransform) {\r\n this.filled.style.transform = `scaleX(${percents})`;\r\n } else {\r\n this.filled.style.width = (percents * 100) + '%';\r\n }\r\n }\r\n\r\n protected scrub(event: GrabEvent) {\r\n const rectMax = this.vertical ? this.rect.height : this.rect.width;\r\n const offsetAxisValue = clamp(this.vertical ? -(event.y - this.rect.bottom) : event.x - this.rect.left, 0, rectMax);\r\n\r\n let value = this.min + (offsetAxisValue / rectMax * (this.max - this.min));\r\n\r\n if((value - this.min) < ((this.max - this.min) / 2)) {\r\n value -= this.step / 10;\r\n }\r\n \r\n value = +value.toFixed(this.decimals);\r\n value = clamp(value, this.min, this.max);\r\n\r\n //this.seek.value = '' + value;\r\n //this.onInput();\r\n\r\n this.setProgress(value);\r\n this.events?.onScrub && this.events.onScrub(value);\r\n\r\n return value;\r\n }\r\n\r\n public removeListeners() {\r\n if(this._removeListeners) {\r\n this._removeListeners();\r\n this._removeListeners = null;\r\n }\r\n\r\n this.seek.removeEventListener('input', this.onInput);\r\n \r\n this.events = {};\r\n }\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { GrabEvent } from \"../helpers/dom/attachGrabListeners\";\nimport appMediaPlaybackController from \"./appMediaPlaybackController\";\nimport RangeSelector from \"./rangeSelector\";\n\nexport default class MediaProgressLine extends RangeSelector {\n protected filledLoad: HTMLDivElement;\n\n protected progressRAF = 0;\n\n protected media: HTMLMediaElement;\n protected streamable: boolean;\n\n constructor(media?: HTMLAudioElement | HTMLVideoElement, streamable?: boolean, withTransition?: boolean, useTransform?: boolean) {\n super({\n step: 1000 / 60 / 1000, \n min: 0, \n max: 1, \n withTransition, \n useTransform\n }, 0);\n\n if(media) {\n this.setMedia(media, streamable);\n }\n }\n\n public setMedia(media: HTMLMediaElement, streamable = false) {\n if(this.media) {\n this.removeListeners();\n }\n\n if(streamable && !this.filledLoad) {\n this.filledLoad = document.createElement('div');\n this.filledLoad.classList.add('progress-line__filled', 'progress-line__loaded');\n this.container.prepend(this.filledLoad);\n //this.setLoadProgress();\n } else if(this.filledLoad) {\n this.filledLoad.classList.toggle('hide', !streamable);\n }\n\n this.media = media;\n this.streamable = streamable;\n if(!media.paused || media.currentTime > 0) {\n this.onPlay();\n }\n\n let wasPlaying = false;\n this.setSeekMax();\n this.setListeners();\n this.setHandlers({\n onMouseDown: () => {\n wasPlaying = !this.media.paused;\n wasPlaying && this.media.pause();\n },\n\n onMouseUp: (e) => {\n // cancelEvent(e.event);\n wasPlaying && this.media.play();\n }\n });\n }\n\n protected onLoadedData = () => {\n this.max = this.media.duration;\n this.seek.setAttribute('max', '' + this.max);\n };\n\n protected onEnded = () => {\n this.setProgress();\n };\n\n protected onPlay = () => {\n let r = () => {\n this.setProgress();\n\n this.progressRAF = this.media.paused ? 0 : window.requestAnimationFrame(r);\n };\n\n if(this.progressRAF) {\n window.cancelAnimationFrame(this.progressRAF);\n }\n\n if(this.streamable) {\n this.setLoadProgress();\n }\n\n this.progressRAF = window.requestAnimationFrame(r);\n };\n\n protected onTimeUpdate = () => {\n if(this.media.paused) {\n this.setProgress();\n\n if(this.streamable) {\n this.setLoadProgress();\n }\n }\n };\n\n protected onProgress = (e: Event) => {\n this.setLoadProgress();\n };\n\n protected scrub(e: GrabEvent) {\n const scrubTime = super.scrub(e);\n this.media.currentTime = scrubTime;\n return scrubTime;\n }\n\n protected setLoadProgress() {\n if(appMediaPlaybackController.isSafariBuffering(this.media)) return;\n const buf = this.media.buffered;\n const numRanges = buf.length;\n\n const currentTime = this.media.currentTime;\n let nearestStart = 0, end = 0;\n for(let i = 0; i < numRanges; ++i) {\n const start = buf.start(i);\n if(currentTime >= start && start >= nearestStart) {\n nearestStart = start;\n end = buf.end(i);\n }\n\n //console.log('onProgress range:', i, buf.start(i), buf.end(i), this.media);\n }\n\n //console.log('onProgress correct range:', nearestStart, end, this.media);\n\n const percents = this.media.duration ? end / this.media.duration : 0;\n this.filledLoad.style.width = (percents * 100) + '%';\n //this.filledLoad.style.transform = 'scaleX(' + percents + ')';\n }\n\n protected setSeekMax() {\n this.max = this.media.duration || 0;\n if(this.max > 0) {\n this.onLoadedData();\n } else {\n this.media.addEventListener('loadeddata', this.onLoadedData);\n }\n }\n\n public setProgress() {\n if(appMediaPlaybackController.isSafariBuffering(this.media)) return;\n const currentTime = this.media.currentTime;\n\n super.setProgress(currentTime);\n }\n\n public setListeners() {\n super.setListeners();\n this.media.addEventListener('ended', this.onEnded);\n this.media.addEventListener('play', this.onPlay);\n this.media.addEventListener('timeupdate', this.onTimeUpdate);\n this.streamable && this.media.addEventListener('progress', this.onProgress);\n }\n\n public removeListeners() {\n super.removeListeners();\n\n if(this.media) {\n this.media.removeEventListener('loadeddata', this.onLoadedData);\n this.media.removeEventListener('ended', this.onEnded);\n this.media.removeEventListener('play', this.onPlay);\n this.media.removeEventListener('timeupdate', this.onTimeUpdate);\n this.streamable && this.media.removeEventListener('progress', this.onProgress);\n }\n\n if(this.progressRAF) {\n window.cancelAnimationFrame(this.progressRAF);\n this.progressRAF = 0;\n }\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport appDocsManager, {MyDocument} from \"../lib/appManagers/appDocsManager\";\nimport { wrapPhoto } from \"./wrappers\";\nimport ProgressivePreloader from \"./preloader\";\nimport appMediaPlaybackController, { MediaItem, MediaSearchContext } from \"./appMediaPlaybackController\";\nimport { DocumentAttribute, Message } from \"../layer\";\nimport mediaSizes from \"../helpers/mediaSizes\";\nimport { IS_SAFARI } from \"../environment/userAgent\";\nimport appMessagesManager from \"../lib/appManagers/appMessagesManager\";\nimport rootScope from \"../lib/rootScope\";\nimport './middleEllipsis';\nimport cancelEvent from \"../helpers/dom/cancelEvent\";\nimport { attachClickEvent } from \"../helpers/dom/clickEvent\";\nimport LazyLoadQueue from \"./lazyLoadQueue\";\nimport deferredPromise, { CancellablePromise } from \"../helpers/cancellablePromise\";\nimport ListenerSetter, { Listener } from \"../helpers/listenerSetter\";\nimport noop from \"../helpers/noop\";\nimport findUpClassName from \"../helpers/dom/findUpClassName\";\nimport { joinElementsWith } from \"../lib/langPack\";\nimport { MiddleEllipsisElement } from \"./middleEllipsis\";\nimport htmlToSpan from \"../helpers/dom/htmlToSpan\";\nimport { formatFullSentTime } from \"../helpers/date\";\nimport throttleWithRaf from \"../helpers/schedulers/throttleWithRaf\";\nimport { NULL_PEER_ID } from \"../lib/mtproto/mtproto_config\";\nimport formatBytes from \"../helpers/formatBytes\";\nimport { animateSingle } from \"../helpers/animation\";\nimport clamp from \"../helpers/number/clamp\";\nimport toHHMMSS from \"../helpers/string/toHHMMSS\";\nimport MediaProgressLine from \"./mediaProgressLine\";\nimport RichTextProcessor from \"../lib/richtextprocessor\";\nimport setInnerHTML from \"../helpers/dom/setInnerHTML\";\n\nrootScope.addEventListener('messages_media_read', ({mids, peerId}) => {\n mids.forEach(mid => {\n const attr = `[data-mid=\"${mid}\"][data-peer-id=\"${peerId}\"]`;\n (Array.from(document.querySelectorAll(`audio-element.is-unread${attr}, .media-round.is-unread${attr}`)) as AudioElement[]).forEach(elem => {\n elem.classList.remove('is-unread');\n });\n });\n});\n\n// https://github.com/LonamiWebs/Telethon/blob/4393ec0b83d511b6a20d8a20334138730f084375/telethon/utils.py#L1285\nexport function decodeWaveform(waveform: Uint8Array | number[]) {\n if(!(waveform instanceof Uint8Array)) {\n waveform = new Uint8Array(waveform);\n }\n\n const bitCount = waveform.length * 8;\n const valueCount = bitCount / 5 | 0;\n if(!valueCount) {\n return new Uint8Array([]);\n }\n\n let result: Uint8Array;\n try {\n const dataView = new DataView(waveform.buffer);\n result = new Uint8Array(valueCount);\n for(let i = 0; i < valueCount; i++) {\n const byteIndex = i * 5 / 8 | 0;\n const bitShift = i * 5 % 8;\n const value = dataView.getUint16(byteIndex, true);\n result[i] = (value >> bitShift) & 0b00011111;\n }\n } catch(err) {\n result = new Uint8Array([]);\n }\n\n /* var byteIndex = (valueCount - 1) / 8 | 0;\n var bitShift = (valueCount - 1) % 8;\n if(byteIndex === waveform.length - 1) {\n var value = waveform[byteIndex];\n } else {\n var value = dataView.getUint16(byteIndex, true);\n }\n console.log('decoded waveform, setting last value:', value, byteIndex, bitShift);\n result[valueCount - 1] = (value >> bitShift) & 0b00011111; */\n return result;\n}\n\nfunction createWaveformBars(waveform: Uint8Array, duration: number) {\n const barWidth = 2;\n const barMargin = 2; //mediaSizes.isMobile ? 2 : 1;\n const barHeightMin = 4; //mediaSizes.isMobile ? 3 : 2;\n const barHeightMax = mediaSizes.isMobile ? 16 : 23;\n // const availW = 150; //mediaSizes.isMobile ? 152 : 190;\n\n const minW = mediaSizes.isMobile ? 152 : 190;\n const maxW = mediaSizes.isMobile ? 190 : 256;\n const availW = clamp(duration / 60 * maxW, minW, maxW); // mediaSizes.isMobile ? 152 : 224;\n\n const svg = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\");\n svg.classList.add('audio-waveform-bars');\n svg.setAttributeNS(null, 'width', '' + availW);\n svg.setAttributeNS(null, 'height', '' + barHeightMax);\n svg.setAttributeNS(null, 'viewBox', `0 0 ${availW} ${barHeightMax}`);\n\n //console.log('decoded waveform:', waveform);\n\n const normValue = Math.max(...waveform);\n const wfSize = waveform.length ? waveform.length : 100;\n const barCount = Math.min((availW / (barWidth + barMargin)) | 0, wfSize);\n\n let maxValue = 0;\n const maxDelta = barHeightMax - barHeightMin;\n\n let html = '';\n for(let i = 0, barX = 0, sumI = 0; i < wfSize; ++i) {\n const value = waveform[i] || 0;\n if((sumI + barCount) >= wfSize) { // draw bar\n sumI = sumI + barCount - wfSize;\n\t\t\tif(sumI < (barCount + 1) / 2) {\n\t\t\t\tif(maxValue < value) maxValue = value;\n }\n \n const bar_value = Math.max(((maxValue * maxDelta) + ((normValue + 1) / 2)) / (normValue + 1), barHeightMin);\n \n const h = `\n <rect x=\"${barX}\" y=\"${barHeightMax - bar_value}\" width=\"${barWidth}\" height=\"${bar_value}\" rx=\"1\" ry=\"1\"></rect>\n `;\n html += h;\n\n barX += barWidth + barMargin;\n\n if(sumI < (barCount + 1) / 2) {\n maxValue = 0;\n } else {\n maxValue = value;\n }\n } else {\n if(maxValue < value) maxValue = value;\n\n sumI += barCount;\n }\n }\n\n const container = document.createElement('div');\n container.classList.add('audio-waveform');\n container.append(svg);\n\n svg.insertAdjacentHTML('beforeend', html);\n return {svg, container, availW};\n}\n\nfunction wrapVoiceMessage(audioEl: AudioElement) {\n audioEl.classList.add('is-voice');\n\n const message = audioEl.message;\n const doc = appMessagesManager.getMediaFromMessage(message) as MyDocument;\n\n if(message.pFlags.out) {\n audioEl.classList.add('is-out');\n }\n\n let waveform = (doc.attributes.find(attribute => attribute._ === 'documentAttributeAudio') as DocumentAttribute.documentAttributeAudio).waveform || new Uint8Array([]);\n waveform = decodeWaveform(waveform.slice(0, 63));\n \n const {svg, container: svgContainer, availW} = createWaveformBars(waveform, doc.duration);\n \n const fakeSvgContainer = svgContainer.cloneNode(true) as HTMLElement;\n fakeSvgContainer.classList.add('audio-waveform-fake');\n svgContainer.classList.add('audio-waveform-background');\n\n const waveformContainer = document.createElement('div');\n waveformContainer.classList.add('audio-waveform-container');\n waveformContainer.append(svgContainer, fakeSvgContainer);\n\n const timeDiv = document.createElement('div');\n timeDiv.classList.add('audio-time');\n audioEl.append(waveformContainer, timeDiv);\n\n let progress = svg as any as HTMLElement;\n \n const onLoad = () => {\n let audio = audioEl.audio;\n\n const setAnimation = () => {\n animateSingle(() => {\n if(!audio) return false;\n onTimeUpdate();\n return !audio.paused;\n }, audioEl);\n };\n\n const onTimeUpdate = () => {\n fakeSvgContainer.style.width = (audio.currentTime / audio.duration * 100) + '%';\n };\n\n if(!audio.paused || (audio.currentTime > 0 && audio.currentTime !== audio.duration)) {\n onTimeUpdate();\n }\n\n const throttledTimeUpdate = throttleWithRaf(onTimeUpdate);\n audioEl.addAudioListener('timeupdate', throttledTimeUpdate);\n audioEl.addAudioListener('ended', throttledTimeUpdate);\n audioEl.addAudioListener('play', setAnimation);\n\n audioEl.readyPromise.then(() => {\n let mousedown = false, mousemove = false;\n progress.addEventListener('mouseleave', (e) => {\n if(mousedown) {\n audio.play();\n mousedown = false;\n }\n mousemove = false;\n })\n progress.addEventListener('mousemove', (e) => {\n mousemove = true;\n if(mousedown) scrub(e);\n });\n progress.addEventListener('mousedown', (e) => {\n e.preventDefault();\n if(e.button !== 0) return;\n if(!audio.paused) {\n audio.pause();\n }\n \n scrub(e);\n mousedown = true;\n });\n progress.addEventListener('mouseup', (e) => {\n if(mousemove && mousedown) {\n audio.play();\n mousedown = false;\n }\n });\n attachClickEvent(progress, (e) => {\n cancelEvent(e);\n if(!audio.paused) scrub(e);\n });\n \n function scrub(e: MouseEvent | TouchEvent) {\n let offsetX: number;\n if(e instanceof MouseEvent) {\n offsetX = e.offsetX;\n } else { // touch\n const rect = (e.target as HTMLElement).getBoundingClientRect();\n offsetX = e.targetTouches[0].pageX - rect.left;\n }\n \n const scrubTime = offsetX / availW /* width */ * audio.duration;\n audio.currentTime = scrubTime;\n }\n }, noop);\n \n return () => {\n progress.remove();\n progress = null;\n audio = null;\n };\n };\n\n return onLoad;\n}\n\nfunction wrapAudio(audioEl: AudioElement) {\n const withTime = audioEl.withTime;\n\n const message = audioEl.message;\n const doc: MyDocument = appMessagesManager.getMediaFromMessage(message);\n\n const isVoice = doc.type === 'voice' || doc.type === 'round';\n const descriptionEl = document.createElement('div');\n descriptionEl.classList.add('audio-description');\n\n const audioAttribute = doc.attributes.find((attr) => attr._ === 'documentAttributeAudio') as DocumentAttribute.documentAttributeAudio;\n \n if(!isVoice) {\n const parts: (Node | string)[] = [];\n if(audioAttribute?.performer) {\n parts.push(RichTextProcessor.wrapEmojiText(audioAttribute.performer));\n }\n\n if(withTime) {\n parts.push(formatFullSentTime(message.date));\n } else if(!parts.length) {\n parts.push(formatBytes(doc.size));\n }\n\n if(audioEl.showSender) {\n parts.push(appMessagesManager.wrapSenderToPeer(message));\n }\n\n descriptionEl.append(...joinElementsWith(parts, ' • '));\n }\n\n const html = `\n <div class=\"audio-details\">\n <div class=\"audio-title\"></div>\n <div class=\"audio-subtitle\"><div class=\"audio-time\"></div></div>\n </div>`;\n audioEl.insertAdjacentHTML('beforeend', html);\n\n const titleEl = audioEl.querySelector('.audio-title') as HTMLElement;\n\n const middleEllipsisEl = new MiddleEllipsisElement();\n middleEllipsisEl.dataset.fontWeight = audioEl.dataset.fontWeight;\n middleEllipsisEl.dataset.sizeType = audioEl.dataset.sizeType;\n if(isVoice) {\n middleEllipsisEl.append(appMessagesManager.wrapSenderToPeer(message));\n } else {\n setInnerHTML(middleEllipsisEl, RichTextProcessor.wrapEmojiText(audioAttribute?.title ?? doc.file_name));\n }\n\n titleEl.append(middleEllipsisEl);\n\n if(audioEl.showSender) {\n titleEl.append(appMessagesManager.wrapSentTime(message));\n }\n \n const subtitleDiv = audioEl.querySelector('.audio-subtitle') as HTMLDivElement;\n subtitleDiv.append(descriptionEl);\n\n const onLoad = () => {\n let launched = false;\n\n let progressLine = new MediaProgressLine(audioEl.audio, doc.supportsStreaming);\n\n audioEl.addAudioListener('ended', () => {\n audioEl.classList.remove('audio-show-progress');\n // Reset subtitle\n subtitleDiv.lastChild.replaceWith(descriptionEl);\n launched = false;\n });\n\n const onPlay = () => {\n if(!launched) {\n audioEl.classList.add('audio-show-progress');\n launched = true;\n\n if(progressLine) {\n subtitleDiv.lastChild.replaceWith(progressLine.container);\n }\n }\n };\n\n audioEl.addAudioListener('play', onPlay);\n\n if(!audioEl.audio.paused || audioEl.audio.currentTime > 0) {\n onPlay();\n }\n\n return () => {\n progressLine.removeListeners();\n progressLine.container.remove();\n progressLine = null;\n };\n };\n\n return onLoad;\n}\n\nfunction constructDownloadPreloader(tryAgainOnFail = true) {\n const preloader = new ProgressivePreloader({cancelable: true, tryAgainOnFail});\n preloader.construct();\n\n if(!tryAgainOnFail) {\n preloader.circle.setAttributeNS(null, 'r', '23');\n preloader.totalLength = 143.58203125;\n }\n\n return preloader;\n}\n\nexport const findMediaTargets = (anchor: HTMLElement, anchorMid: number/* , useSearch: boolean */) => {\n let prev: MediaItem[], next: MediaItem[];\n // if(anchor.classList.contains('search-super-item') || !useSearch) {\n const isBubbles = !anchor.classList.contains('search-super-item');\n const container = findUpClassName(anchor, !isBubbles ? 'tabs-tab' : 'bubbles-inner');\n if(container) {\n const attr = `:not([data-is-outgoing=\"1\"])`;\n const justAudioSelector = `.audio:not(.is-voice)${attr}`;\n let selectors: string[];\n if(!anchor.matches(justAudioSelector)) {\n selectors = [`.audio.is-voice${attr}`, `.media-round${attr}`];\n } else {\n selectors = [justAudioSelector];\n }\n\n if(isBubbles) {\n const prefix = '.bubble:not(.webpage) ';\n selectors = selectors.map(s => prefix + s);\n }\n\n const selector = selectors.join(', ');\n\n const elements = Array.from(container.querySelectorAll(selector)) as HTMLElement[];\n const idx = elements.indexOf(anchor);\n\n const mediaItems: MediaItem[] = elements.map(element => ({peerId: element.dataset.peerId.toPeerId(), mid: +element.dataset.mid}));\n\n prev = mediaItems.slice(0, idx);\n next = mediaItems.slice(idx + 1);\n }\n // }\n\n if((next.length && next[0].mid < anchorMid) || (prev.length && prev[prev.length - 1].mid > anchorMid)) {\n [prev, next] = [next.reverse(), prev.reverse()];\n }\n\n // prev = next = undefined;\n\n return [prev, next];\n};\n\nexport default class AudioElement extends HTMLElement {\n public audio: HTMLAudioElement;\n public preloader: ProgressivePreloader;\n public message: Message.message;\n public withTime = false;\n public voiceAsMusic = false;\n public searchContext: MediaSearchContext;\n public showSender = false;\n public noAutoDownload: boolean;\n public lazyLoadQueue: LazyLoadQueue;\n public loadPromises: Promise<any>[];\n\n private listenerSetter = new ListenerSetter();\n private onTypeDisconnect: () => void;\n public onLoad: (autoload?: boolean) => void;\n public readyPromise: CancellablePromise<void>;\n\n public render() {\n this.classList.add('audio');\n\n this.dataset.mid = '' + this.message.mid;\n this.dataset.peerId = '' + this.message.peerId;\n\n const doc: MyDocument = appMessagesManager.getMediaFromMessage(this.message);\n const isRealVoice = doc.type === 'voice';\n const isVoice = !this.voiceAsMusic && isRealVoice;\n const isOutgoing = this.message.pFlags.is_outgoing;\n const uploading = isOutgoing && this.preloader;\n\n const durationStr = toHHMMSS(doc.duration | 0);\n\n this.innerHTML = `\n <div class=\"audio-toggle audio-ico\">\n <div class=\"audio-play-icon\">\n <div class=\"part one\" x=\"0\" y=\"0\" fill=\"#fff\"></div>\n <div class=\"part two\" x=\"0\" y=\"0\" fill=\"#fff\"></div>\n </div>\n </div>`;\n\n const toggle = this.firstElementChild as HTMLElement;\n\n const downloadDiv = document.createElement('div');\n downloadDiv.classList.add('audio-download');\n\n const isUnread = doc.type !== 'audio' && this.message && this.message.pFlags.media_unread;\n if(isUnread) {\n this.classList.add('is-unread');\n }\n\n if(uploading) {\n this.classList.add('is-outgoing');\n this.append(downloadDiv);\n }\n\n const onTypeLoad = isVoice ? wrapVoiceMessage(this) : wrapAudio(this);\n \n const audioTimeDiv = this.querySelector('.audio-time') as HTMLDivElement;\n audioTimeDiv.innerHTML = durationStr;\n\n const onLoad = this.onLoad = (autoload: boolean) => {\n this.onLoad = undefined;\n\n const audio = this.audio = appMediaPlaybackController.addMedia(this.message, autoload);\n\n const readyPromise = this.readyPromise = deferredPromise<void>();\n if(this.audio.readyState >= this.audio.HAVE_CURRENT_DATA) readyPromise.resolve();\n else {\n this.addAudioListener('canplay', () => readyPromise.resolve(), {once: true});\n }\n\n this.onTypeDisconnect = onTypeLoad();\n \n const getTimeStr = () => toHHMMSS(audio.currentTime | 0) + (isVoice ? (' / ' + durationStr) : '');\n\n const onPlay = () => {\n audioTimeDiv.innerText = getTimeStr();\n toggle.classList.toggle('playing', !audio.paused);\n };\n\n if(!audio.paused || (audio.currentTime > 0 && audio.currentTime !== audio.duration)) {\n onPlay();\n }\n\n const togglePlay = (e?: Event, paused = audio.paused) => {\n e && cancelEvent(e);\n\n if(paused) {\n const hadSearchContext = !!this.searchContext;\n if(appMediaPlaybackController.setSearchContext(this.searchContext || {\n peerId: NULL_PEER_ID, \n inputFilter: {_: 'inputMessagesFilterEmpty'}, \n useSearch: false\n })) {\n const [prev, next] = !hadSearchContext ? [] : findMediaTargets(this, this.message.mid/* , this.searchContext.useSearch */);\n appMediaPlaybackController.setTargets({peerId: this.message.peerId, mid: this.message.mid}, prev, next);\n }\n\n audio.play().catch(() => {});\n } else {\n audio.pause();\n }\n };\n\n attachClickEvent(toggle, (e) => togglePlay(e), {listenerSetter: this.listenerSetter});\n\n this.addAudioListener('ended', () => {\n toggle.classList.remove('playing');\n audioTimeDiv.innerText = durationStr;\n });\n\n this.addAudioListener('timeupdate', () => {\n if((!audio.currentTime && audio.paused) || appMediaPlaybackController.isSafariBuffering(audio)) return;\n audioTimeDiv.innerText = getTimeStr();\n });\n\n this.addAudioListener('pause', () => {\n toggle.classList.remove('playing');\n });\n\n this.addAudioListener('play', onPlay);\n\n return togglePlay;\n };\n\n if(doc.thumbs?.length) {\n const imgs: HTMLElement[] = [];\n const wrapped = wrapPhoto({\n photo: doc, \n message: null, \n container: toggle, \n boxWidth: 48, \n boxHeight: 48,\n loadPromises: this.loadPromises,\n withoutPreloader: true,\n lazyLoadQueue: this.lazyLoadQueue\n });\n toggle.style.width = toggle.style.height = '';\n if(wrapped.images.thumb) imgs.push(wrapped.images.thumb);\n if(wrapped.images.full) imgs.push(wrapped.images.full);\n\n this.classList.add('audio-with-thumb');\n imgs.forEach(img => img.classList.add('audio-thumb'));\n }\n\n if(!isOutgoing) {\n let preloader: ProgressivePreloader = this.preloader;\n\n const autoDownload = doc.type !== 'audio'/* || !this.noAutoDownload */;\n onLoad(autoDownload);\n\n const r = (shouldPlay: boolean) => {\n if(this.audio.src) {\n return;\n }\n\n appMediaPlaybackController.resolveWaitingForLoadMedia(this.message.peerId, this.message.mid, this.message.pFlags.is_scheduled);\n\n const onDownloadInit = () => {\n if(shouldPlay) {\n appMediaPlaybackController.willBePlayed(this.audio); // prepare for loading audio\n \n if(IS_SAFARI && !this.audio.autoplay) {\n this.audio.autoplay = true;\n }\n }\n };\n\n onDownloadInit();\n\n if(!preloader) {\n if(doc.supportsStreaming) {\n this.classList.add('corner-download');\n\n let pauseListener: Listener;\n const onPlay = () => {\n const preloader = constructDownloadPreloader(false);\n const deferred = deferredPromise<void>();\n deferred.notifyAll({done: 75, total: 100});\n deferred.catch(() => {\n this.audio.pause();\n appMediaPlaybackController.willBePlayed(undefined);\n });\n deferred.cancel = () => {\n deferred.cancel = noop;\n const err = new Error();\n (err as any).type = 'CANCELED';\n deferred.reject(err);\n };\n preloader.attach(downloadDiv, false, deferred);\n\n pauseListener = this.addAudioListener('pause', () => {\n deferred.cancel();\n }, {once: true}) as any;\n\n onDownloadInit();\n };\n\n /* if(!this.audio.paused) {\n onPlay();\n } */\n\n const playListener: any = this.addAudioListener('play', onPlay);\n this.readyPromise.then(() => {\n this.listenerSetter.remove(playListener);\n this.listenerSetter.remove(pauseListener);\n });\n } else {\n preloader = constructDownloadPreloader();\n\n if(!shouldPlay) {\n this.readyPromise = deferredPromise();\n }\n\n const load = () => {\n onDownloadInit();\n\n const download = appDocsManager.downloadDoc(doc);\n \n if(!shouldPlay) {\n download.then(() => {\n this.readyPromise.resolve();\n });\n }\n\n preloader.attach(downloadDiv, false, download);\n return {download};\n };\n\n preloader.setDownloadFunction(load);\n load();\n }\n }\n\n if(this.classList.contains('corner-download')) {\n toggle.append(downloadDiv);\n } else {\n this.append(downloadDiv);\n }\n\n this.classList.add('downloading');\n\n this.readyPromise.then(() => {\n this.classList.remove('downloading');\n downloadDiv.classList.add('downloaded');\n setTimeout(() => {\n downloadDiv.remove();\n }, 200);\n \n //setTimeout(() => {\n // release loaded audio\n if(appMediaPlaybackController.willBePlayedMedia === this.audio) {\n this.audio.play();\n appMediaPlaybackController.willBePlayed(undefined);\n }\n //}, 10e3);\n });\n };\n\n if(!this.audio?.src) {\n if(autoDownload) {\n r(false);\n } else {\n attachClickEvent(toggle, () => {\n r(true);\n }, {once: true, capture: true, passive: false, listenerSetter: this.listenerSetter});\n }\n }\n } else if(uploading) {\n this.dataset.isOutgoing = '1';\n this.preloader.attach(downloadDiv, false);\n //onLoad();\n }\n }\n\n get addAudioListener() {\n return this.listenerSetter.add(this.audio);\n }\n\n disconnectedCallback() {\n if(this.isConnected) {\n return;\n }\n \n if(this.onTypeDisconnect) {\n this.onTypeDisconnect();\n this.onTypeDisconnect = null;\n }\n\n if(this.readyPromise) {\n this.readyPromise.reject();\n }\n\n this.listenerSetter.removeAll();\n this.listenerSetter = null;\n\n this.preloader = null;\n }\n}\n\ncustomElements.define(\"audio-element\", AudioElement);\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nexport default class DivAndCaption<T> {\r\n public container: HTMLElement;\r\n public border: HTMLElement;\r\n public content: HTMLElement;\r\n public title: HTMLElement;\r\n public subtitle: HTMLElement;\r\n\r\n constructor(protected className: string, public fill?: T) {\r\n this.container = document.createElement('div');\r\n this.container.className = className;\r\n\r\n this.border = document.createElement('div');\r\n this.border.classList.add(className + '-border');\r\n \r\n this.content = document.createElement('div');\r\n this.content.classList.add(className + '-content');\r\n\r\n this.title = document.createElement('div');\r\n this.title.classList.add(className + '-title');\r\n this.title.setAttribute('dir', 'auto');\r\n\r\n this.subtitle = document.createElement('div');\r\n this.subtitle.classList.add(className + '-subtitle');\r\n this.subtitle.setAttribute('dir', 'auto');\r\n\r\n this.content.append(this.title, this.subtitle);\r\n this.container.append(this.border, this.content);\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport replaceContent from \"../../helpers/dom/replaceContent\";\r\nimport limitSymbols from \"../../helpers/string/limitSymbols\";\r\nimport appImManager, { CHAT_ANIMATION_GROUP } from \"../../lib/appManagers/appImManager\";\r\nimport appMessagesManager from \"../../lib/appManagers/appMessagesManager\";\r\nimport appPhotosManager from \"../../lib/appManagers/appPhotosManager\";\r\nimport { RichTextProcessor } from \"../../lib/richtextprocessor\";\r\nimport DivAndCaption from \"../divAndCaption\";\r\nimport { wrapPhoto, wrapSticker } from \"../wrappers\";\r\n\r\nconst MEDIA_SIZE = 32;\r\n\r\nexport function wrapReplyDivAndCaption(options: {\r\n title: string | HTMLElement | DocumentFragment,\r\n titleEl: HTMLElement,\r\n subtitle: string | HTMLElement | DocumentFragment,\r\n subtitleEl: HTMLElement,\r\n message: any,\r\n mediaEl: HTMLElement,\r\n loadPromises?: Promise<any>[]\r\n}) {\r\n let {title, titleEl, subtitle, subtitleEl, mediaEl, message, loadPromises} = options;\r\n if(title !== undefined) {\r\n if(typeof(title) === 'string') {\r\n title = limitSymbols(title, 140);\r\n title = RichTextProcessor.wrapEmojiText(title);\r\n }\r\n\r\n replaceContent(titleEl, title);\r\n }\r\n\r\n if(!loadPromises) {\r\n loadPromises = [];\r\n }\r\n\r\n let media = message && message.media;\r\n let setMedia = false, isRound = false;\r\n const mediaChildren = mediaEl ? Array.from(mediaEl.children).slice() : [];\r\n let middleware: () => boolean;\r\n if(media && mediaEl) {\r\n subtitleEl.textContent = '';\r\n subtitleEl.append(appMessagesManager.wrapMessageForReply(message, undefined, undefined, undefined, undefined, true));\r\n\r\n //console.log('wrap reply', media);\r\n\r\n if(media.webpage) {\r\n media = media.webpage;\r\n }\r\n \r\n if(media.photo || (media.document && media.document.thumbs?.length)/* ['video', 'sticker', 'gif', 'round', 'photo', 'audio'].indexOf(media.document.type) !== -1) */) {\r\n middleware = appImManager.chat.bubbles.getMiddleware();\r\n const lazyLoadQueue = appImManager.chat.bubbles.lazyLoadQueue;\r\n\r\n if(media.document?.type === 'sticker') {\r\n setMedia = true;\r\n wrapSticker({\r\n doc: media.document,\r\n div: mediaEl,\r\n lazyLoadQueue,\r\n group: CHAT_ANIMATION_GROUP,\r\n //onlyThumb: media.document.sticker === 2,\r\n width: MEDIA_SIZE,\r\n height: MEDIA_SIZE,\r\n middleware,\r\n loadPromises\r\n });\r\n } else {\r\n const photo = media.photo || media.document;\r\n\r\n isRound = photo.type === 'round';\r\n\r\n try {\r\n wrapPhoto({\r\n photo,\r\n container: mediaEl,\r\n boxWidth: MEDIA_SIZE,\r\n boxHeight: MEDIA_SIZE,\r\n size: appPhotosManager.choosePhotoSize(photo, MEDIA_SIZE, MEDIA_SIZE),\r\n middleware,\r\n lazyLoadQueue,\r\n noBlur: true,\r\n withoutPreloader: true,\r\n loadPromises\r\n });\r\n setMedia = true;\r\n } catch(err) {\r\n\r\n }\r\n }\r\n }\r\n } else {\r\n if(message) {\r\n subtitleEl.textContent = '';\r\n subtitleEl.append(appMessagesManager.wrapMessageForReply(message));\r\n } else {\r\n if(typeof(subtitle) === 'string') {\r\n subtitle = limitSymbols(subtitle, 140);\r\n subtitle = RichTextProcessor.wrapEmojiText(subtitle);\r\n }\r\n\r\n replaceContent(subtitleEl, subtitle || '');\r\n }\r\n }\r\n\r\n Promise.all(loadPromises).then(() => {\r\n if(middleware && !middleware()) return;\r\n mediaChildren.forEach(child => child.remove());\r\n\r\n if(mediaEl) {\r\n mediaEl.classList.toggle('is-round', isRound);\r\n }\r\n });\r\n\r\n return setMedia;\r\n}\r\n\r\nexport default class ReplyContainer extends DivAndCaption<(title: string | HTMLElement | DocumentFragment, subtitle: string | HTMLElement | DocumentFragment, message?: any) => void> {\r\n private mediaEl: HTMLElement;\r\n\r\n constructor(protected className: string) {\r\n super(className, (title, subtitle = '', message?) => {\r\n if(!this.mediaEl) {\r\n this.mediaEl = document.createElement('div');\r\n this.mediaEl.classList.add(this.className + '-media');\r\n }\r\n\r\n const isMediaSet = wrapReplyDivAndCaption({\r\n title,\r\n titleEl: this.title,\r\n subtitle,\r\n subtitleEl: this.subtitle,\r\n mediaEl: this.mediaEl,\r\n message\r\n });\r\n \r\n this.container.classList.toggle('is-media', isMediaSet);\r\n if(isMediaSet) {\r\n this.content.prepend(this.mediaEl);\r\n } else {\r\n this.mediaEl.remove();\r\n }\r\n });\r\n }\r\n}\r\n","export default function accumulate(arr: number[], initialValue: number) {\n return arr.reduce((acc, value) => acc + value, initialValue);\n}\n","/*\r\nThis file is part of Telegram Desktop,\r\nthe official desktop application for the Telegram messaging service.\r\nFor license and copyright information please follow this link:\r\nhttps://github.com/telegramdesktop/tdesktop/blob/master/LEGAL\r\n*/\r\n\r\nimport accumulate from \"../helpers/array/accumulate\";\r\nimport clamp from \"../helpers/number/clamp\";\r\n\r\ntype Size = {w: number, h: number};\r\nexport type GroupMediaLayout = {\r\n geometry: {\r\n x: number,\r\n y: number,\r\n width: number,\r\n height: number\r\n },\r\n sides: number\r\n};\r\ntype Attempt = {\r\n lineCounts: number[],\r\n heights: number[]\r\n};\r\nexport const RectPart = {\r\n None: 0,\r\n Top: 1,\r\n Right: 2,\r\n Bottom: 4,\r\n Left: 8\r\n};\r\n\r\n// https://github.com/telegramdesktop/tdesktop/blob/4669c07dc5335cbf4795bbbe5b0ab7c007b9aee2/Telegram/SourceFiles/ui/grouped_layout.cpp\r\nexport class Layouter {\r\n private count: number;\r\n private ratios: number[];\r\n private proportions: string;\r\n private averageRatio: number;\r\n private maxSizeRatio: number;\r\n\r\n constructor(private sizes: Size[], private maxWidth: number, private minWidth: number, private spacing: number, private maxHeight = maxWidth) {\r\n this.count = sizes.length;\r\n this.ratios = Layouter.countRatios(sizes);\r\n this.proportions = Layouter.countProportions(this.ratios);\r\n this.averageRatio = accumulate(this.ratios, 1) / this.count; // warn\r\n this.maxSizeRatio = maxWidth / this.maxHeight;\r\n }\r\n\r\n public layout(): GroupMediaLayout[] {\r\n if(!this.count) return [];\r\n //else if(this.count === 1) return this.layoutOne();\r\n\r\n if(this.count >= 5 || this.ratios.find(r => r > 2)) {\r\n return new ComplexLayouter(this.ratios, this.averageRatio, this.maxWidth, this.minWidth, this.spacing).layout();\r\n }\r\n\r\n if(this.count === 2) return this.layoutTwo();\r\n else if(this.count === 3) return this.layoutThree();\r\n return this.layoutFour();\r\n }\r\n\r\n private layoutTwo(): ReturnType<Layouter['layout']> {\r\n if((this.proportions === \"ww\")\r\n && (this.averageRatio > 1.4 * this.maxSizeRatio)\r\n && (this.ratios[1] - this.ratios[0] < 0.2)) {\r\n return this.layoutTwoTopBottom();\r\n } else if(this.proportions === \"ww\" || this.proportions === \"qq\") {\r\n return this.layoutTwoLeftRightEqual();\r\n }\r\n return this.layoutTwoLeftRight();\r\n }\r\n\r\n private layoutThree(): ReturnType<Layouter['layout']> {\r\n //console.log('layoutThree:', this);\r\n if(this.proportions[0] === 'n') {\r\n return this.layoutThreeLeftAndOther();\r\n }\r\n return this.layoutThreeTopAndOther();\r\n }\r\n\r\n private layoutFour(): ReturnType<Layouter['layout']> {\r\n if(this.proportions[0] === 'w') {\r\n return this.layoutFourTopAndOther();\r\n }\r\n return this.layoutFourLeftAndOther();\r\n }\r\n\r\n private layoutTwoTopBottom(): ReturnType<Layouter['layout']> {\r\n const width = this.maxWidth;\r\n const height = Math.round(Math.min(\r\n width / this.ratios[0],\r\n Math.min(\r\n width / this.ratios[1],\r\n (this.maxHeight - this.spacing) / 2)));\r\n \r\n return [\r\n {\r\n geometry: {x: 0, y: 0, width, height},\r\n sides: RectPart.Left | RectPart.Top | RectPart.Right\r\n },\r\n {\r\n geometry: {x: 0, y: height + this.spacing, width, height},\r\n sides: RectPart.Left | RectPart.Bottom | RectPart.Right\r\n },\r\n ];\r\n }\r\n\r\n private layoutTwoLeftRightEqual(): ReturnType<Layouter['layout']> {\r\n const width = (this.maxWidth - this.spacing) / 2;\r\n const height = Math.round(Math.min(\r\n width / this.ratios[0],\r\n Math.min(width / this.ratios[1], this.maxHeight * 1)));\r\n \r\n return [\r\n {\r\n geometry: {x: 0, y: 0, width, height},\r\n sides: RectPart.Top | RectPart.Left | RectPart.Bottom\r\n },\r\n {\r\n geometry: {x: width + this.spacing, y: 0, width, height},\r\n sides: RectPart.Top | RectPart.Right | RectPart.Bottom\r\n },\r\n ];\r\n }\r\n\r\n private layoutTwoLeftRight(): ReturnType<Layouter['layout']> {\r\n const minimalWidth = Math.round(this.minWidth * 1.5);\r\n const secondWidth = Math.min(\r\n Math.round(Math.max(\r\n 0.4 * (this.maxWidth - this.spacing),\r\n (this.maxWidth - this.spacing) / this.ratios[0]\r\n / (1 / this.ratios[0] + 1 / this.ratios[1]))),\r\n this.maxWidth - this.spacing - minimalWidth);\r\n const firstWidth = this.maxWidth\r\n - secondWidth\r\n - this.spacing;\r\n const height = Math.min(\r\n this.maxHeight,\r\n Math.round(Math.min(\r\n firstWidth / this.ratios[0],\r\n secondWidth / this.ratios[1])));\r\n \r\n return [\r\n {\r\n geometry: {x: 0, y: 0, width: firstWidth, height},\r\n sides: RectPart.Top | RectPart.Left | RectPart.Bottom\r\n },\r\n {\r\n geometry: {x: firstWidth + this.spacing, y: 0, width: secondWidth, height},\r\n sides: RectPart.Top | RectPart.Right | RectPart.Bottom\r\n },\r\n ];\r\n }\r\n\r\n private layoutThreeLeftAndOther(): ReturnType<Layouter['layout']> {\r\n const firstHeight = this.maxHeight;\r\n const thirdHeight = Math.round(Math.min(\r\n (this.maxHeight - this.spacing) / 2.,\r\n (this.ratios[1] * (this.maxWidth - this.spacing)\r\n / (this.ratios[2] + this.ratios[1]))));\r\n const secondHeight = firstHeight\r\n - thirdHeight\r\n - this.spacing;\r\n const rightWidth = Math.max(\r\n this.minWidth,\r\n Math.round(Math.min(\r\n (this.maxWidth - this.spacing) / 2.,\r\n Math.min(\r\n thirdHeight * this.ratios[2],\r\n secondHeight * this.ratios[1]))));\r\n const leftWidth = Math.min(\r\n Math.round(firstHeight * this.ratios[0]),\r\n this.maxWidth - this.spacing - rightWidth);\r\n\r\n return [\r\n {\r\n geometry: {x: 0, y: 0, width: leftWidth, height: firstHeight},\r\n sides: RectPart.Top | RectPart.Left | RectPart.Bottom\r\n },\r\n {\r\n geometry: {x: leftWidth + this.spacing, y: 0, width: rightWidth, height: secondHeight},\r\n sides: RectPart.Top | RectPart.Right\r\n },\r\n {\r\n geometry: {x: leftWidth + this.spacing, y: secondHeight + this.spacing, width: rightWidth, height: thirdHeight},\r\n sides: RectPart.Bottom | RectPart.Right\r\n },\r\n ];\r\n }\r\n \r\n private layoutThreeTopAndOther(): ReturnType<Layouter['layout']> {\r\n const firstWidth = this.maxWidth;\r\n const firstHeight = Math.round(Math.min(\r\n firstWidth / this.ratios[0],\r\n (this.maxHeight - this.spacing) * 0.66));\r\n const secondWidth = (this.maxWidth - this.spacing) / 2;\r\n const secondHeight = Math.min(\r\n this.maxHeight - firstHeight - this.spacing,\r\n Math.round(Math.min(\r\n secondWidth / this.ratios[1],\r\n secondWidth / this.ratios[2])));\r\n const thirdWidth = firstWidth - secondWidth - this.spacing;\r\n \r\n return [\r\n {\r\n geometry: {x: 0, y: 0, width: firstWidth, height: firstHeight},\r\n sides: RectPart.Left | RectPart.Top | RectPart.Right\r\n },\r\n {\r\n geometry: {x: 0, y: firstHeight + this.spacing, width: secondWidth, height: secondHeight},\r\n sides: RectPart.Bottom | RectPart.Left\r\n },\r\n {\r\n geometry: {x: secondWidth + this.spacing, y: firstHeight + this.spacing, width: thirdWidth, height: secondHeight},\r\n sides: RectPart.Bottom | RectPart.Right\r\n },\r\n ];\r\n }\r\n\r\n private layoutFourTopAndOther(): ReturnType<Layouter['layout']> {\r\n const w = this.maxWidth;\r\n const h0 = Math.round(Math.min(\r\n w / this.ratios[0],\r\n (this.maxHeight - this.spacing) * 0.66));\r\n const h = Math.round(\r\n (this.maxWidth - 2 * this.spacing)\r\n / (this.ratios[1] + this.ratios[2] + this.ratios[3]));\r\n const w0 = Math.max(\r\n this.minWidth,\r\n Math.round(Math.min(\r\n (this.maxWidth - 2 * this.spacing) * 0.4,\r\n h * this.ratios[1])));\r\n const w2 = Math.round(Math.max(\r\n Math.max(\r\n this.minWidth * 1.,\r\n (this.maxWidth - 2 * this.spacing) * 0.33),\r\n h * this.ratios[3]));\r\n const w1 = w - w0 - w2 - 2 * this.spacing;\r\n const h1 = Math.min(\r\n this.maxHeight - h0 - this.spacing,\r\n h);\r\n \r\n return [\r\n {\r\n geometry: {x: 0, y: 0, width: w, height: h0},\r\n sides: RectPart.Left | RectPart.Top | RectPart.Right\r\n },\r\n {\r\n geometry: {x: 0, y: h0 + this.spacing, width: w0, height: h1},\r\n sides: RectPart.Bottom | RectPart.Left\r\n },\r\n {\r\n geometry: {x: w0 + this.spacing, y: h0 + this.spacing, width: w1, height: h1},\r\n sides: RectPart.Bottom,\r\n },\r\n {\r\n geometry: {x: w0 + this.spacing + w1 + this.spacing, y: h0 + this.spacing, width: w2, height: h1},\r\n sides: RectPart.Right | RectPart.Bottom\r\n },\r\n ];\r\n }\r\n\r\n private layoutFourLeftAndOther(): ReturnType<Layouter['layout']> {\r\n const h = this.maxHeight;\r\n const w0 = Math.round(Math.min(\r\n h * this.ratios[0],\r\n (this.maxWidth - this.spacing) * 0.6));\r\n \r\n const w = Math.round(\r\n (this.maxHeight - 2 * this.spacing)\r\n / (1. / this.ratios[1] + 1. / this.ratios[2] + 1. / this.ratios[3])\r\n );\r\n const h0 = Math.round(w / this.ratios[1]);\r\n const h1 = Math.round(w / this.ratios[2]);\r\n const h2 = h - h0 - h1 - 2 * this.spacing;\r\n const w1 = Math.max(\r\n this.minWidth,\r\n Math.min(this.maxWidth - w0 - this.spacing, w));\r\n \r\n return [\r\n {\r\n geometry: {x: 0, y: 0, width: w0, height: h},\r\n sides: RectPart.Top | RectPart.Left | RectPart.Bottom\r\n },\r\n {\r\n geometry: {x: w0 + this.spacing, y: 0, width: w1, height: h0},\r\n sides: RectPart.Top | RectPart.Right\r\n },\r\n {\r\n geometry: {x: w0 + this.spacing, y: h0 + this.spacing, width: w1, height: h1},\r\n sides: RectPart.Right\r\n },\r\n {\r\n geometry: {x: w0 + this.spacing, y: h0 + h1 + 2 * this.spacing, width: w1, height: h2},\r\n sides: RectPart.Bottom | RectPart.Right\r\n },\r\n ];\r\n }\r\n\r\n private static countRatios(sizes: Size[]) {\r\n return sizes.map(size => size.w / size.h);\r\n }\r\n\r\n private static countProportions(ratios: number[]) {\r\n return ratios.map(ratio => (ratio > 1.2) ? 'w' : (ratio < 0.8) ? 'n' : 'q').join('');\r\n }\r\n}\r\n\r\nclass ComplexLayouter {\r\n private ratios: number[];\r\n private count: number;\r\n\r\n constructor(ratios: number[], private averageRatio: number, private maxWidth: number, private minWidth: number, private spacing: number, private maxHeight = maxWidth * 4 / 3) {\r\n this.ratios = ComplexLayouter.cropRatios(ratios, averageRatio);\r\n this.count = ratios.length;\r\n }\r\n\r\n private static cropRatios(ratios: number[], averageRatio: number) {\r\n const kMaxRatio = 2.75;\r\n const kMinRatio = 0.6667;\r\n return ratios.map(ratio => {\r\n return averageRatio > 1.1\r\n\t\t\t ? clamp(ratio, 1., kMaxRatio)\r\n\t\t\t : clamp(ratio, kMinRatio, 1.);\r\n });\r\n }\r\n\r\n public layout(): GroupMediaLayout[] {\r\n let result = new Array<GroupMediaLayout>(this.count);\r\n\r\n let attempts: Attempt[] = [];\r\n const multiHeight = (offset: number, count: number) => {\r\n const ratios = this.ratios.slice(offset, offset + count); // warn\r\n const sum = accumulate(ratios, 0);\r\n return (this.maxWidth - (count - 1) * this.spacing) / sum;\r\n };\r\n const pushAttempt = (lineCounts: number[]) => {\r\n let heights: number[] = [];\r\n let offset = 0;\r\n for(let count of lineCounts) {\r\n heights.push(multiHeight(offset, count));\r\n offset += count;\r\n }\r\n attempts.push({lineCounts, heights}); // warn\r\n };\r\n\r\n for(let first = 1; first !== this.count; ++first) {\r\n const second = this.count - first;\r\n if(first > 3 || second > 3) {\r\n continue;\r\n }\r\n pushAttempt([first, second]);\r\n }\r\n for(let first = 1; first !== this.count - 1; ++first) {\r\n for(let second = 1; second !== this.count - first; ++second) {\r\n const third = this.count - first - second;\r\n if((first > 3)\r\n || (second > ((this.averageRatio < 0.85) ? 4 : 3))\r\n || (third > 3)) {\r\n continue;\r\n }\r\n pushAttempt([first, second, third]);\r\n }\r\n }\r\n for(let first = 1; first !== this.count - 1; ++first) {\r\n for(let second = 1; second !== this.count - first; ++second) {\r\n for(let third = 1; third !== this.count - first - second; ++third) {\r\n const fourth = this.count - first - second - third;\r\n if(first > 3 || second > 3 || third > 3 || fourth > 3) {\r\n continue;\r\n }\r\n pushAttempt([first, second, third, fourth]);\r\n }\r\n }\r\n }\r\n\r\n let optimalAttempt: Attempt = null;\r\n let optimalDiff = 0;\r\n for(const attempt of attempts) {\r\n const {heights, lineCounts: counts} = attempt;\r\n const lineCount = counts.length;\r\n const totalHeight = accumulate(heights, 0) \r\n + this.spacing * (lineCount - 1);\r\n const minLineHeight = Math.min(...heights);\r\n const maxLineHeight = Math.max(...heights);\r\n const bad1 = (minLineHeight < this.minWidth) ? 1.5 : 1;\r\n const bad2 = (() => {\r\n for(let line = 1; line !== lineCount; ++line) {\r\n if(counts[line - 1] > counts[line]) {\r\n return 1.5;\r\n }\r\n }\r\n return 1.;\r\n })();\r\n const diff = Math.abs(totalHeight - this.maxHeight) * bad1 * bad2;\r\n if(!optimalAttempt || diff < optimalDiff) {\r\n optimalAttempt = attempt;\r\n optimalDiff = diff;\r\n }\r\n }\r\n\r\n const optimalCounts = optimalAttempt.lineCounts;\r\n\t const optimalHeights = optimalAttempt.heights;\r\n const rowCount = optimalCounts.length;\r\n \r\n let index = 0;\r\n let y = 0;\r\n for(let row = 0; row !== rowCount; ++row) {\r\n const colCount = optimalCounts[row];\r\n const lineHeight = optimalHeights[row];\r\n const height = Math.round(lineHeight);\r\n\r\n let x = 0;\r\n for(let col = 0; col !== colCount; ++col) {\r\n const sides = RectPart.None\r\n | (row === 0 ? RectPart.Top : RectPart.None)\r\n | (row === rowCount - 1 ? RectPart.Bottom : RectPart.None)\r\n | (col === 0 ? RectPart.Left : RectPart.None)\r\n | (col === colCount - 1 ? RectPart.Right : RectPart.None);\r\n\r\n const ratio = this.ratios[index];\r\n const width = (col === colCount - 1)\r\n ? (this.maxWidth - x)\r\n : Math.round(ratio * lineHeight);\r\n result[index] = {\r\n geometry: {x, y, width, height},\r\n sides\r\n };\r\n\r\n x += width + this.spacing;\r\n ++index;\r\n }\r\n y += height + this.spacing;\r\n }\r\n\r\n return result;\r\n }\r\n}","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { InputFile } from \"../layer\";\r\nimport AvatarEdit from \"./avatarEdit\";\r\nimport AvatarElement from \"./avatar\";\r\nimport InputField from \"./inputField\";\r\nimport ListenerSetter from \"../helpers/listenerSetter\";\r\nimport ButtonCorner from \"./buttonCorner\";\r\nimport safeAssign from \"../helpers/object/safeAssign\";\r\n\r\nexport default class EditPeer {\r\n public nextBtn: HTMLButtonElement;\r\n\r\n public uploadAvatar: () => Promise<InputFile>;\r\n public avatarEdit: AvatarEdit;\r\n public avatarElem: AvatarElement;\r\n\r\n private inputFields: InputField[];\r\n private listenerSetter: ListenerSetter;\r\n\r\n private peerId: PeerId;\r\n\r\n private _disabled = false;\r\n private avatarSize = 120;\r\n\r\n constructor(options: {\r\n peerId?: EditPeer['peerId'],\r\n inputFields: EditPeer['inputFields'],\r\n listenerSetter: ListenerSetter,\r\n doNotEditAvatar?: boolean,\r\n withoutAvatar?: boolean,\r\n nextBtn?: HTMLButtonElement,\r\n avatarSize?: number\r\n }) {\r\n safeAssign(this, options);\r\n\r\n if(!this.nextBtn) {\r\n this.nextBtn = ButtonCorner({icon: 'check'});\r\n } else if(!this.nextBtn.classList.contains('btn-corner')) {\r\n this.handleChange = () => {\r\n this.nextBtn.toggleAttribute('disabled', !this.isChanged() || this.disabled);\r\n };\r\n }\r\n\r\n if(!options.withoutAvatar) {\r\n this.avatarElem = document.createElement('avatar-element') as AvatarElement;\r\n this.avatarElem.classList.add('avatar-placeholder', 'avatar-' + this.avatarSize);\r\n this.avatarElem.updateWithOptions({peerId: this.peerId});\r\n \r\n if(!options.doNotEditAvatar) {\r\n this.avatarEdit = new AvatarEdit((_upload) => {\r\n this.uploadAvatar = _upload;\r\n this.handleChange();\r\n this.avatarElem.remove();\r\n });\r\n \r\n this.avatarEdit.container.append(this.avatarElem);\r\n }\r\n }\r\n\r\n this.inputFields.forEach(inputField => {\r\n this.listenerSetter.add(inputField.input)('input', this.handleChange);\r\n });\r\n\r\n this.handleChange();\r\n }\r\n\r\n public get disabled() {\r\n return this._disabled;\r\n }\r\n\r\n public set disabled(value) {\r\n this._disabled = value;\r\n this.inputFields.forEach(inputField => inputField.input.toggleAttribute('disabled', value));\r\n this.handleChange();\r\n }\r\n\r\n public lockWithPromise(promise: Promise<any>, unlockOnSuccess = false) {\r\n this.disabled = true;\r\n promise.then(() => {\r\n if(unlockOnSuccess) {\r\n this.disabled = false;\r\n }\r\n }, () => {\r\n this.disabled = false;\r\n });\r\n }\r\n\r\n public isChanged = () => {\r\n if(this.uploadAvatar) {\r\n return true;\r\n }\r\n\r\n let changedLength = 0, requiredLength = 0, requiredValidLength = 0;\r\n this.inputFields.forEach(inputField => {\r\n if(inputField.isValid()) {\r\n if(inputField.isChanged()) {\r\n ++changedLength;\r\n }\r\n\r\n if(inputField.required) {\r\n ++requiredValidLength;\r\n }\r\n }\r\n\r\n if(inputField.required) {\r\n ++requiredLength;\r\n }\r\n });\r\n\r\n return requiredLength === requiredValidLength && changedLength > 0;\r\n };\r\n\r\n public handleChange = () => {\r\n this.nextBtn.classList.toggle('is-visible', this.isChanged());\r\n };\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nexport default function RadioForm(radios: {container: HTMLElement, input: HTMLInputElement}[], onChange: (value: string, event: Event) => void) {\r\n const form = document.createElement('form');\r\n\r\n radios.forEach(r => {\r\n const {container, input} = r;\r\n form.append(container);\r\n input.addEventListener('change', (e) => {\r\n if(input.checked) {\r\n onChange(input.value, e);\r\n }\r\n });\r\n });\r\n\r\n return form;\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport CheckboxField from \"./checkboxField\";\r\nimport RadioField from \"./radioField\";\r\nimport ripple from \"./ripple\";\r\nimport { SliderSuperTab } from \"./slider\";\r\nimport RadioForm from \"./radioForm\";\r\nimport { i18n, LangPackKey } from \"../lib/langPack\";\r\nimport replaceContent from \"../helpers/dom/replaceContent\";\r\nimport setInnerHTML from \"../helpers/dom/setInnerHTML\";\r\n\r\nexport default class Row {\r\n public container: HTMLElement;\r\n public title: HTMLDivElement;\r\n public titleRight: HTMLElement;\r\n public subtitle: HTMLElement;\r\n public media: HTMLElement;\r\n\r\n public checkboxField: CheckboxField;\r\n public radioField: RadioField;\r\n\r\n public freezed = false;\r\n\r\n constructor(options: Partial<{\r\n icon: string,\r\n subtitle: string | HTMLElement | DocumentFragment,\r\n subtitleLangKey: LangPackKey,\r\n subtitleLangArgs: any[],\r\n radioField: Row['radioField'],\r\n checkboxField: Row['checkboxField'],\r\n noCheckboxSubtitle: boolean,\r\n title: string | HTMLElement | DocumentFragment,\r\n titleLangKey: LangPackKey,\r\n titleRight: string | HTMLElement,\r\n titleRightSecondary: string | HTMLElement,\r\n clickable: boolean | ((e: Event) => void),\r\n navigationTab: SliderSuperTab,\r\n havePadding: boolean,\r\n noRipple: boolean\r\n }> = {}) {\r\n this.container = document.createElement(options.radioField || options.checkboxField ? 'label' : 'div');\r\n this.container.classList.add('row');\r\n\r\n this.subtitle = document.createElement('div');\r\n this.subtitle.classList.add('row-subtitle');\r\n this.subtitle.setAttribute('dir', 'auto');\r\n if(options.subtitle) {\r\n if(typeof(options.subtitle) === 'string') {\r\n setInnerHTML(this.subtitle, options.subtitle);\r\n } else {\r\n this.subtitle.append(options.subtitle);\r\n }\r\n } else if(options.subtitleLangKey) {\r\n this.subtitle.append(i18n(options.subtitleLangKey, options.subtitleLangArgs));\r\n }\r\n this.container.append(this.subtitle);\r\n\r\n let havePadding = !!options.havePadding;\r\n if(options.radioField || options.checkboxField) {\r\n if(options.radioField) {\r\n this.radioField = options.radioField;\r\n this.container.append(this.radioField.label);\r\n havePadding = true;\r\n }\r\n\r\n if(options.checkboxField) {\r\n this.checkboxField = options.checkboxField;\r\n \r\n const isToggle = options.checkboxField.label.classList.contains('checkbox-field-toggle');\r\n if(isToggle) {\r\n this.container.classList.add('row-with-toggle');\r\n options.titleRight = this.checkboxField.label;\r\n } else {\r\n havePadding = true;\r\n this.container.append(this.checkboxField.label);\r\n }\r\n\r\n if(!options.noCheckboxSubtitle && !isToggle) {\r\n this.checkboxField.input.addEventListener('change', () => {\r\n replaceContent(this.subtitle, i18n(this.checkboxField.input.checked ? 'Checkbox.Enabled' : 'Checkbox.Disabled'));\r\n });\r\n }\r\n }\r\n\r\n const i = options.radioField || options.checkboxField;\r\n i.label.classList.add('disable-hover');\r\n } \r\n \r\n if(options.title || options.titleLangKey) {\r\n let c: HTMLElement;\r\n const titleRight = options.titleRight || options.titleRightSecondary;\r\n if(titleRight) {\r\n c = document.createElement('div');\r\n c.classList.add('row-title-row');\r\n this.container.append(c);\r\n } else {\r\n c = this.container;\r\n }\r\n\r\n this.title = document.createElement('div');\r\n this.title.classList.add('row-title');\r\n this.title.setAttribute('dir', 'auto');\r\n if(options.title) {\r\n if(typeof(options.title) === 'string') {\r\n this.title.innerHTML = options.title;\r\n } else {\r\n this.title.append(options.title);\r\n }\r\n } else {\r\n this.title.append(i18n(options.titleLangKey));\r\n }\r\n c.append(this.title);\r\n\r\n if(titleRight) {\r\n const titleRightEl = this.titleRight = document.createElement('div');\r\n titleRightEl.classList.add('row-title', 'row-title-right');\r\n\r\n if(options.titleRightSecondary) {\r\n titleRightEl.classList.add('row-title-right-secondary');\r\n }\r\n\r\n if(typeof(titleRight) === 'string') {\r\n titleRightEl.innerHTML = titleRight;\r\n } else {\r\n titleRightEl.append(titleRight);\r\n }\r\n\r\n c.append(titleRightEl);\r\n }\r\n }\r\n\r\n if(options.icon) {\r\n havePadding = true;\r\n this.title.classList.add('tgico', 'tgico-' + options.icon);\r\n this.container.classList.add('row-with-icon');\r\n }\r\n\r\n if(havePadding) {\r\n this.container.classList.add('row-with-padding');\r\n }\r\n\r\n if(options.navigationTab) {\r\n options.clickable = () => options.navigationTab.open();\r\n }\r\n\r\n if(options.clickable || options.radioField || options.checkboxField) {\r\n if(typeof(options.clickable) === 'function') {\r\n this.container.addEventListener('click', (e) => {\r\n if(this.freezed) return;\r\n (options.clickable as any)(e);\r\n });\r\n }\r\n\r\n this.container.classList.add('row-clickable', 'hover-effect');\r\n\r\n if(!options.noRipple) {\r\n ripple(this.container, undefined, undefined, true);\r\n }\r\n\r\n /* if(options.radioField || options.checkboxField) {\r\n this.container.prepend(this.container.lastElementChild);\r\n } */\r\n }\r\n }\r\n\r\n public createMedia(size?: 'small') {\r\n this.container.classList.add('row-with-padding');\r\n \r\n const media = this.media = document.createElement('div');\r\n media.classList.add('row-media');\r\n\r\n if(size) {\r\n media.classList.add('row-media-' + size);\r\n }\r\n\r\n this.container.append(media);\r\n\r\n return media;\r\n }\r\n}\r\n\r\nexport const RadioFormFromRows = (rows: Row[], onChange: (value: string) => void) => {\r\n return RadioForm(rows.map(r => ({container: r.container, input: r.radioField.input})), onChange);\r\n};\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\n// https://stackoverflow.com/a/30810322\r\nfunction fallbackCopyTextToClipboard(text: string) {\r\n var textArea = document.createElement(\"textarea\");\r\n textArea.value = text;\r\n \r\n // Avoid scrolling to bottom\r\n textArea.style.top = \"0\";\r\n textArea.style.left = \"0\";\r\n textArea.style.position = \"fixed\";\r\n\r\n document.body.appendChild(textArea);\r\n textArea.focus();\r\n textArea.select();\r\n\r\n try {\r\n document.execCommand('copy');\r\n //const successful = document.execCommand('copy');\r\n //const msg = successful ? 'successful' : 'unsuccessful';\r\n //console.log('Fallback: Copying text command was ' + msg);\r\n } catch(err) {\r\n //console.error('Fallback: Oops, unable to copy', err);\r\n }\r\n\r\n document.body.removeChild(textArea);\r\n}\r\n\r\nexport function copyTextToClipboard(text: string) {\r\n if(!navigator.clipboard) {\r\n fallbackCopyTextToClipboard(text);\r\n return;\r\n }\r\n \r\n navigator.clipboard.writeText(text);/* .then(function() {\r\n console.log('Async: Copying to clipboard was successful!');\r\n }, function(err) {\r\n console.error('Async: Could not copy text: ', err);\r\n }); */\r\n}","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport getDeepProperty from \"../helpers/object/getDeepProperty\";\r\nimport appStateManager from \"../lib/appManagers/appStateManager\";\r\nimport { LangPackKey, _i18n } from \"../lib/langPack\";\r\n\r\nexport default class RadioField {\r\n public input: HTMLInputElement;\r\n public label: HTMLLabelElement;\r\n public main: HTMLElement;\r\n\r\n constructor(options: {\r\n text?: string, \r\n langKey?: LangPackKey,\r\n name: string, \r\n value?: string, \r\n stateKey?: string,\r\n alignRight?: boolean\r\n }) {\r\n const label = this.label = document.createElement('label');\r\n label.classList.add('radio-field');\r\n\r\n if(options.alignRight) {\r\n label.classList.add('radio-field-right');\r\n }\r\n \r\n const input = this.input = document.createElement('input');\r\n input.type = 'radio';\r\n /* input.id = */input.name = 'input-radio-' + options.name;\r\n \r\n if(options.value) {\r\n input.value = options.value;\r\n \r\n if(options.stateKey) {\r\n appStateManager.getState().then(state => {\r\n input.checked = getDeepProperty(state, options.stateKey) === options.value;\r\n });\r\n \r\n input.addEventListener('change', () => {\r\n appStateManager.setByKey(options.stateKey, options.value);\r\n });\r\n }\r\n }\r\n \r\n const main = this.main = document.createElement('div');\r\n main.classList.add('radio-field-main');\r\n \r\n if(options.text) {\r\n main.innerHTML = options.text;\r\n /* const caption = document.createElement('div');\r\n caption.classList.add('radio-field-main-caption');\r\n caption.innerHTML = text;\r\n \r\n if(subtitle) {\r\n label.classList.add('radio-field-with-subtitle');\r\n caption.insertAdjacentHTML('beforeend', `<div class=\"radio-field-main-subtitle\">${subtitle}</div>`);\r\n }\r\n \r\n main.append(caption); */\r\n } else if(options.langKey) {\r\n _i18n(main, options.langKey);\r\n }\r\n \r\n label.append(input, main);\r\n }\r\n\r\n get checked() {\r\n return this.input.checked;\r\n }\r\n\r\n set checked(checked: boolean) {\r\n this.setValueSilently(checked);\r\n\r\n const event = new Event('change', {bubbles: true, cancelable: true});\r\n this.input.dispatchEvent(event);\r\n }\r\n\r\n public setValueSilently(checked: boolean) {\r\n this.input.checked = checked;\r\n }\r\n};\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport replaceContent from \"../helpers/dom/replaceContent\";\r\nimport { FormatterArguments, i18n, LangPackKey } from \"../lib/langPack\";\r\n\r\nconst toastEl = document.createElement('div');\r\ntoastEl.classList.add('toast');\r\nexport function toast(content: string | Node) {\r\n replaceContent(toastEl, content);\r\n document.body.append(toastEl);\r\n\r\n if(toastEl.dataset.timeout) clearTimeout(+toastEl.dataset.timeout);\r\n toastEl.dataset.timeout = '' + setTimeout(() => {\r\n toastEl.remove();\r\n delete toastEl.dataset.timeout;\r\n }, 3000);\r\n}\r\n\r\nexport function toastNew(options: Partial<{\r\n langPackKey: LangPackKey,\r\n langPackArguments: FormatterArguments\r\n}>) {\r\n toast(i18n(options.langPackKey, options.langPackArguments));\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport ListenerSetter from \"../helpers/listenerSetter\";\r\nimport debounce from \"../helpers/schedulers/debounce\";\r\nimport appChatsManager from \"../lib/appManagers/appChatsManager\";\r\nimport { LangPackKey } from \"../lib/langPack\";\r\nimport apiManager from \"../lib/mtproto/mtprotoworker\";\r\nimport RichTextProcessor from \"../lib/richtextprocessor\";\r\nimport InputField, { InputFieldOptions, InputState } from \"./inputField\";\r\n\r\nexport class UsernameInputField extends InputField {\r\n private checkUsernamePromise: Promise<any>;\r\n private checkUsernameDebounced: (username: string) => void;\r\n public options: InputFieldOptions & {\r\n peerId?: PeerId,\r\n listenerSetter: ListenerSetter,\r\n onChange?: () => void,\r\n invalidText: LangPackKey,\r\n takenText: LangPackKey,\r\n availableText: LangPackKey,\r\n head?: string\r\n };\r\n\r\n constructor(options: UsernameInputField['options']) {\r\n super(options);\r\n\r\n this.checkUsernameDebounced = debounce(this.checkUsername.bind(this), 150, false, true);\r\n\r\n options.listenerSetter.add(this.input)('input', () => {\r\n const value = this.getValue();\r\n\r\n //console.log('userNameInput:', value);\r\n if(value === this.originalValue || !value.length) {\r\n this.setState(InputState.Neutral, this.options.label);\r\n this.options.onChange && this.options.onChange();\r\n return;\r\n } else if(!RichTextProcessor.isUsernameValid(value)) { // does not check the last underscore\r\n this.setError(this.options.invalidText);\r\n } else {\r\n this.setState(InputState.Neutral);\r\n }\r\n\r\n if(this.input.classList.contains('error')) {\r\n this.options.onChange && this.options.onChange();\r\n return;\r\n }\r\n\r\n this.checkUsernameDebounced(value);\r\n });\r\n }\r\n\r\n public getValue() {\r\n let value = this.value;\r\n if(this.options.head) {\r\n value = value.slice(this.options.head.length);\r\n this.setValueSilently(this.options.head + value);\r\n }\r\n\r\n return value;\r\n }\r\n\r\n private checkUsername(username: string) {\r\n if(this.checkUsernamePromise) return;\r\n\r\n if(this.options.peerId) {\r\n this.checkUsernamePromise = apiManager.invokeApi('channels.checkUsername', {\r\n channel: appChatsManager.getChannelInput(this.options.peerId.toChatId()),\r\n username\r\n });\r\n } else {\r\n this.checkUsernamePromise = apiManager.invokeApi('account.checkUsername', {username});\r\n }\r\n\r\n this.checkUsernamePromise.then(available => {\r\n if(this.getValue() !== username) return;\r\n\r\n if(available) {\r\n this.setState(InputState.Valid, this.options.availableText);\r\n } else {\r\n this.setError(this.options.takenText);\r\n }\r\n }, (err) => {\r\n if(this.getValue() !== username) return;\r\n\r\n switch(err.type) {\r\n case 'USERNAME_INVALID': {\r\n this.setError(this.options.invalidText);\r\n break;\r\n }\r\n }\r\n }).then(() => {\r\n this.checkUsernamePromise = undefined;\r\n this.options.onChange && this.options.onChange();\r\n\r\n const value = this.getValue();\r\n if(value !== username && this.isValidToChange() && RichTextProcessor.isUsernameValid(value)) {\r\n this.checkUsername(value);\r\n }\r\n });\r\n };\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport AvatarElement from \"../avatar\";\nimport PopupElement, { addCancelButton, PopupButton, PopupOptions } from \".\";\nimport { i18n, LangPackKey } from \"../../lib/langPack\";\nimport CheckboxField, { CheckboxFieldOptions } from \"../checkboxField\";\nimport setInnerHTML from \"../../helpers/dom/setInnerHTML\";\n\nexport type PopupPeerButton = Omit<PopupButton, 'callback'> & Partial<{callback: PopupPeerButtonCallback}>;\nexport type PopupPeerButtonCallbackCheckboxes = Set<LangPackKey>;\nexport type PopupPeerButtonCallback = (checkboxes?: PopupPeerButtonCallbackCheckboxes) => void;\nexport type PopupPeerCheckboxOptions = CheckboxFieldOptions & {checkboxField?: CheckboxField};\n\nexport type PopupPeerOptions = PopupOptions & Partial<{\n peerId: PeerId,\n title: string | HTMLElement,\n titleLangKey?: LangPackKey,\n titleLangArgs?: any[],\n noTitle?: boolean,\n description: string | DocumentFragment,\n descriptionLangKey?: LangPackKey,\n descriptionLangArgs?: any[],\n buttons?: Array<PopupPeerButton>,\n checkboxes: Array<PopupPeerCheckboxOptions>\n}>;\nexport default class PopupPeer extends PopupElement {\n protected description: HTMLParagraphElement;\n\n constructor(private className: string, options: PopupPeerOptions = {}) {\n super('popup-peer' + (className ? ' ' + className : ''), options.buttons && addCancelButton(options.buttons), {overlayClosable: true, ...options});\n\n if(options.peerId) {\n const avatarEl = new AvatarElement();\n avatarEl.classList.add('avatar-32');\n avatarEl.updateWithOptions({\n isDialog: true,\n peerId: options.peerId\n });\n this.header.prepend(avatarEl);\n }\n\n if(!options.noTitle) {\n if(options.titleLangKey || !options.title) this.title.append(i18n(options.titleLangKey || 'AppName', options.titleLangArgs));\n else if(options.title instanceof HTMLElement) {\n this.title.append(options.title);\n } else this.title.innerText = options.title || '';\n }\n\n const fragment = document.createDocumentFragment();\n\n if(options.descriptionLangKey || options.description) {\n const p = this.description = document.createElement('p');\n p.classList.add('popup-description');\n if(options.descriptionLangKey) p.append(i18n(options.descriptionLangKey, options.descriptionLangArgs));\n else if(options.description) setInnerHTML(p, options.description);\n \n fragment.append(p);\n }\n\n if(options.checkboxes) {\n this.container.classList.add('have-checkbox');\n \n options.checkboxes.forEach(o => {\n o.withRipple = false;\n const checkboxField = new CheckboxField(o);\n o.checkboxField = checkboxField;\n fragment.append(checkboxField.label);\n });\n\n options.buttons.forEach(button => {\n if(button.callback) {\n const original = button.callback;\n button.callback = () => {\n const c: Set<LangPackKey> = new Set();\n options.checkboxes.forEach(o => {\n if(o.checkboxField.checked) {\n c.add(o.text);\n }\n });\n original(c);\n };\n }\n });\n }\n\n this.container.insertBefore(fragment, this.header.nextElementSibling);\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { copyTextToClipboard } from \"../../../helpers/clipboard\";\r\nimport { randomLong } from \"../../../helpers/random\";\r\nimport { Chat, ChatFull, ExportedChatInvite } from \"../../../layer\";\r\nimport appChatsManager from \"../../../lib/appManagers/appChatsManager\";\r\nimport appProfileManager from \"../../../lib/appManagers/appProfileManager\";\r\nimport Button from \"../../button\";\r\nimport { setButtonLoader } from \"../../misc\";\r\nimport RadioField from \"../../radioField\";\r\nimport Row, { RadioFormFromRows } from \"../../row\";\r\nimport { SettingSection } from \"../../sidebarLeft\";\r\nimport { toast } from \"../../toast\";\r\nimport { UsernameInputField } from \"../../usernameInputField\";\r\nimport { SliderSuperTabEventable } from \"../../sliderTab\";\r\nimport I18n from \"../../../lib/langPack\";\r\nimport PopupPeer from \"../../popups/peer\";\r\nimport ButtonCorner from \"../../buttonCorner\";\r\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\r\nimport toggleDisability from \"../../../helpers/dom/toggleDisability\";\r\nimport CheckboxField from \"../../checkboxField\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\n\r\nexport default class AppChatTypeTab extends SliderSuperTabEventable {\r\n public chatId: ChatId;\r\n public chatFull: ChatFull;\r\n\r\n protected init() {\r\n this.container.classList.add('edit-peer-container', 'group-type-container');\r\n\r\n const isBroadcast = appChatsManager.isBroadcast(this.chatId);\r\n\r\n this.setTitle(isBroadcast ? 'ChannelType' : 'GroupType');\r\n\r\n const section = new SettingSection({\r\n name: isBroadcast ? 'ChannelType' : 'GroupType'\r\n });\r\n\r\n const random = randomLong();\r\n const privateRow = new Row({\r\n radioField: new RadioField({\r\n langKey: isBroadcast ? 'ChannelPrivate' : 'MegaPrivate', \r\n name: random, \r\n value: 'private'\r\n }),\r\n subtitleLangKey: isBroadcast ? 'ChannelPrivateInfo' : 'MegaPrivateInfo'\r\n });\r\n const publicRow = new Row({\r\n radioField: new RadioField({\r\n langKey: isBroadcast ? 'ChannelPublic' : 'MegaPublic', \r\n name: random, \r\n value: 'public'\r\n }),\r\n subtitleLangKey: isBroadcast ? 'ChannelPublicInfo' : 'MegaPublicInfo'\r\n });\r\n const form = RadioFormFromRows([privateRow, publicRow], (value) => {\r\n const a = [privateSection, publicSection];\r\n if(value === 'public') a.reverse();\r\n\r\n a[0].container.classList.remove('hide');\r\n a[1].container.classList.add('hide');\r\n\r\n onChange();\r\n });\r\n\r\n const chat: Chat = appChatsManager.getChat(this.chatId);\r\n\r\n section.content.append(form);\r\n\r\n const privateSection = new SettingSection({});\r\n\r\n //let revoked = false;\r\n const linkRow = new Row({\r\n title: (this.chatFull.exported_invite as ExportedChatInvite.chatInviteExported).link,\r\n subtitleLangKey: isBroadcast ? 'ChannelPrivateLinkHelp' : 'MegaPrivateLinkHelp',\r\n clickable: () => {\r\n copyTextToClipboard((this.chatFull.exported_invite as ExportedChatInvite.chatInviteExported).link);\r\n toast(I18n.format('LinkCopied', true));\r\n }\r\n });\r\n\r\n const btnRevoke = Button('btn-primary btn-transparent danger', {icon: 'delete', text: 'RevokeLink'});\r\n\r\n attachClickEvent(btnRevoke, () => {\r\n new PopupPeer('revoke-link', {\r\n buttons: [{\r\n langKey: 'RevokeButton',\r\n callback: () => {\r\n const toggle = toggleDisability([btnRevoke], true);\r\n \r\n appProfileManager.getChatInviteLink(this.chatId, true).then(link => {\r\n toggle();\r\n linkRow.title.innerHTML = link;\r\n //revoked = true;\r\n //onChange();\r\n });\r\n }\r\n }],\r\n titleLangKey: 'RevokeLink',\r\n descriptionLangKey: 'RevokeAlert'\r\n }).show();\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n privateSection.content.append(linkRow.container, btnRevoke);\r\n\r\n const publicSection = new SettingSection({\r\n caption: isBroadcast ? 'Channel.UsernameAboutChannel' : 'Channel.UsernameAboutGroup',\r\n noDelimiter: true\r\n });\r\n\r\n const inputWrapper = document.createElement('div');\r\n inputWrapper.classList.add('input-wrapper');\r\n\r\n const placeholder = 't.me/';\r\n\r\n const onChange = () => {\r\n const changed = (privateRow.radioField.checked && (originalValue !== placeholder/* || revoked */)) \r\n || (linkInputField.isValidToChange() && linkInputField.input.classList.contains('valid'));\r\n applyBtn.classList.toggle('is-visible', changed);\r\n };\r\n\r\n const linkInputField = new UsernameInputField({\r\n label: 'SetUrlPlaceholder',\r\n name: 'group-public-link',\r\n plainText: true,\r\n listenerSetter: this.listenerSetter,\r\n availableText: 'Link.Available',\r\n invalidText: 'Link.Invalid',\r\n takenText: 'Link.Taken',\r\n onChange: onChange,\r\n peerId: this.chatId.toPeerId(true),\r\n head: placeholder\r\n });\r\n\r\n const originalValue = placeholder + ((chat as Chat.channel).username || '');\r\n\r\n inputWrapper.append(linkInputField.container)\r\n publicSection.content.append(inputWrapper);\r\n\r\n const applyBtn = ButtonCorner({icon: 'check', className: 'is-visible'});\r\n this.content.append(applyBtn);\r\n\r\n attachClickEvent(applyBtn, () => {\r\n /* const unsetLoader = */setButtonLoader(applyBtn);\r\n const username = publicRow.radioField.checked ? linkInputField.getValue() : '';\r\n appChatsManager.migrateChat(this.chatId).then(channelId => {\r\n return appChatsManager.updateUsername(channelId, username);\r\n }).then(() => {\r\n //unsetLoader();\r\n this.close();\r\n });\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n (originalValue !== placeholder ? publicRow : privateRow).radioField.checked = true;\r\n linkInputField.setOriginalValue(originalValue);\r\n\r\n this.scrollable.append(section.container, privateSection.container, publicSection.container);\r\n\r\n {\r\n const section = new SettingSection({\r\n name: 'SavingContentTitle',\r\n caption: isBroadcast ? 'RestrictSavingContentInfoChannel' : 'RestrictSavingContentInfoGroup'\r\n });\r\n\r\n const checkboxField = new CheckboxField({\r\n text: 'RestrictSavingContent',\r\n withRipple: true\r\n });\r\n\r\n this.listenerSetter.add(checkboxField.input)('change', () => {\r\n const toggle = checkboxField.toggleDisability(true);\r\n appChatsManager.toggleNoForwards(this.chatId, checkboxField.checked).then(() => {\r\n toggle();\r\n });\r\n });\r\n\r\n const onChatUpdate = () => {\r\n checkboxField.setValueSilently(!!(chat as Chat.channel).pFlags.noforwards);\r\n };\r\n\r\n this.listenerSetter.add(rootScope)('chat_update', (chatId) => {\r\n if(this.chatId === chatId) {\r\n onChatUpdate();\r\n }\r\n });\r\n\r\n onChatUpdate();\r\n\r\n section.content.append(checkboxField.label);\r\n\r\n this.scrollable.append(section.container);\r\n }\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport Scrollable from \"../components/scrollable\";\r\nimport safeAssign from \"./object/safeAssign\";\r\n\r\nexport default class ScrollableLoader {\r\n public loading = false;\r\n private scrollable: Scrollable;\r\n private getPromise: () => Promise<boolean>;\r\n private promise: Promise<any>;\r\n private loaded = false;\r\n\r\n constructor(options: {\r\n scrollable: ScrollableLoader['scrollable'],\r\n getPromise: ScrollableLoader['getPromise']\r\n }) {\r\n safeAssign(this, options);\r\n\r\n options.scrollable.onScrolledBottom = () => {\r\n this.load();\r\n };\r\n }\r\n \r\n public load() {\r\n if(this.loaded) {\r\n return Promise.resolve();\r\n }\r\n \r\n if(this.loading) {\r\n return this.promise;\r\n }\r\n\r\n this.loading = true;\r\n this.promise = this.getPromise().then(done => {\r\n this.loading = false;\r\n this.promise = undefined;\r\n\r\n if(done) {\r\n this.loaded = true;\r\n this.scrollable.onScrolledBottom = null;\r\n } else {\r\n this.scrollable.checkForTriggers();\r\n }\r\n }, () => {\r\n this.promise = undefined;\r\n this.loading = false;\r\n });\r\n }\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport appChatsManager, { ChatRights } from \"../lib/appManagers/appChatsManager\";\nimport appDialogsManager from \"../lib/appManagers/appDialogsManager\";\nimport appMessagesManager, { Dialog } from \"../lib/appManagers/appMessagesManager\";\nimport appUsersManager from \"../lib/appManagers/appUsersManager\";\nimport rootScope from \"../lib/rootScope\";\nimport Scrollable from \"./scrollable\";\nimport { FocusDirection } from \"../helpers/fastSmoothScroll\";\nimport CheckboxField from \"./checkboxField\";\nimport appProfileManager from \"../lib/appManagers/appProfileManager\";\nimport { i18n, LangPackKey, _i18n } from \"../lib/langPack\";\nimport findUpAttribute from \"../helpers/dom/findUpAttribute\";\nimport findUpClassName from \"../helpers/dom/findUpClassName\";\nimport PeerTitle from \"./peerTitle\";\nimport cancelEvent from \"../helpers/dom/cancelEvent\";\nimport replaceContent from \"../helpers/dom/replaceContent\";\nimport debounce from \"../helpers/schedulers/debounce\";\nimport windowSize from \"../helpers/windowSize\";\nimport appPeersManager, { IsPeerType } from \"../lib/appManagers/appPeersManager\";\nimport { generateDelimiter, SettingSection } from \"./sidebarLeft\";\nimport { attachClickEvent } from \"../helpers/dom/clickEvent\";\nimport filterUnique from \"../helpers/array/filterUnique\";\nimport indexOfAndSplice from \"../helpers/array/indexOfAndSplice\";\nimport safeAssign from \"../helpers/object/safeAssign\";\nimport findAndSplice from \"../helpers/array/findAndSplice\";\nimport AvatarElement from \"./avatar\";\n\ntype SelectSearchPeerType = 'contacts' | 'dialogs' | 'channelParticipants';\n\n// TODO: правильная сортировка для addMembers, т.е. для peerType: 'contacts', потому что там идут сначала контакты - потом неконтакты, а должно всё сортироваться по имени\n\nexport default class AppSelectPeers {\n public container = document.createElement('div');\n public list = appDialogsManager.createChatList(/* {\n handheldsSize: 66,\n avatarSize: 48\n } */);\n private chatsContainer = document.createElement('div');\n public scrollable: Scrollable;\n private selectedScrollable: Scrollable;\n \n private selectedContainer: HTMLElement;\n public input: HTMLInputElement;\n \n //public selected: {[peerId: PeerId]: HTMLElement} = {};\n public selected = new Set<PeerId | string>();\n\n public freezed = false;\n\n private folderId = 0;\n private offsetIndex = 0;\n private promise: Promise<any>;\n\n private query = '';\n private cachedContacts: PeerId[];\n\n private loadedWhat: Partial<{[k in 'dialogs' | 'archived' | 'contacts' | 'channelParticipants']: true}> = {};\n\n private renderedPeerIds: Set<PeerId> = new Set();\n\n private appendTo: HTMLElement;\n private onChange: (length: number) => void;\n private peerType: SelectSearchPeerType[] = ['dialogs'];\n private renderResultsFunc: (peerIds: PeerId[]) => void;\n private chatRightsAction: ChatRights;\n private multiSelect = true;\n private rippleEnabled = true;\n private avatarSize = 48;\n private exceptSelf = false;\n private filterPeerTypeBy: IsPeerType[];\n\n private tempIds: {[k in keyof AppSelectPeers['loadedWhat']]: number} = {};\n private peerId: PeerId;\n\n private placeholder: LangPackKey;\n\n private selfPresence: LangPackKey = 'Presence.YourChat';\n \n private needSwitchList = false;\n\n private sectionNameLangPackKey: LangPackKey;\n \n constructor(options: {\n appendTo: AppSelectPeers['appendTo'], \n onChange?: AppSelectPeers['onChange'], \n peerType?: AppSelectPeers['peerType'], \n peerId?: AppSelectPeers['peerId'],\n onFirstRender?: () => void, \n renderResultsFunc?: AppSelectPeers['renderResultsFunc'], \n chatRightsAction?: AppSelectPeers['chatRightsAction'], \n multiSelect?: AppSelectPeers['multiSelect'],\n rippleEnabled?: AppSelectPeers['rippleEnabled'],\n avatarSize?: AppSelectPeers['avatarSize'],\n placeholder?: AppSelectPeers['placeholder'],\n selfPresence?: AppSelectPeers['selfPresence'],\n exceptSelf?: AppSelectPeers['exceptSelf'],\n filterPeerTypeBy?: AppSelectPeers['filterPeerTypeBy'],\n sectionNameLangPackKey?: AppSelectPeers['sectionNameLangPackKey']\n }) {\n safeAssign(this, options);\n\n this.container.classList.add('selector');\n\n const f = (this.renderResultsFunc || this.renderResults).bind(this);\n this.renderResultsFunc = (peerIds) => {\n if(this.needSwitchList) {\n this.scrollable.splitUp.replaceWith(this.list);\n this.scrollable.setVirtualContainer(this.list);\n this.needSwitchList = false;\n }\n \n peerIds = peerIds.filter(peerId => {\n const notRendered = !this.renderedPeerIds.has(peerId);\n if(notRendered) this.renderedPeerIds.add(peerId);\n return notRendered;\n });\n\n if(this.filterPeerTypeBy) {\n peerIds = peerIds.filter(peerId => {\n if(peerId.isPeerId()) {\n const peer = appPeersManager.getPeer(peerId);\n if(!peer.deleted) {\n return this.filterPeerTypeBy.find(method => appPeersManager[method](peerId));\n }\n }\n\n return true;\n });\n }\n\n return f(peerIds);\n };\n\n this.input = document.createElement('input');\n this.input.classList.add('selector-search-input');\n if(this.placeholder) {\n _i18n(this.input, this.placeholder, undefined, 'placeholder');\n } else {\n _i18n(this.input, 'SendMessageTo', undefined, 'placeholder');\n }\n\n this.input.type = 'text';\n\n if(this.multiSelect) {\n const section = new SettingSection({});\n section.innerContainer.classList.add('selector-search-section');\n let topContainer = document.createElement('div');\n topContainer.classList.add('selector-search-container');\n \n this.selectedContainer = document.createElement('div');\n this.selectedContainer.classList.add('selector-search');\n \n this.selectedContainer.append(this.input);\n topContainer.append(this.selectedContainer);\n this.selectedScrollable = new Scrollable(topContainer);\n \n // let delimiter = document.createElement('hr');\n\n attachClickEvent(this.selectedContainer, (e) => {\n if(this.freezed) return;\n let target = e.target as HTMLElement;\n target = findUpClassName(target, 'selector-user');\n \n if(!target) return;\n \n const peerId = target.dataset.key;\n const li = this.chatsContainer.querySelector('[data-peer-id=\"' + peerId + '\"]') as HTMLElement;\n if(!li) {\n this.remove(peerId.toPeerId());\n } else {\n li.click();\n }\n });\n\n section.content.append(topContainer);\n this.container.append(section.container/* , delimiter */);\n }\n\n this.chatsContainer.classList.add('chatlist-container');\n // this.chatsContainer.append(this.list);\n const section = new SettingSection({\n name: this.sectionNameLangPackKey,\n noShadow: true\n });\n section.content.append(this.list);\n this.chatsContainer.append(section.container);\n this.scrollable = new Scrollable(this.chatsContainer);\n this.scrollable.setVirtualContainer(this.list);\n\n attachClickEvent(this.chatsContainer, (e) => {\n const target = findUpAttribute(e.target, 'data-peer-id') as HTMLElement;\n cancelEvent(e);\n\n if(!target) return;\n if(this.freezed) return;\n\n let key: PeerId | string = target.dataset.peerId;\n key = key.isPeerId() ? key.toPeerId() : key;\n\n if(!this.multiSelect) {\n this.add(key);\n return;\n }\n\n //target.classList.toggle('active');\n if(this.selected.has(key)) {\n this.remove(key);\n } else {\n this.add(key);\n }\n\n const checkbox = target.querySelector('input') as HTMLInputElement;\n checkbox.checked = !checkbox.checked;\n });\n\n const debouncedInput = debounce(this.onInput, 200, false, true);\n this.input.addEventListener('input', debouncedInput);\n\n this.scrollable.onScrolledBottom = () => {\n this.getMoreResults();\n };\n\n this.scrollable.container.prepend(generateDelimiter());\n\n this.container.append(this.chatsContainer);\n this.appendTo.append(this.container);\n\n // WARNING TIMEOUT\n setTimeout(() => {\n let getResultsPromise = this.getMoreResults() as Promise<any>;\n if(options.onFirstRender) {\n getResultsPromise.then(() => {\n options.onFirstRender();\n });\n }\n }, 0);\n }\n\n private onInput = () => {\n const value = this.input.value;\n if(this.query !== value) {\n if(this.peerType.includes('contacts') || this.peerType.includes('dialogs')) {\n this.cachedContacts = null;\n }\n \n if(this.peerType.includes('dialogs')) {\n this.folderId = 0;\n this.offsetIndex = 0;\n }\n\n for(let i in this.tempIds) {\n // @ts-ignore\n ++this.tempIds[i];\n }\n\n this.list = appDialogsManager.createChatList();\n\n this.promise = null;\n this.loadedWhat = {};\n this.query = value;\n this.renderedPeerIds.clear();\n this.needSwitchList = true;\n \n //console.log('selectPeers input:', this.query);\n this.getMoreResults();\n }\n };\n\n private renderSaved() {\n if(!this.exceptSelf && \n !this.offsetIndex && \n this.folderId === 0 && \n this.peerType.includes('dialogs') && \n (!this.query || appUsersManager.testSelfSearch(this.query))) {\n this.renderResultsFunc([rootScope.myId]);\n }\n }\n\n private getTempId(type: keyof AppSelectPeers['tempIds']) {\n if(this.tempIds[type] === undefined) {\n this.tempIds[type] = 0;\n }\n\n return ++this.tempIds[type];\n }\n\n private async getMoreDialogs(): Promise<any> {\n if(this.promise) return this.promise;\n\n if(this.loadedWhat.dialogs && this.loadedWhat.archived) {\n return;\n }\n \n // в десктопе - сначала без группы, потом архивные, потом контакты без сообщений\n const pageCount = windowSize.height / 72 * 1.25 | 0;\n\n const tempId = this.getTempId('dialogs');\n const promise = appMessagesManager.getConversations(this.query, this.offsetIndex, pageCount, this.folderId, true).promise;\n this.promise = promise;\n const value = await promise;\n if(this.tempIds.dialogs !== tempId) {\n return;\n }\n\n this.promise = null;\n\n let dialogs = value.dialogs as Dialog[];\n if(dialogs.length) {\n const newOffsetIndex = dialogs[dialogs.length - 1].index || 0;\n\n dialogs = dialogs.slice();\n findAndSplice(dialogs, d => d.peerId === rootScope.myId); // no my account\n\n if(this.chatRightsAction) {\n dialogs = dialogs.filter(d => this.filterByRights(d.peerId));\n }\n\n this.renderSaved();\n\n this.offsetIndex = newOffsetIndex;\n }\n\n this.renderResultsFunc(dialogs.map(dialog => dialog.peerId));\n \n if(value.isEnd) {\n if(!this.loadedWhat.dialogs) {\n this.renderSaved();\n\n this.loadedWhat.dialogs = true;\n this.offsetIndex = 0;\n this.folderId = 1;\n\n return this.getMoreDialogs();\n } else {\n this.loadedWhat.archived = true;\n\n if(!this.loadedWhat.contacts/* && this.peerType.includes('contacts') */) {\n return this.getMoreContacts();\n }\n }\n }\n }\n\n private filterByRights(peerId: PeerId) {\n return (\n peerId.isUser() && \n (this.chatRightsAction !== 'send_messages' || appUsersManager.canSendToUser(peerId))\n ) || appChatsManager.hasRights(peerId.toChatId(), this.chatRightsAction);\n }\n\n private async getMoreContacts() {\n if(this.promise) return this.promise;\n\n if(this.loadedWhat.contacts) {\n return;\n }\n\n const isGlobalSearch = this.peerType.includes('contacts');\n\n if(!this.cachedContacts) {\n /* const promises: Promise<any>[] = [appUsersManager.getContacts(this.query)];\n if(!this.peerType.includes('dialogs')) {\n promises.push(appMessagesManager.getConversationsAll());\n }\n\n this.promise = Promise.all(promises);\n this.cachedContacts = (await this.promise)[0].slice(); */\n const tempId = this.getTempId('contacts');\n const promise = Promise.all([\n isGlobalSearch ? appUsersManager.getContactsPeerIds(this.query) : [],\n this.query ? appUsersManager.searchContacts(this.query) : undefined\n ]);\n\n this.promise = promise;\n let [cachedContacts, searchResult] = await promise;\n if(this.tempIds.contacts !== tempId) {\n return;\n }\n\n if(searchResult) {\n // do not add global result if only dialogs needed\n let resultPeerIds = isGlobalSearch ? searchResult.my_results.concat(searchResult.results) : searchResult.my_results;\n\n if(this.chatRightsAction) {\n resultPeerIds = resultPeerIds.filter(peerId => this.filterByRights(peerId));\n }\n\n if(!this.peerType.includes('dialogs')) {\n resultPeerIds = resultPeerIds.filter(peerId => peerId.isUser());\n }\n\n this.cachedContacts = filterUnique(cachedContacts.concat(resultPeerIds));\n } else this.cachedContacts = cachedContacts.slice();\n\n indexOfAndSplice(this.cachedContacts, rootScope.myId); // no my account\n this.promise = null;\n }\n\n // if(this.cachedContacts.length) {\n const pageCount = windowSize.height / 72 * 1.25 | 0;\n const arr = this.cachedContacts.splice(0, pageCount);\n this.renderResultsFunc(arr);\n // }\n \n if(!this.cachedContacts.length) {\n this.loadedWhat.contacts = true;\n\n // need to load non-contacts\n /* if(!this.peerType.includes('dialogs')) {\n return this.getMoreDialogs();\n } */\n }\n }\n\n private async getMoreChannelParticipants() {\n if(this.promise) return this.promise;\n\n if(this.loadedWhat.channelParticipants) {\n return;\n }\n\n const pageCount = 50; // same as in group permissions to use cache\n\n const tempId = this.getTempId('channelParticipants');\n const promise = appProfileManager.getChannelParticipants(this.peerId.toChatId(), {_: 'channelParticipantsSearch', q: this.query}, pageCount, this.list.childElementCount);\n const participants = await promise;\n if(this.tempIds.channelParticipants !== tempId) {\n return;\n }\n \n const peerIds = participants.participants.map(participant => {\n return appChatsManager.getParticipantPeerId(participant);\n });\n indexOfAndSplice(peerIds, rootScope.myId);\n this.renderResultsFunc(peerIds);\n\n if(this.list.childElementCount >= participants.count || participants.participants.length < pageCount) {\n this.loadedWhat.channelParticipants = true;\n }\n }\n\n checkForTriggers = () => {\n this.scrollable.checkForTriggers();\n };\n\n private getMoreResults() {\n const get = () => {\n const promises: Promise<any>[] = [];\n\n // if(!loadedAllDialogs && (this.peerType.includes('dialogs')/* || this.peerType.includes('contacts') */)) {\n // if(!loadAllDialogsPromise) {\n // loadAllDialogsPromise = appMessagesManager.getConversationsAll()\n // .then(() => {\n // loadedAllDialogs = true;\n // }).finally(() => {\n // loadAllDialogsPromise = null;\n // });\n // }\n\n // promises.push(loadAllDialogsPromise);\n // }\n \n if((this.peerType.includes('dialogs')/* || this.loadedWhat.contacts */) && !this.loadedWhat.archived) { // to load non-contacts\n promises.push(this.getMoreDialogs());\n \n if(!this.loadedWhat.archived) {\n return promises;\n }\n }\n \n if((this.peerType.includes('contacts') || this.peerType.includes('dialogs')) && !this.loadedWhat.contacts) {\n promises.push(this.getMoreContacts());\n }\n\n if(this.peerType.includes('channelParticipants') && !this.loadedWhat.channelParticipants) {\n promises.push(this.getMoreChannelParticipants());\n }\n \n return promises;\n };\n \n const promises = get();\n const promise = Promise.all(promises);\n if(promises.length) {\n promise.then(this.checkForTriggers);\n }\n\n return promise;\n }\n\n private renderResults(peerIds: PeerId[]) {\n //console.log('will renderResults:', peerIds);\n\n // оставим только неконтакты с диалогов\n if(!this.peerType.includes('dialogs') && this.loadedWhat.contacts) {\n peerIds = peerIds.filter(peerId => {\n return appUsersManager.isNonContactUser(peerId);\n });\n }\n\n peerIds.forEach(peerId => {\n const {dom} = appDialogsManager.addDialogNew({\n dialog: peerId,\n container: this.scrollable,\n drawStatus: false,\n rippleEnabled: this.rippleEnabled,\n avatarSize: this.avatarSize\n });\n\n if(this.multiSelect) {\n const selected = this.selected.has(peerId);\n const checkboxField = new CheckboxField();\n\n if(selected) {\n //dom.listEl.classList.add('active');\n checkboxField.input.checked = true;\n }\n\n dom.containerEl.prepend(checkboxField.label);\n }\n\n let subtitleEl: HTMLElement;\n if(peerId.isAnyChat()) {\n subtitleEl = appProfileManager.getChatMembersString(peerId.toChatId());\n } else if(peerId === rootScope.myId) {\n subtitleEl = i18n(this.selfPresence);\n } else {\n subtitleEl = appUsersManager.getUserStatusString(peerId);\n }\n\n dom.lastMessageSpan.append(subtitleEl);\n });\n }\n\n public add(key: PeerId | string, title?: string | HTMLElement, scroll = true) {\n //console.trace('add');\n this.selected.add(key);\n\n if(!this.multiSelect) {\n this.onChange(this.selected.size);\n return;\n }\n\n if(this.query.trim()) {\n this.input.value = '';\n this.onInput();\n }\n\n const div = document.createElement('div');\n div.classList.add('selector-user', 'scale-in');\n\n const avatarEl = new AvatarElement();\n avatarEl.classList.add('selector-user-avatar', 'tgico', 'avatar-32');\n avatarEl.isDialog = true;\n\n div.dataset.key = '' + key;\n if(key.isPeerId()) {\n if(title === undefined) {\n title = new PeerTitle({peerId: key.toPeerId(), dialog: true}).element;\n }\n\n avatarEl.updateWithOptions({\n peerId: key as PeerId\n });\n }\n\n if(title) {\n if(typeof(title) === 'string') {\n div.innerHTML = title;\n } else {\n replaceContent(div, title);\n div.append(title);\n }\n }\n\n div.insertAdjacentElement('afterbegin', avatarEl);\n\n this.selectedContainer.insertBefore(div, this.input);\n //this.selectedScrollable.scrollTop = this.selectedScrollable.scrollHeight;\n this.onChange && this.onChange(this.selected.size);\n \n if(scroll) {\n this.selectedScrollable.scrollIntoViewNew({\n element: this.input, \n position: 'center'\n });\n }\n \n return div;\n }\n\n public remove(key: PeerId | string) {\n if(!this.multiSelect) return;\n //const div = this.selected[peerId];\n const div = this.selectedContainer.querySelector(`[data-key=\"${key}\"]`) as HTMLElement;\n div.classList.remove('scale-in');\n void div.offsetWidth;\n div.classList.add('scale-out');\n\n const onAnimationEnd = () => {\n this.selected.delete(key);\n div.remove();\n this.onChange && this.onChange(this.selected.size);\n };\n\n if(rootScope.settings.animationsEnabled) {\n div.addEventListener('animationend', onAnimationEnd, {once: true});\n } else {\n onAnimationEnd();\n }\n }\n\n public getSelected() {\n return [...this.selected];\n }\n\n public addInitial(values: any[]) {\n values.forEach(value => {\n this.add(value, undefined, false);\n });\n\n window.requestAnimationFrame(() => { // ! not the best place for this raf though it works\n this.selectedScrollable.scrollIntoViewNew({\n element: this.input, \n position: 'center', \n forceDirection: FocusDirection.Static\n });\n });\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { IS_TOUCH_SUPPORTED } from \"../../environment/touchSupport\";\r\nimport AppSelectPeers from \"../appSelectPeers\";\r\nimport PopupElement from \".\";\r\nimport { LangPackKey, _i18n } from \"../../lib/langPack\";\r\n\r\nexport default class PopupPickUser extends PopupElement {\r\n protected selector: AppSelectPeers;\r\n \r\n constructor(options: {\r\n peerTypes: AppSelectPeers['peerType'], \r\n onSelect?: (peerId: PeerId) => Promise<void> | void, \r\n placeholder: LangPackKey,\r\n chatRightsAction?: AppSelectPeers['chatRightsAction'],\r\n peerId?: number,\r\n selfPresence?: LangPackKey\r\n }) {\r\n super('popup-forward', null, {closable: true, overlayClosable: true, body: true});\r\n\r\n this.selector = new AppSelectPeers({\r\n appendTo: this.body, \r\n onChange: async() => {\r\n const selected = this.selector.getSelected();\r\n const peerId = selected[selected.length - 1].toPeerId();\r\n \r\n if(options.onSelect) {\r\n const res = options.onSelect(peerId);\r\n if(res instanceof Promise) {\r\n try {\r\n await res;\r\n } catch(err) {\r\n return;\r\n }\r\n }\r\n }\r\n\r\n this.selector = null;\r\n this.hide();\r\n }, \r\n peerType: options.peerTypes, \r\n onFirstRender: () => {\r\n this.show();\r\n this.selector.checkForTriggers(); // ! due to zero height before mounting\r\n\r\n if(!IS_TOUCH_SUPPORTED) {\r\n this.selector.input.focus();\r\n }\r\n }, \r\n chatRightsAction: options.chatRightsAction, \r\n multiSelect: false,\r\n rippleEnabled: false,\r\n avatarSize: 46,\r\n peerId: options.peerId,\r\n placeholder: options.placeholder,\r\n selfPresence: options.selfPresence\r\n });\r\n\r\n //this.scrollable = new Scrollable(this.body);\r\n\r\n this.title.append(this.selector.input);\r\n }\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\nimport toggleDisability from \"../../../helpers/dom/toggleDisability\";\nimport deepEqual from \"../../../helpers/object/deepEqual\";\nimport { ChannelParticipant } from \"../../../layer\";\nimport appChatsManager from \"../../../lib/appManagers/appChatsManager\";\nimport appDialogsManager from \"../../../lib/appManagers/appDialogsManager\";\nimport appUsersManager from \"../../../lib/appManagers/appUsersManager\";\nimport Button from \"../../button\";\nimport { SettingSection } from \"../../sidebarLeft\";\nimport { SliderSuperTabEventable } from \"../../sliderTab\";\nimport { ChatPermissions } from \"./groupPermissions\";\n\nexport default class AppUserPermissionsTab extends SliderSuperTabEventable {\n public participant: ChannelParticipant;\n public chatId: ChatId;\n public userId: UserId;\n\n protected init() {\n this.container.classList.add('edit-peer-container', 'user-permissions-container');\n this.setTitle('UserRestrictions');\n\n let destroyListener: () => void;\n\n {\n const section = new SettingSection({\n name: 'UserRestrictionsCanDo',\n });\n \n const div = document.createElement('div');\n div.classList.add('chatlist-container');\n section.content.insertBefore(div, section.title);\n\n const list = appDialogsManager.createChatList({new: true});\n div.append(list);\n\n const {dom} = appDialogsManager.addDialogNew({\n dialog: this.userId.toPeerId(false),\n container: list,\n drawStatus: false,\n rippleEnabled: true,\n avatarSize: 48\n });\n\n dom.lastMessageSpan.append(appUsersManager.getUserStatusString(this.userId));\n\n const p = new ChatPermissions({\n chatId: this.chatId,\n listenerSetter: this.listenerSetter,\n appendTo: section.content,\n participant: this.participant._ === 'channelParticipantBanned' ? this.participant : undefined\n });\n\n destroyListener = () => {\n //appChatsManager.editChatDefaultBannedRights(this.chatId, p.takeOut());\n const rights = p.takeOut();\n if(this.participant._ === 'channelParticipantBanned' && deepEqual(this.participant.banned_rights.pFlags, rights.pFlags)) {\n return;\n }\n\n appChatsManager.editBanned(this.chatId, this.participant, rights);\n };\n\n this.eventListener.addEventListener('destroy', destroyListener, {once: true});\n\n this.scrollable.append(section.container);\n }\n \n {\n const section = new SettingSection({});\n\n if(this.participant._ === 'channelParticipantBanned') {\n const btnDeleteException = Button('btn-primary btn-transparent danger', {icon: 'delete', text: 'GroupPermission.Delete'});\n\n attachClickEvent(btnDeleteException, () => {\n const toggle = toggleDisability([btnDeleteException], true);\n appChatsManager.clearChannelParticipantBannedRights(this.chatId, this.participant).then(() => {\n this.eventListener.removeEventListener('destroy', destroyListener);\n this.close();\n }, () => {\n toggle();\n });\n }, {listenerSetter: this.listenerSetter});\n \n section.content.append(btnDeleteException);\n }\n\n const btnDelete = Button('btn-primary btn-transparent danger', {icon: 'deleteuser', text: 'UserRestrictionsBlock'});\n\n attachClickEvent(btnDelete, () => {\n const toggle = toggleDisability([btnDelete], true);\n appChatsManager.kickFromChannel(this.chatId, this.participant).then(() => {\n this.eventListener.removeEventListener('destroy', destroyListener);\n this.close();\n });\n /* new PopupPeer('popup-group-kick-user', {\n peerId: -this.chatId,\n title: 'Ban User?',\n description: `Are you sure you want to ban <b>${appPeersManager.getPeerTitle(this.userId)}</b>`,\n buttons: addCancelButton([{\n text: 'BAN',\n callback: () => {\n const toggle = toggleDisability([btnDelete], true);\n\n appChatsManager.kickFromChannel(this.chatId, this.participant).then(() => {\n this.eventListener.removeEventListener('destroy', destroyListener);\n this.close();\n }, () => {\n toggle();\n });\n },\n isDanger: true\n }])\n }).show(); */\n }, {listenerSetter: this.listenerSetter});\n\n section.content.append(btnDelete);\n\n this.scrollable.append(section.container);\n }\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\nimport findUpTag from \"../../../helpers/dom/findUpTag\";\nimport replaceContent from \"../../../helpers/dom/replaceContent\";\nimport ListenerSetter from \"../../../helpers/listenerSetter\";\nimport ScrollableLoader from \"../../../helpers/scrollableLoader\";\nimport { ChannelParticipant, Chat, ChatBannedRights, Update } from \"../../../layer\";\nimport appChatsManager, { ChatRights } from \"../../../lib/appManagers/appChatsManager\";\nimport appDialogsManager from \"../../../lib/appManagers/appDialogsManager\";\nimport appPeersManager from \"../../../lib/appManagers/appPeersManager\";\nimport appProfileManager from \"../../../lib/appManagers/appProfileManager\";\nimport I18n, { i18n, join, LangPackKey } from \"../../../lib/langPack\";\nimport rootScope from \"../../../lib/rootScope\";\nimport CheckboxField from \"../../checkboxField\";\nimport PopupPickUser from \"../../popups/pickUser\";\nimport Row from \"../../row\";\nimport { SettingSection } from \"../../sidebarLeft\";\nimport { SliderSuperTabEventable } from \"../../sliderTab\";\nimport { toast } from \"../../toast\";\nimport AppUserPermissionsTab from \"./userPermissions\";\n\nexport class ChatPermissions {\n public v: Array<{\n flags: ChatRights[],\n text: LangPackKey,\n exceptionText: LangPackKey,\n checkboxField?: CheckboxField,\n }>;\n private toggleWith: Partial<{[chatRight in ChatRights]: ChatRights[]}>;\n\n constructor(options: {\n chatId: ChatId,\n listenerSetter: ListenerSetter,\n appendTo: HTMLElement,\n participant?: ChannelParticipant.channelParticipantBanned\n }) {\n this.v = [\n {flags: ['send_messages'], text: 'UserRestrictionsSend', exceptionText: 'UserRestrictionsNoSend'},\n {flags: ['send_media'], text: 'UserRestrictionsSendMedia', exceptionText: 'UserRestrictionsNoSendMedia'},\n {flags: ['send_stickers', 'send_gifs'], text: 'UserRestrictionsSendStickers', exceptionText: 'UserRestrictionsNoSendStickers'},\n {flags: ['send_polls'], text: 'UserRestrictionsSendPolls', exceptionText: 'UserRestrictionsNoSendPolls'},\n {flags: ['embed_links'], text: 'UserRestrictionsEmbedLinks', exceptionText: 'UserRestrictionsNoEmbedLinks'},\n {flags: ['invite_users'], text: 'UserRestrictionsInviteUsers', exceptionText: 'UserRestrictionsNoInviteUsers'},\n {flags: ['pin_messages'], text: 'UserRestrictionsPinMessages', exceptionText: 'UserRestrictionsNoPinMessages'},\n {flags: ['change_info'], text: 'UserRestrictionsChangeInfo', exceptionText: 'UserRestrictionsNoChangeInfo'}\n ];\n\n this.toggleWith = {\n 'send_messages': ['send_media', 'send_stickers', 'send_polls', 'embed_links']\n };\n\n const chat: Chat.chat | Chat.channel = appChatsManager.getChat(options.chatId);\n const defaultBannedRights = chat.default_banned_rights;\n const rights = options.participant ? appChatsManager.combineParticipantBannedRights(options.chatId, options.participant.banned_rights) : defaultBannedRights;\n \n const restrictionText: LangPackKey = options.participant ? 'UserRestrictionsDisabled' : 'EditCantEditPermissionsPublic';\n for(const info of this.v) {\n const mainFlag = info.flags[0];\n info.checkboxField = new CheckboxField({\n text: info.text,\n checked: appChatsManager.hasRights(options.chatId, mainFlag, rights),\n restriction: true,\n withRipple: true\n });\n\n if((\n options.participant && \n defaultBannedRights.pFlags[mainFlag as keyof typeof defaultBannedRights['pFlags']]\n ) || (\n (chat as Chat.channel).username &&\n (\n info.flags.includes('pin_messages') ||\n info.flags.includes('change_info')\n )\n )\n ) {\n info.checkboxField.input.disabled = true;\n \n /* options.listenerSetter.add(info.checkboxField.input)('change', (e) => {\n if(!e.isTrusted) {\n return;\n }\n\n cancelEvent(e);\n toast('This option is disabled for all members in Group Permissions.');\n info.checkboxField.checked = false;\n }); */\n\n attachClickEvent(info.checkboxField.label, (e) => {\n toast(I18n.format(restrictionText, true));\n }, {listenerSetter: options.listenerSetter});\n }\n\n if(this.toggleWith[mainFlag]) {\n options.listenerSetter.add(info.checkboxField.input)('change', () => {\n if(!info.checkboxField.checked) {\n const other = this.v.filter(i => this.toggleWith[mainFlag].includes(i.flags[0]));\n other.forEach(info => {\n info.checkboxField.checked = false;\n });\n }\n });\n }\n\n options.appendTo.append(info.checkboxField.label);\n }\n }\n\n public takeOut() {\n const rights: ChatBannedRights = {\n _: 'chatBannedRights',\n until_date: 0x7FFFFFFF,\n pFlags: {}\n };\n\n for(const info of this.v) {\n const banned = !info.checkboxField.checked;\n if(banned) {\n info.flags.forEach(flag => {\n // @ts-ignore\n rights.pFlags[flag] = true;\n });\n }\n }\n\n return rights;\n }\n}\n\nexport default class AppGroupPermissionsTab extends SliderSuperTabEventable {\n public chatId: ChatId;\n\n protected async init() {\n this.container.classList.add('edit-peer-container', 'group-permissions-container');\n this.setTitle('ChannelPermissions');\n\n let chatPermissions: ChatPermissions;\n {\n const section = new SettingSection({\n name: 'ChannelPermissionsHeader',\n });\n\n chatPermissions = new ChatPermissions({\n chatId: this.chatId,\n listenerSetter: this.listenerSetter,\n appendTo: section.content,\n });\n\n this.eventListener.addEventListener('destroy', () => {\n appChatsManager.editChatDefaultBannedRights(this.chatId, chatPermissions.takeOut());\n }, {once: true});\n\n this.scrollable.append(section.container);\n }\n \n {\n const section = new SettingSection({\n name: 'PrivacyExceptions'\n });\n\n const addExceptionRow = new Row({\n titleLangKey: 'ChannelAddException',\n subtitleLangKey: 'Loading',\n icon: 'adduser',\n clickable: () => {\n new PopupPickUser({\n peerTypes: ['channelParticipants'],\n onSelect: (peerId) => {\n setTimeout(() => {\n openPermissions(peerId);\n }, 0);\n },\n placeholder: 'ExceptionModal.Search.Placeholder',\n peerId: -this.chatId,\n });\n }\n });\n\n const openPermissions = async(peerId: PeerId) => {\n let participant: AppUserPermissionsTab['participant'];\n try {\n participant = await appProfileManager.getChannelParticipant(this.chatId, peerId) as any;\n } catch(err) {\n toast('User is no longer participant');\n return;\n }\n\n const tab = new AppUserPermissionsTab(this.slider);\n tab.participant = participant;\n tab.chatId = this.chatId;\n tab.userId = peerId;\n tab.open();\n };\n\n section.content.append(addExceptionRow.container);\n\n /* const removedUsersRow = new Row({\n titleLangKey: 'ChannelBlockedUsers',\n subtitleLangKey: 'NoBlockedUsers',\n icon: 'deleteuser',\n clickable: true\n });\n\n section.content.append(removedUsersRow.container); */\n\n const c = section.generateContentElement();\n c.classList.add('chatlist-container');\n \n const list = appDialogsManager.createChatList({new: true});\n c.append(list);\n\n attachClickEvent(list, (e) => {\n const target = findUpTag(e.target, 'LI');\n if(!target) return;\n\n const peerId = target.dataset.peerId.toPeerId();\n openPermissions(peerId);\n }, {listenerSetter: this.listenerSetter});\n\n const setSubtitle = (li: Element, participant: ChannelParticipant.channelParticipantBanned) => {\n const bannedRights = participant.banned_rights;//appChatsManager.combineParticipantBannedRights(this.chatId, participant.banned_rights);\n const defaultBannedRights = (appChatsManager.getChat(this.chatId) as Chat.channel).default_banned_rights;\n //const combinedRights = appChatsManager.combineParticipantBannedRights(this.chatId, bannedRights);\n\n const cantWhat: LangPackKey[] = []/* , canWhat: LangPackKey[] = [] */;\n chatPermissions.v.forEach(info => {\n const mainFlag = info.flags[0];\n // @ts-ignore\n if(bannedRights.pFlags[mainFlag] && !defaultBannedRights.pFlags[mainFlag]) {\n cantWhat.push(info.exceptionText);\n // @ts-ignore\n }/* else if(!combinedRights.pFlags[mainFlag]) {\n canWhat.push(info.exceptionText);\n } */\n });\n\n const el = li.querySelector('.user-last-message') as HTMLElement;\n\n if(cantWhat.length) {\n el.innerHTML = '';\n el.append(...join(cantWhat.map(t => i18n(t)), false));\n }/* else if(canWhat.length) {\n str = 'Can ' + canWhat.join(canWhat.length === 2 ? ' and ' : ', ');\n } */\n \n el.classList.toggle('hide', !cantWhat.length);\n };\n\n const add = (participant: ChannelParticipant.channelParticipantBanned, append: boolean) => {\n const {dom} = appDialogsManager.addDialogNew({\n dialog: appPeersManager.getPeerId(participant.peer),\n container: list,\n drawStatus: false,\n rippleEnabled: true,\n avatarSize: 48,\n append\n });\n\n setSubtitle(dom.listEl, participant);\n\n //dom.titleSpan.innerHTML = 'Chinaza Akachi';\n //dom.lastMessageSpan.innerHTML = 'Can Add Users and Pin Messages';\n };\n\n this.listenerSetter.add(rootScope)('updateChannelParticipant', (update: Update.updateChannelParticipant) => {\n const needAdd = update.new_participant?._ === 'channelParticipantBanned' && !update.new_participant.banned_rights.pFlags.view_messages;\n const li = list.querySelector(`[data-peer-id=\"${update.user_id}\"]`);\n if(needAdd) {\n if(!li) {\n add(update.new_participant as ChannelParticipant.channelParticipantBanned, false);\n } else {\n setSubtitle(li, update.new_participant as ChannelParticipant.channelParticipantBanned);\n }\n\n if(update.prev_participant?._ !== 'channelParticipantBanned') {\n ++exceptionsCount;\n }\n } else {\n if(li) {\n li.remove();\n }\n\n if(update.prev_participant?._ === 'channelParticipantBanned') {\n --exceptionsCount;\n }\n }\n\n setLength();\n });\n\n const setLength = () => {\n replaceContent(addExceptionRow.subtitle, i18n(exceptionsCount ? 'Permissions.ExceptionsCount' : 'Permissions.NoExceptions', [exceptionsCount]));\n };\n\n let exceptionsCount = 0;\n let loader: ScrollableLoader;\n const setLoader = () => {\n const LOAD_COUNT = 50;\n loader = new ScrollableLoader({\n scrollable: this.scrollable,\n getPromise: () => {\n return appProfileManager.getChannelParticipants(this.chatId, {_: 'channelParticipantsBanned', q: ''}, LOAD_COUNT, list.childElementCount).then(res => {\n for(const participant of res.participants) {\n add(participant as ChannelParticipant.channelParticipantBanned, true);\n }\n \n exceptionsCount = res.count;\n setLength();\n \n return res.participants.length < LOAD_COUNT || res.count === list.childElementCount;\n });\n }\n });\n\n return loader.load();\n };\n\n this.scrollable.append(section.container);\n\n if(appChatsManager.isChannel(this.chatId)) {\n await setLoader();\n } else {\n setLength();\n \n this.listenerSetter.add(rootScope)('dialog_migrate', ({migrateFrom, migrateTo}) => {\n if(this.chatId === migrateFrom) {\n this.chatId = migrateTo;\n setLoader();\n }\n });\n }\n }\n }\n\n onOpenAfterTimeout() {\n this.scrollable.onScroll();\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport appChatsManager from \"../../lib/appManagers/appChatsManager\";\nimport appMessagesManager from \"../../lib/appManagers/appMessagesManager\";\nimport appPeersManager, { PeerType } from \"../../lib/appManagers/appPeersManager\";\nimport { LangPackKey } from \"../../lib/langPack\";\nimport PeerTitle from \"../peerTitle\";\nimport PopupPeer, { PopupPeerButtonCallbackCheckboxes, PopupPeerOptions } from \"./peer\";\n\nexport default class PopupDeleteDialog {\n constructor(\n peerId: PeerId, \n // actionType: 'leave' | 'delete', \n peerType: PeerType = appPeersManager.getDialogType(peerId), \n onSelect?: (promise: Promise<any>) => void\n ) {\n const peerTitleElement = new PeerTitle({peerId}).element;\n\n /* const callbackFlush = (checked: PopupPeerButtonCallbackCheckboxes) => {\n const promise = appMessagesManager.flushHistory(peerId, checkboxes ? !checked[checkboxes[0].text] : undefined);\n onSelect && onSelect(promise);\n }; */\n\n const callbackLeave = (checked: PopupPeerButtonCallbackCheckboxes, flush = checkboxes && !!checked.size) => {\n let promise = appChatsManager.leave(peerId.toChatId());\n \n if(flush) {\n promise = promise.finally(() => {\n return appMessagesManager.flushHistory(peerId);\n }) as any;\n }\n \n onSelect && onSelect(promise);\n };\n\n const callbackDelete = (checked: PopupPeerButtonCallbackCheckboxes) => {\n let promise: Promise<any>;\n\n if(peerId.isUser()) {\n promise = appMessagesManager.flushHistory(peerId, false, checkboxes ? !!checked.size : undefined);\n } else {\n if(checked.size) {\n promise = appChatsManager.delete(peerId.toChatId());\n } else {\n return callbackLeave(checked);\n }\n }\n \n onSelect && onSelect(promise);\n };\n\n let title: LangPackKey, description: LangPackKey, descriptionArgs: any[], buttons: PopupPeerOptions['buttons'], checkboxes: PopupPeerOptions['checkboxes'];\n switch(peerType) {\n case 'channel': {\n if(/* actionType === 'delete' && */appChatsManager.hasRights(peerId.toChatId(), 'delete_chat')) {\n appChatsManager.deleteChannel\n title = 'ChannelDeleteMenu';\n description = 'AreYouSureDeleteAndExitChannel';\n buttons = [{\n langKey: 'ChannelDeleteMenu',\n isDanger: true,\n callback: callbackDelete\n }];\n\n checkboxes = [{\n text: 'DeleteChannelForAll'\n }];\n } else {\n title = 'LeaveChannelMenu';\n description = 'ChannelLeaveAlertWithName';\n descriptionArgs = [peerTitleElement];\n buttons = [{\n langKey: 'LeaveChannel',\n isDanger: true,\n callback: callbackLeave\n }];\n }\n\n break;\n }\n\n /* case 'megagroup': {\n title = 'Leave Group?';\n description = `Are you sure you want to leave this group?`;\n buttons = [{\n text: 'LEAVE ' + peerTitleElement,\n isDanger: true,\n callback: callbackLeave\n }];\n\n break;\n } */\n\n case 'chat': {\n title = 'DeleteChatUser';\n description = 'AreYouSureDeleteThisChatWithUser';\n descriptionArgs = [peerTitleElement];\n\n buttons = [{\n langKey: 'DeleteChatUser',\n isDanger: true,\n callback: callbackDelete\n }];\n\n checkboxes = [{\n text: 'DeleteMessagesOptionAlso',\n textArgs: [\n new PeerTitle({peerId}).element\n ]\n }];\n\n break;\n }\n\n case 'saved': {\n title = 'DeleteChatUser';\n description = 'AreYouSureDeleteThisChatSavedMessages';\n buttons = [{\n langKey: 'DeleteChatUser',\n isDanger: true,\n callback: callbackDelete\n }];\n\n break;\n }\n\n case 'megagroup':\n case 'group': {\n if(/* actionType === 'delete' && */appChatsManager.hasRights(peerId.toChatId(), 'delete_chat')) {\n title = 'DeleteMegaMenu';\n description = 'AreYouSureDeleteAndExit';\n buttons = [{\n langKey: 'DeleteMegaMenu',\n isDanger: true,\n callback: callbackDelete\n }];\n\n checkboxes = [{\n text: 'DeleteChat.DeleteGroupForAll'\n }];\n } else {\n title = 'LeaveMegaMenu';\n description = 'AreYouSureDeleteAndExitName';\n descriptionArgs = [peerTitleElement];\n buttons = [{\n langKey: 'DeleteChatUser',\n isDanger: true,\n callback: (checkboxes) => callbackLeave(checkboxes, true)\n }];\n }\n\n break;\n }\n }\n\n new PopupPeer('popup-delete-chat', {\n peerId,\n titleLangKey: title,\n descriptionLangKey: description,\n descriptionLangArgs: descriptionArgs,\n buttons,\n checkboxes\n }).show();\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport debounce from \"../../../helpers/schedulers/debounce\";\nimport appChatsManager from \"../../../lib/appManagers/appChatsManager\";\nimport appProfileManager from \"../../../lib/appManagers/appProfileManager\";\nimport appReactionsManager from \"../../../lib/appManagers/appReactionsManager\";\nimport CheckboxField from \"../../checkboxField\";\nimport Row from \"../../row\";\nimport { SettingSection } from \"../../sidebarLeft\";\nimport { SliderSuperTabEventable } from \"../../sliderTab\";\nimport { wrapStickerToRow } from \"../../wrappers\";\n\nexport default class AppChatReactionsTab extends SliderSuperTabEventable {\n public chatId: ChatId;\n\n protected async init() {\n this.setTitle('Reactions');\n\n const availableReactions = await appReactionsManager.getActiveAvailableReactions();\n const chatFull = await appProfileManager.getChatFull(this.chatId);\n let originalReactions = chatFull.available_reactions ?? [];\n const enabledReactions = new Set(originalReactions);\n\n const toggleSection = new SettingSection({\n caption: appChatsManager.isBroadcast(this.chatId) ? 'EnableReactionsChannelInfo' : 'EnableReactionsGroupInfo'\n });\n\n const toggleCheckboxField = new CheckboxField({toggle: true, checked: !!enabledReactions.size});\n const toggleRow = new Row({\n checkboxField: toggleCheckboxField,\n titleLangKey: 'EnableReactions'\n });\n\n toggleSection.content.append(toggleRow.container);\n\n const reactionsSection = new SettingSection({\n name: 'AvailableReactions'\n });\n\n const checkboxFields = availableReactions.map(availableReaction => {\n const checkboxField = new CheckboxField({\n toggle: true, \n checked: enabledReactions.has(availableReaction.reaction)\n });\n\n this.listenerSetter.add(checkboxField.input)('change', () => {\n if(checkboxField.checked) {\n enabledReactions.add(availableReaction.reaction);\n\n if(!toggleCheckboxField.checked) {\n toggleCheckboxField.setValueSilently(true);\n }\n } else {\n enabledReactions.delete(availableReaction.reaction);\n\n if(!enabledReactions.size && toggleCheckboxField.checked) {\n toggleCheckboxField.setValueSilently(false);\n }\n }\n\n saveReactionsDebounced();\n });\n\n const row = new Row({\n checkboxField,\n title: availableReaction.title,\n havePadding: true\n });\n\n wrapStickerToRow({\n row,\n doc: availableReaction.static_icon,\n size: 'small'\n });\n\n reactionsSection.content.append(row.container);\n\n return checkboxField;\n });\n\n this.listenerSetter.add(toggleRow.checkboxField.input)('change', () => {\n if(!toggleCheckboxField.checked) {\n checkboxFields.forEach(checkboxField => checkboxField.checked = false);\n saveReactionsDebounced();\n } else if(checkboxFields.every(checkboxField => !checkboxField.checked)) {\n checkboxFields.forEach(checkboxField => checkboxField.checked = true);\n saveReactionsDebounced();\n }\n });\n\n const saveReactions = () => {\n const newReactions = Array.from(enabledReactions);\n if([...newReactions].sort().join() === [...originalReactions].sort().join()) {\n return;\n }\n\n const chatFull = appProfileManager.getCachedFullChat(this.chatId);\n if(chatFull) {\n chatFull.available_reactions = newReactions;\n }\n \n appChatsManager.setChatAvailableReactions(this.chatId, newReactions);\n originalReactions = newReactions;\n };\n\n const saveReactionsDebounced = debounce(saveReactions, 3000, false, true);\n\n this.eventListener.addEventListener('destroy', saveReactions, {once: true});\n\n this.scrollable.append(toggleSection.container, reactionsSection.container);\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTab } from \"../../slider\"\r\nimport InputField from \"../../inputField\";\r\nimport EditPeer from \"../../editPeer\";\r\nimport { SettingSection } from \"../../sidebarLeft\";\r\nimport Row from \"../../row\";\r\nimport Button from \"../../button\";\r\nimport appChatsManager, { ChatRights } from \"../../../lib/appManagers/appChatsManager\";\r\nimport appProfileManager from \"../../../lib/appManagers/appProfileManager\";\r\nimport { Chat, ChatFull } from \"../../../layer\";\r\nimport AppChatTypeTab from \"./chatType\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport AppGroupPermissionsTab from \"./groupPermissions\";\r\nimport { i18n, LangPackKey } from \"../../../lib/langPack\";\r\nimport PopupDeleteDialog from \"../../popups/deleteDialog\";\r\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\r\nimport toggleDisability from \"../../../helpers/dom/toggleDisability\";\r\nimport CheckboxField from \"../../checkboxField\";\r\nimport appReactionsManager from \"../../../lib/appManagers/appReactionsManager\";\r\nimport AppChatReactionsTab from \"./chatReactions\";\r\n\r\nexport default class AppEditChatTab extends SliderSuperTab {\r\n private chatNameInputField: InputField;\r\n private descriptionInputField: InputField;\r\n private editPeer: EditPeer;\r\n private tempId: number;\r\n public chatId: ChatId;\r\n\r\n protected async _init() {\r\n // * cleanup prev\r\n this.listenerSetter.removeAll();\r\n this.scrollable.container.innerHTML = '';\r\n this.tempId ??= 0;\r\n const tempId = ++this.tempId;\r\n\r\n this.container.classList.add('edit-peer-container', 'edit-group-container');\r\n this.setTitle('Edit');\r\n \r\n let chatFull = await appProfileManager.getChatFull(this.chatId, true);\r\n\r\n const chat: Chat.chat | Chat.channel = appChatsManager.getChat(this.chatId);\r\n const isBroadcast = appChatsManager.isBroadcast(this.chatId);\r\n const isChannel = appChatsManager.isChannel(this.chatId);\r\n\r\n const chatUpdateListeners: (() => void)[] = [];\r\n const addChatUpdateListener = (callback: () => void) => {\r\n chatUpdateListeners.push(callback);\r\n };\r\n\r\n this.listenerSetter.add(rootScope)('chat_update', (chatId) => {\r\n if(this.chatId === chatId) {\r\n chatUpdateListeners.forEach(callback => callback());\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('chat_full_update', (chatId) => {\r\n if(this.chatId === chatId) {\r\n chatFull = appProfileManager.getCachedFullChat(chatId) || chatFull;\r\n }\r\n });\r\n\r\n const peerId = this.chatId.toPeerId(true);\r\n const canChangeType = appChatsManager.hasRights(this.chatId, 'change_type');\r\n const canChangePermissions = appChatsManager.hasRights(this.chatId, 'change_permissions');\r\n\r\n {\r\n const section = new SettingSection({noDelimiter: true});\r\n const inputFields: InputField[] = [];\r\n\r\n const inputWrapper = document.createElement('div');\r\n inputWrapper.classList.add('input-wrapper');\r\n \r\n this.chatNameInputField = new InputField({\r\n label: isBroadcast ? 'EnterChannelName' : 'CreateGroup.NameHolder',\r\n name: 'chat-name',\r\n maxLength: 255,\r\n required: true\r\n });\r\n this.descriptionInputField = new InputField({\r\n label: 'DescriptionPlaceholder',\r\n name: 'chat-description',\r\n maxLength: 255\r\n });\r\n \r\n this.chatNameInputField.setOriginalValue(chat.title);\r\n this.descriptionInputField.setOriginalValue(chatFull.about);\r\n\r\n inputWrapper.append(this.chatNameInputField.container, this.descriptionInputField.container);\r\n \r\n inputFields.push(this.chatNameInputField, this.descriptionInputField);\r\n\r\n this.editPeer = new EditPeer({\r\n peerId,\r\n inputFields,\r\n listenerSetter: this.listenerSetter\r\n });\r\n this.content.append(this.editPeer.nextBtn);\r\n\r\n section.content.append(this.editPeer.avatarEdit.container, inputWrapper);\r\n \r\n if(canChangeType) {\r\n const chatTypeRow = new Row({\r\n titleLangKey: isBroadcast ? 'ChannelType' : 'GroupType',\r\n clickable: () => {\r\n const tab = new AppChatTypeTab(this.slider);\r\n tab.chatId = this.chatId;\r\n tab.chatFull = chatFull;\r\n tab.open();\r\n\r\n this.listenerSetter.add(tab.eventListener)('destroy', setChatTypeSubtitle);\r\n },\r\n icon: 'lock'\r\n });\r\n\r\n const setChatTypeSubtitle = () => {\r\n chatTypeRow.subtitle.textContent = '';\r\n\r\n let key: LangPackKey;\r\n if(isBroadcast) {\r\n key = (chat as Chat.channel).username ? 'TypePublic' : 'TypePrivate';\r\n } else {\r\n key = (chat as Chat.channel).username ? 'TypePublicGroup' : 'TypePrivateGroup';\r\n }\r\n\r\n chatTypeRow.subtitle.append(i18n(key));\r\n };\r\n\r\n setChatTypeSubtitle();\r\n section.content.append(chatTypeRow.container);\r\n }\r\n\r\n if(canChangeType || canChangePermissions) {\r\n const reactionsRow = new Row({\r\n titleLangKey: 'Reactions',\r\n icon: 'reactions',\r\n clickable: () => {\r\n const tab = new AppChatReactionsTab(this.slider);\r\n tab.chatId = this.chatId;\r\n tab.open().then(() => {\r\n if(this.tempId !== tempId) {\r\n return;\r\n }\r\n \r\n this.listenerSetter.add(tab.eventListener)('destroy', setReactionsLength);\r\n });\r\n }\r\n });\r\n\r\n const availableReactions = await appReactionsManager.getAvailableReactions();\r\n const availableReactionsLength = availableReactions.filter(availableReaction => !availableReaction.pFlags.inactive).length;\r\n const setReactionsLength = () => {\r\n const reactions = chatFull.available_reactions ?? [];\r\n reactionsRow.subtitle.innerHTML = reactions.length + '/' + availableReactionsLength;\r\n };\r\n\r\n setReactionsLength();\r\n\r\n section.content.append(reactionsRow.container);\r\n }\r\n\r\n if(canChangePermissions && !isBroadcast) {\r\n const flags = [\r\n 'send_messages',\r\n 'send_media',\r\n 'send_stickers',\r\n 'send_polls',\r\n 'embed_links',\r\n 'invite_users',\r\n 'pin_messages',\r\n 'change_info'\r\n ] as ChatRights[];\r\n\r\n const permissionsRow = new Row({\r\n titleLangKey: 'ChannelPermissions',\r\n clickable: () => {\r\n const tab = new AppGroupPermissionsTab(this.slider);\r\n tab.chatId = this.chatId;\r\n tab.open();\r\n },\r\n icon: 'permissions',\r\n });\r\n\r\n const setPermissionsLength = () => {\r\n permissionsRow.subtitle.innerHTML = flags.reduce((acc, f) => acc + +appChatsManager.hasRights(this.chatId, f, chat.default_banned_rights), 0) + '/' + flags.length;\r\n };\r\n\r\n setPermissionsLength(); \r\n section.content.append(permissionsRow.container);\r\n\r\n this.listenerSetter.add(rootScope)('chat_update', (chatId) => {\r\n if(this.chatId === chatId) {\r\n setPermissionsLength();\r\n }\r\n });\r\n }\r\n\r\n /* const administratorsRow = new Row({\r\n titleLangKey: 'PeerInfo.Administrators',\r\n subtitle: '' + ((chatFull as ChatFull.channelFull).admins_count || 1),\r\n icon: 'admin',\r\n clickable: true\r\n });\r\n\r\n section.content.append(administratorsRow.container); */\r\n\r\n this.scrollable.append(section.container);\r\n\r\n attachClickEvent(this.editPeer.nextBtn, () => {\r\n this.editPeer.nextBtn.disabled = true;\r\n \r\n let promises: Promise<any>[] = [];\r\n\r\n const id = this.chatId;\r\n if(this.chatNameInputField.isValidToChange()) {\r\n promises.push(appChatsManager.editTitle(id, this.chatNameInputField.value));\r\n }\r\n\r\n if(this.descriptionInputField.isValidToChange()) {\r\n promises.push(appChatsManager.editAbout(id, this.descriptionInputField.value));\r\n }\r\n\r\n if(this.editPeer.uploadAvatar) {\r\n promises.push(this.editPeer.uploadAvatar().then(inputFile => {\r\n return appChatsManager.editPhoto(id, inputFile);\r\n }));\r\n }\r\n \r\n Promise.race(promises).finally(() => {\r\n this.editPeer.nextBtn.removeAttribute('disabled');\r\n this.close();\r\n });\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n \r\n /* if(appChatsManager.hasRights(-this.peerId, 'change_info')) {\r\n const discussionRow = new Row({\r\n titleLangKey: 'PeerInfo.Discussion',\r\n subtitleLangKey: 'PeerInfo.Discussion.Add',\r\n clickable: true,\r\n icon: 'message'\r\n });\r\n\r\n section.content.append(discussionRow.container);\r\n }\r\n\r\n const administratorsRow = new Row({\r\n titleLangKey: 'PeerInfo.Administrators',\r\n subtitle: '' + chatFull.admins_count,\r\n icon: 'admin',\r\n clickable: true\r\n });\r\n\r\n section.content.append(administratorsRow.container); */\r\n\r\n if(isBroadcast && appChatsManager.hasRights(this.chatId, 'change_info')) {\r\n const signMessagesCheckboxField = new CheckboxField({\r\n text: 'PeerInfo.SignMessages',\r\n checked: !!(chat as Chat.channel).pFlags.signatures,\r\n withRipple: true\r\n });\r\n\r\n this.listenerSetter.add(signMessagesCheckboxField.input)('change', () => {\r\n const toggle = signMessagesCheckboxField.toggleDisability(true);\r\n appChatsManager.toggleSignatures(this.chatId, signMessagesCheckboxField.checked).then(() => {\r\n toggle();\r\n });\r\n });\r\n\r\n addChatUpdateListener(() => {\r\n signMessagesCheckboxField.setValueSilently(!!(chat as Chat.channel).pFlags.signatures);\r\n });\r\n\r\n section.content.append(signMessagesCheckboxField.label);\r\n }\r\n }\r\n\r\n if(!isBroadcast) {\r\n const section = new SettingSection({\r\n\r\n });\r\n\r\n /* const membersRow = new Row({\r\n titleLangKey: isBroadcast ? 'PeerInfo.Subscribers' : 'GroupMembers',\r\n icon: 'newgroup',\r\n clickable: true\r\n });\r\n\r\n membersRow.subtitle.append(i18n('Subscribers', [numberThousandSplitter(335356)]));\r\n\r\n section.content.append(membersRow.container); */\r\n\r\n if(!isBroadcast && canChangeType) {\r\n const showChatHistoryCheckboxField = new CheckboxField({\r\n text: 'ChatHistory',\r\n withRipple: true\r\n });\r\n\r\n this.listenerSetter.add(showChatHistoryCheckboxField.input)('change', () => {\r\n const toggle = showChatHistoryCheckboxField.toggleDisability(true);\r\n appChatsManager.togglePreHistoryHidden(this.chatId, !showChatHistoryCheckboxField.checked).then(() => {\r\n toggle();\r\n });\r\n });\r\n\r\n // ! it won't be updated because chatFull will be old\r\n const onChatUpdate = () => {\r\n showChatHistoryCheckboxField.setValueSilently(isChannel && !(chatFull as ChatFull.channelFull).pFlags.hidden_prehistory);\r\n };\r\n\r\n onChatUpdate();\r\n addChatUpdateListener(onChatUpdate);\r\n \r\n section.content.append(showChatHistoryCheckboxField.label);\r\n }\r\n\r\n if(section.content.childElementCount) {\r\n this.scrollable.append(section.container);\r\n }\r\n }\r\n\r\n if(appChatsManager.hasRights(this.chatId, 'delete_chat')) {\r\n const section = new SettingSection({});\r\n\r\n const btnDelete = Button('btn-primary btn-transparent danger', {icon: 'delete', text: isBroadcast ? 'PeerInfo.DeleteChannel' : 'DeleteAndExitButton'});\r\n\r\n attachClickEvent(btnDelete, () => {\r\n new PopupDeleteDialog(peerId/* , 'delete' */, undefined, (promise) => {\r\n const toggle = toggleDisability([btnDelete], true);\r\n promise.then(() => {\r\n this.close();\r\n }, () => {\r\n toggle();\r\n });\r\n });\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n section.content.append(btnDelete);\r\n\r\n this.scrollable.append(section.container);\r\n }\r\n\r\n if(!isChannel) {\r\n // ! this one will fire earlier than tab's closeAfterTimeout (destroy) event and listeners will be erased, so destroy won't fire\r\n this.listenerSetter.add(rootScope)('dialog_migrate', ({migrateFrom, migrateTo}) => {\r\n if(peerId === migrateFrom) {\r\n this.chatId = migrateTo.toChatId();\r\n this._init();\r\n }\r\n });\r\n }\r\n }\r\n\r\n protected init() {\r\n return this._init();\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTab } from \"../../slider\"\r\nimport InputField from \"../../inputField\";\r\nimport EditPeer from \"../../editPeer\";\r\nimport { SettingSection } from \"../../sidebarLeft\";\r\nimport Row from \"../../row\";\r\nimport CheckboxField from \"../../checkboxField\";\r\nimport Button from \"../../button\";\r\nimport appUsersManager from \"../../../lib/appManagers/appUsersManager\";\r\nimport appNotificationsManager from \"../../../lib/appManagers/appNotificationsManager\";\r\nimport PeerTitle from \"../../peerTitle\";\r\nimport appMessagesManager from \"../../../lib/appManagers/appMessagesManager\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport appPeersManager from \"../../../lib/appManagers/appPeersManager\";\r\nimport PopupPeer from \"../../popups/peer\";\r\nimport { addCancelButton } from \"../../popups\";\r\nimport { i18n } from \"../../../lib/langPack\";\r\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\r\nimport toggleDisability from \"../../../helpers/dom/toggleDisability\";\r\n\r\nexport default class AppEditContactTab extends SliderSuperTab {\r\n private nameInputField: InputField;\r\n private lastNameInputField: InputField;\r\n private editPeer: EditPeer;\r\n public peerId: PeerId;\r\n\r\n protected init() {\r\n this.container.classList.add('edit-peer-container', 'edit-contact-container');\r\n const isNew = !appUsersManager.isContact(this.peerId.toUserId());\r\n this.setTitle(isNew ? 'AddContactTitle' : 'Edit');\r\n\r\n {\r\n const section = new SettingSection({noDelimiter: true});\r\n const inputFields: InputField[] = [];\r\n\r\n const inputWrapper = document.createElement('div');\r\n inputWrapper.classList.add('input-wrapper');\r\n \r\n this.nameInputField = new InputField({\r\n label: 'FirstName',\r\n name: 'contact-name',\r\n maxLength: 70,\r\n required: true\r\n });\r\n this.lastNameInputField = new InputField({\r\n label: 'LastName',\r\n name: 'contact-lastname',\r\n maxLength: 70\r\n });\r\n\r\n if(this.peerId) {\r\n const user = appUsersManager.getUser(this.peerId);\r\n\r\n if(isNew) {\r\n this.nameInputField.setDraftValue(user.first_name);\r\n this.lastNameInputField.setDraftValue(user.last_name);\r\n } else {\r\n this.nameInputField.setOriginalValue(user.first_name);\r\n this.lastNameInputField.setOriginalValue(user.last_name);\r\n }\r\n }\r\n \r\n inputWrapper.append(this.nameInputField.container, this.lastNameInputField.container);\r\n inputFields.push(this.nameInputField, this.lastNameInputField);\r\n\r\n this.editPeer = new EditPeer({\r\n peerId: this.peerId,\r\n inputFields,\r\n listenerSetter: this.listenerSetter,\r\n doNotEditAvatar: true\r\n });\r\n this.content.append(this.editPeer.nextBtn);\r\n\r\n if(this.peerId) {\r\n const div = document.createElement('div');\r\n div.classList.add('avatar-edit');\r\n div.append(this.editPeer.avatarElem);\r\n \r\n const notificationsCheckboxField = new CheckboxField({\r\n text: 'Notifications'\r\n });\r\n \r\n notificationsCheckboxField.input.addEventListener('change', (e) => {\r\n if(!e.isTrusted) {\r\n return;\r\n }\r\n \r\n appMessagesManager.togglePeerMute(this.peerId);\r\n });\r\n \r\n this.listenerSetter.add(rootScope)('notify_settings', (update) => {\r\n if(update.peer._ !== 'notifyPeer') return;\r\n const peerId = appPeersManager.getPeerId(update.peer.peer);\r\n if(this.peerId === peerId) {\r\n const enabled = !appNotificationsManager.isMuted(update.notify_settings);\r\n if(enabled !== notificationsCheckboxField.checked) {\r\n notificationsCheckboxField.checked = enabled;\r\n }\r\n }\r\n });\r\n \r\n const profileNameDiv = document.createElement('div');\r\n profileNameDiv.classList.add('profile-name');\r\n profileNameDiv.append(new PeerTitle({\r\n peerId: this.peerId\r\n }).element);\r\n //profileNameDiv.innerHTML = 'Karen Stanford';\r\n \r\n const profileSubtitleDiv = document.createElement('div');\r\n profileSubtitleDiv.classList.add('profile-subtitle');\r\n profileSubtitleDiv.append(i18n('EditContact.OriginalName'));\r\n\r\n section.content.append(div, profileNameDiv, profileSubtitleDiv, inputWrapper);\r\n\r\n if(!isNew) {\r\n const notificationsRow = new Row({\r\n checkboxField: notificationsCheckboxField\r\n });\r\n \r\n const enabled = !appNotificationsManager.isPeerLocalMuted(this.peerId, false);\r\n notificationsCheckboxField.checked = enabled;\r\n\r\n section.content.append(notificationsRow.container);\r\n } else {\r\n const user = appUsersManager.getUser(this.peerId);\r\n\r\n const phoneRow = new Row({\r\n icon: 'phone',\r\n titleLangKey: user.phone ? undefined : 'MobileHidden',\r\n title: user.phone ? appUsersManager.formatUserPhone(user.phone) : undefined,\r\n subtitleLangKey: user.phone ? 'Phone' : 'MobileHiddenExceptionInfo',\r\n subtitleLangArgs: user.phone ? undefined : [new PeerTitle({peerId: this.peerId}).element]\r\n });\r\n\r\n section.content.append(phoneRow.container);\r\n }\r\n } else {\r\n section.content.append(inputWrapper);\r\n }\r\n\r\n this.scrollable.append(section.container);\r\n\r\n attachClickEvent(this.editPeer.nextBtn, () => {\r\n this.editPeer.nextBtn.disabled = true;\r\n\r\n appUsersManager.addContact(this.peerId, this.nameInputField.value, this.lastNameInputField.value, appUsersManager.getUser(this.peerId).phone)\r\n .finally(() => {\r\n this.editPeer.nextBtn.removeAttribute('disabled');\r\n this.close();\r\n });\r\n }, {listenerSetter: this.listenerSetter});\r\n }\r\n\r\n if(!isNew) {\r\n const section = new SettingSection({\r\n \r\n });\r\n\r\n const btnDelete = Button('btn-primary btn-transparent danger', {icon: 'delete', text: 'PeerInfo.DeleteContact'});\r\n\r\n attachClickEvent(btnDelete, () => {\r\n new PopupPeer('popup-delete-contact', {\r\n peerId: this.peerId,\r\n titleLangKey: 'DeleteContact',\r\n descriptionLangKey: 'AreYouSureDeleteContact',\r\n buttons: addCancelButton([{\r\n langKey: 'Delete',\r\n callback: () => {\r\n const toggle = toggleDisability([btnDelete], true);\r\n\r\n appUsersManager.deleteContacts([this.peerId]).then(() => {\r\n this.close();\r\n }, () => {\r\n toggle();\r\n });\r\n },\r\n isDanger: true\r\n }])\r\n }).show();\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n section.content.append(btnDelete);\r\n\r\n this.scrollable.append(section.container);\r\n }\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTab } from \"../../slider\";\r\nimport AppSelectPeers from \"../../appSelectPeers\";\r\nimport { setButtonLoader } from \"../../misc\";\r\nimport { LangPackKey, _i18n } from \"../../../lib/langPack\";\r\nimport ButtonCorner from \"../../buttonCorner\";\r\n\r\nexport default class AppAddMembersTab extends SliderSuperTab {\r\n private nextBtn: HTMLButtonElement;\r\n private selector: AppSelectPeers;\r\n private peerType: 'channel' | 'chat' | 'privacy';\r\n private takeOut: (peerIds: PeerId[]) => Promise<any> | false | void;\r\n private skippable: boolean;\r\n\r\n protected init() {\r\n this.container.classList.add('add-members-container');\r\n this.nextBtn = ButtonCorner({icon: 'arrow_next'});\r\n this.content.append(this.nextBtn);\r\n this.scrollable.container.remove();\r\n \r\n this.nextBtn.addEventListener('click', () => {\r\n const peerIds = this.selector.getSelected().map(sel => sel.toPeerId());\r\n\r\n if(this.skippable) {\r\n this.takeOut(peerIds);\r\n this.close();\r\n } else {\r\n const promise = this.takeOut(peerIds);\r\n\r\n if(promise instanceof Promise) {\r\n this.attachToPromise(promise);\r\n } else if(promise === undefined) {\r\n this.close();\r\n }\r\n }\r\n });\r\n }\r\n\r\n public attachToPromise(promise: Promise<any>) {\r\n const removeLoader = setButtonLoader(this.nextBtn, 'arrow_next');\r\n\r\n promise.then(() => {\r\n this.close();\r\n }, () => {\r\n removeLoader();\r\n });\r\n }\r\n\r\n public open(options: {\r\n title: LangPackKey,\r\n placeholder: LangPackKey,\r\n type: AppAddMembersTab['peerType'], \r\n takeOut?: AppAddMembersTab['takeOut'],\r\n skippable: boolean,\r\n selectedPeerIds?: PeerId[]\r\n }) {\r\n const ret = super.open();\r\n\r\n this.setTitle(options.title);\r\n this.peerType = options.type;\r\n this.takeOut = options.takeOut;\r\n this.skippable = options.skippable;\r\n\r\n const isPrivacy = this.peerType === 'privacy';\r\n this.selector = new AppSelectPeers({\r\n appendTo: this.content, \r\n onChange: this.skippable ? null : (length) => {\r\n this.nextBtn.classList.toggle('is-visible', !!length);\r\n }, \r\n peerType: [isPrivacy ? 'dialogs' : 'contacts'],\r\n placeholder: options.placeholder,\r\n exceptSelf: isPrivacy,\r\n filterPeerTypeBy: isPrivacy ? ['isAnyGroup', 'isUser'] : undefined\r\n });\r\n\r\n if(options.selectedPeerIds) {\r\n this.selector.addInitial(options.selectedPeerIds);\r\n }\r\n\r\n this.nextBtn.classList.add('tgico-arrow_next');\r\n this.nextBtn.innerHTML = '';\r\n this.nextBtn.disabled = false;\r\n this.nextBtn.classList.toggle('is-visible', this.skippable);\r\n\r\n return ret;\r\n }\r\n}","import { IS_FIREFOX } from \"./userAgent\";\n\nconst IS_PARALLAX_SUPPORTED = !IS_FIREFOX && false;\n\nexport default IS_PARALLAX_SUPPORTED;\n","import { _i18n } from \"../lib/langPack\";\n\nexport default function generateFakeIcon(isScam?: boolean) {\n const span = document.createElement('span');\n span.classList.add('badge-fake');\n _i18n(span, isScam ? 'ScamMessage' : 'FakeMessage');\n return span;\n}","import { Chat, User } from \"../layer\";\nimport appPeersManager from \"../lib/appManagers/appPeersManager\";\nimport generateFakeIcon from \"./generateFakeIcon\";\nimport generateVerifiedIcon from \"./generateVerifiedIcon\";\n\nexport default function generateTitleIcons(peerId: PeerId) {\n const elements: Element[] = [];\n const peer = appPeersManager.getPeer(peerId);\n if(peer?.pFlags?.verified) {\n elements.push(generateVerifiedIcon());\n }\n\n if((peer as Chat.channel).pFlags.fake || (peer as User.user).pFlags.scam) {\n elements.push(generateFakeIcon((peer as User.user).pFlags.scam));\n }\n\n return elements;\n}\n","export default function generateVerifiedIcon() {\n const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n svg.setAttributeNS(null, 'viewBox', '0 0 24 24');\n svg.setAttributeNS(null, 'width', '24');\n svg.setAttributeNS(null, 'height', '24');\n svg.classList.add('verified-icon');\n\n const use = document.createElementNS('http://www.w3.org/2000/svg', 'use');\n use.setAttributeNS(null, 'href', '#verified-background');\n use.classList.add('verified-background');\n\n const use2 = document.createElementNS('http://www.w3.org/2000/svg', 'use');\n use2.setAttributeNS(null, 'href', '#verified-check');\n use2.classList.add('verified-check');\n\n svg.append(use, use2);\n\n return svg;\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport cancelEvent from \"../helpers/dom/cancelEvent\";\r\nimport { IS_TOUCH_SUPPORTED } from \"../environment/touchSupport\";\r\nimport rootScope from \"../lib/rootScope\";\r\nimport safeAssign from \"../helpers/object/safeAssign\";\r\n\r\nconst getEvent = (e: TouchEvent | MouseEvent) => {\r\n return (e as TouchEvent).touches ? (e as TouchEvent).touches[0] : e as MouseEvent;\r\n};\r\n\r\nconst attachGlobalListenerTo = window;\r\n\r\nlet RESET_GLOBAL = false;\r\nrootScope.addEventListener('context_menu_toggle', (visible) => {\r\n RESET_GLOBAL = visible;\r\n});\r\n\r\nexport type SwipeHandlerOptions = {\r\n element: SwipeHandler['element'],\r\n onSwipe: SwipeHandler['onSwipe'],\r\n verifyTouchTarget?: SwipeHandler['verifyTouchTarget'],\r\n onFirstSwipe?: SwipeHandler['onFirstSwipe'],\r\n onReset?: SwipeHandler['onReset'],\r\n cursor?: SwipeHandler['cursor'],\r\n cancelEvent?: SwipeHandler['cancelEvent'],\r\n listenerOptions?: SwipeHandler['listenerOptions']\r\n};\r\n\r\nexport default class SwipeHandler {\r\n private element: HTMLElement;\r\n private onSwipe: (xDiff: number, yDiff: number, e: TouchEvent | MouseEvent) => boolean | void;\r\n private verifyTouchTarget: (evt: TouchEvent | MouseEvent) => boolean;\r\n private onFirstSwipe: () => void;\r\n private onReset: () => void;\r\n private cursor: 'grabbing' | 'move' | 'row-resize' | 'col-resize' | 'nesw-resize' | 'nwse-resize' | 'ne-resize' | 'se-resize' | 'sw-resize' | 'nw-resize' | 'n-resize' | 'e-resize' | 's-resize' | 'w-resize' | '' = 'grabbing';\r\n private cancelEvent = true;\r\n private listenerOptions: boolean | AddEventListenerOptions = false;\r\n private setCursorTo: HTMLElement;\r\n\r\n private hadMove = false;\r\n private xDown: number = null;\r\n private yDown: number = null;\r\n\r\n constructor(options: SwipeHandlerOptions) {\r\n safeAssign(this, options);\r\n \r\n this.setCursorTo = this.element;\r\n\r\n this.setListeners();\r\n }\r\n\r\n public setListeners() {\r\n if(!IS_TOUCH_SUPPORTED) {\r\n this.element.addEventListener('mousedown', this.handleStart, this.listenerOptions);\r\n attachGlobalListenerTo.addEventListener('mouseup', this.reset);\r\n } else {\r\n this.element.addEventListener('touchstart', this.handleStart, this.listenerOptions);\r\n attachGlobalListenerTo.addEventListener('touchend', this.reset);\r\n }\r\n }\r\n\r\n public removeListeners() {\r\n if(!IS_TOUCH_SUPPORTED) {\r\n this.element.removeEventListener('mousedown', this.handleStart, this.listenerOptions);\r\n attachGlobalListenerTo.removeEventListener('mouseup', this.reset);\r\n } else {\r\n this.element.removeEventListener('touchstart', this.handleStart, this.listenerOptions);\r\n attachGlobalListenerTo.removeEventListener('touchend', this.reset);\r\n }\r\n }\r\n\r\n public setCursor(cursor: SwipeHandler['cursor']) {\r\n this.cursor = cursor;\r\n \r\n if(!IS_TOUCH_SUPPORTED && this.hadMove) {\r\n this.setCursorTo.style.setProperty('cursor', this.cursor, 'important');\r\n }\r\n }\r\n\r\n reset = (e?: Event) => {\r\n /* if(e) {\r\n cancelEvent(e);\r\n } */\r\n\r\n if(IS_TOUCH_SUPPORTED) {\r\n attachGlobalListenerTo.removeEventListener('touchmove', this.handleMove, {capture: true});\r\n } else {\r\n attachGlobalListenerTo.removeEventListener('mousemove', this.handleMove);\r\n this.setCursorTo.style.cursor = '';\r\n }\r\n\r\n if(this.onReset && this.hadMove) {\r\n this.onReset();\r\n }\r\n\r\n this.xDown = this.yDown = null;\r\n this.hadMove = false;\r\n };\r\n\r\n handleStart = (_e: TouchEvent | MouseEvent) => {\r\n const e = getEvent(_e);\r\n if(this.verifyTouchTarget && !this.verifyTouchTarget(_e)) {\r\n return this.reset();\r\n }\r\n\r\n this.xDown = e.clientX;\r\n this.yDown = e.clientY;\r\n\r\n if(IS_TOUCH_SUPPORTED) {\r\n attachGlobalListenerTo.addEventListener('touchmove', this.handleMove, {passive: false, capture: true});\r\n } else {\r\n attachGlobalListenerTo.addEventListener('mousemove', this.handleMove, false);\r\n }\r\n };\r\n\r\n handleMove = (_e: TouchEvent | MouseEvent) => {\r\n if(this.xDown === null || this.yDown === null || RESET_GLOBAL) {\r\n this.reset();\r\n return;\r\n }\r\n\r\n if(this.cancelEvent) {\r\n cancelEvent(_e);\r\n }\r\n\r\n const e = getEvent(_e);\r\n const xUp = e.clientX;\r\n const yUp = e.clientY;\r\n\r\n const xDiff = this.xDown - xUp;\r\n const yDiff = this.yDown - yUp;\r\n\r\n if(!this.hadMove) {\r\n if(!xDiff && !yDiff) {\r\n return;\r\n }\r\n\r\n this.hadMove = true;\r\n\r\n if(!IS_TOUCH_SUPPORTED) {\r\n this.setCursorTo.style.setProperty('cursor', this.cursor, 'important');\r\n }\r\n\r\n if(this.onFirstSwipe) {\r\n this.onFirstSwipe();\r\n }\r\n }\r\n\r\n // if(Math.abs(xDiff) > Math.abs(yDiff)) { /*most significant*/\r\n // if(xDiff > 0) { /* left swipe */ \r\n\r\n // } else { /* right swipe */\r\n\r\n // } \r\n // } else {\r\n // if(yDiff > 0) { /* up swipe */ \r\n \r\n // } else { /* down swipe */\r\n \r\n // }\r\n // }\r\n\r\n /* reset values */\r\n const onSwipeResult = this.onSwipe(xDiff, yDiff, _e);\r\n if(onSwipeResult !== undefined && onSwipeResult) {\r\n this.reset();\r\n }\r\n };\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport IS_PARALLAX_SUPPORTED from \"../environment/parallaxSupport\";\nimport { IS_TOUCH_SUPPORTED } from \"../environment/touchSupport\";\nimport findAndSplice from \"../helpers/array/findAndSplice\";\nimport cancelEvent from \"../helpers/dom/cancelEvent\";\nimport { attachClickEvent } from \"../helpers/dom/clickEvent\";\nimport filterChatPhotosMessages from \"../helpers/filterChatPhotosMessages\";\nimport ListenerSetter from \"../helpers/listenerSetter\";\nimport ListLoader from \"../helpers/listLoader\";\nimport { fastRaf } from \"../helpers/schedulers\";\nimport { Message, ChatFull, MessageAction, Photo } from \"../layer\";\nimport appAvatarsManager from \"../lib/appManagers/appAvatarsManager\";\nimport appMessagesManager, { AppMessagesManager } from \"../lib/appManagers/appMessagesManager\";\nimport appPeersManager from \"../lib/appManagers/appPeersManager\";\nimport appPhotosManager from \"../lib/appManagers/appPhotosManager\";\nimport appProfileManager from \"../lib/appManagers/appProfileManager\";\nimport rootScope from \"../lib/rootScope\";\nimport { openAvatarViewer } from \"./avatar\";\nimport Scrollable from \"./scrollable\";\nimport SwipeHandler from \"./swipeHandler\";\nimport { wrapPhoto } from \"./wrappers\";\n\nconst LOAD_NEAREST = 3;\n\nexport default class PeerProfileAvatars {\n private static BASE_CLASS = 'profile-avatars';\n private static SCALE = IS_PARALLAX_SUPPORTED ? 2 : 1;\n private static TRANSLATE_TEMPLATE = IS_PARALLAX_SUPPORTED ? `translate3d({x}, 0, -1px) scale(${PeerProfileAvatars.SCALE})` : 'translate({x}, 0)';\n public container: HTMLElement;\n public avatars: HTMLElement;\n public gradient: HTMLElement;\n public info: HTMLElement;\n public arrowPrevious: HTMLElement;\n public arrowNext: HTMLElement;\n private tabs: HTMLDivElement;\n private listLoader: ListLoader<Photo.photo['id'] | Message.messageService, Photo.photo['id'] | Message.messageService>;\n private peerId: PeerId;\n private intersectionObserver: IntersectionObserver;\n private loadCallbacks: Map<Element, () => void>;\n private listenerSetter: ListenerSetter;\n private swipeHandler: SwipeHandler;\n\n constructor(public scrollable: Scrollable) {\n this.container = document.createElement('div');\n this.container.classList.add(PeerProfileAvatars.BASE_CLASS + '-container');\n\n this.avatars = document.createElement('div');\n this.avatars.classList.add(PeerProfileAvatars.BASE_CLASS + '-avatars');\n\n this.gradient = document.createElement('div');\n this.gradient.classList.add(PeerProfileAvatars.BASE_CLASS + '-gradient');\n\n this.info = document.createElement('div');\n this.info.classList.add(PeerProfileAvatars.BASE_CLASS + '-info');\n\n this.tabs = document.createElement('div');\n this.tabs.classList.add(PeerProfileAvatars.BASE_CLASS + '-tabs');\n\n this.arrowPrevious = document.createElement('div');\n this.arrowPrevious.classList.add(PeerProfileAvatars.BASE_CLASS + '-arrow', 'tgico-avatarprevious');\n\n /* const previousIcon = document.createElement('i');\n previousIcon.classList.add(PeerProfileAvatars.BASE_CLASS + '-arrow-icon', 'tgico-previous');\n this.arrowBack.append(previousIcon); */\n \n this.arrowNext = document.createElement('div');\n this.arrowNext.classList.add(PeerProfileAvatars.BASE_CLASS + '-arrow', PeerProfileAvatars.BASE_CLASS + '-arrow-next', 'tgico-avatarnext');\n\n /* const nextIcon = document.createElement('i');\n nextIcon.classList.add(PeerProfileAvatars.BASE_CLASS + '-arrow-icon', 'tgico-next');\n this.arrowNext.append(nextIcon); */\n\n this.container.append(this.avatars, this.gradient, this.info, this.tabs, this.arrowPrevious, this.arrowNext);\n\n this.loadCallbacks = new Map();\n this.listenerSetter = new ListenerSetter();\n\n const checkScrollTop = () => {\n if(this.scrollable.scrollTop !== 0) {\n this.scrollable.scrollIntoViewNew({\n element: this.scrollable.container.firstElementChild as HTMLElement, \n position: 'start'\n });\n return false;\n }\n\n return true;\n };\n\n const SWITCH_ZONE = 1 / 3;\n let cancel = false;\n let freeze = false;\n attachClickEvent(this.container, async(_e) => {\n if(freeze) {\n cancelEvent(_e);\n return;\n }\n\n if(cancel) {\n cancel = false;\n return;\n }\n\n if(!checkScrollTop()) {\n return;\n }\n\n const rect = this.container.getBoundingClientRect();\n\n // const e = (_e as TouchEvent).touches ? (_e as TouchEvent).touches[0] : _e as MouseEvent;\n const e = _e;\n const x = e.pageX;\n\n const clickX = x - rect.left;\n if((!this.listLoader.previous.length && !this.listLoader.next.length) \n || (clickX > (rect.width * SWITCH_ZONE) && clickX < (rect.width - rect.width * SWITCH_ZONE))) {\n const peerId = this.peerId;\n\n const targets: {element: HTMLElement, item: Photo.photo['id'] | Message.messageService}[] = [];\n this.listLoader.previous.concat(this.listLoader.current, this.listLoader.next).forEach((item, idx) => {\n targets.push({\n element: /* null */this.avatars.children[idx] as HTMLElement,\n item\n });\n });\n\n const prevTargets = targets.slice(0, this.listLoader.previous.length);\n const nextTargets = targets.slice(this.listLoader.previous.length + 1);\n\n const target = this.avatars.children[this.listLoader.previous.length] as HTMLElement;\n freeze = true;\n openAvatarViewer(target, peerId, () => peerId === this.peerId, this.listLoader.current, prevTargets, nextTargets);\n freeze = false;\n } else {\n const centerX = rect.right - (rect.width / 2);\n const toRight = x > centerX;\n \n // this.avatars.classList.remove('no-transition');\n // fastRaf(() => {\n this.avatars.classList.add('no-transition');\n void this.avatars.offsetLeft; // reflow\n\n let distance: number;\n if(this.listLoader.index === 0 && !toRight) distance = this.listLoader.count - 1;\n else if(this.listLoader.index === (this.listLoader.count - 1) && toRight) distance = -(this.listLoader.count - 1);\n else distance = toRight ? 1 : -1;\n this.listLoader.go(distance);\n\n fastRaf(() => {\n this.avatars.classList.remove('no-transition');\n });\n // });\n }\n }, {listenerSetter: this.listenerSetter});\n\n const cancelNextClick = () => {\n cancel = true;\n document.body.addEventListener(IS_TOUCH_SUPPORTED ? 'touchend' : 'click', (e) => {\n cancel = false;\n }, {once: true});\n };\n\n let width = 0, x = 0, lastDiffX = 0, lastIndex = 0, minX = 0;\n const swipeHandler = this.swipeHandler = new SwipeHandler({\n element: this.avatars, \n onSwipe: (xDiff, yDiff) => {\n lastDiffX = xDiff;\n let lastX = x + xDiff * -PeerProfileAvatars.SCALE;\n if(lastX > 0) lastX = 0;\n else if(lastX < minX) lastX = minX;\n\n this.avatars.style.transform = PeerProfileAvatars.TRANSLATE_TEMPLATE.replace('{x}', lastX + 'px');\n //console.log(xDiff, yDiff);\n return false;\n }, \n verifyTouchTarget: (e) => {\n if(!checkScrollTop()) {\n cancelNextClick();\n cancelEvent(e);\n return false;\n } else if(this.container.classList.contains('is-single') || freeze) {\n return false;\n }\n\n return true;\n }, \n onFirstSwipe: () => {\n const rect = this.avatars.getBoundingClientRect();\n width = rect.width;\n minX = -width * (this.tabs.childElementCount - 1);\n\n /* lastIndex = whichChild(this.tabs.querySelector('.active'));\n x = -width * lastIndex; */\n x = rect.left - this.container.getBoundingClientRect().left;\n \n this.avatars.style.transform = PeerProfileAvatars.TRANSLATE_TEMPLATE.replace('{x}', x + 'px');\n\n this.container.classList.add('is-swiping');\n this.avatars.classList.add('no-transition');\n void this.avatars.offsetLeft; // reflow\n },\n onReset: () => {\n const addIndex = Math.ceil(Math.abs(lastDiffX) / (width / PeerProfileAvatars.SCALE)) * (lastDiffX >= 0 ? 1 : -1);\n cancelNextClick();\n \n //console.log(addIndex);\n\n this.avatars.classList.remove('no-transition');\n fastRaf(() => {\n this.listLoader.go(addIndex);\n this.container.classList.remove('is-swiping');\n });\n }\n });\n\n this.intersectionObserver = new IntersectionObserver(entries => {\n entries.forEach(entry => {\n if(!entry.isIntersecting) {\n return;\n }\n\n this.loadNearestToTarget(entry.target);\n });\n });\n\n /* this.listenerSetter.add(rootScope)('avatar_update', (peerId) => {\n if(this.peerId === peerId) {\n const photo = appPeersManager.getPeerPhoto(peerId);\n if(photo) {\n const id = photo.photo_id;\n const previous = this.listLoader.previous;\n for(let i = 0; i < previous.length; ++i) {\n if(previous[i] === id)\n }\n this.listLoader.previous.forEach((_id, idx, arr) => {});\n }\n }\n }); */\n }\n\n public setPeer(peerId: PeerId) {\n this.peerId = peerId;\n\n const photo = appPeersManager.getPeerPhoto(peerId);\n if(!photo) {\n return;\n }\n\n const listLoader: PeerProfileAvatars['listLoader'] = this.listLoader = new ListLoader({\n loadCount: 50,\n loadMore: (anchor, older, loadCount) => {\n if(!older) return Promise.resolve({count: undefined, items: []});\n\n if(peerId.isUser()) {\n const maxId: Photo.photo['id'] = anchor as any;\n return appPhotosManager.getUserPhotos(peerId, maxId, loadCount).then(value => {\n return {\n count: value.count,\n items: value.photos\n };\n });\n } else {\n const promises: [Promise<ChatFull>, ReturnType<AppMessagesManager['getSearch']>] = [] as any;\n if(!listLoader.current) {\n promises.push(Promise.resolve(appProfileManager.getChatFull(peerId.toChatId())));\n }\n \n promises.push(appMessagesManager.getSearch({\n peerId,\n maxId: Number.MAX_SAFE_INTEGER,\n inputFilter: {\n _: 'inputMessagesFilterChatPhotos'\n },\n limit: loadCount,\n backLimit: 0\n }));\n\n return Promise.all(promises).then((result) => {\n const value = result.pop() as typeof result[1];\n\n filterChatPhotosMessages(value);\n\n if(!listLoader.current) {\n const chatFull = result[0];\n const message = findAndSplice(value.history, m => {\n return ((m as Message.messageService).action as MessageAction.messageActionChannelEditPhoto).photo.id === chatFull.chat_photo.id;\n }) as Message.messageService;\n \n listLoader.current = message || appMessagesManager.generateFakeAvatarMessage(this.peerId, chatFull.chat_photo);\n }\n\n //console.log('avatars loaded:', value);\n return {\n count: value.count,\n items: value.history\n };\n });\n }\n },\n processItem: this.processItem,\n onJump: (item, older) => {\n const id = this.listLoader.index;\n //const nextId = Math.max(0, id);\n const x = 100 * PeerProfileAvatars.SCALE * id;\n this.avatars.style.transform = PeerProfileAvatars.TRANSLATE_TEMPLATE.replace('{x}', `-${x}%`);\n\n const activeTab = this.tabs.querySelector('.active');\n if(activeTab) activeTab.classList.remove('active');\n\n const tab = this.tabs.children[id] as HTMLElement;\n tab.classList.add('active');\n\n this.loadNearestToTarget(this.avatars.children[id]);\n }\n });\n\n if(photo._ === 'userProfilePhoto') {\n listLoader.current = photo.photo_id;\n }\n\n this.processItem(listLoader.current);\n\n // listLoader.loaded\n listLoader.load(true);\n }\n\n public addTab() {\n const tab = document.createElement('div');\n tab.classList.add(PeerProfileAvatars.BASE_CLASS + '-tab');\n this.tabs.append(tab);\n\n if(this.tabs.childElementCount === 1) {\n tab.classList.add('active');\n }\n\n this.container.classList.toggle('is-single', this.tabs.childElementCount <= 1);\n }\n\n public processItem = (photoId: Photo.photo['id'] | Message.messageService) => {\n const avatar = document.createElement('div');\n avatar.classList.add(PeerProfileAvatars.BASE_CLASS + '-avatar', 'media-container');\n\n let photo: Photo.photo;\n if(photoId) {\n photo = typeof(photoId) !== 'object' ? \n appPhotosManager.getPhoto(photoId) : \n (photoId.action as MessageAction.messageActionChannelEditPhoto).photo as Photo.photo;\n }\n\n const img = new Image();\n img.classList.add('avatar-photo');\n img.draggable = false;\n\n const loadCallback = () => {\n if(photo) {\n const res = wrapPhoto({\n container: avatar,\n photo,\n size: appPhotosManager.choosePhotoSize(photo, 420, 420, false),\n withoutPreloader: true\n });\n \n [res.images.thumb, res.images.full].filter(Boolean).forEach(img => {\n img.classList.add('avatar-photo');\n });\n } else {\n const photo = appPeersManager.getPeerPhoto(this.peerId);\n appAvatarsManager.putAvatar(avatar, this.peerId, photo, 'photo_big', img);\n }\n };\n\n if(this.avatars.childElementCount <= LOAD_NEAREST) {\n loadCallback();\n } else {\n this.intersectionObserver.observe(avatar);\n this.loadCallbacks.set(avatar, loadCallback);\n }\n\n this.avatars.append(avatar);\n\n this.addTab();\n\n return photoId;\n };\n\n private loadNearestToTarget(target: Element) {\n const children = Array.from(target.parentElement.children);\n const idx = children.indexOf(target);\n const slice = children.slice(Math.max(0, idx - LOAD_NEAREST), Math.min(children.length, idx + LOAD_NEAREST));\n\n slice.forEach(target => {\n const callback = this.loadCallbacks.get(target);\n if(callback) {\n callback();\n this.loadCallbacks.delete(target);\n this.intersectionObserver.unobserve(target);\n }\n });\n }\n\n public cleanup() {\n this.listenerSetter.removeAll();\n this.swipeHandler.removeListeners();\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport IS_PARALLAX_SUPPORTED from \"../environment/parallaxSupport\";\nimport callbackify from \"../helpers/callbackify\";\nimport { copyTextToClipboard } from \"../helpers/clipboard\";\nimport replaceContent from \"../helpers/dom/replaceContent\";\nimport setInnerHTML from \"../helpers/dom/setInnerHTML\";\nimport ListenerSetter from \"../helpers/listenerSetter\";\nimport { fastRaf } from \"../helpers/schedulers\";\nimport { Chat, ChatFull, User } from \"../layer\";\nimport appChatsManager, { Channel } from \"../lib/appManagers/appChatsManager\";\nimport appImManager from \"../lib/appManagers/appImManager\";\nimport appMessagesManager from \"../lib/appManagers/appMessagesManager\";\nimport appNotificationsManager from \"../lib/appManagers/appNotificationsManager\";\nimport appPeersManager from \"../lib/appManagers/appPeersManager\";\nimport appProfileManager from \"../lib/appManagers/appProfileManager\";\nimport appUsersManager from \"../lib/appManagers/appUsersManager\";\nimport I18n from \"../lib/langPack\";\nimport RichTextProcessor from \"../lib/richtextprocessor\";\nimport rootScope from \"../lib/rootScope\";\nimport AvatarElement from \"./avatar\";\nimport CheckboxField from \"./checkboxField\";\nimport generateTitleIcons from \"./generateTitleIcons\";\nimport PeerProfileAvatars from \"./peerProfileAvatars\";\nimport PeerTitle from \"./peerTitle\";\nimport Row from \"./row\";\nimport Scrollable from \"./scrollable\";\nimport { SettingSection, generateDelimiter } from \"./sidebarLeft\";\nimport { toast } from \"./toast\";\n\nlet setText = (text: Parameters<typeof setInnerHTML>[1], row: Row) => {\n //fastRaf(() => {\n setInnerHTML(row.title, text || '');\n row.container.style.display = text ? '' : 'none';\n //});\n};\n\nexport default class PeerProfile {\n public element: HTMLElement;\n private avatars: PeerProfileAvatars;\n private avatar: AvatarElement;\n private section: SettingSection;\n private name: HTMLDivElement;\n private subtitle: HTMLDivElement;\n private bio: Row;\n private username: Row;\n private phone: Row;\n private notifications: Row;\n private location: Row;\n private link: Row;\n \n private cleaned: boolean;\n private setMoreDetailsTimeout: number;\n private setPeerStatusInterval: number;\n\n private peerId: PeerId;\n private threadId: number;\n\n constructor(\n public scrollable: Scrollable, \n private listenerSetter?: ListenerSetter,\n private isDialog = true\n ) {\n if(!IS_PARALLAX_SUPPORTED) {\n this.scrollable.container.classList.add('no-parallax');\n }\n\n if(!listenerSetter) {\n this.listenerSetter = new ListenerSetter();\n }\n }\n\n public init() {\n this.init = null;\n\n\n this.element = document.createElement('div');\n this.element.classList.add('profile-content');\n\n this.section = new SettingSection({\n noDelimiter: true\n });\n\n this.avatar = new AvatarElement();\n this.avatar.classList.add('profile-avatar', 'avatar-120');\n this.avatar.isDialog = this.isDialog;\n this.avatar.attachClickEvent();\n\n this.name = document.createElement('div');\n this.name.classList.add('profile-name');\n\n this.subtitle = document.createElement('div');\n this.subtitle.classList.add('profile-subtitle');\n\n this.bio = new Row({\n title: ' ',\n subtitleLangKey: 'UserBio',\n icon: 'info',\n clickable: (e) => {\n if((e.target as HTMLElement).tagName === 'A') {\n return;\n }\n \n Promise.resolve(appProfileManager.getProfileByPeerId(this.peerId)).then(full => {\n copyTextToClipboard(full.about);\n toast(I18n.format('BioCopied', true));\n });\n }\n });\n\n this.bio.title.classList.add('pre-wrap');\n\n this.username = new Row({\n title: ' ',\n subtitleLangKey: 'Username',\n icon: 'username',\n clickable: () => {\n const peer: Channel | User.user = appPeersManager.getPeer(this.peerId);\n copyTextToClipboard('@' + peer.username);\n toast(I18n.format('UsernameCopied', true));\n }\n });\n\n this.phone = new Row({\n title: ' ',\n subtitleLangKey: 'Phone',\n icon: 'phone',\n clickable: () => {\n const peer: User = appUsersManager.getUser(this.peerId);\n copyTextToClipboard('+' + peer.phone);\n toast(I18n.format('PhoneCopied', true));\n }\n });\n\n this.link = new Row({\n title: ' ',\n subtitleLangKey: 'SetUrlPlaceholder',\n icon: 'link',\n clickable: () => {\n copyTextToClipboard(this.link.title.textContent);\n // Promise.resolve(appProfileManager.getChatFull(this.peerId.toChatId())).then(chatFull => {\n // copyTextToClipboard(chatFull.exported_invite.link);\n toast(I18n.format('LinkCopied', true));\n // });\n }\n });\n\n this.location = new Row({\n title: ' ',\n subtitleLangKey: 'ChatLocation',\n icon: 'location'\n });\n\n this.section.content.append(\n this.phone.container,\n this.username.container,\n this.location.container,\n this.bio.container,\n this.link.container\n );\n\n const {listenerSetter} = this;\n if(this.isDialog) {\n this.notifications = new Row({\n checkboxField: new CheckboxField({toggle: true}),\n titleLangKey: 'Notifications',\n icon: 'unmute'\n });\n\n listenerSetter.add(this.notifications.checkboxField.input)('change', (e) => {\n if(!e.isTrusted) {\n return;\n }\n \n //let checked = this.notificationsCheckbox.checked;\n appMessagesManager.togglePeerMute(this.peerId);\n });\n\n listenerSetter.add(rootScope)('dialog_notify_settings', (dialog) => {\n if(this.peerId === dialog.peerId) {\n const muted = appNotificationsManager.isPeerLocalMuted(this.peerId, false);\n this.notifications.checkboxField.checked = !muted;\n }\n });\n\n this.section.content.append(this.notifications.container);\n }\n\n this.element.append(this.section.container);\n\n if(IS_PARALLAX_SUPPORTED) {\n this.element.append(generateDelimiter());\n }\n\n listenerSetter.add(rootScope)('peer_typings', ({peerId}) => {\n if(this.peerId === peerId) {\n this.setPeerStatus();\n }\n });\n\n listenerSetter.add(rootScope)('peer_bio_edit', (peerId) => {\n if(peerId === this.peerId) {\n this.setMoreDetails(true);\n }\n });\n\n listenerSetter.add(rootScope)('peer_title_edit', (peerId) => {\n if(peerId === this.peerId) {\n this.fillUsername();\n }\n });\n\n listenerSetter.add(rootScope)('user_update', (userId) => {\n if(this.peerId === userId.toPeerId()) {\n this.setPeerStatus();\n }\n });\n\n listenerSetter.add(rootScope)('contacts_update', (userId) => {\n if(this.peerId === userId.toPeerId()) {\n const user = appUsersManager.getUser(userId);\n if(!user.pFlags.self || !this.isDialog) {\n this.fillUserPhone();\n }\n }\n });\n\n listenerSetter.add(rootScope)('avatar_update', (peerId) => {\n if(this.peerId === peerId) {\n // const photo = appPeersManager.getPeerPhoto(peerId);\n // if(!photo && this.avatars) {\n this.setAvatar();\n // }\n }\n });\n\n this.setPeerStatusInterval = window.setInterval(this.setPeerStatus, 60e3);\n }\n\n public setPeerStatus = (needClear = false) => {\n const peerId = this.peerId;\n this.element.classList.toggle('is-me', peerId === rootScope.myId);\n if(!peerId || (rootScope.myId === peerId && this.isDialog)) return;\n\n appImManager.setPeerStatus(this.peerId, this.subtitle, needClear, true, () => peerId === this.peerId, !this.isDialog);\n };\n\n public cleanupHTML() {\n [\n this.bio,\n this.phone,\n this.username,\n this.location,\n this.link\n ].forEach(row => {\n row.container.style.display = 'none';\n });\n\n if(this.notifications) {\n this.notifications.container.style.display = '';\n this.notifications.checkboxField.checked = true;\n }\n\n if(this.setMoreDetailsTimeout) {\n window.clearTimeout(this.setMoreDetailsTimeout);\n this.setMoreDetailsTimeout = 0;\n }\n }\n\n private canBeDetailed() {\n return this.peerId !== rootScope.myId || !this.isDialog;\n }\n\n public setAvatar() {\n if(this.canBeDetailed()) {\n const photo = appPeersManager.getPeerPhoto(this.peerId);\n\n if(photo) {\n const oldAvatars = this.avatars;\n this.avatars = new PeerProfileAvatars(this.scrollable);\n this.avatars.setPeer(this.peerId);\n this.avatars.info.append(this.name, this.subtitle);\n \n this.avatar.remove();\n \n if(oldAvatars) oldAvatars.container.replaceWith(this.avatars.container);\n else this.element.prepend(this.avatars.container);\n\n if(IS_PARALLAX_SUPPORTED) {\n this.scrollable.container.classList.add('parallax');\n }\n\n return;\n }\n }\n\n if(IS_PARALLAX_SUPPORTED) {\n this.scrollable.container.classList.remove('parallax');\n }\n\n if(this.avatars) {\n this.avatars.container.remove();\n this.avatars.cleanup();\n this.avatars = undefined;\n }\n\n this.avatar.updateWithOptions({peerId: this.peerId});\n\n this.section.content.prepend(this.avatar, this.name, this.subtitle);\n }\n\n private fillUsername() {\n const {peerId} = this;\n if(peerId.isUser() && this.canBeDetailed()) {\n const username = appPeersManager.getPeerUsername(peerId);\n setText(username, this.username);\n }\n }\n\n private fillUserPhone() {\n const {peerId} = this;\n if(peerId.isUser() && this.canBeDetailed()) {\n const user = appUsersManager.getUser(peerId);\n setText(user.phone ? appUsersManager.formatUserPhone(user.phone) : undefined, this.phone);\n }\n }\n\n private fillNotifications() {\n const notificationsRow = this.notifications;\n if(!notificationsRow) {\n return;\n }\n\n if(this.canBeDetailed()) {\n const muted = appNotificationsManager.isPeerLocalMuted(this.peerId, false);\n notificationsRow.checkboxField.checked = !muted;\n } else {\n fastRaf(() => {\n notificationsRow.container.style.display = 'none';\n });\n }\n }\n\n private fillRows() {\n const peerId = this.peerId;\n\n this.fillUsername();\n this.fillUserPhone();\n this.fillNotifications();\n this.setMoreDetails();\n\n replaceContent(this.name, new PeerTitle({\n peerId,\n dialog: this.isDialog,\n }).element);\n\n this.name.append(...generateTitleIcons(peerId));\n\n this.setPeerStatus(true);\n }\n\n public fillProfileElements() {\n if(!this.cleaned) return;\n this.cleaned = false;\n \n this.cleanupHTML();\n this.setAvatar();\n this.fillRows();\n }\n\n public setMoreDetails(override?: true) {\n if(this.setMoreDetailsTimeout) {\n window.clearTimeout(this.setMoreDetailsTimeout);\n this.setMoreDetailsTimeout = 0;\n }\n\n const peerId = this.peerId;\n const threadId = this.threadId;\n\n if(!peerId || appPeersManager.isRestricted(peerId) || !this.canBeDetailed()) {\n return;\n }\n\n callbackify(appProfileManager.getProfileByPeerId(peerId, override), (peerFull) => {\n if(this.peerId !== peerId || this.threadId !== threadId || appPeersManager.isRestricted(peerId)) {\n //this.log.warn('peer changed');\n return;\n }\n \n //this.log('chatInfo res 2:', chatFull);\n \n // if(peerFull.about) {\n setText(peerFull.about ? RichTextProcessor.wrapRichText(peerFull.about) : undefined, this.bio);\n // }\n\n if(!peerId.isUser()) {\n const chat: Chat.channel = appChatsManager.getChat(peerId.toChatId());\n if(chat.username) {\n setText('https://t.me/' + chat.username, this.link);\n } else {\n const exportedInvite = (peerFull as ChatFull.channelFull).exported_invite;\n if(exportedInvite) {\n setText(exportedInvite.link, this.link);\n }\n }\n }\n\n const location = (peerFull as ChatFull.channelFull).location;\n if(location?._ == 'channelLocation') {\n setText(location.address, this.location);\n }\n\n this.setMoreDetailsTimeout = window.setTimeout(() => this.setMoreDetails(true), 60e3);\n });\n }\n\n public setPeer(peerId: PeerId, threadId = 0) {\n if(this.peerId === peerId && this.threadId === threadId) return;\n\n if(this.init) {\n this.init();\n }\n\n this.peerId = peerId;\n this.threadId = threadId;\n \n this.cleaned = true;\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport appMessagesManager from \"../../../lib/appManagers/appMessagesManager\";\nimport appUsersManager from \"../../../lib/appManagers/appUsersManager\";\nimport rootScope from \"../../../lib/rootScope\";\nimport AppSearchSuper, { SearchSuperType } from \"../../appSearchSuper.\";\nimport SidebarSlider, { SliderSuperTab } from \"../../slider\";\nimport { TransitionSlider } from \"../../transition\";\nimport AppEditChatTab from \"./editChat\";\nimport PeerTitle from \"../../peerTitle\";\nimport AppEditContactTab from \"./editContact\";\nimport appChatsManager from \"../../../lib/appManagers/appChatsManager\";\nimport Button from \"../../button\";\nimport ButtonIcon from \"../../buttonIcon\";\nimport { i18n, LangPackKey } from \"../../../lib/langPack\";\nimport { toastNew } from \"../../toast\";\nimport AppAddMembersTab from \"../../sidebarLeft/tabs/addMembers\";\nimport PopupPickUser from \"../../popups/pickUser\";\nimport PopupPeer, { PopupPeerButtonCallbackCheckboxes, PopupPeerCheckboxOptions } from \"../../popups/peer\";\nimport ButtonCorner from \"../../buttonCorner\";\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\nimport PeerProfile from \"../../peerProfile\";\n\n// TODO: отредактированное сообщение не изменится\nexport default class AppSharedMediaTab extends SliderSuperTab {\n private editBtn: HTMLElement;\n\n private peerId: PeerId;\n private threadId = 0;\n\n private historiesStorage: {\n [peerId: PeerId]: Partial<{\n [type in SearchSuperType]: {mid: number, peerId: PeerId}[]\n }>\n } = {};\n\n private searchSuper: AppSearchSuper;\n\n private profile: PeerProfile;\n private peerChanged: boolean;\n\n constructor(slider: SidebarSlider) {\n super(slider, false);\n }\n\n public init() {\n //const perf = performance.now();\n\n this.container.classList.add('shared-media-container', 'profile-container');\n\n // * header\n const newCloseBtn = Button('btn-icon sidebar-close-button', {noRipple: true});\n this.closeBtn.replaceWith(newCloseBtn);\n this.closeBtn = newCloseBtn;\n\n const animatedCloseIcon = document.createElement('div');\n animatedCloseIcon.classList.add('animated-close-icon');\n newCloseBtn.append(animatedCloseIcon);\n\n const transitionContainer = document.createElement('div');\n transitionContainer.className = 'transition slide-fade';\n \n const transitionFirstItem = document.createElement('div');\n transitionFirstItem.classList.add('transition-item');\n\n this.title.append(i18n('Profile'));\n this.editBtn = ButtonIcon('edit');\n //const moreBtn = ButtonIcon('more');\n\n transitionFirstItem.append(this.title, this.editBtn/* , moreBtn */);\n\n const transitionLastItem = document.createElement('div');\n transitionLastItem.classList.add('transition-item');\n\n const secondTitle: HTMLElement = this.title.cloneNode() as any;\n secondTitle.append(i18n('PeerInfo.SharedMedia'));\n\n transitionLastItem.append(secondTitle);\n\n transitionContainer.append(transitionFirstItem, transitionLastItem);\n\n this.header.append(transitionContainer);\n\n // * body\n\n this.profile = new PeerProfile(this.scrollable);\n this.profile.init();\n \n this.scrollable.append(this.profile.element);\n\n const HEADER_HEIGHT = 56;\n this.scrollable.onAdditionalScroll = () => {\n const rect = this.searchSuper.nav.getBoundingClientRect(); \n if(!rect.width) return;\n\n const top = rect.top - 1;\n setIsSharedMedia(top <= HEADER_HEIGHT);\n };\n\n const setIsSharedMedia = (isSharedMedia: boolean) => {\n animatedCloseIcon.classList.toggle('state-back', isSharedMedia);\n this.searchSuper.container.classList.toggle('is-full-viewport', isSharedMedia);\n transition(+isSharedMedia);\n\n if(!isSharedMedia) {\n this.searchSuper.cleanScrollPositions();\n }\n };\n\n const transition = TransitionSlider(transitionContainer, 'slide-fade', 400, null, false);\n\n transition(0);\n\n attachClickEvent(this.closeBtn, (e) => {\n if(this.closeBtn.firstElementChild.classList.contains('state-back')) {\n this.scrollable.scrollIntoViewNew({\n element: this.scrollable.container.firstElementChild as HTMLElement, \n position: 'start'\n });\n transition(0);\n animatedCloseIcon.classList.remove('state-back');\n } else if(!this.scrollable.isHeavyAnimationInProgress) {\n this.slider.onCloseBtnClick();\n }\n });\n\n attachClickEvent(this.editBtn, (e) => {\n let tab: AppEditChatTab | AppEditContactTab;\n if(this.peerId.isAnyChat()) {\n tab = new AppEditChatTab(this.slider);\n } else {\n tab = new AppEditContactTab(this.slider);\n }\n\n if(tab) {\n if(tab instanceof AppEditChatTab) {\n tab.chatId = this.peerId.toChatId();\n } else {\n tab.peerId = this.peerId;\n }\n \n tab.open();\n }\n });\n\n rootScope.addEventListener('contacts_update', (userId) => {\n if(this.peerId === userId) {\n this.toggleEditBtn();\n }\n });\n\n rootScope.addEventListener('chat_update', (chatId) => {\n if(this.peerId === chatId.toPeerId(true)) {\n this.toggleEditBtn();\n }\n });\n\n rootScope.addEventListener('history_multiappend', (msgIdsByPeer) => {\n for(const peerId in msgIdsByPeer) {\n this.renderNewMessages(peerId.toPeerId(), Array.from(msgIdsByPeer[peerId]));\n }\n });\n \n rootScope.addEventListener('history_delete', ({peerId, msgs}) => {\n this.deleteDeletedMessages(peerId, Array.from(msgs));\n });\n\n // Calls when message successfully sent and we have an id\n rootScope.addEventListener('message_sent', ({message}) => {\n this.renderNewMessages(message.peerId, [message.mid]);\n });\n\n //this.container.prepend(this.closeBtn.parentElement);\n\n this.searchSuper = new AppSearchSuper({\n mediaTabs: [{\n inputFilter: 'inputMessagesFilterEmpty',\n name: 'PeerMedia.Members',\n type: 'members'\n }, {\n inputFilter: 'inputMessagesFilterPhotoVideo',\n name: 'SharedMediaTab2',\n type: 'media'\n }, {\n inputFilter: 'inputMessagesFilterDocument',\n name: 'SharedFilesTab2',\n type: 'files'\n }, {\n inputFilter: 'inputMessagesFilterUrl',\n name: 'SharedLinksTab2',\n type: 'links'\n }, {\n inputFilter: 'inputMessagesFilterMusic',\n name: 'SharedMusicTab2',\n type: 'music'\n }, {\n inputFilter: 'inputMessagesFilterRoundVoice',\n name: 'SharedVoiceTab2',\n type: 'voice'\n }], \n scrollable: this.scrollable,\n onChangeTab: (mediaTab) => {\n let timeout = mediaTab.type === 'members' && rootScope.settings.animationsEnabled ? 250 : 0;\n setTimeout(() => {\n btnAddMembers.classList.toggle('is-hidden', mediaTab.type !== 'members');\n }, timeout);\n }\n });\n\n this.searchSuper.scrollStartCallback = () => {\n setIsSharedMedia(true);\n };\n\n this.profile.element.append(this.searchSuper.container);\n\n const btnAddMembers = ButtonCorner({icon: 'addmember_filled'});\n this.content.append(btnAddMembers);\n\n btnAddMembers.addEventListener('click', () => {\n const peerId = this.peerId;\n const id = this.peerId.toChatId();\n const isChannel = appChatsManager.isChannel(id);\n\n const showConfirmation = (peerIds: PeerId[], callback: (checked: PopupPeerButtonCallbackCheckboxes) => void) => {\n let titleLangKey: LangPackKey, titleLangArgs: any[],\n descriptionLangKey: LangPackKey, descriptionLangArgs: any[],\n checkboxes: PopupPeerCheckboxOptions[];\n\n if(peerIds.length > 1) {\n titleLangKey = 'AddMembersAlertTitle';\n titleLangArgs = [i18n('Members', [peerIds.length])];\n descriptionLangKey = 'AddMembersAlertCountText';\n descriptionLangArgs = peerIds.map(peerId => {\n const b = document.createElement('b');\n b.append(new PeerTitle({peerId}).element);\n return b;\n });\n\n if(!isChannel) {\n checkboxes = [{\n text: 'AddMembersForwardMessages',\n checked: true\n }];\n }\n } else {\n titleLangKey = 'AddOneMemberAlertTitle';\n descriptionLangKey = 'AddMembersAlertNamesText';\n const b = document.createElement('b');\n b.append(new PeerTitle({\n peerId: peerIds[0]\n }).element);\n descriptionLangArgs = [b];\n\n if(!isChannel) {\n checkboxes = [{\n text: 'AddOneMemberForwardMessages',\n textArgs: [new PeerTitle({peerId: peerIds[0]}).element],\n checked: true\n }];\n }\n }\n\n descriptionLangArgs.push(new PeerTitle({\n peerId\n }).element);\n\n new PopupPeer('popup-add-members', {\n peerId,\n titleLangKey,\n descriptionLangKey,\n descriptionLangArgs,\n buttons: [{\n langKey: 'Add',\n callback\n }],\n checkboxes\n }).show();\n };\n\n const onError = (err: any) => {\n if(err.type === 'USER_PRIVACY_RESTRICTED') {\n toastNew({langPackKey: 'InviteToGroupError'});\n }\n };\n \n if(isChannel) {\n const tab = new AppAddMembersTab(this.slider);\n tab.open({\n type: 'channel',\n skippable: false,\n takeOut: (peerIds) => {\n showConfirmation(peerIds, () => {\n const promise = appChatsManager.inviteToChannel(id, peerIds);\n promise.catch(onError);\n tab.attachToPromise(promise);\n });\n\n return false;\n },\n title: 'GroupAddMembers',\n placeholder: 'SendMessageTo'\n });\n } else {\n new PopupPickUser({\n peerTypes: ['contacts'],\n placeholder: 'Search',\n onSelect: (peerId) => {\n setTimeout(() => {\n showConfirmation([peerId], (checked) => {\n appChatsManager.addChatUser(id, peerId, checked.size ? undefined : 0)\n .catch(onError);\n });\n }, 0);\n },\n });\n }\n });\n\n //console.log('construct shared media time:', performance.now() - perf);\n }\n\n public renderNewMessages(peerId: PeerId, mids: number[]) {\n if(this.init) return; // * not inited yet\n\n if(!this.historiesStorage[peerId]) return;\n \n mids = mids.slice().reverse(); // ! because it will be ascend sorted array\n for(const mediaTab of this.searchSuper.mediaTabs) {\n const inputFilter = mediaTab.inputFilter;\n const filtered = this.searchSuper.filterMessagesByType(mids.map(mid => appMessagesManager.getMessageByPeer(peerId, mid)), inputFilter);\n if(filtered.length) {\n const history = this.historiesStorage[peerId][inputFilter];\n if(history) {\n history.unshift(...filtered.map(message => ({mid: message.mid, peerId: message.peerId})));\n }\n\n if(this.peerId === peerId && this.searchSuper.usedFromHistory[inputFilter] !== -1) {\n this.searchSuper.usedFromHistory[inputFilter] += filtered.length;\n this.searchSuper.performSearchResult(filtered, mediaTab, false);\n }\n }\n }\n }\n\n public deleteDeletedMessages(peerId: PeerId, mids: number[]) {\n if(this.init) return; // * not inited yet\n\n if(!this.historiesStorage[peerId]) return;\n\n for(const mid of mids) {\n for(const type of this.searchSuper.mediaTabs) {\n const inputFilter = type.inputFilter;\n\n const history = this.historiesStorage[peerId][inputFilter];\n if(!history) continue;\n\n const idx = history.findIndex(m => m.mid === mid);\n if(idx !== -1) {\n history.splice(idx, 1);\n\n if(this.peerId === peerId) {\n const container = this.searchSuper.tabs[inputFilter];\n const div = container.querySelector(`[data-mid=\"${mid}\"][data-peer-id=\"${peerId}\"]`) as HTMLElement;\n if(div) {\n if(this.searchSuper.selection.isSelecting) {\n this.searchSuper.selection.toggleByElement(div);\n }\n\n div.remove();\n }\n \n if(this.searchSuper.usedFromHistory[inputFilter] >= (idx + 1)) {\n this.searchSuper.usedFromHistory[inputFilter]--;\n }\n }\n\n // can have element in different tabs somehow\n // break;\n }\n }\n }\n\n this.scrollable.onScroll();\n }\n\n public cleanupHTML() {\n // const perf = performance.now();\n this.profile.cleanupHTML();\n \n this.editBtn.classList.add('hide');\n\n this.searchSuper.cleanupHTML(true);\n\n this.container.classList.toggle('can-add-members', this.searchSuper.canViewMembers() && appChatsManager.hasRights(this.peerId.toChatId(), 'invite_users'));\n\n // console.log('cleanupHTML shared media time:', performance.now() - perf);\n }\n\n public setLoadMutex(promise: Promise<any>) {\n this.searchSuper.loadMutex = promise;\n }\n\n public setPeer(peerId: PeerId, threadId = 0) {\n if(this.peerId === peerId && this.threadId === threadId) return false;\n\n this.peerId = peerId;\n this.threadId = threadId;\n this.peerChanged = true;\n\n if(this.init) {\n this.init();\n this.init = null;\n }\n\n this.searchSuper.setQuery({\n peerId, \n //threadId, \n historyStorage: this.historiesStorage[peerId] ?? (this.historiesStorage[peerId] = {})\n });\n\n this.profile.setPeer(peerId, threadId);\n \n return true;\n }\n\n public fillProfileElements() {\n if(!this.peerChanged) {\n return;\n }\n\n this.peerChanged = false;\n\n this.cleanupHTML();\n\n this.profile.fillProfileElements();\n\n this.toggleEditBtn();\n }\n\n private toggleEditBtn() {\n let show: boolean;\n if(this.peerId.isUser()) {\n show = this.peerId !== rootScope.myId && appUsersManager.isContact(this.peerId.toUserId());\n } else {\n show = appChatsManager.hasRights(this.peerId.toChatId(), 'change_info');\n }\n\n this.editBtn.classList.toggle('hide', !show);\n }\n\n public loadSidebarMedia(single: boolean, justLoad = false) {\n this.searchSuper.load(single, justLoad);\n }\n\n onOpenAfterTimeout() {\n this.scrollable.onScroll();\n }\n}\n\n// MOUNT_CLASS_TO && (MOUNT_CLASS_TO.AppSharedMediaTab = AppSharedMediaTab);\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport appImManager from \"../../lib/appManagers/appImManager\";\r\nimport SidebarSlider from \"../slider\";\r\nimport mediaSizes, { ScreenSize } from \"../../helpers/mediaSizes\";\r\nimport AppSharedMediaTab from \"./tabs/sharedMedia\";\r\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\r\n\r\nexport const RIGHT_COLUMN_ACTIVE_CLASSNAME = 'is-right-column-shown';\r\n\r\nexport class AppSidebarRight extends SidebarSlider {\r\n public sharedMediaTab: AppSharedMediaTab;\r\n private isColumnProportionSet = false;\r\n\r\n constructor() {\r\n super({\r\n sidebarEl: document.getElementById('column-right') as HTMLElement,\r\n canHideFirst: true,\r\n navigationType: 'right'\r\n });\r\n\r\n mediaSizes.addEventListener('changeScreen', (from, to) => {\r\n if(to === ScreenSize.medium && from !== ScreenSize.mobile) {\r\n this.toggleSidebar(false);\r\n }\r\n });\r\n\r\n mediaSizes.addEventListener('resize', () => {\r\n this.setColumnProportion();\r\n });\r\n\r\n this.sharedMediaTab = new AppSharedMediaTab(this);\r\n }\r\n\r\n public onCloseTab(id: number, animate: boolean, isNavigation?: boolean) {\r\n if(!this.historyTabIds.length) {\r\n this.toggleSidebar(false, animate);\r\n }\r\n\r\n super.onCloseTab(id, animate, isNavigation);\r\n }\r\n\r\n /* public selectTab(id: number) {\r\n const res = super.selectTab(id);\r\n\r\n if(id !== -1) {\r\n this.toggleSidebar(true);\r\n }\r\n\r\n return res;\r\n } */\r\n\r\n private setColumnProportion() {\r\n const proportion = this.sidebarEl.scrollWidth / this.sidebarEl.previousElementSibling.scrollWidth;\r\n document.documentElement.style.setProperty('--right-column-proportion', '' + proportion);\r\n }\r\n\r\n public toggleSidebar(enable?: boolean, animate?: boolean) {\r\n /////this.log('sidebarEl', this.sidebarEl, enable, isElementInViewport(this.sidebarEl));\r\n\r\n const active = document.body.classList.contains(RIGHT_COLUMN_ACTIVE_CLASSNAME);\r\n let willChange: boolean;\r\n if(enable !== undefined) {\r\n if(enable) {\r\n if(!active) {\r\n willChange = true;\r\n }\r\n } else if(active) {\r\n willChange = true;\r\n }\r\n } else {\r\n willChange = true;\r\n }\r\n\r\n if(!willChange) return Promise.resolve();\r\n\r\n if(!active && !this.historyTabIds.length) {\r\n this.sharedMediaTab.open();\r\n //this.selectTab(this.sharedMediaTab);\r\n }\r\n\r\n if(!this.isColumnProportionSet) {\r\n this.setColumnProportion();\r\n this.isColumnProportionSet = true;\r\n }\r\n\r\n const animationPromise = appImManager.selectTab(active ? 1 : 2, animate);\r\n document.body.classList.toggle(RIGHT_COLUMN_ACTIVE_CLASSNAME, enable);\r\n return animationPromise;\r\n\r\n /* return new Promise((resolve, reject) => {\r\n const hidden: {element: HTMLDivElement, height: number}[] = [];\r\n const observer = new IntersectionObserver((entries) => {\r\n for(const entry of entries) {\r\n const bubble = entry.target as HTMLDivElement;\r\n if(!entry.isIntersecting) {\r\n hidden.push({element: bubble, height: bubble.scrollHeight});\r\n }\r\n }\r\n \r\n for(const item of hidden) {\r\n item.element.style.minHeight = item.height + 'px';\r\n (item.element.firstElementChild as HTMLElement).style.display = 'none';\r\n item.element.style.width = '1px';\r\n }\r\n \r\n //console.log('hidden', hidden);\r\n observer.disconnect();\r\n \r\n set();\r\n \r\n setTimeout(() => {\r\n for(const item of hidden) {\r\n item.element.style.minHeight = '';\r\n item.element.style.width = '';\r\n (item.element.firstElementChild as HTMLElement).style.display = '';\r\n }\r\n\r\n resolve();\r\n }, 200);\r\n });\r\n \r\n const length = Object.keys(appImManager.bubbles).length;\r\n if(length) {\r\n for(const i in appImManager.bubbles) {\r\n observer.observe(appImManager.bubbles[i]);\r\n }\r\n } else {\r\n set();\r\n setTimeout(resolve, 200);\r\n }\r\n }); */\r\n }\r\n}\r\n\r\nconst appSidebarRight = new AppSidebarRight();\r\nMOUNT_CLASS_TO.appSidebarRight = appSidebarRight;\r\nexport default appSidebarRight;\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTab } from \"../../slider\";\r\nimport appSidebarRight from \"..\";\r\nimport appPollsManager from \"../../../lib/appManagers/appPollsManager\";\r\nimport { roundPercents } from \"../../poll\";\r\nimport { RichTextProcessor } from \"../../../lib/richtextprocessor\";\r\nimport appDialogsManager from \"../../../lib/appManagers/appDialogsManager\";\r\nimport ripple from \"../../ripple\";\r\nimport { i18n } from \"../../../lib/langPack\";\r\nimport setInnerHTML from \"../../../helpers/dom/setInnerHTML\";\r\n\r\nexport default class AppPollResultsTab extends SliderSuperTab {\r\n private resultsDiv: HTMLElement;\r\n\r\n protected init() {\r\n this.container.id = 'poll-results-container';\r\n this.container.classList.add('chatlist-container');\r\n\r\n this.resultsDiv = document.createElement('div');\r\n this.resultsDiv.classList.add('poll-results');\r\n this.scrollable.append(this.resultsDiv);\r\n }\r\n\r\n public open(message: any) {\r\n const ret = super.open();\r\n const poll = appPollsManager.getPoll(message.media.poll.id);\r\n\r\n this.setTitle(poll.poll.pFlags.quiz ? 'PollResults.Title.Quiz' : 'PollResults.Title.Poll');\r\n\r\n const title = document.createElement('h3');\r\n setInnerHTML(title, RichTextProcessor.wrapEmojiText(poll.poll.question));\r\n\r\n const percents = poll.results.results.map(v => v.voters / poll.results.total_voters * 100);\r\n roundPercents(percents);\r\n\r\n const fragment = document.createDocumentFragment();\r\n poll.results.results.forEach((result, idx) => {\r\n if(!result.voters) return;\r\n\r\n const hr = document.createElement('hr');\r\n\r\n const answer = poll.poll.answers[idx];\r\n\r\n // Head\r\n const answerEl = document.createElement('div');\r\n answerEl.classList.add('poll-results-answer');\r\n\r\n const answerTitle = document.createElement('div');\r\n setInnerHTML(answerTitle, RichTextProcessor.wrapEmojiText(answer.text));\r\n\r\n const answerPercents = document.createElement('div');\r\n answerPercents.innerText = Math.round(percents[idx]) + '%';\r\n\r\n answerEl.append(answerTitle, answerPercents);\r\n\r\n // Humans\r\n const list = appDialogsManager.createChatList();\r\n list.classList.add('poll-results-voters');\r\n\r\n appDialogsManager.setListClickListener(list, () => {\r\n appSidebarRight.onCloseBtnClick();\r\n }, undefined, true);\r\n\r\n list.style.minHeight = Math.min(result.voters, 4) * 50 + 'px';\r\n\r\n fragment.append(hr, answerEl, list);\r\n\r\n let offset: string, limit = 4, loading = false, left = result.voters - 4;\r\n const load = () => {\r\n if(loading) return;\r\n loading = true;\r\n\r\n appPollsManager.getVotes(message, answer.option, offset, limit).then(votesList => {\r\n votesList.votes.forEach(vote => {\r\n const {dom} = appDialogsManager.addDialogNew({\r\n dialog: vote.user_id.toPeerId(false),\r\n container: list,\r\n drawStatus: false,\r\n rippleEnabled: false, \r\n meAsSaved: false,\r\n avatarSize: 32\r\n });\r\n dom.lastMessageSpan.parentElement.remove();\r\n });\r\n\r\n if(offset) {\r\n left -= votesList.votes.length;\r\n (showMore.lastElementChild as HTMLElement).replaceWith(i18n('PollResults.LoadMore', [Math.min(20, left)]));\r\n }\r\n \r\n offset = votesList.next_offset;\r\n limit = 20;\r\n\r\n if(!left || !votesList.votes.length) {\r\n showMore.remove();\r\n }\r\n }).finally(() => {\r\n loading = false;\r\n });\r\n };\r\n\r\n load();\r\n\r\n if(left <= 0) return;\r\n\r\n const showMore = document.createElement('div');\r\n showMore.classList.add('poll-results-more', 'show-more', 'rp-overflow');\r\n showMore.addEventListener('click', load);\r\n ripple(showMore);\r\n const down = document.createElement('div');\r\n down.classList.add('tgico-down');\r\n showMore.append(down, i18n('PollResults.LoadMore', [Math.min(20, left)]));\r\n\r\n fragment.append(showMore);\r\n });\r\n\r\n this.resultsDiv.append(title, fragment);\r\n\r\n appSidebarRight.toggleSidebar(true).then(() => {\r\n /* appPollsManager.getVotes(mid).then(votes => {\r\n console.log('gOt VotEs', votes);\r\n }); */\r\n });\r\n\r\n return ret;\r\n }\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport AvatarElement from \"./avatar\";\nimport type { LazyLoadQueueIntersector } from \"./lazyLoadQueue\";\n\nconst CLASS_NAME = 'stacked-avatars';\nconst AVATAR_CLASS_NAME = CLASS_NAME + '-avatar';\nconst AVATAR_CONTAINER_CLASS_NAME = AVATAR_CLASS_NAME + '-container';\n\nexport default class StackedAvatars {\n public container: HTMLElement;\n private lazyLoadQueue: LazyLoadQueueIntersector;\n private avatarSize: number;\n\n constructor(options: {\n lazyLoadQueue?: LazyLoadQueueIntersector,\n avatarSize: number\n }) {\n this.lazyLoadQueue = options.lazyLoadQueue;\n this.avatarSize = options.avatarSize;\n\n this.container = document.createElement('div');\n this.container.classList.add(CLASS_NAME);\n\n this.container.style.setProperty('--avatar-size', options.avatarSize + 'px');\n }\n /**\n * MACOS, ANDROID - без реверса\n * WINDOWS DESKTOP - реверс\n * все приложения накладывают аватарку первую на вторую, а в макете зато вторая на первую, ЛОЛ!\n */\n public render(peerIds: PeerId[], loadPromises?: Promise<any>[]) {\n const children = this.container.children;\n peerIds = peerIds.slice().reverse();\n if(peerIds.length > 3) {\n peerIds = peerIds.slice(-3);\n }\n\n peerIds.forEach((peerId, idx) => {\n let avatarContainer = children[idx] as HTMLElement;\n if(!avatarContainer) {\n avatarContainer = document.createElement('div');\n avatarContainer.classList.add(AVATAR_CONTAINER_CLASS_NAME);\n }\n\n let avatarElem = avatarContainer.firstElementChild as AvatarElement;\n if(!avatarElem) {\n avatarElem = new AvatarElement();\n avatarElem.classList.add('avatar-' + this.avatarSize, AVATAR_CLASS_NAME);\n avatarElem.updateOptions({\n isDialog: false,\n loadPromises\n });\n }\n\n avatarElem.updateWithOptions({\n lazyLoadQueue: this.lazyLoadQueue,\n peerId: peerId\n });\n \n if(!avatarElem.parentNode) {\n avatarContainer.append(avatarElem);\n }\n\n if(!avatarContainer.parentNode) {\n this.container.append(avatarContainer);\n }\n });\n\n // if were 3 and became 2\n (Array.from(children) as HTMLElement[]).slice(peerIds.length).forEach(el => el.remove());\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport mediaSizes from \"../helpers/mediaSizes\";\r\nimport { IS_TOUCH_SUPPORTED } from \"../environment/touchSupport\";\r\nimport appImManager from \"../lib/appManagers/appImManager\";\r\nimport appPollsManager from \"../lib/appManagers/appPollsManager\";\r\nimport serverTimeManager from \"../lib/mtproto/serverTimeManager\";\r\nimport { RichTextProcessor } from \"../lib/richtextprocessor\";\r\nimport rootScope from \"../lib/rootScope\";\r\nimport ripple from \"./ripple\";\r\nimport appSidebarRight from \"./sidebarRight\";\r\nimport AppPollResultsTab from \"./sidebarRight/tabs/pollResults\";\r\nimport { i18n, LangPackKey } from \"../lib/langPack\";\r\nimport { fastRaf } from \"../helpers/schedulers\";\r\nimport SetTransition from \"./singleTransition\";\r\nimport findUpClassName from \"../helpers/dom/findUpClassName\";\r\nimport cancelEvent from \"../helpers/dom/cancelEvent\";\r\nimport { attachClickEvent, detachClickEvent } from \"../helpers/dom/clickEvent\";\r\nimport replaceContent from \"../helpers/dom/replaceContent\";\r\nimport windowSize from \"../helpers/windowSize\";\r\nimport { Poll, PollResults } from \"../layer\";\r\nimport toHHMMSS from \"../helpers/string/toHHMMSS\";\r\nimport StackedAvatars from \"./stackedAvatars\";\r\nimport setInnerHTML from \"../helpers/dom/setInnerHTML\";\r\n\r\nlet lineTotalLength = 0;\r\nconst tailLength = 9;\r\nconst times = 10;\r\nconst fullTime = 340;\r\nconst oneTime = fullTime / times;\r\n\r\nexport const roundPercents = (percents: number[]) => {\r\n //console.log('roundPercents before percents:', percents);\r\n\r\n const sum = percents.reduce((acc, p) => acc + Math.round(p), 0);\r\n if(sum > 100) {\r\n const diff = sum - 100;\r\n const length = percents.length;\r\n for(let i = 0; i < diff; ++i) {\r\n let minIndex = -1, minRemainder = 1;\r\n for(let k = 0; k < length; ++k) {\r\n let remainder = percents[k] % 1;\r\n if(remainder >= 0.5 && remainder < minRemainder) {\r\n minRemainder = remainder;\r\n minIndex = k;\r\n }\r\n }\r\n\r\n if(minIndex === -1) {\r\n //throw new Error('lol chto');\r\n return;\r\n }\r\n\r\n percents[minIndex] -= minRemainder;\r\n }\r\n } else if(sum < 100) {\r\n const diff = 100 - sum;\r\n const length = percents.length;\r\n for(let i = 0; i < diff; ++i) {\r\n let minIndex = -1, maxRemainder = 0;\r\n for(let k = 0; k < length; ++k) {\r\n let remainder = percents[k] % 1;\r\n if(remainder < 0.5 && remainder > maxRemainder) {\r\n maxRemainder = remainder;\r\n minIndex = k;\r\n }\r\n }\r\n\r\n if(minIndex === -1) {\r\n //throw new Error('lol chto');\r\n return;\r\n }\r\n\r\n percents[minIndex] += 1 - maxRemainder;\r\n }\r\n }\r\n\r\n //console.log('roundPercents after percents:', percents);\r\n};\r\n\r\n/* const connectedPolls: {id: string, element: PollElement}[] = [];\r\nrootScope.on('poll_update', (e) => {\r\n const {poll, results} = e as {poll: Poll, results: PollResults};\r\n\r\n //console.log('poll_update', poll, results);\r\n for(const connected of connectedPolls) {\r\n if(connected.id === poll.id) {\r\n const pollElement = connected.element;\r\n pollElement.isClosed = !!poll.pFlags.closed;\r\n pollElement.performResults(results, poll.chosenIndexes);\r\n }\r\n }\r\n}); */\r\n\r\nrootScope.addEventListener('poll_update', ({poll, results}) => {\r\n const pollElements = Array.from(document.querySelectorAll(`poll-element[poll-id=\"${poll.id}\"]`)) as PollElement[];\r\n pollElements.forEach(pollElement => {\r\n //console.log('poll_update', poll, results);\r\n pollElement.isClosed = !!poll.pFlags.closed;\r\n pollElement.performResults(results, poll.chosenIndexes);\r\n });\r\n});\r\n\r\nrootScope.addEventListener('peer_changed', () => {\r\n if(prevQuizHint) {\r\n hideQuizHint(prevQuizHint, prevQuizHintOnHide, prevQuizHintTimeout);\r\n }\r\n});\r\n\r\nmediaSizes.addEventListener('resize', () => {\r\n PollElement.setMaxLength();\r\n PollElement.resizePolls();\r\n});\r\n\r\nmediaSizes.addEventListener('changeScreen', () => {\r\n PollElement.setMaxLength();\r\n});\r\n\r\nconst hideQuizHint = (element: HTMLElement, onHide: () => void, timeout: number) => {\r\n element.classList.remove('active');\r\n\r\n clearTimeout(timeout);\r\n setTimeout(() => {\r\n onHide();\r\n element.remove();\r\n\r\n if(prevQuizHint === element && prevQuizHintOnHide === onHide && prevQuizHintTimeout === timeout) {\r\n prevQuizHint = prevQuizHintOnHide = null;\r\n prevQuizHintTimeout = 0;\r\n }\r\n }, 200);\r\n};\r\n\r\nlet prevQuizHint: HTMLElement, prevQuizHintOnHide: () => void, prevQuizHintTimeout: number;\r\nconst setQuizHint = (solution: string, solution_entities: any[], onHide: () => void) => {\r\n if(prevQuizHint) {\r\n hideQuizHint(prevQuizHint, prevQuizHintOnHide, prevQuizHintTimeout);\r\n }\r\n\r\n const element = document.createElement('div');\r\n element.classList.add('quiz-hint');\r\n\r\n const container = document.createElement('div');\r\n container.classList.add('container', 'tgico');\r\n\r\n const textEl = document.createElement('div');\r\n textEl.classList.add('text');\r\n\r\n container.append(textEl);\r\n element.append(container);\r\n\r\n setInnerHTML(textEl, RichTextProcessor.wrapRichText(solution, {entities: solution_entities}));\r\n appImManager.chat.bubbles.bubblesContainer.append(element);\r\n\r\n void element.offsetLeft; // reflow\r\n element.classList.add('active');\r\n\r\n prevQuizHint = element;\r\n prevQuizHintOnHide = onHide;\r\n prevQuizHintTimeout = window.setTimeout(() => {\r\n hideQuizHint(element, onHide, prevQuizHintTimeout);\r\n }, IS_TOUCH_SUPPORTED ? 5000 : 7000);\r\n};\r\n\r\nexport default class PollElement extends HTMLElement {\r\n public static MAX_OFFSET = -46.5;\r\n public static MAX_LENGTH = 0;\r\n public svgLines: SVGSVGElement[];\r\n private numberDivs: HTMLDivElement[];\r\n private answerDivs: HTMLDivElement[];\r\n private descDiv: HTMLElement;\r\n private typeDiv: HTMLElement;\r\n private avatarsDiv: HTMLElement;\r\n private viewResults: HTMLElement;\r\n private votersCountDiv: HTMLDivElement;\r\n\r\n // private maxLength: number;\r\n // private maxLengths: number[];\r\n private maxPercents: number[];\r\n\r\n public isClosed = false;\r\n private isQuiz = false;\r\n private isRetracted = false;\r\n private isPublic = false;\r\n private isMultiple = false;\r\n private chosenIndexes: number[] = [];\r\n private percents: number[];\r\n\r\n public message: any;\r\n\r\n private quizInterval: number;\r\n private quizTimer: SVGSVGElement;\r\n\r\n private sendVoteBtn: HTMLElement;\r\n private chosingIndexes: number[] = [];\r\n\r\n private sendVotePromise: Promise<void>;\r\n private sentVote = false;\r\n\r\n constructor() {\r\n super();\r\n // элемент создан\r\n }\r\n\r\n public static setMaxLength() {\r\n const width = windowSize.width <= 360 ? windowSize.width - 120 : mediaSizes.active.poll.width;\r\n this.MAX_LENGTH = width + tailLength + this.MAX_OFFSET + -13.7; // 13 - position left\r\n }\r\n\r\n public static resizePolls() {\r\n if(!this.MAX_LENGTH) return;\r\n const pollElements = Array.from(document.querySelectorAll('poll-element.is-voted')) as PollElement[];\r\n pollElements.forEach(pollElement => {\r\n pollElement.svgLines.forEach((svg, idx) => {\r\n //void svg.getBoundingClientRect(); // reflow\r\n pollElement.setLineProgress(idx, 1);\r\n });\r\n });\r\n }\r\n\r\n public render() {\r\n // браузер вызывает этот метод при добавлении элемента в документ\r\n // (может вызываться много раз, если элемент многократно добавляется/удаляется)\r\n\r\n if(!lineTotalLength) {\r\n lineTotalLength = (document.getElementById('poll-line') as any as SVGPathElement).getTotalLength();\r\n //console.log('line total length:', lineTotalLength);\r\n PollElement.setMaxLength();\r\n }\r\n\r\n const pollId = this.message.media.poll.id;\r\n const {poll, results} = appPollsManager.getPoll(pollId);\r\n\r\n /* const timestamp = Date.now() / 1000 | 0;\r\n if(timestamp < this.message.date) { */\r\n if(this.message.pFlags.is_scheduled) {\r\n this.classList.add('disable-hover');\r\n }\r\n\r\n //console.log('pollElement poll:', poll, results);\r\n\r\n let descKey: LangPackKey;\r\n if(poll.pFlags) {\r\n this.isPublic = !!poll.pFlags.public_voters;\r\n this.isQuiz = !!poll.pFlags.quiz;\r\n this.isClosed = !!poll.pFlags.closed;\r\n this.isMultiple = !!poll.pFlags.multiple_choice;\r\n\r\n if(this.isClosed) {\r\n descKey = 'Chat.Poll.Type.Closed';\r\n this.classList.add('is-closed');\r\n } else if(this.isQuiz) {\r\n descKey = this.isPublic ? 'Chat.Poll.Type.Quiz' : 'Chat.Poll.Type.AnonymousQuiz';\r\n } else {\r\n descKey = this.isPublic ? 'Chat.Poll.Type.Public' : 'Chat.Poll.Type.Anonymous';\r\n }\r\n }\r\n\r\n this.classList.toggle('is-multiple', this.isMultiple);\r\n\r\n const multipleSelect = this.isMultiple ? '<span class=\"poll-answer-selected tgico-check\"></span>' : '';\r\n const votes = poll.answers.map((answer, idx) => {\r\n return `\r\n <div class=\"poll-answer\" data-index=\"${idx}\">\r\n <div class=\"circle-hover\">\r\n <div class=\"animation-ring\"></div>\r\n <svg class=\"progress-ring\">\r\n <circle class=\"progress-ring__circle\" cx=\"13\" cy=\"13\" r=\"9\"></circle>\r\n </svg>\r\n ${multipleSelect}\r\n </div>\r\n <div class=\"poll-answer-percents\"></div>\r\n <div class=\"poll-answer-text\"></div>\r\n <svg version=\"1.1\" class=\"poll-line\" style=\"display: none;\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" viewBox=\"0 0 485.9 35\" xml:space=\"preserve\">\r\n <use href=\"#poll-line\"></use>\r\n </svg>\r\n <span class=\"poll-answer-selected tgico\"></span>\r\n </div>\r\n `;\r\n }).join('');\r\n\r\n this.innerHTML = `\r\n <div class=\"poll-title\"></div>\r\n <div class=\"poll-desc\">\r\n <div class=\"poll-type\"></div>\r\n <div class=\"poll-avatars\"></div>\r\n </div>\r\n ${votes}`;\r\n \r\n setInnerHTML(this.firstElementChild, RichTextProcessor.wrapEmojiText(poll.question));\r\n\r\n Array.from(this.querySelectorAll('.poll-answer-text')).forEach((el, idx) => {\r\n setInnerHTML(el, RichTextProcessor.wrapEmojiText(poll.answers[idx].text));\r\n });\r\n\r\n this.descDiv = this.firstElementChild.nextElementSibling as HTMLElement;\r\n this.typeDiv = this.descDiv.firstElementChild as HTMLElement;\r\n this.avatarsDiv = this.descDiv.lastElementChild as HTMLElement;\r\n\r\n if(descKey) {\r\n this.typeDiv.append(i18n(descKey));\r\n }\r\n\r\n if(this.isQuiz) {\r\n this.classList.add('is-quiz');\r\n\r\n if(poll.close_period && poll.close_date) {\r\n const timeLeftDiv = document.createElement('div');\r\n timeLeftDiv.classList.add('poll-time');\r\n this.descDiv.append(timeLeftDiv);\r\n\r\n const svg = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\");\r\n //svg.setAttributeNS(null, 'viewBox', '0 0 15 15');\r\n svg.classList.add('poll-quiz-timer');\r\n\r\n this.quizTimer = svg;\r\n\r\n const strokeWidth = 2;\r\n const radius = 7;\r\n const circumference = 2 * Math.PI * radius;\r\n\r\n const circle = document.createElementNS(\"http://www.w3.org/2000/svg\", \"circle\");\r\n circle.classList.add('poll-quiz-timer-circle');\r\n circle.setAttributeNS(null, 'cx', '16');\r\n circle.setAttributeNS(null, 'cy', '16');\r\n circle.setAttributeNS(null, 'r', '' + radius);\r\n circle.setAttributeNS(null, 'stroke-width', '' + strokeWidth);\r\n\r\n svg.append(circle);\r\n this.descDiv.append(svg);\r\n \r\n const period = poll.close_period * 1000;\r\n const closeTime = (poll.close_date - serverTimeManager.serverTimeOffset) * 1000;\r\n\r\n //console.log('closeTime:', poll.close_date, serverTimeManager.serverTimeOffset, Date.now() / 1000 | 0);\r\n\r\n // let time = Date.now();\r\n // let percents = (closeTime - time) / period;\r\n\r\n // timeLeftDiv.innerHTML = String((closeTime - time) / 1000 + 1 | 0).toHHMMSS();\r\n\r\n // // @ts-ignore\r\n // circle.style.strokeDashoffset = circumference + percents * circumference;\r\n // circle.style.strokeDasharray = ${circumference} ${circumference};\r\n\r\n this.quizInterval = window.setInterval(() => {\r\n const time = Date.now();\r\n const percents = (closeTime - time) / period;\r\n const timeLeft = (closeTime - time) / 1000 + 1 | 0;\r\n timeLeftDiv.innerHTML = toHHMMSS(timeLeft);\r\n \r\n if (timeLeft <= 5) {\r\n timeLeftDiv.style.color = '#ee545c';\r\n circle.style.stroke = '#ee545c';\r\n }\r\n //timeLeftDiv.style.visibility = 'visible';\r\n\r\n // @ts-ignore\r\n circle.style.strokeDashoffset = circumference + percents * circumference;\r\n circle.style.strokeDasharray = `${circumference} ${circumference}`;\r\n\r\n if(time >= closeTime) {\r\n clearInterval(this.quizInterval);\r\n timeLeftDiv.innerHTML = '';\r\n // @ts-ignore\r\n circle.style.strokeDashoffset = circumference;\r\n this.quizInterval = 0;\r\n\r\n setTimeout(() => {\r\n // нужно запросить апдейт чтобы опрос обновился\r\n appPollsManager.getResults(this.message);\r\n }, 3e3);\r\n }\r\n }, 1e3);\r\n }\r\n }\r\n \r\n this.answerDivs = Array.from(this.querySelectorAll('.poll-answer')) as HTMLDivElement[];\r\n this.svgLines = Array.from(this.querySelectorAll('.poll-line')) as SVGSVGElement[];\r\n this.numberDivs = Array.from(this.querySelectorAll('.poll-answer-percents')) as HTMLDivElement[];\r\n\r\n const footerDiv = document.createElement('div');\r\n footerDiv.classList.add('poll-footer');\r\n\r\n this.viewResults = document.createElement('div');\r\n this.viewResults.className = 'poll-footer-button poll-view-results hide';\r\n this.viewResults.append(i18n('Chat.Poll.ViewResults'));\r\n\r\n this.votersCountDiv = document.createElement('div');\r\n this.votersCountDiv.className = 'poll-votes-count';\r\n\r\n footerDiv.append(this.viewResults, this.votersCountDiv);\r\n this.append(footerDiv);\r\n\r\n this.viewResults.addEventListener('click', (e) => {\r\n cancelEvent(e);\r\n\r\n if(!appSidebarRight.isTabExists(AppPollResultsTab)) {\r\n new AppPollResultsTab(appSidebarRight).open(this.message);\r\n }\r\n });\r\n ripple(this.viewResults);\r\n\r\n if(this.isMultiple) {\r\n this.sendVoteBtn = document.createElement('div');\r\n this.sendVoteBtn.classList.add('poll-footer-button', 'poll-send-vote');\r\n this.sendVoteBtn.append(i18n('Chat.Poll.SubmitVote'));\r\n ripple(this.sendVoteBtn);\r\n\r\n if(!poll.chosenIndexes.length) {\r\n this.votersCountDiv.classList.add('hide');\r\n }\r\n\r\n attachClickEvent(this.sendVoteBtn, (e) => {\r\n cancelEvent(e);\r\n /* const indexes = this.answerDivs.filter(el => el.classList.contains('is-chosing')).map(el => +el.dataset.index);\r\n if(indexes.length) {\r\n \r\n } */\r\n if(this.chosingIndexes.length) {\r\n this.sendVotes(this.chosingIndexes).then(() => {\r\n this.chosingIndexes.length = 0;\r\n this.answerDivs.forEach(el => {\r\n el.classList.remove('is-chosing');\r\n });\r\n });\r\n }\r\n });\r\n\r\n footerDiv.append(this.sendVoteBtn);\r\n }\r\n\r\n // const width = this.getBoundingClientRect().width;\r\n // const width = mediaSizes.active.poll.width;\r\n // this.maxLength = width + tailLength + this.maxOffset + -13.7; // 13 - position left\r\n\r\n const canVote = !(poll.chosenIndexes.length || this.isClosed);\r\n if(!canVote || this.isPublic) {\r\n this.performResults(results, poll.chosenIndexes, false);\r\n }\r\n\r\n if(canVote) {\r\n this.setVotersCount(results);\r\n attachClickEvent(this, this.clickHandler);\r\n }\r\n }\r\n\r\n initQuizHint(results: PollResults) {\r\n if(results.solution && results.solution_entities) {\r\n const toggleHint = document.createElement('div');\r\n toggleHint.classList.add('tgico-tip', 'poll-hint');\r\n this.descDiv.append(toggleHint);\r\n\r\n //let active = false;\r\n attachClickEvent(toggleHint, (e) => {\r\n cancelEvent(e);\r\n\r\n //active = true;\r\n toggleHint.classList.add('active');\r\n setQuizHint(results.solution, results.solution_entities, () => {\r\n //active = false;\r\n toggleHint.classList.remove('active');\r\n });\r\n });\r\n\r\n if(this.sentVote) {\r\n const correctResult = results.results.find(r => r.pFlags.correct);\r\n if(correctResult && !correctResult.pFlags.chosen) {\r\n toggleHint.click();\r\n }\r\n }\r\n }\r\n }\r\n\r\n clickHandler(e: Event) {\r\n const target = findUpClassName(e.target, 'poll-answer') as HTMLElement;\r\n if(!target) {\r\n return;\r\n }\r\n \r\n cancelEvent(e);\r\n const answerIndex = +target.dataset.index;\r\n if(this.isMultiple) {\r\n target.classList.toggle('is-chosing');\r\n\r\n const foundIndex = this.chosingIndexes.indexOf(answerIndex);\r\n if(foundIndex !== -1) {\r\n this.chosingIndexes.splice(foundIndex, 1);\r\n } else {\r\n this.chosingIndexes.push(answerIndex);\r\n }\r\n } else {\r\n this.sendVotes([answerIndex]);\r\n }\r\n \r\n /* target.classList.add('is-voting');\r\n setTimeout(() => { // simulate\r\n this.setResults([100, 0], answerIndex);\r\n target.classList.remove('is-voting');\r\n }, 1000); */\r\n }\r\n\r\n sendVotes(indexes: number[]) {\r\n if(this.sendVotePromise) return this.sendVotePromise;\r\n\r\n const targets = this.answerDivs.filter((_, idx) => indexes.includes(idx));\r\n targets.forEach(target => {\r\n target.classList.add('is-voting');\r\n });\r\n \r\n this.classList.add('disable-hover');\r\n this.sentVote = true;\r\n return this.sendVotePromise = appPollsManager.sendVote(this.message, indexes).then(() => {\r\n targets.forEach(target => {\r\n target.classList.remove('is-voting');\r\n });\r\n\r\n this.classList.remove('disable-hover');\r\n }).catch(() => {\r\n this.sentVote = false;\r\n }).finally(() => {\r\n this.sendVotePromise = null;\r\n });\r\n }\r\n\r\n performResults(results: PollResults, chosenIndexes: number[], animate = true) {\r\n if(!rootScope.settings.animationsEnabled) {\r\n animate = false;\r\n }\r\n\r\n if(this.isQuiz && (results.results?.length || this.isClosed)) {\r\n this.answerDivs.forEach((el, idx) => {\r\n el.classList.toggle('is-correct', !!results.results[idx].pFlags.correct);\r\n });\r\n\r\n if(this.initQuizHint) {\r\n this.initQuizHint(results);\r\n this.initQuizHint = null;\r\n }\r\n\r\n if(this.quizInterval) {\r\n clearInterval(this.quizInterval);\r\n this.quizInterval = 0;\r\n }\r\n\r\n if(this.quizTimer?.parentElement) {\r\n this.quizTimer.remove();\r\n }\r\n\r\n const timeEl = this.descDiv.querySelector('.poll-time');\r\n if(timeEl) {\r\n timeEl.remove();\r\n }\r\n }\r\n\r\n if(this.isClosed) {\r\n this.classList.add('is-closed');\r\n replaceContent(this.typeDiv, i18n('Chat.Poll.Type.Closed'));\r\n }\r\n\r\n // set chosen\r\n if(this.chosenIndexes.length !== chosenIndexes.length || this.isClosed) { // if we voted\r\n this.isRetracted = this.chosenIndexes.length && !chosenIndexes.length;\r\n this.chosenIndexes = chosenIndexes.slice();\r\n\r\n if(this.isRetracted) {\r\n attachClickEvent(this, this.clickHandler);\r\n } else {\r\n detachClickEvent(this, this.clickHandler);\r\n }\r\n }\r\n \r\n // is need update\r\n if(this.chosenIndexes.length || this.isRetracted || this.isClosed) {\r\n const percents = results.results.map(v => results.total_voters ? v.voters / results.total_voters * 100 : 0);\r\n\r\n this.classList.toggle('no-transition', !animate);\r\n if(animate) {\r\n SetTransition(this, '', !this.isRetracted, 340);\r\n }\r\n\r\n fastRaf(() => {\r\n this.setResults(this.isRetracted ? this.percents : percents, this.chosenIndexes, animate);\r\n this.percents = percents;\r\n this.isRetracted = false;\r\n });\r\n }\r\n \r\n this.setVotersCount(results);\r\n\r\n if(this.isPublic) {\r\n if(!this.isMultiple) {\r\n this.viewResults.classList.toggle('hide', !results.total_voters || !this.chosenIndexes.length);\r\n this.votersCountDiv.classList.toggle('hide', !!this.chosenIndexes.length);\r\n }\r\n\r\n const peerIds = (results.recent_voters || []).map(userId => userId.toPeerId());\r\n const stackedAvatars = new StackedAvatars({avatarSize: 16});\r\n stackedAvatars.render(peerIds);\r\n replaceContent(this.avatarsDiv, stackedAvatars.container);\r\n }\r\n\r\n if(this.isMultiple) {\r\n const isVoted = !!this.chosenIndexes.length;\r\n\r\n const hideSendVoteBtn = this.isClosed || isVoted;\r\n const hideViewResultsBtn = !this.isPublic || !results.total_voters || (!isVoted && !this.isClosed);\r\n this.sendVoteBtn.classList.toggle('hide', hideSendVoteBtn);\r\n this.viewResults.classList.toggle('hide', hideViewResultsBtn);\r\n this.votersCountDiv.classList.toggle('hide', !hideSendVoteBtn || !hideViewResultsBtn);\r\n }\r\n }\r\n\r\n setResults(percents: number[], chosenIndexes: number[], animate: boolean) {\r\n this.svgLines.forEach(svg => svg.style.display = '');\r\n\r\n this.answerDivs.forEach((el, idx) => {\r\n el.classList.toggle('is-chosen', chosenIndexes.includes(idx));\r\n });\r\n\r\n const maxValue = Math.max(...percents);\r\n // this.maxLengths = percents.map(p => p / maxValue * this.maxLength);\r\n this.maxPercents = percents.map(p => p / maxValue);\r\n\r\n // line\r\n if(this.isRetracted) {\r\n this.svgLines.forEach((svg, idx) => {\r\n this.setLineProgress(idx, -1);\r\n });\r\n } else {\r\n const cb = () => {\r\n this.svgLines.forEach((svg, idx) => {\r\n //void svg.getBoundingClientRect(); // reflow\r\n this.setLineProgress(idx, 1);\r\n });\r\n };\r\n \r\n animate ? fastRaf(cb) : cb();\r\n }\r\n\r\n percents = percents.slice();\r\n roundPercents(percents);\r\n let getPercentValue: (percents: number, index: number) => number;\r\n const iterate = (i: number) => {\r\n percents.forEach((percents, idx) => {\r\n const value = getPercentValue(percents, i);\r\n this.numberDivs[idx].innerText = value + '%';\r\n });\r\n };\r\n // numbers\r\n if(this.isRetracted) {\r\n getPercentValue = (percents, index) => Math.round(percents / times * index);\r\n\r\n if(animate) {\r\n for(let i = (times - 1), k = 0; i >= 0; --i, ++k) {\r\n setTimeout(() => {\r\n iterate(i);\r\n }, oneTime * k);\r\n }\r\n } else {\r\n iterate(0);\r\n }\r\n } else {\r\n getPercentValue = (percents, index) => Math.round(percents / times * (index + 1));\r\n\r\n if(animate) {\r\n for(let i = 0; i < times; ++i) {\r\n setTimeout(() => {\r\n iterate(i);\r\n }, oneTime * i);\r\n }\r\n } else {\r\n iterate(times - 1);\r\n }\r\n }\r\n\r\n if(this.isRetracted) {\r\n if(animate) {\r\n this.classList.add('is-retracting');\r\n }\r\n\r\n this.classList.remove('is-voted');\r\n const cb = () => {\r\n this.svgLines.forEach(svg => svg.style.display = 'none');\r\n };\r\n\r\n if(animate) {\r\n setTimeout(() => {\r\n this.classList.remove('is-retracting');\r\n cb();\r\n }, fullTime);\r\n } else {\r\n cb();\r\n }\r\n } else {\r\n this.classList.add('is-voted');\r\n }\r\n }\r\n\r\n setVotersCount(results: PollResults) {\r\n const votersCount = results.total_voters || 0;\r\n let key: LangPackKey, args = [votersCount];\r\n if(this.isClosed) {\r\n if(this.isQuiz) key = votersCount ? 'Chat.Quiz.TotalVotes' : 'Chat.Quiz.TotalVotesResultEmpty';\r\n else key = votersCount ? 'Chat.Poll.TotalVotes1' : 'Chat.Poll.TotalVotesResultEmpty';\r\n } else {\r\n if(this.isQuiz) key = votersCount ? 'Chat.Quiz.TotalVotes' : 'Chat.Quiz.TotalVotesEmpty';\r\n else key = votersCount ? 'Chat.Poll.TotalVotes1' : 'Chat.Poll.TotalVotesEmpty';\r\n }\r\n \r\n replaceContent(this.votersCountDiv, i18n(key, args));\r\n }\r\n\r\n setLineProgress(index: number, multiplier: number) {\r\n const svg = this.svgLines[index];\r\n\r\n if(multiplier === -1) {\r\n svg.style.strokeDasharray = '';\r\n svg.style.strokeDashoffset = '';\r\n } else {\r\n // svg.style.strokeDasharray = (multiplier * this.maxLengths[index]) + ', 485.9';\r\n svg.style.strokeDasharray = (multiplier * this.maxPercents[index] * PollElement.MAX_LENGTH) + ', 485.9';\r\n // svg.style.strokeDasharray = (multiplier * this.maxPercents[index] * 100) + '%, 485.9';\r\n svg.style.strokeDashoffset = '' + multiplier * PollElement.MAX_OFFSET;\r\n }\r\n }\r\n\r\n // у элемента могут быть ещё другие методы и свойства\r\n}\r\n\r\ncustomElements.define(\"poll-element\", PollElement);\r\n","export default function createVideo(options: {\n pip?: boolean\n} = {}) {\n const video = document.createElement('video');\n if(!options.pip) video.disablePictureInPicture = true;\n video.setAttribute('playsinline', 'true');\n return video;\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport type Chat from './chat/chat';\r\nimport { getEmojiToneIndex } from '../vendor/emoji';\r\nimport deferredPromise from '../helpers/cancellablePromise';\r\nimport { formatFullSentTime } from '../helpers/date';\r\nimport mediaSizes, { MediaSizeType, ScreenSize } from '../helpers/mediaSizes';\r\nimport { IS_SAFARI } from '../environment/userAgent';\r\nimport { Message, MessageMedia, PhotoSize, StickerSet, WebPage } from '../layer';\r\nimport appDocsManager, { MyDocument } from \"../lib/appManagers/appDocsManager\";\r\nimport appMessagesManager from '../lib/appManagers/appMessagesManager';\r\nimport appPhotosManager, { MyPhoto } from '../lib/appManagers/appPhotosManager';\r\nimport LottieLoader from '../lib/rlottie/lottieLoader';\r\nimport webpWorkerController from '../lib/webp/webpWorkerController';\r\nimport animationIntersector from './animationIntersector';\r\nimport appMediaPlaybackController, { MediaSearchContext } from './appMediaPlaybackController';\r\nimport AudioElement, { findMediaTargets } from './audio';\r\nimport ReplyContainer from './chat/replyContainer';\r\nimport { Layouter, RectPart } from './groupedLayout';\r\nimport LazyLoadQueue from './lazyLoadQueue';\r\nimport PollElement from './poll';\r\nimport ProgressivePreloader from './preloader';\r\nimport './middleEllipsis';\r\nimport RichTextProcessor from '../lib/richtextprocessor';\r\nimport appImManager from '../lib/appManagers/appImManager';\r\nimport rootScope from '../lib/rootScope';\r\nimport { onMediaLoad } from '../helpers/files';\r\nimport { animateSingle } from '../helpers/animation';\r\nimport renderImageFromUrl from '../helpers/dom/renderImageFromUrl';\r\nimport sequentialDom from '../helpers/sequentialDom';\r\nimport { fastRaf } from '../helpers/schedulers';\r\nimport appDownloadManager, { DownloadBlob, ThumbCache } from '../lib/appManagers/appDownloadManager';\r\nimport appStickersManager from '../lib/appManagers/appStickersManager';\r\nimport cancelEvent from '../helpers/dom/cancelEvent';\r\nimport { attachClickEvent, simulateClickEvent } from '../helpers/dom/clickEvent';\r\nimport isInDOM from '../helpers/dom/isInDOM';\r\nimport lottieLoader from '../lib/rlottie/lottieLoader';\r\nimport { clearBadCharsAndTrim } from '../helpers/cleanSearchText';\r\nimport blur from '../helpers/blur';\r\nimport IS_WEBP_SUPPORTED from '../environment/webpSupport';\r\nimport MEDIA_MIME_TYPES_SUPPORTED from '../environment/mediaMimeTypesSupport';\r\nimport { MiddleEllipsisElement } from './middleEllipsis';\r\nimport { joinElementsWith } from '../lib/langPack';\r\nimport throttleWithRaf from '../helpers/schedulers/throttleWithRaf';\r\nimport { NULL_PEER_ID } from '../lib/mtproto/mtproto_config';\r\nimport findUpClassName from '../helpers/dom/findUpClassName';\r\nimport RLottiePlayer from '../lib/rlottie/rlottiePlayer';\r\nimport assumeType from '../helpers/assumeType';\r\nimport appMessagesIdsManager from '../lib/appManagers/appMessagesIdsManager';\r\nimport throttle from '../helpers/schedulers/throttle';\r\nimport { SendMessageEmojiInteractionData } from '../types';\r\nimport IS_VIBRATE_SUPPORTED from '../environment/vibrateSupport';\r\nimport Row from './row';\r\nimport { ChatAutoDownloadSettings } from '../helpers/autoDownload';\r\nimport formatBytes from '../helpers/formatBytes';\r\nimport toHHMMSS from '../helpers/string/toHHMMSS';\r\nimport createVideo from '../helpers/dom/createVideo';\r\nimport setInnerHTML from '../helpers/dom/setInnerHTML';\r\n\r\nconst MAX_VIDEO_AUTOPLAY_SIZE = 50 * 1024 * 1024; // 50 MB\r\n\r\nlet roundVideoCircumference = 0;\r\nmediaSizes.addEventListener('changeScreen', (from, to) => {\r\n if(to === ScreenSize.mobile || from === ScreenSize.mobile) {\r\n const elements = Array.from(document.querySelectorAll('.media-round .progress-ring')) as SVGSVGElement[];\r\n const width = mediaSizes.active.round.width;\r\n const halfSize = width / 2;\r\n const radius = halfSize - 7;\r\n roundVideoCircumference = 2 * Math.PI * radius;\r\n elements.forEach(element => {\r\n element.setAttributeNS(null, 'width', '' + width);\r\n element.setAttributeNS(null, 'height', '' + width);\r\n\r\n const circle = element.firstElementChild as SVGCircleElement;\r\n circle.setAttributeNS(null, 'cx', '' + halfSize);\r\n circle.setAttributeNS(null, 'cy', '' + halfSize);\r\n circle.setAttributeNS(null, 'r', '' + radius);\r\n\r\n circle.style.strokeDasharray = roundVideoCircumference + ' ' + roundVideoCircumference;\r\n circle.style.strokeDashoffset = '' + roundVideoCircumference;\r\n });\r\n }\r\n});\r\n\r\nexport function wrapVideo({doc, container, message, boxWidth, boxHeight, withTail, isOut, middleware, lazyLoadQueue, noInfo, group, onlyPreview, withoutPreloader, loadPromises, noPlayButton, size, searchContext, autoDownload}: {\r\n doc: MyDocument, \r\n container?: HTMLElement, \r\n message?: Message.message, \r\n boxWidth?: number, \r\n boxHeight?: number, \r\n withTail?: boolean, \r\n isOut?: boolean,\r\n middleware?: () => boolean,\r\n lazyLoadQueue?: LazyLoadQueue,\r\n noInfo?: true,\r\n noPlayButton?: boolean,\r\n group?: string,\r\n onlyPreview?: boolean,\r\n withoutPreloader?: boolean,\r\n loadPromises?: Promise<any>[],\r\n autoDownload?: ChatAutoDownloadSettings,\r\n size?: PhotoSize,\r\n searchContext?: MediaSearchContext,\r\n}) {\r\n const autoDownloadSize = autoDownload?.video;\r\n let noAutoDownload = autoDownloadSize === 0;\r\n const isAlbumItem = !(boxWidth && boxHeight);\r\n const canAutoplay = /* doc.sticker || */(\r\n (\r\n doc.type !== 'video' || (\r\n doc.size <= MAX_VIDEO_AUTOPLAY_SIZE && \r\n !isAlbumItem\r\n )\r\n ) && (doc.type === 'gif' ? rootScope.settings.autoPlay.gifs : rootScope.settings.autoPlay.videos)\r\n );\r\n let spanTime: HTMLElement, spanPlay: HTMLElement;\r\n\r\n if(!noInfo) {\r\n spanTime = document.createElement('span');\r\n spanTime.classList.add('video-time');\r\n container.append(spanTime);\r\n \r\n let needPlayButton = false;\r\n if(doc.type !== 'gif') {\r\n spanTime.innerText = toHHMMSS(doc.duration, false);\r\n\r\n if(!noPlayButton && doc.type !== 'round') {\r\n if(canAutoplay && !noAutoDownload) {\r\n spanTime.classList.add('tgico', 'can-autoplay');\r\n } else {\r\n needPlayButton = true;\r\n }\r\n }\r\n } else {\r\n spanTime.innerText = 'GIF';\r\n\r\n if(!canAutoplay && !noPlayButton) {\r\n needPlayButton = true;\r\n noAutoDownload = undefined;\r\n }\r\n }\r\n\r\n if(needPlayButton) {\r\n spanPlay = document.createElement('span');\r\n spanPlay.classList.add('video-play', 'tgico-largeplay', 'btn-circle', 'position-center');\r\n container.append(spanPlay);\r\n }\r\n }\r\n\r\n let res: {\r\n thumb?: typeof photoRes,\r\n loadPromise: Promise<any>\r\n } = {} as any;\r\n\r\n if(doc.mime_type === 'image/gif') {\r\n const photoRes = wrapPhoto({\r\n photo: doc, \r\n message, \r\n container, \r\n boxWidth, \r\n boxHeight, \r\n withTail, \r\n isOut, \r\n lazyLoadQueue, \r\n middleware,\r\n withoutPreloader,\r\n loadPromises,\r\n autoDownloadSize,\r\n size\r\n });\r\n\r\n res.thumb = photoRes;\r\n res.loadPromise = photoRes.loadPromises.full;\r\n return res;\r\n }\r\n\r\n /* const video = doc.type === 'round' ? appMediaPlaybackController.addMedia(doc, message.mid) as HTMLVideoElement : document.createElement('video');\r\n if(video.parentElement) {\r\n video.remove();\r\n } */\r\n\r\n let preloader: ProgressivePreloader; // it must be here, otherwise will get error before initialization in round onPlay\r\n\r\n const video = createVideo();\r\n video.classList.add('media-video');\r\n video.muted = true;\r\n if(doc.type === 'round') {\r\n const divRound = document.createElement('div');\r\n divRound.classList.add('media-round', 'z-depth-1');\r\n divRound.dataset.mid = '' + message.mid;\r\n divRound.dataset.peerId = '' + message.peerId;\r\n (divRound as any).message = message;\r\n\r\n const size = mediaSizes.active.round;\r\n const halfSize = size.width / 2;\r\n const strokeWidth = 3.5;\r\n const radius = halfSize - (strokeWidth * 2);\r\n divRound.innerHTML = `<svg class=\"progress-ring\" width=\"${size.width}\" height=\"${size.width}\" style=\"transform: rotate(-90deg);\">\r\n <circle class=\"progress-ring__circle\" stroke=\"white\" stroke-opacity=\"0.3\" stroke-width=\"${strokeWidth}\" cx=\"${halfSize}\" cy=\"${halfSize}\" r=\"${radius}\" fill=\"transparent\"/>\r\n </svg>`;\r\n\r\n const circle = divRound.firstElementChild.firstElementChild as SVGCircleElement;\r\n if(!roundVideoCircumference) {\r\n roundVideoCircumference = 2 * Math.PI * radius;\r\n }\r\n circle.style.strokeDasharray = roundVideoCircumference + ' ' + roundVideoCircumference;\r\n circle.style.strokeDashoffset = '' + roundVideoCircumference;\r\n \r\n spanTime.classList.add('tgico');\r\n\r\n const isUnread = message.pFlags.media_unread;\r\n if(isUnread) {\r\n divRound.classList.add('is-unread');\r\n }\r\n\r\n const canvas = document.createElement('canvas');\r\n canvas.width = canvas.height = doc.w/* * window.devicePixelRatio */;\r\n\r\n divRound.prepend(canvas, spanTime);\r\n divRound.append(video);\r\n container.append(divRound);\r\n\r\n const ctx = canvas.getContext('2d');\r\n /* ctx.beginPath();\r\n ctx.arc(canvas.width / 2, canvas.height / 2, canvas.width / 2, 0, Math.PI * 2);\r\n ctx.clip(); */\r\n\r\n const onLoad = () => {\r\n const message: Message.message = (divRound as any).message;\r\n const globalVideo = appMediaPlaybackController.addMedia(message, !noAutoDownload) as HTMLVideoElement;\r\n const clear = () => {\r\n (appImManager.chat.setPeerPromise || Promise.resolve()).finally(() => {\r\n if(isInDOM(globalVideo)) {\r\n return;\r\n }\r\n \r\n globalVideo.removeEventListener('play', onPlay);\r\n globalVideo.removeEventListener('timeupdate', throttledTimeUpdate);\r\n globalVideo.removeEventListener('pause', onPaused);\r\n globalVideo.removeEventListener('ended', onEnded);\r\n });\r\n };\r\n \r\n const onFrame = () => {\r\n ctx.drawImage(globalVideo, 0, 0);\r\n \r\n const offset = roundVideoCircumference - globalVideo.currentTime / globalVideo.duration * roundVideoCircumference;\r\n circle.style.strokeDashoffset = '' + offset;\r\n \r\n return !globalVideo.paused;\r\n };\r\n\r\n const onTimeUpdate = () => {\r\n if(!globalVideo.duration) {\r\n return;\r\n }\r\n \r\n if(!isInDOM(globalVideo)) {\r\n clear();\r\n return;\r\n }\r\n\r\n if(globalVideo.paused) {\r\n onFrame();\r\n }\r\n \r\n spanTime.innerText = toHHMMSS(globalVideo.duration - globalVideo.currentTime, false);\r\n };\r\n\r\n const throttledTimeUpdate = throttleWithRaf(onTimeUpdate);\r\n \r\n const onPlay = () => {\r\n video.classList.add('hide');\r\n divRound.classList.remove('is-paused');\r\n animateSingle(onFrame, canvas);\r\n \r\n if(preloader && preloader.preloader && preloader.preloader.classList.contains('manual')) {\r\n preloader.onClick();\r\n }\r\n };\r\n \r\n const onPaused = () => {\r\n if(!isInDOM(globalVideo)) {\r\n clear();\r\n return;\r\n }\r\n \r\n divRound.classList.add('is-paused');\r\n };\r\n \r\n const onEnded = () => {\r\n video.classList.remove('hide');\r\n divRound.classList.add('is-paused');\r\n \r\n video.currentTime = 0;\r\n spanTime.innerText = toHHMMSS(globalVideo.duration, false);\r\n \r\n if(globalVideo.currentTime) {\r\n globalVideo.currentTime = 0;\r\n }\r\n };\r\n \r\n globalVideo.addEventListener('play', onPlay);\r\n globalVideo.addEventListener('timeupdate', throttledTimeUpdate);\r\n globalVideo.addEventListener('pause', onPaused);\r\n globalVideo.addEventListener('ended', onEnded);\r\n \r\n attachClickEvent(canvas, (e) => {\r\n cancelEvent(e);\r\n \r\n // ! костыль\r\n if(preloader && !preloader.detached) {\r\n preloader.onClick();\r\n }\r\n \r\n // ! can't use it here. on Safari iOS video won't start.\r\n /* if(globalVideo.readyState < 2) {\r\n return;\r\n } */\r\n \r\n if(globalVideo.paused) {\r\n const hadSearchContext = !!searchContext;\r\n if(appMediaPlaybackController.setSearchContext(searchContext || {\r\n peerId: NULL_PEER_ID, \r\n inputFilter: {_: 'inputMessagesFilterEmpty'}, \r\n useSearch: false\r\n })) {\r\n const [prev, next] = !hadSearchContext ? [] : findMediaTargets(divRound, message.mid/* , searchContext.useSearch */);\r\n appMediaPlaybackController.setTargets({peerId: message.peerId, mid: message.mid}, prev, next);\r\n }\r\n \r\n globalVideo.play();\r\n } else {\r\n globalVideo.pause();\r\n }\r\n });\r\n \r\n if(globalVideo.paused) {\r\n if(globalVideo.duration && globalVideo.currentTime !== globalVideo.duration && globalVideo.currentTime > 0) {\r\n onFrame();\r\n onTimeUpdate();\r\n video.classList.add('hide');\r\n } else {\r\n onPaused();\r\n }\r\n } else {\r\n onPlay();\r\n }\r\n };\r\n\r\n if(message.pFlags.is_outgoing) {\r\n (divRound as any).onLoad = onLoad;\r\n divRound.dataset.isOutgoing = '1';\r\n } else {\r\n onLoad();\r\n }\r\n } else {\r\n video.autoplay = true; // для safari\r\n }\r\n\r\n let photoRes: ReturnType<typeof wrapPhoto>;\r\n if(message) {\r\n photoRes = wrapPhoto({\r\n photo: doc, \r\n message, \r\n container, \r\n boxWidth, \r\n boxHeight, \r\n withTail, \r\n isOut, \r\n lazyLoadQueue, \r\n middleware,\r\n withoutPreloader: true,\r\n loadPromises,\r\n autoDownloadSize: autoDownload?.photo,\r\n size\r\n });\r\n\r\n res.thumb = photoRes;\r\n\r\n if((!canAutoplay && doc.type !== 'gif') || onlyPreview) {\r\n res.loadPromise = photoRes.loadPromises.full;\r\n return res;\r\n }\r\n\r\n if(withTail) {\r\n const foreignObject = (photoRes.images.thumb || photoRes.images.full).parentElement;\r\n video.width = +foreignObject.getAttributeNS(null, 'width');\r\n video.height = +foreignObject.getAttributeNS(null, 'height');\r\n foreignObject.append(video);\r\n }\r\n } else { // * gifs masonry\r\n const gotThumb = appDocsManager.getThumb(doc, false);\r\n if(gotThumb) {\r\n gotThumb.promise.then(() => {\r\n video.poster = gotThumb.cacheContext.url;\r\n });\r\n }\r\n }\r\n\r\n if(!video.parentElement && container) {\r\n (photoRes?.aspecter || container).append(video);\r\n }\r\n\r\n const cacheContext = appDownloadManager.getCacheContext(doc);\r\n\r\n const isUpload = !!(message?.media as any)?.preloader;\r\n if(isUpload) { // means upload\r\n preloader = (message.media as any).preloader as ProgressivePreloader;\r\n preloader.attach(container, false);\r\n noAutoDownload = undefined;\r\n } else if(!cacheContext.downloaded && !doc.supportsStreaming && !withoutPreloader) {\r\n preloader = new ProgressivePreloader({\r\n attachMethod: 'prepend'\r\n });\r\n } else if(doc.supportsStreaming) {\r\n preloader = new ProgressivePreloader({\r\n cancelable: false,\r\n attachMethod: 'prepend'\r\n });\r\n }\r\n\r\n const renderDeferred = deferredPromise<void>();\r\n video.addEventListener('error', (e) => {\r\n if(video.error.code !== 4) {\r\n console.error(\"Error \" + video.error.code + \"; details: \" + video.error.message);\r\n }\r\n \r\n if(preloader && !isUpload) {\r\n preloader.detach();\r\n }\r\n\r\n if(!renderDeferred.isFulfilled) {\r\n renderDeferred.resolve();\r\n }\r\n }, {once: true});\r\n\r\n onMediaLoad(video).then(() => {\r\n if(group) {\r\n animationIntersector.addAnimation(video, group);\r\n }\r\n\r\n if(preloader && !isUpload) {\r\n preloader.detach();\r\n }\r\n\r\n renderDeferred.resolve();\r\n });\r\n\r\n if(doc.type === 'video') {\r\n const onTimeUpdate = () => {\r\n if(!video.videoWidth) {\r\n return;\r\n }\r\n \r\n spanTime.innerText = toHHMMSS(video.duration - video.currentTime, false);\r\n };\r\n\r\n const throttledTimeUpdate = throttleWithRaf(onTimeUpdate);\r\n\r\n video.addEventListener('timeupdate', throttledTimeUpdate);\r\n\r\n if(spanPlay) {\r\n video.addEventListener('timeupdate', () => {\r\n sequentialDom.mutateElement(spanPlay, () => {\r\n spanPlay.remove();\r\n });\r\n }, {once: true});\r\n }\r\n }\r\n\r\n video.muted = true;\r\n video.loop = true;\r\n //video.play();\r\n video.autoplay = true;\r\n\r\n let loadPhotoThumbFunc = noAutoDownload && photoRes?.preloader?.loadFunc;\r\n const load = () => {\r\n if(preloader && noAutoDownload && !withoutPreloader) {\r\n preloader.construct();\r\n preloader.setManual();\r\n }\r\n\r\n let loadPromise: Promise<any> = Promise.resolve();\r\n if((preloader && !isUpload) || withoutPreloader) {\r\n if(!cacheContext.downloaded && !doc.supportsStreaming) {\r\n const promise = loadPromise = appDocsManager.downloadDoc(doc, lazyLoadQueue?.queueId, noAutoDownload);\r\n if(preloader) {\r\n preloader.attach(container, false, promise);\r\n }\r\n } else if(doc.supportsStreaming) {\r\n if(noAutoDownload) {\r\n loadPromise = Promise.reject();\r\n } else if(!cacheContext.downloaded && preloader) { // * check for uploading video\r\n preloader.attach(container, false, null);\r\n video.addEventListener(IS_SAFARI ? 'timeupdate' : 'canplay', () => {\r\n preloader.detach();\r\n }, {once: true});\r\n }\r\n }\r\n }\r\n\r\n if(!noAutoDownload && loadPhotoThumbFunc) {\r\n loadPhotoThumbFunc();\r\n loadPhotoThumbFunc = null;\r\n }\r\n\r\n noAutoDownload = undefined;\r\n\r\n loadPromise.then(() => {\r\n if(middleware && !middleware()) {\r\n renderDeferred.resolve();\r\n return;\r\n }\r\n\r\n if(doc.type === 'round') {\r\n appMediaPlaybackController.resolveWaitingForLoadMedia(message.peerId, message.mid, message.pFlags.is_scheduled);\r\n }\r\n\r\n renderImageFromUrl(video, cacheContext.url);\r\n }, () => {});\r\n\r\n return {download: loadPromise, render: renderDeferred};\r\n };\r\n\r\n if(preloader && !isUpload) {\r\n preloader.setDownloadFunction(load);\r\n }\r\n\r\n /* if(doc.size >= 20e6 && !doc.downloaded) {\r\n let downloadDiv = document.createElement('div');\r\n downloadDiv.classList.add('download');\r\n\r\n let span = document.createElement('span');\r\n span.classList.add('btn-circle', 'tgico-download');\r\n downloadDiv.append(span);\r\n\r\n downloadDiv.addEventListener('click', () => {\r\n downloadDiv.remove();\r\n loadVideo();\r\n });\r\n\r\n container.prepend(downloadDiv);\r\n\r\n return;\r\n } */\r\n\r\n if(doc.type === 'gif' && !canAutoplay) {\r\n attachClickEvent(container, (e) => {\r\n cancelEvent(e);\r\n spanPlay.remove();\r\n load();\r\n }, {capture: true, once: true});\r\n } else {\r\n res.loadPromise = !lazyLoadQueue ? load().render : (lazyLoadQueue.push({div: container, load: () => load().render}), Promise.resolve());\r\n }\r\n\r\n return res;\r\n}\r\n\r\nrootScope.addEventListener('download_start', (docId) => {\r\n const elements = Array.from(document.querySelectorAll(`.document[data-doc-id=\"${docId}\"]`)) as HTMLElement[];\r\n elements.forEach(element => {\r\n if(element.querySelector('.preloader-container.manual')) {\r\n simulateClickEvent(element);\r\n }\r\n });\r\n});\r\n\r\nexport function wrapDocument({message, withTime, fontWeight, voiceAsMusic, showSender, searchContext, loadPromises, autoDownloadSize, lazyLoadQueue, sizeType}: {\r\n message: Message.message, \r\n withTime?: boolean,\r\n fontWeight?: number,\r\n voiceAsMusic?: boolean,\r\n showSender?: boolean,\r\n searchContext?: MediaSearchContext,\r\n loadPromises?: Promise<any>[],\r\n autoDownloadSize?: number,\r\n lazyLoadQueue?: LazyLoadQueue,\r\n sizeType?: MediaSizeType\r\n}): HTMLElement {\r\n if(!fontWeight) fontWeight = 500;\r\n if(!sizeType) sizeType = '' as any;\r\n const noAutoDownload = autoDownloadSize === 0;\r\n\r\n const doc = ((message.media as MessageMedia.messageMediaDocument).document || ((message.media as MessageMedia.messageMediaWebPage).webpage as WebPage.webPage).document) as MyDocument;\r\n const uploading = message.pFlags.is_outgoing && (message.media as any)?.preloader;\r\n if(doc.type === 'audio' || doc.type === 'voice' || doc.type === 'round') {\r\n const audioElement = new AudioElement();\r\n audioElement.withTime = withTime;\r\n audioElement.message = message;\r\n audioElement.noAutoDownload = noAutoDownload;\r\n audioElement.lazyLoadQueue = lazyLoadQueue;\r\n audioElement.loadPromises = loadPromises;\r\n \r\n if(voiceAsMusic) audioElement.voiceAsMusic = voiceAsMusic;\r\n if(searchContext) audioElement.searchContext = searchContext;\r\n if(showSender) audioElement.showSender = showSender;\r\n if(uploading) audioElement.preloader = (message.media as any).preloader;\r\n\r\n audioElement.dataset.fontWeight = '' + fontWeight;\r\n audioElement.dataset.sizeType = sizeType;\r\n audioElement.render();\r\n return audioElement;\r\n }\r\n\r\n let extSplitted = doc.file_name ? doc.file_name.split('.') : '';\r\n let ext = '';\r\n ext = extSplitted.length > 1 && Array.isArray(extSplitted) ? \r\n clearBadCharsAndTrim(extSplitted.pop().split(' ', 1)[0].toLowerCase()) : \r\n 'file';\r\n\r\n let docDiv = document.createElement('div');\r\n docDiv.classList.add('document', `ext-${ext}`);\r\n docDiv.dataset.docId = '' + doc.id;\r\n\r\n const icoDiv = document.createElement('div');\r\n icoDiv.classList.add('document-ico');\r\n\r\n const cacheContext = appDownloadManager.getCacheContext(doc);\r\n if((doc.thumbs?.length || (message.pFlags.is_outgoing && cacheContext.url && doc.type === 'photo'))/* && doc.mime_type !== 'image/gif' */) {\r\n docDiv.classList.add('document-with-thumb');\r\n\r\n let imgs: (HTMLImageElement | HTMLCanvasElement)[] = [];\r\n // ! WARNING, use thumbs for check when thumb will be generated for media\r\n if(message.pFlags.is_outgoing && ['photo', 'video'].includes(doc.type)) {\r\n icoDiv.innerHTML = `<img src=\"${cacheContext.url}\">`;\r\n imgs.push(icoDiv.firstElementChild as HTMLImageElement);\r\n } else {\r\n const wrapped = wrapPhoto({\r\n photo: doc, \r\n message: null, \r\n container: icoDiv, \r\n boxWidth: 54, \r\n boxHeight: 54,\r\n loadPromises,\r\n withoutPreloader: true,\r\n lazyLoadQueue,\r\n size: appPhotosManager.choosePhotoSize(doc, 54, 54, true)\r\n });\r\n icoDiv.style.width = icoDiv.style.height = '';\r\n if(wrapped.images.thumb) imgs.push(wrapped.images.thumb);\r\n if(wrapped.images.full) imgs.push(wrapped.images.full);\r\n }\r\n\r\n imgs.forEach(img => img.classList.add('document-thumb'));\r\n } else {\r\n icoDiv.innerText = ext;\r\n }\r\n\r\n //let fileName = stringMiddleOverflow(doc.file_name || 'Unknown.file', 26);\r\n let fileName = doc.file_name ? RichTextProcessor.wrapPlainText(doc.file_name) : 'Unknown.file';\r\n const descriptionEl = document.createElement('div');\r\n descriptionEl.classList.add('document-description');\r\n const descriptionParts: (HTMLElement | string | DocumentFragment)[] = [formatBytes(doc.size)];\r\n \r\n if(withTime) {\r\n descriptionParts.push(formatFullSentTime(message.date));\r\n }\r\n\r\n if(showSender) {\r\n descriptionParts.push(appMessagesManager.wrapSenderToPeer(message));\r\n }\r\n\r\n docDiv.innerHTML = `\r\n ${(cacheContext.downloaded && !uploading) || !message.mid ? '' : `<div class=\"document-download\"></div>`}\r\n <div class=\"document-name\"></div>\r\n <div class=\"document-size\"></div>\r\n `;\r\n\r\n const nameDiv = docDiv.querySelector('.document-name') as HTMLElement;\r\n const middleEllipsisEl = new MiddleEllipsisElement();\r\n middleEllipsisEl.dataset.fontWeight = '' + fontWeight;\r\n middleEllipsisEl.dataset.sizeType = sizeType;\r\n middleEllipsisEl.textContent = fileName;\r\n // setInnerHTML(middleEllipsisEl, fileName);\r\n\r\n nameDiv.append(middleEllipsisEl);\r\n\r\n if(showSender) {\r\n nameDiv.append(appMessagesManager.wrapSentTime(message));\r\n }\r\n\r\n const sizeDiv = docDiv.querySelector('.document-size') as HTMLElement;\r\n sizeDiv.append(...joinElementsWith(descriptionParts, ' · '));\r\n\r\n docDiv.prepend(icoDiv);\r\n\r\n if(!uploading && message.pFlags.is_outgoing && !message.mid) {\r\n return docDiv;\r\n }\r\n\r\n let downloadDiv: HTMLElement, preloader: ProgressivePreloader = null;\r\n const onLoad = () => {\r\n if(downloadDiv) {\r\n downloadDiv.classList.add('downloaded');\r\n const _downloadDiv = downloadDiv;\r\n setTimeout(() => {\r\n _downloadDiv.remove();\r\n }, 200);\r\n downloadDiv = null;\r\n }\r\n\r\n if(preloader) {\r\n preloader = null;\r\n }\r\n };\r\n\r\n const load = (e?: Event) => {\r\n const save = !e || e.isTrusted;\r\n const doc = appDocsManager.getDoc(docDiv.dataset.docId);\r\n let download: DownloadBlob;\r\n const queueId = appImManager.chat.bubbles ? appImManager.chat.bubbles.lazyLoadQueue.queueId : undefined;\r\n if(!save) {\r\n download = appDocsManager.downloadDoc(doc, queueId);\r\n } else if(doc.type === 'pdf') {\r\n const canOpenAfter = appDocsManager.downloading.has(doc.id) || cacheContext.downloaded;\r\n download = appDocsManager.downloadDoc(doc, queueId);\r\n if(canOpenAfter) {\r\n download.then(() => {\r\n setTimeout(() => { // wait for preloader animation end\r\n const url = appDownloadManager.getCacheContext(doc).url;\r\n window.open(url);\r\n }, rootScope.settings.animationsEnabled ? 250 : 0);\r\n });\r\n }\r\n } else if(MEDIA_MIME_TYPES_SUPPORTED.has(doc.mime_type) && doc.thumbs?.length) {\r\n download = appDocsManager.downloadDoc(doc, queueId);\r\n } else {\r\n download = appDocsManager.saveDocFile(doc, queueId);\r\n }\r\n\r\n if(downloadDiv) {\r\n download.then(onLoad);\r\n preloader.attach(downloadDiv, true, download);\r\n }\r\n\r\n return {download};\r\n };\r\n\r\n if(appDocsManager.downloading.has(doc.id)) {\r\n downloadDiv = docDiv.querySelector('.document-download');\r\n preloader = new ProgressivePreloader();\r\n preloader.attach(downloadDiv, false, appDocsManager.downloading.get(doc.id));\r\n } else if(!cacheContext.downloaded || uploading) {\r\n downloadDiv = docDiv.querySelector('.document-download');\r\n preloader = (message.media as any).preloader as ProgressivePreloader;\r\n\r\n if(!preloader) {\r\n preloader = new ProgressivePreloader();\r\n\r\n preloader.construct();\r\n preloader.setManual();\r\n preloader.attach(downloadDiv);\r\n preloader.setDownloadFunction(load);\r\n\r\n if(autoDownloadSize !== undefined && autoDownloadSize >= doc.size) {\r\n simulateClickEvent(preloader.preloader);\r\n }\r\n } else {\r\n preloader.attach(downloadDiv);\r\n (message.media as any).promise.then(onLoad);\r\n }\r\n }\r\n\r\n attachClickEvent(docDiv, (e) => {\r\n if(preloader) {\r\n preloader.onClick(e);\r\n } else {\r\n load(e);\r\n }\r\n });\r\n\r\n return docDiv;\r\n}\r\n\r\n/* function wrapMediaWithTail(photo: MyPhoto | MyDocument, message: {mid: number, message: string}, container: HTMLElement, boxWidth: number, boxHeight: number, isOut: boolean) {\r\n const svg = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\");\r\n svg.classList.add('bubble__media-container', isOut ? 'is-out' : 'is-in');\r\n \r\n const foreignObject = document.createElementNS(\"http://www.w3.org/2000/svg\", 'foreignObject');\r\n\r\n const gotThumb = appPhotosManager.getStrippedThumbIfNeeded(photo, true);\r\n if(gotThumb) {\r\n foreignObject.append(gotThumb.image);\r\n }\r\n appPhotosManager.setAttachmentSize(photo, foreignObject, boxWidth, boxHeight);\r\n \r\n const width = +foreignObject.getAttributeNS(null, 'width');\r\n const height = +foreignObject.getAttributeNS(null, 'height');\r\n\r\n svg.setAttributeNS(null, 'width', '' + width);\r\n svg.setAttributeNS(null, 'height', '' + height);\r\n\r\n svg.setAttributeNS(null, 'viewBox', '0 0 ' + width + ' ' + height);\r\n svg.setAttributeNS(null, 'preserveAspectRatio', 'none');\r\n\r\n const clipId = 'clip' + message.mid + '_' + nextRandomInt(9999);\r\n svg.dataset.clipId = clipId;\r\n \r\n const defs = document.createElementNS(\"http://www.w3.org/2000/svg\", 'defs');\r\n let clipPathHTML: string = '';\r\n \r\n if(message.message) {\r\n //clipPathHTML += `<rect width=\"${width}\" height=\"${height}\"></rect>`;\r\n } else {\r\n if(isOut) {\r\n clipPathHTML += `\r\n <use href=\"#message-tail\" transform=\"translate(${width - 2}, ${height}) scale(-1, -1)\"></use>\r\n <path />\r\n `;\r\n } else {\r\n clipPathHTML += `\r\n <use href=\"#message-tail\" transform=\"translate(2, ${height}) scale(1, -1)\"></use>\r\n <path />\r\n `;\r\n }\r\n }\r\n\r\n defs.innerHTML = `<clipPath id=\"${clipId}\">${clipPathHTML}</clipPath>`;\r\n \r\n container.style.width = parseInt(container.style.width) - 9 + 'px';\r\n container.classList.add('with-tail');\r\n\r\n svg.append(defs, foreignObject);\r\n container.append(svg);\r\n\r\n let img = foreignObject.firstElementChild as HTMLImageElement;\r\n if(!img) {\r\n foreignObject.append(img = new Image());\r\n }\r\n\r\n return img;\r\n} */\r\n\r\nexport function wrapPhoto({photo, message, container, boxWidth, boxHeight, withTail, isOut, lazyLoadQueue, middleware, size, withoutPreloader, loadPromises, autoDownloadSize, noBlur, noThumb, noFadeIn, blurAfter}: {\r\n photo: MyPhoto | MyDocument, \r\n message?: any, \r\n container: HTMLElement, \r\n boxWidth?: number, \r\n boxHeight?: number, \r\n withTail?: boolean, \r\n isOut?: boolean, \r\n lazyLoadQueue?: LazyLoadQueue, \r\n middleware?: () => boolean, \r\n size?: PhotoSize,\r\n withoutPreloader?: boolean,\r\n loadPromises?: Promise<any>[],\r\n autoDownloadSize?: number,\r\n noBlur?: boolean,\r\n noThumb?: boolean,\r\n noFadeIn?: boolean,\r\n blurAfter?: boolean,\r\n}) {\r\n if(!((photo as MyPhoto).sizes || (photo as MyDocument).thumbs)) {\r\n if(boxWidth && boxHeight && !size && photo._ === 'document') {\r\n appPhotosManager.setAttachmentSize(photo, container, boxWidth, boxHeight, undefined, message);\r\n }\r\n\r\n return {\r\n loadPromises: {\r\n thumb: Promise.resolve(),\r\n full: Promise.resolve()\r\n },\r\n images: {\r\n thumb: null,\r\n full: null\r\n },\r\n preloader: null,\r\n aspecter: null\r\n };\r\n }\r\n\r\n let noAutoDownload = autoDownloadSize === 0;\r\n\r\n if(!size) {\r\n if(boxWidth === undefined) boxWidth = mediaSizes.active.regular.width;\r\n if(boxHeight === undefined) boxHeight = mediaSizes.active.regular.height;\r\n }\r\n\r\n container.classList.add('media-container');\r\n let aspecter = container;\r\n\r\n let isFit = true;\r\n let loadThumbPromise: Promise<any> = Promise.resolve();\r\n let thumbImage: HTMLImageElement | HTMLCanvasElement;\r\n let image: HTMLImageElement;\r\n let cacheContext: ThumbCache;\r\n const isGif = photo._ === 'document' && photo.mime_type === 'image/gif' && !size;\r\n // if(withTail) {\r\n // image = wrapMediaWithTail(photo, message, container, boxWidth, boxHeight, isOut);\r\n // } else {\r\n image = new Image();\r\n\r\n if(boxWidth && boxHeight && !size) { // !album\r\n const set = appPhotosManager.setAttachmentSize(photo, container, boxWidth, boxHeight, undefined, message, undefined, isGif ? {\r\n _: 'photoSize',\r\n w: photo.w,\r\n h: photo.h,\r\n size: photo.size,\r\n type: 'full'\r\n } : undefined);\r\n size = set.photoSize;\r\n isFit = set.isFit;\r\n cacheContext = appDownloadManager.getCacheContext(photo, size.type);\r\n\r\n if(!isFit) {\r\n aspecter = document.createElement('div');\r\n aspecter.classList.add('media-container-aspecter');\r\n aspecter.style.width = set.size.width + 'px';\r\n aspecter.style.height = set.size.height + 'px';\r\n\r\n const gotThumb = appPhotosManager.getStrippedThumbIfNeeded(photo, cacheContext, !noBlur, true);\r\n if(gotThumb) {\r\n loadThumbPromise = gotThumb.loadPromise;\r\n const thumbImage = gotThumb.image; // local scope\r\n thumbImage.classList.add('media-photo');\r\n container.append(thumbImage);\r\n } else {\r\n const res = wrapPhoto({\r\n container,\r\n message,\r\n photo,\r\n boxWidth: 0,\r\n boxHeight: 0,\r\n size,\r\n lazyLoadQueue,\r\n isOut,\r\n loadPromises,\r\n middleware,\r\n withoutPreloader,\r\n withTail,\r\n autoDownloadSize,\r\n noBlur,\r\n noThumb: true,\r\n blurAfter: true\r\n //noFadeIn: true\r\n });\r\n const thumbImage = res.images.full;\r\n thumbImage.classList.add('media-photo', 'thumbnail');\r\n //container.append(thumbImage);\r\n }\r\n\r\n container.classList.add('media-container-fitted');\r\n container.append(aspecter);\r\n }\r\n } else {\r\n if(!size) {\r\n size = appPhotosManager.choosePhotoSize(photo, boxWidth, boxHeight, true);\r\n }\r\n \r\n cacheContext = appDownloadManager.getCacheContext(photo, size?.type);\r\n }\r\n\r\n if(!noThumb) {\r\n const gotThumb = appPhotosManager.getStrippedThumbIfNeeded(photo, cacheContext, !noBlur);\r\n if(gotThumb) {\r\n loadThumbPromise = Promise.all([loadThumbPromise, gotThumb.loadPromise]);\r\n thumbImage = gotThumb.image;\r\n thumbImage.classList.add('media-photo');\r\n aspecter.append(thumbImage);\r\n }\r\n }\r\n // }\r\n\r\n image.classList.add('media-photo');\r\n \r\n //console.log('wrapPhoto downloaded:', photo, photo.downloaded, container);\r\n\r\n const needFadeIn = (thumbImage || !cacheContext.downloaded) && rootScope.settings.animationsEnabled && !noFadeIn;\r\n\r\n let preloader: ProgressivePreloader;\r\n if(message?.media?.preloader && !withoutPreloader) { // means upload\r\n preloader = message.media.preloader;\r\n preloader.attach(container);\r\n noAutoDownload = undefined;\r\n } else if(!cacheContext.downloaded) {\r\n preloader = new ProgressivePreloader({\r\n attachMethod: 'prepend'\r\n });\r\n }\r\n\r\n const getDownloadPromise = () => {\r\n const promise = isGif && !size ? \r\n appDocsManager.downloadDoc(photo, /* undefined, */lazyLoadQueue?.queueId) : \r\n appPhotosManager.preloadPhoto(photo, size, lazyLoadQueue?.queueId, noAutoDownload);\r\n\r\n return promise;\r\n };\r\n\r\n const renderOnLoad = (url: string) => {\r\n return renderImageWithFadeIn(container, image, url, needFadeIn, aspecter, thumbImage);\r\n };\r\n\r\n const onLoad = (): Promise<void> => {\r\n if(middleware && !middleware()) return Promise.resolve();\r\n\r\n if(blurAfter) {\r\n const result = blur(cacheContext.url, 12);\r\n return result.promise.then(() => {\r\n // image = result.canvas;\r\n return renderOnLoad(result.canvas.toDataURL());\r\n });\r\n }\r\n\r\n return renderOnLoad(cacheContext.url);\r\n };\r\n\r\n let loadPromise: Promise<any>;\r\n const canAttachPreloader = (\r\n (size as PhotoSize.photoSize).w >= 150 && \r\n (size as PhotoSize.photoSize).h >= 150\r\n ) || noAutoDownload;\r\n const load = () => {\r\n if(noAutoDownload && !withoutPreloader && preloader) {\r\n preloader.construct();\r\n preloader.setManual();\r\n }\r\n\r\n const promise = getDownloadPromise();\r\n\r\n if(preloader && \r\n !cacheContext.downloaded && \r\n !withoutPreloader && \r\n canAttachPreloader\r\n ) {\r\n preloader.attach(container, false, promise);\r\n }\r\n\r\n noAutoDownload = undefined;\r\n\r\n const renderPromise = promise.then(onLoad);\r\n renderPromise.catch(() => {});\r\n return {download: promise, render: renderPromise};\r\n };\r\n\r\n if(preloader) {\r\n preloader.setDownloadFunction(load);\r\n }\r\n \r\n if(cacheContext.downloaded) {\r\n loadThumbPromise = loadPromise = load().render;\r\n } else {\r\n if(!lazyLoadQueue) loadPromise = load().render;\r\n /* else if(noAutoDownload) {\r\n preloader.construct();\r\n preloader.setManual();\r\n preloader.attach(container);\r\n } */ else lazyLoadQueue.push({div: container, load: () => load().download});\r\n }\r\n\r\n if(loadPromises && loadThumbPromise) {\r\n loadPromises.push(loadThumbPromise);\r\n }\r\n\r\n return {\r\n loadPromises: {\r\n thumb: loadThumbPromise,\r\n full: loadPromise || Promise.resolve()\r\n },\r\n images: {\r\n thumb: thumbImage,\r\n full: image\r\n },\r\n preloader,\r\n aspecter\r\n };\r\n}\r\n\r\nexport function renderImageWithFadeIn(\r\n container: HTMLElement, \r\n image: HTMLImageElement, \r\n url: string, \r\n needFadeIn: boolean, \r\n aspecter = container,\r\n thumbImage?: HTMLElement\r\n) {\r\n if(needFadeIn) {\r\n image.classList.add('fade-in');\r\n }\r\n\r\n return new Promise<void>((resolve) => {\r\n /* if(photo._ === 'document') {\r\n console.error('wrapPhoto: will render document', photo, size, cacheContext);\r\n return resolve();\r\n } */\r\n\r\n renderImageFromUrl(image, url, () => {\r\n sequentialDom.mutateElement(container, () => {\r\n aspecter.append(image);\r\n\r\n fastRaf(() => {\r\n resolve();\r\n });\r\n\r\n if(needFadeIn) {\r\n image.addEventListener('animationend', () => {\r\n sequentialDom.mutate(() => {\r\n image.classList.remove('fade-in');\r\n \r\n if(thumbImage) {\r\n thumbImage.remove();\r\n }\r\n });\r\n }, {once: true});\r\n }\r\n });\r\n });\r\n });\r\n}\r\n\r\n// export function renderImageWithFadeIn(container: HTMLElement, \r\n// image: HTMLImageElement, \r\n// url: string, \r\n// needFadeIn: boolean, \r\n// aspecter = container,\r\n// thumbImage?: HTMLImageElement\r\n// ) {\r\n// if(needFadeIn) {\r\n// // image.classList.add('fade-in-new', 'not-yet');\r\n// image.classList.add('fade-in');\r\n// }\r\n\r\n// return new Promise<void>((resolve) => {\r\n// /* if(photo._ === 'document') {\r\n// console.error('wrapPhoto: will render document', photo, size, cacheContext);\r\n// return resolve();\r\n// } */\r\n\r\n// renderImageFromUrl(image, url, () => {\r\n// sequentialDom.mutateElement(container, () => {\r\n// aspecter.append(image);\r\n// // (needFadeIn ? getHeavyAnimationPromise() : Promise.resolve()).then(() => {\r\n\r\n// // fastRaf(() => {\r\n// resolve();\r\n// // });\r\n\r\n// if(needFadeIn) {\r\n// fastRaf(() => {\r\n// /* if(!image.isConnected) {\r\n// alert('aaaa');\r\n// } */\r\n// // fastRaf(() => {\r\n// image.classList.remove('not-yet');\r\n// // });\r\n// });\r\n\r\n// image.addEventListener('transitionend', () => {\r\n// sequentialDom.mutate(() => {\r\n// image.classList.remove('fade-in-new');\r\n \r\n// if(thumbImage) {\r\n// thumbImage.remove();\r\n// }\r\n// });\r\n// }, {once: true});\r\n// }\r\n// // });\r\n// });\r\n// });\r\n// });\r\n// }\r\n\r\nexport function wrapStickerAnimation({\r\n size,\r\n doc,\r\n middleware,\r\n target,\r\n side,\r\n skipRatio,\r\n play\r\n}: {\r\n size: number,\r\n doc: MyDocument,\r\n middleware?: () => boolean,\r\n target: HTMLElement,\r\n side: 'left' | 'center' | 'right',\r\n skipRatio?: number,\r\n play: boolean\r\n}) {\r\n const animationDiv = document.createElement('div');\r\n animationDiv.classList.add('emoji-animation');\r\n\r\n // const size = 280;\r\n animationDiv.style.width = size + 'px';\r\n animationDiv.style.height = size + 'px';\r\n\r\n const stickerPromise = wrapSticker({\r\n div: animationDiv,\r\n doc,\r\n middleware,\r\n withThumb: false,\r\n needFadeIn: false,\r\n loop: false,\r\n width: size,\r\n height: size,\r\n play,\r\n group: 'none',\r\n skipRatio\r\n }).then(animation => {\r\n assumeType<RLottiePlayer>(animation);\r\n animation.addEventListener('enterFrame', (frameNo) => {\r\n if(frameNo === animation.maxFrame) {\r\n animation.remove();\r\n animationDiv.remove();\r\n appImManager.chat.bubbles.scrollable.container.removeEventListener('scroll', onScroll);\r\n }\r\n });\r\n\r\n if(IS_VIBRATE_SUPPORTED) {\r\n animation.addEventListener('firstFrame', () => {\r\n navigator.vibrate(100);\r\n }, {once: true});\r\n }\r\n\r\n return animation;\r\n });\r\n\r\n const generateRandomSigned = (max: number) => {\r\n const r = Math.random() * max * 2;\r\n return r > max ? -r % max : r;\r\n };\r\n\r\n const randomOffsetX = generateRandomSigned(16);\r\n const randomOffsetY = generateRandomSigned(4);\r\n const stableOffsetX = size / 8 * (side === 'right' ? 1 : -1);\r\n const setPosition = () => {\r\n if(!isInDOM(target)) {\r\n return;\r\n }\r\n \r\n const rect = target.getBoundingClientRect();\r\n /* const boxWidth = Math.max(rect.width, rect.height);\r\n const boxHeight = Math.max(rect.width, rect.height);\r\n const x = rect.left + ((boxWidth - size) / 2);\r\n const y = rect.top + ((boxHeight - size) / 2); */\r\n\r\n const rectX = side === 'right' ? rect.right : rect.left;\r\n\r\n const addOffsetX = side === 'center' ? (rect.width - size) / 2 : (side === 'right' ? -size : 0) + stableOffsetX + randomOffsetX;\r\n const x = rectX + addOffsetX;\r\n // const y = rect.bottom - size + size / 4;\r\n const y = rect.top + ((rect.height - size) / 2) + (side === 'center' ? 0 : randomOffsetY);\r\n // animationDiv.style.transform = `translate(${x}px, ${y}px)`;\r\n animationDiv.style.top = y + 'px';\r\n animationDiv.style.left = x + 'px';\r\n };\r\n\r\n const onScroll = throttleWithRaf(setPosition);\r\n\r\n appImManager.chat.bubbles.scrollable.container.addEventListener('scroll', onScroll);\r\n\r\n setPosition();\r\n\r\n appImManager.emojiAnimationContainer.append(animationDiv);\r\n\r\n return {animationDiv, stickerPromise};\r\n}\r\n\r\nexport function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, onlyThumb, emoji, width, height, withThumb, loop, loadPromises, needFadeIn, needUpscale, skipRatio, static: asStatic}: {\r\n doc: MyDocument, \r\n div: HTMLElement, \r\n middleware?: () => boolean, \r\n lazyLoadQueue?: LazyLoadQueue, \r\n group?: string, \r\n play?: boolean, \r\n onlyThumb?: boolean,\r\n emoji?: string,\r\n width?: number,\r\n height?: number,\r\n withThumb?: boolean,\r\n loop?: boolean,\r\n loadPromises?: Promise<any>[],\r\n needFadeIn?: boolean,\r\n needUpscale?: boolean,\r\n skipRatio?: number,\r\n static?: boolean\r\n}): Promise<RLottiePlayer | void> {\r\n const stickerType = doc.sticker;\r\n if(stickerType === 1) {\r\n asStatic = true;\r\n }\r\n\r\n if(!width) {\r\n width = !emoji ? 200 : undefined;\r\n }\r\n\r\n if(!height) {\r\n height = !emoji ? 200 : undefined;\r\n }\r\n\r\n if(stickerType === 2) {\r\n //LottieLoader.loadLottie();\r\n LottieLoader.loadLottieWorkers();\r\n }\r\n \r\n if(!stickerType) {\r\n console.error('wrong doc for wrapSticker!', doc);\r\n throw new Error('wrong doc for wrapSticker!');\r\n }\r\n\r\n div.dataset.docId = '' + doc.id;\r\n div.classList.add('media-sticker-wrapper');\r\n\r\n /* if(stickerType === 3) {\r\n const videoRes = wrapVideo({\r\n doc,\r\n boxWidth: width,\r\n boxHeight: height,\r\n container: div,\r\n group,\r\n lazyLoadQueue,\r\n middleware,\r\n withoutPreloader: true,\r\n loadPromises,\r\n noPlayButton: true,\r\n noInfo: true\r\n });\r\n\r\n if(videoRes.thumb) {\r\n if(videoRes.thumb.images.thumb) {\r\n videoRes.thumb.images.thumb.classList.add('media-sticker', 'thumbnail');\r\n }\r\n\r\n if(videoRes.thumb.images.full) {\r\n videoRes.thumb.images.full.classList.add('media-sticker');\r\n }\r\n }\r\n\r\n return videoRes.loadPromise;\r\n } */\r\n \r\n //console.log('wrap sticker', doc, div, onlyThumb);\r\n\r\n let cacheContext: ThumbCache;\r\n if(asStatic && stickerType !== 1) {\r\n const thumb = appPhotosManager.choosePhotoSize(doc, width, height, false) as PhotoSize.photoSize;\r\n cacheContext = appDownloadManager.getCacheContext(doc, thumb.type);\r\n } else {\r\n cacheContext = appDownloadManager.getCacheContext(doc);\r\n }\r\n\r\n const toneIndex = emoji ? getEmojiToneIndex(emoji) : -1;\r\n const downloaded = cacheContext.downloaded && !needFadeIn;\r\n\r\n const isAnimated = !asStatic && (stickerType === 2 || stickerType === 3);\r\n const isThumbNeededForType = isAnimated;\r\n \r\n let loadThumbPromise = deferredPromise<void>();\r\n let haveThumbCached = false;\r\n if((\r\n doc.thumbs?.length || \r\n doc.stickerCachedThumbs\r\n ) && \r\n !div.firstElementChild && (\r\n !downloaded || \r\n isThumbNeededForType || \r\n onlyThumb\r\n ) && withThumb !== false/* && doc.thumbs[0]._ !== 'photoSizeEmpty' */\r\n ) {\r\n let thumb = doc.stickerCachedThumbs && doc.stickerCachedThumbs[toneIndex] || doc.thumbs[0];\r\n \r\n //console.log('wrap sticker', thumb, div);\r\n\r\n let thumbImage: HTMLImageElement;\r\n const afterRender = () => {\r\n if(!div.childElementCount) {\r\n thumbImage.classList.add('media-sticker', 'thumbnail');\r\n \r\n sequentialDom.mutateElement(div, () => {\r\n div.append(thumbImage);\r\n loadThumbPromise.resolve();\r\n });\r\n }\r\n };\r\n\r\n if('url' in thumb) {\r\n thumbImage = new Image();\r\n renderImageFromUrl(thumbImage, thumb.url, afterRender);\r\n haveThumbCached = true;\r\n } else if('bytes' in thumb) {\r\n if(thumb._ === 'photoPathSize') {\r\n if(thumb.bytes.length) {\r\n const d = appPhotosManager.getPathFromPhotoPathSize(thumb);\r\n const svg = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\");\r\n svg.classList.add('rlottie-vector', 'media-sticker', 'thumbnail');\r\n svg.setAttributeNS(null, 'viewBox', `0 0 ${doc.w || 512} ${doc.h || 512}`);\r\n const path = document.createElementNS(\"http://www.w3.org/2000/svg\", \"path\");\r\n path.setAttributeNS(null, 'd', d);\r\n svg.append(path);\r\n div.append(svg);\r\n } else {\r\n thumb = doc.thumbs.find(t => (t as PhotoSize.photoStrippedSize).bytes?.length) || thumb;\r\n }\r\n } \r\n \r\n if(thumb && thumb._ !== 'photoPathSize' && toneIndex <= 0) {\r\n thumbImage = new Image();\r\n\r\n if((IS_WEBP_SUPPORTED || doc.pFlags.stickerThumbConverted || cacheContext.url)/* && false */) {\r\n renderImageFromUrl(thumbImage, appPhotosManager.getPreviewURLFromThumb(doc, thumb as PhotoSize.photoStrippedSize, true), afterRender);\r\n haveThumbCached = true;\r\n } else {\r\n webpWorkerController.convert('' + doc.id, (thumb as PhotoSize.photoStrippedSize).bytes as Uint8Array).then(bytes => {\r\n (thumb as PhotoSize.photoStrippedSize).bytes = bytes;\r\n doc.pFlags.stickerThumbConverted = true;\r\n \r\n if(middleware && !middleware()) return;\r\n \r\n if(!div.childElementCount) {\r\n renderImageFromUrl(thumbImage, appPhotosManager.getPreviewURLFromThumb(doc, thumb as PhotoSize.photoStrippedSize, true), afterRender);\r\n }\r\n }).catch(() => {});\r\n }\r\n }\r\n } else if(((stickerType === 2 && toneIndex <= 0) || stickerType === 3) && (withThumb || onlyThumb)) {\r\n thumbImage = new Image();\r\n\r\n const load = () => {\r\n if(div.childElementCount || (middleware && !middleware())) return;\r\n\r\n const r = () => {\r\n if(div.childElementCount || (middleware && !middleware())) return;\r\n renderImageFromUrl(thumbImage, cacheContext.url, afterRender);\r\n };\r\n \r\n if(cacheContext.url) {\r\n r();\r\n return Promise.resolve();\r\n } else {\r\n return appDocsManager.getThumbURL(doc, thumb as PhotoSize.photoStrippedSize).promise.then(r);\r\n }\r\n };\r\n \r\n if(lazyLoadQueue && onlyThumb) {\r\n lazyLoadQueue.push({div, load});\r\n return Promise.resolve();\r\n } else {\r\n load();\r\n\r\n if((thumb as any).url) {\r\n haveThumbCached = true;\r\n }\r\n }\r\n }\r\n }\r\n\r\n if(loadPromises && haveThumbCached) {\r\n loadPromises.push(loadThumbPromise);\r\n }\r\n\r\n if(onlyThumb) { // for sticker panel\r\n return Promise.resolve();\r\n }\r\n \r\n const load = async() => {\r\n if(middleware && !middleware()) return;\r\n\r\n if(stickerType === 2 && !asStatic) {\r\n /* if(doc.id === '1860749763008266301') {\r\n console.log('loaded sticker:', doc, div);\r\n } */\r\n\r\n //await new Promise((resolve) => setTimeout(resolve, 500));\r\n //return;\r\n\r\n //console.time('download sticker' + doc.id);\r\n\r\n //appDocsManager.downloadDocNew(doc.id).promise.then(res => res.json()).then(async(json) => {\r\n //fetch(doc.url).then(res => res.json()).then(async(json) => {\r\n return await appDocsManager.downloadDoc(doc, /* undefined, */lazyLoadQueue?.queueId)\r\n .then(async(blob) => {\r\n //console.timeEnd('download sticker' + doc.id);\r\n //console.log('loaded sticker:', doc, div/* , blob */);\r\n if(middleware && !middleware()) {\r\n throw new Error('wrapSticker 2 middleware');\r\n }\r\n\r\n let animation = await LottieLoader.loadAnimationWorker({\r\n container: div,\r\n loop: loop && !emoji,\r\n autoplay: play,\r\n animationData: blob,\r\n width,\r\n height,\r\n name: 'doc' + doc.id,\r\n needUpscale,\r\n skipRatio,\r\n toneIndex\r\n }, group, middleware);\r\n\r\n //const deferred = deferredPromise<void>();\r\n \r\n animation.addEventListener('firstFrame', () => {\r\n const element = div.firstElementChild;\r\n if(needFadeIn !== false) {\r\n needFadeIn = (needFadeIn || !element || element.tagName === 'svg') && rootScope.settings.animationsEnabled;\r\n }\r\n\r\n const cb = () => {\r\n if(element && element !== animation.canvas) {\r\n element.remove();\r\n }\r\n };\r\n\r\n if(!needFadeIn) {\r\n if(element) {\r\n sequentialDom.mutate(cb);\r\n }\r\n } else {\r\n sequentialDom.mutate(() => {\r\n animation.canvas.classList.add('fade-in');\r\n if(element) {\r\n element.classList.add('fade-out');\r\n }\r\n \r\n animation.canvas.addEventListener('animationend', () => {\r\n sequentialDom.mutate(() => {\r\n animation.canvas.classList.remove('fade-in');\r\n cb();\r\n });\r\n }, {once: true});\r\n });\r\n }\r\n\r\n if(withThumb !== false) {\r\n appDocsManager.saveLottiePreview(doc, animation.canvas, toneIndex);\r\n }\r\n\r\n //deferred.resolve();\r\n }, {once: true});\r\n \r\n if(emoji) {\r\n const data: SendMessageEmojiInteractionData = {\r\n a: [],\r\n v: 1\r\n };\r\n\r\n let sendInteractionThrottled: () => void;\r\n\r\n appStickersManager.preloadAnimatedEmojiStickerAnimation(emoji);\r\n\r\n attachClickEvent(div, async(e) => {\r\n cancelEvent(e);\r\n const animation = LottieLoader.getAnimation(div);\r\n \r\n if(animation.paused) {\r\n const doc = appStickersManager.getAnimatedEmojiSoundDocument(emoji);\r\n if(doc) {\r\n const audio = document.createElement('audio');\r\n audio.style.display = 'none';\r\n div.parentElement.append(audio);\r\n\r\n try {\r\n await appDocsManager.downloadDoc(doc);\r\n\r\n const cacheContext = appDownloadManager.getCacheContext(doc);\r\n audio.src = cacheContext.url;\r\n audio.play();\r\n await onMediaLoad(audio, undefined, true);\r\n \r\n audio.addEventListener('ended', () => {\r\n audio.src = '';\r\n audio.remove();\r\n }, {once: true});\r\n } catch(err) {\r\n \r\n }\r\n }\r\n\r\n animation.autoplay = true;\r\n animation.restart();\r\n }\r\n\r\n const peerId = appImManager.chat.peerId;\r\n if(!peerId.isUser()) {\r\n return;\r\n }\r\n\r\n const doc = appStickersManager.getAnimatedEmojiSticker(emoji, true);\r\n if(!doc) {\r\n return;\r\n }\r\n \r\n const bubble = findUpClassName(div, 'bubble');\r\n const isOut = bubble.classList.contains('is-out');\r\n\r\n const {animationDiv} = wrapStickerAnimation({\r\n doc,\r\n middleware,\r\n side: isOut ? 'right' : 'left',\r\n size: 280,\r\n target: div,\r\n play: true\r\n });\r\n\r\n if(bubble) {\r\n if(isOut) {\r\n animationDiv.classList.add('is-out');\r\n } else {\r\n animationDiv.classList.add('is-in');\r\n }\r\n }\r\n\r\n if(!sendInteractionThrottled) {\r\n sendInteractionThrottled = throttle(() => {\r\n const length = data.a.length;\r\n if(!length) {\r\n return;\r\n }\r\n \r\n const firstTime = data.a[0].t;\r\n \r\n data.a.forEach((a) => {\r\n a.t = (a.t - firstTime) / 1000;\r\n });\r\n \r\n const bubble = findUpClassName(div, 'bubble');\r\n appMessagesManager.setTyping(appImManager.chat.peerId, {\r\n _: 'sendMessageEmojiInteraction',\r\n msg_id: appMessagesIdsManager.getServerMessageId(+bubble.dataset.mid),\r\n emoticon: emoji,\r\n interaction: {\r\n _: 'dataJSON',\r\n data: JSON.stringify(data)\r\n }\r\n }, true);\r\n \r\n data.a.length = 0;\r\n }, 1000, false);\r\n }\r\n\r\n // using a trick here: simulated event from interlocutor's interaction won't fire ours\r\n if(e.isTrusted) {\r\n data.a.push({\r\n i: 1,\r\n t: Date.now()\r\n });\r\n \r\n sendInteractionThrottled();\r\n }\r\n });\r\n }\r\n\r\n return animation;\r\n\r\n //return deferred;\r\n //await new Promise((resolve) => setTimeout(resolve, 5e3));\r\n });\r\n\r\n //console.timeEnd('render sticker' + doc.id);\r\n } else if(asStatic || stickerType === 3) {\r\n let media: HTMLElement;\r\n if(asStatic) {\r\n media = new Image();\r\n } else {\r\n media = createVideo();\r\n (media as HTMLVideoElement).muted = true;\r\n\r\n if(play) {\r\n (media as HTMLVideoElement).autoplay = true;\r\n (media as HTMLVideoElement).loop = true;\r\n }\r\n }\r\n\r\n const thumbImage = div.firstElementChild !== media && div.firstElementChild;\r\n if(needFadeIn !== false) {\r\n needFadeIn = (needFadeIn || !downloaded || (asStatic ? thumbImage : (!thumbImage || thumbImage.tagName === 'svg'))) && rootScope.settings.animationsEnabled;\r\n }\r\n\r\n media.classList.add('media-sticker');\r\n\r\n if(needFadeIn) {\r\n media.classList.add('fade-in');\r\n }\r\n\r\n return new Promise<void>((resolve, reject) => {\r\n const r = () => {\r\n if(middleware && !middleware()) return resolve();\r\n \r\n const onLoad = () => {\r\n sequentialDom.mutateElement(div, () => {\r\n div.append(media);\r\n if(thumbImage) {\r\n thumbImage.classList.add('fade-out');\r\n }\r\n\r\n if(stickerType === 3 && !appDocsManager.isSavingLottiePreview(doc, toneIndex)) {\r\n // const perf = performance.now();\r\n assumeType<HTMLVideoElement>(media);\r\n const canvas = document.createElement('canvas');\r\n canvas.width = width * window.devicePixelRatio;\r\n canvas.height = height * window.devicePixelRatio;\r\n const ctx = canvas.getContext('2d');\r\n ctx.drawImage(media, 0, 0, canvas.width, canvas.height);\r\n appDocsManager.saveLottiePreview(doc, canvas, toneIndex);\r\n // console.log('perf', performance.now() - perf);\r\n }\r\n\r\n if(stickerType === 3 && group) {\r\n animationIntersector.addAnimation(media as HTMLVideoElement, group);\r\n }\r\n\r\n resolve();\r\n\r\n if(needFadeIn) {\r\n media.addEventListener('animationend', () => {\r\n media.classList.remove('fade-in');\r\n if(thumbImage) {\r\n thumbImage.remove();\r\n }\r\n }, {once: true});\r\n }\r\n });\r\n };\r\n\r\n if(asStatic) {\r\n renderImageFromUrl(media, cacheContext.url, onLoad);\r\n } else {\r\n (media as HTMLVideoElement).src = cacheContext.url;\r\n onMediaLoad(media as HTMLVideoElement).then(onLoad);\r\n }\r\n };\r\n\r\n if(cacheContext.url) r();\r\n else {\r\n let promise: Promise<any>;\r\n if(stickerType === 2 && asStatic) {\r\n const thumb = appPhotosManager.choosePhotoSize(doc, width, height, false) as PhotoSize.photoSize;\r\n promise = appDocsManager.getThumbURL(doc, thumb).promise\r\n } else {\r\n promise = appDocsManager.downloadDoc(doc, /* undefined, */lazyLoadQueue?.queueId);\r\n }\r\n \r\n promise.then(r, resolve);\r\n }\r\n });\r\n }\r\n };\r\n\r\n const loadPromise: Promise<RLottiePlayer | void> = lazyLoadQueue && (!downloaded || isAnimated) ? \r\n (lazyLoadQueue.push({div, load}), Promise.resolve()) : \r\n load();\r\n\r\n if(downloaded && (asStatic/* || stickerType === 3 */)) {\r\n loadThumbPromise = loadPromise as any;\r\n if(loadPromises) {\r\n loadPromises.push(loadThumbPromise);\r\n }\r\n }\r\n\r\n return loadPromise;\r\n}\r\n\r\nexport async function wrapStickerSetThumb({set, lazyLoadQueue, container, group, autoplay, width, height}: {\r\n set: StickerSet.stickerSet,\r\n lazyLoadQueue: LazyLoadQueue,\r\n container: HTMLElement,\r\n group: string,\r\n autoplay: boolean,\r\n width: number,\r\n height: number\r\n}) {\r\n if(set.thumbs?.length) {\r\n container.classList.add('media-sticker-wrapper');\r\n lazyLoadQueue.push({\r\n div: container,\r\n load: () => {\r\n const downloadOptions = appStickersManager.getStickerSetThumbDownloadOptions(set);\r\n const promise = appDownloadManager.download(downloadOptions);\r\n\r\n if(set.pFlags.animated && !set.pFlags.videos) {\r\n return promise\r\n .then((blob) => {\r\n lottieLoader.loadAnimationWorker({\r\n container,\r\n loop: true,\r\n autoplay,\r\n animationData: blob,\r\n width,\r\n height,\r\n needUpscale: true,\r\n name: 'setThumb' + set.id\r\n }, group);\r\n });\r\n } else {\r\n let media: HTMLElement;\r\n if(set.pFlags.videos) {\r\n media = createVideo();\r\n (media as HTMLVideoElement).autoplay = true;\r\n (media as HTMLVideoElement).muted = true;\r\n (media as HTMLVideoElement).loop = true;\r\n } else {\r\n media = new Image();\r\n }\r\n\r\n media.classList.add('media-sticker');\r\n \r\n return promise.then(blob => {\r\n renderImageFromUrl(media, URL.createObjectURL(blob), () => {\r\n container.append(media);\r\n });\r\n });\r\n }\r\n }\r\n });\r\n\r\n return;\r\n }\r\n\r\n const promise = appStickersManager.getStickerSet(set);\r\n const stickerSet = await promise;\r\n if(stickerSet.documents[0]._ !== 'documentEmpty') { // as thumb will be used first sticker\r\n wrapSticker({\r\n doc: stickerSet.documents[0],\r\n div: container, \r\n group: group,\r\n lazyLoadQueue\r\n }); // kostil\r\n }\r\n}\r\n\r\nexport function wrapStickerToRow({doc, row, size}: {\r\n doc: MyDocument,\r\n row: Row,\r\n size?: 'small' | 'large',\r\n}) {\r\n const previousMedia = row.media;\r\n const media = row.createMedia('small');\r\n\r\n if(previousMedia) {\r\n media.classList.add('hide');\r\n }\r\n\r\n const loadPromises: Promise<any>[] = previousMedia ? [] : undefined;\r\n\r\n const _size = size === 'small' ? 32 : 48;\r\n const result = wrapSticker({\r\n div: media,\r\n doc: doc,\r\n width: _size,\r\n height: _size,\r\n loadPromises\r\n });\r\n\r\n loadPromises && Promise.all(loadPromises).then(() => {\r\n media.classList.remove('hide');\r\n previousMedia.remove();\r\n });\r\n\r\n return result;\r\n}\r\n\r\nexport function wrapLocalSticker({emoji, width, height}: {\r\n doc?: MyDocument,\r\n url?: string,\r\n emoji?: string,\r\n width: number,\r\n height: number,\r\n}) {\r\n const container = document.createElement('div');\r\n\r\n const doc = appStickersManager.getAnimatedEmojiSticker(emoji);\r\n if(doc) {\r\n wrapSticker({\r\n doc,\r\n div: container,\r\n loop: false,\r\n play: true,\r\n width,\r\n height,\r\n emoji\r\n }).then(() => {\r\n // this.animation = player;\r\n });\r\n } else {\r\n container.classList.add('media-sticker-wrapper');\r\n }\r\n\r\n return {container};\r\n}\r\n\r\nexport function wrapReply(title: Parameters<ReplyContainer['fill']>[0], subtitle: Parameters<ReplyContainer['fill']>[1], message?: any) {\r\n const replyContainer = new ReplyContainer('reply');\r\n replyContainer.fill(title, subtitle, message);\r\n /////////console.log('wrapReply', title, subtitle, media);\r\n return replyContainer.container;\r\n}\r\n\r\nexport function prepareAlbum(options: {\r\n container: HTMLElement,\r\n items: {w: number, h: number}[],\r\n maxWidth: number,\r\n minWidth: number,\r\n spacing: number,\r\n maxHeight?: number,\r\n forMedia?: true\r\n}) {\r\n const layouter = new Layouter(options.items, options.maxWidth, options.minWidth, options.spacing, options.maxHeight);\r\n const layout = layouter.layout();\r\n\r\n const widthItem = layout.find(item => item.sides & RectPart.Right);\r\n const width = widthItem.geometry.width + widthItem.geometry.x;\r\n\r\n const heightItem = layout.find(item => item.sides & RectPart.Bottom);\r\n const height = heightItem.geometry.height + heightItem.geometry.y;\r\n\r\n const container = options.container;\r\n container.style.width = width + 'px';\r\n container.style.height = height + 'px';\r\n const children = container.children;\r\n\r\n layout.forEach(({geometry, sides}, idx) => {\r\n let div: HTMLElement;\r\n div = children[idx] as HTMLElement;\r\n if(!div) {\r\n div = document.createElement('div');\r\n container.append(div);\r\n }\r\n\r\n div.classList.add('album-item', 'grouped-item');\r\n\r\n div.style.width = (geometry.width / width * 100) + '%';\r\n div.style.height = (geometry.height / height * 100) + '%';\r\n div.style.top = (geometry.y / height * 100) + '%';\r\n div.style.left = (geometry.x / width * 100) + '%';\r\n\r\n if(sides & RectPart.Left && sides & RectPart.Top) {\r\n div.style.borderTopLeftRadius = 'inherit';\r\n }\r\n\r\n if(sides & RectPart.Left && sides & RectPart.Bottom) {\r\n div.style.borderBottomLeftRadius = 'inherit';\r\n }\r\n\r\n if(sides & RectPart.Right && sides & RectPart.Top) {\r\n div.style.borderTopRightRadius = 'inherit';\r\n }\r\n\r\n if(sides & RectPart.Right && sides & RectPart.Bottom) {\r\n div.style.borderBottomRightRadius = 'inherit';\r\n }\r\n\r\n if(options.forMedia) {\r\n const mediaDiv = document.createElement('div');\r\n mediaDiv.classList.add('album-item-media');\r\n \r\n div.append(mediaDiv);\r\n }\r\n\r\n // @ts-ignore\r\n //div.style.backgroundColor = '#' + Math.floor(Math.random() * (2 ** 24 - 1)).toString(16).padStart(6, '0');\r\n });\r\n\r\n /* if(options.forMedia) {\r\n layout.forEach((_, i) => {\r\n const mediaDiv = document.createElement('div');\r\n mediaDiv.classList.add('album-item-media');\r\n \r\n options.container.children[i].append(mediaDiv);\r\n });\r\n } */\r\n}\r\n\r\nexport function wrapAlbum({groupId, attachmentDiv, middleware, uploading, lazyLoadQueue, isOut, chat, loadPromises, autoDownload}: {\r\n groupId: string, \r\n attachmentDiv: HTMLElement,\r\n middleware?: () => boolean,\r\n lazyLoadQueue?: LazyLoadQueue,\r\n uploading?: boolean,\r\n isOut: boolean,\r\n chat: Chat,\r\n loadPromises?: Promise<any>[],\r\n autoDownload?: ChatAutoDownloadSettings,\r\n}) {\r\n const items: {size: PhotoSize.photoSize, media: any, message: any}[] = [];\r\n\r\n // !lowest msgID will be the FIRST in album\r\n const storage = appMessagesManager.getMidsByAlbum(groupId);\r\n for(const mid of storage) {\r\n const m = chat.getMessage(mid);\r\n const media = m.media.photo || m.media.document;\r\n\r\n const size: any = media._ === 'photo' ? appPhotosManager.choosePhotoSize(media, 480, 480) : {w: media.w, h: media.h};\r\n items.push({size, media, message: m});\r\n }\r\n\r\n /* // * pending\r\n if(storage[0] < 0) {\r\n items.reverse();\r\n } */\r\n\r\n prepareAlbum({\r\n container: attachmentDiv,\r\n items: items.map(i => ({w: i.size.w, h: i.size.h})),\r\n maxWidth: mediaSizes.active.album.width,\r\n minWidth: 100,\r\n spacing: 2,\r\n forMedia: true\r\n });\r\n\r\n items.forEach((item, idx) => {\r\n const {size, media, message} = item;\r\n\r\n const div = attachmentDiv.children[idx] as HTMLElement;\r\n div.dataset.mid = '' + message.mid;\r\n div.dataset.peerId = '' + message.peerId;\r\n const mediaDiv = div.firstElementChild as HTMLElement;\r\n const isPhoto = media._ === 'photo';\r\n if(isPhoto) {\r\n wrapPhoto({\r\n photo: media,\r\n message,\r\n container: mediaDiv,\r\n boxWidth: 0,\r\n boxHeight: 0,\r\n isOut,\r\n lazyLoadQueue,\r\n middleware,\r\n size,\r\n loadPromises,\r\n autoDownloadSize: autoDownload.photo\r\n });\r\n } else {\r\n wrapVideo({\r\n doc: message.media.document,\r\n container: mediaDiv,\r\n message,\r\n boxWidth: 0,\r\n boxHeight: 0,\r\n withTail: false,\r\n isOut,\r\n lazyLoadQueue,\r\n middleware,\r\n loadPromises,\r\n autoDownload\r\n });\r\n }\r\n });\r\n}\r\n\r\nexport function wrapGroupedDocuments({albumMustBeRenderedFull, message, bubble, messageDiv, chat, loadPromises, autoDownloadSize, lazyLoadQueue, searchContext, useSearch, sizeType}: {\r\n albumMustBeRenderedFull: boolean,\r\n message: any,\r\n messageDiv: HTMLElement,\r\n bubble: HTMLElement,\r\n uploading?: boolean,\r\n chat: Chat,\r\n loadPromises?: Promise<any>[],\r\n autoDownloadSize?: number,\r\n lazyLoadQueue?: LazyLoadQueue,\r\n searchContext?: MediaSearchContext,\r\n useSearch?: boolean,\r\n sizeType?: MediaSizeType\r\n}) {\r\n let nameContainer: HTMLElement;\r\n const mids = albumMustBeRenderedFull ? chat.getMidsByMid(message.mid) : [message.mid];\r\n /* if(isPending) {\r\n mids.reverse();\r\n } */\r\n\r\n mids.forEach((mid, idx) => {\r\n const message = chat.getMessage(mid);\r\n const div = wrapDocument({\r\n message,\r\n loadPromises,\r\n autoDownloadSize,\r\n lazyLoadQueue,\r\n searchContext,\r\n sizeType\r\n });\r\n\r\n const container = document.createElement('div');\r\n container.classList.add('document-container');\r\n container.dataset.mid = '' + mid;\r\n container.dataset.peerId = '' + message.peerId;\r\n\r\n const wrapper = document.createElement('div');\r\n wrapper.classList.add('document-wrapper');\r\n \r\n if(message.message) {\r\n const messageDiv = document.createElement('div');\r\n messageDiv.classList.add('document-message');\r\n\r\n const richText = RichTextProcessor.wrapRichText(message.message, {\r\n entities: message.totalEntities\r\n });\r\n\r\n setInnerHTML(messageDiv, richText);\r\n wrapper.append(messageDiv);\r\n }\r\n\r\n if(mids.length > 1) {\r\n const selection = document.createElement('div');\r\n selection.classList.add('document-selection');\r\n container.append(selection);\r\n \r\n container.classList.add('grouped-item');\r\n\r\n if(idx === 0) {\r\n nameContainer = wrapper;\r\n }\r\n }\r\n\r\n wrapper.append(div);\r\n container.append(wrapper);\r\n messageDiv.append(container);\r\n });\r\n\r\n if(mids.length > 1) {\r\n bubble.classList.add('is-multiple-documents', 'is-grouped');\r\n }\r\n\r\n return nameContainer;\r\n}\r\n\r\nexport function wrapPoll(message: any) {\r\n const elem = new PollElement();\r\n elem.message = message;\r\n elem.setAttribute('peer-id', '' + message.peerId);\r\n elem.setAttribute('poll-id', message.media.poll.id);\r\n elem.setAttribute('message-id', '' + message.mid);\r\n elem.render();\r\n return elem;\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport whichChild from \"./whichChild\";\r\n\r\nexport default function positionElementByIndex(element: HTMLElement, container: HTMLElement, pos: number, prevPos?: number) {\r\n if(prevPos === undefined) {\r\n prevPos = element.parentElement === container ? whichChild(element) : -1;\r\n }\r\n\r\n if(prevPos === pos) {\r\n return false;\r\n } else if(prevPos !== -1 && prevPos < pos) { // was higher\r\n pos += 1;\r\n }\r\n\r\n if(!pos) {\r\n container.prepend(element);\r\n } else if(container.childElementCount > pos) {\r\n container.insertBefore(element, container.children[pos]);\r\n } else {\r\n container.append(element);\r\n }\r\n\r\n return true;\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport insertInDescendSortedArray from \"./array/insertInDescendSortedArray\";\nimport { getMiddleware } from \"./middleware\";\nimport safeAssign from \"./object/safeAssign\";\n\nexport type SortedElementId = PeerId;\nexport type SortedElementBase = {\n id: SortedElementId, \n index: number\n};\n\nexport default class SortedList<SortedElement extends SortedElementBase> {\n protected elements: Map<SortedElementId, SortedElement>;\n protected sorted: Array<SortedElement>;\n\n protected getIndex: (element: SortedElement) => number;\n protected onDelete: (element: SortedElement) => void;\n protected onUpdate: (element: SortedElement) => void;\n protected onSort: (element: SortedElement, idx: number) => void;\n protected onElementCreate: (base: SortedElementBase, batch: boolean) => SortedElement;\n\n protected updateElementWith = (callback: () => void) => callback();\n protected updateListWith = (callback: (canUpdate: boolean | undefined) => void) => callback(true);\n\n protected middleware = getMiddleware();\n\n constructor(options: {\n getIndex: SortedList<SortedElement>['getIndex'],\n onDelete?: SortedList<SortedElement>['onDelete'],\n onUpdate?: SortedList<SortedElement>['onUpdate'],\n onSort?: SortedList<SortedElement>['onSort'],\n onElementCreate: SortedList<SortedElement>['onElementCreate'],\n\n updateElementWith?: SortedList<SortedElement>['updateElementWith'],\n updateListWith?: SortedList<SortedElement>['updateListWith']\n }) {\n safeAssign(this, options);\n\n this.elements = new Map();\n this.sorted = [];\n }\n\n public clear() {\n this.middleware.clean();\n this.elements.clear();\n this.sorted.length = 0;\n }\n\n protected _updateList() {\n this.elements.forEach(element => {\n this.update(element.id, true);\n });\n\n if(this.onSort) {\n this.sorted.forEach((element, idx) => {\n this.onSort(element, idx);\n });\n }\n }\n\n public updateList(callback: (updated: boolean) => void) {\n const middleware = this.middleware.get();\n this.updateListWith((canUpdate) => {\n if(!middleware() || (canUpdate !== undefined && !canUpdate)) {\n return callback(false);\n }\n\n this._updateList();\n \n callback(true);\n });\n }\n\n public has(id: SortedElementId) {\n return this.elements.has(id);\n }\n\n public get(id: SortedElementId) {\n return this.elements.get(id);\n }\n\n public getAll() {\n return this.elements;\n }\n\n public add(id: SortedElementId, batch = false, updateElementWith?: SortedList<SortedElement>['updateElementWith'], updateBatch = batch) {\n let element = this.get(id);\n if(element) {\n return element;\n }\n\n const base: SortedElementBase = {\n id,\n index: 0\n };\n\n element = this.onElementCreate(base, batch);\n this.elements.set(id, element);\n this.update(id, updateBatch, element, updateElementWith);\n\n return element;\n }\n\n public delete(id: SortedElementId, noScheduler?: boolean) {\n const element = this.elements.get(id);\n if(!element) {\n return false;\n }\n \n this.elements.delete(id);\n \n const idx = this.sorted.indexOf(element);\n if(idx !== -1) {\n this.sorted.splice(idx, 1);\n }\n\n if(this.onDelete) {\n if(noScheduler) {\n this.onDelete(element);\n } else {\n const middleware = this.middleware.get();\n this.updateElementWith(() => {\n if(!middleware()) {\n return;\n }\n\n this.onDelete(element);\n });\n }\n }\n\n return true;\n }\n\n public update(id: SortedElementId, batch = false, element = this.get(id), updateElementWith?: SortedList<SortedElement>['updateElementWith']) {\n if(!element) {\n return;\n }\n\n element.index = this.getIndex(element);\n this.onUpdate && this.onUpdate(element);\n\n const idx = insertInDescendSortedArray(this.sorted, element, 'index');\n if(!batch && this.onSort) {\n const middleware = this.middleware.get();\n (updateElementWith || this.updateElementWith)(() => {\n if(!middleware()) {\n return;\n }\n\n // * в случае пересортировки этого же элемента во время ожидания вызовется вторая такая же. нужно соблюдать последовательность событий\n this.onSort(element, idx);\n /* if(this.get(id) === element) {\n this.onSort(element, this.sorted.indexOf(element));\n } */\n });\n }\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport type { LazyLoadQueueIntersector } from \"./lazyLoadQueue\";\nimport appDialogsManager, { AppDialogsManager, DialogDom } from \"../lib/appManagers/appDialogsManager\";\nimport { getHeavyAnimationPromise } from \"../hooks/useHeavyAnimationCheck\";\nimport appUsersManager from \"../lib/appManagers/appUsersManager\";\nimport isInDOM from \"../helpers/dom/isInDOM\";\nimport positionElementByIndex from \"../helpers/dom/positionElementByIndex\";\nimport replaceContent from \"../helpers/dom/replaceContent\";\nimport { fastRaf } from \"../helpers/schedulers\";\nimport SortedList, { SortedElementBase } from \"../helpers/sortedList\";\nimport safeAssign from \"../helpers/object/safeAssign\";\n\ninterface SortedUser extends SortedElementBase {\n dom: DialogDom\n}\n\nexport default class SortedUserList extends SortedList<SortedUser> {\n protected static SORT_INTERVAL = 30e3;\n public list: HTMLUListElement;\n \n protected lazyLoadQueue: LazyLoadQueueIntersector;\n protected avatarSize = 48;\n protected rippleEnabled = true;\n protected autonomous = true;\n protected createChatListOptions: Parameters<AppDialogsManager['createChatList']>[0];\n protected onListLengthChange: () => void;\n protected getIndex: (element: SortedUser) => number;\n protected onUpdate: (element: SortedUser) => void;\n\n constructor(options: Partial<{\n lazyLoadQueue: SortedUserList['lazyLoadQueue'],\n avatarSize: SortedUserList['avatarSize'],\n rippleEnabled: SortedUserList['rippleEnabled'],\n createChatListOptions: SortedUserList['createChatListOptions'],\n autonomous: SortedUserList['autonomous'],\n onListLengthChange: SortedUserList['onListLengthChange'],\n getIndex: SortedUserList['getIndex'],\n onUpdate: SortedUserList['onUpdate']\n }> = {}) {\n super({\n getIndex: options.getIndex || ((element) => appUsersManager.getUserStatusForSort(element.id)),\n onDelete: (element) => {\n element.dom.listEl.remove();\n this.onListLengthChange && this.onListLengthChange();\n },\n onUpdate: options.onUpdate || ((element) => {\n const status = appUsersManager.getUserStatusString(element.id);\n replaceContent(element.dom.lastMessageSpan, status);\n }),\n onSort: (element, idx) => {\n const willChangeLength = element.dom.listEl.parentElement !== this.list;\n positionElementByIndex(element.dom.listEl, this.list, idx);\n\n if(willChangeLength && this.onListLengthChange) {\n this.onListLengthChange();\n }\n },\n onElementCreate: (base) => {\n const {dom} = appDialogsManager.addDialogNew({\n dialog: base.id,\n container: false,\n drawStatus: false,\n avatarSize: this.avatarSize,\n autonomous: this.autonomous,\n meAsSaved: false,\n rippleEnabled: this.rippleEnabled,\n lazyLoadQueue: this.lazyLoadQueue\n });\n\n (base as SortedUser).dom = dom;\n return base as SortedUser;\n },\n updateElementWith: fastRaf,\n updateListWith: async(callback) => {\n if(!isInDOM(this.list)) {\n return callback(false);\n }\n \n await getHeavyAnimationPromise();\n \n if(!isInDOM(this.list)) {\n return callback(false);\n }\n\n callback(true);\n }\n });\n\n safeAssign(this, options);\n\n this.list = appDialogsManager.createChatList(this.createChatListOptions);\n\n let timeout: number;\n const doTimeout = () => {\n timeout = window.setTimeout(() => {\n this.updateList((good) => {\n if(good) {\n doTimeout();\n }\n });\n }, SortedUserList.SORT_INTERVAL);\n };\n\n doTimeout();\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport SwipeHandler, { SwipeHandlerOptions } from \"../../components/swipeHandler\";\nimport cancelEvent from \"./cancelEvent\";\nimport findUpClassName from \"./findUpClassName\";\nimport isSwipingBackSafari from \"./isSwipingBackSafari\";\n\nexport type SwipeHandlerHorizontalOptions = SwipeHandlerOptions & {\n // xThreshold?: number\n};\n\nexport default function handleHorizontalSwipe(options: SwipeHandlerHorizontalOptions) {\n let cancelY = false;\n return new SwipeHandler({\n ...options,\n verifyTouchTarget: (e) => {\n return !findUpClassName(e.target, 'progress-line') && \n !isSwipingBackSafari(e) && \n (options.verifyTouchTarget ? options.verifyTouchTarget(e) : true);\n },\n onSwipe: (xDiff, yDiff, e) => {\n if(!cancelY && Math.abs(yDiff) > 20) {\n return true;\n }\n\n if(Math.abs(xDiff) > Math.abs(yDiff)) {\n cancelEvent(e);\n cancelY = true;\n } else if(!cancelY && Math.abs(yDiff) > Math.abs(xDiff)/* || Math.abs(yDiff) > 20 */) {\n return true;\n }\n\n /* if(!cancelY && options.xThreshold !== undefined && xDiff >= options.xThreshold) {\n cancelY = true;\n } */\n\n return options.onSwipe(xDiff, yDiff, e);\n },\n onReset: () => {\n cancelY = false;\n options.onReset && options.onReset();\n },\n cancelEvent: false // cannot use cancelEvent on Safari iOS because scroll will be canceled too\n });\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { cancelContextMenuOpening } from \"../../components/misc\";\nimport handleHorizontalSwipe, { SwipeHandlerHorizontalOptions } from \"./handleHorizontalSwipe\";\n\nexport default function handleTabSwipe(options: SwipeHandlerHorizontalOptions) {\n return handleHorizontalSwipe({\n ...options,\n onSwipe: (xDiff, yDiff, e) => {\n if(Math.abs(xDiff) > 50) {\n options.onSwipe(xDiff, yDiff, e);\n cancelContextMenuOpening();\n\n return true;\n }\n }\n });\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport cancelEvent from \"../helpers/dom/cancelEvent\";\nimport { AttachClickOptions, attachClickEvent, CLICK_EVENT_NAME } from \"../helpers/dom/clickEvent\";\nimport ListenerSetter from \"../helpers/listenerSetter\";\nimport { FormatterArguments, i18n, LangPackKey } from \"../lib/langPack\";\nimport CheckboxField from \"./checkboxField\";\nimport { closeBtnMenu } from \"./misc\";\nimport ripple from \"./ripple\";\n\nexport type ButtonMenuItemOptions = {\n icon?: string, \n text?: LangPackKey, \n textArgs?: FormatterArguments,\n regularText?: string, \n onClick: (e: MouseEvent | TouchEvent) => void | boolean, \n element?: HTMLElement,\n textElement?: HTMLElement,\n options?: AttachClickOptions,\n checkboxField?: CheckboxField,\n noCheckboxClickListener?: boolean,\n keepOpen?: boolean\n /* , cancelEvent?: true */\n};\n\nconst ButtonMenuItem = (options: ButtonMenuItemOptions) => {\n if(options.element) return options.element;\n\n const {icon, text, onClick, checkboxField, noCheckboxClickListener} = options;\n const el = document.createElement('div');\n el.className = 'btn-menu-item rp-overflow' + (icon ? ' tgico-' + icon : '');\n ripple(el);\n\n let textElement = options.textElement;\n if(!textElement) {\n textElement = options.textElement = text ? i18n(text, options.textArgs) : document.createElement('span');\n if(options.regularText) textElement.innerHTML = options.regularText;\n }\n \n textElement.classList.add('btn-menu-item-text');\n el.append(textElement);\n\n const keepOpen = !!checkboxField || !!options.keepOpen;\n\n // * cancel mobile keyboard close\n onClick && attachClickEvent(el, /* CLICK_EVENT_NAME !== 'click' || keepOpen ? */ (e) => {\n cancelEvent(e);\n const result = onClick(e);\n\n if(result === false) {\n return;\n }\n\n if(!keepOpen) {\n closeBtnMenu();\n }\n\n if(checkboxField && !noCheckboxClickListener/* && result !== false */) {\n checkboxField.checked = checkboxField.input.type === 'radio' ? true : !checkboxField.checked;\n }\n }/* : onClick */, options.options);\n\n if(checkboxField) {\n el.append(checkboxField.label);\n }\n\n return options.element = el;\n};\n\nconst ButtonMenu = (buttons: ButtonMenuItemOptions[], listenerSetter?: ListenerSetter) => {\n const el = document.createElement('div');\n el.classList.add('btn-menu');\n\n if(listenerSetter) {\n buttons.forEach(b => {\n if(b.options) {\n b.options.listenerSetter = listenerSetter;\n } else {\n b.options = {listenerSetter};\n }\n });\n }\n\n const items = buttons.map(ButtonMenuItem);\n\n el.append(...items);\n\n return el;\n};\n\nexport default ButtonMenu;\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport appImManager from \"../../lib/appManagers/appImManager\";\r\nimport PopupPickUser from \"./pickUser\";\r\n\r\nexport default class PopupForward extends PopupPickUser {\r\n constructor(\r\n peerIdMids: {[fromPeerId: PeerId]: number[]}, \r\n onSelect?: (peerId: PeerId) => Promise<void> | void, \r\n overrideOnSelect = false\r\n ) {\r\n super({\r\n peerTypes: ['dialogs', 'contacts'],\r\n onSelect: overrideOnSelect ? onSelect : async(peerId) => {\r\n if(onSelect) {\r\n const res = onSelect(peerId);\r\n if(res instanceof Promise) {\r\n await res;\r\n }\r\n }\r\n\r\n appImManager.setInnerPeer({peerId});\r\n appImManager.chat.input.initMessagesForward(peerIdMids);\r\n },\r\n placeholder: 'ShareModal.Search.ForwardPlaceholder',\r\n chatRightsAction: 'send_messages',\r\n selfPresence: 'ChatYourSelf'\r\n });\r\n }\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport appChatsManager from \"../../lib/appManagers/appChatsManager\";\nimport appMessagesManager from \"../../lib/appManagers/appMessagesManager\";\nimport rootScope from \"../../lib/rootScope\";\nimport { addCancelButton } from \".\";\nimport PopupPeer, { PopupPeerButtonCallbackCheckboxes, PopupPeerOptions } from \"./peer\";\nimport { ChatType } from \"../chat/chat\";\nimport { i18n, LangPackKey } from \"../../lib/langPack\";\nimport PeerTitle from \"../peerTitle\";\nimport appPeersManager from \"../../lib/appManagers/appPeersManager\";\n\nexport default class PopupDeleteMessages {\n constructor(peerId: PeerId, mids: number[], type: ChatType, onConfirm?: () => void) {\n const peerTitleElement = new PeerTitle({peerId}).element;\n\n mids = mids.slice();\n const callback = (checked: PopupPeerButtonCallbackCheckboxes, revoke?: boolean) => {\n onConfirm && onConfirm();\n if(type === 'scheduled') {\n appMessagesManager.deleteScheduledMessages(peerId, mids);\n } else {\n appMessagesManager.deleteMessages(peerId, mids, !!checked.size || revoke);\n }\n };\n\n let title: LangPackKey, titleArgs: any[], description: LangPackKey, descriptionArgs: any[], buttons: PopupPeerOptions['buttons'], checkboxes: PopupPeerOptions['checkboxes'] = [];\n if(mids.length === 1) {\n title = 'DeleteSingleMessagesTitle';\n } else {\n title = 'DeleteMessagesTitle';\n titleArgs = [i18n('messages', [mids.length])];\n }\n \n if(appPeersManager.isMegagroup(peerId)) {\n description = mids.length === 1 ? 'AreYouSureDeleteSingleMessageMega' : 'AreYouSureDeleteFewMessagesMega';\n } else {\n description = mids.length === 1 ? 'AreYouSureDeleteSingleMessage' : 'AreYouSureDeleteFewMessages';\n }\n\n buttons = [{\n langKey: 'Delete',\n isDanger: true,\n callback\n }];\n\n if(peerId === rootScope.myId || type === 'scheduled') {\n \n } else {\n if(peerId.isUser()) {\n checkboxes.push({\n text: 'DeleteMessagesOptionAlso',\n textArgs: [peerTitleElement]\n });\n } else {\n const chat = appChatsManager.getChat(peerId.toChatId());\n\n const hasRights = appChatsManager.hasRights(peerId.toChatId(), 'delete_messages');\n if(chat._ === 'chat') {\n const canRevoke = hasRights ? mids.slice() : mids.filter(mid => {\n const message = appMessagesManager.getMessageByPeer(peerId, mid);\n return message.fromId === rootScope.myId;\n });\n\n if(canRevoke.length) {\n if(canRevoke.length === mids.length) {\n checkboxes.push({\n text: 'DeleteForAll'\n });\n } else {\n checkboxes.push({\n text: 'DeleteMessagesOption'\n });\n\n description = 'DeleteMessagesTextGroup';\n descriptionArgs = [i18n('messages', [canRevoke.length])];\n //description = `You can also delete the ${canRevoke.length} message${canRevoke.length > 1 ? 's' : ''} you sent from the inboxes of other group members by pressing \"${buttonText}\".`;\n }\n }\n } else {\n buttons[0].callback = (checked) => callback(checked, true);\n }\n }\n }\n\n addCancelButton(buttons);\n\n const popup = new PopupPeer('popup-delete-chat', {\n peerId,\n titleLangKey: title,\n titleLangArgs: titleArgs,\n descriptionLangKey: description,\n descriptionLangArgs: descriptionArgs,\n buttons,\n checkboxes\n });\n\n popup.show();\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport appMessagesManager from \"../../lib/appManagers/appMessagesManager\";\nimport { PopupButton } from \".\";\nimport PopupPeer from \"./peer\";\n\nexport default class PopupSendNow {\n constructor(peerId: PeerId, mids: number[], onConfirm?: () => void) {\n let title: string, description: string, buttons: PopupButton[] = [];\n\n title = `Send Message${mids.length > 1 ? 's' : ''} Now`;\n description = mids.length > 1 ? 'Send ' + mids.length + ' messages now?' : 'Send message now?';\n\n const callback = () => {\n onConfirm && onConfirm();\n appMessagesManager.sendScheduledMessages(peerId, mids);\n };\n\n buttons.push({\n langKey: 'Send',\n callback\n });\n\n const popup = new PopupPeer('popup-delete-chat', {\n peerId,\n title,\n description,\n buttons\n });\n\n popup.show();\n }\n}","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nexport default function cancelSelection() {\r\n if(window.getSelection) {\r\n if(window.getSelection().empty) { // Chrome\r\n window.getSelection().empty();\r\n } else if(window.getSelection().removeAllRanges) { // Firefox\r\n window.getSelection().removeAllRanges();\r\n }\r\n // @ts-ignore\r\n } else if(document.selection) { // IE?\r\n // @ts-ignore\r\n document.selection.empty();\r\n }\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport type { AppMessagesManager } from \"../../lib/appManagers/appMessagesManager\";\nimport type ChatBubbles from \"./bubbles\";\nimport type ChatInput from \"./input\";\nimport type Chat from \"./chat\";\nimport { IS_TOUCH_SUPPORTED } from \"../../environment/touchSupport\";\nimport Button from \"../button\";\nimport ButtonIcon from \"../buttonIcon\";\nimport CheckboxField from \"../checkboxField\";\nimport PopupDeleteMessages from \"../popups/deleteMessages\";\nimport PopupForward from \"../popups/forward\";\nimport { toast } from \"../toast\";\nimport SetTransition from \"../singleTransition\";\nimport ListenerSetter from \"../../helpers/listenerSetter\";\nimport PopupSendNow from \"../popups/sendNow\";\nimport appNavigationController, { NavigationItem } from \"../appNavigationController\";\nimport { IS_MOBILE_SAFARI } from \"../../environment/userAgent\";\nimport I18n, { i18n, _i18n } from \"../../lib/langPack\";\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\nimport blurActiveElement from \"../../helpers/dom/blurActiveElement\";\nimport cancelEvent from \"../../helpers/dom/cancelEvent\";\nimport cancelSelection from \"../../helpers/dom/cancelSelection\";\nimport getSelectedText from \"../../helpers/dom/getSelectedText\";\nimport rootScope from \"../../lib/rootScope\";\nimport { fastRaf } from \"../../helpers/schedulers\";\nimport replaceContent from \"../../helpers/dom/replaceContent\";\nimport AppSearchSuper from \"../appSearchSuper.\";\nimport isInDOM from \"../../helpers/dom/isInDOM\";\nimport { randomLong } from \"../../helpers/random\";\nimport { attachContextMenuListener } from \"../misc\";\nimport { attachClickEvent, AttachClickOptions } from \"../../helpers/dom/clickEvent\";\nimport findUpAsChild from \"../../helpers/dom/findUpAsChild\";\nimport EventListenerBase from \"../../helpers/eventListenerBase\";\nimport safeAssign from \"../../helpers/object/safeAssign\";\n\nconst accumulateMapSet = (map: Map<any, Set<number>>) => {\n return [...map.values()].reduce((acc, v) => acc + v.size, 0);\n};\n\n//const MIN_CLICK_MOVE = 32; // minimum bubble height\n\nclass AppSelection extends EventListenerBase<{\n toggle: (isSelecting: boolean) => void\n}> {\n public selectedMids: Map<PeerId, Set<number>> = new Map();\n public isSelecting = false;\n\n public selectedText: string;\n\n protected listenerSetter: ListenerSetter;\n protected appMessagesManager: AppMessagesManager;\n protected isScheduled: boolean;\n protected listenElement: HTMLElement;\n\n protected onToggleSelection: (forwards: boolean, animate: boolean) => void;\n protected onUpdateContainer: (cantForward: boolean, cantDelete: boolean, cantSend: boolean) => void;\n protected onCancelSelection: () => void;\n protected toggleByMid: (peerId: PeerId, mid: number) => void;\n protected toggleByElement: (bubble: HTMLElement) => void;\n\n protected navigationType: NavigationItem['type'];\n\n protected getElementFromTarget: (target: HTMLElement) => HTMLElement;\n protected verifyTarget: (e: MouseEvent, target: HTMLElement) => boolean;\n protected verifyMouseMoveTarget: (e: MouseEvent, element: HTMLElement, selecting: boolean) => boolean;\n protected verifyTouchLongPress: () => boolean;\n protected targetLookupClassName: string;\n protected lookupBetweenParentClassName: string;\n protected lookupBetweenElementsQuery: string;\n\n protected doNotAnimate: boolean;\n\n constructor(options: {\n appMessagesManager: AppMessagesManager,\n listenElement: HTMLElement,\n listenerSetter: ListenerSetter,\n getElementFromTarget: AppSelection['getElementFromTarget'],\n verifyTarget?: AppSelection['verifyTarget'],\n verifyMouseMoveTarget?: AppSelection['verifyMouseMoveTarget'],\n verifyTouchLongPress?: AppSelection['verifyTouchLongPress'],\n targetLookupClassName: string,\n lookupBetweenParentClassName: string,\n lookupBetweenElementsQuery: string,\n isScheduled?: AppSelection['isScheduled']\n }) {\n super(false);\n\n safeAssign(this, options);\n\n this.navigationType = 'multiselect-' + randomLong() as any;\n\n if(IS_TOUCH_SUPPORTED) {\n this.listenerSetter.add(this.listenElement)('touchend', () => {\n if(!this.isSelecting) return;\n this.selectedText = getSelectedText();\n });\n\n attachContextMenuListener(this.listenElement, (e) => {\n if(this.isSelecting || (this.verifyTouchLongPress && !this.verifyTouchLongPress())) return;\n\n // * these two lines will fix instant text selection on iOS Safari\n document.body.classList.add('no-select'); // * need no-select on body because chat-input transforms in channels\n this.listenElement.addEventListener('touchend', (e) => {\n cancelEvent(e); // ! this one will fix propagation to document loader button, etc\n document.body.classList.remove('no-select');\n\n //this.chat.bubbles.onBubblesClick(e);\n }, {once: true, capture: true});\n\n cancelSelection();\n //cancelEvent(e as any);\n const element = this.getElementFromTarget(e.target as HTMLElement);\n if(element) {\n this.toggleByElement(element);\n }\n }, this.listenerSetter);\n\n return;\n }\n\n const getElementsBetween = (first: HTMLElement, last: HTMLElement) => { \n if(first === last) {\n return [];\n }\n\n const firstRect = first.getBoundingClientRect();\n const lastRect = last.getBoundingClientRect();\n const difference = (firstRect.top - lastRect.top) || (firstRect.left - lastRect.left);\n const isHigher = difference < 0;\n\n const parent = findUpClassName(first, this.lookupBetweenParentClassName);\n if(!parent) {\n return [];\n }\n\n const elements = Array.from(parent.querySelectorAll(this.lookupBetweenElementsQuery)) as HTMLElement[];\n let firstIndex = elements.indexOf(first);\n let lastIndex = elements.indexOf(last);\n\n if(!isHigher) {\n [lastIndex, firstIndex] = [firstIndex, lastIndex];\n }\n\n const slice = elements.slice(firstIndex + 1, lastIndex);\n\n // console.log('getElementsBetween', first, last, slice, firstIndex, lastIndex, isHigher);\n\n return slice;\n };\n\n this.listenerSetter.add(this.listenElement)('mousedown', (e) => {\n //console.log('selection mousedown', e);\n const element = findUpClassName(e.target, this.targetLookupClassName);\n if(e.button !== 0) {\n return;\n }\n\n if(this.verifyTarget && !this.verifyTarget(e, element)) {\n return;\n }\n \n const seen: AppSelection['selectedMids'] = new Map();\n let selecting: boolean;\n\n /* let good = false;\n const {x, y} = e; */\n\n /* const bubbles = appImManager.bubbles;\n for(const mid in bubbles) {\n const bubble = bubbles[mid];\n bubble.addEventListener('mouseover', () => {\n console.log('mouseover');\n }, {once: true});\n } */\n\n let firstTarget = element;\n\n const processElement = (element: HTMLElement, checkBetween = true) => {\n const mid = +element.dataset.mid;\n if(!mid || !element.dataset.peerId) return;\n const peerId = element.dataset.peerId.toPeerId();\n\n if(!isInDOM(firstTarget)) {\n firstTarget = element;\n }\n\n let seenSet = seen.get(peerId);\n if(!seenSet) {\n seen.set(peerId, seenSet = new Set());\n }\n\n if(!seenSet.has(mid)) {\n const isSelected = this.isMidSelected(peerId, mid);\n if(selecting === undefined) {\n //bubblesContainer.classList.add('no-select');\n selecting = !isSelected;\n }\n\n seenSet.add(mid);\n\n if((selecting && !isSelected) || (!selecting && isSelected)) {\n const seenLength = accumulateMapSet(seen);\n if(this.toggleByElement && checkBetween) {\n if(seenLength < 2) {\n if(findUpAsChild(element, firstTarget)) {\n firstTarget = element;\n }\n }\n\n const elementsBetween = getElementsBetween(firstTarget, element);\n // console.log(elementsBetween);\n if(elementsBetween.length) {\n elementsBetween.forEach(element => {\n processElement(element, false);\n });\n }\n }\n\n if(!this.selectedMids.size) {\n if(seenLength === 2 && this.toggleByMid) {\n for(const [peerId, mids] of seen) {\n for(const mid of mids) {\n this.toggleByMid(peerId, mid);\n }\n }\n }\n } else if(this.toggleByElement) {\n this.toggleByElement(element);\n }\n }\n }\n };\n\n //const foundTargets: Map<HTMLElement, true> = new Map();\n let canceledSelection = false;\n const onMouseMove = (e: MouseEvent) => {\n if(!canceledSelection) {\n cancelSelection();\n canceledSelection = true;\n }\n /* if(!good) {\n if(Math.abs(e.x - x) > MIN_CLICK_MOVE || Math.abs(e.y - y) > MIN_CLICK_MOVE) {\n good = true;\n } else {\n return;\n }\n } */\n\n /* if(foundTargets.has(e.target as HTMLElement)) return;\n foundTargets.set(e.target as HTMLElement, true); */\n const element = this.getElementFromTarget(e.target as HTMLElement);\n if(!element) {\n //console.error('found no bubble', e);\n return;\n }\n\n if(this.verifyMouseMoveTarget && !this.verifyMouseMoveTarget(e, element, selecting)) {\n this.listenerSetter.removeManual(this.listenElement, 'mousemove', onMouseMove);\n this.listenerSetter.removeManual(document, 'mouseup', onMouseUp, documentListenerOptions);\n return;\n }\n\n processElement(element);\n };\n\n const onMouseUp = (e: MouseEvent) => {\n if(seen.size) {\n attachClickEvent(window, cancelEvent, {capture: true, once: true, passive: false});\n }\n\n this.listenerSetter.removeManual(this.listenElement, 'mousemove', onMouseMove);\n //bubblesContainer.classList.remove('no-select');\n\n // ! CANCEL USER SELECTION !\n cancelSelection();\n };\n\n const documentListenerOptions = {once: true};\n this.listenerSetter.add(this.listenElement)('mousemove', onMouseMove);\n this.listenerSetter.add(document)('mouseup', onMouseUp, documentListenerOptions);\n });\n }\n\n protected isElementShouldBeSelected(element: HTMLElement) {\n return this.isMidSelected(element.dataset.peerId.toPeerId(), +element.dataset.mid);\n }\n\n protected appendCheckbox(element: HTMLElement, checkboxField: CheckboxField) {\n element.prepend(checkboxField.label);\n }\n\n public toggleElementCheckbox(element: HTMLElement, show: boolean) {\n const hasCheckbox = !!this.getCheckboxInputFromElement(element);\n if(show) {\n if(hasCheckbox) {\n return false;\n }\n \n const checkboxField = new CheckboxField({\n name: element.dataset.mid, \n round: true\n });\n \n // * if it is a render of new message\n if(this.isSelecting) { // ! avoid breaking animation on start\n if(this.isElementShouldBeSelected(element)) {\n checkboxField.input.checked = true;\n element.classList.add('is-selected');\n }\n }\n \n this.appendCheckbox(element, checkboxField);\n } else if(hasCheckbox) {\n this.getCheckboxInputFromElement(element).parentElement.remove();\n }\n\n return true;\n }\n\n protected getCheckboxInputFromElement(element: HTMLElement): HTMLInputElement {\n return element.firstElementChild?.tagName === 'LABEL' && \n element.firstElementChild.firstElementChild as HTMLInputElement;\n }\n\n protected updateContainer(forceSelection = false) {\n const size = this.selectedMids.size;\n if(!size && !forceSelection) return;\n \n let cantForward = !size, \n cantDelete = !size, \n cantSend = !size;\n for(const [peerId, mids] of this.selectedMids) {\n const storage = this.isScheduled ? this.appMessagesManager.getScheduledMessagesStorage(peerId) : this.appMessagesManager.getMessagesStorage(peerId);\n for(const mid of mids) {\n const message = this.appMessagesManager.getMessageFromStorage(storage, mid);\n if(!cantForward) {\n cantForward = !this.appMessagesManager.canForward(message);\n }\n \n if(!cantDelete) {\n cantDelete = !this.appMessagesManager.canDeleteMessage(message);\n }\n\n if(cantForward && cantDelete) break;\n }\n\n if(cantForward && cantDelete) break;\n }\n \n this.onUpdateContainer && this.onUpdateContainer(cantForward, cantDelete, cantSend);\n }\n\n public toggleSelection(toggleCheckboxes = true, forceSelection = false) {\n const wasSelecting = this.isSelecting;\n const size = this.selectedMids.size;\n this.isSelecting = !!size || forceSelection;\n\n if(wasSelecting === this.isSelecting) return false;\n\n this.dispatchEvent('toggle', this.isSelecting);\n \n // const bubblesContainer = this.bubbles.bubblesContainer;\n //bubblesContainer.classList.toggle('is-selecting', !!size);\n\n /* if(bubblesContainer.classList.contains('is-chat-input-hidden')) {\n const scrollable = this.appImManager.scrollable;\n if(scrollable.isScrolledDown) {\n scrollable.scrollTo(scrollable.scrollHeight, 'top', true, true, 200);\n }\n } */\n\n if(!IS_TOUCH_SUPPORTED) {\n this.listenElement.classList.toggle('no-select', this.isSelecting);\n\n if(wasSelecting) {\n // ! CANCEL USER SELECTION !\n cancelSelection();\n }\n }/* else {\n if(!wasSelecting) {\n bubblesContainer.classList.add('no-select');\n setTimeout(() => {\n cancelSelection();\n bubblesContainer.classList.remove('no-select');\n cancelSelection();\n }, 100);\n }\n } */\n\n blurActiveElement();\n\n const forwards = !!size || forceSelection;\n this.onToggleSelection && this.onToggleSelection(forwards, !this.doNotAnimate);\n\n if(!IS_MOBILE_SAFARI) {\n if(forwards) {\n appNavigationController.pushItem({\n type: this.navigationType,\n onPop: () => {\n this.cancelSelection();\n }\n });\n } else {\n appNavigationController.removeByType(this.navigationType);\n }\n }\n\n if(forceSelection) {\n this.updateContainer(forceSelection);\n }\n\n return true;\n }\n\n public cancelSelection = (doNotAnimate?: boolean) => {\n if(doNotAnimate) this.doNotAnimate = true;\n this.onCancelSelection && this.onCancelSelection();\n this.selectedMids.clear();\n this.toggleSelection();\n cancelSelection();\n if(doNotAnimate) this.doNotAnimate = undefined;\n };\n\n public cleanup() {\n this.doNotAnimate = true;\n this.selectedMids.clear();\n this.toggleSelection(false);\n this.doNotAnimate = undefined;\n }\n\n protected updateElementSelection(element: HTMLElement, isSelected: boolean) {\n this.toggleElementCheckbox(element, true);\n const input = this.getCheckboxInputFromElement(element);\n input.checked = isSelected;\n\n this.toggleSelection();\n this.updateContainer();\n SetTransition(element, 'is-selected', isSelected, 200);\n }\n\n public isMidSelected(peerId: PeerId, mid: number) {\n const set = this.selectedMids.get(peerId);\n return set?.has(mid);\n }\n\n public length() {\n return accumulateMapSet(this.selectedMids);\n }\n\n protected toggleMid(peerId: PeerId, mid: number, unselect?: boolean) {\n let set = this.selectedMids.get(peerId);\n if(unselect || (unselect === undefined && set?.has(mid))) {\n if(set) {\n set.delete(mid);\n\n if(!set.size) {\n this.selectedMids.delete(peerId);\n }\n }\n } else {\n const diff = rootScope.config.forwarded_count_max - this.length() - 1;\n if(diff < 0) {\n toast(I18n.format('Chat.Selection.LimitToast', true));\n return false;\n /* const it = this.selectedMids.values();\n do {\n const mid = it.next().value;\n const mounted = this.appImManager.getMountedBubble(mid);\n if(mounted) {\n this.toggleByBubble(mounted.bubble);\n } else {\n const mids = this.appMessagesManager.getMidsByMid(mid);\n for(const mid of mids) {\n this.selectedMids.delete(mid);\n }\n }\n } while(this.selectedMids.size > MAX_SELECTION_LENGTH); */\n }\n\n if(!set) {\n set = new Set();\n this.selectedMids.set(peerId, set);\n }\n\n set.add(mid);\n }\n\n return true;\n }\n\n /**\n * ! Call this method only to handle deleted messages\n */\n public deleteSelectedMids(peerId: PeerId, mids: number[]) {\n const set = this.selectedMids.get(peerId);\n if(!set) {\n return;\n }\n\n mids.forEach(mid => {\n set.delete(mid);\n });\n\n if(!set.size) {\n this.selectedMids.delete(peerId);\n }\n\n this.updateContainer();\n this.toggleSelection();\n }\n}\n\nexport class SearchSelection extends AppSelection {\n protected selectionContainer: HTMLElement;\n protected selectionCountEl: HTMLElement;\n public selectionForwardBtn: HTMLElement;\n public selectionDeleteBtn: HTMLElement;\n public selectionGotoBtn: HTMLElement;\n\n private isPrivate: boolean;\n\n constructor(private searchSuper: AppSearchSuper, appMessagesManager: AppMessagesManager) {\n super({\n appMessagesManager,\n listenElement: searchSuper.container,\n listenerSetter: new ListenerSetter(),\n verifyTarget: (e, target) => !!target && this.isSelecting,\n getElementFromTarget: (target) => findUpClassName(target, 'search-super-item'),\n targetLookupClassName: 'search-super-item',\n lookupBetweenParentClassName: 'tabs-tab',\n lookupBetweenElementsQuery: '.search-super-item'\n });\n\n this.isPrivate = !searchSuper.showSender;\n }\n\n /* public appendCheckbox(element: HTMLElement, checkboxField: CheckboxField) {\n checkboxField.label.classList.add('bubble-select-checkbox');\n\n if(element.classList.contains('document') || element.tagName === 'AUDIO-ELEMENT') {\n element.querySelector('.document, audio-element').append(checkboxField.label);\n } else {\n super.appendCheckbox(bubble, checkboxField);\n }\n } */\n\n public toggleSelection(toggleCheckboxes = true, forceSelection = false) {\n const ret = super.toggleSelection(toggleCheckboxes, forceSelection);\n\n if(ret && toggleCheckboxes) {\n const elements = Array.from(this.searchSuper.tabsContainer.querySelectorAll('.search-super-item')) as HTMLElement[];\n elements.forEach(element => {\n this.toggleElementCheckbox(element, this.isSelecting);\n });\n }\n\n return ret;\n }\n\n public toggleByElement = (element: HTMLElement) => {\n const mid = +element.dataset.mid;\n const peerId = element.dataset.peerId.toPeerId();\n\n if(!this.toggleMid(peerId, mid)) {\n return;\n }\n\n this.updateElementSelection(element, this.isMidSelected(peerId, mid));\n };\n\n public toggleByMid = (peerId: PeerId, mid: number) => {\n const element = this.searchSuper.mediaTab.contentTab.querySelector(`.search-super-item[data-peer-id=\"${peerId}\"][data-mid=\"${mid}\"]`) as HTMLElement;\n this.toggleByElement(element);\n };\n\n protected onUpdateContainer = (cantForward: boolean, cantDelete: boolean, cantSend: boolean) => {\n const length = this.length();\n replaceContent(this.selectionCountEl, i18n('messages', [length]));\n this.selectionGotoBtn.classList.toggle('hide', length !== 1);\n this.selectionForwardBtn.classList.toggle('hide', cantForward);\n this.selectionDeleteBtn && this.selectionDeleteBtn.classList.toggle('hide', cantDelete);\n };\n\n protected onToggleSelection = (forwards: boolean, animate: boolean) => {\n SetTransition(this.searchSuper.navScrollableContainer, 'is-selecting', forwards, animate ? 200 : 0, () => {\n if(!this.isSelecting) {\n this.selectionContainer.remove();\n this.selectionContainer = \n this.selectionForwardBtn = \n this.selectionDeleteBtn = \n null;\n this.selectedText = undefined;\n }\n });\n\n SetTransition(this.searchSuper.container, 'is-selecting', forwards, 200);\n\n if(this.isSelecting) {\n if(!this.selectionContainer) {\n const BASE_CLASS = 'search-super-selection';\n this.selectionContainer = document.createElement('div');\n this.selectionContainer.classList.add(BASE_CLASS + '-container');\n\n const btnCancel = ButtonIcon(`close ${BASE_CLASS}-cancel`, {noRipple: true});\n this.listenerSetter.add(btnCancel)('click', () => this.cancelSelection(), {once: true});\n\n this.selectionCountEl = document.createElement('div');\n this.selectionCountEl.classList.add(BASE_CLASS + '-count');\n\n this.selectionGotoBtn = ButtonIcon(`message ${BASE_CLASS}-goto`);\n\n const attachClickOptions: AttachClickOptions = {listenerSetter: this.listenerSetter};\n attachClickEvent(this.selectionGotoBtn, () => {\n const peerId = [...this.selectedMids.keys()][0];\n const mid = [...this.selectedMids.get(peerId)][0];\n this.cancelSelection();\n\n rootScope.dispatchEvent('history_focus', {\n peerId,\n mid\n });\n }, attachClickOptions);\n\n this.selectionForwardBtn = ButtonIcon(`forward ${BASE_CLASS}-forward`);\n attachClickEvent(this.selectionForwardBtn, () => {\n const obj: {[fromPeerId: PeerId]: number[]} = {};\n for(const [fromPeerId, mids] of this.selectedMids) {\n obj[fromPeerId] = Array.from(mids).sort((a, b) => a - b);\n }\n\n new PopupForward(obj, () => {\n this.cancelSelection();\n });\n }, attachClickOptions);\n\n if(this.isPrivate) {\n this.selectionDeleteBtn = ButtonIcon(`delete danger ${BASE_CLASS}-delete`);\n attachClickEvent(this.selectionDeleteBtn, () => {\n const peerId = [...this.selectedMids.keys()][0];\n new PopupDeleteMessages(peerId, [...this.selectedMids.get(peerId)], 'chat', () => {\n this.cancelSelection();\n });\n }, attachClickOptions);\n }\n\n this.selectionContainer.append(...[\n btnCancel, \n this.selectionCountEl, \n this.selectionGotoBtn, \n this.selectionForwardBtn, \n this.selectionDeleteBtn\n ].filter(Boolean));\n\n const transitionElement = this.selectionContainer;\n transitionElement.style.opacity = '0';\n this.searchSuper.navScrollableContainer.append(transitionElement);\n\n void transitionElement.offsetLeft; // reflow\n transitionElement.style.opacity = '';\n }\n }\n };\n}\n\nexport default class ChatSelection extends AppSelection {\n protected selectionInputWrapper: HTMLElement;\n protected selectionContainer: HTMLElement;\n protected selectionCountEl: HTMLElement;\n public selectionSendNowBtn: HTMLElement;\n public selectionForwardBtn: HTMLElement;\n public selectionDeleteBtn: HTMLElement;\n private selectionLeft: HTMLDivElement;\n private selectionRight: HTMLDivElement;\n\n constructor(private chat: Chat, private bubbles: ChatBubbles, private input: ChatInput, appMessagesManager: AppMessagesManager) {\n super({\n appMessagesManager,\n listenElement: bubbles.bubblesContainer,\n listenerSetter: bubbles.listenerSetter,\n getElementFromTarget: (target) => findUpClassName(target, 'grouped-item') || findUpClassName(target, 'bubble'),\n verifyTarget: (e, target) => {\n // LEFT BUTTON\n // проверка внизу нужна для того, чтобы не активировать селект если target потомок .bubble\n const bad = !this.selectedMids.size \n && !(e.target as HTMLElement).classList.contains('bubble')\n && !(e.target as HTMLElement).classList.contains('document-selection')\n && target;\n\n return !bad;\n },\n verifyMouseMoveTarget: (e, element, selecting) => {\n const bad = e.target !== element && \n !(e.target as HTMLElement).classList.contains('document-selection') && \n selecting === undefined && \n !this.selectedMids.size;\n return !bad;\n },\n verifyTouchLongPress: () => !this.chat.input.recording,\n targetLookupClassName: 'bubble',\n lookupBetweenParentClassName: 'bubbles-inner',\n lookupBetweenElementsQuery: '.bubble:not(.is-multiple-documents), .grouped-item',\n isScheduled: chat.type === 'scheduled'\n });\n }\n\n public appendCheckbox(bubble: HTMLElement, checkboxField: CheckboxField) {\n checkboxField.label.classList.add('bubble-select-checkbox');\n\n if(bubble.classList.contains('document-container')) {\n bubble.querySelector('.document, audio-element').append(checkboxField.label);\n } else {\n super.appendCheckbox(bubble, checkboxField);\n }\n }\n\n public toggleSelection(toggleCheckboxes = true, forceSelection = false) {\n const ret = super.toggleSelection(toggleCheckboxes, forceSelection);\n\n if(ret && toggleCheckboxes) {\n for(const mid in this.bubbles.bubbles) {\n const bubble = this.bubbles.bubbles[mid];\n this.toggleElementCheckbox(bubble, this.isSelecting);\n }\n }\n\n return ret;\n }\n\n public toggleElementCheckbox(bubble: HTMLElement, show: boolean) {\n if(!this.canSelectBubble(bubble)) return;\n\n const ret = super.toggleElementCheckbox(bubble, show);\n if(ret) {\n const isGrouped = bubble.classList.contains('is-grouped');\n if(isGrouped) {\n this.bubbles.getBubbleGroupedItems(bubble).forEach(item => this.toggleElementCheckbox(item, show));\n }\n }\n \n return ret;\n }\n\n public toggleByElement = (bubble: HTMLElement) => {\n if(!this.canSelectBubble(bubble)) return;\n\n const mid = +bubble.dataset.mid;\n\n const isGrouped = bubble.classList.contains('is-grouped');\n if(isGrouped) {\n if(!this.isGroupedBubbleSelected(bubble)) {\n const set = this.selectedMids.get(this.bubbles.peerId);\n if(set) {\n const mids = this.chat.getMidsByMid(mid);\n mids.forEach(mid => set.delete(mid));\n }\n }\n\n this.bubbles.getBubbleGroupedItems(bubble).forEach(this.toggleByElement);\n return;\n }\n\n if(!this.toggleMid(this.bubbles.peerId, mid)) {\n return;\n }\n\n const isGroupedItem = bubble.classList.contains('grouped-item');\n if(isGroupedItem) {\n const groupContainer = findUpClassName(bubble, 'bubble');\n const isGroupedSelected = this.isGroupedBubbleSelected(groupContainer);\n const isGroupedMidsSelected = this.isGroupedMidsSelected(mid);\n\n const willChange = isGroupedMidsSelected || isGroupedSelected;\n if(willChange) {\n this.updateElementSelection(groupContainer, isGroupedMidsSelected);\n }\n }\n\n this.updateElementSelection(bubble, this.isMidSelected(this.bubbles.peerId, mid));\n };\n\n protected toggleByMid = (peerId: PeerId, mid: number) => {\n const mounted = this.bubbles.getMountedBubble(mid);\n if(mounted) {\n this.toggleByElement(mounted.bubble);\n }\n };\n\n public isElementShouldBeSelected(element: HTMLElement) {\n const isGrouped = element.classList.contains('is-grouped');\n return super.isElementShouldBeSelected(element) && (!isGrouped || this.isGroupedMidsSelected(+element.dataset.mid));\n }\n\n protected isGroupedBubbleSelected(bubble: HTMLElement) {\n const groupedCheckboxInput = this.getCheckboxInputFromElement(bubble);\n return groupedCheckboxInput?.checked;\n }\n\n protected isGroupedMidsSelected(mid: number) {\n const mids = this.chat.getMidsByMid(mid);\n const selectedMids = mids.filter(mid => this.isMidSelected(this.bubbles.peerId, mid));\n return mids.length === selectedMids.length;\n }\n\n protected getCheckboxInputFromElement(bubble: HTMLElement) {\n /* let perf = performance.now();\n let checkbox = bubble.firstElementChild.tagName === 'LABEL' && bubble.firstElementChild.firstElementChild as HTMLInputElement;\n console.log('getCheckboxInputFromBubble firstElementChild time:', performance.now() - perf);\n \n perf = performance.now();\n checkbox = bubble.querySelector('label input');\n console.log('getCheckboxInputFromBubble querySelector time:', performance.now() - perf); */\n /* let perf = performance.now();\n let contains = bubble.classList.contains('document-container');\n console.log('getCheckboxInputFromBubble classList time:', performance.now() - perf);\n \n perf = performance.now();\n contains = bubble.className.includes('document-container');\n console.log('getCheckboxInputFromBubble className time:', performance.now() - perf); */\n \n return bubble.classList.contains('document-container') ? \n bubble.querySelector('label input') as HTMLInputElement : \n super.getCheckboxInputFromElement(bubble);\n }\n\n public canSelectBubble(bubble: HTMLElement) {\n return !bubble.classList.contains('service') && \n !bubble.classList.contains('is-outgoing') && \n !bubble.classList.contains('bubble-first') && \n !bubble.classList.contains('avoid-selection');\n }\n\n protected onToggleSelection = (forwards: boolean, animate: boolean) => {\n const {needTranslateX, widthFrom, widthTo} = this.chat.input.center(animate);\n\n SetTransition(this.listenElement, 'is-selecting', forwards, animate ? 200 : 0, () => {\n if(!this.isSelecting) {\n this.selectionInputWrapper.remove();\n this.selectionInputWrapper = \n this.selectionContainer = \n this.selectionSendNowBtn = \n this.selectionForwardBtn = \n this.selectionDeleteBtn = \n this.selectionLeft = \n this.selectionRight = \n null;\n this.selectedText = undefined;\n }\n \n /* fastRaf(() => {\n this.bubbles.onScroll();\n }); */\n });\n\n //const chatInput = this.appImManager.chatInput;\n\n const translateButtonsX = widthFrom < widthTo ? undefined : needTranslateX * 2;\n if(this.isSelecting) {\n if(!this.selectionContainer) {\n this.selectionInputWrapper = document.createElement('div');\n this.selectionInputWrapper.classList.add('chat-input-wrapper', 'selection-wrapper');\n\n // const background = document.createElement('div');\n // background.classList.add('chat-input-wrapper-background');\n\n this.selectionContainer = document.createElement('div');\n this.selectionContainer.classList.add('selection-container');\n\n const attachClickOptions: AttachClickOptions = {listenerSetter: this.listenerSetter};\n const btnCancel = ButtonIcon('close', {noRipple: true});\n attachClickEvent(btnCancel, () => this.cancelSelection(), {once: true, listenerSetter: this.listenerSetter});\n\n this.selectionCountEl = document.createElement('div');\n this.selectionCountEl.classList.add('selection-container-count');\n\n if(this.chat.type === 'scheduled') {\n this.selectionSendNowBtn = Button('btn-primary btn-transparent btn-short text-bold selection-container-send', {icon: 'send2'});\n this.selectionSendNowBtn.append(i18n('MessageScheduleSend'));\n attachClickEvent(this.selectionSendNowBtn, () => {\n new PopupSendNow(this.bubbles.peerId, [...this.selectedMids.get(this.bubbles.peerId)], () => {\n this.cancelSelection();\n });\n }, attachClickOptions);\n } else {\n this.selectionForwardBtn = Button('btn-primary btn-transparent text-bold selection-container-forward', {icon: 'forward'});\n this.selectionForwardBtn.append(i18n('Forward'));\n attachClickEvent(this.selectionForwardBtn, () => {\n const obj: {[fromPeerId: PeerId]: number[]} = {};\n for(const [fromPeerId, mids] of this.selectedMids) {\n obj[fromPeerId] = Array.from(mids).sort((a, b) => a - b);\n }\n\n new PopupForward(obj, () => {\n this.cancelSelection();\n });\n }, attachClickOptions);\n }\n\n this.selectionDeleteBtn = Button('btn-primary btn-transparent danger text-bold selection-container-delete', {icon: 'delete'});\n this.selectionDeleteBtn.append(i18n('Delete'));\n attachClickEvent(this.selectionDeleteBtn, () => {\n new PopupDeleteMessages(this.bubbles.peerId, [...this.selectedMids.get(this.bubbles.peerId)], this.chat.type, () => {\n this.cancelSelection();\n });\n }, attachClickOptions);\n\n const left = this.selectionLeft = document.createElement('div');\n left.classList.add('selection-container-left');\n left.append(btnCancel, this.selectionCountEl);\n\n const right = this.selectionRight = document.createElement('div');\n right.classList.add('selection-container-right');\n right.append(...[\n this.selectionSendNowBtn, \n this.selectionForwardBtn, \n this.selectionDeleteBtn\n ].filter(Boolean))\n\n if(translateButtonsX !== undefined) {\n left.style.transform = `translateX(${-translateButtonsX}px)`;\n right.style.transform = `translateX(${translateButtonsX}px)`;\n }\n\n this.selectionContainer.append(left, right);\n\n // background.style.opacity = '0';\n this.selectionInputWrapper.style.opacity = '0';\n this.selectionInputWrapper.append(/* background, */this.selectionContainer);\n this.input.inputContainer.append(this.selectionInputWrapper);\n \n void this.selectionInputWrapper.offsetLeft; // reflow\n // background.style.opacity = '';\n this.selectionInputWrapper.style.opacity = '';\n left.style.transform = '';\n right.style.transform = '';\n }\n } else if(this.selectionLeft && translateButtonsX !== undefined) {\n this.selectionLeft.style.transform = `translateX(-${translateButtonsX}px)`;\n this.selectionRight.style.transform = `translateX(${translateButtonsX}px)`;\n }\n };\n\n protected onUpdateContainer = (cantForward: boolean, cantDelete: boolean, cantSend: boolean) => {\n replaceContent(this.selectionCountEl, i18n('messages', [this.length()]));\n this.selectionSendNowBtn && this.selectionSendNowBtn.toggleAttribute('disabled', cantSend);\n this.selectionForwardBtn && this.selectionForwardBtn.toggleAttribute('disabled', cantForward);\n this.selectionDeleteBtn.toggleAttribute('disabled', cantDelete);\n };\n\n protected onCancelSelection = () => {\n for(const [peerId, mids] of this.selectedMids) {\n for(const mid of mids) {\n const mounted = this.bubbles.getMountedBubble(mid);\n if(mounted) {\n //this.toggleByBubble(mounted.message.grouped_id ? mounted.bubble.querySelector(`.grouped-item[data-mid=\"${mid}\"]`) : mounted.bubble);\n this.toggleByElement(mounted.bubble);\n }\n /* const bubble = this.appImManager.bubbles[mid];\n if(bubble) {\n this.toggleByBubble(bubble);\n } */\n }\n }\n };\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nexport default function getSelectedText(): string {\r\n if(window.getSelection) {\r\n return window.getSelection().toString();\r\n // @ts-ignore\r\n } else if(document.selection) {\r\n // @ts-ignore\r\n return document.selection.createRange().text;\r\n }\r\n \r\n return '';\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport appChatsManager from \"../lib/appManagers/appChatsManager\";\nimport appDialogsManager from \"../lib/appManagers/appDialogsManager\";\nimport appMessagesManager, { MyInputMessagesFilter, MyMessage } from \"../lib/appManagers/appMessagesManager\";\nimport appPeersManager from \"../lib/appManagers/appPeersManager\";\nimport appPhotosManager from \"../lib/appManagers/appPhotosManager\";\nimport appStateManager from \"../lib/appManagers/appStateManager\";\nimport appUsersManager from \"../lib/appManagers/appUsersManager\";\nimport { logger } from \"../lib/logger\";\nimport RichTextProcessor from \"../lib/richtextprocessor\";\nimport rootScope from \"../lib/rootScope\";\nimport { SearchGroup, SearchGroupType } from \"./appSearch\";\nimport { horizontalMenu } from \"./horizontalMenu\";\nimport LazyLoadQueue from \"./lazyLoadQueue\";\nimport { attachContextMenuListener, openBtnMenu, positionMenu, putPreloader } from \"./misc\";\nimport ripple from \"./ripple\";\nimport Scrollable, { ScrollableX } from \"./scrollable\";\nimport { wrapDocument, wrapPhoto, wrapVideo } from \"./wrappers\";\nimport useHeavyAnimationCheck, { getHeavyAnimationPromise } from \"../hooks/useHeavyAnimationCheck\";\nimport I18n, { LangPackKey, i18n } from \"../lib/langPack\";\nimport findUpClassName from \"../helpers/dom/findUpClassName\";\nimport { getMiddleware } from \"../helpers/middleware\";\nimport appProfileManager from \"../lib/appManagers/appProfileManager\";\nimport { ChannelParticipant, ChatFull, ChatParticipant, ChatParticipants, Message, MessageMedia, Photo, WebPage } from \"../layer\";\nimport SortedUserList from \"./sortedUserList\";\nimport findUpTag from \"../helpers/dom/findUpTag\";\nimport appSidebarRight from \"./sidebarRight\";\nimport mediaSizes from \"../helpers/mediaSizes\";\nimport appImManager from \"../lib/appManagers/appImManager\";\nimport positionElementByIndex from \"../helpers/dom/positionElementByIndex\";\nimport cleanSearchText from \"../helpers/cleanSearchText\";\nimport { IS_TOUCH_SUPPORTED } from \"../environment/touchSupport\";\nimport handleTabSwipe from \"../helpers/dom/handleTabSwipe\";\nimport windowSize from \"../helpers/windowSize\";\nimport { formatPhoneNumber } from \"../helpers/formatPhoneNumber\";\nimport ButtonMenu, { ButtonMenuItemOptions } from \"./buttonMenu\";\nimport PopupForward from \"./popups/forward\";\nimport PopupDeleteMessages from \"./popups/deleteMessages\";\nimport Row from \"./row\";\nimport htmlToDocumentFragment from \"../helpers/dom/htmlToDocumentFragment\";\nimport { SearchSelection } from \"./chat/selection\";\nimport cancelEvent from \"../helpers/dom/cancelEvent\";\nimport { attachClickEvent, simulateClickEvent } from \"../helpers/dom/clickEvent\";\nimport { MyDocument } from \"../lib/appManagers/appDocsManager\";\nimport AppMediaViewer from \"./appMediaViewer\";\nimport lockTouchScroll from \"../helpers/dom/lockTouchScroll\";\nimport copy from \"../helpers/object/copy\";\nimport getObjectKeysAndSort from \"../helpers/object/getObjectKeysAndSort\";\nimport safeAssign from \"../helpers/object/safeAssign\";\nimport escapeRegExp from \"../helpers/string/escapeRegExp\";\nimport limitSymbols from \"../helpers/string/limitSymbols\";\nimport findAndSplice from \"../helpers/array/findAndSplice\";\nimport { ScrollStartCallbackDimensions } from \"../helpers/fastSmoothScroll\";\nimport setInnerHTML from \"../helpers/dom/setInnerHTML\";\nimport appWebPagesManager from \"../lib/appManagers/appWebPagesManager\";\n\n//const testScroll = false;\n\nexport type SearchSuperType = MyInputMessagesFilter/* | 'members' */;\nexport type SearchSuperContext = {\n peerId: PeerId,\n inputFilter: {_: MyInputMessagesFilter},\n query?: string,\n maxId?: number,\n folderId?: number,\n threadId?: number,\n date?: number,\n nextRate?: number,\n minDate?: number,\n maxDate?: number\n};\n\nexport type SearchSuperMediaType = 'members' | 'media' | 'files' | 'links' | 'music' | 'chats' | 'voice';\nexport type SearchSuperMediaTab = {\n inputFilter: SearchSuperType,\n name: LangPackKey,\n type: SearchSuperMediaType,\n contentTab?: HTMLElement,\n menuTab?: HTMLElement,\n scroll?: {scrollTop: number, scrollHeight: number}\n};\n\nclass SearchContextMenu {\n private buttons: (ButtonMenuItemOptions & {verify?: () => boolean, withSelection?: true})[];\n private element: HTMLElement;\n private target: HTMLElement;\n private peerId: PeerId;\n private mid: number;\n private isSelected: boolean;\n\n constructor(\n private attachTo: HTMLElement,\n private searchSuper: AppSearchSuper\n ) {\n const onContextMenu = (e: MouseEvent) => {\n if(this.init) {\n this.init();\n this.init = null;\n }\n\n let item: HTMLElement;\n try {\n item = findUpClassName(e.target, 'search-super-item');\n } catch(e) {}\n\n if(!item) return;\n\n if(e instanceof MouseEvent) e.preventDefault();\n if(this.element.classList.contains('active')) {\n return false;\n }\n if(e instanceof MouseEvent) e.cancelBubble = true;\n\n this.target = item;\n this.peerId = item.dataset.peerId.toPeerId();\n this.mid = +item.dataset.mid;\n this.isSelected = searchSuper.selection.isMidSelected(this.peerId, this.mid);\n\n this.buttons.forEach(button => {\n let good: boolean;\n\n if(this.isSelected && !button.withSelection) {\n good = false;\n } else {\n good = button.verify ? button.verify() : true;\n }\n\n button.element.classList.toggle('hide', !good);\n });\n\n item.classList.add('menu-open');\n\n positionMenu(e, this.element);\n openBtnMenu(this.element, () => {\n item.classList.remove('menu-open');\n });\n };\n\n if(IS_TOUCH_SUPPORTED) {\n\n } else {\n attachContextMenuListener(attachTo, onContextMenu as any);\n }\n }\n\n private init() {\n this.buttons = [{\n icon: 'forward',\n text: 'Forward',\n onClick: this.onForwardClick,\n verify: () => appMessagesManager.canForward(appMessagesManager.getMessageByPeer(this.peerId, this.mid))\n }, {\n icon: 'forward',\n text: 'Message.Context.Selection.Forward',\n onClick: this.onForwardClick,\n verify: () => this.isSelected && \n !this.searchSuper.selection.selectionForwardBtn.classList.contains('hide'),\n withSelection: true\n }, {\n icon: 'message',\n text: 'Message.Context.Goto',\n onClick: this.onGotoClick,\n withSelection: true\n }, {\n icon: 'select',\n text: 'Message.Context.Select',\n onClick: this.onSelectClick\n }, {\n icon: 'select',\n text: 'Message.Context.Selection.Clear',\n onClick: this.onClearSelectionClick,\n verify: () => this.isSelected,\n withSelection: true\n }, {\n icon: 'delete danger',\n text: 'Delete',\n onClick: this.onDeleteClick,\n verify: () => appMessagesManager.canDeleteMessage(appMessagesManager.getMessageByPeer(this.peerId, this.mid))\n }, {\n icon: 'delete danger',\n text: 'Message.Context.Selection.Delete',\n onClick: this.onDeleteClick,\n verify: () => this.isSelected && !this.searchSuper.selection.selectionDeleteBtn.classList.contains('hide'),\n withSelection: true\n }];\n\n this.element = ButtonMenu(this.buttons);\n this.element.classList.add('search-contextmenu', 'contextmenu');\n document.getElementById('page-chats').append(this.element);\n }\n\n private onGotoClick = () => {\n rootScope.dispatchEvent('history_focus', {\n peerId: this.peerId,\n mid: this.mid,\n threadId: this.searchSuper.searchContext.threadId\n });\n };\n\n private onForwardClick = () => {\n if(this.searchSuper.selection.isSelecting) {\n simulateClickEvent(this.searchSuper.selection.selectionForwardBtn);\n } else {\n new PopupForward({\n [this.peerId]: [this.mid]\n });\n }\n };\n\n private onSelectClick = () => {\n this.searchSuper.selection.toggleByElement(this.target);\n };\n\n private onClearSelectionClick = () => {\n this.searchSuper.selection.cancelSelection();\n };\n\n private onDeleteClick = () => {\n if(this.searchSuper.selection.isSelecting) {\n simulateClickEvent(this.searchSuper.selection.selectionDeleteBtn);\n } else {\n new PopupDeleteMessages(this.peerId, [this.mid], 'chat');\n }\n };\n}\n\nexport type ProcessSearchSuperResult = {\n message: Message.message, \n middleware: () => boolean, \n promises: Promise<any>[], \n elemsToAppend: {element: HTMLElement, message: any}[],\n inputFilter: MyInputMessagesFilter,\n searchGroup?: SearchGroup\n};\n\nexport default class AppSearchSuper {\n public tabs: {[t in SearchSuperType]: HTMLDivElement} = {} as any;\n\n public mediaTab: SearchSuperMediaTab;\n\n public container: HTMLElement;\n public nav: HTMLElement;\n public navScrollableContainer: HTMLDivElement;\n public tabsContainer: HTMLElement;\n public navScrollable: ScrollableX;\n private tabsMenu: HTMLElement;\n private prevTabId = -1;\n \n private lazyLoadQueue = new LazyLoadQueue();\n public middleware = getMiddleware();\n\n public historyStorage: Partial<{[type in SearchSuperType]: {mid: number, peerId: PeerId}[]}> = {};\n public usedFromHistory: Partial<{[type in SearchSuperType]: number}> = {};\n public urlsToRevoke: string[] = [];\n\n public searchContext: SearchSuperContext;\n public loadMutex: Promise<any> = Promise.resolve();\n\n private nextRates: Partial<{[type in SearchSuperType]: number}> = {};\n private loadPromises: Partial<{[type in SearchSuperType]: Promise<void>}> = {};\n private loaded: Partial<{[type in SearchSuperType]: boolean}> = {};\n private loadedChats = false;\n private firstLoad = true;\n\n private log = logger('SEARCH-SUPER');\n public selectTab: ReturnType<typeof horizontalMenu>;\n \n private monthContainers: Partial<{\n [type in SearchSuperType]: {\n [timestamp: number]: {\n container: HTMLElement,\n items: HTMLElement\n }\n }\n }> = {};\n\n private searchGroupMedia: SearchGroup;\n\n public mediaTabsMap: Map<SearchSuperMediaType, SearchSuperMediaTab> = new Map();\n\n private membersList: SortedUserList;\n\n private skipScroll: boolean;\n\n // * arguments\n public mediaTabs: SearchSuperMediaTab[];\n public scrollable: Scrollable;\n public searchGroups?: {[group in SearchGroupType]: SearchGroup};\n public asChatList? = false;\n public groupByMonth? = true;\n public hideEmptyTabs? = true;\n public onChangeTab?: (mediaTab: SearchSuperMediaTab) => void;\n public showSender? = false;\n\n private searchContextMenu: SearchContextMenu;\n public selection: SearchSelection;\n\n public scrollStartCallback: (dimensions: ScrollStartCallbackDimensions) => void;\n\n constructor(options: Pick<AppSearchSuper, 'mediaTabs' | 'scrollable' | 'searchGroups' | 'asChatList' | 'groupByMonth' | 'hideEmptyTabs' | 'onChangeTab' | 'showSender'>) {\n safeAssign(this, options);\n\n this.container = document.createElement('div');\n this.container.classList.add('search-super');\n\n this.searchContextMenu = new SearchContextMenu(this.container, this);\n this.selection = new SearchSelection(this, appMessagesManager);\n\n const navScrollableContainer = this.navScrollableContainer = document.createElement('div');\n navScrollableContainer.classList.add('search-super-tabs-scrollable', 'menu-horizontal-scrollable', 'sticky');\n\n const navScrollable = this.navScrollable = new ScrollableX(navScrollableContainer);\n navScrollable.container.classList.add('search-super-nav-scrollable');\n\n const nav = this.nav = document.createElement('nav');\n nav.classList.add('search-super-tabs', 'menu-horizontal-div');\n this.tabsMenu = nav;\n\n navScrollable.container.append(nav);\n\n for(const mediaTab of this.mediaTabs) {\n const menuTab = document.createElement('div');\n menuTab.classList.add('menu-horizontal-div-item');\n const span = document.createElement('span');\n const i = document.createElement('i');\n\n span.append(i18n(mediaTab.name));\n span.append(i);\n\n menuTab.append(span);\n\n ripple(menuTab);\n\n this.tabsMenu.append(menuTab);\n\n this.mediaTabsMap.set(mediaTab.type, mediaTab);\n\n mediaTab.menuTab = menuTab;\n }\n\n this.tabsContainer = document.createElement('div');\n this.tabsContainer.classList.add('search-super-tabs-container', 'tabs-container');\n\n let unlockScroll: ReturnType<typeof lockTouchScroll>;\n if(IS_TOUCH_SUPPORTED) {\n handleTabSwipe({\n element: this.tabsContainer, \n onSwipe: (xDiff, yDiff, e) => {\n const prevId = this.selectTab.prevId();\n const children = Array.from(this.tabsMenu.children) as HTMLElement[];\n let idx: number;\n if(xDiff > 0) {\n for(let i = prevId + 1; i < children.length; ++i) {\n if(!children[i].classList.contains('hide')) {\n idx = i;\n break;\n }\n }\n } else {\n for(let i = prevId - 1; i >= 0; --i) {\n if(!children[i].classList.contains('hide')) {\n idx = i;\n break;\n }\n }\n }\n\n if(idx !== undefined) {\n unlockScroll = lockTouchScroll(this.tabsContainer);\n this.selectTab(idx);\n }\n }\n });\n }\n\n for(const mediaTab of this.mediaTabs) {\n const container = document.createElement('div');\n container.classList.add('search-super-container-' + mediaTab.type, 'tabs-tab');\n\n const content = document.createElement('div');\n content.classList.add('search-super-content-' + mediaTab.type);\n\n container.append(content);\n\n this.tabsContainer.append(container);\n\n this.tabs[mediaTab.inputFilter] = content;\n\n mediaTab.contentTab = content;\n }\n\n this.container.append(navScrollableContainer, this.tabsContainer);\n\n // * construct end\n\n this.searchGroupMedia = new SearchGroup(false, 'messages', true);\n\n this.scrollable.onScrolledBottom = () => {\n if(this.mediaTab.contentTab && !this.loaded[this.mediaTab.inputFilter]/* && false */) {\n //this.log('onScrolledBottom will load media');\n this.load(true);\n }\n };\n //this.scroll.attachSentinels(undefined, 400);\n\n this.selectTab = horizontalMenu(this.tabsMenu, this.tabsContainer, (id, tabContent, animate) => {\n if(this.prevTabId === id && !this.skipScroll) {\n this.scrollable.scrollIntoViewNew({\n element: this.container, \n position: 'start',\n startCallback: this.scrollStartCallback\n });\n return;\n }\n \n const newMediaTab = this.mediaTabs[id];\n if(this.onChangeTab) {\n this.onChangeTab(newMediaTab);\n }\n \n const fromMediaTab = this.mediaTab;\n this.mediaTab = newMediaTab;\n\n if(this.prevTabId !== -1 && animate) {\n this.onTransitionStart();\n }\n\n if(this.skipScroll) {\n this.skipScroll = false;\n } else {\n const offsetTop = this.container.offsetTop;\n let scrollTop = this.scrollable.scrollTop;\n if(scrollTop < offsetTop) {\n this.scrollable.scrollIntoViewNew({\n element: this.container, \n position: 'start',\n startCallback: this.scrollStartCallback\n });\n scrollTop = offsetTop;\n }\n \n fromMediaTab.scroll = {scrollTop: scrollTop, scrollHeight: this.scrollable.scrollHeight};\n \n if(newMediaTab.scroll === undefined) {\n const rect = this.container.getBoundingClientRect();\n const rect2 = this.container.parentElement.getBoundingClientRect();\n const diff = rect.y - rect2.y;\n \n if(scrollTop > diff) {\n newMediaTab.scroll = {scrollTop: diff, scrollHeight: 0};\n }\n }\n \n if(newMediaTab.scroll) {\n const diff = fromMediaTab.scroll.scrollTop - newMediaTab.scroll.scrollTop;\n //console.log('what you gonna do', this.goingHard, diff);\n \n //this.scrollable.scrollTop = scrollTop;\n if(diff/* && diff < 0 */) {\n /* if(diff > -(fromMediaTab.contentTab.scrollHeight + this.nav.scrollHeight)) {\n fromMediaTab.contentTab.style.transform = `translateY(${diff}px)`;\n this.scrollable.scrollTop = scrollTop - diff;\n } else { */\n newMediaTab.contentTab.style.transform = `translateY(${diff}px)`;\n //}\n }\n }\n }\n \n /* if(this.prevTabId !== -1 && nav.offsetTop) {\n this.scrollable.scrollTop -= nav.offsetTop;\n } */\n\n /* this.log('setVirtualContainer', id, this.sharedMediaSelected, this.sharedMediaSelected.childElementCount);\n this.scroll.setVirtualContainer(this.sharedMediaSelected); */\n\n if(this.prevTabId !== -1 && !newMediaTab.contentTab.childElementCount) { // quick brown fix\n //this.contentContainer.classList.remove('loaded');\n this.load(true);\n }\n\n this.prevTabId = id;\n }, () => {\n this.scrollable.onScroll();\n \n //console.log('what y', this.tabSelected.style.transform);\n if(this.mediaTab.scroll !== undefined) {\n this.mediaTab.contentTab.style.transform = '';\n this.scrollable.scrollTop = this.mediaTab.scroll.scrollTop;\n }\n\n if(unlockScroll) {\n unlockScroll();\n unlockScroll = undefined;\n }\n\n this.onTransitionEnd();\n }, undefined, navScrollable);\n\n attachClickEvent(this.tabsContainer, (e) => {\n if(this.selection.isSelecting) {\n cancelEvent(e);\n this.selection.toggleByElement(findUpClassName(e.target, 'search-super-item'));\n }\n }, {capture: true, passive: false});\n \n const onMediaClick = (className: string, targetClassName: string, inputFilter: MyInputMessagesFilter, e: MouseEvent) => {\n const target = findUpClassName(e.target as HTMLDivElement, className);\n if(!target) return;\n \n const mid = +target.dataset.mid;\n if(!mid) {\n this.log.warn('no messageId by click on target:', target);\n return;\n }\n\n const peerId = target.dataset.peerId.toPeerId();\n\n const targets = (Array.from(this.tabs[inputFilter].querySelectorAll('.' + targetClassName)) as HTMLElement[]).map(el => {\n const containerEl = findUpClassName(el, className);\n return {\n element: el, \n mid: +containerEl.dataset.mid, \n peerId: containerEl.dataset.peerId.toPeerId()\n };\n });\n\n //const ids = Object.keys(this.mediaDivsByIds).map(k => +k).sort((a, b) => a - b);\n const idx = targets.findIndex(item => item.mid === mid && item.peerId === peerId);\n \n const message = appMessagesManager.getMessageByPeer(peerId, mid);\n new AppMediaViewer()\n .setSearchContext(this.copySearchContext(inputFilter))\n .openMedia(message, targets[idx].element, 0, false, targets.slice(0, idx), targets.slice(idx + 1));\n };\n\n attachClickEvent(this.tabs.inputMessagesFilterPhotoVideo, onMediaClick.bind(null, 'grid-item', 'grid-item', 'inputMessagesFilterPhotoVideo'));\n attachClickEvent(this.tabs.inputMessagesFilterDocument, onMediaClick.bind(null, 'document-with-thumb', 'media-container', 'inputMessagesFilterDocument'));\n\n /* attachClickEvent(this.tabs.inputMessagesFilterUrl, (e) => {\n const target = e.target as HTMLElement;\n if(target.tagName === 'A') {\n return;\n }\n\n try {\n const a = findUpClassName(target, 'row').querySelector('.anchor-url:last-child') as HTMLAnchorElement;\n a.click();\n } catch(err) {}\n }); */\n\n this.mediaTab = this.mediaTabs[0];\n\n useHeavyAnimationCheck(() => {\n this.lazyLoadQueue.lock();\n }, () => {\n this.lazyLoadQueue.unlockAndRefresh(); // ! maybe not so efficient\n });\n }\n\n private onTransitionStart = () => {\n this.container.classList.add('sliding');\n };\n\n private onTransitionEnd = () => {\n this.container.classList.remove('sliding');\n };\n\n public filterMessagesByType(messages: any[], type: SearchSuperType): MyMessage[] {\n return appMessagesManager.filterMessagesByInputFilter(type, messages, messages.length);\n }\n\n private processEmptyFilter({message, searchGroup}: ProcessSearchSuperResult) {\n const {dialog, dom} = appDialogsManager.addDialogNew({\n dialog: message.peerId, \n container: searchGroup.list, \n drawStatus: false,\n avatarSize: 54\n });\n\n appDialogsManager.setLastMessage(dialog, message, dom, this.searchContext.query);\n }\n\n private processPhotoVideoFilter({message, promises, middleware, elemsToAppend}: ProcessSearchSuperResult) {\n const media = appMessagesManager.getMediaFromMessage(message);\n\n const div = document.createElement('div');\n div.classList.add('grid-item');\n //this.log(message, photo);\n\n let wrapped: ReturnType<typeof wrapPhoto>;\n const size = appPhotosManager.choosePhotoSize(media, 200, 200);\n if(media._ !== 'photo') {\n wrapped = wrapVideo({\n doc: media,\n message,\n container: div,\n boxWidth: 0,\n boxHeight: 0,\n lazyLoadQueue: this.lazyLoadQueue,\n middleware,\n onlyPreview: true,\n withoutPreloader: true,\n noPlayButton: true,\n size\n }).thumb;\n } else {\n wrapped = wrapPhoto({\n photo: media,\n message,\n container: div,\n boxWidth: 0,\n boxHeight: 0,\n lazyLoadQueue: this.lazyLoadQueue,\n middleware,\n withoutPreloader: true,\n noBlur: true,\n size\n });\n }\n\n [wrapped.images.thumb, wrapped.images.full].filter(Boolean).forEach(image => {\n image.classList.add('grid-item-media');\n });\n\n promises.push(wrapped.loadPromises.thumb);\n\n elemsToAppend.push({element: div, message});\n }\n\n private processDocumentFilter({message, elemsToAppend, inputFilter}: ProcessSearchSuperResult) {\n const document = appMessagesManager.getMediaFromMessage(message);\n const showSender = this.showSender || (['voice', 'round'] as MyDocument['type'][]).includes(document.type);\n const div = wrapDocument({\n message,\n withTime: !showSender,\n fontWeight: 400,\n voiceAsMusic: true,\n showSender,\n searchContext: this.copySearchContext(inputFilter),\n lazyLoadQueue: this.lazyLoadQueue,\n autoDownloadSize: 0\n });\n\n if((['audio', 'voice', 'round'] as MyDocument['type'][]).includes(document.type)) {\n div.classList.add('audio-48');\n }\n\n elemsToAppend.push({element: div, message});\n }\n\n private processUrlFilter({message, promises, middleware, elemsToAppend}: ProcessSearchSuperResult) {\n let webpage = (message.media as MessageMedia.messageMediaWebPage)?.webpage as WebPage.webPage;\n\n if(!webpage) {\n const entity = message.totalEntities ? message.totalEntities.find((e: any) => e._ === 'messageEntityUrl' || e._ === 'messageEntityTextUrl') : null;\n let url: string, display_url: string, sliced: string;\n\n if(!entity) {\n //this.log.error('NO ENTITY:', message);\n const match = RichTextProcessor.matchUrl(message.message);\n if(!match) {\n //this.log.error('NO ENTITY AND NO MATCH:', message);\n return;\n }\n\n url = match[0];\n } else {\n sliced = message.message.slice(entity.offset, entity.offset + entity.length);\n }\n\n if(entity?._ === 'messageEntityTextUrl') {\n url = entity.url;\n //display_url = sliced;\n } else {\n url = url || sliced;\n }\n\n display_url = url;\n\n const same = message.message === url;\n if(!url.match(/^(ftp|http|https):\\/\\//)) {\n display_url = 'https://' + url;\n url = url.includes('@') ? url : 'https://' + url;\n }\n\n display_url = new URL(display_url).hostname;\n\n webpage = {\n _: 'webPage',\n url,\n display_url,\n id: '',\n hash: 0\n };\n\n if(!same) {\n webpage.description = message.message;\n }\n }\n\n let previewDiv = document.createElement('div');\n previewDiv.classList.add('preview', 'row-media');\n \n //this.log('wrapping webpage', webpage);\n \n if(webpage.photo) {\n const res = wrapPhoto({\n container: previewDiv,\n message: null,\n photo: webpage.photo as Photo.photo,\n boxWidth: 0,\n boxHeight: 0,\n withoutPreloader: true,\n lazyLoadQueue: this.lazyLoadQueue,\n middleware,\n size: appPhotosManager.choosePhotoSize(webpage.photo as Photo.photo, 60, 60, false),\n loadPromises: promises,\n noBlur: true\n });\n } else {\n previewDiv.classList.add('empty');\n setInnerHTML(previewDiv, RichTextProcessor.getAbbreviation(webpage.title || webpage.display_url || webpage.description || webpage.url, true));\n }\n \n let title = appWebPagesManager.wrapTitle(webpage);\n\n const subtitleFragment = appWebPagesManager.wrapDescription(webpage);\n const aFragment = htmlToDocumentFragment(RichTextProcessor.wrapRichText(webpage.url || ''));\n const a = aFragment.firstElementChild;\n if(a instanceof HTMLAnchorElement) {\n try { // can have 'URIError: URI malformed'\n a.innerText = decodeURIComponent(a.href);\n } catch(err) {\n\n }\n }\n\n if(subtitleFragment.firstChild) {\n subtitleFragment.append('\\n');\n }\n\n subtitleFragment.append(a);\n\n if(this.showSender) {\n subtitleFragment.append('\\n', appMessagesManager.wrapSenderToPeer(message));\n }\n \n if(!title.textContent) {\n //title = new URL(webpage.url).hostname;\n title.append(RichTextProcessor.wrapPlainText(webpage.display_url.split('/', 1)[0]));\n }\n\n const row = new Row({\n title,\n titleRight: appMessagesManager.wrapSentTime(message),\n subtitle: subtitleFragment,\n havePadding: true,\n clickable: true,\n noRipple: true\n });\n\n /* const mediaDiv = document.createElement('div');\n mediaDiv.classList.add('row-media'); */\n\n row.container.append(previewDiv);\n \n /* ripple(div);\n div.append(previewDiv);\n div.insertAdjacentHTML('beforeend', `\n <div class=\"title\">${title}${titleAdditionHTML}</div>\n <div class=\"subtitle\">${subtitle}</div>\n <div class=\"url\">${url}</div>\n ${sender}\n `); */\n \n if(row.container.innerText.trim().length) {\n elemsToAppend.push({element: row.container, message});\n }\n }\n \n public async performSearchResult(messages: any[], mediaTab: SearchSuperMediaTab, append = true) {\n const elemsToAppend: {element: HTMLElement, message: any}[] = [];\n const sharedMediaDiv: HTMLElement = mediaTab.contentTab;\n const promises: Promise<any>[] = [];\n const middleware = this.middleware.get();\n let inputFilter = mediaTab.inputFilter;\n\n await getHeavyAnimationPromise();\n \n let searchGroup: SearchGroup;\n if(inputFilter === 'inputMessagesFilterPhotoVideo' && !!this.searchContext.query.trim()) {\n inputFilter = 'inputMessagesFilterEmpty';\n searchGroup = this.searchGroupMedia;\n sharedMediaDiv.append(searchGroup.container);\n } else if(inputFilter === 'inputMessagesFilterEmpty') {\n searchGroup = this.searchGroups.messages;\n }\n\n const options: ProcessSearchSuperResult = {\n elemsToAppend,\n inputFilter,\n message: undefined,\n middleware,\n promises,\n searchGroup\n };\n\n let processCallback: (options: ProcessSearchSuperResult) => any;\n\n // https://core.telegram.org/type/MessagesFilter\n switch(inputFilter) {\n case 'inputMessagesFilterEmpty': {\n processCallback = this.processEmptyFilter;\n break;\n }\n\n case 'inputMessagesFilterPhotoVideo': {\n processCallback = this.processPhotoVideoFilter;\n break;\n }\n \n case 'inputMessagesFilterVoice':\n case 'inputMessagesFilterRoundVoice':\n case 'inputMessagesFilterMusic':\n case 'inputMessagesFilterDocument': {\n processCallback = this.processDocumentFilter;\n break;\n }\n \n case 'inputMessagesFilterUrl': {\n processCallback = this.processUrlFilter;\n break;\n }\n\n default:\n //this.log.warn('death is my friend', messages);\n break;\n }\n\n if(processCallback) {\n processCallback = processCallback.bind(this);\n\n for(const message of messages) {\n try {\n options.message = message;\n processCallback(options);\n } catch(err) {\n this.log.error('error rendering filter', inputFilter, options, message, err);\n }\n }\n }\n \n if(searchGroup && searchGroup.list.childElementCount) {\n searchGroup.setActive();\n }\n\n if(this.loadMutex) {\n promises.push(this.loadMutex);\n }\n\n if(promises.length) {\n await Promise.all(promises);\n if(!middleware()) {\n //this.log.warn('peer changed');\n return;\n }\n }\n \n if(elemsToAppend.length) {\n const method = append ? 'append' : 'prepend';\n elemsToAppend.forEach(details => {\n const {element, message} = details;\n const monthContainer = this.getMonthContainerByTimestamp(this.groupByMonth ? message.date : 0, inputFilter);\n element.classList.add('search-super-item');\n element.dataset.mid = '' + message.mid;\n element.dataset.peerId = '' + message.peerId;\n monthContainer.items[method](element);\n\n if(this.selection.isSelecting) {\n this.selection.toggleElementCheckbox(element, true);\n }\n });\n }\n \n //if(type !== 'inputMessagesFilterEmpty') {\n this.afterPerforming(inputFilter === 'inputMessagesFilterEmpty' ? 1 : messages.length, sharedMediaDiv);\n //}\n }\n\n private afterPerforming(length: number, contentTab: HTMLElement) {\n if(contentTab) {\n const parent = contentTab.parentElement;\n Array.from(parent.children).slice(1).forEach(child => {\n child.remove();\n });\n\n //this.contentContainer.classList.add('loaded');\n\n if(!length && !contentTab.childElementCount) {\n const div = document.createElement('div');\n div.innerText = 'Nothing interesting here yet...';\n div.classList.add('position-center', 'text-center', 'content-empty', 'no-select');\n\n parent.append(div);\n }\n }\n }\n\n private loadChats() {\n const renderedPeerIds: Set<PeerId> = new Set();\n const middleware = this.middleware.get();\n\n for(let i in this.searchGroups) {\n const group = this.searchGroups[i as SearchGroupType];\n this.tabs.inputMessagesFilterEmpty.append(group.container);\n group.clear();\n }\n\n const query = this.searchContext.query;\n if(query) {\n const setResults = (results: PeerId[], group: SearchGroup, showMembersCount = false) => {\n results.forEach((peerId) => {\n if(renderedPeerIds.has(peerId)) {\n return;\n }\n \n renderedPeerIds.add(peerId);\n \n const peer = appPeersManager.getPeer(peerId);\n \n //////////this.log('contacts peer', peer);\n \n const {dom} = appDialogsManager.addDialogNew({\n dialog: peerId, \n container: group.list, \n drawStatus: false,\n avatarSize: 48,\n autonomous: group.autonomous\n });\n \n if(showMembersCount && (peer.participants_count || peer.participants)) {\n const regExp = new RegExp(`(${escapeRegExp(query)}|${escapeRegExp(cleanSearchText(query))})`, 'gi');\n dom.titleSpan.innerHTML = dom.titleSpan.innerHTML.replace(regExp, '<i>$1</i>');\n dom.lastMessageSpan.append(appProfileManager.getChatMembersString(peerId.toChatId()));\n } else if(peerId === rootScope.myId) {\n dom.lastMessageSpan.append(i18n('Presence.YourChat'));\n } else {\n let username = appPeersManager.getPeerUsername(peerId);\n if(!username) {\n const user = appUsersManager.getUser(peerId);\n if(user && user.phone) {\n username = '+' + formatPhoneNumber(user.phone).formatted;\n }\n } else {\n username = '@' + username;\n }\n \n dom.lastMessageSpan.innerHTML = '<i>' + username + '</i>';\n }\n });\n \n group.toggle();\n };\n \n const onLoad = <T>(arg: T) => {\n if(!middleware()) {\n return;\n }\n \n //this.loadedContacts = true;\n \n return arg;\n };\n \n return Promise.all([\n appUsersManager.getContactsPeerIds(query, true)\n .then(onLoad)\n .then((contacts) => {\n if(contacts) {\n setResults(contacts, this.searchGroups.contacts, true);\n }\n }),\n \n appUsersManager.searchContacts(query, 20)\n .then(onLoad)\n .then((contacts) => {\n if(contacts) {\n setResults(contacts.my_results, this.searchGroups.contacts, true);\n setResults(contacts.results/* .concat(contacts.results, contacts.results, contacts.results) */, this.searchGroups.globalContacts);\n\n this.searchGroups.globalContacts.container.classList.add('is-short');\n\n if(this.searchGroups.globalContacts.nameEl.lastElementChild !== this.searchGroups.globalContacts.nameEl.firstElementChild) {\n this.searchGroups.globalContacts.nameEl.lastElementChild.remove();\n }\n \n if(this.searchGroups.globalContacts.list.childElementCount > 3) {\n const showMore = document.createElement('div');\n showMore.classList.add('search-group__show-more');\n const intlElement = new I18n.IntlElement({\n key: 'Separator.ShowMore'\n });\n showMore.append(intlElement.element);\n this.searchGroups.globalContacts.nameEl.append(showMore);\n attachClickEvent(showMore, () => {\n const isShort = this.searchGroups.globalContacts.container.classList.toggle('is-short');\n intlElement.key = isShort ? 'Separator.ShowMore' : 'Separator.ShowLess';\n intlElement.update();\n });\n }\n }\n }),\n \n appMessagesManager.getConversations(query, 0, 20, 0).promise\n .then(onLoad)\n .then(value => {\n if(value) {\n setResults(value.dialogs.map(d => d.peerId), this.searchGroups.contacts, true);\n }\n })\n ]);\n } else if(!this.searchContext.peerId && !this.searchContext.minDate) {\n const renderRecentSearch = (setActive = true) => {\n return appStateManager.getState().then(state => {\n if(!middleware()) {\n return;\n }\n \n this.searchGroups.recent.list.innerHTML = '';\n \n state.recentSearch.slice(0, 20).forEach(peerId => {\n let {dialog, dom} = appDialogsManager.addDialogNew({\n dialog: peerId,\n container: this.searchGroups.recent.list,\n drawStatus: false,\n meAsSaved: true,\n avatarSize: 48,\n autonomous: true\n });\n \n dom.lastMessageSpan.append(peerId.isUser() ? appUsersManager.getUserStatusString(peerId) : appProfileManager.getChatMembersString(peerId.toChatId()));\n });\n \n if(!state.recentSearch.length) {\n this.searchGroups.recent.clear();\n } else if(setActive) {\n this.searchGroups.recent.setActive();\n }\n });\n };\n\n return Promise.all([\n appUsersManager.getTopPeers('correspondents').then(peers => {\n if(!middleware()) return;\n\n const idx = peers.findIndex(peer => peer.id === rootScope.myId);\n if(idx !== -1) {\n peers = peers.slice();\n peers.splice(idx, 1);\n }\n //console.log('got top categories:', categories);\n if(peers.length) {\n peers.forEach((peer) => {\n appDialogsManager.addDialogNew({\n dialog: peer.id, \n container: this.searchGroups.people.list, \n drawStatus: false,\n onlyFirstName: true,\n avatarSize: 54,\n autonomous: false\n });\n });\n }\n \n this.searchGroups.people.setActive();\n }),\n\n renderRecentSearch()\n ]);\n } else return Promise.resolve();\n }\n\n private loadMembers(mediaTab: SearchSuperMediaTab) {\n const id = this.searchContext.peerId.toChatId();\n const middleware = this.middleware.get();\n let promise: Promise<void>;\n\n const renderParticipants = async(participants: (ChatParticipant | ChannelParticipant)[]) => {\n if(this.loadMutex) {\n await this.loadMutex;\n\n if(!middleware()) {\n return;\n }\n }\n \n if(!this.membersList) {\n this.membersList = new SortedUserList({lazyLoadQueue: this.lazyLoadQueue, rippleEnabled: false});\n attachClickEvent(this.membersList.list, (e) => {\n const li = findUpTag(e.target, 'LI');\n if(!li) {\n return;\n }\n\n const peerId = li.dataset.peerId.toPeerId();\n let promise: Promise<any> = Promise.resolve();\n if(mediaSizes.isMobile) {\n promise = appSidebarRight.toggleSidebar(false);\n }\n \n promise.then(() => {\n appImManager.setInnerPeer({peerId});\n });\n });\n mediaTab.contentTab.append(this.membersList.list);\n this.afterPerforming(1, mediaTab.contentTab);\n }\n\n participants.forEach(participant => {\n const peerId = appChatsManager.getParticipantPeerId(participant);\n if(peerId.isAnyChat()) {\n return;\n }\n\n const user = appUsersManager.getUser(peerId);\n if(user.pFlags.deleted) {\n return;\n }\n\n this.membersList.add(peerId);\n });\n };\n\n if(appChatsManager.isChannel(id)) {\n const LOAD_COUNT = !this.membersList ? 50 : 200;\n promise = appProfileManager.getChannelParticipants(id, undefined, LOAD_COUNT, this.nextRates[mediaTab.inputFilter]).then(participants => {\n if(!middleware()) {\n return;\n }\n\n let list = mediaTab.contentTab.firstElementChild as HTMLUListElement;\n this.nextRates[mediaTab.inputFilter] = (list ? list.childElementCount : 0) + participants.participants.length;\n\n if(participants.participants.length < LOAD_COUNT) {\n this.loaded[mediaTab.inputFilter] = true;\n }\n\n return renderParticipants(participants.participants);\n });\n } else {\n promise = Promise.resolve(appProfileManager.getChatFull(id)).then(chatFull => {\n if(!middleware()) {\n return;\n }\n\n //console.log('anymore', chatFull);\n this.loaded[mediaTab.inputFilter] = true;\n const participants = (chatFull as ChatFull.chatFull).participants;\n if(participants._ === 'chatParticipantsForbidden') {\n return;\n }\n \n return renderParticipants(participants.participants);\n });\n }\n\n return this.loadPromises[mediaTab.inputFilter] = promise.finally(() => { \n if(!middleware()) {\n return;\n }\n\n this.loadPromises[mediaTab.inputFilter] = null;\n });\n }\n\n private loadType(mediaTab: SearchSuperMediaTab, justLoad: boolean, loadCount: number, middleware: () => boolean) {\n const type = mediaTab.inputFilter;\n\n if(this.loadPromises[type]) {\n return this.loadPromises[type];\n }\n\n if(mediaTab.type === 'members') {\n return this.loadMembers(mediaTab);\n }\n\n const history = this.historyStorage[type] ?? (this.historyStorage[type] = []);\n\n if(type === 'inputMessagesFilterEmpty' && !history.length) {\n if(!this.loadedChats) {\n this.loadChats();\n this.loadedChats = true;\n }\n\n if(!this.searchContext.query.trim() && !this.searchContext.peerId && !this.searchContext.minDate) {\n this.loaded[type] = true;\n return Promise.resolve();\n }\n }\n\n const logStr = 'load [' + type + ']: ';\n\n // render from cache\n if(history.length && this.usedFromHistory[type] < history.length && !justLoad) {\n let messages: any[] = [];\n let used = Math.max(0, this.usedFromHistory[type]);\n let slicedLength = 0;\n\n do {\n let ids = history.slice(used, used + loadCount);\n //this.log(logStr + 'will render from cache', used, history, ids, loadCount);\n used += ids.length;\n slicedLength += ids.length;\n\n messages.push(...this.filterMessagesByType(ids.map(m => appMessagesManager.getMessageByPeer(m.peerId, m.mid)), type));\n } while(slicedLength < loadCount && used < history.length);\n \n // если перебор\n /* if(slicedLength > loadCount) {\n let diff = messages.length - loadCount;\n messages = messages.slice(0, messages.length - diff);\n used -= diff;\n } */\n\n this.usedFromHistory[type] = used;\n //if(messages.length) {\n return this.performSearchResult(messages, mediaTab).finally(() => {\n setTimeout(() => {\n this.scrollable.checkForTriggers();\n }, 0);\n });\n //}\n\n return Promise.resolve();\n }\n \n let maxId = history.length ? history[history.length - 1].mid : 0;\n \n //this.log(logStr + 'search house of glass pre', type, maxId);\n \n //let loadCount = history.length ? 50 : 15;\n return this.loadPromises[type] = appMessagesManager.getSearch({\n ...this.searchContext,\n inputFilter: {_: type},\n maxId, \n limit: loadCount,\n nextRate: this.nextRates[type] ?? (this.nextRates[type] = 0)\n }).then(value => {\n history.push(...value.history.map(m => ({mid: m.mid, peerId: m.peerId})));\n \n this.log(logStr + 'search house of glass', type, value);\n\n if(!middleware()) {\n //this.log.warn('peer changed');\n return;\n }\n\n // ! Фикс случая, когда не загружаются документы при открытой панели разработчиков (происходит из-за того, что не совпадают критерии отбора документов в getSearch)\n if(value.history.length < loadCount || (this.searchContext.folderId !== undefined && !value.next_rate) || value.history.length === value.count) {\n //if((value.count || history.length === value.count) && history.length >= value.count) {\n //this.log(logStr + 'loaded all media', value, loadCount);\n this.loaded[type] = true;\n }\n\n this.nextRates[type] = value.next_rate;\n\n if(justLoad) {\n return Promise.resolve();\n }\n\n this.usedFromHistory[type] = history.length;\n\n if(!this.loaded[type]) {\n (this.loadPromises[type] || Promise.resolve()).then(() => {\n setTimeout(() => {\n if(!middleware()) return;\n //this.log('will preload more');\n if(this.mediaTab === mediaTab) {\n const promise = this.load(true, true);\n if(promise) {\n promise.then(() => {\n if(!middleware()) return;\n //this.log('preloaded more');\n setTimeout(() => {\n this.scrollable.checkForTriggers();\n }, 0);\n });\n }\n }\n }, 0);\n });\n }\n\n //if(value.history.length) {\n return this.performSearchResult(this.filterMessagesByType(value.history, type), mediaTab);\n //}\n }).catch(err => {\n this.log.error('load error:', err);\n }).finally(() => {\n this.loadPromises[type] = null;\n });\n }\n \n public async load(single = false, justLoad = false) {\n // if(testScroll/* || 1 === 1 */) {\n // return;\n // }\n\n //return;\n \n const peerId = this.searchContext.peerId;\n this.log('load', single, peerId, this.loadPromises);\n const middleware = this.middleware.get();\n\n if(this.firstLoad) {\n if(this.hideEmptyTabs) {\n const mediaTabs = this.mediaTabs.filter(mediaTab => mediaTab.inputFilter !== 'inputMessagesFilterEmpty')\n const filters = mediaTabs.map(mediaTab => ({_: mediaTab.inputFilter}));\n\n const counters = await appMessagesManager.getSearchCounters(peerId, filters);\n if(!middleware()) {\n return;\n }\n\n if(this.loadMutex) {\n await this.loadMutex;\n\n if(!middleware()) {\n return;\n }\n }\n\n let firstMediaTab: SearchSuperMediaTab;\n let count = 0;\n mediaTabs.forEach(mediaTab => {\n const counter = counters.find(c => c.filter._ === mediaTab.inputFilter);\n\n mediaTab.menuTab.classList.toggle('hide', !counter.count);\n mediaTab.menuTab.classList.remove('active');\n //mediaTab.contentTab.classList.toggle('hide', !counter.count);\n\n if(counter.count && firstMediaTab === undefined) {\n firstMediaTab = mediaTab;\n }\n\n if(counter.count) ++count;\n });\n\n const membersTab = this.mediaTabsMap.get('members');\n const canViewMembers = this.canViewMembers();\n membersTab.menuTab.classList.toggle('hide', !canViewMembers);\n\n if(canViewMembers) {\n firstMediaTab = membersTab;\n }\n\n this.container.classList.toggle('hide', !firstMediaTab);\n this.container.parentElement.classList.toggle('search-empty', !firstMediaTab);\n if(firstMediaTab) {\n this.skipScroll = true;\n this.selectTab(this.mediaTabs.indexOf(firstMediaTab), false);\n firstMediaTab.menuTab.classList.add('active');\n\n this.navScrollableContainer.classList.toggle('hide', count <= 1);\n }\n }\n\n this.firstLoad = false;\n }\n \n let toLoad = single ? [this.mediaTab] : this.mediaTabs.filter(t => t !== this.mediaTab);\n toLoad = toLoad.filter(mediaTab => {\n const inputFilter = mediaTab.inputFilter;\n return !this.loaded[inputFilter] || (this.historyStorage[inputFilter] && this.usedFromHistory[inputFilter] < this.historyStorage[inputFilter].length);\n });\n\n if(peerId.isUser()) {\n findAndSplice(toLoad, mediaTab => mediaTab.type === 'members');\n }\n\n if(!toLoad.length) {\n return;\n }\n\n const loadCount = justLoad ? 50 : Math.round((windowSize.height / 130 | 0) * 3 * 1.25); // that's good for all types\n\n const promises: Promise<any>[] = toLoad.map(mediaTab => {\n return this.loadType(mediaTab, justLoad, loadCount, middleware)\n });\n\n return Promise.all(promises).catch(err => {\n this.log.error('Load error all promises:', err);\n });\n }\n \n public getMonthContainerByTimestamp(timestamp: number, type: SearchSuperType) {\n const date = new Date(timestamp * 1000);\n date.setHours(0, 0, 0);\n date.setDate(1);\n const dateTimestamp = date.getTime();\n const containers = this.monthContainers[type] ?? (this.monthContainers[type] = {});\n if(!(dateTimestamp in containers)) {\n const container = document.createElement('div');\n container.className = 'search-super-month';\n\n const name = document.createElement('div');\n name.classList.add('search-super-month-name');\n\n const options: Intl.DateTimeFormatOptions = {\n month: 'long'\n };\n\n if(date.getFullYear() !== new Date().getFullYear()) {\n options.year = 'numeric';\n }\n\n const dateElement = new I18n.IntlDateElement({\n date,\n options\n }).element;\n name.append(dateElement);\n\n container.append(name);\n\n const items = document.createElement('div');\n items.classList.add('search-super-month-items');\n\n container.append(name, items);\n\n const haveTimestamps = getObjectKeysAndSort(containers, 'desc');\n let i = 0;\n for(; i < haveTimestamps.length; ++i) {\n const t = haveTimestamps[i];\n if(dateTimestamp > t) {\n break;\n }\n }\n \n containers[dateTimestamp] = {container, items};\n positionElementByIndex(container, this.tabs[type], i);\n }\n\n return containers[dateTimestamp];\n }\n\n public canViewMembers() {\n return this.searchContext.peerId.isAnyChat() && !appChatsManager.isBroadcast(this.searchContext.peerId.toChatId()) && appChatsManager.hasRights(this.searchContext.peerId.toChatId(), 'view_participants');\n }\n\n public cleanup() {\n this.loadPromises = {};\n this.loaded = {};\n this.loadedChats = false;\n this.nextRates = {};\n this.firstLoad = true;\n\n this.lazyLoadQueue.clear();\n\n this.mediaTabs.forEach(mediaTab => {\n this.usedFromHistory[mediaTab.inputFilter] = -1;\n });\n\n if(this.selection.isSelecting) {\n this.selection.cancelSelection();\n }\n\n // * must go to first tab (это костыль)\n /* const membersTab = this.mediaTabsMap.get('members');\n if(membersTab) {\n const tab = this.canViewMembers() ? membersTab : this.mediaTabs[this.mediaTabs.indexOf(membersTab) + 1];\n this.mediaTab = tab;\n } */\n\n this.middleware.clean();\n this.cleanScrollPositions();\n this.membersList = undefined;\n }\n\n public cleanScrollPositions() {\n this.mediaTabs.forEach(mediaTab => {\n mediaTab.scroll = undefined;\n });\n }\n\n public cleanupHTML(goFirst = false) {\n if(this.urlsToRevoke.length) {\n this.urlsToRevoke.forEach(url => {\n URL.revokeObjectURL(url);\n });\n this.urlsToRevoke.length = 0;\n }\n\n this.mediaTabs.forEach((tab) => {\n tab.contentTab.innerHTML = '';\n\n if(this.hideEmptyTabs) {\n //tab.menuTab.classList.add('hide');\n this.container.classList.add('hide');\n this.container.parentElement.classList.add('search-empty');\n }\n\n if(tab.type === 'chats') {\n return;\n }\n \n if(!this.historyStorage[tab.inputFilter]) {\n const parent = tab.contentTab.parentElement;\n //if(!testScroll) {\n if(!parent.querySelector('.preloader')) {\n putPreloader(parent, true);\n }\n //}\n\n const empty = parent.querySelector('.content-empty');\n if(empty) {\n empty.remove();\n }\n }\n });\n\n /* if(goFirst) {\n const membersTab = this.mediaTabsMap.get('members');\n if(membersTab) {\n let idx = this.canViewMembers() ? 0 : 1;\n membersTab.menuTab.classList.toggle('hide', idx !== 0);\n\n this.selectTab(idx, false);\n } else {\n this.selectTab(0, false);\n }\n } */\n\n this.monthContainers = {};\n this.searchGroupMedia.clear();\n this.scrollable.scrollTop = 0;\n\n /* if(testScroll) {\n for(let i = 0; i < 1500; ++i) {\n let div = document.createElement('div');\n div.insertAdjacentHTML('beforeend', `<img class=\"media-image\" src=\"assets/img/camomile.jpg\">`);\n div.classList.add('grid-item');\n div.dataset.id = '' + (i / 3 | 0);\n //div.innerText = '' + (i / 3 | 0);\n this.tabs.inputMessagesFilterPhotoVideo.append(div);\n }\n } */\n }\n\n private copySearchContext(newInputFilter: MyInputMessagesFilter) {\n const context = copy(this.searchContext);\n context.inputFilter = {_: newInputFilter};\n context.nextRate = this.nextRates[newInputFilter];\n return context;\n }\n\n public setQuery({peerId, query, threadId, historyStorage, folderId, minDate, maxDate}: {\n peerId: PeerId, \n query?: string, \n threadId?: number, \n historyStorage?: AppSearchSuper['historyStorage'], \n folderId?: number,\n minDate?: number,\n maxDate?: number\n }) {\n this.searchContext = {\n peerId,\n query: query || '',\n inputFilter: {_: this.mediaTab.inputFilter},\n threadId,\n folderId,\n minDate,\n maxDate\n };\n \n this.historyStorage = historyStorage ?? {};\n\n this.cleanup();\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport cancelEvent from \"./cancelEvent\";\n\nexport default function lockTouchScroll(container: HTMLElement) {\n const onTouchMove = (e: TouchEvent) => {\n cancelEvent(e);\n };\n\n let lockers = 2;\n const cb = () => {\n if(!--lockers) {\n container.removeEventListener('touchmove', onTouchMove, {capture: true});\n }\n };\n\n container.addEventListener('touchmove', onTouchMove, {capture: true, passive: false});\n container.addEventListener('touchend', cb, {once: true});\n\n return cb;\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport cancelEvent from \"../helpers/dom/cancelEvent\";\r\nimport { AttachClickOptions, CLICK_EVENT_NAME } from \"../helpers/dom/clickEvent\";\r\nimport ListenerSetter from \"../helpers/listenerSetter\";\r\nimport ButtonIcon from \"./buttonIcon\";\r\nimport ButtonMenu, { ButtonMenuItemOptions } from \"./buttonMenu\";\r\nimport { closeBtnMenu, openBtnMenu } from \"./misc\";\r\n\r\nconst ButtonMenuToggle = (\r\n options: Partial<{\r\n noRipple: true, \r\n onlyMobile: true, \r\n listenerSetter: ListenerSetter, \r\n asDiv: boolean,\r\n container: HTMLElement\r\n }> = {}, \r\n direction: 'bottom-left' | 'bottom-right' | 'top-left' | 'top-right', \r\n buttons: ButtonMenuItemOptions[], \r\n onOpen?: (e: Event) => void,\r\n onClose?: () => void\r\n) => {\r\n options.asDiv = true;\r\n const button = options.container ?? ButtonIcon('more', options);\r\n button.classList.add('btn-menu-toggle');\r\n\r\n const btnMenu = ButtonMenu(buttons, options.listenerSetter);\r\n btnMenu.classList.add(direction);\r\n ButtonMenuToggleHandler(button, onOpen, options, onClose);\r\n button.append(btnMenu);\r\n return button;\r\n};\r\n\r\n// TODO: refactor for attachClickEvent, because if move finger after touchstart, it will start anyway\r\nconst ButtonMenuToggleHandler = (el: HTMLElement, onOpen?: (e: Event) => void, options?: AttachClickOptions, onClose?: () => void) => {\r\n const add = options?.listenerSetter ? options.listenerSetter.add(el) : el.addEventListener.bind(el);\r\n\r\n //console.trace('ButtonMenuToggleHandler attach', el, onOpen, options);\r\n add(CLICK_EVENT_NAME, (e: Event) => {\r\n //console.log('ButtonMenuToggleHandler click', e);\r\n if(!el.classList.contains('btn-menu-toggle')) return false;\r\n\r\n //window.removeEventListener('mousemove', onMouseMove);\r\n const openedMenu = el.querySelector('.btn-menu') as HTMLDivElement;\r\n cancelEvent(e);\r\n\r\n if(el.classList.contains('menu-open')) {\r\n closeBtnMenu();\r\n } else {\r\n onOpen && onOpen(e);\r\n openBtnMenu(openedMenu, onClose);\r\n }\r\n });\r\n};\r\n\r\nexport { ButtonMenuToggleHandler };\r\nexport default ButtonMenuToggle;\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\r\nimport { InputPrivacyKey, InputPrivacyRule, PrivacyRule, Update, PrivacyKey } from \"../../layer\";\r\nimport apiManager from \"../mtproto/mtprotoworker\";\r\nimport appChatsManager from \"./appChatsManager\";\r\nimport appUsersManager from \"./appUsersManager\";\r\nimport apiUpdatesManager from \"./apiUpdatesManager\";\r\nimport rootScope from \"../rootScope\";\r\nimport convertInputKeyToKey from \"../../helpers/string/convertInputKeyToKey\";\r\n\r\nexport enum PrivacyType {\r\n Everybody = 2,\r\n Contacts = 1,\r\n Nobody = 0\r\n}\r\n\r\nexport class AppPrivacyManager {\r\n private privacy: Partial<{\r\n [key in PrivacyKey['_']]: PrivacyRule[] | Promise<PrivacyRule[]>\r\n }> = {};\r\n\r\n constructor() {\r\n rootScope.addMultipleEventsListeners({\r\n updatePrivacy: (update) => {\r\n const key = update.key._;\r\n this.privacy[key] = update.rules;\r\n rootScope.dispatchEvent('privacy_update', update);\r\n }\r\n });\r\n }\r\n\r\n public setPrivacy(inputKey: InputPrivacyKey['_'], rules: InputPrivacyRule[]) {\r\n return apiManager.invokeApi('account.setPrivacy', {\r\n key: {\r\n _: inputKey\r\n },\r\n rules\r\n }).then(privacyRules => {\r\n appUsersManager.saveApiUsers(privacyRules.users);\r\n appChatsManager.saveApiChats(privacyRules.chats);\r\n\r\n apiUpdatesManager.processLocalUpdate({\r\n _: 'updatePrivacy',\r\n key: {\r\n _: convertInputKeyToKey(inputKey)\r\n },\r\n rules: rules.map(inputRule => {\r\n const rule: PrivacyRule = {} as any;\r\n Object.assign(rule, inputRule);\r\n rule._ = convertInputKeyToKey(rule._) as any;\r\n return rule;\r\n })\r\n });\r\n\r\n //console.log('privacy rules', inputKey, privacyRules, privacyRules.rules);\r\n\r\n return privacyRules.rules;\r\n });\r\n }\r\n\r\n public getPrivacy(inputKey: InputPrivacyKey['_']) {\r\n const privacyKey: PrivacyKey['_'] = convertInputKeyToKey(inputKey) as any;\r\n const rules = this.privacy[privacyKey];\r\n if(rules) {\r\n return Promise.resolve(rules);\r\n }\r\n \r\n return this.privacy[privacyKey] = apiManager.invokeApi('account.getPrivacy', {\r\n key: {\r\n _: inputKey\r\n }\r\n }).then(privacyRules => {\r\n appUsersManager.saveApiUsers(privacyRules.users);\r\n appChatsManager.saveApiChats(privacyRules.chats);\r\n\r\n //console.log('privacy rules', inputKey, privacyRules, privacyRules.rules);\r\n\r\n return this.privacy[privacyKey] = privacyRules.rules;\r\n });\r\n }\r\n\r\n public getPrivacyRulesDetails(rules: PrivacyRule[]) {\r\n const types: PrivacyType[] = [];\r\n\r\n type peers = {users: UserId[], chats: ChatId[]};\r\n let allowPeers: peers = {users: [], chats: []}, disallowPeers: peers = {users: [], chats: []};\r\n rules.forEach(rule => {\r\n switch(rule._) {\r\n case 'privacyValueAllowAll':\r\n types.push(2);\r\n break;\r\n case 'privacyValueDisallowAll':\r\n types.push(0);\r\n break;\r\n case 'privacyValueAllowContacts': \r\n types.push(1);\r\n break;\r\n /* case 'privacyValueDisallowContacts':\r\n types.push('Except My Contacts');\r\n break; */\r\n case 'privacyValueAllowChatParticipants':\r\n allowPeers.chats.push(...rule.chats);\r\n break;\r\n case 'privacyValueAllowUsers':\r\n allowPeers.users.push(...rule.users);\r\n break;\r\n case 'privacyValueDisallowChatParticipants':\r\n disallowPeers.chats.push(...rule.chats);\r\n break;\r\n case 'privacyValueDisallowUsers':\r\n disallowPeers.users.push(...rule.users);\r\n break;\r\n }\r\n });\r\n\r\n return {type: types[0], disallowPeers, allowPeers};\r\n }\r\n}\r\n\r\nconst appPrivacyManager = new AppPrivacyManager();\r\nMOUNT_CLASS_TO.appPrivacyManager = appPrivacyManager;\r\nexport default appPrivacyManager;\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport replaceContent from \"../helpers/dom/replaceContent\";\r\nimport { randomLong } from \"../helpers/random\";\r\nimport { InputPrivacyKey, InputPrivacyRule } from \"../layer\";\r\nimport appPrivacyManager, { PrivacyType } from \"../lib/appManagers/appPrivacyManager\";\r\nimport appUsersManager from \"../lib/appManagers/appUsersManager\";\r\nimport { i18n, join, LangPackKey, _i18n } from \"../lib/langPack\";\r\nimport RadioField from \"./radioField\";\r\nimport Row, { RadioFormFromRows } from \"./row\";\r\nimport Scrollable from \"./scrollable\";\r\nimport { SettingSection, generateSection } from \"./sidebarLeft\";\r\nimport AppAddMembersTab from \"./sidebarLeft/tabs/addMembers\";\r\nimport { SliderSuperTabEventable } from \"./sliderTab\";\r\n\r\nexport type PrivacySectionStr = LangPackKey | '' | HTMLElement;\r\nexport default class PrivacySection {\r\n public radioRows: Map<PrivacyType, Row>;\r\n public radioSection: SettingSection;\r\n public exceptions: Map<keyof PrivacySection['peerIds'], {\r\n titleLangKey: LangPackKey,\r\n key: keyof PrivacySection['peerIds'],\r\n row: Row,\r\n icon: string,\r\n subtitleLangKey: LangPackKey,\r\n clickable: true\r\n }>;\r\n public peerIds: {\r\n disallow?: PeerId[],\r\n allow?: PeerId[]\r\n };\r\n public type: PrivacyType;\r\n\r\n constructor(public options: {\r\n tab: SliderSuperTabEventable,\r\n title: LangPackKey, \r\n inputKey: InputPrivacyKey['_'], \r\n captions?: [PrivacySectionStr, PrivacySectionStr, PrivacySectionStr],\r\n appendTo?: Scrollable,\r\n noExceptions?: boolean,\r\n onRadioChange?: (value: number) => any,\r\n skipTypes?: PrivacyType[],\r\n exceptionTexts?: [LangPackKey, LangPackKey]\r\n }) {\r\n if(options.captions) {\r\n options.captions.reverse();\r\n }\r\n\r\n this.radioSection = new SettingSection({name: options.title, caption: true});\r\n\r\n this.radioRows = new Map();\r\n\r\n let r: Array<{type: PrivacyType, langKey: LangPackKey}> = [{\r\n type: PrivacyType.Everybody,\r\n langKey: 'PrivacySettingsController.Everbody'\r\n }, {\r\n type: PrivacyType.Contacts,\r\n langKey: 'PrivacySettingsController.MyContacts'\r\n }, {\r\n type: PrivacyType.Nobody,\r\n langKey: 'PrivacySettingsController.Nobody'\r\n }];\r\n\r\n if(options.skipTypes) {\r\n r = r.filter(r => !options.skipTypes.includes(r.type));\r\n }\r\n \r\n const random = randomLong();\r\n r.forEach(({type, langKey}) => {\r\n const row = new Row({\r\n radioField: new RadioField({\r\n langKey, \r\n name: random, \r\n value: '' + type\r\n })\r\n });\r\n \r\n this.radioRows.set(type, row);\r\n });\r\n\r\n const form = RadioFormFromRows([...this.radioRows.values()], this.onRadioChange);\r\n\r\n this.radioSection.content.append(form);\r\n if(options.appendTo) {\r\n options.appendTo.append(this.radioSection.container);\r\n }\r\n\r\n if(!options.noExceptions) {\r\n const container = generateSection(options.appendTo, 'PrivacyExceptions', 'PrivacySettingsController.PeerInfo');\r\n\r\n this.exceptions = new Map([[\r\n 'disallow', \r\n {\r\n titleLangKey: options.exceptionTexts[0],\r\n key: 'disallow',\r\n row: null,\r\n icon: 'deleteuser',\r\n subtitleLangKey: 'PrivacySettingsController.AddUsers',\r\n clickable: true\r\n }\r\n ], [\r\n 'allow', \r\n {\r\n titleLangKey: options.exceptionTexts[1],\r\n key: 'allow',\r\n row: null,\r\n icon: 'adduser',\r\n subtitleLangKey: 'PrivacySettingsController.AddUsers',\r\n clickable: true\r\n }\r\n ]]);\r\n\r\n this.exceptions.forEach((exception) => {\r\n exception.row = new Row(exception);\r\n\r\n exception.row.container.addEventListener('click', () => {\r\n promise.then(() => {\r\n const _peerIds = this.peerIds[exception.key];\r\n new AppAddMembersTab(options.tab.slider).open({\r\n type: 'privacy',\r\n skippable: true,\r\n title: exception.titleLangKey,\r\n placeholder: 'PrivacyModal.Search.Placeholder',\r\n takeOut: (newPeerIds) => {\r\n _peerIds.length = 0;\r\n _peerIds.push(...newPeerIds);\r\n exception.row.subtitle.innerHTML = '';\r\n exception.row.subtitle.append(...this.generateStr(this.splitPeersByType(newPeerIds)));\r\n },\r\n selectedPeerIds: _peerIds\r\n });\r\n });\r\n });\r\n\r\n container.append(exception.row.container);\r\n });\r\n }\r\n\r\n /* setTimeout(() => {\r\n this.setRadio(PrivacyType.Contacts);\r\n }, 0); */\r\n\r\n const promise = appPrivacyManager.getPrivacy(options.inputKey).then(rules => {\r\n const details = appPrivacyManager.getPrivacyRulesDetails(rules);\r\n this.setRadio(details.type);\r\n\r\n if(this.exceptions) {\r\n this.peerIds = {};\r\n ['allow' as const, 'disallow' as const].forEach(k => {\r\n const arr = [];\r\n const from = k === 'allow' ? details.allowPeers : details.disallowPeers;\r\n arr.push(...from.users.map(id => id.toPeerId()));\r\n arr.push(...from.chats.map(id => id.toPeerId(true)));\r\n this.peerIds[k] = arr;\r\n const s = this.exceptions.get(k).row.subtitle;\r\n s.innerHTML = '';\r\n s.append(...this.generateStr(from));\r\n });\r\n }\r\n\r\n options.tab.eventListener.addEventListener('destroy', () => {\r\n const rules: InputPrivacyRule[] = [];\r\n\r\n switch(this.type) {\r\n case PrivacyType.Everybody:\r\n rules.push({_: 'inputPrivacyValueAllowAll'});\r\n break;\r\n case PrivacyType.Contacts:\r\n rules.push({_: 'inputPrivacyValueAllowContacts'});\r\n break;\r\n case PrivacyType.Nobody:\r\n rules.push({_: 'inputPrivacyValueDisallowAll'});\r\n break;\r\n }\r\n\r\n if(this.exceptions) {\r\n ([\r\n ['allow', 'inputPrivacyValueAllowChatParticipants', 'inputPrivacyValueAllowUsers'],\r\n ['disallow', 'inputPrivacyValueDisallowChatParticipants', 'inputPrivacyValueDisallowUsers']\r\n ] as Array<[\r\n 'allow' | 'disallow', \r\n 'inputPrivacyValueAllowChatParticipants' | 'inputPrivacyValueDisallowChatParticipants', \r\n 'inputPrivacyValueAllowUsers' | 'inputPrivacyValueDisallowUsers'\r\n ]>).forEach(([k, chatKey, usersKey], idx) => {\r\n if(this.exceptions.get(k).row.container.classList.contains('hide')) {\r\n return;\r\n }\r\n\r\n const _peerIds = this.peerIds[k];\r\n if(_peerIds) {\r\n const splitted = this.splitPeersByType(_peerIds);\r\n if(splitted.chats.length) {\r\n rules.push({_: chatKey, chats: splitted.chats});\r\n }\r\n \r\n if(splitted.users.length) {\r\n rules.push({_: usersKey, users: splitted.users.map(id => appUsersManager.getUserInput(id))});\r\n }\r\n }\r\n });\r\n }\r\n \r\n appPrivacyManager.setPrivacy(options.inputKey, rules);\r\n }, {once: true});\r\n });\r\n }\r\n\r\n private onRadioChange = (value: string | PrivacySection['type']) => {\r\n value = +value as PrivacySection['type'];\r\n this.type = value;\r\n\r\n const caption = this.options.captions[this.type];\r\n const captionElement = this.radioSection.caption;\r\n if(!caption) {\r\n captionElement.innerHTML = '';\r\n } else if(caption instanceof HTMLElement) {\r\n replaceContent(captionElement, caption);\r\n } else {\r\n _i18n(captionElement, caption);\r\n }\r\n captionElement.classList.toggle('hide', !caption);\r\n\r\n if(this.exceptions) {\r\n this.exceptions.get('allow').row.container.classList.toggle('hide', this.type === PrivacyType.Everybody);\r\n this.exceptions.get('disallow').row.container.classList.toggle('hide', this.type === PrivacyType.Nobody);\r\n }\r\n\r\n this.options.onRadioChange && this.options.onRadioChange(value);\r\n };\r\n\r\n public setRadio(type: PrivacySection['type']) {\r\n const row = this.radioRows.get(type);\r\n this.onRadioChange(type);\r\n row.radioField.input.checked = true;\r\n }\r\n \r\n private splitPeersByType(peerIds: PeerId[]) {\r\n const peers = {users: [] as UserId[], chats: [] as ChatId[]};\r\n peerIds.forEach(peerId => {\r\n peers[peerId.isAnyChat() ? 'chats' : 'users'].push(peerId.isAnyChat() ? peerId.toChatId() : peerId);\r\n });\r\n\r\n return peers;\r\n }\r\n\r\n private generateStr(peers: {users: UserId[], chats: ChatId[]}) {\r\n if(!peers.users.length && !peers.chats.length) {\r\n return [i18n('PrivacySettingsController.AddUsers')];\r\n }\r\n\r\n return join([\r\n peers.users.length ? i18n('Users', [peers.users.length]) : null, \r\n peers.chats.length ? i18n('Chats', [peers.chats.length]) : null\r\n ].filter(Boolean), false);\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { PrivacyType } from \"../../../../lib/appManagers/appPrivacyManager\";\r\nimport { SliderSuperTabEventable } from \"../../../sliderTab\";\r\nimport PrivacySection, { PrivacySectionStr } from \"../../../privacySection\";\r\nimport { i18n, LangPackKey } from \"../../../../lib/langPack\";\r\nimport anchorCopy from \"../../../../helpers/dom/anchorCopy\";\r\n\r\nexport default class AppPrivacyPhoneNumberTab extends SliderSuperTabEventable {\r\n protected init() {\r\n this.header.classList.add('with-border');\r\n this.container.classList.add('privacy-tab', 'privacy-phone-number');\r\n this.setTitle('PrivacyPhone');\r\n\r\n const captionEl = document.createElement('div');\r\n captionEl.append(\r\n i18n('PrivacyPhoneInfo'), \r\n document.createElement('br'), \r\n document.createElement('br'), \r\n i18n('PrivacyPhoneInfo4'),\r\n document.createElement('br'),\r\n anchorCopy({\r\n mePath: '+380509144504'\r\n })\r\n );\r\n\r\n const phoneSection = new PrivacySection({\r\n tab: this,\r\n title: 'PrivacyPhoneTitle',\r\n inputKey: 'inputPrivacyKeyPhoneNumber',\r\n captions: [captionEl, captionEl, ''],\r\n exceptionTexts: ['PrivacySettingsController.NeverShare', 'PrivacySettingsController.AlwaysShare'],\r\n appendTo: this.scrollable,\r\n onRadioChange: (type) => {\r\n s.setRadio(PrivacyType.Everybody);\r\n s.radioSection.container.classList.toggle('hide', type !== PrivacyType.Nobody);\r\n }\r\n });\r\n\r\n const sCaption: LangPackKey = 'PrivacyPhoneInfo3';\r\n const s = new PrivacySection({\r\n tab: this,\r\n title: 'PrivacyPhoneTitle2',\r\n inputKey: 'inputPrivacyKeyAddedByPhone',\r\n captions: [sCaption, sCaption, ''],\r\n noExceptions: true,\r\n skipTypes: [PrivacyType.Nobody]\r\n });\r\n\r\n this.scrollable.container.insertBefore(s.radioSection.container, phoneSection.radioSection.container.nextSibling);\r\n }\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { toastNew } from \"../../components/toast\";\nimport { copyTextToClipboard } from \"../clipboard\";\nimport cancelEvent from \"./cancelEvent\";\nimport { attachClickEvent } from \"./clickEvent\";\n\nexport default function anchorCopy(options: Partial<{\n // href: string,\n mePath: string\n}> = {}) {\n const anchor = document.createElement('a');\n anchor.classList.add('anchor-copy');\n\n if(options.mePath) {\n const href = 'https://t.me/' + options.mePath;\n anchor.href = anchor.innerText = href;\n }\n\n attachClickEvent(anchor, (e) => {\n cancelEvent(e);\n copyTextToClipboard(anchor.href);\n toastNew({langPackKey: 'LinkCopied'});\n });\n\n return anchor;\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SettingSection } from \"../..\";\r\nimport { attachClickEvent } from \"../../../../helpers/dom/clickEvent\";\r\nimport appStickersManager from \"../../../../lib/appManagers/appStickersManager\";\r\nimport Button from \"../../../button\";\r\nimport { SliderSuperTab } from \"../../../slider\";\r\nimport { wrapSticker } from \"../../../wrappers\";\r\nimport AppSettingsTab from \"../settings\";\r\n\r\nexport default class AppTwoStepVerificationSetTab extends SliderSuperTab {\r\n protected init() {\r\n this.container.classList.add('two-step-verification', 'two-step-verification-set');\r\n this.setTitle('TwoStepVerificationPasswordSet');\r\n\r\n const section = new SettingSection({\r\n caption: 'TwoStepVerificationPasswordSetInfo',\r\n noDelimiter: true\r\n });\r\n\r\n const emoji = '🥳';\r\n const doc = appStickersManager.getAnimatedEmojiSticker(emoji);\r\n const stickerContainer = document.createElement('div');\r\n\r\n if(doc) {\r\n wrapSticker({\r\n doc,\r\n div: stickerContainer,\r\n loop: true,\r\n play: true,\r\n width: 160,\r\n height: 160\r\n }).then(() => {\r\n // this.animation = player;\r\n });\r\n } else {\r\n stickerContainer.classList.add('media-sticker-wrapper');\r\n }\r\n\r\n section.content.append(stickerContainer);\r\n\r\n const inputContent = section.generateContentElement();\r\n\r\n const inputWrapper = document.createElement('div');\r\n inputWrapper.classList.add('input-wrapper');\r\n\r\n const btnReturn = Button('btn-primary btn-color-primary', {text: 'TwoStepVerificationPasswordReturnSettings'});\r\n\r\n attachClickEvent(btnReturn, (e) => {\r\n this.close();\r\n });\r\n\r\n this.slider.sliceTabsUntilTab(AppSettingsTab, this);\r\n\r\n inputWrapper.append(btnReturn);\r\n\r\n inputContent.append(inputWrapper);\r\n\r\n this.scrollable.container.append(section.container);\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { IS_MOBILE_SAFARI } from \"../../environment/userAgent\";\r\n\r\nexport function canFocus(isFirstInput: boolean) {\r\n return !IS_MOBILE_SAFARI || !isFirstInput;\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SettingSection } from \"../..\";\r\nimport { AccountPassword } from \"../../../../layer\";\r\nimport appStickersManager from \"../../../../lib/appManagers/appStickersManager\";\r\nimport Button from \"../../../button\";\r\nimport { SliderSuperTab } from \"../../../slider\";\r\nimport { wrapSticker } from \"../../../wrappers\";\r\nimport passwordManager from \"../../../../lib/mtproto/passwordManager\";\r\nimport AppTwoStepVerificationSetTab from \"./passwordSet\";\r\nimport CodeInputField from \"../../../codeInputField\";\r\nimport AppTwoStepVerificationEmailTab from \"./email\";\r\nimport { putPreloader } from \"../../../misc\";\r\nimport { i18n, _i18n } from \"../../../../lib/langPack\";\r\nimport { canFocus } from \"../../../../helpers/dom/canFocus\";\r\nimport { attachClickEvent } from \"../../../../helpers/dom/clickEvent\";\r\nimport replaceContent from \"../../../../helpers/dom/replaceContent\";\r\nimport toggleDisability from \"../../../../helpers/dom/toggleDisability\";\r\n\r\nexport default class AppTwoStepVerificationEmailConfirmationTab extends SliderSuperTab {\r\n public codeInputField: CodeInputField;\r\n public state: AccountPassword;\r\n public email: string;\r\n public length: number;\r\n public isFirst = false;\r\n\r\n protected init() {\r\n this.container.classList.add('two-step-verification', 'two-step-verification-email-confirmation');\r\n this.setTitle('TwoStepAuth.RecoveryTitle');\r\n\r\n const section = new SettingSection({\r\n caption: true,\r\n noDelimiter: true\r\n });\r\n\r\n _i18n(section.caption, 'TwoStepAuth.ConfirmEmailCodeDesc', [this.email]);\r\n\r\n const emoji = '📬';\r\n const doc = appStickersManager.getAnimatedEmojiSticker(emoji);\r\n const stickerContainer = document.createElement('div');\r\n\r\n if(doc) {\r\n wrapSticker({\r\n doc,\r\n div: stickerContainer,\r\n loop: false,\r\n play: true,\r\n width: 160,\r\n height: 160,\r\n emoji\r\n }).then(() => {\r\n // this.animation = player;\r\n });\r\n } else {\r\n stickerContainer.classList.add('media-sticker-wrapper');\r\n }\r\n\r\n section.content.append(stickerContainer);\r\n\r\n const inputContent = section.generateContentElement();\r\n\r\n const inputWrapper = document.createElement('div');\r\n inputWrapper.classList.add('input-wrapper');\r\n\r\n const inputField = this.codeInputField = new CodeInputField({\r\n name: 'recovery-email-code',\r\n label: 'TwoStepAuth.RecoveryCode',\r\n length: this.length,\r\n onFill: (code) => {\r\n freeze(true);\r\n \r\n passwordManager.confirmPasswordEmail('' + code)\r\n .then(value => {\r\n if(!value) {\r\n\r\n }\r\n\r\n goNext();\r\n })\r\n .catch(err => {\r\n switch(err.type) {\r\n case 'CODE_INVALID':\r\n inputField.input.classList.add('error');\r\n replaceContent(inputField.label, i18n('TwoStepAuth.RecoveryCodeInvalid'));\r\n break;\r\n\r\n case 'EMAIL_HASH_EXPIRED':\r\n inputField.input.classList.add('error');\r\n replaceContent(inputField.label, i18n('TwoStepAuth.RecoveryCodeExpired'));\r\n break;\r\n \r\n default:\r\n console.error('confirm error', err);\r\n break;\r\n }\r\n\r\n freeze(false);\r\n });\r\n }\r\n });\r\n\r\n const btnChange = Button('btn-primary btn-primary-transparent primary', {text: 'TwoStepAuth.EmailCodeChangeEmail'});\r\n const btnResend = Button('btn-primary btn-secondary btn-primary-transparent primary', {text: 'ResendCode'});\r\n\r\n const goNext = () => {\r\n new AppTwoStepVerificationSetTab(this.slider).open();\r\n };\r\n\r\n const freeze = (disable: boolean) => {\r\n toggleDisability([inputField.input, btnChange, btnResend], disable);\r\n };\r\n\r\n attachClickEvent(btnChange, (e) => {\r\n freeze(true);\r\n passwordManager.cancelPasswordEmail().then(value => {\r\n this.slider.sliceTabsUntilTab(AppTwoStepVerificationEmailTab, this);\r\n this.close();\r\n }, () => {\r\n freeze(false);\r\n });\r\n });\r\n\r\n attachClickEvent(btnResend, (e) => {\r\n freeze(true);\r\n const d = putPreloader(btnResend);\r\n passwordManager.resendPasswordEmail().then(value => {\r\n d.remove();\r\n freeze(false);\r\n });\r\n });\r\n\r\n inputWrapper.append(inputField.container, btnChange, btnResend);\r\n\r\n inputContent.append(inputWrapper);\r\n\r\n this.scrollable.container.append(section.container);\r\n }\r\n\r\n onOpenAfterTimeout() {\r\n if(!canFocus(this.isFirst)) return;\r\n this.codeInputField.input.focus();\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SettingSection } from \"../..\";\r\nimport { AccountPassword } from \"../../../../layer\";\r\nimport appStickersManager from \"../../../../lib/appManagers/appStickersManager\";\r\nimport Button from \"../../../button\";\r\nimport { SliderSuperTab } from \"../../../slider\";\r\nimport { wrapSticker } from \"../../../wrappers\";\r\nimport InputField from \"../../../inputField\";\r\nimport { putPreloader } from \"../../../misc\";\r\nimport passwordManager from \"../../../../lib/mtproto/passwordManager\";\r\nimport AppTwoStepVerificationSetTab from \"./passwordSet\";\r\nimport AppTwoStepVerificationEmailConfirmationTab from \"./emailConfirmation\";\r\nimport RichTextProcessor from \"../../../../lib/richtextprocessor\";\r\nimport PopupPeer from \"../../../popups/peer\";\r\nimport cancelEvent from \"../../../../helpers/dom/cancelEvent\";\r\nimport { canFocus } from \"../../../../helpers/dom/canFocus\";\r\nimport { attachClickEvent } from \"../../../../helpers/dom/clickEvent\";\r\n\r\nexport default class AppTwoStepVerificationEmailTab extends SliderSuperTab {\r\n public inputField: InputField;\r\n public state: AccountPassword;\r\n public plainPassword: string;\r\n public newPassword: string;\r\n public hint: string;\r\n public isFirst = false;\r\n\r\n protected init() {\r\n this.container.classList.add('two-step-verification', 'two-step-verification-email');\r\n this.setTitle('RecoveryEmailTitle');\r\n\r\n const section = new SettingSection({\r\n caption: true,\r\n noDelimiter: true\r\n });\r\n\r\n const emoji = '💌';\r\n const doc = appStickersManager.getAnimatedEmojiSticker(emoji);\r\n const stickerContainer = document.createElement('div');\r\n\r\n if(doc) {\r\n wrapSticker({\r\n doc,\r\n div: stickerContainer,\r\n loop: false,\r\n play: true,\r\n width: 160,\r\n height: 160,\r\n emoji\r\n }).then(() => {\r\n // this.animation = player;\r\n });\r\n } else {\r\n stickerContainer.classList.add('media-sticker-wrapper');\r\n }\r\n\r\n section.content.append(stickerContainer);\r\n\r\n const inputContent = section.generateContentElement();\r\n\r\n const inputWrapper = document.createElement('div');\r\n inputWrapper.classList.add('input-wrapper');\r\n\r\n const inputField = this.inputField = new InputField({\r\n name: 'recovery-email',\r\n label: 'RecoveryEmail',\r\n plainText: true\r\n });\r\n\r\n inputField.input.addEventListener('keypress', (e) => {\r\n if(e.key === 'Enter') {\r\n cancelEvent(e);\r\n return onContinueClick();\r\n }\r\n });\r\n\r\n inputField.input.addEventListener('input', (e) => {\r\n inputField.input.classList.remove('error');\r\n });\r\n\r\n const btnContinue = Button('btn-primary btn-color-primary', {text: 'Continue'});\r\n const btnSkip = Button('btn-primary btn-secondary btn-primary-transparent primary', {text: 'YourEmailSkip'});\r\n\r\n const goNext = () => {\r\n new AppTwoStepVerificationSetTab(this.slider).open();\r\n };\r\n\r\n const onContinueClick = () => {\r\n const email = inputField.value.trim();\r\n const match = RichTextProcessor.matchEmail(email);\r\n if(!match || match[0].length !== email.length) {\r\n inputField.input.classList.add('error');\r\n return;\r\n }\r\n\r\n toggleButtons(true);\r\n const d = putPreloader(btnContinue);\r\n\r\n passwordManager.updateSettings({\r\n hint: this.hint,\r\n currentPassword: this.plainPassword,\r\n newPassword: this.newPassword,\r\n email\r\n }).then((value) => {\r\n goNext();\r\n }, (err) => {\r\n if(err.type.includes('EMAIL_UNCONFIRMED')) {\r\n const symbols = +err.type.match(/^EMAIL_UNCONFIRMED_(\\d+)/)[1];\r\n\r\n const tab = new AppTwoStepVerificationEmailConfirmationTab(this.slider);\r\n tab.state = this.state;\r\n tab.email = email;\r\n tab.length = symbols;\r\n tab.open();\r\n } else {\r\n console.log('password set error', err);\r\n }\r\n\r\n toggleButtons(false);\r\n d.remove();\r\n });\r\n };\r\n attachClickEvent(btnContinue, onContinueClick);\r\n\r\n const toggleButtons = (freeze: boolean) => {\r\n if(freeze) {\r\n btnContinue.setAttribute('disabled', 'true');\r\n btnSkip.setAttribute('disabled', 'true');\r\n } else {\r\n btnContinue.removeAttribute('disabled');\r\n btnSkip.removeAttribute('disabled');\r\n }\r\n };\r\n\r\n attachClickEvent(btnSkip, (e) => {\r\n const popup = new PopupPeer('popup-skip-email', {\r\n buttons: [{\r\n langKey: 'Cancel',\r\n isCancel: true\r\n }, {\r\n langKey: 'YourEmailSkip',\r\n callback: () => {\r\n //inputContent.classList.add('sidebar-left-section-disabled');\r\n toggleButtons(true);\r\n putPreloader(btnSkip);\r\n passwordManager.updateSettings({\r\n hint: this.hint, \r\n currentPassword: this.plainPassword,\r\n newPassword: this.newPassword,\r\n email: ''\r\n }).then(() => {\r\n goNext();\r\n }, (err) => {\r\n toggleButtons(false);\r\n });\r\n },\r\n isDanger: true,\r\n }], \r\n titleLangKey: 'YourEmailSkipWarning',\r\n descriptionLangKey: 'YourEmailSkipWarningText'\r\n });\r\n\r\n popup.show();\r\n });\r\n\r\n inputWrapper.append(inputField.container, btnContinue, btnSkip);\r\n\r\n inputContent.append(inputWrapper);\r\n\r\n this.scrollable.container.append(section.container);\r\n }\r\n\r\n onOpenAfterTimeout() {\r\n if(!canFocus(this.isFirst)) return;\r\n this.inputField.input.focus();\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SettingSection } from \"../..\";\r\nimport { AccountPassword } from \"../../../../layer\";\r\nimport appStickersManager from \"../../../../lib/appManagers/appStickersManager\";\r\nimport Button from \"../../../button\";\r\nimport { SliderSuperTab } from \"../../../slider\";\r\nimport { wrapSticker } from \"../../../wrappers\";\r\nimport InputField from \"../../../inputField\";\r\nimport AppTwoStepVerificationEmailTab from \"./email\";\r\nimport { toast } from \"../../../toast\";\r\nimport I18n from \"../../../../lib/langPack\";\r\nimport cancelEvent from \"../../../../helpers/dom/cancelEvent\";\r\nimport { attachClickEvent } from \"../../../../helpers/dom/clickEvent\";\r\n\r\nexport default class AppTwoStepVerificationHintTab extends SliderSuperTab {\r\n public inputField: InputField;\r\n public state: AccountPassword;\r\n public plainPassword: string;\r\n public newPassword: string;\r\n\r\n protected init() {\r\n this.container.classList.add('two-step-verification', 'two-step-verification-hint');\r\n this.setTitle('TwoStepAuth.SetupHintTitle');\r\n\r\n const section = new SettingSection({\r\n noDelimiter: true\r\n });\r\n\r\n const emoji = '💡';\r\n const doc = appStickersManager.getAnimatedEmojiSticker(emoji);\r\n const stickerContainer = document.createElement('div');\r\n\r\n if(doc) {\r\n wrapSticker({\r\n doc,\r\n div: stickerContainer,\r\n loop: false,\r\n play: true,\r\n width: 160,\r\n height: 160,\r\n emoji\r\n }).then(() => {\r\n // this.animation = player;\r\n });\r\n } else {\r\n stickerContainer.classList.add('media-sticker-wrapper');\r\n }\r\n\r\n section.content.append(stickerContainer);\r\n\r\n const inputWrapper = document.createElement('div');\r\n inputWrapper.classList.add('input-wrapper');\r\n\r\n const inputField = this.inputField = new InputField({\r\n name: 'hint',\r\n label: 'TwoStepAuth.SetupHintPlaceholder'\r\n });\r\n\r\n inputField.input.addEventListener('keypress', (e) => {\r\n if(e.key === 'Enter') {\r\n cancelEvent(e);\r\n return inputField.value ? onContinueClick() : onSkipClick();\r\n }\r\n });\r\n\r\n const goNext = (e?: Event, saveHint?: boolean) => {\r\n if(e) {\r\n cancelEvent(e);\r\n }\r\n \r\n const hint = saveHint ? inputField.value : undefined;\r\n if(hint && this.newPassword === hint) {\r\n toast(I18n.format('PasswordAsHintError', true));\r\n return;\r\n }\r\n\r\n const tab = new AppTwoStepVerificationEmailTab(this.slider);\r\n tab.state = this.state;\r\n tab.plainPassword = this.plainPassword;\r\n tab.newPassword = this.newPassword;\r\n tab.hint = hint;\r\n\r\n tab.open();\r\n };\r\n\r\n const btnContinue = Button('btn-primary btn-color-primary', {text: 'Continue'});\r\n const btnSkip = Button('btn-primary btn-secondary btn-primary-transparent primary', {text: 'YourEmailSkip'});\r\n\r\n const onContinueClick = (e?: Event) => goNext(e, true);\r\n const onSkipClick = (e?: Event) => goNext(e, false);\r\n attachClickEvent(btnContinue, onContinueClick);\r\n attachClickEvent(btnSkip, onSkipClick);\r\n\r\n inputWrapper.append(inputField.container, btnContinue, btnSkip);\r\n\r\n section.content.append(inputWrapper);\r\n\r\n this.scrollable.container.append(section.container);\r\n }\r\n\r\n onOpenAfterTimeout() {\r\n this.inputField.input.focus();\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SettingSection } from \"../..\";\r\nimport { AccountPassword } from \"../../../../layer\";\r\nimport Button from \"../../../button\";\r\nimport PasswordInputField from \"../../../passwordInputField\";\r\nimport { SliderSuperTab } from \"../../../slider\";\r\nimport TrackingMonkey from \"../../../monkeys/tracking\";\r\nimport AppTwoStepVerificationHintTab from \"./hint\";\r\nimport { InputState } from \"../../../inputField\";\r\nimport cancelEvent from \"../../../../helpers/dom/cancelEvent\";\r\nimport { attachClickEvent } from \"../../../../helpers/dom/clickEvent\";\r\n\r\nexport default class AppTwoStepVerificationReEnterPasswordTab extends SliderSuperTab {\r\n public state: AccountPassword;\r\n public passwordInputField: PasswordInputField;\r\n public plainPassword: string;\r\n public newPassword: string;\r\n\r\n protected init() {\r\n this.container.classList.add('two-step-verification', 'two-step-verification-enter-password', 'two-step-verification-re-enter-password');\r\n this.setTitle('PleaseReEnterPassword');\r\n\r\n const section = new SettingSection({\r\n noDelimiter: true\r\n });\r\n\r\n const inputWrapper = document.createElement('div');\r\n inputWrapper.classList.add('input-wrapper');\r\n\r\n const passwordInputField = this.passwordInputField = new PasswordInputField({\r\n name: 're-enter-password',\r\n label: 'PleaseReEnterPassword'\r\n });\r\n\r\n const monkey = new TrackingMonkey(passwordInputField, 157);\r\n\r\n const btnContinue = Button('btn-primary btn-color-primary', {text: 'Continue'});\r\n\r\n inputWrapper.append(passwordInputField.container, btnContinue);\r\n section.content.append(monkey.container, inputWrapper);\r\n\r\n this.scrollable.container.append(section.container);\r\n\r\n passwordInputField.input.addEventListener('keypress', (e) => {\r\n if(passwordInputField.input.classList.contains('error')) {\r\n passwordInputField.setState(InputState.Neutral);\r\n }\r\n \r\n if(e.key === 'Enter') {\r\n return onContinueClick();\r\n }\r\n });\r\n\r\n const verifyInput = () => {\r\n if(this.newPassword !== passwordInputField.value) {\r\n passwordInputField.setError();\r\n return false;\r\n }\r\n\r\n return true;\r\n };\r\n\r\n const onContinueClick = (e?: Event) => {\r\n if(e) {\r\n cancelEvent(e);\r\n }\r\n\r\n if(!verifyInput()) return;\r\n\r\n const tab = new AppTwoStepVerificationHintTab(this.slider);\r\n tab.state = this.state;\r\n tab.plainPassword = this.plainPassword;\r\n tab.newPassword = this.newPassword;\r\n tab.open();\r\n };\r\n attachClickEvent(btnContinue, onContinueClick);\r\n\r\n return monkey.load();\r\n }\r\n \r\n onOpenAfterTimeout() {\r\n this.passwordInputField.input.focus();\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport AppTwoStepVerificationTab from \".\";\r\nimport { SettingSection } from \"../..\";\r\nimport cancelEvent from \"../../../../helpers/dom/cancelEvent\";\r\nimport { canFocus } from \"../../../../helpers/dom/canFocus\";\r\nimport { attachClickEvent } from \"../../../../helpers/dom/clickEvent\";\r\nimport replaceContent from \"../../../../helpers/dom/replaceContent\";\r\nimport setInnerHTML from \"../../../../helpers/dom/setInnerHTML\";\r\nimport { AccountPassword } from \"../../../../layer\";\r\nimport I18n, { i18n } from \"../../../../lib/langPack\";\r\nimport passwordManager from \"../../../../lib/mtproto/passwordManager\";\r\nimport RichTextProcessor from \"../../../../lib/richtextprocessor\";\r\nimport Button from \"../../../button\";\r\nimport { putPreloader } from \"../../../misc\";\r\nimport PasswordMonkey from \"../../../monkeys/password\";\r\nimport PasswordInputField from \"../../../passwordInputField\";\r\nimport { SliderSuperTab } from \"../../../slider\";\r\nimport AppTwoStepVerificationReEnterPasswordTab from \"./reEnterPassword\";\r\n\r\nexport default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperTab {\r\n public state: AccountPassword;\r\n public passwordInputField: PasswordInputField;\r\n public plainPassword: string;\r\n public isFirst = true;\r\n \r\n protected init() {\r\n const isNew = !this.state.pFlags.has_password || this.plainPassword;\r\n this.container.classList.add('two-step-verification', 'two-step-verification-enter-password');\r\n this.setTitle(isNew ? 'PleaseEnterFirstPassword' : 'PleaseEnterCurrentPassword');\r\n\r\n const section = new SettingSection({\r\n noDelimiter: true\r\n });\r\n\r\n const inputWrapper = document.createElement('div');\r\n inputWrapper.classList.add('input-wrapper');\r\n\r\n const passwordInputField = this.passwordInputField = new PasswordInputField({\r\n name: 'enter-password',\r\n label: isNew ? 'PleaseEnterFirstPassword' : (this.state.hint ? undefined : 'LoginPassword'),\r\n labelText: !isNew && this.state.hint ? RichTextProcessor.wrapEmojiText(this.state.hint) : undefined\r\n });\r\n\r\n const monkey = new PasswordMonkey(passwordInputField, 157);\r\n\r\n const btnContinue = Button('btn-primary btn-color-primary');\r\n const textEl = new I18n.IntlElement({key: 'Continue'});\r\n\r\n btnContinue.append(textEl.element);\r\n\r\n inputWrapper.append(passwordInputField.container, btnContinue);\r\n section.content.append(monkey.container, inputWrapper);\r\n\r\n this.scrollable.container.append(section.container);\r\n\r\n passwordInputField.input.addEventListener('keypress', (e) => {\r\n if(passwordInputField.input.classList.contains('error')) {\r\n passwordInputField.input.classList.remove('error');\r\n textEl.key = 'Continue';\r\n textEl.update();\r\n }\r\n \r\n if(e.key === 'Enter') {\r\n return onContinueClick();\r\n }\r\n });\r\n\r\n const verifyInput = () => {\r\n if(!passwordInputField.value.length) {\r\n passwordInputField.input.classList.add('error');\r\n return false;\r\n }\r\n\r\n return true;\r\n };\r\n\r\n let onContinueClick: (e?: Event) => void;\r\n if(!isNew) {\r\n let getStateInterval: number;\r\n\r\n let getState = () => {\r\n // * just to check session relevance\r\n if(!getStateInterval) {\r\n getStateInterval = window.setInterval(getState, 10e3);\r\n }\r\n \r\n return passwordManager.getState().then(_state => {\r\n this.state = _state;\r\n \r\n if(this.state.hint) {\r\n setInnerHTML(passwordInputField.label, RichTextProcessor.wrapEmojiText(this.state.hint));\r\n } else {\r\n replaceContent(passwordInputField.label, i18n('LoginPassword'));\r\n }\r\n });\r\n };\r\n \r\n const submit = (e?: Event) => {\r\n if(!verifyInput()) {\r\n cancelEvent(e);\r\n return;\r\n }\r\n\r\n btnContinue.setAttribute('disabled', 'true');\r\n textEl.key = 'PleaseWait';\r\n textEl.update();\r\n const preloader = putPreloader(btnContinue);\r\n \r\n const plainPassword = passwordInputField.value;\r\n passwordManager.check(passwordInputField.value, this.state).then(auth => {\r\n console.log(auth);\r\n \r\n if(auth._ === 'auth.authorization') {\r\n clearInterval(getStateInterval);\r\n if(monkey) monkey.remove();\r\n const tab = new AppTwoStepVerificationTab(this.slider);\r\n tab.state = this.state;\r\n tab.plainPassword = plainPassword;\r\n tab.open();\r\n this.slider.removeTabFromHistory(this);\r\n }\r\n }, (err) => {\r\n btnContinue.removeAttribute('disabled');\r\n passwordInputField.input.classList.add('error');\r\n \r\n switch(err.type) {\r\n default:\r\n //btnContinue.innerText = err.type;\r\n textEl.key = 'TwoStepAuth.InvalidPassword';\r\n textEl.update();\r\n preloader.remove();\r\n passwordInputField.select();\r\n break;\r\n }\r\n \r\n getState();\r\n });\r\n };\r\n \r\n onContinueClick = submit;\r\n\r\n getState();\r\n } else {\r\n onContinueClick = (e) => {\r\n if(e) {\r\n cancelEvent(e);\r\n }\r\n\r\n if(!verifyInput()) return;\r\n\r\n const tab = new AppTwoStepVerificationReEnterPasswordTab(this.slider);\r\n tab.state = this.state;\r\n tab.newPassword = passwordInputField.value;\r\n tab.plainPassword = this.plainPassword;\r\n tab.open();\r\n };\r\n }\r\n\r\n attachClickEvent(btnContinue, onContinueClick);\r\n\r\n return monkey.load();\r\n }\r\n\r\n onOpenAfterTimeout() {\r\n if(!canFocus(this.isFirst)) return;\r\n this.passwordInputField.input.focus();\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SettingSection } from \"../..\";\r\nimport { attachClickEvent } from \"../../../../helpers/dom/clickEvent\";\r\nimport { AccountPassword } from \"../../../../layer\";\r\nimport appStickersManager from \"../../../../lib/appManagers/appStickersManager\";\r\nimport { _i18n } from \"../../../../lib/langPack\";\r\nimport passwordManager from \"../../../../lib/mtproto/passwordManager\";\r\nimport Button from \"../../../button\";\r\nimport PopupPeer from \"../../../popups/peer\";\r\nimport { SliderSuperTab } from \"../../../slider\";\r\nimport { wrapSticker } from \"../../../wrappers\";\r\nimport AppSettingsTab from \"../settings\";\r\nimport AppTwoStepVerificationEmailTab from \"./email\";\r\nimport AppTwoStepVerificationEnterPasswordTab from \"./enterPassword\";\r\n\r\nexport default class AppTwoStepVerificationTab extends SliderSuperTab {\r\n public state: AccountPassword;\r\n public plainPassword: string;\r\n\r\n protected init() {\r\n this.container.classList.add('two-step-verification', 'two-step-verification-main');\r\n this.setTitle('TwoStepVerificationTitle');\r\n\r\n const section = new SettingSection({\r\n caption: true,\r\n noDelimiter: true\r\n });\r\n\r\n const emoji = '🔐';\r\n const doc = appStickersManager.getAnimatedEmojiSticker(emoji);\r\n const stickerContainer = document.createElement('div');\r\n\r\n if(doc) {\r\n wrapSticker({\r\n doc,\r\n div: stickerContainer,\r\n loop: false,\r\n play: true,\r\n width: 168,\r\n height: 168,\r\n emoji\r\n }).then(() => {\r\n // this.animation = player;\r\n });\r\n } else {\r\n stickerContainer.classList.add('media-sticker-wrapper');\r\n }\r\n\r\n section.content.append(stickerContainer);\r\n\r\n const c = section.generateContentElement();\r\n if(this.state.pFlags.has_password) {\r\n _i18n(section.caption, 'TwoStepAuth.GenericHelp');\r\n\r\n const btnChangePassword = Button('btn-primary btn-transparent', {icon: 'edit', text: 'TwoStepAuth.ChangePassword'});\r\n const btnDisablePassword = Button('btn-primary btn-transparent', {icon: 'passwordoff', text: 'TwoStepAuth.RemovePassword'});\r\n const btnSetRecoveryEmail = Button('btn-primary btn-transparent', {icon: 'email', text: this.state.pFlags.has_recovery ? 'TwoStepAuth.ChangeEmail' : 'TwoStepAuth.SetupEmail'});\r\n\r\n attachClickEvent(btnChangePassword, () => {\r\n const tab = new AppTwoStepVerificationEnterPasswordTab(this.slider);\r\n tab.state = this.state;\r\n tab.plainPassword = this.plainPassword;\r\n tab.open();\r\n });\r\n\r\n attachClickEvent(btnDisablePassword, () => {\r\n const popup = new PopupPeer('popup-disable-password', {\r\n buttons: [{\r\n langKey: 'Disable',\r\n callback: () => {\r\n passwordManager.updateSettings({currentPassword: this.plainPassword}).then(() => {\r\n this.slider.sliceTabsUntilTab(AppSettingsTab, this);\r\n this.close();\r\n });\r\n },\r\n isDanger: true,\r\n }], \r\n titleLangKey: 'TurnPasswordOffQuestionTitle',\r\n descriptionLangKey: 'TurnPasswordOffQuestion'\r\n });\r\n\r\n popup.show();\r\n });\r\n\r\n attachClickEvent(btnSetRecoveryEmail, () => {\r\n const tab = new AppTwoStepVerificationEmailTab(this.slider);\r\n tab.state = this.state;\r\n tab.hint = this.state.hint;\r\n tab.plainPassword = this.plainPassword;\r\n tab.newPassword = this.plainPassword;\r\n tab.isFirst = true;\r\n tab.open();\r\n });\r\n\r\n c.append(btnChangePassword, btnDisablePassword, btnSetRecoveryEmail);\r\n } else {\r\n _i18n(section.caption, 'TwoStepAuth.SetPasswordHelp');\r\n\r\n const inputWrapper = document.createElement('div');\r\n inputWrapper.classList.add('input-wrapper');\r\n\r\n const btnSetPassword = Button('btn-primary btn-color-primary', {text: 'TwoStepVerificationSetPassword'});\r\n \r\n inputWrapper.append(btnSetPassword);\r\n c.append(inputWrapper);\r\n\r\n attachClickEvent(btnSetPassword, (e) => {\r\n const tab = new AppTwoStepVerificationEnterPasswordTab(this.slider);\r\n tab.state = this.state;\r\n tab.open();\r\n });\r\n }\r\n\r\n this.scrollable.container.append(section.container);\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTabEventable } from \"../../../sliderTab\";\r\nimport PrivacySection from \"../../../privacySection\";\r\nimport { LangPackKey } from \"../../../../lib/langPack\";\r\n\r\nexport default class AppPrivacyLastSeenTab extends SliderSuperTabEventable {\r\n protected init() {\r\n this.header.classList.add('with-border');\r\n this.container.classList.add('privacy-tab', 'privacy-last-seen');\r\n this.setTitle('PrivacyLastSeen');\r\n\r\n const caption: LangPackKey = 'PrivacySettingsController.LastSeenDescription';\r\n new PrivacySection({\r\n tab: this,\r\n title: 'LastSeenTitle',\r\n inputKey: 'inputPrivacyKeyStatusTimestamp',\r\n captions: [caption, caption, caption],\r\n exceptionTexts: ['PrivacySettingsController.NeverShare', 'PrivacySettingsController.AlwaysShare'],\r\n appendTo: this.scrollable\r\n });\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTabEventable } from \"../../../sliderTab\";\r\nimport PrivacySection from \"../../../privacySection\";\r\nimport { PrivacyType } from \"../../../../lib/appManagers/appPrivacyManager\";\r\nimport { LangPackKey } from \"../../../../lib/langPack\";\r\n\r\nexport default class AppPrivacyProfilePhotoTab extends SliderSuperTabEventable {\r\n protected init() {\r\n this.header.classList.add('with-border');\r\n this.container.classList.add('privacy-tab', 'privacy-profile-photo');\r\n this.setTitle('PrivacyProfilePhoto');\r\n\r\n const caption: LangPackKey = 'PrivacySettingsController.ProfilePhoto.CustomHelp';\r\n new PrivacySection({\r\n tab: this,\r\n title: 'PrivacyProfilePhotoTitle',\r\n inputKey: 'inputPrivacyKeyProfilePhoto',\r\n captions: [caption, caption, caption],\r\n exceptionTexts: ['PrivacySettingsController.NeverShare', 'PrivacySettingsController.AlwaysShare'],\r\n appendTo: this.scrollable,\r\n skipTypes: [PrivacyType.Nobody]\r\n });\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTabEventable } from \"../../../sliderTab\";\r\nimport PrivacySection from \"../../../privacySection\";\r\nimport { LangPackKey } from \"../../../../lib/langPack\";\r\n\r\nexport default class AppPrivacyForwardMessagesTab extends SliderSuperTabEventable {\r\n protected init() {\r\n this.header.classList.add('with-border');\r\n this.container.classList.add('privacy-tab', 'privacy-forward-messages');\r\n this.setTitle('PrivacySettings.Forwards');\r\n\r\n const caption: LangPackKey = 'PrivacySettingsController.Forwards.CustomHelp';\r\n new PrivacySection({\r\n tab: this,\r\n title: 'PrivacyForwardsTitle',\r\n inputKey: 'inputPrivacyKeyForwards',\r\n captions: [caption, caption, caption],\r\n exceptionTexts: ['PrivacySettingsController.NeverAllow', 'PrivacySettingsController.AlwaysAllow'],\r\n appendTo: this.scrollable\r\n });\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTabEventable } from \"../../../sliderTab\";\r\nimport PrivacySection from \"../../../privacySection\";\r\nimport { LangPackKey } from \"../../../../lib/langPack\";\r\nimport { PrivacyType } from \"../../../../lib/appManagers/appPrivacyManager\";\r\n\r\nexport default class AppPrivacyAddToGroupsTab extends SliderSuperTabEventable {\r\n protected init() {\r\n this.header.classList.add('with-border');\r\n this.container.classList.add('privacy-tab', 'privacy-add-to-groups');\r\n this.setTitle('PrivacySettings.Groups');\r\n\r\n const caption: LangPackKey = 'PrivacySettingsController.GroupDescription';\r\n new PrivacySection({\r\n tab: this,\r\n title: 'WhoCanAddMe',\r\n inputKey: 'inputPrivacyKeyChatInvite',\r\n captions: [caption, caption, caption],\r\n exceptionTexts: ['PrivacySettingsController.NeverAllow', 'PrivacySettingsController.AlwaysAllow'],\r\n appendTo: this.scrollable,\r\n skipTypes: [PrivacyType.Nobody]\r\n });\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTabEventable } from \"../../../sliderTab\";\r\nimport PrivacySection from \"../../../privacySection\";\r\nimport { LangPackKey } from \"../../../../lib/langPack\";\r\n\r\nexport default class AppPrivacyCallsTab extends SliderSuperTabEventable {\r\n protected init() {\r\n this.header.classList.add('with-border');\r\n this.container.classList.add('privacy-tab', 'privacy-calls');\r\n this.setTitle('PrivacySettings.VoiceCalls');\r\n\r\n const caption: LangPackKey = 'PrivacySettingsController.PhoneCallDescription';\r\n new PrivacySection({\r\n tab: this,\r\n title: 'WhoCanCallMe',\r\n inputKey: 'inputPrivacyKeyPhoneCall',\r\n captions: [caption, caption, caption],\r\n exceptionTexts: ['PrivacySettingsController.NeverAllow', 'PrivacySettingsController.AlwaysAllow'],\r\n appendTo: this.scrollable\r\n });\r\n\r\n {\r\n const caption: LangPackKey = 'PrivacySettingsController.P2p.Desc';\r\n new PrivacySection({\r\n tab: this,\r\n title: 'PrivacyP2PHeader',\r\n inputKey: 'inputPrivacyKeyPhoneP2P',\r\n captions: [caption, caption, caption],\r\n exceptionTexts: ['PrivacySettingsController.NeverAllow', 'PrivacySettingsController.AlwaysAllow'],\r\n appendTo: this.scrollable\r\n });\r\n }\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTab } from \"../../slider\";\r\nimport { SettingSection } from \"..\";\r\nimport Button from \"../../button\";\r\nimport Row from \"../../row\";\r\nimport { Authorization } from \"../../../layer\";\r\nimport { formatDateAccordingToTodayNew } from \"../../../helpers/date\";\r\nimport { attachContextMenuListener, openBtnMenu, positionMenu } from \"../../misc\";\r\nimport ButtonMenu from \"../../buttonMenu\";\r\nimport apiManager from \"../../../lib/mtproto/mtprotoworker\";\r\nimport { toast } from \"../../toast\";\r\nimport AppPrivacyAndSecurityTab from \"./privacyAndSecurity\";\r\nimport I18n from \"../../../lib/langPack\";\r\nimport PopupPeer from \"../../popups/peer\";\r\nimport findUpClassName from \"../../../helpers/dom/findUpClassName\";\r\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\r\nimport toggleDisability from \"../../../helpers/dom/toggleDisability\";\r\nimport { SliderSuperTabEventable } from \"../../sliderTab\";\r\nimport findAndSplice from \"../../../helpers/array/findAndSplice\";\r\n\r\nexport default class AppActiveSessionsTab extends SliderSuperTabEventable {\r\n public authorizations: Authorization.authorization[];\r\n private menuElement: HTMLElement;\r\n \r\n protected init() {\r\n this.header.classList.add('with-border');\r\n this.container.classList.add('active-sessions-container');\r\n this.setTitle('SessionsTitle');\r\n\r\n const Session = (auth: Authorization.authorization) => {\r\n const row = new Row({\r\n title: [auth.app_name, auth.app_version].join(' '),\r\n subtitle: [auth.ip, auth.country].join(' - '),\r\n clickable: true,\r\n titleRight: auth.pFlags.current ? undefined : formatDateAccordingToTodayNew(new Date(Math.max(auth.date_active, auth.date_created) * 1000))\r\n });\r\n\r\n row.container.dataset.hash = '' + auth.hash;\r\n\r\n const midtitle = document.createElement('div');\r\n midtitle.classList.add('row-midtitle');\r\n midtitle.innerHTML = [auth.device_model, auth.system_version || auth.platform].filter(Boolean).join(', ');\r\n\r\n row.subtitle.parentElement.insertBefore(midtitle, row.subtitle);\r\n\r\n return row;\r\n };\r\n\r\n const authorizations = this.authorizations.slice();\r\n\r\n {\r\n const section = new SettingSection({\r\n name: 'CurrentSession',\r\n caption: 'ClearOtherSessionsHelp'\r\n });\r\n\r\n const auth = findAndSplice(authorizations, auth => auth.pFlags.current);\r\n const session = Session(auth);\r\n\r\n section.content.append(session.container);\r\n\r\n if(authorizations.length) {\r\n const btnTerminate = Button('btn-primary btn-transparent danger', {icon: 'stop', text: 'TerminateAllSessions'});\r\n attachClickEvent(btnTerminate, (e) => {\r\n new PopupPeer('revoke-session', {\r\n buttons: [{\r\n langKey: 'Terminate',\r\n isDanger: true,\r\n callback: () => {\r\n const toggle = toggleDisability([btnTerminate], true);\r\n apiManager.invokeApi('auth.resetAuthorizations').then(value => {\r\n //toggleDisability([btnTerminate], false);\r\n btnTerminate.remove();\r\n otherSection.container.remove();\r\n }, onError).finally(() => {\r\n toggle();\r\n });\r\n }\r\n }],\r\n titleLangKey: 'AreYouSureSessionsTitle',\r\n descriptionLangKey: 'AreYouSureSessions'\r\n }).show();\r\n });\r\n \r\n section.content.append(btnTerminate);\r\n }\r\n\r\n this.scrollable.append(section.container);\r\n }\r\n\r\n if(!authorizations.length) {\r\n return;\r\n }\r\n\r\n const otherSection = new SettingSection({\r\n name: 'OtherSessions',\r\n caption: 'SessionsListInfo'\r\n });\r\n\r\n authorizations.forEach(auth => {\r\n otherSection.content.append(Session(auth).container);\r\n });\r\n\r\n this.scrollable.append(otherSection.container);\r\n\r\n const onError = (err: any) => {\r\n if(err.type === 'FRESH_RESET_AUTHORISATION_FORBIDDEN') {\r\n toast(I18n.format('RecentSessions.Error.FreshReset', true));\r\n }\r\n };\r\n\r\n let target: HTMLElement;\r\n const onTerminateClick = () => {\r\n const hash = target.dataset.hash;\r\n \r\n new PopupPeer('revoke-session', {\r\n buttons: [{\r\n langKey: 'Terminate',\r\n isDanger: true,\r\n callback: () => {\r\n apiManager.invokeApi('account.resetAuthorization', {hash})\r\n .then(value => {\r\n if(value) {\r\n target.remove();\r\n }\r\n }, onError);\r\n }\r\n }],\r\n titleLangKey: 'AreYouSureSessionTitle',\r\n descriptionLangKey: 'TerminateSessionText'\r\n }).show();\r\n };\r\n\r\n const element = this.menuElement = ButtonMenu([{\r\n icon: 'stop',\r\n text: 'Terminate',\r\n onClick: onTerminateClick\r\n }]);\r\n element.id = 'active-sessions-contextmenu';\r\n element.classList.add('contextmenu');\r\n\r\n document.getElementById('page-chats').append(element);\r\n\r\n attachContextMenuListener(this.scrollable.container, (e) => {\r\n target = findUpClassName(e.target, 'row');\r\n if(!target || target.dataset.hash === '0') {\r\n return;\r\n }\r\n\r\n if(e instanceof MouseEvent) e.preventDefault();\r\n // smth\r\n if(e instanceof MouseEvent) e.cancelBubble = true;\r\n\r\n positionMenu(e, element);\r\n openBtnMenu(element);\r\n });\r\n\r\n attachClickEvent(this.scrollable.container, (e) => {\r\n target = findUpClassName(e.target, 'row');\r\n if(!target || target.dataset.hash === '0') {\r\n return;\r\n }\r\n\r\n onTerminateClick();\r\n });\r\n }\r\n\r\n onCloseAfterTimeout() {\r\n if(this.menuElement) {\r\n this.menuElement.remove();\r\n }\r\n\r\n return super.onCloseAfterTimeout();\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTab } from \"../../slider\";\r\nimport { SettingSection } from \"..\";\r\nimport { attachContextMenuListener, openBtnMenu, positionMenu } from \"../../misc\";\r\nimport ButtonMenu from \"../../buttonMenu\";\r\nimport appDialogsManager from \"../../../lib/appManagers/appDialogsManager\";\r\nimport appUsersManager from \"../../../lib/appManagers/appUsersManager\";\r\nimport PopupPickUser from \"../../popups/pickUser\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport findUpTag from \"../../../helpers/dom/findUpTag\";\r\nimport ButtonCorner from \"../../buttonCorner\";\r\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\r\n\r\nexport default class AppBlockedUsersTab extends SliderSuperTab {\r\n public peerIds: PeerId[];\r\n private menuElement: HTMLElement;\r\n \r\n protected init() {\r\n this.header.classList.add('with-border');\r\n this.container.classList.add('blocked-users-container');\r\n this.setTitle('BlockedUsers');\r\n\r\n const section = new SettingSection({\r\n caption: 'BlockedUsersInfo'\r\n });\r\n\r\n section.caption.parentElement.prepend(section.caption);\r\n\r\n this.scrollable.append(section.container);\r\n\r\n const btnAdd = ButtonCorner({icon: 'add', className: 'is-visible'});\r\n this.content.append(btnAdd);\r\n\r\n attachClickEvent(btnAdd, (e) => {\r\n new PopupPickUser({\r\n peerTypes: ['contacts'],\r\n placeholder: 'BlockModal.Search.Placeholder',\r\n onSelect: (peerId) => {\r\n //console.log('block', peerId);\r\n appUsersManager.toggleBlock(peerId, true);\r\n },\r\n });\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n const list = appDialogsManager.createChatList();\r\n this.scrollable.container.classList.add('chatlist-container');\r\n section.content.append(list);\r\n\r\n const add = (peerId: PeerId, append: boolean) => {\r\n const {dom} = appDialogsManager.addDialogNew({\r\n dialog: peerId,\r\n container: list,\r\n drawStatus: false,\r\n rippleEnabled: true,\r\n avatarSize: 48,\r\n append\r\n });\r\n\r\n const user = appUsersManager.getUser(peerId);\r\n if(user.pFlags.bot) {\r\n dom.lastMessageSpan.append('@' + user.username);\r\n } else {\r\n if(user.phone) dom.lastMessageSpan.innerHTML = appUsersManager.formatUserPhone(user.phone);\r\n else dom.lastMessageSpan.append(user.username ? '@' + user.username : appUsersManager.getUserStatusString(peerId));\r\n }\r\n\r\n //dom.titleSpan.innerHTML = 'Raaid El Syed';\r\n //dom.lastMessageSpan.innerHTML = '+1 234 567891';\r\n };\r\n\r\n for(const peerId of this.peerIds) {\r\n add(peerId, true);\r\n }\r\n\r\n let target: HTMLElement;\r\n const onUnblock = () => {\r\n const peerId = target.dataset.peerId.toPeerId();\r\n appUsersManager.toggleBlock(peerId, false);\r\n };\r\n\r\n const element = this.menuElement = ButtonMenu([{\r\n icon: 'lockoff',\r\n text: 'Unblock',\r\n onClick: onUnblock,\r\n options: {listenerSetter: this.listenerSetter}\r\n }]);\r\n element.id = 'blocked-users-contextmenu';\r\n element.classList.add('contextmenu');\r\n\r\n document.getElementById('page-chats').append(element);\r\n\r\n attachContextMenuListener(this.scrollable.container, (e) => {\r\n target = findUpTag(e.target, 'LI');\r\n if(!target) {\r\n return;\r\n }\r\n\r\n if(e instanceof MouseEvent) e.preventDefault();\r\n // smth\r\n if(e instanceof MouseEvent) e.cancelBubble = true;\r\n\r\n positionMenu(e, element);\r\n openBtnMenu(element);\r\n }, this.listenerSetter);\r\n\r\n this.listenerSetter.add(rootScope)('peer_block', (update) => {\r\n const {peerId, blocked} = update;\r\n const li = list.querySelector(`[data-peer-id=\"${peerId}\"]`);\r\n if(blocked) {\r\n if(!li) {\r\n add(peerId, false);\r\n }\r\n } else {\r\n if(li) {\r\n li.remove();\r\n }\r\n }\r\n });\r\n\r\n const LOAD_COUNT = 50;\r\n let loading = false;\r\n this.scrollable.onScrolledBottom = () => {\r\n if(loading) {\r\n return;\r\n }\r\n\r\n loading = true;\r\n appUsersManager.getBlocked(list.childElementCount, LOAD_COUNT).then(res => {\r\n for(const peerId of res.peerIds) {\r\n add(peerId, true);\r\n }\r\n\r\n if(res.peerIds.length < LOAD_COUNT || list.childElementCount === res.count) {\r\n this.scrollable.onScrolledBottom = null;\r\n }\r\n\r\n this.scrollable.checkForTriggers();\r\n }).finally(() => {\r\n loading = false;\r\n });\r\n };\r\n }\r\n\r\n onOpenAfterTimeout() {\r\n this.scrollable.onScroll();\r\n }\r\n\r\n onCloseAfterTimeout() {\r\n if(this.menuElement) {\r\n this.menuElement.remove();\r\n }\r\n\r\n return super.onCloseAfterTimeout();\r\n }\r\n}\r\n","export default function convertKeyToInputKey(key: string) {\n key = key[0].toUpperCase() + key.slice(1);\n key = 'input' + key;\n return key;\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTabEventable } from \"../../sliderTab\";\r\nimport { SettingSection } from \"..\";\r\nimport Row from \"../../row\";\r\nimport { AccountPassword, Authorization, InputPrivacyKey, Updates } from \"../../../layer\";\r\nimport appPrivacyManager, { PrivacyType } from \"../../../lib/appManagers/appPrivacyManager\";\r\nimport AppPrivacyPhoneNumberTab from \"./privacy/phoneNumber\";\r\nimport AppTwoStepVerificationTab from \"./2fa\";\r\nimport passwordManager from \"../../../lib/mtproto/passwordManager\";\r\nimport AppTwoStepVerificationEnterPasswordTab from \"./2fa/enterPassword\";\r\nimport AppTwoStepVerificationEmailConfirmationTab from \"./2fa/emailConfirmation\";\r\nimport AppPrivacyLastSeenTab from \"./privacy/lastSeen\";\r\nimport AppPrivacyProfilePhotoTab from \"./privacy/profilePhoto\";\r\nimport AppPrivacyForwardMessagesTab from \"./privacy/forwardMessages\";\r\nimport AppPrivacyAddToGroupsTab from \"./privacy/addToGroups\";\r\nimport AppPrivacyCallsTab from \"./privacy/calls\";\r\nimport AppActiveSessionsTab from \"./activeSessions\";\r\nimport apiManager from \"../../../lib/mtproto/mtprotoworker\";\r\nimport AppBlockedUsersTab from \"./blockedUsers\";\r\nimport appUsersManager from \"../../../lib/appManagers/appUsersManager\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport { i18n, LangPackKey, _i18n } from \"../../../lib/langPack\";\r\nimport replaceContent from \"../../../helpers/dom/replaceContent\";\r\nimport CheckboxField from \"../../checkboxField\";\r\nimport PopupPeer from \"../../popups/peer\";\r\nimport appDraftsManager from \"../../../lib/appManagers/appDraftsManager\";\r\nimport Button from \"../../button\";\r\nimport toggleDisability from \"../../../helpers/dom/toggleDisability\";\r\nimport convertKeyToInputKey from \"../../../helpers/string/convertKeyToInputKey\";\r\n\r\nexport default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {\r\n private activeSessionsRow: Row;\r\n private authorizations: Authorization.authorization[];\r\n\r\n protected init() {\r\n this.header.classList.add('with-border');\r\n this.container.classList.add('dont-u-dare-block-me');\r\n this.setTitle('PrivacySettings');\r\n\r\n const SUBTITLE: LangPackKey = 'Loading';\r\n\r\n {\r\n const section = new SettingSection({noDelimiter: true, caption: 'SessionsInfo'});\r\n\r\n let blockedPeerIds: PeerId[];\r\n const blockedUsersRow = new Row({\r\n icon: 'deleteuser',\r\n titleLangKey: 'BlockedUsers',\r\n subtitleLangKey: SUBTITLE,\r\n clickable: () => {\r\n const tab = new AppBlockedUsersTab(this.slider);\r\n tab.peerIds = blockedPeerIds;\r\n tab.open();\r\n }\r\n });\r\n blockedUsersRow.freezed = true;\r\n\r\n let passwordState: AccountPassword;\r\n const twoFactorRowOptions = {\r\n icon: 'lock',\r\n titleLangKey: 'TwoStepVerification' as LangPackKey,\r\n subtitleLangKey: SUBTITLE,\r\n clickable: (e: Event) => {\r\n let tab: AppTwoStepVerificationTab | AppTwoStepVerificationEnterPasswordTab | AppTwoStepVerificationEmailConfirmationTab;\r\n if(passwordState.pFlags.has_password) {\r\n tab = new AppTwoStepVerificationEnterPasswordTab(this.slider);\r\n } else if(passwordState.email_unconfirmed_pattern) {\r\n tab = new AppTwoStepVerificationEmailConfirmationTab(this.slider);\r\n tab.email = passwordState.email_unconfirmed_pattern;\r\n tab.length = 6;\r\n tab.isFirst = true;\r\n passwordManager.resendPasswordEmail();\r\n } else {\r\n tab = new AppTwoStepVerificationTab(this.slider);\r\n }\r\n \r\n tab.state = passwordState;\r\n tab.open();\r\n }\r\n };\r\n \r\n const twoFactorRow = new Row(twoFactorRowOptions);\r\n twoFactorRow.freezed = true;\r\n\r\n const activeSessionsRow = this.activeSessionsRow = new Row({\r\n icon: 'activesessions',\r\n titleLangKey: 'SessionsTitle',\r\n subtitleLangKey: SUBTITLE,\r\n clickable: () => {\r\n const tab = new AppActiveSessionsTab(this.slider);\r\n tab.authorizations = this.authorizations;\r\n tab.eventListener.addEventListener('destroy', () => {\r\n this.updateActiveSessions();\r\n }, {once: true});\r\n tab.open();\r\n }\r\n });\r\n activeSessionsRow.freezed = true;\r\n\r\n section.content.append(blockedUsersRow.container, twoFactorRow.container, activeSessionsRow.container);\r\n this.scrollable.append(section.container);\r\n\r\n const setBlockedCount = (count: number) => {\r\n if(count) {\r\n replaceContent(blockedUsersRow.subtitle, i18n('PrivacySettingsController.UserCount', [count]));\r\n } else {\r\n replaceContent(blockedUsersRow.subtitle, i18n('BlockedEmpty', [count]));\r\n }\r\n };\r\n\r\n this.listenerSetter.add(rootScope)('peer_block', () => {\r\n /* const {blocked, peerId} = update;\r\n if(!blocked) blockedPeerIds.findAndSplice(p => p === peerId);\r\n else blockedPeerIds.unshift(peerId);\r\n blockedCount += blocked ? 1 : -1;\r\n setBlockedCount(blockedCount); */\r\n updateBlocked();\r\n });\r\n\r\n const updateBlocked = () => {\r\n appUsersManager.getBlocked().then(res => {\r\n blockedUsersRow.freezed = false;\r\n setBlockedCount(res.count);\r\n blockedPeerIds = res.peerIds;\r\n });\r\n };\r\n\r\n updateBlocked();\r\n\r\n passwordManager.getState().then(state => {\r\n passwordState = state;\r\n replaceContent(twoFactorRow.subtitle, i18n(state.pFlags.has_password ? 'PrivacyAndSecurity.Item.On' : 'PrivacyAndSecurity.Item.Off'));\r\n twoFactorRow.freezed = false;\r\n \r\n //console.log('password state', state);\r\n });\r\n\r\n this.updateActiveSessions();\r\n }\r\n\r\n {\r\n const section = new SettingSection({name: 'PrivacyTitle', caption: 'GroupsAndChannelsHelp'});\r\n\r\n section.content.classList.add('privacy-navigation-container');\r\n\r\n const rowsByKeys: Partial<{\r\n [key in InputPrivacyKey['_']]: Row\r\n }> = {};\r\n\r\n const numberVisibilityRow = rowsByKeys['inputPrivacyKeyPhoneNumber'] = new Row({\r\n titleLangKey: 'PrivacyPhoneTitle',\r\n subtitleLangKey: SUBTITLE,\r\n clickable: () => {\r\n new AppPrivacyPhoneNumberTab(this.slider).open();\r\n }\r\n });\r\n\r\n const lastSeenTimeRow = rowsByKeys['inputPrivacyKeyStatusTimestamp'] = new Row({\r\n titleLangKey: 'LastSeenTitle',\r\n subtitleLangKey: SUBTITLE,\r\n clickable: () => {\r\n new AppPrivacyLastSeenTab(this.slider).open();\r\n }\r\n });\r\n\r\n const photoVisibilityRow = rowsByKeys['inputPrivacyKeyProfilePhoto'] = new Row({\r\n titleLangKey: 'PrivacyProfilePhotoTitle',\r\n subtitleLangKey: SUBTITLE,\r\n clickable: () => {\r\n new AppPrivacyProfilePhotoTab(this.slider).open();\r\n }\r\n });\r\n\r\n const callRow = rowsByKeys['inputPrivacyKeyPhoneCall'] = new Row({\r\n titleLangKey: 'WhoCanCallMe',\r\n subtitleLangKey: SUBTITLE,\r\n clickable: () => {\r\n new AppPrivacyCallsTab(this.slider).open();\r\n }\r\n });\r\n\r\n const linkAccountRow = rowsByKeys['inputPrivacyKeyForwards'] = new Row({\r\n titleLangKey: 'PrivacyForwardsTitle',\r\n subtitleLangKey: SUBTITLE,\r\n clickable: () => {\r\n new AppPrivacyForwardMessagesTab(this.slider).open();\r\n }\r\n });\r\n\r\n const groupChatsAddRow = rowsByKeys['inputPrivacyKeyChatInvite'] = new Row({\r\n titleLangKey: 'WhoCanAddMe',\r\n subtitleLangKey: SUBTITLE,\r\n clickable: () => {\r\n new AppPrivacyAddToGroupsTab(this.slider).open();\r\n }\r\n });\r\n\r\n const updatePrivacyRow = (key: InputPrivacyKey['_']) => {\r\n const row = rowsByKeys[key];\r\n if(!row) {\r\n return;\r\n }\r\n\r\n appPrivacyManager.getPrivacy(key).then(rules => {\r\n const details = appPrivacyManager.getPrivacyRulesDetails(rules);\r\n const langKey = details.type === PrivacyType.Everybody ? 'PrivacySettingsController.Everbody' : (details.type === PrivacyType.Contacts ? 'PrivacySettingsController.MyContacts' : 'PrivacySettingsController.Nobody');\r\n const disallowLength = details.disallowPeers.users.length + details.disallowPeers.chats.length;\r\n const allowLength = details.allowPeers.users.length + details.allowPeers.chats.length;\r\n\r\n row.subtitle.innerHTML = '';\r\n const s = i18n(langKey);\r\n row.subtitle.append(s);\r\n if(disallowLength || allowLength) {\r\n row.subtitle.append(` (${[-disallowLength, allowLength ? '+' + allowLength : 0].filter(Boolean).join(', ')})`);\r\n }\r\n });\r\n };\r\n\r\n section.content.append(\r\n numberVisibilityRow.container, \r\n lastSeenTimeRow.container, \r\n photoVisibilityRow.container, \r\n callRow.container, \r\n linkAccountRow.container, \r\n groupChatsAddRow.container\r\n );\r\n this.scrollable.append(section.container);\r\n\r\n for(const key in rowsByKeys) {\r\n updatePrivacyRow(key as keyof typeof rowsByKeys);\r\n }\r\n\r\n rootScope.addEventListener('privacy_update', (update) => {\r\n updatePrivacyRow(convertKeyToInputKey(update.key._) as any);\r\n });\r\n }\r\n\r\n const promises: Promise<any>[] = [];\r\n {\r\n const section = new SettingSection({name: 'Privacy.SensitiveContent'});\r\n section.container.classList.add('hide');\r\n\r\n promises.push(apiManager.invokeApi('account.getContentSettings').then(settings => {\r\n if(!settings.pFlags.sensitive_can_change) {\r\n return;\r\n }\r\n \r\n const enabled = settings.pFlags.sensitive_enabled;\r\n\r\n const sensitiveRow = new Row({\r\n checkboxField: new CheckboxField({text: 'PrivacyAndSecurity.SensitiveText', checked: enabled}),\r\n subtitleLangKey: 'PrivacyAndSecurity.SensitiveDesc',\r\n noCheckboxSubtitle: true\r\n });\r\n \r\n section.content.append(sensitiveRow.container);\r\n section.container.classList.remove('hide');\r\n \r\n this.eventListener.addEventListener('destroy', () => {\r\n const _enabled = sensitiveRow.checkboxField.checked;\r\n const isChanged = _enabled !== enabled;\r\n if(!isChanged) {\r\n return;\r\n }\r\n \r\n apiManager.invokeApi('account.setContentSettings', {\r\n sensitive_enabled: _enabled\r\n });\r\n }, {once: true});\r\n }));\r\n\r\n this.scrollable.append(section.container);\r\n }\r\n\r\n {\r\n const section = new SettingSection({name: 'FilterChats'});\r\n\r\n const onDeleteClick = () => {\r\n const popup = new PopupPeer('popup-delete-drafts', {\r\n buttons: [{\r\n langKey: 'Delete',\r\n callback: () => {\r\n const toggle = toggleDisability([deleteButton], true);\r\n appDraftsManager.clearAllDrafts().then(() => {\r\n toggle();\r\n });\r\n },\r\n isDanger: true,\r\n }], \r\n titleLangKey: 'AreYouSureClearDraftsTitle',\r\n descriptionLangKey: 'AreYouSureClearDrafts'\r\n });\r\n \r\n popup.show();\r\n };\r\n\r\n const deleteButton = Button('btn-primary btn-transparent', {icon: 'delete', text: 'PrivacyDeleteCloudDrafts'});\r\n this.listenerSetter.add(deleteButton)('click', onDeleteClick);\r\n section.content.append(deleteButton);\r\n\r\n /* promises.push(apiManager.invokeApi('messages.getAllDrafts').then(drafts => {\r\n const draftsRow = new Row({\r\n titleLangKey: 'PrivacyDeleteCloudDrafts',\r\n subtitleLangKey: 'Drafts',\r\n subtitleLangArgs: [(drafts as Updates.updates).updates.length],\r\n icon: 'delete',\r\n clickable: onDeleteClick\r\n });\r\n \r\n section.content.append(draftsRow.container);\r\n })); */\r\n\r\n this.scrollable.append(section.container);\r\n }\r\n\r\n return Promise.all(promises);\r\n }\r\n\r\n public updateActiveSessions() {\r\n apiManager.invokeApi('account.getAuthorizations').then(auths => {\r\n this.activeSessionsRow.freezed = false;\r\n this.authorizations = auths.authorizations;\r\n _i18n(this.activeSessionsRow.subtitle, 'Privacy.Devices', [this.authorizations.length]);\r\n //console.log('auths', auths);\r\n });\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport renderImageFromUrl from \"./dom/renderImageFromUrl\";\r\n\r\nexport function averageColorFromCanvas(canvas: HTMLCanvasElement) {\r\n const context = canvas.getContext('2d');\r\n\r\n const pixel = new Array(4).fill(0);\r\n const pixels = context.getImageData(0, 0, canvas.width, canvas.height).data;\r\n for(let i = 0; i < pixels.length; i += 4) {\r\n pixel[0] += pixels[i];\r\n pixel[1] += pixels[i + 1];\r\n pixel[2] += pixels[i + 2];\r\n pixel[3] += pixels[i + 3];\r\n }\r\n\r\n const pixelsLength = pixels.length / 4;\r\n const outPixel = new Uint8ClampedArray(4);\r\n outPixel[0] = pixel[0] / pixelsLength;\r\n outPixel[1] = pixel[1] / pixelsLength;\r\n outPixel[2] = pixel[2] / pixelsLength;\r\n outPixel[3] = pixel[3] / pixelsLength;\r\n return outPixel;\r\n}\r\n\r\nexport function averageColor(imageUrl: string) {\r\n const img = document.createElement('img');\r\n return new Promise<Uint8ClampedArray>((resolve) => {\r\n renderImageFromUrl(img, imageUrl, () => {\r\n const canvas = document.createElement('canvas');\r\n const ratio = img.naturalWidth / img.naturalHeight;\r\n const DIMENSIONS = 50;\r\n if(ratio === 1) {\r\n canvas.width = DIMENSIONS;\r\n canvas.height = canvas.width / ratio;\r\n } else if(ratio > 1) {\r\n canvas.height = DIMENSIONS;\r\n canvas.width = canvas.height / ratio;\r\n } else {\r\n canvas.width = canvas.height = DIMENSIONS;\r\n }\r\n \r\n const context = canvas.getContext('2d');\r\n context.drawImage(img, 0, 0, img.naturalWidth, img.naturalHeight, 0, 0, canvas.width, canvas.height);\r\n resolve(averageColorFromCanvas(canvas));\r\n });\r\n });\r\n};\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nexport type ColorHsla = {\r\n h: number,\r\n s: number,\r\n l: number,\r\n a: number\r\n};\r\n\r\nexport type ColorRgba = [number, number, number, number];\r\nexport type ColorRgb = [number, number, number];\r\n\r\n/**\r\n * @returns h [0, 360], s [0, 100], l [0, 100], a [0, 1]\r\n */\r\nexport function rgbaToHsla(r: number, g: number, b: number, a: number = 1): ColorHsla {\r\n r /= 255, g /= 255, b /= 255;\r\n const max = Math.max(r, g, b),\r\n min = Math.min(r, g, b);\r\n let h, s, l = (max + min) / 2;\r\n\r\n if(max === min) {\r\n h = s = 0; // achromatic\r\n } else {\r\n let d = max - min;\r\n s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\r\n switch (max) {\r\n case r:\r\n h = (g - b) / d + (g < b ? 6 : 0);\r\n break;\r\n case g:\r\n h = (b - r) / d + 2;\r\n break;\r\n case b:\r\n h = (r - g) / d + 4;\r\n break;\r\n }\r\n h /= 6;\r\n }\r\n\r\n return {\r\n h: h * 360,\r\n s: s * 100,\r\n l: l * 100,\r\n a\r\n };\r\n}\r\n\r\n// * https://stackoverflow.com/a/9493060/6758968\r\n/**\r\n * Converts an HSL color value to RGB. Conversion formula\r\n * adapted from http://en.wikipedia.org/wiki/HSL_color_space.\r\n * Assumes h in [0, 360], s, and l are contained in the set [0, 1], a in [0, 1] and\r\n * returns r, g, and b in the set [0, 255].\r\n *\r\n * @param {number} h The hue\r\n * @param {number} s The saturation\r\n * @param {number} l The lightness\r\n * @return {Array} The RGB representation\r\n */\r\nexport function hslaToRgba(h: number, s: number, l: number, a: number): ColorRgba {\r\n h /= 360, s /= 100, l /= 100;\r\n let r: number, g: number, b: number;\r\n\r\n if(s === 0) {\r\n r = g = b = l; // achromatic\r\n } else {\r\n const hue2rgb = function hue2rgb(p: number, q: number, t: number) {\r\n if(t < 0) t += 1;\r\n if(t > 1) t -= 1;\r\n if(t < 1/6) return p + (q - p) * 6 * t;\r\n if(t < 1/2) return q;\r\n if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;\r\n return p;\r\n }\r\n\r\n const q = l < 0.5 ? l * (1 + s) : l + s - l * s;\r\n const p = 2 * l - q;\r\n r = hue2rgb(p, q, h + 1/3);\r\n g = hue2rgb(p, q, h);\r\n b = hue2rgb(p, q, h - 1/3);\r\n }\r\n\r\n return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255), Math.round(a * 255)];\r\n}\r\n\r\nexport function hslaStringToRgba(hsla: string) {\r\n const splitted = hsla.slice(5, -1).split(', ');\r\n const alpha = +splitted.pop();\r\n const arr = splitted.map((val) => {\r\n if(val.endsWith('%')) {\r\n return +val.slice(0, -1);\r\n }\r\n \r\n return +val;\r\n });\r\n\r\n return hslaToRgba(arr[0], arr[1], arr[2], alpha);\r\n}\r\n\r\nexport function hexaToRgba(hexa: string) {\r\n const arr: ColorRgba = [] as any;\r\n const offset = hexa[0] === '#' ? 1 : 0;\r\n if(hexa.length === (5 + offset)) {\r\n hexa = (offset ? '#' : '') + '0' + hexa.slice(offset);\r\n }\r\n\r\n if(hexa.length === (3 + offset)) {\r\n for(let i = offset; i < hexa.length; ++i) {\r\n arr.push(parseInt(hexa[i] + hexa[i], 16));\r\n }\r\n } else if(hexa.length === (4 + offset)) {\r\n for(let i = offset; i < (hexa.length - 1); ++i) {\r\n arr.push(parseInt(hexa[i] + hexa[i], 16));\r\n }\r\n\r\n arr.push(parseInt(hexa[hexa.length - 1], 16));\r\n } else {\r\n for(let i = offset; i < hexa.length; i += 2) {\r\n arr.push(parseInt(hexa.slice(i, i + 2), 16));\r\n }\r\n }\r\n\r\n return arr;\r\n}\r\n\r\nexport function hexToRgb(hex: string) {\r\n return hexaToRgba(hex.slice(0, 7)) as any as ColorRgb;\r\n}\r\n\r\nexport function hexaToHsla(hexa: string) {\r\n const rgba = hexaToRgba(hexa);\r\n return rgbaToHsla(rgba[0], rgba[1], rgba[2], rgba[3]);\r\n}\r\n\r\nexport function rgbaToHexa(rgba: ColorRgba | ColorRgb) {\r\n return '#' + rgba.map(v => ('0' + v.toString(16)).slice(-2)).join('');\r\n}\r\n\r\nexport function hslaStringToHexa(hsla: string) {\r\n return rgbaToHexa(hslaStringToRgba(hsla));\r\n}\r\n\r\nexport function hslaStringToHex(hsla: string) {\r\n return hslaStringToHexa(hsla).slice(0, -2);\r\n}\r\n","import { rgbaToHsla } from \"./color\";\r\n\r\n// * https://github.com/TelegramMessenger/Telegram-iOS/blob/3d062fff78cc6b287c74e6171f855a3500c0156d/submodules/TelegramPresentationData/Sources/PresentationData.swift#L453\r\nexport default function highlightningColor(rgba: [number, number, number, number?]) {\r\n let {h, s, l} = rgbaToHsla(rgba[0], rgba[1], rgba[2]);\r\n if(s > 0) {\r\n s = Math.min(100, s + 5 + 0.1 * (100 - s));\r\n }\r\n l = Math.max(0, l * .65);\r\n \r\n const hsla = `hsla(${h}, ${s}%, ${l}%, .4)`;\r\n return hsla;\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko, Artem Kolnogorov and unknown creator of the script taken from http://useless.altervista.org/gradient.html\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { animate } from \"../../helpers/animation\";\nimport { hexToRgb } from \"../../helpers/color\";\n\nconst WIDTH = 50;\nconst HEIGHT = WIDTH;\n\nexport default class ChatBackgroundGradientRenderer {\n private readonly _width = WIDTH;\n private readonly _height = HEIGHT;\n private _phase: number;\n private _tail: number;\n private readonly _tails = 90;\n private readonly _scrollTails = 50;\n private _frames: ImageData[];\n private _colors: {r: number, g: number, b: number}[];\n /* private readonly _curve = [ \n 0, 25, 50, 75, 100, 150, 200, 250, 300, 350, 400, 500, 600, 700, 800, 900, \n 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1830, 1860, 1890, 1920, \n 1950, 1980, 2010, 2040, 2070, 2100, 2130, 2160, 2190, 2220, 2250, 2280, 2310, \n 2340, 2370, 2400, 2430, 2460, 2490, 2520, 2550, 2580, 2610, 2630, 2640, 2650, \n 2660, 2670, 2680, 2690, 2700\n ]; */\n private readonly _curve = [\n 0 , 0.25 , 0.50 , 0.75 , 1 , 1.5 , 2 , 2.5 , 3 , 3.5 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 ,\n 13 , 14 , 15 , 16 , 17 , 18 , 18.3 , 18.6 , 18.9 , 19.2 , 19.5 , 19.8 , 20.1 , 20.4 , 20.7 ,\n 21.0 , 21.3 , 21.6 , 21.9 , 22.2 , 22.5 , 22.8 , 23.1 , 23.4 , 23.7 , 24.0 , 24.3 , 24.6 ,\n 24.9 , 25.2 , 25.5 , 25.8 , 26.1 , 26.3 , 26.4 , 26.5 , 26.6 , 26.7 , 26.8 , 26.9 , 27 ,\n ];\n private readonly _incrementalCurve: number[];\n private readonly _positions = [\n { x: 0.80, y: 0.10 },\n { x: 0.60, y: 0.20 },\n { x: 0.35, y: 0.25 },\n { x: 0.25, y: 0.60 },\n { x: 0.20, y: 0.90 },\n { x: 0.40, y: 0.80 },\n { x: 0.65, y: 0.75 },\n { x: 0.75, y: 0.40 }\n ];\n private readonly _phases = this._positions.length;\n private _onWheelRAF: number;\n private _scrollDelta: number;\n\n // private _ts = 0;\n // private _fps = 15;\n // private _frametime = 1000 / this._fps;\n // private _raf: number;\n\n private _canvas: HTMLCanvasElement;\n private _ctx: CanvasRenderingContext2D;\n private _hc: HTMLCanvasElement;\n private _hctx: CanvasRenderingContext2D;\n\n private _addedScrollListener: boolean;\n private _animatingToNextPosition: boolean;\n\n constructor() {\n const diff = this._tails / this._curve[this._curve.length - 1];\n\n for(let i = 0, length = this._curve.length; i < length; ++i) {\n this._curve[i] = this._curve[i] * diff;\n }\n\n this._incrementalCurve = this._curve.map((v, i, arr) => {\n return v - (arr[i - 1] ?? 0);\n });\n }\n\n private hexToRgb(hex: string) {\n const result = hexToRgb(hex);\n return {r: result[0], g: result[1], b: result[2]};\n }\n\n private getPositions(shift: number) {\n const positions = this._positions.slice();\n while(shift > 0) {\n positions.push(positions.shift());\n --shift;\n }\n\n const result: typeof positions = [];\n for(let i = 0; i < positions.length; i += 2) {\n result.push(positions[i]);\n }\n return result;\n }\n\n private getNextPositions(phase: number, curveMax: number, curve: number[]) {\n const pos = this.getPositions(phase);\n if(!curve[0] && curve.length === 1) {\n return [pos];\n }\n \n const nextPos = this.getPositions(++phase % this._phases);\n const distances = nextPos.map((nextPos, idx) => {\n return {\n x: (nextPos.x - pos[idx].x) / curveMax,\n y: (nextPos.y - pos[idx].y) / curveMax,\n };\n });\n\n const positions = curve.map((value) => {\n return distances.map((distance, idx) => {\n return {\n x: pos[idx].x + distance.x * value,\n y: pos[idx].y + distance.y * value\n };\n });\n });\n\n return positions;\n }\n \n private curPosition(phase: number, tail: number) {\n const positions = this.getNextPositions(phase, this._tails, [tail]);\n return positions[0];\n }\n\n private changeTail(diff: number) {\n this._tail += diff;\n\n while(this._tail >= this._tails) {\n this._tail -= this._tails;\n if(++this._phase >= this._phases) {\n this._phase -= this._phases;\n }\n }\n\n while(this._tail < 0) {\n this._tail += this._tails;\n if(--this._phase < 0) {\n this._phase += this._phases;\n }\n }\n }\n \n private onWheel = (e: {deltaY: number}) => {\n if(this._animatingToNextPosition) {\n return;\n }\n\n this._scrollDelta += e.deltaY;\n if(this._onWheelRAF === undefined) {\n this._onWheelRAF = requestAnimationFrame(this.drawOnWheel);\n }\n };\n\n private drawOnWheel = () => {\n let diff = this._scrollDelta / this._scrollTails;\n this._scrollDelta %= this._scrollTails;\n diff = diff > 0 ? Math.floor(diff) : Math.ceil(diff);\n if(diff) {\n this.changeTail(diff);\n const curPos = this.curPosition(this._phase, this._tail);\n this.drawGradient(curPos);\n }\n this._onWheelRAF = undefined;\n };\n\n private drawNextPositionAnimated = () => {\n const frames = this._frames;\n const id = frames.shift();\n if(id) {\n this.drawImageData(id);\n }\n \n const leftLength = frames.length;\n if(!leftLength) {\n this._animatingToNextPosition = undefined;\n }\n\n return !!leftLength;\n };\n\n private getGradientImageData(positions: {x: number, y: number}[]) {\n const id = this._hctx.createImageData(this._width, this._height);\n const pixels = id.data;\n\n let offset = 0;\n for(let y = 0; y < this._height; ++y) {\n const directPixelY = y / this._height;\n const centerDistanceY = directPixelY - 0.5;\n const centerDistanceY2 = centerDistanceY * centerDistanceY;\n\n for(let x = 0; x < this._width; ++x) {\n const directPixelX = x / this._width;\n\n const centerDistanceX = directPixelX - 0.5;\n const centerDistance = Math.sqrt(centerDistanceX * centerDistanceX + centerDistanceY2);\n\n const swirlFactor = 0.35 * centerDistance;\n const theta = swirlFactor * swirlFactor * 0.8 * 8.0;\n const sinTheta = Math.sin(theta);\n const cosTheta = Math.cos(theta);\n\n const pixelX = Math.max(0.0, Math.min(1.0, 0.5 + centerDistanceX * cosTheta - centerDistanceY * sinTheta));\n const pixelY = Math.max(0.0, Math.min(1.0, 0.5 + centerDistanceX * sinTheta + centerDistanceY * cosTheta));\n\n let distanceSum = 0.0;\n\n let r = 0.0;\n let g = 0.0;\n let b = 0.0;\n\n for(let i = 0; i < this._colors.length; i++) {\n const colorX = positions[i].x;\n const colorY = positions[i].y;\n\n const distanceX = pixelX - colorX;\n const distanceY = pixelY - colorY;\n\n let distance = Math.max(0.0, 0.9 - Math.sqrt(distanceX * distanceX + distanceY * distanceY));\n distance = distance * distance * distance * distance;\n distanceSum += distance;\n\n r += distance * this._colors[i].r / 255;\n g += distance * this._colors[i].g / 255;\n b += distance * this._colors[i].b / 255;\n }\n\n pixels[offset++] = r / distanceSum * 255.0;\n pixels[offset++] = g / distanceSum * 255.0;\n pixels[offset++] = b / distanceSum * 255.0;\n pixels[offset++] = 0xFF;\n }\n }\n return id;\n }\n\n private drawImageData(id: ImageData) {\n this._hctx.putImageData(id, 0, 0);\n this._ctx.drawImage(this._hc, 0, 0, this._width, this._height);\n }\n\n private drawGradient(positions: {x: number, y: number}[]) {\n this.drawImageData(this.getGradientImageData(positions));\n }\n\n // private doAnimate = () => {\n // const now = +Date.now();\n // if(!document.hasFocus() || (now - this._ts) < this._frametime) {\n // this._raf = requestAnimationFrame(this.doAnimate);\n // return;\n // }\n\n // this._ts = now;\n // this.changeTail(1);\n // const cur_pos = this.curPosition(this._phase, this._tail);\n // this.drawGradient(cur_pos);\n // this._raf = requestAnimationFrame(this.doAnimate);\n // };\n\n // public animate(start?: boolean) {\n // if(!start) {\n // cancelAnimationFrame(this._raf);\n // return;\n // }\n // this.doAnimate();\n // }\n\n public init(el: HTMLCanvasElement) {\n this._frames = [];\n this._phase = 0;\n this._tail = 0;\n this._scrollDelta = 0;\n if(this._onWheelRAF !== undefined) {\n cancelAnimationFrame(this._onWheelRAF);\n this._onWheelRAF = undefined;\n }\n\n const colors = el.getAttribute('data-colors').split(',').reverse();\n this._colors = colors.map(color => {\n return this.hexToRgb(color);\n });\n\n if(!this._hc) {\n this._hc = document.createElement('canvas');\n this._hc.width = this._width;\n this._hc.height = this._height;\n this._hctx = this._hc.getContext('2d');\n }\n\n this._canvas = el;\n this._ctx = this._canvas.getContext('2d');\n this.update();\n }\n\n public update() {\n if(this._colors.length < 2) {\n const color = this._colors[0];\n this._ctx.fillStyle = `rgb(${color.r}, ${color.g}, ${color.b})`;\n this._ctx.fillRect(0, 0, this._width, this._height);\n return;\n }\n \n const pos = this.curPosition(this._phase, this._tail);\n this.drawGradient(pos);\n }\n\n public toNextPosition() {\n if(this._colors.length < 2) {\n return;\n }\n\n const tail = this._tail;\n const tails = this._tails;\n\n let nextPhaseOnIdx: number;\n\n const curve: number[] = [];\n for(let i = 0, length = this._incrementalCurve.length; i < length; ++i) {\n const inc = this._incrementalCurve[i];\n let value = (curve[i - 1] ?? tail) + inc;\n\n if(+value.toFixed(2) > tails && nextPhaseOnIdx === undefined) {\n nextPhaseOnIdx = i;\n value %= tails;\n }\n \n curve.push(value);\n }\n\n const currentPhaseCurve = curve.slice(0, nextPhaseOnIdx);\n const nextPhaseCurve = nextPhaseOnIdx !== undefined ? curve.slice(nextPhaseOnIdx) : [];\n\n [currentPhaseCurve, nextPhaseCurve].forEach((curve, idx, curves) => {\n const last = curve[curve.length - 1];\n if(last !== undefined && last > tails) {\n curve[curve.length - 1] = +last.toFixed(2);\n }\n \n this._tail = last ?? 0;\n\n if(!curve.length) {\n return;\n }\n\n const positions = this.getNextPositions(this._phase, tails, curve);\n if(idx !== (curves.length - 1)) {\n if(++this._phase >= this._phases) {\n this._phase -= this._phases;\n }\n }\n\n const ids = positions.map((pos) => {\n return this.getGradientImageData(pos);\n });\n \n this._frames.push(...ids);\n });\n\n this._animatingToNextPosition = true;\n animate(this.drawNextPositionAnimated);\n }\n\n public scrollAnimate(start?: boolean) {\n if(this._colors.length < 2 && start) {\n return;\n }\n\n if(start && !this._addedScrollListener) {\n document.addEventListener('wheel', this.onWheel);\n this._addedScrollListener = true;\n } else if(!start && this._addedScrollListener) {\n document.removeEventListener('wheel', this.onWheel);\n this._addedScrollListener = false;\n }\n }\n\n public cleanup() {\n this.scrollAnimate(false);\n // this.animate(false);\n }\n\n public static createCanvas(colors?: string) {\n const canvas = document.createElement('canvas');\n canvas.width = WIDTH;\n canvas.height = HEIGHT;\n if(colors !== undefined) {\n canvas.dataset.colors = colors;\n }\n\n return canvas;\n }\n\n public static create(colors?: string) {\n const canvas = this.createCanvas(colors);\n const gradientRenderer = new ChatBackgroundGradientRenderer();\n gradientRenderer.init(canvas);\n\n return {gradientRenderer, canvas};\n }\n}\n","import { ColorHsla, ColorRgba, hexaToHsla, hslaToRgba, rgbaToHexa as rgbaToHexa, rgbaToHsla } from \"../helpers/color\";\r\nimport attachGrabListeners from \"../helpers/dom/attachGrabListeners\";\r\nimport clamp from \"../helpers/number/clamp\";\r\nimport InputField, { InputState } from \"./inputField\";\r\n\r\nexport type ColorPickerColor = { \r\n hsl: string; \r\n rgb: string; \r\n hex: string; \r\n hsla: string; \r\n rgba: string; \r\n hexa: string; \r\n rgbaArray: ColorRgba; \r\n};\r\n\r\nexport default class ColorPicker {\r\n private static BASE_CLASS = 'color-picker';\r\n public container: HTMLElement;\r\n\r\n private boxRect: DOMRect;\r\n //private boxDraggerRect: DOMRect;\r\n private hueRect: DOMRect;\r\n //private hueDraggerRect: DOMRect;\r\n\r\n\tprivate hue = 0;\r\n\tprivate saturation = 100;\r\n\tprivate lightness = 50;\r\n\tprivate alpha = 1;\r\n private elements: {\r\n box: SVGSVGElement,\r\n boxDragger: SVGSVGElement,\r\n sliders: HTMLElement,\r\n hue: SVGSVGElement,\r\n hueDragger: SVGSVGElement,\r\n saturation: SVGLinearGradientElement,\r\n } = {} as any;\r\n private hexInputField: InputField;\r\n private rgbInputField: InputField;\r\n public onChange: (color: ReturnType<ColorPicker['getCurrentColor']>) => void;\r\n\r\n constructor() {\r\n this.container = document.createElement('div');\r\n this.container.classList.add(ColorPicker.BASE_CLASS);\r\n\r\n const html = `\r\n <svg class=\"${ColorPicker.BASE_CLASS + '-box'}\" viewBox=\"0 0 380 198\">\r\n <defs>\r\n <linearGradient id=\"color-picker-saturation\" x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"0%\">\r\n <stop offset=\"0%\" stop-color=\"#fff\"></stop>\r\n <stop offset=\"100%\" stop-color=\"hsl(0,100%,50%)\"></stop>\r\n </linearGradient>\r\n <linearGradient id=\"color-picker-brightness\" x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">\r\n <stop offset=\"0%\" stop-color=\"rgba(0,0,0,0)\"></stop>\r\n <stop offset=\"100%\" stop-color=\"#000\"></stop>\r\n </linearGradient>\r\n <pattern id=\"color-picker-pattern\" width=\"100%\" height=\"100%\">\r\n <rect x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" fill=\"url(#color-picker-saturation)\"></rect>\r\n <rect x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" fill=\"url(#color-picker-brightness)\"></rect>\r\n </pattern>\r\n </defs>\r\n <rect rx=\"10\" ry=\"10\" x=\"0\" y=\"0\" width=\"380\" height=\"198\" fill=\"url(#color-picker-pattern)\"></rect>\r\n <svg class=\"${ColorPicker.BASE_CLASS + '-dragger'} ${ColorPicker.BASE_CLASS + '-box-dragger'}\" x=\"0\" y=\"0\">\r\n <circle r=\"11\" fill=\"inherit\" stroke=\"#fff\" stroke-width=\"2\"></circle>\r\n </svg>\r\n </svg>\r\n <div class=\"${ColorPicker.BASE_CLASS + '-sliders'}\">\r\n <svg class=\"${ColorPicker.BASE_CLASS + '-color-slider'}\" viewBox=\"0 0 380 24\">\r\n <defs>\r\n <linearGradient id=\"hue\" x1=\"100%\" y1=\"0%\" x2=\"0%\" y2=\"0%\">\r\n <stop offset=\"0%\" stop-color=\"#f00\"></stop>\r\n <stop offset=\"16.666%\" stop-color=\"#f0f\"></stop>\r\n <stop offset=\"33.333%\" stop-color=\"#00f\"></stop>\r\n <stop offset=\"50%\" stop-color=\"#0ff\"></stop>\r\n <stop offset=\"66.666%\" stop-color=\"#0f0\"></stop>\r\n <stop offset=\"83.333%\" stop-color=\"#ff0\"></stop>\r\n <stop offset=\"100%\" stop-color=\"#f00\"></stop>\r\n </linearGradient>\r\n </defs>\r\n <rect rx=\"4\" ry=\"4\" x=\"0\" y=\"9\" width=\"380\" height=\"8\" fill=\"url(#hue)\"></rect>\r\n <svg class=\"${ColorPicker.BASE_CLASS + '-dragger'} ${ColorPicker.BASE_CLASS + '-color-slider-dragger'}\" x=\"0\" y=\"13\">\r\n <circle r=\"11\" fill=\"inherit\" stroke=\"#fff\" stroke-width=\"2\"></circle>\r\n </svg>\r\n </svg>\r\n </div>\r\n `;\r\n\r\n this.container.innerHTML = html;\r\n\r\n this.elements.box = this.container.firstElementChild as any;\r\n this.elements.boxDragger = this.elements.box.lastElementChild as any;\r\n this.elements.saturation = this.elements.box.firstElementChild.firstElementChild as any;\r\n\r\n this.elements.sliders = this.elements.box.nextElementSibling as any;\r\n\r\n this.elements.hue = this.elements.sliders.firstElementChild as any;\r\n this.elements.hueDragger = this.elements.hue.lastElementChild as any;\r\n\r\n this.hexInputField = new InputField({plainText: true, label: 'Appearance.Color.Hex'});\r\n this.rgbInputField = new InputField({plainText: true, label: 'Appearance.Color.RGB'});\r\n\r\n const inputs = document.createElement('div');\r\n inputs.className = ColorPicker.BASE_CLASS + '-inputs';\r\n inputs.append(this.hexInputField.container, this.rgbInputField.container);\r\n this.container.append(inputs);\r\n\r\n this.hexInputField.input.addEventListener('input', () => {\r\n let value = this.hexInputField.value.replace(/#/g, '').slice(0, 6);\r\n\r\n const match = value.match(/([a-fA-F\\d]+)/);\r\n const valid = match && match[0].length === value.length && [/* 3, 4, */6].includes(value.length);\r\n this.hexInputField.setState(valid ? InputState.Neutral : InputState.Error);\r\n\r\n value = '#' + value;\r\n this.hexInputField.setValueSilently(value);\r\n \r\n if(valid) {\r\n this.setColor(value, false, true);\r\n }\r\n });\r\n\r\n // patched https://stackoverflow.com/a/34029238/6758968\r\n const rgbRegExp = /^(?:rgb)?\\(?([01]?\\d\\d?|2[0-4]\\d|25[0-5])(?:\\W+)([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\W+(?:([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\)?)$/;\r\n this.rgbInputField.input.addEventListener('input', () => {\r\n const match = this.rgbInputField.value.match(rgbRegExp);\r\n this.rgbInputField.setState(match ? InputState.Neutral : InputState.Error);\r\n\r\n if(match) {\r\n this.setColor(rgbaToHsla(+match[1], +match[2], +match[3]), true, false);\r\n }\r\n });\r\n\r\n this.attachBoxListeners();\r\n this.attachHueListeners();\r\n }\r\n\r\n private onGrabStart = () => {\r\n document.documentElement.style.cursor = this.elements.boxDragger.style.cursor = 'grabbing';\r\n };\r\n\r\n private onGrabEnd = () => {\r\n document.documentElement.style.cursor = this.elements.boxDragger.style.cursor = '';\r\n };\r\n\r\n private attachBoxListeners() {\r\n attachGrabListeners(this.elements.box as any, () => {\r\n this.onGrabStart();\r\n this.boxRect = this.elements.box.getBoundingClientRect();\r\n //this.boxDraggerRect = this.elements.boxDragger.getBoundingClientRect();\r\n }, (pos) => {\r\n this.saturationHandler(pos.x, pos.y);\r\n }, () => {\r\n this.onGrabEnd();\r\n });\r\n }\r\n\r\n private attachHueListeners() {\r\n attachGrabListeners(this.elements.hue as any, () => {\r\n this.onGrabStart();\r\n this.hueRect = this.elements.hue.getBoundingClientRect();\r\n //this.hueDraggerRect = this.elements.hueDragger.getBoundingClientRect();\r\n }, (pos) => {\r\n this.hueHandler(pos.x);\r\n }, () => {\r\n this.onGrabEnd();\r\n });\r\n }\r\n\r\n public setColor(color: ColorHsla | string, updateHexInput = true, updateRgbInput = true) {\r\n if(color === undefined) { // * set to red\r\n color = {\r\n h: 0,\r\n s: 100,\r\n l: 50,\r\n a: 1\r\n };\r\n } else if(typeof(color) === 'string') {\r\n if(color[0] === '#') {\r\n color = hexaToHsla(color);\r\n } else {\r\n const rgb = color.match(/[.?\\d]+/g);\r\n color = rgbaToHsla(+rgb[0], +rgb[1], +rgb[2], rgb[3] === undefined ? 1 : +rgb[3]);\r\n }\r\n }\r\n\r\n // Set box\r\n this.boxRect = this.elements.box.getBoundingClientRect();\r\n\r\n const boxX = this.boxRect.width / 100 * color.s;\r\n const percentY = 100 - (color.l / (100 - color.s / 2)) * 100;\r\n const boxY = this.boxRect.height / 100 * percentY;\r\n\r\n this.saturationHandler(this.boxRect.left + boxX, this.boxRect.top + boxY, false);\r\n\r\n // Set hue\r\n this.hueRect = this.elements.hue.getBoundingClientRect();\r\n\r\n const percentHue = color.h / 360;\r\n const hueX = this.hueRect.left + this.hueRect.width * percentHue;\r\n\r\n this.hueHandler(hueX, false);\r\n\r\n // Set values\r\n this.hue = color.h;\r\n this.saturation = color.s;\r\n this.lightness = color.l;\r\n this.alpha = color.a;\r\n\r\n this.updatePicker(updateHexInput, updateRgbInput);\r\n };\r\n\r\n public getCurrentColor(): ColorPickerColor {\r\n const rgbaArray = hslaToRgba(this.hue, this.saturation, this.lightness, this.alpha);\r\n const hexa = rgbaToHexa(rgbaArray);\r\n const hex = hexa.slice(0, -2);\r\n\r\n return {\r\n hsl: `hsl(${this.hue}, ${this.saturation}%, ${this.lightness}%)`,\r\n rgb: `rgb(${rgbaArray[0]}, ${rgbaArray[1]}, ${rgbaArray[2]})`,\r\n hex: hex,\r\n hsla: `hsla(${this.hue}, ${this.saturation}%, ${this.lightness}%, ${this.alpha})`,\r\n rgba: `rgba(${rgbaArray[0]}, ${rgbaArray[1]}, ${rgbaArray[2]}, ${rgbaArray[3]})`,\r\n hexa: hexa,\r\n rgbaArray: rgbaArray\r\n };\r\n }\r\n\r\n public updatePicker(updateHexInput = true, updateRgbInput = true) {\r\n const color = this.getCurrentColor();\r\n this.elements.boxDragger.setAttributeNS(null, 'fill', color.hex);\r\n\r\n if(updateHexInput) {\r\n this.hexInputField.setValueSilently(color.hex);\r\n this.hexInputField.setState(InputState.Neutral);\r\n }\r\n\r\n if(updateRgbInput) {\r\n this.rgbInputField.setValueSilently(color.rgbaArray.slice(0, -1).join(', '));\r\n this.rgbInputField.setState(InputState.Neutral);\r\n }\r\n\r\n if(this.onChange) {\r\n this.onChange(color);\r\n }\r\n }\r\n\r\n private hueHandler(pageX: number, update = true) {\r\n const eventX = clamp(pageX - this.hueRect.left, 0, this.hueRect.width);\r\n\r\n const percents = eventX / this.hueRect.width;\r\n this.hue = Math.round(360 * percents);\r\n \r\n const hsla = `hsla(${this.hue}, 100%, 50%, ${this.alpha})`;\r\n\r\n this.elements.hueDragger.setAttributeNS(null, 'x', (percents * 100) + '%');\r\n this.elements.hueDragger.setAttributeNS(null, 'fill', hsla);\r\n \r\n this.elements.saturation.lastElementChild.setAttributeNS(null, 'stop-color', hsla);\r\n\r\n if(update) {\r\n this.updatePicker();\r\n }\r\n }\r\n\r\n private saturationHandler(pageX: number, pageY: number, update = true) {\r\n const maxX = this.boxRect.width;\r\n const maxY = this.boxRect.height;\r\n\r\n const eventX = clamp(pageX - this.boxRect.left, 0, maxX);\r\n const eventY = clamp(pageY - this.boxRect.top, 0, maxY);\r\n\r\n const posX = eventX / maxX * 100;\r\n const posY = eventY / maxY * 100;\r\n \r\n const boxDragger = this.elements.boxDragger;\r\n boxDragger.setAttributeNS(null, 'x', posX + '%');\r\n boxDragger.setAttributeNS(null, 'y', posY + '%');\r\n\r\n const saturation = clamp(posX, 0, 100);\r\n\r\n const lightnessX = 100 - saturation / 2;\r\n const lightnessY = 100 - clamp(posY, 0, 100);\r\n\r\n const lightness = clamp(lightnessY / 100 * lightnessX, 0, 100);\r\n\r\n this.saturation = saturation;\r\n this.lightness = lightness;\r\n\r\n if(update) {\r\n this.updatePicker();\r\n }\r\n };\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SettingSection } from \"..\";\r\nimport { hexaToRgba } from \"../../../helpers/color\";\r\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\r\nimport findUpClassName from \"../../../helpers/dom/findUpClassName\";\r\nimport highlightningColor from \"../../../helpers/highlightningColor\";\r\nimport throttle from \"../../../helpers/schedulers/throttle\";\r\nimport appImManager from \"../../../lib/appManagers/appImManager\";\r\nimport appStateManager, { Theme } from \"../../../lib/appManagers/appStateManager\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport ColorPicker, { ColorPickerColor } from \"../../colorPicker\";\r\nimport { SliderSuperTab } from \"../../slider\";\r\n\r\nexport default class AppBackgroundColorTab extends SliderSuperTab {\r\n private colorPicker: ColorPicker;\r\n private grid: HTMLElement;\r\n private applyColor: (hex: string, updateColorPicker?: boolean) => void;\r\n private theme: Theme;\r\n\r\n init() {\r\n this.header.classList.add('with-border');\r\n this.container.classList.add('background-container', 'background-color-container');\r\n this.setTitle('SetColor');\r\n\r\n this.theme = rootScope.getTheme();\r\n\r\n const section = new SettingSection({});\r\n this.colorPicker = new ColorPicker();\r\n\r\n section.content.append(this.colorPicker.container);\r\n\r\n this.scrollable.append(section.container);\r\n\r\n const gridSection = new SettingSection({});\r\n\r\n const grid = this.grid = document.createElement('div');\r\n grid.classList.add('grid');\r\n\r\n const colors = [\r\n '#E6EBEE',\r\n '#B2CEE1',\r\n '#008DD0',\r\n '#C6E7CB',\r\n '#C4E1A6',\r\n '#60B16E',\r\n '#CCD0AF',\r\n '#A6A997',\r\n '#7A7072',\r\n '#FDD7AF',\r\n '#FDB76E',\r\n '#DD8851'\r\n ];\r\n\r\n colors.forEach(color => {\r\n const item = document.createElement('div');\r\n item.classList.add('grid-item');\r\n item.dataset.color = color.toLowerCase();\r\n\r\n // * need for transform scale\r\n const media = document.createElement('div');\r\n media.classList.add('grid-item-media');\r\n media.style.backgroundColor = color;\r\n\r\n item.append(media);\r\n grid.append(item);\r\n });\r\n\r\n attachClickEvent(grid, (e) => {\r\n const target = findUpClassName(e.target, 'grid-item');\r\n if(!target || target.classList.contains('active')) {\r\n return;\r\n }\r\n\r\n const color = target.dataset.color;\r\n if(!color) {\r\n return;\r\n }\r\n\r\n this.applyColor(color);\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n gridSection.content.append(grid);\r\n this.scrollable.append(gridSection.container);\r\n\r\n this.applyColor = throttle(this._applyColor, 16, true);\r\n }\r\n\r\n private setActive() {\r\n const active = this.grid.querySelector('.active');\r\n const background = this.theme.background;\r\n const target = background.color ? this.grid.querySelector(`.grid-item[data-color=\"${background.color}\"]`) : null;\r\n if(active === target) {\r\n return;\r\n }\r\n\r\n if(active) {\r\n active.classList.remove('active');\r\n }\r\n\r\n if(target) {\r\n target.classList.add('active');\r\n }\r\n }\r\n\r\n private _applyColor = (hex: string, updateColorPicker = true) => {\r\n if(updateColorPicker) {\r\n this.colorPicker.setColor(hex);\r\n } else {\r\n const rgba = hexaToRgba(hex);\r\n const background = this.theme.background;\r\n const hsla = highlightningColor(rgba);\r\n \r\n background.id = '2';\r\n background.intensity = 0;\r\n background.slug = '';\r\n background.color = hex.toLowerCase();\r\n background.highlightningColor = hsla;\r\n appStateManager.pushToState('settings', rootScope.settings);\r\n \r\n appImManager.applyCurrentTheme(undefined, undefined, true);\r\n this.setActive();\r\n }\r\n };\r\n\r\n private onColorChange = (color: ColorPickerColor) => {\r\n this.applyColor(color.hex, false);\r\n };\r\n\r\n onOpen() {\r\n setTimeout(() => {\r\n const background = this.theme.background;\r\n\r\n const color = (background.color || '').split(',')[0];\r\n const isColored = !!color && !background.slug;\r\n \r\n // * set active if type is color\r\n if(isColored) {\r\n this.colorPicker.onChange = this.onColorChange;\r\n }\r\n\r\n this.colorPicker.setColor(color || '#cccccc');\r\n \r\n if(!isColored) {\r\n this.colorPicker.onChange = this.onColorChange;\r\n }\r\n }, 0);\r\n }\r\n\r\n onCloseAfterTimeout() {\r\n this.colorPicker.onChange = undefined;\r\n this.colorPicker = undefined;\r\n\r\n return super.onCloseAfterTimeout();\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { generateSection } from \"..\";\r\nimport { averageColor, averageColorFromCanvas } from \"../../../helpers/averageColor\";\r\nimport blur from \"../../../helpers/blur\";\r\nimport deferredPromise from \"../../../helpers/cancellablePromise\";\r\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\r\nimport findUpClassName from \"../../../helpers/dom/findUpClassName\";\r\nimport { requestFile } from \"../../../helpers/files\";\r\nimport highlightningColor from \"../../../helpers/highlightningColor\";\r\nimport copy from \"../../../helpers/object/copy\";\r\nimport sequentialDom from \"../../../helpers/sequentialDom\";\r\nimport ChatBackgroundGradientRenderer from \"../../chat/gradientRenderer\";\r\nimport { AccountWallPapers, PhotoSize, WallPaper } from \"../../../layer\";\r\nimport appDocsManager, { MyDocument } from \"../../../lib/appManagers/appDocsManager\";\r\nimport appDownloadManager, { DownloadBlob } from \"../../../lib/appManagers/appDownloadManager\";\r\nimport appImManager from \"../../../lib/appManagers/appImManager\";\r\nimport appPhotosManager from \"../../../lib/appManagers/appPhotosManager\";\r\nimport appStateManager, { Theme, STATE_INIT } from \"../../../lib/appManagers/appStateManager\";\r\nimport apiManager from \"../../../lib/mtproto/mtprotoworker\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport Button from \"../../button\";\r\nimport CheckboxField from \"../../checkboxField\";\r\nimport ProgressivePreloader from \"../../preloader\";\r\nimport { SliderSuperTab } from \"../../slider\";\r\nimport { wrapPhoto } from \"../../wrappers\";\r\nimport AppBackgroundColorTab from \"./backgroundColor\";\r\n\r\nlet uploadTempId = 0;\r\n\r\nexport default class AppBackgroundTab extends SliderSuperTab {\r\n private grid: HTMLElement;\r\n private tempId = 0;\r\n private theme: Theme;\r\n private clicked: Set<DocId> = new Set();\r\n private blurCheckboxField: CheckboxField;\r\n\r\n private wallpapersByElement: Map<HTMLElement, WallPaper> = new Map();\r\n private elementsByKey: Map<string, HTMLElement> = new Map();\r\n\r\n init() {\r\n this.header.classList.add('with-border');\r\n this.container.classList.add('background-container', 'background-image-container');\r\n this.setTitle('ChatBackground');\r\n\r\n this.theme = rootScope.getTheme();\r\n\r\n {\r\n const container = generateSection(this.scrollable);\r\n\r\n const uploadButton = Button('btn-primary btn-transparent', {icon: 'cameraadd', text: 'ChatBackground.UploadWallpaper'});\r\n const colorButton = Button('btn-primary btn-transparent', {icon: 'colorize', text: 'SetColor'});\r\n const resetButton = Button('btn-primary btn-transparent', {icon: 'favourites', text: 'Appearance.Reset'});\r\n\r\n attachClickEvent(uploadButton, this.onUploadClick, {listenerSetter: this.listenerSetter});\r\n\r\n attachClickEvent(colorButton, () => {\r\n new AppBackgroundColorTab(this.slider).open();\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n attachClickEvent(resetButton, this.onResetClick, {listenerSetter: this.listenerSetter});\r\n\r\n const blurCheckboxField = this.blurCheckboxField = new CheckboxField({\r\n text: 'ChatBackground.Blur', \r\n name: 'blur', \r\n checked: this.theme.background.blur,\r\n withRipple: true\r\n });\r\n\r\n this.listenerSetter.add(blurCheckboxField.input)('change', () => {\r\n this.theme.background.blur = blurCheckboxField.input.checked;\r\n appStateManager.pushToState('settings', rootScope.settings);\r\n\r\n // * wait for animation end\r\n setTimeout(() => {\r\n const active = grid.querySelector('.active') as HTMLElement;\r\n if(!active) return;\r\n\r\n const wallpaper = this.wallpapersByElement.get(active);\r\n if((wallpaper as WallPaper.wallPaper).pFlags.pattern || wallpaper._ === 'wallPaperNoFile') {\r\n return;\r\n }\r\n \r\n this.setBackgroundDocument(wallpaper);\r\n }, 100);\r\n });\r\n\r\n container.append(uploadButton, colorButton, resetButton, blurCheckboxField.label);\r\n }\r\n\r\n rootScope.addEventListener('background_change', this.setActive);\r\n\r\n apiManager.invokeApiHashable({method: 'account.getWallPapers'}).then((accountWallpapers) => {\r\n const wallpapers = (accountWallpapers as AccountWallPapers.accountWallPapers).wallpapers as WallPaper.wallPaper[];\r\n wallpapers.forEach((wallpaper) => {\r\n this.addWallPaper(wallpaper);\r\n });\r\n\r\n //console.log(accountWallpapers);\r\n });\r\n\r\n const gridContainer = generateSection(this.scrollable);\r\n const grid = this.grid = document.createElement('div');\r\n grid.classList.add('grid');\r\n attachClickEvent(grid, this.onGridClick, {listenerSetter: this.listenerSetter});\r\n gridContainer.append(grid);\r\n }\r\n\r\n private onUploadClick = () => {\r\n requestFile('image/x-png,image/png,image/jpeg').then(file => {\r\n const id = 'wallpaper-upload-' + ++uploadTempId;\r\n\r\n const thumb = {\r\n _: 'photoSize',\r\n h: 0,\r\n w: 0,\r\n location: {} as any,\r\n size: file.size,\r\n type: 'full',\r\n } as PhotoSize.photoSize;\r\n let document: MyDocument = {\r\n _: 'document',\r\n access_hash: '',\r\n attributes: [],\r\n dc_id: 0,\r\n file_reference: [],\r\n id,\r\n mime_type: file.type,\r\n size: file.size,\r\n date: Date.now() / 1000,\r\n pFlags: {},\r\n thumbs: [thumb],\r\n file_name: file.name\r\n };\r\n\r\n document = appDocsManager.saveDoc(document);\r\n\r\n const cacheContext = appDownloadManager.getCacheContext(document);\r\n cacheContext.downloaded = file.size;\r\n cacheContext.url = URL.createObjectURL(file);\r\n\r\n let wallpaper: WallPaper.wallPaper = {\r\n _: 'wallPaper',\r\n access_hash: '',\r\n document: document,\r\n id,\r\n slug: id,\r\n pFlags: {}\r\n };\r\n\r\n const upload = appDownloadManager.upload(file, file.name);\r\n\r\n const deferred = deferredPromise<void>();\r\n deferred.addNotifyListener = upload.addNotifyListener;\r\n deferred.cancel = upload.cancel;\r\n\r\n upload.then(inputFile => {\r\n apiManager.invokeApi('account.uploadWallPaper', {\r\n file: inputFile,\r\n mime_type: file.type,\r\n settings: {\r\n _: 'wallPaperSettings'\r\n }\r\n }).then(_wallpaper => {\r\n const newDoc = (_wallpaper as WallPaper.wallPaper).document as MyDocument;\r\n const newCacheContext = appDownloadManager.getCacheContext(newDoc);\r\n Object.assign(newCacheContext, cacheContext);\r\n\r\n wallpaper = _wallpaper as WallPaper.wallPaper;\r\n wallpaper.document = appDocsManager.saveDoc(wallpaper.document);\r\n\r\n this.setBackgroundDocument(wallpaper).then(deferred.resolve, deferred.reject);\r\n }, deferred.reject);\r\n }, deferred.reject);\r\n\r\n const key = this.getWallpaperKey(wallpaper);\r\n deferred.then(() => {\r\n this.clicked.delete(key);\r\n }, (err) => {\r\n container.remove();\r\n //console.error('i saw the body drop', err);\r\n });\r\n\r\n const preloader = new ProgressivePreloader({\r\n isUpload: true,\r\n cancelable: true,\r\n tryAgainOnFail: false\r\n });\r\n\r\n const container = this.addWallPaper(wallpaper, false);\r\n this.clicked.add(key);\r\n\r\n preloader.attach(container, false, deferred);\r\n });\r\n };\r\n\r\n private onResetClick = () => {\r\n const defaultTheme = STATE_INIT.settings.themes.find(t => t.name === this.theme.name);\r\n if(defaultTheme) {\r\n ++this.tempId;\r\n this.theme.background = copy(defaultTheme.background);\r\n appStateManager.pushToState('settings', rootScope.settings);\r\n appImManager.applyCurrentTheme(undefined, undefined, true);\r\n this.blurCheckboxField.setValueSilently(this.theme.background.blur);\r\n }\r\n };\r\n\r\n private getColorsFromWallpaper(wallpaper: WallPaper) {\r\n return wallpaper.settings ? [\r\n wallpaper.settings.background_color,\r\n wallpaper.settings.second_background_color,\r\n wallpaper.settings.third_background_color,\r\n wallpaper.settings.fourth_background_color\r\n ].filter(Boolean).map(color => '#' + color.toString(16)).join(',') : '';\r\n }\r\n\r\n private getWallpaperKey(wallpaper: WallPaper) {\r\n return '' + wallpaper.id;\r\n }\r\n\r\n private getWallpaperKeyFromTheme(theme: Theme) {\r\n return '' + theme.background.id;\r\n }\r\n\r\n private addWallPaper(wallpaper: WallPaper, append = true) {\r\n const colors = this.getColorsFromWallpaper(wallpaper);\r\n const hasFile = wallpaper._ === 'wallPaper';\r\n if((hasFile && wallpaper.pFlags.pattern && !colors)/* || \r\n (wallpaper.document as MyDocument).mime_type.indexOf('application/') === 0 */) {\r\n return;\r\n }\r\n\r\n const isDark = !!wallpaper.pFlags.dark;\r\n\r\n const doc: MyDocument = hasFile ? (wallpaper.document = appDocsManager.saveDoc(wallpaper.document)) : undefined;\r\n\r\n const container = document.createElement('div');\r\n container.classList.add('grid-item');\r\n\r\n container.dataset.id = '' + wallpaper.id;\r\n\r\n const key = this.getWallpaperKey(wallpaper);\r\n this.wallpapersByElement.set(container, wallpaper);\r\n this.elementsByKey.set(key, container);\r\n\r\n const media = document.createElement('div');\r\n media.classList.add('grid-item-media');\r\n\r\n let wrapped: ReturnType<typeof wrapPhoto>, size: PhotoSize;\r\n if(hasFile) {\r\n size = appPhotosManager.choosePhotoSize(doc, 200, 200);\r\n wrapped = wrapPhoto({\r\n photo: doc,\r\n message: null,\r\n container: media,\r\n withoutPreloader: true,\r\n size: size,\r\n noFadeIn: wallpaper.pFlags.pattern\r\n });\r\n\r\n (wrapped.loadPromises.thumb || wrapped.loadPromises.full).then(() => {\r\n sequentialDom.mutate(() => {\r\n container.append(media);\r\n });\r\n });\r\n\r\n if(wallpaper.pFlags.pattern) {\r\n media.classList.add('is-pattern');\r\n \r\n if(isDark) {\r\n wrapped.images.full.style.display = 'none';\r\n if(wrapped.images.thumb) {\r\n wrapped.images.thumb.style.display = 'none';\r\n }\r\n } else if(wallpaper.settings?.intensity) {\r\n wrapped.images.full.style.opacity = '' + Math.abs(wallpaper.settings.intensity) / 100;\r\n }\r\n }\r\n } else {\r\n container.append(media);\r\n }\r\n\r\n if(wallpaper.settings && wallpaper.settings.background_color !== undefined) {\r\n const {canvas} = ChatBackgroundGradientRenderer.create(colors);\r\n canvas.classList.add('background-colors-canvas');\r\n \r\n if(isDark && hasFile) {\r\n const cacheContext = appDownloadManager.getCacheContext(doc, size.type);\r\n wrapped.loadPromises.full.then(() => {\r\n canvas.style.webkitMaskImage = `url(${cacheContext.url})`;\r\n canvas.style.opacity = '' + Math.abs(wallpaper.settings.intensity) / 100;\r\n media.append(canvas);\r\n });\r\n } else {\r\n media.append(canvas);\r\n }\r\n }\r\n\r\n if(this.getWallpaperKeyFromTheme(this.theme) === key) {\r\n container.classList.add('active');\r\n }\r\n\r\n this.grid[append ? 'append' : 'prepend'](container);\r\n\r\n return container;\r\n }\r\n\r\n private onGridClick = (e: MouseEvent | TouchEvent) => {\r\n const target = findUpClassName(e.target, 'grid-item') as HTMLElement;\r\n if(!target) return;\r\n\r\n const wallpaper = this.wallpapersByElement.get(target);\r\n if(wallpaper._ === 'wallPaperNoFile') {\r\n this.setBackgroundDocument(wallpaper);\r\n return;\r\n }\r\n \r\n const key = this.getWallpaperKey(wallpaper);\r\n if(this.clicked.has(key)) return;\r\n this.clicked.add(key);\r\n \r\n const doc = wallpaper.document as MyDocument;\r\n const preloader = new ProgressivePreloader({\r\n cancelable: true,\r\n tryAgainOnFail: false\r\n });\r\n\r\n const load = () => {\r\n const promise = this.setBackgroundDocument(wallpaper);\r\n const cacheContext = appDownloadManager.getCacheContext(doc);\r\n if(!cacheContext.url || this.theme.background.blur) {\r\n preloader.attach(target, true, promise);\r\n }\r\n };\r\n\r\n preloader.construct();\r\n\r\n attachClickEvent(target, (e) => {\r\n if(preloader.preloader.parentElement) {\r\n preloader.onClick(e);\r\n preloader.detach();\r\n } else {\r\n load();\r\n }\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n load();\r\n\r\n //console.log(doc);\r\n };\r\n\r\n private saveToCache = (slug: string, url: string) => {\r\n fetch(url).then(response => {\r\n appDownloadManager.cacheStorage.save('backgrounds/' + slug, response);\r\n });\r\n };\r\n\r\n private setBackgroundDocument = (wallpaper: WallPaper) => {\r\n let _tempId = ++this.tempId;\r\n const middleware = () => _tempId === this.tempId;\r\n\r\n const doc = (wallpaper as WallPaper.wallPaper).document as MyDocument;\r\n const deferred = deferredPromise<void>();\r\n let download: Promise<void> | DownloadBlob;\r\n if(doc) {\r\n download = appDocsManager.downloadDoc(doc, appImManager.chat.bubbles ? appImManager.chat.bubbles.lazyLoadQueue.queueId : 0);\r\n deferred.addNotifyListener = download.addNotifyListener;\r\n deferred.cancel = download.cancel;\r\n } else {\r\n download = Promise.resolve();\r\n }\r\n\r\n download.then(() => {\r\n if(!middleware()) {\r\n deferred.resolve();\r\n return;\r\n }\r\n\r\n const background = this.theme.background;\r\n const onReady = (url?: string) => {\r\n //const perf = performance.now();\r\n let getPixelPromise: Promise<Uint8ClampedArray>;\r\n if(url && !this.theme.background.color) {\r\n getPixelPromise = averageColor(url);\r\n } else {\r\n const {canvas} = ChatBackgroundGradientRenderer.create(this.getColorsFromWallpaper(wallpaper));\r\n getPixelPromise = Promise.resolve(averageColorFromCanvas(canvas));\r\n }\r\n\r\n getPixelPromise.then((pixel) => {\r\n if(!middleware()) {\r\n deferred.resolve();\r\n return;\r\n }\r\n \r\n const hsla = highlightningColor(Array.from(pixel) as any);\r\n // const hsla = 'rgba(0, 0, 0, 0.3)';\r\n //console.log(doc, hsla, performance.now() - perf);\r\n\r\n const slug = (wallpaper as WallPaper.wallPaper).slug ?? '';\r\n background.id = wallpaper.id;\r\n background.intensity = wallpaper.settings?.intensity ?? 0;\r\n background.color = this.getColorsFromWallpaper(wallpaper);\r\n background.slug = slug;\r\n background.highlightningColor = hsla;\r\n appStateManager.pushToState('settings', rootScope.settings);\r\n\r\n if(slug) {\r\n this.saveToCache(slug, url);\r\n }\r\n\r\n appImManager.applyCurrentTheme(slug, url, true).then(deferred.resolve);\r\n });\r\n };\r\n\r\n if(!doc) {\r\n onReady();\r\n return;\r\n }\r\n\r\n const cacheContext = appDownloadManager.getCacheContext(doc);\r\n if(background.blur) {\r\n setTimeout(() => {\r\n const {canvas, promise} = blur(cacheContext.url, 12, 4)\r\n promise.then(() => {\r\n if(!middleware()) {\r\n deferred.resolve();\r\n return;\r\n }\r\n\r\n onReady(canvas.toDataURL());\r\n });\r\n }, 200);\r\n } else {\r\n onReady(cacheContext.url);\r\n }\r\n });\r\n\r\n return deferred;\r\n };\r\n\r\n private setActive = () => {\r\n const active = this.grid.querySelector('.active');\r\n const target = this.elementsByKey.get(this.getWallpaperKeyFromTheme(this.theme));\r\n if(active === target) {\r\n return;\r\n }\r\n\r\n if(active) {\r\n active.classList.remove('active');\r\n }\r\n\r\n if(target) {\r\n target.classList.add('active');\r\n }\r\n };\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport PopupElement from \".\";\r\nimport appStickersManager, { AppStickersManager } from \"../../lib/appManagers/appStickersManager\";\r\nimport { RichTextProcessor } from \"../../lib/richtextprocessor\";\r\nimport Scrollable from \"../scrollable\";\r\nimport { wrapSticker } from \"../wrappers\";\r\nimport LazyLoadQueue from \"../lazyLoadQueue\";\r\nimport { putPreloader } from \"../misc\";\r\nimport animationIntersector from \"../animationIntersector\";\r\nimport appImManager from \"../../lib/appManagers/appImManager\";\r\nimport { StickerSet } from \"../../layer\";\r\nimport mediaSizes from \"../../helpers/mediaSizes\";\r\nimport { i18n } from \"../../lib/langPack\";\r\nimport Button from \"../button\";\r\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\r\nimport toggleDisability from \"../../helpers/dom/toggleDisability\";\r\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\r\nimport { toastNew } from \"../toast\";\r\nimport setInnerHTML from \"../../helpers/dom/setInnerHTML\";\r\n\r\nconst ANIMATION_GROUP = 'STICKERS-POPUP';\r\n\r\nexport default class PopupStickers extends PopupElement {\r\n private stickersFooter: HTMLElement;\r\n private stickersDiv: HTMLElement;\r\n private h6: HTMLElement;\r\n\r\n private set: StickerSet.stickerSet;\r\n\r\n constructor(private stickerSetInput: Parameters<AppStickersManager['getStickerSet']>[0]) {\r\n super('popup-stickers', null, {closable: true, overlayClosable: true, body: true});\r\n\r\n this.h6 = document.createElement('h6');\r\n this.h6.append(i18n('Loading'));\r\n\r\n this.header.append(this.h6);\r\n\r\n this.addEventListener('close', () => {\r\n animationIntersector.setOnlyOnePlayableGroup('');\r\n });\r\n\r\n const div = document.createElement('div');\r\n div.classList.add('sticker-set');\r\n\r\n this.stickersDiv = document.createElement('div');\r\n this.stickersDiv.classList.add('sticker-set-stickers', 'is-loading');\r\n\r\n attachClickEvent(this.stickersDiv, this.onStickersClick, {listenerSetter: this.listenerSetter});\r\n\r\n putPreloader(this.stickersDiv, true);\r\n\r\n this.stickersFooter = document.createElement('div');\r\n this.stickersFooter.classList.add('sticker-set-footer');\r\n\r\n div.append(this.stickersDiv);\r\n\r\n const btn = Button('btn-primary btn-primary-transparent disable-hover', {noRipple: true, text: 'Loading'});\r\n this.stickersFooter.append(btn);\r\n\r\n this.body.append(div);\r\n const scrollable = new Scrollable(this.body);\r\n this.body.append(this.stickersFooter);\r\n \r\n // const editButton = document.createElement('button');\r\n // editButton.classList.add('btn-primary');\r\n\r\n // this.stickersFooter.append(editButton);\r\n\r\n this.loadStickerSet();\r\n }\r\n\r\n private onStickersClick = (e: MouseEvent) => {\r\n const target = findUpClassName(e.target, 'sticker-set-sticker');\r\n if(!target) return;\r\n\r\n const fileId = target.dataset.docId;\r\n if(appImManager.chat.input.sendMessageWithDocument(fileId)) {\r\n this.hide();\r\n } else {\r\n console.warn('got no doc by id:', fileId);\r\n }\r\n };\r\n\r\n private loadStickerSet() {\r\n return appStickersManager.getStickerSet(this.stickerSetInput).then(set => {\r\n if(!set) {\r\n toastNew({langPackKey: 'StickerSet.DontExist'});\r\n this.hide();\r\n return;\r\n }\r\n //console.log('PopupStickers loadStickerSet got set:', set);\r\n\r\n this.set = set.set;\r\n\r\n animationIntersector.setOnlyOnePlayableGroup(ANIMATION_GROUP);\r\n\r\n setInnerHTML(this.h6, RichTextProcessor.wrapEmojiText(set.set.title));\r\n this.stickersFooter.classList.toggle('add', !set.set.installed_date);\r\n\r\n let button: HTMLElement;\r\n if(set.set.installed_date) {\r\n button = Button('btn-primary btn-primary-transparent danger', {noRipple: true});\r\n button.append(i18n('RemoveStickersCount', [i18n('Stickers', [set.set.count])]));\r\n } else {\r\n button = Button('btn-primary btn-color-primary', {noRipple: true});\r\n button.append(i18n('AddStickersCount', [i18n('Stickers', [set.set.count])]));\r\n }\r\n\r\n this.stickersFooter.textContent = '';\r\n this.stickersFooter.append(button);\r\n\r\n attachClickEvent(button, () => {\r\n const toggle = toggleDisability([button], true);\r\n\r\n appStickersManager.toggleStickerSet(this.set).then(() => {\r\n this.hide();\r\n }).catch(() => {\r\n toggle();\r\n });\r\n });\r\n\r\n const lazyLoadQueue = new LazyLoadQueue();\r\n \r\n this.stickersDiv.classList.remove('is-loading');\r\n this.stickersDiv.innerHTML = '';\r\n for(let doc of set.documents) {\r\n if(doc._ === 'documentEmpty') {\r\n continue;\r\n }\r\n \r\n const div = document.createElement('div');\r\n div.classList.add('sticker-set-sticker');\r\n\r\n const size = mediaSizes.active.esgSticker.width;\r\n \r\n wrapSticker({\r\n doc, \r\n div, \r\n lazyLoadQueue, \r\n group: ANIMATION_GROUP, \r\n play: true,\r\n loop: true,\r\n width: size,\r\n height: size\r\n });\r\n\r\n this.stickersDiv.append(div);\r\n }\r\n });\r\n }\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport eachTimeout from \"./eachTimeout\";\n\n// It's better to use timeout instead of interval, because interval can be corrupted\nexport default function eachMinute(callback: () => any, runFirst = true) {\n return eachTimeout(callback, () => (60 - new Date().getSeconds()) * 1000, runFirst);\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport ctx from \"../environment/ctx\";\nimport noop from \"./noop\";\n\n// It's better to use timeout instead of interval, because interval can be corrupted\nexport default function eachTimeout(callback: () => any, getNextTimeout: () => number, runFirst = true) {\n const cancel = () => {\n clearTimeout(timeout);\n };\n\n // replace callback to run noop and restore after\n const _callback = callback;\n if(!runFirst) {\n callback = noop;\n }\n\n let timeout: number;\n (function run() {\n callback();\n timeout = ctx.setTimeout(run, getNextTimeout());\n })();\n\n callback = _callback;\n\n return cancel;\n}\n","const IS_GEOLOCATION_SUPPORTED = !!navigator?.geolocation?.getCurrentPosition && false;\n\nexport default IS_GEOLOCATION_SUPPORTED;\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { SettingSection } from \"..\";\nimport appReactionsManager from \"../../../lib/appManagers/appReactionsManager\";\nimport RadioField from \"../../radioField\";\nimport Row, { RadioFormFromRows } from \"../../row\";\nimport SliderSuperTab from \"../../sliderTab\";\nimport { wrapStickerToRow } from \"../../wrappers\";\n\nexport default class AppQuickReactionTab extends SliderSuperTab {\n protected init() {\n this.header.classList.add('with-border');\n this.setTitle('DoubleTapSetting');\n this.container.classList.add('quick-reaction-container');\n\n return Promise.all([\n appReactionsManager.getQuickReaction(),\n appReactionsManager.getAvailableReactions()\n ]).then(([quickReaction, availableReactions]) => {\n availableReactions = availableReactions.filter(reaction => !reaction.pFlags.inactive);\n\n const section = new SettingSection();\n\n const name = 'quick-reaction';\n const rows = availableReactions.map((availableReaction) => {\n const radioField = new RadioField({\n name,\n text: availableReaction.title,\n value: availableReaction.reaction,\n alignRight: true\n });\n\n const row = new Row({\n radioField,\n havePadding: true\n });\n\n radioField.main.classList.add('quick-reaction-title');\n\n wrapStickerToRow({\n row,\n doc: availableReaction.static_icon,\n size: 'small'\n });\n\n if(availableReaction === quickReaction) {\n radioField.setValueSilently(true);\n }\n\n return row;\n });\n\n const form = RadioFormFromRows(rows, (value) => {\n appReactionsManager.setDefaultReaction(value);\n });\n\n section.content.append(form);\n this.scrollable.append(section.container);\n });\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { generateSection, SettingSection } from \"..\";\r\nimport RangeSelector from \"../../rangeSelector\";\r\nimport Button from \"../../button\";\r\nimport CheckboxField from \"../../checkboxField\";\r\nimport RadioField from \"../../radioField\";\r\nimport appStateManager, { State } from \"../../../lib/appManagers/appStateManager\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport { IS_APPLE } from \"../../../environment/userAgent\";\r\nimport Row from \"../../row\";\r\nimport AppBackgroundTab from \"./background\";\r\nimport { LangPackKey, _i18n } from \"../../../lib/langPack\";\r\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\r\nimport appStickersManager from \"../../../lib/appManagers/appStickersManager\";\r\nimport assumeType from \"../../../helpers/assumeType\";\r\nimport { MessagesAllStickers, StickerSet } from \"../../../layer\";\r\nimport RichTextProcessor from \"../../../lib/richtextprocessor\";\r\nimport { wrapStickerSetThumb, wrapStickerToRow } from \"../../wrappers\";\r\nimport LazyLoadQueue from \"../../lazyLoadQueue\";\r\nimport PopupStickers from \"../../popups/stickers\";\r\nimport eachMinute from \"../../../helpers/eachMinute\";\r\nimport { SliderSuperTabEventable } from \"../../sliderTab\";\r\nimport IS_GEOLOCATION_SUPPORTED from \"../../../environment/geolocationSupport\";\r\nimport appReactionsManager from \"../../../lib/appManagers/appReactionsManager\";\r\nimport AppQuickReactionTab from \"./quickReaction\";\r\n\r\nexport class RangeSettingSelector {\r\n public container: HTMLDivElement;\r\n public valueContainer: HTMLElement;\r\n private range: RangeSelector;\r\n\r\n public onChange: (value: number) => void;\r\n\r\n constructor(\r\n name: LangPackKey, \r\n step: number, \r\n initialValue: number, \r\n minValue: number, \r\n maxValue: number,\r\n writeValue = true\r\n ) {\r\n const BASE_CLASS = 'range-setting-selector';\r\n this.container = document.createElement('div');\r\n this.container.classList.add(BASE_CLASS);\r\n\r\n const details = document.createElement('div');\r\n details.classList.add(BASE_CLASS + '-details');\r\n\r\n const nameDiv = document.createElement('div');\r\n nameDiv.classList.add(BASE_CLASS + '-name');\r\n _i18n(nameDiv, name);\r\n\r\n const valueDiv = this.valueContainer = document.createElement('div');\r\n valueDiv.classList.add(BASE_CLASS + '-value');\r\n\r\n if(writeValue) {\r\n valueDiv.innerHTML = '' + initialValue;\r\n }\r\n\r\n details.append(nameDiv, valueDiv);\r\n\r\n this.range = new RangeSelector({\r\n step, \r\n min: minValue, \r\n max: maxValue\r\n }, initialValue);\r\n this.range.setListeners();\r\n this.range.setHandlers({\r\n onScrub: value => {\r\n if(this.onChange) {\r\n this.onChange(value);\r\n }\r\n\r\n if(writeValue) {\r\n //console.log('font size scrub:', value);\r\n valueDiv.innerText = '' + value;\r\n }\r\n }\r\n });\r\n\r\n this.container.append(details, this.range.container);\r\n }\r\n}\r\n\r\nexport default class AppGeneralSettingsTab extends SliderSuperTabEventable {\r\n init() {\r\n this.header.classList.add('with-border');\r\n this.container.classList.add('general-settings-container');\r\n this.setTitle('General');\r\n\r\n const section = generateSection.bind(null, this.scrollable);\r\n\r\n {\r\n const container = section('Settings');\r\n \r\n const range = new RangeSettingSelector('TextSize', 1, rootScope.settings.messagesTextSize, 12, 20);\r\n range.onChange = (value) => {\r\n appStateManager.setByKey('settings.messagesTextSize', value);\r\n };\r\n\r\n const chatBackgroundButton = Button('btn-primary btn-transparent', {icon: 'image', text: 'ChatBackground'});\r\n\r\n attachClickEvent(chatBackgroundButton, () => {\r\n new AppBackgroundTab(this.slider).open();\r\n });\r\n\r\n const animationsCheckboxField = new CheckboxField({\r\n text: 'EnableAnimations', \r\n name: 'animations', \r\n stateKey: 'settings.animationsEnabled',\r\n withRipple: true\r\n });\r\n \r\n container.append(range.container, chatBackgroundButton, animationsCheckboxField.label);\r\n }\r\n\r\n {\r\n const container = section('General.Keyboard');\r\n\r\n const form = document.createElement('form');\r\n\r\n const name = 'send-shortcut';\r\n const stateKey = 'settings.sendShortcut';\r\n\r\n const enterRow = new Row({\r\n radioField: new RadioField({\r\n langKey: 'General.SendShortcut.Enter', \r\n name, \r\n value: 'enter', \r\n stateKey\r\n }),\r\n subtitleLangKey: 'General.SendShortcut.NewLine.ShiftEnter'\r\n });\r\n\r\n const ctrlEnterRow = new Row({\r\n radioField: new RadioField({\r\n name,\r\n value: 'ctrlEnter', \r\n stateKey\r\n }),\r\n subtitleLangKey: 'General.SendShortcut.NewLine.Enter'\r\n });\r\n _i18n(ctrlEnterRow.radioField.main, 'General.SendShortcut.CtrlEnter', [IS_APPLE ? '⌘' : 'Ctrl']);\r\n \r\n form.append(enterRow.container, ctrlEnterRow.container);\r\n container.append(form);\r\n }\r\n\r\n if(IS_GEOLOCATION_SUPPORTED) {\r\n const container = section('DistanceUnitsTitle');\r\n\r\n const form = document.createElement('form');\r\n\r\n const name = 'distance-unit';\r\n const stateKey = 'settings.distanceUnit';\r\n\r\n const kilometersRow = new Row({\r\n radioField: new RadioField({\r\n langKey: 'DistanceUnitsKilometers', \r\n name, \r\n value: 'kilometers', \r\n stateKey\r\n })\r\n });\r\n\r\n const milesRow = new Row({\r\n radioField: new RadioField({\r\n langKey: 'DistanceUnitsMiles',\r\n name,\r\n value: 'miles', \r\n stateKey\r\n })\r\n });\r\n \r\n form.append(kilometersRow.container, milesRow.container);\r\n container.append(form);\r\n }\r\n\r\n {\r\n const container = section('General.TimeFormat');\r\n\r\n const form = document.createElement('form');\r\n\r\n const name = 'time-format';\r\n const stateKey = 'settings.timeFormat';\r\n\r\n const formats: [State['settings']['timeFormat'], LangPackKey][] = [\r\n ['h12', 'General.TimeFormat.h12'], \r\n ['h23', 'General.TimeFormat.h23']\r\n ];\r\n\r\n const rows = formats.map(([format, langPackKey]) => {\r\n const row = new Row({\r\n radioField: new RadioField({\r\n langKey: langPackKey, \r\n name, \r\n value: format, \r\n stateKey\r\n })\r\n });\r\n\r\n return row;\r\n });\r\n\r\n const cancel = eachMinute(() => {\r\n const date = new Date();\r\n\r\n formats.forEach(([format], idx) => {\r\n const str = date.toLocaleTimeString(\"en-us-u-hc-\" + format, {\r\n hour: '2-digit', \r\n minute: '2-digit'\r\n });\r\n\r\n rows[idx].subtitle.textContent = str;\r\n });\r\n });\r\n\r\n this.eventListener.addEventListener('destroy', cancel);\r\n\r\n form.append(...rows.map(row => row.container));\r\n container.append(form);\r\n }\r\n\r\n {\r\n const container = section('Emoji');\r\n\r\n const suggestCheckboxField = new CheckboxField({\r\n text: 'GeneralSettings.EmojiPrediction', \r\n name: 'suggest-emoji', \r\n stateKey: 'settings.emoji.suggest',\r\n withRipple: true\r\n });\r\n const bigCheckboxField = new CheckboxField({\r\n text: 'GeneralSettings.BigEmoji', \r\n name: 'emoji-big', \r\n stateKey: 'settings.emoji.big',\r\n withRipple: true\r\n });\r\n\r\n container.append(suggestCheckboxField.label, bigCheckboxField.label);\r\n }\r\n \r\n {\r\n const section = new SettingSection({name: 'Telegram.InstalledStickerPacksController', caption: 'StickersBotInfo'});\r\n\r\n const reactionsRow = new Row({\r\n titleLangKey: 'DoubleTapSetting',\r\n havePadding: true,\r\n clickable: () => {\r\n new AppQuickReactionTab(this.slider).open();\r\n }\r\n });\r\n\r\n const renderQuickReaction = () => {\r\n Promise.resolve(appReactionsManager.getQuickReaction()).then(reaction => {\r\n wrapStickerToRow({\r\n row: reactionsRow,\r\n doc: reaction.static_icon,\r\n size: 'small'\r\n });\r\n });\r\n };\r\n\r\n renderQuickReaction();\r\n\r\n this.listenerSetter.add(rootScope)('quick_reaction', renderQuickReaction);\r\n\r\n const suggestCheckboxField = new CheckboxField({\r\n text: 'Stickers.SuggestStickers', \r\n name: 'suggest', \r\n stateKey: 'settings.stickers.suggest',\r\n withRipple: true\r\n });\r\n const loopCheckboxField = new CheckboxField({\r\n text: 'InstalledStickers.LoopAnimated', \r\n name: 'loop', \r\n stateKey: 'settings.stickers.loop',\r\n withRipple: true\r\n });\r\n\r\n const stickerSets: {[id: string]: Row} = {};\r\n\r\n const stickersContent = section.generateContentElement();\r\n\r\n const lazyLoadQueue = new LazyLoadQueue();\r\n const renderStickerSet = (stickerSet: StickerSet.stickerSet, method: 'append' | 'prepend' = 'append') => {\r\n const row = new Row({\r\n title: RichTextProcessor.wrapEmojiText(stickerSet.title),\r\n subtitleLangKey: 'Stickers',\r\n subtitleLangArgs: [stickerSet.count],\r\n havePadding: true,\r\n clickable: () => {\r\n new PopupStickers({id: stickerSet.id, access_hash: stickerSet.access_hash}).show();\r\n }\r\n });\r\n\r\n stickerSets[stickerSet.id] = row;\r\n\r\n const div = document.createElement('div');\r\n div.classList.add('row-media');\r\n\r\n wrapStickerSetThumb({\r\n set: stickerSet,\r\n container: div,\r\n group: 'GENERAL-SETTINGS',\r\n lazyLoadQueue,\r\n width: 48,\r\n height: 48,\r\n autoplay: true\r\n });\r\n\r\n row.container.append(div);\r\n\r\n stickersContent[method](row.container);\r\n };\r\n\r\n appStickersManager.getAllStickers().then(allStickers => {\r\n assumeType<MessagesAllStickers.messagesAllStickers>(allStickers);\r\n for(const stickerSet of allStickers.sets) {\r\n renderStickerSet(stickerSet);\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('stickers_installed', (e) => {\r\n const set: StickerSet.stickerSet = e;\r\n \r\n if(!stickerSets[set.id]) {\r\n renderStickerSet(set, 'prepend');\r\n }\r\n });\r\n \r\n this.listenerSetter.add(rootScope)('stickers_deleted', (e) => {\r\n const set: StickerSet.stickerSet = e;\r\n \r\n if(stickerSets[set.id]) {\r\n stickerSets[set.id].container.remove();\r\n delete stickerSets[set.id];\r\n }\r\n });\r\n\r\n section.content.append(reactionsRow.container, suggestCheckboxField.label, loopCheckboxField.label);\r\n this.scrollable.append(section.container);\r\n }\r\n }\r\n\r\n onOpen() {\r\n if(this.init) {\r\n this.init();\r\n this.init = null;\r\n }\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport appProfileManager from \"../../../lib/appManagers/appProfileManager\";\r\nimport appUsersManager from \"../../../lib/appManagers/appUsersManager\";\r\nimport InputField from \"../../inputField\";\r\nimport { SliderSuperTab } from \"../../slider\";\r\nimport EditPeer from \"../../editPeer\";\r\nimport { UsernameInputField } from \"../../usernameInputField\";\r\nimport { i18n, i18n_ } from \"../../../lib/langPack\";\r\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport { generateSection, SettingSection } from \"..\";\r\n\r\n// TODO: аватарка не поменяется в этой вкладке после изменения почему-то (если поставить в другом клиенте, и потом тут проверить, для этого ещё вышел в чатлист)\r\n\r\nexport default class AppEditProfileTab extends SliderSuperTab {\r\n private firstNameInputField: InputField;\r\n private lastNameInputField: InputField;\r\n private bioInputField: InputField;\r\n private usernameInputField: InputField;\r\n \r\n private profileUrlContainer: HTMLDivElement;\r\n private profileUrlAnchor: HTMLAnchorElement;\r\n\r\n private editPeer: EditPeer;\r\n\r\n protected async init() {\r\n this.container.classList.add('edit-profile-container');\r\n this.setTitle('EditAccount.Title');\r\n\r\n const inputFields: InputField[] = [];\r\n\r\n {\r\n const section = generateSection(this.scrollable, undefined, 'Bio.Description');\r\n const inputWrapper = document.createElement('div');\r\n inputWrapper.classList.add('input-wrapper');\r\n \r\n this.firstNameInputField = new InputField({\r\n label: 'EditProfile.FirstNameLabel',\r\n name: 'first-name',\r\n maxLength: 70\r\n });\r\n this.lastNameInputField = new InputField({\r\n label: 'Login.Register.LastName.Placeholder',\r\n name: 'last-name',\r\n maxLength: 64\r\n });\r\n this.bioInputField = new InputField({\r\n label: 'EditProfile.BioLabel',\r\n name: 'bio',\r\n maxLength: 70\r\n });\r\n \r\n inputWrapper.append(this.firstNameInputField.container, this.lastNameInputField.container, this.bioInputField.container);\r\n \r\n const caption = document.createElement('div');\r\n caption.classList.add('caption');\r\n i18n_({element: caption, key: 'Bio.Description'});\r\n\r\n inputFields.push(this.firstNameInputField, this.lastNameInputField, this.bioInputField);\r\n\r\n this.editPeer = new EditPeer({\r\n peerId: rootScope.myId,\r\n inputFields,\r\n listenerSetter: this.listenerSetter\r\n });\r\n\r\n this.content.append(this.editPeer.nextBtn);\r\n\r\n section.append(this.editPeer.avatarEdit.container, inputWrapper);\r\n }\r\n\r\n {\r\n const section = new SettingSection({\r\n name: 'EditAccount.Username',\r\n caption: true\r\n });\r\n\r\n const inputWrapper = document.createElement('div');\r\n inputWrapper.classList.add('input-wrapper');\r\n\r\n this.usernameInputField = new UsernameInputField({\r\n label: 'EditProfile.Username.Label',\r\n name: 'username',\r\n plainText: true,\r\n listenerSetter: this.listenerSetter,\r\n onChange: () => {\r\n this.editPeer.handleChange();\r\n this.setProfileUrl();\r\n },\r\n availableText: 'EditProfile.Username.Available',\r\n takenText: 'EditProfile.Username.Taken',\r\n invalidText: 'EditProfile.Username.Invalid'\r\n });\r\n\r\n inputWrapper.append(this.usernameInputField.container);\r\n\r\n const caption = section.caption;\r\n caption.append(i18n('UsernameSettings.ChangeDescription'));\r\n caption.append(document.createElement('br'), document.createElement('br'));\r\n\r\n const profileUrlContainer = this.profileUrlContainer = document.createElement('div');\r\n profileUrlContainer.classList.add('profile-url-container');\r\n \r\n const profileUrlAnchor = this.profileUrlAnchor = document.createElement('a');\r\n profileUrlAnchor.classList.add('profile-url');\r\n profileUrlAnchor.href = '#';\r\n profileUrlAnchor.target = '_blank';\r\n\r\n profileUrlContainer.append(i18n('UsernameHelpLink', [profileUrlAnchor]));\r\n\r\n caption.append(profileUrlContainer);\r\n\r\n inputFields.push(this.usernameInputField);\r\n section.content.append(inputWrapper);\r\n this.scrollable.append(section.container);\r\n }\r\n\r\n attachClickEvent(this.editPeer.nextBtn, () => {\r\n this.editPeer.nextBtn.disabled = true;\r\n\r\n let promises: Promise<any>[] = [];\r\n \r\n promises.push(appProfileManager.updateProfile(this.firstNameInputField.value, this.lastNameInputField.value, this.bioInputField.value).then(() => {\r\n this.close();\r\n }, (err) => {\r\n console.error('updateProfile error:', err);\r\n }));\r\n\r\n if(this.editPeer.uploadAvatar) {\r\n promises.push(this.editPeer.uploadAvatar().then(inputFile => {\r\n return appProfileManager.uploadProfilePhoto(inputFile);\r\n }));\r\n }\r\n\r\n if(this.usernameInputField.isValidToChange()) {\r\n promises.push(appUsersManager.updateUsername(this.usernameInputField.value));\r\n }\r\n\r\n Promise.race(promises).finally(() => {\r\n this.editPeer.nextBtn.removeAttribute('disabled');\r\n });\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n const user = appUsersManager.getSelf();\r\n\r\n const userFull = await appProfileManager.getProfile(user.id, true);\r\n\r\n this.firstNameInputField.setOriginalValue(user.first_name, true);\r\n this.lastNameInputField.setOriginalValue(user.last_name, true);\r\n this.bioInputField.setOriginalValue(userFull.about, true);\r\n this.usernameInputField.setOriginalValue(user.username, true);\r\n\r\n this.setProfileUrl();\r\n this.editPeer.handleChange();\r\n }\r\n\r\n private setProfileUrl() {\r\n if(this.usernameInputField.input.classList.contains('error') || !this.usernameInputField.value.length) {\r\n this.profileUrlContainer.style.display = 'none';\r\n } else {\r\n this.profileUrlContainer.style.display = '';\r\n let url = 'https://t.me/' + this.usernameInputField.value;\r\n this.profileUrlAnchor.innerText = url;\r\n this.profileUrlAnchor.href = url;\r\n }\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTab } from \"../../slider\";\r\nimport AppSelectPeers from \"../../appSelectPeers\";\r\nimport appDialogsManager from \"../../../lib/appManagers/appDialogsManager\";\r\nimport appUsersManager from \"../../../lib/appManagers/appUsersManager\";\r\nimport { MyDialogFilter as DialogFilter } from \"../../../lib/storages/filters\";\r\nimport ButtonIcon from \"../../buttonIcon\";\r\nimport CheckboxField from \"../../checkboxField\";\r\nimport Button from \"../../button\";\r\nimport AppEditFolderTab from \"./editFolder\";\r\nimport I18n, { i18n, LangPackKey, _i18n, join } from \"../../../lib/langPack\";\r\nimport appMessagesManager from \"../../../lib/appManagers/appMessagesManager\";\r\nimport RichTextProcessor from \"../../../lib/richtextprocessor\";\r\nimport { SettingSection } from \"..\";\r\nimport { toast } from \"../../toast\";\r\nimport appPeersManager from \"../../../lib/appManagers/appPeersManager\";\r\nimport copy from \"../../../helpers/object/copy\";\r\nimport forEachReverse from \"../../../helpers/array/forEachReverse\";\r\nimport setInnerHTML from \"../../../helpers/dom/setInnerHTML\";\r\n\r\nexport default class AppIncludedChatsTab extends SliderSuperTab {\r\n private editFolderTab: AppEditFolderTab;\r\n private confirmBtn: HTMLElement;\r\n\r\n private selector: AppSelectPeers;\r\n private type: 'included' | 'excluded';\r\n private filter: DialogFilter;\r\n private originalFilter: DialogFilter;\r\n\r\n private dialogsByFilters: Map<DialogFilter, Set<PeerId>>;\r\n\r\n protected init() {\r\n this.content.remove();\r\n this.container.classList.add('included-chatlist-container');\r\n this.confirmBtn = ButtonIcon('check btn-confirm blue', {noRipple: true});\r\n this.confirmBtn.style.display = 'none';\r\n\r\n this.header.append(this.confirmBtn);\r\n\r\n this.confirmBtn.addEventListener('click', () => {\r\n const selected = this.selector.getSelected();\r\n\r\n //this.filter.pFlags = {};\r\n\r\n if(this.type === 'included') {\r\n for(const key in this.filter.pFlags) {\r\n if(key.indexOf('exclude_') === 0) {\r\n continue;\r\n }\r\n\r\n // @ts-ignore\r\n delete this.filter.pFlags[key];\r\n }\r\n } else {\r\n for(const key in this.filter.pFlags) {\r\n if(key.indexOf('exclude_') !== 0) {\r\n continue;\r\n }\r\n\r\n // @ts-ignore\r\n delete this.filter.pFlags[key];\r\n }\r\n }\r\n\r\n const peerIds: PeerId[] = [];\r\n for(const key of selected) {\r\n if(key.isPeerId()) {\r\n peerIds.push(key.toPeerId());\r\n } else {\r\n // @ts-ignore\r\n this.filter.pFlags[key] = true;\r\n }\r\n }\r\n\r\n let cmp: (peerId: PeerId) => boolean;\r\n if(this.type === 'included') {\r\n cmp = (peerId) => peerIds.includes(peerId);\r\n } else {\r\n cmp = (peerId) => !peerIds.includes(peerId);\r\n }\r\n\r\n forEachReverse(this.filter.pinnedPeerIds, (peerId, idx) => {\r\n if(!cmp(peerId)) {\r\n this.filter.pinnedPeerIds.splice(idx, 1);\r\n this.filter.pinned_peers.splice(idx, 1);\r\n }\r\n });\r\n\r\n const other = this.type === 'included' ? 'excludePeerIds' : 'includePeerIds';\r\n const otherLegacy = this.type === 'included' ? 'exclude_peers' : 'include_peers';\r\n forEachReverse(this.filter[other], (peerId, idx) => {\r\n if(peerIds.includes(peerId)) {\r\n this.filter[other].splice(idx, 1);\r\n this.filter[otherLegacy].splice(idx, 1);\r\n }\r\n });\r\n \r\n this.filter[this.type === 'included' ? 'includePeerIds' : 'excludePeerIds'] = peerIds;\r\n this.filter[this.type === 'included' ? 'include_peers' : 'exclude_peers'] = peerIds.map(peerId => appPeersManager.getInputPeerById(peerId));\r\n //this.filter.pinned_peers = this.filter.pinned_peers.filter(peerId => this.filter.include_peers.includes(peerId));\r\n\r\n this.editFolderTab.setFilter(this.filter, false);\r\n this.close();\r\n });\r\n\r\n this.dialogsByFilters = new Map();\r\n return appMessagesManager.filtersStorage.getDialogFilters().then(filters => {\r\n for(const filter of filters) {\r\n this.dialogsByFilters.set(filter, new Set(appMessagesManager.dialogsStorage.getFolderDialogs(filter.id).map(d => d.peerId)));\r\n }\r\n });\r\n }\r\n\r\n checkbox(selected?: boolean) {\r\n const checkboxField = new CheckboxField({\r\n round: true\r\n });\r\n if(selected) {\r\n checkboxField.input.checked = selected;\r\n }\r\n\r\n return checkboxField.label;\r\n }\r\n\r\n renderResults = async(peerIds: PeerId[]) => {\r\n //const other = this.type === 'included' ? this.filter.exclude_peers : this.filter.include_peers;\r\n\r\n await appUsersManager.getContacts();\r\n peerIds.forEach(peerId => {\r\n //if(other.includes(peerId)) return;\r\n\r\n const {dom} = appDialogsManager.addDialogNew({\r\n dialog: peerId,\r\n container: this.selector.scrollable,\r\n drawStatus: false,\r\n rippleEnabled: true,\r\n avatarSize: 46\r\n });\r\n\r\n const selected = this.selector.selected.has(peerId);\r\n dom.containerEl.append(this.checkbox(selected));\r\n //if(selected) dom.listEl.classList.add('active');\r\n\r\n const foundInFilters: HTMLElement[] = [];\r\n this.dialogsByFilters.forEach((dialogs, filter) => {\r\n if(dialogs.has(peerId)) {\r\n const span = document.createElement('span');\r\n setInnerHTML(span, RichTextProcessor.wrapEmojiText(filter.title));\r\n foundInFilters.push(span);\r\n }\r\n });\r\n\r\n const joined = join(foundInFilters, false);\r\n joined.forEach(el => {\r\n dom.lastMessageSpan.append(el);\r\n });\r\n });\r\n };\r\n\r\n onOpen() {\r\n if(this.init) {\r\n this.init();\r\n this.init = null;\r\n }\r\n\r\n this.confirmBtn.style.display = this.type === 'excluded' ? '' : 'none';\r\n this.setTitle(this.type === 'included' ? 'FilterAlwaysShow' : 'FilterNeverShow');\r\n\r\n const filter = this.filter;\r\n\r\n const categoriesSection = new SettingSection({\r\n noDelimiter: true,\r\n name: 'FilterChatTypes'\r\n });\r\n\r\n categoriesSection.container.classList.add('folder-categories');\r\n\r\n let details: {[flag: string]: {ico: string, text: LangPackKey}};\r\n if(this.type === 'excluded') {\r\n details = {\r\n exclude_muted: {ico: 'mute', text: 'ChatList.Filter.MutedChats'},\r\n exclude_archived: {ico: 'archive', text: 'ChatList.Filter.Archive'},\r\n exclude_read: {ico: 'readchats', text: 'ChatList.Filter.ReadChats'}\r\n };\r\n } else {\r\n details = {\r\n contacts: {ico: 'newprivate', text: 'ChatList.Filter.Contacts'},\r\n non_contacts: {ico: 'noncontacts', text: 'ChatList.Filter.NonContacts'},\r\n groups: {ico: 'group', text: 'ChatList.Filter.Groups'},\r\n broadcasts: {ico: 'newchannel', text: 'ChatList.Filter.Channels'},\r\n bots: {ico: 'bots', text: 'ChatList.Filter.Bots'}\r\n };\r\n }\r\n\r\n const f = document.createDocumentFragment();\r\n for(const key in details) {\r\n const button = Button('btn-primary btn-transparent folder-category-button', {icon: details[key].ico, text: details[key].text});\r\n button.dataset.peerId = key;\r\n button.append(this.checkbox());\r\n f.append(button);\r\n }\r\n categoriesSection.content.append(f);\r\n\r\n /////////////////\r\n\r\n const selectedPeers = (this.type === 'included' ? filter.includePeerIds : filter.excludePeerIds).slice();\r\n\r\n this.selector = new AppSelectPeers({\r\n appendTo: this.container, \r\n onChange: this.onSelectChange, \r\n peerType: ['dialogs'], \r\n renderResultsFunc: this.renderResults,\r\n placeholder: 'Search',\r\n sectionNameLangPackKey: 'FilterChats'\r\n });\r\n this.selector.selected = new Set(selectedPeers);\r\n\r\n let addedInitial = false;\r\n const _add = this.selector.add.bind(this.selector);\r\n this.selector.add = (peerId, title, scroll) => {\r\n if(this.selector.selected.size >= 100 && addedInitial && !details[peerId]) {\r\n const el: HTMLInputElement = this.selector.list.querySelector(`[data-peer-id=\"${peerId}\"] [type=\"checkbox\"]`);\r\n if(el) {\r\n setTimeout(() => {\r\n el.checked = false;\r\n }, 0);\r\n }\r\n\r\n const str = I18n.format(this.type === 'excluded' ? 'ChatList.Filter.Exclude.LimitReached': 'ChatList.Filter.Include.LimitReached', true);\r\n toast(str);\r\n return;\r\n }\r\n\r\n const div = _add(peerId, details[peerId] ? i18n(details[peerId].text) : undefined, scroll);\r\n if(details[peerId]) {\r\n div.querySelector('avatar-element').classList.add('tgico-' + details[peerId].ico);\r\n }\r\n return div;\r\n };\r\n\r\n this.selector.scrollable.container.append(categoriesSection.container, this.selector.scrollable.container.lastElementChild);\r\n\r\n this.selector.addInitial(selectedPeers);\r\n addedInitial = true;\r\n\r\n for(const flag in filter.pFlags) {\r\n // @ts-ignore\r\n if(details.hasOwnProperty(flag) && !!filter.pFlags[flag]) {\r\n (categoriesSection.content.querySelector(`[data-peer-id=\"${flag}\"]`) as HTMLElement).click();\r\n }\r\n }\r\n }\r\n\r\n onSelectChange = (length: number) => {\r\n //const changed = !deepEqual(this.filter, this.originalFilter);\r\n if(this.type === 'included') {\r\n this.confirmBtn.style.display = length ? '' : 'none';\r\n }\r\n };\r\n\r\n onCloseAfterTimeout() {\r\n if(this.selector) {\r\n this.selector.container.remove();\r\n this.selector = null;\r\n }\r\n\r\n return super.onCloseAfterTimeout();\r\n }\r\n\r\n /**\r\n * Do not ignore arguments!\r\n */\r\n public open(filter?: DialogFilter, type?: 'included' | 'excluded', editFolderTab?: AppIncludedChatsTab['editFolderTab']) {\r\n this.originalFilter = filter;\r\n this.filter = copy(this.originalFilter);\r\n this.type = type;\r\n this.editFolderTab = editFolderTab;\r\n \r\n return super.open();\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport appDialogsManager from \"../../../lib/appManagers/appDialogsManager\";\r\nimport { MyDialogFilter as DialogFilter } from \"../../../lib/storages/filters\";\r\nimport lottieLoader, { LottieLoader } from \"../../../lib/rlottie/lottieLoader\";\r\nimport { SliderSuperTab } from \"../../slider\";\r\nimport { toast } from \"../../toast\";\r\nimport appMessagesManager from \"../../../lib/appManagers/appMessagesManager\";\r\nimport InputField from \"../../inputField\";\r\nimport RichTextProcessor from \"../../../lib/richtextprocessor\";\r\nimport ButtonIcon from \"../../buttonIcon\";\r\nimport ButtonMenuToggle from \"../../buttonMenuToggle\";\r\nimport { ButtonMenuItemOptions } from \"../../buttonMenu\";\r\nimport Button from \"../../button\";\r\nimport AppIncludedChatsTab from \"./includedChats\";\r\nimport { i18n, i18n_, LangPackKey } from \"../../../lib/langPack\";\r\nimport { SettingSection } from \"..\";\r\nimport PopupPeer from \"../../popups/peer\";\r\nimport RLottiePlayer from \"../../../lib/rlottie/rlottiePlayer\";\r\nimport copy from \"../../../helpers/object/copy\";\r\nimport deepEqual from \"../../../helpers/object/deepEqual\";\r\nimport appUsersManager from \"../../../lib/appManagers/appUsersManager\";\r\nimport forEachReverse from \"../../../helpers/array/forEachReverse\";\r\nimport documentFragmentToHTML from \"../../../helpers/dom/documentFragmentToHTML\";\r\n\r\nconst MAX_FOLDER_NAME_LENGTH = 12;\r\n\r\nexport default class AppEditFolderTab extends SliderSuperTab {\r\n private caption: HTMLElement;\r\n private stickerContainer: HTMLElement;\r\n\r\n private confirmBtn: HTMLElement;\r\n private menuBtn: HTMLElement;\r\n private nameInputField: InputField;\r\n\r\n private includePeerIds: SettingSection;\r\n private excludePeerIds: SettingSection;\r\n private flags: {[k in 'contacts' | 'non_contacts' | 'groups' | 'broadcasts' | 'bots' | 'exclude_muted' | 'exclude_archived' | 'exclude_read']: HTMLElement} = {} as any;\r\n\r\n private animation: RLottiePlayer;\r\n private filter: DialogFilter;\r\n private originalFilter: DialogFilter;\r\n\r\n private type: 'edit' | 'create';\r\n private loadAnimationPromise: ReturnType<LottieLoader['waitForFirstFrame']>;\r\n\r\n protected init() {\r\n this.container.classList.add('edit-folder-container');\r\n this.caption = document.createElement('div');\r\n this.caption.classList.add('caption');\r\n this.caption.append(i18n('FilterIncludeExcludeInfo'));\r\n this.stickerContainer = document.createElement('div');\r\n this.stickerContainer.classList.add('sticker-container');\r\n\r\n this.confirmBtn = ButtonIcon('check btn-confirm hide blue');\r\n const deleteFolderButton: ButtonMenuItemOptions = {\r\n icon: 'delete danger',\r\n text: 'FilterMenuDelete',\r\n onClick: () => {\r\n new PopupPeer('filter-delete', {\r\n titleLangKey: 'ChatList.Filter.Confirm.Remove.Header',\r\n descriptionLangKey: 'ChatList.Filter.Confirm.Remove.Text',\r\n buttons: [{\r\n langKey: 'Delete',\r\n callback: () => {\r\n deleteFolderButton.element.setAttribute('disabled', 'true');\r\n appMessagesManager.filtersStorage.updateDialogFilter(this.filter, true).then(bool => {\r\n if(bool) {\r\n this.close();\r\n }\r\n }).finally(() => {\r\n deleteFolderButton.element.removeAttribute('disabled');\r\n });\r\n },\r\n isDanger: true\r\n }]\r\n }).show();\r\n }\r\n };\r\n this.menuBtn = ButtonMenuToggle({}, 'bottom-left', [deleteFolderButton]);\r\n this.menuBtn.classList.add('hide');\r\n\r\n this.header.append(this.confirmBtn, this.menuBtn);\r\n\r\n const inputSection = new SettingSection({});\r\n\r\n const inputWrapper = document.createElement('div');\r\n inputWrapper.classList.add('input-wrapper');\r\n \r\n this.nameInputField = new InputField({\r\n label: 'FilterNameHint',\r\n maxLength: MAX_FOLDER_NAME_LENGTH\r\n });\r\n\r\n inputWrapper.append(this.nameInputField.container);\r\n inputSection.content.append(inputWrapper);\r\n\r\n const generateList = (className: string, h2Text: LangPackKey, buttons: {icon: string, name?: string, withRipple?: true, text: LangPackKey}[], to: any) => {\r\n const section = new SettingSection({\r\n name: h2Text,\r\n noDelimiter: true\r\n });\r\n\r\n section.container.classList.add('folder-list', className);\r\n\r\n const categories = section.generateContentElement();\r\n categories.classList.add('folder-categories');\r\n\r\n buttons.forEach(o => {\r\n const button = Button('folder-category-button btn btn-primary btn-transparent', {\r\n icon: o.icon,\r\n text: o.text,\r\n noRipple: o.withRipple ? undefined : true\r\n });\r\n\r\n if(o.name) {\r\n to[o.name] = button;\r\n }\r\n\r\n categories.append(button);\r\n });\r\n\r\n return section;\r\n };\r\n\r\n this.includePeerIds = generateList('folder-list-included', 'FilterInclude', [{\r\n icon: 'add primary',\r\n text: 'ChatList.Filter.Include.AddChat',\r\n withRipple: true\r\n }, {\r\n text: 'ChatList.Filter.Contacts',\r\n icon: 'newprivate',\r\n name: 'contacts'\r\n }, {\r\n text: 'ChatList.Filter.NonContacts',\r\n icon: 'noncontacts',\r\n name: 'non_contacts'\r\n }, {\r\n text: 'ChatList.Filter.Groups',\r\n icon: 'group',\r\n name: 'groups'\r\n }, {\r\n text: 'ChatList.Filter.Channels',\r\n icon: 'channel',\r\n name: 'broadcasts'\r\n }, {\r\n text: 'ChatList.Filter.Bots',\r\n icon: 'bots',\r\n name: 'bots'\r\n }], this.flags);\r\n\r\n this.excludePeerIds = generateList('folder-list-excluded', 'FilterExclude', [{\r\n icon: 'minus primary',\r\n text: 'ChatList.Filter.Exclude.AddChat',\r\n withRipple: true\r\n }, {\r\n text: 'ChatList.Filter.MutedChats',\r\n icon: 'mute',\r\n name: 'exclude_muted'\r\n }, {\r\n text: 'ChatList.Filter.Archive',\r\n icon: 'archive',\r\n name: 'exclude_archived'\r\n }, {\r\n text: 'ChatList.Filter.ReadChats',\r\n icon: 'readchats',\r\n name: 'exclude_read'\r\n }], this.flags);\r\n\r\n this.scrollable.append(this.stickerContainer, this.caption, inputSection.container, this.includePeerIds.container, this.excludePeerIds.container);\r\n\r\n const includedFlagsContainer = this.includePeerIds.container.querySelector('.folder-categories');\r\n const excludedFlagsContainer = this.excludePeerIds.container.querySelector('.folder-categories');\r\n\r\n includedFlagsContainer.querySelector('.btn').addEventListener('click', () => {\r\n new AppIncludedChatsTab(this.slider).open(this.filter, 'included', this);\r\n });\r\n\r\n excludedFlagsContainer.querySelector('.btn').addEventListener('click', () => {\r\n new AppIncludedChatsTab(this.slider).open(this.filter, 'excluded', this);\r\n });\r\n\r\n this.confirmBtn.addEventListener('click', () => {\r\n if(this.nameInputField.input.classList.contains('error')) {\r\n return;\r\n }\r\n\r\n if(!this.nameInputField.value.trim()) {\r\n this.nameInputField.input.classList.add('error');\r\n return;\r\n }\r\n\r\n let include = (Array.from(includedFlagsContainer.children) as HTMLElement[]).slice(1).reduce((acc, el) => acc + +!el.style.display, 0);\r\n include += this.filter.include_peers.length;\r\n \r\n if(!include) {\r\n toast('Please choose at least one chat for this folder.');\r\n return;\r\n }\r\n\r\n this.confirmBtn.setAttribute('disabled', 'true');\r\n\r\n let promise: Promise<boolean>;\r\n if(!this.filter.id) {\r\n promise = appMessagesManager.filtersStorage.createDialogFilter(this.filter);\r\n } else {\r\n promise = appMessagesManager.filtersStorage.updateDialogFilter(this.filter);\r\n }\r\n\r\n promise.then(bool => {\r\n if(bool) {\r\n this.close();\r\n }\r\n }).catch(err => {\r\n if(err.type === 'DIALOG_FILTERS_TOO_MUCH') {\r\n toast('Sorry, you can\\'t create more folders.');\r\n } else {\r\n console.error('updateDialogFilter error:', err);\r\n }\r\n }).finally(() => {\r\n this.confirmBtn.removeAttribute('disabled');\r\n });\r\n });\r\n \r\n this.nameInputField.input.addEventListener('input', () => {\r\n this.filter.title = this.nameInputField.value;\r\n this.editCheckForChange();\r\n });\r\n\r\n const reloadMissingPromises: Promise<any>[] = this.type === 'edit' ? [\r\n appMessagesManager.filtersStorage.reloadMissingPeerIds(this.filter.id, 'pinned_peers'),\r\n appMessagesManager.filtersStorage.reloadMissingPeerIds(this.filter.id, 'include_peers'),\r\n appMessagesManager.filtersStorage.reloadMissingPeerIds(this.filter.id, 'exclude_peers')\r\n ] : [];\r\n\r\n return Promise.all([\r\n this.loadAnimationPromise = lottieLoader.loadAnimationAsAsset({\r\n container: this.stickerContainer,\r\n loop: false,\r\n autoplay: false,\r\n width: 86,\r\n height: 86\r\n }, 'Folders_2').then(player => {\r\n this.animation = player;\r\n\r\n return lottieLoader.waitForFirstFrame(player);\r\n }),\r\n\r\n ...reloadMissingPromises\r\n ]);\r\n }\r\n\r\n onOpenAfterTimeout() {\r\n this.loadAnimationPromise.then(() => {\r\n this.animation.autoplay = true;\r\n this.animation.play();\r\n });\r\n }\r\n\r\n private onCreateOpen() {\r\n // this.caption.style.display = '';\r\n this.setTitle('FilterNew');\r\n this.menuBtn.classList.add('hide');\r\n this.confirmBtn.classList.remove('hide');\r\n this.nameInputField.value = '';\r\n\r\n for(const flag in this.flags) {\r\n // @ts-ignore\r\n this.flags[flag].style.display = 'none';\r\n }\r\n }\r\n\r\n private onEditOpen() {\r\n // this.caption.style.display = 'none';\r\n this.setTitle(this.type === 'create' ? 'FilterNew' : 'FilterHeaderEdit');\r\n\r\n if(this.type === 'edit') {\r\n this.menuBtn.classList.remove('hide');\r\n this.confirmBtn.classList.add('hide');\r\n }\r\n \r\n const filter = this.filter;\r\n this.nameInputField.value = documentFragmentToHTML(RichTextProcessor.wrapDraftText(filter.title));\r\n\r\n for(const flag in this.flags) {\r\n this.flags[flag as keyof AppEditFolderTab['flags']].style.display = !!filter.pFlags[flag as keyof AppEditFolderTab['flags']] ? '' : 'none';\r\n }\r\n\r\n (['includePeerIds' as const, 'excludePeerIds' as const]).forEach(key => {\r\n const section = this[key];\r\n const ul = appDialogsManager.createChatList();\r\n\r\n let peers = filter[key];\r\n\r\n // filter peers where we're kicked\r\n const hasPeer = (peerId: PeerId) => {\r\n return !!appMessagesManager.getDialogOnly(peerId) || (peerId.isUser() ? appUsersManager.getUser(peerId.toUserId())._ === 'user' : false);\r\n };\r\n \r\n forEachReverse(peers, (peerId, idx, arr) => {\r\n if(!hasPeer(peerId)) {\r\n arr.splice(idx, 1);\r\n }\r\n });\r\n\r\n peers = peers.slice();\r\n\r\n const renderMore = (_length: number) => {\r\n for(let i = 0, length = Math.min(peers.length, _length); i < length; ++i) {\r\n const peerId = peers.shift();\r\n if(peerId.isUser() ? false : !appMessagesManager.getDialogOnly(peerId)) {\r\n continue;\r\n }\r\n\r\n const {dom} = appDialogsManager.addDialogNew({\r\n dialog: peerId,\r\n container: ul,\r\n drawStatus: false,\r\n rippleEnabled: false,\r\n meAsSaved: true,\r\n avatarSize: 32\r\n });\r\n dom.lastMessageSpan.parentElement.remove();\r\n }\r\n\r\n if(peers.length) {\r\n showMore.lastElementChild.replaceWith(i18n('FilterShowMoreChats', [peers.length]));\r\n } else if(showMore) {\r\n showMore.remove();\r\n }\r\n };\r\n \r\n section.generateContentElement().append(ul);\r\n\r\n let showMore: HTMLElement;\r\n if(peers.length) {\r\n const content = section.generateContentElement();\r\n showMore = Button('folder-category-button btn btn-primary btn-transparent', {icon: 'down'});\r\n showMore.classList.add('load-more', 'rp-overflow');\r\n showMore.addEventListener('click', () => renderMore(20));\r\n showMore.append(i18n('FilterShowMoreChats', [peers.length]));\r\n\r\n content.append(showMore);\r\n }\r\n\r\n renderMore(4);\r\n });\r\n }\r\n\r\n editCheckForChange() {\r\n if(this.type === 'edit') {\r\n const changed = !deepEqual(this.originalFilter, this.filter);\r\n this.confirmBtn.classList.toggle('hide', !changed);\r\n this.menuBtn.classList.toggle('hide', changed);\r\n }\r\n };\r\n\r\n setFilter(filter: DialogFilter, firstTime: boolean) {\r\n if(this.container) {\r\n // cleanup\r\n Array.from(this.container.querySelectorAll('ul, .load-more')).forEach(el => el.remove());\r\n }\r\n\r\n if(firstTime) {\r\n this.originalFilter = filter;\r\n this.filter = copy(filter);\r\n } else {\r\n this.filter = filter;\r\n this.onEditOpen();\r\n this.editCheckForChange();\r\n }\r\n }\r\n\r\n public open(filter?: DialogFilter) {\r\n if(filter === undefined) {\r\n this.setFilter({\r\n _: 'dialogFilter',\r\n id: 0,\r\n title: '',\r\n pFlags: {},\r\n pinned_peers: [],\r\n include_peers: [],\r\n exclude_peers: [],\r\n pinnedPeerIds: [],\r\n includePeerIds: [],\r\n excludePeerIds: []\r\n }, true);\r\n this.type = 'create';\r\n } else {\r\n this.setFilter(filter, true);\r\n this.type = 'edit';\r\n }\r\n\r\n return super.open().then(() => {\r\n if(this.type === 'edit') {\r\n this.setFilter(this.originalFilter, true);\r\n this.onEditOpen();\r\n } else {\r\n this.onCreateOpen();\r\n }\r\n });\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTab } from \"../../slider\";\r\nimport lottieLoader, { LottieLoader } from \"../../../lib/rlottie/lottieLoader\";\r\nimport { RichTextProcessor } from \"../../../lib/richtextprocessor\";\r\nimport { toast } from \"../../toast\";\r\nimport type { MyDialogFilter } from \"../../../lib/storages/filters\";\r\nimport type { DialogFilterSuggested, DialogFilter } from \"../../../layer\";\r\nimport type _rootScope from \"../../../lib/rootScope\";\r\nimport Button from \"../../button\";\r\nimport appMessagesManager from \"../../../lib/appManagers/appMessagesManager\";\r\nimport appPeersManager from \"../../../lib/appManagers/appPeersManager\";\r\nimport apiManager from \"../../../lib/mtproto/mtprotoworker\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport AppEditFolderTab from \"./editFolder\";\r\nimport Row from \"../../row\";\r\nimport { SettingSection } from \"..\";\r\nimport { i18n, i18n_, LangPackKey, join } from \"../../../lib/langPack\";\r\nimport cancelEvent from \"../../../helpers/dom/cancelEvent\";\r\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\r\nimport positionElementByIndex from \"../../../helpers/dom/positionElementByIndex\";\r\nimport RLottiePlayer from \"../../../lib/rlottie/rlottiePlayer\";\r\n\r\nexport default class AppChatFoldersTab extends SliderSuperTab {\r\n private createFolderBtn: HTMLElement;\r\n private foldersSection: SettingSection;\r\n private suggestedSection: SettingSection;\r\n private stickerContainer: HTMLElement;\r\n private animation: RLottiePlayer;\r\n\r\n private filtersRendered: {[filterId: number]: Row} = {};\r\n private loadAnimationPromise: ReturnType<LottieLoader['waitForFirstFrame']>;\r\n\r\n private renderFolder(dialogFilter: DialogFilterSuggested | DialogFilter | MyDialogFilter, container?: HTMLElement, row?: Row) {\r\n let filter: DialogFilter | MyDialogFilter;\r\n let description = '';\r\n let d: HTMLElement[] = [];\r\n if(dialogFilter._ === 'dialogFilterSuggested') {\r\n filter = dialogFilter.filter;\r\n description = dialogFilter.description;\r\n } else {\r\n filter = dialogFilter;\r\n\r\n let enabledFilters = Object.keys(filter.pFlags).length;\r\n /* (['include_peers', 'exclude_peers'] as ['include_peers', 'exclude_peers']).forEach(key => {\r\n enabledFilters += +!!filter[key].length;\r\n }); */\r\n \r\n if(enabledFilters === 1) {\r\n const pFlags = filter.pFlags;\r\n let k: LangPackKey;\r\n if(pFlags.contacts) k = 'FilterAllContacts';\r\n else if(pFlags.non_contacts) k = 'FilterAllNonContacts';\r\n else if(pFlags.groups) k = 'FilterAllGroups';\r\n else if(pFlags.broadcasts) k = 'FilterAllChannels';\r\n else if(pFlags.bots) k = 'FilterAllBots';\r\n\r\n if(k) {\r\n d.push(i18n(k));\r\n }\r\n }\r\n \r\n if(!d.length) {\r\n const folder = appMessagesManager.dialogsStorage.getFolderDialogs(filter.id);\r\n let chats = 0, channels = 0, groups = 0;\r\n for(const dialog of folder) {\r\n if(appPeersManager.isAnyGroup(dialog.peerId)) groups++;\r\n else if(appPeersManager.isBroadcast(dialog.peerId)) channels++;\r\n else chats++;\r\n }\r\n\r\n if(chats) d.push(i18n('Chats', [chats]));\r\n if(channels) d.push(i18n('Channels', [channels]));\r\n if(groups) d.push(i18n('Groups', [groups]));\r\n }\r\n }\r\n\r\n let div: HTMLElement;\r\n if(!row) {\r\n row = new Row({\r\n title: RichTextProcessor.wrapEmojiText(filter.title),\r\n subtitle: description,\r\n clickable: true\r\n });\r\n\r\n if(d.length) {\r\n join(d).forEach(el => {\r\n row.subtitle.append(el);\r\n });\r\n }\r\n \r\n if(dialogFilter._ === 'dialogFilter') {\r\n const filterId = filter.id;\r\n if(!this.filtersRendered.hasOwnProperty(filter.id)) {\r\n attachClickEvent(row.container, () => {\r\n new AppEditFolderTab(this.slider).open(appMessagesManager.filtersStorage.getFilter(filterId));\r\n }, {listenerSetter: this.listenerSetter});\r\n }\r\n\r\n this.filtersRendered[filter.id] = row;\r\n }\r\n } else {\r\n row.subtitle.textContent = '';\r\n join(d).forEach(el => {\r\n row.subtitle.append(el);\r\n });\r\n }\r\n\r\n div = row.container;\r\n\r\n if((filter as MyDialogFilter).hasOwnProperty('orderIndex')) {\r\n // ! header will be at 0 index\r\n positionElementByIndex(div, div.parentElement || container, (filter as MyDialogFilter).orderIndex);\r\n } else if(container) container.append(div);\r\n \r\n return div;\r\n }\r\n\r\n protected async init() {\r\n this.container.classList.add('chat-folders-container');\r\n this.setTitle('ChatList.Filter.List.Title');\r\n\r\n this.scrollable.container.classList.add('chat-folders');\r\n\r\n this.stickerContainer = document.createElement('div');\r\n this.stickerContainer.classList.add('sticker-container');\r\n \r\n const caption = document.createElement('div');\r\n caption.classList.add('caption');\r\n i18n_({element: caption, key: 'ChatList.Filter.Header'});\r\n \r\n this.createFolderBtn = Button('btn-primary btn-color-primary btn-control tgico', {\r\n text: 'ChatList.Filter.NewTitle',\r\n icon: 'add'\r\n });\r\n\r\n this.foldersSection = new SettingSection({\r\n name: 'Filters'\r\n });\r\n this.foldersSection.container.style.display = 'none';\r\n\r\n this.suggestedSection = new SettingSection({\r\n name: 'FilterRecommended'\r\n });\r\n this.suggestedSection.container.style.display = 'none';\r\n\r\n this.scrollable.append(this.stickerContainer, caption, this.createFolderBtn, this.foldersSection.container, this.suggestedSection.container);\r\n\r\n attachClickEvent(this.createFolderBtn, () => {\r\n if(Object.keys(this.filtersRendered).length >= 10) {\r\n toast('Sorry, you can\\'t create more folders.');\r\n } else {\r\n new AppEditFolderTab(this.slider).open();\r\n }\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n const onFiltersContainerUpdate = () => {\r\n this.foldersSection.container.style.display = Object.keys(this.filtersRendered).length ? '' : 'none';\r\n };\r\n\r\n appMessagesManager.filtersStorage.getDialogFilters().then(filters => {\r\n for(const filter of filters) {\r\n this.renderFolder(filter, this.foldersSection.content);\r\n }\r\n\r\n onFiltersContainerUpdate();\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('filter_update', (filter) => {\r\n if(this.filtersRendered.hasOwnProperty(filter.id)) {\r\n this.renderFolder(filter, null, this.filtersRendered[filter.id]);\r\n } else {\r\n this.renderFolder(filter, this.foldersSection.content);\r\n }\r\n\r\n onFiltersContainerUpdate();\r\n\r\n this.getSuggestedFilters();\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('filter_delete', (filter) => {\r\n if(this.filtersRendered.hasOwnProperty(filter.id)) {\r\n /* for(const suggested of this.suggestedFilters) {\r\n if(deepEqual(suggested.filter, filter)) {\r\n \r\n }\r\n } */\r\n this.getSuggestedFilters();\r\n\r\n this.filtersRendered[filter.id].container.remove();\r\n delete this.filtersRendered[filter.id];\r\n }\r\n\r\n onFiltersContainerUpdate();\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('filter_order', (order) => {\r\n order.forEach((filterId, idx) => {\r\n const container = this.filtersRendered[filterId].container;\r\n positionElementByIndex(container, container.parentElement, idx + 1); // ! + 1 due to header \r\n });\r\n });\r\n\r\n this.loadAnimationPromise = lottieLoader.loadAnimationAsAsset({\r\n container: this.stickerContainer,\r\n loop: false,\r\n autoplay: false,\r\n width: 86,\r\n height: 86\r\n }, 'Folders_1').then(player => {\r\n this.animation = player;\r\n\r\n return lottieLoader.waitForFirstFrame(player);\r\n });\r\n\r\n this.getSuggestedFilters()\r\n\r\n /* return Promise.all([\r\n this.loadAnimationPromise\r\n ]); */\r\n return this.loadAnimationPromise;\r\n }\r\n\r\n onOpenAfterTimeout() {\r\n this.loadAnimationPromise.then(() => {\r\n this.animation.autoplay = true;\r\n this.animation.play();\r\n });\r\n }\r\n\r\n private getSuggestedFilters() {\r\n return apiManager.invokeApi('messages.getSuggestedDialogFilters').then(suggestedFilters => {\r\n this.suggestedSection.container.style.display = suggestedFilters.length ? '' : 'none';\r\n Array.from(this.suggestedSection.content.children).slice(1).forEach(el => el.remove());\r\n\r\n suggestedFilters.forEach(filter => {\r\n const div = this.renderFolder(filter);\r\n const button = Button('btn-primary btn-color-primary', {text: 'Add'});\r\n div.append(button);\r\n this.suggestedSection.content.append(div);\r\n\r\n attachClickEvent(button, (e) => {\r\n cancelEvent(e);\r\n\r\n if(Object.keys(this.filtersRendered).length >= 10) {\r\n toast('Sorry, you can\\'t create more folders.');\r\n return;\r\n }\r\n\r\n button.setAttribute('disabled', 'true');\r\n\r\n const f = filter.filter as MyDialogFilter;\r\n f.includePeerIds = [];\r\n f.excludePeerIds = [];\r\n f.pinnedPeerIds = [];\r\n\r\n appMessagesManager.filtersStorage.createDialogFilter(f, true).then(bool => {\r\n if(bool) {\r\n div.remove();\r\n }\r\n }).finally(() => {\r\n button.removeAttribute('disabled');\r\n });\r\n }, {listenerSetter: this.listenerSetter});\r\n });\r\n });\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SettingSection } from \"..\";\r\nimport Row from \"../../row\";\r\nimport CheckboxField from \"../../checkboxField\";\r\nimport { InputNotifyPeer, Update } from \"../../../layer\";\r\nimport appNotificationsManager from \"../../../lib/appManagers/appNotificationsManager\";\r\nimport { SliderSuperTabEventable } from \"../../sliderTab\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport { LangPackKey } from \"../../../lib/langPack\";\r\nimport appStateManager from \"../../../lib/appManagers/appStateManager\";\r\nimport copy from \"../../../helpers/object/copy\";\r\nimport convertKeyToInputKey from \"../../../helpers/string/convertKeyToInputKey\";\r\n\r\ntype InputNotifyKey = Exclude<InputNotifyPeer['_'], 'inputNotifyPeer'>;\r\n\r\nexport default class AppNotificationsTab extends SliderSuperTabEventable {\r\n protected init() {\r\n this.header.classList.add('with-border');\r\n this.container.classList.add('notifications-container', 'with-border');\r\n this.setTitle('Telegram.NotificationSettingsViewController');\r\n\r\n const NotifySection = (options: {\r\n name: LangPackKey,\r\n typeText: LangPackKey,\r\n inputKey: InputNotifyKey,\r\n }) => {\r\n const section = new SettingSection({\r\n name: options.name\r\n });\r\n\r\n const enabledRow = new Row({\r\n checkboxField: new CheckboxField({text: options.typeText, checked: true}),\r\n subtitleLangKey: 'Loading',\r\n });\r\n \r\n const previewEnabledRow = new Row({\r\n checkboxField: new CheckboxField({text: 'MessagePreview', checked: true}),\r\n subtitleLangKey: 'Loading',\r\n });\r\n\r\n section.content.append(enabledRow.container, previewEnabledRow.container);\r\n\r\n this.scrollable.append(section.container);\r\n\r\n const inputNotifyPeer = {_: options.inputKey};\r\n const ret = appNotificationsManager.getNotifySettings(inputNotifyPeer);\r\n (ret instanceof Promise ? ret : Promise.resolve(ret)).then((notifySettings) => {\r\n const applySettings = () => {\r\n const muted = appNotificationsManager.isMuted(notifySettings);\r\n enabledRow.checkboxField.checked = !muted;\r\n previewEnabledRow.checkboxField.checked = notifySettings.show_previews;\r\n \r\n return muted;\r\n };\r\n \r\n applySettings();\r\n\r\n this.eventListener.addEventListener('destroy', () => {\r\n const mute = !enabledRow.checkboxField.checked;\r\n const showPreviews = previewEnabledRow.checkboxField.checked;\r\n\r\n if(mute === appNotificationsManager.isMuted(notifySettings) && showPreviews === notifySettings.show_previews) {\r\n return;\r\n }\r\n\r\n const inputSettings: any = copy(notifySettings);\r\n inputSettings._ = 'inputPeerNotifySettings';\r\n inputSettings.mute_until = mute ? 0x7FFFFFFF : 0;\r\n inputSettings.show_previews = showPreviews;\r\n\r\n appNotificationsManager.updateNotifySettings(inputNotifyPeer, inputSettings);\r\n }, {once: true});\r\n\r\n this.listenerSetter.add(rootScope)('notify_settings', (update: Update.updateNotifySettings) => {\r\n const inputKey = convertKeyToInputKey(update.peer._) as any;\r\n if(options.inputKey === inputKey) {\r\n notifySettings = update.notify_settings;\r\n applySettings();\r\n }\r\n });\r\n });\r\n };\r\n\r\n NotifySection({\r\n name: 'NotificationsPrivateChats',\r\n typeText: 'NotificationsForPrivateChats',\r\n inputKey: 'inputNotifyUsers'\r\n });\r\n\r\n NotifySection({\r\n name: 'NotificationsGroups',\r\n typeText: 'NotificationsForGroups',\r\n inputKey: 'inputNotifyChats'\r\n });\r\n\r\n NotifySection({\r\n name: 'NotificationsChannels',\r\n typeText: 'NotificationsForChannels',\r\n inputKey: 'inputNotifyBroadcasts'\r\n });\r\n\r\n {\r\n const section = new SettingSection({\r\n name: 'NotificationsOther'\r\n });\r\n\r\n const contactsSignUpRow = new Row({\r\n checkboxField: new CheckboxField({text: 'ContactJoined', checked: true}),\r\n subtitleLangKey: 'Loading',\r\n });\r\n \r\n const soundRow = new Row({\r\n checkboxField: new CheckboxField({text: 'Notifications.Sound', checked: true, stateKey: 'settings.notifications.sound'}),\r\n subtitleLangKey: 'Loading',\r\n });\r\n\r\n appStateManager.getState().then(state => {\r\n soundRow.checkboxField.checked = state.settings.notifications.sound;\r\n });\r\n\r\n section.content.append(contactsSignUpRow.container, soundRow.container);\r\n\r\n this.scrollable.append(section.container);\r\n\r\n appNotificationsManager.getContactSignUpNotification().then(enabled => {\r\n contactsSignUpRow.checkboxField.checked = enabled;\r\n\r\n this.eventListener.addEventListener('destroy', () => {\r\n const _enabled = contactsSignUpRow.checkboxField.checked;\r\n if(enabled !== _enabled) {\r\n appNotificationsManager.setContactSignUpNotification(!_enabled);\r\n }\r\n }, {once: true});\r\n });\r\n }\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SettingSection } from \"..\";\r\nimport { randomLong } from \"../../../helpers/random\";\r\nimport I18n from \"../../../lib/langPack\";\r\nimport apiManager from \"../../../lib/mtproto/mtprotoworker\";\r\nimport RadioField from \"../../radioField\";\r\nimport Row, { RadioFormFromRows } from \"../../row\";\r\nimport { SliderSuperTab } from \"../../slider\"\r\n\r\nexport default class AppLanguageTab extends SliderSuperTab {\r\n protected async init() {\r\n this.header.classList.add('with-border');\r\n this.container.classList.add('language-container');\r\n this.setTitle('Telegram.LanguageViewController');\r\n\r\n const section = new SettingSection({});\r\n\r\n const radioRows: Map<string, Row> = new Map();\r\n\r\n const promise = apiManager.invokeApiCacheable('langpack.getLanguages', {\r\n lang_pack: 'macos'\r\n }).then((languages) => {\r\n const random = randomLong();\r\n languages.forEach((language) => {\r\n const row = new Row({\r\n radioField: new RadioField({\r\n text: language.name, \r\n name: random, \r\n value: language.lang_code\r\n }),\r\n subtitle: language.native_name\r\n });\r\n \r\n radioRows.set(language.lang_code, row);\r\n });\r\n\r\n const form = RadioFormFromRows([...radioRows.values()], (value) => {\r\n I18n.getLangPack(value);\r\n });\r\n \r\n I18n.getCacheLangPack().then(langPack => {\r\n const row = radioRows.get(langPack.lang_code);\r\n if(!row) {\r\n console.error('no row', row, langPack);\r\n return;\r\n }\r\n \r\n row.radioField.setValueSilently(true);\r\n });\r\n \r\n section.content.append(form);\r\n });\r\n\r\n this.scrollable.append(section.container);\r\n\r\n return promise;\r\n }\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { addCancelButton } from \"./popups\";\nimport PopupPeer, { PopupPeerOptions } from \"./popups/peer\";\n\n// type PopupConfirmationOptions = Pick<PopupPeerOptions, 'titleLangKey'>;\ntype PopupConfirmationOptions = PopupPeerOptions & {\n button: PopupPeerOptions['buttons'][0],\n checkbox?: PopupPeerOptions['checkboxes'][0]\n};\n\nexport default function confirmationPopup(options: PopupConfirmationOptions) {\n return new Promise<boolean | void>((resolve, reject) => {\n const {button, checkbox} = options;\n button.callback = (set) => {\n resolve(set ? !!set.size : undefined);\n };\n\n const buttons = addCancelButton([button]);\n const cancelButton = buttons.find(button => button.isCancel);\n cancelButton.callback = () => {\n reject();\n };\n\n options.buttons = buttons;\n options.checkboxes = checkbox && [checkbox];\n\n new PopupPeer('popup-confirmation', options).show();\n });\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { SettingSection } from \"../..\";\nimport { LangPackKey } from \"../../../../lib/langPack\";\nimport CheckboxField from \"../../../checkboxField\";\nimport { SliderSuperTabEventable } from \"../../../sliderTab\";\n\nexport function autoDownloadPeerTypeSection(type: 'photo' | 'video' | 'file', title: LangPackKey) {\n const section = new SettingSection({name: title});\n\n const key = 'settings.autoDownload.' + type + '.';\n const contactsCheckboxField = new CheckboxField({\n text: 'AutodownloadContacts', \n name: 'contacts',\n stateKey: key + 'contacts',\n withRipple: true\n });\n const privateCheckboxField = new CheckboxField({\n text: 'AutodownloadPrivateChats', \n name: 'private',\n stateKey: key + 'private',\n withRipple: true\n });\n const groupsCheckboxField = new CheckboxField({\n text: 'AutodownloadGroupChats', \n name: 'groups',\n stateKey: key + 'groups',\n withRipple: true\n });\n const channelsCheckboxField = new CheckboxField({\n text: 'AutodownloadChannels', \n name: 'channels',\n stateKey: key + 'channels',\n withRipple: true\n });\n\n section.content.append(\n contactsCheckboxField.label, \n privateCheckboxField.label, \n groupsCheckboxField.label, \n channelsCheckboxField.label\n );\n\n return section;\n}\n\nexport default class AppAutoDownloadPhotoTab extends SliderSuperTabEventable {\n protected init() {\n this.header.classList.add('with-border');\n this.setTitle('AutoDownloadPhotos');\n\n const section = autoDownloadPeerTypeSection('photo', 'AutoDownloadPhotosTitle');\n this.scrollable.append(section.container);\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport formatBytes from \"../../../../helpers/formatBytes\";\nimport debounce from \"../../../../helpers/schedulers/debounce\";\nimport appStateManager from \"../../../../lib/appManagers/appStateManager\";\nimport I18n from \"../../../../lib/langPack\";\nimport rootScope from \"../../../../lib/rootScope\";\nimport { SliderSuperTabEventable } from \"../../../sliderTab\";\nimport { RangeSettingSelector } from \"../generalSettings\";\nimport { autoDownloadPeerTypeSection } from \"./photo\";\n\nexport default class AppAutoDownloadFileTab extends SliderSuperTabEventable {\n protected init() {\n this.header.classList.add('with-border');\n this.setTitle('AutoDownloadFiles');\n\n const debouncedSave = debounce((sizeMax: number) => {\n appStateManager.setByKey('settings.autoDownloadNew.file_size_max', sizeMax);\n }, 200, false, true);\n\n const section = autoDownloadPeerTypeSection('file', 'AutoDownloadFilesTitle');\n\n const MIN = 512 * 1024;\n // const MAX = 2 * 1024 * 1024 * 1024;\n const MAX = 20 * 1024 * 1024;\n const MAX_RANGE = MAX - MIN;\n\n const sizeMax = rootScope.settings.autoDownloadNew.file_size_max;\n const value = Math.sqrt(Math.sqrt((sizeMax - MIN) / MAX_RANGE));\n const upTo = new I18n.IntlElement({\n key: 'AutodownloadSizeLimitUpTo',\n args: [formatBytes(sizeMax)]\n });\n const range = new RangeSettingSelector('AutoDownloadMaxFileSize', 0.01, value, 0, 1, false);\n range.onChange = (value) => {\n const sizeMax = (value ** 4 * MAX_RANGE + MIN) | 0;\n\n upTo.compareAndUpdate({args: [formatBytes(sizeMax)]});\n\n debouncedSave(sizeMax);\n };\n\n range.valueContainer.append(upTo.element);\n\n section.content.append(range.container);\n\n this.scrollable.append(section.container);\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { SliderSuperTabEventable } from \"../../../sliderTab\";\nimport { autoDownloadPeerTypeSection } from \"./photo\";\n\nexport default class AppAutoDownloadVideoTab extends SliderSuperTabEventable {\n protected init() {\n this.header.classList.add('with-border');\n this.setTitle('AutoDownloadVideos');\n\n const section = autoDownloadPeerTypeSection('video', 'AutoDownloadVideosTitle');\n this.scrollable.append(section.container);\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { SettingSection } from \"..\";\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\nimport replaceContent from \"../../../helpers/dom/replaceContent\";\nimport toggleDisability from \"../../../helpers/dom/toggleDisability\";\nimport formatBytes from \"../../../helpers/formatBytes\";\nimport copy from \"../../../helpers/object/copy\";\nimport deepEqual from \"../../../helpers/object/deepEqual\";\nimport appStateManager, { AutoDownloadPeerTypeSettings, STATE_INIT } from \"../../../lib/appManagers/appStateManager\";\nimport { FormatterArguments, i18n, join, LangPackKey } from \"../../../lib/langPack\";\nimport rootScope from \"../../../lib/rootScope\";\nimport Button from \"../../button\";\nimport CheckboxField from \"../../checkboxField\";\nimport confirmationPopup from \"../../confirmationPopup\";\nimport Row from \"../../row\";\nimport { SliderSuperTabEventable, SliderSuperTabEventableConstructable } from \"../../sliderTab\";\nimport AppAutoDownloadFileTab from \"./autoDownload/file\";\nimport AppAutoDownloadPhotoTab from \"./autoDownload/photo\";\nimport AppAutoDownloadVideoTab from \"./autoDownload/video\";\n\nconst AUTO_DOWNLOAD_FOR_KEYS: {[k in keyof AutoDownloadPeerTypeSettings]: LangPackKey} = {\n contacts: 'AutoDownloadContacts',\n private: 'AutoDownloadPm',\n groups: 'AutoDownloadGroups',\n channels: 'AutoDownloadChannels'\n};\n\nexport default class AppDataAndStorageTab extends SliderSuperTabEventable {\n protected async init() {\n this.header.classList.add('with-border');\n this.setTitle('DataSettings');\n\n {\n const section = new SettingSection({name: 'AutomaticMediaDownload', caption: 'AutoDownloadAudioInfo'});\n\n const state = await appStateManager.getState();\n\n const autoCheckboxField = new CheckboxField({\n text: 'AutoDownloadMedia', \n name: 'auto',\n checked: !state.settings.autoDownloadNew.pFlags.disabled,\n withRipple: true\n });\n\n const onChange = () => {\n toggleDisability([resetButton], \n deepEqual(state.settings.autoDownload, STATE_INIT.settings.autoDownload) && \n deepEqual(state.settings.autoDownloadNew, STATE_INIT.settings.autoDownloadNew));\n };\n\n const setSubtitles = () => {\n this.setAutoDownloadSubtitle(photoRow, state.settings.autoDownload.photo, /* state.settings.autoDownloadNew.photo_size_max */);\n this.setAutoDownloadSubtitle(videoRow, state.settings.autoDownload.video/* , state.settings.autoDownloadNew.video_size_max */);\n this.setAutoDownloadSubtitle(fileRow, state.settings.autoDownload.file, state.settings.autoDownloadNew.file_size_max);\n };\n\n const openTab = (tabConstructor: SliderSuperTabEventableConstructable) => {\n const tab = new tabConstructor(this.slider, true);\n tab.open();\n\n this.listenerSetter.add(tab.eventListener)('destroy', () => {\n setSubtitles();\n onChange();\n }, {once: true});\n };\n \n const photoRow = new Row({\n titleLangKey: 'AutoDownloadPhotos',\n subtitle: '',\n clickable: () => {\n openTab(AppAutoDownloadPhotoTab);\n }\n });\n\n const videoRow = new Row({\n titleLangKey: 'AutoDownloadVideos',\n subtitle: '',\n clickable: () => {\n openTab(AppAutoDownloadVideoTab);\n }\n });\n\n const fileRow = new Row({\n titleLangKey: 'AutoDownloadFiles',\n subtitle: '',\n clickable: () => {\n openTab(AppAutoDownloadFileTab);\n }\n });\n\n const resetButton = Button('btn-primary btn-transparent primary', {icon: 'delete', text: 'ResetAutomaticMediaDownload'});\n attachClickEvent(resetButton, () => {\n confirmationPopup({\n titleLangKey: 'ResetAutomaticMediaDownloadAlertTitle',\n descriptionLangKey: 'ResetAutomaticMediaDownloadAlert',\n button: {\n langKey: 'Reset'\n }\n }).then(() => {\n rootScope.settings.autoDownloadNew = copy(STATE_INIT.settings.autoDownloadNew);\n rootScope.settings.autoDownload = copy(STATE_INIT.settings.autoDownload);\n appStateManager.pushToState('settings', rootScope.settings);\n rootScope.dispatchEvent('settings_updated', {key: 'settings', value: rootScope.settings});\n\n setSubtitles();\n autoCheckboxField.checked = !state.settings.autoDownloadNew.pFlags.disabled;\n });\n });\n\n const onDisabledChange = () => {\n const disabled = !autoCheckboxField.checked;\n\n const settings = rootScope.settings;\n if(disabled) {\n settings.autoDownloadNew.pFlags.disabled = true;\n } else {\n delete settings.autoDownloadNew.pFlags.disabled;\n }\n\n [photoRow, videoRow, fileRow].forEach(row => {\n row.container.classList.toggle('is-disabled', disabled);\n });\n \n appStateManager.pushToState('settings', settings);\n rootScope.dispatchEvent('settings_updated', {key: 'settings', value: settings});\n\n onChange();\n };\n\n autoCheckboxField.input.addEventListener('change', onDisabledChange);\n onDisabledChange();\n setSubtitles();\n\n section.content.append(\n autoCheckboxField.label,\n photoRow.container,\n videoRow.container,\n fileRow.container,\n resetButton\n );\n \n this.scrollable.append(section.container);\n }\n\n {\n const section = new SettingSection({name: 'AutoplayMedia'});\n\n const gifsCheckboxField = new CheckboxField({\n text: 'AutoplayGIF', \n name: 'gifs', \n stateKey: 'settings.autoPlay.gifs',\n withRipple: true\n });\n const videosCheckboxField = new CheckboxField({\n text: 'AutoplayVideo', \n name: 'videos', \n stateKey: 'settings.autoPlay.videos',\n withRipple: true\n });\n\n section.content.append(gifsCheckboxField.label, videosCheckboxField.label);\n\n this.scrollable.append(section.container);\n }\n }\n\n private setAutoDownloadSubtitle(row: Row, settings: AutoDownloadPeerTypeSettings, sizeMax?: number) {\n let key: LangPackKey, args: FormatterArguments = [];\n \n const peerKeys = Object.keys(settings) as (keyof typeof AUTO_DOWNLOAD_FOR_KEYS)[];\n const enabledKeys = peerKeys.map(key => settings[key] ? AUTO_DOWNLOAD_FOR_KEYS[key] : undefined).filter(Boolean);\n if(!enabledKeys.length || sizeMax === 0) {\n key = 'AutoDownloadOff';\n } else {\n const isAll = enabledKeys.length === peerKeys.length;\n if(sizeMax !== undefined) {\n key = isAll ? 'AutoDownloadUpToOnAllChats' : 'AutoDownloadOnUpToFor';\n args.push(formatBytes(sizeMax));\n } else {\n key = isAll ? 'AutoDownloadOnAllChats' : 'AutoDownloadOnFor';\n }\n \n if(!isAll) {\n const fragment = document.createElement('span');\n fragment.append(...join(enabledKeys.map(key => i18n(key)), true, false));\n args.push(fragment);\n }\n }\n \n replaceContent(row.subtitle, i18n(key, args));\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTab } from \"../../slider\";\r\nimport apiManager from \"../../../lib/mtproto/mtprotoworker\";\r\nimport ButtonMenuToggle from \"../../buttonMenuToggle\";\r\nimport Button from \"../../button\";\r\nimport AppPrivacyAndSecurityTab from \"./privacyAndSecurity\";\r\nimport AppGeneralSettingsTab from \"./generalSettings\";\r\nimport AppEditProfileTab from \"./editProfile\";\r\nimport AppChatFoldersTab from \"./chatFolders\";\r\nimport AppNotificationsTab from \"./notifications\";\r\nimport AppLanguageTab from \"./language\";\r\nimport lottieLoader from \"../../../lib/rlottie/lottieLoader\";\r\nimport PopupPeer from \"../../popups/peer\";\r\nimport AppDataAndStorageTab from \"./dataAndStorage\";\r\nimport ButtonIcon from \"../../buttonIcon\";\r\nimport PeerProfile from \"../../peerProfile\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport { SettingSection } from \"..\";\r\nimport Row from \"../../row\";\r\nimport AppActiveSessionsTab from \"./activeSessions\";\r\nimport { i18n, LangPackKey } from \"../../../lib/langPack\";\r\nimport { SliderSuperTabConstructable } from \"../../sliderTab\";\r\nimport PopupAvatar from \"../../popups/avatar\";\r\nimport appProfileManager from \"../../../lib/appManagers/appProfileManager\";\r\nimport appUsersManager from \"../../../lib/appManagers/appUsersManager\";\r\nimport { AccountAuthorizations, Authorization } from \"../../../layer\";\r\n//import AppMediaViewer from \"../../appMediaViewerNew\";\r\n\r\nexport default class AppSettingsTab extends SliderSuperTab {\r\n private buttons: {\r\n edit: HTMLButtonElement,\r\n folders: HTMLButtonElement,\r\n general: HTMLButtonElement,\r\n notifications: HTMLButtonElement,\r\n storage: HTMLButtonElement,\r\n privacy: HTMLButtonElement,\r\n } = {} as any;\r\n private profile: PeerProfile;\r\n\r\n private languageRow: Row;\r\n private devicesRow: Row;\r\n\r\n private authorizations: Authorization.authorization[];\r\n private getAuthorizationsPromise: Promise<AccountAuthorizations.accountAuthorizations>;\r\n\r\n protected init() {\r\n this.container.classList.add('settings-container');\r\n this.setTitle('Settings');\r\n \r\n const btnMenu = ButtonMenuToggle({}, 'bottom-left', [{\r\n icon: 'logout',\r\n text: 'EditAccount.Logout',\r\n onClick: () => {\r\n new PopupPeer('logout', {\r\n titleLangKey: 'LogOut',\r\n descriptionLangKey: 'LogOut.Description',\r\n buttons: [{\r\n langKey: 'LogOut',\r\n callback: () => {\r\n apiManager.logOut();\r\n },\r\n isDanger: true\r\n }]\r\n }).show();\r\n }\r\n }]);\r\n\r\n this.buttons.edit = ButtonIcon('edit');\r\n\r\n this.header.append(this.buttons.edit, btnMenu);\r\n\r\n this.profile = new PeerProfile(this.scrollable, this.listenerSetter, false);\r\n this.profile.init();\r\n this.profile.setPeer(rootScope.myId);\r\n this.profile.fillProfileElements();\r\n\r\n const changeAvatarBtn = Button('btn-circle btn-corner z-depth-1 profile-change-avatar', {icon: 'cameraadd'});\r\n changeAvatarBtn.addEventListener('click', () => {\r\n const canvas = document.createElement('canvas');\r\n new PopupAvatar().open(canvas, (upload) => {\r\n upload().then(inputFile => {\r\n return appProfileManager.uploadProfilePhoto(inputFile);\r\n });\r\n });\r\n });\r\n this.profile.element.lastElementChild.firstElementChild.append(changeAvatarBtn);\r\n \r\n const updateChangeAvatarBtn = () => {\r\n const user = appUsersManager.getSelf();\r\n changeAvatarBtn.classList.toggle('hide', user.photo?._ !== 'userProfilePhoto');\r\n };\r\n \r\n updateChangeAvatarBtn();\r\n this.listenerSetter.add(rootScope)('avatar_update', (peerId) => {\r\n if(rootScope.myId === peerId) {\r\n updateChangeAvatarBtn();\r\n }\r\n });\r\n\r\n /* const div = document.createElement('div');\r\n //div.style.cssText = 'border-radius: 8px; overflow: hidden; width: 396px; height: 264px; flex: 0 0 auto; position: relative; margin: 10rem 0 10rem auto;';\r\n //div.style.width = '135px';\r\n //div.style.height = '100px';\r\n div.style.cssText = 'border-radius: 8px; overflow: hidden; width: 396px; height: 264px; flex: 0 0 auto; position: relative; margin: 10rem auto 10rem 0;';\r\n div.style.width = '135px';\r\n div.style.height = '100px';\r\n \r\n const img = document.createElement('img');\r\n img.src = 'assets/img/pepe.jpg';\r\n img.classList.add('media-photo');\r\n img.style.cssText = 'max-width: 100%;max-height: 100%;';\r\n\r\n div.append(img);\r\n\r\n div.addEventListener('click', () => {\r\n new AppMediaViewer().setSearchContext({peerId: 61004386, inputFilter: 'inputMessagesFilterPhotos'}).openMedia({\r\n _: 'message',\r\n mid: 1,\r\n peerId: 61004386,\r\n fromId: 61004386,\r\n message: '',\r\n media: {\r\n _: 'messageMediaPhoto',\r\n photo: {\r\n _: 'photo',\r\n url: img.src,\r\n downloaded: 111,\r\n sizes: [{\r\n _: 'photoSize',\r\n type: 'x',\r\n w: 618,\r\n h: 412\r\n }]\r\n }\r\n },\r\n date: Date.now() / 1000 | 0\r\n }, img);\r\n });\r\n\r\n this.scrollable.append(div); */\r\n \r\n const buttonsDiv = document.createElement('div');\r\n buttonsDiv.classList.add('profile-buttons');\r\n\r\n const b: [string, LangPackKey, SliderSuperTabConstructable][] = [\r\n ['unmute', 'AccountSettings.Notifications', AppNotificationsTab],\r\n ['data', 'DataSettings', AppDataAndStorageTab],\r\n ['lock', 'AccountSettings.PrivacyAndSecurity', AppPrivacyAndSecurityTab],\r\n ['settings', 'Telegram.GeneralSettingsViewController', AppGeneralSettingsTab],\r\n ['folder', 'AccountSettings.Filters', AppChatFoldersTab],\r\n ];\r\n\r\n const rows = b.map(([icon, langPackKey, tabConstructor]) => {\r\n return new Row({\r\n titleLangKey: langPackKey,\r\n icon,\r\n clickable: () => {\r\n new tabConstructor(this.slider, true).open();\r\n }\r\n });\r\n });\r\n\r\n rows.push(\r\n this.devicesRow = new Row({\r\n titleLangKey: 'Devices',\r\n titleRightSecondary: ' ',\r\n icon: 'activesessions',\r\n clickable: async() => {\r\n if(!this.authorizations) {\r\n await this.updateActiveSessions();\r\n }\r\n\r\n const tab = new AppActiveSessionsTab(this.slider);\r\n tab.authorizations = this.authorizations;\r\n tab.eventListener.addEventListener('destroy', () => {\r\n this.authorizations = undefined;\r\n this.updateActiveSessions(true);\r\n }, {once: true});\r\n tab.open();\r\n }\r\n }),\r\n\r\n this.languageRow = new Row({\r\n titleLangKey: 'AccountSettings.Language',\r\n titleRightSecondary: i18n('LanguageName'),\r\n icon: 'language',\r\n clickable: () => {\r\n new AppLanguageTab(this.slider).open();\r\n }\r\n })\r\n );\r\n\r\n buttonsDiv.append(...rows.map(row => row.container));\r\n\r\n // const profileSection = new SettingSection({fullWidth: true, noPaddingTop: true});\r\n // profileSection.content.append(this.profile.element);\r\n\r\n const buttonsSection = new SettingSection();\r\n buttonsSection.content.append(buttonsDiv);\r\n\r\n this.scrollable.append(this.profile.element/* profileSection.container */, buttonsSection.container);\r\n\r\n /* rootScope.$on('user_auth', (e) => {\r\n this.fillElements();\r\n }); */\r\n\r\n this.buttons.edit.addEventListener('click', () => {\r\n const tab = new AppEditProfileTab(this.slider);\r\n tab.open();\r\n });\r\n\r\n lottieLoader.loadLottieWorkers();\r\n\r\n this.updateActiveSessions();\r\n }\r\n\r\n private getAuthorizations(overwrite?: boolean) {\r\n if(this.getAuthorizationsPromise && !overwrite) return this.getAuthorizationsPromise;\r\n\r\n const promise = this.getAuthorizationsPromise = apiManager.invokeApi('account.getAuthorizations')\r\n .finally(() => {\r\n if(this.getAuthorizationsPromise === promise) {\r\n this.getAuthorizationsPromise = undefined;\r\n }\r\n });\r\n\r\n return promise;\r\n }\r\n\r\n public updateActiveSessions(overwrite?: boolean) {\r\n return this.getAuthorizations(overwrite).then(auths => {\r\n this.authorizations = auths.authorizations;\r\n this.devicesRow.titleRight.textContent = '' + this.authorizations.length;\r\n });\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport appSidebarLeft, { SettingSection } from \"..\";\r\nimport { InputFile } from \"../../../layer\";\r\nimport appChatsManager from \"../../../lib/appManagers/appChatsManager\";\r\nimport InputField from \"../../inputField\";\r\nimport { SliderSuperTab } from \"../../slider\";\r\nimport AvatarEdit from \"../../avatarEdit\";\r\nimport AppAddMembersTab from \"./addMembers\";\r\nimport { _i18n } from \"../../../lib/langPack\";\r\nimport ButtonCorner from \"../../buttonCorner\";\r\n\r\nexport default class AppNewChannelTab extends SliderSuperTab {\r\n private uploadAvatar: () => Promise<InputFile> = null;\r\n\r\n private channelNameInputField: InputField;\r\n private channelDescriptionInputField: InputField;\r\n private nextBtn: HTMLButtonElement;\r\n private avatarEdit: AvatarEdit;\r\n\r\n protected init() {\r\n this.container.classList.add('new-channel-container');\r\n this.setTitle('NewChannel');\r\n\r\n this.avatarEdit = new AvatarEdit((_upload) => {\r\n this.uploadAvatar = _upload;\r\n });\r\n\r\n const section = new SettingSection({\r\n caption: 'Channel.DescriptionHolderDescrpiton'\r\n });\r\n\r\n const inputWrapper = document.createElement('div');\r\n inputWrapper.classList.add('input-wrapper');\r\n\r\n this.channelNameInputField = new InputField({\r\n label: 'EnterChannelName',\r\n maxLength: 128\r\n });\r\n\r\n this.channelDescriptionInputField = new InputField({\r\n label: 'DescriptionOptionalPlaceholder',\r\n maxLength: 255\r\n });\r\n\r\n inputWrapper.append(this.channelNameInputField.container, this.channelDescriptionInputField.container);\r\n\r\n const onLengthChange = () => {\r\n this.nextBtn.classList.toggle('is-visible', !!this.channelNameInputField.value.length && \r\n !this.channelNameInputField.input.classList.contains('error') && \r\n !this.channelDescriptionInputField.input.classList.contains('error'));\r\n };\r\n\r\n this.channelNameInputField.input.addEventListener('input', onLengthChange);\r\n this.channelDescriptionInputField.input.addEventListener('input', onLengthChange);\r\n\r\n this.nextBtn = ButtonCorner({icon: 'arrow_next'});\r\n\r\n this.nextBtn.addEventListener('click', () => {\r\n const title = this.channelNameInputField.value;\r\n const about = this.channelDescriptionInputField.value;\r\n\r\n this.nextBtn.disabled = true;\r\n appChatsManager.createChannel({\r\n title, \r\n about,\r\n broadcast: true\r\n }).then((channelId) => {\r\n if(this.uploadAvatar) {\r\n this.uploadAvatar().then((inputFile) => {\r\n appChatsManager.editPhoto(channelId, inputFile);\r\n });\r\n }\r\n \r\n appSidebarLeft.removeTabFromHistory(this);\r\n new AppAddMembersTab(this.slider).open({\r\n type: 'channel',\r\n skippable: true,\r\n title: 'GroupAddMembers',\r\n placeholder: 'SendMessageTo',\r\n takeOut: (peerIds) => {\r\n return appChatsManager.inviteToChannel(channelId, peerIds);\r\n }\r\n });\r\n });\r\n });\r\n\r\n this.content.append(this.nextBtn);\r\n section.content.append(this.avatarEdit.container, inputWrapper);\r\n this.scrollable.append(section.container);\r\n }\r\n\r\n public onCloseAfterTimeout() {\r\n this.avatarEdit.clear();\r\n this.uploadAvatar = null;\r\n this.channelNameInputField.value = '';\r\n this.channelDescriptionInputField.value = '';\r\n this.nextBtn.disabled = false;\r\n return super.onCloseAfterTimeout();\r\n }\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport InputField from \"../inputField\";\nimport PopupElement from \".\";\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\nimport EditPeer from \"../editPeer\";\nimport { _i18n } from \"../../lib/langPack\";\nimport TelInputField from \"../telInputField\";\nimport appUsersManager from \"../../lib/appManagers/appUsersManager\";\nimport { formatPhoneNumber } from \"../../helpers/formatPhoneNumber\";\nimport { toastNew } from \"../toast\";\n\nexport default class PopupCreateContact extends PopupElement {\n constructor() {\n super('popup-create-contact popup-send-photo popup-new-media', null, {closable: true, withConfirm: 'Add'});\n\n _i18n(this.title, 'AddContactTitle');\n\n attachClickEvent(this.btnConfirm, () => {\n const promise = appUsersManager.importContact(nameInputField.value, lastNameInputField.value, telInputField.value);\n\n promise.then(() => {\n this.hide();\n }, (err) => {\n if(err.type === 'NO_USER') {\n toastNew({langPackKey: 'Contacts.PhoneNumber.NotRegistred'});\n editPeer.disabled = false;\n }\n });\n\n editPeer.lockWithPromise(promise);\n }, {listenerSetter: this.listenerSetter});\n\n const inputFields: InputField[] = [];\n const div = document.createElement('div');\n div.classList.add('name-fields');\n const nameInputField = new InputField({\n label: 'FirstName',\n name: 'create-contact-name',\n maxLength: 70,\n required: true\n });\n const lastNameInputField = new InputField({\n label: 'LastName',\n name: 'create-contact-lastname',\n maxLength: 70\n });\n const telInputField = new TelInputField({required: true});\n inputFields.push(nameInputField, lastNameInputField, telInputField);\n\n const onInput = () => {\n const name = nameInputField.value + ' ' + lastNameInputField.value;\n // const abbr = RichTextProcessor.getAbbreviation(name);\n editPeer.avatarElem.peerTitle = name;\n editPeer.avatarElem.update();\n };\n\n this.listenerSetter.add(nameInputField.input)('input', onInput);\n this.listenerSetter.add(lastNameInputField.input)('input', onInput);\n\n telInputField.validate = () => {\n return !!telInputField.value.match(/\\d/);\n };\n\n const user = appUsersManager.getSelf();\n const formatted = formatPhoneNumber(user.phone);\n if(formatted.code) {\n telInputField.value = '+' + formatted.code.country_code;\n }\n\n const editPeer = new EditPeer({\n inputFields,\n listenerSetter: this.listenerSetter,\n doNotEditAvatar: true,\n nextBtn: this.btnConfirm,\n avatarSize: 100\n });\n\n div.append(nameInputField.container, lastNameInputField.container, editPeer.avatarElem);\n this.container.append(div, telInputField.container);\n\n this.show();\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { SliderSuperTab } from \"../../slider\";\nimport appDialogsManager from \"../../../lib/appManagers/appDialogsManager\";\nimport appUsersManager from \"../../../lib/appManagers/appUsersManager\";\nimport InputSearch from \"../../inputSearch\";\nimport { IS_MOBILE } from \"../../../environment/userAgent\";\nimport { canFocus } from \"../../../helpers/dom/canFocus\";\nimport windowSize from \"../../../helpers/windowSize\";\nimport ButtonCorner from \"../../buttonCorner\";\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\nimport PopupCreateContact from \"../../popups/createContact\";\nimport SortedUserList from \"../../sortedUserList\";\nimport { getMiddleware } from \"../../../helpers/middleware\";\nimport replaceContent from \"../../../helpers/dom/replaceContent\";\nimport rootScope from \"../../../lib/rootScope\";\n\n// TODO: поиск по людям глобальный, если не нашло в контактах никого\n\nexport default class AppContactsTab extends SliderSuperTab {\n private inputSearch: InputSearch;\n private middleware: ReturnType<typeof getMiddleware>;\n private sortedUserList: SortedUserList;\n \n protected init() {\n this.container.id = 'contacts-container';\n\n // this.list = appDialogsManager.createChatList(/* {avatarSize: 48, handheldsSize: 66} */);\n\n const btnAdd = ButtonCorner({icon: 'add', className: 'is-visible'});\n this.content.append(btnAdd);\n\n attachClickEvent(btnAdd, () => {\n new PopupCreateContact();\n }, {listenerSetter: this.listenerSetter});\n\n this.inputSearch = new InputSearch('Search', (value) => {\n this.openContacts(value);\n });\n\n this.listenerSetter.add(rootScope)('contacts_update', (userId) => {\n const isContact = appUsersManager.isContact(userId);\n const peerId = userId.toPeerId();\n if(isContact) this.sortedUserList.add(peerId);\n else this.sortedUserList.delete(peerId);\n });\n\n this.title.replaceWith(this.inputSearch.container);\n\n this.middleware = getMiddleware();\n\n // preload contacts\n // appUsersManager.getContacts();\n }\n\n protected createList() {\n const sortedUserList = new SortedUserList();\n const list = sortedUserList.list;\n list.id = 'contacts';\n list.classList.add('contacts-container');\n appDialogsManager.setListClickListener(list, () => {\n this.close();\n }, undefined, true);\n return sortedUserList;\n }\n\n protected onClose() {\n this.middleware.clean();\n /* // need to clear, and left 1 page for smooth slide\n let pageCount = appPhotosManager.windowH / 72 * 1.25 | 0;\n (Array.from(this.list.children) as HTMLElement[]).slice(pageCount).forEach(el => el.remove()); */\n }\n\n protected onOpenAfterTimeout() {\n if(IS_MOBILE || !canFocus(true)) return;\n this.inputSearch.input.focus();\n }\n\n public openContacts(query?: string) {\n if(this.init) {\n this.init();\n this.init = null;\n }\n\n this.middleware.clean();\n const middleware = this.middleware.get();\n this.scrollable.onScrolledBottom = null;\n this.scrollable.container.textContent = '';\n\n appUsersManager.getContactsPeerIds(query, undefined, 'online').then(contacts => {\n if(!middleware()) {\n return;\n }\n\n const sortedUserList = this.sortedUserList = this.createList();\n\n let renderPage = () => {\n const pageCount = windowSize.height / 72 * 1.25 | 0;\n const arr = contacts.splice(0, pageCount); // надо splice!\n\n arr.forEach((peerId) => {\n sortedUserList.add(peerId);\n });\n\n if(!contacts.length) {\n renderPage = undefined;\n this.scrollable.onScrolledBottom = null;\n }\n };\n\n renderPage();\n this.scrollable.onScrolledBottom = () => {\n if(renderPage) {\n renderPage();\n } else {\n this.scrollable.onScrolledBottom = null;\n }\n };\n\n replaceContent(this.scrollable.container, sortedUserList.list);\n });\n }\n\n public open() {\n this.openContacts();\n return super.open();\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport appDialogsManager from \"../../../lib/appManagers/appDialogsManager\";\nimport { SliderSuperTab } from \"../../slider\";\n\nexport default class AppArchivedTab extends SliderSuperTab {\n private static filterId = 1;\n private wasFilterId: number;\n\n init() {\n this.container.id = 'chats-archived-container';\n this.setTitle('ArchivedChats');\n\n if(!appDialogsManager.sortedLists[AppArchivedTab.filterId]) {\n const chatList = appDialogsManager.createChatList();\n appDialogsManager.generateScrollable(chatList, AppArchivedTab.filterId).container.append(chatList);\n appDialogsManager.setListClickListener(chatList, null, true);\n //appDialogsManager.setListClickListener(archivedChatList, null, true); // * to test peer changing\n }\n\n const scrollable = appDialogsManager.scrollables[AppArchivedTab.filterId];\n this.scrollable.container.replaceWith(scrollable.container);\n this.scrollable = scrollable;\n }\n\n onOpen() {\n if(this.init) {\n this.init();\n this.init = null;\n }\n\n this.wasFilterId = appDialogsManager.filterId;\n appDialogsManager.setFilterId(AppArchivedTab.filterId);\n appDialogsManager.onTabChange();\n }\n\n // вообще, так делать нельзя, но нет времени чтобы переделать главный чатлист на слайд...\n onOpenAfterTimeout() {\n appDialogsManager.sortedLists[this.wasFilterId].clear();\n }\n\n onClose() {\n appDialogsManager.setFilterId(this.wasFilterId);\n appDialogsManager.onTabChange();\n }\n\n onCloseAfterTimeout() {\n appDialogsManager.sortedLists[AppArchivedTab.filterId].clear();\n return super.onCloseAfterTimeout();\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTab } from \"../../slider\";\r\nimport ButtonCorner from \"../../buttonCorner\";\r\nimport appUsersManager from \"../../../lib/appManagers/appUsersManager\";\r\nimport AppNewGroupTab from \"./newGroup\";\r\nimport { toast } from \"../../toast\";\r\nimport { ButtonMenuItemOptions } from \"../../buttonMenu\";\r\nimport type { LazyLoadQueueIntersector } from \"../../lazyLoadQueue\";\r\nimport { i18n, join, _i18n } from \"../../../lib/langPack\";\r\nimport rootScope from '../../../lib/rootScope';\r\nimport { wrapSticker } from \"../../wrappers\";\r\nimport appStickersManager from \"../../../lib/appManagers/appStickersManager\";\r\nimport SortedUserList from \"../../sortedUserList\";\r\nimport { PeerLocated, Update, Updates } from \"../../../layer\";\r\nimport appPeersManager from \"../../../lib/appManagers/appPeersManager\";\r\nimport { SettingChatListSection } from \"..\";\r\nimport appProfileManager from \"../../../lib/appManagers/appProfileManager\";\r\nimport appDialogsManager from \"../../../lib/appManagers/appDialogsManager\";\r\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\r\nimport confirmationPopup from \"../../confirmationPopup\";\r\n\r\nexport default class AppPeopleNearbyTab extends SliderSuperTab {\r\n private latestLocationSaved: {latitude: number, longitude: number, accuracy: number};\r\n private isLocationWatched: boolean = false;\r\n private errorCategory: HTMLElement;\r\n private retryBtn: HTMLButtonElement;\r\n private btnOptions: HTMLButtonElement;\r\n private menuButtons: (ButtonMenuItemOptions & {verify?: () => boolean})[];\r\n\r\n protected lazyLoadQueue: LazyLoadQueueIntersector;\r\n protected peopleSection: SettingChatListSection;\r\n protected chatsSection: SettingChatListSection;\r\n\r\n protected locatedPeers: Map<PeerId, PeerLocated.peerLocated>;\r\n\r\n protected init() {\r\n this.container.classList.add('people-nearby-container');\r\n this.setTitle('PeopleNearby');\r\n\r\n this.errorCategory = document.createElement('div');\r\n this.errorCategory.classList.add('text', 'hide', 'nearby-error');\r\n\r\n this.retryBtn = ButtonCorner({icon: 'check'});\r\n\r\n const emoji = '🧭';\r\n const doc = appStickersManager.getAnimatedEmojiSticker(emoji);\r\n const stickerContainer = document.createElement('div');\r\n stickerContainer.classList.add('sticker-container');\r\n\r\n if(doc) {\r\n wrapSticker({\r\n doc,\r\n div: stickerContainer,\r\n loop: false,\r\n play: true,\r\n width: 86,\r\n height: 86,\r\n emoji,\r\n needUpscale: true\r\n }).then(() => {\r\n // this.animation = player;\r\n });\r\n } else {\r\n stickerContainer.classList.add('media-sticker-wrapper');\r\n }\r\n\r\n const caption = document.createElement('div');\r\n caption.classList.add('caption');\r\n _i18n(caption, 'PeopleNearbyInfo2');\r\n\r\n this.locatedPeers = new Map();\r\n\r\n const m = () => {\r\n const sortedUserList = new SortedUserList({\r\n avatarSize: 42, \r\n createChatListOptions: {\r\n dialogSize: 48,\r\n new: true\r\n },\r\n autonomous: false,\r\n onUpdate: (element) => {\r\n const peer = this.locatedPeers.get(element.id);\r\n const elements: HTMLElement[] = [\r\n this.parseDistance(peer.distance)\r\n ];\r\n\r\n if(!element.id.isUser()) {\r\n elements.push(appProfileManager.getChatMembersString(element.id.toChatId()));\r\n }\r\n\r\n element.dom.lastMessageSpan.textContent = '';\r\n element.dom.lastMessageSpan.append(...join(elements, false));\r\n },\r\n getIndex: (element) => {\r\n const peer = this.locatedPeers.get(element.id);\r\n return 0x7FFFFFFF - peer.distance;\r\n }\r\n });\r\n\r\n appDialogsManager.setListClickListener(sortedUserList.list, undefined, undefined, false);\r\n \r\n return sortedUserList;\r\n };\r\n \r\n const peopleSection = this.peopleSection = new SettingChatListSection({\r\n name: 'PeopleNearbyHeader',\r\n sortedList: m()\r\n });\r\n\r\n const chatsSection = this.chatsSection = new SettingChatListSection({\r\n name: 'ChatsNearbyHeader',\r\n sortedList: m()\r\n });\r\n\r\n const btnMakeVisible = peopleSection.makeButton({\r\n text: 'MakeMyselfVisible',\r\n icon: 'location'\r\n });\r\n\r\n const btnMakeInvisible = peopleSection.makeButton({\r\n text: 'StopShowingMe',\r\n icon: 'location'\r\n });\r\n\r\n const btnCreateGroup = chatsSection.makeButton({\r\n text: 'NearbyCreateGroup',\r\n icon: 'newgroup'\r\n });\r\n\r\n attachClickEvent(btnMakeVisible, () => {\r\n confirmationPopup({\r\n titleLangKey: 'MakeMyselfVisibleTitle',\r\n descriptionLangKey: 'MakeMyselfVisibleInfo',\r\n button: {\r\n langKey: 'OK'\r\n }\r\n }).then(() => {\r\n this.startWatching();\r\n });\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n attachClickEvent(btnMakeInvisible, () => {\r\n this.stopWatching();\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n attachClickEvent(btnCreateGroup, () => {\r\n new AppNewGroupTab(this.slider).open([], true);\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n btnMakeVisible.classList.add('primary');\r\n btnMakeInvisible.classList.add('danger');\r\n btnCreateGroup.classList.add('primary');\r\n\r\n this.content.append(this.retryBtn);\r\n this.scrollable.append(\r\n stickerContainer,\r\n caption,\r\n peopleSection.container,\r\n chatsSection.container,\r\n this.errorCategory\r\n );\r\n }\r\n\r\n private parseDistance(distance: number) {\r\n if(rootScope.settings.distanceUnit === 'miles') {\r\n if(distance > 1609.34) {\r\n return i18n('MilesAway', [Math.round(distance / 1609)]);\r\n } else {\r\n return i18n('FootsAway', [Math.round(distance * 3.281)]);\r\n }\r\n } else {\r\n if(distance >= 1000) {\r\n return i18n('KMetersAway2', [distance / 1000]);\r\n } else {\r\n return i18n('MetersAway2', [distance]);\r\n }\r\n }\r\n }\r\n\r\n public open() {\r\n const result = super.open();\r\n result.then(() => {\r\n this.retryBtn.classList.remove('is-visible');\r\n navigator.geolocation.getCurrentPosition((location) => {\r\n this.latestLocationSaved = {\r\n latitude: location.coords.latitude,\r\n longitude: location.coords.longitude,\r\n accuracy: location.coords.accuracy\r\n };\r\n\r\n console.log(this.latestLocationSaved);\r\n\r\n appUsersManager.getLocated(\r\n location.coords.latitude,\r\n location.coords.longitude,\r\n location.coords.accuracy\r\n ).then((response) => {\r\n const update = (response as Updates.updates).updates[0] as Update.updatePeerLocated;\r\n const peers = update.peers as PeerLocated.peerLocated[];\r\n const orderedPeers = peers.sort((a, b) => a.distance - b.distance);\r\n const groupsCounter = peers.filter((e) => e.peer._ == 'peerChannel').length;\r\n const usersCounter = peers.filter((e) => e.peer._ != 'peerChannel').length;\r\n orderedPeers?.forEach(peer => {\r\n const peerId = appPeersManager.getPeerId(peer.peer);\r\n const section = peerId.isUser() ? this.peopleSection : this.chatsSection;\r\n this.locatedPeers.set(peerId, peer);\r\n section.sortedList.add(peerId);\r\n });\r\n\r\n this.errorCategory.classList.toggle('hide', !!(usersCounter || groupsCounter));\r\n this.errorCategory.innerHTML = \"No groups or channels found around you.\";\r\n });\r\n }, (error) => {\r\n this.errorCategory.classList.remove('hide');\r\n this.retryBtn.classList.add('is-visible');\r\n this.retryBtn.addEventListener('click', this.open);\r\n if(error instanceof GeolocationPositionError) {\r\n this.errorCategory.innerHTML = \"Location permission denied. Click below to retry.\";\r\n } else {\r\n this.errorCategory.innerHTML = \"An error has occurred. Please retry later clicking the button below.\";\r\n }\r\n });\r\n });\r\n\r\n return result;\r\n }\r\n\r\n private startWatching() {\r\n if(!this.latestLocationSaved || this.isLocationWatched) return;\r\n this.isLocationWatched = true;\r\n\r\n toast('Your position is now being shared. Do not close the page or it will be suspended.');\r\n\r\n appUsersManager.getLocated(\r\n this.latestLocationSaved.latitude,\r\n this.latestLocationSaved.longitude,\r\n this.latestLocationSaved.accuracy,\r\n true, // background parameter\r\n 0x7fffffff // self_expires parameter\r\n );\r\n\r\n navigator.geolocation.watchPosition((result) => {\r\n const isLongitudeDifferent = result.coords.longitude !== this.latestLocationSaved.longitude;\r\n const isLatitudeDifferent = result.coords.latitude !== this.latestLocationSaved.latitude;\r\n const distanceCheck = this.calculateDistance(\r\n result.coords.latitude, result.coords.longitude,\r\n this.latestLocationSaved.latitude, this.latestLocationSaved.longitude\r\n ) > 100;\r\n\r\n if((isLatitudeDifferent || isLongitudeDifferent) && distanceCheck) {\r\n appUsersManager.getLocated(\r\n result.coords.latitude,\r\n result.coords.longitude,\r\n result.coords.accuracy,\r\n true, // background parameter\r\n 0x7fffffff // self_expires parameter\r\n );\r\n this.latestLocationSaved = {\r\n latitude: result.coords.latitude,\r\n longitude: result.coords.longitude,\r\n accuracy: result.coords.accuracy\r\n }\r\n }\r\n });\r\n }\r\n\r\n private stopWatching() {\r\n if(!this.isLocationWatched) return;\r\n this.isLocationWatched = false;\r\n toast('The sharing of your position has been stopped. You will no longer be visible to other users.');\r\n appUsersManager.getLocated(\r\n 0, // latitude parameter\r\n 0, // longitude parameter\r\n 0, // accuracy parameter\r\n false, // background parameter\r\n 0 // self_expires parameter\r\n );\r\n }\r\n\r\n private calculateDistance(lat1: number, long1: number, lat2: number, long2: number) {\r\n const p = 0.017453292519943295; // Math.PI/180\r\n return (\r\n 12742 * Math.asin(\r\n Math.sqrt(\r\n (0.5 - Math.cos((lat2 - lat1) * p)) +\r\n (\r\n Math.cos(lat1 * p) * Math.cos(lat2 * p)\r\n * (1 - Math.cos((long2 - long1) * p)/2)\r\n )\r\n )\r\n )\r\n );\r\n }\r\n}\r\n","export default function formatNumber(bytes: number, decimals = 2) {\n if(bytes === 0) return '0';\n\n const k = 1000;\n const dm = decimals < 0 ? 0 : decimals;\n const sizes = ['', 'K', 'M', 'B', 'T'];\n\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n\n return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + sizes[i];\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport appImManager from \"../../lib/appManagers/appImManager\";\nimport appStateManager from \"../../lib/appManagers/appStateManager\";\nimport appUsersManager from \"../../lib/appManagers/appUsersManager\";\nimport rootScope from \"../../lib/rootScope\";\nimport { SearchGroup } from \"../appSearch\";\nimport \"../avatar\";\nimport Scrollable, { ScrollableX } from \"../scrollable\";\nimport InputSearch from \"../inputSearch\";\nimport SidebarSlider from \"../slider\";\nimport { TransitionSlider } from \"../transition\";\nimport AppNewGroupTab from \"./tabs/newGroup\";\nimport appMessagesManager from \"../../lib/appManagers/appMessagesManager\";\nimport AppSearchSuper from \"../appSearchSuper.\";\nimport { DateData, fillTipDates } from \"../../helpers/date\";\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\nimport AppSettingsTab from \"./tabs/settings\";\nimport AppNewChannelTab from \"./tabs/newChannel\";\nimport AppContactsTab from \"./tabs/contacts\";\nimport AppArchivedTab from \"./tabs/archivedTab\";\nimport AppAddMembersTab from \"./tabs/addMembers\";\nimport I18n, { FormatterArguments, i18n, i18n_, LangPackKey } from \"../../lib/langPack\";\nimport AppPeopleNearbyTab from \"./tabs/peopleNearby\";\nimport { ButtonMenuItemOptions } from \"../buttonMenu\";\nimport CheckboxField from \"../checkboxField\";\nimport { IS_MOBILE_SAFARI } from \"../../environment/userAgent\";\nimport appNavigationController, { NavigationItem } from \"../appNavigationController\";\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\nimport findUpTag from \"../../helpers/dom/findUpTag\";\nimport PeerTitle from \"../peerTitle\";\nimport App from \"../../config/app\";\nimport ButtonMenuToggle from \"../buttonMenuToggle\";\nimport replaceContent from \"../../helpers/dom/replaceContent\";\nimport sessionStorage from \"../../lib/sessionStorage\";\nimport { attachClickEvent, CLICK_EVENT_NAME } from \"../../helpers/dom/clickEvent\";\nimport { closeBtnMenu } from \"../misc\";\nimport ButtonIcon from \"../buttonIcon\";\nimport confirmationPopup from \"../confirmationPopup\";\nimport IS_GEOLOCATION_SUPPORTED from \"../../environment/geolocationSupport\";\nimport type SortedUserList from \"../sortedUserList\";\nimport Button, { ButtonOptions } from \"../button\";\nimport noop from \"../../helpers/noop\";\nimport ripple from \"../ripple\";\nimport indexOfAndSplice from \"../../helpers/array/indexOfAndSplice\";\nimport formatNumber from \"../../helpers/number/formatNumber\";\nimport AvatarElement from \"../avatar\";\n\nexport const LEFT_COLUMN_ACTIVE_CLASSNAME = 'is-left-column-shown';\n\nexport class AppSidebarLeft extends SidebarSlider {\n private toolsBtn: HTMLElement;\n private backBtn: HTMLButtonElement;\n //private searchInput = document.getElementById('global-search') as HTMLInputElement;\n private inputSearch: InputSearch;\n \n public archivedCount: HTMLSpanElement;\n\n private newBtnMenu: HTMLElement;\n\n //private log = logger('SL');\n\n private searchGroups: {[k in 'contacts' | 'globalContacts' | 'messages' | 'people' | 'recent']: SearchGroup} = {} as any;\n private searchSuper: AppSearchSuper;\n\n private updateBtn: HTMLElement;\n private hasUpdate: boolean;\n\n constructor() {\n super({\n sidebarEl: document.getElementById('column-left') as HTMLDivElement,\n navigationType: 'left'\n });\n\n //this._selectTab(0); // make first tab as default\n\n this.inputSearch = new InputSearch('Search');\n const sidebarHeader = this.sidebarEl.querySelector('.item-main .sidebar-header');\n sidebarHeader.append(this.inputSearch.container);\n\n const onNewGroupClick = () => {\n new AppAddMembersTab(this).open({\n type: 'chat',\n skippable: false,\n takeOut: (peerIds) => {\n new AppNewGroupTab(this).open(peerIds);\n },\n title: 'GroupAddMembers',\n placeholder: 'SendMessageTo'\n });\n };\n\n const onContactsClick = () => {\n new AppContactsTab(this).open();\n };\n\n //this.toolsBtn = this.sidebarEl.querySelector('.sidebar-tools-button') as HTMLButtonElement;\n this.backBtn = this.sidebarEl.querySelector('.sidebar-back-button') as HTMLButtonElement;\n\n const btnArchive: ButtonMenuItemOptions & {verify?: () => boolean} = {\n icon: 'archive',\n text: 'ArchivedChats',\n onClick: () => {\n new AppArchivedTab(this).open();\n },\n verify: () => {\n const folder = appMessagesManager.dialogsStorage.getFolderDialogs(1, false);\n return !!folder.length || !appMessagesManager.dialogsStorage.isDialogsLoaded(1);\n }\n };\n\n const themeCheckboxField = new CheckboxField({\n toggle: true,\n checked: rootScope.getTheme().name === 'night'\n });\n themeCheckboxField.input.addEventListener('change', () => {\n rootScope.settings.theme = themeCheckboxField.input.checked ? 'night' : 'day';\n appStateManager.pushToState('settings', rootScope.settings);\n rootScope.dispatchEvent('theme_change');\n });\n\n rootScope.addEventListener('theme_change', () => {\n themeCheckboxField.setValueSilently(rootScope.getTheme().name === 'night');\n });\n\n const menuButtons: (ButtonMenuItemOptions & {verify?: () => boolean})[] = [{\n icon: 'saved',\n text: 'SavedMessages',\n onClick: () => {\n setTimeout(() => { // menu doesn't close if no timeout (lol)\n appImManager.setPeer({\n peerId: appImManager.myId\n });\n }, 0);\n }\n }, btnArchive, {\n icon: 'user',\n text: 'Contacts',\n onClick: onContactsClick\n }, IS_GEOLOCATION_SUPPORTED ? {\n icon: 'group',\n text: 'PeopleNearby',\n onClick: () => {\n new AppPeopleNearbyTab(this).open();\n }\n } : undefined, {\n icon: 'settings',\n text: 'Settings',\n onClick: () => {\n new AppSettingsTab(this).open();\n }\n }, {\n icon: 'darkmode',\n text: 'DarkMode',\n onClick: () => {\n \n },\n checkboxField: themeCheckboxField\n }, {\n icon: 'animations',\n text: 'Animations',\n onClick: () => {\n \n },\n checkboxField: new CheckboxField({\n toggle: true, \n checked: true,\n stateKey: 'settings.animationsEnabled',\n })\n }, {\n icon: 'help',\n text: 'TelegramFeatures',\n onClick: () => {\n const url = I18n.format('TelegramFeaturesUrl', true);\n appImManager.openUrl(url);\n }\n }, {\n icon: 'bug',\n text: 'ReportBug',\n onClick: () => {\n const a = document.createElement('a');\n a.target = '_blank';\n a.href = 'https://bugs.telegram.org/?tag_ids=40&sort=time';\n document.body.append(a);\n a.click();\n setTimeout(() => {\n a.remove();\n }, 0);\n }\n }, {\n icon: 'char z',\n text: 'ChatList.Menu.SwitchTo.Z',\n onClick: () => {\n Promise.all([\n sessionStorage.set({kz_version: 'Z'}),\n sessionStorage.delete('tgme_sync')\n ]).then(() => {\n location.href = 'https://web.telegram.org/z/';\n });\n },\n verify: () => App.isMainDomain\n }, {\n icon: 'char w',\n text: 'ChatList.Menu.SwitchTo.Webogram',\n onClick: () => {\n sessionStorage.delete('tgme_sync').then(() => {\n location.href = 'https://web.telegram.org/?legacy=1';\n });\n },\n verify: () => App.isMainDomain\n }];\n\n const filteredButtons = menuButtons.filter(Boolean);\n\n this.toolsBtn = ButtonMenuToggle({}, 'bottom-right', filteredButtons, (e) => {\n filteredButtons.forEach(button => {\n if(button.verify) {\n button.element.classList.toggle('hide', !button.verify());\n }\n });\n });\n this.toolsBtn.classList.remove('tgico-more');\n this.toolsBtn.classList.add('sidebar-tools-button', 'is-visible');\n\n this.backBtn.parentElement.insertBefore(this.toolsBtn, this.backBtn);\n\n const btnMenu = this.toolsBtn.querySelector('.btn-menu') as HTMLElement;\n\n const btnMenuFooter = document.createElement('a');\n btnMenuFooter.href = 'https://github.com/morethanwords/tweb/blob/master/CHANGELOG.md';\n btnMenuFooter.target = '_blank';\n btnMenuFooter.rel = 'noopener noreferrer';\n btnMenuFooter.classList.add('btn-menu-footer');\n btnMenuFooter.addEventListener(CLICK_EVENT_NAME, (e) => {\n e.stopPropagation();\n closeBtnMenu();\n });\n const t = document.createElement('span');\n t.classList.add('btn-menu-footer-text');\n t.innerHTML = 'Telegram Web' + App.suffix + ' '/* ' alpha ' */ + App.versionFull;\n btnMenuFooter.append(t); \n btnMenu.classList.add('has-footer');\n btnMenu.append(btnMenuFooter);\n\n this.newBtnMenu = ButtonMenuToggle({}, 'top-left', [{\n icon: 'newchannel',\n text: 'NewChannel',\n onClick: () => {\n new AppNewChannelTab(this).open();\n }\n }, {\n icon: 'newgroup',\n text: 'NewGroup',\n onClick: onNewGroupClick\n }, {\n icon: 'newprivate',\n text: 'NewPrivateChat',\n onClick: onContactsClick\n }]);\n this.newBtnMenu.className = 'btn-circle rp btn-corner z-depth-1 btn-menu-toggle animated-button-icon';\n this.newBtnMenu.insertAdjacentHTML('afterbegin', `\n <span class=\"tgico tgico-newchat_filled\"></span>\n <span class=\"tgico tgico-close\"></span>\n `);\n this.newBtnMenu.id = 'new-menu';\n sidebarHeader.nextElementSibling.append(this.newBtnMenu);\n\n this.updateBtn = document.createElement('div');\n // this.updateBtn.classList.add('btn-update');\n this.updateBtn.className = 'btn-circle rp btn-corner z-depth-1 btn-update is-hidden';\n ripple(this.updateBtn);\n this.updateBtn.append(i18n('Update'));\n // const weave = new TopbarWeave();\n // const weaveContainer = weave.render('btn-update-weave');\n // this.updateBtn.prepend(weaveContainer);\n\n attachClickEvent(this.updateBtn, () => {\n location.reload();\n });\n \n sidebarHeader.nextElementSibling.append(this.updateBtn);\n\n // setTimeout(() => {\n // weave.componentDidMount();\n // weave.setCurrentState(GROUP_CALL_STATE.MUTED, true);\n // weave.setAmplitude(0);\n // weave.handleBlur();\n // }, 1e3);\n\n this.inputSearch.input.addEventListener('focus', () => this.initSearch(), {once: true});\n\n //parseMenuButtonsTo(this.newButtons, this.newBtnMenu.firstElementChild.children);\n\n this.archivedCount = document.createElement('span');\n this.archivedCount.className = 'archived-count badge badge-24 badge-gray';\n\n btnArchive.element.append(this.archivedCount);\n\n rootScope.addEventListener('folder_unread', (folder) => {\n if(folder.id === 1) {\n // const count = folder.unreadMessagesCount;\n const count = folder.unreadDialogsCount;\n this.archivedCount.innerText = '' + formatNumber(count, 1);\n this.archivedCount.classList.toggle('hide', !count);\n }\n });\n\n appUsersManager.getTopPeers('correspondents');\n\n // Focus search input by pressing Escape\n const navigationItem: NavigationItem = {\n type: 'global-search-focus',\n onPop: () => {\n setTimeout(() => {\n this.inputSearch.input.focus();\n }, 0);\n\n return false;\n },\n noHistory: true\n };\n appNavigationController.pushItem(navigationItem);\n\n appStateManager.getState().then(state => {\n const recentSearch = state.recentSearch || [];\n for(let i = 0, length = recentSearch.length; i < length; ++i) {\n appStateManager.requestPeer(recentSearch[i], 'recentSearch');\n }\n\n const CHECK_UPDATE_INTERVAL = 1800e3;\n const checkUpdateInterval = setInterval(() => {\n fetch('version', {cache: 'no-cache'})\n .then(res => (res.status === 200 && res.ok && res.text()) || Promise.reject())\n .then(text => {\n if(text !== App.versionFull) {\n this.hasUpdate = true;\n clearInterval(checkUpdateInterval);\n\n if(!this.newBtnMenu.classList.contains('is-hidden')) {\n this.updateBtn.classList.remove('is-hidden');\n }\n }\n })\n .catch(noop);\n }, CHECK_UPDATE_INTERVAL);\n });\n }\n\n private initSearch() {\n const searchContainer = this.sidebarEl.querySelector('#search-container') as HTMLDivElement;\n\n const scrollable = new Scrollable(searchContainer);\n\n const close = () => {\n //setTimeout(() => {\n this.backBtn.click();\n //}, 0);\n };\n\n this.searchGroups = {\n contacts: new SearchGroup('SearchAllChatsShort', 'contacts', undefined, undefined, undefined, undefined, close),\n globalContacts: new SearchGroup('GlobalSearch', 'contacts', undefined, undefined, undefined, undefined, close),\n messages: new SearchGroup('SearchMessages', 'messages'),\n people: new SearchGroup(false, 'contacts', true, 'search-group-people', true, false, close),\n recent: new SearchGroup('Recent', 'contacts', true, 'search-group-recent', true, true, close)\n };\n\n const searchSuper = this.searchSuper = new AppSearchSuper({\n mediaTabs: [{\n inputFilter: 'inputMessagesFilterEmpty',\n name: 'FilterChats',\n type: 'chats'\n }, {\n inputFilter: 'inputMessagesFilterPhotoVideo',\n name: 'SharedMediaTab2',\n type: 'media'\n }, {\n inputFilter: 'inputMessagesFilterUrl',\n name: 'SharedLinksTab2',\n type: 'links'\n }, {\n inputFilter: 'inputMessagesFilterDocument',\n name: 'SharedFilesTab2',\n type: 'files'\n }, {\n inputFilter: 'inputMessagesFilterMusic',\n name: 'SharedMusicTab2',\n type: 'music'\n }, {\n inputFilter: 'inputMessagesFilterRoundVoice',\n name: 'SharedVoiceTab2',\n type: 'voice'\n }], \n scrollable, \n searchGroups: this.searchGroups, \n asChatList: true,\n hideEmptyTabs: false,\n showSender: true\n });\n\n searchContainer.prepend(searchSuper.nav.parentElement.parentElement);\n scrollable.container.append(searchSuper.container);\n\n const resetSearch = () => {\n searchSuper.setQuery({\n peerId: ''.toPeerId(), \n folderId: 0\n });\n searchSuper.selectTab(0);\n searchSuper.load(true); \n };\n\n resetSearch();\n\n let pickedElements: HTMLElement[] = [];\n let selectedPeerId: PeerId = ''.toPeerId();\n let selectedMinDate = 0;\n let selectedMaxDate = 0;\n const updatePicked = () => {\n //(this.inputSearch.input as HTMLInputElement).placeholder = pickedElements.length ? 'Search' : 'Telegram Search';\n this.inputSearch.container.classList.toggle('is-picked-twice', pickedElements.length === 2);\n this.inputSearch.container.classList.toggle('is-picked', !!pickedElements.length);\n\n if(pickedElements.length) {\n this.inputSearch.input.style.setProperty('--paddingLeft', (pickedElements[pickedElements.length - 1].getBoundingClientRect().right - this.inputSearch.input.getBoundingClientRect().left) + 'px');\n } else {\n this.inputSearch.input.style.removeProperty('--paddingLeft');\n }\n };\n\n const helper = document.createElement('div');\n helper.classList.add('search-helper');\n helper.addEventListener('click', (e) => {\n const target = findUpClassName(e.target, 'selector-user');\n if(!target) {\n return;\n }\n\n const key = target.dataset.key;\n if(key.indexOf('date_') === 0) {\n const [_, minDate, maxDate] = key.split('_');\n selectedMinDate = +minDate;\n selectedMaxDate = +maxDate;\n } else {\n selectedPeerId = key.toPeerId();\n }\n\n target.addEventListener('click', () => {\n unselectEntity(target);\n });\n\n this.inputSearch.container.append(target);\n this.inputSearch.onChange(this.inputSearch.value = '');\n pickedElements.push(target);\n updatePicked();\n });\n\n searchSuper.nav.parentElement.append(helper);\n\n const renderEntity = (key: PeerId | string, title?: string | HTMLElement) => {\n const div = document.createElement('div');\n div.classList.add('selector-user'/* , 'scale-in' */);\n\n const avatarEl = new AvatarElement();\n avatarEl.classList.add('selector-user-avatar', 'tgico', 'avatar-30');\n avatarEl.isDialog = true;\n\n div.dataset.key = '' + key;\n if(key.isPeerId()) {\n if(title === undefined) {\n title = new PeerTitle({peerId: key.toPeerId()}).element;\n }\n\n avatarEl.updateWithOptions({peerId: key as PeerId});\n } else {\n avatarEl.classList.add('tgico-calendarfilter');\n }\n\n if(title) {\n if(typeof(title) === 'string') {\n div.innerHTML = title;\n } else {\n replaceContent(div, title);\n div.append(title);\n }\n }\n\n div.insertAdjacentElement('afterbegin', avatarEl);\n\n return div;\n };\n\n const unselectEntity = (target: HTMLElement) => {\n const key = target.dataset.key;\n if(key.indexOf('date_') === 0) {\n selectedMinDate = selectedMaxDate = 0;\n } else {\n selectedPeerId = ''.toPeerId();\n }\n \n target.remove();\n indexOfAndSplice(pickedElements, target);\n\n setTimeout(() => {\n updatePicked();\n this.inputSearch.onChange(this.inputSearch.value);\n }, 0);\n };\n\n this.inputSearch.onClear = () => {\n pickedElements.forEach(el => {\n unselectEntity(el);\n });\n };\n\n this.inputSearch.onChange = (value) => {\n searchSuper.cleanupHTML();\n searchSuper.setQuery({\n peerId: selectedPeerId, \n folderId: selectedPeerId ? undefined : 0,\n query: value,\n minDate: selectedMinDate,\n maxDate: selectedMaxDate\n });\n searchSuper.load(true);\n\n helper.innerHTML = '';\n searchSuper.nav.classList.remove('hide');\n if(!value) {\n }\n \n if(!selectedPeerId && value.trim()) {\n const middleware = searchSuper.middleware.get();\n Promise.all([\n // appMessagesManager.getConversationsAll(value).then(dialogs => dialogs.map(d => d.peerId)),\n appMessagesManager.getConversations(value).promise.then(({dialogs}) => dialogs.map(d => d.peerId)),\n appUsersManager.getContactsPeerIds(value, true)\n ]).then(results => {\n if(!middleware()) return;\n const peerIds = new Set(results[0].concat(results[1]));\n \n peerIds.forEach(peerId => {\n helper.append(renderEntity(peerId));\n });\n \n searchSuper.nav.classList.toggle('hide', !!helper.innerHTML);\n //console.log('got peerIds by value:', value, [...peerIds]);\n });\n }\n \n if(!selectedMinDate && value.trim()) {\n const dates: DateData[] = [];\n fillTipDates(value, dates);\n dates.forEach(dateData => {\n helper.append(renderEntity('date_' + dateData.minDate + '_' + dateData.maxDate, dateData.title));\n });\n\n searchSuper.nav.classList.toggle('hide', !!helper.innerHTML);\n }\n };\n\n searchSuper.tabs.inputMessagesFilterEmpty.addEventListener('mousedown', (e) => {\n const target = findUpTag(e.target, 'LI') as HTMLElement;\n if(!target) {\n return;\n }\n\n const searchGroup = findUpClassName(target, 'search-group');\n if(!searchGroup || searchGroup.classList.contains('search-group-recent') || searchGroup.classList.contains('search-group-people')) {\n return;\n }\n\n const peerId = target.getAttribute('data-peer-id').toPeerId();\n appStateManager.getState().then(state => {\n const recentSearch = state.recentSearch || [];\n if(recentSearch[0] !== peerId) {\n indexOfAndSplice(recentSearch, peerId);\n recentSearch.unshift(peerId);\n if(recentSearch.length > 20) {\n recentSearch.length = 20;\n }\n \n appStateManager.pushToState('recentSearch', recentSearch);\n for(const peerId of recentSearch) {\n appStateManager.requestPeer(peerId, 'recentSearch');\n }\n }\n });\n }, {capture: true});\n\n let peopleContainer = document.createElement('div');\n peopleContainer.classList.add('search-group-scrollable');\n peopleContainer.append(this.searchGroups.people.list);\n this.searchGroups.people.container.append(peopleContainer);\n let peopleScrollable = new ScrollableX(peopleContainer);\n\n let first = true;\n let hideNewBtnMenuTimeout: number;\n //const transition = Transition.bind(null, searchContainer.parentElement, 150);\n const transition = TransitionSlider(searchContainer.parentElement, 'zoom-fade', 150, (id) => {\n if(hideNewBtnMenuTimeout) clearTimeout(hideNewBtnMenuTimeout);\n\n if(id === 0 && !first) {\n searchSuper.selectTab(0, false);\n this.inputSearch.onClearClick();\n hideNewBtnMenuTimeout = window.setTimeout(() => {\n hideNewBtnMenuTimeout = 0;\n this.newBtnMenu.classList.remove('is-hidden');\n this.hasUpdate && this.updateBtn.classList.remove('is-hidden');\n }, 150);\n }\n\n first = false;\n });\n\n transition(0);\n\n const activeClassName = 'is-visible';\n const onFocus = () => {\n this.toolsBtn.classList.remove(activeClassName);\n this.backBtn.classList.add(activeClassName);\n this.newBtnMenu.classList.add('is-hidden');\n this.updateBtn.classList.add('is-hidden');\n this.toolsBtn.parentElement.firstElementChild.classList.toggle('state-back', true);\n\n const navigationType: NavigationItem['type'] = 'global-search';\n if(!IS_MOBILE_SAFARI && !appNavigationController.findItemByType(navigationType)) {\n appNavigationController.pushItem({\n onPop: () => {\n close();\n },\n type: navigationType\n });\n }\n\n transition(1);\n };\n\n this.inputSearch.input.addEventListener('focus', onFocus);\n onFocus();\n\n this.backBtn.addEventListener('click', (e) => {\n this.toolsBtn.classList.add(activeClassName);\n this.backBtn.classList.remove(activeClassName);\n this.toolsBtn.parentElement.firstElementChild.classList.toggle('state-back', false);\n\n appNavigationController.removeByType('global-search');\n\n transition(0);\n });\n\n const clearRecentSearchBtn = ButtonIcon('close');\n this.searchGroups.recent.nameEl.append(clearRecentSearchBtn);\n clearRecentSearchBtn.addEventListener('click', () => {\n confirmationPopup({\n descriptionLangKey: 'Search.Confirm.ClearHistory',\n button: {\n langKey: 'ClearButton',\n isDanger: true\n }\n }).then(() => {\n appStateManager.getState().then(state => {\n this.searchGroups.recent.clear();\n \n const recentSearch = state.recentSearch || [];\n for(const peerId of recentSearch) {\n appStateManager.releaseSinglePeer(peerId, 'recentSearch');\n }\n\n recentSearch.length = 0;\n appStateManager.pushToState('recentSearch', recentSearch);\n });\n });\n });\n }\n}\n\nexport type SettingSectionOptions = {\n name?: LangPackKey, \n nameArgs?: FormatterArguments,\n caption?: LangPackKey | true,\n noDelimiter?: boolean,\n fakeGradientDelimiter?: boolean,\n noShadow?: boolean,\n // fullWidth?: boolean,\n // noPaddingTop?: boolean\n};\n\nconst className = 'sidebar-left-section';\nexport class SettingSection {\n public container: HTMLElement;\n public innerContainer: HTMLElement;\n public content: HTMLElement;\n public title: HTMLElement;\n public caption: HTMLElement;\n\n private fullWidth: boolean;\n\n constructor(options: SettingSectionOptions = {}) {\n const container = this.container = document.createElement('div');\n container.classList.add(className + '-container');\n\n const innerContainer = this.innerContainer = document.createElement('div');\n innerContainer.classList.add(className);\n\n if(options.noShadow) {\n innerContainer.classList.add('no-shadow');\n }\n\n if(options.fakeGradientDelimiter) {\n innerContainer.append(generateDelimiter());\n innerContainer.classList.add('with-fake-delimiter');\n } else if(!options.noDelimiter) {\n const hr = document.createElement('hr');\n innerContainer.append(hr);\n } else {\n innerContainer.classList.add('no-delimiter');\n }\n\n // if(options.fullWidth) {\n // this.fullWidth = true;\n // }\n\n // if(options.noPaddingTop) {\n // innerContainer.classList.add('no-padding-top');\n // }\n\n const content = this.content = this.generateContentElement();\n\n if(options.name) {\n const title = this.title = document.createElement('div');\n title.classList.add('sidebar-left-h2', className + '-name');\n i18n_({element: title, key: options.name, args: options.nameArgs});\n content.append(title);\n }\n\n container.append(innerContainer);\n\n if(options.caption) {\n const caption = this.caption = this.generateContentElement();\n caption.classList.add(className + '-caption');\n container.append(caption);\n\n if(options.caption !== true) {\n i18n_({element: caption, key: options.caption});\n }\n }\n }\n\n public generateContentElement() {\n const content = document.createElement('div');\n content.classList.add(className + '-content');\n\n // if(this.fullWidth) {\n // content.classList.add('full-width');\n // }\n\n this.innerContainer.append(content);\n return content;\n }\n}\n\nexport const generateSection = (appendTo: Scrollable, name?: LangPackKey, caption?: LangPackKey) => {\n const section = new SettingSection({name, caption});\n appendTo.append(section.container);\n return section.content;\n};\n\nexport const generateDelimiter = () => {\n const delimiter = document.createElement('div');\n delimiter.classList.add('gradient-delimiter');\n return delimiter;\n};\n\nexport class SettingChatListSection extends SettingSection {\n public sortedList: SortedUserList;\n\n constructor(options: SettingSectionOptions & {sortedList: SortedUserList}) {\n super(options);\n\n this.sortedList = options.sortedList;\n\n this.content.append(this.sortedList.list);\n }\n\n public makeButton(options: ButtonOptions) {\n const button = Button('folder-category-button btn btn-primary btn-transparent', options);\n if(this.title) this.content.insertBefore(button, this.title.nextSibling);\n else this.content.prepend(button);\n return button;\n }\n}\n\nconst appSidebarLeft = new AppSidebarLeft();\nMOUNT_CLASS_TO.appSidebarLeft = appSidebarLeft;\nexport default appSidebarLeft;\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport rootScope from \"../../lib/rootScope\";\r\n//import { generatePathData } from \"../../helpers/dom\";\r\nimport { MyMessage } from \"../../lib/appManagers/appMessagesManager\";\r\nimport type Chat from \"./chat\";\r\nimport indexOfAndSplice from \"../../helpers/array/indexOfAndSplice\";\r\nimport findAndSplice from \"../../helpers/array/findAndSplice\";\r\n\r\ntype Group = {bubble: HTMLElement, mid: number, timestamp: number}[];\r\ntype BubbleGroup = {timestamp: number, fromId: PeerId, mid: number, group: Group};\r\nexport default class BubbleGroups {\r\n private bubbles: Array<BubbleGroup> = []; // map to group\r\n private detailsMap: Map<HTMLElement, BubbleGroup> = new Map();\r\n private groups: Array<Group> = [];\r\n //updateRAFs: Map<HTMLElement[], number> = new Map();\r\n private newGroupDiff = 121; // * 121 in scheduled messages\r\n\r\n constructor(private chat: Chat) {\r\n\r\n }\r\n\r\n removeBubble(bubble: HTMLElement) {\r\n const details = this.detailsMap.get(bubble);\r\n if(details) {\r\n if(details.group.length) {\r\n findAndSplice(details.group, d => d.bubble === bubble);\r\n if(!details.group.length) {\r\n indexOfAndSplice(this.groups, details.group);\r\n } else {\r\n this.updateGroup(details.group);\r\n }\r\n }\r\n \r\n this.detailsMap.delete(bubble);\r\n }\r\n }\r\n\r\n changeBubbleMid(bubble: HTMLElement, mid: number) {\r\n const details = this.detailsMap.get(bubble);\r\n if(details) {\r\n details.mid = mid;\r\n }\r\n }\r\n \r\n addBubble(bubble: HTMLElement, message: MyMessage, reverse: boolean) {\r\n //return;\r\n\r\n const timestamp = message.date;\r\n const mid = message.mid;\r\n let fromId = message.viaBotId || message.fromId;\r\n let group: Group;\r\n\r\n // fix for saved messages forward to self\r\n if(fromId === rootScope.myId && message.peerId === rootScope.myId && (message as any).fwdFromId === fromId) {\r\n fromId = fromId.toPeerId(true);\r\n }\r\n \r\n // try to find added\r\n this.removeBubble(bubble);\r\n \r\n const insertObject = {bubble, mid, timestamp};\r\n if(this.bubbles.length) {\r\n let foundBubble: BubbleGroup;\r\n let foundAtIndex = -1;\r\n for(let i = 0; i < this.bubbles.length; ++i) {\r\n const bubble = this.bubbles[i];\r\n const diff = Math.abs(bubble.timestamp - timestamp);\r\n const good = bubble.fromId === fromId && diff <= this.newGroupDiff;\r\n\r\n if(good) {\r\n foundAtIndex = i;\r\n\r\n if(this.chat.type === 'scheduled') {\r\n break;\r\n }\r\n } else {\r\n foundAtIndex = -1;\r\n }\r\n\r\n if(this.chat.type !== 'scheduled') {\r\n if(mid > bubble.mid) {\r\n break;\r\n }\r\n }\r\n }\r\n\r\n if(foundAtIndex !== -1) {\r\n foundBubble = this.bubbles[foundAtIndex];\r\n }\r\n /* const foundBubble = this.bubbles.find(bubble => {\r\n const diff = Math.abs(bubble.timestamp - timestamp);\r\n return bubble.fromId === fromId && diff <= this.newGroupDiff;\r\n }); */\r\n\r\n if(!foundBubble) this.groups.push(group = [insertObject]);\r\n else {\r\n group = foundBubble.group;\r\n \r\n let i = 0, foundMidOnSameTimestamp = 0;\r\n for(; i < group.length; ++i) {\r\n const _timestamp = group[i].timestamp;\r\n const _mid = group[i].mid;\r\n\r\n if(timestamp < _timestamp) {\r\n break;\r\n } else if(timestamp === _timestamp) {\r\n foundMidOnSameTimestamp = _mid;\r\n } \r\n \r\n if(foundMidOnSameTimestamp && mid < foundMidOnSameTimestamp) {\r\n break;\r\n }\r\n }\r\n\r\n group.splice(i, 0, insertObject);\r\n }\r\n } else {\r\n this.groups.push(group = [insertObject]);\r\n }\r\n\r\n //console.log('[BUBBLE]: addBubble', bubble, message.mid, fromId, reverse, group);\r\n\r\n const bubbleGroup = {timestamp, fromId, mid: message.mid, group};\r\n let insertIndex = 0;\r\n for(; insertIndex < this.bubbles.length; ++insertIndex) {\r\n if(this.bubbles[insertIndex].mid < mid) {\r\n break;\r\n }\r\n }\r\n \r\n this.bubbles.splice(insertIndex, 0, {timestamp, fromId, mid: message.mid, group});\r\n this.updateGroup(group);\r\n\r\n this.detailsMap.set(bubble, bubbleGroup);\r\n }\r\n\r\n /* setClipIfNeeded(bubble: HTMLDivElement, remove = false) {\r\n //console.log('setClipIfNeeded', bubble, remove);\r\n const className = bubble.className;\r\n if(className.includes('is-message-empty') && (className.includes('photo') || className.includes('video'))) {\r\n let container = bubble.querySelector('.bubble__media-container') as SVGSVGElement;\r\n //console.log('setClipIfNeeded', bubble, remove, container);\r\n if(!container) return;\r\n\r\n try {\r\n Array.from(container.children).forEach(object => {\r\n if(object instanceof SVGDefsElement) return;\r\n \r\n if(remove) {\r\n object.removeAttributeNS(null, 'clip-path');\r\n } else {\r\n let clipId = container.dataset.clipId;\r\n let path = container.firstElementChild.firstElementChild.lastElementChild as SVGPathElement;\r\n let width = +object.getAttributeNS(null, 'width');\r\n let height = +object.getAttributeNS(null, 'height');\r\n let isOut = className.includes('is-out');\r\n let isReply = className.includes('is-reply');\r\n let d = '';\r\n \r\n //console.log('setClipIfNeeded', object, width, height, isOut);\r\n \r\n let tr: number, tl: number;\r\n if(className.includes('forwarded') || isReply) {\r\n tr = tl = 0;\r\n } else if(isOut) {\r\n tr = className.includes('is-group-first') ? 12 : 6;\r\n tl = 12;\r\n } else {\r\n tr = 12;\r\n tl = className.includes('is-group-first') ? 12 : 6;\r\n }\r\n \r\n if(isOut) {\r\n d = generatePathData(0, 0, width - 9, height, tl, tr, 0, 12);\r\n } else {\r\n d = generatePathData(9, 0, width - 9, height, tl, tr, 12, 0);\r\n }\r\n \r\n path.setAttributeNS(null, 'd', d);\r\n object.setAttributeNS(null, 'clip-path', 'url(#' + clipId + ')');\r\n }\r\n });\r\n } catch(err) {}\r\n }\r\n } */\r\n \r\n updateGroup(group: Group) {\r\n /* if(this.updateRAFs.has(group)) {\r\n window.cancelAnimationFrame(this.updateRAFs.get(group));\r\n this.updateRAFs.delete(group);\r\n } */\r\n \r\n //this.updateRAFs.set(group, window.requestAnimationFrame(() => {\r\n //this.updateRAFs.delete(group);\r\n \r\n if(!group.length) {\r\n return;\r\n }\r\n \r\n const first = group[0].bubble;\r\n\r\n //console.log('[BUBBLE]: updateGroup', group, first);\r\n \r\n if(group.length === 1) {\r\n first.classList.add('is-group-first', 'is-group-last');\r\n //this.setClipIfNeeded(first);\r\n return;\r\n } else {\r\n first.classList.remove('is-group-last');\r\n first.classList.add('is-group-first');\r\n //this.setClipIfNeeded(first, true);\r\n }\r\n \r\n const length = group.length - 1;\r\n for(let i = 1; i < length; ++i) {\r\n const bubble = group[i].bubble;\r\n bubble.classList.remove('is-group-last', 'is-group-first');\r\n //this.setClipIfNeeded(bubble, true);\r\n }\r\n \r\n const last = group[group.length - 1].bubble;\r\n last.classList.remove('is-group-first');\r\n last.classList.add('is-group-last');\r\n //this.setClipIfNeeded(last);\r\n //}));\r\n }\r\n\r\n updateGroupByMessageId(mid: number) {\r\n const details = this.bubbles.find(g => g.mid === mid);\r\n if(details) {\r\n this.updateGroup(details.group);\r\n }\r\n }\r\n \r\n cleanup() {\r\n this.bubbles = [];\r\n this.groups = [];\r\n this.detailsMap.clear();\r\n /* for(let value of this.updateRAFs.values()) {\r\n window.cancelAnimationFrame(value);\r\n }\r\n this.updateRAFs.clear(); */\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport PopupElement, { PopupOptions } from \".\";\r\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\r\nimport mediaSizes from \"../../helpers/mediaSizes\";\r\nimport I18n, { i18n, LangPackKey } from \"../../lib/langPack\";\r\nimport InputField from \"../inputField\";\r\n\r\nexport default class PopupDatePicker extends PopupElement {\r\n protected controlsDiv: HTMLElement;\r\n protected monthTitle: HTMLElement;\r\n protected prevBtn: HTMLElement;\r\n protected nextBtn: HTMLElement;\r\n\r\n protected monthsContainer: HTMLElement;\r\n protected month: HTMLElement;\r\n\r\n protected minMonth: Date;\r\n protected maxMonth: Date;\r\n protected minDate: Date;\r\n protected maxDate: Date;\r\n protected selectedDate: Date;\r\n protected selectedMonth: Date;\r\n protected selectedEl: HTMLElement;\r\n\r\n protected timeDiv: HTMLDivElement;\r\n protected hoursInputField: InputField;\r\n protected minutesInputField: InputField;\r\n\r\n constructor(initDate: Date, public onPick: (timestamp: number) => void, protected options: Partial<{\r\n noButtons: true, \r\n noTitle: true, \r\n minDate: Date,\r\n maxDate: Date\r\n withTime: true,\r\n showOverflowMonths: true\r\n }> & PopupOptions = {}) {\r\n super('popup-date-picker', options.noButtons ? [] : [{\r\n langKey: 'JumpToDate',\r\n callback: () => {\r\n if(this.onPick) {\r\n this.onPick(this.selectedDate.getTime() / 1000 | 0);\r\n }\r\n }\r\n }, {\r\n langKey: 'Cancel',\r\n isCancel: true\r\n }], {body: true, overlayClosable: true, ...options});\r\n\r\n this.minDate = options.minDate || new Date('2013-08-01T00:00:00');\r\n\r\n if(initDate < this.minDate) {\r\n initDate.setFullYear(this.minDate.getFullYear(), this.minDate.getMonth(), this.minDate.getDate());\r\n }\r\n\r\n // Controls\r\n this.controlsDiv = document.createElement('div');\r\n this.controlsDiv.classList.add('date-picker-controls');\r\n\r\n this.prevBtn = document.createElement('button');\r\n this.prevBtn.classList.add('btn-icon', 'tgico-down', 'date-picker-prev');\r\n attachClickEvent(this.prevBtn, this.onPrevClick, {listenerSetter: this.listenerSetter});\r\n\r\n this.nextBtn = document.createElement('button');\r\n this.nextBtn.classList.add('btn-icon', 'tgico-down', 'date-picker-next');\r\n attachClickEvent(this.nextBtn, this.onNextClick, {listenerSetter: this.listenerSetter});\r\n \r\n this.monthTitle = document.createElement('div');\r\n this.monthTitle.classList.add('date-picker-month-title');\r\n\r\n this.controlsDiv.append(this.prevBtn, this.monthTitle, this.nextBtn);\r\n\r\n // Month\r\n this.monthsContainer = document.createElement('div');\r\n this.monthsContainer.classList.add('date-picker-months');\r\n attachClickEvent(this.monthsContainer, this.onDateClick, {listenerSetter: this.listenerSetter});\r\n\r\n this.body.append(this.controlsDiv, this.monthsContainer);\r\n\r\n // Time inputs\r\n if(options.withTime) {\r\n this.timeDiv = document.createElement('div');\r\n this.timeDiv.classList.add('date-picker-time');\r\n\r\n const delimiter = document.createElement('div');\r\n delimiter.classList.add('date-picker-time-delimiter');\r\n delimiter.append(':');\r\n\r\n const handleTimeInput = (max: number, inputField: InputField, onInput: (length: number) => void, onOverflow?: (number: number) => void) => {\r\n const maxString = '' + max;\r\n this.listenerSetter.add(inputField.input)('input', (e) => {\r\n let value = inputField.value.replace(/\\D/g, '');\r\n if(value.length > 2) {\r\n value = value.slice(0, 2);\r\n } else {\r\n if((value.length === 1 && +value[0] > +maxString[0]) || (value.length === 2 && +value > max)) {\r\n if(value.length === 2 && onOverflow) {\r\n onOverflow(+value[1]);\r\n }\r\n\r\n value = '0' + value[0];\r\n }\r\n }\r\n\r\n inputField.setValueSilently(value);\r\n onInput(value.length);\r\n });\r\n };\r\n\r\n this.hoursInputField = new InputField({plainText: true});\r\n this.minutesInputField = new InputField({plainText: true});\r\n\r\n handleTimeInput(23, this.hoursInputField, (length) => {\r\n if(length === 2) {\r\n this.minutesInputField.input.focus();\r\n }\r\n\r\n this.setTimeTitle();\r\n }, (number) => {\r\n this.minutesInputField.value = (number + this.minutesInputField.value).slice(0, 2);\r\n });\r\n handleTimeInput(59, this.minutesInputField, (length) => {\r\n if(!length) {\r\n this.hoursInputField.input.focus();\r\n }\r\n\r\n this.setTimeTitle();\r\n });\r\n\r\n this.selectedDate = initDate;\r\n\r\n initDate.setMinutes(initDate.getMinutes() + 10);\r\n \r\n this.hoursInputField.setValueSilently(('0' + initDate.getHours()).slice(-2));\r\n this.minutesInputField.setValueSilently(('0' + initDate.getMinutes()).slice(-2));\r\n\r\n initDate.setHours(0, 0, 0, 0);\r\n \r\n this.timeDiv.append(this.hoursInputField.container, delimiter, this.minutesInputField.container);\r\n\r\n attachClickEvent(this.btnConfirm, () => {\r\n if(this.onPick) {\r\n this.selectedDate.setHours(+this.hoursInputField.value || 0, +this.minutesInputField.value || 0, 0, 0);\r\n this.onPick(this.selectedDate.getTime() / 1000 | 0);\r\n }\r\n\r\n this.hide();\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n this.body.append(this.timeDiv);\r\n\r\n this.prevBtn.classList.add('primary');\r\n this.nextBtn.classList.add('primary');\r\n }\r\n\r\n const popupCenterer = document.createElement('div');\r\n popupCenterer.classList.add('popup-centerer');\r\n popupCenterer.append(this.container);\r\n this.element.append(popupCenterer);\r\n\r\n //const passed = (initDate.getTime() - (initDate.getTimezoneOffset() * 60000)) % 86400000;\r\n //this.selectedDate = this.maxDate = new Date(initDate.getTime() - passed);\r\n initDate.setHours(0, 0, 0, 0);\r\n this.selectedDate = initDate;\r\n\r\n this.maxDate = options.maxDate || new Date();\r\n this.maxDate.setHours(0, 0, 0, 0);\r\n\r\n this.selectedMonth = new Date(this.selectedDate);\r\n this.selectedMonth.setDate(1);\r\n\r\n this.maxMonth = new Date(this.maxDate);\r\n this.maxMonth.setDate(1);\r\n\r\n this.minMonth = new Date(this.minDate);\r\n this.minMonth.setHours(0, 0, 0, 0);\r\n this.minMonth.setDate(1);\r\n\r\n if(this.selectedMonth.getTime() === this.minMonth.getTime()) {\r\n this.prevBtn.setAttribute('disabled', 'true');\r\n }\r\n\r\n if(this.selectedMonth.getTime() === this.maxMonth.getTime()) {\r\n this.nextBtn.setAttribute('disabled', 'true');\r\n }\r\n\r\n if(options.noTitle) {\r\n this.setTitle = () => {};\r\n }\r\n\r\n this.setTimeTitle();\r\n this.setTitle();\r\n this.setMonth();\r\n }\r\n\r\n onPrevClick = (e: MouseEvent) => {\r\n this.selectedMonth.setMonth(this.selectedMonth.getMonth() - 1);\r\n this.setMonth();\r\n\r\n if(this.selectedMonth.getTime() === this.minMonth.getTime()) {\r\n this.prevBtn.setAttribute('disabled', 'true');\r\n }\r\n \r\n this.nextBtn.removeAttribute('disabled');\r\n };\r\n\r\n onNextClick = (e: MouseEvent) => {\r\n this.selectedMonth.setMonth(this.selectedMonth.getMonth() + 1);\r\n this.setMonth();\r\n\r\n if(this.selectedMonth.getTime() === this.maxMonth.getTime()) {\r\n this.nextBtn.setAttribute('disabled', 'true');\r\n }\r\n\r\n this.prevBtn.removeAttribute('disabled');\r\n };\r\n\r\n onDateClick = (e: MouseEvent) => {\r\n //cancelEvent(e);\r\n const target = e.target as HTMLElement;\r\n\r\n if(!target.dataset.timestamp) return;\r\n\r\n if(this.selectedEl) {\r\n if(this.selectedEl === target) return;\r\n this.selectedEl.classList.remove('active');\r\n }\r\n\r\n this.selectedEl = target;\r\n \r\n target.classList.add('active');\r\n const timestamp = +target.dataset.timestamp;\r\n\r\n this.selectedDate = new Date(timestamp);\r\n\r\n this.setTitle();\r\n this.setTimeTitle();\r\n };\r\n\r\n public setTimeTitle() {\r\n if(this.btnConfirm && this.selectedDate) {\r\n let key: LangPackKey, args: any[] = [];\r\n const date = new Date();\r\n date.setHours(0, 0, 0, 0);\r\n\r\n const timeOptions: Intl.DateTimeFormatOptions = {\r\n minute: '2-digit',\r\n hour: '2-digit'\r\n };\r\n \r\n const sendDate = new Date(this.selectedDate.getTime());\r\n sendDate.setHours(+this.hoursInputField.value, +this.minutesInputField.value);\r\n\r\n if(this.selectedDate.getTime() === date.getTime()) {\r\n key = 'Schedule.SendToday';\r\n }/* else if(this.selectedDate.getTime() === (date.getTime() + 86400e3)) {\r\n dayStr = 'Tomorrow';\r\n } */ else {\r\n key = 'Schedule.SendDate';\r\n\r\n const dateOptions: Intl.DateTimeFormatOptions = {\r\n month: 'short',\r\n day: 'numeric'\r\n };\r\n\r\n if(sendDate.getFullYear() !== date.getFullYear()) {\r\n dateOptions.year = 'numeric';\r\n }\r\n\r\n args.push(new I18n.IntlDateElement({\r\n date: sendDate,\r\n options: dateOptions\r\n }).element);\r\n }\r\n\r\n args.push(new I18n.IntlDateElement({\r\n date: sendDate,\r\n options: timeOptions\r\n }).element);\r\n\r\n this.btnConfirm.firstChild.replaceWith(i18n(key, args));\r\n }\r\n }\r\n\r\n public setTitle() {\r\n //const splitted = this.selectedDate.toString().split(' ', 3);\r\n //this.title.innerText = splitted[0] + ', ' + splitted[1] + ' ' + splitted[2];\r\n this.title.textContent = '';\r\n this.title.append(new I18n.IntlDateElement({\r\n date: this.selectedDate,\r\n options: {\r\n day: 'numeric',\r\n month: 'long',\r\n weekday: 'short'\r\n }\r\n }).element);\r\n }\r\n\r\n private renderElement(disabled: boolean, innerText: string | HTMLElement = '') {\r\n const el = document.createElement('button');\r\n el.classList.add('btn-icon', 'date-picker-month-date');\r\n\r\n if(disabled) {\r\n el.setAttribute('disabled', 'true');\r\n }\r\n\r\n if(innerText) {\r\n el.append(innerText);\r\n }\r\n\r\n return el;\r\n }\r\n\r\n public setMonth() {\r\n const firstDate = new Date(this.selectedMonth);\r\n\r\n const options: Intl.DateTimeFormatOptions = {\r\n year: 'numeric',\r\n month: this.timeDiv && mediaSizes.isMobile ? 'short' : 'long'\r\n };\r\n\r\n this.monthTitle.textContent = '';\r\n this.monthTitle.append(new I18n.IntlDateElement({date: firstDate, options}).element);\r\n //this.monthTitle.innerText = (this.timeDiv && mediaSizes.isMobile ? monthName.slice(0, 3) : monthName) + ' ' + this.selectedMonth.getFullYear();\r\n\r\n if(this.month) {\r\n this.month.remove();\r\n }\r\n\r\n this.month = document.createElement('div');\r\n this.month.classList.add('date-picker-month');\r\n\r\n const weekStartDate = new Date();\r\n const day = weekStartDate.getDay();\r\n if(day !== 1) {\r\n weekStartDate.setHours(-24 * (day - 1)); \r\n }\r\n\r\n for(let i = 0; i < 7; ++i) {\r\n const el = this.renderElement(true, new I18n.IntlDateElement({date: weekStartDate, options: {weekday: 'narrow'}}).element);\r\n el.classList.remove('date-picker-month-date');\r\n el.classList.add('date-picker-month-day');\r\n this.month.append(el);\r\n weekStartDate.setDate(weekStartDate.getDate() + 1);\r\n }\r\n\r\n // 0 - sunday\r\n let dayIndex = firstDate.getDay() - 1;\r\n if(dayIndex === -1) dayIndex = 7 - 1;\r\n\r\n const clonedDate = new Date(firstDate.getTime());\r\n clonedDate.setDate(clonedDate.getDate() - dayIndex - 1);\r\n\r\n // Padding first week\r\n for(let i = 0; i < dayIndex; ++i) {\r\n if(this.options.showOverflowMonths) {\r\n clonedDate.setDate(clonedDate.getDate() + 1);\r\n this.month.append(this.renderElement(true, '' + clonedDate.getDate()));\r\n } else {\r\n this.month.append(this.renderElement(true));\r\n }\r\n }\r\n\r\n do {\r\n const date = firstDate.getDate();\r\n const el = this.renderElement(firstDate > this.maxDate || firstDate < this.minDate, '' + date);\r\n el.dataset.timestamp = '' + firstDate.getTime();\r\n\r\n if(firstDate.getTime() === this.selectedDate.getTime()) {\r\n this.selectedEl = el;\r\n el.classList.add('active');\r\n }\r\n\r\n this.month.append(el);\r\n\r\n firstDate.setDate(date + 1);\r\n } while(firstDate.getDate() !== 1);\r\n\r\n const remainder = this.month.childElementCount % 7;\r\n if(this.options.showOverflowMonths && remainder) {\r\n for(let i = remainder; i < 7; ++i) {\r\n this.month.append(this.renderElement(true, '' + firstDate.getDate()));\r\n firstDate.setDate(firstDate.getDate() + 1);\r\n }\r\n }\r\n\r\n const lines = Math.ceil(this.month.childElementCount / 7);\r\n this.container.dataset.lines = '' + lines;\r\n\r\n this.monthsContainer.append(this.month);\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nexport default class StickyIntersector {\r\n private headersObserver: IntersectionObserver;\r\n private elementsObserver: IntersectionObserver;\r\n\r\n constructor(private container: HTMLElement, private handler: (stuck: boolean, target: HTMLElement) => void) {\r\n this.observeHeaders();\r\n this.observeElements();\r\n }\r\n\r\n /**\r\n * Sets up an intersection observer to notify when elements with the class\r\n * `.sticky_sentinel--top` become visible/invisible at the top of the container.\r\n * @param {!Element} container\r\n */\r\n private observeHeaders() {\r\n this.headersObserver = new IntersectionObserver((entries) => {\r\n for(const entry of entries) {\r\n const targetInfo = entry.boundingClientRect;\r\n const stickyTarget = entry.target.parentElement;\r\n const rootBoundsInfo = entry.rootBounds;\r\n \r\n // Started sticking.\r\n if(targetInfo.bottom < rootBoundsInfo.top) {\r\n this.handler(true, stickyTarget);\r\n }\r\n \r\n // Stopped sticking.\r\n if(targetInfo.bottom >= rootBoundsInfo.top &&\r\n targetInfo.bottom < rootBoundsInfo.bottom) {\r\n this.handler(false, stickyTarget);\r\n }\r\n }\r\n }, {threshold: 0, root: this.container});\r\n }\r\n \r\n private observeElements() {\r\n this.elementsObserver = new IntersectionObserver((entries) => {\r\n const entry = entries\r\n .filter(entry => entry.boundingClientRect.top < entry.rootBounds.top)\r\n .sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top)[0];\r\n if(!entry) return;\r\n\r\n const container = entry.isIntersecting ? entry.target : entry.target.nextElementSibling;\r\n this.handler(true, container as HTMLElement);\r\n }, {root: this.container});\r\n }\r\n\r\n /**\r\n * @param {!Element} container\r\n * @param {string} className\r\n */\r\n private addSentinel(container: HTMLElement, className: string) {\r\n const sentinel = document.createElement('div');\r\n sentinel.classList.add('sticky_sentinel', className);\r\n return container.appendChild(sentinel);\r\n }\r\n\r\n /**\r\n * Notifies when elements w/ the `sticky` class begin to stick or stop sticking.\r\n * Note: the elements should be children of `container`.\r\n * @param {!Element} container\r\n */\r\n public observeStickyHeaderChanges(element: HTMLElement) {\r\n const headerSentinel = this.addSentinel(element, 'sticky_sentinel--top');\r\n this.headersObserver.observe(headerSentinel);\r\n\r\n this.elementsObserver.observe(element);\r\n }\r\n\r\n public disconnect() {\r\n this.headersObserver.disconnect();\r\n this.elementsObserver.disconnect();\r\n }\r\n\r\n public unobserve(element: HTMLElement, headerSentinel: HTMLElement) {\r\n this.elementsObserver.unobserve(element);\r\n this.headersObserver.unobserve(headerSentinel);\r\n }\r\n}","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport callbackify from \"../../helpers/callbackify\";\nimport formatNumber from \"../../helpers/number/formatNumber\";\nimport { fastRaf } from \"../../helpers/schedulers\";\nimport { MessagePeerReaction, ReactionCount } from \"../../layer\";\nimport appPeersManager from \"../../lib/appManagers/appPeersManager\";\nimport appReactionsManager from \"../../lib/appManagers/appReactionsManager\";\nimport RLottiePlayer from \"../../lib/rlottie/rlottiePlayer\";\nimport SetTransition from \"../singleTransition\";\nimport StackedAvatars from \"../stackedAvatars\";\nimport { wrapSticker, wrapStickerAnimation } from \"../wrappers\";\n\nconst CLASS_NAME = 'reaction';\nconst TAG_NAME = CLASS_NAME + '-element';\nconst REACTION_INLINE_SIZE = 14;\nconst REACTION_BLOCK_SIZE = 22;\n\nexport const REACTION_DISPLAY_INLINE_COUNTER_AT = 2;\nexport const REACTION_DISPLAY_BLOCK_COUNTER_AT = 4;\n\nexport type ReactionLayoutType = 'block' | 'inline';\n\nexport default class ReactionElement extends HTMLElement {\n private type: ReactionLayoutType;\n private counter: HTMLElement;\n private stickerContainer: HTMLElement;\n private stackedAvatars: StackedAvatars;\n private canRenderAvatars: boolean;\n private _reactionCount: ReactionCount;\n private wrapStickerPromise: ReturnType<typeof wrapSticker>;\n\n constructor() {\n super();\n this.classList.add(CLASS_NAME);\n }\n\n public get reactionCount() {\n return this._reactionCount;\n }\n \n public set reactionCount(reactionCount: ReactionCount) {\n this._reactionCount = reactionCount;\n }\n\n public get count() {\n return this.reactionCount.count;\n }\n\n public init(type: ReactionLayoutType) {\n this.type = type;\n this.classList.add(CLASS_NAME + '-' + type);\n }\n\n public setCanRenderAvatars(canRenderAvatars: boolean) {\n this.canRenderAvatars = canRenderAvatars;\n }\n\n public render(doNotRenderSticker?: boolean) {\n const hadStickerContainer = !!this.stickerContainer;\n if(!hadStickerContainer) {\n this.stickerContainer = document.createElement('div');\n this.stickerContainer.classList.add(CLASS_NAME + '-sticker');\n this.append(this.stickerContainer);\n }\n \n const reactionCount = this.reactionCount;\n if(!doNotRenderSticker && !hadStickerContainer) {\n const availableReaction = appReactionsManager.getReaction(reactionCount.reaction);\n callbackify(availableReaction, (availableReaction) => {\n if(!availableReaction.center_icon) {\n this.stickerContainer.classList.add('is-static');\n }\n\n if(availableReaction.pFlags.inactive) {\n this.classList.add('is-inactive');\n }\n\n const size = this.type === 'inline' ? REACTION_INLINE_SIZE : REACTION_BLOCK_SIZE;\n const wrapPromise = this.wrapStickerPromise = wrapSticker({\n div: this.stickerContainer,\n doc: availableReaction.center_icon ?? availableReaction.static_icon,\n width: size,\n height: size,\n static: true\n }).finally(() => {\n if(this.wrapStickerPromise === wrapPromise) {\n this.wrapStickerPromise = undefined;\n }\n });\n });\n }\n }\n\n public renderCounter() {\n const reactionCount = this.reactionCount;\n const displayOn = this.type === 'inline' ? REACTION_DISPLAY_INLINE_COUNTER_AT : REACTION_DISPLAY_BLOCK_COUNTER_AT;\n if(reactionCount.count >= displayOn || (this.type === 'block' && !this.canRenderAvatars)) {\n if(!this.counter) {\n this.counter = document.createElement(this.type === 'inline' ? 'i' : 'span');\n this.counter.classList.add(CLASS_NAME + '-counter');\n }\n\n const formatted = formatNumber(reactionCount.count);\n if(this.counter.textContent !== formatted) {\n this.counter.textContent = formatted;\n }\n\n if(!this.counter.parentElement) {\n this.append(this.counter);\n }\n } else if(this.counter?.parentElement) {\n this.counter.remove();\n this.counter = undefined;\n }\n }\n\n public renderAvatars(recentReactions: MessagePeerReaction[]) {\n if(this.type === 'inline') {\n return;\n }\n\n if(this.reactionCount.count >= REACTION_DISPLAY_BLOCK_COUNTER_AT || !this.canRenderAvatars) {\n if(this.stackedAvatars) {\n this.stackedAvatars.container.remove();\n this.stackedAvatars = undefined;\n }\n\n return;\n }\n\n if(!this.stackedAvatars) {\n this.stackedAvatars = new StackedAvatars({\n avatarSize: 24\n });\n\n this.append(this.stackedAvatars.container);\n }\n\n this.stackedAvatars.render(recentReactions.map(reaction => appPeersManager.getPeerId(reaction.peer_id)));\n }\n\n public setIsChosen(isChosen = !!this.reactionCount.pFlags.chosen) {\n if(this.type === 'inline') return;\n const wasChosen = this.classList.contains('is-chosen') && !this.classList.contains('backwards');\n if(wasChosen !== isChosen) {\n SetTransition(this, 'is-chosen', isChosen, this.isConnected ? 300 : 0);\n }\n }\n\n public fireAroundAnimation() {\n callbackify(appReactionsManager.getReaction(this.reactionCount.reaction), (availableReaction) => {\n const size = this.type === 'inline' ? REACTION_INLINE_SIZE + 14 : REACTION_BLOCK_SIZE + 18;\n const div = document.createElement('div');\n div.classList.add(CLASS_NAME + '-sticker-activate');\n\n Promise.all([\n wrapSticker({\n div: div,\n doc: availableReaction.center_icon,\n width: size,\n height: size,\n withThumb: false,\n needUpscale: true,\n play: false,\n skipRatio: 1,\n group: 'none',\n needFadeIn: false\n }) as Promise<RLottiePlayer>,\n\n wrapStickerAnimation({\n doc: availableReaction.around_animation,\n size: 80,\n target: this.stickerContainer,\n side: 'center',\n skipRatio: 1,\n play: false\n }).stickerPromise\n ]).then(([iconPlayer, aroundPlayer]) => {\n const remove = () => {\n // if(!isInDOM(div)) return;\n fastRaf(() => {\n // if(!isInDOM(div)) return;\n iconPlayer.remove();\n div.remove();\n this.stickerContainer.classList.remove('has-animation');\n });\n };\n\n iconPlayer.addEventListener('enterFrame', (frameNo) => {\n if(frameNo === iconPlayer.maxFrame) {\n if(this.wrapStickerPromise) { // wait for fade in animation\n this.wrapStickerPromise.then(() => {\n setTimeout(remove, 1e3);\n });\n } else {\n remove();\n }\n }\n });\n\n iconPlayer.addEventListener('firstFrame', () => {\n this.stickerContainer.append(div);\n this.stickerContainer.classList.add('has-animation');\n iconPlayer.play();\n aroundPlayer.play();\n }, {once: true});\n });\n });\n }\n}\n\ncustomElements.define(TAG_NAME, ReactionElement);\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport forEachReverse from \"../../helpers/array/forEachReverse\";\nimport positionElementByIndex from \"../../helpers/dom/positionElementByIndex\";\nimport { Message, ReactionCount } from \"../../layer\";\nimport appReactionsManager from \"../../lib/appManagers/appReactionsManager\";\nimport rootScope from \"../../lib/rootScope\";\nimport ReactionElement, { ReactionLayoutType, REACTION_DISPLAY_BLOCK_COUNTER_AT } from \"./reaction\";\n\nconst CLASS_NAME = 'reactions';\nconst TAG_NAME = CLASS_NAME + '-element';\n\nconst REACTIONS_ELEMENTS: Map<string, Set<ReactionsElement>> = new Map();\nexport {REACTIONS_ELEMENTS};\n\nexport default class ReactionsElement extends HTMLElement {\n private message: Message.message;\n private key: string;\n private isPlaceholder: boolean;\n private type: ReactionLayoutType;\n private sorted: ReactionElement[];\n private onConnectCallback: () => void;\n\n constructor() {\n super();\n this.classList.add(CLASS_NAME);\n this.sorted = [];\n }\n \n connectedCallback() {\n let set = REACTIONS_ELEMENTS.get(this.key);\n if(!set) {\n REACTIONS_ELEMENTS.set(this.key, set = new Set());\n }\n\n set.add(this);\n\n if(this.onConnectCallback && this.isConnected) {\n this.onConnectCallback();\n this.onConnectCallback = undefined;\n }\n }\n\n disconnectedCallback() {\n const set = REACTIONS_ELEMENTS.get(this.key);\n set.delete(this);\n if(!set.size) {\n REACTIONS_ELEMENTS.delete(this.key);\n }\n }\n\n public getReactionCount(reactionElement: ReactionElement) {\n return this.sorted[this.sorted.indexOf(reactionElement)].reactionCount;\n }\n\n public getMessage() {\n return this.message;\n }\n\n public init(message: Message.message, type: ReactionLayoutType, isPlaceholder?: boolean) {\n if(this.key !== undefined) {\n this.disconnectedCallback();\n }\n\n this.message = message;\n this.key = this.message.peerId + '_' + this.message.mid;\n this.isPlaceholder = isPlaceholder;\n\n if(this.type !== type) {\n this.type = type;\n this.classList.add(CLASS_NAME + '-' + type);\n }\n\n this.connectedCallback();\n }\n\n public changeMessage(message: Message.message) {\n return this.init(message, this.type, this.isPlaceholder);\n }\n\n public update(message: Message.message, changedResults?: ReactionCount[]) {\n this.message = message;\n this.render(changedResults);\n }\n\n public render(changedResults?: ReactionCount[]) {\n const reactions = this.message.reactions;\n const hasReactions = !!(reactions && reactions.results.length);\n this.classList.toggle('has-no-reactions', !hasReactions);\n if(!hasReactions && !this.sorted.length) return;\n\n const availableReactionsResult = appReactionsManager.getAvailableReactions();\n // callbackify(availableReactionsResult, () => {\n const counts = hasReactions ? (\n availableReactionsResult instanceof Promise ? \n reactions.results : \n reactions.results.filter(reactionCount => {\n return appReactionsManager.isReactionActive(reactionCount.reaction);\n })\n ) : [];\n\n forEachReverse(this.sorted, (reactionElement, idx, arr) => {\n const reaction = reactionElement.reactionCount.reaction;\n const found = counts.some(reactionCount => reactionCount.reaction === reaction);\n if(!found) {\n arr.splice(idx, 1);\n reactionElement.remove();\n }\n });\n\n const totalReactions = counts.reduce((acc, c) => acc + c.count, 0);\n const canRenderAvatars = reactions && !!reactions.pFlags.can_see_list && totalReactions < REACTION_DISPLAY_BLOCK_COUNTER_AT;\n this.sorted = counts.map((reactionCount, idx) => {\n const reactionElementIdx = this.sorted.findIndex(reactionElement => reactionElement.reactionCount.reaction === reactionCount.reaction);\n let reactionElement = reactionElementIdx !== -1 && this.sorted[reactionElementIdx];\n if(!reactionElement) {\n reactionElement = new ReactionElement();\n reactionElement.init(this.type);\n }\n\n positionElementByIndex(reactionElement, this, idx);\n \n const recentReactions = reactions.recent_reactions ? reactions.recent_reactions.filter(reaction => reaction.reaction === reactionCount.reaction) : [];\n reactionElement.reactionCount = {...reactionCount};\n reactionElement.setCanRenderAvatars(canRenderAvatars);\n reactionElement.render(this.isPlaceholder);\n reactionElement.renderCounter();\n reactionElement.renderAvatars(recentReactions);\n reactionElement.setIsChosen();\n\n return reactionElement;\n });\n\n // this.sorted.forEach((reactionElement, idx) => {\n // /* if(this.type === 'block' && this.childElementCount !== this.sorted.length) { // because of appended time\n // idx += 1;\n // } */\n\n // positionElementByIndex(reactionElement, this, idx);\n // });\n\n if(!this.isPlaceholder && changedResults?.length) {\n if(this.isConnected) {\n this.handleChangedResults(changedResults);\n } else {\n this.onConnectCallback = () => {\n this.handleChangedResults(changedResults);\n };\n }\n }\n // });\n\n // ! тут вообще не должно быть этого кода, но пока он побудет тут\n if(!this.sorted.length && this.type === 'block') {\n const parentElement = this.parentElement;\n this.remove();\n\n if(parentElement.classList.contains('document-message') && !parentElement.childNodes.length) {\n parentElement.remove();\n return;\n }\n\n const timeSpan = this.querySelector('.time');\n if(timeSpan) {\n parentElement.append(timeSpan);\n }\n }\n }\n\n private handleChangedResults(changedResults: ReactionCount[]) {\n // ! temp\n if(this.message.peerId !== rootScope.peerId) return;\n\n changedResults.forEach(reactionCount => {\n const reactionElement = this.sorted.find(reactionElement => reactionElement.reactionCount.reaction === reactionCount.reaction);\n if(reactionElement) {\n reactionElement.fireAroundAnimation();\n }\n });\n }\n}\n\ncustomElements.define(TAG_NAME, ReactionsElement);\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport type { LazyLoadQueueIntersector } from \"../lazyLoadQueue\";\r\nimport { Message } from \"../../layer\";\r\nimport appMessagesManager from \"../../lib/appManagers/appMessagesManager\";\r\nimport appPeersManager from \"../../lib/appManagers/appPeersManager\";\r\nimport rootScope from \"../../lib/rootScope\";\r\nimport ripple from \"../ripple\";\r\nimport I18n from \"../../lib/langPack\";\r\nimport replaceContent from \"../../helpers/dom/replaceContent\";\r\nimport StackedAvatars from \"../stackedAvatars\";\r\nimport formatNumber from \"../../helpers/number/formatNumber\";\r\n\r\nconst TAG_NAME = 'replies-element';\r\n\r\nrootScope.addEventListener('replies_updated', (message) => {\r\n (Array.from(document.querySelectorAll(TAG_NAME + `[data-post-key=\"${message.peerId}_${message.mid}\"]`)) as RepliesElement[]).forEach(element => {\r\n element.message = message;\r\n element.render();\r\n });\r\n});\r\n\r\nexport default class RepliesElement extends HTMLElement {\r\n public message: Message.message;\r\n public type: 'footer' | 'beside';\r\n public loadPromises: Promise<any>[];\r\n public lazyLoadQueue: LazyLoadQueueIntersector;\r\n public stackedAvatars: StackedAvatars;\r\n public text: I18n.IntlElement;\r\n \r\n private updated = false;\r\n\r\n constructor() {\r\n super();\r\n }\r\n\r\n public init() {\r\n this.render();\r\n this.dataset.postKey = this.message.peerId + '_' + this.message.mid;\r\n this.classList.add('replies', 'replies-' + this.type);\r\n }\r\n\r\n public render() {\r\n const replies = this.message.replies;\r\n\r\n /* if(this.firstChild) {\r\n this.innerHTML = '';\r\n } */\r\n\r\n if(this.type === 'footer') {\r\n let leftPart: HTMLElement;\r\n if(this.firstElementChild) {\r\n leftPart = this.firstElementChild as HTMLElement;\r\n }\r\n\r\n if(replies?.recent_repliers) {\r\n if(leftPart && !leftPart.classList.contains('replies-footer-avatars')) {\r\n this.innerHTML = '';\r\n leftPart = null;\r\n }\r\n\r\n if(!this.stackedAvatars) {\r\n this.stackedAvatars = new StackedAvatars({\r\n lazyLoadQueue: this.lazyLoadQueue,\r\n avatarSize: 30\r\n });\r\n\r\n this.stackedAvatars.container.classList.add('replies-footer-avatars');\r\n }\r\n\r\n leftPart = this.stackedAvatars.container;\r\n\r\n this.stackedAvatars.render(replies.recent_repliers.map(peer => appPeersManager.getPeerId(peer)), this.loadPromises);\r\n } else {\r\n if(leftPart && !leftPart.classList.contains('tgico-comments')) {\r\n leftPart.remove();\r\n leftPart = null;\r\n }\r\n\r\n if(!leftPart) {\r\n leftPart = document.createElement('span');\r\n leftPart.classList.add('tgico-comments');\r\n }\r\n }\r\n\r\n if(!leftPart.parentElement) {\r\n this.prepend(leftPart);\r\n }\r\n \r\n if(!this.text) {\r\n this.text = new I18n.IntlElement();\r\n }\r\n\r\n const text = this.text;\r\n if(replies) {\r\n if(replies.replies) {\r\n text.compareAndUpdate({key: 'Comments', args: [replies.replies]});\r\n } else {\r\n text.compareAndUpdate({key: 'LeaveAComment'});\r\n }\r\n } else {\r\n text.compareAndUpdate({key: 'ViewInChat'});\r\n }\r\n\r\n if(replies) {\r\n // const historyStorage = appMessagesManager.getHistoryStorage(replies.channel_id.toPeerId(true));\r\n let isUnread = false;\r\n if(replies.replies) {\r\n if(replies.read_max_id !== undefined && replies.max_id !== undefined) {\r\n isUnread = replies.read_max_id < replies.max_id;\r\n }/* else {\r\n isUnread = !historyStorage.readMaxId || historyStorage.readMaxId < (replies.max_id || 0);\r\n } */\r\n }\r\n this.classList.toggle('is-unread', isUnread);\r\n }\r\n\r\n let textSpan = this.children[1] as HTMLElement;\r\n if(!textSpan) {\r\n textSpan = document.createElement('span');\r\n textSpan.classList.add('replies-footer-text');\r\n\r\n const iconSpan = document.createElement('span');\r\n iconSpan.classList.add('tgico-next');\r\n\r\n const rippleContainer = document.createElement('div');\r\n ripple(rippleContainer);\r\n\r\n this.append(textSpan, iconSpan, rippleContainer);\r\n }\r\n\r\n replaceContent(textSpan, text.element);\r\n } else {\r\n this.classList.add('bubble-beside-button');\r\n this.innerHTML = `<span class=\"tgico-commentssticker\"></span><span class=\"replies-beside-text\">${replies?.replies ? formatNumber(replies.replies, 0) : ''}</span>`;\r\n }\r\n\r\n if(replies && !this.updated && !this.message.pFlags.is_outgoing) {\r\n appMessagesManager.subscribeRepliesThread(this.message.peerId, this.message.mid);\r\n appMessagesManager.updateMessage(this.message.peerId, this.message.mid, 'replies_updated');\r\n this.updated = true;\r\n }\r\n\r\n if(this.loadPromises) {\r\n this.loadPromises = undefined;\r\n }\r\n }\r\n}\r\n\r\ncustomElements.define(TAG_NAME, RepliesElement);\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { formatTime, getFullDate } from \"../../helpers/date\";\nimport setInnerHTML from \"../../helpers/dom/setInnerHTML\";\nimport formatNumber from \"../../helpers/number/formatNumber\";\nimport { Message } from \"../../layer\";\nimport appMessagesManager from \"../../lib/appManagers/appMessagesManager\";\nimport { i18n, _i18n } from \"../../lib/langPack\";\nimport RichTextProcessor from \"../../lib/richtextprocessor\";\nimport { LazyLoadQueueIntersector } from \"../lazyLoadQueue\";\nimport PeerTitle from \"../peerTitle\";\nimport { wrapReply } from \"../wrappers\";\nimport Chat, { ChatType } from \"./chat\";\nimport ReactionsElement from \"./reactions\";\nimport RepliesElement from \"./replies\";\n\nconst NBSP = '&nbsp;';\n\nconst makeEdited = () => {\n const edited = document.createElement('i');\n edited.classList.add('edited');\n _i18n(edited, 'EditedMessage');\n return edited;\n};\n\nconst makeSponsored = () => i18n('SponsoredMessage');\n\nexport namespace MessageRender {\n /* export const setText = () => {\n\n }; */\n\n export const setTime = (options: {\n chatType: ChatType, \n message: Message.message | Message.messageService,\n }) => {\n const {chatType, message} = options;\n const date = new Date(message.date * 1000);\n const args: (HTMLElement | string)[] = [];\n \n let editedSpan: HTMLElement, sponsoredSpan: HTMLElement, reactionsElement: ReactionsElement, reactionsMessage: Message.message;\n \n const isSponsored = !!(message as Message.message).pFlags.sponsored;\n const isMessage = !('action' in message) && !isSponsored;\n let hasReactions: boolean;\n \n let time: HTMLElement = isSponsored ? undefined : formatTime(date);\n if(isMessage) {\n if(message.views) {\n const postAuthor = message.post_author || message.fwd_from?.post_author;\n \n const postViewsSpan = document.createElement('span');\n postViewsSpan.classList.add('post-views');\n postViewsSpan.innerHTML = formatNumber(message.views, 1);\n \n const channelViews = document.createElement('i');\n channelViews.classList.add('tgico-channelviews', 'time-icon');\n \n args.push(postViewsSpan, channelViews);\n if(postAuthor) {\n const span = document.createElement('span');\n setInnerHTML(span, RichTextProcessor.wrapEmojiText(postAuthor));\n span.insertAdjacentHTML('beforeend', ',' + NBSP)\n args.push(span);\n }\n }\n\n if(message.edit_date && chatType !== 'scheduled' && !message.pFlags.edit_hide) {\n args.unshift(editedSpan = makeEdited());\n }\n \n if(chatType !== 'pinned' && message.pFlags.pinned) {\n const i = document.createElement('i');\n i.classList.add('tgico-pinnedchat', 'time-icon');\n args.unshift(i);\n }\n\n if(message.peer_id._ === 'peerUser'/* && message.reactions?.results?.length */) {\n hasReactions = true;\n\n reactionsMessage = appMessagesManager.getGroupsFirstMessage(message);\n\n reactionsElement = new ReactionsElement();\n reactionsElement.init(reactionsMessage, 'inline', true);\n reactionsElement.render();\n args.unshift(reactionsElement);\n }\n } else if(isSponsored) {\n args.push(sponsoredSpan = makeSponsored());\n }\n \n if(time) {\n args.push(time);\n }\n\n let title = isSponsored ? undefined : getFullDate(date);\n if(isMessage) {\n title += (message.edit_date && !message.pFlags.edit_hide ? `\\nEdited: ${getFullDate(new Date(message.edit_date * 1000))}` : '')\n + (message.fwd_from ? `\\nOriginal: ${getFullDate(new Date(message.fwd_from.date * 1000))}` : '');\n }\n\n const timeSpan = document.createElement('span');\n timeSpan.classList.add('time', 'tgico');\n // if(title) timeSpan.title = title;\n timeSpan.append(...args);\n\n const inner = document.createElement('div');\n inner.classList.add('inner', 'tgico');\n if(title) inner.title = title;\n\n let clonedArgs = args;\n if(editedSpan) {\n clonedArgs[clonedArgs.indexOf(editedSpan)] = makeEdited();\n }\n if(sponsoredSpan) {\n clonedArgs[clonedArgs.indexOf(sponsoredSpan)] = makeSponsored();\n }\n if(reactionsElement) {\n const _reactionsElement = clonedArgs[clonedArgs.indexOf(reactionsElement)] = new ReactionsElement();\n _reactionsElement.init(reactionsMessage, 'inline');\n _reactionsElement.render();\n }\n clonedArgs = clonedArgs.map(a => a instanceof HTMLElement && !a.classList.contains('i18n') && !a.classList.contains('reactions') ? a.cloneNode(true) as HTMLElement : a);\n if(time) {\n clonedArgs[clonedArgs.length - 1] = formatTime(date); // clone time\n }\n inner.append(...clonedArgs);\n\n timeSpan.append(inner);\n\n return timeSpan;\n };\n\n export const renderReplies = ({bubble, bubbleContainer, message, messageDiv, loadPromises, lazyLoadQueue}: {\n bubble: HTMLElement,\n bubbleContainer: HTMLElement,\n message: Message.message,\n messageDiv: HTMLElement,\n loadPromises?: Promise<any>[],\n lazyLoadQueue?: LazyLoadQueueIntersector\n }) => {\n const isFooter = !bubble.classList.contains('sticker') && !bubble.classList.contains('emoji-big') && !bubble.classList.contains('round');\n const repliesFooter = new RepliesElement();\n repliesFooter.message = message;\n repliesFooter.type = isFooter ? 'footer' : 'beside';\n repliesFooter.loadPromises = loadPromises;\n repliesFooter.lazyLoadQueue = lazyLoadQueue;\n repliesFooter.init();\n bubbleContainer.prepend(repliesFooter);\n return isFooter;\n };\n\n export const setReply = ({chat, bubble, bubbleContainer, message}: {\n chat: Chat,\n bubble: HTMLElement,\n bubbleContainer?: HTMLElement,\n message: Message.message\n }) => {\n const isReplacing = !bubbleContainer;\n if(isReplacing) {\n bubbleContainer = bubble.querySelector('.bubble-content');\n }\n\n const currentReplyDiv = isReplacing ? bubbleContainer.querySelector('.reply') : null;\n if(!message.reply_to_mid) {\n if(currentReplyDiv) {\n currentReplyDiv.remove();\n }\n\n bubble.classList.remove('is-reply');\n return;\n }\n\n\n const replyToPeerId = message.reply_to.reply_to_peer_id ? chat.appPeersManager.getPeerId(message.reply_to.reply_to_peer_id) : chat.peerId;\n\n let originalMessage = chat.appMessagesManager.getMessageByPeer(replyToPeerId, message.reply_to_mid);\n let originalPeerTitle: string | HTMLElement;\n \n /////////this.log('message to render reply', originalMessage, originalPeerTitle, bubble, message);\n \n // need to download separately\n if(originalMessage._ === 'messageEmpty') {\n //////////this.log('message to render reply empty, need download', message, message.reply_to_mid);\n chat.appMessagesManager.wrapSingleMessage(replyToPeerId, message.reply_to_mid);\n chat.bubbles.needUpdate.push({replyToPeerId, replyMid: message.reply_to_mid, mid: message.mid});\n \n originalPeerTitle = i18n('Loading');\n } else {\n originalPeerTitle = new PeerTitle({\n peerId: originalMessage.fromId || originalMessage.fwdFromId,\n dialog: false,\n onlyFirstName: false,\n plainText: false\n }).element;\n }\n\n const wrapped = wrapReply(originalPeerTitle, undefined, originalMessage);\n if(currentReplyDiv) {\n currentReplyDiv.replaceWith(wrapped);\n } else {\n bubbleContainer.append(wrapped);\n }\n //bubbleContainer.insertBefore(, nameContainer);\n bubble.classList.add('is-reply');\n };\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\r\n\r\nexport function getElementByPoint(container: HTMLElement, verticalSide: 'top' | 'bottom', horizontalSide: 'center' | 'left'): HTMLElement {\r\n //return null;\r\n const rect = container.getBoundingClientRect();\r\n const x = horizontalSide === 'center' ? Math.ceil(rect.left + ((rect.right - rect.left) / 2) + 1) : Math.ceil(rect.left + 1);\r\n const y = verticalSide === 'bottom' ? Math.floor(rect.top + rect.height - 1) : Math.ceil(rect.top + 1);\r\n return document.elementFromPoint(x, y) as any;\r\n};\r\n\r\nMOUNT_CLASS_TO.getElementByPoint = getElementByPoint;\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nexport default function reflowScrollableElement(element: HTMLElement) {\r\n element.style.display = 'none';\r\n void element.offsetLeft; // reflow\r\n element.style.display = '';\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport App from \"../../config/app\";\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\nimport indexOfAndSplice from \"../../helpers/array/indexOfAndSplice\";\nimport isObject from \"../../helpers/object/isObject\";\nimport validateInitObject from \"../../helpers/object/validateInitObject\";\nimport I18n from \"../langPack\";\nimport apiManager from \"../mtproto/mtprotoworker\";\nimport RichTextProcessor from \"../richtextprocessor\";\nimport rootScope from \"../rootScope\";\nimport SearchIndex from \"../searchIndex\";\nimport stateStorage from \"../stateStorage\";\nimport appStateManager from \"./appStateManager\";\n\ntype EmojiLangPack = {\n keywords: {\n [keyword: string]: string[],\n },\n version: number,\n langCode: string\n};\n\nconst EMOJI_LANG_PACK: EmojiLangPack = {\n keywords: {},\n version: 0,\n langCode: App.langPackCode\n};\n\nconst RECENT_MAX_LENGTH = 36;\n\nexport class AppEmojiManager {\n private static POPULAR_EMOJI = [\"😂\", \"😘\", \"❤️\", \"😍\", \"😊\", \"😁\", \"👍\", \"☺️\", \"😔\", \"😄\", \"😭\", \"💋\", \"😒\", \"😳\", \"😜\", \"🙈\", \"😉\", \"😃\", \"😢\", \"😝\", \"😱\", \"😡\", \"😏\", \"😞\", \"😅\", \"😚\", \"🙊\", \"😌\", \"😀\", \"😋\", \"😆\", \"👌\", \"😐\", \"😕\"];\n private keywordLangPacks: {\n [langCode: string]: EmojiLangPack\n } = {};\n\n private index: SearchIndex<EmojiLangPack['keywords'][keyof EmojiLangPack['keywords']]>;\n private indexedLangPacks: {[langCode: string]: boolean} = {};\n\n private getKeywordsPromises: {[langCode: string]: Promise<EmojiLangPack>} = {};\n\n private recent: string[];\n private getRecentEmojisPromise: Promise<AppEmojiManager['recent']>;\n\n /* public getPopularEmoji() {\n return stateStorage.get('emojis_popular').then(popEmojis => {\n var result = []\n if (popEmojis && popEmojis.length) {\n for (var i = 0, len = popEmojis.length; i < len; i++) {\n result.push({code: popEmojis[i][0], rate: popEmojis[i][1]})\n }\n callback(result)\n return\n }\n\n return stateStorage.get('emojis_recent').then(recentEmojis => {\n recentEmojis = recentEmojis || popular || []\n var shortcut\n var code\n for (var i = 0, len = recentEmojis.length; i < len; i++) {\n shortcut = recentEmojis[i]\n if (Array.isArray(shortcut)) {\n shortcut = shortcut[0]\n }\n if (shortcut && typeof shortcut === 'string') {\n if (shortcut.charAt(0) == ':') {\n shortcut = shortcut.substr(1, shortcut.length - 2)\n }\n if (code = shortcuts[shortcut]) {\n result.push({code: code, rate: 1})\n }\n }\n }\n callback(result)\n });\n });\n }\n\n function pushPopularEmoji (code) {\n getPopularEmoji(function (popularEmoji) {\n var exists = false\n var count = popularEmoji.length\n var result = []\n for (var i = 0; i < count; i++) {\n if (popularEmoji[i].code == code) {\n exists = true\n popularEmoji[i].rate++\n }\n result.push([popularEmoji[i].code, popularEmoji[i].rate])\n }\n if (exists) {\n result.sort(function (a, b) {\n return b[1] - a[1]\n })\n } else {\n if (result.length > 41) {\n result = result.slice(0, 41)\n }\n result.push([code, 1])\n }\n ConfigStorage.set({emojis_popular: result})\n })\n } */\n\n public getEmojiKeywords(langCode: string = App.langPackCode) {\n const promise = this.getKeywordsPromises[langCode];\n if(promise) {\n return promise;\n }\n\n const storageKey: any = 'emojiKeywords_' + langCode;\n return this.getKeywordsPromises[langCode] = stateStorage.get(storageKey).then((pack: EmojiLangPack) => {\n if(!isObject(pack)) {\n pack = {} as any;\n }\n\n validateInitObject(EMOJI_LANG_PACK, pack);\n\n // important\n pack.langCode = langCode;\n this.keywordLangPacks[langCode] = pack;\n\n return apiManager.invokeApi('messages.getEmojiKeywordsDifference', {\n lang_code: pack.langCode,\n from_version: pack.version\n }).then((keywordsDifference) => {\n pack.version = keywordsDifference.version;\n \n const packKeywords = pack.keywords;\n const keywords = keywordsDifference.keywords;\n for(let i = 0, length = keywords.length; i < length; ++i) {\n const {keyword, emoticons} = keywords[i];\n packKeywords[keyword] = emoticons;\n }\n\n stateStorage.set({\n [storageKey]: pack\n });\n\n return pack;\n }, () => {\n return pack;\n });\n });\n }\n\n public getBothEmojiKeywords() {\n const promises: Promise<any>[] = [\n this.getEmojiKeywords()\n ];\n\n if(I18n.lastRequestedLangCode !== App.langPackCode) {\n promises.push(this.getEmojiKeywords(I18n.lastRequestedLangCode));\n }\n\n if(!this.recent) {\n promises.push(this.getRecentEmojis());\n }\n\n return Promise.all(promises);\n }\n\n public indexEmojis() {\n if(!this.index) {\n this.index = new SearchIndex(undefined, 2);\n }\n\n for(const langCode in this.keywordLangPacks) {\n if(this.indexedLangPacks[langCode]) {\n continue;\n }\n\n const pack = this.keywordLangPacks[langCode];\n const keywords = pack.keywords;\n\n for(const keyword in keywords) {\n const emoticons = keywords[keyword];\n this.index.indexObject(emoticons, keyword);\n }\n\n this.indexedLangPacks[langCode] = true;\n }\n }\n\n public searchEmojis(q: string) {\n this.indexEmojis();\n\n q = q.toLowerCase().replace(/_/g, ' ');\n \n //const perf = performance.now();\n let emojis: Array<string>;\n if(q.trim()) {\n const set = this.index.search(q);\n emojis = Array.from(set).reduce((acc, v) => acc.concat(v), []);\n } else {\n emojis = this.recent.concat(AppEmojiManager.POPULAR_EMOJI).slice(0, RECENT_MAX_LENGTH);\n }\n\n emojis = Array.from(new Set(emojis));\n //console.log('searchEmojis', q, 'time', performance.now() - perf);\n\n /* for(let i = 0, length = emojis.length; i < length; ++i) {\n if(emojis[i].includes(zeroWidthJoiner) && !emojis[i].includes('\\ufe0f')) {\n emojis[i] += '\\ufe0f';\n }\n } */\n\n return emojis;\n }\n\n public getRecentEmojis() {\n if(this.getRecentEmojisPromise) return this.getRecentEmojisPromise;\n return this.getRecentEmojisPromise = appStateManager.getState().then(state => {\n return this.recent = Array.isArray(state.recentEmoji) ? state.recentEmoji : [];\n });\n }\n\n public pushRecentEmoji(emoji: string) {\n emoji = RichTextProcessor.fixEmoji(emoji);\n this.getRecentEmojis().then(recent => {\n indexOfAndSplice(recent, emoji);\n recent.unshift(emoji);\n if(recent.length > RECENT_MAX_LENGTH) {\n recent.length = RECENT_MAX_LENGTH;\n }\n\n appStateManager.pushToState('recentEmoji', recent);\n rootScope.dispatchEvent('emoji_recent', emoji);\n });\n }\n}\n\nconst appEmojiManager = new AppEmojiManager();\nMOUNT_CLASS_TO && (MOUNT_CLASS_TO.appEmojiManager = appEmojiManager);\nexport default appEmojiManager;\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport emoticonsDropdown, { EmoticonsDropdown, EmoticonsTab } from \"..\";\nimport cancelEvent from \"../../../helpers/dom/cancelEvent\";\nimport findUpClassName from \"../../../helpers/dom/findUpClassName\";\nimport { fastRaf } from \"../../../helpers/schedulers\";\nimport pause from \"../../../helpers/schedulers/pause\";\nimport appEmojiManager from \"../../../lib/appManagers/appEmojiManager\";\nimport appImManager from \"../../../lib/appManagers/appImManager\";\nimport { i18n, LangPackKey } from \"../../../lib/langPack\";\nimport { RichTextProcessor } from \"../../../lib/richtextprocessor\";\nimport rootScope from \"../../../lib/rootScope\";\nimport { emojiFromCodePoints } from \"../../../vendor/emoji\";\nimport { putPreloader } from \"../../misc\";\nimport Scrollable from \"../../scrollable\";\nimport StickyIntersector from \"../../stickyIntersector\";\nimport IS_EMOJI_SUPPORTED from \"../../../environment/emojiSupport\";\nimport IS_TOUCH_SUPPORTED from \"../../../environment/touchSupport\";\nimport blurActiveElement from \"../../../helpers/dom/blurActiveElement\";\nimport Emoji from \"../../../config/emoji\";\n\nconst loadedURLs: Set<string> = new Set();\nexport function appendEmoji(emoji: string, container: HTMLElement, prepend = false, unify = false) {\n //const emoji = details.unified;\n //const emoji = (details.unified as string).split('-')\n //.reduce((prev, curr) => prev + String.fromCodePoint(parseInt(curr, 16)), '');\n\n const spanEmoji = document.createElement('span');\n spanEmoji.classList.add('super-emoji');\n\n let kek: DocumentFragment;\n if(unify && !IS_EMOJI_SUPPORTED) {\n kek = RichTextProcessor.wrapSingleEmoji(emoji);\n } else {\n emoji = RichTextProcessor.fixEmoji(emoji);\n kek = RichTextProcessor.wrapEmojiText(emoji);\n }\n\n /* if(!kek.includes('emoji')) {\n console.log(emoji, kek, spanEmoji, emoji.length, new TextEncoder().encode(emoji), emojiUnicode(emoji));\n return;\n } */\n\n //console.log(kek);\n\n spanEmoji.append(kek);\n\n if(spanEmoji.children.length > 1) {\n const first = spanEmoji.firstElementChild;\n spanEmoji.innerHTML = '';\n spanEmoji.append(first);\n }\n\n if(spanEmoji.firstElementChild?.tagName === 'IMG') {\n const image = spanEmoji.firstElementChild as HTMLImageElement;\n \n const url = image.src;\n if(!loadedURLs.has(url)) {\n image.setAttribute('loading', 'lazy');\n const placeholder = document.createElement('span');\n placeholder.classList.add('emoji-placeholder');\n\n if(rootScope.settings.animationsEnabled) {\n image.style.opacity = '0';\n placeholder.style.opacity = '1';\n }\n\n image.addEventListener('load', () => {\n fastRaf(() => {\n if(rootScope.settings.animationsEnabled) {\n image.style.opacity = '';\n placeholder.style.opacity = '';\n }\n\n spanEmoji.classList.remove('empty');\n\n loadedURLs.add(url);\n });\n }, {once: true});\n\n spanEmoji.append(placeholder);\n }\n }\n\n //spanEmoji = spanEmoji.firstElementChild as HTMLSpanElement;\n //spanEmoji.setAttribute('emoji', emoji);\n if(prepend) container.prepend(spanEmoji);\n else container.appendChild(spanEmoji);\n}\n\nexport function getEmojiFromElement(element: HTMLElement) {\n if(!findUpClassName(element, 'super-emoji')) return '';\n\n if(element.nodeType === 3) return element.nodeValue;\n if(element.tagName === 'SPAN' && !element.classList.contains('emoji') && element.firstElementChild) {\n element = element.firstElementChild as HTMLElement;\n }\n \n return element.getAttribute('alt') || element.innerText;\n}\n\nexport default class EmojiTab implements EmoticonsTab {\n private content: HTMLElement;\n\n private recentItemsDiv: HTMLElement;\n\n private scroll: Scrollable;\n private stickyIntersector: StickyIntersector;\n private menu: HTMLElement;\n\n private closeScrollTop = 0;\n private setMenuActive: (id: number) => boolean;\n\n init() {\n this.content = document.getElementById('content-emoji') as HTMLDivElement;\n\n const categories: LangPackKey[] = [\n 'Emoji.SmilesAndPeople', \n 'Emoji.AnimalsAndNature', \n 'Emoji.FoodAndDrink', \n 'Emoji.TravelAndPlaces', \n 'Emoji.ActivityAndSport', \n 'Emoji.Objects', \n /* 'Emoji.Symbols', */\n 'Emoji.Flags', \n 'Skin Tones' as any\n ];\n const divs: {\n [category in LangPackKey]?: HTMLDivElement\n } = {};\n\n const sorted: Map<LangPackKey, string[]> = new Map([\n [\n 'Emoji.Recent',\n []\n ]\n ]);\n\n for(const emoji in Emoji) {\n const details = Emoji[emoji];\n const i = '' + details;\n const category = categories[+i[0] - 1];\n if(!category) continue; // maybe it's skin tones\n\n let s = sorted.get(category);\n if(!s) {\n s = [];\n sorted.set(category, s);\n }\n \n s[+i.slice(1) || 0] = emoji;\n }\n\n //console.log('emoticons sorted:', sorted);\n\n //Object.keys(sorted).forEach(c => sorted[c].sort((a, b) => a - b));\n\n sorted.delete(categories.pop());\n\n //console.time('emojiParse');\n sorted.forEach((emojis, category) => {\n const div = document.createElement('div');\n div.classList.add('emoji-category');\n\n const titleDiv = document.createElement('div');\n titleDiv.classList.add('category-title');\n titleDiv.append(i18n(category));\n\n const itemsDiv = document.createElement('div');\n itemsDiv.classList.add('super-emojis');\n\n div.append(titleDiv, itemsDiv);\n\n emojis.forEach(unified => {\n /* if(emojiUnicode(emoji) === '1f481-200d-2642') {\n console.log('append emoji', emoji, emojiUnicode(emoji));\n } */\n\n let emoji = emojiFromCodePoints(unified);\n //if(emoji.includes('🕵')) {\n //console.log('toCodePoints', toCodePoints(emoji));\n //emoji = emoji.replace(/(\\u200d[\\u2640\\u2642\\u2695])(?!\\ufe0f)/, '\\ufe0f$1');\n // const zwjIndex = emoji.indexOf('\\u200d');\n // if(zwjIndex !== -1 && !emoji.includes('\\ufe0f')) {\n // /* if(zwjIndex !== (emoji.length - 1)) {\n // emoji = emoji.replace(/(\\u200d)/g, '\\ufe0f$1');\n // } */\n\n // emoji += '\\ufe0f';\n // //emoji += '\\ufe0f';\n // }\n\n //debugger;\n //}\n\n appendEmoji(emoji/* .replace(/[\\ufe0f\\u2640\\u2642\\u2695]/g, '') */, itemsDiv, false/* , false */);\n\n /* if(category === 'Smileys & Emotion') {\n console.log('appended emoji', emoji, itemsDiv.children[itemsDiv.childElementCount - 1].innerHTML, emojiUnicode(emoji));\n } */\n });\n\n divs[category] = div;\n });\n\n //console.timeEnd('emojiParse');\n\n const menu = this.menu = this.content.previousElementSibling as HTMLElement;\n const emojiScroll = this.scroll = new Scrollable(this.content, 'EMOJI');\n\n //emojiScroll.setVirtualContainer(emojiScroll.container);\n\n const preloader = putPreloader(this.content, true);\n\n Promise.all([\n pause(200),\n appEmojiManager.getRecentEmojis().then(recent => {\n const hasRecent = !!recent.length;\n const activeId = hasRecent ? 0 : 1;\n this.menu.children[0].classList.toggle('hide', !hasRecent);\n this.menu.children[activeId].classList.add('active');\n const m = EmoticonsDropdown.menuOnClick(menu, emojiScroll, undefined, activeId);\n this.stickyIntersector = m.stickyIntersector;\n this.setMenuActive = m.setActive;\n return recent;\n })\n ]).then(([_, recent]) => {\n preloader.remove();\n\n this.recentItemsDiv = divs['Emoji.Recent'].querySelector('.super-emojis');\n for(const emoji of recent) {\n appendEmoji(emoji, this.recentItemsDiv);\n }\n\n this.recentItemsDiv.parentElement.classList.toggle('hide', !this.recentItemsDiv.childElementCount);\n\n categories.unshift('Emoji.Recent');\n categories.map(category => {\n const div = divs[category];\n \n if(!div) {\n console.error('no div by category:', category);\n }\n \n emojiScroll.container.append(div);\n this.stickyIntersector.observeStickyHeaderChanges(div);\n return div;\n });\n });\n\n this.content.addEventListener('click', this.onContentClick);\n this.init = null;\n\n rootScope.addEventListener('emoji_recent', (emoji) => {\n const children = Array.from(this.recentItemsDiv.children) as HTMLElement[];\n for(let i = 0, length = children.length; i < length; ++i) {\n const el = children[i];\n const _emoji = RichTextProcessor.fixEmoji(getEmojiFromElement(el));\n if(emoji === _emoji) {\n if(i === 0) {\n return;\n }\n\n el.remove();\n }\n }\n\n appendEmoji(emoji, this.recentItemsDiv, true);\n this.recentItemsDiv.parentElement.classList.remove('hide');\n this.menu.children[0].classList.remove('hide');\n\n if(!this.closeScrollTop) {\n this.setMenuActive(0);\n }\n });\n\n emoticonsDropdown.addEventListener('close', () => {\n this.closeScrollTop = this.scroll.scrollTop;\n });\n }\n\n onContentClick = (e: MouseEvent) => {\n cancelEvent(e);\n \n const emoji = getEmojiFromElement(e.target as HTMLElement);\n if(!emoji) {\n return;\n }\n\n appImManager.chat.input.onEmojiSelected(emoji, false);\n if(IS_TOUCH_SUPPORTED) {\n blurActiveElement();\n }\n };\n\n onClose() {\n\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport appDocsManager, {MyDocument} from \"../lib/appManagers/appDocsManager\";\r\nimport { wrapVideo } from \"./wrappers\";\r\nimport { LazyLoadQueueRepeat2 } from \"./lazyLoadQueue\";\r\nimport animationIntersector from \"./animationIntersector\";\r\nimport Scrollable from \"./scrollable\";\r\nimport deferredPromise, { CancellablePromise } from \"../helpers/cancellablePromise\";\r\nimport renderImageFromUrl from \"../helpers/dom/renderImageFromUrl\";\r\nimport calcImageInBox from \"../helpers/calcImageInBox\";\r\nimport { doubleRaf } from \"../helpers/schedulers\";\r\n\r\nconst width = 400;\r\nconst maxSingleWidth = width - 100;\r\nconst height = 100;\r\n\r\nexport default class GifsMasonry {\r\n public lazyLoadQueue: LazyLoadQueueRepeat2;\r\n private scrollPromise: CancellablePromise<void> = Promise.resolve();\r\n private timeout: number = 0;\r\n\r\n constructor(private element: HTMLElement, private group: string, private scrollable: Scrollable, attach = true) {\r\n this.lazyLoadQueue = new LazyLoadQueueRepeat2(undefined, (target, visible) => {\r\n if(visible) {\r\n this.processVisibleDiv(target);\r\n } else {\r\n this.processInvisibleDiv(target);\r\n }\r\n });\r\n\r\n /* setInterval(() => {\r\n // @ts-ignore\r\n const players = animationIntersector.byGroups[group];\r\n\r\n if(players) {\r\n console.log(`GIFS RENDERED IN ${group}:`, players.length, players.filter(p => !p.animation.paused).length, this.lazyLoadQueue.intersector.getVisible().length);\r\n }\r\n }, .25e3); */\r\n\r\n if(attach) {\r\n this.attach();\r\n }\r\n }\r\n \r\n private onScroll = () => {\r\n if(this.timeout) {\r\n clearTimeout(this.timeout);\r\n } else {\r\n this.scrollPromise = deferredPromise<void>();\r\n //animationIntersector.checkAnimations(true, group);\r\n }\r\n\r\n this.timeout = window.setTimeout(() => {\r\n this.timeout = 0;\r\n this.scrollPromise.resolve();\r\n //animationIntersector.checkAnimations(false, group);\r\n }, 150);\r\n };\r\n\r\n public attach() {\r\n this.scrollable.container.addEventListener('scroll', this.onScroll);\r\n }\r\n\r\n public detach() {\r\n this.clear();\r\n this.scrollable.container.removeEventListener('scroll', this.onScroll);\r\n }\r\n\r\n public clear() {\r\n this.lazyLoadQueue.clear();\r\n }\r\n\r\n private processVisibleDiv(div: HTMLElement) {\r\n const video = div.querySelector('video');\r\n if(video) {\r\n return;\r\n }\r\n\r\n //console.log('processVisibleDiv');\r\n\r\n const load = () => {\r\n const docId = div.dataset.docId;\r\n const doc = appDocsManager.getDoc(docId);\r\n\r\n const promise = this.scrollPromise.then(() => {\r\n const res = wrapVideo({\r\n doc,\r\n container: div as HTMLDivElement,\r\n lazyLoadQueue: null,\r\n //lazyLoadQueue: EmoticonsDropdown.lazyLoadQueue,\r\n group: this.group,\r\n noInfo: true,\r\n });\r\n \r\n const promise = res.loadPromise;\r\n promise.finally(() => {\r\n const video = div.querySelector('video');\r\n\r\n div.style.opacity = '';\r\n const img = div.querySelector('img');\r\n img && img.classList.add('hide');\r\n\r\n if(video && !video.parentElement) {\r\n setTimeout(() => {\r\n video.src = '';\r\n video.load();\r\n const animations = animationIntersector.getAnimations(video);\r\n animations.forEach(item => {\r\n animationIntersector.checkAnimation(item, true, true);\r\n });\r\n }, 0);\r\n }\r\n\r\n //clearTimeout(timeout);\r\n if(!this.lazyLoadQueue.intersector.isVisible(div)) {\r\n this.processInvisibleDiv(div);\r\n }\r\n });\r\n\r\n return promise;\r\n });\r\n\r\n /* let timeout = window.setTimeout(() => {\r\n console.error('processVisibleDiv timeout', div, doc);\r\n }, 1e3); */\r\n\r\n return promise;\r\n };\r\n\r\n //return load();\r\n \r\n this.lazyLoadQueue.push({div, load});\r\n }\r\n\r\n public processInvisibleDiv = (div: HTMLElement) => {\r\n return this.scrollPromise.then(async() => {\r\n //return;\r\n\r\n if(this.lazyLoadQueue.intersector.isVisible(div)) {\r\n return;\r\n }\r\n\r\n const video = div.querySelector('video');\r\n const img = div.querySelector('img');\r\n \r\n if(img) {\r\n img && img.classList.remove('hide');\r\n \r\n await doubleRaf();\r\n }\r\n\r\n if(this.lazyLoadQueue.intersector.isVisible(div)) {\r\n return;\r\n }\r\n \r\n if(video) {\r\n video.remove();\r\n video.src = '';\r\n video.load();\r\n const animations = animationIntersector.getAnimations(video);\r\n animations.forEach(item => {\r\n animationIntersector.checkAnimation(item, true, true);\r\n });\r\n }\r\n });\r\n };\r\n\r\n public add(doc: MyDocument, appendTo = this.element) {\r\n let gifWidth = doc.w;\r\n let gifHeight = doc.h;\r\n if(gifHeight < height) {\r\n gifWidth = height / gifHeight * gifWidth;\r\n gifHeight = height;\r\n }\r\n\r\n const willUseWidth = Math.min(maxSingleWidth, width, gifWidth);\r\n const size = calcImageInBox(gifWidth, gifHeight, willUseWidth, height);\r\n\r\n /* wastedWidth += w;\r\n\r\n if(wastedWidth === width || h < height) {\r\n wastedWidth = 0;\r\n console.log('completed line', i, line);\r\n line = [];\r\n continue;\r\n }\r\n\r\n line.push(gif); */\r\n\r\n //console.log('gif:', gif, w, h);\r\n\r\n const div = document.createElement('div');\r\n div.classList.add('gif', 'fade-in-transition');\r\n div.style.width = size.width + 'px';\r\n div.style.opacity = '0';\r\n //div.style.height = h + 'px';\r\n div.dataset.docId = '' + doc.id;\r\n\r\n appendTo.append(div);\r\n\r\n //this.lazyLoadQueue.observe({div, load: this.processVisibleDiv});\r\n this.lazyLoadQueue.observe(div);\r\n\r\n //let preloader = new ProgressivePreloader(div);\r\n\r\n const gotThumb = appDocsManager.getThumb(doc, false);\r\n\r\n const willBeAPoster = !!gotThumb;\r\n let img: HTMLImageElement;\r\n if(willBeAPoster) {\r\n img = new Image();\r\n img.classList.add('media-poster');\r\n\r\n if(!gotThumb.cacheContext.url) {\r\n gotThumb.promise.then(() => {\r\n img.src = gotThumb.cacheContext.url;\r\n });\r\n }\r\n }\r\n\r\n const afterRender = () => {\r\n if(img) {\r\n div.append(img);\r\n div.style.opacity = '';\r\n }\r\n };\r\n\r\n (gotThumb?.cacheContext?.url ? renderImageFromUrl(img, gotThumb.cacheContext.url, afterRender) : afterRender());\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport emoticonsDropdown, { EmoticonsDropdown, EmoticonsTab, EMOTICONSSTICKERGROUP } from \"..\";\r\nimport GifsMasonry from \"../../gifsMasonry\";\r\nimport Scrollable from \"../../scrollable\";\r\nimport { putPreloader } from \"../../misc\";\r\nimport apiManager from \"../../../lib/mtproto/mtprotoworker\";\r\nimport appDocsManager, {MyDocument} from \"../../../lib/appManagers/appDocsManager\";\r\n\r\nexport default class GifsTab implements EmoticonsTab {\r\n private content: HTMLElement;\r\n\r\n init() {\r\n this.content = document.getElementById('content-gifs');\r\n const gifsContainer = this.content.firstElementChild as HTMLDivElement;\r\n gifsContainer.addEventListener('click', EmoticonsDropdown.onMediaClick);\r\n\r\n const scroll = new Scrollable(this.content, 'GIFS');\r\n const masonry = new GifsMasonry(gifsContainer, EMOTICONSSTICKERGROUP, scroll);\r\n const preloader = putPreloader(this.content, true);\r\n\r\n apiManager.invokeApi('messages.getSavedGifs', {hash: '0'}).then((res) => {\r\n //console.log('getSavedGifs res:', res);\r\n\r\n if(res._ === 'messages.savedGifs') {\r\n res.gifs.forEach((doc, idx) => {\r\n res.gifs[idx] = doc = appDocsManager.saveDoc(doc);\r\n //if(doc._ === 'documentEmpty') return;\r\n masonry.add(doc as MyDocument);\r\n });\r\n }\r\n\r\n preloader.remove();\r\n });\r\n\r\n emoticonsDropdown.addLazyLoadQueueRepeat(masonry.lazyLoadQueue, masonry.processInvisibleDiv);\r\n\r\n this.init = null;\r\n }\r\n\r\n onClose() {\r\n\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport emoticonsDropdown, { EmoticonsDropdown, EMOTICONSSTICKERGROUP, EmoticonsTab } from \"..\";\r\nimport findUpAttribute from \"../../../helpers/dom/findUpAttribute\";\r\nimport findUpClassName from \"../../../helpers/dom/findUpClassName\";\r\nimport mediaSizes from \"../../../helpers/mediaSizes\";\r\nimport { MessagesAllStickers, StickerSet } from \"../../../layer\";\r\nimport appDocsManager, { MyDocument } from \"../../../lib/appManagers/appDocsManager\";\r\nimport appStickersManager from \"../../../lib/appManagers/appStickersManager\";\r\nimport { i18n } from \"../../../lib/langPack\";\r\nimport { RichTextProcessor } from \"../../../lib/richtextprocessor\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport animationIntersector from \"../../animationIntersector\";\r\nimport LazyLoadQueue, { LazyLoadQueueRepeat } from \"../../lazyLoadQueue\";\r\nimport { putPreloader } from \"../../misc\";\r\nimport PopupStickers from \"../../popups/stickers\";\r\nimport Scrollable, { ScrollableX } from \"../../scrollable\";\r\nimport StickyIntersector from \"../../stickyIntersector\";\r\nimport { wrapSticker, wrapStickerSetThumb } from \"../../wrappers\";\r\n\r\nexport class SuperStickerRenderer {\r\n public lazyLoadQueue: LazyLoadQueueRepeat;\r\n private animatedDivs: Set<HTMLDivElement> = new Set();\r\n\r\n constructor(private regularLazyLoadQueue: LazyLoadQueue, private group: string) {\r\n this.lazyLoadQueue = new LazyLoadQueueRepeat(undefined, (target, visible) => {\r\n if(!visible) {\r\n this.processInvisibleDiv(target as HTMLDivElement);\r\n }\r\n });\r\n }\r\n\r\n public clear() {\r\n this.lazyLoadQueue.clear();\r\n }\r\n\r\n public renderSticker(doc: MyDocument, div?: HTMLDivElement, loadPromises?: Promise<any>[]) {\r\n if(!div) {\r\n div = document.createElement('div');\r\n div.classList.add('grid-item', 'super-sticker');\r\n\r\n if(doc.animated) {\r\n this.observeAnimatedDiv(div);\r\n }\r\n }\r\n\r\n // * This will wrap only a thumb\r\n wrapSticker({\r\n doc, \r\n div,\r\n lazyLoadQueue: this.regularLazyLoadQueue, \r\n group: this.group, \r\n onlyThumb: doc.animated,\r\n loadPromises\r\n });\r\n\r\n return div;\r\n }\r\n\r\n public observeAnimatedDiv(div: HTMLDivElement) {\r\n this.animatedDivs.add(div);\r\n\r\n this.lazyLoadQueue.observe({\r\n div, \r\n load: this.processVisibleDiv\r\n });\r\n }\r\n\r\n private checkAnimationContainer = (div: HTMLElement, visible: boolean) => {\r\n //console.error('checkAnimationContainer', div, visible);\r\n const players = animationIntersector.getAnimations(div);\r\n players.forEach(player => {\r\n if(!visible) {\r\n animationIntersector.checkAnimation(player, true, true);\r\n } else {\r\n animationIntersector.checkAnimation(player, false);\r\n }\r\n });\r\n };\r\n\r\n private processVisibleDiv = (div: HTMLElement) => {\r\n const docId = div.dataset.docId;\r\n const doc = appDocsManager.getDoc(docId);\r\n \r\n const size = mediaSizes.active.esgSticker.width;\r\n\r\n //console.log('processVisibleDiv:', div);\r\n\r\n const promise = wrapSticker({\r\n doc, \r\n div: div as HTMLDivElement,\r\n width: size,\r\n height: size,\r\n lazyLoadQueue: null, \r\n group: this.group, \r\n onlyThumb: false,\r\n play: true,\r\n loop: true\r\n });\r\n\r\n promise.then(() => {\r\n //clearTimeout(timeout);\r\n this.checkAnimationContainer(div, this.lazyLoadQueue.intersector.isVisible(div));\r\n });\r\n\r\n /* let timeout = window.setTimeout(() => {\r\n console.error('processVisibleDiv timeout', div, doc);\r\n }, 1e3); */\r\n\r\n return promise;\r\n };\r\n\r\n public processInvisibleDiv = (div: HTMLElement) => {\r\n const docId = div.dataset.docId;\r\n const doc = appDocsManager.getDoc(docId);\r\n\r\n //console.log('STICKER INvisible:', /* div, */docId);\r\n\r\n this.checkAnimationContainer(div, false);\r\n\r\n div.innerHTML = '';\r\n this.renderSticker(doc, div as HTMLDivElement);\r\n };\r\n}\r\n\r\nexport default class StickersTab implements EmoticonsTab {\r\n private content: HTMLElement;\r\n private stickersDiv: HTMLElement;\r\n\r\n private stickerSets: {[id: string]: {\r\n stickers: HTMLElement,\r\n tab: HTMLElement\r\n }} = {};\r\n\r\n private recentDiv: HTMLElement;\r\n private recentStickers: MyDocument[] = [];\r\n\r\n private scroll: Scrollable;\r\n\r\n private menu: HTMLElement;\r\n \r\n private mounted = false;\r\n\r\n private queueCategoryPush: {element: HTMLElement, prepend: boolean}[] = [];\r\n\r\n private stickyIntersector: StickyIntersector;\r\n\r\n private superStickerRenderer: SuperStickerRenderer;\r\n\r\n categoryPush(categoryDiv: HTMLElement, categoryTitle: DocumentFragment | string = '', promise: Promise<MyDocument[]>, prepend?: boolean) {\r\n //if((docs.length % 5) !== 0) categoryDiv.classList.add('not-full');\r\n\r\n const itemsDiv = document.createElement('div');\r\n itemsDiv.classList.add('category-items', 'super-stickers');\r\n\r\n const titleDiv = document.createElement('div');\r\n titleDiv.classList.add('category-title');\r\n\r\n if(categoryTitle) {\r\n if(typeof(categoryTitle) === 'string') titleDiv.innerHTML = categoryTitle;\r\n else titleDiv.append(categoryTitle);\r\n }\r\n\r\n categoryDiv.append(titleDiv, itemsDiv);\r\n\r\n this.stickyIntersector.observeStickyHeaderChanges(categoryDiv);\r\n\r\n this.queueCategoryPush.push({element: categoryDiv, prepend});\r\n\r\n promise.then(documents => {\r\n documents.forEach(doc => {\r\n //if(doc._ === 'documentEmpty') return;\r\n itemsDiv.append(this.superStickerRenderer.renderSticker(doc));\r\n });\r\n\r\n if(this.queueCategoryPush.length) {\r\n this.queueCategoryPush.forEach(({element, prepend}) => {\r\n if(prepend) {\r\n if(this.recentDiv.parentElement) {\r\n this.stickersDiv.prepend(element);\r\n this.stickersDiv.prepend(this.recentDiv);\r\n } else {\r\n this.stickersDiv.prepend(element);\r\n }\r\n } else this.stickersDiv.append(element);\r\n });\r\n\r\n this.queueCategoryPush.length = 0;\r\n }\r\n });\r\n\r\n return {titleDiv};\r\n }\r\n\r\n async renderStickerSet(set: StickerSet.stickerSet, prepend = false) {\r\n const categoryDiv = document.createElement('div');\r\n categoryDiv.classList.add('sticker-category');\r\n categoryDiv.dataset.id = '' + set.id;\r\n categoryDiv.dataset.access_hash = '' + set.access_hash;\r\n\r\n const button = document.createElement('button');\r\n button.classList.add('btn-icon', 'menu-horizontal-div-item');\r\n\r\n this.stickerSets[set.id] = {\r\n stickers: categoryDiv,\r\n tab: button\r\n };\r\n\r\n if(prepend) {\r\n this.menu.insertBefore(button, this.menu.firstElementChild.nextSibling);\r\n } else {\r\n this.menu.append(button);\r\n }\r\n\r\n //stickersScroll.append(categoryDiv);\r\n\r\n const promise = appStickersManager.getStickerSet(set);\r\n this.categoryPush(categoryDiv, RichTextProcessor.wrapEmojiText(set.title), promise.then(stickerSet => stickerSet.documents as MyDocument[]), prepend);\r\n const stickerSet = await promise;\r\n\r\n //console.log('got stickerSet', stickerSet, li);\r\n \r\n wrapStickerSetThumb({\r\n set,\r\n container: button,\r\n group: EMOTICONSSTICKERGROUP,\r\n lazyLoadQueue: EmoticonsDropdown.lazyLoadQueue,\r\n width: 32,\r\n height: 32,\r\n autoplay: false\r\n });\r\n }\r\n\r\n init() {\r\n this.content = document.getElementById('content-stickers');\r\n //let stickersDiv = contentStickersDiv.querySelector('.os-content') as HTMLDivElement;\r\n\r\n this.recentDiv = document.createElement('div');\r\n this.recentDiv.classList.add('sticker-category', 'stickers-recent');\r\n\r\n let menuWrapper = this.content.previousElementSibling as HTMLDivElement;\r\n this.menu = menuWrapper.firstElementChild as HTMLUListElement;\r\n\r\n let menuScroll = new ScrollableX(menuWrapper);\r\n\r\n this.stickersDiv = document.createElement('div');\r\n this.stickersDiv.classList.add('stickers-categories');\r\n this.content.append(this.stickersDiv);\r\n\r\n /* stickersDiv.addEventListener('mouseover', (e) => {\r\n let target = e.target as HTMLElement;\r\n\r\n if(target.tagName === 'CANVAS') { // turn on sticker\r\n let animation = lottieLoader.getAnimation(target.parentElement, EMOTICONSSTICKERGROUP);\r\n\r\n if(animation) {\r\n // @ts-ignore\r\n if(animation.currentFrame === animation.totalFrames - 1) {\r\n animation.goToAndPlay(0, true);\r\n } else {\r\n animation.play();\r\n }\r\n }\r\n }\r\n }); */\r\n\r\n rootScope.addEventListener('stickers_installed', (e) => {\r\n const set: StickerSet.stickerSet = e;\r\n \r\n if(!this.stickerSets[set.id] && this.mounted) {\r\n this.renderStickerSet(set, true);\r\n }\r\n });\r\n\r\n rootScope.addEventListener('stickers_deleted', (e) => {\r\n const set: StickerSet.stickerSet = e;\r\n \r\n if(this.stickerSets[set.id] && this.mounted) {\r\n const elements = this.stickerSets[set.id];\r\n elements.stickers.remove();\r\n elements.tab.remove();\r\n delete this.stickerSets[set.id];\r\n }\r\n });\r\n\r\n this.stickersDiv.addEventListener('click', (e) => {\r\n const target = e.target as HTMLElement;\r\n if(findUpClassName(target, 'category-title')) {\r\n const el = findUpAttribute(target, 'data-id');\r\n new PopupStickers({id: el.dataset.id, access_hash: el.dataset.access_hash}).show();\r\n return;\r\n }\r\n\r\n EmoticonsDropdown.onMediaClick(e);\r\n });\r\n\r\n const setTyping = (cancel = false) => {\r\n rootScope.dispatchEvent('choosing_sticker', !cancel);\r\n };\r\n\r\n this.scroll = new Scrollable(this.content, 'STICKERS');\r\n this.scroll.setVirtualContainer(this.stickersDiv);\r\n this.scroll.onAdditionalScroll = () => {\r\n setTyping();\r\n };\r\n\r\n emoticonsDropdown.addEventListener('closed', () => {\r\n setTyping(true);\r\n });\r\n\r\n emoticonsDropdown.addEventListener('opened', () => {\r\n setTyping();\r\n });\r\n\r\n this.stickyIntersector = EmoticonsDropdown.menuOnClick(this.menu, this.scroll, menuScroll).stickyIntersector;\r\n\r\n const preloader = putPreloader(this.content, true);\r\n\r\n Promise.all([\r\n appStickersManager.getRecentStickers().then(stickers => {\r\n this.recentStickers = stickers.stickers.slice(0, 20) as MyDocument[];\r\n \r\n //stickersScroll.prepend(categoryDiv);\r\n\r\n this.stickerSets['recent'] = {\r\n stickers: this.recentDiv,\r\n tab: this.menu.firstElementChild as HTMLElement\r\n };\r\n\r\n preloader.remove();\r\n const {titleDiv} = this.categoryPush(this.recentDiv, '', Promise.resolve(this.recentStickers), true);\r\n titleDiv.append(i18n('Stickers.Recent'));\r\n }),\r\n\r\n appStickersManager.getAllStickers().then((res) => {\r\n preloader.remove();\r\n\r\n for(let set of (res as MessagesAllStickers.messagesAllStickers).sets) {\r\n this.renderStickerSet(set);\r\n }\r\n })\r\n ]).finally(() => {\r\n this.mounted = true;\r\n setTyping();\r\n });\r\n\r\n this.superStickerRenderer = new SuperStickerRenderer(EmoticonsDropdown.lazyLoadQueue, EMOTICONSSTICKERGROUP);\r\n\r\n emoticonsDropdown.addLazyLoadQueueRepeat(this.superStickerRenderer.lazyLoadQueue, this.superStickerRenderer.processInvisibleDiv);\r\n\r\n /* setInterval(() => {\r\n // @ts-ignore\r\n const players = Object.values(lottieLoader.players).filter(p => p.width === 80);\r\n \r\n console.log('STICKERS RENDERED IN PANEL:', players.length, players.filter(p => !p.paused).length, this.superStickerRenderer.lazyLoadQueue.intersector.getVisible().length);\r\n }, .25e3); */\r\n \r\n\r\n this.init = null;\r\n }\r\n\r\n pushRecentSticker(doc: MyDocument) {\r\n appStickersManager.pushRecentSticker(doc);\r\n \r\n if(!this.recentDiv?.parentElement) {\r\n return;\r\n }\r\n\r\n let div = this.recentDiv.querySelector(`[data-doc-id=\"${doc.id}\"]`);\r\n if(!div) {\r\n div = this.superStickerRenderer.renderSticker(doc);\r\n }\r\n\r\n const items = this.recentDiv.querySelector('.category-items');\r\n items.prepend(div);\r\n\r\n if(items.childElementCount > 20) {\r\n (Array.from(items.children) as HTMLElement[]).slice(20).forEach(el => el.remove());\r\n }\r\n }\r\n\r\n onClose() {\r\n\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n * \r\n * Originally from:\r\n * https://github.com/zhukov/webogram\r\n * Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>\r\n * https://github.com/zhukov/webogram/blob/master/LICENSE\r\n */\r\n\r\nimport { toast } from \"../../components/toast\";\r\nimport { BotInlineResult, GeoPoint, InputGeoPoint, InputMedia, MessageEntity, MessagesBotResults, ReplyMarkup } from \"../../layer\";\r\nimport appPeersManager from \"./appPeersManager\";\r\nimport apiManagerProxy from \"../mtproto/mtprotoworker\";\r\nimport { RichTextProcessor } from \"../richtextprocessor\";\r\nimport appDocsManager, { MyDocument } from \"./appDocsManager\";\r\nimport appPhotosManager, { MyPhoto } from \"./appPhotosManager\";\r\nimport appUsersManager, { MyTopPeer } from \"./appUsersManager\";\r\nimport appMessagesManager from \"./appMessagesManager\";\r\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\r\nimport rootScope from \"../rootScope\";\r\nimport appDraftsManager from \"./appDraftsManager\";\r\nimport appMessagesIdsManager from \"./appMessagesIdsManager\";\r\nimport appStateManager from \"./appStateManager\";\r\nimport insertInDescendSortedArray from \"../../helpers/array/insertInDescendSortedArray\";\r\n\r\nexport class AppInlineBotsManager {\r\n private inlineResults: {[queryAndResultIds: string]: BotInlineResult} = {};\r\n private setHash: {\r\n [botId: UserId]: {\r\n peerId: PeerId, \r\n time: number\r\n }\r\n } = {};\r\n\r\n public getGeoInput(geo: GeoPoint): InputGeoPoint {\r\n return geo._ === 'geoPoint' ? {\r\n _: 'inputGeoPoint',\r\n lat: geo.lat,\r\n long: geo.long,\r\n accuracy_radius: geo.accuracy_radius\r\n } : {\r\n _: 'inputGeoPointEmpty'\r\n };\r\n }\r\n\r\n public getInlineResults(peerId: PeerId, botId: BotId, query = '', offset = '', geo?: GeoPoint) {\r\n return apiManagerProxy.invokeApi('messages.getInlineBotResults', {\r\n bot: appUsersManager.getUserInput(botId),\r\n peer: appPeersManager.getInputPeerById(peerId),\r\n query,\r\n geo_point: geo ? this.getGeoInput(geo) : undefined,\r\n offset\r\n }, {/* timeout: 1, */stopTime: -1, noErrorBox: true}).then(botResults => {\r\n const queryId = botResults.query_id;\r\n\r\n /* if(botResults.switch_pm) {\r\n botResults.switch_pm.rText = RichTextProcessor.wrapRichText(botResults.switch_pm.text, {noLinebreaks: true, noLinks: true});\r\n } */\r\n \r\n botResults.results.forEach(result => {\r\n if(result._ === 'botInlineMediaResult') {\r\n if(result.document) {\r\n result.document = appDocsManager.saveDoc(result.document);\r\n }\r\n \r\n if(result.photo) {\r\n result.photo = appPhotosManager.savePhoto(result.photo);\r\n }\r\n }\r\n \r\n this.inlineResults[this.generateQId(queryId, result.id)] = result;\r\n });\r\n\r\n return botResults;\r\n });\r\n }\r\n\r\n public generateQId(queryId: MessagesBotResults.messagesBotResults['query_id'], resultId: string) {\r\n return queryId + '_' + resultId;\r\n }\r\n\r\n private pushPopularBot(botId: BotId) {\r\n appUsersManager.getTopPeers('bots_inline').then((topPeers) => {\r\n const botPeerId = botId.toPeerId();\r\n const index = topPeers.findIndex(topPeer => topPeer.id === botPeerId);\r\n let topPeer: MyTopPeer;\r\n if(index !== -1) {\r\n topPeer = topPeers[index];\r\n } else {\r\n topPeer = {\r\n id: botPeerId,\r\n rating: 0\r\n };\r\n }\r\n\r\n ++topPeer.rating;\r\n insertInDescendSortedArray(topPeers, topPeer, 'rating');\r\n\r\n appStateManager.setKeyValueToStorage('topPeersCache');\r\n \r\n // rootScope.$broadcast('inline_bots_popular')\r\n });\r\n }\r\n\r\n public switchToPM(fromPeerId: PeerId, botId: BotId, startParam: string) {\r\n this.setHash[botId] = {peerId: fromPeerId, time: Date.now()};\r\n rootScope.dispatchEvent('history_focus', {peerId: botId.toPeerId()});\r\n return appMessagesManager.startBot(botId, undefined, startParam);\r\n }\r\n \r\n /*\r\n function resolveInlineMention (username) {\r\n return AppPeersManager.resolveUsername(username).then(function (peerId) {\r\n if (peerId.isUser()) {\r\n var bot = AppUsersManager.getUser(peerId)\r\n if (bot.pFlags.bot && bot.bot_inline_placeholder !== undefined) {\r\n var resolvedBot = {\r\n username: username,\r\n id: peerId,\r\n placeholder: bot.bot_inline_placeholder\r\n }\r\n if (bot.pFlags.bot_inline_geo &&\r\n GeoLocationManager.isAvailable()) {\r\n return checkGeoLocationAccess(peerId).then(function () {\r\n return GeoLocationManager.getPosition().then(function (coords) {\r\n resolvedBot.geo = coords\r\n return qSync.when(resolvedBot)\r\n })\r\n })['catch'](function () {\r\n return qSync.when(resolvedBot)\r\n })\r\n }\r\n return qSync.when(resolvedBot)\r\n }\r\n }\r\n return $q.reject()\r\n }, function (error) {\r\n error.handled = true\r\n return $q.reject(error)\r\n })\r\n }\r\n \r\n function regroupWrappedResults (results, rowW, rowH) {\r\n if (!results ||\r\n !results[0] ||\r\n ['photo', 'gif', 'sticker'].indexOf(results[0].type) === -1) {\r\n return\r\n }\r\n var ratios = []\r\n angular.forEach(results, function (result) {\r\n var w\r\n var h, doc\r\n var photo\r\n if (result._ === 'botInlineMediaResult') {\r\n if (doc = result.document) {\r\n w = result.document.w\r\n h = result.document.h\r\n }\r\n else if (photo = result.photo) {\r\n var photoSize = (photo.sizes || [])[0]\r\n w = photoSize && photoSize.w\r\n h = photoSize && photoSize.h\r\n }\r\n }else {\r\n w = result.w\r\n h = result.h\r\n }\r\n if (!w || !h) {\r\n w = h = 1\r\n }\r\n ratios.push(w / h)\r\n })\r\n \r\n var rows = []\r\n var curCnt = 0\r\n var curW = 0\r\n angular.forEach(ratios, function (ratio) {\r\n var w = ratio * rowH\r\n curW += w\r\n if (!curCnt || curCnt < 4 && curW < (rowW * 1.1)) {\r\n curCnt++\r\n } else {\r\n rows.push(curCnt)\r\n curCnt = 1\r\n curW = w\r\n }\r\n })\r\n if (curCnt) {\r\n rows.push(curCnt)\r\n }\r\n \r\n var i = 0\r\n var thumbs = []\r\n var lastRowI = rows.length - 1\r\n angular.forEach(rows, function (rowCnt, rowI) {\r\n var lastRow = rowI === lastRowI\r\n var curRatios = ratios.slice(i, i + rowCnt)\r\n var sumRatios = 0\r\n angular.forEach(curRatios, function (ratio) {\r\n sumRatios += ratio\r\n })\r\n angular.forEach(curRatios, function (ratio, j) {\r\n var thumbH = rowH\r\n var thumbW = rowW * ratio / sumRatios\r\n var realW = thumbH * ratio\r\n if (lastRow && thumbW > realW) {\r\n thumbW = realW\r\n }\r\n var result = results[i + j]\r\n result.thumbW = Math.floor(thumbW) - 2\r\n result.thumbH = Math.floor(thumbH) - 2\r\n })\r\n \r\n i += rowCnt\r\n })\r\n } */\r\n\r\n public async checkSwitchReturn(botId: BotId) {\r\n const bot = appUsersManager.getUser(botId);\r\n if(!bot || !bot.pFlags.bot || !bot.bot_inline_placeholder) {\r\n return;\r\n }\r\n\r\n const peerData = this.setHash[botId];\r\n if(peerData) {\r\n delete this.setHash[botId];\r\n if((Date.now() - peerData.time) < 3600e3) {\r\n return peerData.peerId;\r\n }\r\n }\r\n }\r\n\r\n public switchInlineQuery(peerId: PeerId, threadId: number, botId: BotId, query: string) {\r\n rootScope.dispatchEvent('history_focus', {peerId, threadId});\r\n appDraftsManager.setDraft(peerId, threadId, '@' + appUsersManager.getUser(botId).username + ' ' + query);\r\n }\r\n\r\n public callbackButtonClick(peerId: PeerId, mid: number, button: any) {\r\n return apiManagerProxy.invokeApi('messages.getBotCallbackAnswer', {\r\n peer: appPeersManager.getInputPeerById(peerId),\r\n msg_id: appMessagesIdsManager.getServerMessageId(mid),\r\n data: button.data\r\n }, {/* timeout: 1, */stopTime: -1, noErrorBox: true}).then((callbackAnswer) => {\r\n if(typeof callbackAnswer.message === 'string' && callbackAnswer.message.length) {\r\n toast(RichTextProcessor.wrapRichText(callbackAnswer.message, {noLinks: true, noLinebreaks: true}));\r\n }\r\n \r\n //console.log('callbackButtonClick callbackAnswer:', callbackAnswer);\r\n });\r\n }\r\n \r\n /* function gameButtonClick (id) {\r\n var message = AppMessagesManager.getMessage(id)\r\n var peerId = AppMessagesManager.getMessagePeer(message)\r\n \r\n return MtpApiManager.invokeApi('messages.getBotCallbackAnswer', {\r\n peer: AppPeersManager.getInputPeerByID(peerId),\r\n msg_id: AppMessagesIDsManager.getMessageLocalID(id)\r\n }, {timeout: 1, stopTime: -1, noErrorBox: true}).then(function (callbackAnswer) {\r\n if (typeof callbackAnswer.message === 'string' &&\r\n callbackAnswer.message.length) {\r\n showCallbackMessage(callbackAnswer.message, callbackAnswer.pFlags.alert)\r\n }\r\n else if (typeof callbackAnswer.url === 'string') {\r\n AppGamesManager.openGame(message.media.game.id, id, callbackAnswer.url)\r\n }\r\n })\r\n } */\r\n\r\n public sendInlineResult(peerId: PeerId, botId: BotId, queryAndResultIds: string, options: Partial<{\r\n viaBotId: BotId,\r\n queryId: string,\r\n resultId: string,\r\n replyMarkup: ReplyMarkup,\r\n entities: MessageEntity[],\r\n replyToMsgId: number,\r\n clearDraft: true,\r\n scheduleDate: number,\r\n silent: true,\r\n sendAsPeerId: PeerId,\r\n geoPoint: GeoPoint\r\n }> = {}) {\r\n const inlineResult = this.inlineResults[queryAndResultIds];\r\n if(!inlineResult) {\r\n return;\r\n }\r\n\r\n this.pushPopularBot(botId);\r\n const splitted = queryAndResultIds.split('_');\r\n const queryID = splitted.shift();\r\n const resultID = splitted.join('_');\r\n options.viaBotId = botId;\r\n options.queryId = queryID;\r\n options.resultId = resultID;\r\n if(inlineResult.send_message.reply_markup) {\r\n options.replyMarkup = inlineResult.send_message.reply_markup;\r\n }\r\n \r\n if(inlineResult.send_message._ === 'botInlineMessageText') {\r\n options.entities = inlineResult.send_message.entities;\r\n appMessagesManager.sendText(peerId, inlineResult.send_message.message, options);\r\n } else {\r\n let caption = '';\r\n let inputMedia: InputMedia;\r\n const sendMessage = inlineResult.send_message;\r\n switch(sendMessage._) {\r\n case 'botInlineMessageMediaAuto': {\r\n caption = sendMessage.message;\r\n\r\n if(inlineResult._ === 'botInlineMediaResult') {\r\n const {document, photo} = inlineResult;\r\n if(document) {\r\n inputMedia = appDocsManager.getMediaInput(document as MyDocument);\r\n } else {\r\n inputMedia = appPhotosManager.getMediaInput(photo as MyPhoto);\r\n }\r\n }\r\n\r\n break;\r\n }\r\n\r\n case 'botInlineMessageMediaGeo': {\r\n inputMedia = {\r\n _: 'inputMediaGeoPoint',\r\n geo_point: this.getGeoInput(sendMessage.geo)\r\n };\r\n\r\n options.geoPoint = sendMessage.geo;\r\n\r\n break;\r\n }\r\n \r\n case 'botInlineMessageMediaVenue': {\r\n inputMedia = {\r\n _: 'inputMediaVenue',\r\n geo_point: this.getGeoInput(sendMessage.geo),\r\n title: sendMessage.title,\r\n address: sendMessage.address,\r\n provider: sendMessage.provider,\r\n venue_id: sendMessage.venue_id,\r\n venue_type: sendMessage.venue_type\r\n };\r\n\r\n options.geoPoint = sendMessage.geo;\r\n\r\n break;\r\n }\r\n\r\n case 'botInlineMessageMediaContact': {\r\n inputMedia = {\r\n _: 'inputMediaContact',\r\n phone_number: sendMessage.phone_number,\r\n first_name: sendMessage.first_name,\r\n last_name: sendMessage.last_name,\r\n vcard: sendMessage.vcard\r\n };\r\n\r\n break;\r\n }\r\n }\r\n\r\n if(!inputMedia) {\r\n inputMedia = {\r\n _: 'messageMediaPending',\r\n type: inlineResult.type,\r\n file_name: inlineResult.title || \r\n (inlineResult as BotInlineResult.botInlineResult).content?.url || \r\n (inlineResult as BotInlineResult.botInlineResult).url,\r\n size: 0,\r\n progress: {percent: 30, total: 0}\r\n } as any;\r\n }\r\n\r\n appMessagesManager.sendOther(peerId, inputMedia, options);\r\n }\r\n }\r\n \r\n /* function checkGeoLocationAccess (botID) {\r\n var key = 'bot_access_geo' + botID\r\n return Storage.get(key).then(function (geoAccess) {\r\n if (geoAccess && geoAccess.granted) {\r\n return true\r\n }\r\n return ErrorService.confirm({\r\n type: 'BOT_ACCESS_GEO_INLINE'\r\n }).then(function () {\r\n var setHash = {}\r\n setHash[key] = {granted: true, time: tsNow()}\r\n Storage.set(setHash)\r\n return true\r\n }, function () {\r\n var setHash = {}\r\n setHash[key] = {denied: true, time: tsNow()}\r\n Storage.set(setHash)\r\n return $q.reject()\r\n })\r\n })\r\n } */\r\n}\r\n\r\nconst appInlineBotsManager = new AppInlineBotsManager();\r\nMOUNT_CLASS_TO && (MOUNT_CLASS_TO.appInlineBotsManager = appInlineBotsManager);\r\nexport default appInlineBotsManager;\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTab } from \"../../slider\";\r\nimport InputSearch from \"../../inputSearch\";\r\nimport animationIntersector from \"../../animationIntersector\";\r\nimport appSidebarRight from \"..\";\r\nimport appUsersManager from \"../../../lib/appManagers/appUsersManager\";\r\nimport appInlineBotsManager, { AppInlineBotsManager } from \"../../../lib/appManagers/appInlineBotsManager\";\r\nimport GifsMasonry from \"../../gifsMasonry\";\r\nimport appImManager from \"../../../lib/appManagers/appImManager\";\r\nimport type { MyDocument } from \"../../../lib/appManagers/appDocsManager\";\r\nimport mediaSizes from \"../../../helpers/mediaSizes\";\r\nimport findUpClassName from \"../../../helpers/dom/findUpClassName\";\r\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\r\nimport { NULL_PEER_ID } from \"../../../lib/mtproto/mtproto_config\";\r\n\r\nconst ANIMATIONGROUP = 'GIFS-SEARCH';\r\n\r\nexport default class AppGifsTab extends SliderSuperTab {\r\n private inputSearch: InputSearch;\r\n private gifsDiv: HTMLDivElement;\r\n\r\n private nextOffset = '';\r\n private loadedAll = false;\r\n\r\n private gifBotPeerId: PeerId;\r\n private masonry: GifsMasonry;\r\n\r\n private searchPromise: ReturnType<AppInlineBotsManager['getInlineResults']>;\r\n\r\n protected init() {\r\n this.container.id = 'search-gifs-container';\r\n \r\n this.inputSearch = new InputSearch('SearchGifsTitle', (value) => {\r\n this.reset();\r\n this.search(value);\r\n });\r\n \r\n this.title.replaceWith(this.inputSearch.container);\r\n \r\n this.gifsDiv = document.createElement('div');\r\n this.gifsDiv.classList.add('gifs-masonry');\r\n attachClickEvent(this.gifsDiv, this.onGifsClick, {listenerSetter: this.listenerSetter});\r\n \r\n this.scrollable.append(this.gifsDiv);\r\n \r\n this.masonry = new GifsMasonry(this.gifsDiv, ANIMATIONGROUP, this.scrollable);\r\n //this.backBtn.parentElement.append(this.inputSearch.container);\r\n }\r\n\r\n private onGifsClick = (e: MouseEvent | TouchEvent) => {\r\n const target = findUpClassName(e.target, 'gif');\r\n if(!target) return;\r\n\r\n const fileId = target.dataset.docId;\r\n if(appImManager.chat.input.sendMessageWithDocument(fileId)) {\r\n if(mediaSizes.isMobile) {\r\n appSidebarRight.onCloseBtnClick();\r\n }\r\n } else {\r\n console.warn('got no doc by id:', fileId);\r\n }\r\n };\r\n\r\n public onClose() {\r\n this.scrollable.onScrolledBottom = () => {};\r\n }\r\n\r\n public onCloseAfterTimeout() {\r\n this.reset();\r\n this.gifsDiv.innerHTML = '';\r\n animationIntersector.checkAnimations(undefined, ANIMATIONGROUP);\r\n this.inputSearch.remove();\r\n return super.onCloseAfterTimeout();\r\n }\r\n\r\n private reset() {\r\n this.searchPromise = null;\r\n this.nextOffset = '';\r\n this.loadedAll = false;\r\n this.masonry.clear();\r\n }\r\n\r\n public open() {\r\n const ret = super.open();\r\n appSidebarRight.toggleSidebar(true).then(() => {\r\n this.search('', true);\r\n\r\n this.scrollable.onScrolledBottom = () => {\r\n this.search(this.inputSearch.value, false);\r\n };\r\n });\r\n return ret;\r\n }\r\n\r\n public async search(query: string, newSearch = true) {\r\n if(this.searchPromise || this.loadedAll) return;\r\n\r\n if(!this.gifBotPeerId) {\r\n this.gifBotPeerId = (await appUsersManager.resolveUsername('gif')).id.toPeerId(false);\r\n }\r\n\r\n try {\r\n this.searchPromise = appInlineBotsManager.getInlineResults(NULL_PEER_ID, this.gifBotPeerId, query, this.nextOffset);\r\n const { results, next_offset } = await this.searchPromise;\r\n\r\n if(this.inputSearch.value !== query) {\r\n return;\r\n }\r\n\r\n this.searchPromise = null;\r\n this.nextOffset = next_offset;\r\n if(newSearch) {\r\n this.gifsDiv.innerHTML = '';\r\n }\r\n\r\n if(results.length) {\r\n results.forEach((result) => {\r\n if(result._ === 'botInlineMediaResult' && result.document) {\r\n this.masonry.add(result.document as MyDocument);\r\n }\r\n });\r\n } else {\r\n this.loadedAll = true;\r\n }\r\n\r\n this.scrollable.onScroll();\r\n } catch(err) {\r\n this.searchPromise = null;\r\n console.error('gifs loading error:', err);\r\n throw err;\r\n }\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTab } from \"../../slider\";\r\nimport InputSearch from \"../../inputSearch\";\r\nimport LazyLoadQueue from \"../../lazyLoadQueue\";\r\nimport appImManager from \"../../../lib/appManagers/appImManager\";\r\nimport appStickersManager from \"../../../lib/appManagers/appStickersManager\";\r\nimport PopupStickers from \"../../popups/stickers\";\r\nimport animationIntersector from \"../../animationIntersector\";\r\nimport { RichTextProcessor } from \"../../../lib/richtextprocessor\";\r\nimport { wrapSticker } from \"../../wrappers\";\r\nimport appSidebarRight from \"..\";\r\nimport { StickerSet, StickerSetCovered } from \"../../../layer\";\r\nimport { i18n } from \"../../../lib/langPack\";\r\nimport findUpClassName from \"../../../helpers/dom/findUpClassName\";\r\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\r\nimport forEachReverse from \"../../../helpers/array/forEachReverse\";\r\nimport setInnerHTML from \"../../../helpers/dom/setInnerHTML\";\r\n\r\nexport default class AppStickersTab extends SliderSuperTab {\r\n private inputSearch: InputSearch;\r\n private setsDiv: HTMLDivElement;\r\n private lazyLoadQueue: LazyLoadQueue;\r\n\r\n protected init() {\r\n this.container.id = 'stickers-container';\r\n this.container.classList.add('chatlist-container');\r\n\r\n this.lazyLoadQueue = new LazyLoadQueue();\r\n\r\n this.inputSearch = new InputSearch('StickersTab.SearchPlaceholder', (value) => {\r\n this.search(value);\r\n });\r\n\r\n this.title.replaceWith(this.inputSearch.container);\r\n\r\n this.setsDiv = document.createElement('div');\r\n this.setsDiv.classList.add('sticker-sets');\r\n this.scrollable.append(this.setsDiv);\r\n\r\n attachClickEvent(this.setsDiv, (e) => {\r\n const sticker = findUpClassName(e.target, 'sticker-set-sticker');\r\n if(sticker) {\r\n const docId = sticker.dataset.docId;\r\n appImManager.chat.input.sendMessageWithDocument(docId);\r\n return;\r\n }\r\n\r\n const target = findUpClassName(e.target, 'sticker-set');\r\n if(!target) return;\r\n\r\n const id = target.dataset.stickerSet as string;\r\n const access_hash = target.dataset.access_hash as string;\r\n\r\n const button = findUpClassName(e.target, 'sticker-set-button') as HTMLElement;\r\n if(button) {\r\n e.preventDefault();\r\n e.cancelBubble = true;\r\n\r\n button.setAttribute('disabled', 'true');\r\n \r\n appStickersManager.getStickerSet({id, access_hash}).then(full => {\r\n appStickersManager.toggleStickerSet(full.set).then(changed => {\r\n if(changed) {\r\n button.textContent = '';\r\n button.append(i18n(full.set.installed_date ? 'Stickers.SearchAdded' : 'Stickers.SearchAdd'));\r\n button.classList.toggle('gray', !!full.set.installed_date);\r\n }\r\n }).finally(() => {\r\n //button.style.width = set.installed_date ? '68px' : '52px';\r\n button.removeAttribute('disabled');\r\n });\r\n });\r\n } else {\r\n appStickersManager.getStickerSet({id, access_hash}).then(full => {\r\n new PopupStickers(full.set).show();\r\n });\r\n }\r\n }, {listenerSetter: this.listenerSetter});\r\n }\r\n\r\n public onCloseAfterTimeout() {\r\n this.setsDiv.innerHTML = '';\r\n animationIntersector.checkAnimations(undefined, 'STICKERS-SEARCH');\r\n return super.onCloseAfterTimeout();\r\n }\r\n\r\n public renderSet(set: StickerSet.stickerSet) {\r\n //console.log('renderSet:', set);\r\n const div = document.createElement('div');\r\n div.classList.add('sticker-set');\r\n\r\n const header = document.createElement('div');\r\n header.classList.add('sticker-set-header');\r\n\r\n const details = document.createElement('div');\r\n details.classList.add('sticker-set-details');\r\n details.innerHTML = `<div class=\"sticker-set-name\"></div>`;\r\n\r\n setInnerHTML(details.firstElementChild, RichTextProcessor.wrapEmojiText(set.title));\r\n\r\n const countDiv = document.createElement('div');\r\n countDiv.classList.add('sticker-set-count');\r\n countDiv.append(i18n('Stickers', [set.count]));\r\n details.append(countDiv);\r\n \r\n const button = document.createElement('button');\r\n button.classList.add('btn-primary', 'btn-color-primary', 'sticker-set-button');\r\n button.append(i18n(set.installed_date ? 'Stickers.SearchAdded' : 'Stickers.SearchAdd'));\r\n // button.style.width = set.installed_date ? '68px' : '52px';\r\n\r\n if(set.installed_date) {\r\n button.classList.add('gray');\r\n }\r\n\r\n //ripple(button);\r\n\r\n header.append(details, button);\r\n\r\n const stickersDiv = document.createElement('div');\r\n stickersDiv.classList.add('sticker-set-stickers');\r\n\r\n const count = Math.min(5, set.count);\r\n for(let i = 0; i < count; ++i) {\r\n const stickerDiv = document.createElement('div');\r\n stickerDiv.classList.add('sticker-set-sticker');\r\n\r\n stickersDiv.append(stickerDiv);\r\n }\r\n\r\n appStickersManager.getStickerSet(set).then(set => {\r\n //console.log('renderSet got set:', set);\r\n \r\n for(let i = 0; i < count; ++i) {\r\n const div = stickersDiv.children[i] as HTMLDivElement;\r\n const doc = set.documents[i];\r\n if(doc._ === 'documentEmpty') {\r\n continue;\r\n }\r\n\r\n wrapSticker({\r\n doc, \r\n div, \r\n lazyLoadQueue: this.lazyLoadQueue, \r\n group: 'STICKERS-SEARCH', \r\n /* play: false,\r\n loop: false, */\r\n play: true,\r\n loop: true,\r\n width: 68,\r\n height: 68\r\n });\r\n }\r\n });\r\n\r\n /* const onMouseOver = () => {\r\n const animations: AnimationItem['animation'][] = [];\r\n for(let i = 0; i < count; ++i) {\r\n const stickerDiv = stickersDiv.children[i] as HTMLElement;\r\n const animationItem = animationIntersector.getAnimation(stickerDiv);\r\n if(!animationItem) continue;\r\n\r\n const animation = animationItem.animation;\r\n\r\n animations.push(animation);\r\n animation.loop = true;\r\n animation.play();\r\n }\r\n\r\n div.addEventListener('mouseout', () => {\r\n animations.forEach(animation => {\r\n animation.loop = false;\r\n });\r\n\r\n div.addEventListener('mouseover', onMouseOver, {once: true});\r\n }, {once: true});\r\n };\r\n\r\n div.addEventListener('mouseover', onMouseOver, {once: true}); */\r\n\r\n div.dataset.stickerSet = '' + set.id;\r\n div.dataset.access_hash = '' + set.access_hash;\r\n div.dataset.title = set.title;\r\n\r\n div.append(header, stickersDiv);\r\n\r\n this.setsDiv.append(div);\r\n }\r\n\r\n public open() {\r\n const ret = super.open();\r\n appSidebarRight.toggleSidebar(true).then(() => {\r\n this.renderFeatured();\r\n });\r\n\r\n return ret;\r\n }\r\n\r\n public renderFeatured() {\r\n return appStickersManager.getFeaturedStickers().then(coveredSets => {\r\n if(this.inputSearch.value) {\r\n return;\r\n }\r\n\r\n coveredSets = this.filterRendered('', coveredSets);\r\n coveredSets.forEach(set => {\r\n this.renderSet(set.set);\r\n });\r\n });\r\n }\r\n\r\n private filterRendered(query: string, coveredSets: StickerSetCovered[]) {\r\n coveredSets = coveredSets.slice();\r\n\r\n const children = Array.from(this.setsDiv.children) as HTMLElement[];\r\n forEachReverse(children, el => {\r\n const id = el.dataset.stickerSet;\r\n const index = coveredSets.findIndex(covered => covered.set.id === id);\r\n \r\n if(index !== -1) {\r\n coveredSets.splice(index, 1);\r\n } else if(!query || !el.dataset.title.toLowerCase().includes(query.toLowerCase())) {\r\n el.remove();\r\n }\r\n });\r\n\r\n animationIntersector.checkAnimations(undefined, 'STICKERS-SEARCH');\r\n\r\n return coveredSets;\r\n }\r\n\r\n public search(query: string) {\r\n if(!query) {\r\n return this.renderFeatured();\r\n }\r\n\r\n return appStickersManager.searchStickerSets(query, false).then(coveredSets => {\r\n if(this.inputSearch.value !== query) {\r\n return;\r\n }\r\n\r\n //console.log('search result:', coveredSets);\r\n\r\n coveredSets = this.filterRendered(query, coveredSets);\r\n coveredSets.forEach(set => {\r\n this.renderSet(set.set);\r\n });\r\n });\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { attachClickEvent } from \"./dom/clickEvent\";\r\nimport findUpAsChild from \"./dom/findUpAsChild\";\r\nimport EventListenerBase from \"./eventListenerBase\";\r\nimport ListenerSetter from \"./listenerSetter\";\r\nimport { IS_TOUCH_SUPPORTED } from \"../environment/touchSupport\";\r\nimport safeAssign from \"./object/safeAssign\";\r\n\r\nconst KEEP_OPEN = false;\r\nconst TOGGLE_TIMEOUT = 200;\r\nconst ANIMATION_DURATION = 200;\r\n\r\nexport default class DropdownHover extends EventListenerBase<{\r\n open: () => Promise<any> | void,\r\n opened: () => any,\r\n close: () => any,\r\n closed: () => any\r\n}> {\r\n protected element: HTMLElement;\r\n protected displayTimeout: number;\r\n protected forceClose = false;\r\n protected inited = false;\r\n\r\n constructor(options: {\r\n element: DropdownHover['element']\r\n }) {\r\n super(false);\r\n safeAssign(this, options);\r\n }\r\n\r\n public attachButtonListener(button: HTMLElement, listenerSetter: ListenerSetter) {\r\n let firstTime = true;\r\n if(IS_TOUCH_SUPPORTED) {\r\n attachClickEvent(button, () => {\r\n if(firstTime) {\r\n firstTime = false;\r\n this.toggle(true);\r\n } else {\r\n this.toggle();\r\n }\r\n }, {listenerSetter});\r\n } else {\r\n listenerSetter.add(button)('mouseover', (e) => {\r\n //console.log('onmouseover button');\r\n if(firstTime) {\r\n listenerSetter.add(button)('mouseout', this.onMouseOut);\r\n firstTime = false;\r\n }\r\n\r\n clearTimeout(this.displayTimeout);\r\n this.displayTimeout = window.setTimeout(() => {\r\n this.toggle(true);\r\n }, TOGGLE_TIMEOUT);\r\n });\r\n }\r\n }\r\n\r\n private onMouseOut = (e: MouseEvent) => {\r\n if(KEEP_OPEN) return;\r\n clearTimeout(this.displayTimeout);\r\n if(!this.isActive()) return;\r\n\r\n const toElement = (e as any).toElement as Element;\r\n if(toElement && findUpAsChild(toElement, this.element)) {\r\n return;\r\n }\r\n\r\n this.displayTimeout = window.setTimeout(() => {\r\n this.toggle(false);\r\n }, TOGGLE_TIMEOUT);\r\n };\r\n\r\n protected init() {\r\n if(!IS_TOUCH_SUPPORTED) {\r\n this.element.onmouseout = this.onMouseOut;\r\n this.element.onmouseover = (e) => {\r\n if(this.forceClose) {\r\n return;\r\n }\r\n\r\n //console.log('onmouseover element');\r\n clearTimeout(this.displayTimeout);\r\n };\r\n }\r\n }\r\n\r\n public toggle = async(enable?: boolean) => {\r\n //if(!this.element) return;\r\n const willBeActive = (!!this.element.style.display && enable === undefined) || enable;\r\n if(this.init) {\r\n if(willBeActive) {\r\n this.init();\r\n this.init = null;\r\n } else {\r\n return;\r\n }\r\n }\r\n\r\n if(willBeActive === this.isActive()) {\r\n return;\r\n }\r\n \r\n if((this.element.style.display && enable === undefined) || enable) {\r\n const res = this.dispatchResultableEvent('open');\r\n await Promise.all(res);\r\n\r\n this.element.style.display = '';\r\n void this.element.offsetLeft; // reflow\r\n this.element.classList.add('active');\r\n\r\n clearTimeout(this.displayTimeout);\r\n this.displayTimeout = window.setTimeout(() => {\r\n this.forceClose = false;\r\n this.dispatchEvent('opened');\r\n }, IS_TOUCH_SUPPORTED ? 0 : ANIMATION_DURATION);\r\n\r\n // ! can't use together with resizeObserver\r\n /* if(isTouchSupported) {\r\n const height = this.element.scrollHeight + appImManager.chat.input.inputContainer.scrollHeight - 10;\r\n console.log('[ESG]: toggle: enable height', height);\r\n appImManager.chat.bubbles.scrollable.scrollTop += height;\r\n } */\r\n\r\n /* if(touchSupport) {\r\n this.restoreScroll();\r\n } */\r\n } else {\r\n this.dispatchEvent('close');\r\n\r\n this.element.classList.remove('active');\r\n\r\n clearTimeout(this.displayTimeout);\r\n this.displayTimeout = window.setTimeout(() => {\r\n this.element.style.display = 'none';\r\n this.forceClose = false;\r\n this.dispatchEvent('closed');\r\n }, IS_TOUCH_SUPPORTED ? 0 : ANIMATION_DURATION);\r\n\r\n /* if(isTouchSupported) {\r\n const scrollHeight = this.container.scrollHeight;\r\n if(scrollHeight) {\r\n const height = this.container.scrollHeight + appImManager.chat.input.inputContainer.scrollHeight - 10;\r\n appImManager.chat.bubbles.scrollable.scrollTop -= height;\r\n }\r\n } */\r\n\r\n /* if(touchSupport) {\r\n this.restoreScroll();\r\n } */\r\n }\r\n\r\n //animationIntersector.checkAnimations(false, EMOTICONSSTICKERGROUP);\r\n };\r\n\r\n public isActive() {\r\n return this.element.classList.contains('active');\r\n }\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { IS_TOUCH_SUPPORTED } from \"../../environment/touchSupport\";\nimport appImManager from \"../../lib/appManagers/appImManager\";\nimport rootScope from \"../../lib/rootScope\";\nimport animationIntersector from \"../animationIntersector\";\nimport { horizontalMenu } from \"../horizontalMenu\";\nimport LazyLoadQueue, { LazyLoadQueueIntersector } from \"../lazyLoadQueue\";\nimport Scrollable, { ScrollableX } from \"../scrollable\";\nimport appSidebarRight from \"../sidebarRight\";\nimport StickyIntersector from \"../stickyIntersector\";\nimport EmojiTab from \"./tabs/emoji\";\nimport GifsTab from \"./tabs/gifs\";\nimport StickersTab from \"./tabs/stickers\";\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\nimport AppGifsTab from \"../sidebarRight/tabs/gifs\";\nimport AppStickersTab from \"../sidebarRight/tabs/stickers\";\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\nimport findUpTag from \"../../helpers/dom/findUpTag\";\nimport blurActiveElement from \"../../helpers/dom/blurActiveElement\";\nimport whichChild from \"../../helpers/dom/whichChild\";\nimport cancelEvent from \"../../helpers/dom/cancelEvent\";\nimport DropdownHover from \"../../helpers/dropdownHover\";\nimport pause from \"../../helpers/schedulers/pause\";\nimport appMessagesManager from \"../../lib/appManagers/appMessagesManager\";\nimport { IS_APPLE_MOBILE } from \"../../environment/userAgent\";\n\nexport const EMOTICONSSTICKERGROUP = 'emoticons-dropdown';\n\nexport interface EmoticonsTab {\n init: () => void,\n onCloseAfterTimeout?: () => void\n}\n\nexport class EmoticonsDropdown extends DropdownHover {\n public static lazyLoadQueue = new LazyLoadQueue();\n\n private emojiTab: EmojiTab;\n public stickersTab: StickersTab;\n private gifsTab: GifsTab;\n\n private container: HTMLElement;\n private tabsEl: HTMLElement;\n private tabId = -1;\n\n private tabs: {[id: number]: EmoticonsTab};\n\n private searchButton: HTMLElement;\n private deleteBtn: HTMLElement;\n\n private selectTab: ReturnType<typeof horizontalMenu>;\n\n private savedRange: Range;\n\n constructor() {\n super({\n element: document.getElementById('emoji-dropdown') as HTMLDivElement\n });\n\n this.addEventListener('open', async() => {\n if(IS_TOUCH_SUPPORTED) {\n //appImManager.chat.input.saveScroll();\n if(blurActiveElement()) {\n await pause(100);\n }\n }\n\n if(this.element.parentElement !== appImManager.chat.input.chatInput) {\n appImManager.chat.input.chatInput.append(this.element);\n }\n\n this.savedRange = this.getGoodRange();\n\n EmoticonsDropdown.lazyLoadQueue.lock();\n //EmoticonsDropdown.lazyLoadQueue.unlock();\n animationIntersector.lockIntersectionGroup(EMOTICONSSTICKERGROUP);\n });\n\n this.addEventListener('opened', () => {\n animationIntersector.unlockIntersectionGroup(EMOTICONSSTICKERGROUP);\n EmoticonsDropdown.lazyLoadQueue.unlock();\n EmoticonsDropdown.lazyLoadQueue.refresh();\n\n this.container.classList.remove('disable-hover');\n });\n\n this.addEventListener('close', () => {\n EmoticonsDropdown.lazyLoadQueue.lock();\n //EmoticonsDropdown.lazyLoadQueue.lock();\n\n // нужно залочить группу и выключить стикеры\n animationIntersector.lockIntersectionGroup(EMOTICONSSTICKERGROUP);\n animationIntersector.checkAnimations(true, EMOTICONSSTICKERGROUP);\n });\n\n this.addEventListener('closed', () => {\n // теперь можно убрать visible, чтобы они не включились после фокуса\n animationIntersector.unlockIntersectionGroup(EMOTICONSSTICKERGROUP);\n EmoticonsDropdown.lazyLoadQueue.unlock();\n EmoticonsDropdown.lazyLoadQueue.refresh();\n\n this.container.classList.remove('disable-hover');\n\n this.savedRange = undefined;\n });\n }\n\n protected init() {\n this.emojiTab = new EmojiTab();\n this.stickersTab = new StickersTab();\n this.gifsTab = new GifsTab();\n\n this.tabs = {\n 0: this.emojiTab,\n 1: this.stickersTab,\n 2: this.gifsTab\n };\n\n this.container = this.element.querySelector('.emoji-container .tabs-container') as HTMLDivElement;\n this.tabsEl = this.element.querySelector('.emoji-tabs') as HTMLUListElement;\n this.selectTab = horizontalMenu(this.tabsEl, this.container, this.onSelectTabClick, () => {\n const tab = this.tabs[this.tabId];\n if(tab.init) {\n tab.init();\n }\n\n tab.onCloseAfterTimeout && tab.onCloseAfterTimeout();\n animationIntersector.checkAnimations(false, EMOTICONSSTICKERGROUP);\n });\n\n this.searchButton = this.element.querySelector('.emoji-tabs-search');\n this.searchButton.addEventListener('click', () => {\n if(this.tabId === 1) {\n if(!appSidebarRight.isTabExists(AppStickersTab)) {\n new AppStickersTab(appSidebarRight).open();\n }\n } else {\n if(!appSidebarRight.isTabExists(AppGifsTab)) {\n new AppGifsTab(appSidebarRight).open();\n }\n }\n });\n\n this.deleteBtn = this.element.querySelector('.emoji-tabs-delete');\n this.deleteBtn.addEventListener('click', (e) => {\n const input = appImManager.chat.input.messageInput;\n if((input.lastChild as any)?.tagName) {\n input.lastElementChild.remove();\n } else if(input.lastChild) {\n if(!input.lastChild.textContent.length) {\n input.lastChild.remove();\n } else {\n input.lastChild.textContent = input.lastChild.textContent.slice(0, -1);\n }\n }\n\n const event = new Event('input', {bubbles: true, cancelable: true});\n appImManager.chat.input.messageInput.dispatchEvent(event);\n //appSidebarRight.stickersTab.init();\n\n cancelEvent(e);\n });\n \n const HIDE_EMOJI_TAB = IS_APPLE_MOBILE;\n\n const INIT_TAB_ID = HIDE_EMOJI_TAB ? 1 : 0;\n\n if(HIDE_EMOJI_TAB) {\n (this.tabsEl.children[1] as HTMLElement).classList.add('hide');\n }\n\n (this.tabsEl.children[INIT_TAB_ID + 1] as HTMLLIElement).click(); // set emoji tab\n if(this.tabs[INIT_TAB_ID].init) {\n this.tabs[INIT_TAB_ID].init(); // onTransitionEnd не вызовется, т.к. это первая открытая вкладка\n }\n\n rootScope.addEventListener('peer_changed', this.checkRights);\n this.checkRights();\n\n return super.init();\n }\n\n private onSelectTabClick = (id: number) => {\n if(this.tabId === id) {\n return;\n }\n \n animationIntersector.checkAnimations(true, EMOTICONSSTICKERGROUP);\n\n this.tabId = id;\n this.searchButton.classList.toggle('hide', this.tabId === 0);\n this.deleteBtn.classList.toggle('hide', this.tabId !== 0);\n };\n\n private checkRights = () => {\n const {peerId, threadId} = appImManager.chat;\n const children = this.tabsEl.children;\n const tabsElements = Array.from(children) as HTMLElement[];\n\n const canSendStickers = appMessagesManager.canSendToPeer(peerId, threadId, 'send_stickers');\n tabsElements[2].toggleAttribute('disabled', !canSendStickers);\n\n const canSendGifs = appMessagesManager.canSendToPeer(peerId, threadId, 'send_gifs');\n tabsElements[3].toggleAttribute('disabled', !canSendGifs);\n\n const active = this.tabsEl.querySelector('.active');\n if(active && whichChild(active) !== 1 && (!canSendStickers || !canSendGifs)) {\n this.selectTab(0, false);\n }\n };\n\n public static menuOnClick = (menu: HTMLElement, scroll: Scrollable, menuScroll?: ScrollableX, prevId = 0) => {\n let jumpedTo = -1;\n\n const setActive = (id: number) => {\n if(id === prevId) {\n return false;\n }\n\n menu.children[prevId].classList.remove('active');\n menu.children[id].classList.add('active');\n prevId = id;\n\n return true;\n };\n\n const stickyIntersector = new StickyIntersector(scroll.container, (stuck, target) => {\n //console.log('sticky scrollTOp', stuck, target, scroll.container.scrollTop);\n\n if(Math.abs(jumpedTo - scroll.container.scrollTop) <= 1) {\n return;\n } else {\n jumpedTo = -1;\n }\n\n const which = whichChild(target);\n if(!stuck && which) { // * due to stickyIntersector\n return;\n }\n\n setActive(which);\n\n if(menuScroll) {\n if(which < menu.childElementCount - 4) {\n menuScroll.container.scrollLeft = (which - 3) * 47;\n } else {\n menuScroll.container.scrollLeft = which * 47;\n }\n }\n });\n\n menu.addEventListener('click', (e) => {\n let target = e.target as HTMLElement;\n target = findUpClassName(target, 'menu-horizontal-div-item');\n\n if(!target) {\n return;\n }\n\n const which = whichChild(target);\n\n /* if(menuScroll) {\n menuScroll.scrollIntoView(target, false, 0);\n } */\n\n if(!setActive(which)) {\n return;\n }\n\n const element = (scroll.splitUp || scroll.container).children[which] as HTMLElement;\n const offsetTop = element.offsetTop + 1; // * due to stickyIntersector\n\n scroll.container.scrollTop = jumpedTo = offsetTop;\n\n //console.log('set scrollTop:', offsetTop);\n });\n\n return {stickyIntersector, setActive};\n };\n\n public static onMediaClick = (e: {target: EventTarget | Element}, clearDraft = false) => {\n let target = e.target as HTMLElement;\n target = findUpTag(target, 'DIV');\n\n if(!target) return false;\n \n const fileId = target.dataset.docId;\n if(!fileId) return false;\n\n if(appImManager.chat.input.sendMessageWithDocument(fileId, undefined, clearDraft)) {\n /* dropdown.classList.remove('active');\n toggleEl.classList.remove('active'); */\n if(emoticonsDropdown.container) {\n emoticonsDropdown.forceClose = true;\n emoticonsDropdown.container.classList.add('disable-hover');\n emoticonsDropdown.toggle(false);\n }\n\n return true;\n } else {\n console.warn('got no doc by id:', fileId);\n return false;\n }\n };\n\n public addLazyLoadQueueRepeat(lazyLoadQueue: LazyLoadQueueIntersector, processInvisibleDiv: (div: HTMLElement) => void) {\n this.addEventListener('close', () => {\n lazyLoadQueue.lock();\n });\n\n this.addEventListener('closed', () => {\n const divs = lazyLoadQueue.intersector.getVisible();\n\n for(const div of divs) {\n processInvisibleDiv(div);\n }\n\n lazyLoadQueue.intersector.clearVisible();\n });\n\n this.addEventListener('opened', () => {\n lazyLoadQueue.unlockAndRefresh();\n });\n }\n\n public getSavedRange() {\n return this.getGoodRange() || this.savedRange;\n }\n\n private getGoodRange() {\n const sel = document.getSelection();\n if(sel.rangeCount && document.activeElement === appImManager.chat.input.messageInput) {\n return sel.getRangeAt(0);\n }\n }\n}\n\nconst emoticonsDropdown = new EmoticonsDropdown();\nMOUNT_CLASS_TO.emoticonsDropdown = emoticonsDropdown;\nexport default emoticonsDropdown;\n","import { IS_FIREFOX } from \"./userAgent\";\n\nconst IS_WEBRTC_SUPPORTED = !!(typeof(RTCPeerConnection) !== 'undefined' && !IS_FIREFOX);\n\nexport default IS_WEBRTC_SUPPORTED;\n","import IS_WEBRTC_SUPPORTED from \"./webrtcSupport\";\n\nconst IS_CALL_SUPPORTED = IS_WEBRTC_SUPPORTED;\n\nexport default IS_CALL_SUPPORTED;\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nexport default function getVisibleRect(\r\n element: HTMLElement, \r\n overflowElement: HTMLElement, \r\n lookForSticky?: boolean, \r\n rect = element.getBoundingClientRect(),\r\n overflowRect = overflowElement.getBoundingClientRect()\r\n) {\r\n let {top: overflowTop, right: overflowRight, bottom: overflowBottom, left: overflowLeft} = overflowRect;\r\n\r\n // * respect sticky headers\r\n if(lookForSticky) {\r\n const sticky = overflowElement.querySelector('.sticky');\r\n if(sticky) {\r\n const stickyRect = sticky.getBoundingClientRect();\r\n overflowTop = stickyRect.bottom;\r\n }\r\n }\r\n\r\n if(rect.top >= overflowBottom\r\n || rect.bottom <= overflowTop\r\n || rect.right <= overflowLeft\r\n || rect.left >= overflowRight) {\r\n return null;\r\n }\r\n\r\n const overflow = {\r\n top: false,\r\n right: false,\r\n bottom: false,\r\n left: false,\r\n vertical: 0 as 0 | 1 | 2,\r\n horizontal: 0 as 0 | 1 | 2\r\n };\r\n\r\n // @ts-ignore\r\n const w: any = 'visualViewport' in window ? window.visualViewport : window;\r\n const windowWidth = w.width || w.innerWidth;\r\n const windowHeight = w.height || w.innerHeight;\r\n\r\n return {\r\n rect: {\r\n top: rect.top < overflowTop && overflowTop !== 0 ? (overflow.top = true, ++overflow.vertical, overflowTop) : rect.top,\r\n right: rect.right > overflowRight && overflowRight !== windowWidth ? (overflow.right = true, ++overflow.horizontal, overflowRight) : rect.right,\r\n bottom: rect.bottom > overflowBottom && overflowBottom !== windowHeight ? (overflow.bottom = true, ++overflow.vertical, overflowBottom) : rect.bottom,\r\n left: rect.left < overflowLeft && overflowLeft !== 0 ? (overflow.left = true, ++overflow.horizontal, overflowLeft) : rect.left\r\n },\r\n overflow\r\n };\r\n}\r\n\r\n(window as any).getVisibleRect = getVisibleRect;\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nexport enum INTERNAL_LINK_TYPE {\n MESSAGE,\n PRIVATE_POST,\n STICKER_SET,\n JOIN_CHAT,\n VOICE_CHAT,\n USER_PHONE_NUMBER\n};\n\nexport type InternalLink = InternalLink.InternalLinkMessage | InternalLink.InternalLinkPrivatePost | InternalLink.InternalLinkStickerSet | InternalLink.InternalLinkJoinChat | InternalLink.InternalLinkVoiceChat | InternalLink.InternalLinkUserPhoneNumber;\n\nexport namespace InternalLink {\n export interface InternalLinkMessage {\n _: INTERNAL_LINK_TYPE.MESSAGE,\n domain: string,\n post?: string,\n comment?: string,\n start?: string\n }\n\n export interface InternalLinkPrivatePost {\n _: INTERNAL_LINK_TYPE.PRIVATE_POST,\n channel: string,\n post: string,\n thread?: string,\n comment?: string\n }\n\n export interface InternalLinkStickerSet {\n _: INTERNAL_LINK_TYPE.STICKER_SET,\n set: string\n }\n\n export interface InternalLinkJoinChat {\n _: INTERNAL_LINK_TYPE.JOIN_CHAT,\n invite: string\n }\n\n /**\n * LOCAL LINK\n */\n export interface InternalLinkVoiceChat {\n _: INTERNAL_LINK_TYPE.VOICE_CHAT,\n id: string,\n access_hash: string,\n chat_id: string\n }\n\n export interface InternalLinkUserPhoneNumber {\n _: INTERNAL_LINK_TYPE.USER_PHONE_NUMBER,\n phone: string\n }\n}\n\nexport type InternalLinkTypeMap = {\n [INTERNAL_LINK_TYPE.MESSAGE]: InternalLink.InternalLinkMessage,\n [INTERNAL_LINK_TYPE.PRIVATE_POST]: InternalLink.InternalLinkPrivatePost,\n [INTERNAL_LINK_TYPE.STICKER_SET]: InternalLink.InternalLinkStickerSet,\n [INTERNAL_LINK_TYPE.JOIN_CHAT]: InternalLink.InternalLinkJoinChat,\n [INTERNAL_LINK_TYPE.VOICE_CHAT]: InternalLink.InternalLinkVoiceChat,\n [INTERNAL_LINK_TYPE.USER_PHONE_NUMBER]: InternalLink.InternalLinkUserPhoneNumber\n};\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport PopupElement, { addCancelButton } from \".\";\r\nimport setInnerHTML from \"../../helpers/dom/setInnerHTML\";\r\nimport numberThousandSplitter from \"../../helpers/number/numberThousandSplitter\";\r\nimport { ChatInvite, Updates } from \"../../layer\";\r\nimport apiUpdatesManager from \"../../lib/appManagers/apiUpdatesManager\";\r\nimport appAvatarsManager from \"../../lib/appManagers/appAvatarsManager\";\r\nimport appPhotosManager from \"../../lib/appManagers/appPhotosManager\";\r\nimport { i18n, _i18n } from \"../../lib/langPack\";\r\nimport apiManager from \"../../lib/mtproto/mtprotoworker\";\r\nimport { NULL_PEER_ID } from \"../../lib/mtproto/mtproto_config\";\r\nimport RichTextProcessor from \"../../lib/richtextprocessor\";\r\nimport rootScope from \"../../lib/rootScope\";\r\nimport AvatarElement from \"../avatar\";\r\nimport { toastNew } from \"../toast\";\r\nimport { wrapPhoto } from \"../wrappers\";\r\n\r\n// const FAKE_CHAT_ID = Number.MAX_SAFE_INTEGER - 0x1000;\r\n\r\nexport default class PopupJoinChatInvite extends PopupElement {\r\n constructor(hash: string, chatInvite: ChatInvite.chatInvite) {\r\n super('popup-join-chat-invite', addCancelButton([{\r\n langKey: chatInvite.pFlags.request_needed ? 'RequestJoin.Button' : (chatInvite.pFlags.broadcast ? 'JoinByPeekChannelTitle' : 'JoinByPeekGroupTitle'),\r\n callback: () => {\r\n apiManager.invokeApi('messages.importChatInvite', {hash})\r\n .then((updates) => {\r\n apiUpdatesManager.processUpdateMessage(updates);\r\n const chat = (updates as Updates.updates).chats[0];\r\n const peerId = chat.id.toPeerId(true);\r\n rootScope.dispatchEvent('history_focus', {peerId});\r\n }, (error) => {\r\n if(error.type === 'INVITE_REQUEST_SENT') {\r\n toastNew({langPackKey: 'RequestToJoinSent'});\r\n }\r\n });\r\n }\r\n }]), {closable: true, overlayClosable: true, body: true});\r\n\r\n this.header.remove();\r\n\r\n /* const fakeChat: Chat.channel | Chat.chat = {\r\n _: chatInvite.pFlags.channel ? 'channel' : 'chat',\r\n id: FAKE_CHAT_ID,\r\n title: chatInvite.title,\r\n photo: chatInvite.photo as any,\r\n date: Date.now() / 1000 | 0,\r\n version: 0,\r\n participants_count: chatInvite.participants_count,\r\n pFlags: chatInvite.pFlags as any\r\n };\r\n\r\n appChatsManager.saveApiChat(fakeChat); */\r\n \r\n const avatarElem = new AvatarElement();\r\n avatarElem.classList.add('avatar-100');\r\n avatarElem.isDialog = false;\r\n if(chatInvite.photo._ === 'photo') {\r\n chatInvite.photo = appPhotosManager.savePhoto(chatInvite.photo);\r\n wrapPhoto({\r\n container: avatarElem,\r\n message: null,\r\n photo: chatInvite.photo,\r\n boxHeight: 100,\r\n boxWidth: 100,\r\n withoutPreloader: true\r\n });\r\n avatarElem.style.width = avatarElem.style.height = '';\r\n } else {\r\n appAvatarsManager.putPhoto(avatarElem, NULL_PEER_ID, false, chatInvite.title);\r\n }\r\n\r\n const title = document.createElement('div');\r\n title.classList.add('chat-title');\r\n setInnerHTML(title, RichTextProcessor.wrapEmojiText(chatInvite.title));\r\n //avatarElem.setAttribute('peer', '' + -fakeChat.id);\r\n \r\n const isBroadcast = chatInvite.pFlags.broadcast;\r\n const peopleCount = i18n(isBroadcast ? 'Subscribers' : 'Members', [numberThousandSplitter(chatInvite.participants_count)]);\r\n peopleCount.classList.add('chat-participants-count');\r\n\r\n this.body.append(avatarElem, title, peopleCount);\r\n\r\n if(chatInvite.pFlags.request_needed) {\r\n const caption = document.createElement('div');\r\n _i18n(caption, isBroadcast ? 'RequestToJoinChannelDescription' : 'RequestToJoinGroupDescription');\r\n caption.classList.add('chat-participants-count', 'request-caption');\r\n\r\n this.body.append(caption);\r\n }\r\n }\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport Scrollable from \"../components/scrollable\";\nimport { IS_SAFARI } from \"../environment/userAgent\";\nimport reflowScrollableElement from \"./dom/reflowScrollableElement\";\n\nexport default class ScrollSaver {\n private scrollHeight: number;\n private scrollHeightMinusTop: number;\n private scrollTop: number;\n private clientHeight: number;\n\n /**\n * \n * @param scrollable to reset scroll position and direction\n * @param reverse true means top\n */\n constructor(\n private scrollable: Scrollable, \n private reverse: boolean\n ) {\n\n }\n\n private get container() {\n return this.scrollable.container;\n }\n\n public getSaved() {\n return {\n scrollHeight: this.scrollHeight, \n scrollTop: this.scrollTop,\n clientHeight: this.clientHeight\n };\n }\n\n public save() {\n const {scrollTop, scrollHeight, clientHeight} = this.container;\n\n //previousScrollHeight = scrollHeight;\n //previousScrollHeight = scrollHeight + padding;\n this.scrollHeight = scrollHeight;\n this.scrollTop = scrollTop;\n this.clientHeight = clientHeight;\n this.scrollHeightMinusTop = this.reverse ? scrollHeight - scrollTop : scrollTop;\n\n //this.chatInner.style.paddingTop = padding + 'px';\n /* if(reverse) {\n previousScrollHeightMinusTop = this.scrollable.scrollHeight - scrollTop;\n } else {\n previousScrollHeightMinusTop = scrollTop;\n } */\n\n /* if(DEBUG) {\n this.log('performHistoryResult: messagesQueueOnRender, scrollTop:', scrollTop, scrollHeight, previousScrollHeightMinusTop);\n } */\n }\n\n public restore(useReflow?: boolean) {\n const {container, scrollHeightMinusTop: previousScrollHeightMinusTop, scrollable} = this;\n if(previousScrollHeightMinusTop === undefined) {\n throw new Error('scroll was not saved');\n }\n\n const scrollHeight = container.scrollHeight;\n if(scrollHeight === this.scrollHeight) {\n return;\n }\n\n this.scrollHeight = scrollHeight;\n\n /* const scrollHeight = container.scrollHeight;\n const addedHeight = scrollHeight - previousScrollHeight;\n \n this.chatInner.style.paddingTop = (10000 - addedHeight) + 'px'; */\n /* const scrollHeight = scrollHeight;\n const addedHeight = scrollHeight - previousScrollHeight;\n \n this.chatInner.style.paddingTop = (padding - addedHeight) + 'px';\n \n //const newScrollTop = reverse ? scrollHeight - previousScrollHeightMinusTop : previousScrollHeightMinusTop;\n const newScrollTop = reverse ? scrollHeight - addedHeight - previousScrollHeightMinusTop : previousScrollHeightMinusTop;\n this.log('performHistoryResult: will set scrollTop', \n previousScrollHeightMinusTop, scrollHeight, \n newScrollTop, container.container.clientHeight); */\n //const newScrollTop = reverse ? scrollHeight - previousScrollHeightMinusTop : previousScrollHeightMinusTop;\n const newScrollTop = this.reverse ? scrollHeight - previousScrollHeightMinusTop : previousScrollHeightMinusTop;\n \n /* if(DEBUG) {\n this.log('performHistoryResult: will set up scrollTop:', newScrollTop, this.isHeavyAnimationInProgress);\n } */\n\n // touchSupport for safari iOS\n //isTouchSupported && isApple && (container.container.style.overflow = 'hidden');\n this.scrollable.setScrollTopSilently(this.scrollTop = newScrollTop);\n //container.scrollTop = scrollHeight;\n //isTouchSupported && isApple && (container.container.style.overflow = '');\n\n if(IS_SAFARI && useReflow/* && !isAppleMobile */) { // * fix blinking and jumping\n reflowScrollableElement(container);\n }\n\n /* if(DEBUG) {\n this.log('performHistoryResult: have set up scrollTop:', newScrollTop, container.scrollTop, container.scrollHeight, this.isHeavyAnimationInProgress);\n } */\n\n return;\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nexport type IntersectionTarget = Element;\nexport type IntersectionCallback = (entry: IntersectionObserverEntry) => void;\n\nexport default class SuperIntersectionObserver {\n private observing: Map<IntersectionTarget, Set<IntersectionCallback>>;\n private observingQueue: SuperIntersectionObserver['observing'];\n private observer: IntersectionObserver;\n private freezedObservingNew: boolean;\n\n constructor(init?: IntersectionObserverInit) {\n this.observing = new Map();\n this.observingQueue = new Map();\n this.freezedObservingNew = false;\n\n this.observer = new IntersectionObserver((entries) => {\n const observing = this.observing;\n for(let i = 0, length = entries.length; i < length; ++i) {\n const entry = entries[i];\n const callbacks = observing.get(entry.target);\n if(!callbacks) {\n debugger;\n }\n\n for(const callback of callbacks) {\n try {\n callback(entry);\n } catch(err) {\n console.error('intersection process callback error:', err);\n }\n }\n }\n }, init);\n }\n\n public disconnect() {\n this.observing.clear();\n this.observingQueue.clear();\n this.observer.disconnect();\n }\n\n public toggleObservingNew(value: boolean) {\n if(this.freezedObservingNew === value) {\n return;\n }\n\n this.freezedObservingNew = value;\n\n const queue = this.observingQueue;\n if(!value && queue.size) {\n for(const [target, callbacks] of queue) {\n for(const callback of callbacks) {\n this.observe(target, callback);\n }\n }\n\n queue.clear();\n }\n }\n\n public has(target: IntersectionTarget, callback: IntersectionCallback, observing = this.observing) {\n const callbacks = observing.get(target);\n return !!(callbacks && callbacks.has(callback));\n }\n\n public observe(target: IntersectionTarget, callback: IntersectionCallback) {\n if(this.freezedObservingNew && this.has(target, callback)) {\n return;\n }\n\n const observing = this.freezedObservingNew ? this.observingQueue : this.observing;\n let callbacks = observing.get(target);\n if(callbacks && callbacks.has(callback)) {\n return;\n }\n\n if(!callbacks) {\n callbacks = new Set();\n observing.set(target, callbacks);\n\n if(observing === this.observing) {\n this.observer.observe(target);\n }\n }\n\n callbacks.add(callback);\n }\n\n public unobserve(target: IntersectionTarget, callback: IntersectionCallback) {\n const observing = this.freezedObservingNew && !this.has(target, callback) ? this.observingQueue : this.observing;\n const callbacks = observing.get(target);\n if(!callbacks) {\n return;\n }\n\n callbacks.delete(callback);\n if(!callbacks.size) {\n observing.delete(target);\n this.observer.unobserve(target);\n }\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport type { AppImManager } from \"../../lib/appManagers/appImManager\";\r\nimport type { AppMessagesManager, HistoryResult, HistoryStorage, MyMessage } from \"../../lib/appManagers/appMessagesManager\";\r\nimport type { AppStickersManager } from \"../../lib/appManagers/appStickersManager\";\r\nimport type { AppUsersManager } from \"../../lib/appManagers/appUsersManager\";\r\nimport type { AppInlineBotsManager } from \"../../lib/appManagers/appInlineBotsManager\";\r\nimport type { AppPhotosManager } from \"../../lib/appManagers/appPhotosManager\";\r\nimport type { MyDocument } from \"../../lib/appManagers/appDocsManager\";\r\nimport type { AppPeersManager } from \"../../lib/appManagers/appPeersManager\";\r\nimport type { AppChatsManager } from \"../../lib/appManagers/appChatsManager\";\r\nimport type { AppProfileManager } from \"../../lib/appManagers/appProfileManager\";\r\nimport type { AppDraftsManager } from \"../../lib/appManagers/appDraftsManager\";\r\nimport type { AppMessagesIdsManager } from \"../../lib/appManagers/appMessagesIdsManager\";\r\nimport type { AppWebPagesManager } from \"../../lib/appManagers/appWebPagesManager\";\r\nimport type Chat from \"./chat\";\r\nimport { CHAT_ANIMATION_GROUP } from \"../../lib/appManagers/appImManager\";\r\nimport { IS_TOUCH_SUPPORTED } from \"../../environment/touchSupport\";\r\nimport { logger } from \"../../lib/logger\";\r\nimport rootScope from \"../../lib/rootScope\";\r\nimport BubbleGroups from \"./bubbleGroups\";\r\nimport PopupDatePicker from \"../popups/datePicker\";\r\nimport PopupForward from \"../popups/forward\";\r\nimport PopupStickers from \"../popups/stickers\";\r\nimport ProgressivePreloader from \"../preloader\";\r\nimport Scrollable, { SliceSides } from \"../scrollable\";\r\nimport StickyIntersector from \"../stickyIntersector\";\r\nimport animationIntersector from \"../animationIntersector\";\r\nimport RichTextProcessor from \"../../lib/richtextprocessor\";\r\nimport mediaSizes from \"../../helpers/mediaSizes\";\r\nimport { IS_ANDROID, IS_APPLE, IS_MOBILE, IS_SAFARI } from \"../../environment/userAgent\";\r\nimport I18n, { FormatterArguments, i18n, langPack, LangPackKey, UNSUPPORTED_LANG_PACK_KEY, _i18n } from \"../../lib/langPack\";\r\nimport AvatarElement from \"../avatar\";\r\nimport ripple from \"../ripple\";\r\nimport { wrapAlbum, wrapPhoto, wrapVideo, wrapDocument, wrapSticker, wrapPoll, wrapGroupedDocuments } from \"../wrappers\";\r\nimport { MessageRender } from \"./messageRender\";\r\nimport LazyLoadQueue from \"../lazyLoadQueue\";\r\nimport ListenerSetter from \"../../helpers/listenerSetter\";\r\nimport PollElement from \"../poll\";\r\nimport AudioElement from \"../audio\";\r\nimport { ChatInvite, Message, MessageEntity, MessageMedia, MessageReplyHeader, Photo, PhotoSize, ReactionCount, ReplyMarkup, SponsoredMessage, Update, User, WebPage } from \"../../layer\";\r\nimport { NULL_PEER_ID, REPLIES_PEER_ID } from \"../../lib/mtproto/mtproto_config\";\r\nimport { FocusDirection, ScrollStartCallbackDimensions } from \"../../helpers/fastSmoothScroll\";\r\nimport useHeavyAnimationCheck, { getHeavyAnimationPromise, dispatchHeavyAnimationEvent, interruptHeavyAnimation } from \"../../hooks/useHeavyAnimationCheck\";\r\nimport { fastRaf, fastRafPromise } from \"../../helpers/schedulers\";\r\nimport deferredPromise from \"../../helpers/cancellablePromise\";\r\nimport RepliesElement from \"./replies\";\r\nimport DEBUG from \"../../config/debug\";\r\nimport { SliceEnd } from \"../../helpers/slicedArray\";\r\nimport serverTimeManager from \"../../lib/mtproto/serverTimeManager\";\r\nimport PeerTitle from \"../peerTitle\";\r\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\r\nimport findUpTag from \"../../helpers/dom/findUpTag\";\r\nimport { toast, toastNew } from \"../toast\";\r\nimport { getElementByPoint } from \"../../helpers/dom/getElementByPoint\";\r\nimport { getMiddleware } from \"../../helpers/middleware\";\r\nimport cancelEvent from \"../../helpers/dom/cancelEvent\";\r\nimport { attachClickEvent, simulateClickEvent } from \"../../helpers/dom/clickEvent\";\r\nimport htmlToDocumentFragment from \"../../helpers/dom/htmlToDocumentFragment\";\r\nimport positionElementByIndex from \"../../helpers/dom/positionElementByIndex\";\r\nimport reflowScrollableElement from \"../../helpers/dom/reflowScrollableElement\";\r\nimport replaceContent from \"../../helpers/dom/replaceContent\";\r\nimport setInnerHTML from \"../../helpers/dom/setInnerHTML\";\r\nimport whichChild from \"../../helpers/dom/whichChild\";\r\nimport { cancelAnimationByKey } from \"../../helpers/animation\";\r\nimport assumeType from \"../../helpers/assumeType\";\r\nimport { EmoticonsDropdown } from \"../emoticonsDropdown\";\r\nimport debounce, { DebounceReturnType } from \"../../helpers/schedulers/debounce\";\r\nimport { SEND_WHEN_ONLINE_TIMESTAMP } from \"../../lib/mtproto/constants\";\r\nimport windowSize from \"../../helpers/windowSize\";\r\nimport { formatPhoneNumber } from \"../../helpers/formatPhoneNumber\";\r\nimport AppMediaViewer from \"../appMediaViewer\";\r\nimport SetTransition from \"../singleTransition\";\r\nimport handleHorizontalSwipe from \"../../helpers/dom/handleHorizontalSwipe\";\r\nimport { cancelContextMenuOpening } from \"../misc\";\r\nimport findUpAttribute from \"../../helpers/dom/findUpAttribute\";\r\nimport findUpAsChild from \"../../helpers/dom/findUpAsChild\";\r\nimport formatCallDuration from \"../../helpers/formatCallDuration\";\r\nimport IS_CALL_SUPPORTED from \"../../environment/callSupport\";\r\nimport Button from \"../button\";\r\nimport { CallType } from \"../../lib/calls/types\";\r\nimport getVisibleRect from \"../../helpers/dom/getVisibleRect\";\r\nimport PopupJoinChatInvite from \"../popups/joinChatInvite\";\r\nimport { InternalLink, INTERNAL_LINK_TYPE } from \"../../lib/appManagers/internalLink\";\r\nimport ReactionsElement, { REACTIONS_ELEMENTS } from \"./reactions\";\r\nimport type ReactionElement from \"./reaction\";\r\nimport type { AppReactionsManager } from \"../../lib/appManagers/appReactionsManager\";\r\nimport RLottiePlayer from \"../../lib/rlottie/rlottiePlayer\";\r\nimport pause from \"../../helpers/schedulers/pause\";\r\nimport ScrollSaver from \"../../helpers/scrollSaver\";\r\nimport getObjectKeysAndSort from \"../../helpers/object/getObjectKeysAndSort\";\r\nimport forEachReverse from \"../../helpers/array/forEachReverse\";\r\nimport formatNumber from \"../../helpers/number/formatNumber\";\r\nimport findAndSplice from \"../../helpers/array/findAndSplice\";\r\nimport getViewportSlice from \"../../helpers/dom/getViewportSlice\";\r\nimport SuperIntersectionObserver from \"../../helpers/dom/superIntersectionObserver\";\r\nimport generateFakeIcon from \"../generateFakeIcon\";\r\nimport copyFromElement from \"../../helpers/dom/copyFromElement\";\r\n\r\nconst USE_MEDIA_TAILS = false;\r\nconst IGNORE_ACTIONS: Set<Message.messageService['action']['_']> = new Set([\r\n 'messageActionHistoryClear',\r\n 'messageActionChatCreate'/* ,\r\n 'messageActionChannelMigrateFrom' */\r\n]);\r\n\r\nconst SERVICE_AS_REGULAR: Set<Message.messageService['action']['_']> = new Set();\r\n\r\nif(IS_CALL_SUPPORTED) {\r\n SERVICE_AS_REGULAR.add('messageActionPhoneCall');\r\n}\r\n\r\nconst TEST_SCROLL_TIMES: number = undefined;\r\nlet TEST_SCROLL = TEST_SCROLL_TIMES;\r\n\r\nlet queueId = 0;\r\n\r\ntype GenerateLocalMessageType<IsService> = IsService extends true ? Message.messageService : Message.message;\r\n\r\nconst SPONSORED_MESSAGE_ID_OFFSET = 1;\r\nconst STICKY_OFFSET = 3;\r\nconst SCROLLED_DOWN_THRESHOLD = 300;\r\n\r\nexport default class ChatBubbles {\r\n public bubblesContainer: HTMLDivElement;\r\n private chatInner: HTMLDivElement;\r\n public scrollable: Scrollable;\r\n\r\n private getHistoryTopPromise: Promise<boolean>;\r\n private getHistoryBottomPromise: Promise<boolean>;\r\n\r\n public peerId: PeerId;\r\n //public messagesCount: number = -1;\r\n\r\n private unreadOut = new Set<number>();\r\n public needUpdate: {replyToPeerId: PeerId, replyMid: number, mid: number}[] = []; // if need wrapSingleMessage\r\n\r\n public bubbles: {[mid: string]: HTMLElement} = {};\r\n public skippedMids: Set<number> = new Set();\r\n private dateMessages: {[timestamp: number]: { \r\n div: HTMLElement, \r\n firstTimestamp: number, \r\n container: HTMLElement,\r\n timeout?: number \r\n }} = {};\r\n\r\n private scrolledDown = true;\r\n private isScrollingTimeout = 0;\r\n\r\n private stickyIntersector: StickyIntersector;\r\n\r\n private unreaded: Map<HTMLElement, number> = new Map();\r\n private unreadedSeen: Set<number> = new Set();\r\n private readPromise: Promise<void>;\r\n\r\n private bubbleGroups: BubbleGroups;\r\n\r\n private preloader: ProgressivePreloader = null;\r\n\r\n public messagesQueuePromise: Promise<void> = null;\r\n private messagesQueue: {message: any, bubble: HTMLElement, reverse: boolean, promises: Promise<void>[]}[] = [];\r\n private messagesQueueOnRender: () => void = null;\r\n private messagesQueueOnRenderAdditional: () => void = null;\r\n\r\n private firstUnreadBubble: HTMLElement = null;\r\n private attachedUnreadBubble: boolean;\r\n\r\n public lazyLoadQueue: LazyLoadQueue;\r\n\r\n private middleware = getMiddleware();\r\n\r\n private log: ReturnType<typeof logger>;\r\n\r\n public listenerSetter: ListenerSetter;\r\n\r\n private replyFollowHistory: number[] = [];\r\n\r\n private isHeavyAnimationInProgress = false;\r\n private scrollingToBubble: HTMLElement;\r\n\r\n private isFirstLoad = true;\r\n private needReflowScroll: boolean;\r\n\r\n private fetchNewPromise: Promise<void>;\r\n private historyStorage: HistoryStorage;\r\n\r\n private passEntities: Partial<{\r\n [_ in MessageEntity['_']]: boolean\r\n }> = {};\r\n\r\n private onAnimateLadder: () => Promise<any> | void;\r\n // private ladderDeferred: CancellablePromise<void>;\r\n private resolveLadderAnimation: () => Promise<any>;\r\n private emptyPlaceholderMid: number;\r\n\r\n private viewsMids: Set<number> = new Set();\r\n private sendViewCountersDebounced: () => Promise<void>;\r\n\r\n private isTopPaddingSet = false;\r\n\r\n private getSponsoredMessagePromise: Promise<void>;\r\n\r\n private previousStickyDate: HTMLElement;\r\n private sponsoredMessage: SponsoredMessage.sponsoredMessage;\r\n \r\n private hoverBubble: HTMLElement;\r\n private hoverReaction: HTMLElement;\r\n private sliceViewportDebounced: DebounceReturnType<ChatBubbles['sliceViewport']>;\r\n private resizeObserver: ResizeObserver;\r\n private willScrollOnLoad: boolean;\r\n private observer: SuperIntersectionObserver;\r\n\r\n // private reactions: Map<number, ReactionsElement>;\r\n\r\n constructor(\r\n private chat: Chat, \r\n private appMessagesManager: AppMessagesManager, \r\n private appStickersManager: AppStickersManager, \r\n private appUsersManager: AppUsersManager, \r\n private appInlineBotsManager: AppInlineBotsManager, \r\n private appPhotosManager: AppPhotosManager, \r\n private appPeersManager: AppPeersManager,\r\n private appProfileManager: AppProfileManager,\r\n private appDraftsManager: AppDraftsManager,\r\n private appMessagesIdsManager: AppMessagesIdsManager,\r\n private appChatsManager: AppChatsManager,\r\n private appReactionsManager: AppReactionsManager,\r\n private appWebPagesManager: AppWebPagesManager\r\n ) {\r\n //this.chat.log.error('Bubbles construction');\r\n \r\n this.listenerSetter = new ListenerSetter();\r\n\r\n this.bubblesContainer = document.createElement('div');\r\n this.bubblesContainer.classList.add('bubbles', 'scrolled-down');\r\n\r\n this.chatInner = document.createElement('div');\r\n this.chatInner.classList.add('bubbles-inner');\r\n\r\n this.setScroll();\r\n\r\n this.bubblesContainer.append(this.scrollable.container);\r\n\r\n // * constructor end\r\n\r\n this.log = this.chat.log;\r\n this.bubbleGroups = new BubbleGroups(this.chat);\r\n this.preloader = new ProgressivePreloader({\r\n cancelable: false\r\n });\r\n this.lazyLoadQueue = new LazyLoadQueue();\r\n this.lazyLoadQueue.queueId = ++queueId;\r\n\r\n // this.reactions = new Map();\r\n\r\n // * events\r\n\r\n // will call when sent for update pos\r\n this.listenerSetter.add(rootScope)('history_update', ({storage, peerId, mid}) => {\r\n if(this.chat.getMessagesStorage() === storage) {\r\n const bubble = this.bubbles[mid];\r\n if(!bubble) return;\r\n\r\n const message = this.chat.getMessage(mid);\r\n \r\n if(+bubble.dataset.timestamp >= (message.date + serverTimeManager.serverTimeOffset - 1)) {\r\n this.bubbleGroups.changeBubbleMid(bubble, mid);\r\n return;\r\n }\r\n\r\n this.setBubblePosition(bubble, message, false);\r\n //this.log('history_update', this.bubbles[mid], mid, message);\r\n\r\n if(this.scrollingToBubble) {\r\n this.scrollToEnd();\r\n }\r\n\r\n //this.renderMessage(message, false, false, bubble);\r\n }\r\n });\r\n\r\n //this.listenerSetter.add(rootScope)('')\r\n\r\n this.listenerSetter.add(rootScope)('dialog_flush', ({peerId}) => {\r\n if(this.peerId === peerId) {\r\n this.deleteMessagesByIds(Object.keys(this.bubbles).map(m => +m));\r\n }\r\n });\r\n\r\n // Calls when message successfully sent and we have an id\r\n this.listenerSetter.add(rootScope)('message_sent', (e) => {\r\n const {storage, tempId, tempMessage, mid} = e;\r\n\r\n // ! can't use peerId to validate here, because id can be the same in 'scheduled' and 'chat' types\r\n if(this.chat.getMessagesStorage() !== storage) {\r\n return;\r\n }\r\n \r\n //this.log('message_sent', e);\r\n\r\n // cannot use it here because new message will be rendered again\r\n // await getHeavyAnimationPromise();\r\n\r\n const mounted = this.getMountedBubble(tempId, tempMessage) || this.getMountedBubble(mid);\r\n if(mounted) {\r\n const message = this.chat.getMessage(mid);\r\n const bubble = mounted.bubble;\r\n //this.bubbles[mid] = bubble;\r\n \r\n /////this.log('message_sent', bubble);\r\n\r\n const reactionsElements = Array.from(bubble.querySelectorAll('reactions-element')) as ReactionsElement[];\r\n if(reactionsElements.length) {\r\n reactionsElements.forEach(reactionsElement => {\r\n reactionsElement.changeMessage(message as Message.message);\r\n });\r\n }\r\n\r\n if(message.replies) {\r\n const repliesElement = bubble.querySelector('replies-element') as RepliesElement;\r\n if(repliesElement) {\r\n repliesElement.message = message;\r\n repliesElement.init();\r\n }\r\n }\r\n\r\n if(message.media?.document) {\r\n const div = bubble.querySelector(`.document-container[data-mid=\"${tempId}\"] .document`);\r\n if(div) {\r\n const container = findUpClassName(div, 'document-container');\r\n\r\n if(!tempMessage.media?.document?.thumbs?.length && message.media.document.thumbs?.length) {\r\n getHeavyAnimationPromise().then(() => {\r\n const timeSpan = div.querySelector('.time');\r\n const newDiv = wrapDocument({message});\r\n div.replaceWith(newDiv);\r\n \r\n if(timeSpan) {\r\n newDiv.querySelector('.document-size').append(timeSpan);\r\n }\r\n });\r\n }\r\n\r\n if(container) {\r\n container.dataset.mid = '' + mid;\r\n }\r\n }\r\n }\r\n\r\n // set new mids to album items for mediaViewer\r\n if(message.grouped_id) {\r\n const item = (bubble.querySelector(`.grouped-item[data-mid=\"${tempId}\"]`) as HTMLElement) || bubble; // * it can be .document-container\r\n if(item) {\r\n item.dataset.mid = '' + mid;\r\n }\r\n }\r\n\r\n if(message.media?.poll) {\r\n const pollElement = bubble.querySelector('poll-element') as PollElement;\r\n if(pollElement) {\r\n const newPoll = message.media.poll;\r\n pollElement.message = message;\r\n pollElement.setAttribute('poll-id', newPoll.id);\r\n pollElement.setAttribute('message-id', '' + mid);\r\n }\r\n }\r\n\r\n if(message.media?.document) {\r\n const element = bubble.querySelector(`audio-element[data-mid=\"${tempId}\"], .document[data-doc-id=\"${tempId}\"], .media-round[data-mid=\"${tempId}\"]`) as HTMLElement;\r\n if(element) {\r\n if(element instanceof AudioElement || element.classList.contains('media-round')) {\r\n element.dataset.mid = '' + message.mid;\r\n delete element.dataset.isOutgoing;\r\n (element as any).message = message;\r\n (element as any).onLoad(true);\r\n } else {\r\n element.dataset.docId = message.media.document.id;\r\n }\r\n }\r\n }\r\n\r\n /* bubble.classList.remove('is-sending');\r\n bubble.classList.add('is-sent');\r\n bubble.dataset.mid = '' + mid;\r\n\r\n this.bubbleGroups.removeBubble(bubble, tempId); */\r\n\r\n if(message.media?.webpage && !bubble.querySelector('.web')) {\r\n getHeavyAnimationPromise().then(() => {\r\n this.safeRenderMessage(message, true, false, bubble, false);\r\n this.scrollToBubbleIfLast(bubble);\r\n });\r\n /* const mounted = this.getMountedBubble(mid);\r\n if(!mounted) return;\r\n this.renderMessage(mounted.message, true, false, mounted.bubble, false); */\r\n }\r\n \r\n //delete this.bubbles[tempId];\r\n } else {\r\n this.log.warn('message_sent there is no bubble', e);\r\n }\r\n\r\n const bubbles = this.bubbles;\r\n if(bubbles[tempId]) {\r\n const bubble = bubbles[tempId];\r\n bubbles[mid] = bubble;\r\n delete bubbles[tempId];\r\n\r\n //getHeavyAnimationPromise().then(() => {\r\n fastRaf(() => {\r\n const mid = +bubble.dataset.mid;\r\n if(bubbles[mid] === bubble && bubble.classList.contains('is-outgoing')) {\r\n bubble.classList.remove('is-sending', 'is-outgoing');\r\n bubble.classList.add((this.peerId === rootScope.myId && this.chat.type !== 'scheduled') || !this.unreadOut.has(mid) ? 'is-read' : 'is-sent');\r\n }\r\n });\r\n //});\r\n\r\n bubble.dataset.mid = '' + mid;\r\n }\r\n\r\n if(this.unreadOut.has(tempId)) {\r\n this.unreadOut.delete(tempId);\r\n this.unreadOut.add(mid);\r\n }\r\n\r\n // * check timing of scheduled message\r\n if(this.chat.type === 'scheduled') {\r\n const timestamp = Date.now() / 1000 | 0;\r\n const maxTimestamp = tempMessage.date - 10;\r\n //this.log('scheduled timing:', timestamp, maxTimestamp);\r\n if(timestamp >= maxTimestamp) {\r\n this.deleteMessagesByIds([mid]);\r\n }\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('message_edit', ({storage, peerId, mid}) => {\r\n // fastRaf(() => {\r\n if(storage !== this.chat.getMessagesStorage()) return;\r\n const message = this.chat.getMessage(mid);\r\n const mounted = message.grouped_id ? this.getGroupedBubble(message.grouped_id) : this.getMountedBubble(mid);\r\n if(!mounted) return;\r\n\r\n const updatePosition = this.chat.type === 'scheduled';\r\n \r\n const scrollSaver = new ScrollSaver(this.scrollable, true);\r\n scrollSaver.save();\r\n this.safeRenderMessage(mounted.message, true, false, mounted.bubble, updatePosition);\r\n scrollSaver.restore();\r\n\r\n if(updatePosition) {\r\n (this.messagesQueuePromise || Promise.resolve()).then(() => {\r\n this.deleteEmptyDateGroups();\r\n });\r\n }\r\n // });\r\n });\r\n\r\n if(this.chat.type !== 'scheduled') {\r\n this.listenerSetter.add(rootScope)('missed_reactions_element', ({message, changedResults}) => {\r\n if(this.peerId !== message.peerId || !message.reactions || !message.reactions.results.length) {\r\n return;\r\n }\r\n \r\n const bubble = this.getBubbleByMessage(message);\r\n if(!bubble) {\r\n return;\r\n }\r\n\r\n if(message.grouped_id) {\r\n const grouped = this.getGroupedBubble(message.grouped_id);\r\n message = grouped.message;\r\n }\r\n\r\n this.appendReactionsElementToBubble(bubble, message, changedResults);\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('messages_reactions', (arr) => {\r\n let scrollSaver: ScrollSaver;\r\n\r\n for(const {message, changedResults} of arr) {\r\n if(this.peerId !== message.peerId) {\r\n return;\r\n }\r\n \r\n const bubble = this.getBubbleByMessage(message);\r\n if(!bubble) {\r\n return;\r\n }\r\n\r\n if(!scrollSaver) {\r\n scrollSaver = new ScrollSaver(this.scrollable, true);\r\n scrollSaver.save();\r\n }\r\n \r\n const key = message.peerId + '_' + message.mid;\r\n const set = REACTIONS_ELEMENTS.get(key);\r\n if(set) {\r\n for(const element of set) {\r\n element.update(message, changedResults);\r\n }\r\n } else {\r\n rootScope.dispatchEvent('missed_reactions_element', {message, changedResults});\r\n }\r\n }\r\n\r\n if(scrollSaver) {\r\n scrollSaver.restore();\r\n }\r\n });\r\n }\r\n\r\n this.listenerSetter.add(rootScope)('album_edit', ({peerId, groupId, deletedMids}) => {\r\n //fastRaf(() => { // ! can't use delayed smth here, need original bubble to be edited\r\n if(peerId !== this.peerId) return;\r\n const mids = this.appMessagesManager.getMidsByAlbum(groupId);\r\n const renderedId = mids.concat(deletedMids).find(mid => this.bubbles[mid]);\r\n if(!renderedId) return;\r\n\r\n const renderMaxId = getObjectKeysAndSort(this.appMessagesManager.groupedMessagesStorage[groupId], 'asc').pop();\r\n\r\n this.safeRenderMessage(this.chat.getMessage(renderMaxId), true, false, this.bubbles[renderedId], false);\r\n //});\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('messages_downloaded', ({peerId, mids}) => {\r\n const middleware = this.getMiddleware();\r\n getHeavyAnimationPromise().then(() => {\r\n if(!middleware()) return;\r\n\r\n (mids as number[]).forEach(mid => {\r\n /* const promise = (this.scrollable.scrollLocked && this.scrollable.scrollLockedPromise) || Promise.resolve();\r\n promise.then(() => {\r\n \r\n }); */\r\n forEachReverse(this.needUpdate, (obj, idx) => {\r\n if(obj.replyMid === mid && obj.replyToPeerId === peerId) {\r\n const {mid, replyMid} = this.needUpdate.splice(idx, 1)[0];\r\n \r\n //this.log('messages_downloaded', mid, replyMid, i, this.needUpdate, this.needUpdate.length, mids, this.bubbles[mid]);\r\n const bubble = this.bubbles[mid];\r\n if(!bubble) return;\r\n \r\n const message = this.chat.getMessage(mid);\r\n \r\n const repliedMessage = this.appMessagesManager.getMessageByPeer(obj.replyToPeerId, replyMid);\r\n if(repliedMessage.deleted) { // ! чтобы не пыталось бесконечно загрузить удалённое сообщение\r\n delete message.reply_to_mid; // ! WARNING!\r\n }\r\n \r\n MessageRender.setReply({\r\n chat: this.chat,\r\n bubble,\r\n message\r\n });\r\n }\r\n });\r\n });\r\n });\r\n });\r\n\r\n if(IS_TOUCH_SUPPORTED) {\r\n const className = 'is-gesturing-reply';\r\n const MAX = 64;\r\n const replyAfter = MAX * .75;\r\n let shouldReply = false;\r\n let target: HTMLElement;\r\n let icon: HTMLElement;\r\n handleHorizontalSwipe({\r\n element: this.bubblesContainer,\r\n verifyTouchTarget: (e) => {\r\n if(this.chat.selection.isSelecting || !this.chat.canSend()) {\r\n return false;\r\n }\r\n\r\n // cancelEvent(e);\r\n target = findUpClassName(e.target, 'bubble');\r\n if(target) {\r\n SetTransition(target, className, true, 250);\r\n void target.offsetLeft; // reflow\r\n\r\n if(!icon) {\r\n icon = document.createElement('span');\r\n icon.classList.add('tgico-reply_filled', 'bubble-gesture-reply-icon');\r\n } else {\r\n icon.classList.remove('is-visible');\r\n icon.style.opacity = '';\r\n }\r\n\r\n target/* .querySelector('.bubble-content') */.append(icon);\r\n }\r\n\r\n return !!target;\r\n },\r\n onSwipe: (xDiff, yDiff) => {\r\n shouldReply = xDiff >= replyAfter;\r\n\r\n if(shouldReply && !icon.classList.contains('is-visible')) {\r\n icon.classList.add('is-visible');\r\n }\r\n icon.style.opacity = '' + Math.min(1, xDiff / replyAfter);\r\n\r\n const x = -Math.max(0, Math.min(MAX, xDiff));\r\n target.style.transform = `translateX(${x}px)`;\r\n cancelContextMenuOpening();\r\n },\r\n onReset: () => {\r\n const _target = target;\r\n SetTransition(_target, className, false, 250, () => {\r\n if(icon.parentElement === _target) {\r\n icon.classList.remove('is-visible');\r\n icon.remove();\r\n }\r\n });\r\n\r\n fastRaf(() => {\r\n _target.style.transform = ``;\r\n\r\n if(shouldReply) {\r\n const {mid} = _target.dataset;\r\n this.chat.input.initMessageReply(+mid);\r\n shouldReply = false;\r\n }\r\n });\r\n },\r\n listenerOptions: {capture: true}\r\n });\r\n }\r\n\r\n attachClickEvent(this.scrollable.container, this.onBubblesClick, {listenerSetter: this.listenerSetter});\r\n // this.listenerSetter.add(this.bubblesContainer)('click', this.onBubblesClick/* , {capture: true, passive: false} */);\r\n\r\n this.listenerSetter.add(this.scrollable.container)('mousedown', (e) => {\r\n if(e.button !== 0) return;\r\n \r\n const code: HTMLElement = findUpTag(e.target, 'CODE');\r\n if(code) {\r\n cancelEvent(e);\r\n copyFromElement(code);\r\n toastNew({langPackKey: 'TextCopied'});\r\n return;\r\n }\r\n });\r\n\r\n if(DEBUG) {\r\n this.listenerSetter.add(this.bubblesContainer)('dblclick', (e) => {\r\n const bubble = findUpClassName(e.target, 'grouped-item') || findUpClassName(e.target, 'bubble');\r\n if(bubble) {\r\n const mid = +bubble.dataset.mid\r\n this.log('debug message:', this.chat.getMessage(mid));\r\n this.highlightBubble(bubble);\r\n }\r\n });\r\n }\r\n\r\n if(!IS_MOBILE && this.chat.type !== 'pinned') {\r\n this.listenerSetter.add(this.bubblesContainer)('dblclick', (e) => {\r\n if(this.chat.selection.isSelecting || \r\n !this.chat.canSend()) {\r\n return;\r\n }\r\n \r\n const target = e.target as HTMLElement;\r\n const bubble = target.classList.contains('bubble') ? \r\n target : \r\n (target.classList.contains('document-selection') ? target.parentElement : null);\r\n if(bubble && !bubble.classList.contains('bubble-first')) {\r\n const mid = +bubble.dataset.mid;\r\n const message = this.chat.getMessage(mid);\r\n if(message.pFlags.is_outgoing) {\r\n return;\r\n }\r\n \r\n this.chat.input.initMessageReply(mid);\r\n }\r\n });\r\n }\r\n\r\n /* if(false) */this.stickyIntersector = new StickyIntersector(this.scrollable.container, (stuck, target) => {\r\n for(const timestamp in this.dateMessages) {\r\n const dateMessage = this.dateMessages[timestamp];\r\n if(dateMessage.container === target) {\r\n const dateBubble = dateMessage.div;\r\n\r\n // dateMessage.container.classList.add('has-sticky-dates');\r\n\r\n // SetTransition(dateBubble, 'kek', stuck, this.previousStickyDate ? 300 : 0);\r\n // if(this.previousStickyDate) {\r\n // dateBubble.classList.add('kek');\r\n // }\r\n\r\n dateBubble.classList.toggle('is-sticky', stuck);\r\n if(stuck) {\r\n this.previousStickyDate = dateBubble;\r\n }\r\n\r\n break;\r\n }\r\n }\r\n\r\n if(this.previousStickyDate) {\r\n // fastRaf(() => {\r\n // this.bubblesContainer.classList.add('has-sticky-dates');\r\n // });\r\n }\r\n });\r\n\r\n if(!IS_SAFARI) {\r\n this.sliceViewportDebounced = debounce(this.sliceViewport.bind(this), 3000, false, true);\r\n }\r\n\r\n let middleware: ReturnType<ChatBubbles['getMiddleware']>;\r\n useHeavyAnimationCheck(() => {\r\n this.isHeavyAnimationInProgress = true;\r\n this.lazyLoadQueue.lock();\r\n middleware = this.getMiddleware();\r\n\r\n // if(this.sliceViewportDebounced) {\r\n // this.sliceViewportDebounced.clearTimeout();\r\n // }\r\n }, () => {\r\n this.isHeavyAnimationInProgress = false;\r\n\r\n if(middleware && middleware()) {\r\n this.lazyLoadQueue.unlock();\r\n this.lazyLoadQueue.refresh();\r\n\r\n // if(this.sliceViewportDebounced) {\r\n // this.sliceViewportDebounced();\r\n // }\r\n }\r\n\r\n middleware = null;\r\n }, this.listenerSetter);\r\n }\r\n\r\n public constructPeerHelpers() {\r\n // will call when message is sent (only 1)\r\n this.listenerSetter.add(rootScope)('history_append', ({storage, mid}) => {\r\n if(storage !== this.chat.getMessagesStorage()) return;\r\n\r\n if(!this.scrollable.loadedAll.bottom) {\r\n this.chat.setMessageId();\r\n } else {\r\n this.renderNewMessagesByIds([mid], true);\r\n }\r\n\r\n if(rootScope.settings.animationsEnabled) {\r\n const gradientRenderer = this.chat.gradientRenderer;\r\n if(gradientRenderer) {\r\n gradientRenderer.toNextPosition();\r\n }\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('history_multiappend', (msgIdsByPeer) => {\r\n if(!(this.peerId in msgIdsByPeer)) return;\r\n const msgIds = Array.from(msgIdsByPeer[this.peerId]).slice().sort((a, b) => b - a);\r\n this.renderNewMessagesByIds(msgIds);\r\n });\r\n \r\n this.listenerSetter.add(rootScope)('history_delete', ({peerId, msgs}) => {\r\n if(peerId === this.peerId) {\r\n this.deleteMessagesByIds(Array.from(msgs));\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('dialog_unread', ({peerId}) => {\r\n if(peerId === this.peerId) {\r\n this.chat.input.setUnreadCount();\r\n\r\n getHeavyAnimationPromise().then(() => {\r\n this.updateUnreadByDialog();\r\n });\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('dialogs_multiupdate', (dialogs) => {\r\n if(dialogs[this.peerId]) {\r\n this.chat.input.setUnreadCount();\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('dialog_notify_settings', (dialog) => {\r\n if(this.peerId === dialog.peerId) {\r\n this.chat.input.setUnreadCount();\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('chat_update', (chatId) => {\r\n if(this.peerId === chatId.toPeerId(true)) {\r\n const hadRights = this.chatInner.classList.contains('has-rights');\r\n const hasRights = this.chat.canSend();\r\n\r\n if(hadRights !== hasRights) {\r\n this.finishPeerChange();\r\n this.chat.input.finishPeerChange();\r\n }\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('settings_updated', (e) => {\r\n if(e.key === 'settings.emoji.big') {\r\n const isScrolledDown = this.scrollable.isScrolledDown;\r\n if(!isScrolledDown) {\r\n this.setMessagesQueuePromise();\r\n }\r\n \r\n const mids = getObjectKeysAndSort(this.bubbles, 'desc');\r\n mids.forEach(mid => {\r\n const bubble = this.bubbles[mid];\r\n if(bubble.classList.contains('can-have-big-emoji')) {\r\n const message = this.chat.getMessage(mid);\r\n this.safeRenderMessage(message, undefined, false, bubble);\r\n // this.bubbleGroups.addBubble(bubble, message, false);\r\n }\r\n });\r\n\r\n if(isScrolledDown) {\r\n this.scrollable.setScrollTopSilently(99999);\r\n } else {\r\n this.performHistoryResult([], true, false, undefined);\r\n }\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('messages_views', (arr) => {\r\n fastRaf(() => {\r\n let scrollSaver: ScrollSaver;\r\n for(const {peerId, views, mid} of arr) {\r\n if(this.peerId !== peerId) return;\r\n\r\n const bubble = this.bubbles[mid];\r\n if(!bubble) return;\r\n \r\n const postViewsElements = Array.from(bubble.querySelectorAll('.post-views')) as HTMLElement[];\r\n if(postViewsElements.length) {\r\n const str = formatNumber(views, 1);\r\n let different = false;\r\n postViewsElements.forEach(postViews => {\r\n if(different || postViews.innerHTML !== str) {\r\n if(!scrollSaver) {\r\n scrollSaver = new ScrollSaver(this.scrollable, true);\r\n scrollSaver.save();\r\n }\r\n\r\n different = true;\r\n postViews.innerHTML = str;\r\n }\r\n });\r\n }\r\n }\r\n\r\n if(scrollSaver) {\r\n scrollSaver.restore();\r\n }\r\n });\r\n });\r\n\r\n this.observer = new SuperIntersectionObserver({root: this.scrollable.container});\r\n\r\n this.listenerSetter.add(rootScope)('chat_changing', ({to}) => {\r\n const freeze = to !== this.chat;\r\n\r\n const cb = () => {\r\n this.observer.toggleObservingNew(freeze);\r\n };\r\n\r\n if(!freeze) {\r\n setTimeout(() => {\r\n cb();\r\n }, 400);\r\n } else {\r\n cb();\r\n }\r\n });\r\n\r\n this.sendViewCountersDebounced = debounce(() => {\r\n const mids = [...this.viewsMids];\r\n this.viewsMids.clear();\r\n\r\n this.appMessagesManager.incrementMessageViews(this.peerId, mids);\r\n }, 1000, false, true);\r\n }\r\n\r\n private unreadedObserverCallback = (entry: IntersectionObserverEntry) => {\r\n if(entry.isIntersecting) {\r\n const target = entry.target as HTMLElement;\r\n const mid = this.unreaded.get(target as HTMLElement);\r\n this.onUnreadedInViewport(target, mid);\r\n }\r\n };\r\n\r\n private viewsObserverCallback = (entry: IntersectionObserverEntry) => {\r\n if(entry.isIntersecting) {\r\n const mid = +(entry.target as HTMLElement).dataset.mid;\r\n this.observer.unobserve(entry.target, this.viewsObserverCallback);\r\n\r\n if(mid) {\r\n this.viewsMids.add(mid);\r\n this.sendViewCountersDebounced();\r\n } else {\r\n const {sponsoredMessage} = this;\r\n if(sponsoredMessage && sponsoredMessage.random_id) {\r\n delete sponsoredMessage.random_id;\r\n this.chat.apiManager.invokeApiSingle('channels.viewSponsoredMessage', {\r\n channel: this.appChatsManager.getChannelInput(this.peerId.toChatId()),\r\n random_id: sponsoredMessage.random_id\r\n });\r\n }\r\n }\r\n }\r\n };\r\n\r\n private createResizeObserver() {\r\n if(!('ResizeObserver' in window) || this.resizeObserver) {\r\n return;\r\n }\r\n\r\n const container = this.scrollable.container;\r\n let wasHeight = 0/* container.offsetHeight */;\r\n let resizing = false;\r\n let skip = false;\r\n let scrolled = 0;\r\n let part = 0;\r\n let rAF = 0;\r\n // let skipNext = true;\r\n\r\n const onResizeEnd = () => {\r\n const height = container.offsetHeight;\r\n const isScrolledDown = this.scrollable.isScrolledDown;\r\n if(height !== wasHeight && (!skip || !isScrolledDown)) { // * fix opening keyboard while ESG is active, offsetHeight will change right between 'start' and this first frame\r\n part += wasHeight - height;\r\n }\r\n\r\n /* if(DEBUG) {\r\n this.log('resize end', scrolled, part, this.scrollable.scrollTop, height, wasHeight, this.scrollable.isScrolledDown);\r\n } */\r\n\r\n if(part) {\r\n this.scrollable.setScrollTopSilently(this.scrollable.scrollTop + Math.round(part));\r\n }\r\n\r\n wasHeight = height;\r\n scrolled = 0;\r\n rAF = 0;\r\n part = 0;\r\n resizing = false;\r\n skip = false;\r\n };\r\n\r\n const setEndRAF = (single: boolean) => {\r\n if(rAF) window.cancelAnimationFrame(rAF);\r\n rAF = window.requestAnimationFrame(single ? onResizeEnd : () => {\r\n rAF = window.requestAnimationFrame(onResizeEnd);\r\n //this.log('resize after RAF', part);\r\n });\r\n };\r\n\r\n const processEntries: ResizeObserverCallback = (entries) => {\r\n /* if(skipNext) {\r\n skipNext = false;\r\n return;\r\n } */\r\n\r\n if(skip) {\r\n setEndRAF(false);\r\n return;\r\n }\r\n\r\n const entry = entries[0];\r\n const height = entry.contentRect.height;/* Math.ceil(entry.contentRect.height); */\r\n \r\n if(!wasHeight) {\r\n wasHeight = height;\r\n return;\r\n }\r\n\r\n const realDiff = wasHeight - height;\r\n let diff = realDiff + part;\r\n const _part = diff % 1;\r\n diff -= _part;\r\n\r\n if(!resizing) {\r\n resizing = true;\r\n\r\n /* if(DEBUG) {\r\n this.log('resize start', realDiff, this.scrollable.scrollTop, this.scrollable.container.offsetHeight, this.scrollable.isScrolledDown);\r\n } */\r\n\r\n if(realDiff < 0 && this.scrollable.isScrolledDown) {\r\n //if(isSafari) { // * fix opening keyboard while ESG is active \r\n part = -realDiff;\r\n //}\r\n\r\n skip = true;\r\n setEndRAF(false);\r\n return;\r\n }\r\n }\r\n\r\n scrolled += diff;\r\n\r\n /* if(DEBUG) {\r\n this.log('resize', wasHeight - height, diff, this.scrollable.container.offsetHeight, this.scrollable.isScrolledDown, height, wasHeight);\r\n } */\r\n\r\n if(diff) {\r\n const needScrollTop = this.scrollable.scrollTop + diff;\r\n this.scrollable.setScrollTopSilently(needScrollTop);\r\n }\r\n \r\n setEndRAF(false);\r\n\r\n part = _part;\r\n wasHeight = height;\r\n };\r\n\r\n const resizeObserver = this.resizeObserver = new ResizeObserver(processEntries);\r\n resizeObserver.observe(container);\r\n }\r\n\r\n private destroyResizeObserver() {\r\n const resizeObserver = this.resizeObserver;\r\n if(!resizeObserver) {\r\n return;\r\n }\r\n\r\n resizeObserver.disconnect();\r\n this.resizeObserver = undefined;\r\n }\r\n\r\n private onBubblesMouseMove = (e: MouseEvent) => {\r\n const content = findUpClassName(e.target, 'bubble-content');\r\n if(content && !this.chat.selection.isSelecting) {\r\n const bubble = findUpClassName(content, 'bubble');\r\n if(!this.chat.selection.canSelectBubble(bubble)) {\r\n this.unhoverPrevious();\r\n return;\r\n }\r\n\r\n let {hoverBubble, hoverReaction} = this;\r\n if(bubble === hoverBubble) {\r\n return;\r\n }\r\n\r\n this.unhoverPrevious();\r\n\r\n hoverBubble = this.hoverBubble = bubble;\r\n hoverReaction = this.hoverReaction;\r\n // hoverReaction = contentWrapper.querySelector('.bubble-hover-reaction');\r\n if(!hoverReaction) {\r\n hoverReaction = this.hoverReaction = document.createElement('div');\r\n hoverReaction.classList.add('bubble-hover-reaction');\r\n\r\n const stickerWrapper = document.createElement('div');\r\n stickerWrapper.classList.add('bubble-hover-reaction-sticker');\r\n hoverReaction.append(stickerWrapper);\r\n\r\n content.append(hoverReaction);\r\n\r\n let message: Message.message = this.chat.getMessage(+bubble.dataset.mid);\r\n message = this.appMessagesManager.getGroupsFirstMessage(message);\r\n\r\n const middleware = this.getMiddleware(() => this.hoverReaction === hoverReaction);\r\n Promise.all([\r\n this.appReactionsManager.getAvailableReactionsByMessage(message),\r\n pause(400)\r\n ]).then(([availableReactions]) => {\r\n const availableReaction = availableReactions[0];\r\n if(!availableReaction) {\r\n hoverReaction.remove();\r\n return;\r\n }\r\n\r\n wrapSticker({\r\n div: stickerWrapper,\r\n doc: availableReaction.select_animation,\r\n width: 18,\r\n height: 18,\r\n needUpscale: true,\r\n middleware,\r\n group: CHAT_ANIMATION_GROUP,\r\n withThumb: false,\r\n needFadeIn: false\r\n }).then(player => {\r\n assumeType<RLottiePlayer>(player);\r\n if(!middleware()) {\r\n return;\r\n }\r\n\r\n player.addEventListener('firstFrame', () => {\r\n if(!middleware()) {\r\n // debugger;\r\n return;\r\n }\r\n\r\n hoverReaction.dataset.loaded = '1';\r\n this.setHoverVisible(hoverReaction, true);\r\n }, {once: true});\r\n\r\n attachClickEvent(hoverReaction, (e) => {\r\n cancelEvent(e); // cancel triggering selection\r\n\r\n this.appReactionsManager.sendReaction(message, availableReaction.reaction);\r\n this.unhoverPrevious();\r\n }, {listenerSetter: this.listenerSetter});\r\n });\r\n });\r\n } else if(hoverReaction.dataset.loaded) {\r\n this.setHoverVisible(hoverReaction, true);\r\n }\r\n } else {\r\n this.unhoverPrevious();\r\n }\r\n };\r\n\r\n public setReactionsHoverListeners() {\r\n this.listenerSetter.add(rootScope)('context_menu_toggle', this.unhoverPrevious);\r\n this.listenerSetter.add(rootScope)('overlay_toggle', this.unhoverPrevious);\r\n this.listenerSetter.add(this.chat.selection)('toggle', this.unhoverPrevious);\r\n this.listenerSetter.add(this.bubblesContainer)('mousemove', this.onBubblesMouseMove);\r\n }\r\n\r\n private setHoverVisible(hoverReaction: HTMLElement, visible: boolean) {\r\n SetTransition(hoverReaction, 'is-visible', visible, 200, visible ? undefined : () => {\r\n hoverReaction.remove();\r\n }, 2);\r\n }\r\n\r\n private unhoverPrevious = () => {\r\n const {hoverBubble, hoverReaction} = this;\r\n if(hoverBubble) {\r\n this.setHoverVisible(hoverReaction, false);\r\n this.hoverBubble = undefined;\r\n this.hoverReaction = undefined;\r\n }\r\n };\r\n\r\n public setStickyDateManually() {\r\n return;\r\n\r\n const timestamps = Object.keys(this.dateMessages).map(k => +k).sort((a, b) => b - a);\r\n let lastVisible: HTMLElement;\r\n\r\n // if(this.chatInner.classList.contains('is-scrolling')) {\r\n const {scrollTop} = this.scrollable.container;\r\n const isOverflown = scrollTop > 0;\r\n if(isOverflown) {\r\n for(const timestamp of timestamps) {\r\n const dateMessage = this.dateMessages[timestamp];\r\n const visibleRect = getVisibleRect(dateMessage.container, this.scrollable.container);\r\n if(visibleRect && visibleRect.overflow.top) {\r\n lastVisible = dateMessage.div;\r\n } else if(lastVisible) {\r\n break;\r\n }\r\n }\r\n }\r\n // }\r\n\r\n if(lastVisible === this.previousStickyDate) {\r\n return;\r\n }\r\n\r\n if(lastVisible) {\r\n const needReflow = /* !!this.chat.setPeerPromise || */!this.previousStickyDate;\r\n if(needReflow) {\r\n lastVisible.classList.add('no-transition');\r\n }\r\n\r\n lastVisible.classList.add('is-sticky');\r\n\r\n if(needReflow) {\r\n void lastVisible.offsetLeft; // reflow\r\n lastVisible.classList.remove('no-transition');\r\n }\r\n }\r\n\r\n if(this.previousStickyDate && this.previousStickyDate !== lastVisible) {\r\n this.previousStickyDate.classList.remove('is-sticky');\r\n }\r\n\r\n this.previousStickyDate = lastVisible;\r\n }\r\n\r\n public getRenderedLength() {\r\n return Object.keys(this.bubbles).length - this.skippedMids.size;\r\n }\r\n\r\n private onUnreadedInViewport(target: HTMLElement, mid: number) {\r\n this.unreadedSeen.add(mid);\r\n this.observer.unobserve(target, this.unreadedObserverCallback);\r\n this.unreaded.delete(target);\r\n this.readUnreaded();\r\n }\r\n\r\n private readUnreaded() {\r\n if(this.readPromise) return;\r\n\r\n const middleware = this.getMiddleware();\r\n this.readPromise = rootScope.idle.focusPromise.then(() => {\r\n if(!middleware()) return;\r\n let maxId = Math.max(...Array.from(this.unreadedSeen));\r\n\r\n // ? if message with maxId is not rendered ?\r\n if(this.scrollable.loadedAll.bottom) {\r\n const bubblesMaxId = Math.max(...Object.keys(this.bubbles).map(i => +i));\r\n if(maxId >= bubblesMaxId) {\r\n maxId = Math.max(this.appMessagesManager.getHistoryStorage(this.peerId, this.chat.threadId).maxId || 0, maxId);\r\n }\r\n }\r\n\r\n this.unreaded.forEach((mid, target) => {\r\n if(mid <= maxId) {\r\n this.onUnreadedInViewport(target, mid);\r\n }\r\n });\r\n\r\n const readContents: number[] = [];\r\n for(const mid of this.unreadedSeen) {\r\n const message: MyMessage = this.chat.getMessage(mid);\r\n if(this.appMessagesManager.isMentionUnread(message)) {\r\n readContents.push(mid);\r\n }\r\n }\r\n\r\n this.appMessagesManager.readMessages(this.peerId, readContents);\r\n\r\n this.unreadedSeen.clear();\r\n\r\n if(DEBUG) {\r\n this.log('will readHistory by maxId:', maxId);\r\n }\r\n\r\n // return;\r\n \r\n return this.appMessagesManager.readHistory(this.peerId, maxId, this.chat.threadId).catch((err: any) => {\r\n this.log.error('readHistory err:', err);\r\n this.appMessagesManager.readHistory(this.peerId, maxId, this.chat.threadId);\r\n }).finally(() => {\r\n if(!middleware()) return;\r\n this.readPromise = undefined;\r\n\r\n if(this.unreadedSeen.size) {\r\n this.readUnreaded();\r\n }\r\n });\r\n });\r\n }\r\n\r\n public constructPinnedHelpers() {\r\n this.listenerSetter.add(rootScope)('peer_pinned_messages', (e) => {\r\n const {peerId, mids, pinned} = e;\r\n if(peerId !== this.peerId) return;\r\n\r\n if(mids) {\r\n if(!pinned) {\r\n this.deleteMessagesByIds(mids);\r\n }\r\n }\r\n });\r\n }\r\n\r\n public constructScheduledHelpers() {\r\n const onUpdate = () => {\r\n this.chat.topbar.setTitle(this.appMessagesManager.getScheduledMessagesStorage(this.peerId).size);\r\n };\r\n\r\n this.listenerSetter.add(rootScope)('scheduled_new', ({peerId, mid}) => {\r\n if(peerId !== this.peerId) return;\r\n\r\n this.renderNewMessagesByIds([mid]);\r\n onUpdate();\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('scheduled_delete', ({peerId, mids}) => {\r\n if(peerId !== this.peerId) return;\r\n\r\n this.deleteMessagesByIds(mids);\r\n onUpdate();\r\n });\r\n }\r\n\r\n public onBubblesClick = (e: Event) => {\r\n let target = e.target as HTMLElement;\r\n let bubble: HTMLElement = null;\r\n try {\r\n bubble = findUpClassName(target, 'bubble');\r\n } catch(err) {}\r\n \r\n if(!bubble) return;\r\n\r\n if(bubble.classList.contains('is-date') && findUpClassName(target, 'bubble-content')) {\r\n if(bubble.classList.contains('is-sticky') && !this.chatInner.classList.contains('is-scrolling')) {\r\n return;\r\n }\r\n\r\n for(const timestamp in this.dateMessages) {\r\n const d = this.dateMessages[timestamp];\r\n if(d.div === bubble) {\r\n new PopupDatePicker(new Date(+timestamp), this.onDatePick).show();\r\n break;\r\n }\r\n }\r\n\r\n return;\r\n }\r\n\r\n if(!IS_TOUCH_SUPPORTED && findUpClassName(target, 'time')) {\r\n this.chat.selection.toggleByElement(bubble);\r\n return;\r\n }\r\n\r\n // ! Trusted - due to audio autoclick\r\n if(this.chat.selection.isSelecting && e.isTrusted) {\r\n if(bubble.classList.contains('service') && bubble.dataset.mid === undefined) {\r\n return;\r\n }\r\n\r\n cancelEvent(e);\r\n //console.log('bubble click', e);\r\n\r\n if(IS_TOUCH_SUPPORTED && this.chat.selection.selectedText) {\r\n this.chat.selection.selectedText = undefined;\r\n return;\r\n }\r\n\r\n //this.chatSelection.toggleByBubble(bubble);\r\n this.chat.selection.toggleByElement(findUpClassName(target, 'grouped-item') || bubble);\r\n return;\r\n }\r\n\r\n const contactDiv: HTMLElement = findUpClassName(target, 'contact');\r\n if(contactDiv) {\r\n this.chat.appImManager.setInnerPeer({\r\n peerId: contactDiv.dataset.peerId.toPeerId()\r\n });\r\n return;\r\n }\r\n\r\n const callDiv: HTMLElement = findUpClassName(target, 'bubble-call');\r\n if(callDiv) {\r\n this.chat.appImManager.callUser(this.peerId.toUserId(), callDiv.dataset.type as any);\r\n return;\r\n }\r\n\r\n const spoiler: HTMLElement = findUpClassName(target, 'spoiler');\r\n if(spoiler) {\r\n const messageDiv = findUpClassName(spoiler, 'message');\r\n\r\n const className = 'is-spoiler-visible';\r\n const isVisible = messageDiv.classList.contains(className);\r\n if(!isVisible) {\r\n cancelEvent(e);\r\n }\r\n\r\n const duration = 400 / 2;\r\n const showDuration = 5000;\r\n const useRafs = !isVisible ? 2 : 0;\r\n if(useRafs) {\r\n messageDiv.classList.add('will-change');\r\n }\r\n\r\n const spoilerTimeout = messageDiv.dataset.spoilerTimeout;\r\n if(spoilerTimeout !== null) {\r\n clearTimeout(+spoilerTimeout);\r\n delete messageDiv.dataset.spoilerTimeout;\r\n }\r\n\r\n SetTransition(messageDiv, className, true, duration, () => {\r\n messageDiv.dataset.spoilerTimeout = '' + window.setTimeout(() => {\r\n SetTransition(messageDiv, className, false, duration, () => {\r\n messageDiv.classList.remove('will-change');\r\n delete messageDiv.dataset.spoilerTimeout;\r\n });\r\n }, showDuration);\r\n }, useRafs);\r\n\r\n return;\r\n }\r\n\r\n const reactionElement = findUpTag(target, 'REACTION-ELEMENT') as ReactionElement;\r\n if(reactionElement) {\r\n cancelEvent(e);\r\n if(reactionElement.classList.contains('is-inactive')) {\r\n return;\r\n }\r\n\r\n const reactionsElement = reactionElement.parentElement as ReactionsElement;\r\n const reactionCount = reactionsElement.getReactionCount(reactionElement);\r\n\r\n const message = reactionsElement.getMessage();\r\n this.appReactionsManager.sendReaction(message, reactionCount.reaction);\r\n\r\n return;\r\n }\r\n\r\n const commentsDiv: HTMLElement = findUpClassName(target, 'replies');\r\n if(commentsDiv) {\r\n const bubbleMid = +bubble.dataset.mid;\r\n if(this.peerId === REPLIES_PEER_ID) {\r\n const message = this.chat.getMessage(bubbleMid) as Message.message;\r\n const peerId = this.appPeersManager.getPeerId(message.reply_to.reply_to_peer_id);\r\n const threadId = message.reply_to.reply_to_top_id;\r\n const lastMsgId = message.fwd_from.saved_from_msg_id;\r\n this.chat.appImManager.openThread(peerId, lastMsgId, threadId);\r\n } else {\r\n const message = this.appMessagesManager.filterMessages(this.chat.getMessage(bubbleMid), message => !!(message as Message.message).replies)[0] as Message.message;\r\n const replies = message.replies;\r\n if(replies) {\r\n this.appMessagesManager.getDiscussionMessage(this.peerId, message.mid).then(message => {\r\n this.chat.appImManager.setInnerPeer({\r\n peerId: replies.channel_id.toPeerId(true),\r\n type: 'discussion', \r\n threadId: (message as MyMessage).mid\r\n });\r\n });\r\n }\r\n }\r\n\r\n return;\r\n }\r\n\r\n const via = findUpClassName(target, 'is-via');\r\n if(via) {\r\n const el = via.querySelector('.peer-title') as HTMLElement;\r\n if(target === el || findUpAsChild(target, el)) {\r\n const message = el.innerText + ' ';\r\n this.appDraftsManager.setDraft(this.peerId, this.chat.threadId, message);\r\n cancelEvent(e);\r\n \r\n return;\r\n }\r\n }\r\n\r\n const nameDiv = findUpClassName(target, 'peer-title') || findUpTag(target, 'AVATAR-ELEMENT') || findUpAttribute(target, 'data-saved-from');\r\n if(nameDiv && nameDiv !== bubble) {\r\n target = nameDiv || target;\r\n const peerIdStr = target.dataset.peerId || target.getAttribute('peer') || (target as AvatarElement).peerId;\r\n const savedFrom = target.dataset.savedFrom;\r\n if(typeof(peerIdStr) === 'string' || savedFrom) {\r\n if(savedFrom) {\r\n const [peerId, mid] = savedFrom.split('_');\r\n \r\n this.chat.appImManager.setInnerPeer({\r\n peerId: peerId.toPeerId(), \r\n lastMsgId: +mid\r\n });\r\n } else {\r\n const peerId = peerIdStr.toPeerId();\r\n if(peerId !== NULL_PEER_ID) {\r\n this.chat.appImManager.setInnerPeer({peerId});\r\n } else {\r\n toast(I18n.format('HidAccount', true));\r\n }\r\n }\r\n }\r\n\r\n return;\r\n }\r\n\r\n //this.log('chatInner click:', target);\r\n // const isVideoComponentElement = target.tagName === 'SPAN' && findUpClassName(target, 'media-container');\r\n /* if(isVideoComponentElement) {\r\n const video = target.parentElement.querySelector('video') as HTMLElement;\r\n if(video) {\r\n video.click(); // hot-fix for time and play button\r\n return;\r\n }\r\n } */\r\n\r\n if(bubble.classList.contains('sticker') && target.parentElement.classList.contains('attachment')) {\r\n const messageId = +bubble.dataset.mid;\r\n const message = this.chat.getMessage(messageId);\r\n\r\n const doc = message.media?.document;\r\n\r\n if(doc?.stickerSetInput) {\r\n new PopupStickers(doc.stickerSetInput).show();\r\n }\r\n\r\n return;\r\n }\r\n\r\n const documentDiv = findUpClassName(target, 'document-with-thumb');\r\n if((target.tagName === 'IMG' && !target.classList.contains('emoji') && !target.classList.contains('document-thumb')) \r\n || target.classList.contains('album-item')\r\n // || isVideoComponentElement\r\n || (target.tagName === 'VIDEO' && !bubble.classList.contains('round'))\r\n || (documentDiv && !documentDiv.querySelector('.preloader-container'))\r\n || target.classList.contains('canvas-thumbnail')) {\r\n const groupedItem = findUpClassName(target, 'album-item') || findUpClassName(target, 'document-container');\r\n const messageId = +(groupedItem || bubble).dataset.mid;\r\n const message = this.chat.getMessage(messageId);\r\n if(!message) {\r\n this.log.warn('no message by messageId:', messageId);\r\n return;\r\n }\r\n\r\n const preloader = (groupedItem || bubble).querySelector<HTMLElement>('.preloader-container');\r\n if(preloader) {\r\n simulateClickEvent(preloader);\r\n cancelEvent(e);\r\n return;\r\n }\r\n\r\n const SINGLE_MEDIA_CLASSNAME = 'webpage';\r\n const isSingleMedia = bubble.classList.contains(SINGLE_MEDIA_CLASSNAME);\r\n\r\n const f = documentDiv ? (media: any) => {\r\n return AppMediaViewer.isMediaCompatibleForDocumentViewer(media);\r\n } : (media: any) => {\r\n return media._ === 'photo' || ['video', 'gif'].includes(media.type);\r\n };\r\n\r\n const targets: {element: HTMLElement, mid: number, peerId: PeerId}[] = [];\r\n const ids = isSingleMedia ? [messageId] : Object.keys(this.bubbles).map(k => +k).filter(id => {\r\n /* if(isSingleMedia && !this.bubbles[id].classList.contains(SINGLE_MEDIA_CLASSNAME)) {\r\n return false;\r\n } */\r\n //if(!this.scrollable.visibleElements.find(e => e.element === this.bubbles[id])) return false;\r\n\r\n const message = this.chat.getMessage(id);\r\n const media = this.appMessagesManager.getMediaFromMessage(message);\r\n \r\n return media && f(media);\r\n }).sort((a, b) => a - b);\r\n\r\n ids.forEach(id => {\r\n let selector: string;\r\n if(documentDiv) {\r\n selector = '.document-container';\r\n } else {\r\n const withTail = this.bubbles[id].classList.contains('with-media-tail');\r\n selector = '.album-item video, .album-item img, .preview video, .preview img, ';\r\n if(withTail) {\r\n selector += '.bubble__media-container';\r\n } else {\r\n selector += '.attachment video, .attachment img';\r\n }\r\n }\r\n\r\n const elements = Array.from(this.bubbles[id].querySelectorAll(selector)) as HTMLElement[];\r\n const parents: Set<HTMLElement> = new Set();\r\n if(documentDiv) {\r\n elements.forEach((element) => {\r\n targets.push({\r\n element: element.querySelector('.document-ico'),\r\n mid: +element.dataset.mid,\r\n peerId: this.peerId\r\n });\r\n });\r\n } else {\r\n const hasAspecter = !!this.bubbles[id].querySelector('.media-container-aspecter');\r\n elements.forEach((element) => {\r\n if(hasAspecter && !findUpClassName(element, 'media-container-aspecter')) return;\r\n let albumItem = findUpClassName(element, 'album-item');\r\n const parent = albumItem || element.parentElement;\r\n if(parents.has(parent)) return;\r\n parents.add(parent);\r\n targets.push({\r\n element,\r\n mid: albumItem ? +albumItem.dataset.mid : id,\r\n peerId: this.peerId\r\n });\r\n });\r\n }\r\n });\r\n\r\n targets.sort((a, b) => a.mid - b.mid);\r\n\r\n let idx = targets.findIndex(t => t.mid === messageId);\r\n\r\n if(DEBUG) {\r\n this.log('open mediaViewer single with ids:', ids, idx, targets);\r\n }\r\n\r\n if(!targets[idx]) {\r\n this.log('no target for media viewer!', target);\r\n return;\r\n }\r\n\r\n new AppMediaViewer()\r\n .setSearchContext({\r\n threadId: this.chat.threadId,\r\n peerId: this.peerId,\r\n inputFilter: {_: documentDiv ? 'inputMessagesFilterDocument' : 'inputMessagesFilterPhotoVideo'},\r\n useSearch: this.chat.type !== 'scheduled' && !isSingleMedia,\r\n isScheduled: this.chat.type === 'scheduled'\r\n })\r\n .openMedia(message, targets[idx].element, 0, true, targets.slice(0, idx), targets.slice(idx + 1));\r\n \r\n cancelEvent(e);\r\n //appMediaViewer.openMedia(message, target as HTMLImageElement);\r\n return;\r\n }\r\n \r\n if(['IMG', 'DIV', 'SPAN'/* , 'A' */].indexOf(target.tagName) === -1) target = findUpTag(target, 'DIV');\r\n \r\n if(['DIV', 'SPAN'].indexOf(target.tagName) !== -1/* || target.tagName === 'A' */) {\r\n if(target.classList.contains('goto-original')) {\r\n const savedFrom = bubble.dataset.savedFrom;\r\n const [peerId, mid] = savedFrom.split('_');\r\n ////this.log('savedFrom', peerId, msgID);\r\n this.chat.appImManager.setInnerPeer({\r\n peerId: peerId.toPeerId(), \r\n lastMsgId: +mid\r\n });\r\n return;\r\n } else if(target.classList.contains('forward')) {\r\n const mid = +bubble.dataset.mid;\r\n const message = this.appMessagesManager.getMessageByPeer(this.peerId, mid);\r\n new PopupForward({\r\n [this.peerId]: this.appMessagesManager.getMidsByMessage(message)\r\n });\r\n //appSidebarRight.forwardTab.open([mid]);\r\n return;\r\n }\r\n \r\n let isReplyClick = false;\r\n \r\n try {\r\n isReplyClick = !!findUpClassName(e.target, 'reply');\r\n } catch(err) {}\r\n \r\n if(isReplyClick && bubble.classList.contains('is-reply')/* || bubble.classList.contains('forwarded') */) {\r\n const bubbleMid = +bubble.dataset.mid;\r\n this.replyFollowHistory.push(bubbleMid);\r\n\r\n const message = this.chat.getMessage(bubbleMid) as Message.message;\r\n\r\n const replyToPeerId = message.reply_to.reply_to_peer_id ? this.appPeersManager.getPeerId(message.reply_to.reply_to_peer_id) : this.peerId;\r\n const replyToMid = message.reply_to.reply_to_msg_id;\r\n\r\n this.chat.appImManager.setInnerPeer({\r\n peerId: replyToPeerId, \r\n lastMsgId: replyToMid, \r\n type: this.chat.type, \r\n threadId: this.chat.threadId\r\n });\r\n\r\n /* if(this.chat.type === 'discussion') {\r\n this.chat.appImManager.setMessageId(, originalMessageId);\r\n } else {\r\n this.chat.appImManager.setInnerPeer(this.peerId, originalMessageId);\r\n } */\r\n //this.chat.setMessageId(, originalMessageId);\r\n }\r\n }\r\n \r\n //console.log('chatInner click', e);\r\n };\r\n\r\n public onGoDownClick() {\r\n if(this.replyFollowHistory.length) {\r\n forEachReverse(this.replyFollowHistory, (mid, idx) => {\r\n const bubble = this.bubbles[mid];\r\n let bad = true;\r\n if(bubble) {\r\n const rect = bubble.getBoundingClientRect();\r\n bad = (windowSize.height / 2) > rect.top;\r\n } else {\r\n const message = this.chat.getMessage(mid);\r\n if(!message.deleted) {\r\n bad = false;\r\n }\r\n }\r\n \r\n if(bad) {\r\n this.replyFollowHistory.splice(idx, 1);\r\n }\r\n });\r\n\r\n this.replyFollowHistory.sort((a, b) => b - a);\r\n\r\n const mid = this.replyFollowHistory.pop();\r\n this.chat.setMessageId(mid);\r\n } else {\r\n this.chat.setMessageId(/* , dialog.top_message */);\r\n // const dialog = this.appMessagesManager.getDialogByPeerId(this.peerId)[0];\r\n \r\n // if(dialog) {\r\n // this.chat.setPeer(this.peerId/* , dialog.top_message */);\r\n // } else {\r\n // this.log('will scroll down 3');\r\n // this.scroll.scrollTop = this.scroll.scrollHeight;\r\n // }\r\n }\r\n }\r\n\r\n public getBubbleByPoint(verticalSide: 'top' | 'bottom') {\r\n let element = getElementByPoint(this.scrollable.container, verticalSide, 'center');\r\n /* if(element) {\r\n if(element.classList.contains('bubbles-date-group')) {\r\n const children = Array.from(element.children) as HTMLElement[];\r\n if(verticalSide === 'top') {\r\n element = children[this.stickyIntersector ? 2 : 1];\r\n } else {\r\n element = children[children.length - 1];\r\n }\r\n } else {\r\n element = findUpClassName(element, 'bubble');\r\n if(element && element.classList.contains('is-date')) {\r\n element = element.nextElementSibling as HTMLElement;\r\n }\r\n }\r\n } */\r\n if(element) element = findUpClassName(element, 'bubble');\r\n\r\n return element;\r\n }\r\n\r\n public getGroupedBubble(groupId: string) {\r\n const group = this.appMessagesManager.groupedMessagesStorage[groupId];\r\n for(const [mid] of group) {\r\n if(this.bubbles[mid]) {\r\n const maxId = Math.max(...group.keys()); // * because in scheduled album can be rendered by lowest mid during sending\r\n return {\r\n bubble: this.bubbles[mid], \r\n mid: +mid,\r\n message: this.chat.getMessage(maxId) as Message.message\r\n };\r\n }\r\n }\r\n }\r\n\r\n public getBubbleByMessage(message: Message.message | Message.messageService) {\r\n if(!(message as Message.message).grouped_id) return this.bubbles[message.mid];\r\n const grouped = this.getGroupedBubble((message as Message.message).grouped_id);\r\n return grouped?.bubble;\r\n }\r\n\r\n public getBubbleGroupedItems(bubble: HTMLElement) {\r\n return Array.from(bubble.querySelectorAll('.grouped-item')) as HTMLElement[];\r\n }\r\n\r\n public getMountedBubble(mid: number, message = this.chat.getMessage(mid)) {\r\n if(message.grouped_id && this.appMessagesManager.getMidsByAlbum(message.grouped_id).length > 1) {\r\n const a = this.getGroupedBubble(message.grouped_id);\r\n if(a) {\r\n a.bubble = a.bubble.querySelector(`.document-container[data-mid=\"${mid}\"]`) || a.bubble;\r\n return a;\r\n }\r\n }\r\n\r\n const bubble = this.bubbles[mid];\r\n if(!bubble) return;\r\n\r\n return {bubble, mid, message};\r\n }\r\n\r\n private findNextMountedBubbleByMsgId(mid: number) {\r\n return this.bubbles[getObjectKeysAndSort(this.bubbles).find(id => {\r\n if(id < mid) return false;\r\n return !!this.bubbles[id]?.parentElement;\r\n })];\r\n }\r\n\r\n public loadMoreHistory(top: boolean, justLoad = false) {\r\n //this.log('loadMoreHistory', top);\r\n if(!this.peerId || \r\n /* TEST_SCROLL || */ \r\n this.chat.setPeerPromise || \r\n this.isHeavyAnimationInProgress || \r\n (top && (this.getHistoryTopPromise || this.scrollable.loadedAll.top)) || \r\n (!top && (this.getHistoryBottomPromise || this.scrollable.loadedAll.bottom))\r\n ) {\r\n return;\r\n }\r\n\r\n // warning, если иды только отрицательные то вниз не попадёт (хотя мб и так не попадёт)\r\n // some messages can have negative id (such as sponsored message)\r\n const history = Object.keys(this.bubbles)\r\n .map(id => +id)\r\n .sort((a, b) => a - b)\r\n .filter(id => id > 0 && !this.skippedMids.has(id));\r\n if(!history.length) return;\r\n \r\n if(top) {\r\n if(DEBUG) {\r\n this.log('Will load more (up) history by id:', history[0], 'maxId:', history[history.length - 1], justLoad/* , history */);\r\n }\r\n\r\n /* if(history.length === 75) {\r\n this.log('load more', this.scrollable.scrollHeight, this.scrollable.scrollTop, this.scrollable);\r\n return;\r\n } */\r\n /* false && */this.getHistory(history[0], true, undefined, undefined, justLoad);\r\n } else {\r\n //let dialog = this.appMessagesManager.getDialogByPeerId(this.peerId)[0];\r\n const historyStorage = this.appMessagesManager.getHistoryStorage(this.peerId, this.chat.threadId);\r\n \r\n // if scroll down after search\r\n if(history.indexOf(historyStorage.maxId) !== -1) {\r\n this.setLoaded('bottom', true);\r\n return;\r\n }\r\n\r\n if(DEBUG) {\r\n this.log('Will load more (down) history by id:', history[history.length - 1], justLoad/* , history */);\r\n }\r\n\r\n /* false && */this.getHistory(history[history.length - 1], false, true, undefined, justLoad);\r\n }\r\n }\r\n\r\n public onScroll = (ignoreHeavyAnimation?: boolean, scrollDimensions?: ScrollStartCallbackDimensions) => {\r\n //return;\r\n\r\n if(this.isHeavyAnimationInProgress) {\r\n if(this.sliceViewportDebounced) {\r\n this.sliceViewportDebounced.clearTimeout();\r\n }\r\n\r\n // * В таком случае, кнопка не будет моргать если чат в самом низу, и правильно отработает случай написания нового сообщения и проскролла вниз\r\n if(this.scrolledDown && !ignoreHeavyAnimation) {\r\n return;\r\n }\r\n } else {\r\n if(this.chat.topbar.pinnedMessage) {\r\n this.chat.topbar.pinnedMessage.setCorrectIndexThrottled(this.scrollable.lastScrollDirection);\r\n }\r\n \r\n if(this.sliceViewportDebounced) {\r\n this.sliceViewportDebounced();\r\n }\r\n \r\n this.setStickyDateManually();\r\n }\r\n \r\n //lottieLoader.checkAnimations(false, 'chat');\r\n\r\n if(scrollDimensions && scrollDimensions.distanceToEnd < SCROLLED_DOWN_THRESHOLD && this.scrolledDown) {\r\n return;\r\n }\r\n\r\n const distanceToEnd = scrollDimensions?.distanceToEnd ?? this.scrollable.getDistanceToEnd();\r\n if(/* !IS_TOUCH_SUPPORTED && */(this.scrollable.lastScrollDirection !== 0 && distanceToEnd > 0) || scrollDimensions) {\r\n // if(/* !IS_TOUCH_SUPPORTED && */(this.scrollable.lastScrollDirection !== 0 || scrollDimensions) && distanceToEnd > 0) {\r\n if(this.isScrollingTimeout) {\r\n clearTimeout(this.isScrollingTimeout);\r\n } else if(!this.chatInner.classList.contains('is-scrolling')) {\r\n this.chatInner.classList.add('is-scrolling');\r\n }\r\n \r\n this.isScrollingTimeout = window.setTimeout(() => {\r\n this.chatInner.classList.remove('is-scrolling');\r\n this.isScrollingTimeout = 0;\r\n }, 1350 + (scrollDimensions?.duration ?? 0));\r\n }\r\n \r\n if(distanceToEnd < SCROLLED_DOWN_THRESHOLD && (this.scrollable.loadedAll.bottom || this.chat.setPeerPromise || !this.peerId)) {\r\n this.bubblesContainer.classList.add('scrolled-down');\r\n this.scrolledDown = true;\r\n } else if(this.bubblesContainer.classList.contains('scrolled-down')) {\r\n this.bubblesContainer.classList.remove('scrolled-down');\r\n this.scrolledDown = false;\r\n }\r\n };\r\n\r\n public setScroll() {\r\n this.scrollable = new Scrollable(null, 'IM', /* 10300 */300);\r\n this.setLoaded('top', false);\r\n this.setLoaded('bottom', false);\r\n\r\n this.scrollable.container.append(this.chatInner);\r\n\r\n /* const getScrollOffset = () => {\r\n //return Math.round(Math.max(300, appPhotosManager.windowH / 1.5));\r\n return 300; \r\n };\r\n\r\n window.addEventListener('resize', () => {\r\n this.scrollable.onScrollOffset = getScrollOffset();\r\n });\r\n\r\n this.scrollable = new Scrollable(this.bubblesContainer, 'y', 'IM', this.chatInner, getScrollOffset()); */\r\n\r\n this.scrollable.onAdditionalScroll = this.onScroll;\r\n this.scrollable.onScrolledTop = () => this.loadMoreHistory(true);\r\n this.scrollable.onScrolledBottom = () => this.loadMoreHistory(false);\r\n //this.scrollable.attachSentinels(undefined, 300);\r\n\r\n if(IS_TOUCH_SUPPORTED && false) {\r\n this.scrollable.container.addEventListener('touchmove', () => {\r\n if(this.isScrollingTimeout) {\r\n clearTimeout(this.isScrollingTimeout);\r\n } else if(!this.chatInner.classList.contains('is-scrolling')) {\r\n this.chatInner.classList.add('is-scrolling');\r\n }\r\n }, {passive: true});\r\n\r\n this.scrollable.container.addEventListener('touchend', () => {\r\n if(!this.chatInner.classList.contains('is-scrolling')) {\r\n return;\r\n }\r\n\r\n if(this.isScrollingTimeout) {\r\n clearTimeout(this.isScrollingTimeout);\r\n }\r\n\r\n this.isScrollingTimeout = window.setTimeout(() => {\r\n this.chatInner.classList.remove('is-scrolling');\r\n this.isScrollingTimeout = 0;\r\n }, 1350);\r\n }, {passive: true});\r\n }\r\n }\r\n\r\n public updateUnreadByDialog() {\r\n const historyStorage = this.appMessagesManager.getHistoryStorage(this.peerId, this.chat.threadId);\r\n const maxId = this.peerId === rootScope.myId ? historyStorage.readMaxId : historyStorage.readOutboxMaxId;\r\n \r\n ///////this.log('updateUnreadByDialog', maxId, dialog, this.unreadOut);\r\n \r\n for(const msgId of this.unreadOut) {\r\n if(msgId > 0 && msgId <= maxId) {\r\n const bubble = this.bubbles[msgId];\r\n if(bubble) {\r\n this.unreadOut.delete(msgId);\r\n\r\n if(bubble.classList.contains('is-outgoing')) {\r\n continue;\r\n }\r\n \r\n bubble.classList.remove('is-sent', 'is-sending', 'is-outgoing'); // is-sending can be when there are bulk of updates (e.g. sending command to Stickers bot)\r\n bubble.classList.add('is-read');\r\n }\r\n }\r\n }\r\n }\r\n \r\n public deleteMessagesByIds(mids: number[], permanent = true, ignoreOnScroll?: boolean) {\r\n let deleted = false;\r\n mids.forEach(mid => {\r\n if(!(mid in this.bubbles)) return;\r\n \r\n deleted = true;\r\n /* const mounted = this.getMountedBubble(mid);\r\n if(!mounted) return; */\r\n\r\n const bubble = this.bubbles[mid];\r\n delete this.bubbles[mid];\r\n this.skippedMids.delete(mid);\r\n\r\n if(this.firstUnreadBubble === bubble) {\r\n this.firstUnreadBubble = null;\r\n }\r\n\r\n this.bubbleGroups.removeBubble(bubble);\r\n if(this.observer) {\r\n this.observer.unobserve(bubble, this.unreadedObserverCallback);\r\n this.unreaded.delete(bubble);\r\n\r\n this.observer.unobserve(bubble, this.viewsObserverCallback);\r\n this.viewsMids.delete(mid);\r\n }\r\n //this.unreaded.findAndSplice(mid => mid === id);\r\n bubble.remove();\r\n //bubble.remove();\r\n\r\n if(this.emptyPlaceholderMid === mid) {\r\n this.emptyPlaceholderMid = undefined;\r\n }\r\n\r\n // this.reactions.delete(mid);\r\n });\r\n\r\n if(!deleted) {\r\n return;\r\n }\r\n\r\n this.scrollable.ignoreNextScrollEvent();\r\n if(permanent && this.chat.selection.isSelecting) {\r\n this.chat.selection.deleteSelectedMids(this.peerId, mids);\r\n }\r\n \r\n animationIntersector.checkAnimations(false, CHAT_ANIMATION_GROUP);\r\n this.deleteEmptyDateGroups();\r\n\r\n if(!ignoreOnScroll) {\r\n this.onScroll();\r\n }\r\n }\r\n\r\n private setTopPadding(middleware = this.getMiddleware()) {\r\n let isPaddingNeeded = false;\r\n let setPaddingTo: HTMLElement;\r\n if(!this.isTopPaddingSet) {\r\n const {clientHeight, scrollHeight} = this.scrollable.container;\r\n isPaddingNeeded = clientHeight === scrollHeight;\r\n /* const firstEl = this.chatInner.firstElementChild as HTMLElement;\r\n if(this.chatInner.firstElementChild) {\r\n const visibleRect = getVisibleRect(firstEl, this.scrollable.container);\r\n isPaddingNeeded = !visibleRect.overflow.top && (visibleRect.rect.top - firstEl.offsetTop) !== this.scrollable.container.getBoundingClientRect().top;\r\n } else {\r\n isPaddingNeeded = true;\r\n } */\r\n\r\n if(isPaddingNeeded) {\r\n /* const add = clientHeight - scrollHeight;\r\n this.chatInner.style.paddingTop = add + 'px';\r\n this.scrollable.scrollTop += add; */\r\n setPaddingTo = this.chatInner;\r\n setPaddingTo.style.paddingTop = clientHeight + 'px';\r\n this.scrollable.setScrollTopSilently(scrollHeight);\r\n this.isTopPaddingSet = true;\r\n }\r\n }\r\n\r\n return {\r\n isPaddingNeeded,\r\n unsetPadding: isPaddingNeeded ? () => {\r\n if(middleware() && isPaddingNeeded) {\r\n setPaddingTo.style.paddingTop = '';\r\n this.isTopPaddingSet = false;\r\n }\r\n } : undefined\r\n };\r\n }\r\n \r\n public renderNewMessagesByIds(mids: number[], scrolledDown?: boolean) {\r\n if(!this.scrollable.loadedAll.bottom) { // seems search active or sliced\r\n //this.log('renderNewMessagesByIds: seems search is active, skipping render:', mids);\r\n const setPeerPromise = this.chat.setPeerPromise;\r\n if(setPeerPromise) {\r\n const middleware = this.getMiddleware();\r\n setPeerPromise.then(() => {\r\n if(!middleware()) return;\r\n this.renderNewMessagesByIds(mids);\r\n });\r\n }\r\n\r\n return;\r\n }\r\n\r\n if(this.chat.threadId) {\r\n mids = mids.filter(mid => {\r\n const message = this.chat.getMessage(mid);\r\n const replyTo = message.reply_to as MessageReplyHeader;\r\n return replyTo && (replyTo.reply_to_top_id || replyTo.reply_to_msg_id) === this.chat.threadId;\r\n });\r\n }\r\n\r\n mids = mids.filter(mid => !this.bubbles[mid]);\r\n // ! should scroll even without new messages\r\n /* if(!mids.length) {\r\n return;\r\n } */\r\n\r\n if(!scrolledDown) {\r\n scrolledDown = this.scrolledDown && (\r\n !this.scrollingToBubble || \r\n this.scrollingToBubble === this.getLastBubble() || \r\n this.scrollingToBubble === this.chatInner\r\n );\r\n }\r\n\r\n const middleware = this.getMiddleware();\r\n const {isPaddingNeeded, unsetPadding} = this.setTopPadding(middleware);\r\n\r\n const promise = this.performHistoryResult(mids, false, true);\r\n if(scrolledDown) {\r\n promise.then(() => {\r\n if(!middleware()) return;\r\n //this.log('renderNewMessagesByIDs: messagesQueuePromise after', this.scrollable.isScrolledDown);\r\n //this.scrollable.scrollTo(this.scrollable.scrollHeight, 'top', true, true, 5000);\r\n //const bubble = this.bubbles[Math.max(...mids)];\r\n\r\n let bubble: HTMLElement;\r\n if(this.chat.type === 'scheduled') {\r\n bubble = this.bubbles[Math.max(...mids)];\r\n }\r\n\r\n const promise = bubble ? this.scrollToBubbleEnd(bubble) : this.scrollToEnd();\r\n if(isPaddingNeeded) {\r\n // it will be called only once even if was set multiple times (that won't happen)\r\n promise.then(unsetPadding);\r\n }\r\n\r\n //this.scrollable.scrollIntoViewNew(this.chatInner, 'end');\r\n\r\n /* setTimeout(() => {\r\n this.log('messagesQueuePromise afterafter:', this.chatInner.childElementCount, this.scrollable.scrollHeight);\r\n }, 10); */\r\n });\r\n }\r\n }\r\n\r\n public getLastBubble() {\r\n const lastDateGroup = this.getLastDateGroup();\r\n if(lastDateGroup) {\r\n return lastDateGroup.lastElementChild as HTMLElement;\r\n }\r\n }\r\n\r\n public scrollToBubble(\r\n element: HTMLElement, \r\n position: ScrollLogicalPosition,\r\n forceDirection?: FocusDirection,\r\n forceDuration?: number\r\n ) {\r\n const bubble = findUpClassName(element, 'bubble');\r\n\r\n let fallbackToElementStartWhenCentering: HTMLElement;\r\n // * if it's a start, then scroll to start of the group\r\n if(bubble && position !== 'end' && whichChild(bubble) === (this.stickyIntersector ? STICKY_OFFSET : 1)/* && this.chat.setPeerPromise */) {\r\n const dateGroup = bubble.parentElement;\r\n // if(whichChild(dateGroup) === 0) {\r\n fallbackToElementStartWhenCentering = dateGroup;\r\n // position = 'start';\r\n // element = dateGroup;\r\n // }\r\n }\r\n\r\n // const isLastBubble = this.getLastBubble() === bubble;\r\n /* if(isLastBubble) {\r\n element = this.getLastDateGroup();\r\n } */\r\n\r\n let margin = 4; // * 4 = .25rem\r\n /* if(isLastBubble && this.chat.type === 'chat' && this.bubblesContainer.classList.contains('is-chat-input-hidden')) {\r\n margin = 20;\r\n } */\r\n\r\n const isChangingHeight = (this.chat.input.messageInput && this.chat.input.messageInput.classList.contains('is-changing-height')) || this.chat.container.classList.contains('is-toggling-helper');\r\n const promise = this.scrollable.scrollIntoViewNew({\r\n element, \r\n position, \r\n margin, \r\n forceDirection, \r\n forceDuration, \r\n axis: 'y', \r\n getNormalSize: isChangingHeight ? ({rect}) => {\r\n // return rect.height;\r\n\r\n let height = windowSize.height;\r\n // height -= this.chat.topbar.container.getBoundingClientRect().height;\r\n height -= this.bubblesContainer.offsetTop;\r\n height -= mediaSizes.isMobile || windowSize.height < 570 ? 58 : 78;\r\n return height;\r\n\r\n /* const rowsWrapperHeight = this.chat.input.rowsWrapper.getBoundingClientRect().height;\r\n const diff = rowsWrapperHeight - 54;\r\n return rect.height + diff; */\r\n } : undefined,\r\n fallbackToElementStartWhenCentering,\r\n startCallback: (dimensions) => {\r\n // this.onScroll(true, this.scrolledDown && dimensions.distanceToEnd <= SCROLLED_DOWN_THRESHOLD ? undefined : dimensions);\r\n this.onScroll(true, dimensions);\r\n }\r\n });\r\n\r\n // fix flickering date when opening unread chat and focusing message\r\n if(forceDirection === FocusDirection.Static) {\r\n this.scrollable.lastScrollPosition = this.scrollable.scrollTop;\r\n }\r\n \r\n return promise;\r\n }\r\n\r\n public scrollToEnd() {\r\n return this.scrollToBubbleEnd(this.chatInner);\r\n }\r\n\r\n public async scrollToBubbleEnd(bubble: HTMLElement) {\r\n /* if(DEBUG) {\r\n this.log('scrollToNewLastBubble: will scroll into view:', bubble);\r\n } */\r\n\r\n if(bubble) {\r\n this.scrollingToBubble = bubble;\r\n const middleware = this.getMiddleware();\r\n await this.scrollToBubble(bubble, 'end', undefined, undefined);\r\n if(!middleware()) return;\r\n this.scrollingToBubble = undefined;\r\n }\r\n }\r\n\r\n // ! can't get it by chatInner.lastElementChild because placeholder can be the last...\r\n private getLastDateGroup() {\r\n let lastTime = 0, lastElem: HTMLElement;\r\n for(const i in this.dateMessages) {\r\n const dateMessage = this.dateMessages[i];\r\n if(dateMessage.firstTimestamp > lastTime) {\r\n lastElem = dateMessage.container;\r\n lastTime = dateMessage.firstTimestamp;\r\n }\r\n }\r\n\r\n return lastElem;\r\n }\r\n\r\n public async scrollToBubbleIfLast(bubble: HTMLElement) {\r\n if(this.getLastBubble() === bubble) {\r\n // return this.scrollToBubbleEnd(bubble);\r\n return this.scrollToEnd();\r\n }\r\n }\r\n\r\n public highlightBubble(element: HTMLElement) {\r\n const datasetKey = 'highlightTimeout';\r\n if(element.dataset[datasetKey]) {\r\n clearTimeout(+element.dataset[datasetKey]);\r\n element.classList.remove('is-highlighted');\r\n void element.offsetWidth; // reflow\r\n }\r\n\r\n element.classList.add('is-highlighted');\r\n element.dataset[datasetKey] = '' + setTimeout(() => {\r\n element.classList.remove('is-highlighted');\r\n delete element.dataset[datasetKey];\r\n }, 2000);\r\n }\r\n\r\n private createDateBubble(timestamp: number, date: Date = new Date(timestamp * 1000)) {\r\n let dateElement: HTMLElement;\r\n \r\n const today = new Date();\r\n today.setHours(0, 0, 0, 0);\r\n\r\n const isScheduled = this.chat.type === 'scheduled';\r\n \r\n if(today.getTime() === date.getTime()) {\r\n dateElement = i18n(isScheduled ? 'Chat.Date.ScheduledForToday' : 'Date.Today');\r\n } else if(isScheduled && timestamp === SEND_WHEN_ONLINE_TIMESTAMP) {\r\n dateElement = i18n('MessageScheduledUntilOnline');\r\n } else {\r\n const options: Intl.DateTimeFormatOptions = {\r\n day: 'numeric',\r\n month: 'long'\r\n };\r\n\r\n if(date.getFullYear() !== today.getFullYear()) {\r\n options.year = 'numeric';\r\n }\r\n\r\n dateElement = new I18n.IntlDateElement({\r\n date,\r\n options\r\n }).element;\r\n\r\n if(isScheduled) {\r\n dateElement = i18n('Chat.Date.ScheduledFor', [dateElement]);\r\n }\r\n }\r\n \r\n const bubble = document.createElement('div');\r\n bubble.className = 'bubble service is-date';\r\n const bubbleContent = document.createElement('div');\r\n bubbleContent.classList.add('bubble-content');\r\n const serviceMsg = document.createElement('div');\r\n serviceMsg.classList.add('service-msg');\r\n\r\n serviceMsg.append(dateElement);\r\n\r\n bubbleContent.append(serviceMsg);\r\n bubble.append(bubbleContent);\r\n\r\n return bubble;\r\n }\r\n\r\n public getDateContainerByMessage(message: any, reverse: boolean) {\r\n const date = new Date(message.date * 1000);\r\n date.setHours(0, 0, 0);\r\n const dateTimestamp = date.getTime();\r\n if(!this.dateMessages[dateTimestamp]) {\r\n const bubble = this.createDateBubble(message.date, date);\r\n // bubble.classList.add('is-sticky');\r\n const fakeBubble = this.createDateBubble(message.date, date);\r\n fakeBubble.classList.add('is-fake');\r\n\r\n const container = document.createElement('section');\r\n container.className = 'bubbles-date-group';\r\n container.append(bubble, fakeBubble);\r\n\r\n this.dateMessages[dateTimestamp] = {\r\n div: bubble,\r\n container,\r\n firstTimestamp: date.getTime()\r\n };\r\n\r\n const haveTimestamps = getObjectKeysAndSort(this.dateMessages, 'asc');\r\n let i = 0, length = haveTimestamps.length, insertBefore: HTMLElement; // there can be 'first bubble' (e.g. bot description) so can't insert by index\r\n for(; i < haveTimestamps.length; ++i) {\r\n const t = haveTimestamps[i];\r\n insertBefore = this.dateMessages[t].container;\r\n if(dateTimestamp < t) {\r\n break;\r\n }\r\n }\r\n\r\n if(i === length && insertBefore) {\r\n insertBefore = insertBefore.nextElementSibling as HTMLElement;\r\n }\r\n\r\n if(!insertBefore) {\r\n this.chatInner.append(container);\r\n } else {\r\n this.chatInner.insertBefore(container, insertBefore);\r\n }\r\n\r\n if(this.stickyIntersector) {\r\n this.stickyIntersector.observeStickyHeaderChanges(container);\r\n }\r\n }\r\n\r\n return this.dateMessages[dateTimestamp];\r\n }\r\n\r\n public destroy() {\r\n //this.chat.log.error('Bubbles destroying');\r\n\r\n this.scrollable.onScrolledTop = this.scrollable.onScrolledBottom = this.scrollable.onAdditionalScroll = null;\r\n\r\n this.listenerSetter.removeAll();\r\n\r\n this.lazyLoadQueue.clear();\r\n this.observer && this.observer.disconnect();\r\n this.stickyIntersector && this.stickyIntersector.disconnect();\r\n\r\n delete this.lazyLoadQueue;\r\n this.observer && delete this.observer;\r\n this.stickyIntersector && delete this.stickyIntersector;\r\n }\r\n\r\n public cleanup(bubblesToo = false) {\r\n this.bubbles = {}; // clean it before so sponsored message won't be deleted faster on peer changing\r\n ////console.time('appImManager cleanup');\r\n this.setLoaded('top', false);\r\n this.setLoaded('bottom', false);\r\n\r\n // cancel scroll\r\n cancelAnimationByKey(this.scrollable.container);\r\n\r\n // do not wait ending of previous scale animation\r\n interruptHeavyAnimation();\r\n\r\n if(TEST_SCROLL !== undefined) {\r\n TEST_SCROLL = TEST_SCROLL_TIMES;\r\n }\r\n\r\n this.skippedMids.clear();\r\n this.dateMessages = {};\r\n this.bubbleGroups.cleanup();\r\n this.unreadOut.clear();\r\n this.needUpdate.length = 0;\r\n this.lazyLoadQueue.clear();\r\n \r\n // clear messages\r\n if(bubblesToo) {\r\n this.scrollable.container.textContent = '';\r\n }\r\n \r\n this.firstUnreadBubble = null;\r\n this.attachedUnreadBubble = false;\r\n \r\n this.messagesQueue.length = 0;\r\n this.messagesQueuePromise = null;\r\n \r\n this.getHistoryTopPromise = this.getHistoryBottomPromise = undefined;\r\n this.fetchNewPromise = undefined;\r\n this.getSponsoredMessagePromise = undefined;\r\n \r\n if(this.stickyIntersector) {\r\n this.stickyIntersector.disconnect();\r\n }\r\n \r\n if(this.observer) {\r\n this.observer.disconnect();\r\n\r\n this.unreaded.clear();\r\n this.unreadedSeen.clear();\r\n this.readPromise = undefined;\r\n\r\n this.viewsMids.clear();\r\n }\r\n\r\n this.middleware.clean();\r\n \r\n this.onAnimateLadder = undefined;\r\n this.resolveLadderAnimation = undefined;\r\n this.emptyPlaceholderMid = undefined;\r\n this.sponsoredMessage = undefined;\r\n this.previousStickyDate = undefined;\r\n\r\n this.scrollingToBubble = undefined;\r\n ////console.timeEnd('appImManager cleanup');\r\n\r\n this.isTopPaddingSet = false;\r\n\r\n // this.reactions.clear();\r\n\r\n if(this.isScrollingTimeout) {\r\n clearTimeout(this.isScrollingTimeout);\r\n this.isScrollingTimeout = 0;\r\n }\r\n\r\n this.bubblesContainer.classList.remove('has-sticky-dates');\r\n this.scrollable.cancelMeasure();\r\n }\r\n\r\n public setPeer(peerId: PeerId, lastMsgId?: number, startParam?: string): {cached?: boolean, promise: Chat['setPeerPromise']} {\r\n //console.time('appImManager setPeer');\r\n //console.time('appImManager setPeer pre promise');\r\n ////console.time('appImManager: pre render start');\r\n if(!peerId) {\r\n this.cleanup(true);\r\n this.peerId = peerId;\r\n this.preloader.detach();\r\n return null;\r\n }\r\n\r\n const samePeer = this.peerId === peerId;\r\n\r\n /* if(samePeer && this.chat.setPeerPromise) {\r\n return {cached: true, promise: this.chat.setPeerPromise};\r\n } */\r\n\r\n const chatType = this.chat.type;\r\n\r\n if(chatType === 'scheduled' || this.chat.isRestricted) {\r\n lastMsgId = 0;\r\n }\r\n\r\n const historyStorage = this.historyStorage = this.appMessagesManager.getHistoryStorage(peerId, this.chat.threadId);\r\n let topMessage = chatType === 'pinned' ? this.appMessagesManager.pinnedMessages[peerId].maxId : this.historyStorage.maxId ?? 0;\r\n const isTarget = lastMsgId !== undefined;\r\n\r\n // * this one will fix topMessage for null message in history (e.g. channel comments with only 1 comment and it is a topMessage)\r\n /* if(chatType !== 'pinned' && topMessage && !historyStorage.history.slice.includes(topMessage)) {\r\n topMessage = 0;\r\n } */\r\n\r\n let followingUnread: boolean;\r\n let readMaxId = 0, savedPosition: ReturnType<AppImManager['getChatSavedPosition']>, overrideAdditionMsgId: number;\r\n if(!isTarget) {\r\n if(!samePeer) {\r\n savedPosition = this.chat.appImManager.getChatSavedPosition(this.chat);\r\n }\r\n\r\n if(savedPosition) {\r\n \r\n } else if(topMessage) {\r\n readMaxId = this.appMessagesManager.getReadMaxIdIfUnread(peerId, this.chat.threadId);\r\n const dialog = this.appMessagesManager.getDialogOnly(peerId);\r\n if(/* dialog.unread_count */readMaxId && !samePeer && (!dialog || dialog.unread_count !== 1)) {\r\n const foundSlice = historyStorage.history.findSliceOffset(readMaxId);\r\n if(foundSlice && foundSlice.slice.isEnd(SliceEnd.Bottom)) {\r\n overrideAdditionMsgId = foundSlice.slice[foundSlice.offset - 25] || foundSlice.slice[0] || readMaxId;\r\n }\r\n\r\n followingUnread = !isTarget;\r\n lastMsgId = readMaxId;\r\n } else {\r\n lastMsgId = topMessage;\r\n //lastMsgID = topMessage;\r\n }\r\n }\r\n }\r\n\r\n const isJump = lastMsgId !== topMessage/* && overrideAdditionMsgId === undefined */;\r\n\r\n const {scrollable} = this;\r\n \r\n if(samePeer) {\r\n const mounted = this.getMountedBubble(lastMsgId);\r\n if(mounted) {\r\n if(isTarget) {\r\n this.scrollToBubble(mounted.bubble, 'center');\r\n this.highlightBubble(mounted.bubble);\r\n this.chat.dispatchEvent('setPeer', lastMsgId, false);\r\n } else if(topMessage && !isJump) {\r\n //this.log('will scroll down', this.scroll.scrollTop, this.scroll.scrollHeight);\r\n // scrollable.setScrollTopSilently(scrollable.scrollHeight);\r\n this.scrollToEnd();\r\n this.chat.dispatchEvent('setPeer', lastMsgId, true);\r\n }\r\n\r\n if(startParam !== undefined) {\r\n this.chat.input.setStartParam(startParam);\r\n }\r\n \r\n return null;\r\n }\r\n } else {\r\n if(this.peerId) { // * set new queue id if new peer (setting not from 0)\r\n this.lazyLoadQueue.queueId = ++queueId;\r\n this.chat.apiManager.setQueueId(this.chat.bubbles.lazyLoadQueue.queueId);\r\n }\r\n\r\n this.peerId = peerId;\r\n this.replyFollowHistory.length = 0;\r\n\r\n this.passEntities = {\r\n messageEntityBotCommand: this.appPeersManager.isAnyGroup(peerId) || this.appUsersManager.isBot(peerId)\r\n };\r\n }\r\n\r\n if(DEBUG) {\r\n this.log('setPeer peerId:', peerId, this.historyStorage, lastMsgId, topMessage);\r\n }\r\n\r\n // add last message, bc in getHistory will load < max_id\r\n const additionMsgId = overrideAdditionMsgId ?? (isJump || chatType === 'scheduled' || this.chat.isRestricted ? 0 : topMessage);\r\n\r\n /* this.setPeerPromise = null;\r\n this.preloader.detach();\r\n return true; */\r\n\r\n //////appSidebarRight.toggleSidebar(true);\r\n\r\n let maxBubbleId = 0;\r\n if(samePeer) {\r\n let el = this.getBubbleByPoint('bottom'); // ! this may not work if being called when chat is hidden\r\n //this.chat.log('[PM]: setCorrectIndex: get last element perf:', performance.now() - perf, el);\r\n if(el) {\r\n maxBubbleId = +el.dataset.mid;\r\n }\r\n\r\n if(maxBubbleId <= 0) {\r\n maxBubbleId = Math.max(...Object.keys(this.bubbles).map(mid => +mid));\r\n }\r\n } else {\r\n this.isFirstLoad = true;\r\n this.destroyResizeObserver();\r\n }\r\n\r\n const oldChatInner = this.chatInner;\r\n this.cleanup();\r\n const chatInner = this.chatInner = document.createElement('div');\r\n if(samePeer) {\r\n chatInner.className = oldChatInner.className;\r\n chatInner.classList.remove('disable-hover', 'is-scrolling');\r\n } else {\r\n chatInner.classList.add('bubbles-inner');\r\n }\r\n\r\n this.lazyLoadQueue.lock();\r\n\r\n // const haveToScrollToBubble = (topMessage && (isJump || samePeer)) || isTarget;\r\n const haveToScrollToBubble = samePeer || (topMessage && isJump) || isTarget;\r\n const fromUp = maxBubbleId > 0 && (!lastMsgId || maxBubbleId < lastMsgId || lastMsgId < 0);\r\n const scrollFromDown = !fromUp && samePeer;\r\n const scrollFromUp = !scrollFromDown && fromUp/* && (samePeer || forwardingUnread) */;\r\n this.willScrollOnLoad = scrollFromDown || scrollFromUp;\r\n\r\n let result: ReturnType<ChatBubbles['getHistory']>;\r\n if(!savedPosition) {\r\n result = this.getHistory(lastMsgId, true, isJump, additionMsgId);\r\n } else {\r\n result = {\r\n promise: getHeavyAnimationPromise().then(() => {\r\n return this.performHistoryResult(savedPosition.mids, true, false, undefined);\r\n }) as any,\r\n cached: true\r\n };\r\n }\r\n\r\n const {promise, cached} = result;\r\n\r\n // clear \r\n if(!cached) {\r\n if(!samePeer) {\r\n scrollable.container.textContent = '';\r\n //oldChatInner.remove();\r\n this.chat.finishPeerChange(isTarget, isJump, lastMsgId, startParam);\r\n this.preloader.attach(this.bubblesContainer);\r\n }\r\n }\r\n\r\n //console.timeEnd('appImManager setPeer pre promise');\r\n /* this.ladderDeferred && this.ladderDeferred.resolve();\r\n this.ladderDeferred = deferredPromise<void>(); */\r\n\r\n const middleware = this.getMiddleware();\r\n \r\n animationIntersector.lockGroup(CHAT_ANIMATION_GROUP);\r\n const setPeerPromise = promise.then(() => {\r\n ////this.log('setPeer removing preloader');\r\n\r\n if(cached) {\r\n if(!samePeer) {\r\n this.chat.finishPeerChange(isTarget, isJump, lastMsgId, startParam); // * костыль\r\n }\r\n }\r\n\r\n this.preloader.detach();\r\n\r\n if(this.resolveLadderAnimation) {\r\n this.resolveLadderAnimation();\r\n this.resolveLadderAnimation = undefined;\r\n }\r\n\r\n // this.ladderDeferred.resolve();\r\n\r\n scrollable.lastScrollDirection = 0;\r\n scrollable.lastScrollPosition = 0;\r\n replaceContent(scrollable.container, chatInner);\r\n\r\n animationIntersector.unlockGroup(CHAT_ANIMATION_GROUP);\r\n animationIntersector.checkAnimations(false, CHAT_ANIMATION_GROUP/* , true */);\r\n\r\n //fastRaf(() => {\r\n this.lazyLoadQueue.unlock();\r\n //});\r\n\r\n //if(dialog && lastMsgID && lastMsgID !== topMessage && (this.bubbles[lastMsgID] || this.firstUnreadBubble)) {\r\n if(savedPosition) {\r\n scrollable.setScrollTopSilently(savedPosition.top);\r\n /* const mountedByLastMsgId = this.getMountedBubble(lastMsgId);\r\n let bubble: HTMLElement = mountedByLastMsgId?.bubble;\r\n if(!bubble?.parentElement) {\r\n bubble = this.findNextMountedBubbleByMsgId(lastMsgId);\r\n }\r\n\r\n if(bubble) {\r\n const top = bubble.getBoundingClientRect().top;\r\n const distance = savedPosition.top - top;\r\n scrollable.scrollTop += distance;\r\n } */\r\n } else if(haveToScrollToBubble) {\r\n let unsetPadding: () => void;\r\n if(scrollFromDown) {\r\n scrollable.setScrollTopSilently(99999);\r\n } else if(scrollFromUp) {\r\n const set = this.setTopPadding();\r\n if(set.isPaddingNeeded) {\r\n unsetPadding = set.unsetPadding;\r\n }\r\n\r\n scrollable.setScrollTopSilently(0);\r\n }\r\n\r\n const mountedByLastMsgId = lastMsgId ? this.getMountedBubble(lastMsgId) : {bubble: this.getLastBubble()};\r\n let bubble: HTMLElement = (followingUnread && this.firstUnreadBubble) || mountedByLastMsgId?.bubble;\r\n if(!bubble?.parentElement) {\r\n bubble = this.findNextMountedBubbleByMsgId(lastMsgId);\r\n }\r\n \r\n let promise: Promise<void>;\r\n // ! sometimes there can be no bubble\r\n if(bubble) {\r\n const lastBubble = this.getLastBubble();\r\n const position: ScrollLogicalPosition = followingUnread ? 'start' : (!isJump && !isTarget && lastBubble === bubble ? 'end' : 'center');\r\n\r\n if(position === 'end' && lastBubble === bubble && samePeer) {\r\n promise = this.scrollToEnd();\r\n } else {\r\n promise = this.scrollToBubble(bubble, position, !samePeer ? FocusDirection.Static : undefined);\r\n }\r\n\r\n if(!followingUnread && isTarget) {\r\n this.highlightBubble(bubble);\r\n }\r\n }\r\n\r\n if(unsetPadding) {\r\n (promise || Promise.resolve()).then(() => {\r\n unsetPadding();\r\n });\r\n }\r\n } else {\r\n scrollable.setScrollTopSilently(99999);\r\n }\r\n\r\n // if(!cached) {\r\n this.onRenderScrollSet();\r\n // }\r\n\r\n this.onScroll();\r\n\r\n const middleware = this.getMiddleware();\r\n const afterSetPromise = Promise.all([setPeerPromise, getHeavyAnimationPromise()]);\r\n afterSetPromise.then(() => { // check whether list isn't full\r\n scrollable.checkForTriggers();\r\n\r\n // if(cached) {\r\n // this.onRenderScrollSet();\r\n // }\r\n });\r\n\r\n this.chat.dispatchEvent('setPeer', lastMsgId, !isJump);\r\n\r\n const needReactionsInterval = this.appPeersManager.isChannel(peerId);\r\n if(needReactionsInterval) {\r\n const middleware = this.getMiddleware();\r\n const fetchReactions = () => {\r\n if(!middleware()) return;\r\n\r\n const mids: number[] = [];\r\n for(const mid in this.bubbles) {\r\n let message: MyMessage = this.chat.getMessage(+mid);\r\n if(message._ !== 'message') {\r\n continue;\r\n }\r\n\r\n message = this.appMessagesManager.getGroupsFirstMessage(message);\r\n mids.push(message.mid);\r\n }\r\n\r\n const promise = mids.length ? this.appReactionsManager.getMessagesReactions(this.peerId, mids) : Promise.resolve();\r\n promise.then(() => {\r\n setTimeout(fetchReactions, 10e3);\r\n });\r\n };\r\n\r\n Promise.all([afterSetPromise, getHeavyAnimationPromise(), pause(500)]).then(() => {\r\n fetchReactions();\r\n });\r\n }\r\n\r\n const needFetchInterval = this.appMessagesManager.isFetchIntervalNeeded(peerId);\r\n const needFetchNew = savedPosition || needFetchInterval;\r\n if(!needFetchNew) {\r\n // warning\r\n if(!lastMsgId || this.bubbles[topMessage] || lastMsgId === topMessage) {\r\n this.setLoaded('bottom', true);\r\n }\r\n } else {\r\n afterSetPromise.then(() => {\r\n if(!middleware()) {\r\n return;\r\n }\r\n\r\n scrollable.checkForTriggers();\r\n\r\n if(needFetchInterval) {\r\n const f = () => {\r\n this.fetchNewPromise = new Promise<void>((resolve) => {\r\n if(!middleware() || !this.appMessagesManager.isFetchIntervalNeeded(peerId)) {\r\n resolve();\r\n return;\r\n }\r\n \r\n this.appMessagesManager.getNewHistory(peerId, this.chat.threadId).then((historyStorage) => {\r\n if(!middleware() || !historyStorage) {\r\n resolve();\r\n return;\r\n }\r\n \r\n const slice = historyStorage.history.slice;\r\n const isBottomEnd = slice.isEnd(SliceEnd.Bottom);\r\n if(scrollable.loadedAll.bottom && scrollable.loadedAll.bottom !== isBottomEnd) {\r\n this.setLoaded('bottom', isBottomEnd);\r\n this.onScroll();\r\n }\r\n\r\n setTimeout(f, 30e3);\r\n resolve();\r\n });\r\n }).finally(() => {\r\n this.fetchNewPromise = undefined;\r\n });\r\n };\r\n \r\n if(samePeer) {\r\n setTimeout(f, 30e3);\r\n } else {\r\n f();\r\n }\r\n }\r\n });\r\n }\r\n \r\n this.log('scrolledAllDown:', scrollable.loadedAll.bottom);\r\n\r\n //if(!this.unreaded.length && dialog) { // lol\r\n if(scrollable.loadedAll.bottom && topMessage && !this.unreaded.size) { // lol\r\n this.onScrolledAllDown();\r\n }\r\n\r\n if(chatType === 'chat') {\r\n const dialog = this.appMessagesManager.getDialogOnly(peerId);\r\n if(dialog?.pFlags.unread_mark) {\r\n this.appMessagesManager.markDialogUnread(peerId, true);\r\n }\r\n }\r\n\r\n //this.chatInner.classList.remove('disable-hover', 'is-scrolling'); // warning, performance!\r\n\r\n /* if(!document.body.classList.contains(RIGHT_COLUMN_ACTIVE_CLASSNAME)) {\r\n return new Promise<void>((resolve) => fastRaf(resolve));\r\n } */\r\n //console.timeEnd('appImManager setPeer');\r\n }).catch(err => {\r\n this.log.error('getHistory promise error:', err);\r\n if(!middleware()) {\r\n this.preloader.detach();\r\n }\r\n\r\n throw err;\r\n });\r\n\r\n return {cached, promise: setPeerPromise};\r\n }\r\n\r\n public onScrolledAllDown() {\r\n if(this.chat.type === 'chat' || this.chat.type === 'discussion') {\r\n const storage = this.appMessagesManager.getHistoryStorage(this.peerId, this.chat.threadId);\r\n this.appMessagesManager.readHistory(this.peerId, storage.maxId, this.chat.threadId, true);\r\n }\r\n }\r\n\r\n public finishPeerChange() {\r\n const isChannel = this.appPeersManager.isChannel(this.peerId);\r\n const canWrite = this.chat.canSend();\r\n \r\n this.chatInner.classList.toggle('has-rights', canWrite);\r\n this.bubblesContainer.classList.toggle('is-chat-input-hidden', !canWrite);\r\n\r\n this.chatInner.classList.toggle('is-chat', this.chat.isAnyGroup());\r\n this.chatInner.classList.toggle('is-channel', isChannel);\r\n\r\n this.createResizeObserver();\r\n }\r\n\r\n public renderMessagesQueue(message: any, bubble: HTMLElement, reverse: boolean, promises: Promise<any>[]) {\r\n /* let dateMessage = this.getDateContainerByMessage(message, reverse);\r\n if(reverse) dateMessage.container.insertBefore(bubble, dateMessage.div.nextSibling);\r\n else dateMessage.container.append(bubble);\r\n return; */\r\n\r\n /* if(DEBUG && message.mid === 4314759167) {\r\n this.log('renderMessagesQueue', message, bubble, reverse, promises);\r\n } */\r\n\r\n this.messagesQueue.push({message, bubble, reverse, promises});\r\n\r\n return this.setMessagesQueuePromise(); \r\n }\r\n\r\n public setMessagesQueuePromise() {\r\n if(this.messagesQueuePromise || !this.messagesQueue.length) return Promise.resolve();\r\n\r\n return this.messagesQueuePromise = new Promise((resolve, reject) => {\r\n setTimeout(() => {\r\n const queue = this.messagesQueue.slice();\r\n this.messagesQueue.length = 0;\r\n\r\n const promises = queue.reduce((acc, {promises}) => (acc.push(...promises), acc), []);\r\n\r\n // promises.push(pause(200));\r\n\r\n // * это нужно для того, чтобы если захочет подгрузить reply или какое-либо сообщение, то скролл не прервался\r\n // * если добавить этот промис - в таком случае нужно сделать, чтобы скроллило к последнему сообщению после рендера\r\n // promises.push(getHeavyAnimationPromise());\r\n\r\n this.log('promises to call', promises, queue, this.isHeavyAnimationInProgress);\r\n const middleware = this.getMiddleware();\r\n Promise.all(promises).then(() => {\r\n if(!middleware()) {\r\n throw 'setMessagesQueuePromise: peer changed!';\r\n }\r\n\r\n if(this.messagesQueueOnRender) {\r\n this.messagesQueueOnRender();\r\n }\r\n\r\n if(this.messagesQueueOnRenderAdditional) {\r\n this.messagesQueueOnRenderAdditional();\r\n }\r\n\r\n queue.forEach(({message, bubble, reverse}) => {\r\n this.setBubblePosition(bubble, message, reverse);\r\n });\r\n\r\n //setTimeout(() => {\r\n resolve();\r\n //}, 500);\r\n this.messagesQueuePromise = null;\r\n\r\n if(this.messagesQueue.length) {\r\n this.setMessagesQueuePromise();\r\n }\r\n\r\n this.setUnreadDelimiter(); // не нашёл места лучше\r\n // this.setStickyDateManually();\r\n }).catch(reject);\r\n }, 0);\r\n });\r\n\r\n //this.messagesQueuePromise.catch(() => {});\r\n }\r\n\r\n public setBubblePosition(bubble: HTMLElement, message: Message.message | Message.messageService, reverse: boolean) {\r\n if(message.pFlags.local) {\r\n this.chatInner[(message as Message.message).pFlags.sponsored ? 'append' : 'prepend'](bubble);\r\n return;\r\n }\r\n\r\n const dateMessage = this.getDateContainerByMessage(message, reverse);\r\n if(this.chat.type === 'scheduled' || this.chat.type === 'pinned'/* || true */) { // ! TEMP COMMENTED\r\n const offset = this.stickyIntersector ? STICKY_OFFSET : 1;\r\n let children = Array.from(dateMessage.container.children).slice(offset) as HTMLElement[];\r\n let i = 0, foundMidOnSameTimestamp = 0;\r\n for(; i < children.length; ++i) {\r\n const t = children[i];\r\n const timestamp = +t.dataset.timestamp;\r\n if(message.date < timestamp) {\r\n break;\r\n } else if(message.date === timestamp) {\r\n foundMidOnSameTimestamp = +t.dataset.mid;\r\n }\r\n \r\n if(foundMidOnSameTimestamp && message.mid < foundMidOnSameTimestamp) {\r\n break;\r\n }\r\n }\r\n \r\n // * 1 for date, 1 for date sentinel\r\n let index = offset + i;\r\n /* if(bubble.parentElement) { // * if already mounted\r\n const currentIndex = whichChild(bubble);\r\n if(index > currentIndex) {\r\n index -= 1; // * minus for already mounted\r\n }\r\n } */\r\n \r\n positionElementByIndex(bubble, dateMessage.container, index);\r\n } else {\r\n if(reverse) {\r\n dateMessage.container.insertBefore(bubble, dateMessage.container.children[this.stickyIntersector ? STICKY_OFFSET - 1 : 0].nextSibling);\r\n } else {\r\n dateMessage.container.append(bubble);\r\n }\r\n }\r\n\r\n if(message._ === 'message' || (message.action && SERVICE_AS_REGULAR.has(message.action._))) {\r\n this.bubbleGroups.addBubble(bubble, message, reverse);\r\n } else {\r\n bubble.classList.add('is-group-first', 'is-group-last');\r\n }\r\n }\r\n\r\n public getMiddleware(additionalCallback?: () => boolean) {\r\n return this.middleware.get(additionalCallback);\r\n }\r\n \r\n // reverse means top\r\n private renderMessage(message: Message.message | Message.messageService, reverse = false, multipleRender = false, bubble: HTMLElement = null, updatePosition = true) {\r\n /* if(DEBUG) {\r\n this.log.debug('message to render:', message);\r\n } */\r\n if(!bubble && this.bubbles[message.mid]) {\r\n return;\r\n }\r\n\r\n const isMessage = message._ === 'message';\r\n const groupId = isMessage && message.grouped_id;\r\n\r\n //return;\r\n const albumMustBeRenderedFull = this.chat.type !== 'pinned';\r\n if(message.deleted) return;\r\n else if(groupId && albumMustBeRenderedFull) { // will render only last album's message\r\n const storage = this.appMessagesManager.groupedMessagesStorage[groupId];\r\n const maxId = Math.max(...storage.keys());\r\n if(message.mid < maxId) {\r\n return;\r\n }\r\n }\r\n \r\n const peerId = this.peerId;\r\n // * can't use 'message.pFlags.out' here because this check will be used to define side of message (left-right)\r\n const our = message.fromId === rootScope.myId || (message.pFlags.out && this.appPeersManager.isMegagroup(peerId));\r\n \r\n const messageDiv = document.createElement('div');\r\n messageDiv.classList.add('message');\r\n \r\n //messageDiv.innerText = message.message;\r\n\r\n let bubbleContainer: HTMLDivElement;\r\n let contentWrapper: HTMLElement;\r\n \r\n // bubble\r\n if(!bubble) {\r\n contentWrapper = document.createElement('div');\r\n contentWrapper.classList.add('bubble-content-wrapper');\r\n \r\n bubbleContainer = document.createElement('div');\r\n bubbleContainer.classList.add('bubble-content');\r\n \r\n bubble = document.createElement('div');\r\n bubble.classList.add('bubble');\r\n contentWrapper.appendChild(bubbleContainer);\r\n bubble.appendChild(contentWrapper);\r\n\r\n if(!our && !message.pFlags.out && this.observer) {\r\n //this.log('not our message', message, message.pFlags.unread);\r\n const isUnread = message.pFlags.unread || \r\n this.appMessagesManager.isMentionUnread(message) || \r\n (this.historyStorage.readMaxId !== undefined && this.historyStorage.readMaxId < message.mid);\r\n if(isUnread) {\r\n this.observer.observe(bubble, this.unreadedObserverCallback);\r\n this.unreaded.set(bubble, message.mid);\r\n }\r\n }\r\n } else {\r\n const save = ['is-highlighted', 'is-group-first', 'is-group-last'];\r\n const wasClassNames = bubble.className.split(' ');\r\n const classNames = ['bubble'].concat(save.filter(c => wasClassNames.includes(c)));\r\n bubble.className = classNames.join(' ');\r\n\r\n contentWrapper = bubble.lastElementChild as HTMLElement;\r\n if(!contentWrapper.classList.contains('bubble-content-wrapper')) {\r\n contentWrapper = bubble.querySelector('.bubble-content-wrapper');\r\n }\r\n \r\n bubbleContainer = contentWrapper.firstElementChild as HTMLDivElement;\r\n bubbleContainer.innerHTML = '';\r\n bubbleContainer.style.cssText = '';\r\n contentWrapper.innerHTML = '';\r\n contentWrapper.appendChild(bubbleContainer);\r\n //bubbleContainer.style.marginBottom = '';\r\n const transitionDelay = contentWrapper.style.transitionDelay;\r\n contentWrapper.style.cssText = '';\r\n contentWrapper.style.transitionDelay = transitionDelay;\r\n\r\n if(bubble === this.firstUnreadBubble) {\r\n bubble.classList.add('is-first-unread');\r\n }\r\n\r\n // * Нужно очистить прошлую информацию, полезно если удалить последний элемент из альбома в ПОСЛЕДНЕМ БАББЛЕ ГРУППЫ (видно по аватару)\r\n const originalMid = +bubble.dataset.mid;\r\n const sameMid = +message.mid === originalMid;\r\n /* if(updatePosition) {\r\n bubble.remove(); // * for positionElementByIndex\r\n } */\r\n\r\n if(!sameMid) {\r\n delete this.bubbles[originalMid];\r\n this.skippedMids.delete(originalMid);\r\n }\r\n\r\n //bubble.innerHTML = '';\r\n }\r\n\r\n // ! reset due to album edit or delete item\r\n this.bubbles[+message.mid] = bubble;\r\n bubble.dataset.mid = '' + message.mid;\r\n bubble.dataset.peerId = '' + message.peerId;\r\n bubble.dataset.timestamp = '' + message.date;\r\n\r\n const loadPromises: Promise<any>[] = [];\r\n\r\n if(message._ === 'messageService' && (!message.action || !SERVICE_AS_REGULAR.has(message.action._))) {\r\n const action = message.action;\r\n if(action) {\r\n const _ = action._;\r\n if(IGNORE_ACTIONS.has(_) || (langPack.hasOwnProperty(_) && !langPack[_])) {\r\n this.skippedMids.add(+message.mid);\r\n return bubble;\r\n }\r\n }\r\n\r\n bubble.className = 'bubble service';\r\n\r\n bubbleContainer.innerHTML = '';\r\n const s = document.createElement('div');\r\n s.classList.add('service-msg');\r\n if(action) {\r\n if(action._ === 'messageActionChannelMigrateFrom') {\r\n s.append(i18n('ChatMigration.From', [new PeerTitle({peerId: action.chat_id.toPeerId(true)}).element]));\r\n } else if(action._ === 'messageActionChatMigrateTo') {\r\n s.append(i18n('ChatMigration.To', [new PeerTitle({peerId: action.channel_id.toPeerId(true)}).element]));\r\n } else {\r\n s.append(this.appMessagesManager.wrapMessageActionTextNew(message));\r\n }\r\n }\r\n bubbleContainer.append(s);\r\n\r\n if(updatePosition) {\r\n this.renderMessagesQueue(message, bubble, reverse, loadPromises);\r\n\r\n if(message.pFlags.is_single) { // * Ignore 'Discussion started'\r\n bubble.classList.add('is-group-last');\r\n }\r\n }\r\n\r\n return bubble;\r\n }\r\n\r\n let messageMedia: MessageMedia = isMessage && message.media;\r\n\r\n let messageMessage: string, totalEntities: MessageEntity[];\r\n if(isMessage) {\r\n if((messageMedia as MessageMedia.messageMediaDocument)?.document && \r\n !['video', 'gif'].includes(((messageMedia as MessageMedia.messageMediaDocument).document as MyDocument).type)) {\r\n // * just filter these cases for documents caption\r\n } else if(groupId && albumMustBeRenderedFull) {\r\n const t = this.appMessagesManager.getAlbumText(groupId);\r\n messageMessage = t.message;\r\n //totalEntities = t.entities;\r\n totalEntities = t.totalEntities;\r\n } else if(((messageMedia as MessageMedia.messageMediaDocument)?.document as MyDocument)?.type !== 'sticker') {\r\n messageMessage = message.message;\r\n //totalEntities = message.entities;\r\n totalEntities = message.totalEntities;\r\n }\r\n } else {\r\n if(message.action._ === 'messageActionPhoneCall') {\r\n messageMedia = {\r\n _: 'messageMediaCall',\r\n action: message.action\r\n };\r\n }\r\n }\r\n \r\n /* let richText = RichTextProcessor.wrapRichText(messageMessage, {\r\n entities: totalEntities\r\n }); */\r\n let richText = RichTextProcessor.wrapRichText(messageMessage, {\r\n entities: totalEntities,\r\n passEntities: this.passEntities\r\n });\r\n\r\n let canHaveTail = true;\r\n let isStandaloneMedia = false;\r\n let needToSetHTML = true;\r\n if(totalEntities && !messageMedia) {\r\n let emojiEntities = totalEntities.filter((e) => e._ === 'messageEntityEmoji');\r\n let strLength = messageMessage.length;\r\n let emojiStrLength = emojiEntities.reduce((acc, curr) => acc + curr.length, 0);\r\n \r\n if(emojiStrLength === strLength && emojiEntities.length <= 3 && totalEntities.length === emojiEntities.length) {\r\n if(rootScope.settings.emoji.big) {\r\n let sticker = this.appStickersManager.getAnimatedEmojiSticker(messageMessage);\r\n if(emojiEntities.length === 1 && !messageMedia && sticker) {\r\n messageMedia = {\r\n _: 'messageMediaDocument',\r\n document: sticker\r\n };\r\n } else {\r\n let attachmentDiv = document.createElement('div');\r\n attachmentDiv.classList.add('attachment');\r\n \r\n setInnerHTML(attachmentDiv, richText);\r\n \r\n bubble.classList.add('emoji-' + emojiEntities.length + 'x');\r\n \r\n bubbleContainer.append(attachmentDiv);\r\n }\r\n\r\n bubble.classList.add('is-message-empty', 'emoji-big');\r\n isStandaloneMedia = true;\r\n canHaveTail = false;\r\n needToSetHTML = false;\r\n }\r\n \r\n bubble.classList.add('can-have-big-emoji');\r\n }\r\n \r\n /* if(strLength === emojiStrLength) {\r\n messageDiv.classList.add('emoji-only');\r\n messageDiv.classList.add('message-empty');\r\n } */\r\n }\r\n\r\n if(needToSetHTML) {\r\n setInnerHTML(messageDiv, richText);\r\n }\r\n\r\n const timeSpan = MessageRender.setTime({\r\n chatType: this.chat.type, \r\n message\r\n });\r\n messageDiv.append(timeSpan);\r\n bubbleContainer.prepend(messageDiv);\r\n //bubble.prepend(timeSpan, messageDiv); // that's bad\r\n\r\n if(isMessage && message.views) {\r\n bubble.classList.add('channel-post');\r\n\r\n if(!message.fwd_from?.saved_from_msg_id && this.chat.type !== 'pinned') {\r\n const forward = document.createElement('div');\r\n forward.classList.add('bubble-beside-button', 'forward', 'tgico-forward_filled');\r\n bubbleContainer.prepend(forward);\r\n bubble.classList.add('with-beside-button');\r\n }\r\n \r\n if(!message.pFlags.is_outgoing && this.observer) {\r\n this.observer.observe(bubble, this.viewsObserverCallback);\r\n }\r\n }\r\n\r\n const replyMarkup = isMessage && message.reply_markup;\r\n if(replyMarkup && replyMarkup._ === 'replyInlineMarkup' && replyMarkup.rows && replyMarkup.rows.length) {\r\n const rows = replyMarkup.rows;\r\n\r\n const containerDiv = document.createElement('div');\r\n containerDiv.classList.add('reply-markup');\r\n rows.forEach((row) => {\r\n const buttons = row.buttons;\r\n if(!buttons || !buttons.length) return;\r\n\r\n const rowDiv = document.createElement('div');\r\n rowDiv.classList.add('reply-markup-row');\r\n\r\n buttons.forEach((button) => {\r\n const text = RichTextProcessor.wrapRichText(button.text, {noLinks: true, noLinebreaks: true});\r\n\r\n let buttonEl: HTMLButtonElement | HTMLAnchorElement;\r\n \r\n switch(button._) {\r\n case 'keyboardButtonUrl': {\r\n const r = RichTextProcessor.wrapRichText(' ', {\r\n entities: [{\r\n _: 'messageEntityTextUrl',\r\n length: 1,\r\n offset: 0,\r\n url: button.url\r\n }]\r\n });\r\n\r\n buttonEl = htmlToDocumentFragment(r).firstElementChild as HTMLAnchorElement;\r\n buttonEl.classList.add('is-link', 'tgico');\r\n\r\n break;\r\n }\r\n\r\n case 'keyboardButtonSwitchInline': {\r\n buttonEl = document.createElement('button');\r\n buttonEl.classList.add('is-switch-inline', 'tgico');\r\n attachClickEvent(buttonEl, (e) => {\r\n cancelEvent(e);\r\n\r\n const botId = message.viaBotId || message.fromId;\r\n let promise: Promise<PeerId>;\r\n if(button.pFlags.same_peer) promise = Promise.resolve(this.peerId);\r\n else promise = this.appInlineBotsManager.checkSwitchReturn(botId).then(peerId => {\r\n if(peerId) {\r\n return peerId;\r\n }\r\n \r\n return new Promise<PeerId>((resolve, reject) => {\r\n const popup = new PopupForward({\r\n [this.peerId]: []\r\n }, (peerId) => {\r\n resolve(peerId);\r\n }, true);\r\n\r\n popup.addEventListener('close', () => {\r\n reject();\r\n });\r\n });\r\n });\r\n \r\n promise.then(peerId => {\r\n const threadId = this.peerId === peerId ? this.chat.threadId : undefined;\r\n this.appInlineBotsManager.switchInlineQuery(peerId, threadId, botId, button.query);\r\n });\r\n });\r\n break;\r\n }\r\n\r\n default: {\r\n buttonEl = document.createElement('button');\r\n break;\r\n }\r\n }\r\n \r\n buttonEl.classList.add('reply-markup-button', 'rp');\r\n if(typeof(text) === 'string') {\r\n buttonEl.insertAdjacentHTML('beforeend', text);\r\n } else {\r\n buttonEl.append(text);\r\n }\r\n\r\n ripple(buttonEl);\r\n\r\n rowDiv.append(buttonEl);\r\n });\r\n\r\n containerDiv.append(rowDiv);\r\n });\r\n\r\n attachClickEvent(containerDiv, (e) => {\r\n let target = e.target as HTMLElement;\r\n \r\n if(!target.classList.contains('reply-markup-button')) target = findUpClassName(target, 'reply-markup-button');\r\n if(!target || target.classList.contains('is-link') || target.classList.contains('is-switch-inline')) return;\r\n\r\n cancelEvent(e);\r\n\r\n const column = whichChild(target);\r\n const row = rows[whichChild(target.parentElement)];\r\n\r\n if(!row.buttons || !row.buttons[column]) {\r\n this.log.warn('no such button', row, column, message);\r\n return;\r\n }\r\n\r\n const button = row.buttons[column];\r\n this.appInlineBotsManager.callbackButtonClick(this.peerId, message.mid, button);\r\n });\r\n\r\n canHaveTail = false;\r\n bubble.classList.add('with-reply-markup');\r\n contentWrapper.append(containerDiv);\r\n }\r\n \r\n const isOutgoing = message.pFlags.is_outgoing/* && this.peerId !== rootScope.myId */;\r\n if(our) {\r\n if(message.pFlags.unread || isOutgoing) this.unreadOut.add(message.mid);\r\n let status = '';\r\n if(isOutgoing) status = 'is-sending';\r\n else status = message.pFlags.unread || (message as Message.message).pFlags.is_scheduled ? 'is-sent' : 'is-read';\r\n bubble.classList.add(status);\r\n }\r\n\r\n if(isOutgoing) {\r\n bubble.classList.add('is-outgoing');\r\n }\r\n\r\n const messageWithReplies = isMessage && this.appMessagesManager.getMessageWithReplies(message);\r\n const withReplies = !!messageWithReplies && message.mid > 0;\r\n\r\n if(withReplies) {\r\n bubble.classList.add('with-replies');\r\n }\r\n\r\n const fwdFrom = isMessage && message.fwd_from;\r\n const fwdFromId = isMessage && message.fwdFromId;\r\n\r\n const isOut = our && (!fwdFrom || this.peerId !== rootScope.myId);\r\n let nameContainer: HTMLElement = bubbleContainer;\r\n\r\n const canHideNameIfMedia = !message.viaBotId && (message.fromId === rootScope.myId || !message.pFlags.out);\r\n\r\n // media\r\n if(messageMedia/* && messageMedia._ === 'messageMediaPhoto' */) {\r\n let attachmentDiv = document.createElement('div');\r\n attachmentDiv.classList.add('attachment');\r\n \r\n if(!messageMessage) {\r\n bubble.classList.add('is-message-empty');\r\n }\r\n \r\n let processingWebPage = false;\r\n \r\n /* if(isMessage) */switch(messageMedia._) {\r\n case 'messageMediaPhoto': {\r\n const photo = messageMedia.photo;\r\n ////////this.log('messageMediaPhoto', photo);\r\n\r\n if(!messageMessage) {\r\n canHaveTail = false;\r\n }\r\n \r\n if(canHideNameIfMedia) {\r\n bubble.classList.add('hide-name'); \r\n }\r\n\r\n bubble.classList.add('photo');\r\n \r\n const storage = this.appMessagesManager.groupedMessagesStorage[groupId];\r\n if(groupId && storage.size !== 1 && albumMustBeRenderedFull) {\r\n bubble.classList.add('is-album', 'is-grouped');\r\n wrapAlbum({\r\n groupId: groupId, \r\n attachmentDiv,\r\n middleware: this.getMiddleware(),\r\n isOut: our,\r\n lazyLoadQueue: this.lazyLoadQueue,\r\n chat: this.chat,\r\n loadPromises,\r\n autoDownload: this.chat.autoDownload,\r\n });\r\n \r\n break;\r\n }\r\n \r\n const withTail = !IS_ANDROID && canHaveTail && !withReplies && USE_MEDIA_TAILS;\r\n if(withTail) bubble.classList.add('with-media-tail');\r\n wrapPhoto({\r\n photo: photo as Photo.photo, \r\n message,\r\n container: attachmentDiv,\r\n withTail, \r\n isOut, \r\n lazyLoadQueue: this.lazyLoadQueue,\r\n middleware: this.getMiddleware(),\r\n loadPromises,\r\n autoDownloadSize: this.chat.autoDownload.photo,\r\n });\r\n\r\n break;\r\n }\r\n \r\n case 'messageMediaWebPage': {\r\n processingWebPage = true;\r\n \r\n let webpage: WebPage = messageMedia.webpage;\r\n ////////this.log('messageMediaWebPage', webpage);\r\n if(webpage._ !== 'webPage') {\r\n break;\r\n } \r\n \r\n bubble.classList.add('webpage');\r\n \r\n let box = document.createElement('div');\r\n box.classList.add('web');\r\n \r\n let quote = document.createElement('div');\r\n quote.classList.add('quote');\r\n\r\n let previewResizer: HTMLDivElement, preview: HTMLDivElement;\r\n const photo: Photo.photo = webpage.photo as any;\r\n if(photo || webpage.document) {\r\n previewResizer = document.createElement('div');\r\n previewResizer.classList.add('preview-resizer');\r\n preview = document.createElement('div');\r\n preview.classList.add('preview');\r\n previewResizer.append(preview);\r\n }\r\n\r\n let quoteTextDiv = document.createElement('div');\r\n quoteTextDiv.classList.add('quote-text');\r\n \r\n const doc = webpage.document as MyDocument;\r\n if(doc) {\r\n if(doc.type === 'gif' || doc.type === 'video' || doc.type === 'round') {\r\n //if(doc.size <= 20e6) {\r\n const mediaSize = doc.type === 'round' ? mediaSizes.active.round : mediaSizes.active.webpage;\r\n if(doc.type === 'round') {\r\n bubble.classList.add('round');\r\n preview.classList.add('is-round');\r\n } else {\r\n bubble.classList.add('video');\r\n }\r\n wrapVideo({\r\n doc, \r\n container: preview, \r\n message: message as Message.message, \r\n boxWidth: mediaSize.width,\r\n boxHeight: mediaSize.height,\r\n lazyLoadQueue: this.lazyLoadQueue,\r\n middleware: this.getMiddleware(),\r\n isOut,\r\n group: CHAT_ANIMATION_GROUP,\r\n loadPromises,\r\n autoDownload: this.chat.autoDownload,\r\n });\r\n //}\r\n } else {\r\n const docDiv = wrapDocument({\r\n message: message as Message.message,\r\n autoDownloadSize: this.chat.autoDownload.file,\r\n lazyLoadQueue: this.lazyLoadQueue,\r\n loadPromises,\r\n sizeType: 'documentName',\r\n searchContext: {\r\n useSearch: false,\r\n peerId: this.peerId,\r\n inputFilter: {\r\n _: 'inputMessagesFilterEmpty'\r\n }\r\n }\r\n });\r\n preview.append(docDiv);\r\n preview.classList.add('preview-with-document');\r\n quoteTextDiv.classList.add('has-document');\r\n //messageDiv.classList.add((webpage.type || 'document') + '-message');\r\n //doc = null;\r\n }\r\n }\r\n \r\n if(previewResizer) {\r\n quoteTextDiv.append(previewResizer);\r\n }\r\n\r\n let t: HTMLElement;\r\n if(webpage.site_name) {\r\n const html = RichTextProcessor.wrapRichText(webpage.url);\r\n const a: HTMLAnchorElement = htmlToDocumentFragment(html).firstElementChild as any;\r\n a.classList.add('webpage-name');\r\n const strong = document.createElement('strong');\r\n setInnerHTML(strong, RichTextProcessor.wrapEmojiText(webpage.site_name));\r\n a.textContent = '';\r\n a.append(strong);\r\n quoteTextDiv.append(a);\r\n t = a;\r\n }\r\n\r\n const title = this.appWebPagesManager.wrapTitle(webpage);\r\n if(title.textContent) {\r\n let titleDiv = document.createElement('div');\r\n titleDiv.classList.add('title');\r\n const strong = document.createElement('strong');\r\n setInnerHTML(strong, title);\r\n titleDiv.append(strong);\r\n quoteTextDiv.append(titleDiv);\r\n t = titleDiv;\r\n }\r\n\r\n const description = this.appWebPagesManager.wrapDescription(webpage);\r\n if(description.textContent) {\r\n let textDiv = document.createElement('div');\r\n textDiv.classList.add('text');\r\n setInnerHTML(textDiv, description);\r\n quoteTextDiv.append(textDiv);\r\n t = textDiv;\r\n }\r\n\r\n /* if(t) {\r\n t.append(timeSpan);\r\n } else {\r\n box.classList.add('no-text');\r\n } */\r\n\r\n quote.append(quoteTextDiv);\r\n\r\n if(photo && !doc) {\r\n bubble.classList.add('photo');\r\n\r\n const size: PhotoSize.photoSize = photo.sizes[photo.sizes.length - 1] as any;\r\n let isSquare = false;\r\n if(size.w === size.h && t) {\r\n bubble.classList.add('is-square-photo');\r\n isSquare = true;\r\n this.appPhotosManager.setAttachmentSize(photo, preview, 48, 48, false);\r\n\r\n /* if(t) {\r\n t.append(timeSpan);\r\n } */\r\n } else if(size.h > size.w) {\r\n bubble.classList.add('is-vertical-photo');\r\n }\r\n\r\n wrapPhoto({\r\n photo, \r\n message, \r\n container: preview, \r\n boxWidth: isSquare ? 0 : mediaSizes.active.webpage.width, \r\n boxHeight: isSquare ? 0 : mediaSizes.active.webpage.height, \r\n isOut, \r\n lazyLoadQueue: this.lazyLoadQueue, \r\n middleware: this.getMiddleware(),\r\n loadPromises,\r\n withoutPreloader: isSquare,\r\n autoDownloadSize: this.chat.autoDownload.photo,\r\n });\r\n }\r\n \r\n box.append(quote);\r\n \r\n //bubble.prepend(box);\r\n // if(timeSpan.parentElement === messageDiv) {\r\n messageDiv.insertBefore(box, timeSpan);\r\n // } else {\r\n // messageDiv.append(box);\r\n // }\r\n \r\n //this.log('night running', bubble.scrollHeight);\r\n \r\n break;\r\n }\r\n \r\n case 'messageMediaDocument': {\r\n const doc = messageMedia.document as MyDocument;\r\n\r\n //this.log('messageMediaDocument', doc, bubble);\r\n \r\n if(doc.sticker/* && doc.size <= 1e6 */) {\r\n bubble.classList.add('sticker');\r\n canHaveTail = false;\r\n isStandaloneMedia = true;\r\n \r\n if(doc.animated) {\r\n bubble.classList.add('sticker-animated');\r\n }\r\n \r\n const sizes = mediaSizes.active;\r\n const size = bubble.classList.contains('emoji-big') ? sizes.emojiSticker : (doc.animated ? sizes.animatedSticker : sizes.staticSticker);\r\n this.appPhotosManager.setAttachmentSize(doc, attachmentDiv, size.width, size.height);\r\n //let preloader = new ProgressivePreloader(attachmentDiv, false);\r\n bubbleContainer.style.minWidth = attachmentDiv.style.width;\r\n bubbleContainer.style.minHeight = attachmentDiv.style.height;\r\n //appPhotosManager.setAttachmentSize(doc, bubble);\r\n wrapSticker({\r\n doc, \r\n div: attachmentDiv,\r\n middleware: this.getMiddleware(),\r\n lazyLoadQueue: this.lazyLoadQueue,\r\n group: CHAT_ANIMATION_GROUP,\r\n //play: !!message.pending || !multipleRender,\r\n play: true,\r\n loop: true,\r\n emoji: bubble.classList.contains('emoji-big') ? messageMessage : undefined,\r\n withThumb: true,\r\n loadPromises\r\n });\r\n } else if(doc.type === 'video' || doc.type === 'gif' || doc.type === 'round'/* && doc.size <= 20e6 */) {\r\n //this.log('never get free 2', doc);\r\n\r\n const isRound = doc.type === 'round';\r\n if(isRound) {\r\n isStandaloneMedia = true;\r\n }\r\n\r\n if(isRound || !messageMessage) {\r\n canHaveTail = false;\r\n }\r\n\r\n if(canHideNameIfMedia) {\r\n bubble.classList.add('hide-name');\r\n }\r\n \r\n bubble.classList.add(isRound ? 'round' : 'video');\r\n const storage = this.appMessagesManager.groupedMessagesStorage[groupId];\r\n if(groupId && storage.size !== 1 && albumMustBeRenderedFull) {\r\n bubble.classList.add('is-album', 'is-grouped');\r\n \r\n wrapAlbum({\r\n groupId: groupId, \r\n attachmentDiv,\r\n middleware: this.getMiddleware(),\r\n isOut: our,\r\n lazyLoadQueue: this.lazyLoadQueue,\r\n chat: this.chat,\r\n loadPromises,\r\n autoDownload: this.chat.autoDownload,\r\n });\r\n } else {\r\n const withTail = !IS_ANDROID && !IS_APPLE && !isRound && canHaveTail && !withReplies && USE_MEDIA_TAILS;\r\n if(withTail) bubble.classList.add('with-media-tail');\r\n wrapVideo({\r\n doc, \r\n container: attachmentDiv, \r\n message: message as Message.message, \r\n boxWidth: mediaSizes.active.regular.width,\r\n boxHeight: mediaSizes.active.regular.height, \r\n withTail, \r\n isOut,\r\n lazyLoadQueue: this.lazyLoadQueue,\r\n middleware: this.getMiddleware(),\r\n group: CHAT_ANIMATION_GROUP,\r\n loadPromises,\r\n autoDownload: this.chat.autoDownload,\r\n searchContext: isRound ? {\r\n peerId: this.peerId,\r\n inputFilter: {_: 'inputMessagesFilterRoundVoice'},\r\n threadId: this.chat.threadId,\r\n useSearch: !(message as Message.message).pFlags.is_scheduled,\r\n isScheduled: (message as Message.message).pFlags.is_scheduled\r\n } : undefined,\r\n });\r\n }\r\n } else {\r\n\r\n const newNameContainer = wrapGroupedDocuments({\r\n albumMustBeRenderedFull,\r\n message,\r\n bubble,\r\n messageDiv,\r\n chat: this.chat,\r\n loadPromises,\r\n autoDownloadSize: this.chat.autoDownload.file,\r\n lazyLoadQueue: this.lazyLoadQueue,\r\n searchContext: doc.type === 'voice' || doc.type === 'audio' ? {\r\n peerId: this.peerId,\r\n inputFilter: {_: doc.type === 'voice' ? 'inputMessagesFilterRoundVoice' : 'inputMessagesFilterMusic'},\r\n threadId: this.chat.threadId,\r\n useSearch: !(message as Message.message).pFlags.is_scheduled,\r\n isScheduled: (message as Message.message).pFlags.is_scheduled\r\n } : undefined,\r\n sizeType: 'documentName'\r\n });\r\n\r\n if(newNameContainer) {\r\n nameContainer = newNameContainer;\r\n }\r\n\r\n const lastContainer = messageDiv.lastElementChild.querySelector('.document-message, .document-size, .audio');\r\n // lastContainer && lastContainer.append(timeSpan.cloneNode(true));\r\n lastContainer && lastContainer.append(timeSpan);\r\n\r\n bubble.classList.remove('is-message-empty');\r\n messageDiv.classList.add((!(['photo', 'pdf'] as MyDocument['type'][]).includes(doc.type) ? doc.type || 'document' : 'document') + '-message');\r\n processingWebPage = true;\r\n }\r\n\r\n break;\r\n }\r\n\r\n case 'messageMediaCall': {\r\n const action = messageMedia.action;\r\n const div = document.createElement('div');\r\n div.classList.add('bubble-call', action.pFlags.video ? 'tgico-videocamera' : 'tgico-phone');\r\n\r\n const type: CallType = action.pFlags.video ? 'video' : 'voice';\r\n div.dataset.type = type;\r\n\r\n const title = document.createElement('div');\r\n title.classList.add('bubble-call-title');\r\n\r\n _i18n(title, isOut ? \r\n (action.pFlags.video ? 'CallMessageVideoOutgoing' : 'CallMessageOutgoing') : \r\n (action.pFlags.video ? 'CallMessageVideoIncoming' : 'CallMessageIncoming'));\r\n\r\n const subtitle = document.createElement('div');\r\n subtitle.classList.add('bubble-call-subtitle');\r\n\r\n if(action.duration !== undefined) {\r\n subtitle.append(formatCallDuration(action.duration));\r\n } else {\r\n let langPackKey: LangPackKey;\r\n switch(action.reason._) {\r\n case 'phoneCallDiscardReasonBusy':\r\n langPackKey = 'Call.StatusBusy';\r\n break;\r\n case 'phoneCallDiscardReasonMissed':\r\n langPackKey = 'Chat.Service.Call.Missed';\r\n break;\r\n // case 'phoneCallDiscardReasonHangup':\r\n default:\r\n langPackKey = 'Chat.Service.Call.Cancelled';\r\n break;\r\n }\r\n\r\n subtitle.classList.add('is-reason');\r\n _i18n(subtitle, langPackKey);\r\n }\r\n\r\n subtitle.classList.add('tgico', 'arrow-' + (action.duration !== undefined ? 'green' : 'red'));\r\n\r\n div.append(title, subtitle);\r\n\r\n processingWebPage = true;\r\n\r\n bubble.classList.remove('is-message-empty');\r\n messageDiv.classList.add('call-message');\r\n messageDiv.append(div);\r\n\r\n break;\r\n }\r\n\r\n case 'messageMediaContact': {\r\n //this.log('wrapping contact', message);\r\n\r\n const contact = messageMedia;\r\n const contactDiv = document.createElement('div');\r\n contactDiv.classList.add('contact');\r\n contactDiv.dataset.peerId = '' + contact.user_id;\r\n\r\n processingWebPage = true;\r\n\r\n const contactDetails = document.createElement('div');\r\n contactDetails.className = 'contact-details';\r\n const contactNameDiv = document.createElement('div');\r\n contactNameDiv.className = 'contact-name';\r\n contactNameDiv.append(\r\n RichTextProcessor.wrapEmojiText([\r\n contact.first_name,\r\n contact.last_name\r\n ].filter(Boolean).join(' '))\r\n );\r\n\r\n const contactNumberDiv = document.createElement('div');\r\n contactNumberDiv.className = 'contact-number';\r\n contactNumberDiv.textContent = contact.phone_number ? '+' + formatPhoneNumber(contact.phone_number).formatted : 'Unknown phone number';\r\n\r\n contactDiv.append(contactDetails);\r\n contactDetails.append(contactNameDiv, contactNumberDiv);\r\n\r\n const avatarElem = new AvatarElement();\r\n avatarElem.updateWithOptions({\r\n lazyLoadQueue: this.lazyLoadQueue,\r\n peerId: contact.user_id.toPeerId()\r\n });\r\n avatarElem.classList.add('contact-avatar', 'avatar-54');\r\n\r\n contactDiv.prepend(avatarElem);\r\n\r\n bubble.classList.remove('is-message-empty');\r\n messageDiv.classList.add('contact-message');\r\n messageDiv.append(contactDiv);\r\n\r\n break;\r\n }\r\n\r\n case 'messageMediaPoll': {\r\n bubble.classList.remove('is-message-empty');\r\n \r\n const pollElement = wrapPoll(message);\r\n messageDiv.prepend(pollElement);\r\n messageDiv.classList.add('poll-message');\r\n\r\n break;\r\n }\r\n \r\n default:\r\n bubble.classList.remove('is-message-empty');\r\n messageDiv.append(i18n(UNSUPPORTED_LANG_PACK_KEY), timeSpan);\r\n this.log.warn('unrecognized media type:', messageMedia._, message);\r\n break;\r\n }\r\n \r\n if(!processingWebPage) {\r\n bubbleContainer.append(attachmentDiv);\r\n }\r\n\r\n /* if(bubble.classList.contains('is-message-empty') && (bubble.classList.contains('photo') || bubble.classList.contains('video'))) {\r\n bubble.classList.add('no-tail');\r\n\r\n if(!bubble.classList.contains('with-media-tail')) {\r\n bubble.classList.add('use-border-radius');\r\n }\r\n } */\r\n }\r\n\r\n if(isStandaloneMedia) {\r\n bubble.classList.add('just-media');\r\n }\r\n\r\n if(this.chat.selection.isSelecting) {\r\n this.chat.selection.toggleElementCheckbox(bubble, true);\r\n }\r\n\r\n let savedFrom = '';\r\n \r\n // const needName = ((peerId.isAnyChat() && (peerId !== message.fromId || our)) && message.fromId !== rootScope.myId) || message.viaBotId;\r\n const needName = (message.fromId !== rootScope.myId && this.appPeersManager.isAnyGroup(peerId)) || message.viaBotId || (message as Message.message).pFlags.sponsored;\r\n if(needName || fwdFrom || message.reply_to_mid) { // chat\r\n let title: HTMLElement | DocumentFragment;\r\n let titleVia: typeof title;\r\n\r\n const isForwardFromChannel = message.from_id && message.from_id._ === 'peerChannel' && message.fromId === fwdFromId;\r\n \r\n let isHidden = fwdFrom && !fwdFrom.from_id;\r\n if(message.viaBotId) {\r\n titleVia = document.createElement('span');\r\n titleVia.innerText = '@' + this.appUsersManager.getUser(message.viaBotId).username;\r\n titleVia.classList.add('peer-title');\r\n bubble.classList.add('must-have-name');\r\n }\r\n \r\n if(isHidden) {\r\n ///////this.log('message to render hidden', message);\r\n title = document.createElement('span');\r\n setInnerHTML(title, RichTextProcessor.wrapEmojiText(fwdFrom.from_name));\r\n title.classList.add('peer-title');\r\n //title = fwdFrom.from_name;\r\n bubble.classList.add('hidden-profile');\r\n } else {\r\n title = new PeerTitle({peerId: fwdFromId || message.fromId}).element;\r\n }\r\n\r\n if(message.reply_to_mid && message.reply_to_mid !== this.chat.threadId && isMessage) {\r\n MessageRender.setReply({\r\n chat: this.chat,\r\n bubble,\r\n bubbleContainer,\r\n message\r\n });\r\n }\r\n \r\n //this.log(title);\r\n \r\n let nameDiv: HTMLElement;\r\n if((fwdFromId || fwdFrom)) {\r\n if(this.peerId !== rootScope.myId && !isForwardFromChannel) {\r\n bubble.classList.add('forwarded');\r\n }\r\n \r\n if(message.savedFrom) {\r\n savedFrom = message.savedFrom;\r\n title.dataset.savedFrom = savedFrom;\r\n }\r\n \r\n nameDiv = document.createElement('div');\r\n title.dataset.peerId = '' + fwdFromId;\r\n\r\n if((this.peerId === rootScope.myId || this.peerId === REPLIES_PEER_ID || isForwardFromChannel) && !isStandaloneMedia) {\r\n nameDiv.style.color = this.appPeersManager.getPeerColorById(fwdFromId, false);\r\n nameDiv.append(title);\r\n } else {\r\n /* const fromTitle = message.fromId === this.myID || appPeersManager.isBroadcast(fwdFromId || message.fromId) ? '' : `<div class=\"name\" data-peer-id=\"${message.fromId}\" style=\"color: ${appPeersManager.getPeerColorByID(message.fromId, false)};\">${appPeersManager.getPeerTitle(message.fromId)}</div>`;\r\n nameDiv.innerHTML = fromTitle + 'Forwarded from ' + title; */\r\n const args: FormatterArguments = [title];\r\n if(isStandaloneMedia) {\r\n args.unshift(document.createElement('br'));\r\n }\r\n nameDiv.append(i18n('ForwardedFrom', [args]));\r\n }\r\n } else if(!message.viaBotId) {\r\n if(!isStandaloneMedia && needName) {\r\n nameDiv = document.createElement('div');\r\n nameDiv.append(title);\r\n\r\n const peer = this.appPeersManager.getPeer(message.fromId);\r\n const pFlags = (peer as User.user)?.pFlags;\r\n if(pFlags && (pFlags.scam || pFlags.fake)) {\r\n nameDiv.append(generateFakeIcon(pFlags.scam));\r\n }\r\n\r\n if(!our) {\r\n nameDiv.style.color = this.appPeersManager.getPeerColorById(message.fromId, false);\r\n }\r\n\r\n nameDiv.dataset.peerId = '' + message.fromId;\r\n } else /* if(!message.reply_to_mid) */ {\r\n bubble.classList.add('hide-name');\r\n }\r\n }\r\n\r\n if(message.viaBotId) {\r\n if(!nameDiv) {\r\n nameDiv = document.createElement('div');\r\n } else {\r\n nameDiv.append(' ');\r\n }\r\n\r\n const span = document.createElement('span');\r\n span.append(i18n('ViaBot'), ' ', titleVia);\r\n span.classList.add('is-via');\r\n\r\n nameDiv.append(span);\r\n }\r\n\r\n if(nameDiv) {\r\n nameDiv.classList.add('name');\r\n nameContainer.append(nameDiv);\r\n }\r\n\r\n const needAvatar = this.chat.isAnyGroup() && !isOut;\r\n if(needAvatar) {\r\n let avatarElem = new AvatarElement();\r\n avatarElem.classList.add('user-avatar', 'avatar-40');\r\n avatarElem.updateWithOptions({\r\n lazyLoadQueue: this.lazyLoadQueue,\r\n peerId: ((fwdFrom && (this.peerId === rootScope.myId || this.peerId === REPLIES_PEER_ID)) || isForwardFromChannel ? fwdFromId : message.fromId) || NULL_PEER_ID,\r\n peerTitle: !fwdFromId && fwdFrom && fwdFrom.from_name ? /* '🔥 FF 🔥' */fwdFrom.from_name : undefined,\r\n loadPromises\r\n });\r\n \r\n //this.log('exec loadDialogPhoto', message);\r\n\r\n contentWrapper.append(avatarElem);\r\n }\r\n } else {\r\n bubble.classList.add('hide-name');\r\n }\r\n\r\n if(this.chat.type === 'pinned') {\r\n savedFrom = `${this.chat.peerId}_${message.mid}`;\r\n }\r\n\r\n const isThreadStarter = messageWithReplies && messageWithReplies.mid === this.chat.threadId;\r\n if(isThreadStarter) {\r\n bubble.classList.add('is-thread-starter', 'is-group-last');\r\n }\r\n\r\n if(savedFrom && (this.chat.type === 'pinned' || fwdFrom.saved_from_msg_id) && this.peerId !== REPLIES_PEER_ID) {\r\n const goto = document.createElement('div');\r\n goto.classList.add('bubble-beside-button', 'goto-original', 'tgico-arrow_next');\r\n bubbleContainer.append(goto);\r\n bubble.dataset.savedFrom = savedFrom;\r\n bubble.classList.add('with-beside-button');\r\n }\r\n \r\n bubble.classList.add(isOut ? 'is-out' : 'is-in');\r\n if(updatePosition) {\r\n this.renderMessagesQueue(message, bubble, reverse, loadPromises);\r\n }\r\n\r\n if(withReplies) {\r\n const isFooter = MessageRender.renderReplies({\r\n bubble,\r\n bubbleContainer,\r\n message: messageWithReplies,\r\n messageDiv,\r\n loadPromises,\r\n lazyLoadQueue: this.lazyLoadQueue\r\n });\r\n\r\n if(isFooter) {\r\n canHaveTail = true;\r\n }\r\n }\r\n\r\n if(isMessage) {\r\n this.appendReactionsElementToBubble(bubble, message);\r\n }\r\n\r\n /* if(isMessage) {\r\n const reactionHover = document.createElement('div');\r\n reactionHover.classList.add('bubble-reaction-hover');\r\n contentWrapper.append(reactionHover);\r\n } */\r\n\r\n if(canHaveTail) {\r\n bubble.classList.add('can-have-tail');\r\n\r\n bubbleContainer.append(generateTail());\r\n }\r\n\r\n return bubble;\r\n }\r\n\r\n private appendReactionsElementToBubble(bubble: HTMLElement, message: Message.message, changedResults?: ReactionCount[]) {\r\n if(this.peerId.isUser()/* || true */) {\r\n return;\r\n }\r\n\r\n const reactionsMessage = this.appMessagesManager.getGroupsFirstMessage(message);\r\n if(!reactionsMessage.reactions || !reactionsMessage.reactions.results.length) {\r\n return;\r\n }\r\n\r\n // message = this.appMessagesManager.getMessageWithReactions(message);\r\n\r\n const reactionsElement = new ReactionsElement();\r\n reactionsElement.init(reactionsMessage, 'block');\r\n reactionsElement.render(changedResults);\r\n\r\n if(bubble.classList.contains('is-message-empty')) {\r\n bubble.querySelector('.bubble-content-wrapper').append(reactionsElement);\r\n } else {\r\n const messageDiv = bubble.querySelector('.message');\r\n if(bubble.classList.contains('is-multiple-documents')) {\r\n const documentContainer = messageDiv.lastElementChild as HTMLElement;\r\n let documentMessageDiv = documentContainer.querySelector('.document-message');\r\n\r\n let timeSpan: HTMLElement = documentMessageDiv && documentMessageDiv.querySelector('.time');\r\n if(!timeSpan) {\r\n timeSpan = MessageRender.setTime({\r\n chatType: this.chat.type,\r\n message\r\n });\r\n }\r\n \r\n reactionsElement.append(timeSpan);\r\n\r\n if(!documentMessageDiv) {\r\n documentMessageDiv = document.createElement('div');\r\n documentMessageDiv.classList.add('document-message');\r\n documentContainer.querySelector('.document-wrapper').prepend(documentMessageDiv);\r\n }\r\n\r\n documentMessageDiv.append(reactionsElement);\r\n } else {\r\n const timeSpan = Array.from(bubble.querySelectorAll('.time')).pop();\r\n reactionsElement.append(timeSpan);\r\n \r\n messageDiv.append(reactionsElement);\r\n }\r\n }\r\n }\r\n\r\n private safeRenderMessage(message: any, reverse?: boolean, multipleRender?: boolean, bubble?: HTMLElement, updatePosition?: boolean) {\r\n try {\r\n return this.renderMessage(message, reverse, multipleRender, bubble, updatePosition);\r\n } catch(err) {\r\n this.log.error('renderMessage error:', err);\r\n }\r\n }\r\n\r\n public async performHistoryResult(history: (Message.message | Message.messageService | number)[], reverse: boolean, isBackLimit: boolean, additionMsgId?: number) {\r\n // commented bot getProfile in getHistory!\r\n // if(!history/* .filter((id: number) => id > 0) */.length) {\r\n // if(!isBackLimit) {\r\n // this.scrollable.loadedAll.top = true;\r\n\r\n // /* if(this.chat.type === 'discussion') {\r\n // const serviceStartMessageId = this.appMessagesManager.threadsServiceMessagesIdsStorage[this.peerId + '_' + this.chat.threadId];\r\n // if(serviceStartMessageId) history.push(serviceStartMessageId);\r\n // history.push(this.chat.threadId);\r\n // } */\r\n // } else {\r\n // this.scrollable.loadedAll.bottom = true;\r\n // }\r\n // }\r\n\r\n history = history.slice(); // need\r\n\r\n if(additionMsgId) {\r\n history.unshift(additionMsgId);\r\n }\r\n\r\n /* if(testScroll && additionMsgID) {\r\n for(let i = 0; i < 3; ++i) {\r\n let _history = history.slice();\r\n setTimeout(() => {\r\n this.performHistoryResult(_history, reverse, isBackLimit, 0, resetPromises);\r\n }, 0);\r\n }\r\n } */\r\n\r\n //console.time('appImManager render history');\r\n\r\n //await new Promise((resolve) => setTimeout(resolve, 1e3));\r\n\r\n /* if(DEBUG) {\r\n this.log('performHistoryResult: will render some messages:', history.length, this.isHeavyAnimationInProgress, this.messagesQueuePromise);\r\n } */\r\n\r\n let scrollSaver: ScrollSaver, hadScroll: boolean/* , viewportSlice: ReturnType<ChatBubbles['getViewportSlice']> */;\r\n if(this.chatInner.parentElement) {\r\n this.messagesQueueOnRender = () => {\r\n scrollSaver = new ScrollSaver(this.scrollable, reverse);\r\n \r\n if(this.getRenderedLength() && !this.chat.setPeerPromise) {\r\n const viewportSlice = this.getViewportSlice();\r\n this.deleteViewportSlice(viewportSlice, true);\r\n }\r\n \r\n scrollSaver.save();\r\n const saved = scrollSaver.getSaved();\r\n hadScroll = saved.scrollHeight !== saved.clientHeight;\r\n };\r\n }\r\n\r\n if(this.needReflowScroll) {\r\n reflowScrollableElement(this.scrollable.container);\r\n this.needReflowScroll = false;\r\n }\r\n\r\n const cb = (mid: typeof history[0]) => {\r\n const message: Message.message | Message.messageService = typeof(mid) === 'number' ? this.chat.getMessage(mid) : mid;\r\n if(message.pFlags.local) {\r\n this.processLocalMessageRender(message);\r\n } else {\r\n this.safeRenderMessage(message, reverse, true);\r\n }\r\n };\r\n\r\n const length = history.length;\r\n if(reverse) for(let i = 0; i < length; ++i) cb(history[i]);\r\n else for(let i = length - 1; i >= 0; --i) cb(history[i]);\r\n\r\n if(this.chat.type !== 'scheduled') {\r\n const historyStorage = this.appMessagesManager.getHistoryStorage(this.peerId, this.chat.threadId);\r\n const firstSlice = historyStorage.history.first;\r\n const lastSlice = historyStorage.history.last;\r\n if(firstSlice.isEnd(SliceEnd.Bottom) && (!firstSlice.length || history.includes(firstSlice[0]))) {\r\n this.setLoaded('bottom', true, false);\r\n }\r\n \r\n if(lastSlice.isEnd(SliceEnd.Top) && (!lastSlice.length || history.includes(lastSlice[lastSlice.length - 1]))) {\r\n this.setLoaded('top', true, false);\r\n }\r\n } else {\r\n this.setLoaded('top', true);\r\n this.setLoaded('bottom', true);\r\n }\r\n\r\n await this.messagesQueuePromise;//.then(() => new Promise(resolve => setTimeout(resolve, 100)))\r\n\r\n if(this.scrollable.loadedAll.top && this.messagesQueueOnRenderAdditional) {\r\n this.messagesQueueOnRenderAdditional();\r\n\r\n if(this.messagesQueueOnRenderAdditional) {\r\n this.messagesQueueOnRenderAdditional();\r\n }\r\n }\r\n\r\n if(scrollSaver) {\r\n scrollSaver.restore(history.length === 1 && !reverse ? false : true);\r\n this.onRenderScrollSet(scrollSaver.getSaved());\r\n }\r\n\r\n return true;\r\n }\r\n\r\n private onRenderScrollSet(state?: {scrollHeight: number, clientHeight: number}) {\r\n const className = 'has-sticky-dates';\r\n if(!this.bubblesContainer.classList.contains(className)) {\r\n const isLoading = !this.preloader.detached;\r\n\r\n if(isLoading || \r\n (\r\n state ??= {\r\n scrollHeight: this.scrollable.scrollHeight,\r\n clientHeight: this.scrollable.container.clientHeight\r\n }, \r\n state.scrollHeight !== state.clientHeight\r\n )\r\n ) {\r\n /* for(const timestamp in this.dateMessages) {\r\n const dateMessage = this.dateMessages[timestamp];\r\n dateMessage.div.classList.add('is-sticky');\r\n } */\r\n \r\n const middleware = this.getMiddleware();\r\n const callback = () => {\r\n if(!middleware()) return;\r\n this.bubblesContainer.classList.add(className);\r\n };\r\n\r\n if(this.willScrollOnLoad) {\r\n callback();\r\n } else {\r\n setTimeout(callback, 600);\r\n }\r\n\r\n return;\r\n }\r\n }\r\n \r\n this.willScrollOnLoad = undefined;\r\n }\r\n\r\n onDatePick = (timestamp: number) => {\r\n const peerId = this.peerId;\r\n this.appMessagesManager.requestHistory(peerId, 0, 2, -1, timestamp, this.chat.threadId).then(history => {\r\n if(!history?.messages?.length) {\r\n this.log.error('no history!');\r\n return;\r\n } else if(this.peerId !== peerId) {\r\n return;\r\n }\r\n\r\n this.chat.setMessageId((history.messages[0] as MyMessage).mid);\r\n //console.log('got history date:', history);\r\n });\r\n };\r\n\r\n public requestHistory(maxId: number, loadCount: number, backLimit: number) {\r\n //const middleware = this.getMiddleware();\r\n if(this.chat.type === 'chat' || this.chat.type === 'discussion') {\r\n return this.appMessagesManager.getHistory(this.peerId, maxId, loadCount, backLimit, this.chat.threadId);\r\n } else if(this.chat.type === 'pinned') {\r\n const promise = this.appMessagesManager.getSearch({\r\n peerId: this.peerId, \r\n inputFilter: {_: 'inputMessagesFilterPinned'}, \r\n maxId, \r\n limit: loadCount, \r\n backLimit\r\n })\r\n .then(value => ({history: value.history.map(m => m.mid)}));\r\n\r\n return promise;\r\n } else if(this.chat.type === 'scheduled') {\r\n return this.appMessagesManager.getScheduledMessages(this.peerId).then(mids => {\r\n // this.setLoaded('top', true);\r\n // this.setLoaded('bottom', true);\r\n return {history: mids.slice().reverse()};\r\n });\r\n }\r\n }\r\n\r\n private async animateAsLadder(additionMsgId: number, additionMsgIds: number[], isAdditionRender: boolean, backLimit: number, maxId: number) {\r\n /* const middleware = this.getMiddleware();\r\n await this.ladderDeferred; */\r\n\r\n if(this.chat.setPeerPromise && !this.resolveLadderAnimation) {\r\n // @ts-ignore\r\n this.resolveLadderAnimation = this.animateAsLadder.bind(this, additionMsgId, additionMsgIds, isAdditionRender, backLimit, maxId);\r\n return;\r\n }\r\n\r\n /* if(!middleware()) {\r\n return;\r\n } */\r\n\r\n if(!Object.keys(this.bubbles).length) {\r\n return;\r\n }\r\n\r\n let sortedMids = getObjectKeysAndSort(this.bubbles, 'desc');\r\n\r\n if(isAdditionRender && additionMsgIds.length) {\r\n sortedMids = sortedMids.filter(mid => !additionMsgIds.includes(mid));\r\n }\r\n\r\n let targetMid: number;\r\n if(backLimit) {\r\n targetMid = maxId || Math.max(...sortedMids); // * on discussion enter\r\n } else {\r\n if(additionMsgId) {\r\n targetMid = additionMsgId;\r\n } else { // * if maxId === 0\r\n targetMid = Math.max(...sortedMids);\r\n }\r\n }\r\n\r\n const topIds = sortedMids.slice(sortedMids.findIndex(mid => targetMid > mid));\r\n const middleIds = isAdditionRender ? [] : [targetMid];\r\n const bottomIds = isAdditionRender ? [] : sortedMids.slice(0, sortedMids.findIndex(mid => targetMid >= mid)).reverse();\r\n \r\n if(DEBUG) {\r\n this.log('getHistory: targeting mid:', targetMid, maxId, additionMsgId, \r\n topIds.map(m => this.appMessagesIdsManager.getServerMessageId(m)), \r\n bottomIds.map(m => this.appMessagesIdsManager.getServerMessageId(m)));\r\n }\r\n\r\n const setBubbles: HTMLElement[] = [];\r\n\r\n this.chatInner.classList.add('zoom-fading');\r\n const delay = isAdditionRender ? 10 : 40;\r\n const offsetIndex = isAdditionRender ? 0 : 1;\r\n const animateAsLadder = (mids: number[], offsetIndex = 0) => {\r\n const animationPromise = deferredPromise<void>();\r\n let lastMsDelay = 0;\r\n mids.forEach((mid, idx) => {\r\n if(!this.bubbles[mid] || this.skippedMids.has(mid)) {\r\n this.log.warn('animateAsLadder: no bubble by mid:', mid);\r\n return;\r\n }\r\n\r\n const contentWrapper = this.bubbles[mid].lastElementChild as HTMLElement;\r\n\r\n lastMsDelay = ((idx + offsetIndex) || 0.1) * delay;\r\n //lastMsDelay = (idx + offsetIndex) * delay;\r\n //lastMsDelay = (idx || 0.1) * 1000;\r\n \r\n contentWrapper.classList.add('zoom-fade');\r\n contentWrapper.style.transitionDelay = lastMsDelay + 'ms';\r\n\r\n if(idx === (mids.length - 1)) {\r\n const onTransitionEnd = (e: TransitionEvent) => {\r\n if(e.target !== contentWrapper) {\r\n return;\r\n }\r\n\r\n animationPromise.resolve();\r\n contentWrapper.removeEventListener('transitionend', onTransitionEnd);\r\n };\r\n\r\n contentWrapper.addEventListener('transitionend', onTransitionEnd);\r\n }\r\n \r\n //this.log('supa', bubble);\r\n\r\n setBubbles.push(contentWrapper);\r\n });\r\n\r\n if(!mids.length) {\r\n animationPromise.resolve();\r\n }\r\n\r\n return {lastMsDelay, animationPromise};\r\n };\r\n\r\n const topRes = animateAsLadder(topIds, offsetIndex);\r\n const middleRes = animateAsLadder(middleIds);\r\n const bottomRes = animateAsLadder(bottomIds, offsetIndex);\r\n const promises = [topRes.animationPromise, middleRes.animationPromise, bottomRes.animationPromise];\r\n const delays: number[] = [topRes.lastMsDelay, middleRes.lastMsDelay, bottomRes.lastMsDelay];\r\n\r\n if(this.onAnimateLadder) {\r\n await this.onAnimateLadder();\r\n }\r\n\r\n // fastRaf(() => {\r\n fastRaf(() => {\r\n this.setStickyDateManually(); // ! maybe it's not efficient\r\n\r\n setBubbles.forEach(contentWrapper => {\r\n contentWrapper.classList.remove('zoom-fade');\r\n });\r\n });\r\n // });\r\n\r\n let promise: Promise<any>;\r\n if(topIds.length || middleIds.length || bottomIds.length) {\r\n promise = Promise.all(promises);\r\n\r\n dispatchHeavyAnimationEvent(promise, Math.max(...delays) + 200) // * 200 - transition time\r\n .then(() => { \r\n fastRaf(() => {\r\n setBubbles.forEach(contentWrapper => {\r\n contentWrapper.style.transitionDelay = '';\r\n });\r\n\r\n this.chatInner.classList.remove('zoom-fading');\r\n });\r\n\r\n // ! в хроме, каким-то образом из-за zoom-fade класса начинает прыгать скролл при подгрузке сообщений вверх, \r\n // ! т.е. скролл не ставится, так же, как в сафари при translateZ на блок выше scrollable\r\n // if(!IS_SAFARI) {\r\n // this.needReflowScroll = true;\r\n // }\r\n });\r\n }\r\n\r\n return promise;\r\n }\r\n\r\n private renderEmptyPlaceholder(type: 'group' | 'saved' | 'noMessages' | 'noScheduledMessages' | 'greeting' | 'restricted', bubble: HTMLElement, message: any, elements: (Node | string)[]) {\r\n const BASE_CLASS = 'empty-bubble-placeholder';\r\n bubble.classList.add(BASE_CLASS, BASE_CLASS + '-' + type);\r\n\r\n let title: HTMLElement; \r\n if(type === 'group') title = i18n('GroupEmptyTitle1');\r\n else if(type === 'saved') title = i18n('ChatYourSelfTitle');\r\n else if(type === 'noMessages' || type === 'greeting') title = i18n('NoMessages');\r\n else if(type === 'noScheduledMessages') title = i18n('NoScheduledMessages');\r\n else if(type === 'restricted') {\r\n title = document.createElement('span');\r\n title.innerText = this.appPeersManager.getRestrictionReasonText(this.peerId);\r\n }\r\n title.classList.add('center', BASE_CLASS + '-title');\r\n\r\n elements.push(title);\r\n\r\n let listElements: HTMLElement[];\r\n if(type === 'group') {\r\n elements.push(i18n('GroupEmptyTitle2'));\r\n listElements = [\r\n i18n('GroupDescription1'),\r\n i18n('GroupDescription2'),\r\n i18n('GroupDescription3'),\r\n i18n('GroupDescription4')\r\n ];\r\n } else if(type === 'saved') {\r\n listElements = [\r\n i18n('ChatYourSelfDescription1'),\r\n i18n('ChatYourSelfDescription2'),\r\n i18n('ChatYourSelfDescription3'),\r\n i18n('ChatYourSelfDescription4')\r\n ];\r\n } else if(type === 'greeting') {\r\n const subtitle = i18n('NoMessagesGreetingsDescription');\r\n subtitle.classList.add('center', BASE_CLASS + '-subtitle');\r\n\r\n findAndSplice(this.messagesQueue, q => q.bubble === bubble);\r\n\r\n const stickerDiv = document.createElement('div');\r\n stickerDiv.classList.add(BASE_CLASS + '-sticker');\r\n\r\n const middleware = this.getMiddleware();\r\n \r\n const loadPromise = this.appStickersManager.getGreetingSticker().then(doc => {\r\n if(!middleware()) return;\r\n\r\n const loadPromises: Promise<any>[] = [];\r\n wrapSticker({\r\n doc, \r\n // doc: appDocsManager.getDoc(\"5431607541660389336\"), // cubigator mockup\r\n div: stickerDiv,\r\n middleware,\r\n lazyLoadQueue: this.lazyLoadQueue,\r\n group: CHAT_ANIMATION_GROUP,\r\n //play: !!message.pending || !multipleRender,\r\n play: true,\r\n loop: true,\r\n withThumb: true,\r\n loadPromises\r\n });\r\n\r\n attachClickEvent(stickerDiv, (e) => {\r\n cancelEvent(e);\r\n EmoticonsDropdown.onMediaClick({target: e.target});\r\n });\r\n\r\n return Promise.all(loadPromises);\r\n });\r\n\r\n this.renderMessagesQueue(message, bubble, false, [loadPromise]);\r\n\r\n elements.push(subtitle, stickerDiv);\r\n }\r\n\r\n if(listElements) {\r\n elements.push(\r\n ...listElements.map(elem => {\r\n const span = document.createElement('span');\r\n span.classList.add(BASE_CLASS + '-list-item');\r\n span.append(elem);\r\n return span;\r\n })\r\n );\r\n \r\n if(type === 'group') {\r\n listElements.forEach(elem => {\r\n const i = document.createElement('span');\r\n i.classList.add('tgico-check');\r\n elem.prepend(i);\r\n });\r\n } else if(type === 'saved') {\r\n listElements.forEach(elem => {\r\n const i = document.createElement('span');\r\n i.classList.add(BASE_CLASS + '-list-bullet');\r\n i.innerText = '•';\r\n elem.prepend(i);\r\n });\r\n }\r\n }\r\n\r\n if(elements.length > 1) {\r\n bubble.classList.add('has-description');\r\n }\r\n\r\n elements.forEach((element: any) => element.classList.add(BASE_CLASS + '-line'));\r\n }\r\n\r\n private processLocalMessageRender(message: Message.message | Message.messageService) {\r\n const isSponsored = !!(message as Message.message).pFlags.sponsored;\r\n const bubble = this.safeRenderMessage(message, undefined, undefined, undefined, isSponsored);\r\n bubble.classList.add('is-group-last', 'is-group-first');\r\n\r\n if(!isSponsored) {\r\n bubble.classList.add('bubble-first');\r\n bubble.classList.remove('can-have-tail', 'is-in');\r\n }\r\n\r\n const elements: (Node | string)[] = [];\r\n const isBot = this.appPeersManager.isBot(this.peerId);\r\n if(this.chat.isRestricted) {\r\n this.renderEmptyPlaceholder('restricted', bubble, message, elements);\r\n } else if(isSponsored) {\r\n let text: LangPackKey, mid: number, startParam: string, callback: () => void;\r\n\r\n bubble.classList.add('avoid-selection');\r\n\r\n const sponsoredMessage = this.sponsoredMessage = (message as Message.message).sponsoredMessage;\r\n const peerId = this.appPeersManager.getPeerId(sponsoredMessage.from_id);\r\n // const peer = this.appPeersManager.getPeer(peerId);\r\n if(sponsoredMessage.channel_post) {\r\n text = 'OpenChannelPost';\r\n mid = this.appMessagesIdsManager.generateMessageId(sponsoredMessage.channel_post);\r\n } else if(sponsoredMessage.start_param || this.appUsersManager.isBot(peerId.toUserId())) {\r\n text = 'Chat.Message.ViewBot';\r\n startParam = sponsoredMessage.start_param;\r\n } else {\r\n text = this.appPeersManager.isAnyGroup(peerId) ? 'Chat.Message.ViewGroup' : 'Chat.Message.ViewChannel';\r\n }\r\n\r\n if(sponsoredMessage.chat_invite) {\r\n callback = () => {\r\n new PopupJoinChatInvite(sponsoredMessage.chat_invite_hash, sponsoredMessage.chat_invite as ChatInvite.chatInvite).show();\r\n };\r\n } else if(sponsoredMessage.chat_invite_hash) {\r\n callback = () => {\r\n const link: InternalLink = {\r\n _: INTERNAL_LINK_TYPE.JOIN_CHAT,\r\n invite: sponsoredMessage.chat_invite_hash\r\n };\r\n \r\n this.chat.appImManager.processInternalLink(link);\r\n };\r\n } else {\r\n callback = () => {\r\n rootScope.dispatchEvent('history_focus', {\r\n peerId,\r\n mid,\r\n startParam\r\n });\r\n };\r\n }\r\n\r\n const button = Button('btn-primary btn-primary-transparent bubble-view-button', {\r\n text\r\n });\r\n\r\n this.observer.observe(button, this.viewsObserverCallback);\r\n\r\n if(callback) {\r\n attachClickEvent(button, callback);\r\n }\r\n\r\n bubble.querySelector('.bubble-content').prepend(button);\r\n\r\n return;\r\n } else if(isBot && message._ === 'message') {\r\n const b = document.createElement('b');\r\n b.append(i18n('BotInfoTitle'));\r\n elements.push(b, '\\n\\n');\r\n } else if(this.appPeersManager.isAnyGroup(this.peerId) && this.appPeersManager.getPeer(this.peerId).pFlags.creator) {\r\n this.renderEmptyPlaceholder('group', bubble, message, elements);\r\n } else if(this.chat.type === 'scheduled') {\r\n this.renderEmptyPlaceholder('noScheduledMessages', bubble, message, elements);\r\n } else if(rootScope.myId === this.peerId) {\r\n this.renderEmptyPlaceholder('saved', bubble, message, elements);\r\n } else if(this.appPeersManager.isUser(this.peerId) && !isBot && this.chat.canSend() && this.chat.type === 'chat') {\r\n this.renderEmptyPlaceholder('greeting', bubble, message, elements);\r\n } else {\r\n this.renderEmptyPlaceholder('noMessages', bubble, message, elements);\r\n }\r\n\r\n /* for(let i = 1; i < elements.length; i += 2) {\r\n elements.splice(i, 0, '\\n');\r\n } */\r\n\r\n if(elements.length) {\r\n const messageDiv = bubble.querySelector('.message, .service-msg');\r\n messageDiv.prepend(...elements);\r\n }\r\n\r\n const method: 'append' | 'prepend' = isSponsored ? 'append' : 'prepend';\r\n if(this.messagesQueueOnRenderAdditional) {\r\n this.onAnimateLadder = () => {\r\n this.chatInner[method](bubble);\r\n this.onAnimateLadder = undefined;\r\n\r\n // need raf here because animation won't fire if this message is single\r\n if(!this.messagesQueuePromise) {\r\n return fastRafPromise();\r\n }\r\n };\r\n } else {\r\n this.chatInner[method](bubble);\r\n }\r\n\r\n // if(!isSponsored) {\r\n this.emptyPlaceholderMid = message.mid;\r\n // }\r\n }\r\n\r\n private generateLocalMessageId(addOffset = 0) {\r\n // const INCREMENT = 0x10;\r\n let offset = (this.chat.type === 'scheduled' ? -1 : 0) + addOffset;\r\n // offset = this.appMessagesIdsManager.generateMessageId(offset);\r\n // id: -Math.abs(+this.peerId * INCREMENT + offset),\r\n const id = -Math.abs(offset);\r\n const mid = -Math.abs(this.appMessagesIdsManager.generateMessageId(id));\r\n return {id, mid};\r\n }\r\n\r\n private generateLocalFirstMessage<T extends boolean>(service?: T, fill?: (message: GenerateLocalMessageType<T>) => void, addOffset = 0): GenerateLocalMessageType<T> {\r\n const {id, mid} = this.generateLocalMessageId(addOffset);\r\n const message: Omit<Message.message | Message.messageService, 'message'> & {message?: string} = {\r\n _: service ? 'messageService' : 'message',\r\n date: 0,\r\n id,\r\n mid,\r\n peer_id: this.appPeersManager.getOutputPeer(this.peerId),\r\n pFlags: {\r\n local: true\r\n }\r\n };\r\n\r\n if(!service) {\r\n message.message = '';\r\n }/* else {\r\n (message as Message.messageService).action = {} as any;\r\n } */\r\n\r\n assumeType<GenerateLocalMessageType<T>>(message);\r\n\r\n fill && fill(message);\r\n\r\n this.appMessagesManager.saveMessages([message], {storage: new Map()});\r\n message.mid = mid;\r\n return message;\r\n }\r\n\r\n public getViewportSlice() {\r\n // this.log.trace('viewport slice');\r\n return getViewportSlice({\r\n overflowElement: this.scrollable.container, \r\n selector: '.bubbles-date-group .bubble:not(.is-date)',\r\n extraSize: Math.max(700, windowSize.height) * 2\r\n });\r\n }\r\n\r\n public deleteViewportSlice(slice: ReturnType<ChatBubbles['getViewportSlice']>, ignoreScrollSaving?: boolean) {\r\n // return;\r\n\r\n const {invisibleTop, invisibleBottom} = slice;\r\n const invisible = invisibleTop.concat(invisibleBottom);\r\n if(!invisible.length) {\r\n return;\r\n }\r\n\r\n if(invisibleTop.length) this.setLoaded('top', false);\r\n if(invisibleBottom.length) this.setLoaded('bottom', false);\r\n\r\n const mids = invisible.map(({element}) => +element.dataset.mid);\r\n\r\n let scrollSaver: ScrollSaver;\r\n if(!!invisibleTop.length !== !!invisibleBottom.length && !ignoreScrollSaving) {\r\n scrollSaver = new ScrollSaver(this.scrollable, !!invisibleTop.length);\r\n scrollSaver.save();\r\n }\r\n \r\n this.deleteMessagesByIds(mids, false, true);\r\n\r\n if(scrollSaver) {\r\n scrollSaver.restore();\r\n } else if(invisibleTop.length) {\r\n this.scrollable.lastScrollPosition = this.scrollable.scrollTop;\r\n }\r\n }\r\n\r\n public sliceViewport(ignoreHeavyAnimation?: boolean) {\r\n // Safari cannot reset the scroll.\r\n if(IS_SAFARI || (this.isHeavyAnimationInProgress && !ignoreHeavyAnimation)/* || true */) {\r\n return;\r\n }\r\n\r\n // const scrollSaver = new ScrollSaver(this.scrollable, true);\r\n // scrollSaver.save();\r\n const slice = this.getViewportSlice();\r\n // if(IS_SAFARI) slice.invisibleTop = [];\r\n this.deleteViewportSlice(slice);\r\n // scrollSaver.restore();\r\n }\r\n\r\n private setLoaded(side: SliceSides, value: boolean, checkPlaceholders = true) {\r\n const willChange = this.scrollable.loadedAll[side] !== value;\r\n if(!willChange) {\r\n return;\r\n }\r\n\r\n this.scrollable.loadedAll[side] = value;\r\n\r\n /* if(!checkPlaceholders) {\r\n return;\r\n } */\r\n\r\n if(side === 'bottom' && this.appPeersManager.isBroadcast(this.peerId) && !this.chat.isRestricted/* && false */) {\r\n const {mid} = this.generateLocalMessageId(SPONSORED_MESSAGE_ID_OFFSET);\r\n if(value) {\r\n const middleware = this.getMiddleware(() => {\r\n return this.scrollable.loadedAll.bottom && !this.bubbles[mid] && this.getSponsoredMessagePromise === promise;\r\n });\r\n \r\n const promise = this.getSponsoredMessagePromise = this.chat.apiManager.invokeApiCacheable('channels.getSponsoredMessages', {\r\n channel: this.appChatsManager.getChannelInput(this.peerId.toChatId())\r\n }, {cacheSeconds: 300}).then(sponsoredMessages => {\r\n if(!middleware()) return;\r\n\r\n /* forEachReverse(sponsoredMessages.messages, (message, idx, arr) => {\r\n if(message.chat_invite || message.chat_invite_hash) {\r\n arr.splice(idx, 1);\r\n }\r\n }); */\r\n\r\n this.appUsersManager.saveApiUsers(sponsoredMessages.users);\r\n this.appChatsManager.saveApiChats(sponsoredMessages.chats);\r\n \r\n const sponsoredMessage = sponsoredMessages.messages.shift();\r\n if(!sponsoredMessage) {\r\n return;\r\n }\r\n\r\n sponsoredMessages.messages.push(sponsoredMessage);\r\n const message = this.generateLocalFirstMessage(false, (message) => {\r\n message.message = sponsoredMessage.message;\r\n message.from_id = sponsoredMessage.from_id;\r\n message.entities = sponsoredMessage.entities;\r\n message.pFlags.sponsored = true;\r\n message.sponsoredMessage = sponsoredMessage;\r\n }, SPONSORED_MESSAGE_ID_OFFSET);\r\n \r\n return Promise.all([\r\n this.getHistoryTopPromise, // wait for top load and execute rendering after or with it\r\n this.messagesQueuePromise\r\n ]).then(() => {\r\n if(!middleware()) return;\r\n // this.processLocalMessageRender(message);\r\n const promise = this.performHistoryResult([message], false, true);\r\n });\r\n }).finally(() => {\r\n this.getSponsoredMessagePromise = undefined;\r\n });\r\n } else {\r\n this.deleteMessagesByIds([mid]);\r\n this.getSponsoredMessagePromise = undefined;\r\n }\r\n }\r\n\r\n if(side === 'top' && value && this.appPeersManager.isBot(this.peerId) && !this.chat.isRestricted) {\r\n this.log('inject bot description');\r\n\r\n const middleware = this.getMiddleware();\r\n return Promise.resolve(this.appProfileManager.getProfile(this.peerId.toUserId())).then(userFull => {\r\n if(!middleware()) {\r\n return;\r\n }\r\n\r\n if(!userFull.bot_info?.description) {\r\n this.checkIfEmptyPlaceholderNeeded();\r\n return;\r\n }\r\n\r\n const message = this.generateLocalFirstMessage(false, message => {\r\n message.message = userFull.bot_info.description;\r\n });\r\n\r\n this.processLocalMessageRender(message);\r\n });\r\n }\r\n\r\n this.checkIfEmptyPlaceholderNeeded();\r\n }\r\n\r\n public checkIfEmptyPlaceholderNeeded() {\r\n if(this.scrollable.loadedAll.top && \r\n this.scrollable.loadedAll.bottom && \r\n this.emptyPlaceholderMid === undefined && \r\n (\r\n this.chat.isRestricted || \r\n !this.appMessagesManager.getHistoryStorage(this.peerId).count || \r\n (\r\n Object.keys(this.bubbles).length && \r\n !this.getRenderedLength()\r\n ) ||\r\n (this.chat.type === 'scheduled' && !Object.keys(this.bubbles).length)\r\n )\r\n ) {\r\n this.log('inject empty peer placeholder');\r\n\r\n const message = this.generateLocalFirstMessage(true);\r\n this.processLocalMessageRender(message);\r\n\r\n return true;\r\n }\r\n\r\n return false;\r\n }\r\n\r\n /**\r\n * Load and render history\r\n * @param maxId max message id\r\n * @param reverse 'true' means up\r\n * @param isBackLimit is search\r\n * @param additionMsgId for the last message\r\n * @param justLoad do not render\r\n */\r\n public getHistory(maxId = 0, reverse = false, isBackLimit = false, additionMsgId = 0, justLoad = false): {cached: boolean, promise: Promise<boolean>} {\r\n const peerId = this.peerId;\r\n\r\n const isBroadcast = this.appPeersManager.isBroadcast(peerId);\r\n //console.time('appImManager call getHistory');\r\n const pageCount = Math.min(30, windowSize.height / 40/* * 1.25 */ | 0);\r\n //const loadCount = Object.keys(this.bubbles).length > 0 ? 50 : pageCount;\r\n const realLoadCount = isBroadcast ? 20 : (Object.keys(this.bubbles).length > 0 ? Math.max(35, pageCount) : pageCount);\r\n //const realLoadCount = pageCount;//const realLoadCount = 50;\r\n let loadCount = realLoadCount;\r\n \r\n /* if(TEST_SCROLL) {\r\n //loadCount = 1;\r\n if(Object.keys(this.bubbles).length > 0)\r\n return {cached: false, promise: Promise.resolve(true)};\r\n } */\r\n if(TEST_SCROLL !== undefined) {\r\n if(TEST_SCROLL) {\r\n if(Object.keys(this.bubbles).length > 0) {\r\n --TEST_SCROLL;\r\n }\r\n } else {\r\n return {cached: false, promise: Promise.resolve(true)};\r\n }\r\n }\r\n \r\n ////console.time('render history total');\r\n \r\n let backLimit = 0;\r\n if(isBackLimit) {\r\n backLimit = loadCount;\r\n\r\n if(!reverse) { // if not jump\r\n loadCount = 0;\r\n //maxId = this.appMessagesManager.incrementMessageId(maxId, 1);\r\n }\r\n }\r\n\r\n let additionMsgIds: number[];\r\n if(additionMsgId && !isBackLimit) {\r\n if(this.chat.type === 'pinned') {\r\n additionMsgIds = [additionMsgId];\r\n } else {\r\n const historyStorage = this.appMessagesManager.getHistoryStorage(peerId, this.chat.threadId);\r\n const slice = historyStorage.history.slice;\r\n if(slice.length < loadCount && !slice.isEnd(SliceEnd.Both)) {\r\n additionMsgIds = slice.slice();\r\n\r\n // * filter last album, because we don't know is it the last item\r\n for(let i = additionMsgIds.length - 1; i >= 0; --i) {\r\n const message = this.chat.getMessage(additionMsgIds[i]);\r\n if(message.grouped_id) additionMsgIds.splice(i, 1);\r\n else break;\r\n }\r\n\r\n maxId = additionMsgIds[additionMsgIds.length - 1] || maxId;\r\n }\r\n }\r\n }\r\n\r\n /* const result = additionMsgID ? \r\n {history: [additionMsgID]} : \r\n appMessagesManager.getHistory(this.peerId, maxId, loadCount, backLimit); */\r\n let result: ReturnType<AppMessagesManager['getHistory']> | {history: number[]} = this.requestHistory(maxId, loadCount, backLimit) as any;\r\n let resultPromise: Promise<any>;\r\n\r\n //const isFirstMessageRender = !!additionMsgID && result instanceof Promise && !appMessagesManager.getMessage(additionMsgID).grouped_id;\r\n const isAdditionRender = additionMsgIds?.length && result instanceof Promise;\r\n const isFirstMessageRender = (this.isFirstLoad && backLimit && result instanceof Promise) || isAdditionRender;\r\n if(isAdditionRender) {\r\n resultPromise = result as Promise<any>;\r\n result = {history: additionMsgIds};\r\n //additionMsgID = 0;\r\n }\r\n\r\n this.isFirstLoad = false;\r\n\r\n const processResult = async(historyResult: typeof result) => {\r\n if('offsetIdOffset' in historyResult && historyResult.history.isEnd(SliceEnd.Top)) {\r\n if(this.chat.type === 'discussion') { // * inject discussion start\r\n //this.log('discussion got history', loadCount, backLimit, historyResult, isTopEnd);\r\n const serviceStartMessageId = this.appMessagesManager.threadsServiceMessagesIdsStorage[this.peerId + '_' + this.chat.threadId];\r\n if(serviceStartMessageId) historyResult.history.push(serviceStartMessageId);\r\n historyResult.history.push(...this.chat.getMidsByMid(this.chat.threadId).reverse());\r\n }\r\n\r\n await this.setLoaded('top', true);\r\n }\r\n };\r\n\r\n const sup = (result: HistoryResult) => {\r\n /* if(maxId && result.history?.length) {\r\n if(this.bubbles[maxId]) {\r\n result.history.findAndSplice(mid => mid === maxId); \r\n }\r\n } */\r\n\r\n ////console.timeEnd('render history total');\r\n \r\n return getHeavyAnimationPromise().then(() => {\r\n return processResult(result);\r\n }).then(() => {\r\n return this.performHistoryResult(result.history as number[] || [], reverse, isBackLimit, !isAdditionRender && additionMsgId);\r\n });\r\n };\r\n\r\n const processPromise = (result: Promise<HistoryResult>) => {\r\n const promise = result.then((result) => {\r\n //this.log('getHistory not cached result by maxId:', maxId, reverse, isBackLimit, result, peerId, justLoad);\r\n\r\n if(reverse ? this.getHistoryTopPromise !== promise : this.getHistoryBottomPromise !== promise) {\r\n this.log.warn('getHistory: peer changed');\r\n ////console.timeEnd('render history total');\r\n return Promise.reject();\r\n }\r\n\r\n if(justLoad) {\r\n // нужно делать из-за ранней прогрузки\r\n this.scrollable.onScroll();\r\n // fastRaf(() => {\r\n // this.scrollable.checkForTriggers();\r\n // });\r\n return true;\r\n }\r\n //console.timeEnd('appImManager call getHistory');\r\n\r\n return sup(result);\r\n }, (err) => {\r\n this.log.error('getHistory error:', err);\r\n throw err;\r\n });\r\n \r\n return promise;\r\n };\r\n\r\n let promise: Promise<boolean>, cached: boolean;\r\n if(result instanceof Promise) {\r\n cached = false;\r\n promise = processPromise(result);\r\n } else if(justLoad) {\r\n // нужно делать из-за ранней прогрузки\r\n this.scrollable.onScroll();\r\n return null;\r\n } else {\r\n cached = true;\r\n //this.log('getHistory cached result by maxId:', maxId, reverse, isBackLimit, result, peerId, justLoad);\r\n promise = sup(result as HistoryResult);\r\n //return (reverse ? this.getHistoryTopPromise = promise : this.getHistoryBottomPromise = promise);\r\n //return this.performHistoryResult(result.history || [], reverse, isBackLimit, additionMsgID, true);\r\n }\r\n\r\n const waitPromise = isAdditionRender ? processPromise(resultPromise) : promise;\r\n\r\n if(isFirstMessageRender && rootScope.settings.animationsEnabled/* && false */) {\r\n let times = isAdditionRender ? 2 : 1;\r\n this.messagesQueueOnRenderAdditional = () => {\r\n this.log('ship went past rocks of magnets');\r\n\r\n if(--times) return;\r\n\r\n this.messagesQueueOnRenderAdditional = undefined;\r\n \r\n const promise = this.animateAsLadder(additionMsgId, additionMsgIds, isAdditionRender, backLimit, maxId);\r\n promise.then(() => {\r\n setTimeout(() => { // preload messages\r\n this.loadMoreHistory(reverse, true);\r\n }, 0);\r\n });\r\n };\r\n } else {\r\n this.messagesQueueOnRenderAdditional = undefined;\r\n }\r\n\r\n (reverse ? this.getHistoryTopPromise = waitPromise : this.getHistoryBottomPromise = waitPromise);\r\n waitPromise.then(() => {\r\n (reverse ? this.getHistoryTopPromise = undefined : this.getHistoryBottomPromise = undefined);\r\n });\r\n\r\n if(justLoad) {\r\n return null;\r\n }\r\n\r\n promise.then(() => {\r\n // preload more\r\n //if(!isFirstMessageRender) {\r\n if(this.chat.type === 'chat'/* || this.chat.type === 'discussion' */) {\r\n /* const storage = this.appMessagesManager.getHistoryStorage(peerId, this.chat.threadId);\r\n const isMaxIdInHistory = storage.history.indexOf(maxId) !== -1;\r\n if(isMaxIdInHistory || true) { // * otherwise it is a search or jump */\r\n setTimeout(() => {\r\n if(reverse) {\r\n this.loadMoreHistory(true, true);\r\n } else {\r\n this.loadMoreHistory(false, true);\r\n }\r\n }, 0);\r\n //}\r\n }\r\n //}\r\n });\r\n\r\n return {cached, promise};\r\n }\r\n\r\n public setUnreadDelimiter() {\r\n if(!(this.chat.type === 'chat' || this.chat.type === 'discussion')) {\r\n return;\r\n }\r\n\r\n if(this.attachedUnreadBubble) {\r\n return;\r\n }\r\n\r\n const historyStorage = this.appMessagesManager.getHistoryStorage(this.peerId, this.chat.threadId);\r\n let readMaxId = this.appMessagesManager.getReadMaxIdIfUnread(this.peerId, this.chat.threadId);\r\n if(!readMaxId) return;\r\n\r\n readMaxId = Object.keys(this.bubbles)\r\n .filter(mid => !this.bubbles[mid].classList.contains('is-out'))\r\n .map(i => +i)\r\n .sort((a, b) => a - b)\r\n .find(i => i > readMaxId);\r\n\r\n if(readMaxId && this.bubbles[readMaxId]) {\r\n let bubble = this.bubbles[readMaxId];\r\n if(this.firstUnreadBubble && this.firstUnreadBubble !== bubble) {\r\n this.firstUnreadBubble.classList.remove('is-first-unread');\r\n this.firstUnreadBubble = null;\r\n }\r\n\r\n if(readMaxId !== historyStorage.maxId) {\r\n bubble.classList.add('is-first-unread');\r\n }\r\n\r\n this.firstUnreadBubble = bubble;\r\n this.attachedUnreadBubble = true;\r\n }\r\n }\r\n\r\n public deleteEmptyDateGroups() {\r\n const mustBeCount = this.stickyIntersector ? STICKY_OFFSET : 1;\r\n let deleted = false;\r\n for(const i in this.dateMessages) {\r\n const dateMessage = this.dateMessages[i];\r\n\r\n if(dateMessage.container.childElementCount === mustBeCount) { // only date div + sentinel div\r\n dateMessage.container.remove();\r\n if(this.stickyIntersector) {\r\n this.stickyIntersector.unobserve(dateMessage.container, dateMessage.div);\r\n }\r\n delete this.dateMessages[i];\r\n deleted = true;\r\n\r\n // * no sense in it\r\n /* if(dateMessage.div === this.previousStickyDate) {\r\n this.previousStickyDate = undefined;\r\n } */\r\n }\r\n }\r\n\r\n if(!deleted) {\r\n return;\r\n }\r\n\r\n this.checkIfEmptyPlaceholderNeeded();\r\n this.setStickyDateManually();\r\n }\r\n}\r\n\r\nexport function generateTail() {\r\n const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\r\n svg.setAttributeNS(null, 'viewBox', '0 0 11 20');\r\n svg.setAttributeNS(null, 'width', '11');\r\n svg.setAttributeNS(null, 'height', '20');\r\n svg.classList.add('bubble-tail');\r\n\r\n const use = document.createElementNS('http://www.w3.org/2000/svg', 'use');\r\n use.setAttributeNS(null, 'href', '#message-tail-filled');\r\n\r\n svg.append(use);\r\n\r\n return svg;\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { copyTextToClipboard } from \"../clipboard\";\n// import SelectionSaver from \"../selectionSaver\";\n// import selectElementContents from \"./selectElementContents\";\n\nexport default function copyFromElement(element: HTMLElement) {\n copyTextToClipboard(element.textContent);\n // const saver = new SelectionSaver();\n // saver.save();\n // selectElementContents(element);\n // document.execCommand('copy');\n // saver.restore();\n}\n","export const SEND_WHEN_ONLINE_TIMESTAMP = 0x7FFFFFFE;\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport getVisibleRect from \"./getVisibleRect\";\n\nexport type ViewportSlicePart = {element: HTMLElement, rect: DOMRect, visibleRect: ReturnType<typeof getVisibleRect>}[];\n\nexport default function getViewportSlice({overflowElement, selector, extraSize}: {\n overflowElement: HTMLElement,\n selector: string,\n extraSize?: number\n}) {\n // const perf = performance.now();\n const overflowRect = overflowElement.getBoundingClientRect();\n const elements = Array.from(overflowElement.querySelectorAll<HTMLElement>(selector));\n\n const invisibleTop: ViewportSlicePart = [], \n visible: typeof invisibleTop = [], \n invisibleBottom: typeof invisibleTop = [];\n let foundVisible = false;\n for(const element of elements) {\n const rect = element.getBoundingClientRect();\n const visibleRect = getVisibleRect(element, overflowElement, false, rect, overflowRect);\n \n const isVisible = !!visibleRect;\n let array: typeof invisibleTop;\n if(isVisible) {\n foundVisible = true;\n array = visible;\n } else if(foundVisible) {\n array = invisibleBottom; \n } else {\n array = invisibleTop;\n }\n\n array.push({\n element,\n rect,\n visibleRect\n });\n }\n\n if(extraSize && visible.length) {\n const maxTop = visible[0].rect.top;\n const minTop = maxTop - extraSize;\n const minBottom = visible[visible.length - 1].rect.bottom;\n const maxBottom = minBottom + extraSize;\n \n for(let length = invisibleTop.length, i = length - 1; i >= 0; --i) {\n const element = invisibleTop[i];\n if(element.rect.top >= minTop) {\n invisibleTop.splice(i, 1);\n visible.unshift(element);\n }\n }\n\n for(let i = 0, length = invisibleBottom.length; i < length; ++i) {\n const element = invisibleBottom[i];\n if(element.rect.bottom <= maxBottom) {\n invisibleBottom.splice(i--, 1);\n --length;\n visible.push(element);\n }\n }\n }\n\n // console.log('getViewportSlice time:', performance.now() - perf);\n\n return {invisibleTop, visible, invisibleBottom};\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport appMessagesManager from \"../../lib/appManagers/appMessagesManager\";\nimport { addCancelButton } from \".\";\nimport PopupPeer, { PopupPeerButtonCallbackCheckboxes, PopupPeerOptions } from \"./peer\";\nimport appPeersManager from \"../../lib/appManagers/appPeersManager\";\nimport rootScope from \"../../lib/rootScope\";\nimport { FormatterArguments, LangPackKey } from \"../../lib/langPack\";\nimport appChatsManager from \"../../lib/appManagers/appChatsManager\";\nimport PeerTitle from \"../peerTitle\";\n\nexport default class PopupPinMessage {\n constructor(peerId: PeerId, mid: number, unpin?: true, onConfirm?: () => void) {\n let title: LangPackKey, description: LangPackKey, descriptionArgs: FormatterArguments, \n buttons: PopupPeerOptions['buttons'] = [], checkboxes: PopupPeerOptions['checkboxes'] = [];\n\n const canUnpin = appPeersManager.canPinMessage(peerId);\n\n const callback = (checked: PopupPeerButtonCallbackCheckboxes, oneSide?: boolean, silent?: boolean) => {\n setTimeout(() => { // * костыль, потому что document.elementFromPoint вернёт popup-peer пока он будет закрываться\n let promise: Promise<any>;\n if(unpin && !mid) {\n if(canUnpin) {\n promise = appMessagesManager.unpinAllMessages(peerId);\n } else {\n promise = appMessagesManager.hidePinnedMessages(peerId);\n }\n } else {\n promise = appMessagesManager.updatePinnedMessage(peerId, mid, unpin, silent, oneSide);\n }\n\n if(onConfirm) {\n promise.then(onConfirm);\n }\n }, 300);\n };\n\n if(unpin) {\n let buttonText: LangPackKey = 'UnpinMessage';\n if(!mid) {\n if(canUnpin) {\n title = 'Popup.Unpin.AllTitle';\n description = 'Chat.UnpinAllMessagesConfirmation';\n descriptionArgs = ['' + (appMessagesManager.pinnedMessages[peerId]?.count || 1)];\n } else {\n title = 'Popup.Unpin.HideTitle';\n description = 'Popup.Unpin.HideDescription';\n buttonText = 'Popup.Unpin.Hide';\n }\n } else {\n title = 'UnpinMessageAlertTitle';\n description = 'Chat.Confirm.Unpin';\n }\n \n buttons.push({\n langKey: buttonText,\n isDanger: true,\n callback\n });\n } else {\n title = 'PinMessageAlertTitle';\n const pinButtonText: LangPackKey = 'PinMessage';\n \n if(peerId.isAnyChat()) {\n buttons.push({\n langKey: pinButtonText,\n callback: (checked) => callback(checked, false, !checked.size)\n });\n\n if(appChatsManager.isBroadcast(peerId.toChatId())) {\n description = 'PinMessageAlertChannel';\n } else {\n description = 'PinMessageAlert';\n \n checkboxes.push({\n text: 'PinNotify',\n checked: true\n });\n }\n } else {\n description = 'PinMessageAlertChat';\n\n if(peerId === rootScope.myId) {\n buttons.push({\n langKey: pinButtonText,\n callback\n });\n } else {\n buttons.push({\n langKey: pinButtonText,\n callback: (checked) => callback(checked, !checked.size)\n });\n\n checkboxes.push({\n text: 'PinAlsoFor',\n textArgs: [new PeerTitle({peerId}).element],\n checked: true\n });\n }\n }\n }\n\n addCancelButton(buttons);\n\n const popup = new PopupPeer('popup-delete-chat', {\n peerId,\n titleLangKey: title,\n descriptionLangKey: description,\n descriptionLangArgs: descriptionArgs,\n buttons,\n checkboxes\n });\n\n popup.show();\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nexport default function isSelectionEmpty(selection = window.getSelection()) {\r\n if(!selection || !selection.rangeCount) {\r\n return true;\r\n }\r\n\r\n const selectionRange = selection.getRangeAt(0);\r\n if(!selectionRange.toString() || !selectionRange.START_TO_END) {\r\n return true;\r\n }\r\n\r\n return false;\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { ReportReason } from \"../../layer\";\nimport appMessagesManager from \"../../lib/appManagers/appMessagesManager\";\nimport appStickersManager from \"../../lib/appManagers/appStickersManager\";\nimport InputField from \"../inputField\";\nimport { toastNew } from \"../toast\";\nimport { wrapSticker } from \"../wrappers\";\nimport PopupPeer from \"./peer\";\n\nexport default class PopupReportMessagesConfirm extends PopupPeer {\n public static STICKER_EMOJI = '👮‍♀️';\n constructor(peerId: PeerId, mids: number[], reason: ReportReason['_'], onConfirm?: () => void) {\n super('popup-report-messages-confirm', {\n noTitle: true, \n descriptionLangKey: 'ReportInfo', \n buttons: [{\n langKey: 'ReportChat',\n callback: () => {\n if(!inputField.isValid()) {\n return;\n }\n\n onConfirm && onConfirm();\n appMessagesManager.reportMessages(peerId, mids, reason, inputField.value).then(bool => {\n if(!bool) return;\n\n toastNew({\n langPackKey: 'ReportSentInfo'\n });\n });\n }\n }], \n body: true\n });\n\n const div = document.createElement('div');\n const doc = appStickersManager.getAnimatedEmojiSticker(PopupReportMessagesConfirm.STICKER_EMOJI);\n const size = 100;\n wrapSticker({\n doc,\n div,\n emoji: PopupReportMessagesConfirm.STICKER_EMOJI,\n width: size,\n height: size,\n loop: false,\n play: true\n }).finally(() => {\n this.show();\n });\n\n this.header.append(div);\n\n const inputField = new InputField({\n label: 'ReportHint',\n maxLength: 512,\n placeholder: 'ReportChatDescription'\n });\n\n inputField.input.addEventListener('input', () => {\n this.buttons[0].element.toggleAttribute('disabled', !inputField.isValid());\n });\n\n this.body.append(inputField.container);\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\nimport whichChild from \"../../helpers/dom/whichChild\";\nimport { ReportReason } from \"../../layer\";\nimport appStickersManager from \"../../lib/appManagers/appStickersManager\";\nimport { LangPackKey } from \"../../lib/langPack\";\nimport Button from \"../button\";\nimport PopupPeer from \"./peer\";\nimport PopupReportMessagesConfirm from \"./reportMessagesConfirm\";\n\nexport default class PopupReportMessages extends PopupPeer {\n constructor(peerId: PeerId, mids: number[], onConfirm?: () => void) {\n super('popup-report-messages', {titleLangKey: 'ChatTitle.ReportMessages', buttons: [], body: true});\n\n mids = mids.slice();\n\n const buttons: [LangPackKey, ReportReason['_']][] = [\n ['ReportChatSpam', 'inputReportReasonSpam'],\n ['ReportChatViolence', 'inputReportReasonViolence'],\n ['ReportChatChild', 'inputReportReasonChildAbuse'],\n ['ReportChatPornography', 'inputReportReasonPornography'],\n ['ReportChatOther', 'inputReportReasonOther'],\n ['ReportChatPersonalDetails', 'inputReportReasonPersonalDetails'],\n ['ReportChatIllegalDrugs', 'inputReportReasonIllegalDrugs']\n ];\n\n const className = 'btn-primary btn-transparent';\n buttons.forEach(b => {\n const button = Button(className, {/* icon: 'edit', */text: b[0]});\n this.body.append(button);\n });\n\n const preloadStickerPromise = appStickersManager.preloadAnimatedEmojiSticker(PopupReportMessagesConfirm.STICKER_EMOJI);\n\n attachClickEvent(this.body, (e) => {\n const target = findUpClassName(e.target, 'btn-primary');\n const reason = buttons[whichChild(target)][1];\n\n preloadStickerPromise.then(() => {\n this.hide();\n\n new PopupReportMessagesConfirm(peerId, mids, reason, onConfirm);\n });\n }, {listenerSetter: this.listenerSetter});\n \n this.body.style.margin = '0 -1rem';\n this.buttonsEl.style.marginTop = '.5rem';\n\n this.show();\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport I18n, { i18n } from \"../../lib/langPack\";\nimport Scrollable from \"../scrollable\";\nimport PopupPeer from \"./peer\";\n\nexport default class PopupSponsored extends PopupPeer {\n constructor() {\n super('popup-sponsored', {\n titleLangKey: 'Chat.Message.Sponsored.What',\n descriptionLangKey: 'Chat.Message.Ad.Text',\n descriptionLangArgs: [i18n('Chat.Message.Sponsored.Link')],\n buttons: [{\n langKey: 'OK',\n isCancel: true\n }, {\n langKey: 'Chat.Message.Ad.ReadMore',\n callback: () => {\n window.open(I18n.format('Chat.Message.Sponsored.Link', true));\n },\n isCancel: true\n }]\n });\n\n const scrollable = new Scrollable(undefined);\n scrollable.onAdditionalScroll = () => {\n scrollable.container.classList.toggle('scrolled-top', !scrollable.scrollTop);\n scrollable.container.classList.toggle('scrolled-bottom', scrollable.isScrolledDown);\n };\n\n this.description.replaceWith(scrollable.container);\n\n scrollable.container.append(this.description);\n scrollable.container.classList.add('scrolled-top');\n\n this.show();\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport type { AppMessagesManager } from \"../../lib/appManagers/appMessagesManager\";\nimport PopupElement from \".\";\nimport { Message } from \"../../layer\";\nimport { generateDelimiter, SettingSection } from \"../sidebarLeft\";\nimport ReactionsElement from \"../chat/reactions\";\nimport { horizontalMenu } from \"../horizontalMenu\";\nimport Scrollable from \"../scrollable\";\nimport ScrollableLoader from \"../../helpers/scrollableLoader\";\nimport appDialogsManager from \"../../lib/appManagers/appDialogsManager\";\nimport replaceContent from \"../../helpers/dom/replaceContent\";\nimport appUsersManager from \"../../lib/appManagers/appUsersManager\";\nimport appReactionsManager from \"../../lib/appManagers/appReactionsManager\";\nimport { wrapSticker } from \"../wrappers\";\nimport ReactionElement from \"../chat/reaction\";\n\nexport default class PopupReactedList extends PopupElement {\n constructor(\n private appMessagesManager: AppMessagesManager, \n private message: Message.message\n ) {\n super('popup-reacted-list', /* [{\n langKey: 'Close',\n isCancel: true\n }] */null, {closable: true, overlayClosable: true, body: true});\n\n this.init();\n }\n\n private async init() {\n const message = this.appMessagesManager.getGroupsFirstMessage(this.message);\n\n const canViewReadParticipants = this.appMessagesManager.canViewMessageReadParticipants(message);\n\n // this.body.append(generateDelimiter());\n\n const reactionsElement = new ReactionsElement();\n const newMessage: Message.message = {\n ...message,\n mid: 0,\n id: 0,\n reactions: {\n _: 'messageReactions',\n results: [],\n\n ...message.reactions,\n\n pFlags: {},\n recent_reactions: []\n }\n };\n\n newMessage.reactions.results = newMessage.reactions.results.map(reactionCount => {\n return {\n ...reactionCount,\n pFlags: {}\n };\n });\n\n reactionsElement.init(newMessage, 'block');\n reactionsElement.render();\n reactionsElement.classList.add('no-stripe');\n reactionsElement.classList.remove('has-no-reactions');\n \n reactionsElement.append(this.btnClose);\n\n this.header.append(reactionsElement);\n\n const tabsContainer = document.createElement('div');\n tabsContainer.classList.add('tabs-container');\n tabsContainer.dataset.animation = 'tabs';\n\n const loaders: Map<HTMLElement, ScrollableLoader> = new Map();\n\n let hasAllReactions = false;\n if(newMessage.reactions.results.length) {\n const reaction = this.createFakeReaction('reactions', newMessage.reactions.results.reduce((acc, r) => acc + r.count, 0));\n\n reactionsElement.prepend(reaction);\n newMessage.reactions.results.unshift(reaction.reactionCount);\n hasAllReactions = true;\n }\n\n let hasReadParticipants = false;\n if(canViewReadParticipants) {\n try {\n const readUserIds = await this.appMessagesManager.getMessageReadParticipants(message.peerId, message.mid);\n if(!readUserIds.length) {\n throw '';\n }\n\n const reaction = this.createFakeReaction('checks', readUserIds.length);\n\n reactionsElement.prepend(reaction);\n newMessage.reactions.results.unshift(reaction.reactionCount);\n hasReadParticipants = true;\n } catch(err) {\n\n }\n }\n \n newMessage.reactions.results.forEach(reactionCount => {\n const scrollable = new Scrollable(undefined);\n scrollable.container.classList.add('tabs-tab');\n\n const section = new SettingSection({\n noShadow: true,\n noDelimiter: true\n });\n\n const chatlist = appDialogsManager.createChatList({\n dialogSize: 72\n });\n\n appDialogsManager.setListClickListener(chatlist, () => {\n this.hide();\n }, undefined, false, true);\n\n section.content.append(chatlist);\n scrollable.container.append(section.container);\n\n const skipReadParticipants = reactionCount.reaction !== 'checks';\n const skipReactionsList = reactionCount.reaction === 'checks';\n if(['checks', 'reactions'].includes(reactionCount.reaction)) {\n reactionCount.reaction = undefined;\n }\n\n let nextOffset: string;\n const loader = new ScrollableLoader({\n scrollable,\n getPromise: async() => {\n const result = await this.appMessagesManager.getMessageReactionsListAndReadParticipants(message, undefined, reactionCount.reaction, nextOffset, skipReadParticipants, skipReactionsList);\n nextOffset = result.nextOffset;\n\n result.combined.forEach(({peerId, reaction}) => {\n const {dom} = appDialogsManager.addDialogNew({\n dialog: peerId,\n autonomous: true,\n container: chatlist,\n avatarSize: 54,\n rippleEnabled: false,\n meAsSaved: false,\n drawStatus: false\n });\n\n if(reaction) {\n const stickerContainer = document.createElement('div');\n stickerContainer.classList.add('reacted-list-reaction-icon');\n const availableReaction = appReactionsManager.getReactionCached(reaction);\n\n wrapSticker({\n doc: availableReaction.static_icon,\n div: stickerContainer,\n width: 24,\n height: 24\n });\n \n dom.listEl.append(stickerContainer);\n }\n\n replaceContent(dom.lastMessageSpan, appUsersManager.getUserStatusString(peerId.toUserId()));\n });\n\n return !nextOffset;\n }\n });\n\n loaders.set(scrollable.container, loader);\n\n tabsContainer.append(scrollable.container);\n });\n\n this.body.append(tabsContainer);\n\n const selectTab = horizontalMenu(reactionsElement, tabsContainer, (id, tabContent) => {\n if(id === (reactionsElement.childElementCount - 1)) {\n return false;\n }\n\n const reaction = reactionsElement.children[id] as ReactionElement;\n const prevId = selectTab.prevId();\n if(prevId !== -1) {\n (reactionsElement.children[prevId] as ReactionElement).setIsChosen(false);\n }\n \n reaction.setIsChosen(true);\n\n const loader = loaders.get(tabContent);\n loader.load();\n });\n\n // selectTab(hasAllReactions && hasReadParticipants ? 1 : 0, false);\n selectTab(0, false);\n\n this.show();\n }\n\n private createFakeReaction(icon: string, count: number) {\n const reaction = new ReactionElement();\n reaction.init('block');\n reaction.reactionCount = {\n _: 'reactionCount',\n count: count,\n reaction: icon\n };\n reaction.setCanRenderAvatars(false);\n reaction.renderCounter();\n\n const allReactionsSticker = document.createElement('div');\n allReactionsSticker.classList.add('reaction-counter', 'reaction-sticker-icon', 'tgico-' + icon);\n reaction.prepend(allReactionsSticker);\n\n return reaction;\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { IS_TOUCH_SUPPORTED } from \"../../environment/touchSupport\";\nimport { IS_MOBILE, IS_SAFARI } from \"../../environment/userAgent\";\nimport assumeType from \"../../helpers/assumeType\";\nimport callbackify from \"../../helpers/callbackify\";\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\nimport getVisibleRect from \"../../helpers/dom/getVisibleRect\";\nimport { getMiddleware } from \"../../helpers/middleware\";\nimport noop from \"../../helpers/noop\";\nimport { fastRaf } from \"../../helpers/schedulers\";\nimport { Message, AvailableReaction } from \"../../layer\";\nimport type { AppReactionsManager } from \"../../lib/appManagers/appReactionsManager\";\nimport lottieLoader from \"../../lib/rlottie/lottieLoader\";\nimport RLottiePlayer from \"../../lib/rlottie/rlottiePlayer\";\nimport rootScope from \"../../lib/rootScope\";\nimport animationIntersector from \"../animationIntersector\";\nimport Scrollable, { ScrollableBase, ScrollableX } from \"../scrollable\";\nimport { wrapSticker } from \"../wrappers\";\n\nconst REACTIONS_CLASS_NAME = 'btn-menu-reactions';\nconst REACTION_CLASS_NAME = REACTIONS_CLASS_NAME + '-reaction';\n\nconst REACTION_SIZE = 28;\nconst PADDING = 4;\nconst REACTION_CONTAINER_SIZE = REACTION_SIZE + PADDING * 2;\n\nconst CAN_USE_TRANSFORM = !IS_SAFARI;\n\ntype ChatReactionsMenuPlayers = {\n select?: RLottiePlayer,\n appear?: RLottiePlayer,\n selectWrapper: HTMLElement,\n appearWrapper: HTMLElement,\n reaction: string\n};\nexport class ChatReactionsMenu {\n public widthContainer: HTMLElement;\n private container: HTMLElement;\n private reactionsMap: Map<HTMLElement, ChatReactionsMenuPlayers>;\n private scrollable: ScrollableBase;\n private animationGroup: string;\n private middleware: ReturnType<typeof getMiddleware>;\n private message: Message.message;\n\n constructor(\n private appReactionsManager: AppReactionsManager,\n private type: 'horizontal' | 'vertical',\n middleware: ChatReactionsMenu['middleware']\n ) {\n const widthContainer = this.widthContainer = document.createElement('div');\n widthContainer.classList.add(REACTIONS_CLASS_NAME + '-container');\n widthContainer.classList.add(REACTIONS_CLASS_NAME + '-container-' + type);\n\n const reactionsContainer = this.container = document.createElement('div');\n reactionsContainer.classList.add(REACTIONS_CLASS_NAME);\n\n const reactionsScrollable = this.scrollable = type === 'vertical' ? new Scrollable(undefined) : new ScrollableX(undefined);\n reactionsContainer.append(reactionsScrollable.container);\n reactionsScrollable.onAdditionalScroll = this.onScroll;\n reactionsScrollable.setListeners();\n\n reactionsScrollable.container.classList.add('no-scrollbar');\n\n ['big'].forEach(type => {\n const bubble = document.createElement('div');\n bubble.classList.add(REACTIONS_CLASS_NAME + '-bubble', REACTIONS_CLASS_NAME + '-bubble-' + type);\n reactionsContainer.append(bubble);\n });\n\n this.reactionsMap = new Map();\n this.animationGroup = 'CHAT-MENU-REACTIONS-' + Date.now();\n animationIntersector.setOverrideIdleGroup(this.animationGroup, true);\n\n if(!IS_TOUCH_SUPPORTED) {\n reactionsContainer.addEventListener('mousemove', this.onMouseMove);\n }\n\n attachClickEvent(reactionsContainer, (e) => {\n const reactionDiv = findUpClassName(e.target, REACTION_CLASS_NAME);\n if(!reactionDiv) return;\n\n const players = this.reactionsMap.get(reactionDiv);\n if(!players) return;\n\n this.appReactionsManager.sendReaction(this.message, players.reaction);\n });\n\n widthContainer.append(reactionsContainer);\n\n this.middleware = middleware ?? getMiddleware();\n }\n\n public init(message: Message.message) {\n this.message = message;\n\n const middleware = this.middleware.get();\n // const result = Promise.resolve(this.appReactionsManager.getAvailableReactionsForPeer(message.peerId)).then((res) => pause(1000).then(() => res));\n const result = this.appReactionsManager.getAvailableReactionsByMessage(message);\n callbackify(result, (reactions) => {\n if(!middleware() || !reactions.length) return;\n reactions.forEach(reaction => {\n this.renderReaction(reaction);\n });\n\n const setVisible = () => {\n this.container.classList.add('is-visible');\n };\n\n if(result instanceof Promise) {\n fastRaf(setVisible);\n } else {\n setVisible();\n }\n });\n }\n\n public cleanup() {\n this.middleware.clean();\n this.scrollable.removeListeners();\n this.reactionsMap.clear();\n animationIntersector.setOverrideIdleGroup(this.animationGroup, false);\n animationIntersector.checkAnimations(true, this.animationGroup, true);\n }\n\n private onScroll = () => {\n this.reactionsMap.forEach((players, div) => {\n this.onScrollProcessItem(div, players);\n });\n };\n\n private canUseAnimations() {\n return rootScope.settings.animationsEnabled && !IS_MOBILE;\n }\n\n private renderReaction(reaction: AvailableReaction) {\n const reactionDiv = document.createElement('div');\n reactionDiv.classList.add(REACTION_CLASS_NAME);\n\n const scaleContainer = document.createElement('div');\n scaleContainer.classList.add(REACTION_CLASS_NAME + '-scale');\n\n const appearWrapper = document.createElement('div');\n let selectWrapper: HTMLElement;;\n appearWrapper.classList.add(REACTION_CLASS_NAME + '-appear');\n\n if(this.canUseAnimations()) {\n selectWrapper = document.createElement('div');\n selectWrapper.classList.add(REACTION_CLASS_NAME + '-select', 'hide');\n }\n\n const players: ChatReactionsMenuPlayers = {\n selectWrapper,\n appearWrapper,\n reaction: reaction.reaction\n };\n this.reactionsMap.set(reactionDiv, players);\n\n const middleware = this.middleware.get();\n\n const hoverScale = IS_TOUCH_SUPPORTED ? 1 : 1.25;\n const size = REACTION_SIZE * hoverScale;\n\n const options = {\n width: size,\n height: size,\n skipRatio: 1,\n needFadeIn: false,\n withThumb: false,\n group: this.animationGroup,\n middleware\n };\n\n if(!this.canUseAnimations()) {\n delete options.needFadeIn;\n delete options.withThumb;\n\n wrapSticker({\n doc: reaction.static_icon,\n div: appearWrapper,\n ...options\n });\n } else {\n let isFirst = true;\n wrapSticker({\n doc: reaction.appear_animation,\n div: appearWrapper,\n play: true,\n ...options\n }).then(player => {\n assumeType<RLottiePlayer>(player);\n \n players.appear = player;\n \n player.addEventListener('enterFrame', (frameNo) => {\n if(player.maxFrame === frameNo) {\n selectLoadPromise.then((selectPlayer) => {\n assumeType<RLottiePlayer>(selectPlayer);\n appearWrapper.classList.add('hide');\n selectWrapper.classList.remove('hide');\n \n if(isFirst) {\n players.select = selectPlayer;\n isFirst = false;\n }\n }, noop);\n }\n });\n }, noop);\n \n const selectLoadPromise = wrapSticker({\n doc: reaction.select_animation,\n div: selectWrapper,\n ...options\n }).then(player => {\n assumeType<RLottiePlayer>(player);\n\n return lottieLoader.waitForFirstFrame(player);\n }).catch(noop);\n }\n \n scaleContainer.append(appearWrapper);\n selectWrapper && scaleContainer.append(selectWrapper);\n reactionDiv.append(scaleContainer);\n this.scrollable.append(reactionDiv);\n }\n\n private onScrollProcessItem(div: HTMLElement, players: ChatReactionsMenuPlayers) {\n // return;\n\n const scaleContainer = div.firstElementChild as HTMLElement;\n const visibleRect = getVisibleRect(div, this.scrollable.container);\n let transform: string;\n if(!visibleRect) {\n if(!players.appearWrapper.classList.contains('hide') || !players.appear) {\n return;\n }\n\n if(players.select) {\n players.select.stop();\n }\n\n players.appear.stop();\n players.appear.autoplay = true;\n players.appearWrapper.classList.remove('hide');\n players.selectWrapper.classList.add('hide');\n\n transform = '';\n } else if(visibleRect.overflow.left || visibleRect.overflow.right) {\n const diff = Math.abs(visibleRect.rect.left - visibleRect.rect.right);\n const scale = Math.min(diff ** 2 / REACTION_CONTAINER_SIZE ** 2, 1);\n\n transform = 'scale(' + scale + ')';\n } else {\n transform = '';\n }\n\n if(CAN_USE_TRANSFORM) {\n scaleContainer.style.transform = transform;\n }\n }\n\n private onMouseMove = (e: MouseEvent) => {\n const reactionDiv = findUpClassName(e.target, REACTION_CLASS_NAME);\n if(!reactionDiv) {\n return;\n }\n \n const players = this.reactionsMap.get(reactionDiv);\n if(!players) {\n return;\n }\n\n // do not play select animation when appearing\n if(!players.appear?.paused) {\n return;\n }\n\n const player = players.select;\n if(!player) {\n return;\n }\n\n if(player.paused) {\n player.autoplay = true;\n player.restart();\n }\n };\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport type { AppMessagesManager } from \"../../lib/appManagers/appMessagesManager\";\r\nimport type { AppPeersManager } from \"../../lib/appManagers/appPeersManager\";\r\nimport type { AppPollsManager } from \"../../lib/appManagers/appPollsManager\";\r\nimport type { AppDocsManager, MyDocument } from \"../../lib/appManagers/appDocsManager\";\r\nimport type { AppMessagesIdsManager } from \"../../lib/appManagers/appMessagesIdsManager\";\r\nimport type { AppReactionsManager } from \"../../lib/appManagers/appReactionsManager\";\r\nimport type Chat from \"./chat\";\r\nimport { IS_TOUCH_SUPPORTED } from \"../../environment/touchSupport\";\r\nimport ButtonMenu, { ButtonMenuItemOptions } from \"../buttonMenu\";\r\nimport { attachContextMenuListener, MenuPositionPadding, openBtnMenu, positionMenu } from \"../misc\";\r\nimport PopupDeleteMessages from \"../popups/deleteMessages\";\r\nimport PopupForward from \"../popups/forward\";\r\nimport PopupPinMessage from \"../popups/unpinMessage\";\r\nimport { copyTextToClipboard } from \"../../helpers/clipboard\";\r\nimport PopupSendNow from \"../popups/sendNow\";\r\nimport { toast } from \"../toast\";\r\nimport I18n, { i18n, LangPackKey } from \"../../lib/langPack\";\r\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\r\nimport cancelEvent from \"../../helpers/dom/cancelEvent\";\r\nimport { attachClickEvent, simulateClickEvent } from \"../../helpers/dom/clickEvent\";\r\nimport isSelectionEmpty from \"../../helpers/dom/isSelectionEmpty\";\r\nimport { Message, Poll, Chat as MTChat, MessageMedia, AvailableReaction } from \"../../layer\";\r\nimport PopupReportMessages from \"../popups/reportMessages\";\r\nimport assumeType from \"../../helpers/assumeType\";\r\nimport PopupSponsored from \"../popups/sponsored\";\r\nimport ListenerSetter from \"../../helpers/listenerSetter\";\r\nimport { getMiddleware } from \"../../helpers/middleware\";\r\nimport PeerTitle from \"../peerTitle\";\r\nimport StackedAvatars from \"../stackedAvatars\";\r\nimport { IS_APPLE } from \"../../environment/userAgent\";\r\nimport PopupReactedList from \"../popups/reactedList\";\r\nimport { ChatReactionsMenu } from \"./reactionsMenu\";\r\n\r\nexport default class ChatContextMenu {\r\n private buttons: (ButtonMenuItemOptions & {verify: () => boolean, notDirect?: () => boolean, withSelection?: true, isSponsored?: true})[];\r\n private element: HTMLElement;\r\n\r\n private isSelectable: boolean;\r\n private isSelected: boolean;\r\n private target: HTMLElement;\r\n private isTargetAGroupedItem: boolean;\r\n private isTextSelected: boolean;\r\n private isAnchorTarget: boolean;\r\n private isUsernameTarget: boolean;\r\n private isSponsored: boolean;\r\n private isOverBubble: boolean;\r\n private peerId: PeerId;\r\n private mid: number;\r\n private message: Message.message | Message.messageService;\r\n private noForwards: boolean;\r\n\r\n private reactionsMenu: ChatReactionsMenu;\r\n private listenerSetter: ListenerSetter;\r\n\r\n private viewerPeerId: PeerId;\r\n private middleware: ReturnType<typeof getMiddleware>;\r\n private canOpenReactedList: boolean;\r\n\r\n constructor(\r\n private attachTo: HTMLElement, \r\n private chat: Chat, \r\n private appMessagesManager: AppMessagesManager, \r\n private appPeersManager: AppPeersManager, \r\n private appPollsManager: AppPollsManager,\r\n private appDocsManager: AppDocsManager,\r\n private appMessagesIdsManager: AppMessagesIdsManager,\r\n private appReactionsManager: AppReactionsManager\r\n ) {\r\n this.listenerSetter = new ListenerSetter();\r\n this.middleware = getMiddleware();\r\n\r\n if(IS_TOUCH_SUPPORTED/* && false */) {\r\n attachClickEvent(attachTo, (e) => {\r\n if(chat.selection.isSelecting) {\r\n return;\r\n }\r\n\r\n chat.log('touchend', e);\r\n\r\n const badSelectors = [\r\n '.name',\r\n '.peer-title',\r\n '.reply',\r\n '.document',\r\n 'audio-element',\r\n 'avatar-element',\r\n 'a',\r\n '.bubble-beside-button',\r\n 'replies-element',\r\n '[data-saved-from]:not(.bubble)',\r\n 'poll-element',\r\n 'attachment'\r\n ];\r\n let good = !(e.target as HTMLElement).closest(badSelectors.join(', '));\r\n if(good) {\r\n cancelEvent(e);\r\n //onContextMenu((e as TouchEvent).changedTouches[0]);\r\n // onContextMenu((e as TouchEvent).changedTouches ? (e as TouchEvent).changedTouches[0] : e as MouseEvent);\r\n this.onContextMenu(e);\r\n }\r\n }, {listenerSetter: this.chat.bubbles.listenerSetter});\r\n } else attachContextMenuListener(attachTo, this.onContextMenu, this.chat.bubbles.listenerSetter);\r\n }\r\n\r\n private onContextMenu = (e: MouseEvent | Touch | TouchEvent) => {\r\n let bubble: HTMLElement, contentWrapper: HTMLElement;\r\n\r\n try {\r\n contentWrapper = findUpClassName(e.target, 'bubble-content-wrapper');\r\n bubble = contentWrapper ? contentWrapper.parentElement : findUpClassName(e.target, 'bubble');\r\n } catch(e) {}\r\n\r\n // ! context menu click by date bubble (there is no pointer-events)\r\n if(!bubble || bubble.classList.contains('bubble-first')) return;\r\n\r\n let element = this.element;\r\n if(e instanceof MouseEvent || e.hasOwnProperty('preventDefault')) (e as any).preventDefault();\r\n if(element && element.classList.contains('active')) {\r\n return false;\r\n }\r\n if(e instanceof MouseEvent || e.hasOwnProperty('cancelBubble')) (e as any).cancelBubble = true;\r\n\r\n let mid = +bubble.dataset.mid;\r\n if(!mid) return;\r\n\r\n const isSponsored = this.isSponsored = mid < 0;\r\n this.isSelectable = this.chat.selection.canSelectBubble(bubble);\r\n this.peerId = this.chat.peerId;\r\n //this.msgID = msgID;\r\n this.target = e.target as HTMLElement;\r\n this.isTextSelected = !isSelectionEmpty();\r\n this.isAnchorTarget = this.target.tagName === 'A' && (\r\n (this.target as HTMLAnchorElement).target === '_blank' || \r\n this.target.classList.contains('anchor-url')\r\n );\r\n this.isUsernameTarget = this.target.tagName === 'A' && this.target.classList.contains('mention');\r\n\r\n // * если открыть контекстное меню для альбома не по бабблу, и последний элемент не выбран, чтобы показать остальные пункты\r\n if(this.chat.selection.isSelecting && !contentWrapper) {\r\n if(isSponsored) {\r\n return;\r\n }\r\n\r\n const mids = this.chat.getMidsByMid(mid);\r\n if(mids.length > 1) {\r\n const selectedMid = this.chat.selection.isMidSelected(this.peerId, mid) ? \r\n mid : \r\n mids.find(mid => this.chat.selection.isMidSelected(this.peerId, mid));\r\n if(selectedMid) {\r\n mid = selectedMid;\r\n }\r\n }\r\n }\r\n\r\n this.isOverBubble = !!contentWrapper;\r\n\r\n const groupedItem = findUpClassName(this.target, 'grouped-item');\r\n this.isTargetAGroupedItem = !!groupedItem;\r\n if(groupedItem) {\r\n this.mid = +groupedItem.dataset.mid;\r\n } else {\r\n this.mid = mid;\r\n }\r\n\r\n this.isSelected = this.chat.selection.isMidSelected(this.peerId, this.mid);\r\n this.message = this.chat.getMessage(this.mid);\r\n this.noForwards = !isSponsored && !this.appMessagesManager.canForward(this.message);\r\n this.viewerPeerId = undefined;\r\n this.canOpenReactedList = undefined;\r\n\r\n const initResult = this.init();\r\n element = initResult.element;\r\n const {cleanup, destroy, menuPadding} = initResult;\r\n\r\n const side: 'left' | 'right' = bubble.classList.contains('is-in') ? 'left' : 'right';\r\n //bubble.parentElement.append(element);\r\n //appImManager.log('contextmenu', e, bubble, side);\r\n positionMenu((e as TouchEvent).touches ? (e as TouchEvent).touches[0] : e as MouseEvent, element, side, menuPadding);\r\n openBtnMenu(element, () => {\r\n this.mid = 0;\r\n this.peerId = undefined;\r\n this.target = null;\r\n this.viewerPeerId = undefined;\r\n this.canOpenReactedList = undefined;\r\n cleanup();\r\n\r\n setTimeout(() => {\r\n destroy();\r\n }, 300);\r\n });\r\n };\r\n\r\n public cleanup() {\r\n this.listenerSetter.removeAll();\r\n this.reactionsMenu && this.reactionsMenu.cleanup();\r\n this.middleware.clean();\r\n }\r\n\r\n public destroy() {\r\n this.cleanup();\r\n }\r\n\r\n private filterButtons(buttons: ChatContextMenu['buttons']) {\r\n if(this.isSponsored) {\r\n return buttons.filter(button => {\r\n return button.isSponsored;\r\n });\r\n } else {\r\n return buttons.filter(button => {\r\n let good: boolean;\r\n\r\n //if((appImManager.chatSelection.isSelecting && !button.withSelection) || (button.withSelection && !appImManager.chatSelection.isSelecting)) {\r\n if(this.chat.selection.isSelecting && !button.withSelection) {\r\n good = false;\r\n } else {\r\n good = this.isOverBubble || IS_TOUCH_SUPPORTED || true ? \r\n button.verify() : \r\n button.notDirect && button.verify() && button.notDirect();\r\n }\r\n\r\n return good;\r\n });\r\n }\r\n }\r\n\r\n private setButtons() {\r\n this.buttons = [{\r\n icon: 'send2',\r\n text: 'MessageScheduleSend',\r\n onClick: this.onSendScheduledClick,\r\n verify: () => this.chat.type === 'scheduled' && !this.message.pFlags.is_outgoing\r\n }, {\r\n icon: 'send2',\r\n text: 'Message.Context.Selection.SendNow',\r\n onClick: this.onSendScheduledClick,\r\n verify: () => this.chat.type === 'scheduled' && this.isSelected && !this.chat.selection.selectionSendNowBtn.hasAttribute('disabled'),\r\n notDirect: () => true,\r\n withSelection: true\r\n }, {\r\n icon: 'schedule',\r\n text: 'MessageScheduleEditTime',\r\n onClick: () => {\r\n this.chat.input.scheduleSending(() => {\r\n assumeType<Message.message>(this.message);\r\n this.appMessagesManager.editMessage(this.message, this.message.message, {\r\n scheduleDate: this.chat.input.scheduleDate,\r\n entities: this.message.entities\r\n });\r\n\r\n this.chat.input.onMessageSent(false, false);\r\n }, new Date(this.message.date * 1000));\r\n },\r\n verify: () => this.chat.type === 'scheduled'\r\n }, {\r\n icon: 'reply',\r\n text: 'Reply',\r\n onClick: this.onReplyClick,\r\n verify: () => this.chat.canSend() && \r\n !this.message.pFlags.is_outgoing && \r\n !!this.chat.input.messageInput && \r\n this.chat.type !== 'scheduled'/* ,\r\n cancelEvent: true */\r\n }, {\r\n icon: 'edit',\r\n text: 'Edit',\r\n onClick: this.onEditClick,\r\n verify: () => this.appMessagesManager.canEditMessage(this.message, 'text') && !!this.chat.input.messageInput\r\n }, {\r\n icon: 'copy',\r\n text: 'Copy',\r\n onClick: this.onCopyClick,\r\n verify: () => !this.noForwards && !!(this.message as Message.message).message && !this.isTextSelected && (!this.isAnchorTarget || (this.message as Message.message).message !== this.target.innerText)\r\n }, {\r\n icon: 'copy',\r\n text: 'Chat.CopySelectedText',\r\n onClick: this.onCopyClick,\r\n verify: () => !this.noForwards && !!(this.message as Message.message).message && this.isTextSelected\r\n }, {\r\n icon: 'copy',\r\n text: 'Message.Context.Selection.Copy',\r\n onClick: this.onCopyClick,\r\n verify: () => {\r\n if(!this.isSelected || this.noForwards) {\r\n return false;\r\n }\r\n\r\n for(const [peerId, mids] of this.chat.selection.selectedMids) {\r\n for(const mid of mids) {\r\n if(!!this.appMessagesManager.getMessageByPeer(peerId, mid).message) {\r\n return true;\r\n }\r\n }\r\n }\r\n\r\n return false;\r\n },\r\n notDirect: () => true,\r\n withSelection: true\r\n }, {\r\n icon: 'copy',\r\n text: 'CopyLink',\r\n onClick: this.onCopyAnchorLinkClick,\r\n verify: () => this.isAnchorTarget,\r\n withSelection: true\r\n }, {\r\n icon: 'copy',\r\n text: 'Text.Context.Copy.Username',\r\n onClick: () => {\r\n copyTextToClipboard(this.target.innerHTML);\r\n },\r\n verify: () => this.isUsernameTarget,\r\n withSelection: true\r\n }, {\r\n icon: 'copy',\r\n text: 'Text.Context.Copy.Hashtag',\r\n onClick: () => {\r\n copyTextToClipboard(this.target.innerHTML);\r\n },\r\n verify: () => this.target.classList.contains('anchor-hashtag'),\r\n withSelection: true\r\n }, {\r\n icon: 'link',\r\n text: 'MessageContext.CopyMessageLink1',\r\n onClick: this.onCopyLinkClick,\r\n verify: () => this.appPeersManager.isChannel(this.peerId) && !this.message.pFlags.is_outgoing\r\n }, {\r\n icon: 'pin',\r\n text: 'Message.Context.Pin',\r\n onClick: this.onPinClick,\r\n verify: () => !this.message.pFlags.is_outgoing && \r\n this.message._ !== 'messageService' && \r\n !this.message.pFlags.pinned && \r\n this.appPeersManager.canPinMessage(this.peerId) && \r\n this.chat.type !== 'scheduled',\r\n }, {\r\n icon: 'unpin',\r\n text: 'Message.Context.Unpin',\r\n onClick: this.onUnpinClick,\r\n verify: () => (this.message as Message.message).pFlags.pinned && this.appPeersManager.canPinMessage(this.peerId),\r\n }, {\r\n icon: 'download',\r\n text: 'MediaViewer.Context.Download',\r\n onClick: () => {\r\n this.appDocsManager.saveDocFile((this.message as any).media.document);\r\n },\r\n verify: () => {\r\n if(this.message.pFlags.is_outgoing) {\r\n return false;\r\n }\r\n \r\n const doc: MyDocument = ((this.message as Message.message).media as MessageMedia.messageMediaDocument)?.document as any;\r\n if(!doc) return false;\r\n \r\n let hasTarget = !!IS_TOUCH_SUPPORTED;\r\n const isGoodType = !doc.type || !(['gif', 'video', 'sticker'] as MyDocument['type'][]).includes(doc.type);\r\n if(isGoodType) hasTarget = hasTarget || !!findUpClassName(this.target, 'document') || !!findUpClassName(this.target, 'audio');\r\n return isGoodType && hasTarget;\r\n }\r\n }, {\r\n icon: 'checkretract',\r\n text: 'Chat.Poll.Unvote',\r\n onClick: this.onRetractVote,\r\n verify: () => {\r\n const poll = (this.message as any).media?.poll as Poll;\r\n return poll && poll.chosenIndexes.length && !poll.pFlags.closed && !poll.pFlags.quiz;\r\n }/* ,\r\n cancelEvent: true */\r\n }, {\r\n icon: 'stop',\r\n text: 'Chat.Poll.Stop',\r\n onClick: this.onStopPoll,\r\n verify: () => {\r\n const poll = (this.message as any).media?.poll;\r\n return this.appMessagesManager.canEditMessage(this.message, 'poll') && poll && !poll.pFlags.closed && !this.message.pFlags.is_outgoing;\r\n }/* ,\r\n cancelEvent: true */\r\n }, {\r\n icon: 'forward',\r\n text: 'Forward',\r\n onClick: this.onForwardClick, // let forward the message if it's outgoing but not ours (like a changelog)\r\n verify: () => !this.noForwards && this.chat.type !== 'scheduled' && (!this.message.pFlags.is_outgoing || !this.message.pFlags.out) && this.message._ !== 'messageService'\r\n }, {\r\n icon: 'forward',\r\n text: 'Message.Context.Selection.Forward',\r\n onClick: this.onForwardClick,\r\n verify: () => this.chat.selection.selectionForwardBtn && \r\n this.isSelected && \r\n !this.chat.selection.selectionForwardBtn.hasAttribute('disabled'),\r\n notDirect: () => true,\r\n withSelection: true\r\n }, {\r\n icon: 'flag',\r\n text: 'ReportChat',\r\n onClick: () => {\r\n new PopupReportMessages(this.peerId, [this.mid]);\r\n },\r\n verify: () => !this.message.pFlags.out && this.message._ === 'message' && !this.message.pFlags.is_outgoing && this.appPeersManager.isChannel(this.peerId),\r\n notDirect: () => true,\r\n withSelection: true\r\n }, {\r\n icon: 'select',\r\n text: 'Message.Context.Select',\r\n onClick: this.onSelectClick,\r\n verify: () => !(this.message as Message.messageService).action && !this.isSelected && this.isSelectable,\r\n notDirect: () => true,\r\n withSelection: true\r\n }, {\r\n icon: 'select',\r\n text: 'Message.Context.Selection.Clear',\r\n onClick: this.onClearSelectionClick,\r\n verify: () => this.isSelected,\r\n notDirect: () => true,\r\n withSelection: true\r\n }, {\r\n onClick: () => {\r\n if(this.viewerPeerId) {\r\n this.chat.appImManager.setInnerPeer({\r\n peerId: this.viewerPeerId\r\n });\r\n } else if(this.canOpenReactedList) {\r\n new PopupReactedList(this.appMessagesManager, this.message as Message.message);\r\n } else {\r\n return false;\r\n }\r\n },\r\n verify: () => !this.peerId.isUser() && (!!(this.message as Message.message).reactions?.recent_reactions?.length || this.appMessagesManager.canViewMessageReadParticipants(this.message)),\r\n notDirect: () => true\r\n }, {\r\n icon: 'delete danger',\r\n text: 'Delete',\r\n onClick: this.onDeleteClick,\r\n verify: () => this.appMessagesManager.canDeleteMessage(this.message)\r\n }, {\r\n icon: 'delete danger',\r\n text: 'Message.Context.Selection.Delete',\r\n onClick: this.onDeleteClick,\r\n verify: () => this.isSelected && !this.chat.selection.selectionDeleteBtn.hasAttribute('disabled'),\r\n notDirect: () => true,\r\n withSelection: true\r\n }, {\r\n icon: 'info',\r\n text: 'Chat.Message.Sponsored.What',\r\n onClick: () => {\r\n new PopupSponsored();\r\n },\r\n verify: () => false,\r\n isSponsored: true\r\n }];\r\n }\r\n\r\n private init() {\r\n this.cleanup();\r\n this.setButtons();\r\n \r\n const filteredButtons = this.filterButtons(this.buttons);\r\n const element = this.element = ButtonMenu(filteredButtons, this.listenerSetter);\r\n element.id = 'bubble-contextmenu';\r\n element.classList.add('contextmenu');\r\n\r\n const viewsButton = filteredButtons.find(button => !button.icon);\r\n if(viewsButton) {\r\n const reactions = (this.message as Message.message).reactions;\r\n const recentReactions = reactions?.recent_reactions;\r\n const isViewingReactions = !!recentReactions?.length;\r\n const participantsCount = this.appMessagesManager.canViewMessageReadParticipants(this.message) ? (this.appPeersManager.getPeer(this.peerId) as MTChat.chat).participants_count : undefined;\r\n const reactedLength = reactions ? reactions.results.reduce((acc, r) => acc + r.count, 0) : undefined;\r\n\r\n viewsButton.element.classList.add('tgico-' + (isViewingReactions ? 'reactions' : 'checks'));\r\n const i18nElem = new I18n.IntlElement({\r\n key: isViewingReactions ? (\r\n participantsCount === undefined ? 'Chat.Context.ReactedFast' : 'Chat.Context.Reacted'\r\n ) : 'NobodyViewed',\r\n args: isViewingReactions ? (\r\n participantsCount === undefined ? [reactedLength] : [participantsCount, participantsCount]\r\n ) : undefined,\r\n element: viewsButton.textElement\r\n });\r\n\r\n let fakeText: HTMLElement;\r\n if(isViewingReactions) {\r\n if(participantsCount === undefined) {\r\n fakeText = i18n('Chat.Context.ReactedFast', [reactedLength]);\r\n } else {\r\n fakeText = i18n(\r\n recentReactions.length === participantsCount ? 'Chat.Context.ReactedFast' : 'Chat.Context.Reacted', \r\n [recentReactions.length, participantsCount]\r\n );\r\n }\r\n } else {\r\n fakeText = i18n('Loading');\r\n }\r\n\r\n fakeText.classList.add('btn-menu-item-text-fake');\r\n viewsButton.element.append(fakeText);\r\n\r\n const MAX_AVATARS = 3;\r\n const PADDING_PER_AVATAR = .875;\r\n i18nElem.element.style.visibility = 'hidden';\r\n i18nElem.element.style.paddingRight = isViewingReactions ? PADDING_PER_AVATAR * Math.min(MAX_AVATARS, recentReactions.length) + 'rem' : '1rem';\r\n const middleware = this.middleware.get();\r\n this.appMessagesManager.getMessageReactionsListAndReadParticipants(this.message as Message.message).then((result) => {\r\n if(!middleware()) {\r\n return;\r\n }\r\n\r\n if(fakeText) {\r\n fakeText.remove();\r\n }\r\n\r\n const reactions = result.combined;\r\n const reactedLength = participantsCount === undefined ? \r\n result.reactionsCount : \r\n (\r\n isViewingReactions ? \r\n reactions.filter(reaction => reaction.reaction).length : \r\n reactions.length\r\n );\r\n\r\n let fakeElem: HTMLElement;\r\n if(reactions.length === 1) {\r\n fakeElem = new PeerTitle({\r\n peerId: reactions[0].peerId,\r\n onlyFirstName: true,\r\n dialog: false,\r\n }).element;\r\n\r\n if(!isViewingReactions || result.readParticipants.length <= 1) {\r\n this.viewerPeerId = reactions[0].peerId;\r\n }\r\n } else if(isViewingReactions) {\r\n const isFull = reactedLength === reactions.length || participantsCount === undefined;\r\n fakeElem = i18n(\r\n isFull ? 'Chat.Context.ReactedFast' : 'Chat.Context.Reacted', \r\n isFull ? [reactedLength] : [reactedLength, reactions.length]\r\n );\r\n } else {\r\n if(!reactions.length) {\r\n i18nElem.element.style.visibility = '';\r\n } else {\r\n fakeElem = i18n('MessageSeen', [reactions.length]);\r\n }\r\n }\r\n\r\n if(fakeElem) {\r\n fakeElem.style.paddingRight = PADDING_PER_AVATAR * Math.min(MAX_AVATARS, reactedLength) + 'rem';\r\n fakeElem.classList.add('btn-menu-item-text-fake');\r\n viewsButton.element.append(fakeElem);\r\n }\r\n\r\n if(reactions.length) {\r\n const avatars = new StackedAvatars({avatarSize: 24});\r\n avatars.render(recentReactions ? recentReactions.map(r => this.appPeersManager.getPeerId(r.peer_id)) : reactions.map(reaction => reaction.peerId));\r\n viewsButton.element.append(avatars.container);\r\n\r\n // if(reactions.length > 1) {\r\n // if(isViewingReactions) {\r\n this.canOpenReactedList = true;\r\n // }\r\n }\r\n });\r\n }\r\n\r\n let menuPadding: MenuPositionPadding;\r\n let reactionsMenu: ChatReactionsMenu;\r\n if(this.message._ === 'message' && !this.chat.selection.isSelecting && !this.message.pFlags.is_outgoing && !this.message.pFlags.is_scheduled) {\r\n const position: 'horizontal' | 'vertical' = (IS_APPLE || IS_TOUCH_SUPPORTED)/* && false */ ? 'horizontal' : 'vertical';\r\n reactionsMenu = this.reactionsMenu = new ChatReactionsMenu(this.appReactionsManager, position, this.middleware);\r\n reactionsMenu.init(this.appMessagesManager.getGroupsFirstMessage(this.message));\r\n element.prepend(reactionsMenu.widthContainer);\r\n\r\n const size = 42;\r\n const margin = 8;\r\n const totalSize = size + margin;\r\n if(position === 'vertical') {\r\n menuPadding = {\r\n top: 24,\r\n // bottom: 36, // positionMenu will detect it itself somehow\r\n left: totalSize\r\n };\r\n } else {\r\n menuPadding = {\r\n top: totalSize,\r\n right: 36,\r\n left: 24\r\n };\r\n }\r\n }\r\n\r\n this.chat.container.append(element);\r\n\r\n return {\r\n element, \r\n cleanup: () => {\r\n this.cleanup();\r\n reactionsMenu && reactionsMenu.cleanup();\r\n },\r\n destroy: () => {\r\n element.remove();\r\n },\r\n menuPadding\r\n };\r\n }\r\n\r\n private onSendScheduledClick = () => {\r\n if(this.chat.selection.isSelecting) {\r\n simulateClickEvent(this.chat.selection.selectionSendNowBtn);\r\n } else {\r\n new PopupSendNow(this.peerId, this.chat.getMidsByMid(this.mid));\r\n }\r\n };\r\n\r\n private onReplyClick = () => {\r\n this.chat.input.initMessageReply(this.mid);\r\n };\r\n\r\n private onEditClick = () => {\r\n this.chat.input.initMessageEditing(this.mid);\r\n };\r\n\r\n private onCopyClick = () => {\r\n if(isSelectionEmpty()) {\r\n const mids = this.chat.selection.isSelecting ? \r\n [...this.chat.selection.selectedMids.get(this.peerId)].sort((a, b) => a - b) : \r\n [this.mid];\r\n\r\n const str = mids.reduce((acc, mid) => {\r\n const message = this.chat.getMessage(mid);\r\n return acc + (message?.message ? message.message + '\\n' : '');\r\n }, '').trim();\r\n\r\n copyTextToClipboard(str);\r\n } else {\r\n document.execCommand('copy');\r\n //cancelSelection();\r\n }\r\n };\r\n\r\n private onCopyAnchorLinkClick = () => {\r\n copyTextToClipboard((this.target as HTMLAnchorElement).href);\r\n };\r\n\r\n private onCopyLinkClick = () => {\r\n let threadMessage: Message.message;\r\n if(this.chat.type === 'discussion') {\r\n threadMessage = this.appMessagesManager.getMessageByPeer(this.peerId, this.chat.threadId);\r\n }\r\n\r\n const username = this.appPeersManager.getPeerUsername(threadMessage ? threadMessage.fromId : this.peerId);\r\n const msgId = this.appMessagesIdsManager.getServerMessageId(this.mid);\r\n let url = 'https://t.me/';\r\n let key: LangPackKey;\r\n if(username) {\r\n url += username + '/' + (threadMessage ? this.appMessagesIdsManager.getServerMessageId(threadMessage.fwd_from.channel_post) : msgId);\r\n if(threadMessage) url += '?comment=' + msgId;\r\n key = 'LinkCopied';\r\n } else {\r\n url += 'c/' + this.peerId.toChatId() + '/' + msgId;\r\n if(threadMessage) url += '?thread=' + this.appMessagesIdsManager.getServerMessageId(threadMessage.mid);\r\n key = 'LinkCopiedPrivateInfo';\r\n }\r\n\r\n toast(I18n.format(key, true));\r\n\r\n copyTextToClipboard(url);\r\n };\r\n\r\n private onPinClick = () => {\r\n new PopupPinMessage(this.peerId, this.mid);\r\n };\r\n\r\n private onUnpinClick = () => {\r\n new PopupPinMessage(this.peerId, this.mid, true);\r\n };\r\n\r\n private onRetractVote = () => {\r\n this.appPollsManager.sendVote(this.message, []);\r\n };\r\n\r\n private onStopPoll = () => {\r\n this.appPollsManager.stopPoll(this.message);\r\n };\r\n\r\n private onForwardClick = () => {\r\n if(this.chat.selection.isSelecting) {\r\n simulateClickEvent(this.chat.selection.selectionForwardBtn);\r\n } else {\r\n const mids = this.isTargetAGroupedItem ? [this.mid] : this.chat.getMidsByMid(this.mid);\r\n new PopupForward({\r\n [this.peerId]: mids\r\n });\r\n }\r\n };\r\n\r\n private onSelectClick = () => {\r\n this.chat.selection.toggleByElement(findUpClassName(this.target, 'grouped-item') || findUpClassName(this.target, 'bubble'));\r\n };\r\n\r\n private onClearSelectionClick = () => {\r\n this.chat.selection.cancelSelection();\r\n };\r\n\r\n private onDeleteClick = () => {\r\n if(this.chat.selection.isSelecting) {\r\n simulateClickEvent(this.chat.selection.selectionDeleteBtn);\r\n } else {\r\n new PopupDeleteMessages(this.peerId, this.isTargetAGroupedItem ? [this.mid] : this.chat.getMidsByMid(this.mid), this.chat.type);\r\n }\r\n };\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport cancelEvent from \"../../helpers/dom/cancelEvent\";\r\nimport ListenerSetter from \"../../helpers/listenerSetter\";\r\nimport rootScope from \"../../lib/rootScope\";\r\nimport ButtonMenu, { ButtonMenuItemOptions } from \"../buttonMenu\";\r\nimport { attachContextMenuListener, openBtnMenu } from \"../misc\";\r\n\r\nexport default class SendMenu {\r\n public sendMenu: HTMLDivElement;\r\n private sendMenuButtons: (ButtonMenuItemOptions & {verify: () => boolean})[];\r\n private type: 'schedule' | 'reminder';\r\n \r\n constructor(options: {\r\n onSilentClick: () => void,\r\n onScheduleClick: () => void,\r\n listenerSetter?: ListenerSetter,\r\n openSide: string,\r\n onContextElement: HTMLElement,\r\n onOpen?: () => boolean\r\n }) {\r\n this.sendMenuButtons = [{\r\n icon: 'mute',\r\n text: 'Chat.Send.WithoutSound',\r\n onClick: options.onSilentClick,\r\n verify: () => this.type === 'schedule'\r\n }, {\r\n icon: 'schedule',\r\n text: 'Chat.Send.ScheduledMessage',\r\n onClick: options.onScheduleClick,\r\n verify: () => this.type === 'schedule'\r\n }, {\r\n icon: 'schedule',\r\n text: 'Chat.Send.SetReminder',\r\n onClick: options.onScheduleClick,\r\n verify: () => this.type === 'reminder'\r\n }];\r\n \r\n this.sendMenu = ButtonMenu(this.sendMenuButtons, options.listenerSetter);\r\n this.sendMenu.classList.add('menu-send', options.openSide);\r\n\r\n attachContextMenuListener(options.onContextElement, (e: any) => {\r\n if(options.onOpen && !options.onOpen()) {\r\n return;\r\n }\r\n\r\n this.sendMenuButtons.forEach(button => {\r\n button.element.classList.toggle('hide', !button.verify());\r\n });\r\n \r\n cancelEvent(e);\r\n openBtnMenu(this.sendMenu);\r\n }, options.listenerSetter);\r\n }\r\n\r\n public setPeerId(peerId: PeerId) {\r\n this.type = peerId === rootScope.myId ? 'reminder' : 'schedule';\r\n }\r\n};\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport type Chat from \"../chat/chat\";\r\nimport PopupElement from \".\";\r\nimport CheckboxField from \"../checkboxField\";\r\nimport InputField from \"../inputField\";\r\nimport RadioField from \"../radioField\";\r\nimport Scrollable from \"../scrollable\";\r\nimport SendContextMenu from \"../chat/sendContextMenu\";\r\nimport I18n, { _i18n } from \"../../lib/langPack\";\r\nimport findUpTag from \"../../helpers/dom/findUpTag\";\r\nimport cancelEvent from \"../../helpers/dom/cancelEvent\";\r\nimport getRichValue from \"../../helpers/dom/getRichValue\";\r\nimport isInputEmpty from \"../../helpers/dom/isInputEmpty\";\r\nimport whichChild from \"../../helpers/dom/whichChild\";\r\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\r\nimport { Poll } from \"../../layer\";\r\n\r\nconst MAX_LENGTH_QUESTION = 255;\r\nconst MAX_LENGTH_OPTION = 100;\r\nconst MAX_LENGTH_SOLUTION = 200;\r\n\r\nexport default class PopupCreatePoll extends PopupElement {\r\n private questionInputField: InputField;\r\n private questions: HTMLElement;\r\n private scrollable: Scrollable;\r\n private tempId = 0;\r\n\r\n private anonymousCheckboxField: CheckboxField;\r\n private multipleCheckboxField: PopupCreatePoll['anonymousCheckboxField'];\r\n private quizCheckboxField: PopupCreatePoll['anonymousCheckboxField'];\r\n\r\n private correctAnswers: Uint8Array[];\r\n private quizSolutionField: InputField;\r\n private optionInputFields: InputField[];\r\n\r\n constructor(private chat: Chat) {\r\n super('popup-create-poll popup-new-media', null, {closable: true, withConfirm: 'Create', body: true});\r\n\r\n _i18n(this.title, 'NewPoll');\r\n\r\n this.questionInputField = new InputField({\r\n placeholder: 'AskAQuestion',\r\n label: 'AskAQuestion', \r\n name: 'question', \r\n maxLength: MAX_LENGTH_QUESTION\r\n });\r\n\r\n this.listenerSetter.add(this.questionInputField.input)('input', () => {\r\n this.handleChange();\r\n });\r\n\r\n this.optionInputFields = [];\r\n\r\n if(this.chat.type !== 'scheduled') {\r\n const sendMenu = new SendContextMenu({\r\n onSilentClick: () => {\r\n this.chat.input.sendSilent = true;\r\n this.send();\r\n },\r\n onScheduleClick: () => {\r\n this.chat.input.scheduleSending(() => {\r\n this.send();\r\n });\r\n },\r\n openSide: 'bottom-left',\r\n onContextElement: this.btnConfirm,\r\n });\r\n \r\n sendMenu.setPeerId(this.chat.peerId);\r\n\r\n this.header.append(sendMenu.sendMenu);\r\n }\r\n\r\n this.header.append(this.questionInputField.container);\r\n\r\n const hr = document.createElement('hr');\r\n const d = document.createElement('div');\r\n d.classList.add('caption');\r\n _i18n(d, 'PollOptions');\r\n\r\n this.questions = document.createElement('form');\r\n this.questions.classList.add('poll-create-questions');\r\n\r\n const dd = document.createElement('div');\r\n dd.classList.add('poll-create-settings');\r\n \r\n const settingsCaption = document.createElement('div');\r\n settingsCaption.classList.add('caption');\r\n _i18n(settingsCaption, 'Settings');\r\n\r\n if(!this.chat.appPeersManager.isBroadcast(this.chat.peerId)) {\r\n this.anonymousCheckboxField = new CheckboxField({\r\n text: 'NewPoll.Anonymous', \r\n name: 'anonymous'\r\n });\r\n this.anonymousCheckboxField.input.checked = true;\r\n dd.append(this.anonymousCheckboxField.label);\r\n }\r\n \r\n this.multipleCheckboxField = new CheckboxField({\r\n text: 'NewPoll.MultipleChoice', \r\n name: 'multiple'\r\n });\r\n this.quizCheckboxField = new CheckboxField({\r\n text: 'NewPoll.Quiz', \r\n name: 'quiz'\r\n });\r\n\r\n this.listenerSetter.add(this.multipleCheckboxField.input)('change', () => {\r\n const checked = this.multipleCheckboxField.input.checked;\r\n this.quizCheckboxField.input.toggleAttribute('disabled', checked);\r\n });\r\n\r\n this.listenerSetter.add(this.quizCheckboxField.input)('change', () => {\r\n const checked = this.quizCheckboxField.input.checked;\r\n\r\n (Array.from(this.questions.children) as HTMLElement[]).map(el => {\r\n el.classList.toggle('radio-field', checked);\r\n });\r\n\r\n if(!checked) {\r\n this.correctAnswers = undefined;\r\n this.quizSolutionField.setValueSilently('');\r\n }\r\n\r\n quizElements.forEach(el => el.classList.toggle('hide', !checked));\r\n\r\n this.multipleCheckboxField.input.toggleAttribute('disabled', checked);\r\n this.handleChange();\r\n });\r\n\r\n dd.append(this.multipleCheckboxField.label, this.quizCheckboxField.label);\r\n\r\n const quizElements: HTMLElement[] = [];\r\n\r\n const quizSolutionCaption = document.createElement('div');\r\n quizSolutionCaption.classList.add('caption');\r\n _i18n(quizSolutionCaption, 'AccDescrQuizExplanation');\r\n\r\n const quizHr = document.createElement('hr');\r\n\r\n const quizSolutionContainer = document.createElement('div');\r\n quizSolutionContainer.classList.add('poll-create-questions');\r\n\r\n this.quizSolutionField = new InputField({\r\n placeholder: 'NewPoll.Explanation.Placeholder', \r\n label: 'NewPoll.Explanation.Placeholder',\r\n name: 'solution',\r\n maxLength: MAX_LENGTH_SOLUTION\r\n });\r\n\r\n this.listenerSetter.add(this.questionInputField.input)('input', () => {\r\n this.handleChange();\r\n });\r\n\r\n const quizSolutionSubtitle = document.createElement('div');\r\n quizSolutionSubtitle.classList.add('subtitle');\r\n _i18n(quizSolutionSubtitle, 'AddAnExplanationInfo');\r\n\r\n quizSolutionContainer.append(this.quizSolutionField.container, quizSolutionSubtitle);\r\n\r\n quizElements.push(quizHr, quizSolutionCaption, quizSolutionContainer);\r\n quizElements.forEach(el => el.classList.add('hide'));\r\n\r\n this.body.parentElement.insertBefore(hr, this.body);\r\n this.body.append(d, this.questions, document.createElement('hr'), settingsCaption, dd, ...quizElements);\r\n\r\n attachClickEvent(this.btnConfirm, this.onSubmitClick, {listenerSetter: this.listenerSetter});\r\n\r\n this.scrollable = new Scrollable(this.body);\r\n this.appendMoreField();\r\n\r\n this.onEscape = () => {\r\n return !this.getFilledAnswers().length;\r\n };\r\n\r\n this.handleChange();\r\n }\r\n\r\n private getFilledAnswers() {\r\n const answers = Array.from(this.questions.children).map((el, idx) => {\r\n const input = el.querySelector('.input-field-input') as HTMLElement;\r\n return input instanceof HTMLInputElement ? input.value : getRichValue(input, false).value;\r\n }).filter(v => !!v.trim());\r\n\r\n return answers;\r\n }\r\n\r\n private onSubmitClick = () => {\r\n this.send();\r\n };\r\n\r\n private validate() {\r\n const question = this.questionInputField.value;\r\n if(!question) {\r\n return false;\r\n }\r\n\r\n if(question.length > MAX_LENGTH_QUESTION) {\r\n return false;\r\n }\r\n\r\n if(this.quizCheckboxField.input.checked && !this.correctAnswers?.length) {\r\n return false;\r\n }\r\n\r\n const answers = this.getFilledAnswers();\r\n if(answers.length < 2) {\r\n return false;\r\n }\r\n \r\n const tooLongOption = answers.find(a => a.length > MAX_LENGTH_OPTION);\r\n if(tooLongOption) {\r\n return false;\r\n }\r\n\r\n const {value: quizSolution} = getRichValue(this.quizSolutionField.input, false);\r\n if(quizSolution.length > MAX_LENGTH_SOLUTION) {\r\n return false;\r\n }\r\n\r\n return true;\r\n }\r\n\r\n private handleChange() {\r\n const valid = this.validate();\r\n this.btnConfirm.toggleAttribute('disabled', !valid);\r\n }\r\n\r\n public send(force = false) {\r\n const question = this.questionInputField.value;\r\n\r\n const answers = this.getFilledAnswers();\r\n\r\n const {value: quizSolution, entities: quizSolutionEntities} = getRichValue(this.quizSolutionField.input);\r\n\r\n if(this.chat.type === 'scheduled' && !force) {\r\n this.chat.input.scheduleSending(() => {\r\n this.send(true);\r\n });\r\n \r\n return;\r\n }\r\n\r\n this.hide();\r\n\r\n //const randomID = [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)];\r\n //const randomIDS = bigint(randomID[0]).shiftLeft(32).add(bigint(randomID[1])).toString();\r\n\r\n const pFlags: Poll['pFlags'] = {};\r\n\r\n if(this.anonymousCheckboxField && !this.anonymousCheckboxField.input.checked) {\r\n pFlags.public_voters = true;\r\n }\r\n\r\n if(this.multipleCheckboxField.input.checked) {\r\n pFlags.multiple_choice = true;\r\n }\r\n\r\n if(this.quizCheckboxField.input.checked) {\r\n pFlags.quiz = true;\r\n }\r\n\r\n const poll: Poll = {\r\n _: 'poll',\r\n pFlags,\r\n question,\r\n answers: answers.map((value, idx) => {\r\n return {\r\n _: 'pollAnswer',\r\n text: value,\r\n option: new Uint8Array([idx])\r\n };\r\n }),\r\n id: undefined\r\n };\r\n //poll.id = randomIDS;\r\n\r\n const inputMediaPoll = this.chat.appPollsManager.getInputMediaPoll(poll, this.correctAnswers, quizSolution, quizSolutionEntities);\r\n\r\n //console.log('Will try to create poll:', inputMediaPoll);\r\n\r\n this.chat.appMessagesManager.sendOther(this.chat.peerId, inputMediaPoll, {\r\n ...this.chat.getMessageSendingParams()\r\n });\r\n\r\n if(this.chat.input.helperType === 'reply') {\r\n this.chat.input.clearHelper();\r\n }\r\n\r\n this.chat.input.onMessageSent(false, false);\r\n }\r\n\r\n onInput = (e: Event) => {\r\n const target = e.target as HTMLInputElement;\r\n\r\n const radioLabel = findUpTag(target, 'LABEL');\r\n const isEmpty = isInputEmpty(target);\r\n if(!isEmpty) {\r\n target.parentElement.classList.add('is-filled');\r\n radioLabel.classList.remove('hidden-widget');\r\n radioLabel.firstElementChild.removeAttribute('disabled');\r\n }\r\n\r\n const isLast = !radioLabel.nextElementSibling;\r\n if(isLast && !isEmpty && this.questions.childElementCount < 10) {\r\n this.appendMoreField();\r\n }\r\n\r\n this.handleChange();\r\n };\r\n\r\n onDeleteClick = (e: MouseEvent) => {\r\n const target = e.target as HTMLSpanElement;\r\n const label = findUpTag(target, 'LABEL');\r\n const idx = whichChild(label);\r\n\r\n if(this.correctAnswers && this.correctAnswers[0][0] === idx) {\r\n this.correctAnswers = undefined;\r\n }\r\n\r\n label.remove();\r\n this.optionInputFields.splice(idx, 1);\r\n\r\n this.optionInputFields.forEach((inputField, idx) => {\r\n inputField.options.labelOptions.length = 0;\r\n inputField.options.labelOptions.push(idx + 1);\r\n const i18nElement = I18n.weakMap.get(inputField.label.firstElementChild as HTMLElement);\r\n i18nElement.update();\r\n });\r\n\r\n this.handleChange();\r\n };\r\n\r\n private appendMoreField() {\r\n const tempId = this.tempId++;\r\n const idx = this.questions.childElementCount + 1;\r\n const questionField = new InputField({\r\n placeholder: 'NewPoll.OptionsAddOption', \r\n label: 'NewPoll.OptionLabel',\r\n labelOptions: [idx],\r\n name: 'question-' + tempId, \r\n maxLength: MAX_LENGTH_OPTION\r\n });\r\n this.listenerSetter.add(questionField.input)('input', this.onInput);\r\n\r\n const radioField = new RadioField({\r\n text: '', \r\n name: 'question'\r\n });\r\n radioField.main.append(questionField.container);\r\n attachClickEvent(questionField.input, cancelEvent, {listenerSetter: this.listenerSetter});\r\n radioField.label.classList.add('hidden-widget');\r\n radioField.input.disabled = true;\r\n if(!this.quizCheckboxField.input.checked) {\r\n radioField.label.classList.remove('radio-field');\r\n }\r\n this.listenerSetter.add(radioField.input)('change', () => {\r\n const checked = radioField.input.checked;\r\n if(checked) {\r\n const idx = whichChild(radioField.label);\r\n this.correctAnswers = [new Uint8Array([idx])];\r\n this.handleChange();\r\n }\r\n });\r\n\r\n const deleteBtn = document.createElement('span');\r\n deleteBtn.classList.add('btn-icon', 'tgico-close');\r\n questionField.container.append(deleteBtn);\r\n \r\n attachClickEvent(deleteBtn, this.onDeleteClick, {listenerSetter: this.listenerSetter, once: true});\r\n\r\n this.questions.append(radioField.label);\r\n\r\n this.scrollable.scrollIntoViewNew({\r\n element: this.questions.lastElementChild as HTMLElement, \r\n position: 'center'\r\n });\r\n //this.scrollable.scrollTo(this.scrollable.scrollHeight, 'top', true, true);\r\n\r\n this.optionInputFields.push(questionField);\r\n }\r\n}\r\n","/**\n * @returns duration in ms\n */\nexport default function getGifDuration(image: HTMLImageElement) {\n const src = image.src;\n\n return fetch(src)\n .then(response => response.arrayBuffer())\n .then(arrayBuffer => {\n const d = new Uint8Array(arrayBuffer);\n // Thanks to http://justinsomnia.org/2006/10/gif-animation-duration-calculation/\n // And http://www.w3.org/Graphics/GIF/spec-gif89a.txt\n let duration = 0;\n for(let i = 0, length = d.length; i < length; ++i) {\n // Find a Graphic Control Extension hex(21F904__ ____ __00)\n if(d[i] == 0x21 \n && d[i + 1] == 0xF9 \n && d[i + 2] == 0x04 \n && d[i + 7] == 0x00) {\n // Swap 5th and 6th bytes to get the delay per frame\n const delay = (d[i + 5] << 8) | (d[i + 4] & 0xFF);\n \n // Should be aware browsers have a minimum frame delay \n // e.g. 6ms for IE, 2ms modern browsers (50fps)\n duration += delay < 2 ? 10 : delay;\n }\n }\n\n return duration / 1000;\n });\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport type Chat from \"../chat/chat\";\nimport InputField from \"../inputField\";\nimport PopupElement from \".\";\nimport Scrollable from \"../scrollable\";\nimport { toast } from \"../toast\";\nimport { prepareAlbum, wrapDocument } from \"../wrappers\";\nimport CheckboxField from \"../checkboxField\";\nimport SendContextMenu from \"../chat/sendContextMenu\";\nimport { createPosterFromMedia, createPosterFromVideo, onMediaLoad } from \"../../helpers/files\";\nimport { MyDocument } from \"../../lib/appManagers/appDocsManager\";\nimport I18n, { FormatterArguments, i18n, LangPackKey } from \"../../lib/langPack\";\nimport appDownloadManager from \"../../lib/appManagers/appDownloadManager\";\nimport calcImageInBox from \"../../helpers/calcImageInBox\";\nimport placeCaretAtEnd from \"../../helpers/dom/placeCaretAtEnd\";\nimport rootScope from \"../../lib/rootScope\";\nimport { MediaSize } from \"../../helpers/mediaSizes\";\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\nimport MEDIA_MIME_TYPES_SUPPORTED from '../../environment/mediaMimeTypesSupport';\nimport getGifDuration from \"../../helpers/getGifDuration\";\nimport replaceContent from \"../../helpers/dom/replaceContent\";\nimport createVideo from \"../../helpers/dom/createVideo\";\n\ntype SendFileParams = Partial<{\n file: File,\n objectURL: string,\n thumb: {\n blob: Blob,\n url: string,\n size: MediaSize\n },\n width: number,\n height: number,\n duration: number,\n noSound: boolean,\n itemDiv: HTMLElement\n}>;\n\nlet currentPopup: PopupNewMedia;\n\nexport function getCurrentNewMediaPopup() {\n return currentPopup;\n}\n\nexport default class PopupNewMedia extends PopupElement {\n private input: HTMLElement;\n private mediaContainer: HTMLElement;\n private groupCheckboxField: CheckboxField;\n private mediaCheckboxField: CheckboxField;\n private wasInputValue: string;\n\n private willAttach: Partial<{\n type: 'media' | 'document',\n isMedia: true,\n group: boolean,\n sendFileDetails: SendFileParams[]\n }>;\n private inputField: InputField;\n\n constructor(private chat: Chat, private files: File[], willAttachType: PopupNewMedia['willAttach']['type']) {\n super('popup-send-photo popup-new-media', null, {closable: true, withConfirm: 'Modal.Send', confirmShortcutIsSendShortcut: true, body: true});\n\n this.willAttach = {\n type: willAttachType,\n sendFileDetails: [],\n group: false\n };\n\n attachClickEvent(this.btnConfirm, () => this.send(), {listenerSetter: this.listenerSetter});\n\n if(this.chat.type !== 'scheduled') {\n const sendMenu = new SendContextMenu({\n onSilentClick: () => {\n this.chat.input.sendSilent = true;\n this.send();\n },\n onScheduleClick: () => {\n this.chat.input.scheduleSending(() => {\n this.send();\n });\n },\n openSide: 'bottom-left',\n onContextElement: this.btnConfirm,\n listenerSetter: this.listenerSetter\n });\n\n sendMenu.setPeerId(this.chat.peerId);\n\n this.header.append(sendMenu.sendMenu);\n }\n\n this.mediaContainer = document.createElement('div');\n this.mediaContainer.classList.add('popup-photo');\n const scrollable = new Scrollable(null);\n scrollable.container.append(this.mediaContainer);\n \n this.inputField = new InputField({\n placeholder: 'PreviewSender.CaptionPlaceholder',\n label: 'Caption',\n name: 'photo-caption',\n maxLength: rootScope.config.caption_length_max\n });\n this.input = this.inputField.input;\n\n this.inputField.value = this.wasInputValue = this.chat.input.messageInputField.input.innerHTML;\n this.chat.input.messageInputField.value = '';\n\n this.body.append(scrollable.container);\n this.container.append(this.inputField.container);\n\n this.attachFiles();\n\n this.addEventListener('close', () => {\n this.files = [];\n currentPopup = undefined;\n });\n\n currentPopup = this;\n }\n\n public appendDrops(element: HTMLElement) {\n this.body.append(element);\n }\n\n get type() {\n return this.willAttach.type;\n }\n\n set type(type: PopupNewMedia['willAttach']['type']) {\n this.willAttach.type = type;\n }\n\n private appendGroupCheckboxField() {\n const good = this.files.length > 1;\n if(good && !this.groupCheckboxField) {\n this.groupCheckboxField = new CheckboxField({\n text: 'PreviewSender.GroupItems', \n name: 'group-items'\n });\n this.container.append(...[this.groupCheckboxField.label, this.mediaCheckboxField?.label, this.inputField.container].filter(Boolean));\n \n this.willAttach.group = true;\n this.groupCheckboxField.setValueSilently(this.willAttach.group);\n\n this.listenerSetter.add(this.groupCheckboxField.input)('change', () => {\n const checked = this.groupCheckboxField.checked;\n \n this.willAttach.group = checked;\n\n this.attachFiles();\n });\n } else if(this.groupCheckboxField) {\n this.groupCheckboxField.label.classList.toggle('hide', !good);\n }\n }\n\n private appendMediaCheckboxField() {\n const good = !!this.files.find(file => MEDIA_MIME_TYPES_SUPPORTED.has(file.type));\n if(good && !this.mediaCheckboxField) {\n this.mediaCheckboxField = new CheckboxField({\n text: 'PreviewSender.CompressFile',\n name: 'compress-items'\n });\n this.container.append(...[this.groupCheckboxField?.label, this.mediaCheckboxField.label, this.inputField.container].filter(Boolean));\n\n this.mediaCheckboxField.setValueSilently(this.willAttach.type === 'media');\n\n this.listenerSetter.add(this.mediaCheckboxField.input)('change', () => {\n const checked = this.mediaCheckboxField.checked;\n \n this.willAttach.type = checked ? 'media' : 'document';\n\n this.attachFiles();\n });\n } else if(this.mediaCheckboxField) {\n this.mediaCheckboxField.label.classList.toggle('hide', !good);\n }\n }\n\n public addFiles(files: File[]) {\n const toPush = files.filter(file => {\n const found = this.files.find(_file => {\n return _file.lastModified === file.lastModified && _file.name === file.name && _file.size === file.size;\n });\n \n return !found;\n });\n\n if(toPush.length) {\n this.files.push(...toPush);\n this.attachFiles();\n }\n }\n\n private onKeyDown = (e: KeyboardEvent) => {\n const target = e.target as HTMLElement;\n if(target !== this.input) {\n if(target.tagName === 'INPUT' || target.hasAttribute('contenteditable')) {\n return;\n }\n\n this.input.focus();\n placeCaretAtEnd(this.input);\n }\n };\n\n private send(force = false) {\n if(this.chat.type === 'scheduled' && !force) {\n this.chat.input.scheduleSending(() => {\n this.send(true);\n });\n \n return;\n }\n\n let caption = this.inputField.value;\n if(caption.length > rootScope.config.caption_length_max) {\n toast(I18n.format('Error.PreviewSender.CaptionTooLong', true));\n return;\n }\n\n this.hide();\n const willAttach = this.willAttach;\n willAttach.isMedia = willAttach.type === 'media' ? true : undefined;\n const {sendFileDetails, isMedia} = willAttach;\n\n //console.log('will send files with options:', willAttach);\n\n const {peerId, input} = this.chat;\n\n sendFileDetails.forEach(d => {\n d.itemDiv = undefined;\n });\n\n const {length} = sendFileDetails;\n const sendingParams = this.chat.getMessageSendingParams();\n this.iterate((sendFileDetails) => {\n if(caption && sendFileDetails.length !== length) {\n this.chat.appMessagesManager.sendText(peerId, caption, {\n ...sendingParams,\n clearDraft: true\n });\n\n caption = undefined;\n }\n\n const w = {\n ...willAttach,\n sendFileDetails\n };\n\n this.chat.appMessagesManager.sendAlbum(peerId, w.sendFileDetails.map(d => d.file), Object.assign({\n ...sendingParams,\n caption,\n isMedia: isMedia,\n clearDraft: true as true\n }, w));\n\n caption = undefined;\n });\n \n input.replyToMsgId = this.chat.threadId;\n input.onMessageSent();\n }\n\n private attachMedia(file: File, params: SendFileParams, itemDiv: HTMLElement) {\n itemDiv.classList.add('popup-item-media');\n\n const isVideo = file.type.startsWith('video/');\n\n let promise: Promise<void>;\n if(isVideo) {\n const video = createVideo();\n const source = document.createElement('source');\n source.src = params.objectURL = URL.createObjectURL(file);\n video.autoplay = true;\n video.controls = false;\n video.muted = true;\n\n video.addEventListener('timeupdate', () => {\n video.pause();\n }, {once: true});\n\n promise = onMediaLoad(video).then(() => {\n params.width = video.videoWidth;\n params.height = video.videoHeight;\n params.duration = Math.floor(video.duration);\n \n const audioDecodedByteCount = (video as any).webkitAudioDecodedByteCount;\n if(audioDecodedByteCount !== undefined) {\n params.noSound = !audioDecodedByteCount;\n }\n\n itemDiv.append(video);\n return createPosterFromVideo(video).then(thumb => {\n params.thumb = {\n url: URL.createObjectURL(thumb.blob),\n ...thumb\n };\n });\n });\n\n video.append(source);\n } else {\n const img = new Image();\n promise = new Promise<void>((resolve) => {\n img.onload = () => {\n params.width = img.naturalWidth;\n params.height = img.naturalHeight;\n \n itemDiv.append(img);\n \n if(file.type === 'image/gif') {\n params.noSound = true;\n \n Promise.all([\n getGifDuration(img).then(duration => {\n params.duration = Math.ceil(duration);\n }),\n \n createPosterFromMedia(img).then(thumb => {\n params.thumb = {\n url: URL.createObjectURL(thumb.blob),\n ...thumb\n };\n })\n ]).then(() => {\n resolve();\n });\n } else {\n resolve();\n }\n };\n });\n \n img.src = params.objectURL = URL.createObjectURL(file);\n }\n\n return promise;\n }\n\n private attachDocument(file: File, params: SendFileParams, itemDiv: HTMLElement): ReturnType<PopupNewMedia['attachMedia']> {\n itemDiv.classList.add('popup-item-document');\n\n const isPhoto = file.type.startsWith('image/');\n const isAudio = file.type.startsWith('audio/');\n if(isPhoto || isAudio || file.size < 20e6) {\n params.objectURL = URL.createObjectURL(file);\n }\n\n const doc = {\n _: 'document',\n file: file,\n file_name: file.name || '',\n size: file.size,\n type: isPhoto ? 'photo' : 'doc'\n } as MyDocument;\n\n if(params.objectURL) {\n const cacheContext = appDownloadManager.getCacheContext(doc);\n cacheContext.url = params.objectURL;\n cacheContext.downloaded = file.size;\n }\n\n const docDiv = wrapDocument({\n message: {\n _: 'message',\n pFlags: {\n is_outgoing: true\n },\n mid: 0,\n peerId: 0,\n media: {\n _: 'messageMediaDocument',\n document: doc\n }\n } as any\n });\n\n const promise = new Promise<void>((resolve) => {\n const finish = () => {\n itemDiv.append(docDiv);\n resolve();\n };\n \n if(isPhoto) {\n const img = new Image();\n img.src = params.objectURL;\n img.onload = () => {\n params.width = img.naturalWidth;\n params.height = img.naturalHeight;\n \n finish();\n };\n \n img.onerror = finish;\n } else {\n finish();\n }\n });\n\n return promise;\n }\n\n private attachFile = (file: File) => {\n const willAttach = this.willAttach;\n const shouldCompress = this.shouldCompress(file.type);\n\n const params: SendFileParams = {};\n params.file = file;\n\n const itemDiv = document.createElement('div');\n itemDiv.classList.add('popup-item');\n\n params.itemDiv = itemDiv;\n\n const promise = shouldCompress ? this.attachMedia(file, params, itemDiv) : this.attachDocument(file, params, itemDiv);\n willAttach.sendFileDetails.push(params);\n return promise;\n };\n \n private shouldCompress(mimeType: string) {\n return this.willAttach.type === 'media' && MEDIA_MIME_TYPES_SUPPORTED.has(mimeType);\n }\n\n private onRender() {\n // show now\n if(!this.element.classList.contains('active')) {\n this.listenerSetter.add(document.body)('keydown', this.onKeyDown);\n this.addEventListener('close', () => {\n if(this.wasInputValue) {\n this.chat.input.messageInputField.value = this.wasInputValue;\n }\n });\n this.show();\n }\n }\n\n private setTitle() {\n const {willAttach, title, files} = this;\n let key: LangPackKey;\n const args: FormatterArguments = [];\n if(willAttach.type === 'document') {\n key = 'PreviewSender.SendFile';\n args.push(files.length);\n } else {\n let foundPhotos = 0, foundVideos = 0, foundFiles = 0;\n files.forEach(file => {\n if(file.type.startsWith('image/')) ++foundPhotos;\n else if(file.type.startsWith('video/')) ++foundVideos;\n else ++foundFiles;\n });\n\n if([foundPhotos, foundVideos, foundFiles].filter(n => n > 0).length > 1) {\n key = 'PreviewSender.SendFile';\n args.push(files.length);\n } else \n \n /* const sum = foundPhotos + foundVideos;\n if(sum > 1 && willAttach.group) {\n key = 'PreviewSender.SendAlbum';\n const albumsLength = Math.ceil(sum / 10);\n args.push(albumsLength);\n } else */if(foundPhotos) {\n key = 'PreviewSender.SendPhoto';\n args.push(foundPhotos);\n } else if(foundVideos) {\n key = 'PreviewSender.SendVideo';\n args.push(foundVideos);\n }\n }\n\n replaceContent(title, i18n(key, args));\n }\n\n private appendMediaToContainer(div: HTMLElement, params: SendFileParams) {\n if(this.shouldCompress(params.file.type)) {\n const size = calcImageInBox(params.width, params.height, 380, 320);\n div.style.width = size.width + 'px';\n div.style.height = size.height + 'px';\n }\n\n this.mediaContainer.append(div);\n }\n\n private iterate(cb: (sendFileDetails: SendFileParams[]) => void) {\n const {sendFileDetails} = this.willAttach;\n if(!this.willAttach.group) {\n sendFileDetails.forEach(p => cb([p]));\n return;\n }\n\n const length = sendFileDetails.length;\n for(let i = 0; i < length;) {\n const firstType = sendFileDetails[i].file.type;\n let k = 0;\n for(; k < 10 && i < length; ++i, ++k) {\n const type = sendFileDetails[i].file.type;\n if(this.shouldCompress(firstType) !== this.shouldCompress(type)) {\n break;\n }\n }\n\n cb(sendFileDetails.slice(i - k, i));\n }\n }\n\n private attachFiles() {\n const {files, willAttach, mediaContainer} = this;\n willAttach.sendFileDetails.length = 0;\n\n this.appendGroupCheckboxField();\n this.appendMediaCheckboxField();\n\n Promise.all(files.map(this.attachFile)).then(() => {\n mediaContainer.innerHTML = '';\n\n if(!files.length) {\n return;\n }\n\n this.setTitle();\n\n this.iterate((sendFileDetails) => {\n if(this.shouldCompress(sendFileDetails[0].file.type) && sendFileDetails.length > 1) {\n const albumContainer = document.createElement('div');\n albumContainer.classList.add('popup-item-album', 'popup-item');\n albumContainer.append(...sendFileDetails.map(s => s.itemDiv));\n\n prepareAlbum({\n container: albumContainer,\n items: sendFileDetails.map(o => ({w: o.width, h: o.height})),\n maxWidth: 380,\n minWidth: 100,\n spacing: 4\n });\n\n mediaContainer.append(albumContainer);\n } else {\n sendFileDetails.forEach((params) => {\n this.appendMediaToContainer(params.itemDiv, params);\n });\n }\n });\n }).then(() => {\n this.onRender();\n });\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport fastSmoothScroll from \"../fastSmoothScroll\";\r\nimport cancelEvent from \"./cancelEvent\";\r\nimport { attachClickEvent, detachClickEvent } from \"./clickEvent\";\r\nimport findUpAsChild from \"./findUpAsChild\";\r\nimport findUpClassName from \"./findUpClassName\";\r\n\r\ntype ArrowKey = 'ArrowUp' | 'ArrowDown' | 'ArrowLeft' | 'ArrowRight';\r\nconst HANDLE_EVENT = 'keydown';\r\nconst ACTIVE_CLASS_NAME = 'active';\r\n\r\nconst AXIS_Y_KEYS: ArrowKey[] = ['ArrowUp', 'ArrowDown'];\r\nconst AXIS_X_KEYS: ArrowKey[] = ['ArrowLeft', 'ArrowRight'];\r\n\r\nexport default function attachListNavigation({list, type, onSelect, once, waitForKey}: {\r\n list: HTMLElement, \r\n type: 'xy' | 'x' | 'y',\r\n onSelect: (target: Element) => void | boolean,\r\n once: boolean,\r\n waitForKey?: string[]\r\n}) {\r\n let waitForKeySet = waitForKey?.length ? new Set(waitForKey) : undefined;\r\n const keyNames = new Set(type === 'xy' ? AXIS_Y_KEYS.concat(AXIS_X_KEYS) : (type === 'x' ? AXIS_X_KEYS : AXIS_Y_KEYS)); \r\n\r\n let target: Element;\r\n const getCurrentTarget = () => {\r\n return target || list.querySelector('.' + ACTIVE_CLASS_NAME) || list.firstElementChild;\r\n };\r\n\r\n const setCurrentTarget = (_target: Element, scrollTo: boolean) => {\r\n if(target === _target) {\r\n return;\r\n }\r\n\r\n let hadTarget = false;\r\n if(target) {\r\n hadTarget = true;\r\n target.classList.remove(ACTIVE_CLASS_NAME);\r\n }\r\n\r\n target = _target;\r\n if(!target) return;\r\n target.classList.add(ACTIVE_CLASS_NAME);\r\n\r\n if(hadTarget && scrollable && scrollTo) {\r\n fastSmoothScroll({\r\n container: scrollable, \r\n element: target as HTMLElement, \r\n position: 'center', \r\n forceDuration: 100, \r\n axis: type === 'x' ? 'x' : 'y'\r\n });\r\n }\r\n };\r\n\r\n const getNextTargetX = (currentTarget: Element, isNext: boolean) => {\r\n let nextTarget: Element;\r\n if(isNext) nextTarget = currentTarget.nextElementSibling || list.firstElementChild;\r\n else nextTarget = currentTarget.previousElementSibling || list.lastElementChild;\r\n\r\n return nextTarget;\r\n };\r\n\r\n const getNextTargetY = (currentTarget: Element, isNext: boolean) => {\r\n const property = isNext ? 'nextElementSibling' : 'previousElementSibling';\r\n const endProperty = isNext ? 'firstElementChild' : 'lastElementChild';\r\n const currentRect = currentTarget.getBoundingClientRect();\r\n\r\n let nextTarget = currentTarget[property] || list[endProperty];\r\n while(nextTarget !== currentTarget) {\r\n const targetRect = nextTarget.getBoundingClientRect();\r\n if(targetRect.x === currentRect.x && targetRect.y !== currentRect.y) {\r\n break;\r\n }\r\n\r\n nextTarget = nextTarget[property] || list[endProperty];\r\n }\r\n\r\n return nextTarget;\r\n };\r\n\r\n let handleArrowKey: (currentTarget: Element, key: ArrowKey) => Element;\r\n if(type === 'xy') { // flex-direction: row; flex-wrap: wrap;\r\n handleArrowKey = (currentTarget, key) => {\r\n if(key === 'ArrowUp' || key === 'ArrowDown') return getNextTargetY(currentTarget, key === 'ArrowDown');\r\n else return getNextTargetX(currentTarget, key === 'ArrowRight');\r\n };\r\n } else { // flex-direction: row | column;\r\n handleArrowKey = (currentTarget, key) => getNextTargetX(currentTarget, key === 'ArrowRight' || key === 'ArrowDown');\r\n }\r\n\r\n let onKeyDown = (e: KeyboardEvent) => {\r\n const key = e.key;\r\n if(!keyNames.has(key as any)) {\r\n if(key === 'Enter' || (type !== 'xy' && key === 'Tab')) {\r\n cancelEvent(e);\r\n fireSelect(getCurrentTarget());\r\n }\r\n\r\n return;\r\n }\r\n\r\n cancelEvent(e);\r\n\r\n if(list.childElementCount > 1) {\r\n let currentTarget = getCurrentTarget();\r\n currentTarget = handleArrowKey(currentTarget, key as any);\r\n setCurrentTarget(currentTarget, true);\r\n }\r\n };\r\n\r\n const scrollable = findUpClassName(list, 'scrollable');\r\n list.classList.add('navigable-list');\r\n\r\n const onMouseMove = (e: MouseEvent) => {\r\n const target = findUpAsChild(e.target, list) as HTMLElement;\r\n if(!target) {\r\n return;\r\n }\r\n\r\n setCurrentTarget(target, false);\r\n };\r\n\r\n const onClick = (e: Event) => {\r\n cancelEvent(e); // cancel keyboard closening\r\n\r\n const target = findUpAsChild(e.target, list) as HTMLElement;\r\n if(!target) {\r\n return;\r\n }\r\n\r\n setCurrentTarget(target, false);\r\n fireSelect(getCurrentTarget());\r\n };\r\n\r\n const fireSelect = (target: Element) => {\r\n const canContinue = onSelect(target);\r\n if(canContinue !== undefined ? !canContinue : once) {\r\n detach();\r\n }\r\n };\r\n\r\n let attached = false;\r\n const attach = () => {\r\n if(attached) return;\r\n attached = true;\r\n // const input = document.activeElement as HTMLElement;\r\n // input.addEventListener(HANDLE_EVENT, onKeyDown, {capture: true, passive: false});\r\n document.addEventListener(HANDLE_EVENT, onKeyDown, {capture: true, passive: false});\r\n list.addEventListener('mousemove', onMouseMove, {passive: true});\r\n attachClickEvent(list, onClick);\r\n };\r\n\r\n const detach = () => {\r\n if(!attached) return;\r\n attached = false;\r\n // input.removeEventListener(HANDLE_EVENT, onKeyDown, {capture: true});\r\n document.removeEventListener(HANDLE_EVENT, onKeyDown, {capture: true});\r\n list.removeEventListener('mousemove', onMouseMove);\r\n detachClickEvent(list, onClick);\r\n };\r\n\r\n const resetTarget = () => {\r\n if(waitForKeySet) return;\r\n setCurrentTarget(list.firstElementChild, false);\r\n };\r\n\r\n if(waitForKeySet) {\r\n const _onKeyDown = onKeyDown;\r\n onKeyDown = (e) => {\r\n if(waitForKeySet.has(e.key)) {\r\n cancelEvent(e);\r\n\r\n document.removeEventListener(HANDLE_EVENT, onKeyDown, {capture: true});\r\n onKeyDown = _onKeyDown;\r\n document.addEventListener(HANDLE_EVENT, onKeyDown, {capture: true, passive: false});\r\n\r\n waitForKeySet = undefined;\r\n resetTarget();\r\n }\r\n };\r\n } else {\r\n resetTarget();\r\n }\r\n\r\n attach();\r\n\r\n return {\r\n attach,\r\n detach,\r\n resetTarget\r\n };\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport attachListNavigation from \"../../helpers/dom/attachListNavigation\";\r\nimport EventListenerBase from \"../../helpers/eventListenerBase\";\r\nimport { IS_MOBILE } from \"../../environment/userAgent\";\r\nimport rootScope from \"../../lib/rootScope\";\r\nimport appNavigationController, { NavigationItem } from \"../appNavigationController\";\r\nimport SetTransition from \"../singleTransition\";\r\nimport AutocompleteHelperController from \"./autocompleteHelperController\";\r\nimport safeAssign from \"../../helpers/object/safeAssign\";\r\n\r\nexport default class AutocompleteHelper extends EventListenerBase<{\r\n hidden: () => void,\r\n visible: () => void,\r\n hiding: () => void\r\n}> {\r\n protected hidden = true;\r\n protected container: HTMLElement;\r\n protected list: HTMLElement;\r\n protected resetTarget: () => void;\r\n protected attach: () => void;\r\n protected detach: () => void;\r\n protected init?(): void;\r\n\r\n protected controller: AutocompleteHelperController;\r\n protected listType: 'xy' | 'x' | 'y';\r\n protected onSelect: (target: Element) => boolean | void;\r\n protected waitForKey?: string[];\r\n\r\n protected navigationItem: NavigationItem;\r\n\r\n constructor(options: {\r\n appendTo: HTMLElement,\r\n controller?: AutocompleteHelper['controller'],\r\n listType: AutocompleteHelper['listType'],\r\n onSelect: AutocompleteHelper['onSelect'],\r\n waitForKey?: AutocompleteHelper['waitForKey']\r\n }) {\r\n super(false);\r\n\r\n safeAssign(this, options);\r\n \r\n this.container = document.createElement('div');\r\n this.container.classList.add('autocomplete-helper', 'z-depth-1');\r\n \r\n options.appendTo.append(this.container);\r\n \r\n this.attachNavigation();\r\n\r\n this.controller && this.controller.addHelper(this);\r\n }\r\n\r\n public toggleListNavigation(enabled: boolean) {\r\n if(enabled) {\r\n this.attach && this.attach();\r\n } else {\r\n this.detach && this.detach();\r\n }\r\n }\r\n\r\n protected onVisible = () => {\r\n if(this.detach) { // it can be so because 'visible' calls before animation's end\r\n this.detach();\r\n }\r\n\r\n const list = this.list;\r\n const {attach, detach, resetTarget} = attachListNavigation({\r\n list, \r\n type: this.listType,\r\n onSelect: this.onSelect,\r\n once: true,\r\n waitForKey: this.waitForKey\r\n });\r\n\r\n this.attach = attach;\r\n this.detach = detach;\r\n this.resetTarget = resetTarget;\r\n if(!IS_MOBILE && !this.navigationItem) {\r\n this.navigationItem = {\r\n type: 'autocomplete-helper',\r\n onPop: () => {\r\n this.navigationItem = undefined;\r\n this.toggle(true);\r\n },\r\n noBlurOnPop: true\r\n };\r\n\r\n appNavigationController.pushItem(this.navigationItem);\r\n }\r\n\r\n this.addEventListener('hidden', () => {\r\n this.resetTarget = undefined;\r\n this.attach = undefined;\r\n this.detach = undefined;\r\n\r\n list.innerHTML = '';\r\n detach();\r\n\r\n if(this.navigationItem) {\r\n appNavigationController.removeItem(this.navigationItem);\r\n this.navigationItem = undefined;\r\n }\r\n }, {once: true});\r\n };\r\n\r\n protected attachNavigation() {\r\n this.addEventListener('visible', this.onVisible);\r\n }\r\n\r\n public toggle(hide?: boolean, fromController = false, skipAnimation?: boolean) {\r\n if(this.init) {\r\n return;\r\n }\r\n \r\n if(hide === undefined) {\r\n hide = this.container.classList.contains('is-visible') && !this.container.classList.contains('backwards');\r\n }\r\n\r\n if(this.hidden === hide) {\r\n if(!hide) {\r\n this.dispatchEvent('visible'); // reset target and listener\r\n }\r\n\r\n return;\r\n }\r\n\r\n this.hidden = hide;\r\n\r\n if(!hide) {\r\n this.controller && this.controller.hideOtherHelpers(this);\r\n this.dispatchEvent('visible'); // fire it before so target will be set\r\n } else {\r\n if(this.navigationItem) {\r\n appNavigationController.removeItem(this.navigationItem);\r\n this.navigationItem = undefined;\r\n }\r\n\r\n if(!fromController && this.controller) {\r\n this.controller.hideOtherHelpers();\r\n }\r\n\r\n if(this.detach) { // force detach here\r\n this.detach();\r\n }\r\n }\r\n\r\n const useRafs = this.controller || hide ? 0 : 2;\r\n\r\n if(hide) {\r\n this.dispatchEvent('hiding');\r\n }\r\n\r\n SetTransition(\r\n this.container, \r\n 'is-visible', \r\n !hide, \r\n rootScope.settings.animationsEnabled && !skipAnimation ? 300 : 0, \r\n () => {\r\n this.hidden && this.dispatchEvent('hidden');\r\n }, \r\n useRafs\r\n );\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport mediaSizes from \"../../helpers/mediaSizes\";\r\nimport { MyDocument } from \"../../lib/appManagers/appDocsManager\";\r\nimport { CHAT_ANIMATION_GROUP } from \"../../lib/appManagers/appImManager\";\r\nimport appStickersManager from \"../../lib/appManagers/appStickersManager\";\r\nimport rootScope from \"../../lib/rootScope\";\r\nimport { EmoticonsDropdown } from \"../emoticonsDropdown\";\r\nimport { SuperStickerRenderer } from \"../emoticonsDropdown/tabs/stickers\";\r\nimport LazyLoadQueue from \"../lazyLoadQueue\";\r\nimport Scrollable from \"../scrollable\";\r\nimport AutocompleteHelper from \"./autocompleteHelper\";\r\nimport AutocompleteHelperController from \"./autocompleteHelperController\";\r\n\r\nexport default class StickersHelper extends AutocompleteHelper {\r\n private scrollable: Scrollable;\r\n private superStickerRenderer: SuperStickerRenderer;\r\n private lazyLoadQueue: LazyLoadQueue;\r\n private onChangeScreen: () => void;\r\n\r\n constructor(appendTo: HTMLElement, controller: AutocompleteHelperController) {\r\n super({\r\n appendTo, \r\n controller,\r\n listType: 'xy', \r\n onSelect: (target) => {\r\n return !EmoticonsDropdown.onMediaClick({target}, true);\r\n }, \r\n waitForKey: ['ArrowUp', 'ArrowDown']\r\n });\r\n\r\n this.container.classList.add('stickers-helper');\r\n\r\n this.addEventListener('visible', () => {\r\n setTimeout(() => { // it is not rendered yet\r\n this.scrollable.container.scrollTop = 0;\r\n }, 0);\r\n\r\n rootScope.dispatchEvent('choosing_sticker', true);\r\n });\r\n\r\n this.addEventListener('hidden', () => {\r\n if(this.onChangeScreen) {\r\n mediaSizes.removeEventListener('changeScreen', this.onChangeScreen);\r\n this.onChangeScreen = undefined;\r\n }\r\n\r\n rootScope.dispatchEvent('choosing_sticker', false);\r\n });\r\n }\r\n\r\n public checkEmoticon(emoticon: string) {\r\n const middleware = this.controller.getMiddleware();\r\n\r\n if(this.lazyLoadQueue) {\r\n this.lazyLoadQueue.clear();\r\n }\r\n\r\n appStickersManager.preloadAnimatedEmojiSticker(emoticon);\r\n appStickersManager.getStickersByEmoticon(emoticon)\r\n .then((stickers) => {\r\n if(!middleware()) {\r\n return;\r\n }\r\n\r\n if(this.init) {\r\n this.init();\r\n this.init = null;\r\n }\r\n\r\n const container = this.list.cloneNode() as HTMLElement;\r\n\r\n let ready: Promise<void>;\r\n\r\n this.lazyLoadQueue.clear();\r\n if(stickers.length) {\r\n ready = new Promise<void>((resolve) => {\r\n const promises: Promise<any>[] = [];\r\n stickers.forEach(sticker => {\r\n container.append(this.superStickerRenderer.renderSticker(sticker as MyDocument, undefined, promises));\r\n });\r\n\r\n (Promise.all(promises) as Promise<any>).finally(resolve);\r\n });\r\n } else {\r\n ready = Promise.resolve();\r\n }\r\n\r\n ready.then(() => {\r\n this.list.replaceWith(container);\r\n this.list = container;\r\n\r\n if(!this.onChangeScreen) {\r\n this.onChangeScreen = () => {\r\n const width = (this.list.childElementCount * mediaSizes.active.esgSticker.width) + (this.list.childElementCount - 1 * 1);\r\n this.list.style.width = width + 'px';\r\n };\r\n mediaSizes.addEventListener('changeScreen', this.onChangeScreen);\r\n }\r\n\r\n this.onChangeScreen();\r\n\r\n this.toggle(!stickers.length);\r\n this.scrollable.scrollTop = 0;\r\n });\r\n });\r\n }\r\n\r\n protected init() {\r\n this.list = document.createElement('div');\r\n this.list.classList.add('stickers-helper-stickers', 'super-stickers');\r\n\r\n this.container.append(this.list);\r\n\r\n this.scrollable = new Scrollable(this.container);\r\n this.lazyLoadQueue = new LazyLoadQueue();\r\n this.superStickerRenderer = new SuperStickerRenderer(this.lazyLoadQueue, CHAT_ANIMATION_GROUP);\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\r\nimport { SEND_WHEN_ONLINE_TIMESTAMP } from \"../../lib/mtproto/constants\";\r\nimport Button from \"../button\";\r\nimport PopupDatePicker from \"./datePicker\";\r\n\r\nconst getMinDate = () => {\r\n const date = new Date();\r\n //date.setDate(date.getDate() - 1);\r\n date.setHours(0, 0, 0, 0);\r\n return date;\r\n};\r\n\r\nconst getMaxDate = () => {\r\n const date = new Date();\r\n date.setFullYear(date.getFullYear() + 1);\r\n date.setDate(date.getDate() - 1);\r\n return date;\r\n};\r\n\r\nconst checkDate = (date: Date) => {\r\n return date.getTime() > getMaxDate().getTime() ? new Date() : date;\r\n};\r\n\r\nexport default class PopupSchedule extends PopupDatePicker {\r\n constructor(initDate: Date, onPick: (timestamp: number) => void, canSendWhenOnline: boolean) {\r\n super(checkDate(initDate), onPick, {\r\n noButtons: true,\r\n noTitle: true,\r\n closable: true,\r\n withConfirm: true,\r\n minDate: getMinDate(),\r\n maxDate: getMaxDate(),\r\n withTime: true,\r\n showOverflowMonths: true,\r\n confirmShortcutIsSendShortcut: true\r\n });\r\n\r\n this.element.classList.add('popup-schedule');\r\n this.header.append(this.controlsDiv);\r\n this.title.replaceWith(this.monthTitle);\r\n this.body.append(this.btnConfirm);\r\n\r\n if(canSendWhenOnline) {\r\n const btnSendWhenOnline = Button('btn-primary btn-secondary btn-primary-transparent primary', {text: 'Schedule.SendWhenOnline'});\r\n this.body.append(btnSendWhenOnline);\r\n\r\n attachClickEvent(btnSendWhenOnline, () => {\r\n onPick(SEND_WHEN_ONLINE_TIMESTAMP);\r\n this.hide();\r\n });\r\n }\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n * \r\n * Originally from:\r\n * https://github.com/zhukov/webogram\r\n * Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>\r\n * https://github.com/zhukov/webogram/blob/master/LICENSE\r\n */\r\n\r\nimport { MessageEntity } from \"../../layer\";\r\nimport RichTextProcessor from \"../../lib/richtextprocessor\";\r\nimport getRichElementValue from \"./getRichElementValue\";\r\n\r\nexport default function getRichValueWithCaret(field: HTMLElement, withEntities = true) {\r\n const lines: string[] = [];\r\n const line: string[] = [];\r\n\r\n const sel = window.getSelection();\r\n let selNode: Node;\r\n let selOffset: number;\r\n if(sel && sel.rangeCount) {\r\n const range = sel.getRangeAt(0);\r\n const startOffset = range.startOffset;\r\n if(\r\n range.startContainer &&\r\n range.startContainer == range.endContainer &&\r\n startOffset == range.endOffset\r\n ) {\r\n // * if focused on img, or caret has been set via placeCaretAtEnd\r\n const possibleChildrenFocusOffset = startOffset - 1;\r\n const childNodes = field.childNodes;\r\n if(range.startContainer === field && childNodes[possibleChildrenFocusOffset]) {\r\n selNode = childNodes[possibleChildrenFocusOffset];\r\n selOffset = 0;\r\n\r\n for(let i = 0; i < range.endOffset; ++i) {\r\n const node = childNodes[i];\r\n const value = node.nodeValue || (node as HTMLImageElement).alt;\r\n\r\n if(value) {\r\n selOffset += value.length;\r\n }\r\n }\r\n } else {\r\n selNode = range.startContainer;\r\n selOffset = startOffset;\r\n }\r\n }\r\n }\r\n\r\n const entities: MessageEntity[] = withEntities ? [] : undefined;\r\n getRichElementValue(field, lines, line, selNode, selOffset, entities);\r\n\r\n if(line.length) {\r\n lines.push(line.join(''));\r\n }\r\n\r\n let value = lines.join('\\n');\r\n const caretPos = value.indexOf('\\x01');\r\n if(caretPos != -1) {\r\n value = value.substr(0, caretPos) + value.substr(caretPos + 1);\r\n }\r\n value = value.replace(/\\u00A0/g, ' ');\r\n\r\n if(entities) {\r\n RichTextProcessor.combineSameEntities(entities);\r\n }\r\n\r\n return {value, entities, caretPos};\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport type ChatInput from \"./input\";\r\nimport type { AppEmojiManager } from \"../../lib/appManagers/appEmojiManager\";\r\nimport { appendEmoji, getEmojiFromElement } from \"../emoticonsDropdown/tabs/emoji\";\r\nimport { ScrollableX } from \"../scrollable\";\r\nimport AutocompleteHelper from \"./autocompleteHelper\";\r\nimport AutocompleteHelperController from \"./autocompleteHelperController\";\r\n\r\nexport default class EmojiHelper extends AutocompleteHelper {\r\n private scrollable: ScrollableX;\r\n\r\n constructor(appendTo: HTMLElement, \r\n controller: AutocompleteHelperController, \r\n chatInput: ChatInput, \r\n private appEmojiManager: AppEmojiManager) {\r\n super({\r\n appendTo,\r\n controller, \r\n listType: 'x', \r\n onSelect: (target) => {\r\n chatInput.onEmojiSelected(getEmojiFromElement(target as any), true);\r\n }\r\n });\r\n\r\n this.container.classList.add('emoji-helper');\r\n }\r\n\r\n protected init() {\r\n this.list = document.createElement('div');\r\n this.list.classList.add('emoji-helper-emojis', 'super-emojis');\r\n\r\n this.container.append(this.list);\r\n\r\n this.scrollable = new ScrollableX(this.container);\r\n\r\n this.addEventListener('visible', () => {\r\n setTimeout(() => { // it is not rendered yet\r\n this.scrollable.container.scrollLeft = 0;\r\n }, 0);\r\n });\r\n }\r\n\r\n public render(emojis: string[], waitForKey: boolean) {\r\n if(this.init) {\r\n if(!emojis.length) {\r\n return;\r\n }\r\n\r\n this.init();\r\n this.init = null;\r\n }\r\n \r\n emojis = emojis.slice(0, 80);\r\n\r\n if(emojis.length) {\r\n this.list.innerHTML = '';\r\n emojis.forEach(emoji => {\r\n appendEmoji(emoji, this.list, false, true);\r\n });\r\n }\r\n\r\n this.waitForKey = waitForKey ? ['ArrowUp', 'ArrowDown'] : undefined;\r\n this.toggle(!emojis.length);\r\n\r\n /* window.requestAnimationFrame(() => {\r\n this.container.style.width = (3 * 2) + (emojis.length * 44) + 'px';\r\n }); */\r\n }\r\n\r\n public checkQuery(query: string, firstChar: string) {\r\n const middleware = this.controller.getMiddleware();\r\n this.appEmojiManager.getBothEmojiKeywords().then(() => {\r\n if(!middleware()) {\r\n return;\r\n }\r\n\r\n const q = query.replace(/^:/, '');\r\n const emojis = this.appEmojiManager.searchEmojis(q);\r\n this.render(emojis, firstChar !== ':');\r\n //console.log(emojis);\r\n });\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport setInnerHTML from \"../../helpers/dom/setInnerHTML\";\r\nimport RichTextProcessor from \"../../lib/richtextprocessor\";\r\nimport AvatarElement from \"../avatar\";\r\nimport PeerTitle from \"../peerTitle\";\r\nimport Scrollable from \"../scrollable\";\r\nimport AutocompleteHelper from \"./autocompleteHelper\";\r\nimport AutocompleteHelperController from \"./autocompleteHelperController\";\r\n\r\nexport default class AutocompletePeerHelper extends AutocompleteHelper {\r\n protected static BASE_CLASS = 'autocomplete-peer-helper';\r\n protected static BASE_CLASS_LIST_ELEMENT = AutocompletePeerHelper.BASE_CLASS + '-list-element';\r\n private scrollable: Scrollable;\r\n\r\n constructor(\r\n appendTo: HTMLElement, \r\n controller: AutocompleteHelperController, \r\n protected className: string, \r\n onSelect: (target: Element) => boolean | void\r\n ) {\r\n super({\r\n appendTo, \r\n controller,\r\n listType: 'y', \r\n onSelect\r\n });\r\n\r\n this.container.classList.add(AutocompletePeerHelper.BASE_CLASS, className);\r\n }\r\n\r\n protected init() {\r\n this.list = document.createElement('div');\r\n this.list.classList.add(AutocompletePeerHelper.BASE_CLASS + '-list', this.className + '-list');\r\n\r\n this.container.append(this.list);\r\n\r\n this.scrollable = new Scrollable(this.container);\r\n\r\n this.addEventListener('visible', () => {\r\n setTimeout(() => { // it is not rendered yet\r\n this.scrollable.container.scrollTop = 0;\r\n }, 0);\r\n });\r\n }\r\n\r\n public render(data: {peerId: PeerId, name?: string, description?: string}[], doNotShow?: boolean) {\r\n if(this.init) {\r\n if(!data.length) {\r\n return;\r\n }\r\n\r\n this.init();\r\n this.init = null;\r\n }\r\n\r\n if(data.length) {\r\n this.list.innerHTML = '';\r\n data.forEach(d => {\r\n const div = AutocompletePeerHelper.listElement({\r\n className: this.className,\r\n peerId: d.peerId,\r\n name: d.name,\r\n description: d.description\r\n });\r\n\r\n this.list.append(div);\r\n });\r\n }\r\n\r\n if(!doNotShow) {\r\n this.toggle(!data.length);\r\n }\r\n }\r\n\r\n public static listElement(options: {\r\n className: string,\r\n peerId: PeerId,\r\n name?: string,\r\n description?: string\r\n }) {\r\n const BASE = AutocompletePeerHelper.BASE_CLASS_LIST_ELEMENT;\r\n options.className += '-list-element';\r\n\r\n const div = document.createElement('div');\r\n div.classList.add(BASE, options.className);\r\n div.dataset.peerId = '' + options.peerId;\r\n \r\n const avatar = new AvatarElement();\r\n avatar.classList.add('avatar-30', BASE + '-avatar', options.className + '-avatar');\r\n avatar.updateWithOptions({\r\n isDialog: false,\r\n peerId: options.peerId\r\n });\r\n \r\n const name = document.createElement('div');\r\n name.classList.add(BASE + '-name', options.className + '-name');\r\n if(!options.name) {\r\n name.append(new PeerTitle({\r\n peerId: options.peerId,\r\n dialog: false,\r\n onlyFirstName: false,\r\n plainText: false\r\n }).element);\r\n } else {\r\n setInnerHTML(name, RichTextProcessor.wrapEmojiText(options.name));\r\n }\r\n \r\n div.append(avatar, name);\r\n\r\n if(options.description) {\r\n const description = document.createElement('div');\r\n description.classList.add(BASE + '-description', options.className + '-description');\r\n setInnerHTML(description, RichTextProcessor.wrapEmojiText(options.description));\r\n div.append(description);\r\n }\r\n \r\n return div;\r\n }\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport type ChatInput from \"./input\";\nimport type { AppProfileManager } from \"../../lib/appManagers/appProfileManager\";\nimport type { AppUsersManager } from \"../../lib/appManagers/appUsersManager\";\nimport type { BotInfo, ChatFull, UserFull } from \"../../layer\";\nimport AutocompleteHelperController from \"./autocompleteHelperController\";\nimport AutocompletePeerHelper from \"./autocompletePeerHelper\";\nimport SearchIndex from \"../../lib/searchIndex\";\n\nexport function processPeerFullForCommands(full: ChatFull.chatFull | ChatFull.channelFull | UserFull.userFull, query?: string) {\n const botInfos: BotInfo.botInfo[] = [].concat(full.bot_info);\n let index: SearchIndex<string>; \n \n if(query !== undefined) {\n index = new SearchIndex<string>({\n ignoreCase: true\n });\n }\n \n type T = {peerId: PeerId, name: string, description: string, index: number, command: string};\n const commands: Map<string, T> = new Map();\n botInfos.forEach(botInfo => {\n botInfo.commands.forEach((botCommand, idx) => {\n const c = '/' + botCommand.command;\n commands.set(botCommand.command, {\n peerId: botInfo.user_id.toPeerId(false), \n command: botCommand.command, \n name: c, \n description: botCommand.description,\n index: idx\n });\n\n if(index) {\n index.indexObject(botCommand.command, c);\n }\n });\n });\n\n let out: T[];\n if(!index) {\n out = [...commands.values()];\n } else {\n const found = index.search(query);\n out = Array.from(found).map(command => commands.get(command));\n }\n\n out = out.sort((a, b) => commands.get(a.command).index - commands.get(b.command).index);\n \n return out;\n}\n\nexport default class CommandsHelper extends AutocompletePeerHelper {\n constructor(appendTo: HTMLElement, \n controller: AutocompleteHelperController, \n chatInput: ChatInput, \n private appProfileManager: AppProfileManager,\n private appUsersManager: AppUsersManager) {\n super(appendTo, \n controller,\n 'commands-helper',\n (target) => {\n const innerHTML = target.querySelector(`.${AutocompletePeerHelper.BASE_CLASS_LIST_ELEMENT}-name`).innerHTML;\n return chatInput.getReadyToSend(() => {\n chatInput.messageInput.innerHTML = innerHTML;\n chatInput.sendMessage(true);\n });\n }\n );\n }\n\n public checkQuery(query: string, peerId: PeerId) {\n if(!this.appUsersManager.isBot(peerId)) {\n return false;\n }\n\n const middleware = this.controller.getMiddleware();\n Promise.resolve(this.appProfileManager.getProfileByPeerId(peerId)).then(full => {\n if(!middleware()) {\n return;\n }\n\n const filtered = processPeerFullForCommands(full, query);\n this.render(filtered);\n // console.log('found commands', found, filtered);\n });\n\n return true;\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { getMiddleware } from \"../../helpers/middleware\";\r\nimport AutocompleteHelper from \"./autocompleteHelper\";\r\n\r\nexport default class AutocompleteHelperController {\r\n private helpers: Set<AutocompleteHelper> = new Set();\r\n private middleware = getMiddleware();\r\n /* private tempId = 0;\r\n\r\n public incrementToggleCount() {\r\n return ++this.tempId;\r\n }\r\n\r\n public getToggleCount() {\r\n return this.tempId;\r\n } */\r\n\r\n public toggleListNavigation(enabled: boolean) {\r\n for(const helper of this.helpers) {\r\n helper.toggleListNavigation(enabled);\r\n }\r\n }\r\n\r\n public getMiddleware() {\r\n this.middleware.clean();\r\n return this.middleware.get();\r\n }\r\n\r\n public addHelper(helper: AutocompleteHelper) {\r\n this.helpers.add(helper);\r\n }\r\n\r\n public hideOtherHelpers(preserveHelper?: AutocompleteHelper) {\r\n this.helpers.forEach(helper => {\r\n if(helper !== preserveHelper) {\r\n helper.toggle(true, true);\r\n }\r\n });\r\n\r\n if(!preserveHelper) {\r\n this.middleware.clean();\r\n }\r\n }\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport type ChatInput from \"./input\";\nimport type { MessageEntity } from \"../../layer\";\nimport type { AppProfileManager } from \"../../lib/appManagers/appProfileManager\";\nimport type { AppUsersManager } from \"../../lib/appManagers/appUsersManager\";\nimport AutocompleteHelperController from \"./autocompleteHelperController\";\nimport AutocompletePeerHelper from \"./autocompletePeerHelper\";\n\nexport default class MentionsHelper extends AutocompletePeerHelper {\n constructor(appendTo: HTMLElement, \n controller: AutocompleteHelperController, \n chatInput: ChatInput, \n private appProfileManager: AppProfileManager,\n private appUsersManager: AppUsersManager) {\n super(appendTo, \n controller,\n 'mentions-helper',\n (target) => {\n const user = appUsersManager.getUser((target as HTMLElement).dataset.peerId.toUserId());\n let str = '', entity: MessageEntity;\n if(user.username) {\n str = '@' + user.username;\n } else {\n str = user.first_name || user.last_name;\n entity = {\n _: 'messageEntityMentionName',\n length: str.length,\n offset: 0,\n user_id: user.id\n };\n }\n\n str += ' ';\n chatInput.insertAtCaret(str, entity);\n }\n );\n }\n\n public checkQuery(query: string, peerId: PeerId, topMsgId: number) {\n const trimmed = query.trim(); // check that there is no whitespace\n if(query.length !== trimmed.length) return false;\n\n const middleware = this.controller.getMiddleware();\n this.appProfileManager.getMentions(peerId && peerId.toChatId(), trimmed, topMsgId).then(peerIds => {\n if(!middleware()) return;\n \n const username = trimmed.slice(1).toLowerCase();\n this.render(peerIds.map(peerId => {\n const user = this.appUsersManager.getUser(peerId);\n if(user.username && user.username.toLowerCase() === username) { // hide full matched suggestion\n return;\n }\n\n return {\n peerId,\n description: user.username ? '@' + user.username : undefined\n };\n }).filter(Boolean));\n });\n\n return true;\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport type { AppMessagesManager } from \"../../lib/appManagers/appMessagesManager\";\r\nimport type ChatInput from \"./input\";\r\nimport DropdownHover from \"../../helpers/dropdownHover\";\r\nimport { KeyboardButton, ReplyMarkup } from \"../../layer\";\r\nimport RichTextProcessor from \"../../lib/richtextprocessor\";\r\nimport rootScope from \"../../lib/rootScope\";\r\nimport ListenerSetter, { Listener } from \"../../helpers/listenerSetter\";\r\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\r\nimport { IS_TOUCH_SUPPORTED } from \"../../environment/touchSupport\";\r\nimport findUpAsChild from \"../../helpers/dom/findUpAsChild\";\r\nimport cancelEvent from \"../../helpers/dom/cancelEvent\";\r\nimport { getHeavyAnimationPromise } from \"../../hooks/useHeavyAnimationCheck\";\r\nimport confirmationPopup from \"../confirmationPopup\";\r\nimport safeAssign from \"../../helpers/object/safeAssign\";\r\nimport setInnerHTML from \"../../helpers/dom/setInnerHTML\";\r\n\r\nexport default class ReplyKeyboard extends DropdownHover {\r\n private static BASE_CLASS = 'reply-keyboard';\r\n private appendTo: HTMLElement;\r\n private listenerSetter: ListenerSetter;\r\n private appMessagesManager: AppMessagesManager;\r\n private btnHover: HTMLElement;\r\n private peerId: PeerId;\r\n private touchListener: Listener;\r\n private chatInput: ChatInput;\r\n\r\n constructor(options: {\r\n listenerSetter: ListenerSetter,\r\n appMessagesManager: AppMessagesManager,\r\n appendTo: HTMLElement,\r\n btnHover: HTMLElement,\r\n chatInput: ChatInput\r\n }) {\r\n super({\r\n element: document.createElement('div')\r\n });\r\n\r\n safeAssign(this, options);\r\n\r\n this.element.classList.add(ReplyKeyboard.BASE_CLASS);\r\n this.element.style.display = 'none';\r\n\r\n this.attachButtonListener(this.btnHover, this.listenerSetter);\r\n this.listenerSetter.add(rootScope)('history_reply_markup', ({peerId}) => {\r\n if(this.peerId === peerId) {\r\n if(this.checkAvailability() && this.isActive()) {\r\n this.render();\r\n }\r\n\r\n getHeavyAnimationPromise().then(() => {\r\n this.checkForceReply();\r\n });\r\n }\r\n });\r\n }\r\n\r\n protected init() {\r\n this.appendTo.append(this.element);\r\n\r\n this.listenerSetter.add(this)('open', () => {\r\n this.render();\r\n\r\n if(IS_TOUCH_SUPPORTED) {\r\n this.touchListener = this.listenerSetter.add(document.body)('touchstart', this.onBodyTouchStart, {passive: false, capture: true}) as any as Listener;\r\n this.listenerSetter.add(this)('close', () => {\r\n this.listenerSetter.remove(this.touchListener);\r\n }, {once: true});\r\n }\r\n });\r\n \r\n this.listenerSetter.add(this.element)('click', (e) => {\r\n const target = findUpClassName(e.target, 'btn');\r\n if(!target) {\r\n return;\r\n }\r\n\r\n const type = target.dataset.type as KeyboardButton['_'];\r\n const {peerId} = this;\r\n switch(type) {\r\n case 'keyboardButtonRequestPhone': {\r\n confirmationPopup({\r\n titleLangKey: 'ShareYouPhoneNumberTitle',\r\n button: {\r\n langKey: 'OK'\r\n },\r\n descriptionLangKey: 'AreYouSureShareMyContactInfoBot'\r\n }).then(() => {\r\n this.appMessagesManager.sendContact(peerId, rootScope.myId);\r\n });\r\n break;\r\n }\r\n\r\n default: {\r\n this.appMessagesManager.sendText(peerId, target.dataset.text);\r\n break;\r\n }\r\n }\r\n\r\n this.toggle(false);\r\n });\r\n\r\n return super.init();\r\n }\r\n\r\n private onBodyTouchStart = (e: TouchEvent) => {\r\n const target = e.touches[0].target as HTMLElement;\r\n if(!findUpAsChild(target, this.element) && target !== this.btnHover) {\r\n cancelEvent(e);\r\n this.toggle(false);\r\n }\r\n };\r\n\r\n public checkForceReply() {\r\n const replyMarkup = this.getReplyMarkup();\r\n if(replyMarkup._ === 'replyKeyboardForceReply' &&\r\n !replyMarkup.pFlags.hidden && \r\n !replyMarkup.pFlags.used) {\r\n replyMarkup.pFlags.used = true;\r\n this.chatInput.initMessageReply(replyMarkup.mid);\r\n }\r\n }\r\n\r\n private getReplyMarkup(): ReplyMarkup {\r\n return this.appMessagesManager.getHistoryStorage(this.peerId).replyMarkup ?? {\r\n _: 'replyKeyboardHide'\r\n };\r\n }\r\n\r\n public render(replyMarkup: ReplyMarkup.replyKeyboardMarkup = this.getReplyMarkup() as any) {\r\n this.element.innerHTML = '';\r\n\r\n for(const row of replyMarkup.rows) {\r\n const div = document.createElement('div');\r\n div.classList.add(ReplyKeyboard.BASE_CLASS + '-row');\r\n\r\n for(const button of row.buttons) {\r\n const btn = document.createElement('button');\r\n btn.classList.add(ReplyKeyboard.BASE_CLASS + '-button', 'btn');\r\n setInnerHTML(btn, RichTextProcessor.wrapEmojiText(button.text));\r\n btn.dataset.text = button.text;\r\n btn.dataset.type = button._;\r\n div.append(btn);\r\n }\r\n\r\n this.element.append(div);\r\n }\r\n }\r\n\r\n public checkAvailability(replyMarkup: ReplyMarkup = this.getReplyMarkup()) {\r\n const hide = replyMarkup._ === 'replyKeyboardHide' || !(replyMarkup as ReplyMarkup.replyInlineMarkup).rows?.length;\r\n this.btnHover.classList.toggle('hide', hide);\r\n\r\n if(hide) {\r\n this.toggle(false);\r\n }\r\n\r\n return !hide;\r\n }\r\n\r\n public setPeer(peerId: PeerId) {\r\n this.peerId = peerId;\r\n\r\n this.checkAvailability();\r\n this.checkForceReply();\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport type { AppInlineBotsManager } from \"../../lib/appManagers/appInlineBotsManager\";\r\nimport type { AppUsersManager } from \"../../lib/appManagers/appUsersManager\";\r\nimport type Chat from \"./chat\";\r\nimport debounce from \"../../helpers/schedulers/debounce\";\r\nimport { WebDocument } from \"../../layer\";\r\nimport { MyDocument } from \"../../lib/appManagers/appDocsManager\";\r\nimport appDownloadManager from \"../../lib/appManagers/appDownloadManager\";\r\nimport RichTextProcessor from \"../../lib/richtextprocessor\";\r\nimport LazyLoadQueue from \"../lazyLoadQueue\";\r\nimport Scrollable from \"../scrollable\";\r\nimport { renderImageWithFadeIn, wrapPhoto } from \"../wrappers\";\r\nimport AutocompleteHelper from \"./autocompleteHelper\";\r\nimport AutocompleteHelperController from \"./autocompleteHelperController\";\r\nimport Button from \"../button\";\r\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\r\nimport { MyPhoto } from \"../../lib/appManagers/appPhotosManager\";\r\nimport assumeType from \"../../helpers/assumeType\";\r\nimport GifsMasonry from \"../gifsMasonry\";\r\nimport { SuperStickerRenderer } from \"../emoticonsDropdown/tabs/stickers\";\r\nimport mediaSizes from \"../../helpers/mediaSizes\";\r\nimport readBlobAsDataURL from \"../../helpers/blob/readBlobAsDataURL\";\r\nimport setInnerHTML from \"../../helpers/dom/setInnerHTML\";\r\n\r\nconst ANIMATION_GROUP = 'INLINE-HELPER';\r\n// const GRID_ITEMS = 5;\r\n\r\nexport default class InlineHelper extends AutocompleteHelper {\r\n private scrollable: Scrollable;\r\n private lazyLoadQueue: LazyLoadQueue;\r\n private gifsMasonry: GifsMasonry;\r\n private superStickerRenderer: SuperStickerRenderer;\r\n private onChangeScreen: () => void;\r\n public checkQuery: (peerId: PeerId, username: string, query: string) => ReturnType<InlineHelper['_checkQuery']>;\r\n\r\n constructor(appendTo: HTMLElement, \r\n controller: AutocompleteHelperController,\r\n private chat: Chat,\r\n private appUsersManager: AppUsersManager,\r\n private appInlineBotsManager: AppInlineBotsManager) {\r\n super({\r\n appendTo, \r\n controller,\r\n listType: 'xy', \r\n waitForKey: ['ArrowUp', 'ArrowDown'],\r\n onSelect: (target) => {\r\n if(!target) return false; // can happen when there is only button\r\n const {peerId, botId, queryId} = this.list.dataset;\r\n return this.chat.input.getReadyToSend(() => {\r\n const queryAndResultIds = this.appInlineBotsManager.generateQId(queryId, (target as HTMLElement).dataset.resultId);\r\n this.appInlineBotsManager.sendInlineResult(peerId.toPeerId(), botId, queryAndResultIds, {\r\n ...this.chat.getMessageSendingParams(),\r\n clearDraft: true,\r\n });\r\n\r\n this.chat.input.onMessageSent(true, true);\r\n });\r\n }\r\n });\r\n\r\n this.container.classList.add('inline-helper');\r\n\r\n this.addEventListener('visible', () => {\r\n setTimeout(() => { // it is not rendered yet\r\n this.scrollable.container.scrollTop = 0;\r\n }, 0); \r\n });\r\n\r\n this.checkQuery = debounce(this._checkQuery, 200, true, true);\r\n\r\n this.addEventListener('hidden', () => {\r\n if(this.onChangeScreen) {\r\n mediaSizes.removeEventListener('changeScreen', this.onChangeScreen);\r\n this.onChangeScreen = undefined;\r\n }\r\n });\r\n }\r\n\r\n public _checkQuery = async(peerId: PeerId, username: string, query: string) => {\r\n const middleware = this.controller.getMiddleware();\r\n\r\n const peer = await this.appUsersManager.resolveUsername(username);\r\n if(!middleware()) {\r\n throw 'PEER_CHANGED';\r\n }\r\n\r\n if(peer._ !== 'user') {\r\n throw 'NOT_A_BOT';\r\n }\r\n\r\n const renderPromise = this.appInlineBotsManager.getInlineResults(peerId, peer.id, query).then(botResults => {\r\n if(!middleware()) {\r\n throw 'PEER_CHANGED';\r\n }\r\n\r\n if(this.init) {\r\n this.init();\r\n this.init = null;\r\n }\r\n\r\n const list = this.list.cloneNode() as HTMLElement;\r\n list.dataset.peerId = '' + peerId;\r\n list.dataset.botId = '' + peer.id;\r\n list.dataset.queryId = '' + botResults.query_id;\r\n\r\n const gifsMasonry = new GifsMasonry(null, ANIMATION_GROUP, this.scrollable, false);\r\n\r\n this.lazyLoadQueue.clear();\r\n this.superStickerRenderer.clear();\r\n \r\n const loadPromises: Promise<any>[] = [];\r\n const isGallery = !!botResults.pFlags.gallery;\r\n // botResults.results.length = 3;\r\n for(const item of botResults.results) {\r\n const container = document.createElement('div');\r\n container.classList.add('inline-helper-result');\r\n container.dataset.resultId = item.id;\r\n \r\n const preview = isGallery ? undefined : document.createElement('div');\r\n if(preview) {\r\n preview.classList.add('inline-helper-result-preview');\r\n\r\n container.append(preview);\r\n }\r\n\r\n list.append(container);\r\n\r\n if(!isGallery) {\r\n preview.classList.add('empty');\r\n setInnerHTML(preview, RichTextProcessor.wrapEmojiText([...item.title.trim()][0]));\r\n\r\n const title = document.createElement('div');\r\n title.classList.add('inline-helper-result-title');\r\n setInnerHTML(title, RichTextProcessor.wrapEmojiText(item.title));\r\n \r\n const description = document.createElement('div');\r\n description.classList.add('inline-helper-result-description');\r\n setInnerHTML(description, RichTextProcessor.wrapRichText(item.description, {\r\n noCommands: true,\r\n noLinks: true\r\n }));\r\n \r\n container.append(title, description);\r\n \r\n const separator = document.createElement('div');\r\n separator.classList.add('inline-helper-separator');\r\n \r\n list.append(separator);\r\n } else {\r\n container.classList.add('grid-item');\r\n }\r\n \r\n if(item._ === 'botInlineResult') {\r\n if(item.thumb && item.thumb.mime_type.indexOf('image/') === 0) {\r\n let mediaContainer: HTMLElement;\r\n if(preview) {\r\n mediaContainer = document.createElement('div');\r\n preview.append(mediaContainer);\r\n } else {\r\n mediaContainer = container;\r\n }\r\n\r\n mediaContainer.classList.add('media-container'); \r\n isGallery && mediaContainer.classList.add('no-border-radius');\r\n\r\n this.lazyLoadQueue.push({\r\n div: container,\r\n load: () => {\r\n return appDownloadManager.download({\r\n dcId: 4,\r\n location: {\r\n _: 'inputWebFileLocation',\r\n access_hash: (item.thumb as WebDocument.webDocument).access_hash,\r\n url: item.thumb.url\r\n },\r\n size: item.thumb.size,\r\n mimeType: item.thumb.mime_type\r\n }).then(blob => {\r\n const image = new Image();\r\n image.classList.add('media-photo');\r\n readBlobAsDataURL(blob).then(dataURL => {\r\n renderImageWithFadeIn(mediaContainer, image, dataURL, true);\r\n });\r\n });\r\n }\r\n });\r\n }\r\n } else {\r\n const media = item.document as MyDocument || item.photo as MyPhoto;\r\n if((['sticker', 'gif'] as MyDocument['type'][]).includes((media as MyDocument)?.type) && isGallery) {\r\n assumeType<MyDocument>(media);\r\n\r\n if(media.type === 'gif') {\r\n gifsMasonry.add(media, container);\r\n } else if(media.type === 'sticker') {\r\n container.classList.add('super-sticker');\r\n this.superStickerRenderer.renderSticker(media, container, loadPromises);\r\n if(media.sticker === 2) {\r\n this.superStickerRenderer.observeAnimatedDiv(container);\r\n }\r\n }\r\n } else if(media) {\r\n const size = isGallery ? 48 : undefined;\r\n isGallery && container.classList.add('no-border-radius');\r\n wrapPhoto({\r\n photo: media,\r\n container: isGallery ? container : preview,\r\n boxWidth: size,\r\n boxHeight: size,\r\n middleware,\r\n lazyLoadQueue: this.lazyLoadQueue,\r\n loadPromises\r\n });\r\n }\r\n }\r\n }\r\n\r\n return Promise.all(loadPromises).then(() => {\r\n if(!middleware()) {\r\n gifsMasonry.clear();\r\n return;\r\n }\r\n\r\n list.classList.toggle('is-gallery', isGallery);\r\n list.classList.toggle('super-stickers', isGallery);\r\n this.container.classList.toggle('is-gallery', isGallery);\r\n\r\n /* if(isGallery) {\r\n list.style.gridTemplateColumns = `repeat(${Math.min(botResults.results.length, 4)}, 1fr)`;\r\n }\r\n\r\n this.container.style.setProperty('width', isGallery ? `${Math.min(botResults.results.length, 4) * 25}%` : '', 'important'); */\r\n\r\n const parent = this.list.parentElement;\r\n parent.textContent = '';\r\n if(botResults.switch_pm) {\r\n const btnSwitchToPM = Button('btn-primary btn-secondary btn-primary-transparent primary');\r\n setInnerHTML(btnSwitchToPM, RichTextProcessor.wrapEmojiText(botResults.switch_pm.text));\r\n attachClickEvent(btnSwitchToPM, (e) => {\r\n this.appInlineBotsManager.switchToPM(peerId, peer.id, botResults.switch_pm.start_param);\r\n });\r\n parent.append(btnSwitchToPM);\r\n }\r\n parent.append(this.list = list);\r\n\r\n if(this.gifsMasonry) {\r\n this.gifsMasonry.detach();\r\n }\r\n this.gifsMasonry = gifsMasonry;\r\n gifsMasonry.attach();\r\n\r\n if(!this.onChangeScreen) {\r\n this.onChangeScreen = () => {\r\n if(this.list.classList.contains('is-gallery')) {\r\n const width = (this.list.childElementCount * mediaSizes.active.esgSticker.width) + (this.list.childElementCount - 1 * 1);\r\n this.list.style.width = width + 'px';\r\n } else {\r\n this.list.style.width = '';\r\n }\r\n };\r\n mediaSizes.addEventListener('changeScreen', this.onChangeScreen);\r\n }\r\n\r\n this.onChangeScreen();\r\n \r\n this.toggle(!botResults.results.length && !botResults.switch_pm);\r\n this.scrollable.scrollTop = 0;\r\n });\r\n });\r\n\r\n return {user: peer, renderPromise};\r\n };\r\n\r\n protected init() {\r\n this.list = document.createElement('div');\r\n this.list.classList.add('inline-helper-results');\r\n\r\n this.container.append(this.list);\r\n\r\n this.scrollable = new Scrollable(this.container);\r\n this.lazyLoadQueue = new LazyLoadQueue();\r\n this.superStickerRenderer = new SuperStickerRenderer(this.lazyLoadQueue, ANIMATION_GROUP);\r\n }\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport type { AppProfileManager } from \"../../lib/appManagers/appProfileManager\";\nimport type ChatInput from \"./input\";\nimport callbackify from \"../../helpers/callbackify\";\nimport AutocompletePeerHelper from \"./autocompletePeerHelper\";\nimport { processPeerFullForCommands } from \"./commandsHelper\";\n\nconst CLASS_NAME = 'bot-commands';\nexport default class ChatBotCommands extends AutocompletePeerHelper {\n private userId: UserId;\n\n constructor(\n appendTo: HTMLElement,\n private chatInput: ChatInput,\n private appProfileManager: AppProfileManager\n ) {\n super(appendTo, undefined, CLASS_NAME, (target) => {\n const innerHTML = target.querySelector(`.${AutocompletePeerHelper.BASE_CLASS_LIST_ELEMENT}-name`).innerHTML;\n return chatInput.getReadyToSend(() => {\n chatInput.messageInput.innerHTML = innerHTML;\n chatInput.sendMessage(true);\n this.toggle(true);\n });\n });\n }\n\n public setUserId(userId: UserId, middleware: () => boolean) {\n if(this.userId === userId && this.list?.childElementCount) {\n this.toggle(false);\n return;\n }\n\n this.userId = userId;\n return callbackify(this.appProfileManager.getProfile(userId), (full) => {\n if(!middleware()) return;\n const filtered = processPeerFullForCommands(full);\n \n const PADDING_TOP = 8;\n // const PADDING_BOTTOM = 8;\n const PADDING_BOTTOM = 24;\n const height = filtered.length * 50 + PADDING_TOP + PADDING_BOTTOM;\n this.container.style.setProperty('--height', height + 'px');\n\n this.render(filtered);\n \n // this.container.style.top = \n });\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport type { AppNotificationsManager } from '../../lib/appManagers/appNotificationsManager';\r\nimport type { AppChatsManager } from '../../lib/appManagers/appChatsManager';\r\nimport type { AppDocsManager, MyDocument } from \"../../lib/appManagers/appDocsManager\";\r\nimport type { AppMessagesManager } from \"../../lib/appManagers/appMessagesManager\";\r\nimport type { AppPeersManager } from '../../lib/appManagers/appPeersManager';\r\nimport type { AppWebPagesManager } from \"../../lib/appManagers/appWebPagesManager\";\r\nimport type { AppImManager } from '../../lib/appManagers/appImManager';\r\nimport type { AppDraftsManager, MyDraftMessage } from '../../lib/appManagers/appDraftsManager';\r\nimport type { AppEmojiManager } from '../../lib/appManagers/appEmojiManager';\r\nimport type { ServerTimeManager } from '../../lib/mtproto/serverTimeManager';\r\nimport type { AppUsersManager } from '../../lib/appManagers/appUsersManager';\r\nimport type { AppInlineBotsManager } from '../../lib/appManagers/appInlineBotsManager';\r\nimport type { AppMessagesIdsManager } from '../../lib/appManagers/appMessagesIdsManager';\r\nimport type Chat from './chat';\r\nimport Recorder from '../../../public/recorder.min';\r\nimport { IS_TOUCH_SUPPORTED } from \"../../environment/touchSupport\";\r\nimport apiManager from \"../../lib/mtproto/mtprotoworker\";\r\n//import Recorder from '../opus-recorder/dist/recorder.min';\r\nimport opusDecodeController from \"../../lib/opusDecodeController\";\r\nimport RichTextProcessor from \"../../lib/richtextprocessor\";\r\nimport ButtonMenu, { ButtonMenuItemOptions } from '../buttonMenu';\r\nimport emoticonsDropdown from \"../emoticonsDropdown\";\r\nimport PopupCreatePoll from \"../popups/createPoll\";\r\nimport PopupForward from '../popups/forward';\r\nimport PopupNewMedia from '../popups/newMedia';\r\nimport { toast } from \"../toast\";\r\nimport { wrapReply } from \"../wrappers\";\r\nimport InputField from '../inputField';\r\nimport { MessageEntity, DraftMessage, WebPage, Message, ChatFull, UserFull } from '../../layer';\r\nimport StickersHelper from './stickersHelper';\r\nimport ButtonIcon from '../buttonIcon';\r\nimport ButtonMenuToggle from '../buttonMenuToggle';\r\nimport ListenerSetter, { Listener } from '../../helpers/listenerSetter';\r\nimport Button from '../button';\r\nimport PopupSchedule from '../popups/schedule';\r\nimport SendMenu from './sendContextMenu';\r\nimport rootScope from '../../lib/rootScope';\r\nimport PopupPinMessage from '../popups/unpinMessage';\r\nimport { tsNow } from '../../helpers/date';\r\nimport appNavigationController, { NavigationItem } from '../appNavigationController';\r\nimport { IS_MOBILE, IS_MOBILE_SAFARI } from '../../environment/userAgent';\r\nimport I18n, { i18n, join, LangPackKey } from '../../lib/langPack';\r\nimport { generateTail } from './bubbles';\r\nimport findUpClassName from '../../helpers/dom/findUpClassName';\r\nimport ButtonCorner from '../buttonCorner';\r\nimport blurActiveElement from '../../helpers/dom/blurActiveElement';\r\nimport cancelEvent from '../../helpers/dom/cancelEvent';\r\nimport cancelSelection from '../../helpers/dom/cancelSelection';\r\nimport { attachClickEvent, simulateClickEvent } from '../../helpers/dom/clickEvent';\r\nimport getRichValue from '../../helpers/dom/getRichValue';\r\nimport isInputEmpty from '../../helpers/dom/isInputEmpty';\r\nimport isSendShortcutPressed from '../../helpers/dom/isSendShortcutPressed';\r\nimport placeCaretAtEnd from '../../helpers/dom/placeCaretAtEnd';\r\nimport { MarkdownType, markdownTags } from '../../helpers/dom/getRichElementValue';\r\nimport getRichValueWithCaret from '../../helpers/dom/getRichValueWithCaret';\r\nimport EmojiHelper from './emojiHelper';\r\nimport CommandsHelper from './commandsHelper';\r\nimport AutocompleteHelperController from './autocompleteHelperController';\r\nimport AutocompleteHelper from './autocompleteHelper';\r\nimport MentionsHelper from './mentionsHelper';\r\nimport fixSafariStickyInput from '../../helpers/dom/fixSafariStickyInput';\r\nimport { emojiFromCodePoints } from '../../vendor/emoji';\r\nimport ReplyKeyboard from './replyKeyboard';\r\nimport InlineHelper from './inlineHelper';\r\nimport debounce from '../../helpers/schedulers/debounce';\r\nimport noop from '../../helpers/noop';\r\nimport { openBtnMenu, putPreloader } from '../misc';\r\nimport SetTransition from '../singleTransition';\r\nimport PeerTitle from '../peerTitle';\r\nimport { fastRaf } from '../../helpers/schedulers';\r\nimport PopupDeleteMessages from '../popups/deleteMessages';\r\nimport fixSafariStickyInputFocusing, { IS_STICKY_INPUT_BUGGED } from '../../helpers/dom/fixSafariStickyInputFocusing';\r\nimport PopupPeer from '../popups/peer';\r\nimport MEDIA_MIME_TYPES_SUPPORTED from '../../environment/mediaMimeTypesSupport';\r\nimport appMediaPlaybackController from '../appMediaPlaybackController';\r\nimport { BOT_START_PARAM, NULL_PEER_ID } from '../../lib/mtproto/mtproto_config';\r\nimport setCaretAt from '../../helpers/dom/setCaretAt';\r\nimport CheckboxField from '../checkboxField';\r\nimport DropdownHover from '../../helpers/dropdownHover';\r\nimport RadioForm from '../radioForm';\r\nimport findUpTag from '../../helpers/dom/findUpTag';\r\nimport toggleDisability from '../../helpers/dom/toggleDisability';\r\nimport AvatarElement from '../avatar';\r\nimport type { AppProfileManager } from '../../lib/appManagers/appProfileManager';\r\nimport callbackify from '../../helpers/callbackify';\r\nimport ChatBotCommands from './botCommands';\r\nimport copy from '../../helpers/object/copy';\r\nimport indexOfAndSplice from '../../helpers/array/indexOfAndSplice';\r\nimport toHHMMSS from '../../helpers/string/toHHMMSS';\r\nimport documentFragmentToHTML from '../../helpers/dom/documentFragmentToHTML';\r\n\r\nconst RECORD_MIN_TIME = 500;\r\nconst POSTING_MEDIA_NOT_ALLOWED = 'Posting media content isn\\'t allowed in this group.';\r\n\r\nconst SEND_AS_ANIMATION_DURATION = 300;\r\n\r\ntype ChatInputHelperType = 'edit' | 'webpage' | 'forward' | 'reply';\r\n\r\nexport default class ChatInput {\r\n // private static AUTO_COMPLETE_REG_EXP = /(\\s|^)((?::|.)(?!.*[:@]).*|(?:[@\\/]\\S*))$/;\r\n private static AUTO_COMPLETE_REG_EXP = /(\\s|^)((?:(?:@|^\\/)\\S*)|(?::|^[^:@\\/])(?!.*[:@\\/]).*)$/;\r\n public messageInput: HTMLElement;\r\n public messageInputField: InputField;\r\n private fileInput: HTMLInputElement;\r\n private inputMessageContainer: HTMLDivElement;\r\n private btnSend: HTMLButtonElement;\r\n private btnCancelRecord: HTMLButtonElement;\r\n private lastUrl = '';\r\n private lastTimeType = 0;\r\n\r\n public chatInput: HTMLElement;\r\n public inputContainer: HTMLElement;\r\n public rowsWrapper: HTMLDivElement;\r\n private newMessageWrapper: HTMLDivElement;\r\n private btnToggleEmoticons: HTMLButtonElement;\r\n private btnToggleReplyMarkup: HTMLButtonElement;\r\n private btnSendContainer: HTMLDivElement;\r\n\r\n private replyKeyboard: ReplyKeyboard;\r\n\r\n private attachMenu: HTMLElement;\r\n private attachMenuButtons: (ButtonMenuItemOptions & {verify: (peerId: PeerId, threadId: number) => boolean})[];\r\n\r\n private sendMenu: SendMenu;\r\n\r\n private replyElements: {\r\n container: HTMLElement,\r\n cancelBtn: HTMLButtonElement,\r\n iconBtn: HTMLButtonElement\r\n } = {} as any;\r\n\r\n private forwardElements: {\r\n changePeer: ButtonMenuItemOptions,\r\n showSender: ButtonMenuItemOptions,\r\n hideSender: ButtonMenuItemOptions,\r\n showCaption: ButtonMenuItemOptions,\r\n hideCaption: ButtonMenuItemOptions,\r\n container: HTMLElement,\r\n modifyArgs?: ButtonMenuItemOptions[]\r\n }; \r\n private forwardHover: DropdownHover;\r\n private forwardWasDroppingAuthor: boolean;\r\n\r\n private getWebPagePromise: Promise<void>;\r\n private willSendWebPage: WebPage = null;\r\n private forwarding: {[fromPeerId: PeerId]: number[]};\r\n public replyToMsgId: number;\r\n public editMsgId: number;\r\n public editMessage: Message.message;\r\n private noWebPage: true;\r\n public scheduleDate: number;\r\n public sendSilent: true;\r\n public startParam: string;\r\n\r\n private recorder: any;\r\n public recording = false;\r\n private recordCanceled = false;\r\n private recordTimeEl: HTMLElement;\r\n private recordRippleEl: HTMLElement;\r\n private recordStartTime = 0;\r\n private recordingOverlayListener: Listener;\r\n private recordingNavigationItem: NavigationItem;\r\n\r\n // private scrollTop = 0;\r\n // private scrollOffsetTop = 0;\r\n // private scrollDiff = 0;\r\n\r\n public helperType: Exclude<ChatInputHelperType, 'webpage'>;\r\n private helperFunc: () => void;\r\n private helperWaitingForward: boolean;\r\n\r\n public willAttachType: 'document' | 'media';\r\n\r\n private lockRedo = false;\r\n private canRedoFromHTML = '';\r\n private readonly undoHistory: string[] = [];\r\n private readonly executedHistory: string[] = [];\r\n private canUndoFromHTML = '';\r\n\r\n private autocompleteHelperController: AutocompleteHelperController;\r\n private stickersHelper: StickersHelper;\r\n private emojiHelper: EmojiHelper;\r\n private commandsHelper: CommandsHelper;\r\n private mentionsHelper: MentionsHelper;\r\n private inlineHelper: InlineHelper;\r\n private listenerSetter: ListenerSetter;\r\n\r\n private pinnedControlBtn: HTMLButtonElement;\r\n\r\n private goDownBtn: HTMLButtonElement;\r\n private goDownUnreadBadge: HTMLElement;\r\n private goMentionBtn: HTMLButtonElement;\r\n private goMentionUnreadBadge: HTMLSpanElement;\r\n private btnScheduled: HTMLButtonElement;\r\n\r\n private btnPreloader: HTMLButtonElement;\r\n\r\n private saveDraftDebounced: () => void;\r\n\r\n private fakeRowsWrapper: HTMLDivElement;\r\n\r\n private previousQuery: string;\r\n \r\n private releaseMediaPlayback: () => void;\r\n\r\n private botStartBtn: HTMLButtonElement;\r\n private rowsWrapperWrapper: HTMLDivElement;\r\n private controlContainer: HTMLElement;\r\n private fakeSelectionWrapper: HTMLDivElement;\r\n\r\n private fakeWrapperTo: HTMLElement;\r\n private toggleBotStartBtnDisability: () => void;\r\n\r\n private sendAsAvatar: AvatarElement;\r\n private sendAsContainer: HTMLElement;\r\n private sendAsCloseBtn: HTMLElement;\r\n private sendAsBtnMenu: HTMLElement;\r\n private sendAsPeerIds: PeerId[];\r\n public sendAsPeerId: PeerId;\r\n private updatingSendAsPromise: Promise<void>;\r\n\r\n private botCommandsToggle: HTMLElement;\r\n private botCommands: ChatBotCommands;\r\n private botCommandsIcon: HTMLDivElement;\r\n private hasBotCommands: number;\r\n\r\n // private activeContainer: HTMLElement;\r\n\r\n constructor(\r\n private chat: Chat, \r\n private appMessagesManager: AppMessagesManager, \r\n private appMessagesIdsManager: AppMessagesIdsManager, \r\n private appDocsManager: AppDocsManager, \r\n private appChatsManager: AppChatsManager, \r\n private appPeersManager: AppPeersManager, \r\n private appWebPagesManager: AppWebPagesManager, \r\n private appImManager: AppImManager, \r\n private appDraftsManager: AppDraftsManager, \r\n private serverTimeManager: ServerTimeManager, \r\n private appNotificationsManager: AppNotificationsManager,\r\n private appEmojiManager: AppEmojiManager,\r\n private appUsersManager: AppUsersManager,\r\n private appInlineBotsManager: AppInlineBotsManager,\r\n private appProfileManager: AppProfileManager\r\n ) {\r\n this.listenerSetter = new ListenerSetter();\r\n }\r\n\r\n public construct() {\r\n this.chatInput = document.createElement('div');\r\n this.chatInput.classList.add('chat-input');\r\n this.chatInput.style.display = 'none';\r\n\r\n this.inputContainer = document.createElement('div');\r\n this.inputContainer.classList.add('chat-input-container');\r\n\r\n this.rowsWrapperWrapper = document.createElement('div');\r\n this.rowsWrapperWrapper.classList.add('rows-wrapper-wrapper');\r\n\r\n this.rowsWrapper = document.createElement('div');\r\n this.rowsWrapper.classList.add('rows-wrapper', 'chat-input-wrapper');\r\n\r\n this.rowsWrapperWrapper.append(this.rowsWrapper);\r\n\r\n const tail = generateTail();\r\n this.rowsWrapper.append(tail);\r\n\r\n const fakeRowsWrapper = this.fakeRowsWrapper = document.createElement('div');\r\n fakeRowsWrapper.classList.add('fake-wrapper', 'fake-rows-wrapper');\r\n\r\n const fakeSelectionWrapper = this.fakeSelectionWrapper = document.createElement('div');\r\n fakeSelectionWrapper.classList.add('fake-wrapper', 'fake-selection-wrapper');\r\n\r\n this.inputContainer.append(this.rowsWrapperWrapper, fakeRowsWrapper, fakeSelectionWrapper);\r\n this.chatInput.append(this.inputContainer);\r\n\r\n this.goDownBtn = ButtonCorner({icon: 'arrow_down', className: 'bubbles-corner-button bubbles-go-down hide'});\r\n this.inputContainer.append(this.goDownBtn);\r\n\r\n attachClickEvent(this.goDownBtn, (e) => {\r\n cancelEvent(e);\r\n this.chat.bubbles.onGoDownClick();\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n // * constructor end\r\n\r\n /* let setScrollTopTimeout: number;\r\n // @ts-ignore\r\n let height = window.visualViewport.height; */\r\n // @ts-ignore\r\n // this.listenerSetter.add(window.visualViewport)('resize', () => {\r\n // const scrollable = this.chat.bubbles.scrollable;\r\n // const wasScrolledDown = scrollable.isScrolledDown;\r\n \r\n // /* if(wasScrolledDown) {\r\n // this.saveScroll();\r\n // } */\r\n \r\n // // @ts-ignore\r\n // let newHeight = window.visualViewport.height;\r\n // const diff = height - newHeight;\r\n // const scrollTop = scrollable.scrollTop;\r\n // const needScrollTop = wasScrolledDown ? scrollable.scrollHeight : scrollTop + diff; // * wasScrolledDown это проверка для десктоп хрома, когда пропадает панель загрузок снизу\r\n\r\n // console.log('resize before', scrollable.scrollTop, scrollable.container.clientHeight, scrollable.scrollHeight, wasScrolledDown, scrollable.lastScrollTop, diff, needScrollTop);\r\n\r\n // scrollable.scrollTop = needScrollTop;\r\n\r\n // if(setScrollTopTimeout) clearTimeout(setScrollTopTimeout);\r\n // setScrollTopTimeout = window.setTimeout(() => {\r\n // const diff = height - newHeight;\r\n // const isScrolledDown = scrollable.scrollHeight - Math.round(scrollable.scrollTop + scrollable.container.offsetHeight + diff) <= 1;\r\n // height = newHeight;\r\n\r\n // scrollable.scrollTop = needScrollTop;\r\n \r\n // console.log('resize after', scrollable.scrollTop, scrollable.container.clientHeight, scrollable.scrollHeight, scrollable.isScrolledDown, scrollable.lastScrollTop, isScrolledDown);\r\n\r\n // /* if(isScrolledDown) {\r\n // scrollable.scrollTop = scrollable.scrollHeight;\r\n // } */\r\n\r\n // //scrollable.scrollTop += diff;\r\n // setScrollTopTimeout = 0;\r\n // }, 0);\r\n // });\r\n\r\n // ! Can't use it with resizeObserver\r\n /* this.listenerSetter.add(window.visualViewport)('resize', () => {\r\n const scrollable = this.chat.bubbles.scrollable;\r\n const wasScrolledDown = scrollable.isScrolledDown;\r\n\r\n // @ts-ignore\r\n let newHeight = window.visualViewport.height;\r\n const diff = height - newHeight;\r\n const needScrollTop = wasScrolledDown ? scrollable.scrollHeight : scrollable.scrollTop + diff; // * wasScrolledDown это проверка для десктоп хрома, когда пропадает панель загрузок снизу\r\n\r\n //console.log('resize before', scrollable.scrollTop, scrollable.container.clientHeight, scrollable.scrollHeight, wasScrolledDown, scrollable.lastScrollTop, diff, needScrollTop);\r\n\r\n scrollable.scrollTop = needScrollTop;\r\n height = newHeight;\r\n\r\n if(setScrollTopTimeout) clearTimeout(setScrollTopTimeout);\r\n setScrollTopTimeout = window.setTimeout(() => { // * try again for scrolled down Android Chrome\r\n scrollable.scrollTop = needScrollTop;\r\n \r\n //console.log('resize after', scrollable.scrollTop, scrollable.container.clientHeight, scrollable.scrollHeight, scrollable.isScrolledDown, scrollable.lastScrollTop, isScrolledDown);\r\n setScrollTopTimeout = 0;\r\n }, 0);\r\n }); */\r\n\r\n const c = this.controlContainer = document.createElement('div');\r\n c.classList.add('chat-input-control', 'chat-input-wrapper');\r\n this.inputContainer.append(c);\r\n }\r\n\r\n public constructPeerHelpers() {\r\n this.replyElements.container = document.createElement('div');\r\n this.replyElements.container.classList.add('reply-wrapper');\r\n\r\n this.replyElements.iconBtn = ButtonIcon('');\r\n this.replyElements.cancelBtn = ButtonIcon('close reply-cancel', {noRipple: true});\r\n\r\n this.replyElements.container.append(this.replyElements.iconBtn, this.replyElements.cancelBtn);\r\n\r\n //\r\n\r\n const onHideAuthorClick = () => {\r\n isChangingAuthor = true;\r\n return this.canToggleHideAuthor();\r\n };\r\n\r\n const onHideCaptionClick = () => {\r\n isChangingAuthor = false;\r\n };\r\n\r\n const forwardElements: ChatInput['forwardElements'] = this.forwardElements = {} as any;\r\n let isChangingAuthor = false;\r\n const forwardButtons: ButtonMenuItemOptions[] = [\r\n forwardElements.showSender = {\r\n text: 'Chat.Alert.Forward.Action.Show1',\r\n onClick: onHideAuthorClick,\r\n checkboxField: new CheckboxField({checked: true})\r\n },\r\n forwardElements.hideSender = {\r\n text: 'Chat.Alert.Forward.Action.Hide1',\r\n onClick: onHideAuthorClick,\r\n checkboxField: new CheckboxField({checked: false})\r\n },\r\n forwardElements.showCaption = {\r\n text: 'Chat.Alert.Forward.Action.ShowCaption',\r\n onClick: onHideCaptionClick,\r\n checkboxField: new CheckboxField({checked: true})\r\n },\r\n forwardElements.hideCaption = {\r\n text: 'Chat.Alert.Forward.Action.HideCaption',\r\n onClick: onHideCaptionClick,\r\n checkboxField: new CheckboxField({checked: false})\r\n },\r\n forwardElements.changePeer = {\r\n text: 'Chat.Alert.Forward.Action.Another',\r\n onClick: () => {\r\n this.changeForwardRecipient();\r\n },\r\n icon: 'replace'\r\n }\r\n ];\r\n const forwardBtnMenu = forwardElements.container = ButtonMenu(forwardButtons, this.listenerSetter);\r\n // forwardBtnMenu.classList.add('top-center');\r\n\r\n const children = Array.from(forwardBtnMenu.children) as HTMLElement[];\r\n const groups: {\r\n elements: HTMLElement[],\r\n onChange: (value: string, event: Event) => void\r\n }[] = [{\r\n elements: children.slice(0, 2),\r\n onChange: (value, e) => {\r\n const checked = !!+value;\r\n if(isChangingAuthor) {\r\n this.forwardWasDroppingAuthor = !checked;\r\n }\r\n\r\n const replyTitle = this.replyElements.container.querySelector('.reply-title');\r\n if(replyTitle) {\r\n const el = replyTitle.firstElementChild as HTMLElement;\r\n const i = I18n.weakMap.get(el) as I18n.IntlElement;\r\n const langPackKey: LangPackKey = forwardElements.showSender.checkboxField.checked ? 'Chat.Accessory.Forward' : 'Chat.Accessory.Hidden';\r\n i.key = langPackKey;\r\n i.update();\r\n }\r\n }\r\n }, {\r\n elements: children.slice(2, 4),\r\n onChange: (value) => {\r\n const checked = !!+value;\r\n let b: ButtonMenuItemOptions;\r\n if(checked && this.forwardWasDroppingAuthor !== undefined) {\r\n b = this.forwardWasDroppingAuthor ? forwardElements.hideSender : forwardElements.showSender;\r\n } else {\r\n b = checked ? forwardElements.showSender : forwardElements.hideSender;\r\n }\r\n\r\n b.checkboxField.checked = true;\r\n }\r\n }];\r\n groups.forEach(group => {\r\n const container = RadioForm(group.elements.map(e => {\r\n return {\r\n container: e, \r\n input: e.querySelector('input')\r\n };\r\n }), group.onChange);\r\n\r\n const hr = document.createElement('hr');\r\n container.append(hr);\r\n forwardBtnMenu.append(container);\r\n });\r\n\r\n forwardBtnMenu.append(forwardElements.changePeer.element);\r\n\r\n if(!IS_TOUCH_SUPPORTED) {\r\n const forwardHover = this.forwardHover = new DropdownHover({\r\n element: forwardBtnMenu\r\n });\r\n }\r\n\r\n forwardElements.modifyArgs = forwardButtons.slice(0, -1);\r\n this.replyElements.container.append(forwardBtnMenu);\r\n\r\n forwardElements.modifyArgs.forEach((b, idx) => {\r\n const {input} = b.checkboxField;\r\n input.type = 'radio';\r\n input.name = idx < 2 ? 'author' : 'caption';\r\n input.value = '' + +!(idx % 2);\r\n });\r\n\r\n //\r\n\r\n this.newMessageWrapper = document.createElement('div');\r\n this.newMessageWrapper.classList.add('new-message-wrapper');\r\n\r\n this.sendAsContainer = document.createElement('div');\r\n this.sendAsContainer.classList.add('new-message-send-as-container');\r\n\r\n this.sendAsCloseBtn = document.createElement('div');\r\n this.sendAsCloseBtn.classList.add('new-message-send-as-close', 'new-message-send-as-avatar', 'tgico-close');\r\n\r\n const sendAsButtons: ButtonMenuItemOptions[] = [{\r\n text: 'SendMessageAsTitle',\r\n onClick: undefined\r\n }];\r\n\r\n let previousAvatar: HTMLElement;\r\n const onSendAsMenuToggle = (visible: boolean) => {\r\n if(visible) {\r\n previousAvatar = this.sendAsAvatar;\r\n }\r\n\r\n const isChanged = this.sendAsAvatar !== previousAvatar;\r\n const useRafs = !visible && isChanged ? 2 : 0;\r\n\r\n SetTransition(this.sendAsCloseBtn, 'is-visible', visible, SEND_AS_ANIMATION_DURATION, undefined, useRafs);\r\n if(!isChanged) {\r\n SetTransition(previousAvatar, 'is-visible', !visible, SEND_AS_ANIMATION_DURATION, undefined, useRafs);\r\n }\r\n };\r\n\r\n ButtonMenuToggle({\r\n noRipple: true, \r\n listenerSetter: this.listenerSetter, \r\n container: this.sendAsContainer\r\n }, 'top-right', sendAsButtons, () => {\r\n onSendAsMenuToggle(true);\r\n }, () => {\r\n onSendAsMenuToggle(false);\r\n });\r\n\r\n sendAsButtons[0].element.classList.add('btn-menu-item-header');\r\n this.sendAsBtnMenu = this.sendAsContainer.firstElementChild as any;\r\n this.sendAsBtnMenu.classList.add('scrollable', 'scrollable-y');\r\n this.sendAsContainer.append(this.sendAsCloseBtn);\r\n\r\n this.btnToggleEmoticons = ButtonIcon('none toggle-emoticons', {noRipple: true});\r\n\r\n this.inputMessageContainer = document.createElement('div');\r\n this.inputMessageContainer.classList.add('input-message-container');\r\n\r\n if(this.chat.type === 'chat') {\r\n this.goDownUnreadBadge = document.createElement('span');\r\n this.goDownUnreadBadge.classList.add('badge', 'badge-24', 'badge-primary');\r\n this.goDownBtn.append(this.goDownUnreadBadge);\r\n\r\n this.goMentionBtn = ButtonCorner({icon: 'mention', className: 'bubbles-corner-button bubbles-go-mention'});\r\n this.goMentionUnreadBadge = document.createElement('span');\r\n this.goMentionUnreadBadge.classList.add('badge', 'badge-24', 'badge-primary');\r\n this.goMentionBtn.append(this.goMentionUnreadBadge);\r\n this.inputContainer.append(this.goMentionBtn);\r\n\r\n attachClickEvent(this.goMentionBtn, (e) => {\r\n cancelEvent(e);\r\n this.appMessagesManager.goToNextMention(this.chat.peerId);\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n this.btnScheduled = ButtonIcon('scheduled btn-scheduled float hide', {noRipple: true});\r\n\r\n attachClickEvent(this.btnScheduled, (e) => {\r\n this.appImManager.openScheduled(this.chat.peerId);\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n this.listenerSetter.add(rootScope)('scheduled_new', ({peerId}) => {\r\n if(this.chat.peerId !== peerId) {\r\n return;\r\n }\r\n\r\n this.btnScheduled.classList.remove('hide');\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('scheduled_delete', ({peerId}) => {\r\n if(this.chat.peerId !== peerId) {\r\n return;\r\n }\r\n\r\n this.appMessagesManager.getScheduledMessages(this.chat.peerId).then(value => {\r\n this.btnScheduled.classList.toggle('hide', !value.length);\r\n });\r\n });\r\n\r\n this.btnToggleReplyMarkup = ButtonIcon('botcom toggle-reply-markup float hide', {noRipple: true});\r\n this.replyKeyboard = new ReplyKeyboard({\r\n appendTo: this.rowsWrapper,\r\n listenerSetter: this.listenerSetter,\r\n appMessagesManager: this.appMessagesManager,\r\n btnHover: this.btnToggleReplyMarkup,\r\n chatInput: this\r\n });\r\n this.listenerSetter.add(this.replyKeyboard)('open', () => this.btnToggleReplyMarkup.classList.add('active'));\r\n this.listenerSetter.add(this.replyKeyboard)('close', () => this.btnToggleReplyMarkup.classList.remove('active'));\r\n\r\n this.botCommands = new ChatBotCommands(this.rowsWrapper, this, this.appProfileManager);\r\n this.botCommandsToggle = document.createElement('div');\r\n this.botCommandsToggle.classList.add('new-message-bot-commands');\r\n\r\n const scaler = document.createElement('div');\r\n scaler.classList.add('new-message-bot-commands-icon-scale');\r\n\r\n const icon = this.botCommandsIcon = document.createElement('div');\r\n icon.classList.add('animated-menu-icon', 'animated-menu-close-icon');\r\n scaler.append(icon);\r\n this.botCommandsToggle.append(scaler);\r\n\r\n attachClickEvent(this.botCommandsToggle, (e) => {\r\n cancelEvent(e);\r\n const isShown = icon.classList.contains('state-back');\r\n if(isShown) {\r\n this.botCommands.toggle(true);\r\n icon.classList.remove('state-back');\r\n } else {\r\n this.botCommands.setUserId(this.chat.peerId.toUserId(), this.chat.bubbles.getMiddleware());\r\n icon.classList.add('state-back');\r\n }\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n this.botCommands.addEventListener('visible', () => {\r\n icon.classList.add('state-back');\r\n });\r\n\r\n this.botCommands.addEventListener('hiding', () => {\r\n icon.classList.remove('state-back');\r\n });\r\n }\r\n\r\n this.attachMenuButtons = [{\r\n icon: 'image',\r\n text: 'Chat.Input.Attach.PhotoOrVideo',\r\n onClick: () => {\r\n this.fileInput.value = '';\r\n const accept = [...MEDIA_MIME_TYPES_SUPPORTED].join(', ');\r\n this.fileInput.setAttribute('accept', accept);\r\n this.willAttachType = 'media';\r\n this.fileInput.click();\r\n },\r\n verify: () => this.chat.canSend('send_media')\r\n }, {\r\n icon: 'document',\r\n text: 'Chat.Input.Attach.Document',\r\n onClick: () => {\r\n this.fileInput.value = '';\r\n this.fileInput.removeAttribute('accept');\r\n this.willAttachType = 'document';\r\n this.fileInput.click();\r\n },\r\n verify: () => this.chat.canSend('send_media')\r\n }, {\r\n icon: 'poll',\r\n text: 'Poll',\r\n onClick: () => {\r\n new PopupCreatePoll(this.chat).show();\r\n },\r\n verify: (peerId) => peerId.isAnyChat() && this.chat.canSend('send_polls')\r\n }];\r\n\r\n this.attachMenu = ButtonMenuToggle({noRipple: true, listenerSetter: this.listenerSetter}, 'top-left', this.attachMenuButtons);\r\n this.attachMenu.classList.add('attach-file', 'tgico-attach');\r\n this.attachMenu.classList.remove('tgico-more');\r\n\r\n //this.inputContainer.append(this.sendMenu);\r\n\r\n this.recordTimeEl = document.createElement('div');\r\n this.recordTimeEl.classList.add('record-time');\r\n\r\n this.fileInput = document.createElement('input');\r\n this.fileInput.type = 'file';\r\n this.fileInput.multiple = true;\r\n this.fileInput.style.display = 'none';\r\n\r\n this.newMessageWrapper.append(...[this.sendAsContainer, this.botCommandsToggle, this.btnToggleEmoticons, this.inputMessageContainer, this.btnScheduled, this.btnToggleReplyMarkup, this.attachMenu, this.recordTimeEl, this.fileInput].filter(Boolean));\r\n\r\n this.rowsWrapper.append(this.replyElements.container);\r\n this.autocompleteHelperController = new AutocompleteHelperController();\r\n this.stickersHelper = new StickersHelper(this.rowsWrapper, this.autocompleteHelperController);\r\n this.emojiHelper = new EmojiHelper(this.rowsWrapper, this.autocompleteHelperController, this, this.appEmojiManager);\r\n this.commandsHelper = new CommandsHelper(this.rowsWrapper, this.autocompleteHelperController, this, this.chat.appProfileManager, this.chat.appUsersManager);\r\n this.mentionsHelper = new MentionsHelper(this.rowsWrapper, this.autocompleteHelperController, this, this.chat.appProfileManager, this.chat.appUsersManager);\r\n this.inlineHelper = new InlineHelper(this.rowsWrapper, this.autocompleteHelperController, this.chat, this.appUsersManager, this.appInlineBotsManager);\r\n this.rowsWrapper.append(this.newMessageWrapper);\r\n\r\n this.btnCancelRecord = ButtonIcon('delete btn-circle z-depth-1 btn-record-cancel');\r\n\r\n this.btnSendContainer = document.createElement('div');\r\n this.btnSendContainer.classList.add('btn-send-container');\r\n\r\n this.recordRippleEl = document.createElement('div');\r\n this.recordRippleEl.classList.add('record-ripple');\r\n\r\n this.btnSend = ButtonIcon('none btn-circle z-depth-1 btn-send animated-button-icon');\r\n this.btnSend.insertAdjacentHTML('afterbegin', `\r\n <span class=\"tgico tgico-send\"></span>\r\n <span class=\"tgico tgico-schedule\"></span>\r\n <span class=\"tgico tgico-check\"></span>\r\n <span class=\"tgico tgico-microphone_filled\"></span>\r\n `);\r\n\r\n this.btnSendContainer.append(this.recordRippleEl, this.btnSend);\r\n\r\n if(this.chat.type !== 'scheduled') {\r\n this.sendMenu = new SendMenu({\r\n onSilentClick: () => {\r\n this.sendSilent = true;\r\n this.sendMessage();\r\n },\r\n onScheduleClick: () => {\r\n this.scheduleSending(undefined);\r\n },\r\n listenerSetter: this.listenerSetter,\r\n openSide: 'top-left',\r\n onContextElement: this.btnSend,\r\n onOpen: () => {\r\n return !this.isInputEmpty() || !!Object.keys(this.forwarding).length;\r\n }\r\n });\r\n \r\n this.btnSendContainer.append(this.sendMenu.sendMenu);\r\n }\r\n\r\n this.inputContainer.append(this.btnCancelRecord, this.btnSendContainer);\r\n\r\n emoticonsDropdown.attachButtonListener(this.btnToggleEmoticons, this.listenerSetter);\r\n this.listenerSetter.add(emoticonsDropdown)('open', this.onEmoticonsOpen);\r\n this.listenerSetter.add(emoticonsDropdown)('close', this.onEmoticonsClose);\r\n\r\n this.attachMessageInputField();\r\n\r\n /* this.attachMenu.addEventListener('mousedown', (e) => {\r\n const hidden = this.attachMenu.querySelectorAll('.hide');\r\n if(hidden.length === this.attachMenuButtons.length) {\r\n toast(POSTING_MEDIA_NOT_ALLOWED);\r\n cancelEvent(e);\r\n return false;\r\n }\r\n }, {passive: false, capture: true}); */\r\n\r\n this.listenerSetter.add(rootScope)('settings_updated', () => {\r\n if(this.stickersHelper || this.emojiHelper) {\r\n // this.previousQuery = undefined;\r\n this.previousQuery = '';\r\n this.checkAutocomplete();\r\n /* if(!rootScope.settings.stickers.suggest) {\r\n this.stickersHelper.checkEmoticon('');\r\n } else {\r\n this.onMessageInput();\r\n } */\r\n }\r\n\r\n if(this.messageInputField) {\r\n this.messageInputField.onFakeInput();\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('draft_updated', ({peerId, threadId, draft, force}) => {\r\n if(this.chat.threadId !== threadId || this.chat.peerId !== peerId) return;\r\n this.setDraft(draft, true, force);\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('peer_changing', (chat) => {\r\n if(this.chat === chat) {\r\n this.saveDraft();\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('chat_changing', ({from, to}) => {\r\n if(this.chat === from) {\r\n this.autocompleteHelperController.toggleListNavigation(false);\r\n } else if(this.chat === to) {\r\n this.autocompleteHelperController.toggleListNavigation(true);\r\n }\r\n });\r\n\r\n if(this.sendAsContainer) {\r\n this.listenerSetter.add(rootScope)('peer_full_update', (peerId) => {\r\n if(peerId.isChannel() && this.chat.peerId === peerId) {\r\n this.updateSendAs();\r\n }\r\n });\r\n }\r\n\r\n if(this.chat.type === 'scheduled') {\r\n this.listenerSetter.add(rootScope)('scheduled_delete', ({peerId, mids}) => {\r\n if(this.chat.peerId === peerId && mids.includes(this.editMsgId)) {\r\n this.onMessageSent();\r\n }\r\n });\r\n } else {\r\n this.listenerSetter.add(rootScope)('history_delete', ({peerId, msgs}) => {\r\n if(this.chat.peerId === peerId) {\r\n if(msgs.has(this.editMsgId)) {\r\n this.onMessageSent();\r\n }\r\n\r\n if(this.replyToMsgId && msgs.has(this.replyToMsgId)) {\r\n this.clearHelper('reply');\r\n }\r\n\r\n /* if(this.chat.isStartButtonNeeded()) {\r\n this.setStartParam(BOT_START_PARAM);\r\n } */\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('dialogs_multiupdate', (dialogs) => {\r\n if(dialogs[this.chat.peerId]) {\r\n if(this.startParam === BOT_START_PARAM) {\r\n this.setStartParam();\r\n } else { // updateNewMessage comes earlier than dialog appers\r\n this.center(true);\r\n }\r\n }\r\n });\r\n }\r\n\r\n try {\r\n this.recorder = new Recorder({\r\n //encoderBitRate: 32,\r\n //encoderPath: \"../dist/encoderWorker.min.js\",\r\n encoderSampleRate: 48000,\r\n monitorGain: 0,\r\n numberOfChannels: 1,\r\n recordingGain: 1,\r\n reuseWorker: true\r\n });\r\n } catch(err) {\r\n console.error('Recorder constructor error:', err);\r\n }\r\n\r\n this.updateSendBtn();\r\n\r\n this.listenerSetter.add(this.fileInput)('change', (e) => {\r\n let files = (e.target as HTMLInputElement & EventTarget).files;\r\n if(!files.length) {\r\n return;\r\n }\r\n \r\n new PopupNewMedia(this.chat, Array.from(files).slice(), this.willAttachType);\r\n this.fileInput.value = '';\r\n }, false);\r\n\r\n /* let time = Date.now();\r\n this.btnSend.addEventListener('touchstart', (e) => {\r\n time = Date.now();\r\n });\r\n\r\n let eventName1 = 'touchend';\r\n this.btnSend.addEventListener(eventName1, (e: Event) => {\r\n //cancelEvent(e);\r\n console.log(eventName1 + ', time: ' + (Date.now() - time));\r\n });\r\n\r\n let eventName = 'mousedown';\r\n this.btnSend.addEventListener(eventName, (e: Event) => {\r\n cancelEvent(e);\r\n console.log(eventName + ', time: ' + (Date.now() - time));\r\n }); */\r\n attachClickEvent(this.btnSend, this.onBtnSendClick, {listenerSetter: this.listenerSetter, touchMouseDown: true});\r\n\r\n if(this.recorder) {\r\n attachClickEvent(this.btnCancelRecord, this.onCancelRecordClick, {listenerSetter: this.listenerSetter});\r\n\r\n this.recorder.onstop = () => {\r\n this.setRecording(false);\r\n this.chatInput.classList.remove('is-locked');\r\n this.recordRippleEl.style.transform = '';\r\n };\r\n \r\n this.recorder.ondataavailable = (typedArray: Uint8Array) => {\r\n if(this.releaseMediaPlayback) {\r\n this.releaseMediaPlayback();\r\n this.releaseMediaPlayback = undefined;\r\n }\r\n\r\n if(this.recordingOverlayListener) {\r\n this.listenerSetter.remove(this.recordingOverlayListener);\r\n this.recordingOverlayListener = undefined;\r\n }\r\n\r\n if(this.recordingNavigationItem) {\r\n appNavigationController.removeItem(this.recordingNavigationItem);\r\n this.recordingNavigationItem = undefined;\r\n }\r\n\r\n if(this.recordCanceled) {\r\n return;\r\n }\r\n\r\n const {peerId, threadId} = this.chat;\r\n const replyToMsgId = this.replyToMsgId;\r\n \r\n const duration = (Date.now() - this.recordStartTime) / 1000 | 0;\r\n const dataBlob = new Blob([typedArray], {type: 'audio/ogg'});\r\n /* const fileName = new Date().toISOString() + \".opus\";\r\n console.log('Recorder data received', typedArray, dataBlob); */\r\n\r\n //let perf = performance.now();\r\n opusDecodeController.decode(typedArray, true).then(result => {\r\n //console.log('WAVEFORM!:', /* waveform, */performance.now() - perf);\r\n \r\n opusDecodeController.setKeepAlive(false);\r\n \r\n // тут objectURL ставится уже с audio/wav\r\n this.appMessagesManager.sendFile(peerId, dataBlob, {\r\n isVoiceMessage: true,\r\n isMedia: true,\r\n duration,\r\n waveform: result.waveform,\r\n objectURL: result.url,\r\n replyToMsgId,\r\n threadId,\r\n clearDraft: true\r\n });\r\n\r\n this.onMessageSent(false, true);\r\n });\r\n };\r\n }\r\n\r\n attachClickEvent(this.replyElements.cancelBtn, this.onHelperCancel, {listenerSetter: this.listenerSetter});\r\n attachClickEvent(this.replyElements.container, this.onHelperClick, {listenerSetter: this.listenerSetter});\r\n\r\n this.saveDraftDebounced = debounce(() => this.saveDraft(), 2500, false, true);\r\n\r\n this.botStartBtn = Button('btn-primary btn-transparent text-bold chat-input-control-button');\r\n this.botStartBtn.append(i18n('BotStart'));\r\n\r\n attachClickEvent(this.botStartBtn, () => {\r\n const {startParam} = this;\r\n if(startParam === undefined) {\r\n return;\r\n }\r\n\r\n const toggle = this.toggleBotStartBtnDisability = toggleDisability([this.botStartBtn], true);\r\n const peerId = this.chat.peerId;\r\n const middleware = this.chat.bubbles.getMiddleware(() => {\r\n return this.chat.peerId === peerId && this.startParam === startParam && this.toggleBotStartBtnDisability === toggle;\r\n });\r\n\r\n this.appMessagesManager.startBot(peerId.toUserId(), undefined, startParam).then(() => {\r\n if(middleware()) {\r\n toggle();\r\n this.toggleBotStartBtnDisability = undefined;\r\n this.setStartParam();\r\n }\r\n });\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n this.controlContainer.append(this.botStartBtn);\r\n }\r\n\r\n public constructPinnedHelpers() {\r\n this.pinnedControlBtn = Button('btn-primary btn-transparent text-bold chat-input-control-button', {icon: 'unpin'});\r\n this.controlContainer.append(this.pinnedControlBtn);\r\n\r\n this.listenerSetter.add(this.pinnedControlBtn)('click', () => {\r\n const peerId = this.chat.peerId;\r\n\r\n new PopupPinMessage(peerId, 0, true, () => {\r\n this.chat.appImManager.setPeer(); // * close tab\r\n\r\n // ! костыль, это скроет закреплённые сообщения сразу, вместо того, чтобы ждать пока анимация перехода закончится\r\n const originalChat = this.chat.appImManager.chat;\r\n if(originalChat.topbar.pinnedMessage) {\r\n originalChat.topbar.pinnedMessage.pinnedMessageContainer.toggle(true);\r\n }\r\n });\r\n });\r\n\r\n this.chatInput.classList.add('type-pinned');\r\n }\r\n\r\n public center(animate = false) {\r\n const neededFakeContainer = this.getNeededFakeContainer();\r\n if(!neededFakeContainer && !this.inputContainer.classList.contains('is-centering')) {\r\n return;\r\n }\r\n\r\n if(neededFakeContainer === this.fakeWrapperTo) {\r\n return;\r\n }\r\n\r\n /* if(neededFakeContainer === this.botStartContainer && this.fakeWrapperTo === this.fakeSelectionWrapper) {\r\n this.inputContainer.classList.remove('is-centering');\r\n void this.rowsWrapper.offsetLeft; // reflow\r\n // this.inputContainer.classList.add('is-centering');\r\n // void this.rowsWrapper.offsetLeft; // reflow\r\n } */\r\n\r\n const fakeSelectionWrapper = neededFakeContainer || this.fakeWrapperTo;\r\n const forwards = !!neededFakeContainer;\r\n const oldFakeWrapperTo = this.fakeWrapperTo;\r\n let transform = '', borderRadius = '', needTranslateX: number;\r\n // if(forwards) {]\r\n const fakeSelectionRect = fakeSelectionWrapper.getBoundingClientRect();\r\n const fakeRowsRect = this.fakeRowsWrapper.getBoundingClientRect();\r\n const widthFrom = fakeRowsRect.width;\r\n const widthTo = fakeSelectionRect.width;\r\n\r\n if(widthFrom !== widthTo) {\r\n const scale = (widthTo/* - 8 */) / widthFrom;\r\n const initTranslateX = (widthFrom - widthTo) / 2;\r\n needTranslateX = fakeSelectionRect.left - fakeRowsRect.left - initTranslateX;\r\n\r\n if(forwards) {\r\n transform = `translateX(${needTranslateX}px) scaleX(${scale})`;\r\n // transform = `translateX(0px) scaleX(${scale})`;\r\n \r\n if(scale < 1) {\r\n const br = 12;\r\n borderRadius = '' + (br + br * (1 - scale)) + 'px';\r\n }\r\n }\r\n //scale = widthTo / widthFrom;\r\n }\r\n // }\r\n\r\n this.fakeWrapperTo = neededFakeContainer;\r\n\r\n const duration = animate ? 200 : 0;\r\n SetTransition(this.inputContainer, 'is-centering', forwards, duration);\r\n SetTransition(this.rowsWrapperWrapper, 'is-centering-to-control', !!(forwards && neededFakeContainer && neededFakeContainer.classList.contains('chat-input-control')), duration);\r\n this.rowsWrapper.style.transform = transform;\r\n this.rowsWrapper.style.borderRadius = borderRadius;\r\n\r\n return {\r\n transform, \r\n borderRadius, \r\n needTranslateX: oldFakeWrapperTo && (\r\n (\r\n neededFakeContainer && \r\n neededFakeContainer.classList.contains('chat-input-control') && \r\n oldFakeWrapperTo === this.fakeSelectionWrapper\r\n ) || oldFakeWrapperTo.classList.contains('chat-input-control')\r\n ) ? needTranslateX * -.5 : needTranslateX,\r\n widthFrom, \r\n widthTo\r\n };\r\n }\r\n\r\n public setStartParam(startParam?: string) {\r\n if(this.startParam === startParam) {\r\n return;\r\n }\r\n\r\n this.startParam = startParam;\r\n this.center(true);\r\n }\r\n\r\n public getNeededFakeContainer() {\r\n if(this.chat.selection.isSelecting) {\r\n return this.fakeSelectionWrapper;\r\n } else if(this.startParam !== undefined || \r\n !this.chat.canSend() || \r\n this.chat.type === 'pinned' || \r\n this.chat.isStartButtonNeeded()\r\n ) {\r\n return this.controlContainer;\r\n }\r\n }\r\n\r\n // public getActiveContainer() {\r\n // if(this.chat.selection.isSelecting) {\r\n // return this.chat\r\n // }\r\n // return this.startParam !== undefined ? this.botStartContainer : this.rowsWrapper;\r\n // }\r\n\r\n // public setActiveContainer() {\r\n // const container = this.activeContainer;\r\n // const newContainer = this.getActiveContainer();\r\n // if(newContainer === container) {\r\n // return;\r\n // }\r\n\r\n\r\n // }\r\n\r\n private onCancelRecordClick = (e?: Event) => {\r\n if(e) {\r\n cancelEvent(e);\r\n }\r\n \r\n this.recordCanceled = true;\r\n this.recorder.stop();\r\n opusDecodeController.setKeepAlive(false);\r\n };\r\n\r\n private onEmoticonsOpen = () => {\r\n const toggleClass = IS_TOUCH_SUPPORTED ? 'flip-icon' : 'active';\r\n this.btnToggleEmoticons.classList.toggle(toggleClass, true);\r\n };\r\n\r\n private onEmoticonsClose = () => {\r\n const toggleClass = IS_TOUCH_SUPPORTED ? 'flip-icon' : 'active';\r\n this.btnToggleEmoticons.classList.toggle(toggleClass, false);\r\n };\r\n\r\n public getReadyToSend(callback: () => void) {\r\n return this.chat.type === 'scheduled' ? (this.scheduleSending(callback), true) : (callback(), false);\r\n }\r\n\r\n public scheduleSending = (callback: () => void = this.sendMessage.bind(this, true), initDate = new Date()) => {\r\n const {peerId} = this.chat;\r\n const middleware = this.chat.bubbles.getMiddleware();\r\n const canSendWhenOnline = rootScope.myId !== peerId && peerId.isUser() && this.appUsersManager.isUserOnlineVisible(peerId);\r\n\r\n new PopupSchedule(initDate, (timestamp) => {\r\n if(!middleware()) {\r\n return;\r\n }\r\n\r\n const minTimestamp = (Date.now() / 1000 | 0) + 10;\r\n if(timestamp <= minTimestamp) {\r\n timestamp = undefined;\r\n }\r\n\r\n this.scheduleDate = timestamp;\r\n callback();\r\n\r\n if(this.chat.type !== 'scheduled' && timestamp) {\r\n setTimeout(() => { // ! need timeout here because .forwardMessages will be called after timeout\r\n if(!middleware()) {\r\n return;\r\n }\r\n\r\n this.appImManager.openScheduled(peerId);\r\n }, 0);\r\n }\r\n }, canSendWhenOnline).show();\r\n };\r\n\r\n public setUnreadCount() {\r\n if(!this.goDownUnreadBadge) {\r\n return;\r\n }\r\n \r\n const dialog = this.appMessagesManager.getDialogOnly(this.chat.peerId);\r\n const count = dialog?.unread_count;\r\n this.goDownUnreadBadge.innerText = '' + (count || '');\r\n this.goDownUnreadBadge.classList.toggle('badge-gray', this.appNotificationsManager.isPeerLocalMuted(this.chat.peerId, true));\r\n\r\n if(this.goMentionUnreadBadge && this.chat.type === 'chat') {\r\n const hasMentions = !!(dialog?.unread_mentions_count && dialog.unread_count);\r\n this.goMentionUnreadBadge.innerText = hasMentions ? '' + (dialog.unread_mentions_count) : '';\r\n this.goMentionBtn.classList.toggle('is-visible', hasMentions);\r\n }\r\n }\r\n\r\n public saveDraft() {\r\n if(!this.chat.peerId || this.editMsgId || this.chat.type === 'scheduled') return;\r\n \r\n const {value, entities} = getRichValue(this.messageInputField.input);\r\n\r\n let draft: DraftMessage.draftMessage;\r\n if(value.length || this.replyToMsgId) {\r\n draft = {\r\n _: 'draftMessage',\r\n date: tsNow(true) + this.serverTimeManager.serverTimeOffset,\r\n message: value,\r\n entities: entities.length ? entities : undefined,\r\n pFlags: {\r\n no_webpage: this.noWebPage\r\n },\r\n reply_to_msg_id: this.replyToMsgId\r\n };\r\n }\r\n\r\n this.appDraftsManager.syncDraft(this.chat.peerId, this.chat.threadId, draft);\r\n }\r\n\r\n public destroy() {\r\n //this.chat.log.error('Input destroying');\r\n\r\n this.listenerSetter.removeAll();\r\n }\r\n\r\n public cleanup(helperToo = true) {\r\n if(!this.chat.peerId) {\r\n this.chatInput.style.display = 'none';\r\n this.goDownBtn.classList.add('hide');\r\n }\r\n\r\n cancelSelection();\r\n\r\n this.lastTimeType = 0;\r\n this.startParam = undefined;\r\n\r\n if(this.toggleBotStartBtnDisability) {\r\n this.toggleBotStartBtnDisability();\r\n this.toggleBotStartBtnDisability = undefined;\r\n }\r\n\r\n if(this.messageInput) {\r\n this.clearInput();\r\n helperToo && this.clearHelper();\r\n }\r\n }\r\n\r\n public setDraft(draft?: MyDraftMessage, fromUpdate = true, force = false) {\r\n if((!force && !isInputEmpty(this.messageInput)) || this.chat.type === 'scheduled') return false;\r\n \r\n if(!draft) {\r\n draft = this.appDraftsManager.getDraft(this.chat.peerId, this.chat.threadId);\r\n\r\n if(!draft) {\r\n if(force) { // this situation can only happen when sending message with clearDraft\r\n /* const height = this.chatInput.getBoundingClientRect().height;\r\n const willChangeHeight = 78 - height;\r\n this.willChangeHeight = willChangeHeight; */\r\n if(this.chat.container.classList.contains('is-helper-active')) {\r\n this.t();\r\n }\r\n\r\n this.messageInputField.inputFake.textContent = '';\r\n this.messageInputField.onFakeInput(false);\r\n\r\n ((this.chat.bubbles.messagesQueuePromise || Promise.resolve()) as Promise<any>).then(() => {\r\n fastRaf(() => {\r\n this.onMessageSent();\r\n });\r\n });\r\n }\r\n \r\n return false;\r\n }\r\n }\r\n\r\n if(this.messageInputField.value === draft.rMessage && this.replyToMsgId === draft.reply_to_msg_id) return false;\r\n\r\n if(fromUpdate) {\r\n this.clearHelper();\r\n }\r\n\r\n this.noWebPage = draft.pFlags.no_webpage;\r\n if(draft.reply_to_msg_id) {\r\n this.initMessageReply(draft.reply_to_msg_id);\r\n }\r\n\r\n this.setInputValue(draft.rMessage, fromUpdate, fromUpdate);\r\n return true;\r\n }\r\n\r\n public finishPeerChange(startParam?: string) {\r\n const peerId = this.chat.peerId;\r\n\r\n const {forwardElements, btnScheduled, replyKeyboard, sendMenu, goDownBtn, chatInput, sendAsContainer, botCommandsToggle} = this;\r\n chatInput.style.display = '';\r\n \r\n const isBroadcast = this.appPeersManager.isBroadcast(peerId);\r\n goDownBtn.classList.toggle('is-broadcast', isBroadcast);\r\n goDownBtn.classList.remove('hide');\r\n\r\n if(this.goDownUnreadBadge) {\r\n this.setUnreadCount();\r\n }\r\n\r\n if(this.chat.type === 'pinned') {\r\n chatInput.classList.toggle('can-pin', this.appPeersManager.canPinMessage(peerId));\r\n }/* else if(this.chat.type === 'chat') {\r\n } */\r\n\r\n if(forwardElements) {\r\n this.forwardWasDroppingAuthor = false;\r\n forwardElements.showCaption.checkboxField.setValueSilently(true);\r\n forwardElements.showSender.checkboxField.setValueSilently(true);\r\n }\r\n\r\n if(btnScheduled) {\r\n btnScheduled.classList.add('hide');\r\n const middleware = this.chat.bubbles.getMiddleware();\r\n this.appMessagesManager.getScheduledMessages(peerId).then(mids => {\r\n if(!middleware()) return;\r\n btnScheduled.classList.toggle('hide', !mids.length);\r\n });\r\n }\r\n\r\n if(this.newMessageWrapper) {\r\n this.updateOffset(null, false, true);\r\n }\r\n\r\n if(botCommandsToggle) {\r\n this.hasBotCommands = undefined;\r\n this.botCommands.toggle(true, undefined, true);\r\n this.updateBotCommandsToggle(true);\r\n botCommandsToggle.remove();\r\n if(this.appPeersManager.isBot(peerId)) {\r\n const userId = peerId.toUserId();\r\n const middleware = this.chat.bubbles.getMiddleware();\r\n const getUserFullResult = this.appProfileManager.getProfile(userId);\r\n callbackify(getUserFullResult, (userFull) => {\r\n if(!middleware()) return;\r\n this.updateBotCommands(userFull, !(getUserFullResult instanceof Promise));\r\n });\r\n }\r\n }\r\n\r\n if(sendAsContainer) {\r\n if(this.sendAsAvatar) {\r\n this.sendAsAvatar.remove();\r\n this.sendAsAvatar = undefined;\r\n }\r\n \r\n sendAsContainer.remove();\r\n this.sendAsPeerId = undefined;\r\n this.updatingSendAsPromise = undefined;\r\n\r\n this.updateSendAs(true);\r\n }\r\n\r\n if(replyKeyboard) {\r\n replyKeyboard.setPeer(peerId);\r\n }\r\n\r\n if(sendMenu) {\r\n sendMenu.setPeerId(peerId);\r\n }\r\n \r\n if(this.messageInput) {\r\n this.updateMessageInput();\r\n } else if(this.pinnedControlBtn) {\r\n this.pinnedControlBtn.append(i18n(this.appPeersManager.canPinMessage(this.chat.peerId) ? 'Chat.Input.UnpinAll' : 'Chat.Pinned.DontShow'));\r\n }\r\n\r\n // * testing\r\n // this.startParam = this.appPeersManager.isBot(peerId) ? '123' : undefined;\r\n \r\n this.startParam = startParam;\r\n\r\n this.center(false);\r\n }\r\n\r\n private updateOffset(type: 'commands' | 'as', forwards: boolean, skipAnimation?: boolean, useRafs?: number) {\r\n if(type) {\r\n this.newMessageWrapper.dataset.offset = type;\r\n } else {\r\n delete this.newMessageWrapper.dataset.offset;\r\n }\r\n\r\n SetTransition(this.newMessageWrapper, 'has-offset', forwards, skipAnimation ? 0 : 300, undefined, useRafs);\r\n }\r\n\r\n private updateBotCommands(userFull: UserFull.userFull, skipAnimation?: boolean) {\r\n this.hasBotCommands = userFull.bot_info && userFull.bot_info.commands.length;\r\n this.updateBotCommandsToggle(skipAnimation);\r\n }\r\n\r\n private updateBotCommandsToggle(skipAnimation?: boolean) {\r\n const {botCommandsToggle, hasBotCommands} = this;\r\n\r\n const show = !!hasBotCommands && this.isInputEmpty();\r\n if(!hasBotCommands) {\r\n if(!botCommandsToggle.parentElement) {\r\n return;\r\n }\r\n \r\n botCommandsToggle.remove();\r\n }\r\n \r\n const forwards = show;\r\n const useRafs = botCommandsToggle.parentElement ? 0 : 2;\r\n\r\n if(!botCommandsToggle.parentElement) {\r\n this.newMessageWrapper.prepend(botCommandsToggle);\r\n }\r\n\r\n this.updateOffset('commands', forwards, skipAnimation, useRafs);\r\n }\r\n\r\n private updateSendAsButtons(peerIds: PeerId[]) {\r\n const buttons: ButtonMenuItemOptions[] = peerIds.map((sendAsPeerId, idx) => {\r\n const textElement = document.createElement('div');\r\n\r\n const subtitle = document.createElement('div');\r\n subtitle.classList.add('btn-menu-item-subtitle');\r\n if(sendAsPeerId.isUser()) {\r\n subtitle.append(i18n('Chat.SendAs.PersonalAccount'));\r\n } else if(sendAsPeerId === this.chat.peerId) {\r\n subtitle.append(i18n('VoiceChat.DiscussionGroup'));\r\n } else {\r\n subtitle.append(this.appProfileManager.getChatMembersString(sendAsPeerId.toChatId()));\r\n }\r\n\r\n textElement.append(\r\n new PeerTitle({peerId: sendAsPeerId}).element,\r\n subtitle\r\n );\r\n\r\n return {\r\n onClick: idx ? () => {\r\n const currentPeerId = this.chat.peerId;\r\n if(currentPeerId.isChannel()) {\r\n const channelFull = this.appProfileManager.getCachedFullChat(currentPeerId.toChatId()) as ChatFull.channelFull;\r\n if(channelFull) {\r\n channelFull.default_send_as = this.appPeersManager.getOutputPeer(sendAsPeerId);\r\n this.sendAsPeerId = sendAsPeerId;\r\n this.updateSendAsAvatar(sendAsPeerId);\r\n this.updateMessageInputPlaceholder();\r\n\r\n const middleware = this.chat.bubbles.getMiddleware();\r\n const executeButtonsUpdate = () => {\r\n if(this.sendAsPeerId !== sendAsPeerId || !middleware()) return;\r\n const peerIds = this.sendAsPeerIds.slice();\r\n indexOfAndSplice(peerIds, sendAsPeerId);\r\n peerIds.unshift(sendAsPeerId);\r\n this.updateSendAsButtons(peerIds);\r\n };\r\n \r\n if(rootScope.settings.animationsEnabled) {\r\n setTimeout(executeButtonsUpdate, 250);\r\n } else {\r\n executeButtonsUpdate();\r\n }\r\n }\r\n }\r\n\r\n // return;\r\n apiManager.invokeApi('messages.saveDefaultSendAs', {\r\n peer: this.appPeersManager.getInputPeerById(currentPeerId),\r\n send_as: this.appPeersManager.getInputPeerById(sendAsPeerId)\r\n });\r\n } : undefined,\r\n textElement\r\n };\r\n });\r\n\r\n const btnMenu = ButtonMenu(buttons/* , this.listenerSetter */);\r\n buttons.forEach((button, idx) => {\r\n const peerId = peerIds[idx];\r\n const avatar = new AvatarElement();\r\n avatar.classList.add('avatar-32', 'btn-menu-item-icon');\r\n avatar.updateWithOptions({peerId});\r\n\r\n if(!idx) {\r\n avatar.classList.add('active');\r\n }\r\n \r\n button.element.prepend(avatar);\r\n });\r\n\r\n Array.from(this.sendAsBtnMenu.children).slice(1).forEach(node => node.remove());\r\n this.sendAsBtnMenu.append(...Array.from(btnMenu.children));\r\n }\r\n\r\n private updateSendAsAvatar(sendAsPeerId: PeerId, skipAnimation?: boolean) {\r\n const previousAvatar = this.sendAsAvatar;\r\n if(previousAvatar) {\r\n if(previousAvatar.peerId === sendAsPeerId) {\r\n return;\r\n }\r\n }\r\n \r\n if(!previousAvatar) {\r\n skipAnimation = true;\r\n }\r\n \r\n let useRafs = skipAnimation ? 0 : 2;\r\n const duration = skipAnimation ? 0 : SEND_AS_ANIMATION_DURATION;\r\n const avatar = this.sendAsAvatar = new AvatarElement();\r\n avatar.classList.add('new-message-send-as-avatar', 'avatar-30');\r\n avatar.updateWithOptions({\r\n isDialog: false,\r\n peerId: sendAsPeerId\r\n });\r\n\r\n SetTransition(avatar, 'is-visible', true, duration, undefined, useRafs); \r\n if(previousAvatar) {\r\n SetTransition(previousAvatar, 'is-visible', false, duration, () => {\r\n previousAvatar.remove();\r\n }, useRafs);\r\n }\r\n \r\n this.sendAsContainer.append(avatar);\r\n }\r\n\r\n private getDefaultSendAs() {\r\n // return rootScope.myId;\r\n return callbackify(this.appProfileManager.getChannelFull(this.chat.peerId.toChatId()), (channelFull) => {\r\n return channelFull.default_send_as ? this.appPeersManager.getPeerId(channelFull.default_send_as) : undefined;\r\n });\r\n }\r\n\r\n private updateSendAs(skipAnimation?: boolean) {\r\n const peerId = this.chat.peerId;\r\n if(!peerId.isChannel() || this.updatingSendAsPromise) {\r\n return;\r\n }\r\n\r\n const middleware = this.chat.bubbles.getMiddleware(() => {\r\n return !this.updatingSendAsPromise || this.updatingSendAsPromise === updatingSendAsPromise;\r\n });\r\n\r\n const {sendAsContainer} = this;\r\n const chatId = peerId.toChatId();\r\n const result = this.getDefaultSendAs();\r\n // const result = Promise.resolve(this.getDefaultSendAs());\r\n\r\n if(result instanceof Promise) {\r\n skipAnimation = undefined;\r\n }\r\n\r\n const updateSendAsResult = callbackify(result, (sendAsPeerId) => {\r\n if(!middleware() || sendAsPeerId === undefined) return;\r\n \r\n this.sendAsPeerId = sendAsPeerId;\r\n this.updateSendAsAvatar(sendAsPeerId, skipAnimation);\r\n this.updateMessageInputPlaceholder();\r\n\r\n this.appChatsManager.getSendAs(chatId).then(peers => {\r\n if(!middleware()) return;\r\n\r\n const peerIds = peers.map((peer) => this.appPeersManager.getPeerId(peer));\r\n this.sendAsPeerIds = peerIds.slice();\r\n\r\n indexOfAndSplice(peerIds, sendAsPeerId);\r\n peerIds.unshift(sendAsPeerId);\r\n this.updateSendAsButtons(peerIds);\r\n });\r\n\r\n let useRafs = 0;\r\n if(!sendAsContainer.parentElement) {\r\n this.newMessageWrapper.prepend(sendAsContainer);\r\n useRafs = 2;\r\n }\r\n\r\n this.updateOffset('as', true, skipAnimation, useRafs);\r\n\r\n this.updatingSendAsPromise = undefined;\r\n });\r\n\r\n const updatingSendAsPromise = this.updatingSendAsPromise = Promise.resolve(updateSendAsResult);\r\n return updatingSendAsPromise;\r\n }\r\n\r\n private updateMessageInputPlaceholder() {\r\n const i = I18n.weakMap.get(this.messageInput) as I18n.IntlElement;\r\n if(i) {\r\n const {peerId, threadId} = this.chat;\r\n let key: LangPackKey;\r\n if(threadId) {\r\n key = 'Comment';\r\n } else if(this.appPeersManager.isBroadcast(peerId)) {\r\n key = 'ChannelBroadcast';\r\n } else if((this.sendAsPeerId !== undefined && this.sendAsPeerId !== rootScope.myId) || \r\n this.appMessagesManager.isAnonymousSending(peerId)) {\r\n key = 'SendAnonymously';\r\n } else {\r\n key = 'Message';\r\n }\r\n\r\n i.compareAndUpdate({key});\r\n }\r\n }\r\n\r\n public updateMessageInput() {\r\n const {chatInput, attachMenu, messageInput} = this;\r\n const {peerId, threadId} = this.chat;\r\n const canWrite = this.chat.canSend();\r\n const isHidden = chatInput.classList.contains('is-hidden');\r\n const willBeHidden = !canWrite;\r\n if(isHidden !== willBeHidden) {\r\n chatInput.classList.add('no-transition');\r\n chatInput.classList.toggle('is-hidden', !canWrite);\r\n void chatInput.offsetLeft; // reflow\r\n chatInput.classList.remove('no-transition');\r\n }\r\n\r\n this.updateMessageInputPlaceholder();\r\n\r\n const visible = this.attachMenuButtons.filter(button => {\r\n const good = button.verify(peerId, threadId);\r\n button.element.classList.toggle('hide', !good);\r\n return good;\r\n });\r\n\r\n if(!canWrite) {\r\n messageInput.removeAttribute('contenteditable');\r\n } else {\r\n messageInput.setAttribute('contenteditable', 'true');\r\n this.setDraft(undefined, false);\r\n\r\n if(!messageInput.innerHTML) {\r\n this.messageInputField.onFakeInput();\r\n }\r\n }\r\n \r\n attachMenu.toggleAttribute('disabled', !visible.length);\r\n attachMenu.classList.toggle('btn-disabled', !visible.length);\r\n this.updateSendBtn();\r\n }\r\n\r\n private attachMessageInputField() {\r\n const oldInputField = this.messageInputField;\r\n this.messageInputField = new InputField({\r\n placeholder: 'Message',\r\n name: 'message',\r\n animate: true\r\n });\r\n\r\n this.messageInputField.input.classList.replace('input-field-input', 'input-message-input');\r\n this.messageInputField.inputFake.classList.replace('input-field-input', 'input-message-input');\r\n this.messageInput = this.messageInputField.input;\r\n this.messageInput.classList.add('no-scrollbar');\r\n this.attachMessageInputListeners();\r\n \r\n if(IS_STICKY_INPUT_BUGGED) {\r\n fixSafariStickyInputFocusing(this.messageInput);\r\n }\r\n\r\n if(oldInputField) {\r\n oldInputField.input.replaceWith(this.messageInputField.input);\r\n oldInputField.inputFake.replaceWith(this.messageInputField.inputFake);\r\n } else {\r\n this.inputMessageContainer.append(this.messageInputField.input, this.messageInputField.inputFake);\r\n }\r\n }\r\n\r\n private attachMessageInputListeners() {\r\n this.listenerSetter.add(this.messageInput)('keydown', (e: KeyboardEvent) => {\r\n const key = e.key;\r\n if(isSendShortcutPressed(e)) {\r\n cancelEvent(e);\r\n this.sendMessage();\r\n } else if(e.ctrlKey || e.metaKey) {\r\n this.handleMarkdownShortcut(e);\r\n } else if((key === 'PageUp' || key === 'PageDown') && !e.shiftKey) { // * fix pushing page to left (Chrome Windows)\r\n e.preventDefault();\r\n\r\n if(key === 'PageUp') {\r\n const range = document.createRange();\r\n const sel = window.getSelection();\r\n \r\n range.setStart(this.messageInput.childNodes[0] || this.messageInput, 0);\r\n range.collapse(true);\r\n \r\n sel.removeAllRanges();\r\n sel.addRange(range);\r\n } else {\r\n placeCaretAtEnd(this.messageInput);\r\n }\r\n }\r\n });\r\n\r\n if(IS_TOUCH_SUPPORTED) {\r\n attachClickEvent(this.messageInput, (e) => {\r\n this.appImManager.selectTab(1); // * set chat tab for album orientation\r\n //this.saveScroll();\r\n emoticonsDropdown.toggle(false);\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n /* this.listenerSetter.add(window)('resize', () => {\r\n this.restoreScroll();\r\n }); */\r\n\r\n /* if(isSafari) { \r\n this.listenerSetter.add(this.messageInput)('mousedown', () => {\r\n window.requestAnimationFrame(() => {\r\n window.requestAnimationFrame(() => {\r\n emoticonsDropdown.toggle(false);\r\n });\r\n });\r\n });\r\n } */\r\n }\r\n\r\n /* this.listenerSetter.add(this.messageInput)('beforeinput', (e: Event) => {\r\n // * validate due to manual formatting through browser's context menu\r\n const inputType = (e as InputEvent).inputType;\r\n //console.log('message beforeinput event', e);\r\n\r\n if(inputType.indexOf('format') === 0) {\r\n //console.log('message beforeinput format', e, inputType, this.messageInput.innerHTML);\r\n const markdownType = inputType.split('format')[1].toLowerCase() as MarkdownType;\r\n if(this.applyMarkdown(markdownType)) {\r\n cancelEvent(e); // * cancel legacy markdown event\r\n }\r\n }\r\n }); */\r\n this.listenerSetter.add(this.messageInput)('input', this.onMessageInput);\r\n this.listenerSetter.add(this.messageInput)('keyup', () => {\r\n this.checkAutocomplete();\r\n });\r\n\r\n if(this.chat.type === 'chat' || this.chat.type === 'discussion') {\r\n this.listenerSetter.add(this.messageInput)('focusin', () => {\r\n if(this.chat.bubbles.scrollable.loadedAll.bottom) {\r\n this.appMessagesManager.readAllHistory(this.chat.peerId, this.chat.threadId);\r\n }\r\n }); \r\n }\r\n }\r\n\r\n private prepareDocumentExecute = () => {\r\n this.executedHistory.push(this.messageInput.innerHTML);\r\n return () => this.canUndoFromHTML = this.messageInput.innerHTML;\r\n };\r\n\r\n private undoRedo = (e: Event, type: 'undo' | 'redo', needHTML: string) => {\r\n cancelEvent(e); // cancel legacy event\r\n\r\n let html = this.messageInput.innerHTML;\r\n if(html && html !== needHTML) {\r\n this.lockRedo = true;\r\n\r\n let sameHTMLTimes = 0;\r\n do {\r\n document.execCommand(type, false, null);\r\n const currentHTML = this.messageInput.innerHTML;\r\n if(html === currentHTML) {\r\n if(++sameHTMLTimes > 2) { // * unlink, removeFormat (а может и нет, случай: заболдить подчёркнутый текст (выделить ровно его), попробовать отменить)\r\n break;\r\n }\r\n } else {\r\n sameHTMLTimes = 0;\r\n }\r\n\r\n html = currentHTML;\r\n } while(html !== needHTML);\r\n\r\n this.lockRedo = false;\r\n }\r\n };\r\n\r\n public applyMarkdown(type: MarkdownType, href?: string) {\r\n const MONOSPACE_FONT = 'var(--font-monospace)';\r\n const SPOILER_FONT = 'spoiler';\r\n const commandsMap: Partial<{[key in typeof type]: string | (() => void)}> = {\r\n bold: 'Bold',\r\n italic: 'Italic',\r\n underline: 'Underline',\r\n strikethrough: 'Strikethrough',\r\n monospace: () => document.execCommand('fontName', false, MONOSPACE_FONT),\r\n link: href ? () => document.execCommand('createLink', false, href) : () => document.execCommand('unlink', false, null),\r\n spoiler: () => document.execCommand('fontName', false, SPOILER_FONT)\r\n };\r\n\r\n if(!commandsMap[type]) {\r\n return false;\r\n }\r\n\r\n const command = commandsMap[type];\r\n\r\n //type = 'monospace';\r\n\r\n const saveExecuted = this.prepareDocumentExecute();\r\n const executed: any[] = [];\r\n /**\r\n * * clear previous formatting, due to Telegram's inability to handle several entities\r\n */\r\n /* const checkForSingle = () => {\r\n const nodes = getSelectedNodes();\r\n //console.log('Using formatting:', commandsMap[type], nodes, this.executedHistory);\r\n\r\n const parents = [...new Set(nodes.map(node => node.parentNode))];\r\n //const differentParents = !!nodes.find(node => node.parentNode !== firstParent);\r\n const differentParents = parents.length > 1;\r\n\r\n let notSingle = false;\r\n if(differentParents) {\r\n notSingle = true;\r\n } else {\r\n const node = nodes[0];\r\n if(node && (node.parentNode as HTMLElement) !== this.messageInput && (node.parentNode.parentNode as HTMLElement) !== this.messageInput) {\r\n notSingle = true;\r\n }\r\n }\r\n\r\n if(notSingle) {\r\n //if(type === 'monospace') {\r\n executed.push(document.execCommand('styleWithCSS', false, 'true'));\r\n //}\r\n\r\n executed.push(document.execCommand('unlink', false, null));\r\n executed.push(document.execCommand('removeFormat', false, null));\r\n executed.push(typeof(command) === 'function' ? command() : document.execCommand(command, false, null));\r\n\r\n //if(type === 'monospace') {\r\n executed.push(document.execCommand('styleWithCSS', false, 'false'));\r\n //}\r\n }\r\n }; */\r\n\r\n executed.push(document.execCommand('styleWithCSS', false, 'true'));\r\n \r\n if(type === 'monospace' || type === 'spoiler') {\r\n let haveThisType = false;\r\n //executed.push(document.execCommand('styleWithCSS', false, 'true'));\r\n\r\n const selection = window.getSelection();\r\n if(!selection.isCollapsed) {\r\n const range = selection.getRangeAt(0);\r\n const tag = markdownTags[type];\r\n\r\n const node = range.commonAncestorContainer;\r\n if((node.parentNode as HTMLElement).matches(tag.match) || (node instanceof HTMLElement && node.matches(tag.match))) {\r\n haveThisType = true;\r\n }\r\n }\r\n\r\n //executed.push(document.execCommand('removeFormat', false, null));\r\n\r\n if(haveThisType) {\r\n executed.push(this.resetCurrentFormatting());\r\n } else {\r\n executed.push(typeof(command) === 'function' ? command() : document.execCommand(command, false, null));\r\n }\r\n } else {\r\n executed.push(typeof(command) === 'function' ? command() : document.execCommand(command, false, null));\r\n }\r\n\r\n executed.push(document.execCommand('styleWithCSS', false, 'false'));\r\n\r\n //checkForSingle();\r\n saveExecuted();\r\n if(this.appImManager.markupTooltip) {\r\n this.appImManager.markupTooltip.setActiveMarkupButton();\r\n }\r\n\r\n return true;\r\n }\r\n\r\n private resetCurrentFormatting() {\r\n return document.execCommand('fontName', false, 'Roboto');\r\n }\r\n\r\n private handleMarkdownShortcut = (e: KeyboardEvent) => {\r\n // console.log('handleMarkdownShortcut', e);\r\n const formatKeys: {[key: string]: MarkdownType} = {\r\n 'KeyB': 'bold',\r\n 'KeyI': 'italic',\r\n 'KeyU': 'underline',\r\n 'KeyS': 'strikethrough',\r\n 'KeyM': 'monospace',\r\n 'KeyP': 'spoiler'\r\n };\r\n\r\n if(this.appImManager.markupTooltip) {\r\n formatKeys['KeyK'] = 'link';\r\n }\r\n\r\n const code = e.code;\r\n const applyMarkdown = formatKeys[code];\r\n\r\n const selection = document.getSelection();\r\n if(selection.toString().trim().length && applyMarkdown) {\r\n // * костыльчик\r\n if(code === 'KeyK') {\r\n this.appImManager.markupTooltip.showLinkEditor();\r\n } else {\r\n this.applyMarkdown(applyMarkdown);\r\n }\r\n \r\n cancelEvent(e); // cancel legacy event\r\n }\r\n\r\n //return;\r\n if(code === 'KeyZ') {\r\n let html = this.messageInput.innerHTML;\r\n\r\n if(e.shiftKey) {\r\n if(this.undoHistory.length) {\r\n this.executedHistory.push(html);\r\n html = this.undoHistory.pop();\r\n this.undoRedo(e, 'redo', html);\r\n html = this.messageInput.innerHTML;\r\n this.canRedoFromHTML = this.undoHistory.length ? html : '';\r\n this.canUndoFromHTML = html;\r\n }\r\n } else {\r\n // * подождём, когда пользователь сам восстановит поле до нужного состояния, которое стало сразу после saveExecuted\r\n if(this.executedHistory.length && (!this.canUndoFromHTML || html === this.canUndoFromHTML)) {\r\n this.undoHistory.push(html);\r\n html = this.executedHistory.pop();\r\n this.undoRedo(e, 'undo', html);\r\n\r\n // * поставим новое состояние чтобы снова подождать, если пользователь изменит что-то, и потом попробует откатить до предыдущего состояния\r\n this.canUndoFromHTML = this.canRedoFromHTML = this.messageInput.innerHTML;\r\n }\r\n }\r\n }\r\n };\r\n\r\n private onMessageInput = (e?: Event) => {\r\n // * validate due to manual formatting through browser's context menu\r\n /* const inputType = (e as InputEvent).inputType;\r\n console.log('message input event', e);\r\n if(inputType === 'formatBold') {\r\n console.log('message input format', this.messageInput.innerHTML);\r\n cancelEvent(e);\r\n }\r\n\r\n if(!isSelectionSingle()) {\r\n alert('not single');\r\n } */\r\n\r\n //console.log('messageInput input', this.messageInput.innerText);\r\n //const value = this.messageInput.innerText;\r\n const {value: richValue, entities: markdownEntities, caretPos} = getRichValueWithCaret(this.messageInputField.input);\r\n \r\n //const entities = RichTextProcessor.parseEntities(value);\r\n const value = RichTextProcessor.parseMarkdown(richValue, markdownEntities, true);\r\n const entities = RichTextProcessor.mergeEntities(markdownEntities, RichTextProcessor.parseEntities(value));\r\n\r\n //this.chat.log('messageInput entities', richValue, value, markdownEntities, caretPos);\r\n\r\n if(this.canRedoFromHTML && !this.lockRedo && this.messageInput.innerHTML !== this.canRedoFromHTML) {\r\n this.canRedoFromHTML = '';\r\n this.undoHistory.length = 0;\r\n }\r\n\r\n const urlEntities: Array<MessageEntity.messageEntityUrl | MessageEntity.messageEntityTextUrl> = (!this.editMessage?.media || this.editMessage.media._ === 'messageMediaWebPage') && entities.filter(e => e._ === 'messageEntityUrl' || e._ === 'messageEntityTextUrl') as any;\r\n if(urlEntities.length) {\r\n for(const entity of urlEntities) {\r\n let url: string;\r\n if(entity._ === 'messageEntityTextUrl') {\r\n url = entity.url;\r\n } else {\r\n url = richValue.slice(entity.offset, entity.offset + entity.length);\r\n\r\n if(!(url.includes('http://') || url.includes('https://'))) {\r\n continue;\r\n }\r\n }\r\n\r\n //console.log('messageInput url:', url);\r\n\r\n if(this.lastUrl !== url) {\r\n this.lastUrl = url;\r\n // this.willSendWebPage = null;\r\n const promise = this.getWebPagePromise = apiManager.invokeApiHashable({\r\n method: 'messages.getWebPage',\r\n processResult: (webPage) => {\r\n return this.appWebPagesManager.saveWebPage(webPage);\r\n },\r\n params: {\r\n url\r\n },\r\n }).then((webpage) => {\r\n if(this.getWebPagePromise === promise) this.getWebPagePromise = undefined;\r\n if(this.lastUrl !== url) return;\r\n if(webpage._ === 'webPage') {\r\n //console.log('got webpage: ', webpage);\r\n\r\n this.setTopInfo('webpage', () => {}, webpage.site_name || webpage.title || 'Webpage', webpage.description || webpage.url || '');\r\n delete this.noWebPage;\r\n this.willSendWebPage = webpage;\r\n } else if(this.willSendWebPage) {\r\n this.onHelperCancel();\r\n }\r\n });\r\n }\r\n\r\n break;\r\n }\r\n } else if(this.lastUrl) {\r\n this.lastUrl = '';\r\n delete this.noWebPage;\r\n this.willSendWebPage = null;\r\n \r\n if(this.helperType) {\r\n this.helperFunc();\r\n } else {\r\n this.clearHelper();\r\n }\r\n }\r\n\r\n const isEmpty = !richValue.trim();\r\n if(isEmpty) {\r\n if(this.lastTimeType) {\r\n this.appMessagesManager.setTyping(this.chat.peerId, {_: 'sendMessageCancelAction'});\r\n }\r\n\r\n if(this.appImManager.markupTooltip) {\r\n this.appImManager.markupTooltip.hide();\r\n }\r\n\r\n // * Chrome has a bug - it will preserve the formatting if the input with monospace text is cleared\r\n // * so have to reset formatting\r\n if(document.activeElement === this.messageInput) {\r\n // document.execCommand('styleWithCSS', false, 'true');\r\n setTimeout(() => {\r\n if(document.activeElement === this.messageInput) {\r\n this.resetCurrentFormatting();\r\n }\r\n }, 0);\r\n // document.execCommand('styleWithCSS', false, 'false');\r\n }\r\n } else {\r\n const time = Date.now();\r\n if(time - this.lastTimeType >= 6000) {\r\n this.lastTimeType = time;\r\n this.appMessagesManager.setTyping(this.chat.peerId, {_: 'sendMessageTypingAction'});\r\n }\r\n\r\n if(this.botCommands) {\r\n this.botCommands.toggle(true);\r\n }\r\n }\r\n\r\n if(this.botCommands) {\r\n this.updateBotCommandsToggle();\r\n }\r\n\r\n if(!this.editMsgId) {\r\n this.saveDraftDebounced();\r\n }\r\n\r\n this.checkAutocomplete(richValue, caretPos, entities);\r\n\r\n this.updateSendBtn();\r\n };\r\n\r\n public insertAtCaret(insertText: string, insertEntity?: MessageEntity, isHelper = true) {\r\n const {value: fullValue, caretPos, entities} = getRichValueWithCaret(this.messageInput);\r\n const pos = caretPos >= 0 ? caretPos : fullValue.length;\r\n const prefix = fullValue.substr(0, pos);\r\n const suffix = fullValue.substr(pos);\r\n\r\n const matches = isHelper ? prefix.match(ChatInput.AUTO_COMPLETE_REG_EXP) : null;\r\n\r\n const matchIndex = matches ? matches.index + (matches[0].length - matches[2].length) : prefix.length;\r\n const newPrefix = prefix.slice(0, matchIndex);\r\n const newValue = newPrefix + insertText + suffix;\r\n\r\n // merge emojis\r\n const hadEntities = RichTextProcessor.parseEntities(fullValue);\r\n RichTextProcessor.mergeEntities(entities, hadEntities);\r\n\r\n // max for additional whitespace\r\n const insertLength = insertEntity ? Math.max(insertEntity.length, insertText.length) : insertText.length;\r\n const addEntities: MessageEntity[] = [];\r\n if(insertEntity) {\r\n addEntities.push(insertEntity);\r\n insertEntity.offset = matchIndex;\r\n }\r\n\r\n // add offset to entities next to emoji\r\n const diff = matches ? insertLength - matches[2].length : insertLength;\r\n entities.forEach(entity => {\r\n if(entity.offset >= matchIndex) {\r\n entity.offset += diff;\r\n }\r\n });\r\n\r\n RichTextProcessor.mergeEntities(entities, addEntities);\r\n\r\n if(/* caretPos !== -1 && caretPos !== fullValue.length */true) {\r\n const caretEntity: MessageEntity.messageEntityCaret = {\r\n _: 'messageEntityCaret',\r\n offset: matchIndex + insertLength,\r\n length: 0\r\n };\r\n\r\n let insertCaretAtIndex = 0;\r\n for(let length = entities.length; insertCaretAtIndex < length; ++insertCaretAtIndex) {\r\n const entity = entities[insertCaretAtIndex];\r\n if(entity.offset > caretEntity.offset) {\r\n break;\r\n }\r\n }\r\n\r\n entities.splice(insertCaretAtIndex, 0, caretEntity);\r\n }\r\n\r\n //const saveExecuted = this.prepareDocumentExecute();\r\n // can't exec .value here because it will instantly check for autocomplete\r\n const value = documentFragmentToHTML(RichTextProcessor.wrapDraftText(newValue, {entities}));\r\n this.messageInputField.setValueSilently(value, true);\r\n\r\n const caret = this.messageInput.querySelector('.composer-sel');\r\n if(caret) {\r\n setCaretAt(caret);\r\n caret.remove();\r\n }\r\n\r\n // but it's needed to be checked only here\r\n this.onMessageInput();\r\n\r\n //saveExecuted();\r\n\r\n //document.execCommand('insertHTML', true, RichTextProcessor.wrapEmojiText(emoji));\r\n }\r\n\r\n public onEmojiSelected = (emoji: string, autocomplete: boolean) => {\r\n this.insertAtCaret(emoji, RichTextProcessor.getEmojiEntityFromEmoji(emoji), autocomplete);\r\n };\r\n\r\n private checkAutocomplete(value?: string, caretPos?: number, entities?: MessageEntity[]) {\r\n //return;\r\n\r\n if(value === undefined) {\r\n const r = getRichValueWithCaret(this.messageInputField.input, true);\r\n value = r.value;\r\n caretPos = r.caretPos;\r\n entities = r.entities;\r\n }\r\n\r\n if(caretPos === -1) {\r\n caretPos = value.length;\r\n }\r\n\r\n if(entities === undefined) {\r\n const _value = RichTextProcessor.parseMarkdown(value, entities, true);\r\n entities = RichTextProcessor.mergeEntities(entities, RichTextProcessor.parseEntities(_value));\r\n }\r\n\r\n value = value.slice(0, caretPos);\r\n\r\n if(this.previousQuery === value) {\r\n return;\r\n }\r\n\r\n this.previousQuery = value;\r\n \r\n const matches = value.match(ChatInput.AUTO_COMPLETE_REG_EXP);\r\n let foundHelper: AutocompleteHelper;\r\n if(matches) {\r\n const entity = entities[0];\r\n\r\n let query = matches[2];\r\n const firstChar = query[0];\r\n\r\n if(this.stickersHelper && \r\n rootScope.settings.stickers.suggest && \r\n this.chat.canSend('send_stickers') &&\r\n entity?._ === 'messageEntityEmoji' && entity.length === value.length && !entity.offset) {\r\n foundHelper = this.stickersHelper;\r\n this.stickersHelper.checkEmoticon(value);\r\n } else if(firstChar === '@') { // mentions\r\n const topMsgId = this.chat.threadId ? this.appMessagesIdsManager.getServerMessageId(this.chat.threadId) : undefined;\r\n if(this.mentionsHelper.checkQuery(query, this.chat.peerId.isUser() ? NULL_PEER_ID : this.chat.peerId, topMsgId)) {\r\n foundHelper = this.mentionsHelper;\r\n }\r\n } else if(!matches[1] && firstChar === '/') { // commands\r\n if(this.commandsHelper.checkQuery(query, this.chat.peerId)) {\r\n foundHelper = this.commandsHelper;\r\n }\r\n } else if(rootScope.settings.emoji.suggest) { // emoji\r\n query = query.replace(/^\\s*/, '');\r\n if(!value.match(/^\\s*:(.+):\\s*$/) && !value.match(/:[;!@#$%^&*()-=|]/) && query) {\r\n foundHelper = this.emojiHelper;\r\n this.emojiHelper.checkQuery(query, firstChar);\r\n }\r\n }\r\n }\r\n \r\n foundHelper = this.checkInlineAutocomplete(value, foundHelper);\r\n\r\n this.autocompleteHelperController.hideOtherHelpers(foundHelper);\r\n }\r\n\r\n private checkInlineAutocomplete(value: string, foundHelper?: AutocompleteHelper): AutocompleteHelper {\r\n let needPlaceholder = false;\r\n\r\n if(!foundHelper) {\r\n const inlineMatch = value.match(/^@([a-zA-Z\\\\d_]{3,32})\\s/);\r\n if(inlineMatch) {\r\n const username = inlineMatch[1];\r\n const query = value.slice(inlineMatch[0].length);\r\n needPlaceholder = inlineMatch[0].length === value.length;\r\n \r\n foundHelper = this.inlineHelper;\r\n\r\n if(!this.btnPreloader) {\r\n this.btnPreloader = ButtonIcon('none btn-preloader float show disable-hover', {noRipple: true});\r\n putPreloader(this.btnPreloader, true);\r\n this.inputMessageContainer.parentElement.insertBefore(this.btnPreloader, this.inputMessageContainer.nextSibling);\r\n } else {\r\n SetTransition(this.btnPreloader, 'show', true, 400);\r\n }\r\n \r\n this.inlineHelper.checkQuery(this.chat.peerId, username, query).then(({user, renderPromise}) => {\r\n if(needPlaceholder && user.bot_inline_placeholder) {\r\n this.messageInput.dataset.inlinePlaceholder = user.bot_inline_placeholder;\r\n }\r\n\r\n renderPromise.then(() => {\r\n SetTransition(this.btnPreloader, 'show', false, 400);\r\n });\r\n }).catch(noop);\r\n }\r\n }\r\n \r\n if(!needPlaceholder) {\r\n delete this.messageInput.dataset.inlinePlaceholder;\r\n }\r\n\r\n if(foundHelper !== this.inlineHelper) {\r\n if(this.btnPreloader) {\r\n SetTransition(this.btnPreloader, 'show', false, 400);\r\n }\r\n }\r\n\r\n return foundHelper;\r\n }\r\n\r\n private setRecording(value: boolean) {\r\n if(this.recording === value) {\r\n return;\r\n }\r\n\r\n SetTransition(this.chatInput, 'is-recording', value, 200);\r\n this.recording = value;\r\n this.updateSendBtn();\r\n }\r\n\r\n private onBtnSendClick = (e: Event) => {\r\n cancelEvent(e);\r\n\r\n if(!this.recorder || this.recording || !this.isInputEmpty() || this.forwarding || this.editMsgId) {\r\n if(this.recording) {\r\n if((Date.now() - this.recordStartTime) < RECORD_MIN_TIME) {\r\n this.onCancelRecordClick();\r\n } else {\r\n this.recorder.stop();\r\n }\r\n } else {\r\n this.sendMessage();\r\n }\r\n } else {\r\n if(this.chat.peerId.isAnyChat() && !this.chat.canSend('send_media')) {\r\n toast(POSTING_MEDIA_NOT_ALLOWED);\r\n return;\r\n }\r\n\r\n this.chatInput.classList.add('is-locked');\r\n blurActiveElement();\r\n\r\n this.recorder.start().then(() => {\r\n this.releaseMediaPlayback = appMediaPlaybackController.setSingleMedia();\r\n this.recordCanceled = false;\r\n \r\n this.setRecording(true);\r\n opusDecodeController.setKeepAlive(true);\r\n \r\n const showDiscardPopup = () => {\r\n new PopupPeer('popup-cancel-record', {\r\n titleLangKey: 'DiscardVoiceMessageTitle',\r\n descriptionLangKey: 'DiscardVoiceMessageDescription',\r\n buttons: [{\r\n langKey: 'DiscardVoiceMessageAction',\r\n callback: () => {\r\n simulateClickEvent(this.btnCancelRecord);\r\n }\r\n }, {\r\n langKey: 'Continue',\r\n isCancel: true\r\n }]\r\n }).show();\r\n };\r\n\r\n this.recordingOverlayListener = this.listenerSetter.add(document.body)('mousedown', (e) => {\r\n if(!findUpClassName(e.target, 'chat-input') && !findUpClassName(e.target, 'popup-cancel-record')) {\r\n cancelEvent(e);\r\n showDiscardPopup();\r\n }\r\n }, {capture: true, passive: false}) as any;\r\n\r\n appNavigationController.pushItem(this.recordingNavigationItem = {\r\n type: 'voice',\r\n onPop: () => {\r\n setTimeout(() => {\r\n showDiscardPopup();\r\n }, 0);\r\n\r\n return false;\r\n }\r\n });\r\n\r\n this.recordStartTime = Date.now();\r\n\r\n const sourceNode: MediaStreamAudioSourceNode = this.recorder.sourceNode;\r\n const context = sourceNode.context;\r\n\r\n const analyser = context.createAnalyser();\r\n sourceNode.connect(analyser);\r\n //analyser.connect(context.destination);\r\n analyser.fftSize = 32;\r\n\r\n const frequencyData = new Uint8Array(analyser.frequencyBinCount);\r\n const max = frequencyData.length * 255;\r\n const min = 54 / 150;\r\n let r = () => {\r\n if(!this.recording) return;\r\n\r\n analyser.getByteFrequencyData(frequencyData);\r\n\r\n let sum = 0;\r\n frequencyData.forEach(value => {\r\n sum += value;\r\n });\r\n \r\n let percents = Math.min(1, (sum / max) + min);\r\n //console.log('frequencyData', frequencyData, percents);\r\n\r\n this.recordRippleEl.style.transform = `scale(${percents})`;\r\n\r\n let diff = Date.now() - this.recordStartTime;\r\n let ms = diff % 1000;\r\n\r\n let formatted = toHHMMSS(diff / 1000) + ',' + ('00' + Math.round(ms / 10)).slice(-2);\r\n\r\n this.recordTimeEl.innerText = formatted;\r\n\r\n fastRaf(r);\r\n };\r\n\r\n r();\r\n }).catch((e: Error) => {\r\n switch(e.name as string) {\r\n case 'NotAllowedError': {\r\n toast('Please allow access to your microphone');\r\n break;\r\n }\r\n\r\n case 'NotReadableError': {\r\n toast(e.message);\r\n break;\r\n }\r\n\r\n default:\r\n console.error('Recorder start error:', e, e.name, e.message);\r\n toast(e.message);\r\n break;\r\n }\r\n\r\n this.setRecording(false);\r\n this.chatInput.classList.remove('is-locked');\r\n });\r\n }\r\n };\r\n\r\n private onHelperCancel = (e?: Event, force?: boolean) => {\r\n if(e) {\r\n cancelEvent(e);\r\n }\r\n\r\n if(this.willSendWebPage) {\r\n const lastUrl = this.lastUrl;\r\n let needReturn = false;\r\n if(this.helperType) {\r\n //if(this.helperFunc) {\r\n this.helperFunc();\r\n //}\r\n\r\n needReturn = true;\r\n }\r\n\r\n // * restore values\r\n this.lastUrl = lastUrl;\r\n this.noWebPage = true;\r\n this.willSendWebPage = null;\r\n\r\n if(needReturn) return;\r\n }\r\n\r\n if(this.helperType === 'edit' && !force) {\r\n const message = this.editMessage\r\n const value = RichTextProcessor.parseMarkdown(this.messageInputField.value, []);\r\n if(message.message !== value) {\r\n new PopupPeer('discard-editing', {\r\n buttons: [{\r\n langKey: 'Alert.Confirm.Discard',\r\n callback: () => {\r\n this.onHelperCancel(undefined, true);\r\n }\r\n }],\r\n descriptionLangKey: 'Chat.Edit.Cancel.Text'\r\n }).show();\r\n\r\n return;\r\n }\r\n }\r\n\r\n this.clearHelper();\r\n this.updateSendBtn();\r\n };\r\n\r\n private onHelperClick = (e: Event) => {\r\n cancelEvent(e);\r\n \r\n if(!findUpClassName(e.target, 'reply')) return;\r\n if(this.helperType === 'forward') {\r\n const {forwardElements} = this;\r\n if(forwardElements && IS_TOUCH_SUPPORTED && !forwardElements.container.classList.contains('active')) {\r\n openBtnMenu(forwardElements.container);\r\n }\r\n } else if(this.helperType === 'reply') {\r\n this.chat.setMessageId(this.replyToMsgId);\r\n } else if(this.helperType === 'edit') {\r\n this.chat.setMessageId(this.editMsgId);\r\n }\r\n };\r\n\r\n private changeForwardRecipient() {\r\n if(this.helperWaitingForward) return;\r\n this.helperWaitingForward = true;\r\n\r\n const forwarding = copy(this.forwarding);\r\n const helperFunc = this.helperFunc;\r\n this.clearHelper();\r\n this.updateSendBtn();\r\n let selected = false;\r\n const popup = new PopupForward(forwarding, () => {\r\n selected = true;\r\n });\r\n\r\n popup.addEventListener('close', () => {\r\n this.helperWaitingForward = false;\r\n\r\n if(!selected) {\r\n helperFunc();\r\n }\r\n });\r\n }\r\n\r\n public clearInput(canSetDraft = true, fireEvent = true, clearValue = '') {\r\n if(document.activeElement === this.messageInput && IS_MOBILE_SAFARI) { // fix first char uppercase\r\n const i = document.createElement('input');\r\n document.body.append(i);\r\n fixSafariStickyInput(i);\r\n this.messageInputField.setValueSilently(clearValue);\r\n fixSafariStickyInput(this.messageInput);\r\n i.remove();\r\n } else {\r\n this.messageInputField.setValueSilently(clearValue);\r\n }\r\n\r\n if(IS_TOUCH_SUPPORTED) {\r\n //this.messageInput.innerText = '';\r\n } else {\r\n //this.attachMessageInputField();\r\n //this.messageInput.innerText = '';\r\n\r\n // clear executions\r\n this.canRedoFromHTML = '';\r\n this.undoHistory.length = 0;\r\n this.executedHistory.length = 0;\r\n this.canUndoFromHTML = '';\r\n }\r\n\r\n let set = false;\r\n if(canSetDraft) {\r\n set = this.setDraft(undefined, false);\r\n }\r\n\r\n if(!set && fireEvent) {\r\n this.onMessageInput();\r\n }\r\n }\r\n\r\n public isInputEmpty() {\r\n return isInputEmpty(this.messageInput);\r\n }\r\n\r\n public updateSendBtn() {\r\n let icon: 'send' | 'record' | 'edit' | 'schedule';\r\n\r\n const isInputEmpty = this.isInputEmpty();\r\n\r\n if(this.editMsgId) icon = 'edit';\r\n else if(!this.recorder || this.recording || !isInputEmpty || this.forwarding) icon = this.chat.type === 'scheduled' ? 'schedule' : 'send';\r\n else icon = 'record';\r\n\r\n ['send', 'record', 'edit', 'schedule'].forEach(i => {\r\n this.btnSend.classList.toggle(i, icon === i);\r\n });\r\n\r\n if(this.btnScheduled) {\r\n this.btnScheduled.classList.toggle('show', isInputEmpty);\r\n }\r\n\r\n if(this.btnToggleReplyMarkup) {\r\n this.btnToggleReplyMarkup.classList.toggle('show', isInputEmpty);\r\n }\r\n }\r\n\r\n public onMessageSent(clearInput = true, clearReply?: boolean) {\r\n if(this.chat.type !== 'scheduled') {\r\n this.appMessagesManager.readAllHistory(this.chat.peerId, this.chat.threadId, true);\r\n }\r\n\r\n this.scheduleDate = undefined;\r\n this.sendSilent = undefined;\r\n\r\n const value = this.messageInputField.value;\r\n const entities = RichTextProcessor.parseEntities(value);\r\n const emojiEntities: MessageEntity.messageEntityEmoji[] = entities.filter(entity => entity._ === 'messageEntityEmoji') as any;\r\n emojiEntities.forEach(entity => {\r\n const emoji = emojiFromCodePoints(entity.unicode);\r\n this.appEmojiManager.pushRecentEmoji(emoji);\r\n });\r\n\r\n if(clearInput) {\r\n this.lastUrl = '';\r\n delete this.noWebPage;\r\n this.willSendWebPage = null;\r\n this.clearInput();\r\n }\r\n\r\n if(clearReply || clearInput) {\r\n this.clearHelper();\r\n }\r\n\r\n this.updateSendBtn();\r\n }\r\n\r\n public sendMessage(force = false) {\r\n const {editMsgId, chat} = this;\r\n if(chat.type === 'scheduled' && !force && !editMsgId) {\r\n this.scheduleSending();\r\n return;\r\n }\r\n\r\n const {peerId} = chat;\r\n const {noWebPage} = this;\r\n const sendingParams = this.chat.getMessageSendingParams();\r\n\r\n const {value, entities} = getRichValue(this.messageInputField.input);\r\n\r\n //return;\r\n if(editMsgId) {\r\n const message = this.editMessage;\r\n if(value.trim() || message.media) {\r\n this.appMessagesManager.editMessage(message, value, {\r\n entities,\r\n noWebPage: noWebPage\r\n });\r\n\r\n this.onMessageSent();\r\n } else {\r\n new PopupDeleteMessages(peerId, [editMsgId], chat.type);\r\n\r\n return;\r\n }\r\n } else if(value.trim()) {\r\n this.appMessagesManager.sendText(peerId, value, {\r\n entities,\r\n ...sendingParams,\r\n noWebPage: noWebPage,\r\n webPage: this.getWebPagePromise ? undefined : this.willSendWebPage,\r\n clearDraft: true\r\n });\r\n\r\n this.onMessageSent(false, false);\r\n // this.onMessageSent();\r\n }\r\n\r\n // * wait for sendText set messageId for invokeAfterMsg\r\n if(this.forwarding) {\r\n const forwarding = copy(this.forwarding);\r\n setTimeout(() => {\r\n for(const fromPeerId in forwarding) {\r\n this.appMessagesManager.forwardMessages(peerId, fromPeerId.toPeerId(), forwarding[fromPeerId], {\r\n ...sendingParams,\r\n dropAuthor: this.forwardElements && this.forwardElements.hideSender.checkboxField.checked,\r\n dropCaptions: this.isDroppingCaptions()\r\n });\r\n }\r\n\r\n if(!value) {\r\n this.onMessageSent();\r\n }\r\n }, 0);\r\n }\r\n\r\n // this.onMessageSent();\r\n }\r\n\r\n public sendMessageWithDocument(document: MyDocument | string, force = false, clearDraft = false) {\r\n document = this.appDocsManager.getDoc(document);\r\n\r\n const flag = document.type === 'sticker' ? 'send_stickers' : (document.type === 'gif' ? 'send_gifs' : 'send_media');\r\n if(this.chat.peerId.isAnyChat() && !this.chat.canSend(flag)) {\r\n toast(POSTING_MEDIA_NOT_ALLOWED);\r\n return false;\r\n }\r\n\r\n if(this.chat.type === 'scheduled' && !force) {\r\n this.scheduleSending(() => this.sendMessageWithDocument(document, true, clearDraft));\r\n return false;\r\n }\r\n\r\n if(document) {\r\n this.appMessagesManager.sendFile(this.chat.peerId, document, {\r\n ...this.chat.getMessageSendingParams(),\r\n isMedia: true, \r\n clearDraft: clearDraft || undefined\r\n });\r\n this.onMessageSent(clearDraft, true);\r\n\r\n if(document.type === 'sticker') {\r\n emoticonsDropdown.stickersTab?.pushRecentSticker(document);\r\n }\r\n\r\n return true;\r\n }\r\n \r\n return false;\r\n }\r\n\r\n private canToggleHideAuthor() {\r\n const {forwardElements} = this;\r\n if(!forwardElements) return false;\r\n const hideCaptionCheckboxField = forwardElements.hideCaption.checkboxField;\r\n return !hideCaptionCheckboxField.checked ||\r\n findUpTag(hideCaptionCheckboxField.label, 'FORM').classList.contains('hide');\r\n }\r\n\r\n private isDroppingCaptions() {\r\n return !this.canToggleHideAuthor();\r\n }\r\n\r\n /* public sendSomething(callback: () => void, force = false) {\r\n if(this.chat.type === 'scheduled' && !force) {\r\n this.scheduleSending(() => this.sendSomething(callback, true));\r\n return false;\r\n }\r\n\r\n callback();\r\n this.onMessageSent(false, true);\r\n\r\n return true;\r\n } */\r\n\r\n public initMessageEditing(mid: number) {\r\n const message: Message.message = this.chat.getMessage(mid);\r\n\r\n let input = documentFragmentToHTML(RichTextProcessor.wrapDraftText(message.message, {entities: message.totalEntities}));\r\n const f = () => {\r\n const replyFragment = this.appMessagesManager.wrapMessageForReply(message, undefined, [message.mid]);\r\n this.setTopInfo('edit', f, i18n('AccDescrEditing'), replyFragment, input, message);\r\n\r\n this.editMsgId = mid;\r\n this.editMessage = message;\r\n input = undefined;\r\n };\r\n f();\r\n }\r\n\r\n public initMessagesForward(fromPeerIdsMids: {[fromPeerId: PeerId]: number[]}) {\r\n const f = () => {\r\n //const peerTitles: string[]\r\n const fromPeerIds = Object.keys(fromPeerIdsMids).map(fromPeerId => fromPeerId.toPeerId());\r\n const smth: Set<string> = new Set();\r\n let length = 0, messagesWithCaptionsLength = 0;\r\n\r\n fromPeerIds.forEach(fromPeerId => {\r\n const mids = fromPeerIdsMids[fromPeerId];\r\n mids.forEach(mid => {\r\n const message: Message.message = this.appMessagesManager.getMessageByPeer(fromPeerId, mid);\r\n if(message.fwd_from?.from_name && !message.fromId && !message.fwdFromId) {\r\n smth.add('N' + message.fwd_from.from_name);\r\n } else {\r\n smth.add('P' + message.fromId);\r\n }\r\n\r\n if(message.media && message.message) {\r\n ++messagesWithCaptionsLength;\r\n }\r\n });\r\n\r\n length += mids.length;\r\n });\r\n\r\n const onlyFirstName = smth.size > 2;\r\n const peerTitles = [...smth].map(smth => {\r\n const type = smth[0];\r\n smth = smth.slice(1);\r\n if(type === 'P') {\r\n const peerId = smth.toPeerId();\r\n return peerId === rootScope.myId ? i18n('Chat.Accessory.Forward.You') : new PeerTitle({peerId, dialog: false, onlyFirstName}).element;\r\n } else {\r\n return onlyFirstName ? smth.split(' ')[0] : smth;\r\n }\r\n });\r\n\r\n const {forwardElements} = this;\r\n const form = findUpTag(forwardElements.showCaption.checkboxField.label, 'FORM');\r\n form.classList.toggle('hide', !messagesWithCaptionsLength);\r\n const hideCaption = forwardElements.hideCaption.checkboxField.checked;\r\n if(messagesWithCaptionsLength && hideCaption) {\r\n forwardElements.hideSender.checkboxField.setValueSilently(true);\r\n } else if(this.forwardWasDroppingAuthor !== undefined) {\r\n (this.forwardWasDroppingAuthor ? forwardElements.hideSender : forwardElements.showSender).checkboxField.setValueSilently(true);\r\n }\r\n\r\n const titleKey: LangPackKey = forwardElements.showSender.checkboxField.checked ? 'Chat.Accessory.Forward' : 'Chat.Accessory.Hidden';\r\n const title = i18n(titleKey, [length]);\r\n\r\n const senderTitles = document.createDocumentFragment();\r\n if(peerTitles.length < 3) {\r\n senderTitles.append(...join(peerTitles, false));\r\n } else {\r\n senderTitles.append(peerTitles[0], i18n('AndOther', [peerTitles.length - 1]));\r\n }\r\n\r\n let firstMessage: Message.message, usingFullAlbum: boolean;\r\n if(fromPeerIds.length === 1) {\r\n const fromPeerId = fromPeerIds[0];\r\n const mids = fromPeerIdsMids[fromPeerId];\r\n firstMessage = this.appMessagesManager.getMessageByPeer(fromPeerId, mids[0]);\r\n \r\n usingFullAlbum = !!firstMessage.grouped_id;\r\n if(usingFullAlbum) {\r\n const albumMids = this.appMessagesManager.getMidsByMessage(firstMessage);\r\n if(albumMids.length !== length || albumMids.find(mid => !mids.includes(mid))) {\r\n usingFullAlbum = false;\r\n }\r\n }\r\n }\r\n\r\n const subtitleFragment = document.createDocumentFragment();\r\n const delimiter = ': ';\r\n if(usingFullAlbum || length === 1) {\r\n const mids = fromPeerIdsMids[fromPeerIds[0]];\r\n const replyFragment = this.appMessagesManager.wrapMessageForReply(firstMessage, undefined, mids);\r\n subtitleFragment.append(\r\n senderTitles, \r\n delimiter, \r\n replyFragment\r\n );\r\n } else {\r\n subtitleFragment.append(\r\n i18n('Chat.Accessory.Forward.From'), \r\n delimiter, \r\n senderTitles\r\n );\r\n }\r\n \r\n let newReply = this.setTopInfo('forward', f, title, subtitleFragment);\r\n\r\n forwardElements.modifyArgs.forEach((b, idx) => {\r\n const text = b.textElement;\r\n const intl: I18n.IntlElement = I18n.weakMap.get(text) as any;\r\n intl.args = [idx < 2 ? fromPeerIds.length : messagesWithCaptionsLength];\r\n intl.update();\r\n });\r\n\r\n if(this.forwardHover) {\r\n this.forwardHover.attachButtonListener(newReply, this.listenerSetter);\r\n }\r\n\r\n this.forwarding = fromPeerIdsMids;\r\n };\r\n \r\n f();\r\n }\r\n\r\n public initMessageReply(mid: number) {\r\n if(this.replyToMsgId === mid) {\r\n return;\r\n }\r\n \r\n let message: Message = this.chat.getMessage(mid);\r\n const f = () => {\r\n let peerTitleEl: HTMLElement;\r\n if(message._ === 'messageEmpty') { // load missing replying message\r\n peerTitleEl = i18n('Loading');\r\n\r\n this.chat.appMessagesManager.wrapSingleMessage(this.chat.peerId, mid).then((_message) => {\r\n if(this.replyToMsgId !== mid) {\r\n return;\r\n }\r\n\r\n message = _message;\r\n if(message._ === 'messageEmpty') {\r\n this.clearHelper('reply');\r\n } else {\r\n f();\r\n }\r\n });\r\n } else {\r\n peerTitleEl = new PeerTitle({\r\n peerId: message.fromId,\r\n dialog: false\r\n }).element;\r\n }\r\n\r\n this.setTopInfo('reply', f, peerTitleEl, message && (message as Message.message).message, undefined, message);\r\n this.replyToMsgId = mid;\r\n };\r\n f();\r\n }\r\n\r\n public clearHelper(type?: ChatInputHelperType) {\r\n if(this.helperType === 'edit' && type !== 'edit') {\r\n this.clearInput();\r\n }\r\n\r\n if(type) {\r\n this.lastUrl = '';\r\n delete this.noWebPage;\r\n this.willSendWebPage = null;\r\n }\r\n \r\n if(type !== 'reply') {\r\n this.replyToMsgId = undefined;\r\n this.forwarding = undefined;\r\n }\r\n\r\n this.editMsgId = this.editMessage = undefined;\r\n this.helperType = this.helperFunc = undefined;\r\n\r\n if(this.chat.container.classList.contains('is-helper-active')) {\r\n appNavigationController.removeByType('input-helper');\r\n this.chat.container.classList.remove('is-helper-active');\r\n this.t();\r\n }\r\n }\r\n\r\n private t() {\r\n const className = 'is-toggling-helper';\r\n SetTransition(this.chat.container, className, true, 150, () => {\r\n this.chat.container.classList.remove(className);\r\n });\r\n }\r\n\r\n public setInputValue(value: string, clear = true, focus = true) {\r\n if(!value) value = '';\r\n\r\n if(clear) this.clearInput(false, false, value);\r\n else this.messageInputField.setValueSilently(value);\r\n\r\n fastRaf(() => {\r\n focus && placeCaretAtEnd(this.messageInput);\r\n this.onMessageInput();\r\n this.messageInput.scrollTop = this.messageInput.scrollHeight;\r\n });\r\n }\r\n\r\n public setTopInfo(\r\n type: ChatInputHelperType, \r\n callerFunc: () => void, \r\n title: Parameters<typeof wrapReply>[0] = '', \r\n subtitle: Parameters<typeof wrapReply>[1] = '', \r\n input?: string, \r\n message?: any\r\n ) {\r\n if(this.willSendWebPage && type === 'reply') {\r\n return;\r\n }\r\n\r\n if(type !== 'webpage') {\r\n this.clearHelper(type);\r\n this.helperType = type;\r\n this.helperFunc = callerFunc;\r\n }\r\n \r\n const replyParent = this.replyElements.container;\r\n const oldReply = replyParent.lastElementChild.previousElementSibling;\r\n const haveReply = oldReply.classList.contains('reply');\r\n\r\n this.replyElements.iconBtn.replaceWith(this.replyElements.iconBtn = ButtonIcon((type === 'webpage' ? 'link' : type) + ' active reply-icon', {noRipple: true}));\r\n const newReply = wrapReply(title, subtitle, message);\r\n if(haveReply) {\r\n oldReply.replaceWith(newReply);\r\n } else {\r\n replyParent.insertBefore(newReply, replyParent.lastElementChild);\r\n }\r\n\r\n if(type === 'webpage') {\r\n newReply.style.cursor = 'default';\r\n }\r\n\r\n if(!this.chat.container.classList.contains('is-helper-active')) {\r\n this.chat.container.classList.add('is-helper-active');\r\n this.t();\r\n }\r\n\r\n /* const scroll = appImManager.scrollable;\r\n if(scroll.isScrolledDown && !scroll.scrollLocked && !appImManager.messagesQueuePromise && !appImManager.setPeerPromise) {\r\n scroll.scrollTo(scroll.scrollHeight, 'top', true, true, 200);\r\n } */\r\n\r\n if(!IS_MOBILE) {\r\n appNavigationController.pushItem({\r\n type: 'input-helper',\r\n onPop: () => {\r\n this.onHelperCancel();\r\n }\r\n });\r\n }\r\n\r\n if(input !== undefined) {\r\n this.setInputValue(input);\r\n }\r\n\r\n setTimeout(() => {\r\n this.updateSendBtn();\r\n }, 0);\r\n\r\n return newReply;\r\n }\r\n\r\n // public saveScroll() {\r\n // this.scrollTop = this.chat.bubbles.scrollable.container.scrollTop;\r\n // this.scrollOffsetTop = this.chatInput.offsetTop;\r\n // }\r\n\r\n // public restoreScroll() {\r\n // if(this.chatInput.style.display) return;\r\n // //console.log('input resize', offsetTop, this.chatInput.offsetTop);\r\n // let newOffsetTop = this.chatInput.offsetTop;\r\n // let container = this.chat.bubbles.scrollable.container;\r\n // let scrollTop = container.scrollTop;\r\n // let clientHeight = container.clientHeight;\r\n // let maxScrollTop = container.scrollHeight;\r\n\r\n // if(newOffsetTop < this.scrollOffsetTop) {\r\n // this.scrollDiff = this.scrollOffsetTop - newOffsetTop;\r\n // container.scrollTop += this.scrollDiff;\r\n // } else if(scrollTop !== this.scrollTop) {\r\n // let endDiff = maxScrollTop - (scrollTop + clientHeight);\r\n // if(endDiff < this.scrollDiff/* && false */) {\r\n // //container.scrollTop -= endDiff;\r\n // } else {\r\n // container.scrollTop -= this.scrollDiff;\r\n // }\r\n // }\r\n // }\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nexport default function setCaretAt(node: Node) {\n // node.appendChild(document.createTextNode(''));\n\n const originalNode = node;\n node = node.previousSibling;\n\n if(node.nodeType === 1) {\n const newNode = document.createTextNode('');\n node.parentNode.insertBefore(newNode, !originalNode.nextSibling || originalNode.nextSibling.nodeType === node.nodeType ? originalNode : originalNode.nextSibling);\n node = newNode;\n }\n\n if(window.getSelection && document.createRange) {\n const range = document.createRange();\n if(node) {\n range.setStartAfter(node);\n range.insertNode(node);\n range.setStart(node, node.nodeValue.length);\n }\n\n range.collapse(true);\n\n const sel = window.getSelection();\n sel.removeAllRanges();\n sel.addRange(range);\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport type Chat from \"./chat\";\r\nimport type ChatTopbar from \"./topbar\";\r\nimport mediaSizes from \"../../helpers/mediaSizes\";\r\nimport DivAndCaption from \"../divAndCaption\";\r\nimport ripple from \"../ripple\";\r\nimport ListenerSetter from \"../../helpers/listenerSetter\";\r\nimport cancelEvent from \"../../helpers/dom/cancelEvent\";\r\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\r\nimport { Message } from \"../../layer\";\r\nimport safeAssign from \"../../helpers/object/safeAssign\";\r\n\r\nconst classNames: string[] = ['is-pinned-message-shown', 'is-pinned-audio-shown'];\r\nconst CLASSNAME_BASE = 'pinned-container';\r\nconst HEIGHT = 52;\r\n\r\nexport default class PinnedContainer {\r\n public wrapperUtils: HTMLElement;\r\n public btnClose: HTMLElement;\r\n protected wrapper: HTMLElement;\r\n\r\n protected topbar: ChatTopbar;\r\n protected chat: Chat;\r\n protected listenerSetter: ListenerSetter;\r\n public className: string;\r\n public divAndCaption: DivAndCaption<(title: string | HTMLElement | DocumentFragment, subtitle: string | HTMLElement | DocumentFragment, message?: any) => void>;\r\n \r\n protected floating = false;\r\n\r\n public onClose?: () => void | Promise<boolean>;\r\n\r\n constructor(options: {\r\n topbar: PinnedContainer['topbar'],\r\n chat: PinnedContainer['chat'],\r\n listenerSetter: PinnedContainer['listenerSetter'],\r\n className: PinnedContainer['className'],\r\n divAndCaption: PinnedContainer['divAndCaption'],\r\n onClose?: PinnedContainer['onClose'],\r\n floating?: PinnedContainer['floating']\r\n }) {\r\n safeAssign(this, options);\r\n\r\n const {divAndCaption, className} = this;\r\n divAndCaption.container.classList.add(CLASSNAME_BASE, 'hide');\r\n divAndCaption.title.classList.add(CLASSNAME_BASE + '-title');\r\n divAndCaption.subtitle.classList.add(CLASSNAME_BASE + '-subtitle');\r\n divAndCaption.content.classList.add(CLASSNAME_BASE + '-content');\r\n \r\n this.btnClose = document.createElement('button');\r\n this.btnClose.classList.add(CLASSNAME_BASE + '-close', `pinned-${className}-close`, 'btn-icon', 'tgico-close');\r\n \r\n this.wrapper = document.createElement('div');\r\n this.wrapper.classList.add(CLASSNAME_BASE + '-wrapper');\r\n ripple(this.wrapper);\r\n\r\n this.wrapperUtils = document.createElement('div');\r\n this.wrapperUtils.classList.add(CLASSNAME_BASE + '-wrapper-utils');\r\n this.wrapperUtils.append(this.btnClose);\r\n\r\n this.wrapper.append(...Array.from(divAndCaption.container.children), this.wrapperUtils);\r\n\r\n divAndCaption.container.append(this.wrapper/* , this.close */);\r\n\r\n this.attachOnCloseEvent(this.btnClose);\r\n }\r\n\r\n public attachOnCloseEvent(elem: HTMLElement) {\r\n attachClickEvent(elem, (e) => {\r\n cancelEvent(e);\r\n\r\n ((this.onClose ? this.onClose() : null) || Promise.resolve(true)).then(needClose => {\r\n if(needClose) {\r\n this.toggle(true);\r\n }\r\n });\r\n }, {listenerSetter: this.listenerSetter});\r\n }\r\n\r\n public toggle(hide?: boolean) {\r\n const isHidden = this.divAndCaption.container.classList.contains('hide');\r\n if(hide === undefined) {\r\n hide = !isHidden;\r\n } else if(hide === isHidden) {\r\n return;\r\n }\r\n\r\n // const scrollable = this.chat.bubbles.scrollable;\r\n \r\n const isFloating = (this.floating || mediaSizes.isMobile) && !hide;\r\n // const scrollTop = isFloating || this.divAndCaption.container.classList.contains('is-floating') ? scrollable.scrollTop : undefined;\r\n\r\n this.divAndCaption.container.classList.toggle('is-floating', isFloating);\r\n this.divAndCaption.container.classList.toggle('hide', hide);\r\n \r\n this.topbar.container.classList.toggle('is-pinned-floating', isFloating);\r\n this.topbar.container.classList.toggle(`is-pinned-${this.className}-shown`, !hide);\r\n \r\n // const active = classNames.filter(className => this.topbar.container.classList.contains(className));\r\n // const maxActive = hide ? 0 : 1;\r\n \r\n // * not sure when it became unneeded\r\n // if(scrollTop !== undefined && active.length <= maxActive/* && !scrollable.isScrolledDown */) {\r\n // scrollable.scrollTop = scrollTop + ((hide ? -1 : 1) * HEIGHT);\r\n // }\r\n \r\n this.topbar.setFloating();\r\n this.topbar.setUtilsWidth();\r\n }\r\n\r\n public isVisible() {\r\n return !this.divAndCaption.container.classList.contains('hide');\r\n }\r\n\r\n public isFloating() {\r\n return this.divAndCaption.container.classList.contains('is-floating');\r\n }\r\n\r\n public fill(title: string | HTMLElement | DocumentFragment, subtitle: string | HTMLElement | DocumentFragment, message: Message.message) {\r\n this.divAndCaption.container.dataset.peerId = '' + message.peerId;\r\n this.divAndCaption.container.dataset.mid = '' + message.mid;\r\n this.divAndCaption.fill(title, subtitle, message);\r\n this.topbar.setUtilsWidth();\r\n }\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport cancelEvent from \"../helpers/dom/cancelEvent\";\nimport { attachClickEvent } from \"../helpers/dom/clickEvent\";\nimport ListenerSetter from \"../helpers/listenerSetter\";\nimport rootScope from \"../lib/rootScope\";\nimport appMediaPlaybackController from \"./appMediaPlaybackController\";\nimport RangeSelector from \"./rangeSelector\";\n\nexport default class VolumeSelector extends RangeSelector {\n private static ICONS = ['volume_off', 'volume_mute', 'volume_down', 'volume_up'];\n public btn: HTMLElement;\n protected icon: HTMLSpanElement;\n\n constructor(protected listenerSetter: ListenerSetter, protected vertical = false) {\n super({\n step: 0.01, \n min: 0, \n max: 1,\n vertical\n }, 1);\n\n this.setListeners();\n this.setHandlers({\n onScrub: currentTime => {\n const value = Math.max(Math.min(currentTime, 1), 0);\n\n //console.log('volume scrub:', currentTime, value);\n\n appMediaPlaybackController.muted = false;\n appMediaPlaybackController.volume = value;\n },\n\n /* onMouseUp: (e) => {\n cancelEvent(e.event);\n } */\n });\n\n const className = 'player-volume';\n const btn = this.btn = document.createElement('div');\n btn.classList.add('btn-icon', className);\n const icon = this.icon = document.createElement('span');\n icon.classList.add(className + '__icon');\n\n btn.append(icon, this.container);\n\n attachClickEvent(icon, this.onMuteClick, {listenerSetter: this.listenerSetter});\n this.listenerSetter.add(rootScope)('media_playback_params', this.setVolume);\n\n this.setVolume();\n }\n\n private onMuteClick = (e?: Event) => {\n e && cancelEvent(e);\n appMediaPlaybackController.muted = !appMediaPlaybackController.muted;\n };\n\n public setVolume = () => {\n // const volume = video.volume;\n const {volume, muted} = appMediaPlaybackController;\n let d: string;\n let iconIndex: number;\n if(!volume || muted) {\n iconIndex = 0;\n } else if(volume > .5) {\n iconIndex = 3;\n } else if(volume > 0 && volume < .25) {\n iconIndex = 1;\n } else {\n iconIndex = 2;\n }\n\n VolumeSelector.ICONS.forEach(icon => this.icon.classList.remove('tgico-' + icon));\n this.icon.classList.add('tgico-' + VolumeSelector.ICONS[iconIndex]);\n\n if(!this.mousedown) {\n this.setProgress(muted ? 0 : volume);\n }\n };\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport type { AppMessagesManager } from \"../../lib/appManagers/appMessagesManager\";\nimport type ChatTopbar from \"./topbar\";\nimport rootScope from \"../../lib/rootScope\";\nimport appMediaPlaybackController, { AppMediaPlaybackController } from \"../appMediaPlaybackController\";\nimport DivAndCaption from \"../divAndCaption\";\nimport PinnedContainer from \"./pinnedContainer\";\nimport Chat from \"./chat\";\nimport cancelEvent from \"../../helpers/dom/cancelEvent\";\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\nimport replaceContent from \"../../helpers/dom/replaceContent\";\nimport PeerTitle from \"../peerTitle\";\nimport { i18n } from \"../../lib/langPack\";\nimport { formatFullSentTime } from \"../../helpers/date\";\nimport ButtonIcon from \"../buttonIcon\";\nimport { DocumentAttribute } from \"../../layer\";\nimport MediaProgressLine from \"../mediaProgressLine\";\nimport VolumeSelector from \"../volumeSelector\";\nimport RichTextProcessor from \"../../lib/richtextprocessor\";\n\nexport default class ChatAudio extends PinnedContainer {\n private toggleEl: HTMLElement;\n private progressLine: MediaProgressLine;\n private volumeSelector: VolumeSelector;\n private fasterEl: HTMLElement;\n private repeatEl: HTMLButtonElement;\n\n constructor(protected topbar: ChatTopbar, protected chat: Chat, protected appMessagesManager: AppMessagesManager) {\n super({\n topbar, \n chat, \n listenerSetter: topbar.listenerSetter, \n className: 'audio', \n divAndCaption: new DivAndCaption(\n 'pinned-audio', \n (title: string | HTMLElement | DocumentFragment, subtitle: string | HTMLElement | DocumentFragment) => {\n replaceContent(this.divAndCaption.title, title);\n replaceContent(this.divAndCaption.subtitle, subtitle);\n }\n ), \n onClose: () => {\n appMediaPlaybackController.stop();\n },\n floating: true\n });\n\n this.divAndCaption.border.remove();\n\n const prevEl = ButtonIcon('fast_rewind active', {noRipple: true});\n const nextEl = ButtonIcon('fast_forward active', {noRipple: true});\n\n const attachClick = (elem: HTMLElement, callback: () => void) => {\n attachClickEvent(elem, (e) => {\n cancelEvent(e);\n callback();\n }, {listenerSetter: this.topbar.listenerSetter});\n };\n\n attachClick(prevEl, () => {\n appMediaPlaybackController.previous();\n });\n\n attachClick(nextEl, () => {\n appMediaPlaybackController.next();\n });\n\n this.toggleEl = ButtonIcon('', {noRipple: true});\n this.toggleEl.classList.add('active', 'pinned-audio-ico', 'tgico');\n attachClick(this.toggleEl, () => {\n appMediaPlaybackController.toggle();\n });\n this.wrapper.prepend(this.wrapper.firstElementChild, prevEl, this.toggleEl, nextEl);\n\n this.volumeSelector = new VolumeSelector(this.listenerSetter, true);\n const volumeProgressLineContainer = document.createElement('div');\n volumeProgressLineContainer.classList.add('progress-line-container');\n volumeProgressLineContainer.append(this.volumeSelector.container);\n const tunnel = document.createElement('div');\n tunnel.classList.add('pinned-audio-volume-tunnel');\n this.volumeSelector.btn.classList.add('pinned-audio-volume', 'active');\n this.volumeSelector.btn.prepend(tunnel);\n this.volumeSelector.btn.append(volumeProgressLineContainer);\n\n this.repeatEl = ButtonIcon('audio_repeat', {noRipple: true});\n attachClick(this.repeatEl, () => {\n const params = appMediaPlaybackController.getPlaybackParams();\n if(!params.round) {\n appMediaPlaybackController.round = true;\n } else if(params.loop) {\n appMediaPlaybackController.round = false;\n appMediaPlaybackController.loop = false;\n } else {\n appMediaPlaybackController.loop = !appMediaPlaybackController.loop;\n }\n });\n\n const fasterEl = this.fasterEl = ButtonIcon('playback_2x', {noRipple: true});\n attachClick(fasterEl, () => {\n appMediaPlaybackController.playbackRate = fasterEl.classList.contains('active') ? 1 : 1.75;\n });\n\n this.wrapperUtils.prepend(this.volumeSelector.btn, fasterEl, this.repeatEl);\n\n const progressWrapper = document.createElement('div');\n progressWrapper.classList.add('pinned-audio-progress-wrapper');\n\n this.progressLine = new MediaProgressLine(undefined, undefined, true, true);\n this.progressLine.container.classList.add('pinned-audio-progress');\n progressWrapper.append(this.progressLine.container);\n this.wrapper.insertBefore(progressWrapper, this.wrapperUtils);\n\n this.topbar.listenerSetter.add(rootScope)('media_play', this.onMediaPlay);\n this.topbar.listenerSetter.add(rootScope)('media_pause', this.onPause);\n this.topbar.listenerSetter.add(rootScope)('media_stop', this.onStop);\n this.topbar.listenerSetter.add(rootScope)('media_playback_params', this.onPlaybackParams);\n\n const playingDetails = appMediaPlaybackController.getPlayingDetails();\n if(playingDetails) {\n this.onMediaPlay(playingDetails);\n this.onPlaybackParams(playingDetails.playbackParams);\n }\n }\n\n public destroy() {\n if(this.progressLine) {\n this.progressLine.removeListeners();\n }\n }\n\n private onPlaybackParams = (playbackParams: ReturnType<AppMediaPlaybackController['getPlaybackParams']>) => {\n this.fasterEl.classList.toggle('active', playbackParams.playbackRate > 1);\n\n this.repeatEl.classList.remove('tgico-audio_repeat', 'tgico-audio_repeat_single');\n this.repeatEl.classList.add(playbackParams.loop ? 'tgico-audio_repeat_single' : 'tgico-audio_repeat');\n this.repeatEl.classList.toggle('active', playbackParams.loop || playbackParams.round);\n };\n\n private onPause = () => {\n this.toggleEl.classList.remove('flip-icon');\n };\n\n private onStop = () => {\n this.toggle(true);\n };\n \n private onMediaPlay = ({doc, message, media, playbackParams}: ReturnType<AppMediaPlaybackController['getPlayingDetails']>) => {\n let title: string | HTMLElement | DocumentFragment, subtitle: string | HTMLElement | DocumentFragment;\n const isMusic = doc.type !== 'voice' && doc.type !== 'round';\n if(!isMusic) {\n title = new PeerTitle({peerId: message.fromId, fromName: message.fwd_from?.from_name}).element;\n\n //subtitle = 'Voice message';\n subtitle = formatFullSentTime(message.date);\n } else {\n const audioAttribute = doc.attributes.find((attr) => attr._ === 'documentAttributeAudio') as DocumentAttribute.documentAttributeAudio;\n title = RichTextProcessor.wrapEmojiText(audioAttribute?.title ?? doc.file_name);\n subtitle = audioAttribute?.performer ? RichTextProcessor.wrapEmojiText(audioAttribute.performer) : i18n('AudioUnknownArtist');\n }\n\n this.fasterEl.classList.toggle('hide', isMusic);\n this.repeatEl.classList.toggle('hide', !isMusic);\n\n this.onPlaybackParams(playbackParams);\n this.volumeSelector.setVolume();\n\n this.progressLine.setMedia(media);\n\n this.fill(title, subtitle, message);\n // this.toggleEl.classList.add('flip-icon');\n this.toggleEl.classList.toggle('flip-icon', !media.paused);\n this.toggle(false);\n };\n}\n","// https://github.com/evgeny-nadymov/telegram-react/blob/master/src/Components/ColumnMiddle/PinnedMessageBorder.js\n\nenum BAR_HEIGHTS {\n ONE = 32,\n TWO = 15,\n THREE = 10,\n FOUR = 8,\n MORE = 8\n};\n\nconst GAP = 1;\nconst WIDTH = 2;\nconst BASE_CLASS = 'pinned-message-border';\n\nexport default class PinnedMessageBorder {\n private border: HTMLElement;\n private wrapper: HTMLElement;\n private svg: SVGSVGElement;\n private defs: SVGDefsElement;\n private clipPath: SVGClipPathElement;\n private path: SVGPathElement;\n private mark: HTMLElement;\n\n private count: number;\n private index: number;\n\n private drawRect = (x: number, y: number, width: number, height: number, radius: number) => {\n return `M${x},${y + radius}a${radius},${radius},0,0,1,${width},0v${height - 2 * radius}a${radius},${radius},0,0,1,${-width},0Z`;\n };\n\n private getClipPath = (id: string, barHeight: number, count: number) => {\n const radius = 1;\n\n let d = '';\n /* if(count === 3) {\n d = this.drawRect(0, 0, WIDTH, barHeight, radius)\n + this.drawRect(0, barHeight + GAP, WIDTH, barHeight + 1, radius)\n + this.drawRect(0, barHeight * 2 + GAP * 2 + 1, WIDTH, barHeight, radius);\n } */if(count === 2) {\n d = this.drawRect(0, 0, WIDTH, barHeight, radius) + this.drawRect(0, barHeight + GAP * 2, WIDTH, barHeight, radius);\n } else {\n for(let i = 0; i < count; ++i) {\n d += this.drawRect(0, (barHeight + GAP) * i, WIDTH, barHeight, radius);\n }\n }\n\n if(!this.clipPath) {\n this.clipPath = document.createElementNS('http://www.w3.org/2000/svg', 'clipPath');\n this.path = document.createElementNS('http://www.w3.org/2000/svg', 'path');\n\n this.clipPath.append(this.path);\n }\n\n this.clipPath.id = id;\n this.path.setAttributeNS(null, 'd', d);\n\n return this.clipPath;\n };\n\n private getBarHeight = (count: number, index: number) => {\n let barHeight: number;\n if(count <= 1) {\n barHeight = BAR_HEIGHTS.ONE;\n } else if(count === 2) {\n barHeight = BAR_HEIGHTS.TWO;\n } else if(count === 3) {\n barHeight = BAR_HEIGHTS.THREE;\n } else if(count === 4) {\n barHeight = BAR_HEIGHTS.FOUR;\n } else if(count > 3) {\n barHeight = BAR_HEIGHTS.MORE;\n }\n\n return barHeight;\n };\n\n private getMarkHeight = (count: number, index: number) => {\n let markHeight: number;\n if(count <= 1) {\n markHeight = BAR_HEIGHTS.ONE;\n } else if(count === 2) {\n markHeight = BAR_HEIGHTS.TWO;\n } else if(count === 3) {\n markHeight = BAR_HEIGHTS.THREE;\n } else if(count === 4) {\n markHeight = BAR_HEIGHTS.FOUR;\n } else if(count > 3) {\n markHeight = BAR_HEIGHTS.MORE;\n }\n\n return markHeight;\n };\n\n private getMarkTranslateY = (index: number, barHeight: number, count: number) => {\n if(count === 1) {\n return 0;\n } else if(count === 2) {\n return !index ? 0 : barHeight + GAP;\n }\n\n if(count === 3) {\n if(!index) {\n return 0;\n } else if(index === 1) {\n return barHeight + GAP;\n }\n\n return barHeight * 2 + GAP * 2 + 1;\n } else {\n return (barHeight + GAP) * index;\n }\n };\n\n private getTrackTranslateY = (index: number, count: number, barHeight: number, trackHeight: number) => {\n if(count <= 4) {\n return 0;\n }\n\n if(index <= 1) {\n return 0;\n } else if(index >= (count - 2)) {\n return trackHeight - BAR_HEIGHTS.ONE - barHeight;\n }\n\n // return (index + 1) * barHeight + index * GAP;\n return (index - 2) * barHeight + index * GAP;\n //return (barHeight + GAP * 2) / 2 + (index - 2) * (barHeight + GAP);\n };\n\n private getTrackHeight = (count: number, barHeight: number) => {\n return count <= 3 ? BAR_HEIGHTS.ONE : barHeight * count + GAP * (count - 1);\n };\n\n public render(count: number, index: number) {\n if(!this.border) {\n this.border = document.createElement('div');\n this.border.classList.add(BASE_CLASS);\n\n this.wrapper = document.createElement('div');\n this.border.append(this.wrapper);\n }\n \n if(count === 1) {\n if(this.count !== count) {\n this.wrapper.className = BASE_CLASS + '-wrapper-1';\n this.border.classList.remove(BASE_CLASS + '-mask');\n this.wrapper.innerHTML = this.wrapper.style.cssText = '';\n }\n\n return this.border;\n }\n\n const barHeight = this.getBarHeight(count, index);\n const markHeight = this.getMarkHeight(count, index);\n const trackHeight = this.getTrackHeight(count, barHeight);\n\n const clipPathId = `clipPath_${count}`;\n const clipPath = this.getClipPath(clipPathId, barHeight, count);\n\n const markTranslateY = this.getMarkTranslateY(index, barHeight, count);\n const trackTranslateY = this.getTrackTranslateY(index, count, barHeight, trackHeight);\n\n this.border.classList.toggle(BASE_CLASS + '-mask', count > 4);\n\n if(index <= 1) {\n this.border.classList.add('mask-bottom');\n this.border.classList.remove('mask-top');\n } else if(index >= (count - 2)) {\n this.border.classList.add('mask-top');\n this.border.classList.remove('mask-bottom');\n } else {\n this.border.classList.add('mask-top', 'mask-bottom');\n }\n\n this.wrapper.className = BASE_CLASS + '-wrapper';\n this.wrapper.style.cssText = `clip-path: url(#${clipPathId}); width: 2px; height: ${trackHeight}px; transform: translateY(-${trackTranslateY}px);`;\n \n if(!this.svg) {\n this.svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n this.svg.setAttributeNS(null, 'height', '0');\n this.svg.setAttributeNS(null, 'width', '0');\n \n this.defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs');\n this.defs.append(clipPath);\n\n this.svg.append(this.defs);\n\n this.mark = document.createElement('div');\n this.mark.classList.add(BASE_CLASS + '-mark');\n }\n\n if(!this.svg.parentElement) {\n this.wrapper.append(this.svg, this.mark);\n }\n\n this.mark.style.cssText = `height: ${markHeight}px; transform: translateY(${markTranslateY}px);`;\n \n this.count = count;\n this.index = index;\n\n return this.border;\n }\n}","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport type { AppMessagesManager } from \"../../lib/appManagers/appMessagesManager\";\r\nimport type { AppPeersManager } from \"../../lib/appManagers/appPeersManager\";\r\nimport type ChatTopbar from \"./topbar\";\r\nimport PopupPinMessage from \"../popups/unpinMessage\";\r\nimport PinnedContainer from \"./pinnedContainer\";\r\nimport PinnedMessageBorder from \"./pinnedMessageBorder\";\r\nimport ReplyContainer, { wrapReplyDivAndCaption } from \"./replyContainer\";\r\nimport rootScope from \"../../lib/rootScope\";\r\nimport Chat from \"./chat\";\r\nimport ListenerSetter from \"../../helpers/listenerSetter\";\r\nimport ButtonIcon from \"../buttonIcon\";\r\nimport { getHeavyAnimationPromise } from \"../../hooks/useHeavyAnimationCheck\";\r\nimport { i18n } from \"../../lib/langPack\";\r\nimport cancelEvent from \"../../helpers/dom/cancelEvent\";\r\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\r\nimport handleScrollSideEvent from \"../../helpers/dom/handleScrollSideEvent\";\r\nimport debounce from \"../../helpers/schedulers/debounce\";\r\nimport throttle from \"../../helpers/schedulers/throttle\";\r\n\r\nclass AnimatedSuper {\r\n static DURATION = 200;\r\n static BASE_CLASS = 'animated-super';\r\n container: HTMLDivElement;\r\n rows: {[index: string]: {element: HTMLElement, timeout?: number, new?: true}} = {};\r\n clearTimeout: number;\r\n\r\n constructor() {\r\n this.container = document.createElement('div');\r\n this.container.className = AnimatedSuper.BASE_CLASS;\r\n }\r\n\r\n public getRow(index: number, animateFirst = false) {\r\n if(this.rows[index]) return this.rows[index].element;\r\n const row = document.createElement('div');\r\n const isFirst = !Object.keys(this.rows).length && !animateFirst;\r\n row.className = AnimatedSuper.BASE_CLASS + '-row' + (isFirst ? '' : ' is-hiding hide');\r\n this.rows[index] = {element: row, new: true};\r\n this.container.append(row);\r\n return row;\r\n }\r\n\r\n public clearRow(index: number) {\r\n if(!this.rows[index]) return;\r\n this.rows[index].element.remove();\r\n delete this.rows[index];\r\n }\r\n\r\n public clearRows(currentIndex?: number) {\r\n if(this.clearTimeout) clearTimeout(this.clearTimeout);\r\n this.clearTimeout = window.setTimeout(() => {\r\n for(const i in this.rows) {\r\n if(+i === currentIndex) continue;\r\n this.clearRow(+i);\r\n }\r\n }, AnimatedSuper.DURATION);\r\n }\r\n\r\n public setNewRow(index: number, reflow = false) {\r\n const row = this.rows[index];\r\n if(row.new) {\r\n if(reflow) {\r\n row.element.classList.remove('hide');\r\n void row.element.offsetLeft; // reflow\r\n } else {\r\n row.element.classList.remove('is-hiding', 'hide');\r\n }\r\n\r\n delete row.new;\r\n }\r\n\r\n this.clearRows(index);\r\n }\r\n\r\n public animate(index: number, previousIndex: number, fromTop = index > previousIndex, ignorePrevious = false) {\r\n if(index === previousIndex) { // * handle if set index 0 and previousIndex 0\r\n return this.setNewRow(index);\r\n }\r\n\r\n const row = this.rows[index];\r\n const previousRow = this.rows[previousIndex];\r\n if(!previousRow && !ignorePrevious) {\r\n return this.setNewRow(index);\r\n }\r\n\r\n const sides = ['from-top', 'from-bottom'];\r\n if(!fromTop) sides.reverse();\r\n\r\n row.element.classList.add(sides[0]);\r\n row.element.classList.remove(sides[1]);\r\n if(previousRow) {\r\n previousRow.element.classList.add(sides[1]);\r\n previousRow.element.classList.remove(sides[0]);\r\n }\r\n\r\n if(row.new) {\r\n this.setNewRow(index, true);\r\n }\r\n\r\n row.element.classList.toggle('is-hiding', false);\r\n previousRow && previousRow.element.classList.toggle('is-hiding', true);\r\n\r\n /* const height = row.element.getBoundingClientRect().height;\r\n row.element.style.transform = `translateY(${fromTop ? height * -1 : height}px)`;\r\n if(previousRow) {\r\n previousRow.element.style.transform = `translateY(${fromTop ? height : height * -1}px)`;\r\n } */\r\n\r\n /* row.element.style.setProperty('--height', row.element.getBoundingClientRect().height + 'px');\r\n if(previousRow) {\r\n previousRow.element.style.setProperty('--height', previousRow.element.getBoundingClientRect().height + 'px');\r\n } */\r\n \r\n this.clearRows(index);\r\n }\r\n}\r\n\r\nclass AnimatedCounter {\r\n static EMPTY_INDEX = -1;\r\n static BASE_CLASS = 'animated-counter';\r\n container: HTMLElement;\r\n decimals: {\r\n container: HTMLElement,\r\n placeholder: HTMLElement,\r\n animatedSuper: AnimatedSuper\r\n }[] = [];\r\n previousNumber = 0;\r\n clearTimeout: number;\r\n\r\n constructor(private reverse = false) {\r\n this.container = document.createElement('div');\r\n this.container.className = AnimatedCounter.BASE_CLASS;\r\n }\r\n\r\n getDecimal(index: number) {\r\n if(this.decimals[index]) return this.decimals[index];\r\n const item = document.createElement('div');\r\n item.className = AnimatedCounter.BASE_CLASS + '-decimal';\r\n\r\n const placeholder = document.createElement('div');\r\n placeholder.className = AnimatedCounter.BASE_CLASS + '-decimal-placeholder';\r\n\r\n const animatedSuper = new AnimatedSuper();\r\n animatedSuper.container.className = AnimatedCounter.BASE_CLASS + '-decimal-wrapper';\r\n\r\n item.append(placeholder, animatedSuper.container);\r\n\r\n this.container.append(item);\r\n\r\n return this.decimals[index] = {container: item, placeholder, animatedSuper};\r\n }\r\n\r\n clear(number: number) {\r\n if(this.clearTimeout) clearTimeout(this.clearTimeout);\r\n\r\n const decimals = ('' + number).length;\r\n if(decimals >= this.decimals.length) {\r\n return;\r\n }\r\n\r\n this.clearTimeout = window.setTimeout(() => {\r\n const byDecimal = this.decimals.splice(decimals, this.decimals.length - decimals);\r\n byDecimal.forEach((decimal) => {\r\n decimal.container.remove();\r\n });\r\n }, AnimatedSuper.DURATION);\r\n }\r\n\r\n /* prepareNumber(number: number) {\r\n const decimals = ('' + number).length;\r\n if(this.decimals.length < decimals) {\r\n for(let i = this.decimals.length; i < decimals; ++i) {\r\n this.getDecimal(i);\r\n }\r\n }\r\n } */\r\n\r\n hideLeft(number: number) {\r\n const decimals = ('' + number).length;\r\n const byDecimal = this.decimals.slice(decimals);//this.decimals.splice(deleteCount, this.decimals.length - deleteCount);\r\n byDecimal.forEach((decimal) => {\r\n const previousDecimalNumber = +decimal.placeholder.innerText || 0;\r\n const row = decimal.animatedSuper.getRow(AnimatedCounter.EMPTY_INDEX, true);\r\n decimal.animatedSuper.animate(AnimatedCounter.EMPTY_INDEX, previousDecimalNumber, this.reverse ? number < this.previousNumber : number > this.previousNumber, true);\r\n });\r\n\r\n this.clear(number);\r\n }\r\n\r\n setCount(number: number) {\r\n //this.prepareNumber(number);\r\n\r\n const previousByDecimal = Array.from('' + this.previousNumber).map(n => +n);\r\n const byDecimal = Array.from('' + number).map(n => +n);\r\n byDecimal.forEach((decimalNumber, idx) => {\r\n const decimal = this.getDecimal(idx);\r\n //const row = decimal.animatedSuper.getRow(number, true);\r\n const row = decimal.animatedSuper.getRow(decimalNumber, true);\r\n const previousDecimalNumber = previousByDecimal[idx] ?? AnimatedCounter.EMPTY_INDEX;\r\n row.innerText = decimal.placeholder.innerText = '' + decimalNumber;\r\n //decimal.animatedSuper.animate(number, this.previousNumber, this.reverse ? number < this.previousNumber : number > this.previousNumber, true);\r\n decimal.animatedSuper.animate(decimalNumber, previousDecimalNumber, this.reverse ? number < this.previousNumber : number > this.previousNumber, true);\r\n });\r\n\r\n this.hideLeft(number);\r\n //this.clear(number);\r\n this.previousNumber = number;\r\n }\r\n}\r\n\r\nexport default class ChatPinnedMessage {\r\n private static LOAD_COUNT = 50;\r\n private static LOAD_OFFSET = 5;\r\n\r\n public pinnedMessageContainer: PinnedContainer;\r\n private pinnedMessageBorder: PinnedMessageBorder;\r\n\r\n private pinnedMaxMid = 0;\r\n public pinnedMid = 0;\r\n public pinnedIndex = -1;\r\n private wasPinnedIndex = 0;\r\n private wasPinnedMediaIndex = 0;\r\n \r\n public locked = false;\r\n private waitForScrollBottom = false;\r\n\r\n public count = 0;\r\n private mids: number[] = [];\r\n private offsetIndex = 0;\r\n\r\n private loading = false;\r\n private loadedBottom = false;\r\n private loadedTop = false;\r\n\r\n private animatedSubtitle: AnimatedSuper;\r\n private animatedMedia: AnimatedSuper;\r\n private animatedCounter: AnimatedCounter;\r\n\r\n private listenerSetter: ListenerSetter;\r\n private scrollDownListenerSetter: ListenerSetter = null;\r\n\r\n public hidden = false;\r\n\r\n private getCurrentIndexPromise: Promise<any> = null;\r\n private btnOpen: HTMLButtonElement;\r\n \r\n private setPinnedMessage: () => void;\r\n\r\n private isStatic = false;\r\n\r\n private debug = false;\r\n \r\n public setCorrectIndexThrottled: (lastScrollDirection?: number) => void;\r\n \r\n constructor(private topbar: ChatTopbar, private chat: Chat, private appMessagesManager: AppMessagesManager, private appPeersManager: AppPeersManager) {\r\n this.listenerSetter = new ListenerSetter();\r\n\r\n const dAC = new ReplyContainer('pinned-message');\r\n this.pinnedMessageContainer = new PinnedContainer({\r\n topbar, \r\n chat, \r\n listenerSetter: this.listenerSetter, \r\n className: 'message', \r\n divAndCaption: dAC, \r\n onClose: async() => {\r\n if(appPeersManager.canPinMessage(this.topbar.peerId)) {\r\n new PopupPinMessage(this.topbar.peerId, this.pinnedMid, true);\r\n } else {\r\n new PopupPinMessage(this.topbar.peerId, 0, true);\r\n }\r\n\r\n return false;\r\n }\r\n });\r\n\r\n this.pinnedMessageBorder = new PinnedMessageBorder();\r\n dAC.border.replaceWith(this.pinnedMessageBorder.render(1, 0));\r\n\r\n this.animatedSubtitle = new AnimatedSuper();\r\n dAC.subtitle.append(this.animatedSubtitle.container);\r\n\r\n this.animatedMedia = new AnimatedSuper();\r\n this.animatedMedia.container.classList.add('pinned-message-media-container');\r\n dAC.content.prepend(this.animatedMedia.container);\r\n\r\n this.animatedCounter = new AnimatedCounter(true);\r\n dAC.title.append(i18n('PinnedMessage'), ' ', this.animatedCounter.container);\r\n\r\n const btnClose = this.pinnedMessageContainer.btnClose.cloneNode(true) as HTMLElement;\r\n this.pinnedMessageContainer.attachOnCloseEvent(btnClose);\r\n dAC.container.prepend(btnClose);\r\n\r\n this.btnOpen = ButtonIcon('pinlist pinned-container-close pinned-message-pinlist', {noRipple: true});\r\n\r\n this.pinnedMessageContainer.wrapperUtils.prepend(this.btnOpen);\r\n\r\n attachClickEvent(this.btnOpen, (e) => {\r\n cancelEvent(e);\r\n this.topbar.openPinned(true);\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n this.listenerSetter.add(rootScope)('peer_pinned_messages', ({peerId}) => {\r\n if(peerId === this.topbar.peerId) {\r\n //this.wasPinnedIndex = 0;\r\n //setTimeout(() => {\r\n if(this.hidden) {\r\n this.pinnedMessageContainer.toggle(this.hidden = false);\r\n }\r\n\r\n this.loadedTop = this.loadedBottom = false;\r\n this.pinnedIndex = -1;\r\n this.pinnedMid = 0;\r\n this.count = 0;\r\n this.mids = [];\r\n this.offsetIndex = 0;\r\n this.pinnedMaxMid = 0;\r\n this.setCorrectIndex(0);\r\n //}, 300);\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('peer_pinned_hidden', ({peerId}) => {\r\n if(peerId === this.topbar.peerId) {\r\n this.pinnedMessageContainer.toggle(this.hidden = true);\r\n }\r\n });\r\n\r\n // * 200 - no lags\r\n // * 100 - need test\r\n this.setPinnedMessage = debounce(() => this._setPinnedMessage(), 100, true, true);\r\n this.setCorrectIndexThrottled = throttle(this.setCorrectIndex.bind(this), 100, false);\r\n\r\n this.isStatic = this.chat.type === 'discussion';\r\n }\r\n\r\n public destroy() {\r\n this.pinnedMessageContainer.divAndCaption.container.remove();\r\n this.pinnedMessageContainer.toggle(true);\r\n this.listenerSetter.removeAll();\r\n this.unsetScrollDownListener(false);\r\n }\r\n\r\n public setCorrectIndex(lastScrollDirection?: number) {\r\n if(this.isStatic) return;\r\n // return;\r\n\r\n if(this.locked || this.hidden/* || this.chat.setPeerPromise || this.chat.bubbles.messagesQueuePromise */) {\r\n return;\r\n }\r\n\r\n if((this.loadedBottom || this.loadedTop) && !this.count) {\r\n return;\r\n }\r\n\r\n //const perf = performance.now();\r\n let el = this.chat.bubbles.getBubbleByPoint('bottom');\r\n //this.chat.log('[PM]: setCorrectIndex: get last element perf:', performance.now() - perf, el);\r\n if(!el) return;\r\n\r\n //return;\r\n\r\n const mid = el.dataset.mid;\r\n if(el && mid !== undefined) {\r\n //this.chat.log('[PM]: setCorrectIndex will test mid:', mid);\r\n this.testMid(+mid, lastScrollDirection);\r\n }\r\n }\r\n\r\n public testMid(mid: number, lastScrollDirection?: number) {\r\n if(this.isStatic) return;\r\n \r\n //if(lastScrollDirection !== undefined) return;\r\n if(this.hidden) return;\r\n\r\n //this.chat.log('[PM]: testMid', mid);\r\n\r\n let currentIndex: number = this.mids.findIndex(_mid => _mid <= mid);\r\n if(currentIndex !== -1 && !this.isNeededMore(currentIndex)) {\r\n currentIndex += this.offsetIndex;\r\n } else if(this.loadedTop && mid < this.mids[this.mids.length - 1]) {\r\n //currentIndex = 0;\r\n currentIndex = this.mids.length - 1 + this.offsetIndex;\r\n } else {\r\n if(!this.getCurrentIndexPromise) {\r\n this.getCurrentIndexPromise = this.getCurrentIndex(mid, lastScrollDirection !== undefined);\r\n }\r\n\r\n return;\r\n }\r\n\r\n //const idx = Math.max(0, this.mids.indexOf(mid));\r\n\r\n /* if(currentIndex === this.count) {\r\n currentIndex = 0;\r\n } */\r\n\r\n //this.chat.log('[PM]: testMid: pinned currentIndex', currentIndex, mid);\r\n\r\n const changed = this.pinnedIndex !== currentIndex;\r\n if(changed) {\r\n if(this.waitForScrollBottom && lastScrollDirection !== undefined) {\r\n if(this.pinnedIndex === 0 || this.pinnedIndex > currentIndex) { // если не скроллил вниз и пытается поставить нижний пиннед - выйти\r\n return;\r\n }\r\n }\r\n\r\n this.pinnedIndex = currentIndex;\r\n this.pinnedMid = this.mids.find(_mid => _mid <= mid) || this.mids[this.mids.length - 1];\r\n this.setPinnedMessage();\r\n }\r\n }\r\n\r\n private isNeededMore(currentIndex: number) {\r\n return (this.count > ChatPinnedMessage.LOAD_COUNT && \r\n (\r\n (!this.loadedBottom && currentIndex <= ChatPinnedMessage.LOAD_OFFSET) || \r\n (!this.loadedTop && (this.count - 1 - currentIndex) <= ChatPinnedMessage.LOAD_OFFSET)\r\n )\r\n );\r\n }\r\n\r\n private async getCurrentIndex(mid: number, correctAfter = true) {\r\n if(this.loading) return;\r\n this.loading = true;\r\n\r\n try {\r\n let gotRest = false;\r\n const promises = [\r\n this.appMessagesManager.getSearch({\r\n peerId: this.topbar.peerId, \r\n inputFilter: {_: 'inputMessagesFilterPinned'}, \r\n maxId: mid, \r\n limit: ChatPinnedMessage.LOAD_COUNT, \r\n backLimit: ChatPinnedMessage.LOAD_COUNT\r\n })\r\n .then(r => {\r\n gotRest = true;\r\n return r;\r\n })\r\n ];\r\n \r\n if(!this.pinnedMaxMid) {\r\n const promise = this.appMessagesManager.getPinnedMessage(this.topbar.peerId).then(p => {\r\n if(!p.maxId) return;\r\n this.pinnedMaxMid = p.maxId;\r\n\r\n if(!gotRest && correctAfter) {\r\n this.mids = [this.pinnedMaxMid];\r\n this.count = p.count;\r\n this.pinnedIndex = 0;\r\n this.pinnedMid = this.mids[0];\r\n this.setPinnedMessage();\r\n //this.pinnedMessageContainer.toggle(false);\r\n }\r\n });\r\n \r\n promises.push(promise as any);\r\n }\r\n \r\n const result = (await Promise.all(promises))[0];\r\n \r\n let backLimited = result.history.findIndex(message => message.mid <= mid);\r\n if(backLimited === -1) {\r\n backLimited = result.history.length;\r\n }/* else {\r\n backLimited -= 1;\r\n } */\r\n \r\n this.offsetIndex = result.offset_id_offset ? result.offset_id_offset - backLimited : 0;\r\n this.mids = result.history.map(message => message.mid).slice();\r\n this.count = result.count;\r\n\r\n if(!this.count) {\r\n this.pinnedMessageContainer.toggle(true);\r\n }\r\n \r\n this.loadedTop = (this.offsetIndex + this.mids.length) === this.count;\r\n this.loadedBottom = !this.offsetIndex;\r\n \r\n this.debug && this.chat.log('[PM]: getCurrentIndex result:', mid, result, backLimited, this.offsetIndex, this.loadedTop, this.loadedBottom);\r\n } catch(err) {\r\n this.chat.log.error('[PM]: getCurrentIndex error', err);\r\n }\r\n \r\n this.loading = false;\r\n\r\n if(this.locked) {\r\n this.testMid(mid);\r\n } else if(correctAfter) {\r\n this.setCorrectIndex(0);\r\n }\r\n\r\n this.getCurrentIndexPromise = null;\r\n //return result.offset_id_offset || 0;\r\n }\r\n\r\n public setScrollDownListener() {\r\n this.waitForScrollBottom = true;\r\n\r\n if(!this.scrollDownListenerSetter) {\r\n this.scrollDownListenerSetter = new ListenerSetter();\r\n handleScrollSideEvent(this.chat.bubbles.scrollable.container, 'bottom', () => {\r\n this.unsetScrollDownListener();\r\n }, this.scrollDownListenerSetter);\r\n }\r\n }\r\n\r\n public unsetScrollDownListener(refreshPosition = true) {\r\n this.waitForScrollBottom = false;\r\n\r\n if(this.scrollDownListenerSetter) {\r\n this.scrollDownListenerSetter.removeAll();\r\n this.scrollDownListenerSetter = null;\r\n }\r\n\r\n if(refreshPosition) {\r\n this.setCorrectIndex(0);\r\n }\r\n }\r\n\r\n public async handleFollowingPinnedMessage() {\r\n this.locked = true;\r\n\r\n this.debug && this.chat.log('[PM]: handleFollowingPinnedMessage');\r\n try {\r\n this.setScrollDownListener();\r\n\r\n const setPeerPromise = this.chat.setPeerPromise;\r\n if(setPeerPromise instanceof Promise) {\r\n await setPeerPromise;\r\n }\r\n \r\n //await this.chat.bubbles.scrollable.scrollLockedPromise;\r\n await getHeavyAnimationPromise();\r\n\r\n if(this.getCurrentIndexPromise) {\r\n await this.getCurrentIndexPromise;\r\n }\r\n\r\n this.debug && this.chat.log('[PM]: handleFollowingPinnedMessage: unlock');\r\n this.locked = false;\r\n\r\n /* // подождём, пока скролл остановится\r\n setTimeout(() => {\r\n this.chat.log('[PM]: handleFollowingPinnedMessage: unlock');\r\n this.locked = false;\r\n }, 50); */\r\n } catch(err) {\r\n this.chat.log.error('[PM]: handleFollowingPinnedMessage error:', err);\r\n\r\n this.locked = false;\r\n this.waitForScrollBottom = false;\r\n this.setCorrectIndex(0);\r\n }\r\n }\r\n\r\n public async followPinnedMessage(mid: number) {\r\n const message = this.chat.getMessage(mid);\r\n if(message && !message.deleted) {\r\n this.chat.setMessageId(mid);\r\n (this.chat.setPeerPromise || Promise.resolve()).then(() => { // * debounce fast clicker\r\n this.handleFollowingPinnedMessage();\r\n this.testMid(this.pinnedIndex >= (this.count - 1) ? this.pinnedMaxMid : mid - 1);\r\n });\r\n }\r\n }\r\n\r\n public async _setPinnedMessage() {\r\n /////this.log('setting pinned message', message);\r\n //return;\r\n /* const promise: Promise<any> = this.chat.setPeerPromise || this.chat.bubbles.messagesQueuePromise || Promise.resolve();\r\n Promise.all([\r\n promise\r\n ]).then(() => { */\r\n //const mids = results[0];\r\n const count = this.count;\r\n if(count) {\r\n const pinnedIndex = this.pinnedIndex;\r\n const message = this.chat.getMessage(this.pinnedMid);\r\n\r\n //this.animatedCounter.prepareNumber(count);\r\n\r\n //setTimeout(() => {\r\n const isLast = pinnedIndex === 0;\r\n this.animatedCounter.container.classList.toggle('is-last', isLast);\r\n //SetTransition(this.animatedCounter.container, 'is-last', isLast, AnimatedSuper.DURATION);\r\n if(!isLast) {\r\n this.animatedCounter.setCount(count - pinnedIndex);\r\n }\r\n //}, 100);\r\n\r\n //this.pinnedMessageContainer.fill(undefined, message.message, message);\r\n this.pinnedMessageContainer.toggle(false);\r\n\r\n const fromTop = pinnedIndex > this.wasPinnedIndex;\r\n\r\n this.debug && this.chat.log('[PM]: setPinnedMessage: fromTop', fromTop, pinnedIndex, this.wasPinnedIndex);\r\n\r\n const writeTo = this.animatedSubtitle.getRow(pinnedIndex);\r\n const writeMediaTo = this.animatedMedia.getRow(pinnedIndex);\r\n writeMediaTo.classList.add('pinned-message-media');\r\n //writeMediaTo.innerHTML = writeMediaTo.style.cssText = writeMediaTo.dataset.docId = '';\r\n const loadPromises: Promise<any>[] = [];\r\n const isMediaSet = wrapReplyDivAndCaption({\r\n title: undefined,\r\n titleEl: null,\r\n subtitle: message.message,\r\n subtitleEl: writeTo,\r\n message,\r\n mediaEl: writeMediaTo,\r\n loadPromises\r\n });\r\n\r\n await Promise.all(loadPromises);\r\n\r\n this.pinnedMessageContainer.divAndCaption.container.classList.toggle('is-media', isMediaSet);\r\n\r\n //if(this.wasPinnedIndex !== this.pinnedIndex) {\r\n this.animatedSubtitle.animate(pinnedIndex, this.wasPinnedIndex);\r\n if(isMediaSet) {\r\n this.animatedMedia.animate(pinnedIndex, this.wasPinnedMediaIndex); // * wasPinnedMediaIndex из-за того, что блок меняется с другим алгоритмом\r\n this.wasPinnedMediaIndex = pinnedIndex;\r\n } else {\r\n this.animatedMedia.clearRows();\r\n }\r\n //}\r\n\r\n this.pinnedMessageBorder.render(count, count - pinnedIndex - 1);\r\n this.wasPinnedIndex = pinnedIndex;\r\n this.pinnedMessageContainer.divAndCaption.container.dataset.mid = '' + message.mid;\r\n } else {\r\n this.pinnedMessageContainer.toggle(true);\r\n this.wasPinnedIndex = 0;\r\n }\r\n\r\n this.pinnedMessageContainer.divAndCaption.container.classList.toggle('is-many', this.count > 1);\r\n //});\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport type ListenerSetter from \"../listenerSetter\";\r\nimport { IS_TOUCH_SUPPORTED } from \"../../environment/touchSupport\";\r\n\r\nexport default function handleScrollSideEvent(elem: HTMLElement, side: 'top' | 'bottom', callback: () => void, listenerSetter: ListenerSetter) {\r\n if(IS_TOUCH_SUPPORTED) {\r\n let lastY: number;\r\n const options = {passive: true};\r\n listenerSetter.add(elem)('touchstart', (e) => {\r\n if(e.touches.length > 1) {\r\n onTouchEnd();\r\n return;\r\n }\r\n\r\n lastY = e.touches[0].clientY;\r\n\r\n listenerSetter.add(elem)('touchmove', onTouchMove, options);\r\n listenerSetter.add(elem)('touchend', onTouchEnd, options);\r\n }, options);\r\n\r\n const onTouchMove = (e: TouchEvent) => {\r\n const clientY = e.touches[0].clientY;\r\n\r\n const isDown = clientY < lastY;\r\n if(side === 'bottom' && isDown) callback();\r\n else if(side === 'top' && !isDown) callback();\r\n lastY = clientY;\r\n //alert('isDown: ' + !!isDown);\r\n };\r\n \r\n const onTouchEnd = () => {\r\n listenerSetter.removeManual(elem, 'touchmove', onTouchMove, options);\r\n listenerSetter.removeManual(elem, 'touchend', onTouchEnd, options);\r\n };\r\n } else {\r\n listenerSetter.add(elem)('wheel', (e) => {\r\n const isDown = e.deltaY > 0;\r\n //this.log('wheel', e, isDown);\r\n if(side === 'bottom' && isDown) callback();\r\n else if(side === 'top' && !isDown) callback();\r\n }, {passive: true});\r\n }\r\n}\r\n","import IS_WEBRTC_SUPPORTED from \"./webrtcSupport\";\n\nconst IS_GROUP_CALL_SUPPORTED = IS_WEBRTC_SUPPORTED;\n\nexport default IS_GROUP_CALL_SUPPORTED;\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport tsNow from \"../../helpers/tsNow\";\nimport appMessagesManager from \"../../lib/appManagers/appMessagesManager\";\nimport { LangPackKey } from \"../../lib/langPack\";\nimport { MUTE_UNTIL } from \"../../lib/mtproto/mtproto_config\";\nimport RadioField from \"../radioField\";\nimport Row, { RadioFormFromRows } from \"../row\";\nimport { SettingSection } from \"../sidebarLeft\";\nimport PopupPeer from \"./peer\";\n\nexport default class PopupMute extends PopupPeer {\n constructor(peerId: PeerId) {\n super('popup-mute', {\n peerId,\n titleLangKey: 'Notifications',\n buttons: [{\n langKey: 'ChatList.Context.Mute',\n callback: () => {\n appMessagesManager.mutePeer(peerId, time === -1 ? MUTE_UNTIL : tsNow(true) + time);\n }\n }],\n body: true\n });\n\n const ONE_HOUR = 3600;\n const times: {time: number, langKey: LangPackKey}[] = [{\n time: ONE_HOUR, \n langKey: 'ChatList.Mute.1Hour'\n }, {\n time: ONE_HOUR * 4, \n langKey: 'ChatList.Mute.4Hours'\n }, {\n time: ONE_HOUR * 8, \n langKey: 'ChatList.Mute.8Hours'\n }, {\n time: ONE_HOUR * 24, \n langKey: 'ChatList.Mute.1Day'\n }, {\n time: ONE_HOUR * 24 * 3,\n langKey: 'ChatList.Mute.3Days'\n }, {\n time: -1,\n langKey: 'ChatList.Mute.Forever'\n }];\n \n const name = 'mute-time';\n const rows = times.map((time) => {\n const row = new Row({\n radioField: new RadioField({\n langKey: time.langKey, \n name, \n value: '' + time.time\n })\n });\n\n return row;\n });\n\n let time: number;\n const radioForm = RadioFormFromRows(rows, (value) => {\n time = +value;\n });\n\n rows[rows.length - 1].radioField.checked = true;\n\n const section = new SettingSection({noShadow: true, noDelimiter: true});\n section.content.append(radioForm);\n this.body.append(section.container);\n\n this.show();\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport type { AppNotificationsManager } from \"../../lib/appManagers/appNotificationsManager\";\nimport type { AppChatsManager, Channel } from \"../../lib/appManagers/appChatsManager\";\nimport type { AppMessagesManager } from \"../../lib/appManagers/appMessagesManager\";\nimport type { AppPeersManager } from \"../../lib/appManagers/appPeersManager\";\nimport type { AppSidebarRight } from \"../sidebarRight\";\nimport type { AppProfileManager } from \"../../lib/appManagers/appProfileManager\";\nimport type { AppUsersManager } from \"../../lib/appManagers/appUsersManager\";\nimport type { AppGroupCallsManager, MyGroupCall } from \"../../lib/appManagers/appGroupCallsManager\";\nimport type Chat from \"./chat\";\nimport { RIGHT_COLUMN_ACTIVE_CLASSNAME } from \"../sidebarRight\";\nimport mediaSizes, { ScreenSize } from \"../../helpers/mediaSizes\";\nimport { IS_SAFARI } from \"../../environment/userAgent\";\nimport rootScope from \"../../lib/rootScope\";\nimport AvatarElement from \"../avatar\";\nimport Button from \"../button\";\nimport ButtonIcon from \"../buttonIcon\";\nimport ButtonMenuToggle from \"../buttonMenuToggle\";\nimport ChatAudio from \"./audio\";\nimport ChatPinnedMessage from \"./pinnedMessage\";\nimport { ButtonMenuItemOptions } from \"../buttonMenu\";\nimport ListenerSetter from \"../../helpers/listenerSetter\";\nimport appStateManager from \"../../lib/appManagers/appStateManager\";\nimport PopupDeleteDialog from \"../popups/deleteDialog\";\nimport appNavigationController from \"../appNavigationController\";\nimport { LEFT_COLUMN_ACTIVE_CLASSNAME } from \"../sidebarLeft\";\nimport PeerTitle from \"../peerTitle\";\nimport { i18n } from \"../../lib/langPack\";\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\nimport blurActiveElement from \"../../helpers/dom/blurActiveElement\";\nimport cancelEvent from \"../../helpers/dom/cancelEvent\";\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\nimport findUpTag from \"../../helpers/dom/findUpTag\";\nimport { toast, toastNew } from \"../toast\";\nimport replaceContent from \"../../helpers/dom/replaceContent\";\nimport { ChatFull, Chat as MTChat, GroupCall } from \"../../layer\";\nimport PopupPickUser from \"../popups/pickUser\";\nimport PopupPeer from \"../popups/peer\";\nimport { fastRaf } from \"../../helpers/schedulers\";\nimport AppEditContactTab from \"../sidebarRight/tabs/editContact\";\nimport appMediaPlaybackController from \"../appMediaPlaybackController\";\nimport IS_GROUP_CALL_SUPPORTED from \"../../environment/groupCallSupport\";\nimport IS_CALL_SUPPORTED from \"../../environment/callSupport\";\nimport { CallType } from \"../../lib/calls/types\";\nimport PopupMute from \"../popups/mute\";\nimport generateTitleIcons from \"../generateTitleIcons\";\n\ntype ButtonToVerify = {element?: HTMLElement, verify: () => boolean};\n\nexport default class ChatTopbar {\n public container: HTMLDivElement;\n private btnBack: HTMLButtonElement;\n private chatInfo: HTMLDivElement;\n private avatarElement: AvatarElement;\n private title: HTMLDivElement;\n private subtitle: HTMLDivElement;\n private chatUtils: HTMLDivElement;\n private btnJoin: HTMLButtonElement;\n private btnPinned: HTMLButtonElement;\n private btnCall: HTMLButtonElement;\n private btnGroupCall: HTMLButtonElement;\n private btnMute: HTMLButtonElement;\n private btnSearch: HTMLButtonElement;\n private btnMore: HTMLElement;\n \n private chatAudio: ChatAudio;\n public pinnedMessage: ChatPinnedMessage;\n\n private setUtilsRAF: number;\n public peerId: PeerId;\n private wasPeerId: PeerId;\n private setPeerStatusInterval: number;\n\n public listenerSetter: ListenerSetter;\n\n private menuButtons: (ButtonMenuItemOptions & {verify: () => boolean})[];\n private buttonsToVerify: ButtonToVerify[];\n private chatInfoContainer: HTMLDivElement;\n\n constructor(\n private chat: Chat, \n private appSidebarRight: AppSidebarRight, \n private appMessagesManager: AppMessagesManager, \n private appPeersManager: AppPeersManager, \n private appChatsManager: AppChatsManager, \n private appNotificationsManager: AppNotificationsManager,\n private appProfileManager: AppProfileManager,\n private appUsersManager: AppUsersManager,\n private appGroupCallsManager: AppGroupCallsManager\n ) {\n this.listenerSetter = new ListenerSetter();\n\n this.menuButtons = [];\n this.buttonsToVerify = [];\n }\n\n public construct() {\n //this.chat.log.error('Topbar construction');\n\n this.container = document.createElement('div');\n this.container.classList.add('sidebar-header', 'topbar');\n this.container.dataset.floating = '0';\n\n this.btnBack = ButtonIcon('left sidebar-close-button', {noRipple: true});\n\n // * chat info section\n this.chatInfoContainer = document.createElement('div');\n this.chatInfoContainer.classList.add('chat-info-container');\n\n this.chatInfo = document.createElement('div');\n this.chatInfo.classList.add('chat-info');\n\n const person = document.createElement('div');\n person.classList.add('person');\n\n const content = document.createElement('div');\n content.classList.add('content');\n\n const top = document.createElement('div');\n top.classList.add('top');\n\n this.title = document.createElement('div');\n this.title.classList.add('user-title');\n\n top.append(this.title);\n\n const bottom = document.createElement('div');\n bottom.classList.add('bottom');\n\n if(this.subtitle) {\n bottom.append(this.subtitle);\n }\n\n content.append(top, bottom);\n if(this.avatarElement) {\n person.append(this.avatarElement);\n }\n\n person.append(content);\n this.chatInfo.append(person);\n\n // * chat utils section\n this.chatUtils = document.createElement('div');\n this.chatUtils.classList.add('chat-utils');\n\n this.chatAudio = new ChatAudio(this, this.chat, this.appMessagesManager);\n\n if(this.menuButtons.length) {\n this.btnMore = ButtonMenuToggle({listenerSetter: this.listenerSetter}, 'bottom-left', this.menuButtons, this.verifyButtons);\n }\n\n this.chatUtils.append(...[\n // this.chatAudio ? this.chatAudio.divAndCaption.container : null, \n this.pinnedMessage ? this.pinnedMessage.pinnedMessageContainer.divAndCaption.container : null, \n this.btnJoin, \n this.btnPinned, \n this.btnCall, \n this.btnGroupCall, \n this.btnMute, \n this.btnSearch, \n this.btnMore\n ].filter(Boolean));\n\n this.pushButtonToVerify(this.btnCall, this.verifyCallButton.bind(this, 'voice'));\n this.pushButtonToVerify(this.btnGroupCall, this.verifyVideoChatButton);\n\n this.chatInfoContainer.append(this.btnBack, this.chatInfo, this.chatUtils);\n this.container.append(this.chatInfoContainer);\n\n if(this.chatAudio) {\n // this.container.append(this.chatAudio.divAndCaption.container, this.chatUtils);\n this.container.append(this.chatAudio.divAndCaption.container);\n }\n\n // * construction end\n\n // * fix topbar overflow section\n\n this.listenerSetter.add(window)('resize', this.onResize);\n this.listenerSetter.add(mediaSizes)('changeScreen', this.onChangeScreen);\n\n attachClickEvent(this.container, (e) => {\n const container = findUpClassName(e.target, 'pinned-container');\n blurActiveElement();\n if(container) {\n cancelEvent(e);\n\n if(findUpClassName(e.target, 'progress-line')) {\n return;\n }\n \n const mid = +container.dataset.mid;\n if(container.classList.contains('pinned-message')) {\n //if(!this.pinnedMessage.locked) {\n this.pinnedMessage.followPinnedMessage(mid);\n //}\n } else {\n const peerId = container.dataset.peerId.toPeerId();\n const searchContext = appMediaPlaybackController.getSearchContext();\n this.chat.appImManager.setInnerPeer({\n peerId, \n lastMsgId: mid, \n type: searchContext.isScheduled ? 'scheduled' : (searchContext.threadId ? 'discussion' : undefined), \n threadId: searchContext.threadId\n });\n }\n } else {\n if(mediaSizes.activeScreen === ScreenSize.medium && document.body.classList.contains(LEFT_COLUMN_ACTIVE_CLASSNAME)) {\n onBtnBackClick();\n } else if(findUpTag(e.target, 'AVATAR-ELEMENT')) {\n this.appSidebarRight.toggleSidebar(!document.body.classList.contains(RIGHT_COLUMN_ACTIVE_CLASSNAME));\n } else {\n this.appSidebarRight.toggleSidebar(true);\n }\n }\n }, {listenerSetter: this.listenerSetter});\n\n const onBtnBackClick = (e?: Event) => {\n if(e) {\n cancelEvent(e);\n }\n\n //const item = appNavigationController.findItemByType('chat');\n // * return manually to chat by arrow, since can't get back to\n if(mediaSizes.activeScreen === ScreenSize.medium && document.body.classList.contains(LEFT_COLUMN_ACTIVE_CLASSNAME)) {\n this.chat.appImManager.setPeer({peerId: this.peerId});\n } else {\n const isFirstChat = this.chat.appImManager.chats.indexOf(this.chat) === 0;\n appNavigationController.back(isFirstChat ? 'im' : 'chat');\n /* return;\n\n if(mediaSizes.activeScreen === ScreenSize.medium && !appNavigationController.findItemByType('chat')) {\n this.chat.appImManager.setPeer(0);\n blurActiveElement();\n } else {\n appNavigationController.back('chat');\n } */\n }\n };\n\n attachClickEvent(this.btnBack, onBtnBackClick, {listenerSetter: this.listenerSetter});\n }\n\n private pushButtonToVerify(element: HTMLElement, verify: () => boolean) {\n if(!element) {\n return;\n }\n \n this.buttonsToVerify.push({element, verify});\n }\n\n private verifyButtons = (e?: Event) => {\n const isMenuOpen = !!e || !!(this.btnMore && this.btnMore.classList.contains('menu-open'));\n\n e && cancelEvent(e);\n\n const verifyButtons = (buttons: ButtonToVerify[]) => {\n buttons.forEach(button => {\n button.element.classList.toggle('hide', !button.verify());\n });\n };\n\n if(isMenuOpen) {\n verifyButtons(this.menuButtons);\n\n // delete button\n this.menuButtons[this.menuButtons.length - 1].element.lastChild.replaceWith(i18n(this.appPeersManager.getDeleteButtonText(this.peerId)));\n }\n\n verifyButtons(this.buttonsToVerify);\n };\n\n private verifyVideoChatButton = (type?: 'group' | 'broadcast') => {\n if(!IS_GROUP_CALL_SUPPORTED || this.peerId.isUser()) return false;\n\n const currentGroupCall = this.appGroupCallsManager.groupCall;\n const chatId = this.peerId.toChatId();\n if(currentGroupCall?.chatId === chatId) {\n return false;\n }\n\n if(type) {\n if((this.peerId.isBroadcast() && type === 'group') || \n (this.peerId.isAnyGroup() && type === 'broadcast')) {\n return false;\n }\n }\n\n const chat = this.appChatsManager.getChatTyped(chatId);\n return (chat as MTChat.chat).pFlags?.call_active || this.appChatsManager.hasRights(chatId, 'manage_call');\n };\n\n private verifyCallButton = (type?: CallType) => {\n if(!IS_CALL_SUPPORTED || !this.peerId.isUser()) return false;\n const userId = this.peerId.toUserId();\n const userFull = this.appProfileManager.getCachedFullUser(userId);\n\n return !!userFull && !!(type === 'voice' ? userFull.pFlags.phone_calls_available : userFull.pFlags.video_calls_available);\n };\n\n public constructUtils() {\n this.menuButtons = [{\n icon: 'search',\n text: 'Search',\n onClick: () => {\n this.chat.initSearch();\n },\n verify: () => mediaSizes.isMobile\n }, /* {\n icon: 'pinlist',\n text: 'Pinned Messages',\n onClick: () => this.openPinned(false),\n verify: () => mediaSizes.isMobile\n }, */{\n icon: 'mute',\n text: 'ChatList.Context.Mute',\n onClick: this.onMuteClick,\n verify: () => this.chat.type === 'chat' && rootScope.myId !== this.peerId && !this.appNotificationsManager.isPeerLocalMuted(this.peerId, false)\n }, {\n icon: 'unmute',\n text: 'ChatList.Context.Unmute',\n onClick: () => {\n this.appMessagesManager.togglePeerMute(this.peerId);\n },\n verify: () => this.chat.type === 'chat' && rootScope.myId !== this.peerId && this.appNotificationsManager.isPeerLocalMuted(this.peerId, false)\n }, {\n icon: 'comments',\n text: 'ViewDiscussion',\n onClick: () => {\n const middleware = this.chat.bubbles.getMiddleware();\n Promise.resolve(this.appProfileManager.getChannelFull(this.peerId.toChatId())).then(channelFull => {\n if(middleware() && channelFull.linked_chat_id) {\n this.chat.appImManager.setInnerPeer({\n peerId: channelFull.linked_chat_id.toPeerId(true)\n });\n }\n });\n },\n verify: () => {\n const chatFull = this.appProfileManager.getCachedFullChat(this.peerId.toChatId());\n return this.chat.type === 'chat' && !!(chatFull as ChatFull.channelFull)?.linked_chat_id;\n }\n }, {\n icon: 'phone',\n text: 'Call',\n onClick: this.onCallClick.bind(this, 'voice'),\n verify: this.verifyCallButton.bind(this, 'voice')\n }, {\n icon: 'videocamera',\n text: 'VideoCall',\n onClick: this.onCallClick.bind(this, 'video'),\n verify: this.verifyCallButton.bind(this, 'video')\n }, {\n icon: 'videochat',\n text: 'PeerInfo.Action.LiveStream',\n onClick: this.onJoinGroupCallClick,\n verify: this.verifyVideoChatButton.bind(this, 'broadcast')\n }, {\n icon: 'videochat',\n text: 'PeerInfo.Action.VoiceChat',\n onClick: this.onJoinGroupCallClick,\n verify: this.verifyVideoChatButton.bind(this, 'group')\n }, {\n icon: 'select',\n text: 'Chat.Menu.SelectMessages',\n onClick: () => {\n const selection = this.chat.selection;\n selection.toggleSelection(true, true);\n appStateManager.getState().then(state => {\n if(state.chatContextMenuHintWasShown) {\n return;\n }\n\n const original = selection.toggleByElement.bind(selection);\n selection.toggleByElement = (bubble) => {\n appStateManager.pushToState('chatContextMenuHintWasShown', true);\n toast(i18n('Chat.Menu.Hint'));\n\n selection.toggleByElement = original;\n selection.toggleByElement(bubble);\n };\n });\n },\n verify: () => !this.chat.selection.isSelecting && !!this.chat.bubbles.getRenderedLength()\n }, {\n icon: 'select',\n text: 'Chat.Menu.ClearSelection',\n onClick: () => {\n this.chat.selection.cancelSelection();\n },\n verify: () => this.chat.selection.isSelecting\n }, {\n icon: 'adduser',\n text: 'AddContact',\n onClick: () => {\n if(!this.appSidebarRight.isTabExists(AppEditContactTab)) {\n const tab = new AppEditContactTab(this.appSidebarRight);\n tab.peerId = this.peerId;\n tab.open();\n\n this.appSidebarRight.toggleSidebar(true);\n }\n },\n verify: () => this.peerId.isUser() && !this.appPeersManager.isContact(this.peerId)\n }, {\n icon: 'forward',\n text: 'ShareContact',\n onClick: () => {\n const contactPeerId = this.peerId;\n new PopupPickUser({\n peerTypes: ['dialogs', 'contacts'],\n onSelect: (peerId) => {\n return new Promise((resolve, reject) => {\n new PopupPeer('', {\n titleLangKey: 'SendMessageTitle',\n descriptionLangKey: 'SendContactToGroupText',\n descriptionLangArgs: [new PeerTitle({peerId, dialog: true}).element],\n buttons: [{\n langKey: 'Send',\n callback: () => {\n resolve();\n\n this.appMessagesManager.sendContact(peerId, contactPeerId);\n this.chat.appImManager.setInnerPeer({peerId});\n }\n }, {\n langKey: 'Cancel',\n callback: () => {\n reject();\n },\n isCancel: true,\n }],\n peerId,\n overlayClosable: true\n }).show();\n });\n },\n placeholder: 'ShareModal.Search.Placeholder',\n chatRightsAction: 'send_messages',\n selfPresence: 'ChatYourSelf'\n });\n },\n verify: () => rootScope.myId !== this.peerId && this.peerId.isUser() && this.appPeersManager.isContact(this.peerId) && !!this.appUsersManager.getUser(this.peerId.toUserId()).phone\n }, {\n icon: 'lock',\n text: 'BlockUser',\n onClick: () => {\n new PopupPeer('', {\n peerId: this.peerId,\n titleLangKey: 'BlockUser',\n descriptionLangKey: 'AreYouSureBlockContact2',\n descriptionLangArgs: [new PeerTitle({peerId: this.peerId}).element],\n buttons: [{\n langKey: 'BlockUser',\n isDanger: true,\n callback: () => {\n this.appUsersManager.toggleBlock(this.peerId, true).then(value => {\n if(value) {\n toastNew({langPackKey: 'UserBlocked'});\n }\n });\n }\n }]\n }).show();\n },\n verify: () => {\n if(!this.peerId.isUser()) return false;\n const userFull = this.appProfileManager.getCachedFullUser(this.peerId.toUserId());\n return this.peerId !== rootScope.myId && userFull && !userFull.pFlags?.blocked;\n }\n }, {\n icon: 'lockoff',\n text: 'Unblock',\n onClick: () => {\n this.appUsersManager.toggleBlock(this.peerId, false).then(value => {\n if(value) {\n toastNew({langPackKey: 'UserUnblocked'});\n }\n });\n },\n verify: () => {\n const userFull = this.appProfileManager.getCachedFullUser(this.peerId.toUserId());\n return !!userFull?.pFlags?.blocked;\n }\n }, {\n icon: 'delete danger',\n text: 'Delete',\n onClick: () => {\n new PopupDeleteDialog(this.peerId/* , 'leave' */);\n },\n verify: () => this.chat.type === 'chat' && !!this.appMessagesManager.getDialogOnly(this.peerId)\n }];\n\n this.btnSearch = ButtonIcon('search');\n this.attachClickEvent(this.btnSearch, (e) => {\n this.chat.initSearch();\n }, true);\n }\n\n public attachClickEvent(el: HTMLElement, cb: (e: MouseEvent) => void, noBlur?: boolean) {\n attachClickEvent(el, (e) => {\n cancelEvent(e);\n !noBlur && blurActiveElement();\n cb(e);\n }, {listenerSetter: this.listenerSetter});\n }\n\n private onCallClick(type: CallType) {\n this.chat.appImManager.callUser(this.peerId.toUserId(), type);\n }\n\n private onJoinGroupCallClick = () => {\n this.chat.appImManager.joinGroupCall(this.peerId);\n };\n\n public constructPeerHelpers() {\n this.avatarElement = new AvatarElement();\n this.avatarElement.isDialog = true;\n this.avatarElement.classList.add('avatar-42', 'person-avatar');\n\n this.subtitle = document.createElement('div');\n this.subtitle.classList.add('info');\n\n this.pinnedMessage = new ChatPinnedMessage(this, this.chat, this.appMessagesManager, this.appPeersManager);\n\n this.btnJoin = Button('btn-primary btn-color-primary chat-join hide');\n this.btnCall = ButtonIcon('phone');\n this.btnGroupCall = ButtonIcon('videochat');\n this.btnPinned = ButtonIcon('pinlist');\n this.btnMute = ButtonIcon('mute');\n\n this.attachClickEvent(this.btnCall, this.onCallClick.bind(this, 'voice'));\n this.attachClickEvent(this.btnGroupCall, this.onJoinGroupCallClick);\n\n this.attachClickEvent(this.btnPinned, () => {\n this.openPinned(true);\n });\n\n this.attachClickEvent(this.btnMute, this.onMuteClick);\n\n this.attachClickEvent(this.btnJoin, () => {\n const middleware = this.chat.bubbles.getMiddleware();\n this.btnJoin.setAttribute('disabled', 'true');\n\n const chatId = this.peerId.toChatId();\n let promise: Promise<any>;\n if(this.appChatsManager.isChannel(chatId)) {\n promise = this.appChatsManager.joinChannel(chatId);\n } else {\n promise = this.appChatsManager.addChatUser(chatId, rootScope.myId);\n }\n\n promise.finally(() => {\n if(!middleware()) {\n return;\n }\n\n this.btnJoin.removeAttribute('disabled');\n });\n });\n\n this.listenerSetter.add(rootScope)('chat_update', (chatId) => {\n if(this.peerId === chatId.toPeerId(true)) {\n const chat = this.appChatsManager.getChat(chatId) as Channel/* | Chat */;\n \n this.btnJoin.classList.toggle('hide', !(chat as Channel)?.pFlags?.left);\n this.setUtilsWidth();\n this.verifyButtons();\n }\n });\n\n this.listenerSetter.add(rootScope)('dialog_notify_settings', (dialog) => {\n if(dialog.peerId === this.peerId) {\n this.setMutedState();\n }\n });\n\n this.listenerSetter.add(rootScope)('peer_typings', ({peerId}) => {\n if(this.peerId === peerId) {\n this.setPeerStatus();\n }\n });\n\n this.listenerSetter.add(rootScope)('user_update', (userId) => {\n if(this.peerId === userId.toPeerId()) {\n this.setPeerStatus();\n }\n });\n\n this.listenerSetter.add(rootScope)('peer_full_update', (peerId) => {\n if(this.peerId === peerId) {\n this.verifyButtons();\n }\n });\n\n if(this.pinnedMessage) {\n this.chat.addEventListener('setPeer', (mid, isTopMessage) => {\n const middleware = this.chat.bubbles.getMiddleware();\n appStateManager.getState().then((state) => {\n if(!middleware()) return;\n \n this.pinnedMessage.hidden = !!state.hiddenPinnedMessages[this.chat.peerId];\n \n if(isTopMessage) {\n this.pinnedMessage.unsetScrollDownListener();\n this.pinnedMessage.testMid(mid, 0); // * because slider will not let get bubble by document.elementFromPoint\n } else if(!this.pinnedMessage.locked) {\n this.pinnedMessage.handleFollowingPinnedMessage();\n this.pinnedMessage.testMid(mid);\n }\n });\n });\n }\n\n this.setPeerStatusInterval = window.setInterval(this.setPeerStatus, 60e3);\n\n return this;\n }\n\n public constructPinnedHelpers() {\n this.listenerSetter.add(rootScope)('peer_pinned_messages', ({peerId, mids}) => {\n if(peerId !== this.peerId) return;\n\n if(mids) {\n this.setTitle();\n }\n });\n }\n \n public constructDiscussionHelpers() {\n this.pinnedMessage = new ChatPinnedMessage(this, this.chat, this.appMessagesManager, this.appPeersManager);\n }\n\n public openPinned(byCurrent: boolean) {\n this.chat.appImManager.setInnerPeer({\n peerId: this.peerId, \n lastMsgId: byCurrent ? +this.pinnedMessage.pinnedMessageContainer.divAndCaption.container.dataset.mid : 0, \n type: 'pinned'\n });\n }\n\n private onMuteClick = () => {\n new PopupMute(this.peerId);\n };\n\n private onResize = () => {\n this.setUtilsWidth(true);\n this.setFloating();\n };\n\n private onChangeScreen = (from: ScreenSize, to: ScreenSize) => {\n this.container.classList.toggle('is-pinned-floating', mediaSizes.isMobile);\n // this.chatAudio && this.chatAudio.divAndCaption.container.classList.toggle('is-floating', to === ScreenSize.mobile);\n this.pinnedMessage && this.pinnedMessage.pinnedMessageContainer.divAndCaption.container.classList.toggle('is-floating', to === ScreenSize.mobile);\n this.onResize();\n };\n\n public destroy() {\n //this.chat.log.error('Topbar destroying');\n this.listenerSetter.removeAll();\n window.clearInterval(this.setPeerStatusInterval);\n \n if(this.pinnedMessage) {\n this.pinnedMessage.destroy(); // * возможно это можно не делать\n }\n\n if(this.chatAudio) {\n this.chatAudio.destroy();\n }\n\n delete this.chatAudio;\n delete this.pinnedMessage;\n }\n\n public setPeer(peerId: PeerId) {\n this.wasPeerId = this.peerId;\n this.peerId = peerId;\n\n this.container.style.display = peerId ? '' : 'none';\n }\n\n public finishPeerChange(isTarget: boolean, isJump: boolean, lastMsgId: number) {\n const peerId = this.peerId;\n\n if(this.avatarElement) {\n this.avatarElement.updateWithOptions({peerId});\n }\n\n const isBroadcast = this.appPeersManager.isBroadcast(peerId);\n this.btnMute && this.btnMute.classList.toggle('hide', !isBroadcast);\n if(this.btnJoin) {\n if(this.appPeersManager.isAnyChat(peerId)) {\n const chatId = peerId.toChatId();\n replaceContent(this.btnJoin, i18n(this.appChatsManager.isBroadcast(chatId) ? 'Chat.Subscribe' : 'ChannelJoin'));\n this.btnJoin.classList.toggle('hide', !this.appChatsManager.getChat(chatId)?.pFlags?.left);\n } else {\n this.btnJoin.classList.add('hide');\n }\n }\n\n this.setUtilsWidth();\n\n this.verifyButtons();\n\n const middleware = this.chat.bubbles.getMiddleware();\n if(this.pinnedMessage) { // * replace with new one\n if(this.chat.type === 'chat') {\n if(this.wasPeerId !== undefined) { // * change\n const newPinnedMessage = new ChatPinnedMessage(this, this.chat, this.appMessagesManager, this.appPeersManager);\n this.pinnedMessage.pinnedMessageContainer.divAndCaption.container.replaceWith(newPinnedMessage.pinnedMessageContainer.divAndCaption.container);\n this.pinnedMessage.destroy();\n //this.pinnedMessage.pinnedMessageContainer.toggle(true);\n this.pinnedMessage = newPinnedMessage;\n }\n \n appStateManager.getState().then((state) => {\n if(!middleware()) return;\n \n this.pinnedMessage.hidden = !!state.hiddenPinnedMessages[peerId];\n \n if(!isTarget) {\n this.pinnedMessage.setCorrectIndex(0);\n }\n });\n } else if(this.chat.type === 'discussion') {\n this.pinnedMessage.pinnedMid = this.chat.threadId;\n this.pinnedMessage.count = 1;\n this.pinnedMessage.pinnedIndex = 0;\n this.pinnedMessage._setPinnedMessage();\n }\n }\n\n fastRaf(() => {\n this.setTitle();\n this.setPeerStatus(true);\n this.setMutedState();\n });\n }\n\n public setTitle(count?: number) {\n let titleEl: HTMLElement;\n if(this.chat.type === 'pinned') {\n if(count === undefined) titleEl = i18n('Loading');\n else titleEl = i18n('PinnedMessagesCount', [count]);\n\n if(count === undefined) {\n this.appMessagesManager.getSearchCounters(this.peerId, [{_: 'inputMessagesFilterPinned'}], false).then(result => {\n const count = result[0].count;\n this.setTitle(count);\n\n // ! костыль х2, это нужно делать в другом месте\n if(!count) {\n this.chat.appImManager.setPeer(); // * close tab\n\n // ! костыль, это скроет закреплённые сообщения сразу, вместо того, чтобы ждать пока анимация перехода закончится\n const originalChat = this.chat.appImManager.chat;\n if(originalChat.topbar.pinnedMessage) {\n originalChat.topbar.pinnedMessage.pinnedMessageContainer.toggle(true);\n }\n }\n });\n }\n } else if(this.chat.type === 'scheduled') {\n if(this.peerId === rootScope.myId) {\n //title = [count > 1 ? count : false, 'Reminders'].filter(Boolean).join(' ');\n titleEl = i18n('Reminders');\n } else {\n titleEl = i18n('ScheduledMessages');\n //title = [count > 1 ? count : false, 'Scheduled Messages'].filter(Boolean).join(' ');\n }\n \n if(count === undefined) {\n this.appMessagesManager.getScheduledMessages(this.peerId).then(mids => {\n this.setTitle(mids.length);\n });\n }\n } else if(this.chat.type === 'discussion') {\n if(count === undefined) titleEl = i18n('Loading');\n else titleEl = i18n('Chat.Title.Comments', [count]);\n\n if(count === undefined) {\n Promise.all([\n this.appMessagesManager.getHistory(this.peerId, 0, 1, 0, this.chat.threadId),\n Promise.resolve()\n ]).then(() => {\n const count = this.appMessagesManager.getHistoryStorage(this.peerId, this.chat.threadId).count;\n if(count === null) {\n setTimeout(() => {\n this.setTitle();\n }, 30);\n } else {\n this.setTitle(count);\n }\n });\n }\n } else if(this.chat.type === 'chat') {\n titleEl = new PeerTitle({\n peerId: this.peerId,\n dialog: true,\n }).element;\n }\n \n replaceContent(this.title, titleEl);\n\n if(this.chat.type === 'chat') {\n this.title.append(...generateTitleIcons(this.peerId));\n }\n }\n\n public setMutedState() {\n if(!this.btnMute) return;\n\n const peerId = this.peerId;\n let muted = this.appNotificationsManager.isPeerLocalMuted(peerId, false);\n if(this.appPeersManager.isBroadcast(peerId)) { // not human\n this.btnMute.classList.remove('tgico-mute', 'tgico-unmute');\n this.btnMute.classList.add(muted ? 'tgico-unmute' : 'tgico-mute');\n this.btnMute.style.display = '';\n } else {\n this.btnMute.style.display = 'none';\n }\n }\n\n // ! У МЕНЯ ПРОСТО СГОРЕЛО, САФАРИ КОНЧЕННЫЙ БРАУЗЕР - ЕСЛИ НЕ СКРЫВАТЬ БЛОК, ТО ПРИ ПЕРЕВОРОТЕ ЭКРАНА НА АЙФОНЕ БЛОК БУДЕТ НЕПРАВИЛЬНО ШИРИНЫ, ДАЖЕ БЕЗ ЭТОЙ ФУНКЦИИ!\n public setUtilsWidth = (resize = false) => {\n //return;\n if(this.setUtilsRAF) window.cancelAnimationFrame(this.setUtilsRAF);\n\n if(IS_SAFARI && resize) {\n this.chatUtils.classList.add('hide');\n }\n\n //mutationObserver.disconnect();\n this.setUtilsRAF = window.requestAnimationFrame(() => {\n \n //mutationRAF = window.requestAnimationFrame(() => {\n \n //setTimeout(() => {\n if(IS_SAFARI && resize) {\n this.chatUtils.classList.remove('hide');\n }\n /* this.chatInfo.style.removeProperty('--utils-width');\n void this.chatInfo.offsetLeft; // reflow */\n const width = /* chatUtils.scrollWidth */this.chatUtils.getBoundingClientRect().width;\n this.chat.log('utils width:', width);\n this.container.style.setProperty('--utils-width', width + 'px');\n //this.chatInfo.classList.toggle('have-utils-width', !!width);\n //}, 0);\n \n this.setUtilsRAF = 0;\n\n //mutationObserver.observe(chatUtils, observeOptions);\n //});\n });\n };\n\n public setFloating = () => {\n const containers = [this.chatAudio, this.pinnedMessage && this.pinnedMessage.pinnedMessageContainer].filter(Boolean);\n const count = containers.reduce((acc, container) => {\n const isFloating = container.isFloating();\n this.container.classList.toggle(`is-pinned-${container.className}-floating`, isFloating);\n\n if(!container.isVisible()) {\n return acc;\n }\n\n return acc + +isFloating;\n }, 0);\n this.container.dataset.floating = '' + count;\n };\n\n public setPeerStatus = (needClear = false) => {\n if(!this.subtitle) return;\n\n const peerId = this.peerId;\n this.chat.appImManager.setPeerStatus(this.peerId, this.subtitle, needClear, false, () => peerId === this.peerId);\n };\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport appSidebarRight from \"..\";\r\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\r\nimport AppSearch, { SearchGroup } from \"../../appSearch\";\r\nimport ButtonIcon from \"../../buttonIcon\";\r\nimport InputSearch from \"../../inputSearch\";\r\nimport PopupDatePicker from \"../../popups/datePicker\";\r\nimport { SliderSuperTab } from \"../../slider\";\r\n\r\nexport default class AppPrivateSearchTab extends SliderSuperTab {\r\n private inputSearch: InputSearch;\r\n private appSearch: AppSearch;\r\n private btnPickDate: HTMLElement;\r\n\r\n private peerId: PeerId;\r\n private threadId = 0;\r\n private query = '';\r\n private onDatePick: (timestamp: number) => void;\r\n\r\n onOpenAfterTimeout() {\r\n this.appSearch.beginSearch(this.peerId, this.threadId, this.query);\r\n }\r\n\r\n protected init() {\r\n this.container.id = 'search-private-container';\r\n this.container.classList.add('chatlist-container');\r\n this.inputSearch = new InputSearch('Search');\r\n this.title.replaceWith(this.inputSearch.container);\r\n\r\n this.btnPickDate = ButtonIcon('calendar sidebar-header-right');\r\n this.header.append(this.btnPickDate);\r\n\r\n const c = document.createElement('div');\r\n c.classList.add('chatlist-container');\r\n this.scrollable.container.replaceWith(c);\r\n this.appSearch = new AppSearch(c, this.inputSearch, {\r\n messages: new SearchGroup('Chat.Search.PrivateSearch', 'messages')\r\n });\r\n }\r\n\r\n open(peerId: PeerId, threadId?: number, onDatePick?: AppPrivateSearchTab['onDatePick'], query?: string) {\r\n const ret = super.open();\r\n\r\n if(!this.peerId) {\r\n this.query = query;\r\n this.peerId = peerId;\r\n this.threadId = threadId;\r\n this.onDatePick = onDatePick;\r\n \r\n this.btnPickDate.classList.toggle('hide', !this.onDatePick);\r\n if(this.onDatePick) {\r\n attachClickEvent(this.btnPickDate, () => {\r\n new PopupDatePicker(new Date(), this.onDatePick).show();\r\n });\r\n }\r\n\r\n query && this.appSearch.searchInput.inputField.setValueSilently(query);\r\n \r\n appSidebarRight.toggleSidebar(true);\r\n } else {\r\n this.appSearch.beginSearch(this.peerId, this.threadId, query);\r\n }\r\n\r\n return ret;\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport type ChatTopbar from \"./topbar\";\r\nimport AppSearch, { SearchGroup } from \"../appSearch\";\r\nimport PopupDatePicker from \"../popups/datePicker\";\r\nimport ripple from \"../ripple\";\r\nimport InputSearch from \"../inputSearch\";\r\nimport type Chat from \"./chat\";\r\nimport findUpTag from \"../../helpers/dom/findUpTag\";\r\nimport cancelEvent from \"../../helpers/dom/cancelEvent\";\r\nimport whichChild from \"../../helpers/dom/whichChild\";\r\nimport replaceContent from \"../../helpers/dom/replaceContent\";\r\nimport { i18n } from \"../../lib/langPack\";\r\nimport ListenerSetter from \"../../helpers/listenerSetter\";\r\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\r\nimport appNavigationController, { NavigationItem } from \"../appNavigationController\";\r\nimport { IS_MOBILE_SAFARI } from \"../../environment/userAgent\";\r\n\r\nexport default class ChatSearch {\r\n private element: HTMLElement;\r\n private backBtn: HTMLElement;\r\n private inputSearch: InputSearch;\r\n\r\n private results: HTMLElement;\r\n\r\n private footer: HTMLElement;\r\n private dateBtn: HTMLElement;\r\n private foundCountEl: HTMLElement;\r\n private controls: HTMLElement;\r\n private downBtn: HTMLElement;\r\n private upBtn: HTMLElement;\r\n\r\n private appSearch: AppSearch;\r\n private searchGroup: SearchGroup;\r\n\r\n private foundCount = 0;\r\n private selectedIndex = 0;\r\n private setPeerPromise: Promise<any>;\r\n private listenerSetter: ListenerSetter;\r\n private navigationItem: NavigationItem;\r\n\r\n constructor(private topbar: ChatTopbar, private chat: Chat, query?: string) {\r\n this.element = document.createElement('div');\r\n this.element.classList.add('sidebar-header', 'chat-search', 'chatlist-container');\r\n\r\n this.backBtn = document.createElement('button');\r\n this.backBtn.classList.add('btn-icon', 'tgico-left', 'sidebar-close-button');\r\n ripple(this.backBtn);\r\n\r\n const listenerSetter = this.listenerSetter = new ListenerSetter();\r\n\r\n const attachClick = (element: HTMLElement, callback: (e: MouseEvent) => void) => {\r\n attachClickEvent(element, callback, {listenerSetter});\r\n };\r\n \r\n attachClick(this.backBtn, () => {\r\n this.destroy();\r\n });\r\n\r\n this.inputSearch = new InputSearch('Search');\r\n \r\n // Results\r\n this.results = document.createElement('div');\r\n this.results.classList.add('chat-search-results', 'chatlist-container');\r\n\r\n this.searchGroup = new SearchGroup(false, 'messages', undefined, '', false);\r\n attachClick(this.searchGroup.list, this.onResultsClick);\r\n\r\n this.appSearch = new AppSearch(this.results, this.inputSearch, {\r\n messages: this.searchGroup\r\n }, (count) => {\r\n this.foundCount = count;\r\n\r\n if(!this.foundCount) {\r\n replaceContent(this.foundCountEl, this.inputSearch.value ? i18n('NoResult') : '');\r\n this.results.classList.remove('active');\r\n this.chat.bubbles.bubblesContainer.classList.remove('search-results-active');\r\n this.upBtn.setAttribute('disabled', 'true');\r\n this.downBtn.setAttribute('disabled', 'true');\r\n } else {\r\n this.selectResult(this.searchGroup.list.children[0] as HTMLElement);\r\n }\r\n });\r\n this.appSearch.beginSearch(this.chat.peerId, this.chat.threadId);\r\n\r\n //appImManager.topbar.parentElement.insertBefore(this.results, appImManager.bubblesContainer);\r\n this.chat.bubbles.bubblesContainer.append(this.results);\r\n\r\n // Footer\r\n this.footer = document.createElement('div');\r\n this.footer.classList.add('chat-search-footer');\r\n\r\n attachClick(this.footer, this.onFooterClick);\r\n ripple(this.footer);\r\n\r\n this.foundCountEl = document.createElement('span');\r\n this.foundCountEl.classList.add('chat-search-count');\r\n\r\n this.dateBtn = document.createElement('button');\r\n this.dateBtn.classList.add('btn-icon', 'tgico-calendar');\r\n\r\n this.controls = document.createElement('div');\r\n this.controls.classList.add('chat-search-controls');\r\n\r\n this.upBtn = document.createElement('button');\r\n this.upBtn.classList.add('btn-icon', 'tgico-up');\r\n this.downBtn = document.createElement('button');\r\n this.downBtn.classList.add('btn-icon', 'tgico-down');\r\n\r\n this.upBtn.setAttribute('disabled', 'true');\r\n this.downBtn.setAttribute('disabled', 'true');\r\n\r\n attachClick(this.dateBtn, this.onDateClick);\r\n attachClick(this.upBtn, this.onUpClick);\r\n attachClick(this.downBtn, this.onDownClick);\r\n this.controls.append(this.upBtn, this.downBtn);\r\n\r\n this.footer.append(this.foundCountEl, this.dateBtn, this.controls);\r\n \r\n this.topbar.container.parentElement.insertBefore(this.footer, chat.input.chatInput);\r\n\r\n // Append container\r\n this.element.append(this.backBtn, this.inputSearch.container);\r\n\r\n this.topbar.container.classList.add('hide-pinned');\r\n this.topbar.container.parentElement.append(this.element);\r\n\r\n this.inputSearch.input.focus();\r\n\r\n if(query) {\r\n this.setQuery(query);\r\n }\r\n\r\n if(!IS_MOBILE_SAFARI) {\r\n this.navigationItem = {\r\n type: 'mobile-search',\r\n onPop: () => {\r\n this.destroy();\r\n }\r\n };\r\n \r\n appNavigationController.pushItem(this.navigationItem);\r\n }\r\n }\r\n\r\n public destroy() {\r\n this.topbar.container.classList.remove('hide-pinned');\r\n this.element.remove();\r\n this.inputSearch.remove();\r\n this.results.remove();\r\n this.footer.remove();\r\n this.listenerSetter.removeAll();\r\n this.chat.bubbles.bubblesContainer.classList.remove('search-results-active');\r\n this.chat.search = undefined;\r\n appNavigationController.removeItem(this.navigationItem);\r\n }\r\n\r\n public setQuery(query: string) {\r\n this.inputSearch.inputField.value = query;\r\n }\r\n\r\n private onDateClick = (e: MouseEvent) => {\r\n cancelEvent(e);\r\n new PopupDatePicker(new Date(), this.chat.bubbles.onDatePick).show();\r\n };\r\n\r\n private selectResult(elem: HTMLElement) {\r\n if(this.setPeerPromise) return this.setPeerPromise;\r\n\r\n const peerId = elem.dataset.peerId.toPeerId();\r\n const lastMsgId = +elem.dataset.mid || undefined;\r\n\r\n const index = whichChild(elem);\r\n\r\n if(index === (this.foundCount - 1)) {\r\n this.upBtn.setAttribute('disabled', 'true');\r\n } else {\r\n this.upBtn.removeAttribute('disabled');\r\n }\r\n\r\n if(!index) {\r\n this.downBtn.setAttribute('disabled', 'true');\r\n } else {\r\n this.downBtn.removeAttribute('disabled');\r\n }\r\n\r\n this.results.classList.remove('active');\r\n this.chat.bubbles.bubblesContainer.classList.remove('search-results-active');\r\n\r\n const res = this.chat.setPeer(peerId, lastMsgId);\r\n this.setPeerPromise = ((res instanceof Promise ? res : Promise.resolve(res)) as Promise<any>).then(() => {\r\n this.selectedIndex = index;\r\n replaceContent(this.foundCountEl, i18n('Of', [index + 1, this.foundCount]));\r\n\r\n const renderedCount = this.searchGroup.list.childElementCount;\r\n if(this.selectedIndex >= (renderedCount - 6)) {\r\n this.appSearch.searchMore();\r\n }\r\n }).finally(() => {\r\n this.setPeerPromise = null;\r\n });\r\n }\r\n\r\n private onResultsClick = (e: MouseEvent) => {\r\n const target = findUpTag(e.target, 'LI');\r\n if(target) {\r\n this.selectResult(target);\r\n }\r\n };\r\n\r\n private onFooterClick = (e: MouseEvent) => {\r\n if(this.foundCount) {\r\n this.chat.bubbles.bubblesContainer.classList.toggle('search-results-active');\r\n this.results.classList.toggle('active');\r\n }\r\n };\r\n\r\n private onUpClick = (e: MouseEvent) => {\r\n cancelEvent(e);\r\n this.selectResult(this.searchGroup.list.children[this.selectedIndex + 1] as HTMLElement);\r\n };\r\n\r\n private onDownClick = (e: MouseEvent) => {\r\n cancelEvent(e);\r\n this.selectResult(this.searchGroup.list.children[this.selectedIndex - 1] as HTMLElement);\r\n };\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport indexOfAndSplice from \"../../helpers/array/indexOfAndSplice\";\nimport deepEqual from \"../../helpers/object/deepEqual\";\nimport { renderImageFromUrlPromise } from \"../../helpers/dom/renderImageFromUrl\";\nimport mediaSizes, { ScreenSize } from \"../../helpers/mediaSizes\";\n\ntype ChatBackgroundPatternRendererInitOptions = {\n url: string,\n width: number,\n height: number,\n mask?: boolean\n};\n\nexport default class ChatBackgroundPatternRenderer {\n private static INSTANCES: ChatBackgroundPatternRenderer[] = [];\n\n // private pattern: CanvasPattern;\n private objectUrl: string;\n private options: ChatBackgroundPatternRendererInitOptions;\n private canvases: Set<HTMLCanvasElement>;\n // private createCanvasPatternPromise: Promise<CanvasPattern>;\n // private exportCanvasPatternToImagePromise: Promise<string>;\n private renderImageFromUrlPromise: Promise<HTMLImageElement>;\n private img: HTMLImageElement;\n\n constructor() {\n this.canvases = new Set();\n }\n\n public static getInstance(options: ChatBackgroundPatternRendererInitOptions) {\n let instance = this.INSTANCES.find((instance) => {\n return deepEqual(instance.options, options);\n });\n\n if(!instance) {\n instance = new ChatBackgroundPatternRenderer();\n instance.init(options);\n this.INSTANCES.push(instance);\n }\n\n return instance;\n }\n\n public init(options: ChatBackgroundPatternRendererInitOptions) {\n // if(this.options) {\n // if(this.options.width !== options.width || this.options.height !== options.height) {\n // this.createCanvasPatternPromise = \n // this.pattern = \n // this.exportCanvasPatternToImagePromise = \n // undefined;\n // }\n // }\n\n this.options = options;\n }\n\n public renderToCanvas(canvas: HTMLCanvasElement) {\n // return this.createCanvasPattern(canvas).then(() => {\n // return this.fillCanvas(canvas);\n // });\n\n return this.renderImageFromUrl(this.options.url).then(() => {\n return this.fillCanvas(canvas);\n });\n }\n\n private renderImageFromUrl(url: string) {\n if(this.renderImageFromUrlPromise) return this.renderImageFromUrlPromise;\n const img = this.img = document.createElement('img');\n img.crossOrigin = 'anonymous';\n return this.renderImageFromUrlPromise = renderImageFromUrlPromise(img, url, false).then(() => img);\n }\n\n /* private createCanvasPattern(canvas: HTMLCanvasElement) {\n if(this.createCanvasPatternPromise) return this.createCanvasPatternPromise;\n return this.createCanvasPatternPromise = this.renderImageFromUrl(this.options.url).then((img) => {\n let createPatternFrom: HTMLImageElement | HTMLCanvasElement;\n if(IS_SAFARI) {\n const canvas = createPatternFrom = document.createElement('canvas');\n canvas.width = img.naturalWidth;\n canvas.height = img.naturalHeight;\n const ctx = canvas.getContext('2d');\n ctx.drawImage(img, 0, 0, canvas.width, canvas.height);\n } else {\n createPatternFrom = img;\n }\n \n const perf = performance.now();\n this.pattern = canvas.getContext('2d').createPattern(createPatternFrom, 'repeat-x');\n console.warn('creating pattern time:', performance.now() - perf);\n\n return this.pattern;\n });\n }\n\n public exportCanvasPatternToImage(canvas: HTMLCanvasElement) {\n if(this.exportCanvasPatternToImagePromise) return this.exportCanvasPatternToImagePromise;\n return this.exportCanvasPatternToImagePromise = new Promise<string>((resolve) => {\n canvas.toBlob((blob) => {\n const newUrl = this.objectUrl = URL.createObjectURL(blob);\n resolve(newUrl);\n }, 'image/png');\n });\n } */\n\n public cleanup(canvas: HTMLCanvasElement) {\n this.canvases.delete(canvas);\n\n if(!this.canvases.size) {\n indexOfAndSplice(ChatBackgroundPatternRenderer.INSTANCES, this);\n\n if(this.objectUrl) {\n URL.revokeObjectURL(this.objectUrl);\n }\n }\n }\n\n public fillCanvas(canvas: HTMLCanvasElement) {\n const context = canvas.getContext('2d');\n if(context.fillStyle instanceof CanvasPattern) {\n context.clearRect(0, 0, canvas.width, canvas.height);\n }\n\n // const perf = performance.now();\n const img = this.img;\n\n let imageWidth = img.width, imageHeight = img.height;\n // if(imageHeight < canvas.height) {\n const ratio = canvas.height / imageHeight;\n imageWidth *= ratio;\n imageHeight = canvas.height;\n // }\n\n if(this.options.mask) {\n context.fillStyle = '#000';\n context.fillRect(0, 0, canvas.width, canvas.height);\n context.globalCompositeOperation = 'destination-out';\n } else {\n context.globalCompositeOperation = 'source-over';\n }\n\n for(let x = 0; x < canvas.width; x += imageWidth) {\n for(let y = 0; y < canvas.height; y += imageHeight) {\n context.drawImage(img, x, y, imageWidth, imageHeight);\n }\n }\n // context.fillStyle = this.pattern;\n // context.fillRect(0, 0, canvas.width, canvas.height);\n // console.warn('fill canvas time', performance.now() - perf);\n }\n\n public setCanvasDimensions(canvas: HTMLCanvasElement) {\n const devicePixelRatio = Math.min(2, window.devicePixelRatio);\n canvas.width = this.options.width * devicePixelRatio;\n canvas.height = this.options.height * devicePixelRatio * (mediaSizes.activeScreen === ScreenSize.large ? 1.5 : 1);\n }\n\n public createCanvas() {\n const canvas = document.createElement('canvas');\n this.canvases.add(canvas);\n this.setCanvasDimensions(canvas);\n return canvas;\n }\n\n public resize(width: number, height: number) {\n this.init({\n ...this.options,\n width,\n height\n });\n\n const promises: Promise<any>[] = [];\n for(const canvas of this.canvases) {\n this.setCanvasDimensions(canvas);\n promises.push(this.renderToCanvas(canvas));\n }\n\n return Promise.all(promises);\n }\n\n public static resizeInstances(width: number, height: number) {\n return Promise.all(this.INSTANCES.map(instance => instance.resize(width, height)));\n }\n\n /* public setResizeMode(resizing: boolean) {\n const canvases = Array.from(this.canvases);\n const canvas = canvases[canvases.length - 1];\n canvas.style.display = resizing ? 'none' : '';\n const img = this.img;\n img.style.display = resizing ? '' : 'none';\n\n return {img, canvas};\n } */\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport type { AppNotificationsManager } from \"../../lib/appManagers/appNotificationsManager\";\nimport type { AppChatsManager, ChatRights } from \"../../lib/appManagers/appChatsManager\";\nimport type { AppDocsManager } from \"../../lib/appManagers/appDocsManager\";\nimport type { AppImManager } from \"../../lib/appManagers/appImManager\";\nimport type { AppInlineBotsManager } from \"../../lib/appManagers/appInlineBotsManager\";\nimport type { AppMessagesManager } from \"../../lib/appManagers/appMessagesManager\";\nimport type { AppPeersManager } from \"../../lib/appManagers/appPeersManager\";\nimport type { AppPhotosManager } from \"../../lib/appManagers/appPhotosManager\";\nimport type { AppPollsManager } from \"../../lib/appManagers/appPollsManager\";\nimport type { AppProfileManager } from \"../../lib/appManagers/appProfileManager\";\nimport type { AppStickersManager } from \"../../lib/appManagers/appStickersManager\";\nimport type { AppUsersManager } from \"../../lib/appManagers/appUsersManager\";\nimport type { AppWebPagesManager } from \"../../lib/appManagers/appWebPagesManager\";\nimport type { ApiManagerProxy } from \"../../lib/mtproto/mtprotoworker\";\nimport type { AppDraftsManager } from \"../../lib/appManagers/appDraftsManager\";\nimport type { AppEmojiManager } from \"../../lib/appManagers/appEmojiManager\";\nimport type { ServerTimeManager } from \"../../lib/mtproto/serverTimeManager\";\nimport type { AppMessagesIdsManager } from \"../../lib/appManagers/appMessagesIdsManager\";\nimport type { AppGroupCallsManager } from \"../../lib/appManagers/appGroupCallsManager\";\nimport type { AppReactionsManager } from \"../../lib/appManagers/appReactionsManager\";\nimport type stateStorage from '../../lib/stateStorage';\nimport EventListenerBase from \"../../helpers/eventListenerBase\";\nimport { logger, LogTypes } from \"../../lib/logger\";\nimport rootScope from \"../../lib/rootScope\";\nimport appSidebarRight from \"../sidebarRight\";\nimport ChatBubbles from \"./bubbles\";\nimport ChatContextMenu from \"./contextMenu\";\nimport ChatInput from \"./input\";\nimport ChatSelection from \"./selection\";\nimport ChatTopbar from \"./topbar\";\nimport { BOT_START_PARAM, NULL_PEER_ID, REPLIES_PEER_ID } from \"../../lib/mtproto/mtproto_config\";\nimport SetTransition from \"../singleTransition\";\nimport AppPrivateSearchTab from \"../sidebarRight/tabs/search\";\nimport renderImageFromUrl, { renderImageFromUrlPromise } from \"../../helpers/dom/renderImageFromUrl\";\nimport mediaSizes from \"../../helpers/mediaSizes\";\nimport ChatSearch from \"./search\";\nimport { IS_TOUCH_SUPPORTED } from \"../../environment/touchSupport\";\nimport getAutoDownloadSettingsByPeerId, { ChatAutoDownloadSettings } from \"../../helpers/autoDownload\";\nimport ChatBackgroundGradientRenderer from \"./gradientRenderer\";\nimport ChatBackgroundPatternRenderer from \"./patternRenderer\";\nimport pause from \"../../helpers/schedulers/pause\";\n\nexport type ChatType = 'chat' | 'pinned' | 'replies' | 'discussion' | 'scheduled';\n\nexport default class Chat extends EventListenerBase<{\n setPeer: (mid: number, isTopMessage: boolean) => void\n}> {\n public container: HTMLElement;\n public backgroundEl: HTMLElement;\n\n public topbar: ChatTopbar;\n public bubbles: ChatBubbles;\n public input: ChatInput;\n public selection: ChatSelection;\n public contextMenu: ChatContextMenu;\n public search: ChatSearch;\n\n public wasAlreadyUsed: boolean;\n // public initPeerId = 0;\n public peerId: PeerId;\n public threadId: number;\n public setPeerPromise: Promise<void>;\n public peerChanged: boolean;\n\n public log: ReturnType<typeof logger>;\n\n public type: ChatType;\n\n public noForwards: boolean;\n\n public inited: boolean;\n\n public isRestricted: boolean;\n public autoDownload: ChatAutoDownloadSettings;\n\n public gradientRenderer: ChatBackgroundGradientRenderer;\n public patternRenderer: ChatBackgroundPatternRenderer;\n public gradientCanvas: HTMLCanvasElement;\n public patternCanvas: HTMLCanvasElement;\n public backgroundTempId: number;\n public setBackgroundPromise: Promise<void>;\n // public renderDarkPattern: () => Promise<void>;\n \n constructor(\n public appImManager: AppImManager, \n public appChatsManager: AppChatsManager, \n public appDocsManager: AppDocsManager, \n public appInlineBotsManager: AppInlineBotsManager, \n public appMessagesManager: AppMessagesManager, \n public appPeersManager: AppPeersManager, \n public appPhotosManager: AppPhotosManager, \n public appProfileManager: AppProfileManager, \n public appStickersManager: AppStickersManager, \n public appUsersManager: AppUsersManager, \n public appWebPagesManager: AppWebPagesManager, \n public appPollsManager: AppPollsManager, \n public apiManager: ApiManagerProxy, \n public appDraftsManager: AppDraftsManager, \n public serverTimeManager: ServerTimeManager, \n public storage: typeof stateStorage, \n public appNotificationsManager: AppNotificationsManager,\n public appEmojiManager: AppEmojiManager,\n public appMessagesIdsManager: AppMessagesIdsManager,\n public appGroupCallsManager: AppGroupCallsManager,\n public appReactionsManager: AppReactionsManager\n ) {\n super();\n\n this.type = 'chat';\n\n this.container = document.createElement('div');\n this.container.classList.add('chat', 'tabs-tab');\n\n this.backgroundEl = document.createElement('div');\n this.backgroundEl.classList.add('chat-background');\n\n // * constructor end\n\n this.log = logger('CHAT', LogTypes.Log | LogTypes.Warn | LogTypes.Debug | LogTypes.Error);\n //this.log.error('Chat construction');\n\n this.peerId = NULL_PEER_ID;\n\n this.container.append(this.backgroundEl);\n this.appImManager.chatsContainer.append(this.container);\n\n this.backgroundTempId = 0;\n }\n\n public setBackground(url: string, skipAnimation?: boolean): Promise<void> {\n const theme = rootScope.getTheme();\n\n let item: HTMLElement;\n const isColorBackground = !!theme.background.color && !theme.background.slug && !theme.background.intensity;\n if(\n isColorBackground && \n document.documentElement.style.cursor === 'grabbing' && \n this.gradientRenderer && \n !this.patternRenderer\n ) {\n this.gradientCanvas.dataset.colors = theme.background.color;\n this.gradientRenderer.init(this.gradientCanvas);\n return Promise.resolve();\n }\n\n const tempId = ++this.backgroundTempId;\n\n const previousGradientRenderer = this.gradientRenderer;\n const previousPatternRenderer = this.patternRenderer;\n const previousGradientCanvas = this.gradientCanvas;\n const previousPatternCanvas = this.patternCanvas;\n\n this.gradientRenderer = \n this.patternRenderer = \n this.gradientCanvas = \n this.patternCanvas = \n // this.renderDarkPattern = \n undefined;\n\n const intensity = theme.background.intensity && theme.background.intensity / 100;\n const isDarkPattern = !!intensity && intensity < 0;\n \n let patternRenderer: ChatBackgroundPatternRenderer;\n let patternCanvas = item?.firstElementChild as HTMLCanvasElement;\n let gradientCanvas: HTMLCanvasElement;\n if(!item) {\n item = document.createElement('div');\n item.classList.add('chat-background-item');\n\n if(url) {\n if(intensity) {\n item.classList.add('is-pattern');\n\n const rect = this.appImManager.chatsContainer.getBoundingClientRect();\n patternRenderer = this.patternRenderer = ChatBackgroundPatternRenderer.getInstance({\n url,\n width: rect.width,\n height: rect.height,\n mask: isDarkPattern\n });\n\n patternCanvas = this.patternCanvas = patternRenderer.createCanvas();\n patternCanvas.classList.add('chat-background-item-canvas', 'chat-background-item-pattern-canvas');\n\n if(isDarkPattern) {\n item.classList.add('is-dark');\n }\n\n // if(isDarkPattern) {\n // this.renderDarkPattern = () => {\n // return patternRenderer.exportCanvasPatternToImage(patternCanvas).then(url => {\n // if(this.backgroundTempId !== tempId) {\n // return;\n // }\n \n // gradientCanvas.style.webkitMaskImage = `url(${url})`;\n // });\n // };\n // }\n } else if(theme.background.slug) {\n item.classList.add('is-image');\n }\n } else if(theme.background.color) {\n item.classList.add('is-color');\n }\n }\n\n let gradientRenderer: ChatBackgroundGradientRenderer;\n const color = theme.background.color;\n if(color) {\n // if(color.includes(',')) {\n const {canvas, gradientRenderer: _gradientRenderer} = ChatBackgroundGradientRenderer.create(color);\n gradientRenderer = this.gradientRenderer = _gradientRenderer;\n gradientCanvas = this.gradientCanvas = canvas;\n gradientCanvas.classList.add('chat-background-item-canvas', 'chat-background-item-color-canvas');\n\n if(rootScope.settings.animationsEnabled) {\n gradientRenderer.scrollAnimate(true);\n }\n // } else {\n // item.style.backgroundColor = color;\n // item.style.backgroundImage = 'none';\n // }\n }\n\n if(patternRenderer) {\n const setOpacityTo = isDarkPattern ? gradientCanvas : patternCanvas;\n setOpacityTo.style.setProperty('--opacity-max', '' + Math.abs(intensity));\n }\n\n const promise = new Promise<void>((resolve) => {\n const cb = () => {\n if(this.backgroundTempId !== tempId) {\n if(patternRenderer) {\n patternRenderer.cleanup(patternCanvas);\n }\n\n if(gradientRenderer) {\n gradientRenderer.cleanup();\n }\n\n return;\n }\n\n const prev = this.backgroundEl.lastElementChild as HTMLElement;\n\n if(prev === item) {\n resolve();\n return;\n }\n\n const append = [\n gradientCanvas, \n // isDarkPattern && this.renderDarkPattern ? undefined : patternCanvas\n patternCanvas\n ].filter(Boolean);\n if(append.length) {\n item.append(...append);\n }\n\n this.backgroundEl.append(item);\n\n SetTransition(item, 'is-visible', true, !skipAnimation ? 200 : 0, prev ? () => {\n if(previousPatternRenderer) {\n previousPatternRenderer.cleanup(previousPatternCanvas);\n }\n\n if(previousGradientRenderer) {\n previousGradientRenderer.cleanup();\n }\n\n prev.remove();\n } : null, 2);\n\n resolve();\n };\n\n if(patternRenderer) {\n const renderPatternPromise = patternRenderer.renderToCanvas(patternCanvas);\n renderPatternPromise.then(() => {\n if(this.backgroundTempId !== tempId) {\n return;\n }\n\n let promise: Promise<any>;\n // if(isDarkPattern && this.renderDarkPattern) {\n // promise = this.renderDarkPattern();\n // } else {\n promise = Promise.resolve();\n // }\n \n promise.then(cb);\n });\n } else if(url) {\n renderImageFromUrl(item, url, cb);\n } else {\n cb();\n }\n });\n\n return this.setBackgroundPromise = Promise.race([\n pause(500),\n promise\n ]);\n }\n\n public setType(type: ChatType) {\n this.type = type;\n\n if(this.type === 'scheduled') {\n this.getMessagesStorage = () => this.appMessagesManager.getScheduledMessagesStorage(this.peerId);\n //this.getMessage = (mid) => this.appMessagesManager.getMessageFromStorage(this.appMessagesManager.getScheduledMessagesStorage(this.peerId), mid);\n }\n }\n\n public init(/* peerId: PeerId */) {\n // this.initPeerId = peerId;\n\n this.topbar = new ChatTopbar(this, appSidebarRight, this.appMessagesManager, this.appPeersManager, this.appChatsManager, this.appNotificationsManager, this.appProfileManager, this.appUsersManager, this.appGroupCallsManager);\n this.bubbles = new ChatBubbles(this, this.appMessagesManager, this.appStickersManager, this.appUsersManager, this.appInlineBotsManager, this.appPhotosManager, this.appPeersManager, this.appProfileManager, this.appDraftsManager, this.appMessagesIdsManager, this.appChatsManager, this.appReactionsManager, this.appWebPagesManager);\n this.input = new ChatInput(this, this.appMessagesManager, this.appMessagesIdsManager, this.appDocsManager, this.appChatsManager, this.appPeersManager, this.appWebPagesManager, this.appImManager, this.appDraftsManager, this.serverTimeManager, this.appNotificationsManager, this.appEmojiManager, this.appUsersManager, this.appInlineBotsManager, this.appProfileManager);\n this.selection = new ChatSelection(this, this.bubbles, this.input, this.appMessagesManager);\n this.contextMenu = new ChatContextMenu(this.bubbles.bubblesContainer, this, this.appMessagesManager, this.appPeersManager, this.appPollsManager, this.appDocsManager, this.appMessagesIdsManager, this.appReactionsManager);\n\n if(this.type === 'chat') {\n this.topbar.constructUtils();\n this.topbar.constructPeerHelpers();\n } else if(this.type === 'pinned') {\n this.topbar.constructPinnedHelpers();\n } else if(this.type === 'discussion') {\n this.topbar.constructUtils();\n this.topbar.constructDiscussionHelpers();\n }\n\n this.topbar.construct();\n this.input.construct();\n\n if(this.type === 'chat') { // * гений в деле, разный порядок из-за разной последовательности действий\n this.bubbles.constructPeerHelpers();\n this.input.constructPeerHelpers();\n } else if(this.type === 'pinned') {\n this.bubbles.constructPinnedHelpers();\n this.input.constructPinnedHelpers();\n } else if(this.type === 'scheduled') {\n this.bubbles.constructScheduledHelpers();\n this.input.constructPeerHelpers();\n } else if(this.type === 'discussion') {\n this.bubbles.constructPeerHelpers();\n this.input.constructPeerHelpers();\n }\n\n if(this.type !== 'scheduled' && !IS_TOUCH_SUPPORTED) {\n this.bubbles.setReactionsHoverListeners();\n }\n\n this.container.classList.add('type-' + this.type);\n this.container.append(this.topbar.container, this.bubbles.bubblesContainer, this.input.chatInput);\n\n this.bubbles.listenerSetter.add(rootScope)('dialog_migrate', ({migrateFrom, migrateTo}) => {\n if(this.peerId === migrateFrom) {\n this.setPeer(migrateTo);\n }\n });\n\n this.bubbles.listenerSetter.add(rootScope)('dialog_drop', (e) => {\n if(e.peerId === this.peerId) {\n this.appImManager.setPeer();\n }\n });\n }\n\n public beforeDestroy() {\n this.bubbles.cleanup();\n }\n\n private cleanupBackground() {\n ++this.backgroundTempId;\n if(this.patternRenderer) {\n this.patternRenderer.cleanup(this.patternCanvas);\n this.patternRenderer = undefined;\n }\n\n if(this.gradientRenderer) {\n this.gradientRenderer.cleanup();\n this.gradientRenderer = undefined;\n }\n }\n\n public destroy() {\n //const perf = performance.now();\n\n this.topbar.destroy();\n this.bubbles.destroy();\n this.input.destroy();\n this.contextMenu && this.contextMenu.destroy();\n\n this.cleanupBackground();\n\n delete this.topbar;\n delete this.bubbles;\n delete this.input;\n delete this.selection;\n delete this.contextMenu;\n\n this.container.remove();\n\n //this.log.error('Chat destroy time:', performance.now() - perf);\n }\n\n public cleanup(helperToo = true) {\n this.input.cleanup(helperToo);\n this.selection.cleanup();\n }\n\n public setPeer(peerId: PeerId, lastMsgId?: number, startParam?: string) {\n if(!peerId) {\n this.inited = undefined;\n } else if(!this.inited) {\n if(this.init) {\n this.init(/* peerId */);\n this.init = null;\n }\n\n this.inited = true;\n }\n\n const samePeer = this.peerId === peerId;\n if(!samePeer) {\n rootScope.dispatchEvent('peer_changing', this);\n this.peerId = peerId || NULL_PEER_ID;\n } else if(this.setPeerPromise) {\n return;\n }\n\n //console.time('appImManager setPeer');\n //console.time('appImManager setPeer pre promise');\n ////console.time('appImManager: pre render start');\n if(!peerId) {\n appSidebarRight.toggleSidebar(false);\n this.cleanup(true);\n this.topbar.setPeer(peerId);\n this.bubbles.setPeer(peerId);\n rootScope.dispatchEvent('peer_changed', peerId);\n\n return;\n }\n\n // set new\n if(!samePeer) {\n const searchTab = appSidebarRight.getTab(AppPrivateSearchTab);\n if(searchTab) {\n searchTab.close();\n }\n\n this.noForwards = this.appPeersManager.noForwards(peerId);\n this.isRestricted = this.appPeersManager.isRestricted(peerId);\n this.container.classList.toggle('no-forwards', this.noForwards);\n\n appSidebarRight.sharedMediaTab.setPeer(peerId, this.threadId);\n this.input.clearHelper(); // костыль\n this.selection.cleanup(); // TODO: REFACTOR !!!!!!\n this.setAutoDownloadMedia();\n }\n\n this.peerChanged = samePeer;\n\n if(startParam === undefined && this.isStartButtonNeeded()) {\n startParam = BOT_START_PARAM;\n }\n\n const result = this.bubbles.setPeer(peerId, lastMsgId, startParam);\n if(!result) {\n return;\n }\n\n const {promise} = result;\n\n //console.timeEnd('appImManager setPeer pre promise');\n \n const setPeerPromise = this.setPeerPromise = promise.finally(() => {\n if(this.setPeerPromise === setPeerPromise) {\n this.setPeerPromise = null;\n }\n });\n\n if(!samePeer) {\n appSidebarRight.sharedMediaTab.setLoadMutex(this.setPeerPromise);\n appSidebarRight.sharedMediaTab.loadSidebarMedia(true);\n }\n /* this.setPeerPromise.then(() => {\n appSidebarRight.sharedMediaTab.loadSidebarMedia(false);\n }); */\n\n return result;\n }\n\n public setAutoDownloadMedia() {\n this.autoDownload = getAutoDownloadSettingsByPeerId(this.peerId);\n }\n\n public setMessageId(messageId?: number) {\n return this.setPeer(this.peerId, messageId);\n }\n\n public finishPeerChange(isTarget: boolean, isJump: boolean, lastMsgId: number, startParam?: string) {\n if(this.peerChanged) return;\n\n let peerId = this.peerId;\n this.peerChanged = true;\n\n this.cleanup(false);\n\n this.topbar.setPeer(peerId);\n this.topbar.finishPeerChange(isTarget, isJump, lastMsgId);\n this.bubbles.finishPeerChange();\n this.input.finishPeerChange(startParam);\n\n appSidebarRight.sharedMediaTab.fillProfileElements();\n\n this.log.setPrefix('CHAT-' + peerId + '-' + this.type);\n\n rootScope.dispatchEvent('peer_changed', peerId);\n this.wasAlreadyUsed = true;\n }\n\n public getMessagesStorage() {\n return this.appMessagesManager.getMessagesStorage(this.peerId);\n }\n\n public getMessage(mid: number) {\n return this.appMessagesManager.getMessageFromStorage(this.getMessagesStorage(), mid);\n //return this.appMessagesManager.getMessageByPeer(this.peerId, mid);\n }\n\n public getMidsByMid(mid: number) {\n return this.appMessagesManager.getMidsByMessage(this.getMessage(mid));\n }\n\n public isAnyGroup() {\n return this.peerId === rootScope.myId || this.peerId === REPLIES_PEER_ID || this.appPeersManager.isAnyGroup(this.peerId);\n }\n\n public initSearch(query?: string) {\n if(!this.peerId) return;\n\n if(mediaSizes.isMobile) {\n if(!this.search) {\n this.search = new ChatSearch(this.topbar, this, query);\n } else {\n this.search.setQuery(query);\n }\n } else {\n let tab = appSidebarRight.getTab(AppPrivateSearchTab);\n if(!tab) {\n tab = new AppPrivateSearchTab(appSidebarRight);\n }\n\n tab.open(this.peerId, this.threadId, this.bubbles.onDatePick, query);\n }\n }\n\n public canSend(action?: ChatRights) {\n return this.appMessagesManager.canSendToPeer(this.peerId, this.threadId, action);\n }\n\n public isStartButtonNeeded() {\n return this.appPeersManager.isBot(this.peerId) && \n !this.appMessagesManager.getDialogOnly(this.peerId) && \n !this.appMessagesManager.getHistoryStorage(this.peerId).history.length;\n }\n\n public getMessageSendingParams() {\n return {\n threadId: this.threadId,\n replyToMsgId: this.input.replyToMsgId,\n scheduleDate: this.input.scheduleDate,\n sendSilent: this.input.sendSilent,\n sendAsPeerId: this.input.sendAsPeerId\n };\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { State } from \"../lib/appManagers/appStateManager\";\nimport rootScope from \"../lib/rootScope\";\n\nexport type ChatAutoDownloadSettings = {\n photo: number,\n video: number,\n file: number\n};\n\nexport default function getAutoDownloadSettingsByPeerId(peerId: PeerId): ChatAutoDownloadSettings {\n let type: keyof State['settings']['autoDownload'];\n\n let photoSizeMax = 0, videoSizeMax = 0, fileSizeMax = 0;\n const settings = rootScope.settings;\n if(!settings.autoDownloadNew.pFlags.disabled && peerId) {\n if(peerId.isUser()) {\n if(peerId.isContact()) {\n type = 'contacts';\n } else {\n type = 'private';\n }\n } else if(peerId.isBroadcast()) {\n type = 'channels';\n } else {\n type = 'groups';\n }\n \n if(settings.autoDownload.photo[type]) photoSizeMax = settings.autoDownloadNew.photo_size_max;\n if(settings.autoDownload.video[type]) videoSizeMax = settings.autoDownloadNew.video_size_max;\n if(settings.autoDownload.file[type]) fileSizeMax = settings.autoDownloadNew.file_size_max;\n }\n\n return {\n photo: photoSizeMax,\n video: videoSizeMax,\n file: fileSizeMax\n };\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport type { AppImManager } from \"../../lib/appManagers/appImManager\";\r\nimport RichTextProcessor from \"../../lib/richtextprocessor\";\r\nimport ButtonIcon from \"../buttonIcon\";\r\nimport { IS_TOUCH_SUPPORTED } from \"../../environment/touchSupport\";\r\nimport { IS_APPLE, IS_MOBILE } from \"../../environment/userAgent\";\r\nimport appNavigationController from \"../appNavigationController\";\r\nimport { _i18n } from \"../../lib/langPack\";\r\nimport cancelEvent from \"../../helpers/dom/cancelEvent\";\r\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\r\nimport getSelectedNodes from \"../../helpers/dom/getSelectedNodes\";\r\nimport isSelectionEmpty from \"../../helpers/dom/isSelectionEmpty\";\r\nimport { MarkdownType, markdownTags } from \"../../helpers/dom/getRichElementValue\";\r\nimport getVisibleRect from \"../../helpers/dom/getVisibleRect\";\r\nimport clamp from \"../../helpers/number/clamp\";\r\n//import { logger } from \"../../lib/logger\";\r\n\r\nexport default class MarkupTooltip {\r\n public container: HTMLElement;\r\n private wrapper: HTMLElement;\r\n private buttons: {[type in MarkdownType]: HTMLElement} = {} as any;\r\n private linkBackButton: HTMLElement;\r\n private linkApplyButton: HTMLButtonElement;\r\n private hideTimeout: number;\r\n private addedListener = false;\r\n private waitingForMouseUp = false;\r\n private linkInput: HTMLInputElement;\r\n private savedRange: Range;\r\n private mouseUpCounter: number = 0;\r\n //private log: ReturnType<typeof logger>;\r\n\r\n constructor(private appImManager: AppImManager) {\r\n //this.log = logger('MARKUP');\r\n }\r\n\r\n private init() {\r\n this.container = document.createElement('div');\r\n this.container.classList.add('markup-tooltip', 'z-depth-1', 'hide');\r\n\r\n this.wrapper = document.createElement('div');\r\n this.wrapper.classList.add('markup-tooltip-wrapper');\r\n \r\n const tools1 = document.createElement('div');\r\n const tools2 = document.createElement('div');\r\n tools1.classList.add('markup-tooltip-tools');\r\n tools2.classList.add('markup-tooltip-tools');\r\n\r\n const arr = ['bold', 'italic', 'underline', 'strikethrough', 'monospace', 'spoiler', 'link'] as (keyof MarkupTooltip['buttons'])[];\r\n arr.forEach(c => {\r\n const button = ButtonIcon(c, {noRipple: true});\r\n tools1.append(this.buttons[c] = button);\r\n\r\n if(c !== 'link') {\r\n button.addEventListener('mousedown', (e) => {\r\n cancelEvent(e); \r\n this.appImManager.chat.input.applyMarkdown(c);\r\n this.cancelClosening();\r\n \r\n /* this.mouseUpCounter = 0;\r\n this.setMouseUpEvent(); */\r\n //this.hide();\r\n });\r\n } else {\r\n attachClickEvent(button, (e) => {\r\n cancelEvent(e);\r\n this.showLinkEditor();\r\n this.cancelClosening();\r\n });\r\n }\r\n });\r\n\r\n this.linkBackButton = ButtonIcon('left', {noRipple: true});\r\n this.linkInput = document.createElement('input');\r\n _i18n(this.linkInput, 'MarkupTooltip.LinkPlaceholder', undefined, 'placeholder');\r\n this.linkInput.classList.add('input-clear');\r\n this.linkInput.addEventListener('keydown', (e) => {\r\n const valid = !this.linkInput.value.length || !!RichTextProcessor.matchUrl(this.linkInput.value);///^(http)|(https):\\/\\//i.test(this.linkInput.value);\r\n\r\n if(e.key === 'Enter') {\r\n if(!valid) {\r\n if(this.linkInput.classList.contains('error')) {\r\n this.linkInput.classList.remove('error');\r\n void this.linkInput.offsetLeft; // reflow\r\n }\r\n\r\n this.linkInput.classList.add('error');\r\n } else {\r\n this.applyLink(e);\r\n }\r\n }\r\n });\r\n\r\n this.linkInput.addEventListener('input', (e) => {\r\n const valid = this.isLinkValid();\r\n\r\n this.linkInput.classList.toggle('is-valid', valid);\r\n this.linkInput.classList.remove('error');\r\n });\r\n\r\n this.linkBackButton.addEventListener('mousedown', (e) => {\r\n //this.log('linkBackButton click');\r\n cancelEvent(e);\r\n this.container.classList.remove('is-link');\r\n //input.value = '';\r\n this.resetSelection();\r\n this.setTooltipPosition();\r\n this.cancelClosening();\r\n });\r\n\r\n this.linkApplyButton = ButtonIcon('check markup-tooltip-link-apply', {noRipple: true});\r\n this.linkApplyButton.addEventListener('mousedown', (e) => {\r\n //this.log('linkApplyButton click');\r\n this.applyLink(e);\r\n });\r\n\r\n const applyDiv = document.createElement('div');\r\n applyDiv.classList.add('markup-tooltip-link-apply-container');\r\n \r\n const delimiter1 = document.createElement('span');\r\n const delimiter2 = document.createElement('span');\r\n const delimiter3 = document.createElement('span');\r\n delimiter1.classList.add('markup-tooltip-delimiter');\r\n delimiter2.classList.add('markup-tooltip-delimiter');\r\n delimiter3.classList.add('markup-tooltip-delimiter');\r\n tools1.insertBefore(delimiter1, this.buttons.link);\r\n applyDiv.append(delimiter3, this.linkApplyButton);\r\n tools2.append(this.linkBackButton, delimiter2, this.linkInput, applyDiv);\r\n //tools1.insertBefore(delimiter2, this.buttons.link.nextSibling);\r\n\r\n this.wrapper.append(tools1, tools2);\r\n this.container.append(this.wrapper);\r\n document.body.append(this.container);\r\n \r\n window.addEventListener('resize', () => {\r\n this.hide();\r\n });\r\n }\r\n\r\n public showLinkEditor() {\r\n if(!this.container || !this.container.classList.contains('is-visible')) { // * if not inited yet (Ctrl+A + Ctrl+K)\r\n this.show();\r\n }\r\n\r\n const button = this.buttons.link;\r\n this.container.classList.add('is-link');\r\n\r\n const selection = document.getSelection();\r\n this.savedRange = selection.getRangeAt(0);\r\n \r\n if(button.classList.contains('active')) {\r\n const startContainer = this.savedRange.startContainer;\r\n const anchor = startContainer.parentElement as HTMLAnchorElement;\r\n this.linkInput.value = anchor.href;\r\n } else {\r\n this.linkInput.value = '';\r\n }\r\n\r\n this.setTooltipPosition(true);\r\n\r\n setTimeout(() => {\r\n this.linkInput.focus(); // !!! instant focus will break animation\r\n }, 200);\r\n this.linkInput.classList.toggle('is-valid', this.isLinkValid());\r\n }\r\n\r\n private applyLink(e: Event) {\r\n cancelEvent(e);\r\n this.resetSelection();\r\n let url = this.linkInput.value;\r\n if(url && !RichTextProcessor.matchUrlProtocol(url)) {\r\n url = 'https://' + url;\r\n }\r\n this.appImManager.chat.input.applyMarkdown('link', url);\r\n setTimeout(() => {\r\n this.hide();\r\n }, 0);\r\n }\r\n\r\n private isLinkValid() {\r\n return !this.linkInput.value.length || !!RichTextProcessor.matchUrl(this.linkInput.value);\r\n }\r\n\r\n private resetSelection(range: Range = this.savedRange) {\r\n const selection = window.getSelection();\r\n selection.removeAllRanges();\r\n selection.addRange(range);\r\n this.appImManager.chat.input.messageInput.focus();\r\n }\r\n\r\n public hide() {\r\n //return;\r\n\r\n if(this.init) return;\r\n\r\n this.container.classList.remove('is-visible');\r\n //document.removeEventListener('mouseup', this.onMouseUp);\r\n document.removeEventListener('mouseup', this.onMouseUpSingle);\r\n this.waitingForMouseUp = false;\r\n\r\n appNavigationController.removeByType('markup');\r\n\r\n if(this.hideTimeout) clearTimeout(this.hideTimeout);\r\n this.hideTimeout = window.setTimeout(() => {\r\n this.hideTimeout = undefined;\r\n this.container.classList.add('hide');\r\n this.container.classList.remove('is-link');\r\n }, 200);\r\n }\r\n\r\n public getActiveMarkupButton() {\r\n const nodes = getSelectedNodes();\r\n const parents = [...new Set(nodes.map(node => node.parentNode))];\r\n //if(parents.length > 1 && parents) return [];\r\n\r\n const currentMarkups: Set<HTMLElement> = new Set();\r\n (parents as HTMLElement[]).forEach(node => {\r\n for(const type in markdownTags) {\r\n const tag = markdownTags[type as MarkdownType];\r\n const closest = node.closest(tag.match + ', [contenteditable]');\r\n if(closest !== this.appImManager.chat.input.messageInput) {\r\n currentMarkups.add(this.buttons[type as MarkdownType]);\r\n }\r\n }\r\n });\r\n \r\n\r\n return [...currentMarkups];\r\n }\r\n\r\n public setActiveMarkupButton() {\r\n const activeButtons = this.getActiveMarkupButton();\r\n\r\n for(const i in this.buttons) {\r\n // @ts-ignore\r\n const button = this.buttons[i];\r\n button.classList.toggle('active', activeButtons.includes(button));\r\n }\r\n }\r\n\r\n private setTooltipPosition(isLinkToggle = false) {\r\n const selection = document.getSelection();\r\n const range = selection.getRangeAt(0);\r\n\r\n const bodyRect = document.body.getBoundingClientRect();\r\n const selectionRect = range.getBoundingClientRect();\r\n const inputRect = this.appImManager.chat.input.rowsWrapper.getBoundingClientRect();\r\n\r\n this.container.style.maxWidth = inputRect.width + 'px';\r\n\r\n const visibleRect = getVisibleRect(undefined, this.appImManager.chat.input.messageInput, false, selectionRect);\r\n\r\n const selectionTop = visibleRect.rect.top/* selectionRect.top */ + (bodyRect.top * -1);\r\n \r\n const currentTools = this.container.classList.contains('is-link') ? this.wrapper.lastElementChild : this.wrapper.firstElementChild;\r\n\r\n const sizesRect = currentTools.getBoundingClientRect();\r\n const top = selectionTop - sizesRect.height - 8;\r\n \r\n const minX = inputRect.left;\r\n const maxX = (inputRect.left + inputRect.width) - Math.min(inputRect.width, sizesRect.width);\r\n let left: number;\r\n if(isLinkToggle) {\r\n const containerRect = this.container.getBoundingClientRect();\r\n left = clamp(containerRect.left, minX, maxX);\r\n } else {\r\n const x = selectionRect.left + (selectionRect.width - sizesRect.width) / 2;\r\n left = clamp(x, minX, maxX);\r\n }\r\n\r\n /* const isClamped = x !== minX && x !== maxX && (left === minX || left === maxX || this.container.getBoundingClientRect().left >= maxX);\r\n\r\n if(isLinkToggle && this.container.classList.contains('is-link') && !isClamped) return; */\r\n \r\n this.container.style.transform = `translate3d(${left}px, ${top}px, 0)`;\r\n }\r\n\r\n public show() {\r\n if(this.init) {\r\n this.init();\r\n this.init = null;\r\n }\r\n\r\n if(isSelectionEmpty()) {\r\n this.hide();\r\n return;\r\n }\r\n\r\n if(this.hideTimeout !== undefined) {\r\n clearTimeout(this.hideTimeout);\r\n }\r\n\r\n if(this.container.classList.contains('is-visible')) {\r\n return;\r\n }\r\n\r\n this.setActiveMarkupButton();\r\n \r\n this.container.classList.remove('is-link');\r\n const isFirstShow = this.container.classList.contains('hide');\r\n if(isFirstShow) {\r\n this.container.classList.remove('hide');\r\n this.container.classList.add('no-transition');\r\n }\r\n \r\n this.setTooltipPosition();\r\n \r\n if(isFirstShow) {\r\n void this.container.offsetLeft; // reflow\r\n this.container.classList.remove('no-transition');\r\n }\r\n \r\n this.container.classList.add('is-visible');\r\n\r\n if(!IS_MOBILE) {\r\n appNavigationController.pushItem({\r\n type: 'markup',\r\n onPop: () => {\r\n this.hide();\r\n }\r\n });\r\n }\r\n\r\n //this.log('selection', selectionRect, activeButton);\r\n }\r\n\r\n /* private onMouseUp = (e: Event) => {\r\n this.log('onMouseUp');\r\n if(findUpClassName(e.target, 'markup-tooltip')) return;\r\n\r\n this.hide();\r\n //document.removeEventListener('mouseup', this.onMouseUp);\r\n }; */\r\n\r\n private onMouseUpSingle = (e?: Event) => {\r\n //this.log('onMouseUpSingle');\r\n this.waitingForMouseUp = false;\r\n\r\n if(IS_TOUCH_SUPPORTED) {\r\n e && cancelEvent(e);\r\n if(this.mouseUpCounter++ === 0) {\r\n this.resetSelection(this.savedRange);\r\n } else {\r\n this.hide();\r\n return;\r\n }\r\n }\r\n\r\n this.show();\r\n\r\n /* !isTouchSupported && document.addEventListener('mouseup', this.onMouseUp); */\r\n };\r\n\r\n public setMouseUpEvent() {\r\n if(this.waitingForMouseUp) return;\r\n this.waitingForMouseUp = true;\r\n\r\n //this.log('setMouseUpEvent');\r\n\r\n document.addEventListener('mouseup', this.onMouseUpSingle, {once: true});\r\n }\r\n\r\n public cancelClosening() {\r\n if(IS_TOUCH_SUPPORTED && !IS_APPLE) {\r\n document.removeEventListener('mouseup', this.onMouseUpSingle);\r\n document.addEventListener('mouseup', (e) => {\r\n cancelEvent(e);\r\n this.mouseUpCounter = 1;\r\n this.waitingForMouseUp = false;\r\n this.setMouseUpEvent();\r\n }, {once: true});\r\n }\r\n }\r\n\r\n public handleSelection() {\r\n if(this.addedListener) return;\r\n this.addedListener = true;\r\n document.addEventListener('selectionchange', (e) => {\r\n //this.log('selectionchange');\r\n\r\n if(document.activeElement === this.linkInput) {\r\n return;\r\n }\r\n\r\n const messageInput = this.appImManager.chat.input.messageInput;\r\n if(document.activeElement !== messageInput) {\r\n this.hide();\r\n return;\r\n }\r\n\r\n const selection = document.getSelection();\r\n if(isSelectionEmpty(selection)) {\r\n this.hide();\r\n return;\r\n }\r\n\r\n if(IS_TOUCH_SUPPORTED) {\r\n if(IS_APPLE) {\r\n this.show();\r\n this.setTooltipPosition(); // * because can skip this in .show();\r\n } else {\r\n if(this.mouseUpCounter === 2) {\r\n this.mouseUpCounter = 0;\r\n return;\r\n }\r\n\r\n this.savedRange = selection.getRangeAt(0);\r\n this.setMouseUpEvent();\r\n /* document.addEventListener('touchend', (e) => {\r\n cancelEvent(e);\r\n this.resetSelection(range);\r\n this.show();\r\n }, {once: true, passive: false}); */\r\n }\r\n } else if(this.container && this.container.classList.contains('is-visible')) {\r\n this.setTooltipPosition();\r\n } else if(messageInput.matches(':active')) {\r\n this.setMouseUpEvent();\r\n } else {\r\n this.show();\r\n }\r\n });\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nexport default function getSelectedNodes() {\r\n const nodes: Node[] = [];\r\n const selection = window.getSelection();\r\n for(let i = 0; i < selection.rangeCount; ++i) {\r\n const range = selection.getRangeAt(i);\r\n let {startContainer, endContainer} = range;\r\n if(endContainer.nodeType !== 3) endContainer = endContainer.firstChild;\r\n \r\n while(startContainer && startContainer !== endContainer) {\r\n nodes.push(startContainer.nodeType === 3 ? startContainer : startContainer.firstChild);\r\n startContainer = startContainer.nextSibling;\r\n }\r\n \r\n if(nodes[nodes.length - 1] !== endContainer) {\r\n nodes.push(endContainer);\r\n }\r\n }\r\n\r\n // * filter null's due to <br>\r\n return nodes.filter(node => !!node);\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\n// generate a path's arc data parameter\r\n\r\nimport { MOUNT_CLASS_TO } from \"../config/debug\";\r\n\r\n// http://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands\r\nfunction arcParameter(rx: number, ry: number, xAxisRotation: number, largeArcFlag: number, sweepFlag: number, x: number, y: number) {\r\n return [rx, ',', ry, ' ',\r\n xAxisRotation, ' ',\r\n largeArcFlag, ',',\r\n sweepFlag, ' ',\r\n x, ',', y ].join('');\r\n}\r\n\r\nexport default function generatePathData(x: number, y: number, width: number, height: number, tl: number, tr: number, br: number, bl: number) {\r\n const data: string[] = [];\r\n\r\n // start point in top-middle of the rectangle\r\n data.push('M' + (x + width / 2) + ',' + y);\r\n\r\n // next we go to the right\r\n data.push('H' + (x + width - tr));\r\n\r\n if(tr > 0) {\r\n // now we draw the arc in the top-right corner\r\n data.push('A' + arcParameter(tr, tr, 0, 0, 1, (x + width), (y + tr)));\r\n }\r\n\r\n // next we go down\r\n data.push('V' + (y + height - br));\r\n\r\n if(br > 0) {\r\n // now we draw the arc in the lower-right corner\r\n data.push('A' + arcParameter(br, br, 0, 0, 1, (x + width - br), (y + height)));\r\n }\r\n\r\n // now we go to the left\r\n data.push('H' + (x + bl));\r\n\r\n if(bl > 0) {\r\n // now we draw the arc in the lower-left corner\r\n data.push('A' + arcParameter(bl, bl, 0, 0, 1, (x + 0), (y + height - bl)));\r\n }\r\n\r\n // next we go up\r\n data.push('V' + (y + tl));\r\n\r\n if(tl > 0) {\r\n // now we draw the arc in the top-left corner\r\n data.push('A' + arcParameter(tl, tl, 0, 0, 1, (x + tl), (y + 0)));\r\n }\r\n\r\n // and we close the path\r\n data.push('Z');\r\n\r\n return data.join(' ');\r\n}\r\n\r\nMOUNT_CLASS_TO.generatePathData = generatePathData;\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport generatePathData from \"../../helpers/generatePathData\";\r\nimport { FormatterArguments, i18n, LangPackKey } from \"../../lib/langPack\";\r\n\r\nexport default class ChatDragAndDrop {\r\n container: HTMLDivElement;\r\n svg: SVGSVGElement;\r\n outlineWrapper: HTMLDivElement;\r\n path: SVGPathElement;\r\n\r\n constructor(appendTo: HTMLElement, private options: {\r\n icon?: string,\r\n header: LangPackKey,\r\n headerArgs?: FormatterArguments,\r\n subtitle?: LangPackKey,\r\n onDrop: (e: DragEvent) => void\r\n }) {\r\n this.container = document.createElement('div');\r\n this.container.classList.add('drop', 'z-depth-1');\r\n\r\n this.outlineWrapper = document.createElement('div');\r\n this.outlineWrapper.classList.add('drop-outline-wrapper');\r\n\r\n this.svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\r\n this.svg.classList.add('drop-outline');\r\n\r\n this.path = document.createElementNS('http://www.w3.org/2000/svg', 'path');\r\n this.path.classList.add('drop-outline-path');\r\n\r\n let dropIcon: HTMLElement;\r\n if(options.icon) {\r\n dropIcon = document.createElement('div');\r\n dropIcon.classList.add('drop-icon', 'tgico-' + options.icon);\r\n }\r\n\r\n const dropHeader = document.createElement('div');\r\n dropHeader.classList.add('drop-header');\r\n dropHeader.append(i18n(options.header, options.headerArgs));\r\n\r\n let dropSubtitle: HTMLElement;\r\n if(options.subtitle) {\r\n dropSubtitle = document.createElement('div');\r\n dropSubtitle.classList.add('drop-subtitle');\r\n dropSubtitle.append(i18n(options.subtitle));\r\n }\r\n\r\n this.svg.append(this.path);\r\n this.outlineWrapper.append(this.svg);\r\n\r\n this.container.append(...[this.outlineWrapper, dropIcon, dropHeader, dropSubtitle].filter(Boolean));\r\n appendTo.append(this.container);\r\n\r\n this.container.addEventListener('dragover', this.onDragOver);\r\n this.container.addEventListener('dragleave', this.onDragLeave);\r\n this.container.addEventListener('drop', this.onDrop);\r\n }\r\n\r\n onDragOver = (e: DragEvent) => {\r\n this.container.classList.add('is-dragover');\r\n //SetTransition(this.container, 'is-dragover', true, 500);\r\n };\r\n\r\n onDragLeave = (e: DragEvent) => {\r\n this.container.classList.remove('is-dragover');\r\n //SetTransition(this.container, 'is-dragover', false, 500);\r\n };\r\n\r\n onDrop = (e: DragEvent) => {\r\n this.options.onDrop(e);\r\n };\r\n\r\n destroy() {\r\n delete this.options;\r\n this.container.remove();\r\n this.container.removeEventListener('dragover', this.onDragOver);\r\n this.container.removeEventListener('dragleave', this.onDragLeave);\r\n this.container.removeEventListener('drop', this.onDrop);\r\n }\r\n\r\n setPath() {\r\n const rect = this.outlineWrapper.getBoundingClientRect();\r\n this.svg.setAttributeNS(null, 'preserveAspectRatio', 'none');\r\n this.svg.setAttributeNS(null, 'viewBox', `0 0 ${rect.width} ${rect.height}`);\r\n this.svg.setAttributeNS(null, 'width', `${rect.width}`);\r\n this.svg.setAttributeNS(null, 'height', `${rect.height}`);\r\n\r\n const radius = 10;\r\n //const strokeWidth = 2;\r\n const sizeX = rect.width - radius;\r\n const sizeY = rect.height - radius;\r\n const pos = radius / 2;\r\n const d = generatePathData(pos, pos, sizeX, sizeY, radius, radius, radius, radius);\r\n this.path.setAttributeNS(null, 'd', d);\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { doubleRaf } from \"../schedulers\";\r\n\r\nexport default function disableTransition(elements: HTMLElement[]) {\r\n elements.forEach(el => el.classList.add('no-transition'));\r\n\r\n doubleRaf().then(() => {\r\n elements.forEach(el => el.classList.remove('no-transition'));\r\n });\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n * \n * Originally from:\n * https://github.com/evgeny-nadymov/telegram-react\n * Copyright (C) 2018 Evgeny Nadymov\n * https://github.com/evgeny-nadymov/telegram-react/blob/master/LICENSE\n */\n\nexport const MAX_SPEED = 8.2;\nexport const MIN_SPEED = 0.8;\n\n// import { MIN_SPEED, MAX_SPEED } from './BlobDrawable';\n\ntype Radius = number[];\n\nexport default class LineBlobDrawable {\n public maxRadius: number;\n public minRadius: number;\n private N: number;\n private radius: Radius;\n private radiusNext: Radius;\n private progress: number[];\n private speed: number[];\n \n constructor(n: number) {\n this.maxRadius = 10;\n this.minRadius = 0;\n \n this.N = n;\n this.radius = new Array(n + 1);\n \n this.radiusNext = new Array(n + 1);\n this.progress = new Array(n + 1);\n this.speed = new Array(n + 1);\n \n for(let i = 0; i <= n; i++) {\n this.generateBlob(this.radius, i);\n this.generateBlob(this.radiusNext, i);\n this.progress[i] = 0;\n }\n }\n \n private generateBlob(radius: Radius, i: number) {\n const {maxRadius, minRadius, speed} = this;\n \n const radDif = maxRadius - minRadius;\n radius[i] = minRadius + Math.random() * radDif;\n speed[i] = 0.017 + 0.003 * Math.random();\n }\n \n private generateNextBlob() {\n const {radius, radiusNext, progress, N} = this;\n for(let i = 0; i < N; i++) {\n this.generateBlob(radius, i);\n this.generateBlob(radiusNext, i);\n progress[i] = 0.0;\n }\n }\n \n public update(amplitude: number, speedScale: number) {\n const {N, progress, speed, radius, radiusNext} = this;\n for(let i = 0; i <= N; i++) {\n progress[i] += (speed[i] * MIN_SPEED) + amplitude * speed[i] * MAX_SPEED * speedScale;\n if(progress[i] >= 1.0) {\n progress[i] = 0.0;\n radius[i] = radiusNext[i];\n this.generateBlob(radiusNext, i);\n }\n }\n }\n \n public draw(left: number, top: number, right: number, bottom: number, canvas: HTMLCanvasElement, paint: (ctx: CanvasRenderingContext2D) => void, pinnedTop: number, progressToPinned: number) {\n if(canvas.getContext) {\n const ctx = canvas.getContext('2d');\n // ctx.globalAlpha = 0.5;\n // ctx.lineWidth = 1;\n \n ctx.beginPath();\n ctx.moveTo(right, bottom);\n ctx.lineTo(left, bottom);\n \n const {radius, radiusNext, N} = this;\n for(let i = 0; i <= N; i++) {\n if(i === 0) {\n const progress = this.progress[i];\n const r1 = radius[i] * (1.0 - progress) + radiusNext[i] * progress;\n const y = (top - r1) * progressToPinned + pinnedTop * (1.0 - progressToPinned);\n ctx.lineTo(left, y);\n } else {\n const progress = this.progress[i - 1];\n const r1 = radius[i - 1] * (1.0 - progress) + radiusNext[i - 1] * progress;\n const progressNext = this.progress[i];\n const r2 = radius[i] * (1.0 - progressNext) + radiusNext[i] * progressNext;\n const x1 = (right - left) / N * (i - 1);\n const x2 = (right - left) / N * i;\n const cx = x1 + (x2 - x1) / 2;\n \n const y1 = (top - r1) * progressToPinned + pinnedTop * (1.0 - progressToPinned);\n const y2 = (top - r2) * progressToPinned + pinnedTop * (1.0 - progressToPinned);\n ctx.bezierCurveTo(cx, y1, cx, y2, x2, y2);\n if(i === N) {\n ctx.lineTo(right, bottom);\n }\n }\n }\n \n // ctx.scale(1.0, 1.0);\n paint(ctx);\n ctx.fill();\n ctx.closePath();\n }\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n * \n * Originally from:\n * https://github.com/evgeny-nadymov/telegram-react\n * Copyright (C) 2018 Evgeny Nadymov\n * https://github.com/evgeny-nadymov/telegram-react/blob/master/LICENSE\n */\n\nimport GROUP_CALL_STATE from '../lib/calls/groupCallState';\nimport LineBlobDrawable from './lineBlobDrawable';\n\nexport class WeavingState {\n public shader: (ctx: CanvasRenderingContext2D, left: number, top: number, right: number, bottom: number) => void;\n \n constructor(public stateId: GROUP_CALL_STATE) {\n this.createGradient(stateId);\n }\n \n public createGradient(stateId: GROUP_CALL_STATE) {\n this.shader = (ctx, left, top, right, bottom) => {\n ctx.fillStyle = WeavingState.getGradientFromType(ctx, stateId, left, top, right, bottom);\n };\n }\n \n // Android colors\n static getGradientFromType(ctx: CanvasRenderingContext2D, type: GROUP_CALL_STATE, x0: number, y0: number, x1: number, y1: number) {\n const gradient = ctx.createLinearGradient(x0, y0, x1, y1);\n if(type === GROUP_CALL_STATE.MUTED_BY_ADMIN) {\n gradient.addColorStop(0, '#F05459');\n gradient.addColorStop(.4, '#766EE9');\n gradient.addColorStop(1, '#57A4FE');\n } else if(type === GROUP_CALL_STATE.UNMUTED) {\n gradient.addColorStop(0, '#52CE5D');\n gradient.addColorStop(1, '#00B1C0');\n } else if(type === GROUP_CALL_STATE.MUTED) {\n gradient.addColorStop(0, '#0976E3');\n gradient.addColorStop(1, '#2BCEFF');\n } else if(type === GROUP_CALL_STATE.CONNECTING) {\n gradient.addColorStop(0, '#8599aa');\n gradient.addColorStop(1, '#8599aa');\n }\n \n return gradient;\n }\n \n update(height: number, width: number, dt: number, amplitude: number) {\n // TODO: move gradient here\n }\n}\n\nexport default class TopbarWeave {\n private focused: boolean;\n private resizing: boolean;\n private lastUpdateTime: number;\n private amplitude: number;\n private amplitude2: number;\n \n private states: Map<GROUP_CALL_STATE, WeavingState>;\n private previousState: WeavingState;\n private currentState: WeavingState;\n private progressToState: number;\n \n private scale: number;\n private left: number;\n private top: number;\n private right: number;\n private bottom: number;\n \n private mounted: boolean;\n private media: MediaQueryList;\n \n private container: HTMLDivElement;\n private canvas: HTMLCanvasElement;\n \n private resizeHandler: number;\n private raf: number;\n\n private lbd: LineBlobDrawable;\n private lbd1: LineBlobDrawable;\n private lbd2: LineBlobDrawable;\n\n private animateToAmplitude: number;\n private animateAmplitudeDiff: number;\n private animateAmplitudeDiff2: number;\n \n constructor() {\n this.focused = true;\n this.resizing = false;\n this.lastUpdateTime = Date.now();\n this.amplitude = 0.0;\n this.amplitude2 = 0.0;\n \n this.states = new Map([\n [GROUP_CALL_STATE.UNMUTED, new WeavingState(GROUP_CALL_STATE.UNMUTED)],\n [GROUP_CALL_STATE.MUTED, new WeavingState(GROUP_CALL_STATE.MUTED)],\n [GROUP_CALL_STATE.MUTED_BY_ADMIN, new WeavingState(GROUP_CALL_STATE.MUTED_BY_ADMIN)],\n [GROUP_CALL_STATE.CONNECTING, new WeavingState(GROUP_CALL_STATE.CONNECTING)],\n ]);\n this.previousState = null;\n this.currentState = this.states.get(GROUP_CALL_STATE.CONNECTING);\n this.progressToState = 1.0;\n }\n \n public componentDidMount() {\n if(this.mounted) {\n return;\n }\n\n this.mounted = true;\n // window.addEventListener('blur', this.handleBlur);\n // window.addEventListener('focus', this.handleFocus);\n window.addEventListener('resize', this.handleResize);\n this.media = window.matchMedia('screen and (min-resolution: 2dppx)');\n this.media.addEventListener('change', this.handleDevicePixelRatioChanged);\n \n this.setSize();\n this.forceUpdate();\n \n this.lbd = new LineBlobDrawable(3);\n this.lbd1 = new LineBlobDrawable(7);\n this.lbd2 = new LineBlobDrawable(8);\n this.setAmplitude(this.amplitude);\n \n this.draw();\n }\n \n public componentWillUnmount() {\n this.mounted = false;\n // window.removeEventListener('blur', this.handleBlur);\n // window.removeEventListener('focus', this.handleFocus);\n window.removeEventListener('resize', this.handleResize);\n this.media.addEventListener('change', this.handleDevicePixelRatioChanged);\n\n const {canvas} = this;\n const ctx = canvas.getContext('2d');\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n }\n\n private setSize() {\n this.scale = window.devicePixelRatio;\n this.top = 20 * this.scale;\n this.right = (this.mounted ? this.container.offsetWidth : 1261) * this.scale;\n this.bottom = (this.mounted ? this.container.offsetHeight : 68) * this.scale;\n this.left = 0 * this.scale;\n this.setCanvasSize();\n }\n\n private setCanvasSize() {\n this.canvas.width = this.right;\n this.canvas.height = this.bottom;\n }\n \n private handleDevicePixelRatioChanged = (e: Event) => {\n this.setSize();\n this.forceUpdate();\n }\n \n private handleResize = () => {\n if(this.resizeHandler) {\n clearTimeout(this.resizeHandler);\n this.resizeHandler = null;\n }\n \n this.resizing = true;\n this.resizeCanvas();\n this.resizeHandler = window.setTimeout(() => {\n this.resizing = false;\n this.invokeDraw();\n }, 250);\n }\n \n private resizeCanvas() {\n this.scale = window.devicePixelRatio;\n this.right = this.container.offsetWidth * this.scale;\n \n this.forceUpdate();\n this.invokeDraw();\n }\n \n public handleFocus = () => {\n this.focused = true;\n this.invokeDraw();\n }\n \n public handleBlur = () => {\n this.focused = false;\n }\n \n private invokeDraw = () => {\n if(this.raf) return;\n \n this.draw();\n }\n \n private draw = (force = false) => {\n this.raf = null;\n if(!this.mounted) {\n return;\n }\n const {lbd, lbd1, lbd2, scale, left, top, right, bottom, currentState, previousState, focused, resizing, canvas} = this;\n if(!focused && !resizing && this.progressToState >= 1.0) {\n return;\n }\n \n // console.log('[top] draw', [focused, resizing, this.mounted]);\n \n const newTime = Date.now();\n let dt = (newTime - this.lastUpdateTime);\n if(dt > 20) {\n dt = 17;\n }\n \n // console.log('draw start', this.amplitude, this.animateToAmplitude);\n if(this.animateToAmplitude !== this.amplitude) {\n this.amplitude += this.animateAmplitudeDiff * dt;\n if(this.animateAmplitudeDiff > 0) {\n if(this.amplitude > this.animateToAmplitude) {\n this.amplitude = this.animateToAmplitude;\n }\n } else {\n if(this.amplitude < this.animateToAmplitude) {\n this.amplitude = this.animateToAmplitude;\n }\n }\n }\n \n if(this.animateToAmplitude !== this.amplitude2) {\n this.amplitude2 += this.animateAmplitudeDiff2 * dt;\n if(this.animateAmplitudeDiff2 > 0) {\n if(this.amplitude2 > this.animateToAmplitude) {\n this.amplitude2 = this.animateToAmplitude;\n }\n } else {\n if(this.amplitude2 < this.animateToAmplitude) {\n this.amplitude2 = this.animateToAmplitude;\n }\n }\n }\n \n if(previousState) {\n this.progressToState += dt / 250;\n if(this.progressToState > 1) {\n this.progressToState = 1;\n this.previousState = null;\n }\n }\n\n const {amplitude, amplitude2, progressToState} = this;\n \n const top1 = 6 * amplitude2 * scale;\n const top2 = 6 * amplitude2 * scale;\n \n const ctx = canvas.getContext('2d');\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n \n lbd.minRadius = 0;\n lbd.maxRadius = (2 + 2 * amplitude) * scale;\n lbd1.minRadius = 0;\n lbd1.maxRadius = (3 + 9 * amplitude) * scale;\n lbd2.minRadius = 0;\n lbd2.maxRadius = (3 + 9 * amplitude) * scale;\n \n lbd.update(amplitude, 0.3);\n lbd1.update(amplitude, 0.7);\n lbd2.update(amplitude, 0.7);\n \n for(let i = 0; i < 2; i++) {\n if(i === 0 && !previousState) {\n continue;\n }\n \n let alpha = 1;\n let state: WeavingState = null;\n if(i === 0) {\n alpha = 1 - progressToState;\n state = previousState;\n // previousState.setToPaint(paint);\n } else {\n alpha = previousState ? progressToState : 1;\n currentState.update(bottom - top, right - left, dt, amplitude);\n state = currentState;\n // currentState.setToPaint(paint);\n }\n \n const paint1 = (ctx: CanvasRenderingContext2D) => {\n ctx.globalAlpha = 0.3 * alpha;\n state.shader(ctx, left, top, right, bottom);\n };\n const paint = (ctx: CanvasRenderingContext2D) => {\n ctx.globalAlpha = i === 0 ? 1 : alpha;\n state.shader(ctx, left, top, right, bottom);\n };\n \n lbd1.draw(left, top - top1, right, bottom, canvas, paint1, top, 1.0);\n lbd2.draw(left, top - top2, right, bottom, canvas, paint1, top, 1.0);\n lbd.draw(left, top, right, bottom, canvas, paint, top, 1.0);\n }\n \n if(!force) {\n this.raf = requestAnimationFrame(() => this.draw());\n }\n };\n \n public setCurrentState = (stateId: GROUP_CALL_STATE, animated: boolean) => {\n const {currentState, states} = this;\n \n if(currentState?.stateId === stateId) {\n return;\n }\n \n this.previousState = animated ? currentState : null;\n this.currentState = states.get(stateId);\n this.progressToState = this.previousState ? 0.0 : 1.0;\n };\n \n public setAmplitude(value: number) {\n const {amplitude} = this;\n this.animateToAmplitude = value;\n this.animateAmplitudeDiff = (value - amplitude) / 250;\n this.animateAmplitudeDiff2 = (value - amplitude) / 120;\n }\n\n private forceUpdate() {\n this.setCanvasSize();\n }\n \n public render(className: string) {\n const container = this.container = document.createElement('div');\n container.classList.add(className);\n\n const canvas = this.canvas = document.createElement('canvas');\n canvas.classList.add(className + '-canvas');\n\n container.append(canvas);\n\n return container;\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport rootScope from \"../../lib/rootScope\";\n\nexport type CustomProperty = string;\n\nexport class CustomProperties {\n private cache: {[k in CustomProperty]?: string};\n private computedStyle: CSSStyleDeclaration;\n\n constructor() {\n this.cache = {};\n\n rootScope.addEventListener('theme_change', () => {\n this.computedStyle = undefined;\n const cache = this.cache;\n this.cache = {};\n\n for(let i in cache) {\n this.getProperty(i);\n }\n });\n }\n\n public getProperty(name: CustomProperty) {\n let value = this.cache[name];\n if(value) {\n return value;\n }\n\n if(!this.computedStyle) {\n this.computedStyle = window.getComputedStyle(document.documentElement);\n }\n\n value = this.computedStyle.getPropertyValue('--' + name).trim();\n return this.cache[name] = value;\n }\n}\n\nconst customProperties = new CustomProperties();\nexport default customProperties;\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport noop from \"../../helpers/noop\";\nimport safeAssign from \"../../helpers/object/safeAssign\";\nimport rootScope from \"../rootScope\";\nimport lottieLoader, { LottieAssetName } from \"./lottieLoader\";\nimport type RLottiePlayer from \"./rlottiePlayer\";\nimport { RLottieColor } from \"./rlottiePlayer\";\n\nexport type RLottieIconOptions = {\n width: number,\n height: number,\n container?: HTMLElement,\n skipAnimation?: boolean\n};\n\nexport type RLottieIconItemPartOptions = {\n startFrame: number,\n endFrame: number,\n name?: string\n};\n\nexport type RLottieIconItemOptions = {\n name: LottieAssetName,\n parts: RLottieIconItemPartOptions[],\n initFrame?: number,\n player?: RLottiePlayer,\n autoplay?: boolean,\n color?: RLottieColor,\n inverseColor?: RLottieColor,\n};\n\nexport class RLottieIconItemPart implements RLottieIconItemPartOptions {\n public startFrame: number;\n public endFrame: number;\n public name?: string;\n \n constructor(public item: RLottieIconItem, options: RLottieIconItemPartOptions) {\n safeAssign(this, options);\n }\n\n public play(callback?: () => void) {\n return this.item.playPart(this, callback);\n }\n}\n\n// export type RLottieIconItemPart = RLottieIconItemPartOptions;\n\nexport class RLottieIconItem implements RLottieIconItemOptions {\n public name: LottieAssetName;\n public parts: RLottieIconItemPart[];\n public player: RLottiePlayer;\n public initFrame: number;\n public autoplay: boolean;\n public color: RLottieColor;\n public inverseColor: RLottieColor;\n public loadPromise: Promise<void>;\n public onLoadForPart: () => void;\n public onLoadForColor: () => void;\n\n constructor(public icon: RLottieIcon, options: RLottieIconItemOptions) {\n this.autoplay = false;\n\n safeAssign(this, options);\n\n this.parts = this.parts.map(options => this.createPart(options));\n }\n\n public load() {\n let loadPromise = this.loadPromise;\n if(loadPromise) {\n return loadPromise;\n }\n\n const {container, canvas, width, height} = this.icon;\n loadPromise = lottieLoader.loadAnimationAsAsset({\n container,\n canvas,\n width,\n height,\n group: 'none',\n loop: false,\n autoplay: this.autoplay ?? false,\n initFrame: this.initFrame,\n skipFirstFrameRendering: this.initFrame === undefined,\n color: this.color,\n inverseColor: this.inverseColor\n }, this.name).then(player => {\n return lottieLoader.waitForFirstFrame(player);\n }).then(player => {\n this.player = player;\n\n if(this.onLoadForColor) {\n this.onLoadForColor();\n this.onLoadForColor = undefined;\n }\n\n if(this.onLoadForPart) {\n this.onLoadForPart();\n this.onLoadForPart = undefined;\n }\n });\n\n this.loadPromise = loadPromise;\n this.icon.loadPromises.set(this.name, loadPromise);\n return loadPromise;\n }\n\n public createPart(options: RLottieIconItemPartOptions) {\n return new RLottieIconItemPart(this, options);\n }\n\n public getPart(index: string | number | RLottieIconItemPart) {\n if(index instanceof RLottieIconItemPart) return index;\n else if(typeof(index) === 'string') return this.parts.find(part => part.name === index);\n else return this.parts[index];\n }\n\n public playPart(part: RLottieIconItemPart, callback?: () => void) {\n return this.icon.playPart(this, part, callback);\n }\n}\n\nexport default class RLottieIcon {\n public container: HTMLElement;\n public canvas: HTMLCanvasElement;\n public width: number;\n public height: number;\n\n protected items: Map<LottieAssetName, RLottieIconItem>;\n public loadPromises: Map<LottieAssetName, Promise<void>>;\n\n protected skipAnimation: boolean;\n\n constructor(options: RLottieIconOptions) {\n safeAssign(this, options);\n\n if(!this.container) this.container = document.createElement('div');\n this.container.classList.add('rlottie-icon');\n\n const {width, height} = this;\n this.container.style.width = width + 'px';\n this.container.style.height = height + 'px';\n\n const canvas = this.canvas = document.createElement('canvas');\n canvas.classList.add('rlottie');\n canvas.width = width;\n canvas.height = height;\n\n this.items = new Map();\n this.loadPromises = new Map();\n }\n\n public get loadPromise() {\n return Promise.all([...this.loadPromises.values()]).then(noop);\n }\n\n public getItem(name?: LottieAssetName): RLottieIconItem {\n return !name && this.items.size === 1 ? this.items.values().next().value : this.items.get(name);\n }\n\n public add(options: Omit<RLottieIconItemOptions, 'player'>) {\n const item = new RLottieIconItem(this, options);\n this.items.set(options.name, item);\n\n return item;\n }\n\n public playPart(item: RLottieIconItem, index: Parameters<RLottieIconItem['getPart']>[0], callback?: () => void) {\n if(!item.player) {\n item.onLoadForPart = () => {\n this.playPart(item, index, callback);\n };\n\n return;\n }\n \n const part = item.getPart(index);\n item.player.playPart({\n from: rootScope.settings.animationsEnabled && !this.skipAnimation ? part.startFrame : part.endFrame, \n to: part.endFrame,\n callback\n });\n }\n\n /* public playToPart(item: RLottieIconItem, index: Parameters<RLottieIconItem['getPart']>[0], toEnd: boolean) {\n if(!item.player) return;\n const part = item.getPart(index);\n const toFrame = toEnd ? part.endFrame : part.startFrame;\n item.player.playToFrame({\n frame: toFrame\n });\n } */\n \n public static generateEqualParts(length: number, frameCount: number): RLottieIconItemPartOptions[] {\n return new Array(length).fill(0).map((_, idx) => {\n const startFrame = idx * frameCount;\n return {startFrame, endFrame: startFrame + frameCount - 1};\n });\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport noop from \"../helpers/noop\";\nimport safeAssign from \"../helpers/object/safeAssign\";\nimport { LottieAssetName } from \"../lib/rlottie/lottieLoader\";\nimport RLottieIcon, { RLottieIconItemPartOptions, RLottieIconItemPart } from \"../lib/rlottie/rlottieIcon\";\nimport { RLottieColor } from \"../lib/rlottie/rlottiePlayer\";\n\nexport type SuperRLottieIconAddItemOptions = {name: LottieAssetName, parts: RLottieIconItemPartOptions};\nexport type SuperRLottieIconGetInfoResult = RLottieIconItemPart;\nexport class SuperRLottieIcon<Options extends {\n PartState: any,\n ColorState?: any,\n Items?: {\n name: string\n }[]\n}> extends RLottieIcon {\n protected getPart: (state: Options['PartState'], prevState?: Options['PartState']) => SuperRLottieIconGetInfoResult;\n protected getColor?: (state: Options['ColorState'], prevState?: Options['ColorState']) => RLottieColor;\n\n protected partState: Options['PartState'];\n protected colorState: Options['ColorState'];\n protected loaded: boolean;\n\n constructor(options: {\n width: number,\n height: number,\n skipAnimation?: boolean,\n getPart: (state: Options['PartState'], prevState?: Options['PartState']) => SuperRLottieIconGetInfoResult,\n getColor?: (state: Options['ColorState'], prevState?: Options['ColorState']) => RLottieColor,\n }) {\n super({\n width: options.width,\n height: options.height\n });\n\n safeAssign(this, options);\n\n // hook the first call\n /* const originalFunction = this.setState.bind(this);\n this.setState = (partState, colorState) => {\n this.setState = originalFunction;\n this.load(partState, colorState);\n return originalFunction(partState, colorState);\n }; */\n }\n\n public load(partState: Options['PartState'], colorState?: Options['ColorState']) {\n if(this.loaded) {\n return this.loadPromise;\n }\n\n this.loaded = true;\n this.partState = partState;\n this.colorState = colorState;\n\n const part = this.getPart(partState);\n const color = colorState !== undefined && this.getColor && this.getColor(colorState);\n\n const item = part.item;\n item.initFrame = part.endFrame;\n item.color = color;\n\n const promises = [...this.items.values()].map(item => item.load());\n return Promise.all(promises).then(noop);\n }\n\n /**\n * Will redirect setting color state to part callback to synchronize the rendering\n */\n public setState(partState: Options['PartState'], colorState?: Options['ColorState'], partCallback?: () => void) {\n if(!this.loaded) this.load(partState, colorState);\n\n let changedPartState = false, changedColorState = false;\n if(partState !== undefined) changedPartState = this.setPartState(partState, colorState, partCallback);\n else if(colorState !== undefined) changedColorState = this.setColorState(colorState);\n\n return changedPartState || changedColorState;\n }\n\n public setPartState(state: Options['PartState'], colorState?: Options['ColorState'], callback?: () => void) {\n const {partState: prevState} = this;\n if(prevState === state) {\n return colorState !== undefined ? this.setColorState(colorState) : false;\n }\n\n if(colorState !== undefined) {\n this.setColorState(colorState, false);\n }\n\n this.partState = state;\n\n const part = this.getPart(state, prevState);\n part.play(callback);\n\n return true;\n }\n\n public setColorState(state: Options['ColorState'], renderIfPaused = true) {\n const {colorState: prevState} = this;\n if(prevState === state || !this.getColor) {\n return false;\n }\n\n this.colorState = state;\n \n const item = this.getItem();\n const color = this.getColor(state, prevState);\n const invoke = () => {\n item.player.setColor(color, renderIfPaused);\n };\n \n if(item.player) {\n invoke();\n } else {\n item.onLoadForColor = invoke;\n }\n\n return true;\n }\n\n public destroy() {\n this.items.forEach(item => {\n item.loadPromise.then(() => {\n item.player.remove();\n });\n });\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { RLottieIconItemPartOptions } from \"../../lib/rlottie/rlottieIcon\";\nimport { GROUP_CALL_MICROPHONE_BUTTON_STATE } from \".\";\nimport { SuperRLottieIcon } from \"../superIcon\";\n\nexport default class GroupCallMicrophoneIcon extends SuperRLottieIcon<{\n PartState: GROUP_CALL_MICROPHONE_BUTTON_STATE\n}> {\n constructor() {\n super({\n width: 36,\n height: 36,\n getPart: (state, prevState) => {\n const states = GROUP_CALL_MICROPHONE_BUTTON_STATE;\n let partName: string;\n switch(state) {\n case states.HAND:\n partName = prevState === states.MUTED ? 'muted-to-hand' : 'unmuted-to-hand';\n break;\n case states.MUTED:\n partName = prevState === states.HAND ? 'hand-to-muted' : 'mute';\n break;\n case states.UNMUTED:\n partName = 'unmute';\n break;\n }\n\n return this.getItem().getPart(partName);\n }\n });\n\n const className = 'group-call-microphone-icon';\n this.container.classList.add(className + '-container');\n\n const parts: RLottieIconItemPartOptions[] = [{\n startFrame: 0,\n endFrame: 35,\n name: 'hand-to-muted'\n }, {\n startFrame: 36,\n endFrame: 68,\n name: 'unmute'\n }, {\n startFrame: 69,\n endFrame: 98,\n name: 'mute'\n }, {\n startFrame: 99,\n endFrame: 135,\n name: 'muted-to-hand'\n }, {\n startFrame: 136,\n endFrame: 172,\n name: 'unmuted-to-hand'\n }, {\n startFrame: 173,\n endFrame: 201,\n name: 'scheduled-crossing'\n }, {\n startFrame: 202,\n endFrame: 236,\n name: 'scheduled-to-muted'\n }, {\n startFrame: 237,\n endFrame: 273,\n name: 'scheduled-to-hand'\n }, {\n startFrame: 274,\n endFrame: 310,\n name: 'scheduled-crossed-to-hand'\n }, {\n startFrame: 311,\n endFrame: 343,\n name: 'scheduled-uncrossing'\n }, {\n startFrame: 344,\n endFrame: 375,\n name: 'scheduled-to-muted'\n }, {\n startFrame: 376,\n endFrame: 403,\n name: 'play-to-muted'\n }];\n\n this.add({\n name: 'voip_filled',\n parts\n });\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport RLottieIcon from \"../../lib/rlottie/rlottieIcon\";\nimport { GROUP_CALL_PARTICIPANT_CLEARED_MUTED_STATE, GROUP_CALL_PARTICIPANT_MUTED_STATE, getColorByMutedState, clearMutedStateModifier } from \".\";\nimport { SuperRLottieIcon } from \"../superIcon\";\n\nexport default class GroupCallParticipantMutedIcon extends SuperRLottieIcon<{\n PartState: GROUP_CALL_PARTICIPANT_CLEARED_MUTED_STATE, \n ColorState: GROUP_CALL_PARTICIPANT_MUTED_STATE\n}> {\n constructor(private colored: boolean) {\n super({\n width: 32,\n height: 32,\n getPart: (state, prevState) => {\n const states = GROUP_CALL_PARTICIPANT_MUTED_STATE;\n\n let index: number;\n switch(state) {\n case states.HAND:\n index = 3;\n break;\n case states.MUTED:\n index = prevState === states.HAND ? 0 : 2;\n break;\n case states.UNMUTED:\n index = 1;\n break;\n }\n\n return this.getItem().getPart(index);\n },\n getColor: colored ? (state, prevState) => {\n return getColorByMutedState(state);\n } : undefined\n });\n\n const className = 'group-call-participant-muted-icon';\n this.container.classList.add(className + '-container');\n\n const parts = RLottieIcon.generateEqualParts(4, 21);\n this.add({\n name: 'voice_outlined2',\n parts\n });\n }\n\n public setState(state: GROUP_CALL_PARTICIPANT_MUTED_STATE) {\n return super.setState(clearMutedStateModifier(state), state);\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport PopupElement from \"../popups\";\nimport { hexToRgb } from \"../../helpers/color\";\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\nimport customProperties from \"../../helpers/dom/customProperties\";\nimport { GroupCall, GroupCallParticipant } from \"../../layer\";\nimport type { AppChatsManager } from \"../../lib/appManagers/appChatsManager\";\nimport type { AppGroupCallsManager } from \"../../lib/appManagers/appGroupCallsManager\";\nimport type { AppPeersManager } from \"../../lib/appManagers/appPeersManager\";\nimport GROUP_CALL_STATE from \"../../lib/calls/groupCallState\";\nimport { RLottieColor } from \"../../lib/rlottie/rlottiePlayer\";\nimport rootScope from \"../../lib/rootScope\";\nimport ButtonIcon from \"../buttonIcon\";\nimport GroupCallMicrophoneIcon from \"./microphoneIcon\";\nimport GroupCallParticipantsElement from \"./participants\";\nimport GroupCallParticipantsVideoElement from \"./participantVideos\";\nimport PopupPeer from \"../popups/peer\";\nimport GroupCallDescriptionElement from \"./description\";\nimport GroupCallTitleElement from \"./title\";\nimport { addFullScreenListener, cancelFullScreen, isFullScreen, requestFullScreen } from \"../../helpers/dom/fullScreen\";\nimport Scrollable from \"../scrollable\";\nimport { MovableState } from \"../movableElement\";\nimport animationIntersector from \"../animationIntersector\";\nimport { IS_APPLE_MOBILE } from \"../../environment/userAgent\";\nimport throttle from \"../../helpers/schedulers/throttle\";\nimport IS_SCREEN_SHARING_SUPPORTED from \"../../environment/screenSharingSupport\";\nimport GroupCallInstance from \"../../lib/calls/groupCallInstance\";\nimport makeButton from \"../call/button\";\nimport MovablePanel from \"../../helpers/movablePanel\";\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\nimport safeAssign from \"../../helpers/object/safeAssign\";\nimport toggleClassName from \"../../helpers/toggleClassName\";\n\nexport enum GROUP_CALL_PARTICIPANT_MUTED_STATE {\n UNMUTED,\n MUTED,\n MUTED_FOR_ME,\n MUTED_BY_ADMIN,\n HAND\n}\n\nexport type GROUP_CALL_PARTICIPANT_CLEARED_MUTED_STATE = Exclude<GROUP_CALL_PARTICIPANT_MUTED_STATE, GROUP_CALL_PARTICIPANT_MUTED_STATE.MUTED_BY_ADMIN | GROUP_CALL_PARTICIPANT_MUTED_STATE.MUTED_FOR_ME>;\n\nexport function getGroupCallParticipantMutedState(participant: GroupCallParticipant) {\n const states = GROUP_CALL_PARTICIPANT_MUTED_STATE;\n if(participant.pFlags.muted_by_you) {\n return states.MUTED_FOR_ME;\n } else if(participant.raise_hand_rating !== undefined) {\n return states.HAND;\n } else if(participant.pFlags.muted) {\n return participant.pFlags.can_self_unmute ? states.MUTED : states.MUTED_BY_ADMIN;\n } else {\n return states.UNMUTED;\n }\n}\n\nexport function clearMutedStateModifier(state: GROUP_CALL_PARTICIPANT_MUTED_STATE): GROUP_CALL_PARTICIPANT_CLEARED_MUTED_STATE {\n const states = GROUP_CALL_PARTICIPANT_MUTED_STATE;\n switch(state) {\n case states.MUTED_BY_ADMIN:\n case states.MUTED_FOR_ME:\n return states.MUTED;\n default:\n return state;\n }\n}\n\nexport function getColorByMutedState(state: GROUP_CALL_PARTICIPANT_MUTED_STATE) {\n const states = GROUP_CALL_PARTICIPANT_MUTED_STATE;\n let color: RLottieColor, colorStr: 'blue' | 'green' | 'secondary' | 'red';\n switch(state) {\n case states.HAND:\n colorStr = 'blue';\n break;\n case states.MUTED:\n case states.MUTED_FOR_ME:\n case states.MUTED_BY_ADMIN:\n colorStr = state === states.MUTED ? 'secondary' : 'red';\n break;\n case states.UNMUTED:\n colorStr = 'green';\n break;\n }\n\n const propertyValue = customProperties.getProperty('gc-' + colorStr + '-text-color');\n color = hexToRgb(propertyValue);\n\n return color;\n}\n\nexport enum GROUP_CALL_MICROPHONE_BUTTON_STATE {\n HAND,\n MUTED,\n UNMUTED,\n}\n\nexport function getGroupCallMicrophoneButtonState(groupCall: GroupCall.groupCall, participant: GroupCallParticipant) {\n const states = GROUP_CALL_MICROPHONE_BUTTON_STATE;\n if(!participant.pFlags.can_self_unmute) {\n return states.HAND;\n } else if(participant.pFlags.muted) {\n return states.MUTED\n } else {\n return states.UNMUTED;\n }\n}\n\nlet previousState: MovableState = {\n width: 420,\n height: 640\n};\n\nconst className = 'group-call';\n\nexport default class PopupGroupCall extends PopupElement {\n private appGroupCallsManager: AppGroupCallsManager;\n private appPeersManager: AppPeersManager;\n private appChatsManager: AppChatsManager;\n private instance: GroupCallInstance;\n private groupCallTitle: GroupCallTitleElement;\n private groupCallDescription: GroupCallDescriptionElement;\n private groupCallBodyHeaderDescription: GroupCallDescriptionElement;\n private groupCallParticipants: GroupCallParticipantsElement;\n private groupCallParticipantsVideo: GroupCallParticipantsVideoElement;\n private groupCallMicrophoneIcon: GroupCallMicrophoneIcon;\n private videosCount: number;\n private btnFullScreen: HTMLButtonElement;\n private btnExitFullScreen: HTMLButtonElement;\n private btnInvite: HTMLButtonElement;\n private btnShowColumn: HTMLButtonElement;\n private movablePanel: MovablePanel;\n private buttonsContainer: HTMLDivElement;\n private btnFullScreen2: HTMLButtonElement;\n private btnVideo: HTMLDivElement;\n private btnScreen: HTMLDivElement;\n\n constructor(options: {\n appGroupCallsManager: AppGroupCallsManager,\n appPeersManager: AppPeersManager,\n appChatsManager: AppChatsManager,\n }) {\n super('popup-group-call', undefined, {\n body: true,\n withoutOverlay: true,\n closable: true\n });\n\n safeAssign(this, options);\n\n this.videosCount = 0;\n this.container.classList.add(className, 'night');\n\n const instance = this.instance = this.appGroupCallsManager.groupCall;\n const {listenerSetter} = this;\n\n if(!IS_APPLE_MOBILE) {\n const btnFullScreen = this.btnFullScreen = ButtonIcon('fullscreen');\n const btnFullScreen2 = this.btnFullScreen2 = ButtonIcon('fullscreen ' + className + '-cfs');\n const btnExitFullScreen = this.btnExitFullScreen = ButtonIcon('smallscreen');\n \n attachClickEvent(btnFullScreen, this.onFullScreenClick, {listenerSetter});\n attachClickEvent(btnFullScreen2, this.onFullScreenClick, {listenerSetter});\n \n attachClickEvent(btnExitFullScreen, () => {\n cancelFullScreen();\n }, {listenerSetter});\n \n addFullScreenListener(this.container, this.onFullScreenChange, listenerSetter);\n }\n\n const btnInvite = this.btnInvite = ButtonIcon('adduser');\n const btnShowColumn = this.btnShowColumn = ButtonIcon('rightpanel ' + className + '-only-big');\n\n attachClickEvent(btnShowColumn, this.toggleRightColumn, {listenerSetter});\n\n const headerInfo = document.createElement('div');\n headerInfo.classList.add(className + '-header-info');\n\n this.title.classList.add(className + '-header-title');\n\n const subtitle = document.createElement('div');\n subtitle.classList.add(className + '-header-subtitle');\n\n headerInfo.append(this.title, subtitle);\n\n this.header.classList.add(className + '-header');\n this.header.append(...[this.btnExitFullScreen, headerInfo/* , btnInvite */, this.btnFullScreen, btnShowColumn].filter(Boolean));\n\n const newHeader = this.header.cloneNode(false) as HTMLElement;\n const newHeaderInfo = headerInfo.cloneNode(false) as HTMLElement;\n const newHeaderTitle = this.title.cloneNode(false) as HTMLElement;\n\n newHeaderInfo.append(newHeaderTitle);\n\n const btnHideColumn = ButtonIcon('rightpanel');\n newHeader.append(...[btnHideColumn, newHeaderInfo, this.btnFullScreen2].filter(Boolean));\n\n attachClickEvent(btnHideColumn, this.toggleRightColumn, {listenerSetter});\n\n this.body.prepend(newHeader);\n\n const videosScrollable = new Scrollable(undefined);\n videosScrollable.container.classList.add('group-call-big-video-container');\n this.container.append(videosScrollable.container);\n\n this.groupCallTitle = new GroupCallTitleElement(this.title);\n this.groupCallDescription = new GroupCallDescriptionElement(subtitle);\n this.groupCallBodyHeaderDescription = new GroupCallDescriptionElement(newHeaderTitle);\n this.constructButtons();\n\n this.groupCallParticipantsVideo = new GroupCallParticipantsVideoElement({\n appendTo: videosScrollable.container,\n instance,\n listenerSetter,\n displayPinned: true,\n onLengthChange: (length) => {\n this.videosCount = length;\n this.toggleBigLayout();\n },\n ...options\n });\n this.groupCallParticipants = new GroupCallParticipantsElement({\n appendTo: this.body,\n instance,\n listenerSetter,\n ...options\n });\n\n this.movablePanel = new MovablePanel({\n listenerSetter,\n movableOptions: {\n minWidth: 400,\n minHeight: 480,\n element: this.element,\n verifyTouchTarget: (e) => {\n const target = e.target;\n if(findUpClassName(target, 'chatlist') || \n findUpClassName(target, 'group-call-button') || \n findUpClassName(target, 'btn-icon') ||\n findUpClassName(target, 'group-call-participants-video-container') ||\n isFullScreen()) {\n return false;\n }\n\n return true;\n }\n },\n onResize: () => this.toggleBigLayout(),\n previousState\n });\n\n listenerSetter.add(instance)('state', () => {\n this.updateInstance();\n });\n\n listenerSetter.add(rootScope)('group_call_update', (groupCall) => {\n if(this.instance?.id === groupCall.id) {\n this.updateInstance();\n }\n });\n\n listenerSetter.add(instance)('pinned', () => {\n this.setHasPinned();\n });\n\n listenerSetter.add(this.groupCallParticipantsVideo)('toggleControls', this.onToggleControls);\n\n this.addEventListener('close', () => {\n const {movablePanel} = this;\n previousState = movablePanel.state;\n\n this.groupCallParticipantsVideo.destroy();\n this.groupCallParticipants.destroy();\n this.groupCallMicrophoneIcon.destroy();\n\n movablePanel.destroy();\n });\n\n this.toggleRightColumn();\n this.onFullScreenChange();\n\n this.updateInstance();\n }\n\n private constructButtons() {\n const buttons = this.buttonsContainer = document.createElement('div');\n buttons.classList.add(className + '-buttons');\n\n const _makeButton = makeButton.bind(null, className, this.listenerSetter);\n\n const btnVideo = this.btnVideo = _makeButton({\n // text: 'VoiceChat.Video.Stream.Video',\n callback: this.onVideoClick,\n icon: 'videocamera_filled'\n });\n\n const btnScreen = this.btnScreen = _makeButton({\n // text: 'VoiceChat.Video.Stream.Screencast',\n callback: this.onScreenClick,\n icon: 'sharescreen_filled'\n });\n\n btnScreen.classList.toggle('hide', !IS_SCREEN_SHARING_SUPPORTED);\n\n const btnMute = _makeButton({\n noRipple: true,\n callback: throttle(this.onMuteClick, 600, true)\n });\n btnMute.classList.add(className + '-microphone-button');\n\n const microphoneIcon = this.groupCallMicrophoneIcon = new GroupCallMicrophoneIcon();\n btnMute.append(microphoneIcon.container);\n\n const btnMore = _makeButton({\n // text: 'VoiceChat.Video.Stream.More'\n icon: 'settings_filled'\n });\n\n btnMore.classList.add('btn-disabled');\n btnMore.classList.toggle('hide', !IS_SCREEN_SHARING_SUPPORTED);\n\n const btnLeave = _makeButton({\n // text: 'VoiceChat.Leave',\n isDanger: true,\n callback: this.onLeaveClick,\n icon: 'close'\n });\n\n buttons.append(btnVideo, btnScreen, btnMute, btnMore, btnLeave);\n\n this.container.append(buttons);\n }\n\n private onFullScreenClick = () => {\n requestFullScreen(this.container);\n };\n\n private onToggleControls = (show: boolean) => {\n this.container.classList.toggle('show-controls', show);\n this.buttonsContainer.classList.toggle('show-controls', show);\n };\n\n private toggleDisability = toggleClassName.bind(null, 'btn-disabled');\n\n private onVideoClick = () => {\n const toggle = this.toggleDisability([this.btnVideo], true);\n this.instance.toggleVideoSharing().finally(() => {\n toggle();\n });\n };\n\n private onScreenClick = () => {\n const toggle = this.toggleDisability([this.btnScreen], true);\n this.instance.toggleScreenSharing().finally(() => {\n toggle();\n });\n };\n\n private onMuteClick = () => {\n const participant = this.instance.participant;\n if(!participant.pFlags.can_self_unmute) {\n if(participant.raise_hand_rating === undefined) {\n this.instance.changeRaiseHand(true);\n }\n } else {\n this.instance.toggleMuted();\n }\n };\n \n private onLeaveClick = () => {\n const hangUp = (discard: boolean) => {\n this.instance.hangUp(discard);\n };\n\n if(this.appChatsManager.hasRights(this.instance.chatId, 'manage_call')) {\n new PopupPeer('popup-end-video-chat', {\n titleLangKey: 'VoiceChat.End.Title',\n descriptionLangKey: 'VoiceChat.End.Text',\n checkboxes: [{\n text: 'VoiceChat.End.Third'\n }],\n buttons: [{\n langKey: 'VoiceChat.End.OK',\n callback: (checkboxes) => {\n hangUp(!!checkboxes.size);\n },\n isDanger: true,\n }]\n }).show();\n } else {\n hangUp(false);\n }\n };\n\n public getContainer() {\n return this.container;\n }\n\n private onFullScreenChange = () => {\n this.toggleBigLayout();\n const isFull = isFullScreen();\n\n const {btnFullScreen, btnExitFullScreen} = this;\n\n const wasFullScreen = this.container.classList.contains('is-full-screen');\n this.container.classList.toggle('is-full-screen', isFull);\n btnFullScreen && btnFullScreen.classList.toggle('hide', isFull);\n btnExitFullScreen && btnExitFullScreen.classList.toggle('hide', !isFull);\n this.btnClose.classList.toggle('hide', isFull);\n\n if(isFull !== wasFullScreen) {\n animationIntersector.checkAnimations(isFull);\n\n rootScope.setThemeColor(isFull ? '#000000' : undefined);\n }\n };\n\n private toggleBigLayout = () => {\n const isFull = isFullScreen();\n const movable = this.movablePanel?.movable;\n const isBig = (isFull || !!(movable && movable.width >= 680)) && !!this.videosCount;\n\n /* if(!isBig && isFull) {\n cancelFullScreen();\n return;\n } */\n\n const wasBig = this.container.classList.contains('is-big-layout');\n let buttons: HTMLElement[];\n if(isBig && !wasBig) { // fix buttons transition to 0 opacity\n buttons = Array.from(this.buttonsContainer.children) as HTMLElement[];\n buttons.forEach(element => {\n element.style.opacity = '0';\n });\n\n void this.buttonsContainer.offsetLeft;\n }\n\n this.container.classList.toggle('is-big-layout', isBig);\n this.btnInvite.classList.toggle('hide', isBig);\n this.btnShowColumn.classList.toggle('hide', !isBig);\n\n if(buttons) {\n // window.requestAnimationFrame(() => {\n buttons.forEach(element => {\n element.style.opacity = '';\n });\n // });\n }\n };\n\n private toggleRightColumn = () => {\n this.container.classList.toggle('is-right-column-shown');\n };\n\n private setHasPinned() {\n this.container.classList.toggle('has-pinned', !!this.instance.pinnedSource);\n }\n\n private updateInstance() {\n if(this.instance.state === GROUP_CALL_STATE.CLOSED) {\n if(this.container.classList.contains('is-full-screen')) {\n cancelFullScreen();\n }\n\n this.hide();\n return;\n }\n\n const {participant, groupCall} = this.instance;\n if(!participant) {\n return;\n }\n\n this.setTitle();\n this.setDescription();\n this.setHasPinned();\n\n const microphoneButtonState = getGroupCallMicrophoneButtonState(groupCall as any, participant);\n this.container.dataset.micState = microphoneButtonState === GROUP_CALL_MICROPHONE_BUTTON_STATE.HAND ? 'hand' : (microphoneButtonState === GROUP_CALL_MICROPHONE_BUTTON_STATE.MUTED ? 'muted' : 'unmuted');\n this.groupCallMicrophoneIcon.setState(microphoneButtonState);\n }\n\n private setTitle() {\n this.groupCallTitle.update(this.instance);\n }\n\n private setDescription() {\n this.groupCallDescription.update(this.instance);\n this.groupCallBodyHeaderDescription.update(this.instance);\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport replaceContent from \"../../helpers/dom/replaceContent\";\nimport setInnerHTML from \"../../helpers/dom/setInnerHTML\";\nimport { GroupCallParticipant } from \"../../layer\";\nimport { i18n } from \"../../lib/langPack\";\nimport RichTextProcessor from \"../../lib/richtextprocessor\";\nimport { GROUP_CALL_PARTICIPANT_MUTED_STATE } from \".\";\nimport { GroupCallParticipantVideoType } from \"./participantVideo\";\n\nconst className = 'group-call-participant-status';\nexport default class GroupCallParticipantStatusElement {\n public container: HTMLElement;\n\n constructor(private withIcons: GroupCallParticipantVideoType[]) {\n this.container = document.createElement('div');\n this.container.classList.add(className + '-container');\n }\n\n public setState(state: GROUP_CALL_PARTICIPANT_MUTED_STATE, participant: GroupCallParticipant) {\n const states = GROUP_CALL_PARTICIPANT_MUTED_STATE;\n const icons = this.withIcons.filter(type => !!participant[type]).map(type => {\n const iconClassName = `tgico-${type === 'presentation' ? 'listscreenshare' : 'videocamera_filled'}`;\n const i = document.createElement('i');\n i.classList.add(className + '-icon', className + '-icon-' + type, iconClassName);\n return i;\n });\n\n let element2: HTMLElement, actionClassName: string;\n if(state === states.MUTED_FOR_ME) {\n element2 = i18n('VoiceChat.Status.MutedForYou');\n actionClassName = 'is-muted';\n } else if(state === states.UNMUTED) {\n element2 = i18n('VoiceChat.Status.Speaking');\n actionClassName = 'is-speaking';\n } else if(state === states.HAND) {\n element2 = i18n('VoiceChat.Status.WantsSpeak');\n actionClassName = 'is-waiting';\n } else if(participant.about && !icons.length) {\n setInnerHTML(this.container, RichTextProcessor.wrapEmojiText(participant.about));\n return;\n } else {\n element2 = i18n('VoiceChat.Status.Listening');\n actionClassName = 'is-listening';\n }\n\n const span = document.createElement('span');\n span.classList.add(className, actionClassName);\n span.append(...icons, element2);\n \n replaceContent(this.container, span);\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport positionElementByIndex from \"../../helpers/dom/positionElementByIndex\";\nimport replaceContent from \"../../helpers/dom/replaceContent\";\nimport { fastRaf } from \"../../helpers/schedulers\";\nimport SortedList, { SortedElementBase } from \"../../helpers/sortedList\";\nimport { GroupCallParticipant } from \"../../layer\";\nimport appDialogsManager, { DialogDom, AppDialogsManager } from \"../../lib/appManagers/appDialogsManager\";\nimport { LazyLoadQueueIntersector } from \"../lazyLoadQueue\";\nimport { getGroupCallParticipantMutedState } from \".\";\nimport GroupCallParticipantMutedIcon from \"./participantMutedIcon\";\nimport GroupCallParticipantStatusElement from \"./participantStatus\";\nimport type GroupCallInstance from \"../../lib/calls/groupCallInstance\";\n\ninterface SortedParticipant extends SortedElementBase {\n dom: DialogDom,\n participant: GroupCallParticipant,\n mutedIcon: GroupCallParticipantMutedIcon,\n status: GroupCallParticipantStatusElement\n}\n\nexport default class GroupCallParticipantsList extends SortedList<SortedParticipant> {\n public list: HTMLUListElement;\n \n protected lazyLoadQueue: LazyLoadQueueIntersector;\n protected avatarSize = 54;\n protected rippleEnabled = true;\n protected autonomous = true;\n protected createChatListOptions: Parameters<AppDialogsManager['createChatList']>[0] = {/* new: true, */dialogSize: 72};\n\n constructor(private instance: GroupCallInstance) {\n super({\n getIndex: (element) => element.participant.date,\n onDelete: (element) => {\n element.dom.listEl.remove();\n this.onElementDestroy(element);\n },\n onUpdate: (element) => {\n const {participant} = element;\n\n const state = getGroupCallParticipantMutedState(participant);\n\n element.mutedIcon.setState(state);\n element.status.setState(state, participant);\n },\n onSort: (element, idx) => {\n positionElementByIndex(element.dom.listEl, this.list, idx);\n },\n onElementCreate: (base) => {\n const {dom} = appDialogsManager.addDialogNew({\n dialog: base.id,\n container: false,\n drawStatus: false,\n avatarSize: this.avatarSize,\n autonomous: this.autonomous,\n meAsSaved: false,\n rippleEnabled: this.rippleEnabled,\n lazyLoadQueue: this.lazyLoadQueue\n });\n\n const className = 'group-call-participant';\n dom.listEl.classList.add(className);\n\n const participant = instance.participants.get(base.id);\n const mutedState = getGroupCallParticipantMutedState(participant);\n\n const mutedIcon = new GroupCallParticipantMutedIcon(true);\n const status = new GroupCallParticipantStatusElement(['presentation', 'video']);\n \n mutedIcon.setState(mutedState);\n status.setState(mutedState, participant);\n\n replaceContent(dom.lastMessageSpan, status.container);\n dom.listEl.append(mutedIcon.container);\n\n (base as SortedParticipant).dom = dom;\n (base as SortedParticipant).participant = participant;\n (base as SortedParticipant).mutedIcon = mutedIcon;\n (base as SortedParticipant).status = status;\n\n return base as SortedParticipant;\n },\n updateElementWith: fastRaf\n });\n\n this.list = appDialogsManager.createChatList(this.createChatListOptions);\n }\n\n public destroy() {\n this.elements.forEach((element) => {\n this.onElementDestroy(element);\n });\n }\n\n protected onElementDestroy(element: SortedParticipant) {\n element.mutedIcon.destroy();\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { IS_TOUCH_SUPPORTED } from \"../../environment/touchSupport\";\nimport EventListenerBase from \"../eventListenerBase\";\nimport ListenerSetter from \"../listenerSetter\";\nimport safeAssign from \"../object/safeAssign\";\nimport findUpClassName from \"./findUpClassName\";\n\nexport default class ControlsHover extends EventListenerBase<{\n toggleControls: (show: boolean) => void\n}> {\n protected hideControlsTimeout: number;\n protected controlsLocked: boolean;\n\n protected canHideControls: () => boolean;\n protected element: HTMLElement;\n protected listenerSetter: ListenerSetter;\n protected showOnLeaveToClassName: string;\n protected ignoreClickClassName: string;\n\n constructor() {\n super(false);\n this.hideControlsTimeout = 0;\n }\n \n public setup(options: {\n element: HTMLElement, \n listenerSetter: ListenerSetter, \n canHideControls?: () => boolean,\n showOnLeaveToClassName?: string,\n ignoreClickClassName?: string\n }) {\n safeAssign(this, options);\n\n const {listenerSetter, element} = this;\n\n if(IS_TOUCH_SUPPORTED) {\n listenerSetter.add(element)('click', (e) => {\n if(this.ignoreClickClassName && findUpClassName(e.target, this.ignoreClickClassName)) {\n return;\n }\n\n this.toggleControls();\n });\n\n /* listenerSetter.add(player)('touchstart', () => {\n showControls(false);\n });\n\n listenerSetter.add(player)('touchend', () => {\n if(player.classList.contains('is-playing')) {\n showControls();\n }\n }); */\n } else {\n listenerSetter.add(element)('mousemove', () => {\n this.showControls();\n });\n\n listenerSetter.add(element)('mouseenter', () => {\n this.showControls(false);\n });\n\n listenerSetter.add(element)('mouseleave', (e) => {\n if(e.relatedTarget && this.showOnLeaveToClassName && findUpClassName(e.relatedTarget, this.showOnLeaveToClassName)) {\n this.showControls(false);\n return;\n }\n \n this.hideControls();\n });\n }\n }\n\n public hideControls = (setHideTimeout = false) => {\n if(setHideTimeout) {\n if(!this.hideControlsTimeout) {\n this.hideControlsTimeout = window.setTimeout(this.hideControls, 3e3);\n }\n\n return;\n }\n \n clearTimeout(this.hideControlsTimeout);\n this.hideControlsTimeout = 0;\n\n const isShown = this.element.classList.contains('show-controls');\n if(this.controlsLocked !== false) {\n if((this.canHideControls ? !this.canHideControls() : false) || !isShown || this.controlsLocked) {\n return;\n }\n } else if(!isShown) {\n return;\n }\n \n this.dispatchEvent('toggleControls', false);\n this.element.classList.remove('show-controls');\n };\n \n public showControls = (setHideTimeout = true) => {\n if(this.hideControlsTimeout) {\n clearTimeout(this.hideControlsTimeout);\n this.hideControlsTimeout = 0;\n } else if(!this.element.classList.contains('show-controls') && this.controlsLocked !== false) {\n this.dispatchEvent('toggleControls', true);\n this.element.classList.add('show-controls');\n }\n\n if(!setHideTimeout || this.controlsLocked) {\n return;\n }\n\n this.hideControlsTimeout = window.setTimeout(this.hideControls, 3e3);\n };\n\n public toggleControls = (show?: boolean) => {\n const isShown = this.element.classList.contains('show-controls');\n\n if(show === undefined) {\n if(isShown) this.hideControls();\n else this.showControls();\n } else if(show === isShown) return;\n else if(show === false) this.hideControls();\n else this.showControls();\n };\n\n public lockControls(visible: boolean) {\n this.controlsLocked = visible;\n\n this.element.classList.toggle('disable-hover', visible === false);\n this.toggleControls(visible);\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { animate } from \"../../helpers/animation\";\n\nexport default function callVideoCanvasBlur(video: HTMLVideoElement) {\n const canvas = document.createElement('canvas');\n canvas.classList.add('call-video-blur');\n const size = 16;\n canvas.width = size;\n canvas.height = size;\n\n const ctx = canvas.getContext('2d');\n ctx.filter = 'blur(2px)';\n const renderFrame = () => {\n ctx.drawImage(video, 0, 0, video.videoWidth, video.videoHeight, 0, 0, canvas.width, canvas.height);\n };\n\n animate(() => {\n renderFrame();\n return canvas.isConnected;\n });\n\n renderFrame();\n\n return canvas;\n}","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { GroupCallParticipant } from \"../../layer\";\nimport type { GroupCallOutputSource } from \"../../lib/appManagers/appGroupCallsManager\";\nimport type { AppPeersManager } from \"../../lib/appManagers/appPeersManager\";\nimport { i18n } from \"../../lib/langPack\";\nimport PeerTitle from \"../peerTitle\";\nimport { getGroupCallParticipantMutedState } from \".\";\nimport GroupCallParticipantMutedIcon from \"./participantMutedIcon\";\nimport GroupCallParticipantStatusElement from \"./participantStatus\";\nimport GroupCallInstance from \"../../lib/calls/groupCallInstance\";\nimport callVideoCanvasBlur from \"../call/videoCanvasBlur\";\n\nconst className = 'group-call-participant-video';\n\nexport type GroupCallParticipantVideoType = 'video' | 'presentation';\nexport default class GroupCallParticipantVideoElement {\n public container: HTMLElement;\n private peerTitle: PeerTitle;\n private subtitle: HTMLElement;\n private info: HTMLElement;\n private left: HTMLElement;\n private right: HTMLElement;\n private header: HTMLElement;\n private groupCallParticipantMutedIcon: GroupCallParticipantMutedIcon;\n private groupCallParticipantStatus: GroupCallParticipantStatusElement;\n\n constructor(private appPeersManager: AppPeersManager, private instance: GroupCallInstance, public source: GroupCallOutputSource) {\n this.container = document.createElement('div');\n this.container.classList.add(className + '-container');\n\n this.info = document.createElement('div');\n this.info.classList.add(className + '-info');\n\n this.left = document.createElement('div');\n this.left.classList.add(className + '-info-left');\n\n this.right = document.createElement('div');\n this.right.classList.add(className + '-info-right');\n\n this.info.append(this.left, this.right);\n \n this.container.append(this.info);\n }\n\n public setPinned(value: boolean) {\n if(!value) {\n if(this.header) {\n this.header.remove();\n this.header = undefined;\n }\n\n return;\n } else if(this.header) {\n return;\n }\n \n // if(!this.header) {\n this.header = document.createElement('div');\n this.header.classList.add(className + '-header');\n \n const icon = document.createElement('i');\n icon.classList.add('group-call-pin-icon', 'tgico-pin');\n this.header.append(icon);\n \n this.container.append(this.header);\n // }\n \n // this.container.classList.toggle('is-pinned', value);\n }\n\n public setParticipant(participant: GroupCallParticipant, type: GroupCallParticipantVideoType, video: HTMLVideoElement) {\n let peerTitleElement: HTMLElement;\n if(participant.pFlags.self) {\n peerTitleElement = i18n('VoiceChat.Status.You');\n peerTitleElement.classList.add('peer-title');\n } else {\n this.peerTitle = new PeerTitle({\n peerId: this.appPeersManager.getPeerId(participant.peer)\n });\n\n peerTitleElement = this.peerTitle.element;\n }\n\n this.groupCallParticipantMutedIcon = new GroupCallParticipantMutedIcon(false);\n this.groupCallParticipantStatus = new GroupCallParticipantStatusElement([type]);\n\n this.left.append(peerTitleElement, this.groupCallParticipantStatus.container);\n\n this.right.append(this.groupCallParticipantMutedIcon.container);\n\n video.classList.add(className, 'call-video');\n\n if(video.paused) {\n video.play();\n }\n\n const canvas = callVideoCanvasBlur(video);\n canvas.classList.add(className + '-blur');\n \n this.container.prepend(canvas, video);\n\n this.updateParticipant(participant);\n }\n\n public updateParticipant(participant: GroupCallParticipant) {\n const state = getGroupCallParticipantMutedState(participant);\n\n this.groupCallParticipantMutedIcon.setState(state);\n this.groupCallParticipantStatus.setState(state, participant);\n }\n\n public destroy() {\n this.groupCallParticipantMutedIcon.destroy();\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\nimport ControlsHover from \"../../helpers/dom/controlsHover\";\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\nimport ListenerSetter from \"../../helpers/listenerSetter\";\nimport safeAssign from \"../../helpers/object/safeAssign\";\nimport { GroupCallParticipant } from \"../../layer\";\nimport { AppGroupCallsManager, GroupCallOutputSource } from \"../../lib/appManagers/appGroupCallsManager\";\nimport type { AppPeersManager } from \"../../lib/appManagers/appPeersManager\";\nimport GroupCallInstance from \"../../lib/calls/groupCallInstance\";\nimport rootScope from \"../../lib/rootScope\";\nimport GroupCallParticipantVideoElement, { GroupCallParticipantVideoType } from \"./participantVideo\";\n\nexport default class GroupCallParticipantsVideoElement extends ControlsHover {\n private container: HTMLDivElement;\n private instance: GroupCallInstance;\n private appGroupCallsManager: AppGroupCallsManager;\n private appPeersManager: AppPeersManager;\n private participantsElements: Map<PeerId, Map<GroupCallParticipantVideoType, GroupCallParticipantVideoElement>>;\n private displayPinned: boolean;\n private containers: Map<HTMLElement, GroupCallParticipantVideoElement>;\n private onLengthChange: (length: number) => void;\n\n constructor(options: {\n appendTo: HTMLElement,\n appGroupCallsManager: AppGroupCallsManager,\n appPeersManager: AppPeersManager,\n instance: GroupCallInstance,\n listenerSetter: ListenerSetter,\n displayPinned: boolean,\n onLengthChange?: GroupCallParticipantsVideoElement['onLengthChange']\n }) {\n super();\n safeAssign(this, options);\n\n const className = 'group-call-participants-video';\n const container = this.container = document.createElement('div');\n this.container.classList.add(className + '-container');\n \n options.appendTo.append(container);\n\n this.participantsElements = new Map();\n this.containers = new Map();\n\n const {listenerSetter} = this;\n\n listenerSetter.add(rootScope)('group_call_participant', ({groupCallId, participant}) => {\n if(this.instance.id === groupCallId) {\n this.updateParticipant(participant);\n }\n });\n\n listenerSetter.add(this.instance)('pinned', (source) => {\n this.participantsElements.forEach((map) => {\n map.forEach((element) => {\n this.setElementDisplay(element, source);\n });\n });\n });\n\n attachClickEvent(this.container, (e) => {\n const container = findUpClassName(e.target, 'group-call-participant-video-container');\n if(!container) {\n return;\n }\n\n const element = this.containers.get(container);\n if(this.instance.pinnedSource === element.source) {\n this.instance.unpinAll();\n return; \n }\n \n this.instance.pinSource(element.source);\n }, {listenerSetter});\n\n this.setInstance(this.instance);\n\n this.setup({\n element: container,\n listenerSetter: listenerSetter,\n showOnLeaveToClassName: 'group-call-buttons'\n });\n }\n\n private shouldDisplayElement(element: GroupCallParticipantVideoElement, pinnedSource: GroupCallOutputSource) {\n return this.displayPinned ? !pinnedSource || element.source === pinnedSource : pinnedSource && element.source !== pinnedSource;\n }\n\n private setElementDisplay(element: GroupCallParticipantVideoElement, pinnedSource: GroupCallOutputSource) {\n const shouldDisplay = this.shouldDisplayElement(element, pinnedSource);\n element.container.classList.toggle('video-hidden', !shouldDisplay);\n\n const isPinned = element.source === pinnedSource;\n element.setPinned(isPinned);\n }\n\n private updateParticipant(participant: GroupCallParticipant) {\n const peerId = this.appPeersManager.getPeerId(participant.peer);\n const types: GroupCallParticipantVideoType[] = ['video', 'presentation'];\n const hasAnyVideo = types.some(type => !!participant[type]);\n let participantElements = this.participantsElements.get(peerId);\n if(!hasAnyVideo && !participantElements) {\n return;\n }\n\n if(!participantElements) {\n this.participantsElements.set(peerId, participantElements = new Map());\n }\n\n types.forEach(type => {\n let element = participantElements.get(type);\n const participantVideo = participant[type];\n if(!!participantVideo === !!element) {\n if(element) {\n element.updateParticipant(participant);\n }\n\n return;\n }\n\n if(participantVideo) {\n const result = this.instance.getVideoElementFromParticipantByType(participant, type);\n if(!result) {\n return;\n }\n\n const {video, source} = result;\n\n element = new GroupCallParticipantVideoElement(this.appPeersManager, this.instance, source);\n\n this.containers.set(element.container, element);\n\n this.setElementDisplay(element, this.instance.pinnedSource);\n participantElements.set(type, element);\n element.setParticipant(participant, type, video);\n \n this.container.prepend(element.container);\n } else {\n participantElements.delete(type);\n element.container.remove();\n \n if(!participantElements.size) {\n this.participantsElements.delete(peerId);\n this.containers.delete(element.container);\n element.destroy();\n }\n }\n\n this._onLengthChange();\n });\n }\n\n private _onLengthChange() {\n const length = this.container.childElementCount;\n this.container.dataset.length = '' + length;\n this.container.dataset.layout = length <= 2 ? '1' : (length === 3 ? '3' : '4');\n\n this.onLengthChange && this.onLengthChange(length);\n }\n\n public setInstance(instance: GroupCallInstance) {\n instance.participants.forEach((participant) => {\n this.updateParticipant(participant);\n });\n }\n\n public destroy() {\n this.containers.forEach((element) => {\n element.destroy();\n });\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport PopupGroupCall from \".\";\nimport cancelEvent from \"../../helpers/dom/cancelEvent\";\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\nimport { addFullScreenListener, isFullScreen } from \"../../helpers/dom/fullScreen\";\nimport ListenerSetter from \"../../helpers/listenerSetter\";\nimport noop from \"../../helpers/noop\";\nimport safeAssign from \"../../helpers/object/safeAssign\";\nimport ScrollableLoader from \"../../helpers/scrollableLoader\";\nimport { GroupCallParticipant } from \"../../layer\";\nimport type { AppChatsManager } from \"../../lib/appManagers/appChatsManager\";\nimport type { AppGroupCallsManager } from \"../../lib/appManagers/appGroupCallsManager\";\nimport type { AppPeersManager } from \"../../lib/appManagers/appPeersManager\";\nimport GroupCallInstance from \"../../lib/calls/groupCallInstance\";\nimport rootScope from \"../../lib/rootScope\";\nimport ButtonMenu, { ButtonMenuItemOptions } from \"../buttonMenu\";\nimport confirmationPopup from \"../confirmationPopup\";\nimport { attachContextMenuListener, closeBtnMenu, openBtnMenu, positionMenu } from \"../misc\";\nimport PeerTitle from \"../peerTitle\";\nimport PopupElement from \"../popups\";\nimport Scrollable from \"../scrollable\";\nimport GroupCallParticipantsList from \"./participantsList\";\nimport GroupCallParticipantsVideoElement from \"./participantVideos\";\n\nexport class GroupCallParticipantContextMenu {\n private buttons: (ButtonMenuItemOptions & {verify: (peerId: PeerId) => boolean})[];\n private element: HTMLDivElement;\n private appChatsManager: AppChatsManager;\n private appPeersManager: AppPeersManager;\n private appGroupCallsManager: AppGroupCallsManager;\n private chatId: ChatId;\n private targetPeerId: PeerId;\n private participant: GroupCallParticipant;\n private instance: GroupCallInstance;\n private canManageCall: boolean;\n \n constructor(options: {\n listenerSetter: ListenerSetter,\n onContextElement: HTMLElement,\n appChatsManager: AppChatsManager,\n appPeersManager: AppPeersManager,\n appGroupCallsManager: AppGroupCallsManager,\n instance: GroupCallInstance,\n }) {\n this.buttons = [{\n icon: 'gc_microphoneoff',\n text: 'VoiceChat.MutePeer',\n verify: () => this.canManageCall && this.participant.pFlags.can_self_unmute,\n onClick: () => this.toggleParticipantMuted(true)\n }, {\n icon: 'gc_microphone',\n text: 'VoiceChat.UnmutePeer',\n verify: () => this.canManageCall && !this.participant.pFlags.can_self_unmute,\n onClick: () => this.toggleParticipantMuted(false)\n }, {\n icon: 'gc_microphoneoff',\n text: 'VoiceChat.MuteForMe',\n verify: () => !this.canManageCall && !this.participant.pFlags.muted_by_you,\n onClick: () => this.toggleParticipantMuted(true)\n }, {\n icon: 'gc_microphone',\n text: 'VoiceChat.UnmuteForMe',\n verify: () => !this.canManageCall && this.participant.pFlags.muted_by_you,\n onClick: () => this.toggleParticipantMuted(false)\n }, {\n icon: 'newprivate',\n text: 'VoiceChat.OpenProfile',\n verify: () => true,\n onClick: this.onOpenProfileClick\n }, {\n icon: 'deleteuser danger',\n text: 'VoiceChat.RemovePeer',\n verify: () => this.appChatsManager.hasRights(this.chatId, 'ban_users'),\n onClick: () => {\n confirmationPopup({\n peerId: this.targetPeerId,\n title: new PeerTitle({peerId: this.targetPeerId}).element,\n descriptionLangKey: this.appChatsManager.isBroadcast(this.chatId) ? 'VoiceChat.RemovePeer.Confirm.Channel' : 'VoiceChat.RemovePeer.Confirm',\n descriptionLangArgs: [new PeerTitle({peerId: this.targetPeerId}).element],\n button: {\n langKey: 'VoiceChat.RemovePeer.Confirm.OK',\n isDanger: true\n }\n }).then(() => {\n this.appChatsManager.kickFromChat(this.chatId, this.targetPeerId);\n }, noop);\n }\n }];\n\n const {listenerSetter} = options;\n this.appChatsManager = options.appChatsManager;\n this.appPeersManager = options.appPeersManager;\n this.appGroupCallsManager = options.appGroupCallsManager;\n this.instance = options.instance;\n this.chatId = this.instance.chatId;\n \n this.element = ButtonMenu(this.buttons, listenerSetter);\n this.element.classList.add('group-call-participant-menu', 'night');\n\n attachContextMenuListener(options.onContextElement, (e: any) => {\n const li = findUpClassName(e.target, 'group-call-participant');\n if(!li) {\n return;\n }\n\n if(this.element.parentElement !== appendTo) {\n appendTo.append(this.element);\n }\n\n const peerId = this.targetPeerId = li.dataset.peerId.toPeerId();\n this.participant = this.instance.getParticipantByPeerId(peerId);\n if(this.participant.pFlags.self) {\n return;\n }\n\n this.canManageCall = this.appChatsManager.hasRights(this.chatId, 'manage_call');\n\n this.buttons.forEach(button => {\n button.element.classList.toggle('hide', !button.verify(peerId));\n });\n \n cancelEvent(e);\n positionMenu((e as TouchEvent).touches ? (e as TouchEvent).touches[0] : e as MouseEvent, this.element, 'right');\n openBtnMenu(this.element);\n }, listenerSetter);\n\n listenerSetter.add(rootScope)('group_call_participant', ({groupCallId, participant}) => {\n if(this.instance.id === groupCallId) {\n const peerId = this.appPeersManager.getPeerId(participant.peer);\n if(this.targetPeerId === peerId) {\n closeBtnMenu();\n }\n }\n });\n\n let appendTo: HTMLElement = document.body;\n addFullScreenListener(document.body, () => {\n const isFull = isFullScreen();\n appendTo = isFull ? (PopupElement.getPopups(PopupGroupCall) as PopupGroupCall[])[0].getContainer(): document.body;\n\n if(!isFull) {\n closeBtnMenu();\n }\n }, listenerSetter);\n }\n\n private onOpenProfileClick = () => {\n const popup = PopupElement.getPopups(PopupGroupCall)[0];\n if(popup) {\n popup.hide();\n }\n\n rootScope.dispatchEvent('history_focus', {\n peerId: this.targetPeerId\n });\n };\n\n private toggleParticipantMuted = (muted: boolean) => {\n this.appGroupCallsManager.editParticipant(this.instance.id, this.participant, {\n muted\n });\n };\n};\n\nexport default class GroupCallParticipantsElement {\n private container: HTMLDivElement;\n private sortedList: GroupCallParticipantsList;\n private instance: GroupCallInstance;\n private appGroupCallsManager: AppGroupCallsManager;\n private appPeersManager: AppPeersManager;\n private listenerSetter: ListenerSetter;\n private groupCallParticipantsVideo: GroupCallParticipantsVideoElement;\n private contextMenu: GroupCallParticipantContextMenu;\n private appChatsManager: AppChatsManager;\n\n constructor(options: {\n appendTo: HTMLElement,\n appGroupCallsManager: AppGroupCallsManager,\n appPeersManager: AppPeersManager,\n appChatsManager: AppChatsManager,\n instance: GroupCallInstance,\n listenerSetter: ListenerSetter\n }) {\n safeAssign(this, options);\n\n const className = 'group-call-participants';\n\n const scrollable = new Scrollable(undefined);\n scrollable.container.classList.add(className + '-scrollable');\n\n const container = this.container = document.createElement('div');\n container.classList.add(className);\n\n // const invite = Button(`btn-primary btn-transparent ${className}-invite`, {icon: 'adduser', text: 'VoiceChat.Invite.InviteMembers'});\n\n const sortedList = this.sortedList = new GroupCallParticipantsList(this.instance);\n \n const {instance, listenerSetter} = this;\n this.contextMenu = new GroupCallParticipantContextMenu({\n ...options,\n onContextElement: sortedList.list,\n listenerSetter,\n instance\n });\n\n this.groupCallParticipantsVideo = new GroupCallParticipantsVideoElement({\n ...options,\n appendTo: scrollable.container,\n displayPinned: false\n });\n\n scrollable.append(/* invite, */sortedList.list);\n container.append(scrollable.container);\n\n options.appendTo.append(container);\n\n listenerSetter.add(rootScope)('group_call_participant', ({groupCallId, participant}) => {\n if(this.instance.id === groupCallId) {\n this.updateParticipant(participant);\n }\n });\n\n const scrollableLoader = new ScrollableLoader({\n scrollable,\n getPromise: () => {\n return this.appGroupCallsManager.getGroupCallParticipants(this.instance.id).then(({participants, isEnd}) => {\n participants.forEach(participant => {\n this.updateParticipant(participant);\n });\n \n return isEnd;\n });\n }\n });\n\n this.setInstance(instance);\n }\n\n private updateParticipant(participant: GroupCallParticipant) {\n const peerId = this.appPeersManager.getPeerId(participant.peer);\n const has = this.sortedList.has(peerId);\n if(participant.pFlags.left) {\n if(has) {\n this.sortedList.delete(peerId);\n }\n\n return;\n }\n\n if(!has) {\n this.sortedList.add(peerId);\n return;\n }\n\n this.sortedList.update(peerId);\n }\n\n public setInstance(instance: GroupCallInstance) {\n // @ts-ignore\n /* const users = appUsersManager.users;\n for(const userId in users) {\n const participant: GroupCallParticipant = {\n _: 'groupCallParticipant',\n date: 0,\n peer: {_: 'peerUser', user_id: userId.toPeerId()},\n pFlags: {\n muted: true\n },\n source: 1\n };\n\n instance.participants.set(userId.toPeerId(), participant);\n this.updateParticipant(participant);\n } */\n instance.participants.forEach((participant) => {\n this.updateParticipant(participant);\n });\n }\n \n public destroy() {\n this.sortedList.destroy();\n this.groupCallParticipantsVideo.destroy();\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { GroupCall } from \"../../layer\";\nimport GroupCallInstance from \"../../lib/calls/groupCallInstance\";\nimport GROUP_CALL_STATE from \"../../lib/calls/groupCallState\";\nimport I18n, { LangPackKey, FormatterArguments } from \"../../lib/langPack\";\n\nexport default class GroupCallDescriptionElement {\n private descriptionIntl: I18n.IntlElement;\n\n constructor(private appendTo: HTMLElement) {\n this.descriptionIntl = new I18n.IntlElement({\n key: 'VoiceChat.Status.Connecting'\n });\n\n this.descriptionIntl.element.classList.add('group-call-description');\n }\n\n public detach() {\n this.descriptionIntl.element.remove();\n }\n\n public update(instance: GroupCallInstance) {\n const {state} = instance;\n\n let key: LangPackKey, args: FormatterArguments;\n if(state === GROUP_CALL_STATE.CONNECTING) {\n key = 'VoiceChat.Status.Connecting';\n } else {\n key = 'VoiceChat.Status.Members';\n args = [(instance.groupCall as GroupCall.groupCall).participants_count];\n }\n\n const {descriptionIntl} = this;\n descriptionIntl.compareAndUpdate({\n key,\n args\n });\n\n if(!this.descriptionIntl.element.parentElement) {\n this.appendTo.append(this.descriptionIntl.element);\n }\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport setInnerHTML from \"../../helpers/dom/setInnerHTML\";\nimport { GroupCall } from \"../../layer\";\nimport GroupCallInstance from \"../../lib/calls/groupCallInstance\";\nimport RichTextProcessor from \"../../lib/richtextprocessor\";\nimport PeerTitle from \"../peerTitle\";\n\nexport default class GroupCallTitleElement {\n private peerTitle: PeerTitle;\n\n constructor(private appendTo: HTMLElement) {\n this.peerTitle = new PeerTitle({peerId: 0});\n }\n\n public update(instance: GroupCallInstance) {\n const {peerTitle, appendTo} = this;\n const groupCall = instance.groupCall as GroupCall.groupCall;\n const peerId = instance.chatId.toPeerId(true);\n if(groupCall.title) {\n setInnerHTML(appendTo, RichTextProcessor.wrapEmojiText(groupCall.title));\n } else {\n if(peerTitle.peerId !== peerId) {\n peerTitle.peerId = peerId;\n peerTitle.update();\n }\n\n if(peerTitle.element.parentElement !== appendTo) {\n appendTo.append(peerTitle.element);\n }\n } \n }\n}\n","const IS_SCREEN_SHARING_SUPPORTED = !!('getDisplayMedia' in (navigator?.mediaDevices || {}));\n\nexport default IS_SCREEN_SHARING_SUPPORTED;\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\nimport ListenerSetter from \"../../helpers/listenerSetter\";\nimport { i18n, LangPackKey } from \"../../lib/langPack\";\nimport ripple from \"../ripple\";\n\nexport default function makeButton(className: string, listenerSetter: ListenerSetter, options: {\n text?: LangPackKey | HTMLElement,\n isDanger?: boolean,\n noRipple?: boolean,\n callback?: () => void,\n icon?: string,\n isConfirm?: boolean,\n}) {\n const _className = className + '-button';\n const buttonDiv = document.createElement('div');\n buttonDiv.classList.add(_className, 'call-button', 'rp-overflow');\n\n if(options.icon) {\n buttonDiv.classList.add('tgico-' + options.icon);\n }\n\n if(!options.noRipple) {\n ripple(buttonDiv);\n }\n\n if(options.isDanger) {\n buttonDiv.classList.add(_className + '-red');\n }\n\n if(options.isConfirm) {\n buttonDiv.classList.add(_className + '-green');\n }\n\n if(options.callback) {\n attachClickEvent(buttonDiv, options.callback, {listenerSetter});\n }\n\n let ret = buttonDiv;\n if(options.text) {\n const div = document.createElement('div');\n div.classList.add(_className + '-container', 'call-button-container');\n\n const textEl = typeof(options.text) === 'string' ? i18n(options.text) : options.text;\n textEl.classList.add(_className + '-text', 'call-button-text');\n\n div.append(buttonDiv, textEl);\n\n ret = div;\n }\n\n return ret;\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport findUpClassName from \"../helpers/dom/findUpClassName\";\nimport EventListenerBase from \"../helpers/eventListenerBase\";\nimport mediaSizes from \"../helpers/mediaSizes\";\nimport clamp from \"../helpers/number/clamp\";\nimport safeAssign from \"../helpers/object/safeAssign\";\nimport windowSize from \"../helpers/windowSize\";\nimport SwipeHandler from \"./swipeHandler\";\n\ntype ResizeSide = 'n' | 'e' | 's' | 'w' | 'ne' | 'se' | 'sw' | 'nw';\nexport type MovableState = {\n top?: number;\n left?: number;\n width: number;\n height: number;\n};\n\nconst className = 'movable-element';\nconst resizeHandlerClassName = className + '-resize-handler';\n\nexport type MovableElementOptions = {\n minWidth: MovableElement['minWidth'],\n minHeight: MovableElement['minHeight'],\n element: MovableElement['element'],\n verifyTouchTarget?: MovableElement['verifyTouchTarget']\n};\n\nexport default class MovableElement extends EventListenerBase<{\n resize: () => void\n}> {\n private minWidth: number;\n private minHeight: number;\n private element: HTMLElement;\n private verifyTouchTarget: (e: TouchEvent | MouseEvent) => boolean;\n\n private top: number;\n private left: number;\n private _width: number;\n private _height: number;\n\n private swipeHandler: SwipeHandler;\n private handlers: HTMLElement[];\n\n constructor(options: MovableElementOptions) {\n super(true);\n safeAssign(this, options);\n \n this.top = this.left = this.width = this.height = 0;\n this.element.classList.add(className);\n \n this.addResizeHandlers();\n this.setSwipeHandler();\n\n mediaSizes.addEventListener('resize', this.onResize);\n }\n\n private onResize = () => {\n this.fixDimensions();\n this.fixPosition();\n this.setPosition();\n };\n\n public destroyElements() {\n this.element.classList.remove(className);\n\n if(this.handlers) {\n this.handlers.forEach(handler => {\n handler.remove();\n });\n }\n }\n\n public destroy() {\n mediaSizes.removeEventListener('resize', this.onResize);\n this.swipeHandler.removeListeners();\n }\n\n private addResizeHandlers() {\n const sides: ResizeSide[] = ['n', 'e', 's', 'w', 'ne', 'se', 'sw', 'nw'];\n this.handlers = sides.map(side => {\n const div = document.createElement('div');\n div.dataset.side = side;\n div.classList.add(resizeHandlerClassName, resizeHandlerClassName + '-side-' + side);\n this.element.append(div);\n return div;\n });\n }\n\n private setSwipeHandler() {\n let startTop: number, startLeft: number, startWidth: number, startHeight: number, resizingSide: ResizeSide;\n const swipeHandler = this.swipeHandler = new SwipeHandler({\n element: this.element,\n onSwipe: (xDiff, yDiff, e) => {\n xDiff *= -1; // to right will be positive\n yDiff *= -1; // to bottom will be positive\n // console.log(xDiff, yDiff, e);\n\n if(resizingSide) {\n if(resizingSide.includes('e') || resizingSide.includes('w')) {\n const isEnlarging = resizingSide.includes('e') && xDiff > 0 || resizingSide.includes('w') && xDiff < 0;\n const resizeDiff = Math.abs(xDiff) * (isEnlarging ? 1 : -1);\n\n const maxPossible = resizingSide.includes('e') ? windowSize.width - startLeft : startWidth + startLeft;\n this.width = Math.min(maxPossible, startWidth + resizeDiff);\n }\n\n if(resizingSide.includes('n') || resizingSide.includes('s')) {\n const isEnlarging = resizingSide.includes('s') && yDiff > 0 || resizingSide.includes('n') && yDiff < 0;\n const resizeDiff = Math.abs(yDiff) * (isEnlarging ? 1 : -1);\n\n const maxPossible = resizingSide.includes('s') ? windowSize.height - startTop : startHeight + startTop;\n this.height = Math.min(maxPossible, startHeight + resizeDiff);\n }\n\n this.fixDimensions();\n\n if(resizingSide.includes('w')) {\n this.left = Math.min(startLeft + startWidth - this.minWidth, startLeft + xDiff);\n }\n\n if(resizingSide.includes('n')) {\n this.top = Math.min(startTop + startHeight - this.minHeight, startTop + yDiff);\n }\n } else {\n this.top = startTop + yDiff;\n this.left = startLeft + xDiff;\n }\n\n this.fixPosition();\n this.setPosition();\n },\n verifyTouchTarget: (e) => {\n const target = e.target;\n if(this.verifyTouchTarget && !this.verifyTouchTarget(e)) {\n return false;\n }\n\n const resizeHandler = findUpClassName(target, resizeHandlerClassName);\n if(resizeHandler) {\n resizingSide = resizeHandler.dataset.side as ResizeSide;\n swipeHandler.setCursor('');\n } else {\n resizingSide = undefined;\n swipeHandler.setCursor('grabbing');\n }\n\n return true;\n },\n onFirstSwipe: () => {\n startTop = this.top;\n startLeft = this.left;\n startWidth = this.width;\n startHeight = this.height;\n }\n });\n }\n\n public setPositionToCenter() {\n this.top = (windowSize.height / 2) - (this.height / 2);\n this.left = (windowSize.width / 2) - (this.width / 2);\n this.setPosition();\n }\n\n private fixDimensions() {\n this.width = clamp(this.width, this.minWidth, windowSize.width);\n this.height = clamp(this.height, this.minHeight, windowSize.height);\n }\n\n private fixPosition() {\n this.top = clamp(this.top, 0, windowSize.height - this.height);\n this.left = clamp(this.left, 0, windowSize.width - this.width);\n }\n\n private setPosition() {\n this.element.style.top = this.top + 'px';\n this.element.style.left = this.left + 'px';\n this.element.style.right = 'auto';\n this.element.style.bottom = 'auto';\n this.element.style.width = this.width + 'px';\n this.element.style.height = this.height + 'px';\n\n this.dispatchEvent('resize');\n }\n\n public get width() {\n return this._width;\n }\n\n public get height() {\n return this._height;\n }\n\n private set width(value: number) {\n this._width = value;\n }\n\n private set height(value: number) {\n this._height = value;\n }\n\n public get state(): MovableState {\n const {top, left, width, height} = this;\n return {\n top,\n left,\n width,\n height\n };\n }\n\n public set state(state: MovableState) {\n const {top, left, width, height} = state;\n this.top = top;\n this.left = left;\n this.width = width;\n this.height = height;\n this.onResize();\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport MovableElement, { MovableElementOptions, MovableState } from \"../components/movableElement\";\nimport { IS_TOUCH_SUPPORTED } from \"../environment/touchSupport\";\nimport ListenerSetter from \"./listenerSetter\";\nimport mediaSizes, { ScreenSize } from \"./mediaSizes\";\nimport safeAssign from \"./object/safeAssign\";\n\nexport default class MovablePanel {\n #movable: MovableElement;\n private listenerSetter: ListenerSetter;\n private previousState: MovableState;\n private onResize: () => void;\n private movableOptions: MovableElementOptions;\n \n constructor(options: {\n listenerSetter: ListenerSetter,\n previousState: MovableState,\n onResize?: () => void,\n movableOptions: MovableElementOptions\n }) {\n safeAssign(this, options);\n\n this.toggleMovable(!IS_TOUCH_SUPPORTED);\n\n this.listenerSetter.add(mediaSizes)('changeScreen', (from, to) => {\n if(to === ScreenSize.mobile || from === ScreenSize.mobile) {\n this.toggleMovable(!IS_TOUCH_SUPPORTED);\n }\n });\n }\n\n public destroy() {\n const movable = this.movable;\n if(movable) {\n movable.destroy();\n }\n }\n\n public get movable() {\n return this.#movable;\n }\n\n public get state() {\n return this.movable ? this.movable.state : this.previousState;\n }\n\n public set state(state: MovableState) {\n this.previousState = state;\n }\n\n private toggleMovable(enabled: boolean) {\n let {movable} = this;\n if(enabled) {\n if(movable) {\n return;\n }\n\n movable = this.#movable = new MovableElement(this.movableOptions);\n \n movable.state = this.previousState;\n if(this.previousState.top === undefined) {\n movable.setPositionToCenter();\n }\n \n if(this.onResize) {\n this.listenerSetter.add(movable)('resize', this.onResize);\n }\n } else {\n if(!movable) {\n return;\n }\n\n this.previousState = movable.state;\n movable.destroyElements();\n movable.destroy();\n this.#movable = undefined;\n }\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nexport default function toggleClassName(className: string, elements: HTMLElement[], disable: boolean) {\n elements.forEach((element) => {\n element.classList.toggle(className, disable);\n });\n\n return () => toggleClassName(className, elements, !disable);\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nenum CALL_STATE {\n CONNECTED,\n CONNECTING,\n EXCHANGING_KEYS,\n PENDING,\n REQUESTING,\n CLOSING,\n CLOSED\n}\n\nexport default CALL_STATE;\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport replaceContent from \"../../helpers/dom/replaceContent\";\nimport toHHMMSS from \"../../helpers/string/toHHMMSS\";\nimport CALL_STATE from \"../../lib/calls/callState\";\nimport { i18n, LangPackKey } from \"../../lib/langPack\";\n\nexport default class CallDescriptionElement {\n private container: HTMLElement;\n private state: CALL_STATE;\n private interval: number;\n\n constructor(private appendTo: HTMLElement) {\n this.container = document.createElement('div');\n this.container.classList.add('call-description');\n }\n\n public detach() {\n if(this.interval !== undefined) {\n clearInterval(this.interval);\n this.interval = undefined;\n }\n\n this.container.remove();\n this.state = undefined;\n }\n\n public update(instance: any) {\n const {connectionState} = instance;\n\n if(this.state === connectionState) {\n return;\n }\n\n this.state = connectionState;\n\n let element: HTMLElement;\n if(connectionState === CALL_STATE.CONNECTED) {\n element = document.createElement('span');\n element.classList.add('call-description-duration');\n\n const setTime = () => {\n element.innerText = toHHMMSS(instance.duration, true);\n };\n\n this.interval = window.setInterval(setTime, 1000);\n setTime();\n } else {\n let langPackKey: LangPackKey;\n switch(connectionState) {\n case CALL_STATE.PENDING:\n langPackKey = instance.isOutgoing ? 'Call.StatusRinging' : 'Call.StatusCalling';\n break;\n case CALL_STATE.REQUESTING:\n langPackKey = 'Call.StatusRequesting';\n break;\n case CALL_STATE.EXCHANGING_KEYS:\n langPackKey = 'VoipExchangingKeys';\n break;\n case CALL_STATE.CLOSED:\n langPackKey = instance.connectedAt !== undefined ? 'Call.StatusEnded' : 'Call.StatusFailed';\n break;\n default:\n langPackKey = 'Call.StatusConnecting';\n break;\n }\n\n element = i18n(langPackKey);\n if(this.interval !== undefined) {\n clearInterval(this.interval);\n this.interval = undefined;\n }\n }\n\n this.container.classList.toggle('has-duration', connectionState === CALL_STATE.CONNECTED);\n replaceContent(this.container, element);\n\n if(!this.container.parentElement) {\n this.appendTo.append(this.container);\n }\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { SuperRLottieIcon } from \"../superIcon\";\n\nexport default class GroupCallMicrophoneIconMini extends SuperRLottieIcon<{\n PartState: boolean,\n ColorState: boolean,\n Items: {\n name: 'voice_mini'\n }[]\n}> {\n constructor(colored?: boolean, skipAnimation?: boolean) {\n super({\n width: 36,\n height: 36,\n getPart: (state) => {\n return this.getItem().getPart(state ? 'unmute' : 'mute');\n },\n getColor: colored ? (state) => {\n return state ? [255, 255, 255] : [158, 158, 158];\n } : undefined,\n skipAnimation\n });\n\n this.add({\n name: 'voice_mini',\n parts: [{\n startFrame: 0,\n endFrame: 35,\n name: 'hand-to-muted'\n }, {\n startFrame: 36,\n endFrame: 68,\n name: 'unmute'\n }, {\n startFrame: 69,\n endFrame: 98,\n name: 'mute'\n }, {\n startFrame: 99,\n endFrame: 135,\n name: 'muted-to-hand'\n }, {\n startFrame: 136,\n endFrame: 171,\n name: 'unmuted-to-hand'\n }]\n });\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport IS_SCREEN_SHARING_SUPPORTED from \"../../environment/screenSharingSupport\";\nimport { IS_MOBILE } from \"../../environment/userAgent\";\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\nimport ControlsHover from \"../../helpers/dom/controlsHover\";\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\nimport { addFullScreenListener, cancelFullScreen, isFullScreen, requestFullScreen } from \"../../helpers/dom/fullScreen\";\nimport { onMediaLoad } from \"../../helpers/files\";\nimport MovablePanel from \"../../helpers/movablePanel\";\nimport safeAssign from \"../../helpers/object/safeAssign\";\nimport toggleClassName from \"../../helpers/toggleClassName\";\nimport type { AppAvatarsManager } from \"../../lib/appManagers/appAvatarsManager\";\nimport type { AppCallsManager } from \"../../lib/appManagers/appCallsManager\";\nimport type { AppPeersManager } from \"../../lib/appManagers/appPeersManager\";\nimport CallInstance from \"../../lib/calls/callInstance\";\nimport CALL_STATE from \"../../lib/calls/callState\";\nimport I18n, { i18n } from \"../../lib/langPack\";\nimport RichTextProcessor from \"../../lib/richtextprocessor\";\nimport rootScope from \"../../lib/rootScope\";\nimport animationIntersector from \"../animationIntersector\";\nimport AvatarElement from \"../avatar\";\nimport ButtonIcon from \"../buttonIcon\";\nimport GroupCallMicrophoneIconMini from \"../groupCall/microphoneIconMini\";\nimport { MovableState } from \"../movableElement\";\nimport PeerTitle from \"../peerTitle\";\nimport PopupElement from \"../popups\";\nimport SetTransition from \"../singleTransition\";\nimport makeButton from \"./button\";\nimport CallDescriptionElement from \"./description\";\nimport callVideoCanvasBlur from \"./videoCanvasBlur\";\n\nconst className = 'call';\n\nconst MIN_WIDTH = 400;\nconst MIN_HEIGHT = 580;\n\nconst INIT_STATE: MovableState = {\n width: MIN_WIDTH,\n height: MIN_HEIGHT\n};\n\nlet previousState: MovableState = {...INIT_STATE};\n\nexport default class PopupCall extends PopupElement {\n private instance: CallInstance;\n private appCallsManager: AppCallsManager;\n private appAvatarsManager: AppAvatarsManager;\n private appPeersManager: AppPeersManager;\n private peerId: PeerId;\n\n private description: CallDescriptionElement;\n private emojisSubtitle: HTMLElement;\n \n private partyStates: HTMLElement;\n private partyMutedState: HTMLElement;\n\n private firstButtonsRow: HTMLElement;\n private secondButtonsRow: HTMLElement;\n\n private declineI18nElement: I18n.IntlElement;\n\n private makeButton: (options: Parameters<typeof makeButton>[2]) => HTMLElement;\n private btnAccept: HTMLElement;\n private btnDecline: HTMLElement;\n private btnVideo: HTMLElement;\n private btnScreen: HTMLElement;\n private btnMute: HTMLElement;\n private btnFullScreen: HTMLButtonElement;\n private btnExitFullScreen: HTMLButtonElement;\n\n private movablePanel: MovablePanel;\n private microphoneIcon: GroupCallMicrophoneIconMini;\n private muteI18nElement: I18n.IntlElement;\n\n private videoContainers: {\n input?: HTMLElement,\n output?: HTMLElement\n };\n\n private controlsHover: ControlsHover;\n\n constructor(options: {\n appCallsManager: AppCallsManager,\n appAvatarsManager: AppAvatarsManager,\n appPeersManager: AppPeersManager,\n instance: CallInstance\n }) {\n super('popup-call', undefined, {\n withoutOverlay: true,\n closable: true\n });\n\n safeAssign(this, options);\n\n this.videoContainers = {};\n\n const {container, listenerSetter, instance} = this;\n container.classList.add(className, 'night');\n\n const avatarContainer = document.createElement('div');\n avatarContainer.classList.add(className + '-avatar');\n\n const peerId = this.peerId = this.instance.interlocutorUserId.toPeerId();\n const avatar = new AvatarElement();\n avatar.classList.add('avatar-full');\n avatar.updateWithOptions({\n isBig: true,\n peerId: peerId\n });\n avatarContainer.append(avatar);\n\n const title = new PeerTitle({\n peerId\n }).element;\n\n title.classList.add(className + '-title');\n\n const subtitle = document.createElement('div');\n subtitle.classList.add(className + '-subtitle');\n\n const description = this.description = new CallDescriptionElement(subtitle);\n\n const emojisSubtitle = this.emojisSubtitle = document.createElement('div');\n emojisSubtitle.classList.add(className + '-emojis');\n\n container.append(avatarContainer, title, subtitle);\n \n if(!IS_MOBILE) {\n this.btnFullScreen = ButtonIcon('fullscreen');\n this.btnExitFullScreen = ButtonIcon('smallscreen hide');\n attachClickEvent(this.btnFullScreen, this.onFullScreenClick, {listenerSetter});\n attachClickEvent(this.btnExitFullScreen, () => cancelFullScreen(), {listenerSetter});\n addFullScreenListener(this.container, this.onFullScreenChange, listenerSetter);\n this.header.prepend(this.btnExitFullScreen);\n this.header.append(this.btnFullScreen);\n\n container.append(emojisSubtitle);\n } else {\n this.header.append(emojisSubtitle);\n }\n\n this.partyStates = document.createElement('div');\n this.partyStates.classList.add(className + '-party-states');\n\n this.partyMutedState = document.createElement('div');\n this.partyMutedState.classList.add(className + '-party-state');\n const stateText = i18n('VoipUserMicrophoneIsOff', [new PeerTitle({peerId, onlyFirstName: true, limitSymbols: 18}).element]);\n stateText.classList.add(className + '-party-state-text');\n const mutedIcon = new GroupCallMicrophoneIconMini(false, true);\n mutedIcon.setState(false, false);\n this.partyMutedState.append(\n mutedIcon.container, \n stateText\n );\n\n this.partyStates.append(this.partyMutedState);\n this.container.append(this.partyStates);\n\n this.makeButton = makeButton.bind(null, className, this.listenerSetter);\n this.constructFirstButtons();\n this.constructSecondButtons();\n\n listenerSetter.add(instance)('state', () => {\n this.updateInstance();\n });\n\n listenerSetter.add(instance)('mediaState', () => {\n this.updateInstance();\n });\n\n this.movablePanel = new MovablePanel({\n listenerSetter,\n movableOptions: {\n minWidth: MIN_WIDTH,\n minHeight: MIN_HEIGHT,\n element: this.element,\n verifyTouchTarget: (e) => {\n const target = e.target;\n if(findUpClassName(target, 'call-button') || \n findUpClassName(target, 'btn-icon') ||\n isFullScreen()) {\n return false;\n }\n\n return true;\n }\n },\n // onResize: () => this.toggleBigLayout(),\n previousState: !this.instance.wasTryingToJoin && !this.instance.isOutgoing ? {...INIT_STATE} : previousState\n });\n\n const movableElement = this.movablePanel.movable;\n if(movableElement) {\n this.listenerSetter.add(movableElement)('resize', () => {\n this.resizeVideoContainers();\n });\n }\n\n const controlsHover = this.controlsHover = new ControlsHover();\n controlsHover.setup({\n element: this.container,\n listenerSetter: this.listenerSetter,\n showOnLeaveToClassName: 'call-buttons'\n });\n controlsHover.showControls(false);\n\n this.addEventListener('close', () => {\n const {movablePanel} = this;\n previousState = movablePanel.state;\n\n this.microphoneIcon.destroy();\n\n movablePanel.destroy();\n });\n\n this.updateInstance();\n }\n\n public getCallInstance() {\n return this.instance;\n }\n\n private constructFirstButtons() {\n const buttons = this.firstButtonsRow = document.createElement('div');\n buttons.classList.add(className + '-buttons', 'is-first');\n\n const toggleDisability = toggleClassName.bind(null, 'btn-disabled');\n \n const btnVideo = this.btnVideo = this.makeButton({\n text: 'Call.Camera',\n icon: 'videocamera_filled',\n callback: () => {\n const toggle = toggleDisability([btnVideo, btnScreen], true);\n this.instance.toggleVideoSharing().finally(toggle);\n }\n });\n\n const btnScreen = this.btnScreen = this.makeButton({\n text: 'Call.Screen',\n icon: 'sharescreen_filled',\n callback: () => {\n const toggle = toggleDisability([btnVideo, btnScreen], true);\n this.instance.toggleScreenSharing().finally(toggle);\n }\n });\n\n if(!IS_SCREEN_SHARING_SUPPORTED) {\n btnScreen.classList.add('hide');\n this.container.classList.add('no-screen');\n }\n\n this.muteI18nElement = new I18n.IntlElement({\n key: 'Call.Mute'\n });\n const btnMute = this.btnMute = this.makeButton({\n text: this.muteI18nElement.element,\n callback: () => {\n this.instance.toggleMuted();\n }\n });\n\n const microphoneIcon = this.microphoneIcon = new GroupCallMicrophoneIconMini(true, true);\n btnMute.firstElementChild.append(microphoneIcon.container);\n\n // btnVideo.classList.add('disabled');\n // btnScreen.classList.add('disabled');\n\n buttons.append(btnVideo, btnScreen, btnMute);\n this.container.append(buttons);\n }\n\n private constructSecondButtons() {\n const buttons = this.secondButtonsRow = document.createElement('div');\n buttons.classList.add(className + '-buttons', 'is-second');\n \n this.declineI18nElement = new I18n.IntlElement({\n key: 'Call.Decline'\n });\n const btnDecline = this.btnDecline = this.makeButton({\n text: this.declineI18nElement.element,\n icon: 'endcall_filled',\n callback: () => {\n this.instance.hangUp('phoneCallDiscardReasonHangup');\n },\n isDanger: true\n });\n\n const btnAccept = this.btnAccept = this.makeButton({\n text: 'Call.Accept',\n icon: 'phone_filled',\n callback: () => {\n this.instance.acceptCall();\n },\n isConfirm: true,\n });\n\n buttons.append(btnDecline, btnAccept);\n this.container.append(buttons);\n }\n\n private onFullScreenClick = () => {\n requestFullScreen(this.container);\n };\n\n private onFullScreenChange = () => {\n const isFull = isFullScreen();\n\n const {btnFullScreen, btnExitFullScreen} = this;\n\n const wasFullScreen = this.container.classList.contains('is-full-screen');\n this.container.classList.toggle('is-full-screen', isFull);\n btnFullScreen && btnFullScreen.classList.toggle('hide', isFull);\n btnExitFullScreen && btnExitFullScreen.classList.toggle('hide', !isFull);\n this.btnClose.classList.toggle('hide', isFull);\n\n if(isFull !== wasFullScreen) {\n animationIntersector.checkAnimations(isFull);\n\n rootScope.setThemeColor(isFull ? '#000000' : undefined);\n\n this.resizeVideoContainers();\n }\n };\n\n private createVideoContainer(video: HTMLVideoElement) {\n const _className = className + '-video';\n const container = document.createElement('div');\n container.classList.add(_className + '-container');\n\n video.classList.add(_className);\n if(video.paused) {\n video.play();\n }\n\n attachClickEvent(container, () => {\n if(!container.classList.contains('small')) {\n return;\n }\n\n const big = Object.values(this.videoContainers).find(container => !container.classList.contains('small'));\n big.classList.add('small');\n big.style.cssText = container.style.cssText;\n container.classList.remove('small');\n container.style.cssText = '';\n\n this.resizeVideoContainers();\n });\n\n const canvas = callVideoCanvasBlur(video);\n canvas.classList.add(_className + '-blur');\n\n container.append(canvas, video);\n\n return container;\n }\n\n private updateInstance() {\n const {instance} = this;\n const {connectionState} = instance;\n if(connectionState === CALL_STATE.CLOSED) {\n if(this.container.classList.contains('is-full-screen')) {\n cancelFullScreen();\n }\n\n this.btnVideo.classList.add('disabled');\n\n this.hide();\n return;\n }\n\n const isPendingIncoming = !instance.isOutgoing && connectionState === CALL_STATE.PENDING;\n this.declineI18nElement.compareAndUpdate({\n key: connectionState === CALL_STATE.PENDING ? 'Call.Decline' : 'Call.End'\n });\n this.btnAccept.classList.toggle('disable', !isPendingIncoming);\n this.btnAccept.classList.toggle('hide-me', !isPendingIncoming);\n this.container.classList.toggle('two-button-rows', isPendingIncoming);\n\n const isMuted = instance.isMuted;\n const onFrame = () => {\n this.btnMute.firstElementChild.classList.toggle('active', isMuted);\n };\n\n const player = this.microphoneIcon.getItem().player;\n this.microphoneIcon.setState(!isMuted, !isMuted, onFrame);\n if(!player) {\n onFrame();\n }\n\n this.muteI18nElement.compareAndUpdate({\n key: isMuted ? 'VoipUnmute' : 'Call.Mute'\n });\n\n const isSharingVideo = instance.isSharingVideo;\n this.btnVideo.firstElementChild.classList.toggle('active', isSharingVideo);\n\n const isSharingScreen = instance.isSharingScreen;\n this.btnScreen.firstElementChild.classList.toggle('active', isSharingScreen);\n\n const outputState = instance.getMediaState('output');\n\n SetTransition(this.partyMutedState, 'is-visible', !!outputState?.muted, 300);\n\n const containers = this.videoContainers;\n const oldContainers = {...containers};\n ['input' as const, 'output' as const].forEach(type => {\n const mediaState = instance.getMediaState(type);\n const video = instance.getVideoElement(type) as HTMLVideoElement;\n\n const hasFrame = !!(video && video.videoWidth && video.videoHeight);\n if(video && !hasFrame && !video.dataset.hasPromise) {\n video.dataset.hasPromise = '1';\n // container.classList.add('hide');\n onMediaLoad(video).then(() => {\n delete video.dataset.hasPromise;\n this.updateInstance();\n // this.resizeVideoContainers();\n // container.classList.remove('hide');\n });\n }\n\n const isActive = !!video && hasFrame && !!(mediaState && (mediaState.videoState === 'active' || mediaState.screencastState === 'active'));\n let videoContainer = containers[type];\n\n if(isActive && video && !videoContainer) {\n videoContainer = containers[type] = this.createVideoContainer(video);\n this.container.append(videoContainer);\n }\n\n if(!isActive && videoContainer) {\n videoContainer.remove();\n delete containers[type];\n }\n });\n\n {\n const input = containers.input;\n const output = containers.output;\n if(Object.keys(oldContainers).length !== Object.keys(containers).length && input) {\n input.classList.toggle('small', !!output);\n }\n\n if(output && !input) {\n output.classList.remove('small');\n }\n }\n\n this.resizeVideoContainers();\n\n this.container.classList.toggle('no-video', !Object.keys(containers).length);\n\n if(!this.emojisSubtitle.textContent && connectionState < CALL_STATE.EXCHANGING_KEYS) {\n Promise.resolve(instance.getEmojisFingerprint()).then(emojis => {\n this.emojisSubtitle.append(RichTextProcessor.wrapEmojiText(emojis.join('')));\n });\n }\n\n this.setDescription();\n }\n\n private resizeVideoContainers() {\n Object.values(this.videoContainers).forEach(container => {\n const isSmall = container.classList.contains('small');\n if(isSmall) {\n const video = container.querySelector('video');\n const popupWidth = this.movablePanel.state;\n const MAX_WIDTH_PX = 240;\n const MAX_HEIGHT_PX = 240;\n \n const isVertical = video.videoHeight > video.videoWidth;\n const MAX_SIZE = isVertical ? MAX_HEIGHT_PX : MAX_WIDTH_PX;\n\n const biggestSideSize = 1 / 3 * (isFullScreen() ? 0xFFFF : (isVertical ? popupWidth.height : popupWidth.width));\n const widthRatio = isVertical ? video.videoWidth / video.videoHeight : 1;\n const heightRatio = isVertical ? 1 : video.videoHeight / video.videoWidth;\n container.style.width = biggestSideSize * widthRatio + 'px';\n container.style.height = biggestSideSize * heightRatio + 'px';\n container.style.maxWidth = MAX_SIZE * widthRatio + 'px';\n container.style.maxHeight = MAX_SIZE * heightRatio + 'px';\n } else {\n container.style.cssText = '';\n }\n });\n }\n\n private setDescription() {\n this.description.update(this.instance);\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport SDP from \"../sdp\";\nimport { CallSignalingData, P2PVideoCodec } from \"../types\";\nimport parseMediaSectionInfo from \"./parseMediaSectionInfo\";\n\nexport default function parseSignalingData(sdp: SDP) {\n const info = parseMediaSectionInfo(sdp, sdp.media[0]);\n \n const data: CallSignalingData.initialSetup = {\n '@type': 'InitialSetup',\n fingerprints: [info.fingerprint],\n ufrag: info.ufrag,\n pwd: info.pwd,\n audio: undefined,\n video: undefined,\n screencast: undefined\n };\n \n const convertNumber = (number: number) => '' + number;\n \n for(const section of sdp.media) {\n const mediaType = section.mediaType;\n if(mediaType === 'application' || !section.isSending) {\n continue;\n }\n \n const codec: P2PVideoCodec = data[mediaType === 'video' && data['video'] ? 'screencast' : mediaType] = {} as any;\n const info = parseMediaSectionInfo(sdp, section);\n codec.ssrc = convertNumber(info.source);\n \n if(info.sourceGroups) {\n codec.ssrcGroups = info.sourceGroups.map(sourceGroup => ({semantics: sourceGroup.semantics, ssrcs: sourceGroup.sources.map(convertNumber)}));\n }\n \n const rtpExtensions: P2PVideoCodec['rtpExtensions'] = codec.rtpExtensions = [];\n section.attributes.get('extmap').forEach((attribute) => {\n rtpExtensions.push({\n id: +attribute.key,\n uri: attribute.value\n });\n });\n \n const payloadTypesMap: Map<number, P2PVideoCodec['payloadTypes'][0]> = new Map();\n \n const getPayloadType = (id: number) => {\n let payloadType = payloadTypesMap.get(id);\n if(!payloadType) {\n payloadTypesMap.set(id, payloadType = {\n id\n } as any);\n }\n \n return payloadType;\n };\n \n section.attributes.get('rtpmap').forEach((attribute) => {\n const id = +attribute.key;\n const payloadType = getPayloadType(id);\n const splitted = attribute.value.split('/');\n const [name, clockrate, channels] = splitted;\n payloadType.name = name;\n payloadType.clockrate = +clockrate;\n payloadType.channels = channels ? +channels : 0;\n });\n \n section.attributes.get('rtcp-fb').forEach((attribute) => {\n const id = +attribute.key;\n const payloadType = getPayloadType(id);\n payloadType.feedbackTypes = attribute.lines.map((line) => {\n const splitted = line.split(' ');\n const [type, subtype] = splitted;\n return {\n type,\n subtype: subtype || ''\n };\n });\n });\n \n section.attributes.get('fmtp').forEach((attribute) => {\n const id = +attribute.key;\n const payloadType = getPayloadType(id);\n const parameters: P2PVideoCodec['payloadTypes'][0]['parameters'] = payloadType.parameters = {};\n const splitted = attribute.value.split(';');\n for(const str of splitted) {\n const [key, value] = str.split('=');\n parameters[key] = value;\n }\n });\n \n codec.payloadTypes = Array.from(payloadTypesMap.values());\n\n /* if(codec.payloadTypes.length > 5) {\n codec.payloadTypes.length = Math.min(codec.payloadTypes.length, 5);\n } */\n }\n \n return data;\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport CallConnectionInstanceBase, { CallConnectionInstanceOptions } from \"./callConnectionInstanceBase\";\nimport CallInstance from \"./callInstance\";\nimport parseSignalingData from \"./helpers/parseSignalingData\";\nimport { parseSdp } from \"./sdp/utils\";\n\nexport default class CallConnectionInstance extends CallConnectionInstanceBase {\n private call: CallInstance;\n\n constructor(options: CallConnectionInstanceOptions & {\n call: CallConnectionInstance['call']\n }) {\n super(options);\n }\n\n protected async negotiateInternal() {\n const {connection, call} = this;\n\n if(!connection.localDescription && !connection.remoteDescription && !call.isOutgoing) {\n return;\n }\n\n let descriptionInit: RTCSessionDescriptionInit;\n if(call.offerReceived) {\n call.offerReceived = false;\n\n const answer = descriptionInit = await connection.createAnswer();\n\n this.log('[sdp] local', answer.type, answer.sdp);\n await connection.setLocalDescription(answer);\n\n this.log('[InitialSetup] send 2');\n } else {\n const offer = descriptionInit = await connection.createOffer();\n\n this.log('[sdp] local', offer.sdp);\n await connection.setLocalDescription(offer);\n\n call.offerSent = true;\n\n this.log('[InitialSetup] send 0');\n }\n\n const initialSetup = parseSignalingData(parseSdp(descriptionInit.sdp));\n call.sendCallSignalingData(initialSetup);\n }\n}\n","const subtle = typeof(window) !== 'undefined' && 'crypto' in window ? window.crypto.subtle : self.crypto.subtle;\n\nexport default subtle;\n","import convertToUint8Array from \"../../../helpers/bytes/convertToUint8Array\";\nimport subtle from \"../subtle\";\n//import sha256 from '@cryptography/sha256';\n\nexport default function sha256(bytes: Parameters<typeof convertToUint8Array>[0]) {\n return subtle.digest('SHA-256', convertToUint8Array(bytes)).then(b => {\n //console.log('legacy', performance.now() - perfS);\n return new Uint8Array(b);\n });\n /* //console.log('SHA-256 hash start');\n\n let perfS = performance.now();\n \n\n let perfD = performance.now();\n let words = typeof(bytes) === 'string' ? bytes : bytesToWordss(bytes as any);\n let hash = sha256(words);\n console.log('darutkin', performance.now() - perfD);\n\n //console.log('SHA-256 hash finish', hash, sha256(words, 'hex'));\n\n return bytesFromWordss(hash); */\n}\n","export default function convertToUint8Array(bytes: Uint8Array | ArrayBuffer | number[] | string): Uint8Array {\n if(bytes instanceof Uint8Array) {\n return bytes;\n } else if(typeof(bytes) === 'string') {\n return new TextEncoder().encode(bytes);\n }\n\n return new Uint8Array(bytes);\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n * \n * Originally from:\n * https://github.com/evgeny-nadymov/telegram-react\n * Copyright (C) 2018 Evgeny Nadymov\n * https://github.com/evgeny-nadymov/telegram-react/blob/master/LICENSE\n */\n\nimport bufferConcats from '../../../helpers/bytes/bufferConcats';\nimport subtle from '../../crypto/subtle';\nimport sha256 from '../../crypto/utils/sha256';\n\nconst kMaxIncomingPacketSize = 128 * 1024 * 1024;\n\nexport default class P2PEncryptor {\n private type: 'Signaling';\n private counter: number;\n private seqMap: Map<number, number>;\n \n constructor(private isOutgoing: boolean, private p2pKey: Uint8Array) {\n this.type = 'Signaling';\n this.counter = 0;\n this.seqMap = new Map();\n }\n \n private concatSHA256(parts: Uint8Array[]) {\n return sha256(bufferConcats(...parts));\n }\n \n private async encryptPrepared(buffer: Uint8Array) {\n const result = {\n counter: 0, //this.counterFromSeq(this.readSeq(buffer)),\n bytes: new Uint8Array(16 + buffer.length)\n };\n \n const x = (this.isOutgoing ? 0 : 8) + (this.type === 'Signaling' ? 128 : 0);\n const key = this.p2pKey;\n \n const msgKeyLarge = await this.concatSHA256([key.subarray(x + 88, x + 88 + 32), buffer]);\n const msgKey = result.bytes;\n for(let i = 0; i < 16; ++i) {\n msgKey[i] = msgKeyLarge[i + 8];\n }\n \n const aesKeyIv = await this.prepareAesKeyIv(key, msgKey, x);\n \n const bytes = await this.aesProcessCtr(buffer, buffer.length, aesKeyIv, true);\n \n result.bytes = new Uint8Array([...result.bytes.subarray(0, 16), ...bytes]);\n \n return result;\n }\n \n public encryptRawPacket(buffer: Uint8Array) {\n const seq = ++this.counter;\n const arr = new ArrayBuffer(4);\n const view = new DataView(arr);\n view.setUint32(0, seq >>> 0, false); // byteOffset = 0; litteEndian = false\n \n const result = new Uint8Array([...new Uint8Array(arr), ...buffer]);\n \n return this.encryptPrepared(result);\n }\n \n private async prepareAesKeyIv(key: Uint8Array, msgKey: Uint8Array, x: number) {\n const [sha256a, sha256b] = await Promise.all([\n this.concatSHA256([\n msgKey.subarray(0, 16),\n key.subarray(x, x + 36)\n ]),\n\n this.concatSHA256([\n key.subarray(40 + x, 40 + x + 36),\n msgKey.subarray(0, 16)\n ])\n ]);\n \n return {\n key: new Uint8Array([\n ...sha256a.subarray(0, 8),\n ...sha256b.subarray(8, 8 + 16),\n ...sha256a.subarray(24, 24 + 8)\n ]),\n iv: new Uint8Array([\n ...sha256b.subarray(0, 4),\n ...sha256a.subarray(8, 8 + 8),\n ...sha256b.subarray(24, 24 + 4)\n ])\n };\n }\n \n private async aesProcessCtr(encryptedData: Uint8Array, dataSize: number, aesKeyIv: {key: Uint8Array, iv: Uint8Array}, encrypt = true) {\n const cryptoKey = await subtle.importKey(\n 'raw',\n aesKeyIv.key,\n {name: 'AES-CTR'},\n false,\n [encrypt ? 'encrypt' : 'decrypt']\n );\n \n const buffer: ArrayBuffer = await subtle[encrypt ? 'encrypt' : 'decrypt']({\n name: 'AES-CTR',\n counter: aesKeyIv.iv,\n length: aesKeyIv.iv.length * 8\n },\n cryptoKey,\n encryptedData\n );\n\n return new Uint8Array(buffer);\n }\n \n private constTimeIsDifferent(a: Uint8Array, b: Uint8Array, count: number) {\n let msgKeyEquals = true;\n for(let i = 0; i < count; ++i) {\n if(a[i] !== b[i]) {\n msgKeyEquals = false;\n }\n }\n \n return !msgKeyEquals;\n }\n \n public async decryptRawPacket(buffer: Uint8Array) {\n if(buffer.length < 21 || buffer.length > kMaxIncomingPacketSize) {\n return;\n }\n \n const {isOutgoing, type} = this;\n \n const x = (isOutgoing ? 8 : 0) + (type === 'Signaling' ? 128 : 0);\n const key = this.p2pKey;\n \n const msgKey = buffer.subarray(0, 16);\n const encryptedData = buffer.subarray(16);\n const encryptedDataSize = buffer.length - 16;\n \n const aesKeyIv = await this.prepareAesKeyIv(key, msgKey, x);\n \n const decryptionBuffer = await this.aesProcessCtr(encryptedData, encryptedDataSize, aesKeyIv, false);\n \n const msgKeyLarge = await this.concatSHA256([\n key.subarray(88 + x, 88 + x + 32),\n decryptionBuffer\n ]);\n \n if(this.constTimeIsDifferent(msgKeyLarge.subarray(8), msgKey, 16)) {\n return;\n }\n \n const dataView = new DataView(decryptionBuffer.buffer);\n const seq = dataView.getUint32(0);\n if(this.seqMap.has(seq)) {\n return;\n }\n this.seqMap.set(seq, seq);\n \n return decryptionBuffer.slice(4);\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n * \n * Originally from:\n * https://github.com/evgeny-nadymov/telegram-react\n * Copyright (C) 2018 Evgeny Nadymov\n * https://github.com/evgeny-nadymov/telegram-react/blob/master/LICENSE\n */\n\nimport StringFromLineBuilder from '../stringFromLineBuilder';\nimport { addDataChannel, addExtmap, addPayloadTypes, addSsrc } from './p2PSdpBuilder';\n\nexport default class ChromeP2PSdpBuilder {\n static generateOffer(info: any) {\n const {fingerprints, ufrag, pwd, audio, video} = info;\n audio.type = 'audio';\n video.type = 'video';\n const media = [audio, video];\n\n const stringBuilder = new StringFromLineBuilder();\n stringBuilder.add(\n 'v=0', \n 'o=- 1 2 IN IP4 127.0.0.1',\n 's=-',\n 't=0 0'\n );\n\n if(fingerprints) {\n fingerprints.forEach((x: any) => {\n const {hash, fingerprint, setup} = x;\n stringBuilder.add(\n `a=fingerprint:${hash} ${fingerprint}`, \n `a=setup:${setup}`\n );\n });\n }\n if(ufrag && pwd) {\n stringBuilder.add(\n `a=ice-ufrag:${ufrag}`,\n `a=ice-pwd:${pwd}`\n );\n }\n\n stringBuilder.add(\n 'a=group:BUNDLE 0 1 2', \n 'a=extmap-allow-mixed', \n 'a=msid-semantic: WMS *'\n );\n const streamName = 'stream' + media.map(x => x.ssrc).join('_');\n for(let i = 0; i < media.length; i++) {\n const m = media[i];\n const {type, ssrc, ssrcGroups, payloadTypes, rtpExtensions} = m;\n switch(type) {\n case 'audio': {\n stringBuilder.add(\n `m=audio 56930 UDP/TLS/RTP/SAVPF ${payloadTypes.map((x: any) => x.id).join(' ')}`,\n 'c=IN IP4 0.0.0.0',\n 'a=rtcp:9 IN IP4 0.0.0.0',\n 'a=ice-options:trickle',\n `a=mid:${i}`,\n 'a=sendrecv',\n addExtmap(rtpExtensions)\n );\n if(ssrc) {\n stringBuilder.add(`a=msid:${streamName} audio${ssrc}`);\n }\n stringBuilder.add(\n 'a=rtcp-mux',\n addPayloadTypes(payloadTypes),\n addSsrc(type, ssrc, ssrcGroups, streamName)\n );\n\n break;\n }\n\n case 'video': {\n stringBuilder.add(\n `m=video 61986 UDP/TLS/RTP/SAVPF ${payloadTypes.map((x: any) => x.id).join(' ')}`,\n 'c=IN IP4 0.0.0.0',\n 'a=rtcp:9 IN IP4 0.0.0.0',\n 'a=ice-options:trickle',\n `a=mid:${i}`,\n 'a=sendrecv',\n addExtmap(rtpExtensions)\n );\n if(ssrc) {\n stringBuilder.add(`a=msid:${streamName} video${ssrc}`);\n }\n stringBuilder.add(\n 'a=rtcp-mux', \n 'a=rtcp-rsize',\n addPayloadTypes(payloadTypes),\n addSsrc(type, ssrc, ssrcGroups, streamName)\n );\n break;\n }\n }\n }\n stringBuilder.add(addDataChannel(2));\n return stringBuilder.finalize();\n }\n\n static generateAnswer(info: any) {\n const {fingerprints, ufrag, pwd, audio, video} = info;\n audio.type = 'audio';\n video.type = 'video';\n const media = [audio, video];\n\n const stringBuilder = new StringFromLineBuilder();\n stringBuilder.add(\n 'v=0',\n 'o=- 1 2 IN IP4 127.0.0.1',\n 's=-',\n 't=0 0',\n );\n\n if(fingerprints) {\n fingerprints.forEach((x: any) => {\n const {hash, fingerprint, setup} = x;\n stringBuilder.add(\n `a=fingerprint:${hash} ${fingerprint}`,\n `a=setup:${setup}`\n );\n });\n }\n if(ufrag && pwd) {\n stringBuilder.add(\n `a=ice-ufrag:${ufrag}`,\n `a=ice-pwd:${pwd}`\n );\n }\n\n stringBuilder.add(\n 'a=group:BUNDLE 0 1 2',\n 'a=extmap-allow-mixed',\n 'a=msid-semantic: WMS *'\n );\n const streamName = 'stream' + media.map(x => x.ssrc).join('_');\n for(let i = 0; i < media.length; i++) {\n const m = media[i];\n const {type, ssrc, ssrcGroups, payloadTypes, rtpExtensions} = m;\n switch(type) {\n case 'audio': {\n stringBuilder.add(\n `m=audio 56930 UDP/TLS/RTP/SAVPF ${payloadTypes.map((x: any) => x.id).join(' ')}`,\n 'c=IN IP4 0.0.0.0',\n 'a=rtcp:9 IN IP4 0.0.0.0',\n 'a=ice-options:trickle',\n `a=mid:${i}`,\n 'a=sendrecv',\n addExtmap(rtpExtensions)\n );\n if(ssrc) {\n stringBuilder.add(`a=msid:${streamName} audio${ssrc}`);\n }\n stringBuilder.add(\n 'a=rtcp-mux',\n addPayloadTypes(payloadTypes),\n addSsrc(type, ssrc, ssrcGroups, streamName)\n );\n break;\n }\n\n case 'video': {\n stringBuilder.add(\n `m=video 61986 UDP/TLS/RTP/SAVPF ${payloadTypes.map((x: any) => x.id).join(' ')}`,\n 'c=IN IP4 0.0.0.0',\n 'a=rtcp:9 IN IP4 0.0.0.0',\n 'a=ice-options:trickle',\n `a=mid:${i}`,\n 'a=sendrecv',\n addExtmap(rtpExtensions)\n );\n if(ssrc) {\n stringBuilder.add(`a=msid:${streamName} video${ssrc}`);\n }\n\n stringBuilder.add(\n 'a=rtcp-mux',\n 'a=rtcp-rsize',\n addPayloadTypes(payloadTypes),\n addSsrc(type, ssrc, ssrcGroups, streamName)\n );\n break;\n }\n }\n }\n stringBuilder.add(addDataChannel(2));\n return stringBuilder.finalize();\n }\n}\n","/*\n * Copyright (c) 2018-present, Evgeny Nadymov\n *\n * This source code is licensed under the GPL v.3.0 license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport { addDataChannel, addExtmap, addPayloadTypes, addSsrc } from './p2PSdpBuilder';\n\nexport class FirefoxP2PSdpBuilder {\n static generateOffer(info) {\n const { fingerprints, ufrag, pwd, audio, video } = info;\n audio.type = 'audio';\n video.type = 'video';\n const media = [audio, video];\n\n let sdp = `v=0\no=- 1 0 IN IP4 0.0.0.0\ns=-\nt=0 0`;\n if (fingerprints) {\n fingerprints.forEach(x => {\n const { hash, fingerprint, setup } = x;\n sdp += `\na=fingerprint:${hash} ${fingerprint}\na=setup:${setup}`;\n });\n }\n if (ufrag && pwd) {\n sdp += `\na=ice-ufrag:${ufrag}\na=ice-pwd:${pwd}`;\n }\n\n sdp += `\na=group:BUNDLE 0 1 2\na=ice-options:trickle\na=msid-semantic:WMS *`;\n const streamName = 'stream' + media.map(x => x.ssrc).join('_');\n for (let i = 0; i < media.length; i++) {\n const m = media[i];\n const { type, ssrc, ssrcGroups, payloadTypes, rtpExtensions } = m;\n switch (type) {\n case 'audio': {\n sdp += `\nm=audio 9 UDP/TLS/RTP/SAVPF ${payloadTypes.map(x => x.id).join(' ')}\nc=IN IP4 0.0.0.0\na=mid:${i}\na=sendrecv`;\n sdp += addExtmap(rtpExtensions);\n sdp += `\na=rtcp-mux`;\n sdp += addPayloadTypes(payloadTypes);\n sdp += addSsrc(type, ssrc, ssrcGroups, streamName);\n\n break;\n }\n case 'video': {\n sdp += `\nm=video 9 UDP/TLS/RTP/SAVPF ${payloadTypes.map(x => x.id).join(' ')}\nc=IN IP4 0.0.0.0\na=mid:${i}\na=sendrecv`;\n sdp += addExtmap(rtpExtensions);\n sdp += `\na=rtcp-mux\na=rtcp-rsize`;\n sdp += addPayloadTypes(payloadTypes);\n sdp += addSsrc(type, ssrc, ssrcGroups, streamName);\n\n break;\n }\n }\n }\n sdp += addDataChannel(2);\n sdp += `\n`;\n\n return sdp;\n }\n\n static generateAnswer(info) {\n const { fingerprints, ufrag, pwd, audio, video } = info;\n audio.type = 'audio';\n video.type = 'video';\n const media = [audio, video];\n\n let sdp = `v=0\no=- 1 0 IN IP4 0.0.0.0\ns=-\nt=0 0`;\n if (fingerprints) {\n fingerprints.forEach(x => {\n const { hash, fingerprint, setup } = x;\n sdp += `\na=fingerprint:${hash} ${fingerprint}\na=setup:${setup}`;\n });\n }\n if (ufrag && pwd) {\n sdp += `\na=ice-ufrag:${ufrag}\na=ice-pwd:${pwd}`;\n }\n\n sdp += `\na=group:BUNDLE 0 1 2\na=ice-options:trickle\na=msid-semantic:WMS *`;\n const streamName = 'stream' + media.map(x => x.ssrc).join('_');\n for (let i = 0; i < media.length; i++) {\n const m = media[i];\n const { type, mid, ssrc, ssrcGroups, payloadTypes, dir, rtpExtensions } = m;\n switch (type) {\n case 'audio': {\n sdp += `\nm=audio 9 UDP/TLS/RTP/SAVPF ${payloadTypes.map(x => x.id).join(' ')}\nc=IN IP4 0.0.0.0\na=mid:${i}\na=sendrecv`;\n sdp += addExtmap(rtpExtensions);\n sdp += `\na=rtcp-mux`;\n sdp += addPayloadTypes(payloadTypes);\n sdp += addSsrc(type, ssrc, ssrcGroups, streamName);\n\n break;\n }\n case 'video': {\n sdp += `\nm=video 9 UDP/TLS/RTP/SAVPF ${payloadTypes.map(x => x.id).join(' ')}\nc=IN IP4 0.0.0.0\na=mid:${i}\na=sendrecv`;\n sdp += addExtmap(rtpExtensions);\n sdp += `\na=rtcp-mux\na=rtcp-rsize`;\n sdp += addPayloadTypes(payloadTypes);\n sdp += addSsrc(type, ssrc, ssrcGroups, streamName);\n break;\n }\n }\n }\n sdp += addDataChannel(2);\n sdp += `\n`;\n\n return sdp;\n }\n}","/*\n * Copyright (c) 2018-present, Evgeny Nadymov\n *\n * This source code is licensed under the GPL v.3.0 license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport { addDataChannel, addExtmap, addPayloadTypes, addSsrc } from './p2PSdpBuilder';\n\nexport class SafariP2PSdpBuilder {\n static generateOffer(info) {\n const { fingerprints, ufrag, pwd, audio, video } = info;\n audio.type = 'audio';\n video.type = 'video';\n const media = [audio, video];\n\n if (!media.length) {\n return `v=0\no=- 1 2 IN IP4 127.0.0.1\ns=-\nt=0 0\na=msid-semantic: WMS\n`;\n }\n\n let sdp = `v=0\no=- 1 2 IN IP4 127.0.0.1\ns=-\nt=0 0`;\n if (fingerprints) {\n fingerprints.forEach(x => {\n const { hash, fingerprint, setup } = x;\n sdp += `\na=fingerprint:${hash} ${fingerprint}\na=setup:${setup}`;\n });\n }\n if (ufrag && pwd) {\n sdp += `\na=ice-ufrag:${ufrag}\na=ice-pwd:${pwd}`;\n }\n\n sdp += `\na=group:BUNDLE 0 1 2\na=extmap-allow-mixed\na=msid-semantic: WMS *`;\n const streamName = 'stream' + media.map(x => x.ssrc).join('_');\n for (let i = 0; i < media.length; i++) {\n const m = media[i];\n const { type, ssrc, ssrcGroups, payloadTypes, rtpExtensions } = m;\n switch (type) {\n case 'audio': {\n sdp += `\nm=audio 9 UDP/TLS/RTP/SAVPF ${payloadTypes.map(x => x.id).join(' ')}\nc=IN IP4 0.0.0.0\na=rtcp:9 IN IP4 0.0.0.0\na=ice-options:trickle\na=mid:${i}\na=sendrecv`;\n sdp += addExtmap(rtpExtensions);\n if (ssrc) {\n sdp += `\na=msid:${streamName} audio${ssrc}`;\n }\n sdp += `\na=rtcp-mux`;\n sdp += addPayloadTypes(payloadTypes);\n sdp += addSsrc(type, ssrc, ssrcGroups, streamName);\n\n break;\n }\n case 'video': {\n sdp += `\nm=video 9 UDP/TLS/RTP/SAVPF ${payloadTypes.map(x => x.id).join(' ')}\nc=IN IP4 0.0.0.0\na=rtcp:9 IN IP4 0.0.0.0\na=ice-options:trickle\na=mid:${i}\na=sendrecv`;\n sdp += addExtmap(rtpExtensions);\n if (ssrc) {\n sdp += `\na=msid:${streamName} video${ssrc}`;\n }\n sdp += `\na=rtcp-mux\na=rtcp-rsize`;\n sdp += addPayloadTypes(payloadTypes);\n sdp += addSsrc(type, ssrc, ssrcGroups, streamName);\n break;\n }\n }\n }\n sdp += addDataChannel(2);\n sdp += `\n`;\n\n return sdp;\n }\n\n static generateAnswer(info) {\n const { fingerprints, ufrag, pwd, audio, video } = info;\n audio.type = 'audio';\n video.type = 'video';\n const media = [audio, video];\n\n if (!media.length) {\n return `v=0\no=- 1 2 IN IP4 127.0.0.1\ns=-\nt=0 0\na=msid-semantic: WMS\n`;\n }\n\n let sdp = `v=0\no=- 1 2 IN IP4 127.0.0.1\ns=-\nt=0 0`;\n if (fingerprints) {\n fingerprints.forEach(x => {\n const { hash, fingerprint, setup } = x;\n sdp += `\na=fingerprint:${hash} ${fingerprint}\na=setup:${setup}`;\n });\n }\n if (ufrag && pwd) {\n sdp += `\na=ice-ufrag:${ufrag}\na=ice-pwd:${pwd}`;\n }\n\n sdp += `\na=group:BUNDLE 0 1 2\na=extmap-allow-mixed\na=msid-semantic: WMS *`;\n const streamName = 'stream' + media.map(x => x.ssrc).join('_');\n for (let i = 0; i < media.length; i++) {\n const m = media[i];\n const { type, ssrc, ssrcGroups, payloadTypes, rtpExtensions } = m;\n switch (type) {\n case 'audio': {\n sdp += `\nm=audio 9 UDP/TLS/RTP/SAVPF ${payloadTypes.map(x => x.id).join(' ')}\nc=IN IP4 0.0.0.0\na=rtcp:9 IN IP4 0.0.0.0\na=ice-options:trickle\na=mid:${i}\na=sendrecv`;\n sdp += addExtmap(rtpExtensions);\n if (ssrc) {\n sdp += `\na=msid:${streamName} audio${ssrc}`;\n }\n sdp += `\na=rtcp-mux`;\n sdp += addPayloadTypes(payloadTypes);\n sdp += addSsrc(type, ssrc, ssrcGroups, streamName);\n\n break;\n }\n case 'video': {\n sdp += `\nm=video 9 UDP/TLS/RTP/SAVPF ${payloadTypes.map(x => x.id).join(' ')}\nc=IN IP4 0.0.0.0\na=rtcp:9 IN IP4 0.0.0.0\na=ice-options:trickle\na=mid:${i}\na=sendrecv`;\n sdp += addExtmap(rtpExtensions);\n if (ssrc) {\n sdp += `\na=msid:${streamName} video${ssrc}`;\n }\n sdp += `\na=rtcp-mux\na=rtcp-rsize`;\n sdp += addPayloadTypes(payloadTypes);\n sdp += addSsrc(type, ssrc, ssrcGroups, streamName);\n break;\n }\n }\n }\n sdp += addDataChannel(2);\n sdp += `\n`;\n\n return sdp;\n }\n}","/*\n* Copyright (c) 2018-present, Evgeny Nadymov\n*\n* This source code is licensed under the GPL v.3.0 license found in the\n* LICENSE file in the root directory of this source tree.\n*/\n\nimport ChromeP2PSdpBuilder from './chromeP2PSdpBuilder';\nimport { FirefoxP2PSdpBuilder } from './firefoxP2PSdpBuilder';\nimport { SafariP2PSdpBuilder } from './safariP2PSdpBuilder';\n// import { TG_CALLS_SDP_STRING } from '../../Stores/CallStore';\n\nexport function p2pParseCandidate(candidate) {\n if(!candidate || !candidate.startsWith('candidate:')) {\n return;\n }\n \n const sdpString = candidate;\n candidate = candidate.substr('candidate:'.length);\n \n const [foundation, component, protocol, priority, ip, port, ...other] = candidate.split(' ');\n const c = {\n sdpString,\n foundation,\n component,\n protocol,\n priority,\n address: { ip, port }\n };\n \n for(let i = 0; i < other.length; i += 2) {\n switch(other[i]) {\n case 'typ': {\n c.type = other[i + 1];\n break;\n }\n case 'raddr': {\n if(!c.relAddress) {\n c.relAddress = {};\n }\n \n c.relAddress.ip = other[i + 1];\n break;\n }\n case 'rport': {\n if(!c.relAddress) {\n c.relAddress = {};\n }\n \n c.relAddress.port = other[i + 1];\n break;\n }\n case 'generation': {\n c.generation = other[i + 1];\n break;\n }\n case 'tcptype': {\n c.tcpType = other[i + 1];\n break;\n }\n case 'network-id': {\n c.networkId = other[i + 1];\n break;\n }\n case 'network-cost': {\n c.networkCost = other[i + 1];\n break;\n }\n case 'ufrag': {\n c.username = other[i + 1];\n break;\n }\n }\n }\n \n return c;\n}\n\nexport function p2pParseSdp(sdp) {\n const lines = sdp.split('\\r\\n');\n const lookup = (prefix, force = true, lineFrom = 0, lineTo = Number.MAX_VALUE) => {\n if (lineTo === -1) {\n lineTo = Number.MAX_VALUE;\n }\n for (let i = lineFrom; i < lines.length && i < lineTo; i++) {\n const line = lines[i];\n if (line.startsWith(prefix)) {\n return line.substr(prefix.length);\n }\n }\n \n if (force) {\n console.error(\"Can't find prefix\", prefix);\n }\n \n return null;\n };\n const findIndex = (prefix, lineFrom = 0, lineTo = Number.MAX_VALUE) => {\n if (lineTo === -1) {\n lineTo = Number.MAX_VALUE;\n }\n for (let i = lineFrom; i < lines.length && i < lineTo; i++) {\n const line = lines[i];\n if (line.startsWith(prefix)) {\n return i;\n }\n }\n \n return -1;\n };\n \n const pwdIndex = findIndex('a=ice-pwd:');\n const ufragIndex = findIndex('a=ice-ufrag:');\n if (pwdIndex === -1 && ufragIndex === -1) {\n return {\n // sessionId: lookup('o=').split(' ')[1],\n ufrag: null,\n pwd: null,\n fingerprints: []\n };\n }\n \n const info = {\n // sessionId: lookup('o=').split(' ')[1],\n ufrag: null,\n pwd: null,\n fingerprints: []\n };\n \n let mediaIndex = findIndex('m=');\n const fingerprint = lookup('a=fingerprint:', false);\n const setup = lookup('a=setup:', false);\n if (fingerprint && setup) {\n info.fingerprints.push({\n hash: fingerprint.split(' ')[0],\n fingerprint: fingerprint.split(' ')[1],\n setup\n });\n }\n \n const ufrag = lookup('a=ice-ufrag:', false);\n const pwd = lookup('a=ice-pwd:', false);\n if (ufrag && pwd) {\n info.ufrag = ufrag;\n info.pwd = pwd;\n }\n \n while (mediaIndex !== -1) {\n let nextMediaIndex = findIndex('m=', mediaIndex + 1);\n \n const extmap = [];\n const types = [];\n const mediaType = lookup('m=', true, mediaIndex, nextMediaIndex).split(' ')[0];\n const media = {\n // type: lookup('m=', true, mediaIndex, nextMediaIndex).split(' ')[0],\n // mid: lookup('a=mid:', true, mediaIndex, nextMediaIndex),\n // dir: findDirection(mediaIndex, nextMediaIndex),\n rtpExtensions: extmap,\n payloadTypes: types\n }\n \n const lineTo = nextMediaIndex === -1 ? lines.length : nextMediaIndex;\n const fmtp = new Map();\n const rtcpFb = new Map();\n for (let i = mediaIndex; i < lineTo; i++) {\n const line = lines[i];\n if (line.startsWith('a=extmap:')) {\n const [ id, uri ] = line.substr('a=extmap:'.length).split(' ');\n extmap.push({ id: parseInt(id), uri });\n } else if (line.startsWith('a=fmtp:')) {\n const [ id, str ] = line.substr('a=fmtp:'.length).split(' ');\n const obj = { };\n const arr = str.split(';').map(x => {\n const [ key, value ] = x.split('=');\n obj[key] = value;\n return { [key]: value };\n });\n fmtp.set(parseInt(id), obj);\n } else if (line.startsWith('a=rtcp-fb:')) {\n const [ id, type = '', subtype = '' ] = line.substr('a=rtcp-fb:'.length).split(' ');\n if (rtcpFb.has(parseInt(id))) {\n rtcpFb.get(parseInt(id)).push({ type, subtype });\n } else {\n rtcpFb.set(parseInt(id), [{ type, subtype }])\n }\n } else if (line.startsWith('a=rtpmap')) {\n const [ id, str ] = line.substr('a=rtpmap:'.length).split(' ');\n const [ name, clockrate, channels = '0' ] = str.split('/');\n const obj = { id: parseInt(id), name, clockrate: parseInt(clockrate), channels: parseInt(channels) };\n \n types.push(obj);\n }\n }\n \n for (let i = 0; i < types.length; i++) {\n const { id } = types[i];\n if (rtcpFb.has(id)) {\n types[i].feedbackTypes = rtcpFb.get(id);\n }\n if (fmtp.has(id)) {\n types[i].parameters = fmtp.get(id);\n }\n }\n \n const ssrc = lookup('a=ssrc:', false, mediaIndex, nextMediaIndex);\n if (ssrc) {\n media.ssrc = ssrc.split(' ')[0];\n }\n \n const ssrcGroup = lookup('a=ssrc-group:', false, mediaIndex, nextMediaIndex);\n if (ssrcGroup) {\n const [ semantics, ...ssrcs ] = ssrcGroup.split(' ');\n media.ssrcGroups = [{\n semantics,\n ssrcs\n }]\n }\n \n switch (mediaType) {\n case 'audio': {\n info.audio = media;\n break;\n }\n case 'video': {\n info.video = media;\n break;\n }\n }\n \n mediaIndex = nextMediaIndex;\n }\n\n if(!info.video.ssrcGroups) {\n info.video.ssrcGroups = [];\n }\n\n info['@type'] = 'InitialSetup';\n \n // console.log('[p2pParseSdp]', sdp, info);\n return info;\n}\n\nexport function isFirefox() {\n return navigator.userAgent.toLowerCase().indexOf('firefox') > -1;\n}\n\nfunction isSafari() {\n return navigator.userAgent.toLowerCase().indexOf('safari') > -1 && navigator.userAgent.toLowerCase().indexOf('chrome') === -1;\n}\n\nexport function addExtmap(extmap) {\n let sdp = [];\n // return sdp;\n for (let j = 0; j < extmap.length; j++) {\n const ext = extmap[j];\n const { id, uri } = ext;\n // if (isFirefox() && uri.indexOf(''))\n console.log('[extmap] add', id, uri);\n sdp.push(`a=extmap:${id} ${uri}`);\n }\n \n return sdp.join('\\n');\n}\n\nexport function addPayloadTypes(types) {\n let sdp = [];\n console.log('[SDP] addPayloadTypes', types);\n for (let i = 0; i < types.length; i++) {\n const type = types[i];\n const { id, name, clockrate, channels, feedbackTypes, parameters } = type;\n sdp.push(`a=rtpmap:${id} ${name}/${clockrate}${channels ? '/' + channels : ''}`);\n if (feedbackTypes) {\n feedbackTypes.forEach(x => {\n const { type, subtype } = x;\n sdp.push(`a=rtcp-fb:${id} ${[type, subtype].join(' ')}`);\n });\n }\n if (parameters) {\n const fmtp = [];\n Object.getOwnPropertyNames(parameters).forEach(pName => {\n fmtp.push(`${pName}=${parameters[pName]}`);\n });\n \n sdp.push(`a=fmtp:${id} ${fmtp.join(';')}`);\n }\n }\n \n return sdp.join('\\n');\n}\n\nexport function addSsrc(type, ssrc, ssrcGroups, streamName) {\n let sdp = [];\n \n if (ssrcGroups && ssrcGroups.length > 0) {\n ssrcGroups.forEach(ssrcGroup => {\n if (ssrcGroup && ssrcGroup.ssrcs.length > 0) {\n sdp.push(`a=ssrc-group:${ssrcGroup.semantics} ${ssrcGroup.ssrcs.join(' ')}`);\n ssrcGroup.ssrcs.forEach(ssrc => {\n sdp.push(\n `a=ssrc:${ssrc} cname:stream${ssrc}`,\n `a=ssrc:${ssrc} msid:${streamName} ${type}${ssrc}`,\n `a=ssrc:${ssrc} mslabel:${type}${ssrc}`,\n `a=ssrc:${ssrc} label:${type}${ssrc}`\n );\n });\n }\n });\n } else if (ssrc) {\n sdp.push(\n `a=ssrc:${ssrc} cname:stream${ssrc}`,\n `a=ssrc:${ssrc} msid:${streamName} ${type}${ssrc}`,\n `a=ssrc:${ssrc} mslabel:${type}${ssrc}`,\n `a=ssrc:${ssrc} label:${type}${ssrc}`\n );\n }\n \n return sdp.join('\\n');\n}\n\nexport function addDataChannel(mid) {\n return `m=application 9 UDP/DTLS/SCTP webrtc-datachannel\nc=IN IP4 0.0.0.0\na=ice-options:trickle\na=mid:2\na=sctp-port:5000\na=max-message-size:262144`;\n}\n\nexport class P2PSdpBuilder {\n static generateCandidate(info) {\n if (!info) return null;\n \n const { sdpString, sdpMLineIndex, sdpMid, foundation, component, protocol, priority, address, type, relAddress, generation, tcpType, networkId, networkCost, username } = info;\n if (/* TG_CALLS_SDP_STRING */true) {\n if (sdpString) {\n return {\n candidate: sdpString,\n sdpMLineIndex,\n sdpMid\n };\n }\n }\n throw 'no sdpString';\n \n let candidate = `candidate:${foundation} ${component} ${protocol} ${priority} ${address.ip} ${address.port}`;\n const attrs = []\n if (type) {\n attrs.push(`typ ${type}`);\n }\n if (relAddress) {\n attrs.push(`raddr ${relAddress.ip}`);\n attrs.push(`rport ${relAddress.port}`);\n }\n if (tcpType) {\n attrs.push(`tcptype ${tcpType}`);\n }\n if (generation) {\n attrs.push(`generation ${generation}`);\n }\n if (username) {\n attrs.push(`ufrag ${username}`);\n }\n if (networkId) {\n attrs.push(`network-id ${networkId}`);\n }\n if (networkCost) {\n attrs.push(`network-cost ${networkCost}`);\n }\n if (attrs.length > 0) {\n candidate += ` ${attrs.join(' ')}`;\n }\n \n return { candidate, sdpMid, sdpMLineIndex };\n }\n \n static generateOffer(info) {\n if (isFirefox()) {\n return FirefoxP2PSdpBuilder.generateOffer(info);\n } else if (isSafari()) {\n return SafariP2PSdpBuilder.generateOffer(info);\n }\n \n return ChromeP2PSdpBuilder.generateOffer(info);\n }\n \n static generateAnswer(info) {\n if (isFirefox()) {\n return FirefoxP2PSdpBuilder.generateAnswer(info);\n } else if (isSafari()) {\n return SafariP2PSdpBuilder.generateAnswer(info);\n }\n \n return ChromeP2PSdpBuilder.generateAnswer(info);\n }\n}","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport ctx from \"../../environment/ctx\";\nimport { IS_SAFARI } from \"../../environment/userAgent\";\nimport safeAssign from \"../../helpers/object/safeAssign\";\nimport debounce from \"../../helpers/schedulers/debounce\";\nimport { GroupCallParticipantVideoSourceGroup, PhoneCall, PhoneCallDiscardReason, PhoneCallProtocol, Update } from \"../../layer\";\nimport { emojiFromCodePoints } from \"../../vendor/emoji\";\nimport type { ApiUpdatesManager } from \"../appManagers/apiUpdatesManager\";\nimport type { AppCallsManager, CallId } from \"../appManagers/appCallsManager\";\nimport { logger } from \"../logger\";\nimport type { ApiManagerProxy } from \"../mtproto/mtprotoworker\";\nimport rootScope from \"../rootScope\";\nimport CallConnectionInstance from \"./callConnectionInstance\";\nimport CallInstanceBase from \"./callInstanceBase\";\nimport CALL_STATE from \"./callState\";\nimport { GROUP_CALL_AMPLITUDE_ANALYSE_INTERVAL_MS } from \"./constants\";\nimport parseSignalingData from \"./helpers/parseSignalingData\";\nimport stopTrack from \"./helpers/stopTrack\";\nimport localConferenceDescription, { ConferenceEntry, generateSsrc } from \"./localConferenceDescription\";\nimport getCallProtocol from \"./p2P/getCallProtocol\";\nimport getRtcConfiguration from \"./p2P/getRtcConfiguration\";\nimport P2PEncryptor from \"./p2P/p2PEncryptor\";\nimport { p2pParseCandidate, P2PSdpBuilder } from \"./p2P/p2PSdpBuilder\";\nimport { parseSdp } from \"./sdp/utils\";\nimport { WebRTCLineType } from \"./sdpBuilder\";\nimport StreamManager from \"./streamManager\";\nimport { AudioCodec, CallMediaState, CallSignalingData, DiffieHellmanInfo, P2PAudioCodec, P2PVideoCodec, VideoCodec } from \"./types\";\n\nexport default class CallInstance extends CallInstanceBase<{\n state: (state: CALL_STATE) => void,\n id: (id: CallId, prevId: CallId) => void,\n muted: (muted: boolean) => void,\n mediaState: (mediaState: CallMediaState) => void,\n acceptCallOverride: () => Promise<boolean>,\n}> {\n public dh: Partial<DiffieHellmanInfo.a & DiffieHellmanInfo.b>;\n public id: CallId;\n public call: PhoneCall;\n public interlocutorUserId: UserId;\n public protocol: PhoneCallProtocol;\n public isOutgoing: boolean;\n public encryptionKey: Uint8Array;\n public connectionInstance: CallConnectionInstance;\n public encryptor: P2PEncryptor;\n public decryptor: P2PEncryptor;\n public candidates: RTCIceCandidate[];\n\n public offerReceived: boolean;\n public offerSent: boolean;\n \n public createdParticipantEntries: boolean;\n public release: () => Promise<void>;\n public _connectionState: CALL_STATE;\n\n public createdAt: number;\n public connectedAt: number;\n public discardReason: string;\n\n private appCallsManager: AppCallsManager;\n private apiManager: ApiManagerProxy;\n private apiUpdatesManager: ApiUpdatesManager;\n \n private hangUpTimeout: number;\n\n private mediaStates: {\n input: CallMediaState,\n output?: CallMediaState\n };\n\n private sendMediaState: () => Promise<void>;\n\n private decryptQueue: Uint8Array[];\n \n private getEmojisFingerprintPromise: Promise<CallInstance['emojisFingerprint']>;\n private emojisFingerprint: [string, string, string, string];\n\n private wasStartingScreen: boolean;\n private wasStartingVideo: boolean;\n public wasTryingToJoin: boolean;\n\n public streamManager: StreamManager;\n\n constructor(options: {\n isOutgoing: boolean,\n interlocutorUserId: UserId,\n appCallsManager: CallInstance['appCallsManager'],\n apiManager: CallInstance['apiManager'],\n apiUpdatesManager: CallInstance['apiUpdatesManager'],\n protocol?: PhoneCallProtocol\n }) {\n super();\n\n this.log = logger('CALL');\n\n if(!this.protocol) {\n this.protocol = getCallProtocol();\n }\n\n safeAssign(this, options);\n \n this.createdAt = Date.now();\n this.offerReceived = false;\n this.offerSent = false;\n this.decryptQueue = [];\n this.candidates = [];\n\n this.addEventListener('state', (state) => {\n this.log('state', CALL_STATE[state]);\n\n if(state === CALL_STATE.CLOSED) {\n this.cleanup();\n }\n });\n\n const streamManager = this.streamManager = new StreamManager(GROUP_CALL_AMPLITUDE_ANALYSE_INTERVAL_MS);\n streamManager.direction = 'sendrecv';\n streamManager.types.push('screencast');\n if(!this.isOutgoing) {\n streamManager.locked = true;\n streamManager.canCreateConferenceEntry = false;\n }\n\n let mediaState: CallMediaState = {\n '@type': 'MediaState',\n type: 'input',\n lowBattery: false,\n muted: true,\n screencastState: 'inactive',\n videoRotation: 0,\n videoState: 'inactive'\n };\n\n const self = this;\n mediaState = new Proxy(mediaState, {\n set: function(target, key, value) {\n // @ts-ignore\n target[key] = value;\n self.setMediaState(mediaState);\n self.sendMediaState();\n return true;\n }\n });\n\n this.mediaStates = {\n input: mediaState\n };\n\n this.sendMediaState = debounce(this._sendMediaState.bind(this), 0, false, true);\n }\n\n get connectionState() {\n const {_connectionState, connectionInstance} = this;\n if(_connectionState !== undefined) {\n return _connectionState;\n } else if(!connectionInstance) {\n return CALL_STATE.CONNECTING;\n } else {\n const {iceConnectionState} = connectionInstance.connection;\n if(iceConnectionState === 'closed') {\n return CALL_STATE.CLOSED;\n } else if(iceConnectionState !== 'connected' && (!IS_SAFARI || iceConnectionState !== 'completed')) {\n return CALL_STATE.CONNECTING;\n } else {\n return CALL_STATE.CONNECTED;\n }\n }\n }\n\n get sortIndex() {\n const connectionState = this.connectionState;\n const state = CALL_STATE.CLOSED - connectionState + 1;\n let index = state * 10000000000000;\n index += 2147483647000 - (connectionState === CALL_STATE.PENDING && this.isOutgoing ? 0 : this.createdAt);\n return index;\n }\n\n public getVideoElement(type: CallMediaState['type']) {\n if(type === 'input') return this.elements.get('main');\n else {\n const mediaState = this.getMediaState('output');\n if(!mediaState) {\n return;\n }\n\n const type: WebRTCLineType = mediaState.videoState === 'active' ? 'video' : (mediaState.screencastState === 'active' ? 'screencast' : undefined);\n if(!type) {\n return;\n }\n\n const entry = this.description.findEntry((entry) => entry.type === type);\n if(!entry) {\n return;\n }\n\n return this.elements.get('' + entry.recvEntry.source);\n }\n }\n\n public async startScreenSharingInternal() {\n try {\n this.wasStartingScreen = true;\n this.wasStartingVideo = false;\n this.streamManager.types = ['audio', 'screencast'];\n await this.requestScreen();\n } catch(err) {\n this.log.error('startScreenSharing error', err);\n }\n }\n\n public async toggleScreenSharing() {\n if(this.isSharingVideo) {\n await this.stopVideoSharing();\n }\n\n if(this.isSharingScreen) {\n return this.stopVideoSharing();\n } else {\n return this.startScreenSharingInternal();\n }\n }\n\n public async startVideoSharingInternal() {\n try {\n this.wasStartingScreen = false;\n this.wasStartingVideo = true;\n this.streamManager.types = ['audio', 'video'];\n await this.requestInputSource(false, true, false);\n } catch(err) {\n this.log.error('startVideoSharing error', err);\n }\n }\n\n public async stopVideoSharing() {\n const mediaState = this.getMediaState('input');\n mediaState.videoState = mediaState.screencastState = 'inactive';\n\n const {streamManager, description} = this;\n const track = streamManager.inputStream.getVideoTracks()[0];\n if(track) {\n stopTrack(track);\n streamManager.appendToConference(description); // clear sender track\n }\n }\n\n public async toggleVideoSharing() {\n if(this.isSharingScreen) {\n await this.stopVideoSharing();\n }\n\n if(this.isSharingVideo) {\n return this.stopVideoSharing();\n } else {\n return this.startVideoSharingInternal();\n }\n }\n\n public getMediaState(type: CallMediaState['type']) {\n return this.mediaStates[type];\n }\n\n public setMediaState(mediaState: CallMediaState) {\n this.mediaStates[mediaState.type] = mediaState;\n this.dispatchEvent('mediaState', mediaState);\n }\n\n public isSharingVideoType(type: 'video' | 'screencast') {\n try {\n const hasVideoTrack = super.isSharingVideo;\n return hasVideoTrack && !!((this.wasStartingScreen && type === 'screencast') || (this.wasStartingVideo && type === 'video'));\n\n // ! it will be used before the track appears\n // return !!this.description.entries.find(entry => entry.type === type && entry.transceiver.sender.track.enabled);\n } catch(err) {\n return false;\n }\n }\n\n public get isSharingVideo() {\n return this.isSharingVideoType('video');\n }\n\n public get isSharingScreen() {\n return this.isSharingVideoType('screencast');\n }\n\n public get isMuted() {\n const audioTrack = this.streamManager.inputStream.getAudioTracks()[0];\n return !audioTrack?.enabled;\n }\n\n public get isClosing() {\n const {connectionState} = this;\n return connectionState === CALL_STATE.CLOSING || connectionState === CALL_STATE.CLOSED;\n }\n\n public get description(): localConferenceDescription {\n return this.connectionInstance?.description;\n }\n\n public setHangUpTimeout(timeout: number, reason: PhoneCallDiscardReason['_']) {\n this.clearHangUpTimeout();\n this.hangUpTimeout = ctx.setTimeout(() => {\n this.hangUpTimeout = undefined;\n this.hangUp(reason);\n }, timeout);\n }\n\n public clearHangUpTimeout() {\n if(this.hangUpTimeout !== undefined) {\n clearTimeout(this.hangUpTimeout);\n this.hangUpTimeout = undefined;\n }\n }\n\n public setPhoneCall(phoneCall: PhoneCall) {\n this.call = phoneCall;\n\n const {id} = phoneCall;\n if(this.id !== id) {\n const prevId = this.id;\n this.id = id;\n this.dispatchEvent('id', id, prevId);\n }\n }\n\n public async acceptCall() {\n const canAccept = (await Promise.all(this.dispatchResultableEvent('acceptCallOverride')))[0] ?? true;\n if(this.isClosing || !canAccept) {\n return;\n }\n \n // this.clearHangUpTimeout();\n this.overrideConnectionState(CALL_STATE.EXCHANGING_KEYS);\n\n const call = this.call as PhoneCall.phoneCallRequested;\n this.requestInputSource(true, !!call.pFlags.video, false);\n\n const g_a_hash = call.g_a_hash;\n this.appCallsManager.generateDh().then(dh => {\n this.dh = { // ! it is correct\n g_a_hash,\n b: dh.a,\n g_b: dh.g_a,\n g_b_hash: dh.g_a_hash,\n p: dh.p,\n };\n\n return this.apiManager.invokeApi('phone.acceptCall', {\n peer: this.appCallsManager.getCallInput(this.id),\n protocol: this.protocol,\n g_b: this.dh.g_b\n });\n }).then(phonePhoneCall => {\n this.appCallsManager.savePhonePhoneCall(phonePhoneCall);\n }).catch(err => {\n this.log.error('accept call error', err);\n // if(err.type === 'CALL_PROTOCOL_COMPAT_LAYER_INVALID') {\n\n // }\n\n this.hangUp('phoneCallDiscardReasonHangup');\n });\n }\n\n public joinCall() {\n this.log('joinCall');\n\n this.getEmojisFingerprint();\n\n this.overrideConnectionState();\n \n const {isOutgoing, encryptionKey, streamManager} = this;\n \n const configuration = getRtcConfiguration(this.call as PhoneCall.phoneCall);\n this.log('joinCall configuration', configuration);\n if(!configuration) return;\n\n const connectionInstance = this.connectionInstance = new CallConnectionInstance({\n call: this,\n streamManager,\n log: this.log.bindPrefix('connection'),\n });\n\n const connection = connectionInstance.createPeerConnection(configuration);\n connection.addEventListener('iceconnectionstatechange', () => {\n const state = this.connectionState;\n if(this.connectedAt === undefined && state === CALL_STATE.CONNECTED) {\n this.connectedAt = Date.now();\n }\n \n this.dispatchEvent('state', state);\n });\n connection.addEventListener('negotiationneeded', () => {\n connectionInstance.negotiate();\n });\n connection.addEventListener('icecandidate', (event) => {\n const {candidate} = event;\n connection.log('onicecandidate', candidate);\n if(candidate?.candidate) {\n this.sendIceCandidate(candidate);\n }\n });\n connection.addEventListener('track', (event) => {\n const {track} = event;\n connection.log('ontrack', track);\n this.onTrack(event);\n });\n\n const description = connectionInstance.createDescription();\n \n this.encryptor = new P2PEncryptor(isOutgoing, encryptionKey);\n this.decryptor = new P2PEncryptor(!isOutgoing, encryptionKey);\n\n this.log('currentCall', this);\n\n if(isOutgoing) {\n connectionInstance.appendStreamToConference();\n }\n \n this.createDataChannel();\n\n this.processDecryptQueue();\n }\n\n private createDataChannelEntry() {\n const dataChannelEntry = this.description.createEntry('application');\n dataChannelEntry.setDirection('sendrecv');\n dataChannelEntry.sendEntry = dataChannelEntry.recvEntry = dataChannelEntry; \n }\n\n private createDataChannel() {\n if(this.connectionInstance.dataChannel) {\n return;\n }\n\n const channel = this.connectionInstance.createDataChannel({\n id: 0,\n negotiated: true\n });\n channel.addEventListener('message', (e) => {\n this.applyDataChannelData(JSON.parse(e.data));\n });\n channel.addEventListener('open', () => {\n this.sendMediaState();\n });\n }\n\n private applyDataChannelData(data: CallMediaState) {\n switch(data['@type']) {\n case 'MediaState': {\n data.type = 'output';\n this.log('got output media state', data);\n this.setMediaState(data);\n break;\n }\n\n default:\n this.log.error('unknown data channel data:', data);\n break;\n }\n }\n\n private _sendMediaState() {\n const {connectionInstance} = this;\n if(!connectionInstance) return;\n\n const mediaState = {...this.getMediaState('input')};\n // mediaState.videoRotation = 90;\n delete mediaState.type;\n this.log('sendMediaState', mediaState);\n\n connectionInstance.sendDataChannelData(mediaState);\n }\n\n public async sendCallSignalingData(data: CallSignalingData) {\n /* if(data['@type'] === 'InitialSetup') {\n this.filterNotVP8(data);\n } */\n \n const json = JSON.stringify(data);\n const arr = new TextEncoder().encode(json);\n const {bytes} = await this.encryptor.encryptRawPacket(arr);\n \n this.log('sendCallSignalingData', this.id, json);\n await this.apiManager.invokeApi('phone.sendSignalingData', {\n peer: this.appCallsManager.getCallInput(this.id),\n data: bytes\n });\n }\n \n public sendIceCandidate(iceCandidate: RTCIceCandidate) {\n this.log('sendIceCandidate', iceCandidate);\n const {candidate, sdpMLineIndex} = iceCandidate;\n if(sdpMLineIndex !== 0) {\n return;\n }\n \n const parsed = p2pParseCandidate(candidate);\n // const parsed = {sdpString: candidate};\n /* if(parsed.address.ip !== '') {\n return;\n } */\n\n this.sendCallSignalingData({\n '@type': 'Candidates', \n candidates: [parsed]\n });\n }\n\n public async confirmCall() {\n const {appCallsManager, apiManager, protocol, id, call} = this;\n const dh = this.dh as DiffieHellmanInfo.a;\n\n // this.clearHangUpTimeout();\n this.overrideConnectionState(CALL_STATE.EXCHANGING_KEYS);\n const {key, key_fingerprint} = await appCallsManager.computeKey((call as PhoneCall.phoneCallAccepted).g_b, dh.a, dh.p);\n \n const phonePhoneCall = await apiManager.invokeApi('phone.confirmCall', {\n peer: appCallsManager.getCallInput(id),\n protocol: protocol,\n g_a: dh.g_a,\n key_fingerprint: key_fingerprint\n });\n \n this.encryptionKey = key;\n appCallsManager.savePhonePhoneCall(phonePhoneCall);\n this.joinCall();\n }\n\n public getEmojisFingerprint() {\n if(this.emojisFingerprint) return this.emojisFingerprint;\n if(this.getEmojisFingerprintPromise) return this.getEmojisFingerprintPromise;\n return this.getEmojisFingerprintPromise = this.apiManager.invokeCrypto('get-emojis-fingerprint', this.encryptionKey, this.dh.g_a).then(codePoints => {\n this.getEmojisFingerprintPromise = undefined;\n return this.emojisFingerprint = codePoints.map(codePoints => emojiFromCodePoints(codePoints)) as [string, string, string, string];\n });\n }\n\n private unlockStreamManager() {\n this.connectionInstance.streamManager.locked = false;\n this.connectionInstance.appendStreamToConference();\n }\n\n private async doTheMagic() {\n this.connectionInstance.appendStreamToConference();\n\n const connection = this.connectionInstance.connection;\n\n let answer = await connection.createAnswer();\n\n this.log('[sdp] local', answer.type, answer.sdp);\n await connection.setLocalDescription(answer);\n\n connection.getTransceivers().filter(transceiver => transceiver.direction === 'recvonly').forEach(transceiver => {\n const entry = this.connectionInstance.description.getEntryByMid(transceiver.mid);\n entry.transceiver = entry.recvEntry.transceiver = transceiver;\n transceiver.direction = 'sendrecv';\n });\n\n const isAnswer = false;\n\n const description = this.description;\n let bundle = description.entries.map(entry => entry.mid);\n const sdpDescription: RTCSessionDescriptionInit = {\n type: isAnswer ? 'answer' : 'offer',\n sdp: description.generateSdp({\n bundle,\n entries: description.entries.filter(entry => bundle.includes(entry.mid)),\n // isAnswer: isAnswer\n isAnswer: !isAnswer\n })\n };\n\n await connection.setRemoteDescription(sdpDescription);\n\n answer = await connection.createAnswer();\n\n await connection.setLocalDescription(answer);\n \n const initialSetup = parseSignalingData(parseSdp(answer.sdp));\n this.log('[InitialSetup] send 1');\n this.sendCallSignalingData(initialSetup);\n \n this.unlockStreamManager();\n }\n\n public overrideConnectionState(state?: CALL_STATE) {\n this._connectionState = state;\n this.dispatchEvent('state', this.connectionState);\n }\n\n public get duration() {\n return this.connectedAt !== undefined ? (Date.now() - this.connectedAt) / 1000 | 0 : 0;\n }\n\n protected onInputStream(stream: MediaStream): void {\n super.onInputStream(stream);\n\n const videoTrack = stream.getVideoTracks()[0];\n if(videoTrack) {\n const state = this.getMediaState('input');\n\n // handle starting camera\n if(!this.wasStartingScreen && !this.wasStartingVideo) {\n this.wasStartingVideo = true;\n }\n\n if(this.isSharingVideo) {\n state.videoState = 'active';\n } else if(this.isSharingScreen) {\n state.screencastState = 'active';\n }\n\n videoTrack.addEventListener('ended', () => {\n this.stopVideoSharing();\n }, {once: true});\n }\n\n if(stream.getAudioTracks().length) {\n this.onMutedChange();\n }\n }\n \n private onMutedChange() {\n const isMuted = this.isMuted;\n this.dispatchEvent('muted', isMuted);\n\n const state = this.getMediaState('input');\n state.muted = isMuted;\n }\n\n public toggleMuted(): Promise<void> {\n return this.requestAudioSource(true).then(() => {\n this.setMuted();\n this.onMutedChange();\n });\n }\n\n public async hangUp(discardReason?: PhoneCallDiscardReason['_'], discardedByOtherParty?: boolean) {\n if(this.isClosing) {\n return;\n }\n\n this.discardReason = discardReason;\n this.log('hangUp', discardReason);\n this.overrideConnectionState(CALL_STATE.CLOSED);\n\n if(this.connectionInstance) {\n this.connectionInstance.closeConnectionAndStream(true);\n }\n\n if(discardReason && !discardedByOtherParty) {\n let hasVideo = false;\n for(const type in this.mediaStates) {\n const mediaState = this.mediaStates[type as 'input' | 'output'];\n hasVideo = mediaState.videoState === 'active' || mediaState.screencastState === 'active' || hasVideo;\n }\n\n await this.appCallsManager.discardCall(this.id, this.duration, discardReason, hasVideo);\n }\n }\n\n private performCodec(_codec: P2PAudioCodec | P2PVideoCodec) {\n const payloadTypes: AudioCodec['payload-types'] = _codec.payloadTypes.map(payloadType => {\n return {\n ...payloadType,\n 'rtcp-fbs': payloadType.feedbackTypes\n }\n });\n \n const codec: AudioCodec = {\n 'rtp-hdrexts': _codec.rtpExtensions,\n 'payload-types': payloadTypes\n };\n \n return codec;\n }\n\n private setDataToDescription(data: CallSignalingData.initialSetup) {\n this.description.setData({\n transport: {\n pwd: data.pwd,\n ufrag: data.ufrag,\n fingerprints: data.fingerprints,\n 'rtcp-mux': true\n },\n audio: this.performCodec(data.audio),\n video: data.video ? this.performCodec(data.video) as VideoCodec : undefined,\n screencast: data.screencast ? this.performCodec(data.screencast) as VideoCodec : undefined\n });\n }\n\n private filterNotVP8(initialSetup: CallSignalingData.initialSetup) {\n if(!this.isOutgoing) { // only VP8 works now\n [initialSetup.video, initialSetup.screencast].filter(Boolean).forEach(codec => {\n const payloadTypes = codec.payloadTypes;\n const idx = payloadTypes.findIndex(payloadType => payloadType.name === 'VP8');\n const vp8PayloadType = payloadTypes[idx];\n const rtxIdx = payloadTypes.findIndex(payloadType => +payloadType.parameters?.apt === vp8PayloadType.id);\n codec.payloadTypes = [payloadTypes[idx], payloadTypes[rtxIdx]];\n });\n }\n }\n\n public async applyCallSignalingData(data: CallSignalingData) {\n this.log('applyCallSignalingData', this, data);\n \n const {connection, description} = this.connectionInstance;\n\n switch(data['@type']) {\n case 'InitialSetup': {\n this.log('[sdp] InitialSetup', data);\n\n this.filterNotVP8(data);\n this.setDataToDescription(data);\n\n const performSsrcGroups = (ssrcGroups: P2PVideoCodec['ssrcGroups']): GroupCallParticipantVideoSourceGroup[] => {\n return ssrcGroups.map(ssrcGroup => {\n return {\n _: 'groupCallParticipantVideoSourceGroup',\n semantics: ssrcGroup.semantics,\n sources: ssrcGroup.ssrcs.map(source => +source)\n };\n });\n };\n\n const ssrcs = [\n generateSsrc('audio', +data.audio.ssrc),\n data.video ? generateSsrc('video', performSsrcGroups(data.video.ssrcGroups)) : undefined,\n data.screencast ? generateSsrc('screencast', performSsrcGroups(data.screencast.ssrcGroups)) : undefined\n ].filter(Boolean);\n\n ssrcs.forEach(ssrc => {\n let entry = description.getEntryBySource(ssrc.source);\n if(entry) {\n return;\n }\n \n const sendRecvEntry = description.findFreeSendRecvEntry(ssrc.type, false);\n entry = new ConferenceEntry(sendRecvEntry.mid, ssrc.type);\n entry.setDirection('sendrecv');\n sendRecvEntry.recvEntry = entry;\n\n description.setEntrySource(entry, ssrc.sourceGroups || ssrc.source);\n });\n\n this.createDataChannelEntry();\n\n const isAnswer = this.offerSent;\n this.offerSent = false;\n\n let bundle = description.entries.map(entry => entry.mid);\n const sdpDescription: RTCSessionDescriptionInit = {\n type: isAnswer ? 'answer' : 'offer',\n sdp: description.generateSdp({\n bundle,\n entries: description.entries.filter(entry => bundle.includes(entry.mid)),\n // isAnswer: isAnswer\n isAnswer: !isAnswer\n })\n };\n\n this.log('[sdp] remote', sdpDescription.sdp);\n\n await connection.setRemoteDescription(sdpDescription);\n\n await this.tryToReleaseCandidates();\n\n if(!isAnswer) {\n await this.doTheMagic();\n }\n\n break;\n }\n \n case 'Candidates': {\n for(const candidate of data.candidates) {\n const init: RTCIceCandidateInit = P2PSdpBuilder.generateCandidate(candidate);\n init.sdpMLineIndex = 0;\n const iceCandidate = new RTCIceCandidate(init);\n this.candidates.push(iceCandidate);\n }\n \n await this.tryToReleaseCandidates();\n break;\n }\n\n default: {\n this.log.error('unrecognized signaling data', data);\n }\n }\n }\n\n public async tryToReleaseCandidates() {\n const {connectionInstance} = this;\n if(!connectionInstance) {\n return;\n }\n\n const {connection} = connectionInstance;\n if(connection.remoteDescription) {\n const promises: Promise<void>[] = this.candidates.map(candidate => this.addIceCandidate(connection, candidate));\n this.candidates.length = 0;\n\n await Promise.all(promises);\n } else {\n this.log('[candidates] postpone');\n }\n }\n\n private async addIceCandidate(connection: RTCPeerConnection, candidate: RTCIceCandidate) {\n this.log('[candidate] start', candidate);\n try {\n // if(!candidate.address) return;\n await connection.addIceCandidate(candidate);\n this.log('[candidate] add', candidate);\n } catch(e) {\n this.log.error('[candidate] error', candidate, e);\n }\n }\n\n private async processDecryptQueue() {\n const {encryptor} = this;\n if(!encryptor) {\n this.log.warn('got encrypted signaling data before the encryption key');\n return;\n }\n\n const length = this.decryptQueue.length;\n if(!length) {\n return;\n }\n \n const queue = this.decryptQueue.slice();\n this.decryptQueue.length = 0;\n \n for(const data of queue) {\n const decryptedData = await encryptor.decryptRawPacket(data);\n if(!decryptedData) {\n continue;\n }\n\n // this.log('[update] updateNewCallSignalingData', update, decryptedData);\n \n const str = new TextDecoder().decode(decryptedData);\n try {\n const signalingData: CallSignalingData = JSON.parse(str);\n this.log('[update] updateNewCallSignalingData', signalingData);\n this.applyCallSignalingData(signalingData);\n } catch(err) {\n this.log.error('wrong signaling data', str);\n this.hangUp('phoneCallDiscardReasonDisconnect');\n rootScope.dispatchEvent('call_incompatible', this.interlocutorUserId);\n }\n }\n }\n\n public onUpdatePhoneCallSignalingData(update: Update.updatePhoneCallSignalingData) {\n this.decryptQueue.push(update.data);\n this.processDecryptQueue();\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n * \n * Originally from:\n * https://github.com/evgeny-nadymov/telegram-react\n * Copyright (C) 2018 Evgeny Nadymov\n * https://github.com/evgeny-nadymov/telegram-react/blob/master/LICENSE\n */\n\nimport { PhoneCallProtocol } from \"../../../layer\";\n\nexport default function getCallProtocol(): PhoneCallProtocol {\n return {\n _: 'phoneCallProtocol',\n pFlags: {\n udp_p2p: true,\n udp_reflector: true\n },\n min_layer: 92,\n max_layer: 92,\n library_versions: ['4.0.0']\n };\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n * \n * Originally from:\n * https://github.com/evgeny-nadymov/telegram-react\n * Copyright (C) 2018 Evgeny Nadymov\n * https://github.com/evgeny-nadymov/telegram-react/blob/master/LICENSE\n */\n\nimport { PhoneCall } from \"../../../layer\";\n\nexport default function getRtcConfiguration(call: PhoneCall.phoneCall): RTCConfiguration {\n const iceServers: RTCIceServer[] = [];\n call.connections.forEach((connection) => {\n switch(connection._) {\n /* case 'callServerTypeTelegramReflector': {\n break;\n } */\n case 'phoneConnectionWebrtc': {\n const {ip, ipv6, port, username, password} = connection;\n const urls: string[] = [];\n if(connection.pFlags.turn) {\n if(ip) {\n urls.push(`turn:${ip}:${port}`);\n }\n if(ipv6) {\n urls.push(`turn:[${ipv6}]:${port}`);\n }\n } else if(connection.pFlags.stun) {\n if(ip) {\n urls.push(`stun:${ip}:${port}`);\n }\n if(ipv6) {\n urls.push(`stun:[${ipv6}]:${port}`);\n }\n }\n \n if(urls.length > 0) {\n iceServers.push({\n urls,\n username,\n credential: password\n });\n }\n break;\n }\n }\n });\n \n return {\n iceServers,\n iceTransportPolicy: call.pFlags.p2p_allowed ? 'all' : 'relay'\n };\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport cancelEvent from \"../helpers/dom/cancelEvent\";\nimport { attachClickEvent } from \"../helpers/dom/clickEvent\";\nimport ListenerSetter from \"../helpers/listenerSetter\";\nimport type { AppGroupCallsManager } from \"../lib/appManagers/appGroupCallsManager\";\nimport GROUP_CALL_STATE from \"../lib/calls/groupCallState\";\nimport rootScope from \"../lib/rootScope\";\nimport ButtonIcon from \"./buttonIcon\";\nimport TopbarWeave from \"./topbarWeave\";\nimport SetTransition from \"./singleTransition\";\nimport PopupGroupCall from \"./groupCall\";\nimport type { AppPeersManager } from \"../lib/appManagers/appPeersManager\";\nimport type { AppChatsManager } from \"../lib/appManagers/appChatsManager\";\nimport GroupCallDescriptionElement from \"./groupCall/description\";\nimport GroupCallTitleElement from \"./groupCall/title\";\nimport PopupElement from \"./popups\";\nimport throttle from \"../helpers/schedulers/throttle\";\nimport GroupCallInstance from \"../lib/calls/groupCallInstance\";\nimport CALL_STATE from \"../lib/calls/callState\";\nimport replaceContent from \"../helpers/dom/replaceContent\";\nimport PeerTitle from \"./peerTitle\";\nimport CallDescriptionElement from \"./call/description\";\nimport PopupCall from \"./call\";\nimport type { AppAvatarsManager } from \"../lib/appManagers/appAvatarsManager\";\nimport GroupCallMicrophoneIconMini from \"./groupCall/microphoneIconMini\";\nimport CallInstance from \"../lib/calls/callInstance\";\nimport type { AppCallsManager } from \"../lib/appManagers/appCallsManager\";\n\nfunction convertCallStateToGroupState(state: CALL_STATE, isMuted: boolean) {\n switch(state) {\n case CALL_STATE.CLOSING:\n case CALL_STATE.CLOSED:\n return GROUP_CALL_STATE.CLOSED;\n case CALL_STATE.CONNECTED:\n return isMuted ? GROUP_CALL_STATE.MUTED : GROUP_CALL_STATE.UNMUTED;\n default:\n return GROUP_CALL_STATE.CONNECTING;\n }\n}\n\nconst CLASS_NAME = 'topbar-call';\n\nexport default class TopbarCall {\n public container: HTMLElement;\n private listenerSetter: ListenerSetter;\n private weave: TopbarWeave;\n private center: HTMLDivElement;\n private groupCallTitle: GroupCallTitleElement;\n private groupCallDescription: GroupCallDescriptionElement;\n private groupCallMicrophoneIconMini: GroupCallMicrophoneIconMini;\n private callDescription: CallDescriptionElement;\n \n private currentDescription: GroupCallDescriptionElement | CallDescriptionElement;\n\n private instance: GroupCallInstance | any/* CallInstance */;\n private instanceListenerSetter: ListenerSetter;\n \n constructor(\n private appGroupCallsManager: AppGroupCallsManager,\n private appPeersManager: AppPeersManager,\n private appChatsManager: AppChatsManager,\n private appAvatarsManager: AppAvatarsManager,\n private appCallsManager: AppCallsManager\n ) {\n const listenerSetter = this.listenerSetter = new ListenerSetter();\n\n listenerSetter.add(rootScope)('call_instance', ({instance}) => {\n if(!this.instance) {\n this.updateInstance(instance);\n }\n });\n\n listenerSetter.add(rootScope)('call_accepting', (instance) => {\n if(this.instance !== instance) {\n this.updateInstance(instance);\n }\n });\n\n listenerSetter.add(rootScope)('group_call_instance', (instance) => {\n this.updateInstance(instance);\n });\n \n listenerSetter.add(rootScope)('group_call_update', (groupCall) => {\n const instance = this.appGroupCallsManager.groupCall;\n if(instance?.id === groupCall.id) {\n this.updateInstance(instance);\n }\n });\n\n listenerSetter.add(rootScope)('group_call_amplitude', ({amplitudes, type}) => {\n const {weave} = this;\n if(!amplitudes.length || !weave/* || type !== 'input' */) return;\n\n let max = 0;\n for(let i = 0; i < amplitudes.length; ++i) {\n const {type, value} = amplitudes[i];\n max = value > max ? value : max;\n }\n\n weave.setAmplitude(max);\n });\n }\n\n private onState = () => {\n this.updateInstance(this.instance);\n };\n\n private clearCurrentInstance() {\n if(!this.instance) return;\n this.center.textContent = '';\n \n if(this.currentDescription) {\n this.currentDescription.detach();\n this.currentDescription = undefined;\n }\n\n this.instance = undefined;\n this.instanceListenerSetter.removeAll();\n }\n\n private updateInstance(instance: TopbarCall['instance']) {\n if(this.construct) {\n this.construct();\n this.construct = undefined;\n }\n\n const isChangingInstance = this.instance !== instance;\n if(isChangingInstance) {\n this.clearCurrentInstance();\n \n this.instance = instance;\n this.instanceListenerSetter = new ListenerSetter();\n\n this.instanceListenerSetter.add(instance as GroupCallInstance)('state', this.onState);\n\n if(instance instanceof GroupCallInstance) {\n this.currentDescription = this.groupCallDescription;\n } else {\n this.currentDescription = this.callDescription;\n this.instanceListenerSetter.add(instance)('muted', this.onState);\n }\n\n this.container.classList.toggle('is-call', !(instance instanceof GroupCallInstance));\n }\n\n const isMuted = this.instance.isMuted;\n let state = instance instanceof GroupCallInstance ? instance.state : convertCallStateToGroupState(instance.connectionState, isMuted);\n\n const {weave} = this;\n\n weave.componentDidMount();\n \n const isClosed = state === GROUP_CALL_STATE.CLOSED;\n if((!document.body.classList.contains('is-calling') || isChangingInstance) || isClosed) {\n if(isClosed) {\n weave.setAmplitude(0);\n }\n\n SetTransition(document.body, 'is-calling', !isClosed, 250, isClosed ? () => {\n weave.componentWillUnmount();\n\n this.clearCurrentInstance();\n }: undefined);\n }\n \n if(isClosed) {\n return;\n }\n \n weave.setCurrentState(state, true);\n // if(state === GROUP_CALL_STATE.CONNECTING) {\n // weave.setCurrentState(state, true);\n // } else {\n // /* var a = 0;\n // animate(() => {\n // a += 0.1;\n // if(a > 1) a = 0;\n // weave.setAmplitude(a);\n // return true;\n // });\n // weave.setAmplitude(1); */\n // weave.setCurrentState(state, true);\n // }\n \n this.setTitle(instance);\n this.setDescription(instance);\n this.groupCallMicrophoneIconMini.setState(!isMuted);\n }\n\n private setDescription(instance: TopbarCall['instance']) {\n return this.currentDescription.update(instance as any);\n }\n\n private setTitle(instance: TopbarCall['instance']) {\n if(instance instanceof GroupCallInstance) {\n return this.groupCallTitle.update(instance);\n } else {\n replaceContent(this.center, new PeerTitle({peerId: instance.interlocutorUserId.toPeerId()}).element);\n }\n }\n\n private construct() {\n const {listenerSetter} = this;\n const container = this.container = document.createElement('div');\n container.classList.add('sidebar-header', CLASS_NAME + '-container');\n\n const left = document.createElement('div');\n left.classList.add(CLASS_NAME + '-left');\n\n const groupCallMicrophoneIconMini = this.groupCallMicrophoneIconMini = new GroupCallMicrophoneIconMini();\n \n const mute = ButtonIcon();\n mute.append(groupCallMicrophoneIconMini.container);\n left.append(mute);\n\n const throttledMuteClick = throttle(() => {\n this.instance.toggleMuted();\n }, 600, true);\n \n attachClickEvent(mute, (e) => {\n cancelEvent(e);\n throttledMuteClick();\n }, {listenerSetter});\n \n const center = this.center = document.createElement('div');\n center.classList.add(CLASS_NAME + '-center');\n \n this.groupCallTitle = new GroupCallTitleElement(center);\n this.groupCallDescription = new GroupCallDescriptionElement(left);\n\n this.callDescription = new CallDescriptionElement(left);\n \n const right = document.createElement('div');\n right.classList.add(CLASS_NAME + '-right');\n \n const end = ButtonIcon('endcall_filled');\n right.append(end);\n \n attachClickEvent(end, (e) => {\n cancelEvent(e);\n\n const {instance} = this;\n if(!instance) {\n return;\n }\n\n if(instance instanceof GroupCallInstance) {\n instance.hangUp();\n } else {\n instance.hangUp('phoneCallDiscardReasonHangup');\n }\n }, {listenerSetter});\n\n attachClickEvent(container, () => {\n if(this.instance instanceof GroupCallInstance) {\n if(PopupElement.getPopups(PopupGroupCall).length) {\n return;\n }\n \n new PopupGroupCall({\n appGroupCallsManager: this.appGroupCallsManager,\n appPeersManager: this.appPeersManager,\n appChatsManager: this.appChatsManager\n }).show();\n } else if(this.instance instanceof CallInstance) {\n const popups = PopupElement.getPopups(PopupCall) as PopupCall[];\n if(popups.find(popup => popup.getCallInstance() === this.instance)) {\n return;\n }\n\n new PopupCall({\n appCallsManager: this.appCallsManager,\n appAvatarsManager: this.appAvatarsManager,\n appPeersManager: this.appPeersManager,\n instance: this.instance\n }).show();\n }\n }, {listenerSetter});\n \n container.append(left, center, right);\n\n const weave = this.weave = new TopbarWeave();\n const weaveContainer = weave.render(CLASS_NAME + '-weave');\n container.prepend(weaveContainer);\n \n document.getElementById('column-center').prepend(container);\n weave.componentDidMount();\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n * \n * Originally from:\n * https://github.com/evgeny-nadymov/telegram-react\n * Copyright (C) 2018 Evgeny Nadymov\n * https://github.com/evgeny-nadymov/telegram-react/blob/master/LICENSE\n */\n\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\nimport IS_CALL_SUPPORTED from \"../../environment/callSupport\";\nimport indexOfAndSplice from \"../../helpers/array/indexOfAndSplice\";\nimport insertInDescendSortedArray from \"../../helpers/array/insertInDescendSortedArray\";\nimport AudioAssetPlayer from \"../../helpers/audioAssetPlayer\";\nimport bytesCmp from \"../../helpers/bytes/bytesCmp\";\nimport compareVersion from \"../../helpers/compareVersion\";\nimport safeReplaceObject from \"../../helpers/object/safeReplaceObject\";\nimport { nextRandomUint } from \"../../helpers/random\";\nimport tsNow from \"../../helpers/tsNow\";\nimport { InputPhoneCall, MessagesDhConfig, PhoneCall, PhoneCallDiscardReason, PhoneCallProtocol, PhonePhoneCall } from \"../../layer\";\nimport CallInstance from \"../calls/callInstance\";\nimport CALL_STATE from \"../calls/callState\";\nimport getCallProtocol from \"../calls/p2P/getCallProtocol\";\nimport { logger } from \"../logger\";\nimport apiManager from \"../mtproto/mtprotoworker\";\nimport { NULL_PEER_ID } from \"../mtproto/mtproto_config\";\nimport rootScope from \"../rootScope\";\nimport apiUpdatesManager from \"./apiUpdatesManager\";\nimport appProfileManager from \"./appProfileManager\";\nimport appUsersManager from \"./appUsersManager\";\n\nexport type CallId = PhoneCall['id'];\n\nexport type MyPhoneCall = Exclude<PhoneCall, PhoneCall.phoneCallEmpty | PhoneCall.phoneCallDiscarded>;\n\nconst CALL_REQUEST_TIMEOUT = 45e3;\n\nexport type CallAudioAssetName = \"call_busy.mp3\" | \"call_connect.mp3\" | \"call_end.mp3\" | \"call_incoming.mp3\" | \"call_outgoing.mp3\" | \"voip_failed.mp3\" | \"voip_connecting.mp3\";\n\nexport class AppCallsManager {\n private log: ReturnType<typeof logger>;\n private calls: Map<CallId, MyPhoneCall>;\n private instances: Map<CallId, CallInstance>;\n private sortedInstances: Array<CallInstance>;\n private tempId: number;\n private audioAsset: AudioAssetPlayer<CallAudioAssetName>;\n \n constructor() {\n this.log = logger('CALLS');\n \n this.tempId = 0;\n this.calls = new Map();\n this.instances = new Map();\n this.sortedInstances = [];\n\n if(!IS_CALL_SUPPORTED) {\n return;\n }\n \n rootScope.addMultipleEventsListeners({\n updatePhoneCall: async(update) => {\n const call = this.saveCall(update.phone_call);\n\n let instance = this.instances.get(call.id);\n \n switch(call._) {\n case 'phoneCallDiscarded': {\n if(instance) {\n instance.hangUp(call.reason?._, true);\n }\n\n break;\n }\n\n case 'phoneCallAccepted': {\n if(instance) {\n /* if(!this.verifyProtocolCompatibility(call.protocol)) {\n instance.hangUp('phoneCallDiscardReasonDisconnect');\n rootScope.dispatchEvent('call_incompatible', instance.interlocutorUserId);\n break;\n } */\n\n instance.confirmCall();\n }\n\n break;\n }\n \n case 'phoneCallRequested': {\n if(!instance) {\n /* if(!this.verifyProtocolCompatibility(call.protocol)) {\n rootScope.dispatchEvent('call_incompatible', call.admin_id);\n break;\n } */\n\n instance = this.createCallInstance({\n isOutgoing: false,\n interlocutorUserId: call.admin_id\n });\n \n instance.overrideConnectionState(CALL_STATE.PENDING);\n instance.setPhoneCall(call);\n instance.setHangUpTimeout(CALL_REQUEST_TIMEOUT, 'phoneCallDiscardReasonMissed');\n }\n \n break;\n }\n\n case 'phoneCall': {\n if(!instance || instance.encryptionKey) {\n break;\n }\n\n const g_a = instance.dh.g_a = call.g_a_or_b;\n const dh = instance.dh;\n const g_a_hash = await apiManager.invokeCrypto('sha256', g_a);\n if(!bytesCmp(dh.g_a_hash, g_a_hash)) {\n this.log.error('Incorrect g_a_hash', dh.g_a_hash, g_a_hash);\n break;\n }\n\n const {key, key_fingerprint} = await this.computeKey(g_a, dh.b, dh.p);\n if(call.key_fingerprint !== key_fingerprint) {\n this.log.error('Incorrect key fingerprint', call.key_fingerprint, key_fingerprint);\n break;\n }\n\n instance.encryptionKey = key;\n instance.joinCall();\n\n break;\n }\n }\n },\n \n updatePhoneCallSignalingData: (update) => {\n const instance = this.instances.get(update.phone_call_id);\n if(instance?.id !== update.phone_call_id) {\n return;\n }\n \n instance.onUpdatePhoneCallSignalingData(update);\n }\n });\n\n this.audioAsset = new AudioAssetPlayer<CallAudioAssetName>([\n 'call_busy.mp3',\n 'call_connect.mp3',\n 'call_end.mp3',\n 'call_incoming.mp3',\n 'call_outgoing.mp3',\n 'voip_failed.mp3'\n ]);\n }\n\n public get currentCall() {\n return this.sortedInstances[0];\n }\n\n public getCallByUserId(userId: UserId) {\n for(const [callId, instance] of this.instances) {\n if(instance.interlocutorUserId === userId) {\n return instance;\n }\n }\n }\n\n public async computeKey(g_b: Uint8Array, a: Uint8Array, p: Uint8Array) {\n return apiManager.invokeCrypto('compute-dh-key', g_b, a, p);\n }\n \n public saveCall(call: PhoneCall) {\n const isDiscarded = call._ === 'phoneCallDiscarded';\n const oldCall = this.calls.get(call.id);\n if(oldCall) {\n // if(shouldUpdate) {\n safeReplaceObject(oldCall, call);\n // }\n\n if(isDiscarded) {\n this.calls.delete(call.id);\n }\n \n call = oldCall;\n } else if(!isDiscarded) {\n this.calls.set(call.id, call as any);\n }\n\n return call;\n }\n \n public getCall(callId: CallId) {\n return this.calls.get(callId);\n }\n \n public getCallInput(id: CallId): InputPhoneCall {\n const call = this.getCall(id);\n return {\n _: 'inputPhoneCall',\n id: call.id,\n access_hash: call.access_hash\n };\n }\n \n private createCallInstance(options: {\n isOutgoing: boolean,\n interlocutorUserId: UserId,\n protocol?: PhoneCallProtocol\n }) {\n const call = new CallInstance({\n appCallsManager: this,\n apiManager,\n apiUpdatesManager,\n ...options,\n });\n\n call.addEventListener('state', (state) => {\n const currentCall = this.currentCall;\n if(state === CALL_STATE.CLOSED) {\n this.instances.delete(call.id);\n indexOfAndSplice(this.sortedInstances, call);\n } else {\n insertInDescendSortedArray(this.sortedInstances, call, 'sortIndex');\n }\n\n if(state === CALL_STATE.EXCHANGING_KEYS) {\n call.wasTryingToJoin = true;\n }\n\n const hasConnected = call.connectedAt !== undefined;\n if(state === CALL_STATE.EXCHANGING_KEYS || (state === CALL_STATE.CONNECTING && hasConnected)) {\n call.setHangUpTimeout(CALL_REQUEST_TIMEOUT, 'phoneCallDiscardReasonDisconnect');\n } else {\n call.clearHangUpTimeout();\n }\n\n if(currentCall === call || !currentCall) {\n if(state === CALL_STATE.CLOSED) {\n if(!call.isOutgoing && !call.wasTryingToJoin) { // incoming call has been accepted on other device or ended\n this.audioAsset.stopSound();\n } else if(call.wasTryingToJoin && !hasConnected) { // something has happened during the key exchanging\n this.audioAsset.playSound('voip_failed.mp3');\n } else {\n this.audioAsset.playSound(call.discardReason === 'phoneCallDiscardReasonBusy' ? 'call_busy.mp3' : 'call_end.mp3');\n }\n } else if(state === CALL_STATE.PENDING) {\n this.audioAsset.playSound(call.isOutgoing ? 'call_outgoing.mp3' : 'call_incoming.mp3', true);\n } else if(state === CALL_STATE.EXCHANGING_KEYS) {\n this.audioAsset.playSoundIfDifferent('call_connect.mp3');\n } else if(state === CALL_STATE.CONNECTING) {\n if(call.duration) {\n this.audioAsset.playSound('voip_connecting.mp3', true);\n }\n } else {\n this.audioAsset.stopSound();\n }\n }\n });\n\n call.addEventListener('id', (id, prevId) => {\n if(prevId !== undefined) {\n this.instances.delete(prevId);\n }\n\n const hasCurrent = !!this.currentCall;\n this.instances.set(id, call);\n\n if(prevId === undefined) {\n rootScope.dispatchEvent('call_instance', {instance: call, hasCurrent: hasCurrent});\n }\n });\n\n return call;\n }\n\n public savePhonePhoneCall(phonePhoneCall: PhonePhoneCall) {\n appUsersManager.saveApiUsers(phonePhoneCall.users);\n return this.saveCall(phonePhoneCall.phone_call);\n }\n\n public generateDh() {\n return apiManager.invokeApi('messages.getDhConfig', {\n version: 0,\n random_length: 256\n }).then(async(dhConfig) => {\n return apiManager.invokeCrypto('generate-dh', dhConfig as MessagesDhConfig.messagesDhConfig);\n });\n }\n \n public startCallInternal(userId: UserId, isVideo: boolean) {\n this.log('p2pStartCallInternal', userId, isVideo);\n \n const fullInfo = appProfileManager.getCachedFullUser(userId);\n if(!fullInfo) return;\n \n const {video_calls_available} = fullInfo.pFlags;\n \n const call = this.createCallInstance({\n isOutgoing: true,\n interlocutorUserId: userId\n });\n\n call.requestInputSource(true, !!(isVideo && video_calls_available), false);\n\n call.overrideConnectionState(CALL_STATE.REQUESTING);\n call.setPhoneCall({\n _: 'phoneCallWaiting',\n access_hash: '',\n admin_id: NULL_PEER_ID,\n date: tsNow(true),\n id: --this.tempId,\n participant_id: userId,\n protocol: call.protocol,\n pFlags: {\n video: isVideo || undefined\n }\n });\n\n // return;\n this.generateDh().then(dh => {\n call.dh = dh;\n\n return apiManager.invokeApi('phone.requestCall', {\n user_id: appUsersManager.getUserInput(userId),\n protocol: call.protocol,\n video: isVideo && video_calls_available,\n random_id: nextRandomUint(32),\n g_a_hash: call.dh.g_a_hash\n });\n }).then(result => {\n const phoneCall = this.savePhonePhoneCall(result);\n call.overrideConnectionState(CALL_STATE.PENDING);\n call.setPhoneCall(phoneCall);\n call.setHangUpTimeout(CALL_REQUEST_TIMEOUT, 'phoneCallDiscardReasonHangup');\n });\n }\n\n private verifyProtocolCompatibility(protocol: PhoneCallProtocol) {\n const my = getCallProtocol();\n const myVersion = my.library_versions[0];\n return !protocol.library_versions.find(version => {\n return compareVersion(myVersion, version) > 0;\n });\n }\n\n public async discardCall(callId: CallId, duration: number, reason: PhoneCallDiscardReason['_'], video?: boolean) {\n if(!this.getCall(callId)) {\n return;\n }\n\n const updates = await apiManager.invokeApi('phone.discardCall', {\n video,\n peer: this.getCallInput(callId),\n duration,\n reason: {\n _: reason\n },\n connection_id: '0'\n });\n\n apiUpdatesManager.processUpdateMessage(updates);\n }\n}\n\nconst appCallsManager = new AppCallsManager();\nMOUNT_CLASS_TO && (MOUNT_CLASS_TO.appCallsManager = appCallsManager);\nexport default appCallsManager;\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\n//import apiManager from '../mtproto/apiManager';\nimport animationIntersector from '../../components/animationIntersector';\nimport appSidebarLeft, { LEFT_COLUMN_ACTIVE_CLASSNAME } from \"../../components/sidebarLeft\";\nimport appSidebarRight, { RIGHT_COLUMN_ACTIVE_CLASSNAME } from '../../components/sidebarRight';\nimport mediaSizes, { ScreenSize } from '../../helpers/mediaSizes';\nimport { logger, LogTypes } from \"../logger\";\nimport apiManager from '../mtproto/mtprotoworker';\nimport rootScope from '../rootScope';\nimport apiUpdatesManager from './apiUpdatesManager';\nimport appUsersManager from \"./appUsersManager\";\nimport Chat, { ChatType } from '../../components/chat/chat';\nimport appChatsManager from './appChatsManager';\nimport appDocsManager from './appDocsManager';\nimport appInlineBotsManager from './appInlineBotsManager';\nimport appMessagesManager from './appMessagesManager';\nimport appPeersManager from './appPeersManager';\nimport appPhotosManager from './appPhotosManager';\nimport appProfileManager from './appProfileManager';\nimport appStickersManager from './appStickersManager';\nimport appWebPagesManager from './appWebPagesManager';\nimport PopupNewMedia, { getCurrentNewMediaPopup } from '../../components/popups/newMedia';\nimport MarkupTooltip from '../../components/chat/markupTooltip';\nimport { IS_TOUCH_SUPPORTED } from '../../environment/touchSupport';\nimport appPollsManager from './appPollsManager';\nimport SetTransition from '../../components/singleTransition';\nimport ChatDragAndDrop from '../../components/chat/dragAndDrop';\nimport { doubleRaf } from '../../helpers/schedulers';\nimport lottieLoader from '../rlottie/lottieLoader';\nimport useHeavyAnimationCheck, { dispatchHeavyAnimationEvent } from '../../hooks/useHeavyAnimationCheck';\nimport appDraftsManager from './appDraftsManager';\nimport serverTimeManager from '../mtproto/serverTimeManager';\nimport stateStorage from '../stateStorage';\nimport appDownloadManager from './appDownloadManager';\nimport appStateManager, { AppStateManager, STATE_INIT } from './appStateManager';\nimport { MOUNT_CLASS_TO } from '../../config/debug';\nimport appNavigationController from '../../components/appNavigationController';\nimport appNotificationsManager from './appNotificationsManager';\nimport AppPrivateSearchTab from '../../components/sidebarRight/tabs/search';\nimport I18n, { i18n, join, LangPackKey } from '../langPack';\nimport { ChatInvite, Dialog, Message, SendMessageAction } from '../../layer';\nimport { hslaStringToHex } from '../../helpers/color';\nimport { getFilesFromEvent } from '../../helpers/files';\nimport PeerTitle from '../../components/peerTitle';\nimport PopupPeer from '../../components/popups/peer';\nimport { SliceEnd } from '../../helpers/slicedArray';\nimport blurActiveElement from '../../helpers/dom/blurActiveElement';\nimport cancelEvent from '../../helpers/dom/cancelEvent';\nimport disableTransition from '../../helpers/dom/disableTransition';\nimport placeCaretAtEnd from '../../helpers/dom/placeCaretAtEnd';\nimport replaceContent from '../../helpers/dom/replaceContent';\nimport whichChild from '../../helpers/dom/whichChild';\nimport appEmojiManager from './appEmojiManager';\nimport PopupElement from '../../components/popups';\nimport singleInstance from '../mtproto/singleInstance';\nimport PopupStickers from '../../components/popups/stickers';\nimport PopupJoinChatInvite from '../../components/popups/joinChatInvite';\nimport { toast, toastNew } from '../../components/toast';\nimport debounce from '../../helpers/schedulers/debounce';\nimport pause from '../../helpers/schedulers/pause';\nimport appMessagesIdsManager from './appMessagesIdsManager';\nimport { InternalLink, InternalLinkTypeMap, INTERNAL_LINK_TYPE } from './internalLink';\nimport RichTextProcessor from '../richtextprocessor';\nimport MEDIA_MIME_TYPES_SUPPORTED from '../../environment/mediaMimeTypesSupport';\nimport { NULL_PEER_ID } from '../mtproto/mtproto_config';\nimport telegramMeWebManager from '../mtproto/telegramMeWebManager';\nimport { ONE_DAY } from '../../helpers/date';\nimport appGroupCallsManager, { GroupCallId, MyGroupCall } from './appGroupCallsManager';\nimport TopbarCall from '../../components/topbarCall';\nimport confirmationPopup from '../../components/confirmationPopup';\nimport IS_GROUP_CALL_SUPPORTED from '../../environment/groupCallSupport';\nimport appAvatarsManager from './appAvatarsManager';\nimport appCallsManager from './appCallsManager';\nimport IS_CALL_SUPPORTED from '../../environment/callSupport';\nimport { CallType } from '../calls/types';\nimport { Modify, SendMessageEmojiInteractionData } from '../../types';\nimport htmlToSpan from '../../helpers/dom/htmlToSpan';\nimport getVisibleRect from '../../helpers/dom/getVisibleRect';\nimport { simulateClickEvent } from '../../helpers/dom/clickEvent';\nimport appReactionsManager from './appReactionsManager';\nimport PopupCall from '../../components/call';\nimport copy from '../../helpers/object/copy';\nimport getObjectKeysAndSort from '../../helpers/object/getObjectKeysAndSort';\nimport type GroupCallInstance from '../calls/groupCallInstance';\nimport type CallInstance from '../calls/callInstance';\nimport numberThousandSplitter from '../../helpers/number/numberThousandSplitter';\nimport ChatBackgroundPatternRenderer from '../../components/chat/patternRenderer';\nimport { IS_FIREFOX } from '../../environment/userAgent';\nimport compareVersion from '../../helpers/compareVersion';\n\n//console.log('appImManager included33!');\n\nappSidebarLeft; // just to include\n\nexport const CHAT_ANIMATION_GROUP = 'chat';\nconst FOCUS_EVENT_NAME = IS_TOUCH_SUPPORTED ? 'touchstart' : 'mousemove';\n\nexport type ChatSavedPosition = {\n mids: number[], \n top: number\n};\n\nexport type ChatSetPeerOptions = {\n peerId?: PeerId, \n lastMsgId?: number, \n threadId?: number,\n startParam?: string\n};\n\nexport type ChatSetInnerPeerOptions = Modify<ChatSetPeerOptions, {\n peerId: PeerId\n}> & {\n type?: ChatType\n};\n\nexport class AppImManager {\n public columnEl = document.getElementById('column-center') as HTMLDivElement;\n public chatsContainer: HTMLElement;\n\n public offline = false;\n public updateStatusInterval = 0;\n\n public log: ReturnType<typeof logger>;\n\n public setPeerPromise: Promise<void> = null;\n\n public tabId = -1;\n \n public chats: Chat[] = [];\n private prevTab: HTMLElement;\n private chatsSelectTabDebounced: () => void;\n \n public markupTooltip: MarkupTooltip;\n private backgroundPromises: {[slug: string]: Promise<string>};\n \n private topbarCall: TopbarCall;\n public emojiAnimationContainer: HTMLDivElement;\n\n private lastBackgroundUrl: string;\n\n get myId() {\n return rootScope.myId;\n }\n\n get chat(): Chat {\n return this.chats[this.chats.length - 1];\n }\n\n constructor() {\n apiUpdatesManager.attach(I18n.lastRequestedLangCode);\n appNotificationsManager.start();\n\n this.log = logger('IM', LogTypes.Log | LogTypes.Warn | LogTypes.Debug | LogTypes.Error);\n\n this.backgroundPromises = {};\n STATE_INIT.settings.themes.forEach(theme => {\n if(theme.background.slug) {\n const url = 'assets/img/' + theme.background.slug + '.svg' + (IS_FIREFOX ? '?1' : '');\n this.backgroundPromises[theme.background.slug] = Promise.resolve(url);\n }\n });\n\n this.selectTab(0);\n \n window.addEventListener('blur', () => {\n animationIntersector.checkAnimations(true);\n \n this.offline = rootScope.idle.isIDLE = true;\n this.updateStatus();\n clearInterval(this.updateStatusInterval);\n rootScope.dispatchEvent('idle', rootScope.idle.isIDLE);\n \n window.addEventListener('focus', () => {\n this.offline = rootScope.idle.isIDLE = false;\n this.updateStatus();\n this.updateStatusInterval = window.setInterval(() => this.updateStatus(), 50e3);\n \n // в обратном порядке\n animationIntersector.checkAnimations(false);\n\n rootScope.dispatchEvent('idle', rootScope.idle.isIDLE);\n }, {once: true});\n });\n\n // * Prevent setting online after reloading page\n window.addEventListener(FOCUS_EVENT_NAME, () => {\n this.updateStatusInterval = window.setInterval(() => this.updateStatus(), 50e3);\n this.updateStatus();\n\n this.offline = rootScope.idle.isIDLE = false;\n rootScope.dispatchEvent('idle', rootScope.idle.isIDLE);\n }, {once: true, passive: true});\n\n this.chatsContainer = document.createElement('div');\n this.chatsContainer.classList.add('chats-container', 'tabs-container');\n this.chatsContainer.dataset.animation = 'navigation';\n\n this.emojiAnimationContainer = document.createElement('div');\n this.emojiAnimationContainer.classList.add('emoji-animation-container');\n this.appendEmojiAnimationContainer(mediaSizes.activeScreen);\n\n this.columnEl.append(this.chatsContainer);\n \n this.createNewChat();\n this.chatsSelectTab(this.chat.container);\n\n appNavigationController.onHashChange = this.onHashChange;\n //window.addEventListener('hashchange', this.onHashChange);\n\n this.setSettings();\n rootScope.addEventListener('settings_updated', this.setSettings);\n\n useHeavyAnimationCheck(() => {\n animationIntersector.setOnlyOnePlayableGroup('lock');\n animationIntersector.checkAnimations(true);\n }, () => {\n animationIntersector.setOnlyOnePlayableGroup('');\n animationIntersector.checkAnimations(false);\n });\n\n if(IS_FIREFOX && appStateManager.oldVersion && compareVersion(appStateManager.oldVersion, '1.4.3') === -1) {\n this.deleteFilesIterative((response) => {\n return response.headers.get('Content-Type') === 'image/svg+xml';\n }).then(() => {\n this.applyCurrentTheme();\n });\n } else {\n this.applyCurrentTheme();\n }\n\n // * fix simultaneous opened both sidebars, can happen when floating sidebar is opened with left sidebar\n mediaSizes.addEventListener('changeScreen', (from, to) => {\n if(document.body.classList.contains(LEFT_COLUMN_ACTIVE_CLASSNAME) \n && document.body.classList.contains(RIGHT_COLUMN_ACTIVE_CLASSNAME)) {\n appSidebarRight.toggleSidebar(false);\n }\n\n this.appendEmojiAnimationContainer(to);\n });\n\n mediaSizes.addEventListener('resize', () => {\n // const perf = performance.now();\n const rect = this.chatsContainer.getBoundingClientRect();\n ChatBackgroundPatternRenderer.resizeInstances(rect.width, rect.height).then(() => {\n // this.log.warn('resize bg time:', performance.now() - perf);\n // for(const chat of this.chats) {\n // if(chat.renderDarkPattern) {\n // chat.renderDarkPattern();\n // }\n // }\n });\n });\n\n rootScope.addEventListener('history_focus', (e) => {\n let {peerId, threadId, mid, startParam} = e;\n if(threadId) threadId = appMessagesIdsManager.generateMessageId(threadId);\n if(mid) mid = appMessagesIdsManager.generateMessageId(mid); // because mid can come from notification, i.e. server message id\n \n this.setInnerPeer({\n peerId, \n lastMsgId: mid, \n type: threadId ? 'discussion' : undefined, \n threadId,\n startParam\n });\n });\n\n rootScope.addEventListener('peer_changing', (chat) => {\n this.saveChatPosition(chat);\n });\n\n rootScope.addEventListener('theme_change', () => {\n this.applyCurrentTheme();\n });\n\n rootScope.addEventListener('choosing_sticker', (choosing) => {\n this.setChoosingStickerTyping(!choosing);\n });\n\n rootScope.addEventListener('peer_typings', ({peerId, typings}) => {\n const chat = this.chat;\n if(\n !chat || \n chat.peerId !== peerId || \n rootScope.overlaysActive || (\n mediaSizes.activeScreen === ScreenSize.mobile && \n this.tabId !== 1\n )\n ) {\n return;\n }\n\n const typing = typings.find(typing => typing.action._ === 'sendMessageEmojiInteraction');\n if(typing?.action?._ === 'sendMessageEmojiInteraction') {\n const action = typing.action;\n const bubble = chat.bubbles.bubbles[appMessagesIdsManager.generateMessageId(typing.action.msg_id)];\n if(bubble && bubble.classList.contains('emoji-big') && bubble.classList.contains('sticker') && getVisibleRect(bubble, chat.bubbles.scrollable.container)) {\n const stickerWrapper: HTMLElement = bubble.querySelector('.media-sticker-wrapper:not(.bubble-hover-reaction-sticker):not(.reaction-sticker)');\n\n const data: SendMessageEmojiInteractionData = JSON.parse(action.interaction.data);\n data.a.forEach(a => {\n setTimeout(() => {\n simulateClickEvent(stickerWrapper);\n }, a.t * 1000);\n });\n \n appMessagesManager.setTyping(peerId, {\n _: 'sendMessageEmojiInteractionSeen',\n emoticon: action.emoticon\n });\n }\n }\n });\n\n rootScope.addEventListener('instance_deactivated', () => {\n const popup = new PopupElement('popup-instance-deactivated', undefined, {overlayClosable: true});\n const c = document.createElement('div');\n c.classList.add('instance-deactivated-container');\n (popup as any).container.replaceWith(c);\n\n const header = document.createElement('div');\n header.classList.add('header');\n header.append(i18n('Deactivated.Title'));\n\n const subtitle = document.createElement('div');\n subtitle.classList.add('subtitle');\n subtitle.append(i18n('Deactivated.Subtitle'));\n\n c.append(header, subtitle);\n\n document.body.classList.add('deactivated');\n\n popup.addEventListener('close', () => {\n document.body.classList.add('deactivated-backwards');\n\n singleInstance.activateInstance();\n\n setTimeout(() => {\n document.body.classList.remove('deactivated', 'deactivated-backwards');\n }, 333);\n });\n\n popup.show();\n });\n\n // remove scroll listener when setting chat to tray\n rootScope.addEventListener('chat_changing', ({to}) => {\n this.toggleChatGradientAnimation(to);\n });\n\n rootScope.addEventListener('service_notification', (update) => {\n confirmationPopup({\n button: {langKey: 'OK', isCancel: true},\n description: RichTextProcessor.wrapRichText(update.message)\n });\n });\n\n stateStorage.get('chatPositions').then((c) => {\n stateStorage.setToCache('chatPositions', c || {});\n });\n\n if(IS_CALL_SUPPORTED || IS_GROUP_CALL_SUPPORTED) {\n this.topbarCall = new TopbarCall(appGroupCallsManager, appPeersManager, appChatsManager, appAvatarsManager, appCallsManager);\n }\n\n if(IS_CALL_SUPPORTED) {\n rootScope.addEventListener('call_instance', ({instance/* , hasCurrent */}) => {\n // if(hasCurrent) {\n // return;\n // }\n \n const popup = new PopupCall({\n appCallsManager,\n appAvatarsManager,\n appPeersManager,\n instance\n });\n\n instance.addEventListener('acceptCallOverride', () => {\n return this.discardCurrentCall(instance.interlocutorUserId.toPeerId(), undefined, instance)\n .then(() => {\n rootScope.dispatchEvent('call_accepting', instance);\n return true;\n })\n .catch(() => false);\n });\n\n popup.addEventListener('close', () => {\n const currentCall = appCallsManager.currentCall;\n if(currentCall && currentCall !== instance && !instance.wasTryingToJoin) {\n instance.hangUp('phoneCallDiscardReasonBusy');\n }\n }, {once: true});\n\n popup.show();\n });\n\n rootScope.addEventListener('call_incompatible', (userId) => {\n toastNew({\n langPackKey: 'VoipPeerIncompatible', \n langPackArguments: [\n new PeerTitle({peerId: userId.toPeerId()}).element\n ]\n });\n });\n }\n\n // ! do not remove this line \n // ! instance can be deactivated before the UI starts, because it waits in background for RAF that is delayed\n singleInstance.activateInstance();\n\n const setAuthorized = () => {\n telegramMeWebManager.setAuthorized(true);\n };\n\n setInterval(setAuthorized, ONE_DAY);\n setAuthorized();\n\n this.addAnchorListener<{}>({\n name: 'showMaskedAlert', \n callback: (params, element) => {\n const href = element.href;\n\n const a = element.cloneNode(true) as HTMLAnchorElement;\n a.className = 'anchor-url';\n a.innerText = href;\n a.removeAttribute('onclick');\n\n new PopupPeer('popup-masked-url', {\n titleLangKey: 'OpenUrlTitle',\n descriptionLangKey: 'OpenUrlAlert2',\n descriptionLangArgs: [a],\n buttons: [{\n langKey: 'Open',\n callback: () => {\n a.click();\n },\n }]\n }).show();\n }\n });\n\n this.addAnchorListener<{uriParams: {command: string, bot: string}}>({\n name: 'execBotCommand', \n callback: ({uriParams}) => {\n const {command, bot} = uriParams;\n\n /* const promise = bot ? this.openUsername(bot).then(() => this.chat.peerId) : Promise.resolve(this.chat.peerId);\n promise.then(peerId => {\n appMessagesManager.sendText(peerId, '/' + command);\n }); */\n\n appMessagesManager.sendText(this.chat.peerId, '/' + command + (bot ? '@' + bot : ''));\n\n //console.log(command, bot);\n }\n });\n\n this.addAnchorListener<{uriParams: {hashtag: string}}>({\n name: 'searchByHashtag', \n callback: ({uriParams}) => {\n const {hashtag} = uriParams;\n if(!hashtag) {\n return;\n }\n\n this.chat.initSearch('#' + hashtag + ' ');\n }\n });\n\n this.addAnchorListener<{pathnameParams: ['addstickers', string]}>({\n name: 'addstickers', \n callback: ({pathnameParams}) => {\n const link: InternalLink = {\n _: INTERNAL_LINK_TYPE.STICKER_SET,\n set: pathnameParams[1]\n };\n\n this.processInternalLink(link);\n }\n });\n\n // Support old t.me/joinchat/asd and new t.me/+asd\n this.addAnchorListener<{pathnameParams: ['joinchat', string]}>({\n name: 'joinchat', \n callback: ({pathnameParams}) => {\n const link: InternalLink = {\n _: INTERNAL_LINK_TYPE.JOIN_CHAT,\n invite: pathnameParams[1] || decodeURIComponent(pathnameParams[0]).slice(1)\n };\n\n this.processInternalLink(link);\n }\n });\n\n if(IS_GROUP_CALL_SUPPORTED) {\n this.addAnchorListener<{\n uriParams: Omit<InternalLink.InternalLinkVoiceChat, '_'>\n }>({\n name: 'voicechat',\n protocol: 'tg',\n callback: ({uriParams}) => {\n const link = this.makeLink(INTERNAL_LINK_TYPE.VOICE_CHAT, uriParams);\n this.processInternalLink(link);\n }\n });\n }\n\n this.addAnchorListener<{\n // pathnameParams: ['c', string, string],\n // uriParams: {thread?: number}\n // } | {\n // pathnameParams: [string, string?],\n // uriParams: {comment?: number}\n pathnameParams: ['c', string, string] | [string, string?],\n uriParams: {thread?: string, comment?: string} | {comment?: string, start?: string}\n }>({\n name: 'im',\n callback: async({pathnameParams, uriParams}) => {\n let link: InternalLink;\n if(RichTextProcessor.PHONE_NUMBER_REG_EXP.test(pathnameParams[0])) {\n link = {\n _: INTERNAL_LINK_TYPE.USER_PHONE_NUMBER,\n phone: pathnameParams[0].slice(1)\n };\n } else if(pathnameParams[0] === 'c') {\n link = {\n _: INTERNAL_LINK_TYPE.PRIVATE_POST,\n channel: pathnameParams[1],\n post: pathnameParams[2],\n thread: 'thread' in uriParams && uriParams.thread,\n comment: uriParams.comment\n };\n } else {\n link = {\n _: INTERNAL_LINK_TYPE.MESSAGE,\n domain: pathnameParams[0],\n post: pathnameParams[1],\n comment: uriParams.comment,\n start: 'start' in uriParams ? uriParams.start : undefined\n };\n }\n\n this.processInternalLink(link);\n }\n });\n\n this.addAnchorListener<{\n uriParams: {\n domain: string,\n\n // telegrampassport\n scope?: string,\n nonce?: string,\n payload?: string,\n bot_id?: string,\n public_key?: string,\n callback_url?: string,\n\n // regular\n start?: string,\n startgroup?: string,\n game?: string,\n voicechat?: string,\n post?: string,\n thread?: string,\n comment?: string,\n phone?: string\n }\n }>({\n name: 'resolve',\n protocol: 'tg',\n callback: ({uriParams}) => {\n let link: InternalLink;\n if(uriParams.phone) {\n link = this.makeLink(INTERNAL_LINK_TYPE.USER_PHONE_NUMBER, uriParams as Required<typeof uriParams>);\n } else if(uriParams.domain === 'telegrampassport') {\n\n } else {\n link = this.makeLink(INTERNAL_LINK_TYPE.MESSAGE, uriParams);\n }\n\n this.processInternalLink(link);\n }\n });\n\n this.addAnchorListener<{\n uriParams: {\n channel: string,\n post: string,\n thread?: string,\n comment?: string\n }\n }>({\n name: 'privatepost',\n protocol: 'tg',\n callback: ({uriParams}) => {\n const link = this.makeLink(INTERNAL_LINK_TYPE.PRIVATE_POST, uriParams);\n this.processInternalLink(link);\n }\n });\n\n this.addAnchorListener<{\n uriParams: {\n set: string\n }\n }>({\n name: 'addstickers',\n protocol: 'tg',\n callback: ({uriParams}) => {\n const link = this.makeLink(INTERNAL_LINK_TYPE.STICKER_SET, uriParams);\n this.processInternalLink(link);\n }\n });\n\n ['joinchat' as const, 'join' as const].forEach(name => {\n this.addAnchorListener<{\n uriParams: {\n invite: string\n }\n }>({\n name,\n protocol: 'tg',\n callback: ({uriParams}) => {\n const link = this.makeLink(INTERNAL_LINK_TYPE.JOIN_CHAT, uriParams);\n this.processInternalLink(link);\n }\n });\n });\n\n this.onHashChange();\n this.attachKeydownListener();\n }\n\n private deleteFilesIterative(callback: (response: Response) => boolean) {\n return appDownloadManager.cacheStorage.timeoutOperation((cache) => {\n const perf = performance.now();\n return cache.keys().then((requests) => {\n const promises = requests.map((request) => {\n return cache.match(request).then((response) => {\n return callback(response);\n });\n });\n\n return Promise.all(promises).then((values) => {\n values.map((isBad, idx) => {\n if(!isBad) {\n return;\n }\n\n const request = requests[idx];\n return cache.delete(request);\n });\n\n return Promise.all(values.filter(Boolean));\n });\n }).then(() => {\n this.log('deleted files', performance.now() - perf);\n });\n });\n }\n\n private toggleChatGradientAnimation(activatingChat: Chat) {\n this.chats.forEach(chat => {\n if(chat.gradientRenderer) {\n chat.gradientRenderer.scrollAnimate(rootScope.settings.animationsEnabled && chat === activatingChat);\n }\n });\n }\n\n private appendEmojiAnimationContainer(screen: ScreenSize) {\n const appendTo = screen === ScreenSize.mobile ? this.columnEl : document.body;\n if(this.emojiAnimationContainer.parentElement !== appendTo) {\n appendTo.append(this.emojiAnimationContainer)\n }\n }\n\n private attachKeydownListener() {\n const IGNORE_KEYS = new Set(['PageUp', 'PageDown', 'Meta', 'Control']);\n const onKeyDown = (e: KeyboardEvent) => {\n const key = e.key;\n if(rootScope.isOverlayActive || IGNORE_KEYS.has(key)) return;\n \n const target = e.target as HTMLElement;\n \n //if(target.tagName === 'INPUT') return;\n \n //this.log('onkeydown', e, document.activeElement);\n\n const chat = this.chat;\n\n if(e.code === 'KeyC' && (e.ctrlKey || e.metaKey) && target.tagName !== 'INPUT') {\n return;\n } else if(e.altKey && (key === 'ArrowUp' || key === 'ArrowDown')) {\n const folder = appMessagesManager.dialogsStorage.getFolderDialogs(rootScope.filterId, true);\n let nextDialog: Dialog.dialog;\n if(!rootScope.peerId) {\n if(key === 'ArrowDown') {\n nextDialog = folder[0];\n }\n } else {\n const idx = folder.findIndex(dialog => dialog.peerId === rootScope.peerId);\n if(idx !== -1) {\n const nextIndex = key === 'ArrowUp' ? idx - 1 : idx + 1;\n nextDialog = folder[nextIndex];\n }\n }\n \n if(nextDialog) {\n this.setPeer({peerId: nextDialog.peerId});\n }\n } else if(key === 'ArrowUp') {\n if(!chat.input.editMsgId && chat.input.isInputEmpty()) {\n const historyStorage = appMessagesManager.getHistoryStorage(chat.peerId, chat.threadId);\n const slice = historyStorage.history.slice;\n if(slice.isEnd(SliceEnd.Bottom) && slice.length) {\n let goodMid: number;\n for(const mid of slice) {\n const message = chat.getMessage(mid);\n const good = this.myId === chat.peerId ? message.fromId === this.myId : message.pFlags.out;\n\n if(good) {\n if(appMessagesManager.canEditMessage(chat.getMessage(mid), 'text')) {\n goodMid = mid;\n break;\n }\n\n // * this check will allow editing only last message\n //break;\n }\n }\n \n if(goodMid) {\n chat.input.initMessageEditing(goodMid);\n cancelEvent(e); // * prevent from scrolling\n }\n }\n } else {\n return;\n }\n } else if(key === 'ArrowDown') {\n return;\n }\n \n if(\n chat?.input?.messageInput && \n e.target !== chat.input.messageInput && \n target.tagName !== 'INPUT' && \n !target.hasAttribute('contenteditable') && \n !IS_TOUCH_SUPPORTED && \n (!mediaSizes.isMobile || this.tabId === 1) && \n !chat.selection.isSelecting && \n !chat.input.recording\n ) {\n chat.input.messageInput.focus();\n placeCaretAtEnd(chat.input.messageInput);\n\n // clone and dispatch same event to new input. it is needed for sending message if input was blurred\n const newEvent = new KeyboardEvent(e.type, e);\n chat.input.messageInput.dispatchEvent(newEvent);\n }\n };\n \n document.body.addEventListener('keydown', onKeyDown);\n }\n\n private makeLink<T extends INTERNAL_LINK_TYPE>(type: T, uriParams: Omit<InternalLinkTypeMap[T], '_'>) {\n return {\n _: type,\n ...uriParams\n } as any as InternalLinkTypeMap[T];\n }\n\n public async processInternalLink(link: InternalLink) {\n switch(link?._) {\n case INTERNAL_LINK_TYPE.MESSAGE: {\n const postId = link.post ? appMessagesIdsManager.generateMessageId(+link.post) : undefined;\n const commentId = link.comment ? appMessagesIdsManager.generateMessageId(+link.comment) : undefined;\n\n this.openUsername({\n userName: link.domain, \n lastMsgId: postId, \n commentId,\n startParam: link.start\n });\n break;\n }\n\n case INTERNAL_LINK_TYPE.PRIVATE_POST: {\n const chatId = link.channel.toChatId();\n const peerId = chatId.toPeerId(true);\n\n const chat = appChatsManager.getChat(chatId);\n if(chat.deleted) {\n try {\n await appChatsManager.resolveChannel(chatId);\n } catch(err) {\n toastNew({langPackKey: 'LinkNotFound'});\n throw err;\n }\n }\n\n const postId = appMessagesIdsManager.generateMessageId(+link.post);\n const threadId = link.thread ? appMessagesIdsManager.generateMessageId(+link.thread) : undefined;\n\n if(threadId) this.openThread(peerId, postId, threadId);\n else this.setInnerPeer({\n peerId,\n lastMsgId: postId,\n threadId\n });\n break;\n }\n\n case INTERNAL_LINK_TYPE.STICKER_SET: {\n new PopupStickers({id: link.set}).show();\n break;\n }\n\n case INTERNAL_LINK_TYPE.JOIN_CHAT: {\n apiManager.invokeApi('messages.checkChatInvite', {\n hash: link.invite\n }).then(chatInvite => {\n if((chatInvite as ChatInvite.chatInvitePeek).chat) {\n appChatsManager.saveApiChat((chatInvite as ChatInvite.chatInvitePeek).chat, true);\n }\n\n // console.log(chatInvite);\n\n if(chatInvite._ === 'chatInviteAlready' ||\n chatInvite._ === 'chatInvitePeek'/* && chatInvite.expires > tsNow(true) */) {\n this.setInnerPeer({\n peerId: chatInvite.chat.id.toPeerId(true)\n });\n return;\n }\n\n new PopupJoinChatInvite(link.invite, chatInvite).show();\n }, (err) => {\n if(err.type === 'INVITE_HASH_EXPIRED') {\n toast(i18n('InviteExpired'));\n }\n });\n break;\n }\n\n case INTERNAL_LINK_TYPE.VOICE_CHAT: {\n if(IS_GROUP_CALL_SUPPORTED) {\n this.joinGroupCall(link.chat_id.toPeerId(true), link.id);\n }\n \n break;\n }\n\n case INTERNAL_LINK_TYPE.USER_PHONE_NUMBER: {\n appUsersManager.resolvePhone(link.phone).then(user => {\n this.setInnerPeer({\n peerId: user.id.toPeerId(false)\n });\n }).catch(err => {\n if(err.type === 'PHONE_NOT_OCCUPIED') {\n toastNew({langPackKey: 'Alert.UserDoesntExists'});\n }\n });\n\n break;\n }\n\n default: {\n this.log.warn('Not supported internal link:', link);\n break;\n }\n }\n }\n\n public openUrl(url: string) {\n const {url: wrappedUrl, onclick} = RichTextProcessor.wrapUrl(url);\n const a = document.createElement('a');\n a.href = wrappedUrl;\n \n (window as any)[onclick](a);\n }\n\n private addAnchorListener<Params extends {pathnameParams?: any, uriParams?: any}>(options: {\n name: 'showMaskedAlert' | 'execBotCommand' | 'searchByHashtag' | 'addstickers' | 'im' |\n 'resolve' | 'privatepost' | 'addstickers' | 'voicechat' | 'joinchat' | 'join', \n protocol?: 'tg',\n callback: (params: Params, element?: HTMLAnchorElement) => boolean | any, \n noPathnameParams?: boolean,\n noUriParams?: boolean\n }) {\n (window as any)[(options.protocol ? options.protocol + '_' : '') + options.name] = (element?: HTMLAnchorElement/* , e: Event */) => {\n cancelEvent(null);\n\n const href = element.href;\n let pathnameParams: any[];\n let uriParams: any;\n\n if(!options.noPathnameParams) pathnameParams = new URL(element.href).pathname.split('/').slice(1);\n if(!options.noUriParams) uriParams = this.parseUriParams(href);\n\n const res = options.callback({pathnameParams, uriParams} as Params, element);\n return res === undefined ? res : false;\n };\n }\n\n private parseUriParams(uri: string, splitted = uri.split('?')) {\n const params: any = {};\n if(!splitted[1]) return params;\n splitted[1].split('&').forEach(item => {\n params[item.split('=')[0]] = decodeURIComponent(item.split('=')[1]);\n });\n\n return params;\n }\n\n private onHashChange = () => {\n const hash = location.hash;\n const splitted = hash.split('?');\n\n const params = this.parseUriParams(hash, splitted);\n\n this.log('hashchange', hash, splitted[0], params);\n\n if(params.tgaddr) {\n appNavigationController.replaceState();\n const {onclick} = RichTextProcessor.wrapUrl(params.tgaddr);\n if(onclick) {\n const a = document.createElement('a');\n a.href = params.tgaddr;\n (window as any)[onclick](a);\n }\n return;\n }\n\n switch(splitted[0]) {\n case '#/im': {\n const p: string = params.p;\n let postId = params.post !== undefined ? appMessagesIdsManager.generateMessageId(+params.post) : undefined;\n\n switch(p[0]) {\n case '@': {\n this.openUsername({\n userName: p, \n lastMsgId: postId\n });\n break;\n }\n\n default: { // peerId\n this.setInnerPeer({\n peerId: postId ? p.toPeerId(true) : p.toPeerId(), \n lastMsgId: postId\n });\n break;\n }\n }\n }\n }\n\n //appNavigationController.replaceState();\n //location.hash = '';\n };\n\n public openUsername(options: {\n userName: string, \n lastMsgId?: number, \n threadId?: number, \n commentId?: number,\n startParam?: string\n }) {\n const {userName, lastMsgId, threadId, commentId, startParam} = options;\n return appUsersManager.resolveUsername(userName).then(peer => {\n const isUser = peer._ === 'user';\n const peerId = peer.id.toPeerId(!isUser);\n\n if(threadId) {\n return this.openThread(peerId, lastMsgId, threadId);\n } else if(commentId) {\n return this.openComment(peerId, lastMsgId, commentId);\n }\n \n return this.setInnerPeer({\n peerId,\n lastMsgId,\n startParam: startParam\n });\n }, (err) => {\n if(err.type === 'USERNAME_NOT_OCCUPIED') {\n toastNew({langPackKey: 'NoUsernameFound'});\n } else if(err.type === 'USERNAME_INVALID') {\n toastNew({langPackKey: 'Alert.UserDoesntExists'});\n }\n });\n }\n\n /**\n * Opens thread when peerId of discussion group is known\n */\n public openThread(peerId: PeerId, lastMsgId: number, threadId: number) {\n return appMessagesManager.wrapSingleMessage(peerId, threadId).then(() => {\n const message: Message = appMessagesManager.getMessageByPeer(peerId, threadId);\n if(message._ === 'messageEmpty') {\n lastMsgId = undefined;\n } else {\n appMessagesManager.generateThreadServiceStartMessage(message);\n }\n\n return this.setInnerPeer({\n peerId,\n lastMsgId,\n threadId,\n type: 'discussion'\n });\n });\n }\n\n /**\n * Opens comment directly from original channel\n */\n public openComment(peerId: PeerId, msgId: number, commentId: number) {\n return appMessagesManager.getDiscussionMessage(peerId, msgId).then(message => {\n return this.openThread(message.peerId, commentId, message.mid);\n });\n }\n\n public async callUser(userId: UserId, type: CallType) {\n const call = appCallsManager.getCallByUserId(userId);\n if(call) {\n return;\n }\n \n const userFull = await appProfileManager.getProfile(userId);\n if(userFull.pFlags.phone_calls_private) {\n confirmationPopup({\n descriptionLangKey: 'Call.PrivacyErrorMessage',\n descriptionLangArgs: [new PeerTitle({peerId: userId.toPeerId()}).element],\n button: {\n langKey: 'OK',\n isCancel: true\n }\n });\n\n return;\n }\n\n await this.discardCurrentCall(userId.toPeerId());\n\n appCallsManager.startCallInternal(userId, type === 'video');\n }\n\n private discardCurrentCall(toPeerId: PeerId, ignoreGroupCall?: GroupCallInstance, ignoreCall?: CallInstance) {\n if(appGroupCallsManager.groupCall && appGroupCallsManager.groupCall !== ignoreGroupCall) return this.discardGroupCallConfirmation(toPeerId);\n else if(appCallsManager.currentCall && appCallsManager.currentCall !== ignoreCall) return this.discardCallConfirmation(toPeerId);\n else return Promise.resolve();\n }\n\n private async discardCallConfirmation(toPeerId: PeerId) {\n const currentCall = appCallsManager.currentCall;\n if(currentCall) {\n await confirmationPopup({\n titleLangKey: 'Call.Confirm.Discard.Call.Header',\n descriptionLangKey: toPeerId.isUser() ? 'Call.Confirm.Discard.Call.ToCall.Text' : 'Call.Confirm.Discard.Call.ToVoice.Text',\n descriptionLangArgs: [\n new PeerTitle({peerId: currentCall.interlocutorUserId.toPeerId(false)}).element, \n new PeerTitle({peerId: toPeerId}).element\n ],\n button: {\n langKey: 'OK'\n }\n });\n\n if(!currentCall.isClosing) {\n await currentCall.hangUp('phoneCallDiscardReasonDisconnect');\n }\n }\n }\n\n private async discardGroupCallConfirmation(toPeerId: PeerId) {\n const currentGroupCall = appGroupCallsManager.groupCall;\n if(currentGroupCall) {\n await confirmationPopup({\n titleLangKey: 'Call.Confirm.Discard.Voice.Header',\n descriptionLangKey: toPeerId.isUser() ? 'Call.Confirm.Discard.Voice.ToCall.Text' : 'Call.Confirm.Discard.Voice.ToVoice.Text',\n descriptionLangArgs: [\n new PeerTitle({peerId: currentGroupCall.chatId.toPeerId(true)}).element, \n new PeerTitle({peerId: toPeerId}).element\n ],\n button: {\n langKey: 'OK'\n }\n });\n\n if(appGroupCallsManager.groupCall === currentGroupCall) {\n await currentGroupCall.hangUp();\n }\n }\n }\n\n public async joinGroupCall(peerId: PeerId, groupCallId?: GroupCallId) {\n const chatId = peerId.toChatId();\n const hasRights = appChatsManager.hasRights(chatId, 'manage_call');\n const next = async() => {\n const chatFull = await appProfileManager.getChatFull(chatId);\n let call: MyGroupCall;\n if(!chatFull.call) {\n if(!hasRights) {\n return;\n }\n \n call = await appGroupCallsManager.createGroupCall(chatId);\n } else {\n call = appGroupCallsManager.saveGroupCall(chatFull.call, chatId);\n }\n \n appGroupCallsManager.joinGroupCall(chatId, call.id, true, false);\n };\n\n if(groupCallId) {\n const groupCall = await appGroupCallsManager.getGroupCallFull(groupCallId);\n if(groupCall._ === 'groupCallDiscarded') {\n if(!hasRights) {\n toastNew({\n langPackKey: 'VoiceChat.Chat.Ended'\n });\n\n return;\n }\n\n await confirmationPopup({\n descriptionLangKey: 'VoiceChat.Chat.StartNew',\n button: {\n langKey: 'VoiceChat.Chat.StartNew.OK'\n }\n });\n }\n }\n\n await this.discardCurrentCall(peerId);\n\n next();\n };\n\n public setCurrentBackground(broadcastEvent = false): ReturnType<AppImManager['setBackground']> {\n const theme = rootScope.getTheme();\n\n if(theme.background.slug) {\n const defaultTheme = AppStateManager.STATE_INIT.settings.themes.find(t => t.name === theme.name);\n // const isDefaultBackground = theme.background.blur === defaultTheme.background.blur && \n // theme.background.slug === defaultTheme.background.slug;\n\n // if(!isDefaultBackground) {\n return this.getBackground(theme.background.slug).then((url) => {\n return this.setBackground(url, broadcastEvent);\n }, () => { // * if NO_ENTRY_FOUND\n theme.background = copy(defaultTheme.background); // * reset background\n return this.setCurrentBackground(true);\n });\n // }\n }\n \n return this.setBackground('', broadcastEvent);\n }\n\n private getBackground(slug: string) {\n if(this.backgroundPromises[slug]) return this.backgroundPromises[slug];\n return this.backgroundPromises[slug] = appDownloadManager.cacheStorage.getFile('backgrounds/' + slug).then(blob => {\n return URL.createObjectURL(blob);\n });\n }\n\n public setBackground(url: string, broadcastEvent = true): Promise<void> {\n this.lastBackgroundUrl = url;\n const promises = this.chats.map(chat => chat.setBackground(url));\n return promises[promises.length - 1].then(() => {\n if(broadcastEvent) {\n rootScope.dispatchEvent('background_change');\n }\n });\n }\n\n public saveChatPosition(chat: Chat) {\n if(!(['chat', 'discussion'] as ChatType[]).includes(chat.type) || !chat.peerId) {\n return;\n }\n\n //const bubble = chat.bubbles.getBubbleByPoint('top');\n //if(bubble) {\n //const top = bubble.getBoundingClientRect().top;\n const chatBubbles = chat.bubbles;\n const key = chat.peerId + (chat.threadId ? '_' + chat.threadId : '');\n const chatPositions = stateStorage.getFromCache('chatPositions');\n if(!(chatBubbles.scrollable.getDistanceToEnd() <= 16 && chatBubbles.scrollable.loadedAll.bottom) && chatBubbles.getRenderedLength()) {\n chatBubbles.sliceViewport(true);\n const top = chatBubbles.scrollable.scrollTop;\n \n const position = {\n mids: getObjectKeysAndSort(chatBubbles.bubbles, 'desc').filter(mid => !chatBubbles.skippedMids.has(mid)),\n top\n };\n\n chatPositions[key] = position;\n\n this.log('saved chat position:', position);\n } else {\n delete chatPositions[key];\n\n this.log('deleted chat position');\n }\n\n stateStorage.set({chatPositions}, true);\n //}\n }\n\n public getChatSavedPosition(chat: Chat): ChatSavedPosition {\n if(!(['chat', 'discussion'] as ChatType[]).includes(chat.type) || !chat.peerId) {\n return;\n }\n \n const key = chat.peerId + (chat.threadId ? '_' + chat.threadId : '');\n const cache = stateStorage.getFromCache('chatPositions');\n return cache && cache[key];\n }\n\n public applyHighlightningColor() {\n let hsla: string;\n const theme = rootScope.getTheme();\n if(theme.background.highlightningColor) {\n hsla = theme.background.highlightningColor;\n document.documentElement.style.setProperty('--message-highlightning-color', hsla);\n } else {\n document.documentElement.style.removeProperty('--message-highlightning-color');\n }\n\n if(!IS_TOUCH_SUPPORTED && hsla) {\n rootScope.themeColor = hslaStringToHex(hsla);\n }\n }\n\n public applyCurrentTheme(slug?: string, backgroundUrl?: string, broadcastEvent?: boolean) {\n this.applyHighlightningColor();\n\n rootScope.setTheme();\n\n if(backgroundUrl) {\n this.backgroundPromises[slug] = Promise.resolve(backgroundUrl);\n }\n \n return this.setCurrentBackground(broadcastEvent === undefined ? !!slug : broadcastEvent);\n }\n\n private setSettings = () => {\n document.documentElement.style.setProperty('--messages-text-size', rootScope.settings.messagesTextSize + 'px');\n \n document.body.classList.toggle('animation-level-0', !rootScope.settings.animationsEnabled);\n document.body.classList.toggle('animation-level-1', false);\n document.body.classList.toggle('animation-level-2', rootScope.settings.animationsEnabled);\n\n this.chatsSelectTabDebounced = debounce(() => {\n const topbar = this.chat.topbar;\n if(topbar.pinnedMessage) { // * буду молиться богам, чтобы это ничего не сломало, но это исправляет получение пиннеда после анимации\n topbar.pinnedMessage.setCorrectIndex(0);\n }\n\n apiManager.setQueueId(this.chat.bubbles.lazyLoadQueue.queueId);\n }, rootScope.settings.animationsEnabled ? 250 : 0, false, true);\n\n lottieLoader.setLoop(rootScope.settings.stickers.loop);\n animationIntersector.checkAnimations(false);\n \n for(const chat of this.chats) {\n chat.setAutoDownloadMedia();\n }\n \n I18n.setTimeFormat(rootScope.settings.timeFormat);\n\n this.toggleChatGradientAnimation(this.chat);\n };\n\n // * не могу использовать тут TransitionSlider, так как мне нужен отрисованный блок рядом \n // * (или под текущим чатом) чтобы правильно отрендерить чат (напр. scrollTop)\n private chatsSelectTab(tab: HTMLElement, animate?: boolean) {\n if(this.prevTab === tab) {\n return;\n }\n\n if(animate === false && this.prevTab) { // * will be used for Safari iOS history swipe\n disableTransition([tab, this.prevTab].filter(Boolean));\n }\n\n if(this.prevTab) {\n this.prevTab.classList.remove('active');\n this.chatsSelectTabDebounced();\n\n // ! нужно переделать на animation, так как при лаге анимация будет длиться не 250мс\n if(rootScope.settings.animationsEnabled && animate !== false) { \n dispatchHeavyAnimationEvent(pause(250 + 150), 250 + 150);\n }\n\n const prevIdx = whichChild(this.prevTab);\n const idx = whichChild(tab);\n if(idx > prevIdx) {\n appNavigationController.pushItem({\n type: 'chat', \n onPop: (canAnimate) => {\n this.setPeer({}, canAnimate);\n blurActiveElement();\n }\n });\n }\n }\n\n tab.classList.add('active');\n this.prevTab = tab;\n }\n\n private init() {\n document.addEventListener('paste', this.onDocumentPaste, true);\n \n if(!IS_TOUCH_SUPPORTED) {\n this.attachDragAndDropListeners();\n }\n\n //if(!isTouchSupported) {\n this.markupTooltip = new MarkupTooltip(this);\n this.markupTooltip.handleSelection();\n //}\n }\n\n private attachDragAndDropListeners() {\n const drops: ChatDragAndDrop[] = [];\n const mediaDrops: ChatDragAndDrop[] = [];\n let mounted = false;\n const toggle = async(e: DragEvent, mount: boolean) => {\n if(mount === mounted) return;\n\n const _types = e.dataTransfer.types;\n // @ts-ignore\n const isFiles = _types.contains ? _types.contains('Files') : _types.indexOf('Files') >= 0;\n\n const newMediaPopup = getCurrentNewMediaPopup();\n if(!isFiles || (!this.canDrag() && !newMediaPopup)) { // * skip dragging text case\n counter = 0;\n return;\n }\n\n const _dropsContainer = newMediaPopup ? mediaDropsContainer : dropsContainer;\n const _drops = newMediaPopup ? mediaDrops : drops;\n\n if(mount && !_drops.length) {\n const types: string[] = await getFilesFromEvent(e, true);\n const force = isFiles && !types.length; // * can't get file items not from 'drop' on Safari\n \n const foundMedia = types.filter(t => MEDIA_MIME_TYPES_SUPPORTED.has(t)).length;\n // const foundDocuments = types.length - foundMedia;\n \n this.log('drag files', types);\n\n if(newMediaPopup) {\n newMediaPopup.appendDrops(_dropsContainer);\n\n if(types.length || force) {\n _drops.push(new ChatDragAndDrop(_dropsContainer, {\n header: 'Preview.Dragging.AddItems',\n headerArgs: [types.length],\n onDrop: (e: DragEvent) => {\n toggle(e, false);\n appImManager.log('drop', e);\n appImManager.onDocumentPaste(e, 'document');\n }\n }));\n }\n } else {\n if(types.length || force) {\n _drops.push(new ChatDragAndDrop(_dropsContainer, {\n icon: 'dragfiles',\n header: 'Chat.DropTitle',\n subtitle: 'Chat.DropAsFilesDesc',\n onDrop: (e: DragEvent) => {\n toggle(e, false);\n appImManager.log('drop', e);\n appImManager.onDocumentPaste(e, 'document');\n }\n }));\n }\n \n // if((foundMedia && !foundDocuments) || force) {\n if(foundMedia || force) {\n _drops.push(new ChatDragAndDrop(_dropsContainer, {\n icon: 'dragmedia',\n header: 'Chat.DropTitle',\n subtitle: 'Chat.DropQuickDesc',\n onDrop: (e: DragEvent) => {\n toggle(e, false);\n appImManager.log('drop', e);\n appImManager.onDocumentPaste(e, 'media');\n }\n }));\n }\n\n this.chat.container.append(_dropsContainer);\n }\n }\n\n //if(!mount) return;\n\n SetTransition(_dropsContainer, 'is-visible', mount, 200, () => {\n if(!mount) {\n _drops.forEach(drop => {\n drop.destroy();\n });\n\n _drops.length = 0;\n }\n });\n\n if(mount) {\n _drops.forEach(drop => {\n drop.setPath();\n });\n } else {\n counter = 0;\n }\n\n document.body.classList.toggle('is-dragging', mount);\n mounted = mount;\n };\n\n /* document.body.addEventListener('dragover', (e) => {\n cancelEvent(e);\n }); */\n\n let counter = 0;\n document.body.addEventListener('dragenter', (e) => {\n counter++;\n });\n\n document.body.addEventListener('dragover', (e) => {\n //this.log('dragover', e/* , e.dataTransfer.types[0] */);\n toggle(e, true);\n cancelEvent(e);\n });\n\n document.body.addEventListener('dragleave', (e) => {\n //this.log('dragleave', e, counter);\n //if((e.pageX <= 0 || e.pageX >= appPhotosManager.windowW) || (e.pageY <= 0 || e.pageY >= appPhotosManager.windowH)) {\n counter--;\n if(counter === 0) { \n //if(!findUpClassName(e.target, 'drops-container')) {\n toggle(e, false);\n }\n });\n\n const dropsContainer = document.createElement('div');\n dropsContainer.classList.add('drops-container');\n\n const mediaDropsContainer = dropsContainer.cloneNode(true) as HTMLElement;\n }\n\n private canDrag() {\n const chat = this.chat;\n const peerId = chat?.peerId;\n return !(!peerId || rootScope.isOverlayActive || !chat.canSend('send_media'));\n }\n\n private onDocumentPaste = (e: ClipboardEvent | DragEvent, attachType?: 'media' | 'document') => {\n const newMediaPopup = getCurrentNewMediaPopup();\n if(!this.canDrag() && !newMediaPopup) return;\n\n //console.log('document paste');\n //console.log('item', event.clipboardData.getData());\n\n if(e instanceof DragEvent) {\n const _types = e.dataTransfer.types;\n // @ts-ignore\n const isFiles = _types.contains ? _types.contains('Files') : _types.indexOf('Files') >= 0;\n if(isFiles) {\n cancelEvent(e);\n }\n }\n \n getFilesFromEvent(e).then((files: File[]) => {\n if(files.length) {\n if(newMediaPopup) {\n newMediaPopup.addFiles(files);\n return;\n }\n \n const chatInput = this.chat.input;\n chatInput.willAttachType = attachType || (MEDIA_MIME_TYPES_SUPPORTED.has(files[0].type) ? 'media' : 'document');\n new PopupNewMedia(this.chat, files, chatInput.willAttachType);\n }\n });\n };\n\n public selectTab(id: number, animate?: boolean) {\n if(animate === false) { // * will be used for Safari iOS history swipe\n disableTransition([appSidebarLeft.sidebarEl, this.columnEl, appSidebarRight.sidebarEl]);\n }\n\n document.body.classList.toggle(LEFT_COLUMN_ACTIVE_CLASSNAME, id === 0);\n\n const prevTabId = this.tabId;\n\n this.log('selectTab', id, prevTabId);\n\n let animationPromise: Promise<any> = rootScope.settings.animationsEnabled ? doubleRaf() : Promise.resolve();\n if(prevTabId !== -1 && prevTabId !== id && rootScope.settings.animationsEnabled && animate !== false) {\n const transitionTime = (mediaSizes.isMobile ? 250 : 200) + 100; // * cause transition time could be > 250ms\n animationPromise = pause(transitionTime);\n dispatchHeavyAnimationEvent(animationPromise, transitionTime);\n\n // ! it's very heavy operation. will blink in firefox\n /* this.columnEl.classList.add('disable-hover');\n animationPromise.finally(() => {\n this.columnEl.classList.remove('disable-hover');\n }); */\n }\n\n this.tabId = id;\n blurActiveElement();\n if(mediaSizes.isMobile && prevTabId === 2 && id < 2) {\n document.body.classList.remove(RIGHT_COLUMN_ACTIVE_CLASSNAME);\n }\n\n if(prevTabId !== -1 && id > prevTabId) {\n if(id < 2 || !appNavigationController.findItemByType('im')) {\n appNavigationController.pushItem({\n type: 'im', \n onPop: (canAnimate) => {\n //this.selectTab(prevTabId, !isSafari);\n this.setPeer({}, canAnimate);\n }\n });\n }\n }\n\n rootScope.dispatchEvent('im_tab_change', id);\n\n //this._selectTab(id, mediaSizes.isMobile);\n //document.body.classList.toggle(RIGHT_COLUMN_ACTIVE_CLASSNAME, id === 2);\n\n return animationPromise;\n }\n \n public updateStatus() {\n if(!this.myId) return Promise.resolve();\n \n appUsersManager.setUserStatus(this.myId, this.offline);\n return apiManager.invokeApiSingle('account.updateStatus', {offline: this.offline});\n }\n\n private createNewChat() {\n const chat = new Chat(this, \n appChatsManager, \n appDocsManager, \n appInlineBotsManager, \n appMessagesManager, \n appPeersManager, \n appPhotosManager, \n appProfileManager, \n appStickersManager, \n appUsersManager, \n appWebPagesManager, \n appPollsManager, \n apiManager, \n appDraftsManager, \n serverTimeManager, \n stateStorage, \n appNotificationsManager, \n appEmojiManager,\n appMessagesIdsManager,\n appGroupCallsManager,\n appReactionsManager\n );\n\n if(this.chats.length) {\n chat.setBackground(this.lastBackgroundUrl, true);\n }\n\n this.chats.push(chat);\n\n return chat;\n }\n\n private spliceChats(fromIndex: number, justReturn = true, animate?: boolean, spliced?: Chat[]) {\n if(fromIndex >= this.chats.length) return;\n\n const chatFrom = this.chat;\n if(this.chats.length > 1 && justReturn) {\n rootScope.dispatchEvent('peer_changing', this.chat);\n }\n\n if(!spliced) {\n spliced = this.chats.splice(fromIndex, this.chats.length - fromIndex);\n }\n\n rootScope.dispatchEvent('chat_changing', {from: chatFrom, to: this.chat});\n\n // * -1 because one item is being sliced when closing the chat by calling .removeByType\n for(let i = 0; i < spliced.length - 1; ++i) {\n appNavigationController.removeByType('chat', true);\n }\n\n // * fix middle chat z-index on animation\n if(spliced.length > 1) {\n spliced.slice(0, -1).forEach(chat => {\n chat.container.remove();\n });\n }\n\n this.chatsSelectTab(this.chat.container, animate);\n\n if(justReturn) {\n rootScope.dispatchEvent('peer_changed', this.chat.peerId);\n\n const searchTab = appSidebarRight.getTab(AppPrivateSearchTab);\n if(searchTab) {\n searchTab.close();\n }\n \n const isSet = appSidebarRight.sharedMediaTab.setPeer(this.chat.peerId, this.chat.threadId);\n if(isSet) {\n appSidebarRight.sharedMediaTab.loadSidebarMedia(true);\n appSidebarRight.sharedMediaTab.fillProfileElements();\n }\n \n /* setTimeout(() => {\n appSidebarRight.sharedMediaTab.loadSidebarMedia(false);\n }); */\n }\n\n spliced.forEach(chat => {\n chat.beforeDestroy();\n });\n \n setTimeout(() => {\n //chat.setPeer(0);\n spliced.forEach(chat => {\n chat.destroy();\n });\n }, 250 + 100);\n }\n\n public setPeer(options: ChatSetPeerOptions = {}, animate?: boolean): boolean {\n if(this.init) {\n this.init();\n this.init = null;\n }\n\n options.peerId ??= NULL_PEER_ID;\n\n const {peerId, lastMsgId} = options;\n\n const chat = this.chat;\n const chatIndex = this.chats.indexOf(chat);\n\n if(!peerId) {\n if(chatIndex > 0) {\n this.spliceChats(chatIndex, undefined, animate);\n return;\n } else if(mediaSizes.activeScreen === ScreenSize.medium) { // * floating sidebar case\n this.selectTab(+!this.tabId, animate);\n return;\n }\n } else if(chatIndex > 0 && chat.peerId && chat.peerId !== peerId) {\n // const firstChat = this.chats[0];\n // if(firstChat.peerId !== chat.peerId) {\n /* // * slice idx > 0, set background and slice first, so new one will be the first\n const spliced = this.chats.splice(1, this.chats.length - 1);\n this.createNewChat();\n this.chats.splice(0, 1); */\n const spliced = this.chats.splice(1, this.chats.length - 1);\n if(this.chat.peerId === peerId) {\n this.spliceChats(0, true, true, spliced);\n return;\n } else {\n const ret = this.setPeer(options);\n this.spliceChats(0, false, false, spliced);\n return ret;\n }\n // } else {\n // this.spliceChats(1, false, animate);\n // }\n\n //return ret;\n }\n\n // * don't reset peer if returning\n if(peerId === chat.peerId && mediaSizes.activeScreen <= ScreenSize.medium && document.body.classList.contains(LEFT_COLUMN_ACTIVE_CLASSNAME)) {\n this.selectTab(1, animate);\n return false;\n }\n\n if(peerId || mediaSizes.activeScreen !== ScreenSize.mobile) {\n const result = chat.setPeer(peerId, lastMsgId, options.startParam);\n\n // * wait for cached render\n const promise = result?.cached ? result.promise : Promise.resolve();\n if(peerId) {\n Promise.all([\n promise,\n chat.setBackgroundPromise\n ]).then(() => {\n //window.requestAnimationFrame(() => {\n setTimeout(() => { // * setTimeout is better here\n setTimeout(() => {\n this.chatsSelectTab(this.chat.container);\n }, 0);\n this.selectTab(1, animate);\n }, 0);\n });\n }\n }\n\n if(!peerId) {\n this.selectTab(0, animate);\n return false;\n }\n }\n\n public setInnerPeer(options: ChatSetInnerPeerOptions) {\n const {peerId} = options;\n if(peerId === NULL_PEER_ID || !peerId) {\n return;\n }\n\n const type = options.type ??= 'chat';\n\n // * prevent opening already opened peer\n const existingIndex = this.chats.findIndex(chat => chat.peerId === peerId && chat.type === type);\n if(existingIndex !== -1) {\n this.spliceChats(existingIndex + 1);\n return this.setPeer(options);\n }\n\n const oldChat = this.chat;\n let chat = oldChat;\n if(oldChat.inited) { // * use first not inited chat\n chat = this.createNewChat();\n }\n\n if(type) {\n chat.setType(type);\n\n if(options.threadId) {\n chat.threadId = options.threadId;\n }\n }\n\n rootScope.dispatchEvent('chat_changing', {from: oldChat, to: chat});\n\n //this.chatsSelectTab(chat.container);\n\n return this.setPeer(options);\n }\n\n public openScheduled(peerId: PeerId) {\n this.setInnerPeer({\n peerId, \n type: 'scheduled'\n });\n }\n\n private getTypingElement(action: SendMessageAction) {\n const el = document.createElement('span');\n let c = 'peer-typing';\n el.classList.add(c);\n el.dataset.action = action._;\n switch(action._) {\n case 'sendMessageTypingAction': {\n //default: {\n c += '-text';\n for(let i = 0; i < 3; ++i) {\n const dot = document.createElement('span');\n dot.className = c + '-dot';\n el.append(dot);\n }\n break;\n }\n\n case 'sendMessageUploadAudioAction':\n case 'sendMessageUploadDocumentAction':\n case 'sendMessageUploadRoundAction':\n case 'sendMessageUploadVideoAction':\n case 'sendMessageUploadPhotoAction': {\n c += '-upload';\n /* const trail = document.createElement('span');\n trail.className = c + '-trail';\n el.append(trail); */\n break;\n }\n\n case 'sendMessageRecordAudioAction':\n case 'sendMessageRecordRoundAction':\n case 'sendMessageRecordVideoAction': {\n c += '-record';\n break;\n }\n\n case 'sendMessageEmojiInteractionSeen':\n case 'sendMessageChooseStickerAction': {\n c += '-choosing-sticker';\n for(let i = 0; i < 2; ++i) {\n const eye = document.createElement('div');\n eye.className = c + '-eye';\n el.append(eye);\n }\n break;\n }\n }\n\n el.classList.add(c);\n\n return el;\n }\n\n public getPeerTyping(peerId: PeerId, container?: HTMLElement) {\n if(!appUsersManager.isBot(peerId)) {\n const typings = appProfileManager.getPeerTypings(peerId);\n if(!typings || !typings.length) {\n return;\n }\n\n const typing = typings[0];\n\n const langPackKeys: {\n [peerType in 'private' | 'chat' | 'multi']?: Partial<{[action in SendMessageAction['_']]: LangPackKey}>\n } = {\n private: {\n 'sendMessageTypingAction': 'Peer.Activity.User.TypingText',\n 'sendMessageUploadAudioAction': 'Peer.Activity.User.SendingFile',\n 'sendMessageUploadDocumentAction': 'Peer.Activity.User.SendingFile',\n 'sendMessageUploadPhotoAction': 'Peer.Activity.User.SendingPhoto',\n 'sendMessageUploadVideoAction': 'Peer.Activity.User.SendingVideo',\n 'sendMessageUploadRoundAction': 'Peer.Activity.User.SendingVideo',\n 'sendMessageRecordVideoAction': 'Peer.Activity.User.RecordingVideo',\n 'sendMessageRecordAudioAction': 'Peer.Activity.User.RecordingAudio',\n 'sendMessageRecordRoundAction': 'Peer.Activity.User.RecordingVideo',\n 'sendMessageGamePlayAction': 'Peer.Activity.User.PlayingGame',\n 'sendMessageChooseStickerAction': 'Peer.Activity.User.ChoosingSticker',\n 'sendMessageEmojiInteractionSeen': 'Peer.Activity.User.EnjoyingAnimations'\n },\n chat: {\n 'sendMessageTypingAction': 'Peer.Activity.Chat.TypingText',\n 'sendMessageUploadAudioAction': 'Peer.Activity.Chat.SendingFile',\n 'sendMessageUploadDocumentAction': 'Peer.Activity.Chat.SendingFile',\n 'sendMessageUploadPhotoAction': 'Peer.Activity.Chat.SendingPhoto',\n 'sendMessageUploadVideoAction': 'Peer.Activity.Chat.SendingVideo',\n 'sendMessageUploadRoundAction': 'Peer.Activity.Chat.SendingVideo',\n 'sendMessageRecordVideoAction': 'Peer.Activity.Chat.RecordingVideo',\n 'sendMessageRecordAudioAction': 'Peer.Activity.Chat.RecordingAudio',\n 'sendMessageRecordRoundAction': 'Peer.Activity.Chat.RecordingVideo',\n 'sendMessageGamePlayAction': 'Peer.Activity.Chat.PlayingGame',\n 'sendMessageChooseStickerAction': 'Peer.Activity.Chat.ChoosingSticker',\n 'sendMessageEmojiInteractionSeen': 'Peer.Activity.Chat.EnjoyingAnimations'\n },\n multi: {\n 'sendMessageTypingAction': 'Peer.Activity.Chat.Multi.TypingText1',\n 'sendMessageUploadAudioAction': 'Peer.Activity.Chat.Multi.SendingFile1',\n 'sendMessageUploadDocumentAction': 'Peer.Activity.Chat.Multi.SendingFile1',\n 'sendMessageUploadPhotoAction': 'Peer.Activity.Chat.Multi.SendingPhoto1',\n 'sendMessageUploadVideoAction': 'Peer.Activity.Chat.Multi.SendingVideo1',\n 'sendMessageUploadRoundAction': 'Peer.Activity.Chat.Multi.SendingVideo1',\n 'sendMessageRecordVideoAction': 'Peer.Activity.Chat.Multi.RecordingVideo1',\n 'sendMessageRecordAudioAction': 'Peer.Activity.Chat.Multi.RecordingAudio1',\n 'sendMessageRecordRoundAction': 'Peer.Activity.Chat.Multi.RecordingVideo1',\n 'sendMessageGamePlayAction': 'Peer.Activity.Chat.Multi.PlayingGame1',\n 'sendMessageChooseStickerAction': 'Peer.Activity.Chat.Multi.ChoosingSticker1'\n }\n };\n\n const mapa = peerId.isUser() ? langPackKeys.private : (typings.length > 1 ? langPackKeys.multi : langPackKeys.chat);\n let action = typing.action;\n\n if(typings.length > 1) {\n const s: any = {};\n typings.forEach(typing => {\n const type = typing.action._;\n if(s[type] === undefined) s[type] = 0;\n ++s[type];\n });\n\n if(Object.keys(s).length > 1) {\n action = {\n _: 'sendMessageTypingAction'\n };\n }\n }\n\n const langPackKey = mapa[action._];\n if(!langPackKey) {\n return;\n }\n\n if(!container) {\n container = document.createElement('span');\n container.classList.add('online', 'peer-typing-container');\n }\n\n container.classList.toggle('peer-typing-flex', action._ === 'sendMessageChooseStickerAction' || action._ === 'sendMessageEmojiInteractionSeen');\n\n let typingElement = container.firstElementChild as HTMLElement;\n if(!typingElement) {\n typingElement = this.getTypingElement(action);\n container.prepend(typingElement);\n } else {\n if(typingElement.dataset.action !== action._) {\n typingElement.replaceWith(this.getTypingElement(action));\n }\n }\n\n let args: any[];\n if(peerId.isAnyChat()) {\n args = [\n new PeerTitle({peerId: typing.userId.toPeerId(false), onlyFirstName: true}).element,\n typings.length - 1\n ];\n }\n\n if(action._ === 'sendMessageEmojiInteractionSeen') {\n if(args) {\n args.pop();\n } else {\n args = [];\n }\n\n const span = htmlToSpan(RichTextProcessor.wrapEmojiText(action.emoticon));\n args.push(span);\n }\n\n const descriptionElement = i18n(langPackKey, args);\n descriptionElement.classList.add('peer-typing-description');\n\n if(container.childElementCount > 1) container.lastElementChild.replaceWith(descriptionElement);\n else container.append(descriptionElement);\n return container;\n }\n }\n\n public async getPeerStatus(peerId: PeerId, ignoreSelf?: boolean) {\n let subtitle: HTMLElement;\n if(!peerId) return;\n\n if(peerId.isAnyChat()) { // not human\n let span = this.getPeerTyping(peerId);\n if(span) {\n return span;\n }\n\n const chatId = peerId.toChatId();\n const chatInfo = await appProfileManager.getChatFull(chatId) as any;\n this.chat.log('chatInfo res:', chatInfo);\n\n const participants_count = chatInfo.participants_count || (chatInfo.participants && chatInfo.participants.participants && chatInfo.participants.participants.length) || 1;\n //if(participants_count) {\n subtitle = appProfileManager.getChatMembersString(chatId);\n\n if(participants_count < 2) {\n return subtitle;\n }\n\n const onlines = await appProfileManager.getOnlines(chatId);\n if(onlines > 1) {\n const span = document.createElement('span');\n \n span.append(...join([subtitle, i18n('OnlineCount', [numberThousandSplitter(onlines)])], false));\n subtitle = span;\n }\n \n return subtitle;\n //}\n } else { // user\n const user = appUsersManager.getUser(peerId);\n \n if(rootScope.myId === peerId && !ignoreSelf) {\n return;\n } else if(user) {\n subtitle = appUsersManager.getUserStatusString(user.id);\n\n if(!appUsersManager.isBot(peerId)) {\n let span = this.getPeerTyping(peerId);\n if(!span && user.status?._ === 'userStatusOnline') {\n span = document.createElement('span');\n span.classList.add('online');\n span.append(subtitle);\n }\n\n if(span) {\n return span;\n }\n }\n \n return subtitle;\n }\n }\n }\n\n public setPeerStatus(peerId: PeerId, element: HTMLElement, needClear: boolean, useWhitespace: boolean, middleware: () => boolean, ignoreSelf?: boolean) {\n if(needClear) {\n element.innerHTML = useWhitespace ? '' : ''; // ! HERE U CAN FIND WHITESPACE\n }\n\n // * good good good\n const typingContainer = element.querySelector('.peer-typing-container') as HTMLElement;\n if(typingContainer && this.getPeerTyping(peerId, typingContainer)) {\n return;\n }\n\n this.getPeerStatus(peerId, ignoreSelf).then((subtitle) => {\n if(!middleware()) {\n return;\n }\n\n replaceContent(element, subtitle || (useWhitespace ? '' : ''));\n });\n }\n\n public setChoosingStickerTyping(cancel: boolean) {\n appMessagesManager.setTyping(this.chat.peerId, {_: cancel ? 'sendMessageCancelAction' : 'sendMessageChooseStickerAction'});\n }\n}\n\nconst appImManager = new AppImManager();\nMOUNT_CLASS_TO && (MOUNT_CLASS_TO.appImManager = appImManager);\nexport default appImManager;\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport appMediaPlaybackController from \"../components/appMediaPlaybackController\";\nimport { IS_APPLE_MOBILE, IS_MOBILE } from \"../environment/userAgent\";\nimport { IS_TOUCH_SUPPORTED } from \"../environment/touchSupport\";\nimport { onMediaLoad } from \"../helpers/files\";\nimport cancelEvent from \"../helpers/dom/cancelEvent\";\nimport ListenerSetter, { Listener } from \"../helpers/listenerSetter\";\nimport ButtonMenu from \"../components/buttonMenu\";\nimport { ButtonMenuToggleHandler } from \"../components/buttonMenuToggle\";\nimport rootScope from \"./rootScope\";\nimport ControlsHover from \"../helpers/dom/controlsHover\";\nimport { addFullScreenListener, cancelFullScreen, isFullScreen, requestFullScreen } from \"../helpers/dom/fullScreen\";\nimport toHHMMSS from \"../helpers/string/toHHMMSS\";\nimport MediaProgressLine from \"../components/mediaProgressLine\";\nimport VolumeSelector from \"../components/volumeSelector\";\nimport debounce from \"../helpers/schedulers/debounce\";\n\nexport default class VideoPlayer extends ControlsHover {\n private static PLAYBACK_RATES = [0.5, 1, 1.5, 2];\n private static PLAYBACK_RATES_ICONS = ['playback_05', 'playback_1x', 'playback_15', 'playback_2x'];\n\n protected video: HTMLVideoElement;\n protected wrapper: HTMLDivElement;\n protected progress: MediaProgressLine;\n protected skin: 'default';\n\n protected listenerSetter: ListenerSetter;\n protected playbackRateButton: HTMLElement;\n protected pipButton: HTMLElement;\n\n /* protected videoParent: HTMLElement;\n protected videoWhichChild: number; */\n\n protected onPlaybackRackMenuToggle?: (open: boolean) => void;\n protected onPip?: (pip: boolean) => void;\n protected onPipClose?: () => void;\n\n constructor({video, play = false, streamable = false, duration, onPlaybackRackMenuToggle, onPip, onPipClose}: {\n video: HTMLVideoElement, \n play?: boolean, \n streamable?: boolean, \n duration?: number,\n onPlaybackRackMenuToggle?: VideoPlayer['onPlaybackRackMenuToggle'],\n onPip?: VideoPlayer['onPip'],\n onPipClose?: VideoPlayer['onPipClose']\n }) {\n super();\n\n this.video = video;\n this.wrapper = document.createElement('div');\n this.wrapper.classList.add('ckin__player');\n\n this.onPlaybackRackMenuToggle = onPlaybackRackMenuToggle;\n this.onPip = onPip;\n this.onPipClose = onPipClose;\n\n this.listenerSetter = new ListenerSetter();\n\n this.setup({\n element: this.wrapper, \n listenerSetter: this.listenerSetter, \n canHideControls: () => {\n return !this.video.paused && (!this.playbackRateButton || !this.playbackRateButton.classList.contains('menu-open'));\n },\n showOnLeaveToClassName: 'media-viewer-caption',\n ignoreClickClassName: 'ckin__controls'\n });\n\n video.parentNode.insertBefore(this.wrapper, video);\n this.wrapper.appendChild(video);\n\n this.skin = 'default';\n\n this.stylePlayer(duration);\n this.setBtnMenuToggle();\n\n if(this.skin === 'default') {\n const controls = this.wrapper.querySelector('.default__controls.ckin__controls') as HTMLDivElement;\n this.progress = new MediaProgressLine(video, streamable);\n controls.prepend(this.progress.container);\n }\n\n if(play/* && video.paused */) {\n const promise = video.play();\n promise.catch((err: Error) => {\n if(err.name === 'NotAllowedError') {\n video.muted = true;\n video.autoplay = true;\n video.play();\n }\n }).finally(() => { // due to autoplay, play will not call\n this.wrapper.classList.toggle('is-playing', !this.video.paused);\n });\n //(this.wrapper.querySelector('.toggle') as HTMLButtonElement).click();\n }\n }\n\n private stylePlayer(initDuration: number) {\n const {wrapper, video, skin, listenerSetter} = this;\n\n wrapper.classList.add(skin);\n \n const html = this.buildControls();\n wrapper.insertAdjacentHTML('beforeend', html);\n let timeDuration: HTMLElement;\n \n if(skin === 'default') {\n this.playbackRateButton = this.wrapper.querySelector('.playback-rate') as HTMLElement;\n this.pipButton = this.wrapper.querySelector('.pip') as HTMLElement;\n \n const toggle = wrapper.querySelectorAll('.toggle') as NodeListOf<HTMLElement>;\n const fullScreenButton = wrapper.querySelector('.fullscreen') as HTMLElement;\n const timeElapsed = wrapper.querySelector('#time-elapsed');\n timeDuration = wrapper.querySelector('#time-duration') as HTMLElement;\n timeDuration.innerHTML = toHHMMSS(video.duration | 0);\n\n const volumeSelector = new VolumeSelector(listenerSetter);\n\n const leftControls = wrapper.querySelector('.left-controls');\n volumeSelector.btn.classList.remove('btn-icon');\n leftControls.insertBefore(volumeSelector.btn, timeElapsed.parentElement);\n\n Array.from(toggle).forEach((button) => {\n listenerSetter.add(button)('click', () => {\n this.togglePlay();\n });\n });\n\n if(this.pipButton) {\n listenerSetter.add(this.pipButton)('click', () => {\n this.video.requestPictureInPicture();\n });\n\n const onPip = (pip: boolean) => {\n this.wrapper.style.visibility = pip ? 'hidden': '';\n if(this.onPip) {\n this.onPip(pip);\n }\n };\n\n const debounceTime = 20;\n const debouncedPip = debounce(onPip, debounceTime, false, true);\n\n listenerSetter.add(video)('enterpictureinpicture', () => {\n debouncedPip(true);\n\n listenerSetter.add(video)('leavepictureinpicture', () => {\n const onPause = () => {\n clearTimeout(timeout);\n if(this.onPipClose) {\n this.onPipClose();\n }\n };\n const listener = listenerSetter.add(video)('pause', onPause, {once: true}) as any as Listener;\n const timeout = setTimeout(() => {\n listenerSetter.remove(listener);\n }, debounceTime);\n }, {once: true});\n });\n\n listenerSetter.add(video)('leavepictureinpicture', () => {\n debouncedPip(false);\n });\n }\n\n if(!IS_TOUCH_SUPPORTED) {\n listenerSetter.add(video)('click', () => {\n this.togglePlay();\n });\n\n listenerSetter.add(document)('keydown', (e: KeyboardEvent) => {\n if(rootScope.overlaysActive > 1 || document.pictureInPictureElement === video) { // forward popup is active, etc\n return;\n }\n\n const {key, code} = e;\n\n let good = true;\n if(code === 'KeyF') {\n this.toggleFullScreen();\n } else if(code === 'KeyM') {\n appMediaPlaybackController.muted = !appMediaPlaybackController.muted;\n } else if(code === 'Space') {\n this.togglePlay();\n } else if(e.altKey && (code === 'Equal' || code === 'Minus')) {\n const add = code === 'Equal' ? 1 : -1;\n const playbackRate = appMediaPlaybackController.playbackRate;\n const idx = VideoPlayer.PLAYBACK_RATES.indexOf(playbackRate);\n const nextIdx = idx + add;\n if(nextIdx >= 0 && nextIdx < VideoPlayer.PLAYBACK_RATES.length) {\n appMediaPlaybackController.playbackRate = VideoPlayer.PLAYBACK_RATES[nextIdx];\n }\n } else if(wrapper.classList.contains('ckin__fullscreen') && (key === 'ArrowLeft' || key === 'ArrowRight')) {\n if(key === 'ArrowLeft') appMediaPlaybackController.seekBackward({action: 'seekbackward'});\n else appMediaPlaybackController.seekForward({action: 'seekforward'});\n } else {\n good = false;\n }\n\n if(good) {\n cancelEvent(e);\n return false;\n }\n });\n }\n\n listenerSetter.add(video)('dblclick', () => {\n if(!IS_TOUCH_SUPPORTED) {\n this.toggleFullScreen();\n }\n });\n\n listenerSetter.add(fullScreenButton)('click', () => {\n this.toggleFullScreen();\n });\n\n addFullScreenListener(wrapper, this.onFullScreen.bind(this, fullScreenButton), listenerSetter);\n\n listenerSetter.add(video)('timeupdate', () => {\n timeElapsed.innerHTML = toHHMMSS(video.currentTime | 0);\n });\n\n listenerSetter.add(video)('play', () => {\n wrapper.classList.add('played');\n\n if(!IS_TOUCH_SUPPORTED) {\n listenerSetter.add(video)('play', () => {\n this.hideControls(true);\n });\n }\n }, {once: true});\n\n listenerSetter.add(video)('pause', () => {\n this.showControls(false);\n });\n\n listenerSetter.add(rootScope)('media_playback_params', () => {\n this.setPlaybackRateIcon();\n });\n }\n\n listenerSetter.add(video)('play', () => {\n wrapper.classList.add('is-playing');\n });\n\n listenerSetter.add(video)('pause', () => {\n wrapper.classList.remove('is-playing');\n });\n\n if(video.duration || initDuration) {\n timeDuration.innerHTML = toHHMMSS(Math.round(video.duration || initDuration));\n } else {\n onMediaLoad(video).then(() => {\n timeDuration.innerHTML = toHHMMSS(Math.round(video.duration));\n });\n }\n }\n\n protected togglePlay() {\n this.video[this.video.paused ? 'play' : 'pause']();\n }\n\n private buildControls() {\n const skin = this.skin;\n if(skin === 'default') {\n return `\n <button class=\"${skin}__button--big toggle tgico\" title=\"Toggle Play\"></button>\n <div class=\"${skin}__gradient-bottom ckin__controls\"></div>\n <div class=\"${skin}__controls ckin__controls\">\n <div class=\"bottom-controls\">\n <div class=\"left-controls\">\n <button class=\"btn-icon ${skin}__button toggle tgico\" title=\"Toggle Video\"></button>\n <div class=\"time\">\n <time id=\"time-elapsed\">0:00</time>\n <span> / </span>\n <time id=\"time-duration\">0:00</time>\n </div>\n </div>\n <div class=\"right-controls\">\n <button class=\"btn-icon ${skin}__button btn-menu-toggle playback-rate night\" title=\"Playback Rate\"></button>\n ${!IS_MOBILE && document.pictureInPictureEnabled ? `<button class=\"btn-icon ${skin}__button pip tgico-pip\" title=\"Picture-in-Picture\"></button>` : ''}\n <button class=\"btn-icon ${skin}__button fullscreen tgico-fullscreen\" title=\"Full Screen\"></button>\n </div>\n </div>\n </div>`;\n }\n }\n\n protected setBtnMenuToggle() {\n const buttons: Parameters<typeof ButtonMenu>[0] = VideoPlayer.PLAYBACK_RATES.map((rate, idx) => {\n return { \n // icon: VideoPlayer.PLAYBACK_RATES_ICONS[idx],\n regularText: rate + 'x', \n onClick: () => {\n appMediaPlaybackController.playbackRate = rate;\n }\n };\n });\n const btnMenu = ButtonMenu(buttons);\n btnMenu.classList.add('top-left');\n ButtonMenuToggleHandler(\n this.playbackRateButton, \n this.onPlaybackRackMenuToggle ? () => {\n this.onPlaybackRackMenuToggle(true);\n } : undefined, \n undefined, \n this.onPlaybackRackMenuToggle ? () => {\n this.onPlaybackRackMenuToggle(false);\n } : undefined\n );\n this.playbackRateButton.append(btnMenu);\n\n this.setPlaybackRateIcon();\n }\n\n protected setPlaybackRateIcon() {\n const playbackRateButton = this.playbackRateButton;\n VideoPlayer.PLAYBACK_RATES_ICONS.forEach((className) => {\n className = 'tgico-' + className;\n playbackRateButton.classList.remove(className);\n });\n\n let idx = VideoPlayer.PLAYBACK_RATES.indexOf(appMediaPlaybackController.playbackRate);\n if(idx === -1) idx = VideoPlayer.PLAYBACK_RATES.indexOf(1);\n\n playbackRateButton.classList.add('tgico-' + VideoPlayer.PLAYBACK_RATES_ICONS[idx]);\n }\n \n protected toggleFullScreen() {\n const player = this.wrapper;\n\n // * https://caniuse.com/#feat=fullscreen\n if(IS_APPLE_MOBILE) {\n const video = this.video as any;\n video.webkitEnterFullscreen();\n video.enterFullscreen();\n return;\n }\n \n if(!isFullScreen()) {\n /* const videoParent = this.video.parentElement;\n const videoWhichChild = whichChild(this.video);\n const needVideoRemount = videoParent !== player;\n\n if(needVideoRemount) {\n this.videoParent = videoParent;\n this.videoWhichChild = videoWhichChild;\n player.prepend(this.video);\n } */\n \n requestFullScreen(player);\n } else {\n /* if(this.videoParent) {\n const {videoWhichChild, videoParent} = this;\n if(!videoWhichChild) {\n videoParent.prepend(this.video);\n } else {\n videoParent.insertBefore(this.video, videoParent.children[videoWhichChild]);\n }\n\n this.videoParent = null;\n this.videoWhichChild = -1;\n } */\n \n cancelFullScreen();\n }\n }\n \n protected onFullScreen(fullScreenButton: HTMLElement) {\n const isFull = isFullScreen();\n this.wrapper.classList.toggle('ckin__fullscreen', isFull);\n if(!isFull) {\n fullScreenButton.classList.remove('tgico-smallscreen');\n fullScreenButton.classList.add('tgico-fullscreen');\n fullScreenButton.setAttribute('title', 'Full Screen');\n } else {\n fullScreenButton.classList.remove('tgico-fullscreen');\n fullScreenButton.classList.add('tgico-smallscreen');\n fullScreenButton.setAttribute('title', 'Exit Full Screen');\n }\n }\n\n public cleanup() {\n super.cleanup();\n this.listenerSetter.removeAll();\n this.progress.removeListeners();\n this.onPlaybackRackMenuToggle = this.onPip = undefined;\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport deferredPromise from \"../helpers/cancellablePromise\";\nimport mediaSizes from \"../helpers/mediaSizes\";\nimport { IS_TOUCH_SUPPORTED } from \"../environment/touchSupport\";\nimport { IS_MOBILE_SAFARI, IS_SAFARI } from \"../environment/userAgent\";\nimport appDocsManager, { MyDocument } from \"../lib/appManagers/appDocsManager\";\nimport appPhotosManager, { MyPhoto } from \"../lib/appManagers/appPhotosManager\";\nimport { logger } from \"../lib/logger\";\nimport VideoPlayer from \"../lib/mediaPlayer\";\nimport rootScope from \"../lib/rootScope\";\nimport animationIntersector from \"./animationIntersector\";\nimport appMediaPlaybackController, { AppMediaPlaybackController } from \"./appMediaPlaybackController\";\nimport AvatarElement from \"./avatar\";\nimport ButtonIcon from \"./buttonIcon\";\nimport { ButtonMenuItemOptions } from \"./buttonMenu\";\nimport ButtonMenuToggle from \"./buttonMenuToggle\";\nimport { LazyLoadQueueBase } from \"./lazyLoadQueue\";\nimport ProgressivePreloader from \"./preloader\";\nimport SwipeHandler from \"./swipeHandler\";\nimport { formatFullSentTime } from \"../helpers/date\";\nimport appNavigationController, { NavigationItem } from \"./appNavigationController\";\nimport { Message } from \"../layer\";\nimport findUpClassName from \"../helpers/dom/findUpClassName\";\nimport renderImageFromUrl, { renderImageFromUrlPromise } from \"../helpers/dom/renderImageFromUrl\";\nimport getVisibleRect from \"../helpers/dom/getVisibleRect\";\nimport appDownloadManager from \"../lib/appManagers/appDownloadManager\";\nimport cancelEvent from \"../helpers/dom/cancelEvent\";\nimport fillPropertyValue from \"../helpers/fillPropertyValue\";\nimport generatePathData from \"../helpers/generatePathData\";\nimport replaceContent from \"../helpers/dom/replaceContent\";\nimport PeerTitle from \"./peerTitle\";\nimport { doubleRaf, fastRaf } from \"../helpers/schedulers\";\nimport RangeSelector from \"./rangeSelector\";\nimport windowSize from \"../helpers/windowSize\";\nimport ListLoader from \"../helpers/listLoader\";\nimport EventListenerBase from \"../helpers/eventListenerBase\";\nimport { MyMessage } from \"../lib/appManagers/appMessagesManager\";\nimport RichTextProcessor from \"../lib/richtextprocessor\";\nimport { NULL_PEER_ID } from \"../lib/mtproto/mtproto_config\";\nimport { isFullScreen } from \"../helpers/dom/fullScreen\";\nimport { attachClickEvent } from \"../helpers/dom/clickEvent\";\nimport SearchListLoader from \"../helpers/searchListLoader\";\nimport createVideo from \"../helpers/dom/createVideo\";\n\nconst ZOOM_STEP = 0.5;\nconst ZOOM_INITIAL_VALUE = 1;\nconst ZOOM_MIN_VALUE = 0.5;\nconst ZOOM_MAX_VALUE = 4;\n\n// TODO: масштабирование картинок (не SVG) при ресайзе, и правильный возврат на исходную позицию\n// TODO: картинки \"обрезаются\" если возвращаются или появляются с места, где есть их перекрытие (топбар, поле ввода)\n// TODO: видео в мобильной вёрстке, если показываются элементы управления: если свайпнуть в сторону, то элементы вернутся на место, т.е. прыгнут - это не ок, надо бы замаскировать\n\nexport const MEDIA_VIEWER_CLASSNAME = 'media-viewer';\n\nexport default class AppMediaViewerBase<\n ContentAdditionType extends string, \n ButtonsAdditionType extends string, \n TargetType extends {element: HTMLElement\n}> extends EventListenerBase<{\n setMoverBefore: () => void,\n setMoverAfter: () => void\n}> {\n protected wholeDiv: HTMLElement;\n protected overlaysDiv: HTMLElement;\n protected author: {[k in 'container' | 'avatarEl' | 'nameEl' | 'date']: HTMLElement} = {} as any;\n protected content: {[k in 'main' | 'container' | 'media' | 'mover' | ContentAdditionType]: HTMLElement} = {} as any;\n protected buttons: {[k in 'download' | 'close' | 'prev' | 'next' | 'mobile-close' | 'zoom' | ButtonsAdditionType]: HTMLElement} = {} as any;\n protected topbar: HTMLElement;\n protected moversContainer: HTMLElement;\n \n protected tempId = 0;\n protected preloader: ProgressivePreloader = null;\n protected preloaderStreamable: ProgressivePreloader = null;\n\n //protected targetContainer: HTMLElement = null;\n //protected loadMore: () => void = null;\n\n protected log: ReturnType<typeof logger>; \n\n protected isFirstOpen = true;\n\n // protected needLoadMore = true;\n\n protected pageEl = document.getElementById('page-chats') as HTMLDivElement;\n\n protected setMoverPromise: Promise<void>;\n protected setMoverAnimationPromise: Promise<void>;\n\n protected lazyLoadQueue: LazyLoadQueueBase;\n\n protected highlightSwitchersTimeout: number;\n\n protected onDownloadClick: (e: MouseEvent) => void;\n protected onPrevClick: (target: TargetType) => void;\n protected onNextClick: (target: TargetType) => void;\n\n protected videoPlayer: VideoPlayer;\n\n protected zoomElements: {\n container: HTMLElement,\n btnOut: HTMLElement,\n btnIn: HTMLElement,\n rangeSelector: RangeSelector\n } = {} as any;\n // protected zoomValue = ZOOM_INITIAL_VALUE;\n protected zoomSwipeHandler: SwipeHandler;\n protected zoomSwipeStartX = 0;\n protected zoomSwipeStartY = 0;\n protected zoomSwipeX = 0;\n protected zoomSwipeY = 0;\n \n protected ctrlKeyDown: boolean;\n protected releaseSingleMedia: ReturnType<AppMediaPlaybackController['setSingleMedia']>;\n protected navigationItem: NavigationItem;\n\n get target() {\n return this.listLoader.current;\n }\n\n set target(value) {\n this.listLoader.current = value;\n }\n\n constructor(\n protected listLoader: ListLoader<TargetType, any>, \n topButtons: Array<keyof AppMediaViewerBase<ContentAdditionType, ButtonsAdditionType, TargetType>['buttons']>\n ) {\n super(false);\n\n this.log = logger('AMV');\n this.preloader = new ProgressivePreloader();\n this.preloaderStreamable = new ProgressivePreloader({\n cancelable: false,\n streamable: true\n });\n this.preloader.construct();\n this.preloaderStreamable.construct();\n this.lazyLoadQueue = new LazyLoadQueueBase();\n\n this.wholeDiv = document.createElement('div');\n this.wholeDiv.classList.add(MEDIA_VIEWER_CLASSNAME + '-whole');\n\n this.overlaysDiv = document.createElement('div');\n this.overlaysDiv.classList.add('overlays');\n\n const mainDiv = document.createElement('div');\n mainDiv.classList.add(MEDIA_VIEWER_CLASSNAME);\n\n const topbar = this.topbar = document.createElement('div');\n topbar.classList.add(MEDIA_VIEWER_CLASSNAME + '-topbar', MEDIA_VIEWER_CLASSNAME + '-appear');\n\n const topbarLeft = document.createElement('div');\n topbarLeft.classList.add(MEDIA_VIEWER_CLASSNAME + '-topbar-left');\n\n this.buttons['mobile-close'] = ButtonIcon('close', {onlyMobile: true});\n \n // * author\n this.author.container = document.createElement('div');\n this.author.container.classList.add(MEDIA_VIEWER_CLASSNAME + '-author', 'no-select');\n const authorRight = document.createElement('div');\n \n this.author.avatarEl = new AvatarElement();\n this.author.avatarEl.classList.add(MEDIA_VIEWER_CLASSNAME + '-userpic', 'avatar-44');\n \n this.author.nameEl = document.createElement('div');\n this.author.nameEl.classList.add(MEDIA_VIEWER_CLASSNAME + '-name');\n \n this.author.date = document.createElement('div');\n this.author.date.classList.add(MEDIA_VIEWER_CLASSNAME + '-date');\n \n authorRight.append(this.author.nameEl, this.author.date);\n \n this.author.container.append(this.author.avatarEl, authorRight);\n \n // * buttons\n const buttonsDiv = document.createElement('div');\n buttonsDiv.classList.add(MEDIA_VIEWER_CLASSNAME + '-buttons');\n \n topButtons.concat(['download', 'zoom', 'close']).forEach(name => {\n const button = ButtonIcon(name, {noRipple: true});\n this.buttons[name] = button;\n buttonsDiv.append(button);\n });\n\n this.buttons.zoom.classList.add('zoom-in');\n\n // * zoom\n this.zoomElements.container = document.createElement('div');\n this.zoomElements.container.classList.add('zoom-container');\n\n this.zoomElements.btnOut = ButtonIcon('zoomout', {noRipple: true});\n attachClickEvent(this.zoomElements.btnOut, () => this.changeZoom(false));\n this.zoomElements.btnIn = ButtonIcon('zoomin', {noRipple: true});\n attachClickEvent(this.zoomElements.btnIn, () => this.changeZoom(true));\n\n this.zoomElements.rangeSelector = new RangeSelector({\n step: ZOOM_STEP, \n min: ZOOM_MIN_VALUE, \n max: ZOOM_MAX_VALUE, \n withTransition: true\n }, ZOOM_INITIAL_VALUE);\n this.zoomElements.rangeSelector.setListeners();\n this.zoomElements.rangeSelector.setHandlers({\n onScrub: this.setZoomValue,\n onMouseUp: () => this.setZoomValue()\n });\n\n this.zoomElements.container.append(this.zoomElements.btnOut, this.zoomElements.rangeSelector.container, this.zoomElements.btnIn);\n\n this.wholeDiv.append(this.zoomElements.container);\n\n // * content\n this.content.main = document.createElement('div');\n this.content.main.classList.add(MEDIA_VIEWER_CLASSNAME + '-content');\n\n this.content.container = document.createElement('div');\n this.content.container.classList.add(MEDIA_VIEWER_CLASSNAME + '-container');\n\n this.content.media = document.createElement('div');\n this.content.media.classList.add(MEDIA_VIEWER_CLASSNAME + '-media');\n\n this.content.container.append(this.content.media);\n\n this.content.main.append(this.content.container);\n mainDiv.append(this.content.main);\n this.overlaysDiv.append(mainDiv);\n // * overlays end\n \n topbarLeft.append(this.buttons['mobile-close'], this.author.container);\n topbar.append(topbarLeft, buttonsDiv);\n\n this.buttons.prev = document.createElement('div');\n this.buttons.prev.className = `${MEDIA_VIEWER_CLASSNAME}-switcher ${MEDIA_VIEWER_CLASSNAME}-switcher-left`;\n this.buttons.prev.innerHTML = `<span class=\"tgico-down ${MEDIA_VIEWER_CLASSNAME}-prev-button\"></span>`;\n\n this.buttons.next = document.createElement('div');\n this.buttons.next.className = `${MEDIA_VIEWER_CLASSNAME}-switcher ${MEDIA_VIEWER_CLASSNAME}-switcher-right`;\n this.buttons.next.innerHTML = `<span class=\"tgico-down ${MEDIA_VIEWER_CLASSNAME}-next-button\"></span>`;\n\n this.moversContainer = document.createElement('div');\n this.moversContainer.classList.add(MEDIA_VIEWER_CLASSNAME + '-movers');\n\n this.wholeDiv.append(this.overlaysDiv, this.buttons.prev, this.buttons.next, this.topbar, this.moversContainer);\n\n // * constructing html end\n\n this.listLoader.onLoadedMore = () => {\n this.buttons.prev.classList.toggle('hide', !this.listLoader.previous.length);\n this.buttons.next.classList.toggle('hide', !this.listLoader.next.length);\n };\n\n this.setNewMover();\n }\n\n protected setListeners() {\n attachClickEvent(this.buttons.download, this.onDownloadClick);\n [this.buttons.close, this.buttons['mobile-close'], this.preloaderStreamable.preloader].forEach(el => {\n attachClickEvent(el, this.close.bind(this));\n });\n\n ([[-1, this.buttons.prev], [1, this.buttons.next]] as [number, HTMLElement][]).forEach(([moveLength, button]) => {\n // attachClickEvent(button, (e) => {\n button.addEventListener('click', (e) => {\n cancelEvent(e);\n if(this.setMoverPromise) return;\n \n this.listLoader.go(moveLength);\n });\n });\n\n attachClickEvent(this.buttons.zoom, () => {\n if(this.isZooming()) this.toggleZoom(false);\n else {\n this.changeZoom(true);\n }\n });\n\n // ! cannot use the function because it'll cancel slide event on touch devices\n // attachClickEvent(this.wholeDiv, this.onClick);\n this.wholeDiv.addEventListener('click', this.onClick);\n\n this.listLoader.onJump = (item, older) => {\n if(older) this.onNextClick(item);\n else this.onPrevClick(item);\n };\n\n if(IS_TOUCH_SUPPORTED) {\n const swipeHandler = new SwipeHandler({\n element: this.wholeDiv, \n onSwipe: (xDiff, yDiff) => {\n if(isFullScreen()) {\n return;\n }\n //console.log(xDiff, yDiff);\n\n const percents = Math.abs(xDiff) / windowSize.width;\n if(percents > .2 || xDiff > 125) {\n //console.log('will swipe', xDiff);\n\n if(xDiff < 0) {\n this.buttons.prev.click();\n } else {\n this.buttons.next.click();\n }\n\n return true;\n }\n\n const percentsY = Math.abs(yDiff) / windowSize.height;\n if(percentsY > .2 || yDiff > 125) {\n this.close();\n return true;\n }\n\n return false;\n }, \n verifyTouchTarget: (evt) => {\n // * Fix for seek input\n if((evt.target as HTMLElement).tagName === 'INPUT' || findUpClassName(evt.target, 'media-viewer-caption')) {\n return false;\n }\n\n return true;\n }\n });\n }\n }\n\n protected toggleZoom(enable?: boolean) {\n const isVisible = this.isZooming();\n if(this.zoomElements.rangeSelector.mousedown || this.ctrlKeyDown) {\n enable = true;\n }\n\n if(isVisible === enable) return;\n\n if(enable === undefined) {\n enable = !isVisible;\n }\n\n this.buttons.zoom.classList.toggle('zoom-in', !enable);\n this.zoomElements.container.classList.toggle('is-visible', enable);\n const zoomValue = enable ? this.zoomElements.rangeSelector.value : 1;\n this.setZoomValue(zoomValue);\n this.zoomElements.rangeSelector.setProgress(zoomValue);\n\n if(this.videoPlayer) {\n this.videoPlayer.lockControls(enable ? false : undefined);\n }\n\n if(enable) {\n if(!this.zoomSwipeHandler) {\n let lastDiffX: number, lastDiffY: number;\n const multiplier = -1;\n this.zoomSwipeHandler = new SwipeHandler({\n element: this.moversContainer,\n onFirstSwipe: () => {\n lastDiffX = lastDiffY = 0;\n this.moversContainer.classList.add('no-transition');\n },\n onSwipe: (xDiff, yDiff) => {\n [xDiff, yDiff] = [xDiff * multiplier, yDiff * multiplier];\n this.zoomSwipeX += xDiff - lastDiffX;\n this.zoomSwipeY += yDiff - lastDiffY;\n [lastDiffX, lastDiffY] = [xDiff, yDiff];\n\n this.setZoomValue();\n },\n onReset: () => {\n this.moversContainer.classList.remove('no-transition');\n },\n cursor: 'move'\n });\n } else {\n this.zoomSwipeHandler.setListeners();\n }\n \n this.zoomElements.rangeSelector.setProgress(zoomValue);\n } else if(!enable) {\n this.zoomSwipeHandler.removeListeners();\n }\n }\n\n protected changeZoom(add: boolean) {\n this.zoomElements.rangeSelector.addProgress(ZOOM_STEP * (add ? 1 : -1));\n this.setZoomValue();\n }\n\n protected setZoomValue = (value = this.zoomElements.rangeSelector.value) => {\n // this.zoomValue = value;\n if(value === ZOOM_INITIAL_VALUE) {\n this.zoomSwipeX = 0;\n this.zoomSwipeY = 0;\n }\n\n this.moversContainer.style.transform = `matrix(${value}, 0, 0, ${value}, ${this.zoomSwipeX}, ${this.zoomSwipeY})`;\n\n this.zoomElements.btnOut.classList.toggle('inactive', value === ZOOM_MIN_VALUE);\n this.zoomElements.btnIn.classList.toggle('inactive', value === ZOOM_MAX_VALUE);\n\n this.toggleZoom(value !== ZOOM_INITIAL_VALUE);\n };\n\n protected isZooming() {\n return this.zoomElements.container.classList.contains('is-visible');\n }\n\n protected setBtnMenuToggle(buttons: ButtonMenuItemOptions[]) {\n const btnMenuToggle = ButtonMenuToggle({onlyMobile: true}, 'bottom-left', buttons);\n this.topbar.append(btnMenuToggle);\n }\n\n public close(e?: MouseEvent) {\n if(e) {\n cancelEvent(e);\n }\n\n if(this.setMoverAnimationPromise) return Promise.reject();\n\n if(this.navigationItem) {\n appNavigationController.removeItem(this.navigationItem);\n }\n\n this.lazyLoadQueue.clear();\n\n const promise = this.setMoverToTarget(this.target?.element, true).then(({onAnimationEnd}) => onAnimationEnd);\n\n this.listLoader.reset();\n (this.listLoader as SearchListLoader<any>).cleanup && (this.listLoader as SearchListLoader<any>).cleanup();\n this.setMoverPromise = null;\n this.tempId = -1;\n if((window as any).appMediaViewer === this) {\n (window as any).appMediaViewer = undefined;\n }\n\n /* if(appSidebarRight.historyTabIDs.slice(-1)[0] === AppSidebarRight.SLIDERITEMSIDS.forward) {\n promise.then(() => {\n appSidebarRight.forwardTab.closeBtn.click();\n });\n } */\n\n this.removeGlobalListeners();\n\n this.zoomSwipeHandler = undefined;\n\n promise.finally(() => {\n this.wholeDiv.remove();\n this.toggleOverlay(false);\n });\n\n return promise;\n }\n\n protected toggleOverlay(active: boolean) {\n rootScope.isOverlayActive = active;\n animationIntersector.checkAnimations(active);\n }\n\n protected toggleGlobalListeners(active: boolean) {\n if(active) this.setGlobalListeners();\n else this.removeGlobalListeners();\n }\n\n protected removeGlobalListeners() {\n if(this.zoomSwipeHandler) {\n this.zoomSwipeHandler.removeListeners();\n }\n\n window.removeEventListener('keydown', this.onKeyDown);\n window.removeEventListener('keyup', this.onKeyUp);\n window.removeEventListener('wheel', this.onWheel, {capture: true});\n }\n\n protected setGlobalListeners() {\n if(this.isZooming()) {\n this.zoomSwipeHandler.setListeners();\n }\n\n window.addEventListener('keydown', this.onKeyDown);\n window.addEventListener('keyup', this.onKeyUp);\n if(!IS_TOUCH_SUPPORTED) window.addEventListener('wheel', this.onWheel, {passive: false, capture: true});\n }\n\n onClick = (e: MouseEvent) => {\n if(this.setMoverAnimationPromise) return;\n\n const target = e.target as HTMLElement;\n if(target.tagName === 'A') return;\n cancelEvent(e);\n\n if(IS_TOUCH_SUPPORTED) {\n if(this.highlightSwitchersTimeout) {\n clearTimeout(this.highlightSwitchersTimeout);\n } else {\n this.wholeDiv.classList.add('highlight-switchers');\n }\n\n this.highlightSwitchersTimeout = window.setTimeout(() => {\n this.wholeDiv.classList.remove('highlight-switchers');\n this.highlightSwitchersTimeout = 0;\n }, 3e3);\n \n return;\n }\n\n const isZooming = this.isZooming();\n let mover: HTMLElement = null;\n const classNames = ['ckin__player', 'media-viewer-buttons', 'media-viewer-author', 'media-viewer-caption', 'zoom-container'];\n if(isZooming) {\n classNames.push('media-viewer-movers');\n }\n\n classNames.find(s => {\n try {\n mover = findUpClassName(target, s);\n if(mover) return true;\n } catch(err) {return false;}\n });\n\n if(/* target === this.mediaViewerDiv */!mover || (!isZooming && (target.tagName === 'IMG' || target.tagName === 'image'))) {\n this.close();\n }\n };\n\n private onKeyDown = (e: KeyboardEvent) => {\n //this.log('onKeyDown', e);\n if(rootScope.overlaysActive > 1) {\n return;\n }\n\n const key = e.key;\n \n let good = true;\n if(key === 'ArrowRight') {\n this.buttons.next.click();\n } else if(key === 'ArrowLeft') {\n this.buttons.prev.click();\n } else if(key === '-' || key === '=') {\n if(this.ctrlKeyDown) {\n this.changeZoom(key === '=');\n }\n } else {\n good = false;\n }\n\n if(e.ctrlKey || e.metaKey) {\n this.ctrlKeyDown = true;\n }\n\n if(good) {\n cancelEvent(e);\n }\n };\n\n private onKeyUp = (e: KeyboardEvent) => {\n if(rootScope.overlaysActive > 1) {\n return;\n }\n\n if(!(e.ctrlKey || e.metaKey)) {\n this.ctrlKeyDown = false;\n\n if(this.isZooming()) {\n this.setZoomValue();\n }\n }\n };\n\n private onWheel = (e: WheelEvent) => {\n if(rootScope.overlaysActive > 1 || (findUpClassName(e.target, 'media-viewer-caption') && !this.ctrlKeyDown)) {\n return;\n }\n\n cancelEvent(e);\n\n if(this.ctrlKeyDown) {\n const scrollingUp = e.deltaY < 0;\n // if(!scrollingUp && !this.isZooming()) return;\n this.changeZoom(!!scrollingUp);\n }\n };\n\n protected async setMoverToTarget(target: HTMLElement, closing = false, fromRight = 0) {\n this.dispatchEvent('setMoverBefore');\n\n const mover = this.content.mover;\n\n if(!closing) {\n mover.innerHTML = '';\n //mover.append(this.buttons.prev, this.buttons.next);\n }\n \n const zoomValue = this.isZooming() && closing /* && false */ ? this.zoomElements.rangeSelector.value : ZOOM_INITIAL_VALUE;\n /* if(!(zoomValue > 1 && closing)) */ this.removeCenterFromMover(mover);\n\n const wasActive = fromRight !== 0;\n\n const delay = rootScope.settings.animationsEnabled ? (wasActive ? 350 : 200) : 0;\n //let delay = wasActive ? 350 : 10000;\n\n /* if(wasActive) {\n this.moveTheMover(mover);\n mover = this.setNewMover();\n } */\n\n /* if(DEBUG) {\n this.log('setMoverToTarget', target, closing, wasActive, fromRight);\n } */\n\n let realParent: HTMLElement;\n\n let rect: DOMRect;\n if(target) {\n if(target instanceof AvatarElement || target.classList.contains('grid-item')/* || target.classList.contains('document-ico') */) {\n realParent = target;\n rect = target.getBoundingClientRect();\n } else if(target instanceof SVGImageElement || target.parentElement instanceof SVGForeignObjectElement) {\n realParent = findUpClassName(target, 'attachment');\n rect = realParent.getBoundingClientRect();\n } else if(target.classList.contains('profile-avatars-avatar')) {\n realParent = findUpClassName(target, 'profile-avatars-container');\n rect = realParent.getBoundingClientRect();\n\n // * if not active avatar\n if(closing && target.getBoundingClientRect().left !== rect.left) {\n target = realParent = rect = undefined;\n }\n }\n }\n\n if(!target) {\n target = this.content.media;\n }\n\n if(!rect) {\n realParent = target.parentElement as HTMLElement;\n rect = target.getBoundingClientRect();\n }\n\n let needOpacity = false;\n if(target !== this.content.media && !target.classList.contains('profile-avatars-avatar')) {\n const overflowElement = findUpClassName(realParent, 'scrollable');\n const visibleRect = getVisibleRect(realParent, overflowElement, true);\n\n if(closing && (!visibleRect || visibleRect.overflow.vertical === 2 || visibleRect.overflow.horizontal === 2)) {\n target = this.content.media;\n realParent = target.parentElement as HTMLElement;\n rect = target.getBoundingClientRect();\n } else if(visibleRect && (visibleRect.overflow.vertical === 1 || visibleRect.overflow.horizontal === 1)) {\n needOpacity = true;\n }\n }\n\n const containerRect = this.content.media.getBoundingClientRect();\n \n let transform = '';\n let left: number;\n let top: number;\n\n if(wasActive) {\n left = fromRight === 1 ? windowSize.width : -containerRect.width;\n top = containerRect.top;\n } else {\n left = rect.left;\n top = rect.top;\n }\n\n /* if(zoomValue > 1) { // 33\n // const diffX = (rect.width * zoomValue - rect.width) / 4;\n const diffX = (rect.width * zoomValue - rect.width) / 2;\n const diffY = (rect.height * zoomValue - rect.height) / 4;\n // left -= diffX;\n // top += diffY;\n } */\n\n transform += `translate3d(${left}px,${top}px,0) `;\n\n /* if(wasActive) {\n left = fromRight === 1 ? appPhotosManager.windowW / 2 : -(containerRect.width + appPhotosManager.windowW / 2);\n transform += `translate(${left}px,-50%) `;\n } else {\n left = rect.left - (appPhotosManager.windowW / 2);\n top = rect.top - (appPhotosManager.windowH / 2);\n transform += `translate(${left}px,${top}px) `;\n } */\n\n let aspecter: HTMLDivElement;\n if(target instanceof HTMLImageElement || target instanceof HTMLVideoElement || target.tagName === 'DIV') {\n if(mover.firstElementChild && mover.firstElementChild.classList.contains('media-viewer-aspecter')) {\n aspecter = mover.firstElementChild as HTMLDivElement;\n\n const player = aspecter.querySelector('.ckin__player');\n if(player) {\n const video = player.firstElementChild as HTMLVideoElement;\n aspecter.append(video);\n player.remove();\n }\n\n if(!aspecter.style.cssText) { // всё из-за видео, элементы управления скейлятся, так бы можно было этого не делать\n mover.classList.remove('active');\n this.setFullAspect(aspecter, containerRect, rect);\n void mover.offsetLeft; // reflow\n mover.classList.add('active');\n }\n } else {\n aspecter = document.createElement('div');\n aspecter.classList.add('media-viewer-aspecter'/* , 'disable-hover' */);\n mover.prepend(aspecter);\n }\n \n aspecter.style.cssText = `width: ${rect.width}px; height: ${rect.height}px; transform: scale3d(${containerRect.width / rect.width}, ${containerRect.height / rect.height}, 1);`;\n }\n\n mover.style.width = containerRect.width + 'px';\n mover.style.height = containerRect.height + 'px';\n\n // const scaleX = rect.width / (containerRect.width * zoomValue);\n // const scaleY = rect.height / (containerRect.height * zoomValue);\n const scaleX = rect.width / containerRect.width;\n const scaleY = rect.height / containerRect.height;\n if(!wasActive) {\n transform += `scale3d(${scaleX},${scaleY},1) `;\n }\n\n let borderRadius = window.getComputedStyle(realParent).getPropertyValue('border-radius');\n const brSplitted = fillPropertyValue(borderRadius) as string[];\n borderRadius = brSplitted.map(r => (parseInt(r) / scaleX) + 'px').join(' ');\n if(!wasActive) {\n mover.style.borderRadius = borderRadius;\n }\n //let borderRadius = '0px 0px 0px 0px';\n\n if(closing && zoomValue !== 1) {\n // const width = this.moversContainer.scrollWidth * scaleX;\n // const height = this.moversContainer.scrollHeight * scaleY;\n const willBeLeft = windowSize.width / 2 - rect.width / 2;\n const willBeTop = windowSize.height / 2 - rect.height / 2;\n const left = rect.left - willBeLeft/* + (width - rect.width) / 2 */;\n const top = rect.top - willBeTop/* + (height - rect.height) / 2 */;\n this.moversContainer.style.transform = `matrix(${scaleX}, 0, 0, ${scaleY}, ${left}, ${top})`;\n } else {\n mover.style.transform = transform;\n }\n\n needOpacity && (mover.style.opacity = '0'/* !closing ? '0' : '' */);\n\n /* if(wasActive) {\n this.log('setMoverToTarget', mover.style.transform);\n } */\n\n let path: SVGPathElement;\n const isOut = target.classList.contains('is-out');\n\n const deferred = this.setMoverAnimationPromise = deferredPromise<void>();\n const ret = {onAnimationEnd: deferred};\n\n const timeout = setTimeout(() => {\n if(!deferred.isFulfilled && !deferred.isRejected) {\n deferred.resolve();\n }\n }, 1000);\n\n deferred.finally(() => {\n this.dispatchEvent('setMoverAfter');\n\n if(this.setMoverAnimationPromise === deferred) {\n this.setMoverAnimationPromise = null;\n }\n \n clearTimeout(timeout);\n });\n\n if(!closing) {\n let mediaElement: HTMLImageElement | HTMLVideoElement;\n let src: string;\n\n if(target instanceof HTMLVideoElement) {\n const elements = Array.from(target.parentElement.querySelectorAll('img')) as HTMLImageElement[];\n if(elements.length) {\n target = elements.pop();\n }\n }\n\n if(target.tagName === 'DIV' || target.tagName === 'AVATAR-ELEMENT') { // useContainerAsTarget\n const images = Array.from(target.querySelectorAll('img')) as HTMLImageElement[];\n const image = images.pop();\n if(image) {\n mediaElement = new Image();\n src = image.src;\n mover.append(mediaElement);\n }\n /* mediaElement = new Image();\n src = target.style.backgroundImage.slice(5, -2); */\n \n } else if(target instanceof HTMLImageElement) {\n mediaElement = new Image();\n src = target.src;\n } else if(target instanceof HTMLVideoElement) {\n mediaElement = createVideo();\n mediaElement.src = target.src;\n } else if(target instanceof SVGSVGElement) {\n const clipId = target.dataset.clipId;\n const newClipId = clipId + '-mv';\n\n const {width, height} = containerRect;\n\n const newSvg = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\");\n newSvg.setAttributeNS(null, 'width', '' + width);\n newSvg.setAttributeNS(null, 'height', '' + height);\n\n // нижние два свойства для масштабирования\n newSvg.setAttributeNS(null, 'viewBox', `0 0 ${width} ${height}`);\n newSvg.setAttributeNS(null, 'preserveAspectRatio', 'xMidYMid meet');\n\n newSvg.insertAdjacentHTML('beforeend', target.firstElementChild.outerHTML.replace(clipId, newClipId));\n newSvg.insertAdjacentHTML('beforeend', target.lastElementChild.outerHTML.replace(clipId, newClipId));\n\n // теперь надо выставить новую позицию для хвостика\n const defs = newSvg.firstElementChild;\n const use = defs.firstElementChild.firstElementChild as SVGUseElement;\n if(use instanceof SVGUseElement) {\n let transform = use.getAttributeNS(null, 'transform');\n transform = transform.replace(/translate\\((.+?), (.+?)\\) scale\\((.+?), (.+?)\\)/, (match, x, y, sX, sY) => {\n x = +x;\n if(x !== 2) {\n x = width - (2 / scaleX);\n } else {\n x = 2 / scaleX;\n }\n \n y = height;\n \n return `translate(${x}, ${y}) scale(${+sX / scaleX}, ${+sY / scaleY})`;\n });\n use.setAttributeNS(null, 'transform', transform);\n \n // и новый RECT\n path = defs.firstElementChild.lastElementChild as SVGPathElement;\n\n // код ниже нужен только чтобы скрыть моргание до момента как сработает таймаут\n let d: string;\n const br: [number, number, number, number] = borderRadius.split(' ').map(v => parseInt(v)) as any;\n if(isOut) d = generatePathData(0, 0, width - 9 / scaleX, height, ...br);\n else d = generatePathData(9 / scaleX, 0, width - 9 / scaleX, height, ...br);\n path.setAttributeNS(null, 'd', d);\n }\n\n const foreignObject = newSvg.lastElementChild;\n foreignObject.setAttributeNS(null, 'width', '' + containerRect.width);\n foreignObject.setAttributeNS(null, 'height', '' + containerRect.height);\n \n mover.prepend(newSvg);\n }\n\n if(aspecter) {\n aspecter.style.borderRadius = borderRadius;\n\n if(mediaElement) {\n aspecter.append(mediaElement);\n }\n }\n\n mediaElement = mover.querySelector('video, img');\n if(mediaElement instanceof HTMLImageElement) {\n mediaElement.classList.add('thumbnail');\n if(!aspecter) {\n mediaElement.style.width = containerRect.width + 'px';\n mediaElement.style.height = containerRect.height + 'px';\n }\n\n if(src) {\n await renderImageFromUrlPromise(mediaElement, src);\n }\n }/* else if(mediaElement instanceof HTMLVideoElement && mediaElement.firstElementChild && ((mediaElement.firstElementChild as HTMLSourceElement).src || src)) {\n await new Promise((resolve, reject) => {\n mediaElement.addEventListener('loadeddata', resolve);\n\n if(src) {\n (mediaElement.firstElementChild as HTMLSourceElement).src = src;\n }\n });\n } */\n \n mover.style.display = '';\n\n fastRaf(() => {\n mover.classList.add(wasActive ? 'moving' : 'active');\n });\n } else {\n /* if(mover.classList.contains('center')) {\n mover.classList.remove('center');\n void mover.offsetLeft; // reflow\n } */\n \n if(target instanceof SVGSVGElement) {\n path = mover.querySelector('path');\n\n if(path) {\n this.sizeTailPath(path, containerRect, scaleX, delay, false, isOut, borderRadius);\n }\n }\n\n if(target.classList.contains('media-viewer-media')) {\n mover.classList.add('hiding');\n }\n\n this.toggleWholeActive(false);\n\n //return ret;\n\n setTimeout(() => {\n mover.style.borderRadius = borderRadius;\n\n if(mover.firstElementChild) {\n (mover.firstElementChild as HTMLElement).style.borderRadius = borderRadius;\n }\n }, delay / 2);\n\n setTimeout(() => {\n mover.innerHTML = '';\n mover.classList.remove('moving', 'active', 'hiding');\n mover.style.cssText = 'display: none;';\n\n deferred.resolve();\n }, delay);\n\n mover.classList.remove('opening');\n\n return ret;\n }\n\n mover.classList.add('opening');\n\n //await new Promise((resolve) => setTimeout(resolve, 0));\n //await new Promise((resolve) => window.requestAnimationFrame(resolve));\n // * одного RAF'а недостаточно, иногда анимация с одним не срабатывает (преимущественно на мобильных)\n await doubleRaf();\n\n // чтобы проверить установленную позицию - раскомментировать\n // throw '';\n\n //await new Promise((resolve) => setTimeout(resolve, 5e3));\n\n mover.style.transform = `translate3d(${containerRect.left}px,${containerRect.top}px,0) scale3d(1,1,1)`;\n //mover.style.transform = `translate(-50%,-50%) scale(1,1)`;\n needOpacity && (mover.style.opacity = ''/* closing ? '0' : '' */);\n\n if(aspecter) {\n this.setFullAspect(aspecter, containerRect, rect);\n }\n\n //throw '';\n\n setTimeout(() => {\n mover.style.borderRadius = '';\n\n if(mover.firstElementChild) {\n (mover.firstElementChild as HTMLElement).style.borderRadius = '';\n }\n }, 0/* delay / 2 */);\n\n mover.dataset.timeout = '' + setTimeout(() => {\n mover.classList.remove('moving', 'opening');\n\n if(aspecter) { // всё из-за видео, элементы управления скейлятся, так бы можно было этого не делать\n if(mover.querySelector('video') || true) {\n mover.classList.remove('active');\n aspecter.style.cssText = '';\n void mover.offsetLeft; // reflow\n }\n \n //aspecter.classList.remove('disable-hover');\n }\n\n // эти строки нужны для установки центральной позиции, в случае ресайза это будет нужно\n mover.classList.add('center', 'no-transition');\n /* mover.style.left = mover.style.top = '50%';\n mover.style.transform = 'translate(-50%, -50%)';\n void mover.offsetLeft; // reflow */\n\n // это уже нужно для будущих анимаций\n mover.classList.add('active');\n delete mover.dataset.timeout;\n\n deferred.resolve();\n }, delay);\n\n if(path) {\n this.sizeTailPath(path, containerRect, scaleX, delay, true, isOut, borderRadius);\n }\n\n return ret;\n }\n\n protected toggleWholeActive(active: boolean) {\n if(active) {\n this.wholeDiv.classList.add('active');\n } else {\n this.wholeDiv.classList.add('backwards');\n setTimeout(() => {\n this.wholeDiv.classList.remove('active');\n }, 0);\n }\n }\n\n protected setFullAspect(aspecter: HTMLDivElement, containerRect: DOMRect, rect: DOMRect) {\n /* let media = aspecter.firstElementChild;\n let proportion: number;\n if(media instanceof HTMLImageElement) {\n proportion = media.naturalWidth / media.naturalHeight;\n } else if(media instanceof HTMLVideoElement) {\n proportion = media.videoWidth / media.videoHeight;\n } */\n const proportion = containerRect.width / containerRect.height;\n\n let {width, height} = rect;\n /* if(proportion === 1) {\n aspecter.style.cssText = '';\n } else { */\n if(proportion > 0) {\n width = height * proportion;\n } else {\n height = width * proportion;\n }\n\n //this.log('will set style aspecter:', `width: ${width}px; height: ${height}px; transform: scale(${containerRect.width / width}, ${containerRect.height / height});`);\n\n aspecter.style.cssText = `width: ${width}px; height: ${height}px; transform: scale3d(${containerRect.width / width}, ${containerRect.height / height}, 1);`;\n //}\n }\n\n protected sizeTailPath(path: SVGPathElement, rect: DOMRect, scaleX: number, delay: number, upscale: boolean, isOut: boolean, borderRadius: string) {\n const start = Date.now();\n const {width, height} = rect;\n delay = delay / 2;\n\n const br = borderRadius.split(' ').map(v => parseInt(v));\n\n const step = () => {\n const diff = Date.now() - start;\n\n let progress = delay ? diff / delay : 1;\n if(progress > 1) progress = 1;\n if(upscale) progress = 1 - progress;\n\n const _br: [number, number, number, number] = br.map(v => v * progress) as any;\n\n let d: string;\n if(isOut) d = generatePathData(0, 0, width - (9 / scaleX * progress), height, ..._br);\n else d = generatePathData(9 / scaleX * progress, 0, width/* width - (9 / scaleX * progress) */, height, ..._br);\n path.setAttributeNS(null, 'd', d);\n\n if(diff < delay) fastRaf(step);\n };\n \n //window.requestAnimationFrame(step);\n step();\n }\n\n protected removeCenterFromMover(mover: HTMLElement) {\n if(mover.classList.contains('center')) {\n //const rect = mover.getBoundingClientRect();\n const rect = this.content.media.getBoundingClientRect();\n mover.style.transform = `translate3d(${rect.left}px,${rect.top}px,0)`;\n mover.classList.remove('center');\n void mover.offsetLeft; // reflow\n mover.classList.remove('no-transition');\n }\n }\n\n protected moveTheMover(mover: HTMLElement, toLeft = true) {\n const windowW = windowSize.width;\n\n this.removeCenterFromMover(mover);\n\n //mover.classList.remove('active');\n mover.classList.add('moving');\n\n if(mover.dataset.timeout) { // и это тоже всё из-за скейла видео, так бы это не нужно было\n clearTimeout(+mover.dataset.timeout);\n }\n\n const rect = mover.getBoundingClientRect();\n\n const newTransform = mover.style.transform.replace(/translate3d\\((.+?),/, (match, p1) => {\n const x = toLeft ? -rect.width : windowW;\n //const x = toLeft ? -(rect.right + (rect.width / 2)) : windowW / 2;\n\n return match.replace(p1, x + 'px');\n });\n\n ////////this.log('set newTransform:', newTransform, mover.style.transform, toLeft);\n mover.style.transform = newTransform;\n\n setTimeout(() => {\n mover.remove();\n }, 350);\n }\n\n protected setNewMover() {\n const newMover = document.createElement('div');\n newMover.classList.add('media-viewer-mover');\n newMover.style.display = 'none';\n\n if(this.content.mover) {\n const oldMover = this.content.mover;\n oldMover.parentElement.append(newMover);\n } else {\n this.moversContainer.append(newMover);\n }\n\n return this.content.mover = newMover;\n }\n\n protected updateMediaSource(target: HTMLElement, url: string, tagName: 'video' | 'img') {\n //if(target instanceof SVGSVGElement) {\n const el = target.tagName.toLowerCase() === tagName ? target : target.querySelector(tagName) as HTMLElement;\n if(el && !findUpClassName(target, 'document')) {\n if(findUpClassName(target, 'attachment')) {\n // two parentElements because element can be contained in aspecter\n const preloader = target.parentElement.parentElement.querySelector('.preloader-container') as HTMLElement;\n if(preloader) {\n if(tagName === 'video') {\n if(preloader.classList.contains('manual')) {\n preloader.click();\n // return;\n }\n \n return;\n }\n \n preloader.remove();\n }\n }\n\n renderImageFromUrl(el, url);\n\n // ! костыль, но он тут даже и не нужен\n if(el.classList.contains('thumbnail') && el.parentElement.classList.contains('media-container-aspecter')) {\n el.classList.remove('thumbnail');\n }\n }\n /* } else {\n\n } */\n }\n\n protected setAuthorInfo(fromId: PeerId | string, timestamp: number) {\n replaceContent(this.author.date, formatFullSentTime(timestamp));\n\n const isPeerId = fromId.isPeerId();\n let title: HTMLElement;\n if(isPeerId) {\n title = new PeerTitle({\n peerId: fromId as PeerId,\n dialog: false,\n onlyFirstName: false,\n plainText: false\n }).element;\n } else {\n title = document.createElement('span');\n title.append(RichTextProcessor.wrapEmojiText(fromId));\n title.classList.add('peer-title');\n }\n\n replaceContent(this.author.nameEl, title);\n\n let oldAvatar = this.author.avatarEl;\n this.author.avatarEl = (oldAvatar.cloneNode() as AvatarElement);\n (this.author.avatarEl as AvatarElement).updateWithOptions({\n // @ts-ignore\n peerId: fromId || NULL_PEER_ID,\n peerTitle: isPeerId ? undefined : '' + fromId\n });\n\n oldAvatar.parentElement.replaceChild(this.author.avatarEl, oldAvatar);\n }\n \n protected async _openMedia(\n media: MyDocument | MyPhoto, \n timestamp: number, \n fromId: PeerId | string, \n fromRight: number, \n target?: HTMLElement, \n reverse = false, \n prevTargets: TargetType[] = [], \n nextTargets: TargetType[] = [], \n message?: MyMessage\n /* , needLoadMore = true */\n ) {\n if(this.setMoverPromise) return this.setMoverPromise;\n\n /* if(DEBUG) {\n this.log('openMedia:', media, fromId, prevTargets, nextTargets);\n } */\n\n this.setAuthorInfo(fromId, timestamp);\n \n const isDocument = media._ === 'document';\n const isVideo = isDocument && media.mime_type && ((['video', 'gif'] as MyDocument['type'][]).includes(media.type) || media.mime_type.indexOf('video/') === 0);\n\n if(this.isFirstOpen) {\n //this.targetContainer = targetContainer;\n // this.needLoadMore = needLoadMore;\n this.isFirstOpen = false;\n this.listLoader.setTargets(prevTargets, nextTargets, reverse);\n (window as any).appMediaViewer = this;\n //this.loadMore = loadMore;\n\n /* if(appSidebarRight.historyTabIDs.slice(-1)[0] === AppSidebarRight.SLIDERITEMSIDS.forward) {\n appSidebarRight.forwardTab.closeBtn.click();\n await new Promise((resolve) => setTimeout(resolve, 200));\n } */\n }\n\n if(this.listLoader.next.length < 10) {\n setTimeout(() => {\n this.listLoader.load(true);\n }, 0);\n }\n\n //if(prevTarget && (!prevTarget.parentElement || !this.isElementVisible(this.targetContainer, prevTarget))) prevTarget = null;\n //if(nextTarget && (!nextTarget.parentElement || !this.isElementVisible(this.targetContainer, nextTarget))) nextTarget = null;\n\n this.buttons.prev.classList.toggle('hide', !this.listLoader.previous.length);\n this.buttons.next.classList.toggle('hide', !this.listLoader.next.length);\n \n const container = this.content.media;\n const useContainerAsTarget = !target || target === container;\n if(useContainerAsTarget) target = container;\n\n this.target = {element: target} as any;\n const tempId = ++this.tempId;\n\n if(container.firstElementChild) {\n container.innerHTML = '';\n }\n \n // ok set\n\n const wasActive = fromRight !== 0;\n if(wasActive) {\n this.moveTheMover(this.content.mover, fromRight === 1);\n this.setNewMover();\n } else {\n this.toggleOverlay(true);\n this.setGlobalListeners();\n\n if(!this.wholeDiv.parentElement) {\n this.pageEl.insertBefore(this.wholeDiv, document.getElementById('main-columns'));\n void this.wholeDiv.offsetLeft; // reflow\n }\n\n this.toggleWholeActive(true);\n\n if(!IS_MOBILE_SAFARI) {\n this.navigationItem = {\n type: 'media',\n onPop: (canAnimate) => {\n if(this.setMoverAnimationPromise) {\n return false;\n }\n \n this.close();\n }\n };\n\n appNavigationController.pushItem(this.navigationItem);\n }\n }\n\n ////////this.log('wasActive:', wasActive);\n\n const mover = this.content.mover;\n\n const maxWidth = windowSize.width;\n //const maxWidth = this.pageEl.scrollWidth;\n // TODO: const maxHeight = mediaSizes.isMobile ? appPhotosManager.windowH : appPhotosManager.windowH - 100;\n let padding = 0;\n const windowH = windowSize.height;\n if(windowH < 1000000 && !mediaSizes.isMobile) {\n padding = 120;\n }\n const maxHeight = windowH - 120 - padding;\n let thumbPromise: Promise<any> = Promise.resolve();\n const size = appPhotosManager.setAttachmentSize(media, container, maxWidth, maxHeight, mediaSizes.isMobile ? false : true, undefined, !!(isDocument && media.w && media.h)).photoSize;\n if(useContainerAsTarget) {\n const cacheContext = appDownloadManager.getCacheContext(media, size.type);\n let img: HTMLImageElement | HTMLCanvasElement;\n if(cacheContext.downloaded) {\n img = new Image();\n img.src = cacheContext.url;\n } else {\n const gotThumb = appPhotosManager.getStrippedThumbIfNeeded(media, cacheContext, true);\n if(gotThumb) {\n thumbPromise = gotThumb.loadPromise;\n img = gotThumb.image;\n }\n }\n\n if(img) {\n img.classList.add('thumbnail');\n container.append(img);\n }\n }\n\n // need after setAttachmentSize\n /* if(useContainerAsTarget) {\n target = target.querySelector('img, video') || target;\n } */\n\n const supportsStreaming: boolean = !!(isDocument && media.supportsStreaming);\n const preloader = supportsStreaming ? this.preloaderStreamable : this.preloader;\n\n let setMoverPromise: Promise<void>;\n if(isVideo) {\n ////////this.log('will wrap video', media, size);\n\n // потому что для safari нужно создать элемент из event'а\n // const video = document.createElement('video');\n const useController = message && media.type !== 'gif';\n const video = /* useController ? \n appMediaPlaybackController.addMedia(message, false, true) as HTMLVideoElement : \n */createVideo({pip: useController});\n\n const set = () => this.setMoverToTarget(target, false, fromRight).then(({onAnimationEnd}) => {\n //return; // set and don't move\n //if(wasActive) return;\n //return;\n \n const div = mover.firstElementChild && mover.firstElementChild.classList.contains('media-viewer-aspecter') ? mover.firstElementChild : mover;\n //const video = mover.querySelector('video') || document.createElement('video');\n \n const moverVideo = mover.querySelector('video');\n if(moverVideo) {\n moverVideo.remove();\n }\n \n //video.src = '';\n \n video.setAttribute('playsinline', 'true');\n \n // * fix for playing video if viewer is closed (https://contest.com/javascript-web-bonus/entry1425#issue11629)\n video.addEventListener('timeupdate', () => {\n if(this.tempId !== tempId) {\n video.pause();\n }\n });\n\n video.addEventListener('error', () => {\n if(video.error.code !== 4) {\n this.log.error(\"Error \" + video.error.code + \"; details: \" + video.error.message);\n }\n\n if(preloader) {\n preloader.detach();\n }\n }, {once: true});\n\n this.addEventListener('setMoverAfter', () => {\n video.src = '';\n video.load();\n }, {once: true});\n \n if(IS_SAFARI) {\n // test stream\n // video.controls = true;\n video.autoplay = true;\n }\n \n if(media.type === 'gif') {\n video.muted = true;\n video.autoplay = true;\n video.loop = true;\n } else if(media.duration < 60) {\n video.loop = true;\n }\n \n // if(!video.parentElement) {\n div.append(video);\n // }\n \n const canPlayThrough = new Promise((resolve) => {\n video.addEventListener('canplay', resolve, {once: true});\n });\n \n const createPlayer = () => {\n if(media.type !== 'gif') {\n video.dataset.ckin = 'default';\n video.dataset.overlay = '1';\n\n Promise.all([canPlayThrough, onAnimationEnd]).then(() => {\n if(this.tempId !== tempId) {\n return;\n }\n \n // const play = useController ? appMediaPlaybackController.willBePlayedMedia === video : true;\n const play = true;\n const player = this.videoPlayer = new VideoPlayer({\n video, \n play, \n streamable: supportsStreaming,\n onPlaybackRackMenuToggle: (open) => {\n this.wholeDiv.classList.toggle('hide-caption', !!open);\n },\n onPip: (pip) => {\n const otherMediaViewer = (window as any).appMediaViewer;\n if(!pip && otherMediaViewer && otherMediaViewer !== this) {\n this.releaseSingleMedia = undefined;\n this.close();\n return;\n }\n\n const mover = this.moversContainer.lastElementChild as HTMLElement;\n mover.classList.toggle('hiding', pip);\n this.toggleWholeActive(!pip);\n this.toggleOverlay(!pip);\n this.toggleGlobalListeners(!pip);\n\n if(this.navigationItem) {\n if(pip) appNavigationController.removeItem(this.navigationItem);\n else appNavigationController.pushItem(this.navigationItem);\n }\n\n if(useController) {\n if(pip) {\n // appMediaPlaybackController.toggleSwitchers(true);\n\n this.releaseSingleMedia(false);\n this.releaseSingleMedia = undefined;\n\n appMediaPlaybackController.setPictureInPicture(video);\n } else {\n this.releaseSingleMedia = appMediaPlaybackController.setSingleMedia(video, message as Message.message);\n }\n }\n },\n onPipClose: () => {\n // this.target = undefined;\n // this.toggleWholeActive(false);\n // this.toggleOverlay(false);\n this.close();\n }\n });\n player.addEventListener('toggleControls', (show) => {\n this.wholeDiv.classList.toggle('has-video-controls', show);\n });\n\n this.addEventListener('setMoverBefore', () => {\n this.wholeDiv.classList.remove('has-video-controls');\n this.videoPlayer.cleanup();\n this.videoPlayer = undefined;\n }, {once: true});\n\n if(this.isZooming()) {\n this.videoPlayer.lockControls(false);\n }\n /* div.append(video);\n mover.append(player.wrapper); */\n });\n }\n };\n \n if(supportsStreaming) {\n onAnimationEnd.then(() => {\n if(video.readyState < video.HAVE_FUTURE_DATA) {\n preloader.attach(mover, true);\n }\n \n /* canPlayThrough.then(() => {\n preloader.detach();\n }); */\n });\n \n const attachCanPlay = () => {\n video.addEventListener('canplay', () => {\n //this.log('video waited and progress loaded');\n preloader.detach();\n video.parentElement.classList.remove('is-buffering');\n }, {once: true});\n };\n \n video.addEventListener('waiting', () => {\n const loading = video.networkState === video.NETWORK_LOADING;\n const isntEnoughData = video.readyState < video.HAVE_FUTURE_DATA;\n \n //this.log('video waiting for progress', loading, isntEnoughData);\n if(loading && isntEnoughData) {\n attachCanPlay();\n \n preloader.attach(mover, true);\n \n // поставлю класс для плеера, чтобы убрать большую иконку пока прелоадер на месте\n video.parentElement.classList.add('is-buffering');\n }\n });\n\n if(this.wholeDiv.classList.contains('no-forwards')) {\n video.addEventListener('contextmenu', (e) => {\n cancelEvent(e);\n });\n }\n \n attachCanPlay();\n }\n \n //if(!video.src || media.url !== video.src) {\n const load = () => {\n /* if(useController) {\n appMediaPlaybackController.resolveWaitingForLoadMedia(message.peerId, message.mid, message.pFlags.is_scheduled);\n } */\n\n const cacheContext = appDownloadManager.getCacheContext(media);\n const promise: Promise<any> = supportsStreaming ? Promise.resolve() : appDocsManager.downloadDoc(media);\n \n if(!supportsStreaming) {\n onAnimationEnd.then(() => {\n if(!cacheContext.url) {\n preloader.attach(mover, true, promise);\n }\n });\n }\n \n Promise.all([promise, onAnimationEnd]).then(() => {\n if(this.tempId !== tempId) {\n this.log.warn('media viewer changed video');\n return;\n }\n\n const url = cacheContext.url;\n if(target instanceof SVGSVGElement/* && (video.parentElement || !isSafari) */) { // if video exists\n //if(!video.parentElement) {\n div.firstElementChild.lastElementChild.append(video);\n //}\n } else {\n renderImageFromUrl(video, url);\n }\n\n // * have to set options (especially playbackRate) after src\n // * https://github.com/videojs/video.js/issues/2516\n if(useController) {\n this.releaseSingleMedia = appMediaPlaybackController.setSingleMedia(video, message as Message.message);\n\n this.addEventListener('setMoverBefore', () => {\n if(this.releaseSingleMedia) {\n this.releaseSingleMedia();\n this.releaseSingleMedia = undefined;\n }\n }, {once: true});\n }\n\n this.updateMediaSource(target, url, 'video');\n\n createPlayer();\n });\n \n return promise;\n };\n \n this.lazyLoadQueue.unshift({load});\n //} else createPlayer();\n });\n\n setMoverPromise = thumbPromise.then(set);\n } else {\n const set = () => this.setMoverToTarget(target, false, fromRight).then(({onAnimationEnd}) => {\n //return; // set and don't move\n //if(wasActive) return;\n //return;\n \n const load = () => {\n const cacheContext = appDownloadManager.getCacheContext(media, size.type);\n const cancellablePromise = isDocument ? appDocsManager.downloadDoc(media) : appPhotosManager.preloadPhoto(media, size);\n \n onAnimationEnd.then(() => {\n if(!cacheContext.url) {\n this.preloader.attachPromise(cancellablePromise);\n //this.preloader.attach(mover, true, cancellablePromise);\n }\n });\n \n Promise.all([onAnimationEnd, cancellablePromise]).then(() => {\n if(this.tempId !== tempId) {\n this.log.warn('media viewer changed photo');\n return;\n }\n \n ///////this.log('indochina', blob);\n \n const url = cacheContext.url;\n if(target instanceof SVGSVGElement) {\n this.updateMediaSource(target, url, 'img');\n this.updateMediaSource(mover, url, 'img');\n \n if(mediaSizes.isMobile) {\n const imgs = mover.querySelectorAll('img');\n if(imgs && imgs.length) {\n imgs.forEach(img => {\n img.classList.remove('thumbnail'); // может здесь это вообще не нужно\n });\n }\n }\n } else {\n const div = mover.firstElementChild && mover.firstElementChild.classList.contains('media-viewer-aspecter') ? mover.firstElementChild : mover;\n const haveImage = div.firstElementChild?.tagName === 'IMG' ? div.firstElementChild as HTMLImageElement : null;\n if(!haveImage || haveImage.src !== url) {\n let image = new Image();\n image.classList.add('thumbnail');\n \n //this.log('will renderImageFromUrl:', image, div, target);\n \n renderImageFromUrl(image, url, () => {\n this.updateMediaSource(target, url, 'img');\n \n if(haveImage) {\n fastRaf(() => {\n haveImage.remove();\n });\n }\n \n div.append(image);\n });\n }\n }\n \n //this.preloader.detach();\n }).catch(err => {\n this.log.error(err);\n this.preloader.attach(mover);\n this.preloader.setManual();\n });\n \n return cancellablePromise;\n };\n \n this.lazyLoadQueue.unshift({load});\n });\n\n setMoverPromise = thumbPromise.then(set);\n }\n\n return this.setMoverPromise = setMoverPromise.catch(() => {\n this.setMoverAnimationPromise = null;\n }).finally(() => {\n this.setMoverPromise = null;\n });\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nexport default function fillPropertyValue(str: string) {\r\n let splitted = str.split(' ');\r\n if(splitted.length !== 4) {\r\n if(!splitted[0]) splitted[0] = '0px';\r\n for(let i = splitted.length; i < 4; ++i) {\r\n splitted[i] = splitted[i % 2] || splitted[0] || '0px';\r\n }\r\n }\r\n\r\n return splitted;\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport MEDIA_MIME_TYPES_SUPPORTED from \"../environment/mediaMimeTypesSupport\";\nimport cancelEvent from \"../helpers/dom/cancelEvent\";\nimport { attachClickEvent, detachClickEvent } from \"../helpers/dom/clickEvent\";\nimport setInnerHTML from \"../helpers/dom/setInnerHTML\";\nimport mediaSizes from \"../helpers/mediaSizes\";\nimport SearchListLoader from \"../helpers/searchListLoader\";\nimport { Message } from \"../layer\";\nimport appDocsManager, { MyDocument } from \"../lib/appManagers/appDocsManager\";\nimport appImManager from \"../lib/appManagers/appImManager\";\nimport appMessagesManager, { MyMessage } from \"../lib/appManagers/appMessagesManager\";\nimport appPhotosManager, { MyPhoto } from \"../lib/appManagers/appPhotosManager\";\nimport RichTextProcessor from \"../lib/richtextprocessor\";\nimport { MediaSearchContext } from \"./appMediaPlaybackController\";\nimport AppMediaViewerBase, { MEDIA_VIEWER_CLASSNAME } from \"./appMediaViewerBase\";\nimport { ButtonMenuItemOptions } from \"./buttonMenu\";\nimport PopupDeleteMessages from \"./popups/deleteMessages\";\nimport PopupForward from \"./popups/forward\";\nimport Scrollable from \"./scrollable\";\nimport appSidebarRight from \"./sidebarRight\";\nimport AppSharedMediaTab from \"./sidebarRight/tabs/sharedMedia\";\n\ntype AppMediaViewerTargetType = {\n element: HTMLElement,\n mid: number,\n peerId: PeerId\n};\nexport default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delete' | 'forward', AppMediaViewerTargetType> {\n protected listLoader: SearchListLoader<AppMediaViewerTargetType>;\n protected btnMenuForward: ButtonMenuItemOptions;\n protected btnMenuDownload: ButtonMenuItemOptions;\n protected btnMenuDelete: ButtonMenuItemOptions;\n\n get searchContext() {\n return this.listLoader.searchContext;\n }\n\n constructor() {\n super(new SearchListLoader({\n processItem: (item) => {\n const isForDocument = this.searchContext.inputFilter._ === 'inputMessagesFilterDocument';\n const {mid, peerId} = item;\n const media: MyPhoto | MyDocument = appMessagesManager.getMediaFromMessage(item);\n\n if(!media) return;\n \n if(isForDocument && !AppMediaViewer.isMediaCompatibleForDocumentViewer(media)) {\n return;\n }\n\n return {element: null as HTMLElement, mid, peerId};\n }\n }), ['delete', 'forward']);\n\n this.listLoader.onEmptied = () => {\n this.close();\n };\n\n /* const stub = document.createElement('div');\n stub.classList.add(MEDIA_VIEWER_CLASSNAME + '-stub');\n this.content.main.prepend(stub); */\n\n this.content.caption = document.createElement('div');\n this.content.caption.classList.add(MEDIA_VIEWER_CLASSNAME + '-caption'/* , 'media-viewer-stub' */);\n\n let captionTimeout: number;\n const setCaptionTimeout = () => {\n if(captionTimeout) {\n clearTimeout(captionTimeout);\n }\n\n captionTimeout = window.setTimeout(() => {\n captionTimeout = undefined;\n this.content.caption.classList.remove('is-focused');\n }, 800);\n };\n this.content.caption.addEventListener('touchstart', () => {\n if(!mediaSizes.isMobile) return;\n\n this.content.caption.classList.add('is-focused');\n \n if(captionTimeout) {\n clearTimeout(captionTimeout);\n captionTimeout = undefined;\n }\n \n document.addEventListener('touchend', setCaptionTimeout, {once: true});\n });\n\n const captionScrollable = new Scrollable(this.content.caption);\n captionScrollable.onAdditionalScroll = setCaptionTimeout;\n\n //this.content.main.append(this.content.caption);\n this.wholeDiv.append(this.content.caption);\n\n attachClickEvent(this.buttons.delete, this.onDeleteClick);\n\n const buttons: ButtonMenuItemOptions[] = [this.btnMenuForward = {\n icon: 'forward',\n text: 'Forward',\n onClick: this.onForwardClick\n }, this.btnMenuDownload = {\n icon: 'download',\n text: 'MediaViewer.Context.Download',\n onClick: this.onDownloadClick\n }, this.btnMenuDelete = {\n icon: 'delete danger',\n text: 'Delete',\n onClick: this.onDeleteClick\n }];\n\n this.setBtnMenuToggle(buttons);\n\n // * constructing html end\n \n this.setListeners();\n }\n\n protected setListeners() {\n super.setListeners();\n attachClickEvent(this.buttons.forward, this.onForwardClick);\n attachClickEvent(this.author.container, this.onAuthorClick);\n\n const onCaptionClick = (e: MouseEvent) => {\n if(e.target instanceof HTMLAnchorElement) { // close viewer if it's t.me/ redirect\n const onclick = (e.target as HTMLElement).getAttribute('onclick');\n if(!onclick || onclick.includes('showMaskedAlert')) {\n return;\n }\n\n cancelEvent(e);\n\n this.close().then(() => {\n detachClickEvent(this.content.caption, onCaptionClick, {capture: true});\n (e.target as HTMLAnchorElement).click();\n });\n\n return false;\n }\n };\n\n attachClickEvent(this.content.caption, onCaptionClick, {capture: true});\n }\n\n /* public close(e?: MouseEvent) {\n const good = !this.setMoverAnimationPromise;\n const promise = super.close(e);\n\n if(good) { // clear\n this.currentMessageId = 0;\n this.peerId = 0;\n }\n\n return promise;\n } */\n\n protected getMessageByPeer(peerId: PeerId, mid: number) {\n return this.searchContext.isScheduled ? appMessagesManager.getScheduledMessageByPeer(peerId, mid) : appMessagesManager.getMessageByPeer(peerId, mid);\n }\n\n onPrevClick = (target: AppMediaViewerTargetType) => {\n this.openMedia(this.getMessageByPeer(target.peerId, target.mid), target.element, -1);\n };\n\n onNextClick = (target: AppMediaViewerTargetType) => {\n this.openMedia(this.getMessageByPeer(target.peerId, target.mid), target.element, 1);\n };\n\n onDeleteClick = () => {\n const target = this.target;\n new PopupDeleteMessages(target.peerId, [target.mid], 'chat', () => {\n this.target = {element: this.content.media} as any;\n this.close();\n });\n };\n\n onForwardClick = () => {\n const target = this.target;\n if(target.mid) {\n //appSidebarRight.forwardTab.open([target.mid]);\n new PopupForward({\n [target.peerId]: [target.mid]\n }, () => {\n return this.close();\n });\n }\n };\n\n onAuthorClick = (e: MouseEvent) => {\n const {mid, peerId} = this.target;\n if(mid && mid !== Number.MAX_SAFE_INTEGER) {\n const threadId = this.searchContext.threadId;\n const message = this.getMessageByPeer(peerId, mid);\n this.close(e)\n //.then(() => mediaSizes.isMobile ? appSidebarRight.sharedMediaTab.closeBtn.click() : Promise.resolve())\n .then(() => {\n if(mediaSizes.isMobile) {\n const tab = appSidebarRight.getTab(AppSharedMediaTab);\n if(tab) {\n tab.close();\n }\n }\n\n appImManager.setInnerPeer({\n peerId: message.peerId, \n lastMsgId: mid, \n type: threadId ? 'discussion' : undefined, \n threadId\n });\n });\n }\n };\n\n onDownloadClick = () => {\n const {peerId, mid} = this.target;\n const message = this.getMessageByPeer(peerId, mid);\n if(message.media.photo) {\n appPhotosManager.savePhotoFile(message.media.photo, appImManager.chat.bubbles.lazyLoadQueue.queueId);\n } else {\n let document: MyDocument = null;\n\n if(message.media.webpage) document = message.media.webpage.document;\n else document = message.media.document;\n\n if(document) {\n //console.log('will save document:', document);\n appDocsManager.saveDocFile(document, appImManager.chat.bubbles.lazyLoadQueue.queueId);\n }\n }\n };\n\n private setCaption(message: MyMessage) {\n const caption = (message as Message.message).message;\n let html: Parameters<typeof setInnerHTML>[1] = '';\n if(caption) {\n html = RichTextProcessor.wrapRichText(caption, {\n entities: (message as Message.message).totalEntities\n });\n }\n \n // html = 'Dandelion are a family of flowering plants that grow in many parts of the world.';\n setInnerHTML(this.content.caption.firstElementChild, html);\n this.content.caption.classList.toggle('hide', !caption);\n // this.content.container.classList.toggle('with-caption', !!caption);\n }\n\n public setSearchContext(context: MediaSearchContext) {\n this.listLoader.setSearchContext(context);\n\n return this;\n }\n\n public async openMedia(message: MyMessage, target?: HTMLElement, fromRight = 0, reverse = false, \n prevTargets: AppMediaViewerTargetType[] = [], nextTargets: AppMediaViewerTargetType[] = []/* , needLoadMore = true */) {\n if(this.setMoverPromise) return this.setMoverPromise;\n\n const mid = message.mid;\n const fromId = (message as Message.message).fwd_from && !message.fromId ? (message as Message.message).fwd_from.from_name : message.fromId;\n const media = appMessagesManager.getMediaFromMessage(message);\n\n const cantForwardMessage = message._ === 'messageService' || !appMessagesManager.canForward(message);\n [this.buttons.forward, this.btnMenuForward.element].forEach(button => {\n button.classList.toggle('hide', cantForwardMessage);\n });\n\n this.wholeDiv.classList.toggle('no-forwards', cantForwardMessage);\n \n const cantDownloadMessage = cantForwardMessage;\n [this.buttons.download, this.btnMenuDownload.element].forEach(button => {\n button.classList.toggle('hide', cantDownloadMessage);\n });\n\n const canDeleteMessage = appMessagesManager.canDeleteMessage(message);\n [this.buttons.delete, this.btnMenuDelete.element].forEach(button => {\n button.classList.toggle('hide', !canDeleteMessage);\n });\n\n this.setCaption(message);\n const promise = super._openMedia(media, message.date, fromId, fromRight, target, reverse, prevTargets, nextTargets, message/* , needLoadMore */);\n this.target.mid = mid;\n this.target.peerId = message.peerId;\n\n return promise;\n }\n\n public static isMediaCompatibleForDocumentViewer(media: MyPhoto | MyDocument) {\n return media._ === 'photo' || MEDIA_MIME_TYPES_SUPPORTED.has(media.mime_type);\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { Photo } from \"../layer\";\nimport appPhotosManager from \"../lib/appManagers/appPhotosManager\";\nimport ListLoader, { ListLoaderOptions } from \"./listLoader\";\n\nexport default class AvatarListLoader<Item extends {photoId: Photo.photo['id']}> extends ListLoader<Item, any> {\n private peerId: PeerId;\n\n constructor(options: Omit<ListLoaderOptions<Item, any>, 'loadMore'> & {peerId: PeerId}) {\n super({\n ...options,\n loadMore: (anchor, older, loadCount) => {\n if(this.peerId.isAnyChat() || !older) return Promise.resolve({count: 0, items: []}); // ! это значит, что открыло аватар чата, но следующих фотографий нет.\n\n const maxId = anchor?.photoId;\n return appPhotosManager.getUserPhotos(this.peerId, maxId, loadCount).then(value => {\n const items = value.photos.map(photoId => {\n return {element: null as HTMLElement, photoId} as any;\n });\n\n return {count: value.count, items};\n });\n }\n });\n\n this.loadedAllUp = true;\n this.peerId = options.peerId;\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport AvatarListLoader from \"../helpers/avatarListLoader\";\nimport { Photo } from \"../layer\";\nimport appImManager from \"../lib/appManagers/appImManager\";\nimport appPhotosManager from \"../lib/appManagers/appPhotosManager\";\nimport AppMediaViewerBase from \"./appMediaViewerBase\";\n\ntype AppMediaViewerAvatarTargetType = {element: HTMLElement, photoId: Photo.photo['id']};\nexport default class AppMediaViewerAvatar extends AppMediaViewerBase<'', 'delete', AppMediaViewerAvatarTargetType> {\n public peerId: PeerId;\n\n constructor(peerId: PeerId) {\n super(new AvatarListLoader({peerId}), [/* 'delete' */]);\n\n this.peerId = peerId;\n\n this.setBtnMenuToggle([{\n icon: 'download',\n text: 'MediaViewer.Context.Download',\n onClick: this.onDownloadClick\n }/* , {\n icon: 'delete danger btn-disabled',\n text: 'Delete',\n onClick: () => {}\n } */]);\n\n // * constructing html end\n \n this.setListeners();\n }\n\n onPrevClick = (target: AppMediaViewerAvatarTargetType) => {\n this.openMedia(target.photoId, target.element, -1);\n };\n\n onNextClick = (target: AppMediaViewerAvatarTargetType) => {\n this.openMedia(target.photoId, target.element, 1);\n };\n\n onDownloadClick = () => {\n appPhotosManager.savePhotoFile(appPhotosManager.getPhoto(this.target.photoId), appImManager.chat.bubbles.lazyLoadQueue.queueId);\n };\n\n public async openMedia(photoId: Photo.photo['id'], target?: HTMLElement, fromRight = 0, prevTargets?: AppMediaViewerAvatarTargetType[], nextTargets?: AppMediaViewerAvatarTargetType[]) {\n if(this.setMoverPromise) return this.setMoverPromise;\n\n const photo = appPhotosManager.getPhoto(photoId);\n const ret = super._openMedia(photo, photo.date, this.peerId, fromRight, target, false, prevTargets, nextTargets);\n this.target.photoId = photo.id;\n\n return ret;\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport appMessagesManager from \"../lib/appManagers/appMessagesManager\";\r\nimport appProfileManager from \"../lib/appManagers/appProfileManager\";\r\nimport rootScope from \"../lib/rootScope\";\r\nimport { Message, Photo } from \"../layer\";\r\nimport appPeersManager from \"../lib/appManagers/appPeersManager\";\r\nimport appPhotosManager from \"../lib/appManagers/appPhotosManager\";\r\nimport type { LazyLoadQueueIntersector } from \"./lazyLoadQueue\";\r\nimport { attachClickEvent } from \"../helpers/dom/clickEvent\";\r\nimport cancelEvent from \"../helpers/dom/cancelEvent\";\r\nimport appAvatarsManager from \"../lib/appManagers/appAvatarsManager\";\r\nimport AppMediaViewer from \"./appMediaViewer\";\r\nimport AppMediaViewerAvatar from \"./appMediaViewerAvatar\";\r\nimport isObject from \"../helpers/object/isObject\";\r\nimport { ArgumentTypes } from \"../types\";\r\n\r\nconst onAvatarUpdate = (peerId: PeerId) => {\r\n appAvatarsManager.removeFromAvatarsCache(peerId);\r\n (Array.from(document.querySelectorAll('avatar-element[data-peer-id=\"' + peerId + '\"]')) as AvatarElement[]).forEach(elem => {\r\n //console.log('updating avatar:', elem);\r\n elem.update();\r\n });\r\n};\r\n\r\nrootScope.addEventListener('avatar_update', onAvatarUpdate);\r\nrootScope.addEventListener('peer_title_edit', (peerId) => {\r\n if(!appAvatarsManager.isAvatarCached(peerId)) {\r\n onAvatarUpdate(peerId);\r\n }\r\n});\r\n\r\nexport async function openAvatarViewer(\r\n target: HTMLElement, \r\n peerId: PeerId, \r\n middleware: () => boolean, \r\n message?: any, \r\n prevTargets?: {element: HTMLElement, item: Photo.photo['id'] | Message.messageService}[], \r\n nextTargets?: typeof prevTargets\r\n) {\r\n let photo = await appProfileManager.getFullPhoto(peerId);\r\n if(!middleware() || !photo) {\r\n return;\r\n }\r\n\r\n const getTarget = () => {\r\n const good = Array.from(target.querySelectorAll('img')).find(img => !img.classList.contains('emoji'));\r\n return good ? target : null;\r\n };\r\n\r\n if(peerId.isAnyChat()) {\r\n const hadMessage = !!message;\r\n const inputFilter = 'inputMessagesFilterChatPhotos';\r\n if(!message) {\r\n message = await appMessagesManager.getSearch({\r\n peerId, \r\n inputFilter: {_: inputFilter}, \r\n maxId: 0, \r\n limit: 1 \r\n }).then(value => {\r\n //console.log(lol);\r\n // ! by descend\r\n return value.history[0];\r\n });\r\n\r\n if(!middleware()) {\r\n return;\r\n }\r\n }\r\n\r\n if(message) {\r\n // ! гений в деле, костылируем (но это гениально)\r\n const messagePhoto = message.action.photo;\r\n if(messagePhoto.id !== photo.id) {\r\n if(!hadMessage) {\r\n message = appMessagesManager.generateFakeAvatarMessage(peerId, photo);\r\n } else {\r\n \r\n }\r\n }\r\n\r\n const f = (arr: typeof prevTargets) => arr.map(el => ({\r\n element: el.element,\r\n mid: (el.item as Message.messageService).mid,\r\n peerId: (el.item as Message.messageService).peerId\r\n }));\r\n\r\n new AppMediaViewer()\r\n .setSearchContext({\r\n peerId,\r\n inputFilter: {_: inputFilter},\r\n })\r\n .openMedia(message, getTarget(), undefined, undefined, prevTargets ? f(prevTargets) : undefined, nextTargets ? f(nextTargets) : undefined);\r\n\r\n return;\r\n }\r\n }\r\n\r\n if(photo) {\r\n if(!isObject(message) && message) {\r\n photo = appPhotosManager.getPhoto(message);\r\n }\r\n \r\n const f = (arr: typeof prevTargets) => arr.map(el => ({\r\n element: el.element,\r\n photoId: el.item as string\r\n }));\r\n\r\n new AppMediaViewerAvatar(peerId).openMedia(photo.id, getTarget(), undefined, prevTargets ? f(prevTargets) : undefined, nextTargets ? f(nextTargets) : undefined);\r\n }\r\n}\r\n\r\nconst believeMe: Map<PeerId, Set<AvatarElement>> = new Map();\r\nconst seen: Set<PeerId> = new Set();\r\n\r\nexport default class AvatarElement extends HTMLElement {\r\n public peerId: PeerId;\r\n public isDialog: boolean;\r\n public peerTitle: string;\r\n public loadPromises: Promise<any>[];\r\n public lazyLoadQueue: LazyLoadQueueIntersector;\r\n public isBig: boolean;\r\n private addedToQueue = false;\r\n\r\n disconnectedCallback() {\r\n // браузер вызывает этот метод при удалении элемента из документа\r\n // (может вызываться много раз, если элемент многократно добавляется/удаляется)\r\n const set = believeMe.get(this.peerId);\r\n if(set && set.has(this)) {\r\n set.delete(this);\r\n if(!set.size) {\r\n believeMe.delete(this.peerId);\r\n }\r\n }\r\n\r\n if(this.lazyLoadQueue) {\r\n this.lazyLoadQueue.unobserve(this);\r\n }\r\n }\r\n\r\n public attachClickEvent() {\r\n let loading = false;\r\n attachClickEvent(this, async(e) => {\r\n cancelEvent(e);\r\n if(loading) return;\r\n //console.log('avatar clicked');\r\n const peerId = this.peerId;\r\n loading = true;\r\n await openAvatarViewer(this, this.peerId, () => this.peerId === peerId);\r\n loading = false;\r\n });\r\n }\r\n\r\n public updateOptions(options: Partial<ArgumentTypes<AvatarElement['updateWithOptions']>[0]>) {\r\n for(let i in options) {\r\n // @ts-ignore\r\n this[i] = options[i];\r\n }\r\n }\r\n\r\n public updateWithOptions(options: {\r\n peerId: PeerId,\r\n isDialog?: boolean,\r\n isBig?: boolean,\r\n peerTitle?: string,\r\n lazyLoadQueue?: LazyLoadQueueIntersector,\r\n loadPromises?: Promise<any>[]\r\n }) {\r\n const wasPeerId = this.peerId;\r\n this.updateOptions(options);\r\n const newPeerId = this.peerId;\r\n\r\n if(wasPeerId === newPeerId) {\r\n return;\r\n }\r\n\r\n this.peerId = appPeersManager.getPeerMigratedTo(newPeerId) || newPeerId;\r\n this.dataset.peerId = '' + newPeerId;\r\n\r\n if(wasPeerId) {\r\n const set = believeMe.get(wasPeerId);\r\n if(set) {\r\n set.delete(this);\r\n if(!set.size) {\r\n believeMe.delete(wasPeerId);\r\n }\r\n }\r\n }\r\n\r\n return this.update();\r\n }\r\n\r\n private r(onlyThumb = false) {\r\n const res = appAvatarsManager.putPhoto(this, this.peerId, this.isDialog, this.peerTitle, onlyThumb, this.isBig);\r\n const promise = res ? res.loadPromise : Promise.resolve();\r\n if(this.loadPromises) {\r\n if(res && res.cached) {\r\n this.loadPromises.push(promise);\r\n }\r\n\r\n promise.finally(() => {\r\n this.loadPromises = undefined;\r\n });\r\n }\r\n\r\n return res;\r\n }\r\n\r\n public update() {\r\n if(this.lazyLoadQueue) {\r\n if(!seen.has(this.peerId)) {\r\n if(this.addedToQueue) return;\r\n this.addedToQueue = true;\r\n \r\n let set = believeMe.get(this.peerId);\r\n if(!set) {\r\n set = new Set();\r\n believeMe.set(this.peerId, set);\r\n }\r\n \r\n set.add(this);\r\n\r\n this.r(true);\r\n\r\n this.lazyLoadQueue.push({\r\n div: this, \r\n load: () => {\r\n seen.add(this.peerId);\r\n return this.update();\r\n }\r\n });\r\n\r\n return;\r\n } else if(this.addedToQueue) {\r\n this.lazyLoadQueue.unobserve(this);\r\n }\r\n } \r\n \r\n seen.add(this.peerId);\r\n \r\n const res = this.r();\r\n const promise = res ? res.loadPromise : Promise.resolve();\r\n\r\n if(this.addedToQueue) {\r\n promise.finally(() => {\r\n this.addedToQueue = false;\r\n });\r\n }\r\n\r\n const set = believeMe.get(this.peerId);\r\n if(set) {\r\n set.delete(this);\r\n const arr = Array.from(set);\r\n believeMe.delete(this.peerId);\r\n \r\n\r\n for(let i = 0, length = arr.length; i < length; ++i) {\r\n arr[i].update();\r\n }\r\n }\r\n\r\n return promise;\r\n }\r\n}\r\n\r\ncustomElements.define('avatar-element', AvatarElement);\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport appDialogsManager from \"../lib/appManagers/appDialogsManager\";\nimport appMessagesManager, {Dialog} from \"../lib/appManagers/appMessagesManager\";\nimport appPeersManager from \"../lib/appManagers/appPeersManager\";\nimport rootScope from \"../lib/rootScope\";\nimport { positionMenu, openBtnMenu } from \"./misc\";\nimport ButtonMenu, { ButtonMenuItemOptions } from \"./buttonMenu\";\nimport PopupDeleteDialog from \"./popups/deleteDialog\";\nimport { i18n } from \"../lib/langPack\";\nimport findUpTag from \"../helpers/dom/findUpTag\";\nimport appNotificationsManager from \"../lib/appManagers/appNotificationsManager\";\nimport PopupPeer from \"./popups/peer\";\nimport AppChatFoldersTab from \"./sidebarLeft/tabs/chatFolders\";\nimport appSidebarLeft from \"./sidebarLeft\";\nimport { toastNew } from \"./toast\";\nimport PopupMute from \"./popups/mute\";\n\nexport default class DialogsContextMenu {\n private element: HTMLElement;\n private buttons: (ButtonMenuItemOptions & {verify: () => boolean})[];\n\n private selectedId: PeerId;\n private filterId: number;\n private dialog: Dialog;\n\n private init() {\n this.buttons = [{\n icon: 'unread',\n text: 'MarkAsUnread',\n onClick: this.onUnreadClick,\n verify: () => !appMessagesManager.isDialogUnread(this.dialog)\n }, {\n icon: 'readchats',\n text: 'MarkAsRead',\n onClick: this.onUnreadClick,\n verify: () => appMessagesManager.isDialogUnread(this.dialog)\n }, {\n icon: 'pin',\n text: 'ChatList.Context.Pin',\n onClick: this.onPinClick,\n verify: () => {\n const isPinned = this.filterId > 1 ? appMessagesManager.filtersStorage.getFilter(this.filterId).pinnedPeerIds.includes(this.dialog.peerId) : !!this.dialog.pFlags?.pinned;\n return !isPinned;\n }\n }, {\n icon: 'unpin',\n text: 'ChatList.Context.Unpin',\n onClick: this.onPinClick,\n verify: () => {\n const isPinned = this.filterId > 1 ? appMessagesManager.filtersStorage.getFilter(this.filterId).pinnedPeerIds.includes(this.dialog.peerId) : !!this.dialog.pFlags?.pinned;\n return isPinned;\n }\n }, {\n icon: 'mute',\n text: 'ChatList.Context.Mute',\n onClick: this.onMuteClick,\n verify: () => {\n return this.selectedId !== rootScope.myId && !appNotificationsManager.isPeerLocalMuted(this.dialog.peerId); \n }\n }, {\n icon: 'unmute',\n text: 'ChatList.Context.Unmute',\n onClick: this.onUnmuteClick,\n verify: () => {\n return this.selectedId !== rootScope.myId && appNotificationsManager.isPeerLocalMuted(this.dialog.peerId); \n }\n }, {\n icon: 'archive',\n text: 'Archive',\n onClick: this.onArchiveClick,\n verify: () => this.filterId === 0 && this.selectedId !== rootScope.myId\n }, {\n icon: 'unarchive',\n text: 'Unarchive',\n onClick: this.onArchiveClick,\n verify: () => this.filterId === 1 && this.selectedId !== rootScope.myId\n }, {\n icon: 'delete danger',\n text: 'Delete',\n onClick: this.onDeleteClick,\n verify: () => true\n }];\n\n this.element = ButtonMenu(this.buttons);\n this.element.id = 'dialogs-contextmenu';\n this.element.classList.add('contextmenu');\n document.getElementById('page-chats').append(this.element);\n }\n\n private onArchiveClick = () => {\n let dialog = appMessagesManager.getDialogOnly(this.selectedId);\n if(dialog) {\n appMessagesManager.editPeerFolders([dialog.peerId], +!dialog.folder_id);\n }\n };\n\n private onPinClick = () => {\n appMessagesManager.toggleDialogPin(this.selectedId, this.filterId).catch(err => {\n if(err.type === 'PINNED_DIALOGS_TOO_MUCH') {\n if(this.filterId >= 1) {\n toastNew({langPackKey: 'PinFolderLimitReached'});\n } else {\n new PopupPeer('pinned-dialogs-too-much', {\n buttons: [{\n langKey: 'OK',\n isCancel: true\n }, {\n langKey: 'FiltersSetupPinAlert',\n callback: () => {\n new AppChatFoldersTab(appSidebarLeft).open();\n }\n }],\n descriptionLangKey: 'PinToTopLimitReached2',\n descriptionLangArgs: [i18n('Chats', [rootScope.config.pinned_dialogs_count_max])]\n }).show();\n }\n }\n });\n };\n\n private onUnmuteClick = () => {\n appMessagesManager.togglePeerMute(this.selectedId, false);\n };\n \n private onMuteClick = () => {\n new PopupMute(this.selectedId);\n };\n\n private onUnreadClick = () => {\n const dialog = appMessagesManager.getDialogOnly(this.selectedId);\n if(!dialog) return;\n\n if(dialog.unread_count) {\n appMessagesManager.readHistory(this.selectedId, dialog.top_message);\n appMessagesManager.markDialogUnread(this.selectedId, true);\n } else {\n appMessagesManager.markDialogUnread(this.selectedId);\n }\n };\n\n private onDeleteClick = () => {\n new PopupDeleteDialog(this.selectedId/* , 'delete' */);\n };\n\n onContextMenu = (e: MouseEvent | Touch) => {\n if(this.init) {\n this.init();\n this.init = null;\n }\n\n let li: HTMLElement = null;\n \n try {\n li = findUpTag(e.target, 'LI');\n } catch(e) {}\n \n if(!li) return;\n\n if(e instanceof MouseEvent) e.preventDefault();\n if(this.element.classList.contains('active')) {\n return false;\n }\n if(e instanceof MouseEvent) e.cancelBubble = true;\n\n this.filterId = appDialogsManager.filterId;\n\n this.selectedId = li.dataset.peerId.toPeerId();\n this.dialog = appMessagesManager.getDialogOnly(this.selectedId);\n\n this.buttons.forEach(button => {\n const good = button.verify();\n\n button.element.classList.toggle('hide', !good);\n });\n\n // delete button\n this.buttons[this.buttons.length - 1].element.lastChild.replaceWith(i18n(appPeersManager.getDeleteButtonText(this.selectedId)));\n\n li.classList.add('menu-open');\n positionMenu(e, this.element);\n openBtnMenu(this.element, () => {\n li.classList.remove('menu-open');\n this.selectedId = this.dialog = this.filterId = undefined;\n });\n };\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nexport enum ConnectionStatus {\r\n Connected,\r\n Connecting,\r\n Closed,\r\n TimedOut\r\n};\r\n\r\nexport type ConnectionStatusChange = {\r\n _: 'networkerStatus', \r\n status: ConnectionStatus,\r\n dcId: number,\r\n name: string,\r\n isFileNetworker: boolean,\r\n isFileDownload: boolean,\r\n isFileUpload: boolean,\r\n retryAt?: number\r\n};\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { Message } from \"../layer\";\n/* import findUpClassName from \"../helpers/dom/findUpClassName\";\nimport rootScope from \"../lib/rootScope\";\nimport Transition from \"./transition\"; */\n\nexport enum SENDING_STATUS {\n Error = -1,\n Pending,\n Sent,\n Read\n}\n\nexport function getSendingStatus(message: Message.message | Message.messageService) {\n return message.pFlags.is_outgoing ? \n SENDING_STATUS.Pending : (\n message.pFlags.unread ? \n SENDING_STATUS.Sent : \n SENDING_STATUS.Read\n );\n}\n\nexport function setSendingStatus(\n container: HTMLElement, \n message?: Message.message | Message.messageService, \n disableAnimationIfRippleFound?: boolean\n) {\n let className: 'check' | 'checks' | 'sending';\n if(message?.pFlags.out) {\n if(message.pFlags.is_outgoing) {\n className = 'sending';\n } else if(message.pFlags.unread) {\n className = 'check';\n } else {\n className = 'checks';\n }\n }\n\n if(!className) {\n container.textContent = '';\n return;\n }\n \n const iconClassName = 'tgico-' + className;\n const lastElement = container.lastElementChild as HTMLElement;\n if(lastElement && lastElement.classList.contains(iconClassName)) {\n return;\n }\n \n const element = document.createElement('i');\n element.classList.add('sending-status-icon', /* 'transition-item', */ iconClassName);\n container.append(element);\n\n if(lastElement) {\n lastElement.remove();\n }\n\n /* if(!lastElement) {\n element.classList.add('active');\n return;\n }\n\n const select = Transition(container, undefined, 350, () => {\n lastElement.remove();\n }, false, true, false);\n\n let animate = rootScope.settings.animationsEnabled && className !== 'sending' && !lastElement.classList.contains('tgico-sending');\n if(disableAnimationIfRippleFound && animate) {\n const parent = findUpClassName(container, 'rp');\n if(parent.querySelector('.c-ripple__circle') || parent.matches(':hover')) {\n animate = false;\n }\n }\n\n select(element, animate, lastElement); */\n\n /* SetTransition(lastElement, 'is-visible', false, 350, () => {\n // lastElement.remove();\n }, 2);\n SetTransition(element, 'is-visible', true, 350, undefined, 2); */\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport App from \"../config/app\";\r\nimport DEBUG from \"../config/debug\";\r\nimport replaceContent from \"../helpers/dom/replaceContent\";\r\nimport apiUpdatesManager from \"../lib/appManagers/apiUpdatesManager\";\r\nimport { LangPackKey, i18n } from \"../lib/langPack\";\r\nimport { logger } from \"../lib/logger\";\r\nimport rootScope from \"../lib/rootScope\";\r\nimport Button from \"./button\";\r\nimport ProgressivePreloader from \"./preloader\";\r\nimport SetTransition from \"./singleTransition\";\r\nimport sessionStorage from '../lib/sessionStorage';\r\nimport { ConnectionStatus } from \"../lib/mtproto/connectionStatus\";\r\nimport cancelEvent from \"../helpers/dom/cancelEvent\";\r\nimport apiManager from \"../lib/mtproto/mtprotoworker\";\r\nimport { attachClickEvent } from \"../helpers/dom/clickEvent\";\r\n\r\nexport default class ConnectionStatusComponent {\r\n public static CHANGE_STATE_DELAY = 1000;\r\n\r\n private statusContainer: HTMLElement;\r\n private statusEl: HTMLElement;\r\n private statusPreloader: ProgressivePreloader;\r\n\r\n private currentLangPackKey: LangPackKey;\r\n\r\n private hadConnect = false;\r\n private retryAt: number;\r\n private connecting = false;\r\n private timedOut = false;\r\n private updating = false;\r\n\r\n private log: ReturnType<typeof logger>;\r\n\r\n private setFirstConnectionTimeout: number;\r\n private setStateTimeout: number;\r\n\r\n constructor(chatsContainer: HTMLElement) {\r\n this.log = logger('CS', undefined, undefined);\r\n \r\n this.statusContainer = document.createElement('div');\r\n this.statusContainer.classList.add('connection-status'/* , 'hide' */);\r\n\r\n this.statusEl = Button('btn-primary bg-warning connection-status-button', {noRipple: true});\r\n this.statusPreloader = new ProgressivePreloader({cancelable: false});\r\n this.statusPreloader.constructContainer({color: 'transparent', bold: true});\r\n this.statusContainer.append(this.statusEl);\r\n\r\n chatsContainer.prepend(this.statusContainer);\r\n\r\n rootScope.addEventListener('connection_status_change', (status) => {\r\n console.log(status);\r\n\r\n this.setConnectionStatus();\r\n });\r\n\r\n rootScope.addEventListener('state_synchronizing', (channelId) => {\r\n if(!channelId) {\r\n this.updating = true;\r\n DEBUG && this.log('updating', this.updating);\r\n this.setState();\r\n }\r\n });\r\n\r\n rootScope.addEventListener('state_synchronized', (channelId) => {\r\n DEBUG && this.log('state_synchronized', channelId);\r\n if(!channelId) {\r\n this.updating = false;\r\n DEBUG && this.log('updating', this.updating);\r\n this.setState();\r\n }\r\n });\r\n\r\n this.setFirstConnectionTimeout = window.setTimeout(this.setConnectionStatus, ConnectionStatusComponent.CHANGE_STATE_DELAY + 1e3);\r\n\r\n /* let bool = true;\r\n document.addEventListener('dblclick', () => {\r\n const dcId = 2;\r\n rootScope.dispatchEvent('connection_status_change', {\r\n dcId: dcId,\r\n isFileDownload: false,\r\n isFileNetworker: false,\r\n isFileUpload: false,\r\n name: \"NET-\" + dcId,\r\n status: bool ? (bool = false, ConnectionStatus.Closed) : (bool = true, ConnectionStatus.Connected),\r\n _: \"networkerStatus\"\r\n });\r\n }); */\r\n }\r\n\r\n private setConnectionStatus = () => {\r\n sessionStorage.get('dc').then(baseDcId => {\r\n if(!baseDcId) {\r\n baseDcId = App.baseDcId;\r\n }\r\n \r\n if(this.setFirstConnectionTimeout) {\r\n clearTimeout(this.setFirstConnectionTimeout);\r\n this.setFirstConnectionTimeout = 0;\r\n }\r\n\r\n const status = rootScope.connectionStatus['NET-' + baseDcId];\r\n const online = status && status.status === ConnectionStatus.Connected;\r\n\r\n if(this.connecting && online) {\r\n apiUpdatesManager.forceGetDifference();\r\n }\r\n\r\n if(online && !this.hadConnect) {\r\n this.hadConnect = true;\r\n }\r\n \r\n this.timedOut = status && status.status === ConnectionStatus.TimedOut;\r\n this.connecting = !online;\r\n this.retryAt = status && status.retryAt;\r\n DEBUG && this.log('connecting', this.connecting);\r\n this.setState();\r\n });\r\n };\r\n\r\n private setStatusText = (langPackKey: LangPackKey, args?: any[]) => {\r\n if(this.currentLangPackKey === langPackKey) return;\r\n this.currentLangPackKey = langPackKey;\r\n replaceContent(this.statusEl, i18n(langPackKey, args));\r\n this.statusPreloader.attach(this.statusEl);\r\n };\r\n\r\n private getA(langPackKey: LangPackKey, callback: () => void) {\r\n const a = document.createElement('a');\r\n a.classList.add('force-reconnect');\r\n a.append(i18n(langPackKey));\r\n attachClickEvent(a, (e) => {\r\n cancelEvent(e);\r\n callback();\r\n });\r\n\r\n return a;\r\n }\r\n\r\n private setState = () => {\r\n const timeout = ConnectionStatusComponent.CHANGE_STATE_DELAY;\r\n if(this.connecting) {\r\n if(this.timedOut) {\r\n const a = this.getA('ConnectionStatus.ForceReconnect', () => apiManager.forceReconnect());\r\n this.setStatusText('ConnectionStatus.TimedOut', [a]);\r\n } else if(this.hadConnect) {\r\n if(this.retryAt !== undefined) {\r\n const timerSpan = document.createElement('span');\r\n const retryAt = this.retryAt;\r\n const setTime = () => {\r\n const now = Date.now();\r\n timerSpan.innerText = '' + Math.round((retryAt - now) / 1000);\r\n if(now > retryAt) {\r\n clearInterval(interval);\r\n }\r\n };\r\n const interval = setInterval(setTime, 1e3);\r\n setTime();\r\n \r\n const a = this.getA('ConnectionStatus.Reconnect', () => apiManager.forceReconnectTimeout());\r\n this.setStatusText('ConnectionStatus.ReconnectIn', [timerSpan, a]);\r\n } else {\r\n this.setStatusText('ConnectionStatus.Reconnecting');\r\n }\r\n } else {\r\n this.setStatusText('ConnectionStatus.Waiting');\r\n }\r\n } else if(this.updating) {\r\n this.setStatusText('Updating');\r\n }\r\n\r\n DEBUG && this.log('setState', this.connecting || this.updating);\r\n window.requestAnimationFrame(() => {\r\n if(this.setStateTimeout) clearTimeout(this.setStateTimeout);\r\n\r\n const cb = () => {\r\n SetTransition(this.statusContainer, 'is-shown', this.connecting || this.updating, 200);\r\n this.setStateTimeout = 0;\r\n DEBUG && this.log('setState: isShown:', this.connecting || this.updating);\r\n };\r\n\r\n this.setStateTimeout = window.setTimeout(cb, timeout);\r\n //cb();\r\n /* if(timeout) this.setStateTimeout = window.setTimeout(cb, timeout);\r\n else cb(); */\r\n });\r\n };\r\n}\r\n","export default function roundRect(\n ctx: CanvasRenderingContext2D, \n x: number, \n y: number, \n width: number, \n height: number, \n radius: {[k in 'tl' | 'tr' | 'br' | 'bl']?: number} | number, \n fill?: boolean, \n stroke?: boolean\n) {\n if(typeof(radius) === 'number') {\n radius = {tl: radius, tr: radius, br: radius, bl: radius};\n } else {\n const defaultRadius = {tl: 0, tr: 0, br: 0, bl: 0};\n for(const side in defaultRadius) {\n // @ts-ignore\n radius[side] = radius[side] || defaultRadius[side];\n }\n }\n\n ctx.beginPath();\n ctx.moveTo(x + radius.tl, y);\n ctx.lineTo(x + width - radius.tr, y);\n ctx.quadraticCurveTo(x + width, y, x + width, y + radius.tr);\n ctx.lineTo(x + width, y + height - radius.br);\n ctx.quadraticCurveTo(x + width, y + height, x + width - radius.br, y + height);\n ctx.lineTo(x + radius.bl, y + height);\n ctx.quadraticCurveTo(x, y + height, x, y + height - radius.bl);\n ctx.lineTo(x, y + radius.tl);\n ctx.quadraticCurveTo(x, y, x + radius.tl, y);\n ctx.closePath();\n\n if(fill) {\n ctx.fill();\n }\n\n if(stroke) {\n ctx.stroke();\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { animate } from \"../helpers/animation\";\nimport customProperties from \"../helpers/dom/customProperties\";\nimport easeInOutSine from \"../helpers/easing/easeInOutSine\";\nimport mediaSizes from \"../helpers/mediaSizes\";\nimport roundRect from \"../helpers/roundRect\";\n\nconst DPR = window.devicePixelRatio;\nconst SIZE = 20 * DPR;\nconst MARGIN = 2.5 * DPR;\nconst WIDTH = 2 * DPR;\nconst RADIUS = 1 * DPR;\nconst LENGTH = 3;\n\nconst MIN_HEIGHT = 4;\nconst MAX_HEIGHT = 12;\nconst DURATION = 1000;\n\nexport default function groupCallActiveIcon(isActive = false) {\n const canvas = document.createElement('canvas');\n canvas.width = canvas.height = SIZE;\n const context = canvas.getContext('2d');\n \n const TOTAL_WIDTH = LENGTH * WIDTH + (LENGTH - 1) * MARGIN;\n const START_X = (SIZE - TOTAL_WIDTH) / 2;\n \n const startTime = Date.now();\n let wasMounted = false;\n // let hadRound = false;\n const renderFrame = () => {\n if(!canvas.isConnected) {\n if(wasMounted) {\n return false;\n }\n } else if(!wasMounted) {\n wasMounted = canvas.isConnected;\n }\n \n const time = Date.now();\n // if(((time - startTime) / DURATION) >= 1) {\n // hadRound = true;\n // }\n \n const progress = easeInOutSine((time - startTime) % DURATION, 0, 1, DURATION);\n \n context.clearRect(0, 0, SIZE, SIZE);\n context.fillStyle = isActive && !mediaSizes.isMobile ? customProperties.getProperty('primary-color') : '#fff';\n\n for(let i = 0; i < LENGTH; ++i) {\n const x = START_X + (i * WIDTH) + (i * MARGIN);\n\n let itemProgress: number;\n if(progress >= .5) {\n itemProgress = i % 2 ? 2 - progress * 2 : (progress - .5) * 2;\n } else {\n itemProgress = i % 2 ? progress * 2 : 1 - progress * 2;\n }\n\n let height = MIN_HEIGHT + (itemProgress * (MAX_HEIGHT - MIN_HEIGHT));\n /* if(!hadRound && i === 1) {\n console.log('call status animation', itemProgress, height, progress, progress >= .5);\n } */\n \n height *= DPR;\n const y = (SIZE - height) / 2;\n \n roundRect(context, x, y, WIDTH, height, RADIUS, true);\n }\n\n return true;\n };\n\n return {\n canvas,\n startAnimation: () => {\n animate(renderFrame);\n renderFrame();\n },\n setActive: (active: boolean) => {\n isActive = active;\n renderFrame();\n }\n };\n}\n","// https://spicyyoghurt.com/tools/easing-functions\nexport default function easeInOutSine (t: number, b: number, c: number, d: number) {\n return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b;\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport type DialogsStorage from \"../storages/dialogs\";\nimport type {MyDialogFilter as DialogFilter, MyDialogFilter} from \"../storages/filters\";\nimport type { LazyLoadQueueIntersector } from \"../../components/lazyLoadQueue\";\nimport AvatarElement from \"../../components/avatar\";\nimport DialogsContextMenu from \"../../components/dialogsContextMenu\";\nimport { horizontalMenu } from \"../../components/horizontalMenu\";\nimport { attachContextMenuListener, putPreloader } from \"../../components/misc\";\nimport ripple from \"../../components/ripple\";\n//import Scrollable from \"../../components/scrollable\";\nimport Scrollable, { ScrollableX, SliceSides } from \"../../components/scrollable\";\nimport { formatDateAccordingToTodayNew } from \"../../helpers/date\";\nimport { IS_MOBILE_SAFARI, IS_SAFARI } from \"../../environment/userAgent\";\nimport { logger, LogTypes } from \"../logger\";\nimport { RichTextProcessor } from \"../richtextprocessor\";\nimport rootScope from \"../rootScope\";\nimport appPeersManager from './appPeersManager';\nimport appImManager from \"./appImManager\";\nimport appMessagesManager, { Dialog, MyMessage } from \"./appMessagesManager\";\nimport appStateManager, { State } from \"./appStateManager\";\nimport appUsersManager, { User } from \"./appUsersManager\";\nimport Button from \"../../components/button\";\nimport SetTransition from \"../../components/singleTransition\";\nimport appDraftsManager, { MyDraftMessage } from \"./appDraftsManager\";\nimport DEBUG, { MOUNT_CLASS_TO } from \"../../config/debug\";\nimport appNotificationsManager from \"./appNotificationsManager\";\nimport PeerTitle from \"../../components/peerTitle\";\nimport I18n, { FormatterArguments, i18n, LangPackKey, _i18n } from \"../langPack\";\nimport findUpTag from \"../../helpers/dom/findUpTag\";\nimport lottieLoader from \"../rlottie/lottieLoader\";\nimport { wrapLocalSticker, wrapPhoto } from \"../../components/wrappers\";\nimport AppEditFolderTab from \"../../components/sidebarLeft/tabs/editFolder\";\nimport appSidebarLeft, { SettingSection } from \"../../components/sidebarLeft\";\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\nimport positionElementByIndex from \"../../helpers/dom/positionElementByIndex\";\nimport replaceContent from \"../../helpers/dom/replaceContent\";\nimport ConnectionStatusComponent from \"../../components/connectionStatus\";\nimport appChatsManager from \"./appChatsManager\";\nimport { renderImageFromUrlPromise } from \"../../helpers/dom/renderImageFromUrl\";\nimport { fastRafConventional, fastRafPromise } from \"../../helpers/schedulers\";\nimport SortedUserList from \"../../components/sortedUserList\";\nimport { IS_TOUCH_SUPPORTED } from \"../../environment/touchSupport\";\nimport handleTabSwipe from \"../../helpers/dom/handleTabSwipe\";\nimport windowSize from \"../../helpers/windowSize\";\nimport isInDOM from \"../../helpers/dom/isInDOM\";\nimport appPhotosManager, { MyPhoto } from \"./appPhotosManager\";\nimport { MyDocument } from \"./appDocsManager\";\nimport { setSendingStatus } from \"../../components/sendingStatus\";\nimport SortedList, { SortedElementBase } from \"../../helpers/sortedList\";\nimport debounce from \"../../helpers/schedulers/debounce\";\nimport { NULL_PEER_ID } from \"../mtproto/mtproto_config\";\nimport groupCallActiveIcon from \"../../components/groupCallActiveIcon\";\nimport { Chat, NotifyPeer } from \"../../layer\";\nimport IS_GROUP_CALL_SUPPORTED from \"../../environment/groupCallSupport\";\nimport mediaSizes from \"../../helpers/mediaSizes\";\nimport appNavigationController, { NavigationItem } from \"../../components/appNavigationController\";\nimport assumeType from \"../../helpers/assumeType\";\nimport generateTitleIcons from \"../../components/generateTitleIcons\";\nimport appMediaPlaybackController from \"../../components/appMediaPlaybackController\";\nimport setInnerHTML from \"../../helpers/dom/setInnerHTML\";\n\nexport type DialogDom = {\n avatarEl: AvatarElement,\n captionDiv: HTMLDivElement,\n titleSpan: HTMLSpanElement,\n titleSpanContainer: HTMLSpanElement,\n statusSpan: HTMLSpanElement,\n lastTimeSpan: HTMLSpanElement,\n unreadBadge: HTMLElement,\n callIcon?: ReturnType<typeof groupCallActiveIcon>,\n mentionsBadge?: HTMLElement,\n lastMessageSpan: HTMLSpanElement,\n containerEl: HTMLElement,\n listEl: HTMLLIElement,\n subtitleEl: HTMLElement\n};\n\ninterface SortedDialog extends SortedElementBase {\n dom: DialogDom,\n loadPromises?: Promise<any>[]\n}\n\nclass SortedDialogList extends SortedList<SortedDialog> {\n constructor(\n public list: HTMLUListElement, \n public indexKey: ReturnType<DialogsStorage['getDialogIndexKey']>,\n public onListLengthChange?: () => void\n ) {\n super({\n getIndex: (element) => appMessagesManager.getDialogOnly(element.id)[this.indexKey],\n onDelete: (element) => {\n element.dom.listEl.remove();\n this.onListLengthChange && this.onListLengthChange();\n },\n onSort: (element, idx) => {\n const willChangeLength = element.dom.listEl.parentElement !== this.list;\n positionElementByIndex(element.dom.listEl, this.list, idx);\n\n if(willChangeLength) {\n this.onListLengthChange && this.onListLengthChange();\n }\n },\n onElementCreate: (base, batch) => {\n const loadPromises: Promise<any>[] = batch ? [] : undefined;\n\n const {dom} = appDialogsManager.addListDialog({dialog: base.id, loadPromises, isBatch: batch});\n (base as SortedDialog).dom = dom;\n\n if(loadPromises?.length) {\n (base as SortedDialog).loadPromises = loadPromises;\n Promise.all(loadPromises).finally(() => {\n delete (base as SortedDialog).loadPromises;\n });\n }\n\n return base as SortedDialog;\n },\n updateElementWith: fastRafConventional\n });\n }\n\n public clear() {\n this.list.innerHTML = '';\n super.clear();\n }\n}\n\n//const testScroll = false;\n//let testTopSlice = 1;\n\nexport class AppDialogsManager {\n private chatsContainer = document.getElementById('chatlist-container') as HTMLDivElement;\n private chatsPreloader: HTMLElement;\n\n private loadDialogsPromise: Promise<any>;\n\n private scroll: Scrollable = null;\n \n private log = logger('DIALOGS', LogTypes.Log | LogTypes.Error | LogTypes.Warn | LogTypes.Debug);\n\n private contextMenu = new DialogsContextMenu();\n\n public sortedList: SortedDialogList;\n public sortedLists: {[filterId: number]: SortedDialogList} = {};\n public scrollables: {[filterId: number]: Scrollable} = {};\n public filterId: number;\n private folders: {[k in 'menu' | 'container' | 'menuScrollContainer']: HTMLElement} = {\n menu: document.getElementById('folders-tabs'),\n menuScrollContainer: null,\n container: document.getElementById('folders-container')\n };\n private filtersRendered: {\n [filterId: string]: {\n menu: HTMLElement, \n container: HTMLElement,\n unread: HTMLElement,\n title: HTMLElement\n }\n } = {};\n private showFiltersPromise: Promise<void>;\n private allUnreadCount: HTMLElement;\n\n private sliceTimeout: number;\n\n private lastActiveElements: Set<HTMLElement> = new Set();\n\n private offsets: {top: number, bottom: number} = {top: 0, bottom: 0};\n \n private loadContacts: () => void;\n private processContact: (peerId: PeerId) => void;\n\n private indexKey: ReturnType<DialogsStorage['getDialogIndexKey']>;\n\n private initedListeners = false;\n\n private onListLengthChange: () => Promise<void>;\n private loadedDialogsAtLeastOnce = false;\n private allChatsIntlElement: I18n.IntlElement;\n\n private emptyDialogsPlaceholderSubtitle: I18n.IntlElement;\n private updateContactsLengthPromise: Promise<number>;\n\n private filtersNavigationItem: NavigationItem;\n\n constructor() {\n this.chatsPreloader = putPreloader(null, true);\n\n this.allUnreadCount = this.folders.menu.querySelector('.badge');\n \n this.folders.menuScrollContainer = this.folders.menu.parentElement;\n\n this.onListLengthChange = debounce(this._onListLengthChange, 100, false, true);\n\n const bottomPart = document.createElement('div');\n bottomPart.classList.add('connection-status-bottom');\n bottomPart.append(this.folders.container);\n\n /* if(isTouchSupported && isSafari) {\n let allowUp: boolean, allowDown: boolean, slideBeginY: number;\n const container = this.scroll.container;\n container.addEventListener('touchstart', (event) => {\n allowUp = container.scrollTop > 0;\n allowDown = (container.scrollTop < container.scrollHeight - container.clientHeight);\n // @ts-ignore\n slideBeginY = event.pageY;\n });\n \n container.addEventListener('touchmove', (event: any) => {\n var up = (event.pageY > slideBeginY);\n var down = (event.pageY < slideBeginY);\n slideBeginY = event.pageY;\n if((up && allowUp) || (down && allowDown)) {\n event.stopPropagation();\n } else if(up || down) {\n event.preventDefault();\n }\n });\n } */\n\n if(IS_TOUCH_SUPPORTED) {\n handleTabSwipe({\n element: this.folders.container,\n onSwipe: (xDiff) => {\n const prevId = selectTab.prevId();\n selectTab(xDiff > 0 ? prevId + 1 : prevId - 1);\n }\n });\n }\n\n this.allChatsIntlElement = new I18n.IntlElement({\n key: 'FilterAllChatsShort'\n });\n this.setFilterId(0);\n this.addFilter({\n id: this.filterId,\n title: '',\n titleEl: this.allChatsIntlElement.element,\n orderIndex: 0\n });\n\n this.sortedList = this.sortedLists[this.filterId];\n this.scroll = this.scrollables[this.filterId];\n\n /* if(testScroll) {\n let i = 0;\n let add = () => {\n let li = document.createElement('li');\n li.dataset.id = '' + i;\n li.id = '' + i;\n li.innerHTML = `<div class=\"rp\"><avatar-element style=\"background-color: rgb(166, 149, 231); font-size: 0px;\"><img src=\"assets/img/pepe.jpg\"></avatar-element><div class=\"user-caption\"><p><span class=\"user-title\">${i}</span><span><span class=\"message-status\"></span><span class=\"message-time\">18:33</span></span></p><p><span class=\"user-last-message\"><b>-_-_-_-: </b>qweasd</span><span></span></p></div></div>`;\n i++;\n this.scroll.append(li);\n };\n for(let i = 0; i < 500; ++i) {\n add();\n }\n (window as any).addElement = add;\n } */\n\n rootScope.addEventListener('state_cleared', () => {\n //setTimeout(() => \n appStateManager.getState().then((state) => {\n this.loadedDialogsAtLeastOnce = false;\n\n appUsersManager.clear();\n appChatsManager.clear();\n \n const filtersStorage = appMessagesManager.filtersStorage;\n const filters = filtersStorage.filters;\n for(const filterId in filters) { // delete filters\n rootScope.dispatchEvent('updateDialogFilter', {\n _: 'updateDialogFilter',\n id: +filterId,\n });\n }\n\n appMessagesManager.clear();\n\n /* const clearPromises: Promise<any>[] = [];\n for(const name in appStateManager.storagesResults) {\n const results = appStateManager.storagesResults[name as keyof AppStateManager['storages']];\n const storage = appStateManager.storages[name as keyof AppStateManager['storages']];\n results.length = 0;\n clearPromises.push(storage.clear());\n } */\n\n this.sortedList.clear();\n this.onTabChange();\n this.onStateLoaded(state);\n })//, 5000);\n });\n\n const foldersScrollable = new ScrollableX(this.folders.menuScrollContainer);\n bottomPart.prepend(this.folders.menuScrollContainer);\n const selectTab = horizontalMenu(this.folders.menu, this.folders.container, (id, tabContent) => {\n /* if(id !== 0) {\n id += 1;\n } */\n\n id = +tabContent.dataset.filterId || 0;\n\n if(!IS_MOBILE_SAFARI) {\n if(id) {\n if(!this.filtersNavigationItem) {\n this.filtersNavigationItem = {\n type: 'filters',\n onPop: () => {\n selectTab(0);\n this.filtersNavigationItem = undefined;\n }\n };\n \n appNavigationController.spliceItems(1, 0, this.filtersNavigationItem);\n }\n } else if(this.filtersNavigationItem) {\n appNavigationController.removeItem(this.filtersNavigationItem);\n this.filtersNavigationItem = undefined;\n }\n }\n\n if(this.filterId === id) return;\n\n this.sortedLists[id].clear();\n this.setFilterId(id);\n this.onTabChange();\n }, () => {\n for(const folderId in this.sortedLists) {\n if(+folderId !== this.filterId) {\n this.sortedLists[folderId].clear();\n }\n }\n }, undefined, foldersScrollable);\n\n //selectTab(0);\n (this.folders.menu.firstElementChild as HTMLElement).click();\n appMessagesManager.construct();\n appStateManager.getState().then((state) => {\n // * it should've had a better place :(\n appMediaPlaybackController.setPlaybackParams(state.playbackParams);\n rootScope.addEventListener('media_playback_params', (params) => {\n appStateManager.pushToState('playbackParams', params);\n });\n \n return this.onStateLoaded(state);\n })/* .then(() => {\n const isLoadedMain = appMessagesManager.dialogsStorage.isDialogsLoaded(0);\n const isLoadedArchive = appMessagesManager.dialogsStorage.isDialogsLoaded(1);\n const wasLoaded = isLoadedMain || isLoadedArchive;\n const a: Promise<any> = isLoadedMain ? Promise.resolve() : appMessagesManager.getConversationsAll('', 0);\n const b: Promise<any> = isLoadedArchive ? Promise.resolve() : appMessagesManager.getConversationsAll('', 1);\n a.finally(() => {\n b.then(() => {\n if(wasLoaded) {\n (apiUpdatesManager.updatesState.syncLoading || Promise.resolve()).then(() => {\n appMessagesManager.refreshConversations();\n });\n }\n });\n });\n }) */;\n\n mediaSizes.addEventListener('resize', () => {\n this.changeFiltersAllChatsKey();\n });\n\n new ConnectionStatusComponent(this.chatsContainer);\n this.chatsContainer.append(bottomPart);\n\n setTimeout(() => {\n lottieLoader.loadLottieWorkers();\n }, 200);\n }\n\n public get chatList() {\n return this.sortedList.list;\n }\n\n public setFilterId(filterId: number) {\n this.filterId = filterId;\n this.indexKey = appMessagesManager.dialogsStorage ? appMessagesManager.dialogsStorage.getDialogIndexKey(this.filterId) : 'index';\n rootScope.filterId = filterId;\n }\n\n private setOnlineStatus(element: HTMLElement, online: boolean) {\n const className = 'is-online';\n const hasClassName = element.classList.contains(className);\n !hasClassName && online && element.classList.add(className);\n SetTransition(element, 'is-visible', online, 250, online ? undefined : () => {\n element.classList.remove(className);\n }, online && !hasClassName ? 2 : 0);\n }\n\n private initListeners() {\n rootScope.addEventListener('user_update', (userId) => {\n //console.log('updating user:', user, dialog);\n \n const peerId = userId.toPeerId();\n const dom = this.getDialogDom(peerId);\n if(dom && !appUsersManager.isBot(userId) && peerId !== rootScope.myId) {\n const user = appUsersManager.getUser(userId);\n const online = user.status?._ === 'userStatusOnline';\n this.setOnlineStatus(dom.avatarEl, online);\n }\n });\n\n rootScope.addEventListener('chat_update', (chatId) => {\n const peerId = chatId.toPeerId(true);\n const dialog = appMessagesManager.getDialogOnly(peerId);\n if(dialog) {\n this.processDialogForCallStatus(dialog);\n }\n });\n\n /* rootScope.$on('dialog_top', (e) => {\n const dialog = e;\n\n this.setLastMessage(dialog);\n this.setDialogPosition(dialog);\n\n this.setFiltersUnreadCount();\n }); */\n\n rootScope.addEventListener('folder_unread', (folder) => {\n this.setFilterUnreadCount(folder.id);\n });\n\n rootScope.addEventListener('contacts_update', (userId) => {\n this.processContact && this.processContact(userId.toPeerId());\n });\n\n rootScope.addEventListener('dialog_flush', ({peerId}) => {\n const dialog = appMessagesManager.getDialogOnly(peerId);\n if(dialog) {\n this.setLastMessage(dialog, undefined, undefined, undefined, undefined, undefined, true);\n this.validateDialogForFilter(dialog);\n this.setFiltersUnreadCount();\n }\n });\n\n rootScope.addEventListener('dialogs_multiupdate', (dialogs) => {\n for(const peerId in dialogs) {\n const dialog = dialogs[peerId];\n this.updateDialog(dialog);\n\n if(this.processContact) {\n this.processContact(peerId.toPeerId());\n }\n\n this.validateDialogForFilter(dialog);\n }\n });\n\n rootScope.addEventListener('dialog_drop', ({peerId}) => {\n this.deleteDialog(peerId);\n\n if(this.processContact) {\n this.processContact(peerId);\n }\n });\n\n rootScope.addEventListener('dialog_unread', ({peerId}) => {\n const dialog = appMessagesManager.getDialogOnly(peerId);\n if(dialog) {\n this.setUnreadMessages(dialog);\n this.validateDialogForFilter(dialog);\n }\n });\n\n rootScope.addEventListener('dialog_notify_settings', (dialog) => {\n this.validateDialogForFilter(dialog);\n this.setUnreadMessages(dialog); // возможно это не нужно, но нужно менять is-muted\n this.setFiltersUnreadCount();\n });\n\n rootScope.addEventListener('dialog_draft', ({dialog, drop, peerId}) => {\n if(drop) {\n this.sortedList.delete(peerId);\n } else {\n this.updateDialog(dialog);\n }\n\n if(this.processContact) {\n this.processContact(peerId);\n }\n });\n\n rootScope.addEventListener('peer_changed', (peerId) => {\n //const perf = performance.now();\n for(const element of this.lastActiveElements) {\n if(element.dataset.peerId.toPeerId() !== peerId) {\n this.setDialogActive(element, false);\n }\n }\n\n const elements = Array.from(document.querySelectorAll(`[data-autonomous=\"0\"] li[data-peer-id=\"${peerId}\"]`)) as HTMLElement[];\n elements.forEach(element => {\n this.setDialogActive(element, true);\n });\n //this.log('peer_changed total time:', performance.now() - perf);\n });\n\n rootScope.addEventListener('filter_update', (filter) => {\n if(!this.filtersRendered[filter.id]) {\n this.addFilter(filter);\n return;\n } else if(filter.id === this.filterId) { // это нет тут смысла вызывать, так как будет dialogs_multiupdate\n const dialogs = appMessagesManager.dialogsStorage.getCachedDialogs(true);\n this.validateListForFilter();\n for(let i = 0, length = dialogs.length; i < length; ++i) {\n const dialog = dialogs[i];\n this.updateDialog(dialog);\n }\n }\n\n const elements = this.filtersRendered[filter.id];\n setInnerHTML(elements.title, RichTextProcessor.wrapEmojiText(filter.title));\n });\n\n rootScope.addEventListener('filter_delete', (filter) => {\n const elements = this.filtersRendered[filter.id];\n if(!elements) return;\n\n // set tab\n //(this.folders.menu.firstElementChild.children[Math.max(0, filter.id - 2)] as HTMLElement).click();\n (this.folders.menu.firstElementChild as HTMLElement).click();\n\n elements.container.remove();\n elements.menu.remove();\n \n delete this.sortedLists[filter.id];\n delete this.scrollables[filter.id];\n delete this.filtersRendered[filter.id];\n\n this.onFiltersLengthChange();\n });\n\n rootScope.addEventListener('filter_order', (order) => {\n const containerToAppend = this.folders.menu as HTMLElement;\n order.forEach((filterId) => {\n const filter = appMessagesManager.filtersStorage.getFilter(filterId);\n const renderedFilter = this.filtersRendered[filterId];\n\n const sortedList = this.sortedLists[filterId];\n sortedList.indexKey = appMessagesManager.dialogsStorage.getDialogIndexKey(filterId);\n\n positionElementByIndex(renderedFilter.menu, containerToAppend, filter.orderIndex);\n positionElementByIndex(renderedFilter.container, this.folders.container, filter.orderIndex);\n });\n\n this.indexKey = appMessagesManager.dialogsStorage.getDialogIndexKey(this.filterId);\n\n /* if(this.filterId) {\n const tabIndex = order.indexOf(this.filterId) + 1;\n selectTab.prevId = tabIndex;\n } */\n });\n\n rootScope.addEventListener('peer_typings', ({peerId, typings}) => {\n const dialog = appMessagesManager.getDialogOnly(peerId);\n if(!dialog) return;\n\n if(typings.length) {\n this.setTyping(dialog);\n } else {\n this.unsetTyping(dialog);\n }\n });\n }\n\n private setDialogActive(listEl: HTMLElement, active: boolean) {\n // @ts-ignore\n const dom = listEl.dialogDom as DialogDom;\n listEl.classList.toggle('active', active);\n if(active) {\n this.lastActiveElements.add(listEl);\n } else {\n this.lastActiveElements.delete(listEl);\n }\n\n if(dom?.callIcon) {\n dom.callIcon.setActive(active);\n }\n }\n\n private async onStateLoaded(state: State) {\n if(state.notifySettings) {\n for(const key in state.notifySettings) {\n assumeType<Exclude<NotifyPeer['_'], 'notifyPeer'>>(key);\n appNotificationsManager.savePeerSettings({\n key,\n settings: state.notifySettings[key]\n });\n }\n }\n\n appNotificationsManager.getNotifyPeerTypeSettings();\n\n if(!this.initedListeners) {\n this.initListeners();\n this.initedListeners = true;\n }\n \n const renderFiltersPromise = appMessagesManager.filtersStorage.getDialogFilters().then((filters) => {\n for(const filter of filters) {\n this.addFilter(filter);\n }\n });\n\n if(state.filters && Object.keys(state.filters).length) {\n await renderFiltersPromise;\n if(this.showFiltersPromise) {\n await this.showFiltersPromise;\n }\n }\n\n if(appStateManager.storagesResults.dialogs.length) {\n appDraftsManager.addMissedDialogs();\n }\n\n return this.onChatsScroll().then(() => {\n appMessagesManager.fillConversations();\n });\n }\n\n /* private getOffset(side: 'top' | 'bottom'): {index: number, pos: number} {\n if(!this.scroll.loadedAll[side]) {\n const element = (side === 'top' ? this.chatList.firstElementChild : this.chatList.lastElementChild) as HTMLElement;\n if(element) {\n const peerId = element.dataset.peerId;\n const dialog = appMessagesManager.getDialogByPeerId(peerId);\n return {index: dialog[0].index, pos: dialog[1]};\n }\n }\n\n return {index: 0, pos: -1};\n } */\n private getOffsetIndex(side: 'top' | 'bottom') {\n return {index: this.scroll.loadedAll[side] ? 0 : this.offsets[side]};\n }\n\n private isDialogMustBeInViewport(dialog: Dialog) {\n if(dialog.migratedTo !== undefined || !this.testDialogForFilter(dialog)) return false;\n //return true;\n const topOffset = this.getOffsetIndex('top');\n const bottomOffset = this.getOffsetIndex('bottom');\n \n if(!topOffset.index && !bottomOffset.index) {\n return true;\n }\n \n const index = dialog[this.indexKey];\n return (!topOffset.index || index <= topOffset.index) && (!bottomOffset.index || index >= bottomOffset.index);\n }\n\n private deleteDialog(peerId: PeerId) {\n this.sortedList.delete(peerId);\n }\n\n private updateDialog(dialog: Dialog) {\n if(this.isDialogMustBeInViewport(dialog)) {\n if(!this.sortedList.has(dialog.peerId)) {\n this.sortedList.add(dialog.peerId);\n return;\n }\n } else {\n this.deleteDialog(dialog.peerId);\n return;\n }\n\n const dom = this.getDialogDom(dialog.peerId);\n if(dom) {\n this.setLastMessage(dialog, undefined, dom, undefined, undefined, undefined, true);\n this.sortedList.update(dialog.peerId);\n }\n }\n\n public onTabChange = () => {\n this.scroll = this.scrollables[this.filterId];\n this.scroll.loadedAll.top = true;\n this.scroll.loadedAll.bottom = false;\n this.offsets.top = this.offsets.bottom = 0;\n this.loadDialogsPromise = undefined;\n this.sortedList = this.sortedLists[this.filterId];\n this.onChatsScroll();\n };\n\n private setFilterUnreadCount(filterId: number) {\n const unreadSpan = filterId === 0 ? this.allUnreadCount : this.filtersRendered[filterId]?.unread;\n if(!unreadSpan) {\n return;\n }\n\n const folder = appMessagesManager.dialogsStorage.getFolder(filterId);\n const foundUnmuted = filterId === 0 || !!folder.dialogs.find(dialog => {\n return (dialog.unread_count || dialog.pFlags.unread_mark) && !appNotificationsManager.isPeerLocalMuted(dialog.peerId, true);\n });\n \n unreadSpan.classList.toggle('badge-gray', !foundUnmuted);\n \n const sum = folder.unreadDialogsCount;\n unreadSpan.innerText = sum ? '' + sum : '';\n }\n\n private setFiltersUnreadCount() {\n for(const filterId in this.filtersRendered) {\n this.setFilterUnreadCount(+filterId);\n }\n }\n\n /**\n * Удалит неподходящие чаты из списка, но не добавит их(!)\n */\n private validateListForFilter() {\n const filter = appMessagesManager.filtersStorage.getFilter(this.filterId) || null;\n this.sortedList.getAll().forEach((element) => {\n const dialog = appMessagesManager.getDialogOnly(element.id);\n if(!this.testDialogForFilter(dialog, filter)) {\n this.deleteDialog(element.id);\n }\n });\n }\n\n /**\n * Удалит неподходящий чат из списка, но не добавит его(!)\n */\n private validateDialogForFilter(dialog: Dialog, filter?: MyDialogFilter) {\n if(!this.getDialogDom(dialog.peerId)) {\n return;\n }\n\n if(!this.testDialogForFilter(dialog, filter)) {\n this.deleteDialog(dialog.peerId);\n }\n }\n\n public testDialogForFilter(dialog: Dialog, filter = appMessagesManager.filtersStorage.getFilter(this.filterId)) {\n if(!dialog || \n (filter && !appMessagesManager.filtersStorage.testDialogForFilter(dialog, filter)) || \n (!filter && this.filterId !== dialog.folder_id)) {\n return false;\n }\n\n return true;\n }\n\n public generateScrollable(list: HTMLUListElement, filterId: number) {\n const scrollable = new Scrollable(null, 'CL', 500);\n scrollable.container.addEventListener('scroll', this.onChatsRegularScroll);\n scrollable.container.dataset.filterId = '' + filterId;\n scrollable.onScrolledTop = this.onChatsScrollTop;\n scrollable.onScrolledBottom = this.onChatsScroll;\n scrollable.setVirtualContainer(list);\n\n const sortedDialogList = new SortedDialogList(\n list, \n appMessagesManager.dialogsStorage ? appMessagesManager.dialogsStorage.getDialogIndexKey(filterId) : 'index',\n this.onListLengthChange\n );\n\n this.scrollables[filterId] = scrollable;\n this.sortedLists[filterId] = sortedDialogList;\n\n // list.classList.add('hide');\n // scrollable.container.style.backgroundColor = '#' + (Math.random() * (16 ** 6 - 1) | 0).toString(16);\n\n return scrollable;\n }\n\n private addFilter(filter: Pick<DialogFilter, 'title' | 'id' | 'orderIndex'> & Partial<{titleEl: HTMLElement}>) {\n if(this.filtersRendered[filter.id]) return;\n\n const menuTab = document.createElement('div');\n menuTab.classList.add('menu-horizontal-div-item');\n const span = document.createElement('span');\n const titleSpan = document.createElement('span');\n titleSpan.classList.add('text-super');\n if(filter.titleEl) titleSpan.append(filter.titleEl);\n else setInnerHTML(titleSpan, RichTextProcessor.wrapEmojiText(filter.title));\n const unreadSpan = document.createElement('div');\n unreadSpan.classList.add('badge', 'badge-20', 'badge-primary');\n const i = document.createElement('i');\n span.append(titleSpan, unreadSpan, i);\n ripple(menuTab);\n menuTab.append(span);\n\n const containerToAppend = this.folders.menu as HTMLElement;\n positionElementByIndex(menuTab, containerToAppend, filter.orderIndex);\n //containerToAppend.append(li);\n\n const ul = this.createChatList();\n const scrollable = this.generateScrollable(ul, filter.id);\n\n scrollable.container.classList.add('tabs-tab', 'chatlist-parts');\n\n /* const parts = document.createElement('div');\n parts.classList.add('chatlist-parts'); */\n \n const top = document.createElement('div');\n top.classList.add('chatlist-top');\n \n const bottom = document.createElement('div');\n bottom.classList.add('chatlist-bottom');\n\n top.append(ul);\n scrollable.container.append(top, bottom);\n /* parts.append(top, bottom);\n scrollable.container.append(parts); */\n \n const div = scrollable.container;\n //this.folders.container.append(div);\n positionElementByIndex(scrollable.container, this.folders.container, filter.orderIndex);\n\n this.setListClickListener(ul, null, true);\n\n this.filtersRendered[filter.id] = {\n menu: menuTab,\n container: div,\n unread: unreadSpan,\n title: titleSpan\n };\n\n this.onFiltersLengthChange();\n }\n\n private changeFiltersAllChatsKey() {\n const scrollable = this.folders.menuScrollContainer.firstElementChild;\n const key: LangPackKey = scrollable.scrollWidth > scrollable.clientWidth ? 'FilterAllChatsShort' : 'FilterAllChats';\n this.allChatsIntlElement.compareAndUpdate({key});\n }\n\n private onFiltersLengthChange() {\n if(!this.showFiltersPromise) {\n this.showFiltersPromise = new Promise<void>((resolve) => {\n window.setTimeout(() => {\n const length = Object.keys(this.filtersRendered).length;\n const show = length > 1;\n const wasShowing = !this.folders.menuScrollContainer.classList.contains('hide');\n\n if(show !== wasShowing) {\n this.folders.menuScrollContainer.classList.toggle('hide', !show);\n if(show && !wasShowing) {\n this.setFiltersUnreadCount();\n }\n\n this.chatsContainer.classList.toggle('has-filters', show);\n }\n\n this.changeFiltersAllChatsKey();\n\n this.showFiltersPromise = undefined;\n resolve();\n }, 0);\n });\n }\n\n return this.showFiltersPromise;\n }\n\n private loadDialogs(side: SliceSides) {\n /* if(testScroll) {\n return;\n } */\n \n if(this.loadDialogsPromise/* || 1 === 1 */) return this.loadDialogsPromise;\n\n const promise = new Promise<void>(async(resolve) => {\n const {chatList, filterId, indexKey} = this;\n\n //return;\n \n // let loadCount = 30/*this.chatsLoadCount */;\n let loadCount = windowSize.height / 72 * 1.25 | 0;\n let offsetIndex = 0;\n \n const {index: currentOffsetIndex} = this.getOffsetIndex(side);\n if(currentOffsetIndex) {\n if(side === 'top') {\n const storage = appMessagesManager.dialogsStorage.getFolderDialogs(filterId, true);\n const index = storage.findIndex(dialog => dialog[indexKey] <= currentOffsetIndex);\n const needIndex = Math.max(0, index - loadCount);\n loadCount = index - needIndex;\n offsetIndex = storage[needIndex][indexKey] + 1;\n } else {\n offsetIndex = currentOffsetIndex;\n }\n }\n \n //let offset = storage[storage.length - 1]?.index || 0;\n \n try {\n //console.time('getDialogs time');\n \n const getConversationsResult = appMessagesManager.getConversations('', offsetIndex, loadCount, filterId, true);\n if(!getConversationsResult.cached && !chatList.childElementCount) {\n const container = chatList.parentElement;\n container.append(this.chatsPreloader);\n }\n \n const result = await getConversationsResult.promise;\n \n if(this.loadDialogsPromise !== promise) {\n return;\n }\n \n //console.timeEnd('getDialogs time');\n \n // * loaded all\n //if(!result.dialogs.length || chatList.childElementCount === result.count) {\n // !result.dialogs.length не подходит, так как при супердревном диалоге getConversations его не выдаст.\n //if(chatList.childElementCount === result.count) {\n if(side === 'bottom') {\n if(result.isEnd) {\n this.scroll.loadedAll[side] = true;\n }\n } else if(result.isTopEnd) {\n this.scroll.loadedAll[side] = true;\n }\n\n this.loadedDialogsAtLeastOnce = true;\n \n if(result.dialogs.length) {\n const dialogs = side === 'top' ? result.dialogs.slice().reverse() : result.dialogs;\n \n const loadPromises: Promise<any>[] = [];\n\n const callbacks: (() => void)[] = [];\n const cccc = (callback: () => void) => {\n callbacks.push(callback);\n };\n\n dialogs.forEach((dialog) => {\n // :(\n const isBuggedDialog = !appMessagesManager.getDialogOnly(dialog.peerId);\n if(isBuggedDialog) {\n return;\n }\n\n const element = this.sortedList.add(dialog.peerId, true, cccc, false);\n if(element.loadPromises) {\n loadPromises.push(...element.loadPromises);\n }\n });\n\n await Promise.all(loadPromises).finally();\n\n callbacks.forEach(callback => callback());\n } else {\n this.onListLengthChange();\n }\n\n const offsetDialog = result.dialogs[side === 'top' ? 0 : result.dialogs.length - 1];\n if(offsetDialog) {\n this.offsets[side] = offsetDialog[indexKey];\n }\n\n this.log.debug('getDialogs ' + loadCount + ' dialogs by offset:', offsetIndex, result, chatList.childElementCount);\n \n setTimeout(() => {\n this.scroll.onScroll();\n }, 0);\n } catch(err) {\n this.log.error(err);\n }\n \n if(this.chatsPreloader.parentElement) {\n this.chatsPreloader.remove();\n }\n \n resolve();\n }).finally(() => {\n this.loadDialogsPromise = undefined;\n });\n\n return this.loadDialogsPromise = promise;\n }\n\n private generateEmptyPlaceholder(options: {\n title: LangPackKey,\n subtitle?: LangPackKey,\n subtitleArgs?: FormatterArguments,\n classNameType: string\n }) {\n const BASE_CLASS = 'empty-placeholder';\n const container = document.createElement('div');\n container.classList.add(BASE_CLASS, BASE_CLASS + '-' + options.classNameType);\n \n const header = document.createElement('div');\n header.classList.add(BASE_CLASS + '-header');\n _i18n(header, options.title);\n\n const subtitle = document.createElement('div');\n subtitle.classList.add(BASE_CLASS + '-subtitle');\n if(options.subtitle) {\n _i18n(subtitle, options.subtitle, options.subtitleArgs);\n }\n\n container.append(header, subtitle);\n\n return {container, header, subtitle};\n }\n\n private checkIfPlaceholderNeeded() {\n if(this.filterId === 1) {\n return;\n }\n\n const chatList = this.chatList;\n const part = chatList.parentElement as HTMLElement;\n let placeholderContainer = (Array.from(part.children) as HTMLElement[]).find(el => el.matches('.empty-placeholder'));\n const needPlaceholder = this.scroll.loadedAll.bottom && !chatList.childElementCount/* || true */;\n // chatList.style.display = 'none';\n\n if(needPlaceholder && placeholderContainer) {\n return;\n } else if(!needPlaceholder) {\n if(placeholderContainer) {\n part.classList.remove('with-placeholder');\n placeholderContainer.remove();\n }\n\n return;\n }\n\n let placeholder: ReturnType<AppDialogsManager['generateEmptyPlaceholder']>, type: 'dialogs' | 'folder';\n if(!this.filterId) {\n placeholder = this.generateEmptyPlaceholder({\n title: 'ChatList.Main.EmptyPlaceholder.Title',\n classNameType: type = 'dialogs'\n });\n \n placeholderContainer = placeholder.container;\n \n const img = document.createElement('img');\n img.classList.add('empty-placeholder-dialogs-icon');\n\n this.emptyDialogsPlaceholderSubtitle = new I18n.IntlElement({\n element: placeholder.subtitle\n });\n \n Promise.all([\n this.updateContactsLength(false),\n renderImageFromUrlPromise(img, 'assets/img/EmptyChats.svg'),\n fastRafPromise()\n ]).then(([usersLength]) => {\n placeholderContainer.classList.add('visible');\n part.classList.toggle('has-contacts', !!usersLength);\n });\n\n placeholderContainer.prepend(img);\n } else {\n placeholder = this.generateEmptyPlaceholder({\n title: 'FilterNoChatsToDisplay',\n subtitle: 'FilterNoChatsToDisplayInfo',\n classNameType: type = 'folder'\n });\n\n placeholderContainer = placeholder.container;\n\n placeholderContainer.prepend(wrapLocalSticker({\n emoji: '📂',\n width: 128,\n height: 128\n }).container)\n\n const button = Button('btn-primary btn-color-primary btn-control tgico', {\n text: 'FilterHeaderEdit',\n icon: 'settings'\n });\n\n attachClickEvent(button, () => {\n new AppEditFolderTab(appSidebarLeft).open(appMessagesManager.filtersStorage.getFilter(this.filterId));\n });\n\n placeholderContainer.append(button);\n }\n\n part.append(placeholderContainer);\n part.classList.add('with-placeholder');\n part.dataset.placeholderType = type;\n }\n\n private updateContactsLength(updatePartClassName: boolean) {\n if(this.updateContactsLengthPromise) return this.updateContactsLengthPromise;\n return this.updateContactsLengthPromise = appUsersManager.getContacts().then(users => {\n const subtitle = this.emptyDialogsPlaceholderSubtitle;\n if(subtitle) {\n let key: LangPackKey, args: FormatterArguments;\n \n if(users.length/* && false */) {\n key = 'ChatList.Main.EmptyPlaceholder.Subtitle';\n args = [i18n('Contacts.Count', [users.length])];\n } else {\n key = 'ChatList.Main.EmptyPlaceholder.SubtitleNoContacts';\n args = [];\n }\n\n subtitle.compareAndUpdate({\n key,\n args\n });\n }\n\n if(updatePartClassName) {\n const chatList = this.chatList;\n const part = chatList.parentElement as HTMLElement;\n part.classList.toggle('has-contacts', !!users.length);\n }\n\n this.updateContactsLengthPromise = undefined;\n \n return users.length;\n });\n }\n\n private removeContactsPlaceholder() {\n const chatList = this.chatList;\n const parts = chatList.parentElement.parentElement;\n const bottom = chatList.parentElement.nextElementSibling as HTMLElement;\n parts.classList.remove('with-contacts');\n bottom.innerHTML = '';\n this.loadContacts = undefined;\n this.processContact = undefined;\n }\n\n private _onListLengthChange = () => {\n if(!this.loadedDialogsAtLeastOnce) {\n return;\n }\n\n this.checkIfPlaceholderNeeded();\n\n if(this.filterId > 0) return;\n\n const chatList = this.chatList;\n const count = chatList.childElementCount;\n\n const parts = chatList.parentElement.parentElement;\n const bottom = chatList.parentElement.nextElementSibling as HTMLElement;\n const hasContacts = !!bottom.childElementCount;\n if(count >= 10) {\n if(hasContacts) {\n this.removeContactsPlaceholder();\n }\n\n return;\n } else if(hasContacts) return;\n\n parts.classList.add('with-contacts');\n\n const section = new SettingSection({\n name: 'Contacts',\n noDelimiter: true,\n fakeGradientDelimiter: true\n });\n\n section.container.classList.add('hide');\n\n appUsersManager.getContactsPeerIds(undefined, undefined, 'online').then(contacts => {\n let ready = false;\n const onListLengthChange = () => {\n if(ready) {\n section.container.classList.toggle('hide', !sortedUserList.list.childElementCount);\n }\n\n this.updateContactsLength(true);\n };\n\n const sortedUserList = new SortedUserList({\n avatarSize: 42, \n createChatListOptions: {\n dialogSize: 48,\n new: true\n },\n autonomous: false, \n onListLengthChange\n });\n\n this.loadContacts = () => {\n const pageCount = windowSize.height / 60 | 0;\n const arr = contacts.splice(0, pageCount).filter(this.verifyPeerIdForContacts);\n\n arr.forEach((peerId) => {\n sortedUserList.add(peerId);\n });\n\n if(!contacts.length) {\n this.loadContacts = undefined;\n }\n };\n\n this.loadContacts();\n\n this.processContact = (peerId) => {\n if(peerId.isAnyChat()) {\n return;\n }\n\n const good = this.verifyPeerIdForContacts(peerId);\n const added = sortedUserList.has(peerId);\n if(!added && good) sortedUserList.add(peerId);\n else if(added && !good) sortedUserList.delete(peerId);\n };\n\n const list = sortedUserList.list;\n list.classList.add('chatlist-new');\n this.setListClickListener(list);\n section.content.append(list);\n\n ready = true;\n onListLengthChange();\n });\n\n bottom.append(section.container);\n };\n\n private verifyPeerIdForContacts = (peerId: PeerId) => {\n return peerId.isContact() && !appMessagesManager.getDialogOnly(peerId);\n };\n\n public onChatsRegularScroll = () => {\n // return;\n\n if(this.sliceTimeout) clearTimeout(this.sliceTimeout);\n this.sliceTimeout = window.setTimeout(() => {\n this.sliceTimeout = undefined;\n\n if(!this.chatList.childElementCount || this.processContact) {\n return;\n }\n\n /* const observer = new IntersectionObserver((entries) => {\n const \n });\n\n Array.from(this.chatList.children).forEach(el => {\n observer.observe(el);\n }); */\n\n fastRafConventional(() => {\n\n const perf = performance.now();\n\n const scrollTopWas = this.scroll.scrollTop;\n\n const firstElementChild = this.chatList.firstElementChild;\n const rectContainer = this.scroll.container.getBoundingClientRect();\n const rectTarget = firstElementChild.getBoundingClientRect();\n const children = Array.from(this.scroll.splitUp.children) as HTMLElement[];\n\n // const padding = 8;\n // const offsetTop = this.folders.container.offsetTop;\n let offsetTop = this.scroll.splitUp.offsetTop;\n if(offsetTop && scrollTopWas < offsetTop) offsetTop -= scrollTopWas;\n // const offsetTop = scrollTopWas < padding ? padding - scrollTopWas : 0;\n const firstY = rectContainer.y + offsetTop;\n const lastY = rectContainer.y/* - 8 */; // 8px - .chatlist padding-bottom\n \n const firstElement = findUpTag(document.elementFromPoint(Math.ceil(rectTarget.x), Math.ceil(firstY + 1)), firstElementChild.tagName) as HTMLElement;\n const lastElement = findUpTag(document.elementFromPoint(Math.ceil(rectTarget.x), Math.floor(lastY + rectContainer.height - 1)), firstElementChild.tagName) as HTMLElement;\n\n //alert('got element:' + rect.y);\n\n if(!firstElement || !lastElement) {\n return;\n }\n\n //alert('got element:' + !!firstElement);\n\n const firstElementRect = firstElement.getBoundingClientRect();\n const elementOverflow = firstElementRect.y - firstY;\n\n const sliced: HTMLElement[] = [];\n const firstIndex = children.indexOf(firstElement);\n const lastIndex = children.indexOf(lastElement);\n\n const saveLength = 10;\n\n const sliceFromStart = IS_SAFARI ? [] : children.slice(0, Math.max(0, firstIndex - saveLength));\n const sliceFromEnd = children.slice(lastIndex + saveLength);\n\n /* if(sliceFromStart.length !== sliceFromEnd.length) {\n console.log('not equal', sliceFromStart.length, sliceFromEnd.length);\n }\n\n if(sliceFromStart.length > sliceFromEnd.length) {\n const diff = sliceFromStart.length - sliceFromEnd.length;\n sliceFromStart.splice(0, diff);\n } else if(sliceFromEnd.length > sliceFromStart.length) {\n const diff = sliceFromEnd.length - sliceFromStart.length;\n sliceFromEnd.splice(sliceFromEnd.length - diff, diff);\n } */\n\n if(sliceFromStart.length) {\n this.scroll.loadedAll.top = false;\n }\n\n if(sliceFromEnd.length) {\n this.scroll.loadedAll.bottom = false;\n }\n\n sliced.push(...sliceFromStart);\n sliced.push(...sliceFromEnd);\n\n sliced.forEach(el => {\n const peerId = el.dataset.peerId.toPeerId();\n this.deleteDialog(peerId);\n });\n\n this.setOffsets();\n\n //this.log('[slicer] elements', firstElement, lastElement, rect, sliced, sliceFromStart.length, sliceFromEnd.length);\n\n //this.log('[slicer] reset scrollTop', this.scroll.scrollTop, firstElement.offsetTop, firstElementRect.y, rect.y, elementOverflow);\n\n //alert('left length:' + children.length);\n\n this.scroll.scrollTop = firstElement.offsetTop - elementOverflow;\n\n this.log('slice time', performance.now() - perf);\n /* const firstElementRect = firstElement.getBoundingClientRect();\n const scrollTop = */\n\n //this.scroll.scrollIntoView(firstElement, false);\n });\n }, 200);\n };\n\n private setOffsets() {\n const chatList = this.chatList;\n const firstDialog = this.getDialogFromElement(chatList.firstElementChild as HTMLElement);\n const lastDialog = this.getDialogFromElement(chatList.lastElementChild as HTMLElement);\n\n const indexKey = this.indexKey;\n this.offsets.top = firstDialog[indexKey];\n this.offsets.bottom = lastDialog[indexKey];\n }\n\n private getDialogFromElement(element: HTMLElement) {\n return appMessagesManager.getDialogOnly(element.dataset.peerId.toPeerId());\n }\n\n public onChatsScrollTop = () => {\n return this.onChatsScroll('top');\n };\n \n public onChatsScroll = (side: SliceSides = 'bottom') => {\n if(this.scroll.loadedAll[side]) {\n if(this.loadContacts) {\n this.loadContacts();\n }\n\n return Promise.resolve();\n } else if(this.loadDialogsPromise) return this.loadDialogsPromise;\n\n this.log('onChatsScroll', side);\n return this.loadDialogs(side);\n };\n\n public setListClickListener(list: HTMLUListElement, onFound?: () => void, withContext = false, autonomous = false, openInner = false) {\n let lastActiveListElement: HTMLElement;\n\n const setPeerFunc = (openInner ? appImManager.setInnerPeer : appImManager.setPeer).bind(appImManager);\n\n list.dataset.autonomous = '' + +autonomous;\n list.addEventListener('mousedown', (e) => {\n if(e.button !== 0) return;\n //cancelEvent(e);\n\n this.log('dialogs click list');\n const target = e.target as HTMLElement;\n const elem = findUpTag(target, 'LI');\n\n if(!elem) {\n return;\n }\n\n if(autonomous) {\n const sameElement = lastActiveListElement === elem;\n if(lastActiveListElement && !sameElement) {\n lastActiveListElement.classList.remove('active');\n }\n\n if(elem) {\n elem.classList.add('active');\n lastActiveListElement = elem;\n this.lastActiveElements.add(elem);\n }\n }\n\n if(elem) {\n if(onFound) onFound();\n\n const peerId = elem.dataset.peerId.toPeerId();\n const lastMsgId = +elem.dataset.mid || undefined;\n\n setPeerFunc({\n peerId, lastMsgId\n });\n } else {\n setPeerFunc();\n }\n }, {capture: true});\n\n if(DEBUG) {\n list.addEventListener('dblclick', (e) => {\n const li = findUpTag(e.target, 'LI');\n if(li) {\n const peerId = li.dataset.peerId.toPeerId();\n this.log('debug dialog:', appMessagesManager.getDialogByPeerId(peerId));\n }\n });\n }\n\n if(withContext) {\n attachContextMenuListener(list, this.contextMenu.onContextMenu);\n }\n }\n\n public createChatList(options: {\n // avatarSize?: number,\n // handheldsSize?: number,\n // size?: number,\n new?: boolean,\n dialogSize?: number\n } = {}) {\n const list = document.createElement('ul');\n list.classList.add('chatlist'/* , \n 'chatlist-avatar-' + (options.avatarSize || 54) *//* , 'chatlist-' + (options.size || 72) */);\n\n if(options.new) {\n list.classList.add('chatlist-new');\n }\n\n if(options.dialogSize) {\n list.classList.add('chatlist-' + options.dialogSize);\n }\n\n /* if(options.handheldsSize) {\n list.classList.add('chatlist-handhelds-' + options.handheldsSize);\n } */\n\n return list;\n }\n\n public setLastMessage(\n dialog: Dialog, \n lastMessage?: any, \n dom?: DialogDom, \n highlightWord?: string, \n loadPromises?: Promise<any>[],\n isBatch = false,\n setUnread = false\n ) {\n ///////console.log('setlastMessage:', lastMessage);\n if(!dom) {\n dom = this.getDialogDom(dialog.peerId);\n\n if(!dom) {\n //this.log.error('no dom for dialog:', dialog, lastMessage, dom, highlightWord);\n return;\n }\n }\n\n let draftMessage: MyDraftMessage;\n if(!lastMessage) {\n if(dialog.draft && dialog.draft._ === 'draftMessage') {\n draftMessage = dialog.draft;\n }\n \n lastMessage = appMessagesManager.getMessageByPeer(dialog.peerId, dialog.top_message);\n }\n\n if(lastMessage._ === 'messageEmpty'/* || (lastMessage._ === 'messageService' && !lastMessage.rReply) */) {\n dom.lastMessageSpan.innerHTML = '';\n dom.lastTimeSpan.innerHTML = '';\n delete dom.listEl.dataset.mid;\n\n if(setUnread) {\n this.setUnreadMessages(dialog, dom, isBatch);\n }\n\n return;\n }\n\n const peerId = dialog.peerId;\n const isRestricted = lastMessage && appMessagesManager.isRestricted(lastMessage);\n //let peerId = appMessagesManager.getMessagePeer(lastMessage);\n\n //console.log('setting last message:', lastMessage);\n\n /* if(!dom.lastMessageSpan.classList.contains('user-typing')) */ {\n\n let mediaContainer: HTMLElement;\n if(!lastMessage.deleted && !draftMessage && !isRestricted) {\n const media: MyDocument | MyPhoto = appMessagesManager.getMediaFromMessage(lastMessage);\n const videoTypes: Set<MyDocument['type']> = new Set(['video', 'gif', 'round']);\n if(media && (media._ === 'photo' || videoTypes.has(media.type))) {\n const size = appPhotosManager.choosePhotoSize(media, 20, 20);\n\n if(size._ !== 'photoSizeEmpty') {\n mediaContainer = document.createElement('div');\n mediaContainer.classList.add('dialog-subtitle-media');\n\n if((media as MyDocument).type === 'round') {\n mediaContainer.classList.add('is-round');\n }\n \n wrapPhoto({\n photo: media,\n message: lastMessage,\n container: mediaContainer,\n withoutPreloader: true,\n size,\n loadPromises\n });\n\n if(videoTypes.has((media as MyDocument).type)) {\n const playIcon = document.createElement('span');\n playIcon.classList.add('tgico-play');\n\n mediaContainer.append(playIcon);\n }\n }\n }\n }\n\n const withoutMediaType = !!mediaContainer && !!lastMessage?.message;\n\n let fragment: DocumentFragment;\n if(highlightWord && lastMessage.message) {\n fragment = appMessagesManager.wrapMessageForReply(lastMessage, undefined, undefined, false, highlightWord, withoutMediaType);\n } else if(draftMessage) {\n fragment = appMessagesManager.wrapMessageForReply(draftMessage);\n } else if(!lastMessage.deleted) {\n fragment = appMessagesManager.wrapMessageForReply(lastMessage, undefined, undefined, false, undefined, withoutMediaType);\n } else { // rare case\n fragment = document.createDocumentFragment();\n }\n\n if(mediaContainer) {\n fragment.prepend(mediaContainer);\n }\n\n replaceContent(dom.lastMessageSpan, fragment);\n \n /* if(lastMessage.from_id === auth.id) { // You: */\n if(draftMessage) {\n const bold = document.createElement('b');\n bold.classList.add('danger');\n bold.append(i18n('Draft'), ': ');\n dom.lastMessageSpan.prepend(bold);\n } else if(peerId.isAnyChat() && peerId !== lastMessage.fromId && !lastMessage.action) {\n const sender = appPeersManager.getPeer(lastMessage.fromId);\n if(sender && sender.id) {\n const senderBold = document.createElement('b');\n\n if(sender.id === rootScope.myId) {\n senderBold.append(i18n('FromYou'));\n } else {\n //str = sender.first_name || sender.last_name || sender.username;\n senderBold.append(new PeerTitle({\n peerId: lastMessage.fromId,\n onlyFirstName: true,\n }).element);\n }\n\n senderBold.append(': ');\n //console.log(sender, senderBold.innerText);\n dom.lastMessageSpan.prepend(senderBold);\n } //////// else console.log('no sender', lastMessage, peerId);\n }\n }\n\n if(!lastMessage.deleted || draftMessage/* && lastMessage._ !== 'draftMessage' */) {\n const date = draftMessage ? Math.max(draftMessage.date, lastMessage.date || 0) : lastMessage.date;\n replaceContent(dom.lastTimeSpan, formatDateAccordingToTodayNew(new Date(date * 1000)));\n } else dom.lastTimeSpan.textContent = '';\n\n if(setUnread !== null) {\n if(setUnread) {\n this.setUnreadMessages(dialog, dom, isBatch);\n } else { // means search\n dom.listEl.dataset.mid = lastMessage.mid;\n }\n }\n }\n\n private setUnreadMessages(dialog: Dialog, dom = this.getDialogDom(dialog.peerId), isBatch = false) {\n if(!dom) {\n //this.log.error('setUnreadMessages no dom!', dialog);\n return;\n }\n\n if(!isBatch) {\n const isMuted = appNotificationsManager.isPeerLocalMuted(dialog.peerId, true);\n const wasMuted = dom.listEl.classList.contains('is-muted');\n if(isMuted !== wasMuted) {\n SetTransition(dom.listEl, 'is-muted', isMuted, 200);\n }\n }\n\n let setStatusMessage: MyMessage;\n if(dialog.draft?._ !== 'draftMessage') {\n const lastMessage: MyMessage = appMessagesManager.getMessageByPeer(dialog.peerId, dialog.top_message);\n if(!lastMessage.deleted && lastMessage.pFlags.out && lastMessage.peerId !== rootScope.myId) {\n setStatusMessage = lastMessage;\n }\n }\n\n setSendingStatus(dom.statusSpan, setStatusMessage, true);\n\n const filter = appMessagesManager.filtersStorage.getFilter(this.filterId);\n let isPinned: boolean;\n if(filter) {\n isPinned = filter.pinnedPeerIds.indexOf(dialog.peerId) !== -1;\n } else {\n isPinned = !!dialog.pFlags.pinned;\n }\n\n const isDialogUnread = appMessagesManager.isDialogUnread(dialog);\n const hasUnreadBadge = isPinned || isDialogUnread;\n // dom.messageEl.classList.toggle('has-badge', hasBadge);\n\n const isUnreadBadgeMounted = isInDOM(dom.unreadBadge);\n if(hasUnreadBadge && !isUnreadBadgeMounted) {\n dom.subtitleEl.append(dom.unreadBadge);\n }\n\n const hasMentionsBadge = dialog.unread_mentions_count && (dialog.unread_mentions_count > 1 || dialog.unread_count > 1);\n const isMentionBadgeMounted = dom.mentionsBadge && isInDOM(dom.mentionsBadge);\n if(hasMentionsBadge) {\n if(!dom.mentionsBadge) {\n dom.mentionsBadge = document.createElement('div');\n dom.mentionsBadge.className = 'dialog-subtitle-badge badge badge-24 mention mention-badge';\n dom.mentionsBadge.innerText = '@';\n dom.subtitleEl.insertBefore(dom.mentionsBadge, dom.lastMessageSpan.nextSibling);\n }\n }\n\n const transitionDuration = isBatch ? 0 : 200;\n\n SetTransition(dom.unreadBadge, 'is-visible', hasUnreadBadge, transitionDuration, hasUnreadBadge ? undefined : () => {\n dom.unreadBadge.remove();\n }, !isUnreadBadgeMounted ? 2 : 0);\n\n if(dom.mentionsBadge) {\n SetTransition(dom.mentionsBadge, 'is-visible', hasMentionsBadge, transitionDuration, hasMentionsBadge ? undefined : () => {\n dom.mentionsBadge.remove();\n delete dom.mentionsBadge;\n }, !isMentionBadgeMounted ? 2 : 0);\n }\n\n if(!hasUnreadBadge) {\n return;\n }\n\n if(isPinned) {\n dom.unreadBadge.classList.add('tgico-chatspinned', 'tgico');\n } else {\n dom.unreadBadge.classList.remove('tgico-chatspinned', 'tgico');\n }\n\n let isUnread = true, isMention = false;\n if(dialog.unread_mentions_count && dialog.unread_count === 1) {\n dom.unreadBadge.innerText = '@';\n isMention = true;\n // dom.unreadBadge.classList.add('tgico-mention', 'tgico');\n } else if(isDialogUnread) {\n //dom.unreadMessagesSpan.innerText = '' + (dialog.unread_count ? formatNumber(dialog.unread_count, 1) : ' ');\n dom.unreadBadge.innerText = '' + (dialog.unread_count || ' ');\n } else {\n dom.unreadBadge.innerText = '';\n isUnread = false;\n }\n\n dom.unreadBadge.classList.toggle('unread', isUnread);\n dom.unreadBadge.classList.toggle('mention', isMention);\n }\n\n private getDialogDom(peerId: PeerId) {\n // return this.doms[peerId];\n const element = this.sortedList.get(peerId);\n return element?.dom;\n }\n\n private getDialog(dialog: Dialog | PeerId): Dialog {\n if(typeof(dialog) !== 'object') {\n const originalDialog = appMessagesManager.getDialogOnly(dialog);\n if(!originalDialog) {\n const peerId = dialog || NULL_PEER_ID;\n return {\n peerId,\n peer: appPeersManager.getOutputPeer(peerId),\n pFlags: {}\n } as any;\n }\n\n return originalDialog;\n }\n \n return dialog as Dialog;\n }\n\n private setCallStatus(dom: DialogDom, visible: boolean) {\n let {callIcon, listEl} = dom;\n if(!callIcon && visible) {\n const {canvas, startAnimation} = dom.callIcon = callIcon = groupCallActiveIcon(listEl.classList.contains('active'));\n canvas.classList.add('dialog-group-call-icon');\n listEl.append(canvas);\n startAnimation();\n }\n\n if(!callIcon) {\n return;\n }\n\n SetTransition(dom.callIcon.canvas, 'is-visible', visible, 200, visible ? undefined : () => {\n dom.callIcon.canvas.remove();\n dom.callIcon = undefined;\n }, visible ? 2 : 0);\n }\n\n public addListDialog(options: Parameters<AppDialogsManager['addDialogNew']>[0] & {isBatch?: boolean}) {\n const dialog = this.getDialog(options.dialog);\n\n options.autonomous = false;\n\n const ret = this.addDialogNew(options);\n\n if(ret) {\n const {peerId} = dialog;\n const isMuted = appNotificationsManager.isPeerLocalMuted(peerId, true);\n if(isMuted) {\n ret.dom.listEl.classList.add('is-muted');\n }\n\n if(!peerId.isUser()) {\n this.processDialogForCallStatus(dialog, ret.dom);\n }\n\n this.setLastMessage(dialog, undefined, ret.dom, undefined, options.loadPromises, options.isBatch, true);\n }\n\n return ret;\n }\n\n private processDialogForCallStatus(dialog: Dialog, dom?: DialogDom) {\n if(!IS_GROUP_CALL_SUPPORTED) {\n return;\n }\n\n if(!dom) dom = this.getDialogDom(dialog.peerId);\n if(!dom) return;\n \n const chat: Chat.chat | Chat.channel = appChatsManager.getChat(dialog.peerId.toChatId());\n this.setCallStatus(dom, !!(chat.pFlags.call_active && chat.pFlags.call_not_empty));\n }\n\n /**\n * use for rendering search result\n */\n public addDialogAndSetLastMessage(options: Omit<Parameters<AppDialogsManager['addDialogNew']>[0], 'dialog'> & {\n message: MyMessage, \n peerId: PeerId,\n query?: string\n }) {\n const {peerId, message, query} = options;\n const ret = appDialogsManager.addDialogNew({\n ...options,\n ...appMessagesManager.getMessageSenderPeerIdOrName(message),\n dialog: this.getDialog(peerId),\n });\n\n this.setLastMessage(ret.dialog, message, ret.dom, query);\n\n if(message.peerId !== peerId) {\n ret.dom.listEl.dataset.peerId = '' + message.peerId;\n }\n\n return ret;\n }\n\n public addDialogNew(options: {\n dialog: Parameters<AppDialogsManager['addDialog']>[0],\n container?: Parameters<AppDialogsManager['addDialog']>[1],\n drawStatus?: boolean,\n rippleEnabled?: boolean,\n onlyFirstName?: boolean,\n meAsSaved?: boolean,\n append?: boolean,\n avatarSize?: number,\n autonomous?: boolean,\n lazyLoadQueue?: LazyLoadQueueIntersector,\n loadPromises?: Promise<any>[],\n fromName?: string\n }) {\n return this.addDialog(options.dialog, options.container, options.drawStatus, options.rippleEnabled, options.onlyFirstName, options.meAsSaved, options.append, options.avatarSize, options.autonomous, options.lazyLoadQueue, options.loadPromises, options.fromName);\n }\n\n public addDialog(\n _dialog: Parameters<AppDialogsManager['getDialog']>[0], \n container?: HTMLElement | Scrollable | DocumentFragment | false, \n drawStatus = true, \n rippleEnabled = true, \n onlyFirstName = false, \n meAsSaved = true, \n append = true, \n avatarSize = 54, \n autonomous = !!container, \n lazyLoadQueue?: LazyLoadQueueIntersector,\n loadPromises?: Promise<any>[],\n fromName?: string\n ) {\n const dialog = this.getDialog(_dialog);\n const peerId = dialog.peerId;\n\n const avatarEl = new AvatarElement();\n avatarEl.classList.add('dialog-avatar', 'avatar-' + avatarSize);\n avatarEl.updateWithOptions({\n loadPromises,\n lazyLoadQueue,\n isDialog: !!meAsSaved,\n peerId,\n peerTitle: fromName\n });\n\n if(drawStatus && peerId !== rootScope.myId && peerId.isUser()) {\n const user = appUsersManager.getUser(peerId);\n if(user.status?._ === 'userStatusOnline') {\n this.setOnlineStatus(avatarEl, true);\n }\n }\n\n const captionDiv = document.createElement('div');\n captionDiv.classList.add('user-caption');\n\n const titleSpanContainer = document.createElement('span');\n titleSpanContainer.classList.add('user-title');\n\n const peerTitle = new PeerTitle({\n peerId,\n fromName,\n dialog: meAsSaved,\n onlyFirstName,\n plainText: false\n });\n\n titleSpanContainer.append(peerTitle.element);\n //p.classList.add('')\n\n // в других случаях иконка верификации не нужна (а первый - это главные чатлисты)\n //if(!container) {\n \n // for muted icon\n titleSpanContainer.classList.add('tgico'); // * эта строка будет актуальна только для !container, но ладно\n \n titleSpanContainer.append(...generateTitleIcons(peerId));\n //}\n \n const span = document.createElement('span');\n span.classList.add('user-last-message');\n span.setAttribute('dir', 'auto');\n\n //captionDiv.append(titleSpan);\n //captionDiv.append(span);\n\n const li = document.createElement('li');\n li.classList.add('chatlist-chat');\n if(rippleEnabled) {\n ripple(li);\n }\n\n li.append(avatarEl, captionDiv);\n li.dataset.peerId = '' + peerId;\n\n const statusSpan = document.createElement('span');\n statusSpan.classList.add('message-status', 'sending-status'/* , 'transition', 'reveal' */);\n\n const lastTimeSpan = document.createElement('span');\n lastTimeSpan.classList.add('message-time');\n\n const unreadBadge = document.createElement('div');\n unreadBadge.className = 'dialog-subtitle-badge badge badge-24';\n\n const titleP = document.createElement('p');\n titleP.classList.add('dialog-title');\n\n const rightSpan = document.createElement('span');\n rightSpan.classList.add('dialog-title-details');\n rightSpan.append(statusSpan, lastTimeSpan);\n titleP.append(titleSpanContainer, rightSpan);\n\n const subtitleEl = document.createElement('p');\n subtitleEl.classList.add('dialog-subtitle');\n subtitleEl.append(span);\n\n captionDiv.append(titleP, subtitleEl);\n\n const dom: DialogDom = {\n avatarEl,\n captionDiv,\n titleSpan: peerTitle.element,\n titleSpanContainer,\n statusSpan,\n lastTimeSpan,\n unreadBadge,\n lastMessageSpan: span,\n containerEl: li,\n listEl: li,\n subtitleEl\n };\n\n /* let good = false;\n for(const folderId in this.chatLists) {\n if(this.chatLists[folderId] === container) {\n good = true;\n }\n } */\n if(container) {\n const method = append ? 'append' : 'prepend';\n container[method](li);\n }\n\n if(!autonomous) {\n // @ts-ignore\n li.dialogDom = dom;\n\n if(appImManager.chat?.peerId === peerId) {\n this.setDialogActive(li, true);\n }\n } \n \n return {dom, dialog};\n }\n\n public setTyping(dialog: Dialog) {\n const dom = this.getDialogDom(dialog.peerId);\n if(!dom) {\n return;\n }\n\n const oldTypingElement = dom.lastMessageSpan.querySelector('.peer-typing-container') as HTMLElement;\n const newTypingElement = appImManager.getPeerTyping(dialog.peerId, oldTypingElement);\n if(!oldTypingElement && newTypingElement) {\n replaceContent(dom.lastMessageSpan, newTypingElement);\n dom.lastMessageSpan.classList.add('user-typing');\n }\n }\n\n public unsetTyping(dialog: Dialog) {\n const dom = this.getDialogDom(dialog.peerId);\n if(!dom) {\n return;\n }\n\n dom.lastMessageSpan.classList.remove('user-typing');\n this.setLastMessage(dialog, null, dom, undefined, undefined, undefined, null);\n }\n}\n\nconst appDialogsManager = new AppDialogsManager();\nMOUNT_CLASS_TO.appDialogsManager = appDialogsManager;\nexport default appDialogsManager;\n","!function(e,t){\"object\"==typeof exports&&\"object\"==typeof module?module.exports=t():\"function\"==typeof define&&define.amd?define([],t):\"object\"==typeof exports?exports.Recorder=t():e.Recorder=t()}(\"undefined\"!=typeof self?self:this,(function(){return function(e){var t={};function o(i){if(t[i])return t[i].exports;var n=t[i]={i:i,l:!1,exports:{}};return e[i].call(n.exports,n,n.exports,o),n.l=!0,n.exports}return o.m=e,o.c=t,o.d=function(e,t,i){o.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},o.r=function(e){\"undefined\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\"Module\"}),Object.defineProperty(e,\"__esModule\",{value:!0})},o.t=function(e,t){if(1&t&&(e=o(e)),8&t)return e;if(4&t&&\"object\"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(o.r(i),Object.defineProperty(i,\"default\",{enumerable:!0,value:e}),2&t&&\"string\"!=typeof e)for(var n in e)o.d(i,n,function(t){return e[t]}.bind(null,n));return i},o.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(t,\"a\",t),t},o.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},o.p=\"\",o(o.s=0)}([function(e,t,o){\"use strict\";(function(t){var o=t.AudioContext||t.webkitAudioContext,i=function(e){if(!i.isRecordingSupported())throw new Error(\"Recording is not supported in this browser\");e||(e={}),this.state=\"inactive\",this.config=Object.assign({bufferLength:4096,encoderApplication:2049,encoderFrameSize:20,encoderPath:\"encoderWorker.min.js\",encoderSampleRate:48e3,maxFramesPerPage:40,mediaTrackConstraints:!0,monitorGain:0,numberOfChannels:1,recordingGain:1,resampleQuality:3,streamPages:!1,reuseWorker:!1,wavBitDepth:16},e),this.encodedSamplePosition=0};i.isRecordingSupported=function(){return o&&t.navigator&&t.navigator.mediaDevices&&t.navigator.mediaDevices.getUserMedia&&t.WebAssembly},i.prototype.clearStream=function(){this.stream&&(this.stream.getTracks?this.stream.getTracks().forEach((function(e){e.stop()})):this.stream.stop(),delete this.stream),this.audioContext&&this.closeAudioContext&&(this.audioContext.close(),delete this.audioContext)},i.prototype.encodeBuffers=function(e){if(\"recording\"===this.state){for(var t=[],o=0;o<e.numberOfChannels;o++)t[o]=e.getChannelData(o);this.encoder.postMessage({command:\"encode\",buffers:t})}},i.prototype.initAudioContext=function(e){return e&&e.context?(this.audioContext=e.context,this.closeAudioContext=!1):(this.audioContext=new o,this.closeAudioContext=!0),this.audioContext},i.prototype.initAudioGraph=function(){this.encodeBuffers=function(){delete this.encodeBuffers},this.scriptProcessorNode=this.audioContext.createScriptProcessor(this.config.bufferLength,this.config.numberOfChannels,this.config.numberOfChannels),this.scriptProcessorNode.connect(this.audioContext.destination),this.scriptProcessorNode.onaudioprocess=e=>{this.encodeBuffers(e.inputBuffer)},this.monitorGainNode=this.audioContext.createGain(),this.setMonitorGain(this.config.monitorGain),this.monitorGainNode.connect(this.audioContext.destination),this.recordingGainNode=this.audioContext.createGain(),this.setRecordingGain(this.config.recordingGain),this.recordingGainNode.connect(this.scriptProcessorNode)},i.prototype.initSourceNode=function(e){return e&&e.context?t.Promise.resolve(e):t.navigator.mediaDevices.getUserMedia({audio:this.config.mediaTrackConstraints}).then(e=>(this.stream=e,this.audioContext.createMediaStreamSource(e)))},i.prototype.loadWorker=function(){this.encoder||(this.encoder=new t.Worker(this.config.encoderPath))},i.prototype.initWorker=function(){var e=(this.config.streamPages?this.streamPage:this.storePage).bind(this);return this.recordedPages=[],this.totalLength=0,this.loadWorker(),new Promise((t,o)=>{var i=o=>{switch(o.data.message){case\"ready\":t();break;case\"page\":this.encodedSamplePosition=o.data.samplePosition,e(o.data.page);break;case\"done\":this.encoder.removeEventListener(\"message\",i),this.finish()}};this.encoder.addEventListener(\"message\",i),this.encoder.postMessage(Object.assign({command:\"init\",originalSampleRate:this.audioContext.sampleRate,wavSampleRate:this.audioContext.sampleRate},this.config))})},i.prototype.pause=function(e){if(\"recording\"===this.state){if(this.state=\"paused\",e&&this.config.streamPages){var t=this.encoder;return new Promise((e,o)=>{var i=o=>{\"flushed\"===o.data.message&&(t.removeEventListener(\"message\",i),this.onpause(),e())};t.addEventListener(\"message\",i),t.postMessage({command:\"flush\"})})}return this.onpause(),Promise.resolve()}},i.prototype.resume=function(){\"paused\"===this.state&&(this.state=\"recording\",this.onresume())},i.prototype.setRecordingGain=function(e){this.config.recordingGain=e,this.recordingGainNode&&this.audioContext&&this.recordingGainNode.gain.setTargetAtTime(e,this.audioContext.currentTime,.01)},i.prototype.setMonitorGain=function(e){this.config.monitorGain=e,this.monitorGainNode&&this.audioContext&&this.monitorGainNode.gain.setTargetAtTime(e,this.audioContext.currentTime,.01)},i.prototype.start=function(e){if(\"inactive\"===this.state)return this.initAudioContext(e),this.initAudioGraph(),this.encodedSamplePosition=0,this.initWorker().then(()=>this.initSourceNode(e)).then(e=>{this.sourceNode=e,this.state=\"recording\",this.onstart(),this.encoder.postMessage({command:\"getHeaderPages\"}),this.sourceNode.connect(this.monitorGainNode),this.sourceNode.connect(this.recordingGainNode)})},i.prototype.stop=function(){if(\"inactive\"!==this.state){this.state=\"inactive\",this.monitorGainNode.disconnect(),this.scriptProcessorNode.disconnect(),this.recordingGainNode.disconnect(),this.sourceNode.disconnect(),this.clearStream();var e=this.encoder;return new Promise(t=>{var o=i=>{\"done\"===i.data.message&&(e.removeEventListener(\"message\",o),t())};e.addEventListener(\"message\",o),e.postMessage({command:\"done\"}),this.config.reuseWorker||e.postMessage({command:\"close\"})})}return Promise.resolve()},i.prototype.destroyWorker=function(){\"inactive\"===this.state&&this.encoder&&(this.encoder.postMessage({command:\"close\"}),delete this.encoder)},i.prototype.storePage=function(e){this.recordedPages.push(e),this.totalLength+=e.length},i.prototype.streamPage=function(e){this.ondataavailable(e)},i.prototype.finish=function(){if(!this.config.streamPages){var e=new Uint8Array(this.totalLength);this.recordedPages.reduce((function(t,o){return e.set(o,t),t+o.length}),0),this.ondataavailable(e)}this.onstop(),this.config.reuseWorker||delete this.encoder},i.prototype.ondataavailable=function(){},i.prototype.onpause=function(){},i.prototype.onresume=function(){},i.prototype.onstart=function(){},i.prototype.onstop=function(){},e.exports=i}).call(this,o(1))},function(e,t){var o;o=function(){return this}();try{o=o||new Function(\"return this\")()}catch(e){\"object\"==typeof window&&(o=window)}e.exports=o}])}));","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { IS_TOUCH_SUPPORTED } from \"../environment/touchSupport\";\r\nimport { logger, LogTypes } from \"../lib/logger\";\r\nimport fastSmoothScroll, { ScrollOptions } from \"../helpers/fastSmoothScroll\";\r\nimport useHeavyAnimationCheck from \"../hooks/useHeavyAnimationCheck\";\r\nimport cancelEvent from \"../helpers/dom/cancelEvent\";\r\n/*\r\nvar el = $0;\r\nvar height = 0;\r\nvar checkUp = false;\r\n\r\ndo {\r\n height += el.scrollHeight;\r\n} while(el = (checkUp ? el.previousElementSibling : el.nextElementSibling));\r\nconsole.log(height);\r\n*/\r\n\r\n/*\r\nArray.from($0.querySelectorAll('.bubble-content')).forEach(_el => {\r\n\t//_el.style.display = '';\t\r\n\t//return;\r\n\r\n\tlet el = _el.parentElement;\r\n\tlet height = el.scrollHeight;\r\n\tlet width = el.scrollWidth;\r\n\tel.style.width = width + 'px';\r\n\tel.style.height = height + 'px';\r\n\t_el.style.display = 'none';\r\n});\r\n*/\r\n\r\n/* const scrollables: Map<HTMLElement, Scrollable> = new Map();\r\nconst scrollsIntersector = new IntersectionObserver(entries => {\r\n for(let entry of entries) {\r\n const scrollable = scrollables.get(entry.target as HTMLElement);\r\n\r\n if(entry.isIntersecting) {\r\n scrollable.isVisible = true;\r\n } else {\r\n scrollable.isVisible = false;\r\n\r\n if(!isInDOM(entry.target)) {\r\n scrollsIntersector.unobserve(scrollable.container);\r\n scrollables.delete(scrollable.container);\r\n }\r\n }\r\n }\r\n}); */\r\n\r\nexport class ScrollableBase {\r\n protected log: ReturnType<typeof logger>;\r\n\r\n public splitUp: HTMLElement;\r\n public onScrollMeasure: number = 0;\r\n\r\n public lastScrollPosition: number = 0;\r\n public lastScrollDirection: number = 0;\r\n\r\n public onAdditionalScroll: () => void;\r\n public onScrolledTop: () => void;\r\n public onScrolledBottom: () => void;\r\n\r\n public isHeavyAnimationInProgress = false;\r\n protected needCheckAfterAnimation = false;\r\n\r\n public checkForTriggers?: () => void;\r\n\r\n public scrollProperty: 'scrollTop' | 'scrollLeft';\r\n \r\n protected removeHeavyAnimationListener: () => void;\r\n protected addedScrollListener: boolean;\r\n\r\n constructor(public el: HTMLElement, logPrefix = '', public container: HTMLElement = document.createElement('div')) {\r\n this.container.classList.add('scrollable');\r\n\r\n this.log = logger('SCROLL' + (logPrefix ? '-' + logPrefix : ''), LogTypes.Error);\r\n\r\n if(el) {\r\n Array.from(el.children).forEach(c => this.container.append(c));\r\n\r\n el.append(this.container);\r\n }\r\n //this.onScroll();\r\n }\r\n\r\n public addScrollListener() {\r\n if(this.addedScrollListener) {\r\n return;\r\n }\r\n\r\n this.addedScrollListener = true;\r\n this.container.addEventListener('scroll', this.onScroll, {passive: true, capture: true});\r\n }\r\n \r\n public removeScrollListener() {\r\n if(!this.addedScrollListener) {\r\n return;\r\n }\r\n\r\n this.addedScrollListener = false;\r\n this.container.removeEventListener('scroll', this.onScroll, {capture: true});\r\n }\r\n\r\n public setListeners() {\r\n if(this.removeHeavyAnimationListener) {\r\n return;\r\n }\r\n\r\n window.addEventListener('resize', this.onScroll, {passive: true});\r\n this.addScrollListener();\r\n\r\n this.removeHeavyAnimationListener = useHeavyAnimationCheck(() => {\r\n this.isHeavyAnimationInProgress = true;\r\n\r\n if(this.onScrollMeasure) {\r\n this.cancelMeasure();\r\n this.needCheckAfterAnimation = true;\r\n }\r\n }, () => {\r\n this.isHeavyAnimationInProgress = false;\r\n\r\n if(this.needCheckAfterAnimation) {\r\n this.onScroll();\r\n this.needCheckAfterAnimation = false;\r\n }\r\n });\r\n }\r\n\r\n public removeListeners() {\r\n if(!this.removeHeavyAnimationListener) {\r\n return;\r\n }\r\n\r\n window.removeEventListener('resize', this.onScroll);\r\n this.removeScrollListener();\r\n\r\n this.removeHeavyAnimationListener();\r\n this.removeHeavyAnimationListener = undefined;\r\n }\r\n\r\n public append(element: HTMLElement) {\r\n this.container.append(element);\r\n }\r\n\r\n public scrollIntoViewNew(options: Omit<ScrollOptions, 'container'>) {\r\n //return Promise.resolve();\r\n return fastSmoothScroll({\r\n ...options,\r\n container: this.container\r\n });\r\n }\r\n\r\n public onScroll = () => {\r\n //if(this.debug) {\r\n //this.log('onScroll call', this.onScrollMeasure);\r\n //}\r\n\r\n //return;\r\n\r\n if(this.isHeavyAnimationInProgress) {\r\n this.cancelMeasure();\r\n this.needCheckAfterAnimation = true;\r\n return;\r\n }\r\n\r\n //if(this.onScrollMeasure || ((this.scrollLocked || (!this.onScrolledTop && !this.onScrolledBottom)) && !this.splitUp && !this.onAdditionalScroll)) return;\r\n if((!this.onScrolledTop && !this.onScrolledBottom) && !this.splitUp && !this.onAdditionalScroll) return;\r\n if(this.onScrollMeasure) return;\r\n // if(this.onScrollMeasure) window.cancelAnimationFrame(this.onScrollMeasure);\r\n this.onScrollMeasure = window.requestAnimationFrame(() => {\r\n this.onScrollMeasure = 0;\r\n\r\n const scrollPosition = this.container[this.scrollProperty];\r\n this.lastScrollDirection = this.lastScrollPosition === scrollPosition ? 0 : (this.lastScrollPosition < scrollPosition ? 1 : -1); // * 1 - bottom, -1 - top\r\n this.lastScrollPosition = scrollPosition;\r\n\r\n // lastScrollDirection check is useless here, every callback should decide on its own\r\n if(this.onAdditionalScroll/* && this.lastScrollDirection !== 0 */) {\r\n this.onAdditionalScroll();\r\n }\r\n \r\n if(this.checkForTriggers) {\r\n this.checkForTriggers();\r\n }\r\n });\r\n };\r\n\r\n public cancelMeasure() {\r\n if(this.onScrollMeasure) {\r\n window.cancelAnimationFrame(this.onScrollMeasure);\r\n this.onScrollMeasure = 0;\r\n }\r\n }\r\n}\r\n\r\nexport type SliceSides = 'top' | 'bottom';\r\nexport type SliceSidesContainer = {[k in SliceSides]: boolean};\r\n\r\nexport default class Scrollable extends ScrollableBase {\r\n public padding: HTMLElement;\r\n \r\n public loadedAll: SliceSidesContainer = {top: true, bottom: false};\r\n\r\n constructor(el: HTMLElement, logPrefix = '', public onScrollOffset = 300, withPaddingContainer?: boolean) {\r\n super(el, logPrefix);\r\n\r\n /* if(withPaddingContainer) {\r\n this.padding = document.createElement('div');\r\n this.padding.classList.add('scrollable-padding');\r\n Array.from(this.container.children).forEach(c => this.padding.append(c));\r\n this.container.append(this.padding);\r\n } */\r\n\r\n this.container.classList.add('scrollable-y');\r\n this.setListeners();\r\n this.scrollProperty = 'scrollTop';\r\n }\r\n\r\n public setVirtualContainer(el?: HTMLElement) {\r\n this.splitUp = el;\r\n this.log('setVirtualContainer:', el, this);\r\n }\r\n\r\n public checkForTriggers = () => {\r\n if((!this.onScrolledTop && !this.onScrolledBottom)) return;\r\n\r\n if(this.isHeavyAnimationInProgress) {\r\n this.onScroll();\r\n return;\r\n }\r\n\r\n const scrollHeight = this.container.scrollHeight;\r\n if(!scrollHeight) { // незачем вызывать триггеры если блок пустой или не виден\r\n return;\r\n }\r\n\r\n const clientHeight = this.container.clientHeight;\r\n const maxScrollTop = scrollHeight - clientHeight;\r\n const scrollTop = this.lastScrollPosition;\r\n\r\n //this.log('checkForTriggers:', scrollTop, maxScrollTop);\r\n\r\n if(this.onScrolledTop && scrollTop <= this.onScrollOffset && this.lastScrollDirection <= 0/* && direction === -1 */) {\r\n this.onScrolledTop();\r\n }\r\n\r\n if(this.onScrolledBottom && (maxScrollTop - scrollTop) <= this.onScrollOffset && this.lastScrollDirection >= 0/* && direction === 1 */) {\r\n this.onScrolledBottom();\r\n }\r\n };\r\n\r\n public prepend(...elements: (HTMLElement | DocumentFragment)[]) {\r\n (this.splitUp || this.padding || this.container).prepend(...elements);\r\n }\r\n\r\n public append(...elements: (HTMLElement | DocumentFragment)[]) {\r\n (this.splitUp || this.padding || this.container).append(...elements);\r\n }\r\n\r\n public getDistanceToEnd() {\r\n return this.scrollHeight - Math.round(this.scrollTop + this.container.offsetHeight);\r\n }\r\n\r\n get isScrolledDown() {\r\n return this.getDistanceToEnd() <= 1;\r\n }\r\n\r\n set scrollTop(y: number) {\r\n this.container.scrollTop = y;\r\n }\r\n \r\n get scrollTop() {\r\n //this.log.trace('get scrollTop');\r\n return this.container.scrollTop;\r\n }\r\n\r\n public setScrollTopSilently(value: number) {\r\n this.lastScrollPosition = value;\r\n this.ignoreNextScrollEvent();\r\n\r\n this.scrollTop = value;\r\n }\r\n\r\n public ignoreNextScrollEvent() {\r\n if(this.removeHeavyAnimationListener) {\r\n this.removeScrollListener();\r\n this.container.addEventListener('scroll', (e) => {\r\n cancelEvent(e);\r\n this.addScrollListener();\r\n }, {capture: true, passive: false, once: true});\r\n }\r\n }\r\n \r\n get scrollHeight() {\r\n return this.container.scrollHeight;\r\n }\r\n}\r\n\r\nexport class ScrollableX extends ScrollableBase {\r\n constructor(el: HTMLElement, logPrefix = '', public onScrollOffset = 300, public splitCount = 15, public container: HTMLElement = document.createElement('div')) {\r\n super(el, logPrefix, container);\r\n\r\n this.container.classList.add('scrollable-x');\r\n\r\n if(!IS_TOUCH_SUPPORTED) {\r\n const scrollHorizontally = (e: any) => {\r\n if(!e.deltaX && this.container.scrollWidth > this.container.clientWidth) {\r\n this.container.scrollLeft += e.deltaY / 4;\r\n cancelEvent(e);\r\n }\r\n };\r\n \r\n this.container.addEventListener('wheel', scrollHorizontally, {passive: false});\r\n }\r\n\r\n this.scrollProperty = 'scrollLeft';\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport appStateManager from \"../lib/appManagers/appStateManager\";\r\nimport ripple from \"./ripple\";\r\nimport { LangPackKey, _i18n } from \"../lib/langPack\";\r\nimport getDeepProperty from \"../helpers/object/getDeepProperty\";\r\n\r\nexport type CheckboxFieldOptions = {\r\n text?: LangPackKey,\r\n textArgs?: any[],\r\n name?: string, \r\n round?: boolean, \r\n toggle?: boolean,\r\n stateKey?: string,\r\n stateValues?: any[],\r\n disabled?: boolean,\r\n checked?: boolean,\r\n restriction?: boolean,\r\n withRipple?: boolean,\r\n withHover?: boolean,\r\n};\r\nexport default class CheckboxField {\r\n public input: HTMLInputElement;\r\n public label: HTMLLabelElement;\r\n public span: HTMLSpanElement;\r\n\r\n constructor(options: CheckboxFieldOptions = {}) {\r\n const label = this.label = document.createElement('label');\r\n label.classList.add('checkbox-field');\r\n\r\n if(options.restriction) {\r\n label.classList.add('checkbox-field-restriction');\r\n }\r\n\r\n if(options.round) {\r\n label.classList.add('checkbox-field-round');\r\n }\r\n\r\n if(options.disabled) {\r\n this.toggleDisability(true);\r\n }\r\n\r\n const input = this.input = document.createElement('input');\r\n input.classList.add('checkbox-field-input');\r\n input.type = 'checkbox';\r\n if(options.name) {\r\n input.id = 'input-' + options.name;\r\n }\r\n\r\n if(options.checked) {\r\n input.checked = true;\r\n }\r\n\r\n if(options.stateKey) {\r\n appStateManager.getState().then(state => {\r\n const stateValue = getDeepProperty(state, options.stateKey);\r\n let checked: boolean;\r\n if(options.stateValues) {\r\n checked = options.stateValues.indexOf(stateValue) === 1;\r\n } else {\r\n checked = stateValue;\r\n }\r\n\r\n this.setValueSilently(checked);\r\n\r\n input.addEventListener('change', () => {\r\n let value: any;\r\n if(options.stateValues) {\r\n value = options.stateValues[input.checked ? 1 : 0];\r\n } else {\r\n value = input.checked;\r\n }\r\n\r\n appStateManager.setByKey(options.stateKey, value);\r\n });\r\n });\r\n }\r\n\r\n let span: HTMLSpanElement;\r\n if(options.text) {\r\n span = this.span = document.createElement('span');\r\n span.classList.add('checkbox-caption');\r\n _i18n(span, options.text, options.textArgs);\r\n } else {\r\n label.classList.add('checkbox-without-caption');\r\n }\r\n\r\n label.append(input);\r\n\r\n if(options.toggle) {\r\n label.classList.add('checkbox-field-toggle');\r\n\r\n const toggle = document.createElement('div');\r\n toggle.classList.add('checkbox-toggle');\r\n label.append(toggle);\r\n } else {\r\n const box = document.createElement('div');\r\n box.classList.add('checkbox-box');\r\n \r\n const checkSvg = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\");\r\n checkSvg.classList.add('checkbox-box-check');\r\n checkSvg.setAttributeNS(null, 'viewBox', '0 0 24 24');\r\n const use = document.createElementNS(\"http://www.w3.org/2000/svg\", \"use\");\r\n use.setAttributeNS(null, 'href', '#check');\r\n use.setAttributeNS(null, 'x', '-1');\r\n checkSvg.append(use);\r\n \r\n const bg = document.createElement('div');\r\n bg.classList.add('checkbox-box-background');\r\n \r\n const border = document.createElement('div');\r\n border.classList.add('checkbox-box-border');\r\n \r\n box.append(border, bg, checkSvg);\r\n \r\n label.append(box);\r\n }\r\n\r\n if(span) {\r\n label.append(span);\r\n }\r\n\r\n if(options.withRipple) {\r\n label.classList.add('checkbox-ripple', 'hover-effect');\r\n ripple(label, undefined, undefined, true);\r\n //label.prepend(input);\r\n } else if(options.withHover) {\r\n label.classList.add('hover-effect');\r\n }\r\n }\r\n\r\n get checked() {\r\n return this.input.checked;\r\n }\r\n\r\n set checked(checked: boolean) {\r\n /* if(this.checked === checked) {\r\n return;\r\n } */\r\n \r\n this.setValueSilently(checked);\r\n\r\n const event = new Event('change', {bubbles: true, cancelable: true});\r\n this.input.dispatchEvent(event);\r\n }\r\n\r\n public setValueSilently(checked: boolean) {\r\n this.input.checked = checked;\r\n }\r\n\r\n public toggleDisability(disable: boolean) {\r\n this.label.classList.toggle('checkbox-disabled', disable);\r\n return () => this.toggleDisability(!disable);\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nexport default function toggleDisability(elements: HTMLElement[], disable: boolean): () => void {\r\n if(disable) {\r\n elements.forEach(el => el.setAttribute('disabled', 'true'));\r\n } else {\r\n elements.forEach(el => el.removeAttribute('disabled'));\r\n }\r\n\r\n return () => toggleDisability(elements, !disable);\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nexport default function findUpTag(el: any, tag: string): HTMLElement {\r\n return el.closest(tag);\r\n /* if(el.tagName === tag) return el; // 03.02.2020\r\n\r\n while(el.parentElement) {\r\n el = el.parentElement;\r\n if(el.tagName === tag) \r\n return el;\r\n }\r\n return null; */\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n * \r\n * Originally from:\r\n * https://github.com/zhukov/webogram\r\n * Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>\r\n * https://github.com/zhukov/webogram/blob/master/LICENSE\r\n */\r\n\r\nimport type { AccountPassword, AccountUpdatePasswordSettings, InputCheckPasswordSRP, PasswordKdfAlgo } from '../../layer';\r\nimport { MOUNT_CLASS_TO } from '../../config/debug';\r\nimport apiManager from './mtprotoworker';\r\nimport randomize from '../../helpers/array/randomize';\r\n\r\nexport class PasswordManager {\r\n public getState(): Promise<AccountPassword> {\r\n return apiManager.invokeApi('account.getPassword').then((result) => {\r\n return result;\r\n });\r\n }\r\n\r\n public updateSettings(settings: {\r\n hint?: string,\r\n email?: string,\r\n newPassword?: string,\r\n currentPassword?: string\r\n } = {}) {\r\n //state = Object.assign({}, state);\r\n //state.new_algo = Object.assign({}, state.new_algo);\r\n\r\n return this.getState().then(state => {\r\n let currentHashPromise: Promise<InputCheckPasswordSRP>;\r\n let newHashPromise: Promise<Uint8Array>;\r\n const params: AccountUpdatePasswordSettings = {\r\n password: null,\r\n new_settings: {\r\n _: 'account.passwordInputSettings',\r\n hint: settings.hint,\r\n email: settings.email\r\n }\r\n };\r\n \r\n if(settings.currentPassword) {\r\n currentHashPromise = apiManager.invokeCrypto('computeSRP', settings.currentPassword, state, false) as any;\r\n } else {\r\n currentHashPromise = Promise.resolve({\r\n _: 'inputCheckPasswordEmpty'\r\n });\r\n }\r\n \r\n // * https://core.telegram.org/api/srp#setting-a-new-2fa-password, but still there is a mistake, TDesktop passes 'new_algo' everytime\r\n const newAlgo = state.new_algo as PasswordKdfAlgo.passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow;\r\n const salt1 = new Uint8Array(newAlgo.salt1.length + 32);\r\n randomize(salt1);\r\n salt1.set(newAlgo.salt1, 0);\r\n newAlgo.salt1 = salt1;\r\n \r\n if(settings.newPassword) {\r\n newHashPromise = apiManager.invokeCrypto('computeSRP', settings.newPassword, state, true) as any;\r\n } else {\r\n newHashPromise = Promise.resolve(new Uint8Array());\r\n }\r\n \r\n return Promise.all([currentHashPromise, newHashPromise]).then((hashes) => {\r\n params.password = hashes[0];\r\n params.new_settings.new_algo = newAlgo;\r\n params.new_settings.new_password_hash = hashes[1];\r\n \r\n return apiManager.invokeApi('account.updatePasswordSettings', params);\r\n });\r\n });\r\n }\r\n\r\n public check(password: string, state: AccountPassword, options: any = {}) {\r\n return apiManager.invokeCrypto('computeSRP', password, state, false).then((inputCheckPassword) => {\r\n //console.log('SRP', inputCheckPassword);\r\n return apiManager.invokeApi('auth.checkPassword', {\r\n password: inputCheckPassword as InputCheckPasswordSRP.inputCheckPasswordSRP\r\n }, options).then(auth => {\r\n if(auth._ === 'auth.authorization') {\r\n apiManager.setUser(auth.user);\r\n }\r\n\r\n return auth;\r\n });\r\n });\r\n }\r\n\r\n public confirmPasswordEmail(code: string) {\r\n return apiManager.invokeApi('account.confirmPasswordEmail', {code});\r\n }\r\n\r\n public resendPasswordEmail() {\r\n return apiManager.invokeApi('account.resendPasswordEmail');\r\n }\r\n\r\n public cancelPasswordEmail() {\r\n return apiManager.invokeApi('account.cancelPasswordEmail');\r\n }\r\n\r\n /* public requestRecovery(options: any = {}) {\r\n return apiManager.invokeApi('auth.requestPasswordRecovery', {}, options);\r\n }\r\n\r\n public recover(code: any, options: any = {}) {\r\n return apiManager.invokeApi('auth.recoverPassword', {\r\n code\r\n }, options);\r\n } */\r\n}\r\n\r\nconst passwordManager = new PasswordManager();\r\nMOUNT_CLASS_TO.passwordManager = passwordManager;\r\nexport default passwordManager;\r\n","export default function randomize<T extends ArrayBufferView>(arr: T) {\n if(crypto && 'getRandomValues' in crypto) {\n crypto.getRandomValues(arr);\n } else {\n throw new Error('NO_SECURE_RANDOM');\n }\n \n return arr;\n}\n"],"sourceRoot":""}