sticker thumbs & safari open chat fix & online blink fix & login added idle monkey & webp safari save to indexeddb & lazyload queue reorder & minor fixes
This commit is contained in:
parent
7642105c1b
commit
22ceba971d
@ -56,7 +56,6 @@ class AppForward {
|
|||||||
this.cleanup();
|
this.cleanup();
|
||||||
this.msgIDs = ids;
|
this.msgIDs = ids;
|
||||||
|
|
||||||
appSidebarRight.toggleSidebar(true);
|
|
||||||
this.container.classList.add('active');
|
this.container.classList.add('active');
|
||||||
this.sendBtn.innerHTML = '';
|
this.sendBtn.innerHTML = '';
|
||||||
this.sendBtn.classList.add('tgico-send');
|
this.sendBtn.classList.add('tgico-send');
|
||||||
@ -68,6 +67,9 @@ class AppForward {
|
|||||||
} else {
|
} else {
|
||||||
this.sendBtn.classList.remove('is-visible');
|
this.sendBtn.classList.remove('is-visible');
|
||||||
}
|
}
|
||||||
|
}, 'dialogs', () => {
|
||||||
|
console.log('forward rendered:', this.container.querySelector('.selector ul').childElementCount);
|
||||||
|
appSidebarRight.toggleSidebar(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ export class AppSelectPeers {
|
|||||||
private query = '';
|
private query = '';
|
||||||
private cachedContacts: number[];
|
private cachedContacts: number[];
|
||||||
|
|
||||||
constructor(private appendTo: HTMLDivElement, private onChange?: (length: number) => void, private peerType: 'contacts' | 'dialogs' = 'dialogs') {
|
constructor(private appendTo: HTMLDivElement, private onChange?: (length: number) => void, private peerType: 'contacts' | 'dialogs' = 'dialogs', onFirstRender?: () => void) {
|
||||||
this.container.classList.add('selector');
|
this.container.classList.add('selector');
|
||||||
|
|
||||||
let topContainer = document.createElement('div');
|
let topContainer = document.createElement('div');
|
||||||
@ -107,12 +107,18 @@ export class AppSelectPeers {
|
|||||||
this.container.append(topContainer, delimiter, this.chatsContainer);
|
this.container.append(topContainer, delimiter, this.chatsContainer);
|
||||||
appendTo.append(this.container);
|
appendTo.append(this.container);
|
||||||
|
|
||||||
this.getMoreResults();
|
let getResultsPromise = this.getMoreResults() as Promise<any>;
|
||||||
|
if(onFirstRender) {
|
||||||
|
getResultsPromise.then(() => {
|
||||||
|
onFirstRender();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getMoreDialogs() {
|
private getMoreDialogs() {
|
||||||
// в десктопе - сначала без группы, потом архивные, потом контакты без сообщений
|
// в десктопе - сначала без группы, потом архивные, потом контакты без сообщений
|
||||||
appMessagesManager.getConversations(this.offsetIndex, 50, 0).then(value => {
|
let pageCount = appPhotosManager.windowH / 72 * 1.25 | 0;
|
||||||
|
return appMessagesManager.getConversations(this.offsetIndex, pageCount, 0).then(value => {
|
||||||
let dialogs = value.dialogs;
|
let dialogs = value.dialogs;
|
||||||
|
|
||||||
let newOffsetIndex = dialogs[value.dialogs.length - 1].index || 0;
|
let newOffsetIndex = dialogs[value.dialogs.length - 1].index || 0;
|
||||||
@ -150,9 +156,9 @@ export class AppSelectPeers {
|
|||||||
|
|
||||||
private getMoreResults() {
|
private getMoreResults() {
|
||||||
if(this.peerType == 'dialogs') {
|
if(this.peerType == 'dialogs') {
|
||||||
this.getMoreDialogs();
|
return this.getMoreDialogs();
|
||||||
} else {
|
} else {
|
||||||
this.getMoreContacts();
|
return this.getMoreContacts();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ import lottieLoader from "../lib/lottieLoader";
|
|||||||
import { Layouter, RectPart } from "./groupedLayout";
|
import { Layouter, RectPart } from "./groupedLayout";
|
||||||
|
|
||||||
export class ChatInput {
|
export class ChatInput {
|
||||||
public pageEl = document.querySelector('.page-chats') as HTMLDivElement;
|
public pageEl = document.getElementById('page-chats') as HTMLDivElement;
|
||||||
public messageInput = document.getElementById('input-message') as HTMLDivElement/* HTMLInputElement */;
|
public messageInput = document.getElementById('input-message') as HTMLDivElement/* HTMLInputElement */;
|
||||||
public fileInput = document.getElementById('input-file') as HTMLInputElement;
|
public fileInput = document.getElementById('input-file') as HTMLInputElement;
|
||||||
public inputMessageContainer = document.getElementsByClassName('input-message-container')[0] as HTMLDivElement;
|
public inputMessageContainer = document.getElementsByClassName('input-message-container')[0] as HTMLDivElement;
|
||||||
@ -463,6 +463,7 @@ export class ChatInput {
|
|||||||
this.emoticonsDropdown.classList.remove('active');
|
this.emoticonsDropdown.classList.remove('active');
|
||||||
this.toggleEmoticons.classList.remove('active');
|
this.toggleEmoticons.classList.remove('active');
|
||||||
lottieLoader.checkAnimations(true, EMOTICONSSTICKERGROUP);
|
lottieLoader.checkAnimations(true, EMOTICONSSTICKERGROUP);
|
||||||
|
this.emoticonsLazyLoadQueue.lock();
|
||||||
}, 200);
|
}, 200);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -471,6 +472,7 @@ export class ChatInput {
|
|||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
this.emoticonsDropdown.classList.add('active');
|
this.emoticonsDropdown.classList.add('active');
|
||||||
|
this.emoticonsLazyLoadQueue.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.toggleEmoticons.classList.add('active');
|
this.toggleEmoticons.classList.add('active');
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { AppImManager } from "../lib/appManagers/appImManager";
|
import { AppImManager } from "../lib/appManagers/appImManager";
|
||||||
import { AppMessagesManager } from "../lib/appManagers/appMessagesManager";
|
import { AppMessagesManager } from "../lib/appManagers/appMessagesManager";
|
||||||
import { horizontalMenu } from "./misc";
|
import { horizontalMenu, renderImageFromUrl } from "./misc";
|
||||||
import lottieLoader from "../lib/lottieLoader";
|
import lottieLoader from "../lib/lottieLoader";
|
||||||
//import Scrollable from "./scrollable";
|
//import Scrollable from "./scrollable";
|
||||||
import Scrollable from "./scrollable_new";
|
import Scrollable from "./scrollable_new";
|
||||||
@ -12,7 +12,6 @@ import apiManager from '../lib/mtproto/mtprotoworker';
|
|||||||
//import CryptoWorker from '../lib/crypto/cryptoworker';
|
//import CryptoWorker from '../lib/crypto/cryptoworker';
|
||||||
import LazyLoadQueue from "./lazyLoadQueue";
|
import LazyLoadQueue from "./lazyLoadQueue";
|
||||||
import { MTDocument, wrapSticker } from "./wrappers";
|
import { MTDocument, wrapSticker } from "./wrappers";
|
||||||
import appWebpManager from "../lib/appManagers/appWebpManager";
|
|
||||||
import appDocsManager from "../lib/appManagers/appDocsManager";
|
import appDocsManager from "../lib/appManagers/appDocsManager";
|
||||||
import ProgressivePreloader from "./preloader";
|
import ProgressivePreloader from "./preloader";
|
||||||
import Config from "../lib/config";
|
import Config from "../lib/config";
|
||||||
@ -29,15 +28,18 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement,
|
|||||||
|
|
||||||
let container = pageEl.querySelector('.emoji-container .tabs-container') as HTMLDivElement;
|
let container = pageEl.querySelector('.emoji-container .tabs-container') as HTMLDivElement;
|
||||||
let tabs = pageEl.querySelector('.emoji-dropdown .emoji-tabs') as HTMLUListElement;
|
let tabs = pageEl.querySelector('.emoji-dropdown .emoji-tabs') as HTMLUListElement;
|
||||||
|
let tabID = -1;
|
||||||
horizontalMenu(tabs, container, (id) => {
|
horizontalMenu(tabs, container, (id) => {
|
||||||
lottieLoader.checkAnimations(true, EMOTICONSSTICKERGROUP);
|
lottieLoader.checkAnimations(true, EMOTICONSSTICKERGROUP);
|
||||||
|
|
||||||
if(id == 1 && stickersInit) {
|
tabID = id;
|
||||||
|
}, () => {
|
||||||
|
if(tabID == 1 && stickersInit) {
|
||||||
stickersInit();
|
stickersInit();
|
||||||
} else if(id == 2 && gifsInit) {
|
} else if(tabID == 2 && gifsInit) {
|
||||||
gifsInit();
|
gifsInit();
|
||||||
}
|
}
|
||||||
}, () => {
|
|
||||||
lottieLoader.checkAnimations(false, EMOTICONSSTICKERGROUP);
|
lottieLoader.checkAnimations(false, EMOTICONSSTICKERGROUP);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -347,15 +349,7 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement,
|
|||||||
stickersInit = null;
|
stickersInit = null;
|
||||||
|
|
||||||
Promise.all([
|
Promise.all([
|
||||||
apiManager.invokeApi('messages.getRecentStickers', {flags: 0, hash: 0}).then((res) => {
|
appStickersManager.getRecentStickers().then(stickers => {
|
||||||
let stickers: {
|
|
||||||
_: string,
|
|
||||||
hash: number,
|
|
||||||
packs: any[],
|
|
||||||
stickers: MTDocument[],
|
|
||||||
dates: number[]
|
|
||||||
} = res as any;
|
|
||||||
|
|
||||||
let categoryDiv = document.createElement('div');
|
let categoryDiv = document.createElement('div');
|
||||||
categoryDiv.classList.add('sticker-category');
|
categoryDiv.classList.add('sticker-category');
|
||||||
|
|
||||||
@ -408,8 +402,7 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement,
|
|||||||
reader.readAsArrayBuffer(blob);
|
reader.readAsArrayBuffer(blob);
|
||||||
} else {
|
} else {
|
||||||
let image = new Image();
|
let image = new Image();
|
||||||
//image.src = URL.createObjectURL(blob);
|
renderImageFromUrl(image, URL.createObjectURL(blob));
|
||||||
appWebpManager.polyfillImage(image, blob);
|
|
||||||
|
|
||||||
li.append(image);
|
li.append(image);
|
||||||
}
|
}
|
||||||
|
@ -19,16 +19,18 @@ export default class LazyLoadQueue {
|
|||||||
|
|
||||||
constructor(private parallelLimit = 5) {
|
constructor(private parallelLimit = 5) {
|
||||||
this.observer = new IntersectionObserver(entries => {
|
this.observer = new IntersectionObserver(entries => {
|
||||||
|
if(this.lockPromise) return;
|
||||||
|
|
||||||
for(let entry of entries) {
|
for(let entry of entries) {
|
||||||
if(entry.isIntersecting) {
|
if(entry.isIntersecting) {
|
||||||
let target = entry.target as HTMLElement;
|
let target = entry.target as HTMLElement;
|
||||||
|
|
||||||
for(let item of this.lazyLoadMedia) {
|
// need for set element first if scrolled
|
||||||
if(item.div == target) {
|
let item = this.lazyLoadMedia.findAndSplice(i => i.div == target);
|
||||||
|
if(item) {
|
||||||
item.wasSeen = true;
|
item.wasSeen = true;
|
||||||
|
this.lazyLoadMedia.unshift(item);
|
||||||
this.processQueue(item);
|
this.processQueue(item);
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,15 +121,17 @@ let set = (elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLSourceEl
|
|||||||
else elem.style.backgroundImage = 'url(' + url + ')';
|
else elem.style.backgroundImage = 'url(' + url + ')';
|
||||||
};
|
};
|
||||||
|
|
||||||
export function renderImageFromUrl(elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLSourceElement, url: string) {
|
export function renderImageFromUrl(elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLSourceElement, url: string): Promise<boolean> {
|
||||||
if(loadedURLs[url]) {
|
if(loadedURLs[url]) {
|
||||||
set(elem, url);
|
set(elem, url);
|
||||||
return true;
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(elem instanceof HTMLSourceElement) {
|
if(elem instanceof HTMLSourceElement) {
|
||||||
elem.src = url;
|
elem.src = url;
|
||||||
|
return Promise.resolve(false);
|
||||||
} else {
|
} else {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
let loader = new Image();
|
let loader = new Image();
|
||||||
loader.src = url;
|
loader.src = url;
|
||||||
//let perf = performance.now();
|
//let perf = performance.now();
|
||||||
@ -137,10 +139,11 @@ export function renderImageFromUrl(elem: HTMLElement | HTMLImageElement | SVGIma
|
|||||||
set(elem, url);
|
set(elem, url);
|
||||||
loadedURLs[url] = true;
|
loadedURLs[url] = true;
|
||||||
//console.log('onload:', url, performance.now() - perf);
|
//console.log('onload:', url, performance.now() - perf);
|
||||||
|
resolve(false);
|
||||||
|
});
|
||||||
|
loader.addEventListener('error', reject);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function putPreloader(elem: Element, returnDiv = false) {
|
export function putPreloader(elem: Element, returnDiv = false) {
|
||||||
|
@ -56,6 +56,9 @@ export default class Scrollable {
|
|||||||
private lastBottomID = 0;
|
private lastBottomID = 0;
|
||||||
private lastScrollDirection = 0; // true = bottom
|
private lastScrollDirection = 0; // true = bottom
|
||||||
|
|
||||||
|
private onScrolledTopFired = false;
|
||||||
|
private onScrolledBottomFired = false;
|
||||||
|
|
||||||
public scrollLocked = 0;
|
public scrollLocked = 0;
|
||||||
|
|
||||||
private setVisible(element: HTMLElement) {
|
private setVisible(element: HTMLElement) {
|
||||||
@ -184,37 +187,56 @@ export default class Scrollable {
|
|||||||
//this.onScroll();
|
//this.onScroll();
|
||||||
}
|
}
|
||||||
|
|
||||||
public attachSentinels(container = this.container, offset = this.onScrollOffset) {
|
// public attachSentinels(container = this.container, offset = this.onScrollOffset) {
|
||||||
if(!this.sentinelsObserver) {
|
// if(!this.sentinelsObserver) {
|
||||||
this.topSentinel = document.createElement('div');
|
// this.topSentinel = document.createElement('div');
|
||||||
this.topSentinel.classList.add('scrollable-sentinel');
|
// this.topSentinel.classList.add('scrollable-sentinel');
|
||||||
this.topSentinel.style.top = offset + 'px';
|
// this.topSentinel.style.top = offset + 'px';
|
||||||
this.bottomSentinel = document.createElement('div');
|
// this.bottomSentinel = document.createElement('div');
|
||||||
this.bottomSentinel.classList.add('scrollable-sentinel');
|
// this.bottomSentinel.classList.add('scrollable-sentinel');
|
||||||
this.bottomSentinel.style.bottom = offset + 'px';
|
// this.bottomSentinel.style.bottom = offset + 'px';
|
||||||
|
|
||||||
this.container.append(this.topSentinel, this.bottomSentinel);
|
// this.container.append(this.topSentinel, this.bottomSentinel);
|
||||||
|
|
||||||
this.sentinelsObserver = new IntersectionObserver(entries => {
|
// //let fire: () => void;
|
||||||
for(let entry of entries) {
|
|
||||||
if(entry.isIntersecting) {
|
|
||||||
let top = entry.target == this.topSentinel;
|
|
||||||
if(top) {
|
|
||||||
this.onScrolledTop && this.onScrolledTop();
|
|
||||||
} else {
|
|
||||||
this.onScrolledBottom && this.onScrolledBottom();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.sentinelsObserver.observe(this.topSentinel);
|
// this.sentinelsObserver = new IntersectionObserver(entries => {
|
||||||
this.sentinelsObserver.observe(this.bottomSentinel);
|
// for(let entry of entries) {
|
||||||
}
|
// let top = entry.target == this.topSentinel;
|
||||||
|
// if(top) {
|
||||||
|
// this.onScrolledTopFired = entry.isIntersecting;
|
||||||
|
// } else {
|
||||||
|
// this.onScrolledBottomFired = entry.isIntersecting;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
container.prepend(this.topSentinel);
|
// /* this.debug && */this.log('Set onScrolledFires:', this.onScrolledTopFired, this.onScrolledBottomFired);
|
||||||
container.append(this.bottomSentinel);
|
|
||||||
}
|
// /* 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;
|
||||||
@ -246,8 +268,13 @@ export default class Scrollable {
|
|||||||
this.lastScrollDirection = 0;
|
this.lastScrollDirection = 0;
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|
||||||
if(!this.splitUp || this.onScrollMeasure) return;
|
if(this.onScrollMeasure) return;
|
||||||
this.onScrollMeasure = window.requestAnimationFrame(() => {
|
this.onScrollMeasure = window.requestAnimationFrame(() => {
|
||||||
|
this.checkForTriggers();
|
||||||
|
|
||||||
|
this.onScrollMeasure = 0;
|
||||||
|
if(!this.splitUp) return;
|
||||||
|
|
||||||
let scrollTop = this.container.scrollTop;
|
let scrollTop = this.container.scrollTop;
|
||||||
if(this.lastScrollTop != scrollTop) {
|
if(this.lastScrollTop != scrollTop) {
|
||||||
this.lastScrollDirection = this.lastScrollTop < scrollTop ? 1 : -1;
|
this.lastScrollDirection = this.lastScrollTop < scrollTop ? 1 : -1;
|
||||||
@ -255,10 +282,24 @@ export default class Scrollable {
|
|||||||
} else {
|
} else {
|
||||||
this.lastScrollDirection = 0;
|
this.lastScrollDirection = 0;
|
||||||
}
|
}
|
||||||
this.onScrollMeasure = 0;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public checkForTriggers() {
|
||||||
|
if(this.scrollLocked || (!this.onScrolledTop && !this.onScrolledBottom)) return;
|
||||||
|
|
||||||
|
let scrollTop = this.container.scrollTop;
|
||||||
|
let maxScrollTop = this.container.scrollHeight - this.container.clientHeight;
|
||||||
|
|
||||||
|
if(this.onScrolledTop && scrollTop <= this.onScrollOffset) {
|
||||||
|
this.onScrolledTop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.onScrolledBottom && (maxScrollTop - scrollTop) <= this.onScrollOffset) {
|
||||||
|
this.onScrolledBottom();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public reorder() {
|
public reorder() {
|
||||||
(Array.from(this.splitUp.children) as HTMLElement[]).forEach((el, idx) => {
|
(Array.from(this.splitUp.children) as HTMLElement[]).forEach((el, idx) => {
|
||||||
el.dataset.virtual = '' + idx;
|
el.dataset.virtual = '' + idx;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import appPhotosManager, { MTPhoto } from '../lib/appManagers/appPhotosManager';
|
import appPhotosManager from '../lib/appManagers/appPhotosManager';
|
||||||
//import CryptoWorker from '../lib/crypto/cryptoworker';
|
//import CryptoWorker from '../lib/crypto/cryptoworker';
|
||||||
import apiManager from '../lib/mtproto/mtprotoworker';
|
import apiManager from '../lib/mtproto/mtprotoworker';
|
||||||
import LottieLoader from '../lib/lottieLoader';
|
import LottieLoader from '../lib/lottieLoader';
|
||||||
@ -8,7 +8,6 @@ import { formatBytes } from "../lib/utils";
|
|||||||
import ProgressivePreloader from './preloader';
|
import ProgressivePreloader from './preloader';
|
||||||
import LazyLoadQueue from './lazyLoadQueue';
|
import LazyLoadQueue from './lazyLoadQueue';
|
||||||
import apiFileManager from '../lib/mtproto/apiFileManager';
|
import apiFileManager from '../lib/mtproto/apiFileManager';
|
||||||
import appWebpManager from '../lib/appManagers/appWebpManager';
|
|
||||||
import VideoPlayer, { MediaProgressLine } from '../lib/mediaPlayer';
|
import VideoPlayer, { MediaProgressLine } from '../lib/mediaPlayer';
|
||||||
import { RichTextProcessor } from '../lib/richtextprocessor';
|
import { RichTextProcessor } from '../lib/richtextprocessor';
|
||||||
import { CancellablePromise } from '../lib/polyfill';
|
import { CancellablePromise } from '../lib/polyfill';
|
||||||
@ -16,6 +15,7 @@ import { renderImageFromUrl } from './misc';
|
|||||||
import appMessagesManager from '../lib/appManagers/appMessagesManager';
|
import appMessagesManager from '../lib/appManagers/appMessagesManager';
|
||||||
import { Layouter, RectPart } from './groupedLayout';
|
import { Layouter, RectPart } from './groupedLayout';
|
||||||
import PollElement from './poll';
|
import PollElement from './poll';
|
||||||
|
import appWebpManager from '../lib/appManagers/appWebpManager';
|
||||||
|
|
||||||
export type MTDocument = {
|
export type MTDocument = {
|
||||||
_: 'document' | 'documentEmpty',
|
_: 'document' | 'documentEmpty',
|
||||||
@ -40,15 +40,15 @@ export type MTDocument = {
|
|||||||
duration?: number,
|
duration?: number,
|
||||||
downloaded?: boolean,
|
downloaded?: boolean,
|
||||||
url?: string,
|
url?: string,
|
||||||
version?: any,
|
|
||||||
|
|
||||||
audioTitle?: string,
|
audioTitle?: string,
|
||||||
audioPerformer?: string,
|
audioPerformer?: string,
|
||||||
|
|
||||||
sticker?: boolean,
|
sticker?: number,
|
||||||
stickerEmoji?: string,
|
stickerEmoji?: string,
|
||||||
stickerEmojiRaw?: string,
|
stickerEmojiRaw?: string,
|
||||||
stickerSetInput?: any,
|
stickerSetInput?: any,
|
||||||
|
stickerThumbConverted?: true,
|
||||||
|
|
||||||
animated?: boolean
|
animated?: boolean
|
||||||
};
|
};
|
||||||
@ -74,49 +74,40 @@ export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTai
|
|||||||
middleware: () => boolean,
|
middleware: () => boolean,
|
||||||
lazyLoadQueue: LazyLoadQueue
|
lazyLoadQueue: LazyLoadQueue
|
||||||
}) {
|
}) {
|
||||||
let img: HTMLImageElement | SVGImageElement;
|
let img: HTMLImageElement;
|
||||||
|
|
||||||
if(withTail) {
|
if(withTail) {
|
||||||
img = wrapMediaWithTail(doc, message, container, boxWidth, boxHeight, isOut);
|
img = wrapMediaWithTail(doc, message, container, boxWidth, boxHeight, isOut);
|
||||||
} else if(!boxWidth && !boxHeight) { // album
|
} else {
|
||||||
|
if(!boxWidth && !boxHeight) { // album
|
||||||
let sizes = doc.thumbs;
|
let sizes = doc.thumbs;
|
||||||
if(!doc.downloaded && sizes && sizes[0].bytes) {
|
if(!doc.downloaded && sizes && sizes[0].bytes) {
|
||||||
appPhotosManager.setAttachmentPreview(sizes[0].bytes, container, false);
|
appPhotosManager.setAttachmentPreview(sizes[0].bytes, container, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
img = container.firstElementChild as HTMLImageElement || new Image();
|
|
||||||
|
|
||||||
if(!container.contains(img)) {
|
|
||||||
container.append(img);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if(!container.firstElementChild || (container.firstElementChild.tagName != 'IMG' && container.firstElementChild.tagName != 'VIDEO')) {
|
if(!container.firstElementChild || (container.firstElementChild.tagName != 'IMG' && container.firstElementChild.tagName != 'VIDEO')) {
|
||||||
let size = appPhotosManager.setAttachmentSize(doc, container, boxWidth, boxHeight);
|
appPhotosManager.setAttachmentSize(doc, container, boxWidth, boxHeight);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
img = container.firstElementChild as HTMLImageElement || new Image();
|
img = container.lastElementChild as HTMLImageElement;
|
||||||
|
if(!img || img.tagName != 'IMG') {
|
||||||
if(!container.contains(img)) {
|
container.append(img = new Image());
|
||||||
container.append(img);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let video = document.createElement('video');
|
let video = document.createElement('video');
|
||||||
if(withTail) {
|
|
||||||
let foreignObject = document.createElementNS("http://www.w3.org/2000/svg", 'foreignObject');
|
|
||||||
let width = img.getAttributeNS(null, 'width');
|
|
||||||
let height = img.getAttributeNS(null, 'height');
|
|
||||||
foreignObject.setAttributeNS(null, 'width', width);
|
|
||||||
foreignObject.setAttributeNS(null, 'height', height);
|
|
||||||
video.width = +width;
|
|
||||||
video.height = +height;
|
|
||||||
foreignObject.append(video);
|
|
||||||
img.parentElement.append(foreignObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
let source = document.createElement('source');
|
let source = document.createElement('source');
|
||||||
video.append(source);
|
video.append(source);
|
||||||
|
|
||||||
|
if(withTail) {
|
||||||
|
let foreignObject = img.parentElement;
|
||||||
|
video.width = +foreignObject.getAttributeNS(null, 'width');
|
||||||
|
video.height = +foreignObject.getAttributeNS(null, 'height');
|
||||||
|
foreignObject.append(video);
|
||||||
|
} else {
|
||||||
|
container.append(video);
|
||||||
|
}
|
||||||
|
|
||||||
let span: HTMLSpanElement;
|
let span: HTMLSpanElement;
|
||||||
if(doc.type != 'round') {
|
if(doc.type != 'round') {
|
||||||
span = document.createElement('span');
|
span = document.createElement('span');
|
||||||
@ -154,12 +145,8 @@ export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTai
|
|||||||
source.type = doc.mime_type;
|
source.type = doc.mime_type;
|
||||||
video.append(source);
|
video.append(source);
|
||||||
|
|
||||||
if(!withTail) {
|
if(img && img.parentElement) {
|
||||||
if(img && container.contains(img)) {
|
img.remove();
|
||||||
container.removeChild(img);
|
|
||||||
}
|
|
||||||
|
|
||||||
container.append(video);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(doc.type == 'gif') {
|
if(doc.type == 'gif') {
|
||||||
@ -594,13 +581,15 @@ function wrapMediaWithTail(photo: any, message: {mid: number, message: string},
|
|||||||
let svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
let svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
||||||
svg.classList.add('bubble__media-container', isOut ? 'is-out' : 'is-in');
|
svg.classList.add('bubble__media-container', isOut ? 'is-out' : 'is-in');
|
||||||
|
|
||||||
let image = document.createElementNS("http://www.w3.org/2000/svg", "image");
|
let foreignObject = document.createElementNS("http://www.w3.org/2000/svg", 'foreignObject');
|
||||||
svg.append(image);
|
|
||||||
|
|
||||||
let size = appPhotosManager.setAttachmentSize(photo._ == 'document' ? photo : photo.id, svg, boxWidth, boxHeight);
|
appPhotosManager.setAttachmentSize(photo._ == 'document' ? photo : photo.id, foreignObject, boxWidth, boxHeight);
|
||||||
|
|
||||||
let width = +svg.getAttributeNS(null, 'width');
|
let width = +foreignObject.getAttributeNS(null, 'width');
|
||||||
let height = +svg.getAttributeNS(null, 'height');
|
let height = +foreignObject.getAttributeNS(null, 'height');
|
||||||
|
|
||||||
|
svg.setAttributeNS(null, 'width', '' + width);
|
||||||
|
svg.setAttributeNS(null, 'height', '' + height);
|
||||||
|
|
||||||
let clipID = 'clip' + message.mid;
|
let clipID = 'clip' + message.mid;
|
||||||
svg.dataset.clipID = clipID;
|
svg.dataset.clipID = clipID;
|
||||||
@ -626,36 +615,38 @@ function wrapMediaWithTail(photo: any, message: {mid: number, message: string},
|
|||||||
|
|
||||||
defs.innerHTML = `<clipPath id="${clipID}">${clipPathHTML}</clipPath>`;
|
defs.innerHTML = `<clipPath id="${clipID}">${clipPathHTML}</clipPath>`;
|
||||||
|
|
||||||
svg.prepend(defs);
|
container.style.width = parseInt(container.style.width) - 9 + 'px';
|
||||||
container.appendChild(svg);
|
|
||||||
|
|
||||||
return image;
|
svg.append(defs, foreignObject);
|
||||||
|
container.append(svg);
|
||||||
|
|
||||||
|
let img = foreignObject.firstElementChild as HTMLImageElement;
|
||||||
|
if(!img) {
|
||||||
|
foreignObject.append(img = new Image());
|
||||||
|
}
|
||||||
|
|
||||||
|
return img;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function wrapPhoto(photoID: string, message: any, container: HTMLDivElement, boxWidth = 380, boxHeight = 380, withTail = true, isOut = false, lazyLoadQueue: LazyLoadQueue, middleware: () => boolean, size: MTPhotoSize = null) {
|
export function wrapPhoto(photoID: string, message: any, container: HTMLDivElement, boxWidth = 380, boxHeight = 380, withTail = true, isOut = false, lazyLoadQueue: LazyLoadQueue, middleware: () => boolean, size: MTPhotoSize = null) {
|
||||||
let photo = appPhotosManager.getPhoto(photoID);
|
let photo = appPhotosManager.getPhoto(photoID);
|
||||||
|
|
||||||
let image: SVGImageElement | HTMLImageElement;
|
let image: HTMLImageElement;
|
||||||
if(withTail) {
|
if(withTail) {
|
||||||
image = wrapMediaWithTail(photo, message, container, boxWidth, boxHeight, isOut);
|
image = wrapMediaWithTail(photo, message, container, boxWidth, boxHeight, isOut);
|
||||||
} else if(size) { // album
|
} else {
|
||||||
|
if(size) { // album
|
||||||
let sizes = photo.sizes;
|
let sizes = photo.sizes;
|
||||||
if(!photo.downloaded && sizes && sizes[0].bytes) {
|
if(!photo.downloaded && sizes && sizes[0].bytes) {
|
||||||
appPhotosManager.setAttachmentPreview(sizes[0].bytes, container, false);
|
appPhotosManager.setAttachmentPreview(sizes[0].bytes, container, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
image = container.firstElementChild as HTMLImageElement || new Image();
|
|
||||||
|
|
||||||
if(!container.contains(image)) {
|
|
||||||
container.appendChild(image);
|
|
||||||
}
|
|
||||||
} else if(boxWidth && boxHeight) { // means webpage's preview
|
} else if(boxWidth && boxHeight) { // means webpage's preview
|
||||||
size = appPhotosManager.setAttachmentSize(photoID, container, boxWidth, boxHeight, false);
|
size = appPhotosManager.setAttachmentSize(photoID, container, boxWidth, boxHeight, false);
|
||||||
|
}
|
||||||
|
|
||||||
image = container.firstElementChild as HTMLImageElement || new Image();
|
image = container.lastElementChild as HTMLImageElement;
|
||||||
|
if(!image || image.tagName != 'IMG') {
|
||||||
if(!container.contains(image)) {
|
container.append(image = new Image());
|
||||||
container.appendChild(image);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -694,7 +685,7 @@ export function wrapPhoto(photoID: string, message: any, container: HTMLDivEleme
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function wrapSticker(doc: MTDocument, div: HTMLDivElement, middleware?: () => boolean, lazyLoadQueue?: LazyLoadQueue, group?: string, canvas?: boolean, play = false, onlyThumb = false) {
|
export function wrapSticker(doc: MTDocument, div: HTMLDivElement, middleware?: () => boolean, lazyLoadQueue?: LazyLoadQueue, group?: string, canvas?: boolean, play = false, onlyThumb = false) {
|
||||||
let stickerType = doc.mime_type == "application/x-tgsticker" ? 2 : (doc.mime_type == "image/webp" ? 1 : 0);
|
let stickerType = doc.sticker;
|
||||||
|
|
||||||
if(stickerType == 2 && !LottieLoader.loaded) {
|
if(stickerType == 2 && !LottieLoader.loaded) {
|
||||||
LottieLoader.loadLottie();
|
LottieLoader.loadLottie();
|
||||||
@ -702,9 +693,11 @@ export function wrapSticker(doc: MTDocument, div: HTMLDivElement, middleware?: (
|
|||||||
|
|
||||||
if(!stickerType) {
|
if(!stickerType) {
|
||||||
console.error('wrong doc for wrapSticker!', doc);
|
console.error('wrong doc for wrapSticker!', doc);
|
||||||
return Promise.resolve();
|
throw new Error('wrong doc for wrapSticker!');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.dataset.docID = doc.id;
|
||||||
|
|
||||||
//console.log('wrap sticker', doc, div, onlyThumb);
|
//console.log('wrap sticker', doc, div, onlyThumb);
|
||||||
|
|
||||||
if(doc.thumbs && !div.firstElementChild && (!doc.downloaded || stickerType == 2)) {
|
if(doc.thumbs && !div.firstElementChild && (!doc.downloaded || stickerType == 2)) {
|
||||||
@ -713,32 +706,61 @@ export function wrapSticker(doc: MTDocument, div: HTMLDivElement, middleware?: (
|
|||||||
//console.log('wrap sticker', thumb, div);
|
//console.log('wrap sticker', thumb, div);
|
||||||
|
|
||||||
if(thumb.bytes) {
|
if(thumb.bytes) {
|
||||||
apiFileManager.saveSmallFile(thumb.location, thumb.bytes);
|
|
||||||
|
|
||||||
appPhotosManager.setAttachmentPreview(thumb.bytes, div, true);
|
|
||||||
|
|
||||||
if(onlyThumb) return Promise.resolve();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(onlyThumb && doc.thumbs) {
|
|
||||||
let thumb = doc.thumbs[0];
|
|
||||||
|
|
||||||
let load = () => apiFileManager.downloadSmallFile({
|
|
||||||
_: 'inputDocumentFileLocation',
|
|
||||||
access_hash: doc.access_hash,
|
|
||||||
file_reference: doc.file_reference,
|
|
||||||
thumb_size: thumb.type,
|
|
||||||
id: doc.id
|
|
||||||
}, {dcID: doc.dc_id}).then(blob => {
|
|
||||||
let img = new Image();
|
let img = new Image();
|
||||||
|
|
||||||
appWebpManager.polyfillImage(img, blob);
|
if(appWebpManager.isSupported() || doc.stickerThumbConverted) {
|
||||||
|
renderImageFromUrl(img, appPhotosManager.getPreviewURLFromThumb(thumb, true));
|
||||||
|
|
||||||
div.append(img);
|
div.append(img);
|
||||||
|
} else {
|
||||||
|
appWebpManager.convertToPng(thumb.bytes).then(bytes => {
|
||||||
|
if(middleware && !middleware()) return;
|
||||||
|
|
||||||
div.dataset.docID = doc.id;
|
thumb.bytes = bytes;
|
||||||
appStickersManager.saveSticker(doc);
|
doc.stickerThumbConverted = true;
|
||||||
|
|
||||||
|
if(!div.childElementCount) {
|
||||||
|
renderImageFromUrl(img, appPhotosManager.getPreviewURLFromThumb(thumb, true)).then(() => {
|
||||||
|
div.append(img);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if(onlyThumb) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
} else if(!onlyThumb && stickerType == 2) {
|
||||||
|
let img = new Image();
|
||||||
|
let load = () => appDocsManager.downloadDocThumb(doc, thumb.type).then(url => {
|
||||||
|
if(!img.parentElement || (middleware && !middleware())) return;
|
||||||
|
let promise = renderImageFromUrl(img, url);
|
||||||
|
|
||||||
|
if(!downloaded) {
|
||||||
|
promise.then(() => {
|
||||||
|
div.append(img);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let downloaded = appDocsManager.hasDownloadedThumb(doc.id, thumb.type);
|
||||||
|
if(downloaded) {
|
||||||
|
div.append(img);
|
||||||
|
}
|
||||||
|
|
||||||
|
lazyLoadQueue && !downloaded ? lazyLoadQueue.push({div, load}) : load();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(onlyThumb && doc.thumbs) { // for sticker panel
|
||||||
|
let thumb = doc.thumbs[0];
|
||||||
|
|
||||||
|
let load = () => appDocsManager.downloadDocThumb(doc, thumb.type).then(url => {
|
||||||
|
let img = new Image();
|
||||||
|
renderImageFromUrl(img, url).then(() => {
|
||||||
|
if(middleware && !middleware()) return;
|
||||||
|
div.append(img);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return lazyLoadQueue ? (lazyLoadQueue.push({div, load}), Promise.resolve()) : load();
|
return lazyLoadQueue ? (lazyLoadQueue.push({div, load}), Promise.resolve()) : load();
|
||||||
@ -749,9 +771,7 @@ export function wrapSticker(doc: MTDocument, div: HTMLDivElement, middleware?: (
|
|||||||
//console.log('loaded sticker:', blob, div);
|
//console.log('loaded sticker:', blob, div);
|
||||||
if(middleware && !middleware()) return;
|
if(middleware && !middleware()) return;
|
||||||
|
|
||||||
/* if(div.firstElementChild) {
|
//return;
|
||||||
div.firstElementChild.remove();
|
|
||||||
} */
|
|
||||||
|
|
||||||
if(stickerType == 2) {
|
if(stickerType == 2) {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
@ -802,15 +822,7 @@ export function wrapSticker(doc: MTDocument, div: HTMLDivElement, middleware?: (
|
|||||||
}, {once: true});
|
}, {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) {
|
if(play) {
|
||||||
animation.play();
|
animation.play();
|
||||||
@ -831,23 +843,14 @@ export function wrapSticker(doc: MTDocument, div: HTMLDivElement, middleware?: (
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!doc.url) {
|
renderImageFromUrl(img, doc.url).then(() => {
|
||||||
appWebpManager.polyfillImage(img, blob).then((url) => {
|
|
||||||
doc.url = url;
|
|
||||||
|
|
||||||
if(div.firstElementChild && div.firstElementChild != img) {
|
if(div.firstElementChild && div.firstElementChild != img) {
|
||||||
div.firstElementChild.remove();
|
div.firstElementChild.remove();
|
||||||
}
|
}
|
||||||
});
|
|
||||||
} else {
|
|
||||||
img.src = doc.url;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.append(img);
|
div.append(img);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
div.dataset.docID = doc.id;
|
|
||||||
appStickersManager.saveSticker(doc);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return lazyLoadQueue && (!doc.downloaded || stickerType == 2) ? (lazyLoadQueue.push({div, load, wasSeen: group == 'chat'}), Promise.resolve()) : load();
|
return lazyLoadQueue && (!doc.downloaded || stickerType == 2) ? (lazyLoadQueue.push({div, load, wasSeen: group == 'chat'}), Promise.resolve()) : load();
|
||||||
|
@ -3,6 +3,7 @@ import { RichTextProcessor } from "../richtextprocessor";
|
|||||||
import appUsersManager from "./appUsersManager";
|
import appUsersManager from "./appUsersManager";
|
||||||
import apiManager from '../mtproto/mtprotoworker';
|
import apiManager from '../mtproto/mtprotoworker';
|
||||||
import apiUpdatesManager from "./apiUpdatesManager";
|
import apiUpdatesManager from "./apiUpdatesManager";
|
||||||
|
import appProfileManager from "./appProfileManager";
|
||||||
|
|
||||||
type Channel = {
|
type Channel = {
|
||||||
_: 'channel',
|
_: 'channel',
|
||||||
@ -42,6 +43,8 @@ export class AppChatsManager {
|
|||||||
public megagroups: any = {};
|
public megagroups: any = {};
|
||||||
public cachedPhotoLocations: any = {};
|
public cachedPhotoLocations: any = {};
|
||||||
|
|
||||||
|
public megagroupOnlines: {[id: number]: {timestamp: number, onlines: number}} = {};
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
$rootScope.$on('apiUpdate', (e: CustomEvent) => {
|
$rootScope.$on('apiUpdate', (e: CustomEvent) => {
|
||||||
// console.log('on apiUpdate', update)
|
// console.log('on apiUpdate', update)
|
||||||
@ -130,7 +133,7 @@ export class AppChatsManager {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var chat = this.getChat(id);
|
let chat = this.getChat(id);
|
||||||
if(chat._ == 'chatForbidden' ||
|
if(chat._ == 'chatForbidden' ||
|
||||||
chat._ == 'channelForbidden' ||
|
chat._ == 'channelForbidden' ||
|
||||||
chat.pFlags.kicked ||
|
chat.pFlags.kicked ||
|
||||||
@ -191,7 +194,7 @@ export class AppChatsManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public isChannel(id: number) {
|
public isChannel(id: number) {
|
||||||
var chat = this.chats[id];
|
let chat = this.chats[id];
|
||||||
if(chat && (chat._ == 'channel' || chat._ == 'channelForbidden') || this.channelAccess[id]) {
|
if(chat && (chat._ == 'channel' || chat._ == 'channelForbidden') || this.channelAccess[id]) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -203,7 +206,7 @@ export class AppChatsManager {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var chat = this.chats[id];
|
let chat = this.chats[id];
|
||||||
if(chat && chat._ == 'channel' && chat.pFlags.megagroup) {
|
if(chat && chat._ == 'channel' && chat.pFlags.megagroup) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -246,12 +249,12 @@ export class AppChatsManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public hasChat(id: number, allowMin?: any) {
|
public hasChat(id: number, allowMin?: any) {
|
||||||
var chat = this.chats[id]
|
let chat = this.chats[id]
|
||||||
return isObject(chat) && (allowMin || !chat.pFlags.min);
|
return isObject(chat) && (allowMin || !chat.pFlags.min);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getChatPhoto(id: number) {
|
public getChatPhoto(id: number) {
|
||||||
var chat = this.getChat(id);
|
let chat = this.getChat(id);
|
||||||
|
|
||||||
if(this.cachedPhotoLocations[id] === undefined) {
|
if(this.cachedPhotoLocations[id] === undefined) {
|
||||||
this.cachedPhotoLocations[id] = chat && chat.photo ? chat.photo : {empty: true};
|
this.cachedPhotoLocations[id] = chat && chat.photo ? chat.photo : {empty: true};
|
||||||
@ -261,7 +264,7 @@ export class AppChatsManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getChatString(id: number) {
|
public getChatString(id: number) {
|
||||||
var chat = this.getChat(id);
|
let chat = this.getChat(id);
|
||||||
if(this.isChannel(id)) {
|
if(this.isChannel(id)) {
|
||||||
return (this.isMegagroup(id) ? 's' : 'c') + id + '_' + chat.access_hash;
|
return (this.isMegagroup(id) ? 's' : 'c') + id + '_' + chat.access_hash;
|
||||||
}
|
}
|
||||||
@ -277,8 +280,8 @@ export class AppChatsManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public wrapForFull(id: number, fullChat: any) {
|
public wrapForFull(id: number, fullChat: any) {
|
||||||
var chatFull = copy(fullChat);
|
let chatFull = copy(fullChat);
|
||||||
var chat = this.getChat(id);
|
let chat = this.getChat(id);
|
||||||
|
|
||||||
if(!chatFull.participants_count) {
|
if(!chatFull.participants_count) {
|
||||||
chatFull.participants_count = chat.participants_count;
|
chatFull.participants_count = chat.participants_count;
|
||||||
@ -300,10 +303,10 @@ export class AppChatsManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public wrapParticipants(id: number, participants: any[]) {
|
public wrapParticipants(id: number, participants: any[]) {
|
||||||
var chat = this.getChat(id);
|
let chat = this.getChat(id);
|
||||||
var myID = appUsersManager.getSelf().id;
|
let myID = appUsersManager.getSelf().id;
|
||||||
if(this.isChannel(id)) {
|
if(this.isChannel(id)) {
|
||||||
var isAdmin = chat.pFlags.creator || chat.pFlags.editor || chat.pFlags.moderator;
|
let isAdmin = chat.pFlags.creator || chat.pFlags.editor || chat.pFlags.moderator;
|
||||||
participants.forEach((participant) => {
|
participants.forEach((participant) => {
|
||||||
participant.canLeave = myID == participant.user_id;
|
participant.canLeave = myID == participant.user_id;
|
||||||
participant.canKick = isAdmin && participant._ == 'channelParticipant';
|
participant.canKick = isAdmin && participant._ == 'channelParticipant';
|
||||||
@ -312,7 +315,7 @@ export class AppChatsManager {
|
|||||||
participant.user = appUsersManager.getUser(participant.user_id);
|
participant.user = appUsersManager.getUser(participant.user_id);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
var isAdmin = chat.pFlags.creator || chat.pFlags.admins_enabled && chat.pFlags.admin;
|
let isAdmin = chat.pFlags.creator || chat.pFlags.admins_enabled && chat.pFlags.admin;
|
||||||
participants.forEach((participant) => {
|
participants.forEach((participant) => {
|
||||||
participant.canLeave = myID == participant.user_id;
|
participant.canLeave = myID == participant.user_id;
|
||||||
participant.canKick = !participant.canLeave && (
|
participant.canKick = !participant.canLeave && (
|
||||||
@ -388,6 +391,44 @@ export class AppChatsManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async getOnlines(id: number): Promise<number> {
|
||||||
|
if(this.isMegagroup(id)) {
|
||||||
|
let timestamp = Date.now() / 1000 | 0;
|
||||||
|
let cached = this.megagroupOnlines[id] ?? (this.megagroupOnlines[id] = {timestamp: 0, onlines: 1});
|
||||||
|
if((timestamp - cached.timestamp) < 60) {
|
||||||
|
return cached.onlines;
|
||||||
|
}
|
||||||
|
|
||||||
|
let res = await apiManager.invokeApi('messages.getOnlines', {
|
||||||
|
peer: this.getChannelInputPeer(id)
|
||||||
|
});
|
||||||
|
|
||||||
|
let onlines = res.onlines ?? 1;
|
||||||
|
cached.timestamp = timestamp;
|
||||||
|
cached.onlines = onlines;
|
||||||
|
|
||||||
|
return onlines;
|
||||||
|
} else if(this.isBroadcast(id)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let chatInfo = appProfileManager.getChatFull(id);
|
||||||
|
if(chatInfo._ == 'chatFull' && chatInfo.participants && chatInfo.participants.participants) {
|
||||||
|
let participants = chatInfo.participants.participants;
|
||||||
|
|
||||||
|
return participants.reduce((acc: number, participant: any) => {
|
||||||
|
let user = appUsersManager.getUser(participant.user_id);
|
||||||
|
if(user && user.status && user.status._ == 'userStatusOnline') {
|
||||||
|
return acc + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, 0);
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new AppChatsManager();
|
export default new AppChatsManager();
|
||||||
|
@ -409,12 +409,12 @@ export class AppDialogsManager {
|
|||||||
this.scroll = new Scrollable(this.chatsContainer, 'y', 'CL', this.chatList, 500);
|
this.scroll = new Scrollable(this.chatsContainer, 'y', 'CL', this.chatList, 500);
|
||||||
this.scroll.setVirtualContainer(this.chatList);
|
this.scroll.setVirtualContainer(this.chatList);
|
||||||
this.scroll.onScrolledBottom = this.onChatsScroll.bind(this);
|
this.scroll.onScrolledBottom = this.onChatsScroll.bind(this);
|
||||||
this.scroll.attachSentinels();
|
//this.scroll.attachSentinels();
|
||||||
|
|
||||||
this.scrollArchived = new Scrollable(this.chatsArchivedContainer, 'y', 'CLA', this.chatListArchived, 500);
|
this.scrollArchived = new Scrollable(this.chatsArchivedContainer, 'y', 'CLA', this.chatListArchived, 500);
|
||||||
this.scrollArchived.setVirtualContainer(this.chatListArchived);
|
this.scrollArchived.setVirtualContainer(this.chatListArchived);
|
||||||
this.scrollArchived.onScrolledBottom = this.onChatsArchivedScroll.bind(this);
|
this.scrollArchived.onScrolledBottom = this.onChatsArchivedScroll.bind(this);
|
||||||
this.scroll.attachSentinels();
|
///this.scroll.attachSentinels();
|
||||||
|
|
||||||
this.setListClickListener(this.chatList);
|
this.setListClickListener(this.chatList);
|
||||||
this.setListClickListener(this.chatListArchived);
|
this.setListClickListener(this.chatListArchived);
|
||||||
@ -828,7 +828,7 @@ export class AppDialogsManager {
|
|||||||
dom.lastTimeSpan.innerHTML = timeStr;
|
dom.lastTimeSpan.innerHTML = timeStr;
|
||||||
} else dom.lastTimeSpan.innerHTML = '';
|
} else dom.lastTimeSpan.innerHTML = '';
|
||||||
|
|
||||||
if(this.doms[peerID] || this.domsArchived[peerID]) {
|
if((this.doms[peerID] || this.domsArchived[peerID]) == dom) {
|
||||||
this.setUnreadMessages(dialog);
|
this.setUnreadMessages(dialog);
|
||||||
} else { // means search
|
} else { // means search
|
||||||
dom.listEl.dataset.mid = lastMessage.mid;
|
dom.listEl.dataset.mid = lastMessage.mid;
|
||||||
|
@ -7,8 +7,9 @@ import { isObject } from '../utils';
|
|||||||
|
|
||||||
class AppDocsManager {
|
class AppDocsManager {
|
||||||
private docs: {[docID: string]: MTDocument} = {};
|
private docs: {[docID: string]: MTDocument} = {};
|
||||||
|
private thumbs: {[docIDAndSize: string]: Promise<string>} = {};
|
||||||
|
|
||||||
public saveDoc(apiDoc: MTDocument/* any */, context?: any) {
|
public saveDoc(apiDoc: MTDocument, context?: any) {
|
||||||
//console.log('saveDoc', apiDoc, this.docs[apiDoc.id]);
|
//console.log('saveDoc', apiDoc, this.docs[apiDoc.id]);
|
||||||
if(this.docs[apiDoc.id]) {
|
if(this.docs[apiDoc.id]) {
|
||||||
let d = this.docs[apiDoc.id];
|
let d = this.docs[apiDoc.id];
|
||||||
@ -68,8 +69,6 @@ class AppDocsManager {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'documentAttributeSticker':
|
case 'documentAttributeSticker':
|
||||||
apiDoc.sticker = true;
|
|
||||||
|
|
||||||
if(attribute.alt !== undefined) {
|
if(attribute.alt !== undefined) {
|
||||||
apiDoc.stickerEmojiRaw = attribute.alt;
|
apiDoc.stickerEmojiRaw = attribute.alt;
|
||||||
apiDoc.stickerEmoji = RichTextProcessor.wrapRichText(apiDoc.stickerEmojiRaw, {noLinks: true, noLinebreaks: true});
|
apiDoc.stickerEmoji = RichTextProcessor.wrapRichText(apiDoc.stickerEmojiRaw, {noLinks: true, noLinebreaks: true});
|
||||||
@ -83,11 +82,13 @@ class AppDocsManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(apiDoc.thumbs && apiDoc.mime_type == 'image/webp') {
|
if(/* apiDoc.thumbs && */apiDoc.mime_type == 'image/webp') {
|
||||||
apiDoc.type = 'sticker';
|
apiDoc.type = 'sticker';
|
||||||
|
apiDoc.sticker = 1;
|
||||||
} else if(apiDoc.mime_type == 'application/x-tgsticker') {
|
} else if(apiDoc.mime_type == 'application/x-tgsticker') {
|
||||||
apiDoc.type = 'sticker';
|
apiDoc.type = 'sticker';
|
||||||
apiDoc.animated = true;
|
apiDoc.animated = true;
|
||||||
|
apiDoc.sticker = 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -145,7 +146,7 @@ class AppDocsManager {
|
|||||||
return isObject(docID) ? docID : this.docs[docID];
|
return isObject(docID) ? docID : this.docs[docID];
|
||||||
}
|
}
|
||||||
|
|
||||||
public getInputByID(docID: any) {
|
public getMediaInputByID(docID: any) {
|
||||||
let doc = this.getDoc(docID);
|
let doc = this.getDoc(docID);
|
||||||
return {
|
return {
|
||||||
_: 'inputMediaDocument',
|
_: 'inputMediaDocument',
|
||||||
@ -160,6 +161,18 @@ class AppDocsManager {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getInputByID(docID: any, thumbSize?: string) {
|
||||||
|
let doc = this.getDoc(docID);
|
||||||
|
|
||||||
|
return {
|
||||||
|
_: 'inputDocumentFileLocation',
|
||||||
|
id: doc.id,
|
||||||
|
access_hash: doc.access_hash,
|
||||||
|
file_reference: doc.file_reference,
|
||||||
|
thumb_size: thumbSize
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public getFileName(doc: MTDocument) {
|
public getFileName(doc: MTDocument) {
|
||||||
if(doc.file_name) {
|
if(doc.file_name) {
|
||||||
return doc.file_name;
|
return doc.file_name;
|
||||||
@ -173,42 +186,10 @@ class AppDocsManager {
|
|||||||
return 't_' + (doc.type || 'file') + doc.id + fileExt;
|
return 't_' + (doc.type || 'file') + doc.id + fileExt;
|
||||||
}
|
}
|
||||||
|
|
||||||
public updateDocDownloaded(docID: string) {
|
public downloadDoc(docID: any, toFileEntry?: any): CancellablePromise<Blob> {
|
||||||
var doc = this.docs[docID];
|
let doc = this.getDoc(docID);
|
||||||
var inputFileLocation = {
|
|
||||||
_: 'inputDocumentFileLocation',
|
|
||||||
id: docID,
|
|
||||||
access_hash: doc.access_hash,
|
|
||||||
version: doc.version,
|
|
||||||
file_name: this.getFileName(doc)
|
|
||||||
};
|
|
||||||
|
|
||||||
if(doc.downloaded === undefined) {
|
let inputFileLocation = this.getInputByID(doc);
|
||||||
apiFileManager.getDownloadedFile(inputFileLocation, doc.size).then(() => {
|
|
||||||
doc.downloaded = true;
|
|
||||||
}, () => {
|
|
||||||
doc.downloaded = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public downloadDoc(docID: string | MTDocument, toFileEntry?: any): CancellablePromise<Blob> {
|
|
||||||
let doc: MTDocument;
|
|
||||||
if(typeof(docID) === 'string') {
|
|
||||||
doc = this.docs[docID];
|
|
||||||
} else {
|
|
||||||
doc = docID;
|
|
||||||
}
|
|
||||||
|
|
||||||
var inputFileLocation = {
|
|
||||||
_: 'inputDocumentFileLocation',
|
|
||||||
id: doc.id,
|
|
||||||
access_hash: doc.access_hash,
|
|
||||||
file_reference: doc.file_reference,
|
|
||||||
thumb_size: '',
|
|
||||||
version: doc.version,
|
|
||||||
file_name: this.getFileName(doc)
|
|
||||||
};
|
|
||||||
|
|
||||||
if(doc._ == 'documentEmpty') {
|
if(doc._ == 'documentEmpty') {
|
||||||
return Promise.reject();
|
return Promise.reject();
|
||||||
@ -217,7 +198,7 @@ class AppDocsManager {
|
|||||||
if(doc.downloaded && !toFileEntry) {
|
if(doc.downloaded && !toFileEntry) {
|
||||||
if(doc.url) return Promise.resolve(null);
|
if(doc.url) return Promise.resolve(null);
|
||||||
|
|
||||||
var cachedBlob = apiFileManager.getCachedFile(inputFileLocation);
|
let cachedBlob = apiFileManager.getCachedFile(inputFileLocation);
|
||||||
if(cachedBlob) {
|
if(cachedBlob) {
|
||||||
return Promise.resolve(cachedBlob);
|
return Promise.resolve(cachedBlob);
|
||||||
}
|
}
|
||||||
@ -226,17 +207,18 @@ class AppDocsManager {
|
|||||||
//historyDoc.progress = {enabled: !historyDoc.downloaded, percent: 1, total: doc.size};
|
//historyDoc.progress = {enabled: !historyDoc.downloaded, percent: 1, total: doc.size};
|
||||||
|
|
||||||
// нет смысла делать объект с выполняющимися промисами, нижняя строка и так вернёт загружающийся
|
// нет смысла делать объект с выполняющимися промисами, нижняя строка и так вернёт загружающийся
|
||||||
var downloadPromise: CancellablePromise<Blob> = apiFileManager.downloadFile(doc.dc_id, inputFileLocation, doc.size, {
|
let downloadPromise: CancellablePromise<Blob> = apiFileManager.downloadFile(doc.dc_id, inputFileLocation, doc.size, {
|
||||||
mimeType: doc.mime_type || 'application/octet-stream',
|
mimeType: doc.mime_type || 'application/octet-stream',
|
||||||
toFileEntry: toFileEntry
|
toFileEntry: toFileEntry,
|
||||||
|
stickerType: doc.sticker
|
||||||
});
|
});
|
||||||
|
|
||||||
downloadPromise.then((blob) => {
|
downloadPromise.then((blob) => {
|
||||||
if(blob) {
|
if(blob) {
|
||||||
doc.downloaded = true;
|
doc.downloaded = true;
|
||||||
|
|
||||||
if(/* !doc.animated || */doc.type && doc.type != 'sticker') {
|
if(doc.type && doc.sticker != 2) {
|
||||||
doc.url = FileManager.getFileCorrectUrl(blob, doc.mime_type);
|
doc.url = URL.createObjectURL(blob);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,6 +249,36 @@ class AppDocsManager {
|
|||||||
return downloadPromise;
|
return downloadPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public downloadDocThumb(docID: any, thumbSize: string) {
|
||||||
|
let doc = this.getDoc(docID);
|
||||||
|
|
||||||
|
let key = doc.id + '-' + thumbSize;
|
||||||
|
if(this.thumbs[key]) {
|
||||||
|
return this.thumbs[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
let input = this.getInputByID(doc, thumbSize);
|
||||||
|
|
||||||
|
if(doc._ == 'documentEmpty') {
|
||||||
|
return Promise.reject();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mimeType = doc.sticker ? 'image/webp' : doc.mime_type;
|
||||||
|
let promise = apiFileManager.downloadSmallFile(input, {
|
||||||
|
dcID: doc.dc_id,
|
||||||
|
stickerType: doc.sticker ? 1 : undefined,
|
||||||
|
mimeType: mimeType
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.thumbs[key] = promise.then((blob) => {
|
||||||
|
return URL.createObjectURL(blob);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public hasDownloadedThumb(docID: string, thumbSize: string) {
|
||||||
|
return !!this.thumbs[docID + '-' + thumbSize];
|
||||||
|
}
|
||||||
|
|
||||||
public async saveDocFile(docID: string) {
|
public async saveDocFile(docID: string) {
|
||||||
var doc = this.docs[docID];
|
var doc = this.docs[docID];
|
||||||
var fileName = this.getFileName(doc);
|
var fileName = this.getFileName(doc);
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import apiManager from '../mtproto/mtprotoworker';
|
import apiManager from '../mtproto/mtprotoworker';
|
||||||
import { $rootScope, numberWithCommas, findUpClassName, formatNumber, placeCaretAtEnd, findUpTag, langPack, whichChild } from "../utils";
|
import { $rootScope, numberWithCommas, findUpClassName, formatNumber, placeCaretAtEnd, findUpTag, langPack, whichChild } from "../utils";
|
||||||
import appUsersManager from "./appUsersManager";
|
import appUsersManager from "./appUsersManager";
|
||||||
import appMessagesManager, { Dialog } from "./appMessagesManager";
|
import appMessagesManager from "./appMessagesManager";
|
||||||
import appPeersManager from "./appPeersManager";
|
import appPeersManager from "./appPeersManager";
|
||||||
import appProfileManager from "./appProfileManager";
|
import appProfileManager from "./appProfileManager";
|
||||||
import appDialogsManager from "./appDialogsManager";
|
import appDialogsManager from "./appDialogsManager";
|
||||||
@ -38,7 +38,7 @@ appSidebarLeft; // just to include
|
|||||||
let testScroll = false;
|
let testScroll = false;
|
||||||
|
|
||||||
export class AppImManager {
|
export class AppImManager {
|
||||||
public pageEl = document.querySelector('.page-chats') as HTMLDivElement;
|
public pageEl = document.getElementById('page-chats') as HTMLDivElement;
|
||||||
public btnMute = this.pageEl.querySelector('.tool-mute') as HTMLButtonElement;
|
public btnMute = this.pageEl.querySelector('.tool-mute') as HTMLButtonElement;
|
||||||
public btnMenuMute = this.pageEl.querySelector('.menu-mute') as HTMLButtonElement;
|
public btnMenuMute = this.pageEl.querySelector('.menu-mute') as HTMLButtonElement;
|
||||||
public avatarEl = document.getElementById('im-avatar') as AvatarElement;
|
public avatarEl = document.getElementById('im-avatar') as AvatarElement;
|
||||||
@ -754,34 +754,22 @@ export class AppImManager {
|
|||||||
this.log('loadMoreHistory', top);
|
this.log('loadMoreHistory', top);
|
||||||
if(!this.peerID || testScroll || this.setPeerPromise || (top && this.getHistoryTopPromise) || (!top && this.getHistoryBottomPromise)) return;
|
if(!this.peerID || testScroll || this.setPeerPromise || (top && this.getHistoryTopPromise) || (!top && this.getHistoryBottomPromise)) return;
|
||||||
|
|
||||||
let history = Object.keys(this.bubbles).map(id => +id).sort((a, b) => a - b);
|
// warning, если иды только отрицательные то вниз не попадёт (хотя мб и так не попадёт)
|
||||||
|
let history = Object.keys(this.bubbles).map(id => +id).filter(id => id > 0).sort((a, b) => a - b);
|
||||||
if(!history.length) return;
|
if(!history.length) return;
|
||||||
|
|
||||||
/* let history = appMessagesManager.historiesStorage[this.peerID].history;
|
|
||||||
let length = history.length; */
|
|
||||||
|
|
||||||
// filter negative ids
|
|
||||||
let lastBadIndex = -1;
|
|
||||||
for(let i = 0; i < history.length; ++i) {
|
|
||||||
if(history[i] <= 0) lastBadIndex = i;
|
|
||||||
else break;
|
|
||||||
}
|
|
||||||
if(lastBadIndex != -1) {
|
|
||||||
history = history.slice(lastBadIndex + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(top && !this.scrolledAll) {
|
if(top && !this.scrolledAll) {
|
||||||
this.log('Will load more (up) history by id:', history[0], 'maxID:', history[history.length - 1], history);
|
this.log('Will load more (up) history by id:', history[0], 'maxID:', history[history.length - 1], history);
|
||||||
|
/* if(history.length == 75) {
|
||||||
|
this.log('load more', this.scrollable.scrollHeight, this.scrollable.scrollTop, this.scrollable);
|
||||||
|
return;
|
||||||
|
} */
|
||||||
/* false && */this.getHistory(history[0], true);
|
/* false && */this.getHistory(history[0], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.scrolledAllDown) return;
|
if(this.scrolledAllDown) return;
|
||||||
|
|
||||||
let dialog = appMessagesManager.getDialogByPeerID(this.peerID)[0];
|
let dialog = appMessagesManager.getDialogByPeerID(this.peerID)[0];
|
||||||
/* if(!dialog) {
|
|
||||||
this.log.warn('no dialog for load history');
|
|
||||||
return;
|
|
||||||
} */
|
|
||||||
|
|
||||||
// if scroll down after search
|
// if scroll down after search
|
||||||
if(!top && (!dialog || history.indexOf(dialog.top_message) === -1)) {
|
if(!top && (!dialog || history.indexOf(dialog.top_message) === -1)) {
|
||||||
@ -822,14 +810,14 @@ export class AppImManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public setScroll() {
|
public setScroll() {
|
||||||
this.scrollable = new Scrollable(this.bubblesContainer, 'y', 'IM', this.chatInner);
|
this.scrollable = new Scrollable(this.bubblesContainer, 'y', 'IM', this.chatInner, 300);
|
||||||
this.scroll = this.scrollable.container;
|
this.scroll = this.scrollable.container;
|
||||||
|
|
||||||
this.bubblesContainer.append(this.goDownBtn);
|
this.bubblesContainer.append(this.goDownBtn);
|
||||||
|
|
||||||
this.scrollable.onScrolledTop = () => this.loadMoreHistory(true);
|
this.scrollable.onScrolledTop = () => this.loadMoreHistory(true);
|
||||||
this.scrollable.onScrolledBottom = () => this.loadMoreHistory(false);
|
this.scrollable.onScrolledBottom = () => this.loadMoreHistory(false);
|
||||||
this.scrollable.attachSentinels(undefined, 300);
|
//this.scrollable.attachSentinels(undefined, 300);
|
||||||
|
|
||||||
this.scroll.addEventListener('scroll', this.onScroll.bind(this));
|
this.scroll.addEventListener('scroll', this.onScroll.bind(this));
|
||||||
this.scroll.parentElement.classList.add('scrolled-down');
|
this.scroll.parentElement.classList.add('scrolled-down');
|
||||||
@ -850,30 +838,7 @@ export class AppImManager {
|
|||||||
this.subtitleEl.innerText = appSidebarRight.profileElements.subtitle.innerText = '';
|
this.subtitleEl.innerText = appSidebarRight.profileElements.subtitle.innerText = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
Promise.all([
|
appProfileManager.getChatFull(chat.id).then((chatInfo: any) => {
|
||||||
appPeersManager.isMegagroup(this.peerID) ? apiManager.invokeApi('messages.getOnlines', {
|
|
||||||
peer: appPeersManager.getInputPeerByID(this.peerID)
|
|
||||||
}) as Promise<any> : Promise.resolve(),
|
|
||||||
// will redirect if wrong
|
|
||||||
appProfileManager.getChatFull(chat.id)
|
|
||||||
]).then(results => {
|
|
||||||
let [chatOnlines, chatInfo] = results;
|
|
||||||
|
|
||||||
let onlines = chatOnlines ? chatOnlines.onlines : 1;
|
|
||||||
|
|
||||||
if(chatInfo._ == 'chatFull' && chatInfo.participants && chatInfo.participants.participants) {
|
|
||||||
let participants = chatInfo.participants.participants;
|
|
||||||
|
|
||||||
onlines = participants.reduce((acc: number, participant: any) => {
|
|
||||||
let user = appUsersManager.getUser(participant.user_id);
|
|
||||||
if(user && user.status && user.status._ == 'userStatusOnline') {
|
|
||||||
return acc + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return acc;
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.log('chatInfo res:', chatInfo);
|
this.log('chatInfo res:', chatInfo);
|
||||||
|
|
||||||
if(chatInfo.pinned_msg_id) { // request pinned message
|
if(chatInfo.pinned_msg_id) { // request pinned message
|
||||||
@ -885,11 +850,16 @@ export class AppImManager {
|
|||||||
if(participants_count) {
|
if(participants_count) {
|
||||||
let subtitle = numberWithCommas(participants_count) + ' ' + (isChannel ? 'subscribers' : 'members');
|
let subtitle = numberWithCommas(participants_count) + ' ' + (isChannel ? 'subscribers' : 'members');
|
||||||
|
|
||||||
|
this.subtitleEl.innerText = appSidebarRight.profileElements.subtitle.innerText = subtitle;
|
||||||
|
|
||||||
|
if(participants_count < 2) return;
|
||||||
|
appChatsManager.getOnlines(chat.id).then(onlines => {
|
||||||
if(onlines > 1) {
|
if(onlines > 1) {
|
||||||
subtitle += ', ' + numberWithCommas(onlines) + ' online';
|
subtitle += ', ' + numberWithCommas(onlines) + ' online';
|
||||||
}
|
}
|
||||||
|
|
||||||
this.subtitleEl.innerText = appSidebarRight.profileElements.subtitle.innerText = subtitle;
|
this.subtitleEl.innerText = appSidebarRight.profileElements.subtitle.innerText = subtitle;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if(!appUsersManager.isBot(this.peerID)) { // user
|
} else if(!appUsersManager.isBot(this.peerID)) { // user
|
||||||
@ -1071,7 +1041,7 @@ export class AppImManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.scrollable.container.append(this.chatInner);
|
this.scrollable.container.append(this.chatInner);
|
||||||
this.scrollable.attachSentinels();
|
//this.scrollable.attachSentinels();
|
||||||
//this.scrollable.container.insertBefore(this.chatInner, this.scrollable.container.lastElementChild);
|
//this.scrollable.container.insertBefore(this.chatInner, this.scrollable.container.lastElementChild);
|
||||||
|
|
||||||
this.lazyLoadQueue.unlock();
|
this.lazyLoadQueue.unlock();
|
||||||
@ -1328,34 +1298,40 @@ export class AppImManager {
|
|||||||
|
|
||||||
public renderMessagesQueue(message: any, bubble: HTMLDivElement, reverse: boolean) {
|
public renderMessagesQueue(message: any, bubble: HTMLDivElement, reverse: boolean) {
|
||||||
let promises: Promise<any>[] = [];
|
let promises: Promise<any>[] = [];
|
||||||
(Array.from(bubble.querySelectorAll('img, image, video')) as HTMLImageElement[]).forEach(el => {
|
(Array.from(bubble.querySelectorAll('img, video')) as HTMLImageElement[]).forEach(el => {
|
||||||
if(el.tagName == 'VIDEO') {
|
if(el instanceof HTMLVideoElement) {
|
||||||
let source = el.firstElementChild as HTMLSourceElement;
|
let source = el.firstElementChild as HTMLSourceElement;
|
||||||
if(!source || !source.src) {
|
if(!source || !source.src) {
|
||||||
this.log.warn('no source', el, source, 'src', source.src);
|
this.log.warn('no source', el, source, 'src', source.src);
|
||||||
return;
|
return;
|
||||||
}
|
} else if(el.readyState >= 4) return;
|
||||||
} else if(el.complete || (!el.src && !el.getAttribute('href'))) return;
|
} else if(el.complete || !el.src) return;
|
||||||
|
|
||||||
let src = el.src || el.getAttributeNS(null, 'href');
|
let src = el.src;
|
||||||
|
|
||||||
let promise = new Promise((resolve, reject) => {
|
let promise = new Promise((resolve, reject) => {
|
||||||
if(el.tagName == 'VIDEO') {
|
let r: () => boolean;
|
||||||
el.addEventListener('loadeddata', () => {
|
let onLoad = () => {
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
resolve();
|
resolve();
|
||||||
});
|
};
|
||||||
|
|
||||||
|
if(el instanceof HTMLVideoElement) {
|
||||||
|
el.addEventListener('loadeddata', onLoad);
|
||||||
|
r = () => el.readyState >= 4;
|
||||||
} else {
|
} else {
|
||||||
el.addEventListener('load', () => {
|
el.addEventListener('load', onLoad);
|
||||||
clearTimeout(timeout);
|
r = () => el.complete;
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for safari
|
||||||
|
let c = () => r() ? onLoad() : window.requestAnimationFrame(c);
|
||||||
|
window.requestAnimationFrame(c);
|
||||||
|
|
||||||
let timeout = setTimeout(() => {
|
let timeout = setTimeout(() => {
|
||||||
console.log('did not called', el, el.parentElement, el.complete, src);
|
console.log('did not called', el, el.parentElement, el.complete, src);
|
||||||
reject();
|
reject();
|
||||||
}, 5000);
|
}, 1500);
|
||||||
});
|
});
|
||||||
|
|
||||||
promises.push(promise);
|
promises.push(promise);
|
||||||
@ -2092,7 +2068,7 @@ export class AppImManager {
|
|||||||
avatarElem.setAttribute('peer-title', message.fwd_from.from_name);
|
avatarElem.setAttribute('peer-title', message.fwd_from.from_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
avatarElem.setAttribute('peer', '' + ((message.fwd_from ? message.fwdFromID : message.fromID) || 0));
|
avatarElem.setAttribute('peer', '' + ((message.fwd_from && this.peerID == this.myID ? message.fwdFromID : message.fromID) || 0));
|
||||||
|
|
||||||
this.log('exec loadDialogPhoto', message);
|
this.log('exec loadDialogPhoto', message);
|
||||||
|
|
||||||
@ -2151,43 +2127,28 @@ export class AppImManager {
|
|||||||
|
|
||||||
console.time('appImManager render history');
|
console.time('appImManager render history');
|
||||||
|
|
||||||
let firstLoad = !!this.setPeerPromise && false;
|
|
||||||
|
|
||||||
let peerID = this.peerID;
|
|
||||||
return new Promise<boolean>((resolve, reject) => {
|
return new Promise<boolean>((resolve, reject) => {
|
||||||
let method = (reverse ? history.shift : history.pop).bind(history);
|
let method = (reverse ? history.shift : history.pop).bind(history);
|
||||||
|
|
||||||
let r = () => {
|
|
||||||
if(this.peerID != peerID) {
|
|
||||||
return reject('peer changed');
|
|
||||||
}
|
|
||||||
|
|
||||||
let msgID = method();
|
|
||||||
if(!msgID) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let message = appMessagesManager.getMessage(msgID);
|
|
||||||
this.renderMessage(message, reverse, true);
|
|
||||||
|
|
||||||
firstLoad ? window.requestAnimationFrame(r) : r();
|
|
||||||
};
|
|
||||||
|
|
||||||
firstLoad ? window.requestAnimationFrame(r) : r();
|
|
||||||
|
|
||||||
let realLength = this.scrollable.length;
|
let realLength = this.scrollable.length;
|
||||||
let previousScrollHeightMinusTop: number;
|
let previousScrollHeightMinusTop: number;
|
||||||
if(realLength > 0 && reverse) {
|
if(realLength > 0 && reverse) {
|
||||||
this.messagesQueueOnRender = () => {
|
this.messagesQueueOnRender = () => {
|
||||||
let scrollTop = realLength ? this.scrollable.scrollTop : 0;
|
let scrollTop = this.scrollable.scrollTop;
|
||||||
previousScrollHeightMinusTop = realLength ? this.scrollable.scrollHeight - scrollTop : 0;
|
previousScrollHeightMinusTop = this.scrollable.scrollHeight - scrollTop;
|
||||||
|
|
||||||
this.log('performHistoryResult: messagesQueueOnRender, scrollTop:', scrollTop, previousScrollHeightMinusTop);
|
this.log('performHistoryResult: messagesQueueOnRender, scrollTop:', scrollTop, previousScrollHeightMinusTop);
|
||||||
|
this.messagesQueueOnRender = undefined;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while(history.length) {
|
||||||
|
let message = appMessagesManager.getMessage(method());
|
||||||
|
this.renderMessage(message, reverse, true);
|
||||||
|
}
|
||||||
|
|
||||||
(this.messagesQueuePromise || Promise.resolve()).then(() => {
|
(this.messagesQueuePromise || Promise.resolve()).then(() => {
|
||||||
if(realLength > 0 && reverse && previousScrollHeightMinusTop !== undefined) {
|
if(previousScrollHeightMinusTop !== undefined) {
|
||||||
this.log('performHistoryResult: will set scrollTop', this.scrollable.scrollHeight, previousScrollHeightMinusTop);
|
this.log('performHistoryResult: will set scrollTop', this.scrollable.scrollHeight, previousScrollHeightMinusTop);
|
||||||
this.scrollable.scrollTop = this.scrollable.scrollHeight - previousScrollHeightMinusTop;
|
this.scrollable.scrollTop = this.scrollable.scrollHeight - previousScrollHeightMinusTop;
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,8 @@ export class AppMediaViewer {
|
|||||||
private reverse = false; // reverse means next = higher msgid
|
private reverse = false; // reverse means next = higher msgid
|
||||||
private needLoadMore = true;
|
private needLoadMore = true;
|
||||||
|
|
||||||
|
private pageEl = document.getElementById('page-chats') as HTMLDivElement;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.log = logger('AMV');
|
this.log = logger('AMV');
|
||||||
this.preloader = new ProgressivePreloader();
|
this.preloader = new ProgressivePreloader();
|
||||||
@ -568,7 +570,7 @@ export class AppMediaViewer {
|
|||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
public updateMediaSource(target: HTMLElement, url: string, tagName: 'source' | 'image') {
|
public updateMediaSource(target: HTMLElement, url: string, tagName: 'source' | 'img') {
|
||||||
//if(target instanceof SVGSVGElement) {
|
//if(target instanceof SVGSVGElement) {
|
||||||
let el = target.querySelector(tagName) as HTMLElement;
|
let el = target.querySelector(tagName) as HTMLElement;
|
||||||
renderImageFromUrl(el, url);
|
renderImageFromUrl(el, url);
|
||||||
@ -665,17 +667,20 @@ export class AppMediaViewer {
|
|||||||
|
|
||||||
////////this.log('wasActive:', wasActive);
|
////////this.log('wasActive:', wasActive);
|
||||||
|
|
||||||
|
if(useContainerAsTarget) {
|
||||||
|
target = target.querySelector('img, video') || target;
|
||||||
|
}
|
||||||
|
|
||||||
let mover = this.content.mover;
|
let mover = this.content.mover;
|
||||||
|
|
||||||
let maxWidth = appPhotosManager.windowW - 16;
|
//let maxWidth = appPhotosManager.windowW - 16;
|
||||||
|
let maxWidth = this.pageEl.scrollWidth - 16;
|
||||||
let maxHeight = appPhotosManager.windowH - 100;
|
let maxHeight = appPhotosManager.windowH - 100;
|
||||||
if(isVideo) {
|
if(isVideo) {
|
||||||
let size = appPhotosManager.setAttachmentSize(media, container, maxWidth, maxHeight);
|
appPhotosManager.setAttachmentSize(media, container, maxWidth, maxHeight);
|
||||||
|
|
||||||
////////this.log('will wrap video', media, size);
|
////////this.log('will wrap video', media, size);
|
||||||
|
|
||||||
if(useContainerAsTarget) target = target.querySelector('img, video') || target;
|
|
||||||
|
|
||||||
let afterTimeout = this.setMoverToTarget(target, false, fromRight);
|
let afterTimeout = this.setMoverToTarget(target, false, fromRight);
|
||||||
//return; // set and don't move
|
//return; // set and don't move
|
||||||
//if(wasActive) return;
|
//if(wasActive) return;
|
||||||
@ -745,8 +750,6 @@ export class AppMediaViewer {
|
|||||||
} else {
|
} else {
|
||||||
let size = appPhotosManager.setAttachmentSize(media.id, container, maxWidth, maxHeight);
|
let size = appPhotosManager.setAttachmentSize(media.id, container, maxWidth, maxHeight);
|
||||||
|
|
||||||
if(useContainerAsTarget) target = target.querySelector('img, video') || target;
|
|
||||||
|
|
||||||
let afterTimeout = this.setMoverToTarget(target, false, fromRight);
|
let afterTimeout = this.setMoverToTarget(target, false, fromRight);
|
||||||
//return; // set and don't move
|
//return; // set and don't move
|
||||||
//if(wasActive) return;
|
//if(wasActive) return;
|
||||||
@ -766,8 +769,8 @@ export class AppMediaViewer {
|
|||||||
|
|
||||||
let url = media.url;
|
let url = media.url;
|
||||||
if(target instanceof SVGSVGElement) {
|
if(target instanceof SVGSVGElement) {
|
||||||
this.updateMediaSource(target, url, 'image');
|
this.updateMediaSource(target, url, 'img');
|
||||||
this.updateMediaSource(mover, url, 'image');
|
this.updateMediaSource(mover, url, 'img');
|
||||||
} else {
|
} else {
|
||||||
let aspecter = mover.firstElementChild;
|
let aspecter = mover.firstElementChild;
|
||||||
let image = aspecter.firstElementChild as HTMLImageElement;
|
let image = aspecter.firstElementChild as HTMLImageElement;
|
||||||
|
@ -224,7 +224,7 @@ export class AppMessagesManager {
|
|||||||
}).catch(resolve);
|
}).catch(resolve);
|
||||||
});
|
});
|
||||||
|
|
||||||
//setInterval(() => this.saveState(), 10000);
|
setInterval(() => this.saveState(), 10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
public saveState() {
|
public saveState() {
|
||||||
@ -1166,7 +1166,7 @@ export class AppMessagesManager {
|
|||||||
} else {
|
} else {
|
||||||
let doc = messageMedia.document;
|
let doc = messageMedia.document;
|
||||||
appDocsManager.saveDoc(doc);
|
appDocsManager.saveDoc(doc);
|
||||||
inputMedia = appDocsManager.getInputByID(doc.id);
|
inputMedia = appDocsManager.getMediaInputByID(doc.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
inputs.push({
|
inputs.push({
|
||||||
@ -3002,7 +3002,11 @@ export class AppMessagesManager {
|
|||||||
if(messageID > maxID) {
|
if(messageID > maxID) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
message = this.messagesStorage[messageID];
|
message = this.messagesStorage[messageID];
|
||||||
|
if(!message) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if(message.pFlags.out != isOut) {
|
if(message.pFlags.out != isOut) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -177,7 +177,7 @@ export class AppPhotosManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public setAttachmentPreview(bytes: Uint8Array, element: HTMLElement | SVGSVGElement, isSticker = false, background = false) {
|
public getPreviewURLFromBytes(bytes: Uint8Array | number[], isSticker = false) {
|
||||||
let arr: Uint8Array;
|
let arr: Uint8Array;
|
||||||
if(!isSticker) {
|
if(!isSticker) {
|
||||||
arr = AppPhotosManager.jf.concat(bytes.slice(3), AppPhotosManager.Df);
|
arr = AppPhotosManager.jf.concat(bytes.slice(3), AppPhotosManager.Df);
|
||||||
@ -187,9 +187,7 @@ export class AppPhotosManager {
|
|||||||
arr = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);
|
arr = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
//console.log('setAttachmentPreview', bytes, arr, div, isSticker);
|
//console.log('getPreviewURLFromBytes', bytes, arr, div, isSticker);
|
||||||
|
|
||||||
let blob = new Blob([arr], {type: "image/jpeg"});
|
|
||||||
|
|
||||||
/* let reader = new FileReader();
|
/* let reader = new FileReader();
|
||||||
reader.onloadend = () => {
|
reader.onloadend = () => {
|
||||||
@ -197,8 +195,19 @@ export class AppPhotosManager {
|
|||||||
};
|
};
|
||||||
reader.readAsDataURL(blob); */
|
reader.readAsDataURL(blob); */
|
||||||
|
|
||||||
|
let blob = new Blob([arr], {type: "image/jpeg"});
|
||||||
|
|
||||||
|
return URL.createObjectURL(blob);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPreviewURLFromThumb(thumb: any, isSticker = false) {
|
||||||
|
return thumb.url ?? (thumb.url = this.getPreviewURLFromBytes(thumb.bytes, isSticker));
|
||||||
|
}
|
||||||
|
|
||||||
|
public setAttachmentPreview(bytes: Uint8Array | number[], element: HTMLElement | SVGForeignObjectElement, isSticker = false, background = false) {
|
||||||
|
let url = this.getPreviewURLFromBytes(bytes, isSticker);
|
||||||
|
|
||||||
if(background) {
|
if(background) {
|
||||||
let url = URL.createObjectURL(blob);
|
|
||||||
let img = new Image();
|
let img = new Image();
|
||||||
img.src = url;
|
img.src = url;
|
||||||
img.addEventListener('load', () => {
|
img.addEventListener('load', () => {
|
||||||
@ -206,30 +215,23 @@ export class AppPhotosManager {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return element;
|
return element;
|
||||||
//element.style.backgroundImage = 'url(' + url + ')';
|
|
||||||
} else {
|
} else {
|
||||||
if(element instanceof SVGSVGElement) {
|
if(element instanceof HTMLImageElement) {
|
||||||
let image = element.firstElementChild as SVGImageElement || document.createElementNS("http://www.w3.org/2000/svg", "image");
|
element.src = url;
|
||||||
image.setAttributeNS(null, 'href', URL.createObjectURL(blob));
|
|
||||||
element.append(image);
|
|
||||||
|
|
||||||
return image;
|
|
||||||
} else if(element instanceof HTMLImageElement) {
|
|
||||||
element.src = URL.createObjectURL(blob);
|
|
||||||
return element;
|
return element;
|
||||||
} else {
|
} else {
|
||||||
let img = new Image();
|
let img = new Image();
|
||||||
img.style.width = '100%';
|
/* img.style.width = '100%';
|
||||||
img.style.height = '100%';
|
img.style.height = '100%'; */
|
||||||
|
|
||||||
img.src = URL.createObjectURL(blob);
|
img.src = url;
|
||||||
element.append(img);
|
element.append(img);
|
||||||
return img;
|
return img;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public setAttachmentSize(photoID: any, element: HTMLElement | SVGSVGElement, boxWidth = 380, boxHeight = 380, isSticker = false) {
|
public setAttachmentSize(photoID: any, element: HTMLElement | SVGForeignObjectElement, boxWidth = 380, boxHeight = 380, isSticker = false) {
|
||||||
let photo: /* MTDocument | MTPhoto */any = null;
|
let photo: /* MTDocument | MTPhoto */any = null;
|
||||||
|
|
||||||
if(typeof(photoID) === 'string') {
|
if(typeof(photoID) === 'string') {
|
||||||
@ -243,7 +245,7 @@ export class AppPhotosManager {
|
|||||||
//console.log('setAttachmentSize', photo, photo.sizes[0].bytes, div);
|
//console.log('setAttachmentSize', photo, photo.sizes[0].bytes, div);
|
||||||
|
|
||||||
let sizes = photo.sizes || photo.thumbs;
|
let sizes = photo.sizes || photo.thumbs;
|
||||||
if((!photo.downloaded || (isSticker && photo.animated)) && sizes && sizes[0].bytes) {
|
if(!photo.downloaded && !isSticker && sizes && sizes[0].bytes) {
|
||||||
this.setAttachmentPreview(sizes[0].bytes, element, isSticker);
|
this.setAttachmentPreview(sizes[0].bytes, element, isSticker);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,17 +260,11 @@ export class AppPhotosManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let {w, h} = calcImageInBox(width, height, boxWidth, boxHeight);
|
let {w, h} = calcImageInBox(width, height, boxWidth, boxHeight);
|
||||||
if(element instanceof SVGSVGElement) {
|
if(element instanceof SVGForeignObjectElement) {
|
||||||
element.setAttributeNS(null, 'width', '' + w);
|
element.setAttributeNS(null, 'width', '' + w);
|
||||||
element.setAttributeNS(null, 'height', '' + h);
|
element.setAttributeNS(null, 'height', '' + h);
|
||||||
|
|
||||||
//console.log('set dimensions to svg element:', element, w, h);
|
//console.log('set dimensions to svg element:', element, w, h);
|
||||||
|
|
||||||
if(element.firstElementChild) {
|
|
||||||
let imageSvg = element.firstElementChild as SVGImageElement;
|
|
||||||
imageSvg.setAttributeNS(null, 'width', '' + w);
|
|
||||||
imageSvg.setAttributeNS(null, 'height', '' + h);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
element.style.width = w + 'px';
|
element.style.width = w + 'px';
|
||||||
element.style.height = h + 'px';
|
element.style.height = h + 'px';
|
||||||
|
@ -111,14 +111,14 @@ class AppSidebarRight {
|
|||||||
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') as HTMLUListElement;
|
this.profileTabs = this.profileContentEl.querySelector('.profile-tabs') as HTMLUListElement;
|
||||||
|
|
||||||
this.scroll = new Scrollable(this.profileContainer, 'y', 'SR');
|
this.scroll = new Scrollable(this.profileContainer, 'y', 'SR', undefined, 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');
|
||||||
this.loadSidebarMedia(true);
|
this.loadSidebarMedia(true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
this.scroll.attachSentinels(undefined, 400);
|
//this.scroll.attachSentinels(undefined, 400);
|
||||||
|
|
||||||
horizontalMenu(this.profileTabs, container, (id, tabContent) => {
|
horizontalMenu(this.profileTabs, container, (id, tabContent) => {
|
||||||
if(this.prevTabID == id) return;
|
if(this.prevTabID == id) return;
|
||||||
|
@ -52,6 +52,8 @@ class AppStickersManager {
|
|||||||
[stickerSetID: string]: MTStickerSetFull
|
[stickerSetID: string]: MTStickerSetFull
|
||||||
} = {};
|
} = {};
|
||||||
|
|
||||||
|
private saveSetsTimeout: number;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
AppStorage.get<{
|
AppStorage.get<{
|
||||||
[stickerSetID: string]: MTStickerSetFull
|
[stickerSetID: string]: MTStickerSetFull
|
||||||
@ -59,17 +61,15 @@ class AppStickersManager {
|
|||||||
if(sets) {
|
if(sets) {
|
||||||
for(let id in sets) {
|
for(let id in sets) {
|
||||||
let set = sets[id];
|
let set = sets[id];
|
||||||
set.documents.forEach(doc => {
|
this.saveStickers(set.documents);
|
||||||
this.saveSticker(doc);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.stickerSets = sets;
|
this.stickerSets = sets;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!this.stickerSets['emoji']) {
|
//if(!this.stickerSets['emoji']) {
|
||||||
this.getStickerSet({id: 'emoji', access_hash: ''});
|
this.getStickerSet({id: 'emoji', access_hash: ''});
|
||||||
}
|
//}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,6 +82,12 @@ class AppStickersManager {
|
|||||||
return doc;
|
return doc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public saveStickers(docs: MTDocument[]) {
|
||||||
|
docs.forEach((doc, idx) => {
|
||||||
|
docs[idx] = this.saveSticker(doc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public getSticker(fileID: string) {
|
public getSticker(fileID: string) {
|
||||||
return this.documents[fileID];
|
return this.documents[fileID];
|
||||||
}
|
}
|
||||||
@ -115,6 +121,20 @@ class AppStickersManager {
|
|||||||
return stickerSet;
|
return stickerSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async getRecentStickers() {
|
||||||
|
let res: {
|
||||||
|
_: string,
|
||||||
|
hash: number,
|
||||||
|
packs: any[],
|
||||||
|
stickers: MTDocument[],
|
||||||
|
dates: number[]
|
||||||
|
} = await apiManager.invokeApi('messages.getRecentStickers', {flags: 0, hash: 0});
|
||||||
|
|
||||||
|
this.saveStickers(res.stickers);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
public getAnimatedEmojiSticker(emoji: string) {
|
public getAnimatedEmojiSticker(emoji: string) {
|
||||||
let stickerSet = this.stickerSets.emoji;
|
let stickerSet = this.stickerSets.emoji;
|
||||||
|
|
||||||
@ -122,7 +142,7 @@ class AppStickersManager {
|
|||||||
return stickerSet.documents.find(doc => doc.stickerEmojiRaw == emoji);
|
return stickerSet.documents.find(doc => doc.stickerEmojiRaw == emoji);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async saveStickerSet(res: {
|
public saveStickerSet(res: {
|
||||||
_: "messages.stickerSet",
|
_: "messages.stickerSet",
|
||||||
set: MTStickerSet,
|
set: MTStickerSet,
|
||||||
packs: any[],
|
packs: any[],
|
||||||
@ -136,13 +156,19 @@ class AppStickersManager {
|
|||||||
documents: res.documents
|
documents: res.documents
|
||||||
};
|
};
|
||||||
|
|
||||||
res.documents.forEach(this.saveSticker.bind(this));
|
this.saveStickers(res.documents);
|
||||||
|
|
||||||
//console.log('stickers wrote', this.stickerSets);
|
//console.log('stickers wrote', this.stickerSets);
|
||||||
await AppStorage.set({
|
if(this.saveSetsTimeout) return;
|
||||||
|
this.saveSetsTimeout = setTimeout(() => {
|
||||||
|
AppStorage.set({
|
||||||
stickerSets: this.stickerSets
|
stickerSets: this.stickerSets
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.saveSetsTimeout = 0;
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
|
||||||
/* AppStorage.get('stickerSets').then((sets: any) => {
|
/* AppStorage.get('stickerSets').then((sets: any) => {
|
||||||
this.stickerSets = sets;
|
this.stickerSets = sets;
|
||||||
console.log('stickers got', this.stickerSets);
|
console.log('stickers got', this.stickerSets);
|
||||||
@ -153,7 +179,9 @@ class AppStickersManager {
|
|||||||
let thumb = stickerSet.thumb;
|
let thumb = stickerSet.thumb;
|
||||||
let dcID = stickerSet.thumb_dc_id;
|
let dcID = stickerSet.thumb_dc_id;
|
||||||
|
|
||||||
let promise = apiFileManager.downloadSmallFile({
|
let isAnimated = stickerSet.pFlags?.animated;
|
||||||
|
|
||||||
|
let promise = apiFileManager.downloadFile(dcID, {
|
||||||
_: 'inputStickerSetThumb',
|
_: 'inputStickerSetThumb',
|
||||||
stickerset: {
|
stickerset: {
|
||||||
_: 'inputStickerSetID',
|
_: 'inputStickerSetID',
|
||||||
@ -162,7 +190,10 @@ class AppStickersManager {
|
|||||||
},
|
},
|
||||||
volume_id: thumb.location.volume_id,
|
volume_id: thumb.location.volume_id,
|
||||||
local_id: thumb.location.local_id
|
local_id: thumb.location.local_id
|
||||||
}, {dcID: dcID});
|
}, thumb.size, {
|
||||||
|
stickerType: isAnimated ? 2 : 1,
|
||||||
|
mimeType: isAnimated ? "application/x-tgsticker" : 'image/webp'
|
||||||
|
});
|
||||||
|
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
@ -1,31 +1,21 @@
|
|||||||
// @ts-ignore
|
|
||||||
//import createWorker from 'offscreen-canvas/create-worker';
|
|
||||||
|
|
||||||
class AppWebpManager {
|
class AppWebpManager {
|
||||||
public webpMachine: any = null;
|
private webpMachine: any = null;
|
||||||
public loaded: Promise<void>;
|
private loaded: Promise<void>;
|
||||||
public busyPromise: Promise<string>;
|
private busyPromise: Promise<Uint8Array | void>;
|
||||||
public queue: {bytes: Uint8Array, img: HTMLImageElement, callback: (url: string) => void}[] = [];
|
private queue: {bytes: Uint8Array, callback: (res: Uint8Array) => void}[] = [];
|
||||||
//public worker: any;
|
|
||||||
public webpSupport: Promise<boolean> = null;
|
private testPromise: Promise<boolean> = null;
|
||||||
|
public webpSupport = false;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
//let canvas = document.createElement('canvas');
|
this.testWebpSupport();
|
||||||
//console.log('got message from worker:', canvas.toDataURL());
|
|
||||||
/* this.worker = createWorker(canvas, '/webp.bundle.js', (e: any) => {
|
|
||||||
// Messages from the worker
|
|
||||||
console.log('got message from worker:', e, canvas.toDataURL());
|
|
||||||
}); */
|
|
||||||
|
|
||||||
this.webpSupported().then(res => {
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public loadWebpHero() {
|
private loadWebpHero() {
|
||||||
if(this.loaded) return this.loaded;
|
if(this.loaded) return this.loaded;
|
||||||
|
|
||||||
this.loaded = new Promise(async(resolve, reject) => {
|
this.loaded = new Promise(async(resolve, reject) => {
|
||||||
let res = await this.webpSupported();
|
let res = await this.testWebpSupport();
|
||||||
|
|
||||||
if(!res) {
|
if(!res) {
|
||||||
(window as any).webpLoaded = () => {
|
(window as any).webpLoaded = () => {
|
||||||
@ -46,17 +36,16 @@ class AppWebpManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
convert(bytes: Uint8Array): Promise<string> {
|
private convert(bytes: Uint8Array): AppWebpManager['busyPromise'] {
|
||||||
return this.webpMachine.decode(bytes);
|
return this.webpMachine.decode(bytes);
|
||||||
//return this.worker.post({message: 'webpBytes', bytes});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async processQueue() {
|
private async processQueue() {
|
||||||
if(this.busyPromise) return;
|
if(this.busyPromise) return;
|
||||||
|
|
||||||
this.busyPromise = Promise.resolve('');
|
this.busyPromise = Promise.resolve();
|
||||||
|
|
||||||
let {img, bytes, callback} = this.queue.pop();
|
let {bytes, callback} = this.queue.pop();
|
||||||
|
|
||||||
if(!this.loaded) {
|
if(!this.loaded) {
|
||||||
this.loadWebpHero();
|
this.loadWebpHero();
|
||||||
@ -65,13 +54,11 @@ class AppWebpManager {
|
|||||||
await this.loaded;
|
await this.loaded;
|
||||||
|
|
||||||
this.busyPromise = this.convert(bytes);
|
this.busyPromise = this.convert(bytes);
|
||||||
let url = await this.busyPromise;
|
let res = await this.busyPromise;
|
||||||
let imgTemp = new Image();
|
|
||||||
imgTemp.src = url;
|
console.log('converted webp', res);
|
||||||
imgTemp.onload = () => {
|
|
||||||
img.src = imgTemp.src;
|
callback(res as Uint8Array);
|
||||||
};
|
|
||||||
callback(url);
|
|
||||||
|
|
||||||
this.busyPromise = null;
|
this.busyPromise = null;
|
||||||
|
|
||||||
@ -80,42 +67,33 @@ class AppWebpManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
webpSupported() {
|
public testWebpSupport() {
|
||||||
if(this.webpSupport) return this.webpSupport;
|
if(this.testPromise) return this.testPromise;
|
||||||
|
|
||||||
return this.webpSupport = new Promise((resolve, reject) => {
|
return this.testPromise = new Promise((resolve, reject) => {
|
||||||
var webP = new Image();
|
let webP = new Image();
|
||||||
webP.src = 'data:image/webp;base64,UklGRi4AAABXRUJQVlA4TCEAAAAvAUAAEB8wAiMw' +
|
webP.src = 'data:image/webp;base64,UklGRi4AAABXRUJQVlA4TCEAAAAvAUAAEB8wAiMw' +
|
||||||
'AgSSNtse/cXjxyCCmrYNWPwmHRH9jwMA';
|
'AgSSNtse/cXjxyCCmrYNWPwmHRH9jwMA';
|
||||||
webP.onload = webP.onerror = () => {
|
webP.onload = webP.onerror = () => {
|
||||||
resolve(webP.height === 2);
|
resolve(this.webpSupport = webP.height === 2/* && false */);
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async polyfillImage(img: HTMLImageElement, blob: Blob) {
|
public isSupported() {
|
||||||
/* console.log('polyfillImage', this);
|
return this.webpSupport;
|
||||||
return this.webpMachine.polyfillImage(image); */
|
|
||||||
|
|
||||||
//if(await this.webpMachine.webpSupport) {
|
|
||||||
if(await this.webpSupport) {
|
|
||||||
let url = URL.createObjectURL(blob);
|
|
||||||
img.src = url;
|
|
||||||
return url;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Promise<string>((resolve, reject) => {
|
public convertToPng(bytes: Uint8Array) {
|
||||||
const reader = new FileReader();
|
console.warn('convertToPng!');
|
||||||
reader.addEventListener('loadend', (e) => {
|
return new Promise<Uint8Array>((resolve, reject) => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
let bytes = new Uint8Array(e.srcElement.result);
|
this.queue.push({bytes, callback: resolve});
|
||||||
|
|
||||||
this.queue.push({bytes, img, callback: resolve});
|
|
||||||
this.processQueue();
|
this.processQueue();
|
||||||
});
|
});
|
||||||
reader.readAsArrayBuffer(blob);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new AppWebpManager();
|
const appWebpManager = new AppWebpManager();
|
||||||
|
(window as any).appWebpManager = appWebpManager;
|
||||||
|
export default appWebpManager;
|
||||||
|
@ -342,24 +342,6 @@ export function longFromInts(high: number, low: number) {
|
|||||||
return bigint(high).shiftLeft(32).add(bigint(low)).toString(10);
|
return bigint(high).shiftLeft(32).add(bigint(low)).toString(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function intToUint(val: number | string) {
|
|
||||||
if(typeof(val) === 'string') val = parseInt(val);
|
|
||||||
|
|
||||||
/* if(val < 0) {
|
|
||||||
val = val + 4294967296;
|
|
||||||
} */
|
|
||||||
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function uintToInt(val: number) {
|
|
||||||
/* if(val > 2147483647) {
|
|
||||||
val = val - 4294967296;
|
|
||||||
} */
|
|
||||||
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function addPadding(bytes: any, blockSize: number = 16, zeroes?: boolean, full = false, prepend = false) {
|
export function addPadding(bytes: any, blockSize: number = 16, zeroes?: boolean, full = false, prepend = false) {
|
||||||
let len = bytes.byteLength || bytes.length;
|
let len = bytes.byteLength || bytes.length;
|
||||||
let needPadding = blockSize - (len % blockSize);
|
let needPadding = blockSize - (len % blockSize);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {blobSafeMimeType, blobConstruct, bytesToBase64} from './bin_utils';
|
import {blobConstruct} from './bin_utils';
|
||||||
|
|
||||||
/* import 'web-streams-polyfill/ponyfill';
|
/* import 'web-streams-polyfill/ponyfill';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -140,14 +140,6 @@ class FileManager {
|
|||||||
return fakeFileWriter;
|
return fakeFileWriter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getFileCorrectUrl(fileData: Blob | number[], mimeType: string): string {
|
|
||||||
var safeMimeType = blobSafeMimeType(mimeType);
|
|
||||||
if(fileData instanceof Blob) {
|
|
||||||
return URL.createObjectURL(fileData);
|
|
||||||
}
|
|
||||||
return 'data:' + safeMimeType + ';base64,' + bytesToBase64(fileData);
|
|
||||||
}
|
|
||||||
|
|
||||||
public download(blob: Blob, mimeType: string, fileName: string) {
|
public download(blob: Blob, mimeType: string, fileName: string) {
|
||||||
if(window.navigator && navigator.msSaveBlob !== undefined) {
|
if(window.navigator && navigator.msSaveBlob !== undefined) {
|
||||||
window.navigator.msSaveBlob(blob, fileName);
|
window.navigator.msSaveBlob(blob, fileName);
|
||||||
@ -180,7 +172,7 @@ class FileManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let url = this.getFileCorrectUrl(blob, mimeType);
|
let url = URL.createObjectURL(blob);
|
||||||
var anchor = document.createElementNS('http://www.w3.org/1999/xhtml', 'a') as HTMLAnchorElement;
|
var anchor = document.createElementNS('http://www.w3.org/1999/xhtml', 'a') as HTMLAnchorElement;
|
||||||
anchor.href = url as string;
|
anchor.href = url as string;
|
||||||
anchor.download = fileName;
|
anchor.download = fileName;
|
||||||
|
@ -52,6 +52,8 @@ class IdbFileStorage {
|
|||||||
finished = true;
|
finished = true;
|
||||||
var db = request.result;
|
var db = request.result;
|
||||||
|
|
||||||
|
console.log('Opened IndexedDB');
|
||||||
|
|
||||||
db.onerror = (error) => {
|
db.onerror = (error) => {
|
||||||
this.storageIsAvailable = false;
|
this.storageIsAvailable = false;
|
||||||
console.error('Error creating/accessing IndexedDB database', error);
|
console.error('Error creating/accessing IndexedDB database', error);
|
||||||
|
@ -96,7 +96,7 @@ class LottieLoader {
|
|||||||
params.renderer = 'svg';
|
params.renderer = 'svg';
|
||||||
//}
|
//}
|
||||||
|
|
||||||
params.rendererSettings = {
|
let rendererSettings = {
|
||||||
//context: context, // the canvas context
|
//context: context, // the canvas context
|
||||||
//preserveAspectRatio: 'xMinYMin slice', // Supports the same options as the svg element's preserveAspectRatio property
|
//preserveAspectRatio: 'xMinYMin slice', // Supports the same options as the svg element's preserveAspectRatio property
|
||||||
clearCanvas: true,
|
clearCanvas: true,
|
||||||
@ -104,6 +104,12 @@ class LottieLoader {
|
|||||||
hideOnTransparent: true, //Boolean, only svg renderer, hides elements when opacity reaches 0 (defaults to true),
|
hideOnTransparent: true, //Boolean, only svg renderer, hides elements when opacity reaches 0 (defaults to true),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if(params.rendererSettings) {
|
||||||
|
params.rendererSettings = Object.assign(params.rendererSettings, rendererSettings);
|
||||||
|
} else {
|
||||||
|
params.rendererSettings = rendererSettings;
|
||||||
|
}
|
||||||
|
|
||||||
if(!this.lottie) {
|
if(!this.lottie) {
|
||||||
if(!this.loaded) this.loadLottie();
|
if(!this.loaded) this.loadLottie();
|
||||||
await this.loaded;
|
await this.loaded;
|
||||||
|
@ -5,6 +5,7 @@ import FileManager from "../filemanager";
|
|||||||
//import apiManager from "./apiManager";
|
//import apiManager from "./apiManager";
|
||||||
import apiManager from "./mtprotoworker";
|
import apiManager from "./mtprotoworker";
|
||||||
import { logger, deferredPromise, CancellablePromise } from "../polyfill";
|
import { logger, deferredPromise, CancellablePromise } from "../polyfill";
|
||||||
|
import appWebpManager from "../appManagers/appWebpManager";
|
||||||
|
|
||||||
export class ApiFileManager {
|
export class ApiFileManager {
|
||||||
public cachedSavePromises: {
|
public cachedSavePromises: {
|
||||||
@ -14,7 +15,7 @@ export class ApiFileManager {
|
|||||||
[fileName: string]: any
|
[fileName: string]: any
|
||||||
} = {};
|
} = {};
|
||||||
public cachedDownloads: {
|
public cachedDownloads: {
|
||||||
[fileName: string]: any
|
[fileName: string]: Blob
|
||||||
} = {};
|
} = {};
|
||||||
|
|
||||||
/* public indexedKeys: Set<string> = new Set();
|
/* public indexedKeys: Set<string> = new Set();
|
||||||
@ -84,20 +85,32 @@ export class ApiFileManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public getFileName(location: any) {
|
public getFileName(location: any, options?: Partial<{
|
||||||
|
stickerType: number
|
||||||
|
}>) {
|
||||||
switch(location._) {
|
switch(location._) {
|
||||||
case 'inputDocumentFileLocation':
|
case 'inputDocumentFileLocation': {
|
||||||
var fileName = (location.file_name as string || '').split('.');
|
let fileName = (location.file_name as string || '').split('.');
|
||||||
var ext: string = fileName[fileName.length - 1] || '';
|
let ext = fileName[fileName.length - 1] || '';
|
||||||
|
|
||||||
var versionPart = location.version ? ('v' + location.version) : '';
|
if(options?.stickerType == 1 && !appWebpManager.isSupported()) {
|
||||||
return (fileName[0] ? fileName[0] + '_' : '') + location.id + versionPart + (ext ? '.' + ext : ext);
|
ext += '.png'
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
let thumbPart = location.thumb_size ? '_' + location.thumb_size : '';
|
||||||
|
return (fileName[0] ? fileName[0] + '_' : '') + location.id + thumbPart + (ext ? '.' + ext : ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
if(!location.volume_id && !location.file_reference) {
|
if(!location.volume_id && !location.file_reference) {
|
||||||
this.log.trace('Empty location', location);
|
this.log.trace('Empty location', location);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let ext = 'jpg';
|
||||||
|
if(options?.stickerType == 1 && !appWebpManager.isSupported()) {
|
||||||
|
ext += '.png'
|
||||||
|
}
|
||||||
|
|
||||||
if(location.volume_id) {
|
if(location.volume_id) {
|
||||||
return location.volume_id + '_' + location.local_id + '.' + ext;
|
return location.volume_id + '_' + location.local_id + '.' + ext;
|
||||||
} else {
|
} else {
|
||||||
@ -105,6 +118,7 @@ export class ApiFileManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public getTempFileName(file: any) {
|
public getTempFileName(file: any) {
|
||||||
var size = file.size || -1;
|
var size = file.size || -1;
|
||||||
@ -145,10 +159,11 @@ export class ApiFileManager {
|
|||||||
return this.cachedSavePromises[fileName];
|
return this.cachedSavePromises[fileName];
|
||||||
}
|
}
|
||||||
|
|
||||||
public downloadSmallFile(location: any, options: {
|
public downloadSmallFile(location: any, options: Partial<{
|
||||||
mimeType?: string,
|
mimeType: string,
|
||||||
dcID?: number,
|
dcID: number,
|
||||||
} = {}): Promise<Blob> {
|
stickerType: number
|
||||||
|
}> = {}): Promise<Blob> {
|
||||||
if(!FileManager.isAvailable()) {
|
if(!FileManager.isAvailable()) {
|
||||||
return Promise.reject({type: 'BROWSER_BLOB_NOT_SUPPORTED'});
|
return Promise.reject({type: 'BROWSER_BLOB_NOT_SUPPORTED'});
|
||||||
}
|
}
|
||||||
@ -159,10 +174,16 @@ export class ApiFileManager {
|
|||||||
|
|
||||||
//this.log('downloadSmallFile', location, options);
|
//this.log('downloadSmallFile', location, options);
|
||||||
|
|
||||||
|
let processSticker = false;
|
||||||
|
if(options.stickerType == 1 && !appWebpManager.isSupported()) {
|
||||||
|
processSticker = true;
|
||||||
|
options.mimeType = 'image/png';
|
||||||
|
}
|
||||||
|
|
||||||
let dcID = options.dcID || location.dc_id;
|
let dcID = options.dcID || location.dc_id;
|
||||||
let mimeType = options.mimeType || 'image/jpeg';
|
let mimeType = options.mimeType || 'image/jpeg';
|
||||||
var fileName = this.getFileName(location);
|
let fileName = this.getFileName(location, options);
|
||||||
var cachedPromise = this.cachedSavePromises[fileName] || this.cachedDownloadPromises[fileName];
|
let cachedPromise = this.cachedSavePromises[fileName] || this.cachedDownloadPromises[fileName];
|
||||||
|
|
||||||
//this.log('downloadSmallFile!', location, options, fileName, cachedPromise);
|
//this.log('downloadSmallFile!', location, options, fileName, cachedPromise);
|
||||||
|
|
||||||
@ -170,13 +191,14 @@ export class ApiFileManager {
|
|||||||
return cachedPromise;
|
return cachedPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileStorage = this.getFileStorage();
|
let fileStorage = this.getFileStorage();
|
||||||
|
|
||||||
return this.cachedDownloadPromises[fileName] = fileStorage.getFile(fileName).then((blob: any) => {
|
return this.cachedDownloadPromises[fileName] = fileStorage.getFile(fileName).then((blob) => {
|
||||||
|
//throw '';
|
||||||
return this.cachedDownloads[fileName] = blob;
|
return this.cachedDownloads[fileName] = blob;
|
||||||
}, () => {
|
}).catch(() => {
|
||||||
var downloadPromise = this.downloadRequest(dcID, () => {
|
let downloadPromise = this.downloadRequest(dcID, () => {
|
||||||
var inputLocation = location;
|
let inputLocation = location;
|
||||||
if(!inputLocation._ || inputLocation._ == 'fileLocation') {
|
if(!inputLocation._ || inputLocation._ == 'fileLocation') {
|
||||||
inputLocation = Object.assign({}, location, {_: 'inputFileLocation'});
|
inputLocation = Object.assign({}, location, {_: 'inputFileLocation'});
|
||||||
}
|
}
|
||||||
@ -196,18 +218,17 @@ export class ApiFileManager {
|
|||||||
});
|
});
|
||||||
}, dcID);
|
}, dcID);
|
||||||
|
|
||||||
var processDownloaded = (bytes: Uint8Array) => {
|
let processDownloaded = (bytes: Uint8Array) => {
|
||||||
//this.log('processDownloaded', location, bytes);
|
//this.log('processDownloaded', location, bytes);
|
||||||
|
|
||||||
return Promise.resolve(bytes);
|
if(processSticker) {
|
||||||
/* if(!location.sticker || WebpManager.isWebpSupported()) {
|
return appWebpManager.convertToPng(bytes);
|
||||||
return qSync.when(bytes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return WebpManager.getPngBlobFromWebp(bytes); */
|
return Promise.resolve(bytes);
|
||||||
};
|
};
|
||||||
|
|
||||||
return fileStorage.getFileWriter(fileName, mimeType).then((fileWriter: any) => {
|
return fileStorage.getFileWriter(fileName, mimeType).then(fileWriter => {
|
||||||
return downloadPromise.then((result: any) => {
|
return downloadPromise.then((result: any) => {
|
||||||
return processDownloaded(result.bytes).then((proccessedResult) => {
|
return processDownloaded(result.bytes).then((proccessedResult) => {
|
||||||
return FileManager.write(fileWriter, proccessedResult).then(() => {
|
return FileManager.write(fileWriter, proccessedResult).then(() => {
|
||||||
@ -236,12 +257,12 @@ export class ApiFileManager {
|
|||||||
});
|
});
|
||||||
} */
|
} */
|
||||||
|
|
||||||
public downloadFile(dcID: number, location: any, size: number, options: {
|
public downloadFile(dcID: number, location: any, size: number, options: Partial<{
|
||||||
mimeType?: string,
|
mimeType: string,
|
||||||
dcID?: number,
|
toFileEntry: any,
|
||||||
toFileEntry?: any,
|
limitPart: number,
|
||||||
limitPart?: number
|
stickerType: number
|
||||||
} = {}): CancellablePromise<Blob> {
|
}> = {}): CancellablePromise<Blob> {
|
||||||
if(!FileManager.isAvailable()) {
|
if(!FileManager.isAvailable()) {
|
||||||
return Promise.reject({type: 'BROWSER_BLOB_NOT_SUPPORTED'});
|
return Promise.reject({type: 'BROWSER_BLOB_NOT_SUPPORTED'});
|
||||||
}
|
}
|
||||||
@ -250,11 +271,21 @@ export class ApiFileManager {
|
|||||||
this.getIndexedKeys();
|
this.getIndexedKeys();
|
||||||
} */
|
} */
|
||||||
|
|
||||||
|
let processSticker = false;
|
||||||
|
if(options.stickerType == 1 && !appWebpManager.isSupported()) {
|
||||||
|
if(options.toFileEntry || size > 524288) {
|
||||||
|
delete options.stickerType;
|
||||||
|
} else {
|
||||||
|
processSticker = true;
|
||||||
|
options.mimeType = 'image/png';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// this.log('Dload file', dcID, location, size)
|
// this.log('Dload file', dcID, location, size)
|
||||||
var fileName = this.getFileName(location);
|
let fileName = this.getFileName(location, options);
|
||||||
var toFileEntry = options.toFileEntry || null;
|
let toFileEntry = options.toFileEntry || null;
|
||||||
var cachedPromise = this.cachedSavePromises[fileName] || this.cachedDownloadPromises[fileName];
|
let cachedPromise = this.cachedSavePromises[fileName] || this.cachedDownloadPromises[fileName];
|
||||||
var fileStorage = this.getFileStorage();
|
let fileStorage = this.getFileStorage();
|
||||||
|
|
||||||
//this.log('downloadFile', fileStorage.name, fileName, fileName.length, location, arguments);
|
//this.log('downloadFile', fileStorage.name, fileName, fileName.length, location, arguments);
|
||||||
|
|
||||||
@ -272,7 +303,7 @@ export class ApiFileManager {
|
|||||||
if(blob.size < size) {
|
if(blob.size < size) {
|
||||||
this.log('downloadFile need to deleteFile, wrong size:', blob.size, size);
|
this.log('downloadFile need to deleteFile, wrong size:', blob.size, size);
|
||||||
|
|
||||||
return this.deleteFile(location).then(() => {
|
return this.deleteFile(fileName).then(() => {
|
||||||
return this.downloadFile(dcID, location, size, options);
|
return this.downloadFile(dcID, location, size, options);
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
return this.downloadFile(dcID, location, size, options);
|
return this.downloadFile(dcID, location, size, options);
|
||||||
@ -303,10 +334,11 @@ export class ApiFileManager {
|
|||||||
|
|
||||||
fileStorage.getFile(fileName, size).then(async(blob: Blob) => {
|
fileStorage.getFile(fileName, size).then(async(blob: Blob) => {
|
||||||
//this.log('is that i wanted');
|
//this.log('is that i wanted');
|
||||||
|
//throw '';
|
||||||
|
|
||||||
if(blob.size < size) {
|
if(blob.size < size) {
|
||||||
this.log('downloadFile need to deleteFile 2, wrong size:', blob.size, size);
|
this.log('downloadFile need to deleteFile 2, wrong size:', blob.size, size);
|
||||||
await this.deleteFile(location);
|
await this.deleteFile(fileName);
|
||||||
throw false;
|
throw false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,13 +354,12 @@ export class ApiFileManager {
|
|||||||
//var fileWriterPromise = toFileEntry ? FileManager.getFileWriter(toFileEntry) : fileStorage.getFileWriter(fileName, mimeType);
|
//var fileWriterPromise = toFileEntry ? FileManager.getFileWriter(toFileEntry) : fileStorage.getFileWriter(fileName, mimeType);
|
||||||
var fileWriterPromise = toFileEntry ? Promise.resolve(toFileEntry) : fileStorage.getFileWriter(fileName, mimeType);
|
var fileWriterPromise = toFileEntry ? Promise.resolve(toFileEntry) : fileStorage.getFileWriter(fileName, mimeType);
|
||||||
|
|
||||||
var processDownloaded = (bytes: any) => {
|
var processDownloaded = (bytes: Uint8Array) => {
|
||||||
return Promise.resolve(bytes);
|
if(processSticker) {
|
||||||
/* if(!processSticker) {
|
return appWebpManager.convertToPng(bytes);
|
||||||
return Promise.resolve(bytes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return WebpManager.getPngBlobFromWebp(bytes); */
|
return Promise.resolve(bytes);
|
||||||
};
|
};
|
||||||
|
|
||||||
fileWriterPromise.then((fileWriter: any) => {
|
fileWriterPromise.then((fileWriter: any) => {
|
||||||
@ -391,7 +422,7 @@ export class ApiFileManager {
|
|||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
return processDownloaded(result.bytes).then((processedResult: Uint8Array) => {
|
return processDownloaded(result.bytes).then((processedResult) => {
|
||||||
return FileManager.write(fileWriter, processedResult).then(() => {
|
return FileManager.write(fileWriter, processedResult).then(() => {
|
||||||
writeFileDeferred.resolve();
|
writeFileDeferred.resolve();
|
||||||
}, errorHandler).then(() => {
|
}, errorHandler).then(() => {
|
||||||
@ -438,12 +469,13 @@ export class ApiFileManager {
|
|||||||
return deferred;
|
return deferred;
|
||||||
}
|
}
|
||||||
|
|
||||||
public deleteFile(fileName: any) {
|
public deleteFile(fileName: string) {
|
||||||
fileName = typeof(fileName) == 'string' ? fileName : this.getFileName(fileName);
|
|
||||||
this.log('will delete file:', fileName);
|
this.log('will delete file:', fileName);
|
||||||
|
|
||||||
delete this.cachedDownloadPromises[fileName];
|
delete this.cachedDownloadPromises[fileName];
|
||||||
delete this.cachedDownloads[fileName];
|
delete this.cachedDownloads[fileName];
|
||||||
delete this.cachedSavePromises[fileName];
|
delete this.cachedSavePromises[fileName];
|
||||||
|
|
||||||
return this.getFileStorage().deleteFile(fileName);
|
return this.getFileStorage().deleteFile(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import {isObject} from '../bin_utils';
|
import {isObject} from '../bin_utils';
|
||||||
import {convertToUint8Array,
|
import {convertToUint8Array,
|
||||||
bufferConcat, nextRandomInt, bytesToHex, longToBytes,
|
bufferConcat, nextRandomInt, bytesToHex, longToBytes,
|
||||||
bytesCmp, uintToInt, bigStringInt} from '../bin_utils';
|
bytesCmp, bigStringInt} from '../bin_utils';
|
||||||
import {TLDeserialization, TLSerialization} from './tl_utils';
|
import {TLDeserialization, TLSerialization} from './tl_utils';
|
||||||
import CryptoWorker from '../crypto/cryptoworker';
|
import CryptoWorker from '../crypto/cryptoworker';
|
||||||
import AppStorage from '../storage';
|
import AppStorage from '../storage';
|
||||||
@ -296,8 +296,7 @@ class MTPNetworker {
|
|||||||
var isClean = this.cleanupSent();
|
var isClean = this.cleanupSent();
|
||||||
//this.log('Check lp', this.longPollPending, tsNow(), this.dcID, isClean, this);
|
//this.log('Check lp', this.longPollPending, tsNow(), this.dcID, isClean, this);
|
||||||
if((this.longPollPending && Date.now() < this.longPollPending) ||
|
if((this.longPollPending && Date.now() < this.longPollPending) ||
|
||||||
this.offline ||
|
this.offline) {
|
||||||
NetworkerFactory.akStopped) {
|
|
||||||
//this.log('No lp this time');
|
//this.log('No lp this time');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -502,7 +501,7 @@ class MTPNetworker {
|
|||||||
|
|
||||||
public performScheduledRequest() {
|
public performScheduledRequest() {
|
||||||
// this.log('scheduled', this.dcID, this.iii)
|
// this.log('scheduled', this.dcID, this.iii)
|
||||||
if(this.offline || NetworkerFactory.akStopped) {
|
if(this.offline) {
|
||||||
this.log('Cancel scheduled');
|
this.log('Cancel scheduled');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1027,7 +1026,7 @@ class MTPNetworker {
|
|||||||
|
|
||||||
public processError(rawError: {error_message: string, error_code: number}) {
|
public processError(rawError: {error_message: string, error_code: number}) {
|
||||||
var matches = (rawError.error_message || '').match(/^([A-Z_0-9]+\b)(: (.+))?/) || [];
|
var matches = (rawError.error_message || '').match(/^([A-Z_0-9]+\b)(: (.+))?/) || [];
|
||||||
rawError.error_code = uintToInt(rawError.error_code);
|
rawError.error_code = rawError.error_code;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
code: !rawError.error_code || rawError.error_code <= 0 ? 500 : rawError.error_code,
|
code: !rawError.error_code || rawError.error_code <= 0 ? 500 : rawError.error_code,
|
||||||
|
@ -2,24 +2,6 @@ import { MTPNetworker } from "./networker";
|
|||||||
|
|
||||||
export class NetworkerFactory {
|
export class NetworkerFactory {
|
||||||
public updatesProcessor: (obj: any, bool: boolean) => void = null;
|
public updatesProcessor: (obj: any, bool: boolean) => void = null;
|
||||||
//public offlineInited = false;
|
|
||||||
public akStopped = false;
|
|
||||||
|
|
||||||
/* public startAll() {
|
|
||||||
if(this.akStopped) {
|
|
||||||
this.akStopped = false;
|
|
||||||
|
|
||||||
if(this.updatesProcessor) {
|
|
||||||
this.updatesProcessor({
|
|
||||||
_: 'new_session_created'
|
|
||||||
}, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public stopAll() {
|
|
||||||
this.akStopped = true;
|
|
||||||
} */
|
|
||||||
|
|
||||||
public setUpdatesProcessor(callback: (obj: any, bool: boolean) => void) {
|
public setUpdatesProcessor(callback: (obj: any, bool: boolean) => void) {
|
||||||
this.updatesProcessor = callback;
|
this.updatesProcessor = callback;
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* https://github.com/zhukov/webogram/blob/master/LICENSE
|
* https://github.com/zhukov/webogram/blob/master/LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {bigint, intToUint, bigStringInt, bytesToHex, uintToInt, isObject} from '../bin_utils';
|
import {bigint, bigStringInt, bytesToHex, isObject} from '../bin_utils';
|
||||||
import Schema from './schema';
|
import Schema from './schema';
|
||||||
|
|
||||||
/// #if MTPROTO_WORKER
|
/// #if MTPROTO_WORKER
|
||||||
@ -131,8 +131,8 @@ class TLSerialization {
|
|||||||
}
|
}
|
||||||
var divRem = bigStringInt(sLong).divideAndRemainder(bigint(0x100000000));
|
var divRem = bigStringInt(sLong).divideAndRemainder(bigint(0x100000000));
|
||||||
|
|
||||||
this.writeInt(intToUint(divRem[1].intValue()), (field || '') + ':long[low]');
|
this.writeInt(divRem[1].intValue(), (field || '') + ':long[low]');
|
||||||
this.writeInt(intToUint(divRem[0].intValue()), (field || '') + ':long[high]');
|
this.writeInt(divRem[0].intValue(), (field || '') + ':long[high]');
|
||||||
}
|
}
|
||||||
|
|
||||||
public storeDouble(f: any, field?: string) {
|
public storeDouble(f: any, field?: string) {
|
||||||
@ -250,7 +250,7 @@ class TLSerialization {
|
|||||||
throw new Error('No method ' + methodName + ' found');
|
throw new Error('No method ' + methodName + ' found');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.storeInt(intToUint(methodData.id), methodName + '[id]');
|
this.storeInt(methodData.id, methodName + '[id]');
|
||||||
|
|
||||||
var param, type;
|
var param, type;
|
||||||
var i, condType;
|
var i, condType;
|
||||||
@ -347,7 +347,7 @@ class TLSerialization {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!isBare) {
|
if(!isBare) {
|
||||||
this.writeInt(intToUint(constructorData.id), field + '[' + predicate + '][id]');
|
this.writeInt(constructorData.id, field + '[' + predicate + '][id]');
|
||||||
}
|
}
|
||||||
|
|
||||||
var param, type: string;
|
var param, type: string;
|
||||||
@ -601,7 +601,7 @@ class TLDeserialization {
|
|||||||
if(type.substr(0, 6) == 'Vector' || type.substr(0, 6) == 'vector') {
|
if(type.substr(0, 6) == 'Vector' || type.substr(0, 6) == 'vector') {
|
||||||
if(type.charAt(0) == 'V') {
|
if(type.charAt(0) == 'V') {
|
||||||
var constructor = this.readInt(field + '[id]');
|
var constructor = this.readInt(field + '[id]');
|
||||||
var constructorCmp = uintToInt(constructor);
|
var constructorCmp = constructor;
|
||||||
|
|
||||||
if(constructorCmp == gzipPacked) { // Gzip packed
|
if(constructorCmp == gzipPacked) { // Gzip packed
|
||||||
var compressed = this.fetchBytes(field + '[packed_string]');
|
var compressed = this.fetchBytes(field + '[packed_string]');
|
||||||
@ -657,7 +657,7 @@ class TLDeserialization {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var constructor = this.readInt(field + '[id]');
|
var constructor = this.readInt(field + '[id]');
|
||||||
var constructorCmp = uintToInt(constructor);
|
var constructorCmp = constructor;
|
||||||
|
|
||||||
if(constructorCmp == gzipPacked) { // Gzip packed
|
if(constructorCmp == gzipPacked) { // Gzip packed
|
||||||
var compressed = this.fetchBytes(field + '[packed_string]');
|
var compressed = this.fetchBytes(field + '[packed_string]');
|
||||||
|
@ -289,8 +289,10 @@ export function getSelectedText() {
|
|||||||
|
|
||||||
export const $rootScope = {
|
export const $rootScope = {
|
||||||
$broadcast: (name/* : string */, detail/*? : any */) => {
|
$broadcast: (name/* : string */, detail/*? : any */) => {
|
||||||
|
if(name != 'user_update') {
|
||||||
console.log(dT(), 'Broadcasting ' + name + ' event, with args:', detail);
|
console.log(dT(), 'Broadcasting ' + name + ' event, with args:', detail);
|
||||||
//console.trace();
|
}
|
||||||
|
|
||||||
let myCustomEvent = new CustomEvent(name, {detail});
|
let myCustomEvent = new CustomEvent(name, {detail});
|
||||||
document.dispatchEvent(myCustomEvent);
|
document.dispatchEvent(myCustomEvent);
|
||||||
},
|
},
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import {Webp} from "webp-hero/libwebp/dist/webp.js"
|
import {Webp} from "webp-hero/libwebp/dist/webp.js"
|
||||||
import {detectWebpSupport} from "webp-hero/dist/detect-webp-support.js"
|
|
||||||
|
|
||||||
const relax = () => new Promise(resolve => requestAnimationFrame(resolve))
|
const relax = () => new Promise(resolve => requestAnimationFrame(resolve));
|
||||||
|
|
||||||
export class WebpMachineError extends Error {}
|
export class WebpMachineError extends Error {}
|
||||||
|
|
||||||
@ -11,34 +10,39 @@ export class WebpMachineError extends Error {}
|
|||||||
* - can only decode images one-at-a-time (otherwise will throw busy error)
|
* - can only decode images one-at-a-time (otherwise will throw busy error)
|
||||||
*/
|
*/
|
||||||
export class WebpMachine {
|
export class WebpMachine {
|
||||||
private readonly webp: Webp
|
private readonly webp: Webp;
|
||||||
private readonly webpSupport: Promise<boolean>
|
private busy = false;
|
||||||
private busy = false
|
|
||||||
private cache: {[key: string]: string} = {}
|
|
||||||
|
|
||||||
constructor({
|
constructor() {
|
||||||
webp = new Webp(),
|
this.webp = new Webp();
|
||||||
webpSupport = detectWebpSupport()
|
|
||||||
} = {}) {
|
|
||||||
this.webp = webp;
|
|
||||||
this.webp.Module.doNotCaptureKeyboard = true;
|
this.webp.Module.doNotCaptureKeyboard = true;
|
||||||
this.webpSupport = webpSupport;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decode raw webp data into a png data url
|
* Decode raw webp data into a png data url
|
||||||
*/
|
*/
|
||||||
async decode(webpData: Uint8Array): Promise<string> {
|
decode(webpData: Uint8Array): Promise<Uint8Array> {
|
||||||
if(this.busy) throw new WebpMachineError("cannot decode when already busy");
|
if(this.busy) throw new WebpMachineError("cannot decode when already busy");
|
||||||
this.busy = true;
|
this.busy = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await relax();
|
return relax().then(() => {
|
||||||
const canvas = document.createElement("canvas");
|
const canvas = document.createElement("canvas");
|
||||||
this.webp.setCanvas(canvas);
|
this.webp.setCanvas(canvas);
|
||||||
this.webp.webpToSdl(webpData, webpData.length);
|
this.webp.webpToSdl(webpData, webpData.length);
|
||||||
this.busy = false;
|
this.busy = false;
|
||||||
return canvas.toDataURL();
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
canvas.toBlob(blob => {
|
||||||
|
let reader = new FileReader();
|
||||||
|
reader.onload = (event) => {
|
||||||
|
resolve(new Uint8Array(event.target.result as ArrayBuffer));
|
||||||
|
};
|
||||||
|
reader.onerror = reject;
|
||||||
|
reader.readAsArrayBuffer(blob);
|
||||||
|
}, 'image/png', 1);
|
||||||
|
});
|
||||||
|
});
|
||||||
} catch(error) {
|
} catch(error) {
|
||||||
this.busy = false;
|
this.busy = false;
|
||||||
error.name = WebpMachineError.name;
|
error.name = WebpMachineError.name;
|
||||||
|
@ -28,7 +28,12 @@ let sentTypeElement: HTMLParagraphElement = null;
|
|||||||
|
|
||||||
let onFirstMount = (): Promise<any> => {
|
let onFirstMount = (): Promise<any> => {
|
||||||
let needFrame = 0, lastLength = 0;
|
let needFrame = 0, lastLength = 0;
|
||||||
let animation: /* AnimationItem */any = undefined;
|
|
||||||
|
let animation: /* AnimationItem */any;
|
||||||
|
let idleAnimation: any;
|
||||||
|
|
||||||
|
let mTrackingSvg: SVGSVGElement;
|
||||||
|
let mIdleSvg: SVGSVGElement;
|
||||||
|
|
||||||
const CODELENGTH = authCode.type.length;
|
const CODELENGTH = authCode.type.length;
|
||||||
|
|
||||||
@ -113,6 +118,13 @@ let onFirstMount = (): Promise<any> => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let cleanup = () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
if(animation) animation.destroy();
|
||||||
|
if(idleAnimation) idleAnimation.destroy();
|
||||||
|
}, 300);
|
||||||
|
};
|
||||||
|
|
||||||
let submitCode = (code: string) => {
|
let submitCode = (code: string) => {
|
||||||
codeInput.setAttribute('disabled', 'true');
|
codeInput.setAttribute('disabled', 'true');
|
||||||
|
|
||||||
@ -135,7 +147,7 @@ let onFirstMount = (): Promise<any> => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
pageIm.mount();
|
pageIm.mount();
|
||||||
if(animation) animation.destroy();
|
cleanup();
|
||||||
break;
|
break;
|
||||||
case 'auth.authorizationSignUpRequired':
|
case 'auth.authorizationSignUpRequired':
|
||||||
console.log('Registration needed!');
|
console.log('Registration needed!');
|
||||||
@ -145,7 +157,7 @@ let onFirstMount = (): Promise<any> => {
|
|||||||
'phone_code_hash': authCode.phone_code_hash
|
'phone_code_hash': authCode.phone_code_hash
|
||||||
});
|
});
|
||||||
|
|
||||||
if(animation) animation.destroy();
|
cleanup();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
codeInput.innerText = response._;
|
codeInput.innerText = response._;
|
||||||
@ -158,7 +170,7 @@ let onFirstMount = (): Promise<any> => {
|
|||||||
case 'SESSION_PASSWORD_NEEDED':
|
case 'SESSION_PASSWORD_NEEDED':
|
||||||
console.warn('pageAuthCode: SESSION_PASSWORD_NEEDED');
|
console.warn('pageAuthCode: SESSION_PASSWORD_NEEDED');
|
||||||
err.handled = true;
|
err.handled = true;
|
||||||
if(animation) animation.destroy();
|
cleanup();
|
||||||
pagePassword.mount();
|
pagePassword.mount();
|
||||||
break;
|
break;
|
||||||
case 'PHONE_CODE_EMPTY':
|
case 'PHONE_CODE_EMPTY':
|
||||||
@ -196,8 +208,14 @@ let onFirstMount = (): Promise<any> => {
|
|||||||
if(!animation) return;
|
if(!animation) return;
|
||||||
|
|
||||||
let frame: number;
|
let frame: number;
|
||||||
if(length) frame = Math.round((length > max ? max : length) * (165 / max) + 11.33);
|
if(length) {
|
||||||
else frame = 0;
|
frame = Math.round((length > max ? max : length) * (165 / max) + 11.33);
|
||||||
|
|
||||||
|
mIdleSvg.style.display = 'none';
|
||||||
|
mTrackingSvg.style.display = '';
|
||||||
|
} else {
|
||||||
|
frame = 0;
|
||||||
|
}
|
||||||
//animation.playSegments([1, 2]);
|
//animation.playSegments([1, 2]);
|
||||||
|
|
||||||
let direction = needFrame > frame ? -1 : 1;
|
let direction = needFrame > frame ? -1 : 1;
|
||||||
@ -217,24 +235,52 @@ let onFirstMount = (): Promise<any> => {
|
|||||||
//animation.goToAndStop(length / max * );
|
//animation.goToAndStop(length / max * );
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let imageDiv = page.pageEl.querySelector('.auth-image');
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
LottieLoader.loadLottie(),
|
LottieLoader.loadLottie(),
|
||||||
|
|
||||||
|
fetch('assets/img/TwoFactorSetupMonkeyIdle.tgs')
|
||||||
|
.then(res => res.arrayBuffer())
|
||||||
|
.then(data => apiManager.gzipUncompress<string>(data, true))
|
||||||
|
.then(str => LottieLoader.loadAnimation({
|
||||||
|
container: imageDiv,
|
||||||
|
renderer: 'svg',
|
||||||
|
loop: true,
|
||||||
|
autoplay: true,
|
||||||
|
animationData: JSON.parse(str),
|
||||||
|
rendererSettings: {
|
||||||
|
className: 'monkey-idle'
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.then(_animation => {
|
||||||
|
idleAnimation = _animation;
|
||||||
|
|
||||||
|
mIdleSvg = imageDiv.querySelector('.monkey-idle');
|
||||||
|
}),
|
||||||
|
|
||||||
fetch('assets/img/TwoFactorSetupMonkeyTracking.tgs')
|
fetch('assets/img/TwoFactorSetupMonkeyTracking.tgs')
|
||||||
.then(res => res.arrayBuffer())
|
.then(res => res.arrayBuffer())
|
||||||
.then(data => apiManager.gzipUncompress<string>(data, true))
|
.then(data => apiManager.gzipUncompress<string>(data, true))
|
||||||
.then(str => LottieLoader.loadAnimation({
|
.then(str => LottieLoader.loadAnimation({
|
||||||
container: page.pageEl.querySelector('.auth-image'),
|
container: imageDiv,
|
||||||
renderer: 'svg',
|
renderer: 'svg',
|
||||||
loop: false,
|
loop: false,
|
||||||
autoplay: false,
|
autoplay: false,
|
||||||
animationData: JSON.parse(str)
|
animationData: JSON.parse(str),
|
||||||
|
rendererSettings: {
|
||||||
|
className: 'monkey-tracking'
|
||||||
|
}
|
||||||
}))
|
}))
|
||||||
.then(_animation => {
|
.then(_animation => {
|
||||||
animation = _animation;
|
animation = _animation;
|
||||||
animation.setSpeed(1);
|
animation.setSpeed(1);
|
||||||
//console.log(animation.getDuration(), animation.getDuration(true));
|
//console.log(animation.getDuration(), animation.getDuration(true));
|
||||||
|
|
||||||
|
mTrackingSvg = imageDiv.querySelector('.monkey-tracking');
|
||||||
|
if(!codeInput.value.length) {
|
||||||
|
mTrackingSvg.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
animation.addEventListener('enterFrame', (e: any) => {
|
animation.addEventListener('enterFrame', (e: any) => {
|
||||||
//console.log('enterFrame', e, needFrame);
|
//console.log('enterFrame', e, needFrame);
|
||||||
let currentFrame = Math.round(e.currentTime);
|
let currentFrame = Math.round(e.currentTime);
|
||||||
@ -244,6 +290,13 @@ let onFirstMount = (): Promise<any> => {
|
|||||||
animation.setSpeed(1);
|
animation.setSpeed(1);
|
||||||
animation.pause();
|
animation.pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(currentFrame == 0 && needFrame == 0 && mIdleSvg) {
|
||||||
|
mTrackingSvg.style.display = 'none';
|
||||||
|
mIdleSvg.style.display = '';
|
||||||
|
idleAnimation.stop();
|
||||||
|
idleAnimation.play();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
]);
|
]);
|
||||||
|
@ -206,6 +206,8 @@ let onFirstMount = () => {
|
|||||||
putPreloader(this);
|
putPreloader(this);
|
||||||
//this.innerHTML = 'PLEASE WAIT...';
|
//this.innerHTML = 'PLEASE WAIT...';
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
let phone_number = telEl.value;
|
let phone_number = telEl.value;
|
||||||
apiManager.invokeApi('auth.sendCode', {
|
apiManager.invokeApi('auth.sendCode', {
|
||||||
//flags: 0,
|
//flags: 0,
|
||||||
|
@ -205,6 +205,7 @@ $time-background: rgba(0, 0, 0, .35);
|
|||||||
#attach-file {
|
#attach-file {
|
||||||
&.menu-open {
|
&.menu-open {
|
||||||
color: $color-blue;
|
color: $color-blue;
|
||||||
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-menu {
|
.btn-menu {
|
||||||
|
@ -355,8 +355,6 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
img, video {
|
img, video {
|
||||||
width: auto;
|
|
||||||
height: auto;
|
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
@ -394,6 +392,7 @@
|
|||||||
|
|
||||||
width: max-content;
|
width: max-content;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
img:not(.emoji), video {
|
img:not(.emoji), video {
|
||||||
/* object-fit: contain; */
|
/* object-fit: contain; */
|
||||||
@ -401,7 +400,6 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
&.is-album {
|
&.is-album {
|
||||||
.attachment {
|
.attachment {
|
||||||
|
@ -68,7 +68,7 @@
|
|||||||
.category-items {
|
.category-items {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-column-gap: 2.44px;
|
grid-column-gap: 2.44px;
|
||||||
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
|
grid-template-columns: repeat(9, 1fr);
|
||||||
|
|
||||||
font-size: 2.25rem;
|
font-size: 2.25rem;
|
||||||
line-height: 2.25rem;
|
line-height: 2.25rem;
|
||||||
@ -121,10 +121,9 @@
|
|||||||
|
|
||||||
.category-items {
|
.category-items {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: grid;
|
||||||
align-items: center;
|
grid-template-columns: repeat(5, 1fr);
|
||||||
justify-content: space-between;
|
grid-column-gap: 1px;
|
||||||
flex-wrap: wrap;
|
|
||||||
|
|
||||||
> div {
|
> div {
|
||||||
width: 80px;
|
width: 80px;
|
||||||
|
@ -1,22 +1,15 @@
|
|||||||
#column-right {
|
#column-right {
|
||||||
width: 0%;
|
width: 0%;
|
||||||
/* grid-column: 3; */
|
|
||||||
position: relative;
|
position: relative;
|
||||||
transition: .2s ease-in-out;
|
transition: .2s ease-in-out;
|
||||||
|
|
||||||
.profile-container {
|
.sidebar-content {
|
||||||
> .scrollable {
|
|
||||||
min-width: 25vw;
|
min-width: 25vw;
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: $large-screen) {
|
@media (min-width: $large-screen) {
|
||||||
> .scrollable {
|
|
||||||
min-width: calc(#{$large-screen} / 4 - 1px);
|
min-width: calc(#{$large-screen} / 4 - 1px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
&:not(.active) {
|
&:not(.active) {
|
||||||
border-left-width: 0;
|
border-left-width: 0;
|
||||||
@ -51,7 +44,7 @@
|
|||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100%;
|
/* height: 100%; */
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
@ -172,7 +165,7 @@
|
|||||||
&-content {
|
&-content {
|
||||||
//min-height: 100%;
|
//min-height: 100%;
|
||||||
min-height: calc(100% - 49px);
|
min-height: calc(100% - 49px);
|
||||||
position: absolute; // FIX THE SAFARI!
|
//position: absolute; // FIX THE SAFARI!
|
||||||
//position: relative;
|
//position: relative;
|
||||||
/* width: 500%;
|
/* width: 500%;
|
||||||
margin-left: -100%;
|
margin-left: -100%;
|
||||||
|
@ -34,8 +34,8 @@ div.scrollable::-webkit-scrollbar-thumb {
|
|||||||
left: 0px;
|
left: 0px;
|
||||||
bottom: 0px;
|
bottom: 0px;
|
||||||
right: 0px;
|
right: 0px;
|
||||||
display: flex;
|
/* display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column; */
|
||||||
|
|
||||||
&.scrollable-x {
|
&.scrollable-x {
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
@ -50,7 +50,7 @@ div.scrollable::-webkit-scrollbar-thumb {
|
|||||||
-ms-overflow-style: none;
|
-ms-overflow-style: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-sentinel {
|
/* &-sentinel {
|
||||||
position: relative;
|
position: relative;
|
||||||
left: 0;
|
left: 0;
|
||||||
height: 1px;
|
height: 1px;
|
||||||
@ -58,7 +58,7 @@ div.scrollable::-webkit-scrollbar-thumb {
|
|||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
width: 1px;
|
width: 1px;
|
||||||
min-width: 1px;
|
min-width: 1px;
|
||||||
}
|
} */
|
||||||
|
|
||||||
/* &.scrollable-x ~ .scrollbar-thumb {
|
/* &.scrollable-x ~ .scrollbar-thumb {
|
||||||
top: auto;
|
top: auto;
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
#{$parent}-photo {
|
#{$parent}-photo {
|
||||||
max-height: 320px;
|
max-height: 320px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding-bottom: 8px;
|
|
||||||
|
|
||||||
img {
|
img {
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
|
@ -418,18 +418,11 @@ avatar-element {
|
|||||||
|
|
||||||
@keyframes ripple-effect {
|
@keyframes ripple-effect {
|
||||||
0% {
|
0% {
|
||||||
//transform: translate(-50%, -50%) scale(0);
|
|
||||||
transform: scale(0);
|
transform: scale(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 50% {
|
|
||||||
opacity: 1;
|
|
||||||
} */
|
|
||||||
|
|
||||||
to {
|
to {
|
||||||
transform: scale(2);
|
transform: scale(2);
|
||||||
//transform: translate(-50%, -50%) scale(2);
|
|
||||||
//opacity: 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1062,30 +1055,6 @@ input:focus, button:focus {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* button {
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
&:before {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
display: none;
|
|
||||||
content: " ";
|
|
||||||
position: absolute;
|
|
||||||
z-index: 2;
|
|
||||||
background: #000;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
opacity: .08;
|
|
||||||
}
|
|
||||||
} */
|
|
||||||
|
|
||||||
.btn-primary {
|
.btn-primary {
|
||||||
background: $color-blue;
|
background: $color-blue;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
@ -1106,9 +1075,8 @@ input:focus, button:focus {
|
|||||||
|
|
||||||
svg, use {
|
svg, use {
|
||||||
height: calc(100% - 20px);
|
height: calc(100% - 20px);
|
||||||
right: 12.5px;
|
right: 15px;
|
||||||
left: auto;
|
left: auto;
|
||||||
margin: 4px 0 auto;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user