Browse Source

Fix import order

master
morethanwords 3 years ago
parent
commit
6b3b2c343d
  1. 4
      src/components/appSearchSuper..ts
  2. 2
      src/components/appSelectPeers.ts
  3. 5
      src/components/avatar.ts
  4. 3
      src/components/sidebarRight/tabs/sharedMedia.ts
  5. 202
      src/lib/appManagers/appAvatarsManager.ts
  6. 154
      src/lib/appManagers/appChatsManager.ts
  7. 5
      src/lib/appManagers/appImManager.ts
  8. 5
      src/lib/appManagers/appMessagesManager.ts
  9. 2
      src/lib/appManagers/appNotificationsManager.ts
  10. 280
      src/lib/appManagers/appProfileManager.ts
  11. 3
      src/lib/rootScope.ts
  12. 17
      src/pages/pageAuthCode.ts
  13. 5
      src/pages/pagePassword.ts
  14. 5
      src/pages/pageSignUp.ts

4
src/components/appSearchSuper..ts

@ -718,7 +718,7 @@ export default class AppSearchSuper { @@ -718,7 +718,7 @@ export default class AppSearchSuper {
if(showMembersCount && (peer.participants_count || peer.participants)) {
const regExp = new RegExp(`(${escapeRegExp(query)}|${escapeRegExp(cleanSearchText(query))})`, 'gi');
dom.titleSpan.innerHTML = dom.titleSpan.innerHTML.replace(regExp, '<i>$1</i>');
dom.lastMessageSpan.append(appChatsManager.getChatMembersString(-peerId));
dom.lastMessageSpan.append(appProfileManager.getChatMembersString(-peerId));
} else if(peerId === rootScope.myId) {
dom.lastMessageSpan.append(i18n('Presence.YourChat'));
} else {
@ -811,7 +811,7 @@ export default class AppSearchSuper { @@ -811,7 +811,7 @@ export default class AppSearchSuper {
autonomous: true
});
dom.lastMessageSpan.append(peerId > 0 ? appUsersManager.getUserStatusString(peerId) : appChatsManager.getChatMembersString(peerId));
dom.lastMessageSpan.append(peerId > 0 ? appUsersManager.getUserStatusString(peerId) : appProfileManager.getChatMembersString(-peerId));
});
if(!state.recentSearch.length) {

2
src/components/appSelectPeers.ts

@ -447,7 +447,7 @@ export default class AppSelectPeers { @@ -447,7 +447,7 @@ export default class AppSelectPeers {
let subtitleEl: HTMLElement;
if(peerId < 0) {
subtitleEl = appChatsManager.getChatMembersString(-peerId);
subtitleEl = appProfileManager.getChatMembersString(-peerId);
} else if(peerId === rootScope.myId) {
subtitleEl = i18n('Presence.YourChat');
} else {

5
src/components/avatar.ts

@ -14,9 +14,10 @@ import appPhotosManager from "../lib/appManagers/appPhotosManager"; @@ -14,9 +14,10 @@ import appPhotosManager from "../lib/appManagers/appPhotosManager";
import type { LazyLoadQueueIntersector } from "./lazyLoadQueue";
import { attachClickEvent } from "../helpers/dom/clickEvent";
import { cancelEvent } from "../helpers/dom/cancelEvent";
import appAvatarsManager from "../lib/appManagers/appAvatarsManager";
const onAvatarUpdate = (peerId: number) => {
appProfileManager.removeFromAvatarsCache(peerId);
appAvatarsManager.removeFromAvatarsCache(peerId);
(Array.from(document.querySelectorAll('avatar-element[peer="' + peerId + '"]')) as AvatarElement[]).forEach(elem => {
//console.log('updating avatar:', elem);
elem.update();
@ -180,7 +181,7 @@ export default class AvatarElement extends HTMLElement { @@ -180,7 +181,7 @@ export default class AvatarElement extends HTMLElement {
}
private r(onlyThumb = false) {
const res = appProfileManager.putPhoto(this, this.peerId, this.isDialog, this.peerTitle, onlyThumb);
const res = appAvatarsManager.putPhoto(this, this.peerId, this.isDialog, this.peerTitle, onlyThumb);
const promise = res ? res.loadPromise : Promise.resolve();
if(this.loadPromises) {
if(res && res.cached) {

3
src/components/sidebarRight/tabs/sharedMedia.ts

@ -48,6 +48,7 @@ import ButtonCorner from "../../buttonCorner"; @@ -48,6 +48,7 @@ import ButtonCorner from "../../buttonCorner";
import { cancelEvent } from "../../../helpers/dom/cancelEvent";
import { attachClickEvent } from "../../../helpers/dom/clickEvent";
import replaceContent from "../../../helpers/dom/replaceContent";
import appAvatarsManager from "../../../lib/appManagers/appAvatarsManager";
let setText = (text: string, row: Row) => {
//fastRaf(() => {
@ -437,7 +438,7 @@ class PeerProfileAvatars { @@ -437,7 +438,7 @@ class PeerProfileAvatars {
});
} else {
const photo = appPeersManager.getPeerPhoto(this.peerId);
appProfileManager.putAvatar(avatar, this.peerId, photo, 'photo_big', img);
appAvatarsManager.putAvatar(avatar, this.peerId, photo, 'photo_big', img);
}
this.avatars.append(avatar);

202
src/lib/appManagers/appAvatarsManager.ts

@ -0,0 +1,202 @@ @@ -0,0 +1,202 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import renderImageFromUrl from "../../helpers/dom/renderImageFromUrl";
import replaceContent from "../../helpers/dom/replaceContent";
import sequentialDom from "../../helpers/sequentialDom";
import { UserProfilePhoto, ChatPhoto, InputFileLocation } from "../../layer";
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: number]: {
[size in PeerPhotoSize]?: string | Promise<string>
}
} = {};
public removeFromAvatarsCache(peerId: number) {
if(this.savedAvatarURLs[peerId]) {
delete this.savedAvatarURLs[peerId];
}
}
public loadAvatar(peerId: number, photo: UserProfilePhoto.userProfilePhoto | ChatPhoto.chatPhoto, size: PeerPhotoSize) {
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};
}
public putAvatar(div: HTMLElement, peerId: number, photo: UserProfilePhoto.userProfilePhoto | ChatPhoto.chatPhoto, size: PeerPhotoSize, img = new Image(), onlyThumb = false) {
let {cached, loadPromise} = this.loadAvatar(peerId, photo, size);
let renderThumbPromise: Promise<void>;
let callback: () => void;
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');
}
let thumbImage: HTMLImageElement;
if(photo.stripped_thumb) {
thumbImage = new Image();
div.classList.add('avatar-relative');
thumbImage.classList.add('avatar-photo', 'avatar-photo-thumbnail');
img.classList.add('avatar-photo');
const url = appPhotosManager.getPreviewURLFromBytes(photo.stripped_thumb);
renderThumbPromise = renderImageFromUrl(thumbImage, url).then(() => {
replaceContent(div, thumbImage);
});
}
callback = () => {
if(photo.stripped_thumb) {
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) => renderImageFromUrl(img, url/* , false */))
.then(() => callback());
return {cached, loadPromise: renderThumbPromise || renderPromise};
}
// peerId === peerId || title
public putPhoto(div: HTMLElement, peerId: number, isDialog = false, title = '', onlyThumb = false) {
const photo = appPeersManager.getPeerPhoto(peerId);
const size: PeerPhotoSize = 'photo_small';
const avatarAvailable = !!photo;
const avatarRendered = div.firstElementChild && !(div.firstElementChild as HTMLElement).classList.contains('emoji');
const myId = rootScope.myId;
//console.log('loadDialogPhoto location:', location, inputPeer);
if(peerId === myId && isDialog) {
div.innerText = '';
div.dataset.color = '';
div.classList.add('tgico-saved');
div.classList.remove('tgico-deletedaccount');
return;
}
if(peerId > 0) {
const user = appUsersManager.getUser(peerId);
if(user && user.pFlags && user.pFlags.deleted) {
div.innerText = '';
div.dataset.color = appPeersManager.getPeerColorById(peerId);
div.classList.add('tgico-deletedaccount');
div.classList.remove('tgico-saved');
return;
}
}
if(!avatarAvailable || !avatarRendered || !this.savedAvatarURLs[peerId]) {
let color = '';
if(peerId && (peerId !== myId || !isDialog)) {
color = appPeersManager.getPeerColorById(peerId);
}
div.innerText = '';
div.classList.remove('tgico-saved', 'tgico-deletedaccount');
div.dataset.color = color;
let abbr: string;
if(!title) {
const peer = appPeersManager.getPeer(peerId);
abbr = peer.initials ?? '';
} else {
abbr = RichTextProcessor.getAbbreviation(title);
}
div.innerHTML = abbr;
//return Promise.resolve(true);
}
if(avatarAvailable/* && false */) {
return this.putAvatar(div, peerId, photo, size, undefined, onlyThumb);
}
}
}
const appAvatarsManager = new AppAvatarsManager();
export default appAvatarsManager;

154
src/lib/appManagers/appChatsManager.ts

@ -10,17 +10,14 @@ @@ -10,17 +10,14 @@
*/
import { MOUNT_CLASS_TO } from "../../config/debug";
import { numberThousandSplitter } from "../../helpers/number";
import { isObject, safeReplaceObject, copy, deepEqual } from "../../helpers/object";
import { ChannelParticipant, Chat, ChatAdminRights, ChatBannedRights, ChatFull, ChatParticipant, ChatParticipants, ChatPhoto, InputChannel, InputChatPhoto, InputFile, InputPeer, SendMessageAction, Update, Updates } from "../../layer";
import { i18n, LangPackKey } from "../langPack";
import { ChannelParticipant, Chat, ChatAdminRights, ChatBannedRights, ChatParticipant, ChatPhoto, InputChannel, InputChatPhoto, InputFile, InputPeer, Update, Updates } from "../../layer";
import apiManagerProxy from "../mtproto/mtprotoworker";
import apiManager from '../mtproto/mtprotoworker';
import { RichTextProcessor } from "../richtextprocessor";
import rootScope from "../rootScope";
import apiUpdatesManager from "./apiUpdatesManager";
import appPeersManager from "./appPeersManager";
import appProfileManager from "./appProfileManager";
import appStateManager from "./appStateManager";
import appUsersManager from "./appUsersManager";
@ -28,8 +25,6 @@ export type Channel = Chat.channel; @@ -28,8 +25,6 @@ export type Channel = Chat.channel;
export type ChatRights = keyof ChatBannedRights['pFlags'] | keyof ChatAdminRights['pFlags'] | 'change_type' | 'change_permissions' | 'delete_chat' | 'view_participants';
export type UserTyping = Partial<{userId: number, action: SendMessageAction, timeout: number}>;
export class AppChatsManager {
private storage = appStateManager.storages.chats;
@ -38,10 +33,6 @@ export class AppChatsManager { @@ -38,10 +33,6 @@ export class AppChatsManager {
//private channelAccess: any;
//private megagroups: {[id: number]: true};
private megagroupOnlines: {[id: number]: {timestamp: number, onlines: number}};
private typingsInPeer: {[peerId: number]: UserTyping[]};
constructor() {
this.clear();
@ -65,11 +56,7 @@ export class AppChatsManager { @@ -65,11 +56,7 @@ export class AppChatsManager {
chat.default_banned_rights = update.default_banned_rights;
rootScope.dispatchEvent('chat_update', chatId);
}
},
updateUserTyping: this.onUpdateUserTyping,
updateChatUserTyping: this.onUpdateUserTyping,
updateChannelUserTyping: this.onUpdateUserTyping
}
});
appStateManager.getState().then((state) => {
@ -119,81 +106,6 @@ export class AppChatsManager { @@ -119,81 +106,6 @@ export class AppChatsManager {
} else {
this.chats = {};
}
this.megagroupOnlines = {};
this.typingsInPeer = {};
}
private onUpdateUserTyping = (update: Update.updateUserTyping | Update.updateChatUserTyping | Update.updateChannelUserTyping) => {
const fromId = (update as Update.updateUserTyping).user_id || appPeersManager.getPeerId((update as Update.updateChatUserTyping).from_id);
if(rootScope.myId === fromId || update.action._ === 'speakingInGroupCallAction') {
return;
}
const peerId = update._ === 'updateUserTyping' ?
fromId :
-((update as Update.updateChatUserTyping).chat_id || (update as Update.updateChannelUserTyping).channel_id);
const typings = this.typingsInPeer[peerId] ?? (this.typingsInPeer[peerId] = []);
let typing = typings.find(t => t.userId === fromId);
const cancelAction = () => {
delete typing.timeout;
//typings.findAndSplice(t => t === typing);
const idx = typings.indexOf(typing);
if(idx !== -1) {
typings.splice(idx, 1);
}
rootScope.dispatchEvent('peer_typings', {peerId, typings});
if(!typings.length) {
delete this.typingsInPeer[peerId];
}
};
if(typing && typing.timeout !== undefined) {
clearTimeout(typing.timeout);
}
if(update.action._ === 'sendMessageCancelAction') {
if(!typing) {
return;
}
cancelAction();
return;
} else {
if(!typing) {
typing = {
userId: fromId
};
typings.push(typing);
}
//console.log('updateChatUserTyping', update, typings);
typing.action = update.action;
if(!appUsersManager.hasUser(fromId)) {
if(update._ === 'updateChatUserTyping') {
if(update.chat_id && appChatsManager.hasChat(update.chat_id) && !appChatsManager.isChannel(update.chat_id)) {
appProfileManager.getChatFull(update.chat_id);
}
}
//return;
}
appUsersManager.forceUserOnline(fromId);
typing.timeout = window.setTimeout(cancelAction, 6000);
rootScope.dispatchEvent('peer_typings', {peerId, typings});
}
};
public getPeerTypings(peerId: number) {
return this.typingsInPeer[peerId];
}
public saveApiChats(apiChats: any[], override?: boolean) {
@ -486,27 +398,6 @@ export class AppChatsManager { @@ -486,27 +398,6 @@ export class AppChatsManager {
return 'g' + id;
}
public getChatMembersString(id: number) {
const chat = this.getChat(id);
const chatFull = appProfileManager.chatsFull[id];
let count: number;
if(chatFull) {
if(chatFull._ === 'channelFull') {
count = chatFull.participants_count;
} else {
count = (chatFull.participants as ChatParticipants.chatParticipants).participants?.length;
}
} else {
count = chat.participants_count || chat.participants?.participants.length;
}
const isChannel = this.isBroadcast(id);
count = count || 1;
let key: LangPackKey = isChannel ? 'Peer.Status.Subscribers' : 'Peer.Status.Member';
return i18n(key, [numberThousandSplitter(count)]);
}
/* public wrapForFull(id: number, fullChat: any) {
const chatFull = copy(fullChat);
const chat = this.getChat(id);
@ -600,45 +491,6 @@ export class AppChatsManager { @@ -600,45 +491,6 @@ export class AppChatsManager {
});
}
public async getOnlines(id: number): Promise<number> {
if(this.isMegagroup(id)) {
const timestamp = Date.now() / 1000 | 0;
const cached = this.megagroupOnlines[id] ?? (this.megagroupOnlines[id] = {timestamp: 0, onlines: 1});
if((timestamp - cached.timestamp) < 60) {
return cached.onlines;
}
const res = await apiManager.invokeApi('messages.getOnlines', {
peer: this.getChannelInputPeer(id)
});
const onlines = res.onlines ?? 1;
cached.timestamp = timestamp;
cached.onlines = onlines;
return onlines;
} else if(this.isBroadcast(id)) {
return 1;
}
const chatInfo = await appProfileManager.getChatFull(id);
const _participants = (chatInfo as ChatFull.chatFull).participants as ChatParticipants.chatParticipants;
if(_participants && _participants.participants) {
const participants = _participants.participants;
return participants.reduce((acc: number, participant) => {
const user = appUsersManager.getUser(participant.user_id);
if(user && user.status && user.status._ === 'userStatusOnline') {
return acc + 1;
}
return acc;
}, 0);
} else {
return 1;
}
}
private onChatUpdated = (chatId: number, updates: any) => {
//console.log('onChatUpdated', chatId, updates);
@ -647,7 +499,7 @@ export class AppChatsManager { @@ -647,7 +499,7 @@ export class AppChatsManager {
/* updates.updates &&
updates.updates.length && */
this.isChannel(chatId)) {
appProfileManager.invalidateChannelParticipants(chatId);
rootScope.dispatchEvent('invalidate_participants', chatId);
}
};

5
src/lib/appManagers/appImManager.ts

@ -103,6 +103,7 @@ export class AppImManager { @@ -103,6 +103,7 @@ export class AppImManager {
constructor() {
apiUpdatesManager.attach();
appNotificationsManager.start();
this.log = logger('IM', LogTypes.Log | LogTypes.Warn | LogTypes.Debug | LogTypes.Error);
@ -1035,7 +1036,7 @@ export class AppImManager { @@ -1035,7 +1036,7 @@ export class AppImManager {
public getPeerTyping(peerId: number, container?: HTMLElement) {
if(!appUsersManager.isBot(peerId)) {
const typings = appChatsManager.getPeerTypings(peerId);
const typings = appProfileManager.getPeerTypings(peerId);
if(!typings || !typings.length) {
return;
}
@ -1152,7 +1153,7 @@ export class AppImManager { @@ -1152,7 +1153,7 @@ export class AppImManager {
const participants_count = chatInfo.participants_count || (chatInfo.participants && chatInfo.participants.participants && chatInfo.participants.participants.length) || 1;
//if(participants_count) {
subtitle = appChatsManager.getChatMembersString(-peerId);
subtitle = appProfileManager.getChatMembersString(-peerId);
if(participants_count < 2) return subtitle;
/* const onlines = await appChatsManager.getOnlines(chat.id);

5
src/lib/appManagers/appMessagesManager.ts

@ -53,6 +53,7 @@ import htmlToDocumentFragment from "../../helpers/dom/htmlToDocumentFragment"; @@ -53,6 +53,7 @@ import htmlToDocumentFragment from "../../helpers/dom/htmlToDocumentFragment";
import htmlToSpan from "../../helpers/dom/htmlToSpan";
import { REPLIES_PEER_ID } from "../mtproto/mtproto_config";
import formatCallDuration from "../../helpers/formatCallDuration";
import appAvatarsManager from "./appAvatarsManager";
//console.trace('include');
// TODO: если удалить сообщение в непрогруженном диалоге, то при обновлении, из-за стейта, последнего сообщения в чатлисте не будет
@ -304,8 +305,6 @@ export class AppMessagesManager { @@ -304,8 +305,6 @@ export class AppMessagesManager {
this.maxSeenId = state.maxSeenMsgId;
}
});
appNotificationsManager.start();
}
public construct() {
@ -4546,7 +4545,7 @@ export class AppMessagesManager { @@ -4546,7 +4545,7 @@ export class AppMessagesManager {
const peerPhoto = appPeersManager.getPeerPhoto(peerId);
if(peerPhoto) {
appProfileManager.loadAvatar(peerId, peerPhoto, 'photo_small').loadPromise.then(url => {
appAvatarsManager.loadAvatar(peerId, peerPhoto, 'photo_small').loadPromise.then(url => {
if(message.pFlags.unread) {
notification.image = url;
appNotificationsManager.notify(notification);

2
src/lib/appManagers/appNotificationsManager.ts

@ -706,7 +706,6 @@ export class AppNotificationsManager { @@ -706,7 +706,6 @@ export class AppNotificationsManager {
}
private registerDevice(tokenData: PushSubscriptionNotify) {
return;
if(this.registeredDevice && deepEqual(this.registeredDevice, tokenData)) {
return false;
}
@ -725,7 +724,6 @@ export class AppNotificationsManager { @@ -725,7 +724,6 @@ export class AppNotificationsManager {
}
private unregisterDevice(tokenData: PushSubscriptionNotify) {
return;
if(!this.registeredDevice) {
return false;
}

280
src/lib/appManagers/appProfileManager.ts

@ -11,10 +11,9 @@ @@ -11,10 +11,9 @@
import { MOUNT_CLASS_TO } from "../../config/debug";
import { tsNow } from "../../helpers/date";
import renderImageFromUrl from "../../helpers/dom/renderImageFromUrl";
import replaceContent from "../../helpers/dom/replaceContent";
import sequentialDom from "../../helpers/sequentialDom";
import { ChannelParticipantsFilter, ChannelsChannelParticipants, Chat, ChatFull, ChatParticipants, ChatPhoto, ExportedChatInvite, InputChannel, InputFile, InputFileLocation, PhotoSize, Update, UserFull, UserProfilePhoto } from "../../layer";
import { numberThousandSplitter } from "../../helpers/number";
import { ChannelParticipantsFilter, ChannelsChannelParticipants, Chat, ChatFull, ChatParticipants, ChatPhoto, ExportedChatInvite, InputChannel, InputFile, InputFileLocation, PhotoSize, SendMessageAction, Update, UserFull, UserProfilePhoto } from "../../layer";
import { LangPackKey, i18n } from "../langPack";
//import apiManager from '../mtproto/apiManager';
import apiManager from '../mtproto/mtprotoworker';
import { RichTextProcessor } from "../richtextprocessor";
@ -22,13 +21,12 @@ import rootScope from "../rootScope"; @@ -22,13 +21,12 @@ import rootScope from "../rootScope";
import SearchIndex from "../searchIndex";
import apiUpdatesManager from "./apiUpdatesManager";
import appChatsManager from "./appChatsManager";
import appDownloadManager from "./appDownloadManager";
import appNotificationsManager from "./appNotificationsManager";
import appPeersManager from "./appPeersManager";
import appPhotosManager, { MyPhoto } from "./appPhotosManager";
import appPhotosManager from "./appPhotosManager";
import appUsersManager, { User } from "./appUsersManager";
type PeerPhotoSize = 'photo_small' | 'photo_big';
export type UserTyping = Partial<{userId: number, action: SendMessageAction, timeout: number}>;
export class AppProfileManager {
//private botInfos: any = {};
@ -36,11 +34,9 @@ export class AppProfileManager { @@ -36,11 +34,9 @@ export class AppProfileManager {
public chatsFull: {[id: string]: ChatFull} = {};
private fullPromises: {[peerId: string]: Promise<ChatFull.chatFull | ChatFull.channelFull | UserFull>} = {};
private savedAvatarURLs: {
[peerId: number]: {
[size in PeerPhotoSize]?: string | Promise<string>
}
} = {};
private megagroupOnlines: {[id: number]: {timestamp: number, onlines: number}};
private typingsInPeer: {[peerId: number]: UserTyping[]};
constructor() {
rootScope.addMultipleEventsListeners({
@ -93,7 +89,11 @@ export class AppProfileManager { @@ -93,7 +89,11 @@ export class AppProfileManager {
}
}
}
}
},
updateUserTyping: this.onUpdateUserTyping,
updateChatUserTyping: this.onUpdateUserTyping,
updateChannelUserTyping: this.onUpdateUserTyping
});
rootScope.addEventListener('chat_update', (chatId) => {
@ -121,6 +121,13 @@ export class AppProfileManager { @@ -121,6 +121,13 @@ export class AppProfileManager {
rootScope.dispatchEvent('chat_full_update', chatId);
}
});
rootScope.addEventListener('invalidate_participants', chatId => {
this.invalidateChannelParticipants(chatId);
});
this.megagroupOnlines = {};
this.typingsInPeer = {};
}
/* public saveBotInfo(botInfo: any) {
@ -457,177 +464,144 @@ export class AppProfileManager { @@ -457,177 +464,144 @@ export class AppProfileManager {
});
}
public removeFromAvatarsCache(peerId: number) {
if(this.savedAvatarURLs[peerId]) {
delete this.savedAvatarURLs[peerId];
public getChatMembersString(id: number) {
const chat = appChatsManager.getChat(id);
const chatFull = this.chatsFull[id];
let count: number;
if(chatFull) {
if(chatFull._ === 'channelFull') {
count = chatFull.participants_count;
} else {
count = (chatFull.participants as ChatParticipants.chatParticipants).participants?.length;
}
} else {
count = chat.participants_count || chat.participants?.participants.length;
}
}
public loadAvatar(peerId: number, photo: UserProfilePhoto.userProfilePhoto | ChatPhoto.chatPhoto, size: PeerPhotoSize) {
const inputPeer = appPeersManager.getInputPeerById(peerId);
const isChannel = appChatsManager.isBroadcast(id);
count = count || 1;
let key: LangPackKey = isChannel ? 'Peer.Status.Subscribers' : 'Peer.Status.Member';
return i18n(key, [numberThousandSplitter(count)]);
}
let cached = false;
let getAvatarPromise: Promise<string>;
let saved = this.savedAvatarURLs[peerId];
if(!saved || !saved[size]) {
if(!saved) {
saved = this.savedAvatarURLs[peerId] = {};
public async getOnlines(id: number): Promise<number> {
if(appChatsManager.isMegagroup(id)) {
const timestamp = Date.now() / 1000 | 0;
const cached = this.megagroupOnlines[id] ?? (this.megagroupOnlines[id] = {timestamp: 0, onlines: 1});
if((timestamp - cached.timestamp) < 60) {
return cached.onlines;
}
//console.warn('will invoke downloadSmallFile:', peerId);
const peerPhotoFileLocation: InputFileLocation.inputPeerPhotoFileLocation = {
_: 'inputPeerPhotoFileLocation',
pFlags: {},
peer: inputPeer,
photo_id: photo.photo_id
};
const res = await apiManager.invokeApi('messages.getOnlines', {
peer: appChatsManager.getChannelInputPeer(id)
});
if(size === 'photo_big') {
peerPhotoFileLocation.pFlags.big = true;
}
const onlines = res.onlines ?? 1;
cached.timestamp = timestamp;
cached.onlines = onlines;
const downloadOptions = {dcId: photo.dc_id, location: peerPhotoFileLocation};
return onlines;
} else if(appChatsManager.isBroadcast(id)) {
return 1;
}
/* let str: string;
const time = Date.now();
if(peerId === 0) {
str = `download avatar ${peerId}`;
} */
const chatInfo = await this.getChatFull(id);
const _participants = (chatInfo as ChatFull.chatFull).participants as ChatParticipants.chatParticipants;
if(_participants && _participants.participants) {
const participants = _participants.participants;
const promise = appDownloadManager.download(downloadOptions);
getAvatarPromise = saved[size] = promise.then(blob => {
return saved[size] = URL.createObjectURL(blob);
return participants.reduce((acc: number, participant) => {
const user = appUsersManager.getUser(participant.user_id);
if(user && user.status && user.status._ === 'userStatusOnline') {
return acc + 1;
}
/* if(str) {
console.log(str, Date.now() / 1000, Date.now() - time);
} */
});
} else if(typeof(saved[size]) !== 'string') {
getAvatarPromise = saved[size] as Promise<any>;
return acc;
}, 0);
} else {
getAvatarPromise = Promise.resolve(saved[size]);
cached = true;
return 1;
}
return {cached, loadPromise: getAvatarPromise};
}
public putAvatar(div: HTMLElement, peerId: number, photo: UserProfilePhoto.userProfilePhoto | ChatPhoto.chatPhoto, size: PeerPhotoSize, img = new Image(), onlyThumb = false) {
let {cached, loadPromise} = this.loadAvatar(peerId, photo, size);
let renderThumbPromise: Promise<void>;
let callback: () => void;
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');
private onUpdateUserTyping = (update: Update.updateUserTyping | Update.updateChatUserTyping | Update.updateChannelUserTyping) => {
const fromId = (update as Update.updateUserTyping).user_id || appPeersManager.getPeerId((update as Update.updateChatUserTyping).from_id);
if(rootScope.myId === fromId || update.action._ === 'speakingInGroupCallAction') {
return;
}
const peerId = update._ === 'updateUserTyping' ?
fromId :
-((update as Update.updateChatUserTyping).chat_id || (update as Update.updateChannelUserTyping).channel_id);
const typings = this.typingsInPeer[peerId] ?? (this.typingsInPeer[peerId] = []);
let typing = typings.find(t => t.userId === fromId);
const cancelAction = () => {
delete typing.timeout;
//typings.findAndSplice(t => t === typing);
const idx = typings.indexOf(typing);
if(idx !== -1) {
typings.splice(idx, 1);
}
let thumbImage: HTMLImageElement;
if(photo.stripped_thumb) {
thumbImage = new Image();
div.classList.add('avatar-relative');
thumbImage.classList.add('avatar-photo', 'avatar-photo-thumbnail');
img.classList.add('avatar-photo');
const url = appPhotosManager.getPreviewURLFromBytes(photo.stripped_thumb);
renderThumbPromise = renderImageFromUrl(thumbImage, url).then(() => {
replaceContent(div, thumbImage);
});
}
rootScope.dispatchEvent('peer_typings', {peerId, typings});
callback = () => {
if(photo.stripped_thumb) {
div.append(img);
} else {
replaceContent(div, img);
}
if(!typings.length) {
delete this.typingsInPeer[peerId];
}
};
setTimeout(() => {
if(div.childElementCount) {
sequentialDom.mutateElement(img, () => {
div.dataset.color = '';
if(animate) {
img.classList.remove('fade-in');
}
if(thumbImage) {
thumbImage.remove();
}
});
}
}, animate ? 200 : 0);
};
if(typing && typing.timeout !== undefined) {
clearTimeout(typing.timeout);
}
const renderPromise = loadPromise
.then((url) => renderImageFromUrl(img, url/* , false */))
.then(() => callback());
return {cached, loadPromise: renderThumbPromise || renderPromise};
}
// peerId === peerId || title
public putPhoto(div: HTMLElement, peerId: number, isDialog = false, title = '', onlyThumb = false) {
const photo = appPeersManager.getPeerPhoto(peerId);
if(update.action._ === 'sendMessageCancelAction') {
if(!typing) {
return;
}
const size: PeerPhotoSize = 'photo_small';
const avatarAvailable = !!photo;
const avatarRendered = div.firstElementChild && !(div.firstElementChild as HTMLElement).classList.contains('emoji');
const myId = rootScope.myId;
//console.log('loadDialogPhoto location:', location, inputPeer);
if(peerId === myId && isDialog) {
div.innerText = '';
div.dataset.color = '';
div.classList.add('tgico-saved');
div.classList.remove('tgico-deletedaccount');
cancelAction();
return;
}
if(peerId > 0) {
const user = appUsersManager.getUser(peerId);
if(user && user.pFlags && user.pFlags.deleted) {
div.innerText = '';
div.dataset.color = appPeersManager.getPeerColorById(peerId);
div.classList.add('tgico-deletedaccount');
div.classList.remove('tgico-saved');
return;
}
if(!typing) {
typing = {
userId: fromId
};
typings.push(typing);
}
if(!avatarAvailable || !avatarRendered || !this.savedAvatarURLs[peerId]) {
let color = '';
if(peerId && (peerId !== myId || !isDialog)) {
color = appPeersManager.getPeerColorById(peerId);
//console.log('updateChatUserTyping', update, typings);
typing.action = update.action;
const hasUser = appUsersManager.hasUser(fromId);
if(!hasUser) {
// let's load user here
if(update._ === 'updateChatUserTyping') {
if(update.chat_id && appChatsManager.hasChat(update.chat_id) && !appChatsManager.isChannel(update.chat_id)) {
appProfileManager.getChatFull(update.chat_id).then(() => {
if(typing.timeout !== undefined && appUsersManager.hasUser(fromId)) {
rootScope.dispatchEvent('peer_typings', {peerId, typings});
}
});
}
}
div.innerText = '';
div.classList.remove('tgico-saved', 'tgico-deletedaccount');
div.dataset.color = color;
let abbr: string;
if(!title) {
const peer = appPeersManager.getPeer(peerId);
abbr = peer.initials ?? '';
} else {
abbr = RichTextProcessor.getAbbreviation(title);
}
div.innerHTML = abbr;
//return Promise.resolve(true);
//return;
} else {
appUsersManager.forceUserOnline(fromId);
}
if(avatarAvailable/* && false */) {
return this.putAvatar(div, peerId, photo, size, undefined, onlyThumb);
typing.timeout = window.setTimeout(cancelAction, 6000);
if(hasUser) {
rootScope.dispatchEvent('peer_typings', {peerId, typings});
}
};
public getPeerTypings(peerId: number) {
return this.typingsInPeer[peerId];
}
}

3
src/lib/rootScope.ts

@ -10,7 +10,7 @@ import type { AppMessagesManager, Dialog, MessagesStorage } from "./appManagers/ @@ -10,7 +10,7 @@ import type { AppMessagesManager, Dialog, MessagesStorage } from "./appManagers/
import type { Poll, PollResults } from "./appManagers/appPollsManager";
import type { MyDialogFilter } from "./storages/filters";
import type { ConnectionStatusChange } from "../types";
import type { UserTyping } from "./appManagers/appChatsManager";
import type { UserTyping } from "./appManagers/appProfileManager";
import type Chat from "../components/chat/chat";
import type { UserAuth } from "./mtproto/mtproto_config";
import type { State, Theme } from "./appManagers/appStateManager";
@ -86,6 +86,7 @@ export type BroadcastEvents = { @@ -86,6 +86,7 @@ export type BroadcastEvents = {
'chat_full_update': number,
'poll_update': {poll: Poll, results: PollResults},
'chat_update': number,
'invalidate_participants': number,
//'channel_settings': {channelId: number},
'webpage_updated': {id: string, msgs: number[]},

17
src/pages/pageAuthCode.ts

@ -9,10 +9,7 @@ import { AuthSentCode, AuthSentCodeType, AuthSignIn } from '../layer'; @@ -9,10 +9,7 @@ import { AuthSentCode, AuthSentCodeType, AuthSignIn } from '../layer';
import appStateManager from '../lib/appManagers/appStateManager';
import apiManager from '../lib/mtproto/mtprotoworker';
import Page from './page';
import pageIm from './pageIm';
import pagePassword from './pagePassword';
import pageSignIn from './pageSignIn';
import pageSignUp from './pageSignUp';
import TrackingMonkey from '../components/monkeys/tracking';
import CodeInputField from '../components/codeInputField';
import { i18n, LangPackKey } from '../lib/langPack';
@ -72,15 +69,19 @@ let onFirstMount = (): Promise<any> => { @@ -72,15 +69,19 @@ let onFirstMount = (): Promise<any> => {
case 'auth.authorization':
apiManager.setUserAuth(response.user.id);
pageIm.mount();
import('./pageIm').then(m => {
m.default.mount();
});
cleanup();
break;
case 'auth.authorizationSignUpRequired':
//console.log('Registration needed!');
pageSignUp.mount({
'phone_number': authCode.phone_number,
'phone_code_hash': authCode.phone_code_hash
import('./pageSignUp').then(m => {
m.default.mount({
'phone_number': authCode.phone_number,
'phone_code_hash': authCode.phone_code_hash
});
});
cleanup();
@ -96,7 +97,7 @@ let onFirstMount = (): Promise<any> => { @@ -96,7 +97,7 @@ let onFirstMount = (): Promise<any> => {
//console.warn('pageAuthCode: SESSION_PASSWORD_NEEDED');
good = true;
err.handled = true;
await pagePassword.mount();
await (await import('./pagePassword')).default.mount(); // lol
setTimeout(() => {
codeInput.value = '';
}, 300);

5
src/pages/pagePassword.ts

@ -10,7 +10,6 @@ import { AccountPassword } from '../layer'; @@ -10,7 +10,6 @@ import { AccountPassword } from '../layer';
import appStateManager from '../lib/appManagers/appStateManager';
import passwordManager from '../lib/mtproto/passwordManager';
import Page from './page';
import pageIm from './pageIm';
import Button from '../components/button';
import PasswordInputField from '../components/passwordInputField';
import PasswordMonkey from '../components/monkeys/password';
@ -91,7 +90,9 @@ let onFirstMount = (): Promise<any> => { @@ -91,7 +90,9 @@ let onFirstMount = (): Promise<any> => {
switch(response._) {
case 'auth.authorization':
clearInterval(getStateInterval);
pageIm.mount();
import('./pageIm').then(m => {
m.default.mount();
});
if(monkey) monkey.remove();
break;
default:

5
src/pages/pageSignUp.ts

@ -18,7 +18,6 @@ import apiManager from '../lib/mtproto/mtprotoworker'; @@ -18,7 +18,6 @@ import apiManager from '../lib/mtproto/mtprotoworker';
import RichTextProcessor from '../lib/richtextprocessor';
import LoginPage from './loginPage';
import Page from './page';
import pageIm from './pageIm';
import blurActiveElement from '../helpers/dom/blurActiveElement';
import replaceContent from '../helpers/dom/replaceContent';
@ -135,7 +134,9 @@ const onFirstMount = () => import('../lib/appManagers/appProfileManager').then(i @@ -135,7 +134,9 @@ const onFirstMount = () => import('../lib/appManagers/appProfileManager').then(i
apiManager.setUserAuth(response.user.id);
sendAvatar().finally(() => {
pageIm.mount();
import('./pageIm').then(m => {
m.default.mount();
});
});
break;

Loading…
Cancel
Save