Update to layer 133 (#1525)

This commit is contained in:
Alexander Zinchuk 2021-11-05 21:56:58 +03:00
parent d4d11b7d4b
commit 1e60003f5a
177 changed files with 2202 additions and 2040 deletions

View File

@ -11,7 +11,7 @@
"deploy:production": "npm run build:production && git add -A && git commit -a -m '[Build]' --no-verify && git push",
"inc_version": "echo $((`cat .patch-version` + 1)) > .patch-version && echo \"$(node -p -e \"require('./package.json').version.match(/^\\d+\\.\\d+/)[0]\").$(cat .patch-version)\"",
"perf:serve": "cross-env APP_ENV=perf parcel src/index-perf.html",
"lint": "eslint . --ext .ts,.tsx --ignore-pattern src/lib/gramjs",
"lint": "tsc && eslint . --ext .ts,.tsx --ignore-pattern src/lib/gramjs",
"lint:fix": "npm run lint -- --fix",
"gramjs:tl": "node ./src/lib/gramjs/tl/generateModules.js",
"gramjs:lint:fix": "eslint ./src/lib/gramjs --ignore-path=src/lib/gramjs/.eslintignore --fix",

View File

@ -1,3 +1,4 @@
import BigInt from 'big-integer';
import { Api as GramJs } from '../../../lib/gramjs';
import {
ApiChat,
@ -10,7 +11,7 @@ import {
} from '../../types';
import { pick, pickTruthy } from '../../../util/iteratees';
import {
isInputPeerChannel, isInputPeerChat, isInputPeerUser, isPeerChat, isPeerUser,
buildApiPeerId, getApiChatIdFromMtpPeer, isPeerChat, isPeerUser,
} from './peers';
import { omitVirtualClassFields } from './helpers';
import { getServerTime } from '../../../util/serverTime';
@ -93,11 +94,13 @@ function buildApiChatPermissions(peerEntity: GramJs.TypeUser | GramJs.TypeChat):
}
return {
adminRights: omitVirtualClassFields(peerEntity.adminRights),
currentUserBannedRights: peerEntity instanceof GramJs.Channel
adminRights: peerEntity.adminRights ? omitVirtualClassFields(peerEntity.adminRights) : undefined,
currentUserBannedRights: peerEntity instanceof GramJs.Channel && peerEntity.bannedRights
? omitVirtualClassFields(peerEntity.bannedRights)
: undefined,
defaultBannedRights: omitVirtualClassFields(peerEntity.defaultBannedRights),
defaultBannedRights: peerEntity.defaultBannedRights
? omitVirtualClassFields(peerEntity.defaultBannedRights)
: undefined,
};
}
@ -146,7 +149,7 @@ function buildApiChatRestrictions(peerEntity: GramJs.TypeUser | GramJs.TypeChat)
function buildApiChatMigrationInfo(peerEntity: GramJs.TypeChat): {
migratedTo?: {
chatId: number;
chatId: string;
accessHash?: string;
};
} {
@ -159,7 +162,7 @@ function buildApiChatMigrationInfo(peerEntity: GramJs.TypeChat): {
migratedTo: {
chatId: getApiChatIdFromMtpPeer(peerEntity.migratedTo),
...(peerEntity.migratedTo instanceof GramJs.InputChannel && {
accessHash: peerEntity.migratedTo.accessHash.toString(),
accessHash: String(peerEntity.migratedTo.accessHash),
}),
},
};
@ -200,34 +203,13 @@ export function buildApiChatFromPreview(
}
return {
id: preview instanceof GramJs.User ? preview.id : -preview.id,
id: buildApiPeerId(preview.id, preview instanceof GramJs.User ? 'user' : 'chat'),
type: getApiChatTypeFromPeerEntity(preview),
title: preview instanceof GramJs.User ? getUserName(preview) : preview.title,
...buildApiChatFieldsFromPeerEntity(preview, isSupport),
};
}
export function getApiChatIdFromMtpPeer(peer: GramJs.TypePeer): number {
if (isPeerUser(peer)) {
return peer.userId;
} else if (isPeerChat(peer)) {
return -peer.chatId;
} else {
return -peer.channelId;
}
}
export function getApiChatIdFromInputMtpPeer(peer: GramJs.TypeInputPeer): number | undefined {
if (isInputPeerUser(peer)) {
return peer.userId;
} else if (isInputPeerChat(peer)) {
return -peer.chatId;
} else if (isInputPeerChannel(peer)) {
return -peer.channelId;
}
return undefined;
}
export function getApiChatTypeFromPeerEntity(peerEntity: GramJs.TypeChat | GramJs.TypeUser) {
if (peerEntity instanceof GramJs.User || peerEntity instanceof GramJs.UserEmpty) {
return 'chatTypePrivate';
@ -268,7 +250,7 @@ function getUserName(user: GramJs.User) {
export function buildAvatarHash(photo: GramJs.TypeUserProfilePhoto | GramJs.TypeChatPhoto) {
if ('photoId' in photo) {
return photo.photoId.toString();
return String(photo.photoId);
}
return undefined;
@ -279,14 +261,14 @@ export function buildChatMember(
): ApiChatMember | undefined {
const userId = (member instanceof GramJs.ChannelParticipantBanned || member instanceof GramJs.ChannelParticipantLeft)
? getApiChatIdFromMtpPeer(member.peer)
: member.userId;
: buildApiPeerId(member.userId, 'user');
return {
userId,
inviterId: 'inviterId' in member ? member.inviterId : undefined,
inviterId: 'inviterId' in member ? buildApiPeerId(member.inviterId as BigInt.BigInteger, 'user') : undefined,
joinedDate: 'date' in member ? member.date : undefined,
kickedByUserId: 'kickedBy' in member ? member.kickedBy : undefined,
promotedByUserId: 'promotedBy' in member ? member.promotedBy : undefined,
kickedByUserId: 'kickedBy' in member ? buildApiPeerId(member.kickedBy, 'user') : undefined,
promotedByUserId: 'promotedBy' in member ? buildApiPeerId(member.promotedBy, 'user') : undefined,
bannedRights: 'bannedRights' in member ? omitVirtualClassFields(member.bannedRights) : undefined,
adminRights: 'adminRights' in member ? omitVirtualClassFields(member.adminRights) : undefined,
customTitle: 'rank' in member ? member.rank : undefined,
@ -362,9 +344,9 @@ export function buildApiChatFolder(filter: GramJs.DialogFilter): ApiChatFolder {
'excludeMuted', 'excludeRead', 'excludeArchived',
]),
channels: filter.broadcasts,
pinnedChatIds: filter.pinnedPeers.map(getApiChatIdFromInputMtpPeer).filter<number>(Boolean as any),
includedChatIds: filter.includePeers.map(getApiChatIdFromInputMtpPeer).filter<number>(Boolean as any),
excludedChatIds: filter.excludePeers.map(getApiChatIdFromInputMtpPeer).filter<number>(Boolean as any),
pinnedChatIds: filter.pinnedPeers.map(getApiChatIdFromMtpPeer).filter<string>(Boolean as any),
includedChatIds: filter.includePeers.map(getApiChatIdFromMtpPeer).filter<string>(Boolean as any),
excludedChatIds: filter.excludePeers.map(getApiChatIdFromMtpPeer).filter<string>(Boolean as any),
};
}
@ -382,8 +364,10 @@ export function buildApiChatFolderFromSuggested({
export function buildApiChatBotCommands(botInfos: GramJs.BotInfo[]) {
return botInfos.reduce((botCommands, botInfo) => {
const botId = buildApiPeerId(botInfo.userId, 'user');
botCommands = botCommands.concat(botInfo.commands.map((mtpCommand) => ({
botId: botInfo.userId,
botId,
...omitVirtualClassFields(mtpCommand),
})));

View File

@ -1,20 +1,29 @@
import { Api as GramJs } from '../../../lib/gramjs';
type VirtualFields =
'flags'
| 'CONSTRUCTOR_ID'
| 'SUBCLASS_OF_ID'
| 'className'
| 'classType'
| 'getBytes';
export function bytesToDataUri(bytes: Buffer, shouldOmitPrefix = false, mimeType: string = 'image/jpeg') {
const prefix = shouldOmitPrefix ? '' : `data:${mimeType};base64,`;
return `${prefix}${btoa(String.fromCharCode(...bytes))}`;
}
export function omitVirtualClassFields(instance: any) {
if (!instance) {
return undefined;
}
export function omitVirtualClassFields<T extends GramJs.VirtualClass<T> & { flags?: any }>(
instance: T,
): Omit<T, VirtualFields> {
const {
flags,
CONSTRUCTOR_ID,
SUBCLASS_OF_ID,
className,
classType,
getBytes,
...rest
} = instance;

View File

@ -32,21 +32,20 @@ import {
VIDEO_MOV_TYPE,
} from '../../../config';
import { pick } from '../../../util/iteratees';
import { getApiChatIdFromMtpPeer } from './chats';
import { buildStickerFromDocument } from './symbols';
import { buildApiPhoto, buildApiPhotoSize, buildApiThumbnailFromStripped } from './common';
import { interpolateArray } from '../../../util/waveform';
import { buildPeer } from '../gramjsBuilders';
import { addPhotoToLocalDb, resolveMessageApiChatId } from '../helpers';
import { buildApiPeerId, getApiChatIdFromMtpPeer } from './peers';
const LOCAL_IMAGE_UPLOADING_TEMP_ID = 'temp';
const LOCAL_VIDEO_UPLOADING_TEMP_ID = 'temp';
const LOCAL_MEDIA_UPLOADING_TEMP_ID = 'temp';
const INPUT_WAVEFORM_LENGTH = 63;
let localMessageCounter = LOCAL_MESSAGE_ID_BASE;
let currentUserId!: number;
let currentUserId!: string;
export function setMessageBuilderCurrentUserId(_currentUserId: number) {
export function setMessageBuilderCurrentUserId(_currentUserId: string) {
currentUserId = _currentUserId;
}
@ -62,20 +61,20 @@ export function buildApiMessage(mtpMessage: GramJs.TypeMessage): ApiMessage | un
}
export function buildApiMessageFromShort(mtpMessage: GramJs.UpdateShortMessage): ApiMessage {
const chatId = getApiChatIdFromMtpPeer({ userId: mtpMessage.userId } as GramJs.TypePeer);
const chatId = buildApiPeerId(mtpMessage.userId, 'user');
return buildApiMessageWithChatId(chatId, {
...mtpMessage,
fromId: buildPeer(mtpMessage.out ? currentUserId : mtpMessage.userId),
fromId: buildPeer(mtpMessage.out ? currentUserId : buildApiPeerId(mtpMessage.userId, 'user')),
});
}
export function buildApiMessageFromShortChat(mtpMessage: GramJs.UpdateShortChatMessage): ApiMessage {
const chatId = getApiChatIdFromMtpPeer({ chatId: mtpMessage.chatId } as GramJs.TypePeer);
const chatId = buildApiPeerId(mtpMessage.chatId, 'chat');
return buildApiMessageWithChatId(chatId, {
...mtpMessage,
fromId: buildPeer(mtpMessage.fromId),
fromId: buildPeer(buildApiPeerId(mtpMessage.fromId, 'user')),
});
}
@ -117,7 +116,7 @@ type UniversalMessage = (
)>
);
export function buildApiMessageWithChatId(chatId: number, mtpMessage: UniversalMessage): ApiMessage {
export function buildApiMessageWithChatId(chatId: string, mtpMessage: UniversalMessage): ApiMessage {
const fromId = mtpMessage.fromId ? getApiChatIdFromMtpPeer(mtpMessage.fromId) : undefined;
const peerId = mtpMessage.peerId ? getApiChatIdFromMtpPeer(mtpMessage.peerId) : undefined;
const isChatWithSelf = !fromId && chatId === currentUserId;
@ -151,7 +150,7 @@ export function buildApiMessageWithChatId(chatId: number, mtpMessage: UniversalM
} = buildReplyButtons(mtpMessage) || {};
const forwardInfo = mtpMessage.fwdFrom && buildApiMessageForwardInfo(mtpMessage.fwdFrom, isChatWithSelf);
const { replies, mediaUnread: isMediaUnread, postAuthor } = mtpMessage;
const groupedId = mtpMessage.groupedId && mtpMessage.groupedId.toString();
const groupedId = mtpMessage.groupedId && String(mtpMessage.groupedId);
const isInAlbum = Boolean(groupedId) && !(content.document || content.audio);
const shouldHideKeyboardButtons = mtpMessage.replyMarkup instanceof GramJs.ReplyKeyboardHide;
@ -179,7 +178,7 @@ export function buildApiMessageWithChatId(chatId: number, mtpMessage: UniversalM
inlineButtons,
...(keyboardButtons && { keyboardButtons, keyboardPlaceholder, isKeyboardSingleUse }),
...(shouldHideKeyboardButtons && { shouldHideKeyboardButtons }),
...(mtpMessage.viaBotId && { viaBotId: mtpMessage.viaBotId }),
...(mtpMessage.viaBotId && { viaBotId: buildApiPeerId(mtpMessage.viaBotId, 'user') }),
...(replies?.comments && { threadInfo: buildThreadInfo(replies, mtpMessage.id, chatId) }),
...(postAuthor && { adminTitle: postAuthor }),
};
@ -463,12 +462,13 @@ function buildContact(media: GramJs.TypeMessageMedia): ApiContact | undefined {
return undefined;
}
return pick(media, [
'firstName',
'lastName',
'phoneNumber',
'userId',
]);
const {
firstName, lastName, phoneNumber, userId,
} = media;
return {
firstName, lastName, phoneNumber, userId: buildApiPeerId(userId, 'user'),
};
}
function buildPollFromMedia(media: GramJs.TypeMessageMedia): ApiPoll | undefined {
@ -495,7 +495,7 @@ export function buildPoll(poll: GramJs.Poll, pollResults: GramJs.PollResults): A
}));
return {
id: id.toString(),
id: String(id),
summary: {
isPublic: poll.publicVoters,
...pick(poll, [
@ -543,7 +543,7 @@ export function buildPollResults(pollResults: GramJs.PollResults): ApiPoll['resu
return {
totalVoters,
recentVoterIds: recentVoters,
recentVoterIds: recentVoters?.map((id) => buildApiPeerId(id, 'user')),
results,
solution,
...(entities && { solutionEntities: entities.map(buildApiMessageEntity) }),
@ -584,8 +584,8 @@ export function buildWebPage(media: GramJs.TypeMessageMedia): ApiWebPage | undef
function buildAction(
action: GramJs.TypeMessageAction,
senderId: number | undefined,
targetPeerId: number | undefined,
senderId: string | undefined,
targetPeerId: string | undefined,
isChannelPost: boolean,
isOutgoing: boolean,
): ApiAction | undefined {
@ -601,9 +601,9 @@ function buildAction(
let photo: ApiPhoto | undefined;
const targetUserIds = 'users' in action
? action.users && action.users
: ('userId' in action && [action.userId]) || [];
let targetChatId: number | undefined;
? action.users && action.users.map((id) => buildApiPeerId(id, 'user'))
: ('userId' in action && [buildApiPeerId(action.userId, 'user')]) || [];
let targetChatId: string | undefined;
if (action instanceof GramJs.MessageActionChatCreate) {
text = 'Notification.CreatedChatWithTitle';
@ -908,7 +908,7 @@ function buildUploadingMedia(
if (mimeType.startsWith('image/')) {
return {
photo: {
id: LOCAL_IMAGE_UPLOADING_TEMP_ID,
id: LOCAL_MEDIA_UPLOADING_TEMP_ID,
sizes: [],
thumbnail: { width, height, dataUri: '' }, // Used only for dimensions
blobUrl,
@ -917,7 +917,7 @@ function buildUploadingMedia(
} else {
return {
video: {
id: LOCAL_VIDEO_UPLOADING_TEMP_ID,
id: LOCAL_MEDIA_UPLOADING_TEMP_ID,
mimeType,
duration: duration || 0,
fileName,
@ -962,7 +962,7 @@ function buildUploadingMedia(
function buildNewPoll(poll: ApiNewPoll, localId: number) {
return {
poll: {
id: localId.toString(),
id: String(localId),
summary: pick(poll.summary, ['question', 'answers']),
results: {},
},
@ -981,22 +981,26 @@ function buildApiMessageEntity(entity: GramJs.TypeMessageEntity): ApiMessageEnti
}
function buildThreadInfo(
messageReplies: GramJs.TypeMessageReplies, messageId: number, chatId: number,
messageReplies: GramJs.TypeMessageReplies, messageId: number, chatId: string,
): ApiThreadInfo | undefined {
const {
channelId, replies, maxId, readMaxId, recentRepliers,
} = messageReplies;
if (channelId === DELETED_COMMENTS_CHANNEL_ID) {
if (!channelId) {
return undefined;
}
const isPostThread = chatId !== channelId;
const apiChannelId = buildApiPeerId(channelId, 'channel');
if (apiChannelId === DELETED_COMMENTS_CHANNEL_ID) {
return undefined;
}
const isPostThread = chatId !== apiChannelId;
return {
threadId: messageId,
...(isPostThread ? {
chatId: getApiChatIdFromMtpPeer({ channelId } as GramJs.TypePeer),
chatId: apiChannelId,
originChannelId: chatId,
} : {
chatId,

View File

@ -4,7 +4,7 @@ import { ApiCountry, ApiSession, ApiWallpaper } from '../../types';
import { ApiPrivacySettings, ApiPrivacyKey, PrivacyVisibility } from '../../../types';
import { buildApiDocument } from './messages';
import { getApiChatIdFromMtpPeer } from './chats';
import { buildApiPeerId, getApiChatIdFromMtpPeer } from './peers';
import { flatten, pick } from '../../../util/iteratees';
import { getServerTime } from '../../../util/serverTime';
@ -60,10 +60,10 @@ export function buildPrivacyKey(key: GramJs.TypePrivacyKey): ApiPrivacyKey | und
export function buildPrivacyRules(rules: GramJs.TypePrivacyRule[]): ApiPrivacySettings {
let visibility: PrivacyVisibility | undefined;
let allowUserIds: number[] | undefined;
let allowChatIds: number[] | undefined;
let blockUserIds: number[] | undefined;
let blockChatIds: number[] | undefined;
let allowUserIds: string[] | undefined;
let allowChatIds: string[] | undefined;
let blockUserIds: string[] | undefined;
let blockChatIds: string[] | undefined;
rules.forEach((rule) => {
if (rule instanceof GramJs.PrivacyValueAllowAll) {
@ -75,13 +75,13 @@ export function buildPrivacyRules(rules: GramJs.TypePrivacyRule[]): ApiPrivacySe
} else if (rule instanceof GramJs.PrivacyValueDisallowAll) {
visibility = visibility || 'nobody';
} else if (rule instanceof GramJs.PrivacyValueAllowUsers) {
allowUserIds = rule.users;
allowUserIds = rule.users.map((chatId) => buildApiPeerId(chatId, 'user'));
} else if (rule instanceof GramJs.PrivacyValueDisallowUsers) {
blockUserIds = rule.users;
blockUserIds = rule.users.map((chatId) => buildApiPeerId(chatId, 'user'));
} else if (rule instanceof GramJs.PrivacyValueAllowChatParticipants) {
allowChatIds = rule.chats.map((id) => -id);
allowChatIds = rule.chats.map((chatId) => buildApiPeerId(chatId, 'chat'));
} else if (rule instanceof GramJs.PrivacyValueDisallowChatParticipants) {
blockChatIds = rule.chats.map((id) => -id);
blockChatIds = rule.chats.map((chatId) => buildApiPeerId(chatId, 'chat'));
}
});
@ -113,6 +113,7 @@ export function buildApiNotifyException(
...(showPreviews !== undefined && { shouldShowPreviews: Boolean(showPreviews) }),
};
}
function buildApiCountry(country: GramJs.help.Country, code?: GramJs.help.CountryCode) {
const {
hidden, iso2, defaultName, name,

View File

@ -96,7 +96,7 @@ export function buildPaymentForm(form: GramJs.payments.PaymentForm) {
canSaveCredentials,
passwordMissing,
formId: String(formId),
providerId,
providerId: String(providerId),
nativeProvider,
savedInfo,
invoice: {

View File

@ -1,25 +1,29 @@
import BigInt from 'big-integer';
import { Api as GramJs } from '../../../lib/gramjs';
export function isPeerUser(peer: GramJs.TypePeer): peer is GramJs.PeerUser {
export function isPeerUser(peer: GramJs.TypePeer | GramJs.TypeInputPeer): peer is GramJs.PeerUser {
return peer.hasOwnProperty('userId');
}
export function isPeerChat(peer: GramJs.TypePeer): peer is GramJs.PeerChat {
export function isPeerChat(peer: GramJs.TypePeer | GramJs.TypeInputPeer): peer is GramJs.PeerChat {
return peer.hasOwnProperty('chatId');
}
export function isPeerChannel(peer: GramJs.TypePeer): peer is GramJs.PeerChannel {
export function isPeerChannel(peer: GramJs.TypePeer | GramJs.TypeInputPeer): peer is GramJs.PeerChannel {
return peer.hasOwnProperty('channelId');
}
export function isInputPeerUser(peer: GramJs.TypeInputPeer): peer is GramJs.InputPeerUser {
return peer.hasOwnProperty('userId');
export function buildApiPeerId(id: BigInt.BigInteger, type: 'user' | 'chat' | 'channel') {
return type === 'user' ? String(id) : `-${id}`;
}
export function isInputPeerChat(peer: GramJs.TypeInputPeer): peer is GramJs.InputPeerChat {
return peer.hasOwnProperty('chatId');
}
export function isInputPeerChannel(peer: GramJs.TypeInputPeer): peer is GramJs.InputPeerChannel {
return peer.hasOwnProperty('channelId');
export function getApiChatIdFromMtpPeer(peer: GramJs.TypePeer | GramJs.TypeInputPeer) {
if (isPeerUser(peer)) {
return buildApiPeerId(peer.userId, 'user');
} else if (isPeerChat(peer)) {
return buildApiPeerId(peer.chatId, 'chat');
} else {
return buildApiPeerId((peer as GramJs.InputPeerChannel).channelId, 'channel');
}
}

View File

@ -72,7 +72,6 @@ export function buildStickerSet(set: GramJs.StickerSet): ApiStickerSet {
title,
thumbs,
count,
hash,
shortName,
} = set;
@ -85,7 +84,6 @@ export function buildStickerSet(set: GramJs.StickerSet): ApiStickerSet {
title,
hasThumbnail: Boolean(thumbs?.length),
count,
hash,
shortName,
};
}

View File

@ -2,21 +2,24 @@ import { Api as GramJs } from '../../../lib/gramjs';
import {
ApiBotCommand, ApiUser, ApiUserStatus, ApiUserType,
} from '../../types';
import { buildApiPeerId } from './peers';
export function buildApiUserFromFull(mtpUserFull: GramJs.UserFull): ApiUser {
const {
about, commonChatsCount, pinnedMsgId, botInfo, blocked,
} = mtpUserFull;
const user = buildApiUser(mtpUserFull.user)!;
return {
...(buildApiUser(mtpUserFull.user) as ApiUser),
...user,
fullInfo: {
bio: about,
commonChatsCount,
pinnedMessageId: pinnedMsgId,
isBlocked: Boolean(blocked),
...(botInfo && { botDescription: botInfo.description }),
...(botInfo && botInfo.commands.length && { botCommands: buildApiBotCommands(mtpUserFull.user.id, botInfo) }),
...(botInfo && botInfo.commands.length && { botCommands: buildApiBotCommands(user.id, botInfo) }),
},
};
}
@ -33,7 +36,7 @@ export function buildApiUser(mtpUser: GramJs.TypeUser): ApiUser | undefined {
const userType = buildApiUserType(mtpUser);
return {
id,
id: buildApiPeerId(id, 'user'),
isMin: Boolean(mtpUser.min),
...(mtpUser.self && { isSelf: true }),
...(mtpUser.verified && { isVerified: true }),
@ -78,7 +81,7 @@ export function buildApiUserStatus(mtpStatus?: GramJs.TypeUserStatus): ApiUserSt
}
}
function buildApiBotCommands(botId: number, botInfo: GramJs.BotInfo) {
function buildApiBotCommands(botId: string, botInfo: GramJs.BotInfo) {
return botInfo.commands.map(({ command, description }) => ({
botId,
command,

View File

@ -18,7 +18,24 @@ import {
import localDb from '../localDb';
import { pick } from '../../../util/iteratees';
export function getEntityTypeById(chatOrUserId: number) {
const CHANNEL_ID_MIN_LENGTH = 11; // Example: -1000000000
export function getEntityTypeById(chatOrUserId: string) {
if (typeof chatOrUserId === 'number') {
return getEntityTypeByDeprecatedId(chatOrUserId);
}
if (!chatOrUserId.startsWith('-')) {
return 'user';
} else if (chatOrUserId.length >= CHANNEL_ID_MIN_LENGTH) {
return 'channel';
} else {
return 'chat';
}
}
// Workaround for old-fashioned IDs stored locally
export function getEntityTypeByDeprecatedId(chatOrUserId: number) {
if (chatOrUserId > 0) {
return 'user';
} else if (chatOrUserId <= -1000000000) {
@ -28,81 +45,78 @@ export function getEntityTypeById(chatOrUserId: number) {
}
}
export function buildPeer(chatOrUserId: number): GramJs.TypePeer {
if (chatOrUserId > 0) {
export function buildPeer(chatOrUserId: string): GramJs.TypePeer {
const type = getEntityTypeById(chatOrUserId);
if (type === 'user') {
return new GramJs.PeerUser({
userId: chatOrUserId,
userId: buildMtpPeerId(chatOrUserId, 'user'),
});
} else if (chatOrUserId <= -1000000000) {
} else if (type === 'channel') {
return new GramJs.PeerChannel({
channelId: -chatOrUserId,
channelId: buildMtpPeerId(chatOrUserId, 'channel'),
});
} else {
return new GramJs.PeerChat({
chatId: -chatOrUserId,
chatId: buildMtpPeerId(chatOrUserId, 'chat'),
});
}
}
export function buildInputPeer(chatOrUserId: number, accessHash?: string): GramJs.TypeInputPeer {
if (chatOrUserId > 0 || chatOrUserId <= -1000000000) {
return chatOrUserId > 0
? new GramJs.InputPeerUser({
userId: chatOrUserId,
accessHash: BigInt(accessHash!),
})
: new GramJs.InputPeerChannel({
channelId: -chatOrUserId,
accessHash: BigInt(accessHash!),
});
export function buildInputPeer(chatOrUserId: string, accessHash?: string): GramJs.TypeInputPeer {
const type = getEntityTypeById(chatOrUserId);
if (type === 'user') {
return new GramJs.InputPeerUser({
userId: buildMtpPeerId(chatOrUserId, 'user'),
accessHash: BigInt(accessHash!),
});
} else if (type === 'channel') {
return new GramJs.InputPeerChannel({
channelId: buildMtpPeerId(chatOrUserId, 'channel'),
accessHash: BigInt(accessHash!),
});
} else {
return new GramJs.InputPeerChat({
chatId: -chatOrUserId,
chatId: buildMtpPeerId(chatOrUserId, 'chat'),
});
}
}
export function buildInputPeerFromLocalDb(chatOrUserId: number): GramJs.TypeInputPeer | undefined {
if (chatOrUserId > 0) {
const { accessHash } = localDb.users[chatOrUserId] || {};
export function buildInputPeerFromLocalDb(chatOrUserId: string): GramJs.TypeInputPeer | undefined {
const type = getEntityTypeById(chatOrUserId);
let accessHash: BigInt.BigInteger | undefined;
return accessHash
? new GramJs.InputPeerUser({
userId: chatOrUserId,
accessHash,
})
: undefined;
if (type === 'user') {
accessHash = localDb.users[chatOrUserId]?.accessHash;
if (!accessHash) {
return undefined;
}
} else if (type === 'channel') {
accessHash = (localDb.chats[chatOrUserId] as GramJs.Channel)?.accessHash;
if (!accessHash) {
return undefined;
}
}
if (chatOrUserId <= -1000000000) {
const { accessHash } = (localDb.chats[-chatOrUserId] as GramJs.Channel) || {};
return accessHash
? new GramJs.InputPeerChannel({
channelId: -chatOrUserId,
accessHash,
})
: undefined;
}
return new GramJs.InputPeerChat({
chatId: -chatOrUserId,
});
return buildInputPeer(chatOrUserId, String(accessHash));
}
export function buildInputEntity(chatOrUserId: number, accessHash?: string) {
if (chatOrUserId > 0) {
export function buildInputEntity(chatOrUserId: string, accessHash?: string) {
const type = getEntityTypeById(chatOrUserId);
if (type === 'user') {
return new GramJs.InputUser({
userId: chatOrUserId,
userId: buildMtpPeerId(chatOrUserId, 'user'),
accessHash: BigInt(accessHash!),
});
} else if (chatOrUserId <= -1000000000) {
} else if (type === 'channel') {
return new GramJs.InputChannel({
channelId: -chatOrUserId,
channelId: buildMtpPeerId(chatOrUserId, 'channel'),
accessHash: BigInt(accessHash!),
});
} else {
return -chatOrUserId;
return buildMtpPeerId(chatOrUserId, 'chat');
}
}
@ -225,7 +239,7 @@ export function generateRandomBigInt() {
export function buildMessageFromUpdate(
id: number,
chatId: number,
chatId: string,
update: GramJs.UpdateShortSentMessage | GramJs.UpdateServiceNotification,
) {
// This is not a proper message, but we only need these fields for downloading media through `localDb`.
@ -269,24 +283,13 @@ export function buildMtpMessageEntity(entity: ApiMessageEntity): GramJs.TypeMess
return new GramJs.InputMessageEntityMentionName({
offset,
length,
userId: new GramJs.InputUser({ userId: userId!, accessHash: user!.accessHash! }),
userId: new GramJs.InputUser({ userId: BigInt(userId!), accessHash: user!.accessHash! }),
});
default:
return new GramJs.MessageEntityUnknown({ offset, length });
}
}
// TODO: This formula is taken from API docs, but doesn't seem to calculate hash correctly
export function calculateResultHash(ids: number[]) {
let hash = 0;
ids.forEach((id) => {
// eslint-disable-next-line no-bitwise
hash = (((hash * 0x4F25) & 0x7FFFFFFF) + id) & 0x7FFFFFFF;
});
return hash;
}
export function isMessageWithMedia(message: GramJs.Message | GramJs.UpdateServiceNotification) {
const { media } = message;
if (!media) {
@ -412,3 +415,12 @@ export function buildInputReportReason(reason: ApiReportReason) {
return undefined;
}
function buildMtpPeerId(id: string, type: 'user' | 'chat' | 'channel') {
// Workaround for old-fashioned IDs stored locally
if (typeof id === 'number') {
return BigInt(Math.abs(id));
}
return type === 'user' ? BigInt(id) : BigInt(id.slice(1));
}

View File

@ -1,6 +1,6 @@
import { Api as GramJs } from '../../lib/gramjs';
import localDb from './localDb';
import { getApiChatIdFromMtpPeer } from './apiBuilders/chats';
import { getApiChatIdFromMtpPeer } from './apiBuilders/peers';
export function resolveMessageApiChatId(mtpMessage: GramJs.TypeMessage) {
if (!(mtpMessage instanceof GramJs.Message || mtpMessage instanceof GramJs.MessageService)) {

View File

@ -4,8 +4,8 @@ import { ApiMessage } from '../types';
interface LocalDb {
localMessages: Record<string, ApiMessage>;
// Used for loading avatars and media through in-memory Gram JS instances.
chats: Record<number, GramJs.Chat | GramJs.Channel>;
users: Record<number, GramJs.User>;
chats: Record<string, GramJs.Chat | GramJs.Channel>;
users: Record<string, GramJs.User>;
messages: Record<string, GramJs.Message | GramJs.MessageService>;
documents: Record<string, GramJs.Document>;
stickerSets: Record<string, GramJs.StickerSet>;

View File

@ -5,10 +5,11 @@ import { ApiChat, ApiUser } from '../../types';
import localDb from '../localDb';
import { invokeRequest } from './client';
import { buildInputPeer, calculateResultHash, generateRandomBigInt } from '../gramjsBuilders';
import { buildInputPeer, generateRandomBigInt } from '../gramjsBuilders';
import { buildApiUser } from '../apiBuilders/users';
import { buildApiBotInlineMediaResult, buildApiBotInlineResult, buildBotSwitchPm } from '../apiBuilders/bots';
import { buildApiChatFromPreview } from '../apiBuilders/chats';
import { buildApiPeerId } from '../apiBuilders/peers';
export function init() {
}
@ -17,7 +18,7 @@ export function answerCallbackButton(
{
chatId, accessHash, messageId, data,
}: {
chatId: number; accessHash?: string; messageId: number; data: string;
chatId: string; accessHash?: string; messageId: number; data: string;
},
) {
return invokeRequest(new GramJs.messages.GetBotCallbackAnswer({
@ -27,9 +28,8 @@ export function answerCallbackButton(
}));
}
export async function fetchTopInlineBots({ hash = 0 }: { hash?: number }) {
export async function fetchTopInlineBots() {
const topPeers = await invokeRequest(new GramJs.contacts.GetTopPeers({
hash,
botsInline: true,
}));
@ -41,7 +41,6 @@ export async function fetchTopInlineBots({ hash = 0 }: { hash?: number }) {
const ids = users.map(({ id }) => id);
return {
hash: calculateResultHash(ids),
ids,
users,
};
@ -160,7 +159,7 @@ function getInlineBotResultsNextOffset(username: string, nextOffset?: string) {
}
function addUserToLocalDb(user: GramJs.User) {
localDb.users[user.id] = user;
localDb.users[buildApiPeerId(user.id, 'user')] = user;
}
function addDocumentToLocalDb(document: GramJs.Document) {

View File

@ -1,3 +1,4 @@
import BigInt from 'big-integer';
import { Api as GramJs } from '../../../lib/gramjs';
import {
OnApiUpdate,
@ -21,7 +22,6 @@ import {
getPeerKey,
buildChatMembers,
buildApiChatFromPreview,
getApiChatIdFromMtpPeer,
buildApiChatFolder,
buildApiChatFolderFromSuggested,
buildApiChatBotCommands,
@ -40,6 +40,7 @@ import {
buildChatAdminRights,
} from '../gramjsBuilders';
import { addMessageToLocalDb } from '../helpers';
import { buildApiPeerId, getApiChatIdFromMtpPeer } from '../apiBuilders/peers';
const MAX_INT_32 = 2 ** 31 - 1;
let onUpdate: OnApiUpdate;
@ -96,12 +97,12 @@ export async function fetchChats({
...preparePeers(result),
};
const chats: ApiChat[] = [];
const draftsById: Record<number, ApiFormattedText> = {};
const replyingToById: Record<number, number> = {};
const draftsById: Record<string, ApiFormattedText> = {};
const replyingToById: Record<string, number> = {};
const dialogs = (resultPinned ? resultPinned.dialogs : []).concat(result.dialogs);
const orderedPinnedIds: number[] = [];
const orderedPinnedIds: string[] = [];
dialogs.forEach((dialog) => {
if (
@ -325,12 +326,12 @@ export function clearDraft(chat: ApiChat) {
}));
}
async function getFullChatInfo(chatId: number): Promise<{
async function getFullChatInfo(chatId: string): Promise<{
fullInfo: ApiChatFullInfo;
users?: ApiUser[];
} | undefined> {
const result = await invokeRequest(new GramJs.messages.GetFullChat({
chatId: buildInputEntity(chatId) as number,
chatId: buildInputEntity(chatId) as BigInt.BigInteger,
}));
if (!result || !(result.fullChat instanceof GramJs.ChatFull)) {
@ -366,7 +367,7 @@ async function getFullChatInfo(chatId: number): Promise<{
}
async function getFullChannelInfo(
id: number,
id: string,
accessHash: string,
adminRights?: ApiChatAdminRights,
) {
@ -430,7 +431,7 @@ async function getFullChannelInfo(
nextSendDate: slowmodeNextSendDate,
} : undefined,
migratedFrom: migratedFromChatId ? {
chatId: getApiChatIdFromMtpPeer({ chatId: migratedFromChatId } as GramJs.TypePeer),
chatId: buildApiPeerId(migratedFromChatId, 'chat'),
maxMessageId: migratedFromMaxId,
} : undefined,
canViewMembers: canViewParticipants,
@ -438,8 +439,8 @@ async function getFullChannelInfo(
members,
kickedMembers,
adminMembers,
groupCallId: call ? call.id.toString() : undefined,
linkedChatId: linkedChatId ? getApiChatIdFromMtpPeer({ chatId: linkedChatId } as GramJs.TypePeer) : undefined,
groupCallId: call ? String(call.id) : undefined,
linkedChatId: linkedChatId ? buildApiPeerId(linkedChatId, 'chat') : undefined,
botCommands,
},
users: [...(users || []), ...(bannedUsers || []), ...(adminUsers || [])],
@ -515,7 +516,7 @@ export async function createChannel({
export function joinChannel({
channelId, accessHash,
}: {
channelId: number; accessHash: string;
channelId: string; accessHash: string;
}) {
return invokeRequest(new GramJs.channels.JoinChannel({
channel: buildInputEntity(channelId, accessHash) as GramJs.InputChannel,
@ -529,7 +530,7 @@ export function deleteChatUser({
}) {
if (chat.type !== 'chatTypeBasicGroup') return undefined;
return invokeRequest(new GramJs.messages.DeleteChatUser({
chatId: buildInputEntity(chat.id, chat.accessHash) as number,
chatId: buildInputEntity(chat.id, chat.accessHash) as BigInt.BigInteger,
userId: buildInputEntity(user.id, user.accessHash) as GramJs.InputUser,
}), true);
}
@ -537,17 +538,17 @@ export function deleteChatUser({
export function deleteChat({
chatId,
}: {
chatId: number;
chatId: string;
}) {
return invokeRequest(new GramJs.messages.DeleteChat({
chatId: buildInputEntity(chatId) as number,
chatId: buildInputEntity(chatId) as BigInt.BigInteger,
}), true);
}
export function leaveChannel({
channelId, accessHash,
}: {
channelId: number; accessHash: string;
channelId: string; accessHash: string;
}) {
return invokeRequest(new GramJs.channels.LeaveChannel({
channel: buildInputEntity(channelId, accessHash) as GramJs.InputChannel,
@ -557,7 +558,7 @@ export function leaveChannel({
export function deleteChannel({
channelId, accessHash,
}: {
channelId: number; accessHash: string;
channelId: string; accessHash: string;
}) {
return invokeRequest(new GramJs.channels.DeleteChannel({
channel: buildInputEntity(channelId, accessHash) as GramJs.InputChannel,
@ -600,7 +601,7 @@ export async function createGroupChat({
export async function editChatPhoto({
chatId, accessHash, photo,
}: {
chatId: number; accessHash?: string; photo: File;
chatId: string; accessHash?: string; photo: File;
}) {
const uploadedPhoto = await uploadFile(photo);
const inputEntity = buildInputEntity(chatId, accessHash);
@ -614,7 +615,7 @@ export async function editChatPhoto({
}),
})
: new GramJs.messages.EditChatPhoto({
chatId: inputEntity as number,
chatId: inputEntity as BigInt.BigInteger,
photo: new GramJs.InputChatUploadedPhoto({
file: uploadedPhoto,
}),
@ -837,7 +838,7 @@ export async function updateChatTitle(chat: ApiChat, title: string) {
channel: inputEntity as GramJs.InputChannel,
title,
}) : new GramJs.messages.EditChatTitle({
chatId: inputEntity as number,
chatId: inputEntity as BigInt.BigInteger,
title,
}),
true,
@ -881,7 +882,7 @@ type ChannelMembersFilter =
| 'recent';
export async function fetchMembers(
chatId: number,
chatId: string,
accessHash: string,
memberFilter: ChannelMembersFilter = 'recent',
offset?: number,
@ -946,7 +947,7 @@ export function setDiscussionGroup({
export async function migrateChat(chat: ApiChat) {
const result = await invokeRequest(
new GramJs.messages.MigrateChat({ chatId: buildInputEntity(chat.id) as number }), true,
new GramJs.messages.MigrateChat({ chatId: buildInputEntity(chat.id) as BigInt.BigInteger }), true,
);
// `migrateChat` can return a lot of different update types according to docs,
@ -1014,7 +1015,7 @@ export function addChatMembers(chat: ApiChat, users: ApiUser[]) {
return Promise.all(users.map((user) => {
return invokeRequest(new GramJs.messages.AddChatUser({
chatId: buildInputEntity(chat.id) as number,
chatId: buildInputEntity(chat.id) as BigInt.BigInteger,
userId: buildInputEntity(user.id, user.accessHash) as GramJs.InputUser,
}), true);
}));
@ -1043,7 +1044,7 @@ export function deleteChatMember(chat: ApiChat, user: ApiUser) {
});
} else {
return invokeRequest(new GramJs.messages.DeleteChatUser({
chatId: buildInputEntity(chat.id) as number,
chatId: buildInputEntity(chat.id) as BigInt.BigInteger,
userId: buildInputEntity(user.id, user.accessHash) as GramJs.InputUser,
}), true);
}
@ -1074,7 +1075,7 @@ function updateLocalDb(result: (
if ('users' in result) {
result.users.forEach((user) => {
if (user instanceof GramJs.User) {
localDb.users[user.id] = user;
localDb.users[buildApiPeerId(user.id, 'user')] = user;
}
});
}
@ -1082,7 +1083,7 @@ function updateLocalDb(result: (
if ('chats' in result) {
result.chats.forEach((chat) => {
if (chat instanceof GramJs.Chat || chat instanceof GramJs.Channel) {
localDb.chats[chat.id] = chat;
localDb.chats[buildApiPeerId(chat.id, chat instanceof GramJs.Chat ? 'chat' : 'channel')] = chat;
}
});
}
@ -1102,7 +1103,5 @@ export async function importChatInvite({ hash }: { hash: string }) {
return undefined;
}
const chat = buildApiChatFromPreview(updates.chats[0]);
return chat;
return buildApiChatFromPreview(updates.chats[0]);
}

View File

@ -24,6 +24,7 @@ import { setMessageBuilderCurrentUserId } from '../apiBuilders/messages';
import downloadMediaWithClient from './media';
import { buildApiUserFromFull } from '../apiBuilders/users';
import localDb from '../localDb';
import { buildApiPeerId } from '../apiBuilders/peers';
const DEFAULT_USER_AGENT = 'Unknown UserAgent';
const APP_CODE_NAME = 'Z';
@ -254,7 +255,7 @@ export async function fetchCurrentUser() {
return;
}
localDb.users[userFull.user.id] = userFull.user;
localDb.users[buildApiPeerId(userFull.user.id, 'user')] = userFull.user;
const currentUser = buildApiUserFromFull(userFull);
setMessageBuilderCurrentUserId(currentUser.id);

View File

@ -91,16 +91,16 @@ async function download(
}
let entityType: EntityType;
let entityId: string | number = mediaMatch[2];
const entityId: string | number = mediaMatch[2];
const sizeType = mediaMatch[3] ? mediaMatch[3].replace('?size=', '') : undefined;
let entity: (
GramJs.User | GramJs.Chat | GramJs.Channel | GramJs.Photo |
GramJs.Message | GramJs.Document | GramJs.StickerSet | GramJs.TypeWebDocument | undefined
GramJs.Message | GramJs.MessageService |
GramJs.Document | GramJs.StickerSet | GramJs.TypeWebDocument | undefined
);
if (mediaMatch[1] === 'avatar' || mediaMatch[1] === 'profile') {
entityType = getEntityTypeById(Number(entityId));
entityId = Math.abs(Number(entityId));
entityType = getEntityTypeById(entityId);
} else {
entityType = mediaMatch[1] as 'msg' | 'sticker' | 'wallpaper' | 'gif' | 'stickerSet' | 'photo' | 'webDocument';
}
@ -108,27 +108,27 @@ async function download(
switch (entityType) {
case 'channel':
case 'chat':
entity = localDb.chats[entityId as number];
entity = localDb.chats[entityId];
break;
case 'user':
entity = localDb.users[entityId as number];
entity = localDb.users[entityId];
break;
case 'msg':
entity = localDb.messages[entityId as string];
entity = localDb.messages[entityId];
break;
case 'sticker':
case 'gif':
case 'wallpaper':
entity = localDb.documents[entityId as string];
entity = localDb.documents[entityId];
break;
case 'photo':
entity = localDb.photos[entityId as string];
entity = localDb.photos[entityId];
break;
case 'stickerSet':
entity = localDb.stickerSets[entityId as string];
entity = localDb.stickerSets[entityId];
break;
case 'webDocument':
entity = localDb.webDocuments[entityId as string];
entity = localDb.webDocuments[entityId];
break;
}

View File

@ -43,7 +43,6 @@ import {
buildMtpMessageEntity,
isMessageWithMedia,
isServiceMessageWithMedia,
calculateResultHash,
buildInputReportReason,
} from '../gramjsBuilders';
import localDb from '../localDb';
@ -52,6 +51,7 @@ import { fetchFile } from '../../../util/files';
import { addMessageToLocalDb, resolveMessageApiChatId } from '../helpers';
import { interpolateArray } from '../../../util/waveform';
import { requestChatUpdate } from './chats';
import { buildApiPeerId } from '../apiBuilders/peers';
const FAST_SEND_TIMEOUT = 1000;
const INPUT_WAVEFORM_LENGTH = 63;
@ -238,7 +238,7 @@ export function sendMessage(
}, FAST_SEND_TIMEOUT);
const randomId = generateRandomBigInt();
localDb.localMessages[randomId.toString()] = localMessage;
localDb.localMessages[String(randomId)] = localMessage;
if (groupedId) {
return sendGroupedMedia({
@ -1078,12 +1078,11 @@ export async function findFirstMessageIdAfterDate({
return result.messages[0].id;
}
export async function fetchScheduledHistory({ chat, hash = 0 }: { chat: ApiChat; hash?: number }) {
export async function fetchScheduledHistory({ chat }: { chat: ApiChat }) {
const { id, accessHash } = chat;
const result = await invokeRequest(new GramJs.messages.GetScheduledHistory({
peer: buildInputPeer(id, accessHash),
hash,
}));
if (
@ -1100,7 +1099,6 @@ export async function fetchScheduledHistory({ chat, hash = 0 }: { chat: ApiChat;
return {
messages,
hash: calculateResultHash(messages.map((message) => message.id)),
};
}
@ -1119,13 +1117,13 @@ function updateLocalDb(result: (
)) {
result.users.forEach((user) => {
if (user instanceof GramJs.User) {
localDb.users[user.id] = user;
localDb.users[buildApiPeerId(user.id, 'user')] = user;
}
});
result.chats.forEach((chat) => {
if (chat instanceof GramJs.Chat || chat instanceof GramJs.Channel) {
localDb.chats[chat.id] = chat;
localDb.chats[buildApiPeerId(chat.id, chat instanceof GramJs.Chat ? 'chat' : 'channel')] = chat;
}
});

View File

@ -4,7 +4,7 @@ import { Api as GramJs } from '../../../lib/gramjs';
import {
ApiChat, ApiLangString, ApiLanguage, ApiNotifyException, ApiUser, ApiWallpaper,
} from '../../types';
import { ApiPrivacyKey, IInputPrivacyRules } from '../../../types';
import { ApiPrivacyKey, InputPrivacyRules } from '../../../types';
import { BLOCKED_LIST_LIMIT, DEFAULT_LANG_PACK, LANG_PACKS } from '../../../config';
import {
@ -12,13 +12,14 @@ import {
} from '../apiBuilders/misc';
import { buildApiUser } from '../apiBuilders/users';
import { buildApiChatFromPreview, getApiChatIdFromMtpPeer } from '../apiBuilders/chats';
import { buildInputPrivacyKey, buildInputPeer } from '../gramjsBuilders';
import { buildApiChatFromPreview } from '../apiBuilders/chats';
import { buildInputPrivacyKey, buildInputPeer, buildInputEntity } from '../gramjsBuilders';
import { invokeRequest, uploadFile, getClient } from './client';
import { omitVirtualClassFields } from '../apiBuilders/helpers';
import { buildCollectionByKey } from '../../../util/iteratees';
import localDb from '../localDb';
import { getServerTime } from '../../../util/serverTime';
import { buildApiPeerId, getApiChatIdFromMtpPeer } from '../apiBuilders/peers';
const MAX_INT_32 = 2 ** 31 - 1;
const BETA_LANG_CODES = ['ar', 'fa', 'id', 'ko', 'uz'];
@ -61,8 +62,8 @@ export async function uploadProfilePhoto(file: File) {
}));
}
export async function fetchWallpapers(hash: number) {
const result = await invokeRequest(new GramJs.account.GetWallPapers({ hash }));
export async function fetchWallpapers() {
const result = await invokeRequest(new GramJs.account.GetWallPapers({ hash: BigInt('0') }));
if (!result || result instanceof GramJs.account.WallPapersNotModified) {
return undefined;
@ -84,7 +85,6 @@ export async function fetchWallpapers(hash: number) {
});
return {
hash: result.hash,
wallpapers: filteredWallpapers.map(buildApiWallpaper).filter<ApiWallpaper>(Boolean as any),
};
}
@ -130,13 +130,13 @@ export async function fetchBlockedContacts() {
};
}
export function blockContact(chatOrUserId: number, accessHash?: string) {
export function blockContact(chatOrUserId: string, accessHash?: string) {
return invokeRequest(new GramJs.contacts.Block({
id: buildInputPeer(chatOrUserId, accessHash),
}));
}
export function unblockContact(chatOrUserId: number, accessHash?: string) {
export function unblockContact(chatOrUserId: string, accessHash?: string) {
return invokeRequest(new GramJs.contacts.Unblock({
id: buildInputPeer(chatOrUserId, accessHash),
}));
@ -353,29 +353,29 @@ export function unregisterDevice(token: string) {
}
export async function setPrivacySettings(
privacyKey: ApiPrivacyKey, rules: IInputPrivacyRules,
privacyKey: ApiPrivacyKey, rules: InputPrivacyRules,
) {
const key = buildInputPrivacyKey(privacyKey);
const privacyRules: GramJs.TypeInputPrivacyRule[] = [];
if (rules.allowedUsers) {
privacyRules.push(new GramJs.InputPrivacyValueAllowUsers({
users: rules.allowedUsers.map(({ id, accessHash }) => buildInputPeer(id, accessHash)),
users: rules.allowedUsers.map(({ id, accessHash }) => buildInputEntity(id, accessHash) as GramJs.InputUser),
}));
}
if (rules.allowedChats) {
privacyRules.push(new GramJs.InputPrivacyValueAllowChatParticipants({
chats: rules.allowedChats.map(({ id }) => -id),
chats: rules.allowedChats.map(({ id }) => buildInputEntity(id) as BigInt.BigInteger),
}));
}
if (rules.blockedUsers) {
privacyRules.push(new GramJs.InputPrivacyValueDisallowUsers({
users: rules.blockedUsers.map(({ id, accessHash }) => buildInputPeer(id, accessHash)),
users: rules.blockedUsers.map(({ id, accessHash }) => buildInputEntity(id, accessHash) as GramJs.InputUser),
}));
}
if (rules.blockedChats) {
privacyRules.push(new GramJs.InputPrivacyValueDisallowChatParticipants({
chats: rules.blockedChats.map(({ id }) => -id),
chats: rules.blockedChats.map(({ id }) => buildInputEntity(id) as BigInt.BigInteger),
}));
}
switch (rules.visibility) {
@ -437,13 +437,13 @@ function updateLocalDb(
) {
result.users.forEach((user) => {
if (user instanceof GramJs.User) {
localDb.users[user.id] = user;
localDb.users[buildApiPeerId(user.id, 'user')] = user;
}
});
result.chats.forEach((chat) => {
if (chat instanceof GramJs.Chat || chat instanceof GramJs.Channel) {
localDb.chats[chat.id] = chat;
localDb.chats[buildApiPeerId(chat.id, chat instanceof GramJs.Chat ? 'chat' : 'channel')] = chat;
}
});
}

View File

@ -1,3 +1,4 @@
import BigInt from 'big-integer';
import { Api as GramJs } from '../../../lib/gramjs';
import { ApiSticker, ApiVideo, OnApiUpdate } from '../../types';
@ -15,8 +16,8 @@ export function init(_onUpdate: OnApiUpdate) {
onUpdate = _onUpdate;
}
export async function fetchStickerSets({ hash }: { hash: number }) {
const allStickers = await invokeRequest(new GramJs.messages.GetAllStickers({ hash }));
export async function fetchStickerSets({ hash = '0' }: { hash?: string }) {
const allStickers = await invokeRequest(new GramJs.messages.GetAllStickers({ hash: BigInt(hash) }));
if (!allStickers || allStickers instanceof GramJs.messages.AllStickersNotModified) {
return undefined;
@ -29,46 +30,46 @@ export async function fetchStickerSets({ hash }: { hash: number }) {
});
return {
hash: allStickers.hash,
hash: String(allStickers.hash),
sets: allStickers.sets.map(buildStickerSet),
};
}
export async function fetchRecentStickers({ hash }: { hash: number }) {
const result = await invokeRequest(new GramJs.messages.GetRecentStickers({ hash }));
export async function fetchRecentStickers({ hash = '0' }: { hash?: string }) {
const result = await invokeRequest(new GramJs.messages.GetRecentStickers({ hash: BigInt(hash) }));
if (!result || result instanceof GramJs.messages.RecentStickersNotModified) {
return undefined;
}
return {
hash: result.hash,
hash: String(result.hash),
stickers: processStickerResult(result.stickers.slice(0, RECENT_STICKERS_LIMIT)),
};
}
export async function fetchFavoriteStickers({ hash }: { hash: number }) {
const result = await invokeRequest(new GramJs.messages.GetFavedStickers({ hash }));
export async function fetchFavoriteStickers({ hash = '0' }: { hash?: string }) {
const result = await invokeRequest(new GramJs.messages.GetFavedStickers({ hash: BigInt(hash) }));
if (!result || result instanceof GramJs.messages.FavedStickersNotModified) {
return undefined;
}
return {
hash: result.hash,
hash: String(result.hash),
stickers: processStickerResult(result.stickers),
};
}
export async function fetchFeaturedStickers({ hash }: { hash: number }) {
const result = await invokeRequest(new GramJs.messages.GetFeaturedStickers({ hash }));
export async function fetchFeaturedStickers({ hash = '0' }: { hash?: string }) {
const result = await invokeRequest(new GramJs.messages.GetFeaturedStickers({ hash: BigInt(hash) }));
if (!result || result instanceof GramJs.messages.FeaturedStickersNotModified) {
return undefined;
}
return {
hash: result.hash,
hash: String(result.hash),
sets: result.sets.map(buildStickerSetCovered),
};
}
@ -93,8 +94,10 @@ export async function faveSticker({
}
}
export async function fetchStickers({ stickerSetShortName, stickerSetId, accessHash }:
{ stickerSetShortName?: string; stickerSetId?: string; accessHash: string }) {
export async function fetchStickers(
{ stickerSetShortName, stickerSetId, accessHash }:
{ stickerSetShortName?: string; stickerSetId?: string; accessHash: string },
) {
const result = await invokeRequest(new GramJs.messages.GetStickerSet({
stickerset: stickerSetId
? buildInputStickerSet(stickerSetId, accessHash)
@ -127,10 +130,10 @@ export async function fetchAnimatedEmojis() {
};
}
export async function searchStickers({ query, hash }: { query: string; hash: number }) {
export async function searchStickers({ query, hash = '0' }: { query: string; hash?: string }) {
const result = await invokeRequest(new GramJs.messages.SearchStickerSets({
q: query,
hash,
hash: BigInt(hash),
}));
if (!result || result instanceof GramJs.messages.FoundStickerSetsNotModified) {
@ -138,20 +141,20 @@ export async function searchStickers({ query, hash }: { query: string; hash: num
}
return {
hash: result.hash,
hash: String(result.hash),
sets: result.sets.map(buildStickerSetCovered),
};
}
export async function fetchSavedGifs({ hash }: { hash: number }) {
const result = await invokeRequest(new GramJs.messages.GetSavedGifs({ hash }));
export async function fetchSavedGifs({ hash = '0' }: { hash?: string }) {
const result = await invokeRequest(new GramJs.messages.GetSavedGifs({ hash: BigInt(hash) }));
if (!result || result instanceof GramJs.messages.SavedGifsNotModified) {
return undefined;
}
return {
hash: result.hash,
hash: String(result.hash),
gifs: processGifResult(result.gifs),
};
}
@ -233,11 +236,11 @@ export async function searchGifs({ query, offset = '' }: { query: string; offset
}
export async function fetchStickersForEmoji({
emoji, hash = 0,
}: { emoji: string; hash?: number }) {
emoji, hash = '0',
}: { emoji: string; hash?: string }) {
const result = await invokeRequest(new GramJs.messages.GetStickers({
emoticon: emoji,
hash,
hash: BigInt(hash),
}));
if (!result || result instanceof GramJs.messages.StickersNotModified) {
@ -246,7 +249,7 @@ export async function fetchStickersForEmoji({
return {
stickers: processStickerResult(result.stickers),
hash: result.hash,
hash: String(result.hash),
};
}

View File

@ -10,7 +10,6 @@ import { invokeRequest } from './client';
import { searchMessagesLocal } from './messages';
import {
buildInputEntity,
calculateResultHash,
buildInputPeer,
buildInputContact,
} from '../gramjsBuilders';
@ -20,6 +19,7 @@ import { buildApiPhoto } from '../apiBuilders/common';
import localDb from '../localDb';
import { addPhotoToLocalDb } from '../helpers';
import { buildApiCountryList } from '../apiBuilders/misc';
import { buildApiPeerId } from '../apiBuilders/peers';
let onUpdate: OnApiUpdate;
@ -31,7 +31,7 @@ export async function fetchFullUser({
id,
accessHash,
}: {
id: number;
id: string;
accessHash?: string;
}) {
const input = buildInputEntity(id, accessHash);
@ -73,9 +73,8 @@ export async function fetchCountryList({ langCode = 'en' }: { langCode?: LangCod
return buildApiCountryList(countryList.countries);
}
export async function fetchTopUsers({ hash = 0 }: { hash?: number }) {
export async function fetchTopUsers() {
const topPeers = await invokeRequest(new GramJs.contacts.GetTopPeers({
hash,
correspondents: true,
}));
if (!(topPeers instanceof GramJs.contacts.TopPeers)) {
@ -86,29 +85,24 @@ export async function fetchTopUsers({ hash = 0 }: { hash?: number }) {
const ids = users.map(({ id }) => id);
return {
hash: calculateResultHash(ids),
ids,
users,
};
}
export async function fetchContactList({ hash = 0 }: { hash?: number }) {
const result = await invokeRequest(new GramJs.contacts.GetContacts({ hash }));
export async function fetchContactList() {
const result = await invokeRequest(new GramJs.contacts.GetContacts({ hash: BigInt('0') }));
if (!result || result instanceof GramJs.contacts.ContactsNotModified) {
return undefined;
}
result.users.forEach((user) => {
if (user instanceof GramJs.User) {
localDb.users[user.id] = user;
localDb.users[buildApiPeerId(user.id, 'user')] = user;
}
});
return {
hash: calculateResultHash([
result.savedCount,
...result.contacts.map(({ userId }) => userId),
]),
users: result.users.map(buildApiUser).filter<ApiUser>(Boolean as any),
chats: result.users.map((user) => buildApiChatFromPreview(user)).filter<ApiChat>(Boolean as any),
};
@ -124,7 +118,7 @@ export async function fetchUsers({ users }: { users: ApiUser[] }) {
result.forEach((user) => {
if (user instanceof GramJs.User) {
localDb.users[user.id] = user;
localDb.users[buildApiPeerId(user.id, 'user')] = user;
}
});
@ -156,7 +150,7 @@ export function addContact({
firstName = '',
lastName = '',
}: {
id: number;
id: string;
accessHash?: string;
phoneNumber?: string;
firstName?: string;
@ -174,7 +168,7 @@ export async function deleteUser({
id,
accessHash,
}: {
id: number;
id: string;
accessHash?: string;
}) {
const input = buildInputEntity(id, accessHash);

View File

@ -14,14 +14,12 @@ import {
buildMessageDraft,
} from './apiBuilders/messages';
import {
getApiChatIdFromMtpPeer,
buildChatMember,
buildChatMembers,
buildChatTypingStatus,
buildAvatarHash,
buildApiChatFromPreview,
buildApiChatFolder,
getApiChatIdFromInputMtpPeer,
} from './apiBuilders/chats';
import { buildApiUser, buildApiUserStatus } from './apiBuilders/users';
import {
@ -35,6 +33,7 @@ import { DEBUG } from '../../config';
import { addMessageToLocalDb, addPhotoToLocalDb, resolveMessageApiChatId } from './helpers';
import { buildApiNotifyException, buildPrivacyKey, buildPrivacyRules } from './apiBuilders/misc';
import { buildApiPhoto } from './apiBuilders/common';
import { buildApiPeerId, getApiChatIdFromMtpPeer } from './apiBuilders/peers';
type Update = (
(GramJs.TypeUpdate | GramJs.TypeUpdates) & { _entities?: (GramJs.TypeUser | GramJs.TypeChat)[] }
@ -178,7 +177,7 @@ export function updater(update: Update, originRequest?: GramJs.AnyRequest) {
const photo = buildChatPhotoForLocalDb(action.photo);
const avatarHash = buildAvatarHash(photo);
const localDbChatId = Math.abs(resolveMessageApiChatId(update.message)!);
const localDbChatId = resolveMessageApiChatId(update.message)!;
if (localDb.chats[localDbChatId]) {
localDb.chats[localDbChatId].photo = photo;
}
@ -195,7 +194,7 @@ export function updater(update: Update, originRequest?: GramJs.AnyRequest) {
});
}
} else if (action instanceof GramJs.MessageActionChatDeletePhoto) {
const localDbChatId = Math.abs(resolveMessageApiChatId(update.message)!);
const localDbChatId = resolveMessageApiChatId(update.message)!;
if (localDb.chats[localDbChatId]) {
localDb.chats[localDbChatId].photo = new GramJs.ChatPhotoEmpty();
}
@ -270,10 +269,10 @@ export function updater(update: Update, originRequest?: GramJs.AnyRequest) {
onUpdate({
'@type': 'deleteScheduledMessages',
ids: update.messages,
chatId: getApiChatIdFromInputMtpPeer(update.peer),
chatId: getApiChatIdFromMtpPeer(update.peer),
});
} else if (update instanceof GramJs.UpdateDeleteChannelMessages) {
const chatId = getApiChatIdFromMtpPeer({ channelId: update.channelId } as GramJs.PeerChannel);
const chatId = buildApiPeerId(update.channelId, 'channel');
const ids = update.messages;
const existingIds = ids.filter((id) => localDb.messages[`${chatId}-${id}`]);
const missingIds = ids.filter((id) => !localDb.messages[`${chatId}-${id}`]);
@ -339,7 +338,7 @@ export function updater(update: Update, originRequest?: GramJs.AnyRequest) {
randomId = originRequest.randomId;
}
const localMessage = randomId && localDb.localMessages[randomId.toString()];
const localMessage = randomId && localDb.localMessages[String(randomId)];
if (!localMessage) {
throw new Error('Local message not found');
}
@ -400,7 +399,7 @@ export function updater(update: Update, originRequest?: GramJs.AnyRequest) {
} else if (update instanceof GramJs.UpdateChannelReadMessagesContents) {
onUpdate({
'@type': 'updateChannelMessages',
channelId: update.channelId,
channelId: buildApiPeerId(update.channelId, 'channel'),
ids: update.messages,
messageUpdate: {
hasUnreadMention: false,
@ -414,28 +413,28 @@ export function updater(update: Update, originRequest?: GramJs.AnyRequest) {
onUpdate({
'@type': 'updateMessagePoll',
pollId: pollId.toString(),
pollId: String(pollId),
pollUpdate: apiPoll,
});
} else {
const pollResults = buildPollResults(results);
onUpdate({
'@type': 'updateMessagePoll',
pollId: pollId.toString(),
pollId: String(pollId),
pollUpdate: { results: pollResults },
});
}
} else if (update instanceof GramJs.UpdateMessagePollVote) {
onUpdate({
'@type': 'updateMessagePollVote',
pollId: update.pollId.toString(),
userId: update.userId,
pollId: String(update.pollId),
userId: buildApiPeerId(update.userId, 'user'),
options: update.options.map((option) => String.fromCharCode(...option)),
});
} else if (update instanceof GramJs.UpdateChannelMessageViews) {
onUpdate({
'@type': 'updateMessage',
chatId: getApiChatIdFromMtpPeer({ channelId: update.channelId } as GramJs.PeerChannel),
chatId: buildApiPeerId(update.channelId, 'channel'),
id: update.id,
message: { views: update.views },
});
@ -461,7 +460,7 @@ export function updater(update: Update, originRequest?: GramJs.AnyRequest) {
} else if (update instanceof GramJs.UpdateReadChannelInbox) {
onUpdate({
'@type': 'updateChat',
id: getApiChatIdFromMtpPeer({ channelId: update.channelId } as GramJs.PeerChannel),
id: buildApiPeerId(update.channelId, 'channel'),
chat: {
lastReadInboxMessageId: update.maxId,
unreadCount: update.stillUnreadCount,
@ -470,7 +469,7 @@ export function updater(update: Update, originRequest?: GramJs.AnyRequest) {
} else if (update instanceof GramJs.UpdateReadChannelOutbox) {
onUpdate({
'@type': 'updateChat',
id: getApiChatIdFromMtpPeer({ channelId: update.channelId } as GramJs.PeerChannel),
id: buildApiPeerId(update.channelId, 'channel'),
chat: {
lastReadOutboxMessageId: update.maxId,
},
@ -525,7 +524,7 @@ export function updater(update: Update, originRequest?: GramJs.AnyRequest) {
onUpdate({
'@type': 'updateChatMembers',
id: getApiChatIdFromMtpPeer({ chatId: update.participants.chatId } as GramJs.TypePeer),
id: buildApiPeerId(update.participants.chatId, 'chat'),
replacedMembers,
});
} else if (update instanceof GramJs.UpdateChatParticipantAdd) {
@ -535,25 +534,22 @@ export function updater(update: Update, originRequest?: GramJs.AnyRequest) {
onUpdate({
'@type': 'updateChatMembers',
id: getApiChatIdFromMtpPeer({ chatId: update.chatId } as GramJs.PeerChat),
id: buildApiPeerId(update.chatId, 'chat'),
addedMember,
});
} else if (update instanceof GramJs.UpdateChatParticipantDelete) {
const { userId: deletedMemberId } = update;
onUpdate({
'@type': 'updateChatMembers',
id: getApiChatIdFromMtpPeer({ chatId: update.chatId } as GramJs.PeerChat),
deletedMemberId,
id: buildApiPeerId(update.chatId, 'chat'),
deletedMemberId: buildApiPeerId(update.userId, 'user'),
});
} else if (
update instanceof GramJs.UpdatePinnedMessages
|| update instanceof GramJs.UpdatePinnedChannelMessages
) {
const peer = update instanceof GramJs.UpdatePinnedMessages
? update.peer
: { channelId: update.channelId } as GramJs.PeerChannel;
const chatId = getApiChatIdFromMtpPeer(peer);
const chatId = update instanceof GramJs.UpdatePinnedMessages
? getApiChatIdFromMtpPeer(update.peer)
: buildApiPeerId(update.channelId, 'channel');
onUpdate({
'@type': 'updatePinnedIds',
@ -574,8 +570,8 @@ export function updater(update: Update, originRequest?: GramJs.AnyRequest) {
|| update instanceof GramJs.UpdateChatUserTyping
) {
const id = update instanceof GramJs.UpdateUserTyping
? update.userId
: getApiChatIdFromMtpPeer({ chatId: update.chatId } as GramJs.PeerChat);
? buildApiPeerId(update.userId, 'user')
: buildApiPeerId(update.chatId, 'chat');
onUpdate({
'@type': 'updateChatTypingStatus',
@ -583,7 +579,7 @@ export function updater(update: Update, originRequest?: GramJs.AnyRequest) {
typingStatus: buildChatTypingStatus(update, serverTimeOffset),
});
} else if (update instanceof GramJs.UpdateChannelUserTyping) {
const id = getApiChatIdFromMtpPeer({ channelId: update.channelId } as GramJs.PeerChannel);
const id = buildApiPeerId(update.channelId, 'channel');
onUpdate({
'@type': 'updateChatTypingStatus',
@ -612,11 +608,11 @@ export function updater(update: Update, originRequest?: GramJs.AnyRequest) {
onUpdate({
'@type': chat.isNotJoined ? 'updateChatLeave' : 'updateChatJoin',
id: getApiChatIdFromMtpPeer({ channelId: update.channelId } as GramJs.PeerChannel),
id: buildApiPeerId(update.channelId, 'channel'),
});
}
} else if (channel instanceof GramJs.ChannelForbidden) {
const chatId = getApiChatIdFromMtpPeer({ channelId: update.channelId } as GramJs.PeerChannel);
const chatId = buildApiPeerId(update.channelId, 'channel');
onUpdate({
'@type': 'updateChat',
@ -635,7 +631,7 @@ export function updater(update: Update, originRequest?: GramJs.AnyRequest) {
// No corresponding update available at this moment https://core.telegram.org/type/Updates
onUpdate({
'@type': 'resetMessages',
id: getApiChatIdFromMtpPeer({ chatId: update.channelId } as GramJs.PeerChat),
id: buildApiPeerId(update.channelId, 'channel'),
});
}
} else if (
@ -660,35 +656,35 @@ export function updater(update: Update, originRequest?: GramJs.AnyRequest) {
// Users
} else if (update instanceof GramJs.UpdateUserStatus) {
const { userId, status } = update;
onUpdate({
'@type': 'updateUserStatus',
userId,
status: buildApiUserStatus(status),
userId: buildApiPeerId(update.userId, 'user'),
status: buildApiUserStatus(update.status),
});
} else if (update instanceof GramJs.UpdateUserName) {
const updatedUser = localDb.users[update.userId];
const apiUserId = buildApiPeerId(update.userId, 'user');
const updatedUser = localDb.users[apiUserId];
const user = updatedUser?.mutualContact && !updatedUser.self
? pick(update, ['username'])
: pick(update, ['firstName', 'lastName', 'username']);
onUpdate({
'@type': 'updateUser',
id: update.userId,
id: apiUserId,
user,
});
} else if (update instanceof GramJs.UpdateUserPhoto) {
const { userId, photo } = update;
const apiUserId = buildApiPeerId(userId, 'user');
const avatarHash = buildAvatarHash(photo);
if (localDb.users[userId]) {
localDb.users[userId].photo = photo;
if (localDb.users[apiUserId]) {
localDb.users[apiUserId].photo = photo;
}
onUpdate({
'@type': 'updateUser',
id: userId,
id: apiUserId,
user: { avatarHash },
});
} else if (update instanceof GramJs.UpdateUserPhone) {
@ -696,7 +692,7 @@ export function updater(update: Update, originRequest?: GramJs.AnyRequest) {
onUpdate({
'@type': 'updateUser',
id: userId,
id: buildApiPeerId(userId, 'user'),
user: { phoneNumber: phone },
});
} else if (update instanceof GramJs.UpdatePeerSettings) {
@ -712,7 +708,7 @@ export function updater(update: Update, originRequest?: GramJs.AnyRequest) {
.forEach((user) => {
onUpdate({
'@type': 'deleteUser',
id: user.id,
id: buildApiPeerId(user.id, 'user'),
});
});

View File

@ -40,7 +40,7 @@ export interface ApiBotInlineSwitchPm {
}
export interface ApiBotCommand {
botId: number;
botId: string;
command: string;
description: string;
}

View File

@ -8,7 +8,7 @@ type ApiChatType = (
);
export interface ApiChat {
id: number;
id: string;
folderId?: number;
type: ApiChatType;
title?: string;
@ -47,7 +47,7 @@ export interface ApiChat {
defaultBannedRights?: ApiChatBannedRights;
migratedTo?: {
chatId: number;
chatId: string;
accessHash?: string;
};
@ -58,26 +58,11 @@ export interface ApiChat {
}
export interface ApiTypingStatus {
userId?: number;
userId?: string;
action: string;
timestamp: number;
}
export interface ApiTypeGroupCall {
joinMuted?: true;
canChangeJoinMuted?: true;
joinDateAsc?: true;
scheduleStartSubscribed?: true;
id: number;
participantsCount: number;
params?: any;
title?: string;
streamDcId?: number;
recordStartDate?: number;
scheduleDate?: number;
version: number;
}
export interface ApiChatFullInfo {
about?: string;
onlineCount?: number;
@ -93,19 +78,19 @@ export interface ApiChatFullInfo {
nextSendDate?: number;
};
migratedFrom?: {
chatId: number;
chatId: string;
maxMessageId?: number;
};
linkedChatId?: number;
linkedChatId?: string;
botCommands?: ApiBotCommand[];
}
export interface ApiChatMember {
userId: number;
inviterId?: number;
userId: string;
inviterId?: string;
joinedDate?: number;
kickedByUserId?: number;
promotedByUserId?: number;
kickedByUserId?: string;
promotedByUserId?: string;
bannedRights?: ApiChatBannedRights;
adminRights?: ApiChatAdminRights;
customTitle?: string;
@ -159,7 +144,7 @@ export interface ApiChatFolder {
excludeMuted?: true;
excludeRead?: true;
excludeArchived?: true;
pinnedChatIds?: number[];
includedChatIds: number[];
excludedChatIds: number[];
pinnedChatIds?: string[];
includedChatIds: string[];
excludedChatIds: string[];
}

View File

@ -39,7 +39,6 @@ export interface ApiStickerSet {
title: string;
hasThumbnail?: boolean;
count: number;
hash: number;
stickers?: ApiSticker[];
packs?: Record<string, ApiSticker[]>;
covers?: ApiSticker[];
@ -92,7 +91,7 @@ export interface ApiContact {
firstName: string;
lastName: string;
phoneNumber: string;
userId: number;
userId: string;
}
export interface ApiPollAnswer {
@ -122,7 +121,7 @@ export interface ApiPoll {
results: {
results?: ApiPollResult[];
totalVoters?: number;
recentVoterIds?: number[];
recentVoterIds?: string[];
solution?: string;
solutionEntities?: ApiMessageEntity[];
};
@ -149,8 +148,8 @@ export type ApiNewPoll = {
export interface ApiAction {
text: string;
targetUserIds?: number[];
targetChatId?: number;
targetUserIds?: string[];
targetChatId?: string;
type: 'historyClear' | 'contactSignUp' | 'chatCreate' | 'other';
photo?: ApiPhoto;
amount?: number;
@ -176,8 +175,8 @@ export interface ApiMessageForwardInfo {
isChannelPost: boolean;
channelPostId?: number;
isLinkedChannelPost?: boolean;
fromChatId?: number;
senderUserId?: number;
fromChatId?: string;
senderUserId?: string;
fromMessageId?: number;
hiddenUserName?: string;
adminTitle?: string;
@ -187,7 +186,7 @@ export interface ApiMessageEntity {
type: string;
offset: number;
length: number;
userId?: number;
userId?: string;
url?: string;
}
@ -218,7 +217,7 @@ export interface ApiFormattedText {
export interface ApiMessage {
id: number;
chatId: number;
chatId: string;
content: {
text?: ApiFormattedText;
photo?: ApiPhoto;
@ -235,8 +234,8 @@ export interface ApiMessage {
};
date: number;
isOutgoing: boolean;
senderId?: number;
replyToChatId?: number;
senderId?: string;
replyToChatId?: string;
replyToMessageId?: number;
replyToTopMessageId?: number;
sendingState?: 'messageSendingStatePending' | 'messageSendingStateFailed';
@ -254,7 +253,7 @@ export interface ApiMessage {
keyboardButtons?: ApiKeyboardButtons;
keyboardPlaceholder?: string;
isKeyboardSingleUse?: boolean;
viaBotId?: number;
viaBotId?: string;
threadInfo?: ApiThreadInfo;
adminTitle?: string;
isScheduled?: boolean;
@ -264,13 +263,13 @@ export interface ApiMessage {
export interface ApiThreadInfo {
threadId: number;
chatId: number;
chatId: string;
topMessageId?: number;
originChannelId?: number;
originChannelId?: string;
messagesCount: number;
lastMessageId?: number;
lastReadInboxMessageId?: number;
recentReplierIds?: number[];
recentReplierIds?: string[];
}
export type ApiMessageOutgoingStatus = 'read' | 'succeeded' | 'pending' | 'failed';

View File

@ -64,7 +64,7 @@ export interface ApiSessionData {
}
export type ApiNotifyException = {
chatId: number;
chatId: string;
isMuted: boolean;
isSilent?: boolean;
shouldShowPreviews?: boolean;

View File

@ -17,7 +17,7 @@ export interface ApiPaymentSavedInfo {
export interface ApiPaymentForm {
canSaveCredentials?: boolean;
passwordMissing?: boolean;
providerId: number;
providerId: string;
nativeProvider?: string;
savedInfo: any;
invoice: {

View File

@ -65,7 +65,7 @@ export type ApiUpdateCurrentUser = {
export type ApiUpdateChat = {
'@type': 'updateChat';
id: number;
id: string;
chat: Partial<ApiChat>;
newProfilePhoto?: ApiPhoto;
noTopChatsRequest?: boolean;
@ -73,7 +73,7 @@ export type ApiUpdateChat = {
export type ApiUpdateChatJoin = {
'@type': 'updateChatJoin';
id: number;
id: string;
};
export type ApiUpdateShowInvite = {
@ -83,50 +83,50 @@ export type ApiUpdateShowInvite = {
export type ApiUpdateChatLeave = {
'@type': 'updateChatLeave';
id: number;
id: string;
};
export type ApiUpdateChatInbox = {
'@type': 'updateChatInbox';
id: number;
id: string;
chat: Partial<ApiChat>;
};
export type ApiUpdateChatTypingStatus = {
'@type': 'updateChatTypingStatus';
id: number;
id: string;
typingStatus: ApiTypingStatus | undefined;
};
export type ApiUpdateChatFullInfo = {
'@type': 'updateChatFullInfo';
id: number;
id: string;
fullInfo: Partial<ApiChatFullInfo>;
};
export type ApiUpdateChatMembers = {
'@type': 'updateChatMembers';
id: number;
id: string;
replacedMembers?: ApiChatMember[];
addedMember?: ApiChatMember;
deletedMemberId?: number;
deletedMemberId?: string;
};
export type ApiUpdatePinnedChatIds = {
'@type': 'updatePinnedChatIds';
ids: number[];
ids: string[];
folderId?: number;
};
export type ApiUpdateChatListType = {
'@type': 'updateChatListType';
id: number;
id: string;
folderId: number;
};
export type ApiUpdateChatPinned = {
'@type': 'updateChatPinned';
id: number;
id: string;
isPinned: boolean;
};
@ -148,14 +148,14 @@ export type ApiUpdateRecommendedChatFolders = {
export type ApiUpdateNewScheduledMessage = {
'@type': 'newScheduledMessage';
chatId: number;
chatId: string;
id: number;
message: Partial<ApiMessage>;
};
export type ApiUpdateNewMessage = {
'@type': 'newMessage';
chatId: number;
chatId: string;
id: number;
message: Partial<ApiMessage>;
shouldForceReply?: boolean;
@ -163,28 +163,28 @@ export type ApiUpdateNewMessage = {
export type ApiUpdateMessage = {
'@type': 'updateMessage';
chatId: number;
chatId: string;
id: number;
message: Partial<ApiMessage>;
};
export type ApiUpdateScheduledMessage = {
'@type': 'updateScheduledMessage';
chatId: number;
chatId: string;
id: number;
message: Partial<ApiMessage>;
};
export type ApiUpdatePinnedMessageIds = {
'@type': 'updatePinnedIds';
chatId: number;
chatId: string;
isPinned?: boolean;
messageIds: number[];
};
export type ApiUpdateThreadInfo = {
'@type': 'updateThreadInfo';
chatId: number;
chatId: string;
threadId: number;
threadInfo: Partial<ApiThreadInfo>;
firstMessageId?: number;
@ -192,21 +192,21 @@ export type ApiUpdateThreadInfo = {
export type ApiUpdateScheduledMessageSendSucceeded = {
'@type': 'updateScheduledMessageSendSucceeded';
chatId: number;
chatId: string;
localId: number;
message: ApiMessage;
};
export type ApiUpdateMessageSendSucceeded = {
'@type': 'updateMessageSendSucceeded';
chatId: number;
chatId: string;
localId: number;
message: ApiMessage;
};
export type ApiUpdateMessageSendFailed = {
'@type': 'updateMessageSendFailed';
chatId: number;
chatId: string;
localId: number;
sendingState: {
'@type': 'messageSendingStateFailed';
@ -221,7 +221,7 @@ export type ApiUpdateCommonBoxMessages = {
export type ApiUpdateChannelMessages = {
'@type': 'updateChannelMessages';
channelId: number;
channelId: string;
ids: number[];
messageUpdate: Partial<ApiMessage>;
};
@ -235,7 +235,7 @@ export type ApiUpdateMessagePoll = {
export type ApiUpdateMessagePollVote = {
'@type': 'updateMessagePollVote';
pollId: string;
userId: number;
userId: string;
options: string[];
};
@ -247,34 +247,34 @@ export type ApiUpdateServiceNotification = {
export type ApiUpdateDeleteMessages = {
'@type': 'deleteMessages';
ids: number[];
chatId?: number;
chatId?: string;
};
export type ApiUpdateDeleteScheduledMessages = {
'@type': 'deleteScheduledMessages';
ids: number[];
chatId?: number;
chatId?: string;
};
export type ApiUpdateDeleteHistory = {
'@type': 'deleteHistory';
chatId: number;
chatId: string;
};
export type ApiUpdateDeleteProfilePhotos = {
'@type': 'deleteProfilePhotos';
ids: string[];
chatId: number;
chatId: string;
};
export type ApiUpdateResetMessages = {
'@type': 'resetMessages';
id: number;
id: string;
};
export type ApiUpdateDraftMessage = {
'@type': 'draftMessage';
chatId: number;
chatId: string;
formattedText?: ApiFormattedText;
date?: number;
replyingToId?: number;
@ -282,30 +282,30 @@ export type ApiUpdateDraftMessage = {
export type ApiDeleteUser = {
'@type': 'deleteUser';
id: number;
id: string;
};
export type ApiUpdateUser = {
'@type': 'updateUser';
id: number;
id: string;
user: Partial<ApiUser>;
};
export type ApiUpdateUserStatus = {
'@type': 'updateUserStatus';
userId: number;
userId: string;
status: ApiUserStatus;
};
export type ApiUpdateUserFullInfo = {
'@type': 'updateUserFullInfo';
id: number;
id: string;
fullInfo: Partial<ApiUserFullInfo>;
};
export type ApiUpdateAvatar = {
'@type': 'updateAvatar';
chatId: number;
chatId: string;
dataUri: string;
};
@ -357,7 +357,7 @@ export type ApiUpdateTwoFaStateWaitCode = {
export type ApiUpdatePeerBlocked = {
'@type': 'updatePeerBlocked';
id: number;
id: string;
isBlocked: boolean;
};
@ -366,10 +366,10 @@ export type ApiUpdatePrivacy = {
key: 'phoneNumber' | 'lastSeen' | 'profilePhoto' | 'forwards' | 'chatInvite';
rules: {
visibility: 'everybody' | 'contacts' | 'nonContacts' | 'nobody';
allowUserIds: number[];
allowChatIds: number[];
blockUserIds: number[];
blockChatIds: number[];
allowUserIds: string[];
allowChatIds: string[];
blockUserIds: string[];
blockChatIds: string[];
};
};

View File

@ -2,7 +2,7 @@ import { ApiPhoto } from './messages';
import { ApiBotCommand } from './bots';
export interface ApiUser {
id: number;
id: string;
isMin: boolean;
isSelf?: true;
isVerified?: true;

View File

@ -51,10 +51,10 @@ type OwnProps = {
isSelectable?: boolean;
isSelected?: boolean;
isDownloading: boolean;
onPlay: (messageId: number, chatId: number) => void;
onPlay: (messageId: number, chatId: string) => void;
onReadMedia?: () => void;
onCancelUpload?: () => void;
onDateClick?: (messageId: number, chatId: number) => void;
onDateClick?: (messageId: number, chatId: string) => void;
};
const AVG_VOICE_DURATION = 10;

View File

@ -9,7 +9,7 @@ import {
getChatTitle,
getUserColorKey,
getUserFullName,
isChatPrivate,
isUserId,
isChatWithRepliesBot,
isDeletedUser,
isUserOnline,
@ -78,7 +78,7 @@ const Avatar: FC<OwnProps> = ({
content = userFullName ? getFirstLetters(userFullName, 2) : undefined;
} else if (chat) {
const title = getChatTitle(lang, chat);
content = title && getFirstLetters(title, isChatPrivate(chat.id) ? 2 : 1);
content = title && getFirstLetters(title, isUserId(chat.id) ? 2 : 1);
} else if (text) {
content = getFirstLetters(text, 2);
}

View File

@ -10,7 +10,7 @@ import {
selectChat, selectNotifyExceptions, selectNotifySettings, selectUser,
} from '../../modules/selectors';
import {
getChatDescription, getChatLink, getHasAdminRight, isChatChannel, isChatPrivate, isUserRightBanned, selectIsChatMuted,
getChatDescription, getChatLink, getHasAdminRight, isChatChannel, isUserId, isUserRightBanned, selectIsChatMuted,
} from '../../modules/helpers';
import renderText from './helpers/renderText';
import { pick } from '../../util/iteratees';
@ -22,7 +22,7 @@ import ListItem from '../ui/ListItem';
import Switcher from '../ui/Switcher';
type OwnProps = {
chatOrUserId: number;
chatOrUserId: string;
forceShowSelf?: boolean;
};
@ -140,7 +140,7 @@ export default memo(withGlobal<OwnProps>(
const { lastSyncTime, countryList: { phoneCodes: phoneCodeList } } = global;
const chat = chatOrUserId ? selectChat(global, chatOrUserId) : undefined;
const user = isChatPrivate(chatOrUserId) ? selectUser(global, chatOrUserId) : undefined;
const user = isUserId(chatOrUserId) ? selectUser(global, chatOrUserId) : undefined;
const isMuted = chat && selectIsChatMuted(chat, selectNotifySettings(global), selectNotifyExceptions(global));
const canInviteUsers = chat && !user && (

View File

@ -10,7 +10,7 @@ import Link from '../ui/Link';
type OwnProps = {
className?: string;
chatId?: number;
chatId?: string;
children: any;
};

View File

@ -7,7 +7,7 @@ import useInfiniteScroll from '../../hooks/useInfiniteScroll';
import useLang from '../../hooks/useLang';
import useKeyboardListNavigation from '../../hooks/useKeyboardListNavigation';
import useInputFocusOnOpen from '../../hooks/useInputFocusOnOpen';
import { isChatPrivate } from '../../modules/helpers';
import { isUserId } from '../../modules/helpers';
import Loading from '../ui/Loading';
import Modal from '../ui/Modal';
@ -21,15 +21,15 @@ import PrivateChatInfo from './PrivateChatInfo';
import './ChatOrUserPicker.scss';
export type OwnProps = {
currentUserId?: number;
chatOrUserIds: number[];
currentUserId?: string;
chatOrUserIds: string[];
isOpen: boolean;
filterRef: RefObject<HTMLInputElement>;
filterPlaceholder: string;
filter: string;
onFilterChange: (filter: string) => void;
loadMore: NoneToVoidFunction;
onSelectChatOrUser: (chatOrUserId: number) => void;
onSelectChatOrUser: (chatOrUserId: string) => void;
onClose: NoneToVoidFunction;
};
@ -104,7 +104,7 @@ const ChatOrUserPicker: FC<OwnProps> = ({
className="chat-item-clickable force-rounded-corners"
onClick={() => onSelectChatOrUser(id)}
>
{isChatPrivate(id) ? (
{isUserId(id) ? (
<PrivateChatInfo status={id === currentUserId ? lang('SavedMessagesInfo') : undefined} userId={id} />
) : (
<GroupChatInfo chatId={id} />

View File

@ -6,7 +6,7 @@ import { GlobalActions } from '../../global/types';
import { selectIsChatWithSelf, selectUser } from '../../modules/selectors';
import {
isChatPrivate,
isUserId,
isUserBot,
getUserFirstOrLastName,
getPrivateChatUserId,
@ -39,7 +39,7 @@ type StateProps = {
isPrivateChat: boolean;
isBasicGroup: boolean;
isSuperGroup: boolean;
currentUserId: number | undefined;
currentUserId: string | undefined;
canDeleteForAll?: boolean;
contactName?: string;
};
@ -196,7 +196,7 @@ const DeleteChatModal: FC<OwnProps & StateProps & DispatchProps> = ({
export default memo(withGlobal<OwnProps>(
(global, { chat }): StateProps => {
const isPrivateChat = isChatPrivate(chat.id);
const isPrivateChat = isUserId(chat.id);
const isChatWithSelf = selectIsChatWithSelf(global, chat.id);
const user = isPrivateChat && selectUser(global, getPrivateChatUserId(chat)!);
const isBot = user && isUserBot(user) && !chat.isSupport;

View File

@ -13,7 +13,7 @@ import {
selectUser,
} from '../../modules/selectors';
import {
isChatPrivate,
isUserId,
getUserFirstOrLastName,
getPrivateChatUserId,
isChatBasicGroup,
@ -115,7 +115,7 @@ export default memo(withGlobal<OwnProps>(
const { threadId } = selectCurrentMessageList(global) || {};
const { canDeleteForAll } = (threadId && selectAllowedMessageActions(global, message, threadId)) || {};
const chat = selectChat(global, message.chatId);
const contactName = chat && isChatPrivate(chat.id)
const contactName = chat && isUserId(chat.id)
? getUserFirstOrLastName(selectUser(global, getPrivateChatUserId(chat)!))
: undefined;

View File

@ -32,7 +32,7 @@ type OwnProps = {
isDownloading: boolean;
onCancelUpload?: () => void;
onMediaClick?: () => void;
onDateClick?: (messageId: number, chatId: number) => void;
onDateClick?: (messageId: number, chatId: string) => void;
};
const Document: FC<OwnProps> = ({

View File

@ -23,7 +23,7 @@ import VerifiedIcon from './VerifiedIcon';
import TypingStatus from './TypingStatus';
type OwnProps = {
chatId: number;
chatId: string;
typingStatus?: ApiTypingStatus;
avatarSize?: 'small' | 'medium' | 'large' | 'jumbo';
withMediaViewer?: boolean;

View File

@ -16,7 +16,7 @@ import './Media.scss';
type OwnProps = {
message: ApiMessage;
idPrefix?: string;
onClick?: (messageId: number, chatId: number) => void;
onClick?: (messageId: number, chatId: string) => void;
};
const Media: FC<OwnProps> = ({ message, idPrefix = 'shared-media', onClick }) => {

View File

@ -2,7 +2,7 @@ import React, {
FC, useCallback, useRef, useEffect, memo,
} from '../../lib/teact/teact';
import { isChatPrivate } from '../../modules/helpers';
import { isUserId } from '../../modules/helpers';
import InfiniteScroll from '../ui/InfiniteScroll';
import Checkbox from '../ui/Checkbox';
@ -19,15 +19,15 @@ import Loading from '../ui/Loading';
import './Picker.scss';
type OwnProps = {
itemIds: number[];
selectedIds: number[];
itemIds: string[];
selectedIds: string[];
filterValue?: string;
filterPlaceholder?: string;
notFoundText?: string;
searchInputId?: string;
isLoading?: boolean;
noScrollRestore?: boolean;
onSelectedIdsChange: (ids: number[]) => void;
onSelectedIdsChange: (ids: string[]) => void;
onFilterChange: (value: string) => void;
onLoadMore?: () => void;
};
@ -63,7 +63,7 @@ const Picker: FC<OwnProps> = ({
}, FOCUS_DELAY_MS);
}, []);
const handleItemClick = useCallback((id: number) => {
const handleItemClick = useCallback((id: string) => {
const newSelectedIds = [...selectedIds];
if (newSelectedIds.includes(id)) {
newSelectedIds.splice(newSelectedIds.indexOf(id), 1);
@ -119,7 +119,7 @@ const Picker: FC<OwnProps> = ({
ripple
>
<Checkbox label="" checked={selectedIds.includes(id)} />
{isChatPrivate(id) ? (
{isUserId(id) ? (
<PrivateChatInfo userId={id} />
) : (
<GroupChatInfo chatId={id} />

View File

@ -4,7 +4,7 @@ import { withGlobal } from '../../lib/teact/teactn';
import { ApiChat, ApiUser } from '../../api/types';
import { selectChat, selectUser } from '../../modules/selectors';
import { getChatTitle, getUserFirstOrLastName, isChatPrivate } from '../../modules/helpers';
import { getChatTitle, getUserFirstOrLastName, isUserId } from '../../modules/helpers';
import renderText from './helpers/renderText';
import buildClassName from '../../util/buildClassName';
import useLang from '../../hooks/useLang';
@ -14,7 +14,7 @@ import Avatar from './Avatar';
import './PickerSelectedItem.scss';
type OwnProps = {
chatOrUserId?: number;
chatOrUserId?: string;
icon?: string;
title?: string;
isMinimized?: boolean;
@ -106,7 +106,7 @@ export default memo(withGlobal<OwnProps>(
}
const chat = chatOrUserId ? selectChat(global, chatOrUserId) : undefined;
const user = isChatPrivate(chatOrUserId) ? selectUser(global, chatOrUserId) : undefined;
const user = isUserId(chatOrUserId) ? selectUser(global, chatOrUserId) : undefined;
return {
chat,

View File

@ -5,7 +5,7 @@ import { GlobalActions } from '../../global/types';
import { selectChat, selectIsChatWithSelf, selectUser } from '../../modules/selectors';
import {
isChatPrivate,
isUserId,
getUserFirstOrLastName,
getPrivateChatUserId,
isChatBasicGroup,
@ -21,7 +21,7 @@ import Button from '../ui/Button';
export type OwnProps = {
isOpen: boolean;
chatId: number;
chatId: string;
messageId: number;
onClose: () => void;
};
@ -103,14 +103,14 @@ const PinMessageModal: FC<OwnProps & StateProps & DispatchProps> = ({
export default memo(withGlobal<OwnProps>(
(global, { chatId }): StateProps => {
const isPrivateChat = isChatPrivate(chatId);
const isPrivateChat = isUserId(chatId);
const isChatWithSelf = selectIsChatWithSelf(global, chatId);
const chat = selectChat(global, chatId);
const isChannel = !!chat && isChatChannel(chat);
const isGroup = !!chat && isChatBasicGroup(chat);
const isSuperGroup = !!chat && isChatSuperGroup(chat);
const canPinForAll = (isPrivateChat && !isChatWithSelf) || isSuperGroup || isGroup;
const contactName = chat && isChatPrivate(chat.id)
const contactName = chat && isUserId(chat.id)
? getUserFirstOrLastName(selectUser(global, getPrivateChatUserId(chat)!))
: undefined;

View File

@ -19,7 +19,7 @@ import VerifiedIcon from './VerifiedIcon';
import TypingStatus from './TypingStatus';
type OwnProps = {
userId: number;
userId: string;
typingStatus?: ApiTypingStatus;
avatarSize?: 'tiny' | 'small' | 'medium' | 'large' | 'jumbo';
forceShowSelf?: boolean;

View File

@ -26,7 +26,7 @@ import Transition from '../ui/Transition';
import './ProfileInfo.scss';
type OwnProps = {
userId: number;
userId: string;
forceShowSelf?: boolean;
};

View File

@ -9,7 +9,7 @@ import {
getChatTitle,
getUserColorKey,
getUserFullName,
isChatPrivate,
isUserId,
isChatWithRepliesBot,
isDeletedUser,
} from '../../modules/helpers';
@ -87,7 +87,7 @@ const ProfilePhoto: FC<OwnProps> = ({
content = userFullName ? getFirstLetters(userFullName, 2) : undefined;
} else if (!imageSrc && chat) {
const title = getChatTitle(lang, chat);
content = title && getFirstLetters(title, isChatPrivate(chat.id) ? 2 : 1);
content = title && getFirstLetters(title, isUserId(chat.id) ? 2 : 1);
} else {
content = (
<div className="spinner-wrapper">

View File

@ -7,7 +7,7 @@ import Button from '../ui/Button';
export type OwnProps = {
isOpen: boolean;
chatId?: number;
chatId?: string;
pinnedMessagesCount?: number;
onClose: () => void;
onUnpin: () => void;

View File

@ -20,7 +20,7 @@ const MAX_TEXT_LENGTH = 170; // symbols
type OwnProps = {
message: ApiMessage;
senderTitle?: string;
onMessageClick: (messageId: number, chatId: number) => void;
onMessageClick: (messageId: number, chatId: string) => void;
};
const WebLink: FC<OwnProps> = ({

View File

@ -7,7 +7,7 @@ import {
getMessageContent,
getMessageSummaryText,
getUserFullName,
isChatPrivate,
isUserId,
} from '../../../modules/helpers';
import trimText from '../../../util/trimText';
import { formatCurrency } from '../../../util/formatCurrency';
@ -32,7 +32,7 @@ export function renderActionMessageText(
actionOrigin?: ApiUser | ApiChat,
targetUsers?: ApiUser[],
targetMessage?: ApiMessage,
targetChatId?: number,
targetChatId?: string,
options: ActionMessageTextOptions = {},
) {
if (!message.content.action) {
@ -167,7 +167,7 @@ function renderMessageContent(lang: LangFn, message: ApiMessage, options: Action
}
function renderOriginContent(lang: LangFn, origin: ApiUser | ApiChat, asPlain?: boolean) {
return isChatPrivate(origin.id)
return isUserId(origin.id)
? renderUserContent(origin as ApiUser, asPlain)
: renderChatContent(lang, origin as ApiChat, asPlain);
}
@ -192,7 +192,7 @@ function renderChatContent(lang: LangFn, chat: ApiChat, asPlain?: boolean): stri
return <ChatLink className="action-link" chatId={chat.id}>{chat && renderText(text!)}</ChatLink>;
}
function renderMigratedContent(chatId: number, asPlain?: boolean): string | TextPart | undefined {
function renderMigratedContent(chatId: string, asPlain?: boolean): string | TextPart | undefined {
const text = 'another chat';
if (asPlain) {

View File

@ -15,7 +15,7 @@ import CheckboxGroup from '../ui/CheckboxGroup';
export type OwnProps = {
isOpen: boolean;
chatId: number;
chatId: string;
onClose: () => void;
onCloseAnimationEnd?: () => void;
};
@ -63,8 +63,8 @@ const ChatFolderModal: FC<OwnProps & StateProps & DispatchProps> = ({
}, [folderOrderedIds, foldersById]);
const handleSubmit = useCallback(() => {
const idsToRemove = initialSelectedFolderIds.filter((id) => !selectedFolderIds.includes(id)).map(Number);
const idsToAdd = selectedFolderIds.filter((id) => !initialSelectedFolderIds.includes(id)).map(Number);
const idsToRemove = initialSelectedFolderIds.filter((id) => !selectedFolderIds.includes(id));
const idsToAdd = selectedFolderIds.filter((id) => !initialSelectedFolderIds.includes(id));
editChatFolders({ chatId, idsToRemove, idsToAdd });
onClose();

View File

@ -14,7 +14,7 @@ import { ANIMATION_END_DELAY } from '../../../config';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../../util/environment';
import {
getChatTitle,
isChatPrivate,
isUserId,
isActionMessage,
getPrivateChatUserId,
getMessageAction,
@ -56,7 +56,7 @@ import './Chat.scss';
type OwnProps = {
style?: string;
chatId: number;
chatId: string;
folderId?: number;
orderDiff: number;
animationType: ChatAnimationTypes;
@ -67,10 +67,10 @@ type StateProps = {
chat?: ApiChat;
isMuted?: boolean;
privateChatUser?: ApiUser;
actionTargetUserIds?: number[];
usersById?: Record<number, ApiUser>;
actionTargetUserIds?: string[];
usersById?: Record<string, ApiUser>;
actionTargetMessage?: ApiMessage;
actionTargetChatId?: number;
actionTargetChatId?: string;
lastMessageSender?: ApiUser;
lastMessageOutgoingStatus?: ApiMessageOutgoingStatus;
draft?: ApiFormattedText;
@ -264,7 +264,7 @@ const Chat: FC<OwnProps & StateProps & DispatchProps> = ({
const className = buildClassName(
'Chat chat-item-clickable',
isChatPrivate(chatId) ? 'private' : 'group',
isUserId(chatId) ? 'private' : 'group',
isSelected && 'selected',
);

View File

@ -30,14 +30,14 @@ type OwnProps = {
};
type StateProps = {
chatsById: Record<number, ApiChat>;
usersById: Record<number, ApiUser>;
chatsById: Record<string, ApiChat>;
usersById: Record<string, ApiUser>;
chatFoldersById: Record<number, ApiChatFolder>;
notifySettings: NotifySettings;
notifyExceptions?: Record<number, NotifyException>;
orderedFolderIds?: number[];
activeChatFolder: number;
currentUserId?: number;
currentUserId?: string;
lastSyncTime?: number;
shouldSkipHistoryAnimations?: boolean;
};
@ -86,7 +86,7 @@ const ChatFolders: FC<OwnProps & StateProps & DispatchProps> = ({
return undefined;
}
const chatIds = Object.keys(chatsById).map(Number);
const chatIds = Object.keys(chatsById);
const counters = displayedFolders.map((folder) => {
const {
unreadDialogsCount, hasActiveDialogs,

View File

@ -35,11 +35,11 @@ type OwnProps = {
};
type StateProps = {
chatsById: Record<number, ApiChat>;
usersById: Record<number, ApiUser>;
chatsById: Record<string, ApiChat>;
usersById: Record<string, ApiUser>;
chatFolder?: ApiChatFolder;
listIds?: number[];
orderedPinnedIds?: number[];
listIds?: string[];
orderedPinnedIds?: string[];
lastSyncTime?: number;
notifySettings: NotifySettings;
notifyExceptions?: Record<number, NotifyException>;

View File

@ -26,8 +26,8 @@ export type OwnProps = {
};
type StateProps = {
usersById: Record<number, ApiUser>;
contactIds?: number[];
usersById: Record<string, ApiUser>;
contactIds?: string[];
serverTimeOffset: number;
};
@ -49,12 +49,9 @@ const ContactList: FC<OwnProps & StateProps & DispatchProps> = ({
useHistoryBack(isActive, onReset);
const handleClick = useCallback(
(id: number) => {
openChat({ id, shouldReplaceHistory: true });
},
[openChat],
);
const handleClick = useCallback((id: string) => {
openChat({ id, shouldReplaceHistory: true });
}, [openChat]);
const listIds = useMemo(() => {
if (!contactIds) {

View File

@ -43,12 +43,12 @@ type OwnProps = {
type StateProps = {
searchQuery?: string;
isLoading: boolean;
currentUserId?: number;
globalSearchChatId?: number;
currentUserId?: string;
globalSearchChatId?: string;
searchDate?: number;
theme: ISettings['theme'];
animationLevel: 0 | 1 | 2;
chatsById?: Record<number, ApiChat>;
chatsById?: Record<string, ApiChat>;
};
type DispatchProps = Pick<GlobalActions, (

View File

@ -6,15 +6,15 @@ export enum ChatAnimationTypes {
None,
}
export function useChatAnimationType(orderDiffById: Record<number, number>) {
const movesUp = useCallback((id: number) => orderDiffById[id] < 0, [orderDiffById]);
const movesDown = useCallback((id: number) => orderDiffById[id] > 0, [orderDiffById]);
export function useChatAnimationType(orderDiffById: Record<string, number>) {
const movesUp = useCallback((id: string) => orderDiffById[id] < 0, [orderDiffById]);
const movesDown = useCallback((id: string) => orderDiffById[id] > 0, [orderDiffById]);
const orderDiffIds = Object.keys(orderDiffById).map(Number);
const orderDiffIds = Object.keys(orderDiffById);
const numberOfUp = orderDiffIds.filter(movesUp).length;
const numberOfDown = orderDiffIds.filter(movesDown).length;
return useCallback((chatId: number): ChatAnimationTypes => {
return useCallback((chatId: string): ChatAnimationTypes => {
const orderDiff = orderDiffById[chatId];
if (orderDiff === 0) {

View File

@ -29,7 +29,7 @@ const NewChat: FC<OwnProps> = ({
onContentChange,
onReset,
}) => {
const [newChatMemberIds, setNewChatMemberIds] = useState<number[]>([]);
const [newChatMemberIds, setNewChatMemberIds] = useState<string[]>([]);
const handleNextStep = useCallback(() => {
onContentChange(isChannel ? LeftColumnContent.NewChannelStep2 : LeftColumnContent.NewGroupStep2);

View File

@ -20,21 +20,21 @@ import Button from '../../ui/Button';
export type OwnProps = {
isChannel?: boolean;
isActive: boolean;
selectedMemberIds: number[];
onSelectedMemberIdsChange: (ids: number[]) => void;
selectedMemberIds: string[];
onSelectedMemberIdsChange: (ids: string[]) => void;
onNextStep: () => void;
onReset: () => void;
};
type StateProps = {
currentUserId?: number;
usersById: Record<number, ApiUser>;
chatsById: Record<number, ApiChat>;
localContactIds?: number[];
currentUserId?: string;
usersById: Record<string, ApiUser>;
chatsById: Record<string, ApiChat>;
localContactIds?: string[];
searchQuery?: string;
isSearching?: boolean;
localUserIds?: number[];
globalUserIds?: number[];
localUserIds?: string[];
globalUserIds?: string[];
};
type DispatchProps = Pick<GlobalActions, 'loadContactList' | 'setGlobalSearchQuery'>;

View File

@ -21,7 +21,7 @@ import PrivateChatInfo from '../../common/PrivateChatInfo';
export type OwnProps = {
isChannel?: boolean;
isActive: boolean;
memberIds: number[];
memberIds: string[];
onReset: (forceReturnToChatList?: boolean) => void;
};

View File

@ -66,17 +66,17 @@ const AudioResults: FC<OwnProps & StateProps & DispatchProps> = ({
}
return foundIds.map((id) => {
const [chatId, messageId] = id.split('_').map(Number);
const [chatId, messageId] = id.split('_');
return globalMessagesByChatId[chatId]?.byId[messageId];
return globalMessagesByChatId[chatId]?.byId[Number(messageId)];
}).filter(Boolean);
}, [globalMessagesByChatId, foundIds]);
const handleMessageFocus = useCallback((messageId: number, chatId: number) => {
const handleMessageFocus = useCallback((messageId: number, chatId: string) => {
focusMessage({ chatId, messageId });
}, [focusMessage]);
const handlePlayAudio = useCallback((messageId: number, chatId: number) => {
const handlePlayAudio = useCallback((messageId: number, chatId: string) => {
openAudioPlayer({ chatId, messageId, origin: AudioOrigin.Search });
}, [openAudioPlayer]);

View File

@ -36,7 +36,7 @@ import './ChatMessage.scss';
type OwnProps = {
searchQuery?: string;
message: ApiMessage;
chatId: number;
chatId: string;
};
type StateProps = {

View File

@ -26,10 +26,10 @@ export type OwnProps = {
};
type StateProps = {
currentUserId?: number;
currentUserId?: string;
foundIds?: string[];
globalMessagesByChatId?: Record<number, { byId: Record<number, ApiMessage> }>;
chatsById: Record<number, ApiChat>;
globalMessagesByChatId?: Record<string, { byId: Record<number, ApiMessage> }>;
chatsById: Record<string, ApiChat>;
fetchingStatus?: { chats?: boolean; messages?: boolean };
lastSyncTime?: number;
};
@ -70,9 +70,9 @@ const ChatMessageResults: FC<OwnProps & StateProps & DispatchProps> = ({
return foundIds
.map((id) => {
const [chatId, messageId] = id.split('_').map(Number);
const [chatId, messageId] = id.split('_');
return globalMessagesByChatId?.[chatId]?.byId[messageId];
return globalMessagesByChatId?.[chatId]?.byId[Number(messageId)];
})
.filter<ApiMessage>(Boolean as any)
.sort((a, b) => b.date - a.date);

View File

@ -33,16 +33,16 @@ export type OwnProps = {
};
type StateProps = {
currentUserId?: number;
localContactIds?: number[];
localChatIds?: number[];
localUserIds?: number[];
globalChatIds?: number[];
globalUserIds?: number[];
currentUserId?: string;
localContactIds?: string[];
localChatIds?: string[];
localUserIds?: string[];
globalChatIds?: string[];
globalUserIds?: string[];
foundIds?: string[];
globalMessagesByChatId?: Record<number, { byId: Record<number, ApiMessage> }>;
chatsById: Record<number, ApiChat>;
usersById: Record<number, ApiUser>;
globalMessagesByChatId?: Record<string, { byId: Record<number, ApiMessage> }>;
chatsById: Record<string, ApiChat>;
usersById: Record<string, ApiUser>;
fetchingStatus?: { chats?: boolean; messages?: boolean };
lastSyncTime?: number;
};
@ -79,7 +79,7 @@ const ChatResults: FC<OwnProps & StateProps & DispatchProps> = ({
}, [lastSyncTime, searchMessagesGlobal, searchQuery]);
const handleChatClick = useCallback(
(id: number) => {
(id: string) => {
openChat({ id, shouldReplaceHistory: true });
if (id !== currentUserId) {
@ -93,7 +93,7 @@ const ChatResults: FC<OwnProps & StateProps & DispatchProps> = ({
[currentUserId, openChat, addRecentlyFoundChatId, onReset],
);
const handlePickerItemClick = useCallback((id: number) => {
const handlePickerItemClick = useCallback((id: string) => {
setGlobalSearchChatId({ id });
}, [setGlobalSearchChatId]);
@ -142,9 +142,9 @@ const ChatResults: FC<OwnProps & StateProps & DispatchProps> = ({
return foundIds
.map((id) => {
const [chatId, messageId] = id.split('_').map(Number);
const [chatId, messageId] = id.split('_');
return globalMessagesByChatId?.[chatId]?.byId[messageId];
return globalMessagesByChatId?.[chatId]?.byId[Number(messageId)];
})
.filter<ApiMessage>(Boolean as any)
.sort((a, b) => b.date - a.date);

View File

@ -64,14 +64,14 @@ const FileResults: FC<OwnProps & StateProps & DispatchProps> = ({
}
return foundIds.map((id) => {
const [chatId, messageId] = id.split('_').map(Number);
const message = globalMessagesByChatId[chatId]?.byId[messageId];
const [chatId, messageId] = id.split('_');
const message = globalMessagesByChatId[chatId]?.byId[Number(messageId)];
return message && getMessageDocument(message) ? message : undefined;
}).filter(Boolean) as ApiMessage[];
}, [globalMessagesByChatId, foundIds]);
const handleMessageFocus = useCallback((messageId: number, chatId: number) => {
const handleMessageFocus = useCallback((messageId: number, chatId: string) => {
focusMessage({ chatId, messageId });
}, [focusMessage]);

View File

@ -32,7 +32,7 @@ export type OwnProps = {
type StateProps = {
currentContent?: GlobalSearchContent;
chatId?: number;
chatId?: string;
};
type DispatchProps = Pick<GlobalActions, ('setGlobalSearchContent' | 'setGlobalSearchDate')>;

View File

@ -7,7 +7,7 @@ import { ApiChat, ApiUser } from '../../../api/types';
import useChatContextActions from '../../../hooks/useChatContextActions';
import useFlag from '../../../hooks/useFlag';
import { isChatPrivate, getPrivateChatUserId, selectIsChatMuted } from '../../../modules/helpers';
import { isUserId, getPrivateChatUserId, selectIsChatMuted } from '../../../modules/helpers';
import {
selectChat, selectUser, selectIsChatPinned, selectNotifySettings, selectNotifyExceptions,
} from '../../../modules/selectors';
@ -20,9 +20,9 @@ import ListItem from '../../ui/ListItem';
import ChatFolderModal from '../ChatFolderModal.async';
type OwnProps = {
chatId: number;
chatId: string;
withUsername?: boolean;
onClick: (id: number) => void;
onClick: (id: string) => void;
};
type StateProps = {
@ -70,7 +70,7 @@ const LeftSearchResultChat: FC<OwnProps & StateProps> = ({
contextActions={contextActions}
buttonRef={buttonRef}
>
{isChatPrivate(chatId) ? (
{isUserId(chatId) ? (
<PrivateChatInfo userId={chatId} withUsername={withUsername} avatarSize="large" />
) : (
<GroupChatInfo chatId={chatId} withUsername={withUsername} avatarSize="large" />

View File

@ -61,13 +61,13 @@ const LinkResults: FC<OwnProps & StateProps & DispatchProps> = ({
}
return foundIds.map((id) => {
const [chatId, messageId] = id.split('_').map(Number);
const [chatId, messageId] = id.split('_');
return globalMessagesByChatId[chatId]?.byId[messageId];
return globalMessagesByChatId[chatId]?.byId[Number(messageId)];
}).filter(Boolean);
}, [globalMessagesByChatId, foundIds]);
const handleMessageFocus = useCallback((messageId: number, chatId: number) => {
const handleMessageFocus = useCallback((messageId: number, chatId: string) => {
focusMessage({ chatId, messageId });
}, [focusMessage]);

View File

@ -60,13 +60,13 @@ const MediaResults: FC<OwnProps & StateProps & DispatchProps> = ({
}
return foundIds.map((id) => {
const [chatId, messageId] = id.split('_').map(Number);
const [chatId, messageId] = id.split('_');
return globalMessagesByChatId[chatId]?.byId[messageId];
return globalMessagesByChatId[chatId]?.byId[Number(messageId)];
}).filter(Boolean);
}, [globalMessagesByChatId, foundIds]);
const handleSelectMedia = useCallback((messageId: number, chatId: number) => {
const handleSelectMedia = useCallback((messageId: number, chatId: string) => {
openMediaViewer({
chatId,
messageId,

View File

@ -24,9 +24,9 @@ type OwnProps = {
};
type StateProps = {
topUserIds?: number[];
usersById: Record<number, ApiUser>;
recentlyFoundChatIds?: number[];
topUserIds?: string[];
usersById: Record<string, ApiUser>;
recentlyFoundChatIds?: string[];
};
type DispatchProps = Pick<GlobalActions, (
@ -58,16 +58,13 @@ const RecentContacts: FC<OwnProps & StateProps & DispatchProps> = ({
useHorizontalScroll(topUsersRef.current, !topUserIds);
const handleClick = useCallback(
(id: number) => {
openChat({ id, shouldReplaceHistory: true });
onReset();
setTimeout(() => {
addRecentlyFoundChatId({ id });
}, SEARCH_CLOSE_TIMEOUT_MS);
},
[openChat, addRecentlyFoundChatId, onReset],
);
const handleClick = useCallback((id: string) => {
openChat({ id, shouldReplaceHistory: true });
onReset();
setTimeout(() => {
addRecentlyFoundChatId({ id });
}, SEARCH_CLOSE_TIMEOUT_MS);
}, [openChat, addRecentlyFoundChatId, onReset]);
const lang = useLang();

View File

@ -9,13 +9,13 @@ import { selectTheme } from '../../../../modules/selectors';
export type StateProps = {
theme: ISettings['theme'];
isLoading?: boolean;
chatsById: Record<number, ApiChat>;
usersById: Record<number, ApiUser>;
globalMessagesByChatId?: Record<number, { byId: Record<number, ApiMessage> }>;
chatsById: Record<string, ApiChat>;
usersById: Record<string, ApiUser>;
globalMessagesByChatId?: Record<string, { byId: Record<number, ApiMessage> }>;
foundIds?: string[];
lastSyncTime?: number;
searchChatId?: number;
activeDownloads: Record<number, number[]>;
searchChatId?: string;
activeDownloads: Record<string, number[]>;
};
export function createMapStateToProps(type: ApiGlobalMessageSearchType) {

View File

@ -2,26 +2,26 @@ import { ApiChat, ApiMessage, ApiUser } from '../../../../api/types';
import {
getChatTitle,
getSenderTitle,
isChatPrivate,
isUserId,
isChatGroup,
} from '../../../../modules/helpers';
import { LangFn } from '../../../../hooks/useLang';
export function getSenderName(
lang: LangFn, message: ApiMessage, chatsById: Record<number, ApiChat>, usersById: Record<number, ApiUser>,
lang: LangFn, message: ApiMessage, chatsById: Record<string, ApiChat>, usersById: Record<string, ApiUser>,
) {
const { senderId } = message;
if (!senderId) {
return undefined;
}
const sender = isChatPrivate(senderId) ? usersById[senderId] : chatsById[senderId];
const sender = isUserId(senderId) ? usersById[senderId] : chatsById[senderId];
let senderName = getSenderTitle(lang, sender);
const chat = chatsById[message.chatId];
if (chat) {
if (isChatPrivate(senderId) && (sender as ApiUser).isSelf) {
if (isUserId(senderId) && (sender as ApiUser).isSelf) {
senderName = `${lang('FromYou')}${getChatTitle(lang, chat)}`;
} else if (isChatGroup(chat)) {
senderName += `${getChatTitle(lang, chat)}`;

View File

@ -19,11 +19,11 @@ export type OwnProps = {
};
type StateProps = {
usersById: Record<number, ApiUser>;
blockedIds: number[];
contactIds?: number[];
localContactIds?: number[];
currentUserId?: number;
usersById: Record<string, ApiUser>;
blockedIds: string[];
contactIds?: string[];
localContactIds?: string[];
currentUserId?: string;
};
type DispatchProps = Pick<GlobalActions, 'loadContactList' | 'setUserSearchQuery' | 'blockContact'>;
@ -54,7 +54,7 @@ const BlockUserModal: FC<OwnProps & StateProps & DispatchProps> = ({
return !blockedIds.includes(contactId) && contactId !== currentUserId;
});
return unique(availableContactsId).reduce((acc, contactId) => {
return unique(availableContactsId).reduce<string[]>((acc, contactId) => {
if (
!filter
|| !usersById[contactId]
@ -65,7 +65,7 @@ const BlockUserModal: FC<OwnProps & StateProps & DispatchProps> = ({
}
return acc;
}, [] as number[])
}, [])
.sort((firstId, secondId) => {
const firstName = getUserFullName(usersById[firstId]) || '';
const secondName = getUserFullName(usersById[secondId]) || '';
@ -74,7 +74,7 @@ const BlockUserModal: FC<OwnProps & StateProps & DispatchProps> = ({
});
}, [blockedIds, contactIds, currentUserId, filter, localContactIds, usersById]);
const handleRemoveUser = useCallback((userId: number) => {
const handleRemoveUser = useCallback((userId: string) => {
const { id: contactId, accessHash } = usersById[userId] || {};
if (!contactId || !accessHash) {
return;

View File

@ -11,7 +11,7 @@ import { CHAT_HEIGHT_PX } from '../../../config';
import { formatPhoneNumberWithCode } from '../../../util/phoneNumber';
import { pick } from '../../../util/iteratees';
import {
getChatTitle, getUserFullName, isChatPrivate,
getChatTitle, getUserFullName, isUserId,
} from '../../../modules/helpers';
import renderText from '../../common/helpers/renderText';
import buildClassName from '../../../util/buildClassName';
@ -32,9 +32,9 @@ type OwnProps = {
};
type StateProps = {
chatsByIds: Record<number, ApiChat>;
usersByIds: Record<number, ApiUser>;
blockedIds: number[];
chatsByIds: Record<string, ApiChat>;
usersByIds: Record<string, ApiUser>;
blockedIds: string[];
phoneCodeList: ApiCountryCode[];
};
@ -52,14 +52,14 @@ const SettingsPrivacyBlockedUsers: FC<OwnProps & StateProps & DispatchProps> = (
}) => {
const lang = useLang();
const [isBlockUserModalOpen, openBlockUserModal, closeBlockUserModal] = useFlag();
const handleUnblockClick = useCallback((contactId: number) => {
const handleUnblockClick = useCallback((contactId: string) => {
unblockContact({ contactId });
}, [unblockContact]);
useHistoryBack(isActive, onReset, onScreenSelect, SettingsScreens.PrivacyBlockedUsers);
function renderContact(contactId: number, i: number, viewportOffset: number) {
const isPrivate = isChatPrivate(contactId);
function renderContact(contactId: string, i: number, viewportOffset: number) {
const isPrivate = isUserId(contactId);
const user = isPrivate ? usersByIds[contactId] : undefined;
const chat = !isPrivate ? chatsByIds[contactId] : undefined;

View File

@ -23,8 +23,8 @@ type OwnProps = {
};
type StateProps = Partial<ApiPrivacySettings> & {
chatsById?: Record<number, ApiChat>;
usersById?: Record<number, ApiUser>;
chatsById?: Record<string, ApiChat>;
usersById?: Record<string, ApiUser>;
};
type DispatchProps = Pick<GlobalActions, 'setPrivacyVisibility'>;

View File

@ -12,7 +12,7 @@ import { pick } from '../../../util/iteratees';
import searchWords from '../../../util/searchWords';
import { getPrivacyKey } from './helper/privacy';
import {
getChatTitle, isChatGroup, isChatPrivate, prepareChatList,
getChatTitle, isChatGroup, isUserId, prepareChatList,
} from '../../../modules/helpers';
import useHistoryBack from '../../../hooks/useHistoryBack';
@ -28,12 +28,12 @@ export type OwnProps = {
};
type StateProps = {
currentUserId?: number;
chatsById: Record<number, ApiChat>;
listIds?: number[];
orderedPinnedIds?: number[];
archivedListIds?: number[];
archivedPinnedIds?: number[];
currentUserId?: string;
chatsById: Record<string, ApiChat>;
listIds?: string[];
orderedPinnedIds?: string[];
archivedListIds?: string[];
archivedPinnedIds?: string[];
settings?: ApiPrivacySettings;
};
@ -69,7 +69,7 @@ const SettingsPrivacyVisibilityExceptionList: FC<OwnProps & StateProps & Dispatc
}, [isAllowList, settings]);
const [searchQuery, setSearchQuery] = useState<string>('');
const [isSubmitShown, setIsSubmitShown] = useState<boolean>(false);
const [newSelectedContactIds, setNewSelectedContactIds] = useState<number[]>(selectedContactIds);
const [newSelectedContactIds, setNewSelectedContactIds] = useState<string[]>(selectedContactIds);
const chats = useMemo(() => {
const activeChatArrays = listIds
@ -102,7 +102,7 @@ const SettingsPrivacyVisibilityExceptionList: FC<OwnProps & StateProps & Dispatc
return chats
.filter((chat) => (
((isChatPrivate(chat.id) && chat.id !== currentUserId) || isChatGroup(chat))
((isUserId(chat.id) && chat.id !== currentUserId) || isChatGroup(chat))
&& (
!searchQuery
|| searchWords(getChatTitle(lang, chat), searchQuery)
@ -112,7 +112,7 @@ const SettingsPrivacyVisibilityExceptionList: FC<OwnProps & StateProps & Dispatc
.map(({ id }) => id);
}, [chats, currentUserId, lang, searchQuery, selectedContactIds]);
const handleSelectedContactIdsChange = useCallback((value: number[]) => {
const handleSelectedContactIdsChange = useCallback((value: string[]) => {
setNewSelectedContactIds(value);
setIsSubmitShown(true);
}, []);

View File

@ -32,11 +32,11 @@ type OwnProps = {
};
type StateProps = {
chatsById: Record<number, ApiChat>;
listIds?: number[];
orderedPinnedIds?: number[];
archivedListIds?: number[];
archivedPinnedIds?: number[];
chatsById: Record<string, ApiChat>;
listIds?: string[];
orderedPinnedIds?: string[];
archivedListIds?: string[];
archivedPinnedIds?: string[];
};
type DispatchProps = Pick<GlobalActions, 'loadMoreChats'>;
@ -101,7 +101,7 @@ const SettingsFoldersChatFilters: FC<OwnProps & StateProps & DispatchProps> = ({
});
}, [dispatch]);
const handleSelectedIdsChange = useCallback((ids: number[]) => {
const handleSelectedIdsChange = useCallback((ids: string[]) => {
if (mode === 'included') {
dispatch({
type: 'setIncludeFilters',

View File

@ -2,7 +2,7 @@ import React, {
FC, useCallback, useRef, useEffect, memo,
} from '../../../../lib/teact/teact';
import { isChatPrivate } from '../../../../modules/helpers';
import { isUserId } from '../../../../modules/helpers';
import {
INCLUDED_CHAT_TYPES,
EXCLUDED_CHAT_TYPES,
@ -25,11 +25,11 @@ import './SettingsFoldersChatsPicker.scss';
type OwnProps = {
mode: 'included' | 'excluded';
chatIds: number[];
selectedIds: number[];
chatIds: string[];
selectedIds: string[];
selectedChatTypes: string[];
filterValue?: string;
onSelectedIdsChange: (ids: number[]) => void;
onSelectedIdsChange: (ids: string[]) => void;
onSelectedChatTypesChange: (types: string[]) => void;
onFilterChange: (value: string) => void;
onLoadMore: () => void;
@ -67,7 +67,7 @@ const SettingsFoldersChatsPicker: FC<OwnProps> = ({
}, FOCUS_DELAY_MS);
}, []);
const handleItemClick = useCallback((id: number) => {
const handleItemClick = useCallback((id: string) => {
const newSelectedIds = [...selectedIds];
if (newSelectedIds.includes(id)) {
newSelectedIds.splice(newSelectedIds.indexOf(id), 1);
@ -131,7 +131,7 @@ const SettingsFoldersChatsPicker: FC<OwnProps> = ({
);
}
function renderItem(id: number) {
function renderItem(id: string) {
const isSelected = selectedIds.includes(id);
return (
@ -142,7 +142,7 @@ const SettingsFoldersChatsPicker: FC<OwnProps> = ({
ripple
disabled={!isSelected && hasMaxChats}
>
{isChatPrivate(id) ? (
{isUserId(id) ? (
<PrivateChatInfo userId={id} />
) : (
<GroupChatInfo chatId={id} withChatType />

View File

@ -8,7 +8,7 @@ import { SettingsScreens } from '../../../../types';
import { STICKER_SIZE_FOLDER_SETTINGS } from '../../../../config';
import { findIntersectionWithSet, pick } from '../../../../util/iteratees';
import { isChatPrivate } from '../../../../modules/helpers';
import { isUserId } from '../../../../modules/helpers';
import getAnimationData from '../../../common/helpers/animatedAssets';
import {
EXCLUDED_CHAT_TYPES,
@ -41,8 +41,8 @@ type OwnProps = {
};
type StateProps = {
loadedActiveChatIds?: number[];
loadedArchivedChatIds?: number[];
loadedActiveChatIds?: string[];
loadedArchivedChatIds?: string[];
};
type DispatchProps = Pick<GlobalActions, 'editChatFolder' | 'addChatFolder' | 'loadMoreChats'>;
@ -212,7 +212,7 @@ const SettingsFoldersEdit: FC<OwnProps & StateProps & DispatchProps> = ({
narrow
inactive
>
{isChatPrivate(id) ? (
{isUserId(id) ? (
<PrivateChatInfo avatarSize="small" userId={id} />
) : (
<GroupChatInfo avatarSize="small" chatId={id} />

View File

@ -30,8 +30,8 @@ type OwnProps = {
};
type StateProps = {
chatsById: Record<number, ApiChat>;
usersById: Record<number, ApiUser>;
chatsById: Record<string, ApiChat>;
usersById: Record<string, ApiUser>;
orderedFolderIds?: number[];
foldersById: Record<number, ApiChatFolder>;
recommendedChatFolders?: ApiChatFolder[];
@ -104,7 +104,7 @@ const SettingsFoldersMain: FC<OwnProps & StateProps & DispatchProps> = ({
return undefined;
}
const chatIds = Object.keys(chatsById).map(Number);
const chatIds = Object.keys(chatsById);
return orderedFolderIds.map((id) => {
const folder = foldersById[id];

View File

@ -18,12 +18,12 @@ export type OwnProps = {
};
type StateProps = {
chatsById: Record<number, ApiChat>;
pinnedIds?: number[];
activeListIds?: number[];
archivedListIds?: number[];
orderedPinnedIds?: number[];
currentUserId?: number;
chatsById: Record<string, ApiChat>;
pinnedIds?: string[];
activeListIds?: string[];
archivedListIds?: string[];
orderedPinnedIds?: string[];
currentUserId?: string;
};
type DispatchProps = Pick<GlobalActions, 'setForwardChatId' | 'exitForwardMode' | 'loadMoreChats'>;
@ -75,7 +75,7 @@ const ForwardPicker: FC<OwnProps & StateProps & DispatchProps> = ({
], chatsById, undefined, priorityIds);
}, [activeListIds, archivedListIds, chatsById, currentUserId, filter, lang, pinnedIds]);
const handleSelectUser = useCallback((userId: number) => {
const handleSelectUser = useCallback((userId: string) => {
setForwardChatId({ id: userId });
}, [setForwardChatId]);

View File

@ -74,10 +74,10 @@ import PanZoom from './PanZoom';
import './MediaViewer.scss';
type StateProps = {
chatId?: number;
chatId?: string;
threadId?: number;
messageId?: number;
senderId?: number;
senderId?: string;
origin?: MediaViewerOrigin;
avatarOwner?: ApiChat | ApiUser;
profilePhotoIndex?: number;
@ -139,7 +139,7 @@ const MediaViewer: FC<StateProps & DispatchProps> = ({
/* Animation */
const animationKey = useRef<number>();
const prevSenderId = usePrevious<number | undefined>(senderId);
const prevSenderId = usePrevious<string | undefined>(senderId);
if (isOpen && (!prevSenderId || prevSenderId !== senderId || !animationKey.current)) {
animationKey.current = selectedMediaMessageIndex;
}

View File

@ -4,7 +4,7 @@ import { withGlobal } from '../../lib/teact/teactn';
import { GlobalActions } from '../../global/types';
import { ApiChat, ApiMessage, ApiUser } from '../../api/types';
import { getSenderTitle, isChatPrivate } from '../../modules/helpers';
import { getSenderTitle, isUserId } from '../../modules/helpers';
import { formatMediaDateTime } from '../../util/dateFormat';
import renderText from '../common/helpers/renderText';
import {
@ -21,7 +21,7 @@ import Avatar from '../common/Avatar';
import './SenderInfo.scss';
type OwnProps = {
chatId?: number;
chatId?: string;
messageId?: number;
isAvatar?: boolean;
};
@ -53,15 +53,14 @@ const SenderInfo: FC<OwnProps & StateProps & DispatchProps> = ({
return undefined;
}
const isFromChat = sender.id < 0;
const senderTitle = getSenderTitle(lang, sender);
return (
<div className="SenderInfo" onClick={handleFocusMessage}>
{isFromChat ? (
<Avatar key={sender.id} size="medium" chat={sender as ApiChat} />
) : (
{isUserId(sender.id) ? (
<Avatar key={sender.id} size="medium" user={sender as ApiUser} />
) : (
<Avatar key={sender.id} size="medium" chat={sender as ApiChat} />
)}
<div className="meta">
<div className="title" dir="auto">
@ -81,7 +80,7 @@ export default withGlobal<OwnProps>(
(global, { chatId, messageId, isAvatar }): StateProps => {
if (isAvatar && chatId) {
return {
sender: isChatPrivate(chatId) ? selectUser(global, chatId) : selectChat(global, chatId),
sender: isUserId(chatId) ? selectUser(global, chatId) : selectChat(global, chatId),
};
}

View File

@ -36,11 +36,11 @@ type OwnProps = {
};
type StateProps = {
usersById: Record<number, ApiUser>;
usersById: Record<string, ApiUser>;
sender?: ApiUser | ApiChat;
targetUserIds?: number[];
targetUserIds?: string[];
targetMessage?: ApiMessage;
targetChatId?: number;
targetChatId?: string;
isFocused: boolean;
focusDirection?: FocusDirection;
noFocusHighlight?: boolean;

View File

@ -10,13 +10,14 @@ import { pick } from '../../util/iteratees';
import { selectChat } from '../../modules/selectors';
import { useIntersectionObserver } from '../../hooks/useIntersectionObserver';
import useLang from '../../hooks/useLang';
import { getUserIdDividend } from '../../modules/helpers';
import StickerButton from '../common/StickerButton';
import './ContactGreeting.scss';
type OwnProps = {
userId: number;
userId: string;
};
type StateProps = {
@ -94,7 +95,8 @@ const ContactGreeting: FC<OwnProps & StateProps & DispatchProps> = ({
export default memo(withGlobal<OwnProps>(
(global, { userId }): StateProps => {
const { stickers } = global.stickers.greeting;
const sticker = stickers?.length ? stickers[userId % stickers.length] : undefined;
const dividend = getUserIdDividend(userId) + getUserIdDividend(global.currentUserId!);
const sticker = stickers?.length ? stickers[dividend % stickers.length] : undefined;
const chat = selectChat(global, userId);
if (!chat) {
return {};
@ -111,5 +113,4 @@ export default memo(withGlobal<OwnProps>(
(setGlobal, actions): DispatchProps => pick(actions, [
'loadGreetingStickers', 'sendMessage', 'markMessageListRead',
]),
)(ContactGreeting));

View File

@ -7,7 +7,7 @@ import { GlobalActions } from '../../global/types';
import { selectCanDeleteSelectedMessages, selectCurrentChat, selectUser } from '../../modules/selectors';
import {
isChatPrivate,
isUserId,
getUserFirstOrLastName,
getPrivateChatUserId,
isChatBasicGroup,
@ -115,7 +115,7 @@ export default memo(withGlobal<OwnProps>(
const { messageIds: selectedMessageIds } = global.selectedMessages || {};
const { canDeleteForAll } = selectCanDeleteSelectedMessages(global);
const chat = selectCurrentChat(global);
const contactName = chat && isChatPrivate(chat.id)
const contactName = chat && isUserId(chat.id)
? getUserFirstOrLastName(selectUser(global, getPrivateChatUserId(chat)!))
: undefined;

View File

@ -29,7 +29,7 @@ import Button from '../ui/Button';
import HeaderMenuContainer from './HeaderMenuContainer.async';
interface OwnProps {
chatId: number;
chatId: string;
threadId: number;
messageListType: MessageListType;
}

View File

@ -14,7 +14,7 @@ import {
} from '../../modules/selectors';
import { pick } from '../../util/iteratees';
import {
isChatPrivate, getCanDeleteChat, selectIsChatMuted, getCanAddContact,
isUserId, getCanDeleteChat, selectIsChatMuted, getCanAddContact,
} from '../../modules/helpers';
import useShowTransition from '../../hooks/useShowTransition';
import useLang from '../../hooks/useLang';
@ -31,7 +31,7 @@ type DispatchProps = Pick<GlobalActions, (
)>;
export type OwnProps = {
chatId: number;
chatId: string;
threadId: number;
isOpen: boolean;
anchor: IAnchorPosition;
@ -253,7 +253,7 @@ export default memo(withGlobal<OwnProps>(
if (!chat || chat.isRestricted) {
return {};
}
const isPrivate = isChatPrivate(chat.id);
const isPrivate = isUserId(chat.id);
const user = isPrivate ? selectUser(global, chatId) : undefined;
const canAddContact = user && getCanAddContact(user);

View File

@ -28,7 +28,7 @@ import {
} from '../../modules/selectors';
import {
isChatChannel,
isChatPrivate,
isUserId,
isChatWithRepliesBot,
isChatGroup,
} from '../../modules/helpers';
@ -56,7 +56,7 @@ import NoMessages from './NoMessages';
import './MessageList.scss';
type OwnProps = {
chatId: number;
chatId: string;
threadId: number;
type: MessageListType;
canPost: boolean;
@ -447,10 +447,10 @@ const MessageList: FC<OwnProps & StateProps & DispatchProps> = ({
const lang = useLang();
const isPrivate = Boolean(chatId && isChatPrivate(chatId));
const isPrivate = Boolean(chatId && isUserId(chatId));
const withUsers = Boolean((!isPrivate && !isChannelChat) || isChatWithSelf || isRepliesChat);
const noAvatars = Boolean(!withUsers || isChannelChat);
const shouldRenderGreeting = isChatPrivate(chatId) && !isChatWithSelf && !isBot
const shouldRenderGreeting = isUserId(chatId) && !isChatWithSelf && !isBot
&& (
(
!messageGroups && !lastMessage && messageIds

View File

@ -37,7 +37,7 @@ import {
selectPinnedIds,
selectTheme,
} from '../../modules/selectors';
import { getCanPostInChat, getMessageSendingRestrictionReason, isChatPrivate } from '../../modules/helpers';
import { getCanPostInChat, getMessageSendingRestrictionReason, isUserId } from '../../modules/helpers';
import captureEscKeyListener from '../../util/captureEscKeyListener';
import { pick } from '../../util/iteratees';
import buildClassName from '../../util/buildClassName';
@ -64,7 +64,7 @@ import ReceiptModal from '../payment/ReceiptModal.async';
import './MiddleColumn.scss';
type StateProps = {
chatId?: number;
chatId?: string;
threadId?: number;
messageListType?: MessageListType;
isPrivate?: boolean;
@ -477,7 +477,7 @@ export default memo(withGlobal(
chatId,
threadId,
messageListType,
isPrivate: isChatPrivate(chatId),
isPrivate: isUserId(chatId),
canPost: !isPinnedMessageList && (!chat || canPost) && !isBotNotStarted,
isPinnedMessageList,
isScheduledMessageList,

View File

@ -23,7 +23,7 @@ import {
} from '../../config';
import { IS_SINGLE_COLUMN_LAYOUT, IS_TABLET_COLUMN_LAYOUT } from '../../util/environment';
import {
isChatPrivate,
isUserId,
getMessageKey,
getChatTitle,
getSenderTitle,
@ -68,7 +68,7 @@ const ANIMATION_DURATION = 350;
const BACK_BUTTON_INACTIVE_TIME = 450;
type OwnProps = {
chatId: number;
chatId: string;
threadId: number;
messageListType: MessageListType;
isReady?: boolean;
@ -85,7 +85,7 @@ type StateProps = {
isLeftColumnShown?: boolean;
isRightColumnShown?: boolean;
audioMessage?: ApiMessage;
chatsById?: Record<number, ApiChat>;
chatsById?: Record<string, ApiChat>;
messagesCount?: number;
isChatWithSelf?: boolean;
isChatWithBot?: boolean;
@ -348,7 +348,7 @@ const MiddleHeader: FC<OwnProps & StateProps & DispatchProps> = ({
<>
{(isLeftColumnHideable || currentTransitionKey > 0) && renderBackButton(shouldShowCloseButton, true)}
<div className="chat-info-wrapper" onClick={handleHeaderClick}>
{isChatPrivate(chatId) ? (
{isUserId(chatId) ? (
<PrivateChatInfo
userId={chatId}
typingStatus={typingStatus}

View File

@ -7,7 +7,7 @@ import useLang, { LangFn } from '../../hooks/useLang';
import './NoMessages.scss';
type OwnProps = {
chatId: number;
chatId: string;
isChatWithSelf?: boolean;
type: MessageListType;
isGroupChatJustCreated?: boolean;

View File

@ -31,9 +31,9 @@ export type OwnProps = {
attachments: ApiAttachment[];
caption: string;
isReady?: boolean;
currentUserId?: number;
currentUserId?: string;
groupChatMembers?: ApiChatMember[];
usersById?: Record<number, ApiUser>;
usersById?: Record<string, ApiUser>;
recentEmojis: string[];
baseEmojiKeywords?: Record<string, string[]>;
emojiKeywords?: Record<string, string[]>;

View File

@ -26,7 +26,7 @@ export type OwnProps = {
};
type StateProps = {
usersById: Record<number, ApiUser>;
usersById: Record<string, ApiUser>;
};
type DispatchProps = Pick<GlobalActions, 'sendBotCommand'>;

View File

@ -41,7 +41,7 @@ import {
import {
getAllowedAttachmentOptions,
getChatSlowModeOptions,
isChatPrivate,
isUserId,
isChatAdmin,
} from '../../../modules/helpers';
import { formatMediaDuration, formatVoiceRecordDuration, getDayStartAt } from '../../../util/dateFormat';
@ -98,7 +98,7 @@ import CalendarModal from '../../common/CalendarModal.async';
import './Composer.scss';
type OwnProps = {
chatId: number;
chatId: string;
threadId: number;
messageListType: MessageListType;
dropAreaState: string;
@ -123,8 +123,8 @@ type StateProps = {
canScheduleUntilOnline?: boolean;
stickersForEmoji?: ApiSticker[];
groupChatMembers?: ApiChatMember[];
currentUserId?: number;
usersById?: Record<number, ApiUser>;
currentUserId?: string;
usersById?: Record<string, ApiUser>;
recentEmojis: string[];
lastSyncTime?: number;
contentToBeScheduled?: GlobalState['messages']['contentToBeScheduled'];
@ -132,7 +132,7 @@ type StateProps = {
baseEmojiKeywords?: Record<string, string[]>;
emojiKeywords?: Record<string, string[]>;
serverTimeOffset: number;
topInlineBotIds?: number[];
topInlineBotIds?: string[];
isInlineBotLoading: boolean;
inlineBots?: Record<string, false | InlineBotSettings>;
botCommands?: ApiBotCommand[] | false;
@ -1069,7 +1069,7 @@ export default memo(withGlobal<OwnProps>(
isChatWithSelf,
canScheduleUntilOnline: (
!isChatWithSelf && !isChatWithBot
&& (chat && chatUser && isChatPrivate(chatId) && chatUser.status && Boolean(chatUser.status.wasOnline))
&& (chat && chatUser && isUserId(chatId) && chatUser.status && Boolean(chatUser.status.wasOnline))
),
isRightColumnShown: selectIsRightColumnShown(global),
isSelectModeActive: selectIsInSelectMode(global),

View File

@ -23,7 +23,7 @@ import { pick } from '../../../util/iteratees';
import useAsyncRendering from '../../right/hooks/useAsyncRendering';
import useShowTransition from '../../../hooks/useShowTransition';
import buildClassName from '../../../util/buildClassName';
import { isChatPrivate } from '../../../modules/helpers';
import { isUserId } from '../../../modules/helpers';
import Button from '../../ui/Button';
import EmbeddedMessage from '../../common/EmbeddedMessage';
@ -154,7 +154,7 @@ export default memo(withGlobal(
sender = selectSender(global, message);
}
} else if (isForwarding) {
sender = isChatPrivate(fromChatId!) ? selectUser(global, fromChatId!) : selectChat(global, fromChatId!);
sender = isUserId(fromChatId!) ? selectUser(global, fromChatId!) : selectChat(global, fromChatId!);
}
return {

View File

@ -32,7 +32,7 @@ const runThrottled = throttle((cb) => cb(), 500, true);
export type OwnProps = {
isOpen: boolean;
botId?: number;
botId?: string;
isGallery?: boolean;
allowedAttachmentOptions: IAllowedAttachmentOptions;
inlineBotResults?: (ApiBotInlineResult | ApiBotInlineMediaResult)[];

View File

@ -20,7 +20,7 @@ export type OwnProps = {
onClose: () => void;
onInsertUserName: (user: ApiUser, forceFocus?: boolean) => void;
filteredUsers?: ApiUser[];
usersById?: Record<number, ApiUser>;
usersById?: Record<string, ApiUser>;
};
const MentionTooltip: FC<OwnProps> = ({
@ -34,7 +34,7 @@ const MentionTooltip: FC<OwnProps> = ({
const containerRef = useRef<HTMLDivElement>(null);
const { shouldRender, transitionClassNames } = useShowTransition(isOpen, undefined, undefined, false);
const handleUserSelect = useCallback((userId: number, forceFocus = false) => {
const handleUserSelect = useCallback((userId: string, forceFocus = false) => {
const user = usersById?.[userId];
if (!user) {
return;

View File

@ -47,7 +47,7 @@ type OwnProps = {
};
type StateProps = {
currentChatId?: number;
currentChatId?: string;
replyingToId?: number;
noTabCapture?: boolean;
messageSendKeyCombo?: ISettings['messageSendKeyCombo'];

View File

@ -22,7 +22,7 @@ import Button from '../../ui/Button';
import './WebPagePreview.scss';
type OwnProps = {
chatId: number;
chatId: string;
threadId: number;
messageText: string;
disabled?: boolean;

View File

@ -14,12 +14,12 @@ import useBeforeUnload from '../../../../hooks/useBeforeUnload';
import { IS_TOUCH_ENV } from '../../../../util/environment';
// Used to avoid running debounced callbacks when chat changes.
let currentChatId: number | undefined;
let currentChatId: string | undefined;
let currentThreadId: number | undefined;
export default (
draft: ApiFormattedText | undefined,
chatId: number,
chatId: string,
threadId: number,
html: string,
htmlRef: { current: string },
@ -28,7 +28,7 @@ export default (
saveDraft: GlobalActions['saveDraft'],
clearDraft: GlobalActions['clearDraft'],
) => {
const updateDraft = useCallback((draftChatId: number, draftThreadId: number) => {
const updateDraft = useCallback((draftChatId: string, draftThreadId: number) => {
if (htmlRef.current.length && !editedMessage) {
saveDraft({ chatId: draftChatId, threadId: draftThreadId, draft: parseMessageInput(htmlRef.current!) });
} else {

View File

@ -10,7 +10,7 @@ const HAS_NEW_LINE = /^@([a-z0-9_]{1,32})[\u00A0\u0020]+\n{2,}/i;
export default function useInlineBotTooltip(
isAllowed: boolean,
chatId: number,
chatId: string,
html: string,
inlineBots?: Record<string, false | InlineBotSettings>,
) {

View File

@ -28,9 +28,9 @@ export default function useMentionTooltip(
onUpdateHtml: (html: string) => void,
inputId: string = EDITABLE_INPUT_ID,
groupChatMembers?: ApiChatMember[],
topInlineBotIds?: number[],
currentUserId?: number,
usersById?: Record<number, ApiUser>,
topInlineBotIds?: string[],
currentUserId?: string,
usersById?: Record<string, ApiUser>,
) {
const [isOpen, markIsOpen, unmarkIsOpen] = useFlag();
const [usersToMention, setUsersToMention] = useState<ApiUser[] | undefined>();

Some files were not shown because too many files have changed in this diff Show More