webp polyfill & archived dialogs & improved lazy load
This commit is contained in:
parent
55833f2489
commit
d93613b6f2
@ -19,7 +19,7 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement,
|
||||
let dropdown = pageEl.querySelector('.emoji-dropdown') as HTMLDivElement;
|
||||
dropdown.classList.add('active'); // need
|
||||
|
||||
let lazyLoadQueue = new LazyLoadQueue();
|
||||
let lazyLoadQueue = new LazyLoadQueue(5);
|
||||
|
||||
let container = pageEl.querySelector('.emoji-container .tabs-container') as HTMLDivElement;
|
||||
let tabs = pageEl.querySelector('.emoji-dropdown .emoji-tabs') as HTMLUListElement;
|
||||
|
@ -1,20 +1,74 @@
|
||||
import { isElementInViewport } from "../lib/utils";
|
||||
|
||||
export default class LazyLoadQueue {
|
||||
private lazyLoadMedia: Array<{div: HTMLDivElement, load: () => Promise<void>}> = [];
|
||||
private lazyLoadMedia: Array<{div: HTMLDivElement, load: () => Promise<void>, wasSeen?: boolean}> = [];
|
||||
private loadingMedia = 0;
|
||||
private tempID = 0;
|
||||
|
||||
constructor(private parallelLimit = 0) {
|
||||
|
||||
}
|
||||
|
||||
public clear() {
|
||||
this.tempID--;
|
||||
this.lazyLoadMedia.length = 0;
|
||||
this.loadingMedia = 0;
|
||||
}
|
||||
|
||||
public async processQueue(id?: number) {
|
||||
if(this.parallelLimit > 0 && this.loadingMedia >= this.parallelLimit) return;
|
||||
|
||||
let item: {div: HTMLDivElement, load: () => Promise<void>, wasSeen?: boolean};
|
||||
let index: number;
|
||||
/* if(id) item = this.lazyLoadMedia.splice(id, 1) as any;
|
||||
else item = this.lazyLoadMedia.pop(); */
|
||||
|
||||
if(id !== undefined) item = this.lazyLoadMedia.splice(id, 1)[0];
|
||||
else {
|
||||
index = this.lazyLoadMedia.findIndex(i => isElementInViewport(i.div));
|
||||
if(index !== -1) {
|
||||
item = this.lazyLoadMedia.splice(index, 1)[0];
|
||||
} else {
|
||||
//index = this.lazyLoadMedia.findIndex(i => i.wasSeen);
|
||||
//if(index !== -1) {
|
||||
//item = this.lazyLoadMedia.splice(index, 1)[0];
|
||||
/*} else {
|
||||
item = this.lazyLoadMedia.pop();
|
||||
} */
|
||||
|
||||
let length = this.lazyLoadMedia.length;
|
||||
for(index = length - 1; index >= 0; --index) {
|
||||
if(this.lazyLoadMedia[index].wasSeen) {
|
||||
item = this.lazyLoadMedia.splice(index, 1)[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(item) {
|
||||
this.loadingMedia++;
|
||||
|
||||
let tempID = this.tempID;
|
||||
|
||||
try {
|
||||
await item.load();
|
||||
} catch(err) {
|
||||
console.error('loadMediaQueue error:', err, item, id, index);
|
||||
}
|
||||
|
||||
if(tempID == this.tempID) {
|
||||
this.loadingMedia--;
|
||||
}
|
||||
|
||||
if(this.lazyLoadMedia.length) {
|
||||
this.processQueue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public check(id?: number) {
|
||||
/* let length = this.lazyLoadMedia.length;
|
||||
for(let i = length - 1; i >= 0; --i) {
|
||||
let {div, load} = this.lazyLoadMedia[i];
|
||||
|
||||
if(isElementInViewport(div)) {
|
||||
console.log('will load div:', div);
|
||||
load();
|
||||
this.lazyLoadMedia.splice(i, 1);
|
||||
}
|
||||
} */
|
||||
if(id !== undefined) {
|
||||
/* if(id !== undefined) {
|
||||
let {div, load} = this.lazyLoadMedia[id];
|
||||
if(isElementInViewport(div)) {
|
||||
//console.log('will load div by id:', div, div.getBoundingClientRect());
|
||||
@ -24,8 +78,42 @@ export default class LazyLoadQueue {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let length = this.lazyLoadMedia.length;
|
||||
for(let i = length - 1; i >= 0; --i) {
|
||||
let {div, load} = this.lazyLoadMedia[i];
|
||||
|
||||
if(isElementInViewport(div)) {
|
||||
console.log('will load div:', div);
|
||||
load();
|
||||
this.lazyLoadMedia.splice(i, 1);
|
||||
}
|
||||
} */
|
||||
|
||||
if(id !== undefined) {
|
||||
let {div} = this.lazyLoadMedia[id];
|
||||
if(isElementInViewport(div)) {
|
||||
//console.log('will load div by id:', div, div.getBoundingClientRect());
|
||||
this.lazyLoadMedia[id].wasSeen = true;
|
||||
this.processQueue(id);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let length = this.lazyLoadMedia.length;
|
||||
for(let i = length - 1; i >= 0; --i) {
|
||||
let {div} = this.lazyLoadMedia[i];
|
||||
|
||||
if(isElementInViewport(div)) {
|
||||
console.log('will load div:', div);
|
||||
this.lazyLoadMedia[i].wasSeen = true;
|
||||
this.processQueue(i);
|
||||
//this.lazyLoadMedia.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
this.lazyLoadMedia = this.lazyLoadMedia.filter(({div, load}) => {
|
||||
/* this.lazyLoadMedia = this.lazyLoadMedia.filter(({div, load}) => {
|
||||
if(isElementInViewport(div)) {
|
||||
//console.log('will load div:', div, div.getBoundingClientRect());
|
||||
load();
|
||||
@ -33,10 +121,11 @@ export default class LazyLoadQueue {
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}); */
|
||||
}
|
||||
|
||||
public push(el: {div: HTMLDivElement, load: () => Promise<void>}) {
|
||||
public push(el: {div: HTMLDivElement, load: () => Promise<void>, wasSeen?: boolean}) {
|
||||
el.wasSeen = false;
|
||||
let id = this.lazyLoadMedia.push(el) - 1;
|
||||
|
||||
this.check(id);
|
||||
|
@ -1,11 +1,10 @@
|
||||
import {MTProto} from '../lib/mtproto/mtproto';
|
||||
|
||||
import pageSignIn from './pageSignIn';
|
||||
import pageSignUp from './pageSignUp';
|
||||
import pageIm from './pageIm';
|
||||
import pagePassword from './pagePassword';
|
||||
import CryptoWorker from '../lib/crypto/cryptoworker';
|
||||
import LottieLoader from '../lib/lottieLoader';
|
||||
import apiManager from '../lib/mtproto/apiManager';
|
||||
|
||||
let installed = false;
|
||||
let authCode: {
|
||||
@ -102,7 +101,7 @@ export default async(_authCode: typeof authCode) => {
|
||||
|
||||
codeInput.setAttribute('disabled', 'true');
|
||||
|
||||
changePhonePromise = MTProto.apiManager.invokeApi('auth.sendCode', {
|
||||
changePhonePromise = apiManager.invokeApi('auth.sendCode', {
|
||||
/* flags: 0, */
|
||||
phone_number: phone_number,
|
||||
api_id: Config.App.id,
|
||||
@ -179,13 +178,13 @@ export default async(_authCode: typeof authCode) => {
|
||||
|
||||
console.log('invoking auth.signIn with params:', params);
|
||||
|
||||
MTProto.apiManager.invokeApi('auth.signIn', params)
|
||||
apiManager.invokeApi('auth.signIn', params)
|
||||
.then((response: any) => {
|
||||
console.log('auth.signIn response:', response);
|
||||
|
||||
switch(response._) {
|
||||
case 'auth.authorization':
|
||||
MTProto.apiManager.setUserAuth({
|
||||
apiManager.setUserAuth({
|
||||
id: response.user.id
|
||||
});
|
||||
|
||||
|
@ -7,7 +7,10 @@ import lottieLoader from "../lib/lottieLoader";
|
||||
|
||||
import appSidebarLeft from "../lib/appManagers/appSidebarLeft";
|
||||
|
||||
|
||||
/* (window as any).libraryLoaded = function(lol: any) {
|
||||
// @ts-ignore
|
||||
console.log('libraryLoaded', lol, this, window.webpMachine);
|
||||
} */
|
||||
|
||||
export default () => import('../lib/services').then(services => {
|
||||
console.log('included services', services);
|
||||
@ -193,5 +196,7 @@ export default () => import('../lib/services').then(services => {
|
||||
appSidebarLeft.loadDialogs().then(result => {
|
||||
appSidebarLeft.onChatsScroll();
|
||||
appImManager.setScroll(chatScroll);
|
||||
|
||||
appSidebarLeft.loadDialogs(true);
|
||||
});
|
||||
});
|
||||
|
@ -1,10 +1,10 @@
|
||||
import {MTProto} from '../lib/mtproto/mtproto';
|
||||
|
||||
import pageIm from './pageIm';
|
||||
import CryptoWorker from '../lib/crypto/cryptoworker';
|
||||
import { putPreloader } from './misc';
|
||||
|
||||
import LottieLoader from '../lib/lottieLoader';
|
||||
import passwordManager from '../lib/mtproto/passwordManager';
|
||||
import apiManager from '../lib/mtproto/apiManager';
|
||||
|
||||
let installed = false;
|
||||
|
||||
@ -97,15 +97,15 @@ export default async() => {
|
||||
this.textContent = 'PLEASE WAIT...';
|
||||
putPreloader(this);
|
||||
|
||||
MTProto.passwordManager.getState()
|
||||
passwordManager.getState()
|
||||
.then(state => {
|
||||
console.log(state);
|
||||
MTProto.passwordManager.check(state, value).then((response: any) => {
|
||||
passwordManager.check(state, value).then((response: any) => {
|
||||
console.log('passwordManager response:', response);
|
||||
|
||||
switch(response._) {
|
||||
case 'auth.authorization':
|
||||
MTProto.apiManager.setUserAuth({
|
||||
apiManager.setUserAuth({
|
||||
id: response.user.id
|
||||
});
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
import {MTProto} from '../lib/mtproto/mtproto';
|
||||
import {putPreloader} from './misc';
|
||||
|
||||
let installed = false;
|
||||
@ -9,6 +8,7 @@ let authCode: {
|
||||
|
||||
import resizeableImage from '../lib/cropper';
|
||||
import pageIm from './pageIm';
|
||||
import apiManager from '../lib/mtproto/apiManager';
|
||||
|
||||
export default (_authCode: typeof authCode) => {
|
||||
authCode = _authCode;
|
||||
@ -75,10 +75,10 @@ export default (_authCode: typeof authCode) => {
|
||||
/* console.log(file, typeof(file)); */
|
||||
|
||||
// @ts-ignore
|
||||
/* MTProto.apiFileManager.uploadFile(file).then(function(inputFile) {
|
||||
/* apiFileManager.uploadFile(file).then(function(inputFile) {
|
||||
console.log('uploaded smthn', inputFile);
|
||||
|
||||
MTProto.apiManager.invokeApi('photos.uploadProfilePhoto', {
|
||||
apiManager.invokeApi('photos.uploadProfilePhoto', {
|
||||
file: inputFile
|
||||
}).then(function (updateResult) {
|
||||
console.log('updated photo!');
|
||||
@ -137,10 +137,10 @@ export default (_authCode: typeof authCode) => {
|
||||
|
||||
console.log('invoking uploadFile...');
|
||||
// @ts-ignore
|
||||
MTProto.apiFileManager.uploadFile(avatarBlob).then((inputFile: any) => {
|
||||
apiFileManager.uploadFile(avatarBlob).then((inputFile: any) => {
|
||||
console.log('uploaded smthn', inputFile);
|
||||
|
||||
MTProto.apiManager.invokeApi('photos.uploadProfilePhoto', {
|
||||
apiManager.invokeApi('photos.uploadProfilePhoto', {
|
||||
file: inputFile
|
||||
}).then((updateResult) => {
|
||||
console.log('updated photo!');
|
||||
@ -179,13 +179,13 @@ export default (_authCode: typeof authCode) => {
|
||||
this.textContent = 'PLEASE WAIT...';
|
||||
putPreloader(this);
|
||||
|
||||
MTProto.apiManager.invokeApi('auth.signUp', params)
|
||||
apiManager.invokeApi('auth.signUp', params)
|
||||
.then((response: any) => {
|
||||
console.log('auth.signUp response:', response);
|
||||
|
||||
switch(response._) {
|
||||
case 'auth.authorization': // success
|
||||
MTProto.apiManager.setUserAuth({ // warning
|
||||
apiManager.setUserAuth({ // warning
|
||||
id: response.user.id
|
||||
});
|
||||
|
||||
|
@ -129,7 +129,7 @@ export default class Scrollable {
|
||||
//console.log('onresize', thumb.style[type], thumbHeight, height);
|
||||
}
|
||||
|
||||
public setVirtualContainer(el: HTMLElement) {
|
||||
public setVirtualContainer(el?: HTMLElement) {
|
||||
this.splitUp = el;
|
||||
|
||||
this.hiddenElements.up.length = this.hiddenElements.down.length = 0;
|
||||
@ -143,8 +143,10 @@ export default class Scrollable {
|
||||
//this.topObserver.observe(this.paddingTopDiv);
|
||||
//this.bottomObserver.observe(this.paddingBottomDiv);
|
||||
|
||||
el.parentElement.insertBefore(this.paddingTopDiv, el);
|
||||
el.parentNode.insertBefore(this.paddingBottomDiv, el.nextSibling);
|
||||
if(el) {
|
||||
el.parentElement.insertBefore(this.paddingTopDiv, el);
|
||||
el.parentNode.insertBefore(this.paddingBottomDiv, el.nextSibling);
|
||||
}
|
||||
}
|
||||
|
||||
public onScroll() {
|
||||
|
@ -8,6 +8,7 @@ import { formatBytes } from "../lib/utils";
|
||||
import ProgressivePreloader from './preloader';
|
||||
import LazyLoadQueue from './lazyLoadQueue';
|
||||
import apiFileManager from '../lib/mtproto/apiFileManager';
|
||||
import appWebpManager from '../lib/appManagers/appWebpManager';
|
||||
|
||||
export type MTDocument = {
|
||||
_: 'document',
|
||||
@ -224,7 +225,7 @@ export function wrapSticker(doc: MTDocument, div: HTMLDivElement, middleware?: (
|
||||
console.error('wrong doc for wrapSticker!', doc, div);
|
||||
}
|
||||
|
||||
//console.log('wrap sticker', doc);
|
||||
console.log('wrap sticker', doc);
|
||||
|
||||
if(doc.thumbs && !div.firstElementChild) {
|
||||
let thumb = doc.thumbs[0];
|
||||
@ -308,7 +309,10 @@ export function wrapSticker(doc: MTDocument, div: HTMLDivElement, middleware?: (
|
||||
reader.readAsArrayBuffer(blob);
|
||||
} else if(stickerType == 1) {
|
||||
let img = new Image();
|
||||
img.src = URL.createObjectURL(blob);
|
||||
|
||||
appWebpManager.polyfillImage(img, blob);
|
||||
|
||||
//img.src = URL.createObjectURL(blob);
|
||||
|
||||
/* div.style.height = doc.h + 'px';
|
||||
div.style.width = doc.w + 'px'; */
|
||||
|
@ -25,6 +25,7 @@ export class AppDialogsManager {
|
||||
public chatListArchived = document.getElementById('dialogs-archived') as HTMLUListElement;
|
||||
public pinnedDelimiter: HTMLDivElement;
|
||||
public chatsHidden: any;
|
||||
public chatsArchivedHidden: any;
|
||||
|
||||
public myID = 0;
|
||||
public doms: {[peerID: number]: DialogDom} = {};
|
||||
@ -48,6 +49,7 @@ export class AppDialogsManager {
|
||||
//let chatClosedDiv = document.getElementById('chat-closed');
|
||||
|
||||
this.setListClickListener(this.chatList);
|
||||
this.setListClickListener(this.chatListArchived);
|
||||
}
|
||||
|
||||
public setListClickListener(list: HTMLUListElement, onFound?: () => void) {
|
||||
@ -152,46 +154,58 @@ export class AppDialogsManager {
|
||||
public sortDom(archived = false) {
|
||||
//return;
|
||||
|
||||
let dialogs = appMessagesManager.dialogsStorage.dialogs;
|
||||
let dialogs = appMessagesManager.dialogsStorage.dialogs.slice();
|
||||
|
||||
let inUpper: HTMLLIElement[] = [];
|
||||
let inBottom: HTMLLIElement[] = [];
|
||||
|
||||
let pinnedDialogs = [];
|
||||
for(let i = 0; i < dialogs.length; ++i) {
|
||||
let dialog = dialogs[i];
|
||||
if(!dialog.pFlags.pinned) break;
|
||||
pinnedDialogs.push(dialog);
|
||||
}
|
||||
|
||||
if(pinnedDialogs.length) {
|
||||
let dom = this.getDialogDom(pinnedDialogs[pinnedDialogs.length - 1].peerID);
|
||||
if(dom) {
|
||||
dom.listEl.append(this.pinnedDelimiter);
|
||||
let sorted = dialogs;
|
||||
|
||||
if(!archived) {
|
||||
for(let i = 0; i < dialogs.length; ++i) {
|
||||
let dialog = dialogs[i];
|
||||
if(!dialog.pFlags.pinned) break;
|
||||
pinnedDialogs.push(dialog);
|
||||
}
|
||||
|
||||
if(pinnedDialogs.length) {
|
||||
let dom = this.getDialogDom(pinnedDialogs[pinnedDialogs.length - 1].peerID);
|
||||
if(dom) {
|
||||
dom.listEl.append(this.pinnedDelimiter);
|
||||
}
|
||||
} else {
|
||||
if(this.pinnedDelimiter.parentElement) {
|
||||
this.pinnedDelimiter.parentElement.removeChild(this.pinnedDelimiter);
|
||||
}
|
||||
}
|
||||
|
||||
sorted = sorted.filter((d: any) => !d.pFlags.pinned && d.folder_id != 1);
|
||||
} else {
|
||||
if(this.pinnedDelimiter.parentElement) {
|
||||
this.pinnedDelimiter.parentElement.removeChild(this.pinnedDelimiter);
|
||||
}
|
||||
sorted = sorted.filter((d: any) => d.folder_id == 1);
|
||||
}
|
||||
|
||||
let sorted = dialogs
|
||||
.filter((d: any) => !d.pFlags.pinned)
|
||||
.sort((a: any, b: any) => {
|
||||
sorted = sorted.sort((a: any, b: any) => {
|
||||
let timeA = appMessagesManager.getMessage(a.top_message).date;
|
||||
let timeB = appMessagesManager.getMessage(b.top_message).date;
|
||||
|
||||
return timeB - timeA;
|
||||
});
|
||||
|
||||
sorted = pinnedDialogs.concat(sorted);
|
||||
if(!archived) {
|
||||
sorted = pinnedDialogs.concat(sorted);
|
||||
}
|
||||
|
||||
//console.log('sortDom', sorted, this.chatsHidden, this.chatsHidden.up, this.chatsHidden.down);
|
||||
|
||||
let hiddenLength: number = this.chatsHidden.up.length;
|
||||
let inViewportLength = this.chatList.childElementCount;
|
||||
let chatList = archived ? this.chatListArchived : this.chatList;
|
||||
let chatsHidden = archived ? this.chatsArchivedHidden : this.chatsHidden;
|
||||
|
||||
this.chatList.innerHTML = '';
|
||||
let hiddenLength: number = chatsHidden.up.length;
|
||||
let inViewportLength = chatList.childElementCount;
|
||||
|
||||
chatList.innerHTML = '';
|
||||
|
||||
let inViewportIndex = 0;
|
||||
sorted.forEach((d: any, idx) => {
|
||||
@ -221,10 +235,10 @@ export class AppDialogsManager {
|
||||
//this.chatList.append(dom.listEl);
|
||||
});
|
||||
|
||||
console.log('sortDom', sorted.length, inUpper.length, this.chatList.childElementCount, inBottom.length);
|
||||
console.log('sortDom', sorted.length, inUpper.length, chatList.childElementCount, inBottom.length);
|
||||
|
||||
this.chatsHidden.up = inUpper;
|
||||
this.chatsHidden.down = inBottom;
|
||||
chatsHidden.up = inUpper;
|
||||
chatsHidden.down = inBottom;
|
||||
}
|
||||
|
||||
public setLastMessage(dialog: any, lastMessage?: any, dom?: DialogDom) {
|
||||
@ -398,7 +412,7 @@ export class AppDialogsManager {
|
||||
}, container?: HTMLUListElement, drawStatus = true) {
|
||||
let peerID: number = dialog.peerID;
|
||||
|
||||
if((peerID in this.doms) && !container) return;
|
||||
if((this.doms[peerID] || this.domsArchived[peerID]) && !container) return;
|
||||
|
||||
let title = appPeersManager.getPeerTitle(peerID);
|
||||
|
||||
@ -497,7 +511,7 @@ export class AppDialogsManager {
|
||||
};
|
||||
|
||||
if(!container) {
|
||||
if(dialog.folder_id) {
|
||||
if(dialog.folder_id && dialog.folder_id == 1) {
|
||||
this.chatListArchived.append(li);
|
||||
this.domsArchived[dialog.peerID] = dom;
|
||||
} else {
|
||||
|
@ -931,6 +931,8 @@ export class AppImManager {
|
||||
if(item) {
|
||||
this.loadingMedia++;
|
||||
|
||||
let peerID = this.peerID;
|
||||
|
||||
let promise = item();
|
||||
try {
|
||||
await promise;
|
||||
@ -938,7 +940,9 @@ export class AppImManager {
|
||||
this.log.error('loadMediaQueue error:', err);
|
||||
}
|
||||
|
||||
this.loadingMedia--;
|
||||
if(peerID == this.peerID) {
|
||||
this.loadingMedia--;
|
||||
}
|
||||
}
|
||||
|
||||
if(this.loadMediaQueue.length) return this.loadMediaQueueProcess();
|
||||
@ -1179,6 +1183,7 @@ export class AppImManager {
|
||||
this.unreaded = [];
|
||||
this.unreadOut = [];
|
||||
this.loadMediaQueue = [];
|
||||
this.loadingMedia = 0;
|
||||
|
||||
lottieLoader.checkAnimations(false, 'chat', true);
|
||||
|
||||
|
@ -60,7 +60,7 @@ export class AppMessagesManager {
|
||||
|
||||
public maxSeenID = 0;
|
||||
|
||||
public allDialogsLoaded = false;
|
||||
public allDialogsLoaded: {[folder_id: number]: boolean} = {};
|
||||
public dialogsOffsetDate = 0;
|
||||
public pinnedIndex = 0;
|
||||
public dialogsNum = 0;
|
||||
@ -705,11 +705,18 @@ export class AppMessagesManager {
|
||||
};
|
||||
}
|
||||
|
||||
public getConversations(query?: string, offsetIndex?: number, limit = 20) {
|
||||
var curDialogStorage = this.dialogsStorage;
|
||||
var isSearch = typeof(query) == 'string' && query.length;
|
||||
public getConversations(query?: string, offsetIndex?: number, limit = 20, folderID = -1) {
|
||||
//var curDialogStorage = this.dialogsStorage;
|
||||
//var isSearch = typeof(query) == 'string' && query.length;
|
||||
let curDialogStorage = this.dialogsStorage.dialogs;
|
||||
|
||||
if(isSearch) {
|
||||
if(folderID > 0) {
|
||||
curDialogStorage = curDialogStorage.filter(d => d.folder_id == folderID);
|
||||
} else {
|
||||
curDialogStorage = curDialogStorage.filter(d => d.folder_id != 1);
|
||||
}
|
||||
|
||||
/* if(isSearch) {
|
||||
if(!limit || this.cachedResults.query !== query) {
|
||||
this.cachedResults.query = query;
|
||||
|
||||
@ -724,30 +731,38 @@ export class AppMessagesManager {
|
||||
this.cachedResults.count = this.cachedResults.dialogs.length;
|
||||
}
|
||||
curDialogStorage = this.cachedResults;
|
||||
} else {
|
||||
} else { */
|
||||
this.cachedResults.query = false;
|
||||
}
|
||||
//}
|
||||
|
||||
var offset = 0
|
||||
var offset = 0;
|
||||
if(offsetIndex > 0) {
|
||||
for(offset = 0; offset < curDialogStorage.dialogs.length; offset++) {
|
||||
if(offsetIndex > curDialogStorage.dialogs[offset].index) {
|
||||
for(; offset < curDialogStorage.length; offset++) {
|
||||
if(offsetIndex > curDialogStorage[offset].index) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(isSearch || this.allDialogsLoaded || curDialogStorage.dialogs.length >= offset + limit) {
|
||||
if(/* isSearch || */this.allDialogsLoaded[folderID] || curDialogStorage.length >= offset + limit) {
|
||||
return Promise.resolve({
|
||||
dialogs: curDialogStorage.dialogs.slice(offset, offset + limit)
|
||||
dialogs: curDialogStorage.slice(offset, offset + limit)
|
||||
});
|
||||
}
|
||||
|
||||
return this.getTopMessages(limit).then(() => {
|
||||
offset = 0
|
||||
return this.getTopMessages(limit, folderID).then(() => {
|
||||
let curDialogStorage = this.dialogsStorage.dialogs;
|
||||
|
||||
if(folderID > 0) {
|
||||
curDialogStorage = curDialogStorage.filter(d => d.folder_id == folderID);
|
||||
} else {
|
||||
curDialogStorage = curDialogStorage.filter(d => d.folder_id != 1);
|
||||
}
|
||||
|
||||
offset = 0;
|
||||
if(offsetIndex > 0) {
|
||||
for(offset = 0; offset < curDialogStorage.dialogs.length; offset++) {
|
||||
if(offsetIndex > curDialogStorage.dialogs[offset].index) {
|
||||
for(offset = 0; offset < curDialogStorage.length; offset++) {
|
||||
if(offsetIndex > curDialogStorage[offset].index) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -756,12 +771,12 @@ export class AppMessagesManager {
|
||||
//console.warn(offset, offset + limit, curDialogStorage.dialogs.length, this.dialogsStorage.dialogs.length);
|
||||
|
||||
return {
|
||||
dialogs: curDialogStorage.dialogs.slice(offset, offset + limit)
|
||||
dialogs: curDialogStorage.slice(offset, offset + limit)
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
public getTopMessages(limit: number) {
|
||||
public getTopMessages(limit: number, folderID = -1) {
|
||||
var dialogs = this.dialogsStorage.dialogs;
|
||||
var offsetDate = 0;
|
||||
var offsetID = 0;
|
||||
@ -775,12 +790,16 @@ export class AppMessagesManager {
|
||||
flags |= 1;
|
||||
}
|
||||
|
||||
if(folderID > 0) {
|
||||
flags |= 1;
|
||||
flags |= 2;
|
||||
}
|
||||
|
||||
let hash = 0;
|
||||
/* let id = 296814355;
|
||||
hash = (((hash * 0x4F25) & 0x7FFFFFFF) + id) & 0x7FFFFFFF; */
|
||||
|
||||
return apiManager.invokeApi('messages.getDialogs', {
|
||||
flags: flags,
|
||||
folder_id: folderID,
|
||||
offset_date: offsetDate,
|
||||
offset_id: appMessagesIDsManager.getMessageLocalID(offsetID),
|
||||
offset_peer: AppPeersManager.getInputPeerByID(offsetPeerID),
|
||||
@ -789,6 +808,8 @@ export class AppMessagesManager {
|
||||
}, {
|
||||
timeout: 300
|
||||
}).then((dialogsResult: any) => {
|
||||
console.log('messages.getDialogs result:', dialogsResult);
|
||||
|
||||
if(!offsetDate) {
|
||||
telegramMeWebService.setAuthorized(true);
|
||||
}
|
||||
@ -841,7 +862,7 @@ export class AppMessagesManager {
|
||||
if(!dialogsResult.dialogs.length ||
|
||||
!dialogsResult.count ||
|
||||
dialogs.length >= dialogsResult.count) {
|
||||
this.allDialogsLoaded = true;
|
||||
this.allDialogsLoaded[folderID] = true;
|
||||
}
|
||||
|
||||
if(hasPrepend && !this.newDialogsHandlePromise) {
|
||||
@ -1313,6 +1334,7 @@ export class AppMessagesManager {
|
||||
|
||||
dialog.index = this.generateDialogIndex(topDate);
|
||||
dialog.peerID = peerID;
|
||||
if(!dialog.folder_id) dialog.folder_id = 0;
|
||||
|
||||
this.pushDialogToStorage(dialog, offsetDate);
|
||||
|
||||
|
@ -52,6 +52,7 @@ class AppSidebarLeft {
|
||||
|
||||
private chatsArchivedContainer = document.getElementById('chats-archived-container') as HTMLDivElement;
|
||||
private chatsContainer = document.getElementById('chats-container') as HTMLDivElement;
|
||||
private chatsArchivedOffsetIndex = 0;
|
||||
private chatsOffsetIndex = 0;
|
||||
private chatsPreloader: HTMLDivElement;
|
||||
private chatsLoadCount = 0;
|
||||
@ -71,6 +72,7 @@ class AppSidebarLeft {
|
||||
private query = '';
|
||||
|
||||
public scroll: Scrollable = null;
|
||||
public scrollArchived: Scrollable = null;
|
||||
|
||||
public searchGroups: {[group: string]: SearchGroup} = {
|
||||
contacts: new SearchGroup('Contacts and Chats', 'contacts'),
|
||||
@ -90,11 +92,14 @@ class AppSidebarLeft {
|
||||
this.scroll = new Scrollable(this.chatsContainer as HTMLDivElement);
|
||||
this.scroll.setVirtualContainer(appDialogsManager.chatList);
|
||||
appDialogsManager.chatsHidden = this.scroll.hiddenElements;
|
||||
|
||||
this.scroll.container.addEventListener('scroll', this.onChatsScroll.bind(this));
|
||||
|
||||
this.scrollArchived = new Scrollable(this.chatsArchivedContainer as HTMLDivElement);
|
||||
this.scrollArchived.setVirtualContainer(appDialogsManager.chatListArchived);
|
||||
appDialogsManager.chatsArchivedHidden = this.scrollArchived.hiddenElements;
|
||||
this.scroll.container.addEventListener('scroll', this.onChatsArchivedScroll.bind(this));
|
||||
|
||||
this.listsContainer = new Scrollable(this.searchContainer).container;
|
||||
|
||||
for(let i in this.searchGroups) {
|
||||
this.listsContainer.append(this.searchGroups[i].container);
|
||||
}
|
||||
@ -200,7 +205,9 @@ class AppSidebarLeft {
|
||||
|
||||
setTimeout(() => {
|
||||
this.onSidebarScroll();
|
||||
this.scroll.onScroll();
|
||||
this.onChatsScroll();
|
||||
this.onChatsArchivedScroll();
|
||||
}, 0);
|
||||
});
|
||||
|
||||
@ -209,26 +216,34 @@ class AppSidebarLeft {
|
||||
}); */
|
||||
}
|
||||
|
||||
public async loadDialogs() {
|
||||
public async loadDialogs(archived = false) {
|
||||
if(this.loadDialogsPromise/* || 1 == 1 */) return this.loadDialogsPromise;
|
||||
|
||||
this.chatsContainer.append(this.chatsPreloader);
|
||||
(archived ? this.chatsArchivedContainer : this.chatsContainer).append(this.chatsPreloader);
|
||||
|
||||
//let offset = appMessagesManager.generateDialogIndex();/* appMessagesManager.dialogsNum */;
|
||||
|
||||
let offset = archived ? this.chatsArchivedOffsetIndex : this.chatsOffsetIndex;
|
||||
//let offset = 0;
|
||||
|
||||
|
||||
try {
|
||||
this.loadDialogsPromise = appMessagesManager.getConversations('', this.chatsOffsetIndex, this.chatsLoadCount);
|
||||
this.loadDialogsPromise = appMessagesManager.getConversations('', offset, this.chatsLoadCount, +archived);
|
||||
|
||||
let result = await this.loadDialogsPromise;
|
||||
|
||||
if(result && result.dialogs && result.dialogs.length) {
|
||||
this.chatsOffsetIndex = result.dialogs[result.dialogs.length - 1].index;
|
||||
let index = result.dialogs[result.dialogs.length - 1].index;
|
||||
|
||||
if(archived) this.chatsArchivedOffsetIndex = index;
|
||||
else this.chatsOffsetIndex = index;
|
||||
|
||||
result.dialogs.forEach((dialog: any) => {
|
||||
appDialogsManager.addDialog(dialog);
|
||||
});
|
||||
}
|
||||
|
||||
this.log('loaded ' + this.chatsLoadCount + ' dialogs by offset:', this.chatsOffsetIndex, result, this.scroll.hiddenElements);
|
||||
this.log('loaded ' + this.chatsLoadCount + ' dialogs by offset:', offset, result, this.scroll.hiddenElements);
|
||||
this.scroll.onScroll();
|
||||
} catch(err) {
|
||||
this.log.error(err);
|
||||
@ -239,7 +254,7 @@ class AppSidebarLeft {
|
||||
}
|
||||
|
||||
public onChatsScroll() {
|
||||
//this.log(this.scroll);
|
||||
//this.log(this.scroll.hiddenElements.down.length, this.loadDialogsPromise, appDialogsManager.chatList.childNodes);
|
||||
if(this.scroll.hiddenElements.down.length > 0/* || 1 == 1 */) return;
|
||||
|
||||
if(!this.loadDialogsPromise) {
|
||||
@ -254,6 +269,23 @@ class AppSidebarLeft {
|
||||
//console.log('last 5 dialogs:', d);
|
||||
}
|
||||
}
|
||||
|
||||
public onChatsArchivedScroll() {
|
||||
//this.log(this.scrollArchived.hiddenElements.down.length, this.loadDialogsPromise, appDialogsManager.chatListArchived.childNodes);
|
||||
if(this.scrollArchived.hiddenElements.down.length > 0/* || 1 == 1 */) return;
|
||||
|
||||
if(!this.loadDialogsPromise) {
|
||||
let d = Array.from(appDialogsManager.chatListArchived.childNodes).slice(-5);
|
||||
for(let node of d) {
|
||||
if(isElementInViewport(node)) {
|
||||
this.loadDialogs(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//console.log('last 5 dialogs:', d);
|
||||
}
|
||||
}
|
||||
|
||||
public onSidebarScroll() {
|
||||
if(!this.query.trim()) return;
|
||||
@ -339,7 +371,7 @@ class AppSidebarLeft {
|
||||
} else {
|
||||
username = '@' + username;
|
||||
}
|
||||
|
||||
|
||||
dom.lastMessageSpan.innerText = username;
|
||||
}
|
||||
});
|
||||
|
@ -53,7 +53,7 @@ class AppSidebarRight {
|
||||
public sharedMediaType: string = '';
|
||||
private sharedMediaSelected: HTMLDivElement = null;
|
||||
|
||||
private lazyLoadQueueSidebar = new LazyLoadQueue();
|
||||
private lazyLoadQueueSidebar = new LazyLoadQueue(5);
|
||||
/* public minMediaID: {
|
||||
[type: string]: number
|
||||
} = {}; */
|
||||
@ -144,7 +144,10 @@ class AppSidebarRight {
|
||||
});
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
setTimeout(() => this.onSidebarScroll(), 0);
|
||||
setTimeout(() => {
|
||||
this.sidebarScroll.onScroll();
|
||||
this.onSidebarScroll();
|
||||
}, 0);
|
||||
});
|
||||
}
|
||||
|
||||
@ -334,6 +337,7 @@ class AppSidebarRight {
|
||||
|
||||
this.savedVirtualStates = {};
|
||||
this.prevTabID = -1;
|
||||
this.sidebarScroll.setVirtualContainer(null);
|
||||
(this.profileTabs.children[1] as HTMLLIElement).click(); // set media
|
||||
|
||||
if(this.sharedMediaSelected) {
|
||||
@ -348,6 +352,8 @@ class AppSidebarRight {
|
||||
this.profileElements.notificationsCheckbox.checked = true;
|
||||
this.profileElements.notificationsStatus.innerText = 'Enabled';
|
||||
|
||||
this.lazyLoadQueueSidebar.clear();
|
||||
|
||||
Object.keys(this.sharedMedia).forEach(key => {
|
||||
this.sharedMedia[key].innerHTML = '';
|
||||
});
|
||||
|
72
src/lib/appManagers/appWebpManager.ts
Normal file
72
src/lib/appManagers/appWebpManager.ts
Normal file
@ -0,0 +1,72 @@
|
||||
class AppWebpManager {
|
||||
public webpMachine: any = null;
|
||||
public loaded: Promise<void>;
|
||||
public busyPromise: Promise<string>;
|
||||
public queue: {bytes: Uint8Array, img: HTMLImageElement}[] = [];
|
||||
|
||||
constructor() {
|
||||
this.loaded = new Promise((resolve, reject) => {
|
||||
(window as any).webpLoaded = () => {
|
||||
console.log('webpHero loaded');
|
||||
this.webpMachine = new (window as any).webpHero.WebpMachine();
|
||||
this.webpMachine.webp.Module.doNotCaptureKeyboard = true;
|
||||
//this.webpMachine.polyfillDocument();
|
||||
resolve();
|
||||
};
|
||||
|
||||
let sc = document.createElement('script');
|
||||
sc.src = 'webp-hero.bundle.js';
|
||||
sc.async = true;
|
||||
sc.onload = (window as any).webpLoaded;
|
||||
/* sc.innerHTML = `
|
||||
window.webpMachine = new webpHero.WebpMachine();
|
||||
window.webpMachine.polyfillDocument();
|
||||
`; */
|
||||
|
||||
document.body.appendChild(sc);
|
||||
});
|
||||
}
|
||||
|
||||
convert(bytes: Uint8Array): Promise<string> {
|
||||
return this.webpMachine.decode(bytes);
|
||||
}
|
||||
|
||||
async processQueue() {
|
||||
if(this.busyPromise) return;
|
||||
|
||||
let {img, bytes} = this.queue.pop();
|
||||
|
||||
await this.loaded;
|
||||
|
||||
this.busyPromise = this.convert(bytes);
|
||||
img.src = await this.busyPromise;
|
||||
|
||||
this.busyPromise = null;
|
||||
|
||||
if(this.queue.length) {
|
||||
this.processQueue();
|
||||
}
|
||||
}
|
||||
|
||||
async polyfillImage(img: HTMLImageElement, blob: Blob) {
|
||||
/* console.log('polyfillImage', this);
|
||||
return this.webpMachine.polyfillImage(image); */
|
||||
|
||||
if(await this.webpMachine.webpSupport) {
|
||||
img.src = URL.createObjectURL(blob);
|
||||
return;
|
||||
}
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.addEventListener('loadend', async(e) => {
|
||||
// @ts-ignore
|
||||
let bytes = new Uint8Array(e.srcElement.result);
|
||||
|
||||
this.queue.push({bytes, img});
|
||||
this.processQueue();
|
||||
});
|
||||
reader.readAsArrayBuffer(blob);
|
||||
}
|
||||
}
|
||||
|
||||
export default new AppWebpManager();
|
@ -218,7 +218,9 @@ export class ApiFileManager {
|
||||
});
|
||||
}, dcID);
|
||||
|
||||
var processDownloaded = function(bytes: any) {
|
||||
var processDownloaded = (bytes: Uint8Array) => {
|
||||
//this.log('processDownloaded', location, bytes);
|
||||
|
||||
return Promise.resolve(bytes);
|
||||
/* if(!location.sticker || WebpManager.isWebpSupported()) {
|
||||
return qSync.when(bytes);
|
||||
|
@ -190,11 +190,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
.emoji {
|
||||
img.emoji {
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
margin: 0 .05rem;
|
||||
}
|
||||
|
||||
span.emoji {
|
||||
height: auto;
|
||||
width: auto;
|
||||
overflow: visible;
|
||||
vertical-align: unset;
|
||||
}
|
||||
|
||||
&.emoji-big {
|
||||
font-size: 0;
|
||||
@ -915,12 +922,16 @@
|
||||
color: #111;
|
||||
}
|
||||
|
||||
.emoji {
|
||||
font-size: 16px;
|
||||
img.emoji {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
span.emoji {
|
||||
font-size: 16px;
|
||||
vertical-align: unset;
|
||||
}
|
||||
}
|
||||
|
||||
/* #chat-closed {
|
||||
|
@ -43,8 +43,10 @@
|
||||
ul {
|
||||
margin: 0;
|
||||
//padding: 0 .5rem;
|
||||
display: grid;
|
||||
grid-auto-columns: 1fr;
|
||||
/* display: grid;
|
||||
grid-auto-columns: 1fr; */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
/* grid-gap: 4px; */
|
||||
width: 100%;
|
||||
}
|
||||
|
@ -1249,6 +1249,11 @@ div.scrollable::-webkit-scrollbar-thumb {
|
||||
opacity: .4;
|
||||
}
|
||||
|
||||
[contenteditable] {
|
||||
-webkit-user-select: text;
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
.menu-horizontal {
|
||||
width: 100%;
|
||||
color: $darkgrey;
|
||||
|
1
webp-hero.bundle.js
Normal file
1
webp-hero.bundle.js
Normal file
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user