Chats: Various fixes (#3880)

This commit is contained in:
Alexander Zinchuk 2023-09-25 18:53:24 +02:00
parent e8c4b8f713
commit b89ef33aec
18 changed files with 134 additions and 70 deletions

View File

@ -17,6 +17,7 @@ import {
} from '../../types'; } from '../../types';
import { compact } from '../../../util/iteratees'; import { compact } from '../../../util/iteratees';
import localDb from '../localDb';
import { bytesToDataUri } from './helpers'; import { bytesToDataUri } from './helpers';
import { pathBytesToSvg } from './pathBytesToSvg'; import { pathBytesToSvg } from './pathBytesToSvg';
import { buildApiPeerId } from './peers'; import { buildApiPeerId } from './peers';
@ -154,6 +155,8 @@ export function buildPrivacyRules(rules: GramJs.TypePrivacyRule[]): ApiPrivacySe
let blockUserIds: string[] | undefined; let blockUserIds: string[] | undefined;
let blockChatIds: string[] | undefined; let blockChatIds: string[] | undefined;
const localChats = localDb.chats;
rules.forEach((rule) => { rules.forEach((rule) => {
if (rule instanceof GramJs.PrivacyValueAllowAll) { if (rule instanceof GramJs.PrivacyValueAllowAll) {
visibility ||= 'everybody'; visibility ||= 'everybody';
@ -170,9 +173,20 @@ export function buildPrivacyRules(rules: GramJs.TypePrivacyRule[]): ApiPrivacySe
} else if (rule instanceof GramJs.PrivacyValueDisallowUsers) { } else if (rule instanceof GramJs.PrivacyValueDisallowUsers) {
blockUserIds = rule.users.map((chatId) => buildApiPeerId(chatId, 'user')); blockUserIds = rule.users.map((chatId) => buildApiPeerId(chatId, 'user'));
} else if (rule instanceof GramJs.PrivacyValueAllowChatParticipants) { } else if (rule instanceof GramJs.PrivacyValueAllowChatParticipants) {
allowChatIds = rule.chats.map((chatId) => buildApiPeerId(chatId, 'chat')); // Server allows channel ids here, so we need to check
allowChatIds = rule.chats.map((chatId) => {
const dialogId = buildApiPeerId(chatId, 'chat');
const channelId = buildApiPeerId(chatId, 'channel');
if (localChats[dialogId]) return dialogId;
return channelId;
});
} else if (rule instanceof GramJs.PrivacyValueDisallowChatParticipants) { } else if (rule instanceof GramJs.PrivacyValueDisallowChatParticipants) {
blockChatIds = rule.chats.map((chatId) => buildApiPeerId(chatId, 'chat')); blockChatIds = rule.chats.map((chatId) => {
const dialogId = buildApiPeerId(chatId, 'chat');
const channelId = buildApiPeerId(chatId, 'channel');
if (localChats[dialogId]) return dialogId;
return channelId;
});
} }
}); });

View File

