Left Search: Search message deep link (#4061)
This commit is contained in:
parent
0f5bdc05be
commit
74fd74203e
@ -177,8 +177,7 @@ const ChatResults: FC<OwnProps & StateProps> = ({
|
|||||||
|
|
||||||
return globalMessagesByChatId?.[chatId]?.byId[Number(messageId)];
|
return globalMessagesByChatId?.[chatId]?.byId[Number(messageId)];
|
||||||
})
|
})
|
||||||
.filter(Boolean)
|
.filter(Boolean);
|
||||||
.sort((a, b) => b.date - a.date);
|
|
||||||
}, [foundIds, globalMessagesByChatId, searchQuery, searchDate]);
|
}, [foundIds, globalMessagesByChatId, searchQuery, searchDate]);
|
||||||
|
|
||||||
const handleClickShowMoreLocal = useCallback(() => {
|
const handleClickShowMoreLocal = useCallback(() => {
|
||||||
|
|||||||
@ -5,10 +5,12 @@ import type { ActionReturnType, GlobalState, TabArgs } from '../../types';
|
|||||||
|
|
||||||
import { GLOBAL_SEARCH_SLICE, GLOBAL_TOPIC_SEARCH_SLICE } from '../../../config';
|
import { GLOBAL_SEARCH_SLICE, GLOBAL_TOPIC_SEARCH_SLICE } from '../../../config';
|
||||||
import { timestampPlusDay } from '../../../util/dateFormat';
|
import { timestampPlusDay } from '../../../util/dateFormat';
|
||||||
|
import { DeepLinkType, isDeepLink, tryParseDeepLink } from '../../../util/deepLinkParser';
|
||||||
import { getCurrentTabId } from '../../../util/establishMultitabRole';
|
import { getCurrentTabId } from '../../../util/establishMultitabRole';
|
||||||
import { buildCollectionByKey } from '../../../util/iteratees';
|
import { buildCollectionByKey } from '../../../util/iteratees';
|
||||||
import { throttle } from '../../../util/schedulers';
|
import { throttle } from '../../../util/schedulers';
|
||||||
import { callApi } from '../../../api/gramjs';
|
import { callApi } from '../../../api/gramjs';
|
||||||
|
import { isChatChannel, isChatGroup, toChannelId } from '../../helpers/chats';
|
||||||
import { addActionHandler, getGlobal, setGlobal } from '../../index';
|
import { addActionHandler, getGlobal, setGlobal } from '../../index';
|
||||||
import {
|
import {
|
||||||
addChats,
|
addChats,
|
||||||
@ -19,7 +21,9 @@ import {
|
|||||||
updateGlobalSearchResults,
|
updateGlobalSearchResults,
|
||||||
updateTopics,
|
updateTopics,
|
||||||
} from '../../reducers';
|
} from '../../reducers';
|
||||||
import { selectChat, selectCurrentGlobalSearchQuery, selectTabState } from '../../selectors';
|
import {
|
||||||
|
selectChat, selectChatByUsername, selectChatMessage, selectCurrentGlobalSearchQuery, selectTabState,
|
||||||
|
} from '../../selectors';
|
||||||
|
|
||||||
const searchThrottled = throttle((cb) => cb(), 500, false);
|
const searchThrottled = throttle((cb) => cb(), 500, false);
|
||||||
|
|
||||||
@ -120,6 +124,8 @@ async function searchMessagesGlobal<T extends GlobalState>(
|
|||||||
nextRate: number | undefined;
|
nextRate: number | undefined;
|
||||||
} | undefined;
|
} | undefined;
|
||||||
|
|
||||||
|
let messageLink: ApiMessage | undefined;
|
||||||
|
|
||||||
if (chat) {
|
if (chat) {
|
||||||
const localResultRequest = callApi('searchMessagesLocal', {
|
const localResultRequest = callApi('searchMessagesLocal', {
|
||||||
chat,
|
chat,
|
||||||
@ -164,6 +170,14 @@ async function searchMessagesGlobal<T extends GlobalState>(
|
|||||||
maxDate,
|
maxDate,
|
||||||
minDate,
|
minDate,
|
||||||
});
|
});
|
||||||
|
if (isDeepLink(query)) {
|
||||||
|
const link = tryParseDeepLink(query);
|
||||||
|
if (link?.type === DeepLinkType.PublicMessageLink) {
|
||||||
|
messageLink = await getMessageByPublicLink(global, link);
|
||||||
|
} else if (link?.type === DeepLinkType.PrivateMessageLink) {
|
||||||
|
messageLink = await getMessageByPrivateLink(global, link);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
global = getGlobal();
|
global = getGlobal();
|
||||||
@ -174,6 +188,10 @@ async function searchMessagesGlobal<T extends GlobalState>(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (messageLink) {
|
||||||
|
result.totalCount = result.messages.unshift(messageLink);
|
||||||
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
messages, users, chats, totalCount, nextRate,
|
messages, users, chats, totalCount, nextRate,
|
||||||
} = result;
|
} = result;
|
||||||
@ -210,3 +228,38 @@ async function searchMessagesGlobal<T extends GlobalState>(
|
|||||||
|
|
||||||
setGlobal(global);
|
setGlobal(global);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getMessageByPublicLink(global: GlobalState, link: { username: string; messageId: number }) {
|
||||||
|
const { username, messageId } = link;
|
||||||
|
const localChat = selectChatByUsername(global, username);
|
||||||
|
if (localChat) {
|
||||||
|
return getChatGroupOrChannelMessage(global, localChat, messageId);
|
||||||
|
}
|
||||||
|
const { chat } = await callApi('getChatByUsername', username) ?? {};
|
||||||
|
if (!chat) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return getChatGroupOrChannelMessage(global, chat, messageId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMessageByPrivateLink(global: GlobalState, link: { channelId: string; messageId: number }) {
|
||||||
|
const { channelId, messageId } = link;
|
||||||
|
const internalChannelId = toChannelId(channelId);
|
||||||
|
const chat = selectChat(global, internalChannelId);
|
||||||
|
if (!chat) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return getChatGroupOrChannelMessage(global, chat, messageId);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getChatGroupOrChannelMessage(global: GlobalState, chat: ApiChat, messageId: number) {
|
||||||
|
if (!isChatGroup(chat) && !isChatChannel(chat)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
const localMessage = selectChatMessage(global, chat.id, messageId);
|
||||||
|
if (localMessage) {
|
||||||
|
return localMessage;
|
||||||
|
}
|
||||||
|
const result = await callApi('fetchMessage', { chat, messageId });
|
||||||
|
return result === 'MESSAGE_DELETED' ? undefined : result?.message;
|
||||||
|
}
|
||||||
|
|||||||
@ -26,13 +26,12 @@ import {
|
|||||||
MAX_MEDIA_FILES_FOR_ALBUM,
|
MAX_MEDIA_FILES_FOR_ALBUM,
|
||||||
MESSAGE_LIST_SLICE,
|
MESSAGE_LIST_SLICE,
|
||||||
RE_TELEGRAM_LINK,
|
RE_TELEGRAM_LINK,
|
||||||
RE_TG_LINK,
|
|
||||||
RE_TME_LINK,
|
|
||||||
SERVICE_NOTIFICATIONS_USER_ID,
|
SERVICE_NOTIFICATIONS_USER_ID,
|
||||||
SUPPORTED_AUDIO_CONTENT_TYPES,
|
SUPPORTED_AUDIO_CONTENT_TYPES,
|
||||||
SUPPORTED_IMAGE_CONTENT_TYPES,
|
SUPPORTED_IMAGE_CONTENT_TYPES,
|
||||||
SUPPORTED_VIDEO_CONTENT_TYPES,
|
SUPPORTED_VIDEO_CONTENT_TYPES,
|
||||||
} from '../../../config';
|
} from '../../../config';
|
||||||
|
import { isDeepLink } from '../../../util/deepLinkParser';
|
||||||
import { ensureProtocol } from '../../../util/ensureProtocol';
|
import { ensureProtocol } from '../../../util/ensureProtocol';
|
||||||
import { getCurrentTabId } from '../../../util/establishMultitabRole';
|
import { getCurrentTabId } from '../../../util/establishMultitabRole';
|
||||||
import {
|
import {
|
||||||
@ -1542,7 +1541,7 @@ addActionHandler('openUrl', (global, actions, payload): ActionReturnType => {
|
|||||||
const urlWithProtocol = ensureProtocol(url)!;
|
const urlWithProtocol = ensureProtocol(url)!;
|
||||||
const isStoriesViewerOpen = Boolean(selectTabState(global, tabId).storyViewer.peerId);
|
const isStoriesViewerOpen = Boolean(selectTabState(global, tabId).storyViewer.peerId);
|
||||||
|
|
||||||
if (urlWithProtocol.match(RE_TME_LINK) || urlWithProtocol.match(RE_TG_LINK)) {
|
if (isDeepLink(urlWithProtocol)) {
|
||||||
if (isStoriesViewerOpen) {
|
if (isStoriesViewerOpen) {
|
||||||
actions.closeStoryViewer({ tabId });
|
actions.closeStoryViewer({ tabId });
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { RE_TG_LINK, RE_TME_LINK } from '../config';
|
||||||
import { isUsernameValid } from './username';
|
import { isUsernameValid } from './username';
|
||||||
|
|
||||||
export type DeepLinkMethod = 'resolve' | 'login' | 'passport' | 'settings' | 'join' | 'addstickers' | 'addemoji' |
|
export type DeepLinkMethod = 'resolve' | 'login' | 'passport' | 'settings' | 'join' | 'addstickers' | 'addemoji' |
|
||||||
@ -50,6 +51,10 @@ type BuilderReturnType<T extends DeepLink> = T | undefined;
|
|||||||
|
|
||||||
const ELIGIBLE_HOSTNAMES = new Set(['t.me', 'telegram.me', 'telegram.dog']);
|
const ELIGIBLE_HOSTNAMES = new Set(['t.me', 'telegram.me', 'telegram.dog']);
|
||||||
|
|
||||||
|
export function isDeepLink(link: string): boolean {
|
||||||
|
return Boolean(link.match(RE_TME_LINK) || link.match(RE_TG_LINK));
|
||||||
|
}
|
||||||
|
|
||||||
export function tryParseDeepLink(link: string): DeepLink | undefined {
|
export function tryParseDeepLink(link: string): DeepLink | undefined {
|
||||||
try {
|
try {
|
||||||
return parseDeepLink(link);
|
return parseDeepLink(link);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user