Browse Source

virtual chatlist scroll (care)

master
Eduard Kuzmenko 5 years ago
parent
commit
be4205e5cc
  1. BIN
      .DS_Store
  2. 125
      src/components/misc.ts
  3. 71
      src/components/pageIm.ts
  4. 2
      src/components/pageSignIn.ts
  5. 57
      src/lib/appManagers/appDialogsManager.ts
  6. 52
      src/lib/appManagers/appImManager.ts
  7. 2
      src/lib/appManagers/appMessagesIDsManager.ts
  8. 32
      src/lib/appManagers/appMessagesManager.ts
  9. 110
      src/lib/appManagers/appSidebarLeft.ts
  10. 43
      src/lib/appManagers/appSidebarRight.ts
  11. 41
      src/scss/materialize.scss
  12. 7
      src/scss/partials/_leftSidebar.scss

BIN
.DS_Store vendored

Binary file not shown.

125
src/components/misc.ts

@ -376,62 +376,151 @@ export function scrollable(el: HTMLDivElement, x = false, y = true) {
let resize = () => { let resize = () => {
// @ts-ignore // @ts-ignore
scrollHeight = container[scrollType]; scrollSize = container[scrollType];
let rect = container.getBoundingClientRect(); let rect = container.getBoundingClientRect();
// @ts-ignore // @ts-ignore
height = rect[type]; size = rect[type];
if(!height || height == scrollHeight) { if(!size || size == scrollSize) {
thumbHeight = 0; thumbSize = 0;
// @ts-ignore // @ts-ignore
thumb.style[type] = thumbHeight + 'px'; thumb.style[type] = thumbSize + 'px';
return; return;
} }
//if(!height) return; //if(!height) return;
let divider = scrollHeight / height / 0.5; let divider = scrollSize / size / 0.5;
thumbHeight = height / divider; thumbSize = size / divider;
if(thumbHeight < 20) thumbHeight = 20; if(thumbSize < 20) thumbSize = 20;
// @ts-ignore // @ts-ignore
thumb.style[type] = thumbHeight + 'px'; thumb.style[type] = thumbSize + 'px';
// @ts-ignore // @ts-ignore
//console.log('onresize', thumb.style[type], thumbHeight, height); //console.log('onresize', thumb.style[type], thumbHeight, height);
}; };
let scrollHeight = -1; let scrollSize = -1;
let height = 0; let size = 0;
let thumbHeight = 0; let thumbSize = 0;
window.addEventListener('resize', resize); window.addEventListener('resize', resize);
//container.addEventListener('DOMNodeInserted', 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 // @ts-ignore
if(container[scrollType] != scrollHeight || thumbHeight == 0) { //let st = container[scrollSide];
// @ts-ignore
if(container[scrollType] != scrollSize || thumbSize == 0) {
resize(); 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 // @ts-ignore
let value = container[scrollSide] / (scrollHeight - height) * 100; let value = container[scrollSide] / (scrollSize - size) * 100;
let maxValue = 100 - (thumbHeight / height * 100); let maxValue = 100 - (thumbSize / size * 100);
//console.log('onscroll', container.scrollHeight, thumbHeight, height, value, maxValue); //console.log('onscroll', container.scrollHeight, thumbHeight, height, value, maxValue);
// @ts-ignore // @ts-ignore
thumb.style[side] = (value >= maxValue ? maxValue : value) + '%'; 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)); Array.from(el.children).forEach(c => container.append(c));
container.append(paddingBottomDiv);
el.append(container);//container.append(el); el.append(container);//container.append(el);
container.parentElement.append(thumb); container.parentElement.append(thumb);
resize(); resize();
return container; return {container, hiddenElements, onScroll};
} }
export function wrapPhoto(this: AppImManager, photo: any, message: any, container: HTMLDivElement) { export function wrapPhoto(this: AppImManager, photo: any, message: any, container: HTMLDivElement) {

71
src/components/pageIm.ts

@ -13,6 +13,7 @@ import appStickersManager, { MTStickerSet } from "../lib/appManagers/appStickers
import { AppImManager } from "../lib/appManagers/appImManager"; import { AppImManager } from "../lib/appManagers/appImManager";
import { AppMessagesManager } from "../lib/appManagers/appMessagesManager"; import { AppMessagesManager } from "../lib/appManagers/appMessagesManager";
import appSidebarRight from "../lib/appManagers/appSidebarRight"; import appSidebarRight from "../lib/appManagers/appSidebarRight";
import appSidebarLeft from "../lib/appManagers/appSidebarLeft";
const EMOTICONSSTICKERGROUP = 'emoticons-dropdown'; const EMOTICONSSTICKERGROUP = 'emoticons-dropdown';
@ -175,7 +176,7 @@ let initEmoticonsDropdown = (pageEl: HTMLDivElement,
let prevCategoryIndex = 1; let prevCategoryIndex = 1;
let menu = contentEmojiDiv.nextElementSibling as HTMLUListElement; let menu = contentEmojiDiv.nextElementSibling as HTMLUListElement;
let emojiScroll = scrollable(contentEmojiDiv); let emojiScroll = scrollable(contentEmojiDiv).container;
emojiScroll.addEventListener('scroll', (e) => { emojiScroll.addEventListener('scroll', (e) => {
prevCategoryIndex = emoticonsContentOnScroll(menu, heights, prevCategoryIndex, emojiScroll); prevCategoryIndex = emoticonsContentOnScroll(menu, heights, prevCategoryIndex, emojiScroll);
}); });
@ -341,7 +342,7 @@ let initEmoticonsDropdown = (pageEl: HTMLDivElement,
}); });
let prevCategoryIndex = 0; let prevCategoryIndex = 0;
let stickersScroll = scrollable(contentStickersDiv); let stickersScroll = scrollable(contentStickersDiv).container;
stickersScroll.addEventListener('scroll', (e) => { stickersScroll.addEventListener('scroll', (e) => {
lazyLoadQueue.check(); lazyLoadQueue.check();
lottieLoader.checkAnimations(); lottieLoader.checkAnimations();
@ -362,72 +363,15 @@ export default () => import('../lib/services').then(services => {
let {appImManager, appMessagesManager, appDialogsManager, apiUpdatesManager, appUsersManager} = services; let {appImManager, appMessagesManager, appDialogsManager, apiUpdatesManager, appUsersManager} = services;
//export default () => { //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; let pageEl = document.body.getElementsByClassName('page-chats')[0] as HTMLDivElement;
pageEl.style.display = ''; pageEl.style.display = '';
const loadCount = Math.round(document.body.scrollHeight / 70 * 1.5); let sidebarScroll = scrollable(document.body.querySelector('.profile-container')).container;
let chatScroll = scrollable(document.getElementById('bubbles') as HTMLDivElement).container;
let chatsScroll = scrollable(chatsContainer as HTMLDivElement);
let sidebarScroll = scrollable(document.body.querySelector('.profile-container'));
let chatScroll = scrollable(document.getElementById('bubbles') as HTMLDivElement);
apiUpdatesManager.attach(); apiUpdatesManager.attach();
let offsetIndex = 0;
let loadDialogsPromise: Promise<any>;
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 // @ts-ignore
document.addEventListener('user_update', (e: CustomEvent) => { document.addEventListener('user_update', (e: CustomEvent) => {
let userID = e.detail; let userID = e.detail;
@ -797,9 +741,8 @@ export default () => import('../lib/services').then(services => {
}); });
}); });
appSidebarLeft.loadDialogs().then(result => {
loadDialogs().then(result => { appSidebarLeft.onChatsScroll();
onScroll();
appImManager.setScroll(chatScroll); appImManager.setScroll(chatScroll);
appSidebarRight.setScroll(sidebarScroll); appSidebarRight.setScroll(sidebarScroll);
}); });

2
src/components/pageSignIn.ts

@ -51,7 +51,7 @@ export default () => {
wrapper.appendChild(list); wrapper.appendChild(list);
//let wrapperScroll = OverlayScrollbars(wrapper, (window as any).scrollbarOptions); //let wrapperScroll = OverlayScrollbars(wrapper, (window as any).scrollbarOptions);
let wrapperScroll = scrollable(wrapper); scrollable(wrapper);
let initedSelect = false; let initedSelect = false;

57
src/lib/appManagers/appDialogsManager.ts

@ -1,6 +1,6 @@
import apiManager from "../mtproto/apiManager"; import apiManager from "../mtproto/apiManager";
import apiFileManager from '../mtproto/apiFileManager'; import apiFileManager from '../mtproto/apiFileManager';
import { $rootScope, findUpTag } from "../utils"; import { $rootScope, findUpTag, isElementInViewport } from "../utils";
import appImManager from "./appImManager"; import appImManager from "./appImManager";
import appPeersManager from './appPeersManager'; import appPeersManager from './appPeersManager';
import appMessagesManager from "./appMessagesManager"; import appMessagesManager from "./appMessagesManager";
@ -20,10 +20,8 @@ type DialogDom = {
}; };
export class AppDialogsManager { export class AppDialogsManager {
public pinnedChatList = document.getElementById('dialogs-pinned') as HTMLUListElement;
public chatList = document.getElementById('dialogs') as HTMLUListElement; public chatList = document.getElementById('dialogs') as HTMLUListElement;
public chatsHidden: any;
public myID = 0; public myID = 0;
public doms: {[x: number]: any} = {}; public doms: {[x: number]: any} = {};
@ -40,7 +38,6 @@ export class AppDialogsManager {
//let chatClosedDiv = document.getElementById('chat-closed'); //let chatClosedDiv = document.getElementById('chat-closed');
this.setListClickListener(this.pinnedChatList);
this.setListClickListener(this.chatList); this.setListClickListener(this.chatList);
} }
@ -131,20 +128,54 @@ export class AppDialogsManager {
} }
public sortDom() { 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) .filter((d: any) => !d.pFlags.pinned)
.sort((a: any, b: any) => { .sort((a: any, b: any) => {
let timeA = appMessagesManager.getMessage(a.top_message).date; let timeA = appMessagesManager.getMessage(a.top_message).date;
let timeB = appMessagesManager.getMessage(b.top_message).date; let timeB = appMessagesManager.getMessage(b.top_message).date;
return timeB - timeA; 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); let dom = this.getDialogDom(d.peerID);
if(!dom) return; 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) { public setLastMessage(dialog: any, lastMessage?: any, dom?: DialogDom) {
@ -405,7 +436,13 @@ export class AppDialogsManager {
}; };
if(!container) { 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.doms[dialog.peerID] = dom;
this.setLastMessage(dialog); this.setLastMessage(dialog);
} else { } else {

52
src/lib/appManagers/appImManager.ts

@ -132,6 +132,7 @@ export class AppImManager {
private topbar: HTMLDivElement = null; private topbar: HTMLDivElement = null;
private chatInput: HTMLDivElement = null; private chatInput: HTMLDivElement = null;
scrolledAll: boolean;
constructor() { constructor() {
this.log = logger('IM'); this.log = logger('IM');
@ -380,30 +381,39 @@ export class AppImManager {
// load more history // load more history
if(!this.getHistoryPromise && !this.getHistoryTimeout /* && false */) { 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 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; this.getHistoryTimeout = 0;
let willLoad = false; let willLoad = false;
for(let i = 0; i < 10; ++i) { if(!this.scrolledAll) {
let msgID = history[i]; for(let i = 0; i < 10; ++i) {
if(!(msgID in this.bubbles) || msgID <= 0) continue; let msgID = history[i];
let bubble = this.bubbles[msgID]; let bubble = this.bubbles[msgID];
if(isElementInViewport(bubble)) { if(isElementInViewport(bubble)) {
willLoad = true; willLoad = true;
this.log('Will load more (up) history by id:', history[0], 'maxID:', history[history.length - 1], history, bubble); 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 /* false && */!testScroll && this.getHistory(history[0], true).then(() => { // uncomment
this.onScroll(); this.onScroll();
}).catch(err => { }).catch(err => {
this.log.warn('Could not load more history, err:', err); this.log.warn('Could not load more history, err:', err);
}); });
break; break;
}
} }
} }
@ -413,8 +423,6 @@ export class AppImManager {
if(!willLoad && history.indexOf(/* this.lastDialog */dialog.top_message) === -1) { if(!willLoad && history.indexOf(/* this.lastDialog */dialog.top_message) === -1) {
let lastMsgIDs = history.slice(-10); let lastMsgIDs = history.slice(-10);
for(let msgID of lastMsgIDs) { for(let msgID of lastMsgIDs) {
if(!(msgID in this.bubbles) || msgID <= 0) continue;
let bubble = this.bubbles[msgID]; let bubble = this.bubbles[msgID];
if(isElementInViewport(bubble)) { if(isElementInViewport(bubble)) {
@ -520,6 +528,7 @@ export class AppImManager {
public cleanup() { public cleanup() {
this.peerID = $rootScope.selectedPeerID = 0; this.peerID = $rootScope.selectedPeerID = 0;
this.scrolledAll = false;
if(this.lastContainerDiv) this.lastContainerDiv.remove(); if(this.lastContainerDiv) this.lastContainerDiv.remove();
if(this.firstContainerDiv) this.firstContainerDiv.remove(); if(this.firstContainerDiv) this.firstContainerDiv.remove();
@ -645,7 +654,7 @@ export class AppImManager {
appSidebarRight.fillProfileElements() appSidebarRight.fillProfileElements()
]).catch(err => { ]).catch(err => {
this.log.error(err); this.log.error('setPeer promises error:', err);
}); });
} }
@ -1191,6 +1200,11 @@ export class AppImManager {
return true; return true;
} }
// commented bot getProfile in getHistory!
if(!result.history/* .filter((id: number) => id > 0) */.length && !isBackLimit) {
this.scrolledAll = true;
}
//this.chatInner.innerHTML = ''; //this.chatInner.innerHTML = '';
let history = result.history.slice(); let history = result.history.slice();

2
src/lib/appManagers/appMessagesIDsManager.ts

@ -30,7 +30,7 @@ export class AppMessagesIDsManager {
} }
public getMessageLocalID(fullMsgID: number) { public getMessageLocalID(fullMsgID: number) {
if (!fullMsgID) { if(!fullMsgID) {
return 0; return 0;
} }
return fullMsgID % this.fullMsgIDModulus; return fullMsgID % this.fullMsgIDModulus;

32
src/lib/appManagers/appMessagesManager.ts

@ -2418,7 +2418,7 @@ export class AppMessagesManager {
// need be commented for read out messages // need be commented for read out messages
//if(newUnreadCount != 0 || !isOut) { // fix 16.11.2019 (maybe not) //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}); $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) { public requestHistory(peerID: number, maxID: number, limit: number, offset = 0) {
var isChannel = AppPeersManager.isChannel(peerID); 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', { return MTProto.apiManager.invokeApi('messages.getHistory', {
peer: AppPeersManager.getInputPeerByID(peerID), peer: AppPeersManager.getInputPeerByID(peerID),
@ -3079,16 +3079,7 @@ export class AppMessagesManager {
max_id: 0, max_id: 0,
min_id: 0, min_id: 0,
hash: 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, timeout: 300,
noErrorBox: true noErrorBox: true
}).then((historyResult: any) => { }).then((historyResult: any) => {
@ -3101,22 +3092,19 @@ export class AppMessagesManager {
} }
var length = historyResult.messages.length; var length = historyResult.messages.length;
if(length && if(length && historyResult.messages[length - 1].deleted) {
historyResult.messages[length - 1].deleted) {
historyResult.messages.splice(length - 1, 1); historyResult.messages.splice(length - 1, 1);
length--; length--;
historyResult.count--; historyResult.count--;
} }
if( // don't need the intro now
peerID < 0 || /* if(peerID < 0 || !appUsersManager.isBot(peerID) || (length == limit && limit < historyResult.count)) {
!appUsersManager.isBot(peerID) ||
(length == limit && limit < historyResult.count)
) {
return historyResult; 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; var description = userFull.bot_info && userFull.bot_info.description;
if(description) { if(description) {
var messageID = this.tempID--; var messageID = this.tempID--;
@ -3142,7 +3130,7 @@ export class AppMessagesManager {
} }
return historyResult; return historyResult;
}); }); */
}, (error) => { }, (error) => {
switch (error.type) { switch (error.type) {
case 'CHANNEL_PRIVATE': case 'CHANNEL_PRIVATE':

110
src/lib/appManagers/appSidebarLeft.ts

@ -1,10 +1,9 @@
import { logger } from "../polyfill"; import { logger } from "../polyfill";
import { scrollable } from "../../components/misc"; import { scrollable, putPreloader } from "../../components/misc";
import appMessagesManager from "./appMessagesManager"; import appMessagesManager from "./appMessagesManager";
import appDialogsManager from "./appDialogsManager"; import appDialogsManager from "./appDialogsManager";
import { isElementInViewport, $rootScope } from "../utils"; import { isElementInViewport } from "../utils";
import appMessagesIDsManager from "./appMessagesIDsManager"; import appMessagesIDsManager from "./appMessagesIDsManager";
import apiManager from '../mtproto/apiManager';
import appImManager from "./appImManager"; import appImManager from "./appImManager";
class AppSidebarLeft { class AppSidebarLeft {
@ -19,6 +18,15 @@ class AppSidebarLeft {
private listsContainer: HTMLDivElement = null; private listsContainer: HTMLDivElement = null;
private searchMessagesList: HTMLUListElement = 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<any>;
private hiddenScroll: any;
private log = logger('SL'); private log = logger('SL');
private peerID = 0; private peerID = 0;
@ -32,28 +40,40 @@ class AppSidebarLeft {
private query = ''; private query = '';
public myID = 0;
constructor() { constructor() {
this.listsContainer = scrollable(this.searchContainer); this.chatsPreloader = document.createElement('div');
this.searchMessagesList = document.createElement('ul'); this.chatsPreloader.classList.add('preloader');
putPreloader(this.chatsPreloader);
this.chatsContainer.append(this.chatsPreloader);
apiManager.getUserID().then((id) => { this.chatsLoadCount = Math.round(document.body.scrollHeight / 70 * 1.5);
this.myID = id;
});
$rootScope.$on('user_auth', (e: CustomEvent) => { let {container: chatsScroll, hiddenElements: chatsHidden, onScroll: hiddenScroll} = scrollable(this.chatsContainer as HTMLDivElement);
let userAuth = e.detail; this.chatsScroll = chatsScroll;
this.myID = userAuth ? userAuth.id : 0; 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', () => { 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 = `<div class="user-avatar is-online" style="font-size: 0px;"><img src="assets/img/camomile.jpg"></div><div class="user-caption"><p><span class="user-title">Влад</span><span><span class="message-status"></span><span class="message-time">14:41</span></span></p><p><span class="user-last-message">это важно</span><span class="tgico-pinnedchat"></span></p></div><div class="c-ripple"><span class="c-ripple__circle" style="top: 65px; left: 338.5px;"></span></div>`;
this.searchMessagesList.append(li);
} */
this.listsContainer.addEventListener('scroll', this.onSidebarScroll.bind(this)); this.listsContainer.addEventListener('scroll', this.onSidebarScroll.bind(this));
this.searchContainer.append(this.listsContainer); //this.searchContainer.append(this.listsContainer);
appDialogsManager.setListClickListener(this.searchMessagesList); appDialogsManager.setListClickListener(this.searchMessagesList);
@ -85,7 +105,7 @@ class AppSidebarLeft {
this.log('input', value); this.log('input', value);
if(this.listsContainer.contains(this.searchMessagesList)) { if(this.listsContainer.contains(this.searchMessagesList)) {
this.listsContainer.removeChild(this.searchMessagesList) this.listsContainer.removeChild(this.searchMessagesList);
} }
if(!value.trim()) { if(!value.trim()) {
@ -115,11 +135,63 @@ class AppSidebarLeft {
}); });
window.addEventListener('resize', () => { 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() { public onSidebarScroll() {
if(!this.query.trim()) return;
let elements = Array.from(this.searchMessagesList.childNodes).slice(-5); let elements = Array.from(this.searchMessagesList.childNodes).slice(-5);
for(let li of elements) { for(let li of elements) {
if(isElementInViewport(li)) { if(isElementInViewport(li)) {
@ -150,6 +222,8 @@ class AppSidebarLeft {
let query = this.query; let query = this.query;
if(!query.trim()) return;
if(this.loadedCount != 0 && this.loadedCount >= this.foundCount) { if(this.loadedCount != 0 && this.loadedCount >= this.foundCount) {
return Promise.resolve(); return Promise.resolve();
} }

43
src/lib/appManagers/appSidebarRight.ts

@ -65,6 +65,8 @@ class AppSidebarRight {
private log = logger('SR'); private log = logger('SR');
private peerID = 0;
constructor() { constructor() {
let container = this.profileContentEl.querySelector('.profile-tabs-content') as HTMLDivElement; let container = this.profileContentEl.querySelector('.profile-tabs-content') as HTMLDivElement;
let tabs = this.profileContentEl.querySelector('.profile-tabs') as HTMLUListElement; let tabs = this.profileContentEl.querySelector('.profile-tabs') as HTMLUListElement;
@ -143,7 +145,7 @@ class AppSidebarRight {
} }
public loadSidebarMedia(single = false) { public loadSidebarMedia(single = false) {
let peerID = $rootScope.selectedPeerID; let peerID = this.peerID;
let typesToLoad = single ? [this.sharedMediaType] : this.sharedMediaTypes; let typesToLoad = single ? [this.sharedMediaType] : this.sharedMediaTypes;
@ -164,14 +166,14 @@ class AppSidebarRight {
? appMessagesManager.historiesStorage[peerID].history.slice() : []; ? appMessagesManager.historiesStorage[peerID].history.slice() : [];
maxID = !maxID && ids.length ? ids[ids.length - 1] : maxID; 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) return this.loadSidebarMediaPromises[type] = appMessagesManager.getSearch(peerID, '', {_: type}, maxID, 50)
.then(value => { .then(value => {
ids = ids.concat(value.history); ids = ids.concat(value.history);
history.push(...ids); 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) { if($rootScope.selectedPeerID != peerID) {
this.log.warn('peer changed'); this.log.warn('peer changed');
@ -188,11 +190,11 @@ class AppSidebarRight {
let message = appMessagesManager.getMessage(mid); let message = appMessagesManager.getMessage(mid);
if(!message.media) return; if(!message.media) return;
/* 'inputMessagesFilterContacts', /*'inputMessagesFilterContacts',
'inputMessagesFilterPhotoVideo', 'inputMessagesFilterPhotoVideo',
'inputMessagesFilterDocument', 'inputMessagesFilterDocument',
'inputMessagesFilterUrl', 'inputMessagesFilterUrl',
'inputMessagesFilterVoice'*/ 'inputMessagesFilterVoice'*/
switch(type) { switch(type) {
case 'inputMessagesFilterPhotoVideo': { case 'inputMessagesFilterPhotoVideo': {
/* if(!(message.media.photo || message.media.document || message.media.webpage.document)) { /* if(!(message.media.photo || message.media.document || message.media.webpage.document)) {
@ -281,7 +283,8 @@ class AppSidebarRight {
} }
public fillProfileElements() { public fillProfileElements() {
let peerID = $rootScope.selectedPeerID; let peerID = this.peerID = $rootScope.selectedPeerID;
this.loadSidebarMediaPromises = {};
this.profileContentEl.parentElement.scrollTop = 0; this.profileContentEl.parentElement.scrollTop = 0;
this.profileElements.bio.style.display = 'none'; this.profileElements.bio.style.display = 'none';
@ -311,19 +314,19 @@ class AppSidebarRight {
}; };
// username // username
let username = appPeersManager.getPeerUsername($rootScope.selectedPeerID); let username = appPeersManager.getPeerUsername(peerID);
if(username) { if(username) {
setText(appPeersManager.getPeerUsername($rootScope.selectedPeerID), this.profileElements.username); setText(appPeersManager.getPeerUsername(peerID), this.profileElements.username);
} }
if($rootScope.selectedPeerID > 0) { if(peerID > 0) {
let user = appUsersManager.getUser($rootScope.selectedPeerID); let user = appUsersManager.getUser(peerID);
if(user.phone) { if(user.phone) {
setText('+' + formatPhoneNumber(user.phone).formatted, this.profileElements.phone); setText('+' + formatPhoneNumber(user.phone).formatted, this.profileElements.phone);
} }
appProfileManager.getProfile($rootScope.selectedPeerID, true).then(userFull => { appProfileManager.getProfile(peerID, true).then(userFull => {
if($rootScope.selectedPeerID != peerID) { if(this.peerID != peerID) {
this.log.warn('peer changed'); this.log.warn('peer changed');
return; return;
} }
@ -340,10 +343,10 @@ class AppSidebarRight {
} }
}); });
} else { } else {
let chat = appPeersManager.getPeer($rootScope.selectedPeerID); let chat = appPeersManager.getPeer(peerID);
appProfileManager.getChatFull(chat.id).then((chatFull: any) => { appProfileManager.getChatFull(chat.id).then((chatFull: any) => {
if($rootScope.selectedPeerID != peerID) { if(this.peerID != peerID) {
this.log.warn('peer changed'); this.log.warn('peer changed');
return; return;
} }
@ -356,7 +359,7 @@ class AppSidebarRight {
}); });
} }
let dialog: any = appMessagesManager.getDialogByPeerID($rootScope.selectedPeerID); let dialog: any = appMessagesManager.getDialogByPeerID(peerID);
if(dialog.length) { if(dialog.length) {
dialog = dialog[0]; dialog = dialog[0];
let muted = false; let muted = false;
@ -368,8 +371,8 @@ class AppSidebarRight {
} }
} }
if($rootScope.selectedPeerID < 0) { // not human if(peerID < 0) { // not human
let isChannel = appPeersManager.isChannel($rootScope.selectedPeerID) && !appPeersManager.isMegagroup($rootScope.selectedPeerID); let isChannel = appPeersManager.isChannel(peerID) && !appPeersManager.isMegagroup(peerID);
if(isChannel) { if(isChannel) {
appImManager.btnMute.classList.remove('tgico-mute', 'tgico-unmute'); appImManager.btnMute.classList.remove('tgico-mute', 'tgico-unmute');
appImManager.btnMute.classList.add(muted ? 'tgico-unmute' : 'tgico-mute'); appImManager.btnMute.classList.add(muted ? 'tgico-unmute' : 'tgico-mute');

41
src/scss/materialize.scss vendored

@ -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";

7
src/scss/partials/_leftSidebar.scss

@ -5,9 +5,14 @@
.sidebar-content { .sidebar-content {
width: 100%; width: 100%;
max-height: 100%; max-height: 100%;
height: 100%;
overflow: hidden; overflow: hidden;
display: flex; /* idk why but need */ display: flex; /* idk why but need */
position: relative; position: relative;
> div {
width: 100%;
}
} }
#chats-container { #chats-container {
@ -29,7 +34,7 @@
background: #fff; background: #fff;
&.active { &.active {
display: block; display: flex;
} }
} }
} }

Loading…
Cancel
Save