Telegram Web K with changes to work inside I2P
https://web.telegram.i2p/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
268 lines
7.4 KiB
268 lines
7.4 KiB
/* |
|
* https://github.com/morethanwords/tweb |
|
* Copyright (C) 2019-2021 Eduard Kuzmenko |
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE |
|
*/ |
|
|
|
import rootScope from '../lib/rootScope'; |
|
import {Message, Photo} from '../layer'; |
|
import type LazyLoadQueue from './lazyLoadQueue'; |
|
import {attachClickEvent} from '../helpers/dom/clickEvent'; |
|
import cancelEvent from '../helpers/dom/cancelEvent'; |
|
import AppMediaViewer from './appMediaViewer'; |
|
import AppMediaViewerAvatar from './appMediaViewerAvatar'; |
|
import isObject from '../helpers/object/isObject'; |
|
import {ArgumentTypes} from '../types'; |
|
import putPhoto from './putPhoto'; |
|
import {recordPromise} from '../helpers/recordPromise'; |
|
|
|
const onAvatarUpdate = (peerId: PeerId) => { |
|
(Array.from(document.querySelectorAll('avatar-element[data-peer-id="' + peerId + '"]')) as AvatarElement[]).forEach((elem) => { |
|
// console.log('updating avatar:', elem); |
|
elem.update(); |
|
}); |
|
}; |
|
|
|
rootScope.addEventListener('avatar_update', onAvatarUpdate); |
|
rootScope.addEventListener('peer_title_edit', async(peerId) => { |
|
if(!(await rootScope.managers.appAvatarsManager.isAvatarCached(peerId))) { |
|
onAvatarUpdate(peerId); |
|
} |
|
}); |
|
|
|
export async function openAvatarViewer( |
|
target: HTMLElement, |
|
peerId: PeerId, |
|
middleware: () => boolean, |
|
message?: any, |
|
prevTargets?: {element: HTMLElement, item: Photo.photo['id'] | Message.messageService}[], |
|
nextTargets?: typeof prevTargets |
|
) { |
|
let photo = await rootScope.managers.appProfileManager.getFullPhoto(peerId); |
|
if(!middleware() || !photo) { |
|
return; |
|
} |
|
|
|
const getTarget = () => { |
|
const good = Array.from(target.querySelectorAll('img')).find((img) => !img.classList.contains('emoji')); |
|
return good ? target : null; |
|
}; |
|
|
|
if(peerId.isAnyChat()) { |
|
const hadMessage = !!message; |
|
const inputFilter = 'inputMessagesFilterChatPhotos'; |
|
if(!message) { |
|
message = await rootScope.managers.appMessagesManager.getSearch({ |
|
peerId, |
|
inputFilter: {_: inputFilter}, |
|
maxId: 0, |
|
limit: 1 |
|
}).then((value) => { |
|
// console.log(lol); |
|
// ! by descend |
|
return value.history[0]; |
|
}); |
|
|
|
if(!middleware()) { |
|
return; |
|
} |
|
} |
|
|
|
if(message) { |
|
// ! гений в деле, костылируем (но это гениально) |
|
const messagePhoto = message.action.photo; |
|
if(messagePhoto.id !== photo.id) { |
|
if(!hadMessage) { |
|
message = rootScope.managers.appMessagesManager.generateFakeAvatarMessage(peerId, photo); |
|
} else { |
|
|
|
} |
|
} |
|
|
|
const f = (arr: typeof prevTargets) => arr.map((el) => ({ |
|
element: el.element, |
|
mid: (el.item as Message.messageService).mid, |
|
peerId: (el.item as Message.messageService).peerId |
|
})); |
|
|
|
new AppMediaViewer() |
|
.setSearchContext({ |
|
peerId, |
|
inputFilter: {_: inputFilter} |
|
}) |
|
.openMedia(message, getTarget(), undefined, undefined, prevTargets ? f(prevTargets) : undefined, nextTargets ? f(nextTargets) : undefined); |
|
|
|
return; |
|
} |
|
} |
|
|
|
if(photo) { |
|
if(!isObject(message) && message) { |
|
photo = await rootScope.managers.appPhotosManager.getPhoto(message); |
|
} |
|
|
|
const f = (arr: typeof prevTargets) => arr.map((el) => ({ |
|
element: el.element, |
|
photoId: el.item as string |
|
})); |
|
|
|
new AppMediaViewerAvatar(peerId).openMedia( |
|
photo.id, |
|
getTarget(), |
|
undefined, |
|
prevTargets ? f(prevTargets) : undefined, |
|
nextTargets ? f(nextTargets) : undefined |
|
); |
|
} |
|
} |
|
|
|
const believeMe: Map<PeerId, Set<AvatarElement>> = new Map(); |
|
const seen: Set<PeerId> = new Set(); |
|
|
|
export default class AvatarElement extends HTMLElement { |
|
public peerId: PeerId; |
|
public isDialog: boolean; |
|
public peerTitle: string; |
|
public loadPromises: Promise<any>[]; |
|
public lazyLoadQueue: LazyLoadQueue; |
|
public isBig: boolean; |
|
private addedToQueue = false; |
|
|
|
disconnectedCallback() { |
|
// браузер вызывает этот метод при удалении элемента из документа |
|
// (может вызываться много раз, если элемент многократно добавляется/удаляется) |
|
const set = believeMe.get(this.peerId); |
|
if(set && set.has(this)) { |
|
set.delete(this); |
|
if(!set.size) { |
|
believeMe.delete(this.peerId); |
|
} |
|
} |
|
|
|
if(this.lazyLoadQueue) { |
|
this.lazyLoadQueue.unobserve(this); |
|
} |
|
} |
|
|
|
public attachClickEvent() { |
|
let loading = false; |
|
attachClickEvent(this, async(e) => { |
|
cancelEvent(e); |
|
if(loading) return; |
|
// console.log('avatar clicked'); |
|
const peerId = this.peerId; |
|
loading = true; |
|
await openAvatarViewer(this, this.peerId, () => this.peerId === peerId); |
|
loading = false; |
|
}); |
|
} |
|
|
|
public updateOptions(options: Partial<ArgumentTypes<AvatarElement['updateWithOptions']>[0]>) { |
|
for(const i in options) { |
|
// @ts-ignore |
|
this[i] = options[i]; |
|
} |
|
} |
|
|
|
public updateWithOptions(options: { |
|
peerId: PeerId, |
|
isDialog?: boolean, |
|
isBig?: boolean, |
|
peerTitle?: string, |
|
lazyLoadQueue?: LazyLoadQueue, |
|
loadPromises?: Promise<any>[] |
|
}) { |
|
const wasPeerId = this.peerId; |
|
this.updateOptions(options); |
|
const newPeerId = this.peerId; |
|
|
|
if(wasPeerId === newPeerId) { |
|
return; |
|
} |
|
|
|
this.peerId = /* rootScope.managers.appPeersManager.getPeerMigratedTo(newPeerId) || */newPeerId; |
|
this.dataset.peerId = '' + newPeerId; |
|
|
|
if(wasPeerId) { |
|
const set = believeMe.get(wasPeerId); |
|
if(set) { |
|
set.delete(this); |
|
if(!set.size) { |
|
believeMe.delete(wasPeerId); |
|
} |
|
} |
|
} |
|
|
|
return this.update(); |
|
} |
|
|
|
private r(onlyThumb = false) { |
|
const promise = putPhoto(this, this.peerId, this.isDialog, this.peerTitle, onlyThumb, this.isBig); |
|
// recordPromise(promise, 'avatar putPhoto-' + this.peerId); |
|
|
|
if(this.loadPromises) { |
|
this.loadPromises.push(promise); |
|
|
|
promise.finally(() => { |
|
this.loadPromises = undefined; |
|
}); |
|
} |
|
|
|
return promise; |
|
} |
|
|
|
public update() { |
|
if(this.lazyLoadQueue) { |
|
if(!seen.has(this.peerId)) { |
|
if(this.addedToQueue) return; |
|
this.addedToQueue = true; |
|
|
|
let set = believeMe.get(this.peerId); |
|
if(!set) { |
|
set = new Set(); |
|
believeMe.set(this.peerId, set); |
|
} |
|
|
|
set.add(this); |
|
|
|
this.lazyLoadQueue.push({ |
|
div: this, |
|
load: () => { |
|
seen.add(this.peerId); |
|
return this.update(); |
|
} |
|
}); |
|
|
|
return this.r(true); |
|
} else if(this.addedToQueue) { |
|
this.lazyLoadQueue.unobserve(this); |
|
} |
|
} |
|
|
|
seen.add(this.peerId); |
|
|
|
const promise = this.r(); |
|
|
|
if(this.addedToQueue) { |
|
promise.finally(() => { |
|
this.addedToQueue = false; |
|
}); |
|
} |
|
|
|
const set = believeMe.get(this.peerId); |
|
if(set) { |
|
set.delete(this); |
|
const arr = Array.from(set); |
|
believeMe.delete(this.peerId); |
|
|
|
|
|
for(let i = 0, length = arr.length; i < length; ++i) { |
|
arr[i].update(); |
|
} |
|
} |
|
|
|
return promise; |
|
} |
|
} |
|
|
|
customElements.define('avatar-element', AvatarElement);
|
|
|