/* * https://github.com/morethanwords/tweb * Copyright (C) 2019-2021 Eduard Kuzmenko * https://github.com/morethanwords/tweb/blob/master/LICENSE */ import { renderImageFromUrlPromise } from "../../helpers/dom/renderImageFromUrl"; import replaceContent from "../../helpers/dom/replaceContent"; import sequentialDom from "../../helpers/sequentialDom"; import { UserProfilePhoto, ChatPhoto, InputFileLocation } from "../../layer"; import { NULL_PEER_ID, REPLIES_PEER_ID } from "../mtproto/mtproto_config"; import RichTextProcessor from "../richtextprocessor"; import rootScope from "../rootScope"; import appDownloadManager from "./appDownloadManager"; import appPeersManager from "./appPeersManager"; import appPhotosManager from "./appPhotosManager"; import appUsersManager from "./appUsersManager"; type PeerPhotoSize = 'photo_small' | 'photo_big'; export class AppAvatarsManager { private savedAvatarURLs: { [peerId: PeerId]: { [size in PeerPhotoSize]?: string | Promise } } = {}; public isAvatarCached(peerId: PeerId) { return !!this.savedAvatarURLs[peerId]; } public removeFromAvatarsCache(peerId: PeerId) { if(this.savedAvatarURLs[peerId]) { delete this.savedAvatarURLs[peerId]; } } public loadAvatar(peerId: PeerId, photo: UserProfilePhoto.userProfilePhoto | ChatPhoto.chatPhoto, size: PeerPhotoSize) { const inputPeer = appPeersManager.getInputPeerById(peerId); let cached = false; let getAvatarPromise: Promise; let saved = this.savedAvatarURLs[peerId]; if(!saved || !saved[size]) { if(!saved) { saved = this.savedAvatarURLs[peerId] = {}; } //console.warn('will invoke downloadSmallFile:', peerId); const peerPhotoFileLocation: InputFileLocation.inputPeerPhotoFileLocation = { _: 'inputPeerPhotoFileLocation', pFlags: {}, peer: inputPeer, photo_id: photo.photo_id }; if(size === 'photo_big') { peerPhotoFileLocation.pFlags.big = true; } const downloadOptions = {dcId: photo.dc_id, location: peerPhotoFileLocation}; /* let str: string; const time = Date.now(); if(peerId === 0) { str = `download avatar ${peerId}`; } */ const promise = appDownloadManager.download(downloadOptions); getAvatarPromise = saved[size] = promise.then(blob => { return saved[size] = URL.createObjectURL(blob); /* if(str) { console.log(str, Date.now() / 1000, Date.now() - time); } */ }); } else if(typeof(saved[size]) !== 'string') { getAvatarPromise = saved[size] as Promise; } else { getAvatarPromise = Promise.resolve(saved[size]); cached = true; } return {cached, loadPromise: getAvatarPromise}; } public putAvatar( div: HTMLElement, peerId: PeerId, photo: UserProfilePhoto.userProfilePhoto | ChatPhoto.chatPhoto, size: PeerPhotoSize, img = new Image(), onlyThumb = false ) { let {cached, loadPromise} = this.loadAvatar(peerId, photo, size); img.classList.add('avatar-photo'); let renderThumbPromise: Promise; let callback: () => void; let thumbImage: HTMLImageElement; if(cached) { // смотри в misc.ts: renderImageFromUrl callback = () => { replaceContent(div, img); div.dataset.color = ''; }; } else { const animate = rootScope.settings.animationsEnabled; if(animate) { img.classList.add('fade-in'); } if(size === 'photo_big') { // let's load small photo first const res = this.putAvatar(div, peerId, photo, 'photo_small'); renderThumbPromise = res.loadPromise; thumbImage = res.thumbImage; } else if(photo.stripped_thumb) { thumbImage = new Image(); div.classList.add('avatar-relative'); thumbImage.classList.add('avatar-photo', 'avatar-photo-thumbnail'); const url = appPhotosManager.getPreviewURLFromBytes(photo.stripped_thumb); renderThumbPromise = renderImageFromUrlPromise(thumbImage, url).then(() => { replaceContent(div, thumbImage); }); } callback = () => { if(thumbImage) { div.append(img); } else { replaceContent(div, img); } setTimeout(() => { if(div.childElementCount) { sequentialDom.mutateElement(img, () => { div.dataset.color = ''; if(animate) { img.classList.remove('fade-in'); } if(thumbImage) { thumbImage.remove(); } }); } }, animate ? 200 : 0); }; } const renderPromise = loadPromise .then((url) => renderImageFromUrlPromise(img, url/* , false */)) .then(callback); return { cached, loadPromise: renderThumbPromise || renderPromise, thumbImage }; } public s(div: HTMLElement, innerHTML: string, color: string, icon: string) { div.innerHTML = innerHTML; div.dataset.color = color; div.classList.remove('tgico-saved', 'tgico-deletedaccount', 'tgico-reply_filled'); icon && div.classList.add(icon); } // peerId === peerId || title public putPhoto(div: HTMLElement, peerId: PeerId, isDialog = false, title = '', onlyThumb = false, isBig?: boolean) { const myId = rootScope.myId; //console.log('loadDialogPhoto location:', location, inputPeer); if(peerId === myId && isDialog) { this.s(div, '', '', 'tgico-saved'); return; } if(peerId !== NULL_PEER_ID && peerId.isUser()) { const user = appUsersManager.getUser(peerId); if(user && user.pFlags && user.pFlags.deleted) { this.s(div, '', appPeersManager.getPeerColorById(peerId), 'tgico-deletedaccount'); return; } } const photo = appPeersManager.getPeerPhoto(peerId); const avatarAvailable = !!photo; const avatarRendered = !!div.firstElementChild && !(div.firstElementChild as HTMLElement).classList.contains('emoji'); if(!avatarAvailable || !avatarRendered || !this.savedAvatarURLs[peerId]) { let color = ''; if(peerId && (peerId !== myId || !isDialog)) { color = appPeersManager.getPeerColorById(peerId); } if(peerId === REPLIES_PEER_ID) { this.s(div, '', color, 'tgico-reply_filled'); return; } let abbr: string; if(!title) { const peer = appPeersManager.getPeer(peerId); abbr = peer.initials ?? ''; } else { abbr = RichTextProcessor.getAbbreviation(title); } this.s(div, abbr, color, ''); //return Promise.resolve(true); } if(avatarAvailable/* && false */) { const size: PeerPhotoSize = isBig ? 'photo_big' : 'photo_small'; return this.putAvatar(div, peerId, photo, size, undefined, onlyThumb); } } } const appAvatarsManager = new AppAvatarsManager(); export default appAvatarsManager;