virtual chatlist scroll (care)

This commit is contained in:
Eduard Kuzmenko 2020-02-08 18:58:22 +07:00
parent fad3455a2e
commit b9a86781ca
21 changed files with 378 additions and 263 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@ -242,7 +242,16 @@
</div>
<div class="chats-container sidebar sidebar-left">
<div class="sidebar-header">
<button class="btn-icon tgico-menu rp sidebar-tools-button"></button>
<div class="btn-icon tgico-menu btn-menu-toggle rp sidebar-tools-button">
<div class="btn-menu bottom-right">
<div class="btn-menu-item menu-new-group tgico-newgroup rp">New Group</div>
<div class="btn-menu-item menu-contacts tgico-user rp">Contacts</div>
<div class="btn-menu-item menu-archive tgico-archive rp">Archived</div>
<div class="btn-menu-item menu-saved tgico-savedmessages rp">Saved</div>
<div class="btn-menu-item menu-settings tgico-settings rp">Settings</div>
<div class="btn-menu-item menu-help tgico-help rp">Help</div>
</div>
</div>
<div class="input-search">
<input type="text" placeholder="Search" id="global-search" />
<span class="tgico tgico-search"></span>
@ -254,8 +263,7 @@
<ul id="dialogs-pinned"></ul>
<ul id="dialogs"></ul>
</div>
<div id="search-container">
<div id="search-container" class="active">
</div>
</div>
</div>
@ -278,15 +286,7 @@
<div class="pinned-message-border"></div>
<div class="pinned-message-content">
<div class="pinned-message-title">Pinned Message</div>
<div class="pinned-message-subtitle">At the end of this stage, all apps should be able to:
+ Update the chat list and receive new messages.
+ Send new messages.
- Display and send media, files and links. (2 дня)
+ Display a 'Shared media' section for chats that includes photos and files. (2 дня максимум)
+ Display stickers, send emoji and stickers. (3 дня)
+ Use the default camomile background in chats. (1 день)
- Search for messages in chats. (2 дня (+фикс скролла))
</div>
<div class="pinned-message-subtitle"></div>
</div>
</div>
</div>
@ -294,7 +294,12 @@
<div class="pinned-msg"></div>
<div class="btn-icon rp tool-mute chat-mute-button" style="display: none;"></div>
<div class="btn-icon rp tgico-search chat-search-button"></div>
<div class="btn-icon rp tgico-more chat-more-button"></div>
<div class="btn-icon btn-menu-toggle rp tgico-more chat-more-button">
<div class="btn-menu bottom-left">
<div class="btn-menu-item menu-mute rp">Mute</div>
<div class="btn-menu-item menu-delete tgico-delete danger rp">Delete and Leave</div>
</div>
</div>
</div>
<div id="bubbles">
<div id="bubbles-inner"></div>
@ -364,10 +369,10 @@
<button class="btn-icon rp tgico-edit sidebar-edit-button"></button>
<div class="btn-icon tgico-more rp sidebar-menu-button">
<div class="sidebar-menu is-bottom-left">
<button class="btn-icon rp tgico-edit sidebar-menu-edit"></button>
<button class="sidebar-menu-block a-menu-item is-danger">Block</button>
<div class="btn-icon tgico-more rp btn-menu-toggle">
<div class="btn-menu bottom-left">
<div class="btn-menu-item menu-mute rp">Mute</div>
<div class="btn-menu-item menu-delete tgico-delete danger rp">Delete and Leave</div>
</div>
</div>
</div>

Binary file not shown.

View File

@ -260,11 +260,9 @@
<!-- <div class="tabs-container"> -->
<div class="sidebar-content">
<div id="chats-container">
<ul id="dialogs-pinned"></ul>
<ul id="dialogs"></ul>
<ul id="dialogs"></ul>
</div>
<div id="search-container">
</div>
</div>
</div>

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -376,62 +376,151 @@ export function scrollable(el: HTMLDivElement, x = false, y = true) {
let resize = () => {
// @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
if(container[scrollType] != scrollHeight || thumbHeight == 0) {
//let st = container[scrollSide];
// @ts-ignore
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) {

View File

@ -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<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
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);
});

View File

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

View File

@ -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 {

View File

@ -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;
if(!this.scrolledAll) {
for(let i = 0; i < 10; ++i) {
let msgID = history[i];
let bubble = this.bubbles[msgID];
if(isElementInViewport(bubble)) {
willLoad = true;
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);
});
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 = '';

View File

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

View File

@ -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':

View File

@ -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<any>;
private hiddenScroll: any;
private log = logger('SL');
private peerID = 0;
@ -29,31 +37,43 @@ class AppSidebarLeft {
private searchPromise: Promise<void> = null;
private searchTimeout: number = 0;
private query = '';
public myID = 0;
constructor() {
this.listsContainer = scrollable(this.searchContainer);
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');
apiManager.getUserID().then((id) => {
this.myID = id;
});
$rootScope.$on('user_auth', (e: CustomEvent) => {
let userAuth = e.detail;
this.myID = userAuth ? userAuth.id : 0;
});
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.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;
}

View File

@ -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');

View File

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

View File

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