Composer: Support guest bot mentions (#6961)
This commit is contained in:
parent
37c3156493
commit
fb5a7cfb5a
@ -211,7 +211,7 @@ export function buildApiUrlAuthResult(result: GramJs.TypeUrlAuthResult): ApiUrlA
|
||||
export function buildApiConfig(config: GramJs.Config): ApiConfig {
|
||||
const {
|
||||
testMode, expires, gifSearchUsername, chatSizeMax, autologinToken, reactionsDefault,
|
||||
messageLengthMax, editTimeLimit, forwardedCountMax,
|
||||
messageLengthMax, editTimeLimit, forwardedCountMax, ratingEDecay,
|
||||
} = config;
|
||||
const defaultReaction = reactionsDefault && buildApiReaction(reactionsDefault);
|
||||
return {
|
||||
@ -224,6 +224,7 @@ export function buildApiConfig(config: GramJs.Config): ApiConfig {
|
||||
maxMessageLength: messageLengthMax,
|
||||
editTimeLimit,
|
||||
maxForwardedCount: forwardedCountMax,
|
||||
ratingEDecay,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -23,7 +23,6 @@ import {
|
||||
buildBotSwitchPm,
|
||||
buildBotSwitchWebview,
|
||||
} from '../apiBuilders/bots';
|
||||
import { buildApiChatFromPreview } from '../apiBuilders/chats';
|
||||
import { omitVirtualClassFields } from '../apiBuilders/helpers';
|
||||
import { buildMessageMediaContent } from '../apiBuilders/messageContent';
|
||||
import { buildApiUrlAuthResult } from '../apiBuilders/misc';
|
||||
@ -39,7 +38,6 @@ import {
|
||||
import {
|
||||
addDocumentToLocalDb,
|
||||
addPhotoToLocalDb,
|
||||
addUserToLocalDb,
|
||||
addWebDocumentToLocalDb,
|
||||
} from '../helpers/localDb';
|
||||
import { deserializeBytes } from '../helpers/misc';
|
||||
@ -61,68 +59,6 @@ export async function answerCallbackButton({
|
||||
return result ? omitVirtualClassFields(result) : undefined;
|
||||
}
|
||||
|
||||
export async function fetchTopInlineBots() {
|
||||
const topPeers = await invokeRequest(new GramJs.contacts.GetTopPeers({
|
||||
botsInline: true,
|
||||
limit: DEFAULT_PRIMITIVES.INT,
|
||||
offset: DEFAULT_PRIMITIVES.INT,
|
||||
hash: DEFAULT_PRIMITIVES.BIGINT,
|
||||
}));
|
||||
|
||||
if (!(topPeers instanceof GramJs.contacts.TopPeers)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const users = topPeers.users.map(buildApiUser).filter(Boolean);
|
||||
const ids = users.map(({ id }) => id);
|
||||
|
||||
return {
|
||||
ids,
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchTopBotApps() {
|
||||
const topPeers = await invokeRequest(new GramJs.contacts.GetTopPeers({
|
||||
botsApp: true,
|
||||
limit: DEFAULT_PRIMITIVES.INT,
|
||||
offset: DEFAULT_PRIMITIVES.INT,
|
||||
hash: DEFAULT_PRIMITIVES.BIGINT,
|
||||
}));
|
||||
|
||||
if (!(topPeers instanceof GramJs.contacts.TopPeers)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const users = topPeers.users.map(buildApiUser).filter(Boolean);
|
||||
const ids = users.map(({ id }) => id);
|
||||
|
||||
return {
|
||||
ids,
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchInlineBot({ username }: { username: string }) {
|
||||
const resolvedPeer = await invokeRequest(new GramJs.contacts.ResolveUsername({ username }));
|
||||
|
||||
if (
|
||||
!resolvedPeer
|
||||
|| !(
|
||||
resolvedPeer.users[0] instanceof GramJs.User
|
||||
&& resolvedPeer.users[0].bot
|
||||
&& resolvedPeer.users[0].botInlinePlaceholder
|
||||
)
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
addUserToLocalDb(resolvedPeer.users[0]);
|
||||
|
||||
return {
|
||||
user: buildApiUser(resolvedPeer.users[0]),
|
||||
chat: buildApiChatFromPreview(resolvedPeer.users[0]),
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchInlineBotResults({
|
||||
bot, chat, query, offset = DEFAULT_PRIMITIVES.STRING,
|
||||
}: {
|
||||
|
||||
@ -21,6 +21,8 @@ export * from './messages';
|
||||
|
||||
export * from './users';
|
||||
|
||||
export * from './topPeers';
|
||||
|
||||
export * from './symbols';
|
||||
|
||||
export * from './management';
|
||||
|
||||
103
src/api/gramjs/methods/topPeers.ts
Normal file
103
src/api/gramjs/methods/topPeers.ts
Normal file
@ -0,0 +1,103 @@
|
||||
import { Api as GramJs } from '../../../lib/gramjs';
|
||||
|
||||
import type {
|
||||
ApiPeer,
|
||||
ApiTopPeer,
|
||||
ApiTopPeerCategory,
|
||||
ApiTopPeersResult,
|
||||
} from '../../types';
|
||||
|
||||
import { getApiChatIdFromMtpPeer } from '../apiBuilders/peers';
|
||||
import { buildInputPeer, DEFAULT_PRIMITIVES } from '../gramjsBuilders';
|
||||
import { addChatToLocalDb, addUserToLocalDb } from '../helpers/localDb';
|
||||
import { invokeRequest } from './client';
|
||||
|
||||
const TOP_PEER_LIMIT = 50;
|
||||
|
||||
export async function fetchTopPeers({
|
||||
category,
|
||||
}: {
|
||||
category: ApiTopPeerCategory;
|
||||
}): Promise<ApiTopPeersResult | undefined> {
|
||||
const result = await invokeRequest(new GramJs.contacts.GetTopPeers({
|
||||
correspondents: category === 'correspondents' || undefined,
|
||||
botsInline: category === 'botsInline' || undefined,
|
||||
botsApp: category === 'botsApp' || undefined,
|
||||
botsGuestchat: category === 'botsGuestChat' || undefined,
|
||||
offset: DEFAULT_PRIMITIVES.INT,
|
||||
limit: TOP_PEER_LIMIT,
|
||||
hash: DEFAULT_PRIMITIVES.BIGINT,
|
||||
}));
|
||||
|
||||
if (result instanceof GramJs.contacts.TopPeersNotModified) {
|
||||
return { type: 'unchanged' };
|
||||
}
|
||||
|
||||
if (result instanceof GramJs.contacts.TopPeersDisabled) {
|
||||
return { type: 'disabled' };
|
||||
}
|
||||
|
||||
if (!(result instanceof GramJs.contacts.TopPeers)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
result.users.forEach(addUserToLocalDb);
|
||||
result.chats.forEach((chat) => {
|
||||
if (chat instanceof GramJs.Chat || chat instanceof GramJs.Channel) {
|
||||
addChatToLocalDb(chat);
|
||||
}
|
||||
});
|
||||
|
||||
const topPeerCategory = result.categories.find(({ category: mtpCategory }) => {
|
||||
return getTopPeerCategory(mtpCategory) === category;
|
||||
});
|
||||
|
||||
const topPeers: ApiTopPeer[] = topPeerCategory
|
||||
? topPeerCategory.peers.map(({ peer, rating }) => ({
|
||||
peerId: getApiChatIdFromMtpPeer(peer),
|
||||
rating,
|
||||
})) : [];
|
||||
|
||||
return {
|
||||
type: 'topPeers',
|
||||
category,
|
||||
topPeers,
|
||||
};
|
||||
}
|
||||
|
||||
export function resetTopPeerRating({ category, peer }: { category: ApiTopPeerCategory; peer: ApiPeer }) {
|
||||
return invokeRequest(new GramJs.contacts.ResetTopPeerRating({
|
||||
category: buildTopPeerCategory(category),
|
||||
peer: buildInputPeer(peer.id, peer.accessHash),
|
||||
}));
|
||||
}
|
||||
|
||||
function getTopPeerCategory(category: GramJs.TypeTopPeerCategory): ApiTopPeerCategory | undefined {
|
||||
if (category instanceof GramJs.TopPeerCategoryCorrespondents) {
|
||||
return 'correspondents';
|
||||
}
|
||||
if (category instanceof GramJs.TopPeerCategoryBotsInline) {
|
||||
return 'botsInline';
|
||||
}
|
||||
if (category instanceof GramJs.TopPeerCategoryBotsApp) {
|
||||
return 'botsApp';
|
||||
}
|
||||
if (category instanceof GramJs.TopPeerCategoryBotsGuestChat) {
|
||||
return 'botsGuestChat';
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function buildTopPeerCategory(category: ApiTopPeerCategory): GramJs.TypeTopPeerCategory {
|
||||
switch (category) {
|
||||
case 'correspondents':
|
||||
return new GramJs.TopPeerCategoryCorrespondents();
|
||||
case 'botsInline':
|
||||
return new GramJs.TopPeerCategoryBotsInline();
|
||||
case 'botsApp':
|
||||
return new GramJs.TopPeerCategoryBotsApp();
|
||||
case 'botsGuestChat':
|
||||
return new GramJs.TopPeerCategoryBotsGuestChat();
|
||||
}
|
||||
}
|
||||
@ -132,25 +132,6 @@ export async function fetchNearestCountry() {
|
||||
return dcInfo?.country;
|
||||
}
|
||||
|
||||
export async function fetchTopUsers() {
|
||||
const topPeers = await invokeRequest(new GramJs.contacts.GetTopPeers({
|
||||
correspondents: true,
|
||||
offset: DEFAULT_PRIMITIVES.INT,
|
||||
limit: DEFAULT_PRIMITIVES.INT,
|
||||
hash: DEFAULT_PRIMITIVES.BIGINT,
|
||||
}));
|
||||
if (!(topPeers instanceof GramJs.contacts.TopPeers)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const users = topPeers.users.map(buildApiUser).filter((user): user is ApiUser => Boolean(user) && !user.isSelf);
|
||||
const ids = users.map(({ id }) => id);
|
||||
|
||||
return {
|
||||
ids,
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchContactList() {
|
||||
const result = await invokeRequest(new GramJs.contacts.GetContacts({ hash: DEFAULT_PRIMITIVES.BIGINT }));
|
||||
if (!result || result instanceof GramJs.contacts.ContactsNotModified) {
|
||||
|
||||
@ -351,8 +351,26 @@ export interface ApiConfig {
|
||||
maxMessageLength: number;
|
||||
editTimeLimit: number;
|
||||
maxForwardedCount: number;
|
||||
ratingEDecay: number;
|
||||
}
|
||||
|
||||
export type ApiTopPeerCategory = 'correspondents' | 'botsInline' | 'botsApp' | 'botsGuestChat';
|
||||
|
||||
export type ApiTopPeer = {
|
||||
peerId: string;
|
||||
rating: number;
|
||||
};
|
||||
|
||||
export type ApiTopPeersResult = {
|
||||
type: 'topPeers';
|
||||
category: ApiTopPeerCategory;
|
||||
topPeers: ApiTopPeer[];
|
||||
} | {
|
||||
type: 'unchanged';
|
||||
} | {
|
||||
type: 'disabled';
|
||||
};
|
||||
|
||||
export interface ApiPromoData {
|
||||
expires: number;
|
||||
pendingSuggestions: string[];
|
||||
|
||||
@ -67,6 +67,7 @@ import {
|
||||
isChatSuperGroup,
|
||||
isSameReaction,
|
||||
isSystemBot,
|
||||
isUserRightBanned,
|
||||
} from '../../global/helpers';
|
||||
import { getChatNotifySettings } from '../../global/helpers/notifications';
|
||||
import { getPeerTitle } from '../../global/helpers/peers';
|
||||
@ -269,6 +270,7 @@ type StateProps = {
|
||||
baseEmojiKeywords?: Record<string, string[]>;
|
||||
emojiKeywords?: Record<string, string[]>;
|
||||
topInlineBotIds?: string[];
|
||||
topGuestBotIds?: string[];
|
||||
isInlineBotLoading: boolean;
|
||||
inlineBots?: Record<string, false | InlineBotSettings>;
|
||||
botCommands?: ApiBotCommand[] | false;
|
||||
@ -387,6 +389,7 @@ const Composer = ({
|
||||
stickersForEmoji,
|
||||
customEmojiForEmoji,
|
||||
topInlineBotIds,
|
||||
topGuestBotIds,
|
||||
currentUserId,
|
||||
currentUser,
|
||||
captionLimit,
|
||||
@ -591,6 +594,7 @@ const Composer = ({
|
||||
),
|
||||
[chat, chatFullInfo, isChatWithBot, isChatWithSelf, isInStoryViewer, paidMessagesStars, isInScheduledList],
|
||||
);
|
||||
const canUseInlineBots = !chat || isChatAdmin(chat) || !isUserRightBanned(chat, 'sendInline', chatFullInfo);
|
||||
|
||||
const isNeedPremium = isContactRequirePremium && isInStoryViewer;
|
||||
const isSendTextBlocked = isNeedPremium || !canSendPlainText;
|
||||
@ -844,7 +848,8 @@ const Composer = ({
|
||||
getSelectionRange,
|
||||
inputRef,
|
||||
groupChatMembers,
|
||||
topInlineBotIds,
|
||||
canUseInlineBots ? topInlineBotIds : undefined,
|
||||
topGuestBotIds,
|
||||
currentUserId,
|
||||
);
|
||||
|
||||
@ -887,7 +892,7 @@ const Composer = ({
|
||||
help: inlineBotHelp,
|
||||
loadMore: loadMoreForInlineBot,
|
||||
} = useInlineBotTooltip(
|
||||
Boolean(isInMessageList && isReady && isForCurrentMessageList && !hasAttachments),
|
||||
Boolean(canUseInlineBots && isInMessageList && isReady && isForCurrentMessageList && !hasAttachments),
|
||||
chatId,
|
||||
getHtml,
|
||||
inlineBots,
|
||||
@ -1595,7 +1600,7 @@ const Composer = ({
|
||||
const handleInlineBotSelect = useLastCallback((
|
||||
inlineResult: ApiBotInlineResult | ApiBotInlineMediaResult, isSilent?: boolean, isScheduleRequested?: boolean,
|
||||
) => {
|
||||
if (!currentMessageList && !storyId) {
|
||||
if ((!currentMessageList && !storyId) || !inlineBotId) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2786,7 +2791,8 @@ export default memo(withGlobal<OwnProps>(
|
||||
stickersForEmoji: global.stickers.forEmoji.stickers,
|
||||
customEmojiForEmoji: global.customEmojis.forEmoji.stickers,
|
||||
chatFullInfo,
|
||||
topInlineBotIds: global.topInlineBots?.userIds,
|
||||
topInlineBotIds: global.topPeerCategories.botsInline?.peerIds,
|
||||
topGuestBotIds: global.topPeerCategories.botsGuestChat?.peerIds,
|
||||
currentUserId,
|
||||
currentUser,
|
||||
contentToBeScheduled: tabState.contentToBeScheduled,
|
||||
|
||||
@ -152,6 +152,6 @@ export default memo(withGlobal<OwnProps>((global): Complete<StateProps> => {
|
||||
return {
|
||||
isLoading: !foundIds && globalSearch.fetchingStatus?.botApps,
|
||||
foundIds,
|
||||
recentBotIds: global.topBotApps.userIds,
|
||||
recentBotIds: global.topPeerCategories.botsApp?.peerIds,
|
||||
};
|
||||
})(BotAppResults));
|
||||
|
||||
@ -1,19 +1,20 @@
|
||||
import type { FC } from '../../../lib/teact/teact';
|
||||
import {
|
||||
memo,
|
||||
useCallback, useEffect, useRef,
|
||||
} from '../../../lib/teact/teact';
|
||||
import { getActions, withGlobal } from '../../../global';
|
||||
|
||||
import type { ApiUser } from '../../../api/types';
|
||||
import type { GlobalState } from '../../../global/types';
|
||||
|
||||
import { getUserFirstOrLastName } from '../../../global/helpers';
|
||||
import { getPeerTitle } from '../../../global/helpers/peers';
|
||||
import { selectPeer } from '../../../global/selectors';
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
import { throttle } from '../../../util/schedulers';
|
||||
import renderText from '../../common/helpers/renderText';
|
||||
|
||||
import { useShallowSelector } from '../../../hooks/data/useSelector';
|
||||
import useHorizontalScroll from '../../../hooks/useHorizontalScroll';
|
||||
import useOldLang from '../../../hooks/useOldLang';
|
||||
import useLang from '../../../hooks/useLang';
|
||||
|
||||
import Avatar from '../../common/Avatar';
|
||||
import Button from '../../ui/Button';
|
||||
@ -26,8 +27,7 @@ type OwnProps = {
|
||||
};
|
||||
|
||||
type StateProps = {
|
||||
topUserIds?: string[];
|
||||
usersById: Record<string, ApiUser>;
|
||||
topPeerIds?: string[];
|
||||
recentlyFoundChatIds?: string[];
|
||||
};
|
||||
|
||||
@ -36,28 +36,33 @@ const NBSP = '\u00A0';
|
||||
|
||||
const runThrottled = throttle((cb) => cb(), 60000, true);
|
||||
|
||||
const RecentContacts: FC<OwnProps & StateProps> = ({
|
||||
topUserIds,
|
||||
usersById,
|
||||
const RecentContacts = ({
|
||||
topPeerIds,
|
||||
recentlyFoundChatIds,
|
||||
onReset,
|
||||
}) => {
|
||||
}: OwnProps & StateProps) => {
|
||||
const {
|
||||
loadTopUsers, openChat,
|
||||
loadTopPeers, openChat,
|
||||
addRecentlyFoundChatId, clearRecentlyFoundChats,
|
||||
} = getActions();
|
||||
|
||||
const topUsersRef = useRef<HTMLDivElement>();
|
||||
const topPeersRef = useRef<HTMLDivElement>();
|
||||
|
||||
// Due to the parent Transition, this component never gets unmounted,
|
||||
// that's why we use throttled API call on every update.
|
||||
useEffect(() => {
|
||||
runThrottled(() => {
|
||||
loadTopUsers();
|
||||
loadTopPeers({ category: 'correspondents' });
|
||||
});
|
||||
}, [loadTopUsers]);
|
||||
}, [loadTopPeers]);
|
||||
|
||||
useHorizontalScroll(topUsersRef, !topUserIds);
|
||||
const topPeersSelector = useCallback((global: GlobalState) => {
|
||||
return topPeerIds?.map((peerId) => selectPeer(global, peerId)).filter(Boolean);
|
||||
}, [topPeerIds]);
|
||||
const topPeers = useShallowSelector(topPeersSelector);
|
||||
const shouldRenderTopPeers = Boolean(topPeers?.length);
|
||||
|
||||
useHorizontalScroll(topPeersRef, !shouldRenderTopPeers);
|
||||
|
||||
const handleClick = useCallback((id: string) => {
|
||||
openChat({ id, shouldReplaceHistory: true });
|
||||
@ -71,22 +76,22 @@ const RecentContacts: FC<OwnProps & StateProps> = ({
|
||||
clearRecentlyFoundChats();
|
||||
}, [clearRecentlyFoundChats]);
|
||||
|
||||
const lang = useOldLang();
|
||||
const lang = useLang();
|
||||
|
||||
return (
|
||||
<div className="RecentContacts custom-scroll">
|
||||
{topUserIds && (
|
||||
{shouldRenderTopPeers && (
|
||||
<div className="top-peers-section" dir={lang.isRtl ? 'rtl' : undefined}>
|
||||
<div ref={topUsersRef} className="top-peers">
|
||||
{topUserIds.map((userId) => (
|
||||
<div ref={topPeersRef} className="top-peers">
|
||||
{topPeers?.map((peer) => (
|
||||
<div
|
||||
key={userId}
|
||||
key={peer.id}
|
||||
className="top-peer-item"
|
||||
onClick={() => handleClick(userId)}
|
||||
onClick={() => handleClick(peer.id)}
|
||||
dir={lang.isRtl ? 'rtl' : undefined}
|
||||
>
|
||||
<Avatar peer={usersById[userId]} />
|
||||
<div className="top-peer-name">{renderText(getUserFirstOrLastName(usersById[userId]) || NBSP)}</div>
|
||||
<Avatar peer={peer} />
|
||||
<div className="top-peer-name">{renderText(getPeerTitle(lang, peer) || NBSP)}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
@ -97,7 +102,7 @@ const RecentContacts: FC<OwnProps & StateProps> = ({
|
||||
<h3
|
||||
className={buildClassName(
|
||||
'section-heading mt-0 recent-chats-header',
|
||||
!topUserIds && 'without-border',
|
||||
!shouldRenderTopPeers && 'without-border',
|
||||
)}
|
||||
dir={lang.isRtl ? 'rtl' : undefined}
|
||||
>
|
||||
@ -129,13 +134,11 @@ const RecentContacts: FC<OwnProps & StateProps> = ({
|
||||
|
||||
export default memo(withGlobal<OwnProps>(
|
||||
(global): Complete<StateProps> => {
|
||||
const { userIds: topUserIds } = global.topPeers;
|
||||
const usersById = global.users.byId;
|
||||
const topPeerIds = global.topPeerCategories.correspondents?.peerIds;
|
||||
const { recentlyFoundChatIds } = global;
|
||||
|
||||
return {
|
||||
topUserIds,
|
||||
usersById,
|
||||
topPeerIds,
|
||||
recentlyFoundChatIds,
|
||||
};
|
||||
},
|
||||
|
||||
@ -213,7 +213,7 @@ const Main = ({
|
||||
loadNotificationExceptions,
|
||||
updateIsOnline,
|
||||
onTabFocusChange,
|
||||
loadTopInlineBots,
|
||||
loadTopPeers,
|
||||
loadEmojiKeywords,
|
||||
loadCountryList,
|
||||
loadAvailableReactions,
|
||||
@ -257,7 +257,6 @@ const Main = ({
|
||||
loadQuickReplies,
|
||||
loadStarStatus,
|
||||
loadAvailableEffects,
|
||||
loadTopBotApps,
|
||||
loadPaidReactionPrivacy,
|
||||
loadPasswordInfo,
|
||||
loadBotFreezeAppeal,
|
||||
@ -327,13 +326,14 @@ const Main = ({
|
||||
loadAttachBots();
|
||||
loadNotificationSettings();
|
||||
loadNotificationExceptions();
|
||||
loadTopInlineBots();
|
||||
loadTopPeers({ category: 'botsInline' });
|
||||
loadTopReactions();
|
||||
loadStarStatus();
|
||||
loadEmojiKeywords({ language: BASE_EMOJI_KEYWORD_LANG });
|
||||
loadFeaturedEmojiStickers();
|
||||
loadSavedReactionTags();
|
||||
loadTopBotApps();
|
||||
loadTopPeers({ category: 'botsApp' });
|
||||
loadTopPeers({ category: 'botsGuestChat' });
|
||||
loadPaidReactionPrivacy();
|
||||
loadDefaultTopicIcons();
|
||||
loadAnimatedEmojis();
|
||||
|
||||
@ -103,6 +103,7 @@ type StateProps = {
|
||||
emojiKeywords?: Record<string, string[]>;
|
||||
shouldSuggestCustomEmoji?: boolean;
|
||||
customEmojiForEmoji?: ApiSticker[];
|
||||
topGuestBotIds?: string[];
|
||||
captionLimit: number;
|
||||
attachmentSettings: GlobalState['attachmentSettings'];
|
||||
shouldSaveAttachmentsCompression?: boolean;
|
||||
@ -127,6 +128,7 @@ const AttachmentModal = ({
|
||||
isChatWithSelf,
|
||||
currentUserId,
|
||||
groupChatMembers,
|
||||
topGuestBotIds,
|
||||
recentEmojis,
|
||||
baseEmojiKeywords,
|
||||
emojiKeywords,
|
||||
@ -283,6 +285,7 @@ const AttachmentModal = ({
|
||||
inputRef,
|
||||
groupChatMembers,
|
||||
undefined,
|
||||
topGuestBotIds,
|
||||
currentUserId,
|
||||
);
|
||||
|
||||
@ -944,6 +947,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
isChatWithSelf,
|
||||
currentUserId,
|
||||
groupChatMembers: chatFullInfo?.members,
|
||||
topGuestBotIds: global.topPeerCategories.botsGuestChat?.peerIds,
|
||||
recentEmojis,
|
||||
baseEmojiKeywords: baseEmojiKeywords?.keywords,
|
||||
emojiKeywords: emojiKeywords?.keywords,
|
||||
|
||||
@ -39,6 +39,7 @@ export default function useMentionTooltip(
|
||||
inputRef: ElementRef<HTMLDivElement>,
|
||||
groupChatMembers?: ApiChatMember[],
|
||||
topInlineBotIds?: string[],
|
||||
topGuestBotIds?: string[],
|
||||
currentUserId?: string,
|
||||
) {
|
||||
const lang = useLang();
|
||||
@ -65,7 +66,7 @@ export default function useMentionTooltip(
|
||||
useEffect(() => {
|
||||
const usernameTag = getUsernameTag();
|
||||
|
||||
if (!usernameTag || !(groupChatMembers || topInlineBotIds)) {
|
||||
if (!usernameTag || !(groupChatMembers || topInlineBotIds || topGuestBotIds)) {
|
||||
setFilteredUsers(undefined);
|
||||
return;
|
||||
}
|
||||
@ -90,13 +91,14 @@ export default function useMentionTooltip(
|
||||
ids: unique([
|
||||
...((getWithInlineBots() && topInlineBotIds) || []),
|
||||
...(memberIds || []),
|
||||
...(topGuestBotIds || []),
|
||||
]),
|
||||
query: filter,
|
||||
type: 'user',
|
||||
});
|
||||
|
||||
setFilteredUsers(Object.values(pickTruthy(usersById, filteredIds)));
|
||||
}, [currentUserId, groupChatMembers, topInlineBotIds, getUsernameTag, getWithInlineBots]);
|
||||
}, [currentUserId, groupChatMembers, topInlineBotIds, topGuestBotIds, getUsernameTag, getWithInlineBots]);
|
||||
|
||||
const insertMention = useLastCallback((
|
||||
peer: ApiPeer,
|
||||
|
||||
@ -133,6 +133,6 @@ export default memo(withGlobal((global): Complete<StateProps> => {
|
||||
return {
|
||||
isLoading: !foundIds && globalSearch.fetchingStatus?.botApps,
|
||||
foundIds,
|
||||
recentBotIds: global.topBotApps.userIds,
|
||||
recentBotIds: global.topPeerCategories.botsApp?.peerIds,
|
||||
};
|
||||
})(MoreAppsTabContent));
|
||||
|
||||
@ -9,6 +9,7 @@ import './api/sync';
|
||||
import './api/accounts';
|
||||
import './api/ai';
|
||||
import './api/users';
|
||||
import './api/topPeers';
|
||||
import './api/bots';
|
||||
import './api/settings';
|
||||
import './api/twoFaSettings';
|
||||
|
||||
@ -23,12 +23,14 @@ import { formatStarsAsText } from '../../../util/localization/format';
|
||||
import { oldTranslate } from '../../../util/oldLangProvider';
|
||||
import requestActionTimeout from '../../../util/requestActionTimeout';
|
||||
import { debounce } from '../../../util/schedulers';
|
||||
import { getServerTime } from '../../../util/serverTime';
|
||||
import { extractCurrentThemeParams } from '../../../util/themeStyle';
|
||||
import { callApi } from '../../../api/gramjs';
|
||||
import {
|
||||
getMainUsername,
|
||||
getWebAppKey,
|
||||
isChatAdmin,
|
||||
isUserBot,
|
||||
isUserRightBanned,
|
||||
prepareMessageReplyInfo,
|
||||
} from '../../helpers';
|
||||
import {
|
||||
@ -52,6 +54,7 @@ import { updateTabState } from '../../reducers/tabs';
|
||||
import {
|
||||
selectBot,
|
||||
selectChat,
|
||||
selectChatFullInfo,
|
||||
selectChatLastMessageId,
|
||||
selectChatMessage,
|
||||
selectCurrentChat,
|
||||
@ -73,10 +76,13 @@ import { getPeerStarsForMessage } from './messages';
|
||||
|
||||
import { getIsWebAppsFullscreenSupported } from '../../../hooks/useAppLayout';
|
||||
|
||||
const TOP_PEERS_REQUEST_COOLDOWN = 60; // 1 min
|
||||
const runDebouncedForSearch = debounce((cb) => cb(), 500, false);
|
||||
let botFatherId: string | null;
|
||||
|
||||
function canUseInlineBots<T extends GlobalState>(global: T, chat: ApiChat) {
|
||||
return isChatAdmin(chat) || !isUserRightBanned(chat, 'sendInline', selectChatFullInfo(global, chat.id));
|
||||
}
|
||||
|
||||
addActionHandler('clickSuggestedMessageButton', (global, actions, payload): ActionReturnType => {
|
||||
const {
|
||||
chatId, messageId, button, tabId = getCurrentTabId(),
|
||||
@ -285,71 +291,26 @@ addActionHandler('restartBot', async (global, actions, payload): Promise<void> =
|
||||
void sendBotCommand(chat, MAIN_THREAD_ID, '/start', undefined, selectSendAs(global, chatId), lastMessageId);
|
||||
});
|
||||
|
||||
addActionHandler('loadTopInlineBots', async (global): Promise<void> => {
|
||||
const { lastRequestedAt } = global.topInlineBots;
|
||||
if (lastRequestedAt && getServerTime() - lastRequestedAt < TOP_PEERS_REQUEST_COOLDOWN) {
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await callApi('fetchTopInlineBots');
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { ids } = result;
|
||||
|
||||
global = getGlobal();
|
||||
global = {
|
||||
...global,
|
||||
topInlineBots: {
|
||||
...global.topInlineBots,
|
||||
userIds: ids,
|
||||
lastRequestedAt: getServerTime(),
|
||||
},
|
||||
};
|
||||
setGlobal(global);
|
||||
});
|
||||
|
||||
addActionHandler('loadTopBotApps', async (global): Promise<void> => {
|
||||
const { lastRequestedAt } = global.topBotApps;
|
||||
if (lastRequestedAt && getServerTime() - lastRequestedAt < TOP_PEERS_REQUEST_COOLDOWN) {
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await callApi('fetchTopBotApps');
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { ids } = result;
|
||||
|
||||
global = getGlobal();
|
||||
global = {
|
||||
...global,
|
||||
topBotApps: {
|
||||
...global.topBotApps,
|
||||
userIds: ids,
|
||||
lastRequestedAt: getServerTime(),
|
||||
},
|
||||
};
|
||||
setGlobal(global);
|
||||
});
|
||||
|
||||
addActionHandler('queryInlineBot', async (global, actions, payload): Promise<void> => {
|
||||
const {
|
||||
chatId, username, query, offset,
|
||||
tabId = getCurrentTabId(),
|
||||
} = payload;
|
||||
|
||||
const chat = selectChat(global, chatId);
|
||||
if (!chat || !canUseInlineBots(global, chat)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let inlineBotData = selectTabState(global, tabId).inlineBots.byUsername[username];
|
||||
if (inlineBotData === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (inlineBotData === undefined) {
|
||||
const { user: inlineBot, chat } = await callApi('fetchInlineBot', { username }) || {};
|
||||
const { user: inlineBot } = await callApi('getChatByUsername', username) || {};
|
||||
global = getGlobal();
|
||||
if (!inlineBot || !chat) {
|
||||
if (!inlineBot || !isUserBot(inlineBot) || !inlineBot.botPlaceholder) {
|
||||
global = replaceInlineBotSettings(global, username, false, tabId);
|
||||
setGlobal(global);
|
||||
return;
|
||||
@ -818,6 +779,7 @@ addActionHandler('requestMainWebView', async (global, actions, payload): Promise
|
||||
};
|
||||
global = addWebAppToOpenList(global, newActiveApp, true, true, tabId);
|
||||
setGlobal(global);
|
||||
actions.bumpTopPeerRating({ category: 'botsApp', peerId: botId });
|
||||
|
||||
if (isFullscreen && getIsWebAppsFullscreenSupported()) {
|
||||
actions.changeWebAppModalState({ state: 'fullScreen', tabId });
|
||||
|
||||
127
src/global/actions/api/topPeers.ts
Normal file
127
src/global/actions/api/topPeers.ts
Normal file
@ -0,0 +1,127 @@
|
||||
import type { ApiTopPeerCategory } from '../../../api/types';
|
||||
import type { ActionReturnType, GlobalState } from '../../types';
|
||||
|
||||
import { unique } from '../../../util/iteratees';
|
||||
import { getServerTime } from '../../../util/serverTime';
|
||||
import { callApi } from '../../../api/gramjs';
|
||||
import { addActionHandler, getGlobal, setGlobal } from '../../index';
|
||||
import { selectPeer } from '../../selectors';
|
||||
|
||||
const TOP_PEERS_CACHE_TTL = 24 * 60 * 60; // 24 hours
|
||||
|
||||
addActionHandler('loadTopPeers', async (global, actions, payload): Promise<void> => {
|
||||
const { category, force } = payload;
|
||||
const current = global.topPeerCategories[category];
|
||||
const now = getServerTime();
|
||||
|
||||
if (!force && current?.lastRequestedAt && now - current.lastRequestedAt < TOP_PEERS_CACHE_TTL) {
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await callApi('fetchTopPeers', { category });
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
global = getGlobal();
|
||||
const nextNow = getServerTime();
|
||||
const nextCurrent = global.topPeerCategories[category];
|
||||
|
||||
if (result.type === 'unchanged') {
|
||||
global = updateTopPeerCategory(global, category, {
|
||||
...nextCurrent,
|
||||
peerIds: nextCurrent?.peerIds || [],
|
||||
ratingsByPeerId: nextCurrent?.ratingsByPeerId || {},
|
||||
lastRequestedAt: nextNow,
|
||||
});
|
||||
setGlobal(global);
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.type === 'disabled') {
|
||||
global = updateTopPeerCategory(global, category, {
|
||||
peerIds: [],
|
||||
ratingsByPeerId: {},
|
||||
lastRequestedAt: nextNow,
|
||||
isDisabled: true,
|
||||
});
|
||||
setGlobal(global);
|
||||
return;
|
||||
}
|
||||
|
||||
const ratingsByPeerId = result.topPeers.reduce((acc, { peerId, rating }) => {
|
||||
acc[peerId] = rating;
|
||||
return acc;
|
||||
}, {} as Record<string, number>);
|
||||
const peerIds = result.topPeers.map(({ peerId }) => peerId);
|
||||
|
||||
global = updateTopPeerCategory(global, category, {
|
||||
peerIds,
|
||||
ratingsByPeerId,
|
||||
lastRequestedAt: nextNow,
|
||||
isDisabled: undefined,
|
||||
});
|
||||
setGlobal(global);
|
||||
});
|
||||
|
||||
addActionHandler('removeTopPeer', async (global, actions, payload): Promise<void> => {
|
||||
const { category, peerId } = payload;
|
||||
const current = global.topPeerCategories[category];
|
||||
if (!current) {
|
||||
return;
|
||||
}
|
||||
|
||||
const peerIds = current.peerIds.filter((id) => id !== peerId);
|
||||
const { [peerId]: removedRating, ...ratingsByPeerId } = current.ratingsByPeerId;
|
||||
|
||||
global = updateTopPeerCategory(global, category, {
|
||||
...current,
|
||||
peerIds,
|
||||
ratingsByPeerId,
|
||||
});
|
||||
setGlobal(global);
|
||||
|
||||
const peer = selectPeer(global, peerId);
|
||||
if (peer) {
|
||||
await callApi('resetTopPeerRating', { category, peer });
|
||||
}
|
||||
});
|
||||
|
||||
addActionHandler('bumpTopPeerRating', (global, actions, payload): ActionReturnType => {
|
||||
const { category, peerId, date } = payload;
|
||||
const current = global.topPeerCategories[category];
|
||||
const ratingEDecay = global.config?.ratingEDecay;
|
||||
if (!ratingEDecay || current?.isDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ratingDate = date || getServerTime();
|
||||
const basePeerIds = current?.peerIds || [];
|
||||
const peerIds = unique([...basePeerIds, peerId]);
|
||||
const ratingsByPeerId = { ...current?.ratingsByPeerId };
|
||||
const normalizeRate = current?.lastRequestedAt || ratingDate;
|
||||
|
||||
ratingsByPeerId[peerId] = (ratingsByPeerId[peerId] || 0) + Math.exp((ratingDate - normalizeRate) / ratingEDecay);
|
||||
peerIds.sort((firstId, secondId) => (ratingsByPeerId[secondId] || 0) - (ratingsByPeerId[firstId] || 0));
|
||||
|
||||
return updateTopPeerCategory(global, category, {
|
||||
peerIds,
|
||||
ratingsByPeerId,
|
||||
lastRequestedAt: normalizeRate,
|
||||
isDisabled: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
function updateTopPeerCategory<T extends GlobalState>(
|
||||
global: T,
|
||||
category: ApiTopPeerCategory,
|
||||
categoryState: NonNullable<GlobalState['topPeerCategories'][ApiTopPeerCategory]>,
|
||||
): T {
|
||||
return {
|
||||
...global,
|
||||
topPeerCategories: {
|
||||
...global.topPeerCategories,
|
||||
[category]: categoryState,
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -8,7 +8,6 @@ import { getCurrentTabId } from '../../../util/establishMultitabRole';
|
||||
import { buildCollectionByKey, unique } from '../../../util/iteratees';
|
||||
import * as langProvider from '../../../util/oldLangProvider';
|
||||
import { throttle } from '../../../util/schedulers';
|
||||
import { getServerTime } from '../../../util/serverTime';
|
||||
import { callApi } from '../../../api/gramjs';
|
||||
import { isUserBot } from '../../helpers';
|
||||
import { addActionHandler, getGlobal, setGlobal } from '../../index';
|
||||
@ -43,7 +42,6 @@ import {
|
||||
} from '../../selectors';
|
||||
|
||||
const PROFILE_PHOTOS_FIRST_LOAD_LIMIT = 10;
|
||||
const TOP_PEERS_REQUEST_COOLDOWN = 60; // 1 min
|
||||
const runThrottledForSearch = throttle((cb) => cb(), 500, false);
|
||||
|
||||
addActionHandler('loadFullUser', async (global, actions, payload): Promise<void> => {
|
||||
@ -105,32 +103,6 @@ addActionHandler('loadUser', async (global, actions, payload): Promise<void> =>
|
||||
setGlobal(global);
|
||||
});
|
||||
|
||||
addActionHandler('loadTopUsers', async (global): Promise<void> => {
|
||||
const { topPeers: { lastRequestedAt } } = global;
|
||||
|
||||
if (!(!lastRequestedAt || getServerTime() - lastRequestedAt > TOP_PEERS_REQUEST_COOLDOWN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await callApi('fetchTopUsers');
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { ids } = result;
|
||||
|
||||
global = getGlobal();
|
||||
global = {
|
||||
...global,
|
||||
topPeers: {
|
||||
...global.topPeers,
|
||||
userIds: ids,
|
||||
lastRequestedAt: getServerTime(),
|
||||
},
|
||||
};
|
||||
setGlobal(global);
|
||||
});
|
||||
|
||||
addActionHandler('loadContactList', async (global): Promise<void> => {
|
||||
const contactList = await callApi('fetchContactList');
|
||||
if (!contactList) {
|
||||
|
||||
@ -30,7 +30,9 @@ import {
|
||||
getMessageText,
|
||||
groupMessageIdsByThreadId,
|
||||
isActionMessage,
|
||||
isDeletedUser,
|
||||
isMessageLocal,
|
||||
isUserBot,
|
||||
pickMatchingTypingDraftMessage,
|
||||
} from '../../helpers';
|
||||
import { getMessageReplyInfo, getStoryReplyInfo } from '../../helpers/replies';
|
||||
@ -99,6 +101,7 @@ import {
|
||||
selectTabState,
|
||||
selectTopic,
|
||||
selectTopicFromMessage,
|
||||
selectUser,
|
||||
selectViewportIds,
|
||||
} from '../../selectors';
|
||||
import {
|
||||
@ -179,6 +182,25 @@ function removeTypingDraftEntries<T extends GlobalState>(
|
||||
return global;
|
||||
}
|
||||
|
||||
function shouldBumpGuestBotTopPeer<T extends GlobalState>(global: T, message: ApiMessage) {
|
||||
const { guestChatViaId, senderId } = message;
|
||||
if (message.isOutgoing || message.content.action || guestChatViaId !== global.currentUserId || !senderId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const sender = selectUser(global, senderId);
|
||||
return Boolean(sender?.isGuestChatBot);
|
||||
}
|
||||
|
||||
function shouldBumpInlineBotTopPeer(message: ApiMessage) {
|
||||
return Boolean(message.isOutgoing && !message.content.action && message.viaBotId);
|
||||
}
|
||||
|
||||
function shouldBumpCorrespondentTopPeer<T extends GlobalState>(global: T, chatId: string) {
|
||||
const user = selectUser(global, chatId);
|
||||
return Boolean(user && !user.isSelf && !isUserBot(user) && !isDeletedUser(user));
|
||||
}
|
||||
|
||||
addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => {
|
||||
switch (update['@type']) {
|
||||
case 'newMessage': {
|
||||
@ -345,6 +367,22 @@ addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => {
|
||||
|
||||
setGlobal(global);
|
||||
|
||||
if (shouldBumpGuestBotTopPeer(global, newMessage)) {
|
||||
actions.bumpTopPeerRating({
|
||||
category: 'botsGuestChat',
|
||||
peerId: newMessage.senderId!,
|
||||
date: newMessage.date,
|
||||
});
|
||||
}
|
||||
|
||||
if (shouldBumpInlineBotTopPeer(newMessage)) {
|
||||
actions.bumpTopPeerRating({
|
||||
category: 'botsInline',
|
||||
peerId: newMessage.viaBotId!,
|
||||
date: newMessage.date,
|
||||
});
|
||||
}
|
||||
|
||||
// Reload dialogs if chat is not present in the list
|
||||
if (!isLocal && !chat?.isNotJoined && !selectIsChatListed(global, chatId)) {
|
||||
actions.loadTopChats();
|
||||
@ -690,6 +728,10 @@ addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => {
|
||||
|
||||
setGlobal(global);
|
||||
|
||||
if (shouldBumpCorrespondentTopPeer(global, chatId)) {
|
||||
actions.bumpTopPeerRating({ category: 'correspondents', peerId: chatId });
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -725,6 +767,9 @@ addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => {
|
||||
}
|
||||
|
||||
setGlobal(global);
|
||||
if (shouldBumpCorrespondentTopPeer(global, chatId)) {
|
||||
actions.bumpTopPeerRating({ category: 'correspondents', peerId: chatId });
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -252,8 +252,8 @@ function unsafeMigrateCache(cached: GlobalState, initialState: GlobalState) {
|
||||
if (!cached.chats.loadingParameters) {
|
||||
cached.chats.loadingParameters = initialState.chats.loadingParameters;
|
||||
}
|
||||
if (!cached.topBotApps) {
|
||||
cached.topBotApps = initialState.topBotApps;
|
||||
if (!cached.topPeerCategories) {
|
||||
cached.topPeerCategories = initialState.topPeerCategories;
|
||||
}
|
||||
|
||||
if (!cached.reactions.defaultTags?.[0]?.type) {
|
||||
@ -443,9 +443,7 @@ function reduceGlobal<T extends GlobalState>(global: T) {
|
||||
'attachMenu',
|
||||
'currentUserId',
|
||||
'contactList',
|
||||
'topPeers',
|
||||
'topInlineBots',
|
||||
'topBotApps',
|
||||
'topPeerCategories',
|
||||
'recentEmojis',
|
||||
'recentCustomEmojis',
|
||||
'push',
|
||||
@ -560,6 +558,7 @@ function reduceUsers<T extends GlobalState>(global: T): GlobalState['users'] {
|
||||
.filter((id): id is string => Boolean(id) && isUserId(id));
|
||||
|
||||
const attachBotIds = Object.keys(global.attachMenu?.bots || {});
|
||||
const topPeerIds = getTopPeerIds(global);
|
||||
|
||||
const idsToSave = unique([
|
||||
...currentUserId ? [currentUserId] : [],
|
||||
@ -567,7 +566,7 @@ function reduceUsers<T extends GlobalState>(global: T): GlobalState['users'] {
|
||||
...chatStoriesUserIds,
|
||||
...visibleUserIds || [],
|
||||
...attachBotIds,
|
||||
...global.topPeers.userIds || [],
|
||||
...topPeerIds.filter(isUserId),
|
||||
...global.recentlyFoundChatIds?.filter(isUserId) || [],
|
||||
...getOrderedIds(ARCHIVED_FOLDER_ID)?.slice(0, GLOBAL_STATE_CACHE_ARCHIVED_CHAT_LIST_LIMIT).filter(isUserId) || [],
|
||||
...getOrderedIds(ALL_FOLDER_ID)?.filter(isUserId) || [],
|
||||
@ -608,11 +607,13 @@ function reduceChats<T extends GlobalState>(global: T): GlobalState['chats'] {
|
||||
return content.storyData?.peerId || webPage?.story?.peerId || replyPeer;
|
||||
});
|
||||
}));
|
||||
const topPeerIds = getTopPeerIds(global);
|
||||
|
||||
const unlinkedIdsToSave = [
|
||||
...currentUserId ? [currentUserId] : [],
|
||||
...currentChatIds,
|
||||
...messagesChatIds,
|
||||
...topPeerIds,
|
||||
...global.recentlyFoundChatIds || [],
|
||||
...getOrderedIds(ARCHIVED_FOLDER_ID)?.slice(0, GLOBAL_STATE_CACHE_ARCHIVED_CHAT_LIST_LIMIT) || [],
|
||||
...getOrderedIds(ALL_FOLDER_ID) || [],
|
||||
@ -652,6 +653,10 @@ function reduceChats<T extends GlobalState>(global: T): GlobalState['chats'] {
|
||||
};
|
||||
}
|
||||
|
||||
function getTopPeerIds<T extends GlobalState>(global: T) {
|
||||
return unique(Object.values(global.topPeerCategories).flatMap((category) => category?.peerIds || []));
|
||||
}
|
||||
|
||||
function reduceMessages<T extends GlobalState>(global: T): GlobalState['messages'] {
|
||||
const { currentUserId } = global;
|
||||
const byChatId: GlobalState['messages']['byChatId'] = {};
|
||||
|
||||
@ -268,10 +268,7 @@ export const INITIAL_GLOBAL_STATE: GlobalState = {
|
||||
saved: {},
|
||||
},
|
||||
|
||||
topPeers: {},
|
||||
|
||||
topInlineBots: {},
|
||||
topBotApps: {},
|
||||
topPeerCategories: {},
|
||||
|
||||
activeSessions: {
|
||||
byHash: {},
|
||||
|
||||
@ -58,6 +58,7 @@ import type {
|
||||
ApiStickerSetInfo,
|
||||
ApiThemeParameters,
|
||||
ApiTodoItem,
|
||||
ApiTopPeerCategory,
|
||||
ApiTypeCurrencyAmount,
|
||||
ApiTypePrepaidGiveaway,
|
||||
ApiUpdate,
|
||||
@ -1914,7 +1915,6 @@ export interface ActionPayloads {
|
||||
|
||||
// Users
|
||||
loadNearestCountry: undefined;
|
||||
loadTopUsers: undefined;
|
||||
loadContactList: undefined;
|
||||
|
||||
loadCurrentUser: undefined;
|
||||
@ -2164,8 +2164,19 @@ export interface ActionPayloads {
|
||||
command: string;
|
||||
chatId?: string;
|
||||
} & WithTabId;
|
||||
loadTopInlineBots: undefined;
|
||||
loadTopBotApps: undefined;
|
||||
loadTopPeers: {
|
||||
category: ApiTopPeerCategory;
|
||||
force?: boolean;
|
||||
};
|
||||
removeTopPeer: {
|
||||
category: ApiTopPeerCategory;
|
||||
peerId: string;
|
||||
};
|
||||
bumpTopPeerRating: {
|
||||
category: ApiTopPeerCategory;
|
||||
peerId: string;
|
||||
date?: number;
|
||||
};
|
||||
queryInlineBot: {
|
||||
chatId: string;
|
||||
username: string;
|
||||
@ -2175,6 +2186,7 @@ export interface ActionPayloads {
|
||||
sendInlineBotResult: {
|
||||
id: string;
|
||||
queryId: string;
|
||||
botId?: string;
|
||||
chatId: string;
|
||||
threadId: ThreadId;
|
||||
isSilent?: boolean;
|
||||
@ -2185,6 +2197,7 @@ export interface ActionPayloads {
|
||||
chat: ApiChat;
|
||||
id: string;
|
||||
queryId: string;
|
||||
botId?: string;
|
||||
replyInfo?: ApiInputMessageReplyInfo;
|
||||
sendAs?: ApiPeer;
|
||||
isSilent?: boolean;
|
||||
|
||||
@ -46,6 +46,7 @@ import type {
|
||||
ApiStoryAlbum,
|
||||
ApiTimezone,
|
||||
ApiTonAmount,
|
||||
ApiTopPeerCategory,
|
||||
ApiTranscription,
|
||||
ApiUpdateAuthorizationStateType,
|
||||
ApiUpdateConnectionStateType,
|
||||
@ -418,20 +419,12 @@ export type GlobalState = {
|
||||
};
|
||||
};
|
||||
|
||||
topPeers: {
|
||||
userIds?: string[];
|
||||
topPeerCategories: Partial<Record<ApiTopPeerCategory, {
|
||||
peerIds: string[];
|
||||
ratingsByPeerId: Record<string, number>;
|
||||
lastRequestedAt?: number;
|
||||
};
|
||||
|
||||
topInlineBots: {
|
||||
userIds?: string[];
|
||||
lastRequestedAt?: number;
|
||||
};
|
||||
|
||||
topBotApps: {
|
||||
userIds?: string[];
|
||||
lastRequestedAt?: number;
|
||||
};
|
||||
isDisabled?: boolean;
|
||||
}>>;
|
||||
|
||||
activeSessions: {
|
||||
byHash: Record<string, ApiSession>;
|
||||
|
||||
@ -145,7 +145,13 @@ class TelegramClient {
|
||||
if (request instanceof Api.contacts.GetTopPeers) {
|
||||
return new Api.contacts.TopPeers({
|
||||
categories: [new Api.TopPeerCategoryPeers({
|
||||
category: new Api.TopPeerCategoryCorrespondents(),
|
||||
category: request.botsInline
|
||||
? new Api.TopPeerCategoryBotsInline()
|
||||
: request.botsApp
|
||||
? new Api.TopPeerCategoryBotsApp()
|
||||
: request.botsGuestchat
|
||||
? new Api.TopPeerCategoryBotsGuestChat()
|
||||
: new Api.TopPeerCategoryCorrespondents(),
|
||||
count: this.mockData.topPeers.length,
|
||||
peers: this.mockData.topPeers.map((id) => {
|
||||
return new Api.TopPeer({
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user