@ -31,19 +31,18 @@ import {
ApiMessageEntityTypes, ApiMessageEntityTypes,
} from '../../types'; } from '../../types';
import { DEFAULT_STATUS_ICON_ID } from '../../../config'; import { CHANNEL_ID_LENGTH, DEFAULT_STATUS_ICON_ID } from '../../../config';
import { pick } from '../../../util/iteratees'; import { pick } from '../../../util/iteratees';
import { deserializeBytes } from '../helpers'; import { deserializeBytes } from '../helpers';
import localDb from '../localDb'; import localDb from '../localDb';
const CHANNEL_ID_MIN_LENGTH = 11; // Example: -1234567890 const LEGACY_CHANNEL_ID_MIN_LENGTH = 11; // Example: -1234567890
const CHANNEL_ID_NEW_FORMAT_MIN_LENGTH = 14; // Example: -1001234567890
function checkIfChannelId(id: string) { function checkIfChannelId(id: string) {
if (id.length >= CHANNEL_ID_NEW_FORMAT_MIN_LENGTH) return id.startsWith('-100'); if (id.length >= CHANNEL_ID_LENGTH) return id.startsWith('-100');
// LEGACY Unprefixed channel id // LEGACY Unprefixed channel id
if (id.length === CHANNEL_ID_MIN_LENGTH && id.startsWith('-4')) return false; if (id.length === LEGACY_CHANNEL_ID_MIN_LENGTH && id.startsWith('-4')) return false;
return id.length >= CHANNEL_ID_MIN_LENGTH; return id.length >= LEGACY_CHANNEL_ID_MIN_LENGTH;
} }
export function getEntityTypeById(chatOrUserId: string) { export function getEntityTypeById(chatOrUserId: string) {
@ -543,7 +542,7 @@ export function buildMtpPeerId(id: string, type: 'user' | 'chat' | 'channel') {
} }
if (type === 'channel') { if (type === 'channel') {
if (id.length === CHANNEL_ID_NEW_FORMAT_MIN_LENGTH) { if (id.length === CHANNEL_ID_LENGTH) {
return BigInt(id.slice(4)); return BigInt(id.slice(4));
} }

View File

@ -12,7 +12,7 @@ import { IS_TEST } from '../../config';
import { import {
getChatAvatarHash, getChatAvatarHash,
getChatTitle, getChatTitle,
getUserColorKey, getPeerColorKey,
getUserFullName, getUserFullName,
getUserStoryHtmlId, getUserStoryHtmlId,
isChatWithRepliesBot, isChatWithRepliesBot,
@ -208,7 +208,7 @@ const Avatar: FC<OwnProps> = ({
const fullClassName = buildClassName( const fullClassName = buildClassName(
`Avatar size-${size}`, `Avatar size-${size}`,
className, className,
`color-bg-${getUserColorKey(peer)}`, `color-bg-${getPeerColorKey(peer)}`,
isSavedMessages && 'saved-messages', isSavedMessages && 'saved-messages',
isDeleted && 'deleted-account', isDeleted && 'deleted-account',
isReplies && 'replies-bot-account', isReplies && 'replies-bot-account',

View File

@ -12,8 +12,8 @@ import {
getMessageIsSpoiler, getMessageIsSpoiler,
getMessageMediaHash, getMessageMediaHash,
getMessageRoundVideo, getMessageRoundVideo,
getPeerColorKey,
getSenderTitle, getSenderTitle,
getUserColorKey,
isActionMessage, isActionMessage,
isMessageTranslatable, isMessageTranslatable,
} from '../../global/helpers'; } from '../../global/helpers';
@ -93,7 +93,7 @@ const EmbeddedMessage: FC<OwnProps> = ({
className={buildClassName( className={buildClassName(
'EmbeddedMessage', 'EmbeddedMessage',
className, className,
sender && !noUserColors && `color-${getUserColorKey(sender)}`, sender && !noUserColors && `color-${getPeerColorKey(sender)}`,
)} )}
onClick={message && handleClick} onClick={message && handleClick}
onMouseDown={message && handleMouseDown} onMouseDown={message && handleMouseDown}

View File

@ -6,9 +6,9 @@ import type { ApiChat, ApiTypeStory, ApiUser } from '../../api/types';
import type { ObserveFn } from '../../hooks/useIntersectionObserver'; import type { ObserveFn } from '../../hooks/useIntersectionObserver';
import { import {
getPeerColorKey,
getSenderTitle, getSenderTitle,
getStoryMediaHash, getStoryMediaHash,
getUserColorKey,
} from '../../global/helpers'; } from '../../global/helpers';
import buildClassName from '../../util/buildClassName'; import buildClassName from '../../util/buildClassName';
import { getPictogramDimensions } from './helpers/mediaDimensions'; import { getPictogramDimensions } from './helpers/mediaDimensions';
@ -75,7 +75,7 @@ const EmbeddedStory: FC<OwnProps> = ({
ref={ref} ref={ref}
className={buildClassName( className={buildClassName(
'EmbeddedMessage', 'EmbeddedMessage',
sender && !noUserColors && `color-${getUserColorKey(sender)}`, sender && !noUserColors && `color-${getPeerColorKey(sender)}`,
)} )}
onClick={handleClick} onClick={handleClick}
onMouseDown={handleMouseDown} onMouseDown={handleMouseDown}

View File

@ -6,7 +6,7 @@ import type { ApiChat, ApiPhoto, ApiUser } from '../../api/types';
import { import {
getChatAvatarHash, getChatAvatarHash,
getChatTitle, getChatTitle,
getUserColorKey, getPeerColorKey,
getUserFullName, getUserFullName,
getVideoAvatarMediaHash, getVideoAvatarMediaHash,
isChatWithRepliesBot, isChatWithRepliesBot,
@ -139,7 +139,7 @@ const ProfilePhoto: FC<OwnProps> = ({
const fullClassName = buildClassName( const fullClassName = buildClassName(
'ProfilePhoto', 'ProfilePhoto',
`color-bg-${getUserColorKey(user || chat)}`, `color-bg-${getPeerColorKey(user || chat)}`,
isSavedMessages && 'saved-messages', isSavedMessages && 'saved-messages',
isDeleted && 'deleted-account', isDeleted && 'deleted-account',
isRepliesChat && 'replies-bot-account', isRepliesChat && 'replies-bot-account',

View File

@ -5,7 +5,7 @@ import { getActions, withGlobal } from '../../global';
import type { ApiSticker, ApiUpdateConnectionStateType } from '../../api/types'; import type { ApiSticker, ApiUpdateConnectionStateType } from '../../api/types';
import type { MessageList } from '../../global/types'; import type { MessageList } from '../../global/types';
import { getUserIdDividend } from '../../global/helpers'; import { getPeerIdDividend } from '../../global/helpers';
import { selectChat, selectCurrentMessageList } from '../../global/selectors'; import { selectChat, selectCurrentMessageList } from '../../global/selectors';
import useLang from '../../hooks/useLang'; import useLang from '../../hooks/useLang';
@ -94,7 +94,7 @@ const ContactGreeting: FC<OwnProps & StateProps> = ({
export default memo(withGlobal<OwnProps>( export default memo(withGlobal<OwnProps>(
(global, { userId }): StateProps => { (global, { userId }): StateProps => {
const { stickers } = global.stickers.greeting; const { stickers } = global.stickers.greeting;
const dividend = getUserIdDividend(userId) + getUserIdDividend(global.currentUserId!); const dividend = getPeerIdDividend(userId) + getPeerIdDividend(global.currentUserId!);
const sticker = stickers?.length ? stickers[dividend % stickers.length] : undefined; const sticker = stickers?.length ? stickers[dividend % stickers.length] : undefined;
const chat = selectChat(global, userId); const chat = selectChat(global, userId);
if (!chat) { if (!chat) {

View File

@ -54,12 +54,18 @@ const AttachBotItem: FC<OwnProps> = ({
}); });
const handleClick = useLastCallback(() => { const handleClick = useLastCallback(() => {
callAttachBot({ if (isInSideMenu) {
bot, callAttachBot({
chatId: chatId!, bot,
threadId, isFromSideMenu: true,
isFromSideMenu: isInSideMenu, });
}); } else {
callAttachBot({
bot,
chatId: chatId!,
threadId,
});
}
}); });
const handleCloseMenu = useLastCallback(() => { const handleCloseMenu = useLastCallback(() => {

View File

@ -38,8 +38,8 @@ import {
getMessageLocation, getMessageLocation,
getMessageSingleCustomEmoji, getMessageSingleCustomEmoji,
getMessageSingleRegularEmoji, getMessageSingleRegularEmoji,
getPeerColorKey,
getSenderTitle, getSenderTitle,
getUserColorKey,
hasMessageText, hasMessageText,
isAnonymousOwnMessage, isAnonymousOwnMessage,
isChatChannel, isChatChannel,
@ -1209,7 +1209,7 @@ const Message: FC<OwnProps & StateProps> = ({
senderTitle = getSenderTitle(lang, senderPeer); senderTitle = getSenderTitle(lang, senderPeer);
if (!asForwarded && !isOwn) { if (!asForwarded && !isOwn) {
senderColor = `color-${getUserColorKey(senderPeer)}`; senderColor = `color-${getPeerColorKey(senderPeer)}`;
} }
} else if (forwardInfo?.hiddenUserName) { } else if (forwardInfo?.hiddenUserName) {
senderTitle = forwardInfo.hiddenUserName; senderTitle = forwardInfo.hiddenUserName;

View File

@ -129,6 +129,7 @@ export const DRAFT_DEBOUNCE = 10000; // 10s
export const SEND_MESSAGE_ACTION_INTERVAL = 3000; // 3s export const SEND_MESSAGE_ACTION_INTERVAL = 3000; // 3s
// 10000s from https://corefork.telegram.org/api/url-authorization#automatic-authorization // 10000s from https://corefork.telegram.org/api/url-authorization#automatic-authorization
export const APP_CONFIG_REFETCH_INTERVAL = 10000 * 1000; export const APP_CONFIG_REFETCH_INTERVAL = 10000 * 1000;
export const GENERAL_REFETCH_INTERVAL = 60 * 60 * 1000; // 1h
export const EDITABLE_INPUT_ID = 'editable-message-text'; export const EDITABLE_INPUT_ID = 'editable-message-text';
export const EDITABLE_INPUT_MODAL_ID = 'editable-message-text-modal'; export const EDITABLE_INPUT_MODAL_ID = 'editable-message-text-modal';
@ -282,6 +283,7 @@ export const API_CHAT_TYPES = ['bots', 'channels', 'chats', 'users'] as const;
export const SERVICE_NOTIFICATIONS_USER_ID = '777000'; export const SERVICE_NOTIFICATIONS_USER_ID = '777000';
export const REPLIES_USER_ID = '1271266957'; // TODO For Test connection ID must be equal to 708513 export const REPLIES_USER_ID = '1271266957'; // TODO For Test connection ID must be equal to 708513
export const RESTRICTED_EMOJI_SET_ID = '7173162320003080'; export const RESTRICTED_EMOJI_SET_ID = '7173162320003080';
export const CHANNEL_ID_LENGTH = 14; // 14 symbols, including -100 prefix
export const DEFAULT_GIF_SEARCH_BOT_USERNAME = 'gif'; export const DEFAULT_GIF_SEARCH_BOT_USERNAME = 'gif';
export const ALL_FOLDER_ID = 0; export const ALL_FOLDER_ID = 0;
export const ARCHIVED_FOLDER_ID = 1; export const ARCHIVED_FOLDER_ID = 1;

View File

@ -6,10 +6,12 @@ import type { RequiredGlobalActions } from '../../index';
import type { ActionReturnType, GlobalState, TabArgs } from '../../types'; import type { ActionReturnType, GlobalState, TabArgs } from '../../types';
import { MAIN_THREAD_ID } from '../../../api/types'; import { MAIN_THREAD_ID } from '../../../api/types';
import { GENERAL_REFETCH_INTERVAL } from '../../../config';
import { getCurrentTabId } from '../../../util/establishMultitabRole'; import { getCurrentTabId } from '../../../util/establishMultitabRole';
import { buildCollectionByKey } from '../../../util/iteratees'; import { buildCollectionByKey } from '../../../util/iteratees';
import { translate } from '../../../util/langProvider'; import { translate } from '../../../util/langProvider';
import PopupManager from '../../../util/PopupManager'; import PopupManager from '../../../util/PopupManager';
import requestActionTimeout from '../../../util/requestActionTimeout';
import { debounce } from '../../../util/schedulers'; import { debounce } from '../../../util/schedulers';
import { getServerTime } from '../../../util/serverTime'; import { getServerTime } from '../../../util/serverTime';
import { extractCurrentThemeParams } from '../../../util/themeStyle'; import { extractCurrentThemeParams } from '../../../util/themeStyle';
@ -721,7 +723,12 @@ addActionHandler('markBotTrusted', (global, actions, payload): ActionReturnType
addActionHandler('loadAttachBots', async (global, actions, payload): Promise<void> => { addActionHandler('loadAttachBots', async (global, actions, payload): Promise<void> => {
const { hash } = payload || {}; const { hash } = payload || {};
await loadAttachBots(global, hash); const result = await loadAttachBots(global, hash);
requestActionTimeout({
action: 'loadAttachBots',
payload: { hash: result?.hash },
}, GENERAL_REFETCH_INTERVAL);
}); });
addActionHandler('toggleAttachBot', async (global, actions, payload): Promise<void> => { addActionHandler('toggleAttachBot', async (global, actions, payload): Promise<void> => {
@ -737,7 +744,7 @@ addActionHandler('toggleAttachBot', async (global, actions, payload): Promise<vo
async function loadAttachBots<T extends GlobalState>(global: T, hash?: string) { async function loadAttachBots<T extends GlobalState>(global: T, hash?: string) {
const result = await callApi('loadAttachBots', { hash }); const result = await callApi('loadAttachBots', { hash });
if (!result) { if (!result) {
return; return undefined;
} }
global = getGlobal(); global = getGlobal();
@ -750,16 +757,20 @@ async function loadAttachBots<T extends GlobalState>(global: T, hash?: string) {
}, },
}; };
setGlobal(global); setGlobal(global);
return result;
} }
addActionHandler('callAttachBot', (global, actions, payload): ActionReturnType => { addActionHandler('callAttachBot', (global, actions, payload): ActionReturnType => {
const { const {
chatId, bot, url, startParam, threadId, isFromSideMenu, bot, startParam, isFromConfirm, tabId = getCurrentTabId(),
tabId = getCurrentTabId(),
} = payload; } = payload;
const isFromSideMenu = 'isFromSideMenu' in payload && payload.isFromSideMenu;
const isFromBotMenu = !bot; const isFromBotMenu = !bot;
if ((!isFromBotMenu && !global.attachMenu.bots[bot.id]) const shouldDisplayDisclaimer = (!isFromBotMenu && !global.attachMenu.bots[bot.id])
|| (isFromSideMenu && (bot?.isInactive || bot?.isDisclaimerNeeded))) { || (isFromSideMenu && (bot?.isInactive || bot?.isDisclaimerNeeded));
if (!isFromConfirm && shouldDisplayDisclaimer) {
return updateTabState(global, { return updateTabState(global, {
requestedAttachBotInstall: { requestedAttachBotInstall: {
bot, bot,
@ -767,11 +778,7 @@ addActionHandler('callAttachBot', (global, actions, payload): ActionReturnType =
action: 'callAttachBot', action: 'callAttachBot',
payload: { payload: {
...payload, ...payload,
bot: { isFromConfirm: true,
...bot,
isInactive: false,
isDisclaimerNeeded: false,
},
}, },
}, },
}, },
@ -784,15 +791,19 @@ addActionHandler('callAttachBot', (global, actions, payload): ActionReturnType =
botId: bot!.id, botId: bot!.id,
buttonText: '', buttonText: '',
isFromSideMenu: true, isFromSideMenu: true,
startParam,
theme, theme,
tabId, tabId,
}); });
} else { }
if ('chatId' in payload) {
const { chatId, threadId, url } = payload;
actions.openChat({ id: chatId, threadId, tabId }); actions.openChat({ id: chatId, threadId, tabId });
actions.requestWebView({ actions.requestWebView({
url, url,
peerId: chatId, peerId: chatId!,
botId: isFromBotMenu ? chatId : bot.id, botId: (isFromBotMenu ? chatId : bot.id)!,
theme, theme,
buttonText: '', buttonText: '',
isFromBotMenu, isFromBotMenu,
@ -818,6 +829,7 @@ addActionHandler('confirmAttachBotInstall', async (global, actions, payload): Pr
const botUser = selectUser(global, bot.id); const botUser = selectUser(global, bot.id);
if (!botUser) return; if (!botUser) return;
actions.markBotTrusted({ botId: bot.id, isWriteAllowed, tabId });
await callApi('toggleAttachBot', { bot: botUser, isWriteAllowed, isEnabled: true }); await callApi('toggleAttachBot', { bot: botUser, isWriteAllowed, isEnabled: true });
if (onConfirm) { if (onConfirm) {
const { action, payload: actionPayload } = onConfirm; const { action, payload: actionPayload } = onConfirm;

View File

@ -999,14 +999,15 @@ addActionHandler('openTelegramLink', (global, actions, payload): ActionReturnTyp
hash = part2; hash = part2;
} }
const startAttach = params.hasOwnProperty('startattach') && !params.startattach ? true : params.startattach; const hasStartAttach = params.hasOwnProperty('startattach');
const hasStartApp = params.hasOwnProperty('startapp');
const choose = parseChooseParameter(params.choose); const choose = parseChooseParameter(params.choose);
const storyId = part2 === 's' && (Number(part3) || undefined); const storyId = part2 === 's' && (Number(part3) || undefined);
if (part1.match(/^\+([0-9]+)(\?|$)/)) { if (part1.match(/^\+([0-9]+)(\?|$)/)) {
openChatByPhoneNumber({ openChatByPhoneNumber({
phoneNumber: part1.substr(1, part1.length - 1), phoneNumber: part1.substr(1, part1.length - 1),
startAttach, startAttach: params.startattach,
attach: params.attach, attach: params.attach,
tabId, tabId,
}); });
@ -1087,11 +1088,11 @@ addActionHandler('openTelegramLink', (global, actions, payload): ActionReturnTyp
slug: part2, slug: part2,
tabId, tabId,
}); });
} else if (startAttach && choose) { } else if ((hasStartAttach && choose) || (!part2 && hasStartApp)) {
processAttachBotParameters({ processAttachBotParameters({
username: part1, username: part1,
filter: choose, filter: choose,
...(typeof startAttach === 'string' && { startParam: startAttach }), startParam: params.startattach || params.startapp,
tabId, tabId,
}); });
} else { } else {
@ -1101,7 +1102,7 @@ addActionHandler('openTelegramLink', (global, actions, payload): ActionReturnTyp
threadId: messageId ? Number(chatOrChannelPostId) : undefined, threadId: messageId ? Number(chatOrChannelPostId) : undefined,
commentId, commentId,
startParam: params.start, startParam: params.start,
startAttach, startAttach: params.startattach,
attach: params.attach, attach: params.attach,
startApp: params.startapp, startApp: params.startapp,
originalParts: [part1, part2, part3], originalParts: [part1, part2, part3],
@ -1701,6 +1702,18 @@ addActionHandler('processAttachBotParameters', async (global, actions, payload):
const bot = await getAttachBotOrNotify(global, actions, username, tabId); const bot = await getAttachBotOrNotify(global, actions, username, tabId);
if (!bot) return; if (!bot) return;
const isForChat = Boolean(filter);
if (!isForChat) {
actions.callAttachBot({
isFromSideMenu: true,
bot,
startParam,
tabId,
});
return;
}
global = getGlobal(); global = getGlobal();
const { attachMenu: { bots } } = global; const { attachMenu: { bots } } = global;
if (!bots[bot.id]) { if (!bots[bot.id]) {
@ -1720,7 +1733,6 @@ addActionHandler('processAttachBotParameters', async (global, actions, payload):
setGlobal(global); setGlobal(global);
return; return;
} }
actions.requestAttachBotInChat({ actions.requestAttachBotInChat({
bot, bot,
filter, filter,

View File

@ -1,9 +1,11 @@
import type { ActionReturnType } from '../../types'; import type { ActionReturnType } from '../../types';
import { ApiMediaFormat } from '../../../api/types'; import { ApiMediaFormat } from '../../../api/types';
import { GENERAL_REFETCH_INTERVAL } from '../../../config';
import { getCurrentTabId } from '../../../util/establishMultitabRole'; import { getCurrentTabId } from '../../../util/establishMultitabRole';
import { buildCollectionByKey, omit } from '../../../util/iteratees'; import { buildCollectionByKey, omit } from '../../../util/iteratees';
import * as mediaLoader from '../../../util/mediaLoader'; import * as mediaLoader from '../../../util/mediaLoader';
import requestActionTimeout from '../../../util/requestActionTimeout';
import { callApi } from '../../../api/gramjs'; import { callApi } from '../../../api/gramjs';
import { import {
getDocumentMediaHash, getDocumentMediaHash,
@ -61,6 +63,11 @@ addActionHandler('loadAvailableReactions', async (global): Promise<void> => {
availableReactions: result, availableReactions: result,
}; };
setGlobal(global); setGlobal(global);
requestActionTimeout({
action: 'loadAvailableReactions',
payload: undefined,
}, GENERAL_REFETCH_INTERVAL);
}); });
addActionHandler('interactWithAnimatedEmoji', (global, actions, payload): ActionReturnType => { addActionHandler('interactWithAnimatedEmoji', (global, actions, payload): ActionReturnType => {

View File

@ -13,7 +13,7 @@ import {
} from '../../api/types'; } from '../../api/types';
import { import {
ARCHIVED_FOLDER_ID, GENERAL_TOPIC_ID, REPLIES_USER_ID, TME_LINK_PREFIX, ARCHIVED_FOLDER_ID, CHANNEL_ID_LENGTH, GENERAL_TOPIC_ID, REPLIES_USER_ID, TME_LINK_PREFIX,
} from '../../config'; } from '../../config';
import { formatDateToString, formatTime } from '../../util/dateFormat'; import { formatDateToString, formatTime } from '../../util/dateFormat';
import { orderBy } from '../../util/iteratees'; import { orderBy } from '../../util/iteratees';
@ -24,11 +24,16 @@ const FOREVER_BANNED_DATE = Date.now() / 1000 + 31622400; // 366 days
const VERIFIED_PRIORITY_BASE = 3e9; const VERIFIED_PRIORITY_BASE = 3e9;
const PINNED_PRIORITY_BASE = 3e8; const PINNED_PRIORITY_BASE = 3e8;
const USER_COLOR_KEYS = [1, 8, 5, 2, 7, 4, 6];
export function isUserId(entityId: string) { export function isUserId(entityId: string) {
return !entityId.startsWith('-'); return !entityId.startsWith('-');
} }
export function isChannelId(entityId: string) {
return entityId.length === CHANNEL_ID_LENGTH && entityId.startsWith('-100');
}
export function isChatGroup(chat: ApiChat) { export function isChatGroup(chat: ApiChat) {
return isChatBasicGroup(chat) || isChatSuperGroup(chat); return isChatBasicGroup(chat) || isChatSuperGroup(chat);
} }
@ -448,3 +453,18 @@ export function getOrderedTopics(
return [...pinnedOrdered, ...ordered, ...hidden]; return [...pinnedOrdered, ...ordered, ...hidden];
} }
} }
export function getCleanPeerId(peerId: string) {
return isChannelId(peerId) ? peerId.replace('-100', '') : peerId.replace('-', '');
}
export function getPeerIdDividend(peerId: string) {
return Math.abs(Number(getCleanPeerId(peerId)));
}
// https://github.com/telegramdesktop/tdesktop/blob/371510cfe23b0bd226de8c076bc49248fbe40c26/Telegram/SourceFiles/data/data_peer.cpp#L53
export function getPeerColorKey(peer: ApiUser | ApiChat | undefined) {
const index = peer ? getPeerIdDividend(peer.id) % 7 : 0;
return USER_COLOR_KEYS[index];
}

View File

@ -8,8 +8,6 @@ import { formatPhoneNumber } from '../../util/phoneNumber';
import { prepareSearchWordsForNeedle } from '../../util/searchWords'; import { prepareSearchWordsForNeedle } from '../../util/searchWords';
import { getServerTime, getServerTimeOffset } from '../../util/serverTime'; import { getServerTime, getServerTimeOffset } from '../../util/serverTime';
const USER_COLOR_KEYS = [1, 8, 5, 2, 7, 4, 6];
export function getUserFirstOrLastName(user?: ApiUser) { export function getUserFirstOrLastName(user?: ApiUser) {
if (!user) { if (!user) {
return undefined; return undefined;
@ -261,17 +259,6 @@ export function filterUsersByName(
}); });
} }
export function getUserIdDividend(peerId: string) {
return Math.abs(Number(peerId));
}
// https://github.com/telegramdesktop/tdesktop/blob/371510cfe23b0bd226de8c076bc49248fbe40c26/Telegram/SourceFiles/data/data_peer.cpp#L53
export function getUserColorKey(peer: ApiUser | ApiChat | undefined) {
const index = peer ? getUserIdDividend(peer.id) % 7 : 0;
return USER_COLOR_KEYS[index];
}
export function getMainUsername(userOrChat: ApiUser | ApiChat) { export function getMainUsername(userOrChat: ApiUser | ApiChat) {
return userOrChat.usernames?.find((u) => u.isActive)?.username; return userOrChat.usernames?.find((u) => u.isActive)?.username;
} }

View File

@ -2378,7 +2378,7 @@ export interface ActionPayloads {
processAttachBotParameters: { processAttachBotParameters: {
username: string; username: string;
filter: ApiChatType[]; filter?: ApiChatType[];
startParam?: string; startParam?: string;
} & WithTabId; } & WithTabId;
requestAttachBotInChat: { requestAttachBotInChat: {
@ -2404,13 +2404,16 @@ export interface ActionPayloads {
isEnabled: boolean; isEnabled: boolean;
}; };
callAttachBot: { callAttachBot: ({
chatId: string; chatId: string;
threadId?: number; threadId?: number;
bot?: ApiAttachBot;
url?: string; url?: string;
} | {
isFromSideMenu: true;
}) & {
startParam?: string; startParam?: string;
isFromSideMenu?: boolean; bot?: ApiAttachBot;
isFromConfirm?: boolean;
} & WithTabId; } & WithTabId;
requestBotUrlAuth: { requestBotUrlAuth: {

View File

@ -41,7 +41,8 @@ export const processDeepLink = (url: string) => {
appname, startapp, story, appname, startapp, story,
} = params; } = params;
const startAttach = params.hasOwnProperty('startattach') && !startattach ? true : startattach; const hasStartAttach = params.hasOwnProperty('startattach');
const hasStartApp = params.hasOwnProperty('startapp');
const choose = parseChooseParameter(params.choose); const choose = parseChooseParameter(params.choose);
const threadId = Number(thread) || Number(topic) || undefined; const threadId = Number(thread) || Number(topic) || undefined;
@ -52,11 +53,11 @@ export const processDeepLink = (url: string) => {
startApp: startapp, startApp: startapp,
originalParts: [domain, appname], originalParts: [domain, appname],
}); });
} else if (startAttach && choose) { } else if ((hasStartAttach && choose) || (!appname && hasStartApp)) {
processAttachBotParameters({ processAttachBotParameters({
username: domain, username: domain,
filter: choose, filter: choose,
...(typeof startAttach === 'string' && { startParam: startAttach }), startParam: startattach || startapp,
}); });
} else if (params.hasOwnProperty('voicechat') || params.hasOwnProperty('livestream')) { } else if (params.hasOwnProperty('voicechat') || params.hasOwnProperty('livestream')) {
joinVoiceChatByLink({ joinVoiceChatByLink({
@ -64,7 +65,7 @@ export const processDeepLink = (url: string) => {
inviteHash: voicechat || livestream, inviteHash: voicechat || livestream,
}); });
} else if (phone) { } else if (phone) {
openChatByPhoneNumber({ phoneNumber: phone, startAttach, attach }); openChatByPhoneNumber({ phoneNumber: phone, startAttach: startattach, attach });
} else if (story) { } else if (story) {
openStoryViewerByUsername({ username: domain, storyId: Number(story) }); openStoryViewerByUsername({ username: domain, storyId: Number(story) });
} else { } else {
@ -73,7 +74,7 @@ export const processDeepLink = (url: string) => {
messageId: post ? Number(post) : undefined, messageId: post ? Number(post) : undefined,
commentId: comment ? Number(comment) : undefined, commentId: comment ? Number(comment) : undefined,
startParam: start, startParam: start,
startAttach, startAttach: startattach,
attach, attach,
threadId, threadId,
}); });

View File

@ -4,6 +4,7 @@ import type { CallbackAction } from '../global/types';
const callbacks = new Map<string, number>(); const callbacks = new Map<string, number>();
// TODO Pass callbacks to the master tab. Sync them on master change
export default function requestActionTimeout(action: CallbackAction, timeout: number) { export default function requestActionTimeout(action: CallbackAction, timeout: number) {
const name = action.action; const name = action.action;
clearTimeout(callbacks.get(name)); clearTimeout(callbacks.get(name));