Fix jumping scroll again
This commit is contained in:
parent
a7f5bae92a
commit
97d645f1ea
@ -40,20 +40,31 @@ for(const name of Object.keys(nets)) {
|
||||
}
|
||||
|
||||
const useHttp = false;
|
||||
const server = useHttp ? http : https;
|
||||
const transport = useHttp ? http : https;
|
||||
let options = {};
|
||||
if(!useHttp) {
|
||||
options.key = fs.readFileSync(__dirname + '/certs/server-key.pem');
|
||||
options.cert = fs.readFileSync(__dirname + '/certs/server-cert.pem');
|
||||
}
|
||||
|
||||
console.log(results);
|
||||
|
||||
const port = 3000;
|
||||
const protocol = useHttp ? 'http' : 'https';
|
||||
console.log('Listening port:', port);
|
||||
function createServer(host) {
|
||||
server.createServer(options, app).listen(port, host, () => {
|
||||
const server = transport.createServer(options, app);
|
||||
server.listen(port, host, () => {
|
||||
console.log('Host:', `${protocol}://${host || 'localhost'}:${port}/`);
|
||||
});
|
||||
|
||||
server.on('error', (e) => {
|
||||
// @ts-ignore
|
||||
if(e.code === 'EADDRINUSE') {
|
||||
console.log('Address in use:', host);
|
||||
server.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for(const name in results) {
|
||||
|
@ -47,14 +47,24 @@ export class AnimationIntersector {
|
||||
if(entry.isIntersecting) {
|
||||
this.visible.add(player);
|
||||
this.checkAnimation(player, false);
|
||||
|
||||
/* if(animation instanceof HTMLVideoElement && animation.dataset.src) {
|
||||
animation.src = animation.dataset.src;
|
||||
animation.load();
|
||||
} */
|
||||
} else {
|
||||
this.visible.delete(player);
|
||||
this.checkAnimation(player, true);
|
||||
|
||||
if(player.animation instanceof RLottiePlayer/* && player.animation.cachingDelta === 2 */) {
|
||||
|
||||
const animation = player.animation;
|
||||
if(animation instanceof RLottiePlayer/* && animation.cachingDelta === 2 */) {
|
||||
//console.warn('will clear cache', player);
|
||||
player.animation.clearCache();
|
||||
}
|
||||
animation.clearCache();
|
||||
}/* else if(animation instanceof HTMLVideoElement && animation.src) {
|
||||
animation.dataset.src = animation.src;
|
||||
animation.src = '';
|
||||
animation.load();
|
||||
} */
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -208,8 +208,6 @@ export default class ChatBubbles {
|
||||
private hoverBubble: HTMLElement;
|
||||
private hoverReaction: HTMLElement;
|
||||
|
||||
private onUpdateScrollSaver: ScrollSaver;
|
||||
|
||||
// private reactions: Map<number, ReactionsElement>;
|
||||
|
||||
constructor(
|
||||
@ -431,8 +429,10 @@ export default class ChatBubbles {
|
||||
|
||||
const updatePosition = this.chat.type === 'scheduled';
|
||||
|
||||
this.saveOnUpdateScroll();
|
||||
const scrollSaver = new ScrollSaver(this.scrollable, true);
|
||||
scrollSaver.save();
|
||||
this.safeRenderMessage(mounted.message, true, false, mounted.bubble, updatePosition);
|
||||
scrollSaver.restore();
|
||||
|
||||
if(updatePosition) {
|
||||
(this.messagesQueuePromise || Promise.resolve()).then(() => {
|
||||
@ -461,43 +461,41 @@ export default class ChatBubbles {
|
||||
this.appendReactionsElementToBubble(bubble, message, changedResults);
|
||||
});
|
||||
|
||||
this.listenerSetter.add(rootScope)('message_reactions', ({message, changedResults}) => {
|
||||
if(this.peerId !== message.peerId) {
|
||||
return;
|
||||
}
|
||||
this.listenerSetter.add(rootScope)('messages_reactions', (arr) => {
|
||||
let scrollSaver: ScrollSaver;
|
||||
|
||||
const bubble = this.getBubbleByMessage(message);
|
||||
if(!bubble) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.saveOnUpdateScroll();
|
||||
|
||||
const key = message.peerId + '_' + message.mid;
|
||||
const set = REACTIONS_ELEMENTS.get(key);
|
||||
if(set) {
|
||||
for(const element of set) {
|
||||
element.update(message, changedResults);
|
||||
for(const {message, changedResults} of arr) {
|
||||
if(this.peerId !== message.peerId) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
rootScope.dispatchEvent('missed_reactions_element', {message, changedResults});
|
||||
|
||||
const bubble = this.getBubbleByMessage(message);
|
||||
if(!bubble) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!scrollSaver) {
|
||||
scrollSaver = new ScrollSaver(this.scrollable, true);
|
||||
scrollSaver.save();
|
||||
}
|
||||
|
||||
const key = message.peerId + '_' + message.mid;
|
||||
const set = REACTIONS_ELEMENTS.get(key);
|
||||
if(set) {
|
||||
for(const element of set) {
|
||||
element.update(message, changedResults);
|
||||
}
|
||||
} else {
|
||||
rootScope.dispatchEvent('missed_reactions_element', {message, changedResults});
|
||||
}
|
||||
}
|
||||
|
||||
if(scrollSaver) {
|
||||
scrollSaver.restore();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* this.listenerSetter.add(rootScope)('message_reactions', ({peerId, mid}) => {
|
||||
if(this.peerId !== peerId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const reactionsElement = this.reactions.get(mid);
|
||||
if(!reactionsElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
}); */
|
||||
|
||||
this.listenerSetter.add(rootScope)('album_edit', ({peerId, groupId, deletedMids}) => {
|
||||
//fastRaf(() => { // ! can't use delayed smth here, need original bubble to be edited
|
||||
if(peerId !== this.peerId) return;
|
||||
@ -767,24 +765,35 @@ export default class ChatBubbles {
|
||||
}
|
||||
});
|
||||
|
||||
this.listenerSetter.add(rootScope)('message_views', ({peerId, views, mid}) => {
|
||||
if(this.peerId !== peerId) return;
|
||||
|
||||
this.listenerSetter.add(rootScope)('messages_views', (arr) => {
|
||||
fastRaf(() => {
|
||||
const bubble = this.bubbles[mid];
|
||||
if(!bubble) return;
|
||||
let scrollSaver: ScrollSaver;
|
||||
for(const {peerId, views, mid} of arr) {
|
||||
if(this.peerId !== peerId) return;
|
||||
|
||||
const postViewsElements = Array.from(bubble.querySelectorAll('.post-views')) as HTMLElement[];
|
||||
if(postViewsElements.length) {
|
||||
const str = formatNumber(views, 1);
|
||||
let different = false;
|
||||
postViewsElements.forEach(postViews => {
|
||||
if(different || postViews.innerHTML !== str) {
|
||||
this.saveOnUpdateScroll();
|
||||
different = true;
|
||||
postViews.innerHTML = str;
|
||||
}
|
||||
});
|
||||
const bubble = this.bubbles[mid];
|
||||
if(!bubble) return;
|
||||
|
||||
const postViewsElements = Array.from(bubble.querySelectorAll('.post-views')) as HTMLElement[];
|
||||
if(postViewsElements.length) {
|
||||
const str = formatNumber(views, 1);
|
||||
let different = false;
|
||||
postViewsElements.forEach(postViews => {
|
||||
if(different || postViews.innerHTML !== str) {
|
||||
if(!scrollSaver) {
|
||||
scrollSaver = new ScrollSaver(this.scrollable, true);
|
||||
scrollSaver.save();
|
||||
}
|
||||
|
||||
different = true;
|
||||
postViews.innerHTML = str;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if(scrollSaver) {
|
||||
scrollSaver.restore();
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -928,18 +937,6 @@ export default class ChatBubbles {
|
||||
}
|
||||
}
|
||||
|
||||
private saveOnUpdateScroll() {
|
||||
if(!this.onUpdateScrollSaver) {
|
||||
this.onUpdateScrollSaver = new ScrollSaver(this.scrollable, true);
|
||||
setTimeout(() => {
|
||||
this.onUpdateScrollSaver.restore();
|
||||
this.onUpdateScrollSaver = undefined;
|
||||
}, 0);
|
||||
|
||||
this.onUpdateScrollSaver.save();
|
||||
}
|
||||
}
|
||||
|
||||
private onBubblesMouseMove = (e: MouseEvent) => {
|
||||
const content = findUpClassName(e.target, 'bubble-content');
|
||||
if(content && !this.chat.selection.isSelecting) {
|
||||
@ -1048,6 +1045,8 @@ export default class ChatBubbles {
|
||||
};
|
||||
|
||||
public setStickyDateManually() {
|
||||
// return;
|
||||
|
||||
const timestamps = Object.keys(this.dateMessages).map(k => +k).sort((a, b) => b - a);
|
||||
let lastVisible: HTMLElement;
|
||||
|
||||
@ -1716,7 +1715,7 @@ export default class ChatBubbles {
|
||||
//lottieLoader.checkAnimations(false, 'chat');
|
||||
|
||||
const distanceToEnd = this.scrollable.getDistanceToEnd();
|
||||
if(!IS_TOUCH_SUPPORTED && this.scrollable.lastScrollDirection !== 0 && distanceToEnd > 0) {
|
||||
if(/* !IS_TOUCH_SUPPORTED && */this.scrollable.lastScrollDirection !== 0 && distanceToEnd > 0) {
|
||||
if(this.isScrollingTimeout) {
|
||||
clearTimeout(this.isScrollingTimeout);
|
||||
} else if(!this.chatInner.classList.contains('is-scrolling')) {
|
||||
@ -1767,7 +1766,7 @@ export default class ChatBubbles {
|
||||
this.scrollable.onScrolledBottom = () => this.loadMoreHistory(false);
|
||||
//this.scrollable.attachSentinels(undefined, 300);
|
||||
|
||||
if(IS_TOUCH_SUPPORTED) {
|
||||
if(IS_TOUCH_SUPPORTED && false) {
|
||||
this.scrollable.container.addEventListener('touchmove', () => {
|
||||
if(this.isScrollingTimeout) {
|
||||
clearTimeout(this.isScrollingTimeout);
|
||||
@ -3782,7 +3781,7 @@ export default class ChatBubbles {
|
||||
}
|
||||
|
||||
private appendReactionsElementToBubble(bubble: HTMLElement, message: Message.message, changedResults?: ReactionCount[]) {
|
||||
if(this.peerId.isUser()) {
|
||||
if(this.peerId.isUser()/* || true */) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -343,7 +343,7 @@ export default class ChatPinnedMessage {
|
||||
|
||||
public setCorrectIndex(lastScrollDirection?: number) {
|
||||
if(this.isStatic) return;
|
||||
//return;
|
||||
// return;
|
||||
|
||||
if(this.locked || this.hidden/* || this.chat.setPeerPromise || this.chat.bubbles.messagesQueuePromise */) {
|
||||
return;
|
||||
|
@ -451,13 +451,23 @@ export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTai
|
||||
});
|
||||
|
||||
if(doc.type === 'video') {
|
||||
video.addEventListener('timeupdate', () => {
|
||||
const onTimeUpdate = () => {
|
||||
if(!video.videoWidth) {
|
||||
return;
|
||||
}
|
||||
|
||||
spanTime.innerText = toHHMMSS(video.duration - video.currentTime, false);
|
||||
});
|
||||
};
|
||||
|
||||
const throttledTimeUpdate = throttleWithRaf(onTimeUpdate);
|
||||
|
||||
video.addEventListener('timeupdate', throttledTimeUpdate);
|
||||
|
||||
if(spanPlay) {
|
||||
video.addEventListener('timeupdate', () => {
|
||||
spanPlay.remove();
|
||||
sequentialDom.mutateElement(spanPlay, () => {
|
||||
spanPlay.remove();
|
||||
});
|
||||
}, {once: true});
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
import { MOUNT_CLASS_TO } from "../../config/debug";
|
||||
import { renderImageFromUrlPromise } from "../../helpers/dom/renderImageFromUrl";
|
||||
import replaceContent from "../../helpers/dom/replaceContent";
|
||||
import sequentialDom from "../../helpers/sequentialDom";
|
||||
@ -220,4 +221,5 @@ export class AppAvatarsManager {
|
||||
}
|
||||
|
||||
const appAvatarsManager = new AppAvatarsManager();
|
||||
MOUNT_CLASS_TO && (MOUNT_CLASS_TO.appAvatarsManager = appAvatarsManager);
|
||||
export default appAvatarsManager;
|
||||
|
@ -15,8 +15,8 @@ import { CancellablePromise, deferredPromise } from "../../helpers/cancellablePr
|
||||
import { formatDateAccordingToTodayNew, formatTime, tsNow } from "../../helpers/date";
|
||||
import { createPosterForVideo } from "../../helpers/files";
|
||||
import { randomLong } from "../../helpers/random";
|
||||
import { Chat, ChatFull, Dialog as MTDialog, DialogPeer, DocumentAttribute, InputMedia, InputMessage, InputPeerNotifySettings, InputSingleMedia, Message, MessageAction, MessageEntity, MessageFwdHeader, MessageMedia, MessageReplies, MessageReplyHeader, MessagesDialogs, MessagesFilter, MessagesMessages, MethodDeclMap, NotifyPeer, PeerNotifySettings, PhotoSize, SendMessageAction, Update, Photo, Updates, ReplyMarkup, InputPeer, InputPhoto, InputDocument, InputGeoPoint, WebPage, GeoPoint, ReportReason, MessagesGetDialogs, InputChannel, InputDialogPeer, ReactionCount, MessagePeerReaction, MessagesSearchCounter, Peer } from "../../layer";
|
||||
import { InvokeApiOptions } from "../../types";
|
||||
import { Chat, ChatFull, Dialog as MTDialog, DialogPeer, DocumentAttribute, InputMedia, InputMessage, InputPeerNotifySettings, InputSingleMedia, Message, MessageAction, MessageEntity, MessageFwdHeader, MessageMedia, MessageReplies, MessageReplyHeader, MessagesDialogs, MessagesFilter, MessagesMessages, MethodDeclMap, NotifyPeer, PeerNotifySettings, PhotoSize, SendMessageAction, Update, Photo, Updates, ReplyMarkup, InputPeer, InputPhoto, InputDocument, InputGeoPoint, WebPage, GeoPoint, ReportReason, MessagesGetDialogs, InputChannel, InputDialogPeer, ReactionCount, MessagePeerReaction, MessagesSearchCounter, Peer, MessageReactions } from "../../layer";
|
||||
import { ArgumentTypes, InvokeApiOptions } from "../../types";
|
||||
import I18n, { FormatterArguments, i18n, join, langPack, LangPackKey, UNSUPPORTED_LANG_PACK_KEY, _i18n } from "../langPack";
|
||||
import { logger, LogTypes } from "../logger";
|
||||
import type { ApiFileManager } from '../mtproto/apiFileManager';
|
||||
@ -70,6 +70,7 @@ import deepEqual from "../../helpers/object/deepEqual";
|
||||
import escapeRegExp from "../../helpers/string/escapeRegExp";
|
||||
import limitSymbols from "../../helpers/string/limitSymbols";
|
||||
import splitStringByLength from "../../helpers/string/splitStringByLength";
|
||||
import debounce from "../../helpers/schedulers/debounce";
|
||||
|
||||
//console.trace('include');
|
||||
// TODO: если удалить диалог находясь в папке, то он не удалится из папки и будет виден в настройках
|
||||
@ -128,6 +129,13 @@ type PendingAfterMsg = Partial<InvokeApiOptions & {
|
||||
messageId: string
|
||||
}>;
|
||||
|
||||
type MapValueType<A> = A extends Map<any, infer V> ? V : never;
|
||||
|
||||
export type BatchUpdates = {
|
||||
'messages_reactions': AppMessagesManager['batchUpdateReactions'],
|
||||
'messages_views': AppMessagesManager['batchUpdateViews']
|
||||
};
|
||||
|
||||
export class AppMessagesManager {
|
||||
private messagesStorageByPeerId: {[peerId: string]: MessagesStorage};
|
||||
public groupedMessagesStorage: {[groupId: string]: MessagesStorage}; // will be used for albums
|
||||
@ -214,6 +222,14 @@ export class AppMessagesManager {
|
||||
|
||||
private unreadMentions: {[peerId: PeerId]: SlicedArray} = {};
|
||||
private goToNextMentionPromises: {[peerId: PeerId]: Promise<any>} = {};
|
||||
|
||||
private batchUpdates: {
|
||||
[k in keyof BatchUpdates]?: {
|
||||
callback: BatchUpdates[k],
|
||||
batch: ArgumentTypes<BatchUpdates[k]>[0]
|
||||
}
|
||||
} = {};
|
||||
private batchUpdatesDebounced: () => Promise<void>;
|
||||
|
||||
constructor() {
|
||||
this.clear();
|
||||
@ -345,6 +361,20 @@ export class AppMessagesManager {
|
||||
this.maxSeenId = state.maxSeenMsgId;
|
||||
}
|
||||
});
|
||||
|
||||
this.batchUpdatesDebounced = debounce(() => {
|
||||
for(const event in this.batchUpdates) {
|
||||
const details = this.batchUpdates[event as keyof BatchUpdates];
|
||||
delete this.batchUpdates[event as keyof BatchUpdates];
|
||||
|
||||
// @ts-ignore
|
||||
const result = details.callback(details.batch);
|
||||
if(result && (!(result instanceof Array) || result.length)) {
|
||||
// @ts-ignore
|
||||
rootScope.dispatchEvent(event as keyof BatchUpdates, result);
|
||||
}
|
||||
}
|
||||
}, 33, false, true);
|
||||
}
|
||||
|
||||
public clear() {
|
||||
@ -4700,26 +4730,10 @@ export class AppMessagesManager {
|
||||
}
|
||||
}
|
||||
|
||||
const results = reactions?.results ?? [];
|
||||
const previousResults = message.reactions?.results ?? [];
|
||||
const changedResults = results.filter(reactionCount => {
|
||||
const previousReactionCount = previousResults.find(_reactionCount => _reactionCount.reaction === reactionCount.reaction);
|
||||
return (
|
||||
message.pFlags.out && (
|
||||
!previousReactionCount ||
|
||||
reactionCount.count > previousReactionCount.count
|
||||
)
|
||||
) || (
|
||||
reactionCount.pFlags.chosen && (
|
||||
!previousReactionCount ||
|
||||
!previousReactionCount.pFlags.chosen
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
message.reactions = reactions;
|
||||
|
||||
rootScope.dispatchEvent('message_reactions', {message, changedResults});
|
||||
const key = message.peerId + '_' + message.mid;
|
||||
this.pushBatchUpdate('messages_reactions', this.batchUpdateReactions, key, () => copy(message.reactions));
|
||||
|
||||
if(!update.local) {
|
||||
this.setDialogToStateIfMessageIsTop(message);
|
||||
@ -5094,7 +5108,7 @@ export class AppMessagesManager {
|
||||
const message: Message.message = this.getMessageByPeer(peerId, mid);
|
||||
if(!message.deleted && message.views !== undefined && message.views < views) {
|
||||
message.views = views;
|
||||
rootScope.dispatchEvent('message_views', {peerId, mid, views});
|
||||
this.pushBatchUpdate('messages_views', this.batchUpdateViews, message.peerId + '_' + message.mid);
|
||||
this.setDialogToStateIfMessageIsTop(message);
|
||||
}
|
||||
};
|
||||
@ -6283,6 +6297,86 @@ export class AppMessagesManager {
|
||||
public canForward(message: Message.message | Message.messageService) {
|
||||
return !(message as Message.message).pFlags.noforwards && !appPeersManager.noForwards(message.peerId);
|
||||
}
|
||||
|
||||
private pushBatchUpdate<E extends keyof BatchUpdates, C extends BatchUpdates[E]>(
|
||||
event: E,
|
||||
callback: C,
|
||||
key: string,
|
||||
getElementCallback?: () => MapValueType<ArgumentTypes<C>[0]>
|
||||
) {
|
||||
let details = this.batchUpdates[event];
|
||||
if(!details) {
|
||||
// @ts-ignore
|
||||
details = this.batchUpdates[event] = {
|
||||
callback,
|
||||
batch: new Map()
|
||||
};
|
||||
}
|
||||
|
||||
if(!details.batch.has(key)) {
|
||||
// @ts-ignore
|
||||
details.batch.set(key, getElementCallback ? getElementCallback() : undefined);
|
||||
this.batchUpdatesDebounced();
|
||||
}
|
||||
}
|
||||
|
||||
private getMessagesFromMap<T extends Map<any, any>>(map: T) {
|
||||
const newMap: Map<Message.message, MapValueType<T>> = new Map();
|
||||
for(const [key, value] of map) {
|
||||
const [peerIdStr, mid] = key.split('_');
|
||||
const message: Message.message | Message.messageEmpty = this.getMessageByPeer(peerIdStr.toPeerId(), +mid);
|
||||
if(message._ === 'messageEmpty') {
|
||||
continue;
|
||||
}
|
||||
|
||||
newMap.set(message, value);
|
||||
}
|
||||
|
||||
return newMap;
|
||||
}
|
||||
|
||||
private batchUpdateViews = (batch: Map<string, undefined>) => {
|
||||
const toDispatch: {peerId: PeerId, mid: number, views: number}[] = [];
|
||||
|
||||
const map = this.getMessagesFromMap(batch);
|
||||
for(const [message] of map) {
|
||||
toDispatch.push({
|
||||
peerId: message.peerId,
|
||||
mid: message.mid,
|
||||
views: message.views
|
||||
})
|
||||
}
|
||||
|
||||
return toDispatch;
|
||||
};
|
||||
|
||||
private batchUpdateReactions = (batch: Map<string, MessageReactions>) => {
|
||||
const toDispatch: {message: Message.message, changedResults: ReactionCount.reactionCount[]}[] = [];
|
||||
|
||||
const map = this.getMessagesFromMap(batch);
|
||||
for(const [message, reactions] of map) {
|
||||
const results = reactions?.results ?? [];
|
||||
const previousResults = message.reactions?.results ?? [];
|
||||
const changedResults = results.filter(reactionCount => {
|
||||
const previousReactionCount = previousResults.find(_reactionCount => _reactionCount.reaction === reactionCount.reaction);
|
||||
return (
|
||||
message.pFlags.out && (
|
||||
!previousReactionCount ||
|
||||
reactionCount.count > previousReactionCount.count
|
||||
)
|
||||
) || (
|
||||
reactionCount.pFlags.chosen && (
|
||||
!previousReactionCount ||
|
||||
!previousReactionCount.pFlags.chosen
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
toDispatch.push({message, changedResults});
|
||||
}
|
||||
|
||||
return toDispatch;
|
||||
};
|
||||
}
|
||||
|
||||
const appMessagesManager = new AppMessagesManager();
|
||||
|
@ -320,7 +320,7 @@ export class AppReactionsManager {
|
||||
|
||||
if(onlyLocal) {
|
||||
message.reactions = reactions;
|
||||
rootScope.dispatchEvent('message_reactions', {message, changedResults: []});
|
||||
rootScope.dispatchEvent('messages_reactions', [{message, changedResults: []}]);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
|
@ -76,9 +76,9 @@ export type BroadcastEvents = {
|
||||
//'history_request': void,
|
||||
|
||||
'message_edit': {storage: MessagesStorage, peerId: PeerId, mid: number},
|
||||
'message_views': {peerId: PeerId, mid: number, views: number},
|
||||
'message_sent': {storage: MessagesStorage, tempId: number, tempMessage: any, mid: number, message: MyMessage},
|
||||
'message_reactions': {message: Message.message, changedResults: ReactionCount[]},
|
||||
'messages_views': {peerId: PeerId, mid: number, views: number}[],
|
||||
'messages_reactions': {message: Message.message, changedResults: ReactionCount[]}[],
|
||||
'messages_pending': void,
|
||||
'messages_read': void,
|
||||
'messages_downloaded': {peerId: PeerId, mids: number[]},
|
||||
|
Loading…
x
Reference in New Issue
Block a user