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.
674 lines
22 KiB
674 lines
22 KiB
/* |
|
* https://github.com/morethanwords/tweb |
|
* Copyright (C) 2019-2021 Eduard Kuzmenko |
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE |
|
* |
|
* Originally from: |
|
* https://github.com/zhukov/webogram |
|
* Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com> |
|
* https://github.com/zhukov/webogram/blob/master/LICENSE |
|
*/ |
|
|
|
import { MOUNT_CLASS_TO } from "../../config/debug"; |
|
import { tsNow } from "../../helpers/date"; |
|
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"; |
|
import rootScope from "../rootScope"; |
|
import SearchIndex from "../searchIndex"; |
|
import apiUpdatesManager from "./apiUpdatesManager"; |
|
import appChatsManager from "./appChatsManager"; |
|
import appMessagesIdsManager from "./appMessagesIdsManager"; |
|
import appNotificationsManager from "./appNotificationsManager"; |
|
import appPeersManager from "./appPeersManager"; |
|
import appPhotosManager from "./appPhotosManager"; |
|
import appUsersManager, { MyTopPeer, User } from "./appUsersManager"; |
|
|
|
export type UserTyping = Partial<{userId: UserId, action: SendMessageAction, timeout: number}>; |
|
|
|
export class AppProfileManager { |
|
//private botInfos: any = {}; |
|
public usersFull: {[id: UserId]: UserFull.userFull} = {}; |
|
public chatsFull: {[id: ChatId]: ChatFull} = {}; |
|
private fullPromises: {[peerId: PeerId]: Promise<ChatFull.chatFull | ChatFull.channelFull | UserFull>} = {}; |
|
|
|
private megagroupOnlines: {[id: ChatId]: {timestamp: number, onlines: number}}; |
|
|
|
private typingsInPeer: {[peerId: PeerId]: UserTyping[]}; |
|
|
|
constructor() { |
|
rootScope.addMultipleEventsListeners({ |
|
updateChatParticipants: (update) => { |
|
const participants = update.participants; |
|
if(participants._ === 'chatParticipants') { |
|
const chatId = participants.chat_id; |
|
const chatFull = this.chatsFull[chatId] as ChatFull.chatFull; |
|
if(chatFull !== undefined) { |
|
chatFull.participants = participants; |
|
rootScope.dispatchEvent('chat_full_update', chatId); |
|
} |
|
} |
|
}, |
|
|
|
updateChatParticipantAdd: (update) => { |
|
const chatFull = this.chatsFull[update.chat_id] as ChatFull.chatFull; |
|
if(chatFull !== undefined) { |
|
const _participants = chatFull.participants as ChatParticipants.chatParticipants; |
|
const participants = _participants.participants || []; |
|
for(let i = 0, length = participants.length; i < length; i++) { |
|
if(participants[i].user_id === update.user_id) { |
|
return; |
|
} |
|
} |
|
|
|
participants.push({ |
|
_: 'chatParticipant', |
|
user_id: update.user_id, |
|
inviter_id: update.inviter_id, |
|
date: tsNow(true) |
|
}); |
|
|
|
_participants.version = update.version; |
|
rootScope.dispatchEvent('chat_full_update', update.chat_id); |
|
} |
|
}, |
|
|
|
updateChatParticipantDelete: (update) => { |
|
const chatFull = this.chatsFull[update.chat_id] as ChatFull.chatFull; |
|
if(chatFull !== undefined) { |
|
const _participants = chatFull.participants as ChatParticipants.chatParticipants; |
|
const participants = _participants.participants || []; |
|
for(let i = 0, length = participants.length; i < length; i++) { |
|
if(participants[i].user_id === update.user_id) { |
|
participants.splice(i, 1); |
|
_participants.version = update.version; |
|
rootScope.dispatchEvent('chat_full_update', update.chat_id); |
|
return; |
|
} |
|
} |
|
} |
|
}, |
|
|
|
updateUserTyping: this.onUpdateUserTyping, |
|
updateChatUserTyping: this.onUpdateUserTyping, |
|
updateChannelUserTyping: this.onUpdateUserTyping, |
|
|
|
updatePeerBlocked: this.onUpdatePeerBlocked |
|
}); |
|
|
|
rootScope.addEventListener('chat_update', (chatId) => { |
|
const fullChat = this.chatsFull[chatId]; |
|
const chat: Chat.chat = appChatsManager.getChat(chatId); |
|
if(!chat.photo || !fullChat) { |
|
return; |
|
} |
|
|
|
const emptyPhoto = chat.photo._ === 'chatPhotoEmpty'; |
|
//////console.log('chat_update:', fullChat); |
|
if(fullChat.chat_photo && emptyPhoto !== (fullChat.chat_photo._ === 'photoEmpty')) { |
|
delete this.chatsFull[chatId]; |
|
rootScope.dispatchEvent('chat_full_update', chatId); |
|
return; |
|
} |
|
if(emptyPhoto) { |
|
return; |
|
} |
|
|
|
const photoId = (chat.photo as ChatPhoto.chatPhoto).photo_id; |
|
const chatFullPhotoId = fullChat.chat_photo?.id; |
|
if(chatFullPhotoId !== photoId) { |
|
delete this.chatsFull[chatId]; |
|
rootScope.dispatchEvent('chat_full_update', chatId); |
|
} |
|
}); |
|
|
|
rootScope.addEventListener('invalidate_participants', (chatId) => { |
|
this.invalidateChannelParticipants(chatId); |
|
}); |
|
|
|
this.megagroupOnlines = {}; |
|
this.typingsInPeer = {}; |
|
} |
|
|
|
/* public saveBotInfo(botInfo: any) { |
|
const botId = botInfo && botInfo.user_id; |
|
if(!botId) { |
|
return null; |
|
} |
|
|
|
const commands: any = {}; |
|
botInfo.commands.forEach((botCommand: any) => { |
|
commands[botCommand.command] = botCommand.description; |
|
}); |
|
|
|
return this.botInfos[botId] = { |
|
id: botId, |
|
version: botInfo.version, |
|
shareText: botInfo.share_text, |
|
description: botInfo.description, |
|
commands: commands |
|
}; |
|
} */ |
|
|
|
public getProfile(id: UserId, override?: true): Promise<UserFull> { |
|
if(this.usersFull[id] && !override) { |
|
return Promise.resolve(this.usersFull[id]); |
|
} |
|
|
|
const peerId = id.toPeerId(false); |
|
if(this.fullPromises[peerId]) { |
|
return this.fullPromises[peerId] as any; |
|
} |
|
|
|
return this.fullPromises[peerId] = apiManager.invokeApi('users.getFullUser', { |
|
id: appUsersManager.getUserInput(id) |
|
}).then((userFull) => { |
|
const user = userFull.user as User; |
|
appUsersManager.saveApiUser(user, true); |
|
|
|
if(userFull.profile_photo) { |
|
userFull.profile_photo = appPhotosManager.savePhoto(userFull.profile_photo, {type: 'profilePhoto', peerId}); |
|
} |
|
|
|
if(userFull.about !== undefined) { |
|
userFull.rAbout = RichTextProcessor.wrapRichText(userFull.about, {noLinebreaks: true}); |
|
} |
|
|
|
appNotificationsManager.savePeerSettings({ |
|
peerId, |
|
settings: userFull.notify_settings |
|
}); |
|
|
|
/* if(userFull.bot_info) { |
|
userFull.bot_info = this.saveBotInfo(userFull.bot_info) as any; |
|
} */ |
|
|
|
//appMessagesManager.savePinnedMessage(id, userFull.pinned_msg_id); |
|
|
|
delete this.fullPromises[peerId]; |
|
|
|
return this.usersFull[id] = userFull; |
|
}) as any; |
|
} |
|
|
|
public getProfileByPeerId(peerId: PeerId, override?: true): Promise<ChatFull.chatFull | ChatFull.channelFull | UserFull.userFull> { |
|
if(appPeersManager.isAnyChat(peerId)) return this.getChatFull(peerId.toChatId(), override); |
|
else return this.getProfile(peerId.toUserId(), override); |
|
} |
|
|
|
public getFullPhoto(peerId: PeerId) { |
|
return this.getProfileByPeerId(peerId).then(profile => { |
|
switch(profile._) { |
|
case 'userFull': |
|
return profile.profile_photo; |
|
case 'channelFull': |
|
case 'chatFull': |
|
return profile.chat_photo; |
|
} |
|
}); |
|
} |
|
|
|
/* public getPeerBots(peerId: PeerId) { |
|
var peerBots: any[] = []; |
|
if(peerId >= 0 && !appUsersManager.isBot(peerId) || |
|
(appPeersManager.isChannel(peerId) && !appPeersManager.isMegagroup(peerId))) { |
|
return Promise.resolve(peerBots); |
|
} |
|
if(peerId >= 0) { |
|
return this.getProfile(peerId).then((userFull: any) => { |
|
var botInfo = userFull.bot_info; |
|
if(botInfo && botInfo._ !== 'botInfoEmpty') { |
|
peerBots.push(botInfo); |
|
} |
|
return peerBots; |
|
}); |
|
} |
|
|
|
return this.getChatFull(peerId.toChatId()).then((chatFull: any) => { |
|
chatFull.bot_info.forEach((botInfo: any) => { |
|
peerBots.push(this.saveBotInfo(botInfo)) |
|
}); |
|
return peerBots; |
|
}); |
|
} */ |
|
|
|
public getChatFull(id: ChatId, override?: true): Promise<ChatFull.chatFull | ChatFull.channelFull> { |
|
if(appChatsManager.isChannel(id)) { |
|
return this.getChannelFull(id, override); |
|
} |
|
|
|
const fullChat = this.chatsFull[id] as ChatFull.chatFull; |
|
if(fullChat && !override) { |
|
const chat = appChatsManager.getChat(id); |
|
if(chat.version === (fullChat.participants as ChatParticipants.chatParticipants).version || |
|
chat.pFlags.left) { |
|
return Promise.resolve(fullChat); |
|
} |
|
} |
|
|
|
const peerId = id.toPeerId(true); |
|
if(this.fullPromises[peerId] !== undefined) { |
|
return this.fullPromises[peerId] as any; |
|
} |
|
|
|
// console.trace(dT(), 'Get chat full', id, appChatsManager.getChat(id)) |
|
return this.fullPromises[peerId] = apiManager.invokeApi('messages.getFullChat', { |
|
chat_id: id |
|
}).then((result) => { |
|
appChatsManager.saveApiChats(result.chats, true); |
|
appUsersManager.saveApiUsers(result.users); |
|
const fullChat = result.full_chat as ChatFull.chatFull; |
|
if(fullChat && fullChat.chat_photo && fullChat.chat_photo.id) { |
|
fullChat.chat_photo = appPhotosManager.savePhoto(fullChat.chat_photo, {type: 'profilePhoto', peerId}); |
|
} |
|
|
|
//appMessagesManager.savePinnedMessage(peerId, fullChat.pinned_msg_id); |
|
appNotificationsManager.savePeerSettings({ |
|
peerId, |
|
settings: fullChat.notify_settings |
|
}); |
|
delete this.fullPromises[peerId]; |
|
this.chatsFull[id] = fullChat; |
|
rootScope.dispatchEvent('chat_full_update', id); |
|
|
|
return fullChat; |
|
}) as any; |
|
} |
|
|
|
public getChatInviteLink(id: ChatId, force?: boolean) { |
|
return this.getChatFull(id).then((chatFull) => { |
|
if(!force && |
|
chatFull.exported_invite && |
|
chatFull.exported_invite._ == 'chatInviteExported') { |
|
return chatFull.exported_invite.link; |
|
} |
|
|
|
return apiManager.invokeApi('messages.exportChatInvite', { |
|
peer: appPeersManager.getInputPeerById(id.toPeerId(true)) |
|
}).then((exportedInvite) => { |
|
if(this.chatsFull[id] !== undefined) { |
|
this.chatsFull[id].exported_invite = exportedInvite; |
|
} |
|
|
|
return (exportedInvite as ExportedChatInvite.chatInviteExported).link; |
|
}); |
|
}); |
|
} |
|
|
|
public getChannelParticipants(id: ChatId, filter: ChannelParticipantsFilter = {_: 'channelParticipantsRecent'}, limit = 200, offset = 0) { |
|
if(filter._ === 'channelParticipantsRecent') { |
|
const chat = appChatsManager.getChat(id); |
|
if(chat && |
|
chat.pFlags && ( |
|
chat.pFlags.kicked || |
|
chat.pFlags.broadcast && !chat.pFlags.creator && !chat.admin_rights |
|
)) { |
|
return Promise.reject(); |
|
} |
|
} |
|
|
|
return apiManager.invokeApiCacheable('channels.getParticipants', { |
|
channel: appChatsManager.getChannelInput(id), |
|
filter, |
|
offset, |
|
limit, |
|
hash: '0' |
|
}, {cacheSeconds: 60}).then(result => { |
|
appUsersManager.saveApiUsers((result as ChannelsChannelParticipants.channelsChannelParticipants).users); |
|
return result as ChannelsChannelParticipants.channelsChannelParticipants; |
|
}); |
|
/* let maybeAddSelf = (participants: any[]) => { |
|
let chat = appChatsManager.getChat(id); |
|
let selfMustBeFirst = filter._ === 'channelParticipantsRecent' && |
|
!offset && |
|
!chat.pFlags.kicked && |
|
!chat.pFlags.left; |
|
|
|
if(selfMustBeFirst) { |
|
participants = copy(participants); |
|
let myID = appUsersManager.getSelf().id; |
|
let myIndex = participants.findIndex(p => p.user_id === myID); |
|
let myParticipant; |
|
|
|
if(myIndex !== -1) { |
|
myParticipant = participants[myIndex]; |
|
participants.splice(myIndex, 1); |
|
} else { |
|
myParticipant = {_: 'channelParticipantSelf', user_id: myID}; |
|
} |
|
|
|
participants.unshift(myParticipant); |
|
} |
|
|
|
return participants; |
|
} */ |
|
} |
|
|
|
public getChannelParticipant(id: ChatId, peerId: PeerId) { |
|
return apiManager.invokeApiSingle('channels.getParticipant', { |
|
channel: appChatsManager.getChannelInput(id), |
|
participant: appPeersManager.getInputPeerById(peerId), |
|
}).then(channelParticipant => { |
|
appUsersManager.saveApiUsers(channelParticipant.users); |
|
return channelParticipant.participant; |
|
}); |
|
} |
|
|
|
public getChannelFull(id: ChatId, override?: true): Promise<ChatFull.channelFull> { |
|
if(this.chatsFull[id] !== undefined && !override) { |
|
return Promise.resolve(this.chatsFull[id] as ChatFull.channelFull); |
|
} |
|
|
|
const peerId = id.toPeerId(true); |
|
if(this.fullPromises[peerId] !== undefined) { |
|
return this.fullPromises[peerId] as any; |
|
} |
|
|
|
return this.fullPromises[peerId] = apiManager.invokeApi('channels.getFullChannel', { |
|
channel: appChatsManager.getChannelInput(id) |
|
}).then((result) => { |
|
appChatsManager.saveApiChats(result.chats, true); |
|
appUsersManager.saveApiUsers(result.users); |
|
const fullChannel = result.full_chat as ChatFull.channelFull; |
|
if(fullChannel && fullChannel.chat_photo.id) { |
|
fullChannel.chat_photo = appPhotosManager.savePhoto(fullChannel.chat_photo, {type: 'profilePhoto', peerId}); |
|
//appPhotosManager.savePhoto(fullChannel.chat_photo); |
|
} |
|
appNotificationsManager.savePeerSettings({ |
|
peerId, |
|
settings: fullChannel.notify_settings |
|
}); |
|
|
|
delete this.fullPromises[peerId]; |
|
this.chatsFull[id] = fullChannel; |
|
rootScope.dispatchEvent('chat_full_update', id); |
|
|
|
return fullChannel; |
|
}, (error) => { |
|
switch (error.type) { |
|
case 'CHANNEL_PRIVATE': |
|
let channel = appChatsManager.getChat(id); |
|
channel = {_: 'channelForbidden', access_hash: channel.access_hash, title: channel.title}; |
|
apiUpdatesManager.processUpdateMessage({ |
|
_: 'updates', |
|
updates: [{ |
|
_: 'updateChannel', |
|
channel_id: id |
|
} as Update.updateChannel], |
|
chats: [channel], |
|
users: [] |
|
}); |
|
break; |
|
} |
|
|
|
return Promise.reject(error); |
|
}) as any; |
|
} |
|
|
|
public getMentions(chatId: ChatId, query: string, threadId?: number): Promise<PeerId[]> { |
|
const processUserIds = (topPeers: MyTopPeer[]) => { |
|
const startsWithAt = query.charAt(0) === '@'; |
|
if(startsWithAt) query = query.slice(1); |
|
/* const startsWithAt = query.charAt(0) === '@'; |
|
if(startsWithAt) query = query.slice(1); |
|
|
|
const index = new SearchIndex<number>(!startsWithAt, !startsWithAt); */ |
|
const index = new SearchIndex<PeerId>({ |
|
ignoreCase: true |
|
}); |
|
|
|
const ratingMap: Map<PeerId, number> = new Map(); |
|
topPeers.forEach(peer => { |
|
index.indexObject(peer.id, appUsersManager.getUserSearchText(peer.id)); |
|
ratingMap.set(peer.id, peer.rating); |
|
}); |
|
|
|
const peerIds = Array.from(index.search(query)); |
|
peerIds.sort((a, b) => ratingMap.get(b) - ratingMap.get(a)); |
|
return peerIds; |
|
}; |
|
|
|
let promise: Promise<PeerId[]>; |
|
if(appChatsManager.isChannel(chatId)) { |
|
promise = this.getChannelParticipants(chatId, { |
|
_: 'channelParticipantsMentions', |
|
q: query, |
|
top_msg_id: appMessagesIdsManager.getServerMessageId(threadId) |
|
}, 50, 0).then(cP => { |
|
return cP.participants.map(p => appChatsManager.getParticipantPeerId(p)); |
|
}); |
|
} else if(chatId) { |
|
promise = (this.getChatFull(chatId) as Promise<ChatFull.chatFull>).then(chatFull => { |
|
return (chatFull.participants as ChatParticipants.chatParticipants).participants.map(p => p.user_id.toPeerId()); |
|
}); |
|
} else { |
|
promise = Promise.resolve([]); |
|
} |
|
|
|
return Promise.all([ |
|
// [], |
|
appUsersManager.getTopPeers('bots_inline').catch(() => [] as MyTopPeer[]), |
|
promise |
|
]).then(results => { |
|
const peers = results[0].concat(results[1].map(peerId => ({id: peerId, rating: 0}))); |
|
|
|
return processUserIds(peers); |
|
}); |
|
} |
|
|
|
public invalidateChannelParticipants(id: ChatId) { |
|
delete this.chatsFull[id]; |
|
delete this.fullPromises[-id]; |
|
apiManager.clearCache('channels.getParticipants', (params) => (params.channel as InputChannel.inputChannel).channel_id === id); |
|
rootScope.dispatchEvent('chat_full_update', id); |
|
} |
|
|
|
public updateProfile(first_name: string, last_name: string, about: string) { |
|
return apiManager.invokeApi('account.updateProfile', { |
|
first_name, |
|
last_name, |
|
about |
|
}).then(user => { |
|
appUsersManager.saveApiUser(user); |
|
|
|
return this.getProfile(rootScope.myId, true); |
|
}); |
|
} |
|
|
|
public uploadProfilePhoto(inputFile: InputFile) { |
|
return apiManager.invokeApi('photos.uploadProfilePhoto', { |
|
file: inputFile |
|
}).then((updateResult) => { |
|
appUsersManager.saveApiUsers(updateResult.users); |
|
|
|
const myId = rootScope.myId; |
|
appPhotosManager.savePhoto(updateResult.photo, { |
|
type: 'profilePhoto', |
|
peerId: myId |
|
}); |
|
|
|
apiUpdatesManager.processLocalUpdate({ |
|
_: 'updateUserPhoto', |
|
user_id: myId, |
|
date: tsNow(true), |
|
photo: appUsersManager.getUser(myId).photo, |
|
previous: true |
|
}); |
|
}); |
|
} |
|
|
|
public deletePhotos(photoIds: string[]) { |
|
return apiManager.invokeApiSingle('photos.deletePhotos', { |
|
id: photoIds.map(photoId => { |
|
const photo = appPhotosManager.getPhoto(photoId); |
|
return appPhotosManager.getInput(photo); |
|
}) |
|
}).then((deletedList) => { |
|
|
|
}); |
|
} |
|
|
|
public getChatMembersString(id: ChatId) { |
|
const chat: Chat = appChatsManager.getChat(id); |
|
if(chat._ === 'chatForbidden') { |
|
return i18n('YouWereKicked'); |
|
} |
|
|
|
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 as Chat.chat).participants_count || (chat as any).participants?.participants.length; |
|
} |
|
|
|
const isChannel = appChatsManager.isBroadcast(id); |
|
count = count || 1; |
|
|
|
let key: LangPackKey = isChannel ? 'Peer.Status.Subscribers' : 'Peer.Status.Member'; |
|
return i18n(key, [numberThousandSplitter(count)]); |
|
} |
|
|
|
public async getOnlines(id: ChatId): 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; |
|
} |
|
|
|
const res = await apiManager.invokeApi('messages.getOnlines', { |
|
peer: appChatsManager.getChannelInputPeer(id) |
|
}); |
|
|
|
const onlines = res.onlines ?? 1; |
|
cached.timestamp = timestamp; |
|
cached.onlines = onlines; |
|
|
|
return onlines; |
|
} else if(appChatsManager.isBroadcast(id)) { |
|
return 1; |
|
} |
|
|
|
const chatInfo = await this.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 onUpdateUserTyping = (update: Update.updateUserTyping | Update.updateChatUserTyping | Update.updateChannelUserTyping) => { |
|
const fromId = (update as Update.updateUserTyping).user_id ? |
|
(update as Update.updateUserTyping).user_id.toPeerId() : |
|
appPeersManager.getPeerId((update as Update.updateChatUserTyping).from_id); |
|
if(rootScope.myId === fromId || update.action._ === 'speakingInGroupCallAction') { |
|
return; |
|
} |
|
|
|
const peerId = appPeersManager.getPeerId(update); |
|
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; |
|
} |
|
|
|
if(!typing) { |
|
typing = { |
|
userId: fromId |
|
}; |
|
|
|
typings.push(typing); |
|
} |
|
|
|
//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}); |
|
} |
|
}); |
|
} |
|
} |
|
|
|
//return; |
|
} else { |
|
appUsersManager.forceUserOnline(fromId); |
|
} |
|
|
|
typing.timeout = window.setTimeout(cancelAction, 6000); |
|
if(hasUser) { |
|
rootScope.dispatchEvent('peer_typings', {peerId, typings}); |
|
} |
|
}; |
|
|
|
private onUpdatePeerBlocked = (update: Update.updatePeerBlocked) => { |
|
const peerId = appPeersManager.getPeerId(update.peer_id); |
|
if(appPeersManager.isUser(peerId)) { |
|
const userFull = this.usersFull[peerId.toUserId()]; |
|
if(userFull) { |
|
if(update.blocked) userFull.pFlags.blocked = true; |
|
else delete userFull.pFlags.blocked; |
|
} |
|
} |
|
|
|
rootScope.dispatchEvent('peer_block', {peerId, blocked: update.blocked}); |
|
}; |
|
|
|
public getPeerTypings(peerId: PeerId) { |
|
return this.typingsInPeer[peerId]; |
|
} |
|
} |
|
|
|
const appProfileManager = new AppProfileManager(); |
|
MOUNT_CLASS_TO.appProfileManager = appProfileManager; |
|
export default appProfileManager;
|
|
|