This commit is contained in:
Alexander Zinchuk 2023-12-28 14:38:19 +01:00
parent 6a8e685561
commit 8dbc9a590e
46 changed files with 1014 additions and 342 deletions

View File

@ -19,13 +19,17 @@ import type {
ApiTopic,
} from '../../types';
import { pick, pickTruthy } from '../../../util/iteratees';
import { omitUndefined, pick, pickTruthy } from '../../../util/iteratees';
import { getServerTime, getServerTimeOffset } from '../../../util/serverTime';
import { buildApiUsernames } from './common';
import { omitVirtualClassFields } from './helpers';
import {
buildApiEmojiStatus,
buildApiPeerColor,
buildApiPeerId, getApiChatIdFromMtpPeer, isPeerChat, isPeerUser,
buildApiPeerId,
getApiChatIdFromMtpPeer,
isPeerChat,
isPeerUser,
} from './peers';
import { buildApiReaction } from './reactions';
@ -40,10 +44,10 @@ function buildApiChatFieldsFromPeerEntity(
isSupport = false,
): PeerEntityApiChatFields {
const isMin = Boolean('min' in peerEntity && peerEntity.min);
const accessHash = ('accessHash' in peerEntity) && String(peerEntity.accessHash);
const accessHash = ('accessHash' in peerEntity) ? String(peerEntity.accessHash) : undefined;
const hasVideoAvatar = 'photo' in peerEntity && peerEntity.photo && 'hasVideo' in peerEntity.photo
&& peerEntity.photo.hasVideo;
const avatarHash = ('photo' in peerEntity) && peerEntity.photo && buildAvatarHash(peerEntity.photo);
const avatarHash = ('photo' in peerEntity) && peerEntity.photo ? buildAvatarHash(peerEntity.photo) : undefined;
const isSignaturesShown = Boolean('signatures' in peerEntity && peerEntity.signatures);
const hasPrivateLink = Boolean('hasLink' in peerEntity && peerEntity.hasLink);
const isScam = Boolean('scam' in peerEntity && peerEntity.scam);
@ -56,15 +60,17 @@ function buildApiChatFieldsFromPeerEntity(
const maxStoryId = 'storiesMaxId' in peerEntity ? peerEntity.storiesMaxId : undefined;
const storiesUnavailable = Boolean('storiesUnavailable' in peerEntity && peerEntity.storiesUnavailable);
const color = ('color' in peerEntity && peerEntity.color) ? buildApiPeerColor(peerEntity.color) : undefined;
const emojiStatus = ('emojiStatus' in peerEntity && peerEntity.emojiStatus)
? buildApiEmojiStatus(peerEntity.emojiStatus) : undefined;
return {
return omitUndefined({
isMin,
hasPrivateLink,
isSignaturesShown,
usernames,
...(accessHash && { accessHash }),
accessHash,
hasVideoAvatar,
...(avatarHash && { avatarHash }),
avatarHash,
...('verified' in peerEntity && { isVerified: peerEntity.verified }),
...('callActive' in peerEntity && { isCallActive: peerEntity.callActive }),
...('callNotEmpty' in peerEntity && { isCallNotEmpty: peerEntity.callNotEmpty }),
@ -73,7 +79,7 @@ function buildApiChatFieldsFromPeerEntity(
membersCount: peerEntity.participantsCount,
}),
...('noforwards' in peerEntity && { isProtected: Boolean(peerEntity.noforwards) }),
...(isSupport && { isSupport: true }),
isSupport: isSupport || undefined,
...buildApiChatPermissions(peerEntity),
...('creator' in peerEntity && { isCreator: peerEntity.creator }),
...buildApiChatRestrictions(peerEntity),
@ -86,7 +92,8 @@ function buildApiChatFieldsFromPeerEntity(
areStoriesHidden,
maxStoryId,
hasStories: Boolean(maxStoryId) && !storiesUnavailable,
};
emojiStatus,
});
}
export function buildApiChatFromDialog(

View File

@ -7,6 +7,7 @@ import type {
ApiFormattedText,
ApiGame,
ApiGiveaway,
ApiGiveawayResults,
ApiInvoice,
ApiLocation,
ApiMessageExtendedMediaPreview,
@ -122,6 +123,9 @@ export function buildMessageMediaContent(media: GramJs.TypeMessageMedia): MediaC
const giveaway = buildGiweawayFromMedia(media);
if (giveaway) return { giveaway };
const giveawayResults = buildGiweawayResultsFromMedia(media);
if (giveawayResults) return { giveawayResults };
return undefined;
}
@ -480,7 +484,7 @@ function buildGiweawayFromMedia(media: GramJs.TypeMessageMedia): ApiGiveaway | u
function buildGiveaway(media: GramJs.MessageMediaGiveaway): ApiGiveaway | undefined {
const {
channels, months, quantity, untilDate, countriesIso2, onlyNewSubscribers,
channels, months, quantity, untilDate, countriesIso2, onlyNewSubscribers, prizeDescription,
} = media;
const channelIds = channels.map((channel) => buildApiPeerId(channel, 'channel'));
@ -492,6 +496,38 @@ function buildGiveaway(media: GramJs.MessageMediaGiveaway): ApiGiveaway | undefi
untilDate,
countries: countriesIso2,
isOnlyForNewSubscribers: onlyNewSubscribers,
prizeDescription,
};
}
function buildGiweawayResultsFromMedia(media: GramJs.TypeMessageMedia): ApiGiveawayResults | undefined {
if (!(media instanceof GramJs.MessageMediaGiveawayResults)) {
return undefined;
}
return buildGiveawayResults(media);
}
function buildGiveawayResults(media: GramJs.MessageMediaGiveawayResults): ApiGiveawayResults | undefined {
const {
months, untilDate, onlyNewSubscribers, launchMsgId, unclaimedCount, winners, winnersCount,
additionalPeersCount, prizeDescription, refunded, channelId,
} = media;
const winnerIds = winners.map((winner) => buildApiPeerId(winner, 'user'));
return {
months,
untilDate,
isOnlyForNewSubscribers: onlyNewSubscribers,
launchMessageId: launchMsgId,
channelId: buildApiPeerId(channelId, 'channel'),
unclaimedCount,
additionalPeersCount,
isRefunded: refunded,
prizeDescription,
winnerIds,
winnersCount,
};
}

View File

@ -248,7 +248,7 @@ export function buildApiGiveawayInfo(info: GramJs.payments.TypeGiveawayInfo): Ap
type: 'active',
startDate,
isParticipating: participating,
adminDisallowedChatId: adminDisallowedChatId?.toString(),
adminDisallowedChatId: adminDisallowedChatId && buildApiPeerId(adminDisallowedChatId, 'channel'),
disallowedCountry,
joinedTooEarlyDate,
isPreparingResults: preparingResults,

View File

@ -1,7 +1,7 @@
import type BigInt from 'big-integer';
import { Api as GramJs } from '../../../lib/gramjs';
import type { Api as GramJs } from '../../../lib/gramjs';
import type { ApiPeerColor } from '../../types';
import type { ApiEmojiStatus, ApiPeerColor } from '../../types';
export function isPeerUser(peer: GramJs.TypePeer | GramJs.TypeInputPeer): peer is GramJs.PeerUser {
return peer.hasOwnProperty('userId');
@ -44,3 +44,15 @@ export function buildApiPeerColor(peerColor: GramJs.TypePeerColor): ApiPeerColor
backgroundEmojiId: backgroundEmojiId?.toString(),
};
}
export function buildApiEmojiStatus(mtpEmojiStatus: GramJs.TypeEmojiStatus): ApiEmojiStatus | undefined {
if (mtpEmojiStatus instanceof GramJs.EmojiStatus) {
return { documentId: mtpEmojiStatus.documentId.toString() };
}
if (mtpEmojiStatus instanceof GramJs.EmojiStatusUntil) {
return { documentId: mtpEmojiStatus.documentId.toString(), until: mtpEmojiStatus.until };
}
return undefined;
}

View File

@ -5,14 +5,17 @@ import type {
ApiMediaAreaCoordinates,
ApiStealthMode,
ApiStoryForwardInfo,
ApiStoryView, ApiStoryViews,
ApiStoryView,
ApiStoryViews,
ApiTypeStory,
ApiTypeStoryView,
MediaContent,
} from '../../types';
import { buildCollectionByCallback } from '../../../util/iteratees';
import { buildCollectionByCallback, omitUndefined } from '../../../util/iteratees';
import { buildPrivacyRules } from './common';
import { buildGeoPoint, buildMessageMediaContent, buildMessageTextContent } from './messageContent';
import { buildApiMessage } from './messages';
import { buildApiPeerId, getApiChatIdFromMtpPeer } from './peers';
import { buildApiReaction, buildReactionCount } from './reactions';
@ -88,17 +91,53 @@ function buildApiStoryViews(views: GramJs.TypeStoryViews): ApiStoryViews | undef
};
}
export function buildApiStoryView(view: GramJs.TypeStoryView): ApiStoryView {
export function buildApiStoryView(view: GramJs.TypeStoryView): ApiTypeStoryView | undefined {
const {
userId, date, reaction, blockedMyStoriesFrom, blocked,
blockedMyStoriesFrom, blocked,
} = view;
return {
userId: userId.toString(),
date,
...(reaction && { reaction: buildApiReaction(reaction) }),
areStoriesBlocked: blocked || blockedMyStoriesFrom,
isUserBlocked: blocked,
};
if (view instanceof GramJs.StoryView) {
return omitUndefined<ApiStoryView>({
type: 'user',
peerId: buildApiPeerId(view.userId, 'user'),
date: view.date,
reaction: view.reaction && buildApiReaction(view.reaction),
areStoriesBlocked: blocked || blockedMyStoriesFrom,
isUserBlocked: blocked,
});
}
if (view instanceof GramJs.StoryViewPublicForward) {
const message = buildApiMessage(view.message);
if (!message) return undefined;
return {
type: 'forward',
peerId: message.chatId,
messageId: message.id,
message,
date: message.date,
areStoriesBlocked: blocked || blockedMyStoriesFrom,
isUserBlocked: blocked,
};
}
if (view instanceof GramJs.StoryViewPublicRepost) {
const peerId = getApiChatIdFromMtpPeer(view.peerId);
const story = buildApiStory(peerId, view.story);
if (!('content' in story)) return undefined;
return {
type: 'repost',
peerId,
storyId: view.story.id,
date: story.date,
story,
areStoriesBlocked: blocked || blockedMyStoriesFrom,
isUserBlocked: blocked,
};
}
return undefined;
}
export function buildApiStealthMode(stealthMode: GramJs.TypeStoriesStealthMode): ApiStealthMode {
@ -167,6 +206,17 @@ export function buildApiMediaArea(area: GramJs.TypeMediaArea): ApiMediaArea | un
};
}
if (area instanceof GramJs.MediaAreaChannelPost) {
const { coordinates, channelId, msgId } = area;
return {
type: 'channelPost',
coordinates: buildApiMediaAreaCoordinates(coordinates),
channelId: buildApiPeerId(channelId, 'channel'),
messageId: msgId,
};
}
return undefined;
}
@ -177,11 +227,14 @@ export function buildApiPeerStories(peerStories: GramJs.PeerStories) {
}
export function buildApiStoryForwardInfo(forwardHeader: GramJs.TypeStoryFwdHeader): ApiStoryForwardInfo {
const { from, fromName, storyId } = forwardHeader;
const {
from, fromName, storyId, modified,
} = forwardHeader;
return {
storyId,
fromPeerId: from && getApiChatIdFromMtpPeer(from),
fromName,
isModified: modified,
};
}

View File

