tweb/src/lib/appManagers/appAvatarsManager.ts

226 lines
7.0 KiB
TypeScript
Raw Normal View History

2021-06-18 14:00:30 +02:00
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
2022-03-28 17:16:12 +02:00
import { MOUNT_CLASS_TO } from "../../config/debug";
2021-08-11 15:39:49 +02:00
import { renderImageFromUrlPromise } from "../../helpers/dom/renderImageFromUrl";
2021-06-18 14:00:30 +02:00
import replaceContent from "../../helpers/dom/replaceContent";
import sequentialDom from "../../helpers/sequentialDom";
import { UserProfilePhoto, ChatPhoto, InputFileLocation } from "../../layer";
2021-10-21 15:16:43 +02:00
import { NULL_PEER_ID, REPLIES_PEER_ID } from "../mtproto/mtproto_config";
2021-06-18 14:00:30 +02:00
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: {
2021-10-21 15:16:43 +02:00
[peerId: PeerId]: {
2021-06-18 14:00:30 +02:00
[size in PeerPhotoSize]?: string | Promise<string>
}
} = {};
2021-09-15 07:02:03 +02:00
2021-10-21 15:16:43 +02:00
public isAvatarCached(peerId: PeerId) {
2021-09-15 07:02:03 +02:00
return !!this.savedAvatarURLs[peerId];
}
2021-06-18 14:00:30 +02:00
2021-10-21 15:16:43 +02:00
public removeFromAvatarsCache(peerId: PeerId) {
2021-06-18 14:00:30 +02:00
if(this.savedAvatarURLs[peerId]) {
delete this.savedAvatarURLs[peerId];
}
}
2021-10-21 15:16:43 +02:00
public loadAvatar(peerId: PeerId, photo: UserProfilePhoto.userProfilePhoto | ChatPhoto.chatPhoto, size: PeerPhotoSize) {
2021-06-18 14:00:30 +02:00
const inputPeer = appPeersManager.getInputPeerById(peerId);
let cached = false;
let getAvatarPromise: Promise<string>;
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<any>;
} else {
getAvatarPromise = Promise.resolve(saved[size]);
cached = true;
}
return {cached, loadPromise: getAvatarPromise};
}
2021-10-27 21:16:01 +02:00
public putAvatar(
div: HTMLElement,
peerId: PeerId,
photo: UserProfilePhoto.userProfilePhoto | ChatPhoto.chatPhoto,
size: PeerPhotoSize,
img = new Image(),
onlyThumb = false
) {
2021-06-18 14:00:30 +02:00
let {cached, loadPromise} = this.loadAvatar(peerId, photo, size);
2021-10-27 21:16:01 +02:00
img.classList.add('avatar-photo');
2021-06-18 14:00:30 +02:00
let renderThumbPromise: Promise<void>;
let callback: () => void;
2021-10-27 21:16:01 +02:00
let thumbImage: HTMLImageElement;
2021-06-18 14:00:30 +02:00
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');
}
2021-10-27 21:16:01 +02:00
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) {
2021-06-18 14:00:30 +02:00
thumbImage = new Image();
div.classList.add('avatar-relative');
thumbImage.classList.add('avatar-photo', 'avatar-photo-thumbnail');
const url = appPhotosManager.getPreviewURLFromBytes(photo.stripped_thumb);
2021-07-17 14:37:43 +02:00
renderThumbPromise = renderImageFromUrlPromise(thumbImage, url).then(() => {
2021-06-18 14:00:30 +02:00
replaceContent(div, thumbImage);
});
}
callback = () => {
2021-10-27 21:16:01 +02:00
if(thumbImage) {
2021-06-18 14:00:30 +02:00
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
2021-07-17 14:37:43 +02:00
.then((url) => renderImageFromUrlPromise(img, url/* , false */))
2021-10-27 21:16:01 +02:00
.then(callback);
2021-06-18 14:00:30 +02:00
2021-10-27 21:16:01 +02:00
return {
cached,
loadPromise: renderThumbPromise || renderPromise,
thumbImage
};
2021-06-18 14:00:30 +02:00
}
2021-10-21 15:16:43 +02:00
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);
}
2021-06-18 14:00:30 +02:00
2021-10-21 15:16:43 +02:00
// peerId === peerId || title
2022-03-24 15:16:41 +01:00
public putPhoto(div: HTMLElement, peerId: PeerId, isDialog = false, title = '', onlyThumb = false, isBig?: boolean) {
2021-06-18 14:00:30 +02:00
const myId = rootScope.myId;
2021-10-21 15:16:43 +02:00
2021-06-18 14:00:30 +02:00
//console.log('loadDialogPhoto location:', location, inputPeer);
if(peerId === myId && isDialog) {
2021-10-21 15:16:43 +02:00
this.s(div, '', '', 'tgico-saved');
2021-06-18 14:00:30 +02:00
return;
}
2021-10-21 15:16:43 +02:00
if(peerId !== NULL_PEER_ID && peerId.isUser()) {
2021-06-18 14:00:30 +02:00
const user = appUsersManager.getUser(peerId);
if(user && user.pFlags && user.pFlags.deleted) {
2021-10-21 15:16:43 +02:00
this.s(div, '', appPeersManager.getPeerColorById(peerId), 'tgico-deletedaccount');
2021-06-18 14:00:30 +02:00
return;
}
}
2021-10-21 15:16:43 +02:00
const photo = appPeersManager.getPeerPhoto(peerId);
const avatarAvailable = !!photo;
const avatarRendered = !!div.firstElementChild && !(div.firstElementChild as HTMLElement).classList.contains('emoji');
2021-06-18 14:00:30 +02:00
if(!avatarAvailable || !avatarRendered || !this.savedAvatarURLs[peerId]) {
let color = '';
if(peerId && (peerId !== myId || !isDialog)) {
color = appPeersManager.getPeerColorById(peerId);
}
2021-10-21 15:16:43 +02:00
if(peerId === REPLIES_PEER_ID) {
this.s(div, '', color, 'tgico-reply_filled');
return;
}
2021-06-18 14:00:30 +02:00
let abbr: string;
if(!title) {
const peer = appPeersManager.getPeer(peerId);
abbr = peer.initials ?? '';
} else {
abbr = RichTextProcessor.getAbbreviation(title);
}
2021-10-21 15:16:43 +02:00
this.s(div, abbr, color, '');
2021-06-18 14:00:30 +02:00
//return Promise.resolve(true);
}
if(avatarAvailable/* && false */) {
2022-03-24 15:16:41 +01:00
const size: PeerPhotoSize = isBig ? 'photo_big' : 'photo_small';
2021-06-18 14:00:30 +02:00
return this.putAvatar(div, peerId, photo, size, undefined, onlyThumb);
}
}
}
const appAvatarsManager = new AppAvatarsManager();
2022-03-28 17:16:12 +02:00
MOUNT_CLASS_TO && (MOUNT_CLASS_TO.appAvatarsManager = appAvatarsManager);
2021-06-18 14:00:30 +02:00
export default appAvatarsManager;