Browse Source

New (not) virtual chatlist & chat slicer & prepare to fix dialogs sort

master
morethanwords 4 years ago
parent
commit
0bc57d8ea0
  1. 12
      package-lock.json
  2. 7
      package.json
  3. 6
      src/components/appSearch.ts
  4. 2
      src/components/chatInput.ts
  5. 33
      src/components/emoticonsDropdown.ts
  6. 425
      src/components/scrollable_new.ts
  7. 78
      src/lib/appManagers/appDialogsManager.ts
  8. 2
      src/lib/appManagers/appDocsManager.ts
  9. 261
      src/lib/appManagers/appImManager.ts
  10. 75
      src/lib/appManagers/appMessagesManager.ts
  11. 2
      src/lib/appManagers/appPhotosManager.ts
  12. 30
      src/lib/appManagers/appSidebarRight.ts
  13. 29
      src/lib/bin_utils.ts
  14. 12
      src/lib/crypto/crypto_utils.ts
  15. 7
      src/lib/crypto/cryptoworker.ts
  16. 42
      src/lib/mtproto/apiManager.ts
  17. 3
      src/lib/mtproto/authorizer.ts
  18. 3
      src/lib/mtproto/mtproto.ts
  19. 3
      src/lib/mtproto/mtprotoworker.ts
  20. 14
      src/lib/mtproto/networker.ts
  21. 5
      src/lib/mtproto/timeManager.ts
  22. 11
      src/lib/mtproto/tl_utils.ts
  23. 4
      src/lib/utils.js
  24. 2
      src/pages/pageSignIn.ts
  25. 6
      src/scss/partials/_chat.scss
  26. 10
      src/scss/partials/_emojiDropdown.scss
  27. 49
      src/scss/partials/_scrollable.scss
  28. 27952
      stats.json

12
package-lock.json generated

@ -11123,12 +11123,6 @@ @@ -11123,12 +11123,6 @@
"resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz",
"integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg=="
},
"offscreen-canvas": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/offscreen-canvas/-/offscreen-canvas-0.1.1.tgz",
"integrity": "sha512-gZYQ++TK0X9BD6bnMrgk7TGQ0TCVLP5YsCOnLaCP18WpKh3dYfkt0ma4gFhElohBizSwMzjDptam2zPxMUQ2wg==",
"dev": true
},
"on-build-webpack": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/on-build-webpack/-/on-build-webpack-0.1.0.tgz",
@ -11224,12 +11218,6 @@ @@ -11224,12 +11218,6 @@
"os-tmpdir": "^1.0.0"
}
},
"overlayscrollbars": {
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/overlayscrollbars/-/overlayscrollbars-1.12.0.tgz",
"integrity": "sha512-zJGYLeBfaPx2VmiDfBMNTPzm9N8w8wZ6M7dm1ee8TGuet8tsK4nxOzGvEEu0SmueqMHQxhLsstf7iTWCGiYa9Q==",
"dev": true
},
"p-defer": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz",

7
package.json

@ -6,10 +6,11 @@ @@ -6,10 +6,11 @@
"scripts": {
"start": "webpack-dev-server --open --config webpack.dev.js",
"start-production": "webpack-dev-server --open --config webpack.prod.js",
"serve": "node server.js",
"serve": "npm run build; node server.js",
"build": "webpack --config webpack.prod.js",
"test": "jest --config=jest.config.js",
"profile": "webpack --profile --json > stats.json --config webpack.prod.js"
"profile": "webpack --profile --json > stats.json --config webpack.prod.js",
"profile-dev": "webpack --profile --json > stats.json --config webpack.dev.js"
},
"author": "",
"license": "ISC",
@ -43,9 +44,7 @@ @@ -43,9 +44,7 @@
"lottie-web": "^5.6.8",
"node-sass": "^4.13.1",
"npm": "^6.14.4",
"offscreen-canvas": "^0.1.1",
"on-build-webpack": "^0.1.0",
"overlayscrollbars": "^1.12.0",
"pako": "^1.0.11",
"resolve-url-loader": "^3.1.1",
"sass-loader": "^8.0.2",

6
src/components/appSearch.ts

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
import appDialogsManager from "../lib/appManagers/appDialogsManager";
import Scrollable from "./scrollable";
import Scrollable from "./scrollable_new";
import appMessagesIDsManager from "../lib/appManagers/appMessagesIDsManager";
import appUsersManager from "../lib/appManagers/appUsersManager";
import appPeersManager from '../lib/appManagers/appPeersManager';
@ -147,7 +147,7 @@ export default class AppSearch { @@ -147,7 +147,7 @@ export default class AppSearch {
peerID: peerID,
pFlags: {},
peer: peer
};
} as any;
}
let {dialog, dom} = appDialogsManager.addDialog(originalDialog, group.list, false);
@ -213,7 +213,7 @@ export default class AppSearch { @@ -213,7 +213,7 @@ export default class AppSearch {
peerID: message.peerID,
pFlags: {},
peer: message.to_id
};
} as any;
}
let {dialog, dom} = appDialogsManager.addDialog(originalDialog, searchGroup.list, false);

2
src/components/chatInput.ts

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
import Scrollable from "./scrollable";
import Scrollable from "./scrollable_new";
import LazyLoadQueue from "./lazyLoadQueue";
import { RichTextProcessor } from "../lib/richtextprocessor";
//import apiManager from "../lib/mtproto/apiManager";

33
src/components/emoticonsDropdown.ts

