Browse Source

Removed scrollable virtualization

Chatlist slicing (need test)
master
Eduard Kuzmenko 4 years ago
parent
commit
9ec40ea9e9
  1. 4
      src/components/emoticonsDropdown/tabs/emoji.ts
  2. 2
      src/components/emoticonsDropdown/tabs/gifs.ts
  3. 21
      src/components/emoticonsDropdown/tabs/stickers.ts
  4. 339
      src/components/scrollable.ts
  5. 2
      src/components/sidebarLeft/tabs/archivedTab.ts
  6. 3
      src/components/sidebarRight/tabs/gifs.ts
  7. 2
      src/components/sidebarRight/tabs/pollResults.ts
  8. 2
      src/components/sidebarRight/tabs/sharedMedia.ts
  9. 5
      src/components/sidebarRight/tabs/stickers.ts
  10. 2
      src/helpers/date.ts
  11. 5
      src/lib/appManagers/apiUpdatesManager.ts
  12. 5
      src/lib/appManagers/appChatsManager.ts
  13. 208
      src/lib/appManagers/appDialogsManager.ts
  14. 13
      src/lib/appManagers/appImManager.ts
  15. 18
      src/lib/appManagers/appMessagesManager.ts
  16. 2
      src/lib/appManagers/appPeersManager.ts
  17. 5
      src/lib/appManagers/appPhotosManager.ts
  18. 5
      src/lib/appManagers/appUsersManager.ts
  19. 2
      src/lib/rootScope.ts
  20. 62
      src/lib/services.ts
  21. 5
      src/pages/pageIm.ts

4
src/components/emoticonsDropdown/tabs/emoji.ts

@ -81,7 +81,7 @@ export default class EmojiTab implements EmoticonsTab {
//console.timeEnd('emojiParse'); //console.timeEnd('emojiParse');
const menu = this.content.previousElementSibling as HTMLElement; const menu = this.content.previousElementSibling as HTMLElement;
const emojiScroll = this.scroll = new Scrollable(this.content, 'EMOJI', null); const emojiScroll = this.scroll = new Scrollable(this.content, 'EMOJI');
//emojiScroll.setVirtualContainer(emojiScroll.container); //emojiScroll.setVirtualContainer(emojiScroll.container);
@ -111,7 +111,7 @@ export default class EmojiTab implements EmoticonsTab {
console.error('no div by category:', category); console.error('no div by category:', category);
} }
emojiScroll.append(div); emojiScroll.container.append(div);
this.stickyIntersector.observeStickyHeaderChanges(div); this.stickyIntersector.observeStickyHeaderChanges(div);
return div; return div;
}); });

2
src/components/emoticonsDropdown/tabs/gifs.ts

