tweb/public/11.6f1611987776c2248d74.chunk.js.map
Eduard Kuzmenko 6e7128d3d6 Build
2021-04-18 15:56:55 +04:00

1 line
1.7 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:///./public/recorder.min.js","webpack:///./src/components/button.ts","webpack:///./src/components/inputField.ts","webpack:///./src/components/ripple.ts","webpack:///./src/components/scrollable.ts","webpack:///./src/components/checkboxField.ts","webpack:///./src/helpers/dom/findUpTag.ts","webpack:///./src/components/appSearch.ts","webpack:///./src/components/inputSearch.ts","webpack:///./src/helpers/listenerSetter.ts","webpack:///./src/components/buttonIcon.ts","webpack:///./src/components/sliderTab.ts","webpack:///./src/components/slider.ts","webpack:///./src/components/avatarEdit.ts","webpack:///./src/components/sidebarLeft/tabs/newGroup.ts","webpack:///./src/components/appMediaPlaybackController.ts","webpack:///./src/components/rangeSelector.ts","webpack:///./src/lib/mediaPlayer.ts","webpack:///./src/components/audio.ts","webpack:///./src/components/divAndCaption.ts","webpack:///./src/components/chat/replyContainer.ts","webpack:///./src/components/groupedLayout.ts","webpack:///./src/components/editPeer.ts","webpack:///./src/components/row.ts","webpack:///./src/components/radioForm.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/groupType.ts","webpack:///./src/helpers/listLoader.ts","webpack:///./src/components/appSelectPeers.ts","webpack:///./src/helpers/dom/findUpAttribute.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/editGroup.ts","webpack:///./src/components/sidebarRight/tabs/editChannel.ts","webpack:///./src/components/sidebarRight/tabs/editContact.ts","webpack:///./src/components/swipeHandler.ts","webpack:///./src/components/sidebarLeft/tabs/addMembers.ts","webpack:///./src/components/sidebarRight/tabs/sharedMedia.ts","webpack:///./src/components/sidebarRight/index.ts","webpack:///./src/components/sidebarRight/tabs/pollResults.ts","webpack:///./src/components/poll.ts","webpack:///./src/components/wrappers.ts","webpack:///./src/helpers/middleware.ts","webpack:///./src/components/sortedUserList.ts","webpack:///./src/components/appSearchSuper..ts","webpack:///./src/components/buttonMenu.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/lib/appManagers/appStickersManager.ts","webpack:///./src/components/sidebarLeft/tabs/2fa/passwordSet.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/components/sidebarLeft/tabs/privacyAndSecurity.ts","webpack:///./src/helpers/color.ts","webpack:///./src/components/sidebarLeft/tabs/background.ts","webpack:///./src/helpers/averageColor.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/sidebarLeft/tabs/settings.ts","webpack:///./src/components/sidebarLeft/tabs/newChannel.ts","webpack:///./src/components/sidebarLeft/tabs/contacts.ts","webpack:///./src/components/sidebarLeft/tabs/archivedTab.ts","webpack:///./src/components/sidebarLeft/index.ts","webpack:///./src/components/chat/bubbleGroups.ts","webpack:///./src/components/popups/datePicker.ts","webpack:///./src/components/popups/forward.ts","webpack:///./src/components/popups/stickers.ts","webpack:///./src/components/stickyIntersector.ts","webpack:///./src/components/chat/replies.ts","webpack:///./src/components/chat/messageRender.ts","webpack:///./src/helpers/dom/getElementByPoint.ts","webpack:///./src/components/chat/bubbles.ts","webpack:///./src/components/popups/deleteMessages.ts","webpack:///./src/components/popups/unpinMessage.ts","webpack:///./src/components/popups/sendNow.ts","webpack:///./src/components/chat/contextMenu.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/components/emoticonsDropdown/index.ts","webpack:///./src/components/chat/sendContextMenu.ts","webpack:///./src/components/popups/createPoll.ts","webpack:///./src/components/popups/newMedia.ts","webpack:///./src/components/chat/stickersHelper.ts","webpack:///./src/components/popups/schedule.ts","webpack:///./src/components/chat/input.ts","webpack:///./src/components/chat/selection.ts","webpack:///./src/components/chat/pinnedContainer.ts","webpack:///./src/components/chat/audio.ts","webpack:///./src/components/chat/pinnedMessageBorder.ts","webpack:///./src/components/chat/pinnedMessage.ts","webpack:///./src/components/chat/search.ts","webpack:///./src/components/sidebarRight/tabs/search.ts","webpack:///./src/components/chat/topbar.ts","webpack:///./src/components/chat/chat.ts","webpack:///./src/components/chat/markupTooltip.ts","webpack:///./src/components/chat/dragAndDrop.ts","webpack:///./src/lib/appManagers/appImManager.ts","webpack:///./src/components/appMediaViewer.ts","webpack:///./src/helpers/dom/getVisibleRect.ts","webpack:///./src/components/avatar.ts","webpack:///./src/components/dialogsContextMenu.ts","webpack:///./src/lib/appManagers/appDialogsManager.ts"],"names":["self","module","exports","e","t","o","i","n","l","call","m","c","d","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","__esModule","create","bind","default","prototype","hasOwnProperty","p","s","AudioContext","webkitAudioContext","isRecordingSupported","Error","this","state","config","assign","bufferLength","encoderApplication","encoderFrameSize","encoderPath","encoderSampleRate","maxFramesPerPage","mediaTrackConstraints","monitorGain","numberOfChannels","recordingGain","resampleQuality","streamPages","reuseWorker","wavBitDepth","encodedSamplePosition","navigator","mediaDevices","getUserMedia","WebAssembly","clearStream","stream","getTracks","forEach","stop","audioContext","closeAudioContext","close","encodeBuffers","getChannelData","encoder","postMessage","command","buffers","initAudioContext","context","initAudioGraph","scriptProcessorNode","createScriptProcessor","connect","destination","onaudioprocess","inputBuffer","monitorGainNode","createGain","setMonitorGain","recordingGainNode","setRecordingGain","initSourceNode","Promise","resolve","audio","then","createMediaStreamSource","loadWorker","Worker","initWorker","streamPage","storePage","recordedPages","totalLength","data","message","samplePosition","page","removeEventListener","finish","addEventListener","originalSampleRate","sampleRate","wavSampleRate","pause","onpause","resume","onresume","gain","setTargetAtTime","currentTime","start","sourceNode","onstart","disconnect","destroyWorker","push","length","ondataavailable","Uint8Array","reduce","set","onstop","Function","window","className","options","button","document","createElement","icon","noRipple","rippleSquare","classList","add","onlyMobile","disabled","text","append","init","target","hasAttribute","parentElement","preventDefault","originalEvent","clipboardData","getData","entities","parseEntities","filter","_","wrapRichText","noLinks","wrappingDraft","execCommand","checkAndSetRTL","input","char","HTMLInputElement","innerText","direction","style","InputState","container","maxLength","showLengthOn","Math","round","placeholder","name","plainText","processInput","label","labelText","innerHTML","firstElementChild","observer","MutationObserver","inputFake","onFakeInput","observe","characterData","childList","subtree","animate","wasInputFakeClientHeight","showScrollDebounced","remove","setAttribute","undefined","border","setLabel","labelEl","lastElementChild","showingLength","wasError","contains","inputLength","diff","isError","toggle","select","textContent","labelOptions","scrollHeight","clientHeight","height","setValueSilently","event","Event","bubbles","cancelable","dispatchEvent","fireFakeInput","originalValue","silent","wrapDraftText","Valid","setState","rippleClickId","ripple","elem","callback","onEnd","prepend","querySelector","handler","drawRipple","clientX","clientY","startTime","Date","now","clickId","duration","getComputedStyle","getPropertyValue","replace","elapsedTime","cb","mutate","delay","max","setTimeout","touchStartFired","requestAnimationFrame","rect","getBoundingClientRect","clickX","left","clickY","top","size","sqrt","abs","width","x","y","touchEnd","settings","animationsEnabled","touches","includes","tagName","once","cancelBubble","stopPropagation","passive","dataset","ScrollableBase","el","logPrefix","onScrollMeasure","isHeavyAnimationInProgress","needCheckAfterAnimation","log","error","Array","from","children","onScroll","capture","cancelAnimationFrame","element","position","margin","maxDistance","forceDirection","forceDuration","axis","Scrollable","onScrollOffset","withPaddingContainer","super","onAdditionalScroll","onScrolledTop","onScrolledBottom","lastScrollTop","lastScrollDirection","loadedAll","bottom","splitUp","scrollTop","checkForTriggers","maxScrollTop","setListeners","elements","padding","offsetHeight","getDistanceToEnd","ScrollableX","splitCount","scrollHorizontally","deltaX","scrollWidth","clientWidth","scrollLeft","deltaY","CheckboxField","restriction","toggleDisability","span","type","id","checked","stateKey","getState","setByKey","textArgs","box","checkSvg","createElementNS","setAttributeNS","use","bg","withRipple","withHover","disable","findUpTag","tag","closest","clearable","clickable","autonomous","onFound","list","createChatList","nameEl","display","setListClickListener","childElementCount","setActive","clear","searchInput","searchGroups","onSearch","minMsgId","loadedCount","foundCount","searchPromise","searchTimeout","query","listsContainer","peerId","threadId","scrollable","messages","setVirtualContainer","onChange","reset","searchMore","trim","all","focus","maxId","getSearch","inputFilter","limit","res","count","history","mid","shift","searchGroup","dialog","dom","addDialogNew","drawStatus","avatarSize","setLastMessage","catch","err","console","prevValue","timeout","onInput","clearTimeout","onClearClick","onClear","inputField","searchIcon","clearBtn","ListenerSetter","listeners","Set","listener","addManual","delete","_listener","slider","destroyable","_constructor","header","closeBtn","title","content","addTab","listenerSetter","closeTab","args","result","selectTab","tabs","removeAll","key","eventListener","cleanup","onCloseAfterTimeout","historyTabIds","canHideFirst","onCloseBtnClick","appNavigationController","findItemByType","navigationType","back","isNavigation","closingId","pop","onCloseTab","tab","_selectTab","Map","tabsContainer","sidebarEl","querySelectorAll","onOpen","onOpenAfterTimeout","pushItem","onPop","canAnimate","findAndSplice","tabConstructor","preserveTab","removeTabFromHistory","find","getTab","removeByType","onClose","canvas","open","getContext","clearRect","uploadAvatar","setTitle","avatarEdit","_upload","inputWrapper","groupNameInputField","nextBtn","createChat","userIds","chatId","inputFile","editPhoto","chatsContainer","userId","rippleEnabled","lastMessageSpan","getUserStatusString","appMediaPlaybackController","media","waitingMediaForLoad","onPause","rootScope","broadcast","onEnded","nextMid","currentPeerId","resolveWaitingForLoadMedia","play","cssText","body","doc","autoload","storage","volume","playingMedia","paused","loadSiblingsMedia","onError","deferred","supportsStreaming","downloadDoc","handleSafariStreamable","src","url","promise","safariBuffering","prevMid","backLimit","Boolean","getMessageByPeer","addMedia","willBePlayedMedia","step","min","mousedown","events","onMouseMove","scrub","onMouseDown","onMouseUp","filled","seek","setProgress","stepStr","index","indexOf","decimals","setFilled","percents","offsetX","MouseEvent","pageX","targetTouches","toFixed","onScrub","streamable","stopAndScrubTimeout","progressRAF","onLoadedData","onPlay","setLoadProgress","onProgress","filledLoad","setSeekMax","setHandlers","scrubTime","isSafariBuffering","buf","buffered","numRanges","nearestStart","end","removeListeners","lastVolume","video","onFullScreen","webkitFullscreenElement","wrapper","parentNode","insertBefore","appendChild","skin","ckin","stylePlayer","controls","progress","muted","autoplay","finally","initDuration","player","html","buildControls","timeDuration","insertAdjacentHTML","fullScreenButton","timeElapsed","String","toHHMMSS","volumeDiv","volumeSvg","volumeProgress","setVolume","togglePlay","showControlsTimeout","toggleFullScreen","split","eventName","fullscreenElement","mozFullScreenElement","msFullscreenElement","webkitEnterFullscreen","enterFullscreen","isFullScreen","cancelFullScreen","mozCancelFullScreen","webkitCancelFullScreen","msExitFullscreen","requestFullscreen","mozRequestFullScreen","webkitRequestFullscreen","msRequestFullscreen","wrapVoiceMessage","audioEl","webpage","isOut","fromId","myId","isUnread","pFlags","media_unread","out","barHeightMax","mediaSizes","isMobile","svg","timeDiv","waveform","attributes","attribute","valueCount","dataView","DataView","buffer","byteIndex","bitShift","getUint16","decodeWaveform","slice","normValue","wfSize","barCount","maxValue","maxDelta","barX","sumI","bar_value","barWidth","rects","interval","lastIndex","node","clearInterval","setInterval","isNaN","addAudioListener","readMessages","mousemove","on","mids","HTMLElement","withTime","voiceAsMusic","showSender","attachedHandlers","isRealVoice","isVoice","isOutgoing","is_outgoing","uploading","preloader","durationStr","downloadDiv","onTypeLoad","senderTitle","getSenderToPeerText","subtitle","audioTitle","file_name","audioPerformer","wrapPlainText","formatDate","date","titleAdditionHTML","fontWeight","subtitleDiv","launched","progressLine","lastChild","replaceWith","onPlaying","wrapAudio","audioTimeDiv","onLoad","onTypeDisconnect","getTimeStr","attach","getDownloadPromise","load","download","onClick","construct","setManual","setDownloadFunction","noAutoDownload","willBePlayed","readyState","isConnected","customElements","define","DivAndCaption","fill","wrapReplyDivAndCaption","titleEl","subtitleEl","mediaEl","wrapEmojiText","setMedia","wrapMessageForReply","photo","boxSize","backgroundImage","wrapSticker","div","lazyLoadQueue","chat","group","CHAT_ANIMATION_GROUP","getCacheContext","downloaded","sizes","thumbs","bytes","renderImageFromUrl","getPreviewURLFromThumb","choosePhotoSize","preloadPhoto","getDocumentCachedThumb","isMediaSet","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","w","h0","h","w0","w2","w1","h1","h2","map","ratio","join","cropRatios","attempts","multiHeight","offset","sum","pushAttempt","lineCounts","heights","first","second","third","fourth","optimalAttempt","optimalDiff","attempt","counts","lineCount","totalHeight","minLineHeight","bad1","bad2","line","optimalCounts","optimalHeights","rowCount","row","colCount","lineHeight","col","isChanged","inputFields","isValid","handleChange","avatarElem","doNotEditAvatar","freezed","radioField","checkboxField","subtitleLangKey","havePadding","isToggle","titleRight","noCheckboxSubtitle","titleLangKey","navigationTab","RadioFormFromRows","rows","radios","form","RadioForm","copyTextToClipboard","clipboard","writeText","textArea","removeChild","fallbackCopyTextToClipboard","appStateManager","main","langKey","toastEl","toast","checkUsernameDebounced","checkUsername","getValue","Neutral","isUsernameValid","setError","invalidText","head","username","checkUsernamePromise","invokeApi","channel","getChannelInput","available","availableText","takenText","buttons","overlayClosable","avatarEl","descriptionLangKey","titleLangArgs","descriptionLangArgs","description","fragment","createDocumentFragment","checkboxes","original","nextElementSibling","section","random","privateRow","publicRow","a","privateSection","publicSection","reverse","getChat","linkRow","chatFull","exported_invite","link","format","btnRevoke","getChatInviteLink","show","caption","noDelimiter","changed","linkInputField","applyBtn","migrateChat","channelId","updateUsername","setOriginalValue","loading","loaded","getPromise","done","loadAllDialogsPromise","loadedAllDialogs","selected","folderId","offsetIndex","loadedWhat","renderedPeerIds","peerType","multiSelect","tempIds","needSwitchList","f","renderResultsFunc","renderResults","peerIds","notRendered","has","topContainer","selectedContainer","selectedScrollable","delimiter","findUpClassName","li","click","checkbox","cachedContacts","getMoreResults","appendTo","getResultsPromise","onFirstRender","testSelfSearch","dialogs","archived","pageCount","windowH","tempId","getTempId","getConversations","newOffsetIndex","chatRightsAction","canSendToUser","hasRights","renderSaved","getMoreDialogs","contacts","getMoreContacts","getContacts","arr","splice","channelParticipants","getChannelParticipants","q","participants","participant","user_id","u","promises","getConversationsAll","getMoreChannelParticipants","isNonContactUser","listEl","containerEl","getChatMembersString","scroll","onlyFirstName","insertAdjacentElement","scrollIntoViewNew","offsetWidth","onAnimationEnd","values","Static","closable","selector","getSelected","onSelect","hide","peerTypes","destroyListener","rights","takeOut","banned_rights","editBanned","btnDeleteException","clearChannelParticipantBannedRights","btnDelete","kickFromChannel","v","flags","exceptionText","toggleWith","defaultBannedRights","default_banned_rights","combineParticipantBannedRights","info","mainFlag","until_date","flag","chatPermissions","editChatDefaultBannedRights","addExceptionRow","openPermissions","getChannelParticipant","generateContentElement","setSubtitle","bannedRights","cantWhat","update","needAdd","new_participant","view_messages","prev_participant","exceptionsCount","setLength","LOAD_COUNT","loader","getDialogType","peerTitleElement","callbackLeave","leave","callbackDelete","flushHistory","descriptionArgs","isDanger","getChatFull","descriptionInputField","about","editPeer","groupTypeRow","setGroupTypeSubtitle","permissionsRow","setPermissionsLength","acc","editTitle","editAbout","race","removeAttribute","migrateFrom","migrateTo","_init","getChannelFull","nameInputField","deleteChannel","lastNameInputField","user","getUser","first_name","last_name","notificationsCheckboxField","isTrusted","mutePeer","peer","getPeerId","enabled","isMuted","notify_settings","notificationsRow","isPeerLocalMuted","profileNameDiv","profileSubtitleDiv","addContact","phone","deleteContacts","getEvent","attachGlobalListenerTo","hadMove","xDown","yDown","handleMove","cursor","onReset","handleStart","_e","verifyTouchTarget","xUp","yUp","xDiff","yDiff","onFirstSwipe","onSwipe","skippable","attachToPromise","ret","selectedPeerIds","addInitial","setText","previous","next","loadCount","loadedAllUp","loadedAllDown","items","item","current","unshift","onJump","older","loadPromiseDown","loadPromiseUp","anchor","loadMore","processed","processItem","photoId","avatar","BASE_CLASS","getPhoto","action","img","Image","draggable","getPeerPhoto","putAvatar","avatars","gradient","checkScrollTop","cancel","freeze","listLoader","targets","concat","idx","prevTargets","nextTargets","openAvatarViewer","toRight","right","go","cancelNextClick","lastDiffX","minX","lastX","transform","offsetLeft","addIndex","ceil","getUserPhotos","photos","Number","MAX_SAFE_INTEGER","chat_photo","generateFakeAvatarMessage","activeTab","photo_id","setPeerStatus","needClear","getPeerStatus","bio","getProfileByPeerId","full","getPeer","notifications","setBio","setPeerStatusInterval","setBioTimeout","oldAvatars","setPeer","cleaned","cleanupHTML","setAvatar","getPeerUsername","rPhone","override","getProfile","userFull","rAbout","canSetNext","historiesStorage","newCloseBtn","animatedCloseIcon","transitionContainer","transitionFirstItem","editBtn","transitionLastItem","secondTitle","cloneNode","profile","searchSuper","nav","isSharedMedia","transition","cleanScrollPositions","isAnyGroup","mediaTabs","onChangeTab","mediaTab","btnAddMembers","isChannel","showConfirmation","inviteToChannel","addChatUser","filtered","filterMessagesByType","usedFromHistory","performSearchResult","findIndex","canViewMembers","loadMutex","peerChanged","setQuery","historyStorage","fillProfileElements","isContact","admin_rights","single","justLoad","AppSharedMediaTab","getElementById","to","medium","mobile","toggleSidebar","sharedMediaTab","enable","active","willChange","animationPromise","appSidebarRight","resultsDiv","poll","getPoll","quiz","rQuestion","results","voters","total_voters","roundPercents","hr","answer","answers","answerEl","answerTitle","answerPercents","minHeight","getVotes","option","votesList","votes","vote","meAsSaved","showMore","next_offset","down","lineTotalLength","minIndex","minRemainder","k","remainder","maxRemainder","pollElement","isClosed","closed","performResults","chosenIndexes","prevQuizHint","hideQuizHint","prevQuizHintOnHide","prevQuizHintTimeout","onHide","maxOffset","isQuiz","isRetracted","isPublic","isMultiple","chosingIndexes","sentVote","getTotalLength","pollId","descKey","is_scheduled","public_voters","multiple_choice","multipleSelect","regular","descDiv","typeDiv","avatarsDiv","close_period","close_date","timeLeftDiv","quizTimer","strokeWidth","radius","circumference","PI","circle","period","closeTime","serverTimeOffset","quizInterval","time","timeLeft","color","stroke","strokeDashoffset","strokeDasharray","getResults","answerDivs","svgLines","numberDivs","footerDiv","viewResults","votersCountDiv","isTabExists","sendVoteBtn","sendVotes","setVotersCount","clickHandler","solution","solution_entities","toggleHint","textEl","bubblesContainer","setQuizHint","correctResult","correct","chosen","answerIndex","foundIndex","indexes","sendVotePromise","sendVote","initQuizHint","timeEl","setResults","recent_voters","maxPercents","setLineProgress","getPercentValue","iterate","fullTime","votersCount","multiplier","wrapVideo","boxWidth","boxHeight","withTail","middleware","noInfo","onlyPreview","withoutPreloader","loadPromises","noPlayButton","isAlbumItem","canAutoplay","autoPlay","gifs","videos","spanTime","spanPlay","needPlayButton","mime_type","photoRes","wrapPhoto","thumb","loadPromise","globalVideo","divRound","baseVal","ctx","setPeerPromise","onTimeUpdate","onPaused","onFrame","drawImage","foreignObject","images","getAttributeNS","gotThumb","getThumb","poster","attachMethod","loadFunc","reject","detach","queueId","animationIntersector","addAnimation","loop","render","timestamp","monthShort","withYear","month","getMonth","str","getDate","getFullYear","getHours","getMinutes","wrapDocument","searchContext","audioElement","extSplitted","ext","isArray","toLowerCase","docDiv","docId","icoDiv","imgs","wrapped","fileName","_downloadDiv","getDoc","saveDocFile","noBlur","setAttachmentSize","loadThumbPromise","thumbImage","image","getStrippedThumbIfNeeded","clipId","defs","clipPathHTML","parseInt","wrapMediaWithTail","cacheContext","needFadeIn","sequentialDom","mutateElement","renderPromise","onlyThumb","emoji","withThumb","stickerType","sticker","loadLottieWorkers","toneIndex","haveThumbCached","stickerCachedThumbs","afterRender","getPathFromPhotoPathSize","webpWorkerController","isWebpSupported","stickerThumbConverted","convert","getThumbURL","json","animation","loadAnimationWorker","animationData","saveLottiePreview","getAnimation","restart","wrapReply","replyContainer","prepareAlbum","widthItem","heightItem","borderTopLeftRadius","borderBottomLeftRadius","borderTopRightRadius","borderBottomRightRadius","forMedia","mediaDiv","wrapAlbum","groupId","attachmentDiv","getMidsByAlbum","getMessage","album","getMiddleware","cleanupObj","clean","_cleanupObj","users","sorted","doTimeout","updateList","good","SORT_INTERVAL","sortedUser","status","getUserStatusForSort","batch","prevTabId","urlsToRevoke","nextRates","loadedChats","firstLoad","logger","monthContainers","mediaTabsMap","asChatList","groupByMonth","hideEmptyTabs","onTransitionStart","overflowY","onTransitionEnd","navScrollableContainer","navScrollable","tabsMenu","menuTab","contentTab","searchGroupMedia","horizontalMenu","tabContent","skipScroll","newMediaTab","fromMediaTab","offsetTop","rect2","inputMessagesFilterPhotoVideo","warn","setSearchContext","copySearchContext","openMedia","useHeavyAnimationCheck","lock","unlockAndRefresh","elemsToAppend","sharedMediaDiv","entity","totalEntities","display_url","sliced","match","matchUrl","same","URL","hostname","rDescription","previewDiv","getAbbreviation","rTitle","sender","method","details","monthContainer","getMonthContainerByTimestamp","afterPerforming","parent","child","inputMessagesFilterEmpty","showMembersCount","participants_count","regExp","RegExp","searchIndexManager","cleanSearchText","titleSpan","formatted","arg","searchContacts","my_results","globalContacts","isShort","minDate","renderRecentSearch","recent","recentSearch","getTopPeers","peers","people","renderParticipants","membersList","setInnerPeer","deleted","loadMembers","loadChats","logStr","used","slicedLength","ids","nextRate","maxDate","next_rate","filters","counters","getSearchCounters","firstMediaTab","counter","membersTab","toLoad","loadType","setHours","setDate","dateTimestamp","getTime","containers","haveTimestamps","isBroadcast","goFirst","revokeObjectURL","empty","newInputFilter","ButtonMenuItem","b","ButtonMenuToggleHandler","openedMenu","PrivacyType","btnMenu","appPrivacyManager","privacy","rules","inputKey","privacyRules","saveApiUsers","saveApiChats","chats","apiUpdatesManager","processUpdateMessage","inputRule","rule","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","phoneSection","nextSibling","storeName","getStickerSetPromises","getStickersByEmoticonsPromises","getStickerSet","access_hash","overwrite","saveStickerSet","stickerset","docs","saveDoc","params","cachedSet","documents","saveStickers","stickerSet","getStickerSetInput","invokeApiHashable","stickers","getFromCache","pack","packs","emoticon","newSet","setToCache","needSave","installed_date","dcId","thumb_dc_id","isAnimated","animated","location","volume_id","local_id","mimeType","sets","covered","excludeFeatured","exclude_featured","foundSaved","cache","getCache","cover","getAllStickers","allStickers","preloadStickerSets","getRecentStickers","messagesStickers","installedSets","recentStickers","foundStickers","cachedStickersAnimated","cachedStickersStatic","iteratePacks","appStickersManager","getAnimatedEmojiSticker","stickerContainer","inputContent","btnReturn","sliceTabsUntilTab","isFirst","email","codeInputField","onFill","code","passwordManager","confirmPasswordEmail","goNext","btnChange","btnResend","cancelPasswordEmail","resendPasswordEmail","onContinueClick","btnContinue","btnSkip","matchEmail","toggleButtons","updateSettings","hint","currentPassword","plainPassword","newPassword","symbols","isCancel","onSkipClick","saveHint","passwordInputField","monkey","verifyInput","isNew","has_password","IntlElement","getStateInterval","_state","check","auth","btnChangePassword","btnDisablePassword","btnSetRecoveryEmail","has_recovery","btnSetPassword","Session","app_name","app_version","ip","country","date_active","date_created","hash","midtitle","device_model","system_version","authorizations","session","btnTerminate","otherSection","privacyTab","updateActiveSessions","onTerminateClick","menuElement","btnAdd","toggleBlock","bot","blocked","getBlocked","blockedPeerIds","blockedUsersRow","passwordState","twoFactorRow","email_unconfirmed_pattern","activeSessionsRow","blockedCount","setBlockedCount","updateBlocked","rowsByKeys","numberVisibilityRow","lastSeenTimeRow","photoVisibilityRow","callRow","linkAccountRow","groupChatsAddRow","updatePrivacyRow","disallowLength","allowLength","auths","hslaStringToRgba","hsla","alpha","val","endsWith","g","hue2rgb","hslToRgba","hslaStringToRgbString","toString","hslaStringToRgbaString","highlightningColor","pixel","rgbToHsl","blurCheckboxField","grid","setBackgroundDocument","slug","_tempId","addNotifyListener","onReady","imageUrl","naturalWidth","naturalHeight","pixels","getImageData","pixelsLength","outPixel","Uint8ClampedArray","averageColor","background","applyBackgroundColor","pushToState","fetch","response","appDownloadManager","cacheStorage","save","saveToCache","setBackground","blur","accountWallpapers","wallpapers","wallpaper","pattern","clicked","tryAgainOnFail","initialValue","minValue","nameDiv","valueDiv","range","messagesTextSize","chatBackgroundButton","animationsCheckboxField","enterRow","ctrlEnterRow","contactsCheckboxField","privateCheckboxField","groupsCheckboxField","channelsCheckboxField","gifsCheckboxField","videosCheckboxField","suggestCheckboxField","loopCheckboxField","firstNameInputField","bioInputField","getSelf","usernameInputField","setProfileUrl","profileUrlContainer","profileUrlAnchor","href","updateProfile","uploadProfilePhoto","foundInFilters","dialogsByFilters","onSelectChange","confirmBtn","pinned_peers","other","editFolderTab","setFilter","filtersStorage","getDialogFilters","dialogsStorage","getFolder","categoriesSection","exclude_muted","ico","exclude_archived","exclude_read","non_contacts","groups","broadcasts","bots","chatsSection","selectedPeers","include_peers","exclude_peers","_add","originalFilter","deleteFolderButton","updateDialogFilter","bool","menuBtn","generateList","h2Text","categories","includedFlagsContainer","excludedFlagsContainer","include","createDialogFilter","editCheckForChange","loadAnimationPromise","lottieLoader","loadAnimationFromURL","waitForFirstFrame","ul","renderMore","_length","firstTime","onEditOpen","onCreateOpen","filtersRendered","dialogFilter","keys","folder","channels","filterId","orderIndex","createFolderBtn","foldersSection","suggestedSection","onFiltersContainerUpdate","renderFolder","getSuggestedFilters","suggestedFilters","NotifySection","enabledRow","typeText","previewEnabledRow","inputNotifyPeer","getNotifySettings","notifySettings","applySettings","show_previews","mute","showPreviews","inputSettings","mute_until","updateNotifySettings","contactsSignUpRow","soundRow","getContactSignUpNotification","_enabled","setContactSignUpNotification","invokeApiCacheable","lang_pack","languages","language","lang_code","native_name","getLangPack","getCacheLangPack","langPack","logOut","phoneDiv","buttonsDiv","edit","folders","general","fillElements","channelNameInputField","channelDescriptionInputField","onLengthChange","createChannel","alive","inputSearch","openContacts","_contacts","sort","renderPage","chatList","chatLists","onChatsRegularScroll","onChatsScroll","wasFilterId","onTabChange","_scroll","appSidebarLeft","sidebarHeader","onContactsClick","backBtn","btnArchive","verify","menuButtons","openUsername","toolsBtn","btnMenuFooter","version","newBtnMenu","initSearch","archivedCount","searchContainer","pickedElements","selectedPeerId","selectedMinDate","selectedMaxDate","updatePicked","setProperty","removeProperty","helper","unselectEntity","renderEntity","dates","dateData","getAttribute","peopleContainer","hideNewBtnMenuTimeout","onFocus","clearRecentSearchBtn","detailsMap","newGroupDiff","bubble","updateGroup","fwdFromId","removeBubble","insertObject","foundBubble","foundAtIndex","foundMidOnSameTimestamp","_timestamp","_mid","bubbleGroup","insertIndex","last","initDate","onPick","noButtons","selectedDate","onPrevClick","selectedMonth","setMonth","minMonth","prevBtn","onNextClick","maxMonth","onDateClick","selectedEl","setTimeTitle","setFullYear","controlsDiv","monthTitle","monthsContainer","handleTimeInput","onOverflow","maxString","hoursInputField","minutesInputField","number","setMinutes","btnConfirm","popupCenterer","noTitle","timeOptions","minute","hour","sendDate","dateOptions","day","year","IntlDateElement","firstChild","weekday","firstDate","weekStartDate","getDay","renderElement","dayIndex","clonedDate","showOverflowMonths","lines","fromPeerId","initMessagesForward","stickerSetInput","onFooterClick","stickersFooter","toggleStickerSet","onStickersClick","fileId","sendMessageWithDocument","h6","setOnlyOnePlayableGroup","stickersDiv","btn","loadStickerSet","esgSticker","StickyIntersector","observeHeaders","observeElements","headersObserver","IntersectionObserver","entries","entry","targetInfo","boundingClientRect","stickyTarget","rootBoundsInfo","rootBounds","threshold","root","elementsObserver","isIntersecting","sentinel","headerSentinel","addSentinel","unobserve","updated","postKey","replies","leftPart","recent_repliers","getHistoryStorage","channel_id","read_max_id","max_id","readMaxId","textSpan","iconSpan","rippleContainer","subscribeRepliesThread","updateMessage","MessageRender","setTime","bubbleContainer","messageDiv","views","postAuthor","post_author","fwd_from","saved_from_msg_id","forward","edit_date","edit_hide","pinned","timeSpan","renderReplies","isFooter","repliesFooter","setReply","isReplacing","currentReplyDiv","reply_to_mid","replyToPeerId","reply_to","reply_to_peer_id","appPeersManager","originalPeerTitle","originalMessage","appMessagesManager","wrapSingleMessage","needUpdate","replyMid","getPeerTitle","getElementByPoint","verticalSide","horizontalSide","floor","elementFromPoint","IGNORE_ACTIONS","TEST_SCROLL","appUsersManager","appInlineBotsManager","appPhotosManager","appDocsManager","appChatsManager","unreadOut","dateMessages","scrolledDown","isScrollingTimeout","unreaded","loadedTopTimes","loadedBottomTimes","messagesQueuePromise","messagesQueue","messagesQueueOnRender","messagesQueueOnRenderAdditional","firstUnreadBubble","replyFollowHistory","isFirstLoad","onBubblesClick","chatInner","onDatePick","selection","isSelecting","selectedText","toggleByBubble","contactDiv","appImManager","bubbleMid","reply_to_top_id","generateThreadServiceStartMessage","filterMessages","getDiscussionMessage","savedFrom","msgId","isVideoComponentElement","messageId","parents","albumItem","isReplyClick","replyToMid","reply_to_msg_id","topbar","pinnedMessage","setCorrectIndex","requestHistory","setMessageId","setScroll","bubbleGroups","getMessagesStorage","addBubble","setBubblePosition","scrollingToNewBubble","scrollToNewLastBubble","deleteMessagesByIds","tempMessage","mounted","getMountedBubble","repliesElement","grouped_id","newPoll","renderMessage","updatePosition","deleteEmptyDateGroups","deletedMids","renderedId","renderMaxId","groupedMessagesStorage","obj","highlightBubble","stickyIntersector","stuck","dateMessage","unlock","refresh","renderNewMessagesByIds","msgIdsByPeer","msgIds","msgs","setUnreadCount","updateUnreadByDialog","unreadedObserver","offline","readed","bubblesMaxId","readHistory","wasHeight","resizing","skip","scrolled","part","rAF","onResizeEnd","isScrolledDown","setEndRAF","ResizeObserver","contentRect","realDiff","_part","needScrollTop","onUpdate","getScheduledMessagesStorage","bad","getGroupedBubble","getHistoryTopPromise","getHistoryBottomPromise","getHistory","loadMoreHistory","readOutboxMaxId","permanent","deleteSelectedMids","checkAnimations","replyTo","performHistoryResult","dateGroup","scrollToBubble","datasetKey","dateElement","today","bubbleContent","serviceMsg","firstTimestamp","observeStickyHeaderChanges","bubblesToo","attachedUnreadBubble","lastMsgId","samePeer","topMessage","pinnedMessages","isTarget","savedPosition","getChatSavedPosition","getReadMaxIdIfUnread","isJump","apiManager","setQueueId","additionMsgId","maxBubbleId","getBubbleByPoint","oldChatInner","cached","finishPeerChange","lockGroup","unlockGroup","fromUp","followingUnread","mountedByLastMsgId","findNextMountedBubbleByMsgId","onScrolledAllDown","getDialogByPeerId","unread_mark","markDialogUnread","canWrite","canWriteToPeer","setMessagesQueuePromise","queue","setUnreadDelimiter","getDateContainerByMessage","multipleRender","albumMustBeRenderedFull","our","isMegagroup","contentWrapper","wasClassNames","classNames","transitionDelay","originalMid","unread","wrapMessageActionTextNew","renderMessagesQueue","is_single","messageMessage","messageMedia","getAlbumText","richText","canHaveTail","emojiEntities","strLength","curr","reply_markup","containerDiv","rowDiv","noLinebreaks","buttonEl","unsafe","verified","wrapUrl","rel","column","callbackButtonClick","messageWithReplies","withReplies","comments","nameContainer","processingWebPage","noAutoDownloadMedia","previewResizer","preview","quote","quoteTextDiv","site_name","titleDiv","textDiv","isSquare","newNameContainer","getMidsByMid","wrapGroupedDocuments","lastContainer","texts","phone_number","wrapPoll","toggleBubbleCheckbox","needName","isForwardFromChannel","from_id","from_name","getPeerColorById","goto","generateTail","isBackLimit","previousScrollHeightMinusTop","needReflowScroll","newScrollTop","getScheduledMessages","realLoadCount","additionMsgIds","isEnd","Both","resultPromise","isAdditionRender","isFirstMessageRender","processResult","historyResult","Top","serviceStartMessageId","threadsServiceMessagesIdsStorage","sup","processPromise","waitPromise","times","targetMid","sortedMids","topIds","middleIds","bottomIds","getServerMessageId","setBubbles","animateAsLadder","lastMsDelay","topRes","middleRes","bottomRes","delays","safeCount","mustBeCount","onConfirm","revoke","deleteScheduledMessages","deleteMessages","titleArgs","langArgs","canRevoke","unpin","canUnpin","canPinMessage","oneSide","unpinAllMessages","hidePinnedMessages","updatePinnedMessage","buttonText","pinButtonText","sendScheduledMessages","attachTo","appPollsManager","onSendScheduledClick","selectionSendNowBtn","onReplyClick","initMessageReply","onEditClick","initMessageEditing","onCopyClick","selectedMids","onCopyAnchorLinkClick","onCopyLinkClick","onPinClick","onUnpinClick","onRetractVote","onStopPoll","stopPoll","onForwardClick","selectionForwardBtn","isTargetAGroupedItem","onSelectClick","onClearSelectionClick","cancelSelection","onDeleteClick","selectionDeleteBtn","onContextMenu","selectedMid","isSelectable","canSelectBubble","isTextSelected","isAnchorTarget","groupedItem","withSelection","notDirect","side","changedTouches","scheduleSending","editMessage","scheduleDate","onMessageSent","messageInput","canEditMessage","canDeleteMessage","loadedURLs","onContentClick","emojiSupported","nodeType","nodeValue","outerHTML","getEmojiFromElement","recentItemsDiv","_emoji","appendEmoji","divs","Emoji","category","emojis","itemsDiv","prev","fromCodePoint","menu","previousElementSibling","emojiScroll","recentEmoji","menuOnClick","spanEmoji","kek","opacity","scrollPromise","processVisibleDiv","getAnimations","checkAnimation","intersector","isVisible","processInvisibleDiv","visible","gifWidth","gifHeight","willUseWidth","gifsContainer","onMediaClick","masonry","EMOTICONSSTICKERGROUP","addLazyLoadQueueRepeat","regularLazyLoadQueue","animatedDivs","checkAnimationContainer","renderSticker","stickerSets","queueCategoryPush","categoryDiv","categoryTitle","superStickerRenderer","recentDiv","categoryPush","downloadOptions","getStickerSetThumbDownloadOptions","needUpscale","blob","createObjectURL","menuWrapper","menuScroll","renderStickerSet","inlineResults","botId","geo","getInputPeerById","geo_point","lat","long","stopTime","noErrorBox","botResults","queryId","query_id","qId","savePhoto","msg_id","callbackAnswer","nextOffset","onGifsClick","search","gifsDiv","newSearch","gifBotPeerId","resolveUsername","getInlineResults","setsDiv","countDiv","stickerDiv","renderFeatured","getFeaturedStickers","coveredSets","filterRendered","renderSet","searchStickerSets","tabId","onCloseAfter","onOpenAfter","forceClose","onMouseOut","displayTimeout","toElement","onSelectTabClick","searchButton","deleteBtn","checkRights","tabsEl","tabsElements","canSendStickers","toggleAttribute","canSendGifs","willBeActive","chatInput","lockIntersectionGroup","unlockIntersectionGroup","emojiTab","stickersTab","gifsTab","0","1","2","onmouseout","onmouseover","getVisible","clearVisible","prevId","jumpedTo","which","clearDraft","emoticonsDropdown","sendMenuButtons","onSilentClick","onScheduleClick","sendMenu","openSide","onContextElement","withConfirm","onSubmitClick","send","radioLabel","isEmpty","questions","appendMoreField","correctAnswers","optionInputFields","weakMap","questionInputField","sendSilent","setPeerId","dd","settingsCaption","anonymousCheckboxField","multipleCheckboxField","quizCheckboxField","quizSolutionField","quizElements","quizSolutionCaption","quizHr","quizSolutionContainer","quizSolutionSubtitle","onEscape","getFilledAnswers","question","quizSolution","valid","validate","force","quizSolutionEntities","btnClose","inputMediaPoll","getInputMediaPoll","sendOther","replyToMsgId","helperType","clearHelper","questionField","files","willAttachType","wasInputValue","willAttach","sendFileDetails","onKeyDown","attachFile","file","itemDiv","isVideo","source","objectURL","videoWidth","videoHeight","thumbBlob","thumbURL","onload","isPhoto","isAudio","onerror","mediaContainer","messageInputField","groupCheckboxField","attachFiles","isMedia","firstType","sendAlbum","sendText","sendFile","foundPhotos","foundVideos","albumsLength","albumContainer","lastEmoticon","stickersContainer","getStickersByEmoticon","ready","getMinDate","appWebPagesManager","appDraftsManager","serverTimeManager","appNotificationsManager","pageEl","btnSend","lastUrl","lastTimeType","replyElements","willSendWebPage","forwardingMids","forwardingFromPeerId","recording","recordCanceled","recordStartTime","lockRedo","canRedoFromHTML","undoHistory","executedHistory","canUndoFromHTML","onCancelRecordClick","recorder","opusDecodeController","setKeepAlive","onEmoticonsOpen","toggleClass","btnToggleEmoticons","onEmoticonsClose","sendMessage","openScheduled","prepareDocumentExecute","undoRedo","needHTML","sameHTMLTimes","currentHTML","handleMarkdownShortcut","formatKeys","getSelection","markupTooltip","showLinkEditor","applyMarkdown","shiftKey","onMessageInput","markdownEntities","richValue","parseMarkdown","mergeEntities","stickersHelper","suggest","checkEmoticon","urlEntities","saveWebPage","setTopInfo","noWebPage","helperFunc","isInputEmpty","setTyping","editMsgId","saveDraftDebounced","updateSendBtn","onBtnSendClick","analyser","createAnalyser","fftSize","frequencyData","frequencyBinCount","getByteFrequencyData","recordRippleEl","ms","recordTimeEl","onHelperCancel","needReturn","onHelperClick","helperWaitingForward","inputContainer","rowsWrapper","tail","fakeRowsWrapper","fakeSelectionWrapper","goDownBtn","onGoDownClick","cancelBtn","dac","newMessageWrapper","inputMessageContainer","goDownUnreadBadge","btnScheduled","attachMenuButtons","fileInput","attachMenu","multiple","btnCancelRecord","btnSendContainer","attachButtonListener","attachMessageInputField","draft","setDraft","saveDraft","touchMouseDown","typedArray","dataBlob","Blob","decode","isVoiceMessage","pinnedControlBtn","fakeContainer","fakePinnedControlBtn","originalChat","pinnedMessageContainer","unread_count","no_webpage","syncDraft","helperToo","clearInput","fromUpdate","getDraft","setInputValue","rMessage","oldInputField","attachMessageInputListeners","ctrlKey","metaKey","readAllHistory","commandsMap","bold","italic","underline","strikethrough","monospace","saveExecuted","executed","haveThisType","isCollapsed","getRangeAt","commonAncestorContainer","matches","setActiveMarkupButton","canSetDraft","clearReply","webPage","forwardMessages","pushRecentSticker","replyFragment","smth","peerTitles","firstMessage","usingFullAlbum","albumMids","getMidsByMessage","callerFunc","toggleSelection","isGroupedBubbleSelected","getBubbleGroupedItems","found","groupContainer","isGroupedSelected","isGroupedMidsSelected","updateBubbleSelection","seen","selecting","canceledSelection","removeManual","documentListenerOptions","isBubbleSelected","hasCheckbox","getCheckboxInputFromBubble","isGrouped","forceSelection","selectionCountEl","cantForward","cantDelete","cantSend","toggleCheckboxes","wasSelecting","borderRadius","forwards","fakeSelectionRect","fakeRowsRect","widthFrom","widthTo","scale","initTranslateX","br","selectionInputWrapper","selectionContainer","btnCancel","updateContainer","isSelected","groupedCheckboxInput","divAndCaption","CLASSNAME_BASE","needClose","isHidden","maxActive","setUtilsWidth","toggleEl","PinnedMessageBorder","drawRect","getClipPath","barHeight","clipPath","path","getBarHeight","getMarkHeight","getMarkTranslateY","getTrackTranslateY","trackHeight","getTrackHeight","markHeight","clipPathId","markTranslateY","trackTranslateY","mark","AnimatedSuper","animateFirst","new","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","hidden","getCurrentIndexPromise","isStatic","debug","pinnedMessageBorder","animatedSubtitle","animatedMedia","animatedCounter","btnOpen","openPinned","setPinnedMessage","_setPinnedMessage","unsetScrollDownListener","testMid","isNeededMore","getCurrentIndex","LOAD_OFFSET","correctAfter","gotRest","getPinnedMessage","backLimited","offset_id_offset","refreshPosition","setScrollDownListener","handleFollowingPinnedMessage","isLast","setCount","writeTo","writeMediaTo","selectedIndex","selectResult","upBtn","downBtn","foundCountEl","renderedCount","appSearch","onResultsClick","onUpClick","onDownClick","footer","dateBtn","beginSearch","onResize","onChangeScreen","chatAudio","resize","setUtilsRAF","chatUtils","chatInfo","btnBack","person","avatarElement","btnMore","getDeleteButtonText","btnJoin","btnPinned","btnMute","btnSearch","followPinnedMessage","activeScreen","onBtnBackClick","isFirstChat","joinChannel","setMutedState","isTopMessage","hiddenPinnedMessages","byCurrent","destroy","wasPeerId","newPinnedMessage","appProfileManager","wasAlreadyUsed","initPeerId","backgroundEl","contextMenu","constructUtils","constructPeerHelpers","constructPinnedHelpers","constructDiscussionHelpers","constructScheduledHelpers","searchTab","setAutoDownloadMedia","setLoadMutex","loadSidebarMedia","autoDownload","setPrefix","getMessageFromStorage","addedListener","waitingForMouseUp","mouseUpCounter","onMouseUpSingle","resetSelection","savedRange","tools1","tools2","cancelClosening","linkBackButton","linkInput","applyLink","isLinkValid","setTooltipPosition","linkApplyButton","applyDiv","delimiter1","delimiter2","delimiter3","startContainer","removeAllRanges","addRange","hideTimeout","nodes","currentMarkups","activeButtons","getActiveMarkupButton","isLinkToggle","bodyRect","selectionRect","inputRect","selectionTop","sizesRect","maxX","containerRect","isFirstShow","setMouseUpEvent","activeElement","onDragOver","onDragLeave","onDrop","outlineWrapper","dropIcon","dropHeader","dropSubtitle","sizeX","sizeY","FOCUS_EVENT_NAME","columnEl","updateStatusInterval","onHashChange","decodeURIComponent","postId","post","generateMessageId","setSettings","documentElement","nightTheme","chatsSelectTabDebounced","setLoop","onDocumentPaste","attachType","canDrag","DragEvent","_types","dataTransfer","idle","isIDLE","updateStatus","createNewChat","chatsSelectTab","STATE_INIT","getFile","saveChatPosition","sessionStorage","broadcastEvent","chatPositions","themeColor","themeColorElem","prevTab","prevIdx","overlayIsActive","goodMid","renderNewMessages","deleteDeletedMessages","attachDragAndDropListeners","handleSelection","drops","mount","isFiles","foundMedia","foundDocuments","dropsContainer","drop","setPath","transitionTime","setUserStatus","fromIndex","justReturn","spliced","chatIndex","spliceChats","existingIndex","setType","dot","isBot","typings","typingsInPeer","getTypingElement","topButtons","author","preloaderStreamable","lastTarget","isFirstOpen","loadMediaPromiseUp","loadMediaPromiseDown","loadedAllMediaUp","loadedAllMediaDown","needLoadMore","setMoverAnimationPromise","highlightSwitchersTimeout","wholeDiv","mover","MEDIA_VIEWER_CLASSNAME","overlaysDiv","mainDiv","setNewMover","onDownloadClick","setMoverPromise","windowW","evt","btnMenuToggle","setMoverToTarget","closing","fromRight","removeCenterFromMover","wasActive","realParent","SVGImageElement","SVGForeignObjectElement","needOpacity","visibleRect","overflowElement","overflowRect","overflowTop","overflowBottom","sticky","overflow","vertical","horizontal","visualViewport","windowHeight","innerWidth","innerHeight","getVisibleRect","aspecter","HTMLImageElement","HTMLVideoElement","setFullAspect","scaleX","scaleY","brSplitted","SVGSVGElement","sizeTailPath","mediaElement","newClipId","newSvg","SVGUseElement","sX","sY","proportion","upscale","_br","toLeft","newTransform","p1","newMover","timeStr","dateStr","oldAvatar","replaceChild","setAuthorInfo","useContainerAsTarget","loadMoreMedia","moveTheMover","mainColumns","thumbPromise","moverVideo","canPlayThrough","createPlayer","overlay","HAVE_FUTURE_DATA","attachCanPlay","networkState","NETWORK_LOADING","isntEnoughData","updateMediaSource","cancellablePromise","attachPromise","haveImage","currentMessageId","onAuthorClick","savePhotoFile","incrementMessageId","getMediaFromMessage","setBtnMenuToggle","_openMedia","setCaption","currentPhotoId","onAvatarUpdate","removeFromAvatarsCache","getFullPhoto","getTarget","hadMessage","isDialog","oldValue","newValue","getPeerMigratedTo","peerTitle","putPhoto","onArchiveClick","selectedId","editPeerFolders","folder_id","toggleDialogPin","onMuteClick","onUnreadClick","top_message","currentText","connecting","updating","setConnectionStatus","baseDcId","setFirstConnectionTimeout","connectionStatus","online","forceGetDifference","setStatusText","statusEl","statusPreloader","CHANGE_STATE_DELAY","setStateTimeout","statusContainer","constructContainer","doms","menuScrollContainer","lastActiveElements","loadDialogsPromise","loadDialogs","sliceTimeout","rectContainer","rectTarget","firstY","lastY","firstElement","lastElement","elementOverflow","firstIndex","sliceFromStart","sliceFromEnd","onChatsScrollTop","archivedChatList","chatsPreloader","allUnreadCount","bottomPart","addFilter","getDialogDom","validateForFilter","setFiltersUnreadCount","updateDialog","setUnreadMessages","order","containerToAppend","renderedFilter","unsetTyping","foldersScrollable","getAllDrafts","addMissedDialogs","allDialogsLoaded","wasLoaded","accumulateArchivedUnread","updatesState","syncLoading","refreshConversations","pos","topOffset","getOffset","bottomOffset","isDialogMustBeInViewport","reorderDialogs","unreadSpan","mutedCount","notMutedCount","setFilterUnreadCount","_peerId","showFiltersTimeout","needIndex","getConversationPromise","withContext","openInner","lastActiveListElement","setPeerFunc","sameElement","reorderDialogsTimeout","currentOrder","peerIdByIndex","lastMessage","highlightWord","draftMessage","lastTimeSpan","senderBold","statusSpan","unreadMessagesSpan","isPinned","accumulateArchivedTimeout","addDialog","_dialog","originalDialog","getOutputPeer","testDialogForFilter","captionDiv","titleSpanContainer","titleP","rightSpan","messageP","rFirstName","appDialogsManager"],"mappings":"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","file":"11.6f1611987776c2248d74.chunk.js","sourcesContent":["!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 { i18n, LangPackKey } from \"../lib/langPack\";\r\nimport { ripple } from \"./ripple\";\r\n\r\nconst Button = (className: string, options: Partial<{noRipple: true, onlyMobile: true, icon: string, rippleSquare: true, text: LangPackKey, disabled: boolean}> = {}) => {\r\n const button = document.createElement('button');\r\n button.className = className + (options.icon ? ' tgico-' + options.icon : '');\r\n\r\n if(!options.noRipple) {\r\n if(options.rippleSquare) {\r\n button.classList.add('rp-square');\r\n }\r\n\r\n ripple(button);\r\n }\r\n\r\n if(options.onlyMobile) {\r\n button.classList.add('only-handhelds');\r\n }\r\n\r\n if(options.disabled) {\r\n button.disabled = true;\r\n }\r\n\r\n if(options.text) {\r\n button.append(i18n(options.text));\r\n }\r\n\r\n return button;\r\n};\r\n\r\nexport default Button;\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 { getRichValue, isInputEmpty } from \"../helpers/dom\";\r\nimport { debounce } from \"../helpers/schedulers\";\r\nimport { checkRTL } from \"../helpers/string\";\r\nimport { i18n, LangPackKey, _i18n } from \"../lib/langPack\";\r\nimport RichTextProcessor from \"../lib/richtextprocessor\";\r\n\r\nlet init = () => {\r\n document.addEventListener('paste', (e) => {\r\n if(!(e.target as HTMLElement).hasAttribute('contenteditable') && !(e.target as HTMLElement).parentElement.hasAttribute('contenteditable')) {\r\n return;\r\n }\r\n //console.log('document paste');\r\n\r\n //console.log('messageInput paste');\r\n\r\n e.preventDefault();\r\n // @ts-ignore\r\n let text = (e.originalEvent || e).clipboardData.getData('text/plain');\r\n\r\n let entities = RichTextProcessor.parseEntities(text);\r\n //console.log('messageInput paste', text, entities);\r\n entities = entities.filter(e => e._ === 'messageEntityEmoji' || e._ === 'messageEntityLinebreak');\r\n //text = RichTextProcessor.wrapEmojiText(text);\r\n text = RichTextProcessor.wrapRichText(text, {entities, noLinks: true, wrappingDraft: true});\r\n\r\n // console.log('messageInput paste after', text);\r\n\r\n // @ts-ignore\r\n //let html = (e.originalEvent || e).clipboardData.getData('text/html');\r\n\r\n // @ts-ignore\r\n //console.log('paste text', text, );\r\n window.document.execCommand('insertHTML', false, text);\r\n });\r\n\r\n init = null;\r\n};\r\n\r\nconst checkAndSetRTL = (input: HTMLElement) => {\r\n //const isEmpty = isInputEmpty(input);\r\n //console.log('input', isEmpty);\r\n\r\n //const char = [...getRichValue(input)][0];\r\n const char = (input instanceof HTMLInputElement ? input.value : input.innerText)[0];\r\n let direction = 'ltr';\r\n if(char && checkRTL(char)) {\r\n direction = 'rtl';\r\n }\r\n\r\n //console.log('RTL', direction, char);\r\n\r\n input.style.direction = direction;\r\n};\r\n\r\nexport enum InputState {\r\n Neutral = 0,\r\n Valid = 1,\r\n Error = 2\r\n};\r\n\r\nexport type InputFieldOptions = {\r\n placeholder?: LangPackKey, \r\n label?: LangPackKey, \r\n labelOptions?: any[],\r\n labelText?: string,\r\n name?: string, \r\n maxLength?: number, \r\n showLengthOn?: number,\r\n plainText?: true,\r\n animate?: true\r\n};\r\n\r\nclass InputField {\r\n public container: HTMLElement;\r\n public input: HTMLElement;\r\n public inputFake: HTMLElement;\r\n public label: HTMLLabelElement;\r\n\r\n public originalValue: string;\r\n\r\n //public onLengthChange: (length: number, isOverflow: boolean) => void;\r\n protected wasInputFakeClientHeight: number;\r\n protected showScrollDebounced: () => void;\r\n\r\n constructor(public options: InputFieldOptions = {}) {\r\n this.container = document.createElement('div');\r\n this.container.classList.add('input-field');\r\n\r\n if(options.maxLength) {\r\n options.showLengthOn = Math.round(options.maxLength / 3);\r\n }\r\n\r\n const {placeholder, maxLength, showLengthOn, name, plainText} = options;\r\n\r\n let label = options.label || options.labelText;\r\n\r\n let input: HTMLElement;\r\n if(!plainText) {\r\n if(init) {\r\n init();\r\n }\r\n\r\n this.container.innerHTML = `\r\n <div contenteditable=\"true\" class=\"input-field-input\"></div>\r\n `;\r\n\r\n input = this.container.firstElementChild as HTMLElement;\r\n const observer = new MutationObserver(() => {\r\n checkAndSetRTL(input);\r\n\r\n if(processInput) {\r\n processInput();\r\n }\r\n });\r\n\r\n // * because if delete all characters there will br left\r\n input.addEventListener('input', () => {\r\n if(isInputEmpty(input)) {\r\n input.innerHTML = '';\r\n }\r\n\r\n if(this.inputFake) {\r\n this.inputFake.innerHTML = input.innerHTML;\r\n this.onFakeInput();\r\n }\r\n });\r\n \r\n // ! childList for paste first symbol\r\n observer.observe(input, {characterData: true, childList: true, subtree: true});\r\n\r\n if(options.animate) {\r\n input.classList.add('scrollable', 'scrollable-y');\r\n this.wasInputFakeClientHeight = 0;\r\n this.showScrollDebounced = debounce(() => this.input.classList.remove('no-scrollbar'), 150, false, true);\r\n this.inputFake = document.createElement('div');\r\n this.inputFake.setAttribute('contenteditable', 'true');\r\n this.inputFake.className = input.className + ' input-field-input-fake';\r\n }\r\n } else {\r\n this.container.innerHTML = `\r\n <input type=\"text\" ${name ? `name=\"${name}\"` : ''} autocomplete=\"off\" ${label ? 'required=\"\"' : ''} class=\"input-field-input\">\r\n `;\r\n\r\n input = this.container.firstElementChild as HTMLElement;\r\n input.addEventListener('input', () => checkAndSetRTL(input));\r\n }\r\n\r\n if(placeholder) {\r\n _i18n(input, placeholder, undefined, 'placeholder');\r\n\r\n if(this.inputFake) {\r\n _i18n(this.inputFake, placeholder, undefined, 'placeholder');\r\n }\r\n }\r\n\r\n if(label || placeholder) {\r\n const border = document.createElement('div');\r\n border.classList.add('input-field-border');\r\n this.container.append(border);\r\n }\r\n\r\n if(label) {\r\n this.label = document.createElement('label');\r\n this.setLabel();\r\n this.container.append(this.label);\r\n }\r\n\r\n let processInput: () => void;\r\n if(maxLength) {\r\n const labelEl = this.container.lastElementChild as HTMLLabelElement;\r\n let showingLength = false;\r\n\r\n processInput = () => {\r\n const wasError = input.classList.contains('error');\r\n // * https://stackoverflow.com/a/54369605 #2 to count emoji as 1 symbol\r\n const inputLength = plainText ? (input as HTMLInputElement).value.length : [...getRichValue(input)].length;\r\n const diff = maxLength - inputLength;\r\n const isError = diff < 0;\r\n input.classList.toggle('error', isError);\r\n\r\n //this.onLengthChange && this.onLengthChange(inputLength, isError);\r\n\r\n if(isError || diff <= showLengthOn) {\r\n this.setLabel();\r\n labelEl.append(` (${maxLength - inputLength})`);\r\n if(!showingLength) showingLength = true;\r\n } else if((wasError && !isError) || showingLength) {\r\n this.setLabel();\r\n showingLength = false;\r\n }\r\n };\r\n\r\n input.addEventListener('input', processInput);\r\n }\r\n\r\n this.input = input;\r\n }\r\n\r\n public select() {\r\n if((this.input as HTMLInputElement).value) { // * avoid selecting whole empty field on iOS devices\r\n (this.input as HTMLInputElement).select(); // * select text\r\n }\r\n }\r\n\r\n public setLabel() {\r\n this.label.textContent = '';\r\n if(this.options.labelText) {\r\n this.label.innerHTML = this.options.labelText;\r\n } else {\r\n this.label.append(i18n(this.options.label, this.options.labelOptions));\r\n }\r\n }\r\n\r\n public onFakeInput() {\r\n const {scrollHeight, clientHeight} = this.inputFake;\r\n if(this.wasInputFakeClientHeight && this.wasInputFakeClientHeight !== clientHeight) {\r\n this.input.classList.add('no-scrollbar'); // ! в сафари может вообще не появиться скролл после анимации, так как ему нужен полный reflow блока с overflow.\r\n this.showScrollDebounced();\r\n }\r\n\r\n this.wasInputFakeClientHeight = clientHeight;\r\n this.input.style.height = scrollHeight ? scrollHeight + 'px' : '';\r\n }\r\n\r\n get value() {\r\n return this.options.plainText ? (this.input as HTMLInputElement).value : getRichValue(this.input);\r\n //return getRichValue(this.input);\r\n }\r\n\r\n set value(value: string) {\r\n this.setValueSilently(value, false);\r\n\r\n const event = new Event('input', {bubbles: true, cancelable: true});\r\n this.input.dispatchEvent(event);\r\n }\r\n\r\n public setValueSilently(value: string, fireFakeInput = true) {\r\n if(this.options.plainText) {\r\n (this.input as HTMLInputElement).value = value;\r\n } else {\r\n this.input.innerHTML = value;\r\n \r\n if(this.inputFake) {\r\n this.inputFake.innerHTML = value;\r\n\r\n if(fireFakeInput) {\r\n this.onFakeInput();\r\n }\r\n }\r\n }\r\n }\r\n\r\n public isValid() {\r\n return !this.input.classList.contains('error') && this.value !== this.originalValue;\r\n }\r\n\r\n public setOriginalValue(value: InputField['originalValue'] = '', silent = false) {\r\n this.originalValue = value;\r\n\r\n if(!this.options.plainText) {\r\n value = RichTextProcessor.wrapDraftText(value);\r\n }\r\n\r\n if(silent) {\r\n this.setValueSilently(value, false); \r\n } else {\r\n this.value = value;\r\n }\r\n }\r\n\r\n public setState(state: InputState, label?: LangPackKey) {\r\n if(label) {\r\n this.label.textContent = '';\r\n this.label.append(i18n(label, this.options.labelOptions));\r\n }\r\n\r\n this.input.classList.toggle('error', !!(state & InputState.Error));\r\n this.input.classList.toggle('valid', !!(state & InputState.Valid));\r\n }\r\n\r\n public setError(label?: LangPackKey) {\r\n this.setState(InputState.Error, label);\r\n }\r\n}\r\n\r\nexport default InputField;\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 findUpClassName from \"../helpers/dom/findUpClassName\";\r\nimport sequentialDom from \"../helpers/sequentialDom\";\r\nimport {isTouchSupported} from \"../helpers/touchSupport\";\r\nimport rootScope from \"../lib/rootScope\";\r\n\r\nlet rippleClickId = 0;\r\nexport function ripple(elem: HTMLElement, callback: (id: number) => Promise<boolean | void> = () => Promise.resolve(), onEnd: (id: number) => void = null, prepend = false) {\r\n //return;\r\n if(elem.querySelector('.c-ripple')) return;\r\n elem.classList.add('rp');\r\n \r\n let r = document.createElement('div');\r\n r.classList.add('c-ripple');\r\n\r\n const isSquare = elem.classList.contains('rp-square');\r\n if(isSquare) {\r\n r.classList.add('is-square');\r\n }\r\n\r\n elem[prepend ? 'prepend' : 'append'](r);\r\n\r\n let handler: () => void;\r\n //let animationEndPromise: Promise<number>;\r\n const drawRipple = (clientX: number, clientY: number) => {\r\n const startTime = Date.now();\r\n const elem = document.createElement('div');\r\n\r\n const clickId = rippleClickId++;\r\n \r\n //console.log('ripple drawRipple');\r\n \r\n const duration = +window.getComputedStyle(r).getPropertyValue('--ripple-duration').replace('s', '') * 1000;\r\n //console.log('ripple duration', duration);\r\n\r\n handler = () => {\r\n //handler = () => animationEndPromise.then((duration) => {\r\n //console.log('ripple animation was:', duration);\r\n\r\n //const duration = isSquare || mediaSizes.isMobile ? 200 : 700;\r\n //return;\r\n let elapsedTime = Date.now() - startTime;\r\n const cb = () => {\r\n //console.log('ripple elapsedTime total pre-remove:', Date.now() - startTime);\r\n sequentialDom.mutate(() => {\r\n elem.remove();\r\n });\r\n \r\n if(onEnd) onEnd(clickId);\r\n };\r\n if(elapsedTime < duration) {\r\n let delay = Math.max(duration - elapsedTime, duration / 2);\r\n setTimeout(() => elem.classList.add('hiding'), Math.max(delay - duration / 2, 0));\r\n\r\n setTimeout(cb, delay);\r\n } else {\r\n elem.classList.add('hiding');\r\n setTimeout(cb, duration / 2);\r\n }\r\n\r\n if(!isTouchSupported) {\r\n window.removeEventListener('contextmenu', handler);\r\n }\r\n\r\n handler = null;\r\n touchStartFired = false;\r\n };\r\n //});\r\n\r\n callback && callback(clickId);\r\n\r\n /* callback().then((bad) => {\r\n if(bad) {\r\n span.remove();\r\n return;\r\n } */\r\n \r\n //console.log('ripple after promise', Date.now() - startTime);\r\n //console.log('ripple tooSlow:', tooSlow);\r\n /* if(tooSlow) {\r\n span.remove();\r\n return;\r\n } */\r\n\r\n window.requestAnimationFrame(() => {\r\n const rect = r.getBoundingClientRect();\r\n elem.classList.add('c-ripple__circle');\r\n\r\n const clickX = clientX - rect.left;\r\n const clickY = clientY - rect.top;\r\n\r\n const radius = Math.sqrt((Math.abs(clickY - rect.height / 2) + rect.height / 2) ** 2 + (Math.abs(clickX - rect.width / 2) + rect.width / 2) ** 2);\r\n const size = radius;\r\n\r\n // center of circle\r\n const x = clickX - size / 2;\r\n const y = clickY - size / 2;\r\n\r\n //console.log('ripple click', offsetFromCenter, size, clickX, clickY);\r\n\r\n elem.style.width = elem.style.height = size + 'px';\r\n elem.style.left = x + 'px';\r\n elem.style.top = y + 'px';\r\n\r\n // нижний код выполняется с задержкой\r\n /* animationEndPromise = new Promise((resolve) => {\r\n span.addEventListener('animationend', () => {\r\n // 713 -> 700\r\n resolve(((Date.now() - startTime) / 100 | 0) * 100);\r\n }, {once: true});\r\n }); */\r\n \r\n // нижний код не всегда включает анимацию ПРИ КЛИКЕ НА ТАЧПАД БЕЗ ТАПТИК ЭНЖИНА\r\n /* span.style.display = 'none';\r\n r.append(span);\r\n duration = +window.getComputedStyle(span).getPropertyValue('animation-duration').replace('s', '') * 1000;\r\n span.style.display = ''; */\r\n\r\n r.append(elem);\r\n\r\n //r.classList.add('active');\r\n //handler();\r\n });\r\n //});\r\n };\r\n\r\n // TODO: rename this variable\r\n let touchStartFired = false;\r\n if(isTouchSupported) {\r\n let touchEnd = () => {\r\n handler && handler();\r\n };\r\n \r\n elem.addEventListener('touchstart', (e) => {\r\n if(!rootScope.settings.animationsEnabled) {\r\n return;\r\n }\r\n\r\n //console.log('ripple touchstart', e);\r\n if(e.touches.length > 1 \r\n || touchStartFired \r\n || (['BUTTON', 'A'].includes((e.target as HTMLElement).tagName) && e.target !== elem) \r\n || findUpClassName(e.target as HTMLElement, 'c-ripple') !== r) {\r\n return;\r\n }\r\n \r\n //console.log('touchstart', e);\r\n touchStartFired = true;\r\n \r\n let {clientX, clientY} = e.touches[0];\r\n drawRipple(clientX, clientY);\r\n elem.addEventListener('touchend', touchEnd, {once: true});\r\n \r\n window.addEventListener('touchmove', (e) => {\r\n e.cancelBubble = true;\r\n e.stopPropagation();\r\n touchEnd();\r\n elem.removeEventListener('touchend', touchEnd);\r\n }, {once: true});\r\n }, {passive: true});\r\n } else {\r\n elem.addEventListener('mousedown', (e) => {\r\n if(![0, 2].includes(e.button)) { // only left and right buttons\r\n return;\r\n }\r\n\r\n if(!rootScope.settings.animationsEnabled) {\r\n return;\r\n }\r\n //console.log('ripple mousedown', e, e.target, findUpClassName(e.target as HTMLElement, 'c-ripple') === r);\r\n\r\n if(elem.dataset.ripple === '0' || findUpClassName(e.target as HTMLElement, 'c-ripple') !== r || (e.target as HTMLElement).tagName === 'A') {\r\n return false;\r\n } else if(touchStartFired) {\r\n touchStartFired = false;\r\n return false;\r\n }\r\n \r\n let {clientX, clientY} = e;\r\n drawRipple(clientX, clientY);\r\n window.addEventListener('mouseup', handler, {once: true});\r\n window.addEventListener('contextmenu', handler, {once: true});\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 { isTouchSupported } from \"../helpers/touchSupport\";\r\nimport { logger, LogLevels } from \"../lib/logger\";\r\nimport fastSmoothScroll, { FocusDirection } from \"../helpers/fastSmoothScroll\";\r\nimport useHeavyAnimationCheck from \"../hooks/useHeavyAnimationCheck\";\r\nimport { cancelEvent } from \"../helpers/dom\";\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 onScrollMeasure: number = 0;\r\n protected onScroll: () => void;\r\n\r\n public isHeavyAnimationInProgress = false;\r\n protected needCheckAfterAnimation = false;\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 : ''), LogLevels.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 protected setListeners() {\r\n window.addEventListener('resize', this.onScroll, {passive: true});\r\n this.container.addEventListener('scroll', this.onScroll, {passive: true, capture: true});\r\n\r\n useHeavyAnimationCheck(() => {\r\n this.isHeavyAnimationInProgress = true;\r\n\r\n if(this.onScrollMeasure) {\r\n this.needCheckAfterAnimation = true;\r\n window.cancelAnimationFrame(this.onScrollMeasure);\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 append(element: HTMLElement) {\r\n this.container.append(element);\r\n }\r\n\r\n public scrollIntoViewNew(\r\n element: HTMLElement,\r\n position: ScrollLogicalPosition,\r\n margin?: number,\r\n maxDistance?: number,\r\n forceDirection?: FocusDirection,\r\n forceDuration?: number,\r\n axis?: 'x' | 'y'\r\n ) {\r\n //return Promise.resolve();\r\n return fastSmoothScroll(this.container, element, position, margin, maxDistance, forceDirection, forceDuration, axis);\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 splitUp: HTMLElement;\r\n public padding: HTMLElement;\r\n \r\n public onAdditionalScroll: () => void = null;\r\n public onScrolledTop: () => void = null;\r\n public onScrolledBottom: () => void = null;\r\n \r\n public lastScrollTop: number = 0;\r\n public lastScrollDirection: number = 0;\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 }\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 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 if(this.onScrollMeasure) {\r\n window.cancelAnimationFrame(this.onScrollMeasure);\r\n }\r\n\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) window.cancelAnimationFrame(this.onScrollMeasure);\r\n this.onScrollMeasure = window.requestAnimationFrame(() => {\r\n this.onScrollMeasure = 0;\r\n\r\n const scrollTop = this.container.scrollTop;\r\n this.lastScrollDirection = this.lastScrollTop === scrollTop ? 0 : (this.lastScrollTop < scrollTop ? 1 : -1); // * 1 - bottom, -1 - top\r\n this.lastScrollTop = scrollTop;\r\n\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 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.lastScrollTop;\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[]) {\r\n (this.splitUp || this.padding || this.container).prepend(...elements);\r\n }\r\n\r\n public append(...elements: HTMLElement[]) {\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 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(!isTouchSupported) {\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}\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 { getDeepProperty } from \"../helpers/object\";\r\nimport { ripple } from \"./ripple\";\r\nimport { LangPackKey, _i18n } from \"../lib/langPack\";\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 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.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 this.checked = getDeepProperty(state, options.stateKey);\r\n\r\n input.addEventListener('change', () => {\r\n appStateManager.setByKey(options.stateKey, input.checked);\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 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 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\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\n\r\nexport class SearchGroup {\r\n container: HTMLDivElement;\r\n nameEl: HTMLDivElement;\r\n list: HTMLUListElement;\r\n\r\n constructor(public name: string, 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 this.nameEl.innerText = name;\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 public listsContainer: HTMLDivElement = null;\r\n\r\n private peerId = 0; // 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 = 0;\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?: number, threadId?: number) {\r\n if(peerId) {\r\n this.peerId = peerId;\r\n }\r\n\r\n if(threadId) {\r\n this.threadId = threadId;\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 const {dialog, dom} = appDialogsManager.addDialogNew({\r\n dialog: message.peerId, \r\n container: this.scrollable/* searchGroup.list */, \r\n drawStatus: false,\r\n avatarSize: 54\r\n });\r\n appDialogsManager.setLastMessage(dialog, message, dom, query);\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 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 type { RootScope } from \"../lib/rootScope\";\r\nimport { ArgumentTypes } from \"../types\";\r\n\r\n/* export type Listener<T extends ListenerElement> = {\r\n element: ListenerElement, \r\n event: ListenerEvent<T>, \r\n callback: ListenerCallback<T>, \r\n options?: ListenerOptions\r\n};\r\n\r\nexport type ListenerElement = HTMLElement | RootScope;\r\nexport type ListenerEvent<T extends ListenerElement> = ArgumentTypes<T['addEventListener']>[0];\r\nexport type ListenerCallback<T extends ListenerElement> = ArgumentTypes<T['addEventListener']>[1];\r\nexport type ListenerOptions = any; */\r\nexport type Listener<T extends ListenerElement> = {\r\n element: ListenerElement, \r\n event: ListenerEvent<T>, \r\n callback: ListenerCallback, \r\n options?: ListenerOptions\r\n};\r\n\r\nexport type ListenerElement = Window | Document | HTMLElement | Element | RootScope | any;\r\n//export type ListenerEvent<T extends ListenerElement> = ArgumentTypes<T['addEventListener']>[0];\r\nexport type ListenerEvent<T extends ListenerElement> = string;\r\nexport type ListenerCallback = (...args: any[]) => any;\r\nexport type ListenerOptions = any;\r\n\r\nexport default class ListenerSetter {\r\n private listeners: Set<Listener<any>> = new Set();\r\n\r\n public add<T extends ListenerElement>(element: T, event: ListenerEvent<T>, callback: ListenerCallback, options?: ListenerOptions) {\r\n const listener: Listener<T> = {element, event, callback, options};\r\n this.addManual(listener);\r\n return listener;\r\n }\r\n\r\n public addManual<T extends ListenerElement>(listener: Listener<T>) {\r\n // @ts-ignore\r\n listener.element.addEventListener(listener.event, listener.callback, listener.options);\r\n this.listeners.add(listener);\r\n }\r\n\r\n public remove<T extends ListenerElement>(listener: Listener<T>) {\r\n // @ts-ignore\r\n listener.element.removeEventListener(listener.event, listener.callback, listener.options);\r\n this.listeners.delete(listener);\r\n }\r\n\r\n public removeManual<T extends ListenerElement>(element: T, event: ListenerEvent<T>, callback: ListenerCallback, options?: ListenerOptions) {\r\n let listener: Listener<T>;\r\n for(const _listener of this.listeners) {\r\n if(_listener.element === element && _listener.event === event && _listener.callback === callback && _listener.options === options) {\r\n listener = _listener;\r\n break;\r\n }\r\n }\r\n\r\n if(listener) {\r\n this.remove(listener);\r\n }\r\n }\r\n\r\n public removeAll() {\r\n this.listeners.forEach(listener => {\r\n this.remove(listener);\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 Button from \"./button\";\r\n\r\nconst ButtonIcon = (className: string, options: Partial<{noRipple: true, onlyMobile: true}> = {}) => {\r\n const button = Button('btn-icon', {icon: className, ...options});\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 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('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 const result = this.init();\r\n this.init = null;\r\n\r\n if(result instanceof Promise) {\r\n try {\r\n await result;\r\n } catch(err) {\r\n console.error('open tab error', err);\r\n }\r\n }\r\n }\r\n\r\n return 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 { attachClickEvent } from \"../helpers/dom\";\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 { safeAssign } from \"../helpers/object\";\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 this.historyTabIds.findAndSplice(i => i === 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 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 this.container.addEventListener('click', () => {\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 appSidebarLeft 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 { SearchGroup } from \"../../appSearch\";\r\nimport Button from \"../../button\";\r\nimport InputField from \"../../inputField\";\r\nimport { SliderSuperTab } from \"../../slider\";\r\nimport AvatarEdit from \"../../avatarEdit\";\r\nimport { i18n } from \"../../../lib/langPack\";\r\n\r\nexport default class AppNewGroupTab extends SliderSuperTab {\r\n private searchGroup = new SearchGroup(' ', 'contacts', true, 'new-group-members disable-hover', false);\r\n private avatarEdit: AvatarEdit;\r\n private uploadAvatar: () => Promise<InputFile> = null;\r\n private userIds: number[];\r\n private nextBtn: HTMLButtonElement;\r\n private groupNameInputField: InputField;\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 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 inputWrapper.append(this.groupNameInputField.container);\r\n\r\n this.groupNameInputField.input.addEventListener('input', () => {\r\n const value = this.groupNameInputField.value;\r\n this.nextBtn.classList.toggle('is-visible', !!value.length && !this.groupNameInputField.input.classList.contains('error'));\r\n });\r\n\r\n this.nextBtn = Button('btn-corner btn-circle', {icon: 'arrow_next'});\r\n\r\n this.nextBtn.addEventListener('click', () => {\r\n const title = this.groupNameInputField.value;\r\n\r\n this.nextBtn.disabled = true;\r\n appChatsManager.createChat(title, this.userIds).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 const chatsContainer = document.createElement('div');\r\n chatsContainer.classList.add('chatlist-container');\r\n chatsContainer.append(this.searchGroup.container);\r\n\r\n this.content.append(this.nextBtn);\r\n this.scrollable.append(this.avatarEdit.container, inputWrapper, chatsContainer);\r\n }\r\n\r\n public onCloseAfterTimeout() {\r\n this.searchGroup.clear();\r\n this.avatarEdit.clear();\r\n this.uploadAvatar = null;\r\n this.groupNameInputField.value = '';\r\n this.nextBtn.disabled = false;\r\n }\r\n\r\n public open(userIds: number[]) {\r\n const result = super.open();\r\n result.then(() => {\r\n this.userIds = userIds;\r\n\r\n this.userIds.forEach(userId => {\r\n let {dom} = appDialogsManager.addDialogNew({\r\n dialog: userId,\r\n container: this.searchGroup.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 this.searchGroup.nameEl.textContent = '';\r\n this.searchGroup.nameEl.append(i18n('Members', [this.userIds.length]));\r\n this.searchGroup.setActive();\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 rootScope from \"../lib/rootScope\";\r\nimport appMessagesManager from \"../lib/appManagers/appMessagesManager\";\r\nimport appDocsManager, {MyDocument} from \"../lib/appManagers/appDocsManager\";\r\nimport { CancellablePromise, deferredPromise } from \"../helpers/cancellablePromise\";\r\nimport { isSafari } from \"../helpers/userAgent\";\r\nimport { MOUNT_CLASS_TO } from \"../config/debug\";\r\n\r\n// TODO: если удалить сообщение, и при этом аудио будет играть - оно не остановится, и можно будет по нему перейти вникуда\r\n\r\n// TODO: Safari: проверить стрим, включить его и сразу попробовать включить видео или другую песню\r\n// TODO: Safari: попробовать замаскировать подгрузку последнего чанка\r\n// TODO: Safari: пофиксить момент, когда заканчивается песня и пытаешься включить её заново - прогресс сразу в конце\r\n\r\ntype HTMLMediaElement = HTMLAudioElement | HTMLVideoElement;\r\n\r\ntype MediaType = 'voice' | 'audio' | 'round';\r\n\r\nclass AppMediaPlaybackController {\r\n private container: HTMLElement;\r\n private media: {\r\n [peerId: string]: {\r\n [mid: string]: HTMLMediaElement\r\n }\r\n } = {};\r\n private playingMedia: HTMLMediaElement;\r\n\r\n private waitingMediaForLoad: {\r\n [peerId: string]: {\r\n [mid: string]: CancellablePromise<void>\r\n }\r\n } = {};\r\n \r\n public willBePlayedMedia: HTMLMediaElement;\r\n\r\n private currentPeerId: number;\r\n private prevMid: number;\r\n private nextMid: number;\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\r\n public addMedia(peerId: number, doc: MyDocument, mid: number, autoload = true): HTMLMediaElement {\r\n const storage = this.media[peerId] ?? (this.media[peerId] = {});\r\n if(storage[mid]) return storage[mid];\r\n\r\n const media = document.createElement(doc.type === 'round' ? '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 media.dataset.mid = '' + mid;\r\n media.dataset.type = doc.type;\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('playing', () => {\r\n this.currentPeerId = peerId;\r\n\r\n //console.log('appMediaPlaybackController: video playing', this.currentPeerId, this.playingMedia, media);\r\n\r\n if(this.playingMedia !== media) {\r\n if(this.playingMedia && !this.playingMedia.paused) {\r\n this.playingMedia.pause();\r\n }\r\n \r\n this.playingMedia = media;\r\n this.loadSiblingsMedia(peerId, doc.type as MediaType, mid);\r\n }\r\n\r\n // audio_pause не успеет сработать без таймаута\r\n setTimeout(() => {\r\n rootScope.broadcast('audio_play', {peerId, doc, mid});\r\n }, 0);\r\n });\r\n\r\n media.addEventListener('pause', this.onPause);\r\n media.addEventListener('ended', this.onEnded);\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 waitingStorage = this.waitingMediaForLoad[peerId] ?? (this.waitingMediaForLoad[peerId] = {});\r\n waitingStorage[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 ((!doc.supportsStreaming ? appDocsManager.downloadDoc(doc) : Promise.resolve()) as Promise<any>).then(() => {\r\n if(doc.type === 'audio' && doc.supportsStreaming && isSafari) {\r\n this.handleSafariStreamable(media);\r\n }\r\n \r\n media.src = doc.url;\r\n });\r\n }, onError);\r\n \r\n return storage[mid] = media;\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: number, mid: number) {\r\n const storage = this.waitingMediaForLoad[peerId] ?? (this.waitingMediaForLoad[peerId] = {});\r\n const promise = storage[mid];\r\n if(promise) {\r\n promise.resolve();\r\n delete storage[mid];\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 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 rootScope.broadcast('audio_pause');\r\n };\r\n\r\n onEnded = (e?: Event) => {\r\n this.onPause(e);\r\n\r\n //console.log('on media end');\r\n\r\n if(this.nextMid) {\r\n const media = this.media[this.currentPeerId][this.nextMid];\r\n\r\n /* if(isSafari) {\r\n media.autoplay = true;\r\n } */\r\n\r\n this.resolveWaitingForLoadMedia(this.currentPeerId, this.nextMid);\r\n\r\n setTimeout(() => {\r\n media.play()//.catch(() => {});\r\n }, 0);\r\n }\r\n };\r\n\r\n private loadSiblingsMedia(peerId: number, type: MediaType, mid: number) {\r\n const media = this.playingMedia;\r\n this.prevMid = this.nextMid = 0;\r\n\r\n return appMessagesManager.getSearch({\r\n peerId, \r\n query: '', \r\n inputFilter: {\r\n //_: type === 'audio' ? 'inputMessagesFilterMusic' : (type === 'round' ? 'inputMessagesFilterRoundVideo' : 'inputMessagesFilterVoice')\r\n _: type === 'audio' ? 'inputMessagesFilterMusic' : 'inputMessagesFilterRoundVoice'\r\n },\r\n maxId: mid,\r\n limit: 3,\r\n backLimit: 2\r\n }).then(value => {\r\n if(this.playingMedia !== media) {\r\n return;\r\n }\r\n \r\n for(const {mid: m} of value.history) {\r\n if(m > mid) {\r\n this.nextMid = m;\r\n } else if(m < mid) {\r\n this.prevMid = m;\r\n break;\r\n }\r\n }\r\n\r\n [this.prevMid, this.nextMid].filter(Boolean).forEach(mid => {\r\n const message = appMessagesManager.getMessageByPeer(peerId, mid);\r\n this.addMedia(peerId, message.media.document, mid, false);\r\n });\r\n \r\n //console.log('loadSiblingsAudio', audio, type, mid, value, this.prevMid, this.nextMid);\r\n });\r\n }\r\n \r\n public toggle() {\r\n if(!this.playingMedia) return;\r\n\r\n if(this.playingMedia.paused) {\r\n this.playingMedia.play();\r\n } else {\r\n this.playingMedia.pause();\r\n }\r\n }\r\n\r\n public pause() {\r\n if(!this.playingMedia || this.playingMedia.paused) return;\r\n this.playingMedia.pause();\r\n }\r\n\r\n public willBePlayed(media: HTMLMediaElement) {\r\n this.willBePlayedMedia = media;\r\n }\r\n}\r\n\r\nconst appMediaPlaybackController = new AppMediaPlaybackController();\r\nMOUNT_CLASS_TO.appMediaPlaybackController = appMediaPlaybackController;\r\nexport default appMediaPlaybackController;\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 { isTouchSupported } from \"../helpers/touchSupport\";\r\nimport { clamp } from \"../helpers/number\";\r\n\r\ntype SUPEREVENT = MouseEvent | TouchEvent;\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\r\n private events: Partial<{\r\n //onMouseMove: ProgressLine['onMouseMove'],\r\n onMouseDown: RangeSelector['onMouseDown'],\r\n onMouseUp: RangeSelector['onMouseUp'],\r\n onScrub: (scrubTime: number) => void\r\n }> = {};\r\n\r\n protected decimals: number;\r\n\r\n constructor(protected step: number, protected value: number, protected min: number, protected max: number) {\r\n this.container = document.createElement('div');\r\n this.container.classList.add('progress-line');\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 = '' + step;\r\n seek.min = '' + this.min;\r\n seek.max = '' + this.max;\r\n seek.value = '' + value;\r\n\r\n /* this.seek.addEventListener('change', (e) => {\r\n console.log('seek change', e);\r\n }); */\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 public setHandlers(events: RangeSelector['events']) {\r\n this.events = events;\r\n }\r\n\r\n onMouseMove = (e: SUPEREVENT) => {\r\n this.mousedown && this.scrub(e);\r\n };\r\n\r\n onMouseDown = (e: SUPEREVENT) => {\r\n this.scrub(e);\r\n this.mousedown = true;\r\n this.events?.onMouseDown && this.events.onMouseDown(e);\r\n };\r\n\r\n onMouseUp = (e: SUPEREVENT) => {\r\n this.mousedown = false;\r\n this.events?.onMouseUp && this.events.onMouseUp(e);\r\n };\r\n\r\n public setListeners() {\r\n this.container.addEventListener('mousemove', this.onMouseMove);\r\n this.container.addEventListener('mousedown', this.onMouseDown);\r\n this.container.addEventListener('mouseup', this.onMouseUp);\r\n\r\n if(isTouchSupported) {\r\n this.container.addEventListener('touchmove', this.onMouseMove, {passive: true});\r\n this.container.addEventListener('touchstart', this.onMouseDown, {passive: true});\r\n this.container.addEventListener('touchend', this.onMouseUp, {passive: true});\r\n }\r\n }\r\n\r\n public setProgress(value: number) {\r\n this.setFilled(value);\r\n this.seek.value = '' + value;\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 //console.log('setFilled', percents, value);\r\n this.filled.style.width = (percents * 100) + '%';\r\n //this.filled.style.transform = 'scaleX(' + scaleX + ')';\r\n }\r\n\r\n protected scrub(e: SUPEREVENT) {\r\n let offsetX: number;\r\n const rect = (e.target as HTMLElement).getBoundingClientRect();\r\n if(e instanceof MouseEvent) {\r\n offsetX = e.pageX - Math.round(rect.left);\r\n } else { // touch\r\n offsetX = e.targetTouches[0].pageX - Math.round(rect.left);\r\n }\r\n\r\n let value = this.min + (offsetX / Math.round(rect.width) * (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 //console.log('scrub value:', value, this.decimals, offsetX, rect.width, e);\r\n value = +value.toFixed(this.decimals);\r\n //const dotIndex = ('' + value).indexOf('.');\r\n //value = +('' + value).slice(0, this.decimals ? dotIndex + this.decimals : dotIndex);\r\n\r\n value = clamp(value, this.min, this.max);\r\n\r\n this.setFilled(value);\r\n\r\n this.events?.onScrub && this.events.onScrub(value);\r\n return value;\r\n }\r\n\r\n public removeListeners() {\r\n this.container.removeEventListener('mousemove', this.onMouseMove);\r\n this.container.removeEventListener('mousedown', this.onMouseDown);\r\n this.container.removeEventListener('mouseup', this.onMouseUp);\r\n\r\n if(isTouchSupported) {\r\n this.container.removeEventListener('touchmove', this.onMouseMove);\r\n this.container.removeEventListener('touchstart', this.onMouseDown);\r\n this.container.removeEventListener('touchend', this.onMouseUp);\r\n }\r\n\r\n this.events = {};\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\";\r\nimport appMediaPlaybackController from \"../components/appMediaPlaybackController\";\r\nimport { isAppleMobile } from \"../helpers/userAgent\";\r\nimport { isTouchSupported } from \"../helpers/touchSupport\";\r\nimport RangeSelector from \"../components/rangeSelector\";\r\nimport { onVideoLoad } from \"../helpers/files\";\r\n\r\ntype SUPEREVENT = MouseEvent | TouchEvent;\r\n\r\nexport class MediaProgressLine extends RangeSelector {\r\n private filledLoad: HTMLDivElement;\r\n \r\n private stopAndScrubTimeout = 0;\r\n private progressRAF = 0;\r\n\r\n constructor(private media: HTMLAudioElement | HTMLVideoElement, private streamable = false) {\r\n super(1000 / 60 / 1000, 0, 0, 1);\r\n\r\n if(streamable) {\r\n this.filledLoad = document.createElement('div');\r\n this.filledLoad.classList.add('progress-line__filled', 'progress-line__loaded');\r\n this.container.prepend(this.filledLoad);\r\n //this.setLoadProgress();\r\n }\r\n\r\n if(!media.paused || media.currentTime > 0) {\r\n this.onPlay();\r\n }\r\n\r\n this.setSeekMax();\r\n this.setListeners();\r\n this.setHandlers({\r\n onMouseDown: (e: SUPEREVENT) => {\r\n //super.onMouseDown(e);\r\n \r\n //Таймер для того, чтобы стопать видео, если зажал мышку и не отпустил клик\r\n if(this.stopAndScrubTimeout) { // возможно лишнее\r\n clearTimeout(this.stopAndScrubTimeout);\r\n }\r\n \r\n this.stopAndScrubTimeout = window.setTimeout(() => {\r\n !this.media.paused && this.media.pause();\r\n this.stopAndScrubTimeout = 0;\r\n }, 150);\r\n },\r\n\r\n onMouseUp: (e: SUPEREVENT) => {\r\n //super.onMouseUp(e);\r\n \r\n if(this.stopAndScrubTimeout) {\r\n clearTimeout(this.stopAndScrubTimeout);\r\n this.stopAndScrubTimeout = 0;\r\n }\r\n \r\n this.media.paused && this.media.play();\r\n }\r\n })\r\n }\r\n\r\n onLoadedData = () => {\r\n this.max = this.media.duration;\r\n this.seek.setAttribute('max', '' + this.max);\r\n };\r\n\r\n onEnded = () => {\r\n this.setProgress();\r\n };\r\n\r\n onPlay = () => {\r\n let r = () => {\r\n this.setProgress();\r\n\r\n this.progressRAF = this.media.paused ? 0 : window.requestAnimationFrame(r);\r\n };\r\n\r\n if(this.progressRAF) {\r\n window.cancelAnimationFrame(this.progressRAF);\r\n }\r\n\r\n if(this.streamable) {\r\n this.setLoadProgress();\r\n }\r\n\r\n this.progressRAF = window.requestAnimationFrame(r);\r\n };\r\n\r\n onProgress = (e: Event) => {\r\n this.setLoadProgress();\r\n };\r\n\r\n protected scrub(e: MouseEvent) {\r\n const scrubTime = super.scrub(e);\r\n this.media.currentTime = scrubTime;\r\n return scrubTime;\r\n }\r\n\r\n protected setLoadProgress() {\r\n if(appMediaPlaybackController.isSafariBuffering(this.media)) return;\r\n const buf = this.media.buffered;\r\n const numRanges = buf.length;\r\n\r\n const currentTime = this.media.currentTime;\r\n let nearestStart = 0, end = 0;\r\n for(let i = 0; i < numRanges; ++i) {\r\n const start = buf.start(i);\r\n if(currentTime >= start && start >= nearestStart) {\r\n nearestStart = start;\r\n end = buf.end(i);\r\n }\r\n\r\n //console.log('onProgress range:', i, buf.start(i), buf.end(i), this.media);\r\n }\r\n\r\n //console.log('onProgress correct range:', nearestStart, end, this.media);\r\n\r\n const percents = this.media.duration ? end / this.media.duration : 0;\r\n this.filledLoad.style.width = (percents * 100) + '%';\r\n //this.filledLoad.style.transform = 'scaleX(' + percents + ')';\r\n }\r\n\r\n protected setSeekMax() {\r\n this.max = this.media.duration || 0;\r\n if(this.max > 0) {\r\n this.onLoadedData();\r\n } else {\r\n this.media.addEventListener('loadeddata', this.onLoadedData);\r\n }\r\n }\r\n\r\n public setProgress() {\r\n if(appMediaPlaybackController.isSafariBuffering(this.media)) return;\r\n const currentTime = this.media.currentTime;\r\n\r\n super.setProgress(currentTime);\r\n }\r\n\r\n public setListeners() {\r\n super.setListeners();\r\n this.media.addEventListener('ended', this.onEnded);\r\n this.media.addEventListener('play', this.onPlay);\r\n this.streamable && this.media.addEventListener('progress', this.onProgress);\r\n }\r\n\r\n public removeListeners() {\r\n super.removeListeners();\r\n\r\n this.media.removeEventListener('loadeddata', this.onLoadedData);\r\n this.media.removeEventListener('ended', this.onEnded);\r\n this.media.removeEventListener('play', this.onPlay);\r\n this.streamable && this.media.removeEventListener('progress', this.onProgress);\r\n\r\n if(this.stopAndScrubTimeout) {\r\n clearTimeout(this.stopAndScrubTimeout);\r\n }\r\n\r\n if(this.progressRAF) {\r\n window.cancelAnimationFrame(this.progressRAF);\r\n }\r\n }\r\n}\r\n\r\nlet lastVolume = 1, muted = !lastVolume;\r\nexport default class VideoPlayer {\r\n public wrapper: HTMLDivElement;\r\n public progress: MediaProgressLine;\r\n private skin: string;\r\n\r\n /* private videoParent: HTMLElement;\r\n private videoWhichChild: number; */\r\n\r\n constructor(public video: HTMLVideoElement, play = false, streamable = false, duration?: number) {\r\n this.wrapper = document.createElement('div');\r\n this.wrapper.classList.add('ckin__player');\r\n\r\n video.parentNode.insertBefore(this.wrapper, video);\r\n this.wrapper.appendChild(video);\r\n\r\n this.skin = video.dataset.ckin ?? 'default';\r\n\r\n this.stylePlayer(duration);\r\n\r\n if(this.skin === 'default') {\r\n let controls = this.wrapper.querySelector('.default__controls.ckin__controls') as HTMLDivElement;\r\n this.progress = new MediaProgressLine(video, streamable);\r\n controls.prepend(this.progress.container);\r\n }\r\n\r\n if(play/* && video.paused */) {\r\n const promise = video.play();\r\n promise.catch((err: Error) => {\r\n if(err.name === 'NotAllowedError') {\r\n video.muted = true;\r\n video.autoplay = true;\r\n video.play();\r\n }\r\n }).finally(() => { // due to autoplay, play will not call\r\n this.wrapper.classList.toggle('is-playing', !this.video.paused);\r\n });\r\n //(this.wrapper.querySelector('.toggle') as HTMLButtonElement).click();\r\n }\r\n }\r\n\r\n private stylePlayer(initDuration: number) {\r\n const {wrapper: player, video, skin} = this;\r\n\r\n player.classList.add(skin);\r\n \r\n const html = this.buildControls();\r\n player.insertAdjacentHTML('beforeend', html);\r\n let timeDuration: HTMLElement;\r\n \r\n if(skin === 'default') {\r\n const toggle = player.querySelectorAll('.toggle') as NodeListOf<HTMLElement>;\r\n const fullScreenButton = player.querySelector('.fullscreen') as HTMLElement;\r\n const timeElapsed = player.querySelector('#time-elapsed');\r\n timeDuration = player.querySelector('#time-duration') as HTMLElement;\r\n timeDuration.innerHTML = String(video.duration | 0).toHHMMSS();\r\n\r\n const volumeDiv = document.createElement('div');\r\n volumeDiv.classList.add('player-volume');\r\n\r\n volumeDiv.innerHTML = `\r\n <svg class=\"player-volume__icon\" focusable=\"false\" viewBox=\"0 0 24 24\" aria-hidden=\"true\"></svg>\r\n `;\r\n const volumeSvg = volumeDiv.firstElementChild as SVGSVGElement;\r\n\r\n volumeSvg.addEventListener('click', (e) => {\r\n cancelEvent(e);\r\n video.muted = !video.muted;\r\n });\r\n\r\n const volumeProgress = new RangeSelector(0.01, 1, 0, 1);\r\n volumeProgress.setListeners();\r\n volumeProgress.setHandlers({\r\n onScrub: currentTime => {\r\n const value = Math.max(Math.min(currentTime, 1), 0);\r\n\r\n //console.log('volume scrub:', currentTime, value);\r\n\r\n video.muted = false;\r\n video.volume = value;\r\n }\r\n });\r\n volumeDiv.append(volumeProgress.container);\r\n\r\n const setVolume = () => {\r\n const volume = video.volume;\r\n let d: string;\r\n if(!volume || video.muted) {\r\n d = `M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z`;\r\n } else if(volume > .5) {\r\n d = `M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z`;\r\n } else if(volume > 0 && volume < .25) {\r\n d = `M7 9v6h4l5 5V4l-5 5H7z`;\r\n } else {\r\n d = `M18.5 12c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM5 9v6h4l5 5V4L9 9H5z`;\r\n }\r\n\r\n try {\r\n volumeSvg.innerHTML = `<path d=\"${d}\"></path>`;\r\n } catch(err) {}\r\n\r\n if(!volumeProgress.mousedown) {\r\n volumeProgress.setProgress(video.muted ? 0 : volume);\r\n }\r\n };\r\n \r\n // не вызовется повторно если на 1 установить 1\r\n video.addEventListener('volumechange', () => {\r\n muted = video.muted;\r\n lastVolume = video.volume;\r\n setVolume();\r\n });\r\n\r\n video.volume = lastVolume;\r\n video.muted = muted;\r\n\r\n setVolume();\r\n\r\n // volume end\r\n\r\n const leftControls = player.querySelector('.left-controls');\r\n leftControls.insertBefore(volumeDiv, timeElapsed.parentElement);\r\n\r\n Array.from(toggle).forEach((button) => {\r\n return button.addEventListener('click', () => {\r\n this.togglePlay();\r\n });\r\n });\r\n\r\n video.addEventListener('click', () => {\r\n if(!isTouchSupported) {\r\n this.togglePlay();\r\n return;\r\n }\r\n });\r\n\r\n if(isTouchSupported) {\r\n let showControlsTimeout = 0;\r\n\r\n const t = () => {\r\n showControlsTimeout = window.setTimeout(() => {\r\n showControlsTimeout = 0;\r\n player.classList.remove('show-controls');\r\n }, 3e3);\r\n };\r\n\r\n player.addEventListener('click', () => {\r\n if(showControlsTimeout) {\r\n clearTimeout(showControlsTimeout);\r\n } else {\r\n player.classList.add('show-controls');\r\n }\r\n \r\n t();\r\n });\r\n\r\n player.addEventListener('touchstart', () => {\r\n player.classList.add('show-controls');\r\n clearTimeout(showControlsTimeout);\r\n });\r\n\r\n player.addEventListener('touchend', () => {\r\n if(player.classList.contains('is-playing')) {\r\n t();\r\n }\r\n });\r\n }\r\n \r\n /* player.addEventListener('click', (e) => {\r\n if(e.target !== player) {\r\n return;\r\n }\r\n\r\n this.togglePlay();\r\n }); */\r\n \r\n /* video.addEventListener('play', () => {\r\n }); */\r\n\r\n video.addEventListener('dblclick', () => {\r\n if(isTouchSupported) {\r\n return;\r\n }\r\n\r\n return this.toggleFullScreen(fullScreenButton);\r\n })\r\n\r\n fullScreenButton.addEventListener('click', (e) => {\r\n return this.toggleFullScreen(fullScreenButton);\r\n });\r\n\r\n 'webkitfullscreenchange mozfullscreenchange fullscreenchange MSFullscreenChange'.split(' ').forEach(eventName => {\r\n player.addEventListener(eventName, this.onFullScreen, false);\r\n });\r\n\r\n video.addEventListener('timeupdate', () => {\r\n timeElapsed.innerHTML = String(video.currentTime | 0).toHHMMSS();\r\n });\r\n }\r\n\r\n video.addEventListener('play', () => {\r\n this.wrapper.classList.add('is-playing');\r\n });\r\n\r\n video.addEventListener('pause', () => {\r\n this.wrapper.classList.remove('is-playing');\r\n });\r\n \r\n if(video.duration || initDuration) {\r\n timeDuration.innerHTML = String(Math.round(video.duration || initDuration)).toHHMMSS();\r\n } else {\r\n onVideoLoad(video).then(() => {\r\n timeDuration.innerHTML = String(Math.round(video.duration)).toHHMMSS();\r\n });\r\n }\r\n }\r\n\r\n public togglePlay(stop?: boolean) {\r\n //console.log('video togglePlay:', stop, this.video.paused);\r\n\r\n if(stop) {\r\n this.video.pause();\r\n this.wrapper.classList.remove('is-playing');\r\n return;\r\n } else if(stop === false) {\r\n this.video.play();\r\n this.wrapper.classList.add('is-playing');\r\n return;\r\n }\r\n \r\n this.video[this.video.paused ? 'play' : 'pause']();\r\n //this.wrapper.classList.toggle('is-playing', !this.video.paused);\r\n }\r\n\r\n private buildControls() {\r\n const skin = this.skin;\r\n if(skin === 'default') {\r\n return `\r\n <button class=\"${skin}__button--big toggle tgico\" title=\"Toggle Play\"></button>\r\n <div class=\"${skin}__gradient-bottom ckin__controls\"></div>\r\n <div class=\"${skin}__controls ckin__controls\">\r\n <div class=\"bottom-controls\">\r\n <div class=\"left-controls\">\r\n <button class=\"${skin}__button toggle tgico\" title=\"Toggle Video\"></button>\r\n <div class=\"time\">\r\n <time id=\"time-elapsed\">0:00</time>\r\n <span> / </span>\r\n <time id=\"time-duration\">0:00</time>\r\n </div>\r\n </div>\r\n <div class=\"right-controls\">\r\n <button class=\"${skin}__button fullscreen tgico-fullscreen\" title=\"Full Screen\"></button>\r\n </div>\r\n </div>\r\n </div>`;\r\n }\r\n }\r\n\r\n public static isFullScreen(): boolean {\r\n // @ts-ignore\r\n return !!(document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement);\r\n }\r\n \r\n public toggleFullScreen(fullScreenButton: HTMLElement) {\r\n // alternative standard method\r\n const player = this.wrapper;\r\n\r\n // * https://caniuse.com/#feat=fullscreen\r\n if(isAppleMobile) {\r\n const video = this.video as any;\r\n video.webkitEnterFullscreen();\r\n video.enterFullscreen();\r\n return;\r\n }\r\n \r\n if(!VideoPlayer.isFullScreen()) {\r\n player.classList.add('ckin__fullscreen');\r\n\r\n /* const videoParent = this.video.parentElement;\r\n const videoWhichChild = whichChild(this.video);\r\n const needVideoRemount = videoParent !== player;\r\n\r\n if(needVideoRemount) {\r\n this.videoParent = videoParent;\r\n this.videoWhichChild = videoWhichChild;\r\n player.prepend(this.video);\r\n } */\r\n \r\n if(player.requestFullscreen) {\r\n player.requestFullscreen();\r\n // @ts-ignore\r\n } else if(player.mozRequestFullScreen) {\r\n // @ts-ignore\r\n player.mozRequestFullScreen(); // Firefox\r\n // @ts-ignore\r\n } else if(player.webkitRequestFullscreen) {\r\n // @ts-ignore\r\n player.webkitRequestFullscreen(); // Chrome and Safari\r\n // @ts-ignore\r\n } else if(player.msRequestFullscreen) {\r\n // @ts-ignore\r\n player.msRequestFullscreen();\r\n }\r\n \r\n fullScreenButton.classList.remove('tgico-fullscreen');\r\n fullScreenButton.classList.add('tgico-smallscreen');\r\n fullScreenButton.setAttribute('title', 'Exit Full Screen');\r\n } else {\r\n player.classList.remove('ckin__fullscreen');\r\n\r\n /* if(this.videoParent) {\r\n const {videoWhichChild, videoParent} = this;\r\n if(!videoWhichChild) {\r\n videoParent.prepend(this.video);\r\n } else {\r\n videoParent.insertBefore(this.video, videoParent.children[videoWhichChild]);\r\n }\r\n\r\n this.videoParent = null;\r\n this.videoWhichChild = -1;\r\n } */\r\n \r\n // @ts-ignore\r\n if(document.cancelFullScreen) {\r\n // @ts-ignore\r\n document.cancelFullScreen();\r\n // @ts-ignore\r\n } else if(document.mozCancelFullScreen) {\r\n // @ts-ignore\r\n document.mozCancelFullScreen();\r\n // @ts-ignore\r\n } else if(document.webkitCancelFullScreen) {\r\n // @ts-ignore\r\n document.webkitCancelFullScreen();\r\n // @ts-ignore\r\n } else if(document.msExitFullscreen) {\r\n // @ts-ignore\r\n document.msExitFullscreen();\r\n }\r\n \r\n fullScreenButton.classList.remove('tgico-smallscreen');\r\n fullScreenButton.classList.add('tgico-fullscreen');\r\n fullScreenButton.setAttribute('title', 'Full Screen');\r\n }\r\n }\r\n \r\n onFullScreen = () => {\r\n // @ts-ignore\r\n const isFullscreenNow = document.webkitFullscreenElement !== null;\r\n if(!isFullscreenNow) {\r\n this.wrapper.classList.remove('ckin__fullscreen');\r\n } else {\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 appDocsManager, {MyDocument} from \"../lib/appManagers/appDocsManager\";\r\nimport { RichTextProcessor } from \"../lib/richtextprocessor\";\r\nimport { formatDate } from \"./wrappers\";\r\nimport ProgressivePreloader from \"./preloader\";\r\nimport { MediaProgressLine } from \"../lib/mediaPlayer\";\r\nimport appMediaPlaybackController from \"./appMediaPlaybackController\";\r\nimport { DocumentAttribute } from \"../layer\";\r\nimport mediaSizes from \"../helpers/mediaSizes\";\r\nimport { isSafari } from \"../helpers/userAgent\";\r\nimport appMessagesManager from \"../lib/appManagers/appMessagesManager\";\r\nimport rootScope from \"../lib/rootScope\";\r\nimport './middleEllipsis';\r\nimport { attachClickEvent, cancelEvent, detachClickEvent } from \"../helpers/dom\";\r\nimport { SearchSuperContext } from \"./appSearchSuper.\";\r\nimport { formatDateAccordingToToday } from \"../helpers/date\";\r\n\r\nrootScope.on('messages_media_read', e => {\r\n const {mids, peerId} = e;\r\n\r\n mids.forEach(mid => {\r\n (Array.from(document.querySelectorAll('audio-element[message-id=\"' + mid + '\"][peer-id=\"' + peerId + '\"]')) as AudioElement[]).forEach(elem => {\r\n //console.log('updating avatar:', elem);\r\n elem.classList.remove('is-unread');\r\n });\r\n });\r\n});\r\n\r\n// https://github.com/LonamiWebs/Telethon/blob/4393ec0b83d511b6a20d8a20334138730f084375/telethon/utils.py#L1285\r\nexport function decodeWaveform(waveform: Uint8Array | number[]) {\r\n if(!(waveform instanceof Uint8Array)) {\r\n waveform = new Uint8Array(waveform);\r\n }\r\n\r\n const bitCount = waveform.length * 8;\r\n const valueCount = bitCount / 5 | 0;\r\n if(!valueCount) {\r\n return new Uint8Array([]);\r\n }\r\n\r\n let result: Uint8Array;\r\n try {\r\n const dataView = new DataView(waveform.buffer);\r\n result = new Uint8Array(valueCount);\r\n for(let i = 0; i < valueCount; i++) {\r\n const byteIndex = i * 5 / 8 | 0;\r\n const bitShift = i * 5 % 8;\r\n const value = dataView.getUint16(byteIndex, true);\r\n result[i] = (value >> bitShift) & 0b00011111;\r\n }\r\n } catch(err) {\r\n result = new Uint8Array([]);\r\n }\r\n\r\n /* var byteIndex = (valueCount - 1) / 8 | 0;\r\n var bitShift = (valueCount - 1) % 8;\r\n if(byteIndex === waveform.length - 1) {\r\n var value = waveform[byteIndex];\r\n } else {\r\n var value = dataView.getUint16(byteIndex, true);\r\n }\r\n console.log('decoded waveform, setting last value:', value, byteIndex, bitShift);\r\n result[valueCount - 1] = (value >> bitShift) & 0b00011111; */\r\n return result;\r\n}\r\n\r\nfunction wrapVoiceMessage(audioEl: AudioElement) {\r\n audioEl.classList.add('is-voice');\r\n\r\n const message = audioEl.message;\r\n const doc = (message.media.document || message.media.webpage.document) as MyDocument;\r\n const isOut = message.fromId === rootScope.myId && message.peerId !== rootScope.myId;\r\n let isUnread = message && message.pFlags.media_unread;\r\n if(isUnread) {\r\n audioEl.classList.add('is-unread');\r\n }\r\n\r\n if(message.pFlags.out) {\r\n audioEl.classList.add('is-out');\r\n }\r\n\r\n const barWidth = 2;\r\n const barMargin = 2; //mediaSizes.isMobile ? 2 : 1;\r\n const barHeightMin = 4; //mediaSizes.isMobile ? 3 : 2;\r\n const barHeightMax = mediaSizes.isMobile ? 16 : 23;\r\n const availW = 150; //mediaSizes.isMobile ? 152 : 190;\r\n\r\n const svg = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\");\r\n svg.classList.add('audio-waveform');\r\n svg.setAttributeNS(null, 'width', '' + availW);\r\n svg.setAttributeNS(null, 'height', '' + barHeightMax);\r\n svg.setAttributeNS(null, 'viewBox', `0 0 ${availW} ${barHeightMax}`);\r\n\r\n const timeDiv = document.createElement('div');\r\n timeDiv.classList.add('audio-time');\r\n audioEl.append(svg, timeDiv);\r\n\r\n let waveform = (doc.attributes.find(attribute => attribute._ === 'documentAttributeAudio') as DocumentAttribute.documentAttributeAudio).waveform || new Uint8Array([]);\r\n waveform = decodeWaveform(waveform.slice(0, 63));\r\n\r\n //console.log('decoded waveform:', waveform);\r\n\r\n const normValue = Math.max(...waveform);\r\n const wfSize = waveform.length ? waveform.length : 100;\r\n const barCount = Math.min((availW / (barWidth + barMargin)) | 0, wfSize);\r\n\r\n let maxValue = 0;\r\n const maxDelta = barHeightMax - barHeightMin;\r\n\r\n let html = '';\r\n for(let i = 0, barX = 0, sumI = 0; i < wfSize; ++i) {\r\n const value = waveform[i] || 0;\r\n if((sumI + barCount) >= wfSize) { // draw bar\r\n sumI = sumI + barCount - wfSize;\r\n\t\t\tif(sumI < (barCount + 1) / 2) {\r\n\t\t\t\tif(maxValue < value) maxValue = value;\r\n }\r\n \r\n const bar_value = Math.max(((maxValue * maxDelta) + ((normValue + 1) / 2)) / (normValue + 1), barHeightMin);\r\n \r\n const h = `\r\n <rect x=\"${barX}\" y=\"${barHeightMax - bar_value}\" width=\"${barWidth}\" height=\"${bar_value}\" rx=\"1\" ry=\"1\"></rect>\r\n `;\r\n html += h;\r\n\r\n barX += barWidth + barMargin;\r\n\r\n if(sumI < (barCount + 1) / 2) {\r\n maxValue = 0;\r\n } else {\r\n maxValue = value;\r\n }\r\n } else {\r\n if(maxValue < value) maxValue = value;\r\n\r\n sumI += barCount;\r\n }\r\n }\r\n\r\n svg.insertAdjacentHTML('beforeend', html);\r\n const rects = Array.from(svg.children) as HTMLElement[];\r\n\r\n let progress = audioEl.querySelector('.audio-waveform') as HTMLDivElement;\r\n \r\n const onLoad = () => {\r\n let interval = 0;\r\n let lastIndex = 0;\r\n\r\n let audio = audioEl.audio;\r\n\r\n if(!audio.paused || (audio.currentTime > 0 && audio.currentTime !== audio.duration)) {\r\n lastIndex = Math.round(audio.currentTime / audio.duration * barCount);\r\n rects.slice(0, lastIndex + 1).forEach(node => node.classList.add('active'));\r\n }\r\n\r\n let start = () => {\r\n clearInterval(interval);\r\n interval = window.setInterval(() => {\r\n if(lastIndex > svg.childElementCount || isNaN(audio.duration) || audio.paused) {\r\n clearInterval(interval);\r\n return;\r\n }\r\n\r\n lastIndex = Math.round(audio.currentTime / audio.duration * barCount);\r\n \r\n //svg.children[lastIndex].setAttributeNS(null, 'fill', '#000');\r\n //svg.children[lastIndex].classList.add('active'); #Иногда пропускает полоски..\r\n rects.slice(0, lastIndex + 1).forEach(node => node.classList.add('active'));\r\n //++lastIndex;\r\n //console.log('lastIndex:', lastIndex, audio.currentTime);\r\n //}, duration * 1000 / svg.childElementCount | 0/* 63 * duration / 10 */);\r\n }, 20);\r\n };\r\n\r\n if(!audio.paused) {\r\n start();\r\n }\r\n\r\n audioEl.addAudioListener('playing', () => {\r\n if(isUnread && !isOut && audioEl.classList.contains('is-unread')) {\r\n audioEl.classList.remove('is-unread');\r\n appMessagesManager.readMessages(audioEl.message.peerId, [audioEl.message.mid]);\r\n isUnread = false;\r\n }\r\n\r\n //rects.forEach(node => node.classList.remove('active'));\r\n start();\r\n });\r\n\r\n audioEl.addAudioListener('pause', () => {\r\n clearInterval(interval);\r\n });\r\n \r\n audioEl.addAudioListener('ended', () => {\r\n clearInterval(interval);\r\n rects.forEach(node => node.classList.remove('active'));\r\n });\r\n \r\n let mousedown = false, mousemove = false;\r\n progress.addEventListener('mouseleave', (e) => {\r\n if(mousedown) {\r\n audio.play();\r\n mousedown = false;\r\n }\r\n mousemove = false;\r\n })\r\n progress.addEventListener('mousemove', (e) => {\r\n mousemove = true;\r\n if(mousedown) scrub(e);\r\n });\r\n progress.addEventListener('mousedown', (e) => {\r\n e.preventDefault();\r\n if(!audio.paused) {\r\n audio.pause();\r\n }\r\n \r\n scrub(e);\r\n mousedown = true;\r\n });\r\n progress.addEventListener('mouseup', (e) => {\r\n if (mousemove && mousedown) {\r\n audio.play();\r\n mousedown = false;\r\n }\r\n });\r\n attachClickEvent(progress, (e) => {\r\n cancelEvent(e);\r\n if(!audio.paused) scrub(e);\r\n });\r\n \r\n function scrub(e: MouseEvent | TouchEvent) {\r\n let offsetX: number;\r\n if(e instanceof MouseEvent) {\r\n offsetX = e.offsetX;\r\n } else { // touch\r\n const rect = (e.target as HTMLElement).getBoundingClientRect();\r\n offsetX = e.targetTouches[0].pageX - rect.left;\r\n }\r\n \r\n const scrubTime = offsetX / availW /* width */ * audio.duration;\r\n lastIndex = Math.round(scrubTime / audio.duration * barCount);\r\n \r\n rects.slice(0, lastIndex + 1).forEach(node => node.classList.add('active'));\r\n for(let i = lastIndex + 1; i < rects.length; ++i) {\r\n rects[i].classList.remove('active')\r\n }\r\n audio.currentTime = scrubTime;\r\n }\r\n \r\n return () => {\r\n clearInterval(interval);\r\n progress.remove();\r\n progress = null;\r\n audio = null;\r\n };\r\n };\r\n\r\n return onLoad;\r\n}\r\n\r\nfunction wrapAudio(audioEl: AudioElement) {\r\n const withTime = audioEl.withTime;\r\n\r\n const message = audioEl.message;\r\n const doc: MyDocument = message.media.document || message.media.webpage.document;\r\n\r\n const senderTitle = audioEl.showSender ? appMessagesManager.getSenderToPeerText(message) : '';\r\n\r\n let title = doc.type === 'voice' ? senderTitle : (doc.audioTitle || doc.file_name);\r\n let subtitle: string;\r\n \r\n if(doc.type === 'voice') {\r\n subtitle = '';\r\n } else {\r\n subtitle = doc.audioPerformer ? RichTextProcessor.wrapPlainText(doc.audioPerformer) : '';\r\n if(withTime) {\r\n subtitle += (subtitle ? ' • ' : '') + formatDate(doc.date);\r\n } else if(!subtitle) {\r\n subtitle = 'Unknown Artist';\r\n }\r\n\r\n if(audioEl.showSender) {\r\n subtitle += ' • ' + senderTitle;\r\n } else {\r\n subtitle = ' • ' + subtitle;\r\n }\r\n }\r\n\r\n let titleAdditionHTML = '';\r\n if(audioEl.showSender) {\r\n titleAdditionHTML = `<div class=\"sent-time\">${formatDateAccordingToToday(new Date(message.date * 1000))}</div>`;\r\n }\r\n\r\n const html = `\r\n <div class=\"audio-details\">\r\n <div class=\"audio-title\"><middle-ellipsis-element data-font-weight=\"${audioEl.dataset.fontWeight}\">${title}</middle-ellipsis-element>${titleAdditionHTML}</div>\r\n <div class=\"audio-subtitle\"><div class=\"audio-time\"></div>${subtitle || '<div></div>'}</div>\r\n </div>`;\r\n \r\n audioEl.insertAdjacentHTML('beforeend', html);\r\n\r\n const onLoad = () => {\r\n const subtitleDiv = audioEl.querySelector('.audio-subtitle') as HTMLDivElement;\r\n let launched = false;\r\n\r\n let progressLine = new MediaProgressLine(audioEl.audio, doc.supportsStreaming);\r\n\r\n audioEl.addAudioListener('ended', () => {\r\n audioEl.classList.remove('audio-show-progress');\r\n // Reset subtitle\r\n subtitleDiv.lastChild.replaceWith(subtitle);\r\n launched = false;\r\n });\r\n\r\n const onPlaying = () => {\r\n if(!launched) {\r\n audioEl.classList.add('audio-show-progress');\r\n launched = true;\r\n\r\n if(progressLine) {\r\n subtitleDiv.lastChild.replaceWith(progressLine.container);\r\n }\r\n }\r\n };\r\n\r\n audioEl.addAudioListener('playing', onPlaying);\r\n\r\n if(!audioEl.audio.paused || audioEl.audio.currentTime > 0) {\r\n onPlaying();\r\n }\r\n\r\n return () => {\r\n progressLine.removeListeners();\r\n progressLine.container.remove();\r\n progressLine = null;\r\n };\r\n };\r\n\r\n return onLoad;\r\n}\r\n\r\nexport default class AudioElement extends HTMLElement {\r\n public audio: HTMLAudioElement;\r\n public preloader: ProgressivePreloader;\r\n public message: any;\r\n public withTime = false;\r\n public voiceAsMusic = false;\r\n public searchContext: SearchSuperContext;\r\n public showSender = false;\r\n public noAutoDownload: boolean;\r\n\r\n private attachedHandlers: {[name: string]: any[]} = {};\r\n private onTypeDisconnect: () => void;\r\n public onLoad: (autoload?: boolean) => void;\r\n\r\n constructor() {\r\n super();\r\n // элемент создан\r\n }\r\n\r\n public render() {\r\n this.classList.add('audio');\r\n\r\n const doc = this.message.media.document || this.message.media.webpage.document;\r\n const isRealVoice = doc.type === 'voice';\r\n const isVoice = !this.voiceAsMusic && isRealVoice;\r\n const isOutgoing = this.message.pFlags.is_outgoing;\r\n const uploading = isOutgoing && this.preloader;\r\n\r\n const durationStr = String(doc.duration | 0).toHHMMSS();\r\n\r\n this.innerHTML = `<div class=\"audio-toggle audio-ico\"> \r\n <div class=\"part one\" x=\"0\" y=\"0\" fill=\"#fff\"></div>\r\n <div class=\"part two\" x=\"0\" y=\"0\" fill=\"#fff\"></div>\r\n </div>`;\r\n\r\n const downloadDiv = document.createElement('div');\r\n downloadDiv.classList.add('audio-download');\r\n\r\n if(uploading) {\r\n this.append(downloadDiv);\r\n }\r\n\r\n const onTypeLoad = isVoice ? wrapVoiceMessage(this) : wrapAudio(this);\r\n \r\n const audioTimeDiv = this.querySelector('.audio-time') as HTMLDivElement;\r\n audioTimeDiv.innerHTML = durationStr;\r\n\r\n const onLoad = this.onLoad = (autoload = true) => {\r\n this.onLoad = undefined;\r\n\r\n const audio = this.audio = appMediaPlaybackController.addMedia(this.message.peerId, this.message.media.document || this.message.media.webpage.document, this.message.mid, autoload);\r\n\r\n this.onTypeDisconnect = onTypeLoad();\r\n \r\n const toggle = this.querySelector('.audio-toggle') as HTMLDivElement;\r\n\r\n const getTimeStr = () => String(audio.currentTime | 0).toHHMMSS() + (isVoice ? (' / ' + durationStr) : '');\r\n\r\n const onPlaying = () => {\r\n audioTimeDiv.innerText = getTimeStr();\r\n toggle.classList.toggle('playing', !audio.paused);\r\n };\r\n\r\n if(!audio.paused || (audio.currentTime > 0 && audio.currentTime !== audio.duration)) {\r\n onPlaying();\r\n }\r\n\r\n attachClickEvent(toggle, (e) => {\r\n cancelEvent(e);\r\n if(audio.paused) audio.play().catch(() => {});\r\n else audio.pause();\r\n });\r\n\r\n this.addAudioListener('ended', () => {\r\n toggle.classList.remove('playing');\r\n });\r\n\r\n this.addAudioListener('timeupdate', () => {\r\n if(appMediaPlaybackController.isSafariBuffering(audio)) return;\r\n audioTimeDiv.innerText = getTimeStr();\r\n });\r\n\r\n this.addAudioListener('pause', () => {\r\n toggle.classList.remove('playing');\r\n });\r\n\r\n this.addAudioListener('playing', onPlaying);\r\n };\r\n\r\n if(!isOutgoing) {\r\n let preloader: ProgressivePreloader = this.preloader;\r\n\r\n const getDownloadPromise = () => appDocsManager.downloadDoc(doc);\r\n\r\n if(isRealVoice) {\r\n if(!preloader) {\r\n preloader = new ProgressivePreloader({\r\n cancelable: true\r\n });\r\n }\r\n\r\n const load = () => {\r\n const download = getDownloadPromise();\r\n preloader.attach(downloadDiv, false, download);\r\n\r\n if(!downloadDiv.parentElement) {\r\n this.append(downloadDiv);\r\n }\r\n\r\n (download as Promise<any>).then(() => {\r\n detachClickEvent(this, onClick);\r\n onLoad();\r\n\r\n downloadDiv.classList.add('downloaded');\r\n setTimeout(() => {\r\n downloadDiv.remove();\r\n }, 200);\r\n });\r\n\r\n return {download};\r\n };\r\n\r\n preloader.construct();\r\n preloader.setManual();\r\n preloader.attach(downloadDiv);\r\n preloader.setDownloadFunction(load);\r\n\r\n const onClick = (e?: Event) => {\r\n preloader.onClick(e);\r\n };\r\n \r\n attachClickEvent(this, onClick);\r\n\r\n if(!this.noAutoDownload) {\r\n onClick();\r\n }\r\n } else {\r\n if(doc.supportsStreaming) {\r\n onLoad(false);\r\n }\r\n\r\n //if(appMediaPlaybackController.mediaExists(mid)) { // чтобы показать прогресс, если аудио уже было скачано\r\n //onLoad();\r\n //} else {\r\n const r = (e: Event) => {\r\n if(!this.audio) {\r\n onLoad(false);\r\n }\r\n\r\n if(this.audio.src) {\r\n return;\r\n }\r\n //onLoad();\r\n //cancelEvent(e);\r\n appMediaPlaybackController.resolveWaitingForLoadMedia(this.message.peerId, this.message.mid);\r\n \r\n appMediaPlaybackController.willBePlayed(this.audio); // prepare for loading audio\r\n \r\n if(!preloader) {\r\n if(doc.supportsStreaming) {\r\n preloader = new ProgressivePreloader({\r\n cancelable: false\r\n });\r\n\r\n preloader.attach(downloadDiv, false);\r\n } else {\r\n preloader = new ProgressivePreloader({\r\n cancelable: true\r\n });\r\n\r\n const load = () => {\r\n const download = getDownloadPromise();\r\n preloader.attach(downloadDiv, false, download);\r\n return {download};\r\n };\r\n\r\n preloader.setDownloadFunction(load);\r\n load();\r\n }\r\n }\r\n\r\n if(isSafari) {\r\n this.audio.autoplay = true;\r\n this.audio.play().catch(() => {});\r\n }\r\n\r\n this.append(downloadDiv);\r\n \r\n new Promise<void>((resolve) => {\r\n if(this.audio.readyState >= 2) resolve();\r\n else this.addAudioListener('canplay', resolve);\r\n }).then(() => {\r\n downloadDiv.classList.add('downloaded');\r\n setTimeout(() => {\r\n downloadDiv.remove();\r\n }, 200);\r\n \r\n //setTimeout(() => {\r\n // release loaded audio\r\n if(appMediaPlaybackController.willBePlayedMedia === this.audio) {\r\n this.audio.play();\r\n appMediaPlaybackController.willBePlayedMedia = null;\r\n }\r\n //}, 10e3);\r\n });\r\n };\r\n\r\n if(!this.audio?.src) {\r\n attachClickEvent(this, r, {once: true, capture: true, passive: false});\r\n }\r\n //}\r\n }\r\n } else if(uploading) {\r\n this.preloader.attach(downloadDiv, false);\r\n //onLoad();\r\n }\r\n }\r\n\r\n /* connectedCallback() {\r\n // браузер вызывает этот метод при добавлении элемента в документ\r\n // (может вызываться много раз, если элемент многократно добавляется/удаляется)\r\n } */\r\n\r\n public addAudioListener(name: string, callback: any) {\r\n if(!this.attachedHandlers[name]) this.attachedHandlers[name] = [];\r\n this.attachedHandlers[name].push(callback);\r\n this.audio.addEventListener(name, callback);\r\n }\r\n\r\n disconnectedCallback() {\r\n if(this.isConnected) {\r\n return;\r\n }\r\n \r\n // браузер вызывает этот метод при удалении элемента из документа\r\n // (может вызываться много раз, если элемент многократно добавляется/удаляется)\r\n if(this.onTypeDisconnect) {\r\n this.onTypeDisconnect();\r\n this.onTypeDisconnect = null;\r\n }\r\n\r\n for(let name in this.attachedHandlers) {\r\n for(let callback of this.attachedHandlers[name]) {\r\n this.audio.removeEventListener(name, callback);\r\n }\r\n \r\n delete this.attachedHandlers[name];\r\n }\r\n\r\n this.preloader = null;\r\n }\r\n}\r\n\r\ncustomElements.define(\"audio-element\", AudioElement);\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 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\r\n this.subtitle = document.createElement('div');\r\n this.subtitle.classList.add(className + '-subtitle');\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 renderImageFromUrl from \"../../helpers/dom/renderImageFromUrl\";\r\nimport { limitSymbols } from \"../../helpers/string\";\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 { wrapSticker } from \"../wrappers\";\r\n\r\nexport function wrapReplyDivAndCaption(options: {\r\n title: string,\r\n titleEl: HTMLElement,\r\n subtitle: string,\r\n subtitleEl: HTMLElement,\r\n message: any,\r\n mediaEl: HTMLElement\r\n}) {\r\n let {title, titleEl, subtitle, subtitleEl, mediaEl, message} = options;\r\n if(title !== undefined) {\r\n limitSymbols(title, 140);\r\n\r\n title = title ? RichTextProcessor.wrapEmojiText(title) : '';\r\n titleEl.innerHTML = title;\r\n }\r\n\r\n let media = message && message.media;\r\n let setMedia = false;\r\n if(media && mediaEl) {\r\n subtitleEl.textContent = '';\r\n subtitleEl.append(appMessagesManager.wrapMessageForReply(message));\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 && ['video', 'sticker', 'gif'].indexOf(media.document.type) !== -1)) {\r\n /* const middlewareOriginal = appImManager.chat.bubbles.getMiddleware();\r\n const middleware = () => {\r\n \r\n }; */\r\n\r\n const boxSize = 32;\r\n if(media.document?.type === 'sticker') {\r\n if(mediaEl.style.backgroundImage) {\r\n mediaEl.style.backgroundImage = ''; \r\n }\r\n\r\n setMedia = true;\r\n wrapSticker({\r\n doc: media.document,\r\n div: mediaEl,\r\n lazyLoadQueue: appImManager.chat.bubbles.lazyLoadQueue,\r\n group: CHAT_ANIMATION_GROUP,\r\n //onlyThumb: media.document.sticker === 2,\r\n width: boxSize,\r\n height: boxSize\r\n });\r\n } else {\r\n if(mediaEl.firstElementChild) {\r\n mediaEl.innerHTML = '';\r\n }\r\n\r\n const photo = media.photo || media.document;\r\n\r\n const cacheContext = appPhotosManager.getCacheContext(photo);\r\n\r\n if(!cacheContext.downloaded) {\r\n const sizes = photo.sizes || photo.thumbs;\r\n if(sizes && sizes[0].bytes) {\r\n setMedia = true;\r\n renderImageFromUrl(mediaEl, appPhotosManager.getPreviewURLFromThumb(sizes[0]));\r\n }\r\n }\r\n\r\n const size = appPhotosManager.choosePhotoSize(photo, boxSize, boxSize/* mediaSizes.active.regular.width, mediaSizes.active.regular.height */);\r\n if(size._ !== 'photoSizeEmpty') {\r\n setMedia = true;\r\n appPhotosManager.preloadPhoto(photo, size)\r\n .then(() => {\r\n renderImageFromUrl(mediaEl, photo._ === 'photo' ? photo.url : appPhotosManager.getDocumentCachedThumb(photo.id).url);\r\n });\r\n }\r\n }\r\n }\r\n } else {\r\n subtitle = limitSymbols(subtitle, 140);\r\n subtitle = subtitle ? RichTextProcessor.wrapEmojiText(subtitle) : '';\r\n subtitleEl.innerHTML = subtitle;\r\n }\r\n \r\n return setMedia;\r\n}\r\n\r\nexport default class ReplyContainer extends DivAndCaption<(title: string, subtitle: string, message?: any) => void> {\r\n private mediaEl: HTMLElement;\r\n\r\n constructor(protected className: string) {\r\n super(className, (title: string, subtitle: string = '', message?: any) => {\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\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\";\r\nimport { clamp } from \"../helpers/number\";\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 Button from \"./button\";\r\nimport { safeAssign } from \"../helpers/object\";\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: number;\r\n\r\n constructor(options: {\r\n peerId: number,\r\n inputFields: EditPeer['inputFields'],\r\n listenerSetter: ListenerSetter,\r\n doNotEditAvatar?: boolean,\r\n }) {\r\n safeAssign(this, options);\r\n\r\n this.nextBtn = Button('btn-circle btn-corner tgico-check');\r\n\r\n this.avatarElem = document.createElement('avatar-element') as AvatarElement;\r\n this.avatarElem.classList.add('avatar-placeholder', 'avatar-120');\r\n this.avatarElem.setAttribute('peer', '' + 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 this.inputFields.forEach(inputField => {\r\n this.listenerSetter.add(inputField.input, 'input', this.handleChange);\r\n });\r\n }\r\n\r\n public isChanged = () => {\r\n return !!this.uploadAvatar || !!this.inputFields.find(inputField => inputField.isValid());\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\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\";\r\n\r\nexport default class Row {\r\n public container: HTMLElement;\r\n public title: HTMLDivElement;\r\n public subtitle: 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,\r\n subtitleLangKey: LangPackKey\r\n radioField: Row['radioField'],\r\n checkboxField: Row['checkboxField'],\r\n noCheckboxSubtitle: boolean,\r\n title: string,\r\n titleLangKey: LangPackKey,\r\n titleRight: string | HTMLElement,\r\n clickable: boolean | ((e: Event) => void),\r\n navigationTab: SliderSuperTab\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 if(options.subtitle) {\r\n this.subtitle.innerHTML = options.subtitle;\r\n } else if(options.subtitleLangKey) {\r\n this.subtitle.append(i18n(options.subtitleLangKey));\r\n }\r\n this.container.append(this.subtitle);\r\n\r\n let havePadding = false;\r\n if(options.radioField || options.checkboxField) {\r\n havePadding = true;\r\n if(options.radioField) {\r\n this.radioField = options.radioField;\r\n this.container.append(this.radioField.label);\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 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 if(options.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 if(options.title) {\r\n this.title.innerHTML = options.title;\r\n } else {\r\n this.title.append(i18n(options.titleLangKey));\r\n }\r\n c.append(this.title);\r\n\r\n if(options.titleRight) {\r\n const titleRight = document.createElement('div');\r\n titleRight.classList.add('row-title', 'row-title-right');\r\n\r\n if(typeof(options.titleRight) === 'string') {\r\n titleRight.innerHTML = options.titleRight;\r\n } else {\r\n titleRight.append(options.titleRight);\r\n }\r\n\r\n c.append(titleRight);\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 ripple(this.container, undefined, undefined, true);\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\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\nexport default function RadioForm(radios: {container: HTMLElement, input: HTMLInputElement}[], onChange: (value: string) => 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', () => {\r\n if(input.checked) {\r\n onChange(input.value);\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\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 appStateManager from \"../lib/appManagers/appStateManager\";\r\nimport { getDeepProperty } from \"../helpers/object\";\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 }) {\r\n const label = this.label = document.createElement('label');\r\n label.classList.add('radio-field');\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\nconst toastEl = document.createElement('div');\r\ntoastEl.classList.add('toast');\r\nexport function toast(html: string) {\r\n toastEl.innerHTML = html;\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\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\";\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: number,\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),\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.isValid() && RichTextProcessor.isUsernameValid(value)) {\r\n this.checkUsername(value);\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 AvatarElement from \"../avatar\";\r\nimport PopupElement, { addCancelButton, PopupButton, PopupOptions } from \".\";\r\nimport { i18n, LangPackKey } from \"../../lib/langPack\";\r\nimport CheckboxField, { CheckboxFieldOptions } from \"../checkboxField\";\r\n\r\nexport type PopupPeerButtonCallbackCheckboxes = Partial<{[text in LangPackKey]: boolean}>;\r\nexport type PopupPeerButtonCallback = (checkboxes?: PopupPeerButtonCallbackCheckboxes) => void;\r\n\r\nexport type PopupPeerOptions = PopupOptions & Partial<{\r\n peerId: number,\r\n title: string,\r\n titleLangKey?: LangPackKey,\r\n titleLangArgs?: any[],\r\n description: string,\r\n descriptionLangKey?: LangPackKey,\r\n descriptionLangArgs?: any[],\r\n buttons: Array<Omit<PopupButton, 'callback'> & Partial<{callback: PopupPeerButtonCallback}>>,\r\n checkboxes: Array<CheckboxFieldOptions & {checkboxField?: CheckboxField}>\r\n}>;\r\nexport default class PopupPeer extends PopupElement {\r\n constructor(private className: string, options: PopupPeerOptions = {}) {\r\n super('popup-peer' + (className ? ' ' + className : ''), addCancelButton(options.buttons), {overlayClosable: true, ...options});\r\n\r\n if(options.peerId) {\r\n let avatarEl = new AvatarElement();\r\n avatarEl.setAttribute('dialog', '1');\r\n avatarEl.setAttribute('peer', '' + options.peerId);\r\n avatarEl.classList.add('avatar-32');\r\n this.header.prepend(avatarEl);\r\n }\r\n\r\n if(options.descriptionLangKey) this.title.append(i18n(options.titleLangKey, options.titleLangArgs));\r\n else this.title.innerText = options.title || '';\r\n\r\n let p = document.createElement('p');\r\n p.classList.add('popup-description');\r\n if(options.descriptionLangKey) p.append(i18n(options.descriptionLangKey, options.descriptionLangArgs));\r\n else p.innerHTML = options.description;\r\n\r\n const fragment = document.createDocumentFragment();\r\n fragment.append(p);\r\n\r\n if(options.checkboxes) {\r\n this.container.classList.add('have-checkbox');\r\n \r\n options.checkboxes.forEach(o => {\r\n o.withRipple = true;\r\n const checkboxField = new CheckboxField(o);\r\n o.checkboxField = checkboxField;\r\n fragment.append(checkboxField.label);\r\n });\r\n\r\n options.buttons.forEach(button => {\r\n if(button.callback) {\r\n const original = button.callback;\r\n button.callback = () => {\r\n const c: PopupPeerButtonCallbackCheckboxes = {};\r\n options.checkboxes.forEach(o => {\r\n c[o.text] = o.checkboxField.checked;\r\n });\r\n original(c);\r\n };\r\n }\r\n });\r\n }\r\n\r\n this.container.insertBefore(fragment, this.header.nextElementSibling);\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 { copyTextToClipboard } from \"../../../helpers/clipboard\";\r\nimport { attachClickEvent, toggleDisability } from \"../../../helpers/dom\";\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\n\r\nexport default class AppGroupTypeTab extends SliderSuperTabEventable {\r\n public peerId: number;\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 this.setTitle('GroupType');\r\n\r\n const section = new SettingSection({\r\n name: 'GroupType'\r\n });\r\n\r\n const random = randomLong();\r\n const privateRow = new Row({\r\n radioField: new RadioField({\r\n langKey: 'MegaPrivate', \r\n name: random, \r\n value: 'private'\r\n }),\r\n subtitleLangKey: 'MegaPrivateInfo'\r\n });\r\n const publicRow = new Row({\r\n radioField: new RadioField({\r\n langKey: 'MegaPublic', \r\n name: random, \r\n value: 'public'\r\n }),\r\n subtitleLangKey: '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.peerId);\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: '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.peerId, 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: '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.isValid() && 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.peerId,\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 = Button('btn-circle btn-corner tgico-check 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.peerId).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","/*\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\";\r\n\r\nexport default class ScrollableLoader {\r\n public loading = false;\r\n private scrollable: Scrollable;\r\n private getPromise: () => Promise<any>;\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","/*\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 appChatsManager, { ChatRights } from \"../lib/appManagers/appChatsManager\";\r\nimport appDialogsManager from \"../lib/appManagers/appDialogsManager\";\r\nimport appMessagesManager, { Dialog } from \"../lib/appManagers/appMessagesManager\";\r\nimport appPeersManager from \"../lib/appManagers/appPeersManager\";\r\nimport appPhotosManager from \"../lib/appManagers/appPhotosManager\";\r\nimport appUsersManager from \"../lib/appManagers/appUsersManager\";\r\nimport rootScope from \"../lib/rootScope\";\r\nimport { cancelEvent, replaceContent } from \"../helpers/dom\";\r\nimport Scrollable from \"./scrollable\";\r\nimport { FocusDirection } from \"../helpers/fastSmoothScroll\";\r\nimport CheckboxField from \"./checkboxField\";\r\nimport appProfileManager from \"../lib/appManagers/appProfileManager\";\r\nimport { safeAssign } from \"../helpers/object\";\r\nimport { i18n, LangPackKey, _i18n } from \"../lib/langPack\";\r\nimport findUpAttribute from \"../helpers/dom/findUpAttribute\";\r\nimport findUpClassName from \"../helpers/dom/findUpClassName\";\r\nimport PeerTitle from \"./peerTitle\";\r\n\r\ntype PeerType = 'contacts' | 'dialogs' | 'channelParticipants';\r\n\r\n// TODO: правильная сортировка для addMembers, т.е. для peerType: 'contacts', потому что там идут сначала контакты - потом неконтакты, а должно всё сортироваться по имени\r\n\r\nlet loadedAllDialogs = false, loadAllDialogsPromise: Promise<any>;\r\nexport default class AppSelectPeers {\r\n public container = document.createElement('div');\r\n public list = appDialogsManager.createChatList(/* {\r\n handheldsSize: 66,\r\n avatarSize: 48\r\n } */);\r\n public chatsContainer = document.createElement('div');\r\n public scrollable: Scrollable;\r\n public selectedScrollable: Scrollable;\r\n \r\n public selectedContainer: HTMLElement;\r\n public input: HTMLInputElement;\r\n \r\n //public selected: {[peerId: number]: HTMLElement} = {};\r\n public selected = new Set<any>();\r\n\r\n public freezed = false;\r\n\r\n private folderId = 0;\r\n private offsetIndex = 0;\r\n private promise: Promise<any>;\r\n\r\n private query = '';\r\n private cachedContacts: number[];\r\n\r\n private loadedWhat: Partial<{[k in 'dialogs' | 'archived' | 'contacts' | 'channelParticipants']: true}> = {};\r\n\r\n private renderedPeerIds: Set<number> = new Set();\r\n\r\n private appendTo: HTMLElement;\r\n private onChange: (length: number) => void;\r\n private peerType: PeerType[] = ['dialogs'];\r\n private renderResultsFunc: (peerIds: number[]) => void;\r\n private chatRightsAction: ChatRights;\r\n private multiSelect = true;\r\n private rippleEnabled = true;\r\n private avatarSize = 48;\r\n\r\n private tempIds: {[k in keyof AppSelectPeers['loadedWhat']]: number} = {};\r\n private peerId = 0;\r\n\r\n private placeholder: LangPackKey;\r\n \r\n constructor(options: {\r\n appendTo: AppSelectPeers['appendTo'], \r\n onChange?: AppSelectPeers['onChange'], \r\n peerType?: AppSelectPeers['peerType'], \r\n peerId?: number,\r\n onFirstRender?: () => void, \r\n renderResultsFunc?: AppSelectPeers['renderResultsFunc'], \r\n chatRightsAction?: AppSelectPeers['chatRightsAction'], \r\n multiSelect?: AppSelectPeers['multiSelect'],\r\n rippleEnabled?: boolean,\r\n avatarSize?: AppSelectPeers['avatarSize'],\r\n placeholder?: LangPackKey\r\n }) {\r\n safeAssign(this, options);\r\n\r\n this.container.classList.add('selector');\r\n\r\n let needSwitchList = false;\r\n const f = (this.renderResultsFunc || this.renderResults).bind(this);\r\n this.renderResultsFunc = (peerIds: number[]) => {\r\n if(needSwitchList) {\r\n this.scrollable.splitUp.replaceWith(this.list);\r\n this.scrollable.setVirtualContainer(this.list);\r\n needSwitchList = false;\r\n }\r\n \r\n peerIds = peerIds.filter(peerId => {\r\n const notRendered = !this.renderedPeerIds.has(peerId);\r\n if(notRendered) this.renderedPeerIds.add(peerId);\r\n return notRendered;\r\n });\r\n\r\n return f(peerIds);\r\n };\r\n\r\n this.input = document.createElement('input');\r\n this.input.classList.add('selector-search-input');\r\n if(this.placeholder) {\r\n _i18n(this.input, this.placeholder, undefined, 'placeholder');\r\n } else {\r\n _i18n(this.input, 'SendMessageTo', undefined, 'placeholder');\r\n }\r\n\r\n this.input.type = 'text';\r\n\r\n if(this.multiSelect) {\r\n let topContainer = document.createElement('div');\r\n topContainer.classList.add('selector-search-container');\r\n \r\n this.selectedContainer = document.createElement('div');\r\n this.selectedContainer.classList.add('selector-search');\r\n \r\n this.selectedContainer.append(this.input);\r\n topContainer.append(this.selectedContainer);\r\n this.selectedScrollable = new Scrollable(topContainer);\r\n \r\n let delimiter = document.createElement('hr');\r\n\r\n this.selectedContainer.addEventListener('click', (e) => {\r\n if(this.freezed) return;\r\n let target = e.target as HTMLElement;\r\n target = findUpClassName(target, 'selector-user');\r\n \r\n if(!target) return;\r\n \r\n const peerId = target.dataset.key;\r\n const li = this.chatsContainer.querySelector('[data-peer-id=\"' + peerId + '\"]') as HTMLElement;\r\n if(!li) {\r\n this.remove(+peerId || peerId);\r\n } else {\r\n li.click();\r\n }\r\n });\r\n\r\n this.container.append(topContainer, delimiter);\r\n }\r\n\r\n this.chatsContainer.classList.add('chatlist-container');\r\n this.chatsContainer.append(this.list);\r\n this.scrollable = new Scrollable(this.chatsContainer);\r\n this.scrollable.setVirtualContainer(this.list);\r\n\r\n this.chatsContainer.addEventListener('click', (e) => {\r\n const target = findUpAttribute(e.target, 'data-peer-id') as HTMLElement;\r\n cancelEvent(e);\r\n\r\n if(!target) return;\r\n if(this.freezed) return;\r\n\r\n let key: any = target.dataset.peerId;\r\n key = +key || key;\r\n\r\n if(!this.multiSelect) {\r\n this.add(key);\r\n return;\r\n }\r\n\r\n target.classList.toggle('active');\r\n if(this.selected.has(key)) {\r\n this.remove(key);\r\n } else {\r\n this.add(key);\r\n }\r\n\r\n const checkbox = target.querySelector('input') as HTMLInputElement;\r\n checkbox.checked = !checkbox.checked;\r\n });\r\n\r\n this.input.addEventListener('input', () => {\r\n const value = this.input.value;\r\n if(this.query !== value) {\r\n if(this.peerType.includes('contacts')) {\r\n this.cachedContacts = null;\r\n }\r\n \r\n //if(this.peerType.includes('dialogs')) {\r\n this.folderId = 0;\r\n this.offsetIndex = 0;\r\n //}\r\n\r\n for(let i in this.tempIds) {\r\n // @ts-ignore\r\n ++this.tempIds[i];\r\n }\r\n\r\n this.list = appDialogsManager.createChatList();\r\n\r\n this.promise = null;\r\n this.loadedWhat = {};\r\n this.query = value;\r\n this.renderedPeerIds.clear();\r\n needSwitchList = true;\r\n \r\n //console.log('selectPeers input:', this.query);\r\n this.getMoreResults();\r\n }\r\n });\r\n\r\n this.scrollable.onScrolledBottom = () => {\r\n this.getMoreResults();\r\n };\r\n\r\n this.container.append(this.chatsContainer);\r\n this.appendTo.append(this.container);\r\n\r\n // WARNING TIMEOUT\r\n setTimeout(() => {\r\n let getResultsPromise = this.getMoreResults() as Promise<any>;\r\n if(options.onFirstRender) {\r\n getResultsPromise.then(() => {\r\n options.onFirstRender();\r\n });\r\n }\r\n }, 0);\r\n }\r\n\r\n private renderSaved() {\r\n if(!this.offsetIndex && this.folderId === 0 && this.peerType.includes('dialogs') && (!this.query || appUsersManager.testSelfSearch(this.query))) {\r\n this.renderResultsFunc([rootScope.myId]);\r\n }\r\n }\r\n\r\n private getTempId(type: keyof AppSelectPeers['tempIds']) {\r\n if(this.tempIds[type] === undefined) {\r\n this.tempIds[type] = 0;\r\n }\r\n\r\n return ++this.tempIds[type];\r\n }\r\n\r\n private async getMoreDialogs(): Promise<any> {\r\n if(this.promise) return this.promise;\r\n\r\n if(this.loadedWhat.dialogs && this.loadedWhat.archived) {\r\n return;\r\n }\r\n \r\n // в десктопе - сначала без группы, потом архивные, потом контакты без сообщений\r\n const pageCount = appPhotosManager.windowH / 72 * 1.25 | 0;\r\n\r\n const tempId = this.getTempId('dialogs');\r\n this.promise = appMessagesManager.getConversations(this.query, this.offsetIndex, pageCount, this.folderId);\r\n const value = await this.promise;\r\n this.promise = null;\r\n\r\n if(this.tempIds.dialogs !== tempId) {\r\n return;\r\n }\r\n\r\n let dialogs = value.dialogs as Dialog[];\r\n if(dialogs.length) {\r\n const newOffsetIndex = dialogs[dialogs.length - 1].index || 0;\r\n\r\n dialogs = dialogs.slice();\r\n dialogs.findAndSplice(d => d.peerId === rootScope.myId); // no my account\r\n\r\n if(this.chatRightsAction) {\r\n dialogs = dialogs.filter(d => {\r\n return (d.peerId > 0 && (this.chatRightsAction !== 'send_messages' || appUsersManager.canSendToUser(d.peerId))) || appChatsManager.hasRights(-d.peerId, this.chatRightsAction);\r\n });\r\n }\r\n\r\n this.renderSaved();\r\n\r\n this.offsetIndex = newOffsetIndex;\r\n\r\n this.renderResultsFunc(dialogs.map(dialog => dialog.peerId));\r\n } else {\r\n if(!this.loadedWhat.dialogs) {\r\n this.renderSaved();\r\n\r\n this.loadedWhat.dialogs = true;\r\n this.offsetIndex = 0;\r\n this.folderId = 1;\r\n\r\n return this.getMoreDialogs();\r\n } else {\r\n this.loadedWhat.archived = true;\r\n\r\n if(!this.loadedWhat.contacts && this.peerType.includes('contacts')) {\r\n return this.getMoreContacts();\r\n }\r\n }\r\n }\r\n }\r\n\r\n private async getMoreContacts() {\r\n if(this.promise) return this.promise;\r\n\r\n if(this.loadedWhat.contacts) {\r\n return;\r\n }\r\n\r\n if(!this.cachedContacts) {\r\n /* const promises: Promise<any>[] = [appUsersManager.getContacts(this.query)];\r\n if(!this.peerType.includes('dialogs')) {\r\n promises.push(appMessagesManager.getConversationsAll());\r\n }\r\n\r\n this.promise = Promise.all(promises);\r\n this.cachedContacts = (await this.promise)[0].slice(); */\r\n const tempId = this.getTempId('contacts');\r\n this.promise = appUsersManager.getContacts(this.query);\r\n this.cachedContacts = (await this.promise).slice();\r\n if(this.tempIds.contacts !== tempId) {\r\n return;\r\n }\r\n\r\n this.cachedContacts.findAndSplice(userId => userId === rootScope.myId); // no my account\r\n this.promise = null;\r\n }\r\n\r\n if(this.cachedContacts.length) {\r\n const pageCount = appPhotosManager.windowH / 72 * 1.25 | 0;\r\n const arr = this.cachedContacts.splice(0, pageCount);\r\n this.renderResultsFunc(arr);\r\n }\r\n \r\n if(!this.cachedContacts.length) {\r\n this.loadedWhat.contacts = true;\r\n\r\n // need to load non-contacts\r\n if(!this.peerType.includes('dialogs')) {\r\n return this.getMoreDialogs();\r\n }\r\n }\r\n }\r\n\r\n private async getMoreChannelParticipants() {\r\n if(this.promise) return this.promise;\r\n\r\n if(this.loadedWhat.channelParticipants) {\r\n return;\r\n }\r\n\r\n const pageCount = 50; // same as in group permissions to use cache\r\n\r\n const tempId = this.getTempId('channelParticipants');\r\n const promise = appProfileManager.getChannelParticipants(-this.peerId, {_: 'channelParticipantsSearch', q: this.query}, pageCount, this.list.childElementCount);\r\n const participants = await promise;\r\n if(this.tempIds.channelParticipants !== tempId) {\r\n return;\r\n }\r\n \r\n const userIds = participants.participants.map(participant => participant.user_id);\r\n userIds.findAndSplice(u => u === rootScope.myId);\r\n this.renderResultsFunc(userIds);\r\n\r\n if(this.list.childElementCount >= participants.count || participants.participants.length < pageCount) {\r\n this.loadedWhat.channelParticipants = true;\r\n }\r\n }\r\n\r\n checkForTriggers = () => {\r\n this.scrollable.checkForTriggers();\r\n };\r\n\r\n private getMoreResults() {\r\n const get = () => {\r\n const promises: Promise<any>[] = [];\r\n\r\n if(!loadedAllDialogs && (this.peerType.includes('dialogs') || this.peerType.includes('contacts'))) {\r\n if(!loadAllDialogsPromise) {\r\n loadAllDialogsPromise = appMessagesManager.getConversationsAll()\r\n .then(() => {\r\n loadedAllDialogs = true;\r\n }).finally(() => {\r\n loadAllDialogsPromise = null;\r\n });\r\n }\r\n\r\n promises.push(loadAllDialogsPromise);\r\n }\r\n \r\n if((this.peerType.includes('dialogs') || this.loadedWhat.contacts) && !this.loadedWhat.archived) { // to load non-contacts\r\n promises.push(this.getMoreDialogs());\r\n \r\n if(!this.loadedWhat.archived) {\r\n return promises;\r\n }\r\n }\r\n \r\n if(this.peerType.includes('contacts') && !this.loadedWhat.contacts) {\r\n promises.push(this.getMoreContacts());\r\n }\r\n\r\n if(this.peerType.includes('channelParticipants') && !this.loadedWhat.channelParticipants) {\r\n promises.push(this.getMoreChannelParticipants());\r\n }\r\n \r\n return promises;\r\n };\r\n \r\n const promises = get();\r\n const promise = Promise.all(promises);\r\n if(promises.length) {\r\n promise.then(this.checkForTriggers);\r\n }\r\n\r\n return promise;\r\n }\r\n\r\n private renderResults(peerIds: number[]) {\r\n //console.log('will renderResults:', peerIds);\r\n\r\n // оставим только неконтакты с диалогов\r\n if(!this.peerType.includes('dialogs') && this.loadedWhat.contacts) {\r\n peerIds = peerIds.filter(peerId => {\r\n return appUsersManager.isNonContactUser(peerId);\r\n });\r\n }\r\n\r\n peerIds.forEach(peerId => {\r\n const {dom} = appDialogsManager.addDialogNew({\r\n dialog: peerId,\r\n container: this.scrollable,\r\n drawStatus: false,\r\n rippleEnabled: this.rippleEnabled,\r\n avatarSize: this.avatarSize\r\n });\r\n\r\n if(this.multiSelect) {\r\n const selected = this.selected.has(peerId);\r\n const checkboxField = new CheckboxField();\r\n\r\n if(selected) {\r\n dom.listEl.classList.add('active');\r\n checkboxField.input.checked = true;\r\n }\r\n\r\n dom.containerEl.prepend(checkboxField.label);\r\n }\r\n\r\n let subtitleEl: HTMLElement;\r\n if(peerId < 0) {\r\n subtitleEl = appChatsManager.getChatMembersString(-peerId);\r\n } else if(peerId === rootScope.myId) {\r\n subtitleEl = i18n('Presence.YourChat');\r\n } else {\r\n subtitleEl = appUsersManager.getUserStatusString(peerId);\r\n }\r\n\r\n dom.lastMessageSpan.append(subtitleEl);\r\n });\r\n }\r\n\r\n public add(peerId: any, title?: string | HTMLElement, scroll = true) {\r\n //console.trace('add');\r\n this.selected.add(peerId);\r\n\r\n if(!this.multiSelect) {\r\n this.onChange(this.selected.size);\r\n return;\r\n }\r\n\r\n const div = document.createElement('div');\r\n div.classList.add('selector-user', 'scale-in');\r\n\r\n const avatarEl = document.createElement('avatar-element');\r\n avatarEl.classList.add('selector-user-avatar', 'tgico');\r\n avatarEl.setAttribute('dialog', '1');\r\n avatarEl.classList.add('avatar-32');\r\n\r\n div.dataset.key = '' + peerId;\r\n if(typeof(peerId) === 'number') {\r\n if(title === undefined) {\r\n title = new PeerTitle({peerId, onlyFirstName: true}).element;\r\n }\r\n\r\n avatarEl.setAttribute('peer', '' + peerId);\r\n }\r\n\r\n if(title) {\r\n if(typeof(title) === 'string') {\r\n div.innerHTML = title;\r\n } else {\r\n replaceContent(div, title);\r\n div.append(title);\r\n }\r\n }\r\n\r\n div.insertAdjacentElement('afterbegin', avatarEl);\r\n\r\n this.selectedContainer.insertBefore(div, this.input);\r\n //this.selectedScrollable.scrollTop = this.selectedScrollable.scrollHeight;\r\n this.onChange && this.onChange(this.selected.size);\r\n \r\n if(scroll) {\r\n this.selectedScrollable.scrollIntoViewNew(this.input, 'center');\r\n }\r\n \r\n return div;\r\n }\r\n\r\n public remove(key: any) {\r\n if(!this.multiSelect) return;\r\n //const div = this.selected[peerId];\r\n const div = this.selectedContainer.querySelector(`[data-key=\"${key}\"]`) as HTMLElement;\r\n div.classList.remove('scale-in');\r\n void div.offsetWidth;\r\n div.classList.add('scale-out');\r\n\r\n const onAnimationEnd = () => {\r\n this.selected.delete(key);\r\n div.remove();\r\n this.onChange && this.onChange(this.selected.size);\r\n };\r\n\r\n if(rootScope.settings.animationsEnabled) {\r\n div.addEventListener('animationend', onAnimationEnd, {once: true});\r\n } else {\r\n onAnimationEnd();\r\n }\r\n }\r\n\r\n public getSelected() {\r\n return [...this.selected];\r\n }\r\n\r\n public addInitial(values: any[]) {\r\n values.forEach(value => {\r\n this.add(value, undefined, false);\r\n });\r\n\r\n window.requestAnimationFrame(() => { // ! not the best place for this raf though it works\r\n this.selectedScrollable.scrollIntoViewNew(this.input, 'center', undefined, undefined, FocusDirection.Static);\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 findUpAttribute(el: any, attribute: string): HTMLElement {\r\n return el.closest(`[${attribute}]`);\r\n /* if(el.getAttribute(attribute) !== null) return el; // 03.02.2020\r\n\r\n while(el.parentElement) {\r\n el = el.parentElement;\r\n if(el.getAttribute(attribute) !== null) \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\r\nimport { isTouchSupported } from \"../../helpers/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: number) => Promise<void> | void, \r\n onClose?: () => void,\r\n placeholder: LangPackKey,\r\n chatRightsAction?: AppSelectPeers['chatRightsAction'],\r\n peerId?: number,\r\n }) {\r\n super('popup-forward', null, {closable: true, overlayClosable: true, body: true});\r\n\r\n if(options.onClose) this.onClose = options.onClose;\r\n\r\n this.selector = new AppSelectPeers({\r\n appendTo: this.body, \r\n onChange: async() => {\r\n const peerId = this.selector.getSelected()[0];\r\n \r\n this.selector = null;\r\n \r\n if(options.onSelect) {\r\n const res = options.onSelect(peerId);\r\n if(res instanceof Promise) {\r\n await res;\r\n }\r\n }\r\n \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(!isTouchSupported) {\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 });\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","/*\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, toggleDisability } from \"../../../helpers/dom\";\r\nimport { deepEqual } from \"../../../helpers/object\";\r\nimport { ChannelParticipant } from \"../../../layer\";\r\nimport appChatsManager from \"../../../lib/appManagers/appChatsManager\";\r\nimport appDialogsManager from \"../../../lib/appManagers/appDialogsManager\";\r\nimport appPeersManager from \"../../../lib/appManagers/appPeersManager\";\r\nimport appUsersManager from \"../../../lib/appManagers/appUsersManager\";\r\nimport Button from \"../../button\";\r\nimport { addCancelButton } from \"../../popups\";\r\nimport PopupPeer from \"../../popups/peer\";\r\nimport { SettingSection } from \"../../sidebarLeft\";\r\nimport { SliderSuperTabEventable } from \"../../sliderTab\";\r\nimport { ChatPermissions } from \"./groupPermissions\";\r\n\r\nexport default class AppUserPermissionsTab extends SliderSuperTabEventable {\r\n public participant: ChannelParticipant;\r\n public chatId: number;\r\n public userId: number;\r\n\r\n protected init() {\r\n this.container.classList.add('edit-peer-container', 'user-permissions-container');\r\n this.setTitle('UserRestrictions');\r\n\r\n let destroyListener: () => void;\r\n\r\n {\r\n const section = new SettingSection({\r\n name: 'UserRestrictionsCanDo',\r\n });\r\n \r\n const div = document.createElement('div');\r\n div.classList.add('chatlist-container');\r\n section.content.insertBefore(div, section.title);\r\n\r\n const list = appDialogsManager.createChatList();\r\n div.append(list);\r\n\r\n const {dom} = appDialogsManager.addDialogNew({\r\n dialog: this.userId,\r\n container: list,\r\n drawStatus: false,\r\n rippleEnabled: true,\r\n avatarSize: 48\r\n });\r\n\r\n dom.lastMessageSpan.append(appUsersManager.getUserStatusString(this.userId));\r\n\r\n const p = new ChatPermissions({\r\n chatId: this.chatId,\r\n listenerSetter: this.listenerSetter,\r\n appendTo: section.content,\r\n participant: this.participant._ === 'channelParticipantBanned' ? this.participant : undefined\r\n });\r\n\r\n destroyListener = () => {\r\n //appChatsManager.editChatDefaultBannedRights(this.chatId, p.takeOut());\r\n const rights = p.takeOut();\r\n if(this.participant._ === 'channelParticipantBanned' && deepEqual(this.participant.banned_rights.pFlags, rights.pFlags)) {\r\n return;\r\n }\r\n\r\n appChatsManager.editBanned(this.chatId, this.participant, rights);\r\n };\r\n\r\n this.eventListener.addEventListener('destroy', destroyListener);\r\n\r\n this.scrollable.append(section.container);\r\n }\r\n \r\n {\r\n const section = new SettingSection({});\r\n\r\n if(this.participant._ === 'channelParticipantBanned') {\r\n const btnDeleteException = Button('btn-primary btn-transparent danger', {icon: 'delete', text: 'GroupPermission.Delete'});\r\n\r\n attachClickEvent(btnDeleteException, () => {\r\n const toggle = toggleDisability([btnDeleteException], true);\r\n appChatsManager.clearChannelParticipantBannedRights(this.chatId, this.participant).then(() => {\r\n this.eventListener.removeEventListener('destroy', destroyListener);\r\n this.close();\r\n }, () => {\r\n toggle();\r\n });\r\n }, {listenerSetter: this.listenerSetter});\r\n \r\n section.content.append(btnDeleteException);\r\n }\r\n\r\n const btnDelete = Button('btn-primary btn-transparent danger', {icon: 'deleteuser', text: 'UserRestrictionsBlock'});\r\n\r\n attachClickEvent(btnDelete, () => {\r\n const toggle = toggleDisability([btnDelete], true);\r\n appChatsManager.kickFromChannel(this.chatId, this.participant).then(() => {\r\n this.eventListener.removeEventListener('destroy', destroyListener);\r\n this.close();\r\n });\r\n /* new PopupPeer('popup-group-kick-user', {\r\n peerId: -this.chatId,\r\n title: 'Ban User?',\r\n description: `Are you sure you want to ban <b>${appPeersManager.getPeerTitle(this.userId)}</b>`,\r\n buttons: addCancelButton([{\r\n text: 'BAN',\r\n callback: () => {\r\n const toggle = toggleDisability([btnDelete], true);\r\n\r\n appChatsManager.kickFromChannel(this.chatId, this.participant).then(() => {\r\n this.eventListener.removeEventListener('destroy', destroyListener);\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 { attachClickEvent, replaceContent } from \"../../../helpers/dom\";\r\nimport findUpTag from \"../../../helpers/dom/findUpTag\";\r\nimport ListenerSetter from \"../../../helpers/listenerSetter\";\r\nimport ScrollableLoader from \"../../../helpers/listLoader\";\r\nimport { ChannelParticipant, Chat, ChatBannedRights, Update } from \"../../../layer\";\r\nimport appChatsManager, { ChatRights } from \"../../../lib/appManagers/appChatsManager\";\r\nimport appDialogsManager from \"../../../lib/appManagers/appDialogsManager\";\r\nimport appProfileManager from \"../../../lib/appManagers/appProfileManager\";\r\nimport I18n, { i18n, join, LangPackKey } from \"../../../lib/langPack\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport CheckboxField from \"../../checkboxField\";\r\nimport PopupPickUser from \"../../popups/pickUser\";\r\nimport Row from \"../../row\";\r\nimport { SettingSection } from \"../../sidebarLeft\";\r\nimport { SliderSuperTabEventable } from \"../../sliderTab\";\r\nimport { toast } from \"../../toast\";\r\nimport AppUserPermissionsTab from \"./userPermissions\";\r\n\r\nexport class ChatPermissions {\r\n public v: Array<{\r\n flags: ChatRights[],\r\n text: LangPackKey,\r\n exceptionText: LangPackKey,\r\n checkboxField?: CheckboxField,\r\n }>;\r\n private toggleWith: Partial<{[chatRight in ChatRights]: ChatRights[]}>;\r\n\r\n constructor(options: {\r\n chatId: number,\r\n listenerSetter: ListenerSetter,\r\n appendTo: HTMLElement,\r\n participant?: ChannelParticipant.channelParticipantBanned\r\n }) {\r\n this.v = [\r\n {flags: ['send_messages'], text: 'UserRestrictionsSend', exceptionText: 'UserRestrictionsNoSend'},\r\n {flags: ['send_media'], text: 'UserRestrictionsSendMedia', exceptionText: 'UserRestrictionsNoSendMedia'},\r\n {flags: ['send_stickers', 'send_gifs'], text: 'UserRestrictionsSendStickers', exceptionText: 'UserRestrictionsNoSendStickers'},\r\n {flags: ['send_polls'], text: 'UserRestrictionsSendPolls', exceptionText: 'UserRestrictionsNoSendPolls'},\r\n {flags: ['embed_links'], text: 'UserRestrictionsEmbedLinks', exceptionText: 'UserRestrictionsNoEmbedLinks'},\r\n {flags: ['invite_users'], text: 'UserRestrictionsInviteUsers', exceptionText: 'UserRestrictionsNoInviteUsers'},\r\n {flags: ['pin_messages'], text: 'UserRestrictionsPinMessages', exceptionText: 'UserRestrictionsNoPinMessages'},\r\n {flags: ['change_info'], text: 'UserRestrictionsChangeInfo', exceptionText: 'UserRestrictionsNoChangeInfo'}\r\n ];\r\n\r\n this.toggleWith = {\r\n 'send_messages': ['send_media', 'send_stickers', 'send_polls', 'embed_links']\r\n };\r\n\r\n const chat: Chat.chat = appChatsManager.getChat(options.chatId);\r\n const defaultBannedRights = chat.default_banned_rights;\r\n const rights = options.participant ? appChatsManager.combineParticipantBannedRights(options.chatId, options.participant.banned_rights) : defaultBannedRights;\r\n \r\n for(const info of this.v) {\r\n const mainFlag = info.flags[0];\r\n info.checkboxField = new CheckboxField({\r\n text: info.text,\r\n checked: appChatsManager.hasRights(options.chatId, mainFlag, rights),\r\n restriction: true,\r\n withRipple: true\r\n });\r\n\r\n // @ts-ignore\r\n if(options.participant && defaultBannedRights.pFlags[mainFlag]) {\r\n info.checkboxField.input.disabled = true;\r\n \r\n /* options.listenerSetter.add(info.checkboxField.input, 'change', (e) => {\r\n if(!e.isTrusted) {\r\n return;\r\n }\r\n\r\n cancelEvent(e);\r\n toast('This option is disabled for all members in Group Permissions.');\r\n info.checkboxField.checked = false;\r\n }); */\r\n\r\n attachClickEvent(info.checkboxField.label, (e) => {\r\n toast(I18n.format('UserRestrictionsDisabled', true));\r\n }, {listenerSetter: options.listenerSetter});\r\n }\r\n\r\n if(this.toggleWith[mainFlag]) {\r\n options.listenerSetter.add(info.checkboxField.input, 'change', () => {\r\n if(!info.checkboxField.checked) {\r\n const other = this.v.filter(i => this.toggleWith[mainFlag].includes(i.flags[0]));\r\n other.forEach(info => {\r\n info.checkboxField.checked = false;\r\n });\r\n }\r\n });\r\n }\r\n\r\n options.appendTo.append(info.checkboxField.label);\r\n }\r\n }\r\n\r\n public takeOut() {\r\n const rights: ChatBannedRights = {\r\n _: 'chatBannedRights',\r\n until_date: 0x7FFFFFFF,\r\n pFlags: {}\r\n };\r\n\r\n for(const info of this.v) {\r\n const banned = !info.checkboxField.checked;\r\n if(banned) {\r\n info.flags.forEach(flag => {\r\n // @ts-ignore\r\n rights.pFlags[flag] = true;\r\n });\r\n }\r\n }\r\n\r\n return rights;\r\n }\r\n}\r\n\r\nexport default class AppGroupPermissionsTab extends SliderSuperTabEventable {\r\n public chatId: number;\r\n\r\n protected async init() {\r\n this.container.classList.add('edit-peer-container', 'group-permissions-container');\r\n this.setTitle('ChannelPermissions');\r\n\r\n let chatPermissions: ChatPermissions;\r\n {\r\n const section = new SettingSection({\r\n name: 'ChannelPermissionsHeader',\r\n });\r\n\r\n chatPermissions = new ChatPermissions({\r\n chatId: this.chatId,\r\n listenerSetter: this.listenerSetter,\r\n appendTo: section.content,\r\n });\r\n\r\n this.eventListener.addEventListener('destroy', () => {\r\n appChatsManager.editChatDefaultBannedRights(this.chatId, chatPermissions.takeOut());\r\n });\r\n\r\n this.scrollable.append(section.container);\r\n }\r\n \r\n {\r\n const section = new SettingSection({\r\n name: 'PrivacyExceptions'\r\n });\r\n\r\n const addExceptionRow = new Row({\r\n titleLangKey: 'ChannelAddException',\r\n subtitleLangKey: 'Loading',\r\n icon: 'adduser',\r\n clickable: () => {\r\n new PopupPickUser({\r\n peerTypes: ['channelParticipants'],\r\n onSelect: (peerId) => {\r\n setTimeout(() => {\r\n openPermissions(peerId);\r\n }, 0);\r\n },\r\n placeholder: 'ExceptionModal.Search.Placeholder',\r\n peerId: -this.chatId,\r\n });\r\n }\r\n });\r\n\r\n const openPermissions = async(peerId: number) => {\r\n let participant: AppUserPermissionsTab['participant'];\r\n try {\r\n participant = await appProfileManager.getChannelParticipant(this.chatId, peerId) as any;\r\n } catch(err) {\r\n toast('User is no longer participant');\r\n return;\r\n }\r\n\r\n const tab = new AppUserPermissionsTab(this.slider);\r\n tab.participant = participant;\r\n tab.chatId = this.chatId;\r\n tab.userId = peerId;\r\n tab.open();\r\n };\r\n\r\n section.content.append(addExceptionRow.container);\r\n\r\n /* const removedUsersRow = new Row({\r\n titleLangKey: 'ChannelBlockedUsers',\r\n subtitleLangKey: 'NoBlockedUsers',\r\n icon: 'deleteuser',\r\n clickable: true\r\n });\r\n\r\n section.content.append(removedUsersRow.container); */\r\n\r\n const c = section.generateContentElement();\r\n c.classList.add('chatlist-container');\r\n \r\n const list = appDialogsManager.createChatList();\r\n c.append(list);\r\n\r\n attachClickEvent(list, (e) => {\r\n const target = findUpTag(e.target, 'LI');\r\n if(!target) return;\r\n\r\n const peerId = +target.dataset.peerId;\r\n openPermissions(peerId);\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n const setSubtitle = (li: Element, participant: ChannelParticipant.channelParticipantBanned) => {\r\n const bannedRights = participant.banned_rights;//appChatsManager.combineParticipantBannedRights(this.chatId, participant.banned_rights);\r\n const defaultBannedRights = (appChatsManager.getChat(this.chatId) as Chat.channel).default_banned_rights;\r\n //const combinedRights = appChatsManager.combineParticipantBannedRights(this.chatId, bannedRights);\r\n\r\n const cantWhat: LangPackKey[] = []/* , canWhat: LangPackKey[] = [] */;\r\n chatPermissions.v.forEach(info => {\r\n const mainFlag = info.flags[0];\r\n // @ts-ignore\r\n if(bannedRights.pFlags[mainFlag] && !defaultBannedRights.pFlags[mainFlag]) {\r\n cantWhat.push(info.exceptionText);\r\n // @ts-ignore\r\n }/* else if(!combinedRights.pFlags[mainFlag]) {\r\n canWhat.push(info.exceptionText);\r\n } */\r\n });\r\n\r\n const el = li.querySelector('.user-last-message') as HTMLElement;\r\n\r\n if(cantWhat.length) {\r\n el.innerHTML = '';\r\n el.append(...join(cantWhat.map(t => i18n(t)), false));\r\n }/* else if(canWhat.length) {\r\n str = 'Can ' + canWhat.join(canWhat.length === 2 ? ' and ' : ', ');\r\n } */\r\n \r\n el.classList.toggle('hide', !cantWhat.length);\r\n };\r\n\r\n const add = (participant: ChannelParticipant.channelParticipantBanned, append: boolean) => {\r\n const {dom} = appDialogsManager.addDialogNew({\r\n dialog: participant.user_id,\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 setSubtitle(dom.listEl, participant);\r\n\r\n //dom.titleSpan.innerHTML = 'Chinaza Akachi';\r\n //dom.lastMessageSpan.innerHTML = 'Can Add Users and Pin Messages';\r\n };\r\n\r\n this.listenerSetter.add(rootScope, 'apiUpdate', (update: Update) => {\r\n if(update._ === 'updateChannelParticipant') {\r\n const needAdd = update.new_participant?._ === 'channelParticipantBanned' && !update.new_participant.banned_rights.pFlags.view_messages;\r\n const li = list.querySelector(`[data-peer-id=\"${update.user_id}\"]`);\r\n if(needAdd) {\r\n if(!li) {\r\n add(update.new_participant as ChannelParticipant.channelParticipantBanned, false);\r\n } else {\r\n setSubtitle(li, update.new_participant as ChannelParticipant.channelParticipantBanned);\r\n }\r\n\r\n if(update.prev_participant?._ !== 'channelParticipantBanned') {\r\n ++exceptionsCount;\r\n }\r\n } else {\r\n if(li) {\r\n li.remove();\r\n }\r\n\r\n if(update.prev_participant?._ === 'channelParticipantBanned') {\r\n --exceptionsCount;\r\n }\r\n }\r\n\r\n setLength();\r\n }\r\n });\r\n\r\n const setLength = () => {\r\n replaceContent(addExceptionRow.subtitle, i18n(exceptionsCount ? 'Permissions.ExceptionsCount' : 'Permissions.NoExceptions', [exceptionsCount]));\r\n };\r\n\r\n let exceptionsCount = 0;\r\n const LOAD_COUNT = 50;\r\n const loader = new ScrollableLoader({\r\n scrollable: this.scrollable,\r\n getPromise: () => {\r\n return appProfileManager.getChannelParticipants(this.chatId, {_: 'channelParticipantsBanned', q: ''}, LOAD_COUNT, list.childElementCount).then(res => {\r\n for(const participant of res.participants) {\r\n add(participant as ChannelParticipant.channelParticipantBanned, true);\r\n }\r\n\r\n exceptionsCount = res.count;\r\n setLength();\r\n\r\n return res.participants.length < LOAD_COUNT || res.count === list.childElementCount;\r\n });\r\n }\r\n });\r\n\r\n this.scrollable.append(section.container);\r\n\r\n await loader.load();\r\n }\r\n }\r\n\r\n onOpenAfterTimeout() {\r\n this.scrollable.onScroll();\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 appChatsManager from \"../../lib/appManagers/appChatsManager\";\r\nimport appMessagesManager from \"../../lib/appManagers/appMessagesManager\";\r\nimport appPeersManager, { PeerType } from \"../../lib/appManagers/appPeersManager\";\r\nimport { LangPackKey } from \"../../lib/langPack\";\r\nimport PeerTitle from \"../peerTitle\";\r\nimport PopupPeer, { PopupPeerButtonCallbackCheckboxes, PopupPeerOptions } from \"./peer\";\r\n\r\nexport default class PopupDeleteDialog {\r\n constructor(peerId: number, peerType: PeerType = appPeersManager.getDialogType(peerId), onSelect?: (promise: Promise<any>) => void) {\r\n const peerTitleElement = new PeerTitle({\r\n peerId,\r\n onlyFirstName: true\r\n }).element;\r\n\r\n /* const callbackFlush = (checked: PopupPeerButtonCallbackCheckboxes) => {\r\n const promise = appMessagesManager.flushHistory(peerId, checkboxes ? !checked[checkboxes[0].text] : undefined);\r\n onSelect && onSelect(promise);\r\n }; */\r\n\r\n const callbackLeave = (checked: PopupPeerButtonCallbackCheckboxes) => {\r\n const promise = appChatsManager.leave(-peerId);\r\n onSelect && onSelect(promise);\r\n };\r\n\r\n const callbackDelete = (checked: PopupPeerButtonCallbackCheckboxes) => {\r\n let promise: Promise<any>;\r\n\r\n if(peerId > 0) {\r\n promise = appMessagesManager.flushHistory(peerId, false, checkboxes ? checked[checkboxes[0].text] : undefined);\r\n } else {\r\n if(checked[checkboxes[0].text]) {\r\n promise = appChatsManager.delete(-peerId);\r\n } else {\r\n promise = appChatsManager.leave(-peerId);\r\n }\r\n }\r\n \r\n onSelect && onSelect(promise);\r\n };\r\n\r\n let title: LangPackKey, description: LangPackKey, descriptionArgs: any[], buttons: PopupPeerOptions['buttons'], checkboxes: PopupPeerOptions['checkboxes'];\r\n switch(peerType) {\r\n case 'channel': {\r\n title = 'LeaveChannelMenu';\r\n description = 'ChannelLeaveAlertWithName';\r\n descriptionArgs = [peerTitleElement];\r\n buttons = [{\r\n langKey: 'LeaveChannel',\r\n isDanger: true,\r\n callback: callbackLeave\r\n }];\r\n\r\n break;\r\n }\r\n\r\n /* case 'megagroup': {\r\n title = 'Leave Group?';\r\n description = `Are you sure you want to leave this group?`;\r\n buttons = [{\r\n text: 'LEAVE ' + peerTitleElement,\r\n isDanger: true,\r\n callback: callbackLeave\r\n }];\r\n\r\n break;\r\n } */\r\n\r\n case 'chat': {\r\n title = 'DeleteChatUser';\r\n description = 'AreYouSureDeleteThisChatWithUser';\r\n descriptionArgs = [peerTitleElement];\r\n\r\n checkboxes = [{\r\n text: 'DeleteMessagesOptionAlso',\r\n textArgs: [\r\n new PeerTitle({\r\n peerId,\r\n onlyFirstName: true\r\n }).element\r\n ]\r\n }];\r\n\r\n buttons = [{\r\n langKey: 'DeleteChatUser',\r\n isDanger: true,\r\n callback: callbackDelete\r\n }];\r\n\r\n break;\r\n }\r\n\r\n case 'saved': {\r\n title = 'DeleteChatUser';\r\n description = 'AreYouSureDeleteThisChatSavedMessages';\r\n buttons = [{\r\n langKey: 'DeleteChatUser',\r\n isDanger: true,\r\n callback: callbackDelete\r\n }];\r\n\r\n break;\r\n }\r\n\r\n case 'megagroup':\r\n case 'group': {\r\n if(appChatsManager.hasRights(-peerId, 'delete_chat')) {\r\n title = 'DeleteMegaMenu';\r\n description = 'AreYouSureDeleteAndExit';\r\n buttons = [{\r\n langKey: 'DeleteMegaMenu',\r\n isDanger: true,\r\n callback: callbackDelete\r\n }];\r\n\r\n checkboxes = [{\r\n text: 'DeleteChat.DeleteGroupForAll'\r\n }];\r\n } else {\r\n title = 'LeaveMegaMenu';\r\n description = 'AreYouSureDeleteAndExitName';\r\n descriptionArgs = [peerTitleElement];\r\n buttons = [{\r\n langKey: 'DeleteChatUser',\r\n isDanger: true,\r\n callback: callbackLeave\r\n }];\r\n }\r\n\r\n break;\r\n }\r\n }\r\n\r\n new PopupPeer('popup-delete-chat', {\r\n peerId,\r\n titleLangKey: title,\r\n descriptionLangKey: description,\r\n descriptionLangArgs: descriptionArgs,\r\n buttons,\r\n checkboxes\r\n }).show();\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 Button from \"../../button\";\r\nimport appChatsManager, { ChatRights } from \"../../../lib/appManagers/appChatsManager\";\r\nimport appProfileManager from \"../../../lib/appManagers/appProfileManager\";\r\nimport { attachClickEvent, toggleDisability } from \"../../../helpers/dom\";\r\nimport { ChatFull } from \"../../../layer\";\r\nimport AppGroupTypeTab from \"./groupType\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport AppGroupPermissionsTab from \"./groupPermissions\";\r\nimport { i18n } from \"../../../lib/langPack\";\r\nimport PopupDeleteDialog from \"../../popups/deleteDialog\";\r\n\r\nexport default class AppEditGroupTab extends SliderSuperTab {\r\n private groupNameInputField: InputField;\r\n private descriptionInputField: InputField;\r\n private editPeer: EditPeer;\r\n public chatId: number;\r\n\r\n protected async _init() {\r\n // * cleanup prev\r\n this.listenerSetter.removeAll();\r\n this.scrollable.container.innerHTML = '';\r\n\r\n this.container.classList.add('edit-peer-container', 'edit-group-container');\r\n this.setTitle('Edit');\r\n\r\n const chatFull = await appProfileManager.getChatFull(this.chatId, true);\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.groupNameInputField = new InputField({\r\n label: 'CreateGroup.NameHolder',\r\n name: 'group-name',\r\n maxLength: 255\r\n });\r\n this.descriptionInputField = new InputField({\r\n label: 'DescriptionPlaceholder',\r\n name: 'group-description',\r\n maxLength: 255\r\n });\r\n\r\n const chat = appChatsManager.getChat(this.chatId);\r\n \r\n this.groupNameInputField.setOriginalValue(chat.title);\r\n\r\n this.descriptionInputField.setOriginalValue(chatFull.about);\r\n\r\n inputWrapper.append(this.groupNameInputField.container, this.descriptionInputField.container);\r\n \r\n inputFields.push(this.groupNameInputField, this.descriptionInputField);\r\n\r\n this.editPeer = new EditPeer({\r\n peerId: -this.chatId,\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(appChatsManager.hasRights(this.chatId, 'change_type')) {\r\n const groupTypeRow = new Row({\r\n titleLangKey: 'GroupType',\r\n clickable: () => {\r\n const tab = new AppGroupTypeTab(this.slider);\r\n tab.peerId = -this.chatId;\r\n tab.chatFull = chatFull;\r\n tab.open();\r\n\r\n this.listenerSetter.add(tab.eventListener, 'destroy', setGroupTypeSubtitle);\r\n },\r\n icon: 'lock'\r\n });\r\n\r\n const setGroupTypeSubtitle = () => {\r\n groupTypeRow.subtitle.textContent = '';\r\n groupTypeRow.subtitle.append(i18n(chat.username ? 'TypePublicGroup' : 'TypePrivateGroup'));\r\n };\r\n\r\n setGroupTypeSubtitle();\r\n section.content.append(groupTypeRow.container);\r\n }\r\n\r\n if(appChatsManager.hasRights(this.chatId, 'change_permissions')) {\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.groupNameInputField.isValid()) {\r\n promises.push(appChatsManager.editTitle(id, this.groupNameInputField.value));\r\n }\r\n\r\n if(this.descriptionInputField.isValid()) {\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 /* {\r\n const section = new SettingSection({\r\n\r\n });\r\n\r\n const membersRow = new Row({\r\n titleLangKey: 'GroupMembers',\r\n subtitle: '2 500',\r\n icon: 'newgroup',\r\n clickable: true\r\n });\r\n\r\n section.content.append(membersRow.container);\r\n\r\n if(appChatsManager.hasRights(this.chatId, 'change_permissions')) {\r\n const showChatHistoryCheckboxField = new CheckboxField({\r\n text: 'Show chat history for new members',\r\n withRipple: true\r\n });\r\n \r\n if(appChatsManager.isChannel(this.chatId) && !(chatFull as ChatFull.channelFull).pFlags.hidden_prehistory) {\r\n showChatHistoryCheckboxField.checked = true;\r\n }\r\n \r\n section.content.append(showChatHistoryCheckboxField.label);\r\n }\r\n\r\n this.scrollable.append(section.container);\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: 'DeleteMega'});\r\n\r\n attachClickEvent(btnDelete, () => {\r\n new PopupDeleteDialog(-this.chatId, 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 // ! 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(-this.chatId === migrateFrom) {\r\n this.chatId = -migrateTo;\r\n this._init();\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 appChatsManager from \"../../../lib/appManagers/appChatsManager\";\r\nimport appProfileManager from \"../../../lib/appManagers/appProfileManager\";\r\nimport { attachClickEvent, toggleDisability } from \"../../../helpers/dom\";\r\nimport PopupPeer from \"../../popups/peer\";\r\nimport { addCancelButton } from \"../../popups\";\r\nimport { i18n } from \"../../../lib/langPack\";\r\nimport { numberThousandSplitter } from \"../../../helpers/number\";\r\n\r\nexport default class AppEditChannelTab extends SliderSuperTab {\r\n private nameInputField: InputField;\r\n private descriptionInputField: InputField;\r\n private editPeer: EditPeer;\r\n public peerId: number;\r\n\r\n protected async init() {\r\n this.container.classList.add('edit-peer-container', 'edit-channel-container');\r\n this.setTitle('Edit');\r\n\r\n const chatFull = await appProfileManager.getChannelFull(-this.peerId, true);\r\n\r\n {\r\n const section = new SettingSection({noDelimiter: true});\r\n\r\n if(appChatsManager.hasRights(-this.peerId, 'change_info')) {\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: 'Channel.ChannelNameHolder',\r\n name: 'channel-name',\r\n maxLength: 255\r\n });\r\n this.descriptionInputField = new InputField({\r\n label: 'DescriptionPlaceholder',\r\n name: 'channel-description',\r\n maxLength: 255\r\n });\r\n \r\n this.nameInputField.setOriginalValue(appChatsManager.getChat(-this.peerId).title);\r\n\r\n this.descriptionInputField.setOriginalValue(chatFull.about);\r\n\r\n inputWrapper.append(this.nameInputField.container, this.descriptionInputField.container);\r\n \r\n inputFields.push(this.nameInputField, this.descriptionInputField);\r\n\r\n this.editPeer = new EditPeer({\r\n peerId: this.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 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.peerId;\r\n if(this.nameInputField.isValid()) {\r\n promises.push(appChatsManager.editTitle(id, this.nameInputField.value));\r\n }\r\n \r\n if(this.descriptionInputField.isValid()) {\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_type')) {\r\n const channelTypeRow = new Row({\r\n titleLangKey: 'ChannelType',\r\n subtitleLangKey: 'TypePrivate',\r\n clickable: true,\r\n icon: 'lock'\r\n });\r\n \r\n section.content.append(channelTypeRow.container);\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(appChatsManager.hasRights(-this.peerId, 'change_info')) {\r\n const signMessagesCheckboxField = new CheckboxField({\r\n text: 'PeerInfo.SignMessages',\r\n checked: false\r\n });\r\n\r\n section.content.append(signMessagesCheckboxField.label);\r\n } */\r\n\r\n this.scrollable.append(section.container);\r\n }\r\n\r\n /* {\r\n const section = new SettingSection({\r\n\r\n });\r\n\r\n const subscribersRow = new Row({\r\n titleLangKey: 'PeerInfo.Subscribers',\r\n icon: 'newgroup',\r\n clickable: true\r\n });\r\n\r\n subscribersRow.subtitle.append(i18n('Subscribers', [numberThousandSplitter(335356)]));\r\n\r\n section.content.append(subscribersRow.container);\r\n\r\n this.scrollable.append(section.container);\r\n } */\r\n\r\n if(appChatsManager.hasRights(-this.peerId, 'delete_chat')) {\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.DeleteChannel'});\r\n\r\n attachClickEvent(btnDelete, () => {\r\n new PopupPeer('popup-delete-channel', {\r\n peerId: this.peerId,\r\n titleLangKey: 'ChannelDeleteMenu',\r\n descriptionLangKey: 'AreYouSureDeleteAndExitChannel',\r\n buttons: addCancelButton([{\r\n langKey: 'ChannelDeleteMenu',\r\n callback: () => {\r\n const toggle = toggleDisability([btnDelete], true);\r\n\r\n },\r\n isDanger: true\r\n }, {\r\n langKey: 'DeleteChannelForAll',\r\n callback: () => {\r\n const toggle = toggleDisability([btnDelete], true);\r\n\r\n appChatsManager.deleteChannel(-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 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 { attachClickEvent, toggleDisability } from \"../../../helpers/dom\";\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\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: number;\r\n\r\n protected init() {\r\n this.container.classList.add('edit-peer-container', 'edit-contact-container');\r\n this.setTitle('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: 'EditProfile.FirstNameLabel',\r\n name: 'contact-name',\r\n maxLength: 70\r\n });\r\n this.lastNameInputField = new InputField({\r\n label: 'Login.Register.LastName.Placeholder',\r\n name: 'contact-lastname',\r\n maxLength: 70\r\n });\r\n \r\n const user = appUsersManager.getUser(this.peerId);\r\n\r\n this.nameInputField.setOriginalValue(user.first_name);\r\n this.lastNameInputField.setOriginalValue(user.last_name);\r\n\r\n inputWrapper.append(this.nameInputField.container, this.lastNameInputField.container);\r\n \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 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.mutePeer(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 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 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, notificationsRow.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 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 {\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 { cancelEvent } from \"../helpers/dom\";\r\nimport { safeAssign } from \"../helpers/object\";\r\nimport { isTouchSupported } from \"../helpers/touchSupport\";\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\nexport default class SwipeHandler {\r\n private element: HTMLElement;\r\n private onSwipe: (xDiff: number, yDiff: number) => boolean;\r\n private verifyTouchTarget: (evt: TouchEvent | MouseEvent) => boolean;\r\n private onFirstSwipe: () => void;\r\n private onReset: () => void;\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: {\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 }) {\r\n safeAssign(this, options);\r\n\r\n if(!isTouchSupported) {\r\n this.element.addEventListener('mousedown', this.handleStart, false);\r\n attachGlobalListenerTo.addEventListener('mouseup', this.reset);\r\n } else {\r\n this.element.addEventListener('touchstart', this.handleStart, false);\r\n attachGlobalListenerTo.addEventListener('touchend', this.reset);\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(isTouchSupported) {\r\n attachGlobalListenerTo.removeEventListener('touchmove', this.handleMove, {capture: true});\r\n } else {\r\n attachGlobalListenerTo.removeEventListener('mousemove', this.handleMove);\r\n this.element.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(isTouchSupported) {\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) {\r\n return this.reset();\r\n }\r\n\r\n cancelEvent(_e);\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(!isTouchSupported) {\r\n this.element.style.cursor = 'grabbing';\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 if(this.onSwipe(xDiff, yDiff)) {\r\n this.reset();\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 { putPreloader } from \"../../misc\";\r\nimport Button from \"../../button\";\r\nimport { LangPackKey, _i18n } from \"../../../lib/langPack\";\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: number[]) => Promise<any> | false | void;\r\n private skippable: boolean;\r\n\r\n protected init() {\r\n this.nextBtn = Button('btn-corner btn-circle', {icon: 'arrow_next'});\r\n this.content.append(this.nextBtn);\r\n \r\n this.nextBtn.addEventListener('click', () => {\r\n const peerIds = this.selector.getSelected();\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 this.nextBtn.classList.remove('tgico-arrow_next');\r\n this.nextBtn.disabled = true;\r\n putPreloader(this.nextBtn);\r\n this.selector.freezed = true;\r\n\r\n promise.then(() => {\r\n this.close();\r\n });\r\n }\r\n\r\n public open(options: {\r\n title: LangPackKey,\r\n placeholder: LangPackKey,\r\n peerId?: number, \r\n type: AppAddMembersTab['peerType'], \r\n takeOut?: AppAddMembersTab['takeOut'],\r\n skippable: boolean,\r\n selectedPeerIds?: number[]\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 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: ['contacts'],\r\n placeholder: options.placeholder\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}","/*\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 appMessagesManager, { AppMessagesManager } from \"../../../lib/appManagers/appMessagesManager\";\r\nimport appPeersManager from \"../../../lib/appManagers/appPeersManager\";\r\nimport appProfileManager from \"../../../lib/appManagers/appProfileManager\";\r\nimport appUsersManager, { User } from \"../../../lib/appManagers/appUsersManager\";\r\nimport { RichTextProcessor } from \"../../../lib/richtextprocessor\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport AppSearchSuper, { SearchSuperType } from \"../../appSearchSuper.\";\r\nimport AvatarElement, { openAvatarViewer } from \"../../avatar\";\r\nimport SidebarSlider, { SliderSuperTab } from \"../../slider\";\r\nimport CheckboxField from \"../../checkboxField\";\r\nimport { attachClickEvent, replaceContent, cancelEvent } from \"../../../helpers/dom\";\r\nimport appSidebarRight from \"..\";\r\nimport { TransitionSlider } from \"../../transition\";\r\nimport appNotificationsManager from \"../../../lib/appManagers/appNotificationsManager\";\r\nimport AppEditGroupTab from \"./editGroup\";\r\nimport PeerTitle from \"../../peerTitle\";\r\nimport AppEditChannelTab from \"./editChannel\";\r\nimport AppEditContactTab from \"./editContact\";\r\nimport appChatsManager, { Channel } from \"../../../lib/appManagers/appChatsManager\";\r\nimport { Chat, Message, MessageAction, ChatFull, Photo } from \"../../../layer\";\r\nimport Button from \"../../button\";\r\nimport ButtonIcon from \"../../buttonIcon\";\r\nimport I18n, { i18n, LangPackKey } from \"../../../lib/langPack\";\r\nimport { SettingSection } from \"../../sidebarLeft\";\r\nimport Row from \"../../row\";\r\nimport { copyTextToClipboard } from \"../../../helpers/clipboard\";\r\nimport { toast } from \"../../toast\";\r\nimport { fastRaf } from \"../../../helpers/schedulers\";\r\nimport { safeAssign } from \"../../../helpers/object\";\r\nimport { forEachReverse } from \"../../../helpers/array\";\r\nimport appPhotosManager from \"../../../lib/appManagers/appPhotosManager\";\r\nimport renderImageFromUrl from \"../../../helpers/dom/renderImageFromUrl\";\r\nimport SwipeHandler from \"../../swipeHandler\";\r\nimport { MOUNT_CLASS_TO } from \"../../../config/debug\";\r\nimport AppAddMembersTab from \"../../sidebarLeft/tabs/addMembers\";\r\nimport PopupPickUser from \"../../popups/pickUser\";\r\nimport PopupPeer from \"../../popups/peer\";\r\nimport Scrollable from \"../../scrollable\";\r\nimport { isTouchSupported } from \"../../../helpers/touchSupport\";\r\n\r\nlet setText = (text: string, row: Row) => {\r\n //fastRaf(() => {\r\n row.title.innerHTML = text;\r\n row.container.style.display = '';\r\n //});\r\n};\r\n\r\ntype ListLoaderResult<T> = {count: number, items: any[]};\r\nclass ListLoader<T> {\r\n public current: T;\r\n public previous: T[] = [];\r\n public next: T[] = [];\r\n public count: number;\r\n\r\n public tempId = 0;\r\n public loadMore: (anchor: T, older: boolean) => Promise<ListLoaderResult<T>>;\r\n public processItem: (item: any) => false | T;\r\n public onJump: (item: T, older: boolean) => void;\r\n public loadCount = 50;\r\n public reverse = false; // reverse means next = higher msgid\r\n\r\n public loadedAllUp = false;\r\n public loadedAllDown = false;\r\n public loadPromiseUp: Promise<void>;\r\n public loadPromiseDown: Promise<void>;\r\n\r\n constructor(options: {\r\n loadMore: ListLoader<T>['loadMore'],\r\n loadCount: ListLoader<T>['loadCount'],\r\n processItem?: ListLoader<T>['processItem'],\r\n onJump: ListLoader<T>['onJump'],\r\n }) {\r\n safeAssign(this, options);\r\n\r\n\r\n }\r\n\r\n get index() {\r\n return this.count !== undefined ? this.previous.length : -1;\r\n }\r\n\r\n public go(length: number) {\r\n let items: T[], item: T;\r\n if(length > 0) {\r\n items = this.next.splice(0, length);\r\n item = items.pop();\r\n if(!item) {\r\n return;\r\n }\r\n\r\n this.previous.push(this.current, ...items);\r\n } else {\r\n items = this.previous.splice(this.previous.length + length, -length);\r\n item = items.shift();\r\n if(!item) {\r\n return;\r\n }\r\n\r\n this.next.unshift(...items, this.current);\r\n }\r\n\r\n this.current = item;\r\n this.onJump(item, length > 0);\r\n }\r\n\r\n public load(older: boolean) {\r\n if(older && this.loadedAllDown) return Promise.resolve();\r\n else if(!older && this.loadedAllUp) return Promise.resolve();\r\n\r\n if(older && this.loadPromiseDown) return this.loadPromiseDown;\r\n else if(!older && this.loadPromiseUp) return this.loadPromiseUp;\r\n\r\n /* const loadCount = 50;\r\n const backLimit = older ? 0 : loadCount; */\r\n \r\n let anchor: T;\r\n if(older) {\r\n anchor = this.reverse ? this.previous[0] : this.next[this.next.length - 1];\r\n } else {\r\n anchor = this.reverse ? this.next[this.next.length - 1] : this.previous[0];\r\n }\r\n\r\n const promise = this.loadMore(anchor, older).then(result => {\r\n if(result.items.length < this.loadCount) {\r\n if(older) this.loadedAllDown = true;\r\n else this.loadedAllUp = true;\r\n }\r\n\r\n if(this.count === undefined) {\r\n this.count = result.count || result.items.length;\r\n }\r\n\r\n const method = older ? result.items.forEach.bind(result.items) : forEachReverse.bind(null, result.items);\r\n method((item: any) => {\r\n const processed = this.processItem ? this.processItem(item) : item;\r\n\r\n if(!processed) return;\r\n\r\n if(older) {\r\n if(this.reverse) this.previous.unshift(processed);\r\n else this.next.push(processed);\r\n } else {\r\n if(this.reverse) this.next.push(processed);\r\n else this.previous.unshift(processed);\r\n }\r\n });\r\n }, () => {}).then(() => {\r\n if(older) this.loadPromiseDown = null;\r\n else this.loadPromiseUp = null;\r\n });\r\n\r\n if(older) this.loadPromiseDown = promise;\r\n else this.loadPromiseUp = promise;\r\n\r\n return promise;\r\n }\r\n}\r\n\r\nclass PeerProfileAvatars {\r\n public static BASE_CLASS = 'profile-avatars';\r\n public container: HTMLElement;\r\n public avatars: HTMLElement;\r\n public gradient: HTMLElement;\r\n public info: HTMLElement;\r\n public tabs: HTMLDivElement;\r\n public listLoader: ListLoader<string | Message.messageService>;\r\n public peerId: number;\r\n\r\n constructor(public scrollable: Scrollable) {\r\n this.container = document.createElement('div');\r\n this.container.classList.add(PeerProfileAvatars.BASE_CLASS + '-container');\r\n\r\n this.avatars = document.createElement('div');\r\n this.avatars.classList.add(PeerProfileAvatars.BASE_CLASS + '-avatars');\r\n\r\n this.gradient = document.createElement('div');\r\n this.gradient.classList.add(PeerProfileAvatars.BASE_CLASS + '-gradient');\r\n\r\n this.info = document.createElement('div');\r\n this.info.classList.add(PeerProfileAvatars.BASE_CLASS + '-info');\r\n\r\n this.tabs = document.createElement('div');\r\n this.tabs.classList.add(PeerProfileAvatars.BASE_CLASS + '-tabs');\r\n\r\n this.container.append(this.avatars, this.gradient, this.info, this.tabs);\r\n\r\n const checkScrollTop = () => {\r\n if(this.scrollable.scrollTop !== 0) {\r\n this.scrollable.scrollIntoViewNew(this.scrollable.container.firstElementChild as HTMLElement, 'start');\r\n return false;\r\n }\r\n\r\n return true;\r\n };\r\n\r\n const SWITCH_ZONE = 1 / 3;\r\n let cancel = false;\r\n let freeze = false;\r\n attachClickEvent(this.container, async(_e) => {\r\n if(freeze) {\r\n cancelEvent(_e);\r\n return;\r\n }\r\n\r\n if(cancel) {\r\n cancel = false;\r\n return;\r\n }\r\n\r\n if(!checkScrollTop()) {\r\n return;\r\n }\r\n\r\n const rect = this.container.getBoundingClientRect();\r\n\r\n const e = (_e as TouchEvent).touches ? (_e as TouchEvent).touches[0] : _e as MouseEvent;\r\n const x = e.pageX;\r\n\r\n const clickX = x - rect.left;\r\n if((!this.listLoader.previous.length && !this.listLoader.next.length) \r\n || (clickX > (rect.width * SWITCH_ZONE) && clickX < (rect.width - rect.width * SWITCH_ZONE))) {\r\n const peerId = this.peerId;\r\n\r\n const targets: {element: HTMLElement, item: string | Message.messageService}[] = [];\r\n this.listLoader.previous.concat(this.listLoader.current, this.listLoader.next).forEach((item, idx) => {\r\n targets.push({\r\n element: /* null */this.avatars.children[idx] as HTMLElement,\r\n item\r\n });\r\n });\r\n\r\n const prevTargets = targets.slice(0, this.listLoader.previous.length);\r\n const nextTargets = targets.slice(this.listLoader.previous.length + 1);\r\n\r\n const target = this.avatars.children[this.listLoader.previous.length] as HTMLElement;\r\n freeze = true;\r\n openAvatarViewer(target, peerId, () => peerId === this.peerId, this.listLoader.current, prevTargets, nextTargets);\r\n freeze = false;\r\n } else {\r\n const centerX = rect.right - (rect.width / 2);\r\n const toRight = x > centerX;\r\n \r\n // this.avatars.classList.remove('no-transition');\r\n // fastRaf(() => {\r\n this.listLoader.go(toRight ? 1 : -1);\r\n // });\r\n }\r\n });\r\n\r\n const cancelNextClick = () => {\r\n cancel = true;\r\n document.body.addEventListener(isTouchSupported ? 'touchend' : 'click', (e) => {\r\n cancel = false;\r\n }, {once: true});\r\n };\r\n\r\n let width = 0, x = 0, lastDiffX = 0, lastIndex = 0, minX = 0;\r\n const swipeHandler = new SwipeHandler({\r\n element: this.avatars, \r\n onSwipe: (xDiff, yDiff) => {\r\n lastDiffX = xDiff;\r\n let lastX = x + xDiff * -2;\r\n if(lastX > 0) lastX = 0;\r\n else if(lastX < minX) lastX = minX;\r\n\r\n this.avatars.style.transform = `translate3d(${lastX}px, 0, -1px) scale(2)`;\r\n //console.log(xDiff, yDiff);\r\n return false;\r\n }, \r\n verifyTouchTarget: (e) => {\r\n if(!checkScrollTop()) {\r\n cancelNextClick();\r\n cancelEvent(e);\r\n return false;\r\n } else if(this.tabs.classList.contains('hide') || freeze) {\r\n return false;\r\n }\r\n\r\n return true;\r\n }, \r\n onFirstSwipe: () => {\r\n const rect = this.avatars.getBoundingClientRect();\r\n width = rect.width;\r\n minX = -width * (this.tabs.childElementCount - 1);\r\n\r\n /* lastIndex = whichChild(this.tabs.querySelector('.active'));\r\n x = -width * lastIndex; */\r\n x = rect.left - this.container.getBoundingClientRect().left;\r\n \r\n this.avatars.style.transform = `translate3d(${x}px, 0, -1px) scale(2)`;\r\n\r\n this.avatars.classList.add('no-transition');\r\n void this.avatars.offsetLeft; // reflow\r\n },\r\n onReset: () => {\r\n const addIndex = Math.ceil(Math.abs(lastDiffX) / (width / 2)) * (lastDiffX >= 0 ? 1 : -1);\r\n cancelNextClick();\r\n \r\n //console.log(addIndex);\r\n\r\n this.avatars.classList.remove('no-transition');\r\n fastRaf(() => {\r\n this.listLoader.go(addIndex);\r\n });\r\n }\r\n });\r\n }\r\n\r\n public setPeer(peerId: number) {\r\n this.peerId = peerId;\r\n\r\n const photo = appPeersManager.getPeerPhoto(peerId);\r\n if(!photo) {\r\n return;\r\n }\r\n\r\n const loadCount = 50;\r\n const listLoader: PeerProfileAvatars['listLoader'] = this.listLoader = new ListLoader<string | Message.messageService>({\r\n loadCount,\r\n loadMore: (anchor, older) => {\r\n if(peerId > 0) {\r\n return appPhotosManager.getUserPhotos(peerId, (anchor || listLoader.current) as any, loadCount).then(result => {\r\n return {\r\n count: result.count,\r\n items: result.photos\r\n };\r\n });\r\n } else {\r\n const promises: [Promise<ChatFull>, ReturnType<AppMessagesManager['getSearch']>] = [] as any;\r\n if(!listLoader.current) {\r\n promises.push(appProfileManager.getChatFull(-peerId));\r\n }\r\n \r\n promises.push(appMessagesManager.getSearch({\r\n peerId,\r\n maxId: Number.MAX_SAFE_INTEGER,\r\n inputFilter: {\r\n _: 'inputMessagesFilterChatPhotos'\r\n },\r\n limit: loadCount,\r\n backLimit: 0\r\n }));\r\n\r\n return Promise.all(promises).then((result) => {\r\n const value = result.pop() as typeof result[1];\r\n\r\n if(!listLoader.current) {\r\n const chatFull = result[0];\r\n const message = value.history.findAndSplice(m => {\r\n return ((m as Message.messageService).action as MessageAction.messageActionChannelEditPhoto).photo.id === chatFull.chat_photo.id;\r\n }) as Message.messageService;\r\n \r\n listLoader.current = message || appMessagesManager.generateFakeAvatarMessage(this.peerId, chatFull.chat_photo);\r\n }\r\n\r\n //console.log('avatars loaded:', value);\r\n return {\r\n count: value.count,\r\n items: value.history\r\n };\r\n });\r\n }\r\n },\r\n processItem: this.processItem,\r\n onJump: (item, older) => {\r\n const id = this.listLoader.index;\r\n //const nextId = Math.max(0, id);\r\n this.avatars.style.transform = `translate3d(-${200 * id}%, 0, -1px) scale(2)`;\r\n\r\n const activeTab = this.tabs.querySelector('.active');\r\n if(activeTab) activeTab.classList.remove('active');\r\n\r\n const tab = this.tabs.children[id] as HTMLElement;\r\n tab.classList.add('active');\r\n }\r\n });\r\n\r\n if(photo._ === 'userProfilePhoto') {\r\n listLoader.current = photo.photo_id;\r\n }\r\n\r\n this.processItem(listLoader.current);\r\n\r\n listLoader.load(true);\r\n }\r\n\r\n public addTab() {\r\n const tab = document.createElement('div');\r\n tab.classList.add(PeerProfileAvatars.BASE_CLASS + '-tab');\r\n this.tabs.append(tab);\r\n\r\n if(this.tabs.childElementCount === 1) {\r\n tab.classList.add('active');\r\n }\r\n\r\n this.tabs.classList.toggle('hide', this.tabs.childElementCount <= 1);\r\n }\r\n\r\n public processItem = (photoId: string | Message.messageService) => {\r\n const avatar = document.createElement('div');\r\n avatar.classList.add(PeerProfileAvatars.BASE_CLASS + '-avatar');\r\n\r\n let photo: Photo.photo;\r\n if(photoId) {\r\n photo = typeof(photoId) === 'string' ? \r\n appPhotosManager.getPhoto(photoId) : \r\n (photoId.action as MessageAction.messageActionChannelEditPhoto).photo as Photo.photo;\r\n }\r\n\r\n const img = new Image();\r\n img.classList.add(PeerProfileAvatars.BASE_CLASS + '-avatar-image');\r\n img.draggable = false;\r\n\r\n if(photo) {\r\n appPhotosManager.preloadPhoto(photo, appPhotosManager.choosePhotoSize(photo, 420, 420, false)).then(() => {\r\n renderImageFromUrl(img, photo.url, () => {\r\n avatar.append(img);\r\n });\r\n });\r\n } else {\r\n const photo = appPeersManager.getPeerPhoto(this.peerId);\r\n appProfileManager.putAvatar(avatar, this.peerId, photo, 'photo_big', img);\r\n }\r\n\r\n this.avatars.append(avatar);\r\n\r\n this.addTab();\r\n\r\n return photoId;\r\n };\r\n}\r\n\r\nclass PeerProfile {\r\n public element: HTMLElement;\r\n public avatars: PeerProfileAvatars;\r\n private avatar: AvatarElement;\r\n private section: SettingSection;\r\n private name: HTMLDivElement;\r\n private subtitle: HTMLDivElement;\r\n private bio: Row;\r\n private username: Row;\r\n private phone: Row;\r\n private notifications: Row;\r\n \r\n private cleaned: boolean;\r\n private setBioTimeout: number;\r\n private setPeerStatusInterval: number;\r\n\r\n private peerId = 0;\r\n private threadId: number;\r\n\r\n constructor(public scrollable: Scrollable) {\r\n\r\n }\r\n\r\n public init() {\r\n this.init = null;\r\n\r\n this.element = document.createElement('div');\r\n this.element.classList.add('profile-content');\r\n\r\n this.section = new SettingSection({\r\n noDelimiter: true\r\n });\r\n\r\n this.avatar = new AvatarElement();\r\n this.avatar.classList.add('profile-avatar', 'avatar-120');\r\n this.avatar.setAttribute('dialog', '1');\r\n this.avatar.setAttribute('clickable', '');\r\n\r\n this.name = document.createElement('div');\r\n this.name.classList.add('profile-name');\r\n\r\n this.subtitle = document.createElement('div');\r\n this.subtitle.classList.add('profile-subtitle');\r\n\r\n this.bio = new Row({\r\n title: ' ',\r\n subtitleLangKey: 'UserBio',\r\n icon: 'info',\r\n clickable: (e) => {\r\n if((e.target as HTMLElement).tagName === 'A') {\r\n return;\r\n }\r\n \r\n appProfileManager.getProfileByPeerId(this.peerId).then(full => {\r\n copyTextToClipboard(full.about);\r\n toast(I18n.format('BioCopied', true));\r\n });\r\n }\r\n });\r\n\r\n this.bio.title.classList.add('pre-wrap');\r\n\r\n this.username = new Row({\r\n title: ' ',\r\n subtitleLangKey: 'Username',\r\n icon: 'username',\r\n clickable: () => {\r\n const peer: Channel | User = appPeersManager.getPeer(this.peerId);\r\n copyTextToClipboard('@' + peer.username);\r\n toast(I18n.format('UsernameCopied', true));\r\n }\r\n });\r\n\r\n this.phone = new Row({\r\n title: ' ',\r\n subtitleLangKey: 'Phone',\r\n icon: 'phone',\r\n clickable: () => {\r\n const peer: User = appUsersManager.getUser(this.peerId);\r\n copyTextToClipboard('+' + peer.phone);\r\n toast(I18n.format('PhoneCopied', true));\r\n }\r\n });\r\n\r\n this.notifications = new Row({\r\n checkboxField: new CheckboxField({toggle: true}),\r\n titleLangKey: 'Notifications',\r\n icon: 'unmute'\r\n });\r\n \r\n this.section.content.append(this.phone.container, this.username.container, this.bio.container, this.notifications.container);\r\n\r\n const delimiter = document.createElement('div');\r\n delimiter.classList.add('gradient-delimiter');\r\n\r\n this.element.append(this.section.container, delimiter);\r\n\r\n this.notifications.checkboxField.input.addEventListener('change', (e) => {\r\n if(!e.isTrusted) {\r\n return;\r\n }\r\n\r\n //let checked = this.notificationsCheckbox.checked;\r\n appMessagesManager.mutePeer(this.peerId);\r\n });\r\n\r\n rootScope.on('dialog_notify_settings', (dialog) => {\r\n if(this.peerId === dialog.peerId) {\r\n const muted = appNotificationsManager.isPeerLocalMuted(this.peerId, false);\r\n this.notifications.checkboxField.checked = !muted;\r\n }\r\n });\r\n\r\n rootScope.on('peer_typings', (e) => {\r\n const {peerId} = e;\r\n\r\n if(this.peerId === peerId) {\r\n this.setPeerStatus();\r\n }\r\n });\r\n\r\n rootScope.on('peer_bio_edit', (peerId) => {\r\n if(peerId === this.peerId) {\r\n this.setBio(true);\r\n }\r\n });\r\n\r\n rootScope.on('user_update', (e) => {\r\n const userId = e;\r\n\r\n if(this.peerId === userId) {\r\n this.setPeerStatus();\r\n }\r\n });\r\n\r\n this.setPeerStatusInterval = window.setInterval(this.setPeerStatus, 60e3);\r\n }\r\n\r\n public setPeerStatus = (needClear = false) => {\r\n if(!this.peerId) return;\r\n\r\n const peerId = this.peerId;\r\n if(needClear) {\r\n this.subtitle.innerHTML = ''; // ! HERE U CAN FIND WHITESPACE\r\n }\r\n\r\n appImManager.getPeerStatus(this.peerId).then((subtitle) => {\r\n if(peerId !== this.peerId) {\r\n return;\r\n }\r\n\r\n this.subtitle.textContent = '';\r\n this.subtitle.append(subtitle || '');\r\n });\r\n };\r\n\r\n public cleanupHTML() {\r\n this.bio.container.style.display = 'none';\r\n this.phone.container.style.display = 'none';\r\n this.username.container.style.display = 'none';\r\n this.notifications.container.style.display = '';\r\n this.notifications.checkboxField.checked = true;\r\n if(this.setBioTimeout) {\r\n window.clearTimeout(this.setBioTimeout);\r\n this.setBioTimeout = 0;\r\n }\r\n }\r\n\r\n public setAvatar() {\r\n if(this.peerId !== rootScope.myId) {\r\n const photo = appPeersManager.getPeerPhoto(this.peerId);\r\n\r\n if(photo) {\r\n const oldAvatars = this.avatars;\r\n this.avatars = new PeerProfileAvatars(this.scrollable);\r\n this.avatars.setPeer(this.peerId);\r\n this.avatars.info.append(this.name, this.subtitle);\r\n \r\n this.avatar.remove();\r\n \r\n if(oldAvatars) oldAvatars.container.replaceWith(this.avatars.container);\r\n else this.element.prepend(this.avatars.container);\r\n\r\n this.scrollable.container.classList.add('parallax');\r\n\r\n return;\r\n }\r\n }\r\n\r\n this.scrollable.container.classList.remove('parallax');\r\n\r\n if(this.avatars) {\r\n this.avatars.container.remove();\r\n this.avatars = undefined;\r\n }\r\n\r\n this.avatar.setAttribute('peer', '' + this.peerId);\r\n\r\n this.section.content.prepend(this.avatar, this.name, this.subtitle);\r\n }\r\n\r\n public fillProfileElements() {\r\n if(!this.cleaned) return;\r\n this.cleaned = false;\r\n \r\n const peerId = this.peerId;\r\n\r\n this.cleanupHTML();\r\n\r\n this.setAvatar();\r\n\r\n // username\r\n if(peerId !== rootScope.myId) {\r\n let username = appPeersManager.getPeerUsername(peerId);\r\n if(username) {\r\n setText(appPeersManager.getPeerUsername(peerId), this.username);\r\n }\r\n \r\n const muted = appNotificationsManager.isPeerLocalMuted(peerId, false);\r\n this.notifications.checkboxField.checked = !muted;\r\n } else {\r\n window.requestAnimationFrame(() => {\r\n this.notifications.container.style.display = 'none';\r\n });\r\n }\r\n \r\n //let membersLi = this.profileTabs.firstElementChild.children[0] as HTMLLIElement;\r\n if(peerId > 0) {\r\n //membersLi.style.display = 'none';\r\n\r\n let user = appUsersManager.getUser(peerId);\r\n if(user.phone && peerId !== rootScope.myId) {\r\n setText(user.rPhone, this.phone);\r\n }\r\n }/* else {\r\n //membersLi.style.display = appPeersManager.isBroadcast(peerId) ? 'none' : '';\r\n } */\r\n\r\n this.setBio();\r\n\r\n replaceContent(this.name, new PeerTitle({\r\n peerId,\r\n dialog: true\r\n }).element);\r\n\r\n this.setPeerStatus(true);\r\n }\r\n\r\n public setBio(override?: true) {\r\n if(this.setBioTimeout) {\r\n window.clearTimeout(this.setBioTimeout);\r\n this.setBioTimeout = 0;\r\n }\r\n\r\n const peerId = this.peerId;\r\n const threadId = this.threadId;\r\n\r\n if(!peerId) {\r\n return;\r\n }\r\n\r\n let promise: Promise<boolean>;\r\n if(peerId > 0) {\r\n promise = appProfileManager.getProfile(peerId, override).then(userFull => {\r\n if(this.peerId !== peerId || this.threadId !== threadId) {\r\n //this.log.warn('peer changed');\r\n return false;\r\n }\r\n \r\n if(userFull.rAbout && peerId !== rootScope.myId) {\r\n setText(userFull.rAbout, this.bio);\r\n }\r\n \r\n //this.log('userFull', userFull);\r\n return true;\r\n });\r\n } else {\r\n promise = appProfileManager.getChatFull(-peerId, override).then((chatFull) => {\r\n if(this.peerId !== peerId || this.threadId !== threadId) {\r\n //this.log.warn('peer changed');\r\n return false;\r\n }\r\n \r\n //this.log('chatInfo res 2:', chatFull);\r\n \r\n if(chatFull.about) {\r\n setText(RichTextProcessor.wrapRichText(chatFull.about), this.bio);\r\n }\r\n\r\n return true;\r\n });\r\n }\r\n\r\n promise.then((canSetNext) => {\r\n if(canSetNext) {\r\n this.setBioTimeout = window.setTimeout(() => this.setBio(true), 60e3);\r\n }\r\n });\r\n }\r\n\r\n public setPeer(peerId: number, threadId = 0) {\r\n if(this.peerId === peerId && this.threadId === peerId) return;\r\n\r\n if(this.init) {\r\n this.init();\r\n }\r\n\r\n this.peerId = peerId;\r\n this.threadId = threadId;\r\n \r\n this.cleaned = true;\r\n }\r\n}\r\n\r\n// TODO: отредактированное сообщение не изменится\r\nexport default class AppSharedMediaTab extends SliderSuperTab {\r\n private editBtn: HTMLElement;\r\n\r\n private peerId = 0;\r\n private threadId = 0;\r\n\r\n private historiesStorage: {\r\n [peerId: number]: Partial<{\r\n [type in SearchSuperType]: {mid: number, peerId: number}[]\r\n }>\r\n } = {};\r\n\r\n private searchSuper: AppSearchSuper;\r\n\r\n private profile: PeerProfile;\r\n peerChanged: boolean;\r\n\r\n constructor(slider: SidebarSlider) {\r\n super(slider, false);\r\n }\r\n\r\n public init() {\r\n //const perf = performance.now();\r\n\r\n this.container.classList.add('shared-media-container', 'profile-container');\r\n\r\n // * header\r\n const newCloseBtn = Button('btn-icon sidebar-close-button', {noRipple: true});\r\n this.closeBtn.replaceWith(newCloseBtn);\r\n this.closeBtn = newCloseBtn;\r\n\r\n const animatedCloseIcon = document.createElement('div');\r\n animatedCloseIcon.classList.add('animated-close-icon');\r\n newCloseBtn.append(animatedCloseIcon);\r\n\r\n const transitionContainer = document.createElement('div');\r\n transitionContainer.className = 'transition slide-fade';\r\n \r\n const transitionFirstItem = document.createElement('div');\r\n transitionFirstItem.classList.add('transition-item');\r\n\r\n this.title.append(i18n('Profile'));\r\n this.editBtn = ButtonIcon('edit');\r\n //const moreBtn = ButtonIcon('more');\r\n\r\n transitionFirstItem.append(this.title, this.editBtn/* , moreBtn */);\r\n\r\n const transitionLastItem = document.createElement('div');\r\n transitionLastItem.classList.add('transition-item');\r\n\r\n const secondTitle: HTMLElement = this.title.cloneNode() as any;\r\n secondTitle.append(i18n('PeerInfo.SharedMedia'));\r\n\r\n transitionLastItem.append(secondTitle);\r\n\r\n transitionContainer.append(transitionFirstItem, transitionLastItem);\r\n\r\n this.header.append(transitionContainer);\r\n\r\n // * body\r\n\r\n this.profile = new PeerProfile(this.scrollable);\r\n this.profile.init();\r\n \r\n this.scrollable.append(this.profile.element);\r\n\r\n const HEADER_HEIGHT = 56;\r\n this.scrollable.onAdditionalScroll = () => {\r\n const rect = this.searchSuper.nav.getBoundingClientRect(); \r\n if(!rect.width) return;\r\n\r\n const top = rect.top;\r\n const isSharedMedia = top <= HEADER_HEIGHT;\r\n animatedCloseIcon.classList.toggle('state-back', isSharedMedia);\r\n this.searchSuper.container.classList.toggle('is-full-viewport', isSharedMedia);\r\n transition(+isSharedMedia);\r\n\r\n if(!isSharedMedia) {\r\n this.searchSuper.cleanScrollPositions();\r\n }\r\n };\r\n\r\n const transition = TransitionSlider(transitionContainer, 'slide-fade', 400, null, false);\r\n\r\n transition(0);\r\n\r\n attachClickEvent(this.closeBtn, (e) => {\r\n if(this.closeBtn.firstElementChild.classList.contains('state-back')) {\r\n this.scrollable.scrollIntoViewNew(this.scrollable.container.firstElementChild as HTMLElement, 'start');\r\n transition(0);\r\n animatedCloseIcon.classList.remove('state-back');\r\n } else if(!this.scrollable.isHeavyAnimationInProgress) {\r\n appSidebarRight.onCloseBtnClick();\r\n }\r\n });\r\n\r\n attachClickEvent(this.editBtn, (e) => {\r\n let tab: AppEditGroupTab | AppEditChannelTab | AppEditContactTab;\r\n if(appPeersManager.isAnyGroup(this.peerId)) {\r\n tab = new AppEditGroupTab(appSidebarRight);\r\n } else if(this.peerId > 0) {\r\n tab = new AppEditContactTab(appSidebarRight);\r\n } else {\r\n tab = new AppEditChannelTab(appSidebarRight);\r\n }\r\n\r\n if(tab) {\r\n if(tab instanceof AppEditGroupTab) {\r\n tab.chatId = -this.peerId;\r\n } else {\r\n tab.peerId = this.peerId;\r\n }\r\n \r\n tab.open();\r\n }\r\n });\r\n\r\n //this.container.prepend(this.closeBtn.parentElement);\r\n\r\n this.searchSuper = new AppSearchSuper({\r\n mediaTabs: [{\r\n inputFilter: 'inputMessagesFilterEmpty',\r\n name: 'PeerMedia.Members',\r\n type: 'members'\r\n }, {\r\n inputFilter: 'inputMessagesFilterPhotoVideo',\r\n name: 'SharedMediaTab2',\r\n type: 'media'\r\n }, {\r\n inputFilter: 'inputMessagesFilterDocument',\r\n name: 'SharedFilesTab2',\r\n type: 'files'\r\n }, {\r\n inputFilter: 'inputMessagesFilterUrl',\r\n name: 'SharedLinksTab2',\r\n type: 'links'\r\n }, {\r\n inputFilter: 'inputMessagesFilterMusic',\r\n name: 'SharedMusicTab2',\r\n type: 'music'\r\n }, {\r\n inputFilter: 'inputMessagesFilterVoice',\r\n name: 'SharedVoiceTab2',\r\n type: 'voice'\r\n }], \r\n scrollable: this.scrollable,\r\n onChangeTab: (mediaTab) => {\r\n let timeout = mediaTab.type === 'members' && rootScope.settings.animationsEnabled ? 250 : 0;\r\n setTimeout(() => {\r\n btnAddMembers.classList.toggle('is-hidden', mediaTab.type !== 'members');\r\n }, timeout);\r\n }\r\n });\r\n\r\n this.profile.element.append(this.searchSuper.container);\r\n\r\n const btnAddMembers = Button('btn-corner btn-circle', {icon: 'addmember_filled'});\r\n this.content.append(btnAddMembers);\r\n\r\n btnAddMembers.addEventListener('click', () => {\r\n const id = -this.peerId;\r\n const isChannel = appChatsManager.isChannel(id);\r\n\r\n const showConfirmation = (peerIds: number[], callback: () => void) => {\r\n let titleLangKey: LangPackKey = 'GroupAddMembers', descriptionLangKey: LangPackKey, descriptionLangArgs: any[];\r\n\r\n if(peerIds.length > 1) {\r\n descriptionLangKey = 'PeerInfo.Confirm.AddMembers1';\r\n descriptionLangArgs = [peerIds.length];\r\n } else {\r\n descriptionLangKey = 'PeerInfo.Confirm.AddMember';\r\n descriptionLangArgs = [new PeerTitle({\r\n peerId: peerIds[0],\r\n onlyFirstName: true\r\n }).element];\r\n }\r\n\r\n new PopupPeer('popup-add-members', {\r\n peerId: -id,\r\n titleLangKey,\r\n descriptionLangKey,\r\n descriptionLangArgs,\r\n buttons: [{\r\n langKey: 'Add',\r\n callback: () => {\r\n callback();\r\n }\r\n }]\r\n }).show();\r\n };\r\n \r\n if(isChannel) {\r\n const tab = new AppAddMembersTab(this.slider);\r\n tab.open({\r\n peerId: this.peerId,\r\n type: 'channel',\r\n skippable: false,\r\n takeOut: (peerIds) => {\r\n showConfirmation(peerIds, () => {\r\n tab.attachToPromise(appChatsManager.inviteToChannel(id, peerIds));\r\n });\r\n\r\n return false;\r\n },\r\n title: 'GroupAddMembers',\r\n placeholder: 'SendMessageTo'\r\n });\r\n } else {\r\n new PopupPickUser({\r\n peerTypes: ['contacts'],\r\n placeholder: 'Search',\r\n onSelect: (peerId) => {\r\n setTimeout(() => {\r\n showConfirmation([peerId], () => {\r\n appChatsManager.addChatUser(id, peerId);\r\n });\r\n }, 0);\r\n },\r\n });\r\n }\r\n });\r\n\r\n //console.log('construct shared media time:', performance.now() - perf);\r\n }\r\n\r\n public renderNewMessages(peerId: number, mids: number[]) {\r\n if(this.init) return; // * not inited yet\r\n\r\n if(!this.historiesStorage[peerId]) return;\r\n \r\n mids = mids.slice().reverse(); // ! because it will be ascend sorted array\r\n for(const mediaTab of this.searchSuper.mediaTabs) {\r\n const inputFilter = mediaTab.inputFilter;\r\n const filtered = this.searchSuper.filterMessagesByType(mids.map(mid => appMessagesManager.getMessageByPeer(peerId, mid)), inputFilter);\r\n if(filtered.length) {\r\n if(this.historiesStorage[peerId][inputFilter]) {\r\n this.historiesStorage[peerId][inputFilter].unshift(...filtered.map(message => ({mid: message.mid, peerId: message.peerId})));\r\n }\r\n\r\n if(this.peerId === peerId && this.searchSuper.usedFromHistory[inputFilter] !== -1) {\r\n this.searchSuper.usedFromHistory[inputFilter] += filtered.length;\r\n this.searchSuper.performSearchResult(filtered, mediaTab, false);\r\n }\r\n\r\n break;\r\n }\r\n }\r\n }\r\n\r\n public deleteDeletedMessages(peerId: number, mids: number[]) {\r\n if(this.init) return; // * not inited yet\r\n\r\n if(!this.historiesStorage[peerId]) return;\r\n\r\n for(const mid of mids) {\r\n for(const type of this.searchSuper.mediaTabs) {\r\n const inputFilter = type.inputFilter;\r\n\r\n if(!this.historiesStorage[peerId][inputFilter]) continue;\r\n\r\n const history = this.historiesStorage[peerId][inputFilter];\r\n const idx = history.findIndex(m => m.mid === mid);\r\n if(idx !== -1) {\r\n history.splice(idx, 1);\r\n\r\n if(this.peerId === peerId) {\r\n const container = this.searchSuper.tabs[inputFilter];\r\n const div = container.querySelector(`div[data-mid=\"${mid}\"][data-peer-id=\"${peerId}\"]`);\r\n if(div) {\r\n div.remove();\r\n }\r\n \r\n if(this.searchSuper.usedFromHistory[inputFilter] >= (idx + 1)) {\r\n this.searchSuper.usedFromHistory[inputFilter]--;\r\n }\r\n }\r\n\r\n break;\r\n }\r\n }\r\n }\r\n\r\n this.scrollable.onScroll();\r\n }\r\n\r\n public cleanupHTML() {\r\n // const perf = performance.now();\r\n this.profile.cleanupHTML();\r\n \r\n this.editBtn.style.display = 'none';\r\n\r\n this.searchSuper.cleanupHTML(true);\r\n\r\n this.container.classList.toggle('can-add-members', this.searchSuper.canViewMembers() && appChatsManager.hasRights(-this.peerId, 'invite_users'));\r\n\r\n // console.log('cleanupHTML shared media time:', performance.now() - perf);\r\n }\r\n\r\n public setLoadMutex(promise: Promise<any>) {\r\n this.searchSuper.loadMutex = promise;\r\n }\r\n\r\n public setPeer(peerId: number, threadId = 0) {\r\n if(this.peerId === peerId && this.threadId === threadId) return false;\r\n\r\n this.peerId = peerId;\r\n this.threadId = threadId;\r\n this.peerChanged = true;\r\n\r\n if(this.init) {\r\n this.init();\r\n this.init = null;\r\n }\r\n\r\n this.searchSuper.setQuery({\r\n peerId, \r\n //threadId, \r\n historyStorage: this.historiesStorage[peerId] ?? (this.historiesStorage[peerId] = {})\r\n });\r\n\r\n this.profile.setPeer(peerId, threadId);\r\n \r\n return true;\r\n }\r\n\r\n public fillProfileElements() {\r\n if(!this.peerChanged) {\r\n return;\r\n }\r\n\r\n this.peerChanged = false;\r\n\r\n this.cleanupHTML();\r\n\r\n this.profile.fillProfileElements();\r\n\r\n if(this.peerId > 0) {\r\n if(this.peerId !== rootScope.myId && appUsersManager.isContact(this.peerId)) {\r\n this.editBtn.style.display = '';\r\n }\r\n } else {\r\n const chat: Chat = appChatsManager.getChat(-this.peerId);\r\n if(chat._ === 'chat' || (chat as Chat.channel).admin_rights) {\r\n this.editBtn.style.display = '';\r\n }\r\n }\r\n }\r\n\r\n public loadSidebarMedia(single: boolean, justLoad = false) {\r\n this.searchSuper.load(single, justLoad);\r\n }\r\n\r\n onOpenAfterTimeout() {\r\n this.scrollable.onScroll();\r\n }\r\n}\r\n\r\nMOUNT_CLASS_TO && (MOUNT_CLASS_TO.AppSharedMediaTab = AppSharedMediaTab);\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 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\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 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 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 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\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 title.innerHTML = poll.poll.rQuestion;\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 answerTitle.innerHTML = 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,\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","/*\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 { isTouchSupported } from \"../helpers/touchSupport\";\r\nimport appImManager from \"../lib/appManagers/appImManager\";\r\nimport appPollsManager, { Poll, PollResults } 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 { attachClickEvent, cancelEvent, detachClickEvent, replaceContent } from \"../helpers/dom\";\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\n\r\nlet lineTotalLength = 0;\r\n//const 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.on('poll_update', (e) => {\r\n const {poll, results} = e as {poll: Poll, results: PollResults};\r\n\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.on('peer_changed', () => {\r\n if(prevQuizHint) {\r\n hideQuizHint(prevQuizHint, prevQuizHintOnHide, prevQuizHintTimeout);\r\n }\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 textEl.innerHTML = 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 }, isTouchSupported ? 5000 : 7000);\r\n};\r\n\r\nexport default class PollElement extends HTMLElement {\r\n private 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 maxOffset = -46.5;\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 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 }\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 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\">${RichTextProcessor.wrapEmojiText(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 ${mediaSizes.active.regular.width} 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\">${poll.rQuestion}</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 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 = String(timeLeft).toHHMMSS();\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 //this.maxLength = width + tailLength + this.maxOffset + -13.7; // 13 - position left\r\n\r\n if(poll.chosenIndexes.length || this.isClosed) {\r\n this.performResults(results, poll.chosenIndexes, false);\r\n } else if(!this.isClosed) {\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 let html = '';\r\n /**\r\n * MACOS, ANDROID - без реверса\r\n * WINDOWS DESKTOP - реверс\r\n * все приложения накладывают аватарку первую на вторую, а в макете зато вторая на первую, ЛОЛ!\r\n */\r\n results.recent_voters/* .slice().reverse() */.forEach((userId, idx) => {\r\n const style = idx === 0 ? '' : `style=\"transform: translateX(-${idx * 3}px);\"`;\r\n html += `<avatar-element class=\"avatar-16\" dialog=\"0\" peer=\"${userId}\" ${style}></avatar-element>`;\r\n });\r\n this.avatarsDiv.innerHTML = html;\r\n }\r\n\r\n if(this.isMultiple) {\r\n this.sendVoteBtn.classList.toggle('hide', !!this.chosenIndexes.length);\r\n if(!this.chosenIndexes.length) {\r\n this.votersCountDiv.classList.add('hide');\r\n this.viewResults.classList.add('hide');\r\n } else if(this.isPublic) {\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 } else {\r\n this.votersCountDiv.classList.toggle('hide', !this.chosenIndexes.length);\r\n }\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 = (percents * this.maxLengths[index]) + ', 485.9';\r\n svg.style.strokeDasharray = (multiplier * this.maxPercents[index] * 100) + '%, 485.9';\r\n svg.style.strokeDashoffset = '' + multiplier * this.maxOffset;\r\n }\r\n }\r\n\r\n // у элемента могут быть ещё другие методы и свойства\r\n}\r\n\r\ncustomElements.define(\"poll-element\", PollElement);\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 { getEmojiToneIndex } from '../vendor/emoji';\r\nimport { readBlobAsText } from '../helpers/blob';\r\nimport { deferredPromise } from '../helpers/cancellablePromise';\r\nimport { formatDateAccordingToToday, months } from '../helpers/date';\r\nimport mediaSizes from '../helpers/mediaSizes';\r\nimport { formatBytes } from '../helpers/number';\r\nimport { isSafari } from '../helpers/userAgent';\r\nimport { PhotoSize } 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/lottieLoader';\r\nimport { attachClickEvent, cancelEvent, isInDOM } from \"../helpers/dom\";\r\nimport webpWorkerController from '../lib/webp/webpWorkerController';\r\nimport animationIntersector from './animationIntersector';\r\nimport appMediaPlaybackController from './appMediaPlaybackController';\r\nimport AudioElement 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 { nextRandomInt } from '../helpers/random';\r\nimport RichTextProcessor from '../lib/richtextprocessor';\r\nimport appImManager from '../lib/appManagers/appImManager';\r\nimport { SearchSuperContext } from './appSearchSuper.';\r\nimport rootScope from '../lib/rootScope';\r\nimport { onVideoLoad } 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\n\r\nconst MAX_VIDEO_AUTOPLAY_SIZE = 50 * 1024 * 1024; // 50 MB\r\n\r\nexport function wrapVideo({doc, container, message, boxWidth, boxHeight, withTail, isOut, middleware, lazyLoadQueue, noInfo, group, onlyPreview, withoutPreloader, loadPromises, noPlayButton, noAutoDownload}: {\r\n doc: MyDocument, \r\n container?: HTMLElement, \r\n message?: any, \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 noAutoDownload?: boolean,\r\n}) {\r\n const isAlbumItem = !(boxWidth && boxHeight);\r\n const canAutoplay = (doc.type !== 'video' || (doc.size <= MAX_VIDEO_AUTOPLAY_SIZE && !isAlbumItem)) \r\n && (doc.type === 'gif' ? rootScope.settings.autoPlay.gifs : rootScope.settings.autoPlay.videos);\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 = (doc.duration + '').toHHMMSS(false);\r\n\r\n if(!noPlayButton && doc.type !== 'round') {\r\n if(canAutoplay) {\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 noAutoDownload\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 const video = document.createElement('video');\r\n video.classList.add('media-video');\r\n video.setAttribute('playsinline', 'true');\r\n video.muted = true;\r\n if(doc.type === 'round') {\r\n const globalVideo = appMediaPlaybackController.addMedia(message.peerId, doc, message.mid, !noAutoDownload) as HTMLVideoElement;\r\n \r\n const divRound = document.createElement('div');\r\n divRound.classList.add('media-round', 'z-depth-1');\r\n\r\n divRound.innerHTML = `<svg class=\"progress-ring\" width=\"200px\" height=\"200px\">\r\n <circle class=\"progress-ring__circle\" stroke=\"white\" stroke-opacity=\"0.3\" stroke-width=\"3.5\" cx=\"100\" cy=\"100\" r=\"93\" fill=\"transparent\" transform=\"rotate(-90, 100, 100)\"/>\r\n </svg>`;\r\n\r\n const circle = divRound.querySelector('.progress-ring__circle') as SVGCircleElement;\r\n const radius = circle.r.baseVal.value;\r\n const circumference = 2 * Math.PI * radius;\r\n circle.style.strokeDasharray = circumference + ' ' + circumference;\r\n circle.style.strokeDashoffset = '' + circumference;\r\n \r\n spanTime.classList.add('tgico');\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 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', onTimeUpdate);\r\n globalVideo.removeEventListener('pause', onPaused);\r\n });\r\n };\r\n\r\n const onFrame = () => {\r\n ctx.drawImage(globalVideo, 0, 0);\r\n\r\n const offset = circumference - globalVideo.currentTime / globalVideo.duration * circumference;\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) return;\r\n\r\n if(!isInDOM(globalVideo)) {\r\n clear();\r\n return;\r\n }\r\n\r\n spanTime.innerText = (globalVideo.duration - globalVideo.currentTime + '').toHHMMSS(false);\r\n };\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\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 globalVideo.addEventListener('play', onPlay);\r\n globalVideo.addEventListener('timeupdate', onTimeUpdate);\r\n globalVideo.addEventListener('pause', onPaused);\r\n\r\n attachClickEvent(canvas, (e) => {\r\n cancelEvent(e);\r\n\r\n if(globalVideo.paused) {\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) {\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 } 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 noAutoDownload\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.thumb.url;\r\n });\r\n }\r\n }\r\n\r\n if(!video.parentElement && container) {\r\n container.append(video);\r\n }\r\n\r\n let preloader: ProgressivePreloader;\r\n if(message?.media?.preloader) { // means upload\r\n preloader = message.media.preloader as ProgressivePreloader;\r\n preloader.attach(container, false);\r\n noAutoDownload = undefined;\r\n } else if(!doc.downloaded && !doc.supportsStreaming) {\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 let f = 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) {\r\n if(!doc.downloaded && !doc.supportsStreaming) {\r\n const promise = loadPromise = appDocsManager.downloadDoc(doc, lazyLoadQueue?.queueId, noAutoDownload);\r\n preloader.attach(container, false, promise);\r\n } else if(doc.supportsStreaming) {\r\n if(noAutoDownload) {\r\n loadPromise = Promise.reject();\r\n } else if(!doc.downloaded) { // * check for uploading video\r\n preloader.attach(container, false, null);\r\n video.addEventListener(isSafari ? 'timeupdate' : 'canplay', () => {\r\n preloader.detach();\r\n }, {once: true});\r\n }\r\n }\r\n }\r\n\r\n if(!noAutoDownload && f) {\r\n f();\r\n f = null;\r\n }\r\n\r\n noAutoDownload = undefined;\r\n\r\n const deferred = deferredPromise<void>();\r\n loadPromise.then(() => {\r\n if(middleware && !middleware()) {\r\n deferred.resolve();\r\n return;\r\n }\r\n\r\n if(doc.type === 'round') {\r\n appMediaPlaybackController.resolveWaitingForLoadMedia(message.peerId, message.mid);\r\n }\r\n\r\n onVideoLoad(video).then(() => {\r\n if(group) {\r\n animationIntersector.addAnimation(video, group);\r\n }\r\n \r\n deferred.resolve();\r\n });\r\n \r\n if(doc.type === 'video') {\r\n video.addEventListener('timeupdate', () => {\r\n spanTime.innerText = (video.duration - video.currentTime + '').toHHMMSS(false);\r\n });\r\n }\r\n \r\n video.addEventListener('error', (e) => {\r\n deferred.resolve();\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 renderImageFromUrl(video, doc.url);\r\n }, () => {});\r\n\r\n return {download: loadPromise, render: deferred};\r\n };\r\n\r\n if(preloader) {\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\nexport const formatDate = (timestamp: number, monthShort = false, withYear = true) => {\r\n const date = new Date(timestamp * 1000);\r\n \r\n let month = months[date.getMonth()];\r\n if(monthShort) month = month.slice(0, 3);\r\n\r\n let str = month + ' ' + date.getDate();\r\n if(withYear) {\r\n str += ', ' + date.getFullYear();\r\n }\r\n \r\n return str + ' at ' + date.getHours() + ':' + ('0' + date.getMinutes()).slice(-2);\r\n};\r\n\r\nexport function wrapDocument({message, withTime, fontWeight, voiceAsMusic, showSender, searchContext, loadPromises, noAutoDownload}: {\r\n message: any, \r\n withTime?: boolean,\r\n fontWeight?: number,\r\n voiceAsMusic?: boolean,\r\n showSender?: boolean,\r\n searchContext?: SearchSuperContext,\r\n loadPromises?: Promise<any>[],\r\n noAutoDownload?: boolean,\r\n}): HTMLElement {\r\n if(!fontWeight) fontWeight = 500;\r\n\r\n const doc = (message.media.document || message.media.webpage.document) as MyDocument;\r\n const uploading = message.pFlags.is_outgoing && message.media?.preloader;\r\n if(doc.type === 'audio' || doc.type === 'voice') {\r\n const audioElement = new AudioElement();\r\n audioElement.setAttribute('message-id', '' + message.mid);\r\n audioElement.setAttribute('peer-id', '' + message.peerId);\r\n audioElement.withTime = withTime;\r\n audioElement.message = message;\r\n audioElement.noAutoDownload = noAutoDownload;\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 \r\n if(uploading) {\r\n audioElement.preloader = message.media.preloader;\r\n }\r\n\r\n audioElement.dataset.fontWeight = '' + fontWeight;\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) ? extSplitted.pop().toLowerCase() : '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 if(doc.thumbs?.length || (message.pFlags.is_outgoing && doc.url && doc.type === 'photo')) {\r\n docDiv.classList.add('document-with-thumb');\r\n\r\n let imgs: HTMLImageElement[] = [];\r\n if(message.pFlags.is_outgoing) {\r\n icoDiv.innerHTML = `<img src=\"${doc.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 });\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 || 'Unknown.file';\r\n let size = formatBytes(doc.size);\r\n \r\n if(withTime) {\r\n size += ' · ' + formatDate(doc.date);\r\n }\r\n\r\n if(showSender) {\r\n size += ' · ' + appMessagesManager.getSenderToPeerText(message);\r\n }\r\n\r\n let titleAdditionHTML = '';\r\n if(showSender) {\r\n titleAdditionHTML = `<div class=\"sent-time\">${formatDateAccordingToToday(new Date(message.date * 1000))}</div>`;\r\n }\r\n \r\n docDiv.innerHTML = `\r\n ${doc.downloaded && !uploading ? '' : `<div class=\"document-download\"></div>`}\r\n <div class=\"document-name\"><middle-ellipsis-element data-font-weight=\"${fontWeight}\">${fileName}</middle-ellipsis-element>${titleAdditionHTML}</div>\r\n <div class=\"document-size\">${size}</div>\r\n `;\r\n\r\n docDiv.prepend(icoDiv);\r\n\r\n if(!uploading && message.pFlags.is_outgoing) {\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 = () => {\r\n const doc = appDocsManager.getDoc(docDiv.dataset.docId);\r\n const download = appDocsManager.saveDocFile(doc, appImManager.chat.bubbles ? appImManager.chat.bubbles.lazyLoadQueue.queueId : 0);\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(!(doc.downloaded && !uploading)) {\r\n downloadDiv = docDiv.querySelector('.document-download');\r\n preloader = message.media.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 } else {\r\n preloader.attach(downloadDiv);\r\n message.media.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();\r\n }\r\n });\r\n \r\n return docDiv;\r\n}\r\n\r\nfunction 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, noAutoDownload, noBlur}: {\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 noAutoDownload?: boolean,\r\n noBlur?: boolean,\r\n}) {\r\n if(!((photo as MyPhoto).sizes || (photo as MyDocument).thumbs)) {\r\n if(boxWidth && boxHeight && photo._ === 'document') {\r\n size = appPhotosManager.setAttachmentSize(photo, container, boxWidth, boxHeight, undefined, message && message.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 };\r\n }\r\n\r\n if(boxWidth === undefined) boxWidth = mediaSizes.active.regular.width;\r\n if(boxHeight === undefined) boxHeight = mediaSizes.active.regular.height;\r\n\r\n let loadThumbPromise: Promise<any>;\r\n let thumbImage: HTMLImageElement;\r\n let image: HTMLImageElement;\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) { // !album\r\n size = appPhotosManager.setAttachmentSize(photo, container, boxWidth, boxHeight, undefined, message && message.message);\r\n }\r\n\r\n const gotThumb = appPhotosManager.getStrippedThumbIfNeeded(photo, !noBlur);\r\n if(gotThumb) {\r\n loadThumbPromise = gotThumb.loadPromise;\r\n thumbImage = gotThumb.image;\r\n thumbImage.classList.add('media-photo');\r\n container.append(thumbImage);\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 cacheContext = appPhotosManager.getCacheContext(photo);\r\n\r\n const needFadeIn = (thumbImage || !cacheContext.downloaded) && rootScope.settings.animationsEnabled;\r\n if(needFadeIn) {\r\n image.classList.add('fade-in');\r\n }\r\n\r\n let preloader: ProgressivePreloader;\r\n if(message?.media?.preloader) { // means upload\r\n preloader = message.media.preloader;\r\n preloader.attach(container);\r\n noAutoDownload = undefined;\r\n } else {\r\n preloader = new ProgressivePreloader({\r\n attachMethod: 'prepend'\r\n });\r\n }\r\n\r\n const getDownloadPromise = () => {\r\n const promise = photo._ === 'document' && photo.mime_type === 'image/gif' ? \r\n appDocsManager.downloadDoc(photo, /* undefined, */lazyLoadQueue?.queueId) : \r\n appPhotosManager.preloadPhoto(photo, size, lazyLoadQueue?.queueId, noAutoDownload);\r\n\r\n noAutoDownload = undefined;\r\n\r\n return promise;\r\n };\r\n\r\n const onLoad = (): Promise<void> => {\r\n if(middleware && !middleware()) return Promise.resolve();\r\n\r\n return new Promise((resolve) => {\r\n renderImageFromUrl(image, cacheContext.url || photo.url, () => {\r\n sequentialDom.mutateElement(container, () => {\r\n container.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 let loadPromise: Promise<any>;\r\n const load = () => {\r\n if(noAutoDownload && !withoutPreloader) {\r\n preloader.construct();\r\n preloader.setManual();\r\n }\r\n\r\n const promise = getDownloadPromise();\r\n\r\n if(!cacheContext.downloaded && !withoutPreloader && (size as PhotoSize.photoSize).w >= 150 && (size as PhotoSize.photoSize).h >= 150) {\r\n preloader.attach(container, false, promise);\r\n }\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 preloader.setDownloadFunction(load);\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 };\r\n}\r\n\r\nexport function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, onlyThumb, emoji, width, height, withThumb, loop, loadPromises, needFadeIn}: {\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}) {\r\n const stickerType = doc.sticker;\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 && !LottieLoader.loaded) {\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 //console.log('wrap sticker', doc, div, onlyThumb);\r\n\r\n const toneIndex = emoji ? getEmojiToneIndex(emoji) : -1;\r\n const downloaded = doc.downloaded && !needFadeIn;\r\n \r\n let loadThumbPromise = deferredPromise<void>();\r\n let haveThumbCached = false;\r\n if((doc.thumbs?.length || doc.stickerCachedThumbs) && !div.firstElementChild && (!downloaded || stickerType === 2 || onlyThumb)/* && doc.thumbs[0]._ !== 'photoSizeEmpty' */) {\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 div.innerHTML = `<svg class=\"rlottie-vector media-sticker thumbnail\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" viewBox=\"0 0 ${doc.w || 512} ${doc.h || 512}\" xml:space=\"preserve\">\r\n <path d=\"${d}\"/>\r\n </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((webpWorkerController.isWebpSupported() || doc.pFlags.stickerThumbConverted || thumb.url)/* && false */) {\r\n renderImageFromUrl(thumbImage, appPhotosManager.getPreviewURLFromThumb(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(thumb as PhotoSize.photoStrippedSize, true), afterRender);\r\n }\r\n }).catch(() => {});\r\n }\r\n }\r\n } else if(stickerType === 2 && (withThumb || onlyThumb) && toneIndex <= 0) {\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, (thumb as PhotoSize.photoStrippedSize).url, afterRender);\r\n };\r\n \r\n if((thumb as PhotoSize.photoStrippedSize).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) {\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(readBlobAsText)\r\n //.then(JSON.parse)\r\n .then(async(json) => {\r\n //console.timeEnd('download sticker' + doc.id);\r\n //console.log('loaded sticker:', doc, div/* , blob */);\r\n if(middleware && !middleware()) return;\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: json,\r\n width,\r\n height\r\n }, group, toneIndex);\r\n\r\n //const deferred = deferredPromise<void>();\r\n \r\n animation.addEventListener('firstFrame', () => {\r\n const element = div.firstElementChild;\r\n needFadeIn = (needFadeIn || !element || element.tagName === 'svg') && rootScope.settings.animationsEnabled;\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 appDocsManager.saveLottiePreview(doc, animation.canvas, toneIndex);\r\n\r\n //deferred.resolve();\r\n }, true);\r\n \r\n if(emoji) {\r\n attachClickEvent(div, (e) => {\r\n cancelEvent(e);\r\n let animation = LottieLoader.getAnimation(div);\r\n \r\n if(animation.paused) {\r\n animation.autoplay = true;\r\n animation.restart();\r\n }\r\n });\r\n }\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(stickerType === 1) {\r\n const image = new Image();\r\n const thumbImage = div.firstElementChild !== image && div.firstElementChild;\r\n needFadeIn = (needFadeIn || !downloaded || thumbImage) && rootScope.settings.animationsEnabled;\r\n\r\n image.classList.add('media-sticker');\r\n\r\n if(needFadeIn) {\r\n image.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 renderImageFromUrl(image, doc.url, () => {\r\n sequentialDom.mutateElement(div, () => {\r\n div.append(image);\r\n if(thumbImage) {\r\n thumbImage.classList.add('fade-out');\r\n }\r\n\r\n resolve();\r\n\r\n if(needFadeIn) {\r\n image.addEventListener('animationend', () => {\r\n image.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 \r\n if(doc.url) r();\r\n else {\r\n appDocsManager.downloadDoc(doc, /* undefined, */lazyLoadQueue?.queueId).then(r, resolve);\r\n }\r\n });\r\n }\r\n };\r\n\r\n const loadPromise: Promise<any> = lazyLoadQueue && (!downloaded || stickerType === 2) ? \r\n (lazyLoadQueue.push({div, load}), Promise.resolve()) : \r\n load();\r\n\r\n if(downloaded && stickerType === 1) {\r\n loadThumbPromise = loadPromise;\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 function wrapReply(title: string, subtitle: string, 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, noAutoDownload}: {\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 noAutoDownload?: boolean,\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 const mediaDiv = div.firstElementChild as HTMLElement;\r\n if(media._ === 'photo') {\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 noAutoDownload\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 noAutoDownload\r\n });\r\n }\r\n });\r\n}\r\n\r\nexport function wrapGroupedDocuments({albumMustBeRenderedFull, message, bubble, messageDiv, chat, loadPromises, noAutoDownload}: {\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 noAutoDownload?: boolean,\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 noAutoDownload\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\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 messageDiv.innerHTML = 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\n// * will change .cleaned and new instance will be created\r\nexport const getMiddleware = () => {\r\n let cleanupObj = {cleaned: false};\r\n return {\r\n clean: () => {\r\n cleanupObj.cleaned = true;\r\n cleanupObj = {cleaned: false};\r\n },\r\n get: () => {\r\n const _cleanupObj = cleanupObj;\r\n return () => {\r\n return !_cleanupObj.cleaned;\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 appDialogsManager, { DialogDom } from \"../lib/appManagers/appDialogsManager\";\r\nimport { isInDOM, positionElementByIndex, replaceContent } from \"../helpers/dom\";\r\nimport { getHeavyAnimationPromise } from \"../hooks/useHeavyAnimationCheck\";\r\nimport appUsersManager from \"../lib/appManagers/appUsersManager\";\r\nimport { insertInDescendSortedArray } from \"../helpers/array\";\r\n\r\ntype SortedUser = {\r\n peerId: number, \r\n status: number, \r\n dom: DialogDom\r\n};\r\nexport default class SortedUserList {\r\n public static SORT_INTERVAL = 30e3;\r\n public list: HTMLUListElement;\r\n public users: Map<number, SortedUser>;\r\n public sorted: Array<SortedUser>;\r\n\r\n constructor() {\r\n this.list = appDialogsManager.createChatList();\r\n\r\n this.users = new Map();\r\n this.sorted = [];\r\n\r\n let timeout: number;\r\n const doTimeout = () => {\r\n timeout = window.setTimeout(() => {\r\n this.updateList().then((good) => {\r\n if(good) {\r\n doTimeout();\r\n }\r\n });\r\n }, SortedUserList.SORT_INTERVAL);\r\n };\r\n\r\n doTimeout();\r\n }\r\n\r\n public async updateList() {\r\n if(!isInDOM(this.list)) {\r\n return false;\r\n }\r\n\r\n await getHeavyAnimationPromise();\r\n\r\n if(!isInDOM(this.list)) {\r\n return false;\r\n }\r\n\r\n this.users.forEach(user => {\r\n this.update(user.peerId, true);\r\n });\r\n\r\n this.sorted.forEach((sortedUser, idx) => {\r\n positionElementByIndex(sortedUser.dom.listEl, this.list, idx);\r\n });\r\n\r\n return true;\r\n }\r\n\r\n public add(peerId: number) {\r\n if(this.users.has(peerId)) {\r\n return;\r\n }\r\n\r\n const {dom} = appDialogsManager.addDialogNew({\r\n dialog: peerId,\r\n container: false,\r\n drawStatus: false,\r\n avatarSize: 48,\r\n autonomous: true,\r\n meAsSaved: false,\r\n rippleEnabled: false\r\n });\r\n\r\n const sortedUser: SortedUser = {\r\n peerId,\r\n status: appUsersManager.getUserStatusForSort(peerId),\r\n dom\r\n };\r\n\r\n this.users.set(peerId, sortedUser);\r\n this.update(peerId);\r\n }\r\n\r\n public update(peerId: number, batch = false) {\r\n const sortedUser = this.users.get(peerId);\r\n sortedUser.status = appUsersManager.getUserStatusForSort(peerId);\r\n const status = appUsersManager.getUserStatusString(peerId);\r\n replaceContent(sortedUser.dom.lastMessageSpan, status);\r\n\r\n const idx = insertInDescendSortedArray(this.sorted, sortedUser, 'status');\r\n if(!batch) {\r\n positionElementByIndex(sortedUser.dom.listEl, this.list, idx);\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 { formatDateAccordingToToday, months } from \"../helpers/date\";\r\nimport { positionElementByIndex } from \"../helpers/dom\";\r\nimport { copy, getObjectKeysAndSort, safeAssign } from \"../helpers/object\";\r\nimport { escapeRegExp, limitSymbols } from \"../helpers/string\";\r\nimport appChatsManager from \"../lib/appManagers/appChatsManager\";\r\nimport appDialogsManager, { DialogDom } from \"../lib/appManagers/appDialogsManager\";\r\nimport appMessagesManager, { MyInputMessagesFilter, MyMessage } from \"../lib/appManagers/appMessagesManager\";\r\nimport appPeersManager from \"../lib/appManagers/appPeersManager\";\r\nimport appPhotosManager from \"../lib/appManagers/appPhotosManager\";\r\nimport appStateManager from \"../lib/appManagers/appStateManager\";\r\nimport appUsersManager from \"../lib/appManagers/appUsersManager\";\r\nimport { logger } from \"../lib/logger\";\r\nimport RichTextProcessor from \"../lib/richtextprocessor\";\r\nimport rootScope from \"../lib/rootScope\";\r\nimport searchIndexManager from \"../lib/searchIndexManager\";\r\nimport AppMediaViewer from \"./appMediaViewer\";\r\nimport { SearchGroup, SearchGroupType } from \"./appSearch\";\r\nimport { horizontalMenu } from \"./horizontalMenu\";\r\nimport LazyLoadQueue from \"./lazyLoadQueue\";\r\nimport { putPreloader, formatPhoneNumber } from \"./misc\";\r\nimport { ripple } from \"./ripple\";\r\nimport Scrollable, { ScrollableX } from \"./scrollable\";\r\nimport { wrapDocument, wrapPhoto, wrapVideo } from \"./wrappers\";\r\nimport useHeavyAnimationCheck, { getHeavyAnimationPromise } from \"../hooks/useHeavyAnimationCheck\";\r\nimport { isSafari } from \"../helpers/userAgent\";\r\nimport { LangPackKey, i18n } from \"../lib/langPack\";\r\nimport findUpClassName from \"../helpers/dom/findUpClassName\";\r\nimport { getMiddleware } from \"../helpers/middleware\";\r\nimport appProfileManager from \"../lib/appManagers/appProfileManager\";\r\nimport { ChannelParticipant, ChatFull, ChatParticipant, ChatParticipants } from \"../layer\";\r\nimport SortedUserList from \"./sortedUserList\";\r\nimport findUpTag from \"../helpers/dom/findUpTag\";\r\nimport appSidebarRight from \"./sidebarRight\";\r\nimport mediaSizes from \"../helpers/mediaSizes\";\r\nimport appImManager from \"../lib/appManagers/appImManager\";\r\n\r\n//const testScroll = false;\r\n\r\nexport type SearchSuperType = MyInputMessagesFilter/* | 'members' */;\r\nexport type SearchSuperContext = {\r\n peerId: number,\r\n inputFilter: MyInputMessagesFilter,\r\n query?: string,\r\n maxId?: number,\r\n folderId?: number,\r\n threadId?: number,\r\n date?: number,\r\n nextRate?: number,\r\n minDate?: number,\r\n maxDate?: number\r\n};\r\n\r\nexport type SearchSuperMediaType = 'members' | 'media' | 'files' | 'links' | 'music' | 'chats' | 'voice';\r\nexport type SearchSuperMediaTab = {\r\n inputFilter: SearchSuperType,\r\n name: LangPackKey,\r\n type: SearchSuperMediaType,\r\n contentTab?: HTMLElement,\r\n menuTab?: HTMLElement,\r\n scroll?: {scrollTop: number, scrollHeight: number}\r\n};\r\n\r\nexport default class AppSearchSuper {\r\n public tabs: {[t in SearchSuperType]: HTMLDivElement} = {} as any;\r\n\r\n public mediaTab: SearchSuperMediaTab;\r\n\r\n public container: HTMLElement;\r\n public nav: HTMLElement;\r\n private navScrollableContainer: HTMLDivElement;\r\n private tabsContainer: HTMLElement;\r\n private tabsMenu: HTMLElement;\r\n private prevTabId = -1;\r\n \r\n private lazyLoadQueue = new LazyLoadQueue();\r\n public middleware = getMiddleware();\r\n\r\n public historyStorage: Partial<{[type in SearchSuperType]: {mid: number, peerId: number}[]}> = {};\r\n public usedFromHistory: Partial<{[type in SearchSuperType]: number}> = {};\r\n public urlsToRevoke: string[] = [];\r\n\r\n private searchContext: SearchSuperContext;\r\n public loadMutex: Promise<any> = Promise.resolve();\r\n\r\n private nextRates: Partial<{[type in SearchSuperType]: number}> = {};\r\n private loadPromises: Partial<{[type in SearchSuperType]: Promise<void>}> = {};\r\n private loaded: Partial<{[type in SearchSuperType]: boolean}> = {};\r\n private loadedChats = false;\r\n private firstLoad = true;\r\n\r\n private log = logger('SEARCH-SUPER');\r\n public selectTab: ReturnType<typeof horizontalMenu>;\r\n \r\n private monthContainers: Partial<{\r\n [type in SearchSuperType]: {\r\n [timestamp: number]: {\r\n container: HTMLElement,\r\n items: HTMLElement\r\n }\r\n }\r\n }> = {};\r\n\r\n private searchGroupMedia: SearchGroup;\r\n\r\n public mediaTabsMap: Map<SearchSuperMediaType, SearchSuperMediaTab> = new Map();\r\n\r\n private membersList: SortedUserList;\r\n\r\n private skipScroll: boolean;\r\n\r\n // * arguments\r\n public mediaTabs: SearchSuperMediaTab[];\r\n public scrollable: Scrollable;\r\n public searchGroups?: {[group in SearchGroupType]: SearchGroup};\r\n public asChatList? = false;\r\n public groupByMonth? = true;\r\n public hideEmptyTabs? = true;\r\n public onChangeTab?: (mediaTab: SearchSuperMediaTab) => void;\r\n public showSender? = false;\r\n\r\n constructor(options: Pick<AppSearchSuper, 'mediaTabs' | 'scrollable' | 'searchGroups' | 'asChatList' | 'groupByMonth' | 'hideEmptyTabs' | 'onChangeTab' | 'showSender'>) {\r\n safeAssign(this, options);\r\n\r\n this.container = document.createElement('div');\r\n this.container.classList.add('search-super');\r\n\r\n const navScrollableContainer = this.navScrollableContainer = document.createElement('div');\r\n navScrollableContainer.classList.add('search-super-tabs-scrollable', 'menu-horizontal-scrollable', 'sticky');\r\n\r\n const navScrollable = new ScrollableX(navScrollableContainer);\r\n\r\n const nav = this.nav = document.createElement('nav');\r\n nav.classList.add('search-super-tabs', 'menu-horizontal-div');\r\n this.tabsMenu = nav;\r\n\r\n navScrollable.container.append(nav);\r\n\r\n for(const mediaTab of this.mediaTabs) {\r\n const menuTab = document.createElement('div');\r\n menuTab.classList.add('menu-horizontal-div-item');\r\n const span = document.createElement('span');\r\n const i = document.createElement('i');\r\n\r\n span.append(i18n(mediaTab.name));\r\n span.append(i);\r\n\r\n menuTab.append(span);\r\n\r\n ripple(menuTab);\r\n\r\n this.tabsMenu.append(menuTab);\r\n\r\n this.mediaTabsMap.set(mediaTab.type, mediaTab);\r\n\r\n mediaTab.menuTab = menuTab;\r\n }\r\n\r\n this.tabsContainer = document.createElement('div');\r\n this.tabsContainer.classList.add('search-super-tabs-container', 'tabs-container');\r\n\r\n for(const mediaTab of this.mediaTabs) {\r\n const container = document.createElement('div');\r\n container.classList.add('search-super-container-' + mediaTab.type);\r\n\r\n const content = document.createElement('div');\r\n content.classList.add('search-super-content-' + mediaTab.type);\r\n\r\n container.append(content);\r\n\r\n this.tabsContainer.append(container);\r\n\r\n this.tabs[mediaTab.inputFilter] = content;\r\n\r\n mediaTab.contentTab = content;\r\n }\r\n\r\n this.container.append(navScrollableContainer, this.tabsContainer);\r\n\r\n // * construct end\r\n\r\n this.searchGroupMedia = new SearchGroup('', 'messages', true);\r\n\r\n this.scrollable.onScrolledBottom = () => {\r\n if(this.mediaTab.contentTab && this.mediaTab.contentTab.childElementCount/* && false */) {\r\n //this.log('onScrolledBottom will load media');\r\n this.load(true);\r\n }\r\n };\r\n //this.scroll.attachSentinels(undefined, 400);\r\n\r\n this.selectTab = horizontalMenu(this.tabsMenu, this.tabsContainer, (id, tabContent, animate) => {\r\n if(this.prevTabId === id && !this.skipScroll) {\r\n this.scrollable.scrollIntoViewNew(this.container, 'start');\r\n return;\r\n }\r\n \r\n const newMediaTab = this.mediaTabs[id];\r\n if(this.onChangeTab) {\r\n this.onChangeTab(newMediaTab);\r\n }\r\n \r\n const fromMediaTab = this.mediaTab;\r\n this.mediaTab = newMediaTab;\r\n\r\n if(this.prevTabId !== -1 && animate) {\r\n this.onTransitionStart();\r\n }\r\n\r\n if(this.skipScroll) {\r\n this.skipScroll = false;\r\n } else {\r\n const offsetTop = this.container.offsetTop;\r\n let scrollTop = this.scrollable.scrollTop;\r\n if(scrollTop < offsetTop) {\r\n this.scrollable.scrollIntoViewNew(this.container, 'start');\r\n scrollTop = offsetTop;\r\n }\r\n \r\n fromMediaTab.scroll = {scrollTop: scrollTop, scrollHeight: this.scrollable.scrollHeight};\r\n \r\n if(newMediaTab.scroll === undefined) {\r\n const rect = this.container.getBoundingClientRect();\r\n const rect2 = this.container.parentElement.getBoundingClientRect();\r\n const diff = rect.y - rect2.y;\r\n \r\n if(scrollTop > diff) {\r\n newMediaTab.scroll = {scrollTop: diff, scrollHeight: 0};\r\n }\r\n }\r\n \r\n if(newMediaTab.scroll) {\r\n const diff = fromMediaTab.scroll.scrollTop - newMediaTab.scroll.scrollTop;\r\n //console.log('what you gonna do', this.goingHard, diff);\r\n \r\n //this.scrollable.scrollTop = scrollTop;\r\n if(diff/* && diff < 0 */) {\r\n /* if(diff > -(fromMediaTab.contentTab.scrollHeight + this.nav.scrollHeight)) {\r\n fromMediaTab.contentTab.style.transform = `translateY(${diff}px)`;\r\n this.scrollable.scrollTop = scrollTop - diff;\r\n } else { */\r\n newMediaTab.contentTab.style.transform = `translateY(${diff}px)`;\r\n //}\r\n }\r\n }\r\n }\r\n \r\n /* if(this.prevTabId !== -1 && nav.offsetTop) {\r\n this.scrollable.scrollTop -= nav.offsetTop;\r\n } */\r\n\r\n /* this.log('setVirtualContainer', id, this.sharedMediaSelected, this.sharedMediaSelected.childElementCount);\r\n this.scroll.setVirtualContainer(this.sharedMediaSelected); */\r\n\r\n if(this.prevTabId !== -1 && !newMediaTab.contentTab.childElementCount) { // quick brown fix\r\n //this.contentContainer.classList.remove('loaded');\r\n this.load(true);\r\n }\r\n\r\n this.prevTabId = id;\r\n }, () => {\r\n this.scrollable.onScroll();\r\n \r\n //console.log('what y', this.tabSelected.style.transform);\r\n if(this.mediaTab.scroll !== undefined) {\r\n this.mediaTab.contentTab.style.transform = '';\r\n this.scrollable.scrollTop = this.mediaTab.scroll.scrollTop;\r\n }\r\n\r\n this.onTransitionEnd();\r\n }, undefined, navScrollable);\r\n\r\n this.tabs.inputMessagesFilterPhotoVideo.addEventListener('click', (e) => {\r\n const target = findUpClassName(e.target as HTMLDivElement, 'grid-item');\r\n \r\n const mid = +target.dataset.mid;\r\n if(!mid) {\r\n this.log.warn('no messageId by click on target:', target);\r\n return;\r\n }\r\n\r\n const peerId = +target.dataset.peerId;\r\n\r\n const targets = (Array.from(this.tabs.inputMessagesFilterPhotoVideo.querySelectorAll('.grid-item')) as HTMLElement[]).map(el => {\r\n return {element: el, mid: +el.dataset.mid, peerId: +el.dataset.peerId};\r\n });\r\n\r\n //const ids = Object.keys(this.mediaDivsByIds).map(k => +k).sort((a, b) => a - b);\r\n const idx = targets.findIndex(item => item.mid === mid && item.peerId === peerId);\r\n \r\n const message = appMessagesManager.getMessageByPeer(peerId, mid);\r\n new AppMediaViewer()\r\n .setSearchContext(this.copySearchContext(this.mediaTab.inputFilter))\r\n .openMedia(message, target, 0, false, targets.slice(0, idx), targets.slice(idx + 1));\r\n });\r\n\r\n this.mediaTab = this.mediaTabs[0];\r\n\r\n useHeavyAnimationCheck(() => {\r\n this.lazyLoadQueue.lock();\r\n }, () => {\r\n this.lazyLoadQueue.unlockAndRefresh(); // ! maybe not so efficient\r\n });\r\n }\r\n\r\n private onTransitionStart = () => {\r\n // Jolly Cobra's // Workaround for scrollable content flickering during animation.\r\n const container = this.scrollable.container;\r\n if(container.style.overflowY !== 'hidden') {\r\n // const scrollBarWidth = container.offsetWidth - container.clientWidth;\r\n container.style.overflowY = 'hidden';\r\n // container.style.paddingRight = `${scrollBarWidth}px`;\r\n this.container.classList.add('sliding');\r\n }\r\n };\r\n\r\n private onTransitionEnd = () => {\r\n // Jolly Cobra's // Workaround for scrollable content flickering during animation.\r\n const container = this.scrollable.container;\r\n\r\n if(isSafari) { // ! safari doesn't respect sticky header, so it flicks when overflow is changing\r\n container.style.display = 'none';\r\n }\r\n\r\n container.style.overflowY = '';\r\n\r\n if(isSafari) {\r\n void container.offsetLeft; // reflow\r\n container.style.display = '';\r\n }\r\n\r\n // container.style.paddingRight = '0';\r\n this.container.classList.remove('sliding');\r\n };\r\n\r\n public filterMessagesByType(messages: any[], type: SearchSuperType): MyMessage[] {\r\n if(type === 'inputMessagesFilterEmpty') return messages;\r\n\r\n if(type !== 'inputMessagesFilterUrl') {\r\n messages = messages.filter(message => !!message.media);\r\n }\r\n\r\n /* if(!this.peerId) {\r\n messages = messages.filter(message => {\r\n if(message.peerId === rootScope.myId) {\r\n return true;\r\n }\r\n\r\n const dialog = appMessagesManager.getDialogByPeerId(message.fromId)[0];\r\n return dialog && dialog.folder_id === 0;\r\n });\r\n } */\r\n\r\n let filtered: any[] = [];\r\n\r\n switch(type) {\r\n case 'inputMessagesFilterPhotoVideo': {\r\n for(let message of messages) {\r\n let media = message.media.photo || message.media.document || (message.media.webpage && message.media.webpage.document);\r\n if(!media) {\r\n //this.log('no media!', message);\r\n continue;\r\n }\r\n \r\n if(media._ === 'document' && media.type !== 'video'/* && media.type !== 'gif' */) {\r\n //this.log('broken video', media);\r\n continue;\r\n }\r\n\r\n filtered.push(message);\r\n }\r\n \r\n break;\r\n }\r\n\r\n case 'inputMessagesFilterDocument': {\r\n for(let message of messages) {\r\n if(!message.media.document || ['voice', 'audio', 'gif', 'sticker', 'round'].includes(message.media.document.type)) {\r\n continue;\r\n }\r\n \r\n filtered.push(message);\r\n }\r\n break;\r\n }\r\n\r\n case 'inputMessagesFilterUrl': {\r\n //this.log('inputMessagesFilterUrl', messages);\r\n for(let message of messages) {\r\n //if((message.media.webpage && message.media.webpage._ !== 'webPageEmpty')) {\r\n filtered.push(message);\r\n //}\r\n }\r\n \r\n break;\r\n }\r\n\r\n case 'inputMessagesFilterMusic': {\r\n for(let message of messages) {\r\n if(!message.media.document || message.media.document.type !== 'audio') {\r\n continue;\r\n }\r\n\r\n filtered.push(message);\r\n }\r\n\r\n break;\r\n }\r\n\r\n case 'inputMessagesFilterVoice': {\r\n for(let message of messages) {\r\n if(!message.media.document || message.media.document.type !== 'voice') {\r\n continue;\r\n }\r\n\r\n filtered.push(message);\r\n }\r\n\r\n break;\r\n }\r\n\r\n default:\r\n break;\r\n }\r\n\r\n return filtered;\r\n }\r\n \r\n public async performSearchResult(messages: any[], mediaTab: SearchSuperMediaTab, append = true) {\r\n const elemsToAppend: {element: HTMLElement, message: any}[] = [];\r\n const sharedMediaDiv: HTMLElement = mediaTab.contentTab;\r\n const promises: Promise<any>[] = [];\r\n const middleware = this.middleware.get();\r\n let inputFilter = mediaTab.inputFilter;\r\n\r\n await getHeavyAnimationPromise();\r\n \r\n let searchGroup: SearchGroup;\r\n if(inputFilter === 'inputMessagesFilterPhotoVideo' && !!this.searchContext.query.trim()) {\r\n inputFilter = 'inputMessagesFilterEmpty';\r\n searchGroup = this.searchGroupMedia;\r\n sharedMediaDiv.append(searchGroup.container);\r\n } else if(inputFilter === 'inputMessagesFilterEmpty') {\r\n searchGroup = this.searchGroups.messages;\r\n }\r\n\r\n // https://core.telegram.org/type/MessagesFilter\r\n switch(inputFilter) {\r\n case 'inputMessagesFilterEmpty': {\r\n for(const message of messages) {\r\n const {dialog, dom} = appDialogsManager.addDialogNew({\r\n dialog: message.peerId, \r\n container: searchGroup.list, \r\n drawStatus: false,\r\n avatarSize: 54\r\n });\r\n appDialogsManager.setLastMessage(dialog, message, dom, this.searchContext.query);\r\n }\r\n\r\n if(searchGroup.list.childElementCount) {\r\n searchGroup.setActive();\r\n }\r\n break;\r\n }\r\n\r\n case 'inputMessagesFilterPhotoVideo': {\r\n for(const message of messages) {\r\n const media = message.media.photo || message.media.document || (message.media.webpage && message.media.webpage.document);\r\n\r\n const div = document.createElement('div');\r\n div.classList.add('grid-item');\r\n //this.log(message, photo);\r\n\r\n let wrapped: ReturnType<typeof wrapPhoto>;\r\n if(media._ !== 'photo') {\r\n wrapped = wrapVideo({\r\n doc: media,\r\n message,\r\n container: div,\r\n boxWidth: 0,\r\n boxHeight: 0,\r\n lazyLoadQueue: this.lazyLoadQueue,\r\n middleware,\r\n onlyPreview: true,\r\n withoutPreloader: true,\r\n noPlayButton: true\r\n }).thumb;\r\n } else {\r\n wrapped = wrapPhoto({\r\n photo: media,\r\n message,\r\n container: div,\r\n boxWidth: 0,\r\n boxHeight: 0,\r\n lazyLoadQueue: this.lazyLoadQueue,\r\n middleware,\r\n withoutPreloader: true,\r\n noBlur: true\r\n });\r\n }\r\n\r\n [wrapped.images.thumb, wrapped.images.full].filter(Boolean).forEach(image => {\r\n image.classList.add('grid-item-media');\r\n });\r\n\r\n promises.push(wrapped.loadPromises.thumb);\r\n\r\n elemsToAppend.push({element: div, message});\r\n }\r\n \r\n break;\r\n }\r\n \r\n case 'inputMessagesFilterVoice':\r\n case 'inputMessagesFilterMusic':\r\n case 'inputMessagesFilterDocument': {\r\n for(const message of messages) {\r\n const showSender = this.showSender || message.media.document.type === 'voice';\r\n const div = wrapDocument({\r\n message,\r\n withTime: !showSender,\r\n fontWeight: 400,\r\n voiceAsMusic: true,\r\n showSender: showSender,\r\n searchContext: this.copySearchContext(inputFilter)\r\n });\r\n\r\n if(['audio', 'voice'].includes(message.media.document.type)) {\r\n div.classList.add('audio-48');\r\n }\r\n\r\n elemsToAppend.push({element: div, message});\r\n }\r\n break;\r\n }\r\n \r\n case 'inputMessagesFilterUrl': {\r\n for(let message of messages) {\r\n let webpage: any;\r\n\r\n if(message.media?.webpage && message.media.webpage._ !== 'webPageEmpty') {\r\n webpage = message.media.webpage;\r\n } else {\r\n const entity = message.totalEntities ? message.totalEntities.find((e: any) => e._ === 'messageEntityUrl' || e._ === 'messageEntityTextUrl') : null;\r\n let url: string, display_url: string, sliced: string;\r\n\r\n if(!entity) {\r\n //this.log.error('NO ENTITY:', message);\r\n const match = RichTextProcessor.matchUrl(message.message);\r\n if(!match) {\r\n //this.log.error('NO ENTITY AND NO MATCH:', message);\r\n continue;\r\n }\r\n\r\n url = match[0];\r\n } else {\r\n sliced = message.message.slice(entity.offset, entity.offset + entity.length);\r\n }\r\n\r\n if(entity?._ === 'messageEntityTextUrl') {\r\n url = entity.url;\r\n //display_url = sliced;\r\n } else {\r\n url = url || sliced;\r\n }\r\n\r\n display_url = url;\r\n\r\n const same = message.message === url;\r\n if(!url.match(/^(ftp|http|https):\\/\\//)) {\r\n display_url = 'https://' + url;\r\n url = url.includes('@') ? url : 'https://' + url;\r\n }\r\n\r\n display_url = new URL(display_url).hostname;\r\n\r\n webpage = {\r\n url,\r\n display_url\r\n };\r\n\r\n if(!same) {\r\n webpage.description = message.message;\r\n webpage.rDescription = RichTextProcessor.wrapRichText(limitSymbols(message.message, 150, 180));\r\n }\r\n }\r\n\r\n let div = document.createElement('div');\r\n \r\n let previewDiv = document.createElement('div');\r\n previewDiv.classList.add('preview');\r\n \r\n //this.log('wrapping webpage', webpage);\r\n \r\n if(webpage.photo) {\r\n const res = wrapPhoto({\r\n container: previewDiv,\r\n message: null,\r\n photo: webpage.photo,\r\n boxWidth: 0,\r\n boxHeight: 0,\r\n withoutPreloader: true,\r\n lazyLoadQueue: this.lazyLoadQueue,\r\n middleware,\r\n size: appPhotosManager.choosePhotoSize(webpage.photo, 60, 60, false),\r\n loadPromises: promises,\r\n noBlur: true\r\n });\r\n } else {\r\n previewDiv.classList.add('empty');\r\n previewDiv.innerHTML = RichTextProcessor.getAbbreviation(webpage.title || webpage.display_url || webpage.description || webpage.url, true);\r\n }\r\n \r\n let title = webpage.rTitle || '';\r\n let subtitle = webpage.rDescription || '';\r\n let url = RichTextProcessor.wrapRichText(webpage.url || '');\r\n \r\n if(!title) {\r\n //title = new URL(webpage.url).hostname;\r\n title = RichTextProcessor.wrapPlainText(webpage.display_url.split('/', 1)[0]);\r\n }\r\n\r\n let sender = this.showSender ? `<div class=\"subtitle sender\">${appMessagesManager.getSenderToPeerText(message)}</div>` : '';\r\n\r\n let titleAdditionHTML = '';\r\n if(this.showSender) {\r\n titleAdditionHTML = `<div class=\"sent-time\">${formatDateAccordingToToday(new Date(message.date * 1000))}</div>`;\r\n }\r\n\r\n div.append(previewDiv);\r\n div.insertAdjacentHTML('beforeend', `\r\n <div class=\"title\">${title}${titleAdditionHTML}</div>\r\n <div class=\"subtitle\">${subtitle}</div>\r\n <div class=\"url\">${url}</div>\r\n ${sender}\r\n `);\r\n \r\n if(div.innerText.trim().length) {\r\n elemsToAppend.push({element: div, message});\r\n }\r\n \r\n }\r\n \r\n break;\r\n }\r\n\r\n default:\r\n //this.log.warn('death is my friend', messages);\r\n break;\r\n }\r\n\r\n if(this.loadMutex) {\r\n promises.push(this.loadMutex);\r\n }\r\n\r\n if(promises.length) {\r\n await Promise.all(promises);\r\n if(!middleware()) {\r\n //this.log.warn('peer changed');\r\n return;\r\n }\r\n }\r\n \r\n if(elemsToAppend.length) {\r\n const method = append ? 'append' : 'prepend';\r\n elemsToAppend.forEach(details => {\r\n const {element, message} = details;\r\n const monthContainer = this.getMonthContainerByTimestamp(this.groupByMonth ? message.date : 0, inputFilter);\r\n element.classList.add('search-super-item');\r\n element.dataset.mid = '' + message.mid;\r\n element.dataset.peerId = '' + message.peerId;\r\n monthContainer.items[method](element);\r\n });\r\n }\r\n \r\n //if(type !== 'inputMessagesFilterEmpty') {\r\n this.afterPerforming(inputFilter === 'inputMessagesFilterEmpty' ? 1 : messages.length, sharedMediaDiv);\r\n //}\r\n }\r\n\r\n private afterPerforming(length: number, contentTab: HTMLElement) {\r\n if(contentTab) {\r\n const parent = contentTab.parentElement;\r\n Array.from(parent.children).slice(1).forEach(child => {\r\n child.remove();\r\n });\r\n\r\n //this.contentContainer.classList.add('loaded');\r\n\r\n if(!length && !contentTab.childElementCount) {\r\n const div = document.createElement('div');\r\n div.innerText = 'Nothing interesting here yet...';\r\n div.classList.add('position-center', 'text-center', 'content-empty', 'no-select');\r\n\r\n parent.append(div);\r\n }\r\n }\r\n }\r\n\r\n private loadChats() {\r\n const renderedPeerIds: Set<number> = new Set();\r\n const middleware = this.middleware.get();\r\n\r\n for(let i in this.searchGroups) {\r\n const group = this.searchGroups[i as SearchGroupType];\r\n this.tabs.inputMessagesFilterEmpty.append(group.container);\r\n group.clear();\r\n }\r\n\r\n const query = this.searchContext.query;\r\n if(query) {\r\n const setResults = (results: number[], group: SearchGroup, showMembersCount = false) => {\r\n results.forEach((peerId) => {\r\n if(renderedPeerIds.has(peerId)) {\r\n return;\r\n }\r\n \r\n renderedPeerIds.add(peerId);\r\n \r\n const peer = appPeersManager.getPeer(peerId);\r\n \r\n //////////this.log('contacts peer', peer);\r\n \r\n const {dom} = appDialogsManager.addDialogNew({\r\n dialog: peerId, \r\n container: group.list, \r\n drawStatus: false,\r\n avatarSize: 48,\r\n autonomous: group.autonomous\r\n });\r\n \r\n if(showMembersCount && (peer.participants_count || peer.participants)) {\r\n const regExp = new RegExp(`(${escapeRegExp(query)}|${escapeRegExp(searchIndexManager.cleanSearchText(query))})`, 'gi');\r\n dom.titleSpan.innerHTML = dom.titleSpan.innerHTML.replace(regExp, '<i>$1</i>');\r\n dom.lastMessageSpan.append(appChatsManager.getChatMembersString(-peerId));\r\n } else if(peerId === rootScope.myId) {\r\n dom.lastMessageSpan.append(i18n('Presence.YourChat'));\r\n } else {\r\n let username = appPeersManager.getPeerUsername(peerId);\r\n if(!username) {\r\n const user = appUsersManager.getUser(peerId);\r\n if(user && user.phone) {\r\n username = '+' + formatPhoneNumber(user.phone).formatted;\r\n }\r\n } else {\r\n username = '@' + username;\r\n }\r\n \r\n dom.lastMessageSpan.innerHTML = '<i>' + username + '</i>';\r\n }\r\n });\r\n \r\n group.toggle();\r\n };\r\n \r\n const onLoad = <T>(arg: T) => {\r\n if(!middleware()) {\r\n return;\r\n }\r\n \r\n //this.loadedContacts = true;\r\n \r\n return arg;\r\n };\r\n \r\n return Promise.all([\r\n appUsersManager.getContacts(query, true)\r\n .then(onLoad)\r\n .then((contacts) => {\r\n if(contacts) {\r\n setResults(contacts, this.searchGroups.contacts, true);\r\n }\r\n }),\r\n \r\n appUsersManager.searchContacts(query, 20)\r\n .then(onLoad)\r\n .then((contacts) => {\r\n if(contacts) {\r\n setResults(contacts.my_results, this.searchGroups.contacts, true);\r\n setResults(contacts.results/* .concat(contacts.results, contacts.results, contacts.results) */, this.searchGroups.globalContacts);\r\n\r\n if(this.searchGroups.globalContacts.nameEl.lastElementChild) {\r\n this.searchGroups.globalContacts.nameEl.lastElementChild.remove();\r\n }\r\n\r\n this.searchGroups.globalContacts.container.classList.add('is-short');\r\n \r\n if(this.searchGroups.globalContacts.list.childElementCount > 3) {\r\n const showMore = document.createElement('div');\r\n showMore.classList.add('search-group__show-more');\r\n showMore.innerText = 'Show more';\r\n this.searchGroups.globalContacts.nameEl.append(showMore);\r\n showMore.addEventListener('click', () => {\r\n const isShort = this.searchGroups.globalContacts.container.classList.toggle('is-short');\r\n showMore.innerText = isShort ? 'Show more' : 'Show less';\r\n });\r\n }\r\n }\r\n }),\r\n \r\n appMessagesManager.getConversations(query, 0, 20, 0)\r\n .then(onLoad)\r\n .then(value => {\r\n if(value) {\r\n setResults(value.dialogs.map(d => d.peerId), this.searchGroups.contacts, true);\r\n }\r\n })\r\n ]);\r\n } else if(!this.searchContext.peerId && !this.searchContext.minDate) {\r\n const renderRecentSearch = (setActive = true) => {\r\n return appStateManager.getState().then(state => {\r\n if(!middleware()) {\r\n return;\r\n }\r\n \r\n this.searchGroups.recent.list.innerHTML = '';\r\n \r\n state.recentSearch.slice(0, 20).forEach(peerId => {\r\n let {dialog, dom} = appDialogsManager.addDialogNew({\r\n dialog: peerId,\r\n container: this.searchGroups.recent.list,\r\n drawStatus: false,\r\n meAsSaved: true,\r\n avatarSize: 48,\r\n autonomous: true\r\n });\r\n \r\n dom.lastMessageSpan.append(peerId > 0 ? appUsersManager.getUserStatusString(peerId) : appChatsManager.getChatMembersString(peerId));\r\n });\r\n \r\n if(!state.recentSearch.length) {\r\n this.searchGroups.recent.clear();\r\n } else if(setActive) {\r\n this.searchGroups.recent.setActive();\r\n }\r\n });\r\n };\r\n\r\n return Promise.all([\r\n appUsersManager.getTopPeers().then(peers => {\r\n if(!middleware()) return;\r\n\r\n //console.log('got top categories:', categories);\r\n if(peers.length) {\r\n peers.forEach((peerId) => {\r\n appDialogsManager.addDialogNew({\r\n dialog: peerId, \r\n container: this.searchGroups.people.list, \r\n drawStatus: false,\r\n onlyFirstName: true,\r\n avatarSize: 54,\r\n autonomous: false\r\n });\r\n });\r\n }\r\n \r\n this.searchGroups.people.setActive();\r\n }),\r\n\r\n renderRecentSearch()\r\n ]);\r\n } else return Promise.resolve();\r\n }\r\n\r\n private loadMembers(mediaTab: SearchSuperMediaTab) {\r\n const id = -this.searchContext.peerId;\r\n const middleware = this.middleware.get();\r\n let promise: Promise<void>;\r\n\r\n const renderParticipants = async(participants: (ChatParticipant | ChannelParticipant)[]) => {\r\n if(this.loadMutex) {\r\n await this.loadMutex;\r\n\r\n if(!middleware()) {\r\n return;\r\n }\r\n }\r\n \r\n if(!this.membersList) {\r\n this.membersList = new SortedUserList();\r\n this.membersList.list.addEventListener('click', (e) => {\r\n const li = findUpTag(e.target, 'LI');\r\n if(!li) {\r\n return;\r\n }\r\n\r\n const peerId = +li.dataset.peerId;\r\n let promise: Promise<any> = Promise.resolve();\r\n if(mediaSizes.isMobile) {\r\n promise = appSidebarRight.toggleSidebar(false);\r\n }\r\n \r\n promise.then(() => {\r\n appImManager.setInnerPeer(peerId);\r\n });\r\n });\r\n mediaTab.contentTab.append(this.membersList.list);\r\n this.afterPerforming(1, mediaTab.contentTab);\r\n }\r\n\r\n participants.forEach(participant => {\r\n const user = appUsersManager.getUser(participant.user_id);\r\n if(user.pFlags.deleted) {\r\n return;\r\n }\r\n\r\n this.membersList.add(participant.user_id);\r\n });\r\n };\r\n\r\n if(appChatsManager.isChannel(id)) {\r\n const LOAD_COUNT = !this.membersList ? 50 : 200;\r\n promise = appProfileManager.getChannelParticipants(id, undefined, LOAD_COUNT, this.nextRates[mediaTab.inputFilter]).then(participants => {\r\n if(!middleware()) {\r\n return;\r\n }\r\n\r\n let list = mediaTab.contentTab.firstElementChild as HTMLUListElement;\r\n this.nextRates[mediaTab.inputFilter] = (list ? list.childElementCount : 0) + participants.participants.length;\r\n\r\n if(participants.participants.length < LOAD_COUNT) {\r\n this.loaded[mediaTab.inputFilter] = true;\r\n }\r\n\r\n return renderParticipants(participants.participants);\r\n });\r\n } else {\r\n promise = (appProfileManager.getChatFull(id) as Promise<ChatFull.chatFull>).then(chatFull => {\r\n if(!middleware()) {\r\n return;\r\n }\r\n\r\n //console.log('anymore', chatFull);\r\n this.loaded[mediaTab.inputFilter] = true;\r\n const participants = chatFull.participants;\r\n if(participants._ === 'chatParticipantsForbidden') {\r\n return;\r\n }\r\n \r\n return renderParticipants(participants.participants);\r\n });\r\n }\r\n\r\n return this.loadPromises[mediaTab.inputFilter] = promise.finally(() => { \r\n if(!middleware()) {\r\n return;\r\n }\r\n\r\n this.loadPromises[mediaTab.inputFilter] = null;\r\n });\r\n }\r\n\r\n private loadType(mediaTab: SearchSuperMediaTab, justLoad: boolean, loadCount: number, middleware: () => boolean) {\r\n const type = mediaTab.inputFilter;\r\n\r\n if(this.loadPromises[type]) {\r\n return this.loadPromises[type];\r\n }\r\n\r\n if(mediaTab.type === 'members') {\r\n return this.loadMembers(mediaTab);\r\n }\r\n\r\n const history = this.historyStorage[type] ?? (this.historyStorage[type] = []);\r\n\r\n if(type === 'inputMessagesFilterEmpty' && !history.length) {\r\n if(!this.loadedChats) {\r\n this.loadChats();\r\n this.loadedChats = true;\r\n }\r\n\r\n if(!this.searchContext.query.trim() && !this.searchContext.peerId && !this.searchContext.minDate) {\r\n this.loaded[type] = true;\r\n return Promise.resolve();\r\n }\r\n }\r\n\r\n const logStr = 'load [' + type + ']: ';\r\n\r\n // render from cache\r\n if(history.length && this.usedFromHistory[type] < history.length && !justLoad) {\r\n let messages: any[] = [];\r\n let used = Math.max(0, this.usedFromHistory[type]);\r\n let slicedLength = 0;\r\n\r\n do {\r\n let ids = history.slice(used, used + loadCount);\r\n //this.log(logStr + 'will render from cache', used, history, ids, loadCount);\r\n used += ids.length;\r\n slicedLength += ids.length;\r\n\r\n messages.push(...this.filterMessagesByType(ids.map(m => appMessagesManager.getMessageByPeer(m.peerId, m.mid)), type));\r\n } while(slicedLength < loadCount && used < history.length);\r\n \r\n // если перебор\r\n /* if(slicedLength > loadCount) {\r\n let diff = messages.length - loadCount;\r\n messages = messages.slice(0, messages.length - diff);\r\n used -= diff;\r\n } */\r\n\r\n this.usedFromHistory[type] = used;\r\n //if(messages.length) {\r\n return this.performSearchResult(messages, mediaTab).finally(() => {\r\n setTimeout(() => {\r\n this.scrollable.checkForTriggers();\r\n }, 0);\r\n });\r\n //}\r\n\r\n return Promise.resolve();\r\n }\r\n \r\n let maxId = history.length ? history[history.length - 1].mid : 0;\r\n \r\n //this.log(logStr + 'search house of glass pre', type, maxId);\r\n \r\n //let loadCount = history.length ? 50 : 15;\r\n return this.loadPromises[type] = appMessagesManager.getSearch({\r\n peerId: this.searchContext.peerId, \r\n query: this.searchContext.query,\r\n inputFilter: {_: type},\r\n maxId, \r\n limit: loadCount,\r\n nextRate: this.nextRates[type] ?? (this.nextRates[type] = 0),\r\n threadId: this.searchContext.threadId,\r\n folderId: this.searchContext.folderId,\r\n minDate: this.searchContext.minDate,\r\n maxDate: this.searchContext.maxDate\r\n }).then(value => {\r\n history.push(...value.history.map(m => ({mid: m.mid, peerId: m.peerId})));\r\n \r\n this.log(logStr + 'search house of glass', type, value);\r\n\r\n if(!middleware()) {\r\n //this.log.warn('peer changed');\r\n return;\r\n }\r\n\r\n // ! Фикс случая, когда не загружаются документы при открытой панели разработчиков (происходит из-за того, что не совпадают критерии отбора документов в getSearch)\r\n if(value.history.length < loadCount) {\r\n //if((value.count || history.length === value.count) && history.length >= value.count) {\r\n //this.log(logStr + 'loaded all media', value, loadCount);\r\n this.loaded[type] = true;\r\n }\r\n\r\n this.nextRates[type] = value.next_rate;\r\n\r\n if(justLoad) {\r\n return Promise.resolve();\r\n }\r\n\r\n this.usedFromHistory[type] = history.length;\r\n\r\n if(!this.loaded[type]) {\r\n (this.loadPromises[type] || Promise.resolve()).then(() => {\r\n setTimeout(() => {\r\n if(!middleware()) return;\r\n //this.log('will preload more');\r\n if(this.mediaTab === mediaTab) {\r\n const promise = this.load(true, true);\r\n if(promise) {\r\n promise.then(() => {\r\n if(!middleware()) return;\r\n //this.log('preloaded more');\r\n setTimeout(() => {\r\n this.scrollable.checkForTriggers();\r\n }, 0);\r\n });\r\n }\r\n }\r\n }, 0);\r\n });\r\n }\r\n\r\n //if(value.history.length) {\r\n return this.performSearchResult(this.filterMessagesByType(value.history, type), mediaTab);\r\n //}\r\n }).catch(err => {\r\n this.log.error('load error:', err);\r\n }).finally(() => {\r\n this.loadPromises[type] = null;\r\n });\r\n }\r\n \r\n public async load(single = false, justLoad = false) {\r\n // if(testScroll/* || 1 === 1 */) {\r\n // return;\r\n // }\r\n\r\n //return;\r\n \r\n const peerId = this.searchContext.peerId;\r\n this.log('load', single, peerId, this.loadPromises);\r\n const middleware = this.middleware.get();\r\n\r\n if(this.firstLoad) {\r\n if(this.hideEmptyTabs) {\r\n const mediaTabs = this.mediaTabs.filter(mediaTab => mediaTab.inputFilter !== 'inputMessagesFilterEmpty')\r\n const filters = mediaTabs.map(mediaTab => ({_: mediaTab.inputFilter}));\r\n\r\n const counters = await appMessagesManager.getSearchCounters(peerId, filters);\r\n if(!middleware()) {\r\n return;\r\n }\r\n\r\n if(this.loadMutex) {\r\n await this.loadMutex;\r\n\r\n if(!middleware()) {\r\n return;\r\n }\r\n }\r\n\r\n let firstMediaTab: SearchSuperMediaTab;\r\n let count = 0;\r\n mediaTabs.forEach(mediaTab => {\r\n const counter = counters.find(c => c.filter._ === mediaTab.inputFilter);\r\n\r\n mediaTab.menuTab.classList.toggle('hide', !counter.count);\r\n mediaTab.menuTab.classList.remove('active');\r\n //mediaTab.contentTab.classList.toggle('hide', !counter.count);\r\n\r\n if(counter.count && firstMediaTab === undefined) {\r\n firstMediaTab = mediaTab;\r\n }\r\n\r\n if(counter.count) ++count;\r\n });\r\n\r\n const membersTab = this.mediaTabsMap.get('members');\r\n const canViewMembers = this.canViewMembers();\r\n membersTab.menuTab.classList.toggle('hide', !canViewMembers);\r\n\r\n if(canViewMembers) {\r\n firstMediaTab = membersTab;\r\n }\r\n\r\n this.container.classList.toggle('hide', !firstMediaTab);\r\n this.container.parentElement.classList.toggle('search-empty', !firstMediaTab);\r\n if(firstMediaTab) {\r\n this.skipScroll = true;\r\n this.selectTab(this.mediaTabs.indexOf(firstMediaTab), false);\r\n firstMediaTab.menuTab.classList.add('active');\r\n\r\n this.navScrollableContainer.classList.toggle('hide', count <= 1);\r\n }\r\n }\r\n\r\n this.firstLoad = false;\r\n }\r\n \r\n let toLoad = single ? [this.mediaTab] : this.mediaTabs.filter(t => t !== this.mediaTab);\r\n toLoad = toLoad.filter(mediaTab => {\r\n const inputFilter = mediaTab.inputFilter;\r\n return !this.loaded[inputFilter] || (this.historyStorage[inputFilter] && this.usedFromHistory[inputFilter] < this.historyStorage[inputFilter].length);\r\n });\r\n\r\n if(!toLoad.length) {\r\n return;\r\n }\r\n\r\n const loadCount = justLoad ? 50 : Math.round((appPhotosManager.windowH / 130 | 0) * 3 * 1.25); // that's good for all types\r\n\r\n const promises: Promise<any>[] = toLoad.map(mediaTab => {\r\n return this.loadType(mediaTab, justLoad, loadCount, middleware)\r\n });\r\n\r\n return Promise.all(promises).catch(err => {\r\n this.log.error('Load error all promises:', err);\r\n });\r\n }\r\n \r\n public getMonthContainerByTimestamp(timestamp: number, type: SearchSuperType) {\r\n const date = new Date(timestamp * 1000);\r\n date.setHours(0, 0, 0);\r\n date.setDate(1);\r\n const dateTimestamp = date.getTime();\r\n const containers = this.monthContainers[type] ?? (this.monthContainers[type] = {});\r\n if(!(dateTimestamp in containers)) {\r\n const str = months[date.getMonth()] + ' ' + date.getFullYear();\r\n \r\n const container = document.createElement('div');\r\n container.className = 'search-super-month';\r\n\r\n const name = document.createElement('div');\r\n name.classList.add('search-super-month-name');\r\n name.innerText = str;\r\n container.append(name);\r\n\r\n const items = document.createElement('div');\r\n items.classList.add('search-super-month-items');\r\n\r\n container.append(name, items);\r\n\r\n const haveTimestamps = getObjectKeysAndSort(containers, 'desc');\r\n let i = 0;\r\n for(; i < haveTimestamps.length; ++i) {\r\n const t = haveTimestamps[i];\r\n if(dateTimestamp > t) {\r\n break;\r\n }\r\n }\r\n \r\n containers[dateTimestamp] = {container, items};\r\n positionElementByIndex(container, this.tabs[type], i);\r\n }\r\n\r\n return containers[dateTimestamp];\r\n }\r\n\r\n public canViewMembers() {\r\n return this.searchContext.peerId < 0 && !appChatsManager.isBroadcast(-this.searchContext.peerId) && appChatsManager.hasRights(-this.searchContext.peerId, 'view_participants');\r\n }\r\n\r\n public cleanup() {\r\n this.loadPromises = {};\r\n this.loaded = {};\r\n this.loadedChats = false;\r\n this.nextRates = {};\r\n this.firstLoad = true;\r\n\r\n this.lazyLoadQueue.clear();\r\n\r\n this.mediaTabs.forEach(mediaTab => {\r\n this.usedFromHistory[mediaTab.inputFilter] = -1;\r\n });\r\n\r\n // * must go to first tab (это костыль)\r\n /* const membersTab = this.mediaTabsMap.get('members');\r\n if(membersTab) {\r\n const tab = this.canViewMembers() ? membersTab : this.mediaTabs[this.mediaTabs.indexOf(membersTab) + 1];\r\n this.mediaTab = tab;\r\n } */\r\n\r\n this.middleware.clean();\r\n this.cleanScrollPositions();\r\n this.membersList = undefined;\r\n }\r\n\r\n public cleanScrollPositions() {\r\n this.mediaTabs.forEach(mediaTab => {\r\n mediaTab.scroll = undefined;\r\n });\r\n }\r\n\r\n public cleanupHTML(goFirst = false) {\r\n if(this.urlsToRevoke.length) {\r\n this.urlsToRevoke.forEach(url => {\r\n URL.revokeObjectURL(url);\r\n });\r\n this.urlsToRevoke.length = 0;\r\n }\r\n\r\n this.mediaTabs.forEach((tab) => {\r\n tab.contentTab.innerHTML = '';\r\n\r\n if(this.hideEmptyTabs) {\r\n //tab.menuTab.classList.add('hide');\r\n this.container.classList.add('hide');\r\n this.container.parentElement.classList.add('search-empty');\r\n }\r\n\r\n if(tab.type === 'chats') {\r\n return;\r\n }\r\n \r\n if(!this.historyStorage[tab.inputFilter]) {\r\n const parent = tab.contentTab.parentElement;\r\n //if(!testScroll) {\r\n if(!parent.querySelector('.preloader')) {\r\n putPreloader(parent, true);\r\n }\r\n //}\r\n\r\n const empty = parent.querySelector('.content-empty');\r\n if(empty) {\r\n empty.remove();\r\n }\r\n }\r\n });\r\n\r\n /* if(goFirst) {\r\n const membersTab = this.mediaTabsMap.get('members');\r\n if(membersTab) {\r\n let idx = this.canViewMembers() ? 0 : 1;\r\n membersTab.menuTab.classList.toggle('hide', idx !== 0);\r\n\r\n this.selectTab(idx, false);\r\n } else {\r\n this.selectTab(0, false);\r\n }\r\n } */\r\n\r\n this.monthContainers = {};\r\n this.searchGroupMedia.clear();\r\n this.scrollable.scrollTop = 0;\r\n\r\n /* if(testScroll) {\r\n for(let i = 0; i < 1500; ++i) {\r\n let div = document.createElement('div');\r\n div.insertAdjacentHTML('beforeend', `<img class=\"media-image\" src=\"assets/img/camomile.jpg\">`);\r\n div.classList.add('grid-item');\r\n div.dataset.id = '' + (i / 3 | 0);\r\n //div.innerText = '' + (i / 3 | 0);\r\n this.tabs.inputMessagesFilterPhotoVideo.append(div);\r\n }\r\n } */\r\n }\r\n\r\n private copySearchContext(newInputFilter: MyInputMessagesFilter) {\r\n const context = copy(this.searchContext);\r\n context.inputFilter = newInputFilter;\r\n context.nextRate = this.nextRates[newInputFilter];\r\n return context;\r\n }\r\n\r\n public setQuery({peerId, query, threadId, historyStorage, folderId, minDate, maxDate}: {\r\n peerId: number, \r\n query?: string, \r\n threadId?: number, \r\n historyStorage?: AppSearchSuper['historyStorage'], \r\n folderId?: number,\r\n minDate?: number,\r\n maxDate?: number\r\n }) {\r\n this.searchContext = {\r\n peerId: peerId || 0,\r\n query: query || '',\r\n inputFilter: this.mediaTab.inputFilter,\r\n threadId,\r\n folderId,\r\n minDate,\r\n maxDate\r\n };\r\n \r\n this.historyStorage = historyStorage ?? {};\r\n\r\n this.cleanup();\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, AttachClickOptions, cancelEvent, CLICK_EVENT_NAME } from \"../helpers/dom\";\r\nimport ListenerSetter from \"../helpers/listenerSetter\";\r\nimport { i18n, LangPackKey } from \"../lib/langPack\";\r\nimport CheckboxField from \"./checkboxField\";\r\nimport { closeBtnMenu } from \"./misc\";\r\nimport { ripple } from \"./ripple\";\r\n\r\nexport type ButtonMenuItemOptions = {\r\n icon: string, \r\n text: LangPackKey, \r\n onClick: (e: MouseEvent | TouchEvent) => void, \r\n element?: HTMLElement,\r\n options?: AttachClickOptions,\r\n checkboxField?: CheckboxField,\r\n /* , cancelEvent?: true */\r\n};\r\n\r\nconst ButtonMenuItem = (options: ButtonMenuItemOptions) => {\r\n if(options.element) return options.element;\r\n\r\n const {icon, text, onClick} = options;\r\n const el = document.createElement('div');\r\n el.className = 'btn-menu-item tgico-' + icon;\r\n ripple(el);\r\n const t = i18n(text);\r\n t.classList.add('btn-menu-item-text');\r\n el.append(t);\r\n\r\n if(options.checkboxField) {\r\n el.append(options.checkboxField.label);\r\n attachClickEvent(el, () => {\r\n options.checkboxField.checked = !options.checkboxField.checked;\r\n }, options.options);\r\n }\r\n\r\n // * cancel keyboard close\r\n attachClickEvent(el, CLICK_EVENT_NAME !== 'click' ? (e) => {\r\n cancelEvent(e);\r\n onClick(e);\r\n closeBtnMenu();\r\n } : onClick, options.options);\r\n\r\n return options.element = el;\r\n};\r\n\r\nconst ButtonMenu = (buttons: ButtonMenuItemOptions[], listenerSetter?: ListenerSetter) => {\r\n const el = document.createElement('div');\r\n el.classList.add('btn-menu');\r\n\r\n if(listenerSetter) {\r\n buttons.forEach(b => {\r\n if(b.options) {\r\n b.options.listenerSetter = listenerSetter;\r\n } else {\r\n b.options = {listenerSetter};\r\n }\r\n });\r\n }\r\n\r\n const items = buttons.map(ButtonMenuItem);\r\n\r\n el.append(...items);\r\n\r\n return el;\r\n};\r\n\r\nexport default ButtonMenu;\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 { AttachClickOptions, cancelEvent, CLICK_EVENT_NAME } from \"../helpers/dom\";\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 = (options: Partial<{noRipple: true, onlyMobile: true, listenerSetter: ListenerSetter}> = {}, direction: 'bottom-left' | 'bottom-right' | 'top-left' | 'top-right', buttons: ButtonMenuItemOptions[], onOpen?: (e: Event) => void) => {\r\n const button = ButtonIcon('more btn-menu-toggle', options);\r\n\r\n const btnMenu = ButtonMenu(buttons, options.listenerSetter);\r\n btnMenu.classList.add(direction);\r\n ButtonMenuToggleHandler(button, onOpen, options);\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) => {\r\n const add = options?.listenerSetter ? options.listenerSetter.add.bind(options.listenerSetter, 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);\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\";\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.on('apiUpdate', (e) => {\r\n const update = e as Update;\r\n\r\n switch(update._) {\r\n case 'updatePrivacy':\r\n const key = update.key._;\r\n this.privacy[key] = update.rules;\r\n rootScope.broadcast('privacy_update', update);\r\n break;\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.processUpdateMessage({\r\n _: 'updateShort',\r\n update: {\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 } as Update.updatePrivacy\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: number[], chats: number[]};\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 { 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\ntype PrivacySectionStr = LangPackKey | '';\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?: number[],\r\n allow?: number[]\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', 'disallow'] as ('allow' | 'disallow')[]).forEach(k => {\r\n const arr = [];\r\n const from = k === 'allow' ? details.allowPeers : details.disallowPeers;\r\n arr.push(...from.users);\r\n arr.push(...from.chats.map(id => -id));\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: number[] = this.peerIds[k];\r\n \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.map(peerId => -peerId)});\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 }, 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 {\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: number[]) {\r\n const peers = {users: [] as number[], chats: [] as number[]};\r\n peerIds.forEach(peerId => {\r\n peers[peerId < 0 ? 'chats' : 'users'].push(peerId < 0 ? -peerId : peerId);\r\n });\r\n\r\n return peers;\r\n }\r\n\r\n private generateStr(peers: {users: number[], chats: number[]}): HTMLElement[] {\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 from \"../../../privacySection\";\r\nimport { LangPackKey } from \"../../../../lib/langPack\";\r\n\r\nexport default class AppPrivacyPhoneNumberTab extends SliderSuperTabEventable {\r\n protected init() {\r\n this.container.classList.add('privacy-tab', 'privacy-phone-number');\r\n this.setTitle('PrivacyPhone');\r\n\r\n const phoneCaption: LangPackKey = 'PrivacyPhoneInfo';\r\n const phoneSection = new PrivacySection({\r\n tab: this,\r\n title: 'PrivacyPhoneTitle',\r\n inputKey: 'inputPrivacyKeyPhoneNumber',\r\n captions: [phoneCaption, phoneCaption, ''],\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","/*\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 { Document, InputFileLocation, InputStickerSet, MessagesAllStickers, MessagesFeaturedStickers, MessagesFoundStickerSets, MessagesRecentStickers, MessagesStickers, MessagesStickerSet, PhotoSize, StickerPack, StickerSet, StickerSetCovered } from '../../layer';\r\nimport { Modify } from '../../types';\r\nimport apiManager from '../mtproto/mtprotoworker';\r\nimport rootScope from '../rootScope';\r\nimport appDocsManager from './appDocsManager';\r\nimport AppStorage from '../storage';\r\nimport { MOUNT_CLASS_TO } from '../../config/debug';\r\nimport { forEachReverse } from '../../helpers/array';\r\n\r\n// TODO: если пак будет сохранён и потом обновлён, то недостающие стикеры не подгрузит\r\n\r\nexport class AppStickersManager {\r\n private storage = new AppStorage<Record<string, MessagesStickerSet>>({\r\n storeName: 'stickerSets'\r\n });\r\n\r\n private getStickerSetPromises: {[setId: string]: Promise<MessagesStickerSet>} = {};\r\n private getStickersByEmoticonsPromises: {[emoticon: string]: Promise<Document[]>} = {};\r\n \r\n constructor() {\r\n this.getStickerSet({id: 'emoji', access_hash: ''}, {overwrite: true});\r\n\r\n rootScope.on('apiUpdate', (e) => {\r\n const update = e;\r\n \r\n switch(update._) {\r\n case 'updateNewStickerSet': {\r\n this.saveStickerSet(update.stickerset, update.stickerset.set.id);\r\n rootScope.broadcast('stickers_installed', update.stickerset.set);\r\n break;\r\n }\r\n }\r\n });\r\n }\r\n\r\n public saveStickers(docs: Document[]) {\r\n forEachReverse(docs, (doc, idx) => {\r\n doc = appDocsManager.saveDoc(doc);\r\n\r\n if(!doc) docs.splice(idx, 1);\r\n else docs[idx] = doc;\r\n });\r\n }\r\n\r\n public async getStickerSet(set: {\r\n id: string,\r\n access_hash: string\r\n }, params: Partial<{\r\n overwrite: boolean\r\n }> = {}): Promise<MessagesStickerSet> {\r\n if(this.getStickerSetPromises[set.id]) {\r\n return this.getStickerSetPromises[set.id];\r\n }\r\n\r\n return this.getStickerSetPromises[set.id] = new Promise(async(resolve, reject) => {\r\n if(!params.overwrite) {\r\n const cachedSet = await this.storage.get(set.id);\r\n if(cachedSet && cachedSet.documents?.length) {\r\n this.saveStickers(cachedSet.documents);\r\n resolve(cachedSet);\r\n delete this.getStickerSetPromises[set.id];\r\n return;\r\n }\r\n }\r\n\r\n try {\r\n const stickerSet = await apiManager.invokeApi('messages.getStickerSet', {\r\n stickerset: this.getStickerSetInput(set)\r\n });\r\n \r\n this.saveStickerSet(stickerSet, set.id);\r\n \r\n resolve(stickerSet);\r\n } catch(err) {\r\n resolve(null);\r\n }\r\n \r\n delete this.getStickerSetPromises[set.id];\r\n });\r\n }\r\n\r\n public async getRecentStickers(): Promise<Modify<MessagesRecentStickers.messagesRecentStickers, {\r\n stickers: Document[]\r\n }>> {\r\n const res = await apiManager.invokeApiHashable('messages.getRecentStickers') as MessagesRecentStickers.messagesRecentStickers;\r\n\r\n this.saveStickers(res.stickers);\r\n\r\n return res;\r\n }\r\n\r\n public getAnimatedEmojiSticker(emoji: string) {\r\n const stickerSet = this.storage.getFromCache('emoji');\r\n if(!stickerSet || !stickerSet.documents) return undefined;\r\n\r\n emoji = emoji.replace(/\\ufe0f/g, '').replace(/🏻|🏼|🏽|🏾|🏿/g, '');\r\n const pack = stickerSet.packs.find(p => p.emoticon === emoji);\r\n return pack ? appDocsManager.getDoc(pack.documents[0]) : undefined;\r\n }\r\n \r\n public saveStickerSet(res: Omit<MessagesStickerSet.messagesStickerSet, '_'>, id: string) {\r\n //console.log('stickers save set', res);w\r\n\r\n const newSet: MessagesStickerSet = {\r\n _: 'messages.stickerSet',\r\n set: res.set,\r\n packs: res.packs,\r\n documents: res.documents as Document[]\r\n };\r\n \r\n let stickerSet = this.storage.getFromCache(id);\r\n if(stickerSet) {\r\n Object.assign(stickerSet, newSet);\r\n } else {\r\n stickerSet = this.storage.setToCache(id, newSet);\r\n }\r\n\r\n this.saveStickers(res.documents);\r\n \r\n //console.log('stickers wrote', this.stickerSets);\r\n const needSave = stickerSet.set.installed_date || id === 'emoji';\r\n this.storage.set({[id]: stickerSet}, !needSave);\r\n }\r\n\r\n public getStickerSetThumbDownloadOptions(stickerSet: StickerSet.stickerSet) {\r\n const thumb = stickerSet.thumbs.find(thumb => thumb._ === 'photoSize') as PhotoSize.photoSize;\r\n const dcId = stickerSet.thumb_dc_id;\r\n\r\n const isAnimated = stickerSet.pFlags?.animated;\r\n\r\n const input: InputFileLocation.inputStickerSetThumb = {\r\n _: 'inputStickerSetThumb',\r\n stickerset: this.getStickerSetInput(stickerSet),\r\n volume_id: thumb.location.volume_id,\r\n local_id: thumb.location.local_id\r\n };\r\n\r\n return {dcId, location: input, size: thumb.size, mimeType: isAnimated ? \"application/x-tgsticker\" : 'image/webp'};\r\n }\r\n\r\n /* public getStickerSetThumbURL(stickerSet: MTStickerSet) {\r\n const thumb = stickerSet.thumb;\r\n const dcId = stickerSet.thumb_dc_id;\r\n\r\n const isAnimated = stickerSet.pFlags?.animated;\r\n\r\n const input: inputStickerSetThumb = {\r\n _: 'inputStickerSetThumb',\r\n stickerset: this.getStickerSetInput(stickerSet),\r\n volume_id: thumb.location.volume_id,\r\n local_id: thumb.location.local_id\r\n };\r\n\r\n const url = getFileURL('document', this.getStickerSetThumbDownloadOptions(stickerSet));\r\n return url;\r\n\r\n //return promise;\r\n } */\r\n\r\n public getStickerSetInput(set: {id: string, access_hash: string}): InputStickerSet {\r\n return set.id === 'emoji' ? {\r\n _: 'inputStickerSetAnimatedEmoji'\r\n } : {\r\n _: 'inputStickerSetID',\r\n id: set.id,\r\n access_hash: set.access_hash\r\n };\r\n }\r\n\r\n public async getFeaturedStickers() {\r\n const res = await apiManager.invokeApiHashable('messages.getFeaturedStickers') as MessagesFeaturedStickers.messagesFeaturedStickers;\r\n \r\n res.sets.forEach(covered => {\r\n this.saveStickerSet({set: covered.set, documents: [], packs: []}, covered.set.id);\r\n });\r\n\r\n return res.sets;\r\n }\r\n\r\n public async toggleStickerSet(set: StickerSet.stickerSet) {\r\n if(set.installed_date) {\r\n const res = await apiManager.invokeApi('messages.uninstallStickerSet', {\r\n stickerset: this.getStickerSetInput(set)\r\n });\r\n\r\n if(res) {\r\n delete set.installed_date;\r\n rootScope.broadcast('stickers_deleted', set);\r\n this.storage.remove(set.id, true);\r\n return true;\r\n }\r\n } else {\r\n const res = await apiManager.invokeApi('messages.installStickerSet', {\r\n stickerset: this.getStickerSetInput(set),\r\n archived: false\r\n });\r\n\r\n if(res) {\r\n set.installed_date = Date.now() / 1000 | 0;\r\n rootScope.broadcast('stickers_installed', set);\r\n return true;\r\n }\r\n }\r\n\r\n return false;\r\n }\r\n\r\n public async searchStickerSets(query: string, excludeFeatured = true) {\r\n const flags = excludeFeatured ? 1 : 0;\r\n const res = await apiManager.invokeApiHashable('messages.searchStickerSets', {\r\n flags,\r\n exclude_featured: excludeFeatured || undefined,\r\n q: query\r\n }) as MessagesFoundStickerSets.messagesFoundStickerSets;\r\n\r\n res.sets.forEach(covered => {\r\n this.saveStickerSet({set: covered.set, documents: [], packs: []}, covered.set.id);\r\n });\r\n\r\n const foundSaved: StickerSetCovered[] = [];\r\n const cache = this.storage.getCache();\r\n for(let id in cache) {\r\n const {set} = cache[id];\r\n\r\n if(set.title.toLowerCase().includes(query.toLowerCase()) && !res.sets.find(c => c.set.id === set.id)) {\r\n foundSaved.push({_: 'stickerSetCovered', set, cover: null});\r\n }\r\n }\r\n\r\n return res.sets.concat(foundSaved);\r\n }\r\n\r\n public getAllStickers() {\r\n return apiManager.invokeApiHashable('messages.getAllStickers');\r\n }\r\n\r\n public preloadStickerSets() {\r\n return this.getAllStickers().then(allStickers => {\r\n return Promise.all((allStickers as MessagesAllStickers.messagesAllStickers).sets.map(set => this.getStickerSet(set)));\r\n });\r\n }\r\n\r\n public getStickersByEmoticon(emoticon: string) {\r\n if(this.getStickersByEmoticonsPromises[emoticon]) return this.getStickersByEmoticonsPromises[emoticon];\r\n\r\n return this.getStickersByEmoticonsPromises[emoticon] = Promise.all([\r\n apiManager.invokeApiHashable('messages.getStickers', {\r\n emoticon\r\n }),\r\n this.preloadStickerSets(),\r\n this.getRecentStickers()\r\n ]).then(([messagesStickers, installedSets, recentStickers]) => {\r\n const foundStickers = (messagesStickers as MessagesStickers.messagesStickers).stickers.map(sticker => appDocsManager.saveDoc(sticker));\r\n const cachedStickersAnimated: Document.document[] = [], cachedStickersStatic: Document.document[] = [];\r\n\r\n //console.log('getStickersByEmoticon', messagesStickers, installedSets, recentStickers);\r\n\r\n const iteratePacks = (packs: StickerPack.stickerPack[]) => {\r\n for(const pack of packs) {\r\n if(pack.emoticon.includes(emoticon)) {\r\n for(const docId of pack.documents) {\r\n const doc = appDocsManager.getDoc(docId);\r\n (doc.animated ? cachedStickersAnimated : cachedStickersStatic).push(doc);\r\n }\r\n }\r\n }\r\n };\r\n\r\n iteratePacks(recentStickers.packs);\r\n\r\n for(const set of installedSets) {\r\n iteratePacks(set.packs);\r\n }\r\n\r\n const stickers = [...new Set(cachedStickersAnimated.concat(cachedStickersStatic, foundStickers))]/* .filter(doc => !doc.animated) */;\r\n\r\n return stickers;\r\n });\r\n }\r\n}\r\n\r\nconst appStickersManager = new AppStickersManager();\r\nMOUNT_CLASS_TO.appStickersManager = appStickersManager;\r\nexport default appStickersManager;\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\";\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 { 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 { attachClickEvent, canFocus, replaceContent, toggleDisability } from \"../../../../helpers/dom\";\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\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 { attachClickEvent, cancelEvent, canFocus } from \"../../../../helpers/dom\";\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\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 { attachClickEvent, cancelEvent } from \"../../../../helpers/dom\";\r\nimport { toast } from \"../../../toast\";\r\nimport I18n from \"../../../../lib/langPack\";\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 { attachClickEvent, cancelEvent } from \"../../../../helpers/dom\";\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\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 { attachClickEvent, cancelEvent, canFocus, replaceContent } from \"../../../../helpers/dom\";\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 passwordInputField.label.innerHTML = 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\";\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.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.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.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\n\r\nexport default class AppPrivacyAddToGroupsTab extends SliderSuperTabEventable {\r\n protected init() {\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 });\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.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 { formatDateAccordingToToday } from \"../../../helpers/date\";\r\nimport { attachContextMenuListener, openBtnMenu, positionMenu } from \"../../misc\";\r\nimport { attachClickEvent, toggleDisability } from \"../../../helpers/dom\";\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\n\r\nexport default class AppActiveSessionsTab extends SliderSuperTab {\r\n public privacyTab: AppPrivacyAndSecurityTab;\r\n public authorizations: Authorization.authorization[];\r\n private menuElement: HTMLElement;\r\n \r\n protected init() {\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 : formatDateAccordingToToday(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].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 });\r\n\r\n const auth = authorizations.findAndSplice(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 this.privacyTab.updateActiveSessions();\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 });\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 this.privacyTab.updateActiveSessions();\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 { attachClickEvent } from \"../../../helpers/dom\";\r\nimport ButtonMenu from \"../../buttonMenu\";\r\nimport appDialogsManager from \"../../../lib/appManagers/appDialogsManager\";\r\nimport appUsersManager from \"../../../lib/appManagers/appUsersManager\";\r\nimport Button from \"../../button\";\r\nimport PopupPickUser from \"../../popups/pickUser\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport findUpTag from \"../../../helpers/dom/findUpTag\";\r\n\r\nexport default class AppBlockedUsersTab extends SliderSuperTab {\r\n public peerIds: number[];\r\n private menuElement: HTMLElement;\r\n \r\n protected init() {\r\n this.container.classList.add('blocked-users-container');\r\n this.setTitle('BlockedUsers');\r\n\r\n {\r\n const section = new SettingSection({\r\n caption: 'BlockedUsersInfo'\r\n });\r\n\r\n this.scrollable.append(section.container);\r\n }\r\n\r\n const btnAdd = Button('btn-circle btn-corner tgico-add 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 this.scrollable.append(list);\r\n\r\n const add = (peerId: number, 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.rPhone) dom.lastMessageSpan.innerHTML = user.rPhone;\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;\r\n appUsersManager.toggleBlock(peerId, false);\r\n };\r\n\r\n const element = this.menuElement = ButtonMenu([{\r\n icon: 'unlock',\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","/*\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 { generateSection, SettingSection } from \"..\";\r\nimport Row from \"../../row\";\r\nimport { AccountPassword, Authorization, InputPrivacyKey } 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 { convertKeyToInputKey } from \"../../../helpers/string\";\r\nimport { i18n, LangPackKey, _i18n } from \"../../../lib/langPack\";\r\n\r\nexport default class AppPrivacyAndSecurityTab extends SliderSuperTab {\r\n private activeSessionsRow: Row;\r\n private authorizations: Authorization.authorization[];\r\n\r\n protected init() {\r\n this.container.classList.add('privacy-container');\r\n this.setTitle('PrivacySettings');\r\n\r\n const section = generateSection.bind(null, this.scrollable);\r\n\r\n const SUBTITLE: LangPackKey = 'Loading';\r\n\r\n {\r\n const section = new SettingSection({noDelimiter: true});\r\n\r\n let blockedPeerIds: number[];\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.privacyTab = this;\r\n tab.authorizations = this.authorizations;\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 let blockedCount: number;\r\n const setBlockedCount = (count: number) => {\r\n blockedCount = count;\r\n\r\n if(count) {\r\n _i18n(blockedUsersRow.subtitle, 'PrivacySettingsController.UserCount', [count]);\r\n } else {\r\n _i18n(blockedUsersRow.subtitle, 'BlockedEmpty');\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 _i18n(twoFactorRow.subtitle, 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 container = section('PrivacyTitle');\r\n\r\n container.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 for(const key in rowsByKeys) {\r\n updatePrivacyRow(key as keyof typeof rowsByKeys);\r\n }\r\n\r\n rootScope.on('privacy_update', (update) => {\r\n updatePrivacyRow(convertKeyToInputKey(update.key._) as any);\r\n });\r\n\r\n container.append(numberVisibilityRow.container, lastSeenTimeRow.container, photoVisibilityRow.container, callRow.container, linkAccountRow.container, groupChatsAddRow.container);\r\n }\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\nexport function rgbToHsl(r: number, g: number, b: number) {\r\n r /= 255, g /= 255, b /= 255;\r\n let 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,\r\n s: s,\r\n l: l,\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, s, and l are contained in the set [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 hslToRgba(h: number, s: number, l: number, a: number) {\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) / 100;\r\n }\r\n \r\n return +val / 360;\r\n });\r\n\r\n return hslToRgba(arr[0], arr[1], arr[2], alpha);\r\n}\r\n\r\nexport function hslaStringToRgbaString(hsla: string) {\r\n return '#' + hslaStringToRgba(hsla).map(v => ('0' + v.toString(16)).slice(-2)).join('');\r\n}\r\n\r\nexport function hslaStringToRgbString(hsla: string) {\r\n return hslaStringToRgbaString(hsla).slice(0, -2);\r\n}\r\n\r\n// * https://github.com/TelegramMessenger/Telegram-iOS/blob/3d062fff78cc6b287c74e6171f855a3500c0156d/submodules/TelegramPresentationData/Sources/PresentationData.swift#L453\r\nexport function highlightningColor(pixel: Uint8ClampedArray) {\r\n let {h, s, l} = rgbToHsl(pixel[0], pixel[1], pixel[2]);\r\n if(s > 0.0) {\r\n s = Math.min(1.0, s + 0.05 + 0.1 * (1.0 - s));\r\n }\r\n l = Math.max(0.0, l * 0.65);\r\n \r\n const hsla = `hsla(${h * 360}, ${s * 100}%, ${l * 100}%, .4)`;\r\n return hsla;\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 } from \"../../../helpers/averageColor\";\r\nimport blur from \"../../../helpers/blur\";\r\nimport { deferredPromise } from \"../../../helpers/cancellablePromise\";\r\nimport { highlightningColor } from \"../../../helpers/color\";\r\nimport { attachClickEvent } from \"../../../helpers/dom\";\r\nimport findUpClassName from \"../../../helpers/dom/findUpClassName\";\r\nimport { AccountWallPapers, WallPaper } from \"../../../layer\";\r\nimport appDocsManager, { MyDocument } from \"../../../lib/appManagers/appDocsManager\";\r\nimport appDownloadManager from \"../../../lib/appManagers/appDownloadManager\";\r\nimport appImManager from \"../../../lib/appManagers/appImManager\";\r\nimport appStateManager from \"../../../lib/appManagers/appStateManager\";\r\nimport apiManager from \"../../../lib/mtproto/mtprotoworker\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport CheckboxField from \"../../checkboxField\";\r\nimport ProgressivePreloader from \"../../preloader\";\r\nimport { SliderSuperTab } from \"../../slider\";\r\nimport { wrapPhoto } from \"../../wrappers\";\r\n\r\nexport default class AppBackgroundTab extends SliderSuperTab {\r\n init() {\r\n this.container.classList.add('background-container');\r\n this.setTitle('ChatBackground');\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', disabled: true});\r\n //const colorButton = Button('btn-primary btn-transparent', {icon: 'colorize', text: 'ChatBackground.SetColor', disabled: true});\r\n\r\n const blurCheckboxField = new CheckboxField({\r\n text: 'ChatBackground.Blur', \r\n name: 'blur', \r\n stateKey: 'settings.background.blur',\r\n withRipple: true\r\n });\r\n blurCheckboxField.input.addEventListener('change', () => {\r\n const active = grid.querySelector('.active') as HTMLElement;\r\n if(!active) return;\r\n\r\n // * wait for animation end\r\n setTimeout(() => {\r\n setBackgroundDocument(active.dataset.slug, appDocsManager.getDoc(active.dataset.docId));\r\n }, 100);\r\n });\r\n\r\n container.append(/* uploadButton, colorButton, */blurCheckboxField.label);\r\n }\r\n\r\n const grid = document.createElement('div');\r\n grid.classList.add('grid');\r\n\r\n const 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 let tempId = 0;\r\n const setBackgroundDocument = (slug: string, doc: MyDocument) => {\r\n let _tempId = ++tempId;\r\n const middleware = () => _tempId === tempId;\r\n\r\n const download = appDocsManager.downloadDoc(doc, appImManager.chat.bubbles ? appImManager.chat.bubbles.lazyLoadQueue.queueId : 0);\r\n\r\n const deferred = deferredPromise<void>();\r\n deferred.addNotifyListener = download.addNotifyListener;\r\n deferred.cancel = download.cancel;\r\n\r\n download.then(() => {\r\n if(!middleware()) {\r\n return;\r\n }\r\n\r\n const onReady = (url: string) => {\r\n //const perf = performance.now();\r\n averageColor(url).then(pixel => {\r\n if(!middleware()) {\r\n return;\r\n }\r\n \r\n const hsla = highlightningColor(pixel);\r\n //console.log(doc, hsla, performance.now() - perf);\r\n\r\n rootScope.settings.background.slug = slug;\r\n rootScope.settings.background.type = 'image';\r\n rootScope.settings.background.highlightningColor = hsla;\r\n appImManager.applyBackgroundColor();\r\n appStateManager.pushToState('settings', rootScope.settings);\r\n\r\n saveToCache(slug, url);\r\n appImManager.setBackground(url).then(deferred.resolve);\r\n });\r\n };\r\n\r\n if(rootScope.settings.background.blur) {\r\n setTimeout(() => {\r\n blur(doc.url, 12, 4)\r\n .then(url => {\r\n if(!middleware()) {\r\n return;\r\n }\r\n\r\n onReady(url);\r\n });\r\n }, 200);\r\n } else {\r\n onReady(doc.url);\r\n }\r\n });\r\n\r\n return deferred;\r\n };\r\n\r\n const setActive = () => {\r\n const active = grid.querySelector('.active');\r\n const target = rootScope.settings.background.type === 'image' ? grid.querySelector(`.grid-item[data-slug=\"${rootScope.settings.background.slug}\"]`) : 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 rootScope.on('background_change', setActive);\r\n\r\n apiManager.invokeApiHashable('account.getWallPapers').then((accountWallpapers) => {\r\n const wallpapers = (accountWallpapers as AccountWallPapers.accountWallPapers).wallpapers as WallPaper.wallPaper[];\r\n wallpapers.forEach((wallpaper) => {\r\n if(wallpaper.pFlags.pattern || (wallpaper.document as MyDocument).mime_type.indexOf('application/') === 0) {\r\n return;\r\n }\r\n\r\n wallpaper.document = appDocsManager.saveDoc(wallpaper.document);\r\n\r\n const container = document.createElement('div');\r\n container.classList.add('grid-item');\r\n\r\n const wrapped = wrapPhoto({\r\n photo: wallpaper.document,\r\n message: null,\r\n container: container,\r\n boxWidth: 0,\r\n boxHeight: 0,\r\n withoutPreloader: true\r\n });\r\n\r\n [wrapped.images.thumb, wrapped.images.full].filter(Boolean).forEach(image => {\r\n image.classList.add('grid-item-media');\r\n });\r\n\r\n container.dataset.docId = wallpaper.document.id;\r\n container.dataset.slug = wallpaper.slug;\r\n\r\n if(rootScope.settings.background.type === 'image' && rootScope.settings.background.slug === wallpaper.slug) {\r\n container.classList.add('active');\r\n }\r\n\r\n grid.append(container);\r\n });\r\n\r\n let clicked: Set<string> = new Set();\r\n attachClickEvent(grid, (e) => {\r\n const target = findUpClassName(e.target, 'grid-item') as HTMLElement;\r\n if(!target) return;\r\n\r\n const {docId, slug} = target.dataset;\r\n if(clicked.has(docId)) return;\r\n clicked.add(docId);\r\n\r\n const preloader = new ProgressivePreloader({\r\n cancelable: true,\r\n tryAgainOnFail: false\r\n });\r\n\r\n const doc = appDocsManager.getDoc(docId);\r\n\r\n const load = () => {\r\n const promise = setBackgroundDocument(slug, doc);\r\n if(!doc.url || rootScope.settings.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 } else {\r\n load();\r\n }\r\n });\r\n\r\n load();\r\n\r\n //console.log(doc);\r\n });\r\n\r\n //console.log(accountWallpapers);\r\n });\r\n\r\n this.scrollable.append(grid);\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 const averageColor = (imageUrl: string): Promise<Uint8ClampedArray> => {\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\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 resolve(outPixel);\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 { generateSection } from \"..\";\r\nimport RangeSelector from \"../../rangeSelector\";\r\nimport Button from \"../../button\";\r\nimport CheckboxField from \"../../checkboxField\";\r\nimport RadioField from \"../../radioField\";\r\nimport appStateManager from \"../../../lib/appManagers/appStateManager\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport { isApple } from \"../../../helpers/userAgent\";\r\nimport Row from \"../../row\";\r\nimport { attachClickEvent } from \"../../../helpers/dom\";\r\nimport AppBackgroundTab from \"./background\";\r\nimport { LangPackKey, _i18n } from \"../../../lib/langPack\";\r\n\r\nexport class RangeSettingSelector {\r\n public container: HTMLDivElement;\r\n private range: RangeSelector;\r\n\r\n public onChange: (value: number) => void;\r\n\r\n constructor(name: LangPackKey, step: number, initialValue: number, minValue: number, maxValue: number) {\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 = document.createElement('div');\r\n valueDiv.classList.add(BASE_CLASS + '-value');\r\n valueDiv.innerHTML = '' + initialValue;\r\n\r\n details.append(nameDiv, valueDiv);\r\n\r\n this.range = new RangeSelector(step, initialValue, minValue, maxValue);\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 //console.log('font size scrub:', value);\r\n valueDiv.innerText = '' + value;\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 SliderSuperTab {\r\n init() {\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 enterRow = new Row({\r\n radioField: new RadioField({\r\n langKey: 'General.SendShortcut.Enter', \r\n name: 'send-shortcut', \r\n value: 'enter', \r\n stateKey: 'settings.sendShortcut'\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: 'send-shortcut',\r\n value: 'ctrlEnter', \r\n stateKey: 'settings.sendShortcut'\r\n }),\r\n subtitleLangKey: 'General.SendShortcut.NewLine.Enter'\r\n });\r\n _i18n(ctrlEnterRow.radioField.main, 'General.SendShortcut.CtrlEnter', [isApple ? '⌘' : 'Ctrl']);\r\n \r\n form.append(enterRow.container, ctrlEnterRow.container);\r\n container.append(form);\r\n }\r\n\r\n {\r\n const container = section('AutoDownloadMedia');\r\n //container.classList.add('sidebar-left-section-disabled');\r\n\r\n const contactsCheckboxField = new CheckboxField({\r\n text: 'AutodownloadContacts', \r\n name: 'contacts',\r\n stateKey: 'settings.autoDownload.contacts',\r\n withRipple: true\r\n });\r\n const privateCheckboxField = new CheckboxField({\r\n text: 'AutodownloadPrivateChats', \r\n name: 'private',\r\n stateKey: 'settings.autoDownload.private',\r\n withRipple: true\r\n });\r\n const groupsCheckboxField = new CheckboxField({\r\n text: 'AutodownloadGroupChats', \r\n name: 'groups',\r\n stateKey: 'settings.autoDownload.groups',\r\n withRipple: true\r\n });\r\n const channelsCheckboxField = new CheckboxField({\r\n text: 'AutodownloadChannels', \r\n name: 'channels',\r\n stateKey: 'settings.autoDownload.channels',\r\n withRipple: true\r\n });\r\n\r\n container.append(contactsCheckboxField.label, privateCheckboxField.label, groupsCheckboxField.label, channelsCheckboxField.label);\r\n }\r\n\r\n {\r\n const container = section('General.AutoplayMedia');\r\n //container.classList.add('sidebar-left-section-disabled');\r\n\r\n const gifsCheckboxField = new CheckboxField({\r\n text: 'AutoplayGIF', \r\n name: 'gifs', \r\n stateKey: 'settings.autoPlay.gifs',\r\n withRipple: true\r\n });\r\n const videosCheckboxField = new CheckboxField({\r\n text: 'AutoplayVideo', \r\n name: 'videos', \r\n stateKey: 'settings.autoPlay.videos',\r\n withRipple: true\r\n });\r\n\r\n container.append(gifsCheckboxField.label, videosCheckboxField.label);\r\n }\r\n \r\n {\r\n const container = section('Telegram.InstalledStickerPacksController');\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 container.append(suggestCheckboxField.label, loopCheckboxField.label);\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 { attachClickEvent } from \"../../../helpers/dom\";\r\nimport EditPeer from \"../../editPeer\";\r\nimport { UsernameInputField } from \"../../usernameInputField\";\r\nimport { i18n, i18n_ } from \"../../../lib/langPack\";\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 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 this.scrollable.append(inputWrapper, caption);\r\n }\r\n\r\n this.scrollable.append(document.createElement('hr'));\r\n\r\n this.editPeer = new EditPeer({\r\n peerId: appUsersManager.getSelf().id,\r\n inputFields,\r\n listenerSetter: this.listenerSetter\r\n });\r\n this.content.append(this.editPeer.nextBtn);\r\n this.scrollable.prepend(this.editPeer.avatarEdit.container);\r\n\r\n {\r\n const h2 = document.createElement('div');\r\n h2.classList.add('sidebar-left-h2');\r\n i18n_({element: h2, key: 'EditAccount.Username'});\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 peerId: 0,\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 = document.createElement('div');\r\n caption.classList.add('caption');\r\n caption.append(i18n('EditProfile.Username.Help'));\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 this.scrollable.append(h2, inputWrapper, caption);\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.isValid() && this.usernameInputField.input.classList.contains('valid')) {\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 { copy } from \"../../../helpers/object\";\r\nimport ButtonIcon from \"../../buttonIcon\";\r\nimport CheckboxField from \"../../checkboxField\";\r\nimport Button from \"../../button\";\r\nimport AppEditFolderTab from \"./editFolder\";\r\nimport { 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\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<number>>;\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 peers: number[] = [];\r\n for(const key of selected) {\r\n if(typeof(key) === 'number') {\r\n peers.push(key);\r\n } else {\r\n // @ts-ignore\r\n this.filter.pFlags[key] = true;\r\n }\r\n }\r\n\r\n if(this.type === 'included') {\r\n this.filter.pinned_peers = this.filter.pinned_peers.filter(peerId => {\r\n return peers.includes(peerId); // * because I have pinned peer in include_peers too\r\n /* const index = peers.indexOf(peerId);\r\n if(index !== -1) {\r\n peers.splice(index, 1);\r\n return true;\r\n } else {\r\n return false;\r\n } */\r\n });\r\n } else {\r\n this.filter.pinned_peers = this.filter.pinned_peers.filter(peerId => {\r\n return !peers.includes(peerId);\r\n });\r\n }\r\n\r\n const other = this.type === 'included' ? 'exclude_peers' : 'include_peers';\r\n this.filter[other] = this.filter[other].filter(peerId => {\r\n return !peers.includes(peerId);\r\n });\r\n \r\n this.filter[this.type === 'included' ? 'include_peers' : 'exclude_peers'] = peers;\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.getFolder(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: number[]) => {\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 span.innerHTML = 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 fragment = document.createDocumentFragment();\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 const chatsSection = new SettingSection({\r\n name: 'FilterChats'\r\n });\r\n\r\n fragment.append(categoriesSection.container, chatsSection.container);\r\n\r\n /////////////////\r\n\r\n const selectedPeers = (this.type === 'included' ? filter.include_peers : filter.exclude_peers).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 });\r\n this.selector.selected = new Set(selectedPeers);\r\n\r\n const _add = this.selector.add.bind(this.selector);\r\n this.selector.add = (peerId, title, scroll) => {\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 const parent = this.selector.list.parentElement;\r\n chatsSection.content.append(this.selector.list);\r\n parent.append(fragment);\r\n\r\n this.selector.addInitial(selectedPeers);\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 { deepEqual, copy } from \"../../../helpers/object\";\r\nimport appDialogsManager from \"../../../lib/appManagers/appDialogsManager\";\r\nimport { MyDialogFilter as DialogFilter } from \"../../../lib/storages/filters\";\r\nimport lottieLoader, { RLottiePlayer } from \"../../../lib/lottieLoader\";\r\nimport { ripple } from \"../../ripple\";\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\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 include_peers: SettingSection;\r\n private exclude_peers: 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: Promise<void>;\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 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 };\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 inputWrapper = document.createElement('div');\r\n inputWrapper.classList.add('input-wrapper');\r\n \r\n this.nameInputField = new InputField({\r\n label: 'FilterNameInputLabel',\r\n maxLength: MAX_FOLDER_NAME_LENGTH\r\n });\r\n\r\n inputWrapper.append(this.nameInputField.container);\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.include_peers = 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.exclude_peers = 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, inputWrapper, this.include_peers.container, this.exclude_peers.container);\r\n\r\n const includedFlagsContainer = this.include_peers.container.querySelector('.folder-categories');\r\n const excludedFlagsContainer = this.exclude_peers.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 return this.loadAnimationPromise = lottieLoader.loadAnimationFromURL({\r\n container: this.stickerContainer,\r\n loop: false,\r\n autoplay: false,\r\n width: 86,\r\n height: 86\r\n }, 'assets/img/Folders_2.tgs').then(player => {\r\n this.animation = player;\r\n\r\n return lottieLoader.waitForFirstFrame(player);\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 = 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 (['include_peers', 'exclude_peers'] as ['include_peers', 'exclude_peers']).forEach(key => {\r\n const section = this[key];\r\n const ul = appDialogsManager.createChatList();\r\n\r\n const peers = filter[key].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\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 // cleanup\r\n Array.from(this.container.querySelectorAll('ul, .load-more')).forEach(el => el.remove());\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 const ret = super.open();\r\n \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 }, true);\r\n this.type = 'create';\r\n this.onCreateOpen();\r\n } else {\r\n this.setFilter(filter, true);\r\n this.type = 'edit';\r\n this.onEditOpen();\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 { SliderSuperTab } from \"../../slider\";\r\nimport lottieLoader, { RLottiePlayer } from \"../../../lib/lottieLoader\";\r\nimport { RichTextProcessor } from \"../../../lib/richtextprocessor\";\r\nimport { attachClickEvent, cancelEvent, positionElementByIndex } from \"../../../helpers/dom\";\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 type { BroadcastEvents } 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\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]: HTMLElement} = {};\r\n private loadAnimationPromise: Promise<void>;\r\n\r\n private renderFolder(dialogFilter: DialogFilterSuggested | DialogFilter | MyDialogFilter, container?: HTMLElement, div?: HTMLElement) {\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 d.push(i18n(k));\r\n } else {\r\n const folder = appMessagesManager.dialogsStorage.getFolder(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 if(!div) {\r\n const 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 const arr = join(d);\r\n arr.forEach(el => {\r\n row.subtitle.append(el);\r\n });\r\n }\r\n \r\n div = row.container;\r\n\r\n if(dialogFilter._ === 'dialogFilter') {\r\n const filterId = filter.id;\r\n if(!this.filtersRendered.hasOwnProperty(filter.id)) {\r\n attachClickEvent(div, () => {\r\n new AppEditFolderTab(this.slider).open(appMessagesManager.filtersStorage.filters[filterId]);\r\n }, {listenerSetter: this.listenerSetter});\r\n }\r\n\r\n this.filtersRendered[filter.id] = div;\r\n }\r\n }\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-create-folder', {\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', (e) => {\r\n const filter = e;\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', (e) => {\r\n const filter = e;\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].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', (e: BroadcastEvents['filter_order']) => {\r\n const order = e;\r\n order.forEach((filterId, idx) => {\r\n const div = this.filtersRendered[filterId];\r\n positionElementByIndex(div, div.parentElement, idx + 1); // ! + 1 due to header \r\n });\r\n });\r\n\r\n this.getSuggestedFilters();\r\n\r\n return this.loadAnimationPromise = lottieLoader.loadAnimationFromURL({\r\n container: this.stickerContainer,\r\n loop: false,\r\n autoplay: false,\r\n width: 86,\r\n height: 86\r\n }, 'assets/img/Folders_1.tgs').then(player => {\r\n this.animation = player;\r\n\r\n return lottieLoader.waitForFirstFrame(player);\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 getSuggestedFilters() {\r\n 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 appMessagesManager.filtersStorage.createDialogFilter(filter.filter as any).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, PeerNotifySettings, Update } from \"../../../layer\";\r\nimport appNotificationsManager from \"../../../lib/appManagers/appNotificationsManager\";\r\nimport { SliderSuperTabEventable } from \"../../sliderTab\";\r\nimport { copy } from \"../../../helpers/object\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport { convertKeyToInputKey } from \"../../../helpers/string\";\r\nimport { LangPackKey } from \"../../../lib/langPack\";\r\n\r\ntype InputNotifyKey = Exclude<InputNotifyPeer['_'], 'inputNotifyPeer'>;\r\n\r\nexport default class AppNotificationsTab extends SliderSuperTabEventable {\r\n protected init() {\r\n this.container.classList.add('notifications-container');\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: 'Notifications.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 ? 2147483647 : 0;\r\n inputSettings.show_previews = showPreviews;\r\n\r\n appNotificationsManager.updateNotifySettings(inputNotifyPeer, inputSettings);\r\n }, 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: 'Checkbox.Enabled',\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 }, 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.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","/*\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 AvatarElement from \"../../avatar\";\r\nimport apiManager from \"../../../lib/mtproto/mtprotoworker\";\r\nimport appUsersManager from \"../../../lib/appManagers/appUsersManager\";\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 PeerTitle from \"../../peerTitle\";\r\nimport AppLanguageTab from \"./language\";\r\nimport lottieLoader from \"../../../lib/lottieLoader\";\r\n//import AppMediaViewer from \"../../appMediaViewerNew\";\r\n\r\nexport default class AppSettingsTab extends SliderSuperTab {\r\n private avatarElem: AvatarElement;\r\n private nameDiv: HTMLElement;\r\n private phoneDiv: HTMLElement;\r\n\r\n private buttons: {\r\n edit: HTMLButtonElement,\r\n folders: HTMLButtonElement,\r\n general: HTMLButtonElement,\r\n notifications: HTMLButtonElement,\r\n privacy: HTMLButtonElement,\r\n language: HTMLButtonElement\r\n } = {} as any;\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 apiManager.logOut();\r\n }\r\n }]);\r\n\r\n this.header.append(btnMenu);\r\n\r\n this.avatarElem = new AvatarElement();\r\n this.avatarElem.setAttribute('clickable', '');\r\n this.avatarElem.classList.add('profile-avatar', 'avatar-120');\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 this.nameDiv = document.createElement('div');\r\n this.nameDiv.classList.add('profile-name');\r\n\r\n this.phoneDiv = document.createElement('div');\r\n this.phoneDiv.classList.add('profile-subtitle');\r\n\r\n const buttonsDiv = document.createElement('div');\r\n buttonsDiv.classList.add('profile-buttons');\r\n\r\n const className = 'profile-button btn-primary btn-transparent';\r\n buttonsDiv.append(this.buttons.edit = Button(className, {icon: 'edit', text: 'EditAccount.Title'}));\r\n buttonsDiv.append(this.buttons.folders = Button(className, {icon: 'folder', text: 'AccountSettings.Filters'}));\r\n buttonsDiv.append(this.buttons.general = Button(className, {icon: 'settings', text: 'Telegram.GeneralSettingsViewController'}));\r\n buttonsDiv.append(this.buttons.notifications = Button(className, {icon: 'unmute', text: 'AccountSettings.Notifications'}));\r\n buttonsDiv.append(this.buttons.privacy = Button(className, {icon: 'lock', text: 'AccountSettings.PrivacyAndSecurity'}));\r\n buttonsDiv.append(this.buttons.language = Button(className, {icon: 'language', text: 'AccountSettings.Language'}));\r\n \r\n this.scrollable.append(this.avatarElem, this.nameDiv, this.phoneDiv, buttonsDiv);\r\n this.scrollable.container.classList.add('profile-content-wrapper');\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 this.buttons.folders.addEventListener('click', () => {\r\n new AppChatFoldersTab(this.slider).open();\r\n });\r\n\r\n this.buttons.general.addEventListener('click', () => {\r\n new AppGeneralSettingsTab(this.slider).open();\r\n });\r\n\r\n this.buttons.notifications.addEventListener('click', () => {\r\n new AppNotificationsTab(this.slider).open();\r\n });\r\n\r\n this.buttons.privacy.addEventListener('click', () => {\r\n new AppPrivacyAndSecurityTab(this.slider).open();\r\n });\r\n\r\n this.buttons.language.addEventListener('click', () => {\r\n new AppLanguageTab(this.slider).open();\r\n });\r\n\r\n lottieLoader.loadLottieWorkers();\r\n\r\n this.fillElements();\r\n }\r\n\r\n public fillElements() {\r\n let user = appUsersManager.getSelf();\r\n this.avatarElem.setAttribute('peer', '' + user.id);\r\n\r\n this.nameDiv.append(new PeerTitle({peerId: user.id}).element);\r\n this.phoneDiv.innerHTML = user.rPhone || '';\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 from \"..\";\r\nimport { InputFile } from \"../../../layer\";\r\nimport appChatsManager from \"../../../lib/appManagers/appChatsManager\";\r\nimport Button from \"../../button\";\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\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 inputWrapper = document.createElement('div');\r\n inputWrapper.classList.add('input-wrapper');\r\n\r\n this.channelNameInputField = new InputField({\r\n label: 'Channel.ChannelNameHolder',\r\n maxLength: 128\r\n });\r\n\r\n this.channelDescriptionInputField = new InputField({\r\n label: 'Channel.DescriptionPlaceholder',\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 const caption = document.createElement('div');\r\n caption.classList.add('caption');\r\n _i18n(caption, 'Channel.DescriptionHolderDescrpiton');\r\n\r\n this.nextBtn = Button('btn-corner btn-circle', {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(title, about).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 peerId: channelId,\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(Math.abs(channelId), peerIds);\r\n }\r\n });\r\n });\r\n });\r\n\r\n this.content.append(this.nextBtn);\r\n this.scrollable.append(this.avatarEdit.container, inputWrapper, caption);\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","/*\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 appDialogsManager from \"../../../lib/appManagers/appDialogsManager\";\r\nimport appUsersManager from \"../../../lib/appManagers/appUsersManager\";\r\nimport appPhotosManager from \"../../../lib/appManagers/appPhotosManager\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport InputSearch from \"../../inputSearch\";\r\nimport { canFocus } from \"../../../helpers/dom\";\r\nimport { isMobile } from \"../../../helpers/userAgent\";\r\n\r\n// TODO: поиск по людям глобальный, если не нашло в контактах никого\r\n\r\nexport default class AppContactsTab extends SliderSuperTab {\r\n private list: HTMLUListElement;\r\n private promise: Promise<void>;\r\n\r\n private inputSearch: InputSearch;\r\n private alive = true;\r\n \r\n init() {\r\n this.container.id = 'contacts-container';\r\n\r\n this.list = appDialogsManager.createChatList(/* {avatarSize: 48, handheldsSize: 66} */);\r\n this.list.id = 'contacts';\r\n this.list.classList.add('contacts-container');\r\n\r\n appDialogsManager.setListClickListener(this.list, () => {\r\n (this.container.querySelector('.sidebar-close-button') as HTMLElement).click();\r\n }, undefined, true);\r\n\r\n this.inputSearch = new InputSearch('Search', (value) => {\r\n this.list.innerHTML = '';\r\n this.openContacts(value);\r\n });\r\n\r\n this.title.replaceWith(this.inputSearch.container);\r\n\r\n this.scrollable.append(this.list);\r\n\r\n // preload contacts\r\n // appUsersManager.getContacts();\r\n }\r\n\r\n onClose() {\r\n this.alive = false;\r\n /* // need to clear, and left 1 page for smooth slide\r\n let pageCount = appPhotosManager.windowH / 72 * 1.25 | 0;\r\n (Array.from(this.list.children) as HTMLElement[]).slice(pageCount).forEach(el => el.remove()); */\r\n }\r\n\r\n onOpenAfterTimeout() {\r\n if(isMobile || !canFocus(true)) return;\r\n this.inputSearch.input.focus();\r\n }\r\n\r\n public openContacts(query?: string) {\r\n if(this.init) {\r\n this.init();\r\n this.init = null;\r\n }\r\n\r\n if(this.promise) return this.promise;\r\n this.scrollable.onScrolledBottom = null;\r\n\r\n this.promise = appUsersManager.getContacts(query).then(_contacts => {\r\n this.promise = null;\r\n\r\n if(!this.alive) {\r\n //console.warn('user closed contacts before it\\'s loaded');\r\n return;\r\n }\r\n\r\n const contacts = [..._contacts];\r\n\r\n if(!query) {\r\n contacts.findAndSplice(u => u === rootScope.myId);\r\n }\r\n /* if(query && 'saved messages'.includes(query.toLowerCase())) {\r\n contacts.unshift(rootScope.myID);\r\n } */\r\n\r\n let sorted = contacts\r\n .map(userId => {\r\n let user = appUsersManager.getUser(userId);\r\n let status = appUsersManager.getUserStatusForSort(user.status);\r\n\r\n return {user, status};\r\n })\r\n .sort((a, b) => b.status - a.status);\r\n\r\n let renderPage = () => {\r\n let pageCount = appPhotosManager.windowH / 72 * 1.25 | 0;\r\n let arr = sorted.splice(0, pageCount); // надо splice!\r\n\r\n arr.forEach(({user}) => {\r\n let {dialog, dom} = appDialogsManager.addDialogNew({\r\n dialog: user.id,\r\n container: this.list,\r\n drawStatus: false,\r\n avatarSize: 48,\r\n autonomous: true\r\n });\r\n \r\n let status = appUsersManager.getUserStatusString(user.id);\r\n dom.lastMessageSpan.append(status);\r\n });\r\n\r\n if(!sorted.length) renderPage = undefined;\r\n };\r\n\r\n renderPage();\r\n this.scrollable.onScrolledBottom = () => {\r\n if(renderPage) {\r\n renderPage();\r\n } else {\r\n this.scrollable.onScrolledBottom = null;\r\n }\r\n };\r\n });\r\n }\r\n\r\n public open() {\r\n this.openContacts();\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 { SliderSuperTab } from \"../../slider\";\r\n\r\nexport default class AppArchivedTab extends SliderSuperTab {\r\n public static filterId = 1;\r\n public loadedAll: boolean;\r\n public loadDialogsPromise: Promise<any>;\r\n public wasFilterId: number;\r\n\r\n init() {\r\n this.container.id = 'chats-archived-container';\r\n this.setTitle('ArchivedChats');\r\n\r\n //this.scrollable = new Scrollable(this.container, 'CLA', 500);\r\n const chatList = appDialogsManager.chatLists[AppArchivedTab.filterId];\r\n this.scrollable.append(chatList);\r\n this.scrollable.container.addEventListener('scroll', appDialogsManager.onChatsRegularScroll);\r\n this.scrollable.setVirtualContainer(chatList);\r\n this.scrollable.onScrolledBottom = appDialogsManager.onChatsScroll;\r\n ///this.scroll.attachSentinels();\r\n\r\n this.listenerSetter.add(window, 'resize', () => {\r\n setTimeout(appDialogsManager.scroll.checkForTriggers, 0);\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.wasFilterId = appDialogsManager.filterId;\r\n appDialogsManager.scroll = this.scrollable;\r\n appDialogsManager.filterId = AppArchivedTab.filterId;\r\n appDialogsManager.onTabChange();\r\n }\r\n\r\n // вообще, так делать нельзя, но нет времени чтобы переделать главный чатлист на слайд...\r\n onOpenAfterTimeout() {\r\n appDialogsManager.chatLists[this.wasFilterId].innerHTML = '';\r\n }\r\n\r\n onClose() {\r\n appDialogsManager.scroll = appDialogsManager._scroll;\r\n appDialogsManager.filterId = this.wasFilterId;\r\n appDialogsManager.onTabChange();\r\n }\r\n\r\n onCloseAfterTimeout() {\r\n appDialogsManager.chatLists[AppArchivedTab.filterId].innerHTML = '';\r\n return super.onCloseAfterTimeout();\r\n }\r\n}\r\n","//import { logger } from \"../polyfill\";\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 { formatNumber } from \"../../helpers/number\";\r\nimport appImManager from \"../../lib/appManagers/appImManager\";\r\nimport appPeersManager from \"../../lib/appManagers/appPeersManager\";\r\nimport appStateManager from \"../../lib/appManagers/appStateManager\";\r\nimport appUsersManager from \"../../lib/appManagers/appUsersManager\";\r\nimport rootScope from \"../../lib/rootScope\";\r\nimport { SearchGroup } from \"../appSearch\";\r\nimport \"../avatar\";\r\nimport Scrollable, { ScrollableX } from \"../scrollable\";\r\nimport InputSearch from \"../inputSearch\";\r\nimport SidebarSlider from \"../slider\";\r\nimport { TransitionSlider } from \"../transition\";\r\nimport AppNewGroupTab from \"./tabs/newGroup\";\r\nimport appMessagesManager from \"../../lib/appManagers/appMessagesManager\";\r\nimport AppSearchSuper from \"../appSearchSuper.\";\r\nimport { DateData, fillTipDates } from \"../../helpers/date\";\r\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\r\nimport AppSettingsTab from \"./tabs/settings\";\r\nimport AppNewChannelTab from \"./tabs/newChannel\";\r\nimport AppContactsTab from \"./tabs/contacts\";\r\nimport AppArchivedTab from \"./tabs/archivedTab\";\r\nimport AppAddMembersTab from \"./tabs/addMembers\";\r\nimport { i18n_, LangPackKey } from \"../../lib/langPack\";\r\nimport ButtonMenu, { ButtonMenuItemOptions } from \"../buttonMenu\";\r\nimport CheckboxField from \"../checkboxField\";\r\nimport { isMobileSafari } from \"../../helpers/userAgent\";\r\nimport appNavigationController from \"../appNavigationController\";\r\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\r\nimport findUpTag from \"../../helpers/dom/findUpTag\";\r\nimport PeerTitle from \"../peerTitle\";\r\nimport { replaceContent } from \"../../helpers/dom\";\r\nimport App from \"../../config/app\";\r\nimport ButtonMenuToggle from \"../buttonMenuToggle\";\r\n\r\nexport const LEFT_COLUMN_ACTIVE_CLASSNAME = 'is-left-column-shown';\r\n\r\nexport class AppSidebarLeft extends SidebarSlider {\r\n private toolsBtn: HTMLButtonElement;\r\n private backBtn: HTMLButtonElement;\r\n //private searchInput = document.getElementById('global-search') as HTMLInputElement;\r\n private inputSearch: InputSearch;\r\n \r\n public archivedCount: HTMLSpanElement;\r\n\r\n private newBtnMenu: HTMLElement;\r\n\r\n //private log = logger('SL');\r\n\r\n private searchGroups: {[k in 'contacts' | 'globalContacts' | 'messages' | 'people' | 'recent']: SearchGroup} = {} as any;\r\n searchSuper: AppSearchSuper;\r\n\r\n constructor() {\r\n super({\r\n sidebarEl: document.getElementById('column-left') as HTMLDivElement,\r\n navigationType: 'left'\r\n });\r\n\r\n //this._selectTab(0); // make first tab as default\r\n\r\n this.inputSearch = new InputSearch('Search');\r\n const sidebarHeader = this.sidebarEl.querySelector('.item-main .sidebar-header');\r\n sidebarHeader.append(this.inputSearch.container);\r\n\r\n const onNewGroupClick = () => {\r\n new AppAddMembersTab(this).open({\r\n peerId: 0,\r\n type: 'chat',\r\n skippable: false,\r\n takeOut: (peerIds) => {\r\n new AppNewGroupTab(this).open(peerIds);\r\n },\r\n title: 'GroupAddMembers',\r\n placeholder: 'SendMessageTo'\r\n });\r\n };\r\n\r\n const onContactsClick = () => {\r\n new AppContactsTab(this).open();\r\n };\r\n\r\n //this.toolsBtn = this.sidebarEl.querySelector('.sidebar-tools-button') as HTMLButtonElement;\r\n this.backBtn = this.sidebarEl.querySelector('.sidebar-back-button') as HTMLButtonElement;\r\n\r\n const btnArchive: ButtonMenuItemOptions & {verify?: () => boolean} = {\r\n icon: 'archive',\r\n text: 'ArchivedChats',\r\n onClick: () => {\r\n new AppArchivedTab(this).open();\r\n },\r\n verify: () => {\r\n const folder = appMessagesManager.dialogsStorage.getFolder(1);\r\n return !!folder.length;\r\n }\r\n };\r\n\r\n const menuButtons: (ButtonMenuItemOptions & {verify?: () => boolean})[] = [{\r\n icon: 'saved',\r\n text: 'SavedMessages',\r\n onClick: () => {\r\n setTimeout(() => { // menu doesn't close if no timeout (lol)\r\n appImManager.setPeer(appImManager.myId);\r\n }, 0);\r\n }\r\n }, btnArchive, {\r\n icon: 'user',\r\n text: 'Contacts',\r\n onClick: onContactsClick\r\n }, {\r\n icon: 'settings',\r\n text: 'Settings',\r\n onClick: () => {\r\n new AppSettingsTab(this).open();\r\n }\r\n }, {\r\n icon: 'darkmode',\r\n text: 'DarkMode',\r\n onClick: () => {\r\n \r\n },\r\n checkboxField: new CheckboxField({\r\n toggle: true,\r\n stateKey: 'settings.nightTheme',\r\n })\r\n }, {\r\n icon: 'animations',\r\n text: 'Animations',\r\n onClick: () => {\r\n \r\n },\r\n checkboxField: new CheckboxField({\r\n toggle: true, \r\n checked: true,\r\n stateKey: 'settings.animationsEnabled',\r\n })\r\n }, {\r\n icon: 'help',\r\n text: 'TelegramFeatures',\r\n onClick: () => {\r\n appImManager.openUsername('TelegramTips');\r\n }\r\n }, {\r\n icon: 'bug',\r\n text: 'ReportBug',\r\n onClick: () => {\r\n const a = document.createElement('a');\r\n a.target = '_blank';\r\n a.href = 'https://bugs.telegram.org/?tag_ids=40&sort=time';\r\n document.body.append(a);\r\n a.click();\r\n setTimeout(() => {\r\n a.remove();\r\n }, 0);\r\n }\r\n }];\r\n\r\n this.toolsBtn = ButtonMenuToggle({}, 'bottom-right', menuButtons, (e) => {\r\n menuButtons.forEach(button => {\r\n if(button.verify) {\r\n button.element.classList.toggle('hide', !button.verify());\r\n }\r\n });\r\n });\r\n this.toolsBtn.classList.remove('tgico-more');\r\n this.toolsBtn.classList.add('sidebar-tools-button', 'is-visible');\r\n\r\n this.backBtn.parentElement.insertBefore(this.toolsBtn, this.backBtn);\r\n\r\n const btnMenu = this.toolsBtn.querySelector('.btn-menu') as HTMLElement;\r\n\r\n const btnMenuFooter = document.createElement('div');\r\n btnMenuFooter.classList.add('btn-menu-footer');\r\n const t = document.createElement('span');\r\n t.classList.add('btn-menu-footer-text');\r\n t.innerHTML = 'Telegram WebK alpha ' + App.version;\r\n btnMenuFooter.append(t); \r\n btnMenu.classList.add('has-footer');\r\n btnMenu.append(btnMenuFooter);\r\n\r\n this.newBtnMenu = ButtonMenuToggle({}, 'top-left', [{\r\n icon: 'newchannel',\r\n text: 'NewChannel',\r\n onClick: () => {\r\n new AppNewChannelTab(this).open();\r\n }\r\n }, {\r\n icon: 'newgroup',\r\n text: 'NewGroup',\r\n onClick: onNewGroupClick\r\n }, {\r\n icon: 'newprivate',\r\n text: 'NewPrivateChat',\r\n onClick: onContactsClick\r\n }]);\r\n this.newBtnMenu.className = 'btn-circle rp btn-corner btn-menu-toggle animated-button-icon';\r\n this.newBtnMenu.insertAdjacentHTML('afterbegin', `\r\n <span class=\"tgico tgico-newchat_filled\"></span>\r\n <span class=\"tgico tgico-close\"></span>\r\n `);\r\n this.newBtnMenu.id = 'new-menu';\r\n sidebarHeader.nextElementSibling.append(this.newBtnMenu);\r\n\r\n this.inputSearch.input.addEventListener('focus', () => this.initSearch(), {once: true});\r\n\r\n //parseMenuButtonsTo(this.newButtons, this.newBtnMenu.firstElementChild.children);\r\n\r\n this.archivedCount = document.createElement('span');\r\n this.archivedCount.className = 'archived-count badge badge-24 badge-gray';\r\n\r\n btnArchive.element.append(this.archivedCount);\r\n\r\n rootScope.on('dialogs_archived_unread', (e) => {\r\n this.archivedCount.innerText = '' + formatNumber(e.count, 1);\r\n this.archivedCount.classList.toggle('hide', !e.count);\r\n });\r\n\r\n appUsersManager.getTopPeers();\r\n }\r\n\r\n private initSearch() {\r\n const searchContainer = this.sidebarEl.querySelector('#search-container') as HTMLDivElement;\r\n\r\n const scrollable = new Scrollable(searchContainer);\r\n\r\n const close = () => {\r\n //setTimeout(() => {\r\n this.backBtn.click();\r\n //}, 0);\r\n };\r\n\r\n this.searchGroups = {\r\n contacts: new SearchGroup('Chats', 'contacts', undefined, undefined, undefined, undefined, close),\r\n globalContacts: new SearchGroup('Global Search', 'contacts', undefined, undefined, undefined, undefined, close),\r\n messages: new SearchGroup('Messages', 'messages'),\r\n people: new SearchGroup('', 'contacts', true, 'search-group-people', true, false, close),\r\n recent: new SearchGroup('Recent', 'contacts', true, 'search-group-recent', true, true, close)\r\n };\r\n\r\n const searchSuper = this.searchSuper = new AppSearchSuper({\r\n mediaTabs: [{\r\n inputFilter: 'inputMessagesFilterEmpty',\r\n name: 'FilterChats',\r\n type: 'chats'\r\n }, {\r\n inputFilter: 'inputMessagesFilterPhotoVideo',\r\n name: 'SharedMediaTab2',\r\n type: 'media'\r\n }, {\r\n inputFilter: 'inputMessagesFilterUrl',\r\n name: 'SharedLinksTab2',\r\n type: 'links'\r\n }, {\r\n inputFilter: 'inputMessagesFilterDocument',\r\n name: 'SharedFilesTab2',\r\n type: 'files'\r\n }, {\r\n inputFilter: 'inputMessagesFilterMusic',\r\n name: 'SharedMusicTab2',\r\n type: 'music'\r\n }, {\r\n inputFilter: 'inputMessagesFilterVoice',\r\n name: 'SharedVoiceTab2',\r\n type: 'voice'\r\n }], \r\n scrollable, \r\n searchGroups: this.searchGroups, \r\n asChatList: true,\r\n hideEmptyTabs: false,\r\n showSender: true\r\n });\r\n\r\n searchContainer.prepend(searchSuper.nav.parentElement.parentElement);\r\n scrollable.container.append(searchSuper.container);\r\n\r\n const resetSearch = () => {\r\n searchSuper.setQuery({\r\n peerId: 0, \r\n folderId: 0\r\n });\r\n searchSuper.selectTab(0);\r\n searchSuper.load(true); \r\n };\r\n\r\n resetSearch();\r\n\r\n let pickedElements: HTMLElement[] = [];\r\n let selectedPeerId = 0;\r\n let selectedMinDate = 0;\r\n let selectedMaxDate = 0;\r\n const updatePicked = () => {\r\n //(this.inputSearch.input as HTMLInputElement).placeholder = pickedElements.length ? 'Search' : 'Telegram Search';\r\n this.inputSearch.container.classList.toggle('is-picked-twice', pickedElements.length === 2);\r\n this.inputSearch.container.classList.toggle('is-picked', !!pickedElements.length);\r\n\r\n if(pickedElements.length) {\r\n this.inputSearch.input.style.setProperty('--paddingLeft', (pickedElements[pickedElements.length - 1].getBoundingClientRect().right - this.inputSearch.input.getBoundingClientRect().left) + 'px');\r\n } else {\r\n this.inputSearch.input.style.removeProperty('--paddingLeft');\r\n }\r\n };\r\n\r\n const helper = document.createElement('div');\r\n helper.classList.add('search-helper');\r\n helper.addEventListener('click', (e) => {\r\n const target = findUpClassName(e.target, 'selector-user');\r\n if(!target) {\r\n return;\r\n }\r\n\r\n const key = target.dataset.key;\r\n if(key.indexOf('date_') === 0) {\r\n const [_, minDate, maxDate] = key.split('_');\r\n selectedMinDate = +minDate;\r\n selectedMaxDate = +maxDate;\r\n } else {\r\n selectedPeerId = +key;\r\n }\r\n\r\n target.addEventListener('click', () => {\r\n unselectEntity(target);\r\n });\r\n\r\n this.inputSearch.container.append(target);\r\n this.inputSearch.onChange(this.inputSearch.value = '');\r\n pickedElements.push(target);\r\n updatePicked();\r\n });\r\n\r\n searchSuper.nav.parentElement.append(helper);\r\n\r\n const renderEntity = (peerId: any, title?: string | HTMLElement) => {\r\n const div = document.createElement('div');\r\n div.classList.add('selector-user'/* , 'scale-in' */);\r\n\r\n const avatarEl = document.createElement('avatar-element');\r\n avatarEl.classList.add('selector-user-avatar', 'tgico');\r\n avatarEl.setAttribute('dialog', '1');\r\n avatarEl.classList.add('avatar-30');\r\n\r\n div.dataset.key = '' + peerId;\r\n if(typeof(peerId) === 'number') {\r\n if(title === undefined) {\r\n title = new PeerTitle({peerId, onlyFirstName: true}).element;\r\n }\r\n\r\n avatarEl.setAttribute('peer', '' + peerId);\r\n } else {\r\n avatarEl.classList.add('tgico-calendarfilter');\r\n }\r\n\r\n if(title) {\r\n if(typeof(title) === 'string') {\r\n div.innerHTML = title;\r\n } else {\r\n replaceContent(div, title);\r\n div.append(title);\r\n }\r\n }\r\n\r\n div.insertAdjacentElement('afterbegin', avatarEl);\r\n\r\n return div;\r\n };\r\n\r\n const unselectEntity = (target: HTMLElement) => {\r\n const key = target.dataset.key;\r\n if(key.indexOf('date_') === 0) {\r\n selectedMinDate = selectedMaxDate = 0;\r\n } else {\r\n selectedPeerId = 0;\r\n }\r\n \r\n target.remove();\r\n pickedElements.findAndSplice(t => t === target);\r\n\r\n setTimeout(() => {\r\n updatePicked();\r\n this.inputSearch.onChange(this.inputSearch.value);\r\n }, 0);\r\n };\r\n\r\n this.inputSearch.onClear = () => {\r\n pickedElements.forEach(el => {\r\n unselectEntity(el);\r\n });\r\n };\r\n\r\n this.inputSearch.onChange = (value) => {\r\n searchSuper.cleanupHTML();\r\n searchSuper.setQuery({\r\n peerId: selectedPeerId, \r\n folderId: selectedPeerId ? undefined : 0,\r\n query: value,\r\n minDate: selectedMinDate,\r\n maxDate: selectedMaxDate\r\n });\r\n searchSuper.load(true);\r\n\r\n helper.innerHTML = '';\r\n searchSuper.nav.classList.remove('hide');\r\n if(!value) {\r\n }\r\n \r\n if(!selectedPeerId && value.trim()) {\r\n const middleware = searchSuper.middleware.get();\r\n Promise.all([\r\n appMessagesManager.getConversationsAll(value).then(dialogs => dialogs.map(d => d.peerId)),\r\n appUsersManager.getContacts(value, true)\r\n ]).then(results => {\r\n if(!middleware()) return;\r\n const peerIds = new Set(results[0].concat(results[1]));\r\n \r\n peerIds.forEach(peerId => {\r\n helper.append(renderEntity(peerId));\r\n });\r\n \r\n searchSuper.nav.classList.toggle('hide', !!helper.innerHTML);\r\n //console.log('got peerIds by value:', value, [...peerIds]);\r\n });\r\n }\r\n \r\n if(!selectedMinDate && value.trim()) {\r\n const dates: DateData[] = [];\r\n fillTipDates(value, dates);\r\n dates.forEach(dateData => {\r\n helper.append(renderEntity('date_' + dateData.minDate + '_' + dateData.maxDate, dateData.title));\r\n });\r\n\r\n searchSuper.nav.classList.toggle('hide', !!helper.innerHTML);\r\n }\r\n };\r\n\r\n searchSuper.tabs.inputMessagesFilterEmpty.addEventListener('mousedown', (e) => {\r\n const target = findUpTag(e.target, 'LI') as HTMLElement;\r\n if(!target) {\r\n return;\r\n }\r\n\r\n const searchGroup = findUpClassName(target, 'search-group');\r\n if(!searchGroup || searchGroup.classList.contains('search-group-recent') || searchGroup.classList.contains('search-group-people')) {\r\n return;\r\n }\r\n\r\n const peerId = +target.getAttribute('data-peer-id');\r\n appStateManager.getState().then(state => {\r\n const recentSearch = state.recentSearch || [];\r\n if(recentSearch[0] !== peerId) {\r\n recentSearch.findAndSplice(p => p === peerId);\r\n recentSearch.unshift(peerId);\r\n if(recentSearch.length > 20) {\r\n recentSearch.length = 20;\r\n }\r\n \r\n appStateManager.pushToState('recentSearch', recentSearch);\r\n for(const peerId of recentSearch) {\r\n appStateManager.setPeer(peerId, appPeersManager.getPeer(peerId));\r\n }\r\n }\r\n });\r\n }, {capture: true});\r\n\r\n let peopleContainer = document.createElement('div');\r\n peopleContainer.classList.add('search-group-scrollable');\r\n peopleContainer.append(this.searchGroups.people.list);\r\n this.searchGroups.people.container.append(peopleContainer);\r\n let peopleScrollable = new ScrollableX(peopleContainer);\r\n\r\n let hideNewBtnMenuTimeout: number;\r\n //const transition = Transition.bind(null, searchContainer.parentElement, 150);\r\n const transition = TransitionSlider(searchContainer.parentElement, 'zoom-fade', 150, (id) => {\r\n if(hideNewBtnMenuTimeout) clearTimeout(hideNewBtnMenuTimeout);\r\n\r\n if(id === 0) {\r\n searchSuper.selectTab(0, false);\r\n this.inputSearch.onClearClick();\r\n hideNewBtnMenuTimeout = window.setTimeout(() => {\r\n hideNewBtnMenuTimeout = 0;\r\n this.newBtnMenu.classList.remove('is-hidden');\r\n }, 150);\r\n }\r\n });\r\n\r\n transition(0);\r\n\r\n const activeClassName = 'is-visible';\r\n const onFocus = () => {\r\n this.toolsBtn.classList.remove(activeClassName);\r\n this.backBtn.classList.add(activeClassName);\r\n this.newBtnMenu.classList.add('is-hidden');\r\n this.toolsBtn.parentElement.firstElementChild.classList.toggle('state-back', true);\r\n\r\n if(!isMobileSafari && !appNavigationController.findItemByType('global-search')) {\r\n appNavigationController.pushItem({\r\n onPop: () => {\r\n close();\r\n },\r\n type: 'global-search'\r\n });\r\n }\r\n\r\n transition(1);\r\n };\r\n\r\n this.inputSearch.input.addEventListener('focus', onFocus);\r\n onFocus();\r\n\r\n this.backBtn.addEventListener('click', (e) => {\r\n this.toolsBtn.classList.add(activeClassName);\r\n this.backBtn.classList.remove(activeClassName);\r\n this.toolsBtn.parentElement.firstElementChild.classList.toggle('state-back', false);\r\n\r\n appNavigationController.removeByType('global-search');\r\n\r\n transition(0);\r\n });\r\n\r\n const clearRecentSearchBtn = document.createElement('button');\r\n clearRecentSearchBtn.classList.add('btn-icon', 'tgico-close');\r\n this.searchGroups.recent.nameEl.append(clearRecentSearchBtn);\r\n clearRecentSearchBtn.addEventListener('click', () => {\r\n this.searchGroups.recent.clear();\r\n appStateManager.pushToState('recentSearch', []);\r\n });\r\n }\r\n}\r\n\r\nexport class SettingSection {\r\n public container: HTMLElement;\r\n public content: HTMLElement;\r\n public title: HTMLElement;\r\n public caption: HTMLElement;\r\n\r\n constructor(options: {\r\n name?: LangPackKey, \r\n caption?: LangPackKey | true,\r\n noDelimiter?: boolean\r\n }) {\r\n this.container = document.createElement('div');\r\n this.container.classList.add('sidebar-left-section');\r\n\r\n if(!options.noDelimiter) {\r\n const hr = document.createElement('hr');\r\n this.container.append(hr);\r\n } else {\r\n this.container.classList.add('no-delimiter');\r\n }\r\n\r\n this.content = this.generateContentElement();\r\n\r\n if(options.name) {\r\n this.title = document.createElement('div');\r\n this.title.classList.add('sidebar-left-h2', 'sidebar-left-section-name');\r\n i18n_({element: this.title, key: options.name});\r\n this.content.append(this.title);\r\n }\r\n\r\n if(options.caption) {\r\n this.caption = this.generateContentElement();\r\n this.caption.classList.add('sidebar-left-section-caption');\r\n\r\n if(options.caption !== true) {\r\n i18n_({element: this.caption, key: options.caption});\r\n }\r\n }\r\n }\r\n\r\n public generateContentElement() {\r\n const content = document.createElement('div');\r\n content.classList.add('sidebar-left-section-content');\r\n this.container.append(content);\r\n return content;\r\n }\r\n}\r\n\r\nexport const generateSection = (appendTo: Scrollable, name?: LangPackKey, caption?: LangPackKey) => {\r\n const section = new SettingSection({name, caption});\r\n appendTo.append(section.container);\r\n return section.content;\r\n};\r\n\r\nconst appSidebarLeft = new AppSidebarLeft();\r\nMOUNT_CLASS_TO.appSidebarLeft = appSidebarLeft;\r\nexport default appSidebarLeft;\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\n//import { generatePathData } from \"../../helpers/dom\";\r\nimport { MyMessage } from \"../../lib/appManagers/appMessagesManager\";\r\nimport type Chat from \"./chat\";\r\n\r\ntype Group = {bubble: HTMLElement, mid: number, timestamp: number}[];\r\ntype BubbleGroup = {timestamp: number, fromId: number, 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 details.group.findAndSplice(d => d.bubble === bubble);\r\n if(!details.group.length) {\r\n this.groups.findAndSplice(g => g === 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 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.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;\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 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 this.prevBtn.addEventListener('click', this.onPrevClick);\r\n\r\n this.nextBtn = document.createElement('button');\r\n this.nextBtn.classList.add('btn-icon', 'tgico-down', 'date-picker-next');\r\n this.nextBtn.addEventListener('click', this.onNextClick);\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 this.monthsContainer.addEventListener('click', this.onDateClick);\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 inputField.input.addEventListener('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 this.btnConfirm.addEventListener('click', () => {\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 }, {once: true});\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\nimport appImManager from \"../../lib/appManagers/appImManager\";\r\nimport PopupPickUser from \"./pickUser\";\r\n\r\nexport default class PopupForward extends PopupPickUser {\r\n constructor(fromPeerId: number, mids: number[], onSelect?: () => Promise<void> | void, onClose?: () => void) {\r\n super({\r\n peerTypes: ['dialogs', 'contacts'],\r\n onSelect: async(peerId) => {\r\n if(onSelect) {\r\n const res = onSelect();\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(fromPeerId, mids.slice());\r\n },\r\n onClose,\r\n placeholder: 'ShareModal.Search.ForwardPlaceholder',\r\n chatRightsAction: 'send_messages'\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 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 { toggleDisability } from \"../../helpers/dom\";\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\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: {\r\n //_: 'inputStickerSetID',\r\n id: string,\r\n access_hash: string\r\n }) {\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.onClose = () => {\r\n animationIntersector.setOnlyOnePlayableGroup('');\r\n this.stickersFooter.removeEventListener('click', this.onFooterClick);\r\n this.stickersDiv.removeEventListener('click', this.onStickersClick);\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 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 onFooterClick = () => {\r\n const toggle = toggleDisability([this.stickersFooter], 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 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 //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 this.h6.innerHTML = 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 button.addEventListener('click', this.onFooterClick);\r\n\r\n if(set.documents.length) {\r\n this.stickersDiv.addEventListener('click', this.onStickersClick);\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","/*\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 let entry = entries.filter(entry => entry.boundingClientRect.top < 0).sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top)[0];\r\n if(!entry) return;\r\n let 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}","/*\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 { formatNumber } from \"../../helpers/number\";\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 AvatarElement from \"../avatar\";\r\n\r\nconst TAG_NAME = 'replies-element';\r\n\r\nrootScope.on('replies_updated', (e) => {\r\n const message = e;\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 \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(!leftPart) {\r\n leftPart = document.createElement('div');\r\n leftPart.classList.add('replies-footer-avatars');\r\n }\r\n\r\n replies.recent_repliers.slice().reverse().forEach((peer, idx) => {\r\n let avatarElem = leftPart.children[idx] as AvatarElement;\r\n if(!avatarElem) {\r\n avatarElem = new AvatarElement();\r\n avatarElem.setAttribute('dialog', '0');\r\n avatarElem.classList.add('avatar-30');\r\n \r\n if(this.loadPromises) {\r\n avatarElem.loadPromises = this.loadPromises;\r\n }\r\n }\r\n \r\n avatarElem.setAttribute('peer', '' + appPeersManager.getPeerId(peer));\r\n \r\n if(!avatarElem.parentNode) {\r\n leftPart.append(avatarElem);\r\n }\r\n });\r\n\r\n // if were 3 and became 2\r\n (Array.from(leftPart.children) as HTMLElement[]).slice(replies.recent_repliers.length).forEach(el => el.remove());\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.append(leftPart);\r\n }\r\n \r\n let text: string;\r\n if(replies) {\r\n if(replies.replies) {\r\n text = replies.replies + ' ' + (replies.replies > 1 ? 'Comments' : 'Comment');\r\n } else {\r\n text = 'Leave a Comment';\r\n }\r\n } else {\r\n text = 'View in chat';\r\n }\r\n\r\n if(replies) {\r\n const historyStorage = appMessagesManager.getHistoryStorage(-replies.channel_id);\r\n this.classList.toggle('is-unread', replies.read_max_id < replies.max_id && (!historyStorage.readMaxId || historyStorage.readMaxId < replies.max_id));\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 textSpan.innerHTML = text;\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","/*\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 { getFullDate } from \"../../helpers/date\";\r\nimport { formatNumber } from \"../../helpers/number\";\r\nimport RichTextProcessor from \"../../lib/richtextprocessor\";\r\nimport { wrapReply } from \"../wrappers\";\r\nimport Chat from \"./chat\";\r\nimport RepliesElement from \"./replies\";\r\n\r\nexport namespace MessageRender {\r\n /* export const setText = () => {\r\n\r\n }; */\r\n\r\n export const setTime = (chat: Chat, message: any, bubble: HTMLElement, bubbleContainer: HTMLElement, messageDiv: HTMLElement) => {\r\n const date = new Date(message.date * 1000);\r\n let time = ('0' + date.getHours()).slice(-2) + ':' + ('0' + date.getMinutes()).slice(-2);\r\n\r\n if(message.views) {\r\n const postAuthor = message.post_author || message.fwd_from?.post_author;\r\n\r\n bubble.classList.add('channel-post');\r\n time = formatNumber(message.views, 1) + ' <i class=\"tgico-channelviews time-icon\"></i> ' + (postAuthor ? RichTextProcessor.wrapEmojiText(postAuthor) + ', ' : '') + time;\r\n \r\n if(!message.fwd_from?.saved_from_msg_id) {\r\n const forward = document.createElement('div');\r\n forward.classList.add('bubble-beside-button', 'forward');\r\n forward.innerHTML = `\r\n <svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" preserveAspectRatio=\"xMidYMid meet\" viewBox=\"0 0 24 24\">\r\n <defs>\r\n <path d=\"M13.55 3.24L13.64 3.25L13.73 3.27L13.81 3.29L13.9 3.32L13.98 3.35L14.06 3.39L14.14 3.43L14.22 3.48L14.29 3.53L14.36 3.59L14.43 3.64L22.23 10.85L22.36 10.99L22.48 11.15L22.57 11.31L22.64 11.48L22.69 11.66L22.72 11.85L22.73 12.04L22.71 12.22L22.67 12.41L22.61 12.59L22.53 12.76L22.42 12.93L22.29 13.09L22.23 13.15L14.43 20.36L14.28 20.48L14.12 20.58L13.95 20.66L13.77 20.72L13.58 20.76L13.4 20.77L13.22 20.76L13.03 20.73L12.85 20.68L12.68 20.61L12.52 20.52L12.36 20.4L12.22 20.27L12.16 20.2L12.1 20.13L12.05 20.05L12.01 19.98L11.96 19.9L11.93 19.82L11.89 19.73L11.87 19.65L11.84 19.56L11.83 19.47L11.81 19.39L11.81 19.3L11.8 19.2L11.8 16.42L11 16.49L10.23 16.58L9.51 16.71L8.82 16.88L8.18 17.09L7.57 17.33L7.01 17.6L6.48 17.91L5.99 18.26L5.55 18.64L5.14 19.05L4.77 19.51L4.43 19.99L4.29 20.23L4.21 20.35L4.11 20.47L4 20.57L3.88 20.65L3.75 20.72L3.62 20.78L3.48 20.82L3.33 20.84L3.19 20.84L3.04 20.83L2.9 20.79L2.75 20.74L2.62 20.68L2.53 20.62L2.45 20.56L2.38 20.5L2.31 20.43L2.25 20.36L2.2 20.28L2.15 20.19L2.11 20.11L2.07 20.02L2.04 19.92L2.02 19.83L2.01 19.73L2 19.63L2.04 17.99L2.19 16.46L2.46 15.05L2.85 13.75L3.35 12.58L3.97 11.53L4.7 10.6L5.55 9.8L6.51 9.12L7.59 8.56L8.77 8.13L10.07 7.83L11.48 7.65L11.8 7.63L11.8 4.8L11.91 4.56L12.02 4.35L12.14 4.16L12.25 3.98L12.37 3.82L12.48 3.68L12.61 3.56L12.73 3.46L12.85 3.38L12.98 3.31L13.11 3.27L13.24 3.24L13.37 3.23L13.46 3.23L13.55 3.24Z\" id=\"b13RmHDQtl\"></path>\r\n </defs>\r\n <use xlink:href=\"#b13RmHDQtl\" opacity=\"1\" fill=\"#fff\" fill-opacity=\"1\"></use>\r\n </svg>`;\r\n bubbleContainer.append(forward);\r\n bubble.classList.add('with-beside-button');\r\n }\r\n }\r\n\r\n if(message.edit_date && chat.type !== 'scheduled' && !message.pFlags.edit_hide) {\r\n bubble.classList.add('is-edited');\r\n time = '<i class=\"edited\">edited</i> ' + time;\r\n }\r\n\r\n if(chat.type !== 'pinned' && message.pFlags.pinned) {\r\n bubble.classList.add('is-pinned');\r\n time = '<i class=\"tgico-pinnedchat time-icon\"></i>' + time;\r\n }\r\n\r\n const title = getFullDate(date) \r\n + (message.edit_date ? `\\nEdited: ${getFullDate(new Date(message.edit_date * 1000))}` : '')\r\n + (message.fwd_from ? `\\nOriginal: ${getFullDate(new Date(message.fwd_from.date * 1000))}` : '');\r\n\r\n const timeSpan = document.createElement('span');\r\n timeSpan.classList.add('time', 'tgico');\r\n timeSpan.title = title;\r\n timeSpan.innerHTML = `${time}<div class=\"inner tgico\" title=\"${title}\">${time}</div>`;\r\n\r\n messageDiv.append(timeSpan);\r\n\r\n return timeSpan;\r\n };\r\n\r\n export const renderReplies = ({bubble, bubbleContainer, message, messageDiv, loadPromises}: {\r\n bubble: HTMLElement,\r\n bubbleContainer: HTMLElement,\r\n message: any,\r\n messageDiv: HTMLElement,\r\n loadPromises?: Promise<any>[]\r\n }) => {\r\n const isFooter = !bubble.classList.contains('sticker') && !bubble.classList.contains('emoji-big') && !bubble.classList.contains('round');\r\n const repliesFooter = new RepliesElement();\r\n repliesFooter.message = message;\r\n repliesFooter.type = isFooter ? 'footer' : 'beside';\r\n repliesFooter.loadPromises = loadPromises;\r\n repliesFooter.init();\r\n bubbleContainer.prepend(repliesFooter);\r\n return isFooter;\r\n };\r\n\r\n export const setReply = ({chat, bubble, bubbleContainer, message}: {\r\n chat: Chat,\r\n bubble: HTMLElement,\r\n bubbleContainer?: HTMLElement,\r\n message: any\r\n }) => {\r\n const isReplacing = !bubbleContainer;\r\n if(isReplacing) {\r\n bubbleContainer = bubble.querySelector('.bubble-content');\r\n }\r\n\r\n const currentReplyDiv = isReplacing ? bubbleContainer.querySelector('.reply') : null;\r\n if(!message.reply_to_mid) {\r\n if(currentReplyDiv) {\r\n currentReplyDiv.remove();\r\n }\r\n\r\n bubble.classList.remove('is-reply');\r\n return;\r\n }\r\n\r\n\r\n const replyToPeerId = message.reply_to.reply_to_peer_id ? chat.appPeersManager.getPeerId(message.reply_to.reply_to_peer_id) : chat.peerId;\r\n\r\n let originalMessage = chat.appMessagesManager.getMessageByPeer(replyToPeerId, message.reply_to_mid);\r\n let originalPeerTitle: string;\r\n \r\n /////////this.log('message to render reply', originalMessage, originalPeerTitle, bubble, message);\r\n \r\n // need to download separately\r\n if(originalMessage._ === 'messageEmpty') {\r\n //////////this.log('message to render reply empty, need download', message, message.reply_to_mid);\r\n chat.appMessagesManager.wrapSingleMessage(replyToPeerId, message.reply_to_mid);\r\n chat.bubbles.needUpdate.push({replyToPeerId, replyMid: message.reply_to_mid, mid: message.mid});\r\n \r\n originalPeerTitle = 'Loading...';\r\n } else {\r\n originalPeerTitle = chat.appPeersManager.getPeerTitle(originalMessage.fromId || originalMessage.fwdFromId, true) || '';\r\n }\r\n\r\n const wrapped = wrapReply(originalPeerTitle, originalMessage.message || '', originalMessage);\r\n if(currentReplyDiv) {\r\n currentReplyDiv.replaceWith(wrapped);\r\n } else {\r\n bubbleContainer.append(wrapped);\r\n }\r\n //bubbleContainer.insertBefore(, nameContainer);\r\n bubble.classList.add('is-reply');\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 { 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\nimport type { AppImManager } from \"../../lib/appManagers/appImManager\";\r\nimport type { AppMessagesManager, HistoryResult, 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 { AppDocsManager } from \"../../lib/appManagers/appDocsManager\";\r\nimport type { AppPeersManager } from \"../../lib/appManagers/appPeersManager\";\r\nimport type sessionStorage from '../../lib/sessionStorage';\r\nimport type Chat from \"./chat\";\r\nimport { CHAT_ANIMATION_GROUP } from \"../../lib/appManagers/appImManager\";\r\nimport { cancelEvent, whichChild, attachClickEvent, positionElementByIndex, reflowScrollableElement, replaceContent } from \"../../helpers/dom\";\r\nimport { getObjectKeysAndSort } from \"../../helpers/object\";\r\nimport { isTouchSupported } from \"../../helpers/touchSupport\";\r\nimport { logger } from \"../../lib/logger\";\r\nimport rootScope from \"../../lib/rootScope\";\r\nimport AppMediaViewer from \"../appMediaViewer\";\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 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 { isAndroid, isApple, isSafari } from \"../../helpers/userAgent\";\r\nimport I18n, { i18n, langPack } from \"../../lib/langPack\";\r\nimport AvatarElement from \"../avatar\";\r\nimport { formatPhoneNumber } from \"../misc\";\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 { AppChatsManager } from \"../../lib/appManagers/appChatsManager\";\r\nimport ListenerSetter from \"../../helpers/listenerSetter\";\r\nimport PollElement from \"../poll\";\r\nimport AudioElement from \"../audio\";\r\nimport { Message, MessageEntity, MessageReplyHeader } from \"../../layer\";\r\nimport { REPLIES_PEER_ID } from \"../../lib/mtproto/mtproto_config\";\r\nimport { FocusDirection } from \"../../helpers/fastSmoothScroll\";\r\nimport useHeavyAnimationCheck, { getHeavyAnimationPromise, dispatchHeavyAnimationEvent } from \"../../hooks/useHeavyAnimationCheck\";\r\nimport { fastRaf } 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 { forEachReverse } from \"../../helpers/array\";\r\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\r\nimport findUpTag from \"../../helpers/dom/findUpTag\";\r\nimport { toast } from \"../toast\";\r\nimport { getElementByPoint } from \"../../helpers/dom/getElementByPoint\";\r\nimport { getMiddleware } from \"../../helpers/middleware\";\r\n\r\nconst USE_MEDIA_TAILS = false;\r\nconst IGNORE_ACTIONS: Message.messageService['action']['_'][] = [/* 'messageActionHistoryClear' */];\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\nexport default class ChatBubbles {\r\n bubblesContainer: HTMLDivElement;\r\n chatInner: HTMLDivElement;\r\n scrollable: Scrollable;\r\n\r\n private getHistoryTopPromise: Promise<boolean>;\r\n private getHistoryBottomPromise: Promise<boolean>;\r\n\r\n public peerId = 0;\r\n //public messagesCount: number = -1;\r\n\r\n public unreadOut = new Set<number>();\r\n public needUpdate: {replyToPeerId: number, replyMid: number, mid: number}[] = []; // if need wrapSingleMessage\r\n\r\n public bubbles: {[mid: string]: HTMLDivElement} = {};\r\n public dateMessages: {[timestamp: number]: { \r\n div: HTMLDivElement, \r\n firstTimestamp: number, \r\n container: HTMLDivElement,\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 unreadedObserver: IntersectionObserver;\r\n private unreaded: number[] = [];\r\n\r\n public bubbleGroups: BubbleGroups;\r\n\r\n private preloader: ProgressivePreloader = null;\r\n \r\n private loadedTopTimes = 0;\r\n private loadedBottomTimes = 0;\r\n\r\n public messagesQueuePromise: Promise<void> = null;\r\n private messagesQueue: {message: any, bubble: HTMLDivElement, reverse: boolean, promises: Promise<void>[]}[] = [];\r\n private messagesQueueOnRender: () => void = null;\r\n private messagesQueueOnRenderAdditional: () => void = null;\r\n\r\n private firstUnreadBubble: HTMLDivElement = 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 public replyFollowHistory: number[] = [];\r\n\r\n public isHeavyAnimationInProgress = false;\r\n public scrollingToNewBubble: HTMLElement;\r\n\r\n public isFirstLoad = true;\r\n private needReflowScroll: boolean;\r\n\r\n constructor(private chat: Chat, private appMessagesManager: AppMessagesManager, private appStickersManager: AppStickersManager, private appUsersManager: AppUsersManager, private appInlineBotsManager: AppInlineBotsManager, private appPhotosManager: AppPhotosManager, private appDocsManager: AppDocsManager, private appPeersManager: AppPeersManager, private appChatsManager: AppChatsManager, private storage: typeof sessionStorage) {\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 // * events\r\n\r\n // will call when sent for update pos\r\n this.listenerSetter.add(rootScope, 'history_update', (e) => {\r\n const {storage, peerId, mid} = e;\r\n \r\n if(mid && peerId === this.peerId && 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.addBubble(bubble, message, false);\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.scrollingToNewBubble) {\r\n this.scrollToNewLastBubble();\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', (e) => {\r\n let peerId: number = e.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 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 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 && !message.media.document.type) {\r\n const div = bubble.querySelector(`.document-container[data-mid=\"${tempId}\"] .document`);\r\n if(div) {\r\n div.replaceWith(wrapDocument({message}));\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[message-id=\"${tempId}\"], .document[data-doc-id=\"${tempId}\"]`) as HTMLElement;\r\n if(element) {\r\n if(element instanceof AudioElement) {\r\n element.setAttribute('doc-id', message.media.document.id);\r\n element.setAttribute('message-id', '' + mid);\r\n element.message = message;\r\n element.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.renderMessage(message, true, false, bubble, false);\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 if(this.bubbles[tempId]) {\r\n const bubble = this.bubbles[tempId];\r\n this.bubbles[mid] = bubble;\r\n delete this.bubbles[tempId];\r\n\r\n //getHeavyAnimationPromise().then(() => {\r\n fastRaf(() => {\r\n bubble.classList.remove('is-sending');\r\n bubble.classList.add(this.peerId === rootScope.myId && this.chat.type !== 'scheduled' ? 'is-read' : 'is-sent');\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', (e) => {\r\n fastRaf(() => {\r\n const {storage, peerId, mid} = e;\r\n \r\n if(peerId !== this.peerId || storage !== this.chat.getMessagesStorage()) return;\r\n const mounted = this.getMountedBubble(mid);\r\n if(!mounted) return;\r\n\r\n const updatePosition = this.chat.type === 'scheduled';\r\n this.renderMessage(mounted.message, true, false, mounted.bubble, updatePosition);\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 this.listenerSetter.add(rootScope, 'album_edit', (e) => {\r\n //fastRaf(() => { // ! can't use delayed smth here, need original bubble to be edited\r\n const {peerId, groupId, deletedMids} = e;\r\n \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.renderMessage(this.chat.getMessage(renderMaxId), true, false, this.bubbles[renderedId], false);\r\n //});\r\n });\r\n\r\n this.listenerSetter.add(rootScope, 'messages_downloaded', (e) => {\r\n const {peerId, mids} = e;\r\n\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 this.listenerSetter.add(this.bubblesContainer, 'click', this.onBubblesClick/* , {capture: true, passive: false} */);\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(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 dateMessage.div.classList.toggle('is-sticky', stuck);\r\n break;\r\n }\r\n }\r\n });\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 this.isHeavyAnimationInProgress = false;\r\n\r\n if(middleware && middleware()) {\r\n this.lazyLoadQueue.unlock();\r\n this.lazyLoadQueue.refresh();\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', (e) => {\r\n const {peerId, storage, mid} = e;\r\n\r\n if(peerId !== this.peerId || 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\r\n this.listenerSetter.add(rootScope, 'history_multiappend', (e) => {\r\n const msgIdsByPeer = e;\r\n\r\n if(!(this.peerId in msgIdsByPeer)) return;\r\n const msgIds = Array.from(msgIdsByPeer[this.peerId] as number[]).slice().sort((a, b) => b - a);\r\n this.renderNewMessagesByIds(msgIds);\r\n });\r\n \r\n this.listenerSetter.add(rootScope, 'history_delete', (e) => {\r\n const {peerId, msgs} = e;\r\n\r\n const mids = Object.keys(msgs).map(s => +s);\r\n\r\n if(peerId === this.peerId) {\r\n this.deleteMessagesByIds(mids);\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope, 'dialog_unread', (e) => {\r\n const info = e;\r\n\r\n if(info.peerId === this.peerId) {\r\n this.chat.input.setUnreadCount();\r\n this.updateUnreadByDialog();\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope, 'dialogs_multiupdate', (e) => {\r\n const dialogs = e;\r\n\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.unreadedObserver = new IntersectionObserver((entries) => {\r\n if(this.chat.appImManager.offline) { // ! but you can scroll the page without triggering 'focus', need something now\r\n return;\r\n }\r\n\r\n const readed: number[] = [];\r\n \r\n entries.forEach(entry => {\r\n if(entry.isIntersecting) {\r\n const target = entry.target as HTMLElement;\r\n const mid = +target.dataset.mid;\r\n readed.push(mid);\r\n this.unreadedObserver.unobserve(target);\r\n }\r\n });\r\n\r\n if(readed.length) {\r\n let maxId = Math.max(...readed);\r\n\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 = this.appMessagesManager.getHistoryStorage(this.peerId, this.chat.threadId).maxId || maxId;\r\n }\r\n }\r\n\r\n let length = readed.length;\r\n for(let i = this.unreaded.length - 1; i >= 0; --i) {\r\n if(this.unreaded[i] <= maxId) {\r\n length++;\r\n this.unreaded.splice(i, 1);\r\n }\r\n }\r\n\r\n if(DEBUG) {\r\n this.log('will readHistory by ids:', maxId, length);\r\n }\r\n \r\n /* false && */ 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 });\r\n }\r\n });\r\n\r\n if('ResizeObserver' in window) {\r\n let wasHeight = this.scrollable.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\r\n const onResizeEnd = () => {\r\n const height = this.scrollable.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.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 = (entries: any) => {\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.scrollTop = 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 // @ts-ignore\r\n const resizeObserver = new ResizeObserver(processEntries);\r\n resizeObserver.observe(this.bubblesContainer);\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(Object.keys(this.appMessagesManager.getScheduledMessagesStorage(this.peerId)).length);\r\n };\r\n\r\n this.listenerSetter.add(rootScope, 'scheduled_new', (e) => {\r\n const {peerId, mid} = e;\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', (e) => {\r\n const {peerId, mids} = e;\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 // ! 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(isTouchSupported && 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.toggleByBubble(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(+contactDiv.dataset.peerId);\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\r\n this.appMessagesManager.wrapSingleMessage(peerId, threadId).then(() => {\r\n this.appMessagesManager.generateThreadServiceStartMessage(this.appMessagesManager.getMessageByPeer(peerId, threadId));\r\n this.chat.appImManager.setInnerPeer(peerId, message.fwd_from.saved_from_msg_id, 'discussion', threadId);\r\n });\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(-replies.channel_id, undefined, 'discussion', (message as MyMessage).mid);\r\n });\r\n }\r\n }\r\n\r\n return;\r\n }\r\n\r\n const nameDiv = findUpClassName(target, 'peer-title') || findUpClassName(target, 'name') || findUpTag(target, 'AVATAR-ELEMENT');\r\n if(nameDiv) {\r\n target = nameDiv || target;\r\n const peerId = +(target.dataset.peerId || target.getAttribute('peer'));\r\n const savedFrom = target.dataset.savedFrom;\r\n if(savedFrom) {\r\n const splitted = savedFrom.split('_');\r\n const peerId = +splitted[0];\r\n const msgId = +splitted[1];\r\n\r\n this.chat.appImManager.setInnerPeer(peerId, msgId);\r\n } else {\r\n if(peerId) {\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 return;\r\n }\r\n\r\n //this.log('chatInner click:', target);\r\n const isVideoComponentElement = target.tagName === 'SPAN';\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 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 let messageId = +findUpClassName(target, 'album-item')?.dataset.mid || +bubble.dataset.mid;\r\n let 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 let targets: {element: HTMLElement, mid: number, peerId: number}[] = [];\r\n let ids = Object.keys(this.bubbles).map(k => +k).filter(id => {\r\n //if(!this.scrollable.visibleElements.find(e => e.element === this.bubbles[id])) return false;\r\n\r\n let message = this.chat.getMessage(id);\r\n \r\n return message.media && (message.media.photo || (message.media.document && (message.media.document.type === 'video' || message.media.document.type === 'gif')) || (message.media.webpage && (message.media.webpage.document || message.media.webpage.photo)));\r\n }).sort((a, b) => a - b);\r\n\r\n ids.forEach(id => {\r\n let withTail = this.bubbles[id].classList.contains('with-media-tail');\r\n let str = '.album-item video, .album-item img, .preview video, .preview img, ';\r\n if(withTail) {\r\n str += '.bubble__media-container';\r\n } else {\r\n str += '.attachment video, .attachment img';\r\n }\r\n\r\n let elements = this.bubbles[id].querySelectorAll(str) as NodeListOf<HTMLElement>;\r\n const parents: Set<HTMLElement> = new Set();\r\n Array.from(elements).forEach((element: HTMLElement) => {\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?.dataset.mid || id,\r\n peerId: this.peerId\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: 'inputMessagesFilterPhotoVideo'\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 splitted = savedFrom.split('_');\r\n const peerId = +splitted[0];\r\n const msgId = +splitted[1];\r\n ////this.log('savedFrom', peerId, msgID);\r\n this.chat.appImManager.setInnerPeer(peerId, msgId);\r\n return;\r\n } else if(target.classList.contains('forward')) {\r\n const mid = +bubble.dataset.mid;\r\n new PopupForward(this.peerId, [mid]);\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(replyToPeerId, replyToMid, this.chat.type, this.chat.threadId);\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 = (this.appPhotosManager.windowH / 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 in group) {\r\n if(this.bubbles[mid]) {\r\n const maxId = Math.max(...Object.keys(group).map(id => +id)); // * 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)\r\n };\r\n }\r\n }\r\n\r\n return null;\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 const history = Object.keys(this.bubbles).map(id => +id).sort((a, b) => a - b);\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.scrollable.loadedAll.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 = () => {\r\n //return;\r\n \r\n // * В таком случае, кнопка не будет моргать если чат в самом низу, и правильно отработает случай написания нового сообщения и проскролла вниз\r\n if(this.isHeavyAnimationInProgress && this.scrolledDown) return;\r\n //lottieLoader.checkAnimations(false, 'chat');\r\n\r\n if(!isTouchSupported) {\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);\r\n }\r\n \r\n if(this.scrollable.getDistanceToEnd() < 300 && this.scrollable.loadedAll.bottom) {\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 if(this.chat.topbar.pinnedMessage) {\r\n this.chat.topbar.pinnedMessage.setCorrectIndex(this.scrollable.lastScrollDirection);\r\n }\r\n };\r\n\r\n public setScroll() {\r\n this.scrollable = new Scrollable(null, 'IM', /* 10300 */300);\r\n this.scrollable.loadedAll.top = false;\r\n this.scrollable.loadedAll.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(isTouchSupported) {\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 bubble.classList.remove('is-sent');\r\n bubble.classList.add('is-read');\r\n }\r\n \r\n this.unreadOut.delete(msgId);\r\n }\r\n }\r\n }\r\n \r\n public deleteMessagesByIds(mids: number[], permanent = true) {\r\n mids.forEach(mid => {\r\n if(!(mid in this.bubbles)) return;\r\n \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\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.unreadedObserver) {\r\n this.unreadedObserver.unobserve(bubble);\r\n }\r\n //this.unreaded.findAndSplice(mid => mid === id);\r\n bubble.remove();\r\n //bubble.remove();\r\n });\r\n\r\n if(permanent && this.chat.selection.isSelecting) {\r\n this.chat.selection.deleteSelectedMids(mids);\r\n }\r\n \r\n animationIntersector.checkAnimations(false, CHAT_ANIMATION_GROUP);\r\n this.deleteEmptyDateGroups();\r\n }\r\n \r\n public renderNewMessagesByIds(mids: number[], scrolledDown = this.scrolledDown) {\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 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 const promise = this.performHistoryResult(mids, false, true);\r\n if(scrolledDown) {\r\n promise.then(() => {\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 this.scrollToNewLastBubble();\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 scrollToBubble(\r\n element: HTMLElement, \r\n position: ScrollLogicalPosition,\r\n forceDirection?: FocusDirection,\r\n forceDuration?: number\r\n ) {\r\n // * 4 = .25rem\r\n const bubble = findUpClassName(element, 'bubble');\r\n\r\n // * if it's a start, then scroll to start of the group\r\n if(position === 'center' && whichChild(bubble) === (this.stickyIntersector ? 2 : 1)) {\r\n const dateGroup = bubble.parentElement;\r\n if(whichChild(dateGroup) === 0) {\r\n element = dateGroup;\r\n position = 'start';\r\n }\r\n }\r\n\r\n return this.scrollable.scrollIntoViewNew(element, position, 4, undefined, forceDirection, forceDuration);\r\n }\r\n\r\n public scrollToNewLastBubble() {\r\n const bubble = this.chatInner.lastElementChild.lastElementChild as HTMLElement;\r\n\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.scrollingToNewBubble = bubble;\r\n this.scrollToBubble(bubble, 'end').then(() => {\r\n this.scrollingToNewBubble = null;\r\n });\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 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(!(dateTimestamp in this.dateMessages)) {\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 if(today.getTime() === date.getTime()) {\r\n dateElement = i18n(this.chat.type === 'scheduled' ? 'Chat.Date.ScheduledForToday' : 'Date.Today');\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(this.chat.type === 'scheduled') {\r\n dateElement = i18n('Chat.Date.ScheduledFor', [dateElement]);\r\n }\r\n }\r\n\r\n /* if(this.chat.type === 'scheduled') {\r\n str = 'Scheduled for ' + str;\r\n } */\r\n \r\n const div = document.createElement('div');\r\n div.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 div.append(bubbleContent);\r\n ////////this.log('need to render date message', dateTimestamp, str);\r\n\r\n const container = document.createElement('div');\r\n container.className = 'bubbles-date-group';\r\n\r\n const haveTimestamps = getObjectKeysAndSort(this.dateMessages, 'asc');\r\n let i = 0;\r\n for(; i < haveTimestamps.length; ++i) {\r\n const t = haveTimestamps[i];\r\n if(dateTimestamp < t) {\r\n break;\r\n }\r\n }\r\n \r\n this.dateMessages[dateTimestamp] = {\r\n div,\r\n container,\r\n firstTimestamp: date.getTime()\r\n };\r\n\r\n container.append(div);\r\n\r\n positionElementByIndex(container, this.chatInner, i);\r\n\r\n /* if(reverse) {\r\n this.chatInner.prepend(container);\r\n } else {\r\n this.chatInner.append(container);\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.unreadedObserver && this.unreadedObserver.disconnect();\r\n this.stickyIntersector && this.stickyIntersector.disconnect();\r\n\r\n delete this.lazyLoadQueue;\r\n this.unreadedObserver && delete this.unreadedObserver;\r\n this.stickyIntersector && delete this.stickyIntersector;\r\n }\r\n\r\n public cleanup(bubblesToo = false) {\r\n ////console.time('appImManager cleanup');\r\n this.scrollable.loadedAll.top = false;\r\n this.scrollable.loadedAll.bottom = false;\r\n\r\n if(TEST_SCROLL !== undefined) {\r\n TEST_SCROLL = TEST_SCROLL_TIMES;\r\n }\r\n\r\n this.bubbles = {};\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\r\n if(this.stickyIntersector) {\r\n this.stickyIntersector.disconnect();\r\n }\r\n \r\n if(this.unreadedObserver) {\r\n this.unreadedObserver.disconnect();\r\n this.unreaded.length = 0;\r\n }\r\n\r\n this.loadedTopTimes = this.loadedBottomTimes = 0;\r\n\r\n this.middleware.clean();\r\n\r\n ////console.timeEnd('appImManager cleanup');\r\n }\r\n\r\n public setPeer(peerId: number, lastMsgId?: number): {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 = 0;\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 historyStorage = this.appMessagesManager.getHistoryStorage(peerId, this.chat.threadId);\r\n let topMessage = this.chat.type === 'pinned' ? this.appMessagesManager.pinnedMessages[peerId].maxId : 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(this.chat.type !== 'pinned' && topMessage && !historyStorage.history.slice.includes(topMessage)) {\r\n topMessage = 0;\r\n }\r\n\r\n let readMaxId = 0, savedPosition: ReturnType<AppImManager['getChatSavedPosition']>;\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 if(/* dialog.unread_count */readMaxId && !samePeer) {\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;\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 this.scrollable.scrollTop = this.scrollable.scrollHeight;\r\n this.chat.dispatchEvent('setPeer', lastMsgId, true);\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\r\n if(DEBUG) {\r\n this.log('setPeer peerId:', this.peerId, historyStorage, lastMsgId, topMessage);\r\n }\r\n\r\n // add last message, bc in getHistory will load < max_id\r\n const additionMsgId = isJump || this.chat.type === 'scheduled' ? 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 }\r\n\r\n const oldChatInner = this.chatInner;\r\n this.cleanup();\r\n this.chatInner = document.createElement('div');\r\n if(samePeer) {\r\n this.chatInner.className = oldChatInner.className;\r\n this.chatInner.classList.remove('disable-hover', 'is-scrolling');\r\n } else {\r\n this.chatInner.classList.add('bubbles-inner');\r\n }\r\n\r\n this.lazyLoadQueue.lock();\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 this.scrollable.container.textContent = '';\r\n //oldChatInner.remove();\r\n this.chat.finishPeerChange(isTarget, isJump, lastMsgId);\r\n this.preloader.attach(this.bubblesContainer);\r\n }\r\n }\r\n\r\n //console.timeEnd('appImManager setPeer pre promise');\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); // * костыль\r\n }\r\n } else {\r\n this.preloader.detach();\r\n }\r\n\r\n replaceContent(this.scrollable.container, this.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 this.scrollable.scrollTop = 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 this.scrollable.scrollTop += distance;\r\n } */\r\n } else if((topMessage && isJump) || isTarget) {\r\n const fromUp = maxBubbleId > 0 && (maxBubbleId < lastMsgId || lastMsgId < 0);\r\n const followingUnread = readMaxId === lastMsgId && !isTarget;\r\n if(!fromUp && samePeer) {\r\n this.scrollable.scrollTop = 99999;\r\n } else if(fromUp/* && (samePeer || forwardingUnread) */) {\r\n this.scrollable.scrollTop = 0;\r\n }\r\n\r\n const mountedByLastMsgId = this.getMountedBubble(lastMsgId);\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 // ! sometimes there can be no bubble\r\n if(bubble) {\r\n this.scrollToBubble(bubble, followingUnread ? 'start' : 'center', !samePeer ? FocusDirection.Static : undefined);\r\n if(!followingUnread) {\r\n this.highlightBubble(bubble);\r\n }\r\n }\r\n } else {\r\n this.scrollable.scrollTop = 99999;\r\n }\r\n\r\n this.onScroll();\r\n\r\n this.chat.dispatchEvent('setPeer', lastMsgId, !isJump);\r\n\r\n // warning\r\n if((!lastMsgId && !savedPosition) || this.bubbles[topMessage] || lastMsgId === topMessage) {\r\n this.scrollable.loadedAll.bottom = true;\r\n }\r\n\r\n if(savedPosition) {\r\n Promise.all([setPeerPromise, getHeavyAnimationPromise()]).then(() => {\r\n this.scrollable.checkForTriggers();\r\n });\r\n }\r\n\r\n this.log('scrolledAllDown:', this.scrollable.loadedAll.bottom);\r\n\r\n //if(!this.unreaded.length && dialog) { // lol\r\n if(this.scrollable.loadedAll.bottom && topMessage) { // lol\r\n this.onScrolledAllDown();\r\n }\r\n\r\n if(this.chat.type === 'chat') {\r\n const dialog = this.appMessagesManager.getDialogByPeerId(peerId)[0];\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 this.preloader.detach();\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 peerId = this.peerId;\r\n const isChannel = this.appPeersManager.isChannel(peerId);\r\n const canWrite = this.appMessagesManager.canWriteToPeer(peerId);\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\r\n public renderMessagesQueue(message: any, bubble: HTMLDivElement, 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 this.setMessagesQueuePromise(); \r\n }\r\n\r\n public setMessagesQueuePromise() {\r\n if(this.messagesQueuePromise || !this.messagesQueue.length) return;\r\n\r\n 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.concat(promises), []);\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 return Promise.reject('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 }).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: any, reverse: boolean) {\r\n const dateMessage = this.getDateContainerByMessage(message, reverse);\r\n if(this.chat.type === 'scheduled' || this.chat.type === 'pinned' || true) {\r\n const offset = this.stickyIntersector ? 2 : 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 ? 1 : 0].nextSibling);\r\n } else {\r\n dateMessage.container.append(bubble);\r\n }\r\n }\r\n\r\n this.bubbleGroups.addBubble(bubble, message, reverse);\r\n }\r\n\r\n public getMiddleware() {\r\n return this.middleware.get();\r\n }\r\n \r\n // reverse means top\r\n public renderMessage(message: any, reverse = false, multipleRender = false, bubble: HTMLDivElement = 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 //return;\r\n const albumMustBeRenderedFull = this.chat.type !== 'pinned';\r\n if(message.deleted) return;\r\n else if(message.grouped_id && albumMustBeRenderedFull) { // will render only last album's message\r\n const storage = this.appMessagesManager.groupedMessagesStorage[message.grouped_id];\r\n const maxId = Math.max(...Object.keys(storage).map(i => +i));\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(this.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) {\r\n //this.log('not our message', message, message.pFlags.unread);\r\n if(message.pFlags.unread && this.unreadedObserver) {\r\n this.unreadedObserver.observe(bubble); \r\n if(!this.unreaded.indexOf(message.mid)) {\r\n this.unreaded.push(message.mid);\r\n }\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 bubbleContainer = contentWrapper.firstElementChild as HTMLDivElement;\r\n bubbleContainer.innerHTML = '';\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 }\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.timestamp = message.date;\r\n\r\n const loadPromises: Promise<any>[] = [];\r\n\r\n if(message._ === 'messageService') {\r\n let action = message.action;\r\n let _ = action._;\r\n if(IGNORE_ACTIONS.includes(_) || (langPack.hasOwnProperty(_) && !langPack[_])) {\r\n return bubble;\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 s.append(this.appMessagesManager.wrapMessageActionTextNew(message));\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 = message.media;\r\n\r\n let messageMessage: string, totalEntities: MessageEntity[];\r\n if(messageMedia?.document && !['video', 'gif'].includes(messageMedia.document.type)) {\r\n // * just filter these cases for documents caption\r\n } else if(message.grouped_id && albumMustBeRenderedFull) {\r\n const t = this.appMessagesManager.getAlbumText(message.grouped_id);\r\n messageMessage = t.message;\r\n //totalEntities = t.entities;\r\n totalEntities = t.totalEntities;\r\n } else if(messageMedia?.document?.type !== 'sticker') {\r\n messageMessage = message.message;\r\n //totalEntities = message.entities;\r\n totalEntities = message.totalEntities;\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 });\r\n\r\n let canHaveTail = true;\r\n \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: number, curr: any) => acc + curr.length, 0);\r\n \r\n if(emojiStrLength === strLength && emojiEntities.length <= 3) {\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 attachmentDiv.innerHTML = 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 canHaveTail = false;\r\n } else {\r\n messageDiv.innerHTML = richText;\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 } else {\r\n messageDiv.innerHTML = richText;\r\n }\r\n \r\n const timeSpan = MessageRender.setTime(this.chat, message, bubble, bubbleContainer, messageDiv);\r\n bubbleContainer.prepend(messageDiv);\r\n //bubble.prepend(timeSpan, messageDiv); // that's bad\r\n\r\n if(message.reply_markup && message.reply_markup._ === 'replyInlineMarkup' && message.reply_markup.rows && message.reply_markup.rows.length) {\r\n const rows = message.reply_markup.rows;\r\n\r\n const containerDiv = document.createElement('div');\r\n containerDiv.classList.add('reply-markup');\r\n rows.forEach((row: any) => {\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: any) => {\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 from = this.appUsersManager.getUser(message.fromId);\r\n const unsafe = !(from && from.pFlags && from.pFlags.verified);\r\n const url = RichTextProcessor.wrapUrl(button.url, unsafe);\r\n buttonEl = document.createElement('a');\r\n buttonEl.href = url;\r\n buttonEl.rel = 'noopener noreferrer';\r\n buttonEl.target = '_blank';\r\n buttonEl.classList.add('is-link', 'tgico');\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 buttonEl.innerHTML = text;\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 cancelEvent(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) return;\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 ? 'is-sent' : 'is-read';\r\n bubble.classList.add(status);\r\n }\r\n\r\n let messageWithReplies: Message.message;\r\n let withReplies: boolean;\r\n if(this.peerId === REPLIES_PEER_ID) {\r\n messageWithReplies = message;\r\n withReplies = true;\r\n } else {\r\n messageWithReplies = this.appMessagesManager.filterMessages(message, message => !!(message as Message.message).replies)[0] as any;\r\n withReplies = messageWithReplies && messageWithReplies.replies && messageWithReplies.replies.pFlags.comments && messageWithReplies.replies.channel_id !== 777;\r\n }\r\n\r\n if(withReplies) {\r\n bubble.classList.add('with-replies');\r\n }\r\n\r\n const isOut = our && (!message.fwd_from || this.peerId !== rootScope.myId);\r\n let nameContainer: HTMLElement = bubbleContainer;\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 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 bubble.classList.add('hide-name', 'photo');\r\n \r\n const storage = this.appMessagesManager.groupedMessagesStorage[message.grouped_id];\r\n if(message.grouped_id && Object.keys(storage).length !== 1 && albumMustBeRenderedFull) {\r\n bubble.classList.add('is-album', 'is-grouped');\r\n wrapAlbum({\r\n groupId: message.grouped_id, \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 noAutoDownload: this.chat.noAutoDownloadMedia,\r\n });\r\n \r\n break;\r\n }\r\n \r\n const withTail = !isAndroid && canHaveTail && !withReplies && USE_MEDIA_TAILS;\r\n if(withTail) bubble.classList.add('with-media-tail');\r\n wrapPhoto({\r\n 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 noAutoDownload: this.chat.noAutoDownloadMedia,\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 = messageMedia.webpage;\r\n ////////this.log('messageMediaWebPage', webpage);\r\n if(webpage._ === 'webPageEmpty') {\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 if(webpage.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 doc: any = null;\r\n if(webpage.document) {\r\n doc = webpage.document;\r\n \r\n if(doc.type === 'gif' || doc.type === 'video') {\r\n //if(doc.size <= 20e6) {\r\n bubble.classList.add('video');\r\n wrapVideo({\r\n doc, \r\n container: preview, \r\n message, \r\n boxWidth: mediaSizes.active.webpage.width,\r\n boxHeight: mediaSizes.active.webpage.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 noAutoDownload: this.chat.noAutoDownloadMedia,\r\n });\r\n //}\r\n } else {\r\n const docDiv = wrapDocument({\r\n message,\r\n noAutoDownload: this.chat.noAutoDownloadMedia,\r\n });\r\n preview.append(docDiv);\r\n preview.classList.add('preview-with-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 quote.append(previewResizer);\r\n }\r\n \r\n let quoteTextDiv = document.createElement('div');\r\n quoteTextDiv.classList.add('quote-text');\r\n\r\n if(webpage.site_name) {\r\n let nameEl = document.createElement('a');\r\n nameEl.classList.add('name');\r\n nameEl.setAttribute('target', '_blank');\r\n nameEl.href = webpage.url || '#';\r\n nameEl.innerHTML = RichTextProcessor.wrapEmojiText(webpage.site_name);\r\n quoteTextDiv.append(nameEl);\r\n }\r\n\r\n if(webpage.rTitle) {\r\n let titleDiv = document.createElement('div');\r\n titleDiv.classList.add('title');\r\n titleDiv.innerHTML = webpage.rTitle;\r\n quoteTextDiv.append(titleDiv);\r\n }\r\n\r\n if(webpage.rDescription) {\r\n let textDiv = document.createElement('div');\r\n textDiv.classList.add('text');\r\n textDiv.innerHTML = webpage.rDescription;\r\n quoteTextDiv.append(textDiv);\r\n }\r\n\r\n quote.append(quoteTextDiv);\r\n\r\n if(webpage.photo && !doc) {\r\n bubble.classList.add('photo');\r\n\r\n const size = webpage.photo.sizes[webpage.photo.sizes.length - 1];\r\n let isSquare = false;\r\n if(size.w === size.h && quoteTextDiv.childElementCount) {\r\n bubble.classList.add('is-square-photo');\r\n isSquare = true;\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: webpage.photo, \r\n message, \r\n container: preview, \r\n boxWidth: mediaSizes.active.webpage.width, \r\n boxHeight: 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 noAutoDownload: this.chat.noAutoDownloadMedia,\r\n });\r\n }\r\n \r\n box.append(quote);\r\n \r\n //bubble.prepend(box);\r\n messageDiv.insertBefore(box, messageDiv.lastElementChild);\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 let doc = messageMedia.document;\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 \r\n if(doc.animated) {\r\n bubble.classList.add('sticker-animated');\r\n }\r\n \r\n let size = bubble.classList.contains('emoji-big') ? 140 : 200;\r\n this.appPhotosManager.setAttachmentSize(doc, attachmentDiv, size, size);\r\n //let preloader = new ProgressivePreloader(attachmentDiv, false);\r\n bubbleContainer.style.height = attachmentDiv.style.height;\r\n bubbleContainer.style.width = attachmentDiv.style.width;\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\r\n break;\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 if(doc.type === 'round' || !messageMessage) {\r\n canHaveTail = false;\r\n }\r\n \r\n bubble.classList.add('hide-name', doc.type === 'round' ? 'round' : 'video');\r\n const storage = this.appMessagesManager.groupedMessagesStorage[message.grouped_id];\r\n if(message.grouped_id && Object.keys(storage).length !== 1 && albumMustBeRenderedFull) {\r\n bubble.classList.add('is-album', 'is-grouped');\r\n \r\n wrapAlbum({\r\n groupId: message.grouped_id, \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 noAutoDownload: this.chat.noAutoDownloadMedia,\r\n });\r\n } else {\r\n const withTail = !isAndroid && !isApple && doc.type !== 'round' && 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, \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 noAutoDownload: this.chat.noAutoDownloadMedia,\r\n });\r\n }\r\n \r\n break;\r\n } else {\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 noAutoDownload: this.chat.noAutoDownloadMedia\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\r\n bubble.classList.remove('is-message-empty');\r\n messageDiv.classList.add((doc.type !== 'photo' ? doc.type || 'document' : 'document') + '-message');\r\n processingWebPage = true;\r\n \r\n break;\r\n }\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 contactDiv = document.createElement('div');\r\n contactDiv.classList.add('contact');\r\n contactDiv.dataset.peerId = '' + messageMedia.user_id;\r\n\r\n messageDiv.classList.add('contact-message');\r\n processingWebPage = true;\r\n\r\n const texts = [];\r\n if(message.media.first_name) texts.push(RichTextProcessor.wrapEmojiText(message.media.first_name));\r\n if(message.media.last_name) texts.push(RichTextProcessor.wrapEmojiText(message.media.last_name));\r\n\r\n contactDiv.innerHTML = `\r\n <div class=\"contact-details\">\r\n <div class=\"contact-name\">${texts.join(' ')}</div>\r\n <div class=\"contact-number\">${message.media.phone_number ? '+' + formatPhoneNumber(message.media.phone_number).formatted : 'Unknown phone number'}</div>\r\n </div>`;\r\n\r\n const avatarElem = new AvatarElement();\r\n //avatarElem.lazyLoadQueue = this.lazyLoadQueue;\r\n avatarElem.setAttribute('peer', '' + message.media.user_id);\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.innerHTML = '<i class=\"media-not-supported\">This message is currently not supported on Telegram Web. Try <a href=\"https://desktop.telegram.org/\" target=\"_blank\">desktop.telegram.org</a></i>';\r\n messageDiv.append(timeSpan);\r\n this.log.warn('unrecognized media type:', message.media._, 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(this.chat.selection.isSelecting) {\r\n this.chat.selection.toggleBubbleCheckbox(bubble, true);\r\n }\r\n\r\n let savedFrom = '';\r\n \r\n const needName = (peerId < 0 && (peerId !== message.fromId || our)) && message.fromId !== rootScope.myId;\r\n if(needName || message.fwd_from || message.reply_to_mid) { // chat\r\n let title: HTMLSpanElement;\r\n\r\n const isForwardFromChannel = message.from_id && message.from_id._ === 'peerChannel' && message.fromId === message.fwdFromId;\r\n \r\n let isHidden = message.fwd_from && !message.fwd_from.from_id && !message.fwd_from.channel_id;\r\n if(isHidden) {\r\n ///////this.log('message to render hidden', message);\r\n title = document.createElement('span');\r\n title.innerHTML = RichTextProcessor.wrapEmojiText(message.fwd_from.from_name);\r\n title.classList.add('peer-title');\r\n //title = message.fwd_from.from_name;\r\n bubble.classList.add('hidden-profile');\r\n } else {\r\n title = new PeerTitle({peerId: message.fwdFromId || message.fromId}).element;\r\n }\r\n \r\n //this.log(title);\r\n \r\n if((message.fwdFromId || message.fwd_from)) {\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 }\r\n \r\n if(!bubble.classList.contains('sticker')) {\r\n let nameDiv = document.createElement('div');\r\n nameDiv.classList.add('name');\r\n nameDiv.dataset.peerId = message.fwdFromId;\r\n\r\n if(this.peerId === rootScope.myId || this.peerId === REPLIES_PEER_ID || isForwardFromChannel) {\r\n nameDiv.style.color = this.appPeersManager.getPeerColorById(message.fwdFromId, false);\r\n nameDiv.append(title);\r\n } else {\r\n /* const fromTitle = message.fromId === this.myID || appPeersManager.isBroadcast(message.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 nameDiv.append(i18n('ForwardedFrom', [title]));\r\n\r\n if(savedFrom) {\r\n nameDiv.dataset.savedFrom = savedFrom;\r\n }\r\n }\r\n \r\n nameContainer.append(nameDiv);\r\n }\r\n } else {\r\n if(!bubble.classList.contains('sticker') && needName) {\r\n let nameDiv = document.createElement('div');\r\n nameDiv.classList.add('name');\r\n nameDiv.append(title);\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 nameContainer.append(nameDiv);\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.reply_to_mid && message.reply_to_mid !== this.chat.threadId) {\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 const needAvatar = this.chat.isAnyGroup() && !isOut;\r\n if(needAvatar) {\r\n let avatarElem = new AvatarElement();\r\n //avatarElem.lazyLoadQueue = this.lazyLoadQueue;\r\n avatarElem.classList.add('user-avatar', 'avatar-40');\r\n avatarElem.loadPromises = loadPromises;\r\n\r\n if(!message.fwdFromId && message.fwd_from && message.fwd_from.from_name) {\r\n avatarElem.setAttribute('peer-title', /* '🔥 FF 🔥' */message.fwd_from.from_name);\r\n }\r\n\r\n avatarElem.setAttribute('peer', '' + (((message.fwd_from && (this.peerId === rootScope.myId || this.peerId === REPLIES_PEER_ID)) || isForwardFromChannel ? message.fwdFromId : message.fromId) || 0));\r\n //avatarElem.update();\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' || message.fwd_from.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 });\r\n\r\n if(isFooter) {\r\n canHaveTail = true;\r\n }\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 public performHistoryResult(history: 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 const historyStorage = this.appMessagesManager.getHistoryStorage(this.peerId, this.chat.threadId);\r\n if(history.includes(historyStorage.maxId)) {\r\n this.scrollable.loadedAll.bottom = true;\r\n }\r\n\r\n //console.time('appImManager render history');\r\n\r\n return new Promise<boolean>((resolve, reject) => {\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 const method = (reverse ? history.shift : history.pop).bind(history);\r\n\r\n //const padding = 10000;\r\n //const realLength = this.scrollable.container.childElementCount;\r\n let previousScrollHeightMinusTop: number/* , previousScrollHeight: number */;\r\n //if(realLength > 0/* && (reverse || isSafari) */) { // for safari need set when scrolling bottom too\r\n //if(!this.scrollable.isHeavyScrolling) {\r\n this.messagesQueueOnRender = () => {\r\n const {scrollTop, scrollHeight} = this.scrollable;\r\n\r\n //previousScrollHeight = scrollHeight;\r\n //previousScrollHeight = scrollHeight + padding;\r\n previousScrollHeightMinusTop = reverse ? scrollHeight - scrollTop : scrollTop;\r\n\r\n //this.chatInner.style.paddingTop = padding + 'px';\r\n /* if(reverse) {\r\n previousScrollHeightMinusTop = this.scrollable.scrollHeight - scrollTop;\r\n } else {\r\n previousScrollHeightMinusTop = scrollTop;\r\n } */\r\n\r\n /* if(DEBUG) {\r\n this.log('performHistoryResult: messagesQueueOnRender, scrollTop:', scrollTop, scrollHeight, previousScrollHeightMinusTop);\r\n } */\r\n this.messagesQueueOnRender = undefined;\r\n };\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 while(history.length) {\r\n let message = this.chat.getMessage(method());\r\n this.renderMessage(message, reverse, true);\r\n }\r\n\r\n (this.messagesQueuePromise || Promise.resolve())\r\n //.then(() => new Promise(resolve => setTimeout(resolve, 100)))\r\n .then(() => {\r\n if(previousScrollHeightMinusTop !== undefined) {\r\n /* const scrollHeight = this.scrollable.scrollHeight;\r\n const addedHeight = scrollHeight - previousScrollHeight;\r\n \r\n this.chatInner.style.paddingTop = (10000 - addedHeight) + 'px'; */\r\n /* const scrollHeight = this.scrollable.scrollHeight;\r\n const addedHeight = scrollHeight - previousScrollHeight;\r\n \r\n this.chatInner.style.paddingTop = (padding - addedHeight) + 'px';\r\n \r\n //const newScrollTop = reverse ? scrollHeight - previousScrollHeightMinusTop : previousScrollHeightMinusTop;\r\n const newScrollTop = reverse ? scrollHeight - addedHeight - previousScrollHeightMinusTop : previousScrollHeightMinusTop;\r\n this.log('performHistoryResult: will set scrollTop', \r\n previousScrollHeightMinusTop, this.scrollable.scrollHeight, \r\n newScrollTop, this.scrollable.container.clientHeight); */\r\n //const newScrollTop = reverse ? scrollHeight - previousScrollHeightMinusTop : previousScrollHeightMinusTop;\r\n const newScrollTop = reverse ? this.scrollable.scrollHeight - previousScrollHeightMinusTop : previousScrollHeightMinusTop;\r\n \r\n /* if(DEBUG) {\r\n this.log('performHistoryResult: will set up scrollTop:', newScrollTop, this.isHeavyAnimationInProgress);\r\n } */\r\n\r\n // touchSupport for safari iOS\r\n //isTouchSupported && isApple && (this.scrollable.container.style.overflow = 'hidden');\r\n this.scrollable.scrollTop = newScrollTop;\r\n //this.scrollable.scrollTop = this.scrollable.scrollHeight;\r\n //isTouchSupported && isApple && (this.scrollable.container.style.overflow = '');\r\n\r\n if(isSafari/* && !isAppleMobile */) { // * fix blinking and jumping\r\n reflowScrollableElement(this.scrollable.container);\r\n }\r\n\r\n /* if(DEBUG) {\r\n this.log('performHistoryResult: have set up scrollTop:', newScrollTop, this.scrollable.scrollTop, this.scrollable.scrollHeight, this.isHeavyAnimationInProgress);\r\n } */\r\n }\r\n\r\n resolve(true);\r\n }, reject);\r\n }).then(() => {\r\n //console.timeEnd('appImManager render history');\r\n\r\n //return new Promise<boolean>((resolve) => setTimeout(() => resolve(true), 300));\r\n return true;\r\n });\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.scrollable.loadedAll.top = true;\r\n this.scrollable.loadedAll.bottom = true;\r\n return {history: mids.slice().reverse()};\r\n });\r\n }\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 //console.time('appImManager call getHistory');\r\n const pageCount = Math.min(30, this.appPhotosManager.windowH / 38/* * 1.25 */ | 0);\r\n //const loadCount = Object.keys(this.bubbles).length > 0 ? 50 : pageCount;\r\n const realLoadCount = Object.keys(this.bubbles).length > 0/* || additionMsgId */ ? Math.max(40, pageCount) : pageCount;//const realLoadCount = 50;\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 if(historyStorage.history.length < loadCount && !historyStorage.history.slice.isEnd(SliceEnd.Both)) {\r\n additionMsgIds = historyStorage.history.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 = (historyResult: typeof result) => {\r\n if(this.chat.type === 'discussion' && 'offsetIdOffset' in historyResult) {\r\n //this.log('discussion got history', loadCount, backLimit, historyResult, isTopEnd);\r\n\r\n // * inject discussion start\r\n if(historyResult.history.isEnd(SliceEnd.Top)) {\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 this.scrollable.loadedAll.top = true;\r\n }\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 processResult(result);\r\n \r\n ////console.timeEnd('render history total');\r\n \r\n return getHeavyAnimationPromise().then(() => {\r\n return this.performHistoryResult(result.history || [], 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 this.scrollable.onScroll(); // нужно делать из-за ранней прогрузки\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 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 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.appMessagesManager.getServerMessageId(m)), \r\n bottomIds.map(m => this.appMessagesManager.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]) {\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 fastRaf(() => {\r\n setBubbles.forEach(contentWrapper => {\r\n contentWrapper.classList.remove('zoom-fade');\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(!isSafari) {\r\n this.needReflowScroll = true;\r\n }\r\n });\r\n }\r\n\r\n (promise || Promise.resolve()).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 /* false && */!isFirstMessageRender && promise.then(() => {\r\n if(reverse) {\r\n this.loadedTopTimes++;\r\n this.loadedBottomTimes = Math.max(0, --this.loadedBottomTimes);\r\n } else {\r\n this.loadedBottomTimes++;\r\n this.loadedTopTimes = Math.max(0, --this.loadedTopTimes);\r\n }\r\n\r\n let ids: number[];\r\n if((reverse && this.loadedTopTimes > 2) || (!reverse && this.loadedBottomTimes > 2)) {\r\n ids = getObjectKeysAndSort(this.bubbles);\r\n }\r\n\r\n //let removeCount = loadCount / 2;\r\n const safeCount = realLoadCount * 2; // cause i've been runningrunningrunning all day\r\n //this.log('getHistory: slice loadedTimes:', reverse, pageCount, this.loadedTopTimes, this.loadedBottomTimes, ids?.length, safeCount);\r\n if(ids && ids.length > safeCount) {\r\n if(reverse) {\r\n //ids = ids.slice(-removeCount);\r\n //ids = ids.slice(removeCount * 2);\r\n ids = ids.slice(safeCount);\r\n this.scrollable.loadedAll.bottom = false;\r\n\r\n //this.log('getHistory: slice bottom messages:', ids.length, loadCount);\r\n //this.getHistoryBottomPromise = undefined; // !WARNING, это нужно для обратной загрузки истории, если запрос словил флуд\r\n } else {\r\n //ids = ids.slice(0, removeCount);\r\n //ids = ids.slice(0, ids.length - (removeCount * 2));\r\n ids = ids.slice(0, ids.length - safeCount);\r\n this.scrollable.loadedAll.top = false;\r\n\r\n //this.log('getHistory: slice up messages:', ids.length, loadCount);\r\n //this.getHistoryTopPromise = undefined; // !WARNING, это нужно для обратной загрузки истории, если запрос словил флуд\r\n }\r\n\r\n //this.log('getHistory: will slice ids:', ids, reverse);\r\n\r\n this.deleteMessagesByIds(ids, false);\r\n }\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 = 1 + +!!this.stickyIntersector;\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 }\r\n }\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","/*\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 appChatsManager from \"../../lib/appManagers/appChatsManager\";\r\nimport appMessagesManager from \"../../lib/appManagers/appMessagesManager\";\r\nimport rootScope from \"../../lib/rootScope\";\r\nimport { addCancelButton, PopupButton } from \".\";\r\nimport PopupPeer from \"./peer\";\r\nimport { ChatType } from \"../chat/chat\";\r\nimport { i18n, LangPackKey } from \"../../lib/langPack\";\r\nimport PeerTitle from \"../peerTitle\";\r\n\r\nexport default class PopupDeleteMessages {\r\n constructor(peerId: number, mids: number[], type: ChatType, onConfirm?: () => void) {\r\n const peerTitleElement = new PeerTitle({\r\n peerId,\r\n onlyFirstName: true\r\n }).element;\r\n\r\n mids = mids.slice();\r\n const callback = (revoke?: true) => {\r\n onConfirm && onConfirm();\r\n if(type === 'scheduled') {\r\n appMessagesManager.deleteScheduledMessages(peerId, mids);\r\n } else {\r\n appMessagesManager.deleteMessages(peerId, mids, revoke);\r\n }\r\n };\r\n\r\n let title: LangPackKey, titleArgs: any[], description: LangPackKey, descriptionArgs: any[], buttons: PopupButton[];\r\n if(mids.length === 1) {\r\n title = 'DeleteSingleMessagesTitle';\r\n } else {\r\n title = 'DeleteMessagesTitle';\r\n titleArgs = [i18n('messages', [mids.length])];\r\n }\r\n \r\n description = mids.length === 1 ? 'AreYouSureDeleteSingleMessage' : 'AreYouSureDeleteFewMessages';\r\n\r\n buttons = [{\r\n langKey: 'Delete',\r\n isDanger: true,\r\n callback: () => callback()\r\n }];\r\n\r\n if(peerId === rootScope.myId || type === 'scheduled') {\r\n \r\n } else {\r\n if(peerId > 0) {\r\n buttons.push({\r\n langKey: 'DeleteMessagesOptionAlso',\r\n langArgs: [peerTitleElement],\r\n isDanger: true,\r\n callback: () => callback(true)\r\n });\r\n } else {\r\n const chat = appChatsManager.getChat(-peerId);\r\n\r\n const hasRights = appChatsManager.hasRights(-peerId, 'delete_messages');\r\n if(chat._ === 'chat') {\r\n const canRevoke = hasRights ? mids.slice() : mids.filter(mid => {\r\n const message = appMessagesManager.getMessageByPeer(peerId, mid);\r\n return message.fromId === rootScope.myId;\r\n });\r\n\r\n if(canRevoke.length) {\r\n if(canRevoke.length === mids.length) {\r\n buttons.push({\r\n langKey: 'DeleteForAll',\r\n isDanger: true,\r\n callback: () => callback(true)\r\n });\r\n } else {\r\n buttons.push({\r\n langKey: 'DeleteMessagesOption',\r\n isDanger: true,\r\n callback: () => callback(true)\r\n });\r\n\r\n description = 'DeleteMessagesTextGroup';\r\n descriptionArgs = [i18n('messages', [canRevoke.length])];\r\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}\".`;\r\n }\r\n }\r\n } else {\r\n buttons[0].callback = () => callback(true);\r\n }\r\n }\r\n }\r\n\r\n addCancelButton(buttons);\r\n\r\n const popup = new PopupPeer('popup-delete-chat', {\r\n peerId,\r\n titleLangKey: title,\r\n titleLangArgs: titleArgs,\r\n descriptionLangKey: description,\r\n descriptionLangArgs: descriptionArgs,\r\n buttons\r\n });\r\n\r\n popup.show();\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 appMessagesManager from \"../../lib/appManagers/appMessagesManager\";\r\nimport { addCancelButton, PopupButton } from \".\";\r\nimport PopupPeer from \"./peer\";\r\nimport appPeersManager from \"../../lib/appManagers/appPeersManager\";\r\nimport rootScope from \"../../lib/rootScope\";\r\nimport { LangPackKey } from \"../../lib/langPack\";\r\nimport appChatsManager from \"../../lib/appManagers/appChatsManager\";\r\nimport PeerTitle from \"../peerTitle\";\r\n\r\nexport default class PopupPinMessage {\r\n constructor(peerId: number, mid: number, unpin?: true, onConfirm?: () => void) {\r\n let title: LangPackKey, description: LangPackKey, buttons: PopupButton[] = [];\r\n\r\n const canUnpin = appPeersManager.canPinMessage(peerId);\r\n\r\n const callback = (oneSide?: true, silent?: true) => {\r\n setTimeout(() => { // * костыль, потому что document.elementFromPoint вернёт popup-peer пока он будет закрываться\r\n let promise: Promise<any>;\r\n if(unpin && !mid) {\r\n if(canUnpin) {\r\n promise = appMessagesManager.unpinAllMessages(peerId);\r\n } else {\r\n promise = appMessagesManager.hidePinnedMessages(peerId);\r\n }\r\n } else {\r\n promise = appMessagesManager.updatePinnedMessage(peerId, mid, unpin, silent, oneSide);\r\n }\r\n\r\n if(onConfirm) {\r\n promise.then(onConfirm);\r\n }\r\n }, 300);\r\n };\r\n\r\n if(unpin) {\r\n let buttonText: LangPackKey = 'UnpinMessage';\r\n if(!mid) {\r\n if(canUnpin) {\r\n title = 'Popup.Unpin.AllTitle';\r\n description = 'Chat.UnpinAllMessagesConfirmation';\r\n } else {\r\n title = 'Popup.Unpin.HideTitle';\r\n description = 'Popup.Unpin.HideDescription';\r\n buttonText = 'Popup.Unpin.Hide';\r\n }\r\n } else {\r\n title = 'UnpinMessageAlertTitle';\r\n description = 'Chat.Confirm.Unpin';\r\n }\r\n \r\n buttons.push({\r\n langKey: buttonText,\r\n isDanger: true,\r\n callback: () => callback()\r\n });\r\n } else {\r\n title = 'PinMessageAlertTitle';\r\n const pinButtonText: LangPackKey = 'PinMessage';\r\n \r\n if(peerId < 0) {\r\n buttons.push({\r\n langKey: pinButtonText,\r\n callback: () => callback()\r\n });\r\n\r\n if(appChatsManager.isBroadcast(-peerId)) {\r\n description = 'PinMessageAlertChannel';\r\n } else {\r\n description = 'PinMessageAlert';\r\n \r\n buttons.push({\r\n langKey: 'PinNotify',\r\n callback: () => callback(undefined, true)\r\n });\r\n }\r\n } else {\r\n description = 'PinMessageAlertChat';\r\n\r\n if(peerId === rootScope.myId) {\r\n buttons.push({\r\n langKey: pinButtonText,\r\n callback: () => callback()\r\n });\r\n } else {\r\n buttons.push({\r\n langKey: pinButtonText,\r\n callback: () => callback(true)\r\n });\r\n \r\n buttons.push({\r\n langKey: 'PinAlsoFor',\r\n langArgs: [new PeerTitle({peerId, onlyFirstName: true}).element],\r\n callback: () => callback()\r\n });\r\n }\r\n }\r\n }\r\n\r\n addCancelButton(buttons);\r\n\r\n const popup = new PopupPeer('popup-delete-chat', {\r\n peerId,\r\n titleLangKey: title,\r\n descriptionLangKey: description,\r\n buttons\r\n });\r\n\r\n popup.show();\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 appMessagesManager from \"../../lib/appManagers/appMessagesManager\";\r\nimport { PopupButton } from \".\";\r\nimport PopupPeer from \"./peer\";\r\n\r\nexport default class PopupSendNow {\r\n constructor(peerId: number, mids: number[], onConfirm?: () => void) {\r\n let title: string, description: string, buttons: PopupButton[] = [];\r\n\r\n title = `Send Message${mids.length > 1 ? 's' : ''} Now`;\r\n description = mids.length > 1 ? 'Send ' + mids.length + ' messages now?' : 'Send message now?';\r\n\r\n const callback = () => {\r\n onConfirm && onConfirm();\r\n appMessagesManager.sendScheduledMessages(peerId, mids);\r\n };\r\n\r\n buttons.push({\r\n text: 'SEND',\r\n callback\r\n });\r\n\r\n buttons.push({\r\n text: 'CANCEL',\r\n isCancel: true\r\n });\r\n\r\n const popup = new PopupPeer('popup-delete-chat', {\r\n peerId,\r\n title,\r\n description,\r\n buttons\r\n });\r\n\r\n popup.show();\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 { AppMessagesManager } from \"../../lib/appManagers/appMessagesManager\";\r\nimport type { AppChatsManager } from \"../../lib/appManagers/appChatsManager\";\r\nimport type { AppPeersManager } from \"../../lib/appManagers/appPeersManager\";\r\nimport type { AppPollsManager, Poll } from \"../../lib/appManagers/appPollsManager\";\r\nimport type Chat from \"./chat\";\r\nimport { isTouchSupported } from \"../../helpers/touchSupport\";\r\nimport { attachClickEvent, cancelEvent, cancelSelection, isSelectionEmpty } from \"../../helpers/dom\";\r\nimport ButtonMenu, { ButtonMenuItemOptions } from \"../buttonMenu\";\r\nimport { attachContextMenuListener, 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, { LangPackKey } from \"../../lib/langPack\";\r\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\r\n\r\nexport default class ChatContextMenu {\r\n private buttons: (ButtonMenuItemOptions & {verify: () => boolean, notDirect?: () => boolean, withSelection?: true})[];\r\n private element: HTMLElement;\r\n\r\n private isSelectable: boolean;\r\n private target: HTMLElement;\r\n private isTargetAGroupedItem: boolean;\r\n private isTextSelected: boolean;\r\n private isAnchorTarget: boolean;\r\n public peerId: number;\r\n public mid: number;\r\n public message: any;\r\n\r\n constructor(private attachTo: HTMLElement, private chat: Chat, private appMessagesManager: AppMessagesManager, private appChatsManager: AppChatsManager, private appPeersManager: AppPeersManager, private appPollsManager: AppPollsManager) {\r\n const onContextMenu = (e: MouseEvent | Touch) => {\r\n if(this.init) {\r\n this.init();\r\n this.init = null;\r\n }\r\n\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) return;\r\n\r\n if(e instanceof MouseEvent) e.preventDefault();\r\n if(this.element.classList.contains('active')) {\r\n return false;\r\n }\r\n if(e instanceof MouseEvent) e.cancelBubble = true;\r\n\r\n let mid = +bubble.dataset.mid;\r\n if(!mid) return;\r\n\r\n // * если открыть контекстное меню для альбома не по бабблу, и последний элемент не выбран, чтобы показать остальные пункты\r\n if(chat.selection.isSelecting && !contentWrapper) {\r\n const mids = this.chat.getMidsByMid(mid);\r\n if(mids.length > 1) {\r\n const selectedMid = chat.selection.selectedMids.has(mid) ? mid : mids.find(mid => chat.selection.selectedMids.has(mid));\r\n if(selectedMid) {\r\n mid = selectedMid;\r\n }\r\n }\r\n }\r\n\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' && (this.target as HTMLAnchorElement).target === '_blank';\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.message = this.chat.getMessage(this.mid);\r\n\r\n this.buttons.forEach(button => {\r\n let good: boolean;\r\n\r\n //if((appImManager.chatSelection.isSelecting && !button.withSelection) || (button.withSelection && !appImManager.chatSelection.isSelecting)) {\r\n if(chat.selection.isSelecting && !button.withSelection) {\r\n good = false;\r\n } else {\r\n good = contentWrapper || isTouchSupported ? \r\n button.verify() : \r\n button.notDirect && button.verify() && button.notDirect();\r\n }\r\n\r\n button.element.classList.toggle('hide', !good);\r\n });\r\n\r\n const side: 'left' | 'right' = bubble.classList.contains('is-in') ? 'left' : 'right';\r\n //bubble.parentElement.append(this.element);\r\n //appImManager.log('contextmenu', e, bubble, side);\r\n positionMenu(e, this.element, side);\r\n openBtnMenu(this.element, () => {\r\n this.peerId = this.mid = 0;\r\n this.target = null;\r\n });\r\n };\r\n\r\n if(isTouchSupported) {\r\n attachClickEvent(attachTo, (e) => {\r\n if(chat.selection.isSelecting) {\r\n return;\r\n }\r\n\r\n const className = (e.target as HTMLElement).className;\r\n if(!className || !className.includes) return;\r\n\r\n chat.log('touchend', e);\r\n\r\n const good = ['bubble', 'bubble-content-wrapper', 'bubble-content', 'message', 'time', 'inner'].find(c => className.match(new RegExp(c + '($|\\\\s)')));\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 }\r\n }, {listenerSetter: this.chat.bubbles.listenerSetter});\r\n\r\n attachContextMenuListener(attachTo, (e) => {\r\n if(chat.selection.isSelecting) return;\r\n\r\n // * these two lines will fix instant text selection on iOS Safari\r\n document.body.classList.add('no-select'); // * need no-select on body because chat-input transforms in channels\r\n attachTo.addEventListener('touchend', (e) => {\r\n cancelEvent(e); // ! this one will fix propagation to document loader button, etc\r\n document.body.classList.remove('no-select');\r\n\r\n //this.chat.bubbles.onBubblesClick(e);\r\n }, {once: true, capture: true});\r\n\r\n cancelSelection();\r\n //cancelEvent(e as any);\r\n const bubble = findUpClassName(e.target, 'grouped-item') || findUpClassName(e.target, 'bubble');\r\n if(bubble) {\r\n chat.selection.toggleByBubble(bubble);\r\n }\r\n }, this.chat.bubbles.listenerSetter);\r\n } else attachContextMenuListener(attachTo, onContextMenu, this.chat.bubbles.listenerSetter);\r\n }\r\n\r\n private init() {\r\n this.buttons = [{\r\n icon: 'send2',\r\n text: 'Chat.Context.Scheduled.SendNow',\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.chat.selection.selectedMids.has(this.mid) && !this.chat.selection.selectionSendNowBtn.hasAttribute('disabled'),\r\n notDirect: () => true,\r\n withSelection: true\r\n }, {\r\n icon: 'schedule',\r\n text: 'Chat.Context.Scheduled.Reschedule',\r\n onClick: () => {\r\n this.chat.input.scheduleSending(() => {\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.peerId > 0 || this.appChatsManager.hasRights(-this.peerId, 'send_messages')) && \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.message.message && !this.isTextSelected\r\n }, {\r\n icon: 'copy',\r\n text: 'Chat.CopySelectedText',\r\n onClick: this.onCopyClick,\r\n verify: () => !!this.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: () => this.chat.selection.selectedMids.has(this.mid) && !![...this.chat.selection.selectedMids].find(mid => !!this.chat.getMessage(mid).message),\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: 'link',\r\n text: 'CopyLink',\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.pFlags.pinned && this.appPeersManager.canPinMessage(this.peerId),\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.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.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,\r\n verify: () => this.chat.type !== 'scheduled' && !this.message.pFlags.is_outgoing && 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.chat.selection.selectedMids.has(this.mid) && \r\n !this.chat.selection.selectionForwardBtn.hasAttribute('disabled'),\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.action && !this.chat.selection.selectedMids.has(this.mid) && 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.chat.selection.selectedMids.has(this.mid),\r\n notDirect: () => true,\r\n withSelection: 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.chat.selection.selectedMids.has(this.mid) && !this.chat.selection.selectionDeleteBtn.hasAttribute('disabled'),\r\n notDirect: () => true,\r\n withSelection: true\r\n }];\r\n\r\n this.element = ButtonMenu(this.buttons, this.chat.bubbles.listenerSetter);\r\n this.element.id = 'bubble-contextmenu';\r\n this.element.classList.add('contextmenu');\r\n this.chat.container.append(this.element);\r\n };\r\n\r\n private onSendScheduledClick = () => {\r\n if(this.chat.selection.isSelecting) {\r\n this.chat.selection.selectionSendNowBtn.click();\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 ? [...this.chat.selection.selectedMids] : [this.mid];\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 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 const username = this.appPeersManager.getPeerUsername(this.peerId);\r\n const msgId = this.appMessagesManager.getServerMessageId(this.mid);\r\n let url = 'https://t.me/';\r\n let key: LangPackKey;\r\n if(username) {\r\n url += username + '/' + msgId;\r\n key = 'LinkCopied';\r\n } else {\r\n url += 'c/' + Math.abs(this.peerId) + '/' + msgId;\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 this.chat.selection.selectionForwardBtn.click();\r\n } else {\r\n new PopupForward(this.peerId, this.isTargetAGroupedItem ? [this.mid] : this.chat.getMidsByMid(this.mid));\r\n }\r\n };\r\n\r\n private onSelectClick = () => {\r\n this.chat.selection.toggleByBubble(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 this.chat.selection.selectionDeleteBtn.click();\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 * 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, EmoticonsTab } from \"..\";\r\nimport findUpClassName from \"../../../helpers/dom/findUpClassName\";\r\nimport { fastRaf } from \"../../../helpers/schedulers\";\r\nimport appImManager from \"../../../lib/appManagers/appImManager\";\r\nimport appStateManager from \"../../../lib/appManagers/appStateManager\";\r\nimport Config from \"../../../lib/config\";\r\nimport { i18n, LangPackKey } from \"../../../lib/langPack\";\r\nimport { RichTextProcessor } from \"../../../lib/richtextprocessor\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport { putPreloader } from \"../../misc\";\r\nimport Scrollable from \"../../scrollable\";\r\nimport StickyIntersector from \"../../stickyIntersector\";\r\n\r\nexport default class EmojiTab implements EmoticonsTab {\r\n public content: HTMLElement;\r\n\r\n private recent: string[] = [];\r\n private recentItemsDiv: HTMLElement;\r\n\r\n private scroll: Scrollable;\r\n private stickyIntersector: StickyIntersector;\r\n\r\n private loadedURLs: Set<string> = new Set();\r\n\r\n init() {\r\n this.content = document.getElementById('content-emoji') as HTMLDivElement;\r\n\r\n const categories: LangPackKey[] = [\r\n 'Emoji.SmilesAndPeople', \r\n 'Emoji.AnimalsAndNature', \r\n 'Emoji.FoodAndDrink', \r\n 'Emoji.TravelAndPlaces', \r\n 'Emoji.ActivityAndSport', \r\n 'Emoji.Objects', \r\n /* 'Emoji.Symbols', */\r\n 'Emoji.Flags', \r\n 'Skin Tones' as any\r\n ];\r\n const divs: {\r\n [category in LangPackKey]?: HTMLDivElement\r\n } = {};\r\n\r\n const sorted: Map<LangPackKey, string[]> = new Map([\r\n [\r\n 'Emoji.Recent',\r\n []\r\n ]\r\n ]);\r\n\r\n for(const emoji in Config.Emoji) {\r\n const details = Config.Emoji[emoji];\r\n const i = '' + details;\r\n const category = categories[+i[0] - 1];\r\n if(!category) continue; // maybe it's skin tones\r\n\r\n let s = sorted.get(category);\r\n if(!s) {\r\n s = [];\r\n sorted.set(category, s);\r\n }\r\n \r\n s[+i.slice(1) || 0] = emoji;\r\n }\r\n\r\n //console.log('emoticons sorted:', sorted);\r\n\r\n //Object.keys(sorted).forEach(c => sorted[c].sort((a, b) => a - b));\r\n\r\n sorted.delete(categories.pop());\r\n\r\n //console.time('emojiParse');\r\n sorted.forEach((emojis, category) => {\r\n const div = document.createElement('div');\r\n div.classList.add('emoji-category');\r\n\r\n const titleDiv = document.createElement('div');\r\n titleDiv.classList.add('category-title');\r\n titleDiv.append(i18n(category));\r\n\r\n const itemsDiv = document.createElement('div');\r\n itemsDiv.classList.add('category-items');\r\n\r\n div.append(titleDiv, itemsDiv);\r\n\r\n emojis.forEach(emoji => {\r\n /* if(emojiUnicode(emoji) === '1f481-200d-2642') {\r\n console.log('append emoji', emoji, emojiUnicode(emoji));\r\n } */\r\n\r\n emoji = emoji.split('-').reduce((prev, curr) => prev + String.fromCodePoint(parseInt(curr, 16)), '');\r\n\r\n this.appendEmoji(emoji/* .replace(/[\\ufe0f\\u2640\\u2642\\u2695]/g, '') */, itemsDiv, false/* , false */);\r\n\r\n /* if(category === 'Smileys & Emotion') {\r\n console.log('appended emoji', emoji, itemsDiv.children[itemsDiv.childElementCount - 1].innerHTML, emojiUnicode(emoji));\r\n } */\r\n });\r\n\r\n divs[category] = div;\r\n });\r\n\r\n //console.timeEnd('emojiParse');\r\n\r\n const menu = this.content.previousElementSibling as HTMLElement;\r\n const emojiScroll = this.scroll = new Scrollable(this.content, 'EMOJI');\r\n\r\n //emojiScroll.setVirtualContainer(emojiScroll.container);\r\n\r\n const preloader = putPreloader(this.content, true);\r\n\r\n Promise.all([\r\n new Promise((resolve) => setTimeout(resolve, 200)),\r\n\r\n appStateManager.getState().then(state => {\r\n if(Array.isArray(state.recentEmoji)) {\r\n this.recent = state.recentEmoji;\r\n }\r\n })\r\n ]).then(() => {\r\n preloader.remove();\r\n\r\n this.recentItemsDiv = divs['Emoji.Recent'].querySelector('.category-items');\r\n for(const emoji of this.recent) {\r\n this.appendEmoji(emoji, this.recentItemsDiv);\r\n }\r\n\r\n this.recentItemsDiv.parentElement.classList.toggle('hide', !this.recent.length);\r\n\r\n categories.unshift('Emoji.Recent');\r\n categories.map(category => {\r\n const div = divs[category];\r\n \r\n if(!div) {\r\n console.error('no div by category:', category);\r\n }\r\n \r\n emojiScroll.container.append(div);\r\n this.stickyIntersector.observeStickyHeaderChanges(div);\r\n return div;\r\n });\r\n });\r\n\r\n this.content.addEventListener('click', this.onContentClick);\r\n this.stickyIntersector = EmoticonsDropdown.menuOnClick(menu, emojiScroll);\r\n this.init = null;\r\n }\r\n\r\n private appendEmoji(emoji: string, container: HTMLElement, prepend = false/* , unified = false */) {\r\n //const emoji = details.unified;\r\n //const emoji = (details.unified as string).split('-')\r\n //.reduce((prev, curr) => prev + String.fromCodePoint(parseInt(curr, 16)), '');\r\n\r\n const spanEmoji = document.createElement('span');\r\n spanEmoji.classList.add('category-item');\r\n\r\n let kek: string;\r\n /* if(unified) {\r\n kek = RichTextProcessor.wrapRichText('_', {\r\n entities: [{\r\n _: 'messageEntityEmoji',\r\n offset: 0,\r\n length: emoji.split('-').length,\r\n unicode: emoji\r\n }]\r\n });\r\n } else { */\r\n kek = RichTextProcessor.wrapEmojiText(emoji);\r\n //}\r\n\r\n /* if(!kek.includes('emoji')) {\r\n console.log(emoji, kek, spanEmoji, emoji.length, new TextEncoder().encode(emoji), emojiUnicode(emoji));\r\n return;\r\n } */\r\n \r\n //console.log(kek);\r\n \r\n spanEmoji.innerHTML = kek;\r\n\r\n if(spanEmoji.children.length > 1) {\r\n const first = spanEmoji.firstElementChild;\r\n spanEmoji.innerHTML = '';\r\n spanEmoji.append(first);\r\n }\r\n\r\n if(spanEmoji.firstElementChild && !RichTextProcessor.emojiSupported) {\r\n const image = spanEmoji.firstElementChild as HTMLImageElement;\r\n image.setAttribute('loading', 'lazy');\r\n\r\n const url = image.src;\r\n if(!this.loadedURLs.has(url)) {\r\n const placeholder = document.createElement('span');\r\n placeholder.classList.add('emoji-placeholder');\r\n \r\n if(rootScope.settings.animationsEnabled) {\r\n image.style.opacity = '0';\r\n placeholder.style.opacity = '1';\r\n }\r\n \r\n image.addEventListener('load', () => {\r\n fastRaf(() => {\r\n if(rootScope.settings.animationsEnabled) {\r\n image.style.opacity = '';\r\n placeholder.style.opacity = '';\r\n }\r\n \r\n spanEmoji.classList.remove('empty');\r\n \r\n this.loadedURLs.add(url);\r\n });\r\n }, {once: true});\r\n \r\n spanEmoji.append(placeholder);\r\n }\r\n }\r\n \r\n //spanEmoji = spanEmoji.firstElementChild as HTMLSpanElement;\r\n //spanEmoji.setAttribute('emoji', emoji);\r\n if(prepend) container.prepend(spanEmoji);\r\n else container.appendChild(spanEmoji);\r\n }\r\n\r\n private getEmojiFromElement(element: HTMLElement) {\r\n if(element.nodeType === 3) return element.nodeValue;\r\n if(element.tagName === 'SPAN' && !element.classList.contains('emoji')) {\r\n element = element.firstElementChild as HTMLElement;\r\n }\r\n \r\n return element.getAttribute('alt') || element.innerText;\r\n }\r\n\r\n onContentClick = (e: MouseEvent) => {\r\n let target = e.target as HTMLElement;\r\n //if(target.tagName !== 'SPAN') return;\r\n\r\n if(target.tagName === 'SPAN' && !target.classList.contains('emoji')) {\r\n target = findUpClassName(target, 'category-item');\r\n if(!target) {\r\n return;\r\n }\r\n\r\n target = target.firstChild as HTMLElement;\r\n } else if(target.tagName === 'DIV') return;\r\n\r\n //console.log('contentEmoji div', target);\r\n appImManager.chat.input.messageInput.innerHTML += RichTextProcessor.emojiSupported ? \r\n (target.nodeType === 3 ? target.nodeValue : target.innerHTML) : \r\n target.outerHTML;\r\n\r\n // Recent\r\n const emoji = this.getEmojiFromElement(target);\r\n (Array.from(this.recentItemsDiv.children) as HTMLElement[]).forEach((el, idx) => {\r\n const _emoji = this.getEmojiFromElement(el);\r\n if(emoji === _emoji) {\r\n el.remove();\r\n }\r\n });\r\n const scrollHeight = this.recentItemsDiv.scrollHeight;\r\n this.appendEmoji(emoji, this.recentItemsDiv, true);\r\n\r\n this.recent.findAndSplice(e => e === emoji);\r\n this.recent.unshift(emoji);\r\n if(this.recent.length > 36) {\r\n this.recent.length = 36;\r\n }\r\n\r\n this.recentItemsDiv.parentElement.classList.toggle('hide', !this.recent.length);\r\n\r\n appStateManager.pushToState('recentEmoji', this.recent);\r\n\r\n // Append to input\r\n const event = new Event('input', {bubbles: true, cancelable: true});\r\n appImManager.chat.input.messageInput.dispatchEvent(event);\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 { calcImageInBox } from \"../helpers/dom\";\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 { CancellablePromise, deferredPromise } from \"../helpers/cancellablePromise\";\r\nimport renderImageFromUrl from \"../helpers/dom/renderImageFromUrl\";\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\r\n constructor(private element: HTMLElement, private group: string, private scrollable: Scrollable) {\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 let timeout = 0;\r\n // memory leak\r\n scrollable.container.addEventListener('scroll', () => {\r\n if(timeout) {\r\n clearTimeout(timeout);\r\n } else {\r\n this.scrollPromise = deferredPromise<void>();\r\n //animationIntersector.checkAnimations(true, group);\r\n }\r\n\r\n timeout = window.setTimeout(() => {\r\n timeout = 0;\r\n this.scrollPromise.resolve();\r\n //animationIntersector.checkAnimations(false, group);\r\n }, 150);\r\n });\r\n }\r\n\r\n 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 processInvisibleDiv = async(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 new Promise((resolve) => {\r\n window.requestAnimationFrame(() => window.requestAnimationFrame(resolve));\r\n });\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) {\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 {w, h} = 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 = w + '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 this.element.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\r\n if(!gotThumb.thumb.url) {\r\n gotThumb.promise.then(() => {\r\n img.src = gotThumb.thumb.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?.thumb?.url ? renderImageFromUrl(img, gotThumb.thumb.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 public 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 * 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 { readBlobAsText } from \"../../../helpers/blob\";\r\nimport renderImageFromUrl from \"../../../helpers/dom/renderImageFromUrl\";\r\nimport mediaSizes from \"../../../helpers/mediaSizes\";\r\nimport { MessagesAllStickers, StickerSet } from \"../../../layer\";\r\nimport appDocsManager, { MyDocument } from \"../../../lib/appManagers/appDocsManager\";\r\nimport appDownloadManager from \"../../../lib/appManagers/appDownloadManager\";\r\nimport appStickersManager from \"../../../lib/appManagers/appStickersManager\";\r\nimport lottieLoader from \"../../../lib/lottieLoader\";\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 Scrollable, { ScrollableX } from \"../../scrollable\";\r\nimport StickyIntersector from \"../../stickyIntersector\";\r\nimport { wrapSticker } from \"../../wrappers\";\r\n\r\nexport class SuperStickerRenderer {\r\n lazyLoadQueue: LazyLoadQueueRepeat;\r\n 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 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.sticker === 2) {\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\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.sticker === 2,\r\n loadPromises\r\n });\r\n\r\n return div;\r\n }\r\n\r\n 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 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 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 public 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: 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 titleDiv.innerHTML = categoryTitle;\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\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\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 if(stickerSet.set.thumbs?.length) {\r\n EmoticonsDropdown.lazyLoadQueue.push({\r\n div: button,\r\n load: () => {\r\n const downloadOptions = appStickersManager.getStickerSetThumbDownloadOptions(stickerSet.set);\r\n const promise = appDownloadManager.download(downloadOptions);\r\n\r\n if(stickerSet.set.pFlags.animated) {\r\n return promise\r\n .then(readBlobAsText)\r\n //.then(JSON.parse)\r\n .then(json => {\r\n lottieLoader.loadAnimationWorker({\r\n container: button,\r\n loop: true,\r\n autoplay: false,\r\n animationData: json,\r\n width: 32,\r\n height: 32,\r\n needUpscale: true\r\n }, EMOTICONSSTICKERGROUP);\r\n });\r\n } else {\r\n const image = new Image();\r\n \r\n return promise.then(blob => {\r\n renderImageFromUrl(image, URL.createObjectURL(blob), () => {\r\n button.append(image);\r\n });\r\n });\r\n }\r\n }\r\n });\r\n } else if(stickerSet.documents[0]._ !== 'documentEmpty') { // as thumb will be used first sticker\r\n wrapSticker({\r\n doc: stickerSet.documents[0],\r\n div: button as any, \r\n group: EMOTICONSSTICKERGROUP,\r\n lazyLoadQueue: EmoticonsDropdown.lazyLoadQueue\r\n }); // kostil\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');\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.on('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.on('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', EmoticonsDropdown.onMediaClick);\r\n\r\n this.scroll = new Scrollable(this.content, 'STICKERS');\r\n this.scroll.setVirtualContainer(this.stickersDiv);\r\n\r\n this.stickyIntersector = EmoticonsDropdown.menuOnClick(this.menu, this.scroll, menuScroll);\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 this.categoryPush(this.recentDiv, 'Recent', Promise.resolve(this.recentStickers), true);\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 });\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 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 * 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 } from \"../../layer\";\r\nimport appPeersManager from \"./appPeersManager\";\r\nimport apiManagerProxy from \"../mtproto/mtprotoworker\";\r\nimport { RichTextProcessor } from \"../richtextprocessor\";\r\nimport appDocsManager from \"./appDocsManager\";\r\nimport appPhotosManager from \"./appPhotosManager\";\r\nimport appUsersManager from \"./appUsersManager\";\r\nimport appMessagesManager from \"./appMessagesManager\";\r\n\r\nexport class AppInlineBotsManager {\r\n private inlineResults: {[qId: string]: BotInlineResult} = {};\r\n\r\n public getInlineResults(peerId: number, botId: number, query = '', offset = '', geo?: any) {\r\n return apiManagerProxy.invokeApi('messages.getInlineBotResults', {\r\n bot: appUsersManager.getUserInput(botId),\r\n peer: appPeersManager.getInputPeerById(peerId),\r\n query: query,\r\n geo_point: (geo && {_: 'inputGeoPoint', lat: geo['lat'], long: geo['long']}) || undefined,\r\n offset\r\n }, {/* timeout: 1, */stopTime: -1, noErrorBox: true}).then(botResults => {\r\n const queryId = botResults.query_id;\r\n /* delete botResults._;\r\n delete 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 const qId = queryId + '_' + result.id;\r\n /* result.qID = qID;\r\n result.botID = botID;\r\n \r\n result.rTitle = RichTextProcessor.wrapRichText(result.title, {noLinebreaks: true, noLinks: true});\r\n result.rDescription = RichTextProcessor.wrapRichText(result.description, {noLinebreaks: true, noLinks: true});\r\n result.initials = ((result as botInlineResult).url || result.title || result.type || '').substr(0, 1); */\r\n\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[qId] = result;\r\n });\r\n\r\n return botResults;\r\n });\r\n }\r\n \r\n /* function getPopularBots () {\r\n return Storage.get('inline_bots_popular').then(function (bots) {\r\n var result = []\r\n var i, len\r\n var userId\r\n if (bots && bots.length) {\r\n var now = tsNow(true)\r\n for (i = 0, len = bots.length; i < len; i++) {\r\n if ((now - bots[i][3]) > 14 * 86400) {\r\n continue\r\n }\r\n userId = bots[i][0]\r\n if (!AppUsersManager.hasUser(userId)) {\r\n AppUsersManager.saveApiUser(bots[i][1])\r\n }\r\n result.push({id: userId, rate: bots[i][2], date: bots[i][3]})\r\n }\r\n }\r\n return result\r\n })\r\n }\r\n \r\n function pushPopularBot (id) {\r\n getPopularBots().then(function (bots) {\r\n var exists = false\r\n var count = bots.length\r\n var result = []\r\n for (var i = 0; i < count; i++) {\r\n if (bots[i].id === id) {\r\n exists = true\r\n bots[i].rate++\r\n bots[i].date = tsNow(true)\r\n }\r\n var user = AppUsersManager.getUser(bots[i].id)\r\n result.push([bots[i].id, user, bots[i].rate, bots[i].date])\r\n }\r\n if (exists) {\r\n result.sort(function (a, b) {\r\n return b[2] - a[2]\r\n })\r\n } else {\r\n if (result.length > 15) {\r\n result = result.slice(0, 15)\r\n }\r\n result.push([id, AppUsersManager.getUser(id), 1, tsNow(true)])\r\n }\r\n ConfigStorage.set({inline_bots_popular: result})\r\n \r\n rootScope.$broadcast('inline_bots_popular')\r\n })\r\n }\r\n \r\n function resolveInlineMention (username) {\r\n return AppPeersManager.resolveUsername(username).then(function (peerId) {\r\n if (peerId > 0) {\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 function switchToPM (fromPeerID, botID, startParam) {\r\n var peerString = AppPeersManager.getPeerString(fromPeerID)\r\n var setHash = {}\r\n setHash['inline_switch_pm' + botID] = {peer: peerString, time: tsNow()}\r\n Storage.set(setHash)\r\n rootScope.$broadcast('history_focus', {peerString: AppPeersManager.getPeerString(botID)})\r\n AppMessagesManager.startBot(botID, 0, startParam)\r\n }\r\n \r\n function checkSwitchReturn (botID) {\r\n var bot = AppUsersManager.getUser(botID)\r\n if (!bot || !bot.pFlags.bot || !bot.bot_inline_placeholder) {\r\n return qSync.when(false)\r\n }\r\n var key = 'inline_switch_pm' + botID\r\n return Storage.get(key).then(function (peerData) {\r\n if (peerData) {\r\n Storage.remove(key)\r\n if (tsNow() - peerData.time < 3600000) {\r\n return peerData.peer\r\n }\r\n }\r\n return false\r\n })\r\n }\r\n \r\n function switchInlineQuery (botID, toPeerString, query) {\r\n rootScope.$broadcast('history_focus', {\r\n peerString: toPeerString,\r\n attachment: {\r\n _: 'inline_query',\r\n mention: '@' + AppUsersManager.getUser(botID).username,\r\n query: query\r\n }\r\n })\r\n }\r\n \r\n function switchInlineButtonClick (id, button) {\r\n var message = AppMessagesManager.getMessage(id)\r\n var botID = message.viaBotId || message.fromId\r\n if (button.pFlags && button.pFlags.same_peer) {\r\n var peerId = AppMessagesManager.getMessagePeer(message)\r\n var toPeerString = AppPeersManager.getPeerString(peerId)\r\n switchInlineQuery(botID, toPeerString, button.query)\r\n return\r\n }\r\n return checkSwitchReturn(botID).then(function (retPeerString) {\r\n if (retPeerString) {\r\n return switchInlineQuery(botID, retPeerString, button.query)\r\n }\r\n PeersSelectService.selectPeer({\r\n canSend: true\r\n }).then(function (toPeerString) {\r\n return switchInlineQuery(botID, toPeerString, button.query)\r\n })\r\n })\r\n } */\r\n \r\n public callbackButtonClick(peerId: number, mid: number, button: any) {\r\n return apiManagerProxy.invokeApi('messages.getBotCallbackAnswer', {\r\n peer: appPeersManager.getInputPeerById(peerId),\r\n msg_id: appMessagesManager.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 function sendInlineResult (peerId, qID, options) {\r\n var inlineResult = inlineResults[qID]\r\n if (inlineResult === undefined) {\r\n return false\r\n }\r\n pushPopularBot(inlineResult.botID)\r\n var splitted = qID.split('_')\r\n var queryID = splitted.shift()\r\n var resultID = splitted.join('_')\r\n options = options || {}\r\n options.viaBotId = inlineResult.botID\r\n options.queryID = queryID\r\n options.resultID = resultID\r\n if (inlineResult.send_message.reply_markup) {\r\n options.reply_markup = 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 var caption = ''\r\n var inputMedia = false\r\n switch (inlineResult.send_message._) {\r\n case 'botInlineMessageMediaAuto':\r\n caption = inlineResult.send_message.caption\r\n if (inlineResult._ === 'botInlineMediaResult') {\r\n var doc = inlineResult.document\r\n var photo = inlineResult.photo\r\n if (doc) {\r\n inputMedia = {\r\n _: 'inputMediaDocument',\r\n id: {_: 'inputDocument', id: doc.id, access_hash: doc.access_hash},\r\n caption: caption\r\n }\r\n } else {\r\n inputMedia = {\r\n _: 'inputMediaPhoto',\r\n id: {_: 'inputPhoto', id: photo.id, access_hash: photo.access_hash},\r\n caption: caption\r\n }\r\n }\r\n }\r\n break\r\n \r\n case 'botInlineMessageMediaGeo':\r\n inputMedia = {\r\n _: 'inputMediaGeoPoint',\r\n geo_point: {\r\n _: 'inputGeoPoint',\r\n 'lat': inlineResult.send_message.geo['lat'],\r\n 'long': inlineResult.send_message.geo['long']\r\n }\r\n }\r\n break\r\n \r\n case 'botInlineMessageMediaVenue':\r\n inputMedia = {\r\n _: 'inputMediaVenue',\r\n geo_point: {\r\n _: 'inputGeoPoint',\r\n 'lat': inlineResult.send_message.geo['lat'],\r\n 'long': inlineResult.send_message.geo['long']\r\n },\r\n title: inlineResult.send_message.title,\r\n address: inlineResult.send_message.address,\r\n provider: inlineResult.send_message.provider,\r\n venue_id: inlineResult.send_message.venue_id\r\n }\r\n break\r\n \r\n case 'botInlineMessageMediaContact':\r\n inputMedia = {\r\n _: 'inputMediaContact',\r\n phone_number: inlineResult.send_message.phone_number,\r\n first_name: inlineResult.send_message.first_name,\r\n last_name: inlineResult.send_message.last_name\r\n }\r\n break\r\n }\r\n if (!inputMedia) {\r\n inputMedia = {\r\n _: 'messageMediaPending',\r\n type: inlineResult.type,\r\n file_name: inlineResult.title || inlineResult.content_url || inlineResult.url,\r\n size: 0,\r\n progress: {percent: 30, total: 0}\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\nexport default appInlineBotsManager;","/*\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 { attachClickEvent } from \"../../../helpers/dom\";\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\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: number;\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.lazyLoadQueue.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;\r\n }\r\n\r\n try {\r\n this.searchPromise = appInlineBotsManager.getInlineResults(0, 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 { attachClickEvent } from \"../../../helpers/dom\";\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 { forEachReverse } from \"../../../helpers/array\";\r\nimport { i18n } from \"../../../lib/langPack\";\r\nimport findUpClassName from \"../../../helpers/dom/findUpClassName\";\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 = `\r\n <div class=\"sticker-set-name\">${RichTextProcessor.wrapEmojiText(set.title)}</div>\r\n `;\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 { isTouchSupported } from \"../../helpers/touchSupport\";\r\nimport appChatsManager from \"../../lib/appManagers/appChatsManager\";\r\nimport appImManager from \"../../lib/appManagers/appImManager\";\r\nimport rootScope from \"../../lib/rootScope\";\r\nimport { attachClickEvent, blurActiveElement, whichChild } from \"../../helpers/dom\";\r\nimport animationIntersector from \"../animationIntersector\";\r\nimport { horizontalMenu } from \"../horizontalMenu\";\r\nimport LazyLoadQueue, { LazyLoadQueueIntersector } from \"../lazyLoadQueue\";\r\nimport Scrollable, { ScrollableX } from \"../scrollable\";\r\nimport appSidebarRight from \"../sidebarRight\";\r\nimport StickyIntersector from \"../stickyIntersector\";\r\nimport EmojiTab from \"./tabs/emoji\";\r\nimport GifsTab from \"./tabs/gifs\";\r\nimport StickersTab from \"./tabs/stickers\";\r\nimport { pause } from \"../../helpers/schedulers\";\r\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\r\nimport AppGifsTab from \"../sidebarRight/tabs/gifs\";\r\nimport AppStickersTab from \"../sidebarRight/tabs/stickers\";\r\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\r\nimport findUpTag from \"../../helpers/dom/findUpTag\";\r\nimport ListenerSetter from \"../../helpers/listenerSetter\";\r\n\r\nexport const EMOTICONSSTICKERGROUP = 'emoticons-dropdown';\r\n\r\nexport interface EmoticonsTab {\r\n init: () => void,\r\n onCloseAfterTimeout?: () => void\r\n}\r\n\r\nconst KEEP_OPEN = false;\r\nconst TOGGLE_TIMEOUT = 200;\r\nconst ANIMATION_DURATION = 200;\r\n\r\nexport class EmoticonsDropdown {\r\n public static lazyLoadQueue = new LazyLoadQueue();\r\n private element: HTMLElement;\r\n\r\n public emojiTab: EmojiTab;\r\n public stickersTab: StickersTab;\r\n public gifsTab: GifsTab;\r\n\r\n private container: HTMLElement;\r\n private tabsEl: HTMLElement;\r\n private tabId = -1;\r\n\r\n private tabs: {[id: number]: EmoticonsTab};\r\n\r\n public searchButton: HTMLElement;\r\n public deleteBtn: HTMLElement;\r\n \r\n private displayTimeout: number;\r\n\r\n public events: {\r\n onClose: Array<() => void>,\r\n onCloseAfter: Array<() => void>,\r\n onOpen: Array<() => void>,\r\n onOpenAfter: Array<() => void>\r\n } = {\r\n onClose: [],\r\n onCloseAfter: [],\r\n onOpen: [],\r\n onOpenAfter: []\r\n };\r\n\r\n private selectTab: ReturnType<typeof horizontalMenu>;\r\n private forceClose = false;\r\n\r\n constructor() {\r\n this.element = document.getElementById('emoji-dropdown') as HTMLDivElement;\r\n }\r\n\r\n public attachButtonListener(button: HTMLElement, listenerSetter: ListenerSetter) {\r\n let firstTime = true;\r\n if(isTouchSupported) {\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.element.classList.contains('active')) return;\r\n\r\n const toElement = (e as any).toElement as Element;\r\n if(toElement && findUpClassName(toElement, 'emoji-dropdown')) {\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 private init() {\r\n this.emojiTab = new EmojiTab();\r\n this.stickersTab = new StickersTab();\r\n this.gifsTab = new GifsTab();\r\n\r\n this.tabs = {\r\n 0: this.emojiTab,\r\n 1: this.stickersTab,\r\n 2: this.gifsTab\r\n };\r\n\r\n this.container = this.element.querySelector('.emoji-container .tabs-container') as HTMLDivElement;\r\n this.tabsEl = this.element.querySelector('.emoji-tabs') as HTMLUListElement;\r\n this.selectTab = horizontalMenu(this.tabsEl, this.container, this.onSelectTabClick, () => {\r\n const tab = this.tabs[this.tabId];\r\n if(tab.init) {\r\n tab.init();\r\n }\r\n\r\n tab.onCloseAfterTimeout && tab.onCloseAfterTimeout();\r\n animationIntersector.checkAnimations(false, EMOTICONSSTICKERGROUP);\r\n });\r\n\r\n this.searchButton = this.element.querySelector('.emoji-tabs-search');\r\n this.searchButton.addEventListener('click', () => {\r\n if(this.tabId === 1) {\r\n if(!appSidebarRight.isTabExists(AppStickersTab)) {\r\n new AppStickersTab(appSidebarRight).open();\r\n }\r\n } else {\r\n if(!appSidebarRight.isTabExists(AppGifsTab)) {\r\n new AppGifsTab(appSidebarRight).open();\r\n }\r\n }\r\n });\r\n\r\n this.deleteBtn = this.element.querySelector('.emoji-tabs-delete');\r\n this.deleteBtn.addEventListener('click', () => {\r\n const input = appImManager.chat.input.messageInput;\r\n if((input.lastChild as any)?.tagName) {\r\n input.lastElementChild.remove();\r\n } else if(input.lastChild) {\r\n if(!input.lastChild.textContent.length) {\r\n input.lastChild.remove();\r\n } else {\r\n input.lastChild.textContent = input.lastChild.textContent.slice(0, -1);\r\n }\r\n }\r\n\r\n const event = new Event('input', {bubbles: true, cancelable: true});\r\n appImManager.chat.input.messageInput.dispatchEvent(event);\r\n //appSidebarRight.stickersTab.init();\r\n });\r\n\r\n (this.tabsEl.children[1] as HTMLLIElement).click(); // set emoji tab\r\n if(this.tabs[0].init) {\r\n this.tabs[0].init(); // onTransitionEnd не вызовется, т.к. это первая открытая вкладка\r\n }\r\n\r\n rootScope.on('peer_changed', this.checkRights);\r\n this.checkRights();\r\n\r\n if(!isTouchSupported) {\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 private onSelectTabClick = (id: number) => {\r\n if(this.tabId === id) {\r\n return;\r\n }\r\n \r\n animationIntersector.checkAnimations(true, EMOTICONSSTICKERGROUP);\r\n\r\n this.tabId = id;\r\n this.searchButton.classList.toggle('hide', this.tabId === 0);\r\n this.deleteBtn.classList.toggle('hide', this.tabId !== 0);\r\n };\r\n\r\n public checkRights = () => {\r\n const peerId = appImManager.chat.peerId;\r\n const children = this.tabsEl.children;\r\n const tabsElements = Array.from(children) as HTMLElement[];\r\n\r\n const canSendStickers = peerId > 0 || appChatsManager.hasRights(peerId, 'send_stickers');\r\n tabsElements[2].toggleAttribute('disabled', !canSendStickers);\r\n\r\n const canSendGifs = peerId > 0 || appChatsManager.hasRights(peerId, 'send_gifs');\r\n tabsElements[3].toggleAttribute('disabled', !canSendGifs);\r\n\r\n const active = this.tabsEl.querySelector('.active');\r\n if(active && whichChild(active) !== 1 && (!canSendStickers || !canSendGifs)) {\r\n this.selectTab(0, false);\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(isTouchSupported) {\r\n if(willBeActive) {\r\n //appImManager.chat.input.saveScroll();\r\n if(blurActiveElement()) {\r\n await pause(100);\r\n }\r\n }\r\n }\r\n\r\n if(this.element.parentElement !== appImManager.chat.input.chatInput) {\r\n appImManager.chat.input.chatInput.append(this.element);\r\n }\r\n \r\n if((this.element.style.display && enable === undefined) || enable) {\r\n this.events.onOpen.forEach(cb => cb());\r\n\r\n EmoticonsDropdown.lazyLoadQueue.lock();\r\n //EmoticonsDropdown.lazyLoadQueue.unlock();\r\n animationIntersector.lockIntersectionGroup(EMOTICONSSTICKERGROUP);\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 animationIntersector.unlockIntersectionGroup(EMOTICONSSTICKERGROUP);\r\n EmoticonsDropdown.lazyLoadQueue.unlock();\r\n EmoticonsDropdown.lazyLoadQueue.refresh();\r\n\r\n this.forceClose = false;\r\n this.container.classList.remove('disable-hover');\r\n\r\n this.events.onOpenAfter.forEach(cb => cb());\r\n }, isTouchSupported ? 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.events.onClose.forEach(cb => cb());\r\n\r\n EmoticonsDropdown.lazyLoadQueue.lock();\r\n //EmoticonsDropdown.lazyLoadQueue.lock();\r\n\r\n // нужно залочить группу и выключить стикеры\r\n animationIntersector.lockIntersectionGroup(EMOTICONSSTICKERGROUP);\r\n animationIntersector.checkAnimations(true, EMOTICONSSTICKERGROUP);\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\r\n // теперь можно убрать visible, чтобы они не включились после фокуса\r\n animationIntersector.unlockIntersectionGroup(EMOTICONSSTICKERGROUP);\r\n EmoticonsDropdown.lazyLoadQueue.unlock();\r\n EmoticonsDropdown.lazyLoadQueue.refresh();\r\n\r\n this.forceClose = false;\r\n this.container.classList.remove('disable-hover');\r\n\r\n this.events.onCloseAfter.forEach(cb => cb());\r\n }, isTouchSupported ? 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 static menuOnClick = (menu: HTMLElement, scroll: Scrollable, menuScroll?: ScrollableX) => {\r\n let prevId = 0;\r\n let jumpedTo = -1;\r\n\r\n const setActive = (id: number) => {\r\n if(id === prevId) {\r\n return false;\r\n }\r\n\r\n menu.children[prevId].classList.remove('active');\r\n menu.children[id].classList.add('active');\r\n prevId = id;\r\n\r\n return true;\r\n };\r\n\r\n const stickyIntersector = new StickyIntersector(scroll.container, (stuck, target) => {\r\n //console.log('sticky scrollTOp', stuck, target, scroll.container.scrollTop);\r\n\r\n if(Math.abs(jumpedTo - scroll.container.scrollTop) <= 1) {\r\n return;\r\n } else {\r\n jumpedTo = -1;\r\n }\r\n\r\n const which = whichChild(target);\r\n if(!stuck && which) { // * due to stickyIntersector\r\n return;\r\n }\r\n\r\n setActive(which);\r\n\r\n if(menuScroll) {\r\n if(which < menu.childElementCount - 4) {\r\n menuScroll.container.scrollLeft = (which - 3) * 47;\r\n } else {\r\n menuScroll.container.scrollLeft = which * 47;\r\n }\r\n }\r\n });\r\n\r\n menu.addEventListener('click', (e) => {\r\n let target = e.target as HTMLElement;\r\n target = findUpClassName(target, 'menu-horizontal-div-item');\r\n\r\n if(!target) {\r\n return;\r\n }\r\n\r\n const which = whichChild(target);\r\n\r\n /* if(menuScroll) {\r\n menuScroll.scrollIntoView(target, false, 0);\r\n } */\r\n\r\n if(!setActive(which)) {\r\n return;\r\n }\r\n\r\n const element = (scroll.splitUp || scroll.container).children[which] as HTMLElement;\r\n const offsetTop = element.offsetTop + 1; // * due to stickyIntersector\r\n\r\n scroll.container.scrollTop = jumpedTo = offsetTop;\r\n\r\n //console.log('set scrollTop:', offsetTop);\r\n });\r\n\r\n return stickyIntersector;\r\n };\r\n\r\n public static onMediaClick = (e: MouseEvent, clearDraft = false) => {\r\n let target = e.target as HTMLElement;\r\n target = findUpTag(target, 'DIV');\r\n\r\n if(!target) return;\r\n \r\n const fileId = target.dataset.docId;\r\n if(!fileId) return;\r\n\r\n if(appImManager.chat.input.sendMessageWithDocument(fileId, undefined, clearDraft)) {\r\n /* dropdown.classList.remove('active');\r\n toggleEl.classList.remove('active'); */\r\n emoticonsDropdown.forceClose = true;\r\n emoticonsDropdown.container.classList.add('disable-hover');\r\n emoticonsDropdown.toggle(false);\r\n } else {\r\n console.warn('got no doc by id:', fileId);\r\n }\r\n };\r\n\r\n public addLazyLoadQueueRepeat(lazyLoadQueue: LazyLoadQueueIntersector, processInvisibleDiv: (div: HTMLElement) => void) {\r\n this.events.onClose.push(() => {\r\n lazyLoadQueue.lock();\r\n });\r\n\r\n this.events.onCloseAfter.push(() => {\r\n const divs = lazyLoadQueue.intersector.getVisible();\r\n\r\n for(const div of divs) {\r\n processInvisibleDiv(div);\r\n }\r\n\r\n lazyLoadQueue.intersector.clearVisible();\r\n });\r\n\r\n this.events.onOpenAfter.push(() => {\r\n lazyLoadQueue.unlockAndRefresh();\r\n });\r\n }\r\n}\r\n\r\nconst emoticonsDropdown = new EmoticonsDropdown();\r\nMOUNT_CLASS_TO.emoticonsDropdown = emoticonsDropdown;\r\nexport default emoticonsDropdown;\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\";\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: number) {\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 { Poll } from \"../../lib/appManagers/appPollsManager\";\r\nimport type Chat from \"../chat/chat\";\r\nimport PopupElement from \".\";\r\nimport { cancelEvent, getRichValue, isInputEmpty, whichChild } from \"../../helpers/dom\";\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 { MessageEntity } from \"../../layer\";\r\nimport I18n, { _i18n, i18n } from \"../../lib/langPack\";\r\nimport findUpTag from \"../../helpers/dom/findUpTag\";\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: 'NewPoll.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.questionInputField.input.addEventListener('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.multipleCheckboxField.input.addEventListener('change', () => {\r\n const checked = this.multipleCheckboxField.input.checked;\r\n this.quizCheckboxField.input.toggleAttribute('disabled', checked);\r\n });\r\n\r\n this.quizCheckboxField.input.addEventListener('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.questionInputField.input.addEventListener('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 this.btnConfirm.addEventListener('click', this.onSubmitClick);\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);\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 quizSolutionEntities: MessageEntity[] = [];\r\n const quizSolution = getRichValue(this.quizSolutionField.input, quizSolutionEntities) || undefined;\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 quizSolutionEntities: MessageEntity[] = [];\r\n const quizSolution = getRichValue(this.quizSolutionField.input, quizSolutionEntities) || undefined;\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.btnClose.click();\r\n this.btnConfirm.removeEventListener('click', this.onSubmitClick);\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 threadId: this.chat.threadId,\r\n replyToMsgId: this.chat.input.replyToMsgId,\r\n scheduleDate: this.chat.input.scheduleDate,\r\n silent: this.chat.input.sendSilent\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 questionField.input.addEventListener('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 questionField.input.addEventListener('click', cancelEvent);\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 radioField.input.addEventListener('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 deleteBtn.addEventListener('click', this.onDeleteClick, {once: true});\r\n\r\n this.questions.append(radioField.label);\r\n\r\n this.scrollable.scrollIntoViewNew(this.questions.lastElementChild as HTMLElement, 'center');\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","/*\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 { calcImageInBox, placeCaretAtEnd, isSendShortcutPressed } from \"../../helpers/dom\";\r\nimport InputField from \"../inputField\";\r\nimport PopupElement from \".\";\r\nimport Scrollable from \"../scrollable\";\r\nimport { toast } from \"../toast\";\r\nimport { prepareAlbum, wrapDocument } from \"../wrappers\";\r\nimport CheckboxField from \"../checkboxField\";\r\nimport SendContextMenu from \"../chat/sendContextMenu\";\r\nimport { createPosterFromVideo, onVideoLoad } from \"../../helpers/files\";\r\nimport { MyDocument } from \"../../lib/appManagers/appDocsManager\";\r\nimport I18n, { i18n, LangPackKey } from \"../../lib/langPack\";\r\n\r\ntype SendFileParams = Partial<{\r\n file: File,\r\n objectURL: string,\r\n thumbBlob: Blob,\r\n thumbURL: string,\r\n width: number,\r\n height: number,\r\n duration: number\r\n}>;\r\n\r\nconst MAX_LENGTH_CAPTION = 1024;\r\n\r\n// TODO: .gif upload as video\r\n\r\nexport default class PopupNewMedia extends PopupElement {\r\n private input: HTMLElement;\r\n private mediaContainer: HTMLElement;\r\n private groupCheckboxField: CheckboxField;\r\n private wasInputValue = '';\r\n\r\n private willAttach: Partial<{\r\n type: 'media' | 'document',\r\n isMedia: true,\r\n group: boolean,\r\n sendFileDetails: SendFileParams[]\r\n }> = {\r\n sendFileDetails: [],\r\n group: false\r\n };\r\n inputField: InputField;\r\n\r\n constructor(private chat: Chat, files: File[], willAttachType: PopupNewMedia['willAttach']['type']) {\r\n super('popup-send-photo popup-new-media', null, {closable: true, withConfirm: 'Modal.Send'});\r\n\r\n this.willAttach.type = willAttachType;\r\n\r\n this.btnConfirm.addEventListener('click', () => this.send());\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.mediaContainer = document.createElement('div');\r\n this.mediaContainer.classList.add('popup-photo');\r\n const scrollable = new Scrollable(null);\r\n scrollable.container.append(this.mediaContainer);\r\n \r\n this.inputField = new InputField({\r\n placeholder: 'PreviewSender.CaptionPlaceholder',\r\n label: 'Caption',\r\n name: 'photo-caption',\r\n maxLength: MAX_LENGTH_CAPTION,\r\n showLengthOn: 80\r\n });\r\n this.input = this.inputField.input;\r\n\r\n this.inputField.value = this.wasInputValue = this.chat.input.messageInputField.value;\r\n this.chat.input.messageInputField.value = '';\r\n\r\n this.container.append(scrollable.container);\r\n\r\n if(files.length > 1) {\r\n this.groupCheckboxField = new CheckboxField({\r\n text: 'PreviewSender.GroupItems', \r\n name: 'group-items'\r\n });\r\n this.container.append(this.groupCheckboxField.label, this.inputField.container);\r\n \r\n this.groupCheckboxField.input.checked = true;\r\n this.willAttach.group = true;\r\n\r\n this.groupCheckboxField.input.addEventListener('change', () => {\r\n const checked = this.groupCheckboxField.input.checked;\r\n \r\n this.willAttach.group = checked;\r\n this.willAttach.sendFileDetails.length = 0;\r\n\r\n //this.mediaContainer.innerHTML = '';\r\n //this.container.classList.remove('is-media', 'is-document', 'is-album');\r\n this.attachFiles(files);\r\n });\r\n }\r\n \r\n this.container.append(this.inputField.container);\r\n\r\n this.attachFiles(files);\r\n }\r\n\r\n private onKeyDown = (e: KeyboardEvent) => {\r\n const target = e.target as HTMLElement;\r\n if(target !== this.input) {\r\n this.input.focus();\r\n placeCaretAtEnd(this.input);\r\n }\r\n \r\n if(isSendShortcutPressed(e)) {\r\n this.btnConfirm.click();\r\n }\r\n };\r\n\r\n public send(force = false) {\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 let caption = this.inputField.value;\r\n if(caption.length > MAX_LENGTH_CAPTION) {\r\n toast(I18n.format('Error.PreviewSender.CaptionTooLong', true));\r\n return;\r\n }\r\n\r\n this.hide();\r\n const willAttach = this.willAttach;\r\n willAttach.isMedia = willAttach.type === 'media' ? true : undefined;\r\n\r\n //console.log('will send files with options:', willAttach);\r\n\r\n const peerId = this.chat.peerId;\r\n const input = this.chat.input;\r\n const silent = input.sendSilent;\r\n const scheduleDate = input.scheduleDate;\r\n\r\n if(willAttach.sendFileDetails.length > 1 && willAttach.group) {\r\n for(let i = 0; i < willAttach.sendFileDetails.length;) {\r\n let firstType = willAttach.sendFileDetails[i].file.type.split('/')[0];\r\n for(var k = 0; k < 10 && i < willAttach.sendFileDetails.length; ++i, ++k) {\r\n const type = willAttach.sendFileDetails[i].file.type.split('/')[0];\r\n if(firstType !== type) {\r\n break;\r\n }\r\n }\r\n\r\n const w = {...willAttach};\r\n w.sendFileDetails = willAttach.sendFileDetails.slice(i - k, i);\r\n\r\n this.chat.appMessagesManager.sendAlbum(peerId, w.sendFileDetails.map(d => d.file), Object.assign({\r\n caption,\r\n replyToMsgId: input.replyToMsgId,\r\n threadId: this.chat.threadId,\r\n isMedia: willAttach.isMedia,\r\n silent,\r\n scheduleDate,\r\n clearDraft: true as true\r\n }, w));\r\n\r\n caption = undefined;\r\n input.replyToMsgId = this.chat.threadId;\r\n }\r\n } else {\r\n if(caption) {\r\n if(willAttach.sendFileDetails.length > 1) {\r\n this.chat.appMessagesManager.sendText(peerId, caption, {\r\n replyToMsgId: input.replyToMsgId, \r\n threadId: this.chat.threadId,\r\n silent, \r\n scheduleDate,\r\n clearDraft: true\r\n });\r\n caption = '';\r\n //input.replyToMsgId = undefined;\r\n }\r\n }\r\n \r\n const promises = willAttach.sendFileDetails.map(params => {\r\n const promise = this.chat.appMessagesManager.sendFile(peerId, params.file, Object.assign({\r\n //isMedia: willAttach.isMedia, \r\n isMedia: willAttach.isMedia, \r\n caption,\r\n replyToMsgId: input.replyToMsgId,\r\n threadId: this.chat.threadId,\r\n silent,\r\n scheduleDate,\r\n clearDraft: true as true\r\n }, params));\r\n\r\n caption = '';\r\n return promise;\r\n });\r\n\r\n input.replyToMsgId = this.chat.threadId;\r\n }\r\n\r\n //Promise.all(promises);\r\n\r\n //appMessagesManager.sendFile(appImManager.peerId, willAttach.file, willAttach);\r\n \r\n input.onMessageSent();\r\n }\r\n\r\n public attachFile = (file: File) => {\r\n const willAttach = this.willAttach;\r\n return new Promise<HTMLDivElement>((resolve) => {\r\n const params: SendFileParams = {};\r\n params.file = file;\r\n //console.log('selected file:', file, typeof(file), willAttach);\r\n const itemDiv = document.createElement('div');\r\n switch(willAttach.type) {\r\n case 'media': {\r\n const isVideo = file.type.indexOf('video/') === 0;\r\n\r\n itemDiv.classList.add('popup-item-media');\r\n\r\n if(isVideo) {\r\n const video = document.createElement('video');\r\n const source = document.createElement('source');\r\n source.src = params.objectURL = URL.createObjectURL(file);\r\n video.autoplay = true;\r\n video.controls = false;\r\n video.muted = true;\r\n video.setAttribute('playsinline', 'true');\r\n\r\n video.addEventListener('timeupdate', () => {\r\n video.pause();\r\n }, {once: true});\r\n\r\n onVideoLoad(video).then(() => {\r\n params.width = video.videoWidth;\r\n params.height = video.videoHeight;\r\n params.duration = Math.floor(video.duration);\r\n\r\n itemDiv.append(video);\r\n createPosterFromVideo(video).then(blob => {\r\n params.thumbBlob = blob;\r\n params.thumbURL = URL.createObjectURL(blob);\r\n resolve(itemDiv);\r\n });\r\n });\r\n\r\n video.append(source);\r\n } else {\r\n const img = new Image();\r\n img.src = params.objectURL = URL.createObjectURL(file);\r\n img.onload = () => {\r\n params.width = img.naturalWidth;\r\n params.height = img.naturalHeight;\r\n\r\n itemDiv.append(img);\r\n resolve(itemDiv);\r\n };\r\n }\r\n \r\n break;\r\n }\r\n\r\n case 'document': {\r\n const isPhoto = file.type.indexOf('image/') !== -1;\r\n const isAudio = file.type.indexOf('audio/') !== -1;\r\n if(isPhoto || isAudio) {\r\n params.objectURL = URL.createObjectURL(file);\r\n }\r\n\r\n const docDiv = wrapDocument({\r\n message: {\r\n _: 'message',\r\n pFlags: {\r\n is_outgoing: true\r\n },\r\n mid: 0,\r\n peerId: 0,\r\n media: {\r\n _: 'messageMediaDocument',\r\n document: {\r\n _: 'document',\r\n file: file,\r\n file_name: file.name || '',\r\n size: file.size,\r\n type: isPhoto ? 'photo' : 'doc',\r\n url: params.objectURL,\r\n downloaded: true\r\n } as MyDocument\r\n }\r\n } as any\r\n });\r\n\r\n const finish = () => {\r\n itemDiv.append(docDiv);\r\n resolve(itemDiv);\r\n };\r\n\r\n if(isPhoto) {\r\n const img = new Image();\r\n img.src = params.objectURL;\r\n img.onload = () => {\r\n params.width = img.naturalWidth;\r\n params.height = img.naturalHeight;\r\n\r\n finish();\r\n };\r\n\r\n img.onerror = finish;\r\n } else {\r\n finish();\r\n }\r\n\r\n break;\r\n }\r\n }\r\n\r\n willAttach.sendFileDetails.push(params);\r\n });\r\n };\r\n\r\n public attachFiles(files: File[]) {\r\n const container = this.container;\r\n const willAttach = this.willAttach;\r\n\r\n /* if(files.length > 10 && willAttach.type === 'media') {\r\n willAttach.type = 'document';\r\n } */\r\n\r\n files = files.filter(file => {\r\n if(willAttach.type === 'media') {\r\n return ['image/', 'video/'].find(s => file.type.indexOf(s) === 0);\r\n } else {\r\n return true;\r\n }\r\n });\r\n\r\n Promise.all(files.map(this.attachFile)).then(results => {\r\n this.container.classList.remove('is-media', 'is-document', 'is-album');\r\n this.mediaContainer.innerHTML = '';\r\n\r\n if(files.length) {\r\n let key: LangPackKey;\r\n const args: any[] = [];\r\n if(willAttach.type === 'document') {\r\n key = 'PreviewSender.SendFile';\r\n args.push(files.length);\r\n container.classList.add('is-document');\r\n } else {\r\n container.classList.add('is-media');\r\n \r\n let foundPhotos = 0;\r\n let foundVideos = 0;\r\n files.forEach(file => {\r\n if(file.type.indexOf('image/') === 0) ++foundPhotos;\r\n else if(file.type.indexOf('video/') === 0) ++foundVideos;\r\n });\r\n \r\n const sum = foundPhotos + foundVideos;\r\n if(sum > 1 && willAttach.group) {\r\n key = 'PreviewSender.SendAlbum';\r\n const albumsLength = Math.ceil(sum / 10);\r\n args.push(albumsLength);\r\n } else if(foundPhotos) {\r\n key = 'PreviewSender.SendPhoto';\r\n args.push(foundPhotos);\r\n } else if(foundVideos) {\r\n key = 'PreviewSender.SendVideo';\r\n args.push(foundVideos);\r\n }\r\n }\r\n\r\n this.title.textContent = '';\r\n this.title.append(i18n(key, args));\r\n }\r\n\r\n if(willAttach.type === 'media') {\r\n if(willAttach.sendFileDetails.length > 1 && willAttach.group) {\r\n container.classList.add('is-album');\r\n\r\n for(let i = 0; i < results.length; i += 10) {\r\n const albumContainer = document.createElement('div');\r\n albumContainer.classList.add('popup-album');\r\n\r\n albumContainer.append(...results.slice(i, i + 10));\r\n prepareAlbum({\r\n container: albumContainer,\r\n items: willAttach.sendFileDetails.slice(i, i + 10).map(o => ({w: o.width, h: o.height})),\r\n maxWidth: 380,\r\n minWidth: 100,\r\n spacing: 4\r\n });\r\n\r\n this.mediaContainer.append(albumContainer);\r\n }\r\n\r\n //console.log('chatInput album layout:', layout);\r\n } else {\r\n for(let i = 0; i < results.length; ++i) {\r\n const params = willAttach.sendFileDetails[i];\r\n const div = results[i];\r\n const {w, h} = calcImageInBox(params.width, params.height, 380, 320);\r\n div.style.width = w + 'px';\r\n div.style.height = h + 'px';\r\n this.mediaContainer.append(div);\r\n }\r\n }\r\n } else {\r\n this.mediaContainer.append(...results);\r\n }\r\n\r\n // show now\r\n if(!this.element.classList.contains('active')) {\r\n document.body.addEventListener('keydown', this.onKeyDown);\r\n this.onClose = () => {\r\n if(this.wasInputValue) {\r\n this.chat.input.messageInputField.value = this.wasInputValue;\r\n }\r\n\r\n document.body.removeEventListener('keydown', this.onKeyDown);\r\n };\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\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\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 { EmoticonsDropdown } from \"../emoticonsDropdown\";\r\nimport { SuperStickerRenderer } from \"../emoticonsDropdown/tabs/stickers\";\r\nimport LazyLoadQueue from \"../lazyLoadQueue\";\r\nimport Scrollable from \"../scrollable\";\r\nimport SetTransition from \"../singleTransition\";\r\n\r\nexport default class StickersHelper {\r\n private container: HTMLElement;\r\n private stickersContainer: HTMLElement;\r\n private scrollable: Scrollable;\r\n private superStickerRenderer: SuperStickerRenderer;\r\n private lazyLoadQueue: LazyLoadQueue;\r\n private lastEmoticon = '';\r\n\r\n constructor(private appendTo: HTMLElement) {\r\n this.container = document.createElement('div');\r\n this.container.classList.add('stickers-helper', 'z-depth-1');\r\n\r\n this.appendTo.append(this.container);\r\n }\r\n\r\n public checkEmoticon(emoticon: string) {\r\n if(this.lastEmoticon === emoticon) return;\r\n\r\n if(this.lastEmoticon && !emoticon) {\r\n if(this.container) {\r\n SetTransition(this.container, 'is-visible', false, 200, () => {\r\n if(this.stickersContainer) {\r\n this.stickersContainer.innerHTML = '';\r\n }\r\n });\r\n }\r\n }\r\n\r\n this.lastEmoticon = emoticon;\r\n if(this.lazyLoadQueue) {\r\n this.lazyLoadQueue.clear();\r\n }\r\n \r\n if(!emoticon) {\r\n return;\r\n }\r\n\r\n appStickersManager.getStickersByEmoticon(emoticon)\r\n .then((stickers) => {\r\n if(this.lastEmoticon !== emoticon) {\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.stickersContainer.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>).then(resolve, resolve);\r\n });\r\n } else {\r\n ready = Promise.resolve();\r\n }\r\n\r\n ready.then(() => {\r\n this.stickersContainer.replaceWith(container);\r\n this.stickersContainer = container;\r\n\r\n SetTransition(this.container, 'is-visible', !!stickers.length, 200);\r\n this.scrollable.scrollTop = 0;\r\n });\r\n });\r\n }\r\n\r\n private init() {\r\n this.container.addEventListener('click', (e) => {\r\n if(!findUpClassName(e.target, 'super-sticker')) {\r\n return;\r\n }\r\n\r\n EmoticonsDropdown.onMediaClick(e, true);\r\n });\r\n\r\n this.stickersContainer = document.createElement('div');\r\n this.stickersContainer.classList.add('stickers-helper-stickers', 'super-stickers');\r\n\r\n this.container.append(this.stickersContainer);\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 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\nexport default class PopupSchedule extends PopupDatePicker {\r\n constructor(initDate: Date, onPick: (timestamp: number) => void) {\r\n super(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: (() => {\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 withTime: true,\r\n showOverflowMonths: 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}\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 { 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 { ServerTimeManager } from '../../lib/mtproto/serverTimeManager';\r\nimport type Chat from './chat';\r\nimport Recorder from '../../../public/recorder.min';\r\nimport { isTouchSupported } from \"../../helpers/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 { attachClickEvent, blurActiveElement, cancelEvent, cancelSelection, getRichValue, isInputEmpty, markdownTags, MarkdownType, placeCaretAtEnd, isSendShortcutPressed } from \"../../helpers/dom\";\r\nimport { 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 } from '../../layer';\r\nimport StickersHelper from './stickersHelper';\r\nimport ButtonIcon from '../buttonIcon';\r\nimport DivAndCaption from '../divAndCaption';\r\nimport ButtonMenuToggle from '../buttonMenuToggle';\r\nimport ListenerSetter 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 { debounce } from '../../helpers/schedulers';\r\nimport { tsNow } from '../../helpers/date';\r\nimport appNavigationController from '../appNavigationController';\r\nimport { isMobile } from '../../helpers/userAgent';\r\nimport { i18n } from '../../lib/langPack';\r\nimport { generateTail } from './bubbles';\r\nimport findUpClassName from '../../helpers/dom/findUpClassName';\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\ntype ChatInputHelperType = 'edit' | 'webpage' | 'forward' | 'reply';\r\n\r\nexport default class ChatInput {\r\n public pageEl = document.getElementById('page-chats') as HTMLDivElement;\r\n public messageInput: HTMLElement;\r\n public messageInputField: InputField;\r\n public fileInput: HTMLInputElement;\r\n public inputMessageContainer: HTMLDivElement;\r\n public btnSend = document.getElementById('btn-send') as HTMLButtonElement;\r\n public btnCancelRecord: HTMLButtonElement;\r\n public lastUrl = '';\r\n public 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 public btnSendContainer: HTMLDivElement;\r\n\r\n public attachMenu: HTMLButtonElement;\r\n private attachMenuButtons: (ButtonMenuItemOptions & {verify: (peerId: number) => boolean})[];\r\n\r\n public sendMenu: SendMenu;\r\n\r\n public replyElements: {\r\n container?: HTMLElement,\r\n cancelBtn?: HTMLButtonElement,\r\n titleEl?: HTMLElement,\r\n subtitleEl?: HTMLElement\r\n } = {};\r\n\r\n public willSendWebPage: any = null;\r\n public forwardingMids: number[] = [];\r\n public forwardingFromPeerId: number = 0;\r\n public replyToMsgId: number;\r\n public editMsgId: number;\r\n public noWebPage: true;\r\n public scheduleDate: number;\r\n public sendSilent: true;\r\n\r\n private recorder: any;\r\n private recording = false;\r\n private recordCanceled = false;\r\n private recordTimeEl: HTMLElement;\r\n private recordRippleEl: HTMLElement;\r\n private recordStartTime = 0;\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 readonly undoHistory: string[] = [];\r\n readonly executedHistory: string[] = [];\r\n private canUndoFromHTML = '';\r\n\r\n public stickersHelper: StickersHelper;\r\n public listenerSetter: ListenerSetter;\r\n\r\n public pinnedControlBtn: HTMLButtonElement;\r\n\r\n public goDownBtn: HTMLButtonElement;\r\n public goDownUnreadBadge: HTMLElement;\r\n public btnScheduled: HTMLButtonElement;\r\n\r\n public saveDraftDebounced: () => void;\r\n\r\n public fakeRowsWrapper: HTMLDivElement;\r\n private fakePinnedControlBtn: HTMLElement;\r\n\r\n constructor(private chat: Chat, private appMessagesManager: AppMessagesManager, private appDocsManager: AppDocsManager, private appChatsManager: AppChatsManager, private appPeersManager: AppPeersManager, private appWebPagesManager: AppWebPagesManager, private appImManager: AppImManager, private appDraftsManager: AppDraftsManager, private serverTimeManager: ServerTimeManager, private appNotificationsManager: AppNotificationsManager) {\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.rowsWrapper = document.createElement('div');\r\n this.rowsWrapper.classList.add('rows-wrapper', 'chat-input-wrapper');\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 = document.createElement('div');\r\n fakeSelectionWrapper.classList.add('fake-wrapper', 'fake-selection-wrapper');\r\n\r\n this.inputContainer.append(this.rowsWrapper, fakeRowsWrapper, fakeSelectionWrapper);\r\n this.chatInput.append(this.inputContainer);\r\n\r\n this.goDownBtn = Button('bubbles-go-down btn-corner btn-circle z-depth-1 hide', {icon: 'arrow_down'});\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\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.cancelBtn = ButtonIcon('close reply-cancel');\r\n\r\n const dac = new DivAndCaption('reply');\r\n\r\n this.replyElements.titleEl = dac.title;\r\n this.replyElements.subtitleEl = dac.subtitle;\r\n\r\n this.replyElements.container.append(this.replyElements.cancelBtn, dac.container);\r\n\r\n this.newMessageWrapper = document.createElement('div');\r\n this.newMessageWrapper.classList.add('new-message-wrapper');\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.btnScheduled = ButtonIcon('scheduled', {noRipple: true});\r\n this.btnScheduled.classList.add('btn-scheduled', 'hide');\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', (e) => {\r\n const peerId = e.peerId;\r\n\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', (e) => {\r\n const peerId = e.peerId;\r\n\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\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 this.fileInput.setAttribute('accept', 'image/*, video/*');\r\n this.willAttachType = 'media';\r\n this.fileInput.click();\r\n },\r\n verify: (peerId: number) => peerId > 0 || this.appChatsManager.hasRights(peerId, '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: (peerId: number) => peerId > 0 || this.appChatsManager.hasRights(peerId, '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: number) => peerId < 0 && this.appChatsManager.hasRights(peerId, '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.btnToggleEmoticons, this.inputMessageContainer, this.btnScheduled, this.attachMenu, this.recordTimeEl, this.fileInput].filter(Boolean));\r\n\r\n this.rowsWrapper.append(this.replyElements.container);\r\n this.stickersHelper = new StickersHelper(this.rowsWrapper);\r\n this.rowsWrapper.append(this.newMessageWrapper);\r\n\r\n this.btnCancelRecord = ButtonIcon('delete danger 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\"></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();\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 emoticonsDropdown.events.onOpen.push(this.onEmoticonsOpen);\r\n emoticonsDropdown.events.onClose.push(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) {\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', (e) => {\r\n const {peerId, threadId, draft} = e;\r\n if(this.chat.threadId !== threadId || this.chat.peerId !== peerId) return;\r\n this.setDraft(draft);\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 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.recording = false;\r\n this.chatInput.classList.remove('is-recording', 'is-locked');\r\n this.updateSendBtn();\r\n this.recordRippleEl.style.transform = '';\r\n };\r\n \r\n this.recorder.ondataavailable = (typedArray: Uint8Array) => {\r\n if(this.recordCanceled) return;\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 let peerId = this.chat.peerId;\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: this.replyToMsgId,\r\n threadId: this.chat.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\r\n public constructPinnedHelpers() {\r\n const container = document.createElement('div');\r\n container.classList.add('pinned-container');\r\n\r\n this.pinnedControlBtn = Button('btn-primary btn-transparent text-bold pinned-container-button', {icon: 'unpin'});\r\n container.append(this.pinnedControlBtn);\r\n\r\n const fakeContainer = container.cloneNode(true);\r\n this.fakePinnedControlBtn = fakeContainer.firstChild as HTMLElement;\r\n this.fakeRowsWrapper.append(fakeContainer);\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(0); // * 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.rowsWrapper.append(container);\r\n\r\n this.chatInput.classList.add('type-pinned');\r\n this.rowsWrapper.classList.add('is-centered');\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 = isTouchSupported ? 'flip-icon' : 'active';\r\n this.btnToggleEmoticons.classList.toggle(toggleClass, true);\r\n };\r\n\r\n private onEmoticonsClose = () => {\r\n const toggleClass = isTouchSupported ? 'flip-icon' : 'active';\r\n this.btnToggleEmoticons.classList.toggle(toggleClass, false);\r\n };\r\n\r\n public scheduleSending = (callback: () => void = this.sendMessage.bind(this, true), initDate = new Date()) => {\r\n new PopupSchedule(initDate, (timestamp) => {\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 this.appImManager.openScheduled(this.chat.peerId);\r\n }\r\n }).show();\r\n };\r\n\r\n public setUnreadCount() {\r\n const dialog = this.appMessagesManager.getDialogByPeerId(this.chat.peerId)[0];\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\r\n public saveDraft() {\r\n if(!this.chat.peerId || this.editMsgId || this.chat.type === 'scheduled') return;\r\n \r\n const entities: MessageEntity[] = [];\r\n const str = getRichValue(this.messageInputField.input, entities);\r\n\r\n let draft: DraftMessage.draftMessage;\r\n if(str.length || this.replyToMsgId) {\r\n draft = {\r\n _: 'draftMessage',\r\n date: tsNow(true) + this.serverTimeManager.serverTimeOffset,\r\n message: str,\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 emoticonsDropdown.events.onOpen.findAndSplice(f => f === this.onEmoticonsOpen);\r\n emoticonsDropdown.events.onClose.findAndSplice(f => f === this.onEmoticonsClose);\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\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) {\r\n if(!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 return false;\r\n }\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() {\r\n const peerId = this.chat.peerId;\r\n\r\n this.chatInput.style.display = '';\r\n \r\n const isBroadcast = this.appPeersManager.isBroadcast(peerId);\r\n this.goDownBtn.classList.toggle('is-broadcast', isBroadcast);\r\n this.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 this.chatInput.classList.toggle('can-pin', this.appPeersManager.canPinMessage(peerId));\r\n }/* else if(this.chat.type === 'chat') {\r\n } */\r\n\r\n if(this.btnScheduled) {\r\n this.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 this.btnScheduled.classList.toggle('hide', !mids.length);\r\n });\r\n }\r\n\r\n if(this.sendMenu) {\r\n this.sendMenu.setPeerId(peerId);\r\n }\r\n\r\n if(this.messageInput) {\r\n const canWrite = this.appMessagesManager.canWriteToPeer(peerId);\r\n this.chatInput.classList.add('no-transition');\r\n this.chatInput.classList.toggle('is-hidden', !canWrite);\r\n void this.chatInput.offsetLeft; // reflow\r\n this.chatInput.classList.remove('no-transition');\r\n\r\n const visible = this.attachMenuButtons.filter(button => {\r\n const good = button.verify(peerId);\r\n button.element.classList.toggle('hide', !good);\r\n return good;\r\n });\r\n \r\n if(!canWrite) {\r\n this.messageInput.removeAttribute('contenteditable');\r\n } else {\r\n this.messageInput.setAttribute('contenteditable', 'true');\r\n this.setDraft(undefined, false);\r\n\r\n if(!this.messageInput.innerHTML) {\r\n this.messageInputField.onFakeInput();\r\n }\r\n }\r\n \r\n this.attachMenu.toggleAttribute('disabled', !visible.length);\r\n this.updateSendBtn();\r\n } else if(this.pinnedControlBtn) {\r\n if(this.appPeersManager.canPinMessage(this.chat.peerId)) {\r\n this.pinnedControlBtn.append(i18n('Chat.Input.UnpinAll'));\r\n this.fakePinnedControlBtn.append(i18n('Chat.Input.UnpinAll'));\r\n } else {\r\n this.pinnedControlBtn.append(i18n('Chat.Pinned.DontShow'));\r\n this.fakePinnedControlBtn.append(i18n('Chat.Pinned.DontShow'));\r\n }\r\n }\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.attachMessageInputListeners();\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 if(isSendShortcutPressed(e)) {\r\n this.sendMessage();\r\n } else if(e.ctrlKey || e.metaKey) {\r\n this.handleMarkdownShortcut(e);\r\n }\r\n });\r\n\r\n if(isTouchSupported) {\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\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 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'),\r\n link: href ? () => document.execCommand('createLink', false, href) : () => document.execCommand('unlink', false, null)\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') {\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(document.execCommand('fontName', false, 'Roboto'));\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 handleMarkdownShortcut = (e: KeyboardEvent) => {\r\n const formatKeys: {[key: string]: MarkdownType} = {\r\n 'B': 'bold',\r\n 'I': 'italic',\r\n 'U': 'underline',\r\n 'S': 'strikethrough',\r\n 'M': 'monospace',\r\n 'K': 'link'\r\n };\r\n\r\n const selection = document.getSelection();\r\n if(selection.toString().trim().length) {\r\n for(const key in formatKeys) {\r\n const good = e.code === ('Key' + key);\r\n \r\n if(good) {\r\n // * костыльчик\r\n if(key === 'K') {\r\n this.appImManager.markupTooltip.showLinkEditor();\r\n cancelEvent(e);\r\n break;\r\n }\r\n \r\n this.applyMarkdown(formatKeys[key]);\r\n cancelEvent(e); // cancel legacy event\r\n break;\r\n }\r\n }\r\n }\r\n\r\n //return;\r\n if(e.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 markdownEntities: MessageEntity[] = [];\r\n const richValue = getRichValue(this.messageInputField.input, markdownEntities);\r\n \r\n //const entities = RichTextProcessor.parseEntities(value);\r\n const value = RichTextProcessor.parseMarkdown(richValue, markdownEntities);\r\n const entities = RichTextProcessor.mergeEntities(markdownEntities, RichTextProcessor.parseEntities(value));\r\n\r\n //this.chat.log('messageInput entities', richValue, value, markdownEntities);\r\n\r\n if(this.stickersHelper && \r\n rootScope.settings.stickers.suggest && \r\n (this.chat.peerId > 0 || this.appChatsManager.hasRights(this.chat.peerId, 'send_stickers'))) {\r\n let emoticon = '';\r\n if(entities.length && entities[0]._ === 'messageEntityEmoji') {\r\n const entity = entities[0];\r\n if(entity.length === richValue.length && !entity.offset) {\r\n emoticon = richValue;\r\n }\r\n }\r\n\r\n this.stickersHelper.checkEmoticon(emoticon);\r\n }\r\n\r\n if(!richValue.trim()) {\r\n this.appImManager.markupTooltip.hide();\r\n }\r\n\r\n const html = this.messageInput.innerHTML;\r\n if(this.canRedoFromHTML && html !== this.canRedoFromHTML && !this.lockRedo) {\r\n this.canRedoFromHTML = '';\r\n this.undoHistory.length = 0;\r\n }\r\n\r\n const urlEntities: Array<MessageEntity.messageEntityUrl | MessageEntity.messageEntityTextUrl> = 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 apiManager.invokeApi('messages.getWebPage', {\r\n url,\r\n hash: 0\r\n }).then((webpage) => {\r\n webpage = this.appWebPagesManager.saveWebPage(webpage);\r\n if(webpage._ === 'webPage') {\r\n if(this.lastUrl !== url) return;\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\r\n delete this.noWebPage;\r\n this.willSendWebPage = webpage;\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 if(this.isInputEmpty()) {\r\n if(this.lastTimeType) {\r\n this.appMessagesManager.setTyping(this.chat.peerId, 'sendMessageCancelAction');\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\r\n if(!this.editMsgId) {\r\n this.saveDraftDebounced();\r\n }\r\n\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.forwardingMids.length || 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 < 0 && !this.appChatsManager.hasRights(this.chat.peerId, '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 this.recorder.start().then(() => {\r\n this.recordCanceled = false;\r\n \r\n this.chatInput.classList.add('is-recording');\r\n this.recording = true;\r\n this.updateSendBtn();\r\n opusDecodeController.setKeepAlive(true);\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 = ('' + (diff / 1000)).toHHMMSS() + ',' + ('00' + Math.round(ms / 10)).slice(-2);\r\n\r\n this.recordTimeEl.innerText = formatted;\r\n\r\n window.requestAnimationFrame(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.chatInput.classList.remove('is-recording', 'is-locked');\r\n });\r\n }\r\n };\r\n\r\n private onHelperCancel = (e?: Event) => {\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 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-wrapper')) return;\r\n if(this.helperType === 'forward') {\r\n if(this.helperWaitingForward) return;\r\n this.helperWaitingForward = true;\r\n\r\n const fromId = this.forwardingFromPeerId;\r\n const mids = this.forwardingMids.slice();\r\n const helperFunc = this.helperFunc;\r\n this.clearHelper();\r\n let selected = false;\r\n new PopupForward(fromId, mids, () => {\r\n selected = true;\r\n }, () => {\r\n this.helperWaitingForward = false;\r\n\r\n if(!selected) {\r\n helperFunc();\r\n }\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 public clearInput(canSetDraft = true) {\r\n this.messageInputField.value = '';\r\n if(isTouchSupported) {\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) {\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.forwardingMids.length) 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\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 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 if(this.chat.type === 'scheduled' && !force && !this.editMsgId) {\r\n this.scheduleSending();\r\n return;\r\n }\r\n\r\n const entities: MessageEntity[] = [];\r\n const str = getRichValue(this.messageInputField.input, entities);\r\n\r\n //return;\r\n if(this.editMsgId) {\r\n this.appMessagesManager.editMessage(this.chat.getMessage(this.editMsgId), str, {\r\n entities,\r\n noWebPage: this.noWebPage\r\n });\r\n } else {\r\n this.appMessagesManager.sendText(this.chat.peerId, str, {\r\n entities,\r\n replyToMsgId: this.replyToMsgId,\r\n threadId: this.chat.threadId,\r\n noWebPage: this.noWebPage,\r\n webPage: this.willSendWebPage,\r\n scheduleDate: this.scheduleDate,\r\n silent: this.sendSilent,\r\n clearDraft: true\r\n });\r\n }\r\n\r\n // * wait for sendText set messageId for invokeAfterMsg\r\n if(this.forwardingMids.length) {\r\n const mids = this.forwardingMids.slice();\r\n const fromPeerId = this.forwardingFromPeerId;\r\n const peerId = this.chat.peerId;\r\n const silent = this.sendSilent;\r\n const scheduleDate = this.scheduleDate;\r\n setTimeout(() => {\r\n this.appMessagesManager.forwardMessages(peerId, fromPeerId, mids, {\r\n silent,\r\n scheduleDate: scheduleDate\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 < 0 && !this.appChatsManager.hasRights(this.chat.peerId, flag)) {\r\n toast(POSTING_MEDIA_NOT_ALLOWED);\r\n return;\r\n }\r\n\r\n if(this.chat.type === 'scheduled' && !force) {\r\n this.scheduleSending(() => this.sendMessageWithDocument(document, true));\r\n return false;\r\n }\r\n\r\n if(document) {\r\n this.appMessagesManager.sendFile(this.chat.peerId, document, {\r\n isMedia: true, \r\n replyToMsgId: this.replyToMsgId, \r\n threadId: this.chat.threadId,\r\n silent: this.sendSilent, \r\n scheduleDate: this.scheduleDate,\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 /* 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 = this.chat.getMessage(mid);\r\n\r\n let input = RichTextProcessor.wrapDraftText(message.message, {entities: message.totalEntities});\r\n const f = () => {\r\n // ! костыль\r\n const replyFragment = this.appMessagesManager.wrapMessageForReply(message, undefined, [message.mid]);\r\n this.setTopInfo('edit', f, 'Editing', undefined, input, message);\r\n const subtitleEl = this.replyElements.container.querySelector('.reply-subtitle');\r\n subtitleEl.textContent = '';\r\n subtitleEl.append(replyFragment);\r\n\r\n this.editMsgId = mid;\r\n input = undefined;\r\n };\r\n f();\r\n }\r\n\r\n public initMessagesForward(fromPeerId: number, mids: number[]) {\r\n const f = () => {\r\n //const peerTitles: string[]\r\n const smth: Set<string | number> = new Set(mids.map(mid => {\r\n const message = this.appMessagesManager.getMessageByPeer(fromPeerId, mid);\r\n if(message.fwd_from && message.fwd_from.from_name && !message.fromId && !message.fwdFromId) {\r\n return message.fwd_from.from_name;\r\n } else {\r\n return message.fromId;\r\n }\r\n }));\r\n\r\n const onlyFirstName = smth.size > 1;\r\n const peerTitles = [...smth].map(smth => {\r\n return typeof(smth) === 'number' ? \r\n this.appPeersManager.getPeerTitle(smth, true, onlyFirstName) : \r\n (onlyFirstName ? smth.split(' ')[0] : smth);\r\n });\r\n\r\n const title = peerTitles.length < 3 ? peerTitles.join(' and ') : peerTitles[0] + ' and ' + (peerTitles.length - 1) + ' others';\r\n const firstMessage = this.appMessagesManager.getMessageByPeer(fromPeerId, mids[0]);\r\n\r\n let usingFullAlbum = true;\r\n if(firstMessage.grouped_id) {\r\n const albumMids = this.appMessagesManager.getMidsByMessage(firstMessage);\r\n if(albumMids.length !== mids.length || albumMids.find(mid => !mids.includes(mid))) {\r\n usingFullAlbum = false;\r\n }\r\n }\r\n\r\n const replyFragment = this.appMessagesManager.wrapMessageForReply(firstMessage, undefined, mids);\r\n if(usingFullAlbum || mids.length === 1) {\r\n this.setTopInfo('forward', f, title);\r\n\r\n // ! костыль\r\n const subtitleEl = this.replyElements.container.querySelector('.reply-subtitle');\r\n subtitleEl.textContent = '';\r\n subtitleEl.append(replyFragment);\r\n } else {\r\n this.setTopInfo('forward', f, title, mids.length + ' ' + (mids.length > 1 ? 'forwarded messages' : 'forwarded message'));\r\n }\r\n\r\n this.forwardingMids = mids.slice();\r\n this.forwardingFromPeerId = fromPeerId;\r\n };\r\n \r\n f();\r\n }\r\n\r\n public initMessageReply(mid: number) {\r\n const message = this.chat.getMessage(mid);\r\n const f = () => {\r\n this.setTopInfo('reply', f, this.appPeersManager.getPeerTitle(message.fromId, true), 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 this.replyToMsgId = undefined;\r\n this.forwardingMids.length = 0;\r\n this.forwardingFromPeerId = 0;\r\n this.editMsgId = 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 }\r\n }\r\n\r\n public setInputValue(value: string, clear = true, focus = true) {\r\n clear && this.clearInput();\r\n this.messageInputField.value = value || '';\r\n window.requestAnimationFrame(() => {\r\n focus && placeCaretAtEnd(this.messageInput);\r\n this.messageInput.scrollTop = this.messageInput.scrollHeight;\r\n });\r\n }\r\n\r\n public setTopInfo(type: ChatInputHelperType, callerFunc: () => void, title = '', subtitle = '', input?: string, message?: any) {\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 if(this.replyElements.container.lastElementChild.tagName === 'DIV') {\r\n this.replyElements.container.lastElementChild.remove();\r\n this.replyElements.container.append(wrapReply(title, subtitle, message));\r\n }\r\n\r\n this.chat.container.classList.add('is-helper-active');\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(!isMobile) {\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\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","/*\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 ChatBubbles from \"./bubbles\";\r\nimport type ChatInput from \"./input\";\r\nimport type Chat from \"./chat\";\r\nimport { isTouchSupported } from \"../../helpers/touchSupport\";\r\nimport { blurActiveElement, cancelEvent, cancelSelection, getSelectedText } from \"../../helpers/dom\";\r\nimport Button from \"../button\";\r\nimport ButtonIcon from \"../buttonIcon\";\r\nimport CheckboxField from \"../checkboxField\";\r\nimport PopupDeleteMessages from \"../popups/deleteMessages\";\r\nimport PopupForward from \"../popups/forward\";\r\nimport { toast } from \"../toast\";\r\nimport SetTransition from \"../singleTransition\";\r\nimport ListenerSetter from \"../../helpers/listenerSetter\";\r\nimport PopupSendNow from \"../popups/sendNow\";\r\nimport appNavigationController from \"../appNavigationController\";\r\nimport { isMobileSafari } from \"../../helpers/userAgent\";\r\nimport I18n, { i18n, _i18n } from \"../../lib/langPack\";\r\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\r\n\r\nconst MAX_SELECTION_LENGTH = 100;\r\n//const MIN_CLICK_MOVE = 32; // minimum bubble height\r\n\r\nexport default class ChatSelection {\r\n public selectedMids: Set<number> = new Set();\r\n public isSelecting = false;\r\n\r\n private selectionInputWrapper: HTMLElement;\r\n private selectionContainer: HTMLElement;\r\n private selectionCountEl: HTMLElement;\r\n public selectionSendNowBtn: HTMLElement;\r\n public selectionForwardBtn: HTMLElement;\r\n public selectionDeleteBtn: HTMLElement;\r\n\r\n public selectedText: string;\r\n\r\n private listenerSetter: ListenerSetter;\r\n\r\n constructor(private chat: Chat, private bubbles: ChatBubbles, private input: ChatInput, private appMessagesManager: AppMessagesManager) {\r\n const bubblesContainer = bubbles.bubblesContainer;\r\n this.listenerSetter = bubbles.listenerSetter;\r\n\r\n if(isTouchSupported) {\r\n this.listenerSetter.add(bubblesContainer, 'touchend', (e) => {\r\n if(!this.isSelecting) return;\r\n this.selectedText = getSelectedText();\r\n });\r\n return;\r\n }\r\n\r\n this.listenerSetter.add(bubblesContainer, 'mousedown', (e) => {\r\n //console.log('selection mousedown', e);\r\n const bubble = findUpClassName(e.target, 'bubble');\r\n // LEFT BUTTON\r\n // проверка внизу нужна для того, чтобы не активировать селект если target потомок .bubble\r\n if(e.button !== 0\r\n || (\r\n !this.selectedMids.size \r\n && !(e.target as HTMLElement).classList.contains('bubble')\r\n && !(e.target as HTMLElement).classList.contains('document-selection')\r\n && bubble\r\n )\r\n ) {\r\n return;\r\n }\r\n \r\n const seen: Set<number> = new Set();\r\n let selecting: boolean;\r\n\r\n /* let good = false;\r\n const {x, y} = e; */\r\n\r\n /* const bubbles = appImManager.bubbles;\r\n for(const mid in bubbles) {\r\n const bubble = bubbles[mid];\r\n bubble.addEventListener('mouseover', () => {\r\n console.log('mouseover');\r\n }, {once: true});\r\n } */\r\n\r\n //const foundTargets: Map<HTMLElement, true> = new Map();\r\n let canceledSelection = false;\r\n const onMouseMove = (e: MouseEvent) => {\r\n if(!canceledSelection) {\r\n cancelSelection();\r\n canceledSelection = true;\r\n }\r\n /* if(!good) {\r\n if(Math.abs(e.x - x) > MIN_CLICK_MOVE || Math.abs(e.y - y) > MIN_CLICK_MOVE) {\r\n good = true;\r\n } else {\r\n return;\r\n }\r\n } */\r\n\r\n /* if(foundTargets.has(e.target as HTMLElement)) return;\r\n foundTargets.set(e.target as HTMLElement, true); */\r\n const bubble = findUpClassName(e.target, 'grouped-item') || findUpClassName(e.target, 'bubble');\r\n if(!bubble) {\r\n //console.error('found no bubble', e);\r\n return;\r\n }\r\n\r\n const mid = +bubble.dataset.mid;\r\n if(!mid) return;\r\n\r\n // * cancel selecting if selecting message text\r\n if(e.target !== bubble && !(e.target as HTMLElement).classList.contains('document-selection') && selecting === undefined && !this.selectedMids.size) {\r\n this.listenerSetter.removeManual(bubblesContainer, 'mousemove', onMouseMove);\r\n this.listenerSetter.removeManual(document, 'mouseup', onMouseUp, documentListenerOptions);\r\n return;\r\n }\r\n\r\n if(!seen.has(mid)) {\r\n const isBubbleSelected = this.selectedMids.has(mid);\r\n if(selecting === undefined) {\r\n //bubblesContainer.classList.add('no-select');\r\n selecting = !isBubbleSelected;\r\n }\r\n\r\n seen.add(mid);\r\n\r\n if((selecting && !isBubbleSelected) || (!selecting && isBubbleSelected)) {\r\n if(!this.selectedMids.size) {\r\n if(seen.size === 2) {\r\n [...seen].forEach(mid => {\r\n const mounted = this.bubbles.getMountedBubble(mid);\r\n if(mounted) {\r\n this.toggleByBubble(mounted.bubble);\r\n }\r\n })\r\n }\r\n } else {\r\n this.toggleByBubble(bubble);\r\n }\r\n }\r\n }\r\n //console.log('onMouseMove', target);\r\n };\r\n\r\n const onMouseUp = (e: MouseEvent) => {\r\n if(seen.size) {\r\n window.addEventListener('click', (e) => {\r\n cancelEvent(e);\r\n }, {capture: true, once: true, passive: false});\r\n }\r\n\r\n this.listenerSetter.removeManual(bubblesContainer, 'mousemove', onMouseMove);\r\n //bubblesContainer.classList.remove('no-select');\r\n\r\n // ! CANCEL USER SELECTION !\r\n cancelSelection();\r\n };\r\n\r\n const documentListenerOptions = {once: true};\r\n this.listenerSetter.add(bubblesContainer, 'mousemove', onMouseMove);\r\n this.listenerSetter.add(document, 'mouseup', onMouseUp, documentListenerOptions);\r\n });\r\n }\r\n\r\n public toggleBubbleCheckbox(bubble: HTMLElement, show: boolean) {\r\n if(!this.canSelectBubble(bubble)) return;\r\n\r\n const hasCheckbox = !!this.getCheckboxInputFromBubble(bubble);\r\n const isGrouped = bubble.classList.contains('is-grouped');\r\n if(show) {\r\n if(hasCheckbox) return;\r\n \r\n const checkboxField = new CheckboxField({\r\n name: bubble.dataset.mid, \r\n round: true\r\n });\r\n checkboxField.label.classList.add('bubble-select-checkbox');\r\n\r\n // * if it is a render of new message\r\n if(this.isSelecting) { // ! avoid breaking animation on start\r\n const mid = +bubble.dataset.mid;\r\n if(this.selectedMids.has(mid) && (!isGrouped || this.isGroupedMidsSelected(mid))) {\r\n checkboxField.input.checked = true;\r\n bubble.classList.add('is-selected');\r\n }\r\n }\r\n\r\n if(bubble.classList.contains('document-container')) {\r\n bubble.querySelector('.document, audio-element').append(checkboxField.label);\r\n } else {\r\n bubble.prepend(checkboxField.label);\r\n }\r\n } else if(hasCheckbox) {\r\n this.getCheckboxInputFromBubble(bubble).parentElement.remove();\r\n }\r\n\r\n if(isGrouped) {\r\n this.bubbles.getBubbleGroupedItems(bubble).forEach(item => this.toggleBubbleCheckbox(item, show));\r\n }\r\n }\r\n\r\n private getCheckboxInputFromBubble(bubble: HTMLElement): HTMLInputElement {\r\n /* let perf = performance.now();\r\n let checkbox = bubble.firstElementChild.tagName === 'LABEL' && bubble.firstElementChild.firstElementChild as HTMLInputElement;\r\n console.log('getCheckboxInputFromBubble firstElementChild time:', performance.now() - perf);\r\n\r\n perf = performance.now();\r\n checkbox = bubble.querySelector('label input');\r\n console.log('getCheckboxInputFromBubble querySelector time:', performance.now() - perf); */\r\n /* let perf = performance.now();\r\n let contains = bubble.classList.contains('document-container');\r\n console.log('getCheckboxInputFromBubble classList time:', performance.now() - perf);\r\n\r\n perf = performance.now();\r\n contains = bubble.className.includes('document-container');\r\n console.log('getCheckboxInputFromBubble className time:', performance.now() - perf); */\r\n\r\n return bubble.classList.contains('document-container') ? \r\n bubble.querySelector('label input') : \r\n bubble.firstElementChild.tagName === 'LABEL' && bubble.firstElementChild.firstElementChild as HTMLInputElement;\r\n }\r\n\r\n private updateContainer(forceSelection = false) {\r\n if(!this.selectedMids.size && !forceSelection) return;\r\n this.selectionCountEl.textContent = '';\r\n this.selectionCountEl.append(i18n('Chat.Selection.MessagesCount', [this.selectedMids.size]));\r\n\r\n let cantForward = !this.selectedMids.size, cantDelete = !this.selectedMids.size, cantSend = !this.selectedMids.size;\r\n for(const mid of this.selectedMids.values()) {\r\n const message = this.appMessagesManager.getMessageByPeer(this.bubbles.peerId, mid);\r\n if(!cantForward) {\r\n if(message.action) {\r\n cantForward = true;\r\n }\r\n }\r\n \r\n\r\n if(!cantDelete) {\r\n const canDelete = this.appMessagesManager.canDeleteMessage(this.chat.getMessage(mid));\r\n if(!canDelete) {\r\n cantDelete = true;\r\n }\r\n }\r\n\r\n if(cantForward && cantDelete) break;\r\n }\r\n\r\n this.selectionSendNowBtn && this.selectionSendNowBtn.toggleAttribute('disabled', cantSend);\r\n this.selectionForwardBtn && this.selectionForwardBtn.toggleAttribute('disabled', cantForward);\r\n this.selectionDeleteBtn.toggleAttribute('disabled', cantDelete);\r\n }\r\n\r\n public toggleSelection(toggleCheckboxes = true, forceSelection = false) {\r\n const wasSelecting = this.isSelecting;\r\n this.isSelecting = this.selectedMids.size > 0 || forceSelection;\r\n\r\n if(wasSelecting === this.isSelecting) return;\r\n \r\n const bubblesContainer = this.bubbles.bubblesContainer;\r\n //bubblesContainer.classList.toggle('is-selecting', !!this.selectedMids.size);\r\n\r\n /* if(bubblesContainer.classList.contains('is-chat-input-hidden')) {\r\n const scrollable = this.appImManager.scrollable;\r\n if(scrollable.isScrolledDown) {\r\n scrollable.scrollTo(scrollable.scrollHeight, 'top', true, true, 200);\r\n }\r\n } */\r\n\r\n if(!isTouchSupported) {\r\n bubblesContainer.classList.toggle('no-select', this.isSelecting);\r\n\r\n if(wasSelecting) {\r\n // ! CANCEL USER SELECTION !\r\n cancelSelection();\r\n }\r\n }/* else {\r\n if(!wasSelecting) {\r\n bubblesContainer.classList.add('no-select');\r\n setTimeout(() => {\r\n cancelSelection();\r\n bubblesContainer.classList.remove('no-select');\r\n cancelSelection();\r\n }, 100);\r\n }\r\n } */\r\n\r\n blurActiveElement(); // * for mobile keyboards\r\n\r\n let transform = '', borderRadius = '';\r\n const forwards = !!this.selectedMids.size || forceSelection;\r\n if(forwards) {\r\n const p = this.input.rowsWrapper.parentElement;\r\n const fakeSelectionWrapper = p.querySelector('.fake-selection-wrapper');\r\n const fakeRowsWrapper = p.querySelector('.fake-rows-wrapper');\r\n const fakeSelectionRect = fakeSelectionWrapper.getBoundingClientRect();\r\n const fakeRowsRect = 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 const needTranslateX = fakeSelectionRect.left - fakeRowsRect.left - initTranslateX;\r\n transform = `translateX(${needTranslateX}px) 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 //scale = widthTo / widthFrom;\r\n }\r\n }\r\n\r\n SetTransition(this.input.rowsWrapper, 'is-centering', forwards, 200);\r\n this.input.rowsWrapper.style.transform = transform;\r\n this.input.rowsWrapper.style.borderRadius = borderRadius;\r\n SetTransition(bubblesContainer, 'is-selecting', forwards, 200, () => {\r\n if(!this.isSelecting) {\r\n this.selectionInputWrapper.remove();\r\n this.selectionInputWrapper = this.selectionContainer = this.selectionSendNowBtn = this.selectionForwardBtn = this.selectionDeleteBtn = null;\r\n this.selectedText = undefined;\r\n }\r\n \r\n window.requestAnimationFrame(() => {\r\n this.bubbles.onScroll();\r\n });\r\n });\r\n\r\n if(!isMobileSafari) {\r\n if(forwards) {\r\n appNavigationController.pushItem({\r\n type: 'multiselect',\r\n onPop: () => {\r\n this.cancelSelection();\r\n }\r\n });\r\n } else {\r\n appNavigationController.removeByType('multiselect');\r\n }\r\n }\r\n\r\n //const chatInput = this.appImManager.chatInput;\r\n\r\n if(this.isSelecting) {\r\n if(!this.selectionContainer) {\r\n this.selectionInputWrapper = document.createElement('div');\r\n this.selectionInputWrapper.classList.add('chat-input-wrapper', 'selection-wrapper');\r\n\r\n this.selectionContainer = document.createElement('div');\r\n this.selectionContainer.classList.add('selection-container');\r\n\r\n const btnCancel = ButtonIcon('close', {noRipple: true});\r\n this.listenerSetter.add(btnCancel, 'click', this.cancelSelection, {once: true});\r\n\r\n this.selectionCountEl = document.createElement('div');\r\n this.selectionCountEl.classList.add('selection-container-count');\r\n\r\n if(this.chat.type === 'scheduled') {\r\n this.selectionSendNowBtn = Button('btn-primary btn-transparent btn-short text-bold selection-container-send', {icon: 'send2'});\r\n this.selectionSendNowBtn.append(i18n('Chat.Context.Scheduled.SendNow'));\r\n this.listenerSetter.add(this.selectionSendNowBtn, 'click', () => {\r\n new PopupSendNow(this.bubbles.peerId, [...this.selectedMids], () => {\r\n this.cancelSelection();\r\n })\r\n });\r\n } else {\r\n this.selectionForwardBtn = Button('btn-primary btn-transparent text-bold selection-container-forward', {icon: 'forward'});\r\n this.selectionForwardBtn.append(i18n('Forward'));\r\n this.listenerSetter.add(this.selectionForwardBtn, 'click', () => {\r\n new PopupForward(this.bubbles.peerId, [...this.selectedMids], () => {\r\n this.cancelSelection();\r\n });\r\n });\r\n }\r\n\r\n this.selectionDeleteBtn = Button('btn-primary btn-transparent danger text-bold selection-container-delete', {icon: 'delete'});\r\n this.selectionDeleteBtn.append(i18n('Delete'));\r\n this.listenerSetter.add(this.selectionDeleteBtn, 'click', () => {\r\n new PopupDeleteMessages(this.bubbles.peerId, [...this.selectedMids], this.chat.type, () => {\r\n this.cancelSelection();\r\n });\r\n });\r\n\r\n this.selectionContainer.append(...[btnCancel, this.selectionCountEl, this.selectionSendNowBtn, this.selectionForwardBtn, this.selectionDeleteBtn].filter(Boolean));\r\n\r\n this.selectionInputWrapper.style.opacity = '0';\r\n this.selectionInputWrapper.append(this.selectionContainer);\r\n this.input.rowsWrapper.parentElement.append(this.selectionInputWrapper);\r\n\r\n void this.selectionInputWrapper.offsetLeft; // reflow\r\n this.selectionInputWrapper.style.opacity = '';\r\n }\r\n }\r\n\r\n if(toggleCheckboxes) {\r\n for(const mid in this.bubbles.bubbles) {\r\n const bubble = this.bubbles.bubbles[mid];\r\n this.toggleBubbleCheckbox(bubble, this.isSelecting);\r\n }\r\n }\r\n\r\n if(forceSelection) {\r\n this.updateContainer(forceSelection);\r\n }\r\n }\r\n\r\n public cancelSelection = () => {\r\n for(const mid of this.selectedMids) {\r\n const mounted = this.bubbles.getMountedBubble(mid);\r\n if(mounted) {\r\n //this.toggleByBubble(mounted.message.grouped_id ? mounted.bubble.querySelector(`.grouped-item[data-mid=\"${mid}\"]`) : mounted.bubble);\r\n this.toggleByBubble(mounted.bubble);\r\n }\r\n /* const bubble = this.appImManager.bubbles[mid];\r\n if(bubble) {\r\n this.toggleByBubble(bubble);\r\n } */\r\n }\r\n\r\n this.selectedMids.clear();\r\n this.toggleSelection();\r\n cancelSelection();\r\n };\r\n\r\n public cleanup() {\r\n this.selectedMids.clear();\r\n this.toggleSelection(false);\r\n }\r\n\r\n private updateBubbleSelection(bubble: HTMLElement, isSelected: boolean) {\r\n this.toggleBubbleCheckbox(bubble, true);\r\n const input = this.getCheckboxInputFromBubble(bubble);\r\n input.checked = isSelected;\r\n\r\n this.toggleSelection();\r\n this.updateContainer();\r\n SetTransition(bubble, 'is-selected', isSelected, 200);\r\n }\r\n\r\n private isGroupedBubbleSelected(bubble: HTMLElement) {\r\n const groupedCheckboxInput = this.getCheckboxInputFromBubble(bubble);\r\n return groupedCheckboxInput?.checked;\r\n }\r\n\r\n private isGroupedMidsSelected(mid: number) {\r\n const mids = this.chat.getMidsByMid(mid);\r\n const selectedMids = mids.filter(mid => this.selectedMids.has(mid));\r\n return mids.length === selectedMids.length;\r\n }\r\n\r\n public toggleByBubble = (bubble: HTMLElement) => {\r\n if(!this.canSelectBubble(bubble)) return;\r\n\r\n const mid = +bubble.dataset.mid;\r\n\r\n const isGrouped = bubble.classList.contains('is-grouped');\r\n if(isGrouped) {\r\n if(!this.isGroupedBubbleSelected(bubble)) {\r\n const mids = this.chat.getMidsByMid(mid);\r\n mids.forEach(mid => this.selectedMids.delete(mid));\r\n }\r\n\r\n this.bubbles.getBubbleGroupedItems(bubble).forEach(this.toggleByBubble);\r\n return;\r\n }\r\n\r\n const found = this.selectedMids.has(mid);\r\n if(found) {\r\n this.selectedMids.delete(mid);\r\n } else {\r\n const diff = MAX_SELECTION_LENGTH - this.selectedMids.size - 1;\r\n if(diff < 0) {\r\n toast(I18n.format('Chat.Selection.LimitToast', true));\r\n return;\r\n /* const it = this.selectedMids.values();\r\n do {\r\n const mid = it.next().value;\r\n const mounted = this.appImManager.getMountedBubble(mid);\r\n if(mounted) {\r\n this.toggleByBubble(mounted.bubble);\r\n } else {\r\n const mids = this.appMessagesManager.getMidsByMid(mid);\r\n for(const mid of mids) {\r\n this.selectedMids.delete(mid);\r\n }\r\n }\r\n } while(this.selectedMids.size > MAX_SELECTION_LENGTH); */\r\n }\r\n\r\n this.selectedMids.add(mid);\r\n }\r\n\r\n const isGroupedItem = bubble.classList.contains('grouped-item');\r\n if(isGroupedItem) {\r\n const groupContainer = findUpClassName(bubble, 'bubble');\r\n const isGroupedSelected = this.isGroupedBubbleSelected(groupContainer);\r\n const isGroupedMidsSelected = this.isGroupedMidsSelected(mid);\r\n\r\n const willChange = isGroupedMidsSelected || isGroupedSelected;\r\n if(willChange) {\r\n this.updateBubbleSelection(groupContainer, isGroupedMidsSelected);\r\n }\r\n }\r\n\r\n this.updateBubbleSelection(bubble, !found);\r\n };\r\n\r\n /**\r\n * ! Call this method only to handle deleted messages\r\n */\r\n public deleteSelectedMids(mids: number[]) {\r\n mids.forEach(mid => {\r\n this.selectedMids.delete(mid);\r\n });\r\n\r\n this.updateContainer();\r\n this.toggleSelection();\r\n }\r\n\r\n public canSelectBubble(bubble: HTMLElement) {\r\n return !bubble.classList.contains('service') && !bubble.classList.contains('is-sending');\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\";\r\nimport type ChatTopbar from \"./topbar\";\r\nimport mediaSizes from \"../../helpers/mediaSizes\";\r\nimport { attachClickEvent, cancelEvent } from \"../../helpers/dom\";\r\nimport DivAndCaption from \"../divAndCaption\";\r\nimport { ripple } from \"../ripple\";\r\nimport ListenerSetter from \"../../helpers/listenerSetter\";\r\n\r\n//const classNames: string[] = [];\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 private close: HTMLElement;\r\n protected wrapper: HTMLElement;\r\n\r\n constructor(protected topbar: ChatTopbar, protected chat: Chat, public listenerSetter: ListenerSetter, protected className: string, public divAndCaption: DivAndCaption<(title: string, subtitle: string, message?: any) => void>, onClose?: () => void | Promise<boolean>) {\r\n /* const prev = this.divAndCaption.fill;\r\n this.divAndCaption.fill = (mid, title, subtitle) => {\r\n this.divAndCaption.container.dataset.mid = '' + mid;\r\n prev(mid, title, subtitle);\r\n }; */\r\n\r\n //classNames.push(`is-pinned-${className}-shown`);\r\n\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.close = document.createElement('button');\r\n this.close.classList.add(CLASSNAME_BASE + '-close', `pinned-${className}-close`, 'btn-icon', 'tgico-close');\r\n\r\n //divAndCaption.container.prepend(this.close);\r\n\r\n this.wrapper = document.createElement('div');\r\n this.wrapper.classList.add(CLASSNAME_BASE + '-wrapper');\r\n this.wrapper.append(...Array.from(divAndCaption.container.children));\r\n ripple(this.wrapper);\r\n \r\n divAndCaption.container.append(this.close, this.wrapper);\r\n\r\n attachClickEvent(this.close, (e) => {\r\n cancelEvent(e);\r\n\r\n ((onClose ? 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 this.divAndCaption.container.classList.toggle('is-floating', mediaSizes.isMobile);\r\n this.topbar.container.classList.toggle('is-pinned-floating', mediaSizes.isMobile);\r\n\r\n const scrollable = this.chat.bubbles.scrollable;\r\n\r\n const scrollTop = mediaSizes.isMobile /* && !appImManager.scrollable.isScrolledDown */ ? scrollable.scrollTop : undefined;\r\n this.divAndCaption.container.classList.toggle('hide', hide);\r\n const className = `is-pinned-${this.className}-shown`;\r\n this.topbar.container.classList.toggle(className, !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 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.setUtilsWidth();\r\n }\r\n\r\n public fill(title: string, subtitle: string, message: any) {\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","/*\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 { RichTextProcessor } from \"../../lib/richtextprocessor\";\r\nimport rootScope from \"../../lib/rootScope\";\r\nimport { attachClickEvent, cancelEvent } from \"../../helpers/dom\";\r\nimport appMediaPlaybackController from \"../appMediaPlaybackController\";\r\nimport DivAndCaption from \"../divAndCaption\";\r\nimport { formatDate } from \"../wrappers\";\r\nimport PinnedContainer from \"./pinnedContainer\";\r\nimport Chat from \"./chat\";\r\n\r\nexport default class ChatAudio extends PinnedContainer {\r\n private toggleEl: HTMLElement;\r\n\r\n constructor(protected topbar: ChatTopbar, protected chat: Chat, protected appMessagesManager: AppMessagesManager, protected appPeersManager: AppPeersManager) {\r\n super(topbar, chat, topbar.listenerSetter, 'audio', new DivAndCaption('pinned-audio', (title: string, subtitle: string) => {\r\n this.divAndCaption.title.innerHTML = title;\r\n this.divAndCaption.subtitle.innerHTML = subtitle;\r\n }), () => {\r\n if(this.toggleEl.classList.contains('flip-icon')) {\r\n appMediaPlaybackController.toggle();\r\n }\r\n });\r\n\r\n this.divAndCaption.border.remove();\r\n\r\n this.toggleEl = document.createElement('button');\r\n this.toggleEl.classList.add('pinned-audio-ico', 'tgico', 'btn-icon');\r\n attachClickEvent(this.toggleEl, (e) => {\r\n cancelEvent(e);\r\n appMediaPlaybackController.toggle();\r\n }, {listenerSetter: this.topbar.listenerSetter});\r\n\r\n this.wrapper.prepend(this.toggleEl);\r\n\r\n this.topbar.listenerSetter.add(rootScope, 'audio_play', (e) => {\r\n const {doc, mid, peerId} = e;\r\n\r\n let title: string, subtitle: string;\r\n const message = appMessagesManager.getMessageByPeer(peerId, mid);\r\n if(doc.type === 'voice' || doc.type === 'round') {\r\n title = appPeersManager.getPeerTitle(message.fromId, false, true);\r\n //subtitle = 'Voice message';\r\n subtitle = formatDate(message.date, false, false);\r\n } else {\r\n title = doc.audioTitle || doc.file_name;\r\n subtitle = doc.audioPerformer ? RichTextProcessor.wrapPlainText(doc.audioPerformer) : 'Unknown Artist';\r\n }\r\n\r\n this.fill(title, subtitle, message);\r\n this.toggleEl.classList.add('flip-icon');\r\n this.toggle(false);\r\n });\r\n\r\n this.topbar.listenerSetter.add(rootScope, 'audio_pause', () => {\r\n this.toggleEl.classList.remove('flip-icon');\r\n });\r\n }\r\n}","// https://github.com/evgeny-nadymov/telegram-react/blob/master/src/Components/ColumnMiddle/PinnedMessageBorder.js\r\n\r\nexport default class PinnedMessageBorder {\r\n private border: HTMLElement;\r\n private wrapper: HTMLElement;\r\n private svg: SVGSVGElement;\r\n private defs: SVGDefsElement;\r\n private clipPath: SVGClipPathElement;\r\n private path: SVGPathElement;\r\n private mark: HTMLElement;\r\n\r\n private count: number;\r\n private index: number;\r\n\r\n private drawRect = (x: number, y: number, width: number, height: number, radius: number) => {\r\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`;\r\n };\r\n\r\n private getClipPath = (id: string, barHeight: number, count: number) => {\r\n const radius = 1;\r\n\r\n let d = '';\r\n if(count === 3) {\r\n d = this.drawRect(0, 0, 2, barHeight, radius)\r\n + this.drawRect(0, 11, 2, barHeight + 1, radius)\r\n + this.drawRect(0, 23, 2, barHeight, radius);\r\n } else {\r\n for(let i = 0; i < count; i++) {\r\n d += this.drawRect(0, (barHeight + 2) * i, 2, barHeight, radius);\r\n }\r\n }\r\n\r\n if(!this.clipPath) {\r\n this.clipPath = document.createElementNS('http://www.w3.org/2000/svg', 'clipPath');\r\n this.path = document.createElementNS('http://www.w3.org/2000/svg', 'path');\r\n\r\n this.clipPath.append(this.path);\r\n }\r\n\r\n this.clipPath.id = id;\r\n this.path.setAttributeNS(null, 'd', d);\r\n\r\n return this.clipPath;\r\n };\r\n\r\n private getBarHeight = (count: number, index: number) => {\r\n let barHeight = 32;\r\n if(count === 1) {\r\n barHeight = 32;\r\n } else if(count === 2) {\r\n barHeight = 15;\r\n } else if(count === 3) {\r\n barHeight = 9;\r\n } else if(count === 4) {\r\n barHeight = 7;\r\n } else if(count > 3) {\r\n barHeight = 7;\r\n }\r\n\r\n return barHeight;\r\n };\r\n\r\n private getMarkHeight = (count: number, index: number) => {\r\n let barHeight = 32;\r\n if(count === 1) {\r\n barHeight = 32;\r\n } else if(count === 2) {\r\n barHeight = 15;\r\n } else if(count === 3) {\r\n barHeight = index === 1 ? 10 : 9;\r\n } else if(count === 4) {\r\n barHeight = 7;\r\n } else if(count > 3) {\r\n barHeight = 7;\r\n }\r\n\r\n return barHeight;\r\n };\r\n\r\n private getMarkTranslateY = (index: number, barHeight: number, count: number) => {\r\n if(count === 1) {\r\n return 0;\r\n } else if(count === 2) {\r\n return index === 0 ? 0 : barHeight + 2;\r\n }\r\n\r\n if(count === 3) {\r\n if(index === 0) {\r\n return 0;\r\n } else if (index === 1) {\r\n return 11;\r\n }\r\n\r\n return 23;\r\n } else {\r\n return (barHeight + 2) * index;\r\n }\r\n };\r\n\r\n private getTrackTranslateY = (index: number, count: number, barHeight: number, trackHeight: number) => {\r\n if(count <= 4) {\r\n return 0;\r\n }\r\n\r\n if(index <= 1) {\r\n return 0;\r\n } else if(index >= count - 2) {\r\n return trackHeight - 32;\r\n }\r\n\r\n return (barHeight + 4) / 2 + (index - 2) * (barHeight + 2);\r\n };\r\n\r\n private getTrackHeight = (count: number, barHeight: number) => {\r\n return count <= 3 ? 32 : barHeight * count + 2 * (count - 1);\r\n };\r\n\r\n public render(count: number, index: number) {\r\n if(!this.border) {\r\n this.border = document.createElement('div');\r\n this.border.classList.add('pinned-message-border');\r\n\r\n this.wrapper = document.createElement('div');\r\n this.border.append(this.wrapper);\r\n }\r\n \r\n if(count === 1) {\r\n if(this.count !== count) {\r\n this.wrapper.className = 'pinned-message-border-wrapper-1';\r\n this.border.classList.remove('pinned-message-border-mask');\r\n this.wrapper.innerHTML = this.wrapper.style.cssText = '';\r\n }\r\n\r\n return this.border;\r\n }\r\n\r\n const barHeight = this.getBarHeight(count, index);\r\n const markHeight = this.getMarkHeight(count, index);\r\n const trackHeight = this.getTrackHeight(count, barHeight);\r\n\r\n const clipPathId = `clipPath_${count}`;\r\n const clipPath = this.getClipPath(clipPathId, barHeight, count);\r\n\r\n const markTranslateY = this.getMarkTranslateY(index, barHeight, count);\r\n const trackTranslateY = this.getTrackTranslateY(index, count, barHeight, trackHeight);\r\n\r\n this.border.classList.toggle('pinned-message-border-mask', count > 4);\r\n\r\n this.wrapper.className = 'pinned-message-border-wrapper';\r\n this.wrapper.style.cssText = `clip-path: url(#${clipPathId}); width: 2px; height: ${trackHeight}px; transform: translateY(-${trackTranslateY}px);`;\r\n \r\n if(!this.svg) {\r\n this.svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\r\n this.svg.setAttributeNS(null, 'height', '0');\r\n this.svg.setAttributeNS(null, 'width', '0');\r\n \r\n this.defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs');\r\n this.defs.append(clipPath);\r\n\r\n this.svg.append(this.defs);\r\n\r\n this.mark = document.createElement('div');\r\n this.mark.classList.add('pinned-message-border-mark');\r\n }\r\n\r\n if(!this.svg.parentElement) {\r\n this.wrapper.append(this.svg, this.mark);\r\n }\r\n\r\n this.mark.style.cssText = `height: ${markHeight}px; transform: translateY(${markTranslateY}px);`;\r\n \r\n this.count = count;\r\n this.index = index;\r\n\r\n return this.border;\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 { 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 { attachClickEvent, cancelEvent, handleScrollSideEvent } from \"../../helpers/dom\";\r\nimport Chat from \"./chat\";\r\nimport ListenerSetter from \"../../helpers/listenerSetter\";\r\nimport ButtonIcon from \"../buttonIcon\";\r\nimport { debounce } from \"../../helpers/schedulers\";\r\nimport { getHeavyAnimationPromise } from \"../../hooks/useHeavyAnimationCheck\";\r\nimport { i18n } from \"../../lib/langPack\";\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 public static LOAD_COUNT = 50;\r\n public static LOAD_OFFSET = 5;\r\n\r\n public pinnedMessageContainer: PinnedContainer;\r\n public pinnedMessageBorder: PinnedMessageBorder;\r\n\r\n public pinnedMaxMid = 0;\r\n public pinnedMid = 0;\r\n public pinnedIndex = -1;\r\n public wasPinnedIndex = 0;\r\n public wasPinnedMediaIndex = 0;\r\n \r\n public locked = false;\r\n public waitForScrollBottom = false;\r\n\r\n public count = 0;\r\n public mids: number[] = [];\r\n public offsetIndex = 0;\r\n\r\n public loading = false;\r\n public loadedBottom = false;\r\n public loadedTop = false;\r\n\r\n public animatedSubtitle: AnimatedSuper;\r\n public animatedMedia: AnimatedSuper;\r\n public animatedCounter: AnimatedCounter;\r\n\r\n public listenerSetter: ListenerSetter;\r\n public scrollDownListenerSetter: ListenerSetter = null;\r\n\r\n public hidden = false;\r\n\r\n public getCurrentIndexPromise: Promise<any> = null;\r\n public btnOpen: HTMLButtonElement;\r\n \r\n public setPinnedMessage: () => void;\r\n\r\n private isStatic = false;\r\n\r\n private debug = false;\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 this.pinnedMessageContainer = new PinnedContainer(topbar, chat, this.listenerSetter, 'message', new ReplyContainer('pinned-message'), 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 this.pinnedMessageBorder = new PinnedMessageBorder();\r\n this.pinnedMessageContainer.divAndCaption.border.replaceWith(this.pinnedMessageBorder.render(1, 0));\r\n\r\n this.animatedSubtitle = new AnimatedSuper();\r\n this.pinnedMessageContainer.divAndCaption.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 this.pinnedMessageContainer.divAndCaption.content.prepend(this.animatedMedia.container);\r\n\r\n this.animatedCounter = new AnimatedCounter(true);\r\n this.pinnedMessageContainer.divAndCaption.title.append(i18n('PinnedMessage'), ' ', this.animatedCounter.container);\r\n\r\n this.btnOpen = ButtonIcon('pinlist pinned-container-close pinned-message-pinlist', {noRipple: true});\r\n this.pinnedMessageContainer.divAndCaption.container.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', (e) => {\r\n const peerId = e.peerId;\r\n\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', (e) => {\r\n const {peerId, maxId} = e;\r\n\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\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 _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 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 });\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 ChatTopbar from \"./topbar\";\r\nimport { cancelEvent, whichChild } from \"../../helpers/dom\";\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\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\r\n constructor(private topbar: ChatTopbar, private chat: Chat) {\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 this.backBtn.addEventListener('click', () => {\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.footer.removeEventListener('click', this.onFooterClick);\r\n this.dateBtn.removeEventListener('click', this.onDateClick);\r\n this.upBtn.removeEventListener('click', this.onUpClick);\r\n this.downBtn.removeEventListener('click', this.onDownClick);\r\n this.searchGroup.list.removeEventListener('click', this.onResultsClick);\r\n this.chat.bubbles.bubblesContainer.classList.remove('search-results-active');\r\n }, {once: true});\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('', 'messages', undefined, '', false);\r\n this.searchGroup.list.addEventListener('click', 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 this.foundCountEl.innerText = this.inputSearch.value ? 'No results' : '';\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 this.footer.addEventListener('click', 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 this.dateBtn.addEventListener('click', this.onDateClick);\r\n this.upBtn.addEventListener('click', this.onUpClick);\r\n this.downBtn.addEventListener('click', 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\r\n onDateClick = (e: MouseEvent) => {\r\n cancelEvent(e);\r\n new PopupDatePicker(new Date(), this.chat.bubbles.onDatePick).show();\r\n };\r\n\r\n selectResult = (elem: HTMLElement) => {\r\n if(this.setPeerPromise) return this.setPeerPromise;\r\n\r\n const peerId = +elem.dataset.peerId;\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 this.foundCountEl.innerText = `${index + 1} of ${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 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 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 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 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 * 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, { AppSidebarRight } from \"..\";\r\nimport AppSearch, { SearchGroup } from \"../../appSearch\";\r\nimport InputSearch from \"../../inputSearch\";\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\r\n private peerId = 0;\r\n private threadId = 0;\r\n\r\n onOpenAfterTimeout() {\r\n this.appSearch.beginSearch(this.peerId, this.threadId);\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 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('Private Search', 'messages')\r\n });\r\n }\r\n\r\n open(peerId: number, threadId?: number) {\r\n const ret = super.open();\r\n if(this.init) {\r\n this.init();\r\n this.init = null;\r\n }\r\n\r\n if(this.peerId !== 0) {\r\n this.appSearch.beginSearch(this.peerId, this.threadId);\r\n return ret;\r\n }\r\n\r\n this.peerId = peerId;\r\n this.threadId = threadId;\r\n \r\n appSidebarRight.toggleSidebar(true);\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 { AppNotificationsManager } from \"../../lib/appManagers/appNotificationsManager\";\r\nimport type { AppChatsManager, Channel } from \"../../lib/appManagers/appChatsManager\";\r\nimport type { AppMessagesManager } from \"../../lib/appManagers/appMessagesManager\";\r\nimport type { AppPeersManager } from \"../../lib/appManagers/appPeersManager\";\r\nimport type { AppSidebarRight } from \"../sidebarRight\";\r\nimport type Chat from \"./chat\";\r\nimport { cancelEvent, attachClickEvent, blurActiveElement } from \"../../helpers/dom\";\r\nimport mediaSizes, { ScreenSize } from \"../../helpers/mediaSizes\";\r\nimport { isSafari } from \"../../helpers/userAgent\";\r\nimport rootScope from \"../../lib/rootScope\";\r\nimport AvatarElement from \"../avatar\";\r\nimport Button from \"../button\";\r\nimport ButtonIcon from \"../buttonIcon\";\r\nimport ButtonMenuToggle from \"../buttonMenuToggle\";\r\nimport ChatAudio from \"./audio\";\r\nimport ChatPinnedMessage from \"./pinnedMessage\";\r\nimport ChatSearch from \"./search\";\r\nimport { ButtonMenuItemOptions } from \"../buttonMenu\";\r\nimport ListenerSetter from \"../../helpers/listenerSetter\";\r\nimport appStateManager from \"../../lib/appManagers/appStateManager\";\r\nimport PopupDeleteDialog from \"../popups/deleteDialog\";\r\nimport appNavigationController from \"../appNavigationController\";\r\nimport { LEFT_COLUMN_ACTIVE_CLASSNAME } from \"../sidebarLeft\";\r\nimport AppPrivateSearchTab from \"../sidebarRight/tabs/search\";\r\nimport PeerTitle from \"../peerTitle\";\r\nimport { i18n } from \"../../lib/langPack\";\r\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\r\n\r\nexport default class ChatTopbar {\r\n container: HTMLDivElement;\r\n btnBack: HTMLButtonElement;\r\n chatInfo: HTMLDivElement;\r\n avatarElement: AvatarElement;\r\n title: HTMLDivElement;\r\n subtitle: HTMLDivElement;\r\n chatUtils: HTMLDivElement;\r\n btnJoin: HTMLButtonElement;\r\n btnPinned: HTMLButtonElement;\r\n btnMute: HTMLButtonElement;\r\n btnSearch: HTMLButtonElement;\r\n btnMore: HTMLButtonElement;\r\n \r\n public chatAudio: ChatAudio;\r\n public pinnedMessage: ChatPinnedMessage;\r\n\r\n private setUtilsRAF: number;\r\n public peerId: number;\r\n public wasPeerId: number;\r\n private setPeerStatusInterval: number;\r\n\r\n public listenerSetter: ListenerSetter;\r\n\r\n public menuButtons: (ButtonMenuItemOptions & {verify: () => boolean})[] = [];\r\n\r\n constructor(private chat: Chat, private appSidebarRight: AppSidebarRight, private appMessagesManager: AppMessagesManager, private appPeersManager: AppPeersManager, private appChatsManager: AppChatsManager, private appNotificationsManager: AppNotificationsManager) {\r\n this.listenerSetter = new ListenerSetter();\r\n }\r\n\r\n public construct() {\r\n //this.chat.log.error('Topbar construction');\r\n\r\n this.container = document.createElement('div');\r\n this.container.classList.add('sidebar-header', 'topbar');\r\n\r\n this.btnBack = ButtonIcon('left sidebar-close-button', {noRipple: true});\r\n\r\n // * chat info section\r\n this.chatInfo = document.createElement('div');\r\n this.chatInfo.classList.add('chat-info');\r\n\r\n const person = document.createElement('div');\r\n person.classList.add('person');\r\n\r\n const content = document.createElement('div');\r\n content.classList.add('content');\r\n\r\n const top = document.createElement('div');\r\n top.classList.add('top');\r\n\r\n this.title = document.createElement('div');\r\n this.title.classList.add('user-title');\r\n\r\n top.append(this.title);\r\n\r\n const bottom = document.createElement('div');\r\n bottom.classList.add('bottom');\r\n\r\n if(this.subtitle) {\r\n bottom.append(this.subtitle);\r\n }\r\n\r\n content.append(top, bottom);\r\n if(this.avatarElement) {\r\n person.append(this.avatarElement);\r\n }\r\n\r\n person.append(content);\r\n this.chatInfo.append(person);\r\n\r\n // * chat utils section\r\n this.chatUtils = document.createElement('div');\r\n this.chatUtils.classList.add('chat-utils');\r\n\r\n this.chatAudio = new ChatAudio(this, this.chat, this.appMessagesManager, this.appPeersManager);\r\n\r\n if(this.menuButtons.length) {\r\n this.btnMore = ButtonMenuToggle({listenerSetter: this.listenerSetter}, 'bottom-left', this.menuButtons, (e) => {\r\n cancelEvent(e);\r\n this.menuButtons.forEach(button => {\r\n button.element.classList.toggle('hide', !button.verify());\r\n });\r\n\r\n // delete button\r\n this.menuButtons[this.menuButtons.length - 1].element.firstChild.nodeValue = this.appPeersManager.getDeleteButtonText(this.peerId);\r\n });\r\n }\r\n\r\n this.chatUtils.append(...[this.chatAudio ? this.chatAudio.divAndCaption.container : null, this.pinnedMessage ? this.pinnedMessage.pinnedMessageContainer.divAndCaption.container : null, this.btnJoin, this.btnPinned, this.btnMute, this.btnSearch, this.btnMore].filter(Boolean));\r\n\r\n this.container.append(this.btnBack, this.chatInfo, this.chatUtils);\r\n\r\n // * construction end\r\n\r\n // * fix topbar overflow section\r\n\r\n this.listenerSetter.add(window, 'resize', this.onResize);\r\n mediaSizes.addEventListener('changeScreen', this.onChangeScreen);\r\n\r\n attachClickEvent(this.container, (e) => {\r\n const container: HTMLElement = findUpClassName(e.target, 'pinned-container');\r\n blurActiveElement();\r\n if(container) {\r\n cancelEvent(e);\r\n \r\n const mid = +container.dataset.mid;\r\n const peerId = +container.dataset.peerId;\r\n if(container.classList.contains('pinned-message')) {\r\n //if(!this.pinnedMessage.locked) {\r\n this.pinnedMessage.followPinnedMessage(mid);\r\n //}\r\n } else {\r\n this.chat.appImManager.setInnerPeer(peerId, mid);\r\n }\r\n } else {\r\n if(mediaSizes.activeScreen === ScreenSize.medium && document.body.classList.contains(LEFT_COLUMN_ACTIVE_CLASSNAME)) {\r\n onBtnBackClick();\r\n } else {\r\n this.appSidebarRight.toggleSidebar(true);\r\n }\r\n }\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n const onBtnBackClick = (e?: Event) => {\r\n if(e) {\r\n cancelEvent(e);\r\n }\r\n\r\n //const item = appNavigationController.findItemByType('chat');\r\n // * return manually to chat by arrow, since can't get back to\r\n if(mediaSizes.activeScreen === ScreenSize.medium && document.body.classList.contains(LEFT_COLUMN_ACTIVE_CLASSNAME)) {\r\n this.chat.appImManager.setPeer(this.peerId);\r\n } else {\r\n const isFirstChat = this.chat.appImManager.chats.indexOf(this.chat) === 0;\r\n appNavigationController.back(isFirstChat ? 'im' : 'chat');\r\n return;\r\n\r\n if(mediaSizes.activeScreen === ScreenSize.medium && !appNavigationController.findItemByType('chat')) {\r\n this.chat.appImManager.setPeer(0);\r\n blurActiveElement();\r\n } else {\r\n appNavigationController.back('chat');\r\n }\r\n }\r\n };\r\n\r\n attachClickEvent(this.btnBack, onBtnBackClick, {listenerSetter: this.listenerSetter});\r\n }\r\n\r\n public constructUtils() {\r\n this.menuButtons = [{\r\n icon: 'search',\r\n text: 'Search',\r\n onClick: () => {\r\n new ChatSearch(this, this.chat);\r\n },\r\n verify: () => mediaSizes.isMobile\r\n }, /* {\r\n icon: 'pinlist',\r\n text: 'Pinned Messages',\r\n onClick: () => this.openPinned(false),\r\n verify: () => mediaSizes.isMobile\r\n }, */ {\r\n icon: 'mute',\r\n text: 'ChatList.Context.Mute',\r\n onClick: () => {\r\n this.appMessagesManager.mutePeer(this.peerId);\r\n },\r\n verify: () => this.chat.type === 'chat' && rootScope.myId !== this.peerId && !this.appNotificationsManager.isPeerLocalMuted(this.peerId, false)\r\n }, {\r\n icon: 'unmute',\r\n text: 'ChatList.Context.Unmute',\r\n onClick: () => {\r\n this.appMessagesManager.mutePeer(this.peerId);\r\n },\r\n verify: () => this.chat.type === 'chat' && rootScope.myId !== this.peerId && this.appNotificationsManager.isPeerLocalMuted(this.peerId, false)\r\n }, {\r\n icon: 'select',\r\n text: 'Chat.Menu.SelectMessages',\r\n onClick: () => {\r\n this.chat.selection.toggleSelection(true, true);\r\n },\r\n verify: () => !this.chat.selection.isSelecting && !!Object.keys(this.chat.bubbles.bubbles).length\r\n }, {\r\n icon: 'select',\r\n text: 'Chat.Menu.ClearSelection',\r\n onClick: () => {\r\n this.chat.selection.cancelSelection();\r\n },\r\n verify: () => this.chat.selection.isSelecting\r\n }, {\r\n icon: 'delete danger',\r\n text: 'Delete',\r\n onClick: () => {\r\n new PopupDeleteDialog(this.peerId);\r\n },\r\n verify: () => this.chat.type === 'chat' && !!this.appMessagesManager.getDialogByPeerId(this.peerId)[0]\r\n }];\r\n\r\n this.btnSearch = ButtonIcon('search');\r\n attachClickEvent(this.btnSearch, (e) => {\r\n cancelEvent(e);\r\n if(this.peerId) {\r\n let tab = this.appSidebarRight.getTab(AppPrivateSearchTab);\r\n if(!tab) {\r\n tab = new AppPrivateSearchTab(this.appSidebarRight);\r\n }\r\n\r\n tab.open(this.peerId, this.chat.threadId);\r\n }\r\n }, {listenerSetter: this.listenerSetter});\r\n }\r\n\r\n public constructPeerHelpers() {\r\n this.avatarElement = new AvatarElement();\r\n this.avatarElement.setAttribute('dialog', '1');\r\n //this.avatarElement.setAttribute('clickable', '');\r\n this.avatarElement.classList.add('avatar-42', 'person-avatar');\r\n\r\n this.subtitle = document.createElement('div');\r\n this.subtitle.classList.add('info');\r\n\r\n this.pinnedMessage = new ChatPinnedMessage(this, this.chat, this.appMessagesManager, this.appPeersManager);\r\n\r\n this.btnJoin = Button('btn-primary btn-color-primary chat-join hide');\r\n this.btnJoin.append(i18n('Chat.Subscribe'));\r\n\r\n this.btnPinned = ButtonIcon('pinlist');\r\n this.btnMute = ButtonIcon('mute');\r\n\r\n attachClickEvent(this.btnPinned, (e) => {\r\n cancelEvent(e);\r\n blurActiveElement();\r\n this.openPinned(true);\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n attachClickEvent(this.btnMute, (e) => {\r\n cancelEvent(e);\r\n blurActiveElement();\r\n this.appMessagesManager.mutePeer(this.peerId);\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n attachClickEvent(this.btnJoin, (e) => {\r\n cancelEvent(e);\r\n\r\n blurActiveElement();\r\n this.btnJoin.setAttribute('disabled', 'true');\r\n this.appChatsManager.joinChannel(-this.peerId).finally(() => {\r\n this.btnJoin.removeAttribute('disabled');\r\n });\r\n //});\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n this.listenerSetter.add(rootScope, 'chat_update', (e) => {\r\n const peerId: number = e;\r\n if(this.peerId === -peerId) {\r\n const chat = this.appChatsManager.getChat(peerId) as Channel/* | Chat */;\r\n \r\n this.btnJoin.classList.toggle('hide', !(chat as Channel)?.pFlags?.left);\r\n this.setUtilsWidth();\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope, 'dialog_notify_settings', (dialog) => {\r\n if(dialog.peerId === this.peerId) {\r\n this.setMutedState();\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope, 'peer_typings', (e) => {\r\n const {peerId} = e;\r\n\r\n if(this.peerId === peerId) {\r\n this.setPeerStatus();\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope, 'user_update', (e) => {\r\n const userId = e;\r\n\r\n if(this.peerId === userId) {\r\n this.setPeerStatus();\r\n }\r\n });\r\n\r\n if(this.pinnedMessage) {\r\n this.chat.addEventListener('setPeer', (mid, isTopMessage) => {\r\n const middleware = this.chat.bubbles.getMiddleware();\r\n appStateManager.getState().then((state) => {\r\n if(!middleware()) return;\r\n \r\n this.pinnedMessage.hidden = !!state.hiddenPinnedMessages[this.chat.peerId];\r\n \r\n if(isTopMessage) {\r\n this.pinnedMessage.unsetScrollDownListener();\r\n this.pinnedMessage.testMid(mid, 0); // * because slider will not let get bubble by document.elementFromPoint\r\n } else if(!this.pinnedMessage.locked) {\r\n this.pinnedMessage.handleFollowingPinnedMessage();\r\n this.pinnedMessage.testMid(mid);\r\n }\r\n });\r\n });\r\n }\r\n\r\n this.setPeerStatusInterval = window.setInterval(this.setPeerStatus, 60e3);\r\n\r\n return this;\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\r\n if(peerId !== this.peerId) return;\r\n\r\n if(mids) {\r\n this.setTitle();\r\n }\r\n });\r\n }\r\n \r\n public constructDiscussionHelpers() {\r\n this.pinnedMessage = new ChatPinnedMessage(this, this.chat, this.appMessagesManager, this.appPeersManager);\r\n }\r\n\r\n public openPinned(byCurrent: boolean) {\r\n this.chat.appImManager.setInnerPeer(this.peerId, byCurrent ? +this.pinnedMessage.pinnedMessageContainer.divAndCaption.container.dataset.mid : 0, 'pinned');\r\n }\r\n\r\n private onResize = () => {\r\n this.setUtilsWidth(true);\r\n };\r\n\r\n private onChangeScreen = (from: ScreenSize, to: ScreenSize) => {\r\n this.container.classList.toggle('is-pinned-floating', mediaSizes.isMobile);\r\n this.chatAudio && this.chatAudio.divAndCaption.container.classList.toggle('is-floating', to === ScreenSize.mobile);\r\n this.pinnedMessage && this.pinnedMessage.pinnedMessageContainer.divAndCaption.container.classList.toggle('is-floating', to === ScreenSize.mobile);\r\n this.setUtilsWidth(true);\r\n };\r\n\r\n public destroy() {\r\n //this.chat.log.error('Topbar destroying');\r\n\r\n this.listenerSetter.removeAll();\r\n mediaSizes.removeEventListener('changeScreen', this.onChangeScreen);\r\n window.clearInterval(this.setPeerStatusInterval);\r\n \r\n if(this.pinnedMessage) {\r\n this.pinnedMessage.destroy(); // * возможно это можно не делать\r\n }\r\n\r\n delete this.chatAudio;\r\n delete this.pinnedMessage;\r\n }\r\n\r\n public setPeer(peerId: number) {\r\n this.wasPeerId = this.peerId;\r\n this.peerId = peerId;\r\n\r\n this.container.style.display = peerId ? '' : 'none';\r\n }\r\n\r\n public finishPeerChange(isTarget: boolean, isJump: boolean, lastMsgId: number) {\r\n const peerId = this.peerId;\r\n\r\n if(this.avatarElement) {\r\n this.avatarElement.setAttribute('peer', '' + peerId);\r\n this.avatarElement.update();\r\n }\r\n\r\n const isBroadcast = this.appPeersManager.isBroadcast(peerId);\r\n\r\n this.btnMute && this.btnMute.classList.toggle('hide', !isBroadcast);\r\n this.btnJoin && this.btnJoin.classList.toggle('hide', !this.appChatsManager.getChat(-peerId)?.pFlags?.left);\r\n this.setUtilsWidth();\r\n\r\n const middleware = this.chat.bubbles.getMiddleware();\r\n if(this.pinnedMessage) { // * replace with new one\r\n if(this.chat.type === 'chat') {\r\n if(this.wasPeerId) { // * change\r\n const newPinnedMessage = new ChatPinnedMessage(this, this.chat, this.appMessagesManager, this.appPeersManager);\r\n this.pinnedMessage.pinnedMessageContainer.divAndCaption.container.replaceWith(newPinnedMessage.pinnedMessageContainer.divAndCaption.container);\r\n this.pinnedMessage.destroy();\r\n //this.pinnedMessage.pinnedMessageContainer.toggle(true);\r\n this.pinnedMessage = newPinnedMessage;\r\n }\r\n \r\n appStateManager.getState().then((state) => {\r\n if(!middleware()) return;\r\n \r\n this.pinnedMessage.hidden = !!state.hiddenPinnedMessages[peerId];\r\n \r\n if(!isTarget) {\r\n this.pinnedMessage.setCorrectIndex(0);\r\n }\r\n });\r\n } else if(this.chat.type === 'discussion') {\r\n this.pinnedMessage.pinnedMid = this.chat.threadId;\r\n this.pinnedMessage.count = 1;\r\n this.pinnedMessage.pinnedIndex = 0;\r\n this.pinnedMessage._setPinnedMessage();\r\n }\r\n }\r\n\r\n window.requestAnimationFrame(() => {\r\n this.setTitle();\r\n this.setPeerStatus(true);\r\n this.setMutedState();\r\n });\r\n }\r\n\r\n public setTitle(count?: number) {\r\n let titleEl: HTMLElement;\r\n if(this.chat.type === 'pinned') {\r\n if(count === undefined) titleEl = i18n('Loading');\r\n else titleEl = i18n('PinnedMessagesCount', [count]);\r\n\r\n if(count === undefined) {\r\n this.appMessagesManager.getSearchCounters(this.peerId, [{_: 'inputMessagesFilterPinned'}], false).then(result => {\r\n const count = result[0].count;\r\n this.setTitle(count);\r\n\r\n // ! костыль х2, это нужно делать в другом месте\r\n if(!count) {\r\n this.chat.appImManager.setPeer(0); // * 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 } else if(this.chat.type === 'scheduled') {\r\n if(this.peerId === rootScope.myId) {\r\n //title = [count > 1 ? count : false, 'Reminders'].filter(Boolean).join(' ');\r\n titleEl = i18n('Reminders');\r\n } else {\r\n titleEl = i18n('ScheduledMessages');\r\n //title = [count > 1 ? count : false, 'Scheduled Messages'].filter(Boolean).join(' ');\r\n }\r\n \r\n if(count === undefined) {\r\n this.appMessagesManager.getScheduledMessages(this.peerId).then(mids => {\r\n this.setTitle(mids.length);\r\n });\r\n }\r\n } else if(this.chat.type === 'discussion') {\r\n if(count === undefined) titleEl = i18n('Loading');\r\n else titleEl = i18n('Chat.Title.Comments', [count]);\r\n\r\n if(count === undefined) {\r\n Promise.all([\r\n this.appMessagesManager.getHistory(this.peerId, 0, 1, 0, this.chat.threadId),\r\n Promise.resolve()\r\n ]).then(() => {\r\n const count = this.appMessagesManager.getHistoryStorage(this.peerId, this.chat.threadId).count;\r\n if(count === null) {\r\n setTimeout(() => {\r\n this.setTitle();\r\n }, 30);\r\n } else {\r\n this.setTitle(count);\r\n }\r\n });\r\n }\r\n } else if(this.chat.type === 'chat') {\r\n titleEl = new PeerTitle({\r\n peerId: this.peerId,\r\n dialog: true,\r\n }).element;\r\n }\r\n \r\n this.title.textContent = '';\r\n this.title.append(titleEl);\r\n }\r\n\r\n public setMutedState() {\r\n if(!this.btnMute) return;\r\n\r\n const peerId = this.peerId;\r\n let muted = this.appNotificationsManager.isPeerLocalMuted(peerId, false);\r\n if(this.appPeersManager.isBroadcast(peerId)) { // not human\r\n this.btnMute.classList.remove('tgico-mute', 'tgico-unmute');\r\n this.btnMute.classList.add(muted ? 'tgico-unmute' : 'tgico-mute');\r\n this.btnMute.style.display = '';\r\n } else {\r\n this.btnMute.style.display = 'none';\r\n }\r\n }\r\n\r\n // ! У МЕНЯ ПРОСТО СГОРЕЛО, САФАРИ КОНЧЕННЫЙ БРАУЗЕР - ЕСЛИ НЕ СКРЫВАТЬ БЛОК, ТО ПРИ ПЕРЕВОРОТЕ ЭКРАНА НА АЙФОНЕ БЛОК БУДЕТ НЕПРАВИЛЬНО ШИРИНЫ, ДАЖЕ БЕЗ ЭТОЙ ФУНКЦИИ!\r\n public setUtilsWidth = (resize = false) => {\r\n //return;\r\n if(this.setUtilsRAF) window.cancelAnimationFrame(this.setUtilsRAF);\r\n\r\n if(isSafari && resize) {\r\n this.chatUtils.classList.add('hide');\r\n }\r\n\r\n //mutationObserver.disconnect();\r\n this.setUtilsRAF = window.requestAnimationFrame(() => {\r\n \r\n //mutationRAF = window.requestAnimationFrame(() => {\r\n \r\n //setTimeout(() => {\r\n if(isSafari && resize) {\r\n this.chatUtils.classList.remove('hide');\r\n }\r\n /* this.chatInfo.style.removeProperty('--utils-width');\r\n void this.chatInfo.offsetLeft; // reflow */\r\n const width = /* chatUtils.scrollWidth */this.chatUtils.getBoundingClientRect().width;\r\n this.chat.log('utils width:', width);\r\n this.chatInfo.style.setProperty('--utils-width', width + 'px');\r\n //this.chatInfo.classList.toggle('have-utils-width', !!width);\r\n //}, 0);\r\n \r\n this.setUtilsRAF = 0;\r\n\r\n //mutationObserver.observe(chatUtils, observeOptions);\r\n //});\r\n });\r\n };\r\n\r\n public setPeerStatus = (needClear = false) => {\r\n if(!this.subtitle) return;\r\n\r\n const peerId = this.peerId;\r\n if(needClear) {\r\n this.subtitle.innerHTML = '';\r\n }\r\n\r\n this.chat.appImManager.getPeerStatus(this.peerId).then((subtitle) => {\r\n if(peerId !== this.peerId) {\r\n return;\r\n }\r\n\r\n this.subtitle.textContent = '';\r\n this.subtitle.append(subtitle);\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 { AppNotificationsManager } from \"../../lib/appManagers/appNotificationsManager\";\r\nimport type { AppChatsManager } from \"../../lib/appManagers/appChatsManager\";\r\nimport type { AppDocsManager } from \"../../lib/appManagers/appDocsManager\";\r\nimport type { AppImManager } from \"../../lib/appManagers/appImManager\";\r\nimport type { AppInlineBotsManager } from \"../../lib/appManagers/appInlineBotsManager\";\r\nimport type { AppMessagesManager } from \"../../lib/appManagers/appMessagesManager\";\r\nimport type { AppPeersManager } from \"../../lib/appManagers/appPeersManager\";\r\nimport type { AppPhotosManager } from \"../../lib/appManagers/appPhotosManager\";\r\nimport type { AppPollsManager } from \"../../lib/appManagers/appPollsManager\";\r\nimport type { AppProfileManager } from \"../../lib/appManagers/appProfileManager\";\r\nimport type { AppStickersManager } from \"../../lib/appManagers/appStickersManager\";\r\nimport type { AppUsersManager } from \"../../lib/appManagers/appUsersManager\";\r\nimport type { AppWebPagesManager } from \"../../lib/appManagers/appWebPagesManager\";\r\nimport type { ApiManagerProxy } from \"../../lib/mtproto/mtprotoworker\";\r\nimport type { AppDraftsManager } from \"../../lib/appManagers/appDraftsManager\";\r\nimport type { ServerTimeManager } from \"../../lib/mtproto/serverTimeManager\";\r\nimport type sessionStorage from '../../lib/sessionStorage';\r\nimport EventListenerBase from \"../../helpers/eventListenerBase\";\r\nimport { logger, LogLevels } from \"../../lib/logger\";\r\nimport rootScope from \"../../lib/rootScope\";\r\nimport appSidebarRight from \"../sidebarRight\";\r\nimport ChatBubbles from \"./bubbles\";\r\nimport ChatContextMenu from \"./contextMenu\";\r\nimport ChatInput from \"./input\";\r\nimport ChatSelection from \"./selection\";\r\nimport ChatTopbar from \"./topbar\";\r\nimport { REPLIES_PEER_ID } from \"../../lib/mtproto/mtproto_config\";\r\nimport SetTransition from \"../singleTransition\";\r\nimport { fastRaf } from \"../../helpers/schedulers\";\r\nimport AppPrivateSearchTab from \"../sidebarRight/tabs/search\";\r\nimport type { State } from \"../../lib/appManagers/appStateManager\";\r\nimport renderImageFromUrl from \"../../helpers/dom/renderImageFromUrl\";\r\n\r\nexport type ChatType = 'chat' | 'pinned' | 'replies' | 'discussion' | 'scheduled';\r\n\r\nexport default class Chat extends EventListenerBase<{\r\n setPeer: (mid: number, isTopMessage: boolean) => void\r\n}> {\r\n public container: HTMLElement;\r\n public backgroundEl: HTMLElement;\r\n\r\n public topbar: ChatTopbar;\r\n public bubbles: ChatBubbles;\r\n public input: ChatInput;\r\n public selection: ChatSelection;\r\n public contextMenu: ChatContextMenu;\r\n\r\n public wasAlreadyUsed = false;\r\n public initPeerId = 0;\r\n public peerId = 0;\r\n public threadId: number;\r\n public setPeerPromise: Promise<void>;\r\n public peerChanged: boolean;\r\n\r\n public log: ReturnType<typeof logger>;\r\n\r\n public type: ChatType = 'chat';\r\n\r\n public noAutoDownloadMedia: boolean;\r\n \r\n constructor(public appImManager: AppImManager, public appChatsManager: AppChatsManager, public appDocsManager: AppDocsManager, public appInlineBotsManager: AppInlineBotsManager, public appMessagesManager: AppMessagesManager, public appPeersManager: AppPeersManager, public appPhotosManager: AppPhotosManager, public appProfileManager: AppProfileManager, public appStickersManager: AppStickersManager, public appUsersManager: AppUsersManager, public appWebPagesManager: AppWebPagesManager, public appPollsManager: AppPollsManager, public apiManager: ApiManagerProxy, public appDraftsManager: AppDraftsManager, public serverTimeManager: ServerTimeManager, public storage: typeof sessionStorage, public appNotificationsManager: AppNotificationsManager) {\r\n super();\r\n\r\n this.container = document.createElement('div');\r\n this.container.classList.add('chat');\r\n\r\n this.backgroundEl = document.createElement('div');\r\n this.backgroundEl.classList.add('chat-background');\r\n\r\n // * constructor end\r\n\r\n this.log = logger('CHAT', LogLevels.log | LogLevels.warn | LogLevels.debug | LogLevels.error);\r\n //this.log.error('Chat construction');\r\n\r\n this.container.append(this.backgroundEl);\r\n this.appImManager.chatsContainer.append(this.container);\r\n }\r\n\r\n public setBackground(url: string): Promise<void> {\r\n const item = document.createElement('div');\r\n item.classList.add('chat-background-item');\r\n\r\n return new Promise<void>((resolve) => {\r\n const cb = () => {\r\n const prev = this.backgroundEl.children[this.backgroundEl.childElementCount - 1] as HTMLElement;\r\n this.backgroundEl.append(item);\r\n\r\n // * одного недостаточно, при обновлении страницы все равно фон появляется неплавно\r\n // ! с requestAnimationFrame лучше, но все равно иногда моргает, так что использую два фаста.\r\n fastRaf(() => {\r\n fastRaf(() => {\r\n SetTransition(item, 'is-visible', true, 200, prev ? () => {\r\n prev.remove();\r\n } : null);\r\n });\r\n });\r\n\r\n resolve();\r\n };\r\n\r\n if(url) {\r\n renderImageFromUrl(item, url, cb);\r\n } else {\r\n cb();\r\n }\r\n });\r\n }\r\n\r\n public setType(type: ChatType) {\r\n this.type = type;\r\n\r\n if(this.type === 'scheduled') {\r\n this.getMessagesStorage = () => this.appMessagesManager.getScheduledMessagesStorage(this.peerId);\r\n //this.getMessage = (mid) => this.appMessagesManager.getMessageFromStorage(this.appMessagesManager.getScheduledMessagesStorage(this.peerId), mid);\r\n }\r\n }\r\n\r\n public init(peerId: number) {\r\n this.initPeerId = peerId;\r\n\r\n this.topbar = new ChatTopbar(this, appSidebarRight, this.appMessagesManager, this.appPeersManager, this.appChatsManager, this.appNotificationsManager);\r\n this.bubbles = new ChatBubbles(this, this.appMessagesManager, this.appStickersManager, this.appUsersManager, this.appInlineBotsManager, this.appPhotosManager, this.appDocsManager, this.appPeersManager, this.appChatsManager, this.storage);\r\n this.input = new ChatInput(this, this.appMessagesManager, this.appDocsManager, this.appChatsManager, this.appPeersManager, this.appWebPagesManager, this.appImManager, this.appDraftsManager, this.serverTimeManager, this.appNotificationsManager);\r\n this.selection = new ChatSelection(this, this.bubbles, this.input, this.appMessagesManager);\r\n this.contextMenu = new ChatContextMenu(this.bubbles.bubblesContainer, this, this.appMessagesManager, this.appChatsManager, this.appPeersManager, this.appPollsManager);\r\n\r\n if(this.type === 'chat') {\r\n this.topbar.constructUtils();\r\n this.topbar.constructPeerHelpers();\r\n } else if(this.type === 'pinned') {\r\n this.topbar.constructPinnedHelpers();\r\n } else if(this.type === 'discussion') {\r\n this.topbar.constructUtils();\r\n this.topbar.constructDiscussionHelpers();\r\n }\r\n\r\n this.topbar.construct();\r\n this.input.construct();\r\n\r\n if(this.type === 'chat') { // * гений в деле, разный порядок из-за разной последовательности действий\r\n this.bubbles.constructPeerHelpers();\r\n this.input.constructPeerHelpers();\r\n } else if(this.type === 'pinned') {\r\n this.bubbles.constructPinnedHelpers();\r\n this.input.constructPinnedHelpers();\r\n } else if(this.type === 'scheduled') {\r\n this.bubbles.constructScheduledHelpers();\r\n this.input.constructPeerHelpers();\r\n } else if(this.type === 'discussion') {\r\n this.bubbles.constructPeerHelpers();\r\n this.input.constructPeerHelpers();\r\n }\r\n\r\n this.container.classList.add('type-' + this.type);\r\n this.container.append(this.topbar.container, this.bubbles.bubblesContainer, this.input.chatInput);\r\n\r\n this.bubbles.listenerSetter.add(rootScope, 'dialog_migrate', ({migrateFrom, migrateTo}) => {\r\n if(this.peerId === migrateFrom) {\r\n this.setPeer(migrateTo);\r\n }\r\n });\r\n\r\n this.bubbles.listenerSetter.add(rootScope, 'dialog_drop', (e) => {\r\n if(e.peerId === this.peerId) {\r\n this.appImManager.setPeer(0);\r\n }\r\n });\r\n }\r\n\r\n public destroy() {\r\n //const perf = performance.now();\r\n\r\n this.topbar.destroy();\r\n this.bubbles.destroy();\r\n this.input.destroy();\r\n\r\n delete this.topbar;\r\n delete this.bubbles;\r\n delete this.input;\r\n delete this.selection;\r\n delete this.contextMenu;\r\n\r\n this.container.remove();\r\n\r\n //this.log.error('Chat destroy time:', performance.now() - perf);\r\n }\r\n\r\n public cleanup(helperToo = true) {\r\n this.input.cleanup(helperToo);\r\n this.selection.cleanup();\r\n }\r\n\r\n public setPeer(peerId: number, lastMsgId?: number) {\r\n if(this.init) {\r\n this.init(peerId);\r\n this.init = null;\r\n }\r\n\r\n const samePeer = this.peerId === peerId;\r\n if(!samePeer) {\r\n rootScope.broadcast('peer_changing', this);\r\n this.peerId = peerId;\r\n } else if(this.setPeerPromise) {\r\n return;\r\n }\r\n\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 appSidebarRight.toggleSidebar(false);\r\n this.cleanup(true);\r\n this.topbar.setPeer(peerId);\r\n this.bubbles.setPeer(peerId);\r\n rootScope.broadcast('peer_changed', peerId);\r\n\r\n return;\r\n }\r\n\r\n // set new\r\n if(!samePeer) {\r\n const searchTab = appSidebarRight.getTab(AppPrivateSearchTab);\r\n if(searchTab) {\r\n searchTab.close();\r\n }\r\n\r\n appSidebarRight.sharedMediaTab.setPeer(peerId, this.threadId);\r\n this.input.clearHelper(); // костыль\r\n this.selection.cleanup(); // TODO: REFACTOR !!!!!!\r\n this.setAutoDownloadMedia();\r\n }\r\n\r\n this.peerChanged = samePeer;\r\n\r\n const result = this.bubbles.setPeer(peerId, lastMsgId);\r\n if(!result) {\r\n return;\r\n }\r\n\r\n const {promise} = result;\r\n\r\n //console.timeEnd('appImManager setPeer pre promise');\r\n \r\n const setPeerPromise = this.setPeerPromise = promise.finally(() => {\r\n if(this.setPeerPromise === setPeerPromise) {\r\n this.setPeerPromise = null;\r\n }\r\n });\r\n\r\n if(!samePeer) {\r\n appSidebarRight.sharedMediaTab.setLoadMutex(this.setPeerPromise);\r\n appSidebarRight.sharedMediaTab.loadSidebarMedia(true);\r\n }\r\n /* this.setPeerPromise.then(() => {\r\n appSidebarRight.sharedMediaTab.loadSidebarMedia(false);\r\n }); */\r\n\r\n return result;\r\n }\r\n\r\n public setAutoDownloadMedia() {\r\n let type: keyof State['settings']['autoDownload'];\r\n if(this.peerId < 0) {\r\n if(this.appPeersManager.isBroadcast(this.peerId)) {\r\n type = 'channels';\r\n } else {\r\n type = 'groups';\r\n }\r\n } else {\r\n if(this.appUsersManager.isContact(this.peerId)) {\r\n type = 'contacts';\r\n } else {\r\n type = 'private';\r\n }\r\n }\r\n\r\n this.noAutoDownloadMedia = !rootScope.settings.autoDownload[type];\r\n }\r\n\r\n public setMessageId(messageId?: number) {\r\n return this.setPeer(this.peerId, messageId);\r\n }\r\n\r\n public finishPeerChange(isTarget: boolean, isJump: boolean, lastMsgId: number) {\r\n if(this.peerChanged) return;\r\n\r\n let peerId = this.peerId;\r\n this.peerChanged = true;\r\n\r\n this.cleanup(false);\r\n\r\n this.topbar.setPeer(peerId);\r\n this.topbar.finishPeerChange(isTarget, isJump, lastMsgId);\r\n this.bubbles.finishPeerChange();\r\n this.input.finishPeerChange();\r\n\r\n appSidebarRight.sharedMediaTab.fillProfileElements();\r\n\r\n this.log.setPrefix('CHAT-' + peerId + '-' + this.type);\r\n\r\n rootScope.broadcast('peer_changed', peerId);\r\n this.wasAlreadyUsed = true;\r\n }\r\n\r\n public getMessagesStorage() {\r\n return this.appMessagesManager.getMessagesStorage(this.peerId);\r\n }\r\n\r\n public getMessage(mid: number) {\r\n return this.appMessagesManager.getMessageFromStorage(this.getMessagesStorage(), mid);\r\n //return this.appMessagesManager.getMessageByPeer(this.peerId, mid);\r\n }\r\n\r\n public getMidsByMid(mid: number) {\r\n return this.appMessagesManager.getMidsByMessage(this.getMessage(mid));\r\n }\r\n\r\n public isAnyGroup() {\r\n return this.peerId === rootScope.myId || this.peerId === REPLIES_PEER_ID || this.appPeersManager.isAnyGroup(this.peerId);\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 { AppImManager } from \"../../lib/appManagers/appImManager\";\r\nimport { MarkdownType, cancelEvent, getSelectedNodes, markdownTags, attachClickEvent, isSelectionEmpty } from \"../../helpers/dom\";\r\nimport RichTextProcessor from \"../../lib/richtextprocessor\";\r\nimport ButtonIcon from \"../buttonIcon\";\r\nimport { clamp } from \"../../helpers/number\";\r\nimport { isTouchSupported } from \"../../helpers/touchSupport\";\r\nimport { isApple, isMobile } from \"../../helpers/userAgent\";\r\nimport appNavigationController from \"../appNavigationController\";\r\nimport { _i18n } from \"../../lib/langPack\";\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', '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.code === '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 this.appImManager.chat.input.applyMarkdown('link', this.linkInput.value);\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 selectionTop = 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(!isMobile) {\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(isTouchSupported) {\r\n 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(isTouchSupported && !isApple) {\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 if(document.activeElement !== this.appImManager.chat.input.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(isTouchSupported) {\r\n if(isApple) {\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 {\r\n this.setMouseUpEvent();\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 { generatePathData } from \"../../helpers/dom\";\r\nimport { 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 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 const dropIcon = document.createElement('div');\r\n dropIcon.classList.add('drop-icon', 'tgico-' + options.icon);\r\n\r\n const dropHeader = document.createElement('div');\r\n dropHeader.classList.add('drop-header');\r\n dropHeader.append(i18n(options.header));\r\n\r\n const dropSubtitle = document.createElement('div');\r\n dropSubtitle.classList.add('drop-subtitle');\r\n dropSubtitle.append(i18n(options.subtitle));\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);\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 * 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 apiManager from '../mtproto/apiManager';\r\nimport animationIntersector from '../../components/animationIntersector';\r\nimport appSidebarLeft, { LEFT_COLUMN_ACTIVE_CLASSNAME } from \"../../components/sidebarLeft\";\r\nimport appSidebarRight, { RIGHT_COLUMN_ACTIVE_CLASSNAME } from '../../components/sidebarRight';\r\nimport mediaSizes, { ScreenSize } from '../../helpers/mediaSizes';\r\nimport { logger, LogLevels } from \"../logger\";\r\nimport apiManager from '../mtproto/mtprotoworker';\r\nimport rootScope from '../rootScope';\r\nimport apiUpdatesManager from './apiUpdatesManager';\r\nimport appUsersManager from \"./appUsersManager\";\r\nimport Chat, { ChatType } from '../../components/chat/chat';\r\nimport appChatsManager from './appChatsManager';\r\nimport appDocsManager from './appDocsManager';\r\nimport appInlineBotsManager from './appInlineBotsManager';\r\nimport appMessagesManager from './appMessagesManager';\r\nimport appPeersManager from './appPeersManager';\r\nimport appPhotosManager from './appPhotosManager';\r\nimport appProfileManager from './appProfileManager';\r\nimport appStickersManager from './appStickersManager';\r\nimport appWebPagesManager from './appWebPagesManager';\r\nimport { blurActiveElement, cancelEvent, disableTransition, placeCaretAtEnd, whichChild } from '../../helpers/dom';\r\nimport PopupNewMedia from '../../components/popups/newMedia';\r\nimport MarkupTooltip from '../../components/chat/markupTooltip';\r\nimport { isTouchSupported } from '../../helpers/touchSupport';\r\nimport appPollsManager from './appPollsManager';\r\nimport SetTransition from '../../components/singleTransition';\r\nimport ChatDragAndDrop from '../../components/chat/dragAndDrop';\r\nimport { debounce, pause, doubleRaf } from '../../helpers/schedulers';\r\nimport lottieLoader from '../lottieLoader';\r\nimport useHeavyAnimationCheck, { dispatchHeavyAnimationEvent } from '../../hooks/useHeavyAnimationCheck';\r\nimport appDraftsManager from './appDraftsManager';\r\nimport serverTimeManager from '../mtproto/serverTimeManager';\r\nimport sessionStorage from '../sessionStorage';\r\nimport appDownloadManager from './appDownloadManager';\r\nimport appStateManager, { AppStateManager } from './appStateManager';\r\nimport { MOUNT_CLASS_TO } from '../../config/debug';\r\nimport appNavigationController from '../../components/appNavigationController';\r\nimport appNotificationsManager from './appNotificationsManager';\r\nimport AppPrivateSearchTab from '../../components/sidebarRight/tabs/search';\r\nimport { i18n } from '../langPack';\r\nimport { SendMessageAction } from '../../layer';\r\nimport { highlightningColor, hslaStringToRgbString } from '../../helpers/color';\r\nimport { getObjectKeysAndSort } from '../../helpers/object';\r\nimport { getFilesFromEvent } from '../../helpers/files';\r\n\r\n//console.log('appImManager included33!');\r\n\r\nappSidebarLeft; // just to include\r\n\r\nexport const CHAT_ANIMATION_GROUP = 'chat';\r\nconst FOCUS_EVENT_NAME = isTouchSupported ? 'touchstart' : 'mousemove';\r\n\r\nexport type ChatSavedPosition = {\r\n mids: number[], \r\n top: number\r\n};\r\n\r\nexport class AppImManager {\r\n public columnEl = document.getElementById('column-center') as HTMLDivElement;\r\n public chatsContainer: HTMLElement;\r\n\r\n public offline = false;\r\n public updateStatusInterval = 0;\r\n\r\n public log: ReturnType<typeof logger>;\r\n\r\n public setPeerPromise: Promise<void> = null;\r\n\r\n public tabId = -1;\r\n \r\n public chats: Chat[] = [];\r\n private prevTab: HTMLElement;\r\n private chatsSelectTabDebounced: () => void;\r\n \r\n public markupTooltip: MarkupTooltip;\r\n private themeColorElem: Element;\r\n\r\n get myId() {\r\n return rootScope.myId;\r\n }\r\n\r\n get chat(): Chat {\r\n return this.chats[this.chats.length - 1];\r\n }\r\n\r\n constructor() {\r\n apiUpdatesManager.attach();\r\n\r\n this.log = logger('IM', LogLevels.log | LogLevels.warn | LogLevels.debug | LogLevels.error);\r\n\r\n this.selectTab(0);\r\n \r\n window.addEventListener('blur', () => {\r\n animationIntersector.checkAnimations(true);\r\n \r\n this.offline = rootScope.idle.isIDLE = true;\r\n this.updateStatus();\r\n clearInterval(this.updateStatusInterval);\r\n rootScope.broadcast('idle', rootScope.idle.isIDLE);\r\n \r\n window.addEventListener('focus', () => {\r\n this.offline = rootScope.idle.isIDLE = false;\r\n this.updateStatus();\r\n this.updateStatusInterval = window.setInterval(() => this.updateStatus(), 50e3);\r\n \r\n // в обратном порядке\r\n animationIntersector.checkAnimations(false);\r\n\r\n rootScope.broadcast('idle', rootScope.idle.isIDLE);\r\n }, {once: true});\r\n });\r\n\r\n // * Prevent setting online after reloading page\r\n window.addEventListener(FOCUS_EVENT_NAME, () => {\r\n this.updateStatusInterval = window.setInterval(() => this.updateStatus(), 50e3);\r\n this.updateStatus();\r\n\r\n this.offline = rootScope.idle.isIDLE = false;\r\n rootScope.broadcast('idle', rootScope.idle.isIDLE);\r\n }, {once: true, passive: true});\r\n\r\n this.chatsContainer = document.createElement('div');\r\n this.chatsContainer.classList.add('chats-container', 'tabs-container');\r\n this.chatsContainer.dataset.animation = 'navigation';\r\n\r\n this.columnEl.append(this.chatsContainer);\r\n \r\n this.createNewChat();\r\n this.chatsSelectTab(this.chat.container);\r\n\r\n appNavigationController.onHashChange = this.onHashChange;\r\n //window.addEventListener('hashchange', this.onHashChange);\r\n\r\n this.setSettings();\r\n rootScope.on('settings_updated', this.setSettings);\r\n\r\n useHeavyAnimationCheck(() => {\r\n animationIntersector.setOnlyOnePlayableGroup('lock');\r\n animationIntersector.checkAnimations(true);\r\n }, () => {\r\n animationIntersector.setOnlyOnePlayableGroup('');\r\n animationIntersector.checkAnimations(false);\r\n });\r\n\r\n const isDefaultBackground = rootScope.settings.background.blur === AppStateManager.STATE_INIT.settings.background.blur && \r\n rootScope.settings.background.slug === AppStateManager.STATE_INIT.settings.background.slug;\r\n if(!isDefaultBackground) {\r\n appDownloadManager.cacheStorage.getFile('backgrounds/' + rootScope.settings.background.slug).then(blob => {\r\n this.setBackground(URL.createObjectURL(blob), false);\r\n }, () => { // * if NO_ENTRY_FOUND\r\n this.setBackground('');\r\n appStateManager.setByKey('settings.background', AppStateManager.STATE_INIT.settings.background); // * reset background\r\n });\r\n } else {\r\n this.setBackground('');\r\n }\r\n\r\n // * fix simultaneous opened both sidebars, can happen when floating sidebar is opened with left sidebar\r\n mediaSizes.addEventListener('changeScreen', (from, to) => {\r\n if(document.body.classList.contains(LEFT_COLUMN_ACTIVE_CLASSNAME) \r\n && document.body.classList.contains(RIGHT_COLUMN_ACTIVE_CLASSNAME)) {\r\n appSidebarRight.toggleSidebar(false);\r\n }\r\n });\r\n\r\n rootScope.on('history_focus', (e) => {\r\n const {peerId, mid} = e;\r\n this.setInnerPeer(peerId, mid);\r\n });\r\n\r\n rootScope.on('peer_changing', (chat) => {\r\n this.saveChatPosition(chat);\r\n });\r\n\r\n sessionStorage.get('chatPositions').then((c) => {\r\n sessionStorage.setToCache('chatPositions', c || {});\r\n });\r\n }\r\n\r\n private onHashChange = () => {\r\n const hash = location.hash;\r\n const splitted = hash.split('?');\r\n\r\n if(!splitted[1]) {\r\n return;\r\n }\r\n\r\n const params: any = {};\r\n splitted[1].split('&').forEach(item => {\r\n params[item.split('=')[0]] = decodeURIComponent(item.split('=')[1]);\r\n });\r\n\r\n this.log('hashchange', hash, splitted[0], params);\r\n\r\n switch(splitted[0]) {\r\n case '#/im': {\r\n const p = params.p;\r\n let postId = params.post !== undefined ? appMessagesManager.generateMessageId(+params.post) : undefined;\r\n\r\n switch(p[0]) {\r\n case '@': {\r\n this.openUsername(p, postId);\r\n break;\r\n }\r\n\r\n default: { // peerId\r\n this.setInnerPeer(postId ? -+p : +p, postId);\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n\r\n //appNavigationController.replaceState();\r\n //location.hash = '';\r\n };\r\n\r\n public openUsername(username: string, msgId?: number) {\r\n return appUsersManager.resolveUsername(username).then(peer => {\r\n const isUser = peer._ === 'user';\r\n const peerId = isUser ? peer.id : -peer.id;\r\n\r\n return this.setInnerPeer(peerId, msgId);\r\n });\r\n }\r\n\r\n public setBackground(url: string, broadcastEvent = true): Promise<void> {\r\n const promises = this.chats.map(chat => chat.setBackground(url));\r\n return promises[promises.length - 1].then(() => {\r\n if(broadcastEvent) {\r\n rootScope.broadcast('background_change');\r\n }\r\n });\r\n }\r\n\r\n public saveChatPosition(chat: Chat) {\r\n if(!(['chat', 'discussion'] as ChatType[]).includes(chat.type) || !chat.peerId) {\r\n return;\r\n }\r\n\r\n //const bubble = chat.bubbles.getBubbleByPoint('top');\r\n //if(bubble) {\r\n //const top = bubble.getBoundingClientRect().top;\r\n const top = chat.bubbles.scrollable.scrollTop;\r\n\r\n const key = chat.peerId + (chat.threadId ? '_' + chat.threadId : '');\r\n\r\n const chatPositions = sessionStorage.getFromCache('chatPositions');\r\n if(!(chat.bubbles.scrollable.getDistanceToEnd() <= 16 && chat.bubbles.scrollable.loadedAll.bottom) && Object.keys(chat.bubbles.bubbles).length) {\r\n const position = {\r\n mids: getObjectKeysAndSort(chat.bubbles.bubbles, 'desc'),\r\n top\r\n };\r\n\r\n chatPositions[key] = position;\r\n\r\n this.log('saved chat position:', position);\r\n } else {\r\n delete chatPositions[key];\r\n\r\n this.log('deleted chat position');\r\n }\r\n\r\n sessionStorage.set({chatPositions}, true);\r\n //}\r\n }\r\n\r\n public getChatSavedPosition(chat: Chat): ChatSavedPosition {\r\n if(!(['chat', 'discussion'] as ChatType[]).includes(chat.type) || !chat.peerId) {\r\n return;\r\n }\r\n \r\n const key = chat.peerId + (chat.threadId ? '_' + chat.threadId : '');\r\n return sessionStorage.getFromCache('chatPositions')[key];\r\n }\r\n\r\n public applyBackgroundColor() {\r\n let hsla: string;\r\n if(rootScope.settings.nightTheme) {\r\n hsla = highlightningColor(new Uint8ClampedArray([15, 15, 15, 1]));\r\n document.documentElement.style.setProperty('--message-highlightning-color', hsla);\r\n } else {\r\n if(rootScope.settings.background.highlightningColor) {\r\n hsla = rootScope.settings.background.highlightningColor;\r\n document.documentElement.style.setProperty('--message-highlightning-color', hsla);\r\n } else {\r\n document.documentElement.style.removeProperty('--message-highlightning-color');\r\n }\r\n }\r\n\r\n let themeColor = '#ffffff';\r\n if(hsla) {\r\n themeColor = hslaStringToRgbString(hsla);\r\n }\r\n\r\n if(this.themeColorElem === undefined) {\r\n this.themeColorElem = document.head.querySelector('[name=\"theme-color\"]') as Element || null;\r\n }\r\n\r\n if(this.themeColorElem) {\r\n this.themeColorElem.setAttribute('content', themeColor);\r\n }\r\n }\r\n\r\n private setSettings = () => {\r\n document.documentElement.style.setProperty('--messages-text-size', rootScope.settings.messagesTextSize + 'px');\r\n\r\n this.applyBackgroundColor();\r\n \r\n document.documentElement.classList.toggle('night', rootScope.settings.nightTheme);\r\n \r\n document.body.classList.toggle('animation-level-0', !rootScope.settings.animationsEnabled);\r\n document.body.classList.toggle('animation-level-1', false);\r\n document.body.classList.toggle('animation-level-2', rootScope.settings.animationsEnabled);\r\n\r\n this.chatsSelectTabDebounced = debounce(() => {\r\n const topbar = this.chat.topbar;\r\n if(topbar.pinnedMessage) { // * буду молиться богам, чтобы это ничего не сломало, но это исправляет получение пиннеда после анимации\r\n topbar.pinnedMessage.setCorrectIndex(0);\r\n }\r\n\r\n apiManager.setQueueId(this.chat.bubbles.lazyLoadQueue.queueId);\r\n }, rootScope.settings.animationsEnabled ? 250 : 0, false, true);\r\n\r\n lottieLoader.setLoop(rootScope.settings.stickers.loop);\r\n animationIntersector.checkAnimations(false);\r\n \r\n for(const chat of this.chats) {\r\n chat.setAutoDownloadMedia();\r\n }\r\n };\r\n\r\n // * не могу использовать тут TransitionSlider, так как мне нужен отрисованный блок рядом \r\n // * (или под текущим чатом) чтобы правильно отрендерить чат (напр. scrollTop)\r\n private chatsSelectTab(tab: HTMLElement, animate?: boolean) {\r\n if(this.prevTab === tab) {\r\n return;\r\n }\r\n\r\n if(animate === false && this.prevTab) { // * will be used for Safari iOS history swipe\r\n disableTransition([tab, this.prevTab].filter(Boolean));\r\n }\r\n\r\n if(this.prevTab) {\r\n this.prevTab.classList.remove('active');\r\n this.chatsSelectTabDebounced();\r\n\r\n // ! нужно переделать на animation, так как при лаге анимация будет длиться не 250мс\r\n if(rootScope.settings.animationsEnabled && animate !== false) { \r\n dispatchHeavyAnimationEvent(pause(250 + 150), 250 + 150);\r\n }\r\n\r\n const prevIdx = whichChild(this.prevTab);\r\n const idx = whichChild(tab);\r\n if(idx > prevIdx) {\r\n appNavigationController.pushItem({\r\n type: 'chat', \r\n onPop: (canAnimate) => {\r\n this.setPeer(0, undefined, canAnimate);\r\n blurActiveElement();\r\n }\r\n });\r\n }\r\n }\r\n\r\n tab.classList.add('active');\r\n this.prevTab = tab;\r\n }\r\n\r\n private init() {\r\n document.addEventListener('paste', this.onDocumentPaste, true);\r\n \r\n const onKeyDown = (e: KeyboardEvent) => {\r\n if(rootScope.overlayIsActive) return;\r\n \r\n const target = e.target as HTMLElement;\r\n \r\n //if(target.tagName === 'INPUT') return;\r\n \r\n //this.log('onkeydown', e, document.activeElement);\r\n\r\n const chat = this.chat;\r\n\r\n if(e.key === 'Meta' || e.key === 'Control') {\r\n return;\r\n } else if(e.code === \"KeyC\" && (e.ctrlKey || e.metaKey) && target.tagName !== 'INPUT') {\r\n return;\r\n } else if(e.code === 'ArrowUp') {\r\n if(!chat.input.editMsgId && chat.input.isInputEmpty()) {\r\n const history = appMessagesManager.getHistoryStorage(chat.peerId, chat.threadId);\r\n if(history.history.length) {\r\n let goodMid: number;\r\n for(const mid of history.history.slice) {\r\n const message = chat.getMessage(mid);\r\n const good = this.myId === chat.peerId ? message.fromId === this.myId : message.pFlags.out;\r\n\r\n if(good) {\r\n if(appMessagesManager.canEditMessage(chat.getMessage(mid), 'text')) {\r\n goodMid = mid;\r\n break;\r\n }\r\n\r\n // * this check will allow editing only last message\r\n //break;\r\n }\r\n }\r\n \r\n if(goodMid) {\r\n chat.input.initMessageEditing(goodMid);\r\n cancelEvent(e); // * prevent from scrolling\r\n }\r\n }\r\n }\r\n }\r\n \r\n if(chat.input.messageInput && e.target !== chat.input.messageInput && target.tagName !== 'INPUT' && !target.hasAttribute('contenteditable') && !isTouchSupported) {\r\n chat.input.messageInput.focus();\r\n placeCaretAtEnd(chat.input.messageInput);\r\n }\r\n };\r\n \r\n document.body.addEventListener('keydown', onKeyDown);\r\n\r\n rootScope.addEventListener('history_multiappend', (e) => {\r\n const msgIdsByPeer = e;\r\n\r\n for(const peerId in msgIdsByPeer) {\r\n appSidebarRight.sharedMediaTab.renderNewMessages(+peerId, Array.from(msgIdsByPeer[peerId]));\r\n }\r\n });\r\n \r\n rootScope.addEventListener('history_delete', (e) => {\r\n const {peerId, msgs} = e;\r\n\r\n const mids = Object.keys(msgs).map(s => +s);\r\n appSidebarRight.sharedMediaTab.deleteDeletedMessages(peerId, mids);\r\n });\r\n\r\n // Calls when message successfully sent and we have an id\r\n rootScope.addEventListener('message_sent', (e) => {\r\n const {storage, tempId, mid} = e;\r\n const message = appMessagesManager.getMessageFromStorage(storage, mid);\r\n appSidebarRight.sharedMediaTab.renderNewMessages(message.peerId, [mid]);\r\n });\r\n\r\n if(!isTouchSupported) {\r\n this.attachDragAndDropListeners();\r\n }\r\n\r\n //if(!isTouchSupported) {\r\n this.markupTooltip = new MarkupTooltip(this);\r\n this.markupTooltip.handleSelection();\r\n //}\r\n }\r\n\r\n private attachDragAndDropListeners() {\r\n const drops: ChatDragAndDrop[] = [];\r\n let mounted = false;\r\n const toggle = async(e: DragEvent, mount: boolean) => {\r\n if(mount === mounted) return;\r\n\r\n const _types = e.dataTransfer.types;\r\n // @ts-ignore\r\n const isFiles = _types.contains ? _types.contains('Files') : _types.indexOf('Files') >= 0;\r\n\r\n if(!isFiles || !this.canDrag()) { // * skip dragging text case\r\n counter = 0;\r\n return;\r\n }\r\n\r\n if(mount && !drops.length) {\r\n const types: string[] = await getFilesFromEvent(e, true)\r\n const force = isFiles && !types.length; // * can't get file items not from 'drop' on Safari\r\n \r\n const foundMedia = types.filter(t => ['image', 'video'].includes(t.split('/')[0])).length;\r\n const foundDocuments = types.length - foundMedia;\r\n \r\n this.log('drag files', types);\r\n \r\n if(types.length || force) {\r\n drops.push(new ChatDragAndDrop(dropsContainer, {\r\n icon: 'dragfiles',\r\n header: 'Chat.DropTitle',\r\n subtitle: 'Chat.DropAsFilesDesc',\r\n onDrop: (e: DragEvent) => {\r\n toggle(e, false);\r\n appImManager.log('drop', e);\r\n appImManager.onDocumentPaste(e, 'document');\r\n }\r\n }));\r\n }\r\n \r\n if((foundMedia && !foundDocuments) || force) {\r\n drops.push(new ChatDragAndDrop(dropsContainer, {\r\n icon: 'dragmedia',\r\n header: 'Chat.DropTitle',\r\n subtitle: 'Chat.DropQuickDesc',\r\n onDrop: (e: DragEvent) => {\r\n toggle(e, false);\r\n appImManager.log('drop', e);\r\n appImManager.onDocumentPaste(e, 'media');\r\n }\r\n }));\r\n }\r\n \r\n this.chat.container.append(dropsContainer);\r\n }\r\n\r\n //if(!mount) return;\r\n\r\n SetTransition(dropsContainer, 'is-visible', mount, 200, () => {\r\n if(!mount) {\r\n drops.forEach(drop => {\r\n drop.destroy();\r\n });\r\n\r\n drops.length = 0;\r\n }\r\n });\r\n\r\n if(mount) {\r\n drops.forEach(drop => {\r\n drop.setPath();\r\n });\r\n } else {\r\n counter = 0;\r\n }\r\n\r\n document.body.classList.toggle('is-dragging', mount);\r\n mounted = mount;\r\n };\r\n\r\n /* document.body.addEventListener('dragover', (e) => {\r\n cancelEvent(e);\r\n }); */\r\n\r\n let counter = 0;\r\n document.body.addEventListener('dragenter', (e) => {\r\n counter++;\r\n });\r\n\r\n document.body.addEventListener('dragover', (e) => {\r\n //this.log('dragover', e/* , e.dataTransfer.types[0] */);\r\n toggle(e, true);\r\n cancelEvent(e);\r\n });\r\n\r\n document.body.addEventListener('dragleave', (e) => {\r\n //this.log('dragleave', e, counter);\r\n //if((e.pageX <= 0 || e.pageX >= appPhotosManager.windowW) || (e.pageY <= 0 || e.pageY >= appPhotosManager.windowH)) {\r\n counter--;\r\n if(counter === 0) { \r\n //if(!findUpClassName(e.target, 'drops-container')) {\r\n toggle(e, false);\r\n }\r\n });\r\n\r\n const dropsContainer = document.createElement('div');\r\n dropsContainer.classList.add('drops-container');\r\n }\r\n\r\n private canDrag() {\r\n const peerId = this.chat?.peerId;\r\n return !(!peerId || rootScope.overlayIsActive || (peerId < 0 && !appChatsManager.hasRights(peerId, 'send_media')));\r\n }\r\n\r\n private onDocumentPaste = (e: ClipboardEvent | DragEvent, attachType?: 'media' | 'document') => {\r\n if(!this.canDrag()) return;\r\n\r\n //console.log('document paste');\r\n //console.log('item', event.clipboardData.getData());\r\n\r\n if(e instanceof DragEvent) {\r\n const _types = e.dataTransfer.types;\r\n // @ts-ignore\r\n const isFiles = _types.contains ? _types.contains('Files') : _types.indexOf('Files') >= 0;\r\n if(isFiles) {\r\n cancelEvent(e);\r\n }\r\n }\r\n \r\n getFilesFromEvent(e).then((files: File[]) => {\r\n if(files.length) {\r\n if(attachType === 'media' && files.find(file => !['image', 'video'].includes(file.type.split('/')[0]))) {\r\n attachType = 'document';\r\n }\r\n \r\n const chatInput = this.chat.input;\r\n chatInput.willAttachType = attachType || (files[0].type.indexOf('image/') === 0 ? 'media' : \"document\");\r\n new PopupNewMedia(this.chat, files, chatInput.willAttachType);\r\n }\r\n });\r\n };\r\n\r\n public selectTab(id: number, animate?: boolean) {\r\n if(animate === false) { // * will be used for Safari iOS history swipe\r\n disableTransition([appSidebarLeft.sidebarEl, this.columnEl, appSidebarRight.sidebarEl]);\r\n }\r\n\r\n document.body.classList.toggle(LEFT_COLUMN_ACTIVE_CLASSNAME, id === 0);\r\n\r\n const prevTabId = this.tabId;\r\n\r\n this.log('selectTab', id, prevTabId);\r\n\r\n let animationPromise: Promise<any> = doubleRaf();\r\n if(prevTabId !== -1 && prevTabId !== id && rootScope.settings.animationsEnabled && animate !== false) {\r\n const transitionTime = (mediaSizes.isMobile ? 250 : 200) + 100; // * cause transition time could be > 250ms\r\n animationPromise = pause(transitionTime);\r\n dispatchHeavyAnimationEvent(animationPromise, transitionTime);\r\n\r\n this.columnEl.classList.add('disable-hover');\r\n animationPromise.finally(() => {\r\n this.columnEl.classList.remove('disable-hover');\r\n });\r\n }\r\n\r\n this.tabId = id;\r\n if(mediaSizes.isMobile && prevTabId === 2 && id < 2) {\r\n document.body.classList.remove(RIGHT_COLUMN_ACTIVE_CLASSNAME);\r\n }\r\n\r\n if(prevTabId !== -1 && id > prevTabId) {\r\n if(id < 2 || !appNavigationController.findItemByType('im')) {\r\n appNavigationController.pushItem({\r\n type: 'im', \r\n onPop: (canAnimate) => {\r\n //this.selectTab(prevTabId, !isSafari);\r\n this.setPeer(0, undefined, canAnimate);\r\n }\r\n });\r\n }\r\n }\r\n\r\n rootScope.broadcast('im_tab_change', id);\r\n\r\n //this._selectTab(id, mediaSizes.isMobile);\r\n //document.body.classList.toggle(RIGHT_COLUMN_ACTIVE_CLASSNAME, id === 2);\r\n\r\n return animationPromise;\r\n }\r\n \r\n public updateStatus() {\r\n if(!this.myId) return Promise.resolve();\r\n \r\n appUsersManager.setUserStatus(this.myId, this.offline);\r\n return apiManager.invokeApi('account.updateStatus', {offline: this.offline});\r\n }\r\n\r\n private createNewChat() {\r\n const chat = new Chat(this, appChatsManager, appDocsManager, appInlineBotsManager, appMessagesManager, appPeersManager, appPhotosManager, appProfileManager, appStickersManager, appUsersManager, appWebPagesManager, appPollsManager, apiManager, appDraftsManager, serverTimeManager, sessionStorage, appNotificationsManager);\r\n\r\n if(this.chats.length) {\r\n chat.backgroundEl.append(this.chat.backgroundEl.lastElementChild.cloneNode(true));\r\n }\r\n\r\n this.chats.push(chat);\r\n }\r\n\r\n private spliceChats(fromIndex: number, justReturn = true, animate?: boolean, spliced?: Chat[]) {\r\n if(fromIndex >= this.chats.length) return;\r\n\r\n if(this.chats.length > 1 && justReturn) {\r\n rootScope.broadcast('peer_changing', this.chat);\r\n }\r\n\r\n if(!spliced) {\r\n spliced = this.chats.splice(fromIndex, this.chats.length - fromIndex);\r\n }\r\n\r\n // * -1 because one item is being sliced when closing the chat by calling .removeByType\r\n for(let i = 0; i < spliced.length - 1; ++i) {\r\n appNavigationController.removeByType('chat', true);\r\n }\r\n\r\n // * fix middle chat z-index on animation\r\n if(spliced.length > 1) {\r\n spliced.slice(0, -1).forEach(chat => {\r\n chat.container.remove();\r\n });\r\n }\r\n\r\n this.chatsSelectTab(this.chat.container, animate);\r\n\r\n if(justReturn) {\r\n rootScope.broadcast('peer_changed', this.chat.peerId);\r\n\r\n const searchTab = appSidebarRight.getTab(AppPrivateSearchTab);\r\n if(searchTab) {\r\n searchTab.close();\r\n }\r\n \r\n const isSet = appSidebarRight.sharedMediaTab.setPeer(this.chat.peerId, this.chat.threadId);\r\n if(isSet) {\r\n appSidebarRight.sharedMediaTab.loadSidebarMedia(true);\r\n appSidebarRight.sharedMediaTab.fillProfileElements();\r\n }\r\n \r\n /* setTimeout(() => {\r\n appSidebarRight.sharedMediaTab.loadSidebarMedia(false);\r\n }); */\r\n }\r\n \r\n setTimeout(() => {\r\n //chat.setPeer(0);\r\n spliced.forEach(chat => {\r\n chat.destroy();\r\n });\r\n }, 250 + 100);\r\n }\r\n\r\n public setPeer(peerId: number, lastMsgId?: number, animate?: boolean): boolean {\r\n if(this.init) {\r\n this.init();\r\n this.init = null;\r\n }\r\n\r\n const chat = this.chat;\r\n const chatIndex = this.chats.indexOf(chat);\r\n\r\n if(!peerId) {\r\n if(chatIndex > 0) {\r\n this.spliceChats(chatIndex, undefined, animate);\r\n return;\r\n } else if(mediaSizes.activeScreen === ScreenSize.medium) { // * floating sidebar case\r\n this.selectTab(+!this.tabId, animate);\r\n return;\r\n }\r\n } else if(chatIndex > 0 && chat.peerId && chat.peerId !== peerId) {\r\n // const firstChat = this.chats[0];\r\n // if(firstChat.peerId !== chat.peerId) {\r\n /* // * slice idx > 0, set background and slice first, so new one will be the first\r\n const spliced = this.chats.splice(1, this.chats.length - 1);\r\n this.createNewChat();\r\n this.chats.splice(0, 1); */\r\n const spliced = this.chats.splice(1, this.chats.length - 1);\r\n if(this.chat.peerId === peerId) {\r\n this.spliceChats(0, true, true, spliced);\r\n return;\r\n } else {\r\n const ret = this.setPeer(peerId, lastMsgId);\r\n this.spliceChats(0, false, false, spliced);\r\n return ret;\r\n }\r\n // } else {\r\n // this.spliceChats(1, false, animate);\r\n // }\r\n\r\n //return ret;\r\n }\r\n\r\n // * don't reset peer if returning\r\n if(peerId === chat.peerId && mediaSizes.activeScreen <= ScreenSize.medium && document.body.classList.contains(LEFT_COLUMN_ACTIVE_CLASSNAME)) {\r\n this.selectTab(1, animate);\r\n return false;\r\n }\r\n\r\n if(peerId || mediaSizes.activeScreen !== ScreenSize.mobile) {\r\n const result = chat.setPeer(peerId, lastMsgId);\r\n\r\n // * wait for cached render\r\n const promise = result?.cached ? result.promise : Promise.resolve();\r\n if(peerId) {\r\n promise.then(() => {\r\n //window.requestAnimationFrame(() => {\r\n setTimeout(() => { // * setTimeout is better here\r\n setTimeout(() => {\r\n this.chatsSelectTab(this.chat.container);\r\n }, 0);\r\n this.selectTab(1, animate);\r\n }, 0);\r\n });\r\n }\r\n }\r\n\r\n if(!peerId) {\r\n this.selectTab(0, animate);\r\n return false;\r\n }\r\n }\r\n\r\n public setInnerPeer(peerId: number, lastMsgId?: number, type: ChatType = 'chat', threadId?: number) {\r\n // * prevent opening already opened peer\r\n const existingIndex = this.chats.findIndex(chat => chat.peerId === peerId && chat.type === type);\r\n if(existingIndex !== -1) {\r\n this.spliceChats(existingIndex + 1);\r\n return this.setPeer(peerId, lastMsgId);\r\n }\r\n\r\n const chat = this.chat;\r\n if(!chat.init) { // * use first not inited chat\r\n this.createNewChat();\r\n }\r\n\r\n if(type) {\r\n this.chat.setType(type);\r\n\r\n if(threadId) {\r\n this.chat.threadId = threadId;\r\n }\r\n }\r\n\r\n //this.chatsSelectTab(this.chat.container);\r\n\r\n return this.setPeer(peerId, lastMsgId);\r\n }\r\n\r\n public openScheduled(peerId: number) {\r\n this.setInnerPeer(peerId, undefined, 'scheduled');\r\n }\r\n\r\n private getTypingElement(action: SendMessageAction) {\r\n const el = document.createElement('span');\r\n el.classList.add('peer-typing');\r\n switch(action._) {\r\n //case 'sendMessageTypingAction': {\r\n default: {\r\n const c = 'peer-typing-text';\r\n el.classList.add(c);\r\n for(let i = 0; i < 3; ++i) {\r\n const dot = document.createElement('span');\r\n dot.className = c + '-dot';\r\n el.append(dot);\r\n }\r\n break;\r\n }\r\n }\r\n\r\n return el;\r\n }\r\n\r\n public async getPeerStatus(peerId: number) {\r\n let subtitle: HTMLElement;\r\n if(!peerId) return '';\r\n\r\n if(peerId < 0) { // not human\r\n const chatInfo = await appProfileManager.getChatFull(-peerId) as any;\r\n this.chat.log('chatInfo res:', chatInfo);\r\n\r\n const participants_count = chatInfo.participants_count || (chatInfo.participants && chatInfo.participants.participants && chatInfo.participants.participants.length) || 1;\r\n //if(participants_count) {\r\n subtitle = appChatsManager.getChatMembersString(-peerId);\r\n\r\n if(participants_count < 2) return subtitle;\r\n /* const onlines = await appChatsManager.getOnlines(chat.id);\r\n if(onlines > 1) {\r\n subtitle += ', ' + numberThousandSplitter(onlines) + ' online';\r\n } */\r\n \r\n return subtitle;\r\n //}\r\n } else { // user\r\n const user = appUsersManager.getUser(peerId);\r\n \r\n if(rootScope.myId === peerId) {\r\n return '';\r\n } else if(user) {\r\n subtitle = appUsersManager.getUserStatusString(user.id);\r\n\r\n if(!appUsersManager.isBot(peerId)) {\r\n const typings = appChatsManager.typingsInPeer[peerId];\r\n if(typings && typings.length) {\r\n const span = document.createElement('span');\r\n span.classList.add('online');\r\n span.append(this.getTypingElement(typings[0].action), i18n('Peer.Activity.User.TypingText'));\r\n return span;\r\n } else if(user.status?._ === 'userStatusOnline') {\r\n const span = document.createElement('span');\r\n span.classList.add('online');\r\n span.append(subtitle);\r\n return span;\r\n }\r\n }\r\n \r\n return subtitle;\r\n }\r\n }\r\n }\r\n}\r\n\r\nconst appImManager = new AppImManager();\r\nMOUNT_CLASS_TO && (MOUNT_CLASS_TO.appImManager = appImManager);\r\nexport default appImManager;\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 { deferredPromise } from \"../helpers/cancellablePromise\";\r\nimport mediaSizes from \"../helpers/mediaSizes\";\r\nimport { isTouchSupported } from \"../helpers/touchSupport\";\r\nimport { isMobileSafari, isSafari } from \"../helpers/userAgent\";\r\nimport appDocsManager, { MyDocument } from \"../lib/appManagers/appDocsManager\";\r\nimport appImManager from \"../lib/appManagers/appImManager\";\r\nimport appMessagesManager from \"../lib/appManagers/appMessagesManager\";\r\nimport appPeersManager from \"../lib/appManagers/appPeersManager\";\r\nimport appPhotosManager from \"../lib/appManagers/appPhotosManager\";\r\nimport { logger } from \"../lib/logger\";\r\nimport VideoPlayer from \"../lib/mediaPlayer\";\r\nimport { RichTextProcessor } from \"../lib/richtextprocessor\";\r\nimport rootScope from \"../lib/rootScope\";\r\nimport { cancelEvent, fillPropertyValue, generatePathData } from \"../helpers/dom\";\r\nimport animationIntersector from \"./animationIntersector\";\r\nimport appMediaPlaybackController from \"./appMediaPlaybackController\";\r\nimport AvatarElement from \"./avatar\";\r\nimport ButtonIcon from \"./buttonIcon\";\r\nimport { ButtonMenuItemOptions } from \"./buttonMenu\";\r\nimport ButtonMenuToggle from \"./buttonMenuToggle\";\r\nimport { LazyLoadQueueBase } from \"./lazyLoadQueue\";\r\nimport PopupForward from \"./popups/forward\";\r\nimport ProgressivePreloader from \"./preloader\";\r\nimport Scrollable from \"./scrollable\";\r\nimport appSidebarRight, { AppSidebarRight } from \"./sidebarRight\";\r\nimport SwipeHandler from \"./swipeHandler\";\r\nimport { months, ONE_DAY } from \"../helpers/date\";\r\nimport { SearchSuperContext } from \"./appSearchSuper.\";\r\nimport DEBUG from \"../config/debug\";\r\nimport appNavigationController from \"./appNavigationController\";\r\nimport { Message } from \"../layer\";\r\nimport { forEachReverse } from \"../helpers/array\";\r\nimport AppSharedMediaTab from \"./sidebarRight/tabs/sharedMedia\";\r\nimport findUpClassName from \"../helpers/dom/findUpClassName\";\r\nimport renderImageFromUrl from \"../helpers/dom/renderImageFromUrl\";\r\nimport findUpAsChild from \"../helpers/dom/findUpAsChild\";\r\nimport getVisibleRect from \"../helpers/dom/getVisibleRect\";\r\n\r\n// TODO: масштабирование картинок (не SVG) при ресайзе, и правильный возврат на исходную позицию\r\n// TODO: картинки \"обрезаются\" если возвращаются или появляются с места, где есть их перекрытие (топбар, поле ввода)\r\n// TODO: видео в мобильной вёрстке, если показываются элементы управления: если свайпнуть в сторону, то элементы вернутся на место, т.е. прыгнут - это не ок, надо бы замаскировать\r\n\r\nconst MEDIA_VIEWER_CLASSNAME = 'media-viewer';\r\n\r\nclass AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType extends string, TargetType extends object> {\r\n public wholeDiv: HTMLElement;\r\n protected overlaysDiv: HTMLElement;\r\n protected author: {[k in 'container' | 'avatarEl' | 'nameEl' | 'date']: HTMLElement} = {} as any;\r\n protected content: {[k in 'main' | 'container' | 'media' | 'mover' | ContentAdditionType]: HTMLElement} = {} as any;\r\n public buttons: {[k in 'download' | 'close' | 'prev' | 'next' | 'mobile-close' | ButtonsAdditionType]: HTMLElement} = {} as any;\r\n \r\n protected tempId = 0;\r\n protected preloader: ProgressivePreloader = null;\r\n protected preloaderStreamable: ProgressivePreloader = null;\r\n\r\n protected lastTarget: HTMLElement = null;\r\n protected prevTargets: TargetType[] = [];\r\n protected nextTargets: TargetType[] = [];\r\n //protected targetContainer: HTMLElement = null;\r\n //protected loadMore: () => void = null;\r\n\r\n public log: ReturnType<typeof logger>; \r\n\r\n protected isFirstOpen = true;\r\n protected loadMediaPromiseUp: Promise<void> = null;\r\n protected loadMediaPromiseDown: Promise<void> = null;\r\n protected loadedAllMediaUp = false;\r\n protected loadedAllMediaDown = false;\r\n\r\n protected reverse = false; // reverse means next = higher msgid\r\n protected needLoadMore = true;\r\n\r\n protected pageEl = document.getElementById('page-chats') as HTMLDivElement;\r\n\r\n protected setMoverPromise: Promise<void>;\r\n protected setMoverAnimationPromise: Promise<void>;\r\n\r\n protected lazyLoadQueue: LazyLoadQueueBase;\r\n\r\n protected highlightSwitchersTimeout: number;\r\n\r\n protected onDownloadClick: (e: MouseEvent) => void;\r\n protected onPrevClick: (target: TargetType) => void;\r\n protected onNextClick: (target: TargetType) => void;\r\n protected loadMoreMedia: (older: boolean) => Promise<void>;\r\n \r\n constructor(topButtons: Array<keyof AppMediaViewerBase<ContentAdditionType, ButtonsAdditionType, TargetType>['buttons']>) {\r\n this.log = logger('AMV');\r\n this.preloader = new ProgressivePreloader();\r\n this.preloaderStreamable = new ProgressivePreloader({\r\n cancelable: false,\r\n streamable: true\r\n });\r\n this.preloader.construct();\r\n this.preloaderStreamable.construct();\r\n this.lazyLoadQueue = new LazyLoadQueueBase();\r\n\r\n this.wholeDiv = document.createElement('div');\r\n this.wholeDiv.classList.add(MEDIA_VIEWER_CLASSNAME + '-whole');\r\n\r\n this.overlaysDiv = document.createElement('div');\r\n this.overlaysDiv.classList.add('overlays');\r\n\r\n const mainDiv = document.createElement('div');\r\n mainDiv.classList.add(MEDIA_VIEWER_CLASSNAME);\r\n\r\n // * author\r\n this.author.container = document.createElement('div');\r\n this.author.container.classList.add(MEDIA_VIEWER_CLASSNAME + '-author', 'no-select');\r\n\r\n this.author.avatarEl = new AvatarElement();\r\n this.author.avatarEl.classList.add(MEDIA_VIEWER_CLASSNAME + '-userpic', 'avatar-44');\r\n\r\n this.author.nameEl = document.createElement('div');\r\n this.author.nameEl.classList.add(MEDIA_VIEWER_CLASSNAME + '-name');\r\n\r\n this.author.date = document.createElement('div');\r\n this.author.date.classList.add(MEDIA_VIEWER_CLASSNAME + '-date');\r\n\r\n this.author.container.append(this.author.avatarEl, this.author.nameEl, this.author.date);\r\n\r\n // * buttons\r\n const buttonsDiv = document.createElement('div');\r\n buttonsDiv.classList.add(MEDIA_VIEWER_CLASSNAME + '-buttons');\r\n\r\n topButtons.concat(['download', 'close']).forEach(name => {\r\n const button = ButtonIcon(name);\r\n this.buttons[name] = button;\r\n buttonsDiv.append(button);\r\n });\r\n\r\n // * content\r\n this.content.main = document.createElement('div');\r\n this.content.main.classList.add(MEDIA_VIEWER_CLASSNAME + '-content');\r\n\r\n this.content.container = document.createElement('div');\r\n this.content.container.classList.add(MEDIA_VIEWER_CLASSNAME + '-container');\r\n\r\n this.content.media = document.createElement('div');\r\n this.content.media.classList.add(MEDIA_VIEWER_CLASSNAME + '-media');\r\n\r\n this.content.container.append(this.content.media);\r\n\r\n this.content.main.append(this.content.container);\r\n mainDiv.append(this.author.container, buttonsDiv, this.content.main);\r\n this.overlaysDiv.append(mainDiv);\r\n // * overlays end\r\n\r\n this.buttons[\"mobile-close\"] = ButtonIcon('close', {onlyMobile: true});\r\n\r\n this.buttons.prev = document.createElement('div');\r\n this.buttons.prev.className = `${MEDIA_VIEWER_CLASSNAME}-switcher ${MEDIA_VIEWER_CLASSNAME}-switcher-left`;\r\n this.buttons.prev.innerHTML = `<span class=\"tgico-down ${MEDIA_VIEWER_CLASSNAME}-prev-button\"></span>`;\r\n\r\n this.buttons.next = document.createElement('div');\r\n this.buttons.next.className = `${MEDIA_VIEWER_CLASSNAME}-switcher ${MEDIA_VIEWER_CLASSNAME}-switcher-right`;\r\n this.buttons.next.innerHTML = `<span class=\"tgico-down ${MEDIA_VIEWER_CLASSNAME}-next-button\"></span>`;\r\n\r\n this.wholeDiv.append(this.overlaysDiv, this.buttons['mobile-close'], this.buttons.prev, this.buttons.next);\r\n\r\n // * constructing html end\r\n \r\n this.setNewMover();\r\n }\r\n\r\n protected setListeners() {\r\n this.buttons.download.addEventListener('click', this.onDownloadClick);\r\n [this.buttons.close, this.buttons[\"mobile-close\"], this.preloaderStreamable.preloader].forEach(el => {\r\n el.addEventListener('click', this.close.bind(this));\r\n });\r\n\r\n this.buttons.prev.addEventListener('click', (e) => {\r\n cancelEvent(e);\r\n if(this.setMoverPromise) return;\r\n\r\n const target = this.prevTargets.pop();\r\n if(target) {\r\n this.onPrevClick(target);\r\n } else {\r\n this.buttons.prev.style.display = 'none';\r\n }\r\n });\r\n \r\n this.buttons.next.addEventListener('click', (e) => {\r\n cancelEvent(e);\r\n if(this.setMoverPromise) return;\r\n\r\n let target = this.nextTargets.shift();\r\n if(target) {\r\n this.onNextClick(target);\r\n } else {\r\n this.buttons.next.style.display = 'none';\r\n }\r\n });\r\n\r\n this.wholeDiv.addEventListener('click', this.onClick);\r\n\r\n if(isTouchSupported) {\r\n const swipeHandler = new SwipeHandler({\r\n element: this.wholeDiv, \r\n onSwipe: (xDiff, yDiff) => {\r\n if(VideoPlayer.isFullScreen()) {\r\n return;\r\n }\r\n //console.log(xDiff, yDiff);\r\n\r\n const percents = Math.abs(xDiff) / appPhotosManager.windowW;\r\n if(percents > .2 || xDiff > 125) {\r\n //console.log('will swipe', xDiff);\r\n\r\n if(xDiff < 0) {\r\n this.buttons.prev.click();\r\n } else {\r\n this.buttons.next.click();\r\n }\r\n\r\n return true;\r\n }\r\n\r\n const percentsY = Math.abs(yDiff) / appPhotosManager.windowH;\r\n if(percentsY > .2 || yDiff > 125) {\r\n this.buttons.close.click();\r\n return true;\r\n }\r\n\r\n return false;\r\n }, \r\n verifyTouchTarget: (evt) => {\r\n // * Fix for seek input\r\n if((evt.target as HTMLElement).tagName === 'INPUT' || findUpClassName(evt.target, 'media-viewer-caption')) {\r\n return false;\r\n }\r\n\r\n return true;\r\n }\r\n });\r\n }\r\n }\r\n\r\n protected setBtnMenuToggle(buttons: ButtonMenuItemOptions[]) {\r\n const btnMenuToggle = ButtonMenuToggle({onlyMobile: true}, 'bottom-left', buttons);\r\n this.wholeDiv.append(btnMenuToggle);\r\n }\r\n\r\n public close(e?: MouseEvent) {\r\n if(e) {\r\n cancelEvent(e);\r\n }\r\n\r\n if(this.setMoverAnimationPromise) return;\r\n\r\n appNavigationController.removeByType('media');\r\n\r\n this.lazyLoadQueue.clear();\r\n\r\n const promise = this.setMoverToTarget(this.lastTarget, true).then(({onAnimationEnd}) => onAnimationEnd);\r\n\r\n this.lastTarget = null;\r\n this.prevTargets = [];\r\n this.nextTargets = [];\r\n this.loadedAllMediaUp = this.loadedAllMediaDown = false;\r\n this.loadMediaPromiseUp = this.loadMediaPromiseDown = null;\r\n this.setMoverPromise = null;\r\n this.tempId = -1;\r\n\r\n /* if(appSidebarRight.historyTabIDs.slice(-1)[0] === AppSidebarRight.SLIDERITEMSIDS.forward) {\r\n promise.then(() => {\r\n appSidebarRight.forwardTab.closeBtn.click();\r\n });\r\n } */\r\n\r\n window.removeEventListener('keydown', this.onKeyDown);\r\n\r\n promise.finally(() => {\r\n this.wholeDiv.remove();\r\n rootScope.overlayIsActive = false;\r\n animationIntersector.checkAnimations(false);\r\n });\r\n\r\n return promise;\r\n }\r\n\r\n onClick = (e: MouseEvent) => {\r\n if(this.setMoverAnimationPromise) return;\r\n\r\n const target = e.target as HTMLElement;\r\n if(target.tagName === 'A') return;\r\n cancelEvent(e);\r\n\r\n if(isTouchSupported) {\r\n if(this.highlightSwitchersTimeout) {\r\n clearTimeout(this.highlightSwitchersTimeout);\r\n } else {\r\n this.wholeDiv.classList.add('highlight-switchers');\r\n }\r\n\r\n this.highlightSwitchersTimeout = window.setTimeout(() => {\r\n this.wholeDiv.classList.remove('highlight-switchers');\r\n this.highlightSwitchersTimeout = 0;\r\n }, 3e3);\r\n \r\n return;\r\n }\r\n\r\n let mover: HTMLElement = null;\r\n ['media-viewer-mover', 'media-viewer-buttons', 'media-viewer-author', 'media-viewer-caption'].find(s => {\r\n try {\r\n mover = findUpClassName(target, s);\r\n if(mover) return true;\r\n } catch(err) {return false;}\r\n });\r\n\r\n if(/* target === this.mediaViewerDiv */!mover || target.tagName === 'IMG' || target.tagName === 'image') {\r\n this.buttons.close.click();\r\n }\r\n };\r\n\r\n private onKeyDown = (e: KeyboardEvent) => {\r\n //this.log('onKeyDown', e);\r\n \r\n if(e.key === 'ArrowRight') {\r\n this.buttons.next.click();\r\n } else if(e.key === 'ArrowLeft') {\r\n this.buttons.prev.click();\r\n }\r\n };\r\n\r\n protected async setMoverToTarget(target: HTMLElement, closing = false, fromRight = 0) {\r\n const mover = this.content.mover;\r\n\r\n if(!closing) {\r\n mover.innerHTML = '';\r\n //mover.append(this.buttons.prev, this.buttons.next);\r\n }\r\n \r\n this.removeCenterFromMover(mover);\r\n\r\n const wasActive = fromRight !== 0;\r\n\r\n const delay = rootScope.settings.animationsEnabled ? (wasActive ? 350 : 200) : 0;\r\n //let delay = wasActive ? 350 : 10000;\r\n\r\n /* if(wasActive) {\r\n this.moveTheMover(mover);\r\n mover = this.setNewMover();\r\n } */\r\n\r\n /* if(DEBUG) {\r\n this.log('setMoverToTarget', target, closing, wasActive, fromRight);\r\n } */\r\n\r\n let realParent: HTMLElement;\r\n\r\n let rect: DOMRect;\r\n if(target) {\r\n if(target instanceof AvatarElement || target.classList.contains('grid-item')) {\r\n realParent = target;\r\n rect = target.getBoundingClientRect();\r\n } else if(target instanceof SVGImageElement || target.parentElement instanceof SVGForeignObjectElement) {\r\n realParent = findUpClassName(target, 'attachment');\r\n rect = realParent.getBoundingClientRect();\r\n } else if(target.classList.contains('profile-avatars-avatar')) {\r\n realParent = findUpClassName(target, 'profile-avatars-container');\r\n rect = realParent.getBoundingClientRect();\r\n\r\n // * if not active avatar\r\n if(closing && target.getBoundingClientRect().left !== rect.left) {\r\n target = realParent = rect = undefined;\r\n }\r\n }\r\n }\r\n\r\n if(!target) {\r\n target = this.content.media;\r\n }\r\n\r\n if(!rect) {\r\n realParent = target.parentElement as HTMLElement;\r\n rect = target.getBoundingClientRect();\r\n }\r\n\r\n let needOpacity = false;\r\n if(target !== this.content.media && !target.classList.contains('profile-avatars-avatar')) {\r\n const overflowElement = findUpClassName(realParent, 'scrollable');\r\n const visibleRect = getVisibleRect(realParent, overflowElement);\r\n\r\n if(closing && (!visibleRect || visibleRect.overflow.vertical === 2 || visibleRect.overflow.horizontal === 2)) {\r\n target = this.content.media;\r\n realParent = target.parentElement as HTMLElement;\r\n rect = target.getBoundingClientRect();\r\n } else if(visibleRect && (visibleRect.overflow.vertical === 1 || visibleRect.overflow.horizontal === 1)) {\r\n needOpacity = true;\r\n }\r\n }\r\n\r\n const containerRect = this.content.media.getBoundingClientRect();\r\n \r\n let transform = '';\r\n let left: number;\r\n let top: number;\r\n\r\n if(wasActive) {\r\n left = fromRight === 1 ? appPhotosManager.windowW : -containerRect.width;\r\n top = containerRect.top;\r\n } else {\r\n left = rect.left;\r\n top = rect.top;\r\n }\r\n\r\n transform += `translate3d(${left}px,${top}px,0) `;\r\n\r\n /* if(wasActive) {\r\n left = fromRight === 1 ? appPhotosManager.windowW / 2 : -(containerRect.width + appPhotosManager.windowW / 2);\r\n transform += `translate(${left}px,-50%) `;\r\n } else {\r\n left = rect.left - (appPhotosManager.windowW / 2);\r\n top = rect.top - (appPhotosManager.windowH / 2);\r\n transform += `translate(${left}px,${top}px) `;\r\n } */\r\n\r\n let aspecter: HTMLDivElement;\r\n if(target instanceof HTMLImageElement || target instanceof HTMLVideoElement || target.tagName === 'DIV') {\r\n if(mover.firstElementChild && mover.firstElementChild.classList.contains('media-viewer-aspecter')) {\r\n aspecter = mover.firstElementChild as HTMLDivElement;\r\n\r\n const player = aspecter.querySelector('.ckin__player');\r\n if(player) {\r\n const video = player.firstElementChild as HTMLVideoElement;\r\n aspecter.append(video);\r\n player.remove();\r\n }\r\n\r\n if(!aspecter.style.cssText) { // всё из-за видео, элементы управления скейлятся, так бы можно было этого не делать\r\n mover.classList.remove('active');\r\n this.setFullAspect(aspecter, containerRect, rect);\r\n void mover.offsetLeft; // reflow\r\n mover.classList.add('active');\r\n }\r\n } else {\r\n aspecter = document.createElement('div');\r\n aspecter.classList.add('media-viewer-aspecter'/* , 'disable-hover' */);\r\n mover.prepend(aspecter);\r\n }\r\n \r\n aspecter.style.cssText = `width: ${rect.width}px; height: ${rect.height}px; transform: scale3d(${containerRect.width / rect.width}, ${containerRect.height / rect.height}, 1);`;\r\n }\r\n\r\n mover.style.width = containerRect.width + 'px';\r\n mover.style.height = containerRect.height + 'px';\r\n\r\n const scaleX = rect.width / containerRect.width;\r\n const scaleY = rect.height / containerRect.height;\r\n if(!wasActive) {\r\n transform += `scale3d(${scaleX},${scaleY},1) `;\r\n }\r\n\r\n let borderRadius = window.getComputedStyle(realParent).getPropertyValue('border-radius');\r\n const brSplitted = fillPropertyValue(borderRadius) as string[];\r\n borderRadius = brSplitted.map(r => (parseInt(r) / scaleX) + 'px').join(' ');\r\n if(!wasActive) {\r\n mover.style.borderRadius = borderRadius;\r\n }\r\n //let borderRadius = '0px 0px 0px 0px';\r\n\r\n mover.style.transform = transform;\r\n\r\n needOpacity && (mover.style.opacity = '0'/* !closing ? '0' : '' */);\r\n\r\n /* if(wasActive) {\r\n this.log('setMoverToTarget', mover.style.transform);\r\n } */\r\n\r\n let path: SVGPathElement;\r\n const isOut = target.classList.contains('is-out');\r\n\r\n const deferred = this.setMoverAnimationPromise = deferredPromise<void>();\r\n const ret = {onAnimationEnd: deferred};\r\n\r\n this.setMoverAnimationPromise.then(() => {\r\n this.setMoverAnimationPromise = null;\r\n });\r\n\r\n if(!closing) {\r\n let mediaElement: HTMLImageElement | HTMLVideoElement;\r\n let src: string;\r\n\r\n if(target.tagName === 'DIV' || target.tagName === 'AVATAR-ELEMENT') { // useContainerAsTarget\r\n if(target.firstElementChild) {\r\n mediaElement = new Image();\r\n src = (target.firstElementChild as HTMLImageElement).src;\r\n mover.append(mediaElement);\r\n }\r\n /* mediaElement = new Image();\r\n src = target.style.backgroundImage.slice(5, -2); */\r\n \r\n } else if(target instanceof HTMLImageElement) {\r\n mediaElement = new Image();\r\n src = target.src;\r\n } else if(target instanceof HTMLVideoElement) {\r\n const video = mediaElement = document.createElement('video');\r\n video.src = target?.src;\r\n } else if(target instanceof SVGSVGElement) {\r\n const clipId = target.dataset.clipId;\r\n const newClipId = clipId + '-mv';\r\n\r\n const {width, height} = containerRect;\r\n\r\n const newSvg = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\");\r\n newSvg.setAttributeNS(null, 'width', '' + width);\r\n newSvg.setAttributeNS(null, 'height', '' + height);\r\n\r\n // нижние два свойства для масштабирования\r\n newSvg.setAttributeNS(null, 'viewBox', `0 0 ${width} ${height}`);\r\n newSvg.setAttributeNS(null, 'preserveAspectRatio', 'xMidYMid meet');\r\n\r\n newSvg.insertAdjacentHTML('beforeend', target.firstElementChild.outerHTML.replace(clipId, newClipId));\r\n newSvg.insertAdjacentHTML('beforeend', target.lastElementChild.outerHTML.replace(clipId, newClipId));\r\n\r\n // теперь надо выставить новую позицию для хвостика\r\n const defs = newSvg.firstElementChild;\r\n const use = defs.firstElementChild.firstElementChild as SVGUseElement;\r\n if(use instanceof SVGUseElement) {\r\n let transform = use.getAttributeNS(null, 'transform');\r\n transform = transform.replace(/translate\\((.+?), (.+?)\\) scale\\((.+?), (.+?)\\)/, (match, x, y, sX, sY) => {\r\n x = +x;\r\n if(x !== 2) {\r\n x = width - (2 / scaleX);\r\n } else {\r\n x = 2 / scaleX;\r\n }\r\n \r\n y = height;\r\n \r\n return `translate(${x}, ${y}) scale(${+sX / scaleX}, ${+sY / scaleY})`;\r\n });\r\n use.setAttributeNS(null, 'transform', transform);\r\n \r\n // и новый RECT\r\n path = defs.firstElementChild.lastElementChild as SVGPathElement;\r\n\r\n // код ниже нужен только чтобы скрыть моргание до момента как сработает таймаут\r\n let d: string;\r\n const br: [number, number, number, number] = borderRadius.split(' ').map(v => parseInt(v)) as any;\r\n if(isOut) d = generatePathData(0, 0, width - 9 / scaleX, height, ...br);\r\n else d = generatePathData(9 / scaleX, 0, width - 9 / scaleX, height, ...br);\r\n path.setAttributeNS(null, 'd', d);\r\n }\r\n\r\n const foreignObject = newSvg.lastElementChild;\r\n foreignObject.setAttributeNS(null, 'width', '' + containerRect.width);\r\n foreignObject.setAttributeNS(null, 'height', '' + containerRect.height);\r\n \r\n mover.prepend(newSvg);\r\n }\r\n\r\n if(aspecter) {\r\n aspecter.style.borderRadius = borderRadius;\r\n\r\n if(mediaElement) {\r\n aspecter.append(mediaElement);\r\n }\r\n }\r\n\r\n mediaElement = mover.querySelector('video, img');\r\n if(mediaElement instanceof HTMLImageElement) {\r\n mediaElement.classList.add('thumbnail');\r\n if(!aspecter) {\r\n mediaElement.style.width = containerRect.width + 'px';\r\n mediaElement.style.height = containerRect.height + 'px';\r\n }\r\n\r\n if(src) {\r\n await new Promise((resolve, reject) => {\r\n mediaElement.addEventListener('load', resolve);\r\n \r\n if(src) {\r\n mediaElement.src = src;\r\n }\r\n });\r\n }\r\n }/* else if(mediaElement instanceof HTMLVideoElement && mediaElement.firstElementChild && ((mediaElement.firstElementChild as HTMLSourceElement).src || src)) {\r\n await new Promise((resolve, reject) => {\r\n mediaElement.addEventListener('loadeddata', resolve);\r\n\r\n if(src) {\r\n (mediaElement.firstElementChild as HTMLSourceElement).src = src;\r\n }\r\n });\r\n } */\r\n \r\n mover.style.display = '';\r\n\r\n window.requestAnimationFrame(() => {\r\n mover.classList.add(wasActive ? 'moving' : 'active');\r\n });\r\n } else {\r\n /* if(mover.classList.contains('center')) {\r\n mover.classList.remove('center');\r\n void mover.offsetLeft; // reflow\r\n } */\r\n \r\n if(target instanceof SVGSVGElement) {\r\n path = mover.querySelector('path');\r\n\r\n if(path) {\r\n this.sizeTailPath(path, containerRect, scaleX, delay, false, isOut, borderRadius);\r\n }\r\n }\r\n\r\n if(target.classList.contains('media-viewer-media')) {\r\n mover.classList.add('hiding');\r\n }\r\n\r\n setTimeout(() => {\r\n this.wholeDiv.classList.remove('active');\r\n }, 0);\r\n\r\n setTimeout(() => {\r\n mover.style.borderRadius = borderRadius;\r\n\r\n if(mover.firstElementChild) {\r\n (mover.firstElementChild as HTMLElement).style.borderRadius = borderRadius;\r\n }\r\n }, delay / 2);\r\n\r\n setTimeout(() => {\r\n mover.innerHTML = '';\r\n mover.classList.remove('moving', 'active', 'hiding');\r\n mover.style.cssText = 'display: none;';\r\n\r\n deferred.resolve();\r\n }, delay);\r\n\r\n return ret;\r\n }\r\n\r\n mover.classList.toggle('opening', !closing);\r\n\r\n //await new Promise((resolve) => setTimeout(resolve, 0));\r\n //await new Promise((resolve) => window.requestAnimationFrame(resolve));\r\n // * одного RAF'а недостаточно, иногда анимация с одним не срабатывает (преимущественно на мобильных)\r\n await new Promise((resolve) => window.requestAnimationFrame(() => window.requestAnimationFrame(resolve)));\r\n\r\n // чтобы проверить установленную позицию - раскомментировать\r\n // throw '';\r\n\r\n //await new Promise((resolve) => setTimeout(resolve, 5e3));\r\n\r\n mover.style.transform = `translate3d(${containerRect.left}px,${containerRect.top}px,0) scale3d(1,1,1)`;\r\n //mover.style.transform = `translate(-50%,-50%) scale(1,1)`;\r\n needOpacity && (mover.style.opacity = ''/* closing ? '0' : '' */);\r\n\r\n if(aspecter) {\r\n this.setFullAspect(aspecter, containerRect, rect);\r\n }\r\n\r\n //throw '';\r\n\r\n setTimeout(() => {\r\n mover.style.borderRadius = '';\r\n\r\n if(mover.firstElementChild) {\r\n (mover.firstElementChild as HTMLElement).style.borderRadius = '';\r\n }\r\n }, 0/* delay / 2 */);\r\n\r\n mover.dataset.timeout = '' + setTimeout(() => {\r\n mover.classList.remove('moving');\r\n\r\n if(aspecter) { // всё из-за видео, элементы управления скейлятся, так бы можно было этого не делать\r\n if(mover.querySelector('video') || true) {\r\n mover.classList.remove('active');\r\n aspecter.style.cssText = '';\r\n void mover.offsetLeft; // reflow\r\n }\r\n \r\n //aspecter.classList.remove('disable-hover');\r\n }\r\n\r\n // эти строки нужны для установки центральной позиции, в случае ресайза это будет нужно\r\n mover.classList.add('center', 'no-transition');\r\n /* mover.style.left = mover.style.top = '50%';\r\n mover.style.transform = 'translate(-50%, -50%)';\r\n void mover.offsetLeft; // reflow */\r\n\r\n // это уже нужно для будущих анимаций\r\n mover.classList.add('active');\r\n delete mover.dataset.timeout;\r\n\r\n deferred.resolve();\r\n }, delay);\r\n\r\n if(path) {\r\n this.sizeTailPath(path, containerRect, scaleX, delay, true, isOut, borderRadius);\r\n }\r\n\r\n return ret;\r\n }\r\n\r\n protected setFullAspect(aspecter: HTMLDivElement, containerRect: DOMRect, rect: DOMRect) {\r\n /* let media = aspecter.firstElementChild;\r\n let proportion: number;\r\n if(media instanceof HTMLImageElement) {\r\n proportion = media.naturalWidth / media.naturalHeight;\r\n } else if(media instanceof HTMLVideoElement) {\r\n proportion = media.videoWidth / media.videoHeight;\r\n } */\r\n const proportion = containerRect.width / containerRect.height;\r\n\r\n let {width, height} = rect;\r\n /* if(proportion === 1) {\r\n aspecter.style.cssText = '';\r\n } else { */\r\n if(proportion > 0) {\r\n width = height * proportion;\r\n } else {\r\n height = width * proportion;\r\n }\r\n\r\n //this.log('will set style aspecter:', `width: ${width}px; height: ${height}px; transform: scale(${containerRect.width / width}, ${containerRect.height / height});`);\r\n\r\n aspecter.style.cssText = `width: ${width}px; height: ${height}px; transform: scale3d(${containerRect.width / width}, ${containerRect.height / height}, 1);`;\r\n //}\r\n }\r\n\r\n protected sizeTailPath(path: SVGPathElement, rect: DOMRect, scaleX: number, delay: number, upscale: boolean, isOut: boolean, borderRadius: string) {\r\n const start = Date.now();\r\n const {width, height} = rect;\r\n delay = delay / 2;\r\n\r\n const br = borderRadius.split(' ').map(v => parseInt(v));\r\n\r\n const step = () => {\r\n const diff = Date.now() - start;\r\n\r\n let progress = delay ? diff / delay : 1;\r\n if(progress > 1) progress = 1;\r\n if(upscale) progress = 1 - progress;\r\n\r\n const _br: [number, number, number, number] = br.map(v => v * progress) as any;\r\n\r\n let d: string;\r\n if(isOut) d = generatePathData(0, 0, width - (9 / scaleX * progress), height, ..._br);\r\n else d = generatePathData(9 / scaleX * progress, 0, width/* width - (9 / scaleX * progress) */, height, ..._br);\r\n path.setAttributeNS(null, 'd', d);\r\n\r\n if(diff < delay) window.requestAnimationFrame(step);\r\n };\r\n \r\n //window.requestAnimationFrame(step);\r\n step();\r\n }\r\n\r\n protected removeCenterFromMover(mover: HTMLElement) {\r\n if(mover.classList.contains('center')) {\r\n //const rect = mover.getBoundingClientRect();\r\n const rect = this.content.media.getBoundingClientRect();\r\n mover.style.transform = `translate3d(${rect.left}px,${rect.top}px,0)`;\r\n mover.classList.remove('center');\r\n void mover.offsetLeft; // reflow\r\n mover.classList.remove('no-transition');\r\n }\r\n }\r\n\r\n protected moveTheMover(mover: HTMLElement, toLeft = true) {\r\n const windowW = appPhotosManager.windowW;\r\n\r\n this.removeCenterFromMover(mover);\r\n\r\n //mover.classList.remove('active');\r\n mover.classList.add('moving');\r\n\r\n if(mover.dataset.timeout) { // и это тоже всё из-за скейла видео, так бы это не нужно было\r\n clearTimeout(+mover.dataset.timeout);\r\n }\r\n\r\n const rect = mover.getBoundingClientRect();\r\n\r\n const newTransform = mover.style.transform.replace(/translate3d\\((.+?),/, (match, p1) => {\r\n const x = toLeft ? -rect.width : windowW;\r\n //const x = toLeft ? -(rect.right + (rect.width / 2)) : windowW / 2;\r\n\r\n return match.replace(p1, x + 'px');\r\n });\r\n\r\n ////////this.log('set newTransform:', newTransform, mover.style.transform, toLeft);\r\n mover.style.transform = newTransform;\r\n\r\n setTimeout(() => {\r\n mover.remove();\r\n }, 350);\r\n }\r\n\r\n protected setNewMover() {\r\n const newMover = document.createElement('div');\r\n newMover.classList.add('media-viewer-mover');\r\n\r\n if(this.content.mover) {\r\n const oldMover = this.content.mover;\r\n oldMover.parentElement.append(newMover);\r\n } else {\r\n this.wholeDiv.append(newMover);\r\n }\r\n\r\n return this.content.mover = newMover;\r\n }\r\n\r\n /* public isElementVisible(container: HTMLElement, target: HTMLElement) {\r\n const rect = container.getBoundingClientRect();\r\n const targetRect = target.getBoundingClientRect();\r\n\r\n return targetRect.bottom > rect.top && targetRect.top < rect.bottom;\r\n } */\r\n\r\n protected updateMediaSource(target: HTMLElement, url: string, tagName: 'video' | 'img') {\r\n //if(target instanceof SVGSVGElement) {\r\n const el = target.tagName.toLowerCase() === tagName ? target : target.querySelector(tagName) as HTMLElement;\r\n if(el) {\r\n renderImageFromUrl(el, url);\r\n }\r\n /* } else {\r\n\r\n } */\r\n }\r\n\r\n protected setAuthorInfo(fromId: number, timestamp: number) {\r\n const date = new Date();\r\n const time = new Date(timestamp * 1000);\r\n const now = date.getTime() / 1000;\r\n\r\n const timeStr = time.getHours() + ':' + ('0' + time.getMinutes()).slice(-2);\r\n let dateStr: string;\r\n if((now - timestamp) < ONE_DAY && date.getDate() === time.getDate()) { // if the same day\r\n dateStr = 'Today';\r\n } else if((now - timestamp) < (ONE_DAY * 2) && (date.getDate() - 1) === time.getDate()) { // yesterday\r\n dateStr = 'Yesterday';\r\n } else if(date.getFullYear() !== time.getFullYear()) { // different year\r\n dateStr = months[time.getMonth()].slice(0, 3) + ' ' + time.getDate() + ', ' + time.getFullYear();\r\n } else {\r\n dateStr = months[time.getMonth()].slice(0, 3) + ' ' + time.getDate();\r\n }\r\n\r\n this.author.date.innerText = dateStr + ' at ' + timeStr;\r\n\r\n const name = appPeersManager.getPeerTitle(fromId);\r\n this.author.nameEl.innerHTML = name;\r\n\r\n let oldAvatar = this.author.avatarEl;\r\n this.author.avatarEl = (this.author.avatarEl.cloneNode() as AvatarElement);\r\n this.author.avatarEl.setAttribute('peer', '' + fromId);\r\n oldAvatar.parentElement.replaceChild(this.author.avatarEl, oldAvatar);\r\n }\r\n \r\n protected async _openMedia(media: any, timestamp: number, fromId: number, fromRight: number, target?: HTMLElement, reverse = false, \r\n prevTargets: TargetType[] = [], nextTargets: TargetType[] = [], needLoadMore = true) {\r\n if(this.setMoverPromise) return this.setMoverPromise;\r\n\r\n /* if(DEBUG) {\r\n this.log('openMedia:', media, fromId, prevTargets, nextTargets);\r\n } */\r\n\r\n this.setAuthorInfo(fromId, timestamp);\r\n \r\n const isVideo = (media as MyDocument).type === 'video' || (media as MyDocument).type === 'gif';\r\n\r\n if(this.isFirstOpen) {\r\n //this.targetContainer = targetContainer;\r\n this.prevTargets = prevTargets;\r\n this.nextTargets = nextTargets;\r\n this.reverse = reverse;\r\n this.needLoadMore = needLoadMore;\r\n this.isFirstOpen = false;\r\n //this.loadMore = loadMore;\r\n\r\n /* if(appSidebarRight.historyTabIDs.slice(-1)[0] === AppSidebarRight.SLIDERITEMSIDS.forward) {\r\n appSidebarRight.forwardTab.closeBtn.click();\r\n await new Promise((resolve) => setTimeout(resolve, 200));\r\n } */\r\n }\r\n\r\n /* if(this.nextTargets.length < 10 && this.loadMore) {\r\n this.loadMore();\r\n } */\r\n\r\n //if(prevTarget && (!prevTarget.parentElement || !this.isElementVisible(this.targetContainer, prevTarget))) prevTarget = null;\r\n //if(nextTarget && (!nextTarget.parentElement || !this.isElementVisible(this.targetContainer, nextTarget))) nextTarget = null;\r\n\r\n this.buttons.prev.classList.toggle('hide', !this.prevTargets.length);\r\n this.buttons.next.classList.toggle('hide', !this.nextTargets.length);\r\n \r\n const container = this.content.media;\r\n const useContainerAsTarget = !target || target === container;\r\n if(useContainerAsTarget) target = container;\r\n\r\n this.lastTarget = target;\r\n const tempId = ++this.tempId;\r\n\r\n if(this.needLoadMore) {\r\n if(this.nextTargets.length < 20) {\r\n this.loadMoreMedia(!this.reverse);\r\n }\r\n \r\n if(this.prevTargets.length < 20) {\r\n this.loadMoreMedia(this.reverse);\r\n }\r\n }\r\n \r\n if(container.firstElementChild) {\r\n container.innerHTML = '';\r\n }\r\n \r\n // ok set\r\n\r\n const wasActive = fromRight !== 0;\r\n if(wasActive) {\r\n this.moveTheMover(this.content.mover, fromRight === 1);\r\n this.setNewMover();\r\n } else {\r\n window.addEventListener('keydown', this.onKeyDown);\r\n const mainColumns = this.pageEl.querySelector('#main-columns');\r\n this.pageEl.insertBefore(this.wholeDiv, mainColumns);\r\n void this.wholeDiv.offsetLeft; // reflow\r\n this.wholeDiv.classList.add('active');\r\n rootScope.overlayIsActive = true;\r\n animationIntersector.checkAnimations(true);\r\n\r\n if(!isMobileSafari) {\r\n appNavigationController.pushItem({\r\n type: 'media',\r\n onPop: (canAnimate) => {\r\n if(this.setMoverAnimationPromise) {\r\n return false;\r\n }\r\n \r\n this.close();\r\n }\r\n });\r\n }\r\n }\r\n\r\n ////////this.log('wasActive:', wasActive);\r\n\r\n const mover = this.content.mover;\r\n\r\n //const maxWidth = appPhotosManager.windowW - 16;\r\n const maxWidth = mediaSizes.isMobile ? this.pageEl.scrollWidth : this.pageEl.scrollWidth - 16;\r\n const maxHeight = appPhotosManager.windowH - 100;\r\n let thumbPromise: Promise<any> = Promise.resolve();\r\n if(useContainerAsTarget) {\r\n const cacheContext = appPhotosManager.getCacheContext(media);\r\n let img: HTMLImageElement;\r\n if(cacheContext.downloaded) {\r\n img = new Image();\r\n img.src = cacheContext.url;\r\n } else {\r\n const gotThumb = appPhotosManager.getStrippedThumbIfNeeded(media, true);\r\n if(gotThumb) {\r\n thumbPromise = gotThumb.loadPromise;\r\n img = gotThumb.image;\r\n }\r\n }\r\n\r\n if(img) {\r\n img.classList.add('thumbnail');\r\n container.append(img);\r\n }\r\n }\r\n const size = appPhotosManager.setAttachmentSize(media, container, maxWidth, maxHeight, mediaSizes.isMobile ? false : true);\r\n\r\n // need after setAttachmentSize\r\n /* if(useContainerAsTarget) {\r\n target = target.querySelector('img, video') || target;\r\n } */\r\n\r\n const preloader = media.supportsStreaming ? this.preloaderStreamable : this.preloader;\r\n\r\n let setMoverPromise: Promise<void>;\r\n if(isVideo) {\r\n ////////this.log('will wrap video', media, size);\r\n\r\n // потому что для safari нужно создать элемент из event'а\r\n const video = document.createElement('video');\r\n\r\n const set = () => this.setMoverToTarget(target, false, fromRight).then(({onAnimationEnd}) => {\r\n //return; // set and don't move\r\n //if(wasActive) return;\r\n //return;\r\n \r\n const div = mover.firstElementChild && mover.firstElementChild.classList.contains('media-viewer-aspecter') ? mover.firstElementChild : mover;\r\n //const video = mover.querySelector('video') || document.createElement('video');\r\n \r\n const moverVideo = mover.querySelector('video');\r\n if(moverVideo) {\r\n moverVideo.remove();\r\n }\r\n \r\n //video.src = '';\r\n \r\n video.setAttribute('playsinline', 'true');\r\n \r\n // * fix for playing video if viewer is closed (https://contest.com/javascript-web-bonus/entry1425#issue11629)\r\n video.addEventListener('timeupdate', () => {\r\n if(this.tempId !== tempId) {\r\n video.pause();\r\n }\r\n });\r\n \r\n if(isSafari) {\r\n // test stream\r\n // video.controls = true;\r\n video.autoplay = true;\r\n }\r\n \r\n if(media.type === 'gif') {\r\n video.muted = true;\r\n video.autoplay = true;\r\n video.loop = true;\r\n }\r\n \r\n if(!video.parentElement) {\r\n div.append(video);\r\n }\r\n \r\n const canPlayThrough = new Promise((resolve) => {\r\n video.addEventListener('canplay', resolve, {once: true});\r\n });\r\n \r\n const createPlayer = () => {\r\n if(media.type !== 'gif') {\r\n video.dataset.ckin = 'default';\r\n video.dataset.overlay = '1';\r\n \r\n // fix for simultaneous play\r\n appMediaPlaybackController.pause();\r\n appMediaPlaybackController.willBePlayedMedia = null;\r\n \r\n Promise.all([canPlayThrough, onAnimationEnd]).then(() => {\r\n if(this.tempId !== tempId) {\r\n return;\r\n }\r\n \r\n const player = new VideoPlayer(video, true, media.supportsStreaming);\r\n /* div.append(video);\r\n mover.append(player.wrapper); */\r\n });\r\n }\r\n };\r\n \r\n if(media.supportsStreaming) {\r\n onAnimationEnd.then(() => {\r\n if(video.readyState < video.HAVE_FUTURE_DATA) {\r\n preloader.attach(mover, true);\r\n }\r\n \r\n /* canPlayThrough.then(() => {\r\n preloader.detach();\r\n }); */\r\n });\r\n \r\n const attachCanPlay = () => {\r\n video.addEventListener('canplay', () => {\r\n //this.log('video waited and progress loaded');\r\n preloader.detach();\r\n video.parentElement.classList.remove('is-buffering');\r\n }, {once: true});\r\n };\r\n \r\n video.addEventListener('waiting', (e) => {\r\n const loading = video.networkState === video.NETWORK_LOADING;\r\n const isntEnoughData = video.readyState < video.HAVE_FUTURE_DATA;\r\n \r\n //this.log('video waiting for progress', loading, isntEnoughData);\r\n if(loading && isntEnoughData) {\r\n attachCanPlay();\r\n \r\n preloader.attach(mover, true);\r\n \r\n // поставлю класс для плеера, чтобы убрать большую иконку пока прелоадер на месте\r\n video.parentElement.classList.add('is-buffering');\r\n }\r\n });\r\n \r\n attachCanPlay();\r\n }\r\n \r\n //if(!video.src || media.url !== video.src) {\r\n const load = () => {\r\n const promise = media.supportsStreaming ? Promise.resolve() : appDocsManager.downloadDoc(media);\r\n \r\n if(!media.supportsStreaming) {\r\n onAnimationEnd.then(() => {\r\n if(!media.url) {\r\n preloader.attach(mover, true, promise);\r\n }\r\n });\r\n }\r\n \r\n (promise as Promise<any>).then(async() => {\r\n if(this.tempId !== tempId) {\r\n this.log.warn('media viewer changed video');\r\n return;\r\n }\r\n \r\n const url = media.url;\r\n if(target instanceof SVGSVGElement/* && (video.parentElement || !isSafari) */) { // if video exists\r\n //if(!video.parentElement) {\r\n div.firstElementChild.lastElementChild.append(video);\r\n //}\r\n \r\n this.updateMediaSource(mover, url, 'video');\r\n } else {\r\n renderImageFromUrl(video, url);\r\n }\r\n \r\n createPlayer();\r\n });\r\n \r\n return promise;\r\n };\r\n \r\n this.lazyLoadQueue.unshift({load});\r\n //} else createPlayer();\r\n });\r\n\r\n setMoverPromise = thumbPromise.then(set);\r\n } else {\r\n const set = () => this.setMoverToTarget(target, false, fromRight).then(({onAnimationEnd}) => {\r\n //return; // set and don't move\r\n //if(wasActive) return;\r\n //return;\r\n \r\n const load = () => {\r\n const cancellablePromise = appPhotosManager.preloadPhoto(media.id, size);\r\n \r\n onAnimationEnd.then(() => {\r\n if(!media.url) {\r\n this.preloader.attachPromise(cancellablePromise);\r\n //this.preloader.attach(mover, true, cancellablePromise);\r\n }\r\n });\r\n \r\n Promise.all([onAnimationEnd, cancellablePromise]).then(() => {\r\n if(this.tempId !== tempId) {\r\n this.log.warn('media viewer changed photo');\r\n return;\r\n }\r\n \r\n ///////this.log('indochina', blob);\r\n \r\n const url = media.url;\r\n if(target instanceof SVGSVGElement) {\r\n this.updateMediaSource(target, url, 'img');\r\n this.updateMediaSource(mover, url, 'img');\r\n \r\n if(mediaSizes.isMobile) {\r\n const imgs = mover.querySelectorAll('img');\r\n if(imgs && imgs.length) {\r\n imgs.forEach(img => {\r\n img.classList.remove('thumbnail'); // может здесь это вообще не нужно\r\n });\r\n }\r\n }\r\n } else {\r\n const div = mover.firstElementChild && mover.firstElementChild.classList.contains('media-viewer-aspecter') ? mover.firstElementChild : mover;\r\n const haveImage = div.firstElementChild?.tagName === 'IMG' ? div.firstElementChild as HTMLImageElement : null;\r\n if(!haveImage || haveImage.src !== url) {\r\n let image = new Image();\r\n image.classList.add('thumbnail');\r\n \r\n //this.log('will renderImageFromUrl:', image, div, target);\r\n \r\n renderImageFromUrl(image, url, () => {\r\n this.updateMediaSource(target, url, 'img');\r\n \r\n if(haveImage) {\r\n window.requestAnimationFrame(() => {\r\n haveImage.remove();\r\n });\r\n }\r\n \r\n div.append(image);\r\n });\r\n }\r\n }\r\n \r\n //this.preloader.detach();\r\n }).catch(err => {\r\n this.log.error(err);\r\n this.preloader.attach(mover);\r\n this.preloader.setManual();\r\n });\r\n \r\n return cancellablePromise;\r\n };\r\n \r\n this.lazyLoadQueue.unshift({load});\r\n });\r\n\r\n setMoverPromise = thumbPromise.then(set);\r\n }\r\n\r\n return this.setMoverPromise = setMoverPromise.catch(() => {\r\n this.setMoverAnimationPromise = null;\r\n }).finally(() => {\r\n this.setMoverPromise = null;\r\n });\r\n }\r\n}\r\n\r\ntype AppMediaViewerTargetType = {\r\n element: HTMLElement,\r\n mid: number,\r\n peerId: number\r\n};\r\nexport default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delete' | 'forward', AppMediaViewerTargetType> {\r\n public currentMessageId = 0;\r\n public currentPeerId = 0;\r\n public searchContext: SearchSuperContext;\r\n\r\n constructor() {\r\n super(['delete', 'forward']);\r\n\r\n /* const stub = document.createElement('div');\r\n stub.classList.add(MEDIA_VIEWER_CLASSNAME + '-stub');\r\n this.content.main.prepend(stub); */\r\n\r\n this.content.caption = document.createElement('div');\r\n this.content.caption.classList.add(MEDIA_VIEWER_CLASSNAME + '-caption'/* , 'media-viewer-stub' */);\r\n\r\n new Scrollable(this.content.caption);\r\n\r\n //this.content.main.append(this.content.caption);\r\n this.wholeDiv.append(this.content.caption);\r\n\r\n this.setBtnMenuToggle([{\r\n icon: 'forward',\r\n text: 'Forward',\r\n onClick: this.onForwardClick\r\n }, {\r\n icon: 'download',\r\n text: 'MediaViewer.Context.Download',\r\n onClick: this.onDownloadClick\r\n }, {\r\n icon: 'delete danger btn-disabled',\r\n text: 'Delete',\r\n onClick: () => {}\r\n }]);\r\n\r\n // * constructing html end\r\n \r\n this.setListeners();\r\n }\r\n\r\n protected setListeners() {\r\n super.setListeners();\r\n this.buttons.forward.addEventListener('click', this.onForwardClick);\r\n this.author.container.addEventListener('click', this.onAuthorClick);\r\n }\r\n\r\n /* public close(e?: MouseEvent) {\r\n const good = !this.setMoverAnimationPromise;\r\n const promise = super.close(e);\r\n\r\n if(good) { // clear\r\n this.currentMessageId = 0;\r\n this.peerId = 0;\r\n }\r\n\r\n return promise;\r\n } */\r\n\r\n onPrevClick = (target: AppMediaViewerTargetType) => {\r\n this.nextTargets.unshift({element: this.lastTarget, mid: this.currentMessageId, peerId: this.currentPeerId});\r\n this.openMedia(appMessagesManager.getMessageByPeer(target.peerId, target.mid), target.element, -1);\r\n };\r\n\r\n onNextClick = (target: AppMediaViewerTargetType) => {\r\n this.prevTargets.push({element: this.lastTarget, mid: this.currentMessageId, peerId: this.currentPeerId});\r\n this.openMedia(appMessagesManager.getMessageByPeer(target.peerId, target.mid), target.element, 1);\r\n };\r\n\r\n onForwardClick = () => {\r\n if(this.currentMessageId) {\r\n //appSidebarRight.forwardTab.open([this.currentMessageId]);\r\n new PopupForward(this.currentPeerId, [this.currentMessageId], () => {\r\n return this.close();\r\n });\r\n }\r\n };\r\n\r\n onAuthorClick = (e: MouseEvent) => {\r\n if(this.currentMessageId && this.currentMessageId !== Number.MAX_SAFE_INTEGER) {\r\n const mid = this.currentMessageId;\r\n const peerId = this.currentPeerId;\r\n const threadId = this.searchContext.threadId;\r\n this.close(e)\r\n //.then(() => mediaSizes.isMobile ? appSidebarRight.sharedMediaTab.closeBtn.click() : Promise.resolve())\r\n .then(() => {\r\n if(mediaSizes.isMobile) {\r\n const tab = appSidebarRight.getTab(AppSharedMediaTab);\r\n if(tab) {\r\n tab.close();\r\n }\r\n }\r\n\r\n const message = appMessagesManager.getMessageByPeer(peerId, mid);\r\n appImManager.setInnerPeer(message.peerId, mid, threadId ? 'discussion' : undefined, threadId);\r\n });\r\n }\r\n };\r\n\r\n onDownloadClick = () => {\r\n const message = appMessagesManager.getMessageByPeer(this.currentPeerId, this.currentMessageId);\r\n if(message.media.photo) {\r\n appPhotosManager.savePhotoFile(message.media.photo, appImManager.chat.bubbles.lazyLoadQueue.queueId);\r\n } else {\r\n let document: MyDocument = null;\r\n\r\n if(message.media.webpage) document = message.media.webpage.document;\r\n else document = message.media.document;\r\n\r\n if(document) {\r\n //console.log('will save document:', document);\r\n appDocsManager.saveDocFile(document, appImManager.chat.bubbles.lazyLoadQueue.queueId);\r\n }\r\n }\r\n };\r\n\r\n // нет смысла делать проверку для reverse и loadMediaPromise\r\n protected loadMoreMedia = (older = true) => {\r\n //if(!older && this.reverse) return;\r\n\r\n if(older && this.loadedAllMediaDown) return Promise.resolve();\r\n else if(!older && this.loadedAllMediaUp) return Promise.resolve();\r\n\r\n if(older && this.loadMediaPromiseDown) return this.loadMediaPromiseDown;\r\n else if(!older && this.loadMediaPromiseUp) return this.loadMediaPromiseUp;\r\n\r\n const loadCount = 50;\r\n const backLimit = older ? 0 : loadCount;\r\n let maxId = this.currentMessageId;\r\n \r\n let anchor: AppMediaViewerTargetType;\r\n if(older) {\r\n anchor = this.reverse ? this.prevTargets[0] : this.nextTargets[this.nextTargets.length - 1];\r\n } else {\r\n anchor = this.reverse ? this.nextTargets[this.nextTargets.length - 1] : this.prevTargets[0];\r\n }\r\n\r\n if(anchor) maxId = anchor.mid;\r\n if(!older) maxId = appMessagesManager.incrementMessageId(maxId, 1);\r\n\r\n const promise = appMessagesManager.getSearch({\r\n peerId: this.searchContext.peerId,\r\n query: this.searchContext.query,\r\n inputFilter: {\r\n _: this.searchContext.inputFilter\r\n },\r\n maxId,\r\n limit: backLimit ? 0 : loadCount,\r\n backLimit,\r\n threadId: this.searchContext.threadId,\r\n folderId: this.searchContext.folderId,\r\n nextRate: this.searchContext.nextRate,\r\n minDate: this.searchContext.minDate,\r\n maxDate: this.searchContext.maxDate\r\n }).then(value => {\r\n if(DEBUG) {\r\n this.log('loaded more media by maxId:', maxId, value, older, this.reverse);\r\n }\r\n\r\n if(value.next_rate) {\r\n this.searchContext.nextRate = value.next_rate;\r\n }\r\n\r\n if(value.history.length < loadCount) {\r\n /* if(this.reverse) {\r\n if(older) this.loadedAllMediaUp = true;\r\n else this.loadedAllMediaDown = true;\r\n } else { */\r\n if(older) this.loadedAllMediaDown = true;\r\n else this.loadedAllMediaUp = true;\r\n //}\r\n }\r\n\r\n const method: any = older ? value.history.forEach.bind(value.history) : forEachReverse.bind(null, value.history);\r\n method((message: Message.message) => {\r\n const {mid, peerId} = message;\r\n const media = this.getMediaFromMessage(message);\r\n\r\n if(!media) return;\r\n //if(media._ === 'document' && media.type !== 'video') return;\r\n\r\n const t = {element: null as HTMLElement, mid, peerId};\r\n if(older) {\r\n if(this.reverse) this.prevTargets.unshift(t);\r\n else this.nextTargets.push(t);\r\n } else {\r\n if(this.reverse) this.nextTargets.push(t);\r\n else this.prevTargets.unshift(t);\r\n }\r\n });\r\n\r\n this.buttons.prev.classList.toggle('hide', !this.prevTargets.length);\r\n this.buttons.next.classList.toggle('hide', !this.nextTargets.length);\r\n }, () => {}).then(() => {\r\n if(older) this.loadMediaPromiseDown = null;\r\n else this.loadMediaPromiseUp = null;\r\n });\r\n\r\n if(older) this.loadMediaPromiseDown = promise;\r\n else this.loadMediaPromiseUp = promise;\r\n\r\n return promise;\r\n };\r\n\r\n private getMediaFromMessage(message: any) {\r\n return message.action ? message.action.photo : message.media.photo \r\n || message.media.document \r\n || (message.media.webpage && (message.media.webpage.document || message.media.webpage.photo));\r\n }\r\n\r\n private setCaption(message: any) {\r\n const caption = message.message;\r\n this.content.caption.classList.toggle('hide', !caption);\r\n if(caption) {\r\n this.content.caption.firstElementChild.innerHTML = RichTextProcessor.wrapRichText(caption, {\r\n entities: message.totalEntities\r\n });\r\n } else {\r\n this.content.caption.firstElementChild.innerHTML = '';\r\n }\r\n }\r\n\r\n public setSearchContext(context: SearchSuperContext) {\r\n this.searchContext = context;\r\n\r\n if(this.searchContext.folderId !== undefined) {\r\n this.loadedAllMediaUp = true;\r\n\r\n if(this.searchContext.nextRate === undefined) {\r\n this.loadedAllMediaDown = true;\r\n }\r\n }\r\n\r\n return this;\r\n }\r\n\r\n public async openMedia(message: any, target?: HTMLElement, fromRight = 0, reverse = false, \r\n prevTargets: AppMediaViewer['prevTargets'] = [], nextTargets: AppMediaViewer['prevTargets'] = [], needLoadMore = true) {\r\n if(this.setMoverPromise) return this.setMoverPromise;\r\n\r\n const mid = message.mid;\r\n const fromId = message.fromId;\r\n const media = this.getMediaFromMessage(message);\r\n\r\n this.currentMessageId = mid;\r\n this.currentPeerId = message.peerId;\r\n const promise = super._openMedia(media, message.date, fromId, fromRight, target, reverse, prevTargets, nextTargets, needLoadMore);\r\n this.setCaption(message);\r\n\r\n return promise;\r\n }\r\n}\r\n\r\ntype AppMediaViewerAvatarTargetType = {element: HTMLElement, photoId: string};\r\nexport class AppMediaViewerAvatar extends AppMediaViewerBase<'', 'delete', AppMediaViewerAvatarTargetType> {\r\n public currentPhotoId: string;\r\n public peerId: number;\r\n\r\n constructor(peerId: number) {\r\n super(['delete']);\r\n\r\n this.peerId = peerId;\r\n\r\n this.setBtnMenuToggle([{\r\n icon: 'download',\r\n text: 'MediaViewer.Context.Download',\r\n onClick: this.onDownloadClick\r\n }, {\r\n icon: 'delete danger btn-disabled',\r\n text: 'Delete',\r\n onClick: () => {}\r\n }]);\r\n\r\n // * constructing html end\r\n \r\n this.setListeners();\r\n }\r\n\r\n onPrevClick = (target: AppMediaViewerAvatarTargetType) => {\r\n this.nextTargets.unshift({element: this.lastTarget, photoId: this.currentPhotoId});\r\n this.openMedia(target.photoId, target.element, -1);\r\n };\r\n\r\n onNextClick = (target: AppMediaViewerAvatarTargetType) => {\r\n this.prevTargets.push({element: this.lastTarget, photoId: this.currentPhotoId});\r\n this.openMedia(target.photoId, target.element, 1);\r\n };\r\n\r\n onDownloadClick = () => {\r\n appPhotosManager.savePhotoFile(appPhotosManager.getPhoto(this.currentPhotoId), appImManager.chat.bubbles.lazyLoadQueue.queueId);\r\n };\r\n\r\n protected loadMoreMedia = (older = true) => {\r\n if(this.peerId < 0) return Promise.resolve(); // ! это значит, что открыло аватар чата, но следующих фотографий нет.\r\n if(this.loadedAllMediaDown) return Promise.resolve();\r\n if(this.loadMediaPromiseDown) return this.loadMediaPromiseDown;\r\n\r\n const peerId = this.peerId;\r\n const loadCount = 50;\r\n\r\n const maxId = this.nextTargets.length ? this.nextTargets[this.nextTargets.length - 1].photoId : this.currentPhotoId;\r\n\r\n const promise = appPhotosManager.getUserPhotos(peerId, maxId, loadCount).then(value => {\r\n if(this.peerId !== peerId) {\r\n this.log.warn('peer changed');\r\n return;\r\n }\r\n\r\n // if(DEBUG) {\r\n // this.log('loaded more media by maxId:', /* maxId, */value, older, this.reverse);\r\n // }\r\n\r\n if(value.photos.length < loadCount) {\r\n this.loadedAllMediaDown = true;\r\n }\r\n\r\n value.photos.forEach(photoId => {\r\n if(this.currentPhotoId === photoId) return;\r\n this.nextTargets.push({element: null as HTMLElement, photoId: photoId});\r\n });\r\n\r\n this.buttons.prev.classList.toggle('hide', !this.prevTargets.length);\r\n this.buttons.next.classList.toggle('hide', !this.nextTargets.length);\r\n }, () => {}).then(() => {\r\n this.loadMediaPromiseDown = null;\r\n });\r\n\r\n return this.loadMediaPromiseDown = promise;\r\n };\r\n\r\n public async openMedia(photoId: string, target?: HTMLElement, fromRight = 0, prevTargets?: AppMediaViewerAvatarTargetType[], nextTargets?: AppMediaViewerAvatarTargetType[]) {\r\n if(this.setMoverPromise) return this.setMoverPromise;\r\n\r\n const photo = appPhotosManager.getPhoto(photoId);\r\n\r\n this.currentPhotoId = photo.id;\r\n \r\n return super._openMedia(photo, photo.date, this.peerId, fromRight, target, false, prevTargets, nextTargets);\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 getVisibleRect(element: HTMLElement, overflowElement: HTMLElement) {\r\n const rect = element.getBoundingClientRect();\r\n const overflowRect = overflowElement.getBoundingClientRect();\r\n\r\n let {top: overflowTop, bottom: overflowBottom} = overflowRect;\r\n\r\n // * respect sticky headers\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 if(rect.top >= overflowBottom\r\n || rect.bottom <= overflowTop\r\n || rect.right <= overflowRect.left\r\n || rect.left >= overflowRect.right) {\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: 0,\r\n bottom: rect.bottom > overflowBottom && overflowBottom !== windowHeight ? (overflow.bottom = true, ++overflow.vertical, overflowBottom) : rect.bottom,\r\n left: 0\r\n },\r\n overflow\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 appMessagesManager from \"../lib/appManagers/appMessagesManager\";\r\nimport appProfileManager from \"../lib/appManagers/appProfileManager\";\r\nimport rootScope from \"../lib/rootScope\";\r\nimport { attachClickEvent, cancelEvent } from \"../helpers/dom\";\r\nimport AppMediaViewer, { AppMediaViewerAvatar } from \"./appMediaViewer\";\r\nimport { Message, Photo } from \"../layer\";\r\nimport appPeersManager from \"../lib/appManagers/appPeersManager\";\r\nimport appPhotosManager from \"../lib/appManagers/appPhotosManager\";\r\n//import type { LazyLoadQueueIntersector } from \"./lazyLoadQueue\";\r\n\r\nconst onAvatarUpdate = (peerId: number) => {\r\n appProfileManager.removeFromAvatarsCache(peerId);\r\n (Array.from(document.querySelectorAll('avatar-element[peer=\"' + peerId + '\"]')) as AvatarElement[]).forEach(elem => {\r\n //console.log('updating avatar:', elem);\r\n elem.update();\r\n });\r\n};\r\n\r\nrootScope.on('avatar_update', onAvatarUpdate);\r\nrootScope.on('peer_title_edit', onAvatarUpdate);\r\n\r\nexport async function openAvatarViewer(target: HTMLElement, peerId: number, middleware: () => boolean, message?: any, prevTargets?: {element: HTMLElement, item: string | Message.messageService}[], nextTargets?: typeof prevTargets) {\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 < 0) {\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,\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(typeof(message) === 'string') {\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\nexport default class AvatarElement extends HTMLElement {\r\n private peerId: number;\r\n private isDialog = false;\r\n public peerTitle: string;\r\n public loadPromises: Promise<any>[];\r\n //public lazyLoadQueue: LazyLoadQueueIntersector;\r\n //private addedToQueue = false;\r\n\r\n constructor() {\r\n super();\r\n // элемент создан\r\n }\r\n\r\n connectedCallback() {\r\n // браузер вызывает этот метод при добавлении элемента в документ\r\n // (может вызываться много раз, если элемент многократно добавляется/удаляется)\r\n\r\n this.isDialog = !!this.getAttribute('dialog');\r\n if(this.getAttribute('clickable') === '') {\r\n this.setAttribute('clickable', 'set');\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\r\n /* disconnectedCallback() {\r\n // браузер вызывает этот метод при удалении элемента из документа\r\n // (может вызываться много раз, если элемент многократно добавляется/удаляется)\r\n if(this.lazyLoadQueue) {\r\n this.lazyLoadQueue.unobserve(this);\r\n }\r\n } */\r\n\r\n static get observedAttributes(): string[] {\r\n return ['peer', 'dialog', 'peer-title'/* массив имён атрибутов для отслеживания их изменений */];\r\n }\r\n\r\n attributeChangedCallback(name: string, oldValue: string, newValue: string) {\r\n //console.log('avatar changed attribute:', name, oldValue, newValue);\r\n // вызывается при изменении одного из перечисленных выше атрибутов\r\n if(name === 'peer') {\r\n if(this.peerId === +newValue) {\r\n return;\r\n }\r\n \r\n this.peerId = appPeersManager.getPeerMigratedTo(+newValue) || +newValue;\r\n this.update();\r\n } else if(name === 'peer-title') {\r\n this.peerTitle = newValue;\r\n } else if(name === 'dialog') {\r\n this.isDialog = !!+newValue;\r\n }\r\n }\r\n\r\n public update() {\r\n /* if(this.lazyLoadQueue) {\r\n if(this.addedToQueue) return;\r\n this.lazyLoadQueue.push({\r\n div: this, \r\n load: () => {\r\n return appProfileManager.putPhoto(this, this.peerId, this.isDialog, this.peerTitle).finally(() => {\r\n this.addedToQueue = false;\r\n });\r\n }\r\n });\r\n this.addedToQueue = true;\r\n } else { */\r\n const res = appProfileManager.putPhoto(this, this.peerId, this.isDialog, this.peerTitle);\r\n if(this.loadPromises && res && res.cached) {\r\n this.loadPromises.push(res.loadPromise);\r\n res.loadPromise.finally(() => {\r\n this.loadPromises = undefined;\r\n });\r\n }\r\n //}\r\n }\r\n}\r\n\r\ncustomElements.define(\"avatar-element\", AvatarElement);\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 appMessagesManager, {Dialog} from \"../lib/appManagers/appMessagesManager\";\r\nimport appPeersManager from \"../lib/appManagers/appPeersManager\";\r\nimport rootScope from \"../lib/rootScope\";\r\nimport { positionMenu, openBtnMenu } from \"./misc\";\r\nimport ButtonMenu, { ButtonMenuItemOptions } from \"./buttonMenu\";\r\nimport PopupDeleteDialog from \"./popups/deleteDialog\";\r\nimport { i18n } from \"../lib/langPack\";\r\nimport findUpTag from \"../helpers/dom/findUpTag\";\r\n\r\nexport default class DialogsContextMenu {\r\n private element: HTMLElement;\r\n private buttons: (ButtonMenuItemOptions & {verify: () => boolean})[];\r\n\r\n private selectedId: number;\r\n private filterId: number;\r\n private dialog: Dialog;\r\n\r\n private init() {\r\n this.buttons = [{\r\n icon: 'unread',\r\n text: 'MarkAsUnread',\r\n onClick: this.onUnreadClick,\r\n verify: () => {\r\n const isUnread = !!(this.dialog.pFlags?.unread_mark || this.dialog.unread_count);\r\n return !isUnread;\r\n }\r\n }, {\r\n icon: 'readchats',\r\n text: 'MarkAsRead',\r\n onClick: this.onUnreadClick,\r\n verify: () => { \r\n const isUnread = !!(this.dialog.pFlags?.unread_mark || this.dialog.unread_count);\r\n return isUnread;\r\n }\r\n }, {\r\n icon: 'pin',\r\n text: 'ChatList.Context.Pin',\r\n onClick: this.onPinClick,\r\n verify: () => {\r\n const isPinned = this.filterId > 1 ? appMessagesManager.filtersStorage.filters[this.filterId].pinned_peers.includes(this.dialog.peerId) : !!this.dialog.pFlags?.pinned;\r\n return !isPinned;\r\n }\r\n }, {\r\n icon: 'unpin',\r\n text: 'ChatList.Context.Unpin',\r\n onClick: this.onPinClick,\r\n verify: () => {\r\n const isPinned = this.filterId > 1 ? appMessagesManager.filtersStorage.filters[this.filterId].pinned_peers.includes(this.dialog.peerId) : !!this.dialog.pFlags?.pinned;\r\n return isPinned;\r\n }\r\n }, {\r\n icon: 'mute',\r\n text: 'ChatList.Context.Mute',\r\n onClick: this.onMuteClick,\r\n verify: () => {\r\n const isMuted = this.dialog.notify_settings && this.dialog.notify_settings.mute_until > (Date.now() / 1000 | 0);\r\n return !isMuted && this.selectedId !== rootScope.myId; \r\n }\r\n }, {\r\n icon: 'unmute',\r\n text: 'ChatList.Context.Unmute',\r\n onClick: this.onMuteClick,\r\n verify: () => {\r\n const isMuted = this.dialog.notify_settings && this.dialog.notify_settings.mute_until > (Date.now() / 1000 | 0);\r\n return isMuted && this.selectedId !== rootScope.myId; \r\n }\r\n }, {\r\n icon: 'archive',\r\n text: 'Archive',\r\n onClick: this.onArchiveClick,\r\n verify: () => this.filterId === 0 && this.selectedId !== rootScope.myId\r\n }, {\r\n icon: 'unarchive',\r\n text: 'Unarchive',\r\n onClick: this.onArchiveClick,\r\n verify: () => this.filterId === 1 && this.selectedId !== rootScope.myId\r\n }, {\r\n icon: 'delete danger',\r\n text: 'Delete',\r\n onClick: this.onDeleteClick,\r\n verify: () => true\r\n }];\r\n\r\n this.element = ButtonMenu(this.buttons);\r\n this.element.id = 'dialogs-contextmenu';\r\n this.element.classList.add('contextmenu');\r\n document.getElementById('page-chats').append(this.element);\r\n }\r\n\r\n private onArchiveClick = () => {\r\n let dialog = appMessagesManager.getDialogByPeerId(this.selectedId)[0];\r\n if(dialog) {\r\n appMessagesManager.editPeerFolders([dialog.peerId], +!dialog.folder_id);\r\n }\r\n };\r\n\r\n private onPinClick = () => {\r\n appMessagesManager.toggleDialogPin(this.selectedId, this.filterId);\r\n };\r\n \r\n private onMuteClick = () => {\r\n appMessagesManager.mutePeer(this.selectedId);\r\n };\r\n\r\n private onUnreadClick = () => {\r\n const dialog = appMessagesManager.getDialogByPeerId(this.selectedId)[0];\r\n if(!dialog) return;\r\n\r\n if(dialog.unread_count) {\r\n appMessagesManager.readHistory(this.selectedId, dialog.top_message);\r\n appMessagesManager.markDialogUnread(this.selectedId, true);\r\n } else {\r\n appMessagesManager.markDialogUnread(this.selectedId);\r\n }\r\n };\r\n\r\n private onDeleteClick = () => {\r\n new PopupDeleteDialog(this.selectedId);\r\n };\r\n\r\n onContextMenu = (e: MouseEvent | Touch) => {\r\n if(this.init) {\r\n this.init();\r\n this.init = null;\r\n }\r\n\r\n let li: HTMLElement = null;\r\n \r\n try {\r\n li = findUpTag(e.target, 'LI');\r\n } catch(e) {}\r\n \r\n if(!li) return;\r\n\r\n if(e instanceof MouseEvent) e.preventDefault();\r\n if(this.element.classList.contains('active')) {\r\n return false;\r\n }\r\n if(e instanceof MouseEvent) e.cancelBubble = true;\r\n\r\n this.filterId = appDialogsManager.filterId;\r\n\r\n this.selectedId = +li.dataset.peerId;\r\n this.dialog = appMessagesManager.getDialogByPeerId(this.selectedId)[0];\r\n\r\n this.buttons.forEach(button => {\r\n const good = button.verify();\r\n\r\n button.element.classList.toggle('hide', !good);\r\n });\r\n\r\n // delete button\r\n this.buttons[this.buttons.length - 1].element.lastChild.replaceWith(i18n(appPeersManager.getDeleteButtonText(this.selectedId)));\r\n\r\n li.classList.add('menu-open');\r\n positionMenu(e, this.element);\r\n openBtnMenu(this.element, () => {\r\n li.classList.remove('menu-open');\r\n this.selectedId = this.dialog = this.filterId = undefined;\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 AvatarElement from \"../../components/avatar\";\r\nimport DialogsContextMenu from \"../../components/dialogsContextMenu\";\r\nimport { horizontalMenu } from \"../../components/horizontalMenu\";\r\nimport { attachContextMenuListener, putPreloader } from \"../../components/misc\";\r\nimport { ripple } from \"../../components/ripple\";\r\n//import Scrollable from \"../../components/scrollable\";\r\nimport Scrollable, { ScrollableX, SliceSides } from \"../../components/scrollable\";\r\nimport { formatDateAccordingToTodayNew } from \"../../helpers/date\";\r\nimport { isSafari } from \"../../helpers/userAgent\";\r\nimport { logger, LogLevels } from \"../logger\";\r\nimport { RichTextProcessor } from \"../richtextprocessor\";\r\nimport rootScope from \"../rootScope\";\r\nimport { positionElementByIndex } from \"../../helpers/dom\";\r\nimport appImManager from \"./appImManager\";\r\nimport appMessagesManager, { Dialog } from \"./appMessagesManager\";\r\nimport {MyDialogFilter as DialogFilter} from \"../storages/filters\";\r\nimport appPeersManager from './appPeersManager';\r\nimport appStateManager from \"./appStateManager\";\r\nimport appUsersManager, { User } from \"./appUsersManager\";\r\nimport Button from \"../../components/button\";\r\nimport SetTransition from \"../../components/singleTransition\";\r\nimport sessionStorage from '../sessionStorage';\r\nimport apiUpdatesManager from \"./apiUpdatesManager\";\r\nimport appDraftsManager, { MyDraftMessage } from \"./appDraftsManager\";\r\nimport ProgressivePreloader from \"../../components/preloader\";\r\nimport App from \"../../config/app\";\r\nimport DEBUG, { MOUNT_CLASS_TO } from \"../../config/debug\";\r\nimport appNotificationsManager from \"./appNotificationsManager\";\r\nimport { InputNotifyPeer } from \"../../layer\";\r\nimport PeerTitle from \"../../components/peerTitle\";\r\nimport { i18n } from \"../langPack\";\r\nimport findUpTag from \"../../helpers/dom/findUpTag\";\r\n\r\nexport type DialogDom = {\r\n avatarEl: AvatarElement,\r\n captionDiv: HTMLDivElement,\r\n titleSpan: HTMLSpanElement,\r\n titleSpanContainer: HTMLSpanElement,\r\n statusSpan: HTMLSpanElement,\r\n lastTimeSpan: HTMLSpanElement,\r\n unreadMessagesSpan: HTMLSpanElement,\r\n lastMessageSpan: HTMLSpanElement,\r\n containerEl: HTMLElement,\r\n listEl: HTMLLIElement,\r\n muteAnimationTimeout?: number\r\n};\r\n\r\n//const testScroll = false;\r\n//let testTopSlice = 1;\r\n\r\nclass 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 currentText = '';\r\n\r\n private connecting = 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');\r\n \r\n this.statusContainer = document.createElement('div');\r\n this.statusContainer.classList.add('connection-status');\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.on('connection_status_change', (e) => {\r\n const status = e;\r\n console.log(status);\r\n\r\n this.setConnectionStatus();\r\n });\r\n\r\n rootScope.on('state_synchronizing', (e) => {\r\n const channelId = e;\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.on('state_synchronized', (e) => {\r\n const channelId = e;\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 rootScope.broadcast('connection_status_change', {\r\n dcId: 2,\r\n isFileDownload: false,\r\n isFileNetworker: false,\r\n isFileUpload: false,\r\n name: \"NET-2\",\r\n online: bool = !bool,\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.online;\r\n\r\n if(this.connecting && online) {\r\n apiUpdatesManager.forceGetDifference();\r\n }\r\n\r\n this.connecting = !online;\r\n DEBUG && this.log('connecting', this.connecting);\r\n this.setState();\r\n });\r\n };\r\n\r\n private setStatusText = (text: string) => {\r\n if(this.currentText === text) return;\r\n this.statusEl.innerText = this.currentText = text;\r\n this.statusPreloader.attach(this.statusEl);\r\n };\r\n\r\n private setState = () => {\r\n const timeout = ConnectionStatusComponent.CHANGE_STATE_DELAY;\r\n if(this.connecting) {\r\n this.setStatusText('Waiting for network...');\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\r\nexport class AppDialogsManager {\r\n public chatList: HTMLUListElement;\r\n\r\n public doms: {[peerId: number]: DialogDom} = {};\r\n\r\n public chatsContainer = document.getElementById('chatlist-container') as HTMLDivElement;\r\n private chatsPreloader: HTMLElement;\r\n\r\n public loadDialogsPromise: Promise<any>;\r\n\r\n public scroll: Scrollable = null;\r\n public _scroll: Scrollable = null;\r\n \r\n private log = logger('DIALOGS', LogLevels.log | LogLevels.error | LogLevels.warn | LogLevels.debug);\r\n\r\n public contextMenu = new DialogsContextMenu();\r\n\r\n public chatLists: {[filterId: number]: HTMLUListElement};\r\n public filterId: number;\r\n private folders: {[k in 'menu' | 'container' | 'menuScrollContainer']: HTMLElement} = {\r\n menu: document.getElementById('folders-tabs'),\r\n menuScrollContainer: null,\r\n container: document.getElementById('folders-container')\r\n };\r\n private filtersRendered: {\r\n [filterId: string]: {\r\n menu: HTMLElement, \r\n container: HTMLElement,\r\n unread: HTMLElement,\r\n title: HTMLElement\r\n }\r\n } = {};\r\n private showFiltersTimeout: number;\r\n private allUnreadCount: HTMLElement;\r\n\r\n private accumulateArchivedTimeout: number;\r\n\r\n //private topOffsetIndex = 0;\r\n\r\n private sliceTimeout: number;\r\n private reorderDialogsTimeout: number;\r\n\r\n private lastActiveElements: Set<HTMLElement> = new Set();\r\n\r\n constructor() {\r\n const archivedChatList = this.createChatList();\r\n this.chatLists = {\r\n 1: archivedChatList\r\n };\r\n\r\n this.setListClickListener(archivedChatList, null, true);\r\n //this.setListClickListener(archivedChatList, null, true); // * to test peer changing\r\n\r\n this.chatsPreloader = putPreloader(null, true);\r\n\r\n this.allUnreadCount = this.folders.menu.querySelector('.badge');\r\n \r\n this.folders.menuScrollContainer = this.folders.menu.parentElement;\r\n\r\n const bottomPart = document.createElement('div');\r\n bottomPart.classList.add('connection-status-bottom');\r\n bottomPart.append(this.folders.container);\r\n\r\n this.scroll = this._scroll = new Scrollable(bottomPart, 'CL', 500);\r\n this.scroll.container.addEventListener('scroll', this.onChatsRegularScroll);\r\n this.scroll.onScrolledTop = this.onChatsScrollTop;\r\n this.scroll.onScrolledBottom = this.onChatsScroll;\r\n //this.scroll.attachSentinels();\r\n\r\n /* if(isTouchSupported && isSafari) {\r\n let allowUp: boolean, allowDown: boolean, slideBeginY: number;\r\n const container = this.scroll.container;\r\n container.addEventListener('touchstart', (event) => {\r\n allowUp = container.scrollTop > 0;\r\n allowDown = (container.scrollTop < container.scrollHeight - container.clientHeight);\r\n // @ts-ignore\r\n slideBeginY = event.pageY;\r\n });\r\n \r\n container.addEventListener('touchmove', (event: any) => {\r\n var up = (event.pageY > slideBeginY);\r\n var down = (event.pageY < slideBeginY);\r\n slideBeginY = event.pageY;\r\n if((up && allowUp) || (down && allowDown)) {\r\n event.stopPropagation();\r\n } else if(up || down) {\r\n event.preventDefault();\r\n }\r\n });\r\n } */\r\n\r\n this.filterId = 0;\r\n this.addFilter({\r\n id: this.filterId,\r\n title: '',\r\n titleEl: i18n('ChatList.Filter.All'),\r\n orderIndex: 0\r\n });\r\n\r\n this.chatList = this.chatLists[this.filterId];\r\n this.scroll.setVirtualContainer(this.chatList);\r\n\r\n /* if(testScroll) {\r\n let i = 0;\r\n let add = () => {\r\n let li = document.createElement('li');\r\n li.dataset.id = '' + i;\r\n li.id = '' + i;\r\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>`;\r\n i++;\r\n this.scroll.append(li);\r\n };\r\n for(let i = 0; i < 500; ++i) {\r\n add();\r\n }\r\n (window as any).addElement = add;\r\n } */\r\n\r\n rootScope.on('user_update', (e) => {\r\n const userId = e;\r\n const user = appUsersManager.getUser(userId);\r\n const dialog = appMessagesManager.getDialogByPeerId(user.id)[0];\r\n //console.log('updating user:', user, dialog);\r\n\r\n if(dialog && !appUsersManager.isBot(dialog.peerId) && dialog.peerId !== rootScope.myId) {\r\n const online = user.status?._ === 'userStatusOnline';\r\n const dom = this.getDialogDom(dialog.peerId);\r\n\r\n if(dom) {\r\n dom.avatarEl.classList.toggle('is-online', online);\r\n }\r\n }\r\n });\r\n\r\n /* rootScope.$on('dialog_top', (e) => {\r\n const dialog = e;\r\n\r\n this.setLastMessage(dialog);\r\n this.setDialogPosition(dialog);\r\n\r\n this.setFiltersUnreadCount();\r\n }); */\r\n\r\n rootScope.on('dialog_flush', (e) => {\r\n const peerId: number = e.peerId;\r\n const dialog = appMessagesManager.getDialogByPeerId(peerId)[0];\r\n if(dialog) {\r\n this.setLastMessage(dialog);\r\n this.validateForFilter();\r\n this.setFiltersUnreadCount();\r\n }\r\n });\r\n\r\n rootScope.on('dialogs_multiupdate', (e) => {\r\n const dialogs = e;\r\n\r\n for(const id in dialogs) {\r\n const dialog = dialogs[id];\r\n this.updateDialog(dialog);\r\n }\r\n\r\n this.validateForFilter();\r\n this.setFiltersUnreadCount();\r\n });\r\n\r\n rootScope.on('dialog_drop', (e) => {\r\n const {peerId, dialog} = e;\r\n\r\n const dom = this.getDialogDom(peerId);\r\n if(dom) {\r\n dom.listEl.remove();\r\n delete this.doms[peerId];\r\n }\r\n\r\n this.setFiltersUnreadCount();\r\n });\r\n\r\n rootScope.on('dialog_unread', (e) => {\r\n const info = e;\r\n\r\n const dialog = appMessagesManager.getDialogByPeerId(info.peerId)[0];\r\n if(dialog) {\r\n this.setUnreadMessages(dialog);\r\n this.validateForFilter();\r\n this.setFiltersUnreadCount();\r\n }\r\n });\r\n\r\n rootScope.on('dialog_notify_settings', (dialog) => {\r\n this.setUnreadMessages(dialog); // возможно это не нужно, но нужно менять is-muted\r\n });\r\n\r\n rootScope.on('dialog_draft', (e) => {\r\n const dialog = appMessagesManager.getDialogByPeerId(e.peerId)[0];\r\n if(dialog) {\r\n this.updateDialog(dialog);\r\n }\r\n });\r\n\r\n rootScope.on('peer_changed', (e) => {\r\n const peerId = e;\r\n\r\n //const perf = performance.now();\r\n for(const element of this.lastActiveElements) {\r\n if(+element.dataset.peerId !== peerId) {\r\n element.classList.remove('active');\r\n this.lastActiveElements.delete(element);\r\n }\r\n }\r\n\r\n const elements = Array.from(document.querySelectorAll(`[data-autonomous=\"0\"] li[data-peer-id=\"${peerId}\"]`)) as HTMLElement[];\r\n elements.forEach(element => {\r\n element.classList.add('active');\r\n this.lastActiveElements.add(element);\r\n });\r\n //this.log('peer_changed total time:', performance.now() - perf);\r\n });\r\n\r\n rootScope.on('filter_update', (e) => {\r\n const filter: DialogFilter = e;\r\n if(!this.filtersRendered[filter.id]) {\r\n this.addFilter(filter);\r\n return;\r\n } else if(filter.id === this.filterId) { // это нет тут смысла вызывать, так как будет dialogs_multiupdate\r\n //this.validateForFilter();\r\n const folder = appMessagesManager.dialogsStorage.getFolder(filter.id);\r\n this.validateForFilter();\r\n for(let i = 0, length = folder.length; i < length; ++i) {\r\n const dialog = folder[i];\r\n this.updateDialog(dialog);\r\n }\r\n this.setFiltersUnreadCount();\r\n }\r\n\r\n const elements = this.filtersRendered[filter.id];\r\n elements.title.innerHTML = RichTextProcessor.wrapEmojiText(filter.title);\r\n });\r\n\r\n rootScope.on('filter_delete', (e) => {\r\n const filter: DialogFilter = e;\r\n const elements = this.filtersRendered[filter.id];\r\n if(!elements) return;\r\n\r\n // set tab\r\n //(this.folders.menu.firstElementChild.children[Math.max(0, filter.id - 2)] as HTMLElement).click();\r\n (this.folders.menu.firstElementChild as HTMLElement).click();\r\n\r\n elements.container.remove();\r\n elements.menu.remove();\r\n \r\n delete this.chatLists[filter.id];\r\n delete this.filtersRendered[filter.id];\r\n\r\n if(Object.keys(this.filtersRendered).length <= 1) {\r\n this.folders.menuScrollContainer.classList.add('hide');\r\n }\r\n });\r\n\r\n rootScope.on('filter_order', (e) => {\r\n const order = e;\r\n \r\n const containerToAppend = this.folders.menu as HTMLElement;\r\n order.forEach((filterId) => {\r\n const filter = appMessagesManager.filtersStorage.filters[filterId];\r\n const renderedFilter = this.filtersRendered[filterId];\r\n\r\n positionElementByIndex(renderedFilter.menu, containerToAppend, filter.orderIndex);\r\n positionElementByIndex(renderedFilter.container, this.folders.container, filter.orderIndex);\r\n });\r\n\r\n /* if(this.filterId) {\r\n const tabIndex = order.indexOf(this.filterId) + 1;\r\n selectTab.prevId = tabIndex;\r\n } */\r\n });\r\n\r\n rootScope.on('peer_typings', (e) => {\r\n const {peerId, typings} = e;\r\n\r\n const dialog = appMessagesManager.getDialogByPeerId(peerId)[0];\r\n if(!dialog) return;\r\n\r\n if(typings.length) {\r\n this.setTyping(dialog, appUsersManager.getUser(typings[0]));\r\n } else {\r\n this.unsetTyping(dialog);\r\n }\r\n });\r\n\r\n const foldersScrollable = new ScrollableX(this.folders.menuScrollContainer);\r\n bottomPart.prepend(this.folders.menuScrollContainer);\r\n const selectTab = horizontalMenu(this.folders.menu, this.folders.container, (id, tabContent) => {\r\n /* if(id !== 0) {\r\n id += 1;\r\n } */\r\n\r\n id = +tabContent.dataset.filterId || 0;\r\n\r\n if(this.filterId === id) return;\r\n\r\n this.chatLists[id].innerHTML = '';\r\n this.scroll.setVirtualContainer(this.chatLists[id]);\r\n this.filterId = id;\r\n this.onTabChange();\r\n }, () => {\r\n for(const folderId in this.chatLists) {\r\n if(+folderId !== this.filterId) {\r\n this.chatLists[folderId].innerHTML = '';\r\n }\r\n }\r\n }, undefined, foldersScrollable);\r\n\r\n //selectTab(0);\r\n (this.folders.menu.firstElementChild as HTMLElement).click();\r\n appStateManager.getState().then((state) => {\r\n (['inputNotifyBroadcasts', 'inputNotifyUsers', 'inputNotifyChats'] as Exclude<InputNotifyPeer['_'], 'inputNotifyPeer'>[])\r\n .forEach((inputKey) => {\r\n appNotificationsManager.getNotifySettings({_: inputKey});\r\n });\r\n \r\n const getFiltersPromise = appMessagesManager.filtersStorage.getDialogFilters();\r\n getFiltersPromise.then((filters) => {\r\n for(const filter of filters) {\r\n this.addFilter(filter);\r\n }\r\n });\r\n\r\n if(state.dialogs?.length) {\r\n appDraftsManager.getAllDrafts();\r\n appDraftsManager.addMissedDialogs();\r\n }\r\n\r\n return this.loadDialogs();\r\n }).then(() => {\r\n const allDialogsLoaded = appMessagesManager.dialogsStorage.allDialogsLoaded;\r\n const wasLoaded = allDialogsLoaded[0] || allDialogsLoaded[1];\r\n const a: Promise<any> = allDialogsLoaded[0] ? Promise.resolve() : appMessagesManager.getConversationsAll('', 0);\r\n const b: Promise<any> = allDialogsLoaded[1] ? Promise.resolve() : appMessagesManager.getConversationsAll('', 1);\r\n a.finally(() => {\r\n b.then(() => {\r\n this.accumulateArchivedUnread();\r\n\r\n if(wasLoaded) {\r\n (apiUpdatesManager.updatesState.syncLoading || Promise.resolve()).then(() => {\r\n appMessagesManager.refreshConversations();\r\n });\r\n }\r\n });\r\n });\r\n });\r\n\r\n new ConnectionStatusComponent(this.chatsContainer);\r\n this.chatsContainer.append(bottomPart);\r\n }\r\n\r\n private getOffset(side: 'top' | 'bottom'): {index: number, pos: number} {\r\n if(!this.scroll.loadedAll[side]) {\r\n const element = (side === 'top' ? this.chatList.firstElementChild : this.chatList.lastElementChild) as HTMLElement;\r\n if(element) {\r\n const peerId = +element.dataset.peerId;\r\n const dialog = appMessagesManager.getDialogByPeerId(peerId);\r\n return {index: dialog[0].index, pos: dialog[1]};\r\n }\r\n }\r\n\r\n return {index: 0, pos: -1};\r\n }\r\n\r\n private isDialogMustBeInViewport(dialog: Dialog) {\r\n //return true;\r\n const topOffset = this.getOffset('top');\r\n const bottomOffset = this.getOffset('bottom');\r\n \r\n if(!topOffset.index && !bottomOffset.index) {\r\n return true;\r\n }\r\n \r\n const index = dialog.index;\r\n return (!topOffset.index || index <= topOffset.index) && (!bottomOffset.index || index >= bottomOffset.index);\r\n }\r\n\r\n private updateDialog(dialog: Dialog) {\r\n if(!dialog) {\r\n return;\r\n }\r\n\r\n if(this.isDialogMustBeInViewport(dialog)) {\r\n if(!this.doms.hasOwnProperty(dialog.peerId)) {\r\n const ret = this.addDialogNew({dialog});\r\n if(ret) {\r\n const idx = appMessagesManager.getDialogByPeerId(dialog.peerId)[1];\r\n positionElementByIndex(ret.dom.listEl, this.chatList, idx);\r\n } else {\r\n return;\r\n }\r\n }\r\n } else {\r\n const dom = this.getDialogDom(dialog.peerId);\r\n if(dom) {\r\n dom.listEl.remove();\r\n delete this.doms[dialog.peerId];\r\n }\r\n\r\n return;\r\n }\r\n\r\n /* const topOffset = this.getOffset('top');\r\n if(topOffset.index && dialog.index > topOffset.index) {\r\n const dom = this.getDialogDom(dialog.peerId);\r\n if(dom) {\r\n dom.listEl.remove();\r\n delete this.doms[dialog.peerId];\r\n }\r\n\r\n return;\r\n }\r\n\r\n if(!this.doms.hasOwnProperty(dialog.peerId)) {\r\n this.addDialogNew({dialog});\r\n } */\r\n\r\n if(this.getDialogDom(dialog.peerId)) {\r\n this.setLastMessage(dialog);\r\n this.reorderDialogs();\r\n }\r\n }\r\n\r\n onTabChange = () => {\r\n this.doms = {};\r\n this.scroll.loadedAll.top = true;\r\n this.scroll.loadedAll.bottom = false;\r\n this.loadDialogsPromise = undefined;\r\n this.chatList = this.chatLists[this.filterId];\r\n this.loadDialogs();\r\n };\r\n\r\n private setFilterUnreadCount(filterId: number, folder?: Dialog[]) {\r\n const unreadSpan = filterId === 0 ? this.allUnreadCount : this.filtersRendered[filterId]?.unread;\r\n if(!unreadSpan) {\r\n return;\r\n }\r\n\r\n folder = folder || appMessagesManager.dialogsStorage.getFolder(filterId);\r\n let mutedCount = 0;\r\n let notMutedCount = 0;\r\n folder.forEach(dialog => {\r\n const isMuted = appNotificationsManager.isPeerLocalMuted(dialog.peerId, true);\r\n\r\n if(isMuted && filterId === 0) {\r\n return;\r\n }\r\n\r\n const value = +!!dialog.unread_count || +dialog.pFlags.unread_mark || 0; // * unread_mark can be undefined\r\n if(isMuted) mutedCount += value;\r\n else notMutedCount += value;\r\n });\r\n \r\n unreadSpan.classList.toggle('badge-gray', mutedCount && !notMutedCount);\r\n \r\n const sum = mutedCount + notMutedCount;\r\n unreadSpan.innerText = sum ? '' + sum : '';\r\n }\r\n\r\n private setFiltersUnreadCount() {\r\n for(const filterId in this.filtersRendered) {\r\n this.setFilterUnreadCount(+filterId);\r\n }\r\n\r\n this.setFilterUnreadCount(0);\r\n }\r\n\r\n /**\r\n * Удалит неподходящие чаты из списка, но не добавит их(!)\r\n */\r\n private validateForFilter() {\r\n // !WARNING, возможно это было зачем-то, но комментарий исправил архивирование\r\n //if(this.filterId === 0) return;\r\n\r\n const folder = appMessagesManager.dialogsStorage.getFolder(this.filterId);\r\n for(const _peerId in this.doms) {\r\n const peerId = +_peerId;\r\n\r\n // если больше не подходит по фильтру, удаляем\r\n if(folder.findIndex((dialog) => dialog.peerId === peerId) === -1) {\r\n const listEl = this.doms[peerId].listEl;\r\n listEl.remove();\r\n delete this.doms[peerId];\r\n }\r\n }\r\n }\r\n\r\n private addFilter(filter: Pick<DialogFilter, 'title' | 'id' | 'orderIndex'> & Partial<{titleEl: HTMLElement}>) {\r\n if(this.filtersRendered[filter.id]) return;\r\n\r\n const menuTab = document.createElement('div');\r\n menuTab.classList.add('menu-horizontal-div-item');\r\n const span = document.createElement('span');\r\n const titleSpan = document.createElement('span');\r\n titleSpan.classList.add('text-super');\r\n if(filter.titleEl) titleSpan.append(filter.titleEl);\r\n else titleSpan.innerHTML = RichTextProcessor.wrapEmojiText(filter.title);\r\n const unreadSpan = document.createElement('div');\r\n unreadSpan.classList.add('badge', 'badge-20', 'badge-primary');\r\n const i = document.createElement('i');\r\n span.append(titleSpan, unreadSpan, i);\r\n menuTab.append(span);\r\n ripple(menuTab);\r\n\r\n const containerToAppend = this.folders.menu as HTMLElement;\r\n positionElementByIndex(menuTab, containerToAppend, filter.orderIndex);\r\n //containerToAppend.append(li);\r\n\r\n const ul = this.createChatList();\r\n const div = document.createElement('div');\r\n div.append(ul);\r\n div.dataset.filterId = '' + filter.id;\r\n //this.folders.container.append(div);\r\n positionElementByIndex(div, this.folders.container, filter.orderIndex);\r\n\r\n this.chatLists[filter.id] = ul;\r\n this.setListClickListener(ul, null, true);\r\n\r\n this.filtersRendered[filter.id] = {\r\n menu: menuTab,\r\n container: div,\r\n unread: unreadSpan,\r\n title: titleSpan\r\n };\r\n\r\n if(!this.showFiltersTimeout && Object.keys(this.filtersRendered).length > 1) {\r\n this.showFiltersTimeout = window.setTimeout(() => {\r\n this.showFiltersTimeout = 0;\r\n this.folders.menuScrollContainer.classList.remove('hide');\r\n this.setFiltersUnreadCount();\r\n }, 0);\r\n }\r\n }\r\n\r\n private loadDialogs(side: SliceSides = 'bottom') {\r\n /* if(testScroll) {\r\n return;\r\n } */\r\n \r\n if(this.loadDialogsPromise/* || 1 === 1 */) return this.loadDialogsPromise;\r\n\r\n const promise = new Promise<void>(async(resolve, reject) => {\r\n if(!this.chatList.childElementCount) {\r\n const container = this.chatList.parentElement;\r\n container.append(this.chatsPreloader);\r\n }\r\n \r\n //return;\r\n \r\n const filterId = this.filterId;\r\n let loadCount = 30/*this.chatsLoadCount */;\r\n \r\n const storage = appMessagesManager.dialogsStorage.getFolder(filterId);\r\n let offsetIndex = 0;\r\n \r\n if(side === 'top') {\r\n const element = this.chatList.firstElementChild as HTMLElement;\r\n if(element) {\r\n const peerId = +element.dataset.peerId;\r\n const index = storage.findIndex(dialog => dialog.peerId === peerId);\r\n const needIndex = Math.max(0, index - loadCount);\r\n loadCount = index - needIndex;\r\n offsetIndex = storage[needIndex].index + 1;\r\n }\r\n } else {\r\n const element = this.chatList.lastElementChild as HTMLElement;\r\n if(element) {\r\n const peerId = +element.dataset.peerId;\r\n const dialog = storage.find(dialog => dialog.peerId === peerId);\r\n offsetIndex = dialog.index;\r\n }\r\n }\r\n \r\n //let offset = storage[storage.length - 1]?.index || 0;\r\n \r\n try {\r\n //console.time('getDialogs time');\r\n \r\n const getConversationPromise = (this.filterId > 1 ? appUsersManager.getContacts() as Promise<any> : Promise.resolve()).then(() => {\r\n return appMessagesManager.getConversations('', offsetIndex, loadCount, filterId);\r\n });\r\n \r\n const result = await getConversationPromise;\r\n \r\n if(this.filterId !== filterId) {\r\n return;\r\n }\r\n \r\n //console.timeEnd('getDialogs time');\r\n \r\n // * loaded all\r\n //if(!result.dialogs.length || this.chatList.childElementCount === result.count) {\r\n // !result.dialogs.length не подходит, так как при супердревном диалоге getConversations его не выдаст.\r\n //if(this.chatList.childElementCount === result.count) {\r\n if(side === 'bottom') {\r\n if(result.isEnd) {\r\n this.scroll.loadedAll[side] = true;\r\n }\r\n } else {\r\n const storage = appMessagesManager.dialogsStorage.getFolder(filterId);\r\n if(!result.dialogs.length || (storage.length && storage[0].index < offsetIndex)) {\r\n this.scroll.loadedAll[side] = true;\r\n }\r\n }\r\n \r\n if(result.dialogs.length) {\r\n const dialogs = side === 'top' ? result.dialogs.slice().reverse() : result.dialogs;\r\n \r\n dialogs.forEach((dialog) => {\r\n this.addDialogNew({\r\n dialog,\r\n append: side === 'bottom'\r\n });\r\n });\r\n }\r\n \r\n this.log.debug('getDialogs ' + loadCount + ' dialogs by offset:', offsetIndex, result, this.chatList.childElementCount);\r\n \r\n setTimeout(() => {\r\n this.scroll.onScroll();\r\n }, 0);\r\n } catch(err) {\r\n this.log.error(err);\r\n }\r\n \r\n this.chatsPreloader.remove();\r\n resolve();\r\n });\r\n\r\n return this.loadDialogsPromise = promise.finally(() => {\r\n this.loadDialogsPromise = undefined;\r\n });\r\n }\r\n\r\n public onChatsRegularScroll = () => {\r\n if(this.sliceTimeout) clearTimeout(this.sliceTimeout);\r\n this.sliceTimeout = window.setTimeout(() => {\r\n this.sliceTimeout = undefined;\r\n\r\n if(!this.chatList.childElementCount) {\r\n return;\r\n }\r\n\r\n /* const observer = new IntersectionObserver((entries) => {\r\n const \r\n });\r\n\r\n Array.from(this.chatList.children).forEach(el => {\r\n observer.observe(el);\r\n }); */\r\n\r\n //const scrollTopWas = this.scroll.scrollTop;\r\n\r\n const firstElementChild = this.chatList.firstElementChild;\r\n const rectContainer = this.scroll.container.getBoundingClientRect();\r\n const rectTarget = firstElementChild.getBoundingClientRect();\r\n const children = Array.from(this.scroll.splitUp.children) as HTMLElement[];\r\n\r\n const offsetTop = this.folders.container.offsetTop;\r\n const firstY = rectContainer.y + offsetTop;\r\n const lastY = rectContainer.y;\r\n \r\n const firstElement = findUpTag(document.elementFromPoint(Math.ceil(rectTarget.x), Math.ceil(firstY + 1)), firstElementChild.tagName) as HTMLElement;\r\n const lastElement = findUpTag(document.elementFromPoint(Math.ceil(rectTarget.x), Math.floor(lastY + rectContainer.height - 1)), firstElementChild.tagName) as HTMLElement;\r\n\r\n //alert('got element:' + rect.y);\r\n\r\n if(!firstElement || !lastElement) {\r\n return;\r\n }\r\n\r\n //alert('got element:' + !!firstElement);\r\n\r\n const firstElementRect = firstElement.getBoundingClientRect();\r\n const elementOverflow = firstElementRect.y - firstY;\r\n\r\n const sliced: HTMLElement[] = [];\r\n const firstIndex = children.indexOf(firstElement);\r\n const lastIndex = children.indexOf(lastElement);\r\n\r\n const saveLength = 10;\r\n\r\n const sliceFromStart = isSafari ? [] : children.slice(0, Math.max(0, firstIndex - saveLength));\r\n const sliceFromEnd = children.slice(lastIndex + saveLength);\r\n\r\n /* if(sliceFromStart.length !== sliceFromEnd.length) {\r\n console.log('not equal', sliceFromStart.length, sliceFromEnd.length);\r\n }\r\n\r\n if(sliceFromStart.length > sliceFromEnd.length) {\r\n const diff = sliceFromStart.length - sliceFromEnd.length;\r\n sliceFromStart.splice(0, diff);\r\n } else if(sliceFromEnd.length > sliceFromStart.length) {\r\n const diff = sliceFromEnd.length - sliceFromStart.length;\r\n sliceFromEnd.splice(sliceFromEnd.length - diff, diff);\r\n } */\r\n\r\n if(sliceFromStart.length) {\r\n this.scroll.loadedAll['top'] = false;\r\n }\r\n\r\n if(sliceFromEnd.length) {\r\n this.scroll.loadedAll['bottom'] = false;\r\n }\r\n\r\n sliced.push(...sliceFromStart);\r\n sliced.push(...sliceFromEnd);\r\n\r\n sliced.forEach(el => {\r\n el.remove();\r\n const peerId = +el.dataset.peerId;\r\n delete this.doms[peerId];\r\n });\r\n\r\n //this.log('[slicer] elements', firstElement, lastElement, rect, sliced, sliceFromStart.length, sliceFromEnd.length);\r\n\r\n //this.log('[slicer] reset scrollTop', this.scroll.scrollTop, firstElement.offsetTop, firstElementRect.y, rect.y, elementOverflow);\r\n\r\n //alert('left length:' + children.length);\r\n\r\n this.scroll.scrollTop = firstElement.offsetTop - elementOverflow;\r\n /* const firstElementRect = firstElement.getBoundingClientRect();\r\n const scrollTop = */\r\n\r\n //this.scroll.scrollIntoView(firstElement, false);\r\n }, 200);\r\n };\r\n\r\n public onChatsScrollTop = () => {\r\n this.onChatsScroll('top');\r\n };\r\n \r\n public onChatsScroll = (side: SliceSides = 'bottom') => {\r\n if(this.scroll.loadedAll[side] || this.loadDialogsPromise) return;\r\n this.log('onChatsScroll', side);\r\n this.loadDialogs(side);\r\n };\r\n\r\n public setListClickListener(list: HTMLUListElement, onFound?: () => void, withContext = false, autonomous = false, openInner = false) {\r\n let lastActiveListElement: HTMLElement;\r\n\r\n const setPeerFunc = (openInner ? appImManager.setInnerPeer : appImManager.setPeer).bind(appImManager);\r\n\r\n list.dataset.autonomous = '' + +autonomous;\r\n list.addEventListener('mousedown', (e) => {\r\n if(e.button !== 0) return;\r\n //cancelEvent(e);\r\n\r\n this.log('dialogs click list');\r\n const target = e.target as HTMLElement;\r\n const elem = findUpTag(target, 'LI');\r\n\r\n if(!elem) {\r\n return;\r\n }\r\n\r\n if(autonomous) {\r\n const sameElement = lastActiveListElement === elem;\r\n if(lastActiveListElement && !sameElement) {\r\n lastActiveListElement.classList.remove('active');\r\n }\r\n\r\n if(elem) {\r\n elem.classList.add('active');\r\n lastActiveListElement = elem;\r\n this.lastActiveElements.add(elem);\r\n }\r\n }\r\n\r\n if(elem) {\r\n if(onFound) onFound();\r\n\r\n const peerId = +elem.dataset.peerId;\r\n const lastMsgId = +elem.dataset.mid || undefined;\r\n\r\n setPeerFunc(peerId, lastMsgId);\r\n } else {\r\n setPeerFunc(0);\r\n }\r\n }, {capture: true});\r\n\r\n if(DEBUG) {\r\n list.addEventListener('dblclick', (e) => {\r\n const li = findUpTag(e.target, 'LI');\r\n if(li) {\r\n const peerId = +li.dataset.peerId;\r\n this.log('debug dialog:', appMessagesManager.getDialogByPeerId(peerId));\r\n }\r\n });\r\n }\r\n\r\n if(withContext) {\r\n attachContextMenuListener(list, this.contextMenu.onContextMenu);\r\n }\r\n }\r\n\r\n public createChatList(/* options: {\r\n avatarSize?: number,\r\n handheldsSize?: number,\r\n //size?: number,\r\n } = {} */) {\r\n const list = document.createElement('ul');\r\n list.classList.add('chatlist'/* , \r\n 'chatlist-avatar-' + (options.avatarSize || 54) *//* , 'chatlist-' + (options.size || 72) */);\r\n\r\n /* if(options.handheldsSize) {\r\n list.classList.add('chatlist-handhelds-' + options.handheldsSize);\r\n } */\r\n\r\n return list;\r\n }\r\n\r\n private reorderDialogs() {\r\n //const perf = performance.now();\r\n if(this.reorderDialogsTimeout) {\r\n window.cancelAnimationFrame(this.reorderDialogsTimeout);\r\n }\r\n \r\n this.reorderDialogsTimeout = window.requestAnimationFrame(() => {\r\n this.reorderDialogsTimeout = 0;\r\n const offset = Math.max(0, this.getOffset('top').pos);\r\n \r\n const dialogs = appMessagesManager.dialogsStorage.getFolder(this.filterId);\r\n const currentOrder = (Array.from(this.chatList.children) as HTMLElement[]).map(el => +el.dataset.peerId);\r\n \r\n dialogs.forEach((dialog, index) => {\r\n const dom = this.getDialogDom(dialog.peerId);\r\n if(!dom) {\r\n return;\r\n }\r\n \r\n const needIndex = index - offset;\r\n if(needIndex > currentOrder.length) {\r\n dom.listEl.remove();\r\n delete this.doms[dialog.peerId];\r\n return;\r\n }\r\n\r\n const peerIdByIndex = currentOrder[needIndex];\r\n \r\n if(peerIdByIndex !== dialog.peerId) {\r\n if(positionElementByIndex(dom.listEl, this.chatList, needIndex)) {\r\n this.log.debug('setDialogPosition:', dialog, dom, peerIdByIndex, needIndex);\r\n }\r\n }\r\n });\r\n \r\n //this.log('Reorder time:', performance.now() - perf);\r\n });\r\n }\r\n\r\n public setLastMessage(dialog: Dialog, lastMessage?: any, dom?: DialogDom, highlightWord?: string) {\r\n ///////console.log('setlastMessage:', lastMessage);\r\n if(!dom) {\r\n dom = this.getDialogDom(dialog.peerId);\r\n\r\n if(!dom) {\r\n //this.log.error('no dom for dialog:', dialog, lastMessage, dom, highlightWord);\r\n return;\r\n }\r\n }\r\n\r\n let draftMessage: MyDraftMessage;\r\n if(!lastMessage) {\r\n if(dialog.draft && dialog.draft._ === 'draftMessage') {\r\n draftMessage = dialog.draft;\r\n }\r\n \r\n lastMessage = appMessagesManager.getMessageByPeer(dialog.peerId, dialog.top_message);\r\n }\r\n\r\n if(lastMessage._ === 'messageEmpty'/* || (lastMessage._ === 'messageService' && !lastMessage.rReply) */) {\r\n dom.lastMessageSpan.innerHTML = '';\r\n dom.lastTimeSpan.innerHTML = '';\r\n delete dom.listEl.dataset.mid;\r\n return;\r\n }\r\n\r\n let peer = dialog.peer;\r\n let peerId = dialog.peerId;\r\n //let peerId = appMessagesManager.getMessagePeer(lastMessage);\r\n\r\n //console.log('setting last message:', lastMessage);\r\n\r\n /* if(!dom.lastMessageSpan.classList.contains('user-typing')) */ {\r\n\r\n dom.lastMessageSpan.textContent = '';\r\n if(highlightWord && lastMessage.message) {\r\n dom.lastMessageSpan.append(appMessagesManager.wrapMessageForReply(lastMessage, undefined, undefined, false, highlightWord));\r\n } else if(draftMessage) {\r\n dom.lastMessageSpan.append(appMessagesManager.wrapMessageForReply(draftMessage));\r\n } else if(!lastMessage.deleted) {\r\n dom.lastMessageSpan.append(appMessagesManager.wrapMessageForReply(lastMessage));\r\n }\r\n \r\n /* if(lastMessage.from_id === auth.id) { // You: */\r\n if(draftMessage) {\r\n const bold = document.createElement('b');\r\n bold.classList.add('danger');\r\n bold.append(i18n('Draft'));\r\n bold.append(': ');\r\n dom.lastMessageSpan.prepend(bold);\r\n } else if(peer._ !== 'peerUser' && peerId !== lastMessage.fromId && !lastMessage.action) {\r\n const sender = appPeersManager.getPeer(lastMessage.fromId);\r\n if(sender && sender.id) {\r\n const senderBold = document.createElement('b');\r\n\r\n if(sender.id === rootScope.myId) {\r\n senderBold.append(i18n('FromYou'));\r\n } else {\r\n //str = sender.first_name || sender.last_name || sender.username;\r\n senderBold.append(new PeerTitle({\r\n peerId: lastMessage.fromId,\r\n onlyFirstName: true,\r\n }).element);\r\n }\r\n\r\n senderBold.append(': ');\r\n //console.log(sender, senderBold.innerText);\r\n dom.lastMessageSpan.prepend(senderBold);\r\n } //////// else console.log('no sender', lastMessage, peerId);\r\n }\r\n }\r\n\r\n if(!lastMessage.deleted || draftMessage/* && lastMessage._ !== 'draftMessage' */) {\r\n const date = draftMessage ? Math.max(draftMessage.date, lastMessage.date || 0) : lastMessage.date;\r\n dom.lastTimeSpan.textContent = '';\r\n dom.lastTimeSpan.append(formatDateAccordingToTodayNew(new Date(date * 1000)));\r\n } else dom.lastTimeSpan.textContent = '';\r\n\r\n if(this.doms[peerId] === dom) {\r\n this.setUnreadMessages(dialog);\r\n } else { // means search\r\n dom.listEl.dataset.mid = lastMessage.mid;\r\n }\r\n }\r\n\r\n private setUnreadMessages(dialog: Dialog) {\r\n const dom = this.getDialogDom(dialog.peerId);\r\n\r\n if(dialog.folder_id === 1) {\r\n this.accumulateArchivedUnread();\r\n }\r\n\r\n if(!dom) {\r\n //this.log.error('setUnreadMessages no dom!', dialog);\r\n return;\r\n }\r\n\r\n const isMuted = appNotificationsManager.isPeerLocalMuted(dialog.peerId, true);\r\n const wasMuted = dom.listEl.classList.contains('is-muted');\r\n if(isMuted !== wasMuted) {\r\n SetTransition(dom.listEl, 'is-muted', isMuted, 200);\r\n }\r\n\r\n const lastMessage = dialog.draft && dialog.draft._ === 'draftMessage' ? \r\n dialog.draft : \r\n appMessagesManager.getMessageByPeer(dialog.peerId, dialog.top_message);\r\n if(lastMessage._ !== 'messageEmpty' && !lastMessage.deleted && \r\n lastMessage.pFlags.out && lastMessage.peerId !== rootScope.myId/* && \r\n dialog.read_outbox_max_id */) { // maybe comment, 06.20.2020\r\n const outgoing = (lastMessage.pFlags && lastMessage.pFlags.unread)\r\n /* && dialog.read_outbox_max_id !== 0 */; // maybe uncomment, 31.01.2020\r\n \r\n //console.log('outgoing', outgoing, lastMessage);\r\n \r\n if(outgoing) {\r\n dom.statusSpan.classList.remove('tgico-checks');\r\n dom.statusSpan.classList.add('tgico-check');\r\n } else {\r\n dom.statusSpan.classList.remove('tgico-check');\r\n dom.statusSpan.classList.add('tgico-checks');\r\n }\r\n } else dom.statusSpan.classList.remove('tgico-check', 'tgico-checks');\r\n\r\n dom.unreadMessagesSpan.innerText = '';\r\n\r\n const filter = appMessagesManager.filtersStorage.filters[this.filterId];\r\n let isPinned: boolean;\r\n if(filter) {\r\n isPinned = filter.pinned_peers.findIndex(peerId => peerId === dialog.peerId) !== -1;\r\n } else {\r\n isPinned = !!dialog.pFlags.pinned;\r\n }\r\n\r\n if(isPinned) {\r\n dom.unreadMessagesSpan.classList.add('tgico-chatspinned', 'tgico');\r\n } else {\r\n dom.unreadMessagesSpan.classList.remove('tgico-chatspinned', 'tgico');\r\n }\r\n\r\n if(dialog.unread_count || dialog.pFlags.unread_mark) {\r\n //dom.unreadMessagesSpan.innerText = '' + (dialog.unread_count ? formatNumber(dialog.unread_count, 1) : ' ');\r\n dom.unreadMessagesSpan.innerText = '' + (dialog.unread_count || ' ');\r\n dom.unreadMessagesSpan.classList.add('unread');\r\n } else {\r\n dom.unreadMessagesSpan.classList.remove('unread');\r\n }\r\n }\r\n\r\n private accumulateArchivedUnread() {\r\n if(this.accumulateArchivedTimeout) return;\r\n this.accumulateArchivedTimeout = window.setTimeout(() => {\r\n this.accumulateArchivedTimeout = 0;\r\n const dialogs = appMessagesManager.dialogsStorage.getFolder(1);\r\n const sum = dialogs.reduce((acc, dialog) => acc + dialog.unread_count, 0);\r\n rootScope.broadcast('dialogs_archived_unread', {count: sum});\r\n }, 0);\r\n }\r\n\r\n private getDialogDom(peerId: number) {\r\n return this.doms[peerId];\r\n }\r\n\r\n public addDialogNew(options: {\r\n dialog: Dialog | number,\r\n container?: HTMLUListElement | Scrollable | false,\r\n drawStatus?: boolean,\r\n rippleEnabled?: boolean,\r\n onlyFirstName?: boolean,\r\n meAsSaved?: boolean,\r\n append?: boolean,\r\n avatarSize?: number,\r\n autonomous?: boolean\r\n }) {\r\n return this.addDialog(options.dialog, options.container, options.drawStatus, options.rippleEnabled, options.onlyFirstName, options.meAsSaved, options.append, options.avatarSize, options.autonomous);\r\n }\r\n\r\n public addDialog(_dialog: Dialog | number, container?: HTMLUListElement | Scrollable | false, drawStatus = true, rippleEnabled = true, onlyFirstName = false, meAsSaved = true, append = true, avatarSize = 54, autonomous = !!container) {\r\n let dialog: Dialog;\r\n \r\n if(typeof(_dialog) === 'number') {\r\n let originalDialog = appMessagesManager.getDialogByPeerId(_dialog)[0];\r\n if(!originalDialog) {\r\n originalDialog = {\r\n peerId: _dialog,\r\n peer: appPeersManager.getOutputPeer(_dialog),\r\n pFlags: {}\r\n } as any;\r\n }\r\n\r\n dialog = originalDialog;\r\n } else {\r\n dialog = _dialog;\r\n }\r\n\r\n const peerId: number = dialog.peerId;\r\n\r\n if(container === undefined) {\r\n if(this.doms[peerId]) return;\r\n\r\n const filter = appMessagesManager.filtersStorage.filters[this.filterId];\r\n if((filter && !appMessagesManager.filtersStorage.testDialogForFilter(dialog, filter)) || (!filter && this.filterId !== dialog.folder_id)) {\r\n return;\r\n }\r\n }\r\n\r\n const avatarEl = new AvatarElement();\r\n avatarEl.setAttribute('dialog', meAsSaved ? '1' : '0');\r\n avatarEl.setAttribute('peer', '' + peerId);\r\n avatarEl.classList.add('dialog-avatar', 'avatar-' + avatarSize);\r\n\r\n if(drawStatus && peerId !== rootScope.myId && dialog.peer) {\r\n const peer = dialog.peer;\r\n \r\n switch(peer._) {\r\n case 'peerUser':\r\n const user = appUsersManager.getUser(peerId);\r\n //console.log('found user', user);\r\n \r\n if(user.status && user.status._ === 'userStatusOnline') {\r\n avatarEl.classList.add('is-online');\r\n }\r\n \r\n break;\r\n default:\r\n break;\r\n }\r\n }\r\n\r\n const captionDiv = document.createElement('div');\r\n captionDiv.classList.add('user-caption');\r\n\r\n const titleSpanContainer = document.createElement('span');\r\n titleSpanContainer.classList.add('user-title');\r\n\r\n const peerTitle = new PeerTitle({\r\n peerId,\r\n dialog: meAsSaved,\r\n onlyFirstName,\r\n plainText: false\r\n });\r\n\r\n titleSpanContainer.append(peerTitle.element);\r\n //p.classList.add('')\r\n\r\n // в других случаях иконка верификации не нужна (а первый - это главные чатлисты)\r\n //if(!container) {\r\n const peer = appPeersManager.getPeer(peerId);\r\n\r\n // for muted icon\r\n titleSpanContainer.classList.add('tgico'); // * эта строка будет актуальна только для !container, но ладно\r\n\r\n if(peer?.pFlags?.verified) {\r\n titleSpanContainer.classList.add('is-verified');\r\n const i = document.createElement('i');\r\n i.classList.add('verified-icon');\r\n titleSpanContainer.append(i);\r\n }\r\n //}\r\n \r\n const span = document.createElement('span');\r\n span.classList.add('user-last-message');\r\n\r\n //captionDiv.append(titleSpan);\r\n //captionDiv.append(span);\r\n\r\n const li = document.createElement('li');\r\n if(rippleEnabled) {\r\n ripple(li);\r\n }\r\n\r\n li.append(avatarEl, captionDiv);\r\n li.dataset.peerId = '' + peerId;\r\n\r\n const statusSpan = document.createElement('span');\r\n statusSpan.classList.add('message-status');\r\n\r\n const lastTimeSpan = document.createElement('span');\r\n lastTimeSpan.classList.add('message-time');\r\n\r\n const unreadMessagesSpan = document.createElement('div');\r\n unreadMessagesSpan.className = 'dialog-subtitle-badge badge badge-24';\r\n\r\n const titleP = document.createElement('p');\r\n titleP.classList.add('dialog-title');\r\n\r\n const rightSpan = document.createElement('span');\r\n rightSpan.classList.add('dialog-title-details');\r\n rightSpan.append(statusSpan, lastTimeSpan);\r\n titleP.append(titleSpanContainer, rightSpan);\r\n\r\n const messageP = document.createElement('p');\r\n messageP.classList.add('dialog-subtitle');\r\n messageP.append(span, unreadMessagesSpan);\r\n\r\n captionDiv.append(titleP, messageP);\r\n\r\n const dom: DialogDom = {\r\n avatarEl,\r\n captionDiv,\r\n titleSpan: peerTitle.element,\r\n titleSpanContainer,\r\n statusSpan,\r\n lastTimeSpan,\r\n unreadMessagesSpan,\r\n lastMessageSpan: span,\r\n containerEl: li,\r\n listEl: li\r\n };\r\n\r\n /* let good = false;\r\n for(const folderId in this.chatLists) {\r\n if(this.chatLists[folderId] === container) {\r\n good = true;\r\n }\r\n } */\r\n const method: 'append' | 'prepend' = append ? 'append' : 'prepend';\r\n if(container === undefined/* || good */) {\r\n this.scroll[method](li);\r\n\r\n this.doms[dialog.peerId] = dom;\r\n\r\n /* if(container) {\r\n container.append(li);\r\n } */\r\n\r\n const isMuted = appNotificationsManager.isPeerLocalMuted(dialog.peerId, true);\r\n if(isMuted) {\r\n li.classList.add('is-muted');\r\n }\r\n\r\n this.setLastMessage(dialog);\r\n } else if(container) {\r\n container[method](li);\r\n }\r\n\r\n if(!autonomous && appImManager.chat?.peerId === peerId) {\r\n li.classList.add('active');\r\n this.lastActiveElements.add(li);\r\n } \r\n \r\n return {dom, dialog};\r\n }\r\n\r\n public setTyping(dialog: Dialog, user: User) {\r\n const dom = this.getDialogDom(dialog.peerId);\r\n if(!dom) {\r\n return;\r\n }\r\n\r\n let str = '';\r\n if(dialog.peerId < 0) {\r\n let s = user.rFirstName || user.username;\r\n if(!s) return;\r\n str = s + ' ';\r\n } \r\n\r\n const senderBold = document.createElement('i');\r\n str += 'typing...';\r\n senderBold.innerHTML = str;\r\n\r\n dom.lastMessageSpan.innerHTML = '';\r\n dom.lastMessageSpan.append(senderBold);\r\n dom.lastMessageSpan.classList.add('user-typing');\r\n }\r\n\r\n public unsetTyping(dialog: Dialog) {\r\n const dom = this.getDialogDom(dialog.peerId);\r\n if(!dom) {\r\n return;\r\n }\r\n\r\n dom.lastMessageSpan.classList.remove('user-typing');\r\n this.setLastMessage(dialog, null, dom);\r\n }\r\n}\r\n\r\nconst appDialogsManager = new AppDialogsManager();\r\nMOUNT_CLASS_TO.appDialogsManager = appDialogsManager;\r\nexport default appDialogsManager;\r\n"],"sourceRoot":""}