This commit is contained in:
Alexander Zinchuk 2024-03-01 14:02:45 -05:00
parent 2bed347f28
commit 033f8d4791
62 changed files with 883 additions and 581 deletions

View File

@ -66,6 +66,8 @@ export interface GramJsAppConfig extends LimitsConfig {
story_expire_period: number; story_expire_period: number;
story_viewers_expire_period: number; story_viewers_expire_period: number;
stories_changelog_user_id?: number; stories_changelog_user_id?: number;
// Boosts
group_transcribe_level_min?: number;
} }
function buildEmojiSounds(appConfig: GramJsAppConfig) { function buildEmojiSounds(appConfig: GramJsAppConfig) {
@ -134,5 +136,6 @@ export function buildAppConfig(json: GramJs.TypeJSONValue, hash: number): ApiApp
storyExpirePeriod: appConfig.story_expire_period ?? STORY_EXPIRE_PERIOD, storyExpirePeriod: appConfig.story_expire_period ?? STORY_EXPIRE_PERIOD,
storyViewersExpirePeriod: appConfig.story_viewers_expire_period ?? STORY_VIEWERS_EXPIRE_PERIOD, storyViewersExpirePeriod: appConfig.story_viewers_expire_period ?? STORY_VIEWERS_EXPIRE_PERIOD,
storyChangelogUserId: appConfig.stories_changelog_user_id?.toString() ?? SERVICE_NOTIFICATIONS_USER_ID, storyChangelogUserId: appConfig.stories_changelog_user_id?.toString() ?? SERVICE_NOTIFICATIONS_USER_ID,
groupTranscribeLevelMin: appConfig.group_transcribe_level_min,
}; };
} }

View File

@ -62,8 +62,9 @@ function buildApiChatFieldsFromPeerEntity(
const color = ('color' in peerEntity && peerEntity.color) ? buildApiPeerColor(peerEntity.color) : undefined; const color = ('color' in peerEntity && peerEntity.color) ? buildApiPeerColor(peerEntity.color) : undefined;
const emojiStatus = ('emojiStatus' in peerEntity && peerEntity.emojiStatus) const emojiStatus = ('emojiStatus' in peerEntity && peerEntity.emojiStatus)
? buildApiEmojiStatus(peerEntity.emojiStatus) : undefined; ? buildApiEmojiStatus(peerEntity.emojiStatus) : undefined;
const boostLevel = ('level' in peerEntity) ? peerEntity.level : undefined;
return omitUndefined({ return omitUndefined<PeerEntityApiChatFields>({
isMin, isMin,
hasPrivateLink, hasPrivateLink,
isSignaturesShown, isSignaturesShown,
@ -93,6 +94,7 @@ function buildApiChatFieldsFromPeerEntity(
maxStoryId, maxStoryId,
hasStories: Boolean(maxStoryId) && !storiesUnavailable, hasStories: Boolean(maxStoryId) && !storiesUnavailable,
emojiStatus, emojiStatus,
boostLevel,
}); });
} }

View File

@ -159,7 +159,7 @@ export type UniversalMessage = (
'out' | 'message' | 'entities' | 'fromId' | 'peerId' | 'fwdFrom' | 'replyTo' | 'replyMarkup' | 'post' | 'out' | 'message' | 'entities' | 'fromId' | 'peerId' | 'fwdFrom' | 'replyTo' | 'replyMarkup' | 'post' |
'media' | 'action' | 'views' | 'editDate' | 'editHide' | 'mediaUnread' | 'groupedId' | 'mentioned' | 'viaBotId' | 'media' | 'action' | 'views' | 'editDate' | 'editHide' | 'mediaUnread' | 'groupedId' | 'mentioned' | 'viaBotId' |
'replies' | 'fromScheduled' | 'postAuthor' | 'noforwards' | 'reactions' | 'forwards' | 'silent' | 'pinned' | 'replies' | 'fromScheduled' | 'postAuthor' | 'noforwards' | 'reactions' | 'forwards' | 'silent' | 'pinned' |
'savedPeerId' 'savedPeerId' | 'fromBoostsApplied'
)> )>
); );
@ -197,10 +197,11 @@ export function buildApiMessageWithChatId(
const isForwardingAllowed = !mtpMessage.noforwards; const isForwardingAllowed = !mtpMessage.noforwards;
const emojiOnlyCount = getEmojiOnlyCountForMessage(content, groupedId); const emojiOnlyCount = getEmojiOnlyCountForMessage(content, groupedId);
const hasComments = mtpMessage.replies?.comments; const hasComments = mtpMessage.replies?.comments;
const senderBoosts = mtpMessage.fromBoostsApplied;
const savedPeerId = mtpMessage.savedPeerId && getApiChatIdFromMtpPeer(mtpMessage.savedPeerId); const savedPeerId = mtpMessage.savedPeerId && getApiChatIdFromMtpPeer(mtpMessage.savedPeerId);
return omitUndefined({ return omitUndefined<ApiMessage>({
id: mtpMessage.id, id: mtpMessage.id,
chatId, chatId,
isOutgoing, isOutgoing,
@ -237,7 +238,8 @@ export function buildApiMessageWithChatId(
isForwardingAllowed, isForwardingAllowed,
hasComments, hasComments,
savedPeerId, savedPeerId,
} satisfies ApiMessage); senderBoosts,
});
} }
export function buildMessageDraft(draft: GramJs.TypeDraftMessage): ApiDraft | undefined { export function buildMessageDraft(draft: GramJs.TypeDraftMessage): ApiDraft | undefined {
@ -288,7 +290,7 @@ function buildApiReplyInfo(replyHeader: GramJs.TypeMessageReplyHeader): ApiReply
if (replyHeader instanceof GramJs.MessageReplyStoryHeader) { if (replyHeader instanceof GramJs.MessageReplyStoryHeader) {
return { return {
type: 'story', type: 'story',
userId: replyHeader.userId.toString(), peerId: getApiChatIdFromMtpPeer(replyHeader.peer),
storyId: replyHeader.storyId, storyId: replyHeader.storyId,
}; };
} }
@ -563,6 +565,20 @@ function buildAction(
amount = action.winnersCount; amount = action.winnersCount;
pluralValue = action.winnersCount; pluralValue = action.winnersCount;
} }
} else if (action instanceof GramJs.MessageActionBoostApply) {
type = 'chatBoost';
if (action.boosts === 1) {
text = senderId === currentUserId ? 'BoostingBoostsGroupByYouServiceMsg' : 'BoostingBoostsGroupByUserServiceMsg';
translationValues.push('%action_origin%');
} else {
text = senderId === currentUserId ? 'BoostingBoostsGroupByYouServiceMsgCount'
: 'BoostingBoostsGroupByUserServiceMsgCount';
translationValues.push(action.boosts.toString());
if (senderId !== currentUserId) {
translationValues.unshift('%action_origin%');
}
pluralValue = action.boosts;
}
} else { } else {
text = 'ChatList.UnsupportedMessage'; text = 'ChatList.UnsupportedMessage';
} }
@ -901,7 +917,7 @@ function buildReplyInfo(inputInfo: ApiInputReplyInfo, isForum?: boolean): ApiRep
if (inputInfo.type === 'story') { if (inputInfo.type === 'story') {
return { return {
type: 'story', type: 'story',
userId: inputInfo.userId, peerId: inputInfo.peerId,
storyId: inputInfo.storyId, storyId: inputInfo.storyId,
}; };
} }

View File