@ -2,7 +2,8 @@ import { AppImManager } from "../lib/appManagers/appImManager"; @@ -2,7 +2,8 @@ import { AppImManager } from "../lib/appManagers/appImManager";
import { AppMessagesManager } from "../lib/appManagers/appMessagesManager";
import { horizontalMenu } from "./misc";
import lottieLoader from "../lib/lottieLoader";
import Scrollable from "./scrollable";
//import Scrollable from "./scrollable";
import Scrollable from "./scrollable_new";
import { findUpTag, whichChild, calcImageInBox } from "../lib/utils";
import { RichTextProcessor } from "../lib/richtextprocessor";
import appStickersManager, { MTStickerSet } from "../lib/appManagers/appStickersManager";
@ -62,6 +63,18 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement, @@ -62,6 +63,18 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement,
scroll.onAddedBottom = () => {};
}; */
scroll.container.scrollTop = y;
setTimeout(() => {
lottieLoader.checkAnimations(true, EMOTICONSSTICKERGROUP);
lazyLoadQueue.check();
}, 100);
/* window.requestAnimationFrame(() => {
window.requestAnimationFrame(() => {
lottieLoader.checkAnimations(true, EMOTICONSSTICKERGROUP);
lazyLoadQueue.check();
});
}); */
});
};
@ -262,11 +275,14 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement, @@ -262,11 +275,14 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement,
let categoryPush = (categoryDiv: HTMLDivElement, docs: MTDocument[], prepend?: boolean) => {
//if((docs.length % 5) != 0) categoryDiv.classList.add('not-full');
let container = document.createElement('div');
categoryDiv.append(container);
docs.forEach(doc => {
let div = document.createElement('div');
wrapSticker(doc, div, undefined, lazyLoadQueue, EMOTICONSSTICKERGROUP, true, false, true);
categoryDiv.append(div);
container.append(div);
});
if(prepend) stickersScroll.prepend(categoryDiv);
@ -290,9 +306,13 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement, @@ -290,9 +306,13 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement,
let paddingTop = parseInt(window.getComputedStyle(stickersScroll.container).getPropertyValue('padding-top')) || 0;
heights.length = 0;
let concated = stickersScroll.hiddenElements.up.concat(stickersScroll.visibleElements, stickersScroll.hiddenElements.down);
/* let concated = stickersScroll.hiddenElements.up.concat(stickersScroll.visibleElements, stickersScroll.hiddenElements.down);
concated.forEach((el, i) => {
heights[i] = (heights[i - 1] || 0) + el.height + (i == 0 ? paddingTop : 0);
}); */
let concated = Array.from(stickersScroll.splitUp.children);
concated.forEach((el, i) => {
heights[i] = (heights[i - 1] || 0) + el.scrollHeight + (i == 0 ? paddingTop : 0);
});
//console.log('stickers concated', concated, heights);
@ -308,7 +328,7 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement, @@ -308,7 +328,7 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement,
};
let prevCategoryIndex = 0;
let stickersScroll = new Scrollable(contentStickersDiv, 'y', 500, 'STICKERS');
let stickersScroll = new Scrollable(contentStickersDiv, 'y', 500, 'STICKERS', undefined, undefined, 2);
stickersScroll.container.addEventListener('scroll', (e) => {
lazyLoadQueue.check();
lottieLoader.checkAnimations();
@ -316,7 +336,6 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement, @@ -316,7 +336,6 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement,
prevCategoryIndex = emoticonsContentOnScroll(menu, heights, prevCategoryIndex, stickersScroll.container, menuScroll);
});
stickersScroll.setVirtualContainer(stickersDiv);
stickersScroll.lock('both');
emoticonsMenuOnClick(menu, heights, stickersScroll, menuScroll);
@ -397,9 +416,7 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement, @@ -397,9 +416,7 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement,
categoryPush(categoryDiv, stickerSet.documents, false);
}
})
]).then(() => {
stickersScroll.unlock('both');
});
]);
};
let gifsInit = () => {

425
src/components/scrollable_new.ts

@ -0,0 +1,425 @@ @@ -0,0 +1,425 @@
import { logger, deferredPromise, CancellablePromise } from "../lib/polyfill";
/*
var el = $0;
var height = 0;
var checkUp = false;
do {
height += el.scrollHeight;
} while(el = (checkUp ? el.previousElementSibling : el.nextElementSibling));
console.log(height);
*/
/*
Array.from($0.querySelectorAll('.bubble__container')).forEach(_el => {
//_el.style.display = '';
//return;
let el = _el.parentElement;
let height = el.scrollHeight;
let width = el.scrollWidth;
el.style.width = width + 'px';
el.style.height = height + 'px';
_el.style.display = 'none';
});
*/
export default class Scrollable {
public container: HTMLDivElement;
public type: string;
public side: string;
public translate: string;
public scrollType: string;
public scrollSide: string;
public clientAxis: string;
public clientSize: string;
public scrollSize = -1; // it will be scrollHeight
public size = 0; // it will be outerHeight of container (not scrollHeight)
public splitUp: HTMLElement;
public onScrolledTop: () => void = null;
public onScrolledBottom: () => void = null;
public onScrolledTopFired = false;
public onScrolledBottomFired = false;
public onScrollMeasure: number = null;
public lastScrollTop: number = 0;
public scrollTopOffset: number = 0;
private disableHoverTimeout: number = 0;
private log: ReturnType<typeof logger>;
private debug = false;
private measureMutex: CancellablePromise<void>;
private observer: IntersectionObserver;
private visible: Set<HTMLElement>;
private virtualTempIDTop = 0;
private virtualTempIDBottom = 0;
private lastTopID = 0;
private lastBottomID = 0;
private lastScrollDirection = true; // true = bottom
private setVisible(element: HTMLElement) {
if(this.visible.has(element)) return;
this.debug && this.log('setVisible id:', element.dataset.virtual);
(element.firstElementChild as HTMLElement).style.display = '';
this.visible.add(element);
}
private setHidden(element: HTMLElement) {
if(!this.visible.has(element)) return;
this.debug && this.log('setHidden id:', element.dataset.virtual);
(element.firstElementChild as HTMLElement).style.display = 'none';
this.visible.delete(element);
}
constructor(public el: HTMLElement, axis: 'y' | 'x' = 'y', public splitOffset = 300, logPrefix = '', public appendTo = el, public onScrollOffset = splitOffset, public splitCount = 15) {
this.container = document.createElement('div');
this.container.classList.add('scrollable');
this.visible = new Set();
this.observer = new IntersectionObserver(entries => {
let filtered = entries.filter(entry => entry.isIntersecting);
//this.log('entries:', entries);
entries.forEach(entry => {
let target = entry.target as HTMLElement;
if(entry.isIntersecting) {
this.setVisible(target);
this.debug && this.log('intersection entry:', entry, this.lastTopID, this.lastBottomID);
} else {
let id = +target.dataset.virtual;
let isTop = entry.boundingClientRect.top < 0;
if(isTop) {
this.lastTopID = id + 1;
} else {
this.lastBottomID = id - 1;
}
//this.setHidden(target);
//this.log('intersection entry setHidden:', entry);
}
//this.debug && this.log('intersection entry:', entry, isTop, isBottom, this.lastTopID, this.lastBottomID);
});
if(!filtered.length) {
return;
}
if(this.lastScrollDirection) { // bottom
let target = filtered[filtered.length - 1].target as HTMLElement;
this.lastBottomID = +target.dataset.virtual;
for(let i = 0; i < this.splitCount; ++i) {
target = target.nextElementSibling as HTMLElement;
if(!target) break;
this.setVisible(target);
}
} else {
let target = filtered[0].target as HTMLElement;
this.lastTopID = +target.dataset.virtual;
for(let i = 0; i < this.splitCount; ++i) {
target = target.previousElementSibling as HTMLElement;
if(!target) break;
this.setVisible(target);
}
}
this.debug && this.log('entries:', entries, filtered, this.lastScrollDirection, this.lastTopID, this.lastBottomID);
let minVisibleID = this.lastTopID - this.splitCount;
let maxVisibleID = this.lastBottomID + this.splitCount;
for(let target of this.visible) {
let id = +target.dataset.virtual;
if(id < minVisibleID || id > maxVisibleID) {
this.setHidden(target);
}
}
});
// внизу - самый производительный вариант
if(false) this.observer = new IntersectionObserver(entries => {
entries/* .filter(entry => entry.isIntersecting) */.forEach((entry, idx, arr) => {
let target = entry.target as HTMLElement;
if(entry.isIntersecting) {
let isTop = entry.boundingClientRect.top <= 0;
let isBottom = entry.rootBounds.height <= (entry.boundingClientRect.top + entry.boundingClientRect.height);
/* let id = +target.dataset.virtual;
let isOutOfRange = id < (this.lastTopID - 15) || id > (this.lastBottomID + 15);
if(isOutOfRange) {
this.debug && this.log('out of range, scroll jumped!');
if(idx == 0) this.lastTopID = id;
else if(idx == (arr.length - 1)) this.lastBottomID = id;
} */
this.setVisible(target);
if(isTop) {
/* this.lastTopID = id;
this.debug && this.log('set lastTopID to:', this.lastTopID); */
for(let i = 0; i < 15; ++i) {
target = target.previousElementSibling as HTMLElement;
if(!target) break;
this.setVisible(target);
}
} else if(isBottom) {
/* this.lastBottomID = id;
this.debug && this.log('set lastBottomID to:', this.lastBottomID); */
for(let i = 0; i < 15; ++i) {
target = target.nextElementSibling as HTMLElement;
if(!target) break;
this.setVisible(target);
}
}
} else {
this.setHidden(target);
}
//this.debug && this.log('intersection entry:', entry, isTop, isBottom, this.lastTopID, this.lastBottomID);
});
/* let minVisibleID = this.lastTopID - 15;
let maxVisibleID = this.lastBottomID + 15;
for(let target of this.visible) {
let id = +target.dataset.virtual;
if(id < minVisibleID || id > maxVisibleID) {
this.setHidden(target);
}
} */
});
if(!appendTo) {
this.appendTo = this.container;
}
this.log = logger('SCROLL' + (logPrefix ? '-' + logPrefix : ''));
this.measureMutex = deferredPromise<void>();
this.measureMutex.resolve();
if(axis == 'x') {
this.container.classList.add('scrollable-x');
this.type = 'width';
this.side = 'left';
this.translate = 'translateX';
this.scrollType = 'scrollWidth';
this.scrollSide = 'scrollLeft';
this.clientAxis = 'clientX';
this.clientSize = 'clientWidth';
let scrollHorizontally = (e: any) => {
e = window.event || e;
var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
this.container.scrollLeft -= (delta * 20);
e.preventDefault();
};
if(this.container.addEventListener) {
// IE9, Chrome, Safari, Opera
this.container.addEventListener("mousewheel", scrollHorizontally, false);
// Firefox
this.container.addEventListener("DOMMouseScroll", scrollHorizontally, false);
} else {
// IE 6/7/8
// @ts-ignore
this.container.attachEvent("onmousewheel", scrollHorizontally);
}
} else if(axis == 'y') {
this.container.classList.add('scrollable-y');
this.type = 'height';
this.side = 'top';
this.translate = 'translateY';
this.scrollType = 'scrollHeight';
this.scrollSide = 'scrollTop';
this.clientAxis = 'clientY';
this.clientSize = 'clientHeight';
} else {
throw new Error('no side for scroll');
}
//this.container.addEventListener('mouseover', this.resize.bind(this)); // omg
window.addEventListener('resize', () => {
window.requestAnimationFrame(() => {
this.onScroll();
});
});
this.container.addEventListener('scroll', () => this.onScroll(), {passive: true, capture: true});
Array.from(el.children).forEach(c => this.container.append(c));
el.append(this.container);
//this.onScroll();
}
public setVirtualContainer(el?: HTMLElement) {
this.splitUp = el;
this.onScrolledBottomFired = this.onScrolledTopFired = false;
this.lastScrollTop = 0;
this.log('setVirtualContainer:', el, this);
}
public onScroll() {
/* let scrollTop = this.scrollTop;
this.lastScrollDirection = this.lastScrollTop < scrollTop;
this.lastScrollTop = scrollTop;
return; */
/* if(this.debug) {
this.log('onScroll call', this.onScrollMeasure);
} */
let appendTo = this.splitUp || this.appendTo;
clearTimeout(this.disableHoverTimeout);
if(this.el != this.appendTo && this.appendTo != this.container) {
if(!appendTo.classList.contains('disable-hover')) {
appendTo.classList.add('disable-hover');
}
}
this.disableHoverTimeout = setTimeout(() => {
appendTo.classList.remove('disable-hover');
if(!this.measureMutex.isFulfilled) {
this.measureMutex.resolve();
}
}, 100);
if(this.onScrollMeasure) return; //window.cancelAnimationFrame(this.onScrollMeasure);
this.onScrollMeasure = window.requestAnimationFrame(() => {
// @ts-ignore
let scrollPos = this.container[this.scrollSide];
//if(this.measureMutex.isFulfilled) {
// @ts-ignore quick brown fix
this.size = this.container[this.clientSize];
// @ts-ignore
let scrollSize = this.container[this.scrollType];
this.scrollSize = scrollSize;
//this.measureMutex = deferredPromise<void>();
//}
let scrollTop = scrollPos - this.scrollTopOffset;
let maxScrollTop = this.scrollSize - this.scrollTopOffset - this.size;
if(this.onScrolledBottom) {
if((maxScrollTop - scrollTop) <= this.onScrollOffset) {
//if(!this.onScrolledBottomFired) {
this.onScrolledBottomFired = true;
this.onScrolledBottom();
//}
} else {
this.onScrolledBottomFired = false;
}
}
if(this.onScrolledTop) {
//this.log('onScrolledTop:', scrollTop, this.onScrollOffset);
if(scrollTop <= this.onScrollOffset) {
this.onScrolledTopFired = true;
this.onScrolledTop();
} else {
this.onScrolledTopFired = false;
}
}
this.lastScrollDirection = this.lastScrollTop < scrollTop;
this.lastScrollTop = scrollTop;
this.onScrollMeasure = 0;
});
}
public prepareElement(element: HTMLElement, append = true) {
element.dataset.virtual = '' + (append ? this.virtualTempIDBottom++ : this.virtualTempIDTop--);
this.debug && this.log('prepareElement: prepared');
window.requestAnimationFrame(() => {
let {scrollHeight/* , scrollWidth */} = element;
this.debug && this.log('prepareElement: first rAF');
window.requestAnimationFrame(() => {
//element.style.height = scrollHeight + 'px';
element.style.minHeight = scrollHeight + 'px'; // height doesn't work for safari
//element.style.width = scrollWidth + 'px';
//(element.firstElementChild as HTMLElement).style.display = 'none';
});
this.visible.add(element);
this.observer.observe(element);
});
}
public prepend(element: HTMLElement, splitable = true) {
if(splitable) this.prepareElement(element, false);
if(this.splitUp) this.splitUp.prepend(element);
else this.appendTo.prepend(element);
}
public append(element: HTMLElement, splitable = true) {
if(splitable) this.prepareElement(element);
if(this.splitUp) this.splitUp.append(element);
else this.appendTo.append(element);
}
public contains(element: Element) {
if(!this.splitUp) {
return this.appendTo.contains(element);
}
return !!element.parentElement;
}
public scrollIntoView(element: Element) {
if(element.parentElement) {
element.scrollIntoView();
}
}
public removeElement(element: Element) {
element.remove();
}
set scrollTop(y: number) {
this.container.scrollTop = y;
}
get scrollTop() {
//this.log.trace('get scrollTop');
return this.container.scrollTop;
}
get scrollHeight() {
return this.container.scrollHeight;
}
get length() {
return this.appendTo.childElementCount;
}
}

78
src/lib/appManagers/appDialogsManager.ts

@ -1,11 +1,12 @@ @@ -1,11 +1,12 @@
import { langPack, findUpClassName, $rootScope, escapeRegExp } from "../utils";
import { langPack, findUpClassName, $rootScope, escapeRegExp, whichChild } from "../utils";
import appImManager, { AppImManager } from "./appImManager";
import appPeersManager from './appPeersManager';
import appMessagesManager, { AppMessagesManager } from "./appMessagesManager";
import appUsersManager from "./appUsersManager";
import { RichTextProcessor } from "../richtextprocessor";
import { ripple, putPreloader } from "../../components/misc";
import Scrollable from "../../components/scrollable";
//import Scrollable from "../../components/scrollable";
import Scrollable from "../../components/scrollable_new";
import appProfileManager from "./appProfileManager";
import { logger } from "../polyfill";
@ -27,10 +28,10 @@ export class AppDialogsManager { @@ -27,10 +28,10 @@ export class AppDialogsManager {
public chatList = document.getElementById('dialogs') as HTMLUListElement;
public chatListArchived = document.getElementById('dialogs-archived') as HTMLUListElement;
public pinnedDelimiter: HTMLDivElement;
public chatsHidden: Scrollable["hiddenElements"];
/* public chatsHidden: Scrollable["hiddenElements"];
public chatsVisible: Scrollable["visibleElements"];
public chatsArchivedHidden: Scrollable["hiddenElements"];
public chatsArchivedVisible: Scrollable["visibleElements"];
public chatsArchivedVisible: Scrollable["visibleElements"]; */
public doms: {[peerID: number]: DialogDom} = {};
public domsArchived: {[peerID: number]: DialogDom} = {};
@ -72,14 +73,14 @@ export class AppDialogsManager { @@ -72,14 +73,14 @@ export class AppDialogsManager {
this.scroll = new Scrollable(this.chatsContainer, 'y', splitOffset, 'CL', this.chatList, 500);
this.scroll.setVirtualContainer(this.chatList);
this.scroll.onScrolledBottom = this.onChatsScroll.bind(this);
this.chatsHidden = this.scroll.hiddenElements;
this.chatsVisible = this.scroll.visibleElements;
/* this.chatsHidden = this.scroll.hiddenElements;
this.chatsVisible = this.scroll.visibleElements; */
this.scrollArchived = new Scrollable(this.chatsArchivedContainer, 'y', splitOffset, 'CLA', this.chatListArchived, 500);
this.scrollArchived.setVirtualContainer(this.chatListArchived);
this.scrollArchived.onScrolledBottom = this.onChatsArchivedScroll.bind(this);
this.chatsArchivedHidden = this.scrollArchived.hiddenElements;
this.chatsArchivedVisible = this.scrollArchived.visibleElements;
/* this.chatsArchivedHidden = this.scrollArchived.hiddenElements;
this.chatsArchivedVisible = this.scrollArchived.visibleElements; */
//this.scrollArchived.container.addEventListener('scroll', this.onChatsArchivedScroll.bind(this));
//let chatClosedDiv = document.getElementById('chat-closed');
@ -88,12 +89,19 @@ export class AppDialogsManager { @@ -88,12 +89,19 @@ export class AppDialogsManager {
this.setListClickListener(this.chatListArchived);
if(testScroll) {
for(let i = 0; i < 1000; ++i) {
let i = 0;
let add = () => {
let li = document.createElement('li');
li.dataset.id = '' + i;
li.innerHTML = `<div class="rp"><div class="user-avatar" style="background-color: rgb(166, 149, 231); font-size: 0px;"><img src="#"></div><div class="user-caption"><p><span class="user-title">${i}</span><span><span class="message-status"></span><span class="message-time">18:33</span></span></p><p><span class="user-last-message"><b>-_-_-_-: </b>qweasd</span><span></span></p></div></div>`;
li.id = '' + i;
li.innerHTML = `<div class="rp"><div class="user-avatar" style="background-color: rgb(166, 149, 231); font-size: 0px;"><img src="assets/img/pepe.jpg"></div><div class="user-caption"><p><span class="user-title">${i}</span><span><span class="message-status"></span><span class="message-time">18:33</span></span></p><p><span class="user-last-message"><b>-_-_-_-: </b>qweasd</span><span></span></p></div></div>`;
i++;
this.scroll.append(li);
};
for(let i = 0; i < 1000; ++i) {
add();
}
(window as any).addElement = add;
}
window.addEventListener('resize', () => {
@ -134,7 +142,7 @@ export class AppDialogsManager { @@ -134,7 +142,7 @@ export class AppDialogsManager {
let dialog: any = e.detail;
this.setLastMessage(dialog);
this.sortDom();
this.setDialogPosition(dialog);
});
$rootScope.$on('dialogs_multiupdate', (e: CustomEvent) => {
@ -154,12 +162,7 @@ export class AppDialogsManager { @@ -154,12 +162,7 @@ export class AppDialogsManager {
}
this.setLastMessage(dialog);
}
if(performed/* && false */) {
/////////console.log('will sortDom');
this.sortDom();
this.sortDom(true);
this.setDialogPosition(dialog);
}
});
@ -200,8 +203,7 @@ export class AppDialogsManager { @@ -200,8 +203,7 @@ export class AppDialogsManager {
//let offset = 0;
let scroll = archived ? this.scrollArchived : this.scroll;
scroll.lock();
try {
console.time('getDialogs time');
@ -241,17 +243,16 @@ export class AppDialogsManager { @@ -241,17 +243,16 @@ export class AppDialogsManager {
this.chatsPreloader.remove();
this.loadDialogsPromise = undefined;
scroll.unlock();
}
public onChatsScroll() {
if(this.loadedAll || this.scroll.hiddenElements.down.length > 0 || this.loadDialogsPromise/* || 1 == 1 */) return;
if(this.loadedAll /* || this.scroll.hiddenElements.down.length > 0 */ || this.loadDialogsPromise/* || 1 == 1 */) return;
this.loadDialogs();
}
public onChatsArchivedScroll() {
if(this.loadedArchivedAll || this.scrollArchived.hiddenElements.down.length > 0 || this.loadDialogsPromise/* || 1 == 1 */) return;
if(this.loadedArchivedAll /* || this.scrollArchived.hiddenElements.down.length > 0 */ || this.loadDialogsPromise/* || 1 == 1 */) return;
this.loadDialogs(true);
}
@ -329,8 +330,32 @@ export class AppDialogsManager { @@ -329,8 +330,32 @@ export class AppDialogsManager {
});
}
public sortDom(archived = false) {
//return;
public setDialogPosition(dialog: any) {
let pos = appMessagesManager.getDialogByPeerID(dialog.peerID)[1];
let dom = this.getDialogDom(dialog.peerID);
let prevPos = whichChild(dom.listEl);
if(prevPos == pos) {
return;
} else if(prevPos < pos) { // was higher
pos += 1;
}
let chatList = dialog.folder_id == 1 ? this.chatListArchived : this.chatList;
if(chatList.childElementCount > pos) {
chatList.insertBefore(dom.listEl, chatList.children[pos]);
} else {
chatList.append(dom.listEl);
}
// fix order
(Array.from(chatList.children) as HTMLElement[]).forEach((el, idx) => {
el.dataset.virtual = '' + idx;
});
this.log('setDialogPosition:', dialog, dom, pos);
}
/* public sortDom(archived = false) {
//if(archived) return;
let dialogs = appMessagesManager.dialogsStorage.dialogs.slice();
@ -338,7 +363,6 @@ export class AppDialogsManager { @@ -338,7 +363,6 @@ export class AppDialogsManager {
let inUpper: Scrollable['hiddenElements']['up'] = [];
let inBottom: Scrollable['hiddenElements']['down'] = [];
let inVisible: Scrollable['visibleElements'] = [];
let pinnedDialogs = [];
let sorted = dialogs;
@ -396,7 +420,7 @@ export class AppDialogsManager { @@ -396,7 +420,7 @@ export class AppDialogsManager {
let dom = this.getDialogDom(d.peerID);
if(!dom) return;
let child = concated.find(obj => obj.element == dom.listEl);
let child = concated.find((obj: any) => obj.element == dom.listEl);
if(!child) {
return this.log.error('no child by listEl:', dom.listEl, archived, concated);
}
@ -418,7 +442,7 @@ export class AppDialogsManager { @@ -418,7 +442,7 @@ export class AppDialogsManager {
chatsVisible.length = 0;
chatsVisible.push(...inVisible);
chatsHidden.down = inBottom;
}
} */
public setLastMessage(dialog: any, lastMessage?: any, dom?: DialogDom, highlightWord?: string) {
if(!lastMessage) {

2
src/lib/appManagers/appDocsManager.ts

@ -9,7 +9,7 @@ class AppDocsManager { @@ -9,7 +9,7 @@ class AppDocsManager {
private docs: {[docID: string]: MTDocument} = {};
public saveDoc(apiDoc: MTDocument/* any */, context?: any) {
console.log('saveDoc', apiDoc, this.docs[apiDoc.id]);
//console.log('saveDoc', apiDoc, this.docs[apiDoc.id]);
if(this.docs[apiDoc.id]) {
let d = this.docs[apiDoc.id];

261
src/lib/appManagers/appImManager.ts

@ -21,7 +21,8 @@ import { wrapDocument, wrapPhoto, wrapVideo, wrapSticker, wrapReply, wrapAlbum } @@ -21,7 +21,8 @@ import { wrapDocument, wrapPhoto, wrapVideo, wrapSticker, wrapReply, wrapAlbum }
import ProgressivePreloader from '../../components/preloader';
import { openBtnMenu, formatPhoneNumber } from '../../components/misc';
import { ChatInput } from '../../components/chatInput';
import Scrollable from '../../components/scrollable';
//import Scrollable from '../../components/scrollable';
import Scrollable from '../../components/scrollable_new';
import BubbleGroups from '../../components/bubbleGroups';
import LazyLoadQueue from '../../components/lazyLoadQueue';
import appDocsManager from './appDocsManager';
@ -59,8 +60,7 @@ export class AppImManager { @@ -59,8 +60,7 @@ export class AppImManager {
container: HTMLDivElement,
timeout?: number
}} = {};
public unreaded: number[] = [];
public unreadOut: number[] = [];
public unreadOut = new Set<number>();
public needUpdate: {replyMid: number, mid: number}[] = []; // if need wrapSingleMessage
public offline = false;
@ -84,8 +84,8 @@ export class AppImManager { @@ -84,8 +84,8 @@ export class AppImManager {
private typingTimeouts: {[peerID: number]: number} = {};
private typingUsers: {[userID: number]: number} = {} // to peerID
private topbar: HTMLDivElement = null;
private chatInput: HTMLDivElement = null;
private topbar = document.getElementById('topbar') as HTMLDivElement;
private chatInput = document.getElementById('chat-input') as HTMLDivElement;
private scrolledAll: boolean;
private scrolledAllDown: boolean;
@ -111,6 +111,11 @@ export class AppImManager { @@ -111,6 +111,11 @@ export class AppImManager {
private datesIntersectionObserver: IntersectionObserver = null;
private lastDateMessageDiv: HTMLDivElement = null;
private unreadedObserver: IntersectionObserver = null;
private loadedTopTimes = 0;
private loadedBottomTimes = 0;
constructor() {
/* if(!lottieLoader.loaded) {
@ -131,10 +136,7 @@ export class AppImManager { @@ -131,10 +136,7 @@ export class AppImManager {
apiManager.getUserID().then((id) => {
this.myID = $rootScope.myID = id;
});
this.topbar = document.getElementById('topbar') as HTMLDivElement;
this.chatInput = document.getElementById('chat-input') as HTMLDivElement;
$rootScope.$on('user_auth', (e: CustomEvent) => {
let userAuth = e.detail;
this.myID = $rootScope.myID = userAuth ? userAuth.id : 0;
@ -238,12 +240,10 @@ export class AppImManager { @@ -238,12 +240,10 @@ export class AppImManager {
} else {
this.log.warn('message_sent there is no bubble', e.detail);
}
let length = this.unreadOut.length;
for(let i = 0; i < length; i++) {
if(this.unreadOut[i] == tempID) {
this.unreadOut[i] = mid;
}
if(this.unreadOut.has(tempID)) {
this.unreadOut.delete(tempID);
this.unreadOut.add(mid);
}
});
@ -618,7 +618,7 @@ export class AppImManager { @@ -618,7 +618,7 @@ export class AppImManager {
apiUpdatesManager.attach();
this.datesIntersectionObserver = new IntersectionObserver((entries) => {
this.log('intersection', entries);
//this.log('intersection', entries);
let entry = entries.filter(entry => entry.boundingClientRect.top < 0).sort((a, b) => b.boundingClientRect.top - a.boundingClientRect.top)[0];
if(!entry) return;
@ -636,6 +636,35 @@ export class AppImManager { @@ -636,6 +636,35 @@ export class AppImManager {
}
}
}/* , {root: this.chatInner} */);
this.unreadedObserver = new IntersectionObserver((entries) => {
let readed: number[] = [];
entries.forEach(entry => {
if(entry.isIntersecting) {
let target = entry.target as HTMLElement;
let mid = +target.dataset.mid;
readed.push(mid);
this.unreadedObserver.unobserve(target);
}
});
if(readed.length) {
let max = Math.max(...readed);
let min = Math.min(...readed);
if(this.peerID < 0) {
max = appMessagesIDsManager.getMessageIDInfo(max)[0];
min = appMessagesIDsManager.getMessageIDInfo(min)[0];
}
//appMessagesManager.readMessages(readed);
appMessagesManager.readHistory(this.peerID, max, min).catch((err: any) => {
this.log.error('readHistory err:', err);
appMessagesManager.readHistory(this.peerID, max, min);
});
}
});
}
public deleteMessages(revoke = false) {
@ -709,7 +738,6 @@ export class AppImManager { @@ -709,7 +738,6 @@ export class AppImManager {
}
if(top && !this.scrolledAll) {
this.scrollable.lock('both');
this.log('Will load more (up) history by id:', history[0], 'maxID:', history[history.length - 1], history);
/* false && */this.getHistory(history[0], true);
}
@ -724,7 +752,6 @@ export class AppImManager { @@ -724,7 +752,6 @@ export class AppImManager {
// if scroll down after search
if(!top && (!dialog || history.indexOf(dialog.top_message) === -1)) {
this.scrollable.lock('both');
this.log('Will load more (down) history by maxID:', history[history.length - 1], history);
/* false && */this.getHistory(history[history.length - 1], false, true);
}
@ -734,34 +761,7 @@ export class AppImManager { @@ -734,34 +761,7 @@ export class AppImManager {
if(this.onScrollRAF) window.cancelAnimationFrame(this.onScrollRAF);
this.onScrollRAF = window.requestAnimationFrame(() => {
let readed: number[] = [];
this.unreaded.forEachReverse((msgID, idx) => {
let bubble = this.bubbles[msgID];
if(isElementInViewport(bubble)) {
readed.push(msgID);
this.unreaded.splice(idx, 1);
}
});
lottieLoader.checkAnimations(false, 'chat');
if(readed.length) {
let max = Math.max(...readed);
let min = Math.min(...readed);
if(this.peerID < 0) {
max = appMessagesIDsManager.getMessageIDInfo(max)[0];
min = appMessagesIDsManager.getMessageIDInfo(min)[0];
}
//appMessagesManager.readMessages(readed);
appMessagesManager.readHistory(this.peerID, max, min).catch((err: any) => {
this.log.error('readHistory err:', err);
appMessagesManager.readHistory(this.peerID, max, min);
});
}
if(this.isScrollingTimeout) {
clearTimeout(this.isScrollingTimeout);
@ -915,8 +915,7 @@ export class AppImManager { @@ -915,8 +915,7 @@ export class AppImManager {
this.bubbles = {};
this.dateMessages = {};
this.bubbleGroups.cleanup();
this.unreaded = [];
this.unreadOut = [];
this.unreadOut.clear();
this.needUpdate.length = 0;
this.lazyLoadQueue.clear();
@ -936,13 +935,17 @@ export class AppImManager { @@ -936,13 +935,17 @@ export class AppImManager {
this.datesIntersectionObserver.disconnect();
this.lastDateMessageDiv = null;
this.unreadedObserver.disconnect();
this.loadedTopTimes = this.loadedBottomTimes = 0;
////console.timeEnd('appImManager cleanup');
}
public setPeer(peerID: number, lastMsgID = 0, forwarding = false, fromClick = false) {
//console.time('appImManager setPeer');
//console.time('appImManager setPeer pre promise');
console.time('appImManager setPeer');
console.time('appImManager setPeer pre promise');
////console.time('appImManager: pre render start');
if(peerID == 0) {
appSidebarRight.toggleSidebar(false);
@ -1050,7 +1053,7 @@ export class AppImManager { @@ -1050,7 +1053,7 @@ export class AppImManager {
//////appSidebarRight.toggleSidebar(true);
//console.timeEnd('appImManager setPeer pre promise');
console.timeEnd('appImManager setPeer pre promise');
this.preloader.attach(this.bubblesContainer);
return this.setPeerPromise = Promise.all([
this.getHistory(forwarding ? lastMsgID + 1 : lastMsgID, true, false, additionMsgID).then(() => {
@ -1074,7 +1077,7 @@ export class AppImManager { @@ -1074,7 +1077,7 @@ export class AppImManager {
this.preloader.detach();
this.chatInner.style.visibility = '';
//console.timeEnd('appImManager setPeer');
console.timeEnd('appImManager setPeer');
//setTimeout(() => {
//appSidebarRight.fillProfileElements();
@ -1120,19 +1123,22 @@ export class AppImManager { @@ -1120,19 +1123,22 @@ export class AppImManager {
///////this.log('updateUnreadByDialog', maxID, dialog, this.unreadOut);
this.unreadOut.forEachReverse((msgID, idx) => {
for(let msgID of this.unreadOut) {
if(msgID > 0 && msgID <= maxID) {
let bubble = this.bubbles[msgID];
bubble.classList.remove('is-sent');
bubble.classList.add('is-read');
this.unreadOut.splice(idx, 1);
if(bubble) {
bubble.classList.remove('is-sent');
bubble.classList.add('is-read');
}
this.unreadOut.delete(msgID);
}
});
}
}
public deleteMessagesByIDs(msgIDs: number[]) {
public deleteMessagesByIDs(msgIDs: number[], forever = true) {
msgIDs.forEach(id => {
if(this.firstTopMsgID == id) {
if(this.firstTopMsgID == id && forever) {
let dialog = appMessagesManager.getDialogByPeerID(this.peerID)[0];
if(dialog) {
@ -1145,11 +1151,14 @@ export class AppImManager { @@ -1145,11 +1151,14 @@ export class AppImManager {
let bubble = this.bubbles[id];
delete this.bubbles[id];
this.unreadedObserver.unobserve(bubble);
this.scrollable.removeElement(bubble);
//bubble.remove();
});
lottieLoader.checkAnimations();
this.deleteEmptyDateGroups();
}
public renderNewMessagesByIDs(msgIDs: number[]) {
@ -1206,16 +1215,17 @@ export class AppImManager { @@ -1206,16 +1215,17 @@ export class AppImManager {
};
container.append(div);
//this.scrollable.prepareElement(div, false);
if(reverse) {
let scrollTopPrevious = this.scrollable.scrollTop;
this.scrollable.prepend(container);
//let scrollTopPrevious = this.scrollable.scrollTop;
this.scrollable.prepend(container, false);
if(!scrollTopPrevious) {
/* if(!scrollTopPrevious) {
this.scrollable.scrollTop += container.scrollHeight;
}
} */
} else {
this.scrollable.append(container);
this.scrollable.append(container, false);
}
this.datesIntersectionObserver.observe(container);
@ -1298,8 +1308,10 @@ export class AppImManager { @@ -1298,8 +1308,10 @@ export class AppImManager {
} else if(reverse) {
dateContainer.container.insertBefore(bubble, dateContainer.div.nextSibling);
//this.scrollable.prepareElement(bubble, false);
} else {
dateContainer.container.append(bubble);
//this.scrollable.prepareElement(bubble, true);
}
return bubble;
@ -1387,7 +1399,7 @@ export class AppImManager { @@ -1387,7 +1399,7 @@ export class AppImManager {
//bubble.prepend(timeSpan, messageDiv); // that's bad
if(our) {
if(message.pFlags.unread || message.mid < 0) this.unreadOut.push(message.mid); // message.mid < 0 added 11.02.2020
if(message.pFlags.unread || message.mid < 0) this.unreadOut.add(message.mid); // message.mid < 0 added 11.02.2020
let status = '';
if(message.mid < 0) status = 'is-sending';
else status = message.pFlags.unread ? 'is-sent' : 'is-read';
@ -1395,7 +1407,7 @@ export class AppImManager { @@ -1395,7 +1407,7 @@ export class AppImManager {
} else {
//this.log('not our message', message, message.pFlags.unread);
if(message.pFlags.unread) {
this.unreaded.push(message.mid);
this.unreadedObserver.observe(bubble);
}
}
@ -1839,8 +1851,10 @@ export class AppImManager { @@ -1839,8 +1851,10 @@ export class AppImManager {
let dateMessage = this.getDateContainerByMessage(message, reverse);
if(reverse) {
dateMessage.container.insertBefore(bubble, dateMessage.div.nextSibling);
//this.scrollable.prepareElement(bubble, false);
} else {
dateMessage.container.append(bubble);
//this.scrollable.prepareElement(bubble, true);
}
} else {
this.bubbleGroups.updateGroupByMessageID(message.mid);
@ -1868,14 +1882,17 @@ export class AppImManager { @@ -1868,14 +1882,17 @@ export class AppImManager {
if(additionMsgID) {
history.unshift(additionMsgID);
}
//let method = reverse ? result.history.forEach : result.history.forEachReverse;
let method = reverse ? Array.prototype.forEach : Array.prototype.forEachReverse;
method = method.bind(history);
//console.time('appImManager render history');
this.log('getHistory method', method);
if(testScroll && additionMsgID) {
for(let i = 0; i < 3; ++i) {
let _history = history.slice();
setTimeout(() => {
this.performHistoryResult(_history, reverse, isBackLimit, 0, resetPromises);
}, (i + 1) * 2500);
}
}
console.time('appImManager render history');
let firstLoad = !!this.setPeerPromise && false;
@ -1889,13 +1906,15 @@ export class AppImManager { @@ -1889,13 +1906,15 @@ export class AppImManager {
bubbles.push(bubble);
}); */
let leftHeightToScroll = this.scrollable.innerHeight;
//let leftHeightToScroll = this.scrollable.innerHeight;
//console.timeEnd('appImManager: pre render start');
//this.log('start performHistoryResult, scrollTop:', this.scrollable.scrollTop, this.scrollable.scrollHeight, this.scrollable.innerHeight);
let renderedFirstScreen = false;
let method = (reverse ? history.shift : history.pop).bind(history);
let renderedFirstScreen = !!this.scrollable.scrollTop;
let r = () => {
//let bubble = bubbles.shift();
//if(!bubble && !resolved) return resolve();
@ -1912,14 +1931,13 @@ export class AppImManager { @@ -1912,14 +1931,13 @@ export class AppImManager {
//let startTime = Date.now();
//let elapsedTime = 0;
//do {
let msgID = history.shift();
//let msgID = history.shift();
let msgID = method();
if(!msgID) {
if(resetPromises) {
(reverse ? this.getHistoryTopPromise = undefined : this.getHistoryBottomPromise = undefined);
}
this.scrollable.unlock('both');
if(!resolved) {
resolve(true);
}
@ -1995,19 +2013,11 @@ export class AppImManager { @@ -1995,19 +2013,11 @@ export class AppImManager {
this.renderMessage(message, reverse, true);
});
}); */
})/* .then(() => {
if(!isBackLimit) {
this.scrollPosition.restore(() => {
this.scrollable.unlock('both');
});
} else {
this.scrollable.unlock('both');
}
//console.timeEnd('appImManager render history');
}).then(() => {
console.timeEnd('appImManager render history');
return true;
}) */;
});
}
// reverse means scroll up
@ -2021,10 +2031,13 @@ export class AppImManager { @@ -2021,10 +2031,13 @@ export class AppImManager {
maxID = dialog.top_message/* + 1 */;
}
let loadCount = Object.keys(this.bubbles).length > 0 ? 20 : this.scrollable.innerHeight / 38/* * 1.25 */ | 0;
let pageCount = this.bubblesContainer.clientHeight / 38/* * 1.25 */ | 0;
//let loadCount = Object.keys(this.bubbles).length > 0 ? 50 : pageCount;
let realLoadCount = 50;
let loadCount = realLoadCount;
if(testScroll) {
loadCount = 1;
//loadCount = 1;
if(Object.keys(this.bubbles).length > 0)
return Promise.resolve(true);
}
@ -2044,8 +2057,10 @@ export class AppImManager { @@ -2044,8 +2057,10 @@ export class AppImManager {
$rootScope.$broadcast('history_request'); // for ripple
result = new Promise((resolve, reject) => setTimeout(() => resolve(_result), 150));
} */
let promise: Promise<boolean>;
if(result instanceof Promise) {
let promise = result.then((result) => {
promise = result.then((result) => {
this.log('getHistory result by maxID:', maxID, reverse, isBackLimit, result);
//console.timeEnd('appImManager call getHistory');
@ -2062,17 +2077,73 @@ export class AppImManager { @@ -2062,17 +2077,73 @@ export class AppImManager {
}, (err) => {
this.log.error('getHistory error:', err);
(reverse ? this.getHistoryTopPromise = undefined : this.getHistoryBottomPromise = undefined);
this.scrollable.unlock('both');
return false;
});
return (reverse ? this.getHistoryTopPromise = promise : this.getHistoryBottomPromise = promise);
(reverse ? this.getHistoryTopPromise = promise : this.getHistoryBottomPromise = promise);
} else {
let promise = this.performHistoryResult(result.history || [], reverse, isBackLimit, additionMsgID, true);
promise = this.performHistoryResult(result.history || [], reverse, isBackLimit, additionMsgID, true);
//return (reverse ? this.getHistoryTopPromise = promise : this.getHistoryBottomPromise = promise);
return promise;
//return this.performHistoryResult(result.history || [], reverse, isBackLimit, additionMsgID, true);
}
/* false && */promise.then(() => {
if(reverse) {
this.loadedTopTimes++;
this.loadedBottomTimes = Math.max(0, --this.loadedBottomTimes);
} else {
this.loadedBottomTimes++;
this.loadedTopTimes = Math.max(0, --this.loadedTopTimes);
}
let ids: number[];
if((reverse && this.loadedTopTimes > 2) || (!reverse && this.loadedBottomTimes > 2)) {
ids = Object.keys(this.bubbles).map(i => +i).sort((a, b) => a - b);
}
this.log('getHistory: slice loadedTimes:', reverse, pageCount, this.loadedTopTimes, this.loadedBottomTimes, ids && ids.length);
let removeCount = loadCount / 2;
let safeCount = realLoadCount * 2;
if(ids && ids.length > safeCount) {
if(reverse) {
//ids = ids.slice(-removeCount);
//ids = ids.slice(removeCount * 2);
ids = ids.slice(safeCount);
this.scrolledAllDown = false;
} else {
//ids = ids.slice(0, removeCount);
//ids = ids.slice(0, ids.length - (removeCount * 2));
ids = ids.slice(0, ids.length - safeCount);
this.scrolledAll = false;
this.log('getHistory: slice bottom: to:', ids.length, loadCount);
}
this.log('getHistory: will slice ids:', ids, reverse);
this.deleteMessagesByIDs(ids, false);
/* ids.forEach(id => {
this.bubbles[id].remove();
delete this.bubbles[id];
});
this.deleteEmptyDateGroups(); */
}
});
return promise;
}
public deleteEmptyDateGroups() {
for(let i in this.dateMessages) {
let dateMessage = this.dateMessages[i];
if(dateMessage.container.childElementCount == 1) { // only date div
dateMessage.container.remove();
this.datesIntersectionObserver.unobserve(dateMessage.container);
delete this.dateMessages[i];
}
}
}
public setMutedState(muted = false) {

75
src/lib/appManagers/appMessagesManager.ts

@ -22,6 +22,8 @@ import apiManager from '../mtproto/mtprotoworker'; @@ -22,6 +22,8 @@ import apiManager from '../mtproto/mtprotoworker';
import appWebPagesManager from "./appWebPagesManager";
import { CancellablePromise, deferredPromise } from "../polyfill";
const APITIMEOUT = 0;
export type HistoryStorage = {
count: number | null,
history: number[],
@ -36,6 +38,28 @@ export type HistoryResult = { @@ -36,6 +38,28 @@ export type HistoryResult = {
unreadSkip: boolean
};
type Dialog = {
_: 'dialog',
top_message: number,
read_inbox_max_id: number,
read_outbox_max_id: number,
peer: any,
notify_settings: any,
folder_id: number,
flags: number,
draft: any,
unread_count: number,
unread_mentions_count: number,
index: number,
peerID: number,
pinnedIndex: number,
pFlags: Partial<{
pinned: boolean
}>,
pts: number
}
export class AppMessagesManager {
public messagesStorage: any = {};
public messagesForDialogs: any = {};
@ -45,7 +69,7 @@ export class AppMessagesManager { @@ -45,7 +69,7 @@ export class AppMessagesManager {
} = {};
public dialogsStorage: {
count: any,
dialogs: any[]
dialogs: Dialog[]
} = {count: null, dialogs: []};
public pendingByRandomID: {[randomID: string]: [number, number]} = {};
public pendingByMessageID: any = {};
@ -1222,7 +1246,7 @@ export class AppMessagesManager { @@ -1222,7 +1246,7 @@ export class AppMessagesManager {
limit: limit,
hash: hash
}, {
timeout: 300
timeout: APITIMEOUT
}).then((dialogsResult: any) => {
///////console.log('messages.getDialogs result:', dialogsResult);
@ -1351,11 +1375,24 @@ export class AppMessagesManager { @@ -1351,11 +1375,24 @@ export class AppMessagesManager {
return message.from_id;
}
public getDialogByPeerID(peerID: number) {
let length = this.dialogsStorage.dialogs.length;
for(var i = 0; i < length; i++) {
if(this.dialogsStorage.dialogs[i].peerID == peerID) {
return [this.dialogsStorage.dialogs[i], i];
public getDialogByPeerID(peerID: number): [Dialog, number] | [] {
let dialogs = this.dialogsStorage.dialogs;
let byFolders: {[id: number]: number} = {};
for(let i = 0, length = dialogs.length; i < length; i++) {
let dialog = dialogs[i];
if(!byFolders[dialog.folder_id]) byFolders[dialog.folder_id] = 0;
byFolders[dialog.folder_id]++;
if(dialog.peerID == peerID) {
//return [dialog, i];
let sum = 0;
for(let id in byFolders) {
if(+id != dialog.folder_id) {
sum += byFolders[id];
}
}
return [dialog, i - sum];
}
}
@ -1408,11 +1445,9 @@ export class AppMessagesManager { @@ -1408,11 +1445,9 @@ export class AppMessagesManager {
var dialog = this.getDialogByPeerID(peerID)[0];
if(dialog && mid > 0) {
let dialogKey = apiMessage.pFlags.out
apiMessage.pFlags.unread = mid > dialog[apiMessage.pFlags.out
? 'read_outbox_max_id'
: 'read_inbox_max_id';
apiMessage.pFlags.unread = mid > dialog[dialogKey];
: 'read_inbox_max_id'];
} else if(options.isNew) {
apiMessage.pFlags.unread = true;
}
@ -1723,7 +1758,7 @@ export class AppMessagesManager { @@ -1723,7 +1758,7 @@ export class AppMessagesManager {
delete this.messagesForDialogs[msgID];
}
public saveConversation(dialog: any) {
public saveConversation(dialog: Dialog) {
var peerID = AppPeersManager.getPeerID(dialog.peer);
if(!peerID) {
return false;
@ -1792,9 +1827,8 @@ export class AppMessagesManager { @@ -1792,9 +1827,8 @@ export class AppMessagesManager {
this.pushDialogToStorage(dialog, offsetDate);
// Because we saved message without dialog present
var unreadKey = message.pFlags.out ? 'read_outbox_max_id' : 'read_inbox_max_id';
if(message.mid > 0) {
if(message.mid > dialog[unreadKey]) message.pFlags.unread = true;
if(message.mid > dialog[message.pFlags.out ? 'read_outbox_max_id' : 'read_inbox_max_id']) message.pFlags.unread = true;
else message.pFlags.unread = false;
}
@ -2289,7 +2323,7 @@ export class AppMessagesManager { @@ -2289,7 +2323,7 @@ export class AppMessagesManager {
max_id: 0,
min_id: 0
}, {
timeout: 300,
timeout: APITIMEOUT,
noErrorBox: true
});
} else {
@ -2311,7 +2345,7 @@ export class AppMessagesManager { @@ -2311,7 +2345,7 @@ export class AppMessagesManager {
offset_id: appMessagesIDsManager.getMessageLocalID(offsetID),
limit: limit || 20
}, {
timeout: 300,
timeout: APITIMEOUT,
noErrorBox: true
});
}
@ -2888,8 +2922,7 @@ export class AppMessagesManager { @@ -2888,8 +2922,7 @@ export class AppMessagesManager {
newUnreadCount = foundDialog[0].unread_count = 0;
}
let dialogKey = isOut ? 'read_outbox_max_id' : 'read_inbox_max_id';
foundDialog[0][dialogKey] = maxID;
foundDialog[0][isOut ? 'read_outbox_max_id' : 'read_inbox_max_id'] = maxID;
}
// need be commented for read out messages
@ -2949,7 +2982,7 @@ export class AppMessagesManager { @@ -2949,7 +2982,7 @@ export class AppMessagesManager {
var channelID: number = update.channel_id;
var messageID: number;
var message, i;
var peerID: number, foundDialog: any[];
var peerID: number, foundDialog: ReturnType<AppMessagesManager['getDialogByPeerID']>;
let history: any;
var peerMessagesToHandle;
var peerMessagesHandlePos;
@ -3451,7 +3484,7 @@ export class AppMessagesManager { @@ -3451,7 +3484,7 @@ export class AppMessagesManager {
min_id: 0,
hash: 0
}, {
timeout: 300,
timeout: APITIMEOUT,
noErrorBox: true
}).then((historyResult: any) => {
console.log('requestHistory result:', historyResult, maxID, limit, offset);
@ -3474,7 +3507,7 @@ export class AppMessagesManager { @@ -3474,7 +3507,7 @@ export class AppMessagesManager {
// will load more history if last message is album grouped (because it can be not last item)
let historyStorage = this.historiesStorage[peerID];
// historyResult.messages: desc sorted
if(historyResult.messages[length - 1].grouped_id && (historyStorage.history.length + historyResult.messages.length) < historyResult.count) {
if(length && historyResult.messages[length - 1].grouped_id && (historyStorage.history.length + historyResult.messages.length) < historyResult.count) {
return this.requestHistory(peerID, historyResult.messages[length - 1].mid, 10, 0).then((_historyResult: any) => {
return historyResult;
});

2
src/lib/appManagers/appPhotosManager.ts

@ -142,7 +142,7 @@ export class AppPhotosManager { @@ -142,7 +142,7 @@ export class AppPhotosManager {
//console.log('diff', diff, photoSize, bestPhotoSize);
}); */
console.log('choosing', photo, width, height, bestPhotoSize);
//console.log('choosing', photo, width, height, bestPhotoSize);
return bestPhotoSize;
}

30
src/lib/appManagers/appSidebarRight.ts

@ -1,5 +1,6 @@ @@ -1,5 +1,6 @@
import { horizontalMenu, formatPhoneNumber, putPreloader, renderImageFromUrl } from "../../components/misc";
import Scrollable from '../../components/scrollable';
//import Scrollable from '../../components/scrollable';
import Scrollable from '../../components/scrollable_new';
import { $rootScope } from "../utils";
import appMessagesManager from "./appMessagesManager";
import appPhotosManager from "./appPhotosManager";
@ -79,10 +80,7 @@ class AppSidebarRight { @@ -79,10 +80,7 @@ class AppSidebarRight {
private peerID = 0;
public scroll: Scrollable = null;
private savedVirtualStates: {
[id: number]: Scrollable['state']
} = {};
private profileTabs: HTMLUListElement;
private prevTabID = -1;
@ -107,7 +105,7 @@ class AppSidebarRight { @@ -107,7 +105,7 @@ class AppSidebarRight {
//this.scroll = new Scrollable(this.profileContentEl, 'y', 1200, 'SR', undefined, 400);
this.scroll.container.addEventListener('scroll', this.onSidebarScroll.bind(this));
this.scroll.onScrolledBottom = () => {
if(this.sharedMediaSelected && !this.scroll.hiddenElements.down.length && this.sharedMediaSelected.childElementCount/* && false */) {
if(this.sharedMediaSelected && this.sharedMediaSelected.childElementCount/* && false */) {
this.log('onScrolledBottom will load media');
this.loadSidebarMedia(true);
}
@ -123,17 +121,8 @@ class AppSidebarRight { @@ -123,17 +121,8 @@ class AppSidebarRight {
this.scroll.scrollTop -= this.profileTabs.offsetTop;
}
if(this.prevTabID != -1) {
this.savedVirtualStates[this.prevTabID] = this.scroll.state;
}
this.log('setVirtualContainer', id, this.sharedMediaSelected);
this.scroll.setVirtualContainer(this.sharedMediaSelected);
if(this.savedVirtualStates[id]) {
this.log(this.savedVirtualStates[id]);
this.scroll.state = this.savedVirtualStates[id];
}
if(this.prevTabID != -1 && !this.sharedMediaSelected.childElementCount) { // quick brown fix
this.contentContainer.classList.remove('loaded');
@ -423,7 +412,7 @@ class AppSidebarRight { @@ -423,7 +412,7 @@ class AppSidebarRight {
if(elemsToAppend.length) {
//window.requestAnimationFrame(() => {
elemsToAppend.forEach(el => this.scroll.append(el));
elemsToAppend.forEach(el => this.scroll.append(el, false));
//});
}
@ -452,9 +441,7 @@ class AppSidebarRight { @@ -452,9 +441,7 @@ class AppSidebarRight {
if(!typesToLoad.length) return;
let historyStorage = this.historiesStorage[peerID] ?? (this.historiesStorage[peerID] = {});
this.scroll.lock();
let promises = typesToLoad.map(type => {
if(this.loadSidebarMediaPromises[type]) return this.loadSidebarMediaPromises[type];
@ -513,9 +500,7 @@ class AppSidebarRight { @@ -513,9 +500,7 @@ class AppSidebarRight {
});
});
return Promise.all(promises).then(() => {
this.scroll.unlock();
});
return Promise.all(promises);
}
public fillProfileElements() {
@ -546,7 +531,6 @@ class AppSidebarRight { @@ -546,7 +531,6 @@ class AppSidebarRight {
}
});
this.savedVirtualStates = {};
this.prevTabID = -1;
this.scroll.setVirtualContainer(null);
(this.profileTabs.firstElementChild.children[1] as HTMLLIElement).click(); // set media

29
src/lib/bin_utils.ts

@ -7,12 +7,28 @@ @@ -7,12 +7,28 @@
// @ts-ignore
import {BigInteger, SecureRandom} from 'jsbn';
/// #if !MTPROTO_WORKER
// @ts-ignore
import pako from 'pako/dist/pako_inflate.min.js';
var _logTimer = (new Date()).getTime()
export function gzipUncompress(bytes: ArrayBuffer, toString: true): string;
export function gzipUncompress(bytes: ArrayBuffer, toString?: false): Uint8Array;
export function gzipUncompress(bytes: ArrayBuffer, toString?: boolean): string | Uint8Array {
//console.log(dT(), 'Gzip uncompress start');
var result = pako.inflate(bytes, toString ? {to: 'string'} : undefined);
//console.log(dT(), 'Gzip uncompress finish'/* , result */);
return result;
}
/// #endif
var _logTimer = Date.now();
export function dT () {
return '[' + (((new Date()).getTime() - _logTimer) / 1000).toFixed(3) + ']'
return '[' + ((Date.now() - _logTimer) / 1000).toFixed(3) + ']'
}
export function isObject(object: any) {
return typeof(object) === 'object' && object !== null;
}
export function bigint(num: number) {
@ -379,15 +395,6 @@ export function addPadding(bytes: any, blockSize: number = 16, zeroes?: boolean, @@ -379,15 +395,6 @@ export function addPadding(bytes: any, blockSize: number = 16, zeroes?: boolean,
return bytes;
}
export function gzipUncompress(bytes: ArrayBuffer, toString: true): string;
export function gzipUncompress(bytes: ArrayBuffer, toString?: false): Uint8Array;
export function gzipUncompress(bytes: ArrayBuffer, toString?: boolean): string | Uint8Array {
//console.log(dT(), 'Gzip uncompress start');
var result = pako.inflate(bytes, toString ? {to: 'string'} : undefined);
//console.log(dT(), 'Gzip uncompress finish'/* , result */);
return result;
}
export function nextRandomInt(maxValue: number) {
return Math.floor(Math.random() * maxValue);
}

12
src/lib/crypto/crypto_utils.ts

@ -2,6 +2,9 @@ import sha1 from '@cryptography/sha1'; @@ -2,6 +2,9 @@ import sha1 from '@cryptography/sha1';
import sha256 from '@cryptography/sha256';
import {IGE} from '@cryptography/aes';
// @ts-ignore
import pako from 'pako/dist/pako_inflate.min.js';
import {str2bigInt, bpe, equalsInt, greater,
copy_, eGCD_, add_, rightShift_, sub_, copyInt_, isZero,
// @ts-ignore
@ -239,3 +242,12 @@ export function bytesModPow(x: any, y: any, m: any) { @@ -239,3 +242,12 @@ export function bytesModPow(x: any, y: any, m: any) {
return bytesFromBigInt(new BigInteger(x).modPow(new BigInteger(y), new BigInteger(m)), 256);
}
export function gzipUncompress(bytes: ArrayBuffer, toString: true): string;
export function gzipUncompress(bytes: ArrayBuffer, toString?: false): Uint8Array;
export function gzipUncompress(bytes: ArrayBuffer, toString?: boolean): string | Uint8Array {
//console.log(dT(), 'Gzip uncompress start');
var result = pako.inflate(bytes, toString ? {to: 'string'} : undefined);
//console.log(dT(), 'Gzip uncompress finish'/* , result */);
return result;
}

7
src/lib/crypto/cryptoworker.ts

@ -37,13 +37,14 @@ class CryptoWorker extends CryptoWorkerMethods { @@ -37,13 +37,14 @@ class CryptoWorker extends CryptoWorkerMethods {
'aes-decrypt': utils.aesDecryptSync,
'rsa-encrypt': utils.rsaEncrypt,
'factorize': utils.pqPrimeFactorization,
'mod-pow': utils.bytesModPow
'mod-pow': utils.bytesModPow,
'unzip': utils.gzipUncompress
});
}),
})/* ,
import('../bin_utils').then(utils => {
this.utils.unzip = utils.gzipUncompress;
})
}) */
]);
/// #else
if(window.Worker) {

42
src/lib/mtproto/apiManager.ts

@ -1,17 +1,20 @@ @@ -1,17 +1,20 @@
import AppStorage from '../storage';
import { MTPNetworker } from './networker';
import { bytesFromHex, bytesToHex } from '../bin_utils';
import { bytesFromHex, bytesToHex, isObject } from '../bin_utils';
import networkerFactory from './networkerFactory';
import { telegramMeWebService } from './mtproto';
import authorizer from './authorizer';
import { isObject, tsNow, $rootScope } from '../utils';
import {App, Modes} from './mtproto_config';
import dcConfigurator from './dcConfigurator';
import HTTP from './transports/http';
import { logger } from '../polyfill';
import passwordManager from './passwordManager';
/// #if !MTPROTO_WORKER
import { $rootScope } from '../utils';
/// #endif
//console.error('apiManager included!');
export class ApiManager {
@ -51,7 +54,10 @@ export class ApiManager { @@ -51,7 +54,10 @@ export class ApiManager {
});
this.telegramMeNotify(true);
/// #if !MTPROTO_WORKER
$rootScope.$broadcast('user_auth', fullUserAuth);
/// #endif
}
// mtpLogOut
@ -189,21 +195,21 @@ export class ApiManager { @@ -189,21 +195,21 @@ export class ApiManager {
}
// mtpInvokeApi
public invokeApi(method: string, params: any = {}, options: {
dcID?: number,
timeout?: number,
noErrorBox?: boolean,
fileUpload?: boolean,
ignoreErrors?: boolean,
fileDownload?: boolean,
createNetworker?: boolean,
singleInRequest?: boolean,
startMaxLength?: number,
public invokeApi(method: string, params: any = {}, options: Partial<{
dcID: number,
timeout: number,
noErrorBox: boolean,
fileUpload: boolean,
ignoreErrors: boolean,
fileDownload: boolean,
createNetworker: boolean,
singleInRequest: boolean,
startMaxLength: number,
waitTime?: number,
stopTime?: number,
rawError?: any
} = {}) {
waitTime: number,
stopTime: number,
rawError: any
}> = {}) {
///////this.log('Invoke api', method, params, options);
return new Promise((resolve, reject) => {
@ -287,7 +293,7 @@ export class ApiManager { @@ -287,7 +293,7 @@ export class ApiManager {
} else if(!options.rawError && error.code == 420) {
var waitTime = error.type.match(/^FLOOD_WAIT_(\d+)/)[1] || 10;
if(waitTime > (options.timeout || 60)) {
if(waitTime > (options.timeout !== undefined ? options.timeout : 60)) {
return rejectPromise(error);
}
@ -295,7 +301,7 @@ export class ApiManager { @@ -295,7 +301,7 @@ export class ApiManager {
performRequest(cachedNetworker);
}, (waitTime + 5) * 1000); // 03.02.2020
} else if(!options.rawError && (error.code == 500 || error.type == 'MSG_WAIT_FAILED')) {
var now = tsNow();
var now = Date.now();
if(options.stopTime) {
if(now >= options.stopTime) {
return rejectPromise(error);

3
src/lib/mtproto/authorizer.ts

@ -2,7 +2,6 @@ import { TLSerialization, TLDeserialization } from "./tl_utils"; @@ -2,7 +2,6 @@ import { TLSerialization, TLDeserialization } from "./tl_utils";
import dcConfigurator from "./dcConfigurator";
import { dT, bytesToHex, bytesCmp, bytesFromHex, bytesXor } from "../bin_utils";
import rsaKeysManager from "./rsaKeysManager";
import { tsNow } from "../utils";
import timeManager from "./timeManager";
// @ts-ignore
@ -303,7 +302,7 @@ export class Authorizer { @@ -303,7 +302,7 @@ export class Authorizer {
}
public async mtpDecryptServerDhDataAnswer(auth: AuthOptions, encryptedAnswer: any) {
auth.localTime = tsNow();
auth.localTime = Date.now();
// can't concat Array with Uint8Array!
//auth.tmpAesKey = sha1BytesSync(auth.newNonce.concat(auth.serverNonce)).concat(sha1BytesSync(auth.serverNonce.concat(auth.newNonce)).slice(0, 12));

3
src/lib/mtproto/mtproto.ts

@ -1,5 +1,4 @@ @@ -1,5 +1,4 @@
import AppStorage from '../storage';
import {tsNow} from '../utils';
import { Modes, App } from './mtproto_config';
/* import PasswordManager from './passwordManager';
@ -24,7 +23,7 @@ export class TelegramMeWebService { @@ -24,7 +23,7 @@ export class TelegramMeWebService {
}
AppStorage.get<any>('tgme_sync').then((curValue) => {
var ts = tsNow(true);
var ts = Date.now() / 1000;
if(canRedirect &&
curValue &&
curValue.canRedirect == canRedirect &&

3
src/lib/mtproto/mtprotoworker.ts

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
import {dT, isObject} from '../utils';
import {dT, isObject, $rootScope} from '../utils';
import AppStorage from '../storage';
import CryptoWorkerMethods from '../crypto/crypto_methods';
@ -126,6 +126,7 @@ class ApiManagerProxy extends CryptoWorkerMethods { @@ -126,6 +126,7 @@ class ApiManagerProxy extends CryptoWorkerMethods {
}
public setUserAuth(userAuth: {id: number}) {
$rootScope.$broadcast('user_auth', userAuth);
return this.performTaskWorker('setUserAuth', userAuth);
}

14
src/lib/mtproto/networker.ts

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
import {tsNow, isObject} from '../utils';
import {isObject} from '../bin_utils';
import {convertToUint8Array,
bufferConcat, nextRandomInt, bytesToHex, longToBytes,
bytesCmp, uintToInt, bigStringInt} from '../bin_utils';
@ -295,7 +295,7 @@ class MTPNetworker { @@ -295,7 +295,7 @@ class MTPNetworker {
public checkLongPoll() {
var isClean = this.cleanupSent();
//this.log('Check lp', this.longPollPending, tsNow(), this.dcID, isClean, this);
if((this.longPollPending && tsNow() < this.longPollPending) ||
if((this.longPollPending && Date.now() < this.longPollPending) ||
this.offline ||
NetworkerFactory.akStopped) {
//this.log('No lp this time');
@ -307,7 +307,7 @@ class MTPNetworker { @@ -307,7 +307,7 @@ class MTPNetworker {
if(isClean && (
baseDcID != self.dcID ||
self.upload ||
(self.sleepAfter && tsNow() > self.sleepAfter)
(self.sleepAfter && Date.now() > self.sleepAfter)
)) {
//console.warn(dT(), 'Send long-poll for DC is delayed', self.dcID, self.sleepAfter);
return;
@ -320,7 +320,7 @@ class MTPNetworker { @@ -320,7 +320,7 @@ class MTPNetworker {
public sendLongPoll() {
let maxWait = 25000;
this.longPollPending = tsNow() + maxWait;
this.longPollPending = Date.now() + maxWait;
//this.log('Set lp', this.longPollPending, tsNow())
this.wrapMtpCall('http_wait', {
@ -364,7 +364,7 @@ class MTPNetworker { @@ -364,7 +364,7 @@ class MTPNetworker {
}
public pushResend(messageID: string, delay = 0) {
var value = delay ? tsNow() + delay : 0;
var value = delay ? Date.now() + delay : 0;
var sentMessage = this.sentMessages[messageID];
if(sentMessage.container) {
for(var i = 0; i < sentMessage.inner.length; i++) {
@ -548,7 +548,7 @@ class MTPNetworker { @@ -548,7 +548,7 @@ class MTPNetworker {
var messages: Message[] = [],
message: Message;
var messagesByteLen = 0;
var currentTime: number = tsNow();
var currentTime = Date.now();
var hasApiCall = false;
var hasHttpWait = false;
var lengthOverflow = false;
@ -952,7 +952,7 @@ class MTPNetworker { @@ -952,7 +952,7 @@ class MTPNetworker {
delay = 0;
} */
var nextReq = tsNow() + delay;
var nextReq = Date.now() + delay;
if(delay && this.nextReq && this.nextReq <= nextReq) {
return false;

5
src/lib/mtproto/timeManager.ts

@ -1,5 +1,4 @@ @@ -1,5 +1,4 @@
import AppStorage from '../storage';
import { tsNow } from '../utils';
import { nextRandomInt, longFromInts, dT } from '../bin_utils';
export class TimeManager {
@ -15,7 +14,7 @@ export class TimeManager { @@ -15,7 +14,7 @@ export class TimeManager {
}
public generateID(): string {
var timeTicks = tsNow(),
var timeTicks = Date.now(),
timeSec = Math.floor(timeTicks / 1000) + this.timeOffset,
timeMSec = timeTicks % 1000,
random = nextRandomInt(0xFFFF);
@ -34,7 +33,7 @@ export class TimeManager { @@ -34,7 +33,7 @@ export class TimeManager {
}
public applyServerTime(serverTime: number, localTime?: number) {
var newTimeOffset = serverTime - Math.floor((localTime || tsNow()) / 1000);
var newTimeOffset = serverTime - Math.floor((localTime || Date.now()) / 1000);
var changed = Math.abs(this.timeOffset - newTimeOffset) > 10;
AppStorage.set({
server_time_offset: newTimeOffset

11
src/lib/mtproto/tl_utils.ts

@ -5,10 +5,17 @@ @@ -5,10 +5,17 @@
* https://github.com/zhukov/webogram/blob/master/LICENSE
*/
import {bigint, intToUint, bigStringInt, bytesToHex, gzipUncompress, uintToInt} from '../bin_utils';
import {isObject} from '../utils';
import {bigint, intToUint, bigStringInt, bytesToHex, uintToInt, isObject} from '../bin_utils';
import Schema from './schema';
/// #if MTPROTO_WORKER
// @ts-ignore
import {gzipUncompress} from '../crypto/crypto_utils';
/// #else
// @ts-ignore
import {gzipUncompress} from '../bin_utils';
/// #endif
const boolFalse = +Schema.API.constructors.find((c: any) => c.predicate == 'boolFalse').id >>> 0;
const boolTrue = +Schema.API.constructors.find((c: any) => c.predicate == 'boolTrue').id >>> 0;
const vector = +Schema.API.constructors.find((c: any) => c.predicate == 'vector').id >>> 0;

4
src/lib/utils.js

@ -4,9 +4,9 @@ @@ -4,9 +4,9 @@
* Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>
* https://github.com/zhukov/webogram/blob/master/LICENSE
*/
var _logTimer = (new Date()).getTime()
var _logTimer = Date.now();
export function dT () {
return '[' + (((new Date()).getTime() - _logTimer) / 1000).toFixed(3) + ']'
return '[' + ((Date.now() - _logTimer) / 1000).toFixed(3) + ']'
}
export function checkClick (e, noprevent) {

2
src/pages/pageSignIn.ts

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
import { putPreloader, formatPhoneNumber } from "../components/misc";
import Scrollable from '../components/scrollable';
import Scrollable from '../components/scrollable_new';
import {RichTextProcessor} from '../lib/richtextprocessor';
import Config from '../lib/config';

6
src/scss/partials/_chat.scss

@ -125,14 +125,16 @@ $chat-max-width: 696px; @@ -125,14 +125,16 @@ $chat-max-width: 696px;
flex: 1 1 auto; /* Lets middle column shrink/grow to available width */
overflow: hidden;
position: relative;
padding: 0 .5rem;
> .scrollable {
//position: unset;
height: auto;
position: absolute;
/* position: absolute;
bottom: 0;
left: 0;
left: 0; */
position: relative;
//display: flex; // for end
//flex-direction: unset;

10
src/scss/partials/_emojiDropdown.scss

@ -108,8 +108,16 @@ @@ -108,8 +108,16 @@
content: "";
flex: auto;
} */
> div {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
}
> div > div {
width: 80px;
height: 80px;
display: flex;

49
src/scss/partials/_scrollable.scss

@ -45,11 +45,12 @@ div.scrollable::-webkit-scrollbar-thumb { @@ -45,11 +45,12 @@ div.scrollable::-webkit-scrollbar-thumb {
&.scrollable-y {
overflow-y: auto;
overflow-y: overlay;
scrollbar-width: none;
-ms-overflow-style: none;
}
&.scrollable-x ~ .scrollbar-thumb {
/* &.scrollable-x ~ .scrollbar-thumb {
top: auto;
right: auto;
width: auto;
@ -63,10 +64,10 @@ div.scrollable::-webkit-scrollbar-thumb { @@ -63,10 +64,10 @@ div.scrollable::-webkit-scrollbar-thumb {
&:first-child + * {
flex: 1 1 auto;
}
}
} */
}
.scrollbar-thumb {
/* .scrollbar-thumb {
position: absolute;
top: 0;
right: 2px;
@ -80,7 +81,7 @@ div.scrollable::-webkit-scrollbar-thumb { @@ -80,7 +81,7 @@ div.scrollable::-webkit-scrollbar-thumb {
transition-duration: .2s;
transition-timing-function: ease-in-out;
//display: none;
display: none;
border-radius: $border-radius;
z-index: 2;
@ -88,4 +89,42 @@ div.scrollable::-webkit-scrollbar-thumb { @@ -88,4 +89,42 @@ div.scrollable::-webkit-scrollbar-thumb {
:hover > .scrollbar-thumb {
opacity: .4;
}
} */
// BROWSER SCROLL
div.scrollable-y::-webkit-scrollbar {
width: .375rem;
height: 200px;
}
/* div.scrollable-y::-webkit-scrollbar-thumb {
border: 2px solid rgba(0, 0, 0, 0);
background-clip: padding-box;
} */
::-webkit-scrollbar-thumb {
opacity: 0;
transition: .2s ease-in-out;
}
div.scrollable:hover::-webkit-scrollbar-thumb {
height: 200px;
border-radius: $border-radius-medium;
background-color: rgba(0, 0, 0, 0.2);
opacity: 1;
}
::-webkit-scrollbar-button {
width: 0;
height: 0;
display: none;
}
::-webkit-scrollbar-corner {
background-color: transparent;
}

27952
stats.json

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