virtual scroll stickers & right sidebar & pinned dialogs & notify settings
This commit is contained in:
parent
be4205e5cc
commit
01b8e80e05
@ -8,6 +8,7 @@ import appDocsManager from "../lib/appManagers/appDocsManager";
|
||||
import {AppImManager} from "../lib/appManagers/appImManager";
|
||||
import {AppMediaViewer} from '../lib/appManagers/appMediaViewer';
|
||||
import { RichTextProcessor } from "../lib/richtextprocessor";
|
||||
import lottieLoader from "../lib/lottieLoader";
|
||||
|
||||
export type MTDocument = {
|
||||
_: 'document',
|
||||
@ -434,7 +435,8 @@ export function scrollable(el: HTMLDivElement, x = false, y = true) {
|
||||
resize();
|
||||
}
|
||||
|
||||
let splitUp = container.querySelector('ul');
|
||||
//let splitUp = container.querySelector('ul');
|
||||
let splitUp = container.children[1];
|
||||
let children = Array.from(splitUp.children) as HTMLElement[];
|
||||
let firstVisible = -1, lastVisible = -1;
|
||||
let length = children.length;
|
||||
@ -627,7 +629,15 @@ export function wrapSticker(doc: MTDocument, div: HTMLDivElement, middleware?: (
|
||||
}, {once: true});
|
||||
}
|
||||
});
|
||||
}
|
||||
} /* else {
|
||||
let canvas = div.firstElementChild as HTMLCanvasElement;
|
||||
if(!canvas.width && !canvas.height) {
|
||||
console.log('Need lottie resize');
|
||||
|
||||
// @ts-ignore
|
||||
animation.resize();
|
||||
}
|
||||
} */
|
||||
|
||||
if(play) {
|
||||
animation.play();
|
||||
|
@ -1,7 +1,8 @@
|
||||
//import { appImManager, appMessagesManager, appDialogsManager, apiUpdatesManager, appUsersManager } from "../lib/services";
|
||||
import { putPreloader, horizontalMenu, wrapSticker, MTDocument, LazyLoadQueue, scrollable } from "./misc";
|
||||
import { horizontalMenu, wrapSticker, MTDocument, LazyLoadQueue } from "./misc";
|
||||
import Scrollable from './scrollable';
|
||||
|
||||
import { isElementInViewport, whichChild, findUpTag } from "../lib/utils";
|
||||
import { whichChild, findUpTag } from "../lib/utils";
|
||||
import {stackBlurImage} from '../lib/StackBlur';
|
||||
import * as Config from '../lib/config';
|
||||
import { RichTextProcessor } from "../lib/richtextprocessor";
|
||||
@ -12,7 +13,6 @@ import CryptoWorker from '../lib/crypto/cryptoworker';
|
||||
import appStickersManager, { MTStickerSet } from "../lib/appManagers/appStickersManager";
|
||||
import { AppImManager } from "../lib/appManagers/appImManager";
|
||||
import { AppMessagesManager } from "../lib/appManagers/appMessagesManager";
|
||||
import appSidebarRight from "../lib/appManagers/appSidebarRight";
|
||||
import appSidebarLeft from "../lib/appManagers/appSidebarLeft";
|
||||
|
||||
const EMOTICONSSTICKERGROUP = 'emoticons-dropdown';
|
||||
@ -176,12 +176,13 @@ let initEmoticonsDropdown = (pageEl: HTMLDivElement,
|
||||
|
||||
let prevCategoryIndex = 1;
|
||||
let menu = contentEmojiDiv.nextElementSibling as HTMLUListElement;
|
||||
let emojiScroll = scrollable(contentEmojiDiv).container;
|
||||
emojiScroll.addEventListener('scroll', (e) => {
|
||||
prevCategoryIndex = emoticonsContentOnScroll(menu, heights, prevCategoryIndex, emojiScroll);
|
||||
let emojiScroll = new Scrollable(contentEmojiDiv);
|
||||
emojiScroll.container.addEventListener('scroll', (e) => {
|
||||
prevCategoryIndex = emoticonsContentOnScroll(menu, heights, prevCategoryIndex, emojiScroll.container);
|
||||
});
|
||||
//emojiScroll.setVirtualContainer(emojiScroll.container);
|
||||
|
||||
emoticonsMenuOnClick(menu, heights, emojiScroll);
|
||||
emoticonsMenuOnClick(menu, heights, emojiScroll.container);
|
||||
}
|
||||
|
||||
let stickersInit = () => {
|
||||
@ -191,7 +192,7 @@ let initEmoticonsDropdown = (pageEl: HTMLDivElement,
|
||||
let menuWrapper = contentStickersDiv.nextElementSibling as HTMLDivElement;
|
||||
let menu = menuWrapper.firstElementChild as HTMLUListElement;
|
||||
|
||||
let menuScroll = scrollable(menuWrapper, true, false);
|
||||
let menuScroll = new Scrollable(menuWrapper, true, false);
|
||||
|
||||
let stickersDiv = document.createElement('div');
|
||||
stickersDiv.classList.add('stickers-categories');
|
||||
@ -265,6 +266,8 @@ let initEmoticonsDropdown = (pageEl: HTMLDivElement,
|
||||
heights[i] = (heights[i - 1] || 0) + div.scrollHeight;
|
||||
});
|
||||
|
||||
//stickersScroll.onScroll();
|
||||
|
||||
//return heights.push(prevHeight + scrollHeight) - 1;
|
||||
};
|
||||
|
||||
@ -342,15 +345,16 @@ let initEmoticonsDropdown = (pageEl: HTMLDivElement,
|
||||
});
|
||||
|
||||
let prevCategoryIndex = 0;
|
||||
let stickersScroll = scrollable(contentStickersDiv).container;
|
||||
stickersScroll.addEventListener('scroll', (e) => {
|
||||
let stickersScroll = new Scrollable(contentStickersDiv);
|
||||
stickersScroll.container.addEventListener('scroll', (e) => {
|
||||
lazyLoadQueue.check();
|
||||
lottieLoader.checkAnimations();
|
||||
|
||||
prevCategoryIndex = emoticonsContentOnScroll(menu, heights, prevCategoryIndex, stickersScroll);
|
||||
prevCategoryIndex = emoticonsContentOnScroll(menu, heights, prevCategoryIndex, stickersScroll.container);
|
||||
});
|
||||
stickersScroll.setVirtualContainer(stickersDiv);
|
||||
|
||||
emoticonsMenuOnClick(menu, heights, stickersScroll);
|
||||
emoticonsMenuOnClick(menu, heights, stickersScroll.container);
|
||||
|
||||
stickersInit = null;
|
||||
};
|
||||
@ -367,8 +371,7 @@ export default () => import('../lib/services').then(services => {
|
||||
let pageEl = document.body.getElementsByClassName('page-chats')[0] as HTMLDivElement;
|
||||
pageEl.style.display = '';
|
||||
|
||||
let sidebarScroll = scrollable(document.body.querySelector('.profile-container')).container;
|
||||
let chatScroll = scrollable(document.getElementById('bubbles') as HTMLDivElement).container;
|
||||
let chatScroll = new Scrollable(document.getElementById('bubbles') as HTMLDivElement).container;
|
||||
|
||||
apiUpdatesManager.attach();
|
||||
|
||||
@ -577,7 +580,7 @@ export default () => import('../lib/services').then(services => {
|
||||
|
||||
let inputMessageContainer = document.getElementsByClassName('input-message-container')[0] as HTMLDivElement;
|
||||
|
||||
let inputScroll = scrollable(inputMessageContainer);
|
||||
let inputScroll = new Scrollable(inputMessageContainer);
|
||||
|
||||
let sendMessage = () => {
|
||||
let str = serializeNodes(Array.from(messageInput.childNodes));
|
||||
@ -744,6 +747,5 @@ export default () => import('../lib/services').then(services => {
|
||||
appSidebarLeft.loadDialogs().then(result => {
|
||||
appSidebarLeft.onChatsScroll();
|
||||
appImManager.setScroll(chatScroll);
|
||||
appSidebarRight.setScroll(sidebarScroll);
|
||||
});
|
||||
});
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { MTProto } from "../lib/mtproto/mtproto";
|
||||
import { putPreloader, getNearestDc, scrollable, formatPhoneNumber } from "./misc";
|
||||
import { putPreloader, getNearestDc, formatPhoneNumber } from "./misc";
|
||||
import Scrollable from './scrollable';
|
||||
import {RichTextProcessor} from '../lib/richtextprocessor';
|
||||
import * as Config from '../lib/config';
|
||||
|
||||
@ -51,7 +52,7 @@ export default () => {
|
||||
wrapper.appendChild(list);
|
||||
|
||||
//let wrapperScroll = OverlayScrollbars(wrapper, (window as any).scrollbarOptions);
|
||||
scrollable(wrapper);
|
||||
let scroll = new Scrollable(wrapper);
|
||||
|
||||
let initedSelect = false;
|
||||
|
||||
|
244
src/components/scrollable.ts
Normal file
244
src/components/scrollable.ts
Normal file
@ -0,0 +1,244 @@
|
||||
import { isElementInViewport, isScrolledIntoView } from "../lib/utils";
|
||||
|
||||
export default class Scrollable {
|
||||
public container: HTMLDivElement;
|
||||
public thumb: HTMLDivElement;
|
||||
|
||||
public type: string;
|
||||
public side: string;
|
||||
public scrollType: string;
|
||||
public scrollSide: string;
|
||||
|
||||
public scrollSize = -1;
|
||||
public size = 0;
|
||||
public thumbSize = 0;
|
||||
|
||||
public hiddenElements: {
|
||||
up: Element[],
|
||||
down: Element[]
|
||||
} = {
|
||||
up: [],
|
||||
down: []
|
||||
};
|
||||
public paddings = {up: 0, down: 0};
|
||||
|
||||
public paddingTopDiv: HTMLDivElement;
|
||||
public paddingBottomDiv: HTMLDivElement;
|
||||
|
||||
public splitUp: HTMLElement;
|
||||
|
||||
/* public topObserver: IntersectionObserver;
|
||||
public isTopIntersecting: boolean;
|
||||
public bottomObserver: IntersectionObserver;
|
||||
public isBottomIntersecting: boolean; */
|
||||
|
||||
constructor(public el: HTMLDivElement, x = false, y = true) {
|
||||
this.container = document.createElement('div');
|
||||
this.container.classList.add('scrollable');
|
||||
|
||||
/* this.bottomObserver = new IntersectionObserver(entries => {
|
||||
let entry = entries[0];
|
||||
|
||||
this.isBottomIntersecting = entry.intersectionRatio > 0;
|
||||
|
||||
// @ts-ignore
|
||||
//console.log('bottom instersection:', entry, entry.isVisible, entry.intersectionRatio, entry.isIntersecting);
|
||||
console.log('bottom intersection:', this.isBottomIntersecting);
|
||||
});
|
||||
|
||||
this.topObserver = new IntersectionObserver(entries => {
|
||||
let entry = entries[0];
|
||||
|
||||
this.isTopIntersecting = entry.intersectionRatio > 0;
|
||||
|
||||
// @ts-ignore
|
||||
//console.log('top instersection:', entry, entry.isVisible, entry.intersectionRatio, entry.isIntersecting);
|
||||
console.log('top intersection:', this.isTopIntersecting);
|
||||
}); */
|
||||
|
||||
if(x) {
|
||||
this.container.classList.add('scrollable-x');
|
||||
this.type = 'width';
|
||||
this.side = 'left';
|
||||
this.scrollType = 'scrollWidth';
|
||||
this.scrollSide = 'scrollLeft';
|
||||
} else if(y) {
|
||||
this.container.classList.add('scrollable-y');
|
||||
this.type = 'height';
|
||||
this.side = 'top';
|
||||
this.scrollType = 'scrollHeight';
|
||||
this.scrollSide = 'scrollTop';
|
||||
} else {
|
||||
throw new Error('no side for scroll');
|
||||
}
|
||||
|
||||
this.thumb = document.createElement('div');
|
||||
this.thumb.className = 'scrollbar-thumb';
|
||||
|
||||
// @ts-ignore
|
||||
this.thumb.style[this.type] = '30px';
|
||||
|
||||
this.container.addEventListener('mouseover', this.resize.bind(this));
|
||||
window.addEventListener('resize', this.resize.bind(this));
|
||||
|
||||
this.paddingTopDiv = document.createElement('div');
|
||||
this.paddingTopDiv.classList.add('scroll-padding');
|
||||
this.paddingBottomDiv = document.createElement('div');
|
||||
this.paddingBottomDiv.classList.add('scroll-padding');
|
||||
|
||||
this.container.addEventListener('scroll', this.onScroll.bind(this));
|
||||
|
||||
//this.container.append(this.paddingTopDiv);
|
||||
Array.from(el.children).forEach(c => this.container.append(c));
|
||||
//this.container.append(this.paddingBottomDiv);
|
||||
|
||||
el.append(this.container);//container.append(el);
|
||||
this.container.parentElement.append(this.thumb);
|
||||
this.resize();
|
||||
}
|
||||
|
||||
public resize() {
|
||||
// @ts-ignore
|
||||
this.scrollSize = this.container[this.scrollType];
|
||||
|
||||
let rect = this.container.getBoundingClientRect();
|
||||
|
||||
// @ts-ignore
|
||||
this.size = rect[this.type];
|
||||
|
||||
if(!this.size || this.size == this.scrollSize) {
|
||||
this.thumbSize = 0;
|
||||
|
||||
// @ts-ignore
|
||||
this.thumb.style[this.type] = this.thumbSize + 'px';
|
||||
return;
|
||||
}
|
||||
//if(!height) return;
|
||||
|
||||
let divider = this.scrollSize / this.size / 0.5;
|
||||
this.thumbSize = this.size / divider;
|
||||
|
||||
if(this.thumbSize < 20) this.thumbSize = 20;
|
||||
|
||||
// @ts-ignore
|
||||
this.thumb.style[this.type] = this.thumbSize + 'px';
|
||||
|
||||
// @ts-ignore
|
||||
//console.log('onresize', thumb.style[type], thumbHeight, height);
|
||||
}
|
||||
|
||||
public setVirtualContainer(el: HTMLElement) {
|
||||
this.splitUp = el;
|
||||
this.hiddenElements = {
|
||||
up: [],
|
||||
down: []
|
||||
};
|
||||
this.paddings = {
|
||||
up: 0,
|
||||
down: 0
|
||||
};
|
||||
|
||||
if(this.paddingTopDiv.parentElement) {
|
||||
this.paddingTopDiv.style.height = '';
|
||||
this.paddingBottomDiv.style.height = '';
|
||||
}
|
||||
|
||||
//this.topObserver.observe(this.paddingTopDiv);
|
||||
//this.bottomObserver.observe(this.paddingBottomDiv);
|
||||
|
||||
el.parentElement.insertBefore(this.paddingTopDiv, el);
|
||||
el.parentNode.insertBefore(this.paddingBottomDiv, el.nextSibling);
|
||||
}
|
||||
|
||||
public onScroll() {
|
||||
// @ts-ignore
|
||||
//let st = container[scrollSide];
|
||||
|
||||
if(this.container[this.scrollType] != this.scrollSize || this.thumbSize == 0) {
|
||||
this.resize();
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
let value = this.container[this.scrollSide] / (this.scrollSize - this.size) * 100;
|
||||
let maxValue = 100 - (this.thumbSize / this.size * 100);
|
||||
|
||||
//console.log('onscroll', container.scrollHeight, thumbHeight, height, value, maxValue);
|
||||
|
||||
// @ts-ignore
|
||||
this.thumb.style[this.side] = (value >= maxValue ? maxValue : value) + '%';
|
||||
|
||||
if(!this.splitUp) {
|
||||
return;
|
||||
}
|
||||
|
||||
let splitUp = this.splitUp;
|
||||
let children = Array.from(splitUp.children) as HTMLElement[];
|
||||
let firstVisible = -1, lastVisible = -1;
|
||||
let length = children.length;
|
||||
for(let i = 0; i < length; ++i) {
|
||||
let child = children[i];
|
||||
if(isElementInViewport(child) || isScrolledIntoView(child)) {
|
||||
if(firstVisible < 0) firstVisible = i;
|
||||
lastVisible = i;
|
||||
}
|
||||
}
|
||||
|
||||
//console.log('onscroll', firstVisible, lastVisible);
|
||||
|
||||
if(firstVisible > 0) {
|
||||
let sliced = children.slice(0, firstVisible);
|
||||
|
||||
for(let child of sliced) {
|
||||
this.paddings.up += child.scrollHeight;
|
||||
this.hiddenElements.up.push(child);
|
||||
child.parentElement.removeChild(child);
|
||||
}
|
||||
|
||||
//console.log('onscroll sliced up', sliced.length);
|
||||
|
||||
//sliced.forEach(child => child.style.display = 'none');
|
||||
this.paddingTopDiv.style.height = this.paddings.up + 'px';
|
||||
//console.log('onscroll need to add padding: ', paddings.up);
|
||||
} else if(this.hiddenElements.up.length) {
|
||||
//console.log('onscroll up', isElementInViewport(this.paddingTopDiv), isScrolledIntoView(this.paddingTopDiv), this.paddings.up);
|
||||
while((isElementInViewport(this.paddingTopDiv) || isScrolledIntoView(this.paddingTopDiv)) && this.paddings.up) {
|
||||
let child = this.hiddenElements.up.pop();
|
||||
|
||||
splitUp.prepend(child);
|
||||
|
||||
this.paddings.up -= child.scrollHeight;
|
||||
this.paddingTopDiv.style.height = this.paddings.up + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
if(lastVisible < (length - 1)) {
|
||||
let sliced = children.slice(lastVisible + 1).reverse();
|
||||
|
||||
for(let child of sliced) {
|
||||
this.paddings.down += child.scrollHeight;
|
||||
this.hiddenElements.down.unshift(child);
|
||||
child.parentElement.removeChild(child);
|
||||
}
|
||||
|
||||
//console.log('onscroll sliced down', splitUp, sliced.length, this.paddings.down + 'px');
|
||||
|
||||
this.paddingBottomDiv.style.height = this.paddings.down + 'px';
|
||||
//console.log('onscroll need to add padding: ', paddings.up);
|
||||
} else if(this.hiddenElements.down.length) {
|
||||
//console.log('onscroll down', isElementInViewport(this.paddingBottomDiv),
|
||||
//isScrolledIntoView(this.paddingBottomDiv), this.paddings.down, this.hiddenElements);
|
||||
while((isElementInViewport(this.paddingBottomDiv) || isScrolledIntoView(this.paddingBottomDiv)) && this.paddings.down) {
|
||||
let child = this.hiddenElements.down.shift();
|
||||
|
||||
splitUp.append(child);
|
||||
|
||||
this.paddings.down -= child.scrollHeight;
|
||||
this.paddingBottomDiv.style.height = this.paddings.down + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
//console.log('onscroll', container, firstVisible, lastVisible, hiddenElements);
|
||||
|
||||
//lastScrollPos = st;
|
||||
}
|
||||
}
|
270
src/components/scrollable_spliceCount.ts
Normal file
270
src/components/scrollable_spliceCount.ts
Normal file
@ -0,0 +1,270 @@
|
||||
import { isElementInViewport } from "../lib/utils";
|
||||
|
||||
export default class Scrollable {
|
||||
public container: HTMLDivElement;
|
||||
public thumb: HTMLDivElement;
|
||||
|
||||
public type: string;
|
||||
public side: string;
|
||||
public scrollType: string;
|
||||
public scrollSide: string;
|
||||
|
||||
public scrollSize = -1;
|
||||
public size = 0;
|
||||
public thumbSize = 0;
|
||||
|
||||
public hiddenElements: {
|
||||
up: Element[],
|
||||
down: Element[]
|
||||
} = {
|
||||
up: [],
|
||||
down: []
|
||||
};
|
||||
public paddings = {up: 0, down: 0};
|
||||
|
||||
public paddingTopDiv: HTMLDivElement;
|
||||
public paddingBottomDiv: HTMLDivElement;
|
||||
|
||||
public splitUp: HTMLElement;
|
||||
public spliceCount = 1;
|
||||
public useStylePadding = false;
|
||||
public useOneHeight = false;
|
||||
|
||||
constructor(public el: HTMLDivElement, x = false, y = true) {
|
||||
this.container = document.createElement('div');
|
||||
this.container.classList.add('scrollable');
|
||||
|
||||
if(x) {
|
||||
this.container.classList.add('scrollable-x');
|
||||
this.type = 'width';
|
||||
this.side = 'left';
|
||||
this.scrollType = 'scrollWidth';
|
||||
this.scrollSide = 'scrollLeft';
|
||||
} else if(y) {
|
||||
this.container.classList.add('scrollable-y');
|
||||
this.type = 'height';
|
||||
this.side = 'top';
|
||||
this.scrollType = 'scrollHeight';
|
||||
this.scrollSide = 'scrollTop';
|
||||
} else {
|
||||
throw new Error('no side for scroll');
|
||||
}
|
||||
|
||||
this.thumb = document.createElement('div');
|
||||
this.thumb.className = 'scrollbar-thumb';
|
||||
|
||||
// @ts-ignore
|
||||
this.thumb.style[this.type] = '30px';
|
||||
|
||||
this.container.addEventListener('mouseover', this.resize.bind(this));
|
||||
window.addEventListener('resize', this.resize.bind(this));
|
||||
|
||||
this.paddingTopDiv = document.createElement('div');
|
||||
this.paddingTopDiv.classList.add('scroll-padding');
|
||||
this.paddingBottomDiv = document.createElement('div');
|
||||
this.paddingBottomDiv.classList.add('scroll-padding');
|
||||
|
||||
this.container.addEventListener('scroll', this.onScroll.bind(this));
|
||||
|
||||
this.container.append(this.paddingTopDiv);
|
||||
Array.from(el.children).forEach(c => this.container.append(c));
|
||||
this.container.append(this.paddingBottomDiv);
|
||||
|
||||
el.append(this.container);//container.append(el);
|
||||
this.container.parentElement.append(this.thumb);
|
||||
this.resize();
|
||||
}
|
||||
|
||||
public resize() {
|
||||
// @ts-ignore
|
||||
this.scrollSize = this.container[this.scrollType];
|
||||
|
||||
let rect = this.container.getBoundingClientRect();
|
||||
|
||||
// @ts-ignore
|
||||
this.size = rect[this.type];
|
||||
|
||||
if(!this.size || this.size == this.scrollSize) {
|
||||
this.thumbSize = 0;
|
||||
|
||||
// @ts-ignore
|
||||
this.thumb.style[this.type] = this.thumbSize + 'px';
|
||||
return;
|
||||
}
|
||||
//if(!height) return;
|
||||
|
||||
let divider = this.scrollSize / this.size / 0.5;
|
||||
this.thumbSize = this.size / divider;
|
||||
|
||||
if(this.thumbSize < 20) this.thumbSize = 20;
|
||||
|
||||
// @ts-ignore
|
||||
this.thumb.style[this.type] = this.thumbSize + 'px';
|
||||
|
||||
// @ts-ignore
|
||||
//console.log('onresize', thumb.style[type], thumbHeight, height);
|
||||
}
|
||||
|
||||
public setVirtualContainer(el: HTMLElement, spliceCount = 1, useStylePadding = false, useOneHeight = false) {
|
||||
this.splitUp = el;
|
||||
this.hiddenElements = {
|
||||
up: [],
|
||||
down: []
|
||||
};
|
||||
this.paddings = {
|
||||
up: 0,
|
||||
down: 0
|
||||
};
|
||||
|
||||
this.spliceCount = spliceCount;
|
||||
this.useStylePadding = useStylePadding;
|
||||
this.useOneHeight = useOneHeight;
|
||||
|
||||
if(this.paddingTopDiv.parentElement) {
|
||||
this.paddingTopDiv.style.height = '';
|
||||
this.paddingBottomDiv.style.height = '';
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* if(useStylePadding) {
|
||||
this.paddingTopDiv.parentElement.removeChild(this.paddingTopDiv);
|
||||
this.paddingBottomDiv.parentElement.removeChild(this.paddingBottomDiv);
|
||||
} else { */
|
||||
el.parentElement.insertBefore(this.paddingTopDiv, el);
|
||||
el.parentNode.insertBefore(this.paddingBottomDiv, el.nextSibling);
|
||||
//}
|
||||
|
||||
if(useStylePadding) {
|
||||
this.paddingTopDiv.style.height = '10px';
|
||||
this.paddingBottomDiv.style.height = '10px';
|
||||
}
|
||||
}
|
||||
|
||||
public onScroll() {
|
||||
// @ts-ignore
|
||||
//let st = container[scrollSide];
|
||||
|
||||
|
||||
if(this.container[this.scrollType] != this.scrollSize || this.thumbSize == 0) {
|
||||
this.resize();
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
let value = this.container[this.scrollSide] / (this.scrollSize - this.size) * 100;
|
||||
let maxValue = 100 - (this.thumbSize / this.size * 100);
|
||||
|
||||
//console.log('onscroll', container.scrollHeight, thumbHeight, height, value, maxValue);
|
||||
|
||||
// @ts-ignore
|
||||
this.thumb.style[this.side] = (value >= maxValue ? maxValue : value) + '%';
|
||||
|
||||
if(!this.splitUp) {
|
||||
return;
|
||||
}
|
||||
|
||||
let splitUp = this.splitUp;
|
||||
let children = Array.from(splitUp.children) as HTMLElement[];
|
||||
let firstVisible = -1, lastVisible = -1;
|
||||
let length = children.length;
|
||||
for(let i = 0; i < length; ++i) {
|
||||
let child = children[i];
|
||||
if(isElementInViewport(child)) {
|
||||
if(firstVisible < 0) firstVisible = i;
|
||||
lastVisible = i;
|
||||
}
|
||||
}
|
||||
|
||||
console.log('onscroll', firstVisible, lastVisible);
|
||||
|
||||
if(firstVisible > 0) {
|
||||
let sliced = children.slice(0, firstVisible);
|
||||
|
||||
let height = 0, singleHeight = sliced[0].scrollHeight;
|
||||
for(let child of sliced) {
|
||||
height += child.scrollHeight;
|
||||
this.hiddenElements.up.push(child);
|
||||
child.parentElement.removeChild(child);
|
||||
}
|
||||
|
||||
this.paddings.up += this.useOneHeight ? singleHeight : height;
|
||||
|
||||
//console.log('sliced up', sliced.length);
|
||||
|
||||
//sliced.forEach(child => child.style.display = 'none');
|
||||
if(this.useStylePadding) splitUp.style.paddingTop = this.paddings.up + 'px';
|
||||
else this.paddingTopDiv.style.height = this.paddings.up + 'px';
|
||||
//console.log('onscroll need to add padding: ', paddings.up);
|
||||
} else if(this.hiddenElements.up.length) {
|
||||
console.log('onscroll up', isElementInViewport(this.paddingTopDiv), this.paddings.up);
|
||||
while(isElementInViewport(this.paddingTopDiv) && this.paddings.up) {
|
||||
//let child = this.hiddenElements.up.pop();
|
||||
|
||||
/*
|
||||
splitUp.prepend(...childs);
|
||||
|
||||
this.paddings.up -= child.scrollHeight;
|
||||
this.paddingTopDiv.style.height = this.paddings.up + 'px';*/
|
||||
|
||||
let childs = this.hiddenElements.up.splice(-this.spliceCount).reverse();
|
||||
|
||||
let height = 0;
|
||||
for(let child of childs) {
|
||||
splitUp.prepend(child);
|
||||
height += child.scrollHeight;
|
||||
}
|
||||
|
||||
this.paddings.up -= this.useOneHeight ? childs[0].scrollHeight : height;
|
||||
|
||||
if(this.useStylePadding) splitUp.style.paddingTop = this.paddings.up + 'px';
|
||||
else this.paddingTopDiv.style.height = this.paddings.up + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
if(lastVisible < (length - 1)) {
|
||||
let sliced = children.slice(lastVisible + 1, this.useOneHeight ? lastVisible + 1 + this.spliceCount : undefined).reverse();
|
||||
|
||||
let height = 0, singleHeight = sliced[0].scrollHeight;
|
||||
for(let child of sliced) {
|
||||
height += child.scrollHeight;
|
||||
this.hiddenElements.down.unshift(child);
|
||||
child.parentElement.removeChild(child);
|
||||
}
|
||||
|
||||
this.paddings.down += this.useOneHeight ? singleHeight : height;
|
||||
|
||||
console.log('onscroll sliced down', splitUp, sliced.length, this.paddings.down + 'px');
|
||||
|
||||
//sliced.forEach(child => child.style.display = 'none');
|
||||
|
||||
/* if(this.useStylePadding) splitUp.style.paddingBottom = this.paddings.down + 'px';
|
||||
else */ this.paddingBottomDiv.style.height = this.paddings.down + 'px';
|
||||
//console.log('onscroll need to add padding: ', paddings.up);
|
||||
} else if(this.hiddenElements.down.length) {
|
||||
console.log('onscroll down', isElementInViewport(this.paddingBottomDiv), this.paddings.down, this.hiddenElements);
|
||||
while(isElementInViewport(this.paddingBottomDiv) && this.paddings.down) {
|
||||
/* let child = this.hiddenElements.down.shift();
|
||||
|
||||
splitUp.append(child);
|
||||
|
||||
this.paddings.down -= child.scrollHeight;
|
||||
this.paddingBottomDiv.style.height = this.paddings.down + 'px'; */
|
||||
let childs = this.hiddenElements.down.splice(0, this.spliceCount);
|
||||
|
||||
let height = 0;
|
||||
for(let child of childs) {
|
||||
splitUp.append(child);
|
||||
height += child.scrollHeight;
|
||||
}
|
||||
|
||||
this.paddings.down -= this.useOneHeight ? childs[0].scrollHeight : height;
|
||||
/* if(this.useStylePadding) splitUp.style.paddingBottom = this.paddings.down + 'px';
|
||||
else */ this.paddingBottomDiv.style.height = this.paddings.down + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
//console.log('onscroll', container, firstVisible, lastVisible, hiddenElements);
|
||||
|
||||
//lastScrollPos = st;
|
||||
}
|
||||
}
|
@ -16,17 +16,23 @@ type DialogDom = {
|
||||
lastTimeSpan: HTMLSpanElement,
|
||||
unreadMessagesSpan: HTMLSpanElement,
|
||||
lastMessageSpan: HTMLSpanElement,
|
||||
containerEl: HTMLDivElement,
|
||||
listEl: HTMLLIElement
|
||||
};
|
||||
|
||||
export class AppDialogsManager {
|
||||
public chatList = document.getElementById('dialogs') as HTMLUListElement;
|
||||
public pinnedDelimiter: HTMLDivElement;
|
||||
public chatsHidden: any;
|
||||
|
||||
public myID = 0;
|
||||
public doms: {[x: number]: any} = {};
|
||||
|
||||
constructor() {
|
||||
this.pinnedDelimiter = document.createElement('div');
|
||||
this.pinnedDelimiter.classList.add('pinned-delimiter');
|
||||
this.pinnedDelimiter.appendChild(document.createElement('span'));
|
||||
|
||||
apiManager.getUserID().then((id) => {
|
||||
this.myID = id;
|
||||
});
|
||||
@ -168,7 +174,7 @@ export class AppDialogsManager {
|
||||
} else if(this.chatsHidden.down.find((d: HTMLLIElement) => d === dom.listEl)) {
|
||||
inBottom.push(dom.listEl);
|
||||
} else {
|
||||
console.warn('found no dom!', dom);
|
||||
//console.warn('found no dom!', dom, d);
|
||||
}
|
||||
|
||||
//this.chatList.append(dom.listEl);
|
||||
@ -395,12 +401,22 @@ export class AppDialogsManager {
|
||||
//captionDiv.append(titleSpan);
|
||||
//captionDiv.append(span);
|
||||
|
||||
|
||||
|
||||
let paddingDiv = document.createElement('div');
|
||||
paddingDiv.classList.add('rp');
|
||||
paddingDiv.append(avatarDiv, captionDiv);
|
||||
ripple(paddingDiv);
|
||||
|
||||
let li = document.createElement('li');
|
||||
li.append(paddingDiv);
|
||||
li.setAttribute('data-peerID', '' + peerID);
|
||||
/* let li = document.createElement('li');
|
||||
li.classList.add('rp');
|
||||
li.append(avatarDiv, captionDiv);
|
||||
li.setAttribute('data-peerID', '' + peerID);
|
||||
|
||||
ripple(li);
|
||||
ripple(li); */
|
||||
|
||||
/* let detailsDiv = document.createElement('div');
|
||||
detailsDiv.classList.add('dialog-details'); */
|
||||
@ -432,6 +448,7 @@ export class AppDialogsManager {
|
||||
lastTimeSpan,
|
||||
unreadMessagesSpan,
|
||||
lastMessageSpan: span,
|
||||
containerEl: paddingDiv,
|
||||
listEl: li
|
||||
};
|
||||
|
||||
@ -441,6 +458,8 @@ export class AppDialogsManager {
|
||||
|
||||
if(dialog.pFlags.pinned) {
|
||||
li.classList.add('dialog-pinned');
|
||||
//this.chatList.insertBefore(this.pinnedDelimiter, li.nextSibling);
|
||||
dom.listEl.append(this.pinnedDelimiter);
|
||||
}
|
||||
|
||||
this.doms[dialog.peerID] = dom;
|
||||
|
@ -101,6 +101,7 @@ export class AppImManager {
|
||||
|
||||
public myID = 0;
|
||||
public peerID = 0;
|
||||
public muted = false;
|
||||
|
||||
public lastDialog: any;
|
||||
public bubbles: {[mid: number]: HTMLDivElement} = {};
|
||||
@ -198,54 +199,8 @@ export class AppImManager {
|
||||
$rootScope.$on('apiUpdate', (e: CustomEvent) => {
|
||||
let update = e.detail;
|
||||
|
||||
switch(update._) {
|
||||
case 'updateUserTyping':
|
||||
case 'updateChatUserTyping':
|
||||
if(this.myID == update.user_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
var peerID = update._ == 'updateUserTyping' ? update.user_id : -update.chat_id;
|
||||
this.typingUsers[update.user_id] = peerID;
|
||||
|
||||
if(!appUsersManager.hasUser(update.user_id)) {
|
||||
if(update.chat_id &&
|
||||
appChatsManager.hasChat(update.chat_id) &&
|
||||
!appChatsManager.isChannel(update.chat_id)) {
|
||||
appProfileManager.getChatFull(update.chat_id);
|
||||
}
|
||||
|
||||
//return;
|
||||
}
|
||||
|
||||
appUsersManager.forceUserOnline(update.user_id);
|
||||
|
||||
let dialog = appMessagesManager.getDialogByPeerID(peerID)[0];
|
||||
let currentPeer = this.peerID == peerID;
|
||||
|
||||
if(this.typingTimeouts[peerID]) clearTimeout(this.typingTimeouts[peerID]);
|
||||
else if(dialog) {
|
||||
appDialogsManager.setTyping(dialog, appUsersManager.getUser(update.user_id));
|
||||
|
||||
if(currentPeer) { // user
|
||||
this.setPeerStatus();
|
||||
}
|
||||
}
|
||||
|
||||
this.typingTimeouts[peerID] = setTimeout(() => {
|
||||
this.typingTimeouts[peerID] = 0;
|
||||
delete this.typingUsers[update.user_id];
|
||||
|
||||
if(dialog) {
|
||||
appDialogsManager.unsetTyping(dialog);
|
||||
}
|
||||
|
||||
// лень просчитывать случаи
|
||||
this.setPeerStatus();
|
||||
}, 6000);
|
||||
break;
|
||||
}
|
||||
})
|
||||
this.handleUpdate(update);
|
||||
});
|
||||
|
||||
window.addEventListener('blur', () => {
|
||||
lottieLoader.checkAnimations(true);
|
||||
@ -298,6 +253,9 @@ export class AppImManager {
|
||||
this.setPeer(this.peerID, mid);
|
||||
});
|
||||
|
||||
this.btnMenuMute.addEventListener('click', () => this.mutePeer());
|
||||
this.btnMute.addEventListener('click', () => this.mutePeer());
|
||||
|
||||
this.updateStatusInterval = window.setInterval(() => this.updateStatus(), 50e3);
|
||||
this.updateStatus();
|
||||
setInterval(() => this.setPeerStatus(), 60e3);
|
||||
@ -524,11 +482,10 @@ export class AppImManager {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public cleanup() {
|
||||
this.peerID = $rootScope.selectedPeerID = 0;
|
||||
this.scrolledAll = false;
|
||||
this.muted = false;
|
||||
|
||||
if(this.lastContainerDiv) this.lastContainerDiv.remove();
|
||||
if(this.firstContainerDiv) this.firstContainerDiv.remove();
|
||||
@ -545,6 +502,8 @@ export class AppImManager {
|
||||
this.unreadOut = [];
|
||||
this.loadMediaQueue = [];
|
||||
|
||||
lottieLoader.checkAnimations(false, 'chat', true);
|
||||
|
||||
console.time('chatInner clear');
|
||||
|
||||
this.chatInner.innerHTML = '';
|
||||
@ -954,7 +913,7 @@ export class AppImManager {
|
||||
}
|
||||
|
||||
return true;
|
||||
}, null, '', false, !!message.pending)/* .then(() => {
|
||||
}, null, 'chat', false, !!message.pending || !multipleRender)/* .then(() => {
|
||||
|
||||
attachmentDiv.style.width = '';
|
||||
attachmentDiv.style.height = '';
|
||||
@ -1239,6 +1198,150 @@ export class AppImManager {
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public setMutedState(muted = false) {
|
||||
appSidebarRight.profileElements.notificationsCheckbox.checked = !muted;
|
||||
appSidebarRight.profileElements.notificationsStatus.innerText = muted ? 'Disabled' : 'Enabled';
|
||||
|
||||
let peerID = this.peerID;
|
||||
|
||||
this.muted = muted;
|
||||
if(peerID < 0) { // not human
|
||||
let isChannel = appPeersManager.isChannel(peerID) && !appPeersManager.isMegagroup(peerID);
|
||||
if(isChannel) {
|
||||
this.btnMute.classList.remove('tgico-mute', 'tgico-unmute');
|
||||
this.btnMute.classList.add(muted ? 'tgico-unmute' : 'tgico-mute');
|
||||
this.btnMute.style.display = '';
|
||||
} else {
|
||||
this.btnMute.style.display = 'none';
|
||||
}
|
||||
} else {
|
||||
this.btnMute.style.display = 'none';
|
||||
}
|
||||
|
||||
this.btnMenuMute.classList.remove('tgico-mute', 'tgico-unmute');
|
||||
this.btnMenuMute.classList.add(muted ? 'tgico-unmute' : 'tgico-mute');
|
||||
let rp = this.btnMenuMute.firstElementChild;
|
||||
this.btnMenuMute.innerText = muted ? 'Unmute' : 'Mute';
|
||||
this.btnMenuMute.appendChild(rp);
|
||||
}
|
||||
|
||||
public mutePeer() {
|
||||
let inputPeer = appPeersManager.getInputPeerByID(this.peerID);
|
||||
let inputNotifyPeer = {
|
||||
_: 'inputNotifyPeer',
|
||||
peer: inputPeer
|
||||
};
|
||||
|
||||
let settings: any = {
|
||||
_: 'inputPeerNotifySettings',
|
||||
flags: 0,
|
||||
mute_until: 0
|
||||
};
|
||||
|
||||
if(!this.muted) {
|
||||
settings.flags |= 2 << 1;
|
||||
settings.mute_until = 2147483646;
|
||||
} else {
|
||||
settings.flags |= 1 << 1;
|
||||
}
|
||||
|
||||
apiManager.invokeApi('account.updateNotifySettings', {
|
||||
peer: inputNotifyPeer,
|
||||
settings: settings
|
||||
}).then(res => {
|
||||
this.handleUpdate({_: 'updateNotifySettings', peer: inputNotifyPeer, notify_settings: settings});
|
||||
});
|
||||
|
||||
/* return apiManager.invokeApi('account.getNotifySettings', {
|
||||
peer: inputNotifyPeer
|
||||
}).then((settings: any) => {
|
||||
settings.flags |= 2 << 1;
|
||||
settings.mute_until = 2000000000; // 2147483646
|
||||
|
||||
return apiManager.invokeApi('account.updateNotifySettings', {
|
||||
peer: inputNotifyPeer,
|
||||
settings: Object.assign(settings, {
|
||||
_: 'inputPeerNotifySettings'
|
||||
})
|
||||
}).then(res => {
|
||||
this.log('mute result:', res);
|
||||
});
|
||||
}); */
|
||||
|
||||
}
|
||||
|
||||
public handleUpdate(update: any) {
|
||||
switch(update._) {
|
||||
case 'updateUserTyping':
|
||||
case 'updateChatUserTyping':
|
||||
if(this.myID == update.user_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
var peerID = update._ == 'updateUserTyping' ? update.user_id : -update.chat_id;
|
||||
this.typingUsers[update.user_id] = peerID;
|
||||
|
||||
if(!appUsersManager.hasUser(update.user_id)) {
|
||||
if(update.chat_id &&
|
||||
appChatsManager.hasChat(update.chat_id) &&
|
||||
!appChatsManager.isChannel(update.chat_id)) {
|
||||
appProfileManager.getChatFull(update.chat_id);
|
||||
}
|
||||
|
||||
//return;
|
||||
}
|
||||
|
||||
appUsersManager.forceUserOnline(update.user_id);
|
||||
|
||||
let dialog = appMessagesManager.getDialogByPeerID(peerID)[0];
|
||||
let currentPeer = this.peerID == peerID;
|
||||
|
||||
if(this.typingTimeouts[peerID]) clearTimeout(this.typingTimeouts[peerID]);
|
||||
else if(dialog) {
|
||||
appDialogsManager.setTyping(dialog, appUsersManager.getUser(update.user_id));
|
||||
|
||||
if(currentPeer) { // user
|
||||
this.setPeerStatus();
|
||||
}
|
||||
}
|
||||
|
||||
this.typingTimeouts[peerID] = setTimeout(() => {
|
||||
this.typingTimeouts[peerID] = 0;
|
||||
delete this.typingUsers[update.user_id];
|
||||
|
||||
if(dialog) {
|
||||
appDialogsManager.unsetTyping(dialog);
|
||||
}
|
||||
|
||||
// лень просчитывать случаи
|
||||
this.setPeerStatus();
|
||||
}, 6000);
|
||||
break;
|
||||
|
||||
case 'updateNotifySettings': {
|
||||
let {peer, notify_settings} = update;
|
||||
|
||||
// peer was NotifyPeer
|
||||
peer = peer.peer;
|
||||
|
||||
let peerID = appPeersManager.getPeerID(peer);
|
||||
|
||||
let dialog = appMessagesManager.getDialogByPeerID(peerID)[0];
|
||||
if(dialog) {
|
||||
dialog.notify_settings = notify_settings;
|
||||
}
|
||||
|
||||
if(peerID == this.peerID) {
|
||||
let muted = notify_settings.mute_until ? new Date(notify_settings.mute_until * 1000) > new Date() : false;
|
||||
this.setMutedState(muted);
|
||||
}
|
||||
|
||||
this.log('updateNotifySettings', peerID, notify_settings);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default new AppImManager();
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { logger } from "../polyfill";
|
||||
import { scrollable, putPreloader } from "../../components/misc";
|
||||
import { putPreloader } from "../../components/misc";
|
||||
import Scrollable from '../../components/scrollable';
|
||||
import appMessagesManager from "./appMessagesManager";
|
||||
import appDialogsManager from "./appDialogsManager";
|
||||
import { isElementInViewport } from "../utils";
|
||||
@ -20,12 +21,9 @@ class AppSidebarLeft {
|
||||
|
||||
private chatsContainer = document.getElementById('chats-container') as HTMLDivElement;
|
||||
private chatsOffsetIndex = 0;
|
||||
private chatsScroll: HTMLDivElement;
|
||||
private chatsHidden: any;
|
||||
private chatsPreloader: HTMLDivElement;
|
||||
private chatsLoadCount = 0;
|
||||
private loadDialogsPromise: Promise<any>;
|
||||
private hiddenScroll: any;
|
||||
|
||||
private log = logger('SL');
|
||||
|
||||
@ -39,6 +37,8 @@ class AppSidebarLeft {
|
||||
private searchTimeout: number = 0;
|
||||
|
||||
private query = '';
|
||||
|
||||
public scroll: Scrollable = null;
|
||||
|
||||
constructor() {
|
||||
this.chatsPreloader = document.createElement('div');
|
||||
@ -48,16 +48,13 @@ class AppSidebarLeft {
|
||||
|
||||
this.chatsLoadCount = Math.round(document.body.scrollHeight / 70 * 1.5);
|
||||
|
||||
let {container: chatsScroll, hiddenElements: chatsHidden, onScroll: hiddenScroll} = scrollable(this.chatsContainer as HTMLDivElement);
|
||||
this.chatsScroll = chatsScroll;
|
||||
this.chatsHidden = chatsHidden;
|
||||
this.hiddenScroll = hiddenScroll;
|
||||
|
||||
appDialogsManager.chatsHidden = this.chatsHidden;
|
||||
this.scroll = new Scrollable(this.chatsContainer as HTMLDivElement);
|
||||
appDialogsManager.chatsHidden = this.scroll.hiddenElements;
|
||||
this.scroll.setVirtualContainer(appDialogsManager.chatList);
|
||||
|
||||
chatsScroll.addEventListener('scroll', this.onChatsScroll.bind(this));
|
||||
this.scroll.container.addEventListener('scroll', this.onChatsScroll.bind(this));
|
||||
|
||||
this.listsContainer = scrollable(this.searchContainer).container;
|
||||
this.listsContainer = new Scrollable(this.searchContainer).container;
|
||||
this.searchMessagesList = document.createElement('ul');
|
||||
|
||||
this.savedBtn.addEventListener('click', () => {
|
||||
@ -163,8 +160,8 @@ class AppSidebarLeft {
|
||||
});
|
||||
}
|
||||
|
||||
this.log('loaded ' + this.chatsLoadCount + ' dialogs by offset:', this.chatsOffsetIndex, result, this.chatsHidden);
|
||||
this.hiddenScroll();
|
||||
this.log('loaded ' + this.chatsLoadCount + ' dialogs by offset:', this.chatsOffsetIndex, result, this.scroll.hiddenElements);
|
||||
this.scroll.onScroll();
|
||||
} catch(err) {
|
||||
this.log.error(err);
|
||||
}
|
||||
@ -174,7 +171,8 @@ class AppSidebarLeft {
|
||||
}
|
||||
|
||||
public onChatsScroll() {
|
||||
if(this.chatsHidden.down.length > 0/* || 1 == 1 */) return;
|
||||
//this.log(this.scroll);
|
||||
if(this.scroll.hiddenElements.down.length > 0/* || 1 == 1 */) return;
|
||||
|
||||
if(!this.loadDialogsPromise) {
|
||||
let d = Array.from(appDialogsManager.chatList.childNodes).slice(-5);
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { LazyLoadQueue, horizontalMenu, wrapDocument, formatPhoneNumber } from "../../components/misc";
|
||||
import Scrollable from '../../components/scrollable';
|
||||
import { isElementInViewport, $rootScope } from "../utils";
|
||||
import appMessagesManager from "./appMessagesManager";
|
||||
import appPhotosManager from "./appPhotosManager";
|
||||
@ -33,7 +34,7 @@ class AppSidebarRight {
|
||||
contentAudio: this.profileContentEl.querySelector('#content-audio') as HTMLDivElement,
|
||||
};
|
||||
|
||||
public sidebarScroll: HTMLDivElement = null;
|
||||
public lastSharedMediaDiv: HTMLDivElement = null;
|
||||
|
||||
private loadSidebarMediaPromises: {
|
||||
[type: string]: Promise<void>
|
||||
@ -67,13 +68,21 @@ class AppSidebarRight {
|
||||
|
||||
private peerID = 0;
|
||||
|
||||
public sidebarScroll: Scrollable = null;
|
||||
|
||||
constructor() {
|
||||
let container = this.profileContentEl.querySelector('.profile-tabs-content') as HTMLDivElement;
|
||||
let tabs = this.profileContentEl.querySelector('.profile-tabs') as HTMLUListElement;
|
||||
|
||||
this.sidebarScroll = new Scrollable(this.sidebarEl);
|
||||
this.sidebarScroll.container.addEventListener('scroll', this.onSidebarScroll.bind(this));
|
||||
|
||||
horizontalMenu(tabs, container, (id, tabContent) => {
|
||||
this.sharedMediaType = this.sharedMediaTypes[id];
|
||||
this.sharedMediaSelected = tabContent.firstElementChild as HTMLDivElement;
|
||||
|
||||
this.log('setVirtualContainer', this.sharedMediaSelected);
|
||||
this.sidebarScroll.setVirtualContainer(this.sharedMediaSelected);
|
||||
}, this.onSidebarScroll.bind(this));
|
||||
|
||||
(tabs.children[1] as HTMLLIElement).click(); // set media
|
||||
@ -96,6 +105,11 @@ class AppSidebarRight {
|
||||
appMediaViewer.openMedia(message, false);
|
||||
});
|
||||
|
||||
this.profileElements.notificationsCheckbox.addEventListener('change', () => {
|
||||
let checked = this.profileElements.notificationsCheckbox.checked;
|
||||
appImManager.mutePeer();
|
||||
});
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
setTimeout(() => this.onSidebarScroll(), 0);
|
||||
});
|
||||
@ -104,7 +118,7 @@ class AppSidebarRight {
|
||||
public onSidebarScroll() {
|
||||
this.lazyLoadQueueSidebar.check();
|
||||
|
||||
if(this.sharedMediaSelected) {
|
||||
if(this.sharedMediaSelected && !this.sidebarScroll.hiddenElements.down.length/* && false */) {
|
||||
let media = Array.from(this.sharedMediaSelected.childNodes).slice(-15);
|
||||
for(let div of media) {
|
||||
if(isElementInViewport(div)) {
|
||||
@ -117,16 +131,6 @@ class AppSidebarRight {
|
||||
}
|
||||
}
|
||||
|
||||
public setScroll(scroll: HTMLDivElement) {
|
||||
this.sidebarScroll = scroll;
|
||||
this.sidebarScroll.addEventListener('scroll', this.onSidebarScroll.bind(this));
|
||||
/* this.sidebarScroll.options({
|
||||
callbacks: {
|
||||
onScroll: this.onSidebarScroll.bind(this)
|
||||
}
|
||||
}); */
|
||||
}
|
||||
|
||||
public toggleSidebar(enable?: boolean) {
|
||||
this.log('sidebarEl', this.sidebarEl, enable, isElementInViewport(this.sidebarEl));
|
||||
|
||||
@ -239,8 +243,14 @@ class AppSidebarRight {
|
||||
div.setAttribute('message-id', '' + mid);
|
||||
|
||||
this.lazyLoadQueueSidebar.push({div, load});
|
||||
|
||||
this.lastSharedMediaDiv.append(div);
|
||||
if(this.lastSharedMediaDiv.childElementCount == 3) {
|
||||
this.sharedMedia.contentMedia.append(this.lastSharedMediaDiv);
|
||||
this.lastSharedMediaDiv = document.createElement('div');
|
||||
}
|
||||
|
||||
this.sharedMedia.contentMedia.append(div);
|
||||
//this.sharedMedia.contentMedia.append(div);
|
||||
|
||||
break;
|
||||
}
|
||||
@ -285,12 +295,13 @@ class AppSidebarRight {
|
||||
public fillProfileElements() {
|
||||
let peerID = this.peerID = $rootScope.selectedPeerID;
|
||||
this.loadSidebarMediaPromises = {};
|
||||
this.lastSharedMediaDiv = document.createElement('div');
|
||||
|
||||
this.profileContentEl.parentElement.scrollTop = 0;
|
||||
this.profileElements.bio.style.display = 'none';
|
||||
this.profileElements.phone.style.display = 'none';
|
||||
this.profileElements.username.style.display = 'none';
|
||||
this.profileElements.notificationsCheckbox.setAttribute('checked', 'checked');
|
||||
this.profileElements.notificationsCheckbox.checked = true;
|
||||
this.profileElements.notificationsStatus.innerText = 'Enabled';
|
||||
|
||||
Object.keys(this.sharedMedia).forEach(key => {
|
||||
@ -365,30 +376,9 @@ class AppSidebarRight {
|
||||
let muted = false;
|
||||
if(dialog.notify_settings && dialog.notify_settings.mute_until) {
|
||||
muted = new Date(dialog.notify_settings.mute_until * 1000) > new Date();
|
||||
if(muted) {
|
||||
this.profileElements.notificationsCheckbox.removeAttribute('checked');
|
||||
this.profileElements.notificationsStatus.innerText = 'Disabled';
|
||||
}
|
||||
}
|
||||
|
||||
if(peerID < 0) { // not human
|
||||
let isChannel = appPeersManager.isChannel(peerID) && !appPeersManager.isMegagroup(peerID);
|
||||
if(isChannel) {
|
||||
appImManager.btnMute.classList.remove('tgico-mute', 'tgico-unmute');
|
||||
appImManager.btnMute.classList.add(muted ? 'tgico-unmute' : 'tgico-mute');
|
||||
appImManager.btnMute.style.display = '';
|
||||
} else {
|
||||
appImManager.btnMute.style.display = 'none';
|
||||
}
|
||||
} else {
|
||||
appImManager.btnMute.style.display = 'none';
|
||||
}
|
||||
|
||||
appImManager.btnMenuMute.classList.remove('tgico-mute', 'tgico-unmute');
|
||||
appImManager.btnMenuMute.classList.add(muted ? 'tgico-unmute' : 'tgico-mute');
|
||||
let rp = appImManager.btnMenuMute.firstElementChild;
|
||||
appImManager.btnMenuMute.innerText = muted ? 'Unmute' : 'Mute';
|
||||
appImManager.btnMenuMute.appendChild(rp);
|
||||
appImManager.setMutedState(muted);
|
||||
}
|
||||
|
||||
//this.loadSidebarMedia();
|
||||
|
@ -28,7 +28,7 @@ export class AppUsersManager {
|
||||
|
||||
$rootScope.$on('apiUpdate', (e: CustomEvent) => {
|
||||
let update = e.detail;
|
||||
console.log('on apiUpdate', update);
|
||||
//console.log('on apiUpdate', update);
|
||||
switch(update._) {
|
||||
case 'updateUserStatus':
|
||||
var userID = update.user_id;
|
||||
|
@ -2,18 +2,19 @@ import LottiePlayer, { AnimationConfigWithPath, AnimationConfigWithData, Animati
|
||||
import { isElementInViewport, isInDOM } from "./utils";
|
||||
|
||||
class LottieLoader {
|
||||
private lottie: /* any */ typeof LottiePlayer = null;
|
||||
public lottie: /* any */ typeof LottiePlayer = null;
|
||||
private animations: {
|
||||
[group: string]: {
|
||||
animation: AnimationItem,
|
||||
container: HTMLDivElement,
|
||||
paused: boolean,
|
||||
autoplay: boolean
|
||||
autoplay: boolean,
|
||||
canvas: boolean
|
||||
}[]
|
||||
} = {};
|
||||
private debug = false;
|
||||
|
||||
public checkAnimations(blurred?: boolean, group?: string) {
|
||||
public checkAnimations(blurred?: boolean, group?: string, destroy = false) {
|
||||
let groups = group ? [group] : Object.keys(this.animations);
|
||||
|
||||
if(group && !this.animations[group]) {
|
||||
@ -27,9 +28,17 @@ class LottieLoader {
|
||||
|
||||
let length = animations.length;
|
||||
for(let i = length - 1; i >= 0; --i) {
|
||||
let {animation, container, paused, autoplay} = animations[i];
|
||||
let {animation, container, paused, autoplay, canvas} = animations[i];
|
||||
|
||||
if(canvas && isElementInViewport(container)) {
|
||||
let c = container.firstElementChild as HTMLCanvasElement;
|
||||
if(!c.height && !c.width) {
|
||||
console.log('lottie need resize');
|
||||
animation.resize();
|
||||
}
|
||||
}
|
||||
|
||||
if(!isInDOM(container)) {
|
||||
if(destroy && !isInDOM(container)) {
|
||||
this.debug && console.log('destroy animation');
|
||||
animation.destroy();
|
||||
animations.splice(i, 1);
|
||||
@ -82,7 +91,8 @@ class LottieLoader {
|
||||
animation,
|
||||
container: params.container as HTMLDivElement,
|
||||
paused: !params.autoplay,
|
||||
autoplay: params.autoplay
|
||||
autoplay: params.autoplay,
|
||||
canvas: params.renderer == 'canvas'
|
||||
});
|
||||
|
||||
if(params.autoplay) {
|
||||
|
@ -290,6 +290,10 @@ class MTPNetworker {
|
||||
}
|
||||
|
||||
options.resultType = serializer.storeMethod(method, params);
|
||||
|
||||
if(method == 'account.updateNotifySettings') {
|
||||
this.log('api call body:', serializer.getBytes(true));
|
||||
}
|
||||
|
||||
var messageID = timeManager.generateID();
|
||||
var seqNo = this.generateSeqNo();
|
||||
|
@ -242,6 +242,7 @@ class TLSerialization {
|
||||
var i, condType;
|
||||
var fieldBit;
|
||||
var len = methodData.params.length;
|
||||
//console.log('storeMethod', len, methodData);
|
||||
for(i = 0; i < len; i++) {
|
||||
param = methodData.params[i];
|
||||
type = param.type;
|
||||
@ -339,18 +340,22 @@ class TLSerialization {
|
||||
var condType;
|
||||
var fieldBit;
|
||||
var len = constructorData.params.length;
|
||||
//console.log('storeObject', len, constructorData);
|
||||
for(i = 0; i < len; i++) {
|
||||
param = constructorData.params[i];
|
||||
type = param.type;
|
||||
|
||||
//console.log('storeObject', param, type);
|
||||
if(type.indexOf('?') !== -1) {
|
||||
condType = type.split('?');
|
||||
fieldBit = condType[0].split('.');
|
||||
//console.log('storeObject fieldBit', fieldBit, obj[fieldBit[0]]);
|
||||
if(!(obj[fieldBit[0]] & (1 << +fieldBit[1]))) {
|
||||
continue;
|
||||
}
|
||||
type = condType[1];
|
||||
}
|
||||
//console.log('storeObject', param, type);
|
||||
|
||||
this.storeObject(obj[param.name], type, field + '[' + predicate + '][' + param.name + ']');
|
||||
}
|
||||
@ -707,9 +712,12 @@ class TLDeserialization {
|
||||
fieldBit = condType[0].split('.');
|
||||
|
||||
if(!(result[fieldBit[0]] & (1 << fieldBit[1]))) {
|
||||
//console.log('fetchObject bad', constructorData, result[fieldBit[0]], fieldBit);
|
||||
continue;
|
||||
}
|
||||
|
||||
//console.log('fetchObject good', constructorData, result[fieldBit[0]], fieldBit);
|
||||
|
||||
type = condType[1];
|
||||
}
|
||||
|
||||
|
@ -359,6 +359,35 @@ export function isElementInViewport(el) {
|
||||
return elements.find(e => el.contains(e) || el.parentElement == e) !== undefined;
|
||||
}
|
||||
|
||||
export function isScrolledIntoView(el) {
|
||||
var rect = el.getBoundingClientRect();
|
||||
var elemTop = rect.top;
|
||||
var elemBottom = rect.bottom;
|
||||
|
||||
// Only completely visible elements return true:
|
||||
//var isVisible = (elemTop >= 0) && (elemBottom <= window.innerHeight);
|
||||
// Partially visible elements return true:
|
||||
var isVisible = elemTop < window.innerHeight && elemBottom >= 0;
|
||||
return isVisible;
|
||||
}
|
||||
|
||||
/* export function isScrolledIntoView(el) {
|
||||
var rect = el.getBoundingClientRect(), top = rect.top, height = rect.height,
|
||||
el = el.parentNode
|
||||
// Check if bottom of the element is off the page
|
||||
if (rect.bottom < 0) return false
|
||||
// Check its within the document viewport
|
||||
if (top > document.documentElement.clientHeight) return false
|
||||
do {
|
||||
rect = el.getBoundingClientRect()
|
||||
if (top <= rect.bottom === false) return false
|
||||
// Check if the element is out of view due to a container scrolling
|
||||
if ((top + height) <= rect.top) return false
|
||||
el = el.parentNode
|
||||
} while (el != document.body)
|
||||
return true
|
||||
}; */
|
||||
|
||||
export function whichChild(elem/* : Node */) {
|
||||
let i = 0;
|
||||
// @ts-ignore
|
||||
|
@ -42,49 +42,61 @@
|
||||
|
||||
ul {
|
||||
margin: 0;
|
||||
padding: 0 .5rem;
|
||||
}
|
||||
|
||||
#dialogs-pinned {
|
||||
border-bottom: 1px solid #DADCE0;
|
||||
|
||||
&:empty {
|
||||
display: none;
|
||||
}
|
||||
//padding: 0 .5rem;
|
||||
display: grid;
|
||||
grid-auto-columns: 1fr;
|
||||
/* grid-gap: 4px; */
|
||||
}
|
||||
|
||||
li {
|
||||
padding: 0 .5rem;
|
||||
padding: 2px 0;
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
li > .rp {
|
||||
height: 70px;
|
||||
max-height: 70px;
|
||||
overflow: hidden;
|
||||
border-radius: $border-radius;
|
||||
background-color: #fff;
|
||||
display: grid;
|
||||
align-items: center;
|
||||
grid-template-columns: 60px calc(100% - 60px);
|
||||
position: relative;
|
||||
/* grid-template-columns: 60px calc(85% - 60px) 15%; */
|
||||
|
||||
cursor: pointer;
|
||||
padding: 0 .5rem;
|
||||
margin: 0 .5rem;
|
||||
overflow: hidden;
|
||||
|
||||
&:hover {
|
||||
background: rgba(112, 117, 121, .08);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: darken(rgba(112, 117, 121, .1), .8);
|
||||
}
|
||||
|
||||
/* &.dialog-pinned + li:not(.dialog-pinned) {
|
||||
|
||||
} */
|
||||
}
|
||||
|
||||
li.active > .rp {
|
||||
background: darken(rgba(112, 117, 121, .1), .8);
|
||||
}
|
||||
|
||||
.pinned-delimiter {
|
||||
display: flex;
|
||||
padding: 8px 0 4px;
|
||||
|
||||
span {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
background-color: #DADCE0;
|
||||
}
|
||||
}
|
||||
|
||||
/* li.dialog-pinned + .pinned-delimiter {
|
||||
display: flex;
|
||||
} */
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: 1.7rem; // hot-fix
|
||||
|
||||
span:not(.tgico-pinnedchat):not(.emoji):last-child {
|
||||
@ -117,9 +129,6 @@
|
||||
}
|
||||
|
||||
.user-last-message {
|
||||
/* display: block; */
|
||||
/* display: flex;
|
||||
align-items: center; */
|
||||
max-width: 80%;
|
||||
|
||||
i {
|
||||
@ -142,16 +151,7 @@
|
||||
color: $success-color;
|
||||
font-size: 1.15rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* .dialog-details {
|
||||
text-align: right;
|
||||
|
||||
:first-child {
|
||||
font-size: .9rem;
|
||||
display: block;
|
||||
}
|
||||
} */
|
||||
}
|
||||
|
||||
.unread, .unread-muted {
|
||||
border-radius: 12px;
|
||||
|
@ -121,26 +121,36 @@
|
||||
} */
|
||||
|
||||
#content-media {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
grid-auto-rows: max-content;
|
||||
grid-gap: 3.5px;
|
||||
place-items: start;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
> div {
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
grid-auto-rows: max-content;
|
||||
grid-gap: 3.5px;
|
||||
place-items: start;
|
||||
|
||||
& + div {
|
||||
margin-top: 3.5px;
|
||||
}
|
||||
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
background-position: center center;
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
width: 1px;
|
||||
height: 0;
|
||||
padding-bottom: 100%;
|
||||
> div {
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
background-position: center center;
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
width: 1px;
|
||||
height: 0;
|
||||
padding-bottom: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ input {
|
||||
position: absolute;
|
||||
background: #fff;
|
||||
box-shadow: 0 5px 8px 1px rgba(0,0,0,.24);
|
||||
z-index: 1;
|
||||
z-index: 3;
|
||||
top: 100%;
|
||||
margin-top: 8px;
|
||||
padding: 9px 0;
|
||||
@ -1301,6 +1301,7 @@ div.scrollable::-webkit-scrollbar-thumb {
|
||||
|
||||
&.active {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
> div {
|
||||
|
Loading…
x
Reference in New Issue
Block a user