@ -4,6 +4,7 @@ import type {
ApiMediaArea, ApiMediaArea,
ApiMediaAreaCoordinates, ApiMediaAreaCoordinates,
ApiStealthMode, ApiStealthMode,
ApiStory,
ApiStoryForwardInfo, ApiStoryForwardInfo,
ApiStoryView, ApiStoryView,
ApiStoryViews, ApiStoryViews,
@ -46,7 +47,7 @@ export function buildApiStory(peerId: string, story: GramJs.TypeStoryItem): ApiT
edited, pinned, expireDate, id, date, caption, edited, pinned, expireDate, id, date, caption,
entities, media, privacy, views, entities, media, privacy, views,
public: isPublic, noforwards, closeFriends, contacts, selectedContacts, public: isPublic, noforwards, closeFriends, contacts, selectedContacts,
mediaAreas, sentReaction, out, fwdFrom, mediaAreas, sentReaction, out, fwdFrom, fromId,
} = story; } = story;
const content: MediaContent = { const content: MediaContent = {
@ -57,38 +58,38 @@ export function buildApiStory(peerId: string, story: GramJs.TypeStoryItem): ApiT
content.text = buildMessageTextContent(caption, entities); content.text = buildMessageTextContent(caption, entities);
} }
return { return omitUndefined<ApiStory>({
id, id,
peerId, peerId,
date, date,
expireDate, expireDate,
content, content,
...(isPublic && { isPublic }), isPublic,
...(edited && { isEdited: true }), isEdited: edited,
...(pinned && { isPinned: true }), isPinned: pinned,
...(contacts && { isForContacts: true }), isForContacts: contacts,
...(selectedContacts && { isForSelectedContacts: true }), isForSelectedContacts: selectedContacts,
...(closeFriends && { isForCloseFriends: true }), isForCloseFriends: closeFriends,
...(noforwards && { noForwards: true }), noForwards: noforwards,
...(views && { views: buildApiStoryViews(views) }), views: views && buildApiStoryViews(views),
...(out && { isOut: true }), isOut: out,
...(privacy && { visibility: buildPrivacyRules(privacy) }), visibility: privacy && buildPrivacyRules(privacy),
...(mediaAreas && { mediaAreas: mediaAreas.map(buildApiMediaArea).filter(Boolean) }), mediaAreas: mediaAreas?.map(buildApiMediaArea).filter(Boolean),
...(sentReaction && { sentReaction: buildApiReaction(sentReaction) }), sentReaction: sentReaction && buildApiReaction(sentReaction),
...(fwdFrom && { forwardInfo: buildApiStoryForwardInfo(fwdFrom) }), forwardInfo: fwdFrom && buildApiStoryForwardInfo(fwdFrom),
}; fromId: fromId && getApiChatIdFromMtpPeer(fromId),
});
} }
function buildApiStoryViews(views: GramJs.TypeStoryViews): ApiStoryViews | undefined { export function buildApiStoryViews(views: GramJs.TypeStoryViews): ApiStoryViews {
return { return omitUndefined<ApiStoryViews>({
hasViewers: views.hasViewers,
viewsCount: views.viewsCount, viewsCount: views.viewsCount,
forwardsCount: views.forwardsCount, forwardsCount: views.forwardsCount,
reactionsCount: views.reactionsCount, reactionsCount: views.reactionsCount,
...(views?.reactions && { reactions: views.reactions.map(buildReactionCount).filter(Boolean) }), reactions: views.reactions?.map(buildReactionCount).filter(Boolean),
...(views?.recentViewers && { recentViewerIds: views.recentViewers?.map((viewerId) => buildApiPeerId(viewerId, 'user')),
recentViewerIds: views.recentViewers.map((viewerId) => buildApiPeerId(viewerId, 'user')), });
}),
};
} }
export function buildApiStoryView(view: GramJs.TypeStoryView): ApiTypeStoryView | undefined { export function buildApiStoryView(view: GramJs.TypeStoryView): ApiTypeStoryView | undefined {

View File

@ -646,7 +646,7 @@ export function buildInputBotApp(app: ApiBotApp) {
export function buildInputReplyTo(replyInfo: ApiInputReplyInfo) { export function buildInputReplyTo(replyInfo: ApiInputReplyInfo) {
if (replyInfo.type === 'story') { if (replyInfo.type === 'story') {
return new GramJs.InputReplyToStory({ return new GramJs.InputReplyToStory({
userId: buildInputPeerFromLocalDb(replyInfo.userId)!, peer: buildInputPeerFromLocalDb(replyInfo.peerId)!,
storyId: replyInfo.storyId, storyId: replyInfo.storyId,
}); });
} }

View File

@ -80,7 +80,8 @@ import { invokeRequest, uploadFile } from './client';
type FullChatData = { type FullChatData = {
fullInfo: ApiChatFullInfo; fullInfo: ApiChatFullInfo;
users?: ApiUser[]; users: ApiUser[];
chats: ApiChat[];
userStatusesById: { [userId: string]: ApiUserStatus }; userStatusesById: { [userId: string]: ApiUserStatus };
groupCall?: Partial<ApiGroupCall>; groupCall?: Partial<ApiGroupCall>;
membersCount?: number; membersCount?: number;
@ -519,6 +520,7 @@ async function getFullChatInfo(chatId: string): Promise<FullChatData | undefined
const botCommands = botInfo ? buildApiChatBotCommands(botInfo) : undefined; const botCommands = botInfo ? buildApiChatBotCommands(botInfo) : undefined;
const inviteLink = exportedInvite instanceof GramJs.ChatInviteExported ? exportedInvite.link : undefined; const inviteLink = exportedInvite instanceof GramJs.ChatInviteExported ? exportedInvite.link : undefined;
const { users, userStatusesById } = buildApiUsersAndStatuses(result.users); const { users, userStatusesById } = buildApiUsersAndStatuses(result.users);
const chats = result.chats.map((chat) => buildApiChatFromPreview(chat)).filter(Boolean);
return { return {
fullInfo: { fullInfo: {
@ -536,6 +538,7 @@ async function getFullChatInfo(chatId: string): Promise<FullChatData | undefined
isTranslationDisabled: translationsDisabled, isTranslationDisabled: translationsDisabled,
}, },
users, users,
chats,
userStatusesById, userStatusesById,
groupCall: call ? { groupCall: call ? {
chatId, chatId,
@ -590,6 +593,9 @@ async function getFullChannelInfo(
translationsDisabled, translationsDisabled,
storiesPinnedAvailable, storiesPinnedAvailable,
viewForumAsMessages, viewForumAsMessages,
emojiset,
boostsApplied,
boostsUnrestrict,
} = result.fullChat; } = result.fullChat;
if (chatPhoto instanceof GramJs.Photo) { if (chatPhoto instanceof GramJs.Photo) {
@ -608,6 +614,7 @@ async function getFullChannelInfo(
canViewParticipants && await fetchMembers(id, accessHash, 'admin') canViewParticipants && await fetchMembers(id, accessHash, 'admin')
) || {}; ) || {};
const botCommands = botInfo ? buildApiChatBotCommands(botInfo) : undefined; const botCommands = botInfo ? buildApiChatBotCommands(botInfo) : undefined;
const chats = result.chats.map((chat) => buildApiChatFromPreview(chat)).filter(Boolean);
if (result?.chats?.length > 1) { if (result?.chats?.length > 1) {
updateLocalDb(result); updateLocalDb(result);
@ -662,11 +669,15 @@ async function getFullChannelInfo(
recentRequesterIds: recentRequesters?.map((userId) => buildApiPeerId(userId, 'user')), recentRequesterIds: recentRequesters?.map((userId) => buildApiPeerId(userId, 'user')),
statisticsDcId: statsDc, statisticsDcId: statsDc,
stickerSet: stickerset ? buildStickerSet(stickerset) : undefined, stickerSet: stickerset ? buildStickerSet(stickerset) : undefined,
emojiSet: emojiset ? buildStickerSet(emojiset) : undefined,
areParticipantsHidden: participantsHidden, areParticipantsHidden: participantsHidden,
isTranslationDisabled: translationsDisabled, isTranslationDisabled: translationsDisabled,
hasPinnedStories: Boolean(storiesPinnedAvailable), hasPinnedStories: Boolean(storiesPinnedAvailable),
boostsApplied,
boostsToUnrestrict: boostsUnrestrict,
}, },
users: [...(users || []), ...(bannedUsers || []), ...(adminUsers || [])], users: [...(users || []), ...(bannedUsers || []), ...(adminUsers || [])],
chats,
userStatusesById: statusesById, userStatusesById: statusesById,
groupCall: call ? { groupCall: call ? {
chatId: id, chatId: id,

View File

@ -21,6 +21,7 @@ import {
buildApiStealthMode, buildApiStealthMode,
buildApiStory, buildApiStory,
buildApiStoryView, buildApiStoryView,
buildApiStoryViews,
} from '../apiBuilders/stories'; } from '../apiBuilders/stories';
import { buildApiUser } from '../apiBuilders/users'; import { buildApiUser } from '../apiBuilders/users';
import { import {
@ -300,6 +301,33 @@ export async function fetchStoryViewList({
}; };
} }
export async function fetchStoriesViews({
peer,
storyIds,
}: {
peer: ApiPeer;
storyIds: number[];
}) {
const result = await invokeRequest(new GramJs.stories.GetStoriesViews({
peer: buildInputPeer(peer.id, peer.accessHash),
id: storyIds,
}));
if (!result?.views[0]) {
return undefined;
}
addEntitiesToLocalDb(result.users);
const views = buildApiStoryViews(result.views[0]);
const users = result.users.map(buildApiUser).filter(Boolean);
return {
views,
users,
};
}
export async function fetchStoryLink({ peer, storyId }: { peer: ApiPeer ; storyId: number }) { export async function fetchStoryLink({ peer, storyId }: { peer: ApiPeer ; storyId: number }) {
const result = await invokeRequest(new GramJs.stories.ExportStoryLink({ const result = await invokeRequest(new GramJs.stories.ExportStoryLink({
peer: buildInputPeer(peer.id, peer.accessHash), peer: buildInputPeer(peer.id, peer.accessHash),

View File

@ -52,6 +52,7 @@ export interface ApiChat {
listedTopicIds?: number[]; listedTopicIds?: number[];
topicsCount?: number; topicsCount?: number;
orderedPinnedTopicIds?: number[]; orderedPinnedTopicIds?: number[];
boostLevel?: number;
// Calls // Calls
isCallActive?: boolean; isCallActive?: boolean;
@ -128,10 +129,14 @@ export interface ApiChatFullInfo {
requestsPending?: number; requestsPending?: number;
statisticsDcId?: number; statisticsDcId?: number;
stickerSet?: ApiStickerSet; stickerSet?: ApiStickerSet;
emojiSet?: ApiStickerSet;
profilePhoto?: ApiPhoto; profilePhoto?: ApiPhoto;
areParticipantsHidden?: boolean; areParticipantsHidden?: boolean;
isTranslationDisabled?: true; isTranslationDisabled?: true;
hasPinnedStories?: boolean; hasPinnedStories?: boolean;
boostsApplied?: number;
boostsToUnrestrict?: number;
} }
export interface ApiChatMember { export interface ApiChatMember {

View File

@ -298,6 +298,7 @@ export interface ApiAction {
| 'topicCreate' | 'topicCreate'
| 'suggestProfilePhoto' | 'suggestProfilePhoto'
| 'joinedChannel' | 'joinedChannel'
| 'chatBoost'
| 'other'; | 'other';
photo?: ApiPhoto; photo?: ApiPhoto;
amount?: number; amount?: number;
@ -356,7 +357,7 @@ export interface ApiMessageReplyInfo {
export interface ApiStoryReplyInfo { export interface ApiStoryReplyInfo {
type: 'story'; type: 'story';
userId: string; peerId: string;
storyId: number; storyId: number;
} }
@ -370,7 +371,7 @@ export interface ApiInputMessageReplyInfo {
export interface ApiInputStoryReplyInfo { export interface ApiInputStoryReplyInfo {
type: 'story'; type: 'story';
userId: string; peerId: string;
storyId: number; storyId: number;
} }
@ -539,6 +540,7 @@ export interface ApiMessage {
hasComments?: boolean; hasComments?: boolean;
readDate?: number; readDate?: number;
savedPeerId?: string; savedPeerId?: string;
senderBoosts?: number;
} }
export interface ApiReactions { export interface ApiReactions {

View File

@ -197,6 +197,7 @@ export interface ApiAppConfig {
storyExpirePeriod: number; storyExpirePeriod: number;
storyViewersExpirePeriod: number; storyViewersExpirePeriod: number;
storyChangelogUserId: string; storyChangelogUserId: string;
groupTranscribeLevelMin?: number;
} }
export interface ApiConfig { export interface ApiConfig {

View File

@ -23,9 +23,11 @@ export interface ApiStory {
sentReaction?: ApiReaction; sentReaction?: ApiReaction;
mediaAreas?: ApiMediaArea[]; mediaAreas?: ApiMediaArea[];
forwardInfo?: ApiStoryForwardInfo; forwardInfo?: ApiStoryForwardInfo;
fromId?: string;
} }
export interface ApiStoryViews { export interface ApiStoryViews {
hasViewers?: true;
viewsCount?: number; viewsCount?: number;
forwardsCount?: number; forwardsCount?: number;
reactionsCount?: number; reactionsCount?: number;

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="none"><path fill="#000" d="m20.9 10.884.862-5.46c.635-4.018-4.62-6.107-6.918-2.75L6.311 15.146c-1.732 2.533.081 5.97 3.15 5.97H11.1l-.862 5.46c-.635 4.019 4.62 6.108 6.918 2.75l8.533-12.47c1.732-2.533-.081-5.97-3.15-5.97zm-3.807-6.67c.657-.96 2.158-.363 1.977.786l-1.16 7.35a1.09 1.09 0 0 0 1.076 1.26h3.553c.877 0 1.395.982.9 1.705l-8.532 12.471c-.657.96-2.158.362-1.977-.786l.08-.511 1.08-6.838a1.09 1.09 0 0 0-1.076-1.26H9.46a1.09 1.09 0 0 1-.9-1.706z" style="stroke-width:1.36275"/></svg>

After

Width:  |  Height:  |  Size: 561 B

View File

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32"><path d="M19.322 13.194c-.69 0-1.216-.616-1.109-1.298l1.5-9.498c.187-1.182-1.36-1.797-2.035-.809L7.1 17.05c-.51.746.023 1.757.926 1.757h4.652c.69 0 1.216.616 1.109 1.298l-1.5 9.498c-.187 1.182 1.36 1.797 2.035.809L24.9 14.95a1.122 1.122 0 0 0-.926-1.757Z" style="stroke-width:1.68365"/></svg> <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32"><path d="M19.341 13.175a1.129 1.129 0 0 1-1.115-1.303l1.512-9.56c.182-1.192-1.374-1.81-2.052-.817L7.038 17.06a1.129 1.129 0 0 0 .934 1.765h4.682c.696 0 1.225.62 1.116 1.306l-1.507 9.56c-.19 1.19 1.366 1.808 2.047.814l10.65-15.562a1.129 1.129 0 0 0-.93-1.768z" style="stroke-width:2.60715"/></svg>

Before

Width:  |  Height:  |  Size: 355 B

After

Width:  |  Height:  |  Size: 359 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32"><path d="m22.105 16.416-3.054 4.283-1.477 8.992c-.195 1.189 1.425 1.807 2.134.814l11.086-15.562a1.175 1.129 0 0 0-.972-1.768h-4.878a1.175 1.129 0 0 1-1.162-1.303l1.57-9.56c.197-1.192-1.423-1.81-2.132-.817l-6.463 9.073h2.134c3.13 0 4.978 3.366 3.21 5.848zm-3.065-3.233c.855.1 1.33 1.05.825 1.76L8.78 30.505c-.706.993-2.33.375-2.131-.814l1.569-9.56a1.175 1.129 0 0 0-1.162-1.304H2.18a1.175 1.129 0 0 1-.972-1.77L12.294 1.495c.709-.993 2.33-.375 2.134.816l-1.572 9.558c-.111.686.44 1.306 1.162 1.306h4.875z" style="stroke-width:2.66026"/></svg>

After

Width:  |  Height:  |  Size: 604 B

View File

@ -207,6 +207,8 @@ const Avatar: FC<OwnProps> = ({
content = getFirstLetters(text, 2); content = getFirstLetters(text, 2);
} }
const isRoundedRect = isForum && !((withStory || withStorySolid) && peer?.hasStories);
const fullClassName = buildClassName( const fullClassName = buildClassName(
`Avatar size-${size}`, `Avatar size-${size}`,
className, className,
@ -216,7 +218,7 @@ const Avatar: FC<OwnProps> = ({
isAnonymousForwards && 'anonymous-forwards', isAnonymousForwards && 'anonymous-forwards',
isDeleted && 'deleted-account', isDeleted && 'deleted-account',
isReplies && 'replies-bot-account', isReplies && 'replies-bot-account',
isForum && 'forum', isRoundedRect && 'forum',
((withStory && peer?.hasStories) || forPremiumPromo) && 'with-story-circle', ((withStory && peer?.hasStories) || forPremiumPromo) && 'with-story-circle',
withStorySolid && peer?.hasStories && 'with-story-solid', withStorySolid && peer?.hasStories && 'with-story-solid',
withStorySolid && (peer?.hasUnreadStories || forceUnreadStorySolid) && 'has-unread-story', withStorySolid && (peer?.hasUnreadStories || forceUnreadStorySolid) && 'has-unread-story',

View File

@ -2,9 +2,9 @@ import type { FC } from '../../lib/teact/teact';
import React, { import React, {
memo, useMemo, useRef, useState, memo, useMemo, useRef, useState,
} from '../../lib/teact/teact'; } from '../../lib/teact/teact';
import { getActions } from '../../global'; import { getActions, getGlobal } from '../../global';
import type { ApiChat, ApiTopic } from '../../api/types'; import type { ApiTopic } from '../../api/types';
import type { ThreadId } from '../../types'; import type { ThreadId } from '../../types';
import { CHAT_HEIGHT_PX } from '../../config'; import { CHAT_HEIGHT_PX } from '../../config';
@ -35,7 +35,6 @@ import './ChatOrUserPicker.scss';
export type OwnProps = { export type OwnProps = {
currentUserId?: string; currentUserId?: string;
chatOrUserIds: string[]; chatOrUserIds: string[];
chatsById?: Record<string, ApiChat>;
isOpen: boolean; isOpen: boolean;
searchPlaceholder: string; searchPlaceholder: string;
search: string; search: string;
@ -55,7 +54,6 @@ const ChatOrUserPicker: FC<OwnProps> = ({
isOpen, isOpen,
currentUserId, currentUserId,
chatOrUserIds, chatOrUserIds,
chatsById,
search, search,
searchPlaceholder, searchPlaceholder,
className, className,
@ -89,7 +87,11 @@ const ChatOrUserPicker: FC<OwnProps> = ({
useInputFocusOnOpen(topicSearchRef, isOpen && activeKey === TOPIC_LIST_SLIDE); useInputFocusOnOpen(topicSearchRef, isOpen && activeKey === TOPIC_LIST_SLIDE);
const [topicIds, topics] = useMemo(() => { const [topicIds, topics] = useMemo(() => {
const topicsResult = forumId ? chatsById?.[forumId].topics : undefined; const global = getGlobal();
const chatsById = global.chats.byId;
const chatFullInfoById = global.chats.fullInfoById;
const topicsResult = forumId ? chatsById[forumId].topics : undefined;
if (!topicsResult) { if (!topicsResult) {
return [undefined, undefined]; return [undefined, undefined];
} }
@ -99,7 +101,7 @@ const ChatOrUserPicker: FC<OwnProps> = ({
const result = topicsResult const result = topicsResult
? Object.values(topicsResult).reduce((acc, topic) => { ? Object.values(topicsResult).reduce((acc, topic) => {
if ( if (
getCanPostInChat(chatsById![forumId!], topic.id) getCanPostInChat(chatsById[forumId!], topic.id, undefined, chatFullInfoById[forumId!])
&& (!searchTitle || topic.title.toLowerCase().includes(searchTitle)) && (!searchTitle || topic.title.toLowerCase().includes(searchTitle))
) { ) {
acc[topic.id] = topic; acc[topic.id] = topic;
@ -110,7 +112,7 @@ const ChatOrUserPicker: FC<OwnProps> = ({
: topicsResult; : topicsResult;
return [Object.keys(result).map(Number), result]; return [Object.keys(result).map(Number), result];
}, [chatsById, forumId, topicSearch]); }, [forumId, topicSearch]);
const handleHeaderBackClick = useLastCallback(() => { const handleHeaderBackClick = useLastCallback(() => {
setForumId(undefined); setForumId(undefined);
@ -127,8 +129,10 @@ const ChatOrUserPicker: FC<OwnProps> = ({
const handleKeyDown = useKeyboardListNavigation(containerRef, isOpen, (index) => { const handleKeyDown = useKeyboardListNavigation(containerRef, isOpen, (index) => {
if (viewportIds && viewportIds.length > 0) { if (viewportIds && viewportIds.length > 0) {
const chatsById = getGlobal().chats.byId;
const chatId = viewportIds[index === -1 ? 0 : index]; const chatId = viewportIds[index === -1 ? 0 : index];
const chat = chatsById?.[chatId]; const chat = chatsById[chatId];
if (chat?.isForum) { if (chat?.isForum) {
if (!chat.topics) loadTopics({ chatId }); if (!chat.topics) loadTopics({ chatId });
setForumId(chatId); setForumId(chatId);
@ -145,6 +149,7 @@ const ChatOrUserPicker: FC<OwnProps> = ({
}, '.ListItem-button', true); }, '.ListItem-button', true);
const handleClick = useLastCallback((e: React.MouseEvent, chatId: string) => { const handleClick = useLastCallback((e: React.MouseEvent, chatId: string) => {
const chatsById = getGlobal().chats.byId;
const chat = chatsById?.[chatId]; const chat = chatsById?.[chatId];
if (chat?.isForum) { if (chat?.isForum) {
if (!chat.topics) loadTopics({ chatId }); if (!chat.topics) loadTopics({ chatId });

View File

@ -14,7 +14,6 @@ import type {
ApiBotMenuButton, ApiBotMenuButton,
ApiChat, ApiChat,
ApiChatFullInfo, ApiChatFullInfo,
ApiChatMember,
ApiFormattedText, ApiFormattedText,
ApiMessage, ApiMessage,
ApiMessageEntity, ApiMessageEntity,
@ -191,6 +190,7 @@ type StateProps =
isOnActiveTab: boolean; isOnActiveTab: boolean;
editingMessage?: ApiMessage; editingMessage?: ApiMessage;
chat?: ApiChat; chat?: ApiChat;
chatFullInfo?: ApiChatFullInfo;
draft?: ApiDraft; draft?: ApiDraft;
replyToTopic?: ApiTopic; replyToTopic?: ApiTopic;
currentMessageList?: MessageList; currentMessageList?: MessageList;
@ -210,7 +210,6 @@ type StateProps =
canScheduleUntilOnline?: boolean; canScheduleUntilOnline?: boolean;
stickersForEmoji?: ApiSticker[]; stickersForEmoji?: ApiSticker[];
customEmojiForEmoji?: ApiSticker[]; customEmojiForEmoji?: ApiSticker[];
groupChatMembers?: ApiChatMember[];
currentUserId?: string; currentUserId?: string;
currentUser?: ApiUser; currentUser?: ApiUser;
recentEmojis: string[]; recentEmojis: string[];
@ -224,7 +223,6 @@ type StateProps =
inlineBots?: Record<string, false | InlineBotSettings>; inlineBots?: Record<string, false | InlineBotSettings>;
botCommands?: ApiBotCommand[] | false; botCommands?: ApiBotCommand[] | false;
botMenuButton?: ApiBotMenuButton; botMenuButton?: ApiBotMenuButton;
chatBotCommands?: ApiBotCommand[];
sendAsUser?: ApiUser; sendAsUser?: ApiUser;
sendAsChat?: ApiChat; sendAsChat?: ApiChat;
sendAsId?: string; sendAsId?: string;
@ -293,6 +291,7 @@ const Composer: FC<OwnProps & StateProps> = ({
messageListType, messageListType,
draft, draft,
chat, chat,
chatFullInfo,
replyToTopic, replyToTopic,
isForCurrentMessageList, isForCurrentMessageList,
isCurrentUserPremium, isCurrentUserPremium,
@ -312,7 +311,6 @@ const Composer: FC<OwnProps & StateProps> = ({
withScheduledButton, withScheduledButton,
stickersForEmoji, stickersForEmoji,
customEmojiForEmoji, customEmojiForEmoji,
groupChatMembers,
topInlineBotIds, topInlineBotIds,
currentUserId, currentUserId,
currentUser, currentUser,
@ -326,7 +324,6 @@ const Composer: FC<OwnProps & StateProps> = ({
inlineBots, inlineBots,
isInlineBotLoading, isInlineBotLoading,
botCommands, botCommands,
chatBotCommands,
sendAsUser, sendAsUser,
sendAsChat, sendAsChat,
sendAsId, sendAsId,
@ -405,6 +402,9 @@ const Composer: FC<OwnProps & StateProps> = ({
const canMediaBeReplaced = editingMessage && hasReplaceableMedia(editingMessage); const canMediaBeReplaced = editingMessage && hasReplaceableMedia(editingMessage);
const { emojiSet, members: groupChatMembers, botCommands: chatBotCommands } = chatFullInfo || {};
const chatEmojiSetId = emojiSet?.id;
const isSentStoryReactionHeart = sentStoryReaction && 'emoticon' in sentStoryReaction const isSentStoryReactionHeart = sentStoryReaction && 'emoticon' in sentStoryReaction
? sentStoryReaction.emoticon === HEART_REACTION.emoticon : false; ? sentStoryReaction.emoticon === HEART_REACTION.emoticon : false;
@ -457,8 +457,8 @@ const Composer: FC<OwnProps & StateProps> = ({
canSendStickers, canSendGifs, canAttachMedia, canAttachPolls, canAttachEmbedLinks, canSendStickers, canSendGifs, canAttachMedia, canAttachPolls, canAttachEmbedLinks,
canSendVoices, canSendPlainText, canSendAudios, canSendVideos, canSendPhotos, canSendDocuments, canSendVoices, canSendPlainText, canSendAudios, canSendVideos, canSendPhotos, canSendDocuments,
} = useMemo( } = useMemo(
() => getAllowedAttachmentOptions(chat, isChatWithBot, isInStoryViewer), () => getAllowedAttachmentOptions(chat, chatFullInfo, isChatWithBot, isInStoryViewer),
[chat, isChatWithBot, isInStoryViewer], [chat, chatFullInfo, isChatWithBot, isInStoryViewer],
); );
const isComposerBlocked = !canSendPlainText && !editingMessage; const isComposerBlocked = !canSendPlainText && !editingMessage;
@ -1088,7 +1088,8 @@ const Composer: FC<OwnProps & StateProps> = ({
}, [handleFileSelect, requestedDraftFiles, resetOpenChatWithDraft]); }, [handleFileSelect, requestedDraftFiles, resetOpenChatWithDraft]);
const handleCustomEmojiSelect = useLastCallback((emoji: ApiSticker, inInputId?: string) => { const handleCustomEmojiSelect = useLastCallback((emoji: ApiSticker, inInputId?: string) => {
if (!emoji.isFree && !isCurrentUserPremium && !isChatWithSelf) { const emojiSetId = 'id' in emoji.stickerSetInfo && emoji.stickerSetInfo.id;
if (!emoji.isFree && !isCurrentUserPremium && !isChatWithSelf && emojiSetId !== chatEmojiSetId) {
showCustomEmojiPremiumNotification(); showCustomEmojiPremiumNotification();
return; return;
} }
@ -2027,7 +2028,7 @@ export default memo(withGlobal<OwnProps>(
pollModal: tabState.pollModal, pollModal: tabState.pollModal,
stickersForEmoji: global.stickers.forEmoji.stickers, stickersForEmoji: global.stickers.forEmoji.stickers,
customEmojiForEmoji: global.customEmojis.forEmoji.stickers, customEmojiForEmoji: global.customEmojis.forEmoji.stickers,
groupChatMembers: chatFullInfo?.members, chatFullInfo,
topInlineBotIds: global.topInlineBots?.userIds, topInlineBotIds: global.topInlineBots?.userIds,
currentUserId, currentUserId,
currentUser, currentUser,
@ -2040,7 +2041,6 @@ export default memo(withGlobal<OwnProps>(
emojiKeywords: emojiKeywords?.keywords, emojiKeywords: emojiKeywords?.keywords,
inlineBots: tabState.inlineBots.byUsername, inlineBots: tabState.inlineBots.byUsername,
isInlineBotLoading: tabState.inlineBots.isLoading, isInlineBotLoading: tabState.inlineBots.isLoading,
chatBotCommands: chatFullInfo?.botCommands,
botCommands: chatBotFullInfo ? (chatBotFullInfo.botInfo?.commands || false) : undefined, botCommands: chatBotFullInfo ? (chatBotFullInfo.botInfo?.commands || false) : undefined,
botMenuButton: chatBotFullInfo?.botInfo?.menuButton, botMenuButton: chatBotFullInfo?.botInfo?.menuButton,
sendAsUser, sendAsUser,

View File

@ -10,10 +10,8 @@ import type {
import type { StickerSetOrReactionsSetOrRecent } from '../../types'; import type { StickerSetOrReactionsSetOrRecent } from '../../types';
import { import {
CHAT_STICKER_SET_ID,
FAVORITE_SYMBOL_SET_ID, FAVORITE_SYMBOL_SET_ID,
POPULAR_SYMBOL_SET_ID, POPULAR_SYMBOL_SET_ID,
PREMIUM_STICKER_SET_ID,
RECENT_SYMBOL_SET_ID, RECENT_SYMBOL_SET_ID,
SLIDE_TRANSITION_DURATION, SLIDE_TRANSITION_DURATION,
STICKER_PICKER_MAX_SHARED_COVERS, STICKER_PICKER_MAX_SHARED_COVERS,
@ -23,6 +21,7 @@ import {
import { isSameReaction } from '../../global/helpers'; import { isSameReaction } from '../../global/helpers';
import { import {
selectCanPlayAnimatedEmojis, selectCanPlayAnimatedEmojis,
selectChatFullInfo,
selectIsAlwaysHighPriorityEmoji, selectIsAlwaysHighPriorityEmoji,
selectIsChatWithSelf, selectIsChatWithSelf,
selectIsCurrentUserPremium, selectIsCurrentUserPremium,
@ -44,6 +43,7 @@ import { useStickerPickerObservers } from './hooks/useStickerPickerObservers';
import StickerSetCover from '../middle/composer/StickerSetCover'; import StickerSetCover from '../middle/composer/StickerSetCover';
import Button from '../ui/Button'; import Button from '../ui/Button';
import Loading from '../ui/Loading'; import Loading from '../ui/Loading';
import Icon from './Icon';
import StickerButton from './StickerButton'; import StickerButton from './StickerButton';
import StickerSet from './StickerSet'; import StickerSet from './StickerSet';
@ -73,6 +73,7 @@ type StateProps = {
customEmojisById?: Record<string, ApiSticker>; customEmojisById?: Record<string, ApiSticker>;
recentCustomEmojiIds?: string[]; recentCustomEmojiIds?: string[];
recentStatusEmojis?: ApiSticker[]; recentStatusEmojis?: ApiSticker[];
chatEmojiSetId?: string;
topReactions?: ApiReaction[]; topReactions?: ApiReaction[];
recentReactions?: ApiReaction[]; recentReactions?: ApiReaction[];
defaultTagReactions?: ApiReaction[]; defaultTagReactions?: ApiReaction[];
@ -97,8 +98,6 @@ const STICKER_SET_IDS_WITH_COVER = new Set([
RECENT_SYMBOL_SET_ID, RECENT_SYMBOL_SET_ID,
FAVORITE_SYMBOL_SET_ID, FAVORITE_SYMBOL_SET_ID,
POPULAR_SYMBOL_SET_ID, POPULAR_SYMBOL_SET_ID,
CHAT_STICKER_SET_ID,
PREMIUM_STICKER_SET_ID,
]); ]);
const CustomEmojiPicker: FC<OwnProps & StateProps> = ({ const CustomEmojiPicker: FC<OwnProps & StateProps> = ({
@ -112,6 +111,7 @@ const CustomEmojiPicker: FC<OwnProps & StateProps> = ({
selectedReactionIds, selectedReactionIds,
recentStatusEmojis, recentStatusEmojis,
stickerSetsById, stickerSetsById,
chatEmojiSetId,
topReactions, topReactions,
recentReactions, recentReactions,
availableReactions, availableReactions,
@ -250,7 +250,12 @@ const CustomEmojiPicker: FC<OwnProps & StateProps> = ({
}); });
} }
const setIdsToDisplay = unique((addedCustomEmojiIds || []).concat(customEmojiFeaturedIds || [])); const userSetIds = [...(addedCustomEmojiIds || [])];
if (chatEmojiSetId) {
userSetIds.unshift(chatEmojiSetId);
}
const setIdsToDisplay = unique(userSetIds.concat(customEmojiFeaturedIds || []));
const setsToDisplay = Object.values(pickTruthy(stickerSetsById, setIdsToDisplay)); const setsToDisplay = Object.values(pickTruthy(stickerSetsById, setIdsToDisplay));
@ -261,7 +266,7 @@ const CustomEmojiPicker: FC<OwnProps & StateProps> = ({
}, [ }, [
addedCustomEmojiIds, isReactionPicker, isStatusPicker, withDefaultTopicIcons, recentCustomEmojis, addedCustomEmojiIds, isReactionPicker, isStatusPicker, withDefaultTopicIcons, recentCustomEmojis,
customEmojiFeaturedIds, stickerSetsById, topReactions, availableReactions, lang, recentReactions, customEmojiFeaturedIds, stickerSetsById, topReactions, availableReactions, lang, recentReactions,
defaultStatusIconsId, defaultTopicIconsId, isSavedMessages, defaultTagReactions, defaultStatusIconsId, defaultTopicIconsId, isSavedMessages, defaultTagReactions, chatEmojiSetId,
]); ]);
const noPopulatedSets = useMemo(() => ( const noPopulatedSets = useMemo(() => (
@ -327,7 +332,7 @@ const CustomEmojiPicker: FC<OwnProps & StateProps> = ({
onClick={() => selectStickerSet(isRecent ? 0 : index)} onClick={() => selectStickerSet(isRecent ? 0 : index)}
> >
{isRecent ? ( {isRecent ? (
<i className="icon icon-recent" /> <Icon name="recent" />
) : ( ) : (
<StickerSetCover <StickerSetCover
stickerSet={stickerSet as ApiStickerSet} stickerSet={stickerSet as ApiStickerSet}
@ -407,6 +412,7 @@ const CustomEmojiPicker: FC<OwnProps & StateProps> = ({
{allSets.map((stickerSet, i) => { {allSets.map((stickerSet, i) => {
const shouldHideHeader = stickerSet.id === TOP_SYMBOL_SET_ID const shouldHideHeader = stickerSet.id === TOP_SYMBOL_SET_ID
|| (stickerSet.id === RECENT_SYMBOL_SET_ID && (withDefaultTopicIcons || isStatusPicker)); || (stickerSet.id === RECENT_SYMBOL_SET_ID && (withDefaultTopicIcons || isStatusPicker));
const isChatEmojiSet = stickerSet.id === chatEmojiSetId;
return ( return (
<StickerSet <StickerSet
@ -425,6 +431,7 @@ const CustomEmojiPicker: FC<OwnProps & StateProps> = ({
shouldHideHeader={shouldHideHeader} shouldHideHeader={shouldHideHeader}
withDefaultTopicIcon={withDefaultTopicIcons && stickerSet.id === RECENT_SYMBOL_SET_ID} withDefaultTopicIcon={withDefaultTopicIcons && stickerSet.id === RECENT_SYMBOL_SET_ID}
withDefaultStatusIcon={isStatusPicker && stickerSet.id === RECENT_SYMBOL_SET_ID} withDefaultStatusIcon={isStatusPicker && stickerSet.id === RECENT_SYMBOL_SET_ID}
isChatEmojiSet={isChatEmojiSet}
isCurrentUserPremium={isCurrentUserPremium} isCurrentUserPremium={isCurrentUserPremium}
selectedReactionIds={selectedReactionIds} selectedReactionIds={selectedReactionIds}
availableReactions={availableReactions} availableReactions={availableReactions}
@ -466,6 +473,7 @@ export default memo(withGlobal<OwnProps>(
} = global; } = global;
const isSavedMessages = Boolean(chatId && selectIsChatWithSelf(global, chatId)); const isSavedMessages = Boolean(chatId && selectIsChatWithSelf(global, chatId));
const chatFullInfo = chatId ? selectChatFullInfo(global, chatId) : undefined;
return { return {
customEmojisById: !isStatusPicker ? customEmojisById : undefined, customEmojisById: !isStatusPicker ? customEmojisById : undefined,
@ -481,6 +489,7 @@ export default memo(withGlobal<OwnProps>(
defaultStatusIconsId: global.defaultStatusIconsId, defaultStatusIconsId: global.defaultStatusIconsId,
topReactions: isReactionPicker ? topReactions : undefined, topReactions: isReactionPicker ? topReactions : undefined,
recentReactions: isReactionPicker ? recentReactions : undefined, recentReactions: isReactionPicker ? recentReactions : undefined,
chatEmojiSetId: chatFullInfo?.emojiSet?.id,
availableReactions: isReactionPicker ? availableReactions : undefined, availableReactions: isReactionPicker ? availableReactions : undefined,
defaultTagReactions: isReactionPicker ? defaultTags : undefined, defaultTagReactions: isReactionPicker ? defaultTags : undefined,
}; };

View File

@ -2,7 +2,7 @@ import type { FC } from '../../lib/teact/teact';
import React, { memo, useMemo, useState } from '../../lib/teact/teact'; import React, { memo, useMemo, useState } from '../../lib/teact/teact';
import { getGlobal, withGlobal } from '../../global'; import { getGlobal, withGlobal } from '../../global';
import type { ApiChat, ApiChatType } from '../../api/types'; import type { ApiChatType } from '../../api/types';
import type { ThreadId } from '../../types'; import type { ThreadId } from '../../types';
import { MAIN_THREAD_ID } from '../../api/types'; import { MAIN_THREAD_ID } from '../../api/types';
@ -35,7 +35,6 @@ export type OwnProps = {
type StateProps = { type StateProps = {
currentUserId?: string; currentUserId?: string;
chatsById: Record<string, ApiChat>;
activeListIds?: string[]; activeListIds?: string[];
archivedListIds?: string[]; archivedListIds?: string[];
pinnedIds?: string[]; pinnedIds?: string[];
@ -45,7 +44,6 @@ type StateProps = {
const RecipientPicker: FC<OwnProps & StateProps> = ({ const RecipientPicker: FC<OwnProps & StateProps> = ({
isOpen, isOpen,
currentUserId, currentUserId,
chatsById,
activeListIds, activeListIds,
archivedListIds, archivedListIds,
pinnedIds, pinnedIds,
@ -71,6 +69,8 @@ const RecipientPicker: FC<OwnProps & StateProps> = ({
// No need for expensive global updates on users, so we avoid them // No need for expensive global updates on users, so we avoid them
const global = getGlobal(); const global = getGlobal();
const usersById = global.users.byId; const usersById = global.users.byId;
const chatsById = global.chats.byId;
const chatFullInfoById = global.chats.fullInfoById;
const chatIds = [ const chatIds = [
...(activeListIds || []), ...(activeListIds || []),
@ -80,7 +80,7 @@ const RecipientPicker: FC<OwnProps & StateProps> = ({
const user = usersById[id]; const user = usersById[id];
if (user && isDeletedUser(user)) return false; if (user && isDeletedUser(user)) return false;
return chat && getCanPostInChat(chat, MAIN_THREAD_ID); return chat && getCanPostInChat(chat, MAIN_THREAD_ID, undefined, chatFullInfoById[id]);
}); });
const sorted = sortChatIds(unique([ const sorted = sortChatIds(unique([
@ -89,7 +89,7 @@ const RecipientPicker: FC<OwnProps & StateProps> = ({
]), undefined, priorityIds); ]), undefined, priorityIds);
return filterChatIdsByType(global, sorted, filter); return filterChatIdsByType(global, sorted, filter);
}, [pinnedIds, currentUserId, activeListIds, search, archivedListIds, lang, chatsById, contactIds, filter, isOpen]); }, [pinnedIds, currentUserId, activeListIds, search, archivedListIds, lang, contactIds, filter, isOpen]);
const renderingIds = useCurrentOrPrev(ids, true)!; const renderingIds = useCurrentOrPrev(ids, true)!;
@ -98,7 +98,6 @@ const RecipientPicker: FC<OwnProps & StateProps> = ({
isOpen={isOpen} isOpen={isOpen}
className={className} className={className}
chatOrUserIds={renderingIds} chatOrUserIds={renderingIds}
chatsById={chatsById}
searchPlaceholder={searchPlaceholder} searchPlaceholder={searchPlaceholder}
search={search} search={search}
onSearchChange={setSearch} onSearchChange={setSearch}
@ -114,7 +113,6 @@ export default memo(withGlobal<OwnProps>(
(global): StateProps => { (global): StateProps => {
const { const {
chats: { chats: {
byId: chatsById,
listIds, listIds,
orderedPinnedIds, orderedPinnedIds,
}, },
@ -122,7 +120,6 @@ export default memo(withGlobal<OwnProps>(
} = global; } = global;
return { return {
chatsById,
activeListIds: listIds.active, activeListIds: listIds.active,
archivedListIds: listIds.archived, archivedListIds: listIds.archived,
pinnedIds: orderedPinnedIds.active, pinnedIds: orderedPinnedIds.active,

View File

@ -32,6 +32,7 @@
vertical-align: bottom; vertical-align: bottom;
align-self: center; align-self: center;
justify-self: center; justify-self: center;
font-weight: 500;
} }
.sticker-locked { .sticker-locked {

View File

@ -38,6 +38,7 @@ type OwnProps<T> = {
canViewSet?: boolean; canViewSet?: boolean;
isSelected?: boolean; isSelected?: boolean;
isCurrentUserPremium?: boolean; isCurrentUserPremium?: boolean;
shouldIgnorePremium?: boolean;
sharedCanvasRef?: React.RefObject<HTMLCanvasElement>; sharedCanvasRef?: React.RefObject<HTMLCanvasElement>;
withTranslucentThumb?: boolean; withTranslucentThumb?: boolean;
forcePlayback?: boolean; forcePlayback?: boolean;
@ -76,6 +77,7 @@ const StickerButton = <T extends number | ApiSticker | ApiBotInlineMediaResult |
observeIntersectionForShowing, observeIntersectionForShowing,
isSelected, isSelected,
isCurrentUserPremium, isCurrentUserPremium,
shouldIgnorePremium,
noShowPremium, noShowPremium,
sharedCanvasRef, sharedCanvasRef,
withTranslucentThumb, withTranslucentThumb,
@ -101,7 +103,7 @@ const StickerButton = <T extends number | ApiSticker | ApiBotInlineMediaResult |
const { const {
id, isCustomEmoji, hasEffect: isPremium, stickerSetInfo, id, isCustomEmoji, hasEffect: isPremium, stickerSetInfo,
} = sticker; } = sticker;
const isLocked = !isCurrentUserPremium && isPremium; const isLocked = !isCurrentUserPremium && isPremium && !shouldIgnorePremium;
const isIntersecting = useIsIntersecting(ref, observeIntersection); const isIntersecting = useIsIntersecting(ref, observeIntersection);
const shouldLoad = isIntersecting; const shouldLoad = isIntersecting;

View File

@ -52,6 +52,8 @@ type OwnProps = {
selectedReactionIds?: string[]; selectedReactionIds?: string[];
withDefaultTopicIcon?: boolean; withDefaultTopicIcon?: boolean;
withDefaultStatusIcon?: boolean; withDefaultStatusIcon?: boolean;
isChatEmojiSet?: boolean;
isChatStickerSet?: boolean;
isTranslucent?: boolean; isTranslucent?: boolean;
noContextMenus?: boolean; noContextMenus?: boolean;
forcePlayback?: boolean; forcePlayback?: boolean;
@ -91,6 +93,8 @@ const StickerSet: FC<OwnProps> = ({
withDefaultTopicIcon, withDefaultTopicIcon,
selectedReactionIds, selectedReactionIds,
withDefaultStatusIcon, withDefaultStatusIcon,
isChatEmojiSet,
isChatStickerSet,
isTranslucent, isTranslucent,
noContextMenus, noContextMenus,
forcePlayback, forcePlayback,
@ -224,10 +228,11 @@ const StickerSet: FC<OwnProps> = ({
} }
}, [shouldRender, loadStickers, stickerSet]); }, [shouldRender, loadStickers, stickerSet]);
const isLocked = !isSavedMessages && !isCurrentUserPremium && isPremiumSet; const isLocked = !isSavedMessages && !isCurrentUserPremium && isPremiumSet && !isChatEmojiSet;
const isInstalled = stickerSet.installedDate && !stickerSet.isArchived; const isInstalled = stickerSet.installedDate && !stickerSet.isArchived;
const canCut = !isInstalled && stickerSet.id !== RECENT_SYMBOL_SET_ID && stickerSet.id !== POPULAR_SYMBOL_SET_ID; const canCut = !isInstalled && stickerSet.id !== RECENT_SYMBOL_SET_ID && stickerSet.id !== POPULAR_SYMBOL_SET_ID
&& !isChatEmojiSet && !isChatStickerSet;
const [isCut, , expand] = useFlag(canCut); const [isCut, , expand] = useFlag(canCut);
const itemsBeforeCutout = itemsPerRow * 3 - 1; const itemsBeforeCutout = itemsPerRow * 3 - 1;
const totalItemsCount = withDefaultTopicIcon ? stickerSet.count + 1 : stickerSet.count; const totalItemsCount = withDefaultTopicIcon ? stickerSet.count + 1 : stickerSet.count;
@ -240,7 +245,7 @@ const StickerSet: FC<OwnProps> = ({
const favoriteStickerIdsSet = useMemo(() => ( const favoriteStickerIdsSet = useMemo(() => (
favoriteStickers ? new Set(favoriteStickers.map(({ id }) => id)) : undefined favoriteStickers ? new Set(favoriteStickers.map(({ id }) => id)) : undefined
), [favoriteStickers]); ), [favoriteStickers]);
const withAddSetButton = !shouldHideHeader && !isRecent && isEmoji && !isPopular const withAddSetButton = !shouldHideHeader && !isRecent && isEmoji && !isPopular && !isChatEmojiSet
&& (!isInstalled || (!isCurrentUserPremium && !isSavedMessages)); && (!isInstalled || (!isCurrentUserPremium && !isSavedMessages));
const addSetButtonText = useMemo(() => { const addSetButtonText = useMemo(() => {
if (isLocked) { if (isLocked) {
@ -265,6 +270,9 @@ const StickerSet: FC<OwnProps> = ({
<p className={buildClassName('symbol-set-name', withAddSetButton && 'symbol-set-name-external')}> <p className={buildClassName('symbol-set-name', withAddSetButton && 'symbol-set-name-external')}>
{isLocked && <i className="symbol-set-locked-icon icon icon-lock-badge" />} {isLocked && <i className="symbol-set-locked-icon icon icon-lock-badge" />}
{stickerSet.title} {stickerSet.title}
{(isChatEmojiSet || isChatStickerSet) && (
<span className="symbol-set-chat">{lang(isChatEmojiSet ? 'GroupEmoji' : 'GroupStickers')}</span>
)}
{withAddSetButton && Boolean(stickerSet.stickers) && ( {withAddSetButton && Boolean(stickerSet.stickers) && (
<span className="symbol-set-amount"> <span className="symbol-set-amount">
{lang(isEmoji ? 'EmojiCount' : 'Stickers', stickerSet.stickers.length, 'i')} {lang(isEmoji ? 'EmojiCount' : 'Stickers', stickerSet.stickers.length, 'i')}
@ -360,6 +368,7 @@ const StickerSet: FC<OwnProps> = ({
canViewSet canViewSet
noContextMenu={noContextMenus} noContextMenu={noContextMenus}
isCurrentUserPremium={isCurrentUserPremium} isCurrentUserPremium={isCurrentUserPremium}
shouldIgnorePremium={isChatEmojiSet}
sharedCanvasRef={canvasRef} sharedCanvasRef={canvasRef}
withTranslucentThumb={isTranslucent} withTranslucentThumb={isTranslucent}
onClick={onStickerSelect} onClick={onStickerSelect}

View File

@ -12,6 +12,7 @@ import { getAllowedAttachmentOptions, getCanPostInChat } from '../../global/help
import { import {
selectCanScheduleUntilOnline, selectCanScheduleUntilOnline,
selectChat, selectChat,
selectChatFullInfo,
selectCurrentMessageList, selectCurrentMessageList,
selectIsChatWithSelf, selectIsChatWithSelf,
selectIsCurrentUserPremium, selectIsCurrentUserPremium,
@ -258,11 +259,13 @@ export default memo(withGlobal<OwnProps>(
const currentMessageList = selectCurrentMessageList(global); const currentMessageList = selectCurrentMessageList(global);
const { chatId, threadId } = currentMessageList || {}; const { chatId, threadId } = currentMessageList || {};
const chat = chatId && selectChat(global, chatId); const chat = chatId && selectChat(global, chatId);
const sendOptions = chat ? getAllowedAttachmentOptions(chat) : undefined; const chatFullInfo = chatId ? selectChatFullInfo(global, chatId) : undefined;
const sendOptions = chat ? getAllowedAttachmentOptions(chat, chatFullInfo) : undefined;
const threadInfo = chatId && threadId ? selectThreadInfo(global, chatId, threadId) : undefined; const threadInfo = chatId && threadId ? selectThreadInfo(global, chatId, threadId) : undefined;
const isMessageThread = Boolean(!threadInfo?.isCommentsInfo && threadInfo?.fromChannelId); const isMessageThread = Boolean(!threadInfo?.isCommentsInfo && threadInfo?.fromChannelId);
const canSendStickers = Boolean( const canSendStickers = Boolean(
chat && threadId && getCanPostInChat(chat, threadId, isMessageThread) && sendOptions?.canSendStickers, chat && threadId && getCanPostInChat(chat, threadId, isMessageThread, chatFullInfo)
&& sendOptions?.canSendStickers,
); );
const isSavedMessages = Boolean(chatId) && selectIsChatWithSelf(global, chatId); const isSavedMessages = Boolean(chatId) && selectIsChatWithSelf(global, chatId);

View File

@ -14,11 +14,14 @@ export function getBoostProgressInfo(boostInfo: ApiBoostsStatus, freezeOnLevelUp
: (boosts - currentLevelBoosts) / (nextLevelBoosts - currentLevelBoosts); : (boosts - currentLevelBoosts) / (nextLevelBoosts - currentLevelBoosts);
const remainingBoosts = nextLevelBoosts ? nextLevelBoosts - boosts : 0; const remainingBoosts = nextLevelBoosts ? nextLevelBoosts - boosts : 0;
const isMaxLevel = nextLevelBoosts === undefined;
return { return {
currentLevel, currentLevel,
hasNextLevel, hasNextLevel,
boosts, boosts,
levelProgress, levelProgress,
remainingBoosts, remainingBoosts,
isMaxLevel,
}; };
} }

View File

@ -7,7 +7,7 @@ import type { TabState } from '../../global/types';
import { MAIN_THREAD_ID } from '../../api/types'; import { MAIN_THREAD_ID } from '../../api/types';
import { getCanPostInChat } from '../../global/helpers'; import { getCanPostInChat } from '../../global/helpers';
import { selectChat } from '../../global/selectors'; import { selectChat, selectChatFullInfo } from '../../global/selectors';
import useInterval from '../../hooks/useInterval'; import useInterval from '../../hooks/useInterval';
import useLang from '../../hooks/useLang'; import useLang from '../../hooks/useLang';
@ -93,7 +93,8 @@ export default memo(withGlobal<OwnProps>(
(global, { openedGame }): StateProps => { (global, { openedGame }): StateProps => {
const { chatId } = openedGame || {}; const { chatId } = openedGame || {};
const chat = chatId && selectChat(global, chatId); const chat = chatId && selectChat(global, chatId);
const canPost = Boolean(chat) && getCanPostInChat(chat, MAIN_THREAD_ID); const chatFullInfo = chatId ? selectChatFullInfo(global, chatId) : undefined;
const canPost = Boolean(chat) && getCanPostInChat(chat, MAIN_THREAD_ID, undefined, chatFullInfo);
return { return {
canPost, canPost,

View File

@ -268,7 +268,6 @@ const Main: FC<OwnProps & StateProps> = ({
loadDefaultTagReactions, loadDefaultTagReactions,
loadFeaturedEmojiStickers, loadFeaturedEmojiStickers,
setIsElectronUpdateAvailable, setIsElectronUpdateAvailable,
loadPremiumSetStickers,
loadAuthorizations, loadAuthorizations,
loadPeerColors, loadPeerColors,
loadSavedReactionTags, loadSavedReactionTags,
@ -357,7 +356,6 @@ const Main: FC<OwnProps & StateProps> = ({
if (isMasterTab && isCurrentUserPremium) { if (isMasterTab && isCurrentUserPremium) {
loadDefaultStatusIcons(); loadDefaultStatusIcons();
loadRecentEmojiStatuses(); loadRecentEmojiStatuses();
loadPremiumSetStickers();
} }
}, [isCurrentUserPremium, isMasterTab]); }, [isCurrentUserPremium, isMasterTab]);

View File

@ -67,6 +67,7 @@ interface StateProps {
canMute?: boolean; canMute?: boolean;
canViewStatistics?: boolean; canViewStatistics?: boolean;
canViewBoosts?: boolean; canViewBoosts?: boolean;
canShowBoostModal?: boolean;
canLeave?: boolean; canLeave?: boolean;
canEnterVoiceChat?: boolean; canEnterVoiceChat?: boolean;
canCreateVoiceChat?: boolean; canCreateVoiceChat?: boolean;
@ -100,6 +101,7 @@ const HeaderActions: FC<OwnProps & StateProps> = ({
canMute, canMute,
canViewStatistics, canViewStatistics,
canViewBoosts, canViewBoosts,
canShowBoostModal,
canLeave, canLeave,
canEnterVoiceChat, canEnterVoiceChat,
canCreateVoiceChat, canCreateVoiceChat,
@ -433,6 +435,7 @@ const HeaderActions: FC<OwnProps & StateProps> = ({
canMute={canMute} canMute={canMute}
canViewStatistics={canViewStatistics} canViewStatistics={canViewStatistics}
canViewBoosts={canViewBoosts} canViewBoosts={canViewBoosts}
canShowBoostModal={canShowBoostModal}
canLeave={canLeave} canLeave={canLeave}
canEnterVoiceChat={canEnterVoiceChat} canEnterVoiceChat={canEnterVoiceChat}
canCreateVoiceChat={canCreateVoiceChat} canCreateVoiceChat={canCreateVoiceChat}
@ -456,6 +459,7 @@ export default memo(withGlobal<OwnProps>(
}): StateProps => { }): StateProps => {
const chat = selectChat(global, chatId); const chat = selectChat(global, chatId);
const isChannel = Boolean(chat && isChatChannel(chat)); const isChannel = Boolean(chat && isChatChannel(chat));
const isSuperGroup = Boolean(chat && isChatSuperGroup(chat));
const language = selectLanguageCode(global); const language = selectLanguageCode(global);
const translationLanguage = selectTranslationLanguage(global); const translationLanguage = selectTranslationLanguage(global);
const isPrivate = isUserId(chatId); const isPrivate = isUserId(chatId);
@ -486,7 +490,7 @@ export default memo(withGlobal<OwnProps>(
const canStartBot = !canRestartBot && Boolean(selectIsChatBotNotStarted(global, chatId)); const canStartBot = !canRestartBot && Boolean(selectIsChatBotNotStarted(global, chatId));
const canUnblock = isUserBlocked && !bot; const canUnblock = isUserBlocked && !bot;
const canSubscribe = Boolean( const canSubscribe = Boolean(
(isMainThread || chat.isForum) && (isChannel || isChatSuperGroup(chat)) && chat.isNotJoined, (isMainThread || chat.isForum) && (isChannel || isSuperGroup) && chat.isNotJoined,
); );
const canSearch = isMainThread || isDiscussionThread; const canSearch = isMainThread || isDiscussionThread;
const canCall = ARE_CALLS_SUPPORTED && isUserId(chat.id) && !isChatWithSelf && !bot && !chat.isSupport const canCall = ARE_CALLS_SUPPORTED && isUserId(chat.id) && !isChatWithSelf && !bot && !chat.isSupport
@ -498,6 +502,7 @@ export default memo(withGlobal<OwnProps>(
&& (chat.adminRights?.manageCall || (chat.isCreator && isChatBasicGroup(chat))); && (chat.adminRights?.manageCall || (chat.isCreator && isChatBasicGroup(chat)));
const canViewStatistics = isMainThread && chatFullInfo?.canViewStatistics; const canViewStatistics = isMainThread && chatFullInfo?.canViewStatistics;
const canViewBoosts = isMainThread && isChannel && (canViewStatistics || getHasAdminRight(chat, 'postStories')); const canViewBoosts = isMainThread && isChannel && (canViewStatistics || getHasAdminRight(chat, 'postStories'));
const canShowBoostModal = !canViewBoosts && (isSuperGroup || isChannel);
const pendingJoinRequests = isMainThread ? chatFullInfo?.requestsPending : undefined; const pendingJoinRequests = isMainThread ? chatFullInfo?.requestsPending : undefined;
const shouldJoinToSend = Boolean(chat?.isNotJoined && chat.isJoinToSend); const shouldJoinToSend = Boolean(chat?.isNotJoined && chat.isJoinToSend);
const shouldSendJoinRequest = Boolean(chat?.isNotJoined && chat.isJoinRequest); const shouldSendJoinRequest = Boolean(chat?.isNotJoined && chat.isJoinRequest);
@ -518,6 +523,7 @@ export default memo(withGlobal<OwnProps>(
canMute, canMute,
canViewStatistics, canViewStatistics,
canViewBoosts, canViewBoosts,
canShowBoostModal,
canLeave, canLeave,
canEnterVoiceChat, canEnterVoiceChat,
canCreateVoiceChat, canCreateVoiceChat,

View File

@ -84,6 +84,7 @@ export type OwnProps = {
canMute?: boolean; canMute?: boolean;
canViewStatistics?: boolean; canViewStatistics?: boolean;
canViewBoosts?: boolean; canViewBoosts?: boolean;
canShowBoostModal?: boolean;
withForumActions?: boolean; withForumActions?: boolean;
canLeave?: boolean; canLeave?: boolean;
canEnterVoiceChat?: boolean; canEnterVoiceChat?: boolean;
@ -166,6 +167,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
isBot, isBot,
isChatWithSelf, isChatWithSelf,
savedDialog, savedDialog,
canShowBoostModal,
onJoinRequestsClick, onJoinRequestsClick,
onSubscribeChannel, onSubscribeChannel,
onSearchClick, onSearchClick,
@ -195,6 +197,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
blockUser, blockUser,
unblockUser, unblockUser,
setViewForumAsMessages, setViewForumAsMessages,
openBoostModal,
} = getActions(); } = getActions();
const { isMobile } = useAppLayout(); const { isMobile } = useAppLayout();
@ -346,8 +349,12 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
}); });
const handleBoostClick = useLastCallback(() => { const handleBoostClick = useLastCallback(() => {
openBoostStatistics({ chatId }); if (canViewBoosts) {
setShouldCloseFast(!isRightColumnShown); openBoostStatistics({ chatId });
setShouldCloseFast(!isRightColumnShown);
} else {
openBoostModal({ chatId });
}
closeMenu(); closeMenu();
}); });
@ -522,6 +529,14 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
{lang(isChannel ? 'ProfileJoinChannel' : 'ProfileJoinGroup')} {lang(isChannel ? 'ProfileJoinChannel' : 'ProfileJoinGroup')}
</MenuItem> </MenuItem>
)} )}
{canShowBoostModal && !canViewBoosts && (
<MenuItem
icon="boost-outline"
onClick={handleBoostClick}
>
{lang(isChannel ? 'BoostingBoostChannelMenu' : 'BoostingBoostGroupMenu')}
</MenuItem>
)}
{canAddContact && ( {canAddContact && (
<MenuItem <MenuItem
icon="add-user" icon="add-user"
@ -589,7 +604,7 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
)} )}
{canViewBoosts && ( {canViewBoosts && (
<MenuItem <MenuItem
icon="boost" icon="boost-outline"
onClick={handleBoostClick} onClick={handleBoostClick}
> >
{lang('Boosts')} {lang('Boosts')}

View File

@ -763,10 +763,11 @@ export default memo(withGlobal<OwnProps>(
const bot = selectBot(global, chatId); const bot = selectBot(global, chatId);
const pinnedIds = selectPinnedIds(global, chatId, threadId); const pinnedIds = selectPinnedIds(global, chatId, threadId);
const { chatId: audioChatId, messageId: audioMessageId } = audioPlayer; const { chatId: audioChatId, messageId: audioMessageId } = audioPlayer;
const chatFullInfo = chatId ? selectChatFullInfo(global, chatId) : undefined;
const threadInfo = selectThreadInfo(global, chatId, threadId); const threadInfo = selectThreadInfo(global, chatId, threadId);
const isMessageThread = Boolean(!threadInfo?.isCommentsInfo && threadInfo?.fromChannelId); const isMessageThread = Boolean(!threadInfo?.isCommentsInfo && threadInfo?.fromChannelId);
const canPost = chat && getCanPostInChat(chat, threadId, isMessageThread); const canPost = chat && getCanPostInChat(chat, threadId, isMessageThread, chatFullInfo);
const isBotNotStarted = selectIsChatBotNotStarted(global, chatId); const isBotNotStarted = selectIsChatBotNotStarted(global, chatId);
const isPinnedMessageList = messageListType === 'pinned'; const isPinnedMessageList = messageListType === 'pinned';
const isMainThread = messageListType === 'thread' && threadId === MAIN_THREAD_ID; const isMainThread = messageListType === 'thread' && threadId === MAIN_THREAD_ID;
@ -781,7 +782,7 @@ export default memo(withGlobal<OwnProps>(
const canStartBot = !canRestartBot && isBotNotStarted; const canStartBot = !canRestartBot && isBotNotStarted;
const canUnblock = isUserBlocked && !bot; const canUnblock = isUserBlocked && !bot;
const shouldLoadFullChat = Boolean( const shouldLoadFullChat = Boolean(
chat && isChatGroup(chat) && !selectChatFullInfo(global, chat.id), chat && isChatGroup(chat) && !chatFullInfo,
); );
const draftReplyInfo = selectDraft(global, chatId, threadId)?.replyInfo; const draftReplyInfo = selectDraft(global, chatId, threadId)?.replyInfo;
const shouldBlockSendInForum = chat?.isForum const shouldBlockSendInForum = chat?.isForum

View File

@ -11,7 +11,6 @@ import type { StickerSetOrReactionsSetOrRecent, ThreadId } from '../../../types'
import { import {
CHAT_STICKER_SET_ID, CHAT_STICKER_SET_ID,
FAVORITE_SYMBOL_SET_ID, FAVORITE_SYMBOL_SET_ID,
PREMIUM_STICKER_SET_ID,
RECENT_SYMBOL_SET_ID, RECENT_SYMBOL_SET_ID,
SLIDE_TRANSITION_DURATION, SLIDE_TRANSITION_DURATION,
STICKER_PICKER_MAX_SHARED_COVERS, STICKER_PICKER_MAX_SHARED_COVERS,
@ -23,7 +22,7 @@ import {
} from '../../../global/selectors'; } from '../../../global/selectors';
import animateHorizontalScroll from '../../../util/animateHorizontalScroll'; import animateHorizontalScroll from '../../../util/animateHorizontalScroll';
import buildClassName from '../../../util/buildClassName'; import buildClassName from '../../../util/buildClassName';
import { pickTruthy, uniqueByField } from '../../../util/iteratees'; import { pickTruthy } from '../../../util/iteratees';
import { MEMO_EMPTY_ARRAY } from '../../../util/memo'; import { MEMO_EMPTY_ARRAY } from '../../../util/memo';
import { IS_TOUCH_ENV } from '../../../util/windowEnvironment'; import { IS_TOUCH_ENV } from '../../../util/windowEnvironment';
import { REM } from '../../common/helpers/mediaDimensions'; import { REM } from '../../common/helpers/mediaDimensions';
@ -37,7 +36,6 @@ import { useStickerPickerObservers } from '../../common/hooks/useStickerPickerOb
import useAsyncRendering from '../../right/hooks/useAsyncRendering'; import useAsyncRendering from '../../right/hooks/useAsyncRendering';
import Avatar from '../../common/Avatar'; import Avatar from '../../common/Avatar';
import PremiumIcon from '../../common/PremiumIcon';
import StickerButton from '../../common/StickerButton'; import StickerButton from '../../common/StickerButton';
import StickerSet from '../../common/StickerSet'; import StickerSet from '../../common/StickerSet';
import Button from '../../ui/Button'; import Button from '../../ui/Button';
@ -65,7 +63,6 @@ type StateProps = {
chat?: ApiChat; chat?: ApiChat;
recentStickers: ApiSticker[]; recentStickers: ApiSticker[];
favoriteStickers: ApiSticker[]; favoriteStickers: ApiSticker[];
premiumStickers: ApiSticker[];
stickerSetsById: Record<string, ApiStickerSet>; stickerSetsById: Record<string, ApiStickerSet>;
chatStickerSetId?: string; chatStickerSetId?: string;
addedSetIds?: string[]; addedSetIds?: string[];
@ -86,7 +83,6 @@ const StickerPicker: FC<OwnProps & StateProps> = ({
canSendStickers, canSendStickers,
recentStickers, recentStickers,
favoriteStickers, favoriteStickers,
premiumStickers,
addedSetIds, addedSetIds,
stickerSetsById, stickerSetsById,
chatStickerSetId, chatStickerSetId,
@ -140,8 +136,6 @@ const StickerPicker: FC<OwnProps & StateProps> = ({
const defaultSets = []; const defaultSets = [];
const existingAddedSetIds = Object.values(pickTruthy(stickerSetsById, addedSetIds));
if (favoriteStickers.length) { if (favoriteStickers.length) {
defaultSets.push({ defaultSets.push({
id: FAVORITE_SYMBOL_SET_ID, id: FAVORITE_SYMBOL_SET_ID,
@ -162,46 +156,18 @@ const StickerPicker: FC<OwnProps & StateProps> = ({
}); });
} }
if (isCurrentUserPremium) { const userSetIds = [...(addedSetIds || [])];
const addedPremiumStickers = existingAddedSetIds
.map(({ stickers }) => stickers?.filter((sticker) => sticker.hasEffect))
.flat()
.filter(Boolean);
const totalPremiumStickers = uniqueByField([...addedPremiumStickers, ...premiumStickers], 'id');
if (totalPremiumStickers.length) {
defaultSets.push({
id: PREMIUM_STICKER_SET_ID,
accessHash: '0',
title: lang('PremiumStickers'),
stickers: totalPremiumStickers,
count: totalPremiumStickers.length,
});
}
}
if (chatStickerSetId) { if (chatStickerSetId) {
const fullSet = stickerSetsById[chatStickerSetId]; userSetIds.unshift(chatStickerSetId);
if (fullSet) {
defaultSets.push({
id: CHAT_STICKER_SET_ID,
accessHash: fullSet.accessHash,
title: lang('GroupStickers'),
stickers: fullSet.stickers,
count: fullSet.stickers!.length,
});
}
} }
const existingAddedSetIds = Object.values(pickTruthy(stickerSetsById, userSetIds));
return [ return [
...defaultSets, ...defaultSets,
...existingAddedSetIds, ...existingAddedSetIds,
]; ];
}, [ }, [addedSetIds, stickerSetsById, favoriteStickers, recentStickers, chatStickerSetId, lang]);
addedSetIds, stickerSetsById, favoriteStickers, recentStickers, isCurrentUserPremium, chatStickerSetId, lang,
premiumStickers,
]);
const noPopulatedSets = useMemo(() => ( const noPopulatedSets = useMemo(() => (
areAddedLoaded areAddedLoaded
@ -266,7 +232,6 @@ const StickerPicker: FC<OwnProps & StateProps> = ({
if (stickerSet.id === RECENT_SYMBOL_SET_ID if (stickerSet.id === RECENT_SYMBOL_SET_ID
|| stickerSet.id === FAVORITE_SYMBOL_SET_ID || stickerSet.id === FAVORITE_SYMBOL_SET_ID
|| stickerSet.id === CHAT_STICKER_SET_ID || stickerSet.id === CHAT_STICKER_SET_ID
|| stickerSet.id === PREMIUM_STICKER_SET_ID
|| stickerSet.hasThumbnail || stickerSet.hasThumbnail
|| !firstSticker || !firstSticker
) { ) {
@ -281,9 +246,7 @@ const StickerPicker: FC<OwnProps & StateProps> = ({
// eslint-disable-next-line react/jsx-no-bind // eslint-disable-next-line react/jsx-no-bind
onClick={() => selectStickerSet(index)} onClick={() => selectStickerSet(index)}
> >
{stickerSet.id === PREMIUM_STICKER_SET_ID ? ( {stickerSet.id === RECENT_SYMBOL_SET_ID ? (
<PremiumIcon withGradient big />
) : stickerSet.id === RECENT_SYMBOL_SET_ID ? (
<i className="icon icon-recent" /> <i className="icon icon-recent" />
) : stickerSet.id === FAVORITE_SYMBOL_SET_ID ? ( ) : stickerSet.id === FAVORITE_SYMBOL_SET_ID ? (
<i className="icon icon-favorite" /> <i className="icon icon-favorite" />
@ -374,6 +337,7 @@ const StickerPicker: FC<OwnProps & StateProps> = ({
isSavedMessages={isSavedMessages} isSavedMessages={isSavedMessages}
isCurrentUserPremium={isCurrentUserPremium} isCurrentUserPremium={isCurrentUserPremium}
isTranslucent={isTranslucent} isTranslucent={isTranslucent}
isChatStickerSet={stickerSet.id === chatStickerSetId}
onStickerSelect={handleStickerSelect} onStickerSelect={handleStickerSelect}
onStickerUnfave={handleStickerUnfave} onStickerUnfave={handleStickerUnfave}
onStickerFave={handleStickerFave} onStickerFave={handleStickerFave}
@ -393,7 +357,6 @@ export default memo(withGlobal<OwnProps>(
added, added,
recent, recent,
favorite, favorite,
premiumSet,
} = global.stickers; } = global.stickers;
const isSavedMessages = selectIsChatWithSelf(global, chatId); const isSavedMessages = selectIsChatWithSelf(global, chatId);
@ -404,7 +367,6 @@ export default memo(withGlobal<OwnProps>(
chat, chat,
recentStickers: recent.stickers, recentStickers: recent.stickers,
favoriteStickers: favorite.stickers, favoriteStickers: favorite.stickers,
premiumStickers: premiumSet.stickers,
stickerSetsById: setsById, stickerSetsById: setsById,
addedSetIds: added.setIds, addedSetIds: added.setIds,
canAnimate: selectShouldLoopStickers(global), canAnimate: selectShouldLoopStickers(global),

View File

@ -222,6 +222,14 @@
} }
} }
&-chat {
background-color: var(--color-text-secondary);
color: var(--color-background);
border-radius: 0.5rem;
padding-inline: 0.25rem;
margin-inline-start: 0.5rem;
}
&-locked-icon { &-locked-icon {
margin-right: 0.25rem; margin-right: 0.25rem;
} }

View File

@ -81,6 +81,7 @@ import {
selectIsMessageSelected, selectIsMessageSelected,
selectMessageIdsByGroupId, selectMessageIdsByGroupId,
selectOutgoingStatus, selectOutgoingStatus,
selectPeer,
selectPeerStory, selectPeerStory,
selectPerformanceSettingsValue, selectPerformanceSettingsValue,
selectReplySender, selectReplySender,
@ -222,7 +223,7 @@ type StateProps = {
replyMessageChat?: ApiChat; replyMessageChat?: ApiChat;
isReplyPrivate?: boolean; isReplyPrivate?: boolean;
replyStory?: ApiTypeStory; replyStory?: ApiTypeStory;
storySender?: ApiUser; storySender?: ApiPeer;
outgoingStatus?: ApiMessageOutgoingStatus; outgoingStatus?: ApiMessageOutgoingStatus;
uploadProgress?: number; uploadProgress?: number;
isInDocumentGroup: boolean; isInDocumentGroup: boolean;
@ -279,7 +280,9 @@ type StateProps = {
isConnected: boolean; isConnected: boolean;
isLoadingComments?: boolean; isLoadingComments?: boolean;
shouldWarnAboutSvg?: boolean; shouldWarnAboutSvg?: boolean;
senderBoosts?: number;
tags?: Record<ApiReactionKey, ApiSavedReactionTag>; tags?: Record<ApiReactionKey, ApiSavedReactionTag>;
canTranscribeVoice?: boolean;
}; };
type MetaPosition = type MetaPosition =
@ -394,7 +397,9 @@ const Message: FC<OwnProps & StateProps> = ({
isConnected, isConnected,
getIsMessageListReady, getIsMessageListReady,
shouldWarnAboutSvg, shouldWarnAboutSvg,
senderBoosts,
tags, tags,
canTranscribeVoice,
onPinnedIntersectionChange, onPinnedIntersectionChange,
}) => { }) => {
const { const {
@ -655,7 +660,7 @@ const Message: FC<OwnProps & StateProps> = ({
} = getMessageContent(message); } = getMessageContent(message);
const { replyToMsgId, replyToPeerId, isQuote } = messageReplyInfo || {}; const { replyToMsgId, replyToPeerId, isQuote } = messageReplyInfo || {};
const { userId: storyReplyUserId, storyId: storyReplyId } = storyReplyInfo || {}; const { peerId: storyReplyPeerId, storyId: storyReplyId } = storyReplyInfo || {};
const detectedLanguage = useTextLanguage( const detectedLanguage = useTextLanguage(
text?.text, text?.text,
@ -739,7 +744,7 @@ const Message: FC<OwnProps & StateProps> = ({
); );
useEnsureStory( useEnsureStory(
storyReplyUserId || chatId, storyReplyPeerId || chatId,
storyReplyId, storyReplyId,
replyStory, replyStory,
); );
@ -1132,7 +1137,7 @@ const Message: FC<OwnProps & StateProps> = ({
isTranscriptionError={isTranscriptionError} isTranscriptionError={isTranscriptionError}
canDownload={!isProtected} canDownload={!isProtected}
onHideTranscription={setTranscriptionHidden} onHideTranscription={setTranscriptionHidden}
canTranscribe={isPremium && !hasTtl} canTranscribe={canTranscribeVoice && !hasTtl}
/> />
)} )}
{document && ( {document && (
@ -1312,6 +1317,7 @@ const Message: FC<OwnProps & StateProps> = ({
</span> </span>
</> </>
)} )}
<div className="title-spacer" />
{forwardInfo?.isLinkedChannelPost ? ( {forwardInfo?.isLinkedChannelPost ? (
<span className="admin-title" dir="auto">{lang('DiscussChannel')}</span> <span className="admin-title" dir="auto">{lang('DiscussChannel')}</span>
) : message.forwardInfo?.postAuthorTitle && isGroup && asForwarded ? ( ) : message.forwardInfo?.postAuthorTitle && isGroup && asForwarded ? (
@ -1325,6 +1331,12 @@ const Message: FC<OwnProps & StateProps> = ({
)} )}
</span> </span>
) : undefined} ) : undefined}
{Boolean(senderBoosts) && (
<span className="sender-boosts" aria-hidden>
<Icon name={senderBoosts > 1 ? 'boosts' : 'boost'} />
{senderBoosts > 1 ? senderBoosts : undefined}
</span>
)}
</div> </div>
); );
} }
@ -1499,7 +1511,7 @@ export default memo(withGlobal<OwnProps>(
const isThreadTop = message.id === threadId; const isThreadTop = message.id === threadId;
const { replyToMsgId, replyToPeerId, replyFrom } = getMessageReplyInfo(message) || {}; const { replyToMsgId, replyToPeerId, replyFrom } = getMessageReplyInfo(message) || {};
const { userId: storyReplyUserId, storyId: storyReplyId } = getStoryReplyInfo(message) || {}; const { peerId: storyReplyPeerId, storyId: storyReplyId } = getStoryReplyInfo(message) || {};
const shouldHideReply = replyToMsgId && replyToMsgId === threadId; const shouldHideReply = replyToMsgId && replyToMsgId === threadId;
const replyMessage = replyToMsgId ? selectChatMessage(global, replyToPeerId || chatId, replyToMsgId) : undefined; const replyMessage = replyToMsgId ? selectChatMessage(global, replyToPeerId || chatId, replyToMsgId) : undefined;
@ -1512,10 +1524,10 @@ export default memo(withGlobal<OwnProps>(
const isReplyPrivate = !isRepliesChat && !isAnonymousForwards && replyMessageChat && !isChatPublic(replyMessageChat) const isReplyPrivate = !isRepliesChat && !isAnonymousForwards && replyMessageChat && !isChatPublic(replyMessageChat)
&& (replyMessageChat.isNotJoined || replyMessageChat.isRestricted); && (replyMessageChat.isNotJoined || replyMessageChat.isRestricted);
const isReplyToTopicStart = replyMessage?.content.action?.type === 'topicCreate'; const isReplyToTopicStart = replyMessage?.content.action?.type === 'topicCreate';
const replyStory = storyReplyId && storyReplyUserId const replyStory = storyReplyId && storyReplyPeerId
? selectPeerStory(global, storyReplyUserId, storyReplyId) ? selectPeerStory(global, storyReplyPeerId, storyReplyId)
: undefined; : undefined;
const storySender = storyReplyUserId ? selectUser(global, storyReplyUserId) : undefined; const storySender = storyReplyPeerId ? selectPeer(global, storyReplyPeerId) : undefined;
const uploadProgress = selectUploadProgress(global, message); const uploadProgress = selectUploadProgress(global, message);
const isFocused = messageListType === 'thread' && ( const isFocused = messageListType === 'thread' && (
@ -1572,6 +1584,14 @@ export default memo(withGlobal<OwnProps>(
const hasActiveReactions = Boolean(reactionMessage && activeReactions[getMessageKey(reactionMessage)]?.length); const hasActiveReactions = Boolean(reactionMessage && activeReactions[getMessageKey(reactionMessage)]?.length);
const isPremium = selectIsCurrentUserPremium(global);
const senderBoosts = sender && selectIsChatWithSelf(global, sender.id)
? (chatFullInfo?.boostsApplied ?? message.senderBoosts) : message.senderBoosts;
const chatLevel = chat?.boostLevel || 0;
const transcribeMinLevel = global.appConfig?.groupTranscribeLevelMin;
const canTranscribeVoice = isPremium || Boolean(transcribeMinLevel && chatLevel >= transcribeMinLevel);
return { return {
theme: selectTheme(global), theme: selectTheme(global),
forceSenderName, forceSenderName,
@ -1627,7 +1647,7 @@ export default memo(withGlobal<OwnProps>(
hasUnreadReaction, hasUnreadReaction,
isTranscribing: transcriptionId !== undefined && global.transcriptions[transcriptionId]?.isPending, isTranscribing: transcriptionId !== undefined && global.transcriptions[transcriptionId]?.isPending,
transcribedText: transcriptionId !== undefined ? global.transcriptions[transcriptionId]?.text : undefined, transcribedText: transcriptionId !== undefined ? global.transcriptions[transcriptionId]?.text : undefined,
isPremium: selectIsCurrentUserPremium(global), isPremium,
senderAdminMember, senderAdminMember,
messageTopic, messageTopic,
hasTopicChip, hasTopicChip,
@ -1652,7 +1672,9 @@ export default memo(withGlobal<OwnProps>(
isResizingContainer, isResizingContainer,
focusedQuote, focusedQuote,
}), }),
senderBoosts,
tags: global.savedReactionTags?.byKey, tags: global.savedReactionTags?.byKey,
canTranscribeVoice,
}; };
}, },
)(Message)); )(Message));

View File

@ -325,19 +325,32 @@
margin-left: 0.25rem; margin-left: 0.25rem;
} }
.title-spacer {
flex-grow: 1;
}
.admin-title { .admin-title {
flex: 1;
margin-left: 1rem; margin-left: 1rem;
text-align: right; text-align: right;
font-weight: 400; font-weight: 400;
font-size: 0.75rem; font-size: 0.75rem;
margin-top: -0.125rem; margin-top: -0.125rem;
color: rgba(var(--color-text-meta-rgb), 0.75); color: rgba(var(--color-text-meta-rgb), 0.75);
user-select: none;
.Message.own & { .Message.own & {
color: var(--accent-color); color: var(--accent-color);
} }
} }
.sender-boosts {
display: flex;
align-items: center;
font-size: 0.75rem;
margin-top: -0.125rem;
margin-inline-start: 0.125rem;
user-select: none;
}
} }
.message-subheader { .message-subheader {

View File

@ -27,6 +27,7 @@ export function getWebpageButtonText(type?: string) {
case 'telegram_story': case 'telegram_story':
return 'lng_view_button_story'; return 'lng_view_button_story';
case 'telegram_channel_boost': case 'telegram_channel_boost':
case 'telegram_group_boost':
return 'lng_view_button_boost'; return 'lng_view_button_boost';
default: default:
return undefined; return undefined;

View File

@ -27,6 +27,12 @@
.description { .description {
padding: 0.5rem; padding: 0.5rem;
line-height: 1.25; line-height: 1.25;
text-align: center;
text-wrap: balance;
}
.bold {
font-weight: 500;
} }
.chip { .chip {

View File

@ -1,11 +1,12 @@
import React, { memo, useMemo } from '../../../lib/teact/teact'; import React, { memo, useEffect, useMemo } from '../../../lib/teact/teact';
import { getActions, withGlobal } from '../../../global'; import { getActions, withGlobal } from '../../../global';
import type { ApiChat, ApiMyBoost } from '../../../api/types'; import type { ApiChat, ApiChatFullInfo, ApiMyBoost } from '../../../api/types';
import type { TabState } from '../../../global/types'; import type { TabState } from '../../../global/types';
import { getChatTitle } from '../../../global/helpers'; import { getChatTitle, isChatAdmin, isChatChannel } from '../../../global/helpers';
import { selectChat, selectIsCurrentUserPremium } from '../../../global/selectors'; import { selectChat, selectChatFullInfo, selectIsCurrentUserPremium } from '../../../global/selectors';
import buildClassName from '../../../util/buildClassName';
import { formatDateInFuture } from '../../../util/dateFormat'; import { formatDateInFuture } from '../../../util/dateFormat';
import { getServerTime } from '../../../util/serverTime'; import { getServerTime } from '../../../util/serverTime';
import { getBoostProgressInfo } from '../../common/helpers/boostInfo'; import { getBoostProgressInfo } from '../../common/helpers/boostInfo';
@ -50,14 +51,16 @@ export type OwnProps = {
type StateProps = { type StateProps = {
chat?: ApiChat; chat?: ApiChat;
boostedChat?: ApiChat; chatFullInfo?: ApiChatFullInfo;
prevBoostedChat?: ApiChat;
isCurrentUserPremium?: boolean; isCurrentUserPremium?: boolean;
}; };
const BoostModal = ({ const BoostModal = ({
info, info,
chat, chat,
boostedChat, chatFullInfo,
prevBoostedChat,
isCurrentUserPremium, isCurrentUserPremium,
}: OwnProps & StateProps) => { }: OwnProps & StateProps) => {
const { const {
@ -65,16 +68,25 @@ const BoostModal = ({
closeBoostModal, closeBoostModal,
requestConfetti, requestConfetti,
openPremiumModal, openPremiumModal,
loadFullChat,
} = getActions(); } = getActions();
const [isReplaceModalOpen, openReplaceModal, closeReplaceModal] = useFlag(); const [isReplaceModalOpen, openReplaceModal, closeReplaceModal] = useFlag();
const [isWaitDialogOpen, openWaitDialog, closeWaitDialog] = useFlag(); const [isWaitDialogOpen, openWaitDialog, closeWaitDialog] = useFlag();
const [isPremiumDialogOpen, openPremiumDialog, closePremiumDialog] = useFlag(); const [isPremiumDialogOpen, openPremiumDialog, closePremiumDialog] = useFlag();
const isChannel = chat && isChatChannel(chat);
const isOpen = Boolean(info); const isOpen = Boolean(info);
const lang = useLang(); const lang = useLang();
useEffect(() => {
if (chat && !chatFullInfo) {
loadFullChat({ chatId: chat.id });
}
}, [chat, chatFullInfo]);
const chatTitle = useMemo(() => { const chatTitle = useMemo(() => {
if (!chat) { if (!chat) {
return undefined; return undefined;
@ -84,12 +96,12 @@ const BoostModal = ({
}, [chat, lang]); }, [chat, lang]);
const boostedChatTitle = useMemo(() => { const boostedChatTitle = useMemo(() => {
if (!boostedChat) { if (!prevBoostedChat) {
return undefined; return undefined;
} }
return getChatTitle(lang, boostedChat); return getChatTitle(lang, prevBoostedChat);
}, [boostedChat, lang]); }, [prevBoostedChat, lang]);
const { const {
isStatusLoaded, isStatusLoaded,
@ -111,7 +123,7 @@ const BoostModal = ({
} }
const { const {
level, currentLevelBoosts, hasMyBoost, hasMyBoost,
} = info.boostStatus; } = info.boostStatus;
const firstBoost = info?.myBoosts && getFirstAvailableBoost(info.myBoosts, chat.id); const firstBoost = info?.myBoosts && getFirstAvailableBoost(info.myBoosts, chat.id);
@ -123,36 +135,28 @@ const BoostModal = ({
hasNextLevel, hasNextLevel,
levelProgress, levelProgress,
remainingBoosts, remainingBoosts,
isMaxLevel,
} = getBoostProgressInfo(info.boostStatus, true); } = getBoostProgressInfo(info.boostStatus, true);
const hasBoost = hasMyBoost; const hasBoost = hasMyBoost;
const isJustUpgraded = boosts === currentLevelBoosts && hasBoost;
const left = lang('BoostsLevel', currentLevel); const left = lang('BoostsLevel', currentLevel);
const right = hasNextLevel ? lang('BoostsLevel', currentLevel + 1) : undefined; const right = hasNextLevel ? lang('BoostsLevel', currentLevel + 1) : undefined;
const moreBoosts = lang('ChannelBoost.MoreBoosts', remainingBoosts); const moreBoosts = lang('ChannelBoost.MoreBoosts', remainingBoosts);
const currentStoriesPerDay = lang('ChannelBoost.StoriesPerDay', level);
const nextLevelStoriesPerDay = lang('ChannelBoost.StoriesPerDay', level + 1);
const modalTitle = hasBoost ? lang('YouBoostedChannel2', chatTitle) const modalTitle = isChannel ? lang('BoostChannel') : lang('BoostGroup');
: level === 0 ? lang('lng_boost_channel_title_first') : lang('lng_boost_channel_title_more');
const boostsLeftToUnrestrict = (chatFullInfo?.boostsToUnrestrict || 0) - (chatFullInfo?.boostsApplied || 0);
let description: string | undefined; let description: string | undefined;
if (level === 0) { if (isMaxLevel) {
if (!hasBoost) { description = lang('BoostsMaxLevelReached');
description = lang('ChannelBoost.EnableStoriesForChannelText', [chatTitle, moreBoosts]); } else if (boostsLeftToUnrestrict > 0 && !isChatAdmin(chat)) {
} else { const boostTimes = lang('GroupBoost.BoostToUnrestrict.Times', boostsLeftToUnrestrict);
description = lang('ChannelBoost.EnableStoriesMoreRequired', moreBoosts); description = lang('GroupBoost.BoostToUnrestrict', [boostTimes, chatTitle]);
}
} else if (isJustUpgraded) {
if (level === 1) {
description = lang('ChannelBoost.EnabledStoriesForChannelText');
} else {
description = lang('ChannelBoost.BoostedChannelReachedLevel', [level, currentStoriesPerDay]);
}
} else { } else {
description = lang('ChannelBoost.HelpUpgradeChannelText', [chatTitle, moreBoosts, nextLevelStoriesPerDay]); description = lang('ChannelBoost.MoreBoostsNeeded.Text', [chatTitle, moreBoosts]);
} }
return { return {
@ -166,9 +170,9 @@ const BoostModal = ({
descriptionText: description, descriptionText: description,
boost: firstBoost, boost: firstBoost,
isBoosted: hasBoost, isBoosted: hasBoost,
canBoostMore: areBoostsInDifferentChannels, canBoostMore: areBoostsInDifferentChannels && !isMaxLevel,
}; };
}, [chat, chatTitle, info, lang]); }, [chat, chatTitle, info, lang, chatFullInfo, isChannel]);
const isBoostDisabled = !info?.myBoosts?.length && isCurrentUserPremium; const isBoostDisabled = !info?.myBoosts?.length && isCurrentUserPremium;
const isReplacingBoost = boost?.chatId && boost.chatId !== info?.chatId; const isReplacingBoost = boost?.chatId && boost.chatId !== info?.chatId;
@ -189,6 +193,7 @@ const BoostModal = ({
if (!boost) { if (!boost) {
if (!isCurrentUserPremium) { if (!isCurrentUserPremium) {
openPremiumDialog(); openPremiumDialog();
return;
} }
closeBoostModal(); closeBoostModal();
@ -231,6 +236,11 @@ const BoostModal = ({
floatingBadgeText={value} floatingBadgeText={value}
floatingBadgeIcon="boost" floatingBadgeIcon="boost"
/> />
{isBoosted && (
<div className={buildClassName(styles.description, styles.bold)}>
{lang('ChannelBoost.YouBoostedChannelText', chatTitle)}
</div>
)}
<div className={styles.description}> <div className={styles.description}>
{renderText(descriptionText, ['simple_markdown', 'emoji'])} {renderText(descriptionText, ['simple_markdown', 'emoji'])}
</div> </div>
@ -239,7 +249,7 @@ const BoostModal = ({
{canBoostMore ? ( {canBoostMore ? (
<> <>
<Icon name="boost" /> <Icon name="boost" />
{lang(isBoosted && canBoostMore ? 'BoostingBoostAgain' : 'ChannelBoost.BoostChannel')} {lang(isChannel ? 'ChannelBoost.BoostChannel' : 'GroupBoost.BoostGroup')}
</> </>
) : lang('OK')} ) : lang('OK')}
</Button> </Button>
@ -269,7 +279,7 @@ const BoostModal = ({
> >
<div className={styles.avatarContainer}> <div className={styles.avatarContainer}>
<div className={styles.boostedWrapper}> <div className={styles.boostedWrapper}>
<Avatar peer={boostedChat} size="large" /> <Avatar peer={prevBoostedChat} size="large" />
<Icon name="boostcircle" className={styles.boostedMark} /> <Icon name="boostcircle" className={styles.boostedMark} />
</div> </div>
<Icon name="next" className={styles.arrow} /> <Icon name="next" className={styles.arrow} />
@ -334,12 +344,14 @@ function areAllBoostsInChannel(myBoosts: ApiMyBoost[], chatId: string) {
export default memo(withGlobal<OwnProps>( export default memo(withGlobal<OwnProps>(
(global, { info }): StateProps => { (global, { info }): StateProps => {
const chat = info && selectChat(global, info?.chatId); const chat = info && selectChat(global, info?.chatId);
const chatFullInfo = chat && selectChatFullInfo(global, chat.id);
const firstBoost = info?.myBoosts && getFirstAvailableBoost(info.myBoosts, info.chatId); const firstBoost = info?.myBoosts && getFirstAvailableBoost(info.myBoosts, info.chatId);
const boostedChat = firstBoost?.chatId ? selectChat(global, firstBoost?.chatId) : undefined; const boostedChat = firstBoost?.chatId ? selectChat(global, firstBoost?.chatId) : undefined;
return { return {
chat, chat,
boostedChat, chatFullInfo,
prevBoostedChat: boostedChat,
isCurrentUserPremium: selectIsCurrentUserPremium(global), isCurrentUserPremium: selectIsCurrentUserPremium(global),
}; };
}, },

View File

@ -2,13 +2,14 @@ import type { FC } from '../../lib/teact/teact';
import React, { memo, useCallback, useRef } from '../../lib/teact/teact'; import React, { memo, useCallback, useRef } from '../../lib/teact/teact';
import { getActions, withGlobal } from '../../global'; import { getActions, withGlobal } from '../../global';
import type { ApiChat, ApiVideo } from '../../api/types'; import type { ApiChat, ApiChatFullInfo, ApiVideo } from '../../api/types';
import type { MessageList } from '../../global/types'; import type { MessageList } from '../../global/types';
import { getAllowedAttachmentOptions, getCanPostInChat } from '../../global/helpers'; import { getAllowedAttachmentOptions, getCanPostInChat } from '../../global/helpers';
import { import {
selectCanScheduleUntilOnline, selectCanScheduleUntilOnline,
selectChat, selectChat,
selectChatFullInfo,
selectCurrentGifSearch, selectCurrentGifSearch,
selectCurrentMessageList, selectCurrentMessageList,
selectIsChatWithBot, selectIsChatWithBot,
@ -37,6 +38,7 @@ type StateProps = {
query?: string; query?: string;
results?: ApiVideo[]; results?: ApiVideo[];
chat?: ApiChat; chat?: ApiChat;
chatFullInfo?: ApiChatFullInfo;
isChatWithBot?: boolean; isChatWithBot?: boolean;
canScheduleUntilOnline?: boolean; canScheduleUntilOnline?: boolean;
isSavedMessages?: boolean; isSavedMessages?: boolean;
@ -52,6 +54,7 @@ const GifSearch: FC<OwnProps & StateProps> = ({
query, query,
results, results,
chat, chat,
chatFullInfo,
isChatWithBot, isChatWithBot,
canScheduleUntilOnline, canScheduleUntilOnline,
isSavedMessages, isSavedMessages,
@ -74,7 +77,7 @@ const GifSearch: FC<OwnProps & StateProps> = ({
observe: observeIntersection, observe: observeIntersection,
} = useIntersectionObserver({ rootRef: containerRef, debounceMs: INTERSECTION_DEBOUNCE }); } = useIntersectionObserver({ rootRef: containerRef, debounceMs: INTERSECTION_DEBOUNCE });
const canSendGifs = canPostInChat && getAllowedAttachmentOptions(chat, isChatWithBot).canSendGifs; const canSendGifs = canPostInChat && getAllowedAttachmentOptions(chat, chatFullInfo, isChatWithBot).canSendGifs;
const handleGifClick = useCallback((gif: ApiVideo, isSilent?: boolean, shouldSchedule?: boolean) => { const handleGifClick = useCallback((gif: ApiVideo, isSilent?: boolean, shouldSchedule?: boolean) => {
if (canSendGifs) { if (canSendGifs) {
@ -166,11 +169,13 @@ export default memo(withGlobal(
const { query, results } = currentSearch || {}; const { query, results } = currentSearch || {};
const { chatId, threadId } = selectCurrentMessageList(global) || {}; const { chatId, threadId } = selectCurrentMessageList(global) || {};
const chat = chatId ? selectChat(global, chatId) : undefined; const chat = chatId ? selectChat(global, chatId) : undefined;
const chatFullInfo = chatId ? selectChatFullInfo(global, chatId) : undefined;
const isChatWithBot = chat ? selectIsChatWithBot(global, chat) : undefined; const isChatWithBot = chat ? selectIsChatWithBot(global, chat) : undefined;
const isSavedMessages = Boolean(chatId) && selectIsChatWithSelf(global, chatId); const isSavedMessages = Boolean(chatId) && selectIsChatWithSelf(global, chatId);
const threadInfo = chatId && threadId ? selectThreadInfo(global, chatId, threadId) : undefined; const threadInfo = chatId && threadId ? selectThreadInfo(global, chatId, threadId) : undefined;
const isMessageThread = Boolean(!threadInfo?.isCommentsInfo && threadInfo?.fromChannelId); const isMessageThread = Boolean(!threadInfo?.isCommentsInfo && threadInfo?.fromChannelId);
const canPostInChat = Boolean(chat) && Boolean(threadId) && getCanPostInChat(chat, threadId, isMessageThread); const canPostInChat = Boolean(chat) && Boolean(threadId)
&& getCanPostInChat(chat, threadId, isMessageThread, chatFullInfo);
return { return {
query, query,

View File

@ -260,42 +260,36 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
onChange={handlePermissionChange} onChange={handlePermissionChange}
/> />
</div> </div>
{isChannel && ( <div className="ListItem">
<div className="ListItem"> <Checkbox
<Checkbox name="postStories"
name="postStories" checked={Boolean(permissions.postStories)}
checked={Boolean(permissions.postStories)} label={lang('EditAdminPostStories')}
label={lang('EditAdminPostStories')} blocking
blocking disabled={getControlIsDisabled('postStories')}
disabled={getControlIsDisabled('postStories')} onChange={handlePermissionChange}
onChange={handlePermissionChange} />
/> </div>
</div> <div className="ListItem">
)} <Checkbox
{isChannel && ( name="editStories"
<div className="ListItem"> checked={Boolean(permissions.editStories)}
<Checkbox label={lang('EditAdminEditStories')}
name="editStories" blocking
checked={Boolean(permissions.editStories)} disabled={getControlIsDisabled('editStories')}
label={lang('EditAdminEditStories')} onChange={handlePermissionChange}
blocking />
disabled={getControlIsDisabled('editStories')} </div>
onChange={handlePermissionChange} <div className="ListItem">
/> <Checkbox
</div> name="deleteStories"
)} checked={Boolean(permissions.deleteStories)}
{isChannel && ( label={lang('EditAdminDeleteStories')}
<div className="ListItem"> blocking
<Checkbox disabled={getControlIsDisabled('deleteStories')}
name="deleteStories" onChange={handlePermissionChange}
checked={Boolean(permissions.deleteStories)} />
label={lang('EditAdminDeleteStories')} </div>
blocking
disabled={getControlIsDisabled('deleteStories')}
onChange={handlePermissionChange}
/>
</div>
)}
{!isChannel && ( {!isChannel && (
<div className="ListItem"> <div className="ListItem">
<Checkbox <Checkbox

View File

@ -5,6 +5,7 @@ import React, {
import { getActions, withGlobal } from '../../global'; import { getActions, withGlobal } from '../../global';
import type { import type {
ApiChat,
ApiMediaAreaChannelPost, ApiMediaAreaChannelPost,
ApiPeer, ApiStealthMode, ApiStory, ApiTypeStory, ApiPeer, ApiStealthMode, ApiStory, ApiTypeStory,
} from '../../api/types'; } from '../../api/types';
@ -13,7 +14,7 @@ import type { Signal } from '../../util/signals';
import { MAIN_THREAD_ID } from '../../api/types'; import { MAIN_THREAD_ID } from '../../api/types';
import { EDITABLE_STORY_INPUT_CSS_SELECTOR, EDITABLE_STORY_INPUT_ID } from '../../config'; import { EDITABLE_STORY_INPUT_CSS_SELECTOR, EDITABLE_STORY_INPUT_ID } from '../../config';
import { getSenderTitle, isUserId } from '../../global/helpers'; import { getSenderTitle, isChatChannel, isUserId } from '../../global/helpers';
import { import {
selectChat, selectChat,
selectIsCurrentUserPremium, selectIsCurrentUserPremium,
@ -86,6 +87,7 @@ interface OwnProps {
interface StateProps { interface StateProps {
peer: ApiPeer; peer: ApiPeer;
forwardSender?: ApiPeer; forwardSender?: ApiPeer;
fromPeer?: ApiPeer;
story?: ApiTypeStory; story?: ApiTypeStory;
isMuted: boolean; isMuted: boolean;
orderedIds?: number[]; orderedIds?: number[];
@ -109,6 +111,7 @@ function Story({
storyId, storyId,
peer, peer,
forwardSender, forwardSender,
fromPeer,
isMuted, isMuted,
isArchivedStories, isArchivedStories,
isPrivateStories, isPrivateStories,
@ -124,10 +127,10 @@ function Story({
getIsAnimating, getIsAnimating,
isCurrentUserPremium, isCurrentUserPremium,
stealthMode, stealthMode,
withHeaderAnimation,
onDelete, onDelete,
onClose, onClose,
onReport, onReport,
withHeaderAnimation,
}: OwnProps & StateProps) { }: OwnProps & StateProps) {
const { const {
viewStory, viewStory,
@ -179,7 +182,9 @@ function Story({
const isLoadedStory = story && 'content' in story; const isLoadedStory = story && 'content' in story;
const isChangelog = peerId === storyChangelogUserId; const isChangelog = peerId === storyChangelogUserId;
const isChannel = !isUserId(peerId); const isUserStory = isUserId(peerId);
const isChatStory = !isUserStory;
const isChannelStory = isChatStory && isChatChannel(peer as ApiChat);
const isOut = isLoadedStory && story.isOut; const isOut = isLoadedStory && story.isOut;
const canPinToProfile = useCurrentOrPrev( const canPinToProfile = useCurrentOrPrev(
@ -221,7 +226,8 @@ function Story({
? story.content.video.duration ? story.content.video.duration
: undefined; : undefined;
const shouldShowFooter = isLoadedStory && (isOut || isChannel); const shouldShowComposer = !(isOut && isUserStory) && !isChangelog && !isChannelStory;
const shouldShowFooter = isLoadedStory && !shouldShowComposer && (isOut || isChannelStory);
const headerAnimation = isMobile && withHeaderAnimation ? 'slideFade' : 'none'; const headerAnimation = isMobile && withHeaderAnimation ? 'slideFade' : 'none';
const { const {
@ -239,7 +245,7 @@ function Story({
const { const {
shouldRender: shouldRenderComposer, shouldRender: shouldRenderComposer,
transitionClassNames: composerAppearanceAnimationClassNames, transitionClassNames: composerAppearanceAnimationClassNames,
} = useShowTransition(!isOut && !isChangelog && !isChannel); } = useShowTransition(shouldShowComposer);
const { const {
shouldRender: shouldRenderCaptionBackdrop, shouldRender: shouldRenderCaptionBackdrop,
@ -340,11 +346,11 @@ function Story({
}, [hasAllData]); }, [hasAllData]);
useEffect(() => { useEffect(() => {
if (!isOut || isDeletedStory || areViewsExpired) return; if (!isLoadedStory || isDeletedStory || areViewsExpired) return;
// Refresh recent viewers list each time // Refresh counters each time
loadStoryViews({ peerId, storyId, isPreload: true }); loadStoryViews({ peerId, storyId });
}, [isDeletedStory, areViewsExpired, isOut, peerId, storyId]); }, [isDeletedStory, areViewsExpired, isLoadedStory, peerId, storyId]);
useEffect(() => { useEffect(() => {
if ( if (
@ -415,6 +421,11 @@ function Story({
openChat({ id: forwardSender!.id }); openChat({ id: forwardSender!.id });
}); });
const handleFromPeerClick = useLastCallback(() => {
onClose();
openChat({ id: fromPeer!.id });
});
const handleOpenPrevStory = useLastCallback(() => { const handleOpenPrevStory = useLastCallback(() => {
openPreviousStory(); openPreviousStory();
}); });
@ -569,7 +580,7 @@ function Story({
} }
function renderStoryPrivacyButton() { function renderStoryPrivacyButton() {
if (isChannel) return undefined; if (!isUserStory) return undefined;
let privacyIcon = 'channel-filled'; let privacyIcon = 'channel-filled';
const gradient: Record<string, [string, string]> = { const gradient: Record<string, [string, string]> = {
@ -638,11 +649,24 @@ function Story({
onClick={forwardSender ? handleForwardPeerClick : undefined} onClick={forwardSender ? handleForwardPeerClick : undefined}
> >
<Icon name="loop" /> <Icon name="loop" />
<span className={styles.forwardHeaderText}> <span className={styles.headerTitle}>
{renderText(forwardSenderTitle)} {renderText(forwardSenderTitle)}
</span> </span>
</span> </span>
)} )}
{fromPeer && (
<span
className={buildClassName(
styles.storyMeta, styles.fromPeer,
)}
onClick={handleFromPeerClick}
>
<Avatar peer={fromPeer} size="micro" />
<span className={styles.headerTitle}>
{renderText(getSenderTitle(lang, fromPeer) || '')}
</span>
</span>
)}
{story && 'date' in story && ( {story && 'date' in story && (
<span className={styles.storyMeta}>{formatRelativeTime(lang, serverTime, story.date)}</span> <span className={styles.storyMeta}>{formatRelativeTime(lang, serverTime, story.date)}</span>
)} )}
@ -693,17 +717,25 @@ function Story({
> >
{canCopyLink && <MenuItem icon="copy" onClick={handleCopyStoryLink}>{lang('CopyLink')}</MenuItem>} {canCopyLink && <MenuItem icon="copy" onClick={handleCopyStoryLink}>{lang('CopyLink')}</MenuItem>}
{canPinToProfile && ( {canPinToProfile && (
<MenuItem icon="save-story" onClick={handlePinClick}>{lang('StorySave')}</MenuItem> <MenuItem icon="save-story" onClick={handlePinClick}>
{lang(isUserStory ? 'StorySave' : 'SaveToPosts')}
</MenuItem>
)} )}
{canUnpinFromProfile && ( {canUnpinFromProfile && (
<MenuItem icon="delete" onClick={handleUnpinClick}>{lang('ArchiveStory')}</MenuItem> <MenuItem icon="delete" onClick={handleUnpinClick}>
{lang(isUserStory ? 'ArchiveStory' : 'RemoveFromPosts')}
</MenuItem>
)} )}
{canDownload && ( {canDownload && (
<MenuItem icon="download" disabled={!downloadMediaData} onClick={handleDownload}> <MenuItem icon="download" disabled={!downloadMediaData} onClick={handleDownload}>
{lang('lng_media_download')} {lang('lng_media_download')}
</MenuItem> </MenuItem>
)} )}
<MenuItem icon="eye-closed-outline" onClick={handleOpenStealthModal}>{lang('StealthMode')}</MenuItem> {!isOut && isUserStory && (
<MenuItem icon="eye-closed-outline" onClick={handleOpenStealthModal}>
{lang('StealthMode')}
</MenuItem>
)}
{!isOut && <MenuItem icon="flag" onClick={handleReportStoryClick}>{lang('lng_report_story')}</MenuItem>} {!isOut && <MenuItem icon="flag" onClick={handleReportStoryClick}>{lang('lng_report_story')}</MenuItem>}
{isOut && <MenuItem icon="delete" destructive onClick={handleDeleteStoryClick}>{lang('Delete')}</MenuItem>} {isOut && <MenuItem icon="delete" destructive onClick={handleDeleteStoryClick}>{lang('Delete')}</MenuItem>}
</DropdownMenu> </DropdownMenu>
@ -818,7 +850,7 @@ function Story({
</div> </div>
{shouldShowFooter && ( {shouldShowFooter && (
<StoryFooter story={story} className={appearanceAnimationClassNames} areViewsExpired={areViewsExpired} /> <StoryFooter story={story} className={appearanceAnimationClassNames} />
)} )}
{shouldRenderCaptionBackdrop && ( {shouldRenderCaptionBackdrop && (
<div <div
@ -853,7 +885,7 @@ function Story({
editableInputId={EDITABLE_STORY_INPUT_ID} editableInputId={EDITABLE_STORY_INPUT_ID}
inputId="story-input-text" inputId="story-input-text"
className={buildClassName(styles.composer, composerAppearanceAnimationClassNames)} className={buildClassName(styles.composer, composerAppearanceAnimationClassNames)}
inputPlaceholder={lang('ReplyPrivately')} inputPlaceholder={lang(isChatStory ? 'ReplyToGroupStory' : 'ReplyPrivately')}
onForward={canShare ? handleForwardClick : undefined} onForward={canShare ? handleForwardClick : undefined}
onFocus={markComposerHasFocus} onFocus={markComposerHasFocus}
onBlur={unmarkComposerHasFocus} onBlur={unmarkComposerHasFocus}
@ -888,21 +920,25 @@ export default memo(withGlobal<OwnProps>((global, {
} = tabState; } = tabState;
const { isOpen: isPremiumModalOpen } = premiumModal || {}; const { isOpen: isPremiumModalOpen } = premiumModal || {};
const story = selectPeerStory(global, peerId, storyId); const story = selectPeerStory(global, peerId, storyId);
const isLoadedStory = story && 'content' in story;
const shouldForcePause = Boolean( const shouldForcePause = Boolean(
viewModal || forwardedStoryId || tabState.reactionPicker?.storyId || isReportModalOpen || isPrivacyModalOpen viewModal || forwardedStoryId || tabState.reactionPicker?.storyId || isReportModalOpen || isPrivacyModalOpen
|| isPremiumModalOpen || isDeleteModalOpen || safeLinkModalUrl || isStealthModalOpen || mapModal, || isPremiumModalOpen || isDeleteModalOpen || safeLinkModalUrl || isStealthModalOpen || mapModal,
); );
const forwardInfo = (story && 'forwardInfo' in story) ? story.forwardInfo : undefined; const forwardInfo = isLoadedStory ? story.forwardInfo : undefined;
const mediaAreas = (story && 'mediaAreas' in story) ? story.mediaAreas : undefined; const mediaAreas = isLoadedStory ? story.mediaAreas : undefined;
const forwardSenderId = forwardInfo?.fromPeerId const forwardSenderId = forwardInfo?.fromPeerId
|| mediaAreas?.find((area): area is ApiMediaAreaChannelPost => area.type === 'channelPost')?.channelId; || mediaAreas?.find((area): area is ApiMediaAreaChannelPost => area.type === 'channelPost')?.channelId;
const forwardSender = forwardSenderId ? selectPeer(global, forwardSenderId) : undefined; const forwardSender = forwardSenderId ? selectPeer(global, forwardSenderId) : undefined;
const withHeaderAnimation = selectPerformanceSettingsValue(global, 'mediaViewerAnimations'); const withHeaderAnimation = selectPerformanceSettingsValue(global, 'mediaViewerAnimations');
const fromPeer = isLoadedStory && story.fromId ? selectPeer(global, story.fromId) : undefined;
return { return {
peer: (user || chat)!, peer: (user || chat)!,
forwardSender, forwardSender,
fromPeer,
story, story,
orderedIds: storyList?.storyIdsByPeerId[peerId], orderedIds: storyList?.storyIdsByPeerId[peerId],
isMuted, isMuted,

View File

@ -19,13 +19,11 @@ import styles from './StoryFooter.module.scss';
type OwnProps = { type OwnProps = {
story: ApiStory; story: ApiStory;
areViewsExpired?: boolean;
className?: string; className?: string;
}; };
const StoryFooter = ({ const StoryFooter = ({
story, story,
areViewsExpired,
className, className,
}: OwnProps) => { }: OwnProps) => {
const { openStoryViewModal, openForwardMenu, sendStoryReaction } = getActions(); const { openStoryViewModal, openForwardMenu, sendStoryReaction } = getActions();
@ -94,7 +92,7 @@ const StoryFooter = ({
className={buildClassName(styles.viewInfo, !isChannel && styles.interactive)} className={buildClassName(styles.viewInfo, !isChannel && styles.interactive)}
onClick={!isChannel ? handleOpenStoryViewModal : undefined} onClick={!isChannel ? handleOpenStoryViewModal : undefined}
> >
{!areViewsExpired && Boolean(recentViewers?.length) && ( {Boolean(recentViewers?.length) && (
<AvatarList <AvatarList
size="small" size="small"
peers={recentViewers} peers={recentViewers}

View File

@ -58,7 +58,7 @@ function StoryViewModal({
isCurrentUserPremium, isCurrentUserPremium,
}: StateProps) { }: StateProps) {
const { const {
loadStoryViews, closeStoryViewModal, clearStoryViews, loadStoryViewList, closeStoryViewModal, clearStoryViews,
} = getActions(); } = getActions();
const [areJustContacts, markJustContacts, unmarkJustContacts] = useFlag(false); const [areJustContacts, markJustContacts, unmarkJustContacts] = useFlag(false);
@ -102,7 +102,7 @@ function StoryViewModal({
const handleLoadMore = useLastCallback(() => { const handleLoadMore = useLastCallback(() => {
if (!story?.id || nextOffset === undefined) return; if (!story?.id || nextOffset === undefined) return;
loadStoryViews({ loadStoryViewList({
peerId: story.peerId, peerId: story.peerId,
storyId: story.id, storyId: story.id,
offset: nextOffset, offset: nextOffset,

View File

@ -737,17 +737,17 @@
&.clickable { &.clickable {
cursor: var(--custom-cursor, pointer); cursor: var(--custom-cursor, pointer);
&:hover {
text-decoration: underline;
}
} }
} }
.forwardHeaderText { .headerTitle {
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
.forwardHeader.clickable:hover & {
text-decoration: underline;
}
} }
.forwardInfo { .forwardInfo {
@ -759,3 +759,14 @@
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
z-index: 1; z-index: 1;
} }
.fromPeer {
display: flex;
align-items: center;
gap: 0.25rem;
cursor: var(--custom-cursor, pointer);
&:hover {
text-decoration: underline;
}
}

View File

@ -51,7 +51,7 @@ export const CUSTOM_EMOJI_PREVIEW_CACHE_DISABLED = false;
export const CUSTOM_EMOJI_PREVIEW_CACHE_NAME = 'tt-custom-emoji-preview'; export const CUSTOM_EMOJI_PREVIEW_CACHE_NAME = 'tt-custom-emoji-preview';
export const MEDIA_CACHE_MAX_BYTES = 512 * 1024; // 512 KB export const MEDIA_CACHE_MAX_BYTES = 512 * 1024; // 512 KB
export const CUSTOM_BG_CACHE_NAME = 'tt-custom-bg'; export const CUSTOM_BG_CACHE_NAME = 'tt-custom-bg';
export const LANG_CACHE_NAME = 'tt-lang-packs-v31'; export const LANG_CACHE_NAME = 'tt-lang-packs-v32';
export const ASSET_CACHE_NAME = 'tt-assets'; export const ASSET_CACHE_NAME = 'tt-assets';
export const AUTODOWNLOAD_FILESIZE_MB_LIMITS = [1, 5, 10, 50, 100, 500]; export const AUTODOWNLOAD_FILESIZE_MB_LIMITS = [1, 5, 10, 50, 100, 500];
export const DATA_BROADCAST_CHANNEL_NAME = 'tt-global'; export const DATA_BROADCAST_CHANNEL_NAME = 'tt-global';
@ -206,7 +206,6 @@ export const POPULAR_SYMBOL_SET_ID = 'popular';
export const RECENT_SYMBOL_SET_ID = 'recent'; export const RECENT_SYMBOL_SET_ID = 'recent';
export const FAVORITE_SYMBOL_SET_ID = 'favorite'; export const FAVORITE_SYMBOL_SET_ID = 'favorite';
export const CHAT_STICKER_SET_ID = 'chatStickers'; export const CHAT_STICKER_SET_ID = 'chatStickers';
export const PREMIUM_STICKER_SET_ID = 'premium';
export const DEFAULT_TOPIC_ICON_STICKER_ID = 'topic-default-icon'; export const DEFAULT_TOPIC_ICON_STICKER_ID = 'topic-default-icon';
export const DEFAULT_STATUS_ICON_ID = 'status-default-icon'; export const DEFAULT_STATUS_ICON_ID = 'status-default-icon';
export const EMOJI_IMG_REGEX = /<img[^>]+alt="([^"]+)"(?![^>]*data-document-id)[^>]*>/gm; export const EMOJI_IMG_REGEX = /<img[^>]+alt="([^"]+)"(?![^>]*data-document-id)[^>]*>/gm;

View File

@ -1463,7 +1463,7 @@ addActionHandler('processBoostParameters', async (global, actions, payload): Pro
} }
} }
if (!isChatChannel(chat)) { if (!isChatChannel(chat) && !isChatSuperGroup(chat)) {
actions.openChat({ id: chat.id, tabId }); actions.openChat({ id: chat.id, tabId });
return; return;
} }
@ -2781,13 +2781,12 @@ export async function loadFullChat<T extends GlobalState>(
} }
const { const {
users, userStatusesById, fullInfo, groupCall, membersCount, isForumAsMessages, chats, users, userStatusesById, fullInfo, groupCall, membersCount, isForumAsMessages,
} = result; } = result;
global = getGlobal(); global = getGlobal();
if (users) { global = addUsers(global, buildCollectionByKey(users, 'id'));
global = addUsers(global, buildCollectionByKey(users, 'id')); global = updateChats(global, buildCollectionByKey(chats, 'id'));
}
if (userStatusesById) { if (userStatusesById) {
global = addUserStatuses(global, userStatusesById); global = addUserStatuses(global, userStatusesById);
@ -2825,6 +2824,18 @@ export async function loadFullChat<T extends GlobalState>(
}); });
} }
const emojiSet = fullInfo.emojiSet;
const localEmojiSet = emojiSet && selectStickerSet(global, emojiSet);
if (emojiSet && !localEmojiSet) {
actions.loadStickers({
stickerSetInfo: {
id: emojiSet.id,
accessHash: emojiSet.accessHash,
},
tabId,
});
}
return result; return result;
} }

View File

@ -312,7 +312,7 @@ addActionHandler('sendMessage', (global, actions, payload): ActionReturnType =>
const storyReplyInfo = isStoryReply ? { const storyReplyInfo = isStoryReply ? {
type: 'story', type: 'story',
userId: storyPeerId!, peerId: storyPeerId!,
storyId: storyId!, storyId: storyId!,
} satisfies ApiInputStoryReplyInfo : undefined; } satisfies ApiInputStoryReplyInfo : undefined;

View File

@ -9,7 +9,7 @@ import { buildCollectionByKey, unique } from '../../../util/iteratees';
import * as langProvider from '../../../util/langProvider'; import * as langProvider from '../../../util/langProvider';
import { buildQueryString } from '../../../util/requestQuery'; import { buildQueryString } from '../../../util/requestQuery';
import { callApi } from '../../../api/gramjs'; import { callApi } from '../../../api/gramjs';
import { getStripeError, isChatChannel } from '../../helpers'; import { getStripeError, isChatChannel, isChatSuperGroup } from '../../helpers';
import { addActionHandler, getGlobal, setGlobal } from '../../index'; import { addActionHandler, getGlobal, setGlobal } from '../../index';
import { import {
addChats, addChats,
@ -19,12 +19,14 @@ import {
setReceipt, setReceipt,
setRequestInfoId, setRequestInfoId,
setSmartGlocalCardInfo, setStripeCardInfo, setSmartGlocalCardInfo, setStripeCardInfo,
updateChatFullInfo,
updatePayment, updatePayment,
updateShippingOptions, updateShippingOptions,
} from '../../reducers'; } from '../../reducers';
import { updateTabState } from '../../reducers/tabs'; import { updateTabState } from '../../reducers/tabs';
import { import {
selectChat, selectChat,
selectChatFullInfo,
selectChatMessage, selectChatMessage,
selectPaymentFormId, selectPaymentFormId,
selectPaymentInputInvoice, selectPaymentRequestId, selectPaymentInputInvoice, selectPaymentRequestId,
@ -36,6 +38,8 @@ import {
selectUser, selectUser,
} from '../../selectors'; } from '../../selectors';
const LOCAL_BOOST_COOLDOWN = 86400; // 24 hours
addActionHandler('validateRequestedInfo', (global, actions, payload): ActionReturnType => { addActionHandler('validateRequestedInfo', (global, actions, payload): ActionReturnType => {
const { requestInfo, saveInfo, tabId = getCurrentTabId() } = payload; const { requestInfo, saveInfo, tabId = getCurrentTabId() } = payload;
@ -477,7 +481,7 @@ async function validateRequestedInfo<T extends GlobalState>(
addActionHandler('openBoostModal', async (global, actions, payload): Promise<void> => { addActionHandler('openBoostModal', async (global, actions, payload): Promise<void> => {
const { chatId, tabId = getCurrentTabId() } = payload; const { chatId, tabId = getCurrentTabId() } = payload;
const chat = selectChat(global, chatId); const chat = selectChat(global, chatId);
if (!chat || !isChatChannel(chat)) return; if (!chat || !(isChatChannel(chat) || isChatSuperGroup(chat))) return;
global = updateTabState(global, { global = updateTabState(global, {
boostModal: { boostModal: {
@ -614,19 +618,96 @@ addActionHandler('applyBoost', async (global, actions, payload): Promise<void> =
const chat = selectChat(global, chatId); const chat = selectChat(global, chatId);
if (!chat) return; if (!chat) return;
const oldChatFullInfo = selectChatFullInfo(global, chatId);
const oldBoostsApplied = oldChatFullInfo?.boostsApplied || 0;
const appliedBoostsCount = slots.length;
let tabState = selectTabState(global, tabId);
const oldStatus = tabState.boostModal?.boostStatus;
if (oldStatus) {
const boostsPerLevel = oldStatus.nextLevelBoosts ? oldStatus.nextLevelBoosts - oldStatus.currentLevelBoosts : 1;
const newBoosts = oldStatus.boosts + appliedBoostsCount;
const isLevelUp = oldStatus.nextLevelBoosts && newBoosts >= oldStatus.nextLevelBoosts;
const newCurrentLevelBoosts = isLevelUp ? oldStatus.nextLevelBoosts! : oldStatus.currentLevelBoosts;
const newNextLevelBoosts = isLevelUp ? oldStatus.nextLevelBoosts! + boostsPerLevel : oldStatus.nextLevelBoosts;
global = updateTabState(global, {
boostModal: {
...tabState.boostModal!,
boostStatus: {
...oldStatus,
level: isLevelUp ? oldStatus.level + 1 : oldStatus.level,
currentLevelBoosts: newCurrentLevelBoosts,
nextLevelBoosts: newNextLevelBoosts,
hasMyBoost: true,
boosts: newBoosts,
},
},
}, tabId);
setGlobal(global);
}
global = getGlobal();
tabState = selectTabState(global, tabId);
const oldMyBoosts = tabState.boostModal?.myBoosts;
if (oldMyBoosts) {
const unixNow = Math.floor(Date.now() / 1000);
const newMyBoosts = oldMyBoosts.map((boost) => {
if (slots.includes(boost.slot)) {
return {
...boost,
chatId,
date: unixNow,
cooldownUntil: unixNow + LOCAL_BOOST_COOLDOWN, // Will be refetched below
};
}
return boost;
});
global = updateTabState(global, {
boostModal: {
...tabState.boostModal!,
myBoosts: newMyBoosts,
},
}, tabId);
setGlobal(global);
}
const result = await callApi('applyBoost', { const result = await callApi('applyBoost', {
slots, slots,
chat, chat,
}); });
global = getGlobal();
if (!result) { if (!result) {
// Rollback local changes
const boostModal = selectTabState(global, tabId).boostModal;
if (boostModal) {
global = updateTabState(global, {
boostModal: {
...boostModal,
boostStatus: oldStatus,
myBoosts: oldMyBoosts,
},
}, tabId);
setGlobal(global);
}
return; return;
} }
global = getGlobal(); tabState = selectTabState(global, tabId);
let tabState = selectTabState(global, tabId);
global = addUsers(global, buildCollectionByKey(result.users, 'id')); global = addUsers(global, buildCollectionByKey(result.users, 'id'));
global = addChats(global, buildCollectionByKey(result.chats, 'id')); global = addChats(global, buildCollectionByKey(result.chats, 'id'));
if (oldChatFullInfo) {
global = updateChatFullInfo(global, chatId, {
boostsApplied: oldBoostsApplied + slots.length,
});
}
if (tabState.boostModal) { if (tabState.boostModal) {
global = updateTabState(global, { global = updateTabState(global, {
boostModal: { boostModal: {
@ -636,25 +717,6 @@ addActionHandler('applyBoost', async (global, actions, payload): Promise<void> =
}, tabId); }, tabId);
} }
setGlobal(global); setGlobal(global);
const newStatusResult = await callApi('fetchBoostsStatus', {
chat,
});
if (!newStatusResult) {
return;
}
global = getGlobal();
tabState = selectTabState(global, tabId);
if (!tabState.boostModal?.boostStatus) return;
global = updateTabState(global, {
boostModal: {
...tabState.boostModal,
boostStatus: newStatusResult,
},
}, tabId);
setGlobal(global);
}); });
addActionHandler('checkGiftCode', async (global, actions, payload): Promise<void> => { addActionHandler('checkGiftCode', async (global, actions, payload): Promise<void> => {

View File

@ -1,7 +1,6 @@
import type { ApiStoryView } from '../../../api/types';
import type { ActionReturnType } from '../../types'; import type { ActionReturnType } from '../../types';
import { DEBUG, PREVIEW_AVATAR_COUNT } from '../../../config'; import { DEBUG } from '../../../config';
import { getCurrentTabId } from '../../../util/establishMultitabRole'; import { getCurrentTabId } from '../../../util/establishMultitabRole';
import { buildCollectionByKey } from '../../../util/iteratees'; import { buildCollectionByKey } from '../../../util/iteratees';
import { translate } from '../../../util/langProvider'; import { translate } from '../../../util/langProvider';
@ -312,31 +311,43 @@ addActionHandler('loadPeerStoriesByIds', async (global, actions, payload): Promi
}); });
addActionHandler('loadStoryViews', async (global, actions, payload): Promise<void> => { addActionHandler('loadStoryViews', async (global, actions, payload): Promise<void> => {
const { peerId, storyId } = payload;
const peer = selectPeer(global, peerId);
if (!peer) {
return;
}
const result = await callApi('fetchStoriesViews', { peer, storyIds: [storyId] });
if (!result) {
return;
}
global = getGlobal();
global = addUsers(global, buildCollectionByKey(result.users, 'id'));
global = updatePeerStoryViews(global, peerId, storyId, result.views);
setGlobal(global);
});
addActionHandler('loadStoryViewList', async (global, actions, payload): Promise<void> => {
const { const {
peerId, peerId,
storyId, storyId,
offset,
areReactionsFirst,
areJustContacts,
query,
limit,
tabId = getCurrentTabId(), tabId = getCurrentTabId(),
} = payload; } = payload;
const isPreload = 'isPreload' in payload;
const {
offset, areReactionsFirst, areJustContacts, query, limit,
} = isPreload ? {
offset: undefined,
areReactionsFirst: undefined,
areJustContacts: undefined,
query: undefined,
limit: PREVIEW_AVATAR_COUNT,
} : payload;
const peer = selectPeer(global, peerId); const peer = selectPeer(global, peerId);
if (!peer) { if (!peer) {
return; return;
} }
if (!isPreload) { global = updateStoryViewsLoading(global, true, tabId);
global = updateStoryViewsLoading(global, true, tabId); setGlobal(global);
setGlobal(global);
}
const result = await callApi('fetchStoryViewList', { const result = await callApi('fetchStoryViewList', {
peer, peer,
@ -357,18 +368,7 @@ addActionHandler('loadStoryViews', async (global, actions, payload): Promise<voi
global = getGlobal(); global = getGlobal();
global = addUsers(global, buildCollectionByKey(result.users, 'id')); global = addUsers(global, buildCollectionByKey(result.users, 'id'));
global = addChats(global, buildCollectionByKey(result.chats, 'id')); global = addChats(global, buildCollectionByKey(result.chats, 'id'));
if (!isPreload) global = updateStoryViews(global, storyId, result.views, result.nextOffset, tabId); global = updateStoryViews(global, storyId, result.views, result.nextOffset, tabId);
if (isPreload && result.views?.length) {
const recentViewerIds = result.views
.filter((view): view is ApiStoryView => 'date' in view)
.map((view) => view.peerId);
global = updatePeerStoryViews(global, peerId, storyId, {
recentViewerIds,
viewsCount: result.viewsCount,
reactionsCount: result.reactionsCount,
});
}
setGlobal(global); setGlobal(global);
}); });

View File

@ -149,29 +149,6 @@ addActionHandler('loadPremiumStickers', async (global): Promise<void> => {
setGlobal(global); setGlobal(global);
}); });
addActionHandler('loadPremiumSetStickers', async (global): Promise<void> => {
const { hash } = global.stickers.premium || {};
const result = await callApi('fetchStickersForEmoji', { emoji: '📂⭐️', hash });
if (!result) {
return;
}
global = getGlobal();
global = {
...global,
stickers: {
...global.stickers,
premiumSet: {
hash: result.hash,
stickers: result.stickers,
},
},
};
setGlobal(global);
});
addActionHandler('loadGreetingStickers', async (global): Promise<void> => { addActionHandler('loadGreetingStickers', async (global): Promise<void> => {
const { hash } = global.stickers.greeting || {}; const { hash } = global.stickers.greeting || {};

View File

@ -24,6 +24,7 @@ import { updateTabState } from '../../reducers/tabs';
import { import {
selectCanAnimateInterface, selectCanAnimateInterface,
selectChat, selectChat,
selectChatFullInfo,
selectChatMessage, selectChatMessage,
selectCurrentChat, selectCurrentChat,
selectCurrentMessageList, selectCurrentMessageList,
@ -319,11 +320,12 @@ addActionHandler('showAllowedMessageTypesNotification', (global, actions, payloa
const chat = selectChat(global, chatId); const chat = selectChat(global, chatId);
if (!chat) return; if (!chat) return;
const chatFullInfo = selectChatFullInfo(global, chatId);
const { const {
canSendPlainText, canSendPhotos, canSendVideos, canSendDocuments, canSendAudios, canSendPlainText, canSendPhotos, canSendVideos, canSendDocuments, canSendAudios,
canSendStickers, canSendRoundVideos, canSendVoices, canSendStickers, canSendRoundVideos, canSendVoices,
} = getAllowedAttachmentOptions(chat); } = getAllowedAttachmentOptions(chat, chatFullInfo);
const allowedContent = compact([ const allowedContent = compact([
canSendPlainText ? 'Chat.SendAllowedContentTypeText' : undefined, canSendPlainText ? 'Chat.SendAllowedContentTypeText' : undefined,
canSendPhotos ? 'Chat.SendAllowedContentTypePhoto' : undefined, canSendPhotos ? 'Chat.SendAllowedContentTypePhoto' : undefined,

View File

@ -3,6 +3,7 @@ import type {
ApiChatAdminRights, ApiChatAdminRights,
ApiChatBannedRights, ApiChatBannedRights,
ApiChatFolder, ApiChatFolder,
ApiChatFullInfo,
ApiPeer, ApiPeer,
ApiTopic, ApiTopic,
ApiUser, ApiUser,
@ -130,14 +131,18 @@ export function getCanManageTopic(chat: ApiChat, topic: ApiTopic) {
return chat.isCreator || getHasAdminRight(chat, 'manageTopics') || topic.isOwner; return chat.isCreator || getHasAdminRight(chat, 'manageTopics') || topic.isOwner;
} }
export function isUserRightBanned(chat: ApiChat, key: keyof ApiChatBannedRights) { export function isUserRightBanned(chat: ApiChat, key: keyof ApiChatBannedRights, chatFullInfo?: ApiChatFullInfo) {
const unrestrictedByBoosts = chatFullInfo?.boostsToUnrestrict
&& (chatFullInfo.boostsApplied || 0) >= chatFullInfo.boostsToUnrestrict;
return Boolean( return Boolean(
(chat.currentUserBannedRights?.[key]) (chat.currentUserBannedRights?.[key])
|| (chat.defaultBannedRights?.[key]), || (chat.defaultBannedRights?.[key] && !unrestrictedByBoosts),
); );
} }
export function getCanPostInChat(chat: ApiChat, threadId: ThreadId, isMessageThread?: boolean) { export function getCanPostInChat(
chat: ApiChat, threadId: ThreadId, isMessageThread?: boolean, chatFullInfo?: ApiChatFullInfo,
) {
if (threadId !== MAIN_THREAD_ID) { if (threadId !== MAIN_THREAD_ID) {
if (chat.isForum) { if (chat.isForum) {
if (chat.isNotJoined) { if (chat.isNotJoined) {
@ -168,7 +173,7 @@ export function getCanPostInChat(chat: ApiChat, threadId: ThreadId, isMessageThr
return getHasAdminRight(chat, 'postMessages'); return getHasAdminRight(chat, 'postMessages');
} }
return isChatAdmin(chat) || !isUserRightBanned(chat, 'sendMessages'); return isChatAdmin(chat) || !isUserRightBanned(chat, 'sendMessages', chatFullInfo);
} }
export interface IAllowedAttachmentOptions { export interface IAllowedAttachmentOptions {
@ -188,6 +193,7 @@ export interface IAllowedAttachmentOptions {
export function getAllowedAttachmentOptions( export function getAllowedAttachmentOptions(
chat?: ApiChat, chat?: ApiChat,
chatFullInfo?: ApiChatFullInfo,
isChatWithBot = false, isChatWithBot = false,
isStoryReply = false, isStoryReply = false,
): IAllowedAttachmentOptions { ): IAllowedAttachmentOptions {
@ -211,20 +217,20 @@ export function getAllowedAttachmentOptions(
const isAdmin = isChatAdmin(chat); const isAdmin = isChatAdmin(chat);
return { return {
canAttachMedia: isAdmin || isStoryReply || !isUserRightBanned(chat, 'sendMedia'), canAttachMedia: isAdmin || isStoryReply || !isUserRightBanned(chat, 'sendMedia', chatFullInfo),
canAttachPolls: !isStoryReply canAttachPolls: !isStoryReply
&& (isAdmin || !isUserRightBanned(chat, 'sendPolls')) && (isAdmin || !isUserRightBanned(chat, 'sendPolls', chatFullInfo))
&& (!isUserId(chat.id) || isChatWithBot), && (!isUserId(chat.id) || isChatWithBot),
canSendStickers: isAdmin || isStoryReply || !isUserRightBanned(chat, 'sendStickers'), canSendStickers: isAdmin || isStoryReply || !isUserRightBanned(chat, 'sendStickers', chatFullInfo),
canSendGifs: isAdmin || isStoryReply || !isUserRightBanned(chat, 'sendGifs'), canSendGifs: isAdmin || isStoryReply || !isUserRightBanned(chat, 'sendGifs', chatFullInfo),
canAttachEmbedLinks: !isStoryReply && (isAdmin || !isUserRightBanned(chat, 'embedLinks')), canAttachEmbedLinks: !isStoryReply && (isAdmin || !isUserRightBanned(chat, 'embedLinks', chatFullInfo)),
canSendPhotos: isAdmin || isStoryReply || !isUserRightBanned(chat, 'sendPhotos'), canSendPhotos: isAdmin || isStoryReply || !isUserRightBanned(chat, 'sendPhotos', chatFullInfo),
canSendVideos: isAdmin || isStoryReply || !isUserRightBanned(chat, 'sendVideos'), canSendVideos: isAdmin || isStoryReply || !isUserRightBanned(chat, 'sendVideos', chatFullInfo),
canSendRoundVideos: isAdmin || isStoryReply || !isUserRightBanned(chat, 'sendRoundvideos'), canSendRoundVideos: isAdmin || isStoryReply || !isUserRightBanned(chat, 'sendRoundvideos', chatFullInfo),
canSendAudios: isAdmin || isStoryReply || !isUserRightBanned(chat, 'sendAudios'), canSendAudios: isAdmin || isStoryReply || !isUserRightBanned(chat, 'sendAudios', chatFullInfo),
canSendVoices: isAdmin || isStoryReply || !isUserRightBanned(chat, 'sendVoices'), canSendVoices: isAdmin || isStoryReply || !isUserRightBanned(chat, 'sendVoices', chatFullInfo),
canSendPlainText: isAdmin || isStoryReply || !isUserRightBanned(chat, 'sendPlain'), canSendPlainText: isAdmin || isStoryReply || !isUserRightBanned(chat, 'sendPlain', chatFullInfo),
canSendDocuments: isAdmin || isStoryReply || !isUserRightBanned(chat, 'sendDocs'), canSendDocuments: isAdmin || isStoryReply || !isUserRightBanned(chat, 'sendDocs', chatFullInfo),
}; };
} }

View File

@ -172,9 +172,6 @@ export const INITIAL_GLOBAL_STATE: GlobalState = {
premium: { premium: {
stickers: [], stickers: [],
}, },
premiumSet: {
stickers: [],
},
featured: { featured: {
setIds: [], setIds: [],
}, },

View File

@ -591,6 +591,8 @@ export function selectAllowedMessageActions<T extends GlobalState>(global: T, me
const { content } = message; const { content } = message;
const messageTopic = selectTopicFromMessage(global, message); const messageTopic = selectTopicFromMessage(global, message);
const isDocumentSticker = isMessageDocumentSticker(message); const isDocumentSticker = isMessageDocumentSticker(message);
const chatFullInfo = selectChatFullInfo(global, chat.id);
const isBoostMessage = message.content.action?.type === 'chatBoost';
const canEditMessagesIndefinitely = isChatWithSelf const canEditMessagesIndefinitely = isChatWithSelf
|| (isSuperGroup && getHasAdminRight(chat, 'pinMessages')) || (isSuperGroup && getHasAdminRight(chat, 'pinMessages'))
@ -614,7 +616,7 @@ export function selectAllowedMessageActions<T extends GlobalState>(global: T, me
const threadInfo = selectThreadInfo(global, message.chatId, threadId); const threadInfo = selectThreadInfo(global, message.chatId, threadId);
const isMessageThread = Boolean(!threadInfo?.isCommentsInfo && threadInfo?.fromChannelId); const isMessageThread = Boolean(!threadInfo?.isCommentsInfo && threadInfo?.fromChannelId);
const canReply = !isLocal && !isServiceNotification && !chat.isForbidden const canReply = !isLocal && !isServiceNotification && !chat.isForbidden
&& getCanPostInChat(chat, threadId, isMessageThread) && getCanPostInChat(chat, threadId, isMessageThread, chatFullInfo)
&& (!messageTopic || !messageTopic.isClosed || messageTopic.isOwner || getHasAdminRight(chat, 'manageTopics')); && (!messageTopic || !messageTopic.isClosed || messageTopic.isOwner || getHasAdminRight(chat, 'manageTopics'));
const hasPinPermission = isPrivate || ( const hasPinPermission = isPrivate || (
@ -633,7 +635,10 @@ export function selectAllowedMessageActions<T extends GlobalState>(global: T, me
canPin = !canUnpin; canPin = !canUnpin;
} }
const canDelete = (!isLocal || isFailed) && !isServiceNotification && ( const canNotDeleteBoostMessage = isBoostMessage && isOwn
&& !chat.isCreator && !getHasAdminRight(chat, 'deleteMessages');
const canDelete = (!isLocal || isFailed) && !isServiceNotification && !canNotDeleteBoostMessage && (
isPrivate isPrivate
|| isOwn || isOwn
|| isBasicGroup || isBasicGroup
@ -1363,11 +1368,12 @@ export function selectForwardsCanBeSentToChat<T extends GlobalState>(
return true; return true;
} }
const chatFullInfo = selectChatFullInfo(global, toChatId);
const chatMessages = selectChatMessages(global, fromChatId!); const chatMessages = selectChatMessages(global, fromChatId!);
const { const {
canSendVoices, canSendRoundVideos, canSendStickers, canSendDocuments, canSendAudios, canSendVideos, canSendVoices, canSendRoundVideos, canSendStickers, canSendDocuments, canSendAudios, canSendVideos,
canSendPhotos, canSendGifs, canSendPlainText, canSendPhotos, canSendGifs, canSendPlainText,
} = getAllowedAttachmentOptions(chat); } = getAllowedAttachmentOptions(chat, chatFullInfo);
return !messageIds!.some((messageId) => { return !messageIds!.some((messageId) => {
const message = chatMessages[messageId]; const message = chatMessages[messageId];
const isVoice = message.content.voice; const isVoice = message.content.voice;

View File

@ -910,10 +910,6 @@ export type GlobalState = {
hash?: string; hash?: string;
stickers: ApiSticker[]; stickers: ApiSticker[];
}; };
premiumSet: {
hash?: string;
stickers: ApiSticker[];
};
featured: { featured: {
hash?: string; hash?: string;
setIds?: string[]; setIds?: string[];
@ -2212,11 +2208,11 @@ export interface ActionPayloads {
isMuted: boolean; isMuted: boolean;
} & WithTabId; } & WithTabId;
closeStoryViewer: WithTabId | undefined; closeStoryViewer: WithTabId | undefined;
loadStoryViews: ({ loadStoryViews: {
peerId: string; peerId: string;
storyId: number; storyId: number;
isPreload: true; };
} | { loadStoryViewList: ({
peerId: string; peerId: string;
storyId: number; storyId: number;
offset?: string; offset?: string;
@ -2900,9 +2896,6 @@ export interface ActionPayloads {
loadPremiumGifts: undefined; loadPremiumGifts: undefined;
loadDefaultTopicIcons: undefined; loadDefaultTopicIcons: undefined;
loadPremiumStickers: undefined; loadPremiumStickers: undefined;
loadPremiumSetStickers: {
hash?: string;
} | undefined;
openGiftPremiumModal: ({ openGiftPremiumModal: ({
forUserId?: string; forUserId?: string;

View File

@ -1,6 +1,6 @@
const api = require('./api'); const api = require('./api');
const LAYER = 173; const LAYER = 174;
const tlobjects = {}; const tlobjects = {};
for (const tl of Object.values(api)) { for (const tl of Object.values(api)) {

View File

@ -70,7 +70,7 @@ namespace Api {
export type TypeChatPhoto = ChatPhotoEmpty | ChatPhoto; export type TypeChatPhoto = ChatPhotoEmpty | ChatPhoto;
export type TypeMessage = MessageEmpty | Message | MessageService; export type TypeMessage = MessageEmpty | Message | MessageService;
export type TypeMessageMedia = MessageMediaEmpty | MessageMediaPhoto | MessageMediaGeo | MessageMediaContact | MessageMediaUnsupported | MessageMediaDocument | MessageMediaWebPage | MessageMediaVenue | MessageMediaGame | MessageMediaInvoice | MessageMediaGeoLive | MessageMediaPoll | MessageMediaDice | MessageMediaStory | MessageMediaGiveaway | MessageMediaGiveawayResults; export type TypeMessageMedia = MessageMediaEmpty | MessageMediaPhoto | MessageMediaGeo | MessageMediaContact | MessageMediaUnsupported | MessageMediaDocument | MessageMediaWebPage | MessageMediaVenue | MessageMediaGame | MessageMediaInvoice | MessageMediaGeoLive | MessageMediaPoll | MessageMediaDice | MessageMediaStory | MessageMediaGiveaway | MessageMediaGiveawayResults;
export type TypeMessageAction = MessageActionEmpty | MessageActionChatCreate | MessageActionChatEditTitle | MessageActionChatEditPhoto | MessageActionChatDeletePhoto | MessageActionChatAddUser | MessageActionChatDeleteUser | MessageActionChatJoinedByLink | MessageActionChannelCreate | MessageActionChatMigrateTo | MessageActionChannelMigrateFrom | MessageActionPinMessage | MessageActionHistoryClear | MessageActionGameScore | MessageActionPaymentSentMe | MessageActionPaymentSent | MessageActionPhoneCall | MessageActionScreenshotTaken | MessageActionCustomAction | MessageActionBotAllowed | MessageActionSecureValuesSentMe | MessageActionSecureValuesSent | MessageActionContactSignUp | MessageActionGeoProximityReached | MessageActionGroupCall | MessageActionInviteToGroupCall | MessageActionSetMessagesTTL | MessageActionGroupCallScheduled | MessageActionSetChatTheme | MessageActionChatJoinedByRequest | MessageActionWebViewDataSentMe | MessageActionWebViewDataSent | MessageActionGiftPremium | MessageActionTopicCreate | MessageActionTopicEdit | MessageActionSuggestProfilePhoto | MessageActionRequestedPeer | MessageActionSetChatWallPaper | MessageActionGiftCode | MessageActionGiveawayLaunch | MessageActionGiveawayResults; export type TypeMessageAction = MessageActionEmpty | MessageActionChatCreate | MessageActionChatEditTitle | MessageActionChatEditPhoto | MessageActionChatDeletePhoto | MessageActionChatAddUser | MessageActionChatDeleteUser | MessageActionChatJoinedByLink | MessageActionChannelCreate | MessageActionChatMigrateTo | MessageActionChannelMigrateFrom | MessageActionPinMessage | MessageActionHistoryClear | MessageActionGameScore | MessageActionPaymentSentMe | MessageActionPaymentSent | MessageActionPhoneCall | MessageActionScreenshotTaken | MessageActionCustomAction | MessageActionBotAllowed | MessageActionSecureValuesSentMe | MessageActionSecureValuesSent | MessageActionContactSignUp | MessageActionGeoProximityReached | MessageActionGroupCall | MessageActionInviteToGroupCall | MessageActionSetMessagesTTL | MessageActionGroupCallScheduled | MessageActionSetChatTheme | MessageActionChatJoinedByRequest | MessageActionWebViewDataSentMe | MessageActionWebViewDataSent | MessageActionGiftPremium | MessageActionTopicCreate | MessageActionTopicEdit | MessageActionSuggestProfilePhoto | MessageActionRequestedPeer | MessageActionSetChatWallPaper | MessageActionGiftCode | MessageActionGiveawayLaunch | MessageActionGiveawayResults | MessageActionBoostApply;
export type TypeDialog = Dialog | DialogFolder; export type TypeDialog = Dialog | DialogFolder;
export type TypePhoto = PhotoEmpty | Photo; export type TypePhoto = PhotoEmpty | Photo;
export type TypePhotoSize = PhotoSizeEmpty | PhotoSize | PhotoCachedSize | PhotoStrippedSize | PhotoSizeProgressive | PhotoPathSize; export type TypePhotoSize = PhotoSizeEmpty | PhotoSize | PhotoCachedSize | PhotoStrippedSize | PhotoSizeProgressive | PhotoPathSize;
@ -168,7 +168,7 @@ namespace Api {
export type TypeLangPackString = LangPackString | LangPackStringPluralized | LangPackStringDeleted; export type TypeLangPackString = LangPackString | LangPackStringPluralized | LangPackStringDeleted;
export type TypeLangPackDifference = LangPackDifference; export type TypeLangPackDifference = LangPackDifference;
export type TypeLangPackLanguage = LangPackLanguage; export type TypeLangPackLanguage = LangPackLanguage;
export type TypeChannelAdminLogEventAction = ChannelAdminLogEventActionChangeTitle | ChannelAdminLogEventActionChangeAbout | ChannelAdminLogEventActionChangeUsername | ChannelAdminLogEventActionChangePhoto | ChannelAdminLogEventActionToggleInvites | ChannelAdminLogEventActionToggleSignatures | ChannelAdminLogEventActionUpdatePinned | ChannelAdminLogEventActionEditMessage | ChannelAdminLogEventActionDeleteMessage | ChannelAdminLogEventActionParticipantJoin | ChannelAdminLogEventActionParticipantLeave | ChannelAdminLogEventActionParticipantInvite | ChannelAdminLogEventActionParticipantToggleBan | ChannelAdminLogEventActionParticipantToggleAdmin | ChannelAdminLogEventActionChangeStickerSet | ChannelAdminLogEventActionTogglePreHistoryHidden | ChannelAdminLogEventActionDefaultBannedRights | ChannelAdminLogEventActionStopPoll | ChannelAdminLogEventActionChangeLinkedChat | ChannelAdminLogEventActionChangeLocation | ChannelAdminLogEventActionToggleSlowMode | ChannelAdminLogEventActionStartGroupCall | ChannelAdminLogEventActionDiscardGroupCall | ChannelAdminLogEventActionParticipantMute | ChannelAdminLogEventActionParticipantUnmute | ChannelAdminLogEventActionToggleGroupCallSetting | ChannelAdminLogEventActionParticipantJoinByInvite | ChannelAdminLogEventActionExportedInviteDelete | ChannelAdminLogEventActionExportedInviteRevoke | ChannelAdminLogEventActionExportedInviteEdit | ChannelAdminLogEventActionParticipantVolume | ChannelAdminLogEventActionChangeHistoryTTL | ChannelAdminLogEventActionParticipantJoinByRequest | ChannelAdminLogEventActionToggleNoForwards | ChannelAdminLogEventActionSendMessage | ChannelAdminLogEventActionChangeAvailableReactions | ChannelAdminLogEventActionChangeUsernames | ChannelAdminLogEventActionToggleForum | ChannelAdminLogEventActionCreateTopic | ChannelAdminLogEventActionEditTopic | ChannelAdminLogEventActionDeleteTopic | ChannelAdminLogEventActionPinTopic | ChannelAdminLogEventActionToggleAntiSpam | ChannelAdminLogEventActionChangePeerColor | ChannelAdminLogEventActionChangeProfilePeerColor | ChannelAdminLogEventActionChangeWallpaper | ChannelAdminLogEventActionChangeEmojiStatus; export type TypeChannelAdminLogEventAction = ChannelAdminLogEventActionChangeTitle | ChannelAdminLogEventActionChangeAbout | ChannelAdminLogEventActionChangeUsername | ChannelAdminLogEventActionChangePhoto | ChannelAdminLogEventActionToggleInvites | ChannelAdminLogEventActionToggleSignatures | ChannelAdminLogEventActionUpdatePinned | ChannelAdminLogEventActionEditMessage | ChannelAdminLogEventActionDeleteMessage | ChannelAdminLogEventActionParticipantJoin | ChannelAdminLogEventActionParticipantLeave | ChannelAdminLogEventActionParticipantInvite | ChannelAdminLogEventActionParticipantToggleBan | ChannelAdminLogEventActionParticipantToggleAdmin | ChannelAdminLogEventActionChangeStickerSet | ChannelAdminLogEventActionTogglePreHistoryHidden | ChannelAdminLogEventActionDefaultBannedRights | ChannelAdminLogEventActionStopPoll | ChannelAdminLogEventActionChangeLinkedChat | ChannelAdminLogEventActionChangeLocation | ChannelAdminLogEventActionToggleSlowMode | ChannelAdminLogEventActionStartGroupCall | ChannelAdminLogEventActionDiscardGroupCall | ChannelAdminLogEventActionParticipantMute | ChannelAdminLogEventActionParticipantUnmute | ChannelAdminLogEventActionToggleGroupCallSetting | ChannelAdminLogEventActionParticipantJoinByInvite | ChannelAdminLogEventActionExportedInviteDelete | ChannelAdminLogEventActionExportedInviteRevoke | ChannelAdminLogEventActionExportedInviteEdit | ChannelAdminLogEventActionParticipantVolume | ChannelAdminLogEventActionChangeHistoryTTL | ChannelAdminLogEventActionParticipantJoinByRequest | ChannelAdminLogEventActionToggleNoForwards | ChannelAdminLogEventActionSendMessage | ChannelAdminLogEventActionChangeAvailableReactions | ChannelAdminLogEventActionChangeUsernames | ChannelAdminLogEventActionToggleForum | ChannelAdminLogEventActionCreateTopic | ChannelAdminLogEventActionEditTopic | ChannelAdminLogEventActionDeleteTopic | ChannelAdminLogEventActionPinTopic | ChannelAdminLogEventActionToggleAntiSpam | ChannelAdminLogEventActionChangePeerColor | ChannelAdminLogEventActionChangeProfilePeerColor | ChannelAdminLogEventActionChangeWallpaper | ChannelAdminLogEventActionChangeEmojiStatus | ChannelAdminLogEventActionChangeEmojiStickerSet;
export type TypeChannelAdminLogEvent = ChannelAdminLogEvent; export type TypeChannelAdminLogEvent = ChannelAdminLogEvent;
export type TypeChannelAdminLogEventsFilter = ChannelAdminLogEventsFilter; export type TypeChannelAdminLogEventsFilter = ChannelAdminLogEventsFilter;
export type TypePopularContact = PopularContact; export type TypePopularContact = PopularContact;
@ -1395,6 +1395,9 @@ namespace Api {
availableReactions?: Api.TypeChatReactions; availableReactions?: Api.TypeChatReactions;
stories?: Api.TypePeerStories; stories?: Api.TypePeerStories;
wallpaper?: Api.TypeWallPaper; wallpaper?: Api.TypeWallPaper;
boostsApplied?: int;
boostsUnrestrict?: int;
emojiset?: Api.TypeStickerSet;
}> { }> {
// flags: undefined; // flags: undefined;
canViewParticipants?: true; canViewParticipants?: true;
@ -1449,6 +1452,9 @@ namespace Api {
availableReactions?: Api.TypeChatReactions; availableReactions?: Api.TypeChatReactions;
stories?: Api.TypePeerStories; stories?: Api.TypePeerStories;
wallpaper?: Api.TypeWallPaper; wallpaper?: Api.TypeWallPaper;
boostsApplied?: int;
boostsUnrestrict?: int;
emojiset?: Api.TypeStickerSet;
}; };
export class ChatParticipant extends VirtualClass<{ export class ChatParticipant extends VirtualClass<{
userId: long; userId: long;
@ -1529,6 +1535,7 @@ namespace Api {
invertMedia?: true; invertMedia?: true;
id: int; id: int;
fromId?: Api.TypePeer; fromId?: Api.TypePeer;
fromBoostsApplied?: int;
peerId: Api.TypePeer; peerId: Api.TypePeer;
savedPeerId?: Api.TypePeer; savedPeerId?: Api.TypePeer;
fwdFrom?: Api.TypeMessageFwdHeader; fwdFrom?: Api.TypeMessageFwdHeader;
@ -1563,6 +1570,7 @@ namespace Api {
invertMedia?: true; invertMedia?: true;
id: int; id: int;
fromId?: Api.TypePeer; fromId?: Api.TypePeer;
fromBoostsApplied?: int;
peerId: Api.TypePeer; peerId: Api.TypePeer;
savedPeerId?: Api.TypePeer; savedPeerId?: Api.TypePeer;
fwdFrom?: Api.TypeMessageFwdHeader; fwdFrom?: Api.TypeMessageFwdHeader;
@ -2107,6 +2115,11 @@ namespace Api {
winnersCount: int; winnersCount: int;
unclaimedCount: int; unclaimedCount: int;
}; };
export class MessageActionBoostApply extends VirtualClass<{
boosts: int;
}> {
boosts: int;
};
export class Dialog extends VirtualClass<{ export class Dialog extends VirtualClass<{
// flags: undefined; // flags: undefined;
pinned?: true; pinned?: true;
@ -6600,6 +6613,13 @@ namespace Api {
prevValue: Api.TypeEmojiStatus; prevValue: Api.TypeEmojiStatus;
newValue: Api.TypeEmojiStatus; newValue: Api.TypeEmojiStatus;
}; };
export class ChannelAdminLogEventActionChangeEmojiStickerSet extends VirtualClass<{
prevStickerset: Api.TypeInputStickerSet;
newStickerset: Api.TypeInputStickerSet;
}> {
prevStickerset: Api.TypeInputStickerSet;
newStickerset: Api.TypeInputStickerSet;
};
export class ChannelAdminLogEvent extends VirtualClass<{ export class ChannelAdminLogEvent extends VirtualClass<{
id: long; id: long;
date: int; date: int;
@ -7876,10 +7896,10 @@ namespace Api {
quoteOffset?: int; quoteOffset?: int;
}; };
export class MessageReplyStoryHeader extends VirtualClass<{ export class MessageReplyStoryHeader extends VirtualClass<{
userId: long; peer: Api.TypePeer;
storyId: int; storyId: int;
}> { }> {
userId: long; peer: Api.TypePeer;
storyId: int; storyId: int;
}; };
export class MessageReplies extends VirtualClass<{ export class MessageReplies extends VirtualClass<{
@ -8842,6 +8862,7 @@ namespace Api {
out?: true; out?: true;
id: int; id: int;
date: int; date: int;
fromId?: Api.TypePeer;
fwdFrom?: Api.TypeStoryFwdHeader; fwdFrom?: Api.TypeStoryFwdHeader;
expireDate: int; expireDate: int;
caption?: string; caption?: string;
@ -8864,6 +8885,7 @@ namespace Api {
out?: true; out?: true;
id: int; id: int;
date: int; date: int;
fromId?: Api.TypePeer;
fwdFrom?: Api.TypeStoryFwdHeader; fwdFrom?: Api.TypeStoryFwdHeader;
expireDate: int; expireDate: int;
caption?: string; caption?: string;
@ -8931,10 +8953,10 @@ namespace Api {
quoteOffset?: int; quoteOffset?: int;
}; };
export class InputReplyToStory extends VirtualClass<{ export class InputReplyToStory extends VirtualClass<{
userId: Api.TypeInputUser; peer: Api.TypeInputPeer;
storyId: int; storyId: int;
}> { }> {
userId: Api.TypeInputUser; peer: Api.TypeInputPeer;
storyId: int; storyId: int;
}; };
export class ExportedStoryLink extends VirtualClass<{ export class ExportedStoryLink extends VirtualClass<{
@ -10839,6 +10861,7 @@ namespace Api {
colors?: help.TypePeerColorSet; colors?: help.TypePeerColorSet;
darkColors?: help.TypePeerColorSet; darkColors?: help.TypePeerColorSet;
channelMinLevel?: int; channelMinLevel?: int;
groupMinLevel?: int;
}> { }> {
// flags: undefined; // flags: undefined;
hidden?: true; hidden?: true;
@ -10846,6 +10869,7 @@ namespace Api {
colors?: help.TypePeerColorSet; colors?: help.TypePeerColorSet;
darkColors?: help.TypePeerColorSet; darkColors?: help.TypePeerColorSet;
channelMinLevel?: int; channelMinLevel?: int;
groupMinLevel?: int;
}; };
export class PeerColorsNotModified extends VirtualClass<void> {}; export class PeerColorsNotModified extends VirtualClass<void> {};
export class PeerColors extends VirtualClass<{ export class PeerColors extends VirtualClass<{
@ -15506,6 +15530,20 @@ namespace Api {
channel: Api.TypeInputChannel; channel: Api.TypeInputChannel;
emojiStatus: Api.TypeEmojiStatus; emojiStatus: Api.TypeEmojiStatus;
}; };
export class SetBoostsToUnblockRestrictions extends Request<Partial<{
channel: Api.TypeInputChannel;
boosts: int;
}>, Api.TypeUpdates> {
channel: Api.TypeInputChannel;
boosts: int;
};
export class SetEmojiStickers extends Request<Partial<{
channel: Api.TypeInputChannel;
stickerset: Api.TypeInputStickerSet;
}>, Bool> {
channel: Api.TypeInputChannel;
stickerset: Api.TypeInputStickerSet;
};
} }
export namespace bots { export namespace bots {
@ -16606,7 +16644,7 @@ namespace Api {
| photos.UpdateProfilePhoto | photos.UploadProfilePhoto | photos.DeletePhotos | photos.GetUserPhotos | photos.UploadContactProfilePhoto | photos.UpdateProfilePhoto | photos.UploadProfilePhoto | photos.DeletePhotos | photos.GetUserPhotos | photos.UploadContactProfilePhoto
| upload.SaveFilePart | upload.GetFile | upload.SaveBigFilePart | upload.GetWebFile | upload.GetCdnFile | upload.ReuploadCdnFile | upload.GetCdnFileHashes | upload.GetFileHashes | upload.SaveFilePart | upload.GetFile | upload.SaveBigFilePart | upload.GetWebFile | upload.GetCdnFile | upload.ReuploadCdnFile | upload.GetCdnFileHashes | upload.GetFileHashes
| help.GetConfig | help.GetNearestDc | help.GetAppUpdate | help.GetInviteText | help.GetSupport | help.SetBotUpdatesStatus | help.GetCdnConfig | help.GetRecentMeUrls | help.GetTermsOfServiceUpdate | help.AcceptTermsOfService | help.GetDeepLinkInfo | help.GetAppConfig | help.SaveAppLog | help.GetPassportConfig | help.GetSupportName | help.GetUserInfo | help.EditUserInfo | help.GetPromoData | help.HidePromoData | help.DismissSuggestion | help.GetCountriesList | help.GetPremiumPromo | help.GetPeerColors | help.GetPeerProfileColors | help.GetConfig | help.GetNearestDc | help.GetAppUpdate | help.GetInviteText | help.GetSupport | help.SetBotUpdatesStatus | help.GetCdnConfig | help.GetRecentMeUrls | help.GetTermsOfServiceUpdate | help.AcceptTermsOfService | help.GetDeepLinkInfo | help.GetAppConfig | help.SaveAppLog | help.GetPassportConfig | help.GetSupportName | help.GetUserInfo | help.EditUserInfo | help.GetPromoData | help.HidePromoData | help.DismissSuggestion | help.GetCountriesList | help.GetPremiumPromo | help.GetPeerColors | help.GetPeerProfileColors
| channels.ReadHistory | channels.DeleteMessages | channels.ReportSpam | channels.GetMessages | channels.GetParticipants | channels.GetParticipant | channels.GetChannels | channels.GetFullChannel | channels.CreateChannel | channels.EditAdmin | channels.EditTitle | channels.EditPhoto | channels.CheckUsername | channels.UpdateUsername | channels.JoinChannel | channels.LeaveChannel | channels.InviteToChannel | channels.DeleteChannel | channels.ExportMessageLink | channels.ToggleSignatures | channels.GetAdminedPublicChannels | channels.EditBanned | channels.GetAdminLog | channels.SetStickers | channels.ReadMessageContents | channels.DeleteHistory | channels.TogglePreHistoryHidden | channels.GetLeftChannels | channels.GetGroupsForDiscussion | channels.SetDiscussionGroup | channels.EditCreator | channels.EditLocation | channels.ToggleSlowMode | channels.GetInactiveChannels | channels.ConvertToGigagroup | channels.ViewSponsoredMessage | channels.GetSponsoredMessages | channels.GetSendAs | channels.DeleteParticipantHistory | channels.ToggleJoinToSend | channels.ToggleJoinRequest | channels.ReorderUsernames | channels.ToggleUsername | channels.DeactivateAllUsernames | channels.ToggleForum | channels.CreateForumTopic | channels.GetForumTopics | channels.GetForumTopicsByID | channels.EditForumTopic | channels.UpdatePinnedForumTopic | channels.DeleteTopicHistory | channels.ReorderPinnedForumTopics | channels.ToggleAntiSpam | channels.ReportAntiSpamFalsePositive | channels.ToggleParticipantsHidden | channels.ClickSponsoredMessage | channels.UpdateColor | channels.ToggleViewForumAsMessages | channels.GetChannelRecommendations | channels.UpdateEmojiStatus | channels.ReadHistory | channels.DeleteMessages | channels.ReportSpam | channels.GetMessages | channels.GetParticipants | channels.GetParticipant | channels.GetChannels | channels.GetFullChannel | channels.CreateChannel | channels.EditAdmin | channels.EditTitle | channels.EditPhoto | channels.CheckUsername | channels.UpdateUsername | channels.JoinChannel | channels.LeaveChannel | channels.InviteToChannel | channels.DeleteChannel | channels.ExportMessageLink | channels.ToggleSignatures | channels.GetAdminedPublicChannels | channels.EditBanned | channels.GetAdminLog | channels.SetStickers | channels.ReadMessageContents | channels.DeleteHistory | channels.TogglePreHistoryHidden | channels.GetLeftChannels | channels.GetGroupsForDiscussion | channels.SetDiscussionGroup | channels.EditCreator | channels.EditLocation | channels.ToggleSlowMode | channels.GetInactiveChannels | channels.ConvertToGigagroup | channels.ViewSponsoredMessage | channels.GetSponsoredMessages | channels.GetSendAs | channels.DeleteParticipantHistory | channels.ToggleJoinToSend | channels.ToggleJoinRequest | channels.ReorderUsernames | channels.ToggleUsername | channels.DeactivateAllUsernames | channels.ToggleForum | channels.CreateForumTopic | channels.GetForumTopics | channels.GetForumTopicsByID | channels.EditForumTopic | channels.UpdatePinnedForumTopic | channels.DeleteTopicHistory | channels.ReorderPinnedForumTopics | channels.ToggleAntiSpam | channels.ReportAntiSpamFalsePositive | channels.ToggleParticipantsHidden | channels.ClickSponsoredMessage | channels.UpdateColor | channels.ToggleViewForumAsMessages | channels.GetChannelRecommendations | channels.UpdateEmojiStatus | channels.SetBoostsToUnblockRestrictions | channels.SetEmojiStickers
| bots.SendCustomRequest | bots.AnswerWebhookJSONQuery | bots.SetBotCommands | bots.ResetBotCommands | bots.GetBotCommands | bots.SetBotMenuButton | bots.GetBotMenuButton | bots.SetBotBroadcastDefaultAdminRights | bots.SetBotGroupDefaultAdminRights | bots.SetBotInfo | bots.GetBotInfo | bots.ReorderUsernames | bots.ToggleUsername | bots.CanSendMessage | bots.AllowSendMessage | bots.InvokeWebViewCustomMethod | bots.SendCustomRequest | bots.AnswerWebhookJSONQuery | bots.SetBotCommands | bots.ResetBotCommands | bots.GetBotCommands | bots.SetBotMenuButton | bots.GetBotMenuButton | bots.SetBotBroadcastDefaultAdminRights | bots.SetBotGroupDefaultAdminRights | bots.SetBotInfo | bots.GetBotInfo | bots.ReorderUsernames | bots.ToggleUsername | bots.CanSendMessage | bots.AllowSendMessage | bots.InvokeWebViewCustomMethod
| payments.GetPaymentForm | payments.GetPaymentReceipt | payments.ValidateRequestedInfo | payments.SendPaymentForm | payments.GetSavedInfo | payments.ClearSavedInfo | payments.GetBankCardData | payments.ExportInvoice | payments.AssignAppStoreTransaction | payments.AssignPlayMarketTransaction | payments.CanPurchasePremium | payments.GetPremiumGiftCodeOptions | payments.CheckGiftCode | payments.ApplyGiftCode | payments.GetGiveawayInfo | payments.LaunchPrepaidGiveaway | payments.GetPaymentForm | payments.GetPaymentReceipt | payments.ValidateRequestedInfo | payments.SendPaymentForm | payments.GetSavedInfo | payments.ClearSavedInfo | payments.GetBankCardData | payments.ExportInvoice | payments.AssignAppStoreTransaction | payments.AssignPlayMarketTransaction | payments.CanPurchasePremium | payments.GetPremiumGiftCodeOptions | payments.CheckGiftCode | payments.ApplyGiftCode | payments.GetGiveawayInfo | payments.LaunchPrepaidGiveaway
| stickers.CreateStickerSet | stickers.RemoveStickerFromSet | stickers.ChangeStickerPosition | stickers.AddStickerToSet | stickers.SetStickerSetThumb | stickers.CheckShortName | stickers.SuggestShortName | stickers.ChangeSticker | stickers.RenameStickerSet | stickers.DeleteStickerSet | stickers.CreateStickerSet | stickers.RemoveStickerFromSet | stickers.ChangeStickerPosition | stickers.AddStickerToSet | stickers.SetStickerSetThumb | stickers.CheckShortName | stickers.SuggestShortName | stickers.ChangeSticker | stickers.RenameStickerSet | stickers.DeleteStickerSet

View File

@ -81,7 +81,7 @@ chatForbidden#6592a1a7 id:long title:string = Chat;
channel#aadfc8f flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true gigagroup:flags.26?true noforwards:flags.27?true join_to_send:flags.28?true join_request:flags.29?true forum:flags.30?true flags2:# stories_hidden:flags2.1?true stories_hidden_min:flags2.2?true stories_unavailable:flags2.3?true id:long access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int restriction_reason:flags.9?Vector<RestrictionReason> admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int usernames:flags2.0?Vector<Username> stories_max_id:flags2.4?int color:flags2.7?PeerColor profile_color:flags2.8?PeerColor emoji_status:flags2.9?EmojiStatus level:flags2.10?int = Chat; channel#aadfc8f flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true gigagroup:flags.26?true noforwards:flags.27?true join_to_send:flags.28?true join_request:flags.29?true forum:flags.30?true flags2:# stories_hidden:flags2.1?true stories_hidden_min:flags2.2?true stories_unavailable:flags2.3?true id:long access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int restriction_reason:flags.9?Vector<RestrictionReason> admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int usernames:flags2.0?Vector<Username> stories_max_id:flags2.4?int color:flags2.7?PeerColor profile_color:flags2.8?PeerColor emoji_status:flags2.9?EmojiStatus level:flags2.10?int = Chat;
channelForbidden#17d493d5 flags:# broadcast:flags.5?true megagroup:flags.8?true id:long access_hash:long title:string until_date:flags.16?int = Chat; channelForbidden#17d493d5 flags:# broadcast:flags.5?true megagroup:flags.8?true id:long access_hash:long title:string until_date:flags.16?int = Chat;
chatFull#c9d31138 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true translations_disabled:flags.19?true id:long about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string requests_pending:flags.17?int recent_requesters:flags.17?Vector<long> available_reactions:flags.18?ChatReactions = ChatFull; chatFull#c9d31138 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true translations_disabled:flags.19?true id:long about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string requests_pending:flags.17?int recent_requesters:flags.17?Vector<long> available_reactions:flags.18?ChatReactions = ChatFull;
channelFull#f2bcb6f flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags2.0?true antispam:flags2.1?true participants_hidden:flags2.2?true translations_disabled:flags2.3?true stories_pinned_available:flags2.5?true view_forum_as_messages:flags2.6?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector<string> groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector<long> default_send_as:flags.29?Peer available_reactions:flags.30?ChatReactions stories:flags2.4?PeerStories wallpaper:flags2.7?WallPaper = ChatFull; channelFull#44c054a7 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags2.0?true antispam:flags2.1?true participants_hidden:flags2.2?true translations_disabled:flags2.3?true stories_pinned_available:flags2.5?true view_forum_as_messages:flags2.6?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector<string> groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector<long> default_send_as:flags.29?Peer available_reactions:flags.30?ChatReactions stories:flags2.4?PeerStories wallpaper:flags2.7?WallPaper boosts_applied:flags2.8?int boosts_unrestrict:flags2.9?int emojiset:flags2.10?StickerSet = ChatFull;
chatParticipant#c02d4007 user_id:long inviter_id:long date:int = ChatParticipant; chatParticipant#c02d4007 user_id:long inviter_id:long date:int = ChatParticipant;
chatParticipantCreator#e46bcee4 user_id:long = ChatParticipant; chatParticipantCreator#e46bcee4 user_id:long = ChatParticipant;
chatParticipantAdmin#a0933f5b user_id:long inviter_id:long date:int = ChatParticipant; chatParticipantAdmin#a0933f5b user_id:long inviter_id:long date:int = ChatParticipant;
@ -90,7 +90,7 @@ chatParticipants#3cbc93f8 chat_id:long participants:Vector<ChatParticipant> vers
chatPhotoEmpty#37c1011c = ChatPhoto; chatPhotoEmpty#37c1011c = ChatPhoto;
chatPhoto#1c6e1c11 flags:# has_video:flags.0?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = ChatPhoto; chatPhoto#1c6e1c11 flags:# has_video:flags.0?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = ChatPhoto;
messageEmpty#90a6ca84 flags:# id:int peer_id:flags.0?Peer = Message; messageEmpty#90a6ca84 flags:# id:int peer_id:flags.0?Peer = Message;
message#76bec211 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true noforwards:flags.26?true invert_media:flags.27?true id:int from_id:flags.8?Peer peer_id:Peer saved_peer_id:flags.28?Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long reactions:flags.20?MessageReactions restriction_reason:flags.22?Vector<RestrictionReason> ttl_period:flags.25?int = Message; message#1e4c8a69 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true noforwards:flags.26?true invert_media:flags.27?true id:int from_id:flags.8?Peer from_boosts_applied:flags.29?int peer_id:Peer saved_peer_id:flags.28?Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long reactions:flags.20?MessageReactions restriction_reason:flags.22?Vector<RestrictionReason> ttl_period:flags.25?int = Message;
messageService#2b085862 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?Peer peer_id:Peer reply_to:flags.3?MessageReplyHeader date:int action:MessageAction ttl_period:flags.25?int = Message; messageService#2b085862 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?Peer peer_id:Peer reply_to:flags.3?MessageReplyHeader date:int action:MessageAction ttl_period:flags.25?int = Message;
messageMediaEmpty#3ded6320 = MessageMedia; messageMediaEmpty#3ded6320 = MessageMedia;
messageMediaPhoto#695150d7 flags:# spoiler:flags.3?true photo:flags.0?Photo ttl_seconds:flags.2?int = MessageMedia; messageMediaPhoto#695150d7 flags:# spoiler:flags.3?true photo:flags.0?Photo ttl_seconds:flags.2?int = MessageMedia;
@ -149,6 +149,7 @@ messageActionSetChatWallPaper#5060a3f4 flags:# same:flags.0?true for_both:flags.
messageActionGiftCode#678c2e09 flags:# via_giveaway:flags.0?true unclaimed:flags.2?true boost_peer:flags.1?Peer months:int slug:string currency:flags.2?string amount:flags.2?long crypto_currency:flags.3?string crypto_amount:flags.3?long = MessageAction; messageActionGiftCode#678c2e09 flags:# via_giveaway:flags.0?true unclaimed:flags.2?true boost_peer:flags.1?Peer months:int slug:string currency:flags.2?string amount:flags.2?long crypto_currency:flags.3?string crypto_amount:flags.3?long = MessageAction;
messageActionGiveawayLaunch#332ba9ed = MessageAction; messageActionGiveawayLaunch#332ba9ed = MessageAction;
messageActionGiveawayResults#2a9fadc5 winners_count:int unclaimed_count:int = MessageAction; messageActionGiveawayResults#2a9fadc5 winners_count:int unclaimed_count:int = MessageAction;
messageActionBoostApply#cc02aa6d boosts:int = MessageAction;
dialog#d58a08c6 flags:# pinned:flags.2?true unread_mark:flags.3?true view_forum_as_messages:flags.6?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?int = Dialog; dialog#d58a08c6 flags:# pinned:flags.2?true unread_mark:flags.3?true view_forum_as_messages:flags.6?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?int = Dialog;
dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog; dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog;
photoEmpty#2331b22d id:long = Photo; photoEmpty#2331b22d id:long = Photo;
@ -797,6 +798,7 @@ channelAdminLogEventActionChangePeerColor#5796e780 prev_value:PeerColor new_valu
channelAdminLogEventActionChangeProfilePeerColor#5e477b25 prev_value:PeerColor new_value:PeerColor = ChannelAdminLogEventAction; channelAdminLogEventActionChangeProfilePeerColor#5e477b25 prev_value:PeerColor new_value:PeerColor = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeWallpaper#31bb5d52 prev_value:WallPaper new_value:WallPaper = ChannelAdminLogEventAction; channelAdminLogEventActionChangeWallpaper#31bb5d52 prev_value:WallPaper new_value:WallPaper = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeEmojiStatus#3ea9feb1 prev_value:EmojiStatus new_value:EmojiStatus = ChannelAdminLogEventAction; channelAdminLogEventActionChangeEmojiStatus#3ea9feb1 prev_value:EmojiStatus new_value:EmojiStatus = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeEmojiStickerSet#46d840ab prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction;
channelAdminLogEvent#1fad68cd id:long date:int user_id:long action:ChannelAdminLogEventAction = ChannelAdminLogEvent; channelAdminLogEvent#1fad68cd id:long date:int user_id:long action:ChannelAdminLogEventAction = ChannelAdminLogEvent;
channels.adminLogResults#ed8af74d events:Vector<ChannelAdminLogEvent> chats:Vector<Chat> users:Vector<User> = channels.AdminLogResults; channels.adminLogResults#ed8af74d events:Vector<ChannelAdminLogEvent> chats:Vector<Chat> users:Vector<User> = channels.AdminLogResults;
channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true group_call:flags.14?true invites:flags.15?true send:flags.16?true forums:flags.17?true = ChannelAdminLogEventsFilter; channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true group_call:flags.14?true invites:flags.15?true send:flags.16?true forums:flags.17?true = ChannelAdminLogEventsFilter;
@ -982,7 +984,7 @@ messageViews#455b853d flags:# views:flags.0?int forwards:flags.1?int replies:fla
messages.messageViews#b6c4f543 views:Vector<MessageViews> chats:Vector<Chat> users:Vector<User> = messages.MessageViews; messages.messageViews#b6c4f543 views:Vector<MessageViews> chats:Vector<Chat> users:Vector<User> = messages.MessageViews;
messages.discussionMessage#a6341782 flags:# messages:Vector<Message> max_id:flags.0?int read_inbox_max_id:flags.1?int read_outbox_max_id:flags.2?int unread_count:int chats:Vector<Chat> users:Vector<User> = messages.DiscussionMessage; messages.discussionMessage#a6341782 flags:# messages:Vector<Message> max_id:flags.0?int read_inbox_max_id:flags.1?int read_outbox_max_id:flags.2?int unread_count:int chats:Vector<Chat> users:Vector<User> = messages.DiscussionMessage;
messageReplyHeader#afbc09db flags:# reply_to_scheduled:flags.2?true forum_topic:flags.3?true quote:flags.9?true reply_to_msg_id:flags.4?int reply_to_peer_id:flags.0?Peer reply_from:flags.5?MessageFwdHeader reply_media:flags.8?MessageMedia reply_to_top_id:flags.1?int quote_text:flags.6?string quote_entities:flags.7?Vector<MessageEntity> quote_offset:flags.10?int = MessageReplyHeader; messageReplyHeader#afbc09db flags:# reply_to_scheduled:flags.2?true forum_topic:flags.3?true quote:flags.9?true reply_to_msg_id:flags.4?int reply_to_peer_id:flags.0?Peer reply_from:flags.5?MessageFwdHeader reply_media:flags.8?MessageMedia reply_to_top_id:flags.1?int quote_text:flags.6?string quote_entities:flags.7?Vector<MessageEntity> quote_offset:flags.10?int = MessageReplyHeader;
messageReplyStoryHeader#9c98bfc1 user_id:long story_id:int = MessageReplyHeader; messageReplyStoryHeader#e5af939 peer:Peer story_id:int = MessageReplyHeader;
messageReplies#83d60fc2 flags:# comments:flags.0?true replies:int replies_pts:int recent_repliers:flags.1?Vector<Peer> channel_id:flags.0?long max_id:flags.2?int read_max_id:flags.3?int = MessageReplies; messageReplies#83d60fc2 flags:# comments:flags.0?true replies:int replies_pts:int recent_repliers:flags.1?Vector<Peer> channel_id:flags.0?long max_id:flags.2?int read_max_id:flags.3?int = MessageReplies;
peerBlocked#e8fd8014 peer_id:Peer date:int = PeerBlocked; peerBlocked#e8fd8014 peer_id:Peer date:int = PeerBlocked;
stats.messageStats#7fe91c14 views_graph:StatsGraph reactions_by_emotion_graph:StatsGraph = stats.MessageStats; stats.messageStats#7fe91c14 views_graph:StatsGraph reactions_by_emotion_graph:StatsGraph = stats.MessageStats;
@ -1152,7 +1154,7 @@ sponsoredWebPage#3db8ec63 flags:# url:string site_name:string photo:flags.0?Phot
storyViews#8d595cd6 flags:# has_viewers:flags.1?true views_count:int forwards_count:flags.2?int reactions:flags.3?Vector<ReactionCount> reactions_count:flags.4?int recent_viewers:flags.0?Vector<long> = StoryViews; storyViews#8d595cd6 flags:# has_viewers:flags.1?true views_count:int forwards_count:flags.2?int reactions:flags.3?Vector<ReactionCount> reactions_count:flags.4?int recent_viewers:flags.0?Vector<long> = StoryViews;
storyItemDeleted#51e6ee4f id:int = StoryItem; storyItemDeleted#51e6ee4f id:int = StoryItem;
storyItemSkipped#ffadc913 flags:# close_friends:flags.8?true id:int date:int expire_date:int = StoryItem; storyItemSkipped#ffadc913 flags:# close_friends:flags.8?true id:int date:int expire_date:int = StoryItem;
storyItem#af6365a1 flags:# pinned:flags.5?true public:flags.7?true close_friends:flags.8?true min:flags.9?true noforwards:flags.10?true edited:flags.11?true contacts:flags.12?true selected_contacts:flags.13?true out:flags.16?true id:int date:int fwd_from:flags.17?StoryFwdHeader expire_date:int caption:flags.0?string entities:flags.1?Vector<MessageEntity> media:MessageMedia media_areas:flags.14?Vector<MediaArea> privacy:flags.2?Vector<PrivacyRule> views:flags.3?StoryViews sent_reaction:flags.15?Reaction = StoryItem; storyItem#79b26a24 flags:# pinned:flags.5?true public:flags.7?true close_friends:flags.8?true min:flags.9?true noforwards:flags.10?true edited:flags.11?true contacts:flags.12?true selected_contacts:flags.13?true out:flags.16?true id:int date:int from_id:flags.18?Peer fwd_from:flags.17?StoryFwdHeader expire_date:int caption:flags.0?string entities:flags.1?Vector<MessageEntity> media:MessageMedia media_areas:flags.14?Vector<MediaArea> privacy:flags.2?Vector<PrivacyRule> views:flags.3?StoryViews sent_reaction:flags.15?Reaction = StoryItem;
stories.allStoriesNotModified#1158fe3e flags:# state:string stealth_mode:StoriesStealthMode = stories.AllStories; stories.allStoriesNotModified#1158fe3e flags:# state:string stealth_mode:StoriesStealthMode = stories.AllStories;
stories.allStories#6efc5e81 flags:# has_more:flags.0?true count:int state:string peer_stories:Vector<PeerStories> chats:Vector<Chat> users:Vector<User> stealth_mode:StoriesStealthMode = stories.AllStories; stories.allStories#6efc5e81 flags:# has_more:flags.0?true count:int state:string peer_stories:Vector<PeerStories> chats:Vector<Chat> users:Vector<User> stealth_mode:StoriesStealthMode = stories.AllStories;
stories.stories#5dd8c3c8 count:int stories:Vector<StoryItem> chats:Vector<Chat> users:Vector<User> = stories.Stories; stories.stories#5dd8c3c8 count:int stories:Vector<StoryItem> chats:Vector<Chat> users:Vector<User> = stories.Stories;
@ -1162,7 +1164,7 @@ storyViewPublicRepost#bd74cf49 flags:# blocked:flags.0?true blocked_my_stories_f
stories.storyViewsList#59d78fc5 flags:# count:int views_count:int forwards_count:int reactions_count:int views:Vector<StoryView> chats:Vector<Chat> users:Vector<User> next_offset:flags.0?string = stories.StoryViewsList; stories.storyViewsList#59d78fc5 flags:# count:int views_count:int forwards_count:int reactions_count:int views:Vector<StoryView> chats:Vector<Chat> users:Vector<User> next_offset:flags.0?string = stories.StoryViewsList;
stories.storyViews#de9eed1d views:Vector<StoryViews> users:Vector<User> = stories.StoryViews; stories.storyViews#de9eed1d views:Vector<StoryViews> users:Vector<User> = stories.StoryViews;
inputReplyToMessage#22c0f6d5 flags:# reply_to_msg_id:int top_msg_id:flags.0?int reply_to_peer_id:flags.1?InputPeer quote_text:flags.2?string quote_entities:flags.3?Vector<MessageEntity> quote_offset:flags.4?int = InputReplyTo; inputReplyToMessage#22c0f6d5 flags:# reply_to_msg_id:int top_msg_id:flags.0?int reply_to_peer_id:flags.1?InputPeer quote_text:flags.2?string quote_entities:flags.3?Vector<MessageEntity> quote_offset:flags.4?int = InputReplyTo;
inputReplyToStory#15b0f283 user_id:InputUser story_id:int = InputReplyTo; inputReplyToStory#5881323a peer:InputPeer story_id:int = InputReplyTo;
exportedStoryLink#3fc9053b link:string = ExportedStoryLink; exportedStoryLink#3fc9053b link:string = ExportedStoryLink;
storiesStealthMode#712e27fd flags:# active_until_date:flags.0?int cooldown_until_date:flags.1?int = StoriesStealthMode; storiesStealthMode#712e27fd flags:# active_until_date:flags.0?int cooldown_until_date:flags.1?int = StoriesStealthMode;
mediaAreaCoordinates#3d1ea4e x:double y:double w:double h:double rotation:double = MediaAreaCoordinates; mediaAreaCoordinates#3d1ea4e x:double y:double w:double h:double rotation:double = MediaAreaCoordinates;
@ -1195,7 +1197,7 @@ stats.publicForwards#93037e20 flags:# count:int forwards:Vector<PublicForward> n
peerColor#b54b5acf flags:# color:flags.0?int background_emoji_id:flags.1?long = PeerColor; peerColor#b54b5acf flags:# color:flags.0?int background_emoji_id:flags.1?long = PeerColor;
help.peerColorSet#26219a58 colors:Vector<int> = help.PeerColorSet; help.peerColorSet#26219a58 colors:Vector<int> = help.PeerColorSet;
help.peerColorProfileSet#767d61eb palette_colors:Vector<int> bg_colors:Vector<int> story_colors:Vector<int> = help.PeerColorSet; help.peerColorProfileSet#767d61eb palette_colors:Vector<int> bg_colors:Vector<int> story_colors:Vector<int> = help.PeerColorSet;
help.peerColorOption#ef8430ab flags:# hidden:flags.0?true color_id:int colors:flags.1?help.PeerColorSet dark_colors:flags.2?help.PeerColorSet channel_min_level:flags.3?int = help.PeerColorOption; help.peerColorOption#adec6ebe flags:# hidden:flags.0?true color_id:int colors:flags.1?help.PeerColorSet dark_colors:flags.2?help.PeerColorSet channel_min_level:flags.3?int group_min_level:flags.4?int = help.PeerColorOption;
help.peerColorsNotModified#2ba1f5ce = help.PeerColors; help.peerColorsNotModified#2ba1f5ce = help.PeerColors;
help.peerColors#f8ed08 hash:int colors:Vector<help.PeerColorOption> = help.PeerColors; help.peerColors#f8ed08 hash:int colors:Vector<help.PeerColorOption> = help.PeerColors;
storyReaction#6090d6d5 peer_id:Peer date:int reaction:Reaction = StoryReaction; storyReaction#6090d6d5 peer_id:Peer date:int reaction:Reaction = StoryReaction;
@ -1538,6 +1540,7 @@ stories.getStoriesByID#5774ca74 peer:InputPeer id:Vector<int> = stories.Stories;
stories.readStories#a556dac8 peer:InputPeer max_id:int = Vector<int>; stories.readStories#a556dac8 peer:InputPeer max_id:int = Vector<int>;
stories.incrementStoryViews#b2028afb peer:InputPeer id:Vector<int> = Bool; stories.incrementStoryViews#b2028afb peer:InputPeer id:Vector<int> = Bool;
stories.getStoryViewsList#7ed23c57 flags:# just_contacts:flags.0?true reactions_first:flags.2?true forwards_first:flags.3?true peer:InputPeer q:flags.1?string id:int offset:string limit:int = stories.StoryViewsList; stories.getStoryViewsList#7ed23c57 flags:# just_contacts:flags.0?true reactions_first:flags.2?true forwards_first:flags.3?true peer:InputPeer q:flags.1?string id:int offset:string limit:int = stories.StoryViewsList;
stories.getStoriesViews#28e16cc8 peer:InputPeer id:Vector<int> = stories.StoryViews;
stories.exportStoryLink#7b8def20 peer:InputPeer id:int = ExportedStoryLink; stories.exportStoryLink#7b8def20 peer:InputPeer id:int = ExportedStoryLink;
stories.report#1923fa8c peer:InputPeer id:Vector<int> reason:ReportReason message:string = Bool; stories.report#1923fa8c peer:InputPeer id:Vector<int> reason:ReportReason message:string = Bool;
stories.activateStealthMode#57bbd166 flags:# past:flags.0?true future:flags.1?true = Updates; stories.activateStealthMode#57bbd166 flags:# past:flags.0?true future:flags.1?true = Updates;

View File

@ -331,6 +331,7 @@
"stories.getPeerMaxIDs", "stories.getPeerMaxIDs",
"stories.togglePeerStoriesHidden", "stories.togglePeerStoriesHidden",
"stories.getPeerStories", "stories.getPeerStories",
"stories.getStoriesViews",
"premium.getBoostsStatus", "premium.getBoostsStatus",
"premium.getBoostersList", "premium.getBoostersList",
"premium.applyBoost", "premium.applyBoost",

View File

@ -101,7 +101,7 @@ channel#aadfc8f flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5
channelForbidden#17d493d5 flags:# broadcast:flags.5?true megagroup:flags.8?true id:long access_hash:long title:string until_date:flags.16?int = Chat; channelForbidden#17d493d5 flags:# broadcast:flags.5?true megagroup:flags.8?true id:long access_hash:long title:string until_date:flags.16?int = Chat;
chatFull#c9d31138 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true translations_disabled:flags.19?true id:long about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string requests_pending:flags.17?int recent_requesters:flags.17?Vector<long> available_reactions:flags.18?ChatReactions = ChatFull; chatFull#c9d31138 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true translations_disabled:flags.19?true id:long about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string requests_pending:flags.17?int recent_requesters:flags.17?Vector<long> available_reactions:flags.18?ChatReactions = ChatFull;
channelFull#f2bcb6f flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags2.0?true antispam:flags2.1?true participants_hidden:flags2.2?true translations_disabled:flags2.3?true stories_pinned_available:flags2.5?true view_forum_as_messages:flags2.6?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector<string> groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector<long> default_send_as:flags.29?Peer available_reactions:flags.30?ChatReactions stories:flags2.4?PeerStories wallpaper:flags2.7?WallPaper = ChatFull; channelFull#44c054a7 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags2.0?true antispam:flags2.1?true participants_hidden:flags2.2?true translations_disabled:flags2.3?true stories_pinned_available:flags2.5?true view_forum_as_messages:flags2.6?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector<string> groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector<long> default_send_as:flags.29?Peer available_reactions:flags.30?ChatReactions stories:flags2.4?PeerStories wallpaper:flags2.7?WallPaper boosts_applied:flags2.8?int boosts_unrestrict:flags2.9?int emojiset:flags2.10?StickerSet = ChatFull;
chatParticipant#c02d4007 user_id:long inviter_id:long date:int = ChatParticipant; chatParticipant#c02d4007 user_id:long inviter_id:long date:int = ChatParticipant;
chatParticipantCreator#e46bcee4 user_id:long = ChatParticipant; chatParticipantCreator#e46bcee4 user_id:long = ChatParticipant;
@ -114,7 +114,7 @@ chatPhotoEmpty#37c1011c = ChatPhoto;
chatPhoto#1c6e1c11 flags:# has_video:flags.0?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = ChatPhoto; chatPhoto#1c6e1c11 flags:# has_video:flags.0?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = ChatPhoto;
messageEmpty#90a6ca84 flags:# id:int peer_id:flags.0?Peer = Message; messageEmpty#90a6ca84 flags:# id:int peer_id:flags.0?Peer = Message;
message#76bec211 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true noforwards:flags.26?true invert_media:flags.27?true id:int from_id:flags.8?Peer peer_id:Peer saved_peer_id:flags.28?Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long reactions:flags.20?MessageReactions restriction_reason:flags.22?Vector<RestrictionReason> ttl_period:flags.25?int = Message; message#1e4c8a69 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true noforwards:flags.26?true invert_media:flags.27?true id:int from_id:flags.8?Peer from_boosts_applied:flags.29?int peer_id:Peer saved_peer_id:flags.28?Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long reactions:flags.20?MessageReactions restriction_reason:flags.22?Vector<RestrictionReason> ttl_period:flags.25?int = Message;
messageService#2b085862 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?Peer peer_id:Peer reply_to:flags.3?MessageReplyHeader date:int action:MessageAction ttl_period:flags.25?int = Message; messageService#2b085862 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?Peer peer_id:Peer reply_to:flags.3?MessageReplyHeader date:int action:MessageAction ttl_period:flags.25?int = Message;
messageMediaEmpty#3ded6320 = MessageMedia; messageMediaEmpty#3ded6320 = MessageMedia;
@ -175,6 +175,7 @@ messageActionSetChatWallPaper#5060a3f4 flags:# same:flags.0?true for_both:flags.
messageActionGiftCode#678c2e09 flags:# via_giveaway:flags.0?true unclaimed:flags.2?true boost_peer:flags.1?Peer months:int slug:string currency:flags.2?string amount:flags.2?long crypto_currency:flags.3?string crypto_amount:flags.3?long = MessageAction; messageActionGiftCode#678c2e09 flags:# via_giveaway:flags.0?true unclaimed:flags.2?true boost_peer:flags.1?Peer months:int slug:string currency:flags.2?string amount:flags.2?long crypto_currency:flags.3?string crypto_amount:flags.3?long = MessageAction;
messageActionGiveawayLaunch#332ba9ed = MessageAction; messageActionGiveawayLaunch#332ba9ed = MessageAction;
messageActionGiveawayResults#2a9fadc5 winners_count:int unclaimed_count:int = MessageAction; messageActionGiveawayResults#2a9fadc5 winners_count:int unclaimed_count:int = MessageAction;
messageActionBoostApply#cc02aa6d boosts:int = MessageAction;
dialog#d58a08c6 flags:# pinned:flags.2?true unread_mark:flags.3?true view_forum_as_messages:flags.6?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?int = Dialog; dialog#d58a08c6 flags:# pinned:flags.2?true unread_mark:flags.3?true view_forum_as_messages:flags.6?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?int = Dialog;
dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog; dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog;
@ -980,6 +981,7 @@ channelAdminLogEventActionChangePeerColor#5796e780 prev_value:PeerColor new_valu
channelAdminLogEventActionChangeProfilePeerColor#5e477b25 prev_value:PeerColor new_value:PeerColor = ChannelAdminLogEventAction; channelAdminLogEventActionChangeProfilePeerColor#5e477b25 prev_value:PeerColor new_value:PeerColor = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeWallpaper#31bb5d52 prev_value:WallPaper new_value:WallPaper = ChannelAdminLogEventAction; channelAdminLogEventActionChangeWallpaper#31bb5d52 prev_value:WallPaper new_value:WallPaper = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeEmojiStatus#3ea9feb1 prev_value:EmojiStatus new_value:EmojiStatus = ChannelAdminLogEventAction; channelAdminLogEventActionChangeEmojiStatus#3ea9feb1 prev_value:EmojiStatus new_value:EmojiStatus = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeEmojiStickerSet#46d840ab prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction;
channelAdminLogEvent#1fad68cd id:long date:int user_id:long action:ChannelAdminLogEventAction = ChannelAdminLogEvent; channelAdminLogEvent#1fad68cd id:long date:int user_id:long action:ChannelAdminLogEventAction = ChannelAdminLogEvent;
@ -1275,7 +1277,7 @@ messages.messageViews#b6c4f543 views:Vector<MessageViews> chats:Vector<Chat> use
messages.discussionMessage#a6341782 flags:# messages:Vector<Message> max_id:flags.0?int read_inbox_max_id:flags.1?int read_outbox_max_id:flags.2?int unread_count:int chats:Vector<Chat> users:Vector<User> = messages.DiscussionMessage; messages.discussionMessage#a6341782 flags:# messages:Vector<Message> max_id:flags.0?int read_inbox_max_id:flags.1?int read_outbox_max_id:flags.2?int unread_count:int chats:Vector<Chat> users:Vector<User> = messages.DiscussionMessage;
messageReplyHeader#afbc09db flags:# reply_to_scheduled:flags.2?true forum_topic:flags.3?true quote:flags.9?true reply_to_msg_id:flags.4?int reply_to_peer_id:flags.0?Peer reply_from:flags.5?MessageFwdHeader reply_media:flags.8?MessageMedia reply_to_top_id:flags.1?int quote_text:flags.6?string quote_entities:flags.7?Vector<MessageEntity> quote_offset:flags.10?int = MessageReplyHeader; messageReplyHeader#afbc09db flags:# reply_to_scheduled:flags.2?true forum_topic:flags.3?true quote:flags.9?true reply_to_msg_id:flags.4?int reply_to_peer_id:flags.0?Peer reply_from:flags.5?MessageFwdHeader reply_media:flags.8?MessageMedia reply_to_top_id:flags.1?int quote_text:flags.6?string quote_entities:flags.7?Vector<MessageEntity> quote_offset:flags.10?int = MessageReplyHeader;
messageReplyStoryHeader#9c98bfc1 user_id:long story_id:int = MessageReplyHeader; messageReplyStoryHeader#e5af939 peer:Peer story_id:int = MessageReplyHeader;
messageReplies#83d60fc2 flags:# comments:flags.0?true replies:int replies_pts:int recent_repliers:flags.1?Vector<Peer> channel_id:flags.0?long max_id:flags.2?int read_max_id:flags.3?int = MessageReplies; messageReplies#83d60fc2 flags:# comments:flags.0?true replies:int replies_pts:int recent_repliers:flags.1?Vector<Peer> channel_id:flags.0?long max_id:flags.2?int read_max_id:flags.3?int = MessageReplies;
@ -1554,7 +1556,7 @@ storyViews#8d595cd6 flags:# has_viewers:flags.1?true views_count:int forwards_co
storyItemDeleted#51e6ee4f id:int = StoryItem; storyItemDeleted#51e6ee4f id:int = StoryItem;
storyItemSkipped#ffadc913 flags:# close_friends:flags.8?true id:int date:int expire_date:int = StoryItem; storyItemSkipped#ffadc913 flags:# close_friends:flags.8?true id:int date:int expire_date:int = StoryItem;
storyItem#af6365a1 flags:# pinned:flags.5?true public:flags.7?true close_friends:flags.8?true min:flags.9?true noforwards:flags.10?true edited:flags.11?true contacts:flags.12?true selected_contacts:flags.13?true out:flags.16?true id:int date:int fwd_from:flags.17?StoryFwdHeader expire_date:int caption:flags.0?string entities:flags.1?Vector<MessageEntity> media:MessageMedia media_areas:flags.14?Vector<MediaArea> privacy:flags.2?Vector<PrivacyRule> views:flags.3?StoryViews sent_reaction:flags.15?Reaction = StoryItem; storyItem#79b26a24 flags:# pinned:flags.5?true public:flags.7?true close_friends:flags.8?true min:flags.9?true noforwards:flags.10?true edited:flags.11?true contacts:flags.12?true selected_contacts:flags.13?true out:flags.16?true id:int date:int from_id:flags.18?Peer fwd_from:flags.17?StoryFwdHeader expire_date:int caption:flags.0?string entities:flags.1?Vector<MessageEntity> media:MessageMedia media_areas:flags.14?Vector<MediaArea> privacy:flags.2?Vector<PrivacyRule> views:flags.3?StoryViews sent_reaction:flags.15?Reaction = StoryItem;
stories.allStoriesNotModified#1158fe3e flags:# state:string stealth_mode:StoriesStealthMode = stories.AllStories; stories.allStoriesNotModified#1158fe3e flags:# state:string stealth_mode:StoriesStealthMode = stories.AllStories;
stories.allStories#6efc5e81 flags:# has_more:flags.0?true count:int state:string peer_stories:Vector<PeerStories> chats:Vector<Chat> users:Vector<User> stealth_mode:StoriesStealthMode = stories.AllStories; stories.allStories#6efc5e81 flags:# has_more:flags.0?true count:int state:string peer_stories:Vector<PeerStories> chats:Vector<Chat> users:Vector<User> stealth_mode:StoriesStealthMode = stories.AllStories;
@ -1570,7 +1572,7 @@ stories.storyViewsList#59d78fc5 flags:# count:int views_count:int forwards_count
stories.storyViews#de9eed1d views:Vector<StoryViews> users:Vector<User> = stories.StoryViews; stories.storyViews#de9eed1d views:Vector<StoryViews> users:Vector<User> = stories.StoryViews;
inputReplyToMessage#22c0f6d5 flags:# reply_to_msg_id:int top_msg_id:flags.0?int reply_to_peer_id:flags.1?InputPeer quote_text:flags.2?string quote_entities:flags.3?Vector<MessageEntity> quote_offset:flags.4?int = InputReplyTo; inputReplyToMessage#22c0f6d5 flags:# reply_to_msg_id:int top_msg_id:flags.0?int reply_to_peer_id:flags.1?InputPeer quote_text:flags.2?string quote_entities:flags.3?Vector<MessageEntity> quote_offset:flags.4?int = InputReplyTo;
inputReplyToStory#15b0f283 user_id:InputUser story_id:int = InputReplyTo; inputReplyToStory#5881323a peer:InputPeer story_id:int = InputReplyTo;
exportedStoryLink#3fc9053b link:string = ExportedStoryLink; exportedStoryLink#3fc9053b link:string = ExportedStoryLink;
@ -1627,7 +1629,7 @@ peerColor#b54b5acf flags:# color:flags.0?int background_emoji_id:flags.1?long =
help.peerColorSet#26219a58 colors:Vector<int> = help.PeerColorSet; help.peerColorSet#26219a58 colors:Vector<int> = help.PeerColorSet;
help.peerColorProfileSet#767d61eb palette_colors:Vector<int> bg_colors:Vector<int> story_colors:Vector<int> = help.PeerColorSet; help.peerColorProfileSet#767d61eb palette_colors:Vector<int> bg_colors:Vector<int> story_colors:Vector<int> = help.PeerColorSet;
help.peerColorOption#ef8430ab flags:# hidden:flags.0?true color_id:int colors:flags.1?help.PeerColorSet dark_colors:flags.2?help.PeerColorSet channel_min_level:flags.3?int = help.PeerColorOption; help.peerColorOption#adec6ebe flags:# hidden:flags.0?true color_id:int colors:flags.1?help.PeerColorSet dark_colors:flags.2?help.PeerColorSet channel_min_level:flags.3?int group_min_level:flags.4?int = help.PeerColorOption;
help.peerColorsNotModified#2ba1f5ce = help.PeerColors; help.peerColorsNotModified#2ba1f5ce = help.PeerColors;
help.peerColors#f8ed08 hash:int colors:Vector<help.PeerColorOption> = help.PeerColors; help.peerColors#f8ed08 hash:int colors:Vector<help.PeerColorOption> = help.PeerColors;
@ -2111,6 +2113,8 @@ channels.updateColor#d8aa3671 flags:# for_profile:flags.1?true channel:InputChan
channels.toggleViewForumAsMessages#9738bb15 channel:InputChannel enabled:Bool = Updates; channels.toggleViewForumAsMessages#9738bb15 channel:InputChannel enabled:Bool = Updates;
channels.getChannelRecommendations#83b70d97 channel:InputChannel = messages.Chats; channels.getChannelRecommendations#83b70d97 channel:InputChannel = messages.Chats;
channels.updateEmojiStatus#f0d3e6a8 channel:InputChannel emoji_status:EmojiStatus = Updates; channels.updateEmojiStatus#f0d3e6a8 channel:InputChannel emoji_status:EmojiStatus = Updates;
channels.setBoostsToUnblockRestrictions#ad399cee channel:InputChannel boosts:int = Updates;
channels.setEmojiStickers#3cd930b7 channel:InputChannel stickerset:InputStickerSet = Bool;
bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON;
bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool;

View File

@ -53,212 +53,214 @@ $icons-map: (
"avatar-deleted-account": "\f116", "avatar-deleted-account": "\f116",
"avatar-saved-messages": "\f117", "avatar-saved-messages": "\f117",
"bold": "\f118", "bold": "\f118",
"boost": "\f119", "boost-outline": "\f119",
"boostcircle": "\f11a", "boost": "\f11a",
"bot-command": "\f11b", "boostcircle": "\f11b",
"bot-commands-filled": "\f11c", "boosts": "\f11c",
"bots": "\f11d", "bot-command": "\f11d",
"bug": "\f11e", "bot-commands-filled": "\f11e",
"calendar-filter": "\f11f", "bots": "\f11f",
"calendar": "\f120", "bug": "\f120",
"camera-add": "\f121", "calendar-filter": "\f121",
"camera": "\f122", "calendar": "\f122",
"car": "\f123", "camera-add": "\f123",
"card": "\f124", "camera": "\f124",
"channel-filled": "\f125", "car": "\f125",
"channel": "\f126", "card": "\f126",
"channelviews": "\f127", "channel-filled": "\f127",
"chat-badge": "\f128", "channel": "\f128",
"chats-badge": "\f129", "channelviews": "\f129",
"check": "\f12a", "chat-badge": "\f12a",
"close-circle": "\f12b", "chats-badge": "\f12b",
"close-topic": "\f12c", "check": "\f12c",
"close": "\f12d", "close-circle": "\f12d",
"cloud-download": "\f12e", "close-topic": "\f12e",
"collapse": "\f12f", "close": "\f12f",
"colorize": "\f130", "cloud-download": "\f130",
"comments-sticker": "\f131", "collapse": "\f131",
"comments": "\f132", "colorize": "\f132",
"copy-media": "\f133", "comments-sticker": "\f133",
"copy": "\f134", "comments": "\f134",
"darkmode": "\f135", "copy-media": "\f135",
"data": "\f136", "copy": "\f136",
"delete-filled": "\f137", "darkmode": "\f137",
"delete-left": "\f138", "data": "\f138",
"delete-user": "\f139", "delete-filled": "\f139",
"delete": "\f13a", "delete-left": "\f13a",
"document": "\f13b", "delete-user": "\f13b",
"double-badge": "\f13c", "delete": "\f13c",
"down": "\f13d", "document": "\f13d",
"download": "\f13e", "double-badge": "\f13e",
"eats": "\f13f", "down": "\f13f",
"edit": "\f140", "download": "\f140",
"email": "\f141", "eats": "\f141",
"enter": "\f142", "edit": "\f142",
"expand": "\f143", "email": "\f143",
"eye-closed-outline": "\f144", "enter": "\f144",
"eye-closed": "\f145", "expand": "\f145",
"eye-outline": "\f146", "eye-closed-outline": "\f146",
"eye": "\f147", "eye-closed": "\f147",
"favorite-filled": "\f148", "eye-outline": "\f148",
"favorite": "\f149", "eye": "\f149",
"file-badge": "\f14a", "favorite-filled": "\f14a",
"flag": "\f14b", "favorite": "\f14b",
"folder-badge": "\f14c", "file-badge": "\f14c",
"folder": "\f14d", "flag": "\f14d",
"fontsize": "\f14e", "folder-badge": "\f14e",
"forums": "\f14f", "folder": "\f14f",
"forward": "\f150", "fontsize": "\f150",
"fullscreen": "\f151", "forums": "\f151",
"gifs": "\f152", "forward": "\f152",
"gift": "\f153", "fullscreen": "\f153",
"group-filled": "\f154", "gifs": "\f154",
"group": "\f155", "gift": "\f155",
"grouped-disable": "\f156", "group-filled": "\f156",
"grouped": "\f157", "group": "\f157",
"hand-stop": "\f158", "grouped-disable": "\f158",
"hashtag": "\f159", "grouped": "\f159",
"heart-outline": "\f15a", "hand-stop": "\f15a",
"heart": "\f15b", "hashtag": "\f15b",
"help": "\f15c", "heart-outline": "\f15c",
"info-filled": "\f15d", "heart": "\f15d",
"info": "\f15e", "help": "\f15e",
"install": "\f15f", "info-filled": "\f15f",
"italic": "\f160", "info": "\f160",
"key": "\f161", "install": "\f161",
"keyboard": "\f162", "italic": "\f162",
"lamp": "\f163", "key": "\f163",
"language": "\f164", "keyboard": "\f164",
"large-pause": "\f165", "lamp": "\f165",
"large-play": "\f166", "language": "\f166",
"link-badge": "\f167", "large-pause": "\f167",
"link-broken": "\f168", "large-play": "\f168",
"link": "\f169", "link-badge": "\f169",
"location": "\f16a", "link-broken": "\f16a",
"lock-badge": "\f16b", "link": "\f16b",
"lock": "\f16c", "location": "\f16c",
"logout": "\f16d", "lock-badge": "\f16d",
"loop": "\f16e", "lock": "\f16e",
"mention": "\f16f", "logout": "\f16f",
"message-failed": "\f170", "loop": "\f170",
"message-pending": "\f171", "mention": "\f171",
"message-read": "\f172", "message-failed": "\f172",
"message-succeeded": "\f173", "message-pending": "\f173",
"message": "\f174", "message-read": "\f174",
"microphone-alt": "\f175", "message-succeeded": "\f175",
"microphone": "\f176", "message": "\f176",
"monospace": "\f177", "microphone-alt": "\f177",
"more-circle": "\f178", "microphone": "\f178",
"more": "\f179", "monospace": "\f179",
"mute": "\f17a", "more-circle": "\f17a",
"muted": "\f17b", "more": "\f17b",
"my-notes": "\f17c", "mute": "\f17c",
"new-chat-filled": "\f17d", "muted": "\f17d",
"next": "\f17e", "my-notes": "\f17e",
"noise-suppression": "\f17f", "new-chat-filled": "\f17f",
"non-contacts": "\f180", "next": "\f180",
"one-filled": "\f181", "noise-suppression": "\f181",
"open-in-new-tab": "\f182", "non-contacts": "\f182",
"password-off": "\f183", "one-filled": "\f183",
"pause": "\f184", "open-in-new-tab": "\f184",
"permissions": "\f185", "password-off": "\f185",
"phone-discard-outline": "\f186", "pause": "\f186",
"phone-discard": "\f187", "permissions": "\f187",
"phone": "\f188", "phone-discard-outline": "\f188",
"photo": "\f189", "phone-discard": "\f189",
"pin-badge": "\f18a", "phone": "\f18a",
"pin-list": "\f18b", "photo": "\f18b",
"pin": "\f18c", "pin-badge": "\f18c",
"pinned-chat": "\f18d", "pin-list": "\f18d",
"pinned-message": "\f18e", "pin": "\f18e",
"pip": "\f18f", "pinned-chat": "\f18f",
"play-story": "\f190", "pinned-message": "\f190",
"play": "\f191", "pip": "\f191",
"poll": "\f192", "play-story": "\f192",
"premium": "\f193", "play": "\f193",
"previous": "\f194", "poll": "\f194",
"privacy-policy": "\f195", "premium": "\f195",
"quote-text": "\f196", "previous": "\f196",
"quote": "\f197", "privacy-policy": "\f197",
"readchats": "\f198", "quote-text": "\f198",
"recent": "\f199", "quote": "\f199",
"reload": "\f19a", "readchats": "\f19a",
"remove": "\f19b", "recent": "\f19b",
"reopen-topic": "\f19c", "reload": "\f19c",
"replace": "\f19d", "remove": "\f19d",
"replies": "\f19e", "reopen-topic": "\f19e",
"reply-filled": "\f19f", "replace": "\f19f",
"reply": "\f1a0", "replies": "\f1a0",
"revote": "\f1a1", "reply-filled": "\f1a1",
"save-story": "\f1a2", "reply": "\f1a2",
"saved-messages": "\f1a3", "revote": "\f1a3",
"schedule": "\f1a4", "save-story": "\f1a4",
"search": "\f1a5", "saved-messages": "\f1a5",
"select": "\f1a6", "schedule": "\f1a6",
"send-outline": "\f1a7", "search": "\f1a7",
"send": "\f1a8", "select": "\f1a8",
"settings-filled": "\f1a9", "send-outline": "\f1a9",
"settings": "\f1aa", "send": "\f1aa",
"share-filled": "\f1ab", "settings-filled": "\f1ab",
"share-screen-outlined": "\f1ac", "settings": "\f1ac",
"share-screen-stop": "\f1ad", "share-filled": "\f1ad",
"share-screen": "\f1ae", "share-screen-outlined": "\f1ae",
"sidebar": "\f1af", "share-screen-stop": "\f1af",
"skip-next": "\f1b0", "share-screen": "\f1b0",
"skip-previous": "\f1b1", "sidebar": "\f1b1",
"smallscreen": "\f1b2", "skip-next": "\f1b2",
"smile": "\f1b3", "skip-previous": "\f1b3",
"sort": "\f1b4", "smallscreen": "\f1b4",
"speaker-muted-story": "\f1b5", "smile": "\f1b5",
"speaker-outline": "\f1b6", "sort": "\f1b6",
"speaker-story": "\f1b7", "speaker-muted-story": "\f1b7",
"speaker": "\f1b8", "speaker-outline": "\f1b8",
"spoiler-disable": "\f1b9", "speaker-story": "\f1b9",
"spoiler": "\f1ba", "speaker": "\f1ba",
"sport": "\f1bb", "spoiler-disable": "\f1bb",
"stats": "\f1bc", "spoiler": "\f1bc",
"stealth-future": "\f1bd", "sport": "\f1bd",
"stealth-past": "\f1be", "stats": "\f1be",
"stickers": "\f1bf", "stealth-future": "\f1bf",
"stop-raising-hand": "\f1c0", "stealth-past": "\f1c0",
"stop": "\f1c1", "stickers": "\f1c1",
"story-caption": "\f1c2", "stop-raising-hand": "\f1c2",
"story-expired": "\f1c3", "stop": "\f1c3",
"story-priority": "\f1c4", "story-caption": "\f1c4",
"story-reply": "\f1c5", "story-expired": "\f1c5",
"strikethrough": "\f1c6", "story-priority": "\f1c6",
"tag-add": "\f1c7", "story-reply": "\f1c7",
"tag-crossed": "\f1c8", "strikethrough": "\f1c8",
"tag-filter": "\f1c9", "tag-add": "\f1c9",
"tag-name": "\f1ca", "tag-crossed": "\f1ca",
"tag": "\f1cb", "tag-filter": "\f1cb",
"timer": "\f1cc", "tag-name": "\f1cc",
"transcribe": "\f1cd", "tag": "\f1cd",
"truck": "\f1ce", "timer": "\f1ce",
"unarchive": "\f1cf", "transcribe": "\f1cf",
"underlined": "\f1d0", "truck": "\f1d0",
"unlock-badge": "\f1d1", "unarchive": "\f1d1",
"unlock": "\f1d2", "underlined": "\f1d2",
"unmute": "\f1d3", "unlock-badge": "\f1d3",
"unpin": "\f1d4", "unlock": "\f1d4",
"unread": "\f1d5", "unmute": "\f1d5",
"up": "\f1d6", "unpin": "\f1d6",
"user-filled": "\f1d7", "unread": "\f1d7",
"user-online": "\f1d8", "up": "\f1d8",
"user": "\f1d9", "user-filled": "\f1d9",
"video-outlined": "\f1da", "user-online": "\f1da",
"video-stop": "\f1db", "user": "\f1db",
"video": "\f1dc", "video-outlined": "\f1dc",
"view-once": "\f1dd", "video-stop": "\f1dd",
"voice-chat": "\f1de", "video": "\f1de",
"volume-1": "\f1df", "view-once": "\f1df",
"volume-2": "\f1e0", "voice-chat": "\f1e0",
"volume-3": "\f1e1", "volume-1": "\f1e1",
"web": "\f1e2", "volume-2": "\f1e2",
"webapp": "\f1e3", "volume-3": "\f1e3",
"word-wrap": "\f1e4", "web": "\f1e4",
"zoom-in": "\f1e5", "webapp": "\f1e5",
"zoom-out": "\f1e6", "word-wrap": "\f1e6",
"zoom-in": "\f1e7",
"zoom-out": "\f1e8",
); );
.icon-active-sessions::before { .icon-active-sessions::before {
@ -333,12 +335,18 @@ $icons-map: (
.icon-bold::before { .icon-bold::before {
content: map.get($icons-map, "bold"); content: map.get($icons-map, "bold");
} }
.icon-boost-outline::before {
content: map.get($icons-map, "boost-outline");
}
.icon-boost::before { .icon-boost::before {
content: map.get($icons-map, "boost"); content: map.get($icons-map, "boost");
} }
.icon-boostcircle::before { .icon-boostcircle::before {
content: map.get($icons-map, "boostcircle"); content: map.get($icons-map, "boostcircle");
} }
.icon-boosts::before {
content: map.get($icons-map, "boosts");
}
.icon-bot-command::before { .icon-bot-command::before {
content: map.get($icons-map, "bot-command"); content: map.get($icons-map, "bot-command");
} }

Binary file not shown.

Binary file not shown.

View File

@ -23,8 +23,10 @@ export type FontIconName =
| 'avatar-deleted-account' | 'avatar-deleted-account'
| 'avatar-saved-messages' | 'avatar-saved-messages'
| 'bold' | 'bold'
| 'boost-outline'
| 'boost' | 'boost'
| 'boostcircle' | 'boostcircle'
| 'boosts'
| 'bot-command' | 'bot-command'
| 'bot-commands-filled' | 'bot-commands-filled'
| 'bots' | 'bots'