From be4205e5cc65a5b9ffe890b52fe2a712475dc4f8 Mon Sep 17 00:00:00 2001 From: Eduard Kuzmenko Date: Sat, 8 Feb 2020 18:58:22 +0700 Subject: [PATCH] virtual chatlist scroll (care) --- .DS_Store | Bin 10244 -> 10244 bytes src/components/misc.ts | 127 ++++++++++++++--- src/components/pageIm.ts | 71 +--------- src/components/pageSignIn.ts | 2 +- src/lib/appManagers/appDialogsManager.ts | 57 ++++++-- src/lib/appManagers/appImManager.ts | 60 +++++--- src/lib/appManagers/appMessagesIDsManager.ts | 2 +- src/lib/appManagers/appMessagesManager.ts | 32 ++--- src/lib/appManagers/appSidebarLeft.ts | 142 ++++++++++++++----- src/lib/appManagers/appSidebarRight.ts | 43 +++--- src/scss/materialize.scss | 41 ------ src/scss/partials/_leftSidebar.scss | 7 +- 12 files changed, 348 insertions(+), 236 deletions(-) delete mode 100644 src/scss/materialize.scss diff --git a/.DS_Store b/.DS_Store index 9dd56de43c2e1cab938baee7b39a86f5e45eb0b8..102eb72f6e1a93561d5af998dff2b9959512d3a8 100644 GIT binary patch delta 696 zcmc&xJ4gdT5S=??L{QjeqnC@ISNJI+=UqILfTfjju)Y1Kp~GK_PLZ#!NcFjmn~3bt0DN!AweqUgFL)YxiiemW%>c zEoWkowx~>-RN=f$E@jAz;E~VSXGZ6M*?`7)H_DM?#$`r>`|zafy*DCb=QCQQ*U&F? zwU*B@8o6kPfU@6}xn89z&$cnSRw*s6RTf!UFvi*K^_yFwpWDieDy`^tDl!&mojJF8 zf@h_0Y71OiUARyZ4ePi);|0TxALM=PCuhy%10Ivp#x+K4KVuyJxRl^0s!}O(SYoH; z=79V-9C%TEsM~%#ns5gVI~%7nt%BZEK5kgL4Chj^HEeS}V&QyO&G?i5*!{o%_yYQT BpgRBn delta 395 zcmZn(XbIS$Eg(AMKNv8801Ja2LpnnyL&@YoVPQoLBpEK43{W#tD=8#1)h| z8G;yG85|j07<_@W9z!leif2xKa#Buy5>S@_0|Vpd$&L~#Y)t3DhGa`DoLnH{Jvm%b zl*wrO { // @ts-ignore - scrollHeight = container[scrollType]; + scrollSize = container[scrollType]; let rect = container.getBoundingClientRect(); // @ts-ignore - height = rect[type]; + size = rect[type]; - if(!height || height == scrollHeight) { - thumbHeight = 0; + if(!size || size == scrollSize) { + thumbSize = 0; // @ts-ignore - thumb.style[type] = thumbHeight + 'px'; + thumb.style[type] = thumbSize + 'px'; return; } //if(!height) return; - let divider = scrollHeight / height / 0.5; - thumbHeight = height / divider; + let divider = scrollSize / size / 0.5; + thumbSize = size / divider; - if(thumbHeight < 20) thumbHeight = 20; + if(thumbSize < 20) thumbSize = 20; // @ts-ignore - thumb.style[type] = thumbHeight + 'px'; + thumb.style[type] = thumbSize + 'px'; // @ts-ignore //console.log('onresize', thumb.style[type], thumbHeight, height); }; - let scrollHeight = -1; - let height = 0; - let thumbHeight = 0; + let scrollSize = -1; + let size = 0; + let thumbSize = 0; window.addEventListener('resize', resize); //container.addEventListener('DOMNodeInserted', resize); - - container.addEventListener('scroll', (e) => { + + let hiddenElements: { + up: Element[], + down: Element[] + } = { + up: [], + down: [] + }; + + let paddings = {up: 0, down: 0}; + + let paddingTopDiv = document.createElement('div'); + paddingTopDiv.classList.add('scroll-padding'); + let paddingBottomDiv = document.createElement('div'); + paddingBottomDiv.classList.add('scroll-padding'); + + let onScroll = (e: Event) => { + // @ts-ignore + //let st = container[scrollSide]; + // @ts-ignore - if(container[scrollType] != scrollHeight || thumbHeight == 0) { + if(container[scrollType] != scrollSize || thumbSize == 0) { resize(); } + + let splitUp = container.querySelector('ul'); + let children = Array.from(splitUp.children) as HTMLElement[]; + let firstVisible = -1, lastVisible = -1; + let length = children.length; + for(let i = 0; i < length; ++i) { + let child = children[i]; + if(isElementInViewport(child)) { + if(firstVisible < 0) firstVisible = i; + lastVisible = i; + } + } + + if(firstVisible > 0) { + let sliced = children.slice(0, firstVisible); + + for(let child of sliced) { + paddings.up += child.scrollHeight; + hiddenElements.up.push(child); + child.parentElement.removeChild(child); + } + + //console.log('sliced up', sliced.length); + + //sliced.forEach(child => child.style.display = 'none'); + paddingTopDiv.style.height = paddings.up + 'px'; + //console.log('onscroll need to add padding: ', paddings.up); + } else if(hiddenElements.up.length) { + while(isElementInViewport(paddingTopDiv) && paddings.up) { + let child = hiddenElements.up.pop(); + + splitUp.prepend(child); + + paddings.up -= child.scrollHeight; + paddingTopDiv.style.height = paddings.up + 'px'; + } + } + + if(lastVisible < (length - 1)) { + let sliced = children.slice(lastVisible + 1).reverse(); + + for(let child of sliced) { + paddings.down += child.scrollHeight; + hiddenElements.down.unshift(child); + child.parentElement.removeChild(child); + } + + //console.log('onscroll sliced down', sliced.length); + + //sliced.forEach(child => child.style.display = 'none'); + paddingBottomDiv.style.height = paddings.down + 'px'; + //console.log('onscroll need to add padding: ', paddings.up); + } else if(hiddenElements.down.length) { + while(isElementInViewport(paddingBottomDiv) && paddings.down) { + let child = hiddenElements.down.shift(); + + splitUp.append(child); + + paddings.down -= child.scrollHeight; + paddingBottomDiv.style.height = paddings.down + 'px'; + } + } + + //console.log('onscroll', container, firstVisible, lastVisible, hiddenElements); // @ts-ignore - let value = container[scrollSide] / (scrollHeight - height) * 100; - let maxValue = 100 - (thumbHeight / height * 100); + let value = container[scrollSide] / (scrollSize - size) * 100; + let maxValue = 100 - (thumbSize / size * 100); //console.log('onscroll', container.scrollHeight, thumbHeight, height, value, maxValue); // @ts-ignore thumb.style[side] = (value >= maxValue ? maxValue : value) + '%'; - }); + + //lastScrollPos = st; + }; + + let lastScrollPos = 0; + container.addEventListener('scroll', onScroll); + container.append(paddingTopDiv); Array.from(el.children).forEach(c => container.append(c)); + container.append(paddingBottomDiv); el.append(container);//container.append(el); container.parentElement.append(thumb); resize(); - return container; + return {container, hiddenElements, onScroll}; } export function wrapPhoto(this: AppImManager, photo: any, message: any, container: HTMLDivElement) { diff --git a/src/components/pageIm.ts b/src/components/pageIm.ts index 080fdc1c..7cc1c39a 100644 --- a/src/components/pageIm.ts +++ b/src/components/pageIm.ts @@ -13,6 +13,7 @@ import appStickersManager, { MTStickerSet } from "../lib/appManagers/appStickers import { AppImManager } from "../lib/appManagers/appImManager"; import { AppMessagesManager } from "../lib/appManagers/appMessagesManager"; import appSidebarRight from "../lib/appManagers/appSidebarRight"; +import appSidebarLeft from "../lib/appManagers/appSidebarLeft"; const EMOTICONSSTICKERGROUP = 'emoticons-dropdown'; @@ -175,7 +176,7 @@ let initEmoticonsDropdown = (pageEl: HTMLDivElement, let prevCategoryIndex = 1; let menu = contentEmojiDiv.nextElementSibling as HTMLUListElement; - let emojiScroll = scrollable(contentEmojiDiv); + let emojiScroll = scrollable(contentEmojiDiv).container; emojiScroll.addEventListener('scroll', (e) => { prevCategoryIndex = emoticonsContentOnScroll(menu, heights, prevCategoryIndex, emojiScroll); }); @@ -341,7 +342,7 @@ let initEmoticonsDropdown = (pageEl: HTMLDivElement, }); let prevCategoryIndex = 0; - let stickersScroll = scrollable(contentStickersDiv); + let stickersScroll = scrollable(contentStickersDiv).container; stickersScroll.addEventListener('scroll', (e) => { lazyLoadQueue.check(); lottieLoader.checkAnimations(); @@ -362,72 +363,15 @@ export default () => import('../lib/services').then(services => { let {appImManager, appMessagesManager, appDialogsManager, apiUpdatesManager, appUsersManager} = services; //export default () => { - let chatsContainer = document.getElementById('chats-container') as HTMLDivElement; - let d = document.createElement('div'); - d.classList.add('preloader'); - putPreloader(d); - chatsContainer.append(d); let pageEl = document.body.getElementsByClassName('page-chats')[0] as HTMLDivElement; pageEl.style.display = ''; - const loadCount = Math.round(document.body.scrollHeight / 70 * 1.5); - - let chatsScroll = scrollable(chatsContainer as HTMLDivElement); - let sidebarScroll = scrollable(document.body.querySelector('.profile-container')); - let chatScroll = scrollable(document.getElementById('bubbles') as HTMLDivElement); + let sidebarScroll = scrollable(document.body.querySelector('.profile-container')).container; + let chatScroll = scrollable(document.getElementById('bubbles') as HTMLDivElement).container; apiUpdatesManager.attach(); - let offsetIndex = 0; - let loadDialogsPromise: Promise; - let loadDialogs = async() => { - if(loadDialogsPromise) return loadDialogsPromise; - - chatsContainer.append(d); - - //let offset = appMessagesManager.generateDialogIndex();/* appMessagesManager.dialogsNum */; - - try { - loadDialogsPromise = appMessagesManager.getConversations('', offsetIndex, loadCount); - - let result = await loadDialogsPromise; - - console.log('loaded ' + loadCount + ' dialogs by offset:', offsetIndex, result); - - if(result && result.dialogs && result.dialogs.length) { - offsetIndex = result.dialogs[result.dialogs.length - 1].index; - result.dialogs.forEach((dialog: any) => { - appDialogsManager.addDialog(dialog); - }); - } - } catch(err) { - console.error(err); - } - - d.remove(); - loadDialogsPromise = undefined; - }; - - let onScroll = () => { - if(!loadDialogsPromise) { - let d = Array.from(appDialogsManager.chatList.childNodes).slice(-5); - for(let node of d) { - if(isElementInViewport(node)) { - loadDialogs(); - break; - } - } - - //console.log('last 5 dialogs:', d); - } - }; - - chatsScroll.addEventListener('scroll', onScroll); - window.addEventListener('resize', () => { - setTimeout(onScroll, 0); - }); - // @ts-ignore document.addEventListener('user_update', (e: CustomEvent) => { let userID = e.detail; @@ -797,9 +741,8 @@ export default () => import('../lib/services').then(services => { }); }); - - loadDialogs().then(result => { - onScroll(); + appSidebarLeft.loadDialogs().then(result => { + appSidebarLeft.onChatsScroll(); appImManager.setScroll(chatScroll); appSidebarRight.setScroll(sidebarScroll); }); diff --git a/src/components/pageSignIn.ts b/src/components/pageSignIn.ts index 7826e856..acdffe88 100644 --- a/src/components/pageSignIn.ts +++ b/src/components/pageSignIn.ts @@ -51,7 +51,7 @@ export default () => { wrapper.appendChild(list); //let wrapperScroll = OverlayScrollbars(wrapper, (window as any).scrollbarOptions); - let wrapperScroll = scrollable(wrapper); + scrollable(wrapper); let initedSelect = false; diff --git a/src/lib/appManagers/appDialogsManager.ts b/src/lib/appManagers/appDialogsManager.ts index 9a811dea..2dbfcab4 100644 --- a/src/lib/appManagers/appDialogsManager.ts +++ b/src/lib/appManagers/appDialogsManager.ts @@ -1,6 +1,6 @@ import apiManager from "../mtproto/apiManager"; import apiFileManager from '../mtproto/apiFileManager'; -import { $rootScope, findUpTag } from "../utils"; +import { $rootScope, findUpTag, isElementInViewport } from "../utils"; import appImManager from "./appImManager"; import appPeersManager from './appPeersManager'; import appMessagesManager from "./appMessagesManager"; @@ -20,11 +20,9 @@ type DialogDom = { }; export class AppDialogsManager { - public pinnedChatList = document.getElementById('dialogs-pinned') as HTMLUListElement; public chatList = document.getElementById('dialogs') as HTMLUListElement; + public chatsHidden: any; - - public myID = 0; public doms: {[x: number]: any} = {}; @@ -40,7 +38,6 @@ export class AppDialogsManager { //let chatClosedDiv = document.getElementById('chat-closed'); - this.setListClickListener(this.pinnedChatList); this.setListClickListener(this.chatList); } @@ -131,20 +128,54 @@ export class AppDialogsManager { } public sortDom() { - /* let sorted = */appMessagesManager.dialogsStorage.dialogs + console.log('sortDom'); + //return; + + let dialogs = appMessagesManager.dialogsStorage.dialogs; + + let inUpper: HTMLLIElement[] = []; + let inBottom: HTMLLIElement[] = []; + + let lastPinnedIndex = -1; + for(let i = 0; i < dialogs.length; ++i) { + let dialog = dialogs[i]; + if(!dialog.pFlags.pinned) break; + lastPinnedIndex = i; + } + + let sorted = dialogs .filter((d: any) => !d.pFlags.pinned) .sort((a: any, b: any) => { let timeA = appMessagesManager.getMessage(a.top_message).date; let timeB = appMessagesManager.getMessage(b.top_message).date; return timeB - timeA; - }) - .forEach((d: any) => { + }); + + if(lastPinnedIndex != -1) { + sorted = dialogs.slice(0, lastPinnedIndex + 1).concat(sorted); + } + + let inViewportIndex = -1; + sorted.forEach((d: any) => { let dom = this.getDialogDom(d.peerID); if(!dom) return; - this.chatList.append(dom.listEl); + if(this.chatsHidden.up.find((d: HTMLLIElement) => d === dom.listEl)) { + inUpper.push(dom.listEl); + } else if(isElementInViewport(dom.listEl)) { + this.chatList.insertBefore(dom.listEl, this.chatList.children[++inViewportIndex]); + } else if(this.chatsHidden.down.find((d: HTMLLIElement) => d === dom.listEl)) { + inBottom.push(dom.listEl); + } else { + console.warn('found no dom!', dom); + } + + //this.chatList.append(dom.listEl); }); + + this.chatsHidden.up = inUpper; + this.chatsHidden.down = inBottom; } public setLastMessage(dialog: any, lastMessage?: any, dom?: DialogDom) { @@ -405,7 +436,13 @@ export class AppDialogsManager { }; if(!container) { - (dialog.pFlags.pinned ? this.pinnedChatList : this.chatList).append(li); + this.chatList.append(li); + //this.appendTo.push(li); + + if(dialog.pFlags.pinned) { + li.classList.add('dialog-pinned'); + } + this.doms[dialog.peerID] = dom; this.setLastMessage(dialog); } else { diff --git a/src/lib/appManagers/appImManager.ts b/src/lib/appManagers/appImManager.ts index 9bfcc5d6..7ab56f8c 100644 --- a/src/lib/appManagers/appImManager.ts +++ b/src/lib/appManagers/appImManager.ts @@ -132,6 +132,7 @@ export class AppImManager { private topbar: HTMLDivElement = null; private chatInput: HTMLDivElement = null; + scrolledAll: boolean; constructor() { this.log = logger('IM'); @@ -380,30 +381,39 @@ export class AppImManager { // load more history if(!this.getHistoryPromise && !this.getHistoryTimeout /* && false */) { - let history = Object.keys(this.bubbles).map(id => +id).sort(); - /* let history = appMessagesManager.historiesStorage[this.peerID].history; - let length = history.length; */ this.getHistoryTimeout = setTimeout(() => { // must be + let history = Object.keys(this.bubbles).map(id => +id).sort(); + + /* let history = appMessagesManager.historiesStorage[this.peerID].history; + let length = history.length; */ + + // filter negative ids + for(let i = 0; i < history.length; ++i) { + if(history[i] <= 0) history.splice(i, 1); + else break; + } + this.getHistoryTimeout = 0; let willLoad = false; - for(let i = 0; i < 10; ++i) { - let msgID = history[i]; - if(!(msgID in this.bubbles) || msgID <= 0) continue; - - let bubble = this.bubbles[msgID]; - - if(isElementInViewport(bubble)) { - willLoad = true; - - this.log('Will load more (up) history by id:', history[0], 'maxID:', history[history.length - 1], history, bubble); - /* false && */!testScroll && this.getHistory(history[0], true).then(() => { // uncomment - this.onScroll(); - }).catch(err => { - this.log.warn('Could not load more history, err:', err); - }); + if(!this.scrolledAll) { + for(let i = 0; i < 10; ++i) { + let msgID = history[i]; + + let bubble = this.bubbles[msgID]; + + if(isElementInViewport(bubble)) { + willLoad = true; - break; + this.log('Will load more (up) history by id:', history[0], 'maxID:', history[history.length - 1], history, bubble); + /* false && */!testScroll && this.getHistory(history[0], true).then(() => { // uncomment + this.onScroll(); + }).catch(err => { + this.log.warn('Could not load more history, err:', err); + }); + + break; + } } } @@ -413,8 +423,6 @@ export class AppImManager { if(!willLoad && history.indexOf(/* this.lastDialog */dialog.top_message) === -1) { let lastMsgIDs = history.slice(-10); for(let msgID of lastMsgIDs) { - if(!(msgID in this.bubbles) || msgID <= 0) continue; - let bubble = this.bubbles[msgID]; if(isElementInViewport(bubble)) { @@ -520,6 +528,7 @@ export class AppImManager { public cleanup() { this.peerID = $rootScope.selectedPeerID = 0; + this.scrolledAll = false; if(this.lastContainerDiv) this.lastContainerDiv.remove(); if(this.firstContainerDiv) this.firstContainerDiv.remove(); @@ -645,7 +654,7 @@ export class AppImManager { appSidebarRight.fillProfileElements() ]).catch(err => { - this.log.error(err); + this.log.error('setPeer promises error:', err); }); } @@ -1189,7 +1198,12 @@ export class AppImManager { if(!result || !result.history) { console.timeEnd('render history total'); return true; - } + } + + // commented bot getProfile in getHistory! + if(!result.history/* .filter((id: number) => id > 0) */.length && !isBackLimit) { + this.scrolledAll = true; + } //this.chatInner.innerHTML = ''; diff --git a/src/lib/appManagers/appMessagesIDsManager.ts b/src/lib/appManagers/appMessagesIDsManager.ts index b01cec0c..f8f59f23 100644 --- a/src/lib/appManagers/appMessagesIDsManager.ts +++ b/src/lib/appManagers/appMessagesIDsManager.ts @@ -30,7 +30,7 @@ export class AppMessagesIDsManager { } public getMessageLocalID(fullMsgID: number) { - if (!fullMsgID) { + if(!fullMsgID) { return 0; } return fullMsgID % this.fullMsgIDModulus; diff --git a/src/lib/appManagers/appMessagesManager.ts b/src/lib/appManagers/appMessagesManager.ts index ba341b6c..dd1c04f8 100644 --- a/src/lib/appManagers/appMessagesManager.ts +++ b/src/lib/appManagers/appMessagesManager.ts @@ -2418,7 +2418,7 @@ export class AppMessagesManager { // need be commented for read out messages //if(newUnreadCount != 0 || !isOut) { // fix 16.11.2019 (maybe not) - console.warn(dT(), 'cnt', peerID, newUnreadCount); + console.warn(dT(), 'cnt', peerID, newUnreadCount, isOut, foundDialog, update, foundAffected); $rootScope.$broadcast('dialog_unread', {peerID: peerID, count: newUnreadCount}); //} @@ -3068,7 +3068,7 @@ export class AppMessagesManager { public requestHistory(peerID: number, maxID: number, limit: number, offset = 0) { var isChannel = AppPeersManager.isChannel(peerID); - console.trace('requestHistory', peerID, maxID, limit, offset); + //console.trace('requestHistory', peerID, maxID, limit, offset); return MTProto.apiManager.invokeApi('messages.getHistory', { peer: AppPeersManager.getInputPeerByID(peerID), @@ -3079,16 +3079,7 @@ export class AppMessagesManager { max_id: 0, min_id: 0, hash: 0 - }/* { - peer: AppPeersManager.getInputPeerByID(peerID), - offset_id: offset, - offset_date: 0, - add_offset: offset || 0, - limit: limit || 0, - max_id: maxID, - min_id: 0, - hash: 0 - } */, { + }, { timeout: 300, noErrorBox: true }).then((historyResult: any) => { @@ -3101,22 +3092,19 @@ export class AppMessagesManager { } var length = historyResult.messages.length; - if(length && - historyResult.messages[length - 1].deleted) { + if(length && historyResult.messages[length - 1].deleted) { historyResult.messages.splice(length - 1, 1); length--; historyResult.count--; } - if( - peerID < 0 || - !appUsersManager.isBot(peerID) || - (length == limit && limit < historyResult.count) - ) { + // don't need the intro now + /* if(peerID < 0 || !appUsersManager.isBot(peerID) || (length == limit && limit < historyResult.count)) { return historyResult; - } + } */ + return historyResult; - return appProfileManager.getProfile(peerID).then((userFull: any) => { + /* return appProfileManager.getProfile(peerID).then((userFull: any) => { var description = userFull.bot_info && userFull.bot_info.description; if(description) { var messageID = this.tempID--; @@ -3142,7 +3130,7 @@ export class AppMessagesManager { } return historyResult; - }); + }); */ }, (error) => { switch (error.type) { case 'CHANNEL_PRIVATE': diff --git a/src/lib/appManagers/appSidebarLeft.ts b/src/lib/appManagers/appSidebarLeft.ts index 543d3372..447b868d 100644 --- a/src/lib/appManagers/appSidebarLeft.ts +++ b/src/lib/appManagers/appSidebarLeft.ts @@ -1,10 +1,9 @@ import { logger } from "../polyfill"; -import { scrollable } from "../../components/misc"; +import { scrollable, putPreloader } from "../../components/misc"; import appMessagesManager from "./appMessagesManager"; import appDialogsManager from "./appDialogsManager"; -import { isElementInViewport, $rootScope } from "../utils"; +import { isElementInViewport } from "../utils"; import appMessagesIDsManager from "./appMessagesIDsManager"; -import apiManager from '../mtproto/apiManager'; import appImManager from "./appImManager"; class AppSidebarLeft { @@ -12,13 +11,22 @@ class AppSidebarLeft { private searchInput = document.getElementById('global-search') as HTMLInputElement; private toolsBtn = this.sidebarEl.querySelector('.sidebar-tools-button') as HTMLButtonElement; private searchContainer = this.sidebarEl.querySelector('#search-container') as HTMLDivElement; - + private menuEl = this.toolsBtn.querySelector('.btn-menu'); private savedBtn = this.menuEl.querySelector('.menu-saved'); private listsContainer: HTMLDivElement = null; private searchMessagesList: HTMLUListElement = null; + private chatsContainer = document.getElementById('chats-container') as HTMLDivElement; + private chatsOffsetIndex = 0; + private chatsScroll: HTMLDivElement; + private chatsHidden: any; + private chatsPreloader: HTMLDivElement; + private chatsLoadCount = 0; + private loadDialogsPromise: Promise; + private hiddenScroll: any; + private log = logger('SL'); private peerID = 0; @@ -29,31 +37,43 @@ class AppSidebarLeft { private searchPromise: Promise = null; private searchTimeout: number = 0; - - private query = ''; - public myID = 0; + private query = ''; constructor() { - this.listsContainer = scrollable(this.searchContainer); - this.searchMessagesList = document.createElement('ul'); - - apiManager.getUserID().then((id) => { - this.myID = id; - }); - - $rootScope.$on('user_auth', (e: CustomEvent) => { - let userAuth = e.detail; - this.myID = userAuth ? userAuth.id : 0; - }); + this.chatsPreloader = document.createElement('div'); + this.chatsPreloader.classList.add('preloader'); + putPreloader(this.chatsPreloader); + this.chatsContainer.append(this.chatsPreloader); + + this.chatsLoadCount = Math.round(document.body.scrollHeight / 70 * 1.5); + + let {container: chatsScroll, hiddenElements: chatsHidden, onScroll: hiddenScroll} = scrollable(this.chatsContainer as HTMLDivElement); + this.chatsScroll = chatsScroll; + this.chatsHidden = chatsHidden; + this.hiddenScroll = hiddenScroll; + appDialogsManager.chatsHidden = this.chatsHidden; + + chatsScroll.addEventListener('scroll', this.onChatsScroll.bind(this)); + + this.listsContainer = scrollable(this.searchContainer).container; + this.searchMessagesList = document.createElement('ul'); + this.savedBtn.addEventListener('click', () => { - appImManager.setPeer(this.myID); + appImManager.setPeer(appImManager.myID); }); + /* this.listsContainer.insertBefore(this.searchMessagesList, this.listsContainer.lastElementChild); + for(let i = 0; i < 25; ++i) { + let li = document.createElement('li'); + li.innerHTML = `