@ -1,7 +1,6 @@
import { Api as GramJs } from '../../../lib/gramjs';
import type {
ApiEmojiStatus,
ApiPremiumGiftOption,
ApiUser,
ApiUserFullInfo,
@ -11,7 +10,7 @@ import type {
import { buildApiBotInfo } from './bots';
import { buildApiPhoto, buildApiUsernames } from './common';
import { buildApiPeerColor, buildApiPeerId } from './peers';
import { buildApiEmojiStatus, buildApiPeerColor, buildApiPeerId } from './peers';
export function buildApiUserFullInfo(mtpUserFull: GramJs.users.UserFull): ApiUserFullInfo {
const {
@ -57,7 +56,7 @@ export function buildApiUser(mtpUser: GramJs.TypeUser): ApiUser | undefined {
: undefined;
const userType = buildApiUserType(mtpUser);
const usernames = buildApiUsernames(mtpUser);
const emojiStatus = mtpUser.emojiStatus ? buildApiUserEmojiStatus(mtpUser.emojiStatus) : undefined;
const emojiStatus = mtpUser.emojiStatus ? buildApiEmojiStatus(mtpUser.emojiStatus) : undefined;
return {
id: buildApiPeerId(id, 'user'),
@ -116,18 +115,6 @@ export function buildApiUserStatus(mtpStatus?: GramJs.TypeUserStatus): ApiUserSt
}
}
export function buildApiUserEmojiStatus(mtpEmojiStatus: GramJs.TypeEmojiStatus): ApiEmojiStatus | undefined {
if (mtpEmojiStatus instanceof GramJs.EmojiStatus) {
return { documentId: mtpEmojiStatus.documentId.toString() };
}
if (mtpEmojiStatus instanceof GramJs.EmojiStatusUntil) {
return { documentId: mtpEmojiStatus.documentId.toString(), until: mtpEmojiStatus.until };
}
return undefined;
}
export function buildApiUsersAndStatuses(mtpUsers: GramJs.TypeUser[]) {
const userStatusesById: Record<string, ApiUserStatus> = {};
const usersById: Record<string, ApiUser> = {};

View File

@ -87,22 +87,23 @@ export async function fetchMessagePublicForwards({
chat,
messageId,
dcId,
offsetRate = 0,
offset,
}: {
chat: ApiChat;
messageId: number;
dcId?: number;
offsetRate?: number;
offset?: string;
}): Promise<{
forwards?: ApiMessagePublicForward[];
count?: number;
nextRate?: number;
nextOffset?: string;
chats: ApiChat[];
users: ApiUser[];
} | undefined> {
const result = await invokeRequest(new GramJs.stats.GetMessagePublicForwards({
channel: buildInputEntity(chat.id, chat.accessHash) as GramJs.InputChannel,
msgId: messageId,
offsetPeer: new GramJs.InputPeerEmpty(),
offsetRate,
offset,
limit: STATISTICS_PUBLIC_FORWARDS_LIMIT,
}), {
dcId,
@ -112,16 +113,15 @@ export async function fetchMessagePublicForwards({
return undefined;
}
if ('chats' in result) {
addEntitiesToLocalDb(result.chats);
}
addEntitiesToLocalDb(result.chats);
addEntitiesToLocalDb(result.users);
return {
forwards: buildMessagePublicForwards(result),
...('nextRate' in result ? {
count: result.count,
nextRate: result.nextRate,
} : undefined),
count: result.count,
nextOffset: result.nextOffset,
chats: result.chats.map((c) => buildApiChatFromPreview(c)).filter(Boolean),
users: result.users.map(buildApiUser).filter(Boolean),
};
}
@ -177,23 +177,23 @@ export async function fetchStoryPublicForwards({
chat,
storyId,
dcId,
offsetId = '0',
offset,
}: {
chat: ApiChat;
storyId: number;
dcId?: number;
offsetId?: string;
offset?: string;
}): Promise<{
publicForwards: (ApiMessagePublicForward | ApiStoryPublicForward)[] | undefined;
users: ApiUser[];
chats: ApiChat[];
count?: number;
nextOffsetId?: string;
nextOffset?: string;
} | undefined> {
const result = await invokeRequest(new GramJs.stats.GetStoryPublicForwards({
peer: buildInputPeer(chat.id, chat.accessHash),
id: storyId,
offset: offsetId,
offset,
limit: STATISTICS_PUBLIC_FORWARDS_LIMIT,
}), {
dcId,
@ -211,6 +211,6 @@ export async function fetchStoryPublicForwards({
users: result.users.map(buildApiUser).filter(Boolean),
chats: result.chats.map((c) => buildApiChatFromPreview(c)).filter(Boolean),
count: result.count,
nextOffsetId: result.nextOffset,
nextOffset: result.nextOffset,
};
}

View File

@ -285,11 +285,14 @@ export async function fetchStoryViewList({
}
addEntitiesToLocalDb(result.users);
addEntitiesToLocalDb(result.chats);
const users = result.users.map(buildApiUser).filter(Boolean);
const views = result.views.map(buildApiStoryView);
const chats = result.chats.map((c) => buildApiChatFromPreview(c)).filter(Boolean);
const views = result.views.map(buildApiStoryView).filter(Boolean);
return {
users,
chats,
views,
nextOffset: result.nextOffset,
reactionsCount: result.reactionsCount,

View File

@ -7,10 +7,10 @@ import type {
import { DEFAULT_GIF_SEARCH_BOT_USERNAME, RECENT_STATUS_LIMIT, RECENT_STICKERS_LIMIT } from '../../../config';
import { buildVideoFromDocument } from '../apiBuilders/messageContent';
import { buildApiEmojiStatus } from '../apiBuilders/peers';
import {
buildStickerSet, buildStickerSetCovered, processStickerPackResult, processStickerResult,
} from '../apiBuilders/symbols';
import { buildApiUserEmojiStatus } from '../apiBuilders/users';
import { buildInputDocument, buildInputStickerSet, buildInputStickerSetShortName } from '../gramjsBuilders';
import localDb from '../localDb';
import { invokeRequest } from './client';
@ -445,7 +445,7 @@ export async function fetchRecentEmojiStatuses(hash = '0') {
const documentIds = result.statuses
.slice(0, RECENT_STATUS_LIMIT)
.map(buildApiUserEmojiStatus)
.map(buildApiEmojiStatus)
.filter(Boolean)
.map(({ documentId }) => documentId);
const emojiStatuses = await fetchCustomEmoji({ documentId: documentIds });

View File

@ -46,7 +46,7 @@ import {
buildApiNotifyExceptionTopic,
buildPrivacyKey,
} from './apiBuilders/misc';
import { buildApiPeerId, getApiChatIdFromMtpPeer } from './apiBuilders/peers';
import { buildApiEmojiStatus, buildApiPeerId, getApiChatIdFromMtpPeer } from './apiBuilders/peers';
import {
buildApiReaction,
buildMessageReactions,
@ -55,7 +55,6 @@ import { buildApiStealthMode, buildApiStory } from './apiBuilders/stories';
import { buildApiEmojiInteraction, buildStickerSet } from './apiBuilders/symbols';
import {
buildApiUser,
buildApiUserEmojiStatus,
buildApiUserStatus,
} from './apiBuilders/users';
import {
@ -795,7 +794,7 @@ export function updater(update: Update) {
id: buildApiPeerId(update.userId, 'user'),
});
} else if (update instanceof GramJs.UpdateUserEmojiStatus) {
const emojiStatus = buildApiUserEmojiStatus(update.emojiStatus);
const emojiStatus = buildApiEmojiStatus(update.emojiStatus);
onUpdate({
'@type': 'updateUserEmojiStatus',
userId: buildApiPeerId(update.userId, 'user'),

View File

@ -3,7 +3,9 @@ import type {
ApiChatReactions, ApiMessage, ApiPhoto, ApiStickerSet,
} from './messages';
import type { ApiChatInviteImporter } from './misc';
import type { ApiFakeType, ApiUser, ApiUsername } from './users';
import type {
ApiEmojiStatus, ApiFakeType, ApiUser, ApiUsername,
} from './users';
type ApiChatType = (
'chatTypePrivate' | 'chatTypeSecret' |
@ -43,6 +45,7 @@ export interface ApiChat {
isProtected?: boolean;
fakeType?: ApiFakeType;
color?: ApiPeerColor;
emojiStatus?: ApiEmojiStatus;
isForum?: boolean;
isForumAsMessages?: true;
topics?: Record<number, ApiTopic>;

View File

@ -260,6 +260,21 @@ export type ApiGiveaway = {
isOnlyForNewSubscribers?: true;
countries?: string[];
channelIds: string[];
prizeDescription?: string;
};
export type ApiGiveawayResults = {
months: number;
untilDate: number;
isRefunded?: true;
isOnlyForNewSubscribers?: true;
channelId: string;
prizeDescription?: string;
winnersCount?: number;
winnerIds: string[];
additionalPeersCount?: number;
launchMessageId: number;
unclaimedCount: number;
};
export type ApiNewPoll = {
@ -370,6 +385,7 @@ export interface ApiStoryForwardInfo {
fromPeerId?: string;
fromName?: string;
storyId?: number;
isModified?: boolean;
}
export type ApiMessageEntityDefault = {
@ -458,6 +474,7 @@ export type MediaContent = {
game?: ApiGame;
storyData?: ApiMessageStoryData;
giveaway?: ApiGiveaway;
giveawayResults?: ApiGiveawayResults;
};
export interface ApiMessage {

View File

@ -46,8 +46,7 @@ export interface ApiPostStatistics {
publicForwards?: number;
publicForwardsData?: (ApiMessagePublicForward | ApiStoryPublicForward)[];
nextRate?: number;
nextOffsetId?: string;
nextOffset?: string;
}
export interface ApiBoostStatistics {

View File

@ -1,6 +1,6 @@
import type { ApiPrivacySettings } from '../../types';
import type {
ApiGeoPoint, ApiReaction, ApiReactionCount, ApiStoryForwardInfo, MediaContent,
ApiGeoPoint, ApiMessage, ApiReaction, ApiReactionCount, ApiStoryForwardInfo, MediaContent,
} from './messages';
export interface ApiStory {
@ -71,14 +71,37 @@ export type ApiWebPageStoryData = {
peerId: string;
};
export type ApiStoryViewPublicForward = {
type: 'forward';
peerId: string;
messageId: number;
message: ApiMessage;
date: number;
isUserBlocked?: true;
areStoriesBlocked?: true;
};
export type ApiStoryViewPublicRepost = {
type: 'repost';
isUserBlocked?: true;
areStoriesBlocked?: true;
date: number;
peerId: string;
storyId: number;
story: ApiStory;
};
export type ApiStoryView = {
userId: string;
type: 'user';
peerId: string;
date: number;
reaction?: ApiReaction;
isUserBlocked?: true;
areStoriesBlocked?: true;
};
export type ApiTypeStoryView = ApiStoryView | ApiStoryViewPublicForward | ApiStoryViewPublicRepost;
export type ApiStealthMode = {
activeUntil?: number;
cooldownUntil?: number;
@ -113,4 +136,12 @@ export type ApiMediaAreaSuggestedReaction = {
isFlipped?: boolean;
};
export type ApiMediaArea = ApiMediaAreaVenue | ApiMediaAreaGeoPoint | ApiMediaAreaSuggestedReaction;
export type ApiMediaAreaChannelPost = {
type: 'channelPost';
coordinates: ApiMediaAreaCoordinates;
channelId: string;
messageId: number;
};
export type ApiMediaArea = ApiMediaAreaVenue | ApiMediaAreaGeoPoint | ApiMediaAreaSuggestedReaction
| ApiMediaAreaChannelPost;

Binary file not shown.

View File

@ -53,7 +53,6 @@ const FullNameTitle: FC<OwnProps> = ({
const { showNotification } = getActions();
const isUser = isUserId(peer.id);
const title = isUser ? getUserFullName(peer as ApiUser) : getChatTitle(lang, peer as ApiChat);
const emojiStatus = isUser && (peer as ApiUser).emojiStatus;
const isPremium = isUser && (peer as ApiUser).isPremium;
const handleTitleClick = useLastCallback((e) => {
@ -86,16 +85,16 @@ const FullNameTitle: FC<OwnProps> = ({
</h3>
{!noVerified && peer.isVerified && <VerifiedIcon />}
{!noFake && peer.fakeType && <FakeIcon fakeType={peer.fakeType} />}
{withEmojiStatus && emojiStatus && (
{withEmojiStatus && peer.emojiStatus && (
<CustomEmoji
documentId={emojiStatus.documentId}
documentId={peer.emojiStatus.documentId}
size={emojiStatusSize}
loopLimit={!noLoopLimit ? EMOJI_STATUS_LOOP_LIMIT : undefined}
observeIntersectionForLoading={observeIntersection}
onClick={onEmojiStatusClick}
/>
)}
{withEmojiStatus && !emojiStatus && isPremium && <PremiumIcon />}
{withEmojiStatus && !peer.emojiStatus && isPremium && <PremiumIcon />}
</div>
);
};

View File

@ -6,6 +6,7 @@ import type {
ApiChat, ApiThreadInfo, ApiTopic, ApiTypingStatus,
} from '../../api/types';
import type { LangFn } from '../../hooks/useLang';
import type { IconName } from '../../types/icons';
import { MediaViewerOrigin, type StoryViewerOrigin } from '../../types';
import {
@ -30,6 +31,7 @@ import useLastCallback from '../../hooks/useLastCallback';
import Avatar from './Avatar';
import DotAnimation from './DotAnimation';
import FullNameTitle from './FullNameTitle';
import Icon from './Icon';
import TopicIcon from './TopicIcon';
import TypingStatus from './TypingStatus';
@ -39,6 +41,7 @@ type OwnProps = {
chatId: string;
threadId?: number;
className?: string;
statusIcon?: IconName;
typingStatus?: ApiTypingStatus;
avatarSize?: 'tiny' | 'small' | 'medium' | 'large' | 'jumbo';
status?: string;
@ -48,6 +51,8 @@ type OwnProps = {
withFullInfo?: boolean;
withUpdatingStatus?: boolean;
withChatType?: boolean;
noEmojiStatus?: boolean;
emojiStatusSize?: number;
noRtl?: boolean;
noAvatar?: boolean;
noStatusOrTyping?: boolean;
@ -69,6 +74,7 @@ type StateProps =
const GroupChatInfo: FC<OwnProps & StateProps> = ({
typingStatus,
className,
statusIcon,
avatarSize = 'medium',
noAvatar,
status,
@ -88,6 +94,8 @@ const GroupChatInfo: FC<OwnProps & StateProps> = ({
noStatusOrTyping,
withStory,
storyViewerOrigin,
noEmojiStatus,
emojiStatusSize,
onClick,
}) => {
const {
@ -133,7 +141,10 @@ const GroupChatInfo: FC<OwnProps & StateProps> = ({
return withDots ? (
<DotAnimation className="status" content={status} />
) : (
<span className="status" dir="auto">{status}</span>
<span className="status" dir="auto">
{statusIcon && <Icon className="status-icon" name={statusIcon} />}
{renderText(status)}
</span>
);
}
@ -206,7 +217,7 @@ const GroupChatInfo: FC<OwnProps & StateProps> = ({
<div className="info">
{topic
? <h3 dir="auto" className="fullName">{renderText(topic.title)}</h3>
: <FullNameTitle peer={chat} />}
: <FullNameTitle peer={chat} emojiStatusSize={emojiStatusSize} withEmojiStatus={!noEmojiStatus} />}
{!noStatusOrTyping && renderStatusOrTyping()}
</div>
</div>

View File

@ -8,6 +8,7 @@ import type { IconName } from '../../types/icons';
import { getChatTitle, getUserFirstOrLastName } from '../../global/helpers';
import { selectChat, selectUser } from '../../global/selectors';
import buildClassName from '../../util/buildClassName';
import { getPeerColorClass } from './helpers/peerColor';
import renderText from './helpers/renderText';
import useLang from '../../hooks/useLang';
@ -26,6 +27,7 @@ type OwnProps = {
clickArg?: any;
className?: string;
fluid?: boolean;
withPeerColors?: boolean;
onClick: (arg: any) => void;
};
@ -46,6 +48,7 @@ const PickerSelectedItem: FC<OwnProps & StateProps> = ({
className,
fluid,
isSavedMessages,
withPeerColors,
onClick,
}) => {
const lang = useLang();
@ -84,6 +87,7 @@ const PickerSelectedItem: FC<OwnProps & StateProps> = ({
isMinimized && 'minimized',
canClose && 'closeable',
fluid && 'fluid',
withPeerColors && getPeerColorClass(chat || user),
);
return (

View File

@ -21,6 +21,7 @@ import RippleEffect from '../ui/RippleEffect';
import Avatar from './Avatar';
import DotAnimation from './DotAnimation';
import FullNameTitle from './FullNameTitle';
import Icon from './Icon';
import TypingStatus from './TypingStatus';
type OwnProps = {
@ -122,7 +123,7 @@ const PrivateChatInfo: FC<OwnProps & StateProps> = ({
<DotAnimation className="status" content={status} />
) : (
<span className="status" dir="auto">
{statusIcon && <i className={`icon icon-${statusIcon} status-icon`} />}
{statusIcon && <Icon className="status-icon" name={statusIcon} />}
{renderText(status)}
</span>
);

View File

@ -7,6 +7,7 @@ import VoiceAllowTalk from '../../../assets/tgs/calls/VoiceAllowTalk.tgs';
import VoiceMini from '../../../assets/tgs/calls/VoiceMini.tgs';
import VoiceMuted from '../../../assets/tgs/calls/VoiceMuted.tgs';
import VoiceOutlined from '../../../assets/tgs/calls/VoiceOutlined.tgs';
import PartyPopper from '../../../assets/tgs/general/PartyPopper.tgs';
import Invite from '../../../assets/tgs/invites/Invite.tgs';
import JoinRequest from '../../../assets/tgs/invites/Requests.tgs';
import MonkeyClose from '../../../assets/tgs/monkeys/TwoFactorSetupMonkeyClose.tgs';
@ -44,4 +45,5 @@ export const LOCAL_TGS_URLS = {
QrPlane,
Congratulations,
Experimental,
PartyPopper,
};

View File

@ -179,7 +179,6 @@ const Main: FC<OwnProps & StateProps> = ({
isMediaViewerOpen,
isStoryViewerOpen,
isForwardModalOpen,
currentUserId,
hasNotifications,
hasDialogs,
audioMessage,
@ -568,7 +567,7 @@ const Main: FC<OwnProps & StateProps> = ({
isByPhoneNumber={newContactByPhoneNumber}
/>
<BoostModal info={boostModal} />
<GiftCodeModal modal={giftCodeModal} currentUserId={currentUserId} />
<GiftCodeModal modal={giftCodeModal} />
<ChatlistModal info={chatlistModal} />
<GameModal openedGame={openedGame} gameTitle={gameTitle} />
<WebAppModal webApp={webApp} />

View File

@ -203,7 +203,7 @@ const ActionMessage: FC<OwnProps & StateProps> = ({
const handleGiftCodeClick = () => {
const slug = message.content.action?.slug;
if (!slug) return;
checkGiftCode({ slug });
checkGiftCode({ slug, message: { chatId: message.chatId, messageId: message.id } });
};
// TODO Refactoring for action rendering

View File

@ -405,6 +405,7 @@ const MiddleHeader: FC<OwnProps & StateProps> = ({
withUpdatingStatus
withStory
storyViewerOrigin={StoryViewerOrigin.MiddleHeaderAvatar}
emojiStatusSize={EMOJI_STATUS_SIZE}
noRtl
/>
)}

View File

@ -7,14 +7,19 @@
.title {
display: block;
margin-top: 0.5rem;
}
.gift {
.sticker {
position: relative;
margin-top: -2.5rem;
margin-bottom: 1rem;
}
.resultSticker {
margin-top: 0;
}
.count {
position: absolute;
bottom: 0;
@ -43,15 +48,16 @@
margin-bottom: 0;
}
.channels {
.peers {
display: flex;
flex-direction: column;
flex-wrap: wrap;
justify-content: center;
align-items: center;
gap: 0.5rem;
margin-block: 0.25rem;
}
.channel {
.peer {
background-color: var(--accent-background-color);
color: var(--accent-color);
margin: unset;
@ -64,3 +70,29 @@
.button {
margin-bottom: 1rem;
}
.result {
font-weight: 500;
}
.separator {
display: flex;
align-items: center;
text-align: center;
color: var(--color-text-secondary);
}
.separator::before,
.separator::after {
content: '';
flex: 1;
border-bottom: 1px solid var(--color-dividers);
}
.separator:not(:empty)::before {
margin-right: 0.25em;
}
.separator:not(:empty)::after {
margin-left: 0.25em;
}

View File

@ -4,25 +4,30 @@ import React, {
import { getActions, getGlobal, withGlobal } from '../../../global';
import type {
ApiChat, ApiGiveawayInfo, ApiMessage, ApiPeer, ApiSticker,
ApiChat, ApiGiveaway, ApiGiveawayInfo, ApiGiveawayResults, ApiMessage, ApiPeer, ApiSticker,
} from '../../../api/types';
import { getChatTitle, getUserFullName, isApiPeerChat } from '../../../global/helpers';
import {
getChatTitle, getUserFullName, isApiPeerChat, isOwnMessage,
} from '../../../global/helpers';
import {
selectCanPlayAnimatedEmojis,
selectChat,
selectForwardedSender,
selectGiftStickerForDuration,
} from '../../../global/selectors';
import buildClassName from '../../../util/buildClassName';
import { formatDateAtTime, formatDateTimeToString } from '../../../util/dateFormat';
import { isoToEmoji } from '../../../util/emoji';
import { getServerTime } from '../../../util/serverTime';
import { callApi } from '../../../api/gramjs';
import { LOCAL_TGS_URLS } from '../../common/helpers/animatedAssets';
import renderText from '../../common/helpers/renderText';
import useLang from '../../../hooks/useLang';
import useLastCallback from '../../../hooks/useLastCallback';
import AnimatedIcon from '../../common/AnimatedIcon';
import AnimatedIconFromSticker from '../../common/AnimatedIconFromSticker';
import PickerSelectedItem from '../../common/PickerSelectedItem';
import Button from '../../ui/Button';
@ -43,6 +48,7 @@ type StateProps = {
const NBSP = '\u00A0';
const GIFT_STICKER_SIZE = 175;
const RESULT_STICKER_SIZE = 150;
const Giveaway = ({
chat,
@ -57,20 +63,27 @@ const Giveaway = ({
const [giveawayInfo, setGiveawayInfo] = useState<ApiGiveawayInfo | undefined>();
const lang = useLang();
const { giveaway, giveawayResults } = message.content;
const isResults = Boolean(giveawayResults);
const {
months, quantity, channelIds, untilDate, countries,
} = message.content.giveaway!;
months, untilDate, prizeDescription,
} = (giveaway || giveawayResults)!;
const isOwn = isOwnMessage(message);
const quantity = isResults ? giveawayResults.winnersCount : giveaway!.quantity;
const hasEnded = getServerTime() > untilDate;
const countryList = useMemo(() => {
if (isResults) return undefined;
const translatedNames = new Intl.DisplayNames([lang.code!, 'en'].filter(Boolean), { type: 'region' });
return countries?.map((countryCode) => (
return giveaway?.countries?.map((countryCode) => (
`${isoToEmoji(countryCode)}${NBSP}${translatedNames.of(countryCode)}`
)).join(', ');
}, [countries, lang.code]);
}, [giveaway, isResults, lang.code]);
const handleChannelClick = useLastCallback((channelId: string) => {
const handlePeerClick = useLastCallback((channelId: string) => {
openChat({ id: channelId });
});
@ -95,36 +108,149 @@ const Giveaway = ({
return lang(giveawayInfo.type === 'results' ? 'BoostingGiveawayEnd' : 'BoostingGiveAwayAbout');
}, [giveawayInfo, lang]);
function renderGiveawayDescription(media: ApiGiveaway) {
const channelIds = media.channelIds;
return (
<>
<div className={styles.section}>
<strong className={styles.title}>
{renderText(lang('BoostingGiveawayPrizes'), ['simple_markdown'])}
</strong>
{prizeDescription && (
<>
<p className={styles.description}>
{renderText(
lang('BoostingGiveawayMsgPrizes', [quantity, prizeDescription], undefined, quantity),
['simple_markdown'],
)}
</p>
<div className={styles.separator}>{lang('BoostingGiveawayMsgWithDivider')}</div>
</>
)}
<p className={styles.description}>
{renderText(lang('Chat.Giveaway.Info.Subscriptions', quantity), ['simple_markdown'])}
<br />
{renderText(lang(
'ActionGiftPremiumSubtitle',
lang('Chat.Giveaway.Info.Months', months),
), ['simple_markdown'])}
</p>
</div>
<div className={styles.section}>
<strong className={styles.title}>
{renderText(lang('BoostingGiveawayMsgParticipants'), ['simple_markdown'])}
</strong>
<p className={styles.description}>
{renderText(lang('BoostingGiveawayMsgAllSubsPlural', channelIds.length), ['simple_markdown'])}
</p>
<div className={styles.peers}>
{channelIds.map((peerId) => (
<PickerSelectedItem
peerId={peerId}
forceShowSelf
fluid
withPeerColors={!isOwn}
className={styles.peer}
clickArg={peerId}
onClick={handlePeerClick}
/>
))}
</div>
{countryList && (
<span>{renderText(lang('Chat.Giveaway.Message.CountriesFrom', countryList))}</span>
)}
</div>
<div className={styles.section}>
<strong className={styles.title}>
{renderText(lang('BoostingWinnersDate'), ['simple_markdown'])}
</strong>
<p className={styles.description}>
{formatDateTimeToString(untilDate * 1000, lang.code, true)}
</p>
</div>
</>
);
}
function renderGiveawayResultsDescription(media: ApiGiveawayResults) {
const winnerIds = media.winnerIds;
return (
<>
<div className={styles.section}>
<strong className={styles.title}>
{renderText(lang('BoostingGiveawayResultsMsgWinnersSelected'), ['simple_markdown'])}
</strong>
<p className={styles.description}>
{renderText(lang('BoostingGiveawayResultsMsgWinnersTitle', winnerIds.length), ['simple_markdown'])}
</p>
<strong className={styles.title}>
{lang('lng_prizes_results_winners')}
</strong>
<div className={styles.peers}>
{winnerIds.map((peerId) => (
<PickerSelectedItem
peerId={peerId}
forceShowSelf
fluid
withPeerColors={!isOwn}
className={styles.peer}
clickArg={peerId}
onClick={handlePeerClick}
/>
))}
</div>
</div>
<div className={styles.section}>
<p className={styles.description}>
{lang('BoostingGiveawayResultsMsgAllWinnersReceivedLinks')}
</p>
</div>
</>
);
}
function renderGiveawayInfo() {
if (!sender || !giveawayInfo) return undefined;
const isResults = giveawayInfo.type === 'results';
const isResultsInfo = giveawayInfo.type === 'results';
const chatTitle = isApiPeerChat(sender) ? getChatTitle(lang, sender) : getUserFullName(sender);
const duration = lang('Chat.Giveaway.Info.Months', months);
const endDate = formatDateAtTime(lang, untilDate * 1000);
const otherChannelsCount = channelIds.length ? channelIds.length - 1 : 0;
const otherChannelsCount = giveaway?.channelIds ? giveaway.channelIds.length - 1 : 0;
const otherChannelsString = lang('Chat.Giveaway.Info.OtherChannels', otherChannelsCount);
const isSeveral = otherChannelsCount > 0;
const firstKey = isResults ? 'BoostingGiveawayHowItWorksTextEnd' : 'BoostingGiveawayHowItWorksText';
const firstKey = isResultsInfo ? 'BoostingGiveawayHowItWorksTextEnd' : 'BoostingGiveawayHowItWorksText';
const firstParagraph = lang(firstKey, [chatTitle, quantity, duration], undefined, quantity);
const additionalPrizes = prizeDescription
? lang('BoostingGiveawayHowItWorksIncludeText', [chatTitle, quantity, prizeDescription], undefined, quantity)
: undefined;
let secondKey = '';
if (isResults) {
if (isResultsInfo) {
secondKey = isSeveral ? 'BoostingGiveawayHowItWorksSubTextSeveralEnd' : 'BoostingGiveawayHowItWorksSubTextEnd';
} else {
secondKey = isSeveral ? 'BoostingGiveawayHowItWorksSubTextSeveral' : 'BoostingGiveawayHowItWorksSubText';
}
let secondParagraph = lang(secondKey, [endDate, quantity, chatTitle, otherChannelsCount], undefined, quantity);
if (isResults && giveawayInfo.activatedCount) {
if (isResultsInfo && giveawayInfo.activatedCount) {
secondParagraph += ` ${lang('BoostingGiveawayUsedLinksPlural', giveawayInfo.activatedCount)}`;
}
let result = '';
if (isResultsInfo) {
if (giveawayInfo.isRefunded) {
result = lang('BoostingGiveawayCanceledByPayment');
} else {
result = lang(giveawayInfo.isWinner ? 'BoostingGiveawayYouWon' : 'BoostingGiveawayYouNotWon');
}
}
let lastParagraph = '';
if (isResults && giveawayInfo.isRefunded) {
lastParagraph = lang('BoostingGiveawayCanceledByPayment');
} else if (isResults) {
lastParagraph = lang(giveawayInfo.isWinner ? 'BoostingGiveawayYouWon' : 'BoostingGiveawayYouNotWon');
if (isResultsInfo) {
// Nothing
} else if (giveawayInfo.disallowedCountry) {
lastParagraph = lang('BoostingGiveawayNotEligibleCountry');
} else if (giveawayInfo.adminDisallowedChatId) {
@ -148,78 +274,55 @@ const Giveaway = ({
return (
<>
{result && (
<p className={styles.result}>
{renderText(result, ['simple_markdown'])}
</p>
)}
<p>
{renderText(firstParagraph, ['simple_markdown'])}
</p>
{additionalPrizes && (
<p>
{renderText(additionalPrizes, ['simple_markdown'])}
</p>
)}
<p>
{renderText(secondParagraph, ['simple_markdown'])}
</p>
<p>
{renderText(lastParagraph, ['simple_markdown'])}
</p>
{lastParagraph && (
<p>
{renderText(lastParagraph, ['simple_markdown'])}
</p>
)}
</>
);
}
return (
<div className={styles.root}>
<div className={styles.gift}>
<AnimatedIconFromSticker
key={message.id}
sticker={giftSticker}
play={canPlayAnimatedEmojis && hasEnded}
noLoop
nonInteractive
size={GIFT_STICKER_SIZE}
/>
<div className={buildClassName(styles.sticker, isResults && styles.resultSticker)}>
{isResults ? (
<AnimatedIcon
size={RESULT_STICKER_SIZE}
tgsUrl={LOCAL_TGS_URLS.PartyPopper}
nonInteractive
noLoop
/>
) : (
<AnimatedIconFromSticker
sticker={giftSticker}
play={canPlayAnimatedEmojis && hasEnded}
noLoop
nonInteractive
size={GIFT_STICKER_SIZE}
/>
)}
<span className={styles.count}>
{`x${quantity}`}
</span>
</div>
<div className={styles.section}>
<strong className={styles.title}>
{renderText(lang('BoostingGiveawayPrizes'), ['simple_markdown'])}
</strong>
<p className={styles.description}>
{renderText(lang('Chat.Giveaway.Info.Subscriptions', quantity), ['simple_markdown'])}
<br />
{renderText(lang(
'ActionGiftPremiumSubtitle',
lang('Chat.Giveaway.Info.Months', months),
), ['simple_markdown'])}
</p>
</div>
<div className={styles.section}>
<strong className={styles.title}>
{renderText(lang('BoostingGiveawayMsgParticipants'), ['simple_markdown'])}
</strong>
<p className={styles.description}>
{renderText(lang('BoostingGiveawayMsgAllSubsPlural', channelIds.length), ['simple_markdown'])}
</p>
<div className={styles.channels}>
{channelIds.map((channelId) => (
<PickerSelectedItem
peerId={channelId}
forceShowSelf
fluid
className={styles.channel}
clickArg={channelId}
onClick={handleChannelClick}
/>
))}
</div>
{Boolean(countries?.length) && (
<span>{renderText(lang('Chat.Giveaway.Message.CountriesFrom', countryList))}</span>
)}
</div>
<div className={styles.section}>
<strong className={styles.title}>
{renderText(lang('BoostingWinnersDate'), ['simple_markdown'])}
</strong>
<p className={styles.description}>
{formatDateTimeToString(untilDate * 1000, lang.code, true)}
</p>
</div>
{isResults ? renderGiveawayResultsDescription(giveawayResults) : renderGiveawayDescription(giveaway!)}
<Button
className={styles.button}
color="adaptive"
@ -243,15 +346,17 @@ const Giveaway = ({
export default memo(withGlobal<OwnProps>(
(global, { message }): StateProps => {
const duration = message.content.giveaway!.months;
const { giveaway } = message.content;
const chat = selectChat(global, message.chatId)!;
const sender = selectChat(global, message.content.giveaway?.channelIds[0]!)
const sender = selectChat(global, giveaway?.channelIds[0]!)
|| selectForwardedSender(global, message) || chat;
const sticker = giveaway && selectGiftStickerForDuration(global, giveaway.months);
return {
chat,
sender,
giftSticker: selectGiftStickerForDuration(global, duration),
giftSticker: sticker,
canPlayAnimatedEmojis: selectCanPlayAnimatedEmojis(global),
};
},

View File

@ -639,6 +639,7 @@ const Message: FC<OwnProps & StateProps> = ({
voice, document, sticker, contact,
poll, webPage, invoice, location,
action, game, storyData, giveaway,
giveawayResults,
} = getMessageContent(message);
const { replyToMsgId, replyToPeerId, isQuote } = messageReplyInfo || {};
@ -1146,7 +1147,7 @@ const Message: FC<OwnProps & StateProps> = ({
{poll && (
<Poll message={message} poll={poll} onSendVote={handleVoteSend} />
)}
{giveaway && (
{(giveaway || giveawayResults) && (
<Giveaway message={message} />
)}
{game && (

View File

@ -34,7 +34,8 @@ export function buildContentClassName(
} = {},
) {
const {
text, photo, video, audio, voice, document, poll, webPage, contact, location, invoice, storyData, giveaway,
text, photo, video, audio, voice, document, poll, webPage, contact, location, invoice, storyData,
giveaway, giveawayResults,
} = getMessageContent(message);
const classNames = [MESSAGE_CONTENT_CLASS_NAME];
@ -87,7 +88,7 @@ export function buildContentClassName(
classNames.push('contact');
} else if (poll) {
classNames.push('poll');
} else if (giveaway) {
} else if (giveaway || giveawayResults) {
classNames.push('giveaway');
} else if (webPage) {
classNames.push('web-page');

View File

@ -1,9 +1,11 @@
import React, { memo } from '../../../lib/teact/teact';
import { getActions } from '../../../global';
import { getActions, withGlobal } from '../../../global';
import type { ApiPeer } from '../../../api/types';
import type { TabState } from '../../../global/types';
import { TME_LINK_PREFIX } from '../../../config';
import { selectChatMessage, selectSender } from '../../../global/selectors';
import buildClassName from '../../../util/buildClassName';
import { formatDateTimeToString } from '../../../util/dateFormat';
import renderText from '../../common/helpers/renderText';
@ -21,16 +23,21 @@ import styles from './GiftCodeModal.module.scss';
import PremiumLogo from '../../../assets/premium/PremiumLogo.svg';
export type OwnProps = {
currentUserId?: string;
modal: TabState['giftCodeModal'];
};
export type StateProps = {
currentUserId?: string;
messageSender?: ApiPeer;
};
const GIFTCODE_PATH = 'giftcode';
const GiftCodeModal = ({
currentUserId,
modal,
}: OwnProps) => {
messageSender,
}: OwnProps & StateProps) => {
const {
closeGiftCodeModal, openChat, applyGiftCode, focusMessage,
} = getActions();
@ -65,6 +72,8 @@ const GiftCodeModal = ({
if (!modal) return undefined;
const { slug, info } = modal;
const fromId = info.fromId || messageSender?.id;
return (
<>
<img className={styles.logo} src={PremiumLogo} alt="" draggable={false} />
@ -74,13 +83,13 @@ const GiftCodeModal = ({
<tr>
<td className={styles.title}>{lang('BoostingFrom')}</td>
<td>
{info.fromId ? (
{fromId ? (
<PickerSelectedItem
peerId={info.fromId}
peerId={fromId}
className={styles.chatItem}
forceShowSelf
fluid
clickArg={info.fromId}
clickArg={fromId}
onClick={handleOpenChat}
/>
) : lang('BoostingNoRecipient')}
@ -157,4 +166,15 @@ const GiftCodeModal = ({
);
};
export default memo(GiftCodeModal);
export default memo(withGlobal<OwnProps>(
(global, { modal }): StateProps => {
const { message } = modal || {};
const chatMessage = message && selectChatMessage(global, message.chatId, message.messageId);
const sender = chatMessage && selectSender(global, chatMessage);
return {
currentUserId: global.currentUserId,
messageSender: sender,
};
},
)(GiftCodeModal));

View File

@ -5,6 +5,7 @@ import React, {
import { getActions, withGlobal } from '../../global';
import type {
ApiMediaAreaChannelPost,
ApiPeer, ApiStealthMode, ApiStory, ApiTypeStory,
} from '../../api/types';
import type { IDimensions } from '../../global/types';
@ -843,7 +844,11 @@ export default memo(withGlobal<OwnProps>((global, {
viewModal || forwardedStoryId || tabState.reactionPicker?.storyId || isReportModalOpen || isPrivacyModalOpen
|| isPremiumModalOpen || isDeleteModalOpen || safeLinkModalUrl || isStealthModalOpen || mapModal,
);
const forwardSenderId = story && 'forwardInfo' in story ? story.forwardInfo?.fromPeerId : undefined;
const forwardInfo = (story && 'forwardInfo' in story) ? story.forwardInfo : undefined;
const mediaAreas = (story && 'mediaAreas' in story) ? story.mediaAreas : undefined;
const forwardSenderId = forwardInfo?.fromPeerId
|| mediaAreas?.find((area): area is ApiMediaAreaChannelPost => area.type === 'channelPost')?.channelId;
const forwardSender = forwardSenderId ? selectPeer(global, forwardSenderId) : undefined;
return {

View File

@ -1,10 +1,13 @@
import React, { memo, useMemo } from '../../lib/teact/teact';
import { getActions, withGlobal } from '../../global';
import type { ApiAvailableReaction, ApiStoryView, ApiUser } from '../../api/types';
import type {
ApiAvailableReaction, ApiPeer, ApiTypeStoryView, ApiUser,
} from '../../api/types';
import type { IconName } from '../../types/icons';
import { getUserFullName } from '../../global/helpers';
import { selectUser } from '../../global/selectors';
import { getUserFullName, isUserId } from '../../global/helpers';
import { selectPeer } from '../../global/selectors';
import buildClassName from '../../util/buildClassName';
import { formatDateAtTime } from '../../util/dateFormat';
import { REM } from '../common/helpers/mediaDimensions';
@ -12,6 +15,7 @@ import { REM } from '../common/helpers/mediaDimensions';
import useLang from '../../hooks/useLang';
import useLastCallback from '../../hooks/useLastCallback';
import GroupChatInfo from '../common/GroupChatInfo';
import PrivateChatInfo from '../common/PrivateChatInfo';
import ReactionStaticEmoji from '../common/ReactionStaticEmoji';
import ListItem, { type MenuItemContextAction } from '../ui/ListItem';
@ -19,38 +23,64 @@ import ListItem, { type MenuItemContextAction } from '../ui/ListItem';
import styles from './StoryViewModal.module.scss';
type OwnProps = {
storyView: ApiStoryView;
storyView: ApiTypeStoryView;
};
type StateProps = {
user?: ApiUser;
peer?: ApiPeer;
availableReactions?: ApiAvailableReaction[];
};
const CLOSE_ANIMATION_DURATION = 100;
const DEFAULT_REACTION_SIZE = 1.5 * REM;
const BULLET = '\u2022';
const StoryView = ({
storyView,
user,
peer,
availableReactions,
}: OwnProps & StateProps) => {
const {
openChat, closeStoryViewer, unblockUser, blockUser, deleteContact, updateStoryView,
openChat,
closeStoryViewer,
unblockUser,
blockUser,
deleteContact,
updateStoryView,
focusMessage,
openStoryViewer,
closeStoryViewModal,
} = getActions();
const lang = useLang();
const handleClick = useLastCallback(() => {
const { type } = storyView;
if (type === 'repost') {
closeStoryViewModal();
openStoryViewer({
peerId: storyView.peerId,
storyId: storyView.storyId,
});
return;
}
closeStoryViewer();
setTimeout(() => {
openChat({ id: storyView.userId });
if (type === 'user') {
openChat({ id: storyView.peerId });
} else if (type === 'forward') {
focusMessage({ chatId: storyView.peerId, messageId: storyView.messageId });
}
}, CLOSE_ANIMATION_DURATION);
});
const contextActions = useMemo(() => {
const { userId, areStoriesBlocked, isUserBlocked } = storyView;
if (!isUserId(storyView.peerId)) return undefined;
const { peerId, areStoriesBlocked, isUserBlocked } = storyView;
const user = peer as ApiUser;
const { isContact } = user || {};
const fullName = getUserFullName(user);
@ -60,8 +90,8 @@ const StoryView = ({
if (!areStoriesBlocked) {
actions.push({
handler: () => {
blockUser({ userId, isOnlyStories: true });
updateStoryView({ userId, areStoriesBlocked: true });
blockUser({ userId: peerId, isOnlyStories: true });
updateStoryView({ userId: peerId, areStoriesBlocked: true });
},
title: lang('StoryHideFrom', fullName),
icon: 'hand-stop',
@ -69,8 +99,8 @@ const StoryView = ({
} else {
actions.push({
handler: () => {
unblockUser({ userId, isOnlyStories: true });
updateStoryView({ userId, areStoriesBlocked: false });
unblockUser({ userId: peerId, isOnlyStories: true });
updateStoryView({ userId: peerId, areStoriesBlocked: false });
},
title: lang('StoryShowBackTo', fullName),
icon: 'play-story',
@ -81,7 +111,7 @@ const StoryView = ({
if (isContact) {
actions.push({
handler: () => {
deleteContact({ userId });
deleteContact({ userId: peerId });
},
title: lang('DeleteContact'),
icon: 'delete-user',
@ -91,11 +121,11 @@ const StoryView = ({
actions.push({
handler: () => {
if (isUserBlocked) {
unblockUser({ userId });
updateStoryView({ userId, isUserBlocked: false });
unblockUser({ userId: peerId });
updateStoryView({ userId: peerId, isUserBlocked: false });
} else {
blockUser({ userId });
updateStoryView({ userId, isUserBlocked: true });
blockUser({ userId: peerId });
updateStoryView({ userId: peerId, isUserBlocked: true });
}
},
title: lang(isUserBlocked ? 'Unblock' : 'BlockUser'),
@ -105,11 +135,25 @@ const StoryView = ({
}
return actions;
}, [lang, storyView, user]);
}, [lang, storyView, peer]);
const statusIcon: IconName = storyView.type === 'user' ? 'message-read'
: storyView.type === 'forward' ? 'forward' : 'loop';
const shouldColorStatus = storyView.type === 'forward' || storyView.type === 'repost';
const status = useMemo(() => {
const isModified = storyView.type === 'repost' && storyView.story.forwardInfo?.isModified;
const parts = [formatDateAtTime(lang, storyView.date * 1000)];
if (isModified) {
parts.push(lang('lng_edited'));
}
return parts.join(` ${BULLET} `);
}, [lang, storyView]);
return (
<ListItem
key={storyView.userId}
key={storyView.peerId}
className={buildClassName(
'chat-item-clickable small-icon',
styles.opacityFadeIn,
@ -117,7 +161,7 @@ const StoryView = ({
)}
// eslint-disable-next-line react/jsx-no-bind
onClick={() => handleClick()}
rightElement={storyView.reaction ? (
rightElement={storyView.type === 'user' && storyView.reaction ? (
<ReactionStaticEmoji
reaction={storyView.reaction}
className={styles.viewReaction}
@ -130,23 +174,34 @@ const StoryView = ({
withPortalForMenu
menuBubbleClassName={styles.menuBubble}
>
<PrivateChatInfo
userId={storyView.userId}
noStatusOrTyping
status={formatDateAtTime(lang, storyView.date * 1000)}
statusIcon="message-read"
withStory
forceShowSelf
/>
{isUserId(storyView.peerId) ? (
<PrivateChatInfo
className={buildClassName(shouldColorStatus && styles.withColoredStatus)}
userId={storyView.peerId}
noStatusOrTyping
status={status}
statusIcon={statusIcon}
withStory
forceShowSelf
/>
) : (
<GroupChatInfo
className={buildClassName(shouldColorStatus && styles.withColoredStatus)}
chatId={storyView.peerId}
status={status}
statusIcon={statusIcon}
withStory
/>
)}
</ListItem>
);
};
export default memo(withGlobal<OwnProps>((global, { storyView }) => {
const user = selectUser(global, storyView.userId);
const peer = selectPeer(global, storyView.peerId);
return {
user,
peer,
availableReactions: global.availableReactions,
};
})(StoryView));

View File

@ -96,6 +96,7 @@
.footer {
border-top: 0.0625rem solid var(--color-borders);
padding-block: 0.25rem;
}
.closeButton {
@ -118,6 +119,10 @@
max-width: min(25rem, 80vw);
}
.with-colored-status :global(.status-icon) {
color: var(--color-text-green);
}
@keyframes fadeIn {
from {
opacity: 0;

View File

@ -4,7 +4,7 @@ import React, {
} from '../../lib/teact/teact';
import { getActions, withGlobal } from '../../global';
import type { ApiStory, ApiStoryView } from '../../api/types';
import type { ApiStory, ApiTypeStoryView } from '../../api/types';
import {
STORY_MIN_REACTIONS_SORT,
@ -41,7 +41,7 @@ import styles from './StoryViewModal.module.scss';
interface StateProps {
story?: ApiStory;
isLoading?: boolean;
viewsById?: Record<string, ApiStoryView>;
views?: ApiTypeStoryView[];
nextOffset?: string;
viewersExpirePeriod: number;
isCurrentUserPremium?: boolean;
@ -52,7 +52,7 @@ const REFETCH_DEBOUNCE = 250;
function StoryViewModal({
story,
viewersExpirePeriod,
viewsById,
views,
nextOffset,
isLoading,
isCurrentUserPremium,
@ -92,19 +92,13 @@ function StoryViewModal({
refetchViews();
}, [areJustContacts, areReactionsFirst, query, refetchViews]);
const sortedViewIds = useMemo(() => {
if (!viewsById) {
return undefined;
}
const sortedViews = useMemo(() => {
return views?.sort(prepareComparator(areReactionsFirst));
}, [areReactionsFirst, views]);
return Object.values(viewsById)
.sort(prepareComparator(areReactionsFirst))
.map((view) => view.userId);
}, [areReactionsFirst, viewsById]);
const placeholderCount = !sortedViews?.length ? Math.min(viewsCount, 8) : 1;
const placeholderCount = !sortedViewIds?.length ? Math.min(viewsCount, 8) : 1;
const notAllAvailable = Boolean(sortedViewIds?.length) && sortedViewIds!.length < viewsCount && isExpired;
const notAllAvailable = Boolean(sortedViews?.length) && sortedViews!.length < viewsCount && isExpired;
const handleLoadMore = useLastCallback(() => {
if (!story?.id || nextOffset === undefined) return;
@ -207,7 +201,7 @@ function StoryViewModal({
className={buildClassName(styles.content, !isAtBeginning && styles.topScrolled, 'custom-scroll')}
onScroll={handleScroll}
>
{isExpired && !isLoading && !query && Boolean(!sortedViewIds?.length) && (
{isExpired && !isLoading && !query && Boolean(!sortedViews?.length) && (
<div className={buildClassName(styles.info, styles.centeredInfo)}>
{renderText(
lang(isCurrentUserPremium ? 'ServerErrorViewers' : 'ExpiredViewsStub'),
@ -215,18 +209,22 @@ function StoryViewModal({
)}
</div>
)}
{!isLoading && Boolean(query.length) && !sortedViewIds?.length && (
{!isLoading && Boolean(query.length) && !sortedViews?.length && (
<div className={styles.info}>
{lang('Story.ViewList.EmptyTextSearch')}
</div>
)}
<InfiniteScroll
items={sortedViewIds}
items={sortedViews}
onLoadMore={handleLoadMore}
>
{sortedViewIds?.map((id) => (
<StoryView key={id} storyView={viewsById![id]} />
))}
{sortedViews?.map((view) => {
const additionalKeyId = view.type === 'forward' ? view.messageId
: view.type === 'repost' ? view.storyId : 'user';
return (
<StoryView key={`${view.peerId}-${view.date}-${additionalKeyId}`} storyView={view} />
);
})}
{isLoading && Array.from({ length: placeholderCount }).map((_, i) => (
<ListItem
// eslint-disable-next-line react/no-array-index-key
@ -258,12 +256,14 @@ function StoryViewModal({
}
function prepareComparator(areReactionsFirst?: boolean) {
return (a: ApiStoryView, b: ApiStoryView) => {
return (a: ApiTypeStoryView, b: ApiTypeStoryView) => {
if (areReactionsFirst) {
if (a.reaction && !b.reaction) {
const reactionA = a.type === 'user' && a.reaction;
const reactionB = b.type === 'user' && b.reaction;
if (reactionA && !reactionB) {
return -1;
}
if (!a.reaction && b.reaction) {
if (!reactionA && reactionB) {
return 1;
}
}
@ -276,13 +276,13 @@ export default memo(withGlobal((global) => {
const { appConfig } = global;
const { storyViewer: { viewModal } } = selectTabState(global);
const {
storyId, viewsById, nextOffset, isLoading,
storyId, views, nextOffset, isLoading,
} = viewModal || {};
const story = storyId ? selectPeerStory(global, global.currentUserId!, storyId) : undefined;
return {
storyId,
viewsById,
views,
viewersExpirePeriod: appConfig!.storyExpirePeriod + appConfig!.storyViewersExpirePeriod,
story: story && 'content' in story ? story : undefined,
nextOffset,

View File

@ -25,7 +25,7 @@ const STORY_ASPECT_RATIO = 9 / 16;
const MediaAreaOverlay = ({
story, isActive, className,
}: OwnProps) => {
const { openMapModal } = getActions();
const { openMapModal, focusMessage, closeStoryViewer } = getActions();
// eslint-disable-next-line no-null/no-null
const ref = useRef<HTMLDivElement>(null);
@ -58,8 +58,20 @@ const MediaAreaOverlay = ({
}, [isActive, windowSize]);
const handleMediaAreaClick = (mediaArea: ApiMediaArea) => {
if (mediaArea.type === 'geoPoint' || mediaArea.type === 'venue') {
openMapModal({ geoPoint: mediaArea.geo });
switch (mediaArea.type) {
case 'geoPoint':
case 'venue': {
openMapModal({ geoPoint: mediaArea.geo });
break;
}
case 'channelPost': {
focusMessage({
chatId: mediaArea.channelId,
messageId: mediaArea.messageId,
});
closeStoryViewer();
break;
}
}
};
@ -74,13 +86,16 @@ const MediaAreaOverlay = ({
switch (mediaArea.type) {
case 'geoPoint':
case 'venue':
case 'channelPost': {
const isShiny = isActive && (mediaArea.type === 'geoPoint' || mediaArea.type === 'venue');
return (
<div
className={buildClassName(styles.mediaArea, isActive && styles.shiny)}
className={buildClassName(styles.mediaArea, isShiny && styles.shiny)}
style={prepareStyle(mediaArea)}
onClick={() => handleMediaAreaClick(mediaArea)}
/>
);
}
case 'suggestedReaction':
return (
<MediaAreaSuggestedReaction

View File

@ -646,7 +646,7 @@ addActionHandler('applyBoost', async (global, actions, payload): Promise<void> =
});
addActionHandler('checkGiftCode', async (global, actions, payload): Promise<void> => {
const { slug, tabId = getCurrentTabId() } = payload;
const { slug, message, tabId = getCurrentTabId() } = payload;
const result = await callApi('checkGiftCode', {
slug,
@ -667,6 +667,7 @@ addActionHandler('checkGiftCode', async (global, actions, payload): Promise<void
giftCodeModal: {
slug,
info: result.code,
message,
},
}, tabId);
setGlobal(global);

View File

@ -91,14 +91,14 @@ addActionHandler('loadMessagePublicForwards', async (global, actions, payload):
const dcId = fullInfo.statisticsDcId;
const stats = selectTabState(global, tabId).statistics.currentMessage || {};
if (stats?.publicForwards && !stats.nextRate) return;
if (stats?.publicForwards && !stats.nextOffset) return;
const publicForwards = await callApi('fetchMessagePublicForwards', {
chat, messageId, dcId, offsetRate: stats?.nextRate,
chat, messageId, dcId, offset: stats.nextOffset,
});
const {
forwards,
nextRate,
nextOffset,
count,
} = publicForwards || {};
@ -113,7 +113,7 @@ addActionHandler('loadMessagePublicForwards', async (global, actions, payload):
publicForwardsData: (stats.publicForwardsData || []).concat(
shouldOmitFirstElement ? forwards.slice(1) : (forwards || []),
),
nextRate,
nextOffset,
}, tabId);
setGlobal(global);
});
@ -185,16 +185,16 @@ addActionHandler('loadStoryPublicForwards', async (global, actions, payload): Pr
const dcId = fullInfo.statisticsDcId;
const stats = selectTabState(global, tabId).statistics.currentStory || {};
if (stats?.publicForwards && !stats.nextOffsetId) return;
if (stats?.publicForwards && !stats.nextOffset) return;
const {
publicForwards,
users,
chats,
count,
nextOffsetId,
nextOffset,
} = await callApi('fetchStoryPublicForwards', {
chat, storyId, dcId, offsetId: stats.nextOffsetId,
chat, storyId, dcId, offset: stats.nextOffset,
}) || {};
global = getGlobal();
@ -211,7 +211,7 @@ addActionHandler('loadStoryPublicForwards', async (global, actions, payload): Pr
publicForwardsData: (stats.publicForwardsData || []).concat(
publicForwards || [],
),
nextOffsetId,
nextOffset,
}, tabId);
setGlobal(global);
});

View File

@ -1,3 +1,4 @@
import type { ApiStoryView } from '../../../api/types';
import type { ActionReturnType } from '../../types';
import { DEBUG, PREVIEW_AVATAR_COUNT } from '../../../config';
@ -353,14 +354,15 @@ addActionHandler('loadStoryViews', async (global, actions, payload): Promise<voi
return;
}
const viewsById = buildCollectionByKey(result.views, 'userId');
global = getGlobal();
global = addUsers(global, buildCollectionByKey(result.users, 'id'));
if (!isPreload) global = updateStoryViews(global, storyId, viewsById, result.nextOffset, tabId);
global = addChats(global, buildCollectionByKey(result.chats, 'id'));
if (!isPreload) global = updateStoryViews(global, storyId, result.views, result.nextOffset, tabId);
if (isPreload && result.views?.length) {
const recentViewerIds = result.views.map((view) => view.userId);
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,

View File

@ -1,4 +1,3 @@
import type { ApiStoryView } from '../../../api/types';
import type { ActionReturnType } from '../../types';
import { copyTextToClipboard } from '../../../util/clipboard';
@ -374,7 +373,7 @@ addActionHandler('clearStoryViews', (global, actions, payload): ActionReturnType
...tabState.storyViewer,
viewModal: {
...tabState.storyViewer.viewModal,
viewsById: {},
views: undefined,
isLoading,
nextOffset: '',
},
@ -389,24 +388,26 @@ addActionHandler('updateStoryView', (global, actions, payload): ActionReturnType
const tabState = selectTabState(global, tabId);
const { viewModal } = tabState.storyViewer;
if (!viewModal?.storyId) return undefined;
if (!viewModal?.viewsById?.[userId]) return global;
const updatedViews = viewModal?.views?.map((view) => {
if (view.peerId === userId) {
return {
...view,
isUserBlocked: isUserBlocked || undefined,
areStoriesBlocked: areStoriesBlocked || undefined,
};
}
const updatedViewsById: Record<string, ApiStoryView> = {
...viewModal.viewsById,
[userId]: {
...viewModal.viewsById[userId],
isUserBlocked: isUserBlocked || undefined,
areStoriesBlocked: areStoriesBlocked || undefined,
},
};
return view;
});
return updateTabState(global, {
storyViewer: {
...tabState.storyViewer,
viewModal: {
...viewModal,
viewsById: updatedViewsById,
views: updatedViews,
},
},
}, tabId);

View File

@ -121,6 +121,7 @@ export function getMessageSummaryDescription(
game,
storyData,
giveaway,
giveawayResults,
} = message.content;
let hasUsedTruncatedText = false;
@ -195,6 +196,10 @@ export function getMessageSummaryDescription(
summary = lang('BoostingGiveawayChannelStarted');
}
if (giveawayResults) {
summary = lang('Message.GiveawayEndedWinners', giveawayResults.winnersCount);
}
if (storyData) {
if (storyData.isMention) {
// eslint-disable-next-line eslint-multitab-tt/no-immediate-global

View File

@ -55,12 +55,12 @@ export function getMessageTranscription(message: ApiMessage) {
export function hasMessageText(message: ApiMessage | ApiStory) {
const {
text, sticker, photo, video, audio, voice, document, poll, webPage, contact, invoice, location,
game, action, storyData, giveaway,
game, action, storyData, giveaway, giveawayResults,
} = message.content;
return Boolean(text) || !(
sticker || photo || video || audio || voice || document || contact || poll || webPage || invoice || location
|| game || action?.phoneCall || storyData || giveaway
|| game || action?.phoneCall || storyData || giveaway || giveawayResults
);
}

View File

@ -5,9 +5,9 @@ import type {
ApiStory,
ApiStoryDeleted,
ApiStorySkipped,
ApiStoryView,
ApiStoryViews,
ApiTypeStory,
ApiTypeStoryView,
} from '../../api/types';
import type { GlobalState, TabArgs } from '../types';
@ -204,16 +204,16 @@ export function updatePeersWithStories<T extends GlobalState>(
export function updateStoryViews<T extends GlobalState>(
global: T,
storyId: number,
viewsById: Record<string, ApiStoryView>,
views: ApiTypeStoryView[],
nextOffset?: string,
...[tabId = getCurrentTabId()]: TabArgs<T>
): T {
const tabState = selectTabState(global, tabId);
const { viewModal } = tabState.storyViewer;
const newViewsById = viewModal?.storyId === storyId ? {
...viewModal.viewsById,
...viewsById,
} : viewsById;
const newViews = viewModal?.storyId === storyId && viewModal.views ? [
...viewModal.views,
...views,
] : views;
global = updateStoryViewsLoading(global, false, tabId);
@ -223,7 +223,7 @@ export function updateStoryViews<T extends GlobalState>(
viewModal: {
...viewModal,
storyId,
viewsById: newViewsById,
views: newViews,
nextOffset,
isLoading: false,
},

View File

@ -546,7 +546,7 @@ export function selectAllowedMessageActions<T extends GlobalState>(global: T, me
|| getServerTime() - message.date < MESSAGE_EDIT_ALLOWED_TIME
) && !(
content.sticker || content.contact || content.poll || content.action || content.audio
|| (content.video?.isRound) || content.location || content.invoice || content.giveaway
|| (content.video?.isRound) || content.location || content.invoice || content.giveaway || content.giveawayResults
)
&& !isForwarded
&& !message.viaBotId

View File

@ -56,10 +56,10 @@ import type {
ApiSticker,
ApiStickerSet,
ApiStickerSetInfo,
ApiStoryView,
ApiThemeParameters,
ApiThreadInfo,
ApiTranscription,
ApiTypeStoryView,
ApiTypingStatus,
ApiUpdate,
ApiUpdateAuthorizationStateType,
@ -378,7 +378,7 @@ export type TabState = {
isStealthModalOpen?: boolean;
viewModal?: {
storyId: number;
viewsById?: Record<string, ApiStoryView>;
views?: ApiTypeStoryView[];
nextOffset?: string;
isLoading?: boolean;
};
@ -657,6 +657,10 @@ export type TabState = {
giftCodeModal?: {
slug: string;
message?: {
chatId: string;
messageId: number;
};
info: ApiCheckedGiftCode;
};
@ -1878,6 +1882,10 @@ export interface ActionPayloads {
checkGiftCode: {
slug: string;
message?: {
chatId: string;
messageId: number;
};
} & WithTabId;
applyGiftCode: {
slug: string;

View File

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

File diff suppressed because one or more lines are too long

View File

@ -78,10 +78,10 @@ userStatusLastMonth#77ebc742 = UserStatus;
chatEmpty#29562865 id:long = Chat;
chat#41cbf256 flags:# creator:flags.0?true left:flags.2?true deactivated:flags.5?true call_active:flags.23?true call_not_empty:flags.24?true noforwards:flags.25?true id:long title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat;
chatForbidden#6592a1a7 id:long title:string = Chat;
channel#8e87ccd8 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 = 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;
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#723027bd 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 = 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;
chatParticipant#c02d4007 user_id:long inviter_id:long date:int = ChatParticipant;
chatParticipantCreator#e46bcee4 user_id:long = ChatParticipant;
chatParticipantAdmin#a0933f5b user_id:long inviter_id:long date:int = ChatParticipant;
@ -106,7 +106,8 @@ messageMediaGeoLive#b940c666 flags:# geo:GeoPoint heading:flags.0?int period:int
messageMediaPoll#4bd6e798 poll:Poll results:PollResults = MessageMedia;
messageMediaDice#3f7ee58b value:int emoticon:string = MessageMedia;
messageMediaStory#68cb6283 flags:# via_mention:flags.1?true peer:Peer id:int story:flags.0?StoryItem = MessageMedia;
messageMediaGiveaway#58260664 flags:# only_new_subscribers:flags.0?true channels:Vector<long> countries_iso2:flags.1?Vector<string> quantity:int months:int until_date:int = MessageMedia;
messageMediaGiveaway#daad85b0 flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.2?true channels:Vector<long> countries_iso2:flags.1?Vector<string> prize_description:flags.3?string quantity:int months:int until_date:int = MessageMedia;
messageMediaGiveawayResults#c6991068 flags:# only_new_subscribers:flags.0?true refunded:flags.2?true channel_id:long additional_peers_count:flags.3?int launch_msg_id:int winners_count:int unclaimed_count:int winners:Vector<long> months:int prize_description:flags.1?string until_date:int = MessageMedia;
messageActionEmpty#b6aef7b0 = MessageAction;
messageActionChatCreate#bd47cbad title:string users:Vector<long> = MessageAction;
messageActionChatEditTitle#b5a1ce5a title:string = MessageAction;
@ -143,9 +144,9 @@ messageActionGiftPremium#c83d6aec flags:# currency:string amount:long months:int
messageActionTopicCreate#d999256 flags:# title:string icon_color:int icon_emoji_id:flags.0?long = MessageAction;
messageActionTopicEdit#c0944820 flags:# title:flags.0?string icon_emoji_id:flags.1?long closed:flags.2?Bool hidden:flags.3?Bool = MessageAction;
messageActionSuggestProfilePhoto#57de635e photo:Photo = MessageAction;
messageActionRequestedPeer#fe77345d button_id:int peer:Peer = MessageAction;
messageActionRequestedPeer#31518e9b button_id:int peers:Vector<Peer> = MessageAction;
messageActionSetChatWallPaper#5060a3f4 flags:# same:flags.0?true for_both:flags.1?true wallpaper:WallPaper = MessageAction;
messageActionGiftCode#d2cfdb0e flags:# via_giveaway:flags.0?true unclaimed:flags.2?true boost_peer:flags.1?Peer months:int slug:string = 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;
messageActionGiveawayResults#2a9fadc5 winners_count:int unclaimed_count: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;
@ -342,6 +343,8 @@ updateSentStoryReaction#7d627683 peer:Peer story_id:int reaction:Reaction = Upda
updateBotChatBoost#904dd49c peer:Peer boost:Boost qts:int = Update;
updateChannelViewForumAsMessages#7b68920 channel_id:long enabled:Bool = Update;
updatePeerWallpaper#ae3f101d flags:# wallpaper_overridden:flags.1?true peer:Peer wallpaper:flags.0?WallPaper = Update;
updateBotMessageReaction#ac21d3ce peer:Peer msg_id:int date:int actor:Peer old_reactions:Vector<Reaction> new_reactions:Vector<Reaction> qts:int = Update;
updateBotMessageReactions#9cb7759 peer:Peer msg_id:int date:int reactions:Vector<ReactionCount> qts:int = Update;
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference;
updates.difference#f49ca0 new_messages:Vector<Message> new_encrypted_messages:Vector<EncryptedMessage> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> state:updates.State = updates.Difference;
@ -492,7 +495,8 @@ inputStickerSetPremiumGifts#c88b3b02 = InputStickerSet;
inputStickerSetEmojiGenericAnimations#4c4d4ce = InputStickerSet;
inputStickerSetEmojiDefaultStatuses#29d0f5ee = InputStickerSet;
inputStickerSetEmojiDefaultTopicIcons#44c1f8e9 = InputStickerSet;
stickerSet#2dd14edc flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true videos:flags.6?true emojis:flags.7?true text_color:flags.9?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector<PhotoSize> thumb_dc_id:flags.4?int thumb_version:flags.4?int thumb_document_id:flags.8?long count:int hash:int = StickerSet;
inputStickerSetEmojiChannelDefaultStatuses#49748553 = InputStickerSet;
stickerSet#2dd14edc flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true videos:flags.6?true emojis:flags.7?true text_color:flags.9?true channel_emoji_status:flags.10?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector<PhotoSize> thumb_dc_id:flags.4?int thumb_version:flags.4?int thumb_document_id:flags.8?long count:int hash:int = StickerSet;
messages.stickerSet#6e153f16 set:StickerSet packs:Vector<StickerPack> keywords:Vector<StickerKeyword> documents:Vector<Document> = messages.StickerSet;
messages.stickerSetNotModified#d3f924eb = messages.StickerSet;
botCommand#c27ac8c7 command:string description:string = BotCommand;
@ -512,7 +516,7 @@ inputKeyboardButtonUserProfile#e988037b text:string user_id:InputUser = Keyboard
keyboardButtonUserProfile#308660c1 text:string user_id:long = KeyboardButton;
keyboardButtonWebView#13767230 text:string url:string = KeyboardButton;
keyboardButtonSimpleWebView#a0c0505c text:string url:string = KeyboardButton;
keyboardButtonRequestPeer#d0b468c text:string button_id:int peer_type:RequestPeerType = KeyboardButton;
keyboardButtonRequestPeer#53d7bfd8 text:string button_id:int peer_type:RequestPeerType max_quantity:int = KeyboardButton;
keyboardButtonRow#77608b83 buttons:Vector<KeyboardButton> = KeyboardButtonRow;
replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup;
replyKeyboardForceReply#86b40b08 flags:# single_use:flags.1?true selective:flags.2?true placeholder:flags.3?string = ReplyMarkup;
@ -786,8 +790,10 @@ channelAdminLogEventActionEditTopic#f06fe208 prev_topic:ForumTopic new_topic:For
channelAdminLogEventActionDeleteTopic#ae168909 topic:ForumTopic = ChannelAdminLogEventAction;
channelAdminLogEventActionPinTopic#5d8d353b flags:# prev_topic:flags.0?ForumTopic new_topic:flags.1?ForumTopic = ChannelAdminLogEventAction;
channelAdminLogEventActionToggleAntiSpam#64f36dfc new_value:Bool = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeColor#3c2b247b prev_value:int new_value:int = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeBackgroundEmoji#445fc434 prev_value:long new_value:long = ChannelAdminLogEventAction;
channelAdminLogEventActionChangePeerColor#5796e780 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;
channelAdminLogEventActionChangeEmojiStatus#3ea9feb1 prev_value:EmojiStatus new_value:EmojiStatus = ChannelAdminLogEventAction;
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;
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;
@ -902,7 +908,7 @@ inputWallPaperNoFile#967a462e id:long = InputWallPaper;
account.wallPapersNotModified#1c199183 = account.WallPapers;
account.wallPapers#cdc3858c hash:long wallpapers:Vector<WallPaper> = account.WallPapers;
codeSettings#ad253d78 flags:# allow_flashcall:flags.0?true current_number:flags.1?true allow_app_hash:flags.4?true allow_missed_call:flags.5?true allow_firebase:flags.7?true logout_tokens:flags.6?Vector<bytes> token:flags.8?string app_sandbox:flags.8?Bool = CodeSettings;
wallPaperSettings#1dc1bca4 flags:# blur:flags.1?true motion:flags.2?true background_color:flags.0?int second_background_color:flags.4?int third_background_color:flags.5?int fourth_background_color:flags.6?int intensity:flags.3?int rotation:flags.4?int = WallPaperSettings;
wallPaperSettings#372efcd0 flags:# blur:flags.1?true motion:flags.2?true background_color:flags.0?int second_background_color:flags.4?int third_background_color:flags.5?int fourth_background_color:flags.6?int intensity:flags.3?int rotation:flags.4?int emoticon:flags.7?string = WallPaperSettings;
autoDownloadSettings#baa57628 flags:# disabled:flags.0?true video_preload_large:flags.1?true audio_preload_next:flags.2?true phonecalls_less_data:flags.3?true stories_preload:flags.4?true photo_size_max:int video_size_max:long file_size_max:long video_upload_maxbitrate:int small_queue_active_operations_max:int large_queue_active_operations_max:int = AutoDownloadSettings;
account.autoDownloadSettings#63cacf26 low:AutoDownloadSettings medium:AutoDownloadSettings high:AutoDownloadSettings = account.AutoDownloadSettings;
emojiKeyword#d5b3b9f9 keyword:string emoticons:Vector<string> = EmojiKeyword;
@ -1070,7 +1076,7 @@ help.premiumPromo#5334759c status_text:string status_entities:Vector<MessageEnti
inputStorePaymentPremiumSubscription#a6751e66 flags:# restore:flags.0?true upgrade:flags.1?true = InputStorePaymentPurpose;
inputStorePaymentGiftPremium#616f7fe8 user_id:InputUser currency:string amount:long = InputStorePaymentPurpose;
inputStorePaymentPremiumGiftCode#a3805f3f flags:# users:Vector<InputUser> boost_peer:flags.0?InputPeer currency:string amount:long = InputStorePaymentPurpose;
inputStorePaymentPremiumGiveaway#7c9375e6 flags:# only_new_subscribers:flags.0?true boost_peer:InputPeer additional_peers:flags.1?Vector<InputPeer> countries_iso2:flags.2?Vector<string> random_id:long until_date:int currency:string amount:long = InputStorePaymentPurpose;
inputStorePaymentPremiumGiveaway#160544ca flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true boost_peer:InputPeer additional_peers:flags.1?Vector<InputPeer> countries_iso2:flags.2?Vector<string> prize_description:flags.4?string random_id:long until_date:int currency:string amount:long = InputStorePaymentPurpose;
premiumGiftOption#74c34319 flags:# months:int currency:string amount:long bot_url:string store_product:flags.0?string = PremiumGiftOption;
paymentFormMethod#88f8f21b url:string title:string = PaymentFormMethod;
emojiStatusEmpty#2de11aae = EmojiStatus;
@ -1148,7 +1154,9 @@ stories.allStoriesNotModified#1158fe3e flags:# state:string stealth_mode:Stories
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;
storyView#b0bdeac5 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true user_id:long date:int reaction:flags.2?Reaction = StoryView;
stories.storyViewsList#46e9b9ec flags:# count:int reactions_count:int views:Vector<StoryView> users:Vector<User> next_offset:flags.0?string = stories.StoryViewsList;
storyViewPublicForward#9083670b flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true message:Message = StoryView;
storyViewPublicRepost#bd74cf49 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true peer_id:Peer story:StoryItem = StoryView;
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;
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;
@ -1159,11 +1167,13 @@ mediaAreaVenue#be82db9c coordinates:MediaAreaCoordinates geo:GeoPoint title:stri
inputMediaAreaVenue#b282217f coordinates:MediaAreaCoordinates query_id:long result_id:string = MediaArea;
mediaAreaGeoPoint#df8b3b22 coordinates:MediaAreaCoordinates geo:GeoPoint = MediaArea;
mediaAreaSuggestedReaction#14455871 flags:# dark:flags.0?true flipped:flags.1?true coordinates:MediaAreaCoordinates reaction:Reaction = MediaArea;
mediaAreaChannelPost#770416af coordinates:MediaAreaCoordinates channel_id:long msg_id:int = MediaArea;
inputMediaAreaChannelPost#2271f2bf coordinates:MediaAreaCoordinates channel:InputChannel msg_id:int = MediaArea;
peerStories#9a35e999 flags:# peer:Peer max_read_id:flags.0?int stories:Vector<StoryItem> = PeerStories;
stories.peerStories#cae68768 stories:PeerStories chats:Vector<Chat> users:Vector<User> = stories.PeerStories;
messages.webPage#fd5e12bd webpage:WebPage chats:Vector<Chat> users:Vector<User> = messages.WebPage;
premiumGiftCodeOption#257e962b flags:# users:int months:int store_product:flags.0?string store_quantity:flags.1?int currency:string amount:long = PremiumGiftCodeOption;
payments.checkedGiftCode#b722f158 flags:# via_giveaway:flags.2?true from_id:Peer giveaway_msg_id:flags.3?int to_id:flags.0?long date:int months:int used_date:flags.1?int chats:Vector<Chat> users:Vector<User> = payments.CheckedGiftCode;
payments.checkedGiftCode#284a1096 flags:# via_giveaway:flags.2?true from_id:flags.4?Peer giveaway_msg_id:flags.3?int to_id:flags.0?long date:int months:int used_date:flags.1?int chats:Vector<Chat> users:Vector<User> = payments.CheckedGiftCode;
payments.giveawayInfo#4367daa0 flags:# participating:flags.0?true preparing_results:flags.3?true start_date:int joined_too_early_date:flags.1?int admin_disallowed_chat_id:flags.2?long disallowed_country:flags.4?string = payments.GiveawayInfo;
payments.giveawayInfoResults#cd5570 flags:# winner:flags.0?true refunded:flags.1?true start_date:int gift_code_slug:flags.0?string finish_date:int winners_count:int activated_count:int = payments.GiveawayInfo;
prepaidGiveaway#b2539d54 id:long months:int quantity:int date:int = PrepaidGiveaway;
@ -1182,9 +1192,13 @@ stats.publicForwards#93037e20 flags:# count:int forwards:Vector<PublicForward> n
peerColor#b54b5acf flags:# color:flags.0?int background_emoji_id:flags.1?long = PeerColor;
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.peerColorOption#135bd42f flags:# hidden:flags.0?true color_id:int colors:flags.1?help.PeerColorSet dark_colors:flags.2?help.PeerColorSet = help.PeerColorOption;
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.peerColorsNotModified#2ba1f5ce = help.PeerColors;
help.peerColors#f8ed08 hash:int colors:Vector<help.PeerColorOption> = help.PeerColors;
storyReaction#6090d6d5 peer_id:Peer date:int reaction:Reaction = StoryReaction;
storyReactionPublicForward#bbab2643 message:Message = StoryReaction;
storyReactionPublicRepost#cfcd0f13 peer_id:Peer story:StoryItem = StoryReaction;
stories.storyReactionsList#aa5f789c flags:# count:int reactions:Vector<StoryReaction> chats:Vector<Chat> users:Vector<User> next_offset:flags.0?string = stories.StoryReactionsList;
---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
initConnection#c1cd5ea9 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy params:flags.1?JSONValue query:!X = X;
@ -1481,7 +1495,7 @@ folders.editPeerFolders#6847d0ab folder_peers:Vector<InputFolderPeer> = Updates;
stats.getBroadcastStats#ab42441a flags:# dark:flags.0?true channel:InputChannel = stats.BroadcastStats;
stats.loadAsyncGraph#621d5fa0 flags:# token:string x:flags.0?long = StatsGraph;
stats.getMegagroupStats#dcdf8607 flags:# dark:flags.0?true channel:InputChannel = stats.MegagroupStats;
stats.getMessagePublicForwards#5630281b channel:InputChannel msg_id:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
stats.getMessagePublicForwards#5f150144 channel:InputChannel msg_id:int offset:string limit:int = stats.PublicForwards;
stats.getMessageStats#b6e0a3f5 flags:# dark:flags.0?true channel:InputChannel msg_id:int = stats.MessageStats;
stats.getStoryStats#374fef40 flags:# dark:flags.0?true peer:InputPeer id:int = stats.StoryStats;
stats.getStoryPublicForwards#a6437ef6 peer:InputPeer id:int offset:string limit:int = stats.PublicForwards;
@ -1502,7 +1516,7 @@ stories.getStoriesArchive#b4352016 peer:InputPeer offset_id:int limit:int = stor
stories.getStoriesByID#5774ca74 peer:InputPeer id:Vector<int> = stories.Stories;
stories.readStories#a556dac8 peer:InputPeer max_id:int = Vector<int>;
stories.incrementStoryViews#b2028afb peer:InputPeer id:Vector<int> = Bool;
stories.getStoryViewsList#7ed23c57 flags:# just_contacts:flags.0?true reactions_first:flags.2?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.exportStoryLink#7b8def20 peer:InputPeer id:int = ExportedStoryLink;
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;

View File

@ -97,11 +97,11 @@ userStatusLastMonth#77ebc742 = UserStatus;
chatEmpty#29562865 id:long = Chat;
chat#41cbf256 flags:# creator:flags.0?true left:flags.2?true deactivated:flags.5?true call_active:flags.23?true call_not_empty:flags.24?true noforwards:flags.25?true id:long title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat;
chatForbidden#6592a1a7 id:long title:string = Chat;
channel#8e87ccd8 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 = 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;
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#723027bd 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 = 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;
chatParticipant#c02d4007 user_id:long inviter_id:long date:int = ChatParticipant;
chatParticipantCreator#e46bcee4 user_id:long = ChatParticipant;
@ -131,7 +131,8 @@ messageMediaGeoLive#b940c666 flags:# geo:GeoPoint heading:flags.0?int period:int
messageMediaPoll#4bd6e798 poll:Poll results:PollResults = MessageMedia;
messageMediaDice#3f7ee58b value:int emoticon:string = MessageMedia;
messageMediaStory#68cb6283 flags:# via_mention:flags.1?true peer:Peer id:int story:flags.0?StoryItem = MessageMedia;
messageMediaGiveaway#58260664 flags:# only_new_subscribers:flags.0?true channels:Vector<long> countries_iso2:flags.1?Vector<string> quantity:int months:int until_date:int = MessageMedia;
messageMediaGiveaway#daad85b0 flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.2?true channels:Vector<long> countries_iso2:flags.1?Vector<string> prize_description:flags.3?string quantity:int months:int until_date:int = MessageMedia;
messageMediaGiveawayResults#c6991068 flags:# only_new_subscribers:flags.0?true refunded:flags.2?true channel_id:long additional_peers_count:flags.3?int launch_msg_id:int winners_count:int unclaimed_count:int winners:Vector<long> months:int prize_description:flags.1?string until_date:int = MessageMedia;
messageActionEmpty#b6aef7b0 = MessageAction;
messageActionChatCreate#bd47cbad title:string users:Vector<long> = MessageAction;
@ -169,9 +170,9 @@ messageActionGiftPremium#c83d6aec flags:# currency:string amount:long months:int
messageActionTopicCreate#d999256 flags:# title:string icon_color:int icon_emoji_id:flags.0?long = MessageAction;
messageActionTopicEdit#c0944820 flags:# title:flags.0?string icon_emoji_id:flags.1?long closed:flags.2?Bool hidden:flags.3?Bool = MessageAction;
messageActionSuggestProfilePhoto#57de635e photo:Photo = MessageAction;
messageActionRequestedPeer#fe77345d button_id:int peer:Peer = MessageAction;
messageActionRequestedPeer#31518e9b button_id:int peers:Vector<Peer> = MessageAction;
messageActionSetChatWallPaper#5060a3f4 flags:# same:flags.0?true for_both:flags.1?true wallpaper:WallPaper = MessageAction;
messageActionGiftCode#d2cfdb0e flags:# via_giveaway:flags.0?true unclaimed:flags.2?true boost_peer:flags.1?Peer months:int slug:string = 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;
messageActionGiveawayResults#2a9fadc5 winners_count:int unclaimed_count:int = MessageAction;
@ -395,6 +396,8 @@ updateSentStoryReaction#7d627683 peer:Peer story_id:int reaction:Reaction = Upda
updateBotChatBoost#904dd49c peer:Peer boost:Boost qts:int = Update;
updateChannelViewForumAsMessages#7b68920 channel_id:long enabled:Bool = Update;
updatePeerWallpaper#ae3f101d flags:# wallpaper_overridden:flags.1?true peer:Peer wallpaper:flags.0?WallPaper = Update;
updateBotMessageReaction#ac21d3ce peer:Peer msg_id:int date:int actor:Peer old_reactions:Vector<Reaction> new_reactions:Vector<Reaction> qts:int = Update;
updateBotMessageReactions#9cb7759 peer:Peer msg_id:int date:int reactions:Vector<ReactionCount> qts:int = Update;
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
@ -591,8 +594,9 @@ inputStickerSetPremiumGifts#c88b3b02 = InputStickerSet;
inputStickerSetEmojiGenericAnimations#4c4d4ce = InputStickerSet;
inputStickerSetEmojiDefaultStatuses#29d0f5ee = InputStickerSet;
inputStickerSetEmojiDefaultTopicIcons#44c1f8e9 = InputStickerSet;
inputStickerSetEmojiChannelDefaultStatuses#49748553 = InputStickerSet;
stickerSet#2dd14edc flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true videos:flags.6?true emojis:flags.7?true text_color:flags.9?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector<PhotoSize> thumb_dc_id:flags.4?int thumb_version:flags.4?int thumb_document_id:flags.8?long count:int hash:int = StickerSet;
stickerSet#2dd14edc flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true videos:flags.6?true emojis:flags.7?true text_color:flags.9?true channel_emoji_status:flags.10?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector<PhotoSize> thumb_dc_id:flags.4?int thumb_version:flags.4?int thumb_document_id:flags.8?long count:int hash:int = StickerSet;
messages.stickerSet#6e153f16 set:StickerSet packs:Vector<StickerPack> keywords:Vector<StickerKeyword> documents:Vector<Document> = messages.StickerSet;
messages.stickerSetNotModified#d3f924eb = messages.StickerSet;
@ -616,7 +620,7 @@ inputKeyboardButtonUserProfile#e988037b text:string user_id:InputUser = Keyboard
keyboardButtonUserProfile#308660c1 text:string user_id:long = KeyboardButton;
keyboardButtonWebView#13767230 text:string url:string = KeyboardButton;
keyboardButtonSimpleWebView#a0c0505c text:string url:string = KeyboardButton;
keyboardButtonRequestPeer#d0b468c text:string button_id:int peer_type:RequestPeerType = KeyboardButton;
keyboardButtonRequestPeer#53d7bfd8 text:string button_id:int peer_type:RequestPeerType max_quantity:int = KeyboardButton;
keyboardButtonRow#77608b83 buttons:Vector<KeyboardButton> = KeyboardButtonRow;
@ -969,8 +973,10 @@ channelAdminLogEventActionEditTopic#f06fe208 prev_topic:ForumTopic new_topic:For
channelAdminLogEventActionDeleteTopic#ae168909 topic:ForumTopic = ChannelAdminLogEventAction;
channelAdminLogEventActionPinTopic#5d8d353b flags:# prev_topic:flags.0?ForumTopic new_topic:flags.1?ForumTopic = ChannelAdminLogEventAction;
channelAdminLogEventActionToggleAntiSpam#64f36dfc new_value:Bool = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeColor#3c2b247b prev_value:int new_value:int = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeBackgroundEmoji#445fc434 prev_value:long new_value:long = ChannelAdminLogEventAction;
channelAdminLogEventActionChangePeerColor#5796e780 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;
channelAdminLogEventActionChangeEmojiStatus#3ea9feb1 prev_value:EmojiStatus new_value:EmojiStatus = ChannelAdminLogEventAction;
channelAdminLogEvent#1fad68cd id:long date:int user_id:long action:ChannelAdminLogEventAction = ChannelAdminLogEvent;
@ -1147,7 +1153,7 @@ account.wallPapers#cdc3858c hash:long wallpapers:Vector<WallPaper> = account.Wal
codeSettings#ad253d78 flags:# allow_flashcall:flags.0?true current_number:flags.1?true allow_app_hash:flags.4?true allow_missed_call:flags.5?true allow_firebase:flags.7?true logout_tokens:flags.6?Vector<bytes> token:flags.8?string app_sandbox:flags.8?Bool = CodeSettings;
wallPaperSettings#1dc1bca4 flags:# blur:flags.1?true motion:flags.2?true background_color:flags.0?int second_background_color:flags.4?int third_background_color:flags.5?int fourth_background_color:flags.6?int intensity:flags.3?int rotation:flags.4?int = WallPaperSettings;
wallPaperSettings#372efcd0 flags:# blur:flags.1?true motion:flags.2?true background_color:flags.0?int second_background_color:flags.4?int third_background_color:flags.5?int fourth_background_color:flags.6?int intensity:flags.3?int rotation:flags.4?int emoticon:flags.7?string = WallPaperSettings;
autoDownloadSettings#baa57628 flags:# disabled:flags.0?true video_preload_large:flags.1?true audio_preload_next:flags.2?true phonecalls_less_data:flags.3?true stories_preload:flags.4?true photo_size_max:int video_size_max:long file_size_max:long video_upload_maxbitrate:int small_queue_active_operations_max:int large_queue_active_operations_max:int = AutoDownloadSettings;
@ -1426,7 +1432,7 @@ help.premiumPromo#5334759c status_text:string status_entities:Vector<MessageEnti
inputStorePaymentPremiumSubscription#a6751e66 flags:# restore:flags.0?true upgrade:flags.1?true = InputStorePaymentPurpose;
inputStorePaymentGiftPremium#616f7fe8 user_id:InputUser currency:string amount:long = InputStorePaymentPurpose;
inputStorePaymentPremiumGiftCode#a3805f3f flags:# users:Vector<InputUser> boost_peer:flags.0?InputPeer currency:string amount:long = InputStorePaymentPurpose;
inputStorePaymentPremiumGiveaway#7c9375e6 flags:# only_new_subscribers:flags.0?true boost_peer:InputPeer additional_peers:flags.1?Vector<InputPeer> countries_iso2:flags.2?Vector<string> random_id:long until_date:int currency:string amount:long = InputStorePaymentPurpose;
inputStorePaymentPremiumGiveaway#160544ca flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true boost_peer:InputPeer additional_peers:flags.1?Vector<InputPeer> countries_iso2:flags.2?Vector<string> prize_description:flags.4?string random_id:long until_date:int currency:string amount:long = InputStorePaymentPurpose;
premiumGiftOption#74c34319 flags:# months:int currency:string amount:long bot_url:string store_product:flags.0?string = PremiumGiftOption;
@ -1553,8 +1559,10 @@ stories.allStories#6efc5e81 flags:# has_more:flags.0?true count:int state:string
stories.stories#5dd8c3c8 count:int stories:Vector<StoryItem> chats:Vector<Chat> users:Vector<User> = stories.Stories;
storyView#b0bdeac5 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true user_id:long date:int reaction:flags.2?Reaction = StoryView;
storyViewPublicForward#9083670b flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true message:Message = StoryView;
storyViewPublicRepost#bd74cf49 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true peer_id:Peer story:StoryItem = StoryView;
stories.storyViewsList#46e9b9ec flags:# count:int reactions_count:int views:Vector<StoryView> 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;
@ -1571,6 +1579,8 @@ mediaAreaVenue#be82db9c coordinates:MediaAreaCoordinates geo:GeoPoint title:stri
inputMediaAreaVenue#b282217f coordinates:MediaAreaCoordinates query_id:long result_id:string = MediaArea;
mediaAreaGeoPoint#df8b3b22 coordinates:MediaAreaCoordinates geo:GeoPoint = MediaArea;
mediaAreaSuggestedReaction#14455871 flags:# dark:flags.0?true flipped:flags.1?true coordinates:MediaAreaCoordinates reaction:Reaction = MediaArea;
mediaAreaChannelPost#770416af coordinates:MediaAreaCoordinates channel_id:long msg_id:int = MediaArea;
inputMediaAreaChannelPost#2271f2bf coordinates:MediaAreaCoordinates channel:InputChannel msg_id:int = MediaArea;
peerStories#9a35e999 flags:# peer:Peer max_read_id:flags.0?int stories:Vector<StoryItem> = PeerStories;
@ -1580,7 +1590,7 @@ messages.webPage#fd5e12bd webpage:WebPage chats:Vector<Chat> users:Vector<User>
premiumGiftCodeOption#257e962b flags:# users:int months:int store_product:flags.0?string store_quantity:flags.1?int currency:string amount:long = PremiumGiftCodeOption;
payments.checkedGiftCode#b722f158 flags:# via_giveaway:flags.2?true from_id:Peer giveaway_msg_id:flags.3?int to_id:flags.0?long date:int months:int used_date:flags.1?int chats:Vector<Chat> users:Vector<User> = payments.CheckedGiftCode;
payments.checkedGiftCode#284a1096 flags:# via_giveaway:flags.2?true from_id:flags.4?Peer giveaway_msg_id:flags.3?int to_id:flags.0?long date:int months:int used_date:flags.1?int chats:Vector<Chat> users:Vector<User> = payments.CheckedGiftCode;
payments.giveawayInfo#4367daa0 flags:# participating:flags.0?true preparing_results:flags.3?true start_date:int joined_too_early_date:flags.1?int admin_disallowed_chat_id:flags.2?long disallowed_country:flags.4?string = payments.GiveawayInfo;
payments.giveawayInfoResults#cd5570 flags:# winner:flags.0?true refunded:flags.1?true start_date:int gift_code_slug:flags.0?string finish_date:int winners_count:int activated_count:int = payments.GiveawayInfo;
@ -1614,11 +1624,17 @@ peerColor#b54b5acf flags:# color:flags.0?int background_emoji_id:flags.1?long =
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.peerColorOption#135bd42f flags:# hidden:flags.0?true color_id:int colors:flags.1?help.PeerColorSet dark_colors:flags.2?help.PeerColorSet = help.PeerColorOption;
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.peerColorsNotModified#2ba1f5ce = help.PeerColors;
help.peerColors#f8ed08 hash:int colors:Vector<help.PeerColorOption> = help.PeerColors;
storyReaction#6090d6d5 peer_id:Peer date:int reaction:Reaction = StoryReaction;
storyReactionPublicForward#bbab2643 message:Message = StoryReaction;
storyReactionPublicRepost#cfcd0f13 peer_id:Peer story:StoryItem = StoryReaction;
stories.storyReactionsList#aa5f789c flags:# count:int reactions:Vector<StoryReaction> chats:Vector<Chat> users:Vector<User> next_offset:flags.0?string = stories.StoryReactionsList;
---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
@ -1742,6 +1758,8 @@ account.deleteAutoSaveExceptions#53bc0020 = Bool;
account.invalidateSignInCodes#ca8ae8ba codes:Vector<string> = Bool;
account.updateColor#7cefa15d flags:# for_profile:flags.1?true color:flags.2?int background_emoji_id:flags.0?long = Bool;
account.getDefaultBackgroundEmojis#a60ab9ce hash:long = EmojiList;
account.getChannelDefaultEmojiStatuses#7727a7d5 hash:long = account.EmojiStatuses;
account.getChannelRestrictedStatusEmojis#35a9e0d5 hash:long = EmojiList;
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
users.getFullUser#b60f5918 id:InputUser = users.UserFull;
@ -1951,7 +1969,7 @@ messages.clearRecentReactions#9dfeefb4 = Bool;
messages.getExtendedMedia#84f80814 peer:InputPeer id:Vector<int> = Updates;
messages.setDefaultHistoryTTL#9eb51445 period:int = Bool;
messages.getDefaultHistoryTTL#658b7188 = DefaultHistoryTTL;
messages.sendBotRequestedPeer#fe38d01b peer:InputPeer msg_id:int button_id:int requested_peer:InputPeer = Updates;
messages.sendBotRequestedPeer#91b2d060 peer:InputPeer msg_id:int button_id:int requested_peers:Vector<InputPeer> = Updates;
messages.getEmojiGroups#7488ce5b hash:int = messages.EmojiGroups;
messages.getEmojiStatusGroups#2ecd56cd hash:int = messages.EmojiGroups;
messages.getEmojiProfilePhotoGroups#21a548f3 hash:int = messages.EmojiGroups;
@ -1986,7 +2004,6 @@ help.getNearestDc#1fb33026 = NearestDc;
help.getAppUpdate#522d5a7d source:string = help.AppUpdate;
help.getInviteText#4d392343 = help.InviteText;
help.getSupport#9cdf08cd = help.Support;
help.getAppChangelog#9010ef6f prev_app_version:string = Updates;
help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool;
help.getCdnConfig#52029342 = CdnConfig;
help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls;
@ -2063,9 +2080,10 @@ channels.toggleAntiSpam#68f3e4eb channel:InputChannel enabled:Bool = Updates;
channels.reportAntiSpamFalsePositive#a850a693 channel:InputChannel msg_id:int = Bool;
channels.toggleParticipantsHidden#6a6e7854 channel:InputChannel enabled:Bool = Updates;
channels.clickSponsoredMessage#18afbc93 channel:InputChannel random_id:bytes = Bool;
channels.updateColor#621a201f flags:# channel:InputChannel color:int background_emoji_id:flags.0?long = Updates;
channels.updateColor#d8aa3671 flags:# for_profile:flags.1?true channel:InputChannel color:flags.2?int background_emoji_id:flags.0?long = Updates;
channels.toggleViewForumAsMessages#9738bb15 channel:InputChannel enabled:Bool = Updates;
channels.getChannelRecommendations#83b70d97 channel:InputChannel = messages.Chats;
channels.updateEmojiStatus#f0d3e6a8 channel:InputChannel emoji_status:EmojiStatus = Updates;
bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON;
bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool;
@ -2155,7 +2173,7 @@ folders.editPeerFolders#6847d0ab folder_peers:Vector<InputFolderPeer> = Updates;
stats.getBroadcastStats#ab42441a flags:# dark:flags.0?true channel:InputChannel = stats.BroadcastStats;
stats.loadAsyncGraph#621d5fa0 flags:# token:string x:flags.0?long = StatsGraph;
stats.getMegagroupStats#dcdf8607 flags:# dark:flags.0?true channel:InputChannel = stats.MegagroupStats;
stats.getMessagePublicForwards#5630281b channel:InputChannel msg_id:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
stats.getMessagePublicForwards#5f150144 channel:InputChannel msg_id:int offset:string limit:int = stats.PublicForwards;
stats.getMessageStats#b6e0a3f5 flags:# dark:flags.0?true channel:InputChannel msg_id:int = stats.MessageStats;
stats.getStoryStats#374fef40 flags:# dark:flags.0?true peer:InputPeer id:int = stats.StoryStats;
stats.getStoryPublicForwards#a6437ef6 peer:InputPeer id:int offset:string limit:int = stats.PublicForwards;
@ -2184,7 +2202,7 @@ stories.getStoriesByID#5774ca74 peer:InputPeer id:Vector<int> = stories.Stories;
stories.toggleAllStoriesHidden#7c2557c4 hidden:Bool = Bool;
stories.readStories#a556dac8 peer:InputPeer max_id:int = Vector<int>;
stories.incrementStoryViews#b2028afb peer:InputPeer id:Vector<int> = Bool;
stories.getStoryViewsList#7ed23c57 flags:# just_contacts:flags.0?true reactions_first:flags.2?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.report#1923fa8c peer:InputPeer id:Vector<int> reason:ReportReason message:string = Bool;
@ -2195,6 +2213,7 @@ stories.getAllReadPeerStories#9b5ae7f9 = Updates;
stories.getPeerMaxIDs#535983c3 id:Vector<InputPeer> = Vector<int>;
stories.getChatsToSend#a56a8b60 = messages.Chats;
stories.togglePeerStoriesHidden#bd0415c4 peer:InputPeer hidden:Bool = Bool;
stories.getStoryReactionsList#b9b2881f flags:# forwards_first:flags.2?true peer:InputPeer id:int reaction:flags.0?Reaction offset:flags.1?string limit:int = stories.StoryReactionsList;
premium.getBoostsList#60f67660 flags:# gifts:flags.0?true peer:InputPeer offset:string limit:int = premium.BoostsList;
premium.getMyBoosts#be77b4a = premium.MyBoosts;