Browse Source

webp polyfill & archived dialogs & improved lazy load

master
Eduard Kuzmenko 5 years ago
parent
commit
d93613b6f2
  1. BIN
      .DS_Store
  2. 2
      src/components/emoticonsDropdown.ts
  3. 105
      src/components/lazyLoadQueue.ts
  4. 9
      src/components/pageAuthCode.ts
  5. 7
      src/components/pageIm.ts
  6. 10
      src/components/pagePassword.ts
  7. 14
      src/components/pageSignUp.ts
  8. 8
      src/components/scrollable.ts
  9. 8
      src/components/wrappers.ts
  10. 64
      src/lib/appManagers/appDialogsManager.ts
  11. 7
      src/lib/appManagers/appImManager.ts
  12. 64
      src/lib/appManagers/appMessagesManager.ts
  13. 50
      src/lib/appManagers/appSidebarLeft.ts
  14. 10
      src/lib/appManagers/appSidebarRight.ts
  15. 72
      src/lib/appManagers/appWebpManager.ts
  16. 4
      src/lib/mtproto/apiFileManager.ts
  17. 17
      src/scss/partials/_chat.scss
  18. 6
      src/scss/partials/_chatlist.scss
  19. 5
      src/scss/style.scss
  20. 1
      webp-hero.bundle.js

BIN
.DS_Store vendored

Binary file not shown.

2
src/components/emoticonsDropdown.ts

@ -19,7 +19,7 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement, @@ -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;

105
src/components/lazyLoadQueue.ts

@ -1,10 +1,85 @@ @@ -1,10 +1,85 @@
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;
/* if(id !== undefined) {
let {div, load} = this.lazyLoadMedia[id];
if(isElementInViewport(div)) {
//console.log('will load div by id:', div, div.getBoundingClientRect());
load();
this.lazyLoadMedia.splice(id, 1);
}
return;
}
let length = this.lazyLoadMedia.length;
for(let i = length - 1; i >= 0; --i) {
let {div, load} = this.lazyLoadMedia[i];
@ -14,18 +89,31 @@ export default class LazyLoadQueue { @@ -14,18 +89,31 @@ export default class LazyLoadQueue {
this.lazyLoadMedia.splice(i, 1);
}
} */
if(id !== undefined) {
let {div, load} = this.lazyLoadMedia[id];
let {div} = this.lazyLoadMedia[id];
if(isElementInViewport(div)) {
//console.log('will load div by id:', div, div.getBoundingClientRect());
load();
this.lazyLoadMedia.splice(id, 1);
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 { @@ -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);

9
src/components/pageAuthCode.ts

@ -1,11 +1,10 @@ @@ -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) => { @@ -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) => { @@ -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
src/components/pageIm.ts

@ -7,7 +7,10 @@ import lottieLoader from "../lib/lottieLoader"; @@ -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 => { @@ -193,5 +196,7 @@ export default () => import('../lib/services').then(services => {
appSidebarLeft.loadDialogs().then(result => {
appSidebarLeft.onChatsScroll();
appImManager.setScroll(chatScroll);
appSidebarLeft.loadDialogs(true);
});
});

10
src/components/pagePassword.ts

@ -1,10 +1,10 @@ @@ -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() => { @@ -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
});

14
src/components/pageSignUp.ts

@ -1,4 +1,3 @@ @@ -1,4 +1,3 @@
import {MTProto} from '../lib/mtproto/mtproto';
import {putPreloader} from './misc';
let installed = false;
@ -9,6 +8,7 @@ let authCode: { @@ -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) => { @@ -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) => { @@ -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) => { @@ -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
});

8
src/components/scrollable.ts

@ -129,7 +129,7 @@ export default class Scrollable { @@ -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 { @@ -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
src/components/wrappers.ts

@ -8,6 +8,7 @@ import { formatBytes } from "../lib/utils"; @@ -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?: ( @@ -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?: ( @@ -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'; */

64
src/lib/appManagers/appDialogsManager.ts

@ -25,6 +25,7 @@ export class AppDialogsManager { @@ -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 { @@ -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 { @@ -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);
}
} else {
if(this.pinnedDelimiter.parentElement) {
this.pinnedDelimiter.parentElement.removeChild(this.pinnedDelimiter);
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 {
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;
let hiddenLength: number = chatsHidden.up.length;
let inViewportLength = chatList.childElementCount;
this.chatList.innerHTML = '';
chatList.innerHTML = '';
let inViewportIndex = 0;
sorted.forEach((d: any, idx) => {
@ -221,10 +235,10 @@ export class AppDialogsManager { @@ -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 { @@ -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 { @@ -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 {

7
src/lib/appManagers/appImManager.ts

@ -931,6 +931,8 @@ export class AppImManager { @@ -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 { @@ -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 { @@ -1179,6 +1183,7 @@ export class AppImManager {
this.unreaded = [];
this.unreadOut = [];
this.loadMediaQueue = [];
this.loadingMedia = 0;
lottieLoader.checkAnimations(false, 'chat', true);

64
src/lib/appManagers/appMessagesManager.ts

@ -60,7 +60,7 @@ export class AppMessagesManager { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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);

50
src/lib/appManagers/appSidebarLeft.ts

@ -52,6 +52,7 @@ class AppSidebarLeft { @@ -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 { @@ -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 { @@ -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 { @@ -200,7 +205,9 @@ class AppSidebarLeft {
setTimeout(() => {
this.onSidebarScroll();
this.scroll.onScroll();
this.onChatsScroll();
this.onChatsArchivedScroll();
}, 0);
});
@ -209,26 +216,34 @@ class AppSidebarLeft { @@ -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 { @@ -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 { @@ -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 { @@ -339,7 +371,7 @@ class AppSidebarLeft {
} else {
username = '@' + username;
}
dom.lastMessageSpan.innerText = username;
}
});

10
src/lib/appManagers/appSidebarRight.ts

@ -53,7 +53,7 @@ class AppSidebarRight { @@ -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 { @@ -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 { @@ -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 { @@ -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

@ -0,0 +1,72 @@ @@ -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();

4
src/lib/mtproto/apiFileManager.ts

@ -218,7 +218,9 @@ export class ApiFileManager { @@ -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);

17
src/scss/partials/_chat.scss

@ -190,11 +190,18 @@ @@ -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 @@ @@ -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 {

6
src/scss/partials/_chatlist.scss

@ -43,8 +43,10 @@ @@ -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%;
}

5
src/scss/style.scss

@ -1249,6 +1249,11 @@ div.scrollable::-webkit-scrollbar-thumb { @@ -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

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save