Browser History: Fix opening chat from Left Search (#1869)

This commit is contained in:
Alexander Zinchuk 2022-05-16 13:34:12 +02:00
parent e4b2b0911f
commit c333f31f02
3 changed files with 96 additions and 55 deletions

View File

@ -62,7 +62,7 @@ const ChatMessage: FC<OwnProps & StateProps> = ({
const isRoundVideo = Boolean(getMessageRoundVideo(message));
const handleClick = useCallback(() => {
focusMessage({ chatId, messageId: message.id });
focusMessage({ chatId, messageId: message.id, shouldReplaceHistory: true });
}, [chatId, focusMessage, message.id]);
const lang = useLang();

View File

@ -48,6 +48,7 @@ let isAlteringHistory = false;
// Unfortunately Safari doesn't really like when there's 2+ consequent history operations in one frame, so we need
// to delay them to the next raf
let deferredHistoryOperations: HistoryOperation[] = [];
let deferredPopstateOperations: HistoryOperationState[] = [];
let isSafariGestureAnimation = false;
// Do not remove: used for history unit tests
@ -84,13 +85,25 @@ function applyDeferredHistoryOperations() {
const goOperations = deferredHistoryOperations.filter((op) => op.type === 'go') as HistoryOperationGo[];
const stateOperations = deferredHistoryOperations.filter((op) => op.type !== 'go') as HistoryOperationState[];
const goCount = goOperations.reduce((acc, op) => acc + op.delta, 0);
if (goCount) {
window.history.go(goCount);
}
stateOperations.forEach((op) => window.history[op.type](op.data, '', op.hash));
deferredHistoryOperations = [];
if (goCount) {
window.history.go(goCount);
// If we have some `state` operations after the `go` operations, we need to wait until the popstate event
// so the order of operations is correctly preserved
if (stateOperations.length) {
deferredPopstateOperations.push(...stateOperations);
return;
}
}
processStateOperations(stateOperations);
}
function processStateOperations(stateOperations: HistoryOperationState[]) {
stateOperations.forEach((op) => window.history[op.type](op.data, '', op.hash));
}
function deferHistoryOperation(historyOperation: HistoryOperation) {
@ -145,6 +158,10 @@ function cleanupTrashedState() {
window.addEventListener('popstate', ({ state }: PopStateEvent) => {
if (isAlteringHistory) {
isAlteringHistory = false;
if (deferredPopstateOperations.length) {
processStateOperations(deferredPopstateOperations);
deferredPopstateOperations = [];
}
return;
}

View File

@ -1,18 +1,18 @@
import BigInt from 'big-integer';
import { UpdateConnectionState } from '../network';
import Request from '../tl/api';
import { Api as GramJs } from '..';
import Api from '../tl/api';
type Peer = {
peer: GramJs.Chat | GramJs.Channel | GramJs.User;
TEST_messages: GramJs.Message[];
TEST_sendMessage: (data: CreateMessageParams) => GramJs.Message | undefined;
peer: Api.Chat | Api.Channel | Api.User;
inputPeer: Api.TypePeer;
TEST_messages: Api.Message[];
TEST_sendMessage: (data: CreateMessageParams) => Api.Message | undefined;
};
type CreateMessageParams = {
fromId?: any;
repliesChannelId?: any;
replyingTo?: GramJs.MessageReplyHeader;
replyingTo?: Api.MessageReplyHeader;
};
class TelegramClient {
@ -24,7 +24,7 @@ class TelegramClient {
private peers: Peer[] = [];
private dialogs: GramJs.Dialog[] = [];
private dialogs: Api.Dialog[] = [];
start() {
}
@ -57,12 +57,12 @@ class TelegramClient {
const { id } = discussion.TEST_sendMessage({})!;
discussion.TEST_sendMessage({
fromId: new GramJs.PeerUser({
fromId: new Api.PeerUser({
userId: user.peer.id,
}),
replyingTo: new GramJs.MessageReplyHeader({
replyingTo: new Api.MessageReplyHeader({
replyToMsgId: id,
replyToPeerId: new GramJs.PeerChannel({
replyToPeerId: new Api.PeerChannel({
channelId: channel.peer.id,
}),
replyToTopId: message!.id,
@ -70,8 +70,8 @@ class TelegramClient {
});
}
createDialog(peer: GramJs.TypePeer) {
return new GramJs.Dialog({
createDialog(peer: Api.TypePeer) {
return new Api.Dialog({
peer,
topMessage: 0,
readInboxMaxId: 0,
@ -79,11 +79,11 @@ class TelegramClient {
unreadCount: 0,
unreadMentionsCount: 0,
unreadReactionsCount: 0,
notifySettings: new GramJs.PeerNotifySettings({}),
notifySettings: new Api.PeerNotifySettings({}),
});
}
createMessage(peer: GramJs.TypePeer) {
createMessage(peer: Api.TypePeer) {
return ({
fromId,
repliesChannelId,
@ -93,18 +93,18 @@ class TelegramClient {
const p = this.getPeer(peer);
if (!p || pi === undefined) return undefined;
const message = new GramJs.Message({
const message = new Api.Message({
id: p.TEST_messages.length + 1,
fromId,
peerId: peer,
date: Number(new Date()) / 1000 + pi * 60,
message: 'lol @channel',
entities: [new GramJs.MessageEntityMention({
entities: [new Api.MessageEntityMention({
offset: 4,
length: 8,
})],
replyTo: replyingTo,
replies: new GramJs.MessageReplies({
replies: new Api.MessageReplies({
comments: true,
replies: 0,
repliesPts: 0,
@ -117,22 +117,24 @@ class TelegramClient {
}
createChat() {
const chat = new GramJs.Chat({
const chat = new Api.Chat({
id: BigInt(this.lastId++),
title: 'Some chat',
photo: new GramJs.ChatPhotoEmpty(),
photo: new Api.ChatPhotoEmpty(),
participantsCount: 1,
date: 1000,
version: 1,
});
const peerChat = new GramJs.PeerChat({
const peerChat = new Api.PeerChat({
chatId: chat.id,
});
this.dialogs.push(this.createDialog(peerChat));
const testChat: Peer = { peer: chat, TEST_messages: [], TEST_sendMessage: this.createMessage(peerChat) };
const testChat: Peer = {
peer: chat, inputPeer: peerChat, TEST_messages: [], TEST_sendMessage: this.createMessage(peerChat),
};
this.peers.push(testChat);
@ -144,24 +146,26 @@ class TelegramClient {
username: string;
isMegagroup?: boolean;
}) {
const channel = new GramJs.Channel({
const channel = new Api.Channel({
username,
id: BigInt(this.lastId++),
megagroup: isMegagroup ? true : undefined,
title,
photo: new GramJs.ChatPhotoEmpty(),
photo: new Api.ChatPhotoEmpty(),
participantsCount: 1,
date: 1000,
creator: true,
});
const peerChannel = new GramJs.PeerChannel({
const peerChannel = new Api.PeerChannel({
channelId: channel.id,
});
this.dialogs.push(this.createDialog(peerChannel));
const testChat: Peer = { peer: channel, TEST_messages: [], TEST_sendMessage: this.createMessage(peerChannel) };
const testChat: Peer = {
peer: channel, inputPeer: peerChannel, TEST_messages: [], TEST_sendMessage: this.createMessage(peerChannel),
};
this.peers.push(testChat);
@ -175,7 +179,7 @@ class TelegramClient {
firstName: string;
lastName: string;
}): Peer {
const user = new GramJs.User({
const user = new Api.User({
// self: true,
verified: true,
id: BigInt(this.lastId++),
@ -192,23 +196,25 @@ class TelegramClient {
// langCode?: string;
});
const peerUser = new GramJs.PeerUser({
const peerUser = new Api.PeerUser({
userId: user.id,
});
this.dialogs.push(this.createDialog(peerUser));
const testChat: Peer = { peer: user, TEST_messages: [], TEST_sendMessage: this.createMessage(peerUser) };
const testChat: Peer = {
peer: user, inputPeer: peerUser, TEST_messages: [], TEST_sendMessage: this.createMessage(peerUser),
};
this.peers.push(testChat);
return testChat;
}
invoke(request: Request) {
invoke(request: any) {
// await new Promise(resolve => setTimeout(resolve, 1000))
if (request instanceof GramJs.messages.GetDiscussionMessage) {
return new GramJs.messages.DiscussionMessage({
if (request instanceof Api.messages.GetDiscussionMessage) {
return new Api.messages.DiscussionMessage({
messages: [
this.peers[3].TEST_messages[0],
],
@ -218,21 +224,21 @@ class TelegramClient {
users: [],
});
}
if (request instanceof GramJs.messages.GetHistory) {
if (request instanceof Api.messages.GetHistory) {
const peer = this.getPeer(request.peer);
if (!peer) return undefined;
return new GramJs.messages.Messages({
return new Api.messages.Messages({
messages: peer.TEST_messages,
chats: [],
users: [],
});
}
if (request instanceof GramJs.messages.GetReplies) {
if (request instanceof Api.messages.GetReplies) {
const peer = this.peers[3];
if (!peer) return undefined;
return new GramJs.messages.ChannelMessages({
return new Api.messages.ChannelMessages({
messages: peer.TEST_messages,
pts: 0,
count: peer.TEST_messages.length,
@ -240,8 +246,8 @@ class TelegramClient {
users: [],
});
}
if (request instanceof GramJs.messages.GetDialogFilters) {
return [new GramJs.DialogFilter({
if (request instanceof Api.messages.GetDialogFilters) {
return [new Api.DialogFilter({
contacts: true,
nonContacts: true,
groups: true,
@ -258,13 +264,31 @@ class TelegramClient {
excludePeers: [],
})];
}
if (request instanceof GramJs.messages.GetPinnedDialogs) {
return new GramJs.messages.PeerDialogs({
if (request instanceof Api.contacts.GetTopPeers) {
return new Api.contacts.TopPeers({
categories: [new Api.TopPeerCategoryPeers({
category: new Api.TopPeerCategoryCorrespondents(),
count: 1,
peers: [
new Api.TopPeer({
peer: this.peers[0].inputPeer,
rating: 100,
}),
],
})],
chats: [],
users: [
this.getUsers()[0],
],
});
}
if (request instanceof Api.messages.GetPinnedDialogs) {
return new Api.messages.PeerDialogs({
dialogs: [],
chats: [],
messages: [],
users: [],
state: new GramJs.updates.State({
state: new Api.updates.State({
pts: 0,
qts: 0,
date: 0,
@ -273,9 +297,9 @@ class TelegramClient {
}),
});
}
if (request instanceof GramJs.messages.GetDialogs) {
if (request.folderId || !(request.offsetPeer instanceof GramJs.InputPeerEmpty)) {
return new GramJs.messages.Dialogs({
if (request instanceof Api.messages.GetDialogs) {
if (request.folderId || !(request.offsetPeer instanceof Api.InputPeerEmpty)) {
return new Api.messages.Dialogs({
dialogs: [],
users: [],
chats: [],
@ -283,7 +307,7 @@ class TelegramClient {
});
}
return new GramJs.messages.Dialogs({
return new Api.messages.Dialogs({
dialogs: this.dialogs,
messages: this.getAllMessages(),
chats: this.getChats(),
@ -294,7 +318,7 @@ class TelegramClient {
// console.log(request.className, request);
}
private getPeerIndex(peer: GramJs.TypeInputPeer) {
private getPeerIndex(peer: Api.TypeInputPeer) {
const id = 'channelId' in peer ? peer.channelId : (
'userId' in peer ? peer.userId : (
'chatId' in peer ? peer.chatId : undefined
@ -306,7 +330,7 @@ class TelegramClient {
return this.peers.findIndex((l) => l.peer.id.toString() === id.toString());
}
private getPeer(peer: GramJs.TypeInputPeer) {
private getPeer(peer: Api.TypeInputPeer) {
const index = this.getPeerIndex(peer);
if (index === undefined) return undefined;
@ -314,18 +338,18 @@ class TelegramClient {
}
private getAllMessages() {
return this.peers.reduce((acc: GramJs.Message[], el) => {
return this.peers.reduce((acc: Api.Message[], el) => {
acc.push(...el.TEST_messages);
return acc;
}, []);
}
private getChats() {
return this.peers.filter((l) => !(l.peer instanceof GramJs.User)).map((l) => l.peer);
return this.peers.filter((l) => !(l.peer instanceof Api.User)).map((l) => l.peer);
}
private getUsers() {
return this.peers.filter((l) => l.peer instanceof GramJs.User).map((l) => l.peer);
return this.peers.filter((l) => l.peer instanceof Api.User).map((l) => l.peer);
}
}