Влад14:41

это важно

`; + this.searchMessagesList.append(li); + } */ + this.listsContainer.addEventListener('scroll', this.onSidebarScroll.bind(this)); - this.searchContainer.append(this.listsContainer); + //this.searchContainer.append(this.listsContainer); appDialogsManager.setListClickListener(this.searchMessagesList); @@ -85,13 +105,13 @@ class AppSidebarLeft { this.log('input', value); if(this.listsContainer.contains(this.searchMessagesList)) { - this.listsContainer.removeChild(this.searchMessagesList) + this.listsContainer.removeChild(this.searchMessagesList); } if(!value.trim()) { return; } - + this.query = value; this.minMsgID = 0; this.loadedCount = 0; @@ -113,18 +133,70 @@ class AppSidebarLeft { this.peerID = 0; } }); - + window.addEventListener('resize', () => { - setTimeout(() => this.onSidebarScroll(), 0); + this.chatsLoadCount = Math.round(document.body.scrollHeight / 70 * 1.5); + + setTimeout(() => { + this.onSidebarScroll(); + this.onChatsScroll(); + }, 0); }); } + public async loadDialogs() { + if(this.loadDialogsPromise/* || 1 == 1 */) return this.loadDialogsPromise; + + this.chatsContainer.append(this.chatsPreloader); + + //let offset = appMessagesManager.generateDialogIndex();/* appMessagesManager.dialogsNum */; + + try { + this.loadDialogsPromise = appMessagesManager.getConversations('', this.chatsOffsetIndex, this.chatsLoadCount); + + let result = await this.loadDialogsPromise; + + if(result && result.dialogs && result.dialogs.length) { + this.chatsOffsetIndex = result.dialogs[result.dialogs.length - 1].index; + result.dialogs.forEach((dialog: any) => { + appDialogsManager.addDialog(dialog); + }); + } + + this.log('loaded ' + this.chatsLoadCount + ' dialogs by offset:', this.chatsOffsetIndex, result, this.chatsHidden); + this.hiddenScroll(); + } catch(err) { + this.log.error(err); + } + + this.chatsPreloader.remove(); + this.loadDialogsPromise = undefined; + } + + public onChatsScroll() { + if(this.chatsHidden.down.length > 0/* || 1 == 1 */) return; + + if(!this.loadDialogsPromise) { + let d = Array.from(appDialogsManager.chatList.childNodes).slice(-5); + for(let node of d) { + if(isElementInViewport(node)) { + this.loadDialogs(); + break; + } + } + + //console.log('last 5 dialogs:', d); + } + } + public onSidebarScroll() { + if(!this.query.trim()) return; + let elements = Array.from(this.searchMessagesList.childNodes).slice(-5); for(let li of elements) { if(isElementInViewport(li)) { this.log('Will load more search'); - + if(!this.searchTimeout) { this.searchTimeout = setTimeout(() => { this.searchMore(); @@ -144,21 +216,23 @@ class AppSidebarLeft { this.searchInput.focus(); } - + private searchMore() { if(this.searchPromise) return this.searchPromise; - + let query = this.query; - + + if(!query.trim()) return; + if(this.loadedCount != 0 && this.loadedCount >= this.foundCount) { return Promise.resolve(); } let maxID = appMessagesIDsManager.getMessageIDInfo(this.minMsgID)[0]; - + return this.searchPromise = appMessagesManager.getSearch(this.peerID, query, null, maxID, 20, this.offsetRate).then(res => { this.searchPromise = null; - + if(this.searchInput.value != query) { return; } @@ -166,7 +240,7 @@ class AppSidebarLeft { this.log('input search result:', this.peerID, query, null, maxID, 20, res); let {count, history, next_rate} = res; - + if(history[0] == this.minMsgID) { history.shift(); } @@ -177,7 +251,7 @@ class AppSidebarLeft { if(!originalDialog) { this.log('no original dialog by message:', message); - + originalDialog = { peerID: message.peerID, pFlags: {}, @@ -188,11 +262,11 @@ class AppSidebarLeft { let {dialog, dom} = appDialogsManager.addDialog(originalDialog, this.searchMessagesList, false); appDialogsManager.setLastMessage(dialog, message, dom); }); - + this.minMsgID = history[history.length - 1]; this.offsetRate = next_rate; this.loadedCount += history.length; - + if(!this.foundCount) { this.foundCount = count; } diff --git a/src/lib/appManagers/appSidebarRight.ts b/src/lib/appManagers/appSidebarRight.ts index 70f567b6..ba7ec188 100644 --- a/src/lib/appManagers/appSidebarRight.ts +++ b/src/lib/appManagers/appSidebarRight.ts @@ -65,6 +65,8 @@ class AppSidebarRight { private log = logger('SR'); + private peerID = 0; + constructor() { let container = this.profileContentEl.querySelector('.profile-tabs-content') as HTMLDivElement; let tabs = this.profileContentEl.querySelector('.profile-tabs') as HTMLUListElement; @@ -143,7 +145,7 @@ class AppSidebarRight { } public loadSidebarMedia(single = false) { - let peerID = $rootScope.selectedPeerID; + let peerID = this.peerID; let typesToLoad = single ? [this.sharedMediaType] : this.sharedMediaTypes; @@ -164,14 +166,14 @@ class AppSidebarRight { ? appMessagesManager.historiesStorage[peerID].history.slice() : []; maxID = !maxID && ids.length ? ids[ids.length - 1] : maxID; - this.log('search house of glass pre', type, ids, maxID); + //this.log('search house of glass pre', type, ids, maxID); return this.loadSidebarMediaPromises[type] = appMessagesManager.getSearch(peerID, '', {_: type}, maxID, 50) .then(value => { ids = ids.concat(value.history); history.push(...ids); - this.log('search house of glass', type, value, ids, this.cleared); + //this.log('search house of glass', type, value, ids, this.cleared); if($rootScope.selectedPeerID != peerID) { this.log.warn('peer changed'); @@ -188,11 +190,11 @@ class AppSidebarRight { let message = appMessagesManager.getMessage(mid); if(!message.media) return; - /* 'inputMessagesFilterContacts', - 'inputMessagesFilterPhotoVideo', - 'inputMessagesFilterDocument', - 'inputMessagesFilterUrl', - 'inputMessagesFilterVoice'*/ + /*'inputMessagesFilterContacts', + 'inputMessagesFilterPhotoVideo', + 'inputMessagesFilterDocument', + 'inputMessagesFilterUrl', + 'inputMessagesFilterVoice'*/ switch(type) { case 'inputMessagesFilterPhotoVideo': { /* if(!(message.media.photo || message.media.document || message.media.webpage.document)) { @@ -281,7 +283,8 @@ class AppSidebarRight { } public fillProfileElements() { - let peerID = $rootScope.selectedPeerID; + let peerID = this.peerID = $rootScope.selectedPeerID; + this.loadSidebarMediaPromises = {}; this.profileContentEl.parentElement.scrollTop = 0; this.profileElements.bio.style.display = 'none'; @@ -311,19 +314,19 @@ class AppSidebarRight { }; // username - let username = appPeersManager.getPeerUsername($rootScope.selectedPeerID); + let username = appPeersManager.getPeerUsername(peerID); if(username) { - setText(appPeersManager.getPeerUsername($rootScope.selectedPeerID), this.profileElements.username); + setText(appPeersManager.getPeerUsername(peerID), this.profileElements.username); } - if($rootScope.selectedPeerID > 0) { - let user = appUsersManager.getUser($rootScope.selectedPeerID); + if(peerID > 0) { + let user = appUsersManager.getUser(peerID); if(user.phone) { setText('+' + formatPhoneNumber(user.phone).formatted, this.profileElements.phone); } - appProfileManager.getProfile($rootScope.selectedPeerID, true).then(userFull => { - if($rootScope.selectedPeerID != peerID) { + appProfileManager.getProfile(peerID, true).then(userFull => { + if(this.peerID != peerID) { this.log.warn('peer changed'); return; } @@ -340,10 +343,10 @@ class AppSidebarRight { } }); } else { - let chat = appPeersManager.getPeer($rootScope.selectedPeerID); + let chat = appPeersManager.getPeer(peerID); appProfileManager.getChatFull(chat.id).then((chatFull: any) => { - if($rootScope.selectedPeerID != peerID) { + if(this.peerID != peerID) { this.log.warn('peer changed'); return; } @@ -356,7 +359,7 @@ class AppSidebarRight { }); } - let dialog: any = appMessagesManager.getDialogByPeerID($rootScope.selectedPeerID); + let dialog: any = appMessagesManager.getDialogByPeerID(peerID); if(dialog.length) { dialog = dialog[0]; let muted = false; @@ -368,8 +371,8 @@ class AppSidebarRight { } } - if($rootScope.selectedPeerID < 0) { // not human - let isChannel = appPeersManager.isChannel($rootScope.selectedPeerID) && !appPeersManager.isMegagroup($rootScope.selectedPeerID); + if(peerID < 0) { // not human + let isChannel = appPeersManager.isChannel(peerID) && !appPeersManager.isMegagroup(peerID); if(isChannel) { appImManager.btnMute.classList.remove('tgico-mute', 'tgico-unmute'); appImManager.btnMute.classList.add(muted ? 'tgico-unmute' : 'tgico-mute'); diff --git a/src/scss/materialize.scss b/src/scss/materialize.scss deleted file mode 100644 index 6a51657b..00000000 --- a/src/scss/materialize.scss +++ /dev/null @@ -1,41 +0,0 @@ -@charset "UTF-8"; - -// Color -@import "components/color-variables"; -@import "components/color-classes"; - -// Variables; -@import "components/variables"; - -// Reset -@import "components/normalize"; - -// components -@import "components/global"; -@import "components/badges"; -@import "components/icons-material-design"; -@import "components/grid"; -@import "components/navbar"; -@import "components/typography"; -@import "components/transitions"; -@import "components/cards"; -@import "components/toast"; -@import "components/tabs"; -@import "components/tooltip"; -@import "components/buttons"; -@import "components/dropdown"; -@import "components/waves"; -@import "components/modal"; -@import "components/collapsible"; -@import "components/chips"; -@import "components/materialbox"; -@import "components/forms/forms"; -@import "components/table_of_contents"; -@import "components/sidenav"; -@import "components/preloader"; -@import "components/slider"; -@import "components/carousel"; -@import "components/tapTarget"; -@import "components/pulse"; -@import "components/datepicker"; -@import "components/timepicker"; diff --git a/src/scss/partials/_leftSidebar.scss b/src/scss/partials/_leftSidebar.scss index 4db3af61..ea2b4fb3 100644 --- a/src/scss/partials/_leftSidebar.scss +++ b/src/scss/partials/_leftSidebar.scss @@ -5,9 +5,14 @@ .sidebar-content { width: 100%; max-height: 100%; + height: 100%; overflow: hidden; display: flex; /* idk why but need */ position: relative; + + > div { + width: 100%; + } } #chats-container { @@ -29,7 +34,7 @@ background: #fff; &.active { - display: block; + display: flex; } } }