diff --git a/src/components/chat/input.ts b/src/components/chat/input.ts index 7dd5c618..5f61a6d0 100644 --- a/src/components/chat/input.ts +++ b/src/components/chat/input.ts @@ -1102,13 +1102,13 @@ export default class ChatInput { if(this.isInputEmpty()) { if(this.lastTimeType) { - this.appMessagesManager.setTyping(this.chat.peerId, 'sendMessageCancelAction'); + this.appMessagesManager.setTyping(this.chat.peerId, {_: 'sendMessageCancelAction'}); } } else { const time = Date.now(); if(time - this.lastTimeType >= 6000) { this.lastTimeType = time; - this.appMessagesManager.setTyping(this.chat.peerId, 'sendMessageTypingAction'); + this.appMessagesManager.setTyping(this.chat.peerId, {_: 'sendMessageTypingAction'}); } } diff --git a/src/lib/appManagers/appMessagesManager.ts b/src/lib/appManagers/appMessagesManager.ts index 6fa98c8d..121e1b0d 100644 --- a/src/lib/appManagers/appMessagesManager.ts +++ b/src/lib/appManagers/appMessagesManager.ts @@ -192,6 +192,8 @@ export class AppMessagesManager { private groupedTempId = 0; + private typings: {[peerId: string]: {type: SendMessageAction['_'], timeout?: number}} = {}; + constructor() { rootScope.addMultipleEventsListeners({ updateMessageID: this.onUpdateMessageId, @@ -596,7 +598,7 @@ export class AppMessagesManager { let photo: MyPhoto, document: MyDocument; - let actionName = ''; + let actionName: SendMessageAction['_']; if(isDocument) { // maybe it's a sticker or gif attachType = 'document'; apiFileName = ''; @@ -762,7 +764,7 @@ export class AppMessagesManager { sentDeferred.reject(err); this.cancelPendingMessage(message.random_id); - this.setTyping(peerId, 'sendMessageCancelAction'); + this.setTyping(peerId, {_: 'sendMessageCancelAction'}); if(uploadPromise?.cancel) { uploadPromise.cancel(); @@ -885,7 +887,9 @@ export class AppMessagesManager { } */ const percents = Math.max(1, Math.floor(100 * progress.done / progress.total)); - this.setTyping(peerId, {_: actionName, progress: percents | 0}); + if(actionName) { + this.setTyping(peerId, {_: actionName, progress: percents | 0}); + } sentDeferred.notifyAll(progress); }); @@ -913,7 +917,7 @@ export class AppMessagesManager { if(!options.isGroupedItem) { sentDeferred.then(inputMedia => { - this.setTyping(peerId, 'sendMessageCancelAction'); + this.setTyping(peerId, {_: 'sendMessageCancelAction'}); return apiManager.invokeApi('messages.sendMedia', { background: options.background, @@ -1031,7 +1035,7 @@ export class AppMessagesManager { const inputPeer = appPeersManager.getInputPeerById(peerId); const invoke = (multiMedia: any[]) => { - this.setTyping(peerId, 'sendMessageCancelAction'); + this.setTyping(peerId, {_: 'sendMessageCancelAction'}); this.sendSmthLazyLoadQueue.push({ load: () => { @@ -4845,14 +4849,35 @@ export class AppMessagesManager { } } - public setTyping(peerId: number, _action: any): Promise { - if(!rootScope.myId || !peerId || !this.canWriteToPeer(peerId) || peerId === rootScope.myId) return Promise.resolve(false); - - const action: SendMessageAction = typeof(_action) === 'string' ? {_: _action} : _action; + public setTyping(peerId: number, action: SendMessageAction): Promise { + let typing = this.typings[peerId]; + if(!rootScope.myId || + !peerId || + !this.canWriteToPeer(peerId) || + peerId === rootScope.myId || + typing?.type === action._ + ) { + return Promise.resolve(false); + } + + if(typing?.timeout) { + clearTimeout(typing.timeout); + } + + typing = this.typings[peerId] = { + type: action._ + }; + return apiManager.invokeApi('messages.setTyping', { peer: appPeersManager.getInputPeerById(peerId), action - }) as Promise; + }).finally(() => { + if(typing === this.typings[peerId]) { + typing.timeout = window.setTimeout(() => { + delete this.typings[peerId]; + }, 6000); + } + }); } private handleDeletedMessages(peerId: number, storage: MessagesStorage, messages: number[]) { diff --git a/src/scss/partials/_chatlist.scss b/src/scss/partials/_chatlist.scss index 7404ebcf..1ef0ee82 100644 --- a/src/scss/partials/_chatlist.scss +++ b/src/scss/partials/_chatlist.scss @@ -292,6 +292,7 @@ ul.chatlist { .dialog-avatar, .user-caption { pointer-events: none; + position: relative; // for z-index } .user-title {