Implement TDLib-like channel prefix (#3858)
This commit is contained in:
parent
3cd9192c1d
commit
f8c021b043
@ -220,9 +220,14 @@ export function buildApiChatFromPreview(
|
||||
if (preview instanceof GramJs.ChatEmpty || preview instanceof GramJs.UserEmpty) {
|
||||
return undefined;
|
||||
}
|
||||
const id = buildApiPeerId(
|
||||
preview.id,
|
||||
preview instanceof GramJs.User ? 'user'
|
||||
: (preview instanceof GramJs.Chat || preview instanceof GramJs.ChatForbidden) ? 'chat' : 'channel',
|
||||
);
|
||||
|
||||
return {
|
||||
id: buildApiPeerId(preview.id, preview instanceof GramJs.User ? 'user' : 'chat'),
|
||||
id,
|
||||
type: getApiChatTypeFromPeerEntity(preview),
|
||||
title: preview instanceof GramJs.User ? getUserName(preview) : preview.title,
|
||||
...buildApiChatFieldsFromPeerEntity(preview, isSupport),
|
||||
|
||||
@ -15,7 +15,15 @@ export function isPeerChannel(peer: GramJs.TypePeer | GramJs.TypeInputPeer): pee
|
||||
}
|
||||
|
||||
export function buildApiPeerId(id: BigInt.BigInteger, type: 'user' | 'chat' | 'channel') {
|
||||
return type === 'user' ? String(id) : `-${id}`;
|
||||
if (type === 'user') {
|
||||
return id.toString();
|
||||
}
|
||||
|
||||
if (type === 'channel') {
|
||||
return `-100${id}`;
|
||||
}
|
||||
|
||||
return `-${id}`;
|
||||
}
|
||||
|
||||
export function getApiChatIdFromMtpPeer(peer: GramJs.TypePeer | GramJs.TypeInputPeer) {
|
||||
|
||||
@ -37,19 +37,17 @@ import { pick } from '../../../util/iteratees';
|
||||
import { deserializeBytes } from '../helpers';
|
||||
import localDb from '../localDb';
|
||||
|
||||
const CHANNEL_ID_MIN_LENGTH = 11; // Example: -1000000000
|
||||
const CHANNEL_ID_MIN_LENGTH = 11; // Example: -1234567890
|
||||
const CHANNEL_ID_NEW_FORMAT_MIN_LENGTH = 14; // Example: -1001234567890
|
||||
|
||||
function checkIfChannelId(id: string) {
|
||||
// HOTFIX New group id range starts with -4
|
||||
if (id.length >= CHANNEL_ID_NEW_FORMAT_MIN_LENGTH) return id.startsWith('-100');
|
||||
// LEGACY Unprefixed channel id
|
||||
if (id.length === CHANNEL_ID_MIN_LENGTH && id.startsWith('-4')) return false;
|
||||
return id.length >= CHANNEL_ID_MIN_LENGTH;
|
||||
}
|
||||
|
||||
export function getEntityTypeById(chatOrUserId: string) {
|
||||
if (typeof chatOrUserId === 'number') {
|
||||
return getEntityTypeByDeprecatedId(chatOrUserId);
|
||||
}
|
||||
|
||||
if (!chatOrUserId.startsWith('-')) {
|
||||
return 'user';
|
||||
} else if (checkIfChannelId(chatOrUserId)) {
|
||||
@ -59,17 +57,6 @@ export function getEntityTypeById(chatOrUserId: string) {
|
||||
}
|
||||
}
|
||||
|
||||
// Workaround for old-fashioned IDs stored locally
|
||||
export function getEntityTypeByDeprecatedId(chatOrUserId: number) {
|
||||
if (chatOrUserId > 0) {
|
||||
return 'user';
|
||||
} else if (chatOrUserId <= -1000000000) {
|
||||
return 'channel';
|
||||
} else {
|
||||
return 'chat';
|
||||
}
|
||||
}
|
||||
|
||||
export function buildPeer(chatOrUserId: string): GramJs.TypePeer {
|
||||
const type = getEntityTypeById(chatOrUserId);
|
||||
|
||||
@ -546,12 +533,20 @@ export function buildInputThemeParams(params: ApiThemeParameters) {
|
||||
}
|
||||
|
||||
export function buildMtpPeerId(id: string, type: 'user' | 'chat' | 'channel') {
|
||||
// Workaround for old-fashioned IDs stored locally
|
||||
if (typeof id === 'number') {
|
||||
return BigInt(Math.abs(id));
|
||||
if (type === 'user') {
|
||||
return BigInt(id);
|
||||
}
|
||||
|
||||
return type === 'user' ? BigInt(id) : BigInt(id.slice(1));
|
||||
if (type === 'channel') {
|
||||
if (id.length === CHANNEL_ID_NEW_FORMAT_MIN_LENGTH) {
|
||||
return BigInt(id.slice(4));
|
||||
}
|
||||
|
||||
// LEGACY Unprefixed channel id
|
||||
return BigInt(id.slice(1));
|
||||
}
|
||||
|
||||
return BigInt(id.slice(1));
|
||||
}
|
||||
|
||||
export function buildInputGroupCall(groupCall: Partial<ApiGroupCall>) {
|
||||
|
||||
@ -480,7 +480,7 @@ export async function repairFileReference({
|
||||
if (!result || result instanceof GramJs.messages.MessagesNotModified) return false;
|
||||
|
||||
if (peer && 'pts' in result) {
|
||||
updateChannelState(peer.channelId.toString(), result.pts);
|
||||
updateChannelState(buildApiPeerId(peer.channelId, 'channel'), result.pts);
|
||||
}
|
||||
|
||||
const message = result.messages[0];
|
||||
|
||||
@ -13,7 +13,6 @@ import { TME_LINK_PREFIX } from '../../config';
|
||||
import {
|
||||
getChatLink,
|
||||
getHasAdminRight,
|
||||
getTopicLink,
|
||||
isChatChannel,
|
||||
isUserId,
|
||||
isUserRightBanned,
|
||||
@ -25,6 +24,7 @@ import {
|
||||
selectCurrentMessageList,
|
||||
selectNotifyExceptions,
|
||||
selectNotifySettings,
|
||||
selectTopicLink,
|
||||
selectUser,
|
||||
selectUserFullInfo,
|
||||
} from '../../global/selectors';
|
||||
@ -55,6 +55,7 @@ type StateProps =
|
||||
topicId?: number;
|
||||
description?: string;
|
||||
chatInviteLink?: string;
|
||||
topicLink?: string;
|
||||
};
|
||||
|
||||
const runDebounced = debounce((cb) => cb(), 500, false);
|
||||
@ -69,6 +70,7 @@ const ChatExtra: FC<OwnProps & StateProps> = ({
|
||||
topicId,
|
||||
description,
|
||||
chatInviteLink,
|
||||
topicLink,
|
||||
}) => {
|
||||
const {
|
||||
loadFullUser,
|
||||
@ -118,10 +120,8 @@ const ChatExtra: FC<OwnProps & StateProps> = ({
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return isTopicInfo
|
||||
? getTopicLink(chat.id, activeChatUsernames?.[0].username, topicId)
|
||||
: getChatLink(chat) || chatInviteLink;
|
||||
}, [chat, isTopicInfo, activeChatUsernames, topicId, chatInviteLink]);
|
||||
return isTopicInfo ? topicLink! : getChatLink(chat) || chatInviteLink;
|
||||
}, [chat, isTopicInfo, topicLink, chatInviteLink]);
|
||||
|
||||
const handleNotificationChange = useLastCallback(() => {
|
||||
setAreNotificationsEnabled((current) => {
|
||||
@ -281,6 +281,8 @@ export default memo(withGlobal<OwnProps>(
|
||||
|| getHasAdminRight(chat, 'inviteUsers')
|
||||
);
|
||||
|
||||
const topicLink = topicId ? selectTopicLink(global, chatOrUserId, topicId) : undefined;
|
||||
|
||||
return {
|
||||
phoneCodeList,
|
||||
chat,
|
||||
@ -290,6 +292,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
topicId,
|
||||
chatInviteLink,
|
||||
description,
|
||||
topicLink,
|
||||
};
|
||||
},
|
||||
)(ChatExtra));
|
||||
|
||||
@ -13,7 +13,6 @@ import type { IAlbum, IAnchorPosition } from '../../../types';
|
||||
import { PREVIEW_AVATAR_COUNT, SERVICE_NOTIFICATIONS_USER_ID } from '../../../config';
|
||||
import {
|
||||
areReactionsEmpty,
|
||||
getChatMessageLink,
|
||||
getMessageVideo,
|
||||
isActionMessage,
|
||||
isChatChannel,
|
||||
@ -36,6 +35,7 @@ import {
|
||||
selectIsPremiumPurchaseBlocked,
|
||||
selectIsReactionPickerOpen,
|
||||
selectMessageCustomEmojiSets,
|
||||
selectMessageLink,
|
||||
selectMessageTranslations,
|
||||
selectRequestedChatTranslationLanguage,
|
||||
selectRequestedMessageTranslationLanguage,
|
||||
@ -58,7 +58,6 @@ import MessageContextMenu from './MessageContextMenu';
|
||||
|
||||
export type OwnProps = {
|
||||
isOpen: boolean;
|
||||
chatUsername?: string;
|
||||
message: ApiMessage;
|
||||
album?: IAlbum;
|
||||
anchor: IAnchorPosition;
|
||||
@ -109,9 +108,9 @@ type StateProps = {
|
||||
enabledReactions?: ApiChatReactions;
|
||||
canScheduleUntilOnline?: boolean;
|
||||
maxUniqueReactions?: number;
|
||||
threadId?: number;
|
||||
canPlayAnimatedEmojis?: boolean;
|
||||
isReactionPickerOpen?: boolean;
|
||||
messageLink?: string;
|
||||
};
|
||||
|
||||
const ContextMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
@ -119,7 +118,6 @@ const ContextMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
topReactions,
|
||||
isOpen,
|
||||
messageListType,
|
||||
chatUsername,
|
||||
message,
|
||||
customEmojiSetsInfo,
|
||||
customEmojiSets,
|
||||
@ -162,10 +160,10 @@ const ContextMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
canTranslate,
|
||||
canShowOriginal,
|
||||
canSelectLanguage,
|
||||
threadId,
|
||||
isReactionPickerOpen,
|
||||
messageLink,
|
||||
onClose,
|
||||
onCloseAnimationEnd,
|
||||
isReactionPickerOpen,
|
||||
}) => {
|
||||
const {
|
||||
openChat,
|
||||
@ -403,7 +401,7 @@ const ContextMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
});
|
||||
|
||||
const handleCopyLink = useLastCallback(() => {
|
||||
copyTextToClipboard(getChatMessageLink(message.chatId, chatUsername, threadId, message.id));
|
||||
copyTextToClipboard(messageLink!);
|
||||
closeMenu();
|
||||
});
|
||||
|
||||
@ -641,6 +639,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
: undefined;
|
||||
const canTranslate = !hasTranslation && selectCanTranslateMessage(global, message, detectedLanguage);
|
||||
const isChatTranslated = selectRequestedChatTranslationLanguage(global, message.chatId);
|
||||
const messageLink = selectMessageLink(global, message.chatId, threadId, message.id);
|
||||
|
||||
return {
|
||||
availableReactions: global.availableReactions,
|
||||
@ -677,12 +676,12 @@ export default memo(withGlobal<OwnProps>(
|
||||
customEmojiSetsInfo,
|
||||
customEmojiSets,
|
||||
canScheduleUntilOnline: selectCanScheduleUntilOnline(global, message.chatId),
|
||||
threadId,
|
||||
canTranslate,
|
||||
canShowOriginal: hasTranslation && !isChatTranslated,
|
||||
canSelectLanguage: hasTranslation && !isChatTranslated,
|
||||
canPlayAnimatedEmojis: selectCanPlayAnimatedEmojis(global),
|
||||
isReactionPickerOpen: selectIsReactionPickerOpen(global),
|
||||
messageLink,
|
||||
};
|
||||
},
|
||||
)(ContextMenuContainer));
|
||||
|
||||
@ -15,7 +15,6 @@ import type {
|
||||
ApiTopic,
|
||||
ApiTypeStory,
|
||||
ApiUser,
|
||||
ApiUsername,
|
||||
} from '../../../api/types';
|
||||
import type {
|
||||
ActiveEmojiInteraction,
|
||||
@ -200,7 +199,6 @@ type OwnProps =
|
||||
type StateProps = {
|
||||
theme: ISettings['theme'];
|
||||
forceSenderName?: boolean;
|
||||
chatUsernames?: ApiUsername[];
|
||||
sender?: ApiUser | ApiChat;
|
||||
canShowSender: boolean;
|
||||
originSender?: ApiUser | ApiChat;
|
||||
@ -288,7 +286,6 @@ const RESIZE_ANIMATION_DURATION = 400;
|
||||
|
||||
const Message: FC<OwnProps & StateProps> = ({
|
||||
message,
|
||||
chatUsernames,
|
||||
observeIntersectionForBottom,
|
||||
observeIntersectionForLoading,
|
||||
observeIntersectionForPlaying,
|
||||
@ -1278,7 +1275,6 @@ const Message: FC<OwnProps & StateProps> = ({
|
||||
}
|
||||
|
||||
const forwardAuthor = isGroup && asForwarded ? message.postAuthorTitle : undefined;
|
||||
const chatUsername = useMemo(() => chatUsernames?.find((c) => c.isActive), [chatUsernames]);
|
||||
|
||||
return (
|
||||
<div
|
||||
@ -1384,7 +1380,6 @@ const Message: FC<OwnProps & StateProps> = ({
|
||||
targetHref={contextMenuTarget?.matches('a[href]') ? (contextMenuTarget as HTMLAnchorElement).href : undefined}
|
||||
message={message}
|
||||
album={album}
|
||||
chatUsername={chatUsername?.username}
|
||||
messageListType={messageListType}
|
||||
onClose={handleContextMenuClose}
|
||||
onCloseAnimationEnd={handleContextMenuHide}
|
||||
@ -1439,7 +1434,6 @@ export default memo(withGlobal<OwnProps>(
|
||||
const isRepliesChat = isChatWithRepliesBot(chatId);
|
||||
const isChannel = chat && isChatChannel(chat);
|
||||
const isGroup = chat && isChatGroup(chat);
|
||||
const chatUsernames = chat?.usernames;
|
||||
const chatFullInfo = !isUserId(chatId) ? selectChatFullInfo(global, chatId) : undefined;
|
||||
const webPageStoryData = message.content.webPage?.story;
|
||||
const webPageStory = webPageStoryData
|
||||
@ -1529,7 +1523,6 @@ export default memo(withGlobal<OwnProps>(
|
||||
|
||||
return {
|
||||
theme: selectTheme(global),
|
||||
chatUsernames,
|
||||
forceSenderName,
|
||||
canShowSender,
|
||||
originSender,
|
||||
|
||||
@ -285,7 +285,7 @@ export const RESTRICTED_EMOJI_SET_ID = '7173162320003080';
|
||||
export const DEFAULT_GIF_SEARCH_BOT_USERNAME = 'gif';
|
||||
export const ALL_FOLDER_ID = 0;
|
||||
export const ARCHIVED_FOLDER_ID = 1;
|
||||
export const DELETED_COMMENTS_CHANNEL_ID = '-777';
|
||||
export const DELETED_COMMENTS_CHANNEL_ID = '-100777';
|
||||
export const MAX_MEDIA_FILES_FOR_ALBUM = 10;
|
||||
export const MAX_ACTIVE_PINNED_CHATS = 5;
|
||||
export const SCHEDULED_WHEN_ONLINE = 0x7FFFFFFE;
|
||||
|
||||
@ -1065,7 +1065,7 @@ addActionHandler('openTelegramLink', (global, actions, payload): ActionReturnTyp
|
||||
tabId,
|
||||
});
|
||||
} else if (part1 === 'c' && chatOrChannelPostId && messageId) {
|
||||
const chatId = `-${chatOrChannelPostId}`;
|
||||
const chatId = `-100${chatOrChannelPostId}`;
|
||||
const chat = selectChat(global, chatId);
|
||||
if (!chat) {
|
||||
showNotification({ message: 'Chat does not exist', tabId });
|
||||
@ -1073,7 +1073,7 @@ addActionHandler('openTelegramLink', (global, actions, payload): ActionReturnTyp
|
||||
}
|
||||
|
||||
focusMessage({
|
||||
chatId,
|
||||
chatId: chat.id,
|
||||
messageId,
|
||||
tabId,
|
||||
});
|
||||
|
||||
@ -18,7 +18,7 @@ import {
|
||||
import { formatDateToString, formatTime } from '../../util/dateFormat';
|
||||
import { orderBy } from '../../util/iteratees';
|
||||
import { prepareSearchWordsForNeedle } from '../../util/searchWords';
|
||||
import { getUserFirstOrLastName } from './users';
|
||||
import { getMainUsername, getUserFirstOrLastName } from './users';
|
||||
|
||||
const FOREVER_BANNED_DATE = Date.now() / 1000 + 31622400; // 366 days
|
||||
|
||||
@ -26,11 +26,6 @@ const VERIFIED_PRIORITY_BASE = 3e9;
|
||||
const PINNED_PRIORITY_BASE = 3e8;
|
||||
|
||||
export function isUserId(entityId: string) {
|
||||
// Workaround for old-fashioned IDs stored locally
|
||||
if (typeof entityId === 'number') {
|
||||
return entityId > 0;
|
||||
}
|
||||
|
||||
return !entityId.startsWith('-');
|
||||
}
|
||||
|
||||
@ -87,20 +82,9 @@ export function getChatTitle(lang: LangFn, chat: ApiChat, isSelf = false) {
|
||||
}
|
||||
|
||||
export function getChatLink(chat: ApiChat) {
|
||||
const activeUsername = chat.usernames?.find((u) => u.isActive);
|
||||
const activeUsername = getMainUsername(chat);
|
||||
|
||||
return activeUsername ? `${TME_LINK_PREFIX}${activeUsername.username}` : undefined;
|
||||
}
|
||||
|
||||
export function getChatMessageLink(chatId: string, chatUsername?: string, threadId?: number, messageId?: number) {
|
||||
const chatPart = chatUsername || `c/${chatId.replace('-', '')}`;
|
||||
const threadPart = threadId && threadId !== MAIN_THREAD_ID ? `/${threadId}` : '';
|
||||
const messagePart = messageId ? `/${messageId}` : '';
|
||||
return `${TME_LINK_PREFIX}${chatPart}${threadPart}${messagePart}`;
|
||||
}
|
||||
|
||||
export function getTopicLink(chatId: string, chatUsername?: string, topicId?: number) {
|
||||
return getChatMessageLink(chatId, chatUsername, topicId);
|
||||
return activeUsername ? `${TME_LINK_PREFIX}${activeUsername}` : undefined;
|
||||
}
|
||||
|
||||
export function getChatAvatarHash(
|
||||
|
||||
@ -13,7 +13,7 @@ import type {
|
||||
import { ApiMessageEntityTypes, MAIN_THREAD_ID } from '../../api/types';
|
||||
|
||||
import {
|
||||
GENERAL_TOPIC_ID, REPLIES_USER_ID, SERVICE_NOTIFICATIONS_USER_ID,
|
||||
GENERAL_TOPIC_ID, REPLIES_USER_ID, SERVICE_NOTIFICATIONS_USER_ID, TME_LINK_PREFIX,
|
||||
} from '../../config';
|
||||
import { getCurrentTabId } from '../../util/establishMultitabRole';
|
||||
import { findLast } from '../../util/iteratees';
|
||||
@ -25,6 +25,7 @@ import {
|
||||
getAllowedAttachmentOptions,
|
||||
getCanPostInChat,
|
||||
getHasAdminRight,
|
||||
getMainUsername,
|
||||
getMessageAudio,
|
||||
getMessageDocument,
|
||||
getMessageOriginalId,
|
||||
@ -1353,3 +1354,28 @@ export function selectCanTranslateMessage<T extends GlobalState>(
|
||||
return IS_TRANSLATION_SUPPORTED && isTranslationEnabled && canTranslateLanguage && isTranslatable
|
||||
&& !chatRequestedLanguage;
|
||||
}
|
||||
|
||||
export function selectMessageLink<T extends GlobalState>(
|
||||
global: T, chatId: string, threadId?: number, messageId?: number,
|
||||
) {
|
||||
const chat = selectChat(global, chatId);
|
||||
if (!chat) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const chatUsername = getMainUsername(chat);
|
||||
|
||||
const isChannelId = isChatChannel(chat) || isChatSuperGroup(chat);
|
||||
const normalizedId = isChannelId ? chatId.replace('-100', '') : chatId.replace('-', '');
|
||||
|
||||
const chatPart = chatUsername || `c/${normalizedId}`;
|
||||
const threadPart = threadId && threadId !== MAIN_THREAD_ID ? `/${threadId}` : '';
|
||||
const messagePart = messageId ? `/${messageId}` : '';
|
||||
return `${TME_LINK_PREFIX}${chatPart}${threadPart}${messagePart}`;
|
||||
}
|
||||
|
||||
export function selectTopicLink<T extends GlobalState>(
|
||||
global: T, chatId: string, topicId?: number,
|
||||
) {
|
||||
return selectMessageLink(global, chatId, topicId);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user