Stickers helper
Hashable invokeApi
This commit is contained in:
parent
dbd5bda736
commit
9b811795f5
@ -1,8 +1,8 @@
|
||||
import Recorder from '../../../public/recorder.min';
|
||||
import { isTouchSupported } from "../../helpers/touchSupport";
|
||||
import appChatsManager from '../../lib/appManagers/appChatsManager';
|
||||
import appDocsManager from "../../lib/appManagers/appDocsManager";
|
||||
import appImManager from "../../lib/appManagers/appImManager";
|
||||
import appDocsManager, { MyDocument } from "../../lib/appManagers/appDocsManager";
|
||||
import appImManager, { CHAT_ANIMATION_GROUP } from "../../lib/appManagers/appImManager";
|
||||
import appMessagesManager from "../../lib/appManagers/appMessagesManager";
|
||||
import appPeersManager from '../../lib/appManagers/appPeersManager';
|
||||
import appWebPagesManager from "../../lib/appManagers/appWebPagesManager";
|
||||
@ -11,9 +11,9 @@ import apiManager from "../../lib/mtproto/mtprotoworker";
|
||||
import opusDecodeController from "../../lib/opusDecodeController";
|
||||
import { RichTextProcessor } from "../../lib/richtextprocessor";
|
||||
import rootScope from '../../lib/rootScope';
|
||||
import { blurActiveElement, cancelEvent, CLICK_EVENT_NAME, findUpClassName, getRichValue, getSelectedNodes, isInputEmpty, isSelectionSingle, markdownTags, MarkdownType, placeCaretAtEnd, serializeNodes } from "../../helpers/dom";
|
||||
import { blurActiveElement, cancelEvent, CLICK_EVENT_NAME, findUpClassName, getRichValue, getSelectedNodes, isInputEmpty, markdownTags, MarkdownType, placeCaretAtEnd, serializeNodes } from "../../helpers/dom";
|
||||
import ButtonMenu, { ButtonMenuItemOptions } from '../buttonMenu';
|
||||
import emoticonsDropdown from "../emoticonsDropdown";
|
||||
import emoticonsDropdown, { EmoticonsDropdown } from "../emoticonsDropdown";
|
||||
import PopupCreatePoll from "../popupCreatePoll";
|
||||
import PopupForward from '../popupForward';
|
||||
import PopupNewMedia from '../popupNewMedia';
|
||||
@ -24,12 +24,97 @@ import { wrapReply } from "../wrappers";
|
||||
import InputField from '../inputField';
|
||||
import { MessageEntity } from '../../layer';
|
||||
import ButtonIcon from '../buttonIcon';
|
||||
import appStickersManager from '../../lib/appManagers/appStickersManager';
|
||||
import SetTransition from '../singleTransition';
|
||||
import { SuperStickerRenderer } from '../emoticonsDropdown/tabs/stickers';
|
||||
import LazyLoadQueue from '../lazyLoadQueue';
|
||||
|
||||
const RECORD_MIN_TIME = 500;
|
||||
const POSTING_MEDIA_NOT_ALLOWED = 'Posting media content isn\'t allowed in this group.';
|
||||
|
||||
type ChatInputHelperType = 'edit' | 'webpage' | 'forward' | 'reply';
|
||||
|
||||
export class StickersHelper {
|
||||
private container: HTMLElement;
|
||||
private stickersContainer: HTMLElement;
|
||||
private scrollable: Scrollable;
|
||||
private superStickerRenderer: SuperStickerRenderer;
|
||||
private lazyLoadQueue: LazyLoadQueue;
|
||||
private lastEmoticon = '';
|
||||
|
||||
constructor(private appendTo: HTMLElement) {
|
||||
|
||||
}
|
||||
|
||||
public checkEmoticon(emoticon: string) {
|
||||
if(this.lastEmoticon == emoticon) return;
|
||||
|
||||
if(this.lastEmoticon && !emoticon) {
|
||||
if(this.container) {
|
||||
SetTransition(this.container, 'is-visible', false, 200/* , () => {
|
||||
this.stickersContainer.innerHTML = '';
|
||||
} */);
|
||||
}
|
||||
}
|
||||
|
||||
this.lastEmoticon = emoticon;
|
||||
if(this.lazyLoadQueue) {
|
||||
this.lazyLoadQueue.clear();
|
||||
}
|
||||
|
||||
if(!emoticon) {
|
||||
return;
|
||||
}
|
||||
|
||||
appStickersManager.getStickersByEmoticon(emoticon)
|
||||
.then(stickers => {
|
||||
if(this.lastEmoticon != emoticon) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.init) {
|
||||
this.init();
|
||||
this.init = null;
|
||||
}
|
||||
|
||||
this.stickersContainer.innerHTML = '';
|
||||
this.lazyLoadQueue.clear();
|
||||
if(stickers.length) {
|
||||
stickers.forEach(sticker => {
|
||||
this.stickersContainer.append(this.superStickerRenderer.renderSticker(sticker as MyDocument));
|
||||
});
|
||||
}
|
||||
|
||||
SetTransition(this.container, 'is-visible', true, 200);
|
||||
this.scrollable.scrollTop = 0;
|
||||
});
|
||||
}
|
||||
|
||||
private init() {
|
||||
this.container = document.createElement('div');
|
||||
this.container.classList.add('stickers-helper', 'z-depth-1');
|
||||
|
||||
this.stickersContainer = document.createElement('div');
|
||||
this.stickersContainer.classList.add('stickers-helper-stickers', 'super-stickers');
|
||||
this.stickersContainer.addEventListener('click', (e) => {
|
||||
if(!findUpClassName(e.target, 'super-sticker')) {
|
||||
return;
|
||||
}
|
||||
|
||||
appImManager.chatInputC.clearInput();
|
||||
EmoticonsDropdown.onMediaClick(e);
|
||||
});
|
||||
|
||||
this.container.append(this.stickersContainer);
|
||||
|
||||
this.scrollable = new Scrollable(this.container);
|
||||
this.lazyLoadQueue = new LazyLoadQueue();
|
||||
this.superStickerRenderer = new SuperStickerRenderer(this.lazyLoadQueue, CHAT_ANIMATION_GROUP);
|
||||
|
||||
this.appendTo.append(this.container);
|
||||
}
|
||||
}
|
||||
|
||||
export class MarkupTooltip {
|
||||
public container: HTMLElement;
|
||||
private wrapper: HTMLElement;
|
||||
@ -323,6 +408,7 @@ export class ChatInput {
|
||||
private canUndoFromHTML = '';
|
||||
|
||||
public markupTooltip: MarkupTooltip;
|
||||
public stickersHelper: StickersHelper;
|
||||
|
||||
constructor() {
|
||||
if(!isTouchSupported) {
|
||||
@ -382,6 +468,8 @@ export class ChatInput {
|
||||
this.replyElements.titleEl = this.replyElements.container.querySelector('.reply-title') as HTMLDivElement;
|
||||
this.replyElements.subtitleEl = this.replyElements.container.querySelector('.reply-subtitle') as HTMLDivElement;
|
||||
|
||||
this.stickersHelper = new StickersHelper(this.replyElements.container.parentElement);
|
||||
|
||||
try {
|
||||
this.recorder = new Recorder({
|
||||
//encoderBitRate: 32,
|
||||
@ -789,11 +877,24 @@ export class ChatInput {
|
||||
} */
|
||||
|
||||
//console.log('messageInput input', this.messageInput.innerText, this.serializeNodes(Array.from(this.messageInput.childNodes)));
|
||||
const value = this.messageInput.innerText;
|
||||
//const value = this.messageInput.innerText;
|
||||
const value = getRichValue(this.messageInput);
|
||||
|
||||
const entities = RichTextProcessor.parseEntities(value);
|
||||
//console.log('messageInput entities', entities);
|
||||
|
||||
if(this.stickersHelper) {
|
||||
let emoticon = '';
|
||||
if(entities.length && entities[0]._ == 'messageEntityEmoji') {
|
||||
const entity = entities[0];
|
||||
if(entity.length == value.length && !entity.offset) {
|
||||
emoticon = value;
|
||||
}
|
||||
}
|
||||
|
||||
this.stickersHelper.checkEmoticon(emoticon);
|
||||
}
|
||||
|
||||
const html = this.messageInput.innerHTML;
|
||||
if(this.canRedoFromHTML && html != this.canRedoFromHTML && !this.lockRedo) {
|
||||
this.canRedoFromHTML = '';
|
||||
@ -1014,6 +1115,8 @@ export class ChatInput {
|
||||
this.executedHistory.length = 0;
|
||||
this.canUndoFromHTML = '';
|
||||
}
|
||||
|
||||
this.onMessageInput();
|
||||
}
|
||||
|
||||
public isInputEmpty() {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import emoticonsDropdown, { EmoticonsDropdown, EMOTICONSSTICKERGROUP, EmoticonsTab } from "..";
|
||||
import { readBlobAsText } from "../../../helpers/blob";
|
||||
import mediaSizes from "../../../helpers/mediaSizes";
|
||||
import { StickerSet } from "../../../layer";
|
||||
import { MessagesAllStickers, StickerSet } from "../../../layer";
|
||||
import appDocsManager, { MyDocument } from "../../../lib/appManagers/appDocsManager";
|
||||
import appDownloadManager from "../../../lib/appManagers/appDownloadManager";
|
||||
import appStickersManager from "../../../lib/appManagers/appStickersManager";
|
||||
@ -10,12 +10,106 @@ import apiManager from "../../../lib/mtproto/mtprotoworker";
|
||||
import { RichTextProcessor } from "../../../lib/richtextprocessor";
|
||||
import rootScope from "../../../lib/rootScope";
|
||||
import animationIntersector from "../../animationIntersector";
|
||||
import { LazyLoadQueueRepeat } from "../../lazyLoadQueue";
|
||||
import LazyLoadQueue, { LazyLoadQueueRepeat } from "../../lazyLoadQueue";
|
||||
import { putPreloader, renderImageFromUrl } from "../../misc";
|
||||
import Scrollable, { ScrollableX } from "../../scrollable";
|
||||
import StickyIntersector from "../../stickyIntersector";
|
||||
import { wrapSticker } from "../../wrappers";
|
||||
|
||||
export class SuperStickerRenderer {
|
||||
lazyLoadQueue: LazyLoadQueueRepeat;
|
||||
animatedDivs: Set<HTMLDivElement> = new Set();
|
||||
|
||||
constructor(private regularLazyLoadQueue: LazyLoadQueue, private group: string) {
|
||||
this.lazyLoadQueue = new LazyLoadQueueRepeat(undefined, (target, visible) => {
|
||||
if(!visible) {
|
||||
this.processInvisibleDiv(target as HTMLDivElement);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
renderSticker(doc: MyDocument, div?: HTMLDivElement) {
|
||||
if(!div) {
|
||||
div = document.createElement('div');
|
||||
div.classList.add('grid-item', 'super-sticker');
|
||||
|
||||
if(doc.sticker == 2) {
|
||||
this.animatedDivs.add(div);
|
||||
|
||||
this.lazyLoadQueue.observe({
|
||||
div,
|
||||
load: this.processVisibleDiv
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// * This will wrap only a thumb
|
||||
wrapSticker({
|
||||
doc,
|
||||
div,
|
||||
lazyLoadQueue: this.regularLazyLoadQueue,
|
||||
group: this.group,
|
||||
onlyThumb: doc.sticker == 2
|
||||
});
|
||||
|
||||
return div;
|
||||
}
|
||||
|
||||
checkAnimationContainer = (div: HTMLElement, visible: boolean) => {
|
||||
//console.error('checkAnimationContainer', div, visible);
|
||||
const players = animationIntersector.getAnimations(div);
|
||||
players.forEach(player => {
|
||||
if(!visible) {
|
||||
animationIntersector.checkAnimation(player, true, true);
|
||||
} else {
|
||||
animationIntersector.checkAnimation(player, false);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
processVisibleDiv = (div: HTMLElement) => {
|
||||
const docID = div.dataset.docID;
|
||||
const doc = appDocsManager.getDoc(docID);
|
||||
|
||||
const size = mediaSizes.active.esgSticker.width;
|
||||
|
||||
const promise = wrapSticker({
|
||||
doc,
|
||||
div: div as HTMLDivElement,
|
||||
width: size,
|
||||
height: size,
|
||||
lazyLoadQueue: null,
|
||||
group: this.group,
|
||||
onlyThumb: false,
|
||||
play: true,
|
||||
loop: true
|
||||
});
|
||||
|
||||
promise.then(() => {
|
||||
//clearTimeout(timeout);
|
||||
this.checkAnimationContainer(div, this.lazyLoadQueue.intersector.isVisible(div));
|
||||
});
|
||||
|
||||
/* let timeout = window.setTimeout(() => {
|
||||
console.error('processVisibleDiv timeout', div, doc);
|
||||
}, 1e3); */
|
||||
|
||||
return promise;
|
||||
};
|
||||
|
||||
processInvisibleDiv = (div: HTMLElement) => {
|
||||
const docID = div.dataset.docID;
|
||||
const doc = appDocsManager.getDoc(docID);
|
||||
|
||||
//console.log('STICKER INvisible:', /* div, */docID);
|
||||
|
||||
this.checkAnimationContainer(div, false);
|
||||
|
||||
div.innerHTML = '';
|
||||
this.renderSticker(doc, div as HTMLDivElement);
|
||||
};
|
||||
}
|
||||
|
||||
export default class StickersTab implements EmoticonsTab {
|
||||
public content: HTMLElement;
|
||||
private stickersDiv: HTMLElement;
|
||||
@ -38,14 +132,13 @@ export default class StickersTab implements EmoticonsTab {
|
||||
|
||||
private stickyIntersector: StickyIntersector;
|
||||
|
||||
private animatedDivs: Set<HTMLDivElement> = new Set();
|
||||
private lazyLoadQueue: LazyLoadQueueRepeat;
|
||||
private superStickerRenderer: SuperStickerRenderer;
|
||||
|
||||
categoryPush(categoryDiv: HTMLElement, categoryTitle: string, promise: Promise<MyDocument[]>, prepend?: boolean) {
|
||||
//if((docs.length % 5) != 0) categoryDiv.classList.add('not-full');
|
||||
|
||||
const itemsDiv = document.createElement('div');
|
||||
itemsDiv.classList.add('category-items');
|
||||
itemsDiv.classList.add('category-items', 'super-stickers');
|
||||
|
||||
const titleDiv = document.createElement('div');
|
||||
titleDiv.classList.add('category-title');
|
||||
@ -60,7 +153,7 @@ export default class StickersTab implements EmoticonsTab {
|
||||
promise.then(documents => {
|
||||
documents.forEach(doc => {
|
||||
//if(doc._ == 'documentEmpty') return;
|
||||
itemsDiv.append(this.renderSticker(doc));
|
||||
itemsDiv.append(this.superStickerRenderer.renderSticker(doc));
|
||||
});
|
||||
|
||||
if(this.queueCategoryPush.length) {
|
||||
@ -80,33 +173,6 @@ export default class StickersTab implements EmoticonsTab {
|
||||
});
|
||||
}
|
||||
|
||||
renderSticker(doc: MyDocument, div?: HTMLDivElement) {
|
||||
if(!div) {
|
||||
div = document.createElement('div');
|
||||
div.classList.add('grid-item');
|
||||
|
||||
if(doc.sticker == 2) {
|
||||
this.animatedDivs.add(div);
|
||||
|
||||
this.lazyLoadQueue.observe({
|
||||
div,
|
||||
load: this.processVisibleDiv
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// * This will wrap only a thumb
|
||||
wrapSticker({
|
||||
doc,
|
||||
div,
|
||||
lazyLoadQueue: EmoticonsDropdown.lazyLoadQueue,
|
||||
group: EMOTICONSSTICKERGROUP,
|
||||
onlyThumb: doc.sticker == 2
|
||||
});
|
||||
|
||||
return div;
|
||||
}
|
||||
|
||||
async renderStickerSet(set: StickerSet.stickerSet, prepend = false) {
|
||||
const categoryDiv = document.createElement('div');
|
||||
categoryDiv.classList.add('sticker-category');
|
||||
@ -169,60 +235,6 @@ export default class StickersTab implements EmoticonsTab {
|
||||
}
|
||||
}
|
||||
|
||||
checkAnimationContainer = (div: HTMLElement, visible: boolean) => {
|
||||
//console.error('checkAnimationContainer', div, visible);
|
||||
const players = animationIntersector.getAnimations(div);
|
||||
players.forEach(player => {
|
||||
if(!visible) {
|
||||
animationIntersector.checkAnimation(player, true, true);
|
||||
} else {
|
||||
animationIntersector.checkAnimation(player, false);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
processVisibleDiv = (div: HTMLElement) => {
|
||||
const docID = div.dataset.docID;
|
||||
const doc = appDocsManager.getDoc(docID);
|
||||
|
||||
const size = mediaSizes.active.esgSticker.width;
|
||||
|
||||
const promise = wrapSticker({
|
||||
doc,
|
||||
div: div as HTMLDivElement,
|
||||
width: size,
|
||||
height: size,
|
||||
lazyLoadQueue: null,
|
||||
group: EMOTICONSSTICKERGROUP,
|
||||
onlyThumb: false,
|
||||
play: true,
|
||||
loop: true
|
||||
});
|
||||
|
||||
promise.then(() => {
|
||||
//clearTimeout(timeout);
|
||||
this.checkAnimationContainer(div, this.lazyLoadQueue.intersector.isVisible(div));
|
||||
});
|
||||
|
||||
/* let timeout = window.setTimeout(() => {
|
||||
console.error('processVisibleDiv timeout', div, doc);
|
||||
}, 1e3); */
|
||||
|
||||
return promise;
|
||||
};
|
||||
|
||||
processInvisibleDiv = (div: HTMLElement) => {
|
||||
const docID = div.dataset.docID;
|
||||
const doc = appDocsManager.getDoc(docID);
|
||||
|
||||
//console.log('STICKER INvisible:', /* div, */docID);
|
||||
|
||||
this.checkAnimationContainer(div, false);
|
||||
|
||||
div.innerHTML = '';
|
||||
this.renderSticker(doc, div as HTMLDivElement);
|
||||
};
|
||||
|
||||
init() {
|
||||
this.content = document.getElementById('content-stickers');
|
||||
//let stickersDiv = contentStickersDiv.querySelector('.os-content') as HTMLDivElement;
|
||||
@ -299,16 +311,10 @@ export default class StickersTab implements EmoticonsTab {
|
||||
this.categoryPush(this.recentDiv, 'Recent', Promise.resolve(this.recentStickers), true);
|
||||
}),
|
||||
|
||||
apiManager.invokeApi('messages.getAllStickers', {hash: 0}).then(async(res) => {
|
||||
let stickers: {
|
||||
_: 'messages.allStickers',
|
||||
hash: number,
|
||||
sets: Array<StickerSet.stickerSet>
|
||||
} = res as any;
|
||||
|
||||
appStickersManager.getAllStickers().then((res) => {
|
||||
preloader.remove();
|
||||
|
||||
for(let set of stickers.sets) {
|
||||
for(let set of (res as MessagesAllStickers.messagesAllStickers).sets) {
|
||||
this.renderStickerSet(set);
|
||||
}
|
||||
})
|
||||
@ -316,13 +322,9 @@ export default class StickersTab implements EmoticonsTab {
|
||||
this.mounted = true;
|
||||
});
|
||||
|
||||
this.lazyLoadQueue = new LazyLoadQueueRepeat(undefined, (target, visible) => {
|
||||
if(!visible) {
|
||||
this.processInvisibleDiv(target as HTMLDivElement);
|
||||
}
|
||||
});
|
||||
this.superStickerRenderer = new SuperStickerRenderer(EmoticonsDropdown.lazyLoadQueue, EMOTICONSSTICKERGROUP);
|
||||
|
||||
emoticonsDropdown.addLazyLoadQueueRepeat(this.lazyLoadQueue, this.processInvisibleDiv);
|
||||
emoticonsDropdown.addLazyLoadQueueRepeat(this.superStickerRenderer.lazyLoadQueue, this.superStickerRenderer.processInvisibleDiv);
|
||||
|
||||
/* setInterval(() => {
|
||||
// @ts-ignore
|
||||
@ -342,7 +344,7 @@ export default class StickersTab implements EmoticonsTab {
|
||||
|
||||
let div = this.recentDiv.querySelector(`[data-doc-i-d="${doc.id}"]`);
|
||||
if(!div) {
|
||||
div = this.renderSticker(doc);
|
||||
div = this.superStickerRenderer.renderSticker(doc);
|
||||
}
|
||||
|
||||
const items = this.recentDiv.querySelector('.category-items');
|
||||
|
@ -565,7 +565,7 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o
|
||||
const toneIndex = emoji ? getEmojiToneIndex(emoji) : -1;
|
||||
|
||||
if((doc.thumbs?.length || doc.stickerCachedThumbs) && !div.firstElementChild && (!doc.downloaded || stickerType == 2 || onlyThumb)/* && doc.thumbs[0]._ != 'photoSizeEmpty' */) {
|
||||
const thumb = doc.stickerCachedThumbs && doc.stickerCachedThumbs[toneIndex] || doc.thumbs[0];
|
||||
let thumb = doc.stickerCachedThumbs && doc.stickerCachedThumbs[toneIndex] || doc.thumbs[0];
|
||||
|
||||
//console.log('wrap sticker', thumb, div);
|
||||
|
||||
@ -581,23 +581,33 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o
|
||||
renderImageFromUrl(img, thumb.url, afterRender);
|
||||
} else if('bytes' in thumb) {
|
||||
if(thumb._ == 'photoPathSize') {
|
||||
//if(!doc.w) console.error('no w', doc);
|
||||
div.innerHTML = `<svg class="rlottie-vector" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 ${doc.w || 512} ${doc.h || 512}" xml:space="preserve">
|
||||
<path d="${appPhotosManager.getPathFromPhotoPathSize(thumb)}"/>
|
||||
</svg>`;
|
||||
} else if(toneIndex <= 0) {
|
||||
if(thumb.bytes.length) {
|
||||
//if(!doc.w) console.error('no w', doc);
|
||||
const d = appPhotosManager.getPathFromPhotoPathSize(thumb);
|
||||
/* if(d == 'Mz' || d.includes('151,48,349,33z')) {
|
||||
console.error('no path', doc);
|
||||
} */
|
||||
div.innerHTML = `<svg class="rlottie-vector" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 ${doc.w || 512} ${doc.h || 512}" xml:space="preserve">
|
||||
<path d="${d}"/>
|
||||
</svg>`;
|
||||
} else {
|
||||
thumb = doc.thumbs.find(t => (t as PhotoSize.photoStrippedSize).bytes?.length) || thumb;
|
||||
}
|
||||
}
|
||||
|
||||
if(thumb && thumb._ != 'photoPathSize' && toneIndex <= 0) {
|
||||
img = new Image();
|
||||
if((webpWorkerController.isWebpSupported() || doc.pFlags.stickerThumbConverted || thumb.url)/* && false */) {
|
||||
renderImageFromUrl(img, appPhotosManager.getPreviewURLFromThumb(thumb, true), afterRender);
|
||||
renderImageFromUrl(img, appPhotosManager.getPreviewURLFromThumb(thumb as PhotoSize.photoStrippedSize, true), afterRender);
|
||||
} else {
|
||||
webpWorkerController.convert(doc.id, thumb.bytes as Uint8Array).then(bytes => {
|
||||
thumb.bytes = bytes;
|
||||
webpWorkerController.convert(doc.id, (thumb as PhotoSize.photoStrippedSize).bytes as Uint8Array).then(bytes => {
|
||||
(thumb as PhotoSize.photoStrippedSize).bytes = bytes;
|
||||
doc.pFlags.stickerThumbConverted = true;
|
||||
|
||||
if(middleware && !middleware()) return;
|
||||
|
||||
if(!div.childElementCount) {
|
||||
renderImageFromUrl(img, appPhotosManager.getPreviewURLFromThumb(thumb, true), afterRender);
|
||||
renderImageFromUrl(img, appPhotosManager.getPreviewURLFromThumb(thumb as PhotoSize.photoStrippedSize, true), afterRender);
|
||||
}
|
||||
}).catch(() => {});
|
||||
}
|
||||
@ -610,14 +620,14 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o
|
||||
|
||||
const r = () => {
|
||||
if(div.childElementCount || (middleware && !middleware())) return;
|
||||
renderImageFromUrl(img, thumb.url, afterRender);
|
||||
renderImageFromUrl(img, (thumb as PhotoSize.photoStrippedSize).url, afterRender);
|
||||
};
|
||||
|
||||
if(thumb.url) {
|
||||
if((thumb as PhotoSize.photoStrippedSize).url) {
|
||||
r();
|
||||
return Promise.resolve();
|
||||
} else {
|
||||
return appDocsManager.getThumbURL(doc, thumb).promise.then(r);
|
||||
return appDocsManager.getThumbURL(doc, thumb as PhotoSize.photoStrippedSize).promise.then(r);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Document, InputFileLocation, InputStickerSet, MessagesRecentStickers, MessagesStickerSet, PhotoSize, StickerSet, StickerSetCovered } from '../../layer';
|
||||
import { Document, InputFileLocation, InputStickerSet, MessagesAllStickers, MessagesFeaturedStickers, MessagesFoundStickerSets, MessagesRecentStickers, MessagesStickers, MessagesStickerSet, PhotoSize, StickerPack, StickerSet, StickerSetCovered } from '../../layer';
|
||||
import { Modify } from '../../types';
|
||||
import apiManager from '../mtproto/mtprotoworker';
|
||||
import { MOUNT_CLASS_TO } from '../mtproto/mtproto_config';
|
||||
@ -15,18 +15,8 @@ export class AppStickersManager {
|
||||
|
||||
private saveSetsTimeout: number;
|
||||
|
||||
private hashes: Partial<{
|
||||
featured: Partial<{hash: number, result: StickerSetCovered[]}>,
|
||||
search: {
|
||||
[query: string]: Partial<{
|
||||
hash: number,
|
||||
result: StickerSetCovered[]
|
||||
}>
|
||||
}
|
||||
}> = {
|
||||
featured: {},
|
||||
search: {}
|
||||
};
|
||||
private getStickerSetPromises: {[setID: string]: Promise<MessagesStickerSet>} = {};
|
||||
private getStickersByEmoticonsPromises: {[emoticon: string]: Promise<Document[]>} = {};
|
||||
|
||||
constructor() {
|
||||
appStateManager.getState().then(({stickerSets}) => {
|
||||
@ -74,25 +64,29 @@ export class AppStickersManager {
|
||||
}> = {}): Promise<MessagesStickerSet> {
|
||||
if(this.stickerSets[set.id] && !params.overwrite && this.stickerSets[set.id].documents?.length) return this.stickerSets[set.id];
|
||||
|
||||
const stickerSet = await apiManager.invokeApi('messages.getStickerSet', {
|
||||
if(this.getStickerSetPromises[set.id]) {
|
||||
return this.getStickerSetPromises[set.id];
|
||||
}
|
||||
|
||||
const promise = this.getStickerSetPromises[set.id] = apiManager.invokeApi('messages.getStickerSet', {
|
||||
stickerset: this.getStickerSetInput(set)
|
||||
});
|
||||
|
||||
|
||||
const stickerSet = await promise;
|
||||
delete this.getStickerSetPromises[set.id];
|
||||
this.saveStickerSet(stickerSet, set.id);
|
||||
|
||||
return stickerSet as any;
|
||||
return stickerSet;
|
||||
}
|
||||
|
||||
public async getRecentStickers(): Promise<Modify<MessagesRecentStickers.messagesRecentStickers, {
|
||||
stickers: Document[]
|
||||
}>> {
|
||||
const res = await apiManager.invokeApi('messages.getRecentStickers') as MessagesRecentStickers.messagesRecentStickers;
|
||||
const res = await apiManager.invokeApiHashable('messages.getRecentStickers') as MessagesRecentStickers.messagesRecentStickers;
|
||||
|
||||
if(res._ == 'messages.recentStickers') {
|
||||
this.saveStickers(res.stickers);
|
||||
}
|
||||
this.saveStickers(res.stickers);
|
||||
|
||||
return res as any;
|
||||
return res;
|
||||
}
|
||||
|
||||
public getAnimatedEmojiSticker(emoji: string) {
|
||||
@ -185,21 +179,13 @@ export class AppStickersManager {
|
||||
}
|
||||
|
||||
public async getFeaturedStickers() {
|
||||
const res = await apiManager.invokeApi('messages.getFeaturedStickers', {
|
||||
hash: this.hashes.featured?.hash || 0
|
||||
});
|
||||
const res = await apiManager.invokeApiHashable('messages.getFeaturedStickers') as MessagesFeaturedStickers.messagesFeaturedStickers;
|
||||
|
||||
const hashed = this.hashes.featured ?? (this.hashes.featured = {});
|
||||
if(res._ != 'messages.featuredStickersNotModified') {
|
||||
hashed.hash = res.hash;
|
||||
hashed.result = res.sets;
|
||||
}
|
||||
|
||||
hashed.result.forEach(covered => {
|
||||
res.sets.forEach(covered => {
|
||||
this.saveStickerSet({set: covered.set, documents: [], packs: []}, covered.set.id);
|
||||
});
|
||||
|
||||
return hashed.result;
|
||||
return res.sets;
|
||||
}
|
||||
|
||||
public async toggleStickerSet(set: StickerSet.stickerSet) {
|
||||
@ -231,20 +217,13 @@ export class AppStickersManager {
|
||||
|
||||
public async searchStickerSets(query: string, excludeFeatured = true) {
|
||||
const flags = excludeFeatured ? 1 : 0;
|
||||
const res = await apiManager.invokeApi('messages.searchStickerSets', {
|
||||
const res = await apiManager.invokeApiHashable('messages.searchStickerSets', {
|
||||
flags,
|
||||
exclude_featured: excludeFeatured || undefined,
|
||||
q: query,
|
||||
hash: this.hashes.search[query]?.hash || 0
|
||||
});
|
||||
q: query
|
||||
}) as MessagesFoundStickerSets.messagesFoundStickerSets;
|
||||
|
||||
const hashed = this.hashes.search[query] ?? (this.hashes.search[query] = {});
|
||||
if(res._ != 'messages.foundStickerSetsNotModified') {
|
||||
hashed.hash = res.hash;
|
||||
hashed.result = res.sets;
|
||||
}
|
||||
|
||||
hashed.result.forEach(covered => {
|
||||
res.sets.forEach(covered => {
|
||||
this.saveStickerSet({set: covered.set, documents: [], packs: []}, covered.set.id);
|
||||
});
|
||||
|
||||
@ -252,12 +231,60 @@ export class AppStickersManager {
|
||||
for(let id in this.stickerSets) {
|
||||
const {set} = this.stickerSets[id];
|
||||
|
||||
if(set.title.toLowerCase().includes(query.toLowerCase()) && !hashed.result.find(c => c.set.id == set.id)) {
|
||||
if(set.title.toLowerCase().includes(query.toLowerCase()) && !res.sets.find(c => c.set.id == set.id)) {
|
||||
foundSaved.push({_: 'stickerSetCovered', set, cover: null});
|
||||
}
|
||||
}
|
||||
|
||||
return hashed.result.concat(foundSaved);
|
||||
return res.sets.concat(foundSaved);
|
||||
}
|
||||
|
||||
public getAllStickers() {
|
||||
return apiManager.invokeApiHashable('messages.getAllStickers');
|
||||
}
|
||||
|
||||
public preloadStickerSets() {
|
||||
return this.getAllStickers().then(allStickers => {
|
||||
return Promise.all((allStickers as MessagesAllStickers.messagesAllStickers).sets.map(set => this.getStickerSet(set)));
|
||||
});
|
||||
}
|
||||
|
||||
public getStickersByEmoticon(emoticon: string) {
|
||||
if(this.getStickersByEmoticonsPromises[emoticon]) return this.getStickersByEmoticonsPromises[emoticon];
|
||||
|
||||
return this.getStickersByEmoticonsPromises[emoticon] = Promise.all([
|
||||
apiManager.invokeApiHashable('messages.getStickers', {
|
||||
emoticon
|
||||
}),
|
||||
this.preloadStickerSets(),
|
||||
this.getRecentStickers()
|
||||
]).then(([messagesStickers, installedSets, recentStickers]) => {
|
||||
const foundStickers = (messagesStickers as MessagesStickers.messagesStickers).stickers.map(sticker => appDocsManager.saveDoc(sticker));
|
||||
const cachedStickersAnimated: Document.document[] = [], cachedStickersStatic: Document.document[] = [];
|
||||
|
||||
//console.log('getStickersByEmoticon', messagesStickers, installedSets, recentStickers);
|
||||
|
||||
const iteratePacks = (packs: StickerPack.stickerPack[]) => {
|
||||
for(const pack of packs) {
|
||||
if(pack.emoticon.includes(emoticon)) {
|
||||
for(const docID of pack.documents) {
|
||||
const doc = appDocsManager.getDoc(docID);
|
||||
(doc.animated ? cachedStickersAnimated : cachedStickersStatic).push(doc);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
iteratePacks(recentStickers.packs);
|
||||
|
||||
for(const set of installedSets) {
|
||||
iteratePacks(set.packs);
|
||||
}
|
||||
|
||||
const stickers = [...new Set(cachedStickersAnimated.concat(cachedStickersStatic, foundStickers))];
|
||||
|
||||
return stickers;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,15 @@ type Task = {
|
||||
|
||||
const USEWORKERASWORKER = true;
|
||||
|
||||
type HashResult = {
|
||||
hash: number,
|
||||
result: any
|
||||
};
|
||||
|
||||
type HashOptions = {
|
||||
[queryJSON: string]: HashResult
|
||||
};
|
||||
|
||||
export class ApiManagerProxy extends CryptoWorkerMethods {
|
||||
public worker: Worker;
|
||||
public postMessage: (...args: any[]) => void;
|
||||
@ -41,6 +50,8 @@ export class ApiManagerProxy extends CryptoWorkerMethods {
|
||||
|
||||
private log = logger('API-PROXY');
|
||||
|
||||
private hashes: {[method: string]: HashOptions} = {};
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.log('constructor');
|
||||
@ -230,6 +241,36 @@ export class ApiManagerProxy extends CryptoWorkerMethods {
|
||||
return this.performTaskWorker('invokeApi', method, params, o);
|
||||
}
|
||||
|
||||
public invokeApiHashable<T extends keyof MethodDeclMap>(method: T, params: Omit<MethodDeclMap[T]['req'], 'hash'> = {} as any, options: InvokeApiOptions = {}): Promise<MethodDeclMap[T]['res']> {
|
||||
//console.log('will invokeApi:', method, params, options);
|
||||
|
||||
const queryJSON = JSON.stringify(params);
|
||||
let cached: HashResult;
|
||||
if(this.hashes[method]) {
|
||||
cached = this.hashes[method][queryJSON];
|
||||
if(cached) {
|
||||
(params as any).hash = cached.hash;
|
||||
}
|
||||
}
|
||||
|
||||
return this.performTaskWorker('invokeApi', method, params, options).then((result: any) => {
|
||||
if(result._.includes('NotModified')) {
|
||||
//this.log.warn('NotModified saved!', method, queryJSON);
|
||||
return cached.result;
|
||||
}
|
||||
|
||||
if(result.hash) {
|
||||
if(!this.hashes[method]) this.hashes[method] = {};
|
||||
this.hashes[method][queryJSON] = {
|
||||
hash: result.hash,
|
||||
result: result
|
||||
};
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
public setBaseDcID(dcID: number) {
|
||||
return this.performTaskWorker('setBaseDcID', dcID);
|
||||
}
|
||||
|
@ -768,7 +768,7 @@ $chat-helper-size: 39px;
|
||||
|
||||
.btn-menu {
|
||||
padding: 8px 0;
|
||||
right: -8px;
|
||||
right: -11px;
|
||||
bottom: calc(100% + 16px);
|
||||
|
||||
> div {
|
||||
@ -1420,3 +1420,45 @@ $chat-helper-size: 39px;
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
||||
.stickers-helper {
|
||||
position: absolute !important;
|
||||
bottom: calc(100% + 10px);
|
||||
opacity: 0;
|
||||
transition: opacity .2s ease-in-out;
|
||||
overflow: hidden;
|
||||
padding: 0 !important;
|
||||
|
||||
> .scrollable {
|
||||
position: relative;
|
||||
max-height: 220px;
|
||||
min-height: var(--esg-sticker-size);
|
||||
}
|
||||
|
||||
&-stickers {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
&-sticker {
|
||||
position: relative;
|
||||
width: var(--esg-sticker-size);
|
||||
height: var(--esg-sticker-size);
|
||||
margin: 5px;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.is-visible) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.is-visible {
|
||||
&:not(.backwards) {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,19 +12,19 @@
|
||||
@include respond-to(esg-top) {
|
||||
position: absolute !important;
|
||||
left: 1rem;
|
||||
bottom: calc(85px);
|
||||
bottom: 85px;
|
||||
width: 420px !important;
|
||||
height: 420px;
|
||||
max-height: 420px;
|
||||
box-shadow: 0px 5px 10px 5px rgba(16, 35, 47, .14);
|
||||
z-index: 3;
|
||||
border-radius: 10px;
|
||||
transition: all .2s ease-out;
|
||||
transition: transform .2s ease-out;
|
||||
transform: scale(0);
|
||||
transform-origin: 0 100%;
|
||||
|
||||
&.active {
|
||||
transition: all .2s ease-in;
|
||||
transition: transform .2s ease-in;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
@ -225,29 +225,7 @@
|
||||
grid-column-gap: 1px;
|
||||
justify-content: space-between;
|
||||
|
||||
> .grid-item {
|
||||
html.no-touch &:hover {
|
||||
border-radius: 12px;
|
||||
background-color: var(--color-gray-hover);
|
||||
}
|
||||
|
||||
/* &:nth-child(5n+5) {
|
||||
margin-right: 0;
|
||||
} */
|
||||
|
||||
> img, > .rlottie {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
> img {
|
||||
animation: fade-in-opacity .2s ease forwards;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -613,6 +613,7 @@
|
||||
&-sticker {
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
position: relative;
|
||||
//padding: 0 5px;
|
||||
|
||||
&:hover {
|
||||
|
@ -721,6 +721,38 @@ img.emoji {
|
||||
fill: rgba(0, 0, 0, .08);
|
||||
}
|
||||
|
||||
.super-stickers {
|
||||
width: 100%;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, var(--esg-sticker-size)); // 64px
|
||||
grid-column-gap: 1px;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.super-sticker {
|
||||
html.no-touch &:hover {
|
||||
border-radius: 12px;
|
||||
background-color: var(--color-gray-hover);
|
||||
}
|
||||
|
||||
/* &:nth-child(5n+5) {
|
||||
margin-right: 0;
|
||||
} */
|
||||
|
||||
> img, > .rlottie {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
> img {
|
||||
animation: fade-in-opacity .2s ease forwards;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
|
||||
.fade-in-transition {
|
||||
opacity: 1;
|
||||
transition: opacity .2s ease;
|
||||
|
Loading…
x
Reference in New Issue
Block a user