@ -13,7 +13,7 @@ export default class GifsTab implements EmoticonsTab {
const gifsContainer = this.content.firstElementChild as HTMLDivElement; const gifsContainer = this.content.firstElementChild as HTMLDivElement;
gifsContainer.addEventListener('click', EmoticonsDropdown.onMediaClick); gifsContainer.addEventListener('click', EmoticonsDropdown.onMediaClick);
const scroll = new Scrollable(this.content, 'GIFS', null); const scroll = new Scrollable(this.content, 'GIFS');
const masonry = new GifsMasonry(gifsContainer, EMOTICONSSTICKERGROUP, scroll); const masonry = new GifsMasonry(gifsContainer, EMOTICONSSTICKERGROUP, scroll);
const preloader = putPreloader(this.content, true); const preloader = putPreloader(this.content, true);

21
src/components/emoticonsDropdown/tabs/stickers.ts

@ -18,6 +18,7 @@ import { wrapSticker } from "../../wrappers";
export default class StickersTab implements EmoticonsTab { export default class StickersTab implements EmoticonsTab {
public content: HTMLElement; public content: HTMLElement;
private stickersDiv: HTMLElement;
private stickerSets: {[id: string]: { private stickerSets: {[id: string]: {
stickers: HTMLElement, stickers: HTMLElement,
@ -66,12 +67,12 @@ export default class StickersTab implements EmoticonsTab {
this.queueCategoryPush.forEach(({element, prepend}) => { this.queueCategoryPush.forEach(({element, prepend}) => {
if(prepend) { if(prepend) {
if(this.recentDiv.parentElement) { if(this.recentDiv.parentElement) {
this.scroll.prepend(element); this.stickersDiv.prepend(element);
this.scroll.prepend(this.recentDiv); this.stickersDiv.prepend(this.recentDiv);
} else { } else {
this.scroll.prepend(element); this.stickersDiv.prepend(element);
} }
} else this.scroll.append(element); } else this.stickersDiv.append(element);
}); });
this.queueCategoryPush.length = 0; this.queueCategoryPush.length = 0;
@ -234,9 +235,9 @@ export default class StickersTab implements EmoticonsTab {
let menuScroll = new ScrollableX(menuWrapper); let menuScroll = new ScrollableX(menuWrapper);
let stickersDiv = document.createElement('div'); this.stickersDiv = document.createElement('div');
stickersDiv.classList.add('stickers-categories'); this.stickersDiv.classList.add('stickers-categories');
this.content.append(stickersDiv); this.content.append(this.stickersDiv);
/* stickersDiv.addEventListener('mouseover', (e) => { /* stickersDiv.addEventListener('mouseover', (e) => {
let target = e.target as HTMLElement; let target = e.target as HTMLElement;
@ -274,10 +275,10 @@ export default class StickersTab implements EmoticonsTab {
} }
}); });
stickersDiv.addEventListener('click', EmoticonsDropdown.onMediaClick); this.stickersDiv.addEventListener('click', EmoticonsDropdown.onMediaClick);
this.scroll = new Scrollable(this.content, 'STICKERS', undefined, undefined, 2); this.scroll = new Scrollable(this.content, 'STICKERS');
this.scroll.setVirtualContainer(stickersDiv); this.scroll.setVirtualContainer(this.stickersDiv);
this.stickyIntersector = EmoticonsDropdown.menuOnClick(this.menu, this.scroll, menuScroll); this.stickyIntersector = EmoticonsDropdown.menuOnClick(this.menu, this.scroll, menuScroll);

339
src/components/scrollable.ts

@ -2,8 +2,6 @@ import { CancellablePromise, deferredPromise } from "../helpers/cancellablePromi
import { isTouchSupported } from "../helpers/touchSupport"; import { isTouchSupported } from "../helpers/touchSupport";
import { logger, LogLevels } from "../lib/logger"; import { logger, LogLevels } from "../lib/logger";
import smoothscroll, { SCROLL_TIME, SmoothScrollToOptions } from '../vendor/smoothscroll'; import smoothscroll, { SCROLL_TIME, SmoothScrollToOptions } from '../vendor/smoothscroll';
//import { CancellablePromise, deferredPromise } from "../lib/polyfill";
//import { isInDOM } from "../lib/utils";
(window as any).__forceSmoothScrollPolyfill__ = true; (window as any).__forceSmoothScrollPolyfill__ = true;
smoothscroll(); smoothscroll();
/* /*
@ -58,13 +56,9 @@ export class ScrollableBase {
public scrollLocked = 0; public scrollLocked = 0;
public scrollLockedPromise: CancellablePromise<void> = Promise.resolve(); public scrollLockedPromise: CancellablePromise<void> = Promise.resolve();
constructor(public el: HTMLElement, logPrefix = '', public appendTo = el, public container: HTMLElement = document.createElement('div')) { constructor(public el: HTMLElement, logPrefix = '', public container: HTMLElement = document.createElement('div')) {
this.container.classList.add('scrollable'); this.container.classList.add('scrollable');
if(!appendTo) {
this.appendTo = this.container;
}
this.log = logger('SCROLL' + (logPrefix ? '-' + logPrefix : ''), LogLevels.error); this.log = logger('SCROLL' + (logPrefix ? '-' + logPrefix : ''), LogLevels.error);
if(el) { if(el) {
@ -80,20 +74,8 @@ export class ScrollableBase {
this.container.addEventListener('scroll', this.onScroll, {passive: true, capture: true}); this.container.addEventListener('scroll', this.onScroll, {passive: true, capture: true});
} }
public prepend(element: HTMLElement) {
this.appendTo.prepend(element);
}
public append(element: HTMLElement) { public append(element: HTMLElement) {
this.appendTo.append(element); this.container.append(element);
}
public contains(element: Element) {
return !!element.parentElement;
}
public removeElement(element: Element) {
element.remove();
} }
public scrollTo(value: number, side: 'top' | 'left', smooth = true, important = false, scrollTime = SCROLL_TIME) { public scrollTo(value: number, side: 'top' | 'left', smooth = true, important = false, scrollTime = SCROLL_TIME) {
@ -134,12 +116,11 @@ export class ScrollableBase {
this.container.dispatchEvent(new CustomEvent('scroll')); this.container.dispatchEvent(new CustomEvent('scroll'));
} }
} }
get length() {
return this.appendTo.childElementCount;
}
} }
export type SliceSides = 'top' | 'bottom';
export type SliceSidesContainer = {[k in SliceSides]: boolean};
export default class Scrollable extends ScrollableBase { export default class Scrollable extends ScrollableBase {
public splitUp: HTMLElement; public splitUp: HTMLElement;
@ -150,230 +131,30 @@ export default class Scrollable extends ScrollableBase {
public lastScrollTop: number = 0; public lastScrollTop: number = 0;
private disableHoverTimeout: number = 0; public loadedAll: SliceSidesContainer = {top: true, bottom: false};
/* private sentinelsObserver: IntersectionObserver;
private topSentinel: HTMLDivElement;
private bottomSentinel: HTMLDivElement; */
private observer: IntersectionObserver;
private visible: Set<HTMLElement>;
private virtualTempIDTop = 0;
private virtualTempIDBottom = 0;
private lastTopID = 0;
private lastBottomID = 0;
private lastScrollDirection = 0; // true = bottom
/* private onScrolledTopFired = false;
private onScrolledBottomFired = false; */
public isVisible = false;
private reorderTimeout: number;
private setVisible(element: HTMLElement) { constructor(el: HTMLElement, logPrefix = '', public onScrollOffset = 300) {
if(this.visible.has(element)) return; super(el, logPrefix);
this.log.debug('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.log.debug('setHidden id:', element.dataset.virtual);
(element.firstElementChild as HTMLElement).style.display = 'none';
this.visible.delete(element);
}
constructor(el: HTMLElement, logPrefix = '', appendTo = el, public onScrollOffset = 300, public splitCount = 15, container: HTMLElement = document.createElement('div')) {
super(el, logPrefix, appendTo, container);
this.visible = new Set();
this.observer = new IntersectionObserver(entries => {
const filtered = entries.filter(entry => entry.isIntersecting);
//return;
//this.log('entries:', entries);
entries.forEach(entry => {
const target = entry.target as HTMLElement;
if(entry.isIntersecting) {
this.setVisible(target);
this.log.debug('intersection entry:', entry, this.lastTopID, this.lastBottomID);
} else {
const id = +target.dataset.virtual;
const 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 || this.lastScrollDirection === 0) {
return;
}
if(this.lastScrollDirection === 1) { // 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.log.debug('entries:', entries, filtered, this.lastScrollDirection, this.lastTopID, this.lastBottomID);
const minVisibleID = this.lastTopID - this.splitCount;
const maxVisibleID = this.lastBottomID + this.splitCount;
for(const target of this.visible) {
const id = +target.dataset.virtual;
if(id < minVisibleID || id > maxVisibleID) {
this.setHidden(target);
}
}
});
this.container.classList.add('scrollable-y'); this.container.classList.add('scrollable-y');
//this.onScroll();
this.setListeners(); this.setListeners();
} }
// public attachSentinels(container = this.container, offset = this.onScrollOffset) {
// if(!this.sentinelsObserver) {
// this.topSentinel = document.createElement('div');
// this.topSentinel.classList.add('scrollable-sentinel');
// this.topSentinel.style.top = offset + 'px';
// this.bottomSentinel = document.createElement('div');
// this.bottomSentinel.classList.add('scrollable-sentinel');
// this.bottomSentinel.style.bottom = offset + 'px';
// this.container.append(this.topSentinel, this.bottomSentinel);
// //let fire: () => void;
// this.sentinelsObserver = new IntersectionObserver(entries => {
// for(let entry of entries) {
// let top = entry.target == this.topSentinel;
// if(top) {
// this.onScrolledTopFired = entry.isIntersecting;
// } else {
// this.onScrolledBottomFired = entry.isIntersecting;
// }
// }
// /* this.debug && */this.log('Set onScrolledFires:', this.onScrolledTopFired, this.onScrolledBottomFired);
// /* if((this.onScrolledTopFired || this.onScrolledBottomFired) && !fire) {
// fire = () => window.requestAnimationFrame(() => {
// if(!this.scrollLocked) {
// if(this.onScrolledTopFired && this.onScrolledTop) this.onScrolledTop();
// if(this.onScrolledBottomFired && this.onScrolledBottom) this.onScrolledBottom();
// }
// if(!this.onScrolledTopFired && !this.onScrolledBottomFired) {
// fire = undefined;
// } else {
// fire();
// }
// });
// fire();
// } */
// });
// this.sentinelsObserver.observe(this.topSentinel);
// this.sentinelsObserver.observe(this.bottomSentinel);
// }
// container.prepend(this.topSentinel);
// container.append(this.bottomSentinel);
// }
public setVirtualContainer(el?: HTMLElement) { public setVirtualContainer(el?: HTMLElement) {
this.splitUp = el; this.splitUp = el;
this.lastScrollTop = 0;
this.log('setVirtualContainer:', el, this); this.log('setVirtualContainer:', el, this);
} }
public onScroll = () => { public onScroll = () => {
/* let scrollTop = this.scrollTop;
this.lastScrollDirection = this.lastScrollTop < scrollTop;
this.lastScrollTop = scrollTop;
return; */
//if(!this.isVisible) return;
//if(this.debug) { //if(this.debug) {
//this.log('onScroll call', this.onScrollMeasure); //this.log('onScroll call', this.onScrollMeasure);
//} //}
//let appendTo = this.splitUp || this.appendTo;
// this.log('onScroll:', this.container.scrollTop);
// if(this.container.scrollTop <= 0) {
// /* touchSupport && */(this.container.style.overflow = 'hidden');
// this.scrollTop = 0;
// /* touchSupport && */(this.container.style.overflow = '');
// }
if(this.splitUp) {
clearTimeout(this.disableHoverTimeout);
this.disableHoverTimeout = window.setTimeout(() => {
//appendTo.classList.remove('disable-hover');
this.lastScrollDirection = 0;
}, 100);
}
/* if(this.el != this.appendTo && this.appendTo != this.container) {
if(!appendTo.classList.contains('disable-hover')) {
appendTo.classList.add('disable-hover');
}
} */
if(this.onScrollMeasure || ((this.scrollLocked || (!this.onScrolledTop && !this.onScrolledBottom)) && !this.splitUp)) return; if(this.onScrollMeasure || ((this.scrollLocked || (!this.onScrolledTop && !this.onScrolledBottom)) && !this.splitUp)) return;
this.onScrollMeasure = window.requestAnimationFrame(() => { this.onScrollMeasure = window.requestAnimationFrame(() => {
//if(!this.isVisible) return;
this.checkForTriggers(); this.checkForTriggers();
this.onScrollMeasure = 0; this.onScrollMeasure = 0;
if(!this.splitUp) return;
const scrollTop = this.scrollTop;
if(this.lastScrollTop != scrollTop) {
this.lastScrollDirection = this.lastScrollTop < scrollTop ? 1 : -1;
this.lastScrollTop = scrollTop;
} else {
this.lastScrollDirection = 0;
}
}); });
}; };
@ -400,73 +181,12 @@ export default class Scrollable extends ScrollableBase {
} }
} }
public reorder() { public prepend(element: HTMLElement) {
if(!this.splitUp || this.reorderTimeout) return; (this.splitUp || this.container).prepend(element);
this.reorderTimeout = window.setTimeout(() => {
this.reorderTimeout = 0;
(Array.from(this.splitUp.children) as HTMLElement[]).forEach((el, idx) => {
el.dataset.virtual = '' + idx;
});
}, 0);
}
public updateElement(element: HTMLElement) {
element.style.minHeight = '';
window.requestAnimationFrame(() => {
const height = element.scrollHeight;
window.requestAnimationFrame(() => {
element.style.minHeight = height + 'px';
});
});
}
public prepareElement(element: HTMLElement, append = true) {
if(!this.splitUp) return;
//return;
element.dataset.virtual = '' + (append ? this.virtualTempIDBottom++ : this.virtualTempIDTop--);
this.log.debug('prepareElement: prepared');
window.requestAnimationFrame(() => {
const {scrollHeight/* , scrollWidth */} = element;
this.log.debug('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 append(element: HTMLElement) {
(this.splitUp || this.container).append(element);
} }
public scrollIntoView(element: HTMLElement, smooth = true) { public scrollIntoView(element: HTMLElement, smooth = true) {
@ -491,14 +211,37 @@ export default class Scrollable extends ScrollableBase {
} }
} }
public removeElement(element: Element) {
element.remove();
}
public getScrollValue = () => { public getScrollValue = () => {
return this.scrollTop; return this.scrollTop;
}; };
public slice(side: SliceSides, safeCount: number/* sliceLength: number */) {
//const isOtherSideLoaded = this.loadedAll[side == 'top' ? 'bottom' : 'top'];
//const multiplier = 2 - +isOtherSideLoaded;
const multiplier = 2;
safeCount *= multiplier;
const length = this.splitUp.childElementCount;
if(length <= safeCount) {
return [];
}
const children = Array.from(this.splitUp.children) as HTMLElement[];
const sliced = side == 'top' ? children.slice(0, length - safeCount) : children.slice(safeCount);
for(const el of sliced) {
el.remove();
}
this.log.error('slice', side, length, sliced.length, this.splitUp.childElementCount);
if(sliced.length) {
this.loadedAll[side] = false;
}
return sliced;
}
get isScrolledDown() { get isScrolledDown() {
return this.scrollHeight - Math.round(this.scrollTop + this.container.offsetHeight) <= 1; return this.scrollHeight - Math.round(this.scrollTop + this.container.offsetHeight) <= 1;
} }
@ -518,8 +261,8 @@ export default class Scrollable extends ScrollableBase {
} }
export class ScrollableX extends ScrollableBase { export class ScrollableX extends ScrollableBase {
constructor(el: HTMLElement, logPrefix = '', public appendTo = el, public onScrollOffset = 300, public splitCount = 15, public container: HTMLElement = document.createElement('div')) { constructor(el: HTMLElement, logPrefix = '', public onScrollOffset = 300, public splitCount = 15, public container: HTMLElement = document.createElement('div')) {
super(el, logPrefix, appendTo, container); super(el, logPrefix, container);
this.container.classList.add('scrollable-x'); this.container.classList.add('scrollable-x');

2
src/components/sidebarLeft/tabs/archivedTab.ts

@ -11,7 +11,7 @@ export default class AppArchivedTab implements SliderTab {
public wasFilterID: number; public wasFilterID: number;
init() { init() {
this.scroll = new Scrollable(this.container, 'CLA', this.chatList, 500); this.scroll = new Scrollable(this.container, 'CLA', 500);
this.scroll.setVirtualContainer(this.chatList); this.scroll.setVirtualContainer(this.chatList);
this.scroll.onScrolledBottom = appDialogsManager.onChatsScroll; this.scroll.onScrolledBottom = appDialogsManager.onChatsScroll;
///this.scroll.attachSentinels(); ///this.scroll.attachSentinels();

3
src/components/sidebarRight/tabs/gifs.ts

@ -31,8 +31,7 @@ export default class AppGifsTab implements SliderTab {
private searchPromise: ReturnType<AppInlineBotsManager['getInlineResults']>; private searchPromise: ReturnType<AppInlineBotsManager['getInlineResults']>;
constructor() { constructor() {
this.scrollable = new Scrollable(this.contentDiv, ANIMATIONGROUP, undefined, undefined, 2); this.scrollable = new Scrollable(this.contentDiv, ANIMATIONGROUP);
this.scrollable.setVirtualContainer(this.gifsDiv);
this.masonry = new GifsMasonry(this.gifsDiv, ANIMATIONGROUP, this.scrollable); this.masonry = new GifsMasonry(this.gifsDiv, ANIMATIONGROUP, this.scrollable);

2
src/components/sidebarRight/tabs/pollResults.ts

@ -18,7 +18,7 @@ export default class AppPollResultsTab implements SliderTab {
private mid: number; private mid: number;
constructor() { constructor() {
this.scrollable = new Scrollable(this.contentDiv, 'POLL-RESULTS', undefined, undefined, 2); this.scrollable = new Scrollable(this.contentDiv, 'POLL-RESULTS');
} }
public cleanup() { public cleanup() {

2
src/components/sidebarRight/tabs/sharedMedia.ts

@ -131,7 +131,7 @@ export default class AppSharedMediaTab implements SliderTab {
let container = this.profileContentEl.querySelector('.content-container .tabs-container') as HTMLDivElement; let container = this.profileContentEl.querySelector('.content-container .tabs-container') as HTMLDivElement;
this.profileTabs = this.profileContentEl.querySelector('.profile-tabs'); this.profileTabs = this.profileContentEl.querySelector('.profile-tabs');
this.scroll = new Scrollable(this.container, 'SR', undefined, 400); this.scroll = new Scrollable(this.container, 'SR', 400);
this.scroll.onScrolledBottom = () => { this.scroll.onScrolledBottom = () => {
if(this.sharedMediaSelected && this.sharedMediaSelected.childElementCount/* && false */) { if(this.sharedMediaSelected && this.sharedMediaSelected.childElementCount/* && false */) {
//this.log('onScrolledBottom will load media'); //this.log('onScrolledBottom will load media');

5
src/components/sidebarRight/tabs/stickers.ts

@ -23,8 +23,7 @@ export default class AppStickersTab implements SliderTab {
private lazyLoadQueue: LazyLoadQueue; private lazyLoadQueue: LazyLoadQueue;
constructor() { constructor() {
this.scrollable = new Scrollable(this.contentDiv, 'STICKERS-SEARCH', undefined, undefined, 2); this.scrollable = new Scrollable(this.contentDiv, 'STICKERS-SEARCH');
this.scrollable.setVirtualContainer(this.setsDiv);
this.lazyLoadQueue = new LazyLoadQueue(); this.lazyLoadQueue = new LazyLoadQueue();
@ -176,7 +175,7 @@ export default class AppStickersTab implements SliderTab {
div.append(header, stickersDiv); div.append(header, stickersDiv);
this.scrollable.append(div); this.setsDiv.append(div);
} }
public init() { public init() {

2
src/helpers/date.ts

@ -21,7 +21,7 @@ export const formatDateAccordingToToday = (time: Date) => {
if((now - timestamp) < ONE_DAY && date.getDate() == time.getDate()) { // if the same day if((now - timestamp) < ONE_DAY && date.getDate() == time.getDate()) { // if the same day
timeStr = ('0' + time.getHours()).slice(-2) + ':' + ('0' + time.getMinutes()).slice(-2); timeStr = ('0' + time.getHours()).slice(-2) + ':' + ('0' + time.getMinutes()).slice(-2);
} else if(date.getFullYear() != time.getFullYear()) { // different year } else if(date.getFullYear() != time.getFullYear()) { // different year
timeStr = time.getDate() + '.' + (time.getMonth() + 1) + '.' + ('' + time.getFullYear()).slice(-2); timeStr = time.getDate() + '.' + ('0' + (time.getMonth() + 1)).slice(-2) + '.' + ('' + time.getFullYear()).slice(-2);
} else if((now - timestamp) < (ONE_DAY * 7) && getWeekNumber(date) == getWeekNumber(time)) { // current week } else if((now - timestamp) < (ONE_DAY * 7) && getWeekNumber(date) == getWeekNumber(time)) { // current week
timeStr = days[time.getDay()].slice(0, 3); timeStr = days[time.getDay()].slice(0, 3);
} else { // same year } else { // same year

5
src/lib/appManagers/apiUpdatesManager.ts

@ -1,6 +1,7 @@
//import apiManager from '../mtproto/apiManager'; //import apiManager from '../mtproto/apiManager';
import { logger, LogLevels } from '../logger'; import { logger, LogLevels } from '../logger';
import apiManager from '../mtproto/mtprotoworker'; import apiManager from '../mtproto/mtprotoworker';
import { MOUNT_CLASS_TO } from '../mtproto/mtproto_config';
import $rootScope from '../rootScope'; import $rootScope from '../rootScope';
//import networkerFactory from '../mtproto/networkerFactory'; //import networkerFactory from '../mtproto/networkerFactory';
import appChatsManager from "./appChatsManager"; import appChatsManager from "./appChatsManager";
@ -555,4 +556,6 @@ export class ApiUpdatesManager {
} }
} }
export default new ApiUpdatesManager(); const apiUpdatesManager = new ApiUpdatesManager();
MOUNT_CLASS_TO && (MOUNT_CLASS_TO.apiUpdatesManager = apiUpdatesManager);
export default apiUpdatesManager

5
src/lib/appManagers/appChatsManager.ts

@ -2,6 +2,7 @@ import { numberWithCommas } from "../../helpers/number";
import { isObject, safeReplaceObject, copy } from "../../helpers/object"; import { isObject, safeReplaceObject, copy } from "../../helpers/object";
import { ChatAdminRights, ChatBannedRights, ChatFull, ChatParticipants, InputChannel, InputChatPhoto, InputFile, InputPeer, Updates } from "../../layer"; import { ChatAdminRights, ChatBannedRights, ChatFull, ChatParticipants, InputChannel, InputChatPhoto, InputFile, InputPeer, Updates } from "../../layer";
import apiManager from '../mtproto/mtprotoworker'; import apiManager from '../mtproto/mtprotoworker';
import { MOUNT_CLASS_TO } from "../mtproto/mtproto_config";
import { RichTextProcessor } from "../richtextprocessor"; import { RichTextProcessor } from "../richtextprocessor";
import $rootScope from "../rootScope"; import $rootScope from "../rootScope";
import apiUpdatesManager from "./apiUpdatesManager"; import apiUpdatesManager from "./apiUpdatesManager";
@ -529,4 +530,6 @@ export class AppChatsManager {
} }
} }
export default new AppChatsManager(); const appChatsManager = new AppChatsManager();
MOUNT_CLASS_TO && (MOUNT_CLASS_TO.appChatsManager = appChatsManager);
export default appChatsManager;

208
src/lib/appManagers/appDialogsManager.ts

@ -4,7 +4,7 @@ import { horizontalMenu } from "../../components/horizontalMenu";
import { attachContextMenuListener, putPreloader } from "../../components/misc"; import { attachContextMenuListener, putPreloader } from "../../components/misc";
import { ripple } from "../../components/ripple"; import { ripple } from "../../components/ripple";
//import Scrollable from "../../components/scrollable"; //import Scrollable from "../../components/scrollable";
import Scrollable, { ScrollableX } from "../../components/scrollable"; import Scrollable, { ScrollableX, SliceSides, SliceSidesContainer } from "../../components/scrollable";
import appSidebarLeft from "../../components/sidebarLeft"; import appSidebarLeft from "../../components/sidebarLeft";
import { formatDateAccordingToToday } from "../../helpers/date"; import { formatDateAccordingToToday } from "../../helpers/date";
import { escapeRegExp } from "../../helpers/string"; import { escapeRegExp } from "../../helpers/string";
@ -20,6 +20,7 @@ import {MyDialogFilter as DialogFilter} from "../storages/filters";
import appPeersManager from './appPeersManager'; import appPeersManager from './appPeersManager';
import appStateManager from "./appStateManager"; import appStateManager from "./appStateManager";
import appUsersManager, { User } from "./appUsersManager"; import appUsersManager, { User } from "./appUsersManager";
import { MOUNT_CLASS_TO } from "../mtproto/mtproto_config";
type DialogDom = { type DialogDom = {
avatarEl: AvatarElement, avatarEl: AvatarElement,
@ -36,6 +37,7 @@ type DialogDom = {
}; };
const testScroll = false; const testScroll = false;
let testTopSlice = 1;
export class AppDialogsManager { export class AppDialogsManager {
public _chatList = document.getElementById('dialogs') as HTMLUListElement; public _chatList = document.getElementById('dialogs') as HTMLUListElement;
@ -52,7 +54,6 @@ export class AppDialogsManager {
private chatsPreloader: HTMLDivElement; private chatsPreloader: HTMLDivElement;
public loadDialogsPromise: Promise<any>; public loadDialogsPromise: Promise<any>;
public loadedAll = false;
public scroll: Scrollable = null; public scroll: Scrollable = null;
public _scroll: Scrollable = null; public _scroll: Scrollable = null;
@ -84,6 +85,8 @@ export class AppDialogsManager {
private accumulateArchivedTimeout: number; private accumulateArchivedTimeout: number;
private topOffsetIndex = 0;
constructor() { constructor() {
this.chatsPreloader = putPreloader(null, true); this.chatsPreloader = putPreloader(null, true);
@ -91,7 +94,8 @@ export class AppDialogsManager {
this.folders.menuScrollContainer = this.folders.menu.parentElement; this.folders.menuScrollContainer = this.folders.menu.parentElement;
this.scroll = this._scroll = new Scrollable(this.chatsContainer, 'CL', this.chatList, 500); this.scroll = this._scroll = new Scrollable(this.chatsContainer, 'CL', 500);
this.scroll.onScrolledTop = this.onChatsScrollTop;
this.scroll.onScrolledBottom = this.onChatsScroll; this.scroll.onScrolledBottom = this.onChatsScroll;
this.scroll.setVirtualContainer(this.chatList); this.scroll.setVirtualContainer(this.chatList);
//this.scroll.attachSentinels(); //this.scroll.attachSentinels();
@ -120,7 +124,7 @@ export class AppDialogsManager {
this.setListClickListener(this.chatList, null, true); this.setListClickListener(this.chatList, null, true);
/* if(testScroll) { if(testScroll) {
let i = 0; let i = 0;
let add = () => { let add = () => {
let li = document.createElement('li'); let li = document.createElement('li');
@ -130,11 +134,11 @@ export class AppDialogsManager {
i++; i++;
this.scroll.append(li); this.scroll.append(li);
}; };
for(let i = 0; i < 100; ++i) { for(let i = 0; i < 500; ++i) {
add(); add();
} }
(window as any).addElement = add; (window as any).addElement = add;
} */ }
$rootScope.$on('user_update', (e) => { $rootScope.$on('user_update', (e) => {
const userID = e.detail; const userID = e.detail;
@ -156,14 +160,14 @@ export class AppDialogsManager {
} }
}); });
$rootScope.$on('dialog_top', (e) => { /* $rootScope.$on('dialog_top', (e) => {
const dialog = e.detail; const dialog = e.detail;
this.setLastMessage(dialog); this.setLastMessage(dialog);
this.setDialogPosition(dialog); this.setDialogPosition(dialog);
this.setFiltersUnreadCount(); this.setFiltersUnreadCount();
}); }); */
$rootScope.$on('dialog_flush', (e) => { $rootScope.$on('dialog_flush', (e) => {
const peerID: number = e.detail.peerID; const peerID: number = e.detail.peerID;
@ -188,22 +192,21 @@ export class AppDialogsManager {
}); });
$rootScope.$on('dialog_drop', (e) => { $rootScope.$on('dialog_drop', (e) => {
let {peerID, dialog} = e.detail; const {peerID, dialog} = e.detail;
let dom = this.getDialogDom(peerID); const dom = this.getDialogDom(peerID);
if(dom) { if(dom) {
dom.listEl.remove(); dom.listEl.remove();
delete this.doms[peerID]; delete this.doms[peerID];
this.scroll.reorder();
} }
this.setFiltersUnreadCount(); this.setFiltersUnreadCount();
}); });
$rootScope.$on('dialog_unread', (e) => { $rootScope.$on('dialog_unread', (e) => {
let info = e.detail; const info = e.detail;
let dialog = appMessagesManager.getDialogByPeerID(info.peerID)[0]; const dialog = appMessagesManager.getDialogByPeerID(info.peerID)[0];
if(dialog) { if(dialog) {
this.setUnreadMessages(dialog); this.setUnreadMessages(dialog);
@ -327,7 +330,7 @@ export class AppDialogsManager {
//selectTab(0); //selectTab(0);
(this.folders.menu.firstElementChild.firstElementChild as HTMLElement).click(); (this.folders.menu.firstElementChild.firstElementChild as HTMLElement).click();
appStateManager.getState().then((state) => { appStateManager.getState().then((state) => {
const getFiltersPromise = !state.filters || Object.keys(state.filters).length ? appMessagesManager.filtersStorage.getDialogFilters() : Promise.resolve([]); const getFiltersPromise = appMessagesManager.filtersStorage.getDialogFilters();
getFiltersPromise.then((filters) => { getFiltersPromise.then((filters) => {
for(const filter of filters) { for(const filter of filters) {
this.addFilter(filter); this.addFilter(filter);
@ -340,6 +343,12 @@ export class AppDialogsManager {
this.accumulateArchivedUnread(); this.accumulateArchivedUnread();
}); });
}); });
/* const mutationObserver = new MutationObserver((mutationList, observer) => {
});
mutationObserver.observe */
} }
private updateDialog(dialog: Dialog) { private updateDialog(dialog: Dialog) {
@ -347,8 +356,18 @@ export class AppDialogsManager {
return; return;
} }
if(this.topOffsetIndex && dialog.index > this.topOffsetIndex) {
const dom = this.getDialogDom(dialog.peerID);
if(dom) {
dom.listEl.remove();
delete this.doms[dialog.peerID];
}
return;
}
if(!this.doms.hasOwnProperty(dialog.peerID)) { if(!this.doms.hasOwnProperty(dialog.peerID)) {
this.addDialog(dialog); this.addDialogNew({dialog});
} }
if(this.getDialogDom(dialog.peerID)) { if(this.getDialogDom(dialog.peerID)) {
@ -359,14 +378,16 @@ export class AppDialogsManager {
onTabChange = () => { onTabChange = () => {
this.doms = {}; this.doms = {};
this.loadedAll = false; this.topOffsetIndex = 0;
this.scroll.loadedAll.top = true;
this.scroll.loadedAll.bottom = false;
this.lastActiveListElement = null; this.lastActiveListElement = null;
this.loadDialogsPromise = undefined; this.loadDialogsPromise = undefined;
this.chatList = this.chatLists[this.filterID]; this.chatList = this.chatLists[this.filterID];
this.loadDialogs(); this.loadDialogs();
}; };
public setFilterUnreadCount(filterID: number, folder?: Dialog[]) { private setFilterUnreadCount(filterID: number, folder?: Dialog[]) {
const unreadSpan = filterID == 0 ? this.allUnreadCount : this.filtersRendered[filterID]?.unread; const unreadSpan = filterID == 0 ? this.allUnreadCount : this.filtersRendered[filterID]?.unread;
if(!unreadSpan) { if(!unreadSpan) {
return; return;
@ -378,7 +399,7 @@ export class AppDialogsManager {
unreadSpan.innerText = sum ? '' + sum : ''; unreadSpan.innerText = sum ? '' + sum : '';
} }
public setFiltersUnreadCount() { private setFiltersUnreadCount() {
for(const filterID in this.filtersRendered) { for(const filterID in this.filtersRendered) {
this.setFilterUnreadCount(+filterID); this.setFilterUnreadCount(+filterID);
} }
@ -389,12 +410,11 @@ export class AppDialogsManager {
/** /**
* Удалит неподходящие чаты из списка, но не добавит их(!) * Удалит неподходящие чаты из списка, но не добавит их(!)
*/ */
public validateForFilter() { private validateForFilter() {
// !WARNING, возможно это было зачем-то, но комментарий исправил архивирование // !WARNING, возможно это было зачем-то, но комментарий исправил архивирование
//if(this.filterID == 0) return; //if(this.filterID == 0) return;
const folder = appMessagesManager.dialogsStorage.getFolder(this.filterID); const folder = appMessagesManager.dialogsStorage.getFolder(this.filterID);
let affected = false;
for(const _peerID in this.doms) { for(const _peerID in this.doms) {
const peerID = +_peerID; const peerID = +_peerID;
@ -402,20 +422,16 @@ export class AppDialogsManager {
if(folder.findIndex((dialog) => dialog.peerID == peerID) === -1) { if(folder.findIndex((dialog) => dialog.peerID == peerID) === -1) {
const listEl = this.doms[peerID].listEl; const listEl = this.doms[peerID].listEl;
listEl.remove(); listEl.remove();
affected = true; delete this.doms[peerID];
if(this.lastActiveListElement == listEl) { if(this.lastActiveListElement == listEl) {
this.lastActiveListElement = null; this.lastActiveListElement = null;
} }
} }
} }
if(affected) {
this.scroll.reorder();
}
} }
public addFilter(filter: DialogFilter) { private addFilter(filter: DialogFilter) {
if(this.filtersRendered[filter.id]) return; if(this.filtersRendered[filter.id]) return;
const li = document.createElement('li'); const li = document.createElement('li');
@ -459,7 +475,7 @@ export class AppDialogsManager {
}; };
} }
public async loadDialogs() { private async loadDialogs(side: SliceSides = 'bottom') {
if(testScroll) { if(testScroll) {
return; return;
} }
@ -474,24 +490,42 @@ export class AppDialogsManager {
//return; //return;
const filterID = this.filterID; const filterID = this.filterID;
let loadCount = 30/*this.chatsLoadCount */;
const storage = appMessagesManager.dialogsStorage.getFolder(filterID); const storage = appMessagesManager.dialogsStorage.getFolder(filterID);
let offsetIndex = 0; let offsetIndex = 0;
for(let i = storage.length - 1; i >= 0; --i) { if(side == 'top') {
const element = this.chatList.firstElementChild;
if(element) {
const peerID = +element.getAttribute('data-peerID');
const index = storage.findIndex(dialog => dialog.peerID == peerID);
const needIndex = Math.max(0, index - loadCount);
loadCount = index - needIndex;
offsetIndex = storage[needIndex].index + 1;
}
} else {
const element = this.chatList.lastElementChild;
if(element) {
const peerID = +element.getAttribute('data-peerID');
const dialog = storage.find(dialog => dialog.peerID == peerID);
offsetIndex = dialog.index;
}
/* for(let i = storage.length - 1; i >= 0; --i) {
const dialog = storage[i]; const dialog = storage[i];
if(this.getDialogDom(dialog.peerID)) { if(this.getDialogDom(dialog.peerID)) {
offsetIndex = dialog.index; offsetIndex = dialog.index;
break; break;
} }
} */
} }
//let offset = storage[storage.length - 1]?.index || 0; //let offset = storage[storage.length - 1]?.index || 0;
try { try {
//console.time('getDialogs time'); //console.time('getDialogs time');
const loadCount = 50/*this.chatsLoadCount */;
const getConversationPromise = (this.filterID > 1 ? appUsersManager.getContacts() as Promise<any> : Promise.resolve()).then(() => { const getConversationPromise = (this.filterID > 1 ? appUsersManager.getContacts() as Promise<any> : Promise.resolve()).then(() => {
return appMessagesManager.getConversations('', offsetIndex, loadCount, filterID); return appMessagesManager.getConversations('', offsetIndex, loadCount, filterID);
}); });
@ -506,22 +540,58 @@ export class AppDialogsManager {
//console.timeEnd('getDialogs time'); //console.timeEnd('getDialogs time');
if(result && result.dialogs && result.dialogs.length) {
result.dialogs.forEach((dialog) => {
this.addDialog(dialog);
});
}
// * loaded all // * loaded all
//if(!result.dialogs.length || this.chatList.childElementCount == result.count) { //if(!result.dialogs.length || this.chatList.childElementCount == result.count) {
// !result.dialogs.length не подходит, так как при супердревном диалоге getConversations его не выдаст. // !result.dialogs.length не подходит, так как при супердревном диалоге getConversations его не выдаст.
if(this.chatList.childElementCount == result.count) { //if(this.chatList.childElementCount == result.count) {
this.loadedAll = true; if(side == 'bottom') {
if(result.isEnd) {
this.scroll.loadedAll[side] = true;
}
} else {
const storage = appMessagesManager.dialogsStorage.getFolder(filterID);
if(!result.dialogs.length || (storage.length && storage[0].index < offsetIndex)) {
this.scroll.loadedAll[side] = true;
}
}
if(result.dialogs.length) {
const dialogs = side == 'top' ? result.dialogs.slice().reverse() : result.dialogs;
dialogs.forEach((dialog) => {
this.addDialogNew({
dialog,
append: side == 'bottom'
});
});
//if(side == 'bottom' || true || (testTopSlice-- > 0 && side == 'top')) {
//setTimeout(() => {
const sliced = this.scroll.slice(side == 'bottom' ? 'top' : 'bottom', 30/* result.dialogs.length */);
sliced.forEach(el => {
const peerID = +el.getAttribute('data-peerID');
delete this.doms[peerID];
});
//}, 0);
//}
}
if(!this.scroll.loadedAll['top']) {
const element = this.chatList.firstElementChild;
if(element) {
const peerID = +element.getAttribute('data-peerID');
const dialog = appMessagesManager.getDialogByPeerID(peerID)[0];
this.topOffsetIndex = dialog.index;
}
} else {
this.topOffsetIndex = 0;
} }
this.log.debug('getDialogs ' + loadCount + ' dialogs by offset:', offsetIndex, result, this.chatList.childElementCount); this.log.debug('getDialogs ' + loadCount + ' dialogs by offset:', offsetIndex, result, this.chatList.childElementCount);
setTimeout(() => { setTimeout(() => {
/* setTimeout(() => {
this.scroll.slice(true);
}, 100); */
this.scroll.onScroll(); this.scroll.onScroll();
}, 0); }, 0);
} catch(err) { } catch(err) {
@ -532,11 +602,15 @@ export class AppDialogsManager {
this.loadDialogsPromise = undefined; this.loadDialogsPromise = undefined;
} }
onChatsScroll = () => { public onChatsScrollTop = () => {
if(this.loadedAll || this.loadDialogsPromise) return; this.onChatsScroll('top');
this.log('onChatsScroll'); };
this.loadDialogs();
} public onChatsScroll = (side: SliceSides = 'bottom') => {
if(this.scroll.loadedAll[side] || this.loadDialogsPromise) return;
this.log.error('onChatsScroll', side);
this.loadDialogs(side);
};
public setListClickListener(list: HTMLUListElement, onFound?: () => void, withContext = false) { public setListClickListener(list: HTMLUListElement, onFound?: () => void, withContext = false) {
list.addEventListener('mousedown', (e) => { list.addEventListener('mousedown', (e) => {
@ -588,28 +662,28 @@ export class AppDialogsManager {
} }
} }
public setDialogPosition(dialog: Dialog, pos?: number) { private setDialogPosition(dialog: Dialog) {
const dom = this.getDialogDom(dialog.peerID); const dom = this.getDialogDom(dialog.peerID);
if(!dom) { if(!dom) {
return; return;
} }
if(pos === undefined) { let pos = appMessagesManager.dialogsStorage.getDialog(dialog.peerID, this.filterID)[1];
pos = appMessagesManager.dialogsStorage.getDialog(dialog.peerID, this.filterID)[1]; if(this.topOffsetIndex) {
const element = this.chatList.firstElementChild;
if(element) {
const peerID = +element.getAttribute('data-peerID');
const firstDialog = appMessagesManager.getDialogByPeerID(peerID);
pos -= firstDialog[1];
}
} }
if(positionElementByIndex(dom.listEl, this.chatList, pos)) { if(positionElementByIndex(dom.listEl, this.chatList, pos)) {
this.scroll.reorder();
this.log.debug('setDialogPosition:', dialog, dom, pos); this.log.debug('setDialogPosition:', dialog, dom, pos);
} }
} }
public setLastMessage(dialog: any, lastMessage?: any, dom?: DialogDom, highlightWord?: string) { public setLastMessage(dialog: any, lastMessage?: any, dom?: DialogDom, highlightWord?: string) {
if(!lastMessage) {
lastMessage = appMessagesManager.getMessage(dialog.top_message);
}
///////console.log('setlastMessage:', lastMessage); ///////console.log('setlastMessage:', lastMessage);
if(!dom) { if(!dom) {
dom = this.getDialogDom(dialog.peerID); dom = this.getDialogDom(dialog.peerID);
@ -620,6 +694,10 @@ export class AppDialogsManager {
} }
} }
if(!lastMessage) {
lastMessage = appMessagesManager.getMessage(dialog.top_message);
}
if(lastMessage._ == 'messageEmpty' || (lastMessage._ == 'messageService' && !lastMessage.rReply)) { if(lastMessage._ == 'messageEmpty' || (lastMessage._ == 'messageService' && !lastMessage.rReply)) {
dom.lastMessageSpan.innerHTML = ''; dom.lastMessageSpan.innerHTML = '';
dom.lastTimeSpan.innerHTML = ''; dom.lastTimeSpan.innerHTML = '';
@ -700,7 +778,7 @@ export class AppDialogsManager {
} }
} }
public setUnreadMessages(dialog: Dialog) { private setUnreadMessages(dialog: Dialog) {
const dom = this.getDialogDom(dialog.peerID); const dom = this.getDialogDom(dialog.peerID);
if(dialog.folder_id == 1) { if(dialog.folder_id == 1) {
@ -765,7 +843,7 @@ export class AppDialogsManager {
} }
} }
public accumulateArchivedUnread() { private accumulateArchivedUnread() {
if(this.accumulateArchivedTimeout) return; if(this.accumulateArchivedTimeout) return;
this.accumulateArchivedTimeout = window.setTimeout(() => { this.accumulateArchivedTimeout = window.setTimeout(() => {
this.accumulateArchivedTimeout = 0; this.accumulateArchivedTimeout = 0;
@ -775,11 +853,23 @@ export class AppDialogsManager {
}, 0); }, 0);
} }
public getDialogDom(peerID: number) { private getDialogDom(peerID: number) {
return this.doms[peerID]; return this.doms[peerID];
} }
public addDialog(_dialog: Dialog | number, container?: HTMLUListElement | Scrollable, drawStatus = true, rippleEnabled = true, onlyFirstName = false, meAsSaved = true) { public addDialogNew(options: {
dialog: Dialog | number,
container?: HTMLUListElement | Scrollable,
drawStatus?: boolean,
rippleEnabled?: boolean,
onlyFirstName?: boolean,
meAsSaved?: boolean,
append?: boolean
}) {
return this.addDialog(options.dialog, options.container, options.drawStatus, options.rippleEnabled, options.onlyFirstName, options.meAsSaved, options.append);
}
public addDialog(_dialog: Dialog | number, container?: HTMLUListElement | Scrollable, drawStatus = true, rippleEnabled = true, onlyFirstName = false, meAsSaved = true, append = true) {
let dialog: Dialog; let dialog: Dialog;
if(typeof(_dialog) === 'number') { if(typeof(_dialog) === 'number') {
@ -939,8 +1029,9 @@ export class AppDialogsManager {
good = true; good = true;
} }
} */ } */
const method: 'append' | 'prepend' = append ? 'append' : 'prepend';
if(!container/* || good */) { if(!container/* || good */) {
this.scroll.append(li); this.scroll[method](li);
this.doms[dialog.peerID] = dom; this.doms[dialog.peerID] = dom;
@ -955,7 +1046,7 @@ export class AppDialogsManager {
this.setLastMessage(dialog); this.setLastMessage(dialog);
} else { } else {
container.append(li); container[method](li);
} }
return {dom, dialog}; return {dom, dialog};
@ -995,4 +1086,5 @@ export class AppDialogsManager {
} }
const appDialogsManager = new AppDialogsManager(); const appDialogsManager = new AppDialogsManager();
MOUNT_CLASS_TO && (MOUNT_CLASS_TO.appDialogsManager = appDialogsManager);
export default appDialogsManager; export default appDialogsManager;

13
src/lib/appManagers/appImManager.ts

@ -960,7 +960,7 @@ export class AppImManager {
} }
public setScroll() { public setScroll() {
this.scrollable = new Scrollable(this.bubblesContainer/* .firstElementChild */ as HTMLElement, 'IM', this.chatInner, 300); this.scrollable = new Scrollable(this.bubblesContainer/* .firstElementChild */ as HTMLElement, 'IM', 300);
/* const getScrollOffset = () => { /* const getScrollOffset = () => {
//return Math.round(Math.max(300, appPhotosManager.windowH / 1.5)); //return Math.round(Math.max(300, appPhotosManager.windowH / 1.5));
@ -1236,7 +1236,6 @@ export class AppImManager {
this.cleanup(); this.cleanup();
this.chatInner = document.createElement('div'); this.chatInner = document.createElement('div');
this.chatInner.id = 'bubbles-inner'; this.chatInner.id = 'bubbles-inner';
this.scrollable.appendTo = this.chatInner;
this.chatInner.className = oldChatInner.className; this.chatInner.className = oldChatInner.className;
this.chatInner.classList.add('disable-hover', 'is-scrolling'); this.chatInner.classList.add('disable-hover', 'is-scrolling');
@ -1473,7 +1472,7 @@ export class AppImManager {
this.bubbleGroups.removeBubble(bubble, mid); this.bubbleGroups.removeBubble(bubble, mid);
this.unreadedObserver.unobserve(bubble); this.unreadedObserver.unobserve(bubble);
//this.unreaded.findAndSplice(mid => mid == id); //this.unreaded.findAndSplice(mid => mid == id);
this.scrollable.removeElement(bubble); bubble.remove();
//bubble.remove(); //bubble.remove();
}); });
@ -1567,9 +1566,9 @@ export class AppImManager {
container.append(div); container.append(div);
if(reverse) { if(reverse) {
this.scrollable.prepend(container, false); this.chatInner.prepend(container);
} else { } else {
this.scrollable.append(container, false); this.chatInner.append(container);
} }
this.stickyIntersector.observeStickyHeaderChanges(container); this.stickyIntersector.observeStickyHeaderChanges(container);
@ -1715,7 +1714,7 @@ export class AppImManager {
const classNames = ['bubble'].concat(save.filter(c => wasClassNames.includes(c))); const classNames = ['bubble'].concat(save.filter(c => wasClassNames.includes(c)));
bubble.className = classNames.join(' '); bubble.className = classNames.join(' ');
bubbleContainer = bubble.firstElementChild as HTMLDivElement; bubbleContainer = bubble.lastElementChild as HTMLDivElement;
bubbleContainer.innerHTML = ''; bubbleContainer.innerHTML = '';
//bubbleContainer.style.marginBottom = ''; //bubbleContainer.style.marginBottom = '';
bubbleContainer.style.cssText = ''; bubbleContainer.style.cssText = '';
@ -2441,7 +2440,7 @@ export class AppImManager {
const method = (reverse ? history.shift : history.pop).bind(history); const method = (reverse ? history.shift : history.pop).bind(history);
//const padding = 99999; //const padding = 99999;
const realLength = this.scrollable.length; const realLength = this.scrollable.container.childElementCount;
let previousScrollHeightMinusTop: number/* , previousScrollHeight: number */; let previousScrollHeightMinusTop: number/* , previousScrollHeight: number */;
if(realLength > 0 && (reverse || isSafari)) { // for safari need set when scrolling bottom too if(realLength > 0 && (reverse || isSafari)) { // for safari need set when scrolling bottom too
this.messagesQueueOnRender = () => { this.messagesQueueOnRender = () => {

18
src/lib/appManagers/appMessagesManager.ts

@ -12,6 +12,7 @@ import { logger, LogLevels } from "../logger";
import type { ApiFileManager } from '../mtproto/apiFileManager'; import type { ApiFileManager } from '../mtproto/apiFileManager';
//import apiManager from '../mtproto/apiManager'; //import apiManager from '../mtproto/apiManager';
import apiManager from '../mtproto/mtprotoworker'; import apiManager from '../mtproto/mtprotoworker';
import { MOUNT_CLASS_TO } from "../mtproto/mtproto_config";
import referenceDatabase, { ReferenceContext } from "../mtproto/referenceDatabase"; import referenceDatabase, { ReferenceContext } from "../mtproto/referenceDatabase";
import serverTimeManager from "../mtproto/serverTimeManager"; import serverTimeManager from "../mtproto/serverTimeManager";
import { RichTextProcessor } from "../richtextprocessor"; import { RichTextProcessor } from "../richtextprocessor";
@ -1506,7 +1507,8 @@ export class AppMessagesManager {
if(query || this.dialogsStorage.allDialogsLoaded[realFolderID] || curDialogStorage.length >= offset + limit) { if(query || this.dialogsStorage.allDialogsLoaded[realFolderID] || curDialogStorage.length >= offset + limit) {
return Promise.resolve({ return Promise.resolve({
dialogs: curDialogStorage.slice(offset, offset + limit), dialogs: curDialogStorage.slice(offset, offset + limit),
count: this.dialogsStorage.allDialogsLoaded[realFolderID] ? curDialogStorage.length : null count: this.dialogsStorage.allDialogsLoaded[realFolderID] ? curDialogStorage.length : null,
isEnd: this.dialogsStorage.allDialogsLoaded[realFolderID] && (offset + limit) >= curDialogStorage.length
}); });
} }
@ -1526,7 +1528,8 @@ export class AppMessagesManager {
return { return {
dialogs: curDialogStorage.slice(offset, offset + limit), dialogs: curDialogStorage.slice(offset, offset + limit),
count: totalCount count: totalCount,
isEnd: this.dialogsStorage.allDialogsLoaded[realFolderID] && (offset + limit) >= curDialogStorage.length
}; };
}); });
} }
@ -1906,7 +1909,7 @@ export class AppMessagesManager {
message.peerID = peerID; message.peerID = peerID;
if(message.peerID == myID/* && !message.from_id && !message.fwd_from */) { if(message.peerID == myID/* && !message.from_id && !message.fwd_from */) {
message.fromID = message.fwd_from?.from_id ? appPeersManager.getPeerID(message.fwd_from.from_id) : myID; message.fromID = message.fwd_from ? (message.fwd_from.from_id ? appPeersManager.getPeerID(message.fwd_from.from_id) : 0) : myID;
} else { } else {
message.fromID = message.pFlags.post || (!message.pFlags.out && !message.from_id) ? peerID : appPeersManager.getPeerID(message.from_id); message.fromID = message.pFlags.post || (!message.pFlags.out && !message.from_id) ? peerID : appPeersManager.getPeerID(message.from_id);
} }
@ -2424,7 +2427,7 @@ export class AppMessagesManager {
} */ } */
if(topMessage) { if(topMessage) {
const wasDialogBefore = this.getDialogByPeerID(peerID)[0]; //const wasDialogBefore = this.getDialogByPeerID(peerID)[0];
// here need to just replace, not FULL replace dialog! WARNING // here need to just replace, not FULL replace dialog! WARNING
/* if(wasDialogBefore?.pFlags?.pinned && !dialog?.pFlags?.pinned) { /* if(wasDialogBefore?.pFlags?.pinned && !dialog?.pFlags?.pinned) {
@ -2435,12 +2438,12 @@ export class AppMessagesManager {
this.saveConversation(dialog); this.saveConversation(dialog);
if(wasDialogBefore) { /* if(wasDialogBefore) {
$rootScope.$broadcast('dialog_top', dialog); $rootScope.$broadcast('dialog_top', dialog);
} else { } else { */
updatedDialogs[peerID] = dialog; updatedDialogs[peerID] = dialog;
hasUpdated = true; hasUpdated = true;
} //}
} else { } else {
const dropped = this.dialogsStorage.dropDialog(peerID); const dropped = this.dialogsStorage.dropDialog(peerID);
if(dropped.length) { if(dropped.length) {
@ -4220,4 +4223,5 @@ export class AppMessagesManager {
} }
const appMessagesManager = new AppMessagesManager(); const appMessagesManager = new AppMessagesManager();
MOUNT_CLASS_TO && (MOUNT_CLASS_TO.appMessagesManager = appMessagesManager);
export default appMessagesManager; export default appMessagesManager;

2
src/lib/appManagers/appPeersManager.ts

@ -1,5 +1,6 @@
import { isObject } from "../../helpers/object"; import { isObject } from "../../helpers/object";
import { DialogPeer, InputDialogPeer, InputPeer, Peer } from "../../layer"; import { DialogPeer, InputDialogPeer, InputPeer, Peer } from "../../layer";
import { MOUNT_CLASS_TO } from "../mtproto/mtproto_config";
import { RichTextProcessor } from "../richtextprocessor"; import { RichTextProcessor } from "../richtextprocessor";
import $rootScope from "../rootScope"; import $rootScope from "../rootScope";
import appChatsManager from "./appChatsManager"; import appChatsManager from "./appChatsManager";
@ -230,4 +231,5 @@ export class AppPeersManager {
} }
const appPeersManager = new AppPeersManager(); const appPeersManager = new AppPeersManager();
MOUNT_CLASS_TO && (MOUNT_CLASS_TO.appPeersManager = appPeersManager);
export default appPeersManager; export default appPeersManager;

5
src/lib/appManagers/appPhotosManager.ts

@ -11,6 +11,7 @@ import { calcImageInBox } from "../../helpers/dom";
import { MyDocument } from "./appDocsManager"; import { MyDocument } from "./appDocsManager";
import appDownloadManager from "./appDownloadManager"; import appDownloadManager from "./appDownloadManager";
import appUsersManager from "./appUsersManager"; import appUsersManager from "./appUsersManager";
import { MOUNT_CLASS_TO } from "../mtproto/mtproto_config";
export type MyPhoto = Photo.photo; export type MyPhoto = Photo.photo;
@ -346,4 +347,6 @@ export class AppPhotosManager {
} }
} }
export default new AppPhotosManager(); const appPhotosManager = new AppPhotosManager();
MOUNT_CLASS_TO && (MOUNT_CLASS_TO.appPhotosManager = appPhotosManager);
export default appPhotosManager;

5
src/lib/appManagers/appUsersManager.ts

@ -4,6 +4,7 @@ import { safeReplaceObject, isObject } from "../../helpers/object";
import { InputUser, Update, User as MTUser, UserStatus } from "../../layer"; import { InputUser, Update, User as MTUser, UserStatus } from "../../layer";
//import apiManager from '../mtproto/apiManager'; //import apiManager from '../mtproto/apiManager';
import apiManager from '../mtproto/mtprotoworker'; import apiManager from '../mtproto/mtprotoworker';
import { MOUNT_CLASS_TO } from "../mtproto/mtproto_config";
import serverTimeManager from "../mtproto/serverTimeManager"; import serverTimeManager from "../mtproto/serverTimeManager";
import { RichTextProcessor } from "../richtextprocessor"; import { RichTextProcessor } from "../richtextprocessor";
import $rootScope from "../rootScope"; import $rootScope from "../rootScope";
@ -641,4 +642,6 @@ export class AppUsersManager {
} }
} }
export default new AppUsersManager(); const appUsersManager = new AppUsersManager();
MOUNT_CLASS_TO && (MOUNT_CLASS_TO.appUsersManager = appUsersManager);
export default appUsersManager

2
src/lib/rootScope.ts

@ -20,7 +20,7 @@ type BroadcastEvents = {
'dialog_flush': {peerID: number}, 'dialog_flush': {peerID: number},
'dialog_drop': {peerID: number, dialog?: Dialog}, 'dialog_drop': {peerID: number, dialog?: Dialog},
'dialog_migrate': {migrateFrom: number, migrateTo: number}, 'dialog_migrate': {migrateFrom: number, migrateTo: number},
'dialog_top': Dialog, //'dialog_top': Dialog,
'dialog_notify_settings': number, 'dialog_notify_settings': number,
'dialogs_multiupdate': {[peerID: string]: Dialog}, 'dialogs_multiupdate': {[peerID: string]: Dialog},
'dialogs_archived_unread': {count: number}, 'dialogs_archived_unread': {count: number},

62
src/lib/services.ts

@ -1,62 +0,0 @@
console.log('Services included!');
import AppMediaViewer from '../components/appMediaViewer';
import AppSidebarLeft from '../components/sidebarLeft';
import AppSidebarRight from '../components/sidebarRight';
import ApiUpdatesManager from './appManagers/apiUpdatesManager';
import AppChatsManager from './appManagers/appChatsManager';
import AppDialogsManager from './appManagers/appDialogsManager';
import AppDocsManager from './appManagers/appDocsManager';
import AppImManager from './appManagers/appImManager';
import AppMessagesIDsManager from './appManagers/appMessagesIDsManager';
import AppMessagesManager from './appManagers/appMessagesManager';
import AppPeersManager from './appManagers/appPeersManager';
import AppPhotosManager from './appManagers/appPhotosManager';
import AppProfileManager from './appManagers/appProfileManager';
import AppStickersManager from './appManagers/appStickersManager';
import AppUsersManager from './appManagers/appUsersManager';
//import AppSharedMediaManager from './appManagers/appSharedMediaManager';
const appUsersManager = AppUsersManager;
const appChatsManager = AppChatsManager;
const appMessagesIDsManager = AppMessagesIDsManager;
const apiUpdatesManager = ApiUpdatesManager;
const appPhotosManager = AppPhotosManager;
const appMessagesManager = AppMessagesManager;
const appProfileManager = AppProfileManager;
const appImManager = AppImManager;
const appPeersManager = AppPeersManager;
const appStickersManager = AppStickersManager;
const appDocsManager = AppDocsManager;
//export const appSharedMediaManager = AppSharedMediaManager;
const appSidebarRight = AppSidebarRight;
const appSidebarLeft = AppSidebarLeft;
const appMediaViewer = AppMediaViewer;
const appDialogsManager = AppDialogsManager;
const Services = {
appUsersManager,
appChatsManager,
apiUpdatesManager,
appMessagesManager,
appMessagesIDsManager,
appPeersManager,
appProfileManager,
appPhotosManager,
appDocsManager,
appDialogsManager,
appImManager,
appStickersManager,
appSidebarRight,
appSidebarLeft,
appMediaViewer
//appSharedMediaManager
};
(window as any).Services = Services;
for(let i in Services) {
// @ts-ignore
(window as any)[i] = Services[i];
}

5
src/pages/pageIm.ts

@ -1,7 +1,6 @@
//import {stackBlurImage} from '../lib/StackBlur'; //import {stackBlurImage} from '../lib/StackBlur';
//import appStateManager from "../lib/appManagers/appStateManager"; //import appStateManager from "../lib/appManagers/appStateManager";
import appStateManager from "../lib/appManagers/appStateManager"; import appStateManager from "../lib/appManagers/appStateManager";
import { DEBUG } from "../lib/mtproto/mtproto_config";
import Page from "./page"; import Page from "./page";
let onFirstMount = () => { let onFirstMount = () => {
@ -25,10 +24,6 @@ let onFirstMount = () => {
alert('navigator.mediaDevices.getUserMedia:' + typeof(navigator.mediaDevices?.getUserMedia)); alert('navigator.mediaDevices.getUserMedia:' + typeof(navigator.mediaDevices?.getUserMedia));
alert('global.WebAssembly:' + typeof(WebAssembly)); */ alert('global.WebAssembly:' + typeof(WebAssembly)); */
if(DEBUG) {
import('../lib/services');
}
//(Array.from(document.getElementsByClassName('rp')) as HTMLElement[]).forEach(el => ripple(el)); //(Array.from(document.getElementsByClassName('rp')) as HTMLElement[]).forEach(el => ripple(el));
const misc = await import("../components/buttonMenuToggle"); const misc = await import("../components/buttonMenuToggle");

Loading…
Cancel
Save