tweb/public/2.1e035baa608111b048ce.chunk.js.map
Eduard Kuzmenko 60a603b5de Build
2021-04-26 18:34:31 +04:00

1 line
909 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

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

{"version":3,"sources":["webpack:///./src/lib/langPack.ts","webpack:///./src/lib/mtproto/transports/websocket.ts","webpack:///./src/lib/mtproto/mtprotoworker.ts","webpack:///./src/lib/crypto/crypto_methods.ts","webpack:///./src/lib/appManagers/appUsersManager.ts","webpack:///./src/components/misc.ts","webpack:///./src/lib/storages/dialogs.ts","webpack:///./src/lib/storages/filters.ts","webpack:///./src/lib/appManagers/appMessagesManager.ts","webpack:///./src/lib/appManagers/appPeersManager.ts","webpack:///./src/lib/appManagers/appChatsManager.ts","webpack:///./src/helpers/date.ts","webpack:///./src/lib/appManagers/appProfileManager.ts","webpack:///./src/lib/appManagers/appPhotosManager.ts","webpack:///./src/lib/appManagers/appDocsManager.ts","webpack:///./src/components/peerTitle.ts","webpack:///./src/helpers/random.ts","webpack:///./src/components/appNavigationController.ts","webpack:///./src/helpers/array.ts","webpack:///./src/helpers/number.ts","webpack:///./src/lib/appManagers/apiUpdatesManager.ts","webpack:///./src/helpers/dom/renderImageFromUrl.ts","webpack:///./src/lib/appManagers/appDownloadManager.ts","webpack:///./src/components/visibilityIntersector.ts","webpack:///./src/components/lazyLoadQueue.ts","webpack:///./src/lib/appManagers/appNotificationsManager.ts","webpack:///./src/helpers/bytes.ts","webpack:///./src/components/preloader.ts","webpack:///./src/components/singleTransition.ts","webpack:///./src/lib/mtproto/serverTimeManager.ts","webpack:///./src/helpers/files.ts","webpack:///./src/lib/mtproto/referenceDatabase.ts","webpack:///./src/lib/searchIndexManager.ts","webpack:///./src/helpers/fileName.ts","webpack:///./src/lib/appManagers/appPollsManager.ts","webpack:///./src/lib/webp/webpWorkerController.ts","webpack:///./src/countries.ts","webpack:///./src/lib/mtproto/mtproto_config.ts","webpack:///./src/components/middleEllipsis.ts","webpack:///./src/vendor/leemon.ts","webpack:///./src/lib/appManagers/appDraftsManager.ts","webpack:///./src/lib/mtproto/bin_utils.ts","webpack:///./src/lib/filemanager.ts","webpack:///./src/lib/cacheStorage.ts","webpack:///./src/vendor/fastBlur.js","webpack:///./src/helpers/blur.ts","webpack:///./src/helpers/heavyQueue.ts","webpack:///./src/lib/opusDecodeController.ts","webpack:///./src/lib/appManagers/appWebPagesManager.ts","webpack:///./src/helpers/slicedArray.ts","webpack:///./src/lib/mtproto/mtproto.worker.ts","webpack:///./src/lib/webp/webp.worker.ts"],"names":["langPack","I18n","pluralRules","cacheLangPackPromise","loadLocalLangPack","defaultCode","langPackCode","lastRequestedLangCode","Promise","all","then","lang","langSign","strings","formatLocalStrings","default","saveLangPack","_","from_version","lang_code","version","local","loadLangPack","langCode","requestedServerLanguage","invokeApiCacheable","lang_pack","polyfillPromise","pushTo","i","v","push","key","value","getLangPack","_langPack","__langPack","___langPack","forEach","l","concat","string","appVersion","langPackVersion","set","applyLangPack","Intl","PluralRules","clear","broadcast","Array","from","document","querySelectorAll","element","instance","weakMap","get","update","superFormatter","input","args","indexHolder","out","lastIndex","replace","match","p1","p2","p3","offset","slice","b","createElement","append","length","format","plain","str","select","regExp","Map","getCacheLangPack","finally","undefined","getStrings","invokeApi","keys","resolve","_Intl","window","Object","assign","WeakMap","IntlElementBase","options","property","this","classList","add","IntlElement","textContent","formatted","dataset","IntlDateElement","dateTimeFormat","DateTimeFormat","date","i18n","i18n_","_i18n","join","elements","useLast","arr","delimiterKey","dcId","url","logSuffix","super","debug","handleOpen","log","dispatchEvent","handleError","e","error","close","handleClose","removeListeners","handleMessage","event","data","byteLength","send","body","ws","logLevel","logger","connect","removeEventListener","WebSocket","binaryType","addEventListener","err","apiManagerProxy","bytes","performTaskWorker","buffer","salt","iterations","keyBytes","ivBytes","encryptedBytes","publicKey","x","y","m","toString","password","state","isNew","afterMessageIdTemp","taskId","awaiting","pending","updatesProcessor","hashes","apiPromisesSingle","apiPromisesCacheable","isSWRegistered","sockets","onWorkerMessage","task","progress","rootScope","type","location","reload","payload","webpWorkerController","postMessage","_task","onError","originalPayload","file_reference","referenceDatabase","refreshReference","getReferenceByLink","newTask","id","catch","navigator","serviceWorker","controller","socketTask","socket","onOpen","onClose","onMessage","delete","hasOwnProperty","finalizeTask","result","registerServiceWorker","registerWorker","worker","register","scope","registration","installing","waiting","active","appDocsManager","onServiceWorkerFail","warn","releasePending","bind","isWebpSupported","onWorkerFirstMessage","once","deferred","taskName","reject","params","callback","method","o","prepareTempMessageId","messageId","queryJSON","JSON","stringify","cached","hash","includes","q","cache","item","override","fulfilled","promise","timeout","clearTimeout","cacheSeconds","setTimeout","timestamp","Date","now","verify","queueId","userAuth","dc_id","fileName","enabled","appUsersManager","users","usernames","contactsIndex","createIndex","contactsList","Set","updatedContactsList","updateUsersStatuses","timestampNow","user","status","expires","was_online","setInterval","on","addMultipleEventsListeners","updateUserStatus","userId","user_id","serverTimeOffset","updateUserPhoto","forceUserOnline","photo","console","updateUserName","saveApiUser","first_name","last_name","username","getSelf","indexObject","getUserSearchText","getState","isArray","pushContact","size","contactsFillPromise","setPeer","getUser","pushToState","saveApiUsers","contacts","contact","toLowerCase","resolvedPeer","saveApiChats","chats","getPeer","getPeerId","peer","phone","pFlags","self","filter","Boolean","query","includeSaved","fillContacts","_contactsList","results","search","sort","userId1","userId2","sortName1","sortName","sortName2","localeCompare","testSelfSearch","findAndSplice","p","myId","unshift","peerId","block","getInputPeerById","processUpdateMessage","peer_id","getOutputPeer","blocked","index","apiUsers","oldUser","min","fullName","searchUsername","cleanUsername","deleted","cleanSearchText","initials","getAbbreviation","changedTitle","access_hash","isBot","support","d","getDate","getMonth","getHours","getMinutes","bot","has","isRegularUser","isContact","allowMin","eventTimestamp","updatesState","syncLoading","getTopPeersPromise","topPeers","correspondents","limit","peerIds","categories","peers","map","topPeer","contactsBlocked","count","u","c","my_results","offline","showPhone","getUserInput","add_phone_privacy_exception","updates","onContactUpdated","userIds","putPreloader","elem","returnDiv","html","div","innerHTML","appendChild","insertAdjacentHTML","lastElementChild","setButtonLoader","icon","remove","disabled","removeAttribute","sortedCountries","formatPhoneNumber","phoneCode","a","country","find","split","indexOf","pattern","symbol","idx","onMouseMove","rect","openedMenu","getBoundingClientRect","clientX","clientY","diffX","right","left","diffY","bottom","top","closeBtnMenu","onClick","parentElement","menuOverlay","openedMenuOnClose","removeByType","openBtnMenu","menuElement","pushItem","onPop","canAnimate","insertBefore","positionMenu","pageX","pageY","side","scrollWidth","menuWidth","scrollHeight","menuHeight","windowWidth","width","windowHeight","height","isMobile","verticalSide","sides","intermediateX","intermediateY","possibleSides","style","className","attachContextMenuListener","listenerSetter","removeManual","capture","onCancel","touches","appMessagesManager","appChatsManager","appPeersManager","serverTimeManager","dialogs","byFolders","dialogsIndex","searchIndexManager","reset","allDialogsLoaded","dialogsOffsetDate","pinnedOrders","0","1","dialogsNum","folderId","filtersStorage","filters","dialog","testDialogForFilter","pinnedIndex","pinned_peers","generateDialogIndex","generateDialogPinnedDateByIndex","pinned","generateIndexForDialog","folders","getFolder","folder","findIndex","justReturn","message","channelId","isChannel","topDate","generateDialogPinnedDate","getMessageByPeer","top_message","channel","getChat","draft","order","folder_id","foundIndex","offsetDate","pos","splice","foundDialog","getDialog","appNotificationsManager","apiUpdatesManager","orderIndex","onUpdateDialogFilter","saveDialogFilter","onUpdateDialogFilterOrder","filterId","setOrderIndex","updateDialogFilter","updateDialogFilters","oldFilters","getDialogFilters","_filterId","updateDialogFilterOrder","exclude_peers","include_peers","exclude_archived","exclude_read","unread_count","exclude_muted","isPeerLocalMuted","broadcasts","isBroadcast","groups","isAnyGroup","bots","non_contacts","maxId","Math","max","flags","getOutputDialogFilter","bool","overwrite","messagesStorageByPeerId","groupedMessagesStorage","scheduledMessagesStorage","historiesStorage","threadsStorage","searchesStorage","pinnedMessages","threadsServiceMessagesIdsStorage","threadsToReplies","pendingByRandomId","pendingByMessageId","pendingAfterMsgs","pendingTopMsgs","sendFilePromise","tempNum","tempFinalizeCallbacks","sendSmthLazyLoadQueue","needSingleMessages","fetchSingleMessagesPromise","maxSeenId","migratedFromTo","migratedToFrom","newMessagesHandlePromise","newMessagesToHandle","newDialogsHandlePromise","newDialogsToHandle","newUpdatesAfterReloadToHandle","notificationsHandlePromise","notificationsToHandle","reloadConversationsPeers","cachedResults","groupedTempId","saveState","messages","items","dialogsStorage","process","historyStorage","getHistoryStorage","history","removeUnread","mid","is_outgoing","fromId","appStateManager","unread","pts","newPts","channelStates","context","handleNewMessages","handleNewDialogs","newMaxSeenId","reloadConversation","pushDialog","incrementMaxSeenId","handleNotifications","_peerId","idle","isIDLE","notifyPeerToHandle","getNotifyPeerTypeSettings","getNotifySettings","getInputNotifyPeerById","peerTypeNotifySettings","topMessage","notifyAboutMessage","fwdCount","onUpdateMessageId","randomId","random_id","pendingData","tempId","threadId","storage","generateMessageId","getMessageFromStorage","finalizePendingMessageCallbacks","onUpdateNewMessage","getMessagePeer","getMessagesStorage","getDialogByPeerId","isLocalThreadUpdate","saveMessages","threadKey","getThreadKey","good","chat","kicked","deactivated","scheduleHandleNewDialogs","pendingMessage","checkPendingMessage","updateMessageRepliesIfNeeded","findSlice","topMsgId","mergeReplyKeyboard","from_id","inboxUnread","setDialogTopMessage","notifyPeer","fwd_from","onUpdateDialogUnreadMark","unread_mark","onUpdateFolderPeers","folder_peers","folderPeer","dropped","dropDialog","onUpdateDialogPinned","onUpdatePinnedDialogs","handleOrder","willHandle","reverse","newPinned","dialogsResult","applyConversations","onUpdateEditMessage","oldMessage","newMessage","handleEditedMessage","isTopMessage","clear_history","grouped_id","updatedDialogs","onUpdateReadHistory","channel_id","max_id","read_max_id","top_msg_id","isOut","stillUnreadCount","still_unread_count","newUnreadCount","foundAffected","repliesKey","n","updateMessage","replyTo","reply_to","reply_to_top_id","reply_to_msg_id","cancel","readOutboxMaxId","readMaxId","read_outbox_max_id","read_inbox_max_id","getReadMaxIdIfUnread","threadKeyPart","onUpdateReadMessagesContents","mids","getMessageById","media_unread","onUpdateChannelAvailableMessages","msgId","available_min_id","onUpdateDeleteMessages","clearCache","threadKeys","historyUpdated","handleDeletedMessages","threadsStorages","splitted","msgs","onUpdateChannel","needDialog","hasDialog","onUpdateChannelReload","onUpdateChannelMessageViews","views","onUpdateServiceNotification","generateTempMessageId","inbox_date","media","entities","hasUser","verified","isOutgoing","onUpdatePinnedMessages","missingMessages","wrapSingleMessage","werePinned","hiddenPinnedMessages","onUpdateNotifySettings","notify_settings","onUpdateNewScheduledMessage","isScheduled","onUpdateDeleteScheduledMessages","updateMessageID","updateNewDiscussionMessage","updateNewMessage","updateNewChannelMessage","updateDialogUnreadMark","updateFolderPeers","updateDialogPinned","updatePinnedDialogs","updateEditMessage","updateEditChannelMessage","updateReadChannelDiscussionInbox","updateReadChannelDiscussionOutbox","updateReadHistoryInbox","updateReadHistoryOutbox","updateReadChannelInbox","updateReadChannelOutbox","updateChannelReadMessagesContents","updateReadMessagesContents","updateChannelAvailableMessages","updateDeleteMessages","updateDeleteChannelMessages","updateChannel","updateChannelReload","updateChannelMessageViews","updateServiceNotification","updatePinnedMessages","updatePinnedChannelMessages","updateNotifySettings","updateNewScheduledMessage","updateDeleteScheduledMessages","settings","getConversationsAll","filterFunc","peerText","getPeerSearchText","eventData","webpage","appWebPagesManager","getWebPage","maxSeenMsgId","getServerMessageId","saveConversation","start","sendEntites","entity","callbackName","finalize","obj","text","invokeAfterMessageIsSent","editMessage","parseMarkdown","schedule_date","scheduleDate","is_scheduled","newMedia","getInputEntities","no_webpage","noWebPage","handled","replyToMsgId","webPage","sendText","getPeerMigratedTo","viaBotId","generateOutgoingMessage","toggleError","sentRequestOptions","apiPromise","afterMessageId","invokeApiAfter","query_id","queryId","resultId","clear_draft","clearDraft","silent","seq","pts_count","beforeMessageSending","file","attachType","apiFileName","fileType","mime_type","File","name","isDocument","Blob","caption","attributes","isPhoto","actionName","isVoiceMessage","attribute","voice","waveform","duration","isMedia","sizes","w","h","downloaded","objectURL","appPhotosManager","savePhoto","videoAttribute","round_message","isRoundMessage","file_name","thumbs","thumbURL","thumbBlob","thumb","docThumb","getDocumentCachedThumb","saveDoc","preloader","attachMethod","tryAgainOnFail","isUpload","sentDeferred","attachPromise","Error","uploaded","cancelPendingMessage","setTyping","uploadPromise","inputMedia","load","thumbUploadPromise","appDownloadManager","upload","notifyAll","done","total","blob","inputFile","addNotifyListener","percents","floor","isGroupedItem","background","code","files","sendFile","sendFileDetails","groupId","details","appDraftsManager","syncDraft","saveDraft","notify","inputPeer","invoke","multiMedia","multi_media","promises","messageMedia","getInput","doc","getMediaInput","inputSingleMedia","inputs","poll","appPollsManager","savePoll","total_voters","getPoll","getScheduledMessagesStorage","generateFromId","generateFlags","random","generateReplyHeader","via_bot_id","reply_markup","replies","generateReplies","replyToTopId","header","channelFull","appProfileManager","chatsFull","linked_chat_id","comments","replies_pts","admin_rights","anonymous","post","originalMessage","fwdHeader","from_name","post_author","channel_post","saved_from_msg_id","saved_from_peer","Number","MAX_SAFE_INTEGER","action","outDialogs","getTopMessages","offsetIndex","getConversations","realFolderId","curDialogStorage","d1","d2","isEnd","messagesDialogs","chatHistoryStorage","getOffsetDate","offset_date","offset_id","offset_peer","noErrorBox","maxSeenIdIncremented","hasPrepend","noIdsDialogs","fromPeerId","newMessages","generateForwardHeader","group","from_peer","to_peer","with_my_score","withMyScore","createMessageStorage","reloadConversationsPromise","getInputDialogPeerById","justClear","revoke","just_clear","affectedHistory","doFlushHistory","getHistory","historyResult","getChannelInput","getPinnedMessage","getSearch","inputFilter","unpin","oneSide","pm_oneside","unpinAll","unpinAllMessages","totalEntities","foundMessages","getMidsByAlbum","temp","MESSAGE_ID_OFFSET","num","MESSAGE_ID_INCREMENT","used","increment","reply_to_mid","overwriting","savedFromPeerId","savedFromMid","savedFrom","fwdFromId","mediaContext","ttl_seconds","saveWebPage","migrateFrom","migrateTo","video_sizes","suffix","chat_id","reason","migrateChecks","myEntities","parseEntities","apiEntities","mergeEntities","usingMids","highlightWord","parts","addPart","langKey","part","el","usingFullAlbum","getMidsByMessage","getAlbumText","emoticon","wrapEmojiText","title","question","rReply","prefix","game","stickerEmojiRaw","stickerEmoji","actionWrapped","wrapMessageActionTextNew","found","RegExp","exec","messageWrapped","wrapRichText","noLinebreaks","noLinks","noTextFormat","fragment","createDocumentFragment","peerTitle","senderTitle","getPeerTitle","wrapPlainText","langPackKey","getNameDivHTML","trim","anchorHTML","domain","node","toggleDialogPin","getDialogPeer","read","hasChat","fromChat","migrated_to","kind","goodMedias","sticker","canMessageBeEdited","hasRights","topPendingMessage","saveUpdate","unread_mentions_count","migratedToPeer","wasDialogBefore","savePeerSettings","addChannelState","messageReplyMarkup","lastReplyMarkup","selective","maxOutId","single_use","hidden","canCache","func","nextRate","backLimit","minDate","maxDate","foundMsgs","filtering","neededContents","neededDocTypes","excludeDocTypes","goodEntities","matchUrl","next_rate","offset_id_offset","min_date","max_date","add_offset","min_id","offsetPeerId","offsetId","offsetMessage","offset_rate","searchResult","foundCount","getDiscussionMessage","maxMessageId","serviceStartMessage","is_single","msg_id","filterMessages","generateThreadServiceStartMessage","localMessageIds","creator","editor","megagroup","goodMsgIds","affectedMessages","force","triedToReadMaxId","readPromise","soundReset","getPeerString","readHistory","msgIds","threadMessage","broadcastEventName","finalizePendingMessage","mute","mute_until","canSendToUser","finalMessage","callbacks","getPhoto","newPhoto","photoSize","downloadOptions","getPhotoDownloadOptions","fakeDownload","getDoc","newDoc","getInputFileName","polls","tempMessage","notification","peerString","notificationMessage","show_previews","wrapMessageForReply","onclick","tag","peerPhoto","getPeerPhoto","loadAvatar","loadPromise","image","canWriteToPeer","haveSlice","sliceMe","Both","offsetIdOffset","fillHistoryStorage","constructSlice","requestHistory","isTopEnd","insertSlice","last","setEnd","Top","_historyResult","getMessagesResult","fetchSingleMessages","_action","smth","deleteContext","deleteWebPageFromPending","groupedStorage","albums","peerMessagesToHandle","deletedMids","DialogColorsFg","DialogColors","DialogColorsMap","updatePeerBlocked","getUserPhoto","getChatPhoto","plainText","onlyFirstName","chatId","getUserString","getChatString","isUser","charAt","peerParams","substr","isMegagroup","ignorePeerId","getChannelInputPeer","getChatInputPeer","pic","getDialogType","megagroupOnlines","typingsInPeer","onUpdateUserTyping","typings","typing","t","cancelAction","getChatFull","onChatUpdated","invalidateChannelParticipants","updateChannelParticipant","updateChatDefaultBannedRights","default_banned_rights","updateUserTyping","updateChatUserTyping","updateChannelUserTyping","apiChats","saveApiChat","oldChat","participants_count","changedPhoto","oldPhoto","photo_small","rights","defaultRights","banned_rights","myFlags","post_messages","delete_messages","until_date","chatFull","participants","about","usersInputs","onlines","res","_participants","reduce","acc","participant","fwdLimit","fwd_limit","flushHistory","deleteChatUser","leaveChannel","leaveChat","deleteChannel","deleteChat","inputChatPhoto","prev_participant","new_participant","kicked_by","editBanned","view_messages","months","days","ONE_DAY","getWeekNumber","UTC","getFullYear","dayNum","getUTCDay","setUTCDate","getUTCDate","yearStart","getUTCFullYear","ceil","getTime","formatDateAccordingToToday","time","timeStr","getDay","formatDateAccordingToTodayNew","today","hour","minute","year","day","month","weekday","getFullDate","joiner","monthAsNumber","noSeconds","getSeconds","leadingZero","noTime","tsNow","seconds","yearPattern","monthYearOrDayPattern","yearOrDayAndMonthPattern","shortDate","longDate","numberOfDaysEachMonth","fillTipDates","dates","setFullYear","setHours","dayOfWeek","setDate","formatWeekLong","getDayOfWeek","distance","setTime","matches","g1","g2","k","createForDayMonth","createForMonthYear","selectedYear","currentYear","g3","parseInt","validDateForMonth","formatterYearMax","k1","setMonth","formatterMonthYear","formatterDayMonth","AppProfileManager","botInfos","usersFull","fullPromises","savedAvatarURLs","updateChatParticipants","updateChatParticipantAdd","inviter_id","updateChatParticipantDelete","fullChat","emptyPhoto","chat_photo","smallUserpic","smallPhotoSize","choosePhotoSize","botInfo","botId","commands","botCommand","command","description","shareText","share_text","userFull","profile_photo","rAbout","bot_info","saveBotInfo","getProfile","getProfileByPeerId","profile","getChannelFull","full_chat","exported_invite","link","exportedInvite","invokeApiSingle","channelParticipant","fullChannel","updateResult","previous","getAvatarPromise","saved","peerPhotoFileLocation","volume_id","local_id","big","download","URL","createObjectURL","img","Image","color","animate","animationsEnabled","childElementCount","mutateElement","isDialog","avatarAvailable","avatarRendered","firstElementChild","innerText","getPeerColorById","abbr","putAvatar","AppPhotosManager","photos","documentThumbsCache","windowW","windowH","visualViewport","innerWidth","innerHeight","saveContext","useBytes","devicePixelRatio","bestPhotoSize","inputUser","photosResult","photoIds","isSticker","mimeType","Uint8Array","jf","Df","path","getPreviewURLFromBytes","useBlur","getPreviewURLFromThumb","boxWidth","boxHeight","noZoom","hasText","SVGForeignObjectElement","setAttributeNS","getCacheContext","getImageFromStrippedThumb","onlyCache","isMyDocument","thumb_size","isDownloaded","cachedThumb","photoId","fullWidth","fullHeight","cacheContext","getDownload","docId","fullPhotoSize","downloadToDisc","docs","savingLottiePreview","supportsStreaming","oldDoc","audioTitle","audioPerformer","performer","alt","stickerset","stickerSetInput","animated","isServiceWorkerOnline","getFileURL","thumbSize","inputFileLocation","getFileDownloadOptions","preloadPhoto","tryNotToUseBytes","getThumbURL","originalPromise","isPlaySupported","reader","FileReader","onloadend","uint8","target","decode","readAsArrayBuffer","canvas","toneIndex","stickerCachedThumbs","toBlob","downloadDoc","createDownloadAnchor","peerTitleWeakMap","PeerTitle","nextRandomInt","maxValue","randomLong","appNavigationController","navigations","manual","currentHash","isPossibleSwipe","onHashChange","replaceState","pushState","pop","handleItem","onEscape","back","passive","detach","onTouchEnd","onTouchMove","moved","scrollRestoration","ret","findItemByType","noHistory","origin","pathname","single","accumulate","initialValue","findAndSpliceAll","array","forEachReverse","insertInDescendSortedArray","sortProperty","len","numberThousandSplitter","formatBytes","decimals","dm","parseFloat","pow","toFixed","formatNumber","clamp","pendingPtsUpdates","pendingSeqUpdates","syncPending","attached","processOpts","seqStart","seq_start","forceGetDifference","processUpdate","toId","nextSeq","pendingUpdatesData","popPendingSeqUpdate","seqAwaiting","ptsAwaiting","curState","getChannelState","curPts","goodPts","goodIndex","getDifference","first","wasSyncing","qts","differenceResult","other_updates","new_messages","apiMessage","nextState","intermediate_state","justAName","channelState","getChannelDifference","lastPtsUpdateTime","toPeerId","popPts","popSeq","popPendingPtsUpdate","_state","stateResult","setUpdatesProcessor","us","loadedURLs","HTMLImageElement","HTMLVideoElement","src","SVGImageElement","backgroundImage","renderImageFromUrl","useCache","isImage","loader","cacheStorage","downloads","progressCallbacks","uploadId","cancelDownload","clearDownload","getNewDeferred","fetch","response","tryDownload","getFile","downloadFile","ext","uploadFile","onRemove","href","position","clickEvent","createEvent","initMouseEvent","click","open","discFileName","revokeObjectURL","VisibilityIntersector","onVisibilityChange","locked","observer","IntersectionObserver","entries","changed","entry","isIntersecting","visible","getVisible","disconnect","targets","observe","unobserve","unlock","refresh","parallelLimit","queue","inProcess","lockPromise","unlockResolve","processQueue","_processQueue","loadItem","shift","getItem","processItem","addElement","lock","intersector","unlockAndRefresh","intersectorTimeout","wasSeen","setProcessQueueTimeout","_queue","spliced","notificationsShown","notificationIndex","notificationsCount","soundsPlayed","vibrateSupport","vibrate","peerSettings","notifyUsers","notifyChats","notifyBroadcasts","faviconEl","head","querySelector","titleBackup","titleChanged","stopped","pushInited","updateLocalSettings","updSettings","nodesktop","volume","novibrate","nopreview","nopush","nosound","notifications","sound","requestPermission","Notification","mozVibrate","webkitVibrate","notificationsUiSupport","topMessagesDeferred","notifySoundEl","newVal","toggleToggler","enable","resetTitle","setFavicon","clearInterval","titleInterval","ctx","getContext","beginPath","arc","PI","fillStyle","fill","fontSize","font","textBaseline","textAlign","fillText","toDataURL","getNotifyPeerTypePromise","inputKey","compare_sound","notifyContactsSignUp","prevFavicon","cloneNode","parentNode","replaceChild","peerNotifySettings","isMuted","respectType","notifySettings","inputNotify","typeNotifySettings","getPeerLocalSettings","permission","testSound","onclose","show","hide","nextSoundAt","prevSoundVolume","filename","audio","autoplay","setAttribute","tokenData","registeredDevice","token_type","tokenType","token","tokenValue","other_uids","app_sandbox","secret","bytesToHex","bytesFromHex","hexString","bytesToBase64","mod3","nLen","nUint24","nIdx","String","fromCharCode","uint6ToBase64","nUint6","bytesCmp","bytes1","bytes2","convertToArrayBuffer","ArrayBuffer","BYTES_PER_ELEMENT","bufferConcats","tmp","lastLength","ProgressivePreloader","detached","cancelable","streamable","contains","loadFunc","bold","constructContainer","construct","downloadSvg","cancelSvg","previousElementSibling","circle","setProgress","startTime","onEnd","elapsedTime","delay","TRANSITION_TIME","setManual","totalLength","getTotalLength","strokeDasharray","forwards","onTransitionEnd","afterTimeout","toggle","midnightNoOffset","midnightOffseted","midnightOffset","timeParams","to","createPosterFromVideo","video","onseeked","videoWidth","videoHeight","drawImage","onerror","currentTime","createPosterForVideo","onloadedmetadata","preloadVideo","race","onVideoLoad","readyState","HAVE_METADATA","getFilesFromEvent","onlyTypes","scanFiles","isDirectory","directoryReader","createReader","readEntries","itemFile","getAsFile","DataTransferItem","DragEvent","dataTransfer","clipboardData","originalEvent","webkitGetAsEntry","requestFile","accept","display","contexts","links","reference","getContexts","_context","values","next","SearchIndexManager","fullTexts","latinize","hasTag","ch","latinizeCh","LatinizeMap","searchText","searchIndex","newFoundObjs","queryWords","fullText","word","badCharsRe","trimRe","getFileNameByLocation","thumbPart","encodeURIComponent","updateMessagePoll","poll_id","saveResults","rQuestion","chosenIndexes","answer","chosen","pollId","correctAnswers","solution","solutionEntities","correct_answers","solution_entities","optionIds","answers","option","sendVote","votesList","closed","newPoll","getInputMediaPoll","convertPromises","init","isWebpSupportedCache","startsWith","convertPromise","Countries","PhoneCodesMain","REPLIES_PEER_ID","testQueue","fontFamily","timeoutId","setTestQueue","cancelAnimationFrame","requestAnimationFrame","testQueueElements","testElement","mapped","firstTime","textLength","multiplier","textWidth","elementWidth","fontWeight","getTextWidth","newElementWidth","widthChanged","smallerText","smallerWidth","smallerTextLength","half","half1","half2","measureText","MiddleEllipsisElement","HTMLElement","customElements","define","bpe","mask","int2bigInt","bits","minSize","buff","copyInt_","drafts","getAllDraftPromise","updateDraftMessage","peerID","getKey","getAllDrafts","apiDraft","processApiDraft","draft1","draft2","object","isObject","rMessage","wrapDraftText","localDraft","saveOnServer","serverDraft","getDraft","draftsAreEqual","draftObj","isEmptyDraft","saveLocalDraft","blobSupported","fileWriter","fileReader","onload","arrayBuffer","write","saveFileCallback","blobParts","truncate","saveToStorage","dbName","useStorage","test","openDatabase","STORAGES","openDbPromise","caches","entryName","timeoutOperation","put","save","Response","rejected","fakeWriter","getFakeFileWriter","saveFile","deleteAll","mul_table","shg_table","DEBUG","processBlur","dataUri","radius","perf","performance","top_x","top_y","isNaN","imageData","getImageData","pixels","rsum","gsum","bsum","yp","yi","yw","wm","hm","rad1","r","g","mul_sum","shg_sum","vmin","vmax","putImageData","blurPromises","heavyQueue","processingQueue","pushHeavyTask","processHeavyQueue","todo","f","possiblePromise","apply","realResult","timedChunk","opusDecodeController","sampleRate","tasks","keepAlive","isPlaySupportedResult","canPlayType","wavWorker","Worker","page","onTaskEnd","buffers","typedArray","loadWorker","loadWavWorker","terminateWorkers","executeNewTask","kill","terminate","decoderSampleRate","outputBufferSampleRate","wavBitDepth","wavSampleRate","pages","withWaveform","pushDecodeTask","dataBlob","webpages","pendingWebPages","updateWebPage","apiWebPage","siteName","site_name","shortTitle","author","rTitle","contextHashtag","shortDescriptionText","rDescription","contextSite","SliceEnd","SlicedArray","sliceConstructor","end","None","slicedArray","Bottom","slices","lowerBound","upperBound","foundSlice","lowerIndex","upperIndex","sliced","insertIndex","s","flatten","prevSlice","nextSlice","sliceOffset","findSliceOffset","sliceStart","sliceEnd","topWasMeantToLoad","bottomWasMeantToLoad","abs","topFulfilled","bottomFulfilled","module","exports"],"mappings":"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IAAK,IAAK,IAAK,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,GAAI,IAAK,IAAK,IAAK,GAAI,GAAI,IAAK,IAAK,IAAK,GAAI,IAAK,IAAK,GAAI,IAAK,IAAK,IAAK,IAAK,GAAI,IAAK,IAAK,IAAK,IAAK,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAI,IAAK,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAI,GAAI,IAAK,IAAK,GAAI,IAAK,IAAK,EAAG,GAAI,IAAK,GAAI,IAAK,IAAK,GAAI,GAAI,IAAK,GAAI,IAAK,GAAI,IAAK,IAAK,GAAI,IAAK,IAAK,IAAK,IAAK,GAAI,IAAK,IAAK,IAAK,GAAI,IAAK,GAAI,IAAK,GAE5qCC,EAAY,CAAC,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GA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","file":"2.1e035baa608111b048ce.chunk.js","sourcesContent":["/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport DEBUG, { MOUNT_CLASS_TO } from \"../config/debug\";\r\nimport { safeAssign } from \"../helpers/object\";\r\nimport { capitalizeFirstLetter } from \"../helpers/string\";\r\nimport type lang from \"../lang\";\r\nimport type langSign from \"../langSign\";\r\nimport { LangPackDifference, LangPackString } from \"../layer\";\r\nimport apiManager from \"./mtproto/mtprotoworker\";\r\nimport sessionStorage from \"./sessionStorage\";\r\nimport App from \"../config/app\";\r\nimport rootScope from \"./rootScope\";\r\n\r\nexport const langPack: {[actionType: string]: LangPackKey} = {\r\n \"messageActionChatCreate\": \"ActionCreateGroup\",\r\n\t\"messageActionChatEditTitle\": \"ActionChangedTitle\",\r\n\t\"messageActionChatEditPhoto\": \"ActionChangedPhoto\",\r\n\t\"messageActionChatEditVideo\": \"ActionChangedVideo\",\r\n\t\"messageActionChatDeletePhoto\": \"ActionRemovedPhoto\",\r\n\t\"messageActionChatReturn\": \"ActionAddUserSelf\",\r\n\t\"messageActionChatReturnYou\": \"ActionAddUserSelfYou\",\r\n\t\"messageActionChatJoined\": \"ActionAddUserSelfMega\",\r\n\t\"messageActionChatJoinedYou\": \"ChannelMegaJoined\",\r\n \"messageActionChatAddUser\": \"ActionAddUser\",\r\n \"messageActionChatAddUsers\": \"ActionAddUser\",\r\n\t\"messageActionChatLeave\": \"ActionLeftUser\",\r\n\t\"messageActionChatDeleteUser\": \"ActionKickUser\",\r\n\t\"messageActionChatJoinedByLink\": \"ActionInviteUser\",\r\n \"messageActionPinMessage\": \"ActionPinnedNoText\",\r\n \"messageActionContactSignUp\": \"Chat.Service.PeerJoinedTelegram\",\r\n\t\"messageActionChannelCreate\": \"ActionCreateChannel\",\r\n\t\"messageActionChannelEditTitle\": \"Chat.Service.Channel.UpdatedTitle\",\r\n\t\"messageActionChannelEditPhoto\": \"Chat.Service.Channel.UpdatedPhoto\",\r\n\t\"messageActionChannelEditVideo\": \"Chat.Service.Channel.UpdatedVideo\",\r\n \"messageActionChannelDeletePhoto\": \"Chat.Service.Channel.RemovedPhoto\",\r\n \"messageActionHistoryClear\": \"HistoryCleared\",\r\n\r\n \"messageActionChannelMigrateFrom\": \"ActionMigrateFromGroup\",\r\n\r\n \"messageActionPhoneCall.in_ok\": \"ChatList.Service.Call.incoming\",\r\n\t\"messageActionPhoneCall.out_ok\": \"ChatList.Service.Call.outgoing\",\r\n\t\"messageActionPhoneCall.in_missed\": \"ChatList.Service.Call.Missed\",\r\n\t\"messageActionPhoneCall.out_missed\": \"ChatList.Service.Call.Cancelled\",\r\n\r\n\t\"messageActionBotAllowed\": \"Chat.Service.BotPermissionAllowed\"\r\n};\r\n\r\nexport type LangPackKey = /* string | */keyof typeof lang | keyof typeof langSign;\r\n\r\nnamespace I18n {\r\n\texport const strings: Map<LangPackKey, LangPackString> = new Map();\r\n\tlet pluralRules: Intl.PluralRules;\r\n\r\n\tlet cacheLangPackPromise: Promise<LangPackDifference>;\r\n\texport let lastRequestedLangCode: string;\r\n\texport let requestedServerLanguage = false;\r\n\texport function getCacheLangPack(): Promise<LangPackDifference> {\r\n\t\tif(cacheLangPackPromise) return cacheLangPackPromise;\r\n\t\treturn cacheLangPackPromise = Promise.all([\r\n\t\t\tsessionStorage.get('langPack') as Promise<LangPackDifference>,\r\n\t\t\tpolyfillPromise\r\n\t\t]).then(([langPack]) => {\r\n\t\t\tif(!langPack/* || true */) {\r\n\t\t\t\treturn loadLocalLangPack();\r\n\t\t\t} else if(DEBUG && false) {\r\n\t\t\t\treturn getLangPack(langPack.lang_code);\r\n\t\t\t}/* else if(langPack.appVersion !== App.langPackVersion) {\r\n\t\t\t\treturn getLangPack(langPack.lang_code);\r\n\t\t\t} */\r\n\t\t\t\r\n\t\t\tif(!lastRequestedLangCode) {\r\n\t\t\t\tlastRequestedLangCode = langPack.lang_code;\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tapplyLangPack(langPack);\r\n\t\t\treturn langPack;\r\n\t\t}).finally(() => {\r\n\t\t\tcacheLangPackPromise = undefined;\r\n\t\t});\r\n\t}\r\n\r\n\texport function loadLocalLangPack() {\r\n\t\tconst defaultCode = App.langPackCode;\r\n\t\tlastRequestedLangCode = defaultCode;\r\n\t\treturn Promise.all([\r\n\t\t\timport('../lang'),\r\n\t\t\timport('../langSign')\r\n\t\t]).then(([lang, langSign]) => {\r\n\t\t\tconst strings: LangPackString[] = [];\r\n\t\t\tformatLocalStrings(lang.default, strings);\r\n\t\t\tformatLocalStrings(langSign.default, strings);\r\n\r\n\t\t\tconst langPack: LangPackDifference = {\r\n\t\t\t\t_: 'langPackDifference',\r\n\t\t\t\tfrom_version: 0,\r\n\t\t\t\tlang_code: defaultCode,\r\n\t\t\t\tstrings,\r\n\t\t\t\tversion: 0,\r\n\t\t\t\tlocal: true\r\n\t\t\t};\r\n\t\t\treturn saveLangPack(langPack);\r\n\t\t});\r\n\t}\r\n\r\n\texport function loadLangPack(langCode: string) {\r\n\t\trequestedServerLanguage = true;\r\n\t\treturn Promise.all([\r\n\t\t\tapiManager.invokeApiCacheable('langpack.getLangPack', {\r\n\t\t\t\tlang_code: langCode,\r\n\t\t\t\tlang_pack: App.langPack\r\n\t\t\t}),\r\n\t\t\tapiManager.invokeApiCacheable('langpack.getLangPack', {\r\n\t\t\t\tlang_code: langCode,\r\n\t\t\t\tlang_pack: 'android'\r\n\t\t\t}),\r\n\t\t\timport('../lang'),\r\n\t\t\timport('../langSign'),\r\n\t\t\tpolyfillPromise\r\n\t\t]);\r\n\t}\r\n\r\n\texport function getStrings(langCode: string, strings: string[]) {\r\n\t\treturn apiManager.invokeApi('langpack.getStrings', {\r\n\t\t\tlang_pack: App.langPack,\r\n\t\t\tlang_code: langCode,\r\n\t\t\tkeys: strings\r\n\t\t});\r\n\t}\r\n\r\n\texport function formatLocalStrings(strings: any, pushTo: LangPackString[] = []) {\r\n\t\tfor(const i in strings) {\r\n\t\t\t// @ts-ignore\r\n\t\t\tconst v = strings[i];\r\n\t\t\tif(typeof(v) === 'string') {\r\n\t\t\t\tpushTo.push({\r\n\t\t\t\t\t_: 'langPackString',\r\n\t\t\t\t\tkey: i,\r\n\t\t\t\t\tvalue: v\r\n\t\t\t\t});\r\n\t\t\t} else {\r\n\t\t\t\tpushTo.push({\r\n\t\t\t\t\t_: 'langPackStringPluralized',\r\n\t\t\t\t\tkey: i,\r\n\t\t\t\t\t...v\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn pushTo;\r\n\t}\r\n\r\n\texport function getLangPack(langCode: string) {\r\n\t\tlastRequestedLangCode = langCode;\r\n\t\treturn loadLangPack(langCode).then(([langPack, _langPack, __langPack, ___langPack, _]) => {\r\n\t\t\tlet strings: LangPackString[] = [];\r\n\r\n\t\t\t[__langPack, ___langPack].forEach(l => {\r\n\t\t\t\tformatLocalStrings(l.default as any, strings);\r\n\t\t\t});\r\n\r\n\t\t\tstrings = strings.concat(langPack.strings);\r\n\r\n\t\t\tfor(const string of _langPack.strings) {\r\n\t\t\t\tstrings.push(string);\r\n\t\t\t}\r\n\r\n\t\t\tlangPack.strings = strings;\r\n\t\t\treturn saveLangPack(langPack);\r\n\t\t});\r\n\t}\r\n\r\n\texport function saveLangPack(langPack: LangPackDifference) {\r\n\t\tlangPack.appVersion = App.langPackVersion;\r\n\r\n\t\treturn sessionStorage.set({langPack}).then(() => {\r\n\t\t\tapplyLangPack(langPack);\r\n\t\t\treturn langPack;\r\n\t\t});\r\n\t}\r\n\r\n\texport const polyfillPromise = (function checkIfPolyfillNeeded() {\r\n\t\tif(typeof(Intl) !== 'undefined' && typeof(Intl.PluralRules) !== 'undefined'/* && false */) {\r\n\t\t\treturn Promise.resolve();\r\n\t\t} else {\r\n\t\t\treturn import('./pluralPolyfill').then((_Intl) => {\r\n\t\t\t\t(window as any).Intl = Object.assign(typeof(Intl) !== 'undefined' ? Intl : {}, _Intl.default);\r\n\t\t\t});\r\n\t\t}\r\n\t})();\r\n\t\r\n\texport function applyLangPack(langPack: LangPackDifference) {\r\n\t\tif(langPack.lang_code !== lastRequestedLangCode) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tpluralRules = new Intl.PluralRules(langPack.lang_code);\r\n\r\n\t\tstrings.clear();\r\n\r\n\t\tfor(const string of langPack.strings) {\r\n\t\t\tstrings.set(string.key as LangPackKey, string);\r\n\t\t}\r\n\r\n\t\trootScope.broadcast('language_change');\r\n\r\n\t\tconst elements = Array.from(document.querySelectorAll(`.i18n`)) as HTMLElement[];\r\n\t\telements.forEach(element => {\r\n\t\t\tconst instance = weakMap.get(element);\r\n\r\n\t\t\tif(instance) {\r\n\t\t\t\tinstance.update();\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\texport function superFormatter(input: string, args?: any[], indexHolder = {i: 0}) {\r\n\t\tlet out: (string | HTMLElement)[] = [];\r\n\t\tconst regExp = /(\\*\\*)(.+?)\\1|(\\n)|un\\d|%\\d\\$.|%./g;\r\n\r\n\t\tlet lastIndex = 0;\r\n\t\tinput.replace(regExp, (match, p1: any, p2: any, p3: any, offset: number, string: string) => {\r\n\t\t\t//console.table({match, p1, p2, offset, string});\r\n\r\n\t\t\tout.push(string.slice(lastIndex, offset));\r\n\r\n\t\t\tif(p1) {\r\n\t\t\t\t//offset += p1.length;\r\n\t\t\t\tswitch(p1) {\r\n\t\t\t\t\tcase '**': {\r\n\t\t\t\t\t\tconst b = document.createElement('b');\r\n\t\t\t\t\t\tb.append(...superFormatter(p2, args, indexHolder));\r\n\t\t\t\t\t\tout.push(b);\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t} else if(p3) {\r\n\t\t\t\tout.push(document.createElement('br'));\r\n\t\t\t} else if(args) {\r\n\t\t\t\tout.push(args[indexHolder.i++]);\r\n\t\t\t}\r\n\r\n\t\t\tlastIndex = offset + match.length;\r\n\t\t\treturn '';\r\n\t\t});\r\n\t\r\n\t\tif(lastIndex !== input.length) {\r\n\t\t\tout.push(input.slice(lastIndex));\r\n\t\t}\r\n\r\n\t\treturn out;\r\n\t}\r\n\t\r\n\texport function format(key: LangPackKey, plain: true, args?: any[]): string;\r\n\texport function format(key: LangPackKey, plain?: false, args?: any[]): (string | HTMLElement)[];\r\n\texport function format(key: LangPackKey, plain = false, args?: any[]): (string | HTMLElement)[] | string {\r\n\t\tconst str = strings.get(key);\r\n\t\tlet input: string;\r\n\t\tif(str) {\r\n\t\t\tif(str._ === 'langPackStringPluralized' && args?.length) {\r\n\t\t\t\tlet v = args[0] as number | string;\r\n\t\t\t\tif(typeof(v) === 'string') v = +v.replace(/\\D/g, '');\r\n\t\t\t\tconst s = pluralRules.select(v);\r\n\t\t\t\t// @ts-ignore\r\n\t\t\t\tinput = str[s + '_value'] || str['other_value'];\r\n\t\t\t} else if(str._ === 'langPackString') {\r\n\t\t\t\tinput = str.value;\r\n\t\t\t} else {\r\n\t\t\t\t//input = '[' + key + ']';\r\n\t\t\t\tinput = key;\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\t//input = '[' + key + ']';\r\n\t\t\tinput = key;\r\n\t\t}\r\n\t\t\r\n\t\tif(plain) {\r\n\t\t\tif(args?.length) {\r\n\t\t\t\tconst regExp = /un\\d|%\\d\\$.|%./g;\r\n\t\t\t\tlet i = 0;\r\n\t\t\t\tinput = input.replace(regExp, (match, offset, string) => {\r\n\t\t\t\t\treturn '' + args[i++];\r\n\t\t\t\t});\r\n\t\t\t}\r\n\r\n\t\t\treturn input;\r\n\t\t} else {\r\n\t\t\treturn superFormatter(input, args);\r\n\t\t}\r\n\t}\r\n\r\n\texport const weakMap: WeakMap<HTMLElement, IntlElementBase<IntlElementBaseOptions>> = new WeakMap();\r\n\r\n\texport type IntlElementBaseOptions = {\r\n\t\telement?: HTMLElement,\r\n\t\tproperty?: /* 'innerText' | */'innerHTML' | 'placeholder',\r\n\t};\r\n\r\n\tabstract class IntlElementBase<Options extends IntlElementBaseOptions> {\r\n\t\tpublic element: IntlElementBaseOptions['element'];\r\n\t\tpublic property: IntlElementBaseOptions['property'] = 'innerHTML';\r\n\t\r\n\t\tconstructor(options: Options) {\r\n\t\t\tthis.element = options.element || document.createElement('span');\r\n\t\t\tthis.element.classList.add('i18n');\r\n\t\t\t\r\n\t\t\tthis.update(options);\r\n\t\t\tweakMap.set(this.element, this);\r\n\t\t}\r\n\r\n\t\tabstract update(options?: Options): void;\r\n\t}\r\n\r\n\texport type IntlElementOptions = IntlElementBaseOptions & {\r\n\t\tkey: LangPackKey,\r\n\t\targs?: any[]\r\n\t};\r\n\texport class IntlElement extends IntlElementBase<IntlElementOptions> {\r\n\t\tpublic key: IntlElementOptions['key'];\r\n\t\tpublic args: IntlElementOptions['args'];\r\n\r\n\t\tpublic update(options?: IntlElementOptions) {\r\n\t\t\tsafeAssign(this, options);\r\n\t\r\n\t\t\tif(this.property === 'innerHTML') {\r\n\t\t\t\tthis.element.textContent = '';\r\n\t\t\t\tthis.element.append(...format(this.key, false, this.args));\r\n\t\t\t} else {\r\n\t\t\t\t// @ts-ignore\r\n\t\t\t\tconst v = this.element[this.property];\r\n\t\t\t\tconst formatted = format(this.key, true, this.args);\r\n\r\n\t\t\t\t// * hasOwnProperty won't work here\r\n\t\t\t\tif(v === undefined) this.element.dataset[this.property] = formatted;\r\n\t\t\t\telse (this.element as HTMLInputElement)[this.property] = formatted;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\texport type IntlDateElementOptions = IntlElementBaseOptions & {\r\n\t\tdate: Date,\r\n\t\toptions: Intl.DateTimeFormatOptions\r\n\t};\r\n\texport class IntlDateElement extends IntlElementBase<IntlDateElementOptions> {\r\n\t\tpublic date: IntlDateElementOptions['date'];\r\n\t\tpublic options: IntlDateElementOptions['options'];\r\n\r\n\t\tpublic update(options?: IntlDateElementOptions) {\r\n\t\t\tsafeAssign(this, options);\r\n\t\r\n\t\t\t//var options = { month: 'long', day: 'numeric' };\r\n\t\t\t\r\n\t\t\t// * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/hourCycle#adding_an_hour_cycle_via_the_locale_string\r\n\t\t\tconst dateTimeFormat = new Intl.DateTimeFormat(lastRequestedLangCode + '-u-hc-h23', this.options);\r\n\t\t\t\r\n\t\t\t(this.element as any)[this.property] = capitalizeFirstLetter(dateTimeFormat.format(this.date));\r\n\t\t}\r\n\t}\r\n\r\n\texport function i18n(key: LangPackKey, args?: any[]) {\r\n\t\treturn new IntlElement({key, args}).element;\r\n\t}\r\n\t\r\n\texport function i18n_(options: IntlElementOptions) {\r\n\t\treturn new IntlElement(options).element;\r\n\t}\r\n\r\n\texport function _i18n(element: HTMLElement, key: LangPackKey, args?: any[], property?: IntlElementOptions['property']) {\r\n\t\treturn new IntlElement({element, key, args, property}).element;\r\n\t}\r\n}\r\n\r\nexport {I18n};\r\nexport default I18n;\r\n\r\nconst i18n = I18n.i18n;\r\nexport {i18n};\r\n\r\nconst i18n_ = I18n.i18n_;\r\nexport {i18n_};\r\n\r\nconst _i18n = I18n._i18n;\r\nexport {_i18n};\r\n\r\nexport function join(elements: HTMLElement[], useLast = true) {\r\n\tconst arr: HTMLElement[] = elements.slice(0, 1);\r\n for(let i = 1; i < elements.length; ++i) {\r\n const isLast = (elements.length - 1) === i;\r\n const delimiterKey: LangPackKey = isLast && useLast ? 'WordDelimiterLast' : 'WordDelimiter';\r\n arr.push(i18n(delimiterKey));\r\n arr.push(elements[i]);\r\n }\r\n\r\n\treturn arr;\r\n}\r\n\r\nMOUNT_CLASS_TO.I18n = I18n;\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 { logger, LogLevels } from '../../logger';\r\nimport Modes from '../../../config/modes';\r\nimport EventListenerBase from '../../../helpers/eventListenerBase';\r\nimport { MTConnection } from './transport';\r\n\r\nexport default class Socket extends EventListenerBase<{\r\n open: () => void,\r\n message: (buffer: ArrayBuffer) => any,\r\n close: () => void,\r\n}> implements MTConnection {\r\n private ws: WebSocket;\r\n private log: ReturnType<typeof logger>;\r\n private debug = Modes.debug && false;\r\n\r\n constructor(protected dcId: number, protected url: string, logSuffix: string) {\r\n super();\r\n\r\n let logLevel = LogLevels.error | LogLevels.log;\r\n if(this.debug) logLevel |= LogLevels.debug;\r\n this.log = logger(`WS-${dcId}` + logSuffix, logLevel);\r\n this.log('constructor');\r\n this.connect();\r\n\r\n return this;\r\n }\r\n\r\n private removeListeners() {\r\n if(!this.ws) {\r\n return;\r\n }\r\n\r\n this.ws.removeEventListener('open', this.handleOpen);\r\n this.ws.removeEventListener('close', this.handleClose);\r\n this.ws.removeEventListener('error', this.handleError);\r\n this.ws.removeEventListener('message', this.handleMessage);\r\n this.ws = undefined;\r\n }\r\n \r\n private connect() {\r\n this.ws = new WebSocket(this.url, 'binary');\r\n this.ws.binaryType = 'arraybuffer';\r\n this.ws.addEventListener('open', this.handleOpen);\r\n this.ws.addEventListener('close', this.handleClose);\r\n this.ws.addEventListener('error', this.handleError);\r\n this.ws.addEventListener('message', this.handleMessage);\r\n }\r\n\r\n public close() {\r\n if(!this.ws) {\r\n return;\r\n }\r\n\r\n this.log.error('close execution');\r\n\r\n try {\r\n this.ws.close();\r\n } catch(err) {\r\n\r\n }\r\n this.handleClose();\r\n }\r\n \r\n private handleOpen = () => {\r\n this.log('opened');\r\n\r\n this.debug && this.log.debug('sending init packet');\r\n this.dispatchEvent('open');\r\n };\r\n\r\n private handleError = (e: Event) => {\r\n this.log.error('handleError', e);\r\n this.close();\r\n };\r\n\r\n private handleClose = () => {\r\n this.log('closed'/* , event, this.pending, this.ws.bufferedAmount */);\r\n\r\n this.removeListeners();\r\n this.dispatchEvent('close');\r\n };\r\n\r\n private handleMessage = (event: MessageEvent) => {\r\n this.debug && this.log.debug('<-', 'handleMessage', /* event, */event.data.byteLength);\r\n\r\n this.dispatchEvent('message', event.data as ArrayBuffer);\r\n };\r\n\r\n public send = (body: Uint8Array) => {\r\n this.debug && this.log.debug('-> body length to send:', body.length);\r\n\r\n this.ws.send(body);\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 MTProtoWorker from 'worker-loader!./mtproto.worker';\r\n//import './mtproto.worker';\r\nimport { isObject } from '../../helpers/object';\r\nimport type { MethodDeclMap } from '../../layer';\r\nimport type { InvokeApiOptions } from '../../types';\r\nimport CryptoWorkerMethods from '../crypto/crypto_methods';\r\nimport { logger } from '../logger';\r\nimport rootScope from '../rootScope';\r\nimport webpWorkerController from '../webp/webpWorkerController';\r\nimport type { DownloadOptions } from './apiFileManager';\r\nimport { ApiError } from './apiManager';\r\nimport type { ServiceWorkerTask, ServiceWorkerTaskResponse } from './mtproto.service';\r\nimport { UserAuth } from './mtproto_config';\r\nimport type { MTMessage } from './networker';\r\nimport referenceDatabase from './referenceDatabase';\r\nimport appDocsManager from '../appManagers/appDocsManager';\r\nimport DEBUG, { MOUNT_CLASS_TO } from '../../config/debug';\r\nimport Socket from './transports/websocket';\r\n\r\ntype Task = {\r\n taskId: number,\r\n task: string,\r\n args: any[]\r\n};\r\n\r\ntype HashResult = {\r\n hash: number,\r\n result: any\r\n};\r\n\r\ntype HashOptions = {\r\n [queryJSON: string]: HashResult\r\n};\r\n\r\nexport class ApiManagerProxy extends CryptoWorkerMethods {\r\n public worker: /* Window */Worker;\r\n public postMessage: (...args: any[]) => void;\r\n private afterMessageIdTemp = 0;\r\n\r\n private taskId = 0;\r\n private awaiting: {\r\n [id: number]: {\r\n resolve: any,\r\n reject: any,\r\n taskName: string\r\n }\r\n } = {} as any;\r\n private pending: Array<Task> = [];\r\n\r\n public updatesProcessor: (obj: any) => void = null;\r\n\r\n private log = logger('API-PROXY');\r\n\r\n private hashes: {[method: string]: HashOptions} = {};\r\n\r\n private apiPromisesSingle: {\r\n [q: string]: Promise<any>\r\n } = {};\r\n private apiPromisesCacheable: {\r\n [method: string]: {\r\n [queryJSON: string]: {\r\n timestamp: number,\r\n promise: Promise<any>,\r\n fulfilled: boolean,\r\n timeout?: number,\r\n params: any\r\n }\r\n }\r\n } = {};\r\n\r\n private isSWRegistered = true;\r\n\r\n private debug = DEBUG /* && false */;\r\n\r\n private sockets: Map<number, Socket> = new Map();\r\n\r\n constructor() {\r\n super();\r\n this.log('constructor');\r\n\r\n this.registerServiceWorker();\r\n\r\n///////////////////////\r\n this.registerWorker();\r\n//////////////\r\n }\r\n\r\n public isServiceWorkerOnline() {\r\n return this.isSWRegistered;\r\n }\r\n\r\n private registerServiceWorker() {\r\n if(!('serviceWorker' in navigator)) return;\r\n \r\n const worker = navigator.serviceWorker;\r\n worker.register('./sw.js', {scope: './'}).then(registration => {\r\n this.log('SW registered', registration);\r\n this.isSWRegistered = true;\r\n\r\n const sw = registration.installing || registration.waiting || registration.active;\r\n sw.addEventListener('statechange', (e) => {\r\n this.log('SW statechange', e);\r\n });\r\n\r\n////////////////////////\r\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n////////////////////////////////////////////\r\n////////////////\r\n }, (err) => {\r\n this.isSWRegistered = false;\r\n this.log.error('SW registration failed!', err);\r\n appDocsManager.onServiceWorkerFail();\r\n });\r\n\r\n worker.addEventListener('controllerchange', () => {\r\n this.log.warn('controllerchange');\r\n this.releasePending();\r\n\r\n worker.controller.addEventListener('error', (e) => {\r\n this.log.error('controller error:', e);\r\n });\r\n });\r\n\r\n//////////////////////\r\n/////////////////////////////////////////////////////////////\r\n/////////////\r\n worker.addEventListener('message', (e) => {\r\n const task: ServiceWorkerTask = e.data;\r\n if(!isObject(task)) {\r\n return;\r\n }\r\n \r\n this.postMessage(task);\r\n });\r\n//////////////\r\n\r\n worker.addEventListener('messageerror', (e) => {\r\n this.log.error('SW messageerror:', e);\r\n });\r\n }\r\n\r\n private onWorkerFirstMessage(worker: any) {\r\n if(!this.worker) {\r\n this.worker = worker;\r\n this.log('set webWorker');\r\n\r\n this.postMessage = this.worker.postMessage.bind(this.worker);\r\n\r\n const isWebpSupported = webpWorkerController.isWebpSupported();\r\n this.log('WebP supported:', isWebpSupported);\r\n this.postMessage({type: 'webpSupport', payload: isWebpSupported});\r\n\r\n this.releasePending();\r\n }\r\n }\r\n\r\n private onWorkerMessage = (e: MessageEvent) => {\r\n //this.log('got message from worker:', e.data);\r\n\r\n const task = e.data;\r\n\r\n if(!isObject(task)) {\r\n return;\r\n }\r\n\r\n if(task.update) {\r\n if(this.updatesProcessor) {\r\n this.updatesProcessor(task.update);\r\n }\r\n } else if(task.progress) {\r\n rootScope.broadcast('download_progress', task.progress);\r\n } else if(task.type === 'reload') {\r\n location.reload();\r\n } else if(task.type === 'connectionStatusChange') {\r\n rootScope.broadcast('connection_status_change', task.payload);\r\n } else if(task.type === 'convertWebp') {\r\n webpWorkerController.postMessage(task);\r\n } else if((task as ServiceWorkerTaskResponse).type === 'requestFilePart') {\r\n const _task = task as ServiceWorkerTaskResponse;\r\n \r\n if(_task.error) {\r\n const onError = (error: ApiError) => {\r\n if(error?.type === 'FILE_REFERENCE_EXPIRED') {\r\n // @ts-ignore\r\n const bytes = _task.originalPayload[1].file_reference;\r\n referenceDatabase.refreshReference(bytes).then(() => {\r\n // @ts-ignore\r\n _task.originalPayload[1].file_reference = referenceDatabase.getReferenceByLink(bytes);\r\n const newTask: ServiceWorkerTask = {\r\n type: _task.type,\r\n id: _task.id,\r\n payload: _task.originalPayload\r\n };\r\n\r\n this.postMessage(newTask);\r\n }).catch(onError);\r\n } else {\r\n navigator.serviceWorker.controller.postMessage(task);\r\n }\r\n };\r\n\r\n onError(_task.error);\r\n } else {\r\n navigator.serviceWorker.controller.postMessage(task);\r\n }\r\n } else if(task.type === 'socketProxy') {\r\n const socketTask = task.payload;\r\n const id = socketTask.id;\r\n //console.log('socketProxy', socketTask, id);\r\n\r\n if(socketTask.type === 'send') {\r\n const socket = this.sockets.get(id);\r\n socket.send(socketTask.payload);\r\n } else if(socketTask.type === 'close') {\r\n const socket = this.sockets.get(id);\r\n socket.close();\r\n } else if(socketTask.type === 'setup') {\r\n const socket = new Socket(socketTask.payload.dcId, socketTask.payload.url, socketTask.payload.logSuffix);\r\n \r\n const onOpen = () => {\r\n //console.log('socketProxy onOpen');\r\n this.postMessage({\r\n type: 'socketProxy', \r\n payload: {\r\n type: 'open',\r\n id\r\n }\r\n });\r\n };\r\n const onClose = () => {\r\n this.postMessage({\r\n type: 'socketProxy', \r\n payload: {\r\n type: 'close',\r\n id\r\n }\r\n });\r\n\r\n socket.removeEventListener('open', onOpen);\r\n socket.removeEventListener('close', onClose);\r\n socket.removeEventListener('message', onMessage);\r\n this.sockets.delete(id);\r\n };\r\n const onMessage = (buffer: ArrayBuffer) => {\r\n this.postMessage({\r\n type: 'socketProxy', \r\n payload: {\r\n type: 'message',\r\n id,\r\n payload: buffer\r\n }\r\n });\r\n };\r\n\r\n socket.addEventListener('open', onOpen);\r\n socket.addEventListener('close', onClose);\r\n socket.addEventListener('message', onMessage);\r\n this.sockets.set(id, socket);\r\n }\r\n } else if(task.hasOwnProperty('result') || task.hasOwnProperty('error')) {\r\n this.finalizeTask(task.taskId, task.result, task.error);\r\n }\r\n };\r\n\r\n/////////////////////\r\n private registerWorker() {\r\n //return;\r\n\r\n const worker = new MTProtoWorker();\r\n //const worker = window;\r\n worker.addEventListener('message', this.onWorkerFirstMessage.bind(this, worker), {once: true});\r\n worker.addEventListener('message', this.onWorkerMessage);\r\n\r\n worker.addEventListener('error', (err) => {\r\n this.log.error('WORKER ERROR', err);\r\n });\r\n }\r\n////////////\r\n\r\n private finalizeTask(taskId: number, result: any, error: any) {\r\n const deferred = this.awaiting[taskId];\r\n if(deferred !== undefined) {\r\n this.debug && this.log.debug('done', deferred.taskName, result, error);\r\n error ? deferred.reject(error) : deferred.resolve(result);\r\n delete this.awaiting[taskId];\r\n }\r\n }\r\n\r\n public performTaskWorker<T>(task: string, ...args: any[]) {\r\n this.debug && this.log.debug('start', task, args);\r\n\r\n return new Promise<T>((resolve, reject) => {\r\n this.awaiting[this.taskId] = {resolve, reject, taskName: task};\r\n \r\n const params = {\r\n task,\r\n taskId: this.taskId,\r\n args\r\n };\r\n\r\n this.pending.push(params);\r\n this.releasePending();\r\n \r\n this.taskId++;\r\n });\r\n }\r\n\r\n private releasePending() {\r\n if(this.postMessage) {\r\n this.debug && this.log.debug('releasing tasks, length:', this.pending.length);\r\n this.pending.forEach(pending => {\r\n this.postMessage(pending);\r\n });\r\n \r\n this.debug && this.log.debug('released tasks');\r\n this.pending.length = 0;\r\n }\r\n }\r\n\r\n public setUpdatesProcessor(callback: (obj: any) => void) {\r\n this.updatesProcessor = callback;\r\n }\r\n\r\n public invokeApi<T extends keyof MethodDeclMap>(method: T, params: MethodDeclMap[T]['req'] = {}, options: InvokeApiOptions = {}): Promise<MethodDeclMap[T]['res']> {\r\n //console.log('will invokeApi:', method, params, options);\r\n return this.performTaskWorker('invokeApi', method, params, options);\r\n }\r\n\r\n public invokeApiAfter<T extends keyof MethodDeclMap>(method: T, params: MethodDeclMap[T]['req'] = {}, options: InvokeApiOptions = {}): Promise<MethodDeclMap[T]['res']> {\r\n let o = options;\r\n o.prepareTempMessageId = '' + ++this.afterMessageIdTemp;\r\n \r\n o = {...options};\r\n (options as MTMessage).messageId = o.prepareTempMessageId;\r\n\r\n //console.log('will invokeApi:', method, params, options);\r\n return this.invokeApi(method, params, o);\r\n }\r\n\r\n public invokeApiHashable<T extends keyof MethodDeclMap>(method: T, params: Omit<MethodDeclMap[T]['req'], 'hash'> = {} as any, options: InvokeApiOptions = {}): Promise<MethodDeclMap[T]['res']> {\r\n //console.log('will invokeApi:', method, params, options);\r\n\r\n const queryJSON = JSON.stringify(params);\r\n let cached: HashResult;\r\n if(this.hashes[method]) {\r\n cached = this.hashes[method][queryJSON];\r\n if(cached) {\r\n (params as any).hash = cached.hash;\r\n }\r\n }\r\n\r\n return this.invokeApi(method, params, options).then((result: any) => {\r\n if(result._.includes('NotModified')) {\r\n this.debug && this.log.warn('NotModified saved!', method, queryJSON);\r\n return cached.result;\r\n }\r\n \r\n if(result.hash/* || result.messages */) {\r\n const hash = result.hash/* || this.computeHash(result.messages) */;\r\n \r\n if(!this.hashes[method]) this.hashes[method] = {};\r\n this.hashes[method][queryJSON] = {\r\n hash,\r\n result\r\n };\r\n }\r\n\r\n return result;\r\n });\r\n }\r\n\r\n public invokeApiSingle<T extends keyof MethodDeclMap>(method: T, params: MethodDeclMap[T]['req'] = {} as any, options: InvokeApiOptions = {}): Promise<MethodDeclMap[T]['res']> {\r\n const q = method + '-' + JSON.stringify(params);\r\n if(this.apiPromisesSingle[q]) {\r\n return this.apiPromisesSingle[q];\r\n }\r\n\r\n return this.apiPromisesSingle[q] = this.invokeApi(method, params, options).finally(() => {\r\n delete this.apiPromisesSingle[q];\r\n });\r\n }\r\n\r\n public invokeApiCacheable<T extends keyof MethodDeclMap>(method: T, params: MethodDeclMap[T]['req'] = {} as any, options: InvokeApiOptions & Partial<{cacheSeconds: number, override: boolean}> = {}): Promise<MethodDeclMap[T]['res']> {\r\n const cache = this.apiPromisesCacheable[method] ?? (this.apiPromisesCacheable[method] = {});\r\n const queryJSON = JSON.stringify(params);\r\n const item = cache[queryJSON];\r\n if(item && (!options.override || !item.fulfilled)) {\r\n return item.promise;\r\n }\r\n\r\n if(options.override) {\r\n if(item && item.timeout) {\r\n clearTimeout(item.timeout);\r\n delete item.timeout;\r\n }\r\n\r\n delete options.override;\r\n }\r\n\r\n let timeout: number;\r\n if(options.cacheSeconds) {\r\n timeout = window.setTimeout(() => {\r\n delete cache[queryJSON];\r\n }, options.cacheSeconds * 1000);\r\n delete options.cacheSeconds;\r\n }\r\n\r\n const promise = this.invokeApi(method, params, options);\r\n\r\n cache[queryJSON] = {\r\n timestamp: Date.now(),\r\n fulfilled: false,\r\n timeout,\r\n promise,\r\n params\r\n };\r\n\r\n return promise;\r\n }\r\n\r\n public clearCache<T extends keyof MethodDeclMap>(method: T, verify: (params: MethodDeclMap[T]['req']) => boolean) {\r\n const cache = this.apiPromisesCacheable[method];\r\n if(cache) {\r\n for(const queryJSON in cache) {\r\n const item = cache[queryJSON];\r\n if(verify(item.params)) {\r\n if(item.timeout) {\r\n clearTimeout(item.timeout);\r\n }\r\n\r\n delete cache[queryJSON];\r\n }\r\n }\r\n }\r\n }\r\n\r\n /* private computeHash(smth: any[]) {\r\n smth = smth.slice().sort((a, b) => a.id - b.id);\r\n //return smth.reduce((hash, v) => (((hash * 0x4F25) & 0x7FFFFFFF) + v.id) & 0x7FFFFFFF, 0);\r\n return smth.reduce((hash, v) => ((hash * 20261) + 0x80000000 + v.id) % 0x80000000, 0);\r\n } */\r\n\r\n public setBaseDcId(dcId: number) {\r\n return this.performTaskWorker('setBaseDcId', dcId);\r\n }\r\n\r\n public setQueueId(queueId: number) {\r\n return this.performTaskWorker('setQueueId', queueId);\r\n }\r\n\r\n public setUserAuth(userAuth: UserAuth) {\r\n rootScope.broadcast('user_auth', userAuth);\r\n return this.performTaskWorker('setUserAuth', userAuth);\r\n }\r\n\r\n public getNetworker(dc_id: number, options?: InvokeApiOptions) {\r\n return this.performTaskWorker('getNetworker', dc_id, options);\r\n }\r\n\r\n public logOut(): Promise<void> {\r\n return this.performTaskWorker('logOut');\r\n }\r\n\r\n public cancelDownload(fileName: string) {\r\n return this.performTaskWorker('cancelDownload', fileName);\r\n }\r\n\r\n public downloadFile(options: DownloadOptions) {\r\n return this.performTaskWorker('downloadFile', options);\r\n }\r\n\r\n public uploadFile(options: {file: Blob | File, fileName: string}) {\r\n return this.performTaskWorker('uploadFile', options);\r\n }\r\n\r\n public toggleStorage(enabled: boolean) {\r\n return this.performTaskWorker('toggleStorage', enabled);\r\n }\r\n}\r\n\r\nconst apiManagerProxy = new ApiManagerProxy();\r\nMOUNT_CLASS_TO.apiManagerProxy = apiManagerProxy;\r\nexport default apiManagerProxy;\r\n","import { convertToArrayBuffer } from \"../../helpers/bytes\";\r\nimport type { InputCheckPasswordSRP } from \"../../layer\";\r\nimport type { aesEncryptSync } from \"./crypto_utils\";\r\n\r\nexport default abstract class CryptoWorkerMethods {\r\n abstract performTaskWorker<T>(task: string, ...args: any[]): Promise<T>;\r\n\r\n public sha1Hash(bytes: number[] | ArrayBuffer | Uint8Array): Promise<Uint8Array> {\r\n return this.performTaskWorker<Uint8Array>('sha1-hash', bytes);\r\n }\r\n\r\n public sha256Hash(bytes: any) {\r\n return this.performTaskWorker<number[]>('sha256-hash', bytes);\r\n }\r\n\r\n public pbkdf2(buffer: Uint8Array, salt: Uint8Array, iterations: number) {\r\n return this.performTaskWorker<ArrayBuffer>('pbkdf2', buffer, salt, iterations);\r\n }\r\n\r\n public aesEncrypt(bytes: any, keyBytes: any, ivBytes: any) {\r\n return this.performTaskWorker<ReturnType<typeof aesEncryptSync>>('aes-encrypt', convertToArrayBuffer(bytes), \r\n convertToArrayBuffer(keyBytes), convertToArrayBuffer(ivBytes));\r\n }\r\n\r\n public aesDecrypt(encryptedBytes: any, keyBytes: any, ivBytes: any): Promise<ArrayBuffer> {\r\n return this.performTaskWorker<ArrayBuffer>('aes-decrypt', \r\n encryptedBytes, keyBytes, ivBytes)\r\n .then(bytes => convertToArrayBuffer(bytes));\r\n }\r\n\r\n public rsaEncrypt(publicKey: {modulus: string, exponent: string}, bytes: any): Promise<number[]> {\r\n return this.performTaskWorker<number[]>('rsa-encrypt', publicKey, bytes);\r\n }\r\n\r\n public factorize(bytes: Uint8Array) {\r\n return this.performTaskWorker<[number[], number[], number]>('factorize', [...bytes]);\r\n }\r\n\r\n public modPow(x: any, y: any, m: any) {\r\n return this.performTaskWorker<number[]>('mod-pow', x, y, m);\r\n }\r\n\r\n public gzipUncompress<T>(bytes: ArrayBuffer, toString?: boolean) {\r\n return this.performTaskWorker<T>('gzipUncompress', bytes, toString);\r\n }\r\n\r\n public computeSRP(password: string, state: any, isNew = false): Promise<InputCheckPasswordSRP> {\r\n return this.performTaskWorker('computeSRP', password, state, isNew);\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 { formatPhoneNumber } from \"../../components/misc\";\r\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\r\nimport { tsNow } from \"../../helpers/date\";\r\nimport { safeReplaceObject, isObject } from \"../../helpers/object\";\r\nimport { InputUser, Update, User as MTUser, UserStatus } from \"../../layer\";\r\nimport I18n, { i18n, LangPackKey } from \"../langPack\";\r\n//import apiManager from '../mtproto/apiManager';\r\nimport apiManager from '../mtproto/mtprotoworker';\r\nimport { REPLIES_PEER_ID } from \"../mtproto/mtproto_config\";\r\nimport serverTimeManager from \"../mtproto/serverTimeManager\";\r\nimport { RichTextProcessor } from \"../richtextprocessor\";\r\nimport rootScope from \"../rootScope\";\r\nimport searchIndexManager from \"../searchIndexManager\";\r\n//import AppStorage from \"../storage\";\r\nimport apiUpdatesManager from \"./apiUpdatesManager\";\r\nimport appChatsManager from \"./appChatsManager\";\r\nimport appPeersManager from \"./appPeersManager\";\r\nimport appStateManager from \"./appStateManager\";\r\n\r\n// TODO: updateUserBlocked\r\n\r\nexport type User = MTUser.user;\r\n\r\nexport class AppUsersManager {\r\n /* private storage = new AppStorage<Record<number, User>>({\r\n storeName: 'users'\r\n }); */\r\n \r\n private users: {[userId: number]: User} = {};\r\n private usernames: {[username: string]: number} = {};\r\n private contactsIndex = searchIndexManager.createIndex();\r\n private contactsFillPromise: Promise<Set<number>>;\r\n private contactsList: Set<number> = new Set();\r\n private updatedContactsList = false;\r\n \r\n private getTopPeersPromise: Promise<number[]>;\r\n\r\n constructor() {\r\n //this.users = this.storage.getCache();\r\n\r\n setInterval(this.updateUsersStatuses, 60000);\r\n\r\n rootScope.on('state_synchronized', this.updateUsersStatuses);\r\n\r\n rootScope.addMultipleEventsListeners({\r\n updateUserStatus: (update) => {\r\n const userId = update.user_id;\r\n const user = this.users[userId];\r\n if(user) {\r\n user.status = update.status;\r\n if(user.status) {\r\n if('expires' in user.status) {\r\n user.status.expires -= serverTimeManager.serverTimeOffset;\r\n }\r\n\r\n if('was_online' in user.status) {\r\n user.status.was_online -= serverTimeManager.serverTimeOffset;\r\n }\r\n }\r\n\r\n //user.sortStatus = this.getUserStatusForSort(user.status);\r\n rootScope.broadcast('user_update', userId);\r\n } //////else console.warn('No user by id:', userId);\r\n },\r\n\r\n updateUserPhoto: (update) => {\r\n const userId = update.user_id;\r\n const user = this.users[userId];\r\n if(user) {\r\n this.forceUserOnline(userId);\r\n\r\n if(update.photo._ === 'userProfilePhotoEmpty') {\r\n delete user.photo;\r\n } else {\r\n user.photo = safeReplaceObject(user.photo, update.photo);\r\n }\r\n\r\n rootScope.broadcast('user_update', userId);\r\n rootScope.broadcast('avatar_update', userId);\r\n } else console.warn('No user by id:', userId);\r\n },\r\n\r\n updateUserName: (update) => {\r\n const userId = update.user_id;\r\n const user = this.users[userId];\r\n if(user) {\r\n this.forceUserOnline(userId);\r\n \r\n this.saveApiUser(Object.assign({}, user, {\r\n first_name: update.first_name,\r\n last_name: update.last_name,\r\n username: update.username\r\n }), true);\r\n }\r\n }\r\n });\r\n\r\n /* case 'updateContactLink':\r\n this.onContactUpdated(update.user_id, update.my_link._ === 'contactLinkContact');\r\n break; */\r\n\r\n rootScope.on('language_change', (e) => {\r\n const userId = this.getSelf().id;\r\n searchIndexManager.indexObject(userId, this.getUserSearchText(userId), this.contactsIndex);\r\n });\r\n\r\n appStateManager.getState().then((state) => {\r\n this.users = state.users;\r\n\r\n const contactsList = state.contactsList;\r\n if(contactsList && Array.isArray(contactsList)) {\r\n contactsList.forEach(userId => {\r\n this.pushContact(userId);\r\n });\r\n\r\n if(this.contactsList.size) {\r\n this.contactsFillPromise = Promise.resolve(this.contactsList);\r\n }\r\n }\r\n\r\n appStateManager.addEventListener('save', async() => {\r\n const contactsList = [...this.contactsList];\r\n for(const userId of contactsList) {\r\n appStateManager.setPeer(userId, this.getUser(userId));\r\n }\r\n \r\n appStateManager.pushToState('contactsList', contactsList);\r\n });\r\n });\r\n }\r\n\r\n public fillContacts() {\r\n if(this.contactsFillPromise && this.updatedContactsList) {\r\n return this.contactsFillPromise;\r\n }\r\n\r\n this.updatedContactsList = true;\r\n\r\n const promise = apiManager.invokeApi('contacts.getContacts').then((result) => {\r\n if(result._ === 'contacts.contacts') {\r\n this.saveApiUsers(result.users);\r\n\r\n result.contacts.forEach((contact) => {\r\n this.pushContact(contact.user_id);\r\n });\r\n }\r\n\r\n this.contactsFillPromise = promise;\r\n\r\n return this.contactsList;\r\n });\r\n\r\n return this.contactsFillPromise || (this.contactsFillPromise = promise);\r\n }\r\n\r\n public resolveUsername(username: string) {\r\n if(username[0] === '@') {\r\n username = username.slice(1);\r\n }\r\n\r\n username = username.toLowerCase();\r\n if(this.usernames[username]) {\r\n return Promise.resolve(this.users[this.usernames[username]]);\r\n }\r\n\r\n return apiManager.invokeApi('contacts.resolveUsername', {username}).then(resolvedPeer => {\r\n this.saveApiUsers(resolvedPeer.users);\r\n appChatsManager.saveApiChats(resolvedPeer.chats);\r\n\r\n return appPeersManager.getPeer(appPeersManager.getPeerId(resolvedPeer.peer));\r\n });\r\n }\r\n\r\n public pushContact(userId: number) {\r\n this.contactsList.add(userId);\r\n searchIndexManager.indexObject(userId, this.getUserSearchText(userId), this.contactsIndex);\r\n }\r\n\r\n public getUserSearchText(id: number) {\r\n const user = this.users[id];\r\n if(!user) {\r\n return '';\r\n }\r\n\r\n const arr: string[] = [\r\n user.first_name,\r\n user.last_name,\r\n user.phone,\r\n user.username,\r\n user.pFlags.self ? I18n.format('SavedMessages', true) : '',\r\n user.pFlags.self ? 'Saved Messages' : ''\r\n ];\r\n\r\n return arr.filter(Boolean).join(' ');\r\n }\r\n\r\n public getContacts(query?: string, includeSaved = false) {\r\n return this.fillContacts().then(_contactsList => {\r\n let contactsList = [..._contactsList];\r\n if(query) {\r\n const results = searchIndexManager.search(query, this.contactsIndex);\r\n const filteredContactsList = [...contactsList].filter(id => !!results[id]);\r\n\r\n contactsList = filteredContactsList;\r\n }\r\n\r\n contactsList.sort((userId1: number, userId2: number) => {\r\n const sortName1 = (this.users[userId1] || {}).sortName || '';\r\n const sortName2 = (this.users[userId2] || {}).sortName || '';\r\n\r\n return sortName1.localeCompare(sortName2);\r\n });\r\n\r\n if(includeSaved) {\r\n if(this.testSelfSearch(query)) {\r\n contactsList.findAndSplice(p => p === rootScope.myId);\r\n contactsList.unshift(rootScope.myId);\r\n }\r\n }\r\n\r\n /* contactsList.sort((userId1: number, userId2: number) => {\r\n const sortName1 = (this.users[userId1] || {}).sortName || '';\r\n const sortName2 = (this.users[userId2] || {}).sortName || '';\r\n if(sortName1 === sortName2) {\r\n return 0;\r\n } \r\n \r\n return sortName1 > sortName2 ? 1 : -1;\r\n }); */\r\n\r\n return contactsList;\r\n });\r\n }\r\n\r\n public toggleBlock(peerId: number, block: boolean) {\r\n return apiManager.invokeApi(block ? 'contacts.block' : 'contacts.unblock', {\r\n id: appPeersManager.getInputPeerById(peerId)\r\n }).then(value => {\r\n if(value) {\r\n apiUpdatesManager.processUpdateMessage({\r\n _: 'updateShort',\r\n update: {\r\n _: 'updatePeerBlocked',\r\n peer_id: appPeersManager.getOutputPeer(peerId),\r\n blocked: block\r\n } as Update.updatePeerBlocked\r\n });\r\n }\r\n\r\n return value;\r\n });\r\n }\r\n\r\n public testSelfSearch(query: string) {\r\n const user = this.getSelf();\r\n const index = searchIndexManager.createIndex();\r\n searchIndexManager.indexObject(user.id, this.getUserSearchText(user.id), index);\r\n return !!searchIndexManager.search(query, index)[user.id];\r\n }\r\n\r\n public saveApiUsers(apiUsers: any[]) {\r\n apiUsers.forEach((user) => this.saveApiUser(user));\r\n }\r\n\r\n public saveApiUser(user: MTUser, override?: boolean) {\r\n if(user._ === 'userEmpty') return;\r\n\r\n const userId = user.id;\r\n const oldUser = this.users[userId];\r\n\r\n if(oldUser && !override) {\r\n return;\r\n }\r\n\r\n if(user.pFlags === undefined) {\r\n user.pFlags = {};\r\n }\r\n\r\n if(user.pFlags.min && oldUser !== undefined) {\r\n return;\r\n }\r\n\r\n // * exclude from state\r\n // defineNotNumerableProperties(user, ['initials', 'num', 'rFirstName', 'rFullName', 'rPhone', 'sortName', 'sortStatus']);\r\n\r\n const fullName = user.first_name + ' ' + (user.last_name || '');\r\n if(user.username) {\r\n const searchUsername = searchIndexManager.cleanUsername(user.username);\r\n this.usernames[searchUsername] = userId;\r\n }\r\n\r\n user.sortName = user.pFlags.deleted ? '' : searchIndexManager.cleanSearchText(fullName, false);\r\n\r\n user.initials = RichTextProcessor.getAbbreviation(fullName);\r\n\r\n if(user.status) {\r\n if((user.status as UserStatus.userStatusOnline).expires) {\r\n (user.status as UserStatus.userStatusOnline).expires -= serverTimeManager.serverTimeOffset;\r\n }\r\n\r\n if((user.status as UserStatus.userStatusOffline).was_online) {\r\n (user.status as UserStatus.userStatusOffline).was_online -= serverTimeManager.serverTimeOffset;\r\n }\r\n }\r\n\r\n //user.sortStatus = user.pFlags.bot ? -1 : this.getUserStatusForSort(user.status);\r\n\r\n let changedTitle = false;\r\n if(oldUser === undefined) {\r\n this.users[userId] = user;\r\n } else {\r\n if(user.first_name !== oldUser.first_name \r\n || user.last_name !== oldUser.last_name \r\n || user.username !== oldUser.username) {\r\n changedTitle = true;\r\n }\r\n\r\n safeReplaceObject(oldUser, user);\r\n rootScope.broadcast('user_update', userId);\r\n }\r\n\r\n //console.log('we never give this up');\r\n\r\n /* this.storage.set({\r\n [userId]: user\r\n }); */\r\n\r\n if(changedTitle) {\r\n rootScope.broadcast('peer_title_edit', user.id);\r\n }\r\n }\r\n\r\n public formatUserPhone(phone: string) {\r\n return '+' + formatPhoneNumber(phone).formatted;\r\n }\r\n\r\n public getUserStatusForSort(status: User['status'] | number) {\r\n if(typeof(status) === 'number') {\r\n status = this.getUser(status).status;\r\n }\r\n\r\n if(status) {\r\n const expires = status._ === 'userStatusOnline' ? status.expires : (status._ === 'userStatusOffline' ? status.was_online : 0);\r\n if(expires) {\r\n return expires;\r\n }\r\n\r\n /* const timeNow = tsNow(true);\r\n switch(status._) {\r\n case 'userStatusRecently':\r\n return timeNow - 86400 * 3;\r\n case 'userStatusLastWeek':\r\n return timeNow - 86400 * 7;\r\n case 'userStatusLastMonth':\r\n return timeNow - 86400 * 30;\r\n } */\r\n switch(status._) {\r\n case 'userStatusRecently':\r\n return 3;\r\n case 'userStatusLastWeek':\r\n return 2;\r\n case 'userStatusLastMonth':\r\n return 1;\r\n }\r\n }\r\n\r\n return 0;\r\n }\r\n\r\n public getUser(id: any): User {\r\n if(isObject(id)) {\r\n return id;\r\n }\r\n\r\n return this.users[id] || {id: id, pFlags: {deleted: true}, access_hash: ''} as User;\r\n }\r\n\r\n public getSelf() {\r\n return this.getUser(rootScope.myId);\r\n }\r\n\r\n public getUserStatusString(userId: number): HTMLElement {\r\n let key: LangPackKey;\r\n let args: any[];\r\n\r\n switch(userId) {\r\n case REPLIES_PEER_ID:\r\n key = 'Peer.RepliesNotifications';\r\n break;\r\n case 777000:\r\n key = 'Peer.ServiceNotifications';\r\n break;\r\n default: {\r\n if(this.isBot(userId)) {\r\n key = 'Presence.bot';\r\n break;\r\n }\r\n\r\n const user = this.getUser(userId);\r\n if(!user) {\r\n key = '' as any;\r\n break;\r\n }\r\n\r\n if(user.pFlags.support) {\r\n key = 'Presence.Support';\r\n break;\r\n }\r\n\r\n switch(user.status?._) {\r\n case 'userStatusRecently': {\r\n key = 'Peer.Status.recently';\r\n break;\r\n }\r\n \r\n case 'userStatusLastWeek': {\r\n key = 'Peer.Status.lastWeek';\r\n break;\r\n }\r\n \r\n case 'userStatusLastMonth': {\r\n key = 'Peer.Status.lastMonth';\r\n break;\r\n }\r\n \r\n case 'userStatusOffline': {\r\n const date = user.status.was_online;\r\n const now = Date.now() / 1000;\r\n \r\n if((now - date) < 60) {\r\n key = 'Peer.Status.justNow';\r\n } else if((now - date) < 3600) {\r\n key = 'Peer.Status.minAgo';\r\n const c = (now - date) / 60 | 0;\r\n args = [c];\r\n } else if(now - date < 86400) {\r\n key = 'LastSeen.HoursAgo';\r\n const c = (now - date) / 3600 | 0;\r\n args = [c];\r\n } else {\r\n key = 'Peer.Status.LastSeenAt';\r\n const d = new Date(date * 1000);\r\n args = [('0' + d.getDate()).slice(-2) + '.' + ('0' + (d.getMonth() + 1)).slice(-2), \r\n ('0' + d.getHours()).slice(-2) + ':' + ('0' + d.getMinutes()).slice(-2)];\r\n }\r\n \r\n break;\r\n }\r\n \r\n case 'userStatusOnline': {\r\n key = 'Peer.Status.online';\r\n break;\r\n }\r\n \r\n default: {\r\n key = 'Peer.Status.longTimeAgo';\r\n break;\r\n }\r\n }\r\n\r\n break;\r\n }\r\n }\r\n \r\n return i18n(key, args);\r\n }\r\n\r\n public isBot(id: number) {\r\n return this.users[id] && this.users[id].pFlags.bot;\r\n }\r\n\r\n public isContact(id: number) {\r\n return this.contactsList.has(id);\r\n }\r\n \r\n public isRegularUser(id: number) {\r\n const user = this.users[id];\r\n return user && !this.isBot(id) && !user.pFlags.deleted && !user.pFlags.support;\r\n }\r\n\r\n public isNonContactUser(id: number) {\r\n return this.isRegularUser(id) && !this.isContact(id) && id !== rootScope.myId;\r\n }\r\n\r\n public hasUser(id: number, allowMin?: boolean) {\r\n var user = this.users[id];\r\n return isObject(user) && (allowMin || !user.pFlags.min);\r\n }\r\n\r\n public canSendToUser(id: number) {\r\n const user = this.getUser(id);\r\n return !user.pFlags.deleted && user.username !== 'replies';\r\n }\r\n\r\n public getUserPhoto(id: number) {\r\n const user = this.getUser(id);\r\n\r\n return user && user.photo || {\r\n _: 'userProfilePhotoEmpty'\r\n };\r\n }\r\n\r\n public getUserString(id: number) {\r\n const user = this.getUser(id);\r\n return 'u' + id + (user.access_hash ? '_' + user.access_hash : '');\r\n }\r\n\r\n public getUserInput(id: number): InputUser {\r\n const user = this.getUser(id);\r\n if(user.pFlags && user.pFlags.self) {\r\n return {_: 'inputUserSelf'};\r\n }\r\n\r\n return {\r\n _: 'inputUser',\r\n user_id: id,\r\n access_hash: user.access_hash\r\n };\r\n }\r\n\r\n public updateUsersStatuses = () => {\r\n const timestampNow = tsNow(true);\r\n for(const i in this.users) {\r\n const user = this.users[i];\r\n\r\n if(user.status &&\r\n user.status._ === 'userStatusOnline' &&\r\n user.status.expires < timestampNow) {\r\n\r\n user.status = {_: 'userStatusOffline', was_online: user.status.expires};\r\n rootScope.broadcast('user_update', user.id);\r\n }\r\n }\r\n };\r\n\r\n public forceUserOnline(id: number, eventTimestamp?: number) {\r\n if(this.isBot(id)) {\r\n return;\r\n }\r\n\r\n const timestamp = tsNow(true);\r\n const onlineTimeFor = 60;\r\n if(eventTimestamp) {\r\n if((timestamp - eventTimestamp) >= onlineTimeFor) {\r\n return;\r\n }\r\n } else if(apiUpdatesManager.updatesState.syncLoading) {\r\n return;\r\n }\r\n\r\n const user = this.getUser(id);\r\n if(user &&\r\n user.status &&\r\n user.status._ !== 'userStatusOnline' &&\r\n user.status._ !== 'userStatusEmpty' &&\r\n !user.pFlags.support &&\r\n !user.pFlags.deleted) {\r\n\r\n user.status = {\r\n _: 'userStatusOnline',\r\n expires: timestamp + onlineTimeFor\r\n };\r\n \r\n //user.sortStatus = this.getUserStatusForSort(user.status);\r\n rootScope.broadcast('user_update', id);\r\n }\r\n }\r\n\r\n /* function importContact (phone, firstName, lastName) {\r\n return MtpApiManager.invokeApi('contacts.importContacts', {\r\n contacts: [{\r\n _: 'inputPhoneContact',\r\n client_id: '1',\r\n phone: phone,\r\n first_name: firstName,\r\n last_name: lastName\r\n }],\r\n replace: false\r\n }).then(function (importedContactsResult) {\r\n saveApiUsers(importedContactsResult.users)\r\n\r\n var foundUserID = false\r\n angular.forEach(importedContactsResult.imported, function (importedContact) {\r\n onContactUpdated(foundUserID = importedContact.user_id, true)\r\n })\r\n\r\n return foundUserID || false\r\n })\r\n }\r\n\r\n function importContacts (contacts) {\r\n var inputContacts = [],\r\n i\r\n var j\r\n\r\n for (i = 0; i < contacts.length; i++) {\r\n for (j = 0; j < contacts[i].phones.length; j++) {\r\n inputContacts.push({\r\n _: 'inputPhoneContact',\r\n client_id: (i << 16 | j).toString(10),\r\n phone: contacts[i].phones[j],\r\n first_name: contacts[i].first_name,\r\n last_name: contacts[i].last_name\r\n })\r\n }\r\n }\r\n\r\n return MtpApiManager.invokeApi('contacts.importContacts', {\r\n contacts: inputContacts,\r\n replace: false\r\n }).then(function (importedContactsResult) {\r\n saveApiUsers(importedContactsResult.users)\r\n\r\n var result = []\r\n angular.forEach(importedContactsResult.imported, function (importedContact) {\r\n onContactUpdated(importedContact.user_id, true)\r\n result.push(importedContact.user_id)\r\n })\r\n\r\n return result\r\n })\r\n } */\r\n\r\n /* public deleteContacts(userIds: number[]) {\r\n var ids: any[] = [];\r\n userIds.forEach((userId) => {\r\n ids.push(this.getUserInput(userId));\r\n })\r\n\r\n return apiManager.invokeApi('contacts.deleteContacts', {\r\n id: ids\r\n }).then(() => {\r\n userIds.forEach((userId) => {\r\n this.onContactUpdated(userId, false);\r\n });\r\n });\r\n } */\r\n\r\n public getTopPeers(): Promise<number[]> {\r\n if(this.getTopPeersPromise) return this.getTopPeersPromise;\r\n\r\n return this.getTopPeersPromise = appStateManager.getState().then((state) => {\r\n if(state?.topPeers?.length) {\r\n return state.topPeers;\r\n }\r\n\r\n return apiManager.invokeApi('contacts.getTopPeers', {\r\n correspondents: true,\r\n offset: 0,\r\n limit: 15,\r\n hash: 0,\r\n }).then((result) => {\r\n let peerIds: number[] = [];\r\n if(result._ === 'contacts.topPeers') {\r\n //console.log(result);\r\n this.saveApiUsers(result.users);\r\n appChatsManager.saveApiChats(result.chats);\r\n\r\n if(result.categories.length) {\r\n peerIds = result.categories[0].peers.map((topPeer) => {\r\n const peerId = appPeersManager.getPeerId(topPeer.peer);\r\n appStateManager.setPeer(peerId, this.getUser(peerId));\r\n return peerId;\r\n });\r\n }\r\n }\r\n \r\n appStateManager.pushToState('topPeers', peerIds);\r\n \r\n return peerIds;\r\n });\r\n });\r\n }\r\n\r\n public getBlocked(offset = 0, limit = 0) {\r\n return apiManager.invokeApi('contacts.getBlocked', {offset, limit}).then(contactsBlocked => {\r\n this.saveApiUsers(contactsBlocked.users);\r\n appChatsManager.saveApiChats(contactsBlocked.chats);\r\n const count = contactsBlocked._ === 'contacts.blocked' ? contactsBlocked.users.length + contactsBlocked.chats.length : contactsBlocked.count;\r\n\r\n const peerIds = contactsBlocked.users.map(u => u.id).concat(contactsBlocked.chats.map(c => -c.id));\r\n\r\n return {count, peerIds};\r\n });\r\n }\r\n\r\n /* public searchContacts(query: string, limit = 20) {\r\n return Promise.all([\r\n this.getContacts(query),\r\n apiManager.invokeApi('contacts.search', {\r\n q: query,\r\n limit\r\n })\r\n ]).then(results => {\r\n const [myContacts, peers] = results;\r\n\r\n this.saveApiUsers(peers.users);\r\n appChatsManager.saveApiChats(peers.chats);\r\n\r\n // * contacts.search returns duplicates in my_results\r\n const myResults = new Set(myContacts.concat(peers.my_results.map(p => appPeersManager.getPeerID(p))));\r\n\r\n const out = {\r\n my_results: [...myResults].slice(0, limit),\r\n results: peers.results.map(p => appPeersManager.getPeerID(p))\r\n };\r\n\r\n return out;\r\n });\r\n } */\r\n public searchContacts(query: string, limit = 20) {\r\n return apiManager.invokeApi('contacts.search', {\r\n q: query,\r\n limit\r\n }).then(peers => {\r\n this.saveApiUsers(peers.users);\r\n appChatsManager.saveApiChats(peers.chats);\r\n\r\n const out = {\r\n my_results: [...new Set(peers.my_results.map(p => appPeersManager.getPeerId(p)))], // ! contacts.search returns duplicates in my_results\r\n results: peers.results.map(p => appPeersManager.getPeerId(p))\r\n };\r\n\r\n return out;\r\n });\r\n }\r\n\r\n public onContactUpdated(userId: number, isContact: boolean) {\r\n const curIsContact = this.isContact(userId);\r\n if(isContact !== curIsContact) {\r\n if(isContact) {\r\n this.contactsList.add(userId)\r\n searchIndexManager.indexObject(userId, this.getUserSearchText(userId), this.contactsIndex);\r\n } else {\r\n this.contactsList.delete(userId);\r\n }\r\n\r\n rootScope.broadcast('contacts_update', userId);\r\n }\r\n }\r\n\r\n public updateUsername(username: string) {\r\n return apiManager.invokeApi('account.updateUsername', {\r\n username\r\n }).then((user) => {\r\n this.saveApiUser(user);\r\n });\r\n }\r\n\r\n public setUserStatus(userId: number, offline: boolean) {\r\n if(this.isBot(userId)) {\r\n return;\r\n }\r\n\r\n const user = this.users[userId];\r\n if(user) {\r\n const status: any = offline ? {\r\n _: 'userStatusOffline',\r\n was_online: tsNow(true)\r\n } : {\r\n _: 'userStatusOnline',\r\n expires: tsNow(true) + 500\r\n };\r\n\r\n user.status = status;\r\n //user.sortStatus = this.getUserStatusForSort(user.status);\r\n rootScope.broadcast('user_update', userId);\r\n }\r\n }\r\n\r\n public addContact(userId: number, first_name: string, last_name: string, phone: string, showPhone?: true) {\r\n return apiManager.invokeApi('contacts.addContact', {\r\n id: this.getUserInput(userId),\r\n first_name,\r\n last_name,\r\n phone,\r\n add_phone_privacy_exception: showPhone\r\n }).then((updates) => {\r\n apiUpdatesManager.processUpdateMessage(updates);\r\n\r\n this.onContactUpdated(userId, true);\r\n });\r\n }\r\n\r\n public deleteContacts(userIds: number[]) {\r\n return apiManager.invokeApi('contacts.deleteContacts', {\r\n id: userIds.map(userId => this.getUserInput(userId))\r\n }).then((updates) => {\r\n apiUpdatesManager.processUpdateMessage(updates);\r\n\r\n userIds.forEach(userId => {\r\n this.onContactUpdated(userId, false);\r\n });\r\n });\r\n }\r\n}\r\n\r\nconst appUsersManager = new AppUsersManager();\r\nMOUNT_CLASS_TO.appUsersManager = appUsersManager;\r\nexport default appUsersManager\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 Countries, { Country, PhoneCodesMain } from \"../countries\";\r\nimport { cancelEvent, CLICK_EVENT_NAME } from \"../helpers/dom\";\r\nimport ListenerSetter from \"../helpers/listenerSetter\";\r\nimport mediaSizes from \"../helpers/mediaSizes\";\r\nimport { isTouchSupported } from \"../helpers/touchSupport\";\r\nimport { isApple, isMobileSafari, isSafari } from \"../helpers/userAgent\";\r\nimport appNavigationController from \"./appNavigationController\";\r\n\r\nexport function putPreloader(elem: Element, returnDiv = false): HTMLElement {\r\n const html = `\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"preloader-circular\" viewBox=\"25 25 50 50\">\r\n <circle class=\"preloader-path\" cx=\"50\" cy=\"50\" r=\"20\" fill=\"none\" stroke-miterlimit=\"10\"/>\r\n </svg>`;\r\n\r\n if(returnDiv) {\r\n const div = document.createElement('div');\r\n div.classList.add('preloader');\r\n div.innerHTML = html;\r\n\r\n if(elem) {\r\n elem.appendChild(div);\r\n }\r\n\r\n return div;\r\n }\r\n \r\n elem.insertAdjacentHTML('beforeend', html);\r\n return elem.lastElementChild as HTMLElement;\r\n}\r\n\r\nMOUNT_CLASS_TO.putPreloader = putPreloader;\r\n\r\nexport function setButtonLoader(elem: HTMLButtonElement, icon = 'check') {\r\n elem.classList.remove('tgico-' + icon);\r\n elem.disabled = true;\r\n putPreloader(elem);\r\n\r\n return () => {\r\n elem.innerHTML = '';\r\n elem.classList.add('tgico-' + icon);\r\n elem.removeAttribute('disabled');\r\n };\r\n}\r\n\r\nlet sortedCountries: Country[];\r\nexport function formatPhoneNumber(str: string) {\r\n str = str.replace(/\\D/g, '');\r\n let phoneCode = str.slice(0, 6);\r\n \r\n ////console.log('str', str, phoneCode);\r\n if(!sortedCountries) {\r\n sortedCountries = Countries.slice().sort((a, b) => b.phoneCode.length - a.phoneCode.length);\r\n }\r\n \r\n let country = sortedCountries.find((c) => {\r\n return c.phoneCode.split(' and ').find((c) => phoneCode.indexOf(c.replace(/\\D/g, '')) === 0);\r\n });\r\n\r\n if(!country) return {formatted: str, country};\r\n\r\n country = PhoneCodesMain[country.phoneCode] || country;\r\n \r\n let pattern = country.pattern || country.phoneCode;\r\n pattern.split('').forEach((symbol, idx) => {\r\n if(symbol === ' ' && str[idx] !== ' ' && str.length > idx) {\r\n str = str.slice(0, idx) + ' ' + str.slice(idx);\r\n }\r\n });\r\n \r\n /* if(country.pattern) {\r\n str = str.slice(0, country.pattern.length);\r\n } */\r\n \r\n return {formatted: str, country};\r\n}\r\n\r\n/* export function parseMenuButtonsTo(to: {[name: string]: HTMLElement}, elements: HTMLCollection | NodeListOf<HTMLElement>) {\r\n Array.from(elements).forEach(el => {\r\n const match = el.className.match(/(?:^|\\s)menu-(.+?)(?:$|\\s)/);\r\n if(!match) return;\r\n to[match[1]] = el as HTMLElement;\r\n });\r\n} */\r\n\r\nlet onMouseMove = (e: MouseEvent) => {\r\n let rect = openedMenu.getBoundingClientRect();\r\n let {clientX, clientY} = e;\r\n \r\n let diffX = clientX >= rect.right ? clientX - rect.right : rect.left - clientX;\r\n let diffY = clientY >= rect.bottom ? clientY - rect.bottom : rect.top - clientY;\r\n \r\n if(diffX >= 100 || diffY >= 100) {\r\n closeBtnMenu();\r\n //openedMenu.parentElement.click();\r\n }\r\n //console.log('mousemove', diffX, diffY);\r\n};\r\n\r\nconst onClick = (e: MouseEvent | TouchEvent) => {\r\n //cancelEvent(e);\r\n closeBtnMenu();\r\n};\r\n\r\n// ! no need in this due to the same handler in appNavigationController\r\n/* const onKeyDown = (e: KeyboardEvent) => {\r\n if(e.key === 'Escape') {\r\n closeBtnMenu();\r\n cancelEvent(e);\r\n }\r\n}; */\r\n\r\nexport const closeBtnMenu = () => {\r\n if(openedMenu) {\r\n openedMenu.classList.remove('active');\r\n openedMenu.parentElement.classList.remove('menu-open');\r\n //openedMenu.previousElementSibling.remove(); // remove overlay\r\n if(menuOverlay) menuOverlay.remove();\r\n openedMenu = null;\r\n }\r\n \r\n if(openedMenuOnClose) {\r\n openedMenuOnClose();\r\n openedMenuOnClose = null;\r\n }\r\n\r\n if(!isTouchSupported) {\r\n window.removeEventListener('mousemove', onMouseMove);\r\n //window.removeEventListener('keydown', onKeyDown, {capture: true});\r\n window.removeEventListener('contextmenu', onClick);\r\n }\r\n\r\n document.removeEventListener(CLICK_EVENT_NAME, onClick);\r\n\r\n if(!isMobileSafari) {\r\n appNavigationController.removeByType('menu');\r\n }\r\n};\r\n\r\nwindow.addEventListener('resize', () => {\r\n if(openedMenu) {\r\n closeBtnMenu();\r\n }\r\n \r\n /* if(openedMenu && (openedMenu.style.top || openedMenu.style.left)) {\r\n const rect = openedMenu.getBoundingClientRect();\r\n const {innerWidth, innerHeight} = window;\r\n\r\n console.log(innerWidth, innerHeight, rect);\r\n } */\r\n});\r\n\r\nlet openedMenu: HTMLElement = null, openedMenuOnClose: () => void = null, menuOverlay: HTMLElement = null;\r\nexport function openBtnMenu(menuElement: HTMLElement, onClose?: () => void) {\r\n closeBtnMenu();\r\n\r\n if(!isMobileSafari) {\r\n appNavigationController.pushItem({\r\n type: 'menu',\r\n onPop: (canAnimate) => {\r\n closeBtnMenu();\r\n }\r\n });\r\n }\r\n \r\n openedMenu = menuElement;\r\n openedMenu.classList.add('active');\r\n openedMenu.parentElement.classList.add('menu-open');\r\n\r\n if(!menuOverlay) {\r\n menuOverlay = document.createElement('div');\r\n menuOverlay.classList.add('btn-menu-overlay');\r\n\r\n // ! because this event must be canceled, and can't cancel on menu click (below)\r\n menuOverlay.addEventListener(CLICK_EVENT_NAME, (e) => {\r\n cancelEvent(e);\r\n onClick(e);\r\n });\r\n }\r\n\r\n openedMenu.parentElement.insertBefore(menuOverlay, openedMenu);\r\n\r\n //document.body.classList.add('disable-hover');\r\n \r\n openedMenuOnClose = onClose;\r\n\r\n if(!isTouchSupported) {\r\n window.addEventListener('mousemove', onMouseMove);\r\n //window.addEventListener('keydown', onKeyDown, {capture: true});\r\n window.addEventListener('contextmenu', onClick, {once: true});\r\n }\r\n\r\n /* // ! because this event must be canceled, and can't cancel on menu click (below)\r\n overlay.addEventListener(CLICK_EVENT_NAME, (e) => {\r\n cancelEvent(e);\r\n onClick(e);\r\n }); */\r\n \r\n // ! safari iOS doesn't handle window click event on overlay, idk why\r\n document.addEventListener(CLICK_EVENT_NAME, onClick);\r\n}\r\n\r\nconst PADDING_TOP = 8;\r\nconst PADDING_LEFT = 8;\r\nexport function positionMenu({pageX, pageY}: MouseEvent | Touch, elem: HTMLElement, side?: 'left' | 'right' | 'center') {\r\n //let {clientX, clientY} = e;\r\n\r\n // * side mean the OPEN side\r\n\r\n let {scrollWidth: menuWidth, scrollHeight: menuHeight} = elem;\r\n //let {innerWidth: windowWidth, innerHeight: windowHeight} = window;\r\n const rect = document.body.getBoundingClientRect();\r\n const windowWidth = rect.width;\r\n const windowHeight = rect.height;\r\n\r\n side = mediaSizes.isMobile ? 'right' : 'left';\r\n let verticalSide: 'top' /* | 'bottom' */ | 'center' = 'top';\r\n\r\n const getSides = () => {\r\n return {\r\n x: {\r\n left: pageX,\r\n right: pageX - menuWidth\r\n },\r\n intermediateX: side === 'right' ? PADDING_LEFT : windowWidth - menuWidth - PADDING_LEFT,\r\n //intermediateX: clientX < windowWidth / 2 ? PADDING_LEFT : windowWidth - menuWidth - PADDING_LEFT,\r\n y: {\r\n top: pageY,\r\n bottom: pageY - menuHeight\r\n },\r\n //intermediateY: verticalSide === 'top' ? PADDING_TOP : windowHeight - menuHeight - PADDING_TOP,\r\n intermediateY: pageY < windowHeight / 2 ? PADDING_TOP : windowHeight - menuHeight - PADDING_TOP,\r\n };\r\n };\r\n\r\n const sides = getSides();\r\n\r\n const possibleSides = {\r\n x: {\r\n left: sides.x.left + menuWidth + PADDING_LEFT <= windowWidth,\r\n right: sides.x.right >= PADDING_LEFT\r\n },\r\n y: {\r\n top: sides.y.top + menuHeight + PADDING_TOP <= windowHeight,\r\n bottom: sides.y.bottom - PADDING_TOP >= PADDING_TOP\r\n }\r\n };\r\n\r\n /* if(side === undefined) {\r\n if((clientX + menuWidth + PADDING_LEFT) > windowWidth) {\r\n side = 'right';\r\n }\r\n } */\r\n\r\n {\r\n /* const x = sides.x;\r\n\r\n const s = Object.keys(x) as (keyof typeof possibleSides.x)[];\r\n if(side) {\r\n s.findAndSplice(s => s === side);\r\n s.unshift(side);\r\n }\r\n\r\n const possibleSide = s.find(s => possibleSides.x[s]); */\r\n let left: number;\r\n /* if(possibleSide) {\r\n left = x[possibleSide];\r\n side = possibleSide;\r\n } else {\r\n left = sides.intermediateX;\r\n side = undefined;\r\n } */\r\n left = possibleSides.x[side] ? sides.x[side] : (side = 'center', sides.intermediateX);\r\n \r\n elem.style.left = left + 'px';\r\n }\r\n\r\n /* if((clientY + menuHeight + PADDING_TOP) > windowHeight) {\r\n elem.style.top = clamp(clientY - menuHeight, PADDING_TOP, windowHeight - menuHeight - PADDING_TOP) + 'px';\r\n // elem.style.top = (innerHeight - scrollHeight - PADDING_TOP) + 'px';\r\n verticalSide = 'bottom';\r\n } else {\r\n elem.style.top = Math.max(PADDING_TOP, clientY) + 'px';\r\n verticalSide = 'top';\r\n } */\r\n\r\n {\r\n let top: number;\r\n\r\n top = possibleSides.y[verticalSide] ? sides.y[verticalSide] : (verticalSide = 'center', sides.intermediateY);\r\n \r\n elem.style.top = top + 'px';\r\n }\r\n \r\n elem.className = elem.className.replace(/(top|center|bottom)-(left|center|right)/g, '');\r\n elem.classList.add(\r\n //(verticalSide === 'center' ? verticalSide : (verticalSide === 'bottom' ? 'top' : 'bottom')) +\r\n (verticalSide === 'center' ? verticalSide : 'bottom') +\r\n '-' +\r\n (side === 'center' ? side : (side === 'left' ? 'right' : 'left')));\r\n}\r\n\r\nexport function attachContextMenuListener(element: HTMLElement, callback: (e: Touch | MouseEvent) => void, listenerSetter?: ListenerSetter) {\r\n const add = listenerSetter ? listenerSetter.add.bind(listenerSetter, element) : element.addEventListener.bind(element);\r\n const remove = listenerSetter ? listenerSetter.removeManual.bind(listenerSetter, element) : element.removeEventListener.bind(element);\r\n\r\n if(isApple && isTouchSupported) {\r\n let timeout: number;\r\n\r\n const options: any = /* null */{capture: true};\r\n\r\n const onCancel = () => {\r\n clearTimeout(timeout);\r\n remove('touchmove', onCancel, options);\r\n remove('touchend', onCancel, options);\r\n remove('touchcancel', onCancel, options);\r\n };\r\n\r\n add('touchstart', (e: TouchEvent) => {\r\n if(e.touches.length > 1) {\r\n onCancel();\r\n return;\r\n }\r\n \r\n add('touchmove', onCancel, options);\r\n add('touchend', onCancel, options);\r\n add('touchcancel', onCancel, options);\r\n\r\n timeout = window.setTimeout(() => {\r\n callback(e.touches[0]);\r\n onCancel();\r\n\r\n if(openedMenu) {\r\n element.addEventListener('touchend', cancelEvent, {once: true}); // * fix instant closing\r\n }\r\n }, .4e3);\r\n });\r\n\r\n /* if(!isSafari) {\r\n add('contextmenu', (e: any) => {\r\n cancelEvent(e);\r\n }, {passive: false, capture: true});\r\n } */\r\n } else {\r\n add('contextmenu', isTouchSupported ? (e: any) => {\r\n callback(e);\r\n\r\n if(openedMenu) {\r\n element.addEventListener('touchend', cancelEvent, {once: true}); // * fix instant closing\r\n }\r\n } : callback);\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 { tsNow } from \"../../helpers/date\";\r\nimport type { Message } from \"../../layer\";\r\nimport type { AppChatsManager } from \"../appManagers/appChatsManager\";\r\nimport type { AppMessagesManager, Dialog, MyMessage } from \"../appManagers/appMessagesManager\";\r\nimport type { AppPeersManager } from \"../appManagers/appPeersManager\";\r\nimport type { ServerTimeManager } from \"../mtproto/serverTimeManager\";\r\nimport searchIndexManager from \"../searchIndexManager\";\r\nimport { insertInDescendSortedArray } from \"../../helpers/array\";\r\n\r\nexport default class DialogsStorage {\r\n public dialogs: {[peerId: string]: Dialog} = {};\r\n public byFolders: {[folderId: number]: Dialog[]} = {};\r\n\r\n public allDialogsLoaded: {[folder_id: number]: boolean};\r\n private dialogsOffsetDate: {[folder_id: number]: number};\r\n public pinnedOrders: {[folder_id: number]: number[]};\r\n private dialogsNum: number;\r\n\r\n public dialogsIndex = searchIndexManager.createIndex();\r\n\r\n constructor(private appMessagesManager: AppMessagesManager, private appChatsManager: AppChatsManager, private appPeersManager: AppPeersManager, private serverTimeManager: ServerTimeManager) {\r\n this.reset();\r\n }\r\n\r\n public reset() {\r\n this.allDialogsLoaded = {};\r\n this.dialogsOffsetDate = {};\r\n this.pinnedOrders = {\r\n 0: [],\r\n 1: []\r\n };\r\n this.dialogsNum = 0;\r\n }\r\n\r\n public getOffsetDate(folderId: number) {\r\n return this.dialogsOffsetDate[folderId] || 0;\r\n }\r\n\r\n public getFolder(id: number) {\r\n if(id <= 1) {\r\n return this.byFolders[id] ?? (this.byFolders[id] = []);\r\n }\r\n\r\n const dialogs: {dialog: Dialog, index: number}[] = [];\r\n const filter = this.appMessagesManager.filtersStorage.filters[id];\r\n\r\n for(const peerId in this.dialogs) {\r\n const dialog = this.dialogs[peerId];\r\n if(this.appMessagesManager.filtersStorage.testDialogForFilter(dialog, filter)) {\r\n let index: number;\r\n\r\n const pinnedIndex = filter.pinned_peers.indexOf(dialog.peerId);\r\n if(pinnedIndex !== -1) {\r\n index = this.generateDialogIndex(this.generateDialogPinnedDateByIndex(filter.pinned_peers.length - 1 - pinnedIndex));\r\n } else if(dialog.pFlags?.pinned) {\r\n index = this.generateIndexForDialog(dialog, true);\r\n } else {\r\n index = dialog.index;\r\n }\r\n\r\n dialogs.push({dialog, index});\r\n }\r\n }\r\n\r\n dialogs.sort((a, b) => b.index - a.index);\r\n return dialogs.map(d => d.dialog);\r\n }\r\n\r\n public getDialog(peerId: number, folderId?: number): [Dialog, number] | [] {\r\n const folders: Dialog[][] = [];\r\n\r\n if(folderId === undefined) {\r\n const dialogs = this.byFolders;\r\n for(const folderId in dialogs) {\r\n folders.push(dialogs[folderId]);\r\n }\r\n } else {\r\n folders.push(this.getFolder(folderId));\r\n }\r\n\r\n for(let folder of folders) {\r\n const index = folder.findIndex(dialog => dialog.peerId === peerId);\r\n if(index !== -1) {\r\n return [folder[index], index];\r\n }\r\n }\r\n\r\n return [];\r\n }\r\n\r\n /*\r\n var date = Date.now() / 1000 | 0;\r\n var m = date * 0x10000;\r\n\r\n var k = (date + 1) * 0x10000;\r\n k - m;\r\n 65536\r\n */\r\n public generateDialogIndex(date?: number) {\r\n if(date === undefined) {\r\n date = tsNow(true) + this.serverTimeManager.serverTimeOffset;\r\n }\r\n\r\n return (date * 0x10000) + ((++this.dialogsNum) & 0xFFFF);\r\n }\r\n\r\n public generateIndexForDialog(dialog: Dialog, justReturn = false, message?: MyMessage) {\r\n const channelId = this.appPeersManager.isChannel(dialog.peerId) ? -dialog.peerId : 0;\r\n \r\n let topDate = 0;\r\n if(dialog.pFlags.pinned && !justReturn) {\r\n topDate = this.generateDialogPinnedDate(dialog);\r\n } else {\r\n if(!message) {\r\n message = this.appMessagesManager.getMessageByPeer(dialog.peerId, dialog.top_message);\r\n }\r\n\r\n topDate = (message as Message.message).date || topDate;\r\n if(channelId) {\r\n const channel = this.appChatsManager.getChat(channelId);\r\n if(!topDate || (channel.date && channel.date > topDate)) {\r\n topDate = channel.date;\r\n }\r\n }\r\n \r\n if(dialog.draft && dialog.draft._ === 'draftMessage' && dialog.draft.date > topDate) {\r\n topDate = dialog.draft.date;\r\n }\r\n }\r\n\r\n if(!topDate) {\r\n topDate = Date.now() / 1000;\r\n }\r\n\r\n const index = this.generateDialogIndex(topDate);\r\n if(justReturn) return index;\r\n dialog.index = index;\r\n }\r\n\r\n public generateDialogPinnedDateByIndex(pinnedIndex: number) {\r\n return 0x7fff0000 + (pinnedIndex & 0xFFFF); // 0xFFFF - потому что в папках может быть бесконечное число пиннедов\r\n }\r\n\r\n public generateDialogPinnedDate(dialog: Dialog) {\r\n const order = this.pinnedOrders[dialog.folder_id];\r\n\r\n const foundIndex = order.indexOf(dialog.peerId);\r\n const pinnedIndex = foundIndex === -1 ? order.push(dialog.peerId) - 1 : foundIndex;\r\n\r\n return this.generateDialogPinnedDateByIndex(pinnedIndex);\r\n }\r\n\r\n public pushDialog(dialog: Dialog, offsetDate?: number) {\r\n const dialogs = this.getFolder(dialog.folder_id);\r\n const pos = dialogs.findIndex(d => d.peerId === dialog.peerId);\r\n if(pos !== -1) {\r\n dialogs.splice(pos, 1);\r\n }\r\n\r\n //if(!this.dialogs[dialog.peerId]) {\r\n this.dialogs[dialog.peerId] = dialog;\r\n //}\r\n\r\n if(offsetDate &&\r\n !dialog.pFlags.pinned &&\r\n (!this.dialogsOffsetDate[dialog.folder_id] || offsetDate < this.dialogsOffsetDate[dialog.folder_id])) {\r\n if(pos !== -1) {\r\n // So the dialog jumped to the last position\r\n return false;\r\n }\r\n this.dialogsOffsetDate[dialog.folder_id] = offsetDate;\r\n }\r\n\r\n insertInDescendSortedArray(dialogs, dialog, 'index', pos);\r\n }\r\n\r\n public dropDialog(peerId: number): [Dialog, number] | [] {\r\n const foundDialog = this.getDialog(peerId);\r\n if(foundDialog[0]) {\r\n this.byFolders[foundDialog[0].folder_id].splice(foundDialog[1], 1);\r\n delete this.dialogs[peerId];\r\n searchIndexManager.indexObject(peerId, '', this.dialogsIndex);\r\n }\r\n\r\n return foundDialog;\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 { copy } from \"../../helpers/object\";\r\nimport type { DialogFilter, Update } from \"../../layer\";\r\nimport type { Modify } from \"../../types\";\r\nimport type { AppPeersManager } from \"../appManagers/appPeersManager\";\r\nimport type { AppUsersManager } from \"../appManagers/appUsersManager\";\r\n//import type { ApiManagerProxy } from \"../mtproto/mtprotoworker\";\r\nimport type _rootScope from \"../rootScope\";\r\nimport type {AppMessagesManager, Dialog} from '../appManagers/appMessagesManager';\r\nimport type {AppNotificationsManager} from \"../appManagers/appNotificationsManager\";\r\nimport type { ApiUpdatesManager } from \"../appManagers/apiUpdatesManager\";\r\nimport apiManager from \"../mtproto/mtprotoworker\";\r\nimport { forEachReverse } from \"../../helpers/array\";\r\n\r\nexport type MyDialogFilter = Modify<DialogFilter, {\r\n pinned_peers: number[],\r\n include_peers: number[],\r\n exclude_peers: number[],\r\n orderIndex?: number\r\n}>;\r\n\r\n// ! because 0 index is 'All Chats'\r\nconst START_ORDER_INDEX = 1;\r\n\r\nexport default class FiltersStorage {\r\n public filters: {[filterId: string]: MyDialogFilter} = {};\r\n public orderIndex = START_ORDER_INDEX;\r\n\r\n constructor(private appMessagesManager: AppMessagesManager,\r\n private appPeersManager: AppPeersManager, \r\n private appUsersManager: AppUsersManager, \r\n private appNotificationsManager: AppNotificationsManager, \r\n private apiUpdatesManager: ApiUpdatesManager, \r\n /* private apiManager: ApiManagerProxy, */ \r\n private rootScope: typeof _rootScope) {\r\n\r\n rootScope.addMultipleEventsListeners({\r\n updateDialogFilter: this.onUpdateDialogFilter,\r\n\r\n updateDialogFilters: (update) => {\r\n //console.warn('updateDialogFilters', update);\r\n\r\n const oldFilters = copy(this.filters);\r\n\r\n this.getDialogFilters(true).then(filters => {\r\n for(const _filterId in oldFilters) {\r\n const filterId = +_filterId;\r\n if(!filters.find(filter => filter.id === filterId)) { // * deleted\r\n this.onUpdateDialogFilter({_: 'updateDialogFilter', id: filterId});\r\n }\r\n }\r\n\r\n this.onUpdateDialogFilterOrder({_: 'updateDialogFilterOrder', order: filters.map(filter => filter.id)});\r\n });\r\n },\r\n\r\n updateDialogFilterOrder: this.onUpdateDialogFilterOrder\r\n });\r\n }\r\n\r\n private onUpdateDialogFilter = (update: Update.updateDialogFilter) => {\r\n if(update.filter) {\r\n this.saveDialogFilter(update.filter as any);\r\n } else if(this.filters[update.id]) { // Папка удалена\r\n //this.getDialogFilters(true);\r\n this.rootScope.broadcast('filter_delete', this.filters[update.id]);\r\n delete this.filters[update.id];\r\n }\r\n };\r\n\r\n private onUpdateDialogFilterOrder = (update: Update.updateDialogFilterOrder) => {\r\n //console.log('updateDialogFilterOrder', update);\r\n\r\n this.orderIndex = START_ORDER_INDEX;\r\n update.order.forEach((filterId, idx) => {\r\n const filter = this.filters[filterId];\r\n delete filter.orderIndex;\r\n this.setOrderIndex(filter);\r\n });\r\n\r\n this.rootScope.broadcast('filter_order', update.order);\r\n };\r\n\r\n public testDialogForFilter(dialog: Dialog, filter: MyDialogFilter) {\r\n // exclude_peers\r\n for(const peerId of filter.exclude_peers) {\r\n if(peerId === dialog.peerId) {\r\n return false;\r\n }\r\n }\r\n\r\n // include_peers\r\n for(const peerId of filter.include_peers) {\r\n if(peerId === dialog.peerId) {\r\n return true;\r\n }\r\n }\r\n\r\n const pFlags = filter.pFlags;\r\n\r\n // exclude_archived\r\n if(pFlags.exclude_archived && dialog.folder_id === 1) {\r\n return false;\r\n }\r\n\r\n // exclude_read\r\n if(pFlags.exclude_read && !dialog.unread_count) {\r\n return false;\r\n }\r\n\r\n // exclude_muted\r\n if(pFlags.exclude_muted) {\r\n const isMuted = this.appNotificationsManager.isPeerLocalMuted(dialog.peerId);\r\n if(isMuted) {\r\n return false;\r\n }\r\n }\r\n\r\n const peerId = dialog.peerId;\r\n if(peerId < 0) {\r\n // broadcasts\r\n if(pFlags.broadcasts && this.appPeersManager.isBroadcast(peerId)) {\r\n return true;\r\n }\r\n\r\n // groups\r\n if(pFlags.groups && this.appPeersManager.isAnyGroup(peerId)) {\r\n return true;\r\n }\r\n } else {\r\n // bots\r\n if(this.appPeersManager.isBot(peerId)) {\r\n return !!pFlags.bots;\r\n }\r\n \r\n // non_contacts\r\n if(pFlags.non_contacts && !this.appUsersManager.isContact(peerId)) {\r\n return true;\r\n }\r\n\r\n // contacts\r\n if(pFlags.contacts && this.appUsersManager.isContact(peerId)) {\r\n return true;\r\n }\r\n }\r\n\r\n return false;\r\n }\r\n\r\n public toggleDialogPin(peerId: number, filterId: number) {\r\n const filter = this.filters[filterId];\r\n\r\n const wasPinned = filter.pinned_peers.findAndSplice(p => p === peerId);\r\n if(!wasPinned) {\r\n filter.pinned_peers.unshift(peerId);\r\n }\r\n \r\n return this.updateDialogFilter(filter);\r\n }\r\n\r\n public createDialogFilter(filter: MyDialogFilter) {\r\n let maxId = Math.max(1, ...Object.keys(this.filters).map(i => +i));\r\n filter = copy(filter);\r\n filter.id = maxId + 1;\r\n return this.updateDialogFilter(filter);\r\n }\r\n\r\n public updateDialogFilter(filter: MyDialogFilter, remove = false) {\r\n const flags = remove ? 0 : 1;\r\n\r\n return apiManager.invokeApi('messages.updateDialogFilter', {\r\n flags,\r\n id: filter.id,\r\n filter: remove ? undefined : this.getOutputDialogFilter(filter)\r\n }).then((bool: boolean) => { // возможно нужна проверка и откат, если результат не ТРУ\r\n //console.log('updateDialogFilter bool:', bool);\r\n\r\n if(bool) {\r\n /* if(!this.filters[filter.id]) {\r\n this.saveDialogFilter(filter);\r\n }\r\n\r\n rootScope.$broadcast('filter_update', filter); */\r\n\r\n this.onUpdateDialogFilter({\r\n _: 'updateDialogFilter',\r\n id: filter.id,\r\n filter: remove ? undefined : filter as any\r\n });\r\n }\r\n\r\n return bool;\r\n });\r\n }\r\n\r\n public getOutputDialogFilter(filter: MyDialogFilter) {\r\n const c: MyDialogFilter = copy(filter);\r\n ['pinned_peers', 'exclude_peers', 'include_peers'].forEach(key => {\r\n // @ts-ignore\r\n c[key] = c[key].map((peerId: number) => this.appPeersManager.getInputPeerById(peerId));\r\n });\r\n\r\n forEachReverse(c.include_peers, (peerId, idx) => {\r\n if(c.pinned_peers.includes(peerId)) {\r\n c.include_peers.splice(idx, 1);\r\n }\r\n });\r\n\r\n return c as any as DialogFilter;\r\n }\r\n\r\n public async getDialogFilters(overwrite = false): Promise<MyDialogFilter[]> {\r\n const keys = Object.keys(this.filters);\r\n if(keys.length && !overwrite) {\r\n return keys.map(filterId => this.filters[filterId]).sort((a, b) => a.orderIndex - b.orderIndex);\r\n }\r\n\r\n const filters: MyDialogFilter[] = await apiManager.invokeApi('messages.getDialogFilters') as any;\r\n for(const filter of filters) {\r\n this.saveDialogFilter(filter, overwrite);\r\n }\r\n\r\n //console.log(this.filters);\r\n return filters;\r\n }\r\n\r\n public saveDialogFilter(filter: MyDialogFilter, update = true) {\r\n ['pinned_peers', 'exclude_peers', 'include_peers'].forEach(key => {\r\n // @ts-ignore\r\n filter[key] = filter[key].map((peer: any) => this.appPeersManager.getPeerId(peer));\r\n });\r\n\r\n forEachReverse(filter.include_peers, (peerId, idx) => {\r\n if(filter.pinned_peers.includes(peerId)) {\r\n filter.include_peers.splice(idx, 1);\r\n }\r\n });\r\n \r\n filter.include_peers = filter.pinned_peers.concat(filter.include_peers);\r\n\r\n if(this.filters[filter.id]) {\r\n Object.assign(this.filters[filter.id], filter);\r\n } else {\r\n this.filters[filter.id] = filter;\r\n }\r\n\r\n this.setOrderIndex(filter);\r\n\r\n if(update) {\r\n this.rootScope.broadcast('filter_update', filter);\r\n }\r\n }\r\n\r\n public setOrderIndex(filter: MyDialogFilter) {\r\n if(filter.hasOwnProperty('orderIndex')) {\r\n if(filter.orderIndex >= this.orderIndex) {\r\n this.orderIndex = filter.orderIndex + 1;\r\n }\r\n } else {\r\n filter.orderIndex = this.orderIndex++;\r\n }\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n * \r\n * Originally from:\r\n * https://github.com/zhukov/webogram\r\n * Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>\r\n * https://github.com/zhukov/webogram/blob/master/LICENSE\r\n */\r\n\r\nimport { LazyLoadQueueBase } from \"../../components/lazyLoadQueue\";\r\nimport ProgressivePreloader from \"../../components/preloader\";\r\nimport { CancellablePromise, deferredPromise } from \"../../helpers/cancellablePromise\";\r\nimport { tsNow } from \"../../helpers/date\";\r\nimport { createPosterForVideo } from \"../../helpers/files\";\r\nimport { copy, defineNotNumerableProperties, getObjectKeysAndSort } from \"../../helpers/object\";\r\nimport { randomLong } from \"../../helpers/random\";\r\nimport { splitStringByLength, limitSymbols, escapeRegExp } from \"../../helpers/string\";\r\nimport { Chat, ChatFull, Dialog as MTDialog, DialogPeer, DocumentAttribute, InputMedia, InputMessage, InputPeerNotifySettings, InputSingleMedia, Message, MessageAction, MessageEntity, MessageFwdHeader, MessageMedia, MessageReplies, MessageReplyHeader, MessagesDialogs, MessagesFilter, MessagesMessages, MessagesPeerDialogs, MethodDeclMap, NotifyPeer, PeerNotifySettings, PhotoSize, SendMessageAction, Update, Photo } from \"../../layer\";\r\nimport { InvokeApiOptions } from \"../../types\";\r\nimport I18n, { i18n, join, langPack, LangPackKey, _i18n } from \"../langPack\";\r\nimport { logger, LogLevels } from \"../logger\";\r\nimport type { ApiFileManager } from '../mtproto/apiFileManager';\r\n//import apiManager from '../mtproto/apiManager';\r\nimport apiManager from '../mtproto/mtprotoworker';\r\nimport referenceDatabase, { ReferenceContext } from \"../mtproto/referenceDatabase\";\r\nimport serverTimeManager from \"../mtproto/serverTimeManager\";\r\nimport { RichTextProcessor } from \"../richtextprocessor\";\r\nimport rootScope from \"../rootScope\";\r\nimport searchIndexManager from '../searchIndexManager';\r\nimport DialogsStorage from \"../storages/dialogs\";\r\nimport FiltersStorage from \"../storages/filters\";\r\n//import { telegramMeWebService } from \"../mtproto/mtproto\";\r\nimport apiUpdatesManager from \"./apiUpdatesManager\";\r\nimport appChatsManager from \"./appChatsManager\";\r\nimport appDocsManager, { MyDocument } from \"./appDocsManager\";\r\nimport appDownloadManager from \"./appDownloadManager\";\r\nimport appPeersManager from \"./appPeersManager\";\r\nimport appPhotosManager, { MyPhoto } from \"./appPhotosManager\";\r\nimport appPollsManager from \"./appPollsManager\";\r\nimport appStateManager from \"./appStateManager\";\r\nimport appUsersManager from \"./appUsersManager\";\r\nimport appWebPagesManager from \"./appWebPagesManager\";\r\nimport appDraftsManager from \"./appDraftsManager\";\r\nimport pushHeavyTask from \"../../helpers/heavyQueue\";\r\nimport { getFileNameByLocation } from \"../../helpers/fileName\";\r\nimport appProfileManager from \"./appProfileManager\";\r\nimport DEBUG, { MOUNT_CLASS_TO } from \"../../config/debug\";\r\nimport SlicedArray, { Slice, SliceEnd } from \"../../helpers/slicedArray\";\r\nimport appNotificationsManager, { NotifyOptions } from \"./appNotificationsManager\";\r\nimport PeerTitle from \"../../components/peerTitle\";\r\nimport { forEachReverse } from \"../../helpers/array\";\r\nimport { htmlToDocumentFragment, htmlToSpan } from \"../../helpers/dom\";\r\n\r\n//console.trace('include');\r\n// TODO: если удалить сообщение в непрогруженном диалоге, то при обновлении, из-за стейта, последнего сообщения в чатлисте не будет\r\n// TODO: если удалить диалог находясь в папке, то он не удалится из папки и будет виден в настройках\r\n\r\nconst APITIMEOUT = 0;\r\n\r\nexport type HistoryStorage = {\r\n count: number | null,\r\n history: SlicedArray,\r\n\r\n maxId?: number,\r\n readPromise?: Promise<void>,\r\n readMaxId?: number,\r\n readOutboxMaxId?: number,\r\n triedToReadMaxId?: number,\r\n\r\n maxOutId?: number,\r\n reply_markup?: any\r\n};\r\n\r\nexport type HistoryResult = {\r\n count: number,\r\n history: Slice,\r\n offsetIdOffset?: number,\r\n};\r\n\r\nexport type Dialog = MTDialog.dialog;\r\n\r\nexport type MyMessage = Message.message | Message.messageService;\r\nexport type MyInputMessagesFilter = 'inputMessagesFilterEmpty' \r\n | 'inputMessagesFilterPhotos' \r\n | 'inputMessagesFilterPhotoVideo' \r\n | 'inputMessagesFilterVideo' \r\n | 'inputMessagesFilterDocument' \r\n | 'inputMessagesFilterVoice' \r\n | 'inputMessagesFilterRoundVoice' \r\n | 'inputMessagesFilterRoundVideo' \r\n | 'inputMessagesFilterMusic' \r\n | 'inputMessagesFilterUrl' \r\n | 'inputMessagesFilterMyMentions'\r\n | 'inputMessagesFilterChatPhotos'\r\n | 'inputMessagesFilterPinned';\r\n\r\nexport type PinnedStorage = Partial<{\r\n promise: Promise<PinnedStorage>,\r\n count: number,\r\n maxId: number\r\n}>;\r\nexport type MessagesStorage = {\r\n //generateIndex: (message: any) => void\r\n [mid: string]: any\r\n};\r\n\r\nexport type MyMessageActionType = Message.messageService['action']['_'];\r\n\r\nexport class AppMessagesManager {\r\n public static MESSAGE_ID_INCREMENT = 0x10000;\r\n public static MESSAGE_ID_OFFSET = 0xFFFFFFFF;\r\n\r\n public messagesStorageByPeerId: {[peerId: string]: MessagesStorage} = {};\r\n public groupedMessagesStorage: {[groupId: string]: MessagesStorage} = {}; // will be used for albums\r\n public scheduledMessagesStorage: {[peerId: string]: MessagesStorage} = {};\r\n public historiesStorage: {\r\n [peerId: string]: HistoryStorage\r\n } = {};\r\n public threadsStorage: {\r\n [peerId: string]: {\r\n [threadId: string]: HistoryStorage\r\n }\r\n } = {};\r\n public searchesStorage: {\r\n [peerId: string]: Partial<{\r\n [inputFilter in MyInputMessagesFilter]: {\r\n count?: number,\r\n history: number[]\r\n }\r\n }>\r\n } = {};\r\n public pinnedMessages: {[peerId: string]: PinnedStorage} = {};\r\n\r\n public threadsServiceMessagesIdsStorage: {[peerId_threadId: string]: number} = {};\r\n public threadsToReplies: {\r\n [peerId_threadId: string]: string;\r\n } = {};\r\n\r\n public pendingByRandomId: {\r\n [randomId: string]: {\r\n peerId: number,\r\n tempId: number,\r\n threadId: number,\r\n storage: MessagesStorage\r\n }\r\n } = {};\r\n public pendingByMessageId: {[mid: string]: string} = {};\r\n public pendingAfterMsgs: any = {};\r\n public pendingTopMsgs: {[peerId: string]: number} = {};\r\n public sendFilePromise: CancellablePromise<void> = Promise.resolve();\r\n public tempNum = 0;\r\n public tempFinalizeCallbacks: {\r\n [tempId: string]: {\r\n [callbackName: string]: Partial<{\r\n deferred: CancellablePromise<void>, \r\n callback: (message: any) => Promise<any>\r\n }>\r\n }\r\n } = {};\r\n \r\n public sendSmthLazyLoadQueue = new LazyLoadQueueBase(1);\r\n\r\n public needSingleMessages: {[peerId: string]: number[]} = {};\r\n private fetchSingleMessagesPromise: Promise<void> = null;\r\n\r\n public maxSeenId = 0;\r\n\r\n public migratedFromTo: {[peerId: number]: number} = {};\r\n public migratedToFrom: {[peerId: number]: number} = {};\r\n\r\n public newMessagesHandlePromise = 0;\r\n public newMessagesToHandle: {[peerId: string]: Set<number>} = {};\r\n public newDialogsHandlePromise = 0;\r\n public newDialogsToHandle: {[peerId: string]: {reload: true} | Dialog} = {};\r\n public newUpdatesAfterReloadToHandle: {[peerId: string]: Set<Update>} = {};\r\n\r\n private notificationsHandlePromise = 0;\r\n private notificationsToHandle: {[peerId: string]: {\r\n fwdCount: number,\r\n fromId: number,\r\n topMessage?: MyMessage\r\n }} = {};\r\n\r\n private reloadConversationsPromise: Promise<void>;\r\n private reloadConversationsPeers: number[] = [];\r\n\r\n private cachedResults: {\r\n query: string,\r\n count: number,\r\n dialogs: Dialog[],\r\n folderId: number\r\n } = {\r\n query: '',\r\n count: 0,\r\n dialogs: [],\r\n folderId: 0\r\n };\r\n\r\n private log = logger('MESSAGES', LogLevels.error | LogLevels.debug | LogLevels.log | LogLevels.warn);\r\n\r\n public dialogsStorage: DialogsStorage;\r\n public filtersStorage: FiltersStorage;\r\n\r\n private groupedTempId = 0;\r\n\r\n constructor() {\r\n this.dialogsStorage = new DialogsStorage(this, appChatsManager, appPeersManager, serverTimeManager);\r\n this.filtersStorage = new FiltersStorage(this, appPeersManager, appUsersManager, appNotificationsManager, apiUpdatesManager, /* apiManager, */ rootScope);\r\n\r\n rootScope.addMultipleEventsListeners({\r\n updateMessageID: this.onUpdateMessageId,\r\n\r\n updateNewDiscussionMessage: this.onUpdateNewMessage,\r\n updateNewMessage: this.onUpdateNewMessage,\r\n updateNewChannelMessage: this.onUpdateNewMessage,\r\n\r\n updateDialogUnreadMark: this.onUpdateDialogUnreadMark,\r\n\r\n updateFolderPeers: this.onUpdateFolderPeers,\r\n\r\n updateDialogPinned: this.onUpdateDialogPinned,\r\n\r\n updatePinnedDialogs: this.onUpdatePinnedDialogs,\r\n\r\n updateEditMessage: this.onUpdateEditMessage,\r\n updateEditChannelMessage: this.onUpdateEditMessage,\r\n\r\n updateReadChannelDiscussionInbox: this.onUpdateReadHistory,\r\n updateReadChannelDiscussionOutbox: this.onUpdateReadHistory,\r\n updateReadHistoryInbox: this.onUpdateReadHistory,\r\n updateReadHistoryOutbox: this.onUpdateReadHistory,\r\n updateReadChannelInbox: this.onUpdateReadHistory,\r\n updateReadChannelOutbox: this.onUpdateReadHistory,\r\n\r\n updateChannelReadMessagesContents: this.onUpdateReadMessagesContents,\r\n updateReadMessagesContents: this.onUpdateReadMessagesContents,\r\n\r\n updateChannelAvailableMessages: this.onUpdateChannelAvailableMessages,\r\n\r\n updateDeleteMessages: this.onUpdateDeleteMessages,\r\n updateDeleteChannelMessages: this.onUpdateDeleteMessages,\r\n\r\n updateChannel: this.onUpdateChannel,\r\n\r\n // @ts-ignore\r\n updateChannelReload: this.onUpdateChannelReload,\r\n\r\n updateChannelMessageViews: this.onUpdateChannelMessageViews,\r\n\r\n updateServiceNotification: this.onUpdateServiceNotification,\r\n\r\n updatePinnedMessages: this.onUpdatePinnedMessages,\r\n updatePinnedChannelMessages: this.onUpdatePinnedMessages,\r\n\r\n updateNotifySettings: this.onUpdateNotifySettings,\r\n\r\n updateNewScheduledMessage: this.onUpdateNewScheduledMessage,\r\n\r\n updateDeleteScheduledMessages: this.onUpdateDeleteScheduledMessages\r\n });\r\n\r\n // ! Invalidate notify settings, can optimize though\r\n rootScope.on('notify_peer_type_settings', ({key, settings}) => {\r\n this.getConversationsAll().then(dialogs => {\r\n let filterFunc: (dialog: Dialog) => boolean;\r\n if(key === 'notifyUsers') filterFunc = (dialog) => dialog.peerId > 0;\r\n else if(key === 'notifyBroadcasts') filterFunc = (dialog) => appChatsManager.isBroadcast(-dialog.peerId);\r\n else filterFunc = (dialog) => appPeersManager.isAnyGroup(dialog.peerId);\r\n\r\n dialogs\r\n .filter(filterFunc)\r\n .forEach(dialog => {\r\n rootScope.broadcast('dialog_notify_settings', dialog);\r\n });\r\n });\r\n });\r\n\r\n rootScope.on('language_change', (e) => {\r\n const peerId = appUsersManager.getSelf().id;\r\n const dialog = this.getDialogByPeerId(peerId)[0];\r\n if(dialog) {\r\n const peerText = appPeersManager.getPeerSearchText(peerId);\r\n searchIndexManager.indexObject(peerId, peerText, this.dialogsStorage.dialogsIndex);\r\n }\r\n });\r\n\r\n rootScope.on('webpage_updated', (e) => {\r\n const eventData = e;\r\n eventData.msgs.forEach((mid) => {\r\n const message = this.getMessageById(mid) as Message.message;\r\n if(!message) return;\r\n message.media = {\r\n _: 'messageMediaWebPage', \r\n webpage: appWebPagesManager.getWebPage(eventData.id)\r\n };\r\n\r\n const peerId = this.getMessagePeer(message);\r\n const storage = this.getMessagesStorage(peerId);\r\n rootScope.broadcast('message_edit', {\r\n storage,\r\n peerId,\r\n mid\r\n });\r\n });\r\n });\r\n\r\n rootScope.on('draft_updated', (e) => {\r\n const {peerId, threadId, draft} = e;\r\n\r\n if(threadId) return;\r\n\r\n const dialog = this.getDialogByPeerId(peerId)[0];\r\n if(dialog && !threadId) {\r\n dialog.draft = draft;\r\n this.dialogsStorage.generateIndexForDialog(dialog);\r\n this.dialogsStorage.pushDialog(dialog);\r\n\r\n rootScope.broadcast('dialog_draft', {\r\n peerId,\r\n draft,\r\n index: dialog.index\r\n });\r\n } else {\r\n this.reloadConversation(peerId);\r\n }\r\n });\r\n\r\n appStateManager.getState().then(state => {\r\n if(state.maxSeenMsgId) {\r\n this.maxSeenId = state.maxSeenMsgId;\r\n }\r\n\r\n const messages = state.messages;\r\n if(messages) {\r\n /* let tempId = this.tempId;\r\n\r\n for(let message of messages) {\r\n if(message.id < tempId) {\r\n tempId = message.id;\r\n }\r\n }\r\n\r\n if(tempId !== this.tempId) {\r\n this.log('Set tempId to:', tempId);\r\n this.tempId = tempId;\r\n } */\r\n\r\n this.saveMessages(messages);\r\n }\r\n\r\n if(!state.dialogs || !Object.keys(state.dialogs).length) {\r\n state.allDialogsLoaded = {};\r\n }\r\n \r\n if(state.allDialogsLoaded) {\r\n this.dialogsStorage.allDialogsLoaded = state.allDialogsLoaded;\r\n }\r\n\r\n if(state.filters) {\r\n for(const filterId in state.filters) {\r\n this.filtersStorage.saveDialogFilter(state.filters[filterId], false);\r\n }\r\n }\r\n\r\n if(state.dialogs) {\r\n forEachReverse(state.dialogs, dialog => {\r\n dialog.top_message = this.getServerMessageId(dialog.top_message); // * fix outgoing message to avoid copying dialog\r\n\r\n this.saveConversation(dialog);\r\n\r\n // ! WARNING, убрать это когда нужно будет делать чтобы pending сообщения сохранялись\r\n const message = this.getMessageByPeer(dialog.peerId, dialog.top_message);\r\n if(message.deleted) {\r\n this.reloadConversation(dialog.peerId);\r\n }\r\n });\r\n }\r\n\r\n appStateManager.addEventListener('save', this.saveState);\r\n });\r\n\r\n appNotificationsManager.start();\r\n }\r\n\r\n private saveState = () => {\r\n const messages: any[] = [];\r\n const dialogs: Dialog[] = [];\r\n const items: any[] = [];\r\n \r\n const processDialog = (dialog: MTDialog.dialog) => {\r\n const historyStorage = this.getHistoryStorage(dialog.peerId);\r\n const history = [].concat(historyStorage.history.slice);\r\n //dialog = copy(dialog);\r\n let removeUnread = 0;\r\n for(const mid of history) {\r\n const message = this.getMessageByPeer(dialog.peerId, mid);\r\n if(/* message._ !== 'messageEmpty' && */!message.pFlags.is_outgoing) {\r\n messages.push(message);\r\n \r\n if(message.fromId !== dialog.peerId) {\r\n appStateManager.setPeer(message.fromId, appPeersManager.getPeer(message.fromId));\r\n }\r\n \r\n /* dialog.top_message = message.mid;\r\n this.dialogsStorage.generateIndexForDialog(dialog, false, message); */\r\n \r\n break;\r\n } else if(message.pFlags && message.pFlags.unread) {\r\n ++removeUnread;\r\n }\r\n }\r\n \r\n if(removeUnread && dialog.unread_count) dialog.unread_count -= removeUnread;\r\n\r\n if(dialog.peerId < 0 && dialog.pts) {\r\n const newPts = apiUpdatesManager.channelStates[-dialog.peerId].pts;\r\n dialog.pts = newPts;\r\n }\r\n \r\n dialog.unread_count = Math.max(0, dialog.unread_count);\r\n dialogs.push(dialog);\r\n \r\n appStateManager.setPeer(dialog.peerId, appPeersManager.getPeer(dialog.peerId));\r\n };\r\n\r\n for(const folderId in this.dialogsStorage.byFolders) {\r\n const folder = this.dialogsStorage.getFolder(+folderId);\r\n \r\n for(let dialog of folder) {\r\n items.push([dialog]);\r\n }\r\n }\r\n\r\n return pushHeavyTask({\r\n items, \r\n process: processDialog, \r\n context: this\r\n }).then(() => {\r\n appStateManager.pushToState('dialogs', dialogs);\r\n appStateManager.pushToState('messages', messages);\r\n appStateManager.pushToState('filters', this.filtersStorage.filters);\r\n appStateManager.pushToState('allDialogsLoaded', this.dialogsStorage.allDialogsLoaded);\r\n appStateManager.pushToState('maxSeenMsgId', this.maxSeenId);\r\n });\r\n };\r\n\r\n public getInputEntities(entities: MessageEntity[]) {\r\n var sendEntites = copy(entities);\r\n sendEntites.forEach((entity: any) => {\r\n if(entity._ === 'messageEntityMentionName') {\r\n entity._ = 'inputMessageEntityMentionName';\r\n entity.user_id = appUsersManager.getUserInput(entity.user_id);\r\n }\r\n });\r\n return sendEntites;\r\n }\r\n\r\n public invokeAfterMessageIsSent(tempId: number, callbackName: string, callback: (message: any) => Promise<any>) {\r\n const finalize = this.tempFinalizeCallbacks[tempId] ?? (this.tempFinalizeCallbacks[tempId] = {});\r\n const obj = finalize[callbackName] ?? (finalize[callbackName] = {deferred: deferredPromise<void>()});\r\n\r\n obj.callback = callback;\r\n\r\n return obj.deferred;\r\n }\r\n\r\n public editMessage(message: any, text: string, options: Partial<{\r\n noWebPage: true,\r\n newMedia: any,\r\n scheduleDate: number,\r\n entities: MessageEntity[]\r\n }> = {}): Promise<void> {\r\n /* if(!this.canEditMessage(messageId)) {\r\n return Promise.reject({type: 'MESSAGE_EDIT_FORBIDDEN'});\r\n } */\r\n\r\n const {mid, peerId} = message;\r\n\r\n if(message.pFlags.is_outgoing) {\r\n return this.invokeAfterMessageIsSent(mid, 'edit', (message) => {\r\n //this.log('invoke editMessage callback', message);\r\n return this.editMessage(message, text, options);\r\n });\r\n }\r\n\r\n let entities = options.entities || [];\r\n if(text) {\r\n text = RichTextProcessor.parseMarkdown(text, entities);\r\n }\r\n\r\n const schedule_date = options.scheduleDate || (message.pFlags.is_scheduled ? message.date : undefined);\r\n return apiManager.invokeApi('messages.editMessage', {\r\n peer: appPeersManager.getInputPeerById(peerId),\r\n id: message.id,\r\n message: text,\r\n media: options.newMedia,\r\n entities: entities.length ? this.getInputEntities(entities) : undefined,\r\n no_webpage: options.noWebPage,\r\n schedule_date\r\n }).then((updates) => {\r\n apiUpdatesManager.processUpdateMessage(updates);\r\n }, (error) => {\r\n this.log.error('editMessage error:', error);\r\n \r\n if(error && error.type === 'MESSAGE_NOT_MODIFIED') {\r\n error.handled = true;\r\n return;\r\n }\r\n if(error && error.type === 'MESSAGE_EMPTY') {\r\n error.handled = true;\r\n }\r\n return Promise.reject(error);\r\n });\r\n }\r\n\r\n public sendText(peerId: number, text: string, options: Partial<{\r\n entities: any[],\r\n replyToMsgId: number,\r\n threadId: number,\r\n viaBotId: number,\r\n queryId: string,\r\n resultId: string,\r\n noWebPage: true,\r\n reply_markup: any,\r\n clearDraft: true,\r\n webPage: any,\r\n scheduleDate: number,\r\n silent: true\r\n }> = {}) {\r\n if(typeof(text) !== 'string' || !text.length) {\r\n return;\r\n }\r\n\r\n //this.checkSendOptions(options);\r\n\r\n if(options.threadId && !options.replyToMsgId) {\r\n options.replyToMsgId = options.threadId;\r\n }\r\n\r\n const MAX_LENGTH = 4096;\r\n if(text.length > MAX_LENGTH) {\r\n const splitted = splitStringByLength(text, MAX_LENGTH);\r\n text = splitted[0];\r\n\r\n if(splitted.length > 1) {\r\n delete options.webPage;\r\n }\r\n\r\n for(let i = 1; i < splitted.length; ++i) {\r\n setTimeout(() => {\r\n this.sendText(peerId, splitted[i], options);\r\n }, i);\r\n }\r\n }\r\n\r\n peerId = appPeersManager.getPeerMigratedTo(peerId) || peerId;\r\n\r\n let entities = options.entities || [];\r\n if(!options.viaBotId) {\r\n text = RichTextProcessor.parseMarkdown(text, entities);\r\n }\r\n\r\n let sendEntites = this.getInputEntities(entities);\r\n if(!sendEntites.length) {\r\n sendEntites = undefined;\r\n }\r\n\r\n const message = this.generateOutgoingMessage(peerId, options);\r\n message.entities = entities;\r\n message.message = text;\r\n\r\n const replyToMsgId = options.replyToMsgId ? this.getServerMessageId(options.replyToMsgId) : undefined;\r\n const isChannel = appPeersManager.isChannel(peerId);\r\n\r\n if(options.webPage) {\r\n message.media = {\r\n _: 'messageMediaWebPage',\r\n webpage: options.webPage\r\n };\r\n }\r\n\r\n const toggleError = (on: any) => {\r\n if(on) {\r\n message.error = true;\r\n } else {\r\n delete message.error;\r\n }\r\n rootScope.broadcast('messages_pending');\r\n };\r\n\r\n message.send = () => {\r\n toggleError(false);\r\n const sentRequestOptions: InvokeApiOptions = {};\r\n if(this.pendingAfterMsgs[peerId]) {\r\n sentRequestOptions.afterMessageId = this.pendingAfterMsgs[peerId].messageId;\r\n }\r\n\r\n let apiPromise: any;\r\n if(options.viaBotId) {\r\n apiPromise = apiManager.invokeApiAfter('messages.sendInlineBotResult', {\r\n peer: appPeersManager.getInputPeerById(peerId),\r\n random_id: message.random_id,\r\n reply_to_msg_id: replyToMsgId || undefined,\r\n query_id: options.queryId,\r\n id: options.resultId,\r\n clear_draft: options.clearDraft\r\n }, sentRequestOptions);\r\n } else {\r\n apiPromise = apiManager.invokeApiAfter('messages.sendMessage', {\r\n no_webpage: options.noWebPage,\r\n peer: appPeersManager.getInputPeerById(peerId),\r\n message: text,\r\n random_id: message.random_id,\r\n reply_to_msg_id: replyToMsgId || undefined,\r\n entities: sendEntites,\r\n clear_draft: options.clearDraft,\r\n schedule_date: options.scheduleDate || undefined,\r\n silent: options.silent\r\n }, sentRequestOptions);\r\n }\r\n\r\n //this.log('sendText', message.mid);\r\n apiPromise.then((updates: any) => {\r\n //this.log('sendText sent', message.mid);\r\n if(updates._ === 'updateShortSentMessage') {\r\n message.date = updates.date;\r\n message.id = updates.id;\r\n message.media = updates.media;\r\n message.entities = updates.entities;\r\n\r\n // * override with new updates\r\n updates = {\r\n _: 'updates',\r\n users: [],\r\n chats: [],\r\n seq: 0,\r\n updates: [{\r\n _: 'updateMessageID',\r\n random_id: message.random_id,\r\n id: updates.id\r\n }, {\r\n _: options.scheduleDate ? 'updateNewScheduledMessage' : (isChannel ? 'updateNewChannelMessage' : 'updateNewMessage'),\r\n message: message,\r\n pts: updates.pts,\r\n pts_count: updates.pts_count\r\n }]\r\n };\r\n } else if(updates.updates) {\r\n updates.updates.forEach((update: any) => {\r\n if(update._ === 'updateDraftMessage') {\r\n update.local = true;\r\n }\r\n });\r\n }\r\n // Testing bad situations\r\n // var upd = angular.copy(updates)\r\n // updates.updates.splice(0, 1)\r\n\r\n apiUpdatesManager.processUpdateMessage(updates);\r\n\r\n // $timeout(function () {\r\n // ApiUpdatesManager.processUpdateMessage(upd)\r\n // }, 5000)\r\n }, (/* error: any */) => {\r\n toggleError(true);\r\n }).finally(() => {\r\n if(this.pendingAfterMsgs[peerId] === sentRequestOptions) {\r\n delete this.pendingAfterMsgs[peerId];\r\n }\r\n });\r\n\r\n this.pendingAfterMsgs[peerId] = sentRequestOptions;\r\n }\r\n\r\n this.beforeMessageSending(message, {\r\n isScheduled: !!options.scheduleDate || undefined, \r\n threadId: options.threadId,\r\n clearDraft: options.clearDraft\r\n });\r\n }\r\n\r\n public sendFile(peerId: number, file: File | Blob | MyDocument, options: Partial<{\r\n isRoundMessage: true,\r\n isVoiceMessage: true,\r\n isGroupedItem: true,\r\n isMedia: true,\r\n\r\n replyToMsgId: number,\r\n threadId: number,\r\n groupId: string,\r\n caption: string,\r\n entities: MessageEntity[],\r\n width: number,\r\n height: number,\r\n objectURL: string,\r\n thumbBlob: Blob,\r\n thumbURL: string,\r\n duration: number,\r\n background: true,\r\n silent: true,\r\n clearDraft: true,\r\n scheduleDate: number,\r\n\r\n waveform: Uint8Array,\r\n }> = {}) {\r\n peerId = appPeersManager.getPeerMigratedTo(peerId) || peerId;\r\n\r\n //this.checkSendOptions(options);\r\n\r\n const message = this.generateOutgoingMessage(peerId, options);\r\n const replyToMsgId = options.replyToMsgId ? this.getServerMessageId(options.replyToMsgId) : undefined;\r\n\r\n let attachType: string, apiFileName: string;\r\n\r\n const fileType = 'mime_type' in file ? file.mime_type : file.type;\r\n const fileName = file instanceof File ? file.name : '';\r\n const isDocument = !(file instanceof File) && !(file instanceof Blob);\r\n let caption = options.caption || '';\r\n\r\n this.log('sendFile', file, fileType);\r\n\r\n const entities = options.entities || [];\r\n if(caption) {\r\n caption = RichTextProcessor.parseMarkdown(caption, entities);\r\n }\r\n\r\n const attributes: DocumentAttribute[] = [];\r\n\r\n const isPhoto = ['image/jpeg', 'image/png', 'image/bmp'].indexOf(fileType) >= 0;\r\n\r\n let photo: MyPhoto, document: MyDocument;\r\n\r\n let actionName = '';\r\n if(isDocument) { // maybe it's a sticker or gif\r\n attachType = 'document';\r\n apiFileName = '';\r\n } else if(fileType.indexOf('audio/') === 0 || ['video/ogg'].indexOf(fileType) >= 0) {\r\n attachType = 'audio';\r\n apiFileName = 'audio.' + (fileType.split('/')[1] === 'ogg' ? 'ogg' : 'mp3');\r\n actionName = 'sendMessageUploadAudioAction';\r\n\r\n if(options.isVoiceMessage) {\r\n attachType = 'voice';\r\n message.pFlags.media_unread = true;\r\n }\r\n\r\n let attribute: DocumentAttribute.documentAttributeAudio = {\r\n _: 'documentAttributeAudio',\r\n pFlags: {\r\n voice: options.isVoiceMessage\r\n },\r\n waveform: options.waveform,\r\n duration: options.duration || 0\r\n };\r\n\r\n attributes.push(attribute);\r\n } else if(!options.isMedia) {\r\n attachType = 'document';\r\n apiFileName = 'document.' + fileType.split('/')[1];\r\n actionName = 'sendMessageUploadDocumentAction';\r\n } else if(isPhoto) {\r\n attachType = 'photo';\r\n apiFileName = 'photo.' + fileType.split('/')[1];\r\n actionName = 'sendMessageUploadPhotoAction';\r\n\r\n photo = {\r\n _: 'photo',\r\n id: '' + message.id,\r\n sizes: [{\r\n _: 'photoSize',\r\n w: options.width,\r\n h: options.height,\r\n type: 'full',\r\n location: null,\r\n size: file.size\r\n }],\r\n w: options.width,\r\n h: options.height\r\n } as any;\r\n\r\n defineNotNumerableProperties(photo, ['downloaded', 'url']);\r\n photo.downloaded = file.size;\r\n photo.url = options.objectURL || '';\r\n \r\n appPhotosManager.savePhoto(photo);\r\n } else if(fileType.indexOf('video/') === 0) {\r\n attachType = 'video';\r\n apiFileName = 'video.mp4';\r\n actionName = 'sendMessageUploadVideoAction';\r\n\r\n let videoAttribute: DocumentAttribute.documentAttributeVideo = {\r\n _: 'documentAttributeVideo',\r\n pFlags: {\r\n round_message: options.isRoundMessage\r\n }, \r\n duration: options.duration,\r\n w: options.width,\r\n h: options.height\r\n };\r\n\r\n attributes.push(videoAttribute);\r\n } else {\r\n attachType = 'document';\r\n apiFileName = 'document.' + fileType.split('/')[1];\r\n actionName = 'sendMessageUploadDocumentAction';\r\n }\r\n\r\n attributes.push({_: 'documentAttributeFilename', file_name: fileName || apiFileName});\r\n\r\n if(['document', 'video', 'audio', 'voice'].indexOf(attachType) !== -1 && !isDocument) {\r\n const thumbs: PhotoSize[] = [];\r\n document = {\r\n _: 'document',\r\n id: '' + message.id,\r\n duration: options.duration,\r\n attributes,\r\n w: options.width,\r\n h: options.height,\r\n thumbs,\r\n mime_type: fileType,\r\n size: file.size\r\n } as any;\r\n\r\n defineNotNumerableProperties(document, ['downloaded', 'url']);\r\n // @ts-ignore\r\n document.downloaded = file.size;\r\n document.url = options.objectURL || '';\r\n\r\n if(isPhoto) {\r\n attributes.push({\r\n _: 'documentAttributeImageSize',\r\n w: options.width,\r\n h: options.height\r\n });\r\n\r\n thumbs.push({\r\n _: 'photoSize',\r\n w: options.width,\r\n h: options.height,\r\n type: 'full',\r\n location: null,\r\n size: file.size,\r\n url: options.objectURL\r\n });\r\n } else if(attachType === 'video') {\r\n if(options.thumbURL) {\r\n thumbs.push({\r\n _: 'photoSize',\r\n w: options.width,\r\n h: options.height,\r\n type: 'full',\r\n location: null,\r\n size: options.thumbBlob.size,\r\n url: options.thumbURL\r\n });\r\n }\r\n\r\n const thumb = thumbs[0] as PhotoSize.photoSize;\r\n const docThumb = appPhotosManager.getDocumentCachedThumb(document.id);\r\n docThumb.downloaded = thumb.size;\r\n docThumb.url = thumb.url;\r\n }\r\n\r\n /* if(thumbs.length) {\r\n const thumb = thumbs[0] as PhotoSize.photoSize;\r\n const docThumb = appPhotosManager.getDocumentCachedThumb(document.id);\r\n docThumb.downloaded = thumb.size;\r\n docThumb.url = thumb.url;\r\n } */\r\n \r\n appDocsManager.saveDoc(document);\r\n }\r\n\r\n this.log('sendFile', attachType, apiFileName, file.type, options);\r\n\r\n const preloader = isDocument ? undefined : new ProgressivePreloader({\r\n attachMethod: 'prepend',\r\n tryAgainOnFail: false,\r\n isUpload: true\r\n });\r\n\r\n const sentDeferred = deferredPromise<InputMedia>();\r\n\r\n if(preloader) {\r\n preloader.attachPromise(sentDeferred);\r\n sentDeferred.cancel = () => {\r\n const error = new Error('Download canceled');\r\n error.name = 'AbortError';\r\n sentDeferred.reject(error);\r\n };\r\n\r\n sentDeferred.catch(err => {\r\n if(err.name === 'AbortError' && !uploaded) {\r\n this.log('cancelling upload', media);\r\n\r\n sentDeferred.reject(err);\r\n this.cancelPendingMessage(message.random_id);\r\n this.setTyping(peerId, 'sendMessageCancelAction');\r\n\r\n if(uploadPromise?.cancel) {\r\n uploadPromise.cancel();\r\n }\r\n }\r\n });\r\n }\r\n\r\n const media = isDocument ? undefined : {\r\n _: photo ? 'messageMediaPhoto' : 'messageMediaDocument',\r\n pFlags: {},\r\n preloader,\r\n photo,\r\n document,\r\n promise: sentDeferred\r\n };\r\n\r\n message.entities = entities;\r\n message.message = caption;\r\n message.media = isDocument ? {\r\n _: 'messageMediaDocument',\r\n pFlags: {},\r\n document: file \r\n } : media;\r\n\r\n const toggleError = (on: boolean) => {\r\n if(on) {\r\n message.error = true;\r\n } else {\r\n delete message.error;\r\n }\r\n\r\n rootScope.broadcast('messages_pending');\r\n };\r\n\r\n let uploaded = false,\r\n uploadPromise: ReturnType<ApiFileManager['uploadFile']> = null;\r\n\r\n message.send = () => {\r\n if(isDocument) {\r\n const {id, access_hash, file_reference} = file as MyDocument;\r\n\r\n const inputMedia: InputMedia = {\r\n _: 'inputMediaDocument',\r\n id: {\r\n _: 'inputDocument',\r\n id,\r\n access_hash,\r\n file_reference\r\n }\r\n };\r\n \r\n sentDeferred.resolve(inputMedia);\r\n } else if(file instanceof File || file instanceof Blob) {\r\n const load = () => {\r\n if(!uploaded || message.error) {\r\n uploaded = false;\r\n uploadPromise = appDownloadManager.upload(file);\r\n sentDeferred.notifyAll({done: 0, total: file.size});\r\n }\r\n\r\n let thumbUploadPromise: typeof uploadPromise;\r\n if(attachType === 'video' && options.objectURL) {\r\n thumbUploadPromise = new Promise((resolve, reject) => {\r\n const blobPromise = options.thumbBlob ? Promise.resolve(options.thumbBlob) : createPosterForVideo(options.objectURL);\r\n blobPromise.then(blob => {\r\n if(!blob) {\r\n resolve(null);\r\n } else {\r\n appDownloadManager.upload(blob).then(resolve, reject);\r\n }\r\n }, reject);\r\n });\r\n }\r\n \r\n uploadPromise && uploadPromise.then(async(inputFile) => {\r\n /* if(DEBUG) {\r\n this.log('appMessagesManager: sendFile uploaded:', inputFile);\r\n } */\r\n\r\n delete message.media.preloader;\r\n\r\n inputFile.name = apiFileName;\r\n uploaded = true;\r\n let inputMedia: InputMedia;\r\n switch(attachType) {\r\n case 'photo':\r\n inputMedia = {\r\n _: 'inputMediaUploadedPhoto', \r\n file: inputFile\r\n };\r\n break;\r\n\r\n default:\r\n inputMedia = {\r\n _: 'inputMediaUploadedDocument', \r\n file: inputFile, \r\n mime_type: fileType, \r\n attributes\r\n };\r\n }\r\n\r\n if(thumbUploadPromise) {\r\n try {\r\n const inputFile = await thumbUploadPromise;\r\n (inputMedia as InputMedia.inputMediaUploadedDocument).thumb = inputFile;\r\n } catch(err) {\r\n this.log.error('sendFile thumb upload error:', err);\r\n }\r\n }\r\n \r\n sentDeferred.resolve(inputMedia);\r\n }, (/* error */) => {\r\n toggleError(true);\r\n });\r\n \r\n uploadPromise.addNotifyListener((progress: {done: number, total: number}) => {\r\n /* if(DEBUG) {\r\n this.log('upload progress', progress);\r\n } */\r\n\r\n const percents = Math.max(1, Math.floor(100 * progress.done / progress.total));\r\n this.setTyping(peerId, {_: actionName, progress: percents | 0});\r\n sentDeferred.notifyAll(progress);\r\n });\r\n\r\n return sentDeferred;\r\n };\r\n\r\n if(options.isGroupedItem) {\r\n load();\r\n } else {\r\n this.sendSmthLazyLoadQueue.push({\r\n load\r\n });\r\n }\r\n }\r\n\r\n return sentDeferred;\r\n };\r\n\r\n this.beforeMessageSending(message, {\r\n isGroupedItem: options.isGroupedItem, \r\n isScheduled: !!options.scheduleDate || undefined, \r\n threadId: options.threadId,\r\n clearDraft: options.clearDraft\r\n });\r\n\r\n if(!options.isGroupedItem) {\r\n sentDeferred.then(inputMedia => {\r\n this.setTyping(peerId, 'sendMessageCancelAction');\r\n\r\n return apiManager.invokeApi('messages.sendMedia', {\r\n background: options.background,\r\n peer: appPeersManager.getInputPeerById(peerId),\r\n media: inputMedia,\r\n message: caption,\r\n random_id: message.random_id,\r\n reply_to_msg_id: replyToMsgId,\r\n schedule_date: options.scheduleDate,\r\n silent: options.silent,\r\n entities,\r\n clear_draft: options.clearDraft\r\n }).then((updates) => {\r\n apiUpdatesManager.processUpdateMessage(updates);\r\n }, (error) => {\r\n if(attachType === 'photo' &&\r\n error.code === 400 &&\r\n (error.type === 'PHOTO_INVALID_DIMENSIONS' ||\r\n error.type === 'PHOTO_SAVE_FILE_INVALID')) {\r\n error.handled = true;\r\n attachType = 'document';\r\n message.send();\r\n return;\r\n }\r\n\r\n toggleError(true);\r\n });\r\n });\r\n }\r\n\r\n return {message, promise: sentDeferred};\r\n }\r\n\r\n public async sendAlbum(peerId: number, files: File[], options: Partial<{\r\n isMedia: true,\r\n entities: MessageEntity[],\r\n replyToMsgId: number,\r\n threadId: number,\r\n caption: string,\r\n sendFileDetails: Partial<{\r\n duration: number,\r\n width: number,\r\n height: number,\r\n objectURL: string,\r\n thumbBlob: Blob,\r\n thumbURL: string\r\n }>[],\r\n silent: true,\r\n clearDraft: true,\r\n scheduleDate: number\r\n }> = {}) {\r\n //this.checkSendOptions(options);\r\n\r\n if(options.threadId && !options.replyToMsgId) {\r\n options.replyToMsgId = options.threadId;\r\n }\r\n\r\n if(files.length === 1) {\r\n return this.sendFile(peerId, files[0], {...options, ...options.sendFileDetails[0]});\r\n }\r\n\r\n peerId = appPeersManager.getPeerMigratedTo(peerId) || peerId;\r\n const replyToMsgId = options.replyToMsgId ? this.getServerMessageId(options.replyToMsgId) : undefined;\r\n\r\n let caption = options.caption || '';\r\n let entities = options.entities || [];\r\n if(caption) {\r\n caption = RichTextProcessor.parseMarkdown(caption, entities);\r\n }\r\n\r\n this.log('sendAlbum', files, options);\r\n\r\n const groupId = '' + ++this.groupedTempId;\r\n\r\n const messages = files.map((file, idx) => {\r\n const details = options.sendFileDetails[idx];\r\n const o: any = {\r\n isGroupedItem: true,\r\n isMedia: options.isMedia,\r\n scheduleDate: options.scheduleDate,\r\n silent: options.silent,\r\n replyToMsgId,\r\n threadId: options.threadId,\r\n groupId,\r\n ...details\r\n };\r\n\r\n if(idx === 0) {\r\n o.caption = caption;\r\n o.entities = entities;\r\n //o.replyToMsgId = replyToMsgId;\r\n }\r\n\r\n return this.sendFile(peerId, file, o).message;\r\n });\r\n\r\n if(options.threadId) {\r\n appDraftsManager.syncDraft(peerId, options.threadId);\r\n } else {\r\n appDraftsManager.saveDraft(peerId, options.threadId, null, {notify: true}); \r\n }\r\n \r\n // * test pending\r\n //return;\r\n\r\n const toggleError = (message: any, on: boolean) => {\r\n if(on) {\r\n message.error = true;\r\n } else {\r\n delete message.error;\r\n }\r\n\r\n rootScope.broadcast('messages_pending');\r\n };\r\n\r\n const inputPeer = appPeersManager.getInputPeerById(peerId);\r\n const invoke = (multiMedia: any[]) => {\r\n this.setTyping(peerId, 'sendMessageCancelAction');\r\n\r\n this.sendSmthLazyLoadQueue.push({\r\n load: () => {\r\n return apiManager.invokeApi('messages.sendMultiMedia', {\r\n peer: inputPeer,\r\n multi_media: multiMedia,\r\n reply_to_msg_id: replyToMsgId,\r\n schedule_date: options.scheduleDate,\r\n silent: options.silent,\r\n clear_draft: options.clearDraft\r\n }).then((updates) => {\r\n apiUpdatesManager.processUpdateMessage(updates);\r\n }, (error) => {\r\n messages.forEach(message => toggleError(message, true));\r\n });\r\n }\r\n });\r\n };\r\n\r\n const promises: Promise<InputSingleMedia>[] = messages.map((message, idx) => {\r\n return (message.send() as Promise<InputMedia>).then((inputMedia: InputMedia) => {\r\n return apiManager.invokeApi('messages.uploadMedia', {\r\n peer: inputPeer,\r\n media: inputMedia\r\n });\r\n })\r\n .then(messageMedia => {\r\n let inputMedia: any;\r\n if(messageMedia._ === 'messageMediaPhoto') {\r\n const photo = appPhotosManager.savePhoto(messageMedia.photo);\r\n inputMedia = appPhotosManager.getInput(photo);\r\n } else if(messageMedia._ === 'messageMediaDocument') {\r\n const doc = appDocsManager.saveDoc(messageMedia.document);\r\n inputMedia = appDocsManager.getMediaInput(doc);\r\n }\r\n\r\n const inputSingleMedia: InputSingleMedia = {\r\n _: 'inputSingleMedia',\r\n media: inputMedia,\r\n random_id: message.random_id,\r\n message: caption,\r\n entities\r\n };\r\n\r\n // * only 1 caption for all inputs\r\n if(caption) {\r\n caption = '';\r\n entities = [];\r\n }\r\n\r\n return inputSingleMedia;\r\n }).catch((err: any) => {\r\n if(err.name === 'AbortError') {\r\n return null;\r\n }\r\n\r\n this.log.error('sendAlbum upload item error:', err, message);\r\n toggleError(message, true);\r\n throw err;\r\n });\r\n });\r\n\r\n Promise.all(promises).then(inputs => {\r\n invoke(inputs.filter(Boolean));\r\n });\r\n }\r\n\r\n public sendOther(peerId: number, inputMedia: any, options: Partial<{\r\n replyToMsgId: number,\r\n threadId: number,\r\n viaBotId: number,\r\n reply_markup: any,\r\n clearDraft: true,\r\n queryId: string\r\n resultId: string,\r\n scheduleDate: number,\r\n silent: true\r\n }> = {}) {\r\n peerId = appPeersManager.getPeerMigratedTo(peerId) || peerId;\r\n\r\n //this.checkSendOptions(options);\r\n const message = this.generateOutgoingMessage(peerId, options);\r\n const replyToMsgId = options.replyToMsgId ? this.getServerMessageId(options.replyToMsgId) : undefined;\r\n\r\n let media;\r\n switch(inputMedia._) {\r\n case 'inputMediaPoll': {\r\n inputMedia.poll.id = message.id;\r\n appPollsManager.savePoll(inputMedia.poll, {\r\n _: 'pollResults',\r\n flags: 4,\r\n total_voters: 0,\r\n pFlags: {},\r\n });\r\n\r\n const {poll, results} = appPollsManager.getPoll('' + message.id);\r\n media = {\r\n _: 'messageMediaPoll',\r\n poll,\r\n results\r\n };\r\n\r\n break;\r\n }\r\n /* case 'inputMediaPhoto':\r\n media = {\r\n _: 'messageMediaPhoto',\r\n photo: appPhotosManager.getPhoto(inputMedia.id.id),\r\n caption: inputMedia.caption || ''\r\n };\r\n break;\r\n\r\n case 'inputMediaDocument':\r\n var doc = appDocsManager.getDoc(inputMedia.id.id);\r\n if(doc.sticker && doc.stickerSetInput) {\r\n appStickersManager.pushPopularSticker(doc.id);\r\n }\r\n media = {\r\n _: 'messageMediaDocument',\r\n 'document': doc,\r\n caption: inputMedia.caption || ''\r\n };\r\n break;\r\n\r\n case 'inputMediaContact':\r\n media = {\r\n _: 'messageMediaContact',\r\n phone_number: inputMedia.phone_number,\r\n first_name: inputMedia.first_name,\r\n last_name: inputMedia.last_name,\r\n user_id: 0\r\n };\r\n break;\r\n\r\n case 'inputMediaGeoPoint':\r\n media = {\r\n _: 'messageMediaGeo',\r\n geo: {\r\n _: 'geoPoint',\r\n 'lat': inputMedia.geo_point['lat'],\r\n 'long': inputMedia.geo_point['long']\r\n }\r\n };\r\n break;\r\n\r\n case 'inputMediaVenue':\r\n media = {\r\n _: 'messageMediaVenue',\r\n geo: {\r\n _: 'geoPoint',\r\n 'lat': inputMedia.geo_point['lat'],\r\n 'long': inputMedia.geo_point['long']\r\n },\r\n title: inputMedia.title,\r\n address: inputMedia.address,\r\n provider: inputMedia.provider,\r\n venue_id: inputMedia.venue_id\r\n };\r\n break;\r\n\r\n case 'messageMediaPending':\r\n media = inputMedia;\r\n break; */\r\n }\r\n\r\n message.media = media;\r\n\r\n let toggleError = (on: boolean) => {\r\n /* const historyMessage = this.messagesForHistory[messageId];\r\n if (on) {\r\n message.error = true\r\n if (historyMessage) {\r\n historyMessage.error = true\r\n }\r\n } else {\r\n delete message.error\r\n if (historyMessage) {\r\n delete historyMessage.error\r\n }\r\n } */\r\n rootScope.broadcast('messages_pending');\r\n };\r\n\r\n message.send = () => {\r\n const sentRequestOptions: any = {};\r\n if(this.pendingAfterMsgs[peerId]) {\r\n sentRequestOptions.afterMessageId = this.pendingAfterMsgs[peerId].messageId;\r\n }\r\n\r\n let apiPromise: Promise<any>;\r\n if(options.viaBotId) {\r\n apiPromise = apiManager.invokeApiAfter('messages.sendInlineBotResult', {\r\n peer: appPeersManager.getInputPeerById(peerId),\r\n random_id: message.random_id,\r\n reply_to_msg_id: replyToMsgId || undefined,\r\n query_id: options.queryId,\r\n id: options.resultId,\r\n clear_draft: options.clearDraft\r\n }, sentRequestOptions);\r\n } else {\r\n apiPromise = apiManager.invokeApiAfter('messages.sendMedia', {\r\n peer: appPeersManager.getInputPeerById(peerId),\r\n media: inputMedia,\r\n random_id: message.random_id,\r\n reply_to_msg_id: replyToMsgId || undefined,\r\n message: '',\r\n clear_draft: options.clearDraft,\r\n schedule_date: options.scheduleDate,\r\n silent: options.silent\r\n }, sentRequestOptions);\r\n }\r\n\r\n apiPromise.then((updates) => {\r\n if(updates.updates) {\r\n updates.updates.forEach((update: any) => {\r\n if(update._ === 'updateDraftMessage') {\r\n update.local = true\r\n }\r\n });\r\n }\r\n\r\n apiUpdatesManager.processUpdateMessage(updates);\r\n }, (error) => {\r\n toggleError(true);\r\n }).finally(() => {\r\n if(this.pendingAfterMsgs[peerId] === sentRequestOptions) {\r\n delete this.pendingAfterMsgs[peerId];\r\n }\r\n });\r\n this.pendingAfterMsgs[peerId] = sentRequestOptions;\r\n }\r\n\r\n this.beforeMessageSending(message, {\r\n isScheduled: !!options.scheduleDate || undefined, \r\n threadId: options.threadId,\r\n clearDraft: options.clearDraft\r\n });\r\n }\r\n\r\n /* private checkSendOptions(options: Partial<{\r\n scheduleDate: number\r\n }>) {\r\n if(options.scheduleDate) {\r\n const minTimestamp = (Date.now() / 1000 | 0) + 10;\r\n if(options.scheduleDate <= minTimestamp) {\r\n delete options.scheduleDate;\r\n }\r\n }\r\n } */\r\n\r\n private beforeMessageSending(message: any, options: Partial<{\r\n isGroupedItem: true, \r\n isScheduled: true, \r\n threadId: number, \r\n clearDraft: true\r\n }> = {}) {\r\n const messageId = message.id;\r\n const peerId = this.getMessagePeer(message);\r\n const storage = options.isScheduled ? this.getScheduledMessagesStorage(peerId) : this.getMessagesStorage(peerId);\r\n\r\n if(options.isScheduled) {\r\n //if(!options.isGroupedItem) {\r\n this.saveMessages([message], {storage, isScheduled: true, isOutgoing: true});\r\n setTimeout(() => {\r\n rootScope.broadcast('scheduled_new', {peerId, mid: messageId});\r\n }, 0);\r\n } else {\r\n /* if(options.threadId && this.threadsStorage[peerId]) {\r\n delete this.threadsStorage[peerId][options.threadId];\r\n } */\r\n if(options.threadId) {\r\n const historyStorage = this.getHistoryStorage(peerId, options.threadId);\r\n historyStorage.history.unshift(messageId);\r\n }\r\n\r\n const historyStorage = this.getHistoryStorage(peerId);\r\n historyStorage.history.unshift(messageId);\r\n\r\n //if(!options.isGroupedItem) {\r\n this.saveMessages([message], {storage, isOutgoing: true});\r\n setTimeout(() => {\r\n this.setDialogTopMessage(message);\r\n rootScope.broadcast('history_append', {storage, peerId, mid: messageId});\r\n }, 0);\r\n }\r\n\r\n if(!options.isGroupedItem && options.clearDraft) {\r\n if(options.threadId) {\r\n appDraftsManager.syncDraft(peerId, options.threadId);\r\n } else {\r\n appDraftsManager.saveDraft(peerId, options.threadId, null, {notify: true}); \r\n }\r\n }\r\n \r\n this.pendingByRandomId[message.random_id] = {\r\n peerId, \r\n tempId: messageId, \r\n threadId: options.threadId, \r\n storage\r\n };\r\n\r\n if(!options.isGroupedItem && message.send) {\r\n setTimeout(message.send, 0);\r\n //setTimeout(message.send, 4000);\r\n //setTimeout(message.send, 7000);\r\n }\r\n }\r\n\r\n private generateOutgoingMessage(peerId: number, options: Partial<{\r\n scheduleDate: number,\r\n replyToMsgId: number,\r\n threadId: number,\r\n viaBotId: number,\r\n groupId: string,\r\n reply_markup: any,\r\n }>) {\r\n if(options.threadId && !options.replyToMsgId) {\r\n options.replyToMsgId = options.threadId;\r\n }\r\n\r\n const message: any = {\r\n _: 'message',\r\n id: this.generateTempMessageId(peerId),\r\n from_id: this.generateFromId(peerId),\r\n peer_id: appPeersManager.getOutputPeer(peerId),\r\n pFlags: this.generateFlags(peerId),\r\n date: options.scheduleDate || (tsNow(true) + serverTimeManager.serverTimeOffset),\r\n message: '',\r\n grouped_id: options.groupId,\r\n random_id: randomLong(),\r\n reply_to: this.generateReplyHeader(options.replyToMsgId, options.threadId),\r\n via_bot_id: options.viaBotId,\r\n reply_markup: options.reply_markup,\r\n replies: this.generateReplies(peerId),\r\n views: appPeersManager.isBroadcast(peerId) && 1,\r\n pending: true,\r\n };\r\n\r\n return message;\r\n }\r\n\r\n private generateReplyHeader(replyToMsgId: number, replyToTopId?: number) {\r\n const header = {\r\n _: 'messageReplyHeader',\r\n reply_to_msg_id: replyToMsgId || replyToTopId,\r\n } as MessageReplyHeader;\r\n\r\n if(replyToTopId && header.reply_to_msg_id !== replyToTopId) {\r\n header.reply_to_top_id = replyToTopId;\r\n }\r\n\r\n return header;\r\n }\r\n\r\n private generateReplies(peerId: number) {\r\n let replies: MessageReplies.messageReplies;\r\n if(appPeersManager.isBroadcast(peerId)) {\r\n const channelFull = appProfileManager.chatsFull[-peerId] as ChatFull.channelFull;\r\n if(channelFull?.linked_chat_id) {\r\n replies = {\r\n _: 'messageReplies',\r\n flags: 1,\r\n pFlags: {\r\n comments: true\r\n },\r\n channel_id: channelFull.linked_chat_id,\r\n replies: 0,\r\n replies_pts: 0\r\n };\r\n }\r\n }\r\n\r\n return replies;\r\n }\r\n\r\n /**\r\n * Generate correct from_id according to anonymous or broadcast\r\n */\r\n private generateFromId(peerId: number) {\r\n if(peerId < 0 && (appPeersManager.isBroadcast(peerId) || appPeersManager.getPeer(peerId).admin_rights?.pFlags?.anonymous)) {\r\n return undefined;\r\n } else {\r\n return appPeersManager.getOutputPeer(appUsersManager.getSelf().id);\r\n }\r\n }\r\n\r\n private generateFlags(peerId: number) {\r\n const pFlags: any = {};\r\n const fromId = appUsersManager.getSelf().id;\r\n if(peerId !== fromId) {\r\n pFlags.out = true;\r\n\r\n if(!appPeersManager.isChannel(peerId) && !appUsersManager.isBot(peerId)) {\r\n pFlags.unread = true;\r\n }\r\n }\r\n\r\n if(appPeersManager.isBroadcast(peerId)) {\r\n pFlags.post = true;\r\n }\r\n\r\n return pFlags;\r\n }\r\n\r\n private generateForwardHeader(peerId: number, originalMessage: Message.message) {\r\n const myId = appUsersManager.getSelf().id;\r\n if(originalMessage.fromId === myId && originalMessage.peerId === myId && !originalMessage.fwd_from) {\r\n return;\r\n }\r\n\r\n const fwdHeader: MessageFwdHeader.messageFwdHeader = {\r\n _: 'messageFwdHeader',\r\n flags: 0,\r\n date: originalMessage.date\r\n };\r\n\r\n if(originalMessage.fwd_from) {\r\n fwdHeader.from_id = originalMessage.fwd_from.from_id;\r\n fwdHeader.from_name = originalMessage.fwd_from.from_name;\r\n fwdHeader.post_author = originalMessage.fwd_from.post_author;\r\n } else {\r\n fwdHeader.from_id = appPeersManager.getOutputPeer(originalMessage.fromId);\r\n fwdHeader.post_author = originalMessage.post_author;\r\n }\r\n\r\n if(appPeersManager.isBroadcast(originalMessage.peerId)) {\r\n if(originalMessage.post_author) {\r\n fwdHeader.post_author = originalMessage.post_author;\r\n }\r\n\r\n fwdHeader.channel_post = originalMessage.id;\r\n }\r\n \r\n // * there is no way to detect whether user profile is hidden\r\n if(peerId === myId) {\r\n fwdHeader.saved_from_msg_id = originalMessage.id;\r\n fwdHeader.saved_from_peer = appPeersManager.getOutputPeer(originalMessage.peerId);\r\n }\r\n\r\n return fwdHeader;\r\n }\r\n\r\n public generateFakeAvatarMessage(peerId: number, photo: Photo) {\r\n const maxId = Number.MAX_SAFE_INTEGER;\r\n const message = {\r\n _: 'messageService',\r\n action: {\r\n _: 'messageActionChannelEditPhoto',\r\n photo\r\n },\r\n mid: maxId,\r\n peerId,\r\n date: (photo as Photo.photo).date,\r\n fromId: peerId\r\n } as Message.messageService;\r\n\r\n this.getMessagesStorage(peerId)[maxId] = message;\r\n return message;\r\n }\r\n\r\n public setDialogTopMessage(message: MyMessage, dialog: MTDialog.dialog = this.getDialogByPeerId(message.peerId)[0]) {\r\n if(dialog) {\r\n dialog.top_message = message.mid;\r\n \r\n const historyStorage = this.getHistoryStorage(message.peerId);\r\n historyStorage.maxId = message.mid;\r\n\r\n this.dialogsStorage.generateIndexForDialog(dialog, false, message);\r\n\r\n this.newDialogsToHandle[message.peerId] = dialog;\r\n this.scheduleHandleNewDialogs();\r\n }\r\n }\r\n\r\n public cancelPendingMessage(randomId: string) {\r\n const pendingData = this.pendingByRandomId[randomId];\r\n\r\n /* if(DEBUG) {\r\n this.log('cancelPendingMessage', randomId, pendingData);\r\n } */\r\n\r\n if(pendingData) {\r\n const {peerId, tempId, storage} = pendingData;\r\n const historyStorage = this.getHistoryStorage(peerId);\r\n const pos = historyStorage.history.findSlice(tempId);\r\n\r\n apiUpdatesManager.processUpdateMessage({\r\n _: 'updateShort',\r\n update: {\r\n _: 'updateDeleteMessages',\r\n messages: [tempId]\r\n }\r\n });\r\n\r\n if(pos) {\r\n pos.slice.splice(pos.index, 1);\r\n }\r\n\r\n delete this.pendingByRandomId[randomId];\r\n delete storage[tempId];\r\n\r\n return true;\r\n }\r\n\r\n return false;\r\n }\r\n\r\n public async refreshConversations() {\r\n const limit = 100, outDialogs: Dialog[] = [];\r\n for(let folderId = 0; folderId < 2; ++folderId) {\r\n let offsetDate = 0;\r\n for(;;) {\r\n const {dialogs} = await appMessagesManager.getTopMessages(limit, folderId, offsetDate);\r\n \r\n if(dialogs.length) {\r\n outDialogs.push(...dialogs as Dialog[]);\r\n const dialog = dialogs[dialogs.length - 1];\r\n\r\n // * get peerId and mid manually, because dialog can be migrated peer and it won't be saved\r\n const peerId = appPeersManager.getPeerId(dialog.peer);\r\n const mid = this.generateMessageId(dialog.top_message);\r\n offsetDate = this.getMessageByPeer(peerId, mid).date;\r\n\r\n if(!offsetDate) {\r\n console.error('refreshConversations: got no offsetDate', dialog);\r\n break;\r\n }\r\n } else {\r\n break;\r\n }\r\n }\r\n }\r\n\r\n let obj: {[peerId: string]: Dialog} = {};\r\n outDialogs.forEach(dialog => {\r\n obj[dialog.peerId] = dialog;\r\n });\r\n rootScope.broadcast('dialogs_multiupdate', obj);\r\n\r\n return outDialogs;\r\n }\r\n\r\n public async getConversationsAll(query = '', folderId = 0) {\r\n const limit = 100, outDialogs: Dialog[] = [];\r\n for(; folderId < 2; ++folderId) {\r\n let offsetIndex = 0;\r\n for(;;) {\r\n const {dialogs} = await appMessagesManager.getConversations(query, offsetIndex, limit, folderId);\r\n \r\n if(dialogs.length) {\r\n outDialogs.push(...dialogs);\r\n offsetIndex = dialogs[dialogs.length - 1].index || 0;\r\n } else {\r\n break;\r\n }\r\n }\r\n }\r\n\r\n return outDialogs;\r\n }\r\n\r\n public getConversations(query = '', offsetIndex?: number, limit = 20, folderId = 0) {\r\n const realFolderId = folderId > 1 ? 0 : folderId;\r\n let curDialogStorage = this.dialogsStorage.getFolder(folderId);\r\n\r\n if(query) {\r\n if(!limit || this.cachedResults.query !== query || this.cachedResults.folderId !== folderId) {\r\n this.cachedResults.query = query;\r\n this.cachedResults.folderId = folderId;\r\n\r\n const results = searchIndexManager.search(query, this.dialogsStorage.dialogsIndex);\r\n\r\n this.cachedResults.dialogs = [];\r\n\r\n for(const peerId in this.dialogsStorage.dialogs) {\r\n const dialog = this.dialogsStorage.dialogs[peerId];\r\n if(results[dialog.peerId] && dialog.folder_id === folderId) {\r\n this.cachedResults.dialogs.push(dialog);\r\n }\r\n }\r\n\r\n this.cachedResults.dialogs.sort((d1, d2) => d2.index - d1.index);\r\n\r\n this.cachedResults.count = this.cachedResults.dialogs.length;\r\n }\r\n\r\n curDialogStorage = this.cachedResults.dialogs;\r\n } else {\r\n this.cachedResults.query = '';\r\n }\r\n\r\n let offset = 0;\r\n if(offsetIndex > 0) {\r\n for(; offset < curDialogStorage.length; offset++) {\r\n if(offsetIndex > curDialogStorage[offset].index) {\r\n break;\r\n }\r\n }\r\n }\r\n\r\n if(query || this.dialogsStorage.allDialogsLoaded[realFolderId] || curDialogStorage.length >= offset + limit) {\r\n return Promise.resolve({\r\n dialogs: curDialogStorage.slice(offset, offset + limit),\r\n count: this.dialogsStorage.allDialogsLoaded[realFolderId] ? curDialogStorage.length : null,\r\n isEnd: this.dialogsStorage.allDialogsLoaded[realFolderId] && (offset + limit) >= curDialogStorage.length\r\n });\r\n }\r\n\r\n return this.getTopMessages(limit, realFolderId).then(messagesDialogs => {\r\n //const curDialogStorage = this.dialogsStorage[folderId];\r\n\r\n offset = 0;\r\n if(offsetIndex > 0) {\r\n for(; offset < curDialogStorage.length; offset++) {\r\n if(offsetIndex > curDialogStorage[offset].index) {\r\n break;\r\n }\r\n }\r\n }\r\n\r\n //this.log.warn(offset, offset + limit, curDialogStorage.dialogs.length, this.dialogsStorage.dialogs.length);\r\n\r\n return {\r\n dialogs: curDialogStorage.slice(offset, offset + limit),\r\n count: messagesDialogs._ === 'messages.dialogs' ? messagesDialogs.dialogs.length : messagesDialogs.count,\r\n isEnd: this.dialogsStorage.allDialogsLoaded[realFolderId] && (offset + limit) >= curDialogStorage.length\r\n };\r\n });\r\n }\r\n\r\n public getReadMaxIdIfUnread(peerId: number, threadId?: number) {\r\n const historyStorage = this.getHistoryStorage(peerId, threadId);\r\n if(threadId) {\r\n const chatHistoryStorage = this.getHistoryStorage(peerId);\r\n const readMaxId = Math.max(chatHistoryStorage.readMaxId, historyStorage.readMaxId);\r\n const message = this.getMessageByPeer(peerId, historyStorage.maxId);\r\n return !message.pFlags.out && readMaxId < historyStorage.maxId ? readMaxId : 0;\r\n } else {\r\n const message = this.getMessageByPeer(peerId, historyStorage.maxId);\r\n const maxId = peerId > 0 ? Math.max(historyStorage.readMaxId, historyStorage.readOutboxMaxId) : historyStorage.readMaxId;\r\n return !message.pFlags.out && maxId < historyStorage.maxId ? maxId : 0;\r\n }\r\n }\r\n\r\n public getTopMessages(limit: number, folderId: number, offsetDate?: number) {\r\n const dialogs = this.dialogsStorage.getFolder(folderId);\r\n let offsetId = 0;\r\n let offsetPeerId = 0;\r\n let offsetIndex = 0;\r\n\r\n if(offsetDate === undefined) {\r\n offsetDate = this.dialogsStorage.getOffsetDate(folderId);\r\n }\r\n\r\n if(offsetDate) {\r\n offsetIndex = offsetDate * 0x10000;\r\n offsetDate += serverTimeManager.serverTimeOffset;\r\n }\r\n\r\n // ! ВНИМАНИЕ: ОЧЕНЬ СЛОЖНАЯ ЛОГИКА:\r\n // ! если делать запрос сначала по папке 0, потом по папке 1, по индексу 0 в массиве будет один и тот же диалог, с dialog.pFlags.pinned, ЛОЛ???\r\n // ! т.е., с запросом folder_id: 1, и exclude_pinned: 0, в результате будут ещё и закреплённые с папки 0\r\n return apiManager.invokeApi('messages.getDialogs', {\r\n folder_id: folderId,\r\n offset_date: offsetDate,\r\n offset_id: offsetId,\r\n offset_peer: appPeersManager.getInputPeerById(offsetPeerId),\r\n limit,\r\n hash: 0\r\n }, {\r\n //timeout: APITIMEOUT,\r\n noErrorBox: true\r\n }).then((dialogsResult) => {\r\n if(dialogsResult._ === 'messages.dialogsNotModified') return null;\r\n\r\n if(DEBUG) {\r\n this.log('messages.getDialogs result:', dialogsResult.dialogs, {...dialogsResult.dialogs[0]});\r\n }\r\n\r\n /* if(!offsetDate) {\r\n telegramMeWebService.setAuthorized(true);\r\n } */\r\n\r\n appUsersManager.saveApiUsers(dialogsResult.users);\r\n appChatsManager.saveApiChats(dialogsResult.chats);\r\n this.saveMessages(dialogsResult.messages);\r\n\r\n let maxSeenIdIncremented = offsetDate ? true : false;\r\n let hasPrepend = false;\r\n const noIdsDialogs: {[peerId: number]: Dialog} = {};\r\n forEachReverse((dialogsResult.dialogs as Dialog[]), dialog => {\r\n //const d = Object.assign({}, dialog);\r\n // ! нужно передавать folderId, так как по папке !== 0 нет свойства folder_id\r\n this.saveConversation(dialog, dialog.folder_id ?? folderId);\r\n\r\n if(dialog.peerId === undefined) {\r\n return;\r\n }\r\n\r\n /* if(dialog.peerId === -1213511294) {\r\n this.log.error('lun bot', folderId, d);\r\n } */\r\n\r\n if(offsetIndex && dialog.index > offsetIndex) {\r\n this.newDialogsToHandle[dialog.peerId] = dialog;\r\n hasPrepend = true;\r\n }\r\n\r\n // ! это может случиться, если запрос идёт не по папке 0, а по 1. почему-то read'ов нет\r\n // ! в итоге, чтобы получить 1 диалог, делается первый запрос по папке 0, потом запрос для архивных по папке 1, и потом ещё перезагрузка архивного диалога\r\n if(!this.getServerMessageId(dialog.read_inbox_max_id) && !this.getServerMessageId(dialog.read_outbox_max_id)) {\r\n noIdsDialogs[dialog.peerId] = dialog;\r\n\r\n this.log.error('noIdsDialogs', dialog);\r\n\r\n /* if(dialog.peerId === -1213511294) {\r\n this.log.error('lun bot', folderId);\r\n } */\r\n }\r\n\r\n if(!maxSeenIdIncremented &&\r\n !appPeersManager.isChannel(appPeersManager.getPeerId(dialog.peer))) {\r\n this.incrementMaxSeenId(dialog.top_message);\r\n maxSeenIdIncremented = true;\r\n }\r\n });\r\n\r\n if(Object.keys(noIdsDialogs).length) {\r\n //setTimeout(() => { // test bad situation\r\n this.reloadConversation(Object.keys(noIdsDialogs).map(id => +id)).then(() => {\r\n rootScope.broadcast('dialogs_multiupdate', noIdsDialogs);\r\n \r\n for(let peerId in noIdsDialogs) {\r\n rootScope.broadcast('dialog_unread', {peerId: +peerId});\r\n }\r\n });\r\n //}, 10e3);\r\n }\r\n\r\n const count = (dialogsResult as MessagesDialogs.messagesDialogsSlice).count;\r\n\r\n if(!dialogsResult.dialogs.length ||\r\n !count ||\r\n dialogs.length >= count) {\r\n this.dialogsStorage.allDialogsLoaded[folderId] = true;\r\n }\r\n\r\n if(hasPrepend) {\r\n this.scheduleHandleNewDialogs();\r\n } else {\r\n rootScope.broadcast('dialogs_multiupdate', {});\r\n }\r\n\r\n return dialogsResult;\r\n });\r\n }\r\n\r\n public forwardMessages(peerId: number, fromPeerId: number, mids: number[], options: Partial<{\r\n withMyScore: true,\r\n silent: true,\r\n scheduleDate: number\r\n }> = {}) {\r\n peerId = appPeersManager.getPeerMigratedTo(peerId) || peerId;\r\n mids = mids.slice().sort((a, b) => a - b);\r\n\r\n const groups: {\r\n [groupId: string]: {\r\n tempId: string,\r\n messages: any[]\r\n }\r\n } = {};\r\n\r\n const newMessages = mids.map(mid => {\r\n const originalMessage: Message.message = this.getMessageByPeer(fromPeerId, mid);\r\n const message: Message.message = this.generateOutgoingMessage(peerId, options);\r\n message.fwd_from = this.generateForwardHeader(peerId, originalMessage);\r\n\r\n (['entities', 'forwards', 'message', 'media', 'reply_markup', 'views'] as any as Array<keyof MyMessage>).forEach(key => {\r\n // @ts-ignore\r\n message[key] = originalMessage[key];\r\n });\r\n\r\n const document = (message.media as MessageMedia.messageMediaDocument)?.document as MyDocument;\r\n if(document) {\r\n const types: MyDocument['type'][] = ['round', 'voice'];\r\n if(types.includes(document.type)) {\r\n (message as MyMessage).pFlags.media_unread = true;\r\n }\r\n }\r\n\r\n if(originalMessage.grouped_id) {\r\n const group = groups[originalMessage.grouped_id] ?? (groups[originalMessage.grouped_id] = {tempId: '' + ++this.groupedTempId, messages: []});\r\n group.messages.push(message);\r\n }\r\n\r\n return message;\r\n });\r\n\r\n for(const groupId in groups) {\r\n const group = groups[groupId];\r\n if(group.messages.length > 1) {\r\n group.messages.forEach(message => {\r\n message.grouped_id = group.tempId;\r\n });\r\n }\r\n }\r\n\r\n newMessages.forEach(message => {\r\n this.beforeMessageSending(message, {\r\n isScheduled: !!options.scheduleDate || undefined\r\n });\r\n });\r\n\r\n const sentRequestOptions: InvokeApiOptions = {};\r\n if(this.pendingAfterMsgs[peerId]) {\r\n sentRequestOptions.afterMessageId = this.pendingAfterMsgs[peerId].messageId;\r\n }\r\n\r\n const promise = /* true ? Promise.resolve() : */apiManager.invokeApiAfter('messages.forwardMessages', {\r\n from_peer: appPeersManager.getInputPeerById(fromPeerId),\r\n id: mids.map(mid => this.getServerMessageId(mid)),\r\n random_id: newMessages.map(message => message.random_id),\r\n to_peer: appPeersManager.getInputPeerById(peerId),\r\n with_my_score: options.withMyScore,\r\n silent: options.silent,\r\n schedule_date: options.scheduleDate\r\n }, sentRequestOptions).then((updates) => {\r\n this.log('forwardMessages updates:', updates);\r\n apiUpdatesManager.processUpdateMessage(updates);\r\n }).finally(() => {\r\n if(this.pendingAfterMsgs[peerId] === sentRequestOptions) {\r\n delete this.pendingAfterMsgs[peerId];\r\n }\r\n });\r\n\r\n this.pendingAfterMsgs[peerId] = sentRequestOptions;\r\n return promise;\r\n }\r\n\r\n public getMessageFromStorage(storage: MessagesStorage, messageId: number) {\r\n return storage && storage[messageId] || {\r\n _: 'messageEmpty',\r\n id: messageId,\r\n deleted: true,\r\n pFlags: {}\r\n };\r\n }\r\n\r\n private createMessageStorage() {\r\n const storage: MessagesStorage = {} as any;\r\n \r\n /* let num = 0;\r\n Object.defineProperty(storage, 'num', {\r\n get: () => ++num,\r\n set: (_num: number) => num = _num, \r\n enumerable: false\r\n });\r\n\r\n Object.defineProperty(storage, 'generateIndex', {\r\n value: (message: any) => {\r\n if(message.index === undefined) {\r\n message.index = (message.date * 0x10000) + (storage.num & 0xFFFF);\r\n }\r\n },\r\n enumerable: false\r\n }); */\r\n\r\n return storage;\r\n }\r\n\r\n public getMessagesStorage(peerId: number) {\r\n return this.messagesStorageByPeerId[peerId] ?? (this.messagesStorageByPeerId[peerId] = this.createMessageStorage());\r\n }\r\n\r\n public getMessageById(messageId: number) {\r\n for(const peerId in this.messagesStorageByPeerId) {\r\n if(appPeersManager.isChannel(+peerId)) {\r\n continue;\r\n }\r\n\r\n const message = this.messagesStorageByPeerId[peerId][messageId];\r\n if(message) {\r\n return message;\r\n }\r\n }\r\n\r\n return this.getMessageFromStorage(null, messageId);\r\n }\r\n\r\n public getMessageByPeer(peerId: number, messageId: number) {\r\n if(!peerId) {\r\n return this.getMessageById(messageId);\r\n }\r\n\r\n return this.getMessageFromStorage(this.getMessagesStorage(peerId), messageId);\r\n }\r\n\r\n public getMessagePeer(message: any): number {\r\n const toId = message.peer_id && appPeersManager.getPeerId(message.peer_id) || 0;\r\n\r\n return toId;\r\n }\r\n\r\n public getDialogByPeerId(peerId: number): [Dialog, number] | [] {\r\n return this.dialogsStorage.getDialog(peerId);\r\n }\r\n\r\n public reloadConversation(peerId: number | number[]) {\r\n [].concat(peerId).forEach(peerId => {\r\n if(!this.reloadConversationsPeers.includes(peerId)) {\r\n this.reloadConversationsPeers.push(peerId);\r\n //this.log('will reloadConversation', peerId);\r\n }\r\n });\r\n\r\n if(this.reloadConversationsPromise) return this.reloadConversationsPromise;\r\n return this.reloadConversationsPromise = new Promise((resolve, reject) => {\r\n setTimeout(() => {\r\n const peers = this.reloadConversationsPeers.map(peerId => appPeersManager.getInputDialogPeerById(peerId));\r\n this.reloadConversationsPeers.length = 0;\r\n\r\n apiManager.invokeApi('messages.getPeerDialogs', {peers}).then((result) => {\r\n this.applyConversations(result);\r\n resolve();\r\n }, reject).finally(() => {\r\n this.reloadConversationsPromise = null;\r\n });\r\n }, 0);\r\n });\r\n }\r\n\r\n private doFlushHistory(inputPeer: any, justClear?: boolean, revoke?: boolean): Promise<true> {\r\n return apiManager.invokeApi('messages.deleteHistory', {\r\n just_clear: justClear,\r\n revoke: revoke,\r\n peer: inputPeer,\r\n max_id: 0\r\n }).then((affectedHistory) => {\r\n apiUpdatesManager.processUpdateMessage({\r\n _: 'updateShort',\r\n update: {\r\n _: 'updatePts',\r\n pts: affectedHistory.pts,\r\n pts_count: affectedHistory.pts_count\r\n }\r\n });\r\n\r\n if(!affectedHistory.offset) {\r\n return true;\r\n }\r\n\r\n return this.doFlushHistory(inputPeer, justClear);\r\n })\r\n }\r\n\r\n public async flushHistory(peerId: number, justClear?: boolean, revoke?: boolean) {\r\n if(appPeersManager.isChannel(peerId)) {\r\n const promise = this.getHistory(peerId, 0, 1);\r\n\r\n const historyResult = promise instanceof Promise ? await promise : promise;\r\n\r\n const channelId = -peerId;\r\n const maxId = historyResult.history[0] || 0;\r\n return apiManager.invokeApi('channels.deleteHistory', {\r\n channel: appChatsManager.getChannelInput(channelId),\r\n max_id: maxId\r\n }).then(() => {\r\n apiUpdatesManager.processUpdateMessage({\r\n _: 'updateShort',\r\n update: {\r\n _: 'updateChannelAvailableMessages',\r\n channel_id: channelId,\r\n available_min_id: maxId\r\n }\r\n });\r\n\r\n return true;\r\n });\r\n }\r\n\r\n return this.doFlushHistory(appPeersManager.getInputPeerById(peerId), justClear, revoke).then(() => {\r\n delete this.historiesStorage[peerId];\r\n delete this.messagesStorageByPeerId[peerId];\r\n\r\n if(justClear) {\r\n rootScope.broadcast('dialog_flush', {peerId});\r\n } else {\r\n this.dialogsStorage.dropDialog(peerId);\r\n\r\n rootScope.broadcast('dialog_drop', {peerId});\r\n }\r\n });\r\n }\r\n\r\n public hidePinnedMessages(peerId: number) {\r\n return Promise.all([\r\n appStateManager.getState(),\r\n this.getPinnedMessage(peerId)\r\n ])\r\n .then(([state, pinned]) => {\r\n state.hiddenPinnedMessages[peerId] = pinned.maxId;\r\n rootScope.broadcast('peer_pinned_hidden', {peerId, maxId: pinned.maxId});\r\n });\r\n }\r\n\r\n public getPinnedMessage(peerId: number) {\r\n const p = this.pinnedMessages[peerId] ?? (this.pinnedMessages[peerId] = {});\r\n if(p.promise) return p.promise;\r\n else if(p.maxId) return Promise.resolve(p);\r\n\r\n return p.promise = this.getSearch({\r\n peerId, \r\n inputFilter: {_: 'inputMessagesFilterPinned'},\r\n maxId: 0,\r\n limit: 1\r\n }).then(result => {\r\n p.count = result.count;\r\n p.maxId = result.history[0]?.mid;\r\n return p;\r\n }).finally(() => {\r\n delete p.promise;\r\n });\r\n }\r\n\r\n public updatePinnedMessage(peerId: number, mid: number, unpin?: true, silent?: true, oneSide?: true) {\r\n return apiManager.invokeApi('messages.updatePinnedMessage', {\r\n peer: appPeersManager.getInputPeerById(peerId),\r\n unpin,\r\n silent,\r\n pm_oneside: oneSide,\r\n id: this.getServerMessageId(mid)\r\n }).then(updates => {\r\n //this.log('pinned updates:', updates);\r\n apiUpdatesManager.processUpdateMessage(updates);\r\n });\r\n }\r\n\r\n public unpinAllMessages(peerId: number): Promise<boolean> {\r\n return apiManager.invokeApi('messages.unpinAllMessages', {\r\n peer: appPeersManager.getInputPeerById(peerId)\r\n }).then(affectedHistory => {\r\n apiUpdatesManager.processUpdateMessage({\r\n _: 'updateShort',\r\n update: {\r\n _: 'updatePts',\r\n pts: affectedHistory.pts,\r\n pts_count: affectedHistory.pts_count\r\n }\r\n });\r\n\r\n if(!affectedHistory.offset) {\r\n const storage = this.getMessagesStorage(peerId);\r\n for(const mid in storage) {\r\n const message = storage[mid];\r\n if(message.pFlags.pinned) {\r\n delete message.pFlags.pinned;\r\n }\r\n }\r\n\r\n rootScope.broadcast('peer_pinned_messages', {peerId, unpinAll: true});\r\n delete this.pinnedMessages[peerId];\r\n\r\n return true;\r\n }\r\n\r\n return this.unpinAllMessages(peerId);\r\n });\r\n }\r\n\r\n public getAlbumText(grouped_id: string) {\r\n const group = this.groupedMessagesStorage[grouped_id];\r\n let foundMessages = 0, message: string, totalEntities: MessageEntity[], entities: MessageEntity[];\r\n for(const i in group) {\r\n const m = group[i];\r\n if(m.message) {\r\n if(++foundMessages > 1) break;\r\n message = m.message;\r\n totalEntities = m.totalEntities;\r\n entities = m.entities;\r\n } \r\n }\r\n\r\n if(foundMessages > 1) {\r\n message = undefined;\r\n totalEntities = undefined;\r\n entities = undefined;\r\n }\r\n\r\n return {message, entities, totalEntities};\r\n }\r\n\r\n public getMidsByAlbum(grouped_id: string) {\r\n return getObjectKeysAndSort(this.groupedMessagesStorage[grouped_id], 'asc');\r\n //return Object.keys(this.groupedMessagesStorage[grouped_id]).map(id => +id).sort((a, b) => a - b);\r\n }\r\n\r\n public getMidsByMessage(message: any) {\r\n if(message?.grouped_id) return this.getMidsByAlbum(message.grouped_id);\r\n else return [message.mid];\r\n }\r\n\r\n public filterMessages(message: any, verify: (message: MyMessage) => boolean) {\r\n const out: MyMessage[] = [];\r\n if(message.grouped_id) {\r\n const storage = this.groupedMessagesStorage[message.grouped_id];\r\n for(const mid in storage) {\r\n const message = storage[mid];\r\n if(verify(message)) {\r\n out.push(message);\r\n }\r\n }\r\n } else {\r\n if(verify(message)) {\r\n out.push(message);\r\n }\r\n }\r\n\r\n return out;\r\n }\r\n\r\n public generateTempMessageId(peerId: number) {\r\n const dialog = this.getDialogByPeerId(peerId)[0];\r\n return this.generateMessageId(dialog?.top_message || 0, true);\r\n }\r\n\r\n public generateMessageId(messageId: number, temp = false) {\r\n const q = AppMessagesManager.MESSAGE_ID_OFFSET;\r\n const num = temp ? ++this.tempNum : 0;\r\n if(messageId >= q) {\r\n if(temp) {\r\n return messageId + (num & (AppMessagesManager.MESSAGE_ID_INCREMENT - 1));\r\n }\r\n\r\n return messageId;\r\n }\r\n\r\n return q + (messageId * AppMessagesManager.MESSAGE_ID_INCREMENT + (num & (AppMessagesManager.MESSAGE_ID_INCREMENT - 1)));\r\n }\r\n\r\n /**\r\n * * will ignore outgoing offset\r\n */\r\n public getServerMessageId(messageId: number) {\r\n const q = AppMessagesManager.MESSAGE_ID_OFFSET;\r\n if(messageId < q) { // id 0 -> mid 0xFFFFFFFF, so 0xFFFFFFFF must convert to 0\r\n return messageId;\r\n }\r\n\r\n const l = AppMessagesManager.MESSAGE_ID_INCREMENT - 1;\r\n const used = messageId & l;\r\n if(used !== l) {\r\n messageId -= used + 1;\r\n }\r\n\r\n return (messageId - q) / AppMessagesManager.MESSAGE_ID_INCREMENT;\r\n }\r\n\r\n public incrementMessageId(messageId: number, increment: number) {\r\n return this.generateMessageId(this.getServerMessageId(messageId) + increment);\r\n }\r\n\r\n public saveMessages(messages: any[], options: Partial<{\r\n storage: MessagesStorage,\r\n isScheduled: true,\r\n isOutgoing: true,\r\n //isNew: boolean, // * new - from update\r\n }> = {}) {\r\n //let groups: Set<string>;\r\n messages.forEach((message) => {\r\n if(message.pFlags === undefined) {\r\n message.pFlags = {};\r\n }\r\n\r\n if(message._ === 'messageEmpty') {\r\n return;\r\n }\r\n\r\n // * exclude from state\r\n // defineNotNumerableProperties(message, ['rReply', 'mid', 'savedFrom', 'fwdFromId', 'fromId', 'peerId', 'reply_to_mid', 'viaBotId']);\r\n\r\n const peerId = this.getMessagePeer(message);\r\n const storage = options.storage || this.getMessagesStorage(peerId);\r\n const isChannel = message.peer_id._ === 'peerChannel';\r\n const channelId = isChannel ? -peerId : 0;\r\n const isBroadcast = isChannel && appChatsManager.isBroadcast(channelId);\r\n\r\n if(options.isScheduled) {\r\n message.pFlags.is_scheduled = true;\r\n }\r\n\r\n if(options.isOutgoing) {\r\n message.pFlags.is_outgoing = true;\r\n }\r\n \r\n const mid = this.generateMessageId(message.id);\r\n message.mid = mid;\r\n\r\n if(message.grouped_id) {\r\n const storage = this.groupedMessagesStorage[message.grouped_id] ?? (this.groupedMessagesStorage[message.grouped_id] = {});\r\n storage[mid] = message;\r\n }\r\n\r\n const dialog = this.getDialogByPeerId(peerId)[0];\r\n if(dialog && mid) {\r\n if(mid > dialog[message.pFlags.out\r\n ? 'read_outbox_max_id'\r\n : 'read_inbox_max_id']) {\r\n message.pFlags.unread = true;\r\n }\r\n }\r\n // this.log(dT(), 'msg unread', mid, apiMessage.pFlags.out, dialog && dialog[apiMessage.pFlags.out ? 'read_outbox_max_id' : 'read_inbox_max_id'])\r\n\r\n if(message.reply_to) {\r\n if(message.reply_to.reply_to_msg_id) {\r\n message.reply_to.reply_to_msg_id = message.reply_to_mid = this.generateMessageId(message.reply_to.reply_to_msg_id);\r\n } \r\n\r\n if(message.reply_to.reply_to_top_id) message.reply_to.reply_to_top_id = this.generateMessageId(message.reply_to.reply_to_top_id);\r\n }\r\n\r\n if(message.replies) {\r\n if(message.replies.max_id) message.replies.max_id = this.generateMessageId(message.replies.max_id);\r\n if(message.replies.read_max_id) message.replies.read_max_id = this.generateMessageId(message.replies.read_max_id);\r\n }\r\n\r\n const overwriting = !!message.peerId;\r\n if(!overwriting) {\r\n message.date -= serverTimeManager.serverTimeOffset;\r\n }\r\n \r\n //storage.generateIndex(message);\r\n const myId = appUsersManager.getSelf().id;\r\n\r\n message.peerId = peerId;\r\n if(message.peerId === myId/* && !message.from_id && !message.fwd_from */) {\r\n message.fromId = message.fwd_from ? (message.fwd_from.from_id ? appPeersManager.getPeerId(message.fwd_from.from_id) : 0) : myId;\r\n } else {\r\n //message.fromId = message.pFlags.post || (!message.pFlags.out && !message.from_id) ? peerId : appPeersManager.getPeerId(message.from_id);\r\n message.fromId = message.pFlags.post || !message.from_id ? peerId : appPeersManager.getPeerId(message.from_id);\r\n }\r\n\r\n const fwdHeader = message.fwd_from as MessageFwdHeader;\r\n if(fwdHeader) {\r\n //if(peerId === myID) {\r\n if(fwdHeader.saved_from_msg_id) fwdHeader.saved_from_msg_id = this.generateMessageId(fwdHeader.saved_from_msg_id);\r\n if(fwdHeader.channel_post) fwdHeader.channel_post = this.generateMessageId(fwdHeader.channel_post);\r\n\r\n const peer = fwdHeader.saved_from_peer || fwdHeader.from_id;\r\n const msgId = fwdHeader.saved_from_msg_id || fwdHeader.channel_post;\r\n if(peer && msgId) {\r\n const savedFromPeerId = appPeersManager.getPeerId(peer);\r\n const savedFromMid = this.generateMessageId(msgId);\r\n message.savedFrom = savedFromPeerId + '_' + savedFromMid;\r\n }\r\n\r\n /* if(peerId < 0 || peerId === myID) {\r\n message.fromId = appPeersManager.getPeerID(!message.from_id || deepEqual(message.from_id, fwdHeader.from_id) ? fwdHeader.from_id : message.from_id);\r\n } */\r\n /* } else {\r\n apiMessage.fwdPostID = fwdHeader.channel_post;\r\n } */\r\n\r\n message.fwdFromId = appPeersManager.getPeerId(fwdHeader.from_id);\r\n\r\n if(!overwriting) {\r\n fwdHeader.date -= serverTimeManager.serverTimeOffset;\r\n }\r\n }\r\n\r\n if(message.via_bot_id > 0) {\r\n message.viaBotId = message.via_bot_id;\r\n }\r\n\r\n const mediaContext: ReferenceContext = {\r\n type: 'message',\r\n peerId,\r\n messageId: mid\r\n };\r\n\r\n if(message.media) {\r\n switch(message.media._) {\r\n case 'messageMediaEmpty':\r\n delete message.media;\r\n break;\r\n case 'messageMediaPhoto':\r\n if(message.media.ttl_seconds) {\r\n message.media = {_: 'messageMediaUnsupportedWeb'};\r\n } else {\r\n message.media.photo = appPhotosManager.savePhoto(message.media.photo, mediaContext);\r\n }\r\n\r\n if(!message.media.photo) { // * found this bug on test DC\r\n delete message.media;\r\n }\r\n \r\n break;\r\n case 'messageMediaPoll':\r\n message.media.poll = appPollsManager.savePoll(message.media.poll, message.media.results);\r\n break;\r\n case 'messageMediaDocument':\r\n if(message.media.ttl_seconds) {\r\n message.media = {_: 'messageMediaUnsupportedWeb'};\r\n } else {\r\n message.media.document = appDocsManager.saveDoc(message.media.document, mediaContext); // 11.04.2020 warning\r\n }\r\n\r\n break;\r\n case 'messageMediaWebPage':\r\n message.media.webpage = appWebPagesManager.saveWebPage(message.media.webpage, message.mid, mediaContext);\r\n break;\r\n /*case 'messageMediaGame':\r\n AppGamesManager.saveGame(apiMessage.media.game, apiMessage.mid, mediaContext);\r\n apiMessage.media.handleMessage = true;\r\n break; */\r\n case 'messageMediaInvoice':\r\n message.media = {_: 'messageMediaUnsupportedWeb'};\r\n break;\r\n }\r\n }\r\n\r\n if(message.action) {\r\n let migrateFrom: number;\r\n let migrateTo: number;\r\n switch(message.action._) {\r\n //case 'messageActionChannelEditPhoto':\r\n case 'messageActionChatEditPhoto':\r\n message.action.photo = appPhotosManager.savePhoto(message.action.photo, mediaContext);\r\n if(message.action.photo.video_sizes) {\r\n message.action._ = isBroadcast ? 'messageActionChannelEditVideo' : 'messageActionChatEditVideo';\r\n } else {\r\n if(isBroadcast) { // ! messageActionChannelEditPhoto не существует в принципе, это используется для перевода.\r\n message.action._ = 'messageActionChannelEditPhoto';\r\n }\r\n }\r\n break;\r\n\r\n case 'messageActionChatEditTitle':\r\n /* if(options.isNew) {\r\n const chat = appChatsManager.getChat(-peerId);\r\n chat.title = message.action.title;\r\n appChatsManager.saveApiChat(chat, true);\r\n } */\r\n \r\n if(isBroadcast) {\r\n message.action._ = 'messageActionChannelEditTitle';\r\n }\r\n break;\r\n\r\n case 'messageActionChatDeletePhoto':\r\n if(isBroadcast) {\r\n message.action._ = 'messageActionChannelDeletePhoto';\r\n }\r\n break;\r\n\r\n case 'messageActionChatAddUser':\r\n if(message.action.users.length === 1) {\r\n message.action.user_id = message.action.users[0];\r\n if(message.fromId === message.action.user_id) {\r\n let suffix = message.fromId === appUsersManager.getSelf().id ? 'You' : '';\r\n if(isChannel) {\r\n message.action._ = 'messageActionChatJoined' + suffix;\r\n } else {\r\n message.action._ = 'messageActionChatReturn' + suffix;\r\n }\r\n }\r\n } else if(message.action.users.length > 1) {\r\n message.action._ = 'messageActionChatAddUsers';\r\n }\r\n break;\r\n\r\n case 'messageActionChatDeleteUser':\r\n if(message.fromId === message.action.user_id) {\r\n message.action._ = 'messageActionChatLeave';\r\n }\r\n break;\r\n\r\n case 'messageActionChannelMigrateFrom':\r\n migrateFrom = -message.action.chat_id;\r\n migrateTo = -channelId;\r\n break\r\n\r\n case 'messageActionChatMigrateTo':\r\n migrateFrom = -channelId;\r\n migrateTo = -message.action.channel_id;\r\n break;\r\n\r\n case 'messageActionHistoryClear':\r\n //apiMessage.deleted = true;\r\n message.clear_history = true;\r\n delete message.pFlags.out;\r\n delete message.pFlags.unread;\r\n break;\r\n\r\n case 'messageActionPhoneCall':\r\n delete message.fromId;\r\n message.action.type = \r\n (message.pFlags.out ? 'out_' : 'in_') +\r\n (\r\n message.action.reason._ === 'phoneCallDiscardReasonMissed' ||\r\n message.action.reason._ === 'phoneCallDiscardReasonBusy'\r\n ? 'missed'\r\n : 'ok'\r\n );\r\n break;\r\n }\r\n \r\n if(migrateFrom &&\r\n migrateTo &&\r\n !this.migratedFromTo[migrateFrom] &&\r\n !this.migratedToFrom[migrateTo]) {\r\n this.migrateChecks(migrateFrom, migrateTo);\r\n }\r\n }\r\n\r\n /* if(message.grouped_id) {\r\n if(!groups) {\r\n groups = new Set();\r\n }\r\n\r\n groups.add(message.grouped_id);\r\n } else {\r\n message.rReply = this.getRichReplyText(message);\r\n } */\r\n\r\n if(message.message && message.message.length && !message.totalEntities) {\r\n const myEntities = RichTextProcessor.parseEntities(message.message);\r\n const apiEntities = message.entities || [];\r\n message.totalEntities = RichTextProcessor.mergeEntities(apiEntities, myEntities); // ! only in this order, otherwise bold and emoji formatting won't work\r\n }\r\n\r\n storage[mid] = message;\r\n });\r\n\r\n /* if(groups) {\r\n for(const groupId of groups) {\r\n const mids = this.groupedMessagesStorage[groupId];\r\n for(const mid in mids) {\r\n const message = this.groupedMessagesStorage[groupId][mid];\r\n message.rReply = this.getRichReplyText(message);\r\n }\r\n }\r\n } */\r\n }\r\n\r\n public wrapMessageForReply(message: any, text: string, usingMids: number[], plain: true, highlightWord?: string): string;\r\n public wrapMessageForReply(message: any, text?: string, usingMids?: number[], plain?: false, highlightWord?: string): DocumentFragment;\r\n public wrapMessageForReply(message: any, text: string = message.message, usingMids?: number[], plain?: boolean, highlightWord?: string): DocumentFragment | string {\r\n const parts: (HTMLElement | string)[] = [];\r\n\r\n const addPart = (langKey: LangPackKey, part?: string | HTMLElement, text?: string) => {\r\n if(langKey) {\r\n part = plain ? I18n.format(langKey, true) : i18n(langKey);\r\n }\r\n \r\n if(plain) {\r\n parts.push(part);\r\n } else {\r\n const el = document.createElement('i');\r\n if(typeof(part) === 'string') el.innerHTML = part;\r\n else el.append(part);\r\n parts.push(el);\r\n }\r\n\r\n if(text) {\r\n parts.push(', ');\r\n }\r\n };\r\n\r\n if(message.media) {\r\n let usingFullAlbum = true;\r\n if(message.grouped_id) {\r\n if(usingMids) {\r\n const mids = this.getMidsByMessage(message);\r\n if(usingMids.length === mids.length) {\r\n for(const mid of mids) {\r\n if(!usingMids.includes(mid)) {\r\n usingFullAlbum = false;\r\n break;\r\n }\r\n }\r\n } else {\r\n usingFullAlbum = false;\r\n }\r\n }\r\n\r\n if(usingFullAlbum) {\r\n text = this.getAlbumText(message.grouped_id).message;\r\n addPart('AttachAlbum', undefined, text);\r\n }\r\n } else {\r\n usingFullAlbum = false;\r\n }\r\n\r\n if(!usingFullAlbum) {\r\n const media = message.media;\r\n switch(media._) {\r\n case 'messageMediaPhoto':\r\n addPart('AttachPhoto', undefined, message.message);\r\n break;\r\n case 'messageMediaDice':\r\n addPart(undefined, plain ? media.emoticon : RichTextProcessor.wrapEmojiText(media.emoticon));\r\n break;\r\n case 'messageMediaVenue': {\r\n const text = plain ? media.title : RichTextProcessor.wrapEmojiText(media.title);\r\n addPart('AttachLocation', undefined, text);\r\n parts.push(htmlToDocumentFragment(text) as any);\r\n break;\r\n }\r\n case 'messageMediaGeo':\r\n addPart('AttachLocation');\r\n break;\r\n case 'messageMediaGeoLive':\r\n addPart('AttachLiveLocation');\r\n break;\r\n case 'messageMediaPoll':\r\n addPart(undefined, plain ? '📊' + ' ' + (media.poll.question || 'poll') : media.poll.rReply);\r\n break;\r\n case 'messageMediaContact':\r\n addPart('AttachContact');\r\n break;\r\n case 'messageMediaGame': {\r\n const prefix = '🎮' + ' ';\r\n addPart(undefined, plain ? prefix + media.game.title : RichTextProcessor.wrapEmojiText(prefix + media.game.title));\r\n break;\r\n }\r\n case 'messageMediaDocument':\r\n let document = media.document;\r\n \r\n if(document.type === 'video') {\r\n addPart('AttachVideo', undefined, message.message);\r\n } else if(document.type === 'voice') {\r\n addPart('AttachAudio', undefined, message.message);\r\n } else if(document.type === 'gif') {\r\n addPart('AttachGif', undefined, message.message);\r\n } else if(document.type === 'round') {\r\n addPart('AttachRound', undefined, message.message);\r\n } else if(document.type === 'sticker') {\r\n addPart(undefined, ((plain ? document.stickerEmojiRaw : document.stickerEmoji) || '') + 'Sticker');\r\n text = '';\r\n } else {\r\n addPart(document.file_name, undefined, message.message);\r\n }\r\n \r\n break;\r\n \r\n default:\r\n //messageText += media._;\r\n ///////this.log.warn('Got unknown media type!', message);\r\n break;\r\n }\r\n } \r\n }\r\n\r\n if(message.action) {\r\n const actionWrapped = this.wrapMessageActionTextNew(message, plain);\r\n if(actionWrapped) {\r\n addPart(undefined, actionWrapped);\r\n }\r\n }\r\n\r\n if(text) {\r\n text = limitSymbols(text, 100);\r\n\r\n if(plain) {\r\n parts.push(text);\r\n } else {\r\n let entities = RichTextProcessor.parseEntities(text.replace(/\\n/g, ' '));\r\n\r\n if(highlightWord) {\r\n if(!entities) entities = [];\r\n let found = false;\r\n let match: any;\r\n let regExp = new RegExp(escapeRegExp(highlightWord), 'gi');\r\n while((match = regExp.exec(text)) !== null) {\r\n entities.push({_: 'messageEntityHighlight', length: highlightWord.length, offset: match.index});\r\n found = true;\r\n }\r\n \r\n if(found) {\r\n entities.sort((a, b) => a.offset - b.offset);\r\n }\r\n }\r\n\r\n const messageWrapped = RichTextProcessor.wrapRichText(text, {\r\n noLinebreaks: true, \r\n entities, \r\n noLinks: true,\r\n noTextFormat: true\r\n });\r\n \r\n parts.push(htmlToDocumentFragment(messageWrapped) as any);\r\n }\r\n }\r\n\r\n if(plain) {\r\n return parts.join('');\r\n } else {\r\n const fragment = document.createDocumentFragment();\r\n fragment.append(...parts);\r\n return fragment;\r\n }\r\n }\r\n\r\n public getSenderToPeerText(message: MyMessage) {\r\n let senderTitle = '', peerTitle: string;\r\n \r\n senderTitle = message.pFlags.out ? 'You' : appPeersManager.getPeerTitle(message.fromId, false, false);\r\n peerTitle = appPeersManager.isAnyGroup(message.peerId) || (message.pFlags.out && message.peerId !== rootScope.myId) ? \r\n appPeersManager.getPeerTitle(message.peerId, false, false) : \r\n '';\r\n\r\n if(peerTitle) {\r\n senderTitle += ' ➝ ' + peerTitle;\r\n }\r\n\r\n return senderTitle;\r\n }\r\n\r\n public wrapMessageActionTextNew(message: any, plain: true): string;\r\n public wrapMessageActionTextNew(message: any, plain?: false): HTMLElement;\r\n public wrapMessageActionTextNew(message: any, plain: boolean): HTMLElement | string;\r\n public wrapMessageActionTextNew(message: any, plain?: boolean): HTMLElement | string {\r\n const element: HTMLElement = plain ? undefined : document.createElement('span');\r\n const action = message.action as MessageAction;\r\n\r\n // this.log('message action:', action);\r\n\r\n if((action as MessageAction.messageActionCustomAction).message) {\r\n if(plain) {\r\n return RichTextProcessor.wrapPlainText(message.message);\r\n } else {\r\n element.innerHTML = RichTextProcessor.wrapRichText((action as MessageAction.messageActionCustomAction).message, {noLinebreaks: true});\r\n return element;\r\n }\r\n } else {\r\n let _ = action._;\r\n //let suffix = '';\r\n let langPackKey: LangPackKey;\r\n let args: any[];\r\n\r\n const getNameDivHTML = (peerId: number, plain: boolean) => {\r\n return plain ? appPeersManager.getPeerTitle(peerId, plain) + ' ' : (new PeerTitle({peerId})).element;\r\n };\r\n\r\n switch(action._) {\r\n case \"messageActionPhoneCall\": {\r\n _ += '.' + (action as any).type;\r\n\r\n const duration = action.duration || 1;\r\n const d: string[] = [];\r\n \r\n d.push(duration % 60 + ' s');\r\n if(duration >= 60) d.push((duration / 60 | 0) + ' min');\r\n //if(duration >= 3600) d.push((duration / 3600 | 0) + ' h');\r\n\r\n langPackKey = langPack[_];\r\n args = [d.reverse().join(' ')];\r\n break;\r\n }\r\n\r\n case 'messageActionPinMessage':\r\n case 'messageActionContactSignUp':\r\n case 'messageActionChatReturn':\r\n case 'messageActionChatLeave':\r\n case 'messageActionChatJoined':\r\n case 'messageActionChatCreate':\r\n case 'messageActionChatEditPhoto':\r\n case 'messageActionChatDeletePhoto':\r\n case 'messageActionChatEditVideo':\r\n case 'messageActionChatJoinedByLink':\r\n case 'messageActionChannelEditVideo':\r\n case 'messageActionChannelDeletePhoto': {\r\n langPackKey = langPack[_];\r\n args = [getNameDivHTML(message.fromId, plain)];\r\n break;\r\n }\r\n\r\n case 'messageActionChannelEditTitle':\r\n case 'messageActionChatEditTitle': {\r\n langPackKey = langPack[_];\r\n \r\n args = [];\r\n if(action._ === 'messageActionChatEditTitle') {\r\n args.push(getNameDivHTML(message.fromId, plain));\r\n }\r\n\r\n args.push(plain ? action.title : htmlToSpan(RichTextProcessor.wrapEmojiText(action.title)));\r\n break;\r\n }\r\n\r\n case 'messageActionChatDeleteUser':\r\n case 'messageActionChatAddUsers':\r\n case 'messageActionChatAddUser': {\r\n const users: number[] = (action as MessageAction.messageActionChatAddUser).users \r\n || [(action as MessageAction.messageActionChatDeleteUser).user_id];\r\n\r\n langPackKey = langPack[_];\r\n args = [getNameDivHTML(message.fromId, plain)];\r\n\r\n if(users.length > 1) {\r\n if(plain) {\r\n args.push(...users.map((userId: number) => (getNameDivHTML(userId, true) as string).trim()).join(', '));\r\n } else {\r\n const fragment = document.createElement('span');\r\n fragment.append(\r\n ...join(\r\n users.map((userId: number) => getNameDivHTML(userId, false)) as HTMLElement[],\r\n false\r\n )\r\n );\r\n args.push(fragment);\r\n }\r\n } else {\r\n args.push(getNameDivHTML(users[0], plain));\r\n }\r\n\r\n break;\r\n }\r\n\r\n case 'messageActionBotAllowed': {\r\n const anchorHTML = RichTextProcessor.wrapRichText(action.domain, {\r\n entities: [{\r\n _: 'messageEntityUrl',\r\n length: action.domain.length,\r\n offset: 0\r\n }]\r\n });\r\n\r\n const node = htmlToSpan(anchorHTML);\r\n \r\n langPackKey = langPack[_];\r\n args = [node];\r\n break;\r\n }\r\n\r\n default:\r\n langPackKey = (langPack[_] || `[${action._}]`) as any;\r\n break;\r\n }\r\n\r\n if(!langPackKey) {\r\n langPackKey = langPack[_];\r\n if(langPackKey === undefined) {\r\n langPackKey = '[' + _ + ']' as any;\r\n }\r\n }\r\n\r\n if(plain) {\r\n return I18n.format(langPackKey, true, args);\r\n } else {\r\n return _i18n(element, langPackKey, args);\r\n }\r\n\r\n //str = !langPackKey || langPackKey[0].toUpperCase() === langPackKey[0] ? langPackKey : getNameDivHTML(message.fromId) + langPackKey + (suffix ? ' ' : '');\r\n }\r\n }\r\n\r\n public editPeerFolders(peerIds: number[], folderId: number) {\r\n apiManager.invokeApi('folders.editPeerFolders', {\r\n folder_peers: peerIds.map(peerId => {\r\n return {\r\n _: 'inputFolderPeer',\r\n peer: appPeersManager.getInputPeerById(peerId),\r\n folder_id: folderId\r\n };\r\n })\r\n }).then(updates => {\r\n //this.log('editPeerFolders updates:', updates);\r\n apiUpdatesManager.processUpdateMessage(updates); // WARNING! возможно тут нужно добавлять channelId, и вызывать апдейт для каждого канала отдельно\r\n });\r\n }\r\n\r\n public toggleDialogPin(peerId: number, filterId?: number) {\r\n if(filterId > 1) {\r\n this.filtersStorage.toggleDialogPin(peerId, filterId);\r\n return;\r\n }\r\n\r\n const dialog = this.getDialogByPeerId(peerId)[0];\r\n if(!dialog) return Promise.reject();\r\n\r\n const pinned = dialog.pFlags?.pinned ? undefined : true;\r\n return apiManager.invokeApi('messages.toggleDialogPin', {\r\n peer: appPeersManager.getInputDialogPeerById(peerId),\r\n pinned\r\n }).then(bool => {\r\n if(bool) {\r\n const pFlags: Update.updateDialogPinned['pFlags'] = pinned ? {pinned} : {};\r\n this.onUpdateDialogPinned({\r\n _: 'updateDialogPinned',\r\n peer: appPeersManager.getDialogPeer(peerId),\r\n folder_id: filterId,\r\n pFlags\r\n });\r\n }\r\n });\r\n }\r\n\r\n public markDialogUnread(peerId: number, read?: true) {\r\n const dialog = this.getDialogByPeerId(peerId)[0];\r\n if(!dialog) return Promise.reject();\r\n\r\n const unread = read || dialog.pFlags?.unread_mark ? undefined : true;\r\n return apiManager.invokeApi('messages.markDialogUnread', {\r\n peer: appPeersManager.getInputDialogPeerById(peerId),\r\n unread\r\n }).then(bool => {\r\n if(bool) {\r\n const pFlags: Update.updateDialogUnreadMark['pFlags'] = unread ? {unread} : {};\r\n this.onUpdateDialogUnreadMark({\r\n _: 'updateDialogUnreadMark',\r\n peer: appPeersManager.getDialogPeer(peerId),\r\n pFlags\r\n });\r\n }\r\n });\r\n }\r\n\r\n public migrateChecks(migrateFrom: number, migrateTo: number) {\r\n if(!this.migratedFromTo[migrateFrom] &&\r\n !this.migratedToFrom[migrateTo] &&\r\n appChatsManager.hasChat(-migrateTo)) {\r\n const fromChat = appChatsManager.getChat(-migrateFrom);\r\n if(fromChat &&\r\n fromChat.migrated_to &&\r\n fromChat.migrated_to.channel_id === -migrateTo) {\r\n this.migratedFromTo[migrateFrom] = migrateTo;\r\n this.migratedToFrom[migrateTo] = migrateFrom;\r\n\r\n //setTimeout(() => {\r\n rootScope.broadcast('dialog_migrate', {migrateFrom, migrateTo});\r\n\r\n const dropped = this.dialogsStorage.dropDialog(migrateFrom);\r\n if(dropped.length) {\r\n rootScope.broadcast('dialog_drop', {peerId: migrateFrom, dialog: dropped[0]});\r\n }\r\n //}, 100);\r\n }\r\n }\r\n }\r\n\r\n private canMessageBeEdited(message: any, kind: 'text' | 'poll') {\r\n if(message.pFlags.is_outgoing) {\r\n return false;\r\n }\r\n\r\n const goodMedias = [\r\n 'messageMediaPhoto',\r\n 'messageMediaDocument',\r\n 'messageMediaWebPage'\r\n ];\r\n\r\n if(kind === 'poll') {\r\n goodMedias.push('messageMediaPoll');\r\n }\r\n\r\n if(message._ !== 'message' ||\r\n message.deleted ||\r\n message.fwd_from ||\r\n message.via_bot_id ||\r\n message.media && goodMedias.indexOf(message.media._) === -1 ||\r\n message.fromId && appUsersManager.isBot(message.fromId)) {\r\n return false;\r\n }\r\n \r\n if(message.media &&\r\n message.media._ === 'messageMediaDocument' &&\r\n (message.media.document.sticker || message.media.document.type === 'round')) {\r\n return false;\r\n }\r\n\r\n return true;\r\n }\r\n\r\n public canEditMessage(message: any, kind: 'text' | 'poll' = 'text') {\r\n if(!message || !this.canMessageBeEdited(message, kind)) {\r\n return false;\r\n }\r\n\r\n // * second rule for saved messages, because there is no 'out' flag\r\n if(message.pFlags.out || this.getMessagePeer(message) === appUsersManager.getSelf().id) {\r\n return true;\r\n }\r\n\r\n if((message.date < (tsNow(true) - (2 * 86400)) && message.media?._ !== 'messageMediaPoll') || !message.pFlags.out) {\r\n return false;\r\n }\r\n\r\n return true;\r\n }\r\n\r\n public canDeleteMessage(message: any) {\r\n return message && (\r\n message.peerId > 0 \r\n || message.fromId === rootScope.myId \r\n || appChatsManager.getChat(message.peerId)._ === 'chat' \r\n || appChatsManager.hasRights(message.peerId, 'delete_messages')\r\n ) && !message.pFlags.is_outgoing;\r\n }\r\n\r\n public applyConversations(dialogsResult: MessagesPeerDialogs.messagesPeerDialogs) {\r\n // * В эту функцию попадут только те диалоги, в которых есть read_inbox_max_id и read_outbox_max_id, в отличие от тех, что будут в getTopMessages\r\n\r\n // ! fix 'dialogFolder', maybe there is better way to do it, this only can happen by 'messages.getPinnedDialogs' by folder_id: 0\r\n forEachReverse(dialogsResult.dialogs, (dialog, idx) => {\r\n if(dialog._ === 'dialogFolder') {\r\n dialogsResult.dialogs.splice(idx, 1);\r\n }\r\n });\r\n\r\n appUsersManager.saveApiUsers(dialogsResult.users);\r\n appChatsManager.saveApiChats(dialogsResult.chats);\r\n this.saveMessages(dialogsResult.messages);\r\n\r\n this.log('applyConversation', dialogsResult);\r\n\r\n const updatedDialogs: {[peerId: number]: Dialog} = {};\r\n (dialogsResult.dialogs as Dialog[]).forEach((dialog) => {\r\n const peerId = appPeersManager.getPeerId(dialog.peer);\r\n let topMessage = dialog.top_message;\r\n\r\n const topPendingMessage = this.pendingTopMsgs[peerId];\r\n if(topPendingMessage) {\r\n if(!topMessage \r\n || (this.getMessageByPeer(peerId, topPendingMessage) as MyMessage).date > (this.getMessageByPeer(peerId, topMessage) as MyMessage).date) {\r\n dialog.top_message = topMessage = topPendingMessage;\r\n this.getHistoryStorage(peerId).maxId = topPendingMessage;\r\n }\r\n }\r\n\r\n /* const d = Object.assign({}, dialog);\r\n if(peerId === 239602833) {\r\n this.log.error('applyConversation lun', dialog, d);\r\n } */\r\n\r\n if(topMessage || (dialog.draft && dialog.draft._ === 'draftMessage')) {\r\n this.saveConversation(dialog);\r\n updatedDialogs[peerId] = dialog;\r\n } else {\r\n const dropped = this.dialogsStorage.dropDialog(peerId);\r\n if(dropped.length) {\r\n rootScope.broadcast('dialog_drop', {peerId, dialog: dropped[0]});\r\n }\r\n }\r\n\r\n if(this.newUpdatesAfterReloadToHandle[peerId] !== undefined) {\r\n for(const update of this.newUpdatesAfterReloadToHandle[peerId]) {\r\n apiUpdatesManager.saveUpdate(update);\r\n }\r\n\r\n delete this.newUpdatesAfterReloadToHandle[peerId];\r\n }\r\n });\r\n\r\n if(Object.keys(updatedDialogs).length) {\r\n rootScope.broadcast('dialogs_multiupdate', updatedDialogs);\r\n }\r\n }\r\n\r\n public generateDialog(peerId: number) {\r\n const dialog: Dialog = {\r\n _: 'dialog',\r\n pFlags: {},\r\n peer: appPeersManager.getOutputPeer(peerId),\r\n top_message: 0,\r\n read_inbox_max_id: 0,\r\n read_outbox_max_id: 0,\r\n unread_count: 0,\r\n unread_mentions_count: 0,\r\n notify_settings: {\r\n _: 'peerNotifySettings',\r\n },\r\n };\r\n\r\n return dialog;\r\n }\r\n\r\n /**\r\n * Won't save migrated from peer, forbidden peers, left and kicked\r\n */\r\n public saveConversation(dialog: Dialog, folderId = 0) {\r\n const peerId = appPeersManager.getPeerId(dialog.peer);\r\n if(!peerId) {\r\n console.error('saveConversation no peerId???', dialog, folderId);\r\n return false;\r\n }\r\n\r\n if(dialog._ !== 'dialog'/* || peerId === 239602833 */) {\r\n console.error('saveConversation not regular dialog', dialog, Object.assign({}, dialog));\r\n }\r\n \r\n const channelId = appPeersManager.isChannel(peerId) ? -peerId : 0;\r\n\r\n if(peerId < 0) {\r\n const chat: Chat = appChatsManager.getChat(-peerId);\r\n if(chat._ === 'channelForbidden' || chat._ === 'chatForbidden' || (chat as Chat.chat).pFlags.left || (chat as Chat.chat).pFlags.kicked) {\r\n return false;\r\n }\r\n }\r\n\r\n const peerText = appPeersManager.getPeerSearchText(peerId);\r\n searchIndexManager.indexObject(peerId, peerText, this.dialogsStorage.dialogsIndex);\r\n\r\n let mid: number, message;\r\n if(dialog.top_message) {\r\n mid = this.generateMessageId(dialog.top_message);//dialog.top_message;\r\n message = this.getMessageByPeer(peerId, mid);\r\n } else {\r\n mid = this.generateTempMessageId(peerId);\r\n message = {\r\n _: 'message',\r\n id: mid,\r\n mid,\r\n from_id: appPeersManager.getOutputPeer(appUsersManager.getSelf().id),\r\n peer_id: appPeersManager.getOutputPeer(peerId),\r\n deleted: true,\r\n pFlags: {out: true},\r\n date: 0,\r\n message: ''\r\n };\r\n this.saveMessages([message], {isOutgoing: true});\r\n }\r\n\r\n if(!message?.pFlags) {\r\n this.log.error('saveConversation no message:', dialog, message);\r\n }\r\n\r\n if(!channelId && peerId < 0) {\r\n const chat = appChatsManager.getChat(-peerId);\r\n if(chat && chat.migrated_to && chat.pFlags.deactivated) {\r\n const migratedToPeer = appPeersManager.getPeerId(chat.migrated_to);\r\n this.migratedFromTo[peerId] = migratedToPeer;\r\n this.migratedToFrom[migratedToPeer] = peerId;\r\n return;\r\n }\r\n }\r\n\r\n const wasDialogBefore = this.getDialogByPeerId(peerId)[0];\r\n\r\n dialog.top_message = mid;\r\n dialog.read_inbox_max_id = this.generateMessageId(wasDialogBefore && !dialog.read_inbox_max_id ? wasDialogBefore.read_inbox_max_id : dialog.read_inbox_max_id);\r\n dialog.read_outbox_max_id = this.generateMessageId(wasDialogBefore && !dialog.read_outbox_max_id ? wasDialogBefore.read_outbox_max_id : dialog.read_outbox_max_id);\r\n\r\n if(!dialog.hasOwnProperty('folder_id')) {\r\n if(dialog._ === 'dialog') {\r\n // ! СЛОЖНО ! СМОТРИ В getTopMessages\r\n dialog.folder_id = wasDialogBefore ? wasDialogBefore.folder_id : folderId;\r\n }/* else if(dialog._ === 'dialogFolder') {\r\n dialog.folder_id = dialog.folder.id;\r\n } */\r\n }\r\n\r\n dialog.draft = appDraftsManager.saveDraft(peerId, 0, dialog.draft);\r\n dialog.peerId = peerId;\r\n\r\n // Because we saved message without dialog present\r\n if(message.pFlags.is_outgoing) {\r\n if(mid > dialog[message.pFlags.out ? 'read_outbox_max_id' : 'read_inbox_max_id']) message.pFlags.unread = true;\r\n else delete message.pFlags.unread;\r\n }\r\n\r\n let historyStorage = this.getHistoryStorage(peerId);\r\n /* if(historyStorage === undefined) { // warning\r\n historyStorage.history.push(mid);\r\n if(this.mergeReplyKeyboard(historyStorage, message)) {\r\n rootScope.broadcast('history_reply_markup', {peerId});\r\n }\r\n } else */if(!historyStorage.history.slice.length) {\r\n historyStorage.history.unshift(mid);\r\n }\r\n\r\n historyStorage.maxId = mid;\r\n historyStorage.readMaxId = dialog.read_inbox_max_id;\r\n historyStorage.readOutboxMaxId = dialog.read_outbox_max_id;\r\n\r\n appNotificationsManager.savePeerSettings(peerId, dialog.notify_settings)\r\n\r\n if(channelId && dialog.pts) {\r\n apiUpdatesManager.addChannelState(channelId, dialog.pts);\r\n }\r\n\r\n this.dialogsStorage.generateIndexForDialog(dialog);\r\n this.dialogsStorage.pushDialog(dialog, message.date);\r\n }\r\n\r\n public mergeReplyKeyboard(historyStorage: HistoryStorage, message: any) {\r\n // this.log('merge', message.mid, message.reply_markup, historyStorage.reply_markup)\r\n if(!message.reply_markup &&\r\n !message.pFlags?.out &&\r\n !message.action) {\r\n return false;\r\n }\r\n if(message.reply_markup &&\r\n message.reply_markup._ === 'replyInlineMarkup') {\r\n return false;\r\n }\r\n var messageReplyMarkup = message.reply_markup;\r\n var lastReplyMarkup = historyStorage.reply_markup;\r\n if(messageReplyMarkup) {\r\n if(lastReplyMarkup && lastReplyMarkup.mid >= message.mid) {\r\n return false;\r\n }\r\n\r\n if(messageReplyMarkup.pFlags.selective) {\r\n return false;\r\n }\r\n\r\n if(historyStorage.maxOutId &&\r\n message.mid < historyStorage.maxOutId &&\r\n messageReplyMarkup.pFlags.single_use) {\r\n messageReplyMarkup.pFlags.hidden = true;\r\n }\r\n messageReplyMarkup = Object.assign({\r\n mid: message.mid\r\n }, messageReplyMarkup);\r\n if(messageReplyMarkup._ !== 'replyKeyboardHide') {\r\n messageReplyMarkup.fromId = appPeersManager.getPeerId(message.from_id);\r\n }\r\n historyStorage.reply_markup = messageReplyMarkup;\r\n // this.log('set', historyStorage.reply_markup)\r\n return true;\r\n }\r\n\r\n if(message.pFlags.out) {\r\n if(lastReplyMarkup) {\r\n if(lastReplyMarkup.pFlags.single_use &&\r\n !lastReplyMarkup.pFlags.hidden &&\r\n (message.mid > lastReplyMarkup.mid || message.pFlags.is_outgoing) &&\r\n message.message) {\r\n lastReplyMarkup.pFlags.hidden = true;\r\n // this.log('set', historyStorage.reply_markup)\r\n return true;\r\n }\r\n } else if(!historyStorage.maxOutId ||\r\n message.mid > historyStorage.maxOutId) {\r\n historyStorage.maxOutId = message.mid;\r\n }\r\n }\r\n\r\n if(message.action &&\r\n message.action._ === 'messageActionChatDeleteUser' &&\r\n (lastReplyMarkup\r\n ? message.action.user_id === lastReplyMarkup.fromId\r\n : appUsersManager.isBot(message.action.user_id)\r\n )\r\n ) {\r\n historyStorage.reply_markup = {\r\n _: 'replyKeyboardHide',\r\n mid: message.mid,\r\n pFlags: {}\r\n };\r\n // this.log('set', historyStorage.reply_markup)\r\n return true;\r\n }\r\n\r\n return false;\r\n }\r\n\r\n public getSearchStorage(peerId: number, inputFilter: MyInputMessagesFilter) {\r\n if(!this.searchesStorage[peerId]) this.searchesStorage[peerId] = {};\r\n if(!this.searchesStorage[peerId][inputFilter]) this.searchesStorage[peerId][inputFilter] = {history: []};\r\n return this.searchesStorage[peerId][inputFilter];\r\n }\r\n\r\n public getSearchCounters(peerId: number, filters: MessagesFilter[], canCache = true) {\r\n const func = (canCache ? apiManager.invokeApiCacheable : apiManager.invokeApi).bind(apiManager);\r\n return func('messages.getSearchCounters', {\r\n peer: appPeersManager.getInputPeerById(peerId),\r\n filters\r\n });\r\n }\r\n\r\n public getSearch({peerId, query, inputFilter, maxId, limit, nextRate, backLimit, threadId, folderId, minDate, maxDate}: {\r\n peerId?: number,\r\n maxId?: number,\r\n limit?: number,\r\n nextRate?: number,\r\n backLimit?: number,\r\n threadId?: number,\r\n folderId?: number,\r\n query?: string,\r\n inputFilter?: {\r\n _: MyInputMessagesFilter\r\n },\r\n minDate?: number,\r\n maxDate?: number\r\n }): Promise<{\r\n count: number,\r\n next_rate: number,\r\n offset_id_offset: number,\r\n history: MyMessage[]\r\n }> {\r\n if(!peerId) peerId = 0;\r\n if(!query) query = '';\r\n if(!inputFilter) inputFilter = {_: 'inputMessagesFilterEmpty'};\r\n if(limit === undefined) limit = 20;\r\n if(!nextRate) nextRate = 0;\r\n if(!backLimit) backLimit = 0;\r\n\r\n minDate = minDate ? minDate / 1000 | 0 : 0;\r\n maxDate = maxDate ? maxDate / 1000 | 0 : 0;\r\n\r\n const foundMsgs: Message.message[] = [];\r\n\r\n //this.log('search', maxId);\r\n\r\n if(backLimit) {\r\n limit += backLimit;\r\n }\r\n\r\n //const beta = inputFilter._ === 'inputMessagesFilterPinned' && !backLimit;\r\n const beta = false;\r\n\r\n let storage: {\r\n count?: number;\r\n history: SlicedArray;\r\n };\r\n\r\n // * костыль для limit 1, если нужно и получить сообщение, и узнать количество сообщений\r\n if(peerId && !backLimit && !maxId && !query && limit !== 1 && !threadId/* && inputFilter._ !== 'inputMessagesFilterPinned' */) {\r\n storage = beta ? \r\n this.getSearchStorage(peerId, inputFilter._) as any : \r\n this.getHistoryStorage(peerId);\r\n let filtering = true;\r\n\r\n const history = /* maxId ? storage.history.slice(storage.history.indexOf(maxId) + 1) : */storage.history;\r\n\r\n if(storage !== undefined && history.length) {\r\n const neededContents: {\r\n [messageMediaType: string]: boolean\r\n } = {},\r\n neededDocTypes: string[] = [], \r\n excludeDocTypes: string[] = []/* ,\r\n neededFlags: string[] = [] */;\r\n\r\n switch(inputFilter._) {\r\n case 'inputMessagesFilterPhotos':\r\n neededContents['messageMediaPhoto'] = true;\r\n break;\r\n\r\n case 'inputMessagesFilterPhotoVideo':\r\n neededContents['messageMediaPhoto'] = true;\r\n neededContents['messageMediaDocument'] = true;\r\n neededDocTypes.push('video');\r\n break;\r\n\r\n case 'inputMessagesFilterVideo':\r\n neededContents['messageMediaDocument'] = true;\r\n neededDocTypes.push('video');\r\n break;\r\n\r\n case 'inputMessagesFilterDocument':\r\n neededContents['messageMediaDocument'] = true;\r\n excludeDocTypes.push('video');\r\n break;\r\n\r\n case 'inputMessagesFilterVoice':\r\n neededContents['messageMediaDocument'] = true;\r\n neededDocTypes.push('voice');\r\n break;\r\n\r\n case 'inputMessagesFilterRoundVoice':\r\n neededContents['messageMediaDocument'] = true;\r\n neededDocTypes.push('round', 'voice');\r\n break;\r\n\r\n case 'inputMessagesFilterRoundVideo':\r\n neededContents['messageMediaDocument'] = true;\r\n neededDocTypes.push('round');\r\n break;\r\n\r\n case 'inputMessagesFilterMusic':\r\n neededContents['messageMediaDocument'] = true;\r\n neededDocTypes.push('audio');\r\n break;\r\n\r\n case 'inputMessagesFilterUrl':\r\n neededContents['url'] = true;\r\n break;\r\n\r\n case 'inputMessagesFilterChatPhotos':\r\n neededContents['avatar'] = true;\r\n break;\r\n\r\n /* case 'inputMessagesFilterPinned':\r\n neededFlags.push('pinned');\r\n break; */\r\n\r\n /* case 'inputMessagesFilterMyMentions':\r\n neededContents['mentioned'] = true;\r\n break; */\r\n\r\n default:\r\n filtering = false;\r\n break;\r\n /* return Promise.resolve({\r\n count: 0,\r\n next_rate: 0,\r\n history: [] as number[]\r\n }); */\r\n }\r\n\r\n if(filtering) {\r\n const storage = this.getMessagesStorage(peerId);\r\n for(let i = 0, length = history.length; i < length; i++) {\r\n const message = storage[history.slice[i]];\r\n\r\n if(!message) continue;\r\n \r\n //|| (neededContents['mentioned'] && message.totalEntities.find((e: any) => e._ === 'messageEntityMention'));\r\n \r\n let found = false;\r\n if(message.media && neededContents[message.media._] && !message.fwd_from) {\r\n if(message.media._ === 'messageMediaDocument') {\r\n if((neededDocTypes.length && !neededDocTypes.includes(message.media.document.type)) \r\n || excludeDocTypes.includes(message.media.document.type)) {\r\n continue;\r\n }\r\n }\r\n \r\n found = true;\r\n } else if(neededContents['url'] && message.message) {\r\n const goodEntities = ['messageEntityTextUrl', 'messageEntityUrl'];\r\n if((message.totalEntities as MessageEntity[]).find(e => goodEntities.includes(e._)) || RichTextProcessor.matchUrl(message.message)) {\r\n found = true;\r\n }\r\n } else if(neededContents['avatar'] && message.action && ['messageActionChannelEditPhoto', 'messageActionChatEditPhoto', 'messageActionChannelEditVideo', 'messageActionChatEditVideo'].includes(message.action._)) {\r\n found = true;\r\n }/* else if(neededFlags.find(flag => message.pFlags[flag])) {\r\n found = true;\r\n } */\r\n \r\n if(found) {\r\n foundMsgs.push(message);\r\n if(foundMsgs.length >= limit) {\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n if(foundMsgs.length) {\r\n if(foundMsgs.length < limit && (beta ? storage.count !== storage.history.length : true)) {\r\n maxId = foundMsgs[foundMsgs.length - 1].mid;\r\n limit = limit - foundMsgs.length;\r\n } else {\r\n return Promise.resolve({\r\n count: beta ? storage.count : 0,\r\n next_rate: 0,\r\n offset_id_offset: 0,\r\n history: foundMsgs\r\n });\r\n }\r\n } else if(beta && storage?.count) {\r\n return Promise.resolve({\r\n count: storage.count,\r\n next_rate: 0,\r\n offset_id_offset: 0,\r\n history: []\r\n });\r\n }\r\n\r\n const canCache = false && (['inputMessagesFilterChatPhotos', 'inputMessagesFilterPinned'] as MyInputMessagesFilter[]).includes(inputFilter._);\r\n const method = (canCache ? apiManager.invokeApiCacheable : apiManager.invokeApi).bind(apiManager);\r\n\r\n let apiPromise: Promise<any>;\r\n if(peerId && !nextRate && folderId === undefined/* || !query */) {\r\n apiPromise = method('messages.search', {\r\n peer: appPeersManager.getInputPeerById(peerId),\r\n q: query || '',\r\n filter: inputFilter as any as MessagesFilter,\r\n min_date: minDate,\r\n max_date: maxDate,\r\n limit,\r\n offset_id: this.getServerMessageId(maxId) || 0,\r\n add_offset: backLimit ? -backLimit : 0,\r\n max_id: 0,\r\n min_id: 0,\r\n hash: 0,\r\n top_msg_id: this.getServerMessageId(threadId) || 0\r\n }, {\r\n //timeout: APITIMEOUT,\r\n noErrorBox: true\r\n });\r\n } else {\r\n //var offsetDate = 0;\r\n let offsetPeerId = 0;\r\n let offsetId = 0;\r\n let offsetMessage = maxId && this.getMessageByPeer(peerId, maxId);\r\n\r\n if(offsetMessage && offsetMessage.date) {\r\n //offsetDate = offsetMessage.date + serverTimeManager.serverTimeOffset;\r\n offsetId = offsetMessage.id;\r\n offsetPeerId = this.getMessagePeer(offsetMessage);\r\n }\r\n\r\n apiPromise = method('messages.searchGlobal', {\r\n q: query,\r\n filter: inputFilter as any as MessagesFilter,\r\n min_date: minDate,\r\n max_date: maxDate,\r\n offset_rate: nextRate,\r\n offset_peer: appPeersManager.getInputPeerById(offsetPeerId),\r\n offset_id: offsetId,\r\n limit,\r\n folder_id: folderId\r\n }, {\r\n //timeout: APITIMEOUT,\r\n noErrorBox: true\r\n });\r\n }\r\n\r\n return apiPromise.then((searchResult: any) => {\r\n appUsersManager.saveApiUsers(searchResult.users);\r\n appChatsManager.saveApiChats(searchResult.chats);\r\n this.saveMessages(searchResult.messages);\r\n\r\n /* if(beta && storage && (!maxId || storage.history[storage.history.length - 1] === maxId)) {\r\n const storage = this.getSearchStorage(peerId, inputFilter._);\r\n const add = (searchResult.messages.map((m: any) => m.mid) as number[]).filter(mid => storage.history.indexOf(mid) === -1);\r\n storage.history.push(...add);\r\n storage.history.sort((a, b) => b - a);\r\n storage.count = searchResult.count;\r\n } */\r\n\r\n if(DEBUG) {\r\n this.log('getSearch result:', inputFilter, searchResult);\r\n }\r\n\r\n const foundCount: number = searchResult.count || (foundMsgs.length + searchResult.messages.length);\r\n\r\n searchResult.messages.forEach((message: any) => {\r\n const peerId = this.getMessagePeer(message);\r\n if(peerId < 0) {\r\n const chat = appChatsManager.getChat(-peerId);\r\n if(chat.migrated_to) {\r\n this.migrateChecks(peerId, -chat.migrated_to.channel_id);\r\n }\r\n }\r\n\r\n foundMsgs.push(message);\r\n });\r\n\r\n return {\r\n count: foundCount,\r\n offset_id_offset: searchResult.offset_id_offset || 0,\r\n next_rate: searchResult.next_rate,\r\n history: foundMsgs\r\n };\r\n });\r\n }\r\n\r\n public subscribeRepliesThread(peerId: number, mid: number) {\r\n const repliesKey = peerId + '_' + mid;\r\n for(const threadKey in this.threadsToReplies) {\r\n if(this.threadsToReplies[threadKey] === repliesKey) return;\r\n }\r\n\r\n this.getDiscussionMessage(peerId, mid);\r\n }\r\n\r\n public generateThreadServiceStartMessage(message: Message.message) {\r\n const threadKey = message.peerId + '_' + message.mid;\r\n if(this.threadsServiceMessagesIdsStorage[threadKey]) return;\r\n\r\n const maxMessageId = this.getServerMessageId(Math.max(...this.getMidsByMessage(message)));\r\n const serviceStartMessage: Message.messageService = {\r\n _: 'messageService',\r\n pFlags: {\r\n is_single: true\r\n } as any,\r\n id: this.generateMessageId(maxMessageId, true),\r\n date: message.date,\r\n from_id: {_: 'peerUser', user_id: 0}/* message.from_id */,\r\n peer_id: message.peer_id,\r\n action: {\r\n _: 'messageActionCustomAction',\r\n message: 'Discussion started'\r\n },\r\n reply_to: this.generateReplyHeader(message.id)\r\n };\r\n\r\n this.saveMessages([serviceStartMessage], {isOutgoing: true});\r\n this.threadsServiceMessagesIdsStorage[threadKey] = serviceStartMessage.mid;\r\n } \r\n\r\n public getDiscussionMessage(peerId: number, mid: number) {\r\n return apiManager.invokeApi('messages.getDiscussionMessage', {\r\n peer: appPeersManager.getInputPeerById(peerId),\r\n msg_id: this.getServerMessageId(mid)\r\n }).then(result => {\r\n appChatsManager.saveApiChats(result.chats);\r\n appUsersManager.saveApiUsers(result.users);\r\n this.saveMessages(result.messages);\r\n\r\n const message = this.filterMessages(result.messages[0], message => !!(message as Message.message).replies)[0] as Message.message;\r\n const threadKey = message.peerId + '_' + message.mid;\r\n\r\n this.generateThreadServiceStartMessage(message);\r\n \r\n const historyStorage = this.getHistoryStorage(message.peerId, message.mid);\r\n result.max_id = historyStorage.maxId = this.generateMessageId(result.max_id) || 0;\r\n result.read_inbox_max_id = historyStorage.readMaxId = this.generateMessageId(result.read_inbox_max_id) || 0;\r\n result.read_outbox_max_id = historyStorage.readOutboxMaxId = this.generateMessageId(result.read_outbox_max_id) || 0;\r\n\r\n this.threadsToReplies[threadKey] = peerId + '_' + mid;\r\n\r\n return message;\r\n });\r\n }\r\n\r\n handleNewMessages = () => {\r\n clearTimeout(this.newMessagesHandlePromise);\r\n this.newMessagesHandlePromise = 0;\r\n\r\n rootScope.broadcast('history_multiappend', this.newMessagesToHandle);\r\n this.newMessagesToHandle = {};\r\n };\r\n\r\n handleNewDialogs = () => {\r\n clearTimeout(this.newDialogsHandlePromise);\r\n this.newDialogsHandlePromise = 0;\r\n \r\n let newMaxSeenId = 0;\r\n for(const peerId in this.newDialogsToHandle) {\r\n const dialog = this.newDialogsToHandle[peerId];\r\n if('reload' in dialog) {\r\n this.reloadConversation(+peerId);\r\n delete this.newDialogsToHandle[peerId];\r\n } else {\r\n this.dialogsStorage.pushDialog(dialog);\r\n if(!appPeersManager.isChannel(+peerId)) {\r\n newMaxSeenId = Math.max(newMaxSeenId, dialog.top_message || 0);\r\n }\r\n }\r\n }\r\n\r\n //this.log('after order:', this.dialogsStorage[0].map(d => d.peerId));\r\n\r\n if(newMaxSeenId !== 0) {\r\n this.incrementMaxSeenId(newMaxSeenId);\r\n }\r\n\r\n rootScope.broadcast('dialogs_multiupdate', this.newDialogsToHandle as any);\r\n this.newDialogsToHandle = {};\r\n };\r\n\r\n public scheduleHandleNewDialogs() {\r\n if(!this.newDialogsHandlePromise) {\r\n this.newDialogsHandlePromise = window.setTimeout(this.handleNewDialogs, 0);\r\n }\r\n }\r\n\r\n public deleteMessages(peerId: number, mids: number[], revoke?: true) {\r\n let promise: Promise<any>;\r\n\r\n const localMessageIds = mids.map(mid => this.getServerMessageId(mid));\r\n\r\n if(peerId < 0 && appPeersManager.isChannel(peerId)) {\r\n const channelId = -peerId;\r\n const channel = appChatsManager.getChat(channelId);\r\n if(!channel.pFlags.creator && !(channel.pFlags.editor && channel.pFlags.megagroup)) {\r\n const goodMsgIds: number[] = [];\r\n if(channel.pFlags.editor || channel.pFlags.megagroup) {\r\n mids.forEach((msgId, i) => {\r\n const message = this.getMessageByPeer(peerId, mids[i]);\r\n if(message.pFlags.out) {\r\n goodMsgIds.push(msgId);\r\n }\r\n });\r\n }\r\n\r\n if(!goodMsgIds.length) {\r\n return;\r\n }\r\n\r\n mids = goodMsgIds;\r\n }\r\n\r\n promise = apiManager.invokeApi('channels.deleteMessages', {\r\n channel: appChatsManager.getChannelInput(channelId),\r\n id: localMessageIds\r\n }).then((affectedMessages) => {\r\n apiUpdatesManager.processUpdateMessage({\r\n _: 'updateShort',\r\n update: {\r\n _: 'updateDeleteChannelMessages',\r\n channel_id: channelId,\r\n messages: mids,\r\n pts: affectedMessages.pts,\r\n pts_count: affectedMessages.pts_count\r\n }\r\n });\r\n });\r\n } else {\r\n promise = apiManager.invokeApi('messages.deleteMessages', {\r\n revoke,\r\n id: localMessageIds\r\n }).then((affectedMessages) => {\r\n apiUpdatesManager.processUpdateMessage({\r\n _: 'updateShort',\r\n update: {\r\n _: 'updateDeleteMessages',\r\n messages: mids,\r\n pts: affectedMessages.pts,\r\n pts_count: affectedMessages.pts_count\r\n }\r\n });\r\n });\r\n }\r\n\r\n return promise;\r\n }\r\n\r\n public readHistory(peerId: number, maxId = 0, threadId?: number, force = false) {\r\n //return Promise.resolve();\r\n // console.trace('start read')\r\n this.log('readHistory:', peerId, maxId, threadId);\r\n if(!this.getReadMaxIdIfUnread(peerId, threadId) && !force) {\r\n this.log('readHistory: isn\\'t unread');\r\n return Promise.resolve();\r\n }\r\n\r\n const historyStorage = this.getHistoryStorage(peerId, threadId);\r\n\r\n if(historyStorage.triedToReadMaxId >= maxId) {\r\n return Promise.resolve();\r\n }\r\n\r\n let apiPromise: Promise<any>;\r\n if(threadId) {\r\n if(!historyStorage.readPromise) {\r\n apiPromise = apiManager.invokeApi('messages.readDiscussion', {\r\n peer: appPeersManager.getInputPeerById(peerId),\r\n msg_id: this.getServerMessageId(threadId),\r\n read_max_id: this.getServerMessageId(maxId)\r\n });\r\n }\r\n\r\n apiUpdatesManager.processUpdateMessage({\r\n _: 'updateShort',\r\n update: {\r\n _: 'updateReadChannelDiscussionInbox',\r\n channel_id: -peerId,\r\n top_msg_id: threadId,\r\n read_max_id: maxId\r\n } as Update.updateReadChannelDiscussionInbox\r\n });\r\n } else if(appPeersManager.isChannel(peerId)) {\r\n if(!historyStorage.readPromise) {\r\n apiPromise = apiManager.invokeApi('channels.readHistory', {\r\n channel: appChatsManager.getChannelInput(-peerId),\r\n max_id: this.getServerMessageId(maxId)\r\n });\r\n }\r\n\r\n apiUpdatesManager.processUpdateMessage({\r\n _: 'updateShort',\r\n update: {\r\n _: 'updateReadChannelInbox',\r\n max_id: maxId,\r\n channel_id: -peerId\r\n }\r\n });\r\n } else {\r\n if(!historyStorage.readPromise) {\r\n apiPromise = apiManager.invokeApi('messages.readHistory', {\r\n peer: appPeersManager.getInputPeerById(peerId),\r\n max_id: this.getServerMessageId(maxId)\r\n }).then((affectedMessages) => {\r\n apiUpdatesManager.processUpdateMessage({\r\n _: 'updateShort',\r\n update: {\r\n _: 'updatePts',\r\n pts: affectedMessages.pts,\r\n pts_count: affectedMessages.pts_count\r\n }\r\n });\r\n });\r\n }\r\n\r\n apiUpdatesManager.processUpdateMessage({\r\n _: 'updateShort',\r\n update: {\r\n _: 'updateReadHistoryInbox',\r\n max_id: maxId,\r\n peer: appPeersManager.getOutputPeer(peerId)\r\n }\r\n });\r\n }\r\n\r\n if(!threadId && historyStorage && historyStorage.history.length) {\r\n const slice = historyStorage.history.slice;\r\n for(const mid of slice) {\r\n const message = this.getMessageByPeer(peerId, mid);\r\n if(message && !message.pFlags.out) {\r\n message.pFlags.unread = false;\r\n appNotificationsManager.cancel('msg' + mid);\r\n }\r\n }\r\n }\r\n\r\n appNotificationsManager.soundReset(appPeersManager.getPeerString(peerId));\r\n\r\n if(historyStorage.readPromise) {\r\n return historyStorage.readPromise;\r\n }\r\n\r\n historyStorage.triedToReadMaxId = maxId;\r\n\r\n apiPromise.finally(() => {\r\n delete historyStorage.readPromise;\r\n\r\n this.log('readHistory: promise finally', maxId, historyStorage.readMaxId);\r\n\r\n if(historyStorage.readMaxId > maxId) {\r\n this.readHistory(peerId, historyStorage.readMaxId, threadId, true);\r\n }\r\n });\r\n\r\n return historyStorage.readPromise = apiPromise;\r\n }\r\n\r\n public readAllHistory(peerId: number, threadId?: number, force = false) {\r\n const historyStorage = this.getHistoryStorage(peerId, threadId);\r\n if(historyStorage.maxId) {\r\n this.readHistory(peerId, historyStorage.maxId, threadId, force); // lol\r\n }\r\n }\r\n\r\n public readMessages(peerId: number, msgIds: number[]) {\r\n msgIds = msgIds.map(mid => this.getServerMessageId(mid));\r\n if(peerId < 0 && appPeersManager.isChannel(peerId)) {\r\n const channelId = -peerId;\r\n apiManager.invokeApi('channels.readMessageContents', {\r\n channel: appChatsManager.getChannelInput(channelId),\r\n id: msgIds\r\n }).then(() => {\r\n apiUpdatesManager.processUpdateMessage({\r\n _: 'updateShort',\r\n update: {\r\n _: 'updateChannelReadMessagesContents',\r\n channel_id: channelId,\r\n messages: msgIds\r\n }\r\n });\r\n });\r\n } else {\r\n apiManager.invokeApi('messages.readMessageContents', {\r\n id: msgIds\r\n }).then((affectedMessages) => {\r\n apiUpdatesManager.processUpdateMessage({\r\n _: 'updateShort',\r\n update: {\r\n _: 'updateReadMessagesContents',\r\n messages: msgIds,\r\n pts: affectedMessages.pts,\r\n pts_count: affectedMessages.pts_count\r\n }\r\n });\r\n });\r\n }\r\n }\r\n\r\n public getHistoryStorage(peerId: number, threadId?: number) {\r\n if(threadId) {\r\n //threadId = this.getLocalMessageId(threadId);\r\n if(!this.threadsStorage[peerId]) this.threadsStorage[peerId] = {};\r\n return this.threadsStorage[peerId][threadId] ?? (this.threadsStorage[peerId][threadId] = {count: null, history: new SlicedArray()});\r\n }\r\n\r\n return this.historiesStorage[peerId] ?? (this.historiesStorage[peerId] = {count: null, history: new SlicedArray()});\r\n }\r\n\r\n private handleNotifications = () => {\r\n window.clearTimeout(this.notificationsHandlePromise);\r\n this.notificationsHandlePromise = 0;\r\n\r\n //var timeout = $rootScope.idle.isIDLE && StatusManager.isOtherDeviceActive() ? 30000 : 1000;\r\n //const timeout = 1000;\r\n\r\n for(const _peerId in this.notificationsToHandle) {\r\n const peerId = +_peerId;\r\n\r\n if(rootScope.peerId === peerId && !rootScope.idle.isIDLE) {\r\n continue;\r\n }\r\n\r\n const notifyPeerToHandle = this.notificationsToHandle[peerId];\r\n\r\n Promise.all([\r\n appNotificationsManager.getNotifyPeerTypeSettings(),\r\n appNotificationsManager.getNotifySettings(appPeersManager.getInputNotifyPeerById(peerId, true))\r\n ]).then(([_, peerTypeNotifySettings]) => {\r\n const topMessage = notifyPeerToHandle.topMessage;\r\n if(appNotificationsManager.isPeerLocalMuted(peerId, true) || !topMessage.pFlags.unread) {\r\n return;\r\n }\r\n\r\n //setTimeout(() => {\r\n if(topMessage.pFlags.unread) {\r\n this.notifyAboutMessage(topMessage, {\r\n fwdCount: notifyPeerToHandle.fwdCount,\r\n peerTypeNotifySettings\r\n });\r\n }\r\n //}, timeout);\r\n });\r\n }\r\n\r\n this.notificationsToHandle = {};\r\n };\r\n\r\n private onUpdateMessageId = (update: Update.updateMessageID) => {\r\n const randomId = update.random_id;\r\n const pendingData = this.pendingByRandomId[randomId];\r\n //this.log('AMM updateMessageID:', update, pendingData);\r\n if(pendingData) {\r\n const {peerId, tempId, threadId, storage} = pendingData;\r\n //const mid = update.id;\r\n const mid = this.generateMessageId(update.id);\r\n const message = this.getMessageFromStorage(storage, mid);\r\n if(!message.deleted) {\r\n [this.getHistoryStorage(peerId), threadId ? this.getHistoryStorage(peerId, threadId) : undefined]\r\n .filter(Boolean)\r\n .forEach(storage => {\r\n storage.history.delete(tempId);\r\n });\r\n\r\n this.finalizePendingMessageCallbacks(storage, tempId, mid);\r\n } else {\r\n this.pendingByMessageId[mid] = randomId;\r\n }\r\n }\r\n };\r\n\r\n private onUpdateNewMessage = (update: Update.updateNewDiscussionMessage | Update.updateNewMessage | Update.updateNewChannelMessage) => {\r\n const message = update.message as MyMessage;\r\n const peerId = this.getMessagePeer(message);\r\n const storage = this.getMessagesStorage(peerId);\r\n const foundDialog = this.getDialogByPeerId(peerId);\r\n\r\n // * local update\r\n const isLocalThreadUpdate = update._ === 'updateNewDiscussionMessage';\r\n\r\n // * temporary save the message for info (peerId, reply mids...)\r\n this.saveMessages([message], {storage: {}});\r\n\r\n const threadKey = this.getThreadKey(message);\r\n const threadId = threadKey ? +threadKey.split('_')[1] : undefined;\r\n if(threadId && !isLocalThreadUpdate && this.threadsStorage[peerId] && this.threadsStorage[peerId][threadId]) {\r\n const update = {\r\n _: 'updateNewDiscussionMessage',\r\n message\r\n } as Update.updateNewDiscussionMessage;\r\n\r\n this.onUpdateNewMessage(update);\r\n }\r\n\r\n if(!foundDialog.length && !isLocalThreadUpdate) {\r\n let good = true;\r\n if(peerId < 0) {\r\n const chat = appChatsManager.getChat(-peerId);\r\n if(chat._ === 'channelForbidden' \r\n || chat._ === 'chatForbidden' \r\n || (chat as Chat.chat).pFlags.left \r\n || (chat as Chat.chat).pFlags.kicked \r\n || (chat as Chat.chat).pFlags.deactivated) {\r\n good = false;\r\n }\r\n }\r\n\r\n if(good) {\r\n const set = this.newUpdatesAfterReloadToHandle[peerId] ?? (this.newUpdatesAfterReloadToHandle[peerId] = new Set());\r\n if(set.has(update)) {\r\n this.log.error('here we go again', peerId);\r\n return;\r\n }\r\n\r\n this.newDialogsToHandle[peerId] = {reload: true};\r\n this.scheduleHandleNewDialogs();\r\n this.newUpdatesAfterReloadToHandle[peerId].add(update);\r\n }\r\n\r\n return;\r\n }\r\n\r\n /* if(update._ === 'updateNewChannelMessage') {\r\n const chat = appChatsManager.getChat(-peerId);\r\n if(chat.pFlags && (chat.pFlags.left || chat.pFlags.kicked)) {\r\n return;\r\n }\r\n } */\r\n\r\n this.saveMessages([message], {storage});\r\n // this.log.warn(dT(), 'message unread', message.mid, message.pFlags.unread)\r\n\r\n /* if((message as Message.message).grouped_id) {\r\n this.log('updateNewMessage', message);\r\n } */\r\n\r\n const pendingMessage = this.checkPendingMessage(message);\r\n const historyStorage = this.getHistoryStorage(peerId, isLocalThreadUpdate ? threadId : undefined);\r\n\r\n if(!isLocalThreadUpdate) {\r\n this.updateMessageRepliesIfNeeded(message);\r\n }\r\n\r\n if(historyStorage.history.findSlice(message.mid)) {\r\n return false;\r\n }\r\n\r\n const history = historyStorage.history.slice;\r\n const topMsgId = history[0];\r\n history.unshift(message.mid);\r\n if(message.mid < topMsgId) {\r\n //this.log.error('this should\\'nt have happenned!', message, history);\r\n history.sort((a, b) => {\r\n return b - a;\r\n });\r\n }\r\n\r\n if(historyStorage.count !== null) {\r\n historyStorage.count++;\r\n }\r\n\r\n if(this.mergeReplyKeyboard(historyStorage, message)) {\r\n rootScope.broadcast('history_reply_markup', {peerId});\r\n }\r\n\r\n if(message.fromId > 0 && !message.pFlags.out && message.from_id) {\r\n appUsersManager.forceUserOnline(message.fromId, message.date);\r\n }\r\n\r\n if(!pendingMessage) {\r\n if(this.newMessagesToHandle[peerId] === undefined) {\r\n this.newMessagesToHandle[peerId] = new Set();\r\n }\r\n\r\n this.newMessagesToHandle[peerId].add(message.mid);\r\n if(!this.newMessagesHandlePromise) {\r\n this.newMessagesHandlePromise = window.setTimeout(this.handleNewMessages, 0);\r\n }\r\n }\r\n\r\n if(isLocalThreadUpdate) {\r\n return;\r\n }\r\n \r\n const dialog = foundDialog[0];\r\n const inboxUnread = !message.pFlags.out && message.pFlags.unread;\r\n if(dialog) {\r\n this.setDialogTopMessage(message, dialog);\r\n if(inboxUnread) {\r\n dialog.unread_count++;\r\n }\r\n }\r\n\r\n if(inboxUnread/* && ($rootScope.selectedPeerID != peerID || $rootScope.idle.isIDLE) */) {\r\n const notifyPeer = message.peerId;\r\n let notifyPeerToHandle = this.notificationsToHandle[notifyPeer];\r\n if(notifyPeerToHandle === undefined) {\r\n notifyPeerToHandle = this.notificationsToHandle[notifyPeer] = {\r\n fwdCount: 0,\r\n fromId: 0\r\n };\r\n }\r\n\r\n if(notifyPeerToHandle.fromId !== message.fromId) {\r\n notifyPeerToHandle.fromId = message.fromId;\r\n notifyPeerToHandle.fwdCount = 0;\r\n }\r\n\r\n if((message as Message.message).fwd_from) {\r\n notifyPeerToHandle.fwdCount++;\r\n }\r\n\r\n notifyPeerToHandle.topMessage = message;\r\n\r\n if(!this.notificationsHandlePromise) {\r\n this.notificationsHandlePromise = window.setTimeout(this.handleNotifications, 0);\r\n }\r\n }\r\n };\r\n\r\n private onUpdateDialogUnreadMark = (update: Update.updateDialogUnreadMark) => {\r\n //this.log('updateDialogUnreadMark', update);\r\n const peerId = appPeersManager.getPeerId((update.peer as DialogPeer.dialogPeer).peer);\r\n const foundDialog = this.getDialogByPeerId(peerId);\r\n\r\n if(!foundDialog.length) {\r\n this.newDialogsToHandle[peerId] = {reload: true};\r\n this.scheduleHandleNewDialogs();\r\n } else {\r\n const dialog = foundDialog[0];\r\n\r\n if(!update.pFlags.unread) {\r\n delete dialog.pFlags.unread_mark;\r\n } else {\r\n dialog.pFlags.unread_mark = true;\r\n }\r\n\r\n rootScope.broadcast('dialogs_multiupdate', {peerId: dialog});\r\n }\r\n };\r\n\r\n // only 0 and 1 folders\r\n private onUpdateFolderPeers = (update: Update.updateFolderPeers) => {\r\n //this.log('updateFolderPeers', update);\r\n const peers = update.folder_peers;\r\n\r\n this.scheduleHandleNewDialogs();\r\n peers.forEach((folderPeer) => {\r\n const {folder_id, peer} = folderPeer;\r\n\r\n const peerId = appPeersManager.getPeerId(peer);\r\n const dropped = this.dialogsStorage.dropDialog(peerId);\r\n if(!dropped.length) {\r\n this.newDialogsToHandle[peerId] = {reload: true};\r\n } else {\r\n const dialog = dropped[0];\r\n this.newDialogsToHandle[peerId] = dialog;\r\n\r\n if(dialog.pFlags?.pinned) {\r\n delete dialog.pFlags.pinned;\r\n this.dialogsStorage.pinnedOrders[folder_id].findAndSplice(p => p === dialog.peerId);\r\n }\r\n\r\n dialog.folder_id = folder_id;\r\n\r\n this.dialogsStorage.generateIndexForDialog(dialog);\r\n this.dialogsStorage.pushDialog(dialog); // need for simultaneously updatePinnedDialogs\r\n }\r\n });\r\n };\r\n\r\n private onUpdateDialogPinned = (update: Update.updateDialogPinned) => {\r\n const folderId = update.folder_id ?? 0;\r\n //this.log('updateDialogPinned', update);\r\n const peerId = appPeersManager.getPeerId((update.peer as DialogPeer.dialogPeer).peer);\r\n const foundDialog = this.getDialogByPeerId(peerId);\r\n\r\n // этот код внизу никогда не сработает, в папках за пиннед отвечает updateDialogFilter\r\n /* if(update.folder_id > 1) {\r\n const filter = this.filtersStorage.filters[update.folder_id];\r\n if(update.pFlags.pinned) {\r\n filter.pinned_peers.unshift(peerId);\r\n } else {\r\n filter.pinned_peers.findAndSplice(p => p === peerId);\r\n }\r\n } */\r\n\r\n this.scheduleHandleNewDialogs();\r\n if(!foundDialog.length) {\r\n this.newDialogsToHandle[peerId] = {reload: true};\r\n } else {\r\n const dialog = foundDialog[0];\r\n this.newDialogsToHandle[peerId] = dialog;\r\n\r\n if(!update.pFlags.pinned) {\r\n delete dialog.pFlags.pinned;\r\n this.dialogsStorage.pinnedOrders[folderId].findAndSplice(p => p === dialog.peerId);\r\n } else { // means set\r\n dialog.pFlags.pinned = true;\r\n }\r\n\r\n this.dialogsStorage.generateIndexForDialog(dialog);\r\n } \r\n };\r\n\r\n private onUpdatePinnedDialogs = (update: Update.updatePinnedDialogs) => {\r\n const folderId = update.folder_id ?? 0;\r\n \r\n const handleOrder = (order: number[]) => {\r\n this.dialogsStorage.pinnedOrders[folderId].length = 0;\r\n let willHandle = false;\r\n order.reverse(); // index must be higher\r\n order.forEach((peerId) => {\r\n newPinned[peerId] = true;\r\n \r\n const foundDialog = this.getDialogByPeerId(peerId);\r\n if(!foundDialog.length) {\r\n this.newDialogsToHandle[peerId] = {reload: true};\r\n willHandle = true;\r\n return;\r\n }\r\n \r\n const dialog = foundDialog[0];\r\n dialog.pFlags.pinned = true;\r\n this.dialogsStorage.generateIndexForDialog(dialog);\r\n \r\n this.newDialogsToHandle[peerId] = dialog;\r\n willHandle = true;\r\n });\r\n \r\n this.dialogsStorage.getFolder(folderId).forEach(dialog => {\r\n const peerId = dialog.peerId;\r\n if(dialog.pFlags.pinned && !newPinned[peerId]) {\r\n this.newDialogsToHandle[peerId] = {reload: true};\r\n willHandle = true;\r\n }\r\n });\r\n \r\n if(willHandle) {\r\n this.scheduleHandleNewDialogs();\r\n }\r\n };\r\n\r\n //this.log('updatePinnedDialogs', update);\r\n const newPinned: {[peerId: number]: true} = {};\r\n if(!update.order) {\r\n apiManager.invokeApi('messages.getPinnedDialogs', {\r\n folder_id: folderId\r\n }).then((dialogsResult) => {\r\n // * for test reordering and rendering\r\n // dialogsResult.dialogs.reverse();\r\n\r\n this.applyConversations(dialogsResult);\r\n\r\n handleOrder(dialogsResult.dialogs.map(d => d.peerId));\r\n\r\n /* dialogsResult.dialogs.forEach((dialog) => {\r\n newPinned[dialog.peerId] = true;\r\n });\r\n\r\n this.dialogsStorage.getFolder(folderId).forEach((dialog) => {\r\n const peerId = dialog.peerId;\r\n if(dialog.pFlags.pinned && !newPinned[peerId]) {\r\n this.newDialogsToHandle[peerId] = {reload: true};\r\n this.scheduleHandleNewDialogs();\r\n }\r\n }); */\r\n });\r\n\r\n return;\r\n }\r\n\r\n //this.log('before order:', this.dialogsStorage[0].map(d => d.peerId));\r\n\r\n handleOrder(update.order.map(peer => appPeersManager.getPeerId((peer as DialogPeer.dialogPeer).peer)));\r\n };\r\n\r\n private onUpdateEditMessage = (update: Update.updateEditMessage | Update.updateEditChannelMessage) => {\r\n const message = update.message as MyMessage;\r\n const peerId = this.getMessagePeer(message);\r\n const mid = this.generateMessageId(message.id);\r\n const storage = this.getMessagesStorage(peerId);\r\n if(storage[mid] === undefined) {\r\n return;\r\n }\r\n\r\n // console.trace(dT(), 'edit message', message)\r\n \r\n const oldMessage = this.getMessageFromStorage(storage, mid);\r\n this.saveMessages([message], {storage});\r\n const newMessage = this.getMessageFromStorage(storage, mid);\r\n\r\n this.handleEditedMessage(oldMessage, newMessage);\r\n\r\n const dialog = this.getDialogByPeerId(peerId)[0];\r\n const isTopMessage = dialog && dialog.top_message === mid;\r\n // @ts-ignore\r\n if(message.clear_history) { // that's will never happen\r\n if(isTopMessage) {\r\n rootScope.broadcast('dialog_flush', {peerId});\r\n }\r\n } else {\r\n rootScope.broadcast('message_edit', {\r\n storage,\r\n peerId,\r\n mid\r\n });\r\n\r\n if(isTopMessage || (message as Message.message).grouped_id) {\r\n const updatedDialogs: {[peerId: number]: Dialog} = {};\r\n updatedDialogs[peerId] = dialog;\r\n rootScope.broadcast('dialogs_multiupdate', updatedDialogs);\r\n }\r\n }\r\n };\r\n\r\n private onUpdateReadHistory = (update: Update.updateReadChannelDiscussionInbox | Update.updateReadChannelDiscussionOutbox \r\n | Update.updateReadHistoryInbox | Update.updateReadHistoryOutbox \r\n | Update.updateReadChannelInbox | Update.updateReadChannelOutbox) => {\r\n const channelId = (update as Update.updateReadChannelInbox).channel_id;\r\n const maxId = this.generateMessageId((update as Update.updateReadChannelInbox).max_id || (update as Update.updateReadChannelDiscussionInbox).read_max_id);\r\n const threadId = this.generateMessageId((update as Update.updateReadChannelDiscussionInbox).top_msg_id);\r\n const peerId = channelId ? -channelId : appPeersManager.getPeerId((update as Update.updateReadHistoryInbox).peer);\r\n\r\n const isOut = update._ === 'updateReadHistoryOutbox' || update._ === 'updateReadChannelOutbox' || update._ === 'updateReadChannelDiscussionOutbox' ? true : undefined;\r\n\r\n const storage = this.getMessagesStorage(peerId);\r\n const history = getObjectKeysAndSort(storage, 'desc');\r\n const foundDialog = this.getDialogByPeerId(peerId)[0];\r\n const stillUnreadCount = (update as Update.updateReadChannelInbox).still_unread_count;\r\n let newUnreadCount = 0;\r\n let foundAffected = false;\r\n\r\n //this.log.warn(dT(), 'read', peerId, isOut ? 'out' : 'in', maxId)\r\n\r\n const historyStorage = this.getHistoryStorage(peerId, threadId);\r\n\r\n if(peerId > 0 && isOut) {\r\n appUsersManager.forceUserOnline(peerId);\r\n }\r\n\r\n if(threadId) {\r\n const repliesKey = this.threadsToReplies[peerId + '_' + threadId];\r\n if(repliesKey) {\r\n const [peerId, mid] = repliesKey.split('_').map(n => +n);\r\n this.updateMessage(peerId, mid, 'replies_updated');\r\n }\r\n }\r\n\r\n for(let i = 0, length = history.length; i < length; i++) {\r\n const messageId = history[i];\r\n if(messageId > maxId) {\r\n continue;\r\n }\r\n \r\n const message = storage[messageId];\r\n\r\n if(message.pFlags.out !== isOut) {\r\n continue;\r\n }\r\n\r\n if(!message.pFlags.unread) {\r\n break;\r\n }\r\n\r\n if(threadId) {\r\n const replyTo = message.reply_to as MessageReplyHeader;\r\n if(!replyTo || (replyTo.reply_to_top_id || replyTo.reply_to_msg_id) !== threadId) {\r\n continue;\r\n }\r\n }\r\n \r\n // this.log.warn('read', messageId, message.pFlags.unread, message)\r\n if(message.pFlags.unread) {\r\n delete message.pFlags.unread;\r\n if(!foundAffected) {\r\n foundAffected = true;\r\n }\r\n\r\n if(!message.pFlags.out && !threadId && stillUnreadCount === undefined) {\r\n newUnreadCount = --foundDialog.unread_count;\r\n }\r\n \r\n appNotificationsManager.cancel('msg' + messageId);\r\n }\r\n }\r\n\r\n if(isOut) historyStorage.readOutboxMaxId = maxId;\r\n else historyStorage.readMaxId = maxId;\r\n\r\n if(!threadId && foundDialog) {\r\n if(isOut) foundDialog.read_outbox_max_id = maxId;\r\n else foundDialog.read_inbox_max_id = maxId;\r\n\r\n if(!isOut) {\r\n if(newUnreadCount < 0 || !this.getReadMaxIdIfUnread(peerId)) {\r\n foundDialog.unread_count = 0;\r\n } else if(newUnreadCount && foundDialog.top_message > maxId) {\r\n foundDialog.unread_count = newUnreadCount;\r\n }\r\n }\r\n\r\n rootScope.broadcast('dialog_unread', {peerId});\r\n }\r\n\r\n if(foundAffected) {\r\n rootScope.broadcast('messages_read');\r\n }\r\n\r\n if(!threadId && channelId) {\r\n const threadKeyPart = peerId + '_';\r\n for(const threadKey in this.threadsToReplies) {\r\n if(threadKey.indexOf(threadKeyPart) === 0) {\r\n const [peerId, mid] = this.threadsToReplies[threadKey].split('_').map(n => +n);\r\n rootScope.broadcast('replies_updated', this.getMessageByPeer(peerId, mid));\r\n }\r\n }\r\n }\r\n };\r\n\r\n private onUpdateReadMessagesContents = (update: Update.updateChannelReadMessagesContents | Update.updateReadMessagesContents) => {\r\n const channelId = (update as Update.updateChannelReadMessagesContents).channel_id;\r\n const mids = (update as Update.updateReadMessagesContents).messages.map(id => this.generateMessageId(id));\r\n const peerId = channelId ? -channelId : this.getMessageById(mids[0]).peerId;\r\n for(const mid of mids) {\r\n const message = this.getMessageByPeer(peerId, mid);\r\n if(!message.deleted) {\r\n delete message.pFlags.media_unread;\r\n }\r\n }\r\n\r\n rootScope.broadcast('messages_media_read', {peerId, mids});\r\n };\r\n\r\n private onUpdateChannelAvailableMessages = (update: Update.updateChannelAvailableMessages) => {\r\n const channelId: number = update.channel_id;\r\n const messages: number[] = [];\r\n const peerId: number = -channelId;\r\n const history = this.getHistoryStorage(peerId).history.slice;\r\n if(history.length) {\r\n history.forEach((msgId: number) => {\r\n if(!update.available_min_id || msgId <= update.available_min_id) {\r\n messages.push(msgId);\r\n }\r\n });\r\n }\r\n\r\n (update as any as Update.updateDeleteChannelMessages).messages = messages;\r\n this.onUpdateDeleteMessages(update as any as Update.updateDeleteChannelMessages);\r\n };\r\n\r\n private onUpdateDeleteMessages = (update: Update.updateDeleteMessages | Update.updateDeleteChannelMessages) => {\r\n const channelId: number = (update as Update.updateDeleteChannelMessages).channel_id;\r\n //const messages = (update as any as Update.updateDeleteChannelMessages).messages;\r\n const messages = (update as any as Update.updateDeleteChannelMessages).messages.map(id => this.generateMessageId(id));\r\n const peerId: number = channelId ? -channelId : this.getMessageById(messages[0]).peerId;\r\n \r\n if(!peerId) {\r\n return;\r\n }\r\n\r\n apiManager.clearCache('messages.getSearchCounters', (params) => {\r\n return appPeersManager.getPeerId(params.peer) === peerId;\r\n });\r\n\r\n const threadKeys: Set<string> = new Set();\r\n for(const mid of messages) {\r\n const message = this.getMessageByPeer(peerId, mid);\r\n const threadKey = this.getThreadKey(message);\r\n if(threadKey && this.threadsStorage[peerId] && this.threadsStorage[peerId][+threadKey.split('_')[1]]) {\r\n threadKeys.add(threadKey);\r\n }\r\n }\r\n \r\n const historyUpdated = this.handleDeletedMessages(peerId, this.getMessagesStorage(peerId), messages);\r\n\r\n const threadsStorages = Array.from(threadKeys).map(threadKey => {\r\n const splitted = threadKey.split('_');\r\n return this.getHistoryStorage(+splitted[0], +splitted[1]);\r\n });\r\n\r\n [this.getHistoryStorage(peerId)].concat(threadsStorages).forEach(historyStorage => {\r\n for(const mid in historyUpdated.msgs) {\r\n historyStorage.history.delete(+mid);\r\n }\r\n if(historyUpdated.count &&\r\n historyStorage.count !== null &&\r\n historyStorage.count > 0) {\r\n historyStorage.count -= historyUpdated.count;\r\n if(historyStorage.count < 0) {\r\n historyStorage.count = 0;\r\n }\r\n }\r\n });\r\n\r\n rootScope.broadcast('history_delete', {peerId, msgs: historyUpdated.msgs});\r\n\r\n const foundDialog = this.getDialogByPeerId(peerId)[0];\r\n if(foundDialog) {\r\n if(historyUpdated.unread) {\r\n foundDialog.unread_count -= historyUpdated.unread;\r\n\r\n rootScope.broadcast('dialog_unread', {peerId});\r\n }\r\n\r\n if(historyUpdated.msgs[foundDialog.top_message]) {\r\n this.reloadConversation(peerId);\r\n }\r\n }\r\n };\r\n\r\n private onUpdateChannel = (update: Update.updateChannel) => {\r\n const channelId: number = update.channel_id;\r\n const peerId = -channelId;\r\n const channel = appChatsManager.getChat(channelId);\r\n\r\n const needDialog = channel._ === 'channel' && (!channel.pFlags.left && !channel.pFlags.kicked);\r\n const foundDialog = this.getDialogByPeerId(peerId);\r\n const hasDialog = foundDialog.length > 0;\r\n\r\n const canViewHistory = channel._ === 'channel' && (channel.username || !channel.pFlags.left && !channel.pFlags.kicked);\r\n const hasHistory = this.historiesStorage[peerId] !== undefined;\r\n\r\n if(canViewHistory !== hasHistory) {\r\n delete this.historiesStorage[peerId];\r\n rootScope.broadcast('history_forbidden', peerId);\r\n }\r\n\r\n if(hasDialog !== needDialog) {\r\n if(needDialog) {\r\n this.reloadConversation(-channelId);\r\n } else {\r\n if(foundDialog[0]) {\r\n this.dialogsStorage.dropDialog(peerId);\r\n rootScope.broadcast('dialog_drop', {peerId: peerId, dialog: foundDialog[0]});\r\n }\r\n }\r\n }\r\n };\r\n\r\n private onUpdateChannelReload = (update: any) => {\r\n // @ts-ignore\r\n const channelId: number = update.channel_id;\r\n const peerId = -channelId;\r\n\r\n this.dialogsStorage.dropDialog(peerId);\r\n\r\n delete this.historiesStorage[peerId];\r\n this.reloadConversation(-channelId).then(() => {\r\n rootScope.broadcast('history_reload', peerId);\r\n });\r\n };\r\n \r\n private onUpdateChannelMessageViews = (update: Update.updateChannelMessageViews) => {\r\n const views = update.views;\r\n //const mid = update.id;\r\n const mid = this.generateMessageId(update.id);\r\n const message = this.getMessageByPeer(-update.channel_id, mid);\r\n if(!message.deleted && message.views && message.views < views) {\r\n message.views = views;\r\n rootScope.broadcast('message_views', {mid, views});\r\n }\r\n };\r\n\r\n private onUpdateServiceNotification = (update: Update.updateServiceNotification) => {\r\n //this.log('updateServiceNotification', update);\r\n const fromId = 777000;\r\n const peerId = fromId;\r\n const messageId = this.generateTempMessageId(peerId);\r\n const message: any = {\r\n _: 'message',\r\n id: messageId,\r\n from_id: appPeersManager.getOutputPeer(fromId),\r\n peer_id: appPeersManager.getOutputPeer(peerId),\r\n pFlags: {unread: true},\r\n date: (update.inbox_date || tsNow(true)) + serverTimeManager.serverTimeOffset,\r\n message: update.message,\r\n media: update.media,\r\n entities: update.entities\r\n };\r\n if(!appUsersManager.hasUser(fromId)) {\r\n appUsersManager.saveApiUsers([{\r\n _: 'user',\r\n id: fromId,\r\n pFlags: {verified: true},\r\n access_hash: 0,\r\n first_name: 'Telegram',\r\n phone: '42777'\r\n }]);\r\n }\r\n this.saveMessages([message], {isOutgoing: true});\r\n\r\n if(update.inbox_date) {\r\n this.pendingTopMsgs[peerId] = messageId;\r\n this.onUpdateNewMessage({\r\n _: 'updateNewMessage',\r\n message\r\n } as any);\r\n }\r\n };\r\n\r\n private onUpdatePinnedMessages = (update: Update.updatePinnedMessages | Update.updatePinnedChannelMessages) => {\r\n const channelId = update._ === 'updatePinnedChannelMessages' ? update.channel_id : undefined;\r\n const peerId = channelId ? -channelId : appPeersManager.getPeerId((update as Update.updatePinnedMessages).peer);\r\n\r\n /* const storage = this.getSearchStorage(peerId, 'inputMessagesFilterPinned');\r\n if(storage.count !== storage.history.length) {\r\n if(storage.count !== undefined) {\r\n delete this.searchesStorage[peerId]['inputMessagesFilterPinned']; \r\n }\r\n\r\n rootScope.broadcast('peer_pinned_messages', peerId);\r\n break;\r\n } */\r\n\r\n const messages = update.messages.map(id => this.generateMessageId(id)); \r\n\r\n const storage = this.getMessagesStorage(peerId);\r\n const missingMessages = messages.filter(mid => !storage[mid]);\r\n const getMissingPromise = missingMessages.length ? Promise.all(missingMessages.map(mid => this.wrapSingleMessage(peerId, mid))) : Promise.resolve();\r\n getMissingPromise.finally(() => {\r\n const werePinned = update.pFlags?.pinned;\r\n if(werePinned) {\r\n for(const mid of messages) {\r\n //storage.history.push(mid);\r\n const message = storage[mid];\r\n message.pFlags.pinned = true;\r\n }\r\n\r\n /* if(this.pinnedMessages[peerId]?.maxId) {\r\n const maxMid = Math.max(...messages);\r\n this.pinnedMessages\r\n } */\r\n\r\n //storage.history.sort((a, b) => b - a);\r\n } else {\r\n for(const mid of messages) {\r\n //storage.history.findAndSplice(_mid => _mid === mid);\r\n const message = storage[mid];\r\n delete message.pFlags.pinned;\r\n }\r\n }\r\n\r\n /* const info = this.pinnedMessages[peerId];\r\n if(info) {\r\n info.count += messages.length * (werePinned ? 1 : -1);\r\n } */\r\n \r\n delete this.pinnedMessages[peerId];\r\n appStateManager.getState().then(state => {\r\n delete state.hiddenPinnedMessages[peerId];\r\n rootScope.broadcast('peer_pinned_messages', {peerId, mids: messages, pinned: werePinned});\r\n });\r\n });\r\n };\r\n\r\n private onUpdateNotifySettings = (update: Update.updateNotifySettings) => {\r\n const {peer, notify_settings} = update;\r\n if(peer._ === 'notifyPeer') {\r\n const peerId = appPeersManager.getPeerId((peer as NotifyPeer.notifyPeer).peer);\r\n \r\n const dialog = this.getDialogByPeerId(peerId)[0];\r\n if(dialog) {\r\n dialog.notify_settings = notify_settings;\r\n rootScope.broadcast('dialog_notify_settings', dialog);\r\n }\r\n }\r\n };\r\n\r\n private onUpdateNewScheduledMessage = (update: Update.updateNewScheduledMessage) => {\r\n const message = update.message as MyMessage;\r\n const peerId = this.getMessagePeer(message);\r\n\r\n const storage = this.scheduledMessagesStorage[peerId];\r\n if(storage) {\r\n const mid = this.generateMessageId(message.id);\r\n\r\n const oldMessage = this.getMessageFromStorage(storage, mid);\r\n this.saveMessages([message], {storage, isScheduled: true});\r\n const newMessage = this.getMessageFromStorage(storage, mid);\r\n\r\n if(!oldMessage.deleted) {\r\n this.handleEditedMessage(oldMessage, newMessage);\r\n rootScope.broadcast('message_edit', {storage, peerId, mid: message.mid});\r\n } else {\r\n const pendingMessage = this.checkPendingMessage(message);\r\n if(!pendingMessage) {\r\n rootScope.broadcast('scheduled_new', {peerId, mid: message.mid});\r\n }\r\n }\r\n }\r\n };\r\n\r\n private onUpdateDeleteScheduledMessages = (update: Update.updateDeleteScheduledMessages) => {\r\n const peerId = appPeersManager.getPeerId(update.peer);\r\n\r\n const storage = this.scheduledMessagesStorage[peerId];\r\n if(storage) {\r\n const mids = update.messages.map(id => this.generateMessageId(id));\r\n this.handleDeletedMessages(peerId, storage, mids);\r\n\r\n rootScope.broadcast('scheduled_delete', {peerId, mids});\r\n }\r\n };\r\n\r\n private updateMessageRepliesIfNeeded(threadMessage: MyMessage) {\r\n try { // * на всякий случай, скорее всего это не понадобится\r\n const threadKey = this.getThreadKey(threadMessage);\r\n if(threadKey) {\r\n const repliesKey = this.threadsToReplies[threadKey];\r\n if(repliesKey) {\r\n const [peerId, mid] = repliesKey.split('_').map(n => +n);\r\n\r\n this.updateMessage(peerId, mid, 'replies_updated');\r\n }\r\n }\r\n } catch(err) {\r\n this.log.error('incrementMessageReplies err', err, threadMessage);\r\n }\r\n }\r\n\r\n private getThreadKey(threadMessage: MyMessage) {\r\n let threadKey = '';\r\n if(threadMessage.peerId < 0 && threadMessage.reply_to) {\r\n const threadId = threadMessage.reply_to.reply_to_top_id || threadMessage.reply_to.reply_to_msg_id;\r\n threadKey = threadMessage.peerId + '_' + threadId;\r\n }\r\n\r\n return threadKey;\r\n }\r\n\r\n public updateMessage(peerId: number, mid: number, broadcastEventName?: 'replies_updated'): Promise<Message.message> {\r\n const promise: Promise<Message.message> = this.wrapSingleMessage(peerId, mid, true).then(() => {\r\n const message = this.getMessageByPeer(peerId, mid);\r\n\r\n if(broadcastEventName) {\r\n rootScope.broadcast(broadcastEventName, message);\r\n }\r\n\r\n return message;\r\n });\r\n \r\n return promise;\r\n }\r\n\r\n private checkPendingMessage(message: any) {\r\n const randomId = this.pendingByMessageId[message.mid];\r\n let pendingMessage: any;\r\n if(randomId) {\r\n const pendingData = this.pendingByRandomId[randomId];\r\n if(pendingMessage = this.finalizePendingMessage(randomId, message)) {\r\n rootScope.broadcast('history_update', {storage: pendingData.storage, peerId: message.peerId, mid: message.mid});\r\n }\r\n\r\n delete this.pendingByMessageId[message.mid];\r\n }\r\n\r\n return pendingMessage;\r\n }\r\n\r\n public mutePeer(peerId: number, mute?: boolean) {\r\n const settings: InputPeerNotifySettings = {\r\n _: 'inputPeerNotifySettings'\r\n };\r\n\r\n if(mute === undefined) {\r\n mute = false;\r\n const dialog = appMessagesManager.getDialogByPeerId(peerId)[0];\r\n if(dialog && dialog.notify_settings) {\r\n mute = (dialog.notify_settings.mute_until || 0) <= (Date.now() / 1000 | 0);\r\n }\r\n }\r\n \r\n settings.mute_until = mute ? 0xFFFFFFFF : 0;\r\n\r\n return appNotificationsManager.updateNotifySettings({\r\n _: 'inputNotifyPeer',\r\n peer: appPeersManager.getInputPeerById(peerId)\r\n }, settings);\r\n }\r\n\r\n public canWriteToPeer(peerId: number) {\r\n if(peerId < 0) {\r\n const isChannel = appPeersManager.isChannel(peerId);\r\n const hasRights = isChannel && appChatsManager.hasRights(-peerId, 'send_messages'); \r\n return !isChannel || hasRights;\r\n } else {\r\n return appUsersManager.canSendToUser(peerId);\r\n }\r\n }\r\n\r\n public finalizePendingMessage(randomId: string, finalMessage: any) {\r\n const pendingData = this.pendingByRandomId[randomId];\r\n // this.log('pdata', randomID, pendingData)\r\n\r\n if(pendingData) {\r\n const {peerId, tempId, threadId, storage} = pendingData;\r\n\r\n [this.getHistoryStorage(peerId), threadId ? this.getHistoryStorage(peerId, threadId) : undefined]\r\n .filter(Boolean)\r\n .forEach(storage => {\r\n storage.history.delete(tempId);\r\n });\r\n\r\n // this.log('pending', randomID, historyStorage.pending)\r\n\r\n const message = this.getMessageFromStorage(storage, tempId);\r\n if(!message.deleted) {\r\n delete message.pFlags.is_outgoing;\r\n delete message.pending;\r\n delete message.error;\r\n delete message.random_id;\r\n delete message.send;\r\n\r\n rootScope.broadcast('messages_pending');\r\n }\r\n \r\n delete this.pendingByRandomId[randomId];\r\n\r\n this.finalizePendingMessageCallbacks(storage, tempId, finalMessage.mid);\r\n\r\n return message;\r\n }\r\n\r\n return false;\r\n }\r\n\r\n public finalizePendingMessageCallbacks(storage: MessagesStorage, tempId: number, mid: number) {\r\n const message = this.getMessageFromStorage(storage, mid);\r\n const callbacks = this.tempFinalizeCallbacks[tempId];\r\n //this.log.warn(callbacks, tempId);\r\n if(callbacks !== undefined) {\r\n for(const name in callbacks) {\r\n const {deferred, callback} = callbacks[name];\r\n //this.log(`finalizePendingMessageCallbacks: will invoke ${name} callback`);\r\n callback(message).then(deferred.resolve, deferred.reject);\r\n }\r\n\r\n delete this.tempFinalizeCallbacks[tempId];\r\n }\r\n\r\n // set cached url to media\r\n if(message.media) {\r\n if(message.media.photo) {\r\n const photo = appPhotosManager.getPhoto('' + tempId);\r\n if(/* photo._ !== 'photoEmpty' */photo) {\r\n const newPhoto = message.media.photo as MyPhoto;\r\n // костыль\r\n defineNotNumerableProperties(newPhoto, ['downloaded', 'url']);\r\n newPhoto.downloaded = photo.downloaded;\r\n newPhoto.url = photo.url;\r\n\r\n const photoSize = newPhoto.sizes[newPhoto.sizes.length - 1] as PhotoSize.photoSize;\r\n defineNotNumerableProperties(photoSize, ['url']);\r\n photoSize.url = photo.url;\r\n\r\n const downloadOptions = appPhotosManager.getPhotoDownloadOptions(newPhoto, photoSize);\r\n const fileName = getFileNameByLocation(downloadOptions.location);\r\n appDownloadManager.fakeDownload(fileName, photo.url);\r\n }\r\n } else if(message.media.document) {\r\n const doc = appDocsManager.getDoc('' + tempId);\r\n if(doc) {\r\n if(/* doc._ !== 'documentEmpty' && */doc.type && doc.type !== 'sticker') {\r\n const newDoc = message.media.document;\r\n newDoc.downloaded = doc.downloaded;\r\n newDoc.url = doc.url;\r\n\r\n const fileName = appDocsManager.getInputFileName(newDoc);\r\n appDownloadManager.fakeDownload(fileName, doc.url);\r\n }\r\n }\r\n } else if(message.media.poll) {\r\n delete appPollsManager.polls[tempId];\r\n delete appPollsManager.results[tempId];\r\n }\r\n }\r\n\r\n const tempMessage = this.getMessageFromStorage(storage, tempId);\r\n delete storage[tempId];\r\n\r\n rootScope.broadcast('message_sent', {storage, tempId, tempMessage, mid});\r\n }\r\n\r\n public incrementMaxSeenId(maxId: number) {\r\n if(!maxId || !(!this.maxSeenId || maxId > this.maxSeenId)) {\r\n return false;\r\n }\r\n\r\n this.maxSeenId = maxId;\r\n\r\n apiManager.invokeApi('messages.receivedMessages', {\r\n max_id: this.getServerMessageId(maxId)\r\n });\r\n }\r\n\r\n private notifyAboutMessage(message: MyMessage, options: Partial<{\r\n fwdCount: number,\r\n peerTypeNotifySettings: PeerNotifySettings\r\n }> = {}) {\r\n const peerId = this.getMessagePeer(message);\r\n const notification: NotifyOptions = {};\r\n const peerString = appPeersManager.getPeerString(peerId);\r\n let notificationMessage: string;\r\n\r\n if(options.peerTypeNotifySettings.show_previews) {\r\n if(message._ === 'message' && message.fwd_from && options.fwdCount) {\r\n notificationMessage = I18n.format('Notifications.Forwarded', true, [options.fwdCount]);\r\n } else {\r\n notificationMessage = this.wrapMessageForReply(message, undefined, undefined, true);\r\n }\r\n } else {\r\n notificationMessage = I18n.format('Notifications.New', true);\r\n }\r\n\r\n notification.title = appPeersManager.getPeerTitle(peerId, true);\r\n if(peerId < 0 && message.fromId !== message.peerId) {\r\n notification.title = appPeersManager.getPeerTitle(message.fromId, true) +\r\n ' @ ' +\r\n notification.title;\r\n }\r\n\r\n notification.title = RichTextProcessor.wrapPlainText(notification.title);\r\n\r\n notification.onclick = () => {\r\n rootScope.broadcast('history_focus', {peerId, mid: message.mid});\r\n };\r\n\r\n notification.message = notificationMessage;\r\n notification.key = 'msg' + message.mid;\r\n notification.tag = peerString;\r\n notification.silent = true;//message.pFlags.silent || false;\r\n\r\n const peerPhoto = appPeersManager.getPeerPhoto(peerId);\r\n if(peerPhoto) {\r\n appProfileManager.loadAvatar(peerId, peerPhoto, 'photo_small').loadPromise.then(url => {\r\n if(message.pFlags.unread) {\r\n notification.image = url;\r\n appNotificationsManager.notify(notification);\r\n }\r\n });\r\n } else {\r\n appNotificationsManager.notify(notification);\r\n }\r\n }\r\n\r\n public getScheduledMessagesStorage(peerId: number) {\r\n return this.scheduledMessagesStorage[peerId] ?? (this.scheduledMessagesStorage[peerId] = this.createMessageStorage());\r\n }\r\n\r\n public getScheduledMessages(peerId: number): Promise<number[]> {\r\n if(!this.canWriteToPeer(peerId)) return Promise.resolve([]);\r\n\r\n const storage = this.getScheduledMessagesStorage(peerId);\r\n if(Object.keys(storage).length) {\r\n return Promise.resolve(Object.keys(storage).map(id => +id));\r\n }\r\n\r\n return apiManager.invokeApi('messages.getScheduledHistory', {\r\n peer: appPeersManager.getInputPeerById(peerId),\r\n hash: 0\r\n }).then(historyResult => {\r\n if(historyResult._ !== 'messages.messagesNotModified') {\r\n appUsersManager.saveApiUsers(historyResult.users);\r\n appChatsManager.saveApiChats(historyResult.chats);\r\n \r\n const storage = this.getScheduledMessagesStorage(peerId);\r\n this.saveMessages(historyResult.messages, {storage, isScheduled: true});\r\n return Object.keys(storage).map(id => +id);\r\n }\r\n \r\n return [];\r\n });\r\n }\r\n\r\n public sendScheduledMessages(peerId: number, mids: number[]) {\r\n return apiManager.invokeApi('messages.sendScheduledMessages', {\r\n peer: appPeersManager.getInputPeerById(peerId),\r\n id: mids.map(mid => this.getServerMessageId(mid))\r\n }).then(updates => {\r\n apiUpdatesManager.processUpdateMessage(updates);\r\n });\r\n }\r\n\r\n public deleteScheduledMessages(peerId: number, mids: number[]) {\r\n return apiManager.invokeApi('messages.deleteScheduledMessages', {\r\n peer: appPeersManager.getInputPeerById(peerId),\r\n id: mids.map(mid => this.getServerMessageId(mid))\r\n }).then(updates => {\r\n apiUpdatesManager.processUpdateMessage(updates);\r\n });\r\n }\r\n\r\n /**\r\n * * https://core.telegram.org/api/offsets, offset_id is inclusive\r\n */\r\n public getHistory(peerId: number, maxId = 0, limit: number, backLimit?: number, threadId?: number): Promise<HistoryResult> | HistoryResult {\r\n const historyStorage = this.getHistoryStorage(peerId, threadId);\r\n\r\n let offset = 0;\r\n /* \r\n let offsetFound = true;\r\n\r\n if(maxId) {\r\n offsetFound = false;\r\n for(; offset < historyStorage.history.length; offset++) {\r\n if(maxId > historyStorage.history.slice[offset]) {\r\n offsetFound = true;\r\n break;\r\n }\r\n }\r\n }\r\n\r\n if(offsetFound && (\r\n historyStorage.count !== null && historyStorage.history.length === historyStorage.count ||\r\n historyStorage.history.length >= offset + limit\r\n )) {\r\n if(backLimit) {\r\n backLimit = Math.min(offset, backLimit);\r\n offset = Math.max(0, offset - backLimit);\r\n limit += backLimit;\r\n } else {\r\n limit = limit;\r\n }\r\n\r\n const history = historyStorage.history.slice.slice(offset, offset + limit);\r\n return {\r\n count: historyStorage.count,\r\n history: history,\r\n offsetIdOffset: offset\r\n };\r\n }\r\n\r\n if(offsetFound) {\r\n offset = 0;\r\n } */\r\n\r\n if(backLimit) {\r\n offset = -backLimit;\r\n limit += backLimit;\r\n\r\n /* return this.requestHistory(reqPeerId, maxId, limit, offset, undefined, threadId).then((historyResult) => {\r\n historyStorage.count = (historyResult as MessagesMessages.messagesMessagesSlice).count || historyResult.messages.length;\r\n\r\n const history = (historyResult.messages as MyMessage[]).map(message => message.mid);\r\n return {\r\n count: historyStorage.count,\r\n history,\r\n offsetIdOffset: (historyResult as MessagesMessages.messagesMessagesSlice).offset_id_offset || 0\r\n };\r\n }); */\r\n }\r\n\r\n const haveSlice = historyStorage.history.sliceMe(maxId, offset, limit);\r\n if(haveSlice && (haveSlice.slice.length === limit || (haveSlice.fulfilled & SliceEnd.Both))) {\r\n return {\r\n count: historyStorage.count,\r\n history: haveSlice.slice,\r\n offsetIdOffset: haveSlice.offsetIdOffset\r\n }; \r\n }\r\n\r\n return this.fillHistoryStorage(peerId, maxId, limit, offset, historyStorage, threadId).then(() => {\r\n const slice = historyStorage.history.sliceMe(maxId, offset, limit);\r\n return {\r\n count: historyStorage.count,\r\n history: slice?.slice || historyStorage.history.constructSlice(),\r\n offsetIdOffset: slice?.offsetIdOffset || historyStorage.count\r\n };\r\n });\r\n }\r\n\r\n public fillHistoryStorage(peerId: number, offset_id: number, limit: number, add_offset: number, historyStorage: HistoryStorage, threadId?: number): Promise<void> {\r\n return this.requestHistory(peerId, offset_id, limit, add_offset, undefined, threadId).then((historyResult) => {\r\n historyStorage.count = (historyResult as MessagesMessages.messagesMessagesSlice).count || historyResult.messages.length;\r\n\r\n const offsetIdOffset = (historyResult as MessagesMessages.messagesMessagesSlice).offset_id_offset || 0;\r\n const isTopEnd = offsetIdOffset >= (historyStorage.count - limit) || historyStorage.count < (limit + add_offset);\r\n\r\n /* if(!maxId && historyResult.messages.length) {\r\n maxId = this.incrementMessageId((historyResult.messages[0] as MyMessage).mid, 1);\r\n }\r\n\r\n const wasTotalCount = historyStorage.history.length; */\r\n\r\n historyResult.messages.forEach((message) => {\r\n if(this.mergeReplyKeyboard(historyStorage, message)) {\r\n rootScope.broadcast('history_reply_markup', {peerId});\r\n }\r\n });\r\n\r\n const mids = historyResult.messages.map((message) => (message as MyMessage).mid);\r\n // * add bound manually. \r\n // * offset_id will be inclusive only if there is 'add_offset' <= -1 (-1 - will only include the 'offset_id')\r\n if(offset_id && !mids.includes(offset_id) && offsetIdOffset < historyStorage.count) {\r\n let i = 0;\r\n for(const length = mids.length; i < length; ++i) {\r\n if(offset_id > mids[i]) {\r\n break;\r\n }\r\n }\r\n\r\n mids.splice(i, 0, offset_id);\r\n }\r\n \r\n historyStorage.history.insertSlice(mids);\r\n\r\n if(isTopEnd) {\r\n historyStorage.history.last.setEnd(SliceEnd.Top);\r\n }\r\n \r\n /* const isBackLimit = offset < 0 && -offset !== fullLimit;\r\n if(isBackLimit) {\r\n return;\r\n }\r\n\r\n const totalCount = historyStorage.history.length;\r\n fullLimit -= (totalCount - wasTotalCount);\r\n\r\n const migratedNextPeer = this.migratedFromTo[peerId];\r\n const migratedPrevPeer = this.migratedToFrom[peerId]\r\n const isMigrated = migratedNextPeer !== undefined || migratedPrevPeer !== undefined;\r\n\r\n if(isMigrated) {\r\n historyStorage.count = Math.max(historyStorage.count, totalCount) + 1;\r\n }\r\n\r\n if(fullLimit > 0) {\r\n maxId = historyStorage.history.slice[totalCount - 1];\r\n if(isMigrated) {\r\n if(!historyResult.messages.length) {\r\n if(migratedPrevPeer) {\r\n maxId = 0;\r\n peerId = migratedPrevPeer;\r\n } else {\r\n historyStorage.count = totalCount;\r\n return true;\r\n }\r\n }\r\n\r\n return this.fillHistoryStorage(peerId, maxId, fullLimit, historyStorage, threadId);\r\n } else if(totalCount < historyStorage.count) {\r\n return this.fillHistoryStorage(peerId, maxId, fullLimit, offset, historyStorage, threadId);\r\n }\r\n } */\r\n });\r\n }\r\n\r\n public requestHistory(peerId: number, maxId: number, limit = 0, offset = 0, offsetDate = 0, threadId = 0): Promise<Exclude<MessagesMessages, MessagesMessages.messagesMessagesNotModified>> {\r\n //console.trace('requestHistory', peerId, maxId, limit, offset);\r\n\r\n //rootScope.broadcast('history_request');\r\n\r\n const options: any = {\r\n peer: appPeersManager.getInputPeerById(peerId),\r\n offset_id: this.getServerMessageId(maxId) || 0,\r\n offset_date: offsetDate,\r\n add_offset: offset,\r\n limit,\r\n max_id: 0,\r\n min_id: 0,\r\n hash: 0\r\n };\r\n\r\n if(threadId) {\r\n options.msg_id = this.getServerMessageId(threadId) || 0;\r\n }\r\n\r\n const promise: ReturnType<AppMessagesManager['requestHistory']> = apiManager.invokeApi(threadId ? 'messages.getReplies' : 'messages.getHistory', options, {\r\n //timeout: APITIMEOUT,\r\n noErrorBox: true\r\n }) as any;\r\n\r\n return promise.then((historyResult) => {\r\n if(DEBUG) {\r\n this.log('requestHistory result:', peerId, historyResult, maxId, limit, offset);\r\n }\r\n\r\n appUsersManager.saveApiUsers(historyResult.users);\r\n appChatsManager.saveApiChats(historyResult.chats);\r\n this.saveMessages(historyResult.messages);\r\n\r\n if(appPeersManager.isChannel(peerId)) {\r\n apiUpdatesManager.addChannelState(-peerId, (historyResult as MessagesMessages.messagesChannelMessages).pts);\r\n }\r\n\r\n let length = historyResult.messages.length;\r\n if(length && historyResult.messages[length - 1].deleted) {\r\n historyResult.messages.splice(length - 1, 1);\r\n length--;\r\n (historyResult as MessagesMessages.messagesMessagesSlice).count--;\r\n }\r\n\r\n // will load more history if last message is album grouped (because it can be not last item)\r\n const historyStorage = this.getHistoryStorage(peerId, threadId);\r\n // historyResult.messages: desc sorted\r\n if(length && (historyResult.messages[length - 1] as Message.message).grouped_id \r\n && (historyStorage.history.length + historyResult.messages.length) < (historyResult as MessagesMessages.messagesMessagesSlice).count) {\r\n return this.requestHistory(peerId, (historyResult.messages[length - 1] as Message.message).mid, 10, 0, offsetDate, threadId).then((_historyResult) => {\r\n return historyResult;\r\n });\r\n }\r\n\r\n return historyResult;\r\n }, (error) => {\r\n switch (error.type) {\r\n case 'CHANNEL_PRIVATE':\r\n let channel = appChatsManager.getChat(-peerId);\r\n channel = {_: 'channelForbidden', access_hash: channel.access_hash, title: channel.title};\r\n apiUpdatesManager.processUpdateMessage({\r\n _: 'updates',\r\n updates: [{\r\n _: 'updateChannel',\r\n channel_id: -peerId\r\n }],\r\n chats: [channel],\r\n users: []\r\n });\r\n break;\r\n }\r\n\r\n throw error;\r\n });\r\n }\r\n\r\n public fetchSingleMessages() {\r\n if(this.fetchSingleMessagesPromise) {\r\n return this.fetchSingleMessagesPromise;\r\n }\r\n\r\n return this.fetchSingleMessagesPromise = new Promise((resolve) => {\r\n setTimeout(() => {\r\n let promises: Promise<void>[] = [];\r\n \r\n for(const peerId in this.needSingleMessages) {\r\n const mids = this.needSingleMessages[peerId];\r\n delete this.needSingleMessages[peerId];\r\n \r\n const msgIds: InputMessage[] = mids.map((msgId: number) => {\r\n return {\r\n _: 'inputMessageID',\r\n id: this.getServerMessageId(msgId)\r\n };\r\n });\r\n \r\n let promise: Promise<MethodDeclMap['channels.getMessages']['res'] | MethodDeclMap['messages.getMessages']['res']>;\r\n if(+peerId < 0 && appPeersManager.isChannel(+peerId)) {\r\n promise = apiManager.invokeApi('channels.getMessages', {\r\n channel: appChatsManager.getChannelInput(-+peerId),\r\n id: msgIds\r\n });\r\n } else {\r\n promise = apiManager.invokeApi('messages.getMessages', {\r\n id: msgIds\r\n });\r\n }\r\n \r\n promises.push(promise.then(getMessagesResult => {\r\n if(getMessagesResult._ !== 'messages.messagesNotModified') {\r\n appUsersManager.saveApiUsers(getMessagesResult.users);\r\n appChatsManager.saveApiChats(getMessagesResult.chats);\r\n this.saveMessages(getMessagesResult.messages);\r\n }\r\n \r\n rootScope.broadcast('messages_downloaded', {peerId: +peerId, mids});\r\n }));\r\n }\r\n\r\n Promise.all(promises).finally(() => {\r\n this.fetchSingleMessagesPromise = null;\r\n if(Object.keys(this.needSingleMessages).length) this.fetchSingleMessages();\r\n resolve();\r\n });\r\n }, 0);\r\n });\r\n }\r\n\r\n public wrapSingleMessage(peerId: number, msgId: number, overwrite = false): Promise<void> {\r\n if(!this.getMessageByPeer(peerId, msgId).deleted && !overwrite) {\r\n rootScope.broadcast('messages_downloaded', {peerId, mids: [msgId]});\r\n return Promise.resolve();\r\n } else if(!this.needSingleMessages[peerId] || this.needSingleMessages[peerId].indexOf(msgId) === -1) {\r\n (this.needSingleMessages[peerId] ?? (this.needSingleMessages[peerId] = [])).push(msgId);\r\n return this.fetchSingleMessages();\r\n } else if(this.fetchSingleMessagesPromise) {\r\n return this.fetchSingleMessagesPromise;\r\n }\r\n }\r\n\r\n public setTyping(peerId: number, _action: any): Promise<boolean> {\r\n if(!rootScope.myId || !peerId || !this.canWriteToPeer(peerId) || peerId === rootScope.myId) return Promise.resolve(false);\r\n \r\n const action: SendMessageAction = typeof(_action) === 'string' ? {_: _action} : _action;\r\n return apiManager.invokeApi('messages.setTyping', {\r\n peer: appPeersManager.getInputPeerById(peerId),\r\n action\r\n }) as Promise<boolean>;\r\n }\r\n\r\n private handleDeletedMessages(peerId: number, storage: MessagesStorage, messages: number[]) {\r\n const history: {\r\n count: number, \r\n unread: number, \r\n msgs: {[mid: number]: true},\r\n albums?: {[groupId: string]: Set<number>},\r\n } = {count: 0, unread: 0, msgs: {}} as any;\r\n\r\n for(const mid of messages) {\r\n const message: MyMessage = this.getMessageFromStorage(storage, mid);\r\n if(message.deleted) continue;\r\n\r\n if((message as Message.message).media) {\r\n // @ts-ignore\r\n const c = message.media.webpage || message.media;\r\n const smth = c.photo || c.document;\r\n\r\n if(smth?.file_reference) {\r\n referenceDatabase.deleteContext(smth.file_reference, {type: 'message', peerId, messageId: mid});\r\n }\r\n\r\n // @ts-ignore\r\n if(message.media.webpage) {\r\n // @ts-ignore\r\n appWebPagesManager.deleteWebPageFromPending(message.media.webpage, mid);\r\n }\r\n }\r\n\r\n this.updateMessageRepliesIfNeeded(message);\r\n\r\n if(!message.pFlags.out && !message.pFlags.is_outgoing && message.pFlags.unread) {\r\n history.unread++;\r\n appNotificationsManager.cancel('msg' + mid);\r\n }\r\n history.count++;\r\n history.msgs[mid] = true;\r\n\r\n message.deleted = true;\r\n\r\n if(message._ !== 'messageService' && message.grouped_id) {\r\n const groupedStorage = this.groupedMessagesStorage[message.grouped_id];\r\n if(groupedStorage) {\r\n delete groupedStorage[mid];\r\n\r\n if(!history.albums) history.albums = {};\r\n (history.albums[message.grouped_id] || (history.albums[message.grouped_id] = new Set())).add(mid);\r\n\r\n if(!Object.keys(groupedStorage).length) {\r\n delete history.albums;\r\n delete this.groupedMessagesStorage[message.grouped_id];\r\n }\r\n }\r\n }\r\n\r\n delete storage[mid];\r\n\r\n const peerMessagesToHandle = this.newMessagesToHandle[peerId];\r\n if(peerMessagesToHandle && peerMessagesToHandle.has(mid)) {\r\n peerMessagesToHandle.delete(mid);\r\n }\r\n }\r\n\r\n if(history.albums) {\r\n for(const groupId in history.albums) {\r\n rootScope.broadcast('album_edit', {peerId, groupId, deletedMids: [...history.albums[groupId]]});\r\n /* const mids = this.getMidsByAlbum(groupId);\r\n if(mids.length) {\r\n const mid = Math.max(...mids);\r\n rootScope.$broadcast('message_edit', {peerId, mid, justMedia: false});\r\n } */\r\n }\r\n }\r\n\r\n return history;\r\n }\r\n \r\n private handleEditedMessage(oldMessage: any, newMessage: any) {\r\n if(oldMessage.media?.webpage) {\r\n appWebPagesManager.deleteWebPageFromPending(oldMessage.media.webpage, oldMessage.mid);\r\n }\r\n }\r\n}\r\n\r\nconst appMessagesManager = new AppMessagesManager();\r\nMOUNT_CLASS_TO.appMessagesManager = appMessagesManager;\r\nexport default appMessagesManager;\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 { MOUNT_CLASS_TO } from \"../../config/debug\";\r\nimport { isObject } from \"../../helpers/object\";\r\nimport { ChatPhoto, DialogPeer, InputDialogPeer, InputNotifyPeer, InputPeer, Peer, Update, UserProfilePhoto } from \"../../layer\";\r\nimport { LangPackKey } from \"../langPack\";\r\nimport { RichTextProcessor } from \"../richtextprocessor\";\r\nimport rootScope from \"../rootScope\";\r\nimport appChatsManager from \"./appChatsManager\";\r\nimport appUsersManager from \"./appUsersManager\";\r\n\r\n// https://github.com/eelcohn/Telegram-API/wiki/Calculating-color-for-a-Telegram-user-on-IRC\r\n/*\r\n HTML-color IRC-color Description\r\n #c03d33 4 red\r\n #4fad2d 3 green\r\n #d09306 7 yellow\r\n #168acd 10 blue\r\n #8544d6 6 purple\r\n #cd4073 13 pink\r\n #2996ad 11 sea\r\n #ce671b 5 orange\r\n */\r\nconst DialogColorsFg = ['#fc5c51', '#0fb297', '#d09306', '#3d72ed', '#895dd5', '#cd4073', '#00c1a6', '#fa790f'];\r\nconst DialogColors = ['red', 'green', 'yellow', 'blue', 'violet', 'pink', 'cyan', 'orange'];\r\nconst DialogColorsMap = [0, 7, 4, 1, 6, 3, 5];\r\n\r\nexport type PeerType = 'channel' | 'chat' | 'megagroup' | 'group' | 'saved';\r\nexport class AppPeersManager {\r\n constructor() {\r\n rootScope.addMultipleEventsListeners({\r\n updatePeerBlocked: (update) => {\r\n rootScope.broadcast('peer_block', {peerId: this.getPeerId(update.peer_id), blocked: update.blocked});\r\n }\r\n });\r\n }\r\n /* public savePeerInstance(peerId: number, instance: any) {\r\n if(peerId < 0) appChatsManager.saveApiChat(instance);\r\n else appUsersManager.saveApiUser(instance);\r\n } */\r\n\r\n public canPinMessage(peerId: number) {\r\n return peerId > 0 || appChatsManager.hasRights(-peerId, 'pin_messages');\r\n }\r\n\r\n public getPeerPhoto(peerId: number): UserProfilePhoto.userProfilePhoto | ChatPhoto.chatPhoto {\r\n const photo = peerId > 0\r\n ? appUsersManager.getUserPhoto(peerId)\r\n : appChatsManager.getChatPhoto(-peerId);\r\n\r\n return photo._ !== 'chatPhotoEmpty' && photo._ !== 'userProfilePhotoEmpty' ? photo : null;\r\n }\r\n\r\n public getPeerMigratedTo(peerId: number) {\r\n if(peerId >= 0) {\r\n return false;\r\n }\r\n\r\n let chat = appChatsManager.getChat(-peerId);\r\n if(chat && chat.migrated_to && chat.pFlags.deactivated) {\r\n return this.getPeerId(chat.migrated_to);\r\n }\r\n \r\n return false;\r\n }\r\n\r\n public getPeerTitle(peerId: number | any, plainText = false, onlyFirstName = false) {\r\n if(!peerId) {\r\n peerId = rootScope.myId;\r\n }\r\n \r\n let peer: any = {}; \r\n if(!isObject(peerId)) {\r\n peer = this.getPeer(peerId);\r\n } else peer = peerId;\r\n\r\n let title = '';\r\n if(peerId > 0) {\r\n if(peer.first_name) title += peer.first_name;\r\n if(peer.last_name) title += ' ' + peer.last_name;\r\n \r\n if(!title) title = peer.pFlags.deleted ? 'Deleted Account' : peer.username;\r\n else title = title.trim();\r\n } else {\r\n title = peer.title;\r\n }\r\n\r\n if(onlyFirstName) {\r\n title = title.split(' ')[0];\r\n }\r\n \r\n return plainText ? title : RichTextProcessor.wrapEmojiText(title);\r\n }\r\n \r\n public getOutputPeer(peerId: number): Peer {\r\n if(peerId > 0) {\r\n return {_: 'peerUser', user_id: peerId};\r\n }\r\n\r\n let chatId = -peerId;\r\n if(appChatsManager.isChannel(chatId)) {\r\n return {_: 'peerChannel', channel_id: chatId};\r\n }\r\n\r\n return {_: 'peerChat', chat_id: chatId};\r\n }\r\n\r\n public getPeerString(peerId: number) {\r\n if(peerId > 0) {\r\n return appUsersManager.getUserString(peerId);\r\n }\r\n return appChatsManager.getChatString(-peerId);\r\n }\r\n\r\n public getPeerUsername(peerId: number): string {\r\n if(peerId > 0) {\r\n return appUsersManager.getUser(peerId).username || '';\r\n }\r\n return appChatsManager.getChat(-peerId).username || '';\r\n }\r\n\r\n public getPeer(peerId: number) {\r\n return peerId > 0\r\n ? appUsersManager.getUser(peerId)\r\n : appChatsManager.getChat(-peerId)\r\n }\r\n\r\n public getPeerId(peerId: Peer | InputPeer | number | string): number {\r\n if(typeof(peerId) === 'number') return peerId;\r\n else if(isObject(peerId)) return (peerId as Peer.peerUser).user_id || -((peerId as Peer.peerChannel).channel_id || (peerId as Peer.peerChat).chat_id);\r\n else if(!peerId) return 0;\r\n \r\n const isUser = (peerId as string).charAt(0) === 'u';\r\n const peerParams = (peerId as string).substr(1).split('_');\r\n\r\n return isUser ? +peerParams[0] : -peerParams[0] || 0;\r\n }\r\n\r\n public getDialogPeer(peerId: number): DialogPeer {\r\n return {\r\n _: 'dialogPeer',\r\n peer: this.getOutputPeer(peerId)\r\n };\r\n }\r\n\r\n public isChannel(peerId: number): boolean {\r\n return (peerId < 0) && appChatsManager.isChannel(-peerId);\r\n }\r\n\r\n public isMegagroup(peerId: number) {\r\n return (peerId < 0) && appChatsManager.isMegagroup(-peerId);\r\n }\r\n\r\n public isAnyGroup(peerId: number): boolean {\r\n return (peerId < 0) && !appChatsManager.isBroadcast(-peerId);\r\n }\r\n\r\n public isBroadcast(peerId: number): boolean {\r\n return this.isChannel(peerId) && !this.isMegagroup(peerId);\r\n }\r\n\r\n public isBot(peerId: number): boolean {\r\n return (peerId > 0) && appUsersManager.isBot(peerId);\r\n }\r\n\r\n /* public getInputPeer(peerString: string): InputPeer {\r\n var firstChar = peerString.charAt(0);\r\n var peerParams = peerString.substr(1).split('_');\r\n let id = +peerParams[0];\r\n\r\n if(firstChar === 'u') {\r\n //appUsersManager.saveUserAccess(id, peerParams[1]);\r\n\r\n return {\r\n _: 'inputPeerUser',\r\n user_id: id,\r\n access_hash: peerParams[1]\r\n };\r\n } else if(firstChar === 'c' || firstChar === 's') {\r\n //appChatsManager.saveChannelAccess(id, peerParams[1]);\r\n if(firstChar === 's') {\r\n appChatsManager.saveIsMegagroup(id);\r\n }\r\n\r\n return {\r\n _: 'inputPeerChannel',\r\n channel_id: id,\r\n access_hash: peerParams[1] || '0'\r\n };\r\n } else {\r\n return {\r\n _: 'inputPeerChat',\r\n chat_id: id\r\n };\r\n }\r\n } */\r\n\r\n public getInputNotifyPeerById(peerId: number, ignorePeerId: true): Exclude<InputNotifyPeer, InputNotifyPeer.inputNotifyPeer>;\r\n public getInputNotifyPeerById(peerId: number, ignorePeerId?: false): InputNotifyPeer.inputNotifyPeer;\r\n public getInputNotifyPeerById(peerId: number, ignorePeerId?: boolean): InputNotifyPeer {\r\n if(ignorePeerId) {\r\n if(peerId > 0) {\r\n return {_: 'inputNotifyUsers'};\r\n } else {\r\n if(appPeersManager.isBroadcast(peerId)) {\r\n return {_: 'inputNotifyBroadcasts'};\r\n } else {\r\n return {_: 'inputNotifyChats'};\r\n }\r\n }\r\n } else {\r\n return {\r\n _: 'inputNotifyPeer', \r\n peer: this.getInputPeerById(peerId)\r\n };\r\n }\r\n }\r\n\r\n public getInputPeerById(peerId: number): InputPeer {\r\n if(!peerId) {\r\n return {_: 'inputPeerEmpty'};\r\n }\r\n\r\n if(peerId < 0) {\r\n const chatId = -peerId;\r\n if(!appChatsManager.isChannel(chatId)) {\r\n return appChatsManager.getChatInputPeer(chatId);\r\n } else {\r\n return appChatsManager.getChannelInputPeer(chatId);\r\n }\r\n }\r\n\r\n return {\r\n _: 'inputPeerUser',\r\n user_id: peerId,\r\n access_hash: appUsersManager.getUser(peerId).access_hash\r\n };\r\n }\r\n\r\n public getInputDialogPeerById(peerId: number): InputDialogPeer {\r\n return {\r\n _: 'inputDialogPeer',\r\n peer: this.getInputPeerById(peerId)\r\n }\r\n }\r\n\r\n public getPeerColorById(peerId: number, pic = true) {\r\n if(!peerId) return '';\r\n\r\n const idx = DialogColorsMap[(peerId < 0 ? -peerId : peerId) % 7];\r\n const color = (pic ? DialogColors : DialogColorsFg)[idx];\r\n return color;\r\n }\r\n\r\n public getPeerSearchText(peerId: number) {\r\n let text;\r\n if(peerId > 0) {\r\n text = '%pu ' + appUsersManager.getUserSearchText(peerId);\r\n } else if(peerId < 0) {\r\n const chat = appChatsManager.getChat(-peerId);\r\n text = '%pg ' + (chat.title || '');\r\n }\r\n return text;\r\n }\r\n\r\n public getDialogType(peerId: number): PeerType {\r\n if(appPeersManager.isMegagroup(peerId)) {\r\n return 'megagroup';\r\n } else if(appPeersManager.isChannel(peerId)) {\r\n return 'channel';\r\n } else if(peerId < 0) {\r\n return 'group';\r\n } else {\r\n return peerId === rootScope.myId ? 'saved' : 'chat';\r\n }\r\n }\r\n\r\n public getDeleteButtonText(peerId: number): LangPackKey {\r\n switch(this.getDialogType(peerId)) {\r\n case 'channel':\r\n return 'ChatList.Context.LeaveChannel';\r\n\r\n case 'megagroup':\r\n return 'ChatList.Context.LeaveGroup';\r\n\r\n case 'group':\r\n return 'ChatList.Context.DeleteAndExit';\r\n \r\n default:\r\n return 'ChatList.Context.DeleteChat';\r\n }\r\n }\r\n}\r\n\r\nconst appPeersManager = new AppPeersManager();\r\nMOUNT_CLASS_TO.appPeersManager = appPeersManager;\r\nexport default appPeersManager;\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 { MOUNT_CLASS_TO } from \"../../config/debug\";\r\nimport { numberThousandSplitter } from \"../../helpers/number\";\r\nimport { isObject, safeReplaceObject, copy, deepEqual } from \"../../helpers/object\";\r\nimport { ChannelParticipant, Chat, ChatAdminRights, ChatBannedRights, ChatFull, ChatParticipants, InputChannel, InputChatPhoto, InputFile, InputPeer, SendMessageAction, Update, Updates } from \"../../layer\";\r\nimport { i18n, LangPackKey } from \"../langPack\";\r\nimport apiManagerProxy from \"../mtproto/mtprotoworker\";\r\nimport apiManager from '../mtproto/mtprotoworker';\r\nimport { RichTextProcessor } from \"../richtextprocessor\";\r\nimport rootScope from \"../rootScope\";\r\n//import AppStorage from \"../storage\";\r\nimport apiUpdatesManager from \"./apiUpdatesManager\";\r\nimport appMessagesManager from \"./appMessagesManager\";\r\nimport appPeersManager from \"./appPeersManager\";\r\nimport appProfileManager from \"./appProfileManager\";\r\nimport appStateManager from \"./appStateManager\";\r\nimport appUsersManager from \"./appUsersManager\";\r\n\r\nexport type Channel = Chat.channel;\r\n\r\nexport type ChatRights = keyof ChatBannedRights['pFlags'] | keyof ChatAdminRights['pFlags'] | 'change_type' | 'change_permissions' | 'delete_chat' | 'view_participants';\r\n\r\nexport type UserTyping = Partial<{userId: number, action: SendMessageAction, timeout: number}>;\r\n\r\nexport class AppChatsManager {\r\n /* private storage = new AppStorage<Record<number, Chat>>({\r\n storeName: 'chats'\r\n }); */\r\n \r\n private chats: {[id: number]: Chat.channel | Chat.chat | any} = {};\r\n //private usernames: any = {};\r\n //private channelAccess: any = {};\r\n //private megagroups: {[id: number]: true} = {};\r\n\r\n private megagroupOnlines: {[id: number]: {timestamp: number, onlines: number}} = {};\r\n\r\n private typingsInPeer: {[peerId: number]: UserTyping[]} = {};\r\n\r\n constructor() {\r\n rootScope.addMultipleEventsListeners({\r\n updateChannel: (update) => {\r\n const channelId = update.channel_id;\r\n //console.log('updateChannel:', update);\r\n rootScope.broadcast('channel_settings', {channelId});\r\n },\r\n\r\n updateChannelParticipant: (update) => {\r\n apiManagerProxy.clearCache('channels.getParticipants', (params) => {\r\n return (params.channel as InputChannel.inputChannel).channel_id === update.channel_id;\r\n });\r\n },\r\n\r\n updateChatDefaultBannedRights: (update) => {\r\n const chatId = -appPeersManager.getPeerId(update.peer);\r\n const chat: Chat.chat = this.chats[chatId];\r\n if(chat) {\r\n chat.default_banned_rights = update.default_banned_rights;\r\n rootScope.broadcast('chat_update', chatId);\r\n }\r\n },\r\n\r\n updateUserTyping: this.onUpdateUserTyping,\r\n updateChatUserTyping: this.onUpdateUserTyping,\r\n updateChannelUserTyping: this.onUpdateUserTyping\r\n });\r\n\r\n appStateManager.getState().then((state) => {\r\n this.chats = state.chats;\r\n });\r\n }\r\n\r\n private onUpdateUserTyping = (update: Update.updateUserTyping | Update.updateChatUserTyping | Update.updateChannelUserTyping) => {\r\n const fromId = (update as Update.updateUserTyping).user_id || appPeersManager.getPeerId((update as Update.updateChatUserTyping).from_id);\r\n if(rootScope.myId === fromId || update.action._ === 'speakingInGroupCallAction') {\r\n return;\r\n }\r\n \r\n const peerId = update._ === 'updateUserTyping' ? \r\n fromId : \r\n -((update as Update.updateChatUserTyping).chat_id || (update as Update.updateChannelUserTyping).channel_id);\r\n const typings = this.typingsInPeer[peerId] ?? (this.typingsInPeer[peerId] = []);\r\n let typing = typings.find(t => t.userId === fromId);\r\n\r\n const cancelAction = () => {\r\n delete typing.timeout;\r\n //typings.findAndSplice(t => t === typing);\r\n const idx = typings.indexOf(typing);\r\n if(idx !== -1) {\r\n typings.splice(idx, 1);\r\n }\r\n\r\n rootScope.broadcast('peer_typings', {peerId, typings});\r\n\r\n if(!typings.length) {\r\n delete this.typingsInPeer[peerId];\r\n }\r\n };\r\n\r\n if(typing && typing.timeout !== undefined) {\r\n clearTimeout(typing.timeout);\r\n }\r\n\r\n if(update.action._ === 'sendMessageCancelAction') {\r\n if(!typing) {\r\n return;\r\n }\r\n\r\n cancelAction();\r\n return;\r\n } else {\r\n if(!typing) {\r\n typing = {\r\n userId: fromId\r\n };\r\n\r\n typings.push(typing);\r\n }\r\n\r\n //console.log('updateChatUserTyping', update, typings);\r\n \r\n typing.action = update.action;\r\n \r\n if(!appUsersManager.hasUser(fromId)) {\r\n if(update._ === 'updateChatUserTyping') {\r\n if(update.chat_id && appChatsManager.hasChat(update.chat_id) && !appChatsManager.isChannel(update.chat_id)) {\r\n appProfileManager.getChatFull(update.chat_id);\r\n }\r\n }\r\n \r\n //return;\r\n }\r\n \r\n appUsersManager.forceUserOnline(fromId);\r\n\r\n typing.timeout = window.setTimeout(cancelAction, 6000);\r\n rootScope.broadcast('peer_typings', {peerId, typings});\r\n }\r\n };\r\n\r\n public getPeerTypings(peerId: number) {\r\n return this.typingsInPeer[peerId];\r\n }\r\n\r\n public saveApiChats(apiChats: any[], override?: boolean) {\r\n apiChats.forEach(chat => this.saveApiChat(chat, override));\r\n }\r\n\r\n public saveApiChat(chat: any, override?: boolean) {\r\n /* if(chat._ !== 'chat' && chat._ !== 'channel') {\r\n return;\r\n } */\r\n \r\n // * exclude from state\r\n // defineNotNumerableProperties(chat, ['rTitle', 'initials']);\r\n\r\n const oldChat = this.chats[chat.id];\r\n\r\n /* if(oldChat && !override) {\r\n return;\r\n } */\r\n\r\n if(chat.pFlags === undefined) {\r\n chat.pFlags = {};\r\n }\r\n\r\n if(chat.pFlags.min && oldChat !== undefined) {\r\n return;\r\n }\r\n\r\n chat.initials = RichTextProcessor.getAbbreviation(chat.title);\r\n\r\n //console.log('im the weatherman', chat.id);\r\n\r\n if(chat._ === 'channel' &&\r\n chat.participants_count === undefined &&\r\n oldChat !== undefined &&\r\n oldChat.participants_count) {\r\n chat.participants_count = oldChat.participants_count;\r\n }\r\n\r\n /* if(chat.username) {\r\n let searchUsername = searchIndexManager.cleanUsername(chat.username);\r\n this.usernames[searchUsername] = chat.id;\r\n } */\r\n\r\n let changedPhoto = false, changedTitle = false;\r\n if(oldChat === undefined) {\r\n this.chats[chat.id] = chat;\r\n } else {\r\n const oldPhoto = oldChat.photo?.photo_small;\r\n const newPhoto = chat.photo?.photo_small;\r\n if(JSON.stringify(oldPhoto) !== JSON.stringify(newPhoto)) {\r\n changedPhoto = true;\r\n }\r\n\r\n if(oldChat.title !== chat.title) {\r\n changedTitle = true;\r\n }\r\n\r\n safeReplaceObject(oldChat, chat);\r\n rootScope.broadcast('chat_update', chat.id);\r\n }\r\n\r\n if(changedPhoto) {\r\n rootScope.broadcast('avatar_update', -chat.id);\r\n }\r\n\r\n if(changedTitle) {\r\n rootScope.broadcast('peer_title_edit', -chat.id);\r\n }\r\n\r\n /* this.storage.set({\r\n [chat.id]: chat\r\n }); */\r\n }\r\n\r\n public getChat(id: number) {\r\n if(id < 0) id = -id;\r\n return this.chats[id] || {_: 'chatEmpty', id, deleted: true, access_hash: '', pFlags: {}/* this.channelAccess[id] */};\r\n }\r\n\r\n public combineParticipantBannedRights(id: number, rights: ChatBannedRights) {\r\n const chat: Chat.channel = this.getChat(id);\r\n\r\n if(chat.default_banned_rights) {\r\n rights = copy(rights);\r\n const defaultRights = chat.default_banned_rights.pFlags;\r\n for(let i in defaultRights) {\r\n // @ts-ignore\r\n rights.pFlags[i] = defaultRights[i];\r\n }\r\n }\r\n\r\n return rights;\r\n }\r\n\r\n public hasRights(id: number, action: ChatRights, rights?: ChatAdminRights | ChatBannedRights) {\r\n const chat: Chat = this.getChat(id);\r\n if(chat._ === 'chatEmpty') return false;\r\n\r\n if(chat._ === 'chatForbidden' ||\r\n chat._ === 'channelForbidden' ||\r\n (chat as Chat.chat).pFlags.kicked ||\r\n (chat.pFlags.left && !(chat as Chat.channel).pFlags.megagroup)) {\r\n return false;\r\n }\r\n\r\n if(chat.pFlags.creator && rights === undefined) {\r\n return true;\r\n }\r\n\r\n if(!rights) {\r\n rights = chat.admin_rights || (chat as Chat.channel).banned_rights || chat.default_banned_rights;\r\n }\r\n \r\n if(!rights) {\r\n return false;\r\n }\r\n\r\n let myFlags: Partial<{[flag in keyof ChatBannedRights['pFlags'] | keyof ChatAdminRights['pFlags']]: true}> = {};\r\n if(rights) myFlags = rights.pFlags as any;\r\n\r\n switch(action) {\r\n case 'embed_links':\r\n case 'send_games':\r\n case 'send_gifs':\r\n case 'send_inline':\r\n case 'send_media':\r\n case 'send_messages':\r\n case 'send_polls':\r\n case 'send_stickers': {\r\n if(rights._ === 'chatBannedRights' && myFlags[action]) {\r\n return false;\r\n }\r\n\r\n if(chat._ === 'channel') {\r\n if((!chat.pFlags.megagroup && !myFlags.post_messages)) {\r\n return false;\r\n }\r\n }\r\n\r\n break;\r\n }\r\n\r\n // * revoke foreign messages\r\n case 'delete_messages': {\r\n return !!myFlags.delete_messages;\r\n }\r\n\r\n case 'pin_messages': {\r\n return rights._ === 'chatAdminRights' ? myFlags[action] || !!myFlags.post_messages : !myFlags[action];\r\n }\r\n\r\n case 'invite_users':\r\n case 'change_info': {\r\n return rights._ === 'chatAdminRights' ? myFlags[action] : !myFlags[action];\r\n }\r\n\r\n // * only creator can do that\r\n case 'change_type':\r\n case 'delete_chat': {\r\n return false;\r\n }\r\n\r\n case 'change_permissions': {\r\n return rights._ === 'chatAdminRights' && myFlags['ban_users'];\r\n }\r\n\r\n case 'view_participants': {\r\n return !!(chat._ === 'chat' || !chat.pFlags.broadcast || chat.pFlags.creator || chat.admin_rights);\r\n }\r\n }\r\n\r\n return true;\r\n }\r\n\r\n public editChatDefaultBannedRights(id: number, banned_rights: ChatBannedRights) {\r\n const chat: Chat.chat = this.getChat(id);\r\n if(chat.default_banned_rights) {\r\n if(chat.default_banned_rights.until_date === banned_rights.until_date && deepEqual(chat.default_banned_rights.pFlags, banned_rights.pFlags)) {\r\n return Promise.resolve();\r\n }\r\n }\r\n \r\n return apiManager.invokeApi('messages.editChatDefaultBannedRights', {\r\n peer: appPeersManager.getInputPeerById(-id),\r\n banned_rights\r\n }).then(this.onChatUpdated.bind(this, id));\r\n }\r\n\r\n /* public resolveUsername(username: string) {\r\n return this.usernames[username] || 0;\r\n } */\r\n\r\n /* public saveChannelAccess(id: number, accessHash: string) {\r\n this.channelAccess[id] = accessHash;\r\n } */\r\n\r\n /* public saveIsMegagroup(id: number) {\r\n this.megagroups[id] = true;\r\n } */\r\n\r\n public isChannel(id: number) {\r\n if(id < 0) id = -id;\r\n const chat = this.chats[id];\r\n return chat && (chat._ === 'channel' || chat._ === 'channelForbidden')/* || this.channelAccess[id] */;\r\n }\r\n\r\n public isMegagroup(id: number) {\r\n /* if(this.megagroups[id]) {\r\n return true;\r\n } */\r\n\r\n const chat = this.chats[id];\r\n return chat && chat._ === 'channel' && chat.pFlags.megagroup;\r\n }\r\n\r\n public isBroadcast(id: number) {\r\n return this.isChannel(id) && !this.isMegagroup(id);\r\n }\r\n\r\n public getChannelInput(id: number): InputChannel {\r\n if(id < 0) id = -id;\r\n const chat: Chat = this.getChat(id);\r\n if(chat._ === 'chatEmpty' || !(chat as Chat.channel).access_hash) {\r\n return {\r\n _: 'inputChannelEmpty'\r\n };\r\n } else {\r\n return {\r\n _: 'inputChannel',\r\n channel_id: id,\r\n access_hash: (chat as Chat.channel).access_hash/* || this.channelAccess[id] */ || '0'\r\n };\r\n }\r\n }\r\n\r\n public getChatInputPeer(id: number): InputPeer.inputPeerChat {\r\n return {\r\n _: 'inputPeerChat',\r\n chat_id: id\r\n };\r\n }\r\n\r\n public getChannelInputPeer(id: number): InputPeer.inputPeerChannel {\r\n return {\r\n _: 'inputPeerChannel',\r\n channel_id: id,\r\n access_hash: this.getChat(id).access_hash/* || this.channelAccess[id] */ || 0\r\n };\r\n }\r\n\r\n public hasChat(id: number, allowMin?: true) {\r\n const chat = this.chats[id]\r\n return isObject(chat) && (allowMin || !chat.pFlags.min);\r\n }\r\n\r\n public getChatPhoto(id: number) {\r\n const chat: Chat.chat = this.getChat(id);\r\n\r\n return chat && chat.photo || {\r\n _: 'chatPhotoEmpty'\r\n };\r\n }\r\n\r\n public getChatString(id: number) {\r\n const chat = this.getChat(id);\r\n if(this.isChannel(id)) {\r\n return (this.isMegagroup(id) ? 's' : 'c') + id + '_' + chat.access_hash;\r\n }\r\n return 'g' + id;\r\n }\r\n\r\n public getChatMembersString(id: number) {\r\n const chat = this.getChat(id);\r\n const chatFull = appProfileManager.chatsFull[id];\r\n let count: number;\r\n if(chatFull) {\r\n if(chatFull._ === 'channelFull') {\r\n count = chatFull.participants_count;\r\n } else {\r\n count = (chatFull.participants as ChatParticipants.chatParticipants).participants?.length;\r\n }\r\n } else {\r\n count = chat.participants_count || chat.participants?.participants.length;\r\n }\r\n\r\n const isChannel = this.isBroadcast(id);\r\n count = count || 1;\r\n\r\n let key: LangPackKey = isChannel ? 'Peer.Status.Subscribers' : 'Peer.Status.Member';\r\n return i18n(key, [numberThousandSplitter(count)]);\r\n }\r\n\r\n /* public wrapForFull(id: number, fullChat: any) {\r\n const chatFull = copy(fullChat);\r\n const chat = this.getChat(id);\r\n\r\n if(!chatFull.participants_count) {\r\n chatFull.participants_count = chat.participants_count;\r\n }\r\n\r\n if(chatFull.participants &&\r\n chatFull.participants._ === 'chatParticipants') {\r\n chatFull.participants.participants = this.wrapParticipants(id, chatFull.participants.participants);\r\n }\r\n\r\n if(chatFull.about) {\r\n chatFull.rAbout = RichTextProcessor.wrapRichText(chatFull.about, {noLinebreaks: true});\r\n }\r\n\r\n //chatFull.peerString = this.getChatString(id);\r\n chatFull.chat = chat;\r\n\r\n return chatFull;\r\n }\r\n\r\n public wrapParticipants(id: number, participants: any[]) {\r\n const chat = this.getChat(id);\r\n const myId = appUsersManager.getSelf().id;\r\n if(this.isChannel(id)) {\r\n const isAdmin = chat.pFlags.creator;\r\n participants.forEach((participant) => {\r\n participant.canLeave = myId === participant.user_id;\r\n participant.canKick = isAdmin && participant._ === 'channelParticipant';\r\n\r\n // just for order by last seen\r\n participant.user = appUsersManager.getUser(participant.user_id);\r\n });\r\n } else {\r\n const isAdmin = chat.pFlags.creator || chat.pFlags.admins_enabled && chat.pFlags.admin;\r\n participants.forEach((participant) => {\r\n participant.canLeave = myId === participant.user_id;\r\n participant.canKick = !participant.canLeave && (\r\n chat.pFlags.creator ||\r\n participant._ === 'chatParticipant' && (isAdmin || myId === participant.inviter_id)\r\n );\r\n\r\n // just for order by last seen\r\n participant.user = appUsersManager.getUser(participant.user_id);\r\n });\r\n }\r\n\r\n return participants;\r\n } */\r\n\r\n public createChannel(title: string, about: string): Promise<number> {\r\n return apiManager.invokeApi('channels.createChannel', {\r\n broadcast: true,\r\n title,\r\n about\r\n }).then((updates: any) => {\r\n apiUpdatesManager.processUpdateMessage(updates);\r\n\r\n const channelId = updates.chats[0].id;\r\n rootScope.broadcast('history_focus', {peerId: -channelId});\r\n\r\n return channelId;\r\n });\r\n }\r\n\r\n public inviteToChannel(id: number, userIds: number[]) {\r\n const input = this.getChannelInput(id);\r\n const usersInputs = userIds.map(u => appUsersManager.getUserInput(u));\r\n\r\n return apiManager.invokeApi('channels.inviteToChannel', {\r\n channel: input,\r\n users: usersInputs\r\n }).then(updates => {\r\n apiUpdatesManager.processUpdateMessage(updates);\r\n });\r\n }\r\n\r\n public createChat(title: string, userIds: number[]): Promise<number> {\r\n return apiManager.invokeApi('messages.createChat', {\r\n users: userIds.map(u => appUsersManager.getUserInput(u)),\r\n title\r\n }).then(updates => {\r\n apiUpdatesManager.processUpdateMessage(updates);\r\n\r\n const chatId = (updates as any as Updates.updates).chats[0].id;\r\n rootScope.broadcast('history_focus', {peerId: -chatId});\r\n\r\n return chatId;\r\n });\r\n }\r\n\r\n public async getOnlines(id: number): Promise<number> {\r\n if(this.isMegagroup(id)) {\r\n const timestamp = Date.now() / 1000 | 0;\r\n const cached = this.megagroupOnlines[id] ?? (this.megagroupOnlines[id] = {timestamp: 0, onlines: 1});\r\n if((timestamp - cached.timestamp) < 60) {\r\n return cached.onlines;\r\n }\r\n\r\n const res = await apiManager.invokeApi('messages.getOnlines', {\r\n peer: this.getChannelInputPeer(id)\r\n });\r\n\r\n const onlines = res.onlines ?? 1;\r\n cached.timestamp = timestamp;\r\n cached.onlines = onlines;\r\n\r\n return onlines;\r\n } else if(this.isBroadcast(id)) {\r\n return 1;\r\n }\r\n\r\n const chatInfo = await appProfileManager.getChatFull(id);\r\n const _participants = (chatInfo as ChatFull.chatFull).participants as ChatParticipants.chatParticipants;\r\n if(_participants && _participants.participants) {\r\n const participants = _participants.participants;\r\n\r\n return participants.reduce((acc: number, participant) => {\r\n const user = appUsersManager.getUser(participant.user_id);\r\n if(user && user.status && user.status._ === 'userStatusOnline') {\r\n return acc + 1;\r\n }\r\n\r\n return acc;\r\n }, 0);\r\n } else {\r\n return 1;\r\n }\r\n }\r\n\r\n private onChatUpdated = (chatId: number, updates: any) => {\r\n //console.log('onChatUpdated', chatId, updates);\r\n\r\n apiUpdatesManager.processUpdateMessage(updates);\r\n if(updates &&\r\n /* updates.updates &&\r\n updates.updates.length && */\r\n this.isChannel(chatId)) {\r\n appProfileManager.invalidateChannelParticipants(chatId);\r\n }\r\n };\r\n\r\n public leaveChannel(id: number) {\r\n return apiManager.invokeApi('channels.leaveChannel', {\r\n channel: this.getChannelInput(id)\r\n }).then(this.onChatUpdated.bind(this, id));\r\n }\r\n\r\n public joinChannel(id: number) {\r\n return apiManager.invokeApi('channels.joinChannel', {\r\n channel: this.getChannelInput(id)\r\n }).then(this.onChatUpdated.bind(this, id));\r\n }\r\n\r\n public addChatUser(id: number, userId: number, fwdLimit = 100) {\r\n return apiManager.invokeApi('messages.addChatUser', {\r\n chat_id: id,\r\n user_id: appUsersManager.getUserInput(userId),\r\n fwd_limit: fwdLimit\r\n }).then(this.onChatUpdated.bind(this, id));\r\n }\r\n\r\n public deleteChatUser(id: number, userId: number) {\r\n return apiManager.invokeApi('messages.deleteChatUser', {\r\n chat_id: id,\r\n user_id: appUsersManager.getUserInput(userId)\r\n }).then(this.onChatUpdated.bind(this, id));\r\n }\r\n\r\n public leaveChat(id: number, flushHistory = true) {\r\n let promise: Promise<any> = this.deleteChatUser(id, appUsersManager.getSelf().id)\r\n if(flushHistory) promise = promise.then(() => {\r\n return appMessagesManager.flushHistory(-id);\r\n });\r\n return promise;;\r\n }\r\n\r\n public leave(id: number) {\r\n return this.isChannel(id) ? this.leaveChannel(id) : this.leaveChat(id);\r\n }\r\n\r\n public delete(id: number) {\r\n return this.isChannel(id) ? this.deleteChannel(id) : this.deleteChat(id);\r\n }\r\n\r\n public deleteChannel(id: number) {\r\n return apiManager.invokeApi('channels.deleteChannel', {\r\n channel: this.getChannelInput(id)\r\n }).then(this.onChatUpdated.bind(this, id));\r\n }\r\n\r\n public deleteChat(id: number) {\r\n //return this.leaveChat(id).then(() => {\r\n return apiManager.invokeApi('messages.deleteChat', {\r\n chat_id: id\r\n });\r\n //});\r\n }\r\n\r\n public migrateChat(id: number): Promise<number> {\r\n const chat: Chat = this.getChat(id);\r\n if(chat._ === 'channel') return Promise.resolve(chat.id);\r\n return apiManager.invokeApi('messages.migrateChat', {\r\n chat_id: id\r\n }).then((updates) => {\r\n this.onChatUpdated(id, updates);\r\n const update: Update.updateChannel = (updates as Updates.updates).updates.find(u => u._ === 'updateChannel') as any;\r\n return update.channel_id;\r\n });\r\n }\r\n\r\n public updateUsername(id: number, username: string) {\r\n return apiManager.invokeApi('channels.updateUsername', {\r\n channel: this.getChannelInput(id),\r\n username\r\n }).then((bool) => {\r\n if(bool) {\r\n const chat: Chat.channel = this.getChat(id);\r\n chat.username = username;\r\n }\r\n\r\n return bool;\r\n });\r\n }\r\n\r\n public editPhoto(id: number, inputFile: InputFile) {\r\n const inputChatPhoto: InputChatPhoto = {\r\n _: 'inputChatUploadedPhoto',\r\n file: inputFile\r\n };\r\n\r\n let promise: any;\r\n if(this.isChannel(id)) {\r\n promise = apiManager.invokeApi('channels.editPhoto', {\r\n channel: this.getChannelInput(id),\r\n photo: inputChatPhoto\r\n });\r\n } else {\r\n promise = apiManager.invokeApi('messages.editChatPhoto', {\r\n chat_id: id,\r\n photo: inputChatPhoto\r\n });\r\n }\r\n\r\n return promise.then((updates: any) => {\r\n apiUpdatesManager.processUpdateMessage(updates);\r\n });\r\n }\r\n\r\n public editTitle(id: number, title: string) {\r\n let promise: any;\r\n\r\n if(this.isChannel(id)) {\r\n promise = apiManager.invokeApi('channels.editTitle', {\r\n channel: this.getChannelInput(id),\r\n title\r\n });\r\n } else {\r\n promise = apiManager.invokeApi('messages.editChatTitle', {\r\n chat_id: id,\r\n title\r\n });\r\n }\r\n\r\n return promise.then((updates: any) => {\r\n apiUpdatesManager.processUpdateMessage(updates);\r\n });\r\n }\r\n\r\n public editAbout(id: number, about: string) {\r\n return apiManager.invokeApi('messages.editChatAbout', {\r\n peer: appPeersManager.getInputPeerById(-id),\r\n about\r\n }).then(bool => {\r\n //apiUpdatesManager.processUpdateMessage(updates);\r\n rootScope.broadcast('peer_bio_edit', -id);\r\n });\r\n }\r\n\r\n public editBanned(id: number, participant: number | ChannelParticipant, banned_rights: ChatBannedRights) {\r\n const userId = typeof(participant) === 'number' ? participant : participant.user_id;\r\n return apiManager.invokeApi('channels.editBanned', {\r\n channel: this.getChannelInput(id),\r\n user_id: appUsersManager.getUserInput(userId),\r\n banned_rights\r\n }).then((updates) => {\r\n this.onChatUpdated(id, updates);\r\n\r\n if(typeof(participant) !== 'number') {\r\n const timestamp = Date.now() / 1000 | 0;\r\n apiUpdatesManager.processUpdateMessage({\r\n _: 'updateShort',\r\n update: {\r\n _: 'updateChannelParticipant',\r\n channel_id: id,\r\n date: timestamp,\r\n //qts: 0,\r\n user_id: userId,\r\n prev_participant: participant,\r\n new_participant: Object.keys(banned_rights.pFlags).length ? {\r\n _: 'channelParticipantBanned',\r\n date: timestamp,\r\n banned_rights,\r\n kicked_by: appUsersManager.getSelf().id,\r\n user_id: userId,\r\n pFlags: {}\r\n } : undefined\r\n } as Update.updateChannelParticipant\r\n });\r\n }\r\n });\r\n }\r\n\r\n public clearChannelParticipantBannedRights(id: number, participant: number | ChannelParticipant) {\r\n return this.editBanned(id, participant, {\r\n _: 'chatBannedRights',\r\n until_date: 0,\r\n pFlags: {}\r\n });\r\n }\r\n \r\n public kickFromChannel(id: number, participant: number | ChannelParticipant) {\r\n return this.editBanned(id, participant, {\r\n _: 'chatBannedRights',\r\n until_date: 0,\r\n pFlags: {\r\n view_messages: true\r\n }\r\n });\r\n }\r\n}\r\n\r\nconst appChatsManager = new AppChatsManager();\r\nMOUNT_CLASS_TO.appChatsManager = appChatsManager;\r\nexport default appChatsManager;\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 I18n from \"../lib/langPack\";\r\n\r\nexport const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];\r\nexport const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];\r\n\r\nexport const ONE_DAY = 86400;\r\n\r\n// https://stackoverflow.com/a/6117889\r\nexport const getWeekNumber = (date: Date) => {\r\n const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));\r\n const dayNum = d.getUTCDay() || 7;\r\n d.setUTCDate(d.getUTCDate() + 4 - dayNum);\r\n const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));\r\n return Math.ceil((((d.getTime() - yearStart.getTime()) / ONE_DAY) + 1) / 7);\r\n};\r\n\r\nexport const formatDateAccordingToToday = (time: Date) => {\r\n const date = new Date();\r\n const now = date.getTime() / 1000 | 0;\r\n const timestamp = time.getTime() / 1000 | 0;\r\n\r\n let timeStr: string;\r\n if((now - timestamp) < ONE_DAY && date.getDate() === time.getDate()) { // if the same day\r\n timeStr = ('0' + time.getHours()).slice(-2) + ':' + ('0' + time.getMinutes()).slice(-2);\r\n } else if(date.getFullYear() !== time.getFullYear()) { // different year\r\n timeStr = time.getDate() + '.' + ('0' + (time.getMonth() + 1)).slice(-2) + '.' + ('' + time.getFullYear()).slice(-2);\r\n } else if((now - timestamp) < (ONE_DAY * 7) && getWeekNumber(date) === getWeekNumber(time)) { // current week\r\n timeStr = days[time.getDay()].slice(0, 3);\r\n } else { // same year\r\n timeStr = months[time.getMonth()].slice(0, 3) + ' ' + ('0' + time.getDate()).slice(-2);\r\n }\r\n\r\n return timeStr;\r\n};\r\n\r\nexport function formatDateAccordingToTodayNew(time: Date) {\r\n const today = new Date();\r\n const now = today.getTime() / 1000 | 0;\r\n const timestamp = time.getTime() / 1000 | 0;\r\n\r\n const options: Intl.DateTimeFormatOptions = {};\r\n if((now - timestamp) < ONE_DAY && today.getDate() === time.getDate()) { // if the same day\r\n options.hour = options.minute = '2-digit';\r\n } else if(today.getFullYear() !== time.getFullYear()) { // different year\r\n options.year = options.day = 'numeric';\r\n options.month = '2-digit';\r\n } else if((now - timestamp) < (ONE_DAY * 7) && getWeekNumber(today) === getWeekNumber(time)) { // current week\r\n options.weekday = 'short';\r\n } else { // same year\r\n options.month = 'short';\r\n options.day = 'numeric';\r\n }\r\n\r\n return new I18n.IntlDateElement({\r\n date: time,\r\n options\r\n }).element;\r\n}\r\n\r\nMOUNT_CLASS_TO && (MOUNT_CLASS_TO.formatDateAccordingToTodayNew = formatDateAccordingToTodayNew);\r\n\r\nexport const getFullDate = (date: Date, options: Partial<{\r\n noTime: true, \r\n noSeconds: true,\r\n monthAsNumber: true,\r\n leadingZero: true\r\n}> = {}) => {\r\n const joiner = options.monthAsNumber ? '.' : ' ';\r\n const time = ('0' + date.getHours()).slice(-2) + ':' + ('0' + date.getMinutes()).slice(-2) + (options.noSeconds ? '' : ':' + ('0' + date.getSeconds()).slice(-2));\r\n\r\n return (options.leadingZero ? ('0' + date.getDate()).slice(-2) : date.getDate()) + \r\n joiner + (options.monthAsNumber ? ('0' + (date.getMonth() + 1)).slice(-2) : months[date.getMonth()]) + \r\n joiner + date.getFullYear() + \r\n (options.noTime ? '' : ', ' + time);\r\n};\r\n\r\nexport function tsNow(seconds?: true) {\r\n const t = Date.now();\r\n return seconds ? Math.floor(t / 1000) : t;\r\n}\r\n\r\n// https://github.com/DrKLO/Telegram/blob/d52b2c921abd3c1e8d6368858313ad0cb0468c07/TMessagesProj/src/main/java/org/telegram/ui/Adapters/FiltersView.java\r\nconst minYear = 2013;\r\nconst yearPattern = new RegExp(\"20[0-9]{1,2}\");\r\nconst monthYearOrDayPattern = new RegExp(\"(\\\\w{3,}) ([0-9]{0,4})\", 'i');\r\nconst yearOrDayAndMonthPattern = new RegExp(\"([0-9]{0,4}) (\\\\w{2,})\", 'i');\r\nconst shortDate = new RegExp(\"^([0-9]{1,4})(\\\\.| |/|\\\\-)([0-9]{1,4})$\", 'i');\r\nconst longDate = new RegExp(\"^([0-9]{1,2})(\\\\.| |/|\\\\-)([0-9]{1,2})(\\\\.| |/|\\\\-)([0-9]{1,4})$\", 'i');\r\nconst numberOfDaysEachMonth = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];\r\nexport type DateData = {\r\n title: string,\r\n minDate: number,\r\n maxDate: number,\r\n};\r\nexport function fillTipDates(query: string, dates: DateData[]) {\r\n const q = query.trim().toLowerCase();\r\n\r\n if(q.length < 3) {\r\n return;\r\n }\r\n\r\n if(\"today\".indexOf(q) === 0) {\r\n const date = new Date();\r\n const year = date.getFullYear();\r\n const month = date.getMonth();\r\n const day = date.getDate();\r\n date.setFullYear(year, month, day);\r\n date.setHours(0, 0, 0);\r\n\r\n const minDate = date.getTime();\r\n date.setFullYear(year, month, day + 1);\r\n date.setHours(0, 0, 0);\r\n\r\n const maxDate = date.getTime() - 1;\r\n dates.push({\r\n title: 'Today',\r\n minDate,\r\n maxDate\r\n });\r\n return;\r\n }\r\n\r\n if(\"yesterday\".indexOf(q) === 0) {\r\n const date = new Date();\r\n const year = date.getFullYear();\r\n const month = date.getMonth();\r\n const day = date.getDate();\r\n date.setFullYear(year, month, day);\r\n date.setHours(0, 0, 0);\r\n\r\n const minDate = date.getTime() - 86400000;\r\n date.setFullYear(year, month, day + 1);\r\n date.setHours(0, 0, 0);\r\n\r\n const maxDate = date.getTime() - 86400001;\r\n dates.push({\r\n title: 'Yesterday',\r\n minDate,\r\n maxDate\r\n });\r\n return;\r\n }\r\n\r\n const dayOfWeek = getDayOfWeek(q);\r\n if(dayOfWeek >= 0) {\r\n const date = new Date();\r\n const now = date.getTime();\r\n const currentDay = date.getDay();\r\n const distance = dayOfWeek - currentDay;\r\n date.setDate(date.getDate() + distance);\r\n if(date.getTime() > now) {\r\n date.setTime(date.getTime() - 604800000);\r\n }\r\n const year = date.getFullYear()\r\n const month = date.getMonth();\r\n const day = date.getDate();\r\n date.setFullYear(year, month, day);\r\n date.setHours(0, 0, 0);\r\n\r\n const minDate = date.getTime();\r\n date.setFullYear(year, month, day + 1);\r\n date.setHours(0, 0, 0);\r\n\r\n const maxDate = date.getTime() - 1;\r\n dates.push({\r\n title: formatWeekLong(minDate),\r\n minDate,\r\n maxDate\r\n });\r\n return;\r\n }\r\n\r\n let matches: any[];\r\n if((matches = shortDate.exec(q)) !== null) {\r\n const g1 = matches[1];\r\n const g2 = matches[3];\r\n const k = parseInt(g1);\r\n const k1 = parseInt(g2);\r\n if(k > 0 && k <= 31) {\r\n if(k1 >= minYear && k <= 12) {\r\n const selectedYear = k1;\r\n const month = k - 1;\r\n createForMonthYear(dates, month, selectedYear);\r\n return;\r\n } else if (k1 <= 12) {\r\n const day = k - 1;\r\n const month = k1 - 1;\r\n createForDayMonth(dates, day, month);\r\n }\r\n } else if (k >= minYear && k1 <= 12) {\r\n const selectedYear = k;\r\n const month = k1 - 1;\r\n createForMonthYear(dates, month, selectedYear);\r\n }\r\n\r\n return;\r\n }\r\n\r\n if((matches = longDate.exec(q)) !== null) {\r\n const g1 = matches[1];\r\n const g2 = matches[3];\r\n const g3 = matches[5];\r\n if(!matches[2] === matches[4]) {\r\n return;\r\n }\r\n\r\n const day = parseInt(g1);\r\n const month = parseInt(g2) - 1;\r\n let year = parseInt(g3);\r\n if(year >= 10 && year <= 99) {\r\n year += 2000;\r\n }\r\n\r\n const currentYear = new Date().getFullYear();\r\n if(validDateForMonth(day - 1, month) && year >= minYear && year <= currentYear) {\r\n const date = new Date();\r\n date.setFullYear(year, month, day);\r\n date.setHours(0, 0, 0);\r\n \r\n const minDate = date.getTime();\r\n date.setFullYear(year, month, day + 1);\r\n date.setHours(0, 0, 0);\r\n\r\n const maxDate = date.getTime() - 1;\r\n dates.push({\r\n title: formatterYearMax(minDate),\r\n minDate,\r\n maxDate\r\n });\r\n return;\r\n }\r\n\r\n return;\r\n }\r\n\r\n if((matches = yearPattern.exec(q)) !== null) {\r\n let selectedYear = +q;\r\n const currentYear = new Date().getFullYear();\r\n if(selectedYear < minYear) {\r\n selectedYear = minYear;\r\n for(let i = currentYear; i >= selectedYear; i--) {\r\n const date = new Date();\r\n date.setFullYear(i, 0, 1);\r\n date.setHours(0, 0, 0);\r\n\r\n const minDate = date.getTime();\r\n date.setFullYear(i + 1, 0, 1);\r\n date.setHours(0, 0, 0);\r\n\r\n const maxDate = date.getTime() - 1;\r\n dates.push({\r\n title: '' + i,\r\n minDate,\r\n maxDate\r\n });\r\n }\r\n } else if(selectedYear <= currentYear) {\r\n const date = new Date();\r\n date.setFullYear(selectedYear, 0, 1);\r\n date.setHours(0, 0, 0);\r\n\r\n const minDate = date.getTime();\r\n date.setFullYear(selectedYear + 1, 0, 1);\r\n date.setHours(0, 0, 0);\r\n\r\n const maxDate = date.getTime() - 1;\r\n dates.push({\r\n title: '' + selectedYear,\r\n minDate,\r\n maxDate\r\n });\r\n }\r\n\r\n return;\r\n }\r\n\r\n if((matches = monthYearOrDayPattern.exec(q)) !== null) {\r\n const g1 = matches[1];\r\n const g2 = matches[2];\r\n const month = getMonth(g1);\r\n if(month >= 0) {\r\n const k = +g2;\r\n if(k > 0 && k <= 31) {\r\n const day = k - 1;\r\n createForDayMonth(dates, day, month);\r\n return;\r\n } else if(k >= minYear) {\r\n const selectedYear = k;\r\n createForMonthYear(dates, month, selectedYear);\r\n return;\r\n }\r\n }\r\n }\r\n\r\n if((matches = yearOrDayAndMonthPattern.exec(q)) !== null) {\r\n const g1 = matches[1];\r\n const g2 = matches[2];\r\n const month = getMonth(g2);\r\n if(month >= 0) {\r\n const k = +g1;\r\n if(k > 0 && k <= 31) {\r\n const day = k - 1;\r\n createForDayMonth(dates, day, month);\r\n return;\r\n } else if (k >= minYear) {\r\n const selectedYear = k;\r\n createForMonthYear(dates, month, selectedYear);\r\n }\r\n }\r\n }\r\n}\r\n\r\nfunction createForMonthYear(dates: DateData[], month: number, selectedYear: number) {\r\n const currentYear = new Date().getFullYear();\r\n const today = Date.now();\r\n if(selectedYear >= minYear && selectedYear <= currentYear) {\r\n const date = new Date();\r\n date.setFullYear(selectedYear, month, 1);\r\n date.setHours(0, 0, 0);\r\n const minDate = date.getTime();\r\n if(minDate > today) {\r\n return;\r\n }\r\n date.setMonth(date.getMonth() + 1);\r\n const maxDate = date.getTime() - 1;\r\n\r\n dates.push({\r\n title: formatterMonthYear(minDate),\r\n minDate,\r\n maxDate\r\n });\r\n }\r\n}\r\n\r\nfunction createForDayMonth(dates: DateData[], day: number, month: number) {\r\n if(validDateForMonth(day, month)) {\r\n const currentYear = new Date().getFullYear();\r\n const today = Date.now();\r\n \r\n for(let i = currentYear; i >= minYear; i--) {\r\n if(month === 1 && day === 28 && !isLeapYear(i)) {\r\n continue;\r\n }\r\n\r\n const date = new Date();\r\n date.setFullYear(i, month, day + 1);\r\n date.setHours(0, 0, 0);\r\n \r\n const minDate = date.getTime();\r\n if(minDate > today) {\r\n continue;\r\n }\r\n\r\n date.setFullYear(i, month, day + 2);\r\n date.setHours(0, 0, 0);\r\n const maxDate = date.getTime() - 1;\r\n if(i === currentYear) {\r\n dates.push({\r\n title: formatterDayMonth(minDate),\r\n minDate,\r\n maxDate\r\n });\r\n } else {\r\n dates.push({\r\n title: formatterYearMax(minDate),\r\n minDate,\r\n maxDate\r\n });\r\n }\r\n }\r\n }\r\n}\r\n\r\nfunction formatterMonthYear(timestamp: number) {\r\n const date = new Date(timestamp);\r\n return months[date.getMonth()].slice(0, 3) + ' ' + date.getFullYear();\r\n}\r\n\r\nfunction formatterDayMonth(timestamp: number) {\r\n const date = new Date(timestamp);\r\n return months[date.getMonth()].slice(0, 3) + ' ' + date.getDate();\r\n}\r\n\r\nfunction formatterYearMax(timestamp: number) {\r\n const date = new Date(timestamp);\r\n return ('0' + date.getDate()).slice(-2) + '.' + ('0' + (date.getMonth() + 1)).slice(-2) + '.' + date.getFullYear();\r\n}\r\n\r\nfunction formatWeekLong(timestamp: number) {\r\n const date = new Date(timestamp);\r\n return days[date.getDay()];\r\n}\r\n\r\nfunction validDateForMonth(day: number, month: number) {\r\n if(month >= 0 && month < 12) {\r\n if(day >= 0 && day < numberOfDaysEachMonth[month]) {\r\n return true;\r\n }\r\n }\r\n return false;\r\n}\r\n\r\nfunction isLeapYear(year: number) {\r\n return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);\r\n}\r\n\r\nfunction getMonth(q: string) {\r\n /* String[] months = new String[]{\r\n LocaleController.getString(\"January\", R.string.January).toLowerCase(),\r\n LocaleController.getString(\"February\", R.string.February).toLowerCase(),\r\n LocaleController.getString(\"March\", R.string.March).toLowerCase(),\r\n LocaleController.getString(\"April\", R.string.April).toLowerCase(),\r\n LocaleController.getString(\"May\", R.string.May).toLowerCase(),\r\n LocaleController.getString(\"June\", R.string.June).toLowerCase(),\r\n LocaleController.getString(\"July\", R.string.July).toLowerCase(),\r\n LocaleController.getString(\"August\", R.string.August).toLowerCase(),\r\n LocaleController.getString(\"September\", R.string.September).toLowerCase(),\r\n LocaleController.getString(\"October\", R.string.October).toLowerCase(),\r\n LocaleController.getString(\"November\", R.string.November).toLowerCase(),\r\n LocaleController.getString(\"December\", R.string.December).toLowerCase()\r\n }; */\r\n\r\n /* String[] monthsEng = new String[12];\r\n Calendar c = Calendar.getInstance();\r\n for (int i = 1; i <= 12; i++) {\r\n c.set(0, 0, 0, 0, 0, 0);\r\n c.set(Calendar.MONTH, i);\r\n monthsEng[i - 1] = c.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.ENGLISH).toLowerCase();\r\n } */\r\n\r\n q = q.toLowerCase();\r\n for(let i = 0; i < 12; i++) {\r\n const month = months[i].toLowerCase();\r\n if(month.indexOf(q) === 0) {\r\n return i;\r\n }\r\n }\r\n return -1;\r\n}\r\n\r\nfunction getDayOfWeek(q: string) {\r\n const c = new Date();\r\n if(q.length <= 3) {\r\n return -1;\r\n }\r\n \r\n for(let i = 0; i < 7; i++) {\r\n c.setDate(c.getDate() + 1);\r\n \r\n if(formatWeekLong(c.getTime()).toLowerCase().indexOf(q) === 0) {\r\n return c.getDay();\r\n }\r\n }\r\n return -1;\r\n}\r\n\r\nMOUNT_CLASS_TO.fillTipDates = fillTipDates;\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 { MOUNT_CLASS_TO } from \"../../config/debug\";\r\nimport { tsNow } from \"../../helpers/date\";\r\nimport { replaceContent } from \"../../helpers/dom\";\r\nimport renderImageFromUrl from \"../../helpers/dom/renderImageFromUrl\";\r\nimport sequentialDom from \"../../helpers/sequentialDom\";\r\nimport { ChannelParticipantsFilter, ChannelsChannelParticipants, ChatFull, ChatParticipants, ChatPhoto, ExportedChatInvite, InputChannel, InputFile, InputFileLocation, PhotoSize, UserFull, UserProfilePhoto } from \"../../layer\";\r\n//import apiManager from '../mtproto/apiManager';\r\nimport apiManager from '../mtproto/mtprotoworker';\r\nimport { RichTextProcessor } from \"../richtextprocessor\";\r\nimport rootScope from \"../rootScope\";\r\nimport apiUpdatesManager from \"./apiUpdatesManager\";\r\nimport appChatsManager from \"./appChatsManager\";\r\nimport appDownloadManager from \"./appDownloadManager\";\r\nimport appNotificationsManager from \"./appNotificationsManager\";\r\nimport appPeersManager from \"./appPeersManager\";\r\nimport appPhotosManager, { MyPhoto } from \"./appPhotosManager\";\r\nimport appUsersManager, { User } from \"./appUsersManager\";\r\n\r\ntype PeerPhotoSize = 'photo_small' | 'photo_big';\r\n\r\nexport class AppProfileManager {\r\n private botInfos: any = {};\r\n private usersFull: {[id: string]: UserFull.userFull} = {};\r\n public chatsFull: {[id: string]: ChatFull} = {};\r\n private fullPromises: {[peerId: string]: Promise<ChatFull.chatFull | ChatFull.channelFull | UserFull>} = {};\r\n\r\n private savedAvatarURLs: {\r\n [peerId: number]: {\r\n [size in PeerPhotoSize]?: string | Promise<string>\r\n }\r\n } = {};\r\n\r\n constructor() {\r\n rootScope.addMultipleEventsListeners({\r\n updateChatParticipants: (update) => {\r\n const participants = update.participants;\r\n if(participants._ === 'chatParticipants') {\r\n const chatId = participants.chat_id;\r\n const chatFull = this.chatsFull[chatId] as ChatFull.chatFull;\r\n if(chatFull !== undefined) {\r\n chatFull.participants = participants;\r\n rootScope.broadcast('chat_full_update', chatId);\r\n }\r\n }\r\n },\r\n\r\n updateChatParticipantAdd: (update) => {\r\n const chatFull = this.chatsFull[update.chat_id] as ChatFull.chatFull;\r\n if(chatFull !== undefined) {\r\n const _participants = chatFull.participants as ChatParticipants.chatParticipants;\r\n const participants = _participants.participants || [];\r\n for(let i = 0, length = participants.length; i < length; i++) {\r\n if(participants[i].user_id === update.user_id) {\r\n return;\r\n }\r\n }\r\n\r\n participants.push({\r\n _: 'chatParticipant',\r\n user_id: update.user_id,\r\n inviter_id: update.inviter_id,\r\n date: tsNow(true)\r\n });\r\n\r\n _participants.version = update.version;\r\n rootScope.broadcast('chat_full_update', update.chat_id);\r\n }\r\n },\r\n\r\n updateChatParticipantDelete: (update) => {\r\n const chatFull = this.chatsFull[update.chat_id] as ChatFull.chatFull;\r\n if(chatFull !== undefined) {\r\n const _participants = chatFull.participants as ChatParticipants.chatParticipants;\r\n const participants = _participants.participants || [];\r\n for(let i = 0, length = participants.length; i < length; i++) {\r\n if(participants[i].user_id === update.user_id) {\r\n participants.splice(i, 1);\r\n _participants.version = update.version;\r\n rootScope.broadcast('chat_full_update', update.chat_id);\r\n return;\r\n }\r\n }\r\n }\r\n }\r\n });\r\n\r\n rootScope.on('chat_update', (chatId) => {\r\n const fullChat = this.chatsFull[chatId];\r\n const chat = appChatsManager.getChat(chatId);\r\n if(!chat.photo || !fullChat) {\r\n return;\r\n }\r\n const emptyPhoto = chat.photo._ === 'chatPhotoEmpty';\r\n //////console.log('chat_update:', fullChat);\r\n if(fullChat.chat_photo && emptyPhoto !== (fullChat.chat_photo._ === 'photoEmpty')) {\r\n delete this.chatsFull[chatId];\r\n rootScope.broadcast('chat_full_update', chatId);\r\n return;\r\n }\r\n if(emptyPhoto) {\r\n return;\r\n }\r\n\r\n const smallUserpic = chat.photo.photo_small;\r\n const smallPhotoSize = fullChat.chat_photo ? appPhotosManager.choosePhotoSize(fullChat.chat_photo as MyPhoto, 0, 0) : undefined;\r\n if(!smallPhotoSize || JSON.stringify(smallUserpic) !== JSON.stringify((smallPhotoSize as PhotoSize.photoSize).location)) {\r\n delete this.chatsFull[chatId];\r\n rootScope.broadcast('chat_full_update', chatId);\r\n }\r\n });\r\n }\r\n\r\n public saveBotInfo(botInfo: any) {\r\n const botId = botInfo && botInfo.user_id;\r\n if(!botId) {\r\n return null;\r\n }\r\n\r\n const commands: any = {};\r\n botInfo.commands.forEach((botCommand: any) => {\r\n commands[botCommand.command] = botCommand.description;\r\n });\r\n\r\n return this.botInfos[botId] = {\r\n id: botId,\r\n version: botInfo.version,\r\n shareText: botInfo.share_text,\r\n description: botInfo.description,\r\n commands: commands\r\n };\r\n }\r\n\r\n public getProfile(id: number, override?: true): Promise<UserFull> {\r\n if(this.usersFull[id] && !override) {\r\n return Promise.resolve(this.usersFull[id]);\r\n }\r\n\r\n if(this.fullPromises[id]) {\r\n return this.fullPromises[id] as any;\r\n }\r\n\r\n return this.fullPromises[id] = apiManager.invokeApi('users.getFullUser', {\r\n id: appUsersManager.getUserInput(id)\r\n }).then((userFull) => {\r\n const user = userFull.user as User;\r\n appUsersManager.saveApiUser(user, true);\r\n\r\n if(userFull.profile_photo) {\r\n userFull.profile_photo = appPhotosManager.savePhoto(userFull.profile_photo, {type: 'profilePhoto', peerId: id});\r\n }\r\n\r\n if(userFull.about !== undefined) {\r\n userFull.rAbout = RichTextProcessor.wrapRichText(userFull.about, {noLinebreaks: true});\r\n }\r\n\r\n appNotificationsManager.savePeerSettings(id, userFull.notify_settings);\r\n\r\n if(userFull.bot_info) {\r\n userFull.bot_info = this.saveBotInfo(userFull.bot_info) as any;\r\n }\r\n\r\n //appMessagesManager.savePinnedMessage(id, userFull.pinned_msg_id);\r\n\r\n delete this.fullPromises[id];\r\n\r\n return this.usersFull[id] = userFull;\r\n }) as any;\r\n }\r\n\r\n public getProfileByPeerId(peerId: number, override?: true): Promise<ChatFull.chatFull | ChatFull.channelFull | UserFull.userFull> {\r\n if(peerId < 0) return this.getChatFull(-peerId, override);\r\n else return this.getProfile(peerId, override);\r\n }\r\n\r\n public getFullPhoto(peerId: number) {\r\n return this.getProfileByPeerId(peerId).then(profile => {\r\n switch(profile._) {\r\n case 'userFull':\r\n return profile.profile_photo;\r\n case 'channelFull':\r\n case 'chatFull':\r\n return profile.chat_photo;\r\n }\r\n });\r\n }\r\n\r\n /* public getPeerBots(peerId: number) {\r\n var peerBots: any[] = [];\r\n if(peerId >= 0 && !appUsersManager.isBot(peerId) ||\r\n (appPeersManager.isChannel(peerId) && !appPeersManager.isMegagroup(peerId))) {\r\n return Promise.resolve(peerBots);\r\n }\r\n if(peerId >= 0) {\r\n return this.getProfile(peerId).then((userFull: any) => {\r\n var botInfo = userFull.bot_info;\r\n if(botInfo && botInfo._ !== 'botInfoEmpty') {\r\n peerBots.push(botInfo);\r\n }\r\n return peerBots;\r\n });\r\n }\r\n\r\n return this.getChatFull(-peerId).then((chatFull: any) => {\r\n chatFull.bot_info.forEach((botInfo: any) => {\r\n peerBots.push(this.saveBotInfo(botInfo))\r\n });\r\n return peerBots;\r\n });\r\n } */\r\n\r\n public getChatFull(id: number, override?: true): Promise<ChatFull.chatFull | ChatFull.channelFull> {\r\n if(appChatsManager.isChannel(id)) {\r\n return this.getChannelFull(id, override);\r\n }\r\n\r\n const fullChat = this.chatsFull[id] as ChatFull.chatFull;\r\n if(fullChat && !override) {\r\n const chat = appChatsManager.getChat(id);\r\n if(chat.version === (fullChat.participants as ChatParticipants.chatParticipants).version ||\r\n chat.pFlags.left) {\r\n return Promise.resolve(fullChat);\r\n }\r\n }\r\n\r\n const peerId = -id;\r\n if(this.fullPromises[peerId] !== undefined) {\r\n return this.fullPromises[peerId] as any;\r\n }\r\n\r\n // console.trace(dT(), 'Get chat full', id, appChatsManager.getChat(id))\r\n return this.fullPromises[peerId] = apiManager.invokeApi('messages.getFullChat', {\r\n chat_id: id\r\n }).then((result) => {\r\n appChatsManager.saveApiChats(result.chats, true);\r\n appUsersManager.saveApiUsers(result.users);\r\n const fullChat = result.full_chat as ChatFull.chatFull;\r\n if(fullChat && fullChat.chat_photo && fullChat.chat_photo.id) {\r\n fullChat.chat_photo = appPhotosManager.savePhoto(fullChat.chat_photo, {type: 'profilePhoto', peerId: peerId});\r\n }\r\n\r\n //appMessagesManager.savePinnedMessage(peerId, fullChat.pinned_msg_id);\r\n appNotificationsManager.savePeerSettings(peerId, fullChat.notify_settings);\r\n delete this.fullPromises[peerId];\r\n this.chatsFull[id] = fullChat;\r\n rootScope.broadcast('chat_full_update', id);\r\n\r\n return fullChat;\r\n }) as any;\r\n }\r\n\r\n public getChatInviteLink(id: number, force?: boolean) {\r\n return this.getChatFull(id).then((chatFull) => {\r\n if(!force &&\r\n chatFull.exported_invite &&\r\n chatFull.exported_invite._ == 'chatInviteExported') {\r\n return chatFull.exported_invite.link;\r\n }\r\n \r\n return apiManager.invokeApi('messages.exportChatInvite', {\r\n peer: appPeersManager.getInputPeerById(-id)\r\n }).then((exportedInvite) => {\r\n if(this.chatsFull[id] !== undefined) {\r\n this.chatsFull[id].exported_invite = exportedInvite;\r\n }\r\n\r\n return (exportedInvite as ExportedChatInvite.chatInviteExported).link;\r\n });\r\n });\r\n }\r\n\r\n public getChannelParticipants(id: number, filter: ChannelParticipantsFilter = {_: 'channelParticipantsRecent'}, limit = 200, offset = 0) {\r\n if(filter._ === 'channelParticipantsRecent') {\r\n const chat = appChatsManager.getChat(id);\r\n if(chat &&\r\n chat.pFlags && (\r\n chat.pFlags.kicked ||\r\n chat.pFlags.broadcast && !chat.pFlags.creator && !chat.admin_rights\r\n )) {\r\n return Promise.reject();\r\n }\r\n }\r\n\r\n return apiManager.invokeApiCacheable('channels.getParticipants', {\r\n channel: appChatsManager.getChannelInput(id),\r\n filter,\r\n offset,\r\n limit,\r\n hash: 0\r\n }, {cacheSeconds: 60}).then(result => {\r\n appUsersManager.saveApiUsers((result as ChannelsChannelParticipants.channelsChannelParticipants).users);\r\n return result as ChannelsChannelParticipants.channelsChannelParticipants;\r\n });\r\n /* let maybeAddSelf = (participants: any[]) => {\r\n let chat = appChatsManager.getChat(id);\r\n let selfMustBeFirst = filter._ === 'channelParticipantsRecent' &&\r\n !offset &&\r\n !chat.pFlags.kicked &&\r\n !chat.pFlags.left;\r\n\r\n if(selfMustBeFirst) {\r\n participants = copy(participants);\r\n let myID = appUsersManager.getSelf().id;\r\n let myIndex = participants.findIndex(p => p.user_id === myID);\r\n let myParticipant;\r\n\r\n if(myIndex !== -1) {\r\n myParticipant = participants[myIndex];\r\n participants.splice(myIndex, 1);\r\n } else {\r\n myParticipant = {_: 'channelParticipantSelf', user_id: myID};\r\n }\r\n\r\n participants.unshift(myParticipant);\r\n }\r\n\r\n return participants;\r\n } */\r\n }\r\n\r\n public getChannelParticipant(id: number, userId: number) {\r\n return apiManager.invokeApiSingle('channels.getParticipant', {\r\n channel: appChatsManager.getChannelInput(id),\r\n user_id: appUsersManager.getUserInput(userId)\r\n }).then(channelParticipant => {\r\n appUsersManager.saveApiUsers(channelParticipant.users);\r\n return channelParticipant.participant;\r\n });\r\n }\r\n\r\n public getChannelFull(id: number, override?: true): Promise<ChatFull.channelFull> {\r\n if(this.chatsFull[id] !== undefined && !override) {\r\n return Promise.resolve(this.chatsFull[id] as ChatFull.channelFull);\r\n }\r\n\r\n const peerId = -id;\r\n if(this.fullPromises[peerId] !== undefined) {\r\n return this.fullPromises[peerId] as any;\r\n }\r\n\r\n return this.fullPromises[peerId] = apiManager.invokeApi('channels.getFullChannel', {\r\n channel: appChatsManager.getChannelInput(id)\r\n }).then((result) => {\r\n appChatsManager.saveApiChats(result.chats, true);\r\n appUsersManager.saveApiUsers(result.users);\r\n const fullChannel = result.full_chat as ChatFull.channelFull;\r\n if(fullChannel && fullChannel.chat_photo.id) {\r\n fullChannel.chat_photo = appPhotosManager.savePhoto(fullChannel.chat_photo, {type: 'profilePhoto', peerId});\r\n //appPhotosManager.savePhoto(fullChannel.chat_photo);\r\n }\r\n appNotificationsManager.savePeerSettings(peerId, fullChannel.notify_settings);\r\n\r\n delete this.fullPromises[peerId];\r\n this.chatsFull[id] = fullChannel;\r\n rootScope.broadcast('chat_full_update', id);\r\n\r\n return fullChannel;\r\n }, (error) => {\r\n switch (error.type) {\r\n case 'CHANNEL_PRIVATE':\r\n let channel = appChatsManager.getChat(id);\r\n channel = {_: 'channelForbidden', access_hash: channel.access_hash, title: channel.title};\r\n apiUpdatesManager.processUpdateMessage({\r\n _: 'updates',\r\n updates: [{\r\n _: 'updateChannel',\r\n channel_id: id\r\n }],\r\n chats: [channel],\r\n users: []\r\n });\r\n break;\r\n }\r\n\r\n return Promise.reject(error);\r\n }) as any;\r\n }\r\n\r\n public invalidateChannelParticipants(id: number) {\r\n delete this.chatsFull[id];\r\n delete this.fullPromises[-id];\r\n apiManager.clearCache('channels.getParticipants', (params) => (params.channel as InputChannel.inputChannel).channel_id === id);\r\n rootScope.broadcast('chat_full_update', id);\r\n }\r\n\r\n public updateProfile(first_name: string, last_name: string, about: string) {\r\n return apiManager.invokeApi('account.updateProfile', {\r\n first_name,\r\n last_name,\r\n about\r\n }).then(user => {\r\n appUsersManager.saveApiUser(user);\r\n \r\n return this.getProfile(rootScope.myId, true);\r\n });\r\n }\r\n\r\n public uploadProfilePhoto(inputFile: InputFile) {\r\n return apiManager.invokeApi('photos.uploadProfilePhoto', {\r\n file: inputFile\r\n }).then((updateResult) => {\r\n appUsersManager.saveApiUsers(updateResult.users);\r\n\r\n const myId = rootScope.myId;\r\n appPhotosManager.savePhoto(updateResult.photo, {\r\n type: 'profilePhoto',\r\n peerId: myId\r\n });\r\n\r\n apiUpdatesManager.processUpdateMessage({\r\n _: 'updateShort',\r\n update: {\r\n _: 'updateUserPhoto',\r\n user_id: myId,\r\n date: tsNow(true),\r\n photo: appUsersManager.getUser(myId).photo,\r\n previous: true\r\n }\r\n });\r\n });\r\n }\r\n\r\n public removeFromAvatarsCache(peerId: number) {\r\n if(this.savedAvatarURLs[peerId]) {\r\n delete this.savedAvatarURLs[peerId];\r\n }\r\n }\r\n\r\n public loadAvatar(peerId: number, photo: UserProfilePhoto.userProfilePhoto | ChatPhoto.chatPhoto, size: PeerPhotoSize) {\r\n const inputPeer = appPeersManager.getInputPeerById(peerId);\r\n\r\n let cached = false;\r\n let getAvatarPromise: Promise<string>;\r\n let saved = this.savedAvatarURLs[peerId];\r\n if(!saved || !saved[size]) {\r\n if(!saved) {\r\n saved = this.savedAvatarURLs[peerId] = {};\r\n }\r\n\r\n //console.warn('will invoke downloadSmallFile:', peerId);\r\n const peerPhotoFileLocation: InputFileLocation.inputPeerPhotoFileLocation = {\r\n _: 'inputPeerPhotoFileLocation', \r\n pFlags: {},\r\n peer: inputPeer, \r\n volume_id: photo[size].volume_id, \r\n local_id: photo[size].local_id\r\n };\r\n\r\n if(size === 'photo_big') {\r\n peerPhotoFileLocation.pFlags.big = true;\r\n }\r\n\r\n const downloadOptions = {dcId: photo.dc_id, location: peerPhotoFileLocation};\r\n\r\n /* let str: string;\r\n const time = Date.now();\r\n if(peerId === 0) {\r\n str = `download avatar ${peerId}`;\r\n } */\r\n\r\n const promise = appDownloadManager.download(downloadOptions);\r\n getAvatarPromise = saved[size] = promise.then(blob => {\r\n return saved[size] = URL.createObjectURL(blob);\r\n\r\n /* if(str) {\r\n console.log(str, Date.now() / 1000, Date.now() - time);\r\n } */\r\n });\r\n } else if(typeof(saved[size]) !== 'string') {\r\n getAvatarPromise = saved[size] as Promise<any>;\r\n } else {\r\n getAvatarPromise = Promise.resolve(saved[size]);\r\n cached = true;\r\n }\r\n\r\n return {cached, loadPromise: getAvatarPromise};\r\n }\r\n\r\n public putAvatar(div: HTMLElement, peerId: number, photo: UserProfilePhoto.userProfilePhoto | ChatPhoto.chatPhoto, size: PeerPhotoSize, img = new Image()) {\r\n const {cached, loadPromise} = this.loadAvatar(peerId, photo, size);\r\n\r\n let callback: () => void;\r\n if(cached) {\r\n // смотри в misc.ts: renderImageFromUrl\r\n callback = () => {\r\n replaceContent(div, img);\r\n div.dataset.color = '';\r\n };\r\n } else {\r\n const animate = rootScope.settings.animationsEnabled;\r\n if(animate) {\r\n img.classList.add('fade-in');\r\n }\r\n\r\n callback = () => {\r\n replaceContent(div, img);\r\n\r\n setTimeout(() => {\r\n if(div.childElementCount) {\r\n div.dataset.color = '';\r\n\r\n if(animate) {\r\n sequentialDom.mutateElement(img, () => {\r\n img.classList.remove('fade-in');\r\n });\r\n }\r\n }\r\n }, animate ? 200 : 0);\r\n };\r\n }\r\n\r\n const renderPromise = loadPromise.then((url) => {\r\n return new Promise<void>((resolve) => {\r\n renderImageFromUrl(img, url, () => {\r\n callback();\r\n resolve();\r\n }/* , false */);\r\n });\r\n });\r\n\r\n return {cached, loadPromise: renderPromise};\r\n }\r\n\r\n // peerId === peerId || title\r\n public putPhoto(div: HTMLElement, peerId: number, isDialog = false, title = '') {\r\n const photo = appPeersManager.getPeerPhoto(peerId);\r\n\r\n const size: PeerPhotoSize = 'photo_small';\r\n const avatarAvailable = photo && photo[size];\r\n const avatarRendered = !!div.firstElementChild;\r\n \r\n const myId = rootScope.myId;\r\n\r\n //console.log('loadDialogPhoto location:', location, inputPeer);\r\n if(peerId === myId && isDialog) {\r\n div.innerText = '';\r\n div.dataset.color = '';\r\n div.classList.add('tgico-saved');\r\n div.classList.remove('tgico-deletedaccount');\r\n return;\r\n }\r\n\r\n if(peerId > 0) {\r\n const user = appUsersManager.getUser(peerId);\r\n if(user && user.pFlags && user.pFlags.deleted) {\r\n div.innerText = '';\r\n div.dataset.color = appPeersManager.getPeerColorById(peerId);\r\n div.classList.add('tgico-deletedaccount');\r\n div.classList.remove('tgico-saved');\r\n return;\r\n }\r\n }\r\n\r\n if(!avatarAvailable || !avatarRendered || !this.savedAvatarURLs[peerId]) {\r\n let color = '';\r\n if(peerId && (peerId !== myId || !isDialog)) {\r\n color = appPeersManager.getPeerColorById(peerId);\r\n }\r\n \r\n div.innerText = '';\r\n div.classList.remove('tgico-saved', 'tgico-deletedaccount');\r\n div.dataset.color = color;\r\n\r\n let abbr: string;\r\n if(!title) {\r\n abbr = appPeersManager.getPeer(peerId).initials ?? '';\r\n } else {\r\n abbr = RichTextProcessor.getAbbreviation(title);\r\n }\r\n\r\n div.innerHTML = abbr;\r\n //return Promise.resolve(true);\r\n }\r\n\r\n if(avatarAvailable/* && false */) {\r\n return this.putAvatar(div, peerId, photo, size);\r\n }\r\n }\r\n}\r\n\r\nconst appProfileManager = new AppProfileManager();\r\nMOUNT_CLASS_TO.appProfileManager = appProfileManager;\r\nexport default appProfileManager;\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 { bytesFromHex } from \"../../helpers/bytes\";\r\nimport { CancellablePromise } from \"../../helpers/cancellablePromise\";\r\nimport { getFileNameByLocation } from \"../../helpers/fileName\";\r\nimport { safeReplaceArrayInObject, defineNotNumerableProperties, isObject } from \"../../helpers/object\";\r\nimport { isSafari } from \"../../helpers/userAgent\";\r\nimport { FileLocation, InputFileLocation, InputMedia, Photo, PhotoSize, PhotosPhotos } from \"../../layer\";\r\nimport apiManager from \"../mtproto/mtprotoworker\";\r\nimport referenceDatabase, { ReferenceContext } from \"../mtproto/referenceDatabase\";\r\nimport { calcImageInBox } from \"../../helpers/dom\";\r\nimport { MyDocument } from \"./appDocsManager\";\r\nimport appDownloadManager from \"./appDownloadManager\";\r\nimport appUsersManager from \"./appUsersManager\";\r\nimport blur from \"../../helpers/blur\";\r\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\r\nimport renderImageFromUrl from \"../../helpers/dom/renderImageFromUrl\";\r\n\r\nexport type MyPhoto = Photo.photo;\r\n\r\n// TIMES = 2 DUE TO SIDEBAR AND CHAT\r\n//let TEST_FILE_REFERENCE = \"5440692274120994569\", TEST_FILE_REFERENCE_TIMES = 2;\r\n\r\ntype DocumentCacheThumb = {\r\n downloaded: number, \r\n url: string\r\n};\r\n\r\nexport class AppPhotosManager {\r\n private photos: {\r\n [id: string]: MyPhoto\r\n } = {};\r\n private documentThumbsCache: {\r\n [docId: string]: DocumentCacheThumb\r\n } = {};\r\n public windowW = 0;\r\n public windowH = 0;\r\n \r\n public static jf = new Uint8Array(bytesFromHex('ffd8ffe000104a46494600010100000100010000ffdb004300281c1e231e19282321232d2b28303c64413c37373c7b585d4964918099968f808c8aa0b4e6c3a0aadaad8a8cc8ffcbdaeef5ffffff9bc1fffffffaffe6fdfff8ffdb0043012b2d2d3c353c76414176f8a58ca5f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8ffc00011080000000003012200021101031101ffc4001f0000010501010101010100000000000000000102030405060708090a0bffc400b5100002010303020403050504040000017d01020300041105122131410613516107227114328191a1082342b1c11552d1f02433627282090a161718191a25262728292a3435363738393a434445464748494a535455565758595a636465666768696a737475767778797a838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae1e2e3e4e5e6e7e8e9eaf1f2f3f4f5f6f7f8f9faffc4001f0100030101010101010101010000000000000102030405060708090a0bffc400b51100020102040403040705040400010277000102031104052131061241510761711322328108144291a1b1c109233352f0156272d10a162434e125f11718191a262728292a35363738393a434445464748494a535455565758595a636465666768696a737475767778797a82838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae2e3e4e5e6e7e8e9eaf2f3f4f5f6f7f8f9faffda000c03010002110311003f00'));\r\n public static Df = bytesFromHex('ffd9');\r\n \r\n constructor() {\r\n // @ts-ignore\r\n const w: any = 'visualViewport' in window ? window.visualViewport : window;\r\n const set = () => {\r\n this.windowW = w.width || w.innerWidth;\r\n this.windowH = w.height || w.innerHeight;\r\n };\r\n w.addEventListener('resize', set);\r\n set();\r\n }\r\n \r\n public savePhoto(photo: Photo, context?: ReferenceContext) {\r\n if(photo._ === 'photoEmpty') return undefined;\r\n\r\n /* if(photo.id === TEST_FILE_REFERENCE) {\r\n console.warn('Testing FILE_REFERENCE_EXPIRED');\r\n const bytes = [2, 67, 175, 43, 190, 0, 0, 20, 62, 95, 111, 33, 45, 99, 220, 116, 218, 11, 167, 127, 213, 18, 127, 32, 243, 202, 117, 80, 30];\r\n //photo.file_reference = new Uint8Array(bytes);\r\n photo.file_reference = bytes;\r\n if(!--TEST_FILE_REFERENCE_TIMES) {\r\n TEST_FILE_REFERENCE = '';\r\n }\r\n } */\r\n\r\n const oldPhoto = this.photos[photo.id];\r\n if(photo.file_reference) { // * because we can have a new object w/o the file_reference while sending\r\n safeReplaceArrayInObject('file_reference', oldPhoto, photo);\r\n referenceDatabase.saveContext(photo.file_reference, context);\r\n }\r\n\r\n if(photo.sizes?.length) {\r\n const size = photo.sizes[photo.sizes.length - 1];\r\n if(size._ === 'photoSizeProgressive') {\r\n size.size = size.sizes[size.sizes.length - 1];\r\n }\r\n }\r\n\r\n if(oldPhoto) {\r\n return Object.assign(oldPhoto, photo);\r\n }\r\n\r\n return this.photos[photo.id] = photo;\r\n }\r\n \r\n public choosePhotoSize(photo: MyPhoto | MyDocument, width = 0, height = 0, useBytes = false) {\r\n if(window.devicePixelRatio > 1) {\r\n width *= 2;\r\n height *= 2;\r\n }\r\n \r\n /*\r\n s\tbox\t100x100\r\n m\tbox\t320x320\r\n x\tbox\t800x800\r\n y\tbox\t1280x1280\r\n w\tbox\t2560x2560\r\n a\tcrop\t160x160\r\n b\tcrop\t320x320\r\n c\tcrop\t640x640\r\n d\tcrop\t1280x1280 */\r\n\r\n let bestPhotoSize: PhotoSize = {_: 'photoSizeEmpty', type: ''};\r\n const sizes = ((photo as MyPhoto).sizes || (photo as MyDocument).thumbs) as PhotoSize[];\r\n if(sizes?.length) {\r\n for(const photoSize of sizes) {\r\n if(!('w' in photoSize) && !('h' in photoSize)) continue;\r\n \r\n bestPhotoSize = photoSize;\r\n \r\n const {w, h} = calcImageInBox(photoSize.w, photoSize.h, width, height);\r\n if(w >= width || h >= height) {\r\n break;\r\n }\r\n }\r\n\r\n if(useBytes && bestPhotoSize._ === 'photoSizeEmpty' && sizes[0]._ === 'photoStrippedSize') {\r\n bestPhotoSize = sizes[0];\r\n }\r\n }\r\n \r\n return bestPhotoSize;\r\n }\r\n \r\n public getUserPhotos(userId: number, maxId: string = '0', limit: number = 20) {\r\n const inputUser = appUsersManager.getUserInput(userId);\r\n return apiManager.invokeApiCacheable('photos.getUserPhotos', {\r\n user_id: inputUser,\r\n offset: 0,\r\n limit,\r\n max_id: maxId\r\n }, {cacheSeconds: 60}).then((photosResult) => {\r\n appUsersManager.saveApiUsers(photosResult.users);\r\n const photoIds: string[] = photosResult.photos.map((photo, idx) => {\r\n photosResult.photos[idx] = this.savePhoto(photo, {type: 'profilePhoto', peerId: userId});\r\n return photo.id;\r\n });\r\n \r\n return {\r\n count: (photosResult as PhotosPhotos.photosPhotosSlice).count || photosResult.photos.length,\r\n photos: photoIds\r\n };\r\n });\r\n }\r\n\r\n public getPreviewURLFromBytes(bytes: Uint8Array | number[], isSticker = false) {\r\n let arr: Uint8Array;\r\n if(!isSticker) {\r\n arr = AppPhotosManager.jf.concat(bytes.slice(3), AppPhotosManager.Df);\r\n arr[164] = bytes[1];\r\n arr[166] = bytes[2];\r\n } else {\r\n arr = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);\r\n }\r\n\r\n let mimeType: string;\r\n if(isSticker) {\r\n mimeType = isSafari ? 'image/png' : 'image/webp';\r\n } else {\r\n mimeType = 'image/jpeg';\r\n }\r\n\r\n const blob = new Blob([arr], {type: mimeType});\r\n return URL.createObjectURL(blob);\r\n }\r\n\r\n /**\r\n * https://core.telegram.org/api/files#vector-thumbnails\r\n */\r\n public getPathFromPhotoPathSize(size: PhotoSize.photoPathSize) {\r\n const bytes = size.bytes;\r\n const lookup = \"AACAAAAHAAALMAAAQASTAVAAAZaacaaaahaaalmaaaqastava.az0123456789-,\";\r\n\r\n let path = 'M';\r\n for(let i = 0, length = bytes.length; i < length; ++i) {\r\n const num = bytes[i];\r\n\r\n if(num >= (128 + 64)) {\r\n path += lookup[num - 128 - 64];\r\n } else {\r\n if(num >= 128) {\r\n path += ',';\r\n } else if(num >= 64) {\r\n path += '-'; \r\n }\r\n path += '' + (num & 63);\r\n }\r\n }\r\n path += 'z';\r\n\r\n return path;\r\n }\r\n\r\n public getPreviewURLFromThumb(thumb: PhotoSize.photoCachedSize | PhotoSize.photoStrippedSize, isSticker = false) {\r\n return thumb.url ?? (defineNotNumerableProperties(thumb, ['url']), thumb.url = this.getPreviewURLFromBytes(thumb.bytes, isSticker));\r\n }\r\n \r\n public getImageFromStrippedThumb(thumb: PhotoSize.photoCachedSize | PhotoSize.photoStrippedSize, useBlur: boolean) {\r\n const url = this.getPreviewURLFromThumb(thumb, false);\r\n\r\n const image = new Image();\r\n image.classList.add('thumbnail');\r\n\r\n const loadPromise = (useBlur ? blur(url) : Promise.resolve(url)).then(url => {\r\n return new Promise<any>((resolve) => {\r\n renderImageFromUrl(image, url, resolve);\r\n });\r\n });\r\n \r\n return {image, loadPromise};\r\n }\r\n \r\n public setAttachmentSize(photo: MyPhoto | MyDocument, element: HTMLElement | SVGForeignObjectElement, boxWidth: number, boxHeight: number, noZoom = true, hasText?: boolean) {\r\n const photoSize = this.choosePhotoSize(photo, boxWidth, boxHeight);\r\n //console.log('setAttachmentSize', photo, photo.sizes[0].bytes, div);\r\n \r\n let width: number;\r\n let height: number;\r\n if(photo._ === 'document') {\r\n width = photo.w || 512;\r\n height = photo.h || 512;\r\n } else {\r\n width = 'w' in photoSize ? photoSize.w : 100;\r\n height = 'h' in photoSize ? photoSize.h : 100;\r\n }\r\n \r\n let {w, h} = calcImageInBox(width, height, boxWidth, boxHeight, noZoom);\r\n\r\n /* if(hasText) {\r\n w = Math.max(boxWidth, w);\r\n } */\r\n\r\n if(element instanceof SVGForeignObjectElement) {\r\n element.setAttributeNS(null, 'width', '' + w);\r\n element.setAttributeNS(null, 'height', '' + h);\r\n\r\n //console.log('set dimensions to svg element:', element, w, h);\r\n } else {\r\n element.style.width = w + 'px';\r\n element.style.height = h + 'px';\r\n }\r\n \r\n return photoSize;\r\n }\r\n\r\n public getStrippedThumbIfNeeded(photo: MyPhoto | MyDocument, useBlur: boolean): ReturnType<AppPhotosManager['getImageFromStrippedThumb']> {\r\n if(!photo.downloaded || (photo as MyDocument).type === 'video' || (photo as MyDocument).type === 'gif') {\r\n if(photo._ === 'document') {\r\n const cacheContext = this.getCacheContext(photo); \r\n if(cacheContext.downloaded) {\r\n return null;\r\n } \r\n }\r\n\r\n const sizes = (photo as MyPhoto).sizes || (photo as MyDocument).thumbs;\r\n const thumb = sizes?.length ? sizes.find(size => size._ === 'photoStrippedSize') : null;\r\n if(thumb && ('bytes' in thumb)) {\r\n return appPhotosManager.getImageFromStrippedThumb(thumb as any, useBlur);\r\n }\r\n }\r\n\r\n return null;\r\n }\r\n \r\n public getPhotoDownloadOptions(photo: MyPhoto | MyDocument, photoSize: PhotoSize, queueId?: number, onlyCache?: boolean) {\r\n const isMyDocument = photo._ === 'document';\r\n\r\n if(!photoSize || photoSize._ === 'photoSizeEmpty') {\r\n //console.error('no photoSize by photo:', photo);\r\n throw new Error('photoSizeEmpty!');\r\n }\r\n \r\n // maybe it's a thumb\r\n const isPhoto = (photoSize._ === 'photoSize' || photoSize._ === 'photoSizeProgressive') && photo.access_hash && photo.file_reference;\r\n const location: InputFileLocation.inputPhotoFileLocation | InputFileLocation.inputDocumentFileLocation | FileLocation = isPhoto ? {\r\n _: isMyDocument ? 'inputDocumentFileLocation' : 'inputPhotoFileLocation',\r\n id: photo.id,\r\n access_hash: photo.access_hash,\r\n file_reference: photo.file_reference,\r\n thumb_size: photoSize.type\r\n } : (photoSize as PhotoSize.photoSize).location;\r\n\r\n return {dcId: photo.dc_id, location, size: isPhoto ? (photoSize as PhotoSize.photoSize).size : undefined, queueId, onlyCache};\r\n }\r\n\r\n /* public getPhotoURL(photo: MTPhoto | MTMyDocument, photoSize: MTPhotoSize) {\r\n const downloadOptions = this.getPhotoDownloadOptions(photo, photoSize);\r\n\r\n return {url: getFileURL('photo', downloadOptions), location: downloadOptions.location};\r\n } */\r\n\r\n public isDownloaded(media: any) {\r\n const isPhoto = media._ === 'photo';\r\n const photo = isPhoto ? this.getPhoto(media.id) : null;\r\n let isDownloaded: boolean;\r\n if(photo) {\r\n isDownloaded = photo.downloaded > 0;\r\n } else {\r\n const cachedThumb = this.getDocumentCachedThumb(media.id);\r\n isDownloaded = cachedThumb?.downloaded > 0;\r\n }\r\n\r\n return isDownloaded;\r\n }\r\n \r\n public preloadPhoto(photoId: any, photoSize?: PhotoSize, queueId?: number, onlyCache?: boolean): CancellablePromise<Blob> {\r\n const photo = this.getPhoto(photoId);\r\n\r\n // @ts-ignore\r\n if(!photo || photo._ === 'photoEmpty') {\r\n throw new Error('preloadPhoto photoEmpty!');\r\n }\r\n\r\n if(!photoSize) {\r\n const fullWidth = this.windowW;\r\n const fullHeight = this.windowH;\r\n \r\n photoSize = this.choosePhotoSize(photo, fullWidth, fullHeight);\r\n }\r\n\r\n const cacheContext = this.getCacheContext(photo);\r\n if(cacheContext.downloaded >= ('size' in photoSize ? photoSize.size : 0) && cacheContext.url) {\r\n return Promise.resolve() as any;\r\n }\r\n \r\n const downloadOptions = this.getPhotoDownloadOptions(photo, photoSize, queueId, onlyCache);\r\n\r\n const fileName = getFileNameByLocation(downloadOptions.location);\r\n\r\n let download = appDownloadManager.getDownload(fileName);\r\n if(download) {\r\n return download;\r\n }\r\n\r\n download = appDownloadManager.download(downloadOptions);\r\n download.then(blob => {\r\n const url = URL.createObjectURL(blob);\r\n if(!cacheContext.downloaded || cacheContext.downloaded < blob.size) {\r\n defineNotNumerableProperties(cacheContext, ['downloaded', 'url']);\r\n\r\n cacheContext.downloaded = blob.size;\r\n cacheContext.url = url;\r\n\r\n //console.log('wrote photo:', photo, photoSize, cacheContext, blob);\r\n }\r\n\r\n defineNotNumerableProperties(photoSize, ['url']);\r\n (photoSize as any).url = url;\r\n\r\n return blob;\r\n }).catch(() => {});\r\n\r\n return download;\r\n }\r\n\r\n public getCacheContext(photo: any): DocumentCacheThumb {\r\n return photo._ === 'document' ? this.getDocumentCachedThumb(photo.id) : photo;\r\n }\r\n\r\n public getDocumentCachedThumb(docId: string) {\r\n return this.documentThumbsCache[docId] ?? (this.documentThumbsCache[docId] = {downloaded: 0, url: ''});\r\n }\r\n \r\n public getPhoto(photoId: any): MyPhoto {\r\n return isObject(photoId) ? photoId : this.photos[photoId];\r\n }\r\n\r\n public getInput(photo: MyPhoto): InputMedia.inputMediaPhoto {\r\n return {\r\n _: 'inputMediaPhoto',\r\n id: {\r\n _: 'inputPhoto',\r\n id: photo.id,\r\n access_hash: photo.access_hash,\r\n file_reference: photo.file_reference\r\n },\r\n ttl_seconds: 0\r\n };\r\n }\r\n\r\n public savePhotoFile(photo: MyPhoto | MyDocument, queueId?: number) {\r\n const fullPhotoSize = this.choosePhotoSize(photo, 0xFFFF, 0xFFFF);\r\n if(!(fullPhotoSize._ === 'photoSize' || fullPhotoSize._ === 'photoSizeProgressive')) {\r\n return;\r\n }\r\n\r\n const location: InputFileLocation.inputDocumentFileLocation | InputFileLocation.inputPhotoFileLocation = {\r\n _: photo._ === 'document' ? 'inputDocumentFileLocation' : 'inputPhotoFileLocation',\r\n id: photo.id,\r\n access_hash: photo.access_hash,\r\n file_reference: photo.file_reference,\r\n thumb_size: fullPhotoSize.type\r\n };\r\n\r\n appDownloadManager.downloadToDisc({\r\n dcId: photo.dc_id, \r\n location, \r\n size: fullPhotoSize.size, \r\n fileName: 'photo' + photo.id + '.jpg',\r\n queueId\r\n }, 'photo' + photo.id + '.jpg');\r\n }\r\n}\r\n\r\nconst appPhotosManager = new AppPhotosManager();\r\nMOUNT_CLASS_TO.appPhotosManager = appPhotosManager;\r\nexport default appPhotosManager;\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 { FileURLType, getFileNameByLocation, getFileURL } from '../../helpers/fileName';\r\nimport { safeReplaceArrayInObject, defineNotNumerableProperties, isObject } from '../../helpers/object';\r\nimport { Document, InputFileLocation, PhotoSize } from '../../layer';\r\nimport referenceDatabase, { ReferenceContext } from '../mtproto/referenceDatabase';\r\nimport opusDecodeController from '../opusDecodeController';\r\nimport { RichTextProcessor } from '../richtextprocessor';\r\nimport webpWorkerController from '../webp/webpWorkerController';\r\nimport appDownloadManager, { DownloadBlob } from './appDownloadManager';\r\nimport appPhotosManager from './appPhotosManager';\r\nimport blur from '../../helpers/blur';\r\nimport apiManager from '../mtproto/mtprotoworker';\r\nimport { MOUNT_CLASS_TO } from '../../config/debug';\r\n\r\nexport type MyDocument = Document.document;\r\n\r\n// TODO: если залить картинку файлом, а потом перезайти в диалог - превьюшка заново скачается\r\n\r\nexport class AppDocsManager {\r\n private docs: {[docId: string]: MyDocument} = {};\r\n private savingLottiePreview: {[docId: string]: true} = {};\r\n\r\n public onServiceWorkerFail() {\r\n for(const id in this.docs) {\r\n const doc = this.docs[id];\r\n delete doc.supportsStreaming;\r\n delete doc.url;\r\n }\r\n }\r\n\r\n public saveDoc(doc: Document, context?: ReferenceContext): MyDocument {\r\n if(doc._ === 'documentEmpty') {\r\n return undefined;\r\n }\r\n\r\n const oldDoc = this.docs[doc.id];\r\n\r\n if(doc.file_reference) { // * because we can have a new object w/o the file_reference while sending\r\n safeReplaceArrayInObject('file_reference', oldDoc, doc);\r\n referenceDatabase.saveContext(doc.file_reference, context);\r\n }\r\n \r\n //console.log('saveDoc', apiDoc, this.docs[apiDoc.id]);\r\n if(oldDoc) {\r\n //if(doc._ !== 'documentEmpty' && doc._ === d._) {\r\n if(doc.thumbs) {\r\n if(!oldDoc.thumbs) oldDoc.thumbs = doc.thumbs;\r\n /* else if(apiDoc.thumbs[0].bytes && !d.thumbs[0].bytes) {\r\n d.thumbs.unshift(apiDoc.thumbs[0]);\r\n } else if(d.thumbs[0].url) { // fix for converted thumb in safari\r\n apiDoc.thumbs[0] = d.thumbs[0];\r\n } */\r\n }\r\n\r\n //}\r\n\r\n return oldDoc;\r\n\r\n //return Object.assign(d, apiDoc, context);\r\n //return context ? Object.assign(d, context) : d;\r\n }\r\n\r\n this.docs[doc.id] = doc;\r\n\r\n // * exclude from state\r\n // defineNotNumerableProperties(doc, [/* 'thumbs', */'type', 'h', 'w', 'file_name', \r\n // 'file', 'duration', 'downloaded', 'url', 'audioTitle', \r\n // 'audioPerformer', 'sticker', 'stickerEmoji', 'stickerEmojiRaw', \r\n // 'stickerSetInput', 'stickerThumbConverted', 'animated', 'supportsStreaming']);\r\n defineNotNumerableProperties(doc, ['downloaded', 'url']);\r\n \r\n doc.attributes.forEach(attribute => {\r\n switch(attribute._) {\r\n case 'documentAttributeFilename':\r\n doc.file_name = RichTextProcessor.wrapPlainText(attribute.file_name);\r\n break;\r\n\r\n case 'documentAttributeAudio':\r\n doc.duration = attribute.duration;\r\n doc.audioTitle = attribute.title;\r\n doc.audioPerformer = attribute.performer;\r\n doc.type = attribute.pFlags.voice && doc.mime_type === \"audio/ogg\" ? 'voice' : 'audio';\r\n\r\n /* if(apiDoc.type === 'audio') {\r\n apiDoc.supportsStreaming = true;\r\n } */\r\n break;\r\n\r\n case 'documentAttributeVideo':\r\n doc.duration = attribute.duration;\r\n doc.w = attribute.w;\r\n doc.h = attribute.h;\r\n //apiDoc.supportsStreaming = attribute.pFlags?.supports_streaming/* && apiDoc.size > 524288 */;\r\n if(/* apiDoc.thumbs && */attribute.pFlags.round_message) {\r\n doc.type = 'round';\r\n } else /* if(apiDoc.thumbs) */ {\r\n doc.type = 'video';\r\n }\r\n break;\r\n\r\n case 'documentAttributeSticker':\r\n if(attribute.alt !== undefined) {\r\n doc.stickerEmojiRaw = attribute.alt;\r\n doc.stickerEmoji = RichTextProcessor.wrapRichText(doc.stickerEmojiRaw, {noLinks: true, noLinebreaks: true});\r\n }\r\n\r\n if(attribute.stickerset) {\r\n if(attribute.stickerset._ === 'inputStickerSetEmpty') {\r\n delete attribute.stickerset;\r\n } else if(attribute.stickerset._ === 'inputStickerSetID') {\r\n doc.stickerSetInput = attribute.stickerset;\r\n }\r\n }\r\n\r\n // * there can be no thumbs, then it is a document\r\n if(/* apiDoc.thumbs && */doc.mime_type === 'image/webp' && (doc.thumbs || webpWorkerController.isWebpSupported())) {\r\n doc.type = 'sticker';\r\n doc.sticker = 1;\r\n }\r\n break;\r\n\r\n case 'documentAttributeImageSize':\r\n doc.type = 'photo';\r\n doc.w = attribute.w;\r\n doc.h = attribute.h;\r\n break;\r\n\r\n case 'documentAttributeAnimated':\r\n if((doc.mime_type === 'image/gif' || doc.mime_type === 'video/mp4')/* && apiDoc.thumbs */) {\r\n doc.type = 'gif';\r\n }\r\n\r\n doc.animated = true;\r\n break;\r\n }\r\n });\r\n \r\n if(!doc.mime_type) {\r\n switch(doc.type) {\r\n case 'gif':\r\n case 'video':\r\n case 'round':\r\n doc.mime_type = 'video/mp4';\r\n break;\r\n case 'sticker':\r\n doc.mime_type = 'image/webp';\r\n break;\r\n case 'audio':\r\n doc.mime_type = 'audio/mpeg';\r\n break;\r\n case 'voice':\r\n doc.mime_type = 'audio/ogg';\r\n break;\r\n default:\r\n doc.mime_type = 'application/octet-stream';\r\n break;\r\n }\r\n }\r\n\r\n if(apiManager.isServiceWorkerOnline()) {\r\n if((doc.type === 'gif' && doc.size > 8e6) || doc.type === 'audio' || doc.type === 'video') {\r\n doc.supportsStreaming = true;\r\n \r\n if(!doc.url) {\r\n doc.url = this.getFileURL(doc);\r\n }\r\n }\r\n }\r\n\r\n // for testing purposes\r\n // doc.supportsStreaming = false;\r\n // doc.url = ''; // * this will break upload urls\r\n \r\n if(!doc.file_name) {\r\n doc.file_name = '';\r\n }\r\n\r\n if(doc.mime_type === 'application/x-tgsticker' && doc.file_name === \"AnimatedSticker.tgs\") {\r\n doc.type = 'sticker';\r\n doc.animated = true;\r\n doc.sticker = 2;\r\n }\r\n\r\n /* if(!doc.url) {\r\n doc.url = this.getFileURL(doc);\r\n } */\r\n\r\n return doc;\r\n }\r\n \r\n public getDoc(docId: string | MyDocument): MyDocument {\r\n return isObject(docId) && typeof(docId) !== 'string' ? docId as any : this.docs[docId as string] as any;\r\n }\r\n\r\n public getMediaInput(doc: MyDocument) {\r\n return {\r\n _: 'inputMediaDocument',\r\n id: {\r\n _: 'inputDocument',\r\n id: doc.id,\r\n access_hash: doc.access_hash,\r\n file_reference: doc.file_reference\r\n },\r\n ttl_seconds: 0\r\n };\r\n }\r\n\r\n public getInput(doc: MyDocument, thumbSize?: string): InputFileLocation.inputDocumentFileLocation {\r\n return {\r\n _: 'inputDocumentFileLocation',\r\n id: doc.id,\r\n access_hash: doc.access_hash,\r\n file_reference: doc.file_reference,\r\n thumb_size: thumbSize\r\n };\r\n }\r\n\r\n public getFileDownloadOptions(doc: MyDocument, thumb?: PhotoSize.photoSize, queueId?: number, onlyCache?: boolean) {\r\n const inputFileLocation = this.getInput(doc, thumb?.type);\r\n\r\n let mimeType: string;\r\n if(thumb) {\r\n mimeType = doc.sticker ? 'image/webp' : 'image/jpeg'/* doc.mime_type */;\r\n } else {\r\n mimeType = doc.mime_type || 'application/octet-stream';\r\n }\r\n\r\n return {\r\n dcId: doc.dc_id, \r\n location: inputFileLocation, \r\n size: thumb ? thumb.size : doc.size, \r\n mimeType: mimeType,\r\n fileName: doc.file_name,\r\n queueId,\r\n onlyCache\r\n };\r\n }\r\n\r\n public getFileURL(doc: MyDocument, download = false, thumb?: PhotoSize.photoSize) {\r\n let type: FileURLType;\r\n if(download) {\r\n type = 'download';\r\n } else if(thumb) {\r\n type = 'thumb';\r\n } else if(doc.supportsStreaming) {\r\n type = 'stream';\r\n } else {\r\n type = 'document';\r\n }\r\n\r\n return getFileURL(type, this.getFileDownloadOptions(doc, thumb));\r\n }\r\n\r\n public getThumbURL(doc: MyDocument, thumb: PhotoSize.photoSize | PhotoSize.photoCachedSize | PhotoSize.photoStrippedSize) {\r\n let promise: Promise<any> = Promise.resolve();\r\n\r\n if(!thumb.url) {\r\n if('bytes' in thumb) {\r\n promise = blur(appPhotosManager.getPreviewURLFromBytes(thumb.bytes, !!doc.sticker)).then(url => {\r\n defineNotNumerableProperties(thumb, ['url']); // * exclude from state\r\n const cacheContext = appPhotosManager.getCacheContext(doc);\r\n cacheContext.url = thumb.url = url;\r\n }) as any;\r\n } else {\r\n //return this.getFileURL(doc, false, thumb);\r\n promise = appPhotosManager.preloadPhoto(doc, thumb) as any;\r\n }\r\n }\r\n\r\n return {thumb, promise};\r\n }\r\n\r\n public getThumb(doc: MyDocument, tryNotToUseBytes = true) {\r\n const thumb = appPhotosManager.choosePhotoSize(doc, 0, 0, !tryNotToUseBytes);\r\n if(thumb._ === 'photoSizeEmpty') return null;\r\n return this.getThumbURL(doc, thumb as any);\r\n }\r\n\r\n public getInputFileName(doc: MyDocument, thumbSize?: string) {\r\n return getFileNameByLocation(this.getInput(doc, thumbSize), {fileName: doc.file_name});\r\n }\r\n\r\n public downloadDoc(doc: MyDocument, queueId?: number, onlyCache?: boolean): DownloadBlob {\r\n const fileName = this.getInputFileName(doc);\r\n\r\n let download: DownloadBlob = appDownloadManager.getDownload(fileName);\r\n if(download) {\r\n return download;\r\n }\r\n\r\n const downloadOptions = this.getFileDownloadOptions(doc, undefined, queueId, onlyCache);\r\n download = appDownloadManager.download(downloadOptions);\r\n\r\n const originalPromise = download;\r\n originalPromise.then((blob) => {\r\n doc.url = URL.createObjectURL(blob);\r\n doc.downloaded = true;\r\n }, () => {});\r\n \r\n if(doc.type === 'voice' && !opusDecodeController.isPlaySupported()) {\r\n download = originalPromise.then(async(blob) => {\r\n const reader = new FileReader();\r\n \r\n await new Promise<void>((resolve, reject) => {\r\n reader.onloadend = (e) => {\r\n const uint8 = new Uint8Array(e.target.result as ArrayBuffer);\r\n //console.log('sending uint8 to decoder:', uint8);\r\n opusDecodeController.decode(uint8).then(result => {\r\n doc.url = result.url;\r\n resolve();\r\n }, (err) => {\r\n delete doc.downloaded;\r\n reject(err);\r\n });\r\n };\r\n \r\n reader.readAsArrayBuffer(blob);\r\n });\r\n \r\n return blob;\r\n });\r\n }\r\n\r\n return download;\r\n }\r\n\r\n public saveLottiePreview(doc: MyDocument, canvas: HTMLCanvasElement, toneIndex: number) {\r\n const key = doc.id + '-' + toneIndex;\r\n if(this.savingLottiePreview[key]/* || true */) return;\r\n\r\n if(!doc.stickerCachedThumbs) {\r\n defineNotNumerableProperties(doc, ['stickerCachedThumbs']);\r\n doc.stickerCachedThumbs = {};\r\n }\r\n\r\n const thumb = doc.stickerCachedThumbs[toneIndex];\r\n if(thumb && thumb.w >= canvas.width && thumb.h >= canvas.height) {\r\n return;\r\n }\r\n\r\n /* if(doc.thumbs.find(t => t._ === 'photoStrippedSize') \r\n || (doc.stickerCachedThumb || (doc.stickerSavedThumbWidth >= canvas.width && doc.stickerSavedThumbHeight >= canvas.height))) {\r\n return;\r\n } */\r\n\r\n this.savingLottiePreview[key] = true;\r\n canvas.toBlob((blob) => {\r\n //console.log('got lottie preview', doc, blob, URL.createObjectURL(blob));\r\n\r\n const thumb = {\r\n url: URL.createObjectURL(blob),\r\n w: canvas.width,\r\n h: canvas.height\r\n };\r\n\r\n doc.stickerCachedThumbs[toneIndex] = thumb;\r\n\r\n delete this.savingLottiePreview[key];\r\n \r\n /* const reader = new FileReader();\r\n reader.onloadend = (e) => {\r\n const uint8 = new Uint8Array(e.target.result as ArrayBuffer);\r\n const thumb: PhotoSize.photoStrippedSize = {\r\n _: 'photoStrippedSize',\r\n bytes: uint8,\r\n type: 'i'\r\n };\r\n\r\n doc.stickerSavedThumbWidth = canvas.width;\r\n doc.stickerSavedThumbHeight = canvas.width;\r\n\r\n defineNotNumerableProperties(thumb, ['url']);\r\n thumb.url = URL.createObjectURL(blob);\r\n doc.thumbs.findAndSplice(t => t._ === thumb._);\r\n doc.thumbs.unshift(thumb);\r\n\r\n if(!webpWorkerController.isWebpSupported()) {\r\n doc.pFlags.stickerThumbConverted = true;\r\n }\r\n\r\n delete this.savingLottiePreview[doc.id];\r\n };\r\n reader.readAsArrayBuffer(blob); */\r\n });\r\n }\r\n\r\n public saveDocFile(doc: MyDocument, queueId?: number) {\r\n /* const options = this.getFileDownloadOptions(doc, undefined, queueId);\r\n return appDownloadManager.downloadToDisc(options, doc.file_name); */\r\n const promise = this.downloadDoc(doc, queueId);\r\n promise.then(() => {\r\n appDownloadManager.createDownloadAnchor(doc.url, doc.file_name);\r\n });\r\n return promise;\r\n }\r\n}\r\n\r\nconst appDocsManager = new AppDocsManager();\r\nMOUNT_CLASS_TO.appDocsManager = appDocsManager;\r\nexport default appDocsManager;\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 appPeersManager from \"../lib/appManagers/appPeersManager\";\r\nimport rootScope from \"../lib/rootScope\";\r\nimport { replaceContent } from \"../helpers/dom\";\r\nimport { i18n } from \"../lib/langPack\";\r\n\r\nexport type PeerTitleOptions = {\r\n peerId: number,\r\n plainText?: boolean,\r\n onlyFirstName?: boolean,\r\n dialog?: boolean\r\n};\r\n\r\nconst weakMap: WeakMap<HTMLElement, PeerTitle> = new WeakMap();\r\n\r\nMOUNT_CLASS_TO.peerTitleWeakMap = weakMap;\r\n\r\nrootScope.on('peer_title_edit', (peerId) => {\r\n const elements = Array.from(document.querySelectorAll(`.peer-title[data-peer-id=\"${peerId}\"]`)) as HTMLElement[];\r\n elements.forEach(element => {\r\n const peerTitle = weakMap.get(element);\r\n //console.log('in the summer silence i was doing nothing', peerTitle, peerId);\r\n\r\n if(peerTitle) {\r\n peerTitle.update();\r\n }\r\n });\r\n});\r\n\r\nexport default class PeerTitle {\r\n public element: HTMLElement;\r\n public peerId: number;\r\n public plainText = false;\r\n public onlyFirstName = false;\r\n public dialog = false;\r\n\r\n constructor(options: PeerTitleOptions) {\r\n this.element = document.createElement('span');\r\n this.element.classList.add('peer-title');\r\n \r\n this.update(options);\r\n weakMap.set(this.element, this);\r\n }\r\n\r\n public update(options?: PeerTitleOptions) {\r\n if(options) {\r\n for(let i in options) {\r\n // @ts-ignore\r\n this.element.dataset[i] = options[i] ? '' + (typeof(options[i]) === 'boolean' ? +options[i] : options[i]) : '0';\r\n // @ts-ignore\r\n this[i] = options[i];\r\n }\r\n }\r\n\r\n if(this.peerId !== rootScope.myId || !this.dialog) {\r\n this.element.innerHTML = appPeersManager.getPeerTitle(this.peerId, this.plainText, this.onlyFirstName);\r\n } else {\r\n replaceContent(this.element, i18n(this.onlyFirstName ? 'Saved' : 'SavedMessages'));\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 nextRandomInt(maxValue: number) {\r\n return Math.floor(Math.random() * maxValue);\r\n}\r\n\r\nexport function randomLong() {\r\n return '' + nextRandomInt(0xFFFFFFFF) + nextRandomInt(0xFFFFFF);\r\n //return '' + parseInt(nextRandomInt(0xFFFFFFFF).toString(16) + nextRandomInt(0xFFFFFFFF).toString(16), 16);\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\nimport { isMobileSafari } from \"../helpers/userAgent\";\r\nimport { blurActiveElement, cancelEvent } from \"../helpers/dom\";\r\nimport { logger } from \"../lib/logger\";\r\nimport { doubleRaf } from \"../helpers/schedulers\";\r\n\r\nexport type NavigationItem = {\r\n type: 'left' | 'right' | 'im' | 'chat' | 'popup' | 'media' | 'menu' | 'esg' | 'multiselect' | 'input-helper' | 'markup' | 'global-search',\r\n onPop: (canAnimate: boolean) => boolean | void,\r\n onEscape?: () => boolean,\r\n noHistory?: boolean,\r\n};\r\n\r\nexport class AppNavigationController {\r\n private navigations: Array<NavigationItem> = [];\r\n private id = Date.now();\r\n private manual = false;\r\n private log = logger('NC');\r\n private debug = true;\r\n private currentHash = window.location.hash;\r\n public onHashChange: () => void;\r\n\r\n constructor() {\r\n let isPossibleSwipe = false;\r\n window.addEventListener('popstate', (e) => {\r\n this.debug && this.log('popstate', e, isPossibleSwipe);\r\n\r\n if(window.location.hash !== this.currentHash) {\r\n this.onHashChange && this.onHashChange();\r\n this.replaceState();\r\n return;\r\n }\r\n this.currentHash = window.location.hash;\r\n\r\n const id: number = e.state;\r\n if(id !== this.id/* && !this.navigations.length */) {\r\n this.pushState();\r\n return;\r\n }\r\n\r\n const item = this.navigations.pop();\r\n if(!item) {\r\n this.pushState();\r\n return;\r\n }\r\n\r\n this.manual = !isPossibleSwipe;\r\n this.handleItem(item);\r\n //this.pushState(); // * prevent adding forward arrow\r\n });\r\n\r\n window.addEventListener('keydown', (e) => {\r\n const item = this.navigations[this.navigations.length - 1];\r\n if(!item) return;\r\n if(e.key === 'Escape' && (item.onEscape ? item.onEscape() : true)) {\r\n cancelEvent(e);\r\n this.back();\r\n }\r\n }, {capture: true});\r\n\r\n if(isMobileSafari) {\r\n const options = {passive: true};\r\n window.addEventListener('touchstart', (e) => {\r\n if(e.touches.length > 1) return;\r\n this.debug && this.log('touchstart');\r\n\r\n const detach = () => {\r\n window.removeEventListener('touchend', onTouchEnd);\r\n window.removeEventListener('touchmove', onTouchMove);\r\n };\r\n\r\n let moved = false;\r\n const onTouchMove = (e: TouchEvent) => {\r\n this.debug && this.log('touchmove');\r\n if(e.touches.length > 1) {\r\n detach();\r\n return;\r\n }\r\n\r\n moved = true;\r\n };\r\n\r\n const onTouchEnd = (e: TouchEvent) => {\r\n this.debug && this.log('touchend');\r\n if(e.touches.length > 1 || !moved) {\r\n detach();\r\n return;\r\n }\r\n\r\n isPossibleSwipe = true;\r\n doubleRaf().then(() => {\r\n isPossibleSwipe = false;\r\n });\r\n\r\n detach();\r\n };\r\n\r\n window.addEventListener('touchend', onTouchEnd, options);\r\n window.addEventListener('touchmove', onTouchMove, options);\r\n }, options);\r\n }\r\n\r\n history.scrollRestoration = 'manual';\r\n\r\n this.pushState(); // * push init state\r\n }\r\n\r\n private handleItem(item: NavigationItem) {\r\n const good = item.onPop(!this.manual ? false : undefined);\r\n this.debug && this.log('popstate, navigation:', item, this.navigations);\r\n if(good === false) {\r\n this.pushItem(item);\r\n } else {\r\n blurActiveElement(); // no better place for it\r\n }\r\n\r\n this.manual = false;\r\n }\r\n\r\n public findItemByType(type: NavigationItem['type']) {\r\n for(let i = this.navigations.length - 1; i >= 0; --i) {\r\n const item = this.navigations[i];\r\n if(item.type === type) {\r\n return {item, index: i};\r\n }\r\n }\r\n }\r\n\r\n public back(type?: NavigationItem['type']) {\r\n if(type) {\r\n const ret = this.findItemByType(type);\r\n if(ret) {\r\n this.manual = true;\r\n // ! commented because 'popstate' event will be fired with delay\r\n //if(ret.index !== (this.navigations.length - 1)) {\r\n this.navigations.splice(ret.index, 1);\r\n this.handleItem(ret.item);\r\n return;\r\n //}\r\n }\r\n }\r\n\r\n history.back();\r\n }\r\n\r\n public pushItem(item: NavigationItem) {\r\n this.navigations.push(item);\r\n this.debug && this.log('pushstate', item, this.navigations);\r\n\r\n if(!item.noHistory) {\r\n this.pushState();\r\n }\r\n }\r\n\r\n private pushState() {\r\n this.manual = false;\r\n history.pushState(this.id, '');\r\n }\r\n\r\n public replaceState() {\r\n history.replaceState(this.id, '', location.origin + location.pathname);\r\n }\r\n\r\n public removeItem(item: NavigationItem) {\r\n this.navigations.findAndSplice(i => i === item);\r\n }\r\n\r\n public removeByType(type: NavigationItem['type'], single = false) {\r\n for(let i = this.navigations.length - 1; i >= 0; --i) {\r\n const item = this.navigations[i];\r\n if(item.type === type) {\r\n this.navigations.splice(i, 1);\r\n\r\n if(single) {\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n}\r\n\r\nconst appNavigationController = new AppNavigationController();\r\nMOUNT_CLASS_TO.appNavigationController = appNavigationController;\r\nexport default appNavigationController;\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 { copy } from \"./object\";\r\n\r\nexport function listMergeSorted(list1: any[] = [], list2: any[] = []) {\r\n const result = copy(list1);\r\n\r\n const minId = list1.length ? list1[list1.length - 1] : 0xFFFFFFFF;\r\n for(let i = 0; i < list2.length; i++) {\r\n if(list2[i] < minId) {\r\n result.push(list2[i]);\r\n }\r\n }\r\n\r\n return result;\r\n} */\r\n\r\nexport const accumulate = (arr: number[], initialValue: number) => arr.reduce((acc, value) => acc + value, initialValue);\r\n\r\nexport function findAndSpliceAll<T>(array: Array<T>, verify: (value: T, index: number, arr: typeof array) => boolean) {\r\n const out: typeof array = [];\r\n let idx = -1;\r\n while((idx = array.findIndex(verify)) !== -1) {\r\n out.push(array.splice(idx, 1)[0]);\r\n }\r\n\r\n return out;\r\n}\r\n\r\nexport function forEachReverse<T>(array: Array<T>, callback: (value: T, index?: number, array?: Array<T>) => void) {\r\n for(let length = array.length, i = length - 1; i >= 0; --i) {\r\n callback(array[i], i, array);\r\n }\r\n};\r\n\r\nexport function insertInDescendSortedArray<T extends {[smth in K]?: number}, K extends keyof T>(array: Array<T>, element: T, property: K, pos?: number) {\r\n if(pos === undefined) {\r\n pos = array.indexOf(element);\r\n if(pos !== -1) {\r\n array.splice(pos, 1);\r\n }\r\n }\r\n\r\n const sortProperty: number = element[property];\r\n const len = array.length;\r\n if(!len || sortProperty <= array[len - 1][property]) {\r\n return array.push(element) - 1;\r\n } else if(sortProperty >= array[0][property]) {\r\n array.unshift(element);\r\n return 0;\r\n } else {\r\n for(let i = 0; i < len; i++) {\r\n if(sortProperty > array[i][property]) {\r\n array.splice(i, 0, element);\r\n return i;\r\n }\r\n }\r\n }\r\n\r\n console.error('wtf', array, element);\r\n return array.indexOf(element);\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 numberThousandSplitter(x: number, joiner = ' ') {\r\n const parts = x.toString().split(\".\");\r\n parts[0] = parts[0].replace(/\\B(?=(\\d{3})+(?!\\d))/g, joiner);\r\n return parts.join(\".\");\r\n}\r\n\r\nexport function formatBytes(bytes: number, decimals = 2) {\r\n if(bytes === 0) return '0 Bytes';\r\n\r\n const k = 1024;\r\n const dm = decimals < 0 ? 0 : decimals;\r\n const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];\r\n\r\n const i = Math.floor(Math.log(bytes) / Math.log(k));\r\n\r\n return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];\r\n}\r\n\r\nexport function formatNumber(bytes: number, decimals = 2) {\r\n if(bytes === 0) return '0';\r\n\r\n const k = 1000;\r\n const dm = decimals < 0 ? 0 : decimals;\r\n const sizes = ['', 'K', 'M', 'B', 'T'];\r\n\r\n const i = Math.floor(Math.log(bytes) / Math.log(k));\r\n\r\n return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + sizes[i];\r\n}\r\n\r\nexport function clamp(v: number, min: number, max: number): number {\r\n return v < min ? min : ((v > max) ? max : v);\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\n//import apiManager from '../mtproto/apiManager';\r\nimport DEBUG, { MOUNT_CLASS_TO } from '../../config/debug';\r\nimport { copy } from '../../helpers/object';\r\nimport { Update } from '../../layer';\r\nimport { logger, LogLevels } from '../logger';\r\nimport apiManager from '../mtproto/mtprotoworker';\r\nimport rootScope from '../rootScope';\r\n//import networkerFactory from '../mtproto/networkerFactory';\r\nimport appChatsManager from \"./appChatsManager\";\r\nimport appPeersManager from \"./appPeersManager\";\r\nimport appStateManager from './appStateManager';\r\nimport appUsersManager from \"./appUsersManager\";\r\n\r\ntype UpdatesState = {\r\n pendingPtsUpdates: {pts: number, pts_count: number}[],\r\n pendingSeqUpdates?: {[seq: number]: {seq: number, date: number, updates: any[]}},\r\n syncPending: {\r\n seqAwaiting?: number,\r\n ptsAwaiting?: true,\r\n timeout: number\r\n },\r\n syncLoading: Promise<void>,\r\n\r\n seq?: number,\r\n pts?: number,\r\n date?: number,\r\n lastPtsUpdateTime?: number\r\n};\r\n\r\nconst SYNC_DELAY = 6;\r\n\r\nexport class ApiUpdatesManager {\r\n public updatesState: UpdatesState = {\r\n pendingPtsUpdates: [],\r\n pendingSeqUpdates: {},\r\n syncPending: null,\r\n syncLoading: null\r\n };\r\n\r\n public channelStates: {[channelId: number]: UpdatesState} = {};\r\n private attached = false;\r\n\r\n private log = logger('UPDATES', LogLevels.error | LogLevels.log | LogLevels.warn | LogLevels.debug);\r\n private debug = DEBUG;\r\n\r\n private popPendingSeqUpdate() {\r\n const state = this.updatesState;\r\n const nextSeq = state.seq + 1;\r\n const pendingUpdatesData = state.pendingSeqUpdates[nextSeq];\r\n if(!pendingUpdatesData) {\r\n return false;\r\n }\r\n\r\n const updates = pendingUpdatesData.updates;\r\n for(let i = 0, length = updates.length; i < length; ++i) {\r\n this.saveUpdate(updates[i]);\r\n }\r\n\r\n state.seq = pendingUpdatesData.seq;\r\n if(pendingUpdatesData.date && state.date < pendingUpdatesData.date) {\r\n state.date = pendingUpdatesData.date;\r\n }\r\n delete state.pendingSeqUpdates[nextSeq];\r\n \r\n if(!this.popPendingSeqUpdate() &&\r\n state.syncPending &&\r\n state.syncPending.seqAwaiting &&\r\n state.seq >= state.syncPending.seqAwaiting) {\r\n if(!state.syncPending.ptsAwaiting) {\r\n clearTimeout(state.syncPending.timeout);\r\n state.syncPending = null;\r\n } else {\r\n delete state.syncPending.seqAwaiting;\r\n }\r\n }\r\n \r\n return true;\r\n }\r\n\r\n private popPendingPtsUpdate(channelId: number) {\r\n const curState = channelId ? this.getChannelState(channelId) : this.updatesState;\r\n if(!curState.pendingPtsUpdates.length) {\r\n return false;\r\n }\r\n\r\n curState.pendingPtsUpdates.sort((a, b) => {\r\n return a.pts - b.pts;\r\n });\r\n // this.log('pop update', channelId, curState.pendingPtsUpdates)\r\n \r\n let curPts = curState.pts;\r\n let goodPts = 0;\r\n let goodIndex = 0;\r\n for(let i = 0, length = curState.pendingPtsUpdates.length; i < length; ++i) {\r\n const update = curState.pendingPtsUpdates[i];\r\n curPts += update.pts_count;\r\n if(curPts >= update.pts) {\r\n goodPts = update.pts;\r\n goodIndex = i;\r\n }\r\n }\r\n \r\n if(!goodPts) {\r\n return false;\r\n }\r\n \r\n this.debug && this.log('pop pending pts updates', goodPts, curState.pendingPtsUpdates.slice(0, goodIndex + 1));\r\n \r\n curState.pts = goodPts;\r\n for(let i = 0; i <= goodIndex; ++i) {\r\n const update = curState.pendingPtsUpdates[i];\r\n\r\n // @ts-ignore\r\n this.saveUpdate(update);\r\n }\r\n curState.pendingPtsUpdates.splice(0, goodIndex + 1);\r\n \r\n if(!curState.pendingPtsUpdates.length && curState.syncPending) {\r\n if(!curState.syncPending.seqAwaiting) {\r\n clearTimeout(curState.syncPending.timeout);\r\n curState.syncPending = null;\r\n } else {\r\n delete curState.syncPending.ptsAwaiting;\r\n }\r\n }\r\n \r\n return true;\r\n }\r\n\r\n public forceGetDifference() {\r\n if(!this.updatesState.syncLoading) {\r\n this.getDifference();\r\n }\r\n }\r\n\r\n public processUpdateMessage = (updateMessage: any/* , options: Partial<{\r\n ignoreSyncLoading: boolean\r\n }> = {} */) => {\r\n // return forceGetDifference()\r\n const processOpts = {\r\n date: updateMessage.date,\r\n seq: updateMessage.seq,\r\n seqStart: updateMessage.seq_start,\r\n //ignoreSyncLoading: options.ignoreSyncLoading\r\n };\r\n\r\n this.debug && this.log('processUpdateMessage', updateMessage);\r\n \r\n switch(updateMessage._) {\r\n case 'updatesTooLong':\r\n case 'new_session_created':\r\n this.forceGetDifference();\r\n break;\r\n \r\n case 'updateShort':\r\n this.processUpdate(updateMessage.update, processOpts);\r\n break;\r\n \r\n case 'updateShortMessage':\r\n case 'updateShortChatMessage': {\r\n this.debug && this.log('updateShortMessage | updateShortChatMessage', {...updateMessage});\r\n const isOut = updateMessage.pFlags.out;\r\n const fromId = updateMessage.from_id || (isOut ? rootScope.myId : updateMessage.user_id);\r\n const toId = updateMessage.chat_id\r\n ? -updateMessage.chat_id\r\n : (updateMessage.user_id || rootScope.myId);\r\n \r\n this.processUpdate({\r\n _: 'updateNewMessage',\r\n message: {\r\n _: 'message',\r\n pFlags: updateMessage.pFlags,\r\n id: updateMessage.id,\r\n from_id: appPeersManager.getOutputPeer(fromId),\r\n peer_id: appPeersManager.getOutputPeer(toId),\r\n date: updateMessage.date,\r\n message: updateMessage.message,\r\n fwd_from: updateMessage.fwd_from,\r\n reply_to: updateMessage.reply_to,\r\n entities: updateMessage.entities\r\n },\r\n pts: updateMessage.pts,\r\n pts_count: updateMessage.pts_count\r\n }, processOpts);\r\n break;\r\n }\r\n \r\n case 'updatesCombined':\r\n case 'updates':\r\n appUsersManager.saveApiUsers(updateMessage.users);\r\n appChatsManager.saveApiChats(updateMessage.chats);\r\n \r\n updateMessage.updates.forEach((update: any) => {\r\n this.processUpdate(update, processOpts);\r\n });\r\n break;\r\n \r\n default:\r\n this.log.warn('Unknown update message', updateMessage);\r\n }\r\n };\r\n \r\n private getDifference(first = false): Promise<void> {\r\n // this.trace('Get full diff')\r\n const updatesState = this.updatesState;\r\n let wasSyncing = updatesState.syncLoading;\r\n if(!wasSyncing) {\r\n updatesState.pendingSeqUpdates = {};\r\n updatesState.pendingPtsUpdates = [];\r\n }\r\n \r\n if(updatesState.syncPending) {\r\n clearTimeout(updatesState.syncPending.timeout);\r\n updatesState.syncPending = null;\r\n }\r\n\r\n const promise = apiManager.invokeApi('updates.getDifference', {\r\n pts: updatesState.pts, \r\n date: updatesState.date, \r\n qts: -1\r\n }, {\r\n timeout: 0x7fffffff\r\n }).then((differenceResult) => {\r\n this.debug && this.log('Get diff result', differenceResult);\r\n\r\n if(differenceResult._ === 'updates.differenceEmpty') {\r\n this.debug && this.log('apply empty diff', differenceResult.seq);\r\n updatesState.date = differenceResult.date;\r\n updatesState.seq = differenceResult.seq;\r\n return;\r\n }\r\n\r\n // ! SORRY I'M SORRY I'M SORRY\r\n if(first) {\r\n rootScope.broadcast('state_synchronizing');\r\n }\r\n\r\n if(differenceResult._ !== 'updates.differenceTooLong') {\r\n appUsersManager.saveApiUsers(differenceResult.users);\r\n appChatsManager.saveApiChats(differenceResult.chats);\r\n\r\n // Should be first because of updateMessageID\r\n // this.log('applying', differenceResult.other_updates.length, 'other updates')\r\n \r\n differenceResult.other_updates.forEach((update) => {\r\n switch(update._) {\r\n case 'updateChannelTooLong':\r\n case 'updateNewChannelMessage':\r\n case 'updateEditChannelMessage':\r\n this.processUpdate(update);\r\n return;\r\n }\r\n \r\n this.saveUpdate(update);\r\n });\r\n\r\n // this.log('applying', differenceResult.new_messages.length, 'new messages')\r\n differenceResult.new_messages.forEach((apiMessage) => {\r\n this.saveUpdate({\r\n _: 'updateNewMessage',\r\n message: apiMessage,\r\n pts: updatesState.pts,\r\n pts_count: 0\r\n });\r\n });\r\n\r\n const nextState = differenceResult._ === 'updates.difference' ? differenceResult.state : differenceResult.intermediate_state;\r\n updatesState.seq = nextState.seq;\r\n updatesState.pts = nextState.pts;\r\n updatesState.date = nextState.date;\r\n } else {\r\n updatesState.pts = differenceResult.pts;\r\n delete updatesState.seq;\r\n delete updatesState.date;\r\n }\r\n \r\n // this.log('apply diff', updatesState.seq, updatesState.pts)\r\n \r\n if(differenceResult._ === 'updates.differenceSlice') {\r\n return this.getDifference();\r\n } else {\r\n this.debug && this.log('finished get diff');\r\n }\r\n });\r\n\r\n if(!wasSyncing) {\r\n this.justAName(updatesState, promise);\r\n }\r\n \r\n return promise;\r\n }\r\n\r\n private getChannelDifference(channelId: number): Promise<void> {\r\n const channelState = this.getChannelState(channelId);\r\n const wasSyncing = channelState.syncLoading;\r\n if(!wasSyncing) {\r\n channelState.pendingPtsUpdates = [];\r\n }\r\n\r\n if(channelState.syncPending) {\r\n clearTimeout(channelState.syncPending.timeout);\r\n channelState.syncPending = null;\r\n }\r\n\r\n //this.log.trace('Get channel diff', appChatsManager.getChat(channelId), channelState.pts);\r\n const promise = apiManager.invokeApi('updates.getChannelDifference', {\r\n channel: appChatsManager.getChannelInput(channelId),\r\n filter: {_: 'channelMessagesFilterEmpty'},\r\n pts: channelState.pts,\r\n limit: 30\r\n }, {timeout: 0x7fffffff}).then((differenceResult) => {\r\n this.debug && this.log('Get channel diff result', differenceResult)\r\n channelState.pts = 'pts' in differenceResult ? differenceResult.pts : undefined;\r\n \r\n if(differenceResult._ === 'updates.channelDifferenceEmpty') {\r\n this.debug && this.log('apply channel empty diff', differenceResult);\r\n return;\r\n }\r\n \r\n if(differenceResult._ === 'updates.channelDifferenceTooLong') {\r\n this.debug && this.log('channel diff too long', differenceResult);\r\n delete this.channelStates[channelId];\r\n\r\n // @ts-ignore\r\n this.saveUpdate({_: 'updateChannelReload', channel_id: channelId});\r\n return;\r\n }\r\n \r\n appUsersManager.saveApiUsers(differenceResult.users);\r\n appChatsManager.saveApiChats(differenceResult.chats);\r\n \r\n // Should be first because of updateMessageID\r\n this.debug && this.log('applying', differenceResult.other_updates.length, 'channel other updates');\r\n differenceResult.other_updates.forEach((update) => {\r\n this.saveUpdate(update);\r\n });\r\n \r\n this.debug && this.log('applying', differenceResult.new_messages.length, 'channel new messages');\r\n differenceResult.new_messages.forEach((apiMessage) => {\r\n this.saveUpdate({\r\n _: 'updateNewChannelMessage',\r\n message: apiMessage,\r\n pts: channelState.pts,\r\n pts_count: 0\r\n });\r\n });\r\n \r\n this.debug && this.log('apply channel diff', channelState.pts);\r\n \r\n if(differenceResult._ === 'updates.channelDifference' &&\r\n !differenceResult.pFlags['final']) {\r\n return this.getChannelDifference(channelId);\r\n } else {\r\n this.debug && this.log('finished channel get diff');\r\n }\r\n });\r\n\r\n if(!wasSyncing) {\r\n this.justAName(channelState, promise, channelId);\r\n }\r\n\r\n return promise;\r\n }\r\n\r\n private justAName(state: UpdatesState, promise: UpdatesState['syncLoading'], channelId?: number) {\r\n state.syncLoading = promise;\r\n rootScope.broadcast('state_synchronizing', channelId);\r\n\r\n promise.then(() => {\r\n state.syncLoading = null;\r\n rootScope.broadcast('state_synchronized', channelId);\r\n }, () => {\r\n state.syncLoading = null;\r\n });\r\n }\r\n \r\n public addChannelState(channelId: number, pts: number) {\r\n if(!pts) {\r\n throw new Error('Add channel state without pts ' + channelId);\r\n }\r\n\r\n if(!(channelId in this.channelStates)) {\r\n this.channelStates[channelId] = {\r\n pts,\r\n pendingPtsUpdates: [],\r\n syncPending: null,\r\n syncLoading: null\r\n };\r\n\r\n return true;\r\n }\r\n\r\n return false;\r\n }\r\n \r\n private getChannelState(channelId: number, pts?: number) {\r\n if(this.channelStates[channelId] === undefined) {\r\n this.addChannelState(channelId, pts);\r\n }\r\n\r\n return this.channelStates[channelId];\r\n }\r\n\r\n private processUpdate(update: any, options: Partial<{\r\n date: number,\r\n seq: number,\r\n seqStart: number/* ,\r\n ignoreSyncLoading: boolean */\r\n }> = {}) {\r\n let channelId = 0;\r\n switch(update._) {\r\n case 'updateNewChannelMessage':\r\n case 'updateEditChannelMessage':\r\n channelId = -appPeersManager.getPeerId(update.message.peer_id);\r\n break;\r\n case 'updateDeleteChannelMessages':\r\n channelId = update.channel_id;\r\n break;\r\n case 'updateChannelTooLong':\r\n channelId = update.channel_id;\r\n if(!(channelId in this.channelStates)) {\r\n return false;\r\n }\r\n break;\r\n }\r\n \r\n const curState = channelId ? this.getChannelState(channelId, update.pts) : this.updatesState;\r\n \r\n // this.log.log('process', channelId, curState.pts, update)\r\n \r\n if(curState.syncLoading/* && !options.ignoreSyncLoading */) {\r\n return false;\r\n }\r\n \r\n if(update._ === 'updateChannelTooLong') {\r\n if(!curState.lastPtsUpdateTime ||\r\n curState.lastPtsUpdateTime < (Date.now() - SYNC_DELAY)) {\r\n // this.log.trace('channel too long, get diff', channelId, update)\r\n this.getChannelDifference(channelId);\r\n }\r\n return false;\r\n }\r\n \r\n if(update._ === 'updateNewMessage' ||\r\n update._ === 'updateEditMessage' ||\r\n update._ === 'updateNewChannelMessage' ||\r\n update._ === 'updateEditChannelMessage') {\r\n const message = update.message;\r\n const toPeerId = appPeersManager.getPeerId(message.peer_id);\r\n const fwdHeader = message.fwd_from || {};\r\n let reason: any = false;\r\n if(message.from_id && !appUsersManager.hasUser(appPeersManager.getPeerId(message.from_id), message.pFlags.post/* || channelId*/) && (reason = 'author') ||\r\n fwdHeader.from_id && !appUsersManager.hasUser(appPeersManager.getPeerId(fwdHeader.from_id), !!fwdHeader.channel_id) && (reason = 'fwdAuthor') ||\r\n fwdHeader.channel_id && !appChatsManager.hasChat(fwdHeader.channel_id, true) && (reason = 'fwdChannel') ||\r\n toPeerId > 0 && !appUsersManager.hasUser(toPeerId) && (reason = 'toPeer User') ||\r\n toPeerId < 0 && !appChatsManager.hasChat(-toPeerId) && (reason = 'toPeer Chat')) {\r\n this.log.warn('Not enough data for message update', toPeerId, reason, message)\r\n if(channelId && appChatsManager.hasChat(channelId)) {\r\n this.getChannelDifference(channelId);\r\n } else {\r\n this.forceGetDifference();\r\n }\r\n return false;\r\n }\r\n } else if(channelId && !appChatsManager.hasChat(channelId)) {\r\n // this.log.log('skip update, missing channel', channelId, update)\r\n return false;\r\n }\r\n \r\n let popPts: boolean;\r\n let popSeq: boolean;\r\n \r\n if(update.pts) {\r\n const newPts = curState.pts + (update.pts_count || 0);\r\n if(newPts < update.pts) {\r\n this.debug && this.log.warn('Pts hole', curState, update, channelId && appChatsManager.getChat(channelId));\r\n curState.pendingPtsUpdates.push(update);\r\n if(!curState.syncPending && !curState.syncLoading) {\r\n curState.syncPending = {\r\n timeout: window.setTimeout(() => {\r\n curState.syncPending = null;\r\n\r\n if(curState.syncLoading) {\r\n return;\r\n }\r\n\r\n if(channelId) {\r\n this.getChannelDifference(channelId);\r\n } else {\r\n this.getDifference();\r\n }\r\n }, SYNC_DELAY)\r\n };\r\n }\r\n\r\n curState.syncPending.ptsAwaiting = true;\r\n return false;\r\n }\r\n\r\n if(update.pts > curState.pts) {\r\n curState.pts = update.pts;\r\n popPts = true;\r\n \r\n curState.lastPtsUpdateTime = Date.now();\r\n } else if(update.pts_count) {\r\n // this.log.warn('Duplicate update', update)\r\n return false;\r\n }\r\n\r\n if(channelId && options.date && this.updatesState.date < options.date) {\r\n this.updatesState.date = options.date;\r\n }\r\n } else if(!channelId && options.seq > 0) {\r\n const seq = options.seq;\r\n const seqStart = options.seqStart || seq;\r\n \r\n if(seqStart !== curState.seq + 1) {\r\n if(seqStart > curState.seq) {\r\n this.debug && this.log.warn('Seq hole', curState, curState.syncPending && curState.syncPending.seqAwaiting);\r\n \r\n if(curState.pendingSeqUpdates[seqStart] === undefined) {\r\n curState.pendingSeqUpdates[seqStart] = {seq, date: options.date, updates: []};\r\n }\r\n curState.pendingSeqUpdates[seqStart].updates.push(update);\r\n \r\n if(!curState.syncPending) {\r\n curState.syncPending = {\r\n timeout: window.setTimeout(() => {\r\n curState.syncPending = null;\r\n\r\n if(curState.syncLoading) {\r\n return;\r\n }\r\n\r\n this.getDifference();\r\n }, SYNC_DELAY)\r\n };\r\n }\r\n\r\n if(!curState.syncPending.seqAwaiting ||\r\n curState.syncPending.seqAwaiting < seqStart) {\r\n curState.syncPending.seqAwaiting = seqStart;\r\n }\r\n return false;\r\n }\r\n }\r\n \r\n if(curState.seq !== seq) {\r\n curState.seq = seq;\r\n if(options.date && curState.date < options.date) {\r\n curState.date = options.date;\r\n }\r\n\r\n popSeq = true;\r\n }\r\n }\r\n \r\n this.saveUpdate(update);\r\n \r\n if(popPts) {\r\n this.popPendingPtsUpdate(channelId);\r\n } else if(popSeq) {\r\n this.popPendingSeqUpdate();\r\n }\r\n }\r\n\r\n public saveUpdate(update: Update) {\r\n rootScope.dispatchEvent(update._, update as any);\r\n }\r\n \r\n public attach() {\r\n if(this.attached) return;\r\n\r\n //return;\r\n\r\n this.log('attach');\r\n \r\n this.attached = true;\r\n\r\n appStateManager.getState().then(_state => {\r\n const state = _state.updates;\r\n\r\n //rootScope.broadcast('state_synchronizing');\r\n if(!state || !state.pts || !state.date || !state.seq) {\r\n this.log('will get new state');\r\n\r\n this.updatesState.syncLoading = new Promise((resolve) => {\r\n apiManager.invokeApi('updates.getState', {}, {noErrorBox: true}).then((stateResult) => {\r\n this.updatesState.seq = stateResult.seq;\r\n this.updatesState.pts = stateResult.pts;\r\n this.updatesState.date = stateResult.date;\r\n //setTimeout(() => {\r\n this.updatesState.syncLoading = null;\r\n resolve();\r\n //rootScope.broadcast('state_synchronized');\r\n //}, 1000);\r\n \r\n // ! for testing\r\n // updatesState.seq = 1\r\n // updatesState.pts = stateResult.pts - 5000\r\n // updatesState.date = 1\r\n // getDifference()\r\n });\r\n });\r\n } else {\r\n // ! for testing\r\n /* state.seq = 1;\r\n state.pts = state.pts - 15;\r\n state.date = 1; */\r\n\r\n Object.assign(this.updatesState, state);\r\n \r\n this.log('will get difference', copy(state));\r\n \r\n this.getDifference(true)/* .finally(() => {\r\n if(this.updatesState.syncLoading) {\r\n rootScope.broadcast('state_synchronizing');\r\n }\r\n }) */;\r\n }\r\n\r\n apiManager.setUpdatesProcessor(this.processUpdateMessage);\r\n\r\n this.updatesState.syncLoading.then(() => {\r\n // * false for test purposes\r\n /* false && */appStateManager.addEventListener('save', async() => {\r\n const us = this.updatesState;\r\n appStateManager.pushToState('updates', {\r\n seq: us.seq,\r\n pts: us.pts,\r\n date: us.date\r\n });\r\n });\r\n });\r\n });\r\n }\r\n}\r\n\r\nconst apiUpdatesManager = new ApiUpdatesManager();\r\nMOUNT_CLASS_TO.apiUpdatesManager = apiUpdatesManager;\r\nexport default apiUpdatesManager\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 const loadedURLs: {[url: string]: boolean} = {};\r\nconst set = (elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLVideoElement, url: string) => {\r\n if(elem instanceof HTMLImageElement || elem instanceof HTMLVideoElement) elem.src = url;\r\n else if(elem instanceof SVGImageElement) elem.setAttributeNS(null, 'href', url);\r\n else elem.style.backgroundImage = 'url(' + url + ')';\r\n};\r\n\r\n// проблема функции в том, что она не подходит для ссылок, пригодна только для blob'ов, потому что обычным ссылкам нужен 'load' каждый раз.\r\nexport default function renderImageFromUrl(elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLVideoElement, url: string, callback?: (err?: Event) => void, useCache = true): boolean {\r\n if(((loadedURLs[url]/* && false */) && useCache) || elem instanceof HTMLVideoElement) {\r\n if(elem) {\r\n set(elem, url);\r\n }\r\n \r\n callback && callback();\r\n return true;\r\n } else {\r\n const isImage = elem instanceof HTMLImageElement;\r\n const loader = isImage ? elem as HTMLImageElement : new Image();\r\n //const loader = new Image();\r\n loader.src = url;\r\n //let perf = performance.now();\r\n loader.addEventListener('load', () => {\r\n if(!isImage && elem) {\r\n set(elem, url);\r\n }\r\n\r\n loadedURLs[url] = true;\r\n //console.log('onload:', url, performance.now() - perf);\r\n if(callback) {\r\n // TODO: переделать прогрузки аватаров до начала анимации, иначе с этим ожиданием они неприятно появляются\r\n /* getHeavyAnimationPromise().then(() => {\r\n callback();\r\n }); */\r\n callback();\r\n }\r\n\r\n //callback && callback();\r\n });\r\n\r\n if(callback) {\r\n loader.addEventListener('error', callback);\r\n }\r\n\r\n return 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 rootScope from \"../rootScope\";\r\nimport apiManager from \"../mtproto/mtprotoworker\";\r\nimport { deferredPromise, CancellablePromise } from \"../../helpers/cancellablePromise\";\r\nimport type { DownloadOptions } from \"../mtproto/apiFileManager\";\r\nimport { InputFile } from \"../../layer\";\r\nimport referenceDatabase, {ReferenceBytes} from \"../mtproto/referenceDatabase\";\r\nimport type { ApiError } from \"../mtproto/apiManager\";\r\nimport { getFileNameByLocation } from \"../../helpers/fileName\";\r\nimport CacheStorageController from \"../cacheStorage\";\r\n\r\nexport type ResponseMethodBlob = 'blob';\r\nexport type ResponseMethodJson = 'json';\r\nexport type ResponseMethod = ResponseMethodBlob | ResponseMethodJson;\r\n\r\n/* export type DownloadBlob = {promise: Promise<Blob>, controller: AbortController};\r\nexport type DownloadJson = {promise: Promise<any>, controller: AbortController}; */\r\nexport type DownloadBlob = CancellablePromise<Blob>;\r\nexport type DownloadJson = CancellablePromise<any>;\r\n//export type Download = DownloadBlob/* | DownloadJson */;\r\nexport type Download = DownloadBlob/* | DownloadJson */;\r\n\r\nexport type Progress = {done: number, fileName: string, total: number, offset: number};\r\nexport type ProgressCallback = (details: Progress) => void;\r\n\r\nexport class AppDownloadManager {\r\n public cacheStorage = new CacheStorageController('cachedFiles');\r\n private downloads: {[fileName: string]: Download} = {};\r\n private progress: {[fileName: string]: Progress} = {};\r\n private progressCallbacks: {[fileName: string]: Array<ProgressCallback>} = {};\r\n\r\n private uploadId = 0;\r\n\r\n constructor() {\r\n rootScope.on('download_progress', (e) => {\r\n const details = e as {done: number, fileName: string, total: number, offset: number};\r\n this.progress[details.fileName] = details;\r\n\r\n const callbacks = this.progressCallbacks[details.fileName];\r\n if(callbacks) {\r\n callbacks.forEach(callback => callback(details));\r\n }\r\n\r\n const download = this.downloads[details.fileName];\r\n if(download) {\r\n download.notifyAll(details);\r\n }\r\n });\r\n }\r\n\r\n private getNewDeferred(fileName: string) {\r\n const deferred = deferredPromise<Blob>();\r\n\r\n deferred.cancel = () => {\r\n //try {\r\n const error = new Error('Download canceled');\r\n error.name = 'AbortError';\r\n \r\n apiManager.cancelDownload(fileName);\r\n \r\n deferred.reject(error);\r\n deferred.cancel = () => {};\r\n /* } catch(err) {\r\n\r\n } */\r\n };\r\n\r\n deferred.finally(() => {\r\n delete this.progress[fileName];\r\n delete this.progressCallbacks[fileName];\r\n });\r\n\r\n deferred.catch(() => {\r\n this.clearDownload(fileName);\r\n });\r\n\r\n return this.downloads[fileName] = deferred;\r\n }\r\n\r\n private clearDownload(fileName: string) {\r\n delete this.downloads[fileName];\r\n }\r\n\r\n public fakeDownload(fileName: string, value: Blob | string) {\r\n const deferred = this.getNewDeferred(fileName);\r\n if(typeof(value) === 'string') {\r\n fetch(value)\r\n .then(response => response.blob())\r\n .then(blob => deferred.resolve(blob));\r\n } else {\r\n deferred.resolve(value);\r\n }\r\n\r\n return deferred;\r\n }\r\n\r\n public download(options: DownloadOptions): DownloadBlob {\r\n const fileName = getFileNameByLocation(options.location, {fileName: options.fileName});\r\n if(this.downloads.hasOwnProperty(fileName)) return this.downloads[fileName];\r\n\r\n const deferred = this.getNewDeferred(fileName);\r\n\r\n const onError = (err: ApiError) => {\r\n switch(err.type) {\r\n case 'FILE_REFERENCE_EXPIRED': {\r\n // @ts-ignore\r\n const bytes: ReferenceBytes = options?.location?.file_reference;\r\n if(bytes) {\r\n referenceDatabase.refreshReference(bytes).then(tryDownload);\r\n /* referenceDatabase.refreshReference(bytes).then(() => {\r\n console.log('FILE_REFERENCE_EXPIRED: refreshed reference', bytes);\r\n }); */\r\n break;\r\n } else {\r\n console.warn('FILE_REFERENCE_EXPIRED: no context for bytes:', bytes);\r\n }\r\n }\r\n\r\n default:\r\n deferred.reject(err);\r\n break;\r\n }\r\n };\r\n\r\n const tryDownload = (): Promise<unknown> => {\r\n //return Promise.resolve();\r\n\r\n if(!apiManager.worker || options.onlyCache) {\r\n const promise = this.cacheStorage.getFile(fileName).then((blob) => {\r\n if(blob.size < options.size) throw 'wrong size';\r\n else deferred.resolve(blob);\r\n });\r\n \r\n if(options.onlyCache) return promise.catch(onError);\r\n return promise.catch(() => {\r\n return apiManager.downloadFile(options).then(deferred.resolve, onError);\r\n });\r\n } else {\r\n /* return apiManager.downloadFile(options).then(res => {\r\n setTimeout(() => deferred.resolve(res), 5e3);\r\n }, onError); */\r\n\r\n return apiManager.downloadFile(options).then(deferred.resolve, onError);\r\n }\r\n };\r\n\r\n tryDownload();\r\n\r\n //console.log('Will download file:', fileName, url);\r\n return deferred;\r\n }\r\n\r\n public upload(file: File | Blob, fileName?: string) {\r\n if(!fileName) {\r\n const mimeType = file?.type;\r\n if(mimeType) { // the same like apiFileName in appMessagesManager for upload!\r\n const ext = this.uploadId++ + '.' + mimeType.split('/')[1];\r\n \r\n if(['image/jpeg', 'image/png', 'image/bmp'].indexOf(mimeType) >= 0) {\r\n fileName = 'photo' + ext;\r\n } else if(mimeType.indexOf('audio/') === 0 || ['video/ogg'].indexOf(mimeType) >= 0) {\r\n fileName = 'audio' + ext;\r\n } else if(mimeType.indexOf('video/') === 0) {\r\n fileName = 'video' + ext;\r\n } else {\r\n fileName = 'document' + ext;\r\n }\r\n \r\n } else {\r\n fileName = 'upload-' + this.uploadId++;\r\n }\r\n }\r\n\r\n const deferred = this.getNewDeferred(fileName);\r\n apiManager.uploadFile({file, fileName}).then(deferred.resolve, deferred.reject);\r\n\r\n deferred.finally(() => {\r\n this.clearDownload(fileName);\r\n });\r\n\r\n return deferred as any as CancellablePromise<InputFile>;\r\n }\r\n\r\n public getDownload(fileName: string) {\r\n return this.downloads[fileName];\r\n }\r\n\r\n public addProgressCallback(fileName: string, callback: ProgressCallback) {\r\n const progress = this.progress[fileName];\r\n (this.progressCallbacks[fileName] ?? (this.progressCallbacks[fileName] = [])).push(callback);\r\n\r\n if(progress) {\r\n callback(progress);\r\n }\r\n }\r\n\r\n public createDownloadAnchor(url: string, fileName: string, onRemove?: () => void) {\r\n const a = document.createElement('a');\r\n a.href = url;\r\n a.download = fileName;\r\n a.target = '_blank';\r\n \r\n a.style.position = 'absolute';\r\n a.style.top = '1px';\r\n a.style.left = '1px';\r\n \r\n document.body.append(a);\r\n \r\n try {\r\n var clickEvent = document.createEvent('MouseEvents');\r\n clickEvent.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);\r\n a.dispatchEvent(clickEvent);\r\n } catch (e) {\r\n console.error('Download click error', e);\r\n try {\r\n a.click();\r\n } catch (e) {\r\n window.open(url as string, '_blank');\r\n }\r\n }\r\n \r\n setTimeout(() => {\r\n a.remove();\r\n onRemove && onRemove();\r\n }, 100);\r\n }\r\n\r\n /* public downloadToDisc(fileName: string, url: string) {\r\n this.createDownloadAnchor(url);\r\n \r\n return this.download(fileName, url);\r\n } */\r\n\r\n public downloadToDisc(options: DownloadOptions, discFileName: string) {\r\n const download = this.download(options);\r\n download/* .promise */.then(blob => {\r\n const objectURL = URL.createObjectURL(blob);\r\n this.createDownloadAnchor(objectURL, discFileName, () => {\r\n URL.revokeObjectURL(objectURL);\r\n });\r\n });\r\n \r\n return download;\r\n }\r\n}\r\n\r\nexport default new AppDownloadManager();\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\ntype TargetType = HTMLElement;\r\nexport type OnVisibilityChange = (target: TargetType, visible: boolean) => void;\r\n\r\nexport default class VisibilityIntersector {\r\n private observer: IntersectionObserver;\r\n private items: Map<TargetType, boolean> = new Map();\r\n private locked = false;\r\n\r\n constructor(onVisibilityChange: OnVisibilityChange) {\r\n this.observer = new IntersectionObserver((entries) => {\r\n if(this.locked) {\r\n return;\r\n }\r\n\r\n const changed: {target: TargetType, visible: boolean}[] = [];\r\n\r\n entries.forEach(entry => {\r\n const target = entry.target as TargetType;\r\n\r\n if(this.items.get(target) === entry.isIntersecting) {\r\n return;\r\n } else {\r\n this.items.set(target, entry.isIntersecting);\r\n }\r\n\r\n /* if(entry.isIntersecting) {\r\n console.log('ooo', entry);\r\n } */\r\n\r\n /* if(this.locked) {\r\n return;\r\n } */\r\n\r\n changed[entry.isIntersecting ? 'unshift' : 'push']({target, visible: entry.isIntersecting});\r\n\r\n //onVisibilityChange(target, entry.isIntersecting);\r\n });\r\n\r\n changed.forEach(smth => {\r\n onVisibilityChange(smth.target, smth.visible);\r\n });\r\n });\r\n }\r\n\r\n public getVisible() {\r\n const items: TargetType[] = [];\r\n this.items.forEach((value, key) => {\r\n if(value) {\r\n items.push(key);\r\n }\r\n });\r\n\r\n return items;\r\n }\r\n\r\n public clearVisible() {\r\n const visible = this.getVisible();\r\n for(const target of visible) {\r\n this.items.set(target, false);\r\n }\r\n }\r\n\r\n public isVisible(target: TargetType) {\r\n return this.items.get(target);\r\n }\r\n\r\n public disconnect() {\r\n this.observer.disconnect();\r\n this.items.clear();\r\n }\r\n\r\n public refresh() {\r\n this.observer.disconnect();\r\n\r\n //window.requestAnimationFrame(() => {\r\n const targets = [...this.items.keys()];\r\n for(const target of targets) {\r\n //this.items.set(target, false);\r\n this.observer.observe(target);\r\n }\r\n //});\r\n }\r\n\r\n public refreshVisible() {\r\n const visible = this.getVisible();\r\n for(const target of visible) {\r\n this.observer.unobserve(target);\r\n }\r\n\r\n for(const target of visible) {\r\n this.observer.observe(target);\r\n }\r\n }\r\n\r\n public observe(target: TargetType) {\r\n this.items.set(target, false);\r\n this.observer.observe(target);\r\n }\r\n\r\n public unobserve(target: TargetType) {\r\n this.observer.unobserve(target);\r\n this.items.delete(target);\r\n }\r\n\r\n public unlock() {\r\n this.locked = false;\r\n }\r\n\r\n public unlockAndRefresh() {\r\n this.unlock();\r\n this.refresh();\r\n }\r\n\r\n public lock() {\r\n this.locked = true;\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 { throttle } from \"../helpers/schedulers\";\r\nimport { logger, LogLevels } from \"../lib/logger\";\r\nimport VisibilityIntersector, { OnVisibilityChange } from \"./visibilityIntersector\";\r\nimport { findAndSpliceAll } from \"../helpers/array\";\r\n\r\ntype LazyLoadElementBase = {\r\n load: () => Promise<any>\r\n};\r\n\r\ntype LazyLoadElement = Omit<LazyLoadElementBase, 'load'> & {\r\n load: (target?: HTMLElement) => Promise<any>,\r\n div: HTMLElement\r\n wasSeen?: boolean,\r\n};\r\n\r\nconst PARALLEL_LIMIT = 8;\r\n\r\nexport class LazyLoadQueueBase {\r\n public queueId = 0;\r\n protected queue: Array<LazyLoadElementBase> = [];\r\n protected inProcess: Set<LazyLoadElementBase> = new Set();\r\n\r\n protected lockPromise: Promise<void> = null;\r\n protected unlockResolve: () => void = null;\r\n\r\n protected log = logger('LL', LogLevels.error);\r\n protected processQueue: () => void;\r\n\r\n constructor(protected parallelLimit = PARALLEL_LIMIT) {\r\n this.processQueue = throttle(() => this._processQueue(), 20, false);\r\n }\r\n\r\n public clear() {\r\n this.inProcess.clear(); // ацтеки забьются, будет плохо\r\n\r\n this.queue.length = 0;\r\n // unreachable code\r\n /* for(let item of this.inProcess) { \r\n this.lazyLoadMedia.push(item);\r\n } */\r\n }\r\n\r\n public lock() {\r\n if(this.lockPromise) return;\r\n\r\n //const perf = performance.now();\r\n this.lockPromise = new Promise((resolve, reject) => {\r\n this.unlockResolve = resolve;\r\n });\r\n\r\n /* if(DEBUG) {\r\n this.lockPromise.then(() => {\r\n this.log('was locked for:', performance.now() - perf);\r\n });\r\n } */\r\n }\r\n\r\n public unlock() {\r\n if(!this.unlockResolve) return;\r\n\r\n this.unlockResolve();\r\n this.unlockResolve = this.lockPromise = null;\r\n\r\n this.processQueue();\r\n }\r\n\r\n protected async processItem(item: LazyLoadElementBase) {\r\n if(this.lockPromise) {\r\n return;\r\n }\r\n\r\n this.inProcess.add(item);\r\n\r\n /* if(DEBUG) {\r\n this.log('will load media', this.lockPromise, item);\r\n } */\r\n\r\n try {\r\n //await new Promise((resolve) => setTimeout(resolve, 2e3));\r\n //await new Promise((resolve, reject) => window.requestAnimationFrame(() => window.requestAnimationFrame(resolve)));\r\n //await item.load(item.div);\r\n await this.loadItem(item);\r\n } catch(err) {\r\n if(!['NO_ENTRY_FOUND', 'STORAGE_OFFLINE'].includes(err)) {\r\n this.log.error('loadMediaQueue error:', err/* , item */);\r\n }\r\n }\r\n\r\n this.inProcess.delete(item);\r\n\r\n /* if(DEBUG) {\r\n this.log('loaded media', item);\r\n } */\r\n\r\n this.processQueue();\r\n }\r\n\r\n protected loadItem(item: LazyLoadElementBase) {\r\n return item.load();\r\n }\r\n\r\n protected getItem() {\r\n return this.queue.shift();\r\n }\r\n\r\n protected addElement(method: 'push' | 'unshift', el: LazyLoadElementBase) {\r\n this.queue[method](el);\r\n this.processQueue();\r\n }\r\n\r\n protected _processQueue(item?: LazyLoadElementBase) {\r\n if(!this.queue.length || this.lockPromise || (this.parallelLimit > 0 && this.inProcess.size >= this.parallelLimit)) return;\r\n\r\n //console.log('_processQueue start');\r\n let added = 0;\r\n do {\r\n if(item) {\r\n this.queue.findAndSplice(i => i === item);\r\n } else {\r\n item = this.getItem();\r\n }\r\n \r\n if(item) {\r\n this.processItem(item);\r\n } else {\r\n break;\r\n }\r\n\r\n item = null;\r\n ++added;\r\n } while(this.inProcess.size < this.parallelLimit && this.queue.length);\r\n //console.log('_processQueue end, added', added, this.queue.length);\r\n }\r\n\r\n public push(el: LazyLoadElementBase) {\r\n this.addElement('push', el);\r\n }\r\n\r\n public unshift(el: LazyLoadElementBase) {\r\n this.addElement('unshift', el);\r\n }\r\n}\r\n\r\nexport class LazyLoadQueueIntersector extends LazyLoadQueueBase {\r\n protected queue: Array<LazyLoadElement> = [];\r\n protected inProcess: Set<LazyLoadElement> = new Set();\r\n\r\n public intersector: VisibilityIntersector;\r\n protected intersectorTimeout: number;\r\n\r\n constructor(protected parallelLimit = PARALLEL_LIMIT) {\r\n super(parallelLimit);\r\n }\r\n\r\n public lock() {\r\n super.lock();\r\n this.intersector.lock();\r\n }\r\n\r\n public unlock() {\r\n super.unlock();\r\n this.intersector.unlock();\r\n }\r\n\r\n public unlockAndRefresh() {\r\n super.unlock();\r\n this.intersector.unlockAndRefresh();\r\n }\r\n\r\n public clear() {\r\n super.clear();\r\n this.intersector.disconnect();\r\n }\r\n\r\n public refresh() {\r\n this.intersector.refresh();\r\n }\r\n\r\n protected loadItem(item: LazyLoadElement) {\r\n return item.load(item.div);\r\n }\r\n\r\n protected addElement(method: 'push' | 'unshift', el: LazyLoadElement) {\r\n const item = this.queue.find(i => i.div === el.div && i.load === el.load);\r\n if(item) {\r\n return false;\r\n } else {\r\n for(const item of this.inProcess) {\r\n if(item.div === el.div && item.load === el.load) {\r\n return false;\r\n }\r\n }\r\n }\r\n\r\n this.queue[method](el);\r\n return true;\r\n }\r\n\r\n protected setProcessQueueTimeout() {\r\n if(!this.intersectorTimeout) {\r\n this.intersectorTimeout = window.setTimeout(() => {\r\n this.intersectorTimeout = 0;\r\n this.processQueue();\r\n }, 0);\r\n }\r\n }\r\n\r\n public push(el: LazyLoadElement) {\r\n super.push(el);\r\n }\r\n\r\n public unshift(el: LazyLoadElement) {\r\n super.unshift(el);\r\n }\r\n\r\n public unobserve(el: HTMLElement) {\r\n findAndSpliceAll(this.queue, (i) => i.div === el);\r\n\r\n this.intersector.unobserve(el);\r\n }\r\n}\r\n\r\nexport default class LazyLoadQueue extends LazyLoadQueueIntersector {\r\n constructor(protected parallelLimit = PARALLEL_LIMIT) {\r\n super(parallelLimit);\r\n\r\n this.intersector = new VisibilityIntersector(this.onVisibilityChange);\r\n }\r\n\r\n private onVisibilityChange = (target: HTMLElement, visible: boolean) => {\r\n if(visible) {\r\n /* if(DEBUG) {\r\n this.log('isIntersecting', target);\r\n } */\r\n\r\n // need for set element first if scrolled\r\n findAndSpliceAll(this.queue, (i) => i.div === target).forEach(item => {\r\n item.wasSeen = true;\r\n this.queue.unshift(item);\r\n //this.processQueue(item);\r\n });\r\n\r\n this.setProcessQueueTimeout();\r\n }\r\n };\r\n\r\n protected getItem() {\r\n return this.queue.findAndSplice(item => item.wasSeen);\r\n }\r\n\r\n public async processItem(item: LazyLoadElement) {\r\n await super.processItem(item);\r\n this.intersector.unobserve(item.div);\r\n }\r\n\r\n protected addElement(method: 'push' | 'unshift', el: LazyLoadElement) {\r\n const inserted = super.addElement(method, el);\r\n\r\n if(!inserted) return false;\r\n\r\n this.intersector.observe(el.div);\r\n /* if(el.wasSeen) {\r\n this.processQueue(el);\r\n } else */if(!el.hasOwnProperty('wasSeen')) {\r\n el.wasSeen = false;\r\n }\r\n \r\n return true;\r\n }\r\n}\r\n\r\nexport class LazyLoadQueueRepeat extends LazyLoadQueueIntersector {\r\n private _queue: Map<HTMLElement, LazyLoadElement> = new Map();\r\n\r\n constructor(protected parallelLimit = PARALLEL_LIMIT, protected onVisibilityChange?: OnVisibilityChange) {\r\n super(parallelLimit);\r\n\r\n this.intersector = new VisibilityIntersector((target, visible) => {\r\n const spliced = findAndSpliceAll(this.queue, (i) => i.div === target);\r\n if(visible) {\r\n const items = spliced.length ? spliced : [this._queue.get(target)];\r\n items.forEach(item => {\r\n this.queue.unshift(item || this._queue.get(target));\r\n });\r\n }\r\n \r\n this.onVisibilityChange && this.onVisibilityChange(target, visible);\r\n this.setProcessQueueTimeout();\r\n });\r\n }\r\n\r\n public clear() {\r\n super.clear();\r\n this._queue.clear();\r\n }\r\n\r\n /* public async processItem(item: LazyLoadElement) {\r\n //await super.processItem(item);\r\n await LazyLoadQueueBase.prototype.processItem.call(this, item);\r\n\r\n if(this.lazyLoadMedia.length) {\r\n this.processQueue();\r\n }\r\n } */\r\n\r\n public observe(el: LazyLoadElement) {\r\n this._queue.set(el.div, el);\r\n this.intersector.observe(el.div);\r\n }\r\n}\r\n\r\nexport class LazyLoadQueueRepeat2 extends LazyLoadQueueIntersector {\r\n constructor(protected parallelLimit = PARALLEL_LIMIT, protected onVisibilityChange?: OnVisibilityChange) {\r\n super(parallelLimit);\r\n\r\n this.intersector = new VisibilityIntersector((target, visible) => {\r\n const spliced = findAndSpliceAll(this.queue, (i) => i.div === target);\r\n if(visible && spliced.length) {\r\n spliced.forEach(item => {\r\n this.queue.unshift(item);\r\n });\r\n }\r\n \r\n this.onVisibilityChange && this.onVisibilityChange(target, visible);\r\n this.setProcessQueueTimeout();\r\n });\r\n }\r\n\r\n public observe(el: HTMLElement) {\r\n this.intersector.observe(el);\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 { fontFamily } from \"../../components/middleEllipsis\";\r\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\r\nimport { CancellablePromise, deferredPromise } from \"../../helpers/cancellablePromise\";\r\nimport { tsNow } from \"../../helpers/date\";\r\nimport { deepEqual } from \"../../helpers/object\";\r\nimport { convertInputKeyToKey } from \"../../helpers/string\";\r\nimport { isMobile } from \"../../helpers/userAgent\";\r\nimport { InputNotifyPeer, InputPeerNotifySettings, NotifyPeer, PeerNotifySettings, Update } from \"../../layer\";\r\nimport I18n from \"../langPack\";\r\nimport apiManager from \"../mtproto/mtprotoworker\";\r\nimport rootScope from \"../rootScope\";\r\nimport sessionStorage from \"../sessionStorage\";\r\nimport apiUpdatesManager from \"./apiUpdatesManager\";\r\nimport appPeersManager from \"./appPeersManager\";\r\nimport appStateManager from \"./appStateManager\";\r\n\r\ntype MyNotification = Notification & {\r\n hidden?: boolean,\r\n show?: () => void,\r\n};\r\n\r\nexport type NotifyOptions = Partial<{\r\n tag: string;\r\n image: string;\r\n key: string;\r\n title: string;\r\n message: string;\r\n silent: boolean;\r\n onclick: () => void;\r\n}>;\r\n\r\ntype ImSadAboutIt = Promise<PeerNotifySettings> | PeerNotifySettings;\r\nexport class AppNotificationsManager {\r\n private notificationsUiSupport: boolean;\r\n private notificationsShown: {[key: string]: MyNotification} = {};\r\n private notificationIndex = 0;\r\n private notificationsCount = 0;\r\n private soundsPlayed: {[tag: string]: number} = {};\r\n private vibrateSupport = !!navigator.vibrate;\r\n private nextSoundAt: number;\r\n private prevSoundVolume: number;\r\n private peerSettings = {\r\n notifyPeer: {} as {[peerId: number]: ImSadAboutIt},\r\n notifyUsers: null as ImSadAboutIt,\r\n notifyChats: null as ImSadAboutIt,\r\n notifyBroadcasts: null as ImSadAboutIt\r\n };\r\n //private exceptions: {[peerId: string]: PeerNotifySettings} = {};\r\n private notifyContactsSignUp: Promise<boolean>;\r\n private faviconEl: HTMLLinkElement = document.head.querySelector('link[rel=\"icon\"]');\r\n\r\n private titleBackup = document.title;\r\n private titleChanged = false;\r\n private titleInterval: number;\r\n private prevFavicon: string;\r\n private stopped = false;\r\n\r\n private settings: Partial<{\r\n nodesktop: boolean,\r\n volume: number,\r\n novibrate: boolean,\r\n nopreview: boolean,\r\n nopush: boolean,\r\n nosound: boolean,\r\n }> = {};\r\n\r\n private registeredDevice: any;\r\n private pushInited = false;\r\n\r\n private topMessagesDeferred: CancellablePromise<void>;\r\n\r\n private notifySoundEl: HTMLElement;\r\n\r\n private getNotifyPeerTypePromise: Promise<any>;\r\n\r\n constructor() {\r\n // @ts-ignore\r\n navigator.vibrate = navigator.vibrate || navigator.mozVibrate || navigator.webkitVibrate;\r\n\r\n this.notificationsUiSupport = ('Notification' in window) || ('mozNotification' in navigator);\r\n\r\n this.topMessagesDeferred = deferredPromise<void>();\r\n\r\n this.notifySoundEl = document.createElement('div');\r\n this.notifySoundEl.id = 'notify-sound';\r\n document.body.append(this.notifySoundEl);\r\n\r\n /* rootScope.on('idle.deactivated', (newVal) => {\r\n if(newVal) {\r\n stop();\r\n }\r\n });*/\r\n\r\n rootScope.on('idle', (newVal) => {\r\n if(this.stopped) {\r\n return;\r\n }\r\n\r\n if(!newVal) {\r\n this.clear();\r\n }\r\n\r\n this.toggleToggler();\r\n });\r\n\r\n rootScope.addMultipleEventsListeners({\r\n updateNotifySettings: (update) => {\r\n this.savePeerSettings(update.peer._ === 'notifyPeer' ? appPeersManager.getPeerId(update.peer.peer) : update.peer._, update.notify_settings);\r\n rootScope.broadcast('notify_settings', update);\r\n }\r\n });\r\n\r\n /* rootScope.on('push_init', (tokenData) => {\r\n this.pushInited = true\r\n if(!this.settings.nodesktop && !this.settings.nopush) {\r\n if(tokenData) {\r\n this.registerDevice(tokenData);\r\n } else {\r\n WebPushApiManager.subscribe();\r\n }\r\n } else {\r\n this.unregisterDevice(tokenData);\r\n }\r\n });\r\n rootScope.on('push_subscribe', (tokenData) => {\r\n this.registerDevice(tokenData);\r\n });\r\n rootScope.on('push_unsubscribe', (tokenData) => {\r\n this.unregisterDevice(tokenData);\r\n }); */\r\n\r\n rootScope.addEventListener('dialogs_multiupdate', () => {\r\n //unregisterTopMsgs()\r\n this.topMessagesDeferred.resolve();\r\n }, true);\r\n\r\n /* rootScope.on('push_notification_click', (notificationData) => {\r\n if(notificationData.action === 'push_settings') {\r\n this.topMessagesDeferred.then(() => {\r\n $modal.open({\r\n templateUrl: templateUrl('settings_modal'),\r\n controller: 'SettingsModalController',\r\n windowClass: 'settings_modal_window mobile_modal',\r\n backdrop: 'single'\r\n })\r\n });\r\n return;\r\n }\r\n\r\n if(notificationData.action === 'mute1d') {\r\n apiManager.invokeApi('account.updateDeviceLocked', {\r\n period: 86400\r\n }).then(() => {\r\n // var toastData = toaster.pop({\r\n // type: 'info',\r\n // body: _('push_action_mute1d_success'),\r\n // bodyOutputType: 'trustedHtml',\r\n // clickHandler: () => {\r\n // toaster.clear(toastData)\r\n // },\r\n // showCloseButton: false\r\n // })\r\n });\r\n\r\n return;\r\n }\r\n\r\n const peerId = notificationData.custom && notificationData.custom.peerId;\r\n console.log('click', notificationData, peerId);\r\n if(peerId) {\r\n this.topMessagesDeferred.then(() => {\r\n if(notificationData.custom.channel_id &&\r\n !appChatsManager.hasChat(notificationData.custom.channel_id)) {\r\n return;\r\n }\r\n\r\n if(peerId > 0 && !appUsersManager.hasUser(peerId)) {\r\n return;\r\n }\r\n\r\n // rootScope.broadcast('history_focus', {\r\n // peerString: appPeersManager.getPeerString(peerId)\r\n // });\r\n });\r\n }\r\n }); */\r\n }\r\n\r\n private toggleToggler(enable = rootScope.idle.isIDLE) {\r\n if(isMobile) return;\r\n\r\n const resetTitle = () => {\r\n this.titleChanged = false;\r\n document.title = this.titleBackup;\r\n this.setFavicon();\r\n };\r\n\r\n window.clearInterval(this.titleInterval);\r\n this.titleInterval = 0;\r\n\r\n if(!enable) {\r\n resetTitle();\r\n } else {\r\n this.titleInterval = window.setInterval(() => {\r\n if(!this.notificationsCount) {\r\n this.toggleToggler(false);\r\n } else if(this.titleChanged) {\r\n resetTitle();\r\n } else {\r\n this.titleChanged = true;\r\n document.title = I18n.format('Notifications.Count', true, [this.notificationsCount]);\r\n //this.setFavicon('assets/img/favicon_unread.ico');\r\n\r\n // fetch('assets/img/favicon.ico')\r\n // .then(res => res.blob())\r\n // .then(blob => {\r\n // const img = document.createElement('img');\r\n // img.src = URL.createObjectURL(blob);\r\n\r\n const canvas = document.createElement('canvas');\r\n canvas.width = 32 * window.devicePixelRatio;\r\n canvas.height = canvas.width;\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, 2 * Math.PI, false);\r\n ctx.fillStyle = '#3390ec';\r\n ctx.fill();\r\n\r\n let fontSize = 24;\r\n let str = '' + this.notificationsCount;\r\n if(this.notificationsCount < 10) {\r\n fontSize = 22;\r\n } else if(this.notificationsCount < 100) {\r\n fontSize = 20;\r\n } else {\r\n str = '99+';\r\n fontSize = 16;\r\n }\r\n\r\n fontSize *= window.devicePixelRatio;\r\n \r\n ctx.font = `700 ${fontSize}px ${fontFamily}`;\r\n ctx.textBaseline = 'middle';\r\n ctx.textAlign = 'center';\r\n ctx.fillStyle = 'white';\r\n ctx.fillText(str, canvas.width / 2, canvas.height * .5625);\r\n\r\n /* const ctx = canvas.getContext('2d');\r\n ctx.drawImage(img, 0, 0, canvas.width, canvas.height); */\r\n \r\n this.setFavicon(canvas.toDataURL());\r\n // });\r\n }\r\n }, 1000);\r\n }\r\n }\r\n\r\n public updateLocalSettings = () => {\r\n Promise.all(['notify_nodesktop', 'notify_volume', 'notify_novibrate', 'notify_nopreview', 'notify_nopush'].map(k => sessionStorage.get(k as any)))\r\n .then((updSettings) => {\r\n this.settings.nodesktop = updSettings[0];\r\n this.settings.volume = updSettings[1] === undefined ? 0.5 : updSettings[1];\r\n this.settings.novibrate = updSettings[2];\r\n this.settings.nopreview = updSettings[3];\r\n this.settings.nopush = updSettings[4];\r\n\r\n /* if(this.pushInited) {\r\n const needPush = !this.settings.nopush && !this.settings.nodesktop && WebPushApiManager.isAvailable || false;\r\n const hasPush = this.registeredDevice !== false;\r\n if(needPush !== hasPush) {\r\n if(needPush) {\r\n WebPushApiManager.subscribe();\r\n } else {\r\n WebPushApiManager.unsubscribe();\r\n }\r\n }\r\n }\r\n\r\n WebPushApiManager.setSettings(this.settings); */\r\n });\r\n\r\n appStateManager.getState().then(state => {\r\n this.settings.nosound = !state.settings.notifications.sound;\r\n });\r\n }\r\n\r\n public getLocalSettings() {\r\n return this.settings;\r\n }\r\n\r\n public getNotifySettings(peer: InputNotifyPeer): ImSadAboutIt {\r\n let key: any = convertInputKeyToKey(peer._);\r\n let obj: any = this.peerSettings[key as NotifyPeer['_']];\r\n\r\n if(peer._ === 'inputNotifyPeer') {\r\n key = appPeersManager.getPeerId(peer.peer);\r\n obj = obj[key];\r\n }\r\n\r\n if(obj) {\r\n return obj;\r\n }\r\n\r\n return (obj || this.peerSettings)[key] = apiManager.invokeApi('account.getNotifySettings', {peer})\r\n .then(settings => {\r\n this.savePeerSettings(key, settings);\r\n return settings;\r\n });\r\n }\r\n\r\n public getNotifyPeerTypeSettings() {\r\n if(this.getNotifyPeerTypePromise) return this.getNotifyPeerTypePromise;\r\n\r\n const promises = (['inputNotifyBroadcasts', 'inputNotifyUsers', 'inputNotifyChats'] as Exclude<InputNotifyPeer['_'], 'inputNotifyPeer'>[])\r\n .map((inputKey) => {\r\n return this.getNotifySettings({_: inputKey});\r\n });\r\n\r\n return this.getNotifyPeerTypePromise = Promise.all(promises);\r\n }\r\n\r\n public updateNotifySettings(peer: InputNotifyPeer, settings: InputPeerNotifySettings) {\r\n //this.savePeerSettings(peerId, settings);\r\n\r\n /* const inputSettings: InputPeerNotifySettings = copy(settings) as any;\r\n inputSettings._ = 'inputPeerNotifySettings'; */\r\n\r\n return apiManager.invokeApi('account.updateNotifySettings', {\r\n peer,\r\n settings\r\n }).then(value => {\r\n if(value) {\r\n apiUpdatesManager.processUpdateMessage({\r\n _: 'updateShort',\r\n update: {\r\n _: 'updateNotifySettings', \r\n peer: {\r\n ...peer,\r\n _: convertInputKeyToKey(peer._)\r\n }, \r\n notify_settings: { // ! WOW, IT WORKS !\r\n ...settings,\r\n _: 'peerNotifySettings',\r\n }\r\n } as Update.updateNotifySettings\r\n });\r\n }\r\n });\r\n }\r\n\r\n public getNotifyExceptions() {\r\n apiManager.invokeApi('account.getNotifyExceptions', {compare_sound: true})\r\n .then((updates) => {\r\n apiUpdatesManager.processUpdateMessage(updates);\r\n });\r\n }\r\n\r\n public getContactSignUpNotification() {\r\n if(this.notifyContactsSignUp) return this.notifyContactsSignUp;\r\n return this.notifyContactsSignUp = apiManager.invokeApi('account.getContactSignUpNotification');\r\n }\r\n\r\n public setContactSignUpNotification(silent: boolean) {\r\n apiManager.invokeApi('account.setContactSignUpNotification', {silent})\r\n .then(value => {\r\n this.notifyContactsSignUp = Promise.resolve(!silent);\r\n });\r\n }\r\n\r\n private setFavicon(href: string = 'assets/img/favicon.ico') {\r\n if(this.prevFavicon === href) {\r\n return;\r\n }\r\n\r\n const link = this.faviconEl.cloneNode() as HTMLLinkElement;\r\n link.href = href;\r\n this.faviconEl.parentNode.replaceChild(link, this.faviconEl);\r\n this.faviconEl = link;\r\n\r\n this.prevFavicon = href;\r\n }\r\n\r\n public savePeerSettings(key: number | Exclude<NotifyPeer['_'], 'notifyPeer'>, settings: PeerNotifySettings) {\r\n let obj: any;\r\n if(typeof(key) === 'number') {\r\n obj = this.peerSettings['notifyPeer'];\r\n }\r\n \r\n (obj || this.peerSettings)[key] = settings;\r\n\r\n if(typeof(key) !== 'number') {\r\n rootScope.broadcast('notify_peer_type_settings', {key, settings});\r\n }\r\n\r\n //rootScope.broadcast('notify_settings', {peerId: peerId});\r\n }\r\n\r\n public isMuted(peerNotifySettings: PeerNotifySettings) {\r\n return peerNotifySettings._ === 'peerNotifySettings' &&\r\n (peerNotifySettings.mute_until * 1000) > tsNow();\r\n }\r\n\r\n public getPeerMuted(peerId: number) {\r\n const ret = this.getNotifySettings({_: 'inputNotifyPeer', peer: appPeersManager.getInputPeerById(peerId)});\r\n return (ret instanceof Promise ? ret : Promise.resolve(ret))\r\n .then((peerNotifySettings) => this.isMuted(peerNotifySettings));\r\n }\r\n\r\n public getPeerLocalSettings(peerId: number, respectType = true): PeerNotifySettings {\r\n const n: PeerNotifySettings = {\r\n _: 'peerNotifySettings'\r\n };\r\n\r\n const notifySettings = this.peerSettings['notifyPeer'][peerId];\r\n //if(!notifySettings || (notifySettings instanceof Promise)) return false;\r\n if(notifySettings && !(notifySettings instanceof Promise)) {\r\n Object.assign(n, notifySettings);\r\n }\r\n\r\n if(respectType) {\r\n const inputNotify = appPeersManager.getInputNotifyPeerById(peerId, true);\r\n const key = convertInputKeyToKey(inputNotify._);\r\n const typeNotifySettings = this.peerSettings[key as NotifyPeer['_']];\r\n if(typeNotifySettings && !(typeNotifySettings instanceof Promise)) {\r\n for(let i in typeNotifySettings) {\r\n // @ts-ignore\r\n if(n[i] === undefined) {\r\n // @ts-ignore\r\n n[i] = typeNotifySettings[i];\r\n }\r\n }\r\n }\r\n }\r\n\r\n return n;\r\n }\r\n\r\n public isPeerLocalMuted(peerId: number, respectType = true) {\r\n if(peerId === rootScope.myId) return false;\r\n\r\n const notifySettings = this.getPeerLocalSettings(peerId, respectType);\r\n return this.isMuted(notifySettings);\r\n }\r\n\r\n public start() {\r\n this.updateLocalSettings();\r\n rootScope.on('settings_updated', this.updateLocalSettings);\r\n //WebPushApiManager.start();\r\n\r\n if(!this.notificationsUiSupport) {\r\n return false;\r\n }\r\n\r\n if('Notification' in window && Notification.permission !== 'granted' && Notification.permission !== 'denied') {\r\n window.addEventListener('click', this.requestPermission);\r\n }\r\n\r\n try {\r\n if('onbeforeunload' in window) {\r\n window.addEventListener('beforeunload', this.clear);\r\n }\r\n } catch (e) {}\r\n }\r\n\r\n private stop() {\r\n this.clear();\r\n window.clearInterval(this.titleInterval);\r\n this.titleInterval = 0;\r\n this.setFavicon();\r\n this.stopped = true;\r\n }\r\n\r\n private requestPermission = () => {\r\n Notification.requestPermission();\r\n window.removeEventListener('click', this.requestPermission);\r\n };\r\n\r\n public notify(data: NotifyOptions) {\r\n console.log('notify', data, rootScope.idle.isIDLE, this.notificationsUiSupport, this.stopped);\r\n if(this.stopped) {\r\n return;\r\n }\r\n\r\n // FFOS Notification blob src bug workaround\r\n /* if(Config.Navigator.ffos && !Config.Navigator.ffos2p) {\r\n data.image = 'https://telegram.org/img/t_logo.png'\r\n }\r\n else if (data.image && !angular.isString(data.image)) {\r\n if (Config.Navigator.ffos2p) {\r\n FileManager.getDataUrl(data.image, 'image/jpeg').then(function (url) {\r\n data.image = url\r\n notify(data)\r\n })\r\n return false\r\n } else {\r\n data.image = FileManager.getUrl(data.image, 'image/jpeg')\r\n }\r\n }\r\n else */ if(!data.image) {\r\n data.image = 'assets/img/logo_filled_rounded.png';\r\n }\r\n // console.log('notify image', data.image)\r\n\r\n this.notificationsCount++;\r\n if(!this.titleInterval) {\r\n this.toggleToggler();\r\n }\r\n\r\n const now = tsNow();\r\n if(this.settings.volume > 0 && !this.settings.nosound/* &&\r\n (\r\n !data.tag ||\r\n !this.soundsPlayed[data.tag] ||\r\n now > this.soundsPlayed[data.tag] + 60000\r\n ) */\r\n ) {\r\n this.testSound(this.settings.volume);\r\n this.soundsPlayed[data.tag] = now;\r\n }\r\n\r\n if(!this.notificationsUiSupport ||\r\n 'Notification' in window && Notification.permission !== 'granted') {\r\n return false;\r\n }\r\n\r\n if(this.settings.nodesktop) {\r\n if(this.vibrateSupport && !this.settings.novibrate) {\r\n navigator.vibrate([200, 100, 200]);\r\n return;\r\n }\r\n\r\n return;\r\n }\r\n\r\n const idx = ++this.notificationIndex;\r\n const key = data.key || 'k' + idx;\r\n let notification: MyNotification;\r\n\r\n if('Notification' in window) {\r\n try {\r\n if(data.tag) {\r\n for(let i in this.notificationsShown) {\r\n const notification = this.notificationsShown[i];\r\n if(notification &&\r\n notification.tag === data.tag) {\r\n notification.hidden = true;\r\n }\r\n }\r\n }\r\n\r\n notification = new Notification(data.title, {\r\n icon: data.image || '',\r\n body: data.message || '',\r\n tag: data.tag || '',\r\n silent: data.silent || false\r\n });\r\n console.log('notify constructed notification');\r\n } catch(e) {\r\n this.notificationsUiSupport = false;\r\n //WebPushApiManager.setLocalNotificationsDisabled();\r\n return;\r\n }\r\n } /* else if('mozNotification' in navigator) {\r\n notification = navigator.mozNotification.createNotification(data.title, data.message || '', data.image || '')\r\n } else if(notificationsMsSiteMode) {\r\n window.external.msSiteModeClearIconOverlay()\r\n window.external.msSiteModeSetIconOverlay('img/icons/icon16.png', data.title)\r\n window.external.msSiteModeActivate()\r\n notification = {\r\n index: idx\r\n }\r\n } */ else {\r\n return;\r\n }\r\n\r\n notification.onclick = () => {\r\n notification.close();\r\n //AppRuntimeManager.focus();\r\n this.clear();\r\n if(data.onclick) {\r\n data.onclick();\r\n }\r\n };\r\n\r\n notification.onclose = () => {\r\n if(!notification.hidden) {\r\n delete this.notificationsShown[key];\r\n this.clear();\r\n }\r\n };\r\n\r\n if(notification.show) {\r\n notification.show();\r\n }\r\n this.notificationsShown[key] = notification;\r\n\r\n if(!isMobile) {\r\n setTimeout(() => {\r\n this.hide(key);\r\n }, 8000);\r\n }\r\n }\r\n\r\n public testSound(volume: number) {\r\n const now = tsNow();\r\n if(this.nextSoundAt && now < this.nextSoundAt && this.prevSoundVolume === volume) {\r\n return;\r\n }\r\n\r\n this.nextSoundAt = now + 1000;\r\n this.prevSoundVolume = volume;\r\n const filename = 'assets/audio/notification.mp3';\r\n const audio = document.createElement('audio');\r\n audio.autoplay = true;\r\n audio.setAttribute('mozaudiochannel', 'notification');\r\n audio.volume = volume;\r\n audio.innerHTML = `\r\n <source src=\"${filename}\" type=\"audio/mpeg\" />\r\n <embed hidden=\"true\" autostart=\"true\" loop=\"false\" volume=\"${volume * 100}\" src=\"${filename}\" />\r\n `;\r\n this.notifySoundEl.append(audio);\r\n\r\n audio.addEventListener('ended', () => {\r\n audio.remove();\r\n }, {once: true});\r\n }\r\n\r\n public cancel(key: string) {\r\n const notification = this.notificationsShown[key];\r\n if(notification) {\r\n if(this.notificationsCount > 0) {\r\n this.notificationsCount--;\r\n }\r\n\r\n try {\r\n if(notification.close) {\r\n notification.hidden = true;\r\n notification.close();\r\n }/* else if(notificationsMsSiteMode &&\r\n notification.index === notificationIndex) {\r\n window.external.msSiteModeClearIconOverlay()\r\n } */\r\n } catch (e) {}\r\n\r\n delete this.notificationsShown[key];\r\n }\r\n }\r\n\r\n private hide(key: string) {\r\n const notification = this.notificationsShown[key];\r\n if(notification) {\r\n try {\r\n if(notification.close) {\r\n notification.hidden = true;\r\n notification.close();\r\n }\r\n } catch (e) {}\r\n }\r\n }\r\n\r\n public soundReset(tag: string) {\r\n delete this.soundsPlayed[tag];\r\n }\r\n\r\n public clear() {\r\n /* if(notificationsMsSiteMode) {\r\n window.external.msSiteModeClearIconOverlay()\r\n } else { */\r\n for(let i in this.notificationsShown) {\r\n const notification = this.notificationsShown[i];\r\n try {\r\n if(notification.close) {\r\n notification.close();\r\n }\r\n } catch (e) {}\r\n }\r\n /* } */\r\n this.notificationsShown = {};\r\n this.notificationsCount = 0;\r\n\r\n //WebPushApiManager.hidePushNotifications();\r\n }\r\n\r\n private registerDevice(tokenData: any) {\r\n if(this.registeredDevice &&\r\n deepEqual(this.registeredDevice, tokenData)) {\r\n return false;\r\n }\r\n\r\n apiManager.invokeApi('account.registerDevice', {\r\n token_type: tokenData.tokenType,\r\n token: tokenData.tokenValue,\r\n other_uids: [],\r\n app_sandbox: false,\r\n secret: new Uint8Array()\r\n }).then(() => {\r\n this.registeredDevice = tokenData;\r\n }, (error) => {\r\n error.handled = true;\r\n })\r\n }\r\n\r\n private unregisterDevice(tokenData: any) {\r\n if(!this.registeredDevice) {\r\n return false;\r\n }\r\n\r\n apiManager.invokeApi('account.unregisterDevice', {\r\n token_type: tokenData.tokenType,\r\n token: tokenData.tokenValue,\r\n other_uids: []\r\n }).then(() => {\r\n this.registeredDevice = false\r\n }, (error) => {\r\n error.handled = true\r\n })\r\n }\r\n\r\n public getVibrateSupport() {\r\n return this.vibrateSupport\r\n }\r\n}\r\n\r\nconst appNotificationsManager = new AppNotificationsManager();\r\nMOUNT_CLASS_TO.appNotificationsManager = appNotificationsManager;\r\nexport default appNotificationsManager;\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\nexport function bytesToHex(bytes: ArrayLike<number>) {\r\n bytes = bytes || [];\r\n let arr: string[] = [];\r\n for(let i = 0; i < bytes.length; ++i) {\r\n arr.push((bytes[i] < 16 ? '0' : '') + (bytes[i] || 0).toString(16));\r\n }\r\n return arr.join('');\r\n}\r\n\r\nexport function bytesFromHex(hexString: string) {\r\n const len = hexString.length;\r\n let start = 0;\r\n let bytes: number[] = [];\r\n\r\n if(len % 2) { // read 0x581 as 0x0581\r\n bytes.push(parseInt(hexString.charAt(0), 16));\r\n ++start;\r\n }\r\n\r\n for(let i = start; i < len; i += 2) {\r\n bytes.push(parseInt(hexString.substr(i, 2), 16));\r\n }\r\n\r\n return bytes;\r\n}\r\n\r\nexport function bytesToBase64(bytes: number[] | Uint8Array) {\r\n let mod3: number;\r\n let result = '';\r\n\r\n for(let nLen = bytes.length, nUint24 = 0, nIdx = 0; nIdx < nLen; ++nIdx) {\r\n mod3 = nIdx % 3;\r\n nUint24 |= bytes[nIdx] << (16 >>> mod3 & 24);\r\n if(mod3 === 2 || nLen - nIdx === 1) {\r\n result += String.fromCharCode(\r\n uint6ToBase64(nUint24 >>> 18 & 63),\r\n uint6ToBase64(nUint24 >>> 12 & 63),\r\n uint6ToBase64(nUint24 >>> 6 & 63),\r\n uint6ToBase64(nUint24 & 63)\r\n );\r\n nUint24 = 0;\r\n }\r\n }\r\n\r\n return result.replace(/A(?=A$|$)/g, '=');\r\n}\r\n\r\nexport function uint6ToBase64(nUint6: number) {\r\n return nUint6 < 26\r\n ? nUint6 + 65\r\n : nUint6 < 52\r\n ? nUint6 + 71\r\n : nUint6 < 62\r\n ? nUint6 - 4\r\n : nUint6 === 62\r\n ? 43\r\n : nUint6 === 63\r\n ? 47\r\n : 65\r\n}\r\n\r\nexport function bytesCmp(bytes1: number[] | Uint8Array, bytes2: number[] | Uint8Array) {\r\n const len = bytes1.length;\r\n if(len !== bytes2.length) {\r\n return false;\r\n }\r\n\r\n for(let i = 0; i < len; ++i) {\r\n if(bytes1[i] !== bytes2[i]) {\r\n return false;\r\n }\r\n }\r\n\r\n return true;\r\n}\r\n\r\nexport function bytesXor(bytes1: number[] | Uint8Array, bytes2: number[] | Uint8Array) {\r\n const len = bytes1.length;\r\n const bytes: number[] = [];\r\n\r\n for(let i = 0; i < len; ++i) {\r\n bytes[i] = bytes1[i] ^ bytes2[i];\r\n }\r\n\r\n return bytes;\r\n}\r\n\r\nexport function bytesToArrayBuffer(b: number[]) {\r\n return (new Uint8Array(b)).buffer;\r\n}\r\n\r\nexport function convertToArrayBuffer(bytes: any | ArrayBuffer | Uint8Array) {\r\n // Be careful with converting subarrays!!\r\n if(bytes instanceof ArrayBuffer) {\r\n return bytes;\r\n }\r\n if(bytes.buffer !== undefined &&\r\n bytes.buffer.byteLength === bytes.length * bytes.BYTES_PER_ELEMENT) {\r\n return bytes.buffer;\r\n }\r\n return bytesToArrayBuffer(bytes);\r\n}\r\n\r\nexport function convertToUint8Array(bytes: Uint8Array | number[]): Uint8Array {\r\n if((bytes as Uint8Array).buffer !== undefined) {\r\n return bytes as Uint8Array;\r\n }\r\n\r\n return new Uint8Array(bytes);\r\n}\r\n\r\nexport function bytesFromArrayBuffer(buffer: ArrayBuffer) {\r\n const len = buffer.byteLength;\r\n const byteView = new Uint8Array(buffer);\r\n const bytes: number[] = [];\r\n\r\n for(let i = 0; i < len; ++i) {\r\n bytes[i] = byteView[i];\r\n }\r\n\r\n return bytes;\r\n}\r\n\r\nexport function bufferConcat(buffer1: any, buffer2: any) {\r\n const l1 = buffer1.byteLength || buffer1.length;\r\n const l2 = buffer2.byteLength || buffer2.length;\r\n const tmp = new Uint8Array(l1 + l2);\r\n tmp.set(buffer1 instanceof ArrayBuffer ? new Uint8Array(buffer1) : buffer1, 0);\r\n tmp.set(buffer2 instanceof ArrayBuffer ? new Uint8Array(buffer2) : buffer2, l1);\r\n\r\n return tmp.buffer;\r\n}\r\n\r\nexport function bufferConcats(...args: any[]) {\r\n let length = 0;\r\n args.forEach(b => length += b.byteLength || b.length);\r\n\r\n const tmp = new Uint8Array(length);\r\n \r\n let lastLength = 0;\r\n args.forEach(b => {\r\n tmp.set(b instanceof ArrayBuffer ? new Uint8Array(b) : b, lastLength);\r\n lastLength += b.byteLength || b.length;\r\n });\r\n\r\n return tmp/* .buffer */;\r\n}\r\n\r\nexport function bytesFromWordss(input: Uint32Array) {\r\n const o: number[] = [];\r\n for(let i = 0, length = input.length * 4; i < length; ++i) {\r\n o.push((input[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff);\r\n }\r\n\r\n return o;\r\n}\r\n\r\nexport function bytesToWordss(input: ArrayBuffer | Uint8Array) {\r\n let bytes: Uint8Array;\r\n if(input instanceof ArrayBuffer) bytes = new Uint8Array(input);\r\n else bytes = input;\r\n\r\n const words: number[] = [];\r\n for(let i = 0, len = bytes.length; i < len; ++i) {\r\n words[i >>> 2] |= bytes[i] << (24 - (i % 4) * 8);\r\n }\r\n\r\n return new Uint32Array(words);\r\n}\r\n\r\n// * https://stackoverflow.com/a/52827031\r\n/* export const isBigEndian = (() => {\r\n const array = new Uint8Array(4);\r\n const view = new Uint32Array(array.buffer);\r\n return !((view[0] = 1) & array[0]);\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 { isInDOM, cancelEvent, attachClickEvent } from \"../helpers/dom\";\r\nimport { CancellablePromise } from \"../helpers/cancellablePromise\";\r\nimport SetTransition from \"./singleTransition\";\r\nimport { fastRaf } from \"../helpers/schedulers\";\r\nimport { safeAssign } from \"../helpers/object\";\r\n\r\nconst TRANSITION_TIME = 200;\r\n\r\nexport default class ProgressivePreloader {\r\n public preloader: HTMLDivElement;\r\n private circle: SVGCircleElement;\r\n private cancelSvg: SVGSVGElement;\r\n private downloadSvg: HTMLElement;\r\n \r\n private tempId = 0;\r\n private detached = true;\r\n\r\n public promise: CancellablePromise<any> = null;\r\n\r\n public isUpload = false;\r\n private cancelable = true;\r\n private streamable = false;\r\n private tryAgainOnFail = true;\r\n private attachMethod: 'append' | 'prepend' = 'append';\r\n\r\n public loadFunc: () => {download: CancellablePromise<any>};\r\n\r\n private totalLength: number;\r\n\r\n constructor(options?: Partial<{\r\n isUpload: ProgressivePreloader['isUpload'],\r\n cancelable: ProgressivePreloader['cancelable'], \r\n streamable: ProgressivePreloader['streamable'], \r\n tryAgainOnFail: ProgressivePreloader['tryAgainOnFail'],\r\n attachMethod: ProgressivePreloader['attachMethod']\r\n }>) {\r\n if(options) {\r\n safeAssign(this, options);\r\n }\r\n }\r\n\r\n public constructContainer(options: Partial<{\r\n color: 'transparent',\r\n bold: boolean\r\n }> = {}) {\r\n if(!this.preloader) {\r\n this.preloader = document.createElement('div');\r\n this.preloader.classList.add('preloader-container');\r\n\r\n if(options.color) {\r\n this.preloader.classList.add('preloader-' + options.color);\r\n }\r\n\r\n if(options.bold) {\r\n this.preloader.classList.add('preloader-bold');\r\n }\r\n \r\n if(this.streamable) {\r\n this.preloader.classList.add('preloader-streamable');\r\n }\r\n }\r\n }\r\n\r\n public constructDownloadIcon() {\r\n this.constructContainer();\r\n }\r\n\r\n public construct() {\r\n this.construct = null;\r\n\r\n this.constructContainer();\r\n \r\n this.preloader.innerHTML = `\r\n <div class=\"you-spin-me-round\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"preloader-circular\" viewBox=\"${this.streamable ? '25 25 50 50' : '27 27 54 54'}\">\r\n <circle class=\"preloader-path-new\" cx=\"${this.streamable ? '50' : '54'}\" cy=\"${this.streamable ? '50' : '54'}\" r=\"${this.streamable ? 19 : 24}\" fill=\"none\" stroke-miterlimit=\"10\"/>\r\n </svg>\r\n </div>`;\r\n\r\n if(this.cancelable) {\r\n this.preloader.innerHTML += `\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"preloader-close\" viewBox=\"0 0 24 24\">\r\n <g fill=\"none\" fill-rule=\"evenodd\">\r\n <polygon points=\"0 0 24 0 24 24 0 24\"/>\r\n <path fill=\"#000\" fill-rule=\"nonzero\" d=\"M5.20970461,5.38710056 L5.29289322,5.29289322 C5.65337718,4.93240926 6.22060824,4.90467972 6.61289944,5.20970461 L6.70710678,5.29289322 L12,10.585 L17.2928932,5.29289322 C17.6834175,4.90236893 18.3165825,4.90236893 18.7071068,5.29289322 C19.0976311,5.68341751 19.0976311,6.31658249 18.7071068,6.70710678 L13.415,12 L18.7071068,17.2928932 C19.0675907,17.6533772 19.0953203,18.2206082 18.7902954,18.6128994 L18.7071068,18.7071068 C18.3466228,19.0675907 17.7793918,19.0953203 17.3871006,18.7902954 L17.2928932,18.7071068 L12,13.415 L6.70710678,18.7071068 C6.31658249,19.0976311 5.68341751,19.0976311 5.29289322,18.7071068 C4.90236893,18.3165825 4.90236893,17.6834175 5.29289322,17.2928932 L10.585,12 L5.29289322,6.70710678 C4.93240926,6.34662282 4.90467972,5.77939176 5.20970461,5.38710056 L5.29289322,5.29289322 L5.20970461,5.38710056 Z\"/>\r\n </g>\r\n </svg>\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"preloader-download\" viewBox=\"0 0 24 24\">\r\n <g fill=\"none\" fill-rule=\"evenodd\">\r\n <polygon points=\"0 0 24 0 24 24 0 24\"/>\r\n <path fill=\"#000\" fill-rule=\"nonzero\" d=\"M5,19 L19,19 C19.5522847,19 20,19.4477153 20,20 C20,20.5128358 19.6139598,20.9355072 19.1166211,20.9932723 L19,21 L5,21 C4.44771525,21 4,20.5522847 4,20 C4,19.4871642 4.38604019,19.0644928 4.88337887,19.0067277 L5,19 L19,19 L5,19 Z M11.8833789,3.00672773 L12,3 C12.5128358,3 12.9355072,3.38604019 12.9932723,3.88337887 L13,4 L13,13.585 L16.2928932,10.2928932 C16.6533772,9.93240926 17.2206082,9.90467972 17.6128994,10.2097046 L17.7071068,10.2928932 C18.0675907,10.6533772 18.0953203,11.2206082 17.7902954,11.6128994 L17.7071068,11.7071068 L12.7071068,16.7071068 C12.3466228,17.0675907 11.7793918,17.0953203 11.3871006,16.7902954 L11.2928932,16.7071068 L6.29289322,11.7071068 C5.90236893,11.3165825 5.90236893,10.6834175 6.29289322,10.2928932 C6.65337718,9.93240926 7.22060824,9.90467972 7.61289944,10.2097046 L7.70710678,10.2928932 L11,13.585 L11,4 C11,3.48716416 11.3860402,3.06449284 11.8833789,3.00672773 L12,3 L11.8833789,3.00672773 Z\"/>\r\n </g>\r\n </svg>`;\r\n\r\n this.downloadSvg = this.preloader.lastElementChild as HTMLElement;\r\n this.cancelSvg = this.downloadSvg.previousElementSibling as any;\r\n } else {\r\n this.preloader.classList.add('preloader-swing');\r\n }\r\n \r\n this.circle = this.preloader.firstElementChild.firstElementChild.firstElementChild as SVGCircleElement;\r\n\r\n if(this.cancelable) {\r\n attachClickEvent(this.preloader, this.onClick);\r\n }\r\n }\r\n\r\n public onClick = (e?: Event) => {\r\n if(e) {\r\n cancelEvent(e);\r\n }\r\n\r\n if(this.preloader.classList.contains('manual')) {\r\n if(this.loadFunc) {\r\n this.loadFunc();\r\n }\r\n } else {\r\n if(this.promise && this.promise.cancel) {\r\n this.promise.cancel();\r\n }\r\n }\r\n };\r\n\r\n public setDownloadFunction(func: ProgressivePreloader['loadFunc']) {\r\n this.loadFunc = func;\r\n }\r\n\r\n public setManual() {\r\n this.preloader.classList.add('manual');\r\n this.setProgress(0);\r\n }\r\n\r\n public attachPromise(promise: CancellablePromise<any>) {\r\n if(this.isUpload && this.promise) return;\r\n\r\n this.promise = promise;\r\n\r\n const tempId = --this.tempId;\r\n const startTime = Date.now();\r\n\r\n const onEnd = (err: Error) => {\r\n promise.notify = null;\r\n\r\n if(tempId !== this.tempId) {\r\n return;\r\n }\r\n\r\n const elapsedTime = Date.now() - startTime;\r\n\r\n //console.log('[PP]: end', this.detached, performance.now());\r\n\r\n if(!err && this.cancelable) {\r\n this.setProgress(100);\r\n\r\n const delay = TRANSITION_TIME * 0.75;\r\n\r\n if(elapsedTime < delay) {\r\n this.detach();\r\n } else {\r\n setTimeout(() => { // * wait for transition complete\r\n if(tempId === this.tempId) {\r\n this.detach();\r\n }\r\n }, delay);\r\n }\r\n } else {\r\n if(this.tryAgainOnFail) {\r\n SetTransition(this.preloader, '', true, TRANSITION_TIME);\r\n fastRaf(() => {\r\n this.setManual();\r\n });\r\n } else {\r\n this.detach();\r\n }\r\n }\r\n \r\n this.promise = promise = null;\r\n };\r\n \r\n promise\r\n .then(() => onEnd(null))\r\n .catch((err) => onEnd(err));\r\n\r\n if(promise.addNotifyListener) {\r\n promise.addNotifyListener((details: {done: number, total: number}) => {\r\n /* if(details.done >= details.total) {\r\n onEnd();\r\n } */\r\n\r\n if(tempId !== this.tempId) return;\r\n\r\n //console.log('preloader download', promise, details);\r\n const percents = details.done / details.total * 100;\r\n this.setProgress(percents);\r\n });\r\n }\r\n }\r\n\r\n public attach(elem: Element, reset = false, promise?: CancellablePromise<any>) {\r\n if(promise/* && false */) {\r\n this.attachPromise(promise);\r\n }\r\n\r\n //return;\r\n\r\n this.detached = false;\r\n /* fastRaf(() => {\r\n if(this.detached) return;\r\n this.detached = false; */\r\n\r\n if(this.construct) {\r\n this.construct();\r\n }\r\n\r\n if(this.preloader.parentElement) {\r\n this.preloader.classList.remove('manual');\r\n }\r\n\r\n if(this.preloader.parentElement !== elem) {\r\n elem[this.attachMethod](this.preloader);\r\n }\r\n\r\n fastRaf(() => {\r\n //console.log('[PP]: attach after rAF', this.detached, performance.now());\r\n\r\n if(this.detached) {\r\n return;\r\n }\r\n\r\n SetTransition(this.preloader, 'is-visible', true, TRANSITION_TIME);\r\n });\r\n\r\n if(this.cancelable && reset) {\r\n this.setProgress(0);\r\n }\r\n //});\r\n }\r\n \r\n public detach() {\r\n //return;\r\n\r\n this.detached = true;\r\n\r\n //return;\r\n \r\n if(this.preloader && this.preloader.parentElement) {\r\n /* setTimeout(() => *///fastRaf(() => {\r\n /* if(!this.detached) return;\r\n this.detached = true; */\r\n\r\n fastRaf(() => {\r\n //console.log('[PP]: detach after rAF', this.detached, performance.now());\r\n\r\n if(!this.detached || !this.preloader.parentElement) {\r\n return;\r\n }\r\n\r\n SetTransition(this.preloader, 'is-visible', false, TRANSITION_TIME, () => {\r\n this.preloader.remove();\r\n });\r\n });\r\n //})/* , 5e3) */;\r\n }\r\n }\r\n \r\n public setProgress(percents: number) {\r\n if(!isInDOM(this.circle)) {\r\n return;\r\n }\r\n \r\n if(percents === 0) {\r\n this.circle.style.strokeDasharray = '';\r\n return;\r\n }\r\n \r\n try {\r\n if(!this.totalLength) {\r\n this.totalLength = this.circle.getTotalLength();\r\n }\r\n\r\n //console.log('setProgress', (percents / 100 * totalLength));\r\n this.circle.style.strokeDasharray = '' + Math.max(5, percents / 100 * this.totalLength) + ', ' + this.totalLength;\r\n } catch(err) {}\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport rootScope from \"../lib/rootScope\";\r\n\r\nconst SetTransition = (element: HTMLElement, className: string, forwards: boolean, duration: number, onTransitionEnd?: () => void) => {\r\n const timeout = element.dataset.timeout;\r\n if(timeout !== undefined) {\r\n clearTimeout(+timeout);\r\n }\r\n\r\n if(forwards && className) {\r\n element.classList.add(className);\r\n }\r\n\r\n const afterTimeout = () => {\r\n delete element.dataset.timeout;\r\n if(!forwards && className) {\r\n element.classList.remove('backwards', className);\r\n }\r\n\r\n element.classList.remove('animating');\r\n \r\n onTransitionEnd && onTransitionEnd();\r\n };\r\n\r\n if(!rootScope.settings.animationsEnabled) {\r\n element.classList.remove('animating', 'backwards');\r\n afterTimeout();\r\n return;\r\n }\r\n\r\n element.classList.add('animating');\r\n\r\n element.classList.toggle('backwards', !forwards);\r\n element.dataset.timeout = '' + setTimeout(afterTimeout, duration);\r\n};\r\n\r\nexport default SetTransition;\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 { MOUNT_CLASS_TO } from '../../config/debug';\r\nimport { tsNow } from '../../helpers/date';\r\nimport sessionStorage from '../sessionStorage';\r\n\r\nexport class ServerTimeManager {\r\n public timestampNow = tsNow(true);\r\n public midnightNoOffset = this.timestampNow - (this.timestampNow % 86400);\r\n public midnightOffseted = new Date();\r\n\r\n public midnightOffset = this.midnightNoOffset - (Math.floor(+this.midnightOffseted / 1000));\r\n\r\n public serverTimeOffset = 0; // in seconds\r\n public timeParams = {\r\n midnightOffset: this.midnightOffset,\r\n serverTimeOffset: this.serverTimeOffset\r\n };\r\n\r\n constructor() {\r\n this.midnightOffseted.setHours(0, 0, 0, 0);\r\n\r\n sessionStorage.get('server_time_offset').then((to) => {\r\n if(to) {\r\n this.serverTimeOffset = to;\r\n this.timeParams.serverTimeOffset = to;\r\n }\r\n });\r\n }\r\n}\r\n\r\nconst serverTimeManager = new ServerTimeManager();\r\nMOUNT_CLASS_TO && (MOUNT_CLASS_TO.serverTimeManager = serverTimeManager);\r\nexport default serverTimeManager;\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 { pause } from \"./schedulers\";\r\nimport { isAppleMobile } from \"./userAgent\";\r\n\r\nexport function preloadVideo(url: string): Promise<HTMLVideoElement> {\r\n return new Promise((resolve, reject) => {\r\n const video = document.createElement('video');\r\n video.volume = 0;\r\n video.onloadedmetadata = () => resolve(video);\r\n video.onerror = reject;\r\n video.src = url;\r\n });\r\n}\r\n\r\nexport function createPosterFromVideo(video: HTMLVideoElement): Promise<Blob> {\r\n return new Promise((resolve, reject) => {\r\n video.onseeked = () => {\r\n const canvas = document.createElement('canvas');\r\n canvas.width = Math.min(1280, video.videoWidth);\r\n canvas.height = Math.min(720, video.videoHeight);\r\n const ctx = canvas.getContext('2d')!;\r\n ctx.drawImage(video, 0, 0);\r\n canvas.toBlob(blob => {\r\n resolve(blob);\r\n }, 'image/jpeg', 1);\r\n };\r\n\r\n video.onerror = reject;\r\n video.currentTime = Math.min(video.duration, 1);\r\n });\r\n}\r\n\r\nexport async function createPosterForVideo(url: string): Promise<Blob | undefined> {\r\n const video = await preloadVideo(url);\r\n\r\n return Promise.race([\r\n pause(2000) as Promise<undefined>,\r\n createPosterFromVideo(video),\r\n ]);\r\n}\r\n\r\nexport function onVideoLoad(video: HTMLVideoElement) {\r\n return new Promise<void>((resolve) => {\r\n if(video.readyState >= video.HAVE_METADATA) {\r\n resolve();\r\n return;\r\n }\r\n\r\n video.addEventListener(isAppleMobile ? 'loadeddata' : 'canplay', () => resolve(), {once: true});\r\n });\r\n}\r\n\r\nexport async function getFilesFromEvent(e: ClipboardEvent | DragEvent, onlyTypes = false): Promise<any[]> {\r\n const files: any[] = [];\r\n\r\n const scanFiles = async(entry: any, item: DataTransferItem) => {\r\n if(entry.isDirectory) {\r\n const directoryReader = entry.createReader();\r\n await new Promise<void>((resolve, reject) => {\r\n directoryReader.readEntries(async(entries: any) => {\r\n for(const entry of entries) {\r\n await scanFiles(entry, item);\r\n }\r\n\r\n resolve();\r\n });\r\n });\r\n } else if(entry) {\r\n if(onlyTypes) {\r\n files.push(entry.type);\r\n } else {\r\n const itemFile = item.getAsFile(); // * Safari can't handle entry.file with pasting\r\n const file = entry instanceof File ? \r\n entry : \r\n (\r\n entry instanceof DataTransferItem ? \r\n entry.getAsFile() : \r\n await new Promise((resolve, reject) => entry.file(resolve, (err: any) => resolve(itemFile)))\r\n );\r\n\r\n /* if(!onlyTypes) {\r\n console.log('getFilesFromEvent: got file', item, file);\r\n } */\r\n\r\n if(!file) return;\r\n files.push(file);\r\n }\r\n }\r\n };\r\n\r\n if(e instanceof DragEvent && e.dataTransfer.files && !e.dataTransfer.items) {\r\n for(let i = 0; i < e.dataTransfer.files.length; i++) {\r\n const file = e.dataTransfer.files[i];\r\n files.push(onlyTypes ? file.type : file);\r\n }\r\n } else {\r\n // @ts-ignore\r\n const items = (e.dataTransfer || e.clipboardData || e.originalEvent.clipboardData).items;\r\n\r\n const promises: Promise<any>[] = [];\r\n for(let i = 0; i < items.length; ++i) {\r\n const item: DataTransferItem = items[i];\r\n if(item.kind === 'file') {\r\n const entry = (onlyTypes ? item : item.webkitGetAsEntry()) || item.getAsFile();\r\n promises.push(scanFiles(entry, item));\r\n }\r\n }\r\n \r\n await Promise.all(promises);\r\n }\r\n\r\n /* if(!onlyTypes) {\r\n console.log('getFilesFromEvent: got files:', e, files);\r\n } */\r\n \r\n return files;\r\n}\r\n\r\nexport function requestFile(accept?: string) {\r\n const input = document.createElement('input');\r\n input.type = 'file';\r\n input.style.display = 'none';\r\n\r\n if(accept) {\r\n input.accept = accept;\r\n }\r\n\r\n document.body.append(input);\r\n\r\n const promise = new Promise<File>((resolve, reject) => {\r\n input.addEventListener('change', (e: any) => {\r\n const file: File = e.target.files[0];\r\n if(!file) {\r\n reject('NO_FILE_SELECTED');\r\n return;\r\n }\r\n \r\n resolve(file);\r\n }, {once: true});\r\n }).finally(() => {\r\n input.remove();\r\n });\r\n\r\n input.click();\r\n\r\n return promise;\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 \"../appManagers/appMessagesManager\";\r\nimport { Photo } from \"../../layer\";\r\nimport { bytesToHex } from \"../../helpers/bytes\";\r\nimport { deepEqual } from \"../../helpers/object\";\r\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\r\n\r\nexport type ReferenceContext = ReferenceContext.referenceContextProfilePhoto | ReferenceContext.referenceContextMessage;\r\nexport namespace ReferenceContext {\r\n export type referenceContextProfilePhoto = {\r\n type: 'profilePhoto',\r\n peerId: number\r\n };\r\n\r\n export type referenceContextMessage = {\r\n type: 'message',\r\n peerId: number,\r\n messageId: number\r\n };\r\n}\r\n\r\nexport type ReferenceBytes = Photo.photo['file_reference'];\r\nexport type ReferenceContexts = Set<ReferenceContext>;\r\n\r\n//type ReferenceBytes = Uint8Array;\r\n\r\nclass ReferenceDatabase {\r\n private contexts: Map<ReferenceBytes, ReferenceContexts> = new Map();\r\n //private references: Map<ReferenceBytes, number[]> = new Map();\r\n private links: {[hex: string]: ReferenceBytes} = {};\r\n\r\n public saveContext(reference: ReferenceBytes, context: ReferenceContext, contexts?: ReferenceContexts) {\r\n [contexts, reference] = this.getContexts(reference);\r\n if(!contexts) {\r\n contexts = new Set();\r\n this.contexts.set(reference, contexts);\r\n this.links[bytesToHex(reference)] = reference;\r\n }\r\n\r\n for(const _context of contexts) {\r\n if(deepEqual(_context, context)) {\r\n return;\r\n }\r\n }\r\n\r\n contexts.add(context);\r\n }\r\n\r\n public getReferenceByLink(reference: ReferenceBytes) {\r\n return this.links[bytesToHex(reference)];\r\n }\r\n\r\n public getContexts(reference: ReferenceBytes): [ReferenceContexts, ReferenceBytes] {\r\n const contexts = this.contexts.get(reference) || (reference = this.getReferenceByLink(reference) || reference, this.contexts.get(reference));\r\n return [contexts, reference];\r\n }\r\n\r\n public getContext(reference: ReferenceBytes): [ReferenceContext, ReferenceBytes] {\r\n const contexts = this.getContexts(reference);\r\n return contexts ? [contexts[0].values().next().value, contexts[1]] : undefined;\r\n }\r\n\r\n public deleteContext(reference: ReferenceBytes, context: ReferenceContext, contexts?: ReferenceContexts) {\r\n [contexts, reference] = this.getContexts(reference);\r\n if(contexts) {\r\n for(const _context of contexts) {\r\n if(deepEqual(_context, context)) {\r\n contexts.delete(_context);\r\n if(!contexts.size) {\r\n this.contexts.delete(reference);\r\n delete this.links[bytesToHex(reference)];\r\n }\r\n return true;\r\n }\r\n }\r\n }\r\n\r\n return false;\r\n }\r\n\r\n public refreshReference(reference: ReferenceBytes, context?: ReferenceContext): Promise<void> {\r\n [context, reference] = this.getContext(reference);\r\n switch(context?.type) {\r\n case 'message': {\r\n return appMessagesManager.wrapSingleMessage(context.peerId, context.messageId, true);\r\n // .then(() => {\r\n // console.log('FILE_REFERENCE_EXPIRED: got message', context, appMessagesManager.getMessage((context as ReferenceContext.referenceContextMessage).messageId).media, reference);\r\n // });\r\n }\r\n\r\n default: {\r\n console.warn('FILE_REFERENCE_EXPIRED: not implemented context', context);\r\n return Promise.reject();\r\n }\r\n }\r\n }\r\n\r\n /* handleReferenceError = (reference: ReferenceBytes, error: ApiError) => {\r\n switch(error.type) {\r\n case 'FILE_REFERENCE_EXPIRED': {\r\n return this.refreshReference(reference);\r\n }\r\n\r\n default:\r\n return Promise.reject(error);\r\n }\r\n }; */\r\n\r\n /* public replaceReference(oldReference: ReferenceBytes, newReference: ReferenceBytes) {\r\n const contexts = this.contexts.get(oldReference);\r\n if(contexts) {\r\n this.contexts.delete(oldReference);\r\n this.contexts.set(newReference, contexts);\r\n }\r\n } */\r\n}\r\n\r\nconst referenceDatabase = new ReferenceDatabase();\r\nMOUNT_CLASS_TO.referenceDatabase = referenceDatabase;\r\nexport default referenceDatabase;","/*\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 Config from './config';\r\n\r\nexport type SearchIndex = {\r\n fullTexts: {\r\n [peerId: string]: string\r\n }/* ,\r\n shortIndexes: {\r\n [shortStr: string]: number[]\r\n } */\r\n};\r\n\r\nclass SearchIndexManager {\r\n public static badCharsRe = /[`~!@#$%^&*()\\-_=+\\[\\]\\\\|{}'\";:\\/?.>,<]+/g;\r\n public static trimRe = /^\\s+|\\s$/g;\r\n\r\n public createIndex(): SearchIndex {\r\n return {\r\n fullTexts: {}/* ,\r\n shortIndexes: {} */\r\n };\r\n }\r\n\r\n public cleanSearchText(text: string, latinize = true) {\r\n const hasTag = text.charAt(0) === '%';\r\n text = text.replace(SearchIndexManager['badCharsRe'], '').replace(SearchIndexManager['trimRe'], '');\r\n if(latinize) {\r\n text = text.replace(/[^A-Za-z0-9]/g, (ch) => {\r\n const latinizeCh = Config.LatinizeMap[ch];\r\n return latinizeCh !== undefined ? latinizeCh : ch;\r\n });\r\n }\r\n \r\n text = text.toLowerCase();\r\n if(hasTag) {\r\n text = '%' + text;\r\n }\r\n\r\n return text;\r\n }\r\n\r\n public cleanUsername(username: string) {\r\n return username && username.toLowerCase() || '';\r\n }\r\n\r\n public indexObject(id: number, searchText: string, searchIndex: SearchIndex) {\r\n /* if(searchIndex.fullTexts.hasOwnProperty(id)) {\r\n return false;\r\n } */\r\n\r\n if(searchText.trim()) {\r\n searchText = this.cleanSearchText(searchText);\r\n }\r\n\r\n if(!searchText) {\r\n delete searchIndex.fullTexts[id];\r\n return false;\r\n }\r\n\r\n searchIndex.fullTexts[id] = searchText;\r\n \r\n /* const shortIndexes = searchIndex.shortIndexes;\r\n searchText.split(' ').forEach((searchWord) => {\r\n let len = Math.min(searchWord.length, 3),\r\n wordPart, i;\r\n for(i = 1; i <= len; i++) {\r\n wordPart = searchWord.substr(0, i);\r\n if(shortIndexes[wordPart] === undefined) {\r\n shortIndexes[wordPart] = [id];\r\n } else {\r\n shortIndexes[wordPart].push(id);\r\n }\r\n }\r\n }); */\r\n }\r\n\r\n public search(query: string, searchIndex: SearchIndex) {\r\n const fullTexts = searchIndex.fullTexts;\r\n //const shortIndexes = searchIndex.shortIndexes;\r\n\r\n query = this.cleanSearchText(query);\r\n\r\n const newFoundObjs: {[peerId: string]: true} = {};\r\n const queryWords = query.split(' ');\r\n for(const peerId in fullTexts) {\r\n const fullText = fullTexts[peerId];\r\n\r\n let found = true;\r\n for(const word of queryWords) { // * verify that all words are found\r\n const idx = fullText.indexOf(word);\r\n if(idx === -1 || (idx !== 0 && fullText[idx - 1] !== ' ')) { // * search only from word beginning\r\n found = false;\r\n break;\r\n }\r\n }\r\n\r\n if(found) {\r\n newFoundObjs[peerId] = true;\r\n }\r\n }\r\n \r\n\r\n /* const queryWords = query.split(' ');\r\n let foundArr: number[];\r\n for(let i = 0; i < queryWords.length; i++) {\r\n const newFound = shortIndexes[queryWords[i].substr(0, 3)];\r\n if(!newFound) {\r\n foundArr = [];\r\n break;\r\n }\r\n \r\n if(foundArr === undefined || foundArr.length > newFound.length) {\r\n foundArr = newFound;\r\n }\r\n }\r\n\r\n for(let j = 0; j < foundArr.length; j++) {\r\n let found = true;\r\n let searchText = fullTexts[foundArr[j]];\r\n for(let i = 0; i < queryWords.length; i++) {\r\n if(searchText.indexOf(queryWords[i]) === -1) {\r\n found = false;\r\n break;\r\n }\r\n }\r\n\r\n if(found) {\r\n newFoundObjs[foundArr[j]] = true;\r\n }\r\n } */\r\n\r\n return newFoundObjs;\r\n }\r\n}\r\n\r\nexport default new SearchIndexManager();\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 { InputFileLocation, FileLocation } from \"../layer\";\r\nimport type { DownloadOptions } from \"../lib/mtproto/apiFileManager\";\r\n\r\nexport function getFileNameByLocation(location: InputFileLocation | FileLocation, options?: Partial<{\r\n fileName: string\r\n}>) {\r\n const fileName = '';//(options?.fileName || '').split('.');\r\n const ext = fileName[fileName.length - 1] || '';\r\n\r\n switch(location._) {\r\n case 'inputPhotoFileLocation':\r\n case 'inputDocumentFileLocation': {\r\n const thumbPart = location.thumb_size ? '_' + location.thumb_size : '';\r\n return (fileName[0] ? fileName[0] + '_' : '') + location.id + thumbPart + (ext ? '.' + ext : ext);\r\n }\r\n\r\n case 'fileLocationToBeDeprecated':\r\n case 'inputPeerPhotoFileLocation':\r\n case 'inputStickerSetThumb':\r\n case 'inputFileLocation': {\r\n return location.volume_id + '_' + location.local_id + (ext ? '.' + ext : ext);\r\n }\r\n\r\n default: {\r\n console.error('Unrecognized location:', location);\r\n return '';\r\n }\r\n }\r\n}\r\n\r\nexport type FileURLType = 'photo' | 'thumb' | 'document' | 'stream' | 'download';\r\nexport function getFileURL(type: FileURLType, options: DownloadOptions) {\r\n //console.log('getFileURL', location);\r\n //const perf = performance.now();\r\n const encoded = encodeURIComponent(JSON.stringify(options));\r\n //console.log('getFileURL encode:', performance.now() - perf, encoded);\r\n\r\n return '/' + type + '/' + encoded;\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 { copy } from \"../../helpers/object\";\r\nimport { InputMedia, MessageEntity } from \"../../layer\";\r\nimport { logger, LogLevels } from \"../logger\";\r\nimport apiManager from \"../mtproto/mtprotoworker\";\r\nimport { RichTextProcessor } from \"../richtextprocessor\";\r\nimport rootScope from \"../rootScope\";\r\nimport apiUpdatesManager from \"./apiUpdatesManager\";\r\nimport appMessagesManager from './appMessagesManager';\r\nimport appPeersManager from './appPeersManager';\r\nimport appUsersManager from \"./appUsersManager\";\r\n\r\nexport type PollAnswer = {\r\n _: 'pollAnswer',\r\n text: string,\r\n option: Uint8Array\r\n};\r\n\r\nexport type PollAnswerVoters = {\r\n _: 'pollAnswerVoters',\r\n flags: number,\r\n option: Uint8Array,\r\n voters: number,\r\n\r\n pFlags: Partial<{\r\n chosen: true,\r\n correct: true\r\n }>\r\n};\r\n\r\nexport type PollResult = {\r\n _: 'pollAnswerVoters',\r\n flags: number,\r\n option: Uint8Array,\r\n voters: number,\r\n\r\n pFlags?: Partial<{chosen: true, correct: true}>\r\n};\r\n\r\nexport type PollResults = {\r\n _: 'pollResults',\r\n flags: number,\r\n results?: Array<PollResult>,\r\n total_voters?: number,\r\n recent_voters?: number[],\r\n solution?: string,\r\n solution_entities?: any[],\r\n\r\n pFlags: Partial<{\r\n min: true\r\n }>,\r\n};\r\n\r\nexport type Poll = {\r\n _: 'poll',\r\n question: string,\r\n id: string,\r\n answers: Array<PollAnswer>,\r\n close_period?: number,\r\n close_date?: number\r\n\r\n pFlags?: Partial<{\r\n closed: true,\r\n public_voters: true,\r\n multiple_choice: true,\r\n quiz: true\r\n }>,\r\n rQuestion?: string,\r\n rReply?: string,\r\n chosenIndexes?: number[]\r\n};\r\n\r\nexport class AppPollsManager {\r\n public polls: {[id: string]: Poll} = {};\r\n public results: {[id: string]: PollResults} = {};\r\n\r\n private log = logger('POLLS', LogLevels.error);\r\n\r\n constructor() {\r\n rootScope.addMultipleEventsListeners({\r\n updateMessagePoll: (update) => {\r\n this.log('updateMessagePoll:', update);\r\n\r\n let poll: Poll = update.poll || this.polls[update.poll_id];\r\n if(!poll) {\r\n return;\r\n }\r\n\r\n poll = this.savePoll(poll, update.results as any);\r\n rootScope.broadcast('poll_update', {poll, results: update.results as any});\r\n }\r\n });\r\n }\r\n\r\n public savePoll(poll: Poll, results: PollResults) {\r\n const id = poll.id;\r\n if(this.polls[id]) {\r\n poll = Object.assign(this.polls[id], poll);\r\n this.saveResults(poll, results);\r\n return poll;\r\n }\r\n\r\n this.polls[id] = poll;\r\n\r\n poll.rQuestion = RichTextProcessor.wrapEmojiText(poll.question);\r\n poll.rReply = RichTextProcessor.wrapEmojiText('📊') + ' ' + (poll.rQuestion || 'poll');\r\n poll.chosenIndexes = [];\r\n this.saveResults(poll, results);\r\n return poll;\r\n }\r\n\r\n public saveResults(poll: Poll, results: PollResults) {\r\n if(this.results[poll.id]) {\r\n results = Object.assign(this.results[poll.id], results);\r\n } else {\r\n this.results[poll.id] = results;\r\n }\r\n\r\n if(!results.pFlags.min) { // ! https://core.telegram.org/constructor/pollResults - min\r\n poll.chosenIndexes.length = 0;\r\n if(results?.results?.length) {\r\n results.results.forEach((answer, idx) => {\r\n if(answer.pFlags?.chosen) {\r\n poll.chosenIndexes.push(idx);\r\n }\r\n });\r\n }\r\n }\r\n }\r\n\r\n public getPoll(pollId: string): {poll: Poll, results: PollResults} {\r\n return {\r\n poll: this.polls[pollId], \r\n results: this.results[pollId]\r\n };\r\n }\r\n\r\n public getInputMediaPoll(poll: Poll, correctAnswers?: Uint8Array[], solution?: string, solutionEntities?: MessageEntity[]): InputMedia.inputMediaPoll {\r\n if(solution) {\r\n if(!solutionEntities) {\r\n solutionEntities = [];\r\n }\r\n\r\n solution = RichTextProcessor.parseMarkdown(solution, solutionEntities);\r\n }\r\n\r\n return {\r\n _: 'inputMediaPoll',\r\n poll,\r\n correct_answers: correctAnswers,\r\n solution,\r\n solution_entities: solutionEntities?.length ? solutionEntities : undefined\r\n };\r\n }\r\n\r\n public sendVote(message: any, optionIds: number[]): Promise<void> {\r\n const poll: Poll = message.media.poll;\r\n\r\n const options: Uint8Array[] = optionIds.map(index => {\r\n return poll.answers[index].option;\r\n });\r\n \r\n const messageId = message.mid;\r\n const peerId = message.peerId;\r\n const inputPeer = appPeersManager.getInputPeerById(peerId);\r\n\r\n if(message.pFlags.is_outgoing) {\r\n return appMessagesManager.invokeAfterMessageIsSent(messageId, 'sendVote', (message) => {\r\n this.log('invoke sendVote callback');\r\n return this.sendVote(message, optionIds);\r\n });\r\n }\r\n\r\n return apiManager.invokeApi('messages.sendVote', {\r\n peer: inputPeer,\r\n msg_id: appMessagesManager.getServerMessageId(message.mid),\r\n options\r\n }).then(updates => {\r\n this.log('sendVote updates:', updates);\r\n apiUpdatesManager.processUpdateMessage(updates);\r\n });\r\n }\r\n\r\n public getResults(message: any) {\r\n const inputPeer = appPeersManager.getInputPeerById(message.peerId);\r\n\r\n return apiManager.invokeApi('messages.getPollResults', {\r\n peer: inputPeer,\r\n msg_id: appMessagesManager.getServerMessageId(message.mid)\r\n }).then(updates => {\r\n apiUpdatesManager.processUpdateMessage(updates);\r\n this.log('getResults updates:', updates);\r\n });\r\n }\r\n\r\n public getVotes(message: any, option?: Uint8Array, offset?: string, limit = 20) {\r\n return apiManager.invokeApi('messages.getPollVotes', {\r\n peer: appPeersManager.getInputPeerById(message.peerId),\r\n id: appMessagesManager.getServerMessageId(message.mid),\r\n option,\r\n offset,\r\n limit\r\n }).then((votesList) => {\r\n this.log('getPollVotes messages:', votesList);\r\n\r\n appUsersManager.saveApiUsers(votesList.users);\r\n\r\n return votesList;\r\n });\r\n }\r\n\r\n public stopPoll(message: any) {\r\n const poll: Poll = message.media.poll;\r\n \r\n if(poll.pFlags.closed) return Promise.resolve();\r\n\r\n const newPoll = copy(poll);\r\n newPoll.pFlags.closed = true;\r\n return appMessagesManager.editMessage(message, undefined, {\r\n newMedia: this.getInputMediaPoll(newPoll)\r\n }).then(() => {\r\n //console.log('stopped poll');\r\n }, err => {\r\n this.log.error('stopPoll error:', err);\r\n });\r\n }\r\n}\r\n\r\nconst appPollsManager = new AppPollsManager();\r\nMOUNT_CLASS_TO.appPollsManager = appPollsManager;\r\nexport default appPollsManager;\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 WebpWorker from 'worker-loader!./webp.worker';\r\nimport { MOUNT_CLASS_TO } from '../../config/debug';\r\nimport { CancellablePromise, deferredPromise } from '../../helpers/cancellablePromise';\r\nimport apiManagerProxy from '../mtproto/mtprotoworker';\r\n\r\nexport type WebpConvertTask = {\r\n type: 'convertWebp', \r\n payload: {\r\n fileName: string, \r\n bytes: Uint8Array\r\n }\r\n};\r\n\r\nexport class WebpWorkerController {\r\n private worker: Worker;\r\n private convertPromises: {[fileName: string]: CancellablePromise<Uint8Array>} = {};\r\n private isWebpSupportedCache: boolean;\r\n \r\n init() {\r\n this.worker = new WebpWorker();\r\n this.worker.addEventListener('message', (e) => {\r\n const payload = (e.data as WebpConvertTask).payload;\r\n\r\n if(payload.fileName.indexOf('main-') === 0) {\r\n const promise = this.convertPromises[payload.fileName];\r\n if(promise) {\r\n payload.bytes ? promise.resolve(payload.bytes) : promise.reject();\r\n delete this.convertPromises[payload.fileName];\r\n }\r\n } else {\r\n apiManagerProxy.postMessage(e.data);\r\n }\r\n });\r\n }\r\n\r\n postMessage(data: WebpConvertTask) {\r\n if(this.init) {\r\n this.init();\r\n this.init = null;\r\n }\r\n\r\n this.worker.postMessage(data);\r\n }\r\n\r\n isWebpSupported() {\r\n if(this.isWebpSupportedCache === undefined) {\r\n this.isWebpSupportedCache = document.createElement('canvas').toDataURL('image/webp').startsWith('data:image/webp');\r\n }\r\n\r\n return this.isWebpSupportedCache;\r\n }\r\n\r\n convert(fileName: string, bytes: Uint8Array) {\r\n fileName = 'main-' + fileName;\r\n\r\n if(this.convertPromises.hasOwnProperty(fileName)) {\r\n return this.convertPromises[fileName];\r\n }\r\n \r\n const convertPromise = deferredPromise<Uint8Array>();\r\n\r\n this.postMessage({type: 'convertWebp', payload: {fileName, bytes}});\r\n\r\n return this.convertPromises[fileName] = convertPromise;\r\n }\r\n}\r\n\r\nconst webpWorkerController = new WebpWorkerController();\r\nMOUNT_CLASS_TO.webpWorkerController = webpWorkerController;\r\nexport default webpWorkerController;","/*\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 type Country = {\r\n phoneCode: string,\r\n code: string,\r\n name: string,\r\n pattern: string,\r\n emoji: string\r\n};\r\n\r\nconst Countries: Country[] = [{\"phoneCode\":\"7 840\",\"code\":\"AB\",\"name\":\"Abkhazia\",\"pattern\":\"\",\"emoji\":\"\"},{\"phoneCode\":\"93\",\"code\":\"AF\",\"name\":\"Afghanistan\",\"pattern\":\"93 XXX XXX XXX\",\"emoji\":\"🇦🇫\"},{\"phoneCode\":\"358 18\",\"code\":\"AX\",\"name\":\"Aland Islands\",\"pattern\":\"\",\"emoji\":\"🇦🇽\"},{\"phoneCode\":\"355\",\"code\":\"AL\",\"name\":\"Albania\",\"pattern\":\"355 XX XXX XXXX\",\"emoji\":\"🇦🇱\"},{\"phoneCode\":\"213\",\"code\":\"DZ\",\"name\":\"Algeria\",\"pattern\":\"213 XXX XX XX XX\",\"emoji\":\"🇩🇿\"},{\"phoneCode\":\"1 684\",\"code\":\"AS\",\"name\":\"American Samoa\",\"pattern\":\"1684 XXX XXXX\",\"emoji\":\"🇦🇸\"},{\"phoneCode\":\"376\",\"code\":\"AD\",\"name\":\"Andorra\",\"pattern\":\"376 XX XX XX\",\"emoji\":\"🇦🇩\"},{\"phoneCode\":\"244\",\"code\":\"AO\",\"name\":\"Angola\",\"pattern\":\"244 XXX XXX XXX\",\"emoji\":\"🇦🇴\"},{\"phoneCode\":\"1 264\",\"code\":\"AI\",\"name\":\"Anguilla\",\"pattern\":\"1264 XXX XXXX\",\"emoji\":\"🇦🇮\"},{\"phoneCode\":\"1 268\",\"code\":\"AG\",\"name\":\"Antigua & Barbuda\",\"pattern\":\"1268 XXX XXXX\",\"emoji\":\"🇦🇬\"},{\"phoneCode\":\"54\",\"code\":\"AR\",\"name\":\"Argentina\",\"pattern\":\"\",\"emoji\":\"🇦🇷\"},{\"phoneCode\":\"374\",\"code\":\"AM\",\"name\":\"Armenia\",\"pattern\":\"374 XX XXX XXX\",\"emoji\":\"🇦🇲\"},{\"phoneCode\":\"297\",\"code\":\"AW\",\"name\":\"Aruba\",\"pattern\":\"297 XXX XXXX\",\"emoji\":\"🇦🇼\"},{\"phoneCode\":\"247\",\"code\":\"SH\",\"name\":\"Ascension\",\"pattern\":\"290 XX XXX\",\"emoji\":\"🇸🇭\"},{\"phoneCode\":\"61\",\"code\":\"AU\",\"name\":\"Australia\",\"pattern\":\"61 XXX XXX XXX\",\"emoji\":\"🇦🇺\"},{\"phoneCode\":\"672\",\"code\":\"AU\",\"name\":\"Australian External Territories\",\"pattern\":\"61 XXX XXX XXX\",\"emoji\":\"🇦🇺\"},{\"phoneCode\":\"43\",\"code\":\"AT\",\"name\":\"Austria\",\"pattern\":\"\",\"emoji\":\"🇦🇹\"},{\"phoneCode\":\"994\",\"code\":\"AZ\",\"name\":\"Azerbaijan\",\"pattern\":\"994 XX XXX XX XX\",\"emoji\":\"🇦🇿\"},{\"phoneCode\":\"1 242\",\"code\":\"BS\",\"name\":\"Bahamas\",\"pattern\":\"1242 XXX XXXX\",\"emoji\":\"🇧🇸\"},{\"phoneCode\":\"973\",\"code\":\"BH\",\"name\":\"Bahrain\",\"pattern\":\"973 XXXX XXXX\",\"emoji\":\"🇧🇭\"},{\"phoneCode\":\"880\",\"code\":\"BD\",\"name\":\"Bangladesh\",\"pattern\":\"\",\"emoji\":\"🇧🇩\"},{\"phoneCode\":\"1 246\",\"code\":\"BB\",\"name\":\"Barbados\",\"pattern\":\"1246 XXX XXXX\",\"emoji\":\"🇧🇧\"},{\"phoneCode\":\"1 268\",\"code\":\"AG\",\"name\":\"Barbuda\",\"pattern\":\"1268 XXX XXXX\",\"emoji\":\"🇦🇬\"},{\"phoneCode\":\"375\",\"code\":\"BY\",\"name\":\"Belarus\",\"pattern\":\"375 XX XXX XXXX\",\"emoji\":\"🇧🇾\"},{\"phoneCode\":\"32\",\"code\":\"BE\",\"name\":\"Belgium\",\"pattern\":\"32 XXX XX XX XX\",\"emoji\":\"🇧🇪\"},{\"phoneCode\":\"501\",\"code\":\"BZ\",\"name\":\"Belize\",\"pattern\":\"\",\"emoji\":\"🇧🇿\"},{\"phoneCode\":\"229\",\"code\":\"BJ\",\"name\":\"Benin\",\"pattern\":\"229 XX XXX XXX\",\"emoji\":\"🇧🇯\"},{\"phoneCode\":\"1 441\",\"code\":\"BM\",\"name\":\"Bermuda\",\"pattern\":\"1441 XXX XXXX\",\"emoji\":\"🇧🇲\"},{\"phoneCode\":\"975\",\"code\":\"BT\",\"name\":\"Bhutan\",\"pattern\":\"\",\"emoji\":\"🇧🇹\"},{\"phoneCode\":\"591\",\"code\":\"BO\",\"name\":\"Bolivia\",\"pattern\":\"591 X XXX XXXX\",\"emoji\":\"🇧🇴\"},{\"phoneCode\":\"599 7\",\"code\":\"BQ\",\"name\":\"Caribbean Netherlands\",\"pattern\":\"\",\"emoji\":\"🇧🇶\"},{\"phoneCode\":\"387\",\"code\":\"BA\",\"name\":\"Bosnia & Herzegovina\",\"pattern\":\"\",\"emoji\":\"🇧🇦\"},{\"phoneCode\":\"267\",\"code\":\"BW\",\"name\":\"Botswana\",\"pattern\":\"267 XX XXX XXX\",\"emoji\":\"🇧🇼\"},{\"phoneCode\":\"55\",\"code\":\"BR\",\"name\":\"Brazil\",\"pattern\":\"55 XX XXXXX XXXX\",\"emoji\":\"🇧🇷\"},{\"phoneCode\":\"246\",\"code\":\"IO\",\"name\":\"British Indian Ocean Territory\",\"pattern\":\"246 XXX XXXX\",\"emoji\":\"🇮🇴\"},{\"phoneCode\":\"1 284\",\"code\":\"VG\",\"name\":\"British Virgin Islands\",\"pattern\":\"1284 XXX XXXX\",\"emoji\":\"🇻🇬\"},{\"phoneCode\":\"673\",\"code\":\"BN\",\"name\":\"Brunei\",\"pattern\":\"673 XXX XXXX\",\"emoji\":\"🇧🇳\"},{\"phoneCode\":\"359\",\"code\":\"BG\",\"name\":\"Bulgaria\",\"pattern\":\"\",\"emoji\":\"🇧🇬\"},{\"phoneCode\":\"226\",\"code\":\"BF\",\"name\":\"Burkina Faso\",\"pattern\":\"226 XX XX XX XX\",\"emoji\":\"🇧🇫\"},{\"phoneCode\":\"95\",\"code\":\"MM\",\"name\":\"Myanmar (Burma)\",\"pattern\":\"\",\"emoji\":\"🇲🇲\"},{\"phoneCode\":\"257\",\"code\":\"BI\",\"name\":\"Burundi\",\"pattern\":\"257 XX XX XXXX\",\"emoji\":\"🇧🇮\"},{\"phoneCode\":\"855\",\"code\":\"KH\",\"name\":\"Cambodia\",\"pattern\":\"\",\"emoji\":\"🇰🇭\"},{\"phoneCode\":\"237\",\"code\":\"CM\",\"name\":\"Cameroon\",\"pattern\":\"237 XXXX XXXX\",\"emoji\":\"🇨🇲\"},{\"phoneCode\":\"1\",\"code\":\"CA\",\"name\":\"Canada\",\"pattern\":\"1 XXX XXX XXXX\",\"emoji\":\"🇨🇦\"},{\"phoneCode\":\"238\",\"code\":\"CV\",\"name\":\"Cape Verde\",\"pattern\":\"238 XXX XXXX\",\"emoji\":\"🇨🇻\"},{\"phoneCode\":\"1 345\",\"code\":\"KY\",\"name\":\"Cayman Islands\",\"pattern\":\"1345 XXX XXXX\",\"emoji\":\"🇰🇾\"},{\"phoneCode\":\"236\",\"code\":\"CF\",\"name\":\"Central African Republic\",\"pattern\":\"236 XX XX XX XX\",\"emoji\":\"🇨🇫\"},{\"phoneCode\":\"235\",\"code\":\"TD\",\"name\":\"Chad\",\"pattern\":\"235 XX XX XX XX\",\"emoji\":\"🇹🇩\"},{\"phoneCode\":\"56\",\"code\":\"CL\",\"name\":\"Chile\",\"pattern\":\"56 X XXXX XXXX\",\"emoji\":\"🇨🇱\"},{\"phoneCode\":\"86\",\"code\":\"CN\",\"name\":\"China\",\"pattern\":\"86 XXX XXXX XXXX\",\"emoji\":\"🇨🇳\"},{\"phoneCode\":\"61\",\"code\":\"CX\",\"name\":\"Christmas Island\",\"pattern\":\"\",\"emoji\":\"🇨🇽\"},{\"phoneCode\":\"61\",\"code\":\"CC\",\"name\":\"Cocos (Keeling) Islands\",\"pattern\":\"\",\"emoji\":\"🇨🇨\"},{\"phoneCode\":\"57\",\"code\":\"CO\",\"name\":\"Colombia\",\"pattern\":\"57 XXX XXX XXXX\",\"emoji\":\"🇨🇴\"},{\"phoneCode\":\"269\",\"code\":\"KM\",\"name\":\"Comoros\",\"pattern\":\"269 XXX XXXX\",\"emoji\":\"🇰🇲\"},{\"phoneCode\":\"242\",\"code\":\"CG\",\"name\":\"Congo - Brazzaville\",\"pattern\":\"242 XX XXX XXXX\",\"emoji\":\"🇨🇬\"},{\"phoneCode\":\"243\",\"code\":\"CD\",\"name\":\"Congo - Kinshasa\",\"pattern\":\"243 XX XXX XXXX\",\"emoji\":\"🇨🇩\"},{\"phoneCode\":\"682\",\"code\":\"CK\",\"name\":\"Cook Islands\",\"pattern\":\"\",\"emoji\":\"🇨🇰\"},{\"phoneCode\":\"506\",\"code\":\"CR\",\"name\":\"Costa Rica\",\"pattern\":\"\",\"emoji\":\"🇨🇷\"},{\"phoneCode\":\"225\",\"code\":\"CI\",\"name\":\"Cote dIvoire\",\"pattern\":\"225 XX XXX XXX\",\"emoji\":\"🇨🇮\"},{\"phoneCode\":\"385\",\"code\":\"HR\",\"name\":\"Croatia\",\"pattern\":\"\",\"emoji\":\"🇭🇷\"},{\"phoneCode\":\"53\",\"code\":\"CU\",\"name\":\"Cuba\",\"pattern\":\"53 XXXX XXXX\",\"emoji\":\"🇨🇺\"},{\"phoneCode\":\"599 9\",\"code\":\"CW\",\"name\":\"Curacao\",\"pattern\":\"\",\"emoji\":\"🇨🇼\"},{\"phoneCode\":\"357\",\"code\":\"CY\",\"name\":\"Cyprus\",\"pattern\":\"357 XXXX XXXX\",\"emoji\":\"🇨🇾\"},{\"phoneCode\":\"420\",\"code\":\"CZ\",\"name\":\"Czech Republic\",\"pattern\":\"\",\"emoji\":\"🇨🇿\"},{\"phoneCode\":\"45\",\"code\":\"DK\",\"name\":\"Denmark\",\"pattern\":\"45 XXXX XXXX\",\"emoji\":\"🇩🇰\"},{\"phoneCode\":\"246\",\"code\":\"DG\",\"name\":\"Diego Garcia\",\"pattern\":\"\",\"emoji\":\"🇩🇬\"},{\"phoneCode\":\"253\",\"code\":\"DJ\",\"name\":\"Djibouti\",\"pattern\":\"253 XX XX XX XX\",\"emoji\":\"🇩🇯\"},{\"phoneCode\":\"1 767\",\"code\":\"DM\",\"name\":\"Dominica\",\"pattern\":\"1767 XXX XXXX\",\"emoji\":\"🇩🇲\"},{\"phoneCode\":\"1 809 and 1 829\",\"code\":\"DO\",\"name\":\"Dominican Republic\",\"pattern\":\"1 XXX XXX XXXX\",\"emoji\":\"🇩🇴\"},{\"phoneCode\":\"670\",\"code\":\"TL\",\"name\":\"Timor-Leste\",\"pattern\":\"\",\"emoji\":\"🇹🇱\"},{\"phoneCode\":\"593\",\"code\":\"EC\",\"name\":\"Ecuador\",\"pattern\":\"\",\"emoji\":\"🇪🇨\"},{\"phoneCode\":\"20\",\"code\":\"EG\",\"name\":\"Egypt\",\"pattern\":\"20 XX XXX XXXX\",\"emoji\":\"🇪🇬\"},{\"phoneCode\":\"503\",\"code\":\"SV\",\"name\":\"El Salvador\",\"pattern\":\"503 XXXX XXXX\",\"emoji\":\"🇸🇻\"},{\"phoneCode\":\"240\",\"code\":\"GQ\",\"name\":\"Equatorial Guinea\",\"pattern\":\"240 XXX XXX XXX\",\"emoji\":\"🇬🇶\"},{\"phoneCode\":\"291\",\"code\":\"ER\",\"name\":\"Eritrea\",\"pattern\":\"291 X XXX XXX\",\"emoji\":\"🇪🇷\"},{\"phoneCode\":\"372\",\"code\":\"EE\",\"name\":\"Estonia\",\"pattern\":\"\",\"emoji\":\"🇪🇪\"},{\"phoneCode\":\"251\",\"code\":\"ET\",\"name\":\"Ethiopia\",\"pattern\":\"251 XX XXX XXXX\",\"emoji\":\"🇪🇹\"},{\"phoneCode\":\"500\",\"code\":\"FK\",\"name\":\"Falkland Islands\",\"pattern\":\"\",\"emoji\":\"🇫🇰\"},{\"phoneCode\":\"298\",\"code\":\"FO\",\"name\":\"Faroe Islands\",\"pattern\":\"298 XXX XXX\",\"emoji\":\"🇫🇴\"},{\"phoneCode\":\"679\",\"code\":\"FJ\",\"name\":\"Fiji\",\"pattern\":\"\",\"emoji\":\"🇫🇯\"},{\"phoneCode\":\"358\",\"code\":\"FI\",\"name\":\"Finland\",\"pattern\":\"\",\"emoji\":\"🇫🇮\"},{\"phoneCode\":\"33\",\"code\":\"FR\",\"name\":\"France\",\"pattern\":\"33 X XX XX XX XX\",\"emoji\":\"🇫🇷\"},{\"phoneCode\":\"594\",\"code\":\"GF\",\"name\":\"French Guiana\",\"pattern\":\"\",\"emoji\":\"🇬🇫\"},{\"phoneCode\":\"689\",\"code\":\"PF\",\"name\":\"French Polynesia\",\"pattern\":\"\",\"emoji\":\"🇵🇫\"},{\"phoneCode\":\"241\",\"code\":\"GA\",\"name\":\"Gabon\",\"pattern\":\"241 X XX XX XX\",\"emoji\":\"🇬🇦\"},{\"phoneCode\":\"220\",\"code\":\"GM\",\"name\":\"Gambia\",\"pattern\":\"220 XXX XXXX\",\"emoji\":\"🇬🇲\"},{\"phoneCode\":\"995\",\"code\":\"GE\",\"name\":\"Georgia\",\"pattern\":\"\",\"emoji\":\"🇬🇪\"},{\"phoneCode\":\"49\",\"code\":\"DE\",\"name\":\"Germany\",\"pattern\":\"49 XXX XXXXXXXX\",\"emoji\":\"🇩🇪\"},{\"phoneCode\":\"233\",\"code\":\"GH\",\"name\":\"Ghana\",\"pattern\":\"\",\"emoji\":\"🇬🇭\"},{\"phoneCode\":\"350\",\"code\":\"GI\",\"name\":\"Gibraltar\",\"pattern\":\"350 XXXX XXXX\",\"emoji\":\"🇬🇮\"},{\"phoneCode\":\"30\",\"code\":\"GR\",\"name\":\"Greece\",\"pattern\":\"30 XX XXXX XXXX\",\"emoji\":\"🇬🇷\"},{\"phoneCode\":\"299\",\"code\":\"GL\",\"name\":\"Greenland\",\"pattern\":\"299 XXX XXX\",\"emoji\":\"🇬🇱\"},{\"phoneCode\":\"1 473\",\"code\":\"GD\",\"name\":\"Grenada\",\"pattern\":\"1473 XXX XXXX\",\"emoji\":\"🇬🇩\"},{\"phoneCode\":\"590\",\"code\":\"GP\",\"name\":\"Guadeloupe\",\"pattern\":\"\",\"emoji\":\"🇬🇵\"},{\"phoneCode\":\"1 671\",\"code\":\"GU\",\"name\":\"Guam\",\"pattern\":\"1671 XXX XXXX\",\"emoji\":\"🇬🇺\"},{\"phoneCode\":\"502\",\"code\":\"GT\",\"name\":\"Guatemala\",\"pattern\":\"502 X XXX XXXX\",\"emoji\":\"🇬🇹\"},{\"phoneCode\":\"44\",\"code\":\"GG\",\"name\":\"Guernsey\",\"pattern\":\"\",\"emoji\":\"🇬🇬\"},{\"phoneCode\":\"224\",\"code\":\"GN\",\"name\":\"Guinea\",\"pattern\":\"224 XXX XXX XXX\",\"emoji\":\"🇬🇳\"},{\"phoneCode\":\"245\",\"code\":\"GW\",\"name\":\"Guinea-Bissau\",\"pattern\":\"245 XXX XXXX\",\"emoji\":\"🇬🇼\"},{\"phoneCode\":\"592\",\"code\":\"GY\",\"name\":\"Guyana\",\"pattern\":\"\",\"emoji\":\"🇬🇾\"},{\"phoneCode\":\"509\",\"code\":\"HT\",\"name\":\"Haiti\",\"pattern\":\"\",\"emoji\":\"🇭🇹\"},{\"phoneCode\":\"504\",\"code\":\"HN\",\"name\":\"Honduras\",\"pattern\":\"504 XXXX XXXX\",\"emoji\":\"🇭🇳\"},{\"phoneCode\":\"852\",\"code\":\"HK\",\"name\":\"Hong Kong SAR China\",\"pattern\":\"\",\"emoji\":\"🇭🇰\"},{\"phoneCode\":\"36\",\"code\":\"HU\",\"name\":\"Hungary\",\"pattern\":\"36 XX XXX XXXX\",\"emoji\":\"🇭🇺\"},{\"phoneCode\":\"354\",\"code\":\"IS\",\"name\":\"Iceland\",\"pattern\":\"354 XXX XXXX\",\"emoji\":\"🇮🇸\"},{\"phoneCode\":\"91\",\"code\":\"IN\",\"name\":\"India\",\"pattern\":\"91 XXXXX XXXXX\",\"emoji\":\"🇮🇳\"},{\"phoneCode\":\"62\",\"code\":\"ID\",\"name\":\"Indonesia\",\"pattern\":\"\",\"emoji\":\"🇮🇩\"},{\"phoneCode\":\"98\",\"code\":\"IR\",\"name\":\"Iran\",\"pattern\":\"98 XXX XXX XXXX\",\"emoji\":\"🇮🇷\"},{\"phoneCode\":\"964\",\"code\":\"IQ\",\"name\":\"Iraq\",\"pattern\":\"964 XXX XXX XXXX\",\"emoji\":\"🇮🇶\"},{\"phoneCode\":\"353\",\"code\":\"IE\",\"name\":\"Ireland\",\"pattern\":\"353 XX XXX XXXX\",\"emoji\":\"🇮🇪\"},{\"phoneCode\":\"972\",\"code\":\"IL\",\"name\":\"Israel\",\"pattern\":\"972 XX XXX XXXX\",\"emoji\":\"🇮🇱\"},{\"phoneCode\":\"39\",\"code\":\"IT\",\"name\":\"Italy\",\"pattern\":\"39 XXX XXX XXXX\",\"emoji\":\"🇮🇹\"},{\"phoneCode\":\"1 876\",\"code\":\"JM\",\"name\":\"Jamaica\",\"pattern\":\"1876 XXX XXXX\",\"emoji\":\"🇯🇲\"},{\"phoneCode\":\"47 79\",\"code\":\"SJ\",\"name\":\"Svalbard & Jan Mayen\",\"pattern\":\"\",\"emoji\":\"🇸🇯\"},{\"phoneCode\":\"81\",\"code\":\"JP\",\"name\":\"Japan\",\"pattern\":\"81 XX XXXX XXXX\",\"emoji\":\"🇯🇵\"},{\"phoneCode\":\"44\",\"code\":\"JE\",\"name\":\"Jersey\",\"pattern\":\"\",\"emoji\":\"🇯🇪\"},{\"phoneCode\":\"962\",\"code\":\"JO\",\"name\":\"Jordan\",\"pattern\":\"962 X XXXX XXXX\",\"emoji\":\"🇯🇴\"},{\"phoneCode\":\"7 7\",\"code\":\"KZ\",\"name\":\"Kazakhstan\",\"pattern\":\"7 XXX XXX XX XX\",\"emoji\":\"🇰🇿\"},{\"phoneCode\":\"254\",\"code\":\"KE\",\"name\":\"Kenya\",\"pattern\":\"254 XXX XXX XXX\",\"emoji\":\"🇰🇪\"},{\"phoneCode\":\"686\",\"code\":\"KI\",\"name\":\"Kiribati\",\"pattern\":\"\",\"emoji\":\"🇰🇮\"},{\"phoneCode\":\"850\",\"code\":\"KP\",\"name\":\"North Korea\",\"pattern\":\"\",\"emoji\":\"🇰🇵\"},{\"phoneCode\":\"82\",\"code\":\"KR\",\"name\":\"South Korea\",\"pattern\":\"\",\"emoji\":\"🇰🇷\"},{\"phoneCode\":\"965\",\"code\":\"KW\",\"name\":\"Kuwait\",\"pattern\":\"965 XXXX XXXX\",\"emoji\":\"🇰🇼\"},{\"phoneCode\":\"996\",\"code\":\"KG\",\"name\":\"Kyrgyzstan\",\"pattern\":\"\",\"emoji\":\"🇰🇬\"},{\"phoneCode\":\"856\",\"code\":\"LA\",\"name\":\"Laos\",\"pattern\":\"\",\"emoji\":\"🇱🇦\"},{\"phoneCode\":\"371\",\"code\":\"LV\",\"name\":\"Latvia\",\"pattern\":\"371 XXX XXXXX\",\"emoji\":\"🇱🇻\"},{\"phoneCode\":\"961\",\"code\":\"LB\",\"name\":\"Lebanon\",\"pattern\":\"\",\"emoji\":\"🇱🇧\"},{\"phoneCode\":\"266\",\"code\":\"LS\",\"name\":\"Lesotho\",\"pattern\":\"266 XX XXX XXX\",\"emoji\":\"🇱🇸\"},{\"phoneCode\":\"231\",\"code\":\"LR\",\"name\":\"Liberia\",\"pattern\":\"\",\"emoji\":\"🇱🇷\"},{\"phoneCode\":\"218\",\"code\":\"LY\",\"name\":\"Libya\",\"pattern\":\"218 XX XXX XXXX\",\"emoji\":\"🇱🇾\"},{\"phoneCode\":\"423\",\"code\":\"LI\",\"name\":\"Liechtenstein\",\"pattern\":\"\",\"emoji\":\"🇱🇮\"},{\"phoneCode\":\"370\",\"code\":\"LT\",\"name\":\"Lithuania\",\"pattern\":\"370 XXX XXXXX\",\"emoji\":\"🇱🇹\"},{\"phoneCode\":\"352\",\"code\":\"LU\",\"name\":\"Luxembourg\",\"pattern\":\"\",\"emoji\":\"🇱🇺\"},{\"phoneCode\":\"853\",\"code\":\"MO\",\"name\":\"Macau SAR China\",\"pattern\":\"\",\"emoji\":\"🇲🇴\"},{\"phoneCode\":\"389\",\"code\":\"MK\",\"name\":\"Macedonia\",\"pattern\":\"\",\"emoji\":\"🇲🇰\"},{\"phoneCode\":\"261\",\"code\":\"MG\",\"name\":\"Madagascar\",\"pattern\":\"261 XX XX XXX XX\",\"emoji\":\"🇲🇬\"},{\"phoneCode\":\"265\",\"code\":\"MW\",\"name\":\"Malawi\",\"pattern\":\"\",\"emoji\":\"🇲🇼\"},{\"phoneCode\":\"60\",\"code\":\"MY\",\"name\":\"Malaysia\",\"pattern\":\"\",\"emoji\":\"🇲🇾\"},{\"phoneCode\":\"960\",\"code\":\"MV\",\"name\":\"Maldives\",\"pattern\":\"\",\"emoji\":\"🇲🇻\"},{\"phoneCode\":\"223\",\"code\":\"ML\",\"name\":\"Mali\",\"pattern\":\"223 XXXX XXXX\",\"emoji\":\"🇲🇱\"},{\"phoneCode\":\"356\",\"code\":\"MT\",\"name\":\"Malta\",\"pattern\":\"356 XX XX XX XX\",\"emoji\":\"🇲🇹\"},{\"phoneCode\":\"692\",\"code\":\"MH\",\"name\":\"Marshall Islands\",\"pattern\":\"\",\"emoji\":\"🇲🇭\"},{\"phoneCode\":\"596\",\"code\":\"MQ\",\"name\":\"Martinique\",\"pattern\":\"\",\"emoji\":\"🇲🇶\"},{\"phoneCode\":\"222\",\"code\":\"MR\",\"name\":\"Mauritania\",\"pattern\":\"222 XXXX XXXX\",\"emoji\":\"🇲🇷\"},{\"phoneCode\":\"230\",\"code\":\"MU\",\"name\":\"Mauritius\",\"pattern\":\"\",\"emoji\":\"🇲🇺\"},{\"phoneCode\":\"262\",\"code\":\"YT\",\"name\":\"Mayotte\",\"pattern\":\"\",\"emoji\":\"🇾🇹\"},{\"phoneCode\":\"52\",\"code\":\"MX\",\"name\":\"Mexico\",\"pattern\":\"\",\"emoji\":\"🇲🇽\"},{\"phoneCode\":\"691\",\"code\":\"FM\",\"name\":\"Micronesia\",\"pattern\":\"\",\"emoji\":\"🇫🇲\"},{\"phoneCode\":\"373\",\"code\":\"MD\",\"name\":\"Moldova\",\"pattern\":\"373 XX XXX XXX\",\"emoji\":\"🇲🇩\"},{\"phoneCode\":\"377\",\"code\":\"MC\",\"name\":\"Monaco\",\"pattern\":\"377 XXXX XXXX\",\"emoji\":\"🇲🇨\"},{\"phoneCode\":\"976\",\"code\":\"MN\",\"name\":\"Mongolia\",\"pattern\":\"\",\"emoji\":\"🇲🇳\"},{\"phoneCode\":\"382\",\"code\":\"ME\",\"name\":\"Montenegro\",\"pattern\":\"\",\"emoji\":\"🇲🇪\"},{\"phoneCode\":\"1 664\",\"code\":\"MS\",\"name\":\"Montserrat\",\"pattern\":\"1664 XXX XXXX\",\"emoji\":\"🇲🇸\"},{\"phoneCode\":\"212\",\"code\":\"MA\",\"name\":\"Morocco\",\"pattern\":\"212 XX XXX XXXX\",\"emoji\":\"🇲🇦\"},{\"phoneCode\":\"258\",\"code\":\"MZ\",\"name\":\"Mozambique\",\"pattern\":\"258 XX XXX XXXX\",\"emoji\":\"🇲🇿\"},{\"phoneCode\":\"264\",\"code\":\"NA\",\"name\":\"Namibia\",\"pattern\":\"264 XX XXX XXXX\",\"emoji\":\"🇳🇦\"},{\"phoneCode\":\"674\",\"code\":\"NR\",\"name\":\"Nauru\",\"pattern\":\"\",\"emoji\":\"🇳🇷\"},{\"phoneCode\":\"977\",\"code\":\"NP\",\"name\":\"Nepal\",\"pattern\":\"\",\"emoji\":\"🇳🇵\"},{\"phoneCode\":\"31\",\"code\":\"NL\",\"name\":\"Netherlands\",\"pattern\":\"31 X XX XX XX XX\",\"emoji\":\"🇳🇱\"},{\"phoneCode\":\"687\",\"code\":\"NC\",\"name\":\"New Caledonia\",\"pattern\":\"\",\"emoji\":\"🇳🇨\"},{\"phoneCode\":\"64\",\"code\":\"NZ\",\"name\":\"New Zealand\",\"pattern\":\"\",\"emoji\":\"🇳🇿\"},{\"phoneCode\":\"505\",\"code\":\"NI\",\"name\":\"Nicaragua\",\"pattern\":\"505 XXXX XXXX\",\"emoji\":\"🇳🇮\"},{\"phoneCode\":\"227\",\"code\":\"NE\",\"name\":\"Niger\",\"pattern\":\"227 XX XX XX XX\",\"emoji\":\"🇳🇪\"},{\"phoneCode\":\"234\",\"code\":\"NG\",\"name\":\"Nigeria\",\"pattern\":\"\",\"emoji\":\"🇳🇬\"},{\"phoneCode\":\"683\",\"code\":\"NU\",\"name\":\"Niue\",\"pattern\":\"\",\"emoji\":\"🇳🇺\"},{\"phoneCode\":\"672\",\"code\":\"NF\",\"name\":\"Norfolk Island\",\"pattern\":\"\",\"emoji\":\"🇳🇫\"},{\"phoneCode\":\"1 670\",\"code\":\"MP\",\"name\":\"Northern Mariana Islands\",\"pattern\":\"1670 XXX XXXX\",\"emoji\":\"🇲🇵\"},{\"phoneCode\":\"47\",\"code\":\"NO\",\"name\":\"Norway\",\"pattern\":\"47 XXXX XXXX\",\"emoji\":\"🇳🇴\"},{\"phoneCode\":\"968\",\"code\":\"OM\",\"name\":\"Oman\",\"pattern\":\"968 XXXX XXXX\",\"emoji\":\"🇴🇲\"},{\"phoneCode\":\"92\",\"code\":\"PK\",\"name\":\"Pakistan\",\"pattern\":\"92 XXX XXX XXXX\",\"emoji\":\"🇵🇰\"},{\"phoneCode\":\"680\",\"code\":\"PW\",\"name\":\"Palau\",\"pattern\":\"\",\"emoji\":\"🇵🇼\"},{\"phoneCode\":\"970\",\"code\":\"PS\",\"name\":\"Palestinian Territories\",\"pattern\":\"970 XXX XX XXXX\",\"emoji\":\"🇵🇸\"},{\"phoneCode\":\"507\",\"code\":\"PA\",\"name\":\"Panama\",\"pattern\":\"507 XXXX XXXX\",\"emoji\":\"🇵🇦\"},{\"phoneCode\":\"675\",\"code\":\"PG\",\"name\":\"Papua New Guinea\",\"pattern\":\"\",\"emoji\":\"🇵🇬\"},{\"phoneCode\":\"595\",\"code\":\"PY\",\"name\":\"Paraguay\",\"pattern\":\"595 XXX XXX XXX\",\"emoji\":\"🇵🇾\"},{\"phoneCode\":\"51\",\"code\":\"PE\",\"name\":\"Peru\",\"pattern\":\"51 XXX XXX XXX\",\"emoji\":\"🇵🇪\"},{\"phoneCode\":\"63\",\"code\":\"PH\",\"name\":\"Philippines\",\"pattern\":\"63 XXX XXX XXXX\",\"emoji\":\"🇵🇭\"},{\"phoneCode\":\"64\",\"code\":\"PN\",\"name\":\"Pitcairn Islands\",\"pattern\":\"\",\"emoji\":\"🇵🇳\"},{\"phoneCode\":\"48\",\"code\":\"PL\",\"name\":\"Poland\",\"pattern\":\"48 XXX XXX XXX\",\"emoji\":\"🇵🇱\"},{\"phoneCode\":\"351\",\"code\":\"PT\",\"name\":\"Portugal\",\"pattern\":\"351 X XXXX XXXX\",\"emoji\":\"🇵🇹\"},{\"phoneCode\":\"1 787 and 1 939\",\"code\":\"PR\",\"name\":\"Puerto Rico\",\"pattern\":\"1 XXX XXX XXXX\",\"emoji\":\"🇵🇷\"},{\"phoneCode\":\"974\",\"code\":\"QA\",\"name\":\"Qatar\",\"pattern\":\"\",\"emoji\":\"🇶🇦\"},{\"phoneCode\":\"262\",\"code\":\"RE\",\"name\":\"Reunion\",\"pattern\":\"262 XXX XXX XXX\",\"emoji\":\"🇷🇪\"},{\"phoneCode\":\"40\",\"code\":\"RO\",\"name\":\"Romania\",\"pattern\":\"40 XXX XXX XXX\",\"emoji\":\"🇷🇴\"},{\"phoneCode\":\"7\",\"code\":\"RU\",\"name\":\"Russia\",\"pattern\":\"7 XXX XXX XX XX\",\"emoji\":\"🇷🇺\"},{\"phoneCode\":\"250\",\"code\":\"RW\",\"name\":\"Rwanda\",\"pattern\":\"250 XXX XXX XXX\",\"emoji\":\"🇷🇼\"},{\"phoneCode\":\"590\",\"code\":\"BL\",\"name\":\"St. Barthelemy\",\"pattern\":\"\",\"emoji\":\"🇧🇱\"},{\"phoneCode\":\"290\",\"code\":\"SH\",\"name\":\"St. Helena\",\"pattern\":\"290 XX XXX\",\"emoji\":\"🇸🇭\"},{\"phoneCode\":\"1 869\",\"code\":\"KN\",\"name\":\"St. Kitts & Nevis\",\"pattern\":\"1869 XXX XXXX\",\"emoji\":\"🇰🇳\"},{\"phoneCode\":\"1 758\",\"code\":\"LC\",\"name\":\"St. Lucia\",\"pattern\":\"1758 XXX XXXX\",\"emoji\":\"🇱🇨\"},{\"phoneCode\":\"590\",\"code\":\"MF\",\"name\":\"St. Martin (France)\",\"pattern\":\"\",\"emoji\":\"🇲🇫\"},{\"phoneCode\":\"508\",\"code\":\"PM\",\"name\":\"St. Pierre and Miquelon\",\"pattern\":\"\",\"emoji\":\"🇵🇲\"},{\"phoneCode\":\"1 784\",\"code\":\"VC\",\"name\":\"St. Vincent and the Grenadines\",\"pattern\":\"1784 XXX XXXX\",\"emoji\":\"🇻🇨\"},{\"phoneCode\":\"685\",\"code\":\"WS\",\"name\":\"Samoa\",\"pattern\":\"\",\"emoji\":\"🇼🇸\"},{\"phoneCode\":\"378\",\"code\":\"SM\",\"name\":\"San Marino\",\"pattern\":\"378 XXX XXX XXXX\",\"emoji\":\"🇸🇲\"},{\"phoneCode\":\"239\",\"code\":\"ST\",\"name\":\"São Tome & Principe\",\"pattern\":\"239 XX XXXXX\",\"emoji\":\"🇸🇹\"},{\"phoneCode\":\"966\",\"code\":\"SA\",\"name\":\"Saudi Arabia\",\"pattern\":\"\",\"emoji\":\"🇸🇦\"},{\"phoneCode\":\"221\",\"code\":\"SN\",\"name\":\"Senegal\",\"pattern\":\"221 XX XXX XXXX\",\"emoji\":\"🇸🇳\"},{\"phoneCode\":\"381\",\"code\":\"RS\",\"name\":\"Serbia\",\"pattern\":\"381 XX XXX XXXX\",\"emoji\":\"🇷🇸\"},{\"phoneCode\":\"248\",\"code\":\"SC\",\"name\":\"Seychelles\",\"pattern\":\"248 X XX XX XX\",\"emoji\":\"🇸🇨\"},{\"phoneCode\":\"232\",\"code\":\"SL\",\"name\":\"Sierra Leone\",\"pattern\":\"232 XX XXX XXX\",\"emoji\":\"🇸🇱\"},{\"phoneCode\":\"65\",\"code\":\"SG\",\"name\":\"Singapore\",\"pattern\":\"65 XXXX XXXX\",\"emoji\":\"🇸🇬\"},{\"phoneCode\":\"599 3\",\"code\":\"BQ\",\"name\":\"Sint Eustatius\",\"pattern\":\"\",\"emoji\":\"🇧🇶\"},{\"phoneCode\":\"1 721\",\"code\":\"SX\",\"name\":\"Sint Maarten\",\"pattern\":\"1721 XXX XXXX\",\"emoji\":\"🇸🇽\"},{\"phoneCode\":\"421\",\"code\":\"SK\",\"name\":\"Slovakia\",\"pattern\":\"\",\"emoji\":\"🇸🇰\"},{\"phoneCode\":\"386\",\"code\":\"SI\",\"name\":\"Slovenia\",\"pattern\":\"\",\"emoji\":\"🇸🇮\"},{\"phoneCode\":\"677\",\"code\":\"SB\",\"name\":\"Solomon Islands\",\"pattern\":\"\",\"emoji\":\"🇸🇧\"},{\"phoneCode\":\"252\",\"code\":\"SO\",\"name\":\"Somalia\",\"pattern\":\"252 XX XXX XXX\",\"emoji\":\"🇸🇴\"},{\"phoneCode\":\"27\",\"code\":\"ZA\",\"name\":\"South Africa\",\"pattern\":\"27 XX XXX XXXX\",\"emoji\":\"🇿🇦\"},{\"phoneCode\":\"500\",\"code\":\"GS\",\"name\":\"South Georgia & South Sandwich Islands\",\"pattern\":\"\",\"emoji\":\"🇬🇸\"},{\"phoneCode\":\"995 34\",\"code\":\"\",\"name\":\"South Ossetia\",\"pattern\":\"\",\"emoji\":\"\"},{\"phoneCode\":\"211\",\"code\":\"SS\",\"name\":\"South Sudan\",\"pattern\":\"211 XX XXX XXXX\",\"emoji\":\"🇸🇸\"},{\"phoneCode\":\"34\",\"code\":\"ES\",\"name\":\"Spain\",\"pattern\":\"34 XXX XXX XXX\",\"emoji\":\"🇪🇸\"},{\"phoneCode\":\"94\",\"code\":\"LK\",\"name\":\"Sri Lanka\",\"pattern\":\"94 XX XXX XXXX\",\"emoji\":\"🇱🇰\"},{\"phoneCode\":\"249\",\"code\":\"SD\",\"name\":\"Sudan\",\"pattern\":\"249 XX XXX XXXX\",\"emoji\":\"🇸🇩\"},{\"phoneCode\":\"597\",\"code\":\"SR\",\"name\":\"Suriname\",\"pattern\":\"597 XXX XXXX\",\"emoji\":\"🇸🇷\"},{\"phoneCode\":\"47 79\",\"code\":\"SJ\",\"name\":\"Svalbard\",\"pattern\":\"\",\"emoji\":\"🇸🇯\"},{\"phoneCode\":\"268\",\"code\":\"SZ\",\"name\":\"Swaziland\",\"pattern\":\"268 XXXX XXXX\",\"emoji\":\"🇸🇿\"},{\"phoneCode\":\"46\",\"code\":\"SE\",\"name\":\"Sweden\",\"pattern\":\"46 XX XXX XXXX\",\"emoji\":\"🇸🇪\"},{\"phoneCode\":\"41\",\"code\":\"CH\",\"name\":\"Switzerland\",\"pattern\":\"41 XX XXX XXXX\",\"emoji\":\"🇨🇭\"},{\"phoneCode\":\"963\",\"code\":\"SY\",\"name\":\"Syria\",\"pattern\":\"\",\"emoji\":\"🇸🇾\"},{\"phoneCode\":\"886\",\"code\":\"TW\",\"name\":\"Taiwan\",\"pattern\":\"\",\"emoji\":\"🇹🇼\"},{\"phoneCode\":\"992\",\"code\":\"TJ\",\"name\":\"Tajikistan\",\"pattern\":\"\",\"emoji\":\"🇹🇯\"},{\"phoneCode\":\"255\",\"code\":\"TZ\",\"name\":\"Tanzania\",\"pattern\":\"255 XX XXX XXXX\",\"emoji\":\"🇹🇿\"},{\"phoneCode\":\"66\",\"code\":\"TH\",\"name\":\"Thailand\",\"pattern\":\"66 X XXXX XXXX\",\"emoji\":\"🇹🇭\"},{\"phoneCode\":\"228\",\"code\":\"TG\",\"name\":\"Togo\",\"pattern\":\"228 XX XXX XXX\",\"emoji\":\"🇹🇬\"},{\"phoneCode\":\"690\",\"code\":\"TK\",\"name\":\"Tokelau\",\"pattern\":\"\",\"emoji\":\"🇹🇰\"},{\"phoneCode\":\"676\",\"code\":\"TO\",\"name\":\"Tonga\",\"pattern\":\"\",\"emoji\":\"🇹🇴\"},{\"phoneCode\":\"1 868\",\"code\":\"TT\",\"name\":\"Trinidad & Tobago\",\"pattern\":\"1868 XXX XXXX\",\"emoji\":\"🇹🇹\"},{\"phoneCode\":\"216\",\"code\":\"TN\",\"name\":\"Tunisia\",\"pattern\":\"216 XX XXX XXX\",\"emoji\":\"🇹🇳\"},{\"phoneCode\":\"90\",\"code\":\"TR\",\"name\":\"Turkey\",\"pattern\":\"90 XXX XXX XXXX\",\"emoji\":\"🇹🇷\"},{\"phoneCode\":\"993\",\"code\":\"TM\",\"name\":\"Turkmenistan\",\"pattern\":\"993 XX XXXXXX\",\"emoji\":\"🇹🇲\"},{\"phoneCode\":\"1 649\",\"code\":\"TC\",\"name\":\"Turks & Caicos Islands\",\"pattern\":\"1649 XXX XXXX\",\"emoji\":\"🇹🇨\"},{\"phoneCode\":\"688\",\"code\":\"TV\",\"name\":\"Tuvalu\",\"pattern\":\"\",\"emoji\":\"🇹🇻\"},{\"phoneCode\":\"256\",\"code\":\"UG\",\"name\":\"Uganda\",\"pattern\":\"256 XX XXX XXXX\",\"emoji\":\"🇺🇬\"},{\"phoneCode\":\"380\",\"code\":\"UA\",\"name\":\"Ukraine\",\"pattern\":\"380 XX XXX XX XX\",\"emoji\":\"🇺🇦\"},{\"phoneCode\":\"971\",\"code\":\"AE\",\"name\":\"United Arab Emirates\",\"pattern\":\"971 XX XXX XXXX\",\"emoji\":\"🇦🇪\"},{\"phoneCode\":\"44\",\"code\":\"GB\",\"name\":\"United Kingdom\",\"pattern\":\"44 XXXX XXXXXX\",\"emoji\":\"🇬🇧\"},{\"phoneCode\":\"1\",\"code\":\"US\",\"name\":\"United States\",\"pattern\":\"1 XXX XXX XXXX\",\"emoji\":\"🇺🇸\"},{\"phoneCode\":\"598\",\"code\":\"UY\",\"name\":\"Uruguay\",\"pattern\":\"598 XXXX XXXX\",\"emoji\":\"🇺🇾\"},{\"phoneCode\":\"1 340\",\"code\":\"VI\",\"name\":\"U.S. Virgin Islands\",\"pattern\":\"1340 XXX XXXX\",\"emoji\":\"🇻🇮\"},{\"phoneCode\":\"998\",\"code\":\"UZ\",\"name\":\"Uzbekistan\",\"pattern\":\"998 XX XXXXXXX\",\"emoji\":\"🇺🇿\"},{\"phoneCode\":\"678\",\"code\":\"VU\",\"name\":\"Vanuatu\",\"pattern\":\"\",\"emoji\":\"🇻🇺\"},{\"phoneCode\":\"58\",\"code\":\"VE\",\"name\":\"Venezuela\",\"pattern\":\"58 XXX XXX XXXX\",\"emoji\":\"🇻🇪\"},{\"phoneCode\":\"39 06 698\",\"code\":\"VA\",\"name\":\"Vatican City\",\"pattern\":\"\",\"emoji\":\"🇻🇦\"},{\"phoneCode\":\"84\",\"code\":\"VN\",\"name\":\"Vietnam\",\"pattern\":\"\",\"emoji\":\"🇻🇳\"},{\"phoneCode\":\"681\",\"code\":\"WF\",\"name\":\"Wallis & Futuna\",\"pattern\":\"\",\"emoji\":\"🇼🇫\"},{\"phoneCode\":\"967\",\"code\":\"YE\",\"name\":\"Yemen\",\"pattern\":\"967 XXX XXX XXX\",\"emoji\":\"🇾🇪\"},{\"phoneCode\":\"260\",\"code\":\"ZM\",\"name\":\"Zambia\",\"pattern\":\"260 XX XXX XXXX\",\"emoji\":\"🇿🇲\"},{\"phoneCode\":\"255\",\"code\":\"\",\"name\":\"Zanzibar\",\"pattern\":\"\",\"emoji\":\"\"},{\"phoneCode\":\"263\",\"code\":\"ZW\",\"name\":\"Zimbabwe\",\"pattern\":\"263 XX XXX XXXX\",\"emoji\":\"🇿🇼\"}];\r\nconst PhoneCodesMain: {[phoneCode: string]: Country} = {\r\n '1': Countries.find(c => c.name === 'United States'),\r\n '44': Countries.find(c => c.name === 'United Kingdom'),\r\n '61': Countries.find(c => c.name === 'Australia'),\r\n '64': Countries.find(c => c.name === 'New Zealand'),\r\n '246': Countries.find(c => c.name === 'Diego Garcia'),\r\n '255': Countries.find(c => c.name === 'Tanzania'),\r\n '262': Countries.find(c => c.name === 'Reunion'),\r\n '500': Countries.find(c => c.name === 'Falkland Islands'),\r\n '590': Countries.find(c => c.name === 'Guadeloupe'),\r\n '672': Countries.find(c => c.name === 'Norfolk Island'),\r\n '1 268': Countries.find(c => c.name === 'Antigua & Barbuda'),\r\n};\r\n\r\n/* \r\nconst toInt = (str) => {\r\n return parseInt(str.replace(/ /g, ''));\r\n};\r\nvar arr = window.Countries.sort((a, b) => toInt(a.phoneCode) - toInt(b.phoneCode));\r\narr.forEach((el, idx) => {\r\n if(idx === (arr.length - 1)) {\r\n return;\r\n }\r\n\r\n if(toInt(arr[idx + 1].phoneCode) === toInt(el.phoneCode)) {\r\n console.log('duplicate', el, arr[idx + 1]);\r\n }\r\n});\r\n*/\r\n\r\nMOUNT_CLASS_TO.Countries = Countries;\r\n\r\nexport default Countries;\r\nexport {PhoneCodesMain};","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nexport type UserAuth = number;\r\n\r\nexport const REPLIES_PEER_ID = 1271266957;\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// Thanks to https://stackoverflow.com/a/49349813\r\nimport { clamp } from \"../helpers/number\";\r\n\r\n/**\r\n * Attibute modifier to create middle ellipsis\r\n * When the attribute value is left blank the ellipsis will be in the middle\r\n * When positive the attribute value will be used as a percentage\r\n * When negative the attribute value will be used as character index counted from the end\r\n * @example\r\n * <div data-middle-ellipsis>A Javascript solution to middle ellipsis</div>\r\n * <div data-middle-ellipsis=\"20\">A Javascript solution to middle ellipsis</div>\r\n * <div data-middle-ellipsis=\"-3\">A Javascript solution to middle ellipsis</div>\r\n */\r\nconst ellipsis = '…';\r\nconst map: Map<HTMLElement, {\r\n text: string,\r\n textLength: number,\r\n from: number,\r\n multiplier: number,\r\n font: string,\r\n textWidth: number,\r\n elementWidth: number\r\n}> = new Map();\r\n\r\nconst testQueue: Set<HTMLElement> = new Set();\r\nexport const fontFamily = 'Roboto, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen-Sans, Ubuntu, Cantarell, \"Helvetica Neue\", sans-serif';\r\nconst fontSize = '16px';\r\nlet timeoutId: number;\r\n\r\nconst setTestQueue = () => {\r\n cancelAnimationFrame(timeoutId);\r\n timeoutId = window.requestAnimationFrame(testQueueElements);\r\n};\r\n\r\nconst testQueueElements = () => {\r\n testQueue.forEach(testElement);\r\n testQueue.clear();\r\n};\r\n\r\nwindow.addEventListener('resize', () => {\r\n for(const [key] of map) {\r\n testQueue.add(key);\r\n }\r\n \r\n setTestQueue();\r\n}, {capture: true, passive: true});\r\n\r\nconst testElement = (element: HTMLElement) => {\r\n //const perf = performance.now();\r\n // do not recalculate variables a second time\r\n let mapped = map.get(element);\r\n const firstTime = !mapped;\r\n\r\n let {text, textLength, from, multiplier, font, textWidth, elementWidth} = mapped || {};\r\n //console.log('[MEE] testElement got mapped', mapped);\r\n\r\n if(firstTime) {\r\n text = element.textContent;\r\n textLength = text.length;\r\n from = /* parseFloat(element.getAttribute(attributeName)) || */50;\r\n multiplier = from > 0 && from / 100;\r\n\r\n //const perf = performance.now();\r\n font = `${element.dataset.fontWeight || 400} ${fontSize} ${fontFamily}`;\r\n /* const computedStyle = window.getComputedStyle(elm, null);\r\n font = `${computedStyle.getPropertyValue('font-weight')} ${computedStyle.getPropertyValue('font-size')} ${computedStyle.getPropertyValue('font-family')}`; */\r\n //console.log('testMiddleEllipsis get computed style:', performance.now() - perf, font);\r\n\r\n textWidth = getTextWidth(text, font);\r\n //const perf = performance.now();\r\n elementWidth = element.getBoundingClientRect().width;\r\n //console.log('testMiddleEllipsis get offsetWidth:', performance.now() - perf, font);\r\n mapped = {text, textLength, from, multiplier, font, textWidth, elementWidth};\r\n map.set(element, mapped);\r\n\r\n //console.log('[MEE] testElement map set', element);\r\n }\r\n \r\n const newElementWidth = element.getBoundingClientRect().width;\r\n const widthChanged = firstTime || elementWidth !== newElementWidth;\r\n !firstTime && widthChanged && (mapped.elementWidth = elementWidth = newElementWidth);\r\n \r\n if(widthChanged) {\r\n if(textWidth > elementWidth) {\r\n element.setAttribute('title', text);\r\n let smallerText = text;\r\n let smallerWidth = elementWidth;\r\n while(smallerText.length > 3) {\r\n let smallerTextLength = smallerText.length;\r\n const half = multiplier &&\r\n clamp(multiplier * smallerTextLength << 0, 1, smallerTextLength - 2) ||\r\n Math.max(smallerTextLength + from - 1, 1);\r\n const half1 = smallerText.substr(0, half).replace(/\\s*$/,'');\r\n const half2 = smallerText.substr(half + 1).replace(/^\\s*/,'');\r\n smallerText = half1 + half2;\r\n smallerWidth = getTextWidth(smallerText + ellipsis, font);\r\n if(smallerWidth < elementWidth) {\r\n element.textContent = half1 + ellipsis + half2;\r\n break;\r\n }\r\n }\r\n\r\n // * set new width after cutting text\r\n mapped.elementWidth = element.getBoundingClientRect().width;\r\n //mapped.textWidth = smallerWidth;\r\n } else {\r\n element.removeAttribute('title');\r\n }\r\n }\r\n\r\n //console.log('testMiddleEllipsis for element:', elm, performance.now() - perf);\r\n};\r\n\r\nlet context: CanvasRenderingContext2D;\r\n/**\r\n * Get the text width\r\n * @param {string} text\r\n * @param {string} font\r\n */\r\nfunction getTextWidth(text: string, font: string) {\r\n //const perf = performance.now();\r\n if(!context) {\r\n const canvas = document.createElement('canvas');\r\n context = canvas.getContext('2d');\r\n context.font = font;\r\n }\r\n\r\n //context.font = font;\r\n const metrics = context.measureText(text);\r\n //console.log('getTextWidth perf:', performance.now() - perf);\r\n return metrics.width;\r\n //return Math.round(metrics.width);\r\n}\r\n\r\nexport class MiddleEllipsisElement extends HTMLElement {\r\n constructor() {\r\n super();\r\n }\r\n\r\n connectedCallback() {\r\n //console.log('[MEE]: connectedCallback before', map.has(this), testQueue.has(this), map.size, this.textContent, map);\r\n\r\n map.set(this, null);\r\n testQueue.add(this);\r\n setTestQueue();\r\n //testElement(this);\r\n\r\n //console.log('[MEE]: connectedCallback after', map.has(this), map.size, testQueue.has(this), testQueue.size);\r\n }\r\n\r\n disconnectedCallback() {\r\n const deleted = map.delete(this);\r\n //console.log('[MEE]: disconnectedCallback', deleted, map.has(this), map.size, this.textContent, map);\r\n }\r\n}\r\n\r\ncustomElements.define(\"middle-ellipsis-element\", MiddleEllipsisElement);\r\n","'use strict'\r\n//@flow\r\n\r\n/** * * * * * * * * * *\r\n * Big Integer Library *\r\n * Created 2000 *\r\n * Leemon Baird *\r\n * www.leemon.com *\r\n * * * * * * * * * * * */\r\n\r\n////////////////////////////////////////////////////////////////////////////////////////\r\n// These functions are designed to avoid frequent dynamic memory allocation in the inner loop.\r\n// For most functions, if it needs a BigInt as a local variable it will actually use\r\n// a global, and will only allocate to it only when it's not the right size. This ensures\r\n// that when a function is called repeatedly with same-sized parameters, it only allocates\r\n// memory on the first call.\r\n//\r\n// Note that for cryptographic purposes, the calls to Math.random() must\r\n// be replaced with calls to a better pseudorandom number generator.\r\n//\r\n// In the following, \"bigInt\" means a bigInt with at least one leading zero element,\r\n// and \"integer\" means a nonnegative integer less than radix. In some cases, integer\r\n// can be negative. Negative bigInts are 2s complement.\r\n//\r\n// The following functions do not modify their inputs.\r\n// Those returning a bigInt, string, or Array will dynamically allocate memory for that value.\r\n// Those returning a boolean will return the integer 0 (false) or 1 (true).\r\n// Those returning boolean or int will not allocate memory except possibly on the first\r\n// time they're called with a given parameter size.\r\n//\r\n// bigInt add(x,y) //return (x+y) for bigInts x and y.\r\n// bigInt addInt(x,n) //return (x+n) where x is a bigInt and n is an integer.\r\n// string bigInt2str(x,base) //return a string form of bigInt x in a given base, with 2 <= base <= 95\r\n// int bitSize(x) //return how many bits long the bigInt x is, not counting leading zeros\r\n// bigInt dup(x) //return a copy of bigInt x\r\n// boolean equals(x,y) //is the bigInt x equal to the bigint y?\r\n// boolean equalsInt(x,y) //is bigint x equal to integer y?\r\n// bigInt expand(x,n) //return a copy of x with at least n elements, adding leading zeros if needed\r\n// Array findPrimes(n) //return array of all primes less than integer n\r\n// bigInt GCD(x,y) //return greatest common divisor of bigInts x and y (each with same number of elements).\r\n// boolean greater(x,y) //is x>y? (x and y are nonnegative bigInts)\r\n// boolean greaterShift(x,y,shift)//is (x <<(shift*bpe)) > y?\r\n// bigInt int2bigInt(t,n,m) //return a bigInt equal to integer t, with at least n bits and m array elements\r\n// bigInt inverseMod(x,n) //return (x**(-1) mod n) for bigInts x and n. If no inverse exists, it returns null\r\n// int inverseModInt(x,n) //return x**(-1) mod n, for integers x and n. Return 0 if there is no inverse\r\n// boolean isZero(x) //is the bigInt x equal to zero?\r\n// boolean millerRabin(x,b) //does one round of Miller-Rabin base integer b say that bigInt x is possibly prime? (b is bigInt, 1<b<x)\r\n// boolean millerRabinInt(x,b) //does one round of Miller-Rabin base integer b say that bigInt x is possibly prime? (b is int, 1<b<x)\r\n// bigInt mod(x,n) //return a new bigInt equal to (x mod n) for bigInts x and n.\r\n// int modInt(x,n) //return x mod n for bigInt x and integer n.\r\n// bigInt mult(x,y) //return x*y for bigInts x and y. This is faster when y<x.\r\n// bigInt multMod(x,y,n) //return (x*y mod n) for bigInts x,y,n. For greater speed, let y<x.\r\n// boolean negative(x) //is bigInt x negative?\r\n// bigInt powMod(x,y,n) //return (x**y mod n) where x,y,n are bigInts and ** is exponentiation. 0**0=1. Faster for odd n.\r\n// bigInt randBigInt(n,s) //return an n-bit random BigInt (n>=1). If s=1, then the most significant of those n bits is set to 1.\r\n// bigInt randTruePrime(k) //return a new, random, k-bit, true prime bigInt using Maurer's algorithm.\r\n// bigInt randProbPrime(k) //return a new, random, k-bit, probable prime bigInt (probability it's composite less than 2^-80).\r\n// bigInt str2bigInt(s,b,n,m) //return a bigInt for number represented in string s in base b with at least n bits and m array elements\r\n// bigInt sub(x,y) //return (x-y) for bigInts x and y. Negative answers will be 2s complement\r\n// bigInt trim(x,k) //return a copy of x with exactly k leading zero elements\r\n//\r\n//\r\n// The following functions each have a non-underscored version, which most users should call instead.\r\n// These functions each write to a single parameter, and the caller is responsible for ensuring the array\r\n// passed in is large enough to hold the result.\r\n//\r\n// void addInt_(x,n) //do x=x+n where x is a bigInt and n is an integer\r\n// void add_(x,y) //do x=x+y for bigInts x and y\r\n// void copy_(x,y) //do x=y on bigInts x and y\r\n// void copyInt_(x,n) //do x=n on bigInt x and integer n\r\n// void GCD_(x,y) //set x to the greatest common divisor of bigInts x and y, (y is destroyed). (This never overflows its array).\r\n// boolean inverseMod_(x,n) //do x=x**(-1) mod n, for bigInts x and n. Returns 1 (0) if inverse does (doesn't) exist\r\n// void mod_(x,n) //do x=x mod n for bigInts x and n. (This never overflows its array).\r\n// void mult_(x,y) //do x=x*y for bigInts x and y.\r\n// void multMod_(x,y,n) //do x=x*y mod n for bigInts x,y,n.\r\n// void powMod_(x,y,n) //do x=x**y mod n, where x,y,n are bigInts (n is odd) and ** is exponentiation. 0**0=1.\r\n// void randBigInt_(b,n,s) //do b = an n-bit random BigInt. if s=1, then nth bit (most significant bit) is set to 1. n>=1.\r\n// void randTruePrime_(ans,k) //do ans = a random k-bit true random prime (not just probable prime) with 1 in the msb.\r\n// void sub_(x,y) //do x=x-y for bigInts x and y. Negative answers will be 2s complement.\r\n//\r\n// The following functions do NOT have a non-underscored version.\r\n// They each write a bigInt result to one or more parameters. The caller is responsible for\r\n// ensuring the arrays passed in are large enough to hold the results.\r\n//\r\n// void addShift_(x,y,ys) //do x=x+(y<<(ys*bpe))\r\n// void carry_(x) //do carries and borrows so each element of the bigInt x fits in bpe bits.\r\n// void divide_(x,y,q,r) //divide x by y giving quotient q and remainder r\r\n// int divInt_(x,n) //do x=floor(x/n) for bigInt x and integer n, and return the remainder. (This never overflows its array).\r\n// void eGCD_(x,y,d,a,b) //sets a,b,d to positive bigInts such that d = GCD_(x,y) = a*x-b*y\r\n// void halve_(x) //do x=floor(|x|/2)*sgn(x) for bigInt x in 2's complement. (This never overflows its array).\r\n// void leftShift_(x,n) //left shift bigInt x by n bits. n<bpe.\r\n// void linComb_(x,y,a,b) //do x=a*x+b*y for bigInts x and y and integers a and b\r\n// void linCombShift_(x,y,b,ys) //do x=x+b*(y<<(ys*bpe)) for bigInts x and y, and integers b and ys\r\n// void mont_(x,y,n,np) //Montgomery multiplication (see comments where the function is defined)\r\n// void multInt_(x,n) //do x=x*n where x is a bigInt and n is an integer.\r\n// void rightShift_(x,n) //right shift bigInt x by n bits. 0 <= n < bpe. (This never overflows its array).\r\n// void squareMod_(x,n) //do x=x*x mod n for bigInts x,n\r\n// void subShift_(x,y,ys) //do x=x-(y<<(ys*bpe)). Negative answers will be 2s complement.\r\n//\r\n// The following functions are based on algorithms from the _Handbook of Applied Cryptography_\r\n// powMod_() = algorithm 14.94, Montgomery exponentiation\r\n// eGCD_,inverseMod_() = algorithm 14.61, Binary extended GCD_\r\n// GCD_() = algorothm 14.57, Lehmer's algorithm\r\n// mont_() = algorithm 14.36, Montgomery multiplication\r\n// divide_() = algorithm 14.20 Multiple-precision division\r\n// squareMod_() = algorithm 14.16 Multiple-precision squaring\r\n// randTruePrime_() = algorithm 4.62, Maurer's algorithm\r\n// millerRabin() = algorithm 4.24, Miller-Rabin algorithm\r\n//\r\n// Profiling shows:\r\n// randTruePrime_() spends:\r\n// 10% of its time in calls to powMod_()\r\n// 85% of its time in calls to millerRabin()\r\n// millerRabin() spends:\r\n// 99% of its time in calls to powMod_() (always with a base of 2)\r\n// powMod_() spends:\r\n// 94% of its time in calls to mont_() (almost always with x==y)\r\n//\r\n// This suggests there are several ways to speed up this library slightly:\r\n// - convert powMod_ to use a Montgomery form of k-ary window (or maybe a Montgomery form of sliding window)\r\n// -- this should especially focus on being fast when raising 2 to a power mod n\r\n// - convert randTruePrime_() to use a minimum r of 1/3 instead of 1/2 with the appropriate change to the test\r\n// - tune the parameters in randTruePrime_(), including c, m, and recLimit\r\n// - speed up the single loop in mont_() that takes 95% of the runtime, perhaps by reducing checking\r\n// within the loop when all the parameters are the same length.\r\n//\r\n// There are several ideas that look like they wouldn't help much at all:\r\n// - replacing trial division in randTruePrime_() with a sieve (that speeds up something taking almost no time anyway)\r\n// - increase bpe from 15 to 30 (that would help if we had a 32*32->64 multiplier, but not with JavaScript's 32*32->32)\r\n// - speeding up mont_(x,y,n,np) when x==y by doing a non-modular, non-Montgomery square\r\n// followed by a Montgomery reduction. The intermediate answer will be twice as long as x, so that\r\n// method would be slower. This is unfortunate because the code currently spends almost all of its time\r\n// doing mont_(x,x,...), both for randTruePrime_() and powMod_(). A faster method for Montgomery squaring\r\n// would have a large impact on the speed of randTruePrime_() and powMod_(). HAC has a couple of poorly-worded\r\n// sentences that seem to imply it's faster to do a non-modular square followed by a single\r\n// Montgomery reduction, but that's obviously wrong.\r\n////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nexport type Bool = 1 | 0\r\n\r\n//globals\r\nexport var bpe = 0 //bits stored per array element\r\nvar mask = 0 //AND this with an array element to chop it down to bpe bits\r\nvar radix = mask + 1 //equals 2^bpe. A single 1 bit to the left of the last bit of mask.\r\n\r\n//the digits for converting to different bases\r\nvar digitsStr =\r\n '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_=!@#$%^&*()[]{}|;:,.<>/?`~ \\\\\\'\"+-'\r\n\r\n//initialize the global variables\r\n\r\n//bpe=number of bits in the mantissa on this platform\r\nfor (bpe = 0; 1 << (bpe + 1) > 1 << bpe; bpe++);\r\nbpe >>= 1 //bpe=number of bits in one element of the array representing the bigInt\r\nmask = (1 << bpe) - 1 //AND the mask with an integer to get its bpe least significant bits\r\nradix = mask + 1 //2^bpe. a single 1 bit to the left of the first bit of mask\r\nexport var one = int2bigInt(1, 1, 1) //constant used in powMod_()\r\nexport var zero = int2bigInt(0, 1, 1)\r\n\r\n//the following global variables are scratchpad memory to\r\n//reduce dynamic memory allocation in the inner loop\r\nvar t: number[] | number = new Array(0)\r\nvar ss = t //used in mult_()\r\nvar s0 = t //used in multMod_(), squareMod_()\r\n// var s1=t; //used in powMod_(), multMod_(), squareMod_()\r\n// var s2=t; //used in powMod_(), multMod_()\r\nvar s3 = t //used in powMod_()\r\nvar s4 = t,\r\n s5 = t //used in mod_()\r\nvar s6 = t //used in bigInt2str()\r\nvar s7 = t //used in powMod_()\r\nvar T = t //used in GCD_()\r\nvar sa = t //used in mont_()\r\nvar mr_x1 = t,\r\n mr_r = t,\r\n mr_a = t, //used in millerRabin()\r\n eg_v = t,\r\n eg_u = t,\r\n eg_A = t,\r\n eg_B = t,\r\n eg_C = t,\r\n eg_D = t, //used in eGCD_(), inverseMod_()\r\n //, md_q1=t, md_q2=t, md_q3=t, md_r=t, md_r1=t, md_r2=t, md_tt=t, //used in mod_()\r\n\r\n primes = t,\r\n pows = t,\r\n s_i = t,\r\n s_i2 = t,\r\n s_R = t,\r\n s_rm = t,\r\n s_q = t,\r\n s_n1 = t,\r\n s_a = t,\r\n s_r2 = t,\r\n s_n = t,\r\n s_b = t,\r\n s_d = t,\r\n s_x1 = t,\r\n s_x2 = t,\r\n s_aa = t, //used in randTruePrime_()\r\n rpprb = t //used in randProbPrimeRounds() (which also uses \"primes\")\r\n\r\n////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nvar k, buff\r\n\r\n/**\r\n * return array of all primes less than integer n\r\n *\r\n * @param {number} n\r\n * @returns {number[]}\r\n */\r\nexport function findPrimes(n: number): number[] {\r\n var i, s, p, ans\r\n s = new Array(n)\r\n for (i = 0; i < n; i++) s[i] = 0\r\n s[0] = 2\r\n p = 0 //first p elements of s are primes, the rest are a sieve\r\n for (; s[p] < n; ) {\r\n //s[p] is the pth prime\r\n for (\r\n i = s[p] * s[p];\r\n i < n;\r\n i += s[p] //mark multiples of s[p]\r\n )\r\n s[i] = 1\r\n p++\r\n s[p] = s[p - 1] + 1\r\n for (; s[p] < n && s[s[p]]; s[p]++); //find next prime (where s[p]==0)\r\n }\r\n ans = new Array(p)\r\n for (i = 0; i < p; i++) ans[i] = s[i]\r\n return ans\r\n}\r\n\r\n/**\r\n * does a single round of Miller-Rabin base b consider x to be a possible prime?\r\n *\r\n * x is a bigInt, and b is an integer, with b<x\r\n *\r\n * @export\r\n * @param {number[]} x\r\n * @param {number} b\r\n * @returns {(0 | 1)}\r\n */\r\nexport function millerRabinInt(x: number[], b: number): Bool {\r\n if (mr_x1.length !== x.length) {\r\n mr_x1 = dup(x)\r\n mr_r = dup(x)\r\n mr_a = dup(x)\r\n }\r\n\r\n copyInt_(mr_a, b)\r\n return millerRabin(x, mr_a)\r\n}\r\n\r\n/**\r\n * does a single round of Miller-Rabin base b consider x to be a possible prime?\r\n *\r\n * x and b are bigInts with b<x\r\n *\r\n * @export\r\n * @param {number[]} x\r\n * @param {number[]} b\r\n * @returns {(0 | 1)}\r\n */\r\nexport function millerRabin(x: number[], b: number[]): Bool {\r\n var i, j, k, s\r\n\r\n if (mr_x1.length !== x.length) {\r\n mr_x1 = dup(x)\r\n mr_r = dup(x)\r\n mr_a = dup(x)\r\n }\r\n\r\n copy_(mr_a, b)\r\n copy_(mr_r, x)\r\n copy_(mr_x1, x)\r\n\r\n addInt_(mr_r, -1)\r\n addInt_(mr_x1, -1)\r\n\r\n //s=the highest power of two that divides mr_r\r\n k = 0\r\n for (i = 0; i < mr_r.length; i++)\r\n for (j = 1; j < mask; j <<= 1)\r\n if (x[i] & j) {\r\n s = k < mr_r.length + bpe ? k : 0\r\n i = mr_r.length\r\n j = mask\r\n } else k++\r\n\r\n if (s) rightShift_(mr_r, s)\r\n\r\n powMod_(mr_a, mr_r, x)\r\n\r\n if (!equalsInt(mr_a, 1) && !equals(mr_a, mr_x1)) {\r\n j = 1\r\n //$off\r\n while (j <= s - 1 && !equals(mr_a, mr_x1)) {\r\n squareMod_(mr_a, x)\r\n if (equalsInt(mr_a, 1)) {\r\n return 0\r\n }\r\n j++\r\n }\r\n if (!equals(mr_a, mr_x1)) {\r\n return 0\r\n }\r\n }\r\n return 1\r\n}\r\n\r\n/**\r\n * returns how many bits long the bigInt is, not counting leading zeros.\r\n *\r\n * @param {number[]} x\r\n * @returns {number}\r\n */\r\nexport function bitSize(x: number[]): number {\r\n var j, z, w\r\n for (j = x.length - 1; x[j] == 0 && j > 0; j--);\r\n for (z = 0, w = x[j]; w; w >>= 1, z++);\r\n z += bpe * j\r\n return z\r\n}\r\n\r\n/**\r\n * return a copy of x with at least n elements, adding leading zeros if needed\r\n *\r\n * @param {number[]} x\r\n * @param {number} n\r\n * @returns {number[]}\r\n */\r\nexport function expand(x: number[], n: number): number[] {\r\n var ans = int2bigInt(0, (x.length > n ? x.length : n) * bpe, 0)\r\n copy_(ans, x)\r\n return ans\r\n}\r\n\r\n/**\r\n * return a k-bit true random prime using Maurer's algorithm.\r\n *\r\n * @export\r\n * @param {number} k\r\n * @returns {number[]}\r\n */\r\nexport function randTruePrime(k: number): number[] {\r\n var ans = int2bigInt(0, k, 0)\r\n randTruePrime_(ans, k)\r\n return trim(ans, 1)\r\n}\r\n\r\n/**\r\n * return a k-bit random probable prime with probability of error < 2^-80\r\n *\r\n * @export\r\n * @param {number} k\r\n * @returns {number[]}\r\n */\r\nexport function randProbPrime(k: number): number[] {\r\n if (k >= 600) return randProbPrimeRounds(k, 2) //numbers from HAC table 4.3\r\n if (k >= 550) return randProbPrimeRounds(k, 4)\r\n if (k >= 500) return randProbPrimeRounds(k, 5)\r\n if (k >= 400) return randProbPrimeRounds(k, 6)\r\n if (k >= 350) return randProbPrimeRounds(k, 7)\r\n if (k >= 300) return randProbPrimeRounds(k, 9)\r\n if (k >= 250) return randProbPrimeRounds(k, 12) //numbers from HAC table 4.4\r\n if (k >= 200) return randProbPrimeRounds(k, 15)\r\n if (k >= 150) return randProbPrimeRounds(k, 18)\r\n if (k >= 100) return randProbPrimeRounds(k, 27)\r\n return randProbPrimeRounds(k, 40) //number from HAC remark 4.26 (only an estimate)\r\n}\r\n\r\n/**\r\n * return a k-bit probable random prime using n rounds of Miller Rabin\r\n * (after trial division with small primes)\r\n *\r\n * @export\r\n * @param {number} k\r\n * @param {number} n\r\n * @returns {number[]}\r\n */\r\nexport function randProbPrimeRounds(k: number, n: number): number[] {\r\n var ans, i, divisible, B\r\n B = 30000 //B is largest prime to use in trial division\r\n ans = int2bigInt(0, k, 0)\r\n\r\n //optimization: try larger and smaller B to find the best limit.\r\n\r\n if (primes.length === 0) primes = findPrimes(30000) //check for divisibility by primes <=30000\r\n\r\n if (rpprb.length !== ans.length) rpprb = dup(ans)\r\n\r\n for (;;) {\r\n //keep trying random values for ans until one appears to be prime\r\n //optimization: pick a random number times L=2*3*5*...*p, plus a\r\n // random element of the list of all numbers in [0,L) not divisible by any prime up to p.\r\n // This can reduce the amount of random number generation.\r\n\r\n randBigInt_(ans, k, 0) //ans = a random odd number to check\r\n ans[0] |= 1\r\n divisible = 0\r\n\r\n //check ans for divisibility by small primes up to B\r\n for (i = 0; i < primes.length && primes[i] <= B; i++)\r\n if (modInt(ans, primes[i]) === 0 && !equalsInt(ans, primes[i])) {\r\n divisible = 1\r\n break\r\n }\r\n\r\n //optimization: change millerRabin so the base can be bigger than the number being checked, then eliminate the while here.\r\n\r\n //do n rounds of Miller Rabin, with random bases less than ans\r\n for (i = 0; i < n && !divisible; i++) {\r\n randBigInt_(rpprb, k, 0)\r\n while (\r\n !greater(ans, rpprb) //pick a random rpprb that's < ans\r\n )\r\n randBigInt_(rpprb, k, 0)\r\n if (!millerRabin(ans, rpprb)) divisible = 1\r\n }\r\n\r\n if (!divisible) return ans\r\n }\r\n /*::\r\n declare var never: empty\r\n return never\r\n */\r\n}\r\n\r\n/**\r\n * return a new bigInt equal to (x mod n) for bigInts x and n.\r\n *\r\n * @param {number[]} x\r\n * @param {number[]} n\r\n * @returns {number[]}\r\n */\r\nexport function mod(x: number[], n: number[]): number[] {\r\n var ans = dup(x)\r\n mod_(ans, n)\r\n return trim(ans, 1)\r\n}\r\n\r\n/**\r\n * return (x+n) where x is a bigInt and n is an integer.\r\n *\r\n * @export\r\n * @param {number[]} x\r\n * @param {number} n\r\n * @returns {number[]}\r\n */\r\nexport function addInt(x: number[], n: number): number[] {\r\n var ans = expand(x, x.length + 1)\r\n addInt_(ans, n)\r\n return trim(ans, 1)\r\n}\r\n\r\n/**\r\n * return x*y for bigInts x and y. This is faster when y<x.\r\n *\r\n * @export\r\n * @param {number[]} x\r\n * @param {number[]} y\r\n * @returns {number[]}\r\n */\r\nexport function mult(x: number[], y: number[]): number[] {\r\n var ans = expand(x, x.length + y.length)\r\n mult_(ans, y)\r\n return trim(ans, 1)\r\n}\r\n\r\n/**\r\n * return (x**y mod n) where x,y,n are bigInts and ** is exponentiation.\r\n *\r\n * 0**0=1.\r\n *\r\n * Faster for odd n.\r\n *\r\n * @export\r\n * @param {number[]} x\r\n * @param {number[]} y\r\n * @param {number[]} n\r\n * @returns {number[]}\r\n */\r\nexport function powMod(x: number[], y: number[], n: number[]): number[] {\r\n var ans = expand(x, n.length)\r\n powMod_(\r\n //this should work without the trim, but doesn't\r\n ans,\r\n trim(y, 2),\r\n trim(n, 2),\r\n )\r\n return trim(ans, 1)\r\n}\r\n\r\n/**\r\n * Simple pow with no optimizations (in 40x times slower than jsbn's pow)\r\n * @param x bigInt\r\n * @param e\r\n */\r\nexport function pow(x: number[], e: number) {\r\n let ans = dup(x);\r\n e -= 1;\r\n for(let i = 0; i < e; ++i) {\r\n ans = mult(ans, x);\r\n }\r\n return trim(ans, 1);\r\n}\r\n\r\n/**\r\n * return (x-y) for bigInts x and y\r\n *\r\n * Negative answers will be 2s complement\r\n *\r\n * @export\r\n * @param {number[]} x\r\n * @param {number[]} y\r\n * @returns {number[]}\r\n */\r\nexport function sub(x: number[], y: number[]): number[] {\r\n var ans = expand(x, x.length > y.length ? x.length + 1 : y.length + 1)\r\n sub_(ans, y)\r\n return trim(ans, 1)\r\n}\r\n\r\n/**\r\n * return (x+y) for bigInts x and y\r\n *\r\n * @export\r\n * @param {number[]} x\r\n * @param {number[]} y\r\n * @returns {number[]}\r\n */\r\nexport function add(x: number[], y: number[]): number[] {\r\n var ans = expand(x, x.length > y.length ? x.length + 1 : y.length + 1)\r\n add_(ans, y)\r\n return trim(ans, 1)\r\n}\r\n\r\n/**\r\n * return (x**(-1) mod n) for bigInts x and n.\r\n *\r\n * If no inverse exists, it returns null\r\n *\r\n * @param {number[]} x\r\n * @param {number[]} n\r\n * @returns {(number[] | null)}\r\n */\r\nexport function inverseMod(x: number[], n: number[]): number[] | null {\r\n var ans = expand(x, n.length)\r\n var s = inverseMod_(ans, n)\r\n return s ? trim(ans, 1) : null\r\n}\r\n\r\n/**\r\n * return (x*y mod n) for bigInts x,y,n.\r\n *\r\n * For greater speed, let y<x.\r\n *\r\n * @export\r\n * @param {number[]} x\r\n * @param {number[]} y\r\n * @param {number[]} n\r\n * @returns {number[]}\r\n */\r\nexport function multMod(x: number[], y: number[], n: number[]): number[] {\r\n var ans = expand(x, n.length)\r\n multMod_(ans, y, n)\r\n return trim(ans, 1)\r\n}\r\n\r\n/**\r\n * generate a k-bit true random prime using Maurer's algorithm, and put it into ans.\r\n *\r\n * The bigInt ans must be large enough to hold it.\r\n *\r\n * @export\r\n * @param {number[]} ans\r\n * @param {number} k\r\n * @return {void}\r\n */\r\nexport function randTruePrime_(ans: number[], k: number): void {\r\n var c, m, pm, dd, j, r, B, divisible, z, zz, recSize\r\n var w\r\n if (primes.length == 0) primes = findPrimes(30000) //check for divisibility by primes <=30000\r\n\r\n if (pows.length == 0) {\r\n pows = new Array(512)\r\n for (j = 0; j < 512; j++) {\r\n pows[j] = Math.pow(2, j / 511 - 1)\r\n }\r\n }\r\n\r\n //c and m should be tuned for a particular machine and value of k, to maximize speed\r\n c = 0.1 //c=0.1 in HAC\r\n m = 20 //generate this k-bit number by first recursively generating a number that has between k/2 and k-m bits\r\n var recLimit = 20 //stop recursion when k <=recLimit. Must have recLimit >= 2\r\n\r\n if (s_i2.length != ans.length) {\r\n s_i2 = dup(ans)\r\n s_R = dup(ans)\r\n s_n1 = dup(ans)\r\n s_r2 = dup(ans)\r\n s_d = dup(ans)\r\n s_x1 = dup(ans) //TODO Seems like a bug in eslint, reports as unused\r\n s_x2 = dup(ans)\r\n s_b = dup(ans)\r\n s_n = dup(ans)\r\n s_i = dup(ans)\r\n s_rm = dup(ans)\r\n s_q = dup(ans)\r\n s_a = dup(ans)\r\n s_aa = dup(ans)\r\n }\r\n\r\n if (k <= recLimit) {\r\n //generate small random primes by trial division up to its square root\r\n pm = (1 << ((k + 2) >> 1)) - 1 //pm is binary number with all ones, just over sqrt(2^k)\r\n copyInt_(ans, 0)\r\n for (dd = 1; dd; ) {\r\n dd = 0\r\n ans[0] = 1 | (1 << (k - 1)) | Math.floor(Math.random() * (1 << k)) //random, k-bit, odd integer, with msb 1\r\n for (j = 1; j < primes.length && (primes[j] & pm) == primes[j]; j++) {\r\n //trial division by all primes 3...sqrt(2^k)\r\n if (0 == ans[0] % primes[j]) {\r\n dd = 1\r\n break\r\n }\r\n }\r\n }\r\n carry_(ans)\r\n return\r\n }\r\n\r\n B = c * k * k //try small primes up to B (or all the primes[] array if the largest is less than B).\r\n if (k > 2 * m)\r\n //generate this k-bit number by first recursively generating a number that has between k/2 and k-m bits\r\n for (r = 1; k - k * r <= m; ) r = pows[Math.floor(Math.random() * 512)] //r=Math.pow(2,Math.random()-1);\r\n else r = 0.5\r\n\r\n //simulation suggests the more complex algorithm using r=.333 is only slightly faster.\r\n\r\n recSize = Math.floor(r * k) + 1\r\n\r\n randTruePrime_(s_q, recSize)\r\n copyInt_(s_i2, 0)\r\n s_i2[Math.floor((k - 2) / bpe)] |= 1 << ((k - 2) % bpe) //s_i2=2^(k-2)\r\n divide_(s_i2, s_q, s_i, s_rm) //s_i=floor((2^(k-1))/(2q))\r\n\r\n z = bitSize(s_i)\r\n\r\n for (;;) {\r\n for (;;) {\r\n //generate z-bit numbers until one falls in the range [0,s_i-1]\r\n randBigInt_(s_R, z, 0)\r\n if (greater(s_i, s_R)) break\r\n } //now s_R is in the range [0,s_i-1]\r\n addInt_(s_R, 1) //now s_R is in the range [1,s_i]\r\n add_(s_R, s_i) //now s_R is in the range [s_i+1,2*s_i]\r\n\r\n copy_(s_n, s_q)\r\n mult_(s_n, s_R)\r\n multInt_(s_n, 2)\r\n addInt_(s_n, 1) //s_n=2*s_R*s_q+1\r\n\r\n copy_(s_r2, s_R)\r\n multInt_(s_r2, 2) //s_r2=2*s_R\r\n\r\n //check s_n for divisibility by small primes up to B\r\n for (divisible = 0, j = 0; j < primes.length && primes[j] < B; j++)\r\n if (modInt(s_n, primes[j]) == 0 && !equalsInt(s_n, primes[j])) {\r\n divisible = 1\r\n break\r\n }\r\n\r\n if (!divisible)\r\n if (!millerRabinInt(s_n, 2))\r\n //if it passes small primes check, then try a single Miller-Rabin base 2\r\n //this line represents 75% of the total runtime for randTruePrime_\r\n divisible = 1\r\n\r\n if (!divisible) {\r\n //if it passes that test, continue checking s_n\r\n addInt_(s_n, -3)\r\n for (j = s_n.length - 1; s_n[j] == 0 && j > 0; j--); //strip leading zeros\r\n for (zz = 0, w = s_n[j]; w; w >>= 1, zz++);\r\n zz += bpe * j //zz=number of bits in s_n, ignoring leading zeros\r\n for (;;) {\r\n //generate z-bit numbers until one falls in the range [0,s_n-1]\r\n randBigInt_(s_a, zz, 0)\r\n if (greater(s_n, s_a)) break\r\n } //now s_a is in the range [0,s_n-1]\r\n addInt_(s_n, 3) //now s_a is in the range [0,s_n-4]\r\n addInt_(s_a, 2) //now s_a is in the range [2,s_n-2]\r\n copy_(s_b, s_a)\r\n copy_(s_n1, s_n)\r\n addInt_(s_n1, -1)\r\n powMod_(s_b, s_n1, s_n) //s_b=s_a^(s_n-1) modulo s_n\r\n addInt_(s_b, -1)\r\n if (isZero(s_b)) {\r\n copy_(s_b, s_a)\r\n powMod_(s_b, s_r2, s_n)\r\n addInt_(s_b, -1)\r\n copy_(s_aa, s_n)\r\n copy_(s_d, s_b)\r\n GCD_(s_d, s_n) //if s_b and s_n are relatively prime, then s_n is a prime\r\n if (equalsInt(s_d, 1)) {\r\n copy_(ans, s_aa)\r\n return //if we've made it this far, then s_n is absolutely guaranteed to be prime\r\n }\r\n }\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Return an n-bit random BigInt (n>=1). If s=1, then the most significant of those n bits is set to 1.\r\n *\r\n * @export\r\n * @param {number} n\r\n * @param {number} s\r\n * @returns {number[]}\r\n */\r\nexport function randBigInt(n: number, s: number): number[] {\r\n var a, b\r\n a = Math.floor((n - 1) / bpe) + 2 //# array elements to hold the BigInt with a leading 0 element\r\n b = int2bigInt(0, 0, a)\r\n randBigInt_(b, n, s)\r\n return b\r\n}\r\n\r\n/**\r\n * Set b to an n-bit random BigInt. If s=1, then the most significant of those n bits is set to 1.\r\n *\r\n * Array b must be big enough to hold the result. Must have n>=1\r\n *\r\n * @export\r\n * @param {number[]} b\r\n * @param {number} n\r\n * @param {number} s\r\n * @return {void}\r\n */\r\nexport function randBigInt_(b: number[], n: number, s: number): void {\r\n var i, a\r\n for (i = 0; i < b.length; i++) b[i] = 0\r\n a = Math.floor((n - 1) / bpe) + 1 //# array elements to hold the BigInt\r\n for (i = 0; i < a; i++) {\r\n b[i] = Math.floor(Math.random() * (1 << (bpe - 1)))\r\n }\r\n b[a - 1] &= (2 << ((n - 1) % bpe)) - 1\r\n if (s == 1) b[a - 1] |= 1 << ((n - 1) % bpe)\r\n}\r\n\r\n/**\r\n * Return the greatest common divisor of bigInts x and y (each with same number of elements).\r\n *\r\n * @export\r\n * @param {number[]} x\r\n * @param {number[]} y\r\n * @returns {number[]}\r\n */\r\nexport function GCD(x: number[], y: number[]): number[] {\r\n var xc, yc\r\n xc = dup(x)\r\n yc = dup(y)\r\n GCD_(xc, yc)\r\n return xc\r\n}\r\n\r\n/**\r\n * set x to the greatest common divisor of bigInts x and y (each with same number of elements).\r\n *\r\n * y is destroyed.\r\n *\r\n * @export\r\n * @param {number[]} x\r\n * @param {number[]} y\r\n */\r\nexport function GCD_(x: number[], y: number[]): void {\r\n var i: number, xp: number, yp: number, A: number, B, C: number, D: number, q, sing\r\n var qp\r\n if (T.length !== x.length) T = dup(x)\r\n\r\n sing = 1\r\n while (sing) {\r\n //while y has nonzero elements other than y[0]\r\n sing = 0\r\n for (\r\n i = 1;\r\n i < y.length;\r\n i++ //check if y has nonzero elements other than 0\r\n )\r\n if (y[i]) {\r\n sing = 1\r\n break\r\n }\r\n if (!sing) break //quit when y all zero elements except possibly y[0]\r\n\r\n for (i = x.length; !x[i] && i >= 0; i--); //find most significant element of x\r\n xp = x[i]\r\n yp = y[i]\r\n A = 1\r\n B = 0\r\n C = 0\r\n D = 1\r\n while (yp + C && yp + D) {\r\n q = Math.floor((xp + A) / (yp + C))\r\n qp = Math.floor((xp + B) / (yp + D))\r\n if (q != qp) break\r\n t = A - q * C\r\n A = C\r\n C = t // do (A,B,xp, C,D,yp) = (C,D,yp, A,B,xp) - q*(0,0,0, C,D,yp)\r\n t = B - q * D\r\n B = D\r\n D = t\r\n t = xp - q * yp\r\n xp = yp\r\n yp = t\r\n }\r\n if (B) {\r\n copy_(T, x)\r\n linComb_(x, y, A, B) //x=A*x+B*y\r\n linComb_(y, T, D, C) //y=D*y+C*T\r\n } else {\r\n mod_(x, y)\r\n copy_(T, x)\r\n copy_(x, y)\r\n copy_(y, T)\r\n }\r\n }\r\n if (y[0] === 0) return\r\n t = modInt(x, y[0])\r\n copyInt_(x, y[0])\r\n y[0] = t\r\n while (y[0]) {\r\n x[0] %= y[0]\r\n t = x[0]\r\n x[0] = y[0]\r\n y[0] = t\r\n }\r\n}\r\n\r\n/**\r\n * do x=x**(-1) mod n, for bigInts x and n.\r\n *\r\n * If no inverse exists, it sets x to zero and returns 0, else it returns 1.\r\n * The x array must be at least as large as the n array.\r\n *\r\n * @export\r\n * @param {number[]} x\r\n * @param {number[]} n\r\n * @returns {(0 | 1)}\r\n */\r\nexport function inverseMod_(x: number[], n: number[]): Bool {\r\n var k = 1 + 2 * Math.max(x.length, n.length)\r\n\r\n if (!(x[0] & 1) && !(n[0] & 1)) {\r\n //if both inputs are even, then inverse doesn't exist\r\n copyInt_(x, 0)\r\n return 0\r\n }\r\n\r\n if (eg_u.length != k) {\r\n eg_u = new Array(k)\r\n eg_v = new Array(k)\r\n eg_A = new Array(k)\r\n eg_B = new Array(k)\r\n eg_C = new Array(k)\r\n eg_D = new Array(k)\r\n }\r\n\r\n copy_(eg_u, x)\r\n copy_(eg_v, n)\r\n copyInt_(eg_A, 1)\r\n copyInt_(eg_B, 0)\r\n copyInt_(eg_C, 0)\r\n copyInt_(eg_D, 1)\r\n for (;;) {\r\n while (!(eg_u[0] & 1)) {\r\n //while eg_u is even\r\n halve_(eg_u)\r\n if (!(eg_A[0] & 1) && !(eg_B[0] & 1)) {\r\n //if eg_A==eg_B==0 mod 2\r\n halve_(eg_A)\r\n halve_(eg_B)\r\n } else {\r\n add_(eg_A, n)\r\n halve_(eg_A)\r\n sub_(eg_B, x)\r\n halve_(eg_B)\r\n }\r\n }\r\n\r\n while (!(eg_v[0] & 1)) {\r\n //while eg_v is even\r\n halve_(eg_v)\r\n if (!(eg_C[0] & 1) && !(eg_D[0] & 1)) {\r\n //if eg_C==eg_D==0 mod 2\r\n halve_(eg_C)\r\n halve_(eg_D)\r\n } else {\r\n add_(eg_C, n)\r\n halve_(eg_C)\r\n sub_(eg_D, x)\r\n halve_(eg_D)\r\n }\r\n }\r\n\r\n if (!greater(eg_v, eg_u)) {\r\n //eg_v <= eg_u\r\n sub_(eg_u, eg_v)\r\n sub_(eg_A, eg_C)\r\n sub_(eg_B, eg_D)\r\n } else {\r\n //eg_v > eg_u\r\n sub_(eg_v, eg_u)\r\n sub_(eg_C, eg_A)\r\n sub_(eg_D, eg_B)\r\n }\r\n\r\n if (equalsInt(eg_u, 0)) {\r\n while (\r\n negative(eg_C) //make sure answer is nonnegative\r\n )\r\n add_(eg_C, n)\r\n copy_(x, eg_C)\r\n\r\n if (!equalsInt(eg_v, 1)) {\r\n //if GCD_(x,n)!=1, then there is no inverse\r\n copyInt_(x, 0)\r\n return 0\r\n }\r\n return 1\r\n }\r\n }\r\n /*::\r\n declare var never: empty\r\n return never\r\n */\r\n}\r\n\r\n/**\r\n * return x**(-1) mod n, for integers x and n.\r\n *\r\n * Return 0 if there is no inverse\r\n *\r\n * @param {number} x\r\n * @param {number} n\r\n * @returns {number}\r\n */\r\nexport function inverseModInt(x: number, n: number): number {\r\n var a = 1,\r\n b = 0,\r\n t\r\n for (;;) {\r\n if (x === 1) return a\r\n if (x === 0) return 0\r\n b -= a * Math.floor(n / x)\r\n //$off\r\n n %= x\r\n\r\n if (n === 1) return b //to avoid negatives, change this b to n-b, and each -= to +=\r\n if (n === 0) return 0\r\n a -= b * Math.floor(x / n)\r\n //$off\r\n x %= n\r\n }\r\n /*::\r\n declare var never: empty\r\n return never\r\n */\r\n}\r\n\r\n//this deprecated function is for backward compatibility only.\r\nfunction inverseModInt_(x: number, n: number) {\r\n return inverseModInt(x, n)\r\n}\r\n\r\n/**\r\n * Given positive bigInts x and y, change the bigints v, a, and b to positive bigInts such that:\r\n *\r\n * v = GCD_(x,y) = a*x-b*y\r\n *\r\n * The bigInts v, a, b, must have exactly as many elements as the larger of x and y.\r\n *\r\n * @export\r\n * @param {number[]} x\r\n * @param {number[]} y\r\n * @param {number[]} v\r\n * @param {number[]} a\r\n * @param {number[]} b\r\n * @return {void}\r\n */\r\nexport function eGCD_(\r\n x: number[],\r\n y: number[],\r\n v: number[],\r\n a: number[],\r\n b: number[],\r\n): void {\r\n var g = 0\r\n var k = Math.max(x.length, y.length)\r\n if (eg_u.length != k) {\r\n eg_u = new Array(k)\r\n eg_A = new Array(k)\r\n eg_B = new Array(k)\r\n eg_C = new Array(k)\r\n eg_D = new Array(k)\r\n }\r\n while (!(x[0] & 1) && !(y[0] & 1)) {\r\n //while x and y both even\r\n halve_(x)\r\n halve_(y)\r\n g++\r\n }\r\n copy_(eg_u, x)\r\n copy_(v, y)\r\n copyInt_(eg_A, 1)\r\n copyInt_(eg_B, 0)\r\n copyInt_(eg_C, 0)\r\n copyInt_(eg_D, 1)\r\n for (;;) {\r\n while (!(eg_u[0] & 1)) {\r\n //while u is even\r\n halve_(eg_u)\r\n if (!(eg_A[0] & 1) && !(eg_B[0] & 1)) {\r\n //if A==B==0 mod 2\r\n halve_(eg_A)\r\n halve_(eg_B)\r\n } else {\r\n add_(eg_A, y)\r\n halve_(eg_A)\r\n sub_(eg_B, x)\r\n halve_(eg_B)\r\n }\r\n }\r\n\r\n while (!(v[0] & 1)) {\r\n //while v is even\r\n halve_(v)\r\n if (!(eg_C[0] & 1) && !(eg_D[0] & 1)) {\r\n //if C==D==0 mod 2\r\n halve_(eg_C)\r\n halve_(eg_D)\r\n } else {\r\n add_(eg_C, y)\r\n halve_(eg_C)\r\n sub_(eg_D, x)\r\n halve_(eg_D)\r\n }\r\n }\r\n\r\n if (!greater(v, eg_u)) {\r\n //v<=u\r\n sub_(eg_u, v)\r\n sub_(eg_A, eg_C)\r\n sub_(eg_B, eg_D)\r\n } else {\r\n //v>u\r\n sub_(v, eg_u)\r\n sub_(eg_C, eg_A)\r\n sub_(eg_D, eg_B)\r\n }\r\n if (equalsInt(eg_u, 0)) {\r\n while (negative(eg_C)) {\r\n //make sure a (C) is nonnegative\r\n add_(eg_C, y)\r\n sub_(eg_D, x)\r\n }\r\n multInt_(eg_D, -1) ///make sure b (D) is nonnegative\r\n copy_(a, eg_C)\r\n copy_(b, eg_D)\r\n leftShift_(v, g)\r\n return\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * is bigInt x negative?\r\n *\r\n * @param {number[]} x\r\n * @returns {(1 | 0)}\r\n */\r\nexport function negative(x: number[]) {\r\n //TODO Flow Bool type inference\r\n return (x[x.length - 1] >> (bpe - 1)) & 1\r\n}\r\n\r\n/**\r\n * is (x << (shift*bpe)) > y?\r\n *\r\n * x and y are nonnegative bigInts\r\n * shift is a nonnegative integer\r\n *\r\n * @param {number[]} x\r\n * @param {number[]} y\r\n * @param {number} shift\r\n * @returns {(1 | 0)}\r\n */\r\nexport function greaterShift(x: number[], y: number[], shift: number): Bool {\r\n var i,\r\n kx = x.length,\r\n ky = y.length\r\n k = kx + shift < ky ? kx + shift : ky\r\n for (i = ky - 1 - shift; i < kx && i >= 0; i++) if (x[i] > 0) return 1 //if there are nonzeros in x to the left of the first column of y, then x is bigger\r\n for (i = kx - 1 + shift; i < ky; i++) if (y[i] > 0) return 0 //if there are nonzeros in y to the left of the first column of x, then x is not bigger\r\n for (i = k - 1; i >= shift; i--)\r\n if (x[i - shift] > y[i]) return 1\r\n else if (x[i - shift] < y[i]) return 0\r\n return 0\r\n}\r\n\r\n/**\r\n * is x > y?\r\n *\r\n * x and y both nonnegative\r\n *\r\n * @export\r\n * @param {number[]} x\r\n * @param {number[]} y\r\n * @returns {(1 | 0)}\r\n */\r\nexport function greater(x: number[], y: number[]): Bool {\r\n var i\r\n var k = x.length < y.length ? x.length : y.length\r\n\r\n for (i = x.length; i < y.length; i++) if (y[i]) return 0 //y has more digits\r\n\r\n for (i = y.length; i < x.length; i++) if (x[i]) return 1 //x has more digits\r\n\r\n for (i = k - 1; i >= 0; i--)\r\n if (x[i] > y[i]) return 1\r\n else if (x[i] < y[i]) return 0\r\n return 0\r\n}\r\n\r\n/**\r\n * divide x by y giving quotient q and remainder r.\r\n *\r\n * q = floor(x/y)\r\n * r = x mod y\r\n *\r\n * All 4 are bigints.\r\n *\r\n * * x must have at least one leading zero element.\r\n * * y must be nonzero.\r\n * * q and r must be arrays that are exactly the same length as x. (Or q can have more).\r\n * * Must have x.length >= y.length >= 2.\r\n *\r\n * @export\r\n * @param {number[]} x\r\n * @param {number[]} y\r\n * @param {number[]} q\r\n * @param {number[]} r\r\n * @return {void}\r\n */\r\nexport function divide_(\r\n x: number[],\r\n y: number[],\r\n q: number[],\r\n r: number[],\r\n): void {\r\n var kx, ky\r\n var i, j, y1, y2, c, a, b\r\n copy_(r, x)\r\n for (ky = y.length; y[ky - 1] === 0; ky--); //ky is number of elements in y, not including leading zeros\r\n\r\n //normalize: ensure the most significant element of y has its highest bit set\r\n b = y[ky - 1]\r\n for (a = 0; b; a++) b >>= 1\r\n a = bpe - a //a is how many bits to shift so that the high order bit of y is leftmost in its array element\r\n leftShift_(y, a) //multiply both by 1<<a now, then divide both by that at the end\r\n leftShift_(r, a)\r\n\r\n //Rob Visser discovered a bug: the following line was originally just before the normalization.\r\n for (kx = r.length; r[kx - 1] === 0 && kx > ky; kx--); //kx is number of elements in normalized x, not including leading zeros\r\n\r\n copyInt_(q, 0) // q=0\r\n while (!greaterShift(y, r, kx - ky)) {\r\n // while (leftShift_(y,kx-ky) <= r) {\r\n subShift_(r, y, kx - ky) // r=r-leftShift_(y,kx-ky)\r\n q[kx - ky]++ // q[kx-ky]++;\r\n } // }\r\n\r\n for (i = kx - 1; i >= ky; i--) {\r\n if (r[i] == y[ky - 1]) q[i - ky] = mask\r\n else q[i - ky] = Math.floor((r[i] * radix + r[i - 1]) / y[ky - 1])\r\n\r\n //The following for(;;) loop is equivalent to the commented while loop,\r\n //except that the uncommented version avoids overflow.\r\n //The commented loop comes from HAC, which assumes r[-1]==y[-1]==0\r\n // while (q[i-ky]*(y[ky-1]*radix+y[ky-2]) > r[i]*radix*radix+r[i-1]*radix+r[i-2])\r\n // q[i-ky]--;\r\n for (;;) {\r\n y2 = (ky > 1 ? y[ky - 2] : 0) * q[i - ky]\r\n c = y2 >> bpe\r\n y2 = y2 & mask\r\n y1 = c + q[i - ky] * y[ky - 1]\r\n c = y1 >> bpe\r\n y1 = y1 & mask\r\n\r\n if (\r\n c == r[i]\r\n ? y1 == r[i - 1] ? y2 > (i > 1 ? r[i - 2] : 0) : y1 > r[i - 1]\r\n : c > r[i]\r\n )\r\n q[i - ky]--\r\n else break\r\n }\r\n\r\n linCombShift_(r, y, -q[i - ky], i - ky) //r=r-q[i-ky]*leftShift_(y,i-ky)\r\n if (negative(r)) {\r\n addShift_(r, y, i - ky) //r=r+leftShift_(y,i-ky)\r\n q[i - ky]--\r\n }\r\n }\r\n\r\n rightShift_(y, a) //undo the normalization step\r\n rightShift_(r, a) //undo the normalization step\r\n}\r\n\r\n/**\r\n * do carries and borrows so each element of the bigInt x fits in bpe bits.\r\n *\r\n * @param {number[]} x\r\n */\r\nexport function carry_(x: number[]): void {\r\n var i, k, c, b\r\n k = x.length\r\n c = 0\r\n for (i = 0; i < k; i++) {\r\n c += x[i]\r\n b = 0\r\n if (c < 0) {\r\n b = -(c >> bpe)\r\n c += b * radix\r\n }\r\n x[i] = c & mask\r\n c = (c >> bpe) - b\r\n }\r\n}\r\n\r\n/**\r\n * return x mod n for bigInt x and integer n.\r\n *\r\n * @export\r\n * @param {number[]} x\r\n * @param {number} n\r\n * @returns {number}\r\n */\r\nexport function modInt(x: number[], n: number): number {\r\n var i,\r\n c = 0\r\n for (i = x.length - 1; i >= 0; i--) c = (c * radix + x[i]) % n\r\n return c\r\n}\r\n\r\n/**\r\n * convert the integer t into a bigInt with at least the given number of bits.\r\n * the returned array stores the bigInt in bpe-bit chunks, little endian (buff[0] is least significant word)\r\n * Pad the array with leading zeros so that it has at least minSize elements.\r\n *\r\n * There will always be at least one leading 0 element.\r\n *\r\n * @export\r\n * @param {number} t\r\n * @param {number} bits\r\n * @param {number} minSize\r\n * @returns {number[]}\r\n */\r\nexport function int2bigInt(t: number, bits: number, minSize: number): number[] {\r\n var i, k\r\n k = Math.ceil(bits / bpe) + 1\r\n k = minSize > k ? minSize : k\r\n var buff = new Array(k)\r\n copyInt_(buff, t)\r\n return buff\r\n}\r\n\r\n/**\r\n * return the bigInt given a string representation in a given base.\r\n * Pad the array with leading zeros so that it has at least minSize elements.\r\n * If base=-1, then it reads in a space-separated list of array elements in decimal.\r\n *\r\n * The array will always have at least one leading zero, unless base=-1.\r\n *\r\n * @export\r\n * @param {string} s\r\n * @param {number} base\r\n * @param {number} [minSize]\r\n * @returns {number[]}\r\n */\r\nexport function str2bigInt(\r\n s: string,\r\n base: number,\r\n minSize?: number,\r\n): number[] {\r\n var d, i, x, y, kk\r\n var k = s.length\r\n if (base === -1) {\r\n //comma-separated list of array elements in decimal\r\n x = new Array(0)\r\n for (;;) {\r\n y = new Array(x.length + 1)\r\n for (i = 0; i < x.length; i++) y[i + 1] = x[i]\r\n y[0] = parseInt(s, 10) //TODO PERF Should we replace that with ~~ (not not)? https://jsperf.com/number-vs-parseint-vs-plus/7\r\n x = y\r\n d = s.indexOf(',', 0)\r\n if (d < 1) break\r\n //$off\r\n s = s.substring(d + 1)\r\n if (s.length == 0) break\r\n }\r\n //$off\r\n if (x.length < minSize) {\r\n //$off\r\n y = new Array(minSize)\r\n copy_(y, x)\r\n return y\r\n }\r\n return x\r\n }\r\n\r\n x = int2bigInt(0, base * k, 0)\r\n for (i = 0; i < k; i++) {\r\n d = digitsStr.indexOf(s.substring(i, i + 1), 0)\r\n if (base <= 36 && d >= 36)\r\n //convert lowercase to uppercase if base<=36\r\n d -= 26\r\n if (d >= base || d < 0) {\r\n //stop at first illegal character\r\n break\r\n }\r\n multInt_(x, base)\r\n addInt_(x, d)\r\n }\r\n\r\n for (k = x.length; k > 0 && !x[k - 1]; k--); //strip off leading zeros\r\n //$off\r\n k = minSize > k + 1 ? minSize : k + 1\r\n //$off\r\n y = new Array(k)\r\n //$off\r\n kk = k < x.length ? k : x.length\r\n //$off\r\n for (i = 0; i < kk; i++) y[i] = x[i]\r\n //$off\r\n for (; i < k; i++) y[i] = 0\r\n return y\r\n}\r\n\r\n//return the bigInt given a string representation in a given base.\r\n//Pad the array with leading zeros so that it has at least minSize elements.\r\n//If base=-1, then it reads in a space-separated list of array elements in decimal.\r\n//The array will always have at least one leading zero, unless base=-1.\r\n// function str2bigInt(s,b,minSize) {\r\n// var d, i, j, base, str, x, y, kk;\r\n// if (typeof b === 'string') {\r\n// base = b.length;\r\n// str = b;\r\n// } else {\r\n// base = b;\r\n// str = digitsStr;\r\n// }\r\n// var k=s.length;\r\n// if (base==-1) { //comma-separated list of array elements in decimal\r\n// x=new Array(0);\r\n// for (;;) {\r\n// y=new Array(x.length+1);\r\n// for (i=0;i<x.length;i++)\r\n// y[i+1]=x[i];\r\n// y[0]=parseInt(s,10);\r\n// x=y;\r\n// d=s.indexOf(',',0);\r\n// if (d<1)\r\n// break;\r\n// s=s.substring(d+1);\r\n// if (s.length==0)\r\n// break;\r\n// }\r\n// if (x.length<minSize) {\r\n// y=new Array(minSize);\r\n// copy_(y,x);\r\n// return y;\r\n// }\r\n// return x;\r\n// }\r\n\r\n// x=int2bigInt(0,base*k,0);\r\n// for (i=0;i<k;i++) {\r\n// d=str.indexOf(s.substring(i,i+1),0);\r\n// if (base<=36 && d>=36) { //convert lowercase to uppercase if base<=36\r\n// d-=26;\r\n// }\r\n// if (d>=base || d<0) { //ignore illegal characters\r\n// continue;\r\n// }\r\n// multInt_(x,base);\r\n// addInt_(x,d);\r\n// }\r\n\r\n// for (k=x.length;k>0 && !x[k-1];k--); //strip off leading zeros\r\n// k=minSize>k+1 ? minSize : k+1;\r\n// y=new Array(k);\r\n// kk=k<x.length ? k : x.length;\r\n// for (i=0;i<kk;i++)\r\n// y[i]=x[i];\r\n// for (;i<k;i++)\r\n// y[i]=0;\r\n// return y;\r\n// }\r\n\r\n/**\r\n * is bigint x equal to integer y?\r\n *\r\n * y must have less than bpe bits\r\n *\r\n * @export\r\n * @param {number[]} x\r\n * @param {number} y\r\n * @returns {(1 | 0)}\r\n */\r\nexport function equalsInt(x: number[], y: number): Bool {\r\n var i\r\n if (x[0] != y) return 0\r\n for (i = 1; i < x.length; i++) if (x[i]) return 0\r\n return 1\r\n}\r\n\r\n/**\r\n * are bigints x and y equal?\r\n *\r\n * this works even if x and y are different lengths and have arbitrarily many leading zeros\r\n *\r\n * @param {number[]} x\r\n * @param {number[]} y\r\n * @returns {(1 | 0)}\r\n */\r\nexport function equals(x: number[], y: number[]): Bool {\r\n var i\r\n var k = x.length < y.length ? x.length : y.length\r\n for (i = 0; i < k; i++) if (x[i] !== y[i]) return 0\r\n if (x.length > y.length) {\r\n for (; i < x.length; i++) if (x[i]) return 0\r\n } else {\r\n for (; i < y.length; i++) if (y[i]) return 0\r\n }\r\n return 1\r\n}\r\n\r\n/**\r\n * is the bigInt x equal to zero?\r\n *\r\n * @export\r\n * @param {number[]} x\r\n * @returns {(1 | 0)}\r\n */\r\nexport function isZero(x: number[]): Bool {\r\n var i\r\n for (i = 0; i < x.length; i++) if (x[i]) return 0\r\n return 1\r\n}\r\n\r\n/**\r\n * Convert a bigInt into a string in a given base, from base 2 up to base 95.\r\n *\r\n * Base -1 prints the contents of the array representing the number.\r\n *\r\n * @export\r\n * @param {number[]} x\r\n * @param {number} base\r\n * @returns {string}\r\n */\r\nexport function bigInt2str(x: number[], base: number): string {\r\n var i,\r\n t,\r\n s = ''\r\n\r\n if (s6.length !== x.length) s6 = dup(x)\r\n else copy_(s6, x)\r\n\r\n if (base === -1) {\r\n //return the list of array contents\r\n for (i = x.length - 1; i > 0; i--) s += x[i] + ','\r\n s += x[0]\r\n } else {\r\n //return it in the given base\r\n while (!isZero(s6)) {\r\n t = divInt_(s6, base) //t=s6 % base; s6=floor(s6/base);\r\n s = digitsStr.substring(t, t + 1) + s\r\n }\r\n }\r\n if (s.length === 0) s = '0'\r\n return s\r\n}\r\n\r\n/**\r\n * Convert a bigInt into bytes\r\n * @param x bigInt\r\n * @param littleEndian byte order by default\r\n */\r\nexport function bigInt2bytes(x: number[], littleEndian = true) {\r\n if(s6.length !== x.length) s6 = dup(x);\r\n else copy_(s6, x);\r\n\r\n const out: number[] = [];\r\n\r\n //console.log('bigInt2bytes');\r\n while(!isZero(s6)) {\r\n t = divInt_(s6, 256); //t=s6 % base; s6=floor(s6/base);\r\n out.push(t);\r\n //console.log('bigInt2bytes', t);\r\n }\r\n\r\n if(littleEndian) {\r\n out.reverse();\r\n }\r\n\r\n //console.log('bigInt2bytes', out);\r\n\r\n return out;\r\n}\r\n\r\n/**\r\n * Compare two bigInts and return -1 if x is less, 0 if equals, 1 if greater\r\n * @param x bigInt\r\n * @param y bigInt\r\n */\r\nexport function cmp(x: number[], y: number[]) {\r\n return greater(x, y) ? 1 : (equals(x, y) ? 0 : -1);\r\n}\r\n\r\n/* Object.assign(self, {\r\n cmp,\r\n str2bigInt,\r\n int2bigInt,\r\n bigInt2str,\r\n one,\r\n divide_,\r\n divInt_,\r\n dup,\r\n negative\r\n}); */\r\n\r\n/**\r\n * Returns a duplicate of bigInt x\r\n *\r\n * @export\r\n * @param {number[]} x\r\n * @returns {number[]}\r\n */\r\nexport function dup(x: number[]): number[] {\r\n var i\r\n buff = Array(x.length)\r\n copy_(buff, x)\r\n return buff\r\n}\r\n\r\n/**\r\n * do x=y on bigInts x and y.\r\n *\r\n * x must be an array at least as big as y (not counting the leading zeros in y).\r\n *\r\n * @export\r\n * @param {number[]} x\r\n * @param {number[]} y\r\n * @returns {void}\r\n */\r\nexport function copy_(x: number[], y: number[]): void {\r\n var i\r\n var k = x.length < y.length ? x.length : y.length\r\n for (i = 0; i < k; i++) x[i] = y[i]\r\n for (i = k; i < x.length; i++) x[i] = 0\r\n}\r\n\r\n/**\r\n * do x=y on bigInt x and integer y.\r\n *\r\n * @export\r\n * @param {number[]} x\r\n * @param {number} n\r\n * @returns {void}\r\n */\r\nexport function copyInt_(x: number[], n: number): void {\r\n var i, c\r\n var len = x.length //TODO .length in for loop have perfomance costs. Bench this\r\n for (c = n, i = 0; i < len; i++) {\r\n x[i] = c & mask\r\n c >>= bpe\r\n }\r\n}\r\n\r\n/**\r\n * do x=x+n where x is a bigInt and n is an integer.\r\n *\r\n * x must be large enough to hold the result.\r\n *\r\n * @export\r\n * @param {number[]} x\r\n * @param {number} n\r\n * @returns {void}\r\n */\r\nexport function addInt_(x: number[], n: number): void {\r\n var i, k, c, b\r\n x[0] += n\r\n k = x.length\r\n c = 0\r\n for (i = 0; i < k; i++) {\r\n c += x[i]\r\n b = 0\r\n if (c < 0) {\r\n b = -(c >> bpe)\r\n c += b * radix\r\n }\r\n x[i] = c & mask\r\n c = (c >> bpe) - b\r\n if (!c) return //stop carrying as soon as the carry is zero\r\n }\r\n}\r\n\r\n/**\r\n * right shift bigInt x by n bits.\r\n *\r\n * 0 <= n < bpe.\r\n *\r\n * @export\r\n * @param {number[]} x\r\n * @param {number} n\r\n */\r\nexport function rightShift_(x: number[], n: number): void {\r\n var i\r\n var k = Math.floor(n / bpe)\r\n if (k) {\r\n for (\r\n i = 0;\r\n i < x.length - k;\r\n i++ //right shift x by k elements\r\n )\r\n x[i] = x[i + k]\r\n for (; i < x.length; i++) x[i] = 0\r\n //$off\r\n n %= bpe\r\n }\r\n for (i = 0; i < x.length - 1; i++) {\r\n x[i] = mask & ((x[i + 1] << (bpe - n)) | (x[i] >> n))\r\n }\r\n x[i] >>= n\r\n}\r\n\r\n/**\r\n * do x=floor(|x|/2)*sgn(x) for bigInt x in 2's complement\r\n *\r\n * @param {number[]} x\r\n * @returns {void}\r\n */\r\nexport function halve_(x: number[]): void {\r\n var i\r\n for (i = 0; i < x.length - 1; i++) {\r\n x[i] = mask & ((x[i + 1] << (bpe - 1)) | (x[i] >> 1))\r\n }\r\n x[i] = (x[i] >> 1) | (x[i] & (radix >> 1)) //most significant bit stays the same\r\n}\r\n\r\n/**\r\n * left shift bigInt x by n bits\r\n *\r\n * @export\r\n * @param {number[]} x\r\n * @param {number} n\r\n * @returns {void}\r\n */\r\nexport function leftShift_(x: number[], n: number): void {\r\n var i\r\n var k = Math.floor(n / bpe)\r\n if (k) {\r\n for (\r\n i = x.length;\r\n i >= k;\r\n i-- //left shift x by k elements\r\n )\r\n x[i] = x[i - k]\r\n for (; i >= 0; i--) x[i] = 0\r\n //$off\r\n n %= bpe\r\n }\r\n if (!n) return\r\n for (i = x.length - 1; i > 0; i--) {\r\n x[i] = mask & ((x[i] << n) | (x[i - 1] >> (bpe - n)))\r\n }\r\n x[i] = mask & (x[i] << n)\r\n}\r\n\r\n/**\r\n * do x=x*n where x is a bigInt and n is an integer.\r\n *\r\n * x must be large enough to hold the result.\r\n *\r\n * @param {number[]} x\r\n * @param {number} n\r\n * @returns {void}\r\n */\r\nexport function multInt_(x: number[], n: number): void {\r\n var i, k, c, b\r\n if (!n) return\r\n k = x.length\r\n c = 0\r\n for (i = 0; i < k; i++) {\r\n c += x[i] * n\r\n b = 0\r\n if (c < 0) {\r\n b = -(c >> bpe)\r\n c += b * radix\r\n }\r\n x[i] = c & mask\r\n c = (c >> bpe) - b\r\n }\r\n}\r\n\r\n/**\r\n * do x=floor(x/n) for bigInt x and integer n, and return the remainder\r\n *\r\n * @param {number[]} x\r\n * @param {number} n\r\n * @returns {number} remainder\r\n */\r\nexport function divInt_(x: number[], n: number): number {\r\n var i,\r\n r = 0,\r\n s\r\n for (i = x.length - 1; i >= 0; i--) {\r\n s = r * radix + x[i]\r\n x[i] = Math.floor(s / n)\r\n r = s % n\r\n }\r\n return r\r\n}\r\n\r\n/**\r\n * do the linear combination x=a*x+b*y for bigInts x and y, and integers a and b.\r\n *\r\n * x must be large enough to hold the answer.\r\n *\r\n * @param {number[]} x\r\n * @param {number[]} y\r\n * @param {number} a\r\n * @param {number} b\r\n * @returns {void}\r\n */\r\nexport function linComb_(x: number[], y: number[], a: number, b: number): void {\r\n var i, c, k, kk\r\n k = x.length < y.length ? x.length : y.length\r\n kk = x.length\r\n for (c = 0, i = 0; i < k; i++) {\r\n c += a * x[i] + b * y[i]\r\n x[i] = c & mask\r\n c >>= bpe\r\n }\r\n for (i = k; i < kk; i++) {\r\n c += a * x[i]\r\n x[i] = c & mask\r\n c >>= bpe\r\n }\r\n}\r\n\r\n/**\r\n * do the linear combination x=a*x+b*(y<<(ys*bpe)) for bigInts x and y, and integers a, b and ys.\r\n *\r\n * x must be large enough to hold the answer.\r\n *\r\n * @param {number[]} x\r\n * @param {number[]} y\r\n * @param {number} b\r\n * @param {number} ys\r\n * @returns {void}\r\n */\r\nexport function linCombShift_(\r\n x: number[],\r\n y: number[],\r\n b: number,\r\n ys: number,\r\n): void {\r\n var i, c, k, kk\r\n k = x.length < ys + y.length ? x.length : ys + y.length\r\n kk = x.length\r\n for (c = 0, i = ys; i < k; i++) {\r\n c += x[i] + b * y[i - ys]\r\n x[i] = c & mask\r\n c >>= bpe\r\n }\r\n for (i = k; c && i < kk; i++) {\r\n c += x[i]\r\n x[i] = c & mask\r\n c >>= bpe\r\n }\r\n}\r\n\r\n/**\r\n * do x=x+(y<<(ys*bpe)) for bigInts x and y, and integer ys.\r\n *\r\n * x must be large enough to hold the answer.\r\n *\r\n * @export\r\n * @param {number[]} x\r\n * @param {number[]} y\r\n * @param {number} ys\r\n * @return {void}\r\n */\r\nexport function addShift_(x: number[], y: number[], ys: number): void {\r\n var i, c, k, kk\r\n k = x.length < ys + y.length ? x.length : ys + y.length\r\n kk = x.length\r\n for (c = 0, i = ys; i < k; i++) {\r\n c += x[i] + y[i - ys]\r\n x[i] = c & mask\r\n c >>= bpe\r\n }\r\n for (i = k; c && i < kk; i++) {\r\n c += x[i]\r\n x[i] = c & mask\r\n c >>= bpe\r\n }\r\n}\r\n\r\n/**\r\n * do x=x-(y<<(ys*bpe)) for bigInts x and y, and integer ys\r\n *\r\n * x must be large enough to hold the answer\r\n *\r\n * @param {number[]} x\r\n * @param {number[]} y\r\n * @param {number} ys\r\n * @return {void}\r\n */\r\nexport function subShift_(x: number[], y: number[], ys: number): void {\r\n var i, c, k, kk\r\n k = x.length < ys + y.length ? x.length : ys + y.length\r\n kk = x.length\r\n for (c = 0, i = ys; i < k; i++) {\r\n c += x[i] - y[i - ys]\r\n x[i] = c & mask\r\n c >>= bpe\r\n }\r\n for (i = k; c && i < kk; i++) {\r\n c += x[i]\r\n x[i] = c & mask\r\n c >>= bpe\r\n }\r\n}\r\n\r\n/**\r\n * do x=x-y for bigInts x and y\r\n *\r\n * x must be large enough to hold the answer\r\n *\r\n * negative answers will be 2s complement\r\n *\r\n * @export\r\n * @param {number[]} x\r\n * @param {number[]} y\r\n * @return {void}\r\n */\r\nexport function sub_(x: number[], y: number[]): void {\r\n var i, c, k, kk\r\n k = x.length < y.length ? x.length : y.length\r\n for (c = 0, i = 0; i < k; i++) {\r\n c += x[i] - y[i]\r\n x[i] = c & mask\r\n c >>= bpe\r\n }\r\n for (i = k; c && i < x.length; i++) {\r\n c += x[i]\r\n x[i] = c & mask\r\n c >>= bpe\r\n }\r\n}\r\n\r\n/**\r\n * do x=x+y for bigInts x and y\r\n *\r\n * x must be large enough to hold the answer\r\n *\r\n * @export\r\n * @param {number[]} x\r\n * @param {number[]} y\r\n * @return {void}\r\n */\r\nexport function add_(x: number[], y: number[]): void {\r\n var i, c, k, kk\r\n k = x.length < y.length ? x.length : y.length\r\n for (c = 0, i = 0; i < k; i++) {\r\n c += x[i] + y[i]\r\n x[i] = c & mask\r\n c >>= bpe\r\n }\r\n for (i = k; c && i < x.length; i++) {\r\n c += x[i]\r\n x[i] = c & mask\r\n c >>= bpe\r\n }\r\n}\r\n\r\n/**\r\n * do x=x*y for bigInts x and y.\r\n *\r\n * This is faster when y<x.\r\n *\r\n * @export\r\n * @param {number[]} x\r\n * @param {number[]} y\r\n * @return {void}\r\n */\r\nexport function mult_(x: number[], y: number[]): void {\r\n var i\r\n if (ss.length != 2 * x.length) ss = new Array(2 * x.length)\r\n copyInt_(ss, 0)\r\n for (i = 0; i < y.length; i++) if (y[i]) linCombShift_(ss, x, y[i], i) //ss=1*ss+y[i]*(x<<(i*bpe))\r\n copy_(x, ss)\r\n}\r\n\r\n/**\r\n * do x=x mod n for bigInts x and n\r\n *\r\n * @export\r\n * @param {number[]} x\r\n * @param {number[]} n\r\n * @return {void}\r\n */\r\nexport function mod_(x: number[], n: number[]): void {\r\n if (s4.length !== x.length) s4 = dup(x)\r\n else copy_(s4, x)\r\n if (s5.length !== x.length) s5 = dup(x)\r\n divide_(s4, n, s5, x) //x = remainder of s4 / n\r\n}\r\n\r\n/**\r\n * do x=x*y mod n for bigInts x,y,n.\r\n *\r\n * for greater speed, let y<x.\r\n *\r\n * @param {number[]} x\r\n * @param {number[]} y\r\n * @param {number[]} n\r\n * @return {void}\r\n */\r\nexport function multMod_(x: number[], y: number[], n: number[]): void {\r\n var i\r\n if (s0.length != 2 * x.length) s0 = new Array(2 * x.length)\r\n copyInt_(s0, 0)\r\n for (i = 0; i < y.length; i++) if (y[i]) linCombShift_(s0, x, y[i], i) //s0=1*s0+y[i]*(x<<(i*bpe))\r\n mod_(s0, n)\r\n copy_(x, s0)\r\n}\r\n\r\n/**\r\n * do x=x*x mod n for bigInts x,n.\r\n *\r\n * @export\r\n * @param {number[]} x\r\n * @param {number[]} n\r\n * @return {void}\r\n */\r\nexport function squareMod_(x: number[], n: number[]): void {\r\n var i, j, d, c, kx, kn, k\r\n for (kx = x.length; kx > 0 && !x[kx - 1]; kx--); //ignore leading zeros in x\r\n k = kx > n.length ? 2 * kx : 2 * n.length //k=# elements in the product, which is twice the elements in the larger of x and n\r\n if (s0.length != k) s0 = new Array(k)\r\n copyInt_(s0, 0)\r\n for (i = 0; i < kx; i++) {\r\n c = s0[2 * i] + x[i] * x[i]\r\n s0[2 * i] = c & mask\r\n c >>= bpe\r\n for (j = i + 1; j < kx; j++) {\r\n c = s0[i + j] + 2 * x[i] * x[j] + c\r\n s0[i + j] = c & mask\r\n c >>= bpe\r\n }\r\n s0[i + kx] = c\r\n }\r\n mod_(s0, n)\r\n copy_(x, s0)\r\n}\r\n\r\n/**\r\n * return x with exactly k leading zero elements\r\n *\r\n * @export\r\n * @param {number[]} x\r\n * @param {number} k\r\n * @returns {number[]}\r\n */\r\nexport function trim(x: number[], k: number): number[] {\r\n var i, y\r\n for (i = x.length; i > 0 && !x[i - 1]; i--);\r\n y = new Array(i + k)\r\n copy_(y, x)\r\n return y\r\n}\r\n\r\n/**\r\n * do `x=x**y mod n`, where x,y,n are bigInts and `**` is exponentiation. `0**0=1`.\r\n *\r\n * this is faster when n is odd.\r\n *\r\n * x usually needs to have as many elements as n.\r\n *\r\n * @param {number[]} x\r\n * @param {number[]} y\r\n * @param {number[]} n\r\n * @return {void}\r\n */\r\nexport function powMod_(x: number[], y: number[], n: number[]): void {\r\n var k1, k2, kn, np\r\n if (s7.length != n.length) s7 = dup(n)\r\n\r\n //for even modulus, use a simple square-and-multiply algorithm,\r\n //rather than using the more complex Montgomery algorithm.\r\n if ((n[0] & 1) == 0) {\r\n copy_(s7, x)\r\n copyInt_(x, 1)\r\n while (!equalsInt(y, 0)) {\r\n if (y[0] & 1) multMod_(x, s7, n)\r\n divInt_(y, 2)\r\n squareMod_(s7, n)\r\n }\r\n return\r\n }\r\n\r\n //calculate np from n for the Montgomery multiplications\r\n copyInt_(s7, 0)\r\n for (kn = n.length; kn > 0 && !n[kn - 1]; kn--);\r\n np = radix - inverseModInt(modInt(n, radix), radix)\r\n s7[kn] = 1\r\n multMod_(x, s7, n) // x = x * 2**(kn*bp) mod n\r\n\r\n if (s3.length != x.length) s3 = dup(x)\r\n else copy_(s3, x)\r\n //$off\r\n // @ts-ignore\r\n for (k1 = y.length - 1; (k1 > 0) & !y[k1]; k1--); //k1=first nonzero element of y\r\n if (y[k1] == 0) {\r\n //anything to the 0th power is 1\r\n copyInt_(x, 1)\r\n return\r\n }\r\n for (k2 = 1 << (bpe - 1); k2 && !(y[k1] & k2); k2 >>= 1); //k2=position of first 1 bit in y[k1]\r\n for (;;) {\r\n if (!(k2 >>= 1)) {\r\n //look at next bit of y\r\n k1--\r\n if (k1 < 0) {\r\n mont_(x, one, n, np)\r\n return\r\n }\r\n k2 = 1 << (bpe - 1)\r\n }\r\n mont_(x, x, n, np)\r\n\r\n if (k2 & y[k1])\r\n //if next bit is a 1\r\n mont_(x, s3, n, np)\r\n }\r\n}\r\n\r\n/**\r\n * do x=x*y*Ri mod n for bigInts x,y,n,\r\n * where Ri = 2**(-kn*bpe) mod n, and kn is the\r\n * number of elements in the n array, not\r\n * counting leading zeros.\r\n *\r\n * x array must have at least as many elemnts as the n array\r\n * It's OK if x and y are the same variable.\r\n *\r\n * must have:\r\n * * x,y < n\r\n * * n is odd\r\n * * np = -(n^(-1)) mod radix\r\n *\r\n * @export\r\n * @param {number[]} x\r\n * @param {number[]} y\r\n * @param {number[]} n\r\n * @param {number} np\r\n * @return {void}\r\n */\r\nexport function mont_(x: number[], y: number[], n: number[], np: number): void {\r\n var i, j, c, ui, t, ks\r\n var kn = n.length\r\n var ky = y.length\r\n\r\n if (sa.length != kn) sa = new Array(kn)\r\n\r\n copyInt_(sa, 0)\r\n\r\n for (; kn > 0 && n[kn - 1] == 0; kn--); //ignore leading zeros of n\r\n for (; ky > 0 && y[ky - 1] == 0; ky--); //ignore leading zeros of y\r\n ks = sa.length - 1 //sa will never have more than this many nonzero elements.\r\n\r\n //the following loop consumes 95% of the runtime for randTruePrime_() and powMod_() for large numbers\r\n for (i = 0; i < kn; i++) {\r\n t = sa[0] + x[i] * y[0]\r\n ui = ((t & mask) * np) & mask //the inner \"& mask\" was needed on Safari (but not MSIE) at one time\r\n c = (t + ui * n[0]) >> bpe\r\n t = x[i]\r\n\r\n //do sa=(sa+x[i]*y+ui*n)/b where b=2**bpe. Loop is unrolled 5-fold for speed\r\n j = 1\r\n for (; j < ky - 4; ) {\r\n c += sa[j] + ui * n[j] + t * y[j]\r\n sa[j - 1] = c & mask\r\n c >>= bpe\r\n j++\r\n c += sa[j] + ui * n[j] + t * y[j]\r\n sa[j - 1] = c & mask\r\n c >>= bpe\r\n j++\r\n c += sa[j] + ui * n[j] + t * y[j]\r\n sa[j - 1] = c & mask\r\n c >>= bpe\r\n j++\r\n c += sa[j] + ui * n[j] + t * y[j]\r\n sa[j - 1] = c & mask\r\n c >>= bpe\r\n j++\r\n c += sa[j] + ui * n[j] + t * y[j]\r\n sa[j - 1] = c & mask\r\n c >>= bpe\r\n j++\r\n }\r\n for (; j < ky; ) {\r\n c += sa[j] + ui * n[j] + t * y[j]\r\n sa[j - 1] = c & mask\r\n c >>= bpe\r\n j++\r\n }\r\n for (; j < kn - 4; ) {\r\n c += sa[j] + ui * n[j]\r\n sa[j - 1] = c & mask\r\n c >>= bpe\r\n j++\r\n c += sa[j] + ui * n[j]\r\n sa[j - 1] = c & mask\r\n c >>= bpe\r\n j++\r\n c += sa[j] + ui * n[j]\r\n sa[j - 1] = c & mask\r\n c >>= bpe\r\n j++\r\n c += sa[j] + ui * n[j]\r\n sa[j - 1] = c & mask\r\n c >>= bpe\r\n j++\r\n c += sa[j] + ui * n[j]\r\n sa[j - 1] = c & mask\r\n c >>= bpe\r\n j++\r\n }\r\n for (; j < kn; ) {\r\n c += sa[j] + ui * n[j]\r\n sa[j - 1] = c & mask\r\n c >>= bpe\r\n j++\r\n }\r\n for (; j < ks; ) {\r\n c += sa[j]\r\n sa[j - 1] = c & mask\r\n c >>= bpe\r\n j++\r\n }\r\n sa[j - 1] = c & mask\r\n }\r\n\r\n if (!greater(n, sa)) sub_(sa, n)\r\n copy_(x, sa)\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 rootScope from \"../rootScope\";\r\nimport appPeersManager from \"./appPeersManager\";\r\nimport appMessagesManager from \"./appMessagesManager\";\r\nimport apiUpdatesManager from \"./apiUpdatesManager\";\r\nimport RichTextProcessor from \"../richtextprocessor\";\r\nimport serverTimeManager from \"../mtproto/serverTimeManager\";\r\nimport { MessageEntity, DraftMessage, MessagesSaveDraft } from \"../../layer\";\r\nimport apiManager from \"../mtproto/mtprotoworker\";\r\nimport { tsNow } from \"../../helpers/date\";\r\nimport { deepEqual } from \"../../helpers/object\";\r\nimport appStateManager from \"./appStateManager\";\r\nimport { isObject } from \"../mtproto/bin_utils\";\r\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\r\n\r\nexport type MyDraftMessage = DraftMessage.draftMessage;\r\n\r\nexport class AppDraftsManager {\r\n private drafts: {[peerIdAndThreadId: string]: MyDraftMessage} = {};\r\n private getAllDraftPromise: Promise<void> = null;\r\n\r\n constructor() {\r\n appStateManager.getState().then(state => {\r\n this.drafts = state.drafts;\r\n\r\n appStateManager.addEventListener('save', async() => {\r\n appStateManager.pushToState('drafts', this.drafts);\r\n });\r\n });\r\n\r\n rootScope.addMultipleEventsListeners({\r\n updateDraftMessage: (update) => {\r\n const peerID = appPeersManager.getPeerId(update.peer);\r\n this.saveDraft(peerID, (update as any).threadId, update.draft, {notify: true});\r\n }\r\n });\r\n }\r\n\r\n private getKey(peerId: number, threadId?: number) {\r\n return '' + peerId + (threadId ? '_' + threadId : '');\r\n }\r\n\r\n public getDraft(peerId: number, threadId?: number) {\r\n return this.drafts[this.getKey(peerId, threadId)];\r\n }\r\n\r\n public addMissedDialogs() {\r\n return this.getAllDrafts().then(() => {\r\n for(const key in this.drafts) {\r\n if(key.indexOf('_') !== -1) { // exclude threads\r\n continue;\r\n }\r\n\r\n const peerId = +key;\r\n const dialog = appMessagesManager.getDialogByPeerId(peerId)[0];\r\n if(!dialog) {\r\n appMessagesManager.reloadConversation(peerId);\r\n /* const dialog = appMessagesManager.generateDialog(peerId);\r\n dialog.draft = this.drafts[key];\r\n appMessagesManager.saveConversation(dialog);\r\n appMessagesManager.newDialogsToHandle[peerId] = dialog;\r\n appMessagesManager.scheduleHandleNewDialogs(); */\r\n }\r\n }\r\n });\r\n }\r\n\r\n public getAllDrafts() {\r\n return this.getAllDraftPromise || (this.getAllDraftPromise = new Promise((resolve) => {\r\n apiManager.invokeApi('messages.getAllDrafts').then((updates) => {\r\n const p = apiUpdatesManager.updatesState.syncLoading || Promise.resolve();\r\n p.then(() => {\r\n apiUpdatesManager.processUpdateMessage(updates);\r\n });\r\n \r\n resolve();\r\n });\r\n }));\r\n }\r\n\r\n public saveDraft(peerId: number, threadId: number, apiDraft: DraftMessage, options: Partial<{\r\n notify: boolean\r\n }> = {}) {\r\n const draft = this.processApiDraft(apiDraft);\r\n\r\n const key = this.getKey(peerId, threadId);\r\n if(draft) {\r\n this.drafts[key] = draft;\r\n } else {\r\n delete this.drafts[key];\r\n }\r\n\r\n if(options.notify) {\r\n // console.warn(dT(), 'save draft', peerId, apiDraft, options)\r\n rootScope.broadcast('draft_updated', {\r\n peerId,\r\n threadId,\r\n draft\r\n });\r\n }\r\n\r\n return draft;\r\n }\r\n\r\n public draftsAreEqual(draft1: DraftMessage, draft2: DraftMessage) {\r\n if(typeof(draft1) !== typeof(draft2)) {\r\n return false;\r\n }\r\n\r\n if(!isObject(draft1)) {\r\n return true;\r\n }\r\n\r\n if(draft1._ !== draft2._) {\r\n return false;\r\n }\r\n \r\n if(draft1._ === 'draftMessage' && draft2._ === draft1._) {\r\n if(draft1.reply_to_msg_id !== draft2.reply_to_msg_id) {\r\n return false;\r\n }\r\n \r\n if(!deepEqual(draft1.entities, draft2.entities)) {\r\n return false;\r\n }\r\n \r\n if(draft1.message !== draft2.message) {\r\n return false;\r\n }\r\n \r\n if(draft1.pFlags.no_webpage !== draft2.pFlags.no_webpage) {\r\n return false;\r\n }\r\n }\r\n\r\n return true;\r\n }\r\n\r\n public isEmptyDraft(draft: DraftMessage) {\r\n if(!draft || draft._ === 'draftMessageEmpty') {\r\n return true;\r\n }\r\n \r\n if(draft.reply_to_msg_id > 0) {\r\n return false;\r\n }\r\n \r\n if(!draft.message.length) {\r\n return true;\r\n }\r\n \r\n return false;\r\n }\r\n\r\n public processApiDraft(draft: DraftMessage): MyDraftMessage {\r\n if(!draft || draft._ !== 'draftMessage') {\r\n return undefined;\r\n }\r\n\r\n const myEntities = RichTextProcessor.parseEntities(draft.message);\r\n const apiEntities = draft.entities || [];\r\n const totalEntities = RichTextProcessor.mergeEntities(apiEntities, myEntities); // ! only in this order, otherwise bold and emoji formatting won't work\r\n\r\n draft.rMessage = RichTextProcessor.wrapDraftText(draft.message, {entities: totalEntities});\r\n //draft.rReply = appMessagesManager.getRichReplyText(draft);\r\n if(draft.reply_to_msg_id) {\r\n draft.reply_to_msg_id = appMessagesManager.generateMessageId(draft.reply_to_msg_id);\r\n }\r\n\r\n return draft;\r\n }\r\n\r\n public async syncDraft(peerId: number, threadId: number, localDraft?: MyDraftMessage, saveOnServer = true) {\r\n // console.warn(dT(), 'sync draft', peerID)\r\n const serverDraft = this.getDraft(peerId, threadId);\r\n if(this.draftsAreEqual(serverDraft, localDraft)) {\r\n // console.warn(dT(), 'equal drafts', localDraft, serverDraft)\r\n return true;\r\n }\r\n\r\n // console.warn(dT(), 'changed draft', localDraft, serverDraft)\r\n let params: MessagesSaveDraft = {\r\n peer: appPeersManager.getInputPeerById(peerId),\r\n message: ''\r\n };\r\n\r\n let draftObj: DraftMessage;\r\n if(this.isEmptyDraft(localDraft)) {\r\n draftObj = {_: 'draftMessageEmpty'};\r\n } else {\r\n let message = localDraft.message;\r\n let entities: MessageEntity[] = localDraft.entities;\r\n\r\n if(localDraft.reply_to_msg_id) {\r\n params.reply_to_msg_id = appMessagesManager.getServerMessageId(localDraft.reply_to_msg_id);\r\n }\r\n\r\n if(entities?.length) {\r\n params.entities = entities;\r\n }\r\n\r\n if(localDraft.pFlags.no_webpage) {\r\n params.no_webpage = localDraft.pFlags.no_webpage;\r\n }\r\n\r\n params.message = message;\r\n }\r\n\r\n const saveLocalDraft = draftObj || localDraft;\r\n saveLocalDraft.date = tsNow(true) + serverTimeManager.serverTimeOffset;\r\n\r\n this.saveDraft(peerId, threadId, saveLocalDraft, {notify: true});\r\n\r\n if(saveOnServer && !threadId) {\r\n return apiManager.invokeApi('messages.saveDraft', params);\r\n }\r\n\r\n return true;\r\n }\r\n}\r\n\r\nconst appDraftsManager = new AppDraftsManager();\r\nMOUNT_CLASS_TO.appDraftsManager = appDraftsManager;\r\nexport default appDraftsManager;\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 { bufferConcats } from '../../helpers/bytes';\r\nimport { add_, bigInt2str, cmp, leftShift_, str2bigInt } from '../../vendor/leemon';\r\nimport { nextRandomInt } from '../../helpers/random';\r\n\r\n///////////////////////\r\n/////////////\r\n/////////////////////////////////////////////////\r\n\r\n///////////////////////////////////////////////////////////////////////////\r\n/////////////////////////////////////////////////////////////////////////////////\r\n/////////////////////////////////////////////////////////////////////////////////////////////\r\n///////////////////////////////////////////////\r\n//////////////////////////////////////////////////////////////////////////\r\n//////////////////////////////////////////////////////////////\r\n////////////////\r\n \r\n//////////\r\n\r\nexport function isObject(object: any) {\r\n return typeof(object) === 'object' && object !== null;\r\n}\r\n\r\n/* export function bigint(num: number) {\r\n return new BigInteger(num.toString(16), 16);\r\n} */\r\n\r\n/* export function bigStringInt(strNum: string) {\r\n return new BigInteger(strNum, 10);\r\n} */\r\n\r\n/* export function base64ToBlob(base64str: string, mimeType: string) {\r\n var sliceSize = 1024;\r\n var byteCharacters = atob(base64str);\r\n var bytesLength = byteCharacters.length;\r\n var slicesCount = Math.ceil(bytesLength / sliceSize);\r\n var byteArrays = new Array(slicesCount);\r\n\r\n for(var sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) {\r\n var begin = sliceIndex * sliceSize;\r\n var end = Math.min(begin + sliceSize, bytesLength);\r\n\r\n var bytes = new Array(end - begin);\r\n for(var offset = begin, i = 0; offset < end; ++i, ++offset) {\r\n bytes[i] = byteCharacters[offset].charCodeAt(0);\r\n }\r\n byteArrays[sliceIndex] = new Uint8Array(bytes);\r\n }\r\n\r\n return blobConstruct(byteArrays, mimeType);\r\n}\r\n\r\nexport function dataUrlToBlob(url: string) {\r\n // var name = 'b64blob ' + url.length\r\n // console.time(name)\r\n var urlParts = url.split(',');\r\n var base64str = urlParts[1];\r\n var mimeType = urlParts[0].split(':')[1].split(';')[0];\r\n var blob = base64ToBlob(base64str, mimeType);\r\n // console.timeEnd(name)\r\n return blob;\r\n} */\r\n\r\n/* export function bytesFromBigInt(bigInt: BigInteger, len?: number) {\r\n var bytes = bigInt.toByteArray();\r\n\r\n if(len && bytes.length < len) {\r\n var padding = [];\r\n for(var i = 0, needPadding = len - bytes.length; i < needPadding; i++) {\r\n padding[i] = 0;\r\n }\r\n if(bytes instanceof ArrayBuffer) {\r\n bytes = bufferConcat(padding, bytes);\r\n } else {\r\n bytes = padding.concat(bytes);\r\n }\r\n } else {\r\n while (!bytes[0] && (!len || bytes.length > len)) {\r\n bytes = bytes.slice(1);\r\n }\r\n }\r\n\r\n return bytes;\r\n} */\r\n\r\nexport function longFromInts(high: number, low: number): string {\r\n //let perf = performance.now();\r\n //let str = bigint(high).shiftLeft(32).add(bigint(low)).toString(10);\r\n //console.log('longFromInts jsbn', performance.now() - perf);\r\n \r\n //perf = performance.now();\r\n const bigInt = str2bigInt(high.toString(16), 16, 32);//int2bigInt(high, 64, 64);\r\n //console.log('longFromInts construct high', bigint(high).toString(10), bigInt2str(bigInt, 10));\r\n leftShift_(bigInt, 32);\r\n //console.log('longFromInts shiftLeft', bigint(high).shiftLeft(32).toString(10), bigInt2str(bigInt, 10));\r\n add_(bigInt, str2bigInt(low.toString(16), 16, 32));\r\n const _str = bigInt2str(bigInt, 10);\r\n\r\n //console.log('longFromInts leemon', performance.now() - perf);\r\n\r\n //console.log('longFromInts', high, low, str, _str, str === _str);\r\n\r\n return _str;\r\n}\r\n\r\nexport function sortLongsArray(arr: string[]) {\r\n return arr.map(long => {\r\n return str2bigInt(long, 10);\r\n }).sort((a, b) => {\r\n return cmp(a, b);\r\n }).map(bigInt => {\r\n return bigInt2str(bigInt, 10);\r\n });\r\n}\r\n\r\nexport function addPadding(bytes: any, blockSize: number = 16, zeroes?: boolean, full = false, prepend = false) {\r\n let len = bytes.byteLength || bytes.length;\r\n let needPadding = blockSize - (len % blockSize);\r\n if(needPadding > 0 && (needPadding < blockSize || full)) {\r\n ////console.log('addPadding()', len, blockSize, needPadding);\r\n let padding = new Array(needPadding);\r\n if(zeroes) {\r\n for(let i = 0; i < needPadding; i++) {\r\n padding[i] = 0;\r\n }\r\n } else {\r\n for(let i = 0; i < padding.length; ++i) {\r\n padding[i] = nextRandomInt(255);\r\n }\r\n }\r\n\r\n if(bytes instanceof ArrayBuffer) {\r\n bytes = (prepend ? bufferConcats(padding, bytes) : bufferConcats(bytes, padding)).buffer;\r\n } else if(bytes instanceof Uint8Array) {\r\n bytes = prepend ? bufferConcats(padding, bytes) : bufferConcats(bytes, padding);\r\n } else {\r\n bytes = prepend ? padding.concat(bytes) : bytes.concat(padding);\r\n }\r\n }\r\n\r\n return bytes;\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 { blobConstruct } from \"../helpers/blob\";\r\n\r\nexport class FileManager {\r\n public blobSupported = true;\r\n \r\n constructor() {\r\n try {\r\n blobConstruct([], '');\r\n } catch(e) {\r\n this.blobSupported = false;\r\n }\r\n }\r\n \r\n public isAvailable() {\r\n return this.blobSupported;\r\n }\r\n \r\n public write(fileWriter: ReturnType<FileManager['getFakeFileWriter']>, bytes: Uint8Array | Blob | string): Promise<void> {\r\n if(bytes instanceof Blob) { // is file bytes\r\n return new Promise((resolve, reject) => {\r\n let fileReader = new FileReader();\r\n fileReader.onload = function(event) {\r\n let arrayBuffer = event.target.result as ArrayBuffer;\r\n \r\n let arr = new Uint8Array(arrayBuffer);\r\n \r\n fileWriter.write(arr).then(resolve, reject);\r\n };\r\n \r\n fileReader.readAsArrayBuffer(bytes);\r\n });\r\n } else {\r\n return fileWriter.write(bytes);\r\n }\r\n }\r\n\r\n public getFakeFileWriter(mimeType: string, saveFileCallback?: (blob: Blob) => Promise<Blob>) {\r\n const blobParts: Array<Uint8Array | string> = [];\r\n const fakeFileWriter = {\r\n write: async(part: Uint8Array | string) => {\r\n if(!this.blobSupported) {\r\n throw false;\r\n }\r\n \r\n blobParts.push(part);\r\n },\r\n truncate: () => {\r\n blobParts.length = 0;\r\n },\r\n finalize: (saveToStorage = true) => {\r\n const blob = blobConstruct(blobParts, mimeType);\r\n\r\n if(saveToStorage && saveFileCallback) {\r\n saveFileCallback(blob);\r\n }\r\n \r\n return blob;\r\n }\r\n };\r\n \r\n return fakeFileWriter;\r\n }\r\n}\r\n\r\nexport default new FileManager();\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 Modes from '../config/modes';\r\nimport { blobConstruct } from '../helpers/blob';\r\nimport FileManager from './filemanager';\r\n//import { MOUNT_CLASS_TO } from './mtproto/mtproto_config';\r\n//import { logger } from './polyfill';\r\n\r\nexport default class CacheStorageController {\r\n private static STORAGES: CacheStorageController[] = [];\r\n //public dbName = 'cachedFiles';\r\n private openDbPromise: Promise<Cache>;\r\n\r\n private useStorage = true;\r\n\r\n //private log: ReturnType<typeof logger> = logger('CS');\r\n\r\n constructor(private dbName: string) {\r\n if(Modes.test) {\r\n this.dbName += '_test';\r\n }\r\n \r\n this.openDatabase();\r\n CacheStorageController.STORAGES.push(this);\r\n }\r\n\r\n private openDatabase(): Promise<Cache> {\r\n if(this.openDbPromise) {\r\n return this.openDbPromise;\r\n }\r\n\r\n return this.openDbPromise = caches.open(this.dbName);\r\n }\r\n\r\n public delete(entryName: string) {\r\n return this.timeoutOperation((cache) => {\r\n return cache.delete('/' + entryName);\r\n });\r\n }\r\n\r\n public deleteAll() {\r\n return caches.delete(this.dbName);\r\n }\r\n\r\n public save(entryName: string, response: Response) {\r\n if(!this.useStorage) return Promise.reject('STORAGE_OFFLINE');\r\n\r\n return this.timeoutOperation((cache) => {\r\n return cache.put('/' + entryName, response);\r\n });\r\n }\r\n\r\n public saveFile(fileName: string, blob: Blob | Uint8Array) {\r\n if(!this.useStorage) return Promise.reject('STORAGE_OFFLINE');\r\n\r\n //return Promise.resolve(blobConstruct([blob]));\r\n if(!(blob instanceof Blob)) {\r\n blob = blobConstruct(blob) as Blob;\r\n }\r\n\r\n return this.save(fileName, new Response(blob)).then(() => {\r\n return blob as Blob;\r\n });\r\n }\r\n\r\n /* public getBlobSize(blob: any) {\r\n return blob.size || blob.byteLength || blob.length;\r\n } */\r\n\r\n public getFile(fileName: string, method: 'blob' | 'json' | 'text' = 'blob'): Promise<any> {\r\n if(!this.useStorage) return Promise.reject('STORAGE_OFFLINE');\r\n\r\n /* if(method === 'blob') {\r\n return Promise.reject();\r\n } */\r\n\r\n // const str = `get fileName: ${fileName}`;\r\n // console.time(str);\r\n return this.timeoutOperation(async(cache) => {\r\n const response = await cache.match('/' + fileName);\r\n\r\n if(!response || !cache) {\r\n //console.warn('getFile:', response, fileName);\r\n throw 'NO_ENTRY_FOUND';\r\n }\r\n \r\n const promise = response[method]();\r\n // promise.then(() => {\r\n // console.timeEnd(str);\r\n // });\r\n return promise;\r\n });\r\n }\r\n\r\n private timeoutOperation<T>(callback: (cache: Cache) => Promise<T>) {\r\n return new Promise<T>(async(resolve, reject) => {\r\n let rejected = false;\r\n const timeout = setTimeout(() => {\r\n reject();\r\n //console.warn('CACHESTORAGE TIMEOUT');\r\n rejected = true;\r\n }, 15e3);\r\n\r\n try {\r\n const cache = await this.openDatabase();\r\n if(!cache) {\r\n throw 'no cache?';\r\n }\r\n\r\n const res = await callback(cache);\r\n\r\n if(rejected) return;\r\n resolve(res);\r\n } catch(err) {\r\n reject(err);\r\n }\r\n\r\n clearTimeout(timeout);\r\n });\r\n }\r\n\r\n public getFileWriter(fileName: string, mimeType: string) {\r\n const fakeWriter = FileManager.getFakeFileWriter(mimeType, (blob) => {\r\n return this.saveFile(fileName, blob);\r\n });\r\n\r\n return Promise.resolve(fakeWriter);\r\n }\r\n\r\n public static toggleStorage(enabled: boolean) {\r\n return Promise.all(this.STORAGES.map(storage => {\r\n storage.useStorage = enabled;\r\n \r\n if(!enabled) {\r\n return storage.deleteAll();\r\n }\r\n }));\r\n }\r\n}\r\n\r\n//const cacheStorage = new CacheStorageController(); \r\n//MOUNT_CLASS_TO.cacheStorage = cacheStorage;\r\n//export default cacheStorage;\r\n","/*\r\nSuperfast Blur - a fast Box Blur For Canvas\r\n\r\nVersion: 0.5\r\nAuthor: Mario Klingemann\r\nContact: mario@quasimondo.com\r\nWebsite: http://www.quasimondo.com/BoxBlurForCanvas\r\nTwitter: @quasimondo\r\n\r\nIn case you find this class useful - especially in commercial projects -\r\nI am not totally unhappy for a small donation to my PayPal account\r\nmario@quasimondo.de\r\n\r\nOr support me on flattr:\r\nhttps://flattr.com/thing/140066/Superfast-Blur-a-pretty-fast-Box-Blur-Effect-for-CanvasJavascript\r\n\r\nCopyright (c) 2011 Mario Klingemann\r\n\r\nPermission is hereby granted, free of charge, to any person\r\nobtaining a copy of this software and associated documentation\r\nfiles (the \"Software\"), to deal in the Software without\r\nrestriction, including without limitation the rights to use,\r\ncopy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the\r\nSoftware is furnished to do so, subject to the following\r\nconditions:\r\n\r\nThe above copyright notice and this permission notice shall be\r\nincluded in all copies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\r\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\r\nOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\r\nHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\r\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\r\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\r\nOTHER DEALINGS IN THE SOFTWARE.\r\n*/\r\n\r\n// eslint-disable-next-line max-len\r\nconst mul_table = [1, 57, 41, 21, 203, 34, 97, 73, 227, 91, 149, 62, 105, 45, 39, 137, 241, 107, 3, 173, 39, 71, 65, 238, 219, 101, 187, 87, 81, 151, 141, 133, 249, 117, 221, 209, 197, 187, 177, 169, 5, 153, 73, 139, 133, 127, 243, 233, 223, 107, 103, 99, 191, 23, 177, 171, 165, 159, 77, 149, 9, 139, 135, 131, 253, 245, 119, 231, 224, 109, 211, 103, 25, 195, 189, 23, 45, 175, 171, 83, 81, 79, 155, 151, 147, 9, 141, 137, 67, 131, 129, 251, 123, 30, 235, 115, 113, 221, 217, 53, 13, 51, 50, 49, 193, 189, 185, 91, 179, 175, 43, 169, 83, 163, 5, 79, 155, 19, 75, 147, 145, 143, 35, 69, 17, 67, 33, 65, 255, 251, 247, 243, 239, 59, 29, 229, 113, 111, 219, 27, 213, 105, 207, 51, 201, 199, 49, 193, 191, 47, 93, 183, 181, 179, 11, 87, 43, 85, 167, 165, 163, 161, 159, 157, 155, 77, 19, 75, 37, 73, 145, 143, 141, 35, 138, 137, 135, 67, 33, 131, 129, 255, 63, 250, 247, 61, 121, 239, 237, 117, 29, 229, 227, 225, 111, 55, 109, 216, 213, 211, 209, 207, 205, 203, 201, 199, 197, 195, 193, 48, 190, 47, 93, 185, 183, 181, 179, 178, 176, 175, 173, 171, 85, 21, 167, 165, 41, 163, 161, 5, 79, 157, 78, 154, 153, 19, 75, 149, 74, 147, 73, 144, 143, 71, 141, 140, 139, 137, 17, 135, 134, 133, 66, 131, 65, 129, 1];\r\n// eslint-disable-next-line max-len\r\nconst shg_table = [0, 9, 10, 10, 14, 12, 14, 14, 16, 15, 16, 15, 16, 15, 15, 17, 18, 17, 12, 18, 16, 17, 17, 19, 19, 18, 19, 18, 18, 19, 19, 19, 20, 19, 20, 20, 20, 20, 20, 20, 15, 20, 19, 20, 20, 20, 21, 21, 21, 20, 20, 20, 21, 18, 21, 21, 21, 21, 20, 21, 17, 21, 21, 21, 22, 22, 21, 22, 22, 21, 22, 21, 19, 22, 22, 19, 20, 22, 22, 21, 21, 21, 22, 22, 22, 18, 22, 22, 21, 22, 22, 23, 22, 20, 23, 22, 22, 23, 23, 21, 19, 21, 21, 21, 23, 23, 23, 22, 23, 23, 21, 23, 22, 23, 18, 22, 23, 20, 22, 23, 23, 23, 21, 22, 20, 22, 21, 22, 24, 24, 24, 24, 24, 22, 21, 24, 23, 23, 24, 21, 24, 23, 24, 22, 24, 24, 22, 24, 24, 22, 23, 24, 24, 24, 20, 23, 22, 23, 24, 24, 24, 24, 24, 24, 24, 23, 21, 23, 22, 23, 24, 24, 24, 22, 24, 24, 24, 23, 22, 24, 24, 25, 23, 25, 25, 23, 24, 25, 25, 24, 22, 25, 25, 25, 24, 23, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 23, 25, 23, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 24, 22, 25, 25, 23, 25, 25, 20, 24, 25, 24, 25, 25, 22, 24, 25, 24, 25, 24, 25, 25, 24, 25, 25, 25, 25, 22, 25, 25, 25, 24, 25, 24, 25, 18];\r\n\r\nexport default function boxBlurCanvasRGB(context, top_x, top_y, width, height, radius, iterations) {\r\n if (Number.isNaN(radius) || radius < 1) return;\r\n\r\n radius |= 0;\r\n\r\n if (Number.isNaN(iterations)) iterations = 1;\r\n iterations |= 0;\r\n if (iterations > 3) iterations = 3;\r\n if (iterations < 1) iterations = 1;\r\n\r\n const imageData = context.getImageData(top_x, top_y, width, height);\r\n\r\n const pixels = imageData.data;\r\n\r\n let rsum;\r\n let gsum;\r\n let bsum;\r\n let x;\r\n let y;\r\n let i;\r\n let p;\r\n let p1;\r\n let p2;\r\n let yp;\r\n let yi;\r\n let yw;\r\n let wm = width - 1;\r\n let hm = height - 1;\r\n let rad1 = radius + 1;\r\n\r\n let r = [];\r\n let g = [];\r\n let b = [];\r\n\r\n let mul_sum = mul_table[radius];\r\n let shg_sum = shg_table[radius];\r\n\r\n let vmin = [];\r\n let vmax = [];\r\n\r\n while (iterations-- > 0) {\r\n yw = yi = 0;\r\n\r\n for (y = 0; y < height; y++) {\r\n rsum = pixels[yw] * rad1;\r\n gsum = pixels[yw + 1] * rad1;\r\n bsum = pixels[yw + 2] * rad1;\r\n\r\n for (i = 1; i <= radius; i++) {\r\n p = yw + (((i > wm ? wm : i)) << 2);\r\n rsum += pixels[p++];\r\n gsum += pixels[p++];\r\n bsum += pixels[p++];\r\n }\r\n\r\n for (x = 0; x < width; x++) {\r\n r[yi] = rsum;\r\n g[yi] = gsum;\r\n b[yi] = bsum;\r\n\r\n if (y == 0) {\r\n vmin[x] = ((p = x + rad1) < wm ? p : wm) << 2;\r\n vmax[x] = ((p = x - radius) > 0 ? p << 2 : 0);\r\n }\r\n\r\n p1 = yw + vmin[x];\r\n p2 = yw + vmax[x];\r\n\r\n rsum += pixels[p1++] - pixels[p2++];\r\n gsum += pixels[p1++] - pixels[p2++];\r\n bsum += pixels[p1++] - pixels[p2++];\r\n\r\n yi++;\r\n }\r\n yw += (width << 2);\r\n }\r\n\r\n for (x = 0; x < width; x++) {\r\n yp = x;\r\n rsum = r[yp] * rad1;\r\n gsum = g[yp] * rad1;\r\n bsum = b[yp] * rad1;\r\n\r\n for (i = 1; i <= radius; i++) {\r\n yp += (i > hm ? 0 : width);\r\n rsum += r[yp];\r\n gsum += g[yp];\r\n bsum += b[yp];\r\n }\r\n\r\n yi = x << 2;\r\n for (y = 0; y < height; y++) {\r\n pixels[yi] = (rsum * mul_sum) >>> shg_sum;\r\n pixels[yi + 1] = (gsum * mul_sum) >>> shg_sum;\r\n pixels[yi + 2] = (bsum * mul_sum) >>> shg_sum;\r\n\r\n if (x == 0) {\r\n vmin[y] = ((p = y + rad1) < hm ? p : hm) * width;\r\n vmax[y] = ((p = y - radius) > 0 ? p * width : 0);\r\n }\r\n\r\n p1 = x + vmin[y];\r\n p2 = x + vmax[y];\r\n\r\n rsum += r[p1] - r[p2];\r\n gsum += g[p1] - g[p2];\r\n bsum += b[p1] - b[p2];\r\n\r\n yi += width << 2;\r\n }\r\n }\r\n }\r\n\r\n context.putImageData(imageData, top_x, top_y);\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 _DEBUG from '../config/debug';\r\nimport fastBlur from '../vendor/fastBlur';\r\nimport pushHeavyTask from './heavyQueue';\r\n\r\nconst RADIUS = 2;\r\nconst ITERATIONS = 2;\r\n\r\nconst DEBUG = _DEBUG && false;\r\n\r\nfunction processBlur(dataUri: string, radius: number, iterations: number) {\r\n return new Promise<string>((resolve) => {\r\n const img = new Image();\r\n\r\n const perf = performance.now();\r\n if(DEBUG) {\r\n console.log('[blur] start');\r\n }\r\n\r\n img.onload = () => {\r\n const canvas = document.createElement('canvas');\r\n canvas.width = img.width;\r\n canvas.height = img.height;\r\n\r\n const ctx = canvas.getContext('2d')!;\r\n\r\n ctx.drawImage(img, 0, 0);\r\n fastBlur(ctx, 0, 0, canvas.width, canvas.height, radius, iterations);\r\n\r\n //resolve(canvas.toDataURL());\r\n canvas.toBlob(blob => {\r\n resolve(URL.createObjectURL(blob));\r\n\r\n if(DEBUG) {\r\n console.log(`[blur] end, radius: ${radius}, iterations: ${iterations}, time: ${performance.now() - perf}`);\r\n }\r\n });\r\n };\r\n\r\n img.src = dataUri;\r\n });\r\n}\r\n\r\nconst blurPromises: {[dataUri: string]: Promise<string>} = {};\r\n\r\nexport default function blur(dataUri: string, radius: number = RADIUS, iterations: number = ITERATIONS) {\r\n if(blurPromises[dataUri]) return blurPromises[dataUri];\r\n return blurPromises[dataUri] = new Promise<string>((resolve) => {\r\n //return resolve(dataUri);\r\n pushHeavyTask({\r\n items: [[dataUri, radius, iterations]],\r\n context: null,\r\n process: processBlur\r\n }).then(results => {\r\n resolve(results[0]);\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 { CancellablePromise, deferredPromise } from \"./cancellablePromise\";\r\nimport { getHeavyAnimationPromise } from \"../hooks/useHeavyAnimationCheck\";\r\nimport { fastRaf } from \"./schedulers\";\r\n\r\ntype HeavyQueue<T> = {\r\n items: any[], \r\n process: (...args: any[]) => T,\r\n context: any,\r\n promise?: CancellablePromise<ReturnType<HeavyQueue<T>['process']>[]>\r\n};\r\nconst heavyQueue: HeavyQueue<any>[] = [];\r\nlet processingQueue = false;\r\n\r\nexport default function pushHeavyTask<T>(queue: HeavyQueue<T>) {\r\n if(!queue.items.length) {\r\n return Promise.resolve([]);\r\n }\r\n \r\n queue.promise = deferredPromise<T[]>();\r\n heavyQueue.push(queue);\r\n processHeavyQueue();\r\n\r\n return queue.promise;\r\n}\r\n\r\nfunction processHeavyQueue() {\r\n if(!processingQueue) {\r\n const queue = heavyQueue.shift();\r\n timedChunk(queue).finally(() => {\r\n processingQueue = false;\r\n if(heavyQueue.length) {\r\n processHeavyQueue();\r\n }\r\n });\r\n }\r\n}\r\n\r\nfunction timedChunk<T>(queue: HeavyQueue<T>) {\r\n if(!queue.items.length) {\r\n queue.promise.resolve([]);\r\n return Promise.resolve([]);\r\n }\r\n\r\n const todo = queue.items.slice();\r\n const results: T[] = [];\r\n\r\n return new Promise<T[]>((resolve, reject) => {\r\n const f = async() => {\r\n const start = performance.now();\r\n\r\n do {\r\n await getHeavyAnimationPromise();\r\n const possiblePromise = queue.process.apply(queue.context, todo.shift());\r\n let realResult: T;\r\n if(possiblePromise instanceof Promise) {\r\n try {\r\n realResult = await possiblePromise;\r\n } catch(err) {\r\n reject(err);\r\n return;\r\n }\r\n } else {\r\n realResult = possiblePromise;\r\n }\r\n\r\n results.push(realResult);\r\n } while(todo.length > 0 && (performance.now() - start) < 6);\r\n\r\n if(todo.length > 0) {\r\n fastRaf(f);\r\n //setTimeout(f, 25);\r\n } else {\r\n resolve(results);\r\n }\r\n };\r\n\r\n fastRaf(f);\r\n //setTimeout(f, 25);\r\n }).then(queue.promise.resolve, queue.promise.reject);\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 { isSafari } from \"../helpers/userAgent\";\r\nimport { logger, LogLevels } from \"./logger\";\r\n\r\ntype Result = {\r\n bytes: Uint8Array, \r\n waveform?: Uint8Array\r\n};\r\n\r\ntype Task = {\r\n pages: Uint8Array,\r\n withWaveform: boolean,\r\n waveform?: Uint8Array,\r\n callback: {resolve: (result: Result) => void, reject: (err: any) => void},\r\n timeout: number\r\n};\r\n\r\nexport class OpusDecodeController {\r\n private worker: Worker;\r\n private wavWorker : Worker;\r\n private sampleRate = 48000;\r\n private tasks: Array<Task> = [];\r\n private keepAlive = false;\r\n private isPlaySupportedResult: boolean;\r\n private log = logger('OPUS', LogLevels.error);\r\n\r\n public isPlaySupported() {\r\n if(this.isPlaySupportedResult !== undefined) return this.isPlaySupportedResult;\r\n\r\n const audio = document.createElement('audio');\r\n return this.isPlaySupportedResult = !!(audio.canPlayType && audio.canPlayType('audio/ogg;').replace(/no/, ''))/* && false */;\r\n }\r\n\r\n public loadWavWorker() {\r\n if(this.wavWorker) return;\r\n\r\n this.wavWorker = new Worker('waveWorker.min.js');\r\n this.wavWorker.addEventListener('message', (e) => {\r\n const data = e.data;\r\n\r\n this.log('[WAV] got message:', data);\r\n if(data && data.page) {\r\n const bytes = data.page;\r\n this.onTaskEnd(this.tasks.shift(), bytes);\r\n }\r\n });\r\n }\r\n\r\n public loadWorker() {\r\n if(this.worker) return;\r\n\r\n this.worker = new Worker('decoderWorker.min.js');\r\n this.worker.addEventListener('message', (e) => {\r\n const data = e.data;\r\n \r\n this.log('[DECODER] got message', data);\r\n if(data.type === 'done') {\r\n //this.log('[DECODER] send done to wav');\r\n this.wavWorker.postMessage({command: 'done'});\r\n\r\n if(data.waveform) {\r\n this.tasks[0].waveform = data.waveform;\r\n }\r\n } else { // e.data contains decoded buffers as float32 values\r\n //this.log('[DECODER] send encode to wav');\r\n this.wavWorker.postMessage({\r\n command: 'encode',\r\n buffers: e.data\r\n }, isSafari ? undefined : data.map((typedArray: Uint8Array) => typedArray.buffer));\r\n }\r\n });\r\n }\r\n\r\n public setKeepAlive(keepAlive: boolean) {\r\n this.keepAlive = keepAlive;\r\n if(this.keepAlive) {\r\n this.loadWorker();\r\n this.loadWavWorker();\r\n } else if(!this.tasks.length) {\r\n this.terminateWorkers();\r\n }\r\n }\r\n\r\n public onTaskEnd(task: Task, result?: Uint8Array) {\r\n if(!result) {\r\n task.callback.reject('timeout');\r\n } else {\r\n clearTimeout(task.timeout);\r\n task.callback.resolve({bytes: result, waveform: task.waveform});\r\n }\r\n\r\n if(this.tasks.length) {\r\n this.executeNewTask(this.tasks[0]);\r\n }\r\n\r\n this.terminateWorkers();\r\n }\r\n\r\n public terminateWorkers(kill = false) {\r\n if((this.keepAlive || this.tasks.length) && !kill) return;\r\n\r\n if(this.worker) {\r\n this.worker.terminate();\r\n this.worker = null;\r\n }\r\n \r\n if(this.wavWorker) {\r\n this.wavWorker.terminate();\r\n this.wavWorker = null;\r\n }\r\n }\r\n\r\n public executeNewTask(task: Task) {\r\n this.worker.postMessage({ \r\n command: 'init',\r\n decoderSampleRate: this.sampleRate,\r\n outputBufferSampleRate: this.sampleRate\r\n });\r\n\r\n this.wavWorker.postMessage({ \r\n command: 'init',\r\n wavBitDepth: 16,\r\n wavSampleRate: this.sampleRate\r\n });\r\n\r\n //console.log('sending command to worker:', task);\r\n //setTimeout(() => {\r\n this.log('[DECODER] send decode');\r\n this.worker.postMessage({\r\n command: 'decode',\r\n pages: task.pages,\r\n waveform: task.withWaveform\r\n }, isSafari ? undefined : [task.pages.buffer]);\r\n //}, 1e3);\r\n\r\n task.timeout = window.setTimeout(() => {\r\n this.log.error('decode timeout'/* , task */);\r\n\r\n this.terminateWorkers(true);\r\n if(this.tasks.length) {\r\n this.loadWorker();\r\n this.loadWavWorker();\r\n }\r\n\r\n this.onTaskEnd(this.tasks.shift());\r\n }, 10e3);\r\n }\r\n\r\n public pushDecodeTask(pages: Uint8Array, withWaveform: boolean) {\r\n return new Promise<Result>((resolve, reject) => {\r\n const task = {\r\n pages,\r\n withWaveform,\r\n callback: {resolve, reject},\r\n timeout: 0\r\n };\r\n\r\n this.loadWorker();\r\n this.loadWavWorker();\r\n\r\n if(this.tasks.push(task) === 1) {\r\n this.executeNewTask(task);\r\n }\r\n });\r\n }\r\n\r\n public async decode(typedArray: Uint8Array, withWaveform = false) {\r\n return this.pushDecodeTask(typedArray, withWaveform).then(result => {\r\n const dataBlob = new Blob([result.bytes], {type: \"audio/wav\"});\r\n return {url: URL.createObjectURL(dataBlob), waveform: result.waveform};\r\n });\r\n }\r\n}\r\n\r\nconst opusDecodeController = new OpusDecodeController();\r\nMOUNT_CLASS_TO.opusDecodeController = opusDecodeController;\r\nexport default opusDecodeController;","/*\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 appPhotosManager from \"./appPhotosManager\";\r\nimport appDocsManager from \"./appDocsManager\";\r\nimport { RichTextProcessor } from \"../richtextprocessor\";\r\nimport { ReferenceContext } from \"../mtproto/referenceDatabase\";\r\nimport rootScope from \"../rootScope\";\r\nimport { safeReplaceObject } from \"../../helpers/object\";\r\nimport { limitSymbols } from \"../../helpers/string\";\r\n\r\nexport class AppWebPagesManager {\r\n private webpages: any = {};\r\n private pendingWebPages: {\r\n [webPageId: string]: {\r\n [mid: string]: true\r\n }\r\n } = {};\r\n \r\n constructor() {\r\n rootScope.addMultipleEventsListeners({\r\n updateWebPage: (update) => {\r\n this.saveWebPage(update.webpage);\r\n }\r\n });\r\n }\r\n \r\n public saveWebPage(apiWebPage: any, mid?: number, mediaContext?: ReferenceContext) {\r\n if(apiWebPage.photo && apiWebPage.photo._ === 'photo') {\r\n //appPhotosManager.savePhoto(apiWebPage.photo, mediaContext);\r\n apiWebPage.photo = appPhotosManager.savePhoto(apiWebPage.photo, mediaContext);\r\n } else {\r\n delete apiWebPage.photo;\r\n }\r\n\r\n if(apiWebPage.document && apiWebPage.document._ === 'document') {\r\n apiWebPage.document = appDocsManager.saveDoc(apiWebPage.document, mediaContext); // warning 11.04.2020\r\n } else {\r\n if(apiWebPage.type === 'document') {\r\n delete apiWebPage.type;\r\n }\r\n\r\n delete apiWebPage.document;\r\n }\r\n \r\n const siteName = apiWebPage.site_name;\r\n let shortTitle = apiWebPage.title || apiWebPage.author || siteName || '';\r\n if(siteName && shortTitle === siteName) {\r\n delete apiWebPage.site_name;\r\n }\r\n\r\n shortTitle = limitSymbols(shortTitle, 80, 100);\r\n\r\n apiWebPage.rTitle = RichTextProcessor.wrapRichText(shortTitle, {noLinks: true, noLinebreaks: true});\r\n let contextHashtag = '';\r\n if(siteName === 'GitHub') {\r\n const matches = apiWebPage.url.match(/(https?:\\/\\/github\\.com\\/[^\\/]+\\/[^\\/]+)/);\r\n if(matches) {\r\n contextHashtag = matches[0] + '/issues/{1}';\r\n }\r\n }\r\n\r\n // delete apiWebPage.description\r\n const shortDescriptionText = limitSymbols(apiWebPage.description || '', 150, 180);\r\n apiWebPage.rDescription = RichTextProcessor.wrapRichText(shortDescriptionText, {\r\n contextSite: siteName || 'external',\r\n contextHashtag: contextHashtag\r\n });\r\n \r\n if(apiWebPage.type !== 'photo' &&\r\n apiWebPage.type !== 'video' &&\r\n apiWebPage.type !== 'gif' &&\r\n apiWebPage.type !== 'document' &&\r\n !apiWebPage.description &&\r\n apiWebPage.photo) {\r\n apiWebPage.type = 'photo';\r\n }\r\n \r\n if(mid) {\r\n if(this.pendingWebPages[apiWebPage.id] === undefined) {\r\n this.pendingWebPages[apiWebPage.id] = {};\r\n }\r\n\r\n this.pendingWebPages[apiWebPage.id][mid] = true;\r\n }\r\n \r\n if(this.webpages[apiWebPage.id] === undefined) {\r\n this.webpages[apiWebPage.id] = apiWebPage;\r\n } else {\r\n safeReplaceObject(this.webpages[apiWebPage.id], apiWebPage);\r\n }\r\n \r\n if(!mid && this.pendingWebPages[apiWebPage.id] !== undefined) {\r\n const msgs: number[] = [];\r\n for(const msgId in this.pendingWebPages[apiWebPage.id]) {\r\n msgs.push(+msgId);\r\n }\r\n\r\n rootScope.broadcast('webpage_updated', {\r\n id: apiWebPage.id,\r\n msgs\r\n });\r\n }\r\n\r\n return apiWebPage;\r\n }\r\n\r\n public deleteWebPageFromPending(webPage: any, mid: number) {\r\n const id = webPage.id;\r\n if(this.pendingWebPages[id] && this.pendingWebPages[id][mid]) {\r\n delete this.pendingWebPages[id][mid];\r\n\r\n if(!Object.keys(this.pendingWebPages[id]).length) {\r\n delete this.pendingWebPages[id];\r\n }\r\n }\r\n }\r\n\r\n public getWebPage(id: string) {\r\n return this.webpages[id];\r\n }\r\n}\r\n\r\nexport default new AppWebPagesManager();\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/**\r\n * Descend sorted storage\r\n */\r\n\r\ntype ItemType = number;\r\n\r\nexport enum SliceEnd {\r\n None = 0,\r\n Top = 1,\r\n Bottom = 2,\r\n Both = 4\r\n};\r\n\r\nexport interface Slice extends Array<ItemType> {\r\n slicedArray: SlicedArray;\r\n end: SliceEnd;\r\n\r\n isEnd: (side: SliceEnd) => boolean;\r\n setEnd: (side: SliceEnd) => void;\r\n}\r\n\r\nexport interface SliceConstructor {\r\n new(...items: ItemType[]): Slice;\r\n}\r\n\r\n// TODO: Clear empty arrays after deleting items\r\nexport default class SlicedArray {\r\n private slices: Slice[]/* = [[7,6,5],[4,3,2],[1,0,-1]] */;\r\n private sliceConstructor: SliceConstructor;\r\n \r\n constructor() {\r\n const self = this;\r\n this.sliceConstructor = class Slice extends Array<ItemType> implements Slice {\r\n slicedArray: SlicedArray;\r\n end: SliceEnd = SliceEnd.None;\r\n\r\n constructor(...items: ItemType[]) {\r\n super(...items);\r\n this.slicedArray = self;\r\n }\r\n\r\n isEnd(side: SliceEnd) {\r\n if(this.end & side) {\r\n return true;\r\n }\r\n\r\n if(side === SliceEnd.Top) {\r\n const slice = self.last;\r\n return slice.end & side ? this.includes(slice[slice.length - 1]) || !slice.length : false;\r\n } else if(side === SliceEnd.Bottom) {\r\n const slice = self.first;\r\n return slice.end & side ? this.includes(slice[0]) || !slice.length : false;\r\n }/* else if(side === SliceEnd.Both) {\r\n\r\n } */\r\n\r\n return false;\r\n }\r\n\r\n setEnd(side: SliceEnd) {\r\n this.end |= side;\r\n\r\n if(side !== SliceEnd.Both && this.end & SliceEnd.Top && this.end & SliceEnd.Bottom) {\r\n this.end |= SliceEnd.Both;\r\n }\r\n }\r\n }\r\n\r\n const first = this.constructSlice();\r\n first.setEnd(SliceEnd.Bottom);\r\n this.slices = [first];\r\n }\r\n\r\n public constructSlice(...items: ItemType[]) {\r\n //const slice = new Slice(this, ...items);\r\n const slice = new this.sliceConstructor(...items);\r\n return slice;\r\n \r\n // ! code below will slow execution in 15 times\r\n /* const self = this;\r\n const p: Slice = new Proxy(slice, {\r\n get: function(target, name: any) {\r\n if(name === 'constructor') {\r\n const p = new Proxy(Slice, {\r\n construct: (target, args) => {\r\n return self.constructSlice(...args);\r\n }\r\n });\r\n\r\n return p;\r\n }\r\n\r\n return target[name];\r\n }\r\n });\r\n\r\n return p; */\r\n\r\n /*\r\n var p = slicedArray.constructSlice();\r\n p.length = 100000;\r\n p.fill(255);\r\n\r\n var a = new Array(100000);\r\n a.fill(255);\r\n\r\n var b = 0;\r\n var perf = performance.now();\r\n for(var i = 0; i < p.length; ++i) {\r\n b += p[i];\r\n }\r\n\r\n console.log('perf 1', performance.now() - perf);\r\n\r\n b = 0;\r\n perf = performance.now();\r\n for(var i = 0; i < a.length; ++i) {\r\n b += a[i];\r\n }\r\n\r\n console.log('perf 2', performance.now() - perf);\r\n */\r\n }\r\n\r\n public insertSlice(slice: ItemType[]) {\r\n if(!slice.length) {\r\n return;\r\n }\r\n\r\n const first = this.slices[0];\r\n if(!first.length) {\r\n first.push(...slice);\r\n return;\r\n }\r\n\r\n const lowerBound = slice[slice.length - 1];\r\n const upperBound = slice[0];\r\n\r\n let foundSlice: Slice, lowerIndex = -1, upperIndex = -1;\r\n for(let i = 0; i < this.slices.length; ++i) {\r\n foundSlice = this.slices[i];\r\n lowerIndex = foundSlice.indexOf(lowerBound);\r\n upperIndex = foundSlice.indexOf(upperBound);\r\n \r\n if(upperIndex !== -1 && -1 !== lowerIndex) {\r\n break;\r\n } else if(upperIndex !== -1 || -1 !== lowerIndex) {\r\n break;\r\n }\r\n }\r\n\r\n if(upperIndex !== -1 && -1 !== lowerIndex) {\r\n\r\n } else if(upperIndex !== -1) { // ([1, 2, 3] | [1, 2, 3, 4, 5]) -> [1, 2, 3, 4, 5]\r\n const sliced = slice.slice(foundSlice.length - upperIndex);\r\n foundSlice.push(...sliced);\r\n } else if(lowerIndex !== -1) { // ([1, 2, 3] | [-1, 0, 1]) -> [-1, 0, 1, 2, 3]\r\n const sliced = slice.slice(0, slice.length - lowerIndex - 1);\r\n foundSlice.unshift(...sliced);\r\n } else {\r\n let insertIndex = 0;\r\n for(const length = this.slices.length; insertIndex < length; ++insertIndex) { // * maybe should iterate from the end, could be faster ?\r\n const s = this.slices[insertIndex];\r\n if(slice[0] > s[0]) {\r\n break;\r\n }\r\n }\r\n\r\n this.slices.splice(insertIndex, 0, this.constructSlice(...slice));\r\n }\r\n\r\n this.flatten();\r\n }\r\n\r\n private flatten() {\r\n if(this.slices.length < 2) {\r\n return;\r\n }\r\n\r\n for(let i = 0, length = this.slices.length; i < (length - 1); ++i) {\r\n const prevSlice = this.slices[i];\r\n const nextSlice = this.slices[i + 1];\r\n\r\n const upperIndex = prevSlice.indexOf(nextSlice[0]);\r\n if(upperIndex !== -1) {\r\n prevSlice.setEnd(nextSlice.end);\r\n this.slices.splice(i + 1, 1);\r\n length--;\r\n\r\n this.insertSlice(nextSlice);\r\n }\r\n }\r\n }\r\n\r\n // * \r\n \r\n get first() {\r\n return this.slices[0];\r\n }\r\n \r\n get last() {\r\n return this.slices[this.slices.length - 1];\r\n }\r\n\r\n get slice() {\r\n return this.first;\r\n }\r\n\r\n get length() {\r\n return this.slice.length;\r\n }\r\n\r\n public findSlice(item: ItemType) {\r\n for(let i = 0; i < this.slices.length; ++i) {\r\n const slice = this.slices[i];\r\n const index = slice.indexOf(item);\r\n if(index !== -1) {\r\n return {slice, index};\r\n }\r\n }\r\n \r\n return undefined;\r\n }\r\n\r\n public findSliceOffset(maxId: number) {\r\n let slice: Slice;\r\n for(let i = 0; i < this.slices.length; ++i) {\r\n let offset = 0;\r\n slice = this.slices[i];\r\n if(slice.length < 2) {\r\n continue;\r\n }\r\n \r\n for(; offset < slice.length; offset++) {\r\n if(maxId >= slice[offset]) {\r\n /* if(!offset) { // because can't find 3 in [[5,4], [2,1]]\r\n return undefined;\r\n } */\r\n\r\n return {\r\n slice, \r\n offset: maxId === slice[offset] ? offset : offset - 1\r\n };\r\n }\r\n }\r\n }\r\n\r\n if(slice && slice.isEnd(SliceEnd.Top)) {\r\n return {\r\n slice,\r\n offset: slice.length\r\n };\r\n }\r\n\r\n return undefined;\r\n }\r\n\r\n // * https://core.telegram.org/api/offsets\r\n public sliceMe(offsetId: number, add_offset: number, limit: number) {\r\n let slice = this.slice;\r\n let offset = 0;\r\n let sliceOffset = 0;\r\n\r\n if(offsetId) {\r\n const pos = this.findSliceOffset(offsetId);\r\n if(!pos) {\r\n return undefined;\r\n }\r\n\r\n slice = pos.slice;\r\n offset = sliceOffset = pos.offset;\r\n\r\n if(slice.includes(offsetId)) {\r\n sliceOffset += 1;\r\n }\r\n\r\n /* if(slice.includes(offsetId) && add_offset < 0) {\r\n add_offset += 1;\r\n } */\r\n }\r\n\r\n let sliceStart = Math.max(sliceOffset + add_offset, 0);\r\n let sliceEnd = sliceOffset + add_offset + limit;\r\n //const fixHalfBackLimit = add_offset && !(limit / add_offset % 2) && (sliceEnd % 2) ? 1 : 0;\r\n //sliceEnd += fixHalfBackLimit;\r\n\r\n const sliced = slice.slice(sliceStart, sliceEnd) as Slice;\r\n\r\n const topWasMeantToLoad = add_offset < 0 ? limit + add_offset : limit;\r\n const bottomWasMeantToLoad = Math.abs(add_offset);\r\n\r\n const topFulfilled = (slice.length - sliceOffset) >= topWasMeantToLoad || (slice.isEnd(SliceEnd.Top) ? (sliced.setEnd(SliceEnd.Top), true) : false);\r\n const bottomFulfilled = (sliceOffset - bottomWasMeantToLoad) >= 0 || (slice.isEnd(SliceEnd.Bottom) ? (sliced.setEnd(SliceEnd.Bottom), true) : false);\r\n\r\n //console.log('sliceMe', topFulfilled, bottomFulfilled);\r\n\r\n return {\r\n slice: sliced, \r\n offsetIdOffset: offset,\r\n fulfilled: SliceEnd.None | (topFulfilled && bottomFulfilled ? SliceEnd.Both : ((topFulfilled ? SliceEnd.Top : SliceEnd.None) | (bottomFulfilled ? SliceEnd.Bottom : SliceEnd.None)))\r\n };\r\n }\r\n\r\n public unshift(...items: ItemType[]) {\r\n this.first.unshift(...items);\r\n }\r\n\r\n public push(...items: ItemType[]) {\r\n this.last.push(...items);\r\n }\r\n\r\n public delete(item: ItemType) {\r\n const found = this.findSlice(item);\r\n if(found) {\r\n found.slice.splice(found.index, 1);\r\n }\r\n }\r\n}\r\n\r\n(window as any).slicedArray = new SlicedArray();\r\n","module.exports = function() {\n return new Worker(__webpack_public_path__ + \"bdc9916fcf69ae974927.worker.js\");\n};","module.exports = function() {\n return new Worker(__webpack_public_path__ + \"24db672b71bab921b1b3.worker.js\");\n};"],"sourceRoot":""}