Message: Preserve focus stack for deeplinks within the same chat (#464)
This commit is contained in:
parent
08a4dd9117
commit
17fe96dff3
@ -1038,6 +1038,13 @@ export type ApiSearchPostsFlood = {
|
||||
starsAmount: number;
|
||||
};
|
||||
|
||||
export type LinkContext = {
|
||||
type: 'message';
|
||||
threadId?: ThreadId;
|
||||
chatId: string;
|
||||
messageId: number;
|
||||
};
|
||||
|
||||
export const MAIN_THREAD_ID = -1;
|
||||
|
||||
// `Symbol` can not be transferred from worker
|
||||
|
||||
@ -2256,6 +2256,7 @@ const Composer: FC<OwnProps & StateProps> = ({
|
||||
{isInMessageList && Boolean(botKeyboardMessageId) && (
|
||||
<BotKeyboardMenu
|
||||
messageId={botKeyboardMessageId}
|
||||
threadId={threadId}
|
||||
isOpen={isBotKeyboardOpen}
|
||||
onClose={closeBotKeyboard}
|
||||
/>
|
||||
|
||||
@ -2,6 +2,7 @@ import type { TeactNode } from '../../lib/teact/teact';
|
||||
import type React from '../../lib/teact/teact';
|
||||
import { getActions } from '../../global';
|
||||
|
||||
import type { ThreadId } from '../../types';
|
||||
import { ApiMessageEntityTypes } from '../../api/types';
|
||||
|
||||
import { ensureProtocol, getUnicodeUrl, isMixedScriptUrl } from '../../util/browser/url';
|
||||
@ -16,6 +17,9 @@ type OwnProps = {
|
||||
children?: TeactNode;
|
||||
isRtl?: boolean;
|
||||
shouldSkipModal?: boolean;
|
||||
chatId?: string;
|
||||
messageId?: number;
|
||||
threadId?: ThreadId;
|
||||
};
|
||||
|
||||
const SafeLink = ({
|
||||
@ -25,6 +29,9 @@ const SafeLink = ({
|
||||
children,
|
||||
isRtl,
|
||||
shouldSkipModal,
|
||||
chatId,
|
||||
messageId,
|
||||
threadId,
|
||||
}: OwnProps) => {
|
||||
const { openUrl } = getActions();
|
||||
|
||||
@ -37,7 +44,13 @@ const SafeLink = ({
|
||||
e.preventDefault();
|
||||
|
||||
const isTrustedLink = isRegularLink && !isMixedScriptUrl(url);
|
||||
openUrl({ url, shouldSkipModal: shouldSkipModal || isTrustedLink });
|
||||
openUrl({
|
||||
url,
|
||||
shouldSkipModal: shouldSkipModal || isTrustedLink,
|
||||
...(chatId && messageId && {
|
||||
linkContext: { type: 'message', chatId, threadId, messageId },
|
||||
}),
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
@ -616,6 +616,9 @@ function processEntity({
|
||||
<SafeLink
|
||||
url={getLinkUrl(entityText, entity)}
|
||||
text={entityText}
|
||||
chatId={chatId}
|
||||
messageId={messageId}
|
||||
threadId={threadId}
|
||||
>
|
||||
{renderNestedMessagePart()}
|
||||
</SafeLink>
|
||||
|
||||
@ -3,6 +3,7 @@ import { memo, useMemo } from '../../../lib/teact/teact';
|
||||
import { getActions, withGlobal } from '../../../global';
|
||||
|
||||
import type { ApiMessage } from '../../../api/types';
|
||||
import type { ThreadId } from '../../../types';
|
||||
|
||||
import { selectChatMessage, selectCurrentMessageList } from '../../../global/selectors';
|
||||
import { IS_TOUCH_ENV } from '../../../util/browser/windowEnvironment';
|
||||
@ -24,10 +25,11 @@ export type OwnProps = {
|
||||
|
||||
type StateProps = {
|
||||
message?: ApiMessage;
|
||||
threadId?: ThreadId;
|
||||
};
|
||||
|
||||
const BotKeyboardMenu: FC<OwnProps & StateProps> = ({
|
||||
isOpen, message, onClose,
|
||||
isOpen, message, onClose, threadId,
|
||||
}) => {
|
||||
const { clickBotInlineButton } = getActions();
|
||||
|
||||
@ -70,7 +72,9 @@ const BotKeyboardMenu: FC<OwnProps & StateProps> = ({
|
||||
ripple
|
||||
disabled={button.type === 'unsupported'}
|
||||
|
||||
onClick={() => clickBotInlineButton({ chatId: message.chatId, messageId: message.id, button })}
|
||||
onClick={() => clickBotInlineButton({
|
||||
chatId: message.chatId, messageId: message.id, threadId, button,
|
||||
})}
|
||||
>
|
||||
{buttonTexts?.[i][j]}
|
||||
</Button>
|
||||
|
||||
@ -3,6 +3,7 @@ import { memo } from '../../../lib/teact/teact';
|
||||
import { getActions } from '../../../global';
|
||||
|
||||
import type { ApiMessage } from '../../../api/types';
|
||||
import type { ThreadId } from '../../../types';
|
||||
|
||||
import { getGamePreviewPhotoHash, getGamePreviewVideoHash, getMessageText } from '../../../global/helpers';
|
||||
|
||||
@ -19,11 +20,13 @@ const DEFAULT_PREVIEW_DIMENSIONS = {
|
||||
|
||||
type OwnProps = {
|
||||
message: ApiMessage;
|
||||
threadId?: ThreadId;
|
||||
canAutoLoadMedia?: boolean;
|
||||
};
|
||||
|
||||
const Game: FC<OwnProps> = ({
|
||||
message,
|
||||
threadId,
|
||||
canAutoLoadMedia,
|
||||
}) => {
|
||||
const { clickBotInlineButton } = getActions();
|
||||
@ -41,6 +44,7 @@ const Game: FC<OwnProps> = ({
|
||||
clickBotInlineButton({
|
||||
chatId: message.chatId,
|
||||
messageId: message.id,
|
||||
threadId,
|
||||
button: message.inlineButtons![0][0],
|
||||
});
|
||||
};
|
||||
|
||||
@ -1286,6 +1286,7 @@ const Message: FC<OwnProps & StateProps> = ({
|
||||
{game && (
|
||||
<Game
|
||||
message={message}
|
||||
threadId={threadId}
|
||||
canAutoLoadMedia={canAutoLoadMedia}
|
||||
/>
|
||||
)}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import type { InlineBotSettings } from '../../../types';
|
||||
import type { InlineBotSettings, ThreadId } from '../../../types';
|
||||
import type { WebApp } from '../../../types/webapp';
|
||||
import type { RequiredGlobalActions } from '../../index';
|
||||
import type {
|
||||
@ -95,7 +95,7 @@ addActionHandler('clickSuggestedMessageButton', (global, actions, payload): Acti
|
||||
|
||||
addActionHandler('clickBotInlineButton', (global, actions, payload): ActionReturnType => {
|
||||
const {
|
||||
chatId, messageId, button, tabId = getCurrentTabId(),
|
||||
chatId, messageId, threadId, button, tabId = getCurrentTabId(),
|
||||
} = payload;
|
||||
const chat = selectChat(global, chatId);
|
||||
const message = selectChatMessage(global, chatId, messageId);
|
||||
@ -109,7 +109,7 @@ addActionHandler('clickBotInlineButton', (global, actions, payload): ActionRetur
|
||||
break;
|
||||
case 'url': {
|
||||
const { url } = button;
|
||||
actions.openUrl({ url, tabId });
|
||||
actions.openUrl({ url, tabId, linkContext: { type: 'message', chatId, messageId, threadId } });
|
||||
break;
|
||||
}
|
||||
case 'copy': {
|
||||
@ -118,7 +118,7 @@ addActionHandler('clickBotInlineButton', (global, actions, payload): ActionRetur
|
||||
break;
|
||||
}
|
||||
case 'callback': {
|
||||
void answerCallbackButton(global, actions, chat, messageId, button.data, undefined, tabId);
|
||||
void answerCallbackButton(global, actions, chat, messageId, threadId, button.data, undefined, tabId);
|
||||
break;
|
||||
}
|
||||
case 'requestPoll':
|
||||
@ -157,7 +157,7 @@ addActionHandler('clickBotInlineButton', (global, actions, payload): ActionRetur
|
||||
break;
|
||||
}
|
||||
case 'game': {
|
||||
void answerCallbackButton(global, actions, chat, messageId, undefined, true, tabId);
|
||||
void answerCallbackButton(global, actions, chat, messageId, threadId, undefined, true, tabId);
|
||||
break;
|
||||
}
|
||||
case 'switchBotInline': {
|
||||
@ -1287,7 +1287,7 @@ async function sendBotCommand(
|
||||
|
||||
async function answerCallbackButton<T extends GlobalState>(
|
||||
global: T,
|
||||
actions: RequiredGlobalActions, chat: ApiChat, messageId: number, data?: string, isGame = false,
|
||||
actions: RequiredGlobalActions, chat: ApiChat, messageId: number, threadId?: ThreadId, data?: string, isGame = false,
|
||||
...[tabId = getCurrentTabId()]: TabArgs<T>
|
||||
) {
|
||||
const {
|
||||
@ -1317,7 +1317,7 @@ async function answerCallbackButton<T extends GlobalState>(
|
||||
url, chatId: chat.id, messageId, tabId,
|
||||
});
|
||||
} else {
|
||||
openUrl({ url, tabId });
|
||||
openUrl({ url, tabId, linkContext: { type: 'message', chatId: chat.id, messageId, threadId } });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ import type {
|
||||
ApiChat, ApiChatFolder, ApiChatlistExportedInvite,
|
||||
ApiChatMember, ApiError, ApiMissingInvitedUser,
|
||||
ApiTopic,
|
||||
LinkContext,
|
||||
} from '../../../api/types';
|
||||
import type { RequiredGlobalActions } from '../../index';
|
||||
import type {
|
||||
@ -1458,6 +1459,7 @@ addActionHandler('openTelegramLink', async (global, actions, payload): Promise<v
|
||||
const {
|
||||
url,
|
||||
shouldIgnoreCache,
|
||||
linkContext,
|
||||
tabId = getCurrentTabId(),
|
||||
} = payload;
|
||||
|
||||
@ -1475,7 +1477,7 @@ addActionHandler('openTelegramLink', async (global, actions, payload): Promise<v
|
||||
} = actions;
|
||||
|
||||
if (isDeepLink(url)) {
|
||||
const isProcessed = processDeepLink(url);
|
||||
const isProcessed = processDeepLink(url, linkContext);
|
||||
if (isProcessed || url.match(RE_TG_LINK)) {
|
||||
return;
|
||||
}
|
||||
@ -1653,7 +1655,7 @@ addActionHandler('openChatByUsername', async (global, actions, payload): Promise
|
||||
const {
|
||||
username, messageId, commentId, startParam, startAttach, attach, threadId, originalParts,
|
||||
startApp, shouldStartMainApp, mode,
|
||||
text, onChatChanged, choose, ref, timestamp,
|
||||
text, onChatChanged, choose, ref, timestamp, linkContext,
|
||||
tabId = getCurrentTabId(),
|
||||
} = payload;
|
||||
|
||||
@ -1708,6 +1710,7 @@ addActionHandler('openChatByUsername', async (global, actions, payload): Promise
|
||||
attach,
|
||||
text,
|
||||
timestamp,
|
||||
linkContext,
|
||||
}, tabId,
|
||||
);
|
||||
if (onChatChanged) {
|
||||
@ -1785,7 +1788,7 @@ addActionHandler('openChatByUsername', async (global, actions, payload): Promise
|
||||
|
||||
addActionHandler('openPrivateChannel', (global, actions, payload): ActionReturnType => {
|
||||
const {
|
||||
id, commentId, messageId, threadId, timestamp, tabId = getCurrentTabId(),
|
||||
id, commentId, messageId, threadId, timestamp, linkContext, tabId = getCurrentTabId(),
|
||||
} = payload;
|
||||
const chat = selectChat(global, id);
|
||||
if (!chat) {
|
||||
@ -1827,6 +1830,7 @@ addActionHandler('openPrivateChannel', (global, actions, payload): ActionReturnT
|
||||
messageId,
|
||||
threadId,
|
||||
timestamp,
|
||||
linkContext,
|
||||
}, tabId);
|
||||
});
|
||||
|
||||
@ -3401,11 +3405,13 @@ async function openChatByUsername<T extends GlobalState>(
|
||||
attach?: string;
|
||||
text?: string;
|
||||
timestamp?: number;
|
||||
linkContext?: LinkContext;
|
||||
},
|
||||
...[tabId = getCurrentTabId()]: TabArgs<T>
|
||||
) {
|
||||
const {
|
||||
username, threadId, channelPostId, startParam, ref, startAttach, attach, text, timestamp,
|
||||
linkContext,
|
||||
} = params;
|
||||
const currentChat = selectCurrentChat(global, tabId);
|
||||
|
||||
@ -3461,6 +3467,7 @@ async function openChatByUsername<T extends GlobalState>(
|
||||
attach,
|
||||
text,
|
||||
timestamp,
|
||||
linkContext,
|
||||
}, tabId);
|
||||
}
|
||||
|
||||
@ -3478,11 +3485,13 @@ async function openChatWithParams<T extends GlobalState>(
|
||||
attach?: string;
|
||||
text?: string;
|
||||
timestamp?: number;
|
||||
linkContext?: LinkContext;
|
||||
},
|
||||
...[tabId = getCurrentTabId()]: TabArgs<T>
|
||||
) {
|
||||
const {
|
||||
isCurrentChat, threadId, messageId, startParam, referrer, startAttach, attach, text, timestamp,
|
||||
linkContext,
|
||||
} = params;
|
||||
|
||||
if (messageId) {
|
||||
@ -3506,6 +3515,7 @@ async function openChatWithParams<T extends GlobalState>(
|
||||
if (!isTopicProcessed) {
|
||||
actions.focusMessage({
|
||||
chatId: chat.id, threadId, messageId, timestamp, tabId,
|
||||
replyMessageId: linkContext?.messageId,
|
||||
});
|
||||
}
|
||||
} else if (!isCurrentChat) {
|
||||
|
||||
@ -2372,7 +2372,7 @@ addActionHandler('readAllMentions', (global, actions, payload): ActionReturnType
|
||||
|
||||
addActionHandler('openUrl', (global, actions, payload): ActionReturnType => {
|
||||
const {
|
||||
url, shouldSkipModal, ignoreDeepLinks, tabId = getCurrentTabId(),
|
||||
url, shouldSkipModal, ignoreDeepLinks, linkContext, tabId = getCurrentTabId(),
|
||||
} = payload;
|
||||
const urlWithProtocol = ensureProtocol(url);
|
||||
const parsedUrl = new URL(urlWithProtocol);
|
||||
@ -2382,7 +2382,7 @@ addActionHandler('openUrl', (global, actions, payload): ActionReturnType => {
|
||||
actions.closeStoryViewer({ tabId });
|
||||
actions.closePaymentModal({ tabId });
|
||||
|
||||
actions.openTelegramLink({ url, tabId });
|
||||
actions.openTelegramLink({ url, linkContext, tabId });
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { LinkContext } from './../../api/types/messages';
|
||||
import type {
|
||||
ApiAttachBot,
|
||||
ApiAttachment,
|
||||
@ -55,6 +56,7 @@ import type {
|
||||
ApiUser,
|
||||
ApiVideo,
|
||||
BotsPrivacyType,
|
||||
LinkContext,
|
||||
PrivacyVisibility,
|
||||
} from '../../api/types';
|
||||
import type { ApiEmojiStatusCollectible, ApiEmojiStatusType } from '../../api/types/users';
|
||||
@ -652,6 +654,7 @@ export interface ActionPayloads {
|
||||
openTelegramLink: {
|
||||
url: string;
|
||||
shouldIgnoreCache?: boolean;
|
||||
linkContext?: LinkContext;
|
||||
} & WithTabId;
|
||||
resolveBusinessChatLink: {
|
||||
slug: string;
|
||||
@ -673,6 +676,7 @@ export interface ActionPayloads {
|
||||
originalParts?: (string | undefined)[];
|
||||
timestamp?: number;
|
||||
onChatChanged?: CallbackAction;
|
||||
linkContext?: LinkContext;
|
||||
} & WithTabId;
|
||||
processBoostParameters: {
|
||||
usernameOrId: string;
|
||||
@ -1202,6 +1206,7 @@ export interface ActionPayloads {
|
||||
messageId?: number;
|
||||
commentId?: number;
|
||||
timestamp?: number;
|
||||
linkContext?: LinkContext;
|
||||
} & WithTabId;
|
||||
loadFullChat: {
|
||||
chatId: string;
|
||||
@ -2035,6 +2040,7 @@ export interface ActionPayloads {
|
||||
clickBotInlineButton: {
|
||||
chatId: string;
|
||||
messageId: number;
|
||||
threadId?: ThreadId;
|
||||
button: ApiKeyboardButton;
|
||||
} & WithTabId;
|
||||
clickSuggestedMessageButton: {
|
||||
@ -2290,6 +2296,7 @@ export interface ActionPayloads {
|
||||
url: string;
|
||||
shouldSkipModal?: boolean;
|
||||
ignoreDeepLinks?: boolean;
|
||||
linkContext?: LinkContext;
|
||||
} & WithTabId;
|
||||
openMapModal: {
|
||||
geoPoint: ApiGeoPoint;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { getActions } from '../global';
|
||||
|
||||
import type { ApiChatType, ApiFormattedText } from '../api/types';
|
||||
import type { ApiChatType, ApiFormattedText, LinkContext } from '../api/types';
|
||||
import type { DeepLinkMethod } from './deepLinkParser';
|
||||
import { LeftColumnContent, SettingsScreens } from '../types';
|
||||
|
||||
@ -8,7 +8,7 @@ import { API_CHAT_TYPES, RE_TG_LINK, TON_CURRENCY_CODE } from '../config';
|
||||
import { IS_BAD_URL_PARSER } from './browser/globalEnvironment';
|
||||
import { tryParseDeepLink } from './deepLinkParser';
|
||||
|
||||
export const processDeepLink = (url: string): boolean => {
|
||||
export const processDeepLink = (url: string, linkContext?: LinkContext): boolean => {
|
||||
const actions = getActions();
|
||||
|
||||
const parsedLink = tryParseDeepLink(url);
|
||||
@ -21,6 +21,7 @@ export const processDeepLink = (url: string): boolean => {
|
||||
messageId: parsedLink.messageId,
|
||||
commentId: parsedLink.commentId,
|
||||
timestamp: parsedLink.timestamp,
|
||||
linkContext,
|
||||
});
|
||||
return true;
|
||||
case 'publicMessageLink': {
|
||||
@ -30,6 +31,7 @@ export const processDeepLink = (url: string): boolean => {
|
||||
messageId: parsedLink.messageId,
|
||||
commentId: parsedLink.commentId,
|
||||
timestamp: parsedLink.timestamp,
|
||||
linkContext,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user