Sponsored Message: Implement reporting (#4487)
This commit is contained in:
parent
19e90c8fbb
commit
37ad59d937
@ -74,6 +74,7 @@ export interface GramJsAppConfig extends LimitsConfig {
|
|||||||
// Boosts
|
// Boosts
|
||||||
group_transcribe_level_min?: number;
|
group_transcribe_level_min?: number;
|
||||||
new_noncontact_peers_require_premium_without_ownpremium?: boolean;
|
new_noncontact_peers_require_premium_without_ownpremium?: boolean;
|
||||||
|
channel_restrict_sponsored_level_min?: number;
|
||||||
// Upload premium notifications
|
// Upload premium notifications
|
||||||
upload_premium_speedup_notify_period?: number;
|
upload_premium_speedup_notify_period?: number;
|
||||||
upload_premium_speedup_download?: number;
|
upload_premium_speedup_download?: number;
|
||||||
@ -156,5 +157,6 @@ export function buildAppConfig(json: GramJs.TypeJSONValue, hash: number): ApiApp
|
|||||||
bandwidthPremiumNotifyPeriod: appConfig.upload_premium_speedup_notify_period,
|
bandwidthPremiumNotifyPeriod: appConfig.upload_premium_speedup_notify_period,
|
||||||
bandwidthPremiumUploadSpeedup: appConfig.upload_premium_speedup_upload,
|
bandwidthPremiumUploadSpeedup: appConfig.upload_premium_speedup_upload,
|
||||||
bandwidthPremiumDownloadSpeedup: appConfig.upload_premium_speedup_download,
|
bandwidthPremiumDownloadSpeedup: appConfig.upload_premium_speedup_download,
|
||||||
|
channelRestrictAdsLevelMin: appConfig.channel_restrict_sponsored_level_min,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,11 +17,13 @@ import type {
|
|||||||
ApiMissingInvitedUser,
|
ApiMissingInvitedUser,
|
||||||
ApiRestrictionReason,
|
ApiRestrictionReason,
|
||||||
ApiSendAsPeerId,
|
ApiSendAsPeerId,
|
||||||
|
ApiSponsoredMessageReportResult,
|
||||||
ApiTopic,
|
ApiTopic,
|
||||||
} from '../../types';
|
} from '../../types';
|
||||||
|
|
||||||
import { omitUndefined, pick, pickTruthy } from '../../../util/iteratees';
|
import { omitUndefined, pick, pickTruthy } from '../../../util/iteratees';
|
||||||
import { getServerTime, getServerTimeOffset } from '../../../util/serverTime';
|
import { getServerTime, getServerTimeOffset } from '../../../util/serverTime';
|
||||||
|
import { serializeBytes } from '../helpers';
|
||||||
import { buildApiUsernames } from './common';
|
import { buildApiUsernames } from './common';
|
||||||
import { omitVirtualClassFields } from './helpers';
|
import { omitVirtualClassFields } from './helpers';
|
||||||
import {
|
import {
|
||||||
@ -645,3 +647,31 @@ export function buildApiMissingInvitedUser(
|
|||||||
isRequiringPremiumToInvite: user.premiumWouldAllowInvite,
|
isRequiringPremiumToInvite: user.premiumWouldAllowInvite,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function buildApiSponsoredMessageReportResult(
|
||||||
|
result: GramJs.channels.TypeSponsoredMessageReportResult,
|
||||||
|
): ApiSponsoredMessageReportResult {
|
||||||
|
if (result instanceof GramJs.channels.SponsoredMessageReportResultReported) {
|
||||||
|
return {
|
||||||
|
type: 'reported',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result instanceof GramJs.channels.SponsoredMessageReportResultAdsHidden) {
|
||||||
|
return {
|
||||||
|
type: 'hidden',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const title = result.title;
|
||||||
|
const options = result.options.map((option) => ({
|
||||||
|
text: option.text,
|
||||||
|
option: serializeBytes(option.option),
|
||||||
|
}));
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: 'selectOption',
|
||||||
|
title,
|
||||||
|
options,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@ -20,7 +20,6 @@ import type {
|
|||||||
ApiReplyInfo,
|
ApiReplyInfo,
|
||||||
ApiReplyKeyboard,
|
ApiReplyKeyboard,
|
||||||
ApiSponsoredMessage,
|
ApiSponsoredMessage,
|
||||||
ApiSponsoredWebPage,
|
|
||||||
ApiSticker,
|
ApiSticker,
|
||||||
ApiStory,
|
ApiStory,
|
||||||
ApiStorySkipped,
|
ApiStorySkipped,
|
||||||
@ -51,13 +50,12 @@ import {
|
|||||||
resolveMessageApiChatId,
|
resolveMessageApiChatId,
|
||||||
serializeBytes,
|
serializeBytes,
|
||||||
} from '../helpers';
|
} from '../helpers';
|
||||||
import { buildApiBotApp } from './bots';
|
|
||||||
import { buildApiCallDiscardReason } from './calls';
|
import { buildApiCallDiscardReason } from './calls';
|
||||||
import {
|
import {
|
||||||
buildApiPhoto,
|
buildApiPhoto,
|
||||||
} from './common';
|
} from './common';
|
||||||
import { buildMessageContent, buildMessageMediaContent, buildMessageTextContent } from './messageContent';
|
import { buildMessageContent, buildMessageMediaContent, buildMessageTextContent } from './messageContent';
|
||||||
import { buildApiPeerId, getApiChatIdFromMtpPeer, isPeerUser } from './peers';
|
import { buildApiPeerColor, buildApiPeerId, getApiChatIdFromMtpPeer } from './peers';
|
||||||
import { buildMessageReactions } from './reactions';
|
import { buildMessageReactions } from './reactions';
|
||||||
|
|
||||||
const LOCAL_MESSAGES_LIMIT = 1e6; // 1M
|
const LOCAL_MESSAGES_LIMIT = 1e6; // 1M
|
||||||
@ -79,33 +77,28 @@ export function setMessageBuilderCurrentUserId(_currentUserId: string) {
|
|||||||
|
|
||||||
export function buildApiSponsoredMessage(mtpMessage: GramJs.SponsoredMessage): ApiSponsoredMessage | undefined {
|
export function buildApiSponsoredMessage(mtpMessage: GramJs.SponsoredMessage): ApiSponsoredMessage | undefined {
|
||||||
const {
|
const {
|
||||||
fromId, message, entities, startParam, channelPost, chatInvite, chatInviteHash, randomId, recommended, sponsorInfo,
|
message, entities, randomId, recommended, sponsorInfo, additionalInfo, buttonText, canReport, title, url, color,
|
||||||
additionalInfo, showPeerPhoto, webpage, buttonText, app,
|
|
||||||
} = mtpMessage;
|
} = mtpMessage;
|
||||||
const chatId = fromId ? getApiChatIdFromMtpPeer(fromId) : undefined;
|
|
||||||
const chatInviteTitle = chatInvite
|
let photo: ApiPhoto | undefined;
|
||||||
? (chatInvite instanceof GramJs.ChatInvite
|
if (mtpMessage.photo instanceof GramJs.Photo) {
|
||||||
? chatInvite.title
|
addPhotoToLocalDb(mtpMessage.photo);
|
||||||
: !(chatInvite.chat instanceof GramJs.ChatEmpty) ? chatInvite.chat.title : undefined)
|
photo = buildApiPhoto(mtpMessage.photo);
|
||||||
: undefined;
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
randomId: serializeBytes(randomId),
|
randomId: serializeBytes(randomId),
|
||||||
isBot: fromId ? isPeerUser(fromId) : false,
|
|
||||||
text: buildMessageTextContent(message, entities),
|
text: buildMessageTextContent(message, entities),
|
||||||
expiresAt: Math.round(Date.now() / 1000) + SPONSORED_MESSAGE_CACHE_MS,
|
expiresAt: Math.round(Date.now() / 1000) + SPONSORED_MESSAGE_CACHE_MS,
|
||||||
isRecommended: Boolean(recommended),
|
isRecommended: recommended,
|
||||||
...(webpage && { webPage: buildSponsoredWebPage(webpage) }),
|
sponsorInfo,
|
||||||
...(showPeerPhoto && { isAvatarShown: true }),
|
additionalInfo,
|
||||||
...(chatId && { chatId }),
|
buttonText,
|
||||||
...(chatInviteHash && { chatInviteHash }),
|
canReport,
|
||||||
...(chatInvite && { chatInviteTitle }),
|
title,
|
||||||
...(startParam && { startParam }),
|
url,
|
||||||
...(channelPost && { channelPostId: channelPost }),
|
peerColor: color && buildApiPeerColor(color),
|
||||||
...(sponsorInfo && { sponsorInfo }),
|
photo,
|
||||||
...(additionalInfo && { additionalInfo }),
|
|
||||||
...(buttonText && { buttonText }),
|
|
||||||
...(app && { botApp: buildApiBotApp(app) }),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1094,19 +1087,3 @@ export function buildApiQuickReply(reply: GramJs.TypeQuickReply): ApiQuickReply
|
|||||||
topMessageId: topMessage,
|
topMessageId: topMessage,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildSponsoredWebPage(webPage: GramJs.TypeSponsoredWebPage): ApiSponsoredWebPage {
|
|
||||||
let photo: ApiPhoto | undefined;
|
|
||||||
if (webPage.photo instanceof GramJs.Photo) {
|
|
||||||
addPhotoToLocalDb(webPage.photo);
|
|
||||||
photo = buildApiPhoto(webPage.photo);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...pick(webPage, [
|
|
||||||
'url',
|
|
||||||
'siteName',
|
|
||||||
]),
|
|
||||||
photo,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|||||||
@ -22,7 +22,7 @@ export function buildApiUserFullInfo(mtpUserFull: GramJs.users.UserFull): ApiUse
|
|||||||
profilePhoto, voiceMessagesForbidden, premiumGifts,
|
profilePhoto, voiceMessagesForbidden, premiumGifts,
|
||||||
fallbackPhoto, personalPhoto, translationsDisabled, storiesPinnedAvailable,
|
fallbackPhoto, personalPhoto, translationsDisabled, storiesPinnedAvailable,
|
||||||
contactRequirePremium, businessWorkHours, businessLocation, businessIntro,
|
contactRequirePremium, businessWorkHours, businessLocation, businessIntro,
|
||||||
birthday, personalChannelId, personalChannelMessage,
|
birthday, personalChannelId, personalChannelMessage, sponsoredEnabled,
|
||||||
},
|
},
|
||||||
users,
|
users,
|
||||||
} = mtpUserFull;
|
} = mtpUserFull;
|
||||||
@ -49,6 +49,7 @@ export function buildApiUserFullInfo(mtpUserFull: GramJs.users.UserFull): ApiUse
|
|||||||
businessIntro: businessIntro && buildApiBusinessIntro(businessIntro),
|
businessIntro: businessIntro && buildApiBusinessIntro(businessIntro),
|
||||||
personalChannelId: personalChannelId && buildApiPeerId(personalChannelId, 'channel'),
|
personalChannelId: personalChannelId && buildApiPeerId(personalChannelId, 'channel'),
|
||||||
personalChannelMessageId: personalChannelMessage,
|
personalChannelMessageId: personalChannelMessage,
|
||||||
|
areAdsEnabled: sponsoredEnabled,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -94,3 +94,15 @@ export async function resolveBusinessChatLink({ slug } : { slug: string }) {
|
|||||||
chatLink,
|
chatLink,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function toggleSponsoredMessages({
|
||||||
|
enabled,
|
||||||
|
}: {
|
||||||
|
enabled: boolean;
|
||||||
|
}) {
|
||||||
|
return invokeRequest(new GramJs.account.ToggleSponsoredMessages({
|
||||||
|
enabled,
|
||||||
|
}), {
|
||||||
|
shouldReturnTrue: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@ -44,6 +44,7 @@ import {
|
|||||||
buildApiChatReactions,
|
buildApiChatReactions,
|
||||||
buildApiChatSettings,
|
buildApiChatSettings,
|
||||||
buildApiMissingInvitedUser,
|
buildApiMissingInvitedUser,
|
||||||
|
buildApiSponsoredMessageReportResult,
|
||||||
buildApiTopic,
|
buildApiTopic,
|
||||||
buildChatMembers,
|
buildChatMembers,
|
||||||
getPeerKey,
|
getPeerKey,
|
||||||
@ -70,6 +71,7 @@ import {
|
|||||||
addEntitiesToLocalDb,
|
addEntitiesToLocalDb,
|
||||||
addMessageToLocalDb,
|
addMessageToLocalDb,
|
||||||
addPhotoToLocalDb,
|
addPhotoToLocalDb,
|
||||||
|
deserializeBytes,
|
||||||
isChatFolder,
|
isChatFolder,
|
||||||
} from '../helpers';
|
} from '../helpers';
|
||||||
import localDb from '../localDb';
|
import localDb from '../localDb';
|
||||||
@ -2017,3 +2019,39 @@ export async function fetchChannelRecommendations({ chat }: { chat: ApiChat }) {
|
|||||||
result instanceof GramJs.messages.ChatsSlice ? result.count : undefined,
|
result instanceof GramJs.messages.ChatsSlice ? result.count : undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function reportSponsoredMessage({
|
||||||
|
chat,
|
||||||
|
randomId,
|
||||||
|
option,
|
||||||
|
}: {
|
||||||
|
chat: ApiChat;
|
||||||
|
randomId: string;
|
||||||
|
option: string;
|
||||||
|
}) {
|
||||||
|
const { id, accessHash } = chat;
|
||||||
|
const channel = buildInputEntity(id, accessHash);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await invokeRequest(new GramJs.channels.ReportSponsoredMessage({
|
||||||
|
channel: channel as GramJs.InputChannel,
|
||||||
|
randomId: deserializeBytes(randomId),
|
||||||
|
option: deserializeBytes(option),
|
||||||
|
}), {
|
||||||
|
shouldThrow: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buildApiSponsoredMessageReportResult(result);
|
||||||
|
} catch (err) {
|
||||||
|
if (err instanceof Error && err.message === 'PREMIUM_ACCOUNT_REQUIRED') {
|
||||||
|
return {
|
||||||
|
type: 'premiumRequired' as const,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -22,7 +22,7 @@ export {
|
|||||||
editTopic, toggleForum, fetchTopicById, createTopic, toggleParticipantsHidden, checkChatlistInvite,
|
editTopic, toggleForum, fetchTopicById, createTopic, toggleParticipantsHidden, checkChatlistInvite,
|
||||||
joinChatlistInvite, createChalistInvite, editChatlistInvite, deleteChatlistInvite, fetchChatlistInvites,
|
joinChatlistInvite, createChalistInvite, editChatlistInvite, deleteChatlistInvite, fetchChatlistInvites,
|
||||||
fetchLeaveChatlistSuggestions, leaveChatlist, togglePeerTranslations, setViewForumAsMessages,
|
fetchLeaveChatlistSuggestions, leaveChatlist, togglePeerTranslations, setViewForumAsMessages,
|
||||||
fetchChannelRecommendations, fetchSavedChats, toggleSavedDialogPinned,
|
fetchChannelRecommendations, fetchSavedChats, toggleSavedDialogPinned, reportSponsoredMessage,
|
||||||
} from './chats';
|
} from './chats';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import type { ThreadId } from '../../types';
|
import type { ThreadId } from '../../types';
|
||||||
import type { ApiWebDocument } from './bots';
|
import type { ApiWebDocument } from './bots';
|
||||||
import type { ApiGroupCall, PhoneCallAction } from './calls';
|
import type { ApiGroupCall, PhoneCallAction } from './calls';
|
||||||
import type { ApiChat } from './chats';
|
import type { ApiChat, ApiPeerColor } from './chats';
|
||||||
import type { ApiInputStorePaymentPurpose, ApiPremiumGiftCodeOption } from './payments';
|
import type { ApiInputStorePaymentPurpose, ApiPremiumGiftCodeOption } from './payments';
|
||||||
import type { ApiMessageStoryData, ApiWebPageStoryData } from './stories';
|
import type { ApiMessageStoryData, ApiWebPageStoryData } from './stories';
|
||||||
|
|
||||||
@ -382,12 +382,6 @@ export interface ApiWebPage {
|
|||||||
story?: ApiWebPageStoryData;
|
story?: ApiWebPageStoryData;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ApiSponsoredWebPage {
|
|
||||||
url: string;
|
|
||||||
siteName: string;
|
|
||||||
photo?: ApiPhoto;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ApiReplyInfo = ApiMessageReplyInfo | ApiStoryReplyInfo;
|
export type ApiReplyInfo = ApiMessageReplyInfo | ApiStoryReplyInfo;
|
||||||
|
|
||||||
export interface ApiMessageReplyInfo {
|
export interface ApiMessageReplyInfo {
|
||||||
@ -685,22 +679,18 @@ export type ApiThreadInfo = ApiCommentsInfo | ApiMessageThreadInfo;
|
|||||||
export type ApiMessageOutgoingStatus = 'read' | 'succeeded' | 'pending' | 'failed';
|
export type ApiMessageOutgoingStatus = 'read' | 'succeeded' | 'pending' | 'failed';
|
||||||
|
|
||||||
export type ApiSponsoredMessage = {
|
export type ApiSponsoredMessage = {
|
||||||
chatId?: string;
|
|
||||||
randomId: string;
|
randomId: string;
|
||||||
isRecommended?: boolean;
|
isRecommended?: true;
|
||||||
isAvatarShown?: boolean;
|
|
||||||
isBot?: boolean;
|
|
||||||
channelPostId?: number;
|
|
||||||
startParam?: string;
|
|
||||||
chatInviteHash?: string;
|
|
||||||
chatInviteTitle?: string;
|
|
||||||
text: ApiFormattedText;
|
text: ApiFormattedText;
|
||||||
webPage?: ApiSponsoredWebPage;
|
|
||||||
expiresAt: number;
|
expiresAt: number;
|
||||||
sponsorInfo?: string;
|
sponsorInfo?: string;
|
||||||
additionalInfo?: string;
|
additionalInfo?: string;
|
||||||
buttonText?: string;
|
buttonText?: string;
|
||||||
botApp?: ApiBotApp;
|
canReport?: true;
|
||||||
|
title: string;
|
||||||
|
url: string;
|
||||||
|
photo?: ApiPhoto;
|
||||||
|
peerColor?: ApiPeerColor;
|
||||||
};
|
};
|
||||||
|
|
||||||
// KeyboardButtons
|
// KeyboardButtons
|
||||||
@ -841,6 +831,17 @@ export type ApiQuickReply = {
|
|||||||
topMessageId: number;
|
topMessageId: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ApiSponsoredMessageReportResult = {
|
||||||
|
type: 'reported' | 'hidden' | 'premiumRequired';
|
||||||
|
} | {
|
||||||
|
type: 'selectOption';
|
||||||
|
title: string;
|
||||||
|
options: {
|
||||||
|
text: string;
|
||||||
|
option: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
|
||||||
export const MAIN_THREAD_ID = -1;
|
export const MAIN_THREAD_ID = -1;
|
||||||
|
|
||||||
// `Symbol` can not be transferred from worker
|
// `Symbol` can not be transferred from worker
|
||||||
|
|||||||
@ -208,6 +208,7 @@ export interface ApiAppConfig {
|
|||||||
bandwidthPremiumNotifyPeriod?: number;
|
bandwidthPremiumNotifyPeriod?: number;
|
||||||
bandwidthPremiumUploadSpeedup?: number;
|
bandwidthPremiumUploadSpeedup?: number;
|
||||||
bandwidthPremiumDownloadSpeedup?: number;
|
bandwidthPremiumDownloadSpeedup?: number;
|
||||||
|
channelRestrictAdsLevelMin?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ApiConfig {
|
export interface ApiConfig {
|
||||||
|
|||||||
@ -53,6 +53,7 @@ export interface ApiUserFullInfo {
|
|||||||
noVoiceMessages?: boolean;
|
noVoiceMessages?: boolean;
|
||||||
premiumGifts?: ApiPremiumGiftOption[];
|
premiumGifts?: ApiPremiumGiftOption[];
|
||||||
isTranslationDisabled?: true;
|
isTranslationDisabled?: true;
|
||||||
|
areAdsEnabled?: boolean;
|
||||||
hasPinnedStories?: boolean;
|
hasPinnedStories?: boolean;
|
||||||
isContactRequirePremium?: boolean;
|
isContactRequirePremium?: boolean;
|
||||||
birthday?: ApiBirthday;
|
birthday?: ApiBirthday;
|
||||||
|
|||||||
1
src/assets/font-icons/nochannel.svg
Normal file
1
src/assets/font-icons/nochannel.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="none"><g clip-path="url(#clip0_427_83808)" transform="matrix(1.66667 0 0 1.66667 -5.667 -4)"><path fill="#000" d="M9.414 7h2.24l4.14-3.253C17.5 2.407 20 3.622 20 5.792v10.916c0 .272-.04.528-.111.767l1.818 1.818a1 1 0 0 1-1.414 1.414l-16-16a1 1 0 0 1 1.414-1.414zm2 2L18 15.586V5.792a.6.6 0 0 0-.97-.472l-4.383 3.443a1.107 1.107 0 0 1-.684.237zM4 11.25c0-1.573.855-2.947 2.125-3.682l1.516 1.515A2.251 2.251 0 0 0 8.25 13.5h3.713c.033 0 .066.002.099.004l5.77 5.77a2.554 2.554 0 0 1-2.038-.522L13 16.558V17a3 3 0 0 1-6 0v-1.687a4.252 4.252 0 0 1-3-4.063zm7 4.25H9V17a1 1 0 0 0 2 0Z"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 660 B |
1
src/assets/font-icons/revenue-split.svg
Normal file
1
src/assets/font-icons/revenue-split.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="none"><path fill="#000" d="M20.313 5.268a1.67 1.67 0 0 1 2.06-1.158 12.455 12.455 0 0 1 2.72 1.13 1.675 1.675 0 0 1 .64 2.278 1.668 1.668 0 0 1-2.273.64 9.117 9.117 0 0 0-1.992-.826 1.674 1.674 0 0 1-1.155-2.064Zm7.223 4.059a1.668 1.668 0 0 1 2.274.64c.482.86.86 1.776 1.127 2.726a1.67 1.67 0 1 1-3.215.905 9.109 9.109 0 0 0-.825-1.993 1.675 1.675 0 0 1 .639-2.278zm2.246 7.987a1.674 1.674 0 0 1 1.155 2.064 12.482 12.482 0 0 1-1.127 2.726 1.668 1.668 0 0 1-2.273.641 1.675 1.675 0 0 1-.64-2.278 9.192 9.192 0 0 0 .825-1.996 1.67 1.67 0 0 1 2.06-1.157zm-4.05 7.238a1.675 1.675 0 0 1-.639 2.278c-.859.483-1.773.863-2.72 1.13a1.674 1.674 0 0 1-.903-3.222 9.065 9.065 0 0 0 1.988-.826 1.668 1.668 0 0 1 2.274.64z" style="stroke-width:1.67169"/><path fill="#000" d="M14.531 1.05C6.936 1.806 1 8.247 1 16.036c0 7.79 5.936 14.23 13.531 14.985 1.73.171 3.172-1.292 3.172-2.936V3.986c0-1.643-1.441-3.107-3.172-2.935zm-.172 3.475v23.02c-5.649-.826-10.015-5.6-10.015-11.51S8.71 5.351 14.359 4.525z" style="stroke-linecap:round;-inkscape-stroke:none"/><path fill="#000" d="M15.361 3.318a1.672 1.672 0 0 0-1.181.49L1.822 16.194a1.672 1.672 0 0 0 .002 2.364 1.672 1.672 0 0 0 2.365-.002L16.547 6.172a1.672 1.672 0 0 0-.004-2.365 1.672 1.672 0 0 0-1.182-.489zm1.849 8.186a1.672 1.672 0 0 0-2.362.004L4.1 22.278a1.672 1.672 0 0 0 .004 2.363 1.672 1.672 0 0 0 2.363-.002l10.748-10.77a1.672 1.672 0 0 0-.004-2.365zm-1.18 7.879a1.672 1.672 0 0 0-1.182.492L8.475 26.26a1.672 1.672 0 0 0 .004 2.365 1.672 1.672 0 0 0 2.363-.002l6.373-6.387a1.672 1.672 0 0 0-.004-2.363 1.672 1.672 0 0 0-1.182-.49z" style="stroke-linecap:round;-inkscape-stroke:none"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.7 KiB |
@ -27,6 +27,7 @@ export { default as GiftCodeModal } from '../components/modals/giftcode/GiftCode
|
|||||||
export { default as ChatlistModal } from '../components/modals/chatlist/ChatlistModal';
|
export { default as ChatlistModal } from '../components/modals/chatlist/ChatlistModal';
|
||||||
|
|
||||||
export { default as AboutAdsModal } from '../components/common/AboutAdsModal';
|
export { default as AboutAdsModal } from '../components/common/AboutAdsModal';
|
||||||
|
export { default as ReportAdModal } from '../components/modals/reportAd/ReportAdModal';
|
||||||
export { default as CalendarModal } from '../components/common/CalendarModal';
|
export { default as CalendarModal } from '../components/common/CalendarModal';
|
||||||
export { default as DeleteMessageModal } from '../components/common/DeleteMessageModal';
|
export { default as DeleteMessageModal } from '../components/common/DeleteMessageModal';
|
||||||
export { default as PinMessageModal } from '../components/common/PinMessageModal';
|
export { default as PinMessageModal } from '../components/common/PinMessageModal';
|
||||||
|
|||||||
35
src/components/common/AboutAdsModal.module.scss
Normal file
35
src/components/common/AboutAdsModal.module.scss
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
.title, .description {
|
||||||
|
text-align: center !important;
|
||||||
|
text-wrap: pretty;
|
||||||
|
padding-inline: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.secondary {
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.separator {
|
||||||
|
margin-block: 1rem;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topIcon {
|
||||||
|
--premium-gradient: linear-gradient(88.39deg, #6C93FF -2.56%, #976FFF 51.27%, #DF69D1 107.39%);
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: var(--premium-gradient);
|
||||||
|
|
||||||
|
font-size: 4rem;
|
||||||
|
color: white;
|
||||||
|
width: 6rem;
|
||||||
|
height: 6rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
@ -1,45 +1,120 @@
|
|||||||
import type { FC } from '../../lib/teact/teact';
|
import type { FC } from '../../lib/teact/teact';
|
||||||
import React, { memo } from '../../lib/teact/teact';
|
import React, { memo, useMemo } from '../../lib/teact/teact';
|
||||||
|
|
||||||
|
import buildClassName from '../../util/buildClassName';
|
||||||
import renderText from './helpers/renderText';
|
import renderText from './helpers/renderText';
|
||||||
|
|
||||||
|
import useDerivedState from '../../hooks/useDerivedState';
|
||||||
import useLang from '../../hooks/useLang';
|
import useLang from '../../hooks/useLang';
|
||||||
|
import useSelectorSignal from '../../hooks/useSelectorSignal';
|
||||||
|
|
||||||
import Button from '../ui/Button';
|
import Button from '../ui/Button';
|
||||||
|
import ListItem from '../ui/ListItem';
|
||||||
import Modal from '../ui/Modal';
|
import Modal from '../ui/Modal';
|
||||||
|
import Separator from '../ui/Separator';
|
||||||
|
import Icon from './Icon';
|
||||||
import SafeLink from './SafeLink';
|
import SafeLink from './SafeLink';
|
||||||
|
|
||||||
|
import styles from './AboutAdsModal.module.scss';
|
||||||
|
|
||||||
export type OwnProps = {
|
export type OwnProps = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
onClose: () => void;
|
isRevenueSharing?: boolean;
|
||||||
|
onClose: NoneToVoidFunction;
|
||||||
};
|
};
|
||||||
|
|
||||||
const AboutAdsModal: FC<OwnProps> = ({
|
const AboutAdsModal: FC<OwnProps> = ({
|
||||||
isOpen,
|
isOpen,
|
||||||
|
isRevenueSharing,
|
||||||
onClose,
|
onClose,
|
||||||
}) => {
|
}) => {
|
||||||
const lang = useLang();
|
const lang = useLang();
|
||||||
|
|
||||||
|
const minLevelSignal = useSelectorSignal((global) => global.appConfig?.channelRestrictAdsLevelMin);
|
||||||
|
const minLevelToRestrictAds = useDerivedState(minLevelSignal);
|
||||||
|
|
||||||
|
const regularAdContent = useMemo(() => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h3>{lang('SponsoredMessageInfoScreen.Title')}</h3>
|
||||||
|
<p>{renderText(lang('SponsoredMessageInfoDescription1'), ['br'])}</p>
|
||||||
|
<p>{renderText(lang('SponsoredMessageInfoDescription2'), ['br'])}</p>
|
||||||
|
<p>{renderText(lang('SponsoredMessageInfoDescription3'), ['br'])}</p>
|
||||||
|
<p>
|
||||||
|
<SafeLink
|
||||||
|
url={lang('SponsoredMessageAlertLearnMoreUrl')}
|
||||||
|
text={lang('SponsoredMessageAlertLearnMoreUrl')}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<p>{renderText(lang('SponsoredMessageInfoDescription4'), ['br'])}</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}, [lang]);
|
||||||
|
|
||||||
|
const revenueSharingAdContent = useMemo(() => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={styles.topIcon}><Icon name="channel" /></div>
|
||||||
|
<h3 className={styles.title}>{lang('AboutRevenueSharingAds')}</h3>
|
||||||
|
<p className={buildClassName(styles.description, styles.secondary)}>
|
||||||
|
{lang('RevenueSharingAdsAlertSubtitle')}
|
||||||
|
</p>
|
||||||
|
<ListItem
|
||||||
|
isStatic
|
||||||
|
multiline
|
||||||
|
icon="lock"
|
||||||
|
>
|
||||||
|
<span className="title">{lang('RevenueSharingAdsInfo1Title')}</span>
|
||||||
|
<span className="subtitle">
|
||||||
|
{renderText(lang('RevenueSharingAdsInfo1Subtitle'), ['simple_markdown'])}
|
||||||
|
</span>
|
||||||
|
</ListItem>
|
||||||
|
<ListItem
|
||||||
|
isStatic
|
||||||
|
multiline
|
||||||
|
icon="revenue-split"
|
||||||
|
>
|
||||||
|
<span className="title">{lang('RevenueSharingAdsInfo2Title')}</span>
|
||||||
|
<span className="subtitle">
|
||||||
|
{renderText(lang('RevenueSharingAdsInfo2Subtitle'), ['simple_markdown'])}
|
||||||
|
</span>
|
||||||
|
</ListItem>
|
||||||
|
<ListItem
|
||||||
|
isStatic
|
||||||
|
multiline
|
||||||
|
icon="nochannel"
|
||||||
|
>
|
||||||
|
<span className="title">{lang('RevenueSharingAdsInfo3Title')}</span>
|
||||||
|
<span className="subtitle">
|
||||||
|
{renderText(lang('RevenueSharingAdsInfo3Subtitle', minLevelToRestrictAds), ['simple_markdown'])}
|
||||||
|
</span>
|
||||||
|
</ListItem>
|
||||||
|
<Separator className={styles.separator} />
|
||||||
|
<h3 className={styles.title}>{renderText(lang('RevenueSharingAdsInfo4Title'), ['simple_markdown'])}</h3>
|
||||||
|
<p className={styles.description}>
|
||||||
|
{renderText(lang('RevenueSharingAdsInfo4Subtitle2', ''), ['simple_markdown'])}
|
||||||
|
<SafeLink
|
||||||
|
url={lang('PromoteUrl')}
|
||||||
|
text={lang('LearnMoreArrow')}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}, [lang, minLevelToRestrictAds]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
|
contentClassName={styles.content}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
hasCloseButton
|
|
||||||
title={lang('SponsoredMessageInfo')}
|
|
||||||
>
|
>
|
||||||
<p>{renderText(lang('SponsoredMessageInfoDescription1'), ['br'])}</p>
|
{isRevenueSharing ? revenueSharingAdContent : regularAdContent}
|
||||||
<p>{renderText(lang('SponsoredMessageInfoDescription2'), ['br'])}</p>
|
<Button
|
||||||
<p>{renderText(lang('SponsoredMessageInfoDescription3'), ['br'])}</p>
|
size="smaller"
|
||||||
<p>
|
onClick={onClose}
|
||||||
<SafeLink
|
>
|
||||||
url={lang('SponsoredMessageAlertLearnMoreUrl')}
|
{lang('RevenueSharingAdsUnderstood')}
|
||||||
text={lang('SponsoredMessageAlertLearnMoreUrl')}
|
</Button>
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
<p>{renderText(lang('SponsoredMessageInfoDescription4'), ['br'])}</p>
|
|
||||||
<div className="dialog-buttons mt-2">
|
|
||||||
<Button className="confirm-dialog-button" isText onClick={onClose}>{lang('Close')}</Button>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
3
src/components/common/PeerColorWrapper.module.scss
Normal file
3
src/components/common/PeerColorWrapper.module.scss
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.root {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
@ -1,30 +1,44 @@
|
|||||||
import React, { memo } from '../../lib/teact/teact';
|
import React, { memo } from '../../lib/teact/teact';
|
||||||
|
|
||||||
import type { ApiPeer } from '../../api/types';
|
import type { ApiPeer, ApiPeerColor } from '../../api/types';
|
||||||
|
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import { getPeerColorClass } from './helpers/peerColor';
|
import { getApiPeerColorClass, getPeerColorClass } from './helpers/peerColor';
|
||||||
|
|
||||||
import EmojiIconBackground from './embedded/EmojiIconBackground';
|
import EmojiIconBackground from './embedded/EmojiIconBackground';
|
||||||
|
|
||||||
type OwnProps = {
|
import styles from './PeerColorWrapper.module.scss';
|
||||||
|
|
||||||
|
interface OwnProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||||
peer?: ApiPeer;
|
peer?: ApiPeer;
|
||||||
|
peerColor?: ApiPeerColor;
|
||||||
noUserColors?: boolean;
|
noUserColors?: boolean;
|
||||||
shoudReset?: boolean;
|
shoudReset?: boolean;
|
||||||
className?: string;
|
className?: string;
|
||||||
emojiIconClassName?: string;
|
emojiIconClassName?: string;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
};
|
}
|
||||||
|
|
||||||
function PeerColorWrapper({
|
function PeerColorWrapper({
|
||||||
peer, noUserColors, shoudReset, className, emojiIconClassName, children,
|
peer, peerColor, noUserColors, shoudReset, className, emojiIconClassName, children, ...otherProps
|
||||||
}: OwnProps) {
|
}: OwnProps) {
|
||||||
|
const color = peerColor || peer?.color;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={buildClassName(getPeerColorClass(peer, noUserColors, shoudReset), className)}>
|
<div
|
||||||
{peer?.color?.backgroundEmojiId && (
|
className={buildClassName(
|
||||||
|
styles.root,
|
||||||
|
peer && getPeerColorClass(peer, noUserColors, shoudReset),
|
||||||
|
peerColor && getApiPeerColorClass(peerColor),
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||||
|
{...otherProps}
|
||||||
|
>
|
||||||
|
{color?.backgroundEmojiId && (
|
||||||
<EmojiIconBackground
|
<EmojiIconBackground
|
||||||
className={emojiIconClassName}
|
className={emojiIconClassName}
|
||||||
emojiDocumentId={peer.color.backgroundEmojiId}
|
emojiDocumentId={color.backgroundEmojiId}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import type { ApiPeer } from '../../../api/types';
|
import type { ApiPeer, ApiPeerColor } from '../../../api/types';
|
||||||
|
|
||||||
import { getPeerColorCount, getPeerColorKey } from '../../../global/helpers';
|
import { getPeerColorCount, getPeerColorKey } from '../../../global/helpers';
|
||||||
|
|
||||||
@ -9,3 +9,7 @@ export function getPeerColorClass(peer?: ApiPeer, noUserColors?: boolean, should
|
|||||||
}
|
}
|
||||||
return noUserColors ? `peer-color-count-${getPeerColorCount(peer)}` : `peer-color-${getPeerColorKey(peer)}`;
|
return noUserColors ? `peer-color-count-${getPeerColorCount(peer)}` : `peer-color-${getPeerColorKey(peer)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getApiPeerColorClass(color: ApiPeerColor) {
|
||||||
|
return `peer-color-${color.color}`;
|
||||||
|
}
|
||||||
|
|||||||
@ -114,7 +114,7 @@ const BusinessHours = ({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isExpanded) return;
|
if (!isExpanded) return;
|
||||||
const slide = document.querySelector<HTMLElement>(`.${ACTIVE_SLIDE_CLASS_NAME} .${styles.timetable}`);
|
const slide = document.querySelector<HTMLElement>(`.${ACTIVE_SLIDE_CLASS_NAME} > .${styles.timetable}`);
|
||||||
if (!slide) return;
|
if (!slide) return;
|
||||||
|
|
||||||
const height = slide.offsetHeight;
|
const height = slide.offsetHeight;
|
||||||
@ -124,7 +124,7 @@ const BusinessHours = ({
|
|||||||
}, [isExpanded]);
|
}, [isExpanded]);
|
||||||
|
|
||||||
const handleAnimationStart = useLastCallback(() => {
|
const handleAnimationStart = useLastCallback(() => {
|
||||||
const slide = document.querySelector<HTMLElement>(`.${TO_SLIDE_CLASS_NAME} .${styles.timetable}`)!;
|
const slide = document.querySelector<HTMLElement>(`.${TO_SLIDE_CLASS_NAME} > .${styles.timetable}`)!;
|
||||||
|
|
||||||
requestMeasure(() => {
|
requestMeasure(() => {
|
||||||
const height = slide.offsetHeight;
|
const height = slide.offsetHeight;
|
||||||
|
|||||||
@ -52,6 +52,7 @@ import {
|
|||||||
selectScrollOffset,
|
selectScrollOffset,
|
||||||
selectTabState,
|
selectTabState,
|
||||||
selectThreadInfo,
|
selectThreadInfo,
|
||||||
|
selectUserFullInfo,
|
||||||
} from '../../global/selectors';
|
} from '../../global/selectors';
|
||||||
import animateScroll, { isAnimatingScroll, restartCurrentScrollAnimation } from '../../util/animateScroll';
|
import animateScroll, { isAnimatingScroll, restartCurrentScrollAnimation } from '../../util/animateScroll';
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
@ -101,7 +102,6 @@ type OwnProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type StateProps = {
|
type StateProps = {
|
||||||
isCurrentUserPremium?: boolean;
|
|
||||||
isChatLoaded?: boolean;
|
isChatLoaded?: boolean;
|
||||||
isChannelChat?: boolean;
|
isChannelChat?: boolean;
|
||||||
isGroupChat?: boolean;
|
isGroupChat?: boolean;
|
||||||
@ -127,6 +127,7 @@ type StateProps = {
|
|||||||
isEmptyThread?: boolean;
|
isEmptyThread?: boolean;
|
||||||
isForum?: boolean;
|
isForum?: boolean;
|
||||||
currentUserId: string;
|
currentUserId: string;
|
||||||
|
areAdsEnabled?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const MESSAGE_REACTIONS_POLLING_INTERVAL = 20 * 1000;
|
const MESSAGE_REACTIONS_POLLING_INTERVAL = 20 * 1000;
|
||||||
@ -150,7 +151,6 @@ const MessageList: FC<OwnProps & StateProps> = ({
|
|||||||
hasTools,
|
hasTools,
|
||||||
onScrollDownToggle,
|
onScrollDownToggle,
|
||||||
onNotchToggle,
|
onNotchToggle,
|
||||||
isCurrentUserPremium,
|
|
||||||
isChatLoaded,
|
isChatLoaded,
|
||||||
isForum,
|
isForum,
|
||||||
isChannelChat,
|
isChannelChat,
|
||||||
@ -184,6 +184,7 @@ const MessageList: FC<OwnProps & StateProps> = ({
|
|||||||
getForceNextPinnedInHeader,
|
getForceNextPinnedInHeader,
|
||||||
onPinnedIntersectionChange,
|
onPinnedIntersectionChange,
|
||||||
isContactRequirePremium,
|
isContactRequirePremium,
|
||||||
|
areAdsEnabled,
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
loadViewportMessages, setScrollOffset, loadSponsoredMessages, loadMessageReactions, copyMessagesByIds,
|
loadViewportMessages, setScrollOffset, loadSponsoredMessages, loadMessageReactions, copyMessagesByIds,
|
||||||
@ -230,10 +231,10 @@ const MessageList: FC<OwnProps & StateProps> = ({
|
|||||||
}, [firstUnreadId]);
|
}, [firstUnreadId]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isCurrentUserPremium && isChannelChat && isSynced && isReady) {
|
if (areAdsEnabled && isChannelChat && isSynced && isReady) {
|
||||||
loadSponsoredMessages({ chatId });
|
loadSponsoredMessages({ chatId });
|
||||||
}
|
}
|
||||||
}, [isCurrentUserPremium, chatId, isSynced, isReady, isChannelChat]);
|
}, [chatId, isSynced, isReady, isChannelChat, areAdsEnabled]);
|
||||||
|
|
||||||
// Updated only once when messages are loaded (as we want the unread divider to keep its position)
|
// Updated only once when messages are loaded (as we want the unread divider to keep its position)
|
||||||
useSyncEffect(() => {
|
useSyncEffect(() => {
|
||||||
@ -633,7 +634,7 @@ const MessageList: FC<OwnProps & StateProps> = ({
|
|||||||
/>
|
/>
|
||||||
) : hasMessages ? (
|
) : hasMessages ? (
|
||||||
<MessageListContent
|
<MessageListContent
|
||||||
isCurrentUserPremium={isCurrentUserPremium}
|
areAdsEnabled={areAdsEnabled}
|
||||||
chatId={chatId}
|
chatId={chatId}
|
||||||
isComments={isComments}
|
isComments={isComments}
|
||||||
isChannelChat={isChannelChat}
|
isChannelChat={isChannelChat}
|
||||||
@ -705,8 +706,11 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
const chatFullInfo = !isUserId(chatId) ? selectChatFullInfo(global, chatId) : undefined;
|
const chatFullInfo = !isUserId(chatId) ? selectChatFullInfo(global, chatId) : undefined;
|
||||||
const isEmptyThread = !selectThreadInfo(global, chatId, threadId)?.messagesCount;
|
const isEmptyThread = !selectThreadInfo(global, chatId, threadId)?.messagesCount;
|
||||||
|
|
||||||
|
const isCurrentUserPremium = selectIsCurrentUserPremium(global);
|
||||||
|
const areAdsEnabled = !isCurrentUserPremium || selectUserFullInfo(global, currentUserId)?.areAdsEnabled;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isCurrentUserPremium: selectIsCurrentUserPremium(global),
|
areAdsEnabled,
|
||||||
isChatLoaded: true,
|
isChatLoaded: true,
|
||||||
isRestricted,
|
isRestricted,
|
||||||
restrictionReason,
|
restrictionReason,
|
||||||
|
|||||||
@ -32,7 +32,7 @@ import SponsoredMessage from './message/SponsoredMessage';
|
|||||||
import MessageListBotInfo from './MessageListBotInfo';
|
import MessageListBotInfo from './MessageListBotInfo';
|
||||||
|
|
||||||
interface OwnProps {
|
interface OwnProps {
|
||||||
isCurrentUserPremium?: boolean;
|
areAdsEnabled?: boolean;
|
||||||
chatId: string;
|
chatId: string;
|
||||||
threadId: ThreadId;
|
threadId: ThreadId;
|
||||||
messageIds: number[];
|
messageIds: number[];
|
||||||
@ -64,7 +64,7 @@ interface OwnProps {
|
|||||||
const UNREAD_DIVIDER_CLASS = 'unread-divider';
|
const UNREAD_DIVIDER_CLASS = 'unread-divider';
|
||||||
|
|
||||||
const MessageListContent: FC<OwnProps> = ({
|
const MessageListContent: FC<OwnProps> = ({
|
||||||
isCurrentUserPremium,
|
areAdsEnabled,
|
||||||
chatId,
|
chatId,
|
||||||
threadId,
|
threadId,
|
||||||
messageIds,
|
messageIds,
|
||||||
@ -290,7 +290,7 @@ const MessageListContent: FC<OwnProps> = ({
|
|||||||
{withHistoryTriggers && <div ref={backwardsTriggerRef} key="backwards-trigger" className="backwards-trigger" />}
|
{withHistoryTriggers && <div ref={backwardsTriggerRef} key="backwards-trigger" className="backwards-trigger" />}
|
||||||
{shouldRenderBotInfo && <MessageListBotInfo isInMessageList key={`bot_info_${chatId}`} chatId={chatId} />}
|
{shouldRenderBotInfo && <MessageListBotInfo isInMessageList key={`bot_info_${chatId}`} chatId={chatId} />}
|
||||||
{dateGroups.flat()}
|
{dateGroups.flat()}
|
||||||
{!isCurrentUserPremium && isViewportNewest && (
|
{areAdsEnabled && isViewportNewest && (
|
||||||
<SponsoredMessage key={chatId} chatId={chatId} containerRef={containerRef} />
|
<SponsoredMessage key={chatId} chatId={chatId} containerRef={containerRef} />
|
||||||
)}
|
)}
|
||||||
{withHistoryTriggers && (
|
{withHistoryTriggers && (
|
||||||
|
|||||||
@ -674,47 +674,43 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-action-button {
|
.message-action-buttons {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
color: white;
|
|
||||||
background-color: var(--pattern-color);
|
background-color: var(--pattern-color);
|
||||||
|
border-radius: 1rem;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: opacity 150ms, backdrop-filter 150ms, filter 150ms;
|
transition: opacity 150ms;
|
||||||
|
|
||||||
@media (pointer: coarse) {
|
@media (pointer: coarse) {
|
||||||
opacity: 1 !important;
|
opacity: 1 !important;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&:hover,
|
.message-action-button {
|
||||||
&:active,
|
color: white;
|
||||||
&:focus {
|
|
||||||
background-color: var(--pattern-color) !important;
|
|
||||||
backdrop-filter: brightness(115%);
|
|
||||||
|
|
||||||
@supports not (backdrop-filter: brightness(115%)) {
|
|
||||||
filter: brightness(115%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover,
|
&:hover,
|
||||||
&[data-is-document-group-hover] {
|
&[data-is-document-group-hover] {
|
||||||
.message-action-button {
|
.message-action-buttons {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-action-button-shown {
|
.message-action-buttons-shown {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.own .message-action-button {
|
&.own .message-action-buttons {
|
||||||
left: -3rem;
|
left: -3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(.own) .message-action-button {
|
&:not(.own) .message-action-buttons {
|
||||||
right: -3rem;
|
right: -3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1389,7 +1389,7 @@ const Message: FC<OwnProps & StateProps> = ({
|
|||||||
/>
|
/>
|
||||||
{!isInDocumentGroup && (
|
{!isInDocumentGroup && (
|
||||||
<div className="message-select-control">
|
<div className="message-select-control">
|
||||||
{isSelected && <i className="icon icon-select" />}
|
{isSelected && <Icon name="select" />}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{isLastInDocumentGroup && (
|
{isLastInDocumentGroup && (
|
||||||
@ -1398,7 +1398,7 @@ const Message: FC<OwnProps & StateProps> = ({
|
|||||||
onClick={handleDocumentGroupSelectAll}
|
onClick={handleDocumentGroupSelectAll}
|
||||||
>
|
>
|
||||||
{isGroupSelected && (
|
{isGroupSelected && (
|
||||||
<i className="icon icon-select" />
|
<Icon name="select" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@ -1419,33 +1419,38 @@ const Message: FC<OwnProps & StateProps> = ({
|
|||||||
)}
|
)}
|
||||||
{renderContent()}
|
{renderContent()}
|
||||||
{!isInDocumentGroupNotLast && metaPosition === 'standalone' && !isStoryMention && renderReactionsAndMeta()}
|
{!isInDocumentGroupNotLast && metaPosition === 'standalone' && !isStoryMention && renderReactionsAndMeta()}
|
||||||
{canShowActionButton && canForward ? (
|
{canShowActionButton && (
|
||||||
<Button
|
<div className={buildClassName(
|
||||||
className={buildClassName(
|
'message-action-buttons',
|
||||||
'message-action-button', isLoadingComments && 'message-action-button-shown',
|
isLoadingComments && 'message-action-buttons-shown',
|
||||||
)}
|
)}
|
||||||
color="translucent-white"
|
|
||||||
round
|
|
||||||
size="tiny"
|
|
||||||
ariaLabel={lang('lng_context_forward_msg')}
|
|
||||||
onClick={isLastInDocumentGroup ? handleGroupForward : handleForward}
|
|
||||||
>
|
>
|
||||||
<i className="icon icon-share-filled" />
|
{canForward && (
|
||||||
</Button>
|
<Button
|
||||||
) : canShowActionButton && canFocus ? (
|
className="message-action-button"
|
||||||
<Button
|
color="translucent-white"
|
||||||
className={buildClassName(
|
round
|
||||||
'message-action-button', isLoadingComments && 'message-action-button-shown',
|
size="tiny"
|
||||||
|
ariaLabel={lang('lng_context_forward_msg')}
|
||||||
|
onClick={isLastInDocumentGroup ? handleGroupForward : handleForward}
|
||||||
|
>
|
||||||
|
<Icon name="share-filled" />
|
||||||
|
</Button>
|
||||||
)}
|
)}
|
||||||
color="translucent-white"
|
{canFocus && (
|
||||||
round
|
<Button
|
||||||
size="tiny"
|
className="message-action-button"
|
||||||
ariaLabel="Focus message"
|
color="translucent-white"
|
||||||
onClick={isPinnedList ? handleFocus : handleFocusForwarded}
|
round
|
||||||
>
|
size="tiny"
|
||||||
<i className="icon icon-arrow-right" />
|
ariaLabel="Focus message"
|
||||||
</Button>
|
onClick={isPinnedList ? handleFocus : handleFocusForwarded}
|
||||||
) : undefined}
|
>
|
||||||
|
<Icon name="arrow-right" />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{withCommentButton && (
|
{withCommentButton && (
|
||||||
<CommentButton
|
<CommentButton
|
||||||
threadInfo={repliesThreadInfo}
|
threadInfo={repliesThreadInfo}
|
||||||
|
|||||||
@ -118,6 +118,7 @@ type OwnProps = {
|
|||||||
onAboutAds?: NoneToVoidFunction;
|
onAboutAds?: NoneToVoidFunction;
|
||||||
onSponsoredHide?: NoneToVoidFunction;
|
onSponsoredHide?: NoneToVoidFunction;
|
||||||
onSponsorInfo?: NoneToVoidFunction;
|
onSponsorInfo?: NoneToVoidFunction;
|
||||||
|
onSponsoredReport?: NoneToVoidFunction;
|
||||||
onTranslate?: NoneToVoidFunction;
|
onTranslate?: NoneToVoidFunction;
|
||||||
onShowOriginal?: NoneToVoidFunction;
|
onShowOriginal?: NoneToVoidFunction;
|
||||||
onSelectLanguage?: NoneToVoidFunction;
|
onSelectLanguage?: NoneToVoidFunction;
|
||||||
@ -207,6 +208,7 @@ const MessageContextMenu: FC<OwnProps> = ({
|
|||||||
onAboutAds,
|
onAboutAds,
|
||||||
onSponsoredHide,
|
onSponsoredHide,
|
||||||
onSponsorInfo,
|
onSponsorInfo,
|
||||||
|
onSponsoredReport,
|
||||||
onReactionPickerOpen,
|
onReactionPickerOpen,
|
||||||
onTranslate,
|
onTranslate,
|
||||||
onShowOriginal,
|
onShowOriginal,
|
||||||
@ -443,9 +445,21 @@ const MessageContextMenu: FC<OwnProps> = ({
|
|||||||
{isSponsoredMessage && message.sponsorInfo && (
|
{isSponsoredMessage && message.sponsorInfo && (
|
||||||
<MenuItem icon="channel" onClick={onSponsorInfo}>{lang('SponsoredMessageSponsor')}</MenuItem>
|
<MenuItem icon="channel" onClick={onSponsorInfo}>{lang('SponsoredMessageSponsor')}</MenuItem>
|
||||||
)}
|
)}
|
||||||
{isSponsoredMessage && <MenuItem icon="help" onClick={onAboutAds}>{lang('SponsoredMessageInfo')}</MenuItem>}
|
{isSponsoredMessage && (
|
||||||
|
<MenuItem icon="info" onClick={onAboutAds}>
|
||||||
|
{lang(message.canReport ? 'AboutRevenueSharingAds' : 'SponsoredMessageInfo')}
|
||||||
|
</MenuItem>
|
||||||
|
)}
|
||||||
|
{isSponsoredMessage && message.canReport && (
|
||||||
|
<MenuItem icon="hand-stop" onClick={onSponsoredReport}>
|
||||||
|
{lang('ReportAd')}
|
||||||
|
</MenuItem>
|
||||||
|
)}
|
||||||
{isSponsoredMessage && onSponsoredHide && (
|
{isSponsoredMessage && onSponsoredHide && (
|
||||||
<MenuItem icon="stop" onClick={onSponsoredHide}>{lang('HideAd')}</MenuItem>
|
<>
|
||||||
|
<MenuSeparator />
|
||||||
|
<MenuItem icon="close-circle" onClick={onSponsoredHide}>{lang('HideAd')}</MenuItem>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
{(canShowSeenBy || canShowReactionsCount) && !isSponsoredMessage && (
|
{(canShowSeenBy || canShowReactionsCount) && !isSponsoredMessage && (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
margin-top: -0.5rem;
|
margin-top: -0.5rem;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
|
z-index: calc(var(--z-sticky-date) + 1);
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
display: none;
|
display: none;
|
||||||
@ -36,26 +37,9 @@
|
|||||||
color: var(--color-text);
|
color: var(--color-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.with-avatar {
|
.message-action-buttons {
|
||||||
padding-left: 2.5rem !important;
|
|
||||||
|
|
||||||
& > .Avatar {
|
|
||||||
display: flex !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@media (max-width: 600px) {
|
|
||||||
padding-left: 2.875rem !important;
|
|
||||||
|
|
||||||
.message-content {
|
|
||||||
max-width: min(29rem, calc(100vw - 7.0625rem)) !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-action-button {
|
|
||||||
bottom: auto !important;
|
bottom: auto !important;
|
||||||
top: 0.5rem;
|
top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-content {
|
.message-content {
|
||||||
@ -67,7 +51,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.channel-avatar {
|
.channel-avatar {
|
||||||
--radius: 0.125rem;
|
--radius: 0.25rem;
|
||||||
|
|
||||||
float: right;
|
float: right;
|
||||||
margin: 0 0 0.5rem 0.5rem;
|
margin: 0 0 0.5rem 0.5rem;
|
||||||
@ -86,7 +70,6 @@
|
|||||||
font-size: calc(var(--message-text-size, 1rem) - 0.125rem);
|
font-size: calc(var(--message-text-size, 1rem) - 0.125rem);
|
||||||
background-color: var(--accent-background-color);
|
background-color: var(--accent-background-color);
|
||||||
border-radius: 0.375rem;
|
border-radius: 0.375rem;
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
@ -131,4 +114,19 @@
|
|||||||
.svg-appendix {
|
.svg-appendix {
|
||||||
transform: translate(0.01875rem, -0.00625rem);
|
transform: translate(0.01875rem, -0.00625rem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ad-about {
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
margin-inline-start: 0.25rem;
|
||||||
|
border-radius: 1rem;
|
||||||
|
padding-inline: 0.375rem;
|
||||||
|
transition: 150ms filter ease-in;
|
||||||
|
background: var(--accent-background-active-color);
|
||||||
|
cursor: var(--custom-cursor, pointer);
|
||||||
|
filter: opacity(0.8);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
filter: opacity(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,23 +1,16 @@
|
|||||||
import type { MouseEvent as ReactMouseEvent, RefObject } from 'react';
|
import type { RefObject } from 'react';
|
||||||
import type { FC } from '../../../lib/teact/teact';
|
import type { FC } from '../../../lib/teact/teact';
|
||||||
import React, { memo, useEffect, useRef } from '../../../lib/teact/teact';
|
import React, { memo, useEffect, useRef } from '../../../lib/teact/teact';
|
||||||
import { getActions, withGlobal } from '../../../global';
|
import { getActions, withGlobal } from '../../../global';
|
||||||
|
|
||||||
import type {
|
import type { ApiSponsoredMessage } from '../../../api/types';
|
||||||
ApiChat, ApiSponsoredMessage, ApiUser,
|
|
||||||
} from '../../../api/types';
|
|
||||||
|
|
||||||
import { getChatTitle, getUserFullName } from '../../../global/helpers';
|
import { selectSponsoredMessage } from '../../../global/selectors';
|
||||||
import { selectChat, selectSponsoredMessage, selectUser } from '../../../global/selectors';
|
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import { extractCurrentThemeParams } from '../../../util/themeStyle';
|
import { IS_ANDROID } from '../../../util/windowEnvironment';
|
||||||
import { IS_ANDROID, IS_TOUCH_ENV } from '../../../util/windowEnvironment';
|
|
||||||
import { getPeerColorClass } from '../../common/helpers/peerColor';
|
|
||||||
import renderText from '../../common/helpers/renderText';
|
|
||||||
import { renderTextWithEntities } from '../../common/helpers/renderTextWithEntities';
|
import { renderTextWithEntities } from '../../common/helpers/renderTextWithEntities';
|
||||||
import { preventMessageInputBlur } from '../helpers/preventMessageInputBlur';
|
import { preventMessageInputBlur } from '../helpers/preventMessageInputBlur';
|
||||||
|
|
||||||
import useAppLayout from '../../../hooks/useAppLayout';
|
|
||||||
import useContextMenuHandlers from '../../../hooks/useContextMenuHandlers';
|
import useContextMenuHandlers from '../../../hooks/useContextMenuHandlers';
|
||||||
import useFlag from '../../../hooks/useFlag';
|
import useFlag from '../../../hooks/useFlag';
|
||||||
import { useIntersectionObserver } from '../../../hooks/useIntersectionObserver';
|
import { useIntersectionObserver } from '../../../hooks/useIntersectionObserver';
|
||||||
@ -26,6 +19,8 @@ import useLastCallback from '../../../hooks/useLastCallback';
|
|||||||
|
|
||||||
import AboutAdsModal from '../../common/AboutAdsModal.async';
|
import AboutAdsModal from '../../common/AboutAdsModal.async';
|
||||||
import Avatar from '../../common/Avatar';
|
import Avatar from '../../common/Avatar';
|
||||||
|
import Icon from '../../common/Icon';
|
||||||
|
import PeerColorWrapper from '../../common/PeerColorWrapper';
|
||||||
import Button from '../../ui/Button';
|
import Button from '../../ui/Button';
|
||||||
import MessageAppendix from './MessageAppendix';
|
import MessageAppendix from './MessageAppendix';
|
||||||
import SponsoredMessageContextMenuContainer from './SponsoredMessageContextMenuContainer.async';
|
import SponsoredMessageContextMenuContainer from './SponsoredMessageContextMenuContainer.async';
|
||||||
@ -39,31 +34,21 @@ type OwnProps = {
|
|||||||
|
|
||||||
type StateProps = {
|
type StateProps = {
|
||||||
message?: ApiSponsoredMessage;
|
message?: ApiSponsoredMessage;
|
||||||
peer?: ApiChat;
|
|
||||||
bot?: ApiUser;
|
|
||||||
channel?: ApiChat;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const INTERSECTION_DEBOUNCE_MS = 200;
|
const INTERSECTION_DEBOUNCE_MS = 200;
|
||||||
|
|
||||||
const SponsoredMessage: FC<OwnProps & StateProps> = ({
|
const SponsoredMessage: FC<OwnProps & StateProps> = ({
|
||||||
chatId,
|
chatId,
|
||||||
peer,
|
|
||||||
message,
|
message,
|
||||||
containerRef,
|
containerRef,
|
||||||
bot,
|
|
||||||
channel,
|
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
viewSponsoredMessage,
|
viewSponsoredMessage,
|
||||||
openChat,
|
|
||||||
openChatByInvite,
|
|
||||||
requestAppWebView,
|
|
||||||
startBot,
|
|
||||||
focusMessage,
|
|
||||||
openUrl,
|
openUrl,
|
||||||
openPremiumModal,
|
hideSponsoredMessages,
|
||||||
clickSponsoredMessage,
|
clickSponsoredMessage,
|
||||||
|
reportSponsoredMessage,
|
||||||
} = getActions();
|
} = getActions();
|
||||||
|
|
||||||
const lang = useLang();
|
const lang = useLang();
|
||||||
@ -83,11 +68,8 @@ const SponsoredMessage: FC<OwnProps & StateProps> = ({
|
|||||||
isContextMenuOpen, contextMenuPosition,
|
isContextMenuOpen, contextMenuPosition,
|
||||||
handleBeforeContextMenu, handleContextMenu,
|
handleBeforeContextMenu, handleContextMenu,
|
||||||
handleContextMenuClose, handleContextMenuHide,
|
handleContextMenuClose, handleContextMenuHide,
|
||||||
} = useContextMenuHandlers(ref, IS_TOUCH_ENV, true, IS_ANDROID);
|
} = useContextMenuHandlers(ref, undefined, true, IS_ANDROID);
|
||||||
const [isAboutAdsModalOpen, openAboutAdsModal, closeAboutAdsModal] = useFlag(false);
|
const [isAboutAdsModalOpen, openAboutAdsModal, closeAboutAdsModal] = useFlag(false);
|
||||||
const { isMobile } = useAppLayout();
|
|
||||||
const withAvatar = Boolean(message?.isAvatarShown && peer);
|
|
||||||
const isBotApp = Boolean(message?.botApp);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return shouldObserve ? observeIntersection(contentRef.current!, (target) => {
|
return shouldObserve ? observeIntersection(contentRef.current!, (target) => {
|
||||||
@ -102,146 +84,30 @@ const SponsoredMessage: FC<OwnProps & StateProps> = ({
|
|||||||
handleBeforeContextMenu(e);
|
handleBeforeContextMenu(e);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAvatarClick = useLastCallback(() => {
|
const handleReportSponsoredMessage = useLastCallback(() => {
|
||||||
if (!peer) {
|
reportSponsoredMessage({ chatId, randomId: message!.randomId });
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
openChat({ id: peer.id });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleLinkClick = useLastCallback((e: ReactMouseEvent<HTMLButtonElement, MouseEvent>) => {
|
const handleHideSponsoredMessage = useLastCallback(() => {
|
||||||
e.preventDefault();
|
hideSponsoredMessages();
|
||||||
|
|
||||||
clickSponsoredMessage({ chatId });
|
|
||||||
openUrl({ url: message!.webPage!.url, shouldSkipModal: true });
|
|
||||||
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleCloseSponsoredMessage = useLastCallback(() => {
|
|
||||||
openPremiumModal();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleClick = useLastCallback(() => {
|
const handleClick = useLastCallback(() => {
|
||||||
if (!message) return;
|
if (!message) return;
|
||||||
|
|
||||||
clickSponsoredMessage({ chatId });
|
clickSponsoredMessage({ chatId });
|
||||||
|
openUrl({ url: message!.url, shouldSkipModal: true });
|
||||||
if (isBotApp) {
|
|
||||||
const { shortName } = message.botApp!;
|
|
||||||
const theme = extractCurrentThemeParams();
|
|
||||||
|
|
||||||
requestAppWebView({
|
|
||||||
botId: message.chatId!,
|
|
||||||
appName: shortName,
|
|
||||||
startApp: message.startParam,
|
|
||||||
theme,
|
|
||||||
});
|
|
||||||
} else if (message.chatInviteHash) {
|
|
||||||
openChatByInvite({ hash: message.chatInviteHash });
|
|
||||||
} else if (message.channelPostId) {
|
|
||||||
focusMessage({ chatId: message.chatId!, messageId: message.channelPostId });
|
|
||||||
} else {
|
|
||||||
openChat({ id: message.chatId });
|
|
||||||
|
|
||||||
if (message.startParam) {
|
|
||||||
startBot({
|
|
||||||
botId: message.chatId!,
|
|
||||||
param: message.startParam,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!message) {
|
if (!message) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderAvatar() {
|
|
||||||
return (
|
|
||||||
<Avatar
|
|
||||||
size={isMobile ? 'small-mobile' : 'small'}
|
|
||||||
peer={peer}
|
|
||||||
onClick={peer ? handleAvatarClick : undefined}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderPhoto() {
|
|
||||||
if (message?.botApp) {
|
|
||||||
if (!message.botApp.photo) return undefined;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Avatar
|
|
||||||
size="large"
|
|
||||||
peer={bot}
|
|
||||||
photo={message.botApp.photo}
|
|
||||||
className={buildClassName('channel-avatar', lang.isRtl && 'is-rtl')}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (channel) {
|
|
||||||
return (
|
|
||||||
<Avatar
|
|
||||||
size="large"
|
|
||||||
peer={channel}
|
|
||||||
className={buildClassName('channel-avatar', lang.isRtl && 'is-rtl')}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderContent() {
|
function renderContent() {
|
||||||
if (message?.webPage) {
|
if (!message) return undefined;
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className="text-content with-meta" dir="auto" ref={contentRef}>
|
|
||||||
<div className="message-title message-peer" dir="ltr">
|
|
||||||
{renderText(message.webPage.siteName)}
|
|
||||||
</div>
|
|
||||||
<span className="text-content-inner" dir="auto">
|
|
||||||
{renderTextWithEntities({
|
|
||||||
text: message!.text.text,
|
|
||||||
entities: message!.text.entities,
|
|
||||||
})}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
className="SponsoredMessage__button"
|
|
||||||
size="tiny"
|
|
||||||
color="translucent"
|
|
||||||
isRectangular
|
|
||||||
onClick={handleLinkClick}
|
|
||||||
>
|
|
||||||
<i className="icon icon-arrow-right" aria-hidden />
|
|
||||||
{lang('OpenLink')}
|
|
||||||
</Button>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const buttonText = message?.buttonText ?? (
|
|
||||||
isBotApp
|
|
||||||
? lang('BotWebAppInstantViewOpen')
|
|
||||||
: (message!.isBot
|
|
||||||
? lang('Conversation.ViewBot')
|
|
||||||
: lang(message!.channelPostId ? 'Conversation.ViewPost' : 'Conversation.ViewChannel')
|
|
||||||
));
|
|
||||||
const title = isBotApp
|
|
||||||
? message!.botApp!.title
|
|
||||||
: (bot
|
|
||||||
? renderText(getUserFullName(bot) || '')
|
|
||||||
: (channel ? renderText(message!.chatInviteTitle || getChatTitle(lang, channel) || '') : '')
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="message-title message-peer" dir="auto">{title}</div>
|
<div className="message-title message-peer" dir="auto">{message.title}</div>
|
||||||
<div className="text-content with-meta" dir="auto" ref={contentRef}>
|
<div className="text-content with-meta" dir="auto" ref={contentRef}>
|
||||||
<span className="text-content-inner" dir="auto">
|
<span className="text-content-inner" dir="auto">
|
||||||
{renderTextWithEntities({
|
{renderTextWithEntities({
|
||||||
@ -258,48 +124,64 @@ const SponsoredMessage: FC<OwnProps & StateProps> = ({
|
|||||||
isRectangular
|
isRectangular
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
>
|
>
|
||||||
{buttonText}
|
{message.buttonText}
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const contentClassName = buildClassName(
|
|
||||||
'message-content has-shadow has-solid-background has-appendix',
|
|
||||||
getPeerColorClass(bot || peer || channel),
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={ref}
|
||||||
key="sponsored-message"
|
key="sponsored-message"
|
||||||
className={buildClassName('SponsoredMessage Message open', withAvatar && 'with-avatar')}
|
className="SponsoredMessage Message open"
|
||||||
>
|
>
|
||||||
{withAvatar && renderAvatar()}
|
|
||||||
<div
|
<div
|
||||||
className={contentClassName}
|
className="message-content has-shadow has-solid-background has-appendix"
|
||||||
dir="auto"
|
dir="auto"
|
||||||
onMouseDown={handleMouseDown}
|
onMouseDown={handleMouseDown}
|
||||||
onContextMenu={handleContextMenu}
|
onContextMenu={handleContextMenu}
|
||||||
>
|
>
|
||||||
<div className="content-inner" dir="auto">
|
<PeerColorWrapper peerColor={message.peerColor} className="content-inner" dir="auto">
|
||||||
{renderPhoto()}
|
{message.photo && (
|
||||||
|
<Avatar
|
||||||
|
size="large"
|
||||||
|
photo={message.photo}
|
||||||
|
className={buildClassName('channel-avatar', lang.isRtl && 'is-rtl')}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<span className="message-title message-type">
|
<span className="message-title message-type">
|
||||||
{message!.isRecommended ? lang('Message.RecommendedLabel') : lang('SponsoredMessage')}
|
{message!.isRecommended ? lang('Message.RecommendedLabel') : lang('SponsoredMessage')}
|
||||||
|
<span onClick={openAboutAdsModal} className="ad-about">{lang('SponsoredMessageAdWhatIsThis')}</span>
|
||||||
</span>
|
</span>
|
||||||
{renderContent()}
|
{renderContent()}
|
||||||
</div>
|
</PeerColorWrapper>
|
||||||
<MessageAppendix />
|
<MessageAppendix />
|
||||||
<Button
|
<div className="message-action-buttons">
|
||||||
className="message-action-button"
|
<Button
|
||||||
color="translucent-white"
|
className="message-action-button"
|
||||||
round
|
color="translucent-white"
|
||||||
size="tiny"
|
round
|
||||||
ariaLabel={lang('Close')}
|
size="tiny"
|
||||||
onClick={handleCloseSponsoredMessage}
|
ariaLabel={lang('Close')}
|
||||||
>
|
onClick={handleHideSponsoredMessage}
|
||||||
<i className="icon icon-close" aria-hidden />
|
>
|
||||||
</Button>
|
<Icon name="close" />
|
||||||
|
</Button>
|
||||||
|
{message.canReport && (
|
||||||
|
<Button
|
||||||
|
className="message-action-button"
|
||||||
|
color="translucent-white"
|
||||||
|
round
|
||||||
|
size="tiny"
|
||||||
|
ariaLabel={lang('More')}
|
||||||
|
onClick={handleContextMenu}
|
||||||
|
onContextMenu={handleContextMenu}
|
||||||
|
>
|
||||||
|
<Icon name="more" />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{contextMenuPosition && (
|
{contextMenuPosition && (
|
||||||
<SponsoredMessageContextMenuContainer
|
<SponsoredMessageContextMenuContainer
|
||||||
@ -307,12 +189,14 @@ const SponsoredMessage: FC<OwnProps & StateProps> = ({
|
|||||||
anchor={contextMenuPosition}
|
anchor={contextMenuPosition}
|
||||||
message={message!}
|
message={message!}
|
||||||
onAboutAds={openAboutAdsModal}
|
onAboutAds={openAboutAdsModal}
|
||||||
|
onReportAd={handleReportSponsoredMessage}
|
||||||
onClose={handleContextMenuClose}
|
onClose={handleContextMenuClose}
|
||||||
onCloseAnimationEnd={handleContextMenuHide}
|
onCloseAnimationEnd={handleContextMenuHide}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<AboutAdsModal
|
<AboutAdsModal
|
||||||
isOpen={isAboutAdsModalOpen}
|
isOpen={isAboutAdsModalOpen}
|
||||||
|
isRevenueSharing={message.canReport}
|
||||||
onClose={closeAboutAdsModal}
|
onClose={closeAboutAdsModal}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -322,14 +206,9 @@ const SponsoredMessage: FC<OwnProps & StateProps> = ({
|
|||||||
export default memo(withGlobal<OwnProps>(
|
export default memo(withGlobal<OwnProps>(
|
||||||
(global, { chatId }): StateProps => {
|
(global, { chatId }): StateProps => {
|
||||||
const message = selectSponsoredMessage(global, chatId);
|
const message = selectSponsoredMessage(global, chatId);
|
||||||
const peer = message?.chatId ? selectChat(global, message?.chatId) : undefined;
|
|
||||||
const { chatId: fromChatId, isBot } = message || {};
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
message,
|
message,
|
||||||
peer,
|
|
||||||
bot: fromChatId && isBot ? selectUser(global, fromChatId) : undefined,
|
|
||||||
channel: !isBot && fromChatId ? selectChat(global, fromChatId) : undefined,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
)(SponsoredMessage));
|
)(SponsoredMessage));
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
import type { FC } from '../../../lib/teact/teact';
|
import type { FC } from '../../../lib/teact/teact';
|
||||||
import React, { memo } from '../../../lib/teact/teact';
|
import React, { memo } from '../../../lib/teact/teact';
|
||||||
import { getActions, withGlobal } from '../../../global';
|
import { getActions } from '../../../global';
|
||||||
|
|
||||||
import type { ApiSponsoredMessage } from '../../../api/types';
|
import type { ApiSponsoredMessage } from '../../../api/types';
|
||||||
import type { IAnchorPosition } from '../../../types';
|
import type { IAnchorPosition } from '../../../types';
|
||||||
|
|
||||||
import { selectIsCurrentUserPremium, selectIsPremiumPurchaseBlocked } from '../../../global/selectors';
|
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
|
|
||||||
import useFlag from '../../../hooks/useFlag';
|
import useFlag from '../../../hooks/useFlag';
|
||||||
@ -18,22 +17,19 @@ export type OwnProps = {
|
|||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
message: ApiSponsoredMessage;
|
message: ApiSponsoredMessage;
|
||||||
anchor: IAnchorPosition;
|
anchor: IAnchorPosition;
|
||||||
onAboutAds: () => void;
|
onAboutAds: NoneToVoidFunction;
|
||||||
onClose: () => void;
|
onReportAd: NoneToVoidFunction;
|
||||||
onCloseAnimationEnd: () => void;
|
onClose: NoneToVoidFunction;
|
||||||
|
onCloseAnimationEnd: NoneToVoidFunction;
|
||||||
};
|
};
|
||||||
|
|
||||||
type StateProps = {
|
const SponsoredMessageContextMenuContainer: FC<OwnProps> = ({
|
||||||
canBuyPremium?: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
const SponsoredMessageContextMenuContainer: FC<OwnProps & StateProps> = ({
|
|
||||||
message,
|
message,
|
||||||
anchor,
|
anchor,
|
||||||
onAboutAds,
|
onAboutAds,
|
||||||
|
onReportAd,
|
||||||
onClose,
|
onClose,
|
||||||
onCloseAnimationEnd,
|
onCloseAnimationEnd,
|
||||||
canBuyPremium,
|
|
||||||
}) => {
|
}) => {
|
||||||
const { openPremiumModal, showDialog } = getActions();
|
const { openPremiumModal, showDialog } = getActions();
|
||||||
|
|
||||||
@ -60,6 +56,11 @@ const SponsoredMessageContextMenuContainer: FC<OwnProps & StateProps> = ({
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const handleReportSponsoredMessage = useLastCallback(() => {
|
||||||
|
closeMenu();
|
||||||
|
onReportAd();
|
||||||
|
});
|
||||||
|
|
||||||
if (!anchor) {
|
if (!anchor) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@ -73,17 +74,12 @@ const SponsoredMessageContextMenuContainer: FC<OwnProps & StateProps> = ({
|
|||||||
onClose={closeMenu}
|
onClose={closeMenu}
|
||||||
onCloseAnimationEnd={closeMenu}
|
onCloseAnimationEnd={closeMenu}
|
||||||
onAboutAds={handleAboutAdsOpen}
|
onAboutAds={handleAboutAdsOpen}
|
||||||
onSponsoredHide={canBuyPremium ? handleSponsoredHide : undefined}
|
onSponsoredHide={handleSponsoredHide}
|
||||||
onSponsorInfo={handleSponsorInfo}
|
onSponsorInfo={handleSponsorInfo}
|
||||||
|
onSponsoredReport={handleReportSponsoredMessage}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default memo(withGlobal<OwnProps>(
|
export default memo(SponsoredMessageContextMenuContainer);
|
||||||
(global): StateProps => {
|
|
||||||
return {
|
|
||||||
canBuyPremium: !selectIsCurrentUserPremium(global) && !selectIsPremiumPurchaseBlocked(global),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
)(SponsoredMessageContextMenuContainer));
|
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import ChatlistModal from './chatlist/ChatlistModal.async';
|
|||||||
import GiftCodeModal from './giftcode/GiftCodeModal.async';
|
import GiftCodeModal from './giftcode/GiftCodeModal.async';
|
||||||
import InviteViaLinkModal from './inviteViaLink/InviteViaLinkModal.async';
|
import InviteViaLinkModal from './inviteViaLink/InviteViaLinkModal.async';
|
||||||
import OneTimeMediaModal from './oneTimeMedia/OneTimeMediaModal.async';
|
import OneTimeMediaModal from './oneTimeMedia/OneTimeMediaModal.async';
|
||||||
|
import ReportAdModal from './reportAd/ReportAdModal.async';
|
||||||
import UrlAuthModal from './urlAuth/UrlAuthModal.async';
|
import UrlAuthModal from './urlAuth/UrlAuthModal.async';
|
||||||
import WebAppModal from './webApp/WebAppModal.async';
|
import WebAppModal from './webApp/WebAppModal.async';
|
||||||
|
|
||||||
@ -24,6 +25,7 @@ type ModalKey = keyof Pick<TabState,
|
|||||||
'oneTimeMediaModal' |
|
'oneTimeMediaModal' |
|
||||||
'inviteViaLinkModal' |
|
'inviteViaLinkModal' |
|
||||||
'requestedAttachBotInstall' |
|
'requestedAttachBotInstall' |
|
||||||
|
'reportAdModal' |
|
||||||
'webApp'
|
'webApp'
|
||||||
>;
|
>;
|
||||||
|
|
||||||
@ -47,6 +49,7 @@ const MODALS: ModalRegistry = {
|
|||||||
oneTimeMediaModal: OneTimeMediaModal,
|
oneTimeMediaModal: OneTimeMediaModal,
|
||||||
inviteViaLinkModal: InviteViaLinkModal,
|
inviteViaLinkModal: InviteViaLinkModal,
|
||||||
requestedAttachBotInstall: AttachBotInstallModal,
|
requestedAttachBotInstall: AttachBotInstallModal,
|
||||||
|
reportAdModal: ReportAdModal,
|
||||||
webApp: WebAppModal,
|
webApp: WebAppModal,
|
||||||
};
|
};
|
||||||
const MODAL_KEYS = Object.keys(MODALS) as ModalKey[];
|
const MODAL_KEYS = Object.keys(MODALS) as ModalKey[];
|
||||||
|
|||||||
18
src/components/modals/reportAd/ReportAdModal.async.tsx
Normal file
18
src/components/modals/reportAd/ReportAdModal.async.tsx
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import type { FC } from '../../../lib/teact/teact';
|
||||||
|
import React from '../../../lib/teact/teact';
|
||||||
|
|
||||||
|
import type { OwnProps } from './ReportAdModal';
|
||||||
|
|
||||||
|
import { Bundles } from '../../../util/moduleLoader';
|
||||||
|
|
||||||
|
import useModuleLoader from '../../../hooks/useModuleLoader';
|
||||||
|
|
||||||
|
const ReportAdModalAsync: FC<OwnProps> = (props) => {
|
||||||
|
const { modal } = props;
|
||||||
|
const ReportAdModal = useModuleLoader(Bundles.Extra, 'ReportAdModal', !modal);
|
||||||
|
|
||||||
|
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||||
|
return ReportAdModal ? <ReportAdModal {...props} /> : undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ReportAdModalAsync;
|
||||||
54
src/components/modals/reportAd/ReportAdModal.module.scss
Normal file
54
src/components/modals/reportAd/ReportAdModal.module.scss
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
.slide { // Do not remove .slide, identifier used in JS
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modalTitle {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.optionText {
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option {
|
||||||
|
margin-bottom: 0.25rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.optionButton {
|
||||||
|
padding-block: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sectionTitle {
|
||||||
|
color: var(--color-primary);
|
||||||
|
padding-inline: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
margin-top: 0.75rem;
|
||||||
|
margin-bottom: 0;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
padding-inline: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.titleMultiline > .title {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.transition {
|
||||||
|
/* stylelint-disable-next-line plugin/no-low-performance-animation-properties */
|
||||||
|
transition: height 0.25s ease-in-out;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
157
src/components/modals/reportAd/ReportAdModal.tsx
Normal file
157
src/components/modals/reportAd/ReportAdModal.tsx
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
import React, {
|
||||||
|
memo, useEffect, useMemo, useRef,
|
||||||
|
} from '../../../lib/teact/teact';
|
||||||
|
import { getActions } from '../../../global';
|
||||||
|
|
||||||
|
import type { TabState } from '../../../global/types';
|
||||||
|
|
||||||
|
import { requestMeasure, requestMutation } from '../../../lib/fasterdom/fasterdom';
|
||||||
|
import buildClassName from '../../../util/buildClassName';
|
||||||
|
|
||||||
|
import useLang from '../../../hooks/useLang';
|
||||||
|
import useLastCallback from '../../../hooks/useLastCallback';
|
||||||
|
|
||||||
|
import Icon from '../../common/Icon';
|
||||||
|
import SafeLink from '../../common/SafeLink';
|
||||||
|
import Button from '../../ui/Button';
|
||||||
|
import ListItem from '../../ui/ListItem';
|
||||||
|
import Modal from '../../ui/Modal';
|
||||||
|
import Transition, { ACTIVE_SLIDE_CLASS_NAME, TO_SLIDE_CLASS_NAME } from '../../ui/Transition';
|
||||||
|
|
||||||
|
import styles from './ReportAdModal.module.scss';
|
||||||
|
|
||||||
|
const ADDED_PADDING = 40;
|
||||||
|
|
||||||
|
export type OwnProps = {
|
||||||
|
modal: TabState['reportAdModal'];
|
||||||
|
};
|
||||||
|
|
||||||
|
const ReportAdModal = ({
|
||||||
|
modal,
|
||||||
|
}: OwnProps) => {
|
||||||
|
const {
|
||||||
|
reportSponsoredMessage, closeReportAdModal, openPreviousReportAdModal,
|
||||||
|
} = getActions();
|
||||||
|
const lang = useLang();
|
||||||
|
const isOpen = Boolean(modal);
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-null/no-null
|
||||||
|
const transitionRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
const handleOptionClick = useLastCallback((e, option: string) => {
|
||||||
|
const { chatId, randomId } = modal!;
|
||||||
|
reportSponsoredMessage({ chatId, randomId, option });
|
||||||
|
});
|
||||||
|
|
||||||
|
const [renderingSection, renderingDepth] = useMemo(() => {
|
||||||
|
if (!modal) return [undefined, 0];
|
||||||
|
const sectionDepth = modal.sections.length - 1;
|
||||||
|
return [modal.sections[sectionDepth], sectionDepth];
|
||||||
|
}, [modal]);
|
||||||
|
|
||||||
|
const handleBackClick = useLastCallback(() => {
|
||||||
|
if (!renderingDepth) {
|
||||||
|
closeReportAdModal();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
openPreviousReportAdModal();
|
||||||
|
});
|
||||||
|
|
||||||
|
const bottomText = useMemo(() => {
|
||||||
|
if (!modal) return undefined;
|
||||||
|
const template = lang('lng_report_sponsored_reported_learn');
|
||||||
|
const parts = template.split('{link}');
|
||||||
|
return [
|
||||||
|
parts[0],
|
||||||
|
<SafeLink text={lang('lng_report_sponsored_reported_link')} url={lang('ReportAd.Help_URL')} />,
|
||||||
|
parts[1],
|
||||||
|
];
|
||||||
|
}, [lang, modal]);
|
||||||
|
|
||||||
|
const header = useMemo(() => {
|
||||||
|
if (!modal) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasSubtitle = Boolean(renderingSection?.subtitle);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="modal-header-condensed">
|
||||||
|
<Button
|
||||||
|
round
|
||||||
|
color="translucent"
|
||||||
|
size="smaller"
|
||||||
|
ariaLabel={lang(renderingDepth ? 'Back' : 'Close')}
|
||||||
|
onClick={handleBackClick}
|
||||||
|
>
|
||||||
|
<Icon name={renderingDepth ? 'arrow-left' : 'close'} />
|
||||||
|
</Button>
|
||||||
|
<div className={buildClassName('modal-title', styles.modalTitle, hasSubtitle && styles.titleMultiline)}>
|
||||||
|
<h3 className={styles.title}>{lang('ReportAd')}</h3>
|
||||||
|
{hasSubtitle && (
|
||||||
|
<span className={styles.subtitle}>{renderingSection.subtitle}</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}, [lang, modal, renderingDepth, renderingSection?.subtitle]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!modal) return;
|
||||||
|
const slide = document.querySelector<HTMLElement>(`.${ACTIVE_SLIDE_CLASS_NAME} > .${styles.slide}`);
|
||||||
|
if (!slide) return;
|
||||||
|
|
||||||
|
const height = slide.scrollHeight;
|
||||||
|
requestMutation(() => {
|
||||||
|
transitionRef.current!.style.height = `${height + ADDED_PADDING}px`;
|
||||||
|
});
|
||||||
|
}, [modal]);
|
||||||
|
|
||||||
|
const handleAnimationStart = useLastCallback(() => {
|
||||||
|
const slide = document.querySelector<HTMLElement>(`.${TO_SLIDE_CLASS_NAME} > .${styles.slide}`)!;
|
||||||
|
|
||||||
|
requestMeasure(() => {
|
||||||
|
const height = slide.scrollHeight;
|
||||||
|
requestMutation(() => {
|
||||||
|
transitionRef.current!.style.height = `${height + ADDED_PADDING}px`;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
isOpen={isOpen}
|
||||||
|
hasCloseButton
|
||||||
|
header={header}
|
||||||
|
onClose={closeReportAdModal}
|
||||||
|
>
|
||||||
|
<Transition
|
||||||
|
name="slide"
|
||||||
|
className={styles.transition}
|
||||||
|
ref={transitionRef}
|
||||||
|
activeKey={renderingDepth}
|
||||||
|
onStart={handleAnimationStart}
|
||||||
|
>
|
||||||
|
<div className={styles.slide}>
|
||||||
|
<h3 className={styles.sectionTitle}>{renderingSection?.title}</h3>
|
||||||
|
{renderingSection?.options.map((option) => (
|
||||||
|
<ListItem
|
||||||
|
narrow
|
||||||
|
secondaryIcon="next"
|
||||||
|
className={styles.option}
|
||||||
|
buttonClassName={styles.optionButton}
|
||||||
|
clickArg={option.option}
|
||||||
|
onClick={handleOptionClick}
|
||||||
|
>
|
||||||
|
<div className={styles.optionText}>{option.text}</div>
|
||||||
|
</ListItem>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<p className={styles.description}>{bottomText}</p>
|
||||||
|
</Transition>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(ReportAdModal);
|
||||||
@ -7,7 +7,7 @@ import useLang from '../../hooks/useLang';
|
|||||||
import styles from './Separator.module.scss';
|
import styles from './Separator.module.scss';
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
children: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
className?: string;
|
className?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -49,7 +49,7 @@ export const MEDIA_PROGRESSIVE_CACHE_DISABLED = false;
|
|||||||
export const MEDIA_PROGRESSIVE_CACHE_NAME = 'tt-media-progressive';
|
export const MEDIA_PROGRESSIVE_CACHE_NAME = 'tt-media-progressive';
|
||||||
export const MEDIA_CACHE_MAX_BYTES = 512 * 1024; // 512 KB
|
export const MEDIA_CACHE_MAX_BYTES = 512 * 1024; // 512 KB
|
||||||
export const CUSTOM_BG_CACHE_NAME = 'tt-custom-bg';
|
export const CUSTOM_BG_CACHE_NAME = 'tt-custom-bg';
|
||||||
export const LANG_CACHE_NAME = 'tt-lang-packs-v34';
|
export const LANG_CACHE_NAME = 'tt-lang-packs-v35';
|
||||||
export const ASSET_CACHE_NAME = 'tt-assets';
|
export const ASSET_CACHE_NAME = 'tt-assets';
|
||||||
export const AUTODOWNLOAD_FILESIZE_MB_LIMITS = [1, 5, 10, 50, 100, 500];
|
export const AUTODOWNLOAD_FILESIZE_MB_LIMITS = [1, 5, 10, 50, 100, 500];
|
||||||
export const DATA_BROADCAST_CHANNEL_NAME = 'tt-global';
|
export const DATA_BROADCAST_CHANNEL_NAME = 'tt-global';
|
||||||
|
|||||||
@ -67,6 +67,7 @@ import {
|
|||||||
addChatMessagesById,
|
addChatMessagesById,
|
||||||
addChats,
|
addChats,
|
||||||
addUsers,
|
addUsers,
|
||||||
|
deleteSponsoredMessage,
|
||||||
removeOutlyingList,
|
removeOutlyingList,
|
||||||
removeRequestedMessageTranslation,
|
removeRequestedMessageTranslation,
|
||||||
replaceSettings,
|
replaceSettings,
|
||||||
@ -90,6 +91,7 @@ import {
|
|||||||
updateThreadUnreadFromForwardedMessage,
|
updateThreadUnreadFromForwardedMessage,
|
||||||
updateTopic,
|
updateTopic,
|
||||||
updateUploadByMessageKey,
|
updateUploadByMessageKey,
|
||||||
|
updateUserFullInfo,
|
||||||
updateUsers,
|
updateUsers,
|
||||||
} from '../../reducers';
|
} from '../../reducers';
|
||||||
import { updateTabState } from '../../reducers/tabs';
|
import { updateTabState } from '../../reducers/tabs';
|
||||||
@ -1548,6 +1550,79 @@ addActionHandler('clickSponsoredMessage', (global, actions, payload): ActionRetu
|
|||||||
void callApi('clickSponsoredMessage', { chat, random: message.randomId });
|
void callApi('clickSponsoredMessage', { chat, random: message.randomId });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
addActionHandler('reportSponsoredMessage', async (global, actions, payload): Promise<void> => {
|
||||||
|
const {
|
||||||
|
chatId, randomId, option = '', tabId = getCurrentTabId(),
|
||||||
|
} = payload;
|
||||||
|
const chat = selectChat(global, chatId);
|
||||||
|
if (!chat) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await callApi('reportSponsoredMessage', { chat, randomId, option });
|
||||||
|
|
||||||
|
if (!result) return;
|
||||||
|
|
||||||
|
if (result.type === 'premiumRequired') {
|
||||||
|
actions.openPremiumModal({ initialSection: 'no_ads', tabId });
|
||||||
|
actions.closeReportAdModal({ tabId });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.type === 'reported' || result.type === 'hidden') {
|
||||||
|
actions.showNotification({
|
||||||
|
message: translate(result.type === 'reported' ? 'AdReported' : 'AdHidden'),
|
||||||
|
tabId,
|
||||||
|
});
|
||||||
|
actions.closeReportAdModal({ tabId });
|
||||||
|
|
||||||
|
global = getGlobal();
|
||||||
|
global = deleteSponsoredMessage(global, chatId);
|
||||||
|
setGlobal(global);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.type === 'selectOption') {
|
||||||
|
global = getGlobal();
|
||||||
|
const oldSections = selectTabState(global, tabId).reportAdModal?.sections;
|
||||||
|
const selectedOption = oldSections?.[oldSections.length - 1]?.options.find((o) => o.option === option);
|
||||||
|
const newSection = {
|
||||||
|
title: result.title,
|
||||||
|
options: result.options,
|
||||||
|
subtitle: selectedOption?.text,
|
||||||
|
};
|
||||||
|
global = updateTabState(global, {
|
||||||
|
reportAdModal: {
|
||||||
|
chatId,
|
||||||
|
randomId,
|
||||||
|
sections: oldSections ? [...oldSections, newSection] : [newSection],
|
||||||
|
},
|
||||||
|
}, tabId);
|
||||||
|
setGlobal(global);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
addActionHandler('hideSponsoredMessages', async (global, actions, payload): Promise<void> => {
|
||||||
|
const { tabId = getCurrentTabId() } = payload || {};
|
||||||
|
const isCurrentUserPremium = selectIsCurrentUserPremium(global);
|
||||||
|
if (!isCurrentUserPremium) {
|
||||||
|
actions.openPremiumModal({ initialSection: 'no_ads', tabId });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await callApi('toggleSponsoredMessages', { enabled: false });
|
||||||
|
if (!result) return;
|
||||||
|
global = getGlobal();
|
||||||
|
global = updateUserFullInfo(global, global.currentUserId!, {
|
||||||
|
areAdsEnabled: false,
|
||||||
|
});
|
||||||
|
setGlobal(global);
|
||||||
|
actions.showNotification({
|
||||||
|
message: translate('AdHidden'),
|
||||||
|
tabId,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
addActionHandler('fetchUnreadMentions', async (global, actions, payload): Promise<void> => {
|
addActionHandler('fetchUnreadMentions', async (global, actions, payload): Promise<void> => {
|
||||||
const { chatId, offsetId } = payload;
|
const { chatId, offsetId } = payload;
|
||||||
await fetchUnreadMentions(global, chatId, offsetId);
|
await fetchUnreadMentions(global, chatId, offsetId);
|
||||||
|
|||||||
@ -863,6 +863,33 @@ addActionHandler('closeOneTimeMediaModal', (global, actions, payload): ActionRet
|
|||||||
setGlobal(global);
|
setGlobal(global);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
addActionHandler('closeReportAdModal', (global, actions, payload): ActionReturnType => {
|
||||||
|
const { tabId = getCurrentTabId() } = payload || {};
|
||||||
|
return updateTabState(global, {
|
||||||
|
reportAdModal: undefined,
|
||||||
|
}, tabId);
|
||||||
|
});
|
||||||
|
|
||||||
|
addActionHandler('openPreviousReportAdModal', (global, actions, payload): ActionReturnType => {
|
||||||
|
const { tabId = getCurrentTabId() } = payload || {};
|
||||||
|
const reportAdModal = selectTabState(global, tabId).reportAdModal;
|
||||||
|
if (!reportAdModal) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reportAdModal.sections.length === 1) {
|
||||||
|
actions.closeReportAdModal({ tabId });
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return updateTabState(global, {
|
||||||
|
reportAdModal: {
|
||||||
|
...reportAdModal,
|
||||||
|
sections: reportAdModal.sections.slice(0, -1),
|
||||||
|
},
|
||||||
|
}, tabId);
|
||||||
|
});
|
||||||
|
|
||||||
function copyTextForMessages(global: GlobalState, chatId: string, messageIds: number[]) {
|
function copyTextForMessages(global: GlobalState, chatId: string, messageIds: number[]) {
|
||||||
const { type: messageListType, threadId } = selectCurrentMessageList(global) || {};
|
const { type: messageListType, threadId } = selectCurrentMessageList(global) || {};
|
||||||
const lang = langProvider.translate;
|
const lang = langProvider.translate;
|
||||||
|
|||||||
@ -671,6 +671,23 @@ export function updateSponsoredMessage<T extends GlobalState>(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function deleteSponsoredMessage<T extends GlobalState>(
|
||||||
|
global: T, chatId: string,
|
||||||
|
): T {
|
||||||
|
const byChatId = global.messages.sponsoredByChatId;
|
||||||
|
if (!byChatId[chatId]) {
|
||||||
|
return global;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...global,
|
||||||
|
messages: {
|
||||||
|
...global.messages,
|
||||||
|
sponsoredByChatId: omit(byChatId, [chatId]),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function updateFocusDirection<T extends GlobalState>(
|
export function updateFocusDirection<T extends GlobalState>(
|
||||||
global: T, direction?: FocusDirection,
|
global: T, direction?: FocusDirection,
|
||||||
...[tabId = getCurrentTabId()]: TabArgs<T>
|
...[tabId = getCurrentTabId()]: TabArgs<T>
|
||||||
|
|||||||
@ -533,6 +533,19 @@ export type TabState = {
|
|||||||
openedStickerSetShortName?: string;
|
openedStickerSetShortName?: string;
|
||||||
openedCustomEmojiSetIds?: string[];
|
openedCustomEmojiSetIds?: string[];
|
||||||
|
|
||||||
|
reportAdModal?: {
|
||||||
|
chatId: string;
|
||||||
|
randomId: string;
|
||||||
|
sections: {
|
||||||
|
title: string;
|
||||||
|
subtitle?: string;
|
||||||
|
options: {
|
||||||
|
text: string;
|
||||||
|
option: string;
|
||||||
|
}[];
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
|
||||||
activeDownloads: {
|
activeDownloads: {
|
||||||
byChatId: {
|
byChatId: {
|
||||||
[chatId: string]: {
|
[chatId: string]: {
|
||||||
@ -1465,6 +1478,14 @@ export interface ActionPayloads {
|
|||||||
clickSponsoredMessage: {
|
clickSponsoredMessage: {
|
||||||
chatId: string;
|
chatId: string;
|
||||||
};
|
};
|
||||||
|
reportSponsoredMessage: {
|
||||||
|
chatId: string;
|
||||||
|
randomId: string;
|
||||||
|
option?: string;
|
||||||
|
} & WithTabId;
|
||||||
|
openPreviousReportAdModal: WithTabId | undefined;
|
||||||
|
closeReportAdModal: WithTabId | undefined;
|
||||||
|
hideSponsoredMessages: WithTabId | undefined;
|
||||||
loadSendAs: {
|
loadSendAs: {
|
||||||
chatId: string;
|
chatId: string;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
const api = require('./api');
|
const api = require('./api');
|
||||||
|
|
||||||
const LAYER = 177;
|
const LAYER = 178;
|
||||||
const tlobjects = {};
|
const tlobjects = {};
|
||||||
|
|
||||||
for (const tl of Object.values(api)) {
|
for (const tl of Object.values(api)) {
|
||||||
|
|||||||
129
src/lib/gramjs/tl/api.d.ts
vendored
129
src/lib/gramjs/tl/api.d.ts
vendored
File diff suppressed because one or more lines are too long
@ -80,8 +80,8 @@ chat#41cbf256 flags:# creator:flags.0?true left:flags.2?true deactivated:flags.5
|
|||||||
chatForbidden#6592a1a7 id:long title:string = Chat;
|
chatForbidden#6592a1a7 id:long title:string = Chat;
|
||||||
channel#aadfc8f flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true gigagroup:flags.26?true noforwards:flags.27?true join_to_send:flags.28?true join_request:flags.29?true forum:flags.30?true flags2:# stories_hidden:flags2.1?true stories_hidden_min:flags2.2?true stories_unavailable:flags2.3?true id:long access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int restriction_reason:flags.9?Vector<RestrictionReason> admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int usernames:flags2.0?Vector<Username> stories_max_id:flags2.4?int color:flags2.7?PeerColor profile_color:flags2.8?PeerColor emoji_status:flags2.9?EmojiStatus level:flags2.10?int = Chat;
|
channel#aadfc8f flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true gigagroup:flags.26?true noforwards:flags.27?true join_to_send:flags.28?true join_request:flags.29?true forum:flags.30?true flags2:# stories_hidden:flags2.1?true stories_hidden_min:flags2.2?true stories_unavailable:flags2.3?true id:long access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int restriction_reason:flags.9?Vector<RestrictionReason> admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int usernames:flags2.0?Vector<Username> stories_max_id:flags2.4?int color:flags2.7?PeerColor profile_color:flags2.8?PeerColor emoji_status:flags2.9?EmojiStatus level:flags2.10?int = Chat;
|
||||||
channelForbidden#17d493d5 flags:# broadcast:flags.5?true megagroup:flags.8?true id:long access_hash:long title:string until_date:flags.16?int = Chat;
|
channelForbidden#17d493d5 flags:# broadcast:flags.5?true megagroup:flags.8?true id:long access_hash:long title:string until_date:flags.16?int = Chat;
|
||||||
chatFull#c9d31138 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true translations_disabled:flags.19?true id:long about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string requests_pending:flags.17?int recent_requesters:flags.17?Vector<long> available_reactions:flags.18?ChatReactions = ChatFull;
|
chatFull#2633421b 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 reactions_limit:flags.20?int = ChatFull;
|
||||||
channelFull#44c054a7 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags2.0?true antispam:flags2.1?true participants_hidden:flags2.2?true translations_disabled:flags2.3?true stories_pinned_available:flags2.5?true view_forum_as_messages:flags2.6?true restricted_sponsored:flags2.11?true can_view_revenue:flags2.12?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector<string> groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector<long> default_send_as:flags.29?Peer available_reactions:flags.30?ChatReactions stories:flags2.4?PeerStories wallpaper:flags2.7?WallPaper boosts_applied:flags2.8?int boosts_unrestrict:flags2.9?int emojiset:flags2.10?StickerSet = ChatFull;
|
channelFull#bbab348d 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 restricted_sponsored:flags2.11?true can_view_revenue:flags2.12?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 reactions_limit:flags2.13?int stories:flags2.4?PeerStories wallpaper:flags2.7?WallPaper boosts_applied:flags2.8?int boosts_unrestrict:flags2.9?int emojiset:flags2.10?StickerSet = ChatFull;
|
||||||
chatParticipant#c02d4007 user_id:long inviter_id:long date:int = ChatParticipant;
|
chatParticipant#c02d4007 user_id:long inviter_id:long date:int = ChatParticipant;
|
||||||
chatParticipantCreator#e46bcee4 user_id:long = ChatParticipant;
|
chatParticipantCreator#e46bcee4 user_id:long = ChatParticipant;
|
||||||
chatParticipantAdmin#a0933f5b user_id:long inviter_id:long date:int = ChatParticipant;
|
chatParticipantAdmin#a0933f5b user_id:long inviter_id:long date:int = ChatParticipant;
|
||||||
@ -188,7 +188,7 @@ inputReportReasonGeoIrrelevant#dbd4feed = ReportReason;
|
|||||||
inputReportReasonFake#f5ddd6e7 = ReportReason;
|
inputReportReasonFake#f5ddd6e7 = ReportReason;
|
||||||
inputReportReasonIllegalDrugs#a8eb2be = ReportReason;
|
inputReportReasonIllegalDrugs#a8eb2be = ReportReason;
|
||||||
inputReportReasonPersonalDetails#9ec7863d = ReportReason;
|
inputReportReasonPersonalDetails#9ec7863d = ReportReason;
|
||||||
userFull#cc997720 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true voice_messages_forbidden:flags.20?true translations_disabled:flags.23?true stories_pinned_available:flags.26?true blocked_my_stories_from:flags.27?true wallpaper_overridden:flags.28?true contact_require_premium:flags.29?true read_dates_private:flags.30?true flags2:# id:long about:flags.1?string settings:PeerSettings personal_photo:flags.21?Photo profile_photo:flags.2?Photo fallback_photo:flags.22?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme_emoticon:flags.15?string private_forward_name:flags.16?string bot_group_admin_rights:flags.17?ChatAdminRights bot_broadcast_admin_rights:flags.18?ChatAdminRights premium_gifts:flags.19?Vector<PremiumGiftOption> wallpaper:flags.24?WallPaper stories:flags.25?PeerStories business_work_hours:flags2.0?BusinessWorkHours business_location:flags2.1?BusinessLocation business_greeting_message:flags2.2?BusinessGreetingMessage business_away_message:flags2.3?BusinessAwayMessage business_intro:flags2.4?BusinessIntro birthday:flags2.5?Birthday personal_channel_id:flags2.6?long personal_channel_message:flags2.6?int = UserFull;
|
userFull#cc997720 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true voice_messages_forbidden:flags.20?true translations_disabled:flags.23?true stories_pinned_available:flags.26?true blocked_my_stories_from:flags.27?true wallpaper_overridden:flags.28?true contact_require_premium:flags.29?true read_dates_private:flags.30?true flags2:# sponsored_enabled:flags2.7?true id:long about:flags.1?string settings:PeerSettings personal_photo:flags.21?Photo profile_photo:flags.2?Photo fallback_photo:flags.22?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme_emoticon:flags.15?string private_forward_name:flags.16?string bot_group_admin_rights:flags.17?ChatAdminRights bot_broadcast_admin_rights:flags.18?ChatAdminRights premium_gifts:flags.19?Vector<PremiumGiftOption> wallpaper:flags.24?WallPaper stories:flags.25?PeerStories business_work_hours:flags2.0?BusinessWorkHours business_location:flags2.1?BusinessLocation business_greeting_message:flags2.2?BusinessGreetingMessage business_away_message:flags2.3?BusinessAwayMessage business_intro:flags2.4?BusinessIntro birthday:flags2.5?Birthday personal_channel_id:flags2.6?long personal_channel_message:flags2.6?int = UserFull;
|
||||||
contact#145ade0b user_id:long mutual:Bool = Contact;
|
contact#145ade0b user_id:long mutual:Bool = Contact;
|
||||||
importedContact#c13e3c50 user_id:long client_id:long = ImportedContact;
|
importedContact#c13e3c50 user_id:long client_id:long = ImportedContact;
|
||||||
contactStatus#16d9703b user_id:long status:UserStatus = ContactStatus;
|
contactStatus#16d9703b user_id:long status:UserStatus = ContactStatus;
|
||||||
@ -359,6 +359,7 @@ updateBotBusinessConnect#8ae5c97a connection:BotBusinessConnection qts:int = Upd
|
|||||||
updateBotNewBusinessMessage#9ddb347c flags:# connection_id:string message:Message reply_to_message:flags.0?Message qts:int = Update;
|
updateBotNewBusinessMessage#9ddb347c flags:# connection_id:string message:Message reply_to_message:flags.0?Message qts:int = Update;
|
||||||
updateBotEditBusinessMessage#7df587c flags:# connection_id:string message:Message reply_to_message:flags.0?Message qts:int = Update;
|
updateBotEditBusinessMessage#7df587c flags:# connection_id:string message:Message reply_to_message:flags.0?Message qts:int = Update;
|
||||||
updateBotDeleteBusinessMessage#a02a982e connection_id:string peer:Peer messages:Vector<int> qts:int = Update;
|
updateBotDeleteBusinessMessage#a02a982e connection_id:string peer:Peer messages:Vector<int> qts:int = Update;
|
||||||
|
updateNewStoryReaction#1824e40b story_id:int peer:Peer reaction:Reaction = Update;
|
||||||
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
|
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.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;
|
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;
|
||||||
@ -927,7 +928,7 @@ inputWallPaperSlug#72091c80 slug:string = InputWallPaper;
|
|||||||
inputWallPaperNoFile#967a462e id:long = InputWallPaper;
|
inputWallPaperNoFile#967a462e id:long = InputWallPaper;
|
||||||
account.wallPapersNotModified#1c199183 = account.WallPapers;
|
account.wallPapersNotModified#1c199183 = account.WallPapers;
|
||||||
account.wallPapers#cdc3858c hash:long wallpapers:Vector<WallPaper> = 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;
|
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 unknown_number:flags.9?true logout_tokens:flags.6?Vector<bytes> token:flags.8?string app_sandbox:flags.8?Bool = CodeSettings;
|
||||||
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;
|
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;
|
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;
|
account.autoDownloadSettings#63cacf26 low:AutoDownloadSettings medium:AutoDownloadSettings high:AutoDownloadSettings = account.AutoDownloadSettings;
|
||||||
@ -967,6 +968,7 @@ inputThemeSettings#8fde504f flags:# message_colors_animated:flags.2?true base_th
|
|||||||
themeSettings#fa58b6d4 flags:# message_colors_animated:flags.2?true base_theme:BaseTheme accent_color:int outbox_accent_color:flags.3?int message_colors:flags.0?Vector<int> wallpaper:flags.1?WallPaper = ThemeSettings;
|
themeSettings#fa58b6d4 flags:# message_colors_animated:flags.2?true base_theme:BaseTheme accent_color:int outbox_accent_color:flags.3?int message_colors:flags.0?Vector<int> wallpaper:flags.1?WallPaper = ThemeSettings;
|
||||||
webPageAttributeTheme#54b56617 flags:# documents:flags.0?Vector<Document> settings:flags.1?ThemeSettings = WebPageAttribute;
|
webPageAttributeTheme#54b56617 flags:# documents:flags.0?Vector<Document> settings:flags.1?ThemeSettings = WebPageAttribute;
|
||||||
webPageAttributeStory#2e94c3e7 flags:# peer:Peer id:int story:flags.0?StoryItem = WebPageAttribute;
|
webPageAttributeStory#2e94c3e7 flags:# peer:Peer id:int story:flags.0?StoryItem = WebPageAttribute;
|
||||||
|
webPageAttributeStickerSet#50cc03d3 flags:# emojis:flags.0?true text_color:flags.1?true stickers:Vector<Document> = WebPageAttribute;
|
||||||
messages.votesList#4899484e flags:# count:int votes:Vector<MessagePeerVote> chats:Vector<Chat> users:Vector<User> next_offset:flags.0?string = messages.VotesList;
|
messages.votesList#4899484e flags:# count:int votes:Vector<MessagePeerVote> chats:Vector<Chat> users:Vector<User> next_offset:flags.0?string = messages.VotesList;
|
||||||
bankCardOpenUrl#f568028a url:string name:string = BankCardOpenUrl;
|
bankCardOpenUrl#f568028a url:string name:string = BankCardOpenUrl;
|
||||||
payments.bankCardData#3e24e573 title:string open_urls:Vector<BankCardOpenUrl> = payments.BankCardData;
|
payments.bankCardData#3e24e573 title:string open_urls:Vector<BankCardOpenUrl> = payments.BankCardData;
|
||||||
@ -1041,7 +1043,7 @@ botCommandScopePeerUser#a1321f3 peer:InputPeer user_id:InputUser = BotCommandSco
|
|||||||
account.resetPasswordFailedWait#e3779861 retry_date:int = account.ResetPasswordResult;
|
account.resetPasswordFailedWait#e3779861 retry_date:int = account.ResetPasswordResult;
|
||||||
account.resetPasswordRequestedWait#e9effc7d until_date:int = account.ResetPasswordResult;
|
account.resetPasswordRequestedWait#e9effc7d until_date:int = account.ResetPasswordResult;
|
||||||
account.resetPasswordOk#e926d63e = account.ResetPasswordResult;
|
account.resetPasswordOk#e926d63e = account.ResetPasswordResult;
|
||||||
sponsoredMessage#ed5383f7 flags:# recommended:flags.5?true show_peer_photo:flags.6?true can_report:flags.12?true random_id:bytes from_id:flags.3?Peer chat_invite:flags.4?ChatInvite chat_invite_hash:flags.4?string channel_post:flags.2?int start_param:flags.0?string webpage:flags.9?SponsoredWebPage app:flags.10?BotApp message:string entities:flags.1?Vector<MessageEntity> button_text:flags.11?string sponsor_info:flags.7?string additional_info:flags.8?string = SponsoredMessage;
|
sponsoredMessage#bdedf566 flags:# recommended:flags.5?true can_report:flags.12?true random_id:bytes url:string title:string message:string entities:flags.1?Vector<MessageEntity> photo:flags.6?Photo color:flags.13?PeerColor button_text:string sponsor_info:flags.7?string additional_info:flags.8?string = SponsoredMessage;
|
||||||
messages.sponsoredMessages#c9ee1d87 flags:# posts_between:flags.0?int messages:Vector<SponsoredMessage> chats:Vector<Chat> users:Vector<User> = messages.SponsoredMessages;
|
messages.sponsoredMessages#c9ee1d87 flags:# posts_between:flags.0?int messages:Vector<SponsoredMessage> chats:Vector<Chat> users:Vector<User> = messages.SponsoredMessages;
|
||||||
messages.sponsoredMessagesEmpty#1839490f = messages.SponsoredMessages;
|
messages.sponsoredMessagesEmpty#1839490f = messages.SponsoredMessages;
|
||||||
searchResultsCalendarPeriod#c9b0539f date:int min_msg_id:int max_msg_id:int count:int = SearchResultsCalendarPeriod;
|
searchResultsCalendarPeriod#c9b0539f date:int min_msg_id:int max_msg_id:int count:int = SearchResultsCalendarPeriod;
|
||||||
@ -1165,14 +1167,13 @@ bots.botInfo#e8a775b0 name:string about:string description:string = bots.BotInfo
|
|||||||
messagePeerVote#b6cc2d5c peer:Peer option:bytes date:int = MessagePeerVote;
|
messagePeerVote#b6cc2d5c peer:Peer option:bytes date:int = MessagePeerVote;
|
||||||
messagePeerVoteInputOption#74cda504 peer:Peer date:int = MessagePeerVote;
|
messagePeerVoteInputOption#74cda504 peer:Peer date:int = MessagePeerVote;
|
||||||
messagePeerVoteMultiple#4628f6e6 peer:Peer options:Vector<bytes> date:int = MessagePeerVote;
|
messagePeerVoteMultiple#4628f6e6 peer:Peer options:Vector<bytes> date:int = MessagePeerVote;
|
||||||
sponsoredWebPage#3db8ec63 flags:# url:string site_name:string photo:flags.0?Photo = SponsoredWebPage;
|
|
||||||
storyViews#8d595cd6 flags:# has_viewers:flags.1?true views_count:int forwards_count:flags.2?int reactions:flags.3?Vector<ReactionCount> reactions_count:flags.4?int recent_viewers:flags.0?Vector<long> = StoryViews;
|
storyViews#8d595cd6 flags:# has_viewers:flags.1?true views_count:int forwards_count:flags.2?int reactions:flags.3?Vector<ReactionCount> reactions_count:flags.4?int recent_viewers:flags.0?Vector<long> = StoryViews;
|
||||||
storyItemDeleted#51e6ee4f id:int = StoryItem;
|
storyItemDeleted#51e6ee4f id:int = StoryItem;
|
||||||
storyItemSkipped#ffadc913 flags:# close_friends:flags.8?true id:int date:int expire_date:int = StoryItem;
|
storyItemSkipped#ffadc913 flags:# close_friends:flags.8?true id:int date:int expire_date:int = StoryItem;
|
||||||
storyItem#79b26a24 flags:# pinned:flags.5?true public:flags.7?true close_friends:flags.8?true min:flags.9?true noforwards:flags.10?true edited:flags.11?true contacts:flags.12?true selected_contacts:flags.13?true out:flags.16?true id:int date:int from_id:flags.18?Peer fwd_from:flags.17?StoryFwdHeader expire_date:int caption:flags.0?string entities:flags.1?Vector<MessageEntity> media:MessageMedia media_areas:flags.14?Vector<MediaArea> privacy:flags.2?Vector<PrivacyRule> views:flags.3?StoryViews sent_reaction:flags.15?Reaction = StoryItem;
|
storyItem#79b26a24 flags:# pinned:flags.5?true public:flags.7?true close_friends:flags.8?true min:flags.9?true noforwards:flags.10?true edited:flags.11?true contacts:flags.12?true selected_contacts:flags.13?true out:flags.16?true id:int date:int from_id:flags.18?Peer fwd_from:flags.17?StoryFwdHeader expire_date:int caption:flags.0?string entities:flags.1?Vector<MessageEntity> media:MessageMedia media_areas:flags.14?Vector<MediaArea> privacy:flags.2?Vector<PrivacyRule> views:flags.3?StoryViews sent_reaction:flags.15?Reaction = StoryItem;
|
||||||
stories.allStoriesNotModified#1158fe3e flags:# state:string stealth_mode:StoriesStealthMode = stories.AllStories;
|
stories.allStoriesNotModified#1158fe3e flags:# state:string stealth_mode:StoriesStealthMode = stories.AllStories;
|
||||||
stories.allStories#6efc5e81 flags:# has_more:flags.0?true count:int state:string peer_stories:Vector<PeerStories> chats:Vector<Chat> users:Vector<User> stealth_mode:StoriesStealthMode = stories.AllStories;
|
stories.allStories#6efc5e81 flags:# has_more:flags.0?true count:int state:string peer_stories:Vector<PeerStories> chats:Vector<Chat> users:Vector<User> stealth_mode:StoriesStealthMode = stories.AllStories;
|
||||||
stories.stories#5dd8c3c8 count:int stories:Vector<StoryItem> chats:Vector<Chat> users:Vector<User> = stories.Stories;
|
stories.stories#63c3dd0a flags:# count:int stories:Vector<StoryItem> pinned_to_top:flags.0?Vector<int> 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;
|
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;
|
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;
|
storyViewPublicRepost#bd74cf49 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true peer_id:Peer story:StoryItem = StoryView;
|
||||||
@ -1284,6 +1285,9 @@ broadcastRevenueTransactionProceeds#557e2cc4 amount:long from_date:int to_date:i
|
|||||||
broadcastRevenueTransactionWithdrawal#5a590978 flags:# pending:flags.0?true failed:flags.2?true amount:long date:int provider:string transaction_date:flags.1?int transaction_url:flags.1?string = BroadcastRevenueTransaction;
|
broadcastRevenueTransactionWithdrawal#5a590978 flags:# pending:flags.0?true failed:flags.2?true amount:long date:int provider:string transaction_date:flags.1?int transaction_url:flags.1?string = BroadcastRevenueTransaction;
|
||||||
broadcastRevenueTransactionRefund#42d30d2e amount:long date:int provider:string = BroadcastRevenueTransaction;
|
broadcastRevenueTransactionRefund#42d30d2e amount:long date:int provider:string = BroadcastRevenueTransaction;
|
||||||
stats.broadcastRevenueTransactions#87158466 count:int transactions:Vector<BroadcastRevenueTransaction> = stats.BroadcastRevenueTransactions;
|
stats.broadcastRevenueTransactions#87158466 count:int transactions:Vector<BroadcastRevenueTransaction> = stats.BroadcastRevenueTransactions;
|
||||||
|
reactionNotificationsFromContacts#bac3a61a = ReactionNotificationsFrom;
|
||||||
|
reactionNotificationsFromAll#4b9e22a0 = ReactionNotificationsFrom;
|
||||||
|
reactionsNotifySettings#56e34970 flags:# messages_notify_from:flags.0?ReactionNotificationsFrom stories_notify_from:flags.1?ReactionNotificationsFrom sound:NotificationSound show_previews:Bool = ReactionsNotifySettings;
|
||||||
---functions---
|
---functions---
|
||||||
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
|
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;
|
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;
|
||||||
@ -1345,6 +1349,7 @@ account.getRecentEmojiStatuses#f578105 hash:long = account.EmojiStatuses;
|
|||||||
account.reorderUsernames#ef500eab order:Vector<string> = Bool;
|
account.reorderUsernames#ef500eab order:Vector<string> = Bool;
|
||||||
account.toggleUsername#58d6b376 username:string active:Bool = Bool;
|
account.toggleUsername#58d6b376 username:string active:Bool = Bool;
|
||||||
account.resolveBusinessChatLink#5492e5ee slug:string = account.ResolvedBusinessChatLinks;
|
account.resolveBusinessChatLink#5492e5ee slug:string = account.ResolvedBusinessChatLinks;
|
||||||
|
account.toggleSponsoredMessages#b9d9a38d enabled:Bool = Bool;
|
||||||
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
|
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
|
||||||
users.getFullUser#b60f5918 id:InputUser = users.UserFull;
|
users.getFullUser#b60f5918 id:InputUser = users.UserFull;
|
||||||
contacts.getContacts#5dd69e12 hash:long = contacts.Contacts;
|
contacts.getContacts#5dd69e12 hash:long = contacts.Contacts;
|
||||||
@ -1395,7 +1400,7 @@ messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool;
|
|||||||
messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates;
|
messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates;
|
||||||
messages.getMessagesViews#5784d3e1 peer:InputPeer id:Vector<int> increment:Bool = messages.MessageViews;
|
messages.getMessagesViews#5784d3e1 peer:InputPeer id:Vector<int> increment:Bool = messages.MessageViews;
|
||||||
messages.migrateChat#a2875319 chat_id:long = Updates;
|
messages.migrateChat#a2875319 chat_id:long = Updates;
|
||||||
messages.searchGlobal#4bc6589a flags:# folder_id:flags.0?int q:string filter:MessagesFilter min_date:int max_date:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
|
messages.searchGlobal#4bc6589a flags:# broadcasts_only:flags.1?true folder_id:flags.0?int q:string filter:MessagesFilter min_date:int max_date:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
|
||||||
messages.getDocumentByHash#b1f2061f sha256:bytes size:long mime_type:string = Document;
|
messages.getDocumentByHash#b1f2061f sha256:bytes size:long mime_type:string = Document;
|
||||||
messages.getSavedGifs#5cf09635 hash:long = messages.SavedGifs;
|
messages.getSavedGifs#5cf09635 hash:long = messages.SavedGifs;
|
||||||
messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool;
|
messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool;
|
||||||
@ -1457,7 +1462,7 @@ messages.saveDefaultSendAs#ccfddf96 peer:InputPeer send_as:InputPeer = Bool;
|
|||||||
messages.sendReaction#d30d78d4 flags:# big:flags.1?true add_to_recent:flags.2?true peer:InputPeer msg_id:int reaction:flags.0?Vector<Reaction> = Updates;
|
messages.sendReaction#d30d78d4 flags:# big:flags.1?true add_to_recent:flags.2?true peer:InputPeer msg_id:int reaction:flags.0?Vector<Reaction> = Updates;
|
||||||
messages.getMessagesReactions#8bba90e6 peer:InputPeer id:Vector<int> = Updates;
|
messages.getMessagesReactions#8bba90e6 peer:InputPeer id:Vector<int> = Updates;
|
||||||
messages.getMessageReactionsList#461b3f48 flags:# peer:InputPeer id:int reaction:flags.0?Reaction offset:flags.1?string limit:int = messages.MessageReactionsList;
|
messages.getMessageReactionsList#461b3f48 flags:# peer:InputPeer id:int reaction:flags.0?Reaction offset:flags.1?string limit:int = messages.MessageReactionsList;
|
||||||
messages.setChatAvailableReactions#feb16771 peer:InputPeer available_reactions:ChatReactions = Updates;
|
messages.setChatAvailableReactions#5a150bd4 flags:# peer:InputPeer available_reactions:ChatReactions reactions_limit:flags.0?int = Updates;
|
||||||
messages.getAvailableReactions#18dea0ac hash:int = messages.AvailableReactions;
|
messages.getAvailableReactions#18dea0ac hash:int = messages.AvailableReactions;
|
||||||
messages.setDefaultReaction#4f47a016 reaction:Reaction = Bool;
|
messages.setDefaultReaction#4f47a016 reaction:Reaction = Bool;
|
||||||
messages.translateText#63183030 flags:# peer:flags.0?InputPeer id:flags.0?Vector<int> text:flags.1?Vector<TextWithEntities> to_lang:string = messages.TranslatedText;
|
messages.translateText#63183030 flags:# peer:flags.0?InputPeer id:flags.0?Vector<int> text:flags.1?Vector<TextWithEntities> to_lang:string = messages.TranslatedText;
|
||||||
@ -1557,7 +1562,8 @@ channels.deleteTopicHistory#34435f2d channel:InputChannel top_msg_id:int = messa
|
|||||||
channels.toggleParticipantsHidden#6a6e7854 channel:InputChannel enabled:Bool = Updates;
|
channels.toggleParticipantsHidden#6a6e7854 channel:InputChannel enabled:Bool = Updates;
|
||||||
channels.clickSponsoredMessage#18afbc93 channel:InputChannel random_id:bytes = Bool;
|
channels.clickSponsoredMessage#18afbc93 channel:InputChannel random_id:bytes = Bool;
|
||||||
channels.toggleViewForumAsMessages#9738bb15 channel:InputChannel enabled:Bool = Updates;
|
channels.toggleViewForumAsMessages#9738bb15 channel:InputChannel enabled:Bool = Updates;
|
||||||
channels.getChannelRecommendations#83b70d97 channel:InputChannel = messages.Chats;
|
channels.getChannelRecommendations#25a71742 flags:# channel:flags.0?InputChannel = messages.Chats;
|
||||||
|
channels.reportSponsoredMessage#af8ff6b9 channel:InputChannel random_id:bytes option:bytes = channels.SponsoredMessageReportResult;
|
||||||
bots.setBotInfo#10cf3123 flags:# bot:flags.2?InputUser lang_code:string name:flags.3?string about:flags.0?string description:flags.1?string = Bool;
|
bots.setBotInfo#10cf3123 flags:# bot:flags.2?InputUser lang_code:string name:flags.3?string about:flags.0?string description:flags.1?string = Bool;
|
||||||
bots.canSendMessage#1359f4e6 bot:InputUser = Bool;
|
bots.canSendMessage#1359f4e6 bot:InputUser = Bool;
|
||||||
bots.allowSendMessage#f132e3ef bot:InputUser = Updates;
|
bots.allowSendMessage#f132e3ef bot:InputUser = Updates;
|
||||||
|
|||||||
@ -59,6 +59,7 @@
|
|||||||
"account.reorderUsernames",
|
"account.reorderUsernames",
|
||||||
"account.toggleUsername",
|
"account.toggleUsername",
|
||||||
"account.resolveBusinessChatLink",
|
"account.resolveBusinessChatLink",
|
||||||
|
"account.toggleSponsoredMessages",
|
||||||
"users.getUsers",
|
"users.getUsers",
|
||||||
"users.getFullUser",
|
"users.getFullUser",
|
||||||
"contacts.getContacts",
|
"contacts.getContacts",
|
||||||
@ -221,6 +222,7 @@
|
|||||||
"channels.viewSponsoredMessage",
|
"channels.viewSponsoredMessage",
|
||||||
"channels.getSponsoredMessages",
|
"channels.getSponsoredMessages",
|
||||||
"channels.getChannelRecommendations",
|
"channels.getChannelRecommendations",
|
||||||
|
"channels.reportSponsoredMessage",
|
||||||
"bots.canSendMessage",
|
"bots.canSendMessage",
|
||||||
"bots.allowSendMessage",
|
"bots.allowSendMessage",
|
||||||
"bots.invokeWebViewCustomMethod",
|
"bots.invokeWebViewCustomMethod",
|
||||||
|
|||||||
@ -100,8 +100,8 @@ chatForbidden#6592a1a7 id:long title:string = Chat;
|
|||||||
channel#aadfc8f flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true gigagroup:flags.26?true noforwards:flags.27?true join_to_send:flags.28?true join_request:flags.29?true forum:flags.30?true flags2:# stories_hidden:flags2.1?true stories_hidden_min:flags2.2?true stories_unavailable:flags2.3?true id:long access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int restriction_reason:flags.9?Vector<RestrictionReason> admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int usernames:flags2.0?Vector<Username> stories_max_id:flags2.4?int color:flags2.7?PeerColor profile_color:flags2.8?PeerColor emoji_status:flags2.9?EmojiStatus level:flags2.10?int = Chat;
|
channel#aadfc8f flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true gigagroup:flags.26?true noforwards:flags.27?true join_to_send:flags.28?true join_request:flags.29?true forum:flags.30?true flags2:# stories_hidden:flags2.1?true stories_hidden_min:flags2.2?true stories_unavailable:flags2.3?true id:long access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int restriction_reason:flags.9?Vector<RestrictionReason> admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int usernames:flags2.0?Vector<Username> stories_max_id:flags2.4?int color:flags2.7?PeerColor profile_color:flags2.8?PeerColor emoji_status:flags2.9?EmojiStatus level:flags2.10?int = Chat;
|
||||||
channelForbidden#17d493d5 flags:# broadcast:flags.5?true megagroup:flags.8?true id:long access_hash:long title:string until_date:flags.16?int = Chat;
|
channelForbidden#17d493d5 flags:# broadcast:flags.5?true megagroup:flags.8?true id:long access_hash:long title:string until_date:flags.16?int = Chat;
|
||||||
|
|
||||||
chatFull#c9d31138 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true translations_disabled:flags.19?true id:long about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string requests_pending:flags.17?int recent_requesters:flags.17?Vector<long> available_reactions:flags.18?ChatReactions = ChatFull;
|
chatFull#2633421b 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 reactions_limit:flags.20?int = ChatFull;
|
||||||
channelFull#44c054a7 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags2.0?true antispam:flags2.1?true participants_hidden:flags2.2?true translations_disabled:flags2.3?true stories_pinned_available:flags2.5?true view_forum_as_messages:flags2.6?true restricted_sponsored:flags2.11?true can_view_revenue:flags2.12?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector<string> groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector<long> default_send_as:flags.29?Peer available_reactions:flags.30?ChatReactions stories:flags2.4?PeerStories wallpaper:flags2.7?WallPaper boosts_applied:flags2.8?int boosts_unrestrict:flags2.9?int emojiset:flags2.10?StickerSet = ChatFull;
|
channelFull#bbab348d 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 restricted_sponsored:flags2.11?true can_view_revenue:flags2.12?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 reactions_limit:flags2.13?int stories:flags2.4?PeerStories wallpaper:flags2.7?WallPaper boosts_applied:flags2.8?int boosts_unrestrict:flags2.9?int emojiset:flags2.10?StickerSet = ChatFull;
|
||||||
|
|
||||||
chatParticipant#c02d4007 user_id:long inviter_id:long date:int = ChatParticipant;
|
chatParticipant#c02d4007 user_id:long inviter_id:long date:int = ChatParticipant;
|
||||||
chatParticipantCreator#e46bcee4 user_id:long = ChatParticipant;
|
chatParticipantCreator#e46bcee4 user_id:long = ChatParticipant;
|
||||||
@ -228,7 +228,7 @@ inputReportReasonFake#f5ddd6e7 = ReportReason;
|
|||||||
inputReportReasonIllegalDrugs#a8eb2be = ReportReason;
|
inputReportReasonIllegalDrugs#a8eb2be = ReportReason;
|
||||||
inputReportReasonPersonalDetails#9ec7863d = ReportReason;
|
inputReportReasonPersonalDetails#9ec7863d = ReportReason;
|
||||||
|
|
||||||
userFull#cc997720 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true voice_messages_forbidden:flags.20?true translations_disabled:flags.23?true stories_pinned_available:flags.26?true blocked_my_stories_from:flags.27?true wallpaper_overridden:flags.28?true contact_require_premium:flags.29?true read_dates_private:flags.30?true flags2:# id:long about:flags.1?string settings:PeerSettings personal_photo:flags.21?Photo profile_photo:flags.2?Photo fallback_photo:flags.22?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme_emoticon:flags.15?string private_forward_name:flags.16?string bot_group_admin_rights:flags.17?ChatAdminRights bot_broadcast_admin_rights:flags.18?ChatAdminRights premium_gifts:flags.19?Vector<PremiumGiftOption> wallpaper:flags.24?WallPaper stories:flags.25?PeerStories business_work_hours:flags2.0?BusinessWorkHours business_location:flags2.1?BusinessLocation business_greeting_message:flags2.2?BusinessGreetingMessage business_away_message:flags2.3?BusinessAwayMessage business_intro:flags2.4?BusinessIntro birthday:flags2.5?Birthday personal_channel_id:flags2.6?long personal_channel_message:flags2.6?int = UserFull;
|
userFull#cc997720 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true voice_messages_forbidden:flags.20?true translations_disabled:flags.23?true stories_pinned_available:flags.26?true blocked_my_stories_from:flags.27?true wallpaper_overridden:flags.28?true contact_require_premium:flags.29?true read_dates_private:flags.30?true flags2:# sponsored_enabled:flags2.7?true id:long about:flags.1?string settings:PeerSettings personal_photo:flags.21?Photo profile_photo:flags.2?Photo fallback_photo:flags.22?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme_emoticon:flags.15?string private_forward_name:flags.16?string bot_group_admin_rights:flags.17?ChatAdminRights bot_broadcast_admin_rights:flags.18?ChatAdminRights premium_gifts:flags.19?Vector<PremiumGiftOption> wallpaper:flags.24?WallPaper stories:flags.25?PeerStories business_work_hours:flags2.0?BusinessWorkHours business_location:flags2.1?BusinessLocation business_greeting_message:flags2.2?BusinessGreetingMessage business_away_message:flags2.3?BusinessAwayMessage business_intro:flags2.4?BusinessIntro birthday:flags2.5?Birthday personal_channel_id:flags2.6?long personal_channel_message:flags2.6?int = UserFull;
|
||||||
|
|
||||||
contact#145ade0b user_id:long mutual:Bool = Contact;
|
contact#145ade0b user_id:long mutual:Bool = Contact;
|
||||||
|
|
||||||
@ -412,6 +412,7 @@ updateBotBusinessConnect#8ae5c97a connection:BotBusinessConnection qts:int = Upd
|
|||||||
updateBotNewBusinessMessage#9ddb347c flags:# connection_id:string message:Message reply_to_message:flags.0?Message qts:int = Update;
|
updateBotNewBusinessMessage#9ddb347c flags:# connection_id:string message:Message reply_to_message:flags.0?Message qts:int = Update;
|
||||||
updateBotEditBusinessMessage#7df587c flags:# connection_id:string message:Message reply_to_message:flags.0?Message qts:int = Update;
|
updateBotEditBusinessMessage#7df587c flags:# connection_id:string message:Message reply_to_message:flags.0?Message qts:int = Update;
|
||||||
updateBotDeleteBusinessMessage#a02a982e connection_id:string peer:Peer messages:Vector<int> qts:int = Update;
|
updateBotDeleteBusinessMessage#a02a982e connection_id:string peer:Peer messages:Vector<int> qts:int = Update;
|
||||||
|
updateNewStoryReaction#1824e40b story_id:int peer:Peer reaction:Reaction = Update;
|
||||||
|
|
||||||
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
|
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
|
||||||
|
|
||||||
@ -1171,7 +1172,7 @@ inputWallPaperNoFile#967a462e id:long = InputWallPaper;
|
|||||||
account.wallPapersNotModified#1c199183 = account.WallPapers;
|
account.wallPapersNotModified#1c199183 = account.WallPapers;
|
||||||
account.wallPapers#cdc3858c hash:long wallpapers:Vector<WallPaper> = 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;
|
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 unknown_number:flags.9?true logout_tokens:flags.6?Vector<bytes> token:flags.8?string app_sandbox:flags.8?Bool = CodeSettings;
|
||||||
|
|
||||||
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;
|
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;
|
||||||
|
|
||||||
@ -1236,6 +1237,7 @@ themeSettings#fa58b6d4 flags:# message_colors_animated:flags.2?true base_theme:B
|
|||||||
|
|
||||||
webPageAttributeTheme#54b56617 flags:# documents:flags.0?Vector<Document> settings:flags.1?ThemeSettings = WebPageAttribute;
|
webPageAttributeTheme#54b56617 flags:# documents:flags.0?Vector<Document> settings:flags.1?ThemeSettings = WebPageAttribute;
|
||||||
webPageAttributeStory#2e94c3e7 flags:# peer:Peer id:int story:flags.0?StoryItem = WebPageAttribute;
|
webPageAttributeStory#2e94c3e7 flags:# peer:Peer id:int story:flags.0?StoryItem = WebPageAttribute;
|
||||||
|
webPageAttributeStickerSet#50cc03d3 flags:# emojis:flags.0?true text_color:flags.1?true stickers:Vector<Document> = WebPageAttribute;
|
||||||
|
|
||||||
messages.votesList#4899484e flags:# count:int votes:Vector<MessagePeerVote> chats:Vector<Chat> users:Vector<User> next_offset:flags.0?string = messages.VotesList;
|
messages.votesList#4899484e flags:# count:int votes:Vector<MessagePeerVote> chats:Vector<Chat> users:Vector<User> next_offset:flags.0?string = messages.VotesList;
|
||||||
|
|
||||||
@ -1361,7 +1363,7 @@ account.resetPasswordFailedWait#e3779861 retry_date:int = account.ResetPasswordR
|
|||||||
account.resetPasswordRequestedWait#e9effc7d until_date:int = account.ResetPasswordResult;
|
account.resetPasswordRequestedWait#e9effc7d until_date:int = account.ResetPasswordResult;
|
||||||
account.resetPasswordOk#e926d63e = account.ResetPasswordResult;
|
account.resetPasswordOk#e926d63e = account.ResetPasswordResult;
|
||||||
|
|
||||||
sponsoredMessage#ed5383f7 flags:# recommended:flags.5?true show_peer_photo:flags.6?true can_report:flags.12?true random_id:bytes from_id:flags.3?Peer chat_invite:flags.4?ChatInvite chat_invite_hash:flags.4?string channel_post:flags.2?int start_param:flags.0?string webpage:flags.9?SponsoredWebPage app:flags.10?BotApp message:string entities:flags.1?Vector<MessageEntity> button_text:flags.11?string sponsor_info:flags.7?string additional_info:flags.8?string = SponsoredMessage;
|
sponsoredMessage#bdedf566 flags:# recommended:flags.5?true can_report:flags.12?true random_id:bytes url:string title:string message:string entities:flags.1?Vector<MessageEntity> photo:flags.6?Photo color:flags.13?PeerColor button_text:string sponsor_info:flags.7?string additional_info:flags.8?string = SponsoredMessage;
|
||||||
|
|
||||||
messages.sponsoredMessages#c9ee1d87 flags:# posts_between:flags.0?int messages:Vector<SponsoredMessage> chats:Vector<Chat> users:Vector<User> = messages.SponsoredMessages;
|
messages.sponsoredMessages#c9ee1d87 flags:# posts_between:flags.0?int messages:Vector<SponsoredMessage> chats:Vector<Chat> users:Vector<User> = messages.SponsoredMessages;
|
||||||
messages.sponsoredMessagesEmpty#1839490f = messages.SponsoredMessages;
|
messages.sponsoredMessagesEmpty#1839490f = messages.SponsoredMessages;
|
||||||
@ -1565,8 +1567,6 @@ messagePeerVote#b6cc2d5c peer:Peer option:bytes date:int = MessagePeerVote;
|
|||||||
messagePeerVoteInputOption#74cda504 peer:Peer date:int = MessagePeerVote;
|
messagePeerVoteInputOption#74cda504 peer:Peer date:int = MessagePeerVote;
|
||||||
messagePeerVoteMultiple#4628f6e6 peer:Peer options:Vector<bytes> date:int = MessagePeerVote;
|
messagePeerVoteMultiple#4628f6e6 peer:Peer options:Vector<bytes> date:int = MessagePeerVote;
|
||||||
|
|
||||||
sponsoredWebPage#3db8ec63 flags:# url:string site_name:string photo:flags.0?Photo = SponsoredWebPage;
|
|
||||||
|
|
||||||
storyViews#8d595cd6 flags:# has_viewers:flags.1?true views_count:int forwards_count:flags.2?int reactions:flags.3?Vector<ReactionCount> reactions_count:flags.4?int recent_viewers:flags.0?Vector<long> = StoryViews;
|
storyViews#8d595cd6 flags:# has_viewers:flags.1?true views_count:int forwards_count:flags.2?int reactions:flags.3?Vector<ReactionCount> reactions_count:flags.4?int recent_viewers:flags.0?Vector<long> = StoryViews;
|
||||||
|
|
||||||
storyItemDeleted#51e6ee4f id:int = StoryItem;
|
storyItemDeleted#51e6ee4f id:int = StoryItem;
|
||||||
@ -1576,7 +1576,7 @@ storyItem#79b26a24 flags:# pinned:flags.5?true public:flags.7?true close_friends
|
|||||||
stories.allStoriesNotModified#1158fe3e flags:# state:string stealth_mode:StoriesStealthMode = stories.AllStories;
|
stories.allStoriesNotModified#1158fe3e flags:# state:string stealth_mode:StoriesStealthMode = stories.AllStories;
|
||||||
stories.allStories#6efc5e81 flags:# has_more:flags.0?true count:int state:string peer_stories:Vector<PeerStories> chats:Vector<Chat> users:Vector<User> stealth_mode:StoriesStealthMode = stories.AllStories;
|
stories.allStories#6efc5e81 flags:# has_more:flags.0?true count:int state:string peer_stories:Vector<PeerStories> chats:Vector<Chat> users:Vector<User> stealth_mode:StoriesStealthMode = stories.AllStories;
|
||||||
|
|
||||||
stories.stories#5dd8c3c8 count:int stories:Vector<StoryItem> chats:Vector<Chat> users:Vector<User> = stories.Stories;
|
stories.stories#63c3dd0a flags:# count:int stories:Vector<StoryItem> pinned_to_top:flags.0?Vector<int> 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;
|
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;
|
storyViewPublicForward#9083670b flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true message:Message = StoryView;
|
||||||
@ -1770,6 +1770,11 @@ broadcastRevenueTransactionRefund#42d30d2e amount:long date:int provider:string
|
|||||||
|
|
||||||
stats.broadcastRevenueTransactions#87158466 count:int transactions:Vector<BroadcastRevenueTransaction> = stats.BroadcastRevenueTransactions;
|
stats.broadcastRevenueTransactions#87158466 count:int transactions:Vector<BroadcastRevenueTransaction> = stats.BroadcastRevenueTransactions;
|
||||||
|
|
||||||
|
reactionNotificationsFromContacts#bac3a61a = ReactionNotificationsFrom;
|
||||||
|
reactionNotificationsFromAll#4b9e22a0 = ReactionNotificationsFrom;
|
||||||
|
|
||||||
|
reactionsNotifySettings#56e34970 flags:# messages_notify_from:flags.0?ReactionNotificationsFrom stories_notify_from:flags.1?ReactionNotificationsFrom sound:NotificationSound show_previews:Bool = ReactionsNotifySettings;
|
||||||
|
|
||||||
---functions---
|
---functions---
|
||||||
|
|
||||||
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
|
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
|
||||||
@ -1913,6 +1918,9 @@ account.deleteBusinessChatLink#60073674 slug:string = Bool;
|
|||||||
account.getBusinessChatLinks#6f70dde1 = account.BusinessChatLinks;
|
account.getBusinessChatLinks#6f70dde1 = account.BusinessChatLinks;
|
||||||
account.resolveBusinessChatLink#5492e5ee slug:string = account.ResolvedBusinessChatLinks;
|
account.resolveBusinessChatLink#5492e5ee slug:string = account.ResolvedBusinessChatLinks;
|
||||||
account.updatePersonalChannel#d94305e0 channel:InputChannel = Bool;
|
account.updatePersonalChannel#d94305e0 channel:InputChannel = Bool;
|
||||||
|
account.toggleSponsoredMessages#b9d9a38d enabled:Bool = Bool;
|
||||||
|
account.getReactionsNotifySettings#6dd654c = ReactionsNotifySettings;
|
||||||
|
account.setReactionsNotifySettings#316ce548 settings:ReactionsNotifySettings = ReactionsNotifySettings;
|
||||||
|
|
||||||
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
|
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
|
||||||
users.getFullUser#b60f5918 id:InputUser = users.UserFull;
|
users.getFullUser#b60f5918 id:InputUser = users.UserFull;
|
||||||
@ -1993,7 +2001,7 @@ messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_par
|
|||||||
messages.getMessagesViews#5784d3e1 peer:InputPeer id:Vector<int> increment:Bool = messages.MessageViews;
|
messages.getMessagesViews#5784d3e1 peer:InputPeer id:Vector<int> increment:Bool = messages.MessageViews;
|
||||||
messages.editChatAdmin#a85bd1c2 chat_id:long user_id:InputUser is_admin:Bool = Bool;
|
messages.editChatAdmin#a85bd1c2 chat_id:long user_id:InputUser is_admin:Bool = Bool;
|
||||||
messages.migrateChat#a2875319 chat_id:long = Updates;
|
messages.migrateChat#a2875319 chat_id:long = Updates;
|
||||||
messages.searchGlobal#4bc6589a flags:# folder_id:flags.0?int q:string filter:MessagesFilter min_date:int max_date:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
|
messages.searchGlobal#4bc6589a flags:# broadcasts_only:flags.1?true folder_id:flags.0?int q:string filter:MessagesFilter min_date:int max_date:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
|
||||||
messages.reorderStickerSets#78337739 flags:# masks:flags.0?true emojis:flags.1?true order:Vector<long> = Bool;
|
messages.reorderStickerSets#78337739 flags:# masks:flags.0?true emojis:flags.1?true order:Vector<long> = Bool;
|
||||||
messages.getDocumentByHash#b1f2061f sha256:bytes size:long mime_type:string = Document;
|
messages.getDocumentByHash#b1f2061f sha256:bytes size:long mime_type:string = Document;
|
||||||
messages.getSavedGifs#5cf09635 hash:long = messages.SavedGifs;
|
messages.getSavedGifs#5cf09635 hash:long = messages.SavedGifs;
|
||||||
@ -2097,7 +2105,7 @@ messages.saveDefaultSendAs#ccfddf96 peer:InputPeer send_as:InputPeer = Bool;
|
|||||||
messages.sendReaction#d30d78d4 flags:# big:flags.1?true add_to_recent:flags.2?true peer:InputPeer msg_id:int reaction:flags.0?Vector<Reaction> = Updates;
|
messages.sendReaction#d30d78d4 flags:# big:flags.1?true add_to_recent:flags.2?true peer:InputPeer msg_id:int reaction:flags.0?Vector<Reaction> = Updates;
|
||||||
messages.getMessagesReactions#8bba90e6 peer:InputPeer id:Vector<int> = Updates;
|
messages.getMessagesReactions#8bba90e6 peer:InputPeer id:Vector<int> = Updates;
|
||||||
messages.getMessageReactionsList#461b3f48 flags:# peer:InputPeer id:int reaction:flags.0?Reaction offset:flags.1?string limit:int = messages.MessageReactionsList;
|
messages.getMessageReactionsList#461b3f48 flags:# peer:InputPeer id:int reaction:flags.0?Reaction offset:flags.1?string limit:int = messages.MessageReactionsList;
|
||||||
messages.setChatAvailableReactions#feb16771 peer:InputPeer available_reactions:ChatReactions = Updates;
|
messages.setChatAvailableReactions#5a150bd4 flags:# peer:InputPeer available_reactions:ChatReactions reactions_limit:flags.0?int = Updates;
|
||||||
messages.getAvailableReactions#18dea0ac hash:int = messages.AvailableReactions;
|
messages.getAvailableReactions#18dea0ac hash:int = messages.AvailableReactions;
|
||||||
messages.setDefaultReaction#4f47a016 reaction:Reaction = Bool;
|
messages.setDefaultReaction#4f47a016 reaction:Reaction = Bool;
|
||||||
messages.translateText#63183030 flags:# peer:flags.0?InputPeer id:flags.0?Vector<int> text:flags.1?Vector<TextWithEntities> to_lang:string = messages.TranslatedText;
|
messages.translateText#63183030 flags:# peer:flags.0?InputPeer id:flags.0?Vector<int> text:flags.1?Vector<TextWithEntities> to_lang:string = messages.TranslatedText;
|
||||||
@ -2258,7 +2266,7 @@ channels.toggleParticipantsHidden#6a6e7854 channel:InputChannel enabled:Bool = U
|
|||||||
channels.clickSponsoredMessage#18afbc93 channel:InputChannel random_id:bytes = Bool;
|
channels.clickSponsoredMessage#18afbc93 channel:InputChannel random_id:bytes = Bool;
|
||||||
channels.updateColor#d8aa3671 flags:# for_profile:flags.1?true channel:InputChannel color:flags.2?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.toggleViewForumAsMessages#9738bb15 channel:InputChannel enabled:Bool = Updates;
|
||||||
channels.getChannelRecommendations#83b70d97 channel:InputChannel = messages.Chats;
|
channels.getChannelRecommendations#25a71742 flags:# channel:flags.0?InputChannel = messages.Chats;
|
||||||
channels.updateEmojiStatus#f0d3e6a8 channel:InputChannel emoji_status:EmojiStatus = Updates;
|
channels.updateEmojiStatus#f0d3e6a8 channel:InputChannel emoji_status:EmojiStatus = Updates;
|
||||||
channels.setBoostsToUnblockRestrictions#ad399cee channel:InputChannel boosts:int = Updates;
|
channels.setBoostsToUnblockRestrictions#ad399cee channel:InputChannel boosts:int = Updates;
|
||||||
channels.setEmojiStickers#3cd930b7 channel:InputChannel stickerset:InputStickerSet = Bool;
|
channels.setEmojiStickers#3cd930b7 channel:InputChannel stickerset:InputStickerSet = Bool;
|
||||||
@ -2398,6 +2406,7 @@ stories.getPeerMaxIDs#535983c3 id:Vector<InputPeer> = Vector<int>;
|
|||||||
stories.getChatsToSend#a56a8b60 = messages.Chats;
|
stories.getChatsToSend#a56a8b60 = messages.Chats;
|
||||||
stories.togglePeerStoriesHidden#bd0415c4 peer:InputPeer hidden:Bool = Bool;
|
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;
|
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;
|
||||||
|
stories.togglePinnedToTop#b297e9b peer:InputPeer id:Vector<int> = Bool;
|
||||||
|
|
||||||
premium.getBoostsList#60f67660 flags:# gifts:flags.0?true peer:InputPeer offset:string limit:int = premium.BoostsList;
|
premium.getBoostsList#60f67660 flags:# gifts:flags.0?true peer:InputPeer offset:string limit:int = premium.BoostsList;
|
||||||
premium.getMyBoosts#be77b4a = premium.MyBoosts;
|
premium.getMyBoosts#be77b4a = premium.MyBoosts;
|
||||||
|
|||||||
@ -158,110 +158,112 @@ $icons-map: (
|
|||||||
"my-notes": "\f17f",
|
"my-notes": "\f17f",
|
||||||
"new-chat-filled": "\f180",
|
"new-chat-filled": "\f180",
|
||||||
"next": "\f181",
|
"next": "\f181",
|
||||||
"noise-suppression": "\f182",
|
"nochannel": "\f182",
|
||||||
"non-contacts": "\f183",
|
"noise-suppression": "\f183",
|
||||||
"one-filled": "\f184",
|
"non-contacts": "\f184",
|
||||||
"open-in-new-tab": "\f185",
|
"one-filled": "\f185",
|
||||||
"password-off": "\f186",
|
"open-in-new-tab": "\f186",
|
||||||
"pause": "\f187",
|
"password-off": "\f187",
|
||||||
"permissions": "\f188",
|
"pause": "\f188",
|
||||||
"phone-discard-outline": "\f189",
|
"permissions": "\f189",
|
||||||
"phone-discard": "\f18a",
|
"phone-discard-outline": "\f18a",
|
||||||
"phone": "\f18b",
|
"phone-discard": "\f18b",
|
||||||
"photo": "\f18c",
|
"phone": "\f18c",
|
||||||
"pin-badge": "\f18d",
|
"photo": "\f18d",
|
||||||
"pin-list": "\f18e",
|
"pin-badge": "\f18e",
|
||||||
"pin": "\f18f",
|
"pin-list": "\f18f",
|
||||||
"pinned-chat": "\f190",
|
"pin": "\f190",
|
||||||
"pinned-message": "\f191",
|
"pinned-chat": "\f191",
|
||||||
"pip": "\f192",
|
"pinned-message": "\f192",
|
||||||
"play-story": "\f193",
|
"pip": "\f193",
|
||||||
"play": "\f194",
|
"play-story": "\f194",
|
||||||
"poll": "\f195",
|
"play": "\f195",
|
||||||
"premium": "\f196",
|
"poll": "\f196",
|
||||||
"previous": "\f197",
|
"premium": "\f197",
|
||||||
"privacy-policy": "\f198",
|
"previous": "\f198",
|
||||||
"quote-text": "\f199",
|
"privacy-policy": "\f199",
|
||||||
"quote": "\f19a",
|
"quote-text": "\f19a",
|
||||||
"readchats": "\f19b",
|
"quote": "\f19b",
|
||||||
"recent": "\f19c",
|
"readchats": "\f19c",
|
||||||
"reload": "\f19d",
|
"recent": "\f19d",
|
||||||
"remove": "\f19e",
|
"reload": "\f19e",
|
||||||
"reopen-topic": "\f19f",
|
"remove": "\f19f",
|
||||||
"replace": "\f1a0",
|
"reopen-topic": "\f1a0",
|
||||||
"replies": "\f1a1",
|
"replace": "\f1a1",
|
||||||
"reply-filled": "\f1a2",
|
"replies": "\f1a2",
|
||||||
"reply": "\f1a3",
|
"reply-filled": "\f1a3",
|
||||||
"revote": "\f1a4",
|
"reply": "\f1a4",
|
||||||
"save-story": "\f1a5",
|
"revenue-split": "\f1a5",
|
||||||
"saved-messages": "\f1a6",
|
"revote": "\f1a6",
|
||||||
"schedule": "\f1a7",
|
"save-story": "\f1a7",
|
||||||
"search": "\f1a8",
|
"saved-messages": "\f1a8",
|
||||||
"select": "\f1a9",
|
"schedule": "\f1a9",
|
||||||
"send-outline": "\f1aa",
|
"search": "\f1aa",
|
||||||
"send": "\f1ab",
|
"select": "\f1ab",
|
||||||
"settings-filled": "\f1ac",
|
"send-outline": "\f1ac",
|
||||||
"settings": "\f1ad",
|
"send": "\f1ad",
|
||||||
"share-filled": "\f1ae",
|
"settings-filled": "\f1ae",
|
||||||
"share-screen-outlined": "\f1af",
|
"settings": "\f1af",
|
||||||
"share-screen-stop": "\f1b0",
|
"share-filled": "\f1b0",
|
||||||
"share-screen": "\f1b1",
|
"share-screen-outlined": "\f1b1",
|
||||||
"sidebar": "\f1b2",
|
"share-screen-stop": "\f1b2",
|
||||||
"skip-next": "\f1b3",
|
"share-screen": "\f1b3",
|
||||||
"skip-previous": "\f1b4",
|
"sidebar": "\f1b4",
|
||||||
"smallscreen": "\f1b5",
|
"skip-next": "\f1b5",
|
||||||
"smile": "\f1b6",
|
"skip-previous": "\f1b6",
|
||||||
"sort": "\f1b7",
|
"smallscreen": "\f1b7",
|
||||||
"speaker-muted-story": "\f1b8",
|
"smile": "\f1b8",
|
||||||
"speaker-outline": "\f1b9",
|
"sort": "\f1b9",
|
||||||
"speaker-story": "\f1ba",
|
"speaker-muted-story": "\f1ba",
|
||||||
"speaker": "\f1bb",
|
"speaker-outline": "\f1bb",
|
||||||
"spoiler-disable": "\f1bc",
|
"speaker-story": "\f1bc",
|
||||||
"spoiler": "\f1bd",
|
"speaker": "\f1bd",
|
||||||
"sport": "\f1be",
|
"spoiler-disable": "\f1be",
|
||||||
"stats": "\f1bf",
|
"spoiler": "\f1bf",
|
||||||
"stealth-future": "\f1c0",
|
"sport": "\f1c0",
|
||||||
"stealth-past": "\f1c1",
|
"stats": "\f1c1",
|
||||||
"stickers": "\f1c2",
|
"stealth-future": "\f1c2",
|
||||||
"stop-raising-hand": "\f1c3",
|
"stealth-past": "\f1c3",
|
||||||
"stop": "\f1c4",
|
"stickers": "\f1c4",
|
||||||
"story-caption": "\f1c5",
|
"stop-raising-hand": "\f1c5",
|
||||||
"story-expired": "\f1c6",
|
"stop": "\f1c6",
|
||||||
"story-priority": "\f1c7",
|
"story-caption": "\f1c7",
|
||||||
"story-reply": "\f1c8",
|
"story-expired": "\f1c8",
|
||||||
"strikethrough": "\f1c9",
|
"story-priority": "\f1c9",
|
||||||
"tag-add": "\f1ca",
|
"story-reply": "\f1ca",
|
||||||
"tag-crossed": "\f1cb",
|
"strikethrough": "\f1cb",
|
||||||
"tag-filter": "\f1cc",
|
"tag-add": "\f1cc",
|
||||||
"tag-name": "\f1cd",
|
"tag-crossed": "\f1cd",
|
||||||
"tag": "\f1ce",
|
"tag-filter": "\f1ce",
|
||||||
"timer": "\f1cf",
|
"tag-name": "\f1cf",
|
||||||
"transcribe": "\f1d0",
|
"tag": "\f1d0",
|
||||||
"truck": "\f1d1",
|
"timer": "\f1d1",
|
||||||
"unarchive": "\f1d2",
|
"transcribe": "\f1d2",
|
||||||
"underlined": "\f1d3",
|
"truck": "\f1d3",
|
||||||
"unlock-badge": "\f1d4",
|
"unarchive": "\f1d4",
|
||||||
"unlock": "\f1d5",
|
"underlined": "\f1d5",
|
||||||
"unmute": "\f1d6",
|
"unlock-badge": "\f1d6",
|
||||||
"unpin": "\f1d7",
|
"unlock": "\f1d7",
|
||||||
"unread": "\f1d8",
|
"unmute": "\f1d8",
|
||||||
"up": "\f1d9",
|
"unpin": "\f1d9",
|
||||||
"user-filled": "\f1da",
|
"unread": "\f1da",
|
||||||
"user-online": "\f1db",
|
"up": "\f1db",
|
||||||
"user": "\f1dc",
|
"user-filled": "\f1dc",
|
||||||
"video-outlined": "\f1dd",
|
"user-online": "\f1dd",
|
||||||
"video-stop": "\f1de",
|
"user": "\f1de",
|
||||||
"video": "\f1df",
|
"video-outlined": "\f1df",
|
||||||
"view-once": "\f1e0",
|
"video-stop": "\f1e0",
|
||||||
"voice-chat": "\f1e1",
|
"video": "\f1e1",
|
||||||
"volume-1": "\f1e2",
|
"view-once": "\f1e2",
|
||||||
"volume-2": "\f1e3",
|
"voice-chat": "\f1e3",
|
||||||
"volume-3": "\f1e4",
|
"volume-1": "\f1e4",
|
||||||
"web": "\f1e5",
|
"volume-2": "\f1e5",
|
||||||
"webapp": "\f1e6",
|
"volume-3": "\f1e6",
|
||||||
"word-wrap": "\f1e7",
|
"web": "\f1e7",
|
||||||
"zoom-in": "\f1e8",
|
"webapp": "\f1e8",
|
||||||
"zoom-out": "\f1e9",
|
"word-wrap": "\f1e9",
|
||||||
|
"zoom-in": "\f1ea",
|
||||||
|
"zoom-out": "\f1eb",
|
||||||
);
|
);
|
||||||
|
|
||||||
.icon-active-sessions::before {
|
.icon-active-sessions::before {
|
||||||
@ -651,6 +653,9 @@ $icons-map: (
|
|||||||
.icon-next::before {
|
.icon-next::before {
|
||||||
content: map.get($icons-map, "next");
|
content: map.get($icons-map, "next");
|
||||||
}
|
}
|
||||||
|
.icon-nochannel::before {
|
||||||
|
content: map.get($icons-map, "nochannel");
|
||||||
|
}
|
||||||
.icon-noise-suppression::before {
|
.icon-noise-suppression::before {
|
||||||
content: map.get($icons-map, "noise-suppression");
|
content: map.get($icons-map, "noise-suppression");
|
||||||
}
|
}
|
||||||
@ -753,6 +758,9 @@ $icons-map: (
|
|||||||
.icon-reply::before {
|
.icon-reply::before {
|
||||||
content: map.get($icons-map, "reply");
|
content: map.get($icons-map, "reply");
|
||||||
}
|
}
|
||||||
|
.icon-revenue-split::before {
|
||||||
|
content: map.get($icons-map, "revenue-split");
|
||||||
|
}
|
||||||
.icon-revote::before {
|
.icon-revote::before {
|
||||||
content: map.get($icons-map, "revote");
|
content: map.get($icons-map, "revote");
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@ -128,6 +128,7 @@ export type FontIconName =
|
|||||||
| 'my-notes'
|
| 'my-notes'
|
||||||
| 'new-chat-filled'
|
| 'new-chat-filled'
|
||||||
| 'next'
|
| 'next'
|
||||||
|
| 'nochannel'
|
||||||
| 'noise-suppression'
|
| 'noise-suppression'
|
||||||
| 'non-contacts'
|
| 'non-contacts'
|
||||||
| 'one-filled'
|
| 'one-filled'
|
||||||
@ -162,6 +163,7 @@ export type FontIconName =
|
|||||||
| 'replies'
|
| 'replies'
|
||||||
| 'reply-filled'
|
| 'reply-filled'
|
||||||
| 'reply'
|
| 'reply'
|
||||||
|
| 'revenue-split'
|
||||||
| 'revote'
|
| 'revote'
|
||||||
| 'save-story'
|
| 'save-story'
|
||||||
| 'saved-messages'
|
| 'saved-messages'
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user