GIFs search
GIFs autoplay in panel Fixed (not) bubble time (edited, etc)
This commit is contained in:
parent
0102df4247
commit
489ecb974b
@ -5,12 +5,13 @@
|
|||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "webpack-dev-server --config webpack.dev.js",
|
"start": "webpack-dev-server --config webpack.dev.js",
|
||||||
"start-production": "webpack-dev-server --config webpack.prod.js",
|
"start:production": "webpack-dev-server --config webpack.prod.js",
|
||||||
"serve": "npm run build; node server.js",
|
"serve": "npm run build; node server.js",
|
||||||
"build": "webpack --config webpack.prod.js",
|
"build": "webpack --config webpack.prod.js",
|
||||||
|
"build:dev": "webpack --config webpack.dev.js",
|
||||||
"test": "jest --config=jest.config.js",
|
"test": "jest --config=jest.config.js",
|
||||||
"profile": "webpack --profile --json > stats.json --config webpack.prod.js",
|
"profile": "webpack --profile --json > stats.json --config webpack.prod.js",
|
||||||
"profile-dev": "webpack --profile --json > stats.json --config webpack.dev.js"
|
"profile:dev": "webpack --profile --json > stats.json --config webpack.dev.js"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
|
@ -6,7 +6,7 @@ $rootScope.$on('avatar_update', (e: CustomEvent) => {
|
|||||||
|
|
||||||
appProfileManager.removeFromAvatarsCache(peerID);
|
appProfileManager.removeFromAvatarsCache(peerID);
|
||||||
(Array.from(document.querySelectorAll('avatar-element[peer="' + peerID + '"]')) as AvatarElement[]).forEach(elem => {
|
(Array.from(document.querySelectorAll('avatar-element[peer="' + peerID + '"]')) as AvatarElement[]).forEach(elem => {
|
||||||
console.log('updating avatar:', elem);
|
//console.log('updating avatar:', elem);
|
||||||
elem.update();
|
elem.update();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -18,6 +18,7 @@ import animationIntersector from "./animationIntersector";
|
|||||||
import appSidebarRight from "../lib/appManagers/appSidebarRight";
|
import appSidebarRight from "../lib/appManagers/appSidebarRight";
|
||||||
import appStateManager from "../lib/appManagers/appStateManager";
|
import appStateManager from "../lib/appManagers/appStateManager";
|
||||||
import { horizontalMenu } from "./horizontalMenu";
|
import { horizontalMenu } from "./horizontalMenu";
|
||||||
|
import GifsMasonry from "./gifsMasonry";
|
||||||
|
|
||||||
export const EMOTICONSSTICKERGROUP = 'emoticons-dropdown';
|
export const EMOTICONSSTICKERGROUP = 'emoticons-dropdown';
|
||||||
|
|
||||||
@ -329,7 +330,7 @@ class StickersTab implements EmoticonsTab {
|
|||||||
loop: false, */
|
loop: false, */
|
||||||
lazyLoadQueue: EmoticonsDropdown.lazyLoadQueue,
|
lazyLoadQueue: EmoticonsDropdown.lazyLoadQueue,
|
||||||
group: EMOTICONSSTICKERGROUP,
|
group: EMOTICONSSTICKERGROUP,
|
||||||
onlyThumb: true
|
onlyThumb: doc.sticker == 2
|
||||||
});
|
});
|
||||||
|
|
||||||
return div;
|
return div;
|
||||||
@ -535,18 +536,13 @@ class GifsTab implements EmoticonsTab {
|
|||||||
|
|
||||||
init() {
|
init() {
|
||||||
this.content = document.getElementById('content-gifs');
|
this.content = document.getElementById('content-gifs');
|
||||||
const masonry = this.content.firstElementChild as HTMLDivElement;
|
const gifsContainer = this.content.firstElementChild as HTMLDivElement;
|
||||||
|
gifsContainer.addEventListener('click', EmoticonsDropdown.onMediaClick);
|
||||||
masonry.addEventListener('click', EmoticonsDropdown.onMediaClick);
|
|
||||||
|
|
||||||
|
const masonry = new GifsMasonry(gifsContainer);
|
||||||
const scroll = new Scrollable(this.content, 'y', 'GIFS', null);
|
const scroll = new Scrollable(this.content, 'y', 'GIFS', null);
|
||||||
|
|
||||||
const preloader = putPreloader(this.content, true);
|
const preloader = putPreloader(this.content, true);
|
||||||
|
|
||||||
const width = 400;
|
|
||||||
const maxSingleWidth = width - 100;
|
|
||||||
const height = 100;
|
|
||||||
|
|
||||||
apiManager.invokeApi('messages.getSavedGifs', {hash: 0}).then((_res) => {
|
apiManager.invokeApi('messages.getSavedGifs', {hash: 0}).then((_res) => {
|
||||||
let res = _res as {
|
let res = _res as {
|
||||||
_: 'messages.savedGifs',
|
_: 'messages.savedGifs',
|
||||||
@ -557,155 +553,11 @@ class GifsTab implements EmoticonsTab {
|
|||||||
|
|
||||||
//let line: MTDocument[] = [];
|
//let line: MTDocument[] = [];
|
||||||
|
|
||||||
let wastedWidth = 0;
|
|
||||||
|
|
||||||
res.gifs.forEach((gif, idx) => {
|
|
||||||
res.gifs[idx] = appDocsManager.saveDoc(gif);
|
|
||||||
});
|
|
||||||
|
|
||||||
preloader.remove();
|
preloader.remove();
|
||||||
|
res.gifs.forEach((doc, idx) => {
|
||||||
for(let i = 0, length = res.gifs.length; i < length;) {
|
res.gifs[idx] = appDocsManager.saveDoc(doc);
|
||||||
const doc = res.gifs[i];
|
masonry.add(doc, EMOTICONSSTICKERGROUP, EmoticonsDropdown.lazyLoadQueue);
|
||||||
|
|
||||||
let gifWidth = doc.w;
|
|
||||||
let gifHeight = doc.h;
|
|
||||||
if(gifHeight < height) {
|
|
||||||
gifWidth = height / gifHeight * gifWidth;
|
|
||||||
gifHeight = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
let willUseWidth = Math.min(maxSingleWidth, width - wastedWidth, gifWidth);
|
|
||||||
let {w, h} = calcImageInBox(gifWidth, gifHeight, willUseWidth, height);
|
|
||||||
|
|
||||||
/* wastedWidth += w;
|
|
||||||
|
|
||||||
if(wastedWidth == width || h < height) {
|
|
||||||
wastedWidth = 0;
|
|
||||||
console.log('completed line', i, line);
|
|
||||||
line = [];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
line.push(gif); */
|
|
||||||
++i;
|
|
||||||
|
|
||||||
//console.log('gif:', gif, w, h);
|
|
||||||
|
|
||||||
let div = document.createElement('div');
|
|
||||||
div.classList.add('gif', 'fade-in-transition');
|
|
||||||
div.style.width = w + 'px';
|
|
||||||
div.style.opacity = '0';
|
|
||||||
//div.style.height = h + 'px';
|
|
||||||
div.dataset.docID = doc.id;
|
|
||||||
|
|
||||||
masonry.append(div);
|
|
||||||
|
|
||||||
//let preloader = new ProgressivePreloader(div);
|
|
||||||
|
|
||||||
const posterURL = appDocsManager.getThumbURL(doc, false);
|
|
||||||
let img: HTMLImageElement;
|
|
||||||
if(posterURL) {
|
|
||||||
img = new Image();
|
|
||||||
img.src = posterURL;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mouseOut = false;
|
|
||||||
const onMouseOver = (e: MouseEvent) => {
|
|
||||||
//console.log('onMouseOver', doc.id);
|
|
||||||
//cancelEvent(e);
|
|
||||||
mouseOut = false;
|
|
||||||
|
|
||||||
wrapVideo({
|
|
||||||
doc,
|
|
||||||
container: div,
|
|
||||||
//lazyLoadQueue: EmoticonsDropdown.lazyLoadQueue,
|
|
||||||
//group: EMOTICONSSTICKERGROUP,
|
|
||||||
noInfo: true,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const video = div.querySelector('video');
|
|
||||||
video.addEventListener('canplay', () => {
|
|
||||||
div.style.opacity = '';
|
|
||||||
if(!mouseOut) {
|
|
||||||
img && img.classList.add('hide');
|
|
||||||
} else {
|
|
||||||
img && img.classList.remove('hide');
|
|
||||||
if(div.lastElementChild != img) {
|
|
||||||
div.lastElementChild.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, {once: true});
|
|
||||||
};
|
|
||||||
|
|
||||||
const afterRender = () => {
|
|
||||||
if(img) {
|
|
||||||
div.append(img);
|
|
||||||
div.style.opacity = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
div.addEventListener('mouseover', onMouseOver, {once: true});
|
|
||||||
div.addEventListener('mouseout', (e) => {
|
|
||||||
const toElement = (e as any).toElement as Element;
|
|
||||||
//console.log('onMouseOut', doc.id, e);
|
|
||||||
if(findUpClassName(toElement, 'gif') == div) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//cancelEvent(e);
|
|
||||||
|
|
||||||
mouseOut = true;
|
|
||||||
|
|
||||||
const cb = () => {
|
|
||||||
if(div.lastElementChild != img) {
|
|
||||||
div.lastElementChild.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
div.addEventListener('mouseover', onMouseOver, {once: true});
|
|
||||||
};
|
|
||||||
|
|
||||||
img && img.classList.remove('hide');
|
|
||||||
/* window.requestAnimationFrame(() => {
|
|
||||||
window.requestAnimationFrame();
|
|
||||||
}); */
|
|
||||||
if(img) window.requestAnimationFrame(() => window.requestAnimationFrame(cb));
|
|
||||||
else cb();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
(posterURL ? renderImageFromUrl(img, posterURL, afterRender) : afterRender());
|
|
||||||
|
|
||||||
/* wrapVideo({
|
|
||||||
doc,
|
|
||||||
container: div,
|
|
||||||
lazyLoadQueue: EmoticonsDropdown.lazyLoadQueue,
|
|
||||||
group: EMOTICONSSTICKERGROUP,
|
|
||||||
noInfo: true,
|
|
||||||
}); */
|
|
||||||
|
|
||||||
/* EmoticonsDropdown.lazyLoadQueue.push({
|
|
||||||
div,
|
|
||||||
load: () => {
|
|
||||||
const download = appDocsManager.downloadDocNew(doc);
|
|
||||||
|
|
||||||
let thumbSize: string, posterURL: string;
|
|
||||||
if(doc.thumbs?.length) {
|
|
||||||
thumbSize = doc.thumbs[0].type;
|
|
||||||
posterURL = appDocsManager.getThumbURL(doc, thumbSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
preloader.attach(div, true, appDocsManager.getInputFileName(doc, thumbSize));
|
|
||||||
|
|
||||||
download.promise.then(blob => {
|
|
||||||
preloader.detach();
|
|
||||||
|
|
||||||
div.innerHTML = `<video autoplay="true" muted="true" loop="true" src="${doc.url}" poster="${posterURL}" type="${doc.mime_type}"></video>`;
|
|
||||||
});
|
|
||||||
|
|
||||||
return download.promise;
|
|
||||||
}
|
|
||||||
}); */
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.init = null;
|
this.init = null;
|
||||||
@ -797,7 +649,7 @@ class EmoticonsDropdown {
|
|||||||
animationIntersector.checkAnimations(true, EMOTICONSSTICKERGROUP);
|
animationIntersector.checkAnimations(true, EMOTICONSSTICKERGROUP);
|
||||||
|
|
||||||
this.tabID = id;
|
this.tabID = id;
|
||||||
this.searchButton.classList.toggle('hide', this.tabID != 1);
|
this.searchButton.classList.toggle('hide', this.tabID == 0);
|
||||||
this.deleteBtn.classList.toggle('hide', this.tabID != 0);
|
this.deleteBtn.classList.toggle('hide', this.tabID != 0);
|
||||||
}, () => {
|
}, () => {
|
||||||
const tab = this.tabs[this.tabID];
|
const tab = this.tabs[this.tabID];
|
||||||
@ -811,7 +663,11 @@ class EmoticonsDropdown {
|
|||||||
|
|
||||||
this.searchButton = this.element.querySelector('.emoji-tabs-search');
|
this.searchButton = this.element.querySelector('.emoji-tabs-search');
|
||||||
this.searchButton.addEventListener('click', () => {
|
this.searchButton.addEventListener('click', () => {
|
||||||
|
if(this.tabID == 1) {
|
||||||
appSidebarRight.stickersTab.init();
|
appSidebarRight.stickersTab.init();
|
||||||
|
} else {
|
||||||
|
appSidebarRight.gifsTab.init();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.deleteBtn = this.element.querySelector('.emoji-tabs-delete');
|
this.deleteBtn = this.element.querySelector('.emoji-tabs-delete');
|
||||||
|
129
src/components/gifsMasonry.ts
Normal file
129
src/components/gifsMasonry.ts
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
import { MTDocument } from "../types";
|
||||||
|
import { calcImageInBox, findUpClassName } from "../lib/utils";
|
||||||
|
import appDocsManager from "../lib/appManagers/appDocsManager";
|
||||||
|
import { wrapVideo } from "./wrappers";
|
||||||
|
import { renderImageFromUrl } from "./misc";
|
||||||
|
import LazyLoadQueue from "./lazyLoadQueue";
|
||||||
|
|
||||||
|
const width = 400;
|
||||||
|
const maxSingleWidth = width - 100;
|
||||||
|
const height = 100;
|
||||||
|
|
||||||
|
export default class GifsMasonry {
|
||||||
|
constructor(private element: HTMLElement) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public add(doc: MTDocument, group: string, lazyLoadQueue?: LazyLoadQueue) {
|
||||||
|
let gifWidth = doc.w;
|
||||||
|
let gifHeight = doc.h;
|
||||||
|
if(gifHeight < height) {
|
||||||
|
gifWidth = height / gifHeight * gifWidth;
|
||||||
|
gifHeight = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
let willUseWidth = Math.min(maxSingleWidth, width, gifWidth);
|
||||||
|
let {w, h} = calcImageInBox(gifWidth, gifHeight, willUseWidth, height);
|
||||||
|
|
||||||
|
/* wastedWidth += w;
|
||||||
|
|
||||||
|
if(wastedWidth == width || h < height) {
|
||||||
|
wastedWidth = 0;
|
||||||
|
console.log('completed line', i, line);
|
||||||
|
line = [];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
line.push(gif); */
|
||||||
|
|
||||||
|
//console.log('gif:', gif, w, h);
|
||||||
|
|
||||||
|
let div = document.createElement('div');
|
||||||
|
div.classList.add('gif', 'fade-in-transition');
|
||||||
|
div.style.width = w + 'px';
|
||||||
|
div.style.opacity = '0';
|
||||||
|
//div.style.height = h + 'px';
|
||||||
|
div.dataset.docID = doc.id;
|
||||||
|
|
||||||
|
this.element.append(div);
|
||||||
|
|
||||||
|
//let preloader = new ProgressivePreloader(div);
|
||||||
|
|
||||||
|
const posterURL = appDocsManager.getThumbURL(doc, false);
|
||||||
|
let img: HTMLImageElement;
|
||||||
|
if(posterURL) {
|
||||||
|
img = new Image();
|
||||||
|
img.src = posterURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mouseOut = false;
|
||||||
|
const onMouseOver = (/* e: MouseEvent */) => {
|
||||||
|
//console.log('onMouseOver', doc.id);
|
||||||
|
//cancelEvent(e);
|
||||||
|
mouseOut = false;
|
||||||
|
|
||||||
|
wrapVideo({
|
||||||
|
doc,
|
||||||
|
container: div,
|
||||||
|
lazyLoadQueue,
|
||||||
|
//lazyLoadQueue: EmoticonsDropdown.lazyLoadQueue,
|
||||||
|
group,
|
||||||
|
noInfo: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const video = div.querySelector('video');
|
||||||
|
video.addEventListener('canplay', () => {
|
||||||
|
div.style.opacity = '';
|
||||||
|
if(!mouseOut) {
|
||||||
|
img && img.classList.add('hide');
|
||||||
|
} else {
|
||||||
|
img && img.classList.remove('hide');
|
||||||
|
if(div.lastElementChild != img) {
|
||||||
|
div.lastElementChild.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {once: true});
|
||||||
|
};
|
||||||
|
|
||||||
|
const afterRender = () => {
|
||||||
|
if(img) {
|
||||||
|
div.append(img);
|
||||||
|
div.style.opacity = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if(lazyLoadQueue) {
|
||||||
|
onMouseOver();
|
||||||
|
} else {
|
||||||
|
div.addEventListener('mouseover', onMouseOver, {once: true});
|
||||||
|
div.addEventListener('mouseout', (e) => {
|
||||||
|
const toElement = (e as any).toElement as Element;
|
||||||
|
//console.log('onMouseOut', doc.id, e);
|
||||||
|
if(findUpClassName(toElement, 'gif') == div) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//cancelEvent(e);
|
||||||
|
|
||||||
|
mouseOut = true;
|
||||||
|
|
||||||
|
const cb = () => {
|
||||||
|
if(div.lastElementChild != img) {
|
||||||
|
div.lastElementChild.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
div.addEventListener('mouseover', onMouseOver, {once: true});
|
||||||
|
};
|
||||||
|
|
||||||
|
img && img.classList.remove('hide');
|
||||||
|
/* window.requestAnimationFrame(() => {
|
||||||
|
window.requestAnimationFrame();
|
||||||
|
}); */
|
||||||
|
if(img) window.requestAnimationFrame(() => window.requestAnimationFrame(cb));
|
||||||
|
else cb();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
(posterURL ? renderImageFromUrl(img, posterURL, afterRender) : afterRender());
|
||||||
|
}
|
||||||
|
}
|
105
src/components/sidebarRight/gifs.ts
Normal file
105
src/components/sidebarRight/gifs.ts
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
import { SliderTab } from "../slider";
|
||||||
|
import SearchInput from "../searchInput";
|
||||||
|
import Scrollable from "../scrollable_new";
|
||||||
|
import LazyLoadQueue from "../lazyLoadQueue";
|
||||||
|
import animationIntersector from "../animationIntersector";
|
||||||
|
import appSidebarRight, { AppSidebarRight } from "../../lib/appManagers/appSidebarRight";
|
||||||
|
import appUsersManager, { User } from "../../lib/appManagers/appUsersManager";
|
||||||
|
import appInlineBotsManager, { AppInlineBotsManager } from "../../lib/appManagers/AppInlineBotsManager";
|
||||||
|
import GifsMasonry from "../gifsMasonry";
|
||||||
|
|
||||||
|
const ANIMATIONGROUP = 'GIFS-SEARCH';
|
||||||
|
|
||||||
|
export default class AppGifsTab implements SliderTab {
|
||||||
|
private container = document.getElementById('search-gifs-container') as HTMLDivElement;
|
||||||
|
private contentDiv = this.container.querySelector('.sidebar-content') as HTMLDivElement;
|
||||||
|
private backBtn = this.container.querySelector('.sidebar-close-button') as HTMLButtonElement;
|
||||||
|
//private input = this.container.querySelector('#stickers-search') as HTMLInputElement;
|
||||||
|
private searchInput: SearchInput;
|
||||||
|
private gifsDiv = this.contentDiv.firstElementChild as HTMLDivElement;
|
||||||
|
private scrollable: Scrollable;
|
||||||
|
private lazyLoadQueue: LazyLoadQueue;
|
||||||
|
|
||||||
|
private nextOffset = '';
|
||||||
|
|
||||||
|
private gifBotPeerID: number;
|
||||||
|
private masonry: GifsMasonry;
|
||||||
|
|
||||||
|
private searchPromise: ReturnType<AppInlineBotsManager['getInlineResults']>;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.scrollable = new Scrollable(this.contentDiv, 'y', ANIMATIONGROUP, undefined, undefined, 2);
|
||||||
|
this.scrollable.setVirtualContainer(this.gifsDiv);
|
||||||
|
|
||||||
|
this.masonry = new GifsMasonry(this.gifsDiv);
|
||||||
|
|
||||||
|
this.lazyLoadQueue = new LazyLoadQueue();
|
||||||
|
|
||||||
|
this.searchInput = new SearchInput('Search GIFs', (value) => {
|
||||||
|
this.reset();
|
||||||
|
this.search(value);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.scrollable.onScrolledBottom = () => {
|
||||||
|
this.search(this.searchInput.value, false);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.backBtn.parentElement.append(this.searchInput.container);
|
||||||
|
}
|
||||||
|
|
||||||
|
public onCloseAfterTimeout() {
|
||||||
|
this.reset();
|
||||||
|
this.gifsDiv.innerHTML = '';
|
||||||
|
this.searchInput.value = '';
|
||||||
|
animationIntersector.checkAnimations(undefined, ANIMATIONGROUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
private reset() {
|
||||||
|
this.searchPromise = null;
|
||||||
|
this.nextOffset = '';
|
||||||
|
this.lazyLoadQueue.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public init() {
|
||||||
|
appSidebarRight.selectTab(AppSidebarRight.SLIDERITEMSIDS.gifs);
|
||||||
|
|
||||||
|
appSidebarRight.toggleSidebar(true).then(() => {
|
||||||
|
//this.renderFeatured();
|
||||||
|
this.search('', true);
|
||||||
|
this.reset();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async search(query: string, newSearch = true) {
|
||||||
|
if(this.searchPromise) return;
|
||||||
|
|
||||||
|
if(!this.gifBotPeerID) {
|
||||||
|
this.gifBotPeerID = (await appUsersManager.resolveUsername('gif')).id;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.searchPromise = appInlineBotsManager.getInlineResults(0, this.gifBotPeerID, query, this.nextOffset);
|
||||||
|
const { results, next_offset } = await this.searchPromise;
|
||||||
|
|
||||||
|
if(this.searchInput.value != query) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.searchPromise = null;
|
||||||
|
this.nextOffset = next_offset;
|
||||||
|
if(newSearch) {
|
||||||
|
this.gifsDiv.innerHTML = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
results.forEach((result) => {
|
||||||
|
if(result._ === 'botInlineMediaResult' && result.document) {
|
||||||
|
this.masonry.add(result.document, ANIMATIONGROUP, this.lazyLoadQueue);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.scrollable.onScroll();
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error(JSON.stringify(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
130
src/components/sidebarRight/pollResults.ts
Normal file
130
src/components/sidebarRight/pollResults.ts
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
import { SliderTab } from "../slider";
|
||||||
|
import Scrollable from "../scrollable_new";
|
||||||
|
import appSidebarRight, { AppSidebarRight } from "../../lib/appManagers/appSidebarRight";
|
||||||
|
import appPollsManager from "../../lib/appManagers/appPollsManager";
|
||||||
|
import { roundPercents } from "../poll";
|
||||||
|
import { RichTextProcessor } from "../../lib/richtextprocessor";
|
||||||
|
import appDialogsManager from "../../lib/appManagers/appDialogsManager";
|
||||||
|
import { ripple } from "../ripple";
|
||||||
|
|
||||||
|
export default class AppPollResultsTab implements SliderTab {
|
||||||
|
private container = document.getElementById('poll-results-container') as HTMLDivElement;
|
||||||
|
private contentDiv = this.container.querySelector('.sidebar-content') as HTMLDivElement;
|
||||||
|
private resultsDiv = this.contentDiv.firstElementChild as HTMLDivElement;
|
||||||
|
private scrollable: Scrollable;
|
||||||
|
|
||||||
|
private pollID: string;
|
||||||
|
private mid: number;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.scrollable = new Scrollable(this.contentDiv, 'y', 'POLL-RESULTS', undefined, undefined, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public cleanup() {
|
||||||
|
this.resultsDiv.innerHTML = '';
|
||||||
|
this.pollID = '';
|
||||||
|
this.mid = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public onCloseAfterTimeout() {
|
||||||
|
this.cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(pollID: string, mid: number) {
|
||||||
|
if(this.pollID == pollID && this.mid == mid) return;
|
||||||
|
|
||||||
|
this.cleanup();
|
||||||
|
|
||||||
|
this.pollID = pollID;
|
||||||
|
this.mid = mid;
|
||||||
|
|
||||||
|
appSidebarRight.selectTab(AppSidebarRight.SLIDERITEMSIDS.pollResults);
|
||||||
|
|
||||||
|
const poll = appPollsManager.getPoll(pollID);
|
||||||
|
|
||||||
|
const title = document.createElement('h3');
|
||||||
|
title.innerHTML = poll.poll.rQuestion;
|
||||||
|
|
||||||
|
const percents = poll.results.results.map(v => v.voters / poll.results.total_voters * 100);
|
||||||
|
roundPercents(percents);
|
||||||
|
|
||||||
|
const fragment = document.createDocumentFragment();
|
||||||
|
poll.results.results.forEach((result, idx) => {
|
||||||
|
if(!result.voters) return;
|
||||||
|
|
||||||
|
const hr = document.createElement('hr');
|
||||||
|
|
||||||
|
const answer = poll.poll.answers[idx];
|
||||||
|
|
||||||
|
// Head
|
||||||
|
const answerEl = document.createElement('div');
|
||||||
|
answerEl.classList.add('poll-results-answer');
|
||||||
|
|
||||||
|
const answerTitle = document.createElement('div');
|
||||||
|
answerTitle.innerHTML = RichTextProcessor.wrapEmojiText(answer.text);
|
||||||
|
|
||||||
|
const answerPercents = document.createElement('div');
|
||||||
|
answerPercents.innerText = Math.round(percents[idx]) + '%';
|
||||||
|
|
||||||
|
answerEl.append(answerTitle, answerPercents);
|
||||||
|
|
||||||
|
// Humans
|
||||||
|
const list = document.createElement('ul');
|
||||||
|
list.classList.add('poll-results-voters');
|
||||||
|
|
||||||
|
appDialogsManager.setListClickListener(list);
|
||||||
|
|
||||||
|
list.style.minHeight = Math.min(result.voters, 4) * 50 + 'px';
|
||||||
|
|
||||||
|
fragment.append(hr, answerEl, list);
|
||||||
|
|
||||||
|
let offset: string, limit = 4, loading = false, left = result.voters - 4;
|
||||||
|
const load = () => {
|
||||||
|
if(loading) return;
|
||||||
|
loading = true;
|
||||||
|
|
||||||
|
appPollsManager.getVotes(mid, answer.option, offset, limit).then(votesList => {
|
||||||
|
votesList.votes.forEach(vote => {
|
||||||
|
const {dom} = appDialogsManager.addDialog(vote.user_id, list, false, false, undefined, false);
|
||||||
|
dom.lastMessageSpan.parentElement.remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
if(offset) {
|
||||||
|
left -= votesList.votes.length;
|
||||||
|
(showMore.lastElementChild as HTMLElement).innerText = `Show ${Math.min(20, left)} more voter${left > 1 ? 's' : ''}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = votesList.next_offset;
|
||||||
|
limit = 20;
|
||||||
|
|
||||||
|
if(!left || !votesList.votes.length) {
|
||||||
|
showMore.remove();
|
||||||
|
}
|
||||||
|
}).finally(() => {
|
||||||
|
loading = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
load();
|
||||||
|
|
||||||
|
if(left <= 0) return;
|
||||||
|
|
||||||
|
const showMore = document.createElement('div');
|
||||||
|
showMore.classList.add('poll-results-more', 'show-more');
|
||||||
|
showMore.addEventListener('click', load);
|
||||||
|
|
||||||
|
showMore.innerHTML = `<div class="tgico-down"></div><div>Show ${Math.min(20, left)} more voter${left > 1 ? 's' : ''}</div>`;
|
||||||
|
ripple(showMore);
|
||||||
|
|
||||||
|
fragment.append(showMore);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.resultsDiv.append(title, fragment);
|
||||||
|
|
||||||
|
appSidebarRight.toggleSidebar(true).then(() => {
|
||||||
|
/* appPollsManager.getVotes(mid).then(votes => {
|
||||||
|
console.log('gOt VotEs', votes);
|
||||||
|
}); */
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
235
src/components/sidebarRight/stickers.ts
Normal file
235
src/components/sidebarRight/stickers.ts
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
import { SliderTab } from "../slider";
|
||||||
|
import SearchInput from "../searchInput";
|
||||||
|
import Scrollable from "../scrollable_new";
|
||||||
|
import LazyLoadQueue from "../lazyLoadQueue";
|
||||||
|
import { findUpClassName } from "../../lib/utils";
|
||||||
|
import appImManager from "../../lib/appManagers/appImManager";
|
||||||
|
import appStickersManager, { MTStickerSet, MTStickerSetCovered, MTStickerSetMultiCovered } from "../../lib/appManagers/appStickersManager";
|
||||||
|
import PopupStickers from "../popupStickers";
|
||||||
|
import animationIntersector from "../animationIntersector";
|
||||||
|
import { RichTextProcessor } from "../../lib/richtextprocessor";
|
||||||
|
import { wrapSticker } from "../wrappers";
|
||||||
|
import appSidebarRight, { AppSidebarRight } from "../../lib/appManagers/appSidebarRight";
|
||||||
|
|
||||||
|
export default class AppStickersTab implements SliderTab {
|
||||||
|
private container = document.getElementById('stickers-container') as HTMLDivElement;
|
||||||
|
private contentDiv = this.container.querySelector('.sidebar-content') as HTMLDivElement;
|
||||||
|
private backBtn = this.container.querySelector('.sidebar-close-button') as HTMLButtonElement;
|
||||||
|
//private input = this.container.querySelector('#stickers-search') as HTMLInputElement;
|
||||||
|
private searchInput: SearchInput;
|
||||||
|
private setsDiv = this.contentDiv.firstElementChild as HTMLDivElement;
|
||||||
|
private scrollable: Scrollable;
|
||||||
|
private lazyLoadQueue: LazyLoadQueue;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.scrollable = new Scrollable(this.contentDiv, 'y', 'STICKERS-SEARCH', undefined, undefined, 2);
|
||||||
|
this.scrollable.setVirtualContainer(this.setsDiv);
|
||||||
|
|
||||||
|
this.lazyLoadQueue = new LazyLoadQueue();
|
||||||
|
|
||||||
|
this.searchInput = new SearchInput('Search Stickers', (value) => {
|
||||||
|
this.search(value);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.backBtn.parentElement.append(this.searchInput.container);
|
||||||
|
|
||||||
|
this.setsDiv.addEventListener('click', (e) => {
|
||||||
|
const sticker = findUpClassName(e.target, 'sticker-set-sticker');
|
||||||
|
if(sticker) {
|
||||||
|
const docID = sticker.dataset.docID;
|
||||||
|
appImManager.chatInputC.sendMessageWithDocument(docID);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const target = findUpClassName(e.target, 'sticker-set');
|
||||||
|
if(!target) return;
|
||||||
|
|
||||||
|
|
||||||
|
const id = target.dataset.stickerSet as string;
|
||||||
|
const access_hash = target.dataset.stickerSet as string;
|
||||||
|
|
||||||
|
const button = findUpClassName(e.target, 'sticker-set-button') as HTMLElement;
|
||||||
|
if(button) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.cancelBubble = true;
|
||||||
|
|
||||||
|
button.setAttribute('disabled', 'true');
|
||||||
|
|
||||||
|
appStickersManager.getStickerSet({id, access_hash}).then(full => {
|
||||||
|
appStickersManager.toggleStickerSet(full.set).then(changed => {
|
||||||
|
if(changed) {
|
||||||
|
button.innerText = full.set.installed_date ? 'Added' : 'Add';
|
||||||
|
button.classList.toggle('gray', !!full.set.installed_date);
|
||||||
|
}
|
||||||
|
}).finally(() => {
|
||||||
|
//button.style.width = set.installed_date ? '68px' : '52px';
|
||||||
|
button.removeAttribute('disabled');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
appStickersManager.getStickerSet({id, access_hash}).then(full => {
|
||||||
|
new PopupStickers(full.set).show();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public onCloseAfterTimeout() {
|
||||||
|
this.setsDiv.innerHTML = '';
|
||||||
|
this.searchInput.value = '';
|
||||||
|
animationIntersector.checkAnimations(undefined, 'STICKERS-SEARCH');
|
||||||
|
}
|
||||||
|
|
||||||
|
public renderSet(set: MTStickerSet) {
|
||||||
|
//console.log('renderSet:', set);
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.classList.add('sticker-set');
|
||||||
|
|
||||||
|
const header = document.createElement('div');
|
||||||
|
header.classList.add('sticker-set-header');
|
||||||
|
|
||||||
|
const details = document.createElement('div');
|
||||||
|
details.classList.add('sticker-set-details');
|
||||||
|
details.innerHTML = `
|
||||||
|
<div class="sticker-set-name">${RichTextProcessor.wrapEmojiText(set.title)}</div>
|
||||||
|
<div class="sticker-set-count">${set.count} stickers</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
const button = document.createElement('button');
|
||||||
|
button.classList.add('btn-primary', 'sticker-set-button');
|
||||||
|
button.innerText = set.installed_date ? 'Added' : 'Add';
|
||||||
|
// button.style.width = set.installed_date ? '68px' : '52px';
|
||||||
|
|
||||||
|
if(set.installed_date) {
|
||||||
|
button.classList.add('gray');
|
||||||
|
}
|
||||||
|
|
||||||
|
//ripple(button);
|
||||||
|
|
||||||
|
header.append(details, button);
|
||||||
|
|
||||||
|
const stickersDiv = document.createElement('div');
|
||||||
|
stickersDiv.classList.add('sticker-set-stickers');
|
||||||
|
|
||||||
|
const count = Math.min(5, set.count);
|
||||||
|
for(let i = 0; i < count; ++i) {
|
||||||
|
const stickerDiv = document.createElement('div');
|
||||||
|
stickerDiv.classList.add('sticker-set-sticker');
|
||||||
|
|
||||||
|
stickersDiv.append(stickerDiv);
|
||||||
|
}
|
||||||
|
|
||||||
|
appStickersManager.getStickerSet(set).then(set => {
|
||||||
|
//console.log('renderSet got set:', set);
|
||||||
|
|
||||||
|
for(let i = 0; i < count; ++i) {
|
||||||
|
const div = stickersDiv.children[i] as HTMLDivElement;
|
||||||
|
wrapSticker({
|
||||||
|
doc: set.documents[i],
|
||||||
|
div,
|
||||||
|
lazyLoadQueue: this.lazyLoadQueue,
|
||||||
|
group: 'STICKERS-SEARCH',
|
||||||
|
/* play: false,
|
||||||
|
loop: false, */
|
||||||
|
play: true,
|
||||||
|
loop: true,
|
||||||
|
width: 68,
|
||||||
|
height: 68
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/* const onMouseOver = () => {
|
||||||
|
const animations: AnimationItem['animation'][] = [];
|
||||||
|
for(let i = 0; i < count; ++i) {
|
||||||
|
const stickerDiv = stickersDiv.children[i] as HTMLElement;
|
||||||
|
const animationItem = animationIntersector.getAnimation(stickerDiv);
|
||||||
|
if(!animationItem) continue;
|
||||||
|
|
||||||
|
const animation = animationItem.animation;
|
||||||
|
|
||||||
|
animations.push(animation);
|
||||||
|
animation.loop = true;
|
||||||
|
animation.play();
|
||||||
|
}
|
||||||
|
|
||||||
|
div.addEventListener('mouseout', () => {
|
||||||
|
animations.forEach(animation => {
|
||||||
|
animation.loop = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
div.addEventListener('mouseover', onMouseOver, {once: true});
|
||||||
|
}, {once: true});
|
||||||
|
};
|
||||||
|
|
||||||
|
div.addEventListener('mouseover', onMouseOver, {once: true}); */
|
||||||
|
|
||||||
|
div.dataset.stickerSet = set.id;
|
||||||
|
div.dataset.access_hash = set.access_hash;
|
||||||
|
div.dataset.title = set.title;
|
||||||
|
|
||||||
|
div.append(header, stickersDiv);
|
||||||
|
|
||||||
|
this.scrollable.append(div);
|
||||||
|
}
|
||||||
|
|
||||||
|
public init() {
|
||||||
|
appSidebarRight.selectTab(AppSidebarRight.SLIDERITEMSIDS.stickers);
|
||||||
|
|
||||||
|
appSidebarRight.toggleSidebar(true).then(() => {
|
||||||
|
this.renderFeatured();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public renderFeatured() {
|
||||||
|
return appStickersManager.getFeaturedStickers().then(coveredSets => {
|
||||||
|
if(this.searchInput.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
coveredSets = this.filterRendered('', coveredSets);
|
||||||
|
coveredSets.forEach(set => {
|
||||||
|
this.renderSet(set.set);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private filterRendered(query: string, coveredSets: (MTStickerSetCovered | MTStickerSetMultiCovered)[]) {
|
||||||
|
coveredSets = coveredSets.slice();
|
||||||
|
|
||||||
|
const children = Array.from(this.setsDiv.children) as HTMLElement[];
|
||||||
|
children.forEachReverse(el => {
|
||||||
|
const id = el.dataset.stickerSet;
|
||||||
|
const index = coveredSets.findIndex(covered => covered.set.id == id);
|
||||||
|
|
||||||
|
if(index !== -1) {
|
||||||
|
coveredSets.splice(index, 1);
|
||||||
|
} else if(!query || !el.dataset.title.toLowerCase().includes(query.toLowerCase())) {
|
||||||
|
el.remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
animationIntersector.checkAnimations(undefined, 'STICKERS-SEARCH');
|
||||||
|
|
||||||
|
return coveredSets;
|
||||||
|
}
|
||||||
|
|
||||||
|
public search(query: string) {
|
||||||
|
if(!query) {
|
||||||
|
return this.renderFeatured();
|
||||||
|
}
|
||||||
|
|
||||||
|
return appStickersManager.searchStickerSets(query, false).then(coveredSets => {
|
||||||
|
if(this.searchInput.value != query) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//console.log('search result:', coveredSets);
|
||||||
|
|
||||||
|
coveredSets = this.filterRendered(query, coveredSets);
|
||||||
|
coveredSets.forEach(set => {
|
||||||
|
this.renderSet(set.set);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -446,7 +446,7 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if(thumb.bytes) {
|
if(thumb.bytes || thumb.url) {
|
||||||
img = new Image();
|
img = new Image();
|
||||||
|
|
||||||
if((!isSafari || doc.stickerThumbConverted)/* && false */) {
|
if((!isSafari || doc.stickerThumbConverted)/* && false */) {
|
||||||
|
@ -672,6 +672,12 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="sidebar-content"><div class="poll-results"></div></div>
|
<div class="sidebar-content"><div class="poll-results"></div></div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="sidebar-slider-item sidebar-search chats-container" id="search-gifs-container">
|
||||||
|
<div class="sidebar-header">
|
||||||
|
<button class="btn-icon rp tgico-close sidebar-close-button"></button>
|
||||||
|
</div>
|
||||||
|
<div class="sidebar-content"><div class="gifs-masonry"></div></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -4,11 +4,99 @@ import appPeersManager from "../appManagers/appPeersManager";
|
|||||||
import appMessagesIDsManager from "./appMessagesIDsManager";
|
import appMessagesIDsManager from "./appMessagesIDsManager";
|
||||||
import { RichTextProcessor } from "../richtextprocessor";
|
import { RichTextProcessor } from "../richtextprocessor";
|
||||||
import { toast } from "../../components/toast";
|
import { toast } from "../../components/toast";
|
||||||
|
import appUsersManager, { User } from "./appUsersManager";
|
||||||
|
import appPhotosManager, { MTPhoto } from "./appPhotosManager";
|
||||||
|
import { MTDocument } from "../../types";
|
||||||
|
import appDocsManager from "./appDocsManager";
|
||||||
|
|
||||||
|
type botInlineResult = {
|
||||||
|
_: 'botInlineResult',
|
||||||
|
flags: number,
|
||||||
|
id: string,
|
||||||
|
type: string,
|
||||||
|
title?: string,
|
||||||
|
description?: string,
|
||||||
|
url?: string,
|
||||||
|
thumb: any,
|
||||||
|
content: any,
|
||||||
|
send_message: any
|
||||||
|
};
|
||||||
|
type botInlineMediaResult = {
|
||||||
|
_: 'botInlineMediaResult',
|
||||||
|
flags: number,
|
||||||
|
id: string,
|
||||||
|
type: string,
|
||||||
|
photo?: MTPhoto,
|
||||||
|
document?: MTDocument,
|
||||||
|
title?: string,
|
||||||
|
description?: string,
|
||||||
|
send_message: any
|
||||||
|
};
|
||||||
|
type BotInlineResult = (botInlineResult | botInlineMediaResult) & Partial<{
|
||||||
|
qID: string,
|
||||||
|
botID: number,
|
||||||
|
rTitle: string,
|
||||||
|
rDescription: string,
|
||||||
|
initials: string
|
||||||
|
}>;
|
||||||
|
|
||||||
export class AppInlineBotsManager {
|
export class AppInlineBotsManager {
|
||||||
/* private inlineResults: any = {};
|
private inlineResults: {[qID: string]: BotInlineResult} = {};
|
||||||
|
|
||||||
function getPopularBots () {
|
public getInlineResults(peerID: number, botID: number, query = '', offset = '', geo?: any) {
|
||||||
|
return apiManagerProxy.invokeApi('messages.getInlineBotResults', {
|
||||||
|
flags: 0 | (geo ? 1 : 0),
|
||||||
|
bot: appUsersManager.getUserInput(botID),
|
||||||
|
peer: appPeersManager.getInputPeerByID(peerID),
|
||||||
|
query: query,
|
||||||
|
geo_point: geo && {_: 'inputGeoPoint', lat: geo['lat'], long: geo['long']},
|
||||||
|
offset
|
||||||
|
}, {timeout: 1, stopTime: -1, noErrorBox: true}).then((botResults: {
|
||||||
|
_: 'messages.botResults',
|
||||||
|
flags: number,
|
||||||
|
pFlags: Partial<{gallery: true}>,
|
||||||
|
query_id: string,
|
||||||
|
next_offset?: string,
|
||||||
|
switch_pm?: any,
|
||||||
|
results: BotInlineResult[],
|
||||||
|
cache_time: number,
|
||||||
|
users: User[]
|
||||||
|
}) => {
|
||||||
|
const queryID = botResults.query_id;
|
||||||
|
/* delete botResults._;
|
||||||
|
delete botResults.flags;
|
||||||
|
delete botResults.query_id; */
|
||||||
|
|
||||||
|
if(botResults.switch_pm) {
|
||||||
|
botResults.switch_pm.rText = RichTextProcessor.wrapRichText(botResults.switch_pm.text, {noLinebreaks: true, noLinks: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
botResults.results.forEach((result: BotInlineResult) => {
|
||||||
|
const qID = queryID + '_' + result.id;
|
||||||
|
result.qID = qID;
|
||||||
|
result.botID = botID;
|
||||||
|
|
||||||
|
result.rTitle = RichTextProcessor.wrapRichText(result.title, {noLinebreaks: true, noLinks: true});
|
||||||
|
result.rDescription = RichTextProcessor.wrapRichText(result.description, {noLinebreaks: true, noLinks: true});
|
||||||
|
result.initials = ((result as botInlineResult).url || result.title || result.type || '').substr(0, 1);
|
||||||
|
|
||||||
|
if(result._ == 'botInlineMediaResult') {
|
||||||
|
if(result.document) {
|
||||||
|
result.document = appDocsManager.saveDoc(result.document);
|
||||||
|
}
|
||||||
|
if(result.photo) {
|
||||||
|
result.photo = appPhotosManager.savePhoto(result.photo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.inlineResults[qID] = result;
|
||||||
|
});
|
||||||
|
|
||||||
|
return botResults;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* function getPopularBots () {
|
||||||
return Storage.get('inline_bots_popular').then(function (bots) {
|
return Storage.get('inline_bots_popular').then(function (bots) {
|
||||||
var result = []
|
var result = []
|
||||||
var i, len
|
var i, len
|
||||||
@ -91,46 +179,6 @@ export class AppInlineBotsManager {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function getInlineResults (peerID, botID, query, geo, offset) {
|
|
||||||
return MtpApiManager.invokeApi('messages.getInlineBotResults', {
|
|
||||||
flags: 0 | (geo ? 1 : 0),
|
|
||||||
bot: AppUsersManager.getUserInput(botID),
|
|
||||||
peer: AppPeersManager.getInputPeerByID(peerID),
|
|
||||||
query: query,
|
|
||||||
geo_point: geo && {_: 'inputGeoPoint', lat: geo['lat'], long: geo['long']},
|
|
||||||
offset: offset
|
|
||||||
}, {timeout: 1, stopTime: -1, noErrorBox: true}).then(function (botResults) {
|
|
||||||
var queryID = botResults.query_id
|
|
||||||
delete botResults._
|
|
||||||
delete botResults.flags
|
|
||||||
delete botResults.query_id
|
|
||||||
|
|
||||||
if (botResults.switch_pm) {
|
|
||||||
botResults.switch_pm.rText = RichTextProcessor.wrapRichText(botResults.switch_pm.text, {noLinebreaks: true, noLinks: true})
|
|
||||||
}
|
|
||||||
|
|
||||||
angular.forEach(botResults.results, function (result) {
|
|
||||||
var qID = queryID + '_' + result.id
|
|
||||||
result.qID = qID
|
|
||||||
result.botID = botID
|
|
||||||
|
|
||||||
result.rTitle = RichTextProcessor.wrapRichText(result.title, {noLinebreaks: true, noLinks: true})
|
|
||||||
result.rDescription = RichTextProcessor.wrapRichText(result.description, {noLinebreaks: true, noLinks: true})
|
|
||||||
result.initials = (result.url || result.title || result.type || '').substr(0, 1)
|
|
||||||
|
|
||||||
if (result.document) {
|
|
||||||
AppDocsManager.saveDoc(result.document)
|
|
||||||
}
|
|
||||||
if (result.photo) {
|
|
||||||
AppPhotosManager.savePhoto(result.photo)
|
|
||||||
}
|
|
||||||
|
|
||||||
inlineResults[qID] = result
|
|
||||||
})
|
|
||||||
return botResults
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function regroupWrappedResults (results, rowW, rowH) {
|
function regroupWrappedResults (results, rowW, rowH) {
|
||||||
if (!results ||
|
if (!results ||
|
||||||
!results[0] ||
|
!results[0] ||
|
||||||
|
@ -18,15 +18,11 @@ import AvatarElement from "../../components/avatar";
|
|||||||
import appForward from "../../components/appForward";
|
import appForward from "../../components/appForward";
|
||||||
import { mediaSizes } from "../config";
|
import { mediaSizes } from "../config";
|
||||||
import SidebarSlider, { SliderTab } from "../../components/slider";
|
import SidebarSlider, { SliderTab } from "../../components/slider";
|
||||||
import appStickersManager, { MTStickerSet, MTStickerSetCovered, MTStickerSetMultiCovered } from "./appStickersManager";
|
|
||||||
import animationIntersector from "../../components/animationIntersector";
|
|
||||||
import PopupStickers from "../../components/popupStickers";
|
|
||||||
import SearchInput from "../../components/searchInput";
|
import SearchInput from "../../components/searchInput";
|
||||||
import appPollsManager from "./appPollsManager";
|
|
||||||
import { roundPercents } from "../../components/poll";
|
|
||||||
import appDialogsManager from "./appDialogsManager";
|
|
||||||
import { ripple } from "../../components/ripple";
|
|
||||||
import { horizontalMenu } from "../../components/horizontalMenu";
|
import { horizontalMenu } from "../../components/horizontalMenu";
|
||||||
|
import AppStickersTab from "../../components/sidebarRight/stickers";
|
||||||
|
import AppPollResultsTab from "../../components/sidebarRight/pollResults";
|
||||||
|
import AppGifsTab from "../../components/sidebarRight/gifs";
|
||||||
|
|
||||||
const testScroll = false;
|
const testScroll = false;
|
||||||
|
|
||||||
@ -44,353 +40,9 @@ let setText = (text: string, el: HTMLDivElement) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
class AppStickersTab implements SliderTab {
|
|
||||||
private container = document.getElementById('stickers-container') as HTMLDivElement;
|
|
||||||
private contentDiv = this.container.querySelector('.sidebar-content') as HTMLDivElement;
|
|
||||||
private backBtn = this.container.querySelector('.sidebar-close-button') as HTMLButtonElement;
|
|
||||||
//private input = this.container.querySelector('#stickers-search') as HTMLInputElement;
|
|
||||||
private searchInput: SearchInput;
|
|
||||||
private setsDiv = this.contentDiv.firstElementChild as HTMLDivElement;
|
|
||||||
private scrollable: Scrollable;
|
|
||||||
private lazyLoadQueue: LazyLoadQueue;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.scrollable = new Scrollable(this.contentDiv, 'y', 'STICKERS-SEARCH', undefined, undefined, 2);
|
|
||||||
this.scrollable.setVirtualContainer(this.setsDiv);
|
|
||||||
|
|
||||||
this.lazyLoadQueue = new LazyLoadQueue();
|
|
||||||
|
|
||||||
this.searchInput = new SearchInput('Search Stickers', (value) => {
|
|
||||||
this.search(value);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.backBtn.parentElement.append(this.searchInput.container);
|
|
||||||
|
|
||||||
this.setsDiv.addEventListener('click', (e) => {
|
|
||||||
const sticker = findUpClassName(e.target, 'sticker-set-sticker');
|
|
||||||
if(sticker) {
|
|
||||||
const docID = sticker.dataset.docID;
|
|
||||||
appImManager.chatInputC.sendMessageWithDocument(docID);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const target = findUpClassName(e.target, 'sticker-set');
|
|
||||||
if(!target) return;
|
|
||||||
|
|
||||||
|
|
||||||
const id = target.dataset.stickerSet as string;
|
|
||||||
const access_hash = target.dataset.stickerSet as string;
|
|
||||||
|
|
||||||
const button = findUpClassName(e.target, 'sticker-set-button') as HTMLElement;
|
|
||||||
if(button) {
|
|
||||||
e.preventDefault();
|
|
||||||
e.cancelBubble = true;
|
|
||||||
|
|
||||||
button.setAttribute('disabled', 'true');
|
|
||||||
|
|
||||||
appStickersManager.getStickerSet({id, access_hash}).then(full => {
|
|
||||||
appStickersManager.toggleStickerSet(full.set).then(changed => {
|
|
||||||
if(changed) {
|
|
||||||
button.innerText = full.set.installed_date ? 'Added' : 'Add';
|
|
||||||
button.classList.toggle('gray', !!full.set.installed_date);
|
|
||||||
}
|
|
||||||
}).finally(() => {
|
|
||||||
//button.style.width = set.installed_date ? '68px' : '52px';
|
|
||||||
button.removeAttribute('disabled');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
appStickersManager.getStickerSet({id, access_hash}).then(full => {
|
|
||||||
new PopupStickers(full.set).show();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public onCloseAfterTimeout() {
|
|
||||||
this.setsDiv.innerHTML = '';
|
|
||||||
this.searchInput.value = '';
|
|
||||||
animationIntersector.checkAnimations(undefined, 'STICKERS-SEARCH');
|
|
||||||
}
|
|
||||||
|
|
||||||
public renderSet(set: MTStickerSet) {
|
|
||||||
//console.log('renderSet:', set);
|
|
||||||
const div = document.createElement('div');
|
|
||||||
div.classList.add('sticker-set');
|
|
||||||
|
|
||||||
const header = document.createElement('div');
|
|
||||||
header.classList.add('sticker-set-header');
|
|
||||||
|
|
||||||
const details = document.createElement('div');
|
|
||||||
details.classList.add('sticker-set-details');
|
|
||||||
details.innerHTML = `
|
|
||||||
<div class="sticker-set-name">${RichTextProcessor.wrapEmojiText(set.title)}</div>
|
|
||||||
<div class="sticker-set-count">${set.count} stickers</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
const button = document.createElement('button');
|
|
||||||
button.classList.add('btn-primary', 'sticker-set-button');
|
|
||||||
button.innerText = set.installed_date ? 'Added' : 'Add';
|
|
||||||
// button.style.width = set.installed_date ? '68px' : '52px';
|
|
||||||
|
|
||||||
if(set.installed_date) {
|
|
||||||
button.classList.add('gray');
|
|
||||||
}
|
|
||||||
|
|
||||||
//ripple(button);
|
|
||||||
|
|
||||||
header.append(details, button);
|
|
||||||
|
|
||||||
const stickersDiv = document.createElement('div');
|
|
||||||
stickersDiv.classList.add('sticker-set-stickers');
|
|
||||||
|
|
||||||
const count = Math.min(5, set.count);
|
|
||||||
for(let i = 0; i < count; ++i) {
|
|
||||||
const stickerDiv = document.createElement('div');
|
|
||||||
stickerDiv.classList.add('sticker-set-sticker');
|
|
||||||
|
|
||||||
stickersDiv.append(stickerDiv);
|
|
||||||
}
|
|
||||||
|
|
||||||
appStickersManager.getStickerSet(set).then(set => {
|
|
||||||
//console.log('renderSet got set:', set);
|
|
||||||
|
|
||||||
for(let i = 0; i < count; ++i) {
|
|
||||||
const div = stickersDiv.children[i] as HTMLDivElement;
|
|
||||||
wrapSticker({
|
|
||||||
doc: set.documents[i],
|
|
||||||
div,
|
|
||||||
lazyLoadQueue: this.lazyLoadQueue,
|
|
||||||
group: 'STICKERS-SEARCH',
|
|
||||||
/* play: false,
|
|
||||||
loop: false, */
|
|
||||||
play: true,
|
|
||||||
loop: true,
|
|
||||||
width: 68,
|
|
||||||
height: 68
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/* const onMouseOver = () => {
|
|
||||||
const animations: AnimationItem['animation'][] = [];
|
|
||||||
for(let i = 0; i < count; ++i) {
|
|
||||||
const stickerDiv = stickersDiv.children[i] as HTMLElement;
|
|
||||||
const animationItem = animationIntersector.getAnimation(stickerDiv);
|
|
||||||
if(!animationItem) continue;
|
|
||||||
|
|
||||||
const animation = animationItem.animation;
|
|
||||||
|
|
||||||
animations.push(animation);
|
|
||||||
animation.loop = true;
|
|
||||||
animation.play();
|
|
||||||
}
|
|
||||||
|
|
||||||
div.addEventListener('mouseout', () => {
|
|
||||||
animations.forEach(animation => {
|
|
||||||
animation.loop = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
div.addEventListener('mouseover', onMouseOver, {once: true});
|
|
||||||
}, {once: true});
|
|
||||||
};
|
|
||||||
|
|
||||||
div.addEventListener('mouseover', onMouseOver, {once: true}); */
|
|
||||||
|
|
||||||
div.dataset.stickerSet = set.id;
|
|
||||||
div.dataset.access_hash = set.access_hash;
|
|
||||||
div.dataset.title = set.title;
|
|
||||||
|
|
||||||
div.append(header, stickersDiv);
|
|
||||||
|
|
||||||
this.scrollable.append(div);
|
|
||||||
}
|
|
||||||
|
|
||||||
public init() {
|
|
||||||
appSidebarRight.selectTab(AppSidebarRight.SLIDERITEMSIDS.stickers);
|
|
||||||
|
|
||||||
appSidebarRight.toggleSidebar(true).then(() => {
|
|
||||||
this.renderFeatured();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public renderFeatured() {
|
|
||||||
return appStickersManager.getFeaturedStickers().then(coveredSets => {
|
|
||||||
if(this.searchInput.value) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
coveredSets = this.filterRendered('', coveredSets);
|
|
||||||
coveredSets.forEach(set => {
|
|
||||||
this.renderSet(set.set);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private filterRendered(query: string, coveredSets: (MTStickerSetCovered | MTStickerSetMultiCovered)[]) {
|
|
||||||
coveredSets = coveredSets.slice();
|
|
||||||
|
|
||||||
const children = Array.from(this.setsDiv.children) as HTMLElement[];
|
|
||||||
children.forEachReverse(el => {
|
|
||||||
const id = el.dataset.stickerSet;
|
|
||||||
const index = coveredSets.findIndex(covered => covered.set.id == id);
|
|
||||||
|
|
||||||
if(index !== -1) {
|
|
||||||
coveredSets.splice(index, 1);
|
|
||||||
} else if(!query || !el.dataset.title.toLowerCase().includes(query.toLowerCase())) {
|
|
||||||
el.remove();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
animationIntersector.checkAnimations(undefined, 'STICKERS-SEARCH');
|
|
||||||
|
|
||||||
return coveredSets;
|
|
||||||
}
|
|
||||||
|
|
||||||
public search(query: string) {
|
|
||||||
if(!query) {
|
|
||||||
return this.renderFeatured();
|
|
||||||
}
|
|
||||||
|
|
||||||
return appStickersManager.searchStickerSets(query, false).then(coveredSets => {
|
|
||||||
if(this.searchInput.value != query) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//console.log('search result:', coveredSets);
|
|
||||||
|
|
||||||
coveredSets = this.filterRendered(query, coveredSets);
|
|
||||||
coveredSets.forEach(set => {
|
|
||||||
this.renderSet(set.set);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class AppPollResultsTab implements SliderTab {
|
|
||||||
private container = document.getElementById('poll-results-container') as HTMLDivElement;
|
|
||||||
private contentDiv = this.container.querySelector('.sidebar-content') as HTMLDivElement;
|
|
||||||
private resultsDiv = this.contentDiv.firstElementChild as HTMLDivElement;
|
|
||||||
private scrollable: Scrollable;
|
|
||||||
|
|
||||||
private pollID: string;
|
|
||||||
private mid: number;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.scrollable = new Scrollable(this.contentDiv, 'y', 'POLL-RESULTS', undefined, undefined, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public cleanup() {
|
|
||||||
this.resultsDiv.innerHTML = '';
|
|
||||||
this.pollID = '';
|
|
||||||
this.mid = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public onCloseAfterTimeout() {
|
|
||||||
this.cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
public init(pollID: string, mid: number) {
|
|
||||||
if(this.pollID == pollID && this.mid == mid) return;
|
|
||||||
|
|
||||||
this.cleanup();
|
|
||||||
|
|
||||||
this.pollID = pollID;
|
|
||||||
this.mid = mid;
|
|
||||||
|
|
||||||
appSidebarRight.selectTab(AppSidebarRight.SLIDERITEMSIDS.pollResults);
|
|
||||||
|
|
||||||
const poll = appPollsManager.getPoll(pollID);
|
|
||||||
|
|
||||||
const title = document.createElement('h3');
|
|
||||||
title.innerHTML = poll.poll.rQuestion;
|
|
||||||
|
|
||||||
const percents = poll.results.results.map(v => v.voters / poll.results.total_voters * 100);
|
|
||||||
roundPercents(percents);
|
|
||||||
|
|
||||||
const fragment = document.createDocumentFragment();
|
|
||||||
poll.results.results.forEach((result, idx) => {
|
|
||||||
if(!result.voters) return;
|
|
||||||
|
|
||||||
const hr = document.createElement('hr');
|
|
||||||
|
|
||||||
const answer = poll.poll.answers[idx];
|
|
||||||
|
|
||||||
// Head
|
|
||||||
const answerEl = document.createElement('div');
|
|
||||||
answerEl.classList.add('poll-results-answer');
|
|
||||||
|
|
||||||
const answerTitle = document.createElement('div');
|
|
||||||
answerTitle.innerHTML = RichTextProcessor.wrapEmojiText(answer.text);
|
|
||||||
|
|
||||||
const answerPercents = document.createElement('div');
|
|
||||||
answerPercents.innerText = Math.round(percents[idx]) + '%';
|
|
||||||
|
|
||||||
answerEl.append(answerTitle, answerPercents);
|
|
||||||
|
|
||||||
// Humans
|
|
||||||
const list = document.createElement('ul');
|
|
||||||
list.classList.add('poll-results-voters');
|
|
||||||
|
|
||||||
appDialogsManager.setListClickListener(list);
|
|
||||||
|
|
||||||
list.style.minHeight = Math.min(result.voters, 4) * 50 + 'px';
|
|
||||||
|
|
||||||
fragment.append(hr, answerEl, list);
|
|
||||||
|
|
||||||
let offset: string, limit = 4, loading = false, left = result.voters - 4;
|
|
||||||
const load = () => {
|
|
||||||
if(loading) return;
|
|
||||||
loading = true;
|
|
||||||
|
|
||||||
appPollsManager.getVotes(mid, answer.option, offset, limit).then(votesList => {
|
|
||||||
votesList.votes.forEach(vote => {
|
|
||||||
const {dom} = appDialogsManager.addDialog(vote.user_id, list, false, false, undefined, false);
|
|
||||||
dom.lastMessageSpan.parentElement.remove();
|
|
||||||
});
|
|
||||||
|
|
||||||
if(offset) {
|
|
||||||
left -= votesList.votes.length;
|
|
||||||
(showMore.lastElementChild as HTMLElement).innerText = `Show ${Math.min(20, left)} more voter${left > 1 ? 's' : ''}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset = votesList.next_offset;
|
|
||||||
limit = 20;
|
|
||||||
|
|
||||||
if(!left || !votesList.votes.length) {
|
|
||||||
showMore.remove();
|
|
||||||
}
|
|
||||||
}).finally(() => {
|
|
||||||
loading = false;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
load();
|
|
||||||
|
|
||||||
if(left <= 0) return;
|
|
||||||
|
|
||||||
const showMore = document.createElement('div');
|
|
||||||
showMore.classList.add('poll-results-more', 'show-more');
|
|
||||||
showMore.addEventListener('click', load);
|
|
||||||
|
|
||||||
showMore.innerHTML = `<div class="tgico-down"></div><div>Show ${Math.min(20, left)} more voter${left > 1 ? 's' : ''}</div>`;
|
|
||||||
ripple(showMore);
|
|
||||||
|
|
||||||
fragment.append(showMore);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.resultsDiv.append(title, fragment);
|
|
||||||
|
|
||||||
appSidebarRight.toggleSidebar(true).then(() => {
|
|
||||||
/* appPollsManager.getVotes(mid).then(votes => {
|
|
||||||
console.log('gOt VotEs', votes);
|
|
||||||
}); */
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const stickersTab = new AppStickersTab();
|
const stickersTab = new AppStickersTab();
|
||||||
const pollResultsTab = new AppPollResultsTab();
|
const pollResultsTab = new AppPollResultsTab();
|
||||||
|
const gifsTab = new AppGifsTab();
|
||||||
|
|
||||||
export class AppSidebarRight extends SidebarSlider {
|
export class AppSidebarRight extends SidebarSlider {
|
||||||
public static SLIDERITEMSIDS = {
|
public static SLIDERITEMSIDS = {
|
||||||
@ -398,6 +50,7 @@ export class AppSidebarRight extends SidebarSlider {
|
|||||||
forward: 2,
|
forward: 2,
|
||||||
stickers: 3,
|
stickers: 3,
|
||||||
pollResults: 4,
|
pollResults: 4,
|
||||||
|
gifs: 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
public profileContainer: HTMLDivElement;
|
public profileContainer: HTMLDivElement;
|
||||||
@ -467,17 +120,20 @@ export class AppSidebarRight extends SidebarSlider {
|
|||||||
|
|
||||||
public stickersTab: AppStickersTab;
|
public stickersTab: AppStickersTab;
|
||||||
public pollResultsTab: AppPollResultsTab;
|
public pollResultsTab: AppPollResultsTab;
|
||||||
|
public gifsTab: AppGifsTab;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super(document.getElementById('column-right') as HTMLElement, {
|
super(document.getElementById('column-right') as HTMLElement, {
|
||||||
[AppSidebarRight.SLIDERITEMSIDS.stickers]: stickersTab,
|
[AppSidebarRight.SLIDERITEMSIDS.stickers]: stickersTab,
|
||||||
[AppSidebarRight.SLIDERITEMSIDS.pollResults]: pollResultsTab,
|
[AppSidebarRight.SLIDERITEMSIDS.pollResults]: pollResultsTab,
|
||||||
|
[AppSidebarRight.SLIDERITEMSIDS.gifs]: gifsTab
|
||||||
});
|
});
|
||||||
|
|
||||||
//this._selectTab(3);
|
//this._selectTab(3);
|
||||||
|
|
||||||
this.stickersTab = stickersTab;
|
this.stickersTab = stickersTab;
|
||||||
this.pollResultsTab = pollResultsTab;
|
this.pollResultsTab = pollResultsTab;
|
||||||
|
this.gifsTab = gifsTab;
|
||||||
|
|
||||||
this.profileContainer = this.sidebarEl.querySelector('.profile-container');
|
this.profileContainer = this.sidebarEl.querySelector('.profile-container');
|
||||||
this.profileContentEl = this.sidebarEl.querySelector('.profile-content');
|
this.profileContentEl = this.sidebarEl.querySelector('.profile-content');
|
||||||
|
@ -133,6 +133,19 @@ export class AppUsersManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async resolveUsername(username: string) {
|
||||||
|
if(this.usernames[username]) {
|
||||||
|
return this.users[this.usernames[username]];
|
||||||
|
}
|
||||||
|
|
||||||
|
return await apiManager.invokeApi('contacts.resolveUsername', {username}).then(resolvedPeer => {
|
||||||
|
this.saveApiUser(resolvedPeer.users[0]);
|
||||||
|
appChatsManager.saveApiChats(resolvedPeer.chats);
|
||||||
|
|
||||||
|
return this.users[this.usernames[username]];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public pushContact(userID: number) {
|
public pushContact(userID: number) {
|
||||||
this.contactsList.add(userID);
|
this.contactsList.add(userID);
|
||||||
searchIndexManager.indexObject(userID, this.getUserSearchText(userID), this.contactsIndex);
|
searchIndexManager.indexObject(userID, this.getUserSearchText(userID), this.contactsIndex);
|
||||||
@ -183,9 +196,9 @@ export class AppUsersManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public resolveUsername(username: string) {
|
/* public resolveUsername(username: string) {
|
||||||
return this.usernames[username] || 0;
|
return this.usernames[username] || 0;
|
||||||
}
|
} */
|
||||||
|
|
||||||
public saveApiUsers(apiUsers: any[]) {
|
public saveApiUsers(apiUsers: any[]) {
|
||||||
apiUsers.forEach((user) => this.saveApiUser(user));
|
apiUsers.forEach((user) => this.saveApiUser(user));
|
||||||
|
@ -78,7 +78,7 @@ networkerFactory.setUpdatesProcessor((obj, bool) => {
|
|||||||
notify({update: {obj, bool}});
|
notify({update: {obj, bool}});
|
||||||
});
|
});
|
||||||
|
|
||||||
ctx.addEventListener('message', async(e) => {
|
const onMessage = async(e: ExtendableMessageEvent) => {
|
||||||
const taskID = e.data.taskID;
|
const taskID = e.data.taskID;
|
||||||
|
|
||||||
log.debug('got message:', taskID, e, e.data);
|
log.debug('got message:', taskID, e, e.data);
|
||||||
@ -139,7 +139,9 @@ ctx.addEventListener('message', async(e) => {
|
|||||||
//throw new Error('Unknown task: ' + e.data.task);
|
//throw new Error('Unknown task: ' + e.data.task);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
ctx.onmessage = onMessage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service Worker Installation
|
* Service Worker Installation
|
||||||
@ -195,14 +197,11 @@ function responseForSafariFirstRange(range: [number, number], mimeType: string,
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.addEventListener('error', (error) => {
|
ctx.onerror = (error) => {
|
||||||
log.error('error:', error);
|
log.error('error:', error);
|
||||||
});
|
};
|
||||||
|
|
||||||
/**
|
const onFetch = (event: FetchEvent): void => {
|
||||||
* Fetch requests
|
|
||||||
*/
|
|
||||||
ctx.addEventListener('fetch', (event: FetchEvent): void => {
|
|
||||||
const [, url, scope, params] = /http[:s]+\/\/.*?(\/(.*?)(?:$|\/(.*)$))/.exec(event.request.url) || [];
|
const [, url, scope, params] = /http[:s]+\/\/.*?(\/(.*?)(?:$|\/(.*)$))/.exec(event.request.url) || [];
|
||||||
|
|
||||||
log.debug('[fetch]:', event);
|
log.debug('[fetch]:', event);
|
||||||
@ -440,11 +439,19 @@ ctx.addEventListener('fetch', (event: FetchEvent): void => {
|
|||||||
if (url && url.endsWith('.tgs')) event.respondWith(fetchTGS(url));
|
if (url && url.endsWith('.tgs')) event.respondWith(fetchTGS(url));
|
||||||
else event.respondWith(fetch(event.request.url)); */
|
else event.respondWith(fetch(event.request.url)); */
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch requests
|
||||||
|
*/
|
||||||
|
//ctx.addEventListener('fetch', );
|
||||||
|
ctx.onfetch = onFetch;
|
||||||
|
|
||||||
const DOWNLOAD_CHUNK_LIMIT = 512 * 1024;
|
const DOWNLOAD_CHUNK_LIMIT = 512 * 1024;
|
||||||
const STREAM_CHUNK_UPPER_LIMIT = 256 * 1024;
|
//const STREAM_CHUNK_UPPER_LIMIT = 256 * 1024;
|
||||||
const SMALLEST_CHUNK_LIMIT = 256 * 4;
|
//const SMALLEST_CHUNK_LIMIT = 256 * 4;
|
||||||
|
const STREAM_CHUNK_UPPER_LIMIT = 1024 * 1024;
|
||||||
|
const SMALLEST_CHUNK_LIMIT = 1024 * 4;
|
||||||
|
|
||||||
function parseRange(header: string): [number, number] {
|
function parseRange(header: string): [number, number] {
|
||||||
if(!header) return [0, 0];
|
if(!header) return [0, 0];
|
||||||
@ -462,3 +469,9 @@ function alignOffset(offset: number, base = SMALLEST_CHUNK_LIMIT) {
|
|||||||
function alignLimit(limit: number) {
|
function alignLimit(limit: number) {
|
||||||
return 2 ** Math.ceil(Math.log(limit) / Math.log(2));
|
return 2 ** Math.ceil(Math.log(limit) / Math.log(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
if(process.env.NODE_ENV != 'production') {
|
||||||
|
(ctx as any).onMessage = onMessage;
|
||||||
|
(ctx as any).onFetch = onFetch;
|
||||||
|
}
|
||||||
|
@ -878,7 +878,7 @@ $bubble-margin: .25rem;
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: auto;
|
width: auto !important;
|
||||||
|
|
||||||
.inner {
|
.inner {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
@ -910,7 +910,7 @@ $bubble-margin: .25rem;
|
|||||||
i {
|
i {
|
||||||
font-size: 1.15rem;
|
font-size: 1.15rem;
|
||||||
margin-right: .4rem;
|
margin-right: .4rem;
|
||||||
margin-left: .1rem;
|
/* margin-left: .1rem; */
|
||||||
}
|
}
|
||||||
|
|
||||||
i.edited {
|
i.edited {
|
||||||
@ -960,7 +960,8 @@ $bubble-margin: .25rem;
|
|||||||
|
|
||||||
&.emoji-big, &.sticker {
|
&.emoji-big, &.sticker {
|
||||||
.time {
|
.time {
|
||||||
width: 81px !important;
|
/* width: 81px !important; */
|
||||||
|
min-width: unset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1167,7 +1168,8 @@ $bubble-margin: .25rem;
|
|||||||
|
|
||||||
.time {
|
.time {
|
||||||
color: #a3adb6;
|
color: #a3adb6;
|
||||||
width: 36px;
|
/* width: 36px; */
|
||||||
|
padding-left: 36px;
|
||||||
|
|
||||||
.inner {
|
.inner {
|
||||||
padding: 0 7px 0 5px;
|
padding: 0 7px 0 5px;
|
||||||
|
@ -322,33 +322,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#content-gifs {
|
|
||||||
.gifs-masonry {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
|
|
||||||
> .gif {
|
|
||||||
flex: 1 0 auto;
|
|
||||||
max-width: 100%;
|
|
||||||
height: 100px;
|
|
||||||
margin: 2.5px;
|
|
||||||
cursor: pointer;
|
|
||||||
//background: #000;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
video, img {
|
|
||||||
object-fit: cover;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
26
src/scss/partials/_gifsMasonry.scss
Normal file
26
src/scss/partials/_gifsMasonry.scss
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
.gifs-masonry {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
> .gif {
|
||||||
|
flex: 1 0 auto;
|
||||||
|
max-width: 100%;
|
||||||
|
height: 100px;
|
||||||
|
margin: 2.5px;
|
||||||
|
cursor: pointer;
|
||||||
|
//background: #000;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
video, img {
|
||||||
|
object-fit: cover;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -48,6 +48,7 @@ $large-screen: 1680px;
|
|||||||
@import "partials/scrollable";
|
@import "partials/scrollable";
|
||||||
@import "partials/slider";
|
@import "partials/slider";
|
||||||
@import "partials/selector";
|
@import "partials/selector";
|
||||||
|
@import "partials/gifsMasonry";
|
||||||
|
|
||||||
@import "partials/popups/popup";
|
@import "partials/popups/popup";
|
||||||
@import "partials/popups/editAvatar";
|
@import "partials/popups/editAvatar";
|
||||||
|
3
src/types.d.ts
vendored
3
src/types.d.ts
vendored
@ -9,6 +9,7 @@ export type MTDocument = {
|
|||||||
mime_type: string,
|
mime_type: string,
|
||||||
size: number,
|
size: number,
|
||||||
thumbs: MTPhotoSize[],
|
thumbs: MTPhotoSize[],
|
||||||
|
video_thumbs?: MTVideoSize[],
|
||||||
dc_id: number,
|
dc_id: number,
|
||||||
attributes: any[],
|
attributes: any[],
|
||||||
|
|
||||||
@ -46,6 +47,8 @@ export type MTPhotoSize = {
|
|||||||
url?: string
|
url?: string
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type MTVideoSize = Omit<MTPhotoSize, '_'> & {_: 'videoSize'};
|
||||||
|
|
||||||
export type InvokeApiOptions = Partial<{
|
export type InvokeApiOptions = Partial<{
|
||||||
dcID: number,
|
dcID: number,
|
||||||
timeout: number,
|
timeout: number,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user