Privacy: Support chat no forwards (#6775)

This commit is contained in:
Alexander Zinchuk 2026-03-31 11:29:04 +02:00
parent cbce577dab
commit 9cd17b4921
54 changed files with 1765 additions and 987 deletions

View File

@ -110,6 +110,7 @@ export interface GramJsAppConfig extends LimitsConfig {
stars_suggested_post_age_min?: number;
stars_suggested_post_future_max?: number;
stars_suggested_post_future_min?: number;
no_forwards_request_expire_period?: number;
ton_suggested_post_commission_permille?: number;
ton_suggested_post_amount_max?: number;
ton_suggested_post_amount_min?: number;
@ -250,6 +251,7 @@ export function buildAppConfig(json: GramJs.TypeJSONValue, hash: number): ApiApp
starsSuggestedPostAgeMin: appConfig.stars_suggested_post_age_min,
starsSuggestedPostFutureMax: appConfig.stars_suggested_post_future_max,
starsSuggestedPostFutureMin: appConfig.stars_suggested_post_future_min,
noForwardsRequestExpirePeriod: appConfig.no_forwards_request_expire_period,
tonSuggestedPostCommissionPermille: appConfig.ton_suggested_post_commission_permille,
tonSuggestedPostAmountMax: appConfig.ton_suggested_post_amount_max,
tonSuggestedPostAmountMin: appConfig.ton_suggested_post_amount_min,

View File

@ -573,6 +573,25 @@ export function buildApiMessageAction(action: GramJs.TypeMessageAction): ApiMess
newCreatorId: buildApiPeerId(newCreatorId, 'user'),
};
}
if (action instanceof GramJs.MessageActionNoForwardsToggle) {
const { prevValue, newValue } = action;
return {
mediaType: 'action',
type: 'noForwardsToggle',
prevValue: Boolean(prevValue),
newValue: Boolean(newValue),
};
}
if (action instanceof GramJs.MessageActionNoForwardsRequest) {
const { expired, prevValue, newValue } = action;
return {
mediaType: 'action',
type: 'noForwardsRequest',
isExpired: expired,
prevValue: Boolean(prevValue),
newValue: Boolean(newValue),
};
}
return UNSUPPORTED_ACTION;
}

View File

@ -37,6 +37,7 @@ export function buildApiUserFullInfo(mtpUserFull: GramJs.users.UserFull): ApiUse
birthday, personalChannelId, personalChannelMessage, sponsoredEnabled, stargiftsCount, botVerification,
botCanManageEmojiStatus, settings, sendPaidMessagesStars, displayGiftsButton, disallowedGifts,
starsRating, starsMyPendingRating, starsMyPendingRatingDate, mainTab, note,
noforwardsMyEnabled, noforwardsPeerEnabled,
},
users,
} = mtpUserFull;
@ -77,6 +78,8 @@ export function buildApiUserFullInfo(mtpUserFull: GramJs.users.UserFull): ApiUse
settings: buildApiPeerSettings(settings),
mainTab: mainTab && buildApiProfileTab(mainTab),
note: note && buildApiFormattedText(note),
noForwardsMyEnabled: noforwardsMyEnabled,
noForwardsPeerEnabled: noforwardsPeerEnabled,
};
}

View File

@ -380,3 +380,21 @@ export function updateContactNote(user: ApiUser, note: ApiFormattedText) {
shouldReturnTrue: true,
});
}
export function toggleNoForwards({
user,
isEnabled,
requestMsgId,
}: {
user: ApiUser;
isEnabled: boolean;
requestMsgId?: number;
}) {
return invokeRequest(new GramJs.messages.ToggleNoForwards({
peer: buildInputPeer(user.id, user.accessHash),
enabled: isEnabled,
requestMsgId,
}), {
shouldReturnTrue: true,
});
}

View File

@ -357,6 +357,19 @@ export interface ApiMessageActionChangeCreator extends ActionMediaType {
newCreatorId: string;
}
export interface ApiMessageActionNoForwardsToggle extends ActionMediaType {
type: 'noForwardsToggle';
prevValue: boolean;
newValue: boolean;
}
export interface ApiMessageActionNoForwardsRequest extends ActionMediaType {
type: 'noForwardsRequest';
isExpired?: boolean;
prevValue: boolean;
newValue: boolean;
}
export interface ApiMessageActionUnsupported extends ActionMediaType {
type: 'unsupported';
}
@ -378,4 +391,4 @@ export type ApiMessageAction = ApiMessageActionUnsupported | ApiMessageActionCha
| ApiMessageActionSuggestedPostSuccess | ApiMessageActionSuggestedPostRefund | ApiMessageActionTodoCompletions
| ApiMessageActionTodoAppendTasks | ApiMessageActionStarGiftPurchaseOffer
| ApiMessageActionStarGiftPurchaseOfferDeclined | ApiMessageActionNewCreatorPending
| ApiMessageActionChangeCreator;
| ApiMessageActionChangeCreator | ApiMessageActionNoForwardsToggle | ApiMessageActionNoForwardsRequest;

View File

@ -968,6 +968,12 @@ export interface KeyboardButtonGiftOffer extends ApiKeyboardButtonBase {
buttonType: 'accept' | 'reject';
}
export interface KeyboardButtonNoForwardsRequest extends ApiKeyboardButtonBase {
type: 'noForwardsRequest';
text: string;
buttonType: 'accept' | 'reject';
}
export type ApiKeyboardButton = (
ApiKeyboardButtonSimple
| ApiKeyboardButtonReceipt
@ -983,6 +989,7 @@ export type ApiKeyboardButton = (
| KeyboardButtonSuggestedMessage
| KeyboardButtonOpenThread
| KeyboardButtonGiftOffer
| KeyboardButtonNoForwardsRequest
);
export type ApiKeyboardButtons = ApiKeyboardButton[][];

View File

@ -274,6 +274,7 @@ export interface ApiAppConfig {
starsSuggestedPostAgeMin: number;
starsSuggestedPostFutureMax: number;
starsSuggestedPostFutureMin: number;
noForwardsRequestExpirePeriod: number;
tonSuggestedPostCommissionPermille: number;
tonSuggestedPostAmountMax: number;
tonSuggestedPostAmountMin: number;

View File

@ -85,6 +85,8 @@ export interface ApiUserFullInfo {
settings?: ApiPeerSettings;
mainTab?: ApiProfileTab;
note?: ApiFormattedText;
noForwardsMyEnabled?: boolean;
noForwardsPeerEnabled?: boolean;
}
export type ApiUserType = 'userTypeBot' | 'userTypeRegular' | 'userTypeDeleted' | 'userTypeUnknown';

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M14.208 22.56c-.291 0-.585-.06-.867-.185a2.1 2.1 0 0 1-1.268-1.945v-2.494c-.763.057-2.06.256-4.032.864-2.019.622-3.629 2.002-4.625 3.05a1.89 1.89 0 0 1-2.18.404 1.89 1.89 0 0 1-1.07-1.947c.36-2.833 1.353-6.764 4.045-9.409 2.795-2.748 6.058-3.36 7.862-3.468V4.838c0-.855.487-1.599 1.268-1.944a2.1 2.1 0 0 1 2.29.374l8.694 7.931a1.95 1.95 0 0 1 0 2.871L15.632 22c-.404.369-.908.56-1.424.56m-1.65-6.944q.162 0 .3.007a1.58 1.58 0 0 1 1.516 1.582v2.83l8.111-7.4-8.111-7.4v2.89a1.58 1.58 0 0 1-1.578 1.585l-.045-.001c-1.002 0-4.272.218-6.928 2.83-1.931 1.897-2.799 4.776-3.187 6.861 1.174-1.062 2.78-2.198 4.727-2.798 2.583-.796 4.22-.986 5.196-.986m.198 2.304h.003zM20.365 29.29c-.316 0-.633-.121-.874-.363l-3.289-3.289a1.15 1.15 0 0 1 1.627-1.627l2.57 2.57 9.524-8.689a1.151 1.151 0 0 1 1.55 1.7l-10.276 9.375a1.23 1.23 0 0 1-.832.323" /></svg>

After

Width:  |  Height:  |  Size: 909 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M6.921 7.047A2.05 2.05 0 0 0 4.868 9.03l-.001 10.644c0 5.96 4.85 10.81 10.81 10.81h.925a9.7 9.7 0 0 0 8.846-5.747l3.92-8.814a1.893 1.893 0 0 0-.883-2.475 1.819 1.819 0 0 0-2.323.616l-.043.062-2.841 5.66c-.05.098-.113.138-.21.138a.32.32 0 0 1-.202-.071c-.045-.042-.068-.095-.068-.185V5.43a2 2 0 0 0-.524-1.459 2.18 2.18 0 0 0-1.526-.694 2.053 2.053 0 0 0-2.051 1.95c-.004.262-.002 8.435-.002 9.68v.157c0 .135-.116.25-.251.25a.25.25 0 0 1-.25-.251V3.539c-.036-1.115-.907-1.986-1.983-2.024h-.003c-1.181 0-2.082.87-2.12 1.981l-.002 11.567c0 .136-.115.25-.252.25a.254.254 0 0 1-.25-.25V5.381c-.038-1.117-.909-1.987-1.984-2.024h-.002c-1.184 0-2.083.872-2.12 1.984l-.001 10.643c0 .136-.115.25-.251.25a.248.248 0 0 1-.25-.25V9.074c-.038-1.117-.91-1.989-1.985-2.025z" /></svg>

After

Width:  |  Height:  |  Size: 837 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="m28.893 27.266-2.813-2.812c1.971-2.344 3.107-5.313 3.107-8.454C29.187 8.729 23.27 2.814 16 2.814c-3.141 0-6.111 1.135-8.454 3.105L4.734 3.108a1.15 1.15 0 0 0-1.627 1.626l2.801 2.8-.012.013 1.637 1.638.012-.013 15.283 15.283-.013.012 1.637 1.636.013-.012 2.8 2.801a1.15 1.15 0 0 0 1.628 0 1.15 1.15 0 0 0 0-1.626M16 5.114c6.003 0 10.886 4.884 10.886 10.886 0 2.524-.884 4.917-2.433 6.827l-3.512-3.512.86-.86a1.15 1.15 0 1 0-1.626-1.626l-.86.86-2.165-2.165v-6.28a1.15 1.15 0 0 0-2.3 0v3.98L9.173 7.545A10.82 10.82 0 0 1 16 5.114M20.117 26.076c-2.311.948-4.927 1.09-7.497.287-3.48-1.087-6.097-3.803-7.081-7.312-.692-2.465-.521-4.956.385-7.168.182-.443.105-.95-.234-1.289-.572-.572-1.56-.4-1.87.346a13.27 13.27 0 0 0-.816 7.33C3.922 23.717 8.31 28.093 13.758 29c2.524.42 5.036.123 7.301-.82.747-.31.918-1.298.347-1.87-.339-.339-.845-.416-1.289-.234" class="cls-1"/><path d="M14.85 19.465v.337l-3.026-2.974a1.151 1.151 0 0 0-1.627 1.627l4.75 4.749c.28.281.653.437 1.05.438H16c.396 0 .769-.155 1.05-.435l.626-.627-.001-.001.14-.15z"/></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="m24.367 21.046 3.402-3.104c.403-.368.634-.891.634-1.436 0-.546-.231-1.07-.634-1.438l-8.693-7.93a2.1 2.1 0 0 0-2.29-.373 2.1 2.1 0 0 0-1.267 1.944v2.593c-.42.025-.935.096-1.485.196L7.949 5.876a1.15 1.15 0 0 0-1.56 1.69l20.084 18.557a1.147 1.147 0 0 0 1.625-.064 1.15 1.15 0 0 0-.065-1.625zm-7.013-7.926c.3-.299.466-.698.466-1.123V9.106l8.112 7.399-3.261 2.974-6.39-5.905c.427-.034.785-.167 1.073-.454M19.287 22.566l-1.467 1.34v-2.83c0-.848-.666-1.544-1.518-1.584-.93-.033-2.633.099-5.494.982-1.946.6-3.552 1.735-4.727 2.798.388-2.084 1.255-4.963 3.186-6.863.436-.427.91-.813 1.41-1.146a1.151 1.151 0 0 0-1.278-1.914c-.619.413-1.205.891-1.744 1.42-2.692 2.647-3.683 6.577-4.042 9.408-.103.812.326 1.595 1.069 1.947s1.617.19 2.18-.402c.995-1.048 2.606-2.429 4.624-3.051 1.972-.607 3.27-.807 4.033-.864v2.495a2.1 2.1 0 0 0 1.267 1.944c.282.124.576.186.867.186a2.1 2.1 0 0 0 1.424-.56l1.76-1.606a1.151 1.151 0 0 0-1.55-1.7" /></svg>

After

Width:  |  Height:  |  Size: 998 B

View File

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M7.38 26.33H5.06c-1.66 0-3.01-1.35-3.01-3.01V21c0-1.66 1.35-3.01 3.01-3.01h2.32c1.66 0 3.01 1.35 3.01 3.01v2.32c0 1.66-1.35 3.01-3.01 3.01M5.06 20c-.55 0-1 .45-1 1v2.33c0 .55.45 1 1 1h2.33c.55 0 1-.45 1-1V21c0-.55-.45-1-1-1zM17.16 26.33h-2.32c-1.66 0-3.01-1.35-3.01-3.01V21c0-1.66 1.35-3.01 3.01-3.01h2.32c1.66 0 3.01 1.35 3.01 3.01v2.32c0 1.66-1.35 3.01-3.01 3.01M14.83 20c-.55 0-1 .45-1 1v2.33c0 .55.45 1 1 1h2.33c.55 0 1-.45 1-1V21c0-.55-.45-1-1-1zM26.94 26.33h-2.32c-1.66 0-3.01-1.35-3.01-3.01V21c0-1.66 1.35-3.01 3.01-3.01h2.32c1.66 0 3.01 1.35 3.01 3.01v2.32c0 1.66-1.35 3.01-3.01 3.01M24.61 20c-.55 0-1 .45-1 1v2.33c0 .55.45 1 1 1h2.33c.55 0 1-.45 1-1V21c0-.55-.45-1-1-1zM25.78 15.26c-.55 0-1-.45-1-1V8.34c0-.32-.41-.67-1.01-.67H8.23c-.59 0-1.01.35-1.01.67v5.92c0 .55-.45 1-1 1s-1-.45-1-1V8.34c0-1.47 1.35-2.67 3.01-2.67h15.54c1.66 0 3.01 1.2 3.01 2.67v5.92c0 .55-.45 1-1 1" class="cls-1"/><path d="M6.22 15.99c-.27 0-.52-.11-.71-.29l-3.14-3.15a.996.996 0 1 1 1.41-1.41l2.44 2.44 2.44-2.44a.996.996 0 1 1 1.41 1.41L6.93 15.7a1 1 0 0 1-.71.29"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M7.38 26.33H5.06c-1.66 0-3.01-1.35-3.01-3.01V21c0-1.66 1.35-3.01 3.01-3.01h2.32c1.66 0 3.01 1.35 3.01 3.01v2.32c0 1.66-1.35 3.01-3.01 3.01M5.06 20c-.55 0-1 .45-1 1v2.33c0 .55.45 1 1 1h2.33c.55 0 1-.45 1-1V21c0-.55-.45-1-1-1zM17.16 26.33h-2.32c-1.66 0-3.01-1.35-3.01-3.01V21c0-1.66 1.35-3.01 3.01-3.01h2.32c1.66 0 3.01 1.35 3.01 3.01v2.32c0 1.66-1.35 3.01-3.01 3.01M14.83 20c-.55 0-1 .45-1 1v2.33c0 .55.45 1 1 1h2.33c.55 0 1-.45 1-1V21c0-.55-.45-1-1-1zM26.94 26.33h-2.32c-1.66 0-3.01-1.35-3.01-3.01V21c0-1.66 1.35-3.01 3.01-3.01h2.32c1.66 0 3.01 1.35 3.01 3.01v2.32c0 1.66-1.35 3.01-3.01 3.01M24.61 20c-.55 0-1 .45-1 1v2.33c0 .55.45 1 1 1h2.33c.55 0 1-.45 1-1V21c0-.55-.45-1-1-1zM25.78 15.26c-.55 0-1-.45-1-1V8.34c0-.32-.41-.67-1.01-.67H8.23c-.59 0-1.01.35-1.01.67v5.92c0 .55-.45 1-1 1s-1-.45-1-1V8.34c0-1.47 1.35-2.67 3.01-2.67h15.54c1.66 0 3.01 1.2 3.01 2.67v5.92c0 .55-.45 1-1 1" /><path d="M6.22 15.99c-.27 0-.52-.11-.71-.29l-3.14-3.15a.996.996 0 1 1 1.41-1.41l2.44 2.44 2.44-2.44a.996.996 0 1 1 1.41 1.41L6.93 15.7a1 1 0 0 1-.71.29"/></svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M16 1.333C7.9 1.333 1.333 7.9 1.333 16S7.9 30.667 16 30.667 30.667 24.1 30.667 16 24.1 1.333 16 1.333m7.687 11.282-8.858 8.857h-.001a1.476 1.476 0 0 1-2.088 0l-3.69-3.69a1.477 1.477 0 0 1 2.088-2.089l2.648 2.648 7.813-7.814a1.477 1.477 0 0 1 2.088 2.088" /></svg>

After

Width:  |  Height:  |  Size: 333 B

View File

@ -72,6 +72,8 @@
"PremiumPreviewUploadsDescription" = "4 GB per each document, unlimited storage for your chats and media overall.";
"PremiumPreviewAdvancedChatManagementDescription" = "Tools to set the default folder, auto-archive and hide new chats from non-contacts.";
"PremiumPreviewAnimatedProfilesDescription" = "Video avatars animated in chat lists and chats to allow for additional self-expression.";
"PremiumPreviewNoForwards" = "Disable Sharing";
"PremiumPreviewNoForwardsDescription" = "Prevent forwarding, saving and copying content in private chats.";
"PremiumLimitAccountsTitle" = "Limit Reached";
"PremiumLimitAccountsNoPremium" = "You have reached your current limit of connected accounts. You can free one more place by subscribing to Telegram Premium.";
"PremiumLimitAccounts" = "You have reached your current limit of connected accounts. You can free one more place by subscribing to Telegram Premium with one of these connected accounts.";
@ -1931,6 +1933,26 @@
"ActionPaymentUsedRecurring" = "You were charged {amount} via recurring payment";
"ActionScreenshotTaken" = "{from} took a screenshot!";
"ActionScreenshotTakenYou" = "You took a screenshot!";
"ActionSharingDisabled" = "{from} disabled sharing in this chat";
"ActionSharingDisabledYou" = "You disabled sharing in this chat";
"ActionSharingEnabled" = "{from} enabled sharing in this chat";
"ActionSharingEnabledYou" = "You enabled sharing in this chat";
"ActionSharingStillDisabled" = "Sharing in this chat is still disabled";
"ContextMenuNoForwardsPeer" = "{name} disabled copying and forwarding in this chat.";
"ContextMenuNoForwardsYou" = "You disabled copying and forwarding in this chat.";
"DisableSharing" = "Disable Sharing";
"EnableSharing" = "Enable Sharing";
"NotificationSharingEnabled" = "Sharing enabled for this chat.";
"NotificationSharingDisabled" = "Sharing disabled for this chat.";
"NoForwardingTitle" = "No Forwarding";
"NoForwardingDescription" = "Disable message forwarding to other chats.";
"NoSavingTitle" = "No Saving";
"NoSavingDescription" = "Disable copying text and saving photos and videos.";
"NoForwardsRequestTitle" = "{user} would like to enable sharing in this chat, which includes:";
"NoForwardsRequestYouTitle" = "You suggested to enable sharing in this chat, which includes:";
"NoForwardsRequestForwarding" = "forwarding messages";
"NoForwardsRequestSaving" = "saving photos and videos";
"NoForwardsRequestCopying" = "copying messages";
"ActionBotAllowedFromDomain" = "You allowed this bot to message you when you logged in on {domain}.";
"ActionBotAllowedFromApp" = "You allowed this bot to message you when you opened {app}.";
"ActionBotAppPlaceholder" = "App";
@ -2750,3 +2772,5 @@
"RankEditTextOwn" = "Share your role, title or how you're known in this group. Your tag is visible to all members.";
"RankEditText" = "Add a short tag next to {user}'s name.";
"MenuAddCaption" = "Add Caption";
"NoForwardsRequestReject" = "Reject";
"NoForwardsRequestAccept" = "Accept";

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><defs><style>.cls-1{fill:#fff}</style></defs><path d="M15.821 15.367c5.48 0 9.924-1.222 9.924-2.73 0-.94-1.731-1.77-4.364-2.26-.033-.535-.1-1.045-.118-1.39a8.7 8.7 0 0 0-.929-3.508c-.239-.471-.535-.935-.976-1.227s-1.055-.372-1.492-.075c-.59.401-.639 1.283-1.155 1.776-.238.228-.542.34-.862.428-.32-.088-.623-.2-.861-.428-.516-.493-.565-1.375-1.155-1.776-.437-.297-1.052-.216-1.493.075s-.736.756-.976 1.227a8.7 8.7 0 0 0-.929 3.508c-.017.342-.083.849-.117 1.38-2.664.49-4.42 1.323-4.42 2.27 0 1.508 4.443 2.73 9.923 2.73m12.225 2.487c-.956-1.02-1.874-2.075-2.81-3.114-.596.336-1.327.611-2.14.834l.003.13-.061 3.537c-3.775 1.212-6.969 4.125-8.522 7.773-.092.215-.179.438-.181.671s.098.482.302.594c.355.195.773-.091 1.082-.353a21.5 21.5 0 0 1 8.971-4.498c.224-.052.642-.19.306-.716-.198-.31-.692-.91-.878-1.228-.168-.288-.36-.404-.102-.614.332-.27.731-.482 1.034-.622.976-.455 1.717-.844 2.68-1.328.95-.477.717-.638.316-1.066" class="cls-1"/><path d="M17.533 18.326a2.7 2.7 0 0 0 2.346.451 2.5 2.5 0 0 0 1.15-.693c.426-.455.65-1.077.671-1.7.005-.153.01-.32.012-.489-1.742.335-3.645.486-5.242.517.118.754.496 1.478 1.063 1.914m-7.171-.785c.25.435.62.802 1.067 1.031 1.373.704 3.378.012 3.565-1.65a6 6 0 0 1 .096-.511c-1.552-.034-3.385-.182-5.073-.5a2.6 2.6 0 0 0-.005.547c.036.38.159.751.35 1.083m-.097 3.188c-1.116-1.52-1.866-3.346-1.96-5.224-.765-.224-1.448-.499-2.005-.83l-.296.328-2.035 2.25c-.202.223-.418.499-.352.792.054.238.275.393.48.525l3.577 2.31-1.116 1.411c2.568 1.51 4.556 2.599 7.268 3.741q.329-.684.725-1.33c-1.745-1.094-3.061-2.307-4.286-3.973" class="cls-1"/></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

View File

@ -105,6 +105,7 @@ export { default as OneTimeMediaModal } from '../components/modals/oneTimeMedia/
export { default as WebAppsCloseConfirmationModal } from '../components/main/WebAppsCloseConfirmationModal';
export { default as FrozenAccountModal } from '../components/modals/frozenAccount/FrozenAccountModal';
export { default as ProfileRatingModal } from '../components/modals/profileRating/ProfileRatingModal';
export { default as DisableSharingAboutModal } from '../components/modals/disableSharing/DisableSharingAboutModal';
export { default as EditRankModal } from '../components/modals/rank/EditRankModal';
export { default as RankModal } from '../components/modals/rank/RankModal';
export { default as QuickPreviewModal } from '../components/modals/quickPreview/QuickPreviewModal';

View File

@ -35,6 +35,7 @@ import Experimental from '../../../assets/tgs/settings/Experimental.tgs';
import FoldersAll from '../../../assets/tgs/settings/FoldersAll.tgs';
import FoldersNew from '../../../assets/tgs/settings/FoldersNew.tgs';
import FoldersShare from '../../../assets/tgs/settings/FoldersShare.tgs';
import HandStop from '../../../assets/tgs/settings/HandStop.tgs';
import Lock from '../../../assets/tgs/settings/Lock.tgs';
import Passkeys from '../../../assets/tgs/settings/Passkeys.tgs';
import StarReaction from '../../../assets/tgs/stars/StarReaction.tgs';
@ -42,9 +43,11 @@ import StarReactionEffect from '../../../assets/tgs/stars/StarReactionEffect.tgs
import Unlock from '../../../assets/tgs/Unlock.tgs';
import DuckNothingFoundPreview from '../../../assets/tgs-previews/DuckNothingFound.svg';
import SearchPreview from '../../../assets/tgs-previews/Search.svg';
import HandStopPreview from '../../../assets/tgs-previews/settings/HandStopPreview.png';
import PasskeysPreview from '../../../assets/tgs-previews/settings/Passkeys.svg';
export const LOCAL_TGS_PREVIEW_URLS = {
HandStop: HandStopPreview,
BrokenGift: BrokenGiftPreview,
DuckNothingFound: DuckNothingFoundPreview,
Search: SearchPreview,
@ -93,4 +96,5 @@ export const LOCAL_TGS_URLS = {
DuckNothingFound,
Passkeys,
DuckCake,
HandStop,
};

View File

@ -53,7 +53,7 @@
margin-bottom: 7.5rem;
}
.limits, .stories {
.limits, .stories, .noForward {
background: var(--color-background);
}
@ -68,6 +68,13 @@
height: calc(var(--vh) * 55 + 100px);
}
.noForwardFooter {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
}
.header {
position: absolute;
@ -112,7 +119,7 @@
}
.description {
padding: 0 5%;
padding: 0 max(5%, 2rem);
font-size: 1rem;
font-weight: var(--font-weight-normal);

View File

@ -30,6 +30,7 @@ import usePreviousDeprecated from '../../../hooks/usePreviousDeprecated';
import SliderDots from '../../common/SliderDots';
import Button from '../../ui/Button';
import PremiumLimitPreview from './common/PremiumLimitPreview';
import PremiumFeaturePreviewNoForwards from './previews/PremiumFeaturePreviewNoForwards';
import PremiumFeaturePreviewStickers from './previews/PremiumFeaturePreviewStickers';
import PremiumFeaturePreviewStories from './previews/PremiumFeaturePreviewStories';
import PremiumFeaturePreviewVideo from './previews/PremiumFeaturePreviewVideo';
@ -56,6 +57,7 @@ export const PREMIUM_FEATURE_TITLES: Record<ApiPremiumSection, string> = {
message_privacy: 'PremiumPreviewMessagePrivacy',
effects: 'Premium.MessageEffects',
todo: 'PremiumPreviewTodo',
pm_noforwards: 'PremiumPreviewNoForwards',
};
export const PREMIUM_FEATURE_DESCRIPTIONS: Record<ApiPremiumSection, string> = {
@ -78,6 +80,7 @@ export const PREMIUM_FEATURE_DESCRIPTIONS: Record<ApiPremiumSection, string> = {
message_privacy: 'PremiumPreviewMessagePrivacyDescription',
effects: 'Premium.MessageEffectsInfo',
todo: 'PremiumPreviewTodoDescription',
pm_noforwards: 'PremiumPreviewNoForwardsDescription',
};
const LIMITS_TITLES: Record<ApiLimitTypeForPromo, string> = {
@ -221,7 +224,8 @@ const PremiumFeatureModal: FC<OwnProps> = ({
});
const currentSection = filteredSections[currentSlideIndex];
const hasHeaderBackdrop = currentSection !== 'double_limits' && currentSection !== 'stories';
const hasHeaderBackdrop = currentSection !== 'double_limits' &&
currentSection !== 'stories' && currentSection !== 'pm_noforwards';
return (
<div className={styles.root}>
@ -289,16 +293,31 @@ const PremiumFeatureModal: FC<OwnProps> = ({
);
}
if (section === 'pm_noforwards') {
return (
<div className={buildClassName(styles.slide, styles.noForward)}>
<PremiumFeaturePreviewNoForwards />
<div className={styles.noForwardFooter}>
<h1 className={styles.title}>
{lang(PREMIUM_FEATURE_TITLES.pm_noforwards as keyof LangPair)}
</h1>
<div className={styles.description}>
{lang(PREMIUM_FEATURE_DESCRIPTIONS.pm_noforwards as keyof LangPair)}
</div>
</div>
</div>
);
}
const i = promo.videoSections.indexOf(section);
if (i === -1) return undefined;
const shouldUseNewLang = section === 'todo';
return (
<div className={styles.slide}>
<div className={styles.frame}>
<PremiumFeaturePreviewVideo
isActive={currentSlideIndex === index}
videoId={promo.videos[i].id}
videoThumbnail={promo.videos[i].thumbnail}
videoId={i !== -1 ? promo.videos[i].id : undefined}
videoThumbnail={i !== -1 ? promo.videos[i].thumbnail : undefined}
isDown={PREMIUM_BOTTOM_VIDEOS.includes(section)}
index={index}
isReverseAnimation={index === reverseAnimationSlideIndex}
@ -336,7 +355,7 @@ const PremiumFeatureModal: FC<OwnProps> = ({
)}
>
<SliderDots
length={PREMIUM_FEATURE_SECTIONS.length}
length={filteredSections.length}
active={currentSlideIndex}
onSelectSlide={handleSelectSlide}
/>

View File

@ -57,6 +57,7 @@ import PremiumFile from '../../../assets/premium/PremiumFile.svg';
import PremiumLastSeen from '../../../assets/premium/PremiumLastSeen.svg';
import PremiumLimits from '../../../assets/premium/PremiumLimits.svg';
import PremiumMessagePrivacy from '../../../assets/premium/PremiumMessagePrivacy.svg';
import PremiumNoforwards from '../../../assets/premium/PremiumNoForwardsPrivacy.svg';
import PremiumReactions from '../../../assets/premium/PremiumReactions.svg';
import PremiumSpeed from '../../../assets/premium/PremiumSpeed.svg';
import PremiumStatus from '../../../assets/premium/PremiumStatus.svg';
@ -89,6 +90,7 @@ const PREMIUM_FEATURE_COLOR_ICONS: Record<ApiPremiumSection, string> = {
message_privacy: PremiumMessagePrivacy,
effects: PremiumEffects,
todo: PremiumBadge,
pm_noforwards: PremiumNoforwards,
};
export type OwnProps = {
@ -442,7 +444,7 @@ const PremiumMainModal: FC<OwnProps & StateProps> = ({
</div>
<div className={buildClassName(styles.list, isPremium && styles.noButton)}>
{filteredSections.map((section, index) => {
const shouldUseNewLang = section === 'todo';
const shouldUseNewLang = section === 'todo' || section === 'pm_noforwards';
return (
<PremiumFeatureItem
key={section}

View File

@ -0,0 +1,45 @@
.root {
display: flex;
flex-direction: column;
gap: 4rem;
padding-block: 3.5rem;
}
.header {
display: flex;
flex-direction: column;
gap: 0.75rem;
align-items: center;
}
.listItems {
display: flex;
flex-direction: column;
gap: 0.5rem;
margin-inline: 1rem;
}
.listItem {
:global(.ListItem-button) {
align-items: flex-start;
padding-inline: 1.5rem;
}
:global(.ListItem-main-icon) {
margin-top: 0.875rem;
margin-inline-end: 0.875rem;
font-size: 1.5rem;
color: var(--accent-color);
}
:global(.multiline-item .subtitle) {
margin-top: 0.125rem;
font-size: 1rem;
line-height: 1.375rem;
}
}
.listItemTitle {
font-size: 1rem;
font-weight: var(--font-weight-medium);
}

View File

@ -0,0 +1,54 @@
import { memo, useMemo } from '../../../../lib/teact/teact';
import type { TableAboutData } from '../../../modals/common/TableAboutModal';
import buildClassName from '../../../../util/buildClassName';
import { LOCAL_TGS_PREVIEW_URLS, LOCAL_TGS_URLS } from '../../../common/helpers/animatedAssets';
import useLang from '../../../../hooks/useLang';
import AnimatedIconWithPreview from '../../../common/AnimatedIconWithPreview';
import ListItem from '../../../ui/ListItem';
import styles from './PremiumFeaturePreviewNoForwards.module.scss';
const ICON_SIZE = 100;
const PremiumFeaturePreviewNoForwards = () => {
const lang = useLang();
const listItemData = useMemo(() => {
return [
['no-share', lang('NoForwardingTitle'), lang('NoForwardingDescription')],
['no-download', lang('NoSavingTitle'), lang('NoSavingDescription')],
] satisfies TableAboutData;
}, [lang]);
return (
<div className={styles.root}>
<div className={styles.header}>
<AnimatedIconWithPreview
size={ICON_SIZE}
tgsUrl={LOCAL_TGS_URLS.HandStop}
previewUrl={LOCAL_TGS_PREVIEW_URLS.HandStop}
noLoop
/>
</div>
<div className={styles.listItems}>
{listItemData.map(([icon, title, subtitle]) => (
<ListItem
isStatic
multiline
icon={icon}
className={styles.listItem}
>
<span className={buildClassName('title', styles.listItemTitle)}>{title}</span>
<span className="subtitle">{subtitle}</span>
</ListItem>
))}
</div>
</div>
);
};
export default memo(PremiumFeaturePreviewNoForwards);

View File

@ -133,6 +133,8 @@ type StateProps = {
savedDialog?: ApiChat;
disallowedGifts?: ApiDisallowedGifts;
isAccountFrozen?: boolean;
noForwardsMyEnabled?: boolean;
noForwardsPeerEnabled?: boolean;
};
const CLOSE_MENU_ANIMATION_DURATION = 200;
@ -184,6 +186,8 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
canShowBoostModal,
disallowedGifts,
isAccountFrozen,
noForwardsMyEnabled,
noForwardsPeerEnabled,
channelMonoforumId,
onJoinRequestsClick,
onSubscribeChannel,
@ -220,6 +224,8 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
openBoostModal,
reportMessages,
showNotification,
toggleNoForwards,
openDisableSharingAboutModal,
} = getActions();
const oldLang = useOldLang();
@ -495,6 +501,21 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
closeMenu();
});
const handleToggleNoForwards = useLastCallback(() => {
closeMenu();
if (isAccountFrozen) {
openFrozenAccountModal();
return;
}
if (noForwardsMyEnabled || noForwardsPeerEnabled) {
toggleNoForwards({ userId: chatId, isEnabled: false });
return;
}
openDisableSharingAboutModal({ userId: chatId });
});
const handleSendChannelMessage = useLastCallback(() => {
openChat({ id: channelMonoforumId });
closeMenu();
@ -801,6 +822,14 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
{isBlocked ? oldLang('BotRestart') : oldLang('Bot.Stop')}
</MenuItem>
)}
{isPrivate && !isChatWithSelf && !isBot && (
<MenuItem
icon={noForwardsMyEnabled || noForwardsPeerEnabled ? 'allow-share' : 'no-share'}
onClick={handleToggleNoForwards}
>
{noForwardsMyEnabled || noForwardsPeerEnabled ? lang('EnableSharing') : lang('DisableSharing')}
</MenuItem>
)}
{isPrivate && !isChatWithSelf && !isBot && (
<MenuItem
icon={isBlocked ? 'user' : 'hand-stop'}
@ -906,6 +935,8 @@ export default memo(withGlobal<OwnProps>(
savedDialog,
disallowedGifts: userFullInfo?.disallowedGifts,
isAccountFrozen,
noForwardsMyEnabled: userFullInfo?.noForwardsMyEnabled,
noForwardsPeerEnabled: userFullInfo?.noForwardsPeerEnabled,
};
},
)(HeaderMenuContainer));

View File

@ -16,6 +16,7 @@ import {
type ApiMessage,
type ApiPeer,
type KeyboardButtonGiftOffer,
type KeyboardButtonNoForwardsRequest,
MAIN_THREAD_ID,
} from '../../../api/types';
import { MediaViewerOrigin } from '../../../types';
@ -60,6 +61,7 @@ import ActionMessageText from './ActionMessageText';
import ChannelPhoto from './actions/ChannelPhoto';
import Gift from './actions/Gift';
import GiveawayPrize from './actions/GiveawayPrize';
import NoForwardsRequest from './actions/NoForwardsRequest';
import StarGift from './actions/StarGift';
import StarGiftPurchaseOffer from './actions/StarGiftPurchaseOffer';
import StarGiftUnique from './actions/StarGiftUnique';
@ -103,6 +105,7 @@ type StateProps = {
isResizingContainer?: boolean;
scrollTargetPosition?: ScrollTargetPosition;
isAccountFrozen?: boolean;
noForwardsRequestExpirePeriod: number;
};
const SINGLE_LINE_ACTIONS = new Set<ApiMessageAction['type']>([
@ -114,7 +117,7 @@ const SINGLE_LINE_ACTIONS = new Set<ApiMessageAction['type']>([
'unsupported',
]);
const HIDDEN_TEXT_ACTIONS = new Set<ApiMessageAction['type']>(['giftCode', 'prizeStars',
'suggestProfilePhoto', 'suggestedPostApproval', 'starGiftPurchaseOffer']);
'suggestProfilePhoto', 'suggestedPostApproval', 'starGiftPurchaseOffer', 'noForwardsRequest']);
const ActionMessage = ({
message,
@ -138,6 +141,7 @@ const ActionMessage = ({
isResizingContainer,
scrollTargetPosition,
isAccountFrozen,
noForwardsRequestExpirePeriod,
observeIntersectionForBottom,
observeIntersectionForLoading,
observeIntersectionForPlaying,
@ -159,6 +163,7 @@ const ActionMessage = ({
openGiftOfferAcceptModal,
declineStarGiftOffer,
showNotification,
toggleNoForwards,
} = getActions();
const ref = useRef<HTMLDivElement>();
@ -182,7 +187,12 @@ const ActionMessage = ({
const shouldRenderGiftOfferButtons = action.type === 'starGiftPurchaseOffer'
&& !message.isOutgoing && !action.isAccepted && !action.isDeclined && !hasGiftOfferExpired;
const shouldRenderInlineButtons = shouldRenderGiftOfferButtons;
const hasNoForwardsRequestExpired = action.type === 'noForwardsRequest'
&& (message.date + noForwardsRequestExpirePeriod) <= getServerTime();
const shouldRenderNoForwardsButtons = action.type === 'noForwardsRequest'
&& !message.isOutgoing && !action.isExpired && !hasNoForwardsRequestExpired;
const shouldRenderInlineButtons = shouldRenderGiftOfferButtons || shouldRenderNoForwardsButtons;
const shouldSkipRender = isInsideTopic && action.type === 'topicCreate';
@ -204,6 +214,21 @@ const ActionMessage = ({
],
], [lang]);
const noForwardsInlineButtons: KeyboardButtonNoForwardsRequest[][] = useMemo(() => [
[
{
type: 'noForwardsRequest',
buttonType: 'reject',
text: lang('NoForwardsRequestReject'),
},
{
type: 'noForwardsRequest',
buttonType: 'accept',
text: lang('NoForwardsRequestAccept'),
},
],
], [lang]);
const [isRejectOfferDialogOpen, openRejectOfferDialog, closeRejectOfferDialog] = useFlag(false);
const handleInlineButtonClick = useLastCallback((button: ApiKeyboardButton) => {
@ -220,6 +245,15 @@ const ActionMessage = ({
} else if (button.buttonType === 'reject') {
openRejectOfferDialog();
}
} else if (button.type === 'noForwardsRequest') {
if (action.type === 'noForwardsRequest') {
const isAccept = button.buttonType === 'accept';
toggleNoForwards({
userId: chatId,
isEnabled: isAccept ? action.newValue : action.prevValue,
requestMsgId: id,
});
}
}
});
@ -522,6 +556,13 @@ const ActionMessage = ({
/>
);
case 'noForwardsRequest':
return (
<NoForwardsRequest
message={message}
/>
);
case 'suggestedPostApproval':
if (action.isBalanceTooLow) {
return (
@ -614,13 +655,20 @@ const ActionMessage = ({
{(fullContent || shouldRenderInlineButtons) && (
<div className={styles.contentWrapper}>
{fullContent}
{shouldRenderInlineButtons && (
{shouldRenderGiftOfferButtons && (
<InlineButtons
className={styles.inlineButtons}
inlineButtons={giftOfferInlineButtons}
onClick={handleInlineButtonClick}
/>
)}
{shouldRenderNoForwardsButtons && (
<InlineButtons
className={styles.inlineButtons}
inlineButtons={noForwardsInlineButtons}
onClick={handleInlineButtonClick}
/>
)}
</div>
)}
{contextMenuAnchor && (
@ -703,6 +751,7 @@ export default memo(withGlobal<OwnProps>(
isResizingContainer,
scrollTargetPosition,
isAccountFrozen,
noForwardsRequestExpirePeriod: global.appConfig.noForwardsRequestExpirePeriod,
};
},
)(ActionMessage));

View File

@ -1059,6 +1059,25 @@ const ActionMessageText = ({
case 'phoneCall': // Rendered as a regular message, but considered an action for the summary
return lang(getCallMessageKey(action, isOutgoing));
case 'noForwardsToggle': {
const { prevValue, newValue } = action;
if (newValue && newValue === prevValue) {
return lang('ActionSharingStillDisabled');
}
return translateWithYou(
lang,
newValue ? 'ActionSharingDisabled' : 'ActionSharingEnabled',
isOutgoing,
{ from: senderLink },
);
}
case 'noForwardsRequest': {
return isOutgoing
? lang('NoForwardsRequestYouTitle')
: lang('NoForwardsRequestTitle', { user: senderLink }, { withNodes: true });
}
case 'newCreatorPending': {
const { newCreatorId } = action;
const newCreator = selectPeer(global, newCreatorId);

View File

@ -68,6 +68,7 @@ import {
selectStickerSet,
selectTopic,
selectUser,
selectUserFullInfo,
selectUserStatus,
selectWebPageFromMessage,
} from '../../../global/selectors';
@ -162,6 +163,8 @@ type StateProps = {
userFullName?: string;
canGift?: boolean;
savedDialogId?: string;
noForwardsMyEnabled?: boolean;
noForwardsPeerEnabled?: boolean;
};
const selection = window.getSelection();
@ -232,6 +235,8 @@ const ContextMenuContainer: FC<OwnProps & StateProps> = ({
canGift,
className,
savedDialogId,
noForwardsMyEnabled,
noForwardsPeerEnabled,
onClose,
onCloseAnimationEnd,
}) => {
@ -277,6 +282,11 @@ const ContextMenuContainer: FC<OwnProps & StateProps> = ({
const oldLang = useOldLang();
const lang = useLang();
const noForwardsNotice = noForwardsPeerEnabled
? lang('ContextMenuNoForwardsPeer', { name: userFullName })
: (noForwardsMyEnabled ? lang('ContextMenuNoForwardsYou') : undefined);
const { ref: containerRef } = useShowTransition({
isOpen,
onCloseAnimationEnd,
@ -774,6 +784,7 @@ const ContextMenuContainer: FC<OwnProps & StateProps> = ({
onSelectLanguage={handleSelectLanguage}
userFullName={userFullName}
canGift={canGift}
noForwardsNotice={noForwardsNotice}
/>
<PinMessageModal
isOpen={isPinModalOpen}
@ -805,6 +816,7 @@ export default memo(withGlobal<OwnProps>(
const chatFullInfo = !isPrivate ? selectChatFullInfo(global, message.chatId) : undefined;
const user = selectUser(global, message.chatId);
const userFullName = user && getUserFullName(user);
const userFullInfo = isPrivate ? selectUserFullInfo(global, message.chatId) : undefined;
const {
seenByExpiresAt, seenByMaxChatMembers, maxUniqueReactions, readDateExpiresAt,
@ -970,6 +982,8 @@ export default memo(withGlobal<OwnProps>(
canGift,
savedDialogId,
webPage,
noForwardsMyEnabled: userFullInfo?.noForwardsMyEnabled,
noForwardsPeerEnabled: userFullInfo?.noForwardsPeerEnabled,
};
},
)(ContextMenuContainer));

View File

@ -75,4 +75,8 @@
top: 0;
transform: translateY(calc(-100% - 0.5rem));
}
.no-forwards-notice {
min-width: 12rem;
}
}

View File

@ -136,6 +136,7 @@ type OwnProps = {
onReactionPickerOpen?: (position: IAnchorPosition) => void;
userFullName?: string;
canGift?: boolean;
noForwardsNotice?: string;
};
const SCROLLBAR_WIDTH = 10;
@ -230,6 +231,7 @@ const MessageContextMenu: FC<OwnProps> = ({
onSelectLanguage,
userFullName,
canGift,
noForwardsNotice,
}) => {
const {
showNotification, openStickerSet, openCustomEmojiSets, loadStickers, openGiftModal,
@ -515,7 +517,7 @@ const MessageContextMenu: FC<OwnProps> = ({
</MenuItem>
</>
)}
{(canLoadReadDate || shouldRenderShowWhen || isEdited) && (
{(canLoadReadDate || shouldRenderShowWhen || isEdited || noForwardsNotice) && (
<MenuSeparator size={hasCustomEmoji ? 'thin' : 'thick'} />
)}
{(canLoadReadDate || shouldRenderShowWhen) && (
@ -531,6 +533,11 @@ const MessageContextMenu: FC<OwnProps> = ({
message={message}
/>
)}
{noForwardsNotice && (
<MenuItem disabled withWrap className="no-forwards-notice">
{noForwardsNotice}
</MenuItem>
)}
</div>
</Menu>
);

View File

@ -0,0 +1,27 @@
.root {
padding: 0.75rem 1rem;
text-align: center;
}
.title {
line-height: 1.125rem;
}
.list {
display: flex;
flex-direction: column;
gap: 0.5rem;
align-items: flex-start;
width: 100%;
}
.item {
display: flex;
gap: 0.375rem;
align-items: center;
}
.checkIcon {
font-size: 1rem;
}

View File

@ -0,0 +1,72 @@
import { memo } from '../../../../lib/teact/teact';
import { withGlobal } from '../../../../global';
import type { ApiMessage, ApiPeer } from '../../../../api/types';
import { getPeerTitle } from '../../../../global/helpers/peers';
import { selectSender } from '../../../../global/selectors';
import buildClassName from '../../../../util/buildClassName';
import { renderPeerLink } from '../helpers/messageActions';
import useLang from '../../../../hooks/useLang';
import Icon from '../../../common/icons/Icon';
import actionStyles from '../ActionMessage.module.scss';
import styles from './NoForwardsRequest.module.scss';
type OwnProps = {
message: ApiMessage;
};
type StateProps = {
sender?: ApiPeer;
};
const SHARING_FEATURES = [
'NoForwardsRequestForwarding',
'NoForwardsRequestSaving',
'NoForwardsRequestCopying',
] as const;
const NoForwardsRequest = ({
message,
sender,
}: OwnProps & StateProps) => {
const lang = useLang();
const { isOutgoing } = message;
const peerTitle = sender && getPeerTitle(lang, sender);
const peerLink = renderPeerLink(sender?.id, peerTitle || lang('ActionFallbackUser'));
const title = isOutgoing
? lang('NoForwardsRequestYouTitle')
: lang('NoForwardsRequestTitle', { user: peerLink }, { withNodes: true, withMarkdown: false });
return (
<div className={buildClassName(actionStyles.contentBox, styles.root)}>
<div className={styles.title}>
{title}
</div>
<div className={styles.list}>
{SHARING_FEATURES.map((featureKey) => (
<div key={featureKey} className={styles.item}>
<Icon name="check" className={styles.checkIcon} />
<span>{lang(featureKey)}</span>
</div>
))}
</div>
</div>
);
};
export default memo(withGlobal<OwnProps>(
(global, { message }): Complete<StateProps> => {
const sender = selectSender(global, message);
return {
sender,
};
},
)(NoForwardsRequest));

View File

@ -18,6 +18,7 @@ import ChatlistModal from './chatlist/ChatlistModal.async';
import CocoonModal from './cocoon/CocoonModal.async';
import CollectibleInfoModal from './collectible/CollectibleInfoModal.async';
import DeleteAccountModal from './deleteAccount/DeleteAccountModal.async';
import DisableSharingAboutModal from './disableSharing/DisableSharingAboutModal.async';
import EmojiStatusAccessModal from './emojiStatusAccess/EmojiStatusAccessModal.async';
import FrozenAccountModal from './frozenAccount/FrozenAccountModal.async';
import AboutStarGiftModal from './gift/AboutStarGiftModal.async';
@ -134,6 +135,7 @@ type ModalKey = keyof Pick<TabState,
'giftDescriptionRemoveModal' |
'giftOfferAcceptModal' |
'chatRefundModal' |
'disableSharingAboutModal' |
'priceConfirmModal' |
'isFrozenAccountModalOpen' |
'deleteAccountModal' |
@ -219,6 +221,7 @@ const MODALS: ModalRegistry = {
giftDescriptionRemoveModal: GiftDescriptionRemoveModal,
giftOfferAcceptModal: GiftOfferAcceptModal,
chatRefundModal: ChatRefundModal,
disableSharingAboutModal: DisableSharingAboutModal,
priceConfirmModal: PriceConfirmModal,
isFrozenAccountModalOpen: FrozenAccountModal,
deleteAccountModal: DeleteAccountModal,

View File

@ -0,0 +1,14 @@
import type { OwnProps } from './DisableSharingAboutModal';
import { Bundles } from '../../../util/moduleLoader';
import useModuleLoader from '../../../hooks/useModuleLoader';
const DisableSharingAboutModalAsync = (props: OwnProps) => {
const { modal } = props;
const DisableSharingAboutModal = useModuleLoader(Bundles.Extra, 'DisableSharingAboutModal', !modal);
return DisableSharingAboutModal ? <DisableSharingAboutModal {...props} /> : undefined;
};
export default DisableSharingAboutModalAsync;

View File

@ -0,0 +1,23 @@
.header {
display: flex;
flex-direction: column;
gap: 0.75rem;
align-items: center;
}
.title {
margin: 0;
margin-bottom: 0.5rem;
font-size: 1.25rem;
font-weight: var(--font-weight-semibold);
}
.footer {
display: flex;
align-self: stretch;
margin-top: 1rem;
}
.unlockIcon {
font-size: 1.25rem;
}

View File

@ -0,0 +1,127 @@
import { memo, useMemo } from '../../../lib/teact/teact';
import { getActions, withGlobal } from '../../../global';
import type { TabState } from '../../../global/types';
import { selectIsCurrentUserPremium } from '../../../global/selectors';
import { LOCAL_TGS_PREVIEW_URLS, LOCAL_TGS_URLS } from '../../common/helpers/animatedAssets';
import useCurrentOrPrev from '../../../hooks/useCurrentOrPrev';
import useLang from '../../../hooks/useLang';
import useLastCallback from '../../../hooks/useLastCallback';
import AnimatedIconWithPreview from '../../common/AnimatedIconWithPreview';
import Button from '../../ui/Button';
import TableAboutModal, { type TableAboutData } from '../common/TableAboutModal';
import styles from './DisableSharingAboutModal.module.scss';
const ICON_SIZE = 100;
export type OwnProps = {
modal: TabState['disableSharingAboutModal'];
};
type StateProps = {
isCurrentUserPremium?: boolean;
};
const DisableSharingAboutModal = ({
modal,
isCurrentUserPremium,
}: OwnProps & StateProps) => {
const {
closeDisableSharingAboutModal,
toggleNoForwards,
openPremiumModal,
} = getActions();
const lang = useLang();
const isOpen = Boolean(modal);
const renderingModal = useCurrentOrPrev(modal);
const userId = renderingModal?.userId;
const handleClose = useLastCallback(() => {
closeDisableSharingAboutModal();
});
const handleDisableSharing = useLastCallback(() => {
if (userId) {
toggleNoForwards({ userId, isEnabled: true });
}
closeDisableSharingAboutModal();
});
const handleOpenPremium = useLastCallback(() => {
closeDisableSharingAboutModal();
openPremiumModal({ initialSection: 'pm_noforwards' });
});
const header = useMemo(() => {
return (
<div className={styles.header}>
<AnimatedIconWithPreview
size={ICON_SIZE}
tgsUrl={LOCAL_TGS_URLS.HandStop}
previewUrl={LOCAL_TGS_PREVIEW_URLS.HandStop}
noLoop
/>
<h3 className={styles.title}>{lang('DisableSharing')}</h3>
</div>
);
}, [lang]);
const listItemData = useMemo(() => {
return [
['no-share', lang('NoForwardingTitle'), lang('NoForwardingDescription')],
['no-download', lang('NoSavingTitle'), lang('NoSavingDescription')],
] satisfies TableAboutData;
}, [lang]);
const footer = useMemo(() => {
if (isCurrentUserPremium) {
return (
<div className={styles.footer}>
<Button
onClick={handleDisableSharing}
noForcedUpperCase
>
{lang('DisableSharing')}
</Button>
</div>
);
}
return (
<div className={styles.footer}>
<Button
onClick={handleOpenPremium}
iconName="unlock-badge"
iconClassName={styles.unlockIcon}
noForcedUpperCase
>
{lang('UnlockButtonTitle')}
</Button>
</div>
);
}, [isCurrentUserPremium, lang, handleDisableSharing, handleOpenPremium]);
return (
<TableAboutModal
isOpen={isOpen}
header={header}
listItemData={listItemData}
footer={footer}
onClose={handleClose}
/>
);
};
export default memo(withGlobal<OwnProps>(
(global): Complete<StateProps> => {
return {
isCurrentUserPremium: selectIsCurrentUserPremium(global),
};
},
)(DisableSharingAboutModal));

View File

@ -68,6 +68,13 @@
&.disabled {
cursor: var(--custom-cursor, default) !important;
opacity: 0.5 !important;
&:hover,
&:focus,
&:active {
transform: none !important;
background-color: transparent !important;
}
}
&.destructive {

View File

@ -127,7 +127,7 @@ const MenuItem = (props: MenuItemProps) => {
return (
<div
role="menuitem"
tabIndex={0}
tabIndex={disabled ? -1 : 0}
className={fullClassName}
onClick={handleClick}
onKeyDown={handleKeyDown}

View File

@ -417,6 +417,7 @@ export const PREMIUM_FEATURE_SECTIONS = [
'message_privacy',
'effects',
'todo',
'pm_noforwards',
] as const;
export const PREMIUM_BOTTOM_VIDEOS: ApiPremiumSection[] = [

View File

@ -629,3 +629,14 @@ addActionHandler('markBotVerificationInfoShown', (global, actions, payload): Act
setGlobal(global);
});
addActionHandler('toggleNoForwards', async (global, actions, payload): Promise<void> => {
const { userId, isEnabled, requestMsgId } = payload;
const user = selectUser(global, userId);
if (!user) {
return;
}
await callApi('toggleNoForwards', { user, isEnabled, requestMsgId });
});

View File

@ -73,6 +73,7 @@ import {
updateThreadInfoMessagesCount,
updateThreadReadState,
} from '../../reducers/threads';
import { updateUserFullInfo } from '../../reducers/users';
import {
selectCanAnimateSnapEffect,
selectChat,
@ -179,6 +180,19 @@ addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => {
} else {
global = updateChatLastMessage(global, chatId, newMessage);
}
if (!isLocal && message.isOutgoing && message.content?.action?.type === 'noForwardsRequest') {
const currentMessageList = selectCurrentMessageList(global, tabId);
if (currentMessageList?.chatId === chatId && currentMessageList.type === 'thread') {
actions.focusMessage({
chatId,
threadId: MAIN_THREAD_ID,
messageId: message.id,
noHighlight: true,
tabId,
});
}
}
});
if (poll) {
@ -201,6 +215,37 @@ addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => {
global = replaceThreadLocalStateParam(global, chatId, threadId, 'typingDraftIdByRandomId', undefined);
}
if (!isLocal && message.content?.action?.type === 'noForwardsToggle') {
const { newValue } = message.content.action;
if (message.isOutgoing) {
global = updateUserFullInfo(global, chatId, {
noForwardsMyEnabled: newValue,
});
const tabId = getCurrentTabId();
if (selectCurrentMessageList(global, tabId)?.chatId === chatId) {
actions.showNotification({
icon: newValue ? 'hand-stop-filled' : 'select-filled',
message: { key: newValue ? 'NotificationSharingDisabled' : 'NotificationSharingEnabled' },
tabId,
});
}
} else {
const originalMessage = replyInfo?.replyToMsgId ?
selectChatMessage(global, chatId, replyInfo.replyToMsgId) : undefined;
// When peer accepted user request to enable sharing
if (originalMessage?.isOutgoing && !newValue) {
global = updateUserFullInfo(global, chatId, {
noForwardsMyEnabled: false,
});
} else {
global = updateUserFullInfo(global, chatId, {
noForwardsPeerEnabled: newValue,
});
}
}
}
setGlobal(global);
// Reload dialogs if chat is not present in the list

View File

@ -65,6 +65,16 @@ addActionHandler('closeSuggestedStatusModal', (global, actions, payload): Action
addTabStateResetterAction('closeChatRefundModal', 'chatRefundModal');
addActionHandler('openDisableSharingAboutModal', (global, actions, payload): ActionReturnType => {
const { userId, tabId = getCurrentTabId() } = payload;
return updateTabState(global, {
disableSharingAboutModal: { userId },
}, tabId);
});
addTabStateResetterAction('closeDisableSharingAboutModal', 'disableSharingAboutModal');
addActionHandler('openProfileRatingModal', (global, actions, payload): ActionReturnType => {
const { userId, level, tabId = getCurrentTabId() } = payload;

View File

@ -97,7 +97,7 @@ import {
} from './threads';
import { selectTopic, selectTopicFromMessage } from './topics';
import {
selectBot, selectUser, selectUserStatus,
selectBot, selectIsUserChatProtected, selectUser, selectUserStatus,
} from './users';
export function selectCurrentMessageList<T extends GlobalState>(
@ -1141,11 +1141,19 @@ export function selectIsMessageProtected<T extends GlobalState>(global: T, messa
}
export function selectIsChatProtected<T extends GlobalState>(global: T, chatId: string) {
return selectChat(global, chatId)?.isProtected || false;
const chat = selectChat(global, chatId);
if (!chat) return false;
if (chat.isProtected || (isUserId(chatId) && selectIsUserChatProtected(global, chatId))) {
return true;
}
return false;
}
export function selectHasProtectedMessage<T extends GlobalState>(global: T, chatId: string, messageIds?: number[]) {
if (selectChat(global, chatId)?.isProtected) {
if (selectIsChatProtected(global, chatId)) {
return true;
}
@ -1159,7 +1167,7 @@ export function selectHasProtectedMessage<T extends GlobalState>(global: T, chat
}
export function selectCanForwardMessages<T extends GlobalState>(global: T, chatId: string, messageIds?: number[]) {
if (selectChat(global, chatId)?.isProtected) {
if (selectIsChatProtected(global, chatId)) {
return false;
}

View File

@ -29,6 +29,13 @@ export function selectIsUserBlocked<T extends GlobalState>(global: T, userId: st
return selectUserFullInfo(global, userId)?.isBlocked;
}
export function selectIsUserChatProtected<T extends GlobalState>(global: T, userId: string) {
const fullInfo = selectUserFullInfo(global, userId);
if (!fullInfo) return undefined;
return Boolean(fullInfo.noForwardsMyEnabled || fullInfo.noForwardsPeerEnabled);
}
export function selectIsCurrentUserPremium<T extends GlobalState>(global: T) {
if (!global.currentUserId) return false;

View File

@ -315,6 +315,11 @@ export interface ActionPayloads {
markBotVerificationInfoShown: {
peerId: string;
};
toggleNoForwards: {
userId: string;
isEnabled: boolean;
requestMsgId?: number;
};
// Message search
openMiddleSearch: {
@ -1938,6 +1943,10 @@ export interface ActionPayloads {
userId: string;
} & WithTabId;
closeChatRefundModal: WithTabId | undefined;
openDisableSharingAboutModal: {
userId: string;
} & WithTabId;
closeDisableSharingAboutModal: WithTabId | undefined;
openProfileRatingModal: {
userId: string;
level: number;

View File

@ -719,6 +719,10 @@ export type TabState = {
starsToRefund: number;
};
disableSharingAboutModal?: {
userId: string;
};
limitReachedModal?: {
limit: ApiLimitTypeWithModal;
};

View File

@ -110,6 +110,7 @@ export const DEFAULT_APP_CONFIG: ApiAppConfig = {
'animated_userpics',
'premium_stickers',
'effects',
'pm_noforwards',
],
isPremiumPurchaseBlocked: false,
maxUniqueReactions: 11,
@ -129,6 +130,7 @@ export const DEFAULT_APP_CONFIG: ApiAppConfig = {
starsSuggestedPostFutureMin: 300,
starsSuggestedPostFutureMax: 2678400,
starsSuggestedPostCommissionPermille: 850,
noForwardsRequestExpirePeriod: 86400,
tonSuggestedPostCommissionPermille: 850,
todoItemLengthMax: 64,
todoItemsMax: 30,

File diff suppressed because it is too large Load Diff

View File

@ -16,327 +16,332 @@
}
$icons-map: (
"active-sessions": "\f101",
"add-caption": "\f102",
"add-filled": "\f103",
"add-one-badge": "\f104",
"add-user-filled": "\f105",
"add-user": "\f106",
"add": "\f107",
"admin": "\f108",
"allow-speak": "\f109",
"animals": "\f10a",
"animations": "\f10b",
"archive-filled": "\f10c",
"archive-from-main": "\f10d",
"archive-to-main": "\f10e",
"archive": "\f10f",
"arrow-down-circle": "\f110",
"arrow-down": "\f111",
"arrow-left": "\f112",
"arrow-right": "\f113",
"ask-support": "\f114",
"attach": "\f115",
"auction-drop": "\f116",
"auction-filled": "\f117",
"auction-next-round": "\f118",
"auction": "\f119",
"author-hidden": "\f11a",
"avatar-archived-chats": "\f11b",
"avatar-deleted-account": "\f11c",
"avatar-saved-messages": "\f11d",
"bold": "\f11e",
"boost-craft-chance": "\f11f",
"boost-outline": "\f120",
"boost": "\f121",
"boostcircle": "\f122",
"boosts": "\f123",
"bot-command": "\f124",
"bot-commands-filled": "\f125",
"bots": "\f126",
"brush": "\f127",
"bug": "\f128",
"calendar-filter": "\f129",
"calendar": "\f12a",
"camera-add": "\f12b",
"camera": "\f12c",
"car": "\f12d",
"card": "\f12e",
"cash-circle": "\f12f",
"channel-filled": "\f130",
"channel": "\f131",
"channelviews": "\f132",
"chat-badge": "\f133",
"chats-badge": "\f134",
"check": "\f135",
"clock-edit": "\f136",
"clock": "\f137",
"close-circle": "\f138",
"close-topic": "\f139",
"close": "\f13a",
"closed-gift": "\f13b",
"cloud-download": "\f13c",
"collapse-modal": "\f13d",
"collapse": "\f13e",
"colorize": "\f13f",
"combine-craft": "\f140",
"comments-sticker": "\f141",
"comments": "\f142",
"copy-media": "\f143",
"copy": "\f144",
"craft": "\f145",
"crop": "\f146",
"crown-take-off-outline": "\f147",
"crown-take-off": "\f148",
"crown-wear-outline": "\f149",
"crown-wear": "\f14a",
"darkmode": "\f14b",
"data": "\f14c",
"delete-filled": "\f14d",
"delete-left": "\f14e",
"delete-user": "\f14f",
"delete": "\f150",
"diamond": "\f151",
"document": "\f152",
"double-badge": "\f153",
"down": "\f154",
"download": "\f155",
"dropdown-arrows": "\f156",
"eats": "\f157",
"edit": "\f158",
"email": "\f159",
"enter": "\f15a",
"expand-modal": "\f15b",
"expand": "\f15c",
"eye-crossed-outline": "\f15d",
"eye-crossed": "\f15e",
"eye-outline": "\f15f",
"eye": "\f160",
"favorite-filled": "\f161",
"favorite": "\f162",
"file-badge": "\f163",
"flag": "\f164",
"flip": "\f165",
"folder-badge": "\f166",
"folder-tabs-bot": "\f167",
"folder-tabs-channel": "\f168",
"folder-tabs-chat": "\f169",
"folder-tabs-chats": "\f16a",
"folder-tabs-folder": "\f16b",
"folder-tabs-group": "\f16c",
"folder-tabs-star": "\f16d",
"folder-tabs-user": "\f16e",
"folder": "\f16f",
"fontsize": "\f170",
"forums": "\f171",
"forward": "\f172",
"fragment": "\f173",
"frozen-time": "\f174",
"fullscreen": "\f175",
"gifs": "\f176",
"gift-transfer-inline": "\f177",
"gift": "\f178",
"group-filled": "\f179",
"group": "\f17a",
"grouped-disable": "\f17b",
"grouped": "\f17c",
"hand-stop": "\f17d",
"hashtag": "\f17e",
"hd-photo": "\f17f",
"heart-outline": "\f180",
"heart": "\f181",
"help": "\f182",
"info-filled": "\f183",
"info": "\f184",
"install": "\f185",
"italic": "\f186",
"key": "\f187",
"keyboard": "\f188",
"lamp": "\f189",
"language": "\f18a",
"large-pause": "\f18b",
"large-play": "\f18c",
"link-badge": "\f18d",
"link-broken": "\f18e",
"link": "\f18f",
"location": "\f190",
"lock-badge": "\f191",
"lock": "\f192",
"logout": "\f193",
"loop": "\f194",
"mention": "\f195",
"menu": "\f196",
"message-failed": "\f197",
"message-pending": "\f198",
"message-read": "\f199",
"zoom-out": "\f101",
"zoom-in": "\f102",
"word-wrap": "\f103",
"webapp": "\f104",
"web": "\f105",
"warning": "\f106",
"volume-3": "\f107",
"volume-2": "\f108",
"volume-1": "\f109",
"voice-chat": "\f10a",
"view-once": "\f10b",
"video": "\f10c",
"video-stop": "\f10d",
"video-outlined": "\f10e",
"user": "\f10f",
"user-tag": "\f110",
"user-stars": "\f111",
"user-online": "\f112",
"user-filled": "\f113",
"up": "\f114",
"unread": "\f115",
"unpin": "\f116",
"unmute": "\f117",
"unlock": "\f118",
"unlock-badge": "\f119",
"unlist": "\f11a",
"unlist-outline": "\f11b",
"unique-profile": "\f11c",
"undo": "\f11d",
"understood": "\f11e",
"underlined": "\f11f",
"unarchive": "\f120",
"truck": "\f121",
"transcribe": "\f122",
"trade": "\f123",
"topic-new": "\f124",
"tools": "\f125",
"toncoin": "\f126",
"timer": "\f127",
"tag": "\f128",
"tag-name": "\f129",
"tag-filter": "\f12a",
"tag-crossed": "\f12b",
"tag-add": "\f12c",
"strikethrough": "\f12d",
"story-reply": "\f12e",
"story-priority": "\f12f",
"story-expired": "\f130",
"story-caption": "\f131",
"stop": "\f132",
"stop-raising-hand": "\f133",
"stickers": "\f134",
"stealth-past": "\f135",
"stealth-future": "\f136",
"stats": "\f137",
"stars-refund": "\f138",
"stars-lock": "\f139",
"star": "\f13a",
"sport": "\f13b",
"spoiler": "\f13c",
"spoiler-disable": "\f13d",
"speaker": "\f13e",
"speaker-story": "\f13f",
"speaker-outline": "\f140",
"speaker-muted-story": "\f141",
"sort": "\f142",
"sort-by-price": "\f143",
"sort-by-number": "\f144",
"sort-by-date": "\f145",
"smile": "\f146",
"smallscreen": "\f147",
"skip-previous": "\f148",
"skip-next": "\f149",
"sidebar": "\f14a",
"show-message": "\f14b",
"share-screen": "\f14c",
"share-screen-stop": "\f14d",
"share-screen-outlined": "\f14e",
"share-filled": "\f14f",
"settings": "\f150",
"settings-filled": "\f151",
"send": "\f152",
"send-outline": "\f153",
"sell": "\f154",
"sell-outline": "\f155",
"select": "\f156",
"select-filled": "\f157",
"search": "\f158",
"sd-photo": "\f159",
"scheduled": "\f15a",
"schedule": "\f15b",
"saved-messages": "\f15c",
"save-story": "\f15d",
"rotate": "\f15e",
"revote": "\f15f",
"revenue-split": "\f160",
"reply": "\f161",
"reply-filled": "\f162",
"replies": "\f163",
"replace": "\f164",
"reorder-tabs": "\f165",
"reopen-topic": "\f166",
"remove": "\f167",
"remove-quote": "\f168",
"reload": "\f169",
"refund": "\f16a",
"redo": "\f16b",
"recent": "\f16c",
"readchats": "\f16d",
"radial-badge": "\f16e",
"quote": "\f16f",
"quote-text": "\f170",
"proof-of-ownership": "\f171",
"privacy-policy": "\f172",
"previous": "\f173",
"poll": "\f174",
"play": "\f175",
"play-story": "\f176",
"pip": "\f177",
"pinned-message": "\f178",
"pinned-chat": "\f179",
"pin": "\f17a",
"pin-list": "\f17b",
"pin-badge": "\f17c",
"photo": "\f17d",
"phone": "\f17e",
"phone-discard": "\f17f",
"phone-discard-outline": "\f180",
"permissions": "\f181",
"pause": "\f182",
"password-off": "\f183",
"open-in-new-tab": "\f184",
"one-filled": "\f185",
"note": "\f186",
"non-contacts": "\f187",
"noise-suppression": "\f188",
"nochannel": "\f189",
"no-share": "\f18a",
"no-download": "\f18b",
"next": "\f18c",
"next-link": "\f18d",
"new-chat-filled": "\f18e",
"my-notes": "\f18f",
"muted": "\f190",
"mute": "\f191",
"move-caption-up": "\f192",
"move-caption-down": "\f193",
"more": "\f194",
"more-circle": "\f195",
"monospace": "\f196",
"microphone": "\f197",
"microphone-alt": "\f198",
"message": "\f199",
"message-succeeded": "\f19a",
"message": "\f19b",
"microphone-alt": "\f19c",
"microphone": "\f19d",
"monospace": "\f19e",
"more-circle": "\f19f",
"more": "\f1a0",
"move-caption-down": "\f1a1",
"move-caption-up": "\f1a2",
"mute": "\f1a3",
"muted": "\f1a4",
"my-notes": "\f1a5",
"new-chat-filled": "\f1a6",
"next-link": "\f1a7",
"next": "\f1a8",
"nochannel": "\f1a9",
"noise-suppression": "\f1aa",
"non-contacts": "\f1ab",
"note": "\f1ac",
"one-filled": "\f1ad",
"open-in-new-tab": "\f1ae",
"password-off": "\f1af",
"pause": "\f1b0",
"permissions": "\f1b1",
"phone-discard-outline": "\f1b2",
"phone-discard": "\f1b3",
"phone": "\f1b4",
"photo": "\f1b5",
"pin-badge": "\f1b6",
"pin-list": "\f1b7",
"pin": "\f1b8",
"pinned-chat": "\f1b9",
"pinned-message": "\f1ba",
"pip": "\f1bb",
"play-story": "\f1bc",
"play": "\f1bd",
"poll": "\f1be",
"previous": "\f1bf",
"privacy-policy": "\f1c0",
"proof-of-ownership": "\f1c1",
"quote-text": "\f1c2",
"quote": "\f1c3",
"radial-badge": "\f1c4",
"rating-icons-level1": "\f1c5",
"rating-icons-level10": "\f1c6",
"rating-icons-level2": "\f1c7",
"rating-icons-level20": "\f1c8",
"rating-icons-level3": "\f1c9",
"rating-icons-level30": "\f1ca",
"rating-icons-level4": "\f1cb",
"rating-icons-level40": "\f1cc",
"rating-icons-level5": "\f1cd",
"rating-icons-level50": "\f1ce",
"rating-icons-level6": "\f1cf",
"rating-icons-level60": "\f1d0",
"rating-icons-level7": "\f1d1",
"rating-icons-level70": "\f1d2",
"rating-icons-level8": "\f1d3",
"rating-icons-level80": "\f1d4",
"rating-icons-level9": "\f1d5",
"rating-icons-level90": "\f1d6",
"rating-icons-negative": "\f1d7",
"readchats": "\f1d8",
"recent": "\f1d9",
"redo": "\f1da",
"refund": "\f1db",
"reload": "\f1dc",
"remove-quote": "\f1dd",
"remove": "\f1de",
"reopen-topic": "\f1df",
"reorder-tabs": "\f1e0",
"replace": "\f1e1",
"replies": "\f1e2",
"reply-filled": "\f1e3",
"reply": "\f1e4",
"revenue-split": "\f1e5",
"revote": "\f1e6",
"rotate": "\f1e7",
"save-story": "\f1e8",
"saved-messages": "\f1e9",
"schedule": "\f1ea",
"scheduled": "\f1eb",
"sd-photo": "\f1ec",
"search": "\f1ed",
"select": "\f1ee",
"sell-outline": "\f1ef",
"sell": "\f1f0",
"send-outline": "\f1f1",
"send": "\f1f2",
"settings-filled": "\f1f3",
"settings": "\f1f4",
"share-filled": "\f1f5",
"share-screen-outlined": "\f1f6",
"share-screen-stop": "\f1f7",
"share-screen": "\f1f8",
"show-message": "\f1f9",
"sidebar": "\f1fa",
"skip-next": "\f1fb",
"skip-previous": "\f1fc",
"smallscreen": "\f1fd",
"smile": "\f1fe",
"sort-by-date": "\f1ff",
"sort-by-number": "\f200",
"sort-by-price": "\f201",
"sort": "\f202",
"speaker-muted-story": "\f203",
"speaker-outline": "\f204",
"speaker-story": "\f205",
"speaker": "\f206",
"spoiler-disable": "\f207",
"spoiler": "\f208",
"sport": "\f209",
"star": "\f20a",
"stars-lock": "\f20b",
"stars-refund": "\f20c",
"stats": "\f20d",
"stealth-future": "\f20e",
"stealth-past": "\f20f",
"stickers": "\f210",
"stop-raising-hand": "\f211",
"stop": "\f212",
"story-caption": "\f213",
"story-expired": "\f214",
"story-priority": "\f215",
"story-reply": "\f216",
"strikethrough": "\f217",
"tag-add": "\f218",
"tag-crossed": "\f219",
"tag-filter": "\f21a",
"tag-name": "\f21b",
"tag": "\f21c",
"timer": "\f21d",
"toncoin": "\f21e",
"tools": "\f21f",
"topic-new": "\f220",
"trade": "\f221",
"transcribe": "\f222",
"truck": "\f223",
"unarchive": "\f224",
"underlined": "\f225",
"understood": "\f226",
"undo": "\f227",
"unique-profile": "\f228",
"unlist-outline": "\f229",
"unlist": "\f22a",
"unlock-badge": "\f22b",
"unlock": "\f22c",
"unmute": "\f22d",
"unpin": "\f22e",
"unread": "\f22f",
"up": "\f230",
"user-filled": "\f231",
"user-online": "\f232",
"user-stars": "\f233",
"user-tag": "\f234",
"user": "\f235",
"video-outlined": "\f236",
"video-stop": "\f237",
"video": "\f238",
"view-once": "\f239",
"voice-chat": "\f23a",
"volume-1": "\f23b",
"volume-2": "\f23c",
"volume-3": "\f23d",
"warning": "\f23e",
"web": "\f23f",
"webapp": "\f240",
"word-wrap": "\f241",
"zoom-in": "\f242",
"zoom-out": "\f243",
"message-read": "\f19b",
"message-pending": "\f19c",
"message-failed": "\f19d",
"menu": "\f19e",
"mention": "\f19f",
"loop": "\f1a0",
"logout": "\f1a1",
"lock": "\f1a2",
"lock-badge": "\f1a3",
"location": "\f1a4",
"link": "\f1a5",
"link-broken": "\f1a6",
"link-badge": "\f1a7",
"large-play": "\f1a8",
"large-pause": "\f1a9",
"language": "\f1aa",
"lamp": "\f1ab",
"keyboard": "\f1ac",
"key": "\f1ad",
"italic": "\f1ae",
"install": "\f1af",
"info": "\f1b0",
"info-filled": "\f1b1",
"help": "\f1b2",
"heart": "\f1b3",
"heart-outline": "\f1b4",
"hd-photo": "\f1b5",
"hashtag": "\f1b6",
"hand-stop": "\f1b7",
"hand-stop-filled": "\f1b8",
"grouped": "\f1b9",
"grouped-disable": "\f1ba",
"group": "\f1bb",
"group-filled": "\f1bc",
"gift": "\f1bd",
"gift-transfer-inline": "\f1be",
"gifs": "\f1bf",
"fullscreen": "\f1c0",
"frozen-time": "\f1c1",
"fragment": "\f1c2",
"forward": "\f1c3",
"forums": "\f1c4",
"fontsize": "\f1c5",
"folder": "\f1c6",
"folder-badge": "\f1c7",
"flip": "\f1c8",
"flag": "\f1c9",
"file-badge": "\f1ca",
"favorite": "\f1cb",
"favorite-filled": "\f1cc",
"eye": "\f1cd",
"eye-outline": "\f1ce",
"eye-crossed": "\f1cf",
"eye-crossed-outline": "\f1d0",
"expand": "\f1d1",
"expand-modal": "\f1d2",
"enter": "\f1d3",
"email": "\f1d4",
"edit": "\f1d5",
"eats": "\f1d6",
"dropdown-arrows": "\f1d7",
"download": "\f1d8",
"down": "\f1d9",
"double-badge": "\f1da",
"document": "\f1db",
"diamond": "\f1dc",
"delete": "\f1dd",
"delete-user": "\f1de",
"delete-left": "\f1df",
"delete-filled": "\f1e0",
"data": "\f1e1",
"darkmode": "\f1e2",
"crown-wear": "\f1e3",
"crown-wear-outline": "\f1e4",
"crown-take-off": "\f1e5",
"crown-take-off-outline": "\f1e6",
"crop": "\f1e7",
"craft": "\f1e8",
"copy": "\f1e9",
"copy-media": "\f1ea",
"comments": "\f1eb",
"comments-sticker": "\f1ec",
"combine-craft": "\f1ed",
"colorize": "\f1ee",
"collapse": "\f1ef",
"collapse-modal": "\f1f0",
"cloud-download": "\f1f1",
"closed-gift": "\f1f2",
"close": "\f1f3",
"close-topic": "\f1f4",
"close-circle": "\f1f5",
"clock": "\f1f6",
"clock-edit": "\f1f7",
"check": "\f1f8",
"chats-badge": "\f1f9",
"chat-badge": "\f1fa",
"channelviews": "\f1fb",
"channel": "\f1fc",
"channel-filled": "\f1fd",
"cash-circle": "\f1fe",
"card": "\f1ff",
"car": "\f200",
"camera": "\f201",
"camera-add": "\f202",
"calendar": "\f203",
"calendar-filter": "\f204",
"bug": "\f205",
"brush": "\f206",
"bots": "\f207",
"bot-commands-filled": "\f208",
"bot-command": "\f209",
"boosts": "\f20a",
"boostcircle": "\f20b",
"boost": "\f20c",
"boost-outline": "\f20d",
"boost-craft-chance": "\f20e",
"bold": "\f20f",
"avatar-saved-messages": "\f210",
"avatar-deleted-account": "\f211",
"avatar-archived-chats": "\f212",
"author-hidden": "\f213",
"auction": "\f214",
"auction-next-round": "\f215",
"auction-filled": "\f216",
"auction-drop": "\f217",
"attach": "\f218",
"ask-support": "\f219",
"arrow-right": "\f21a",
"arrow-left": "\f21b",
"arrow-down": "\f21c",
"arrow-down-circle": "\f21d",
"archive": "\f21e",
"archive-to-main": "\f21f",
"archive-from-main": "\f220",
"archive-filled": "\f221",
"animations": "\f222",
"animals": "\f223",
"allow-speak": "\f224",
"allow-share": "\f225",
"admin": "\f226",
"add": "\f227",
"add-user": "\f228",
"add-user-filled": "\f229",
"add-one-badge": "\f22a",
"add-filled": "\f22b",
"add-caption": "\f22c",
"active-sessions": "\f22d",
"rating-icons-negative": "\f22e",
"rating-icons-level90": "\f22f",
"rating-icons-level9": "\f230",
"rating-icons-level80": "\f231",
"rating-icons-level8": "\f232",
"rating-icons-level70": "\f233",
"rating-icons-level7": "\f234",
"rating-icons-level60": "\f235",
"rating-icons-level6": "\f236",
"rating-icons-level50": "\f237",
"rating-icons-level5": "\f238",
"rating-icons-level40": "\f239",
"rating-icons-level4": "\f23a",
"rating-icons-level30": "\f23b",
"rating-icons-level3": "\f23c",
"rating-icons-level20": "\f23d",
"rating-icons-level2": "\f23e",
"rating-icons-level10": "\f23f",
"rating-icons-level1": "\f240",
"folder-tabs-user": "\f241",
"folder-tabs-star": "\f242",
"folder-tabs-group": "\f243",
"folder-tabs-folder": "\f244",
"folder-tabs-chats": "\f245",
"folder-tabs-chat": "\f246",
"folder-tabs-channel": "\f247",
"folder-tabs-bot": "\f248",
);

Binary file not shown.

Binary file not shown.

View File

@ -1,324 +1,329 @@
export type FontIconName =
| 'active-sessions'
| 'add-caption'
| 'add-filled'
| 'add-one-badge'
| 'add-user-filled'
| 'add-user'
| 'add'
| 'admin'
| 'allow-speak'
| 'animals'
| 'animations'
| 'archive-filled'
| 'archive-from-main'
| 'archive-to-main'
| 'archive'
| 'arrow-down-circle'
| 'arrow-down'
| 'arrow-left'
| 'arrow-right'
| 'ask-support'
| 'attach'
| 'auction-drop'
| 'auction-filled'
| 'auction-next-round'
| 'auction'
| 'author-hidden'
| 'avatar-archived-chats'
| 'avatar-deleted-account'
| 'avatar-saved-messages'
| 'bold'
| 'boost-craft-chance'
| 'boost-outline'
| 'boost'
| 'boostcircle'
| 'boosts'
| 'bot-command'
| 'bot-commands-filled'
| 'bots'
| 'brush'
| 'bug'
| 'calendar-filter'
| 'calendar'
| 'camera-add'
| 'camera'
| 'car'
| 'card'
| 'cash-circle'
| 'channel-filled'
| 'channel'
| 'channelviews'
| 'chat-badge'
| 'chats-badge'
| 'check'
| 'clock-edit'
| 'clock'
| 'close-circle'
| 'close-topic'
| 'close'
| 'closed-gift'
| 'cloud-download'
| 'collapse-modal'
| 'collapse'
| 'colorize'
| 'combine-craft'
| 'comments-sticker'
| 'comments'
| 'copy-media'
| 'copy'
| 'craft'
| 'crop'
| 'crown-take-off-outline'
| 'crown-take-off'
| 'crown-wear-outline'
| 'crown-wear'
| 'darkmode'
| 'data'
| 'delete-filled'
| 'delete-left'
| 'delete-user'
| 'delete'
| 'diamond'
| 'document'
| 'double-badge'
| 'down'
| 'download'
| 'dropdown-arrows'
| 'eats'
| 'edit'
| 'email'
| 'enter'
| 'expand-modal'
| 'expand'
| 'eye-crossed-outline'
| 'eye-crossed'
| 'eye-outline'
| 'eye'
| 'favorite-filled'
| 'favorite'
| 'file-badge'
| 'flag'
| 'flip'
| 'folder-badge'
| 'folder-tabs-bot'
| 'folder-tabs-channel'
| 'folder-tabs-chat'
| 'folder-tabs-chats'
| 'folder-tabs-folder'
| 'folder-tabs-group'
| 'folder-tabs-star'
| 'folder-tabs-user'
| 'folder'
| 'fontsize'
| 'forums'
| 'forward'
| 'fragment'
| 'frozen-time'
| 'fullscreen'
| 'gifs'
| 'gift-transfer-inline'
| 'gift'
| 'group-filled'
| 'group'
| 'grouped-disable'
| 'grouped'
| 'hand-stop'
| 'hashtag'
| 'hd-photo'
| 'heart-outline'
| 'heart'
| 'help'
| 'info-filled'
| 'info'
| 'install'
| 'italic'
| 'key'
| 'keyboard'
| 'lamp'
| 'language'
| 'large-pause'
| 'large-play'
| 'link-badge'
| 'link-broken'
| 'link'
| 'location'
| 'lock-badge'
| 'lock'
| 'logout'
| 'loop'
| 'mention'
| 'menu'
| 'message-failed'
| 'message-pending'
| 'message-read'
| 'message-succeeded'
| 'message'
| 'microphone-alt'
| 'microphone'
| 'monospace'
| 'more-circle'
| 'more'
| 'move-caption-down'
| 'move-caption-up'
| 'mute'
| 'muted'
| 'my-notes'
| 'new-chat-filled'
| 'next-link'
| 'next'
| 'nochannel'
| 'noise-suppression'
| 'non-contacts'
| 'note'
| 'one-filled'
| 'open-in-new-tab'
| 'password-off'
| 'pause'
| 'permissions'
| 'phone-discard-outline'
| 'phone-discard'
| 'phone'
| 'photo'
| 'pin-badge'
| 'pin-list'
| 'pin'
| 'pinned-chat'
| 'pinned-message'
| 'pip'
| 'play-story'
| 'play'
| 'poll'
| 'previous'
| 'privacy-policy'
| 'proof-of-ownership'
| 'quote-text'
| 'quote'
| 'radial-badge'
| 'rating-icons-level1'
| 'rating-icons-level10'
| 'rating-icons-level2'
| 'rating-icons-level20'
| 'rating-icons-level3'
| 'rating-icons-level30'
| 'rating-icons-level4'
| 'rating-icons-level40'
| 'rating-icons-level5'
| 'rating-icons-level50'
| 'rating-icons-level6'
| 'rating-icons-level60'
| 'rating-icons-level7'
| 'rating-icons-level70'
| 'rating-icons-level8'
| 'rating-icons-level80'
| 'rating-icons-level9'
| 'rating-icons-level90'
| 'rating-icons-negative'
| 'readchats'
| 'recent'
| 'redo'
| 'refund'
| 'reload'
| 'remove-quote'
| 'remove'
| 'reopen-topic'
| 'reorder-tabs'
| 'replace'
| 'replies'
| 'reply-filled'
| 'reply'
| 'revenue-split'
| 'revote'
| 'rotate'
| 'save-story'
| 'saved-messages'
| 'schedule'
| 'scheduled'
| 'sd-photo'
| 'search'
| 'select'
| 'sell-outline'
| 'sell'
| 'send-outline'
| 'send'
| 'settings-filled'
| 'settings'
| 'share-filled'
| 'share-screen-outlined'
| 'share-screen-stop'
| 'share-screen'
| 'show-message'
| 'sidebar'
| 'skip-next'
| 'skip-previous'
| 'smallscreen'
| 'smile'
| 'sort-by-date'
| 'sort-by-number'
| 'sort-by-price'
| 'sort'
| 'speaker-muted-story'
| 'speaker-outline'
| 'speaker-story'
| 'speaker'
| 'spoiler-disable'
| 'spoiler'
| 'sport'
| 'star'
| 'stars-lock'
| 'stars-refund'
| 'stats'
| 'stealth-future'
| 'stealth-past'
| 'stickers'
| 'stop-raising-hand'
| 'stop'
| 'story-caption'
| 'story-expired'
| 'story-priority'
| 'story-reply'
| 'strikethrough'
| 'tag-add'
| 'tag-crossed'
| 'tag-filter'
| 'tag-name'
| 'tag'
| 'timer'
| 'toncoin'
| 'tools'
| 'topic-new'
| 'trade'
| 'transcribe'
| 'truck'
| 'unarchive'
| 'underlined'
| 'understood'
| 'undo'
| 'unique-profile'
| 'unlist-outline'
| 'unlist'
| 'unlock-badge'
| 'unlock'
| 'unmute'
| 'unpin'
| 'unread'
| 'up'
| 'user-filled'
| 'user-online'
| 'user-stars'
| 'user-tag'
| 'user'
| 'video-outlined'
| 'video-stop'
| 'video'
| 'view-once'
| 'voice-chat'
| 'volume-1'
| 'volume-2'
| 'volume-3'
| 'warning'
| 'web'
| 'webapp'
| 'word-wrap'
| 'zoom-out'
| 'zoom-in'
| 'zoom-out';
| 'word-wrap'
| 'webapp'
| 'web'
| 'warning'
| 'volume-3'
| 'volume-2'
| 'volume-1'
| 'voice-chat'
| 'view-once'
| 'video'
| 'video-stop'
| 'video-outlined'
| 'user'
| 'user-tag'
| 'user-stars'
| 'user-online'
| 'user-filled'
| 'up'
| 'unread'
| 'unpin'
| 'unmute'
| 'unlock'
| 'unlock-badge'
| 'unlist'
| 'unlist-outline'
| 'unique-profile'
| 'undo'
| 'understood'
| 'underlined'
| 'unarchive'
| 'truck'
| 'transcribe'
| 'trade'
| 'topic-new'
| 'tools'
| 'toncoin'
| 'timer'
| 'tag'
| 'tag-name'
| 'tag-filter'
| 'tag-crossed'
| 'tag-add'
| 'strikethrough'
| 'story-reply'
| 'story-priority'
| 'story-expired'
| 'story-caption'
| 'stop'
| 'stop-raising-hand'
| 'stickers'
| 'stealth-past'
| 'stealth-future'
| 'stats'
| 'stars-refund'
| 'stars-lock'
| 'star'
| 'sport'
| 'spoiler'
| 'spoiler-disable'
| 'speaker'
| 'speaker-story'
| 'speaker-outline'
| 'speaker-muted-story'
| 'sort'
| 'sort-by-price'
| 'sort-by-number'
| 'sort-by-date'
| 'smile'
| 'smallscreen'
| 'skip-previous'
| 'skip-next'
| 'sidebar'
| 'show-message'
| 'share-screen'
| 'share-screen-stop'
| 'share-screen-outlined'
| 'share-filled'
| 'settings'
| 'settings-filled'
| 'send'
| 'send-outline'
| 'sell'
| 'sell-outline'
| 'select'
| 'select-filled'
| 'search'
| 'sd-photo'
| 'scheduled'
| 'schedule'
| 'saved-messages'
| 'save-story'
| 'rotate'
| 'revote'
| 'revenue-split'
| 'reply'
| 'reply-filled'
| 'replies'
| 'replace'
| 'reorder-tabs'
| 'reopen-topic'
| 'remove'
| 'remove-quote'
| 'reload'
| 'refund'
| 'redo'
| 'recent'
| 'readchats'
| 'radial-badge'
| 'quote'
| 'quote-text'
| 'proof-of-ownership'
| 'privacy-policy'
| 'previous'
| 'poll'
| 'play'
| 'play-story'
| 'pip'
| 'pinned-message'
| 'pinned-chat'
| 'pin'
| 'pin-list'
| 'pin-badge'
| 'photo'
| 'phone'
| 'phone-discard'
| 'phone-discard-outline'
| 'permissions'
| 'pause'
| 'password-off'
| 'open-in-new-tab'
| 'one-filled'
| 'note'
| 'non-contacts'
| 'noise-suppression'
| 'nochannel'
| 'no-share'
| 'no-download'
| 'next'
| 'next-link'
| 'new-chat-filled'
| 'my-notes'
| 'muted'
| 'mute'
| 'move-caption-up'
| 'move-caption-down'
| 'more'
| 'more-circle'
| 'monospace'
| 'microphone'
| 'microphone-alt'
| 'message'
| 'message-succeeded'
| 'message-read'
| 'message-pending'
| 'message-failed'
| 'menu'
| 'mention'
| 'loop'
| 'logout'
| 'lock'
| 'lock-badge'
| 'location'
| 'link'
| 'link-broken'
| 'link-badge'
| 'large-play'
| 'large-pause'
| 'language'
| 'lamp'
| 'keyboard'
| 'key'
| 'italic'
| 'install'
| 'info'
| 'info-filled'
| 'help'
| 'heart'
| 'heart-outline'
| 'hd-photo'
| 'hashtag'
| 'hand-stop'
| 'hand-stop-filled'
| 'grouped'
| 'grouped-disable'
| 'group'
| 'group-filled'
| 'gift'
| 'gift-transfer-inline'
| 'gifs'
| 'fullscreen'
| 'frozen-time'
| 'fragment'
| 'forward'
| 'forums'
| 'fontsize'
| 'folder'
| 'folder-badge'
| 'flip'
| 'flag'
| 'file-badge'
| 'favorite'
| 'favorite-filled'
| 'eye'
| 'eye-outline'
| 'eye-crossed'
| 'eye-crossed-outline'
| 'expand'
| 'expand-modal'
| 'enter'
| 'email'
| 'edit'
| 'eats'
| 'dropdown-arrows'
| 'download'
| 'down'
| 'double-badge'
| 'document'
| 'diamond'
| 'delete'
| 'delete-user'
| 'delete-left'
| 'delete-filled'
| 'data'
| 'darkmode'
| 'crown-wear'
| 'crown-wear-outline'
| 'crown-take-off'
| 'crown-take-off-outline'
| 'crop'
| 'craft'
| 'copy'
| 'copy-media'
| 'comments'
| 'comments-sticker'
| 'combine-craft'
| 'colorize'
| 'collapse'
| 'collapse-modal'
| 'cloud-download'
| 'closed-gift'
| 'close'
| 'close-topic'
| 'close-circle'
| 'clock'
| 'clock-edit'
| 'check'
| 'chats-badge'
| 'chat-badge'
| 'channelviews'
| 'channel'
| 'channel-filled'
| 'cash-circle'
| 'card'
| 'car'
| 'camera'
| 'camera-add'
| 'calendar'
| 'calendar-filter'
| 'bug'
| 'brush'
| 'bots'
| 'bot-commands-filled'
| 'bot-command'
| 'boosts'
| 'boostcircle'
| 'boost'
| 'boost-outline'
| 'boost-craft-chance'
| 'bold'
| 'avatar-saved-messages'
| 'avatar-deleted-account'
| 'avatar-archived-chats'
| 'author-hidden'
| 'auction'
| 'auction-next-round'
| 'auction-filled'
| 'auction-drop'
| 'attach'
| 'ask-support'
| 'arrow-right'
| 'arrow-left'
| 'arrow-down'
| 'arrow-down-circle'
| 'archive'
| 'archive-to-main'
| 'archive-from-main'
| 'archive-filled'
| 'animations'
| 'animals'
| 'allow-speak'
| 'allow-share'
| 'admin'
| 'add'
| 'add-user'
| 'add-user-filled'
| 'add-one-badge'
| 'add-filled'
| 'add-caption'
| 'active-sessions'
| 'rating-icons-negative'
| 'rating-icons-level90'
| 'rating-icons-level9'
| 'rating-icons-level80'
| 'rating-icons-level8'
| 'rating-icons-level70'
| 'rating-icons-level7'
| 'rating-icons-level60'
| 'rating-icons-level6'
| 'rating-icons-level50'
| 'rating-icons-level5'
| 'rating-icons-level40'
| 'rating-icons-level4'
| 'rating-icons-level30'
| 'rating-icons-level3'
| 'rating-icons-level20'
| 'rating-icons-level2'
| 'rating-icons-level10'
| 'rating-icons-level1'
| 'folder-tabs-user'
| 'folder-tabs-star'
| 'folder-tabs-group'
| 'folder-tabs-folder'
| 'folder-tabs-chats'
| 'folder-tabs-chat'
| 'folder-tabs-channel'
| 'folder-tabs-bot';

View File

@ -54,6 +54,8 @@ export interface LangPair {
'PremiumPreviewUploadsDescription': undefined;
'PremiumPreviewAdvancedChatManagementDescription': undefined;
'PremiumPreviewAnimatedProfilesDescription': undefined;
'PremiumPreviewNoForwards': undefined;
'PremiumPreviewNoForwardsDescription': undefined;
'PremiumLimitAccountsTitle': undefined;
'PremiumLimitAccountsNoPremium': undefined;
'PremiumLimitAccounts': undefined;
@ -1537,6 +1539,22 @@ export interface LangPair {
'ActionChangedPhotoChannel': undefined;
'ActionCreatedChannel': undefined;
'ActionScreenshotTakenYou': undefined;
'ActionSharingDisabledYou': undefined;
'ActionSharingEnabledYou': undefined;
'ActionSharingStillDisabled': undefined;
'ContextMenuNoForwardsYou': undefined;
'DisableSharing': undefined;
'EnableSharing': undefined;
'NotificationSharingEnabled': undefined;
'NotificationSharingDisabled': undefined;
'NoForwardingTitle': undefined;
'NoForwardingDescription': undefined;
'NoSavingTitle': undefined;
'NoSavingDescription': undefined;
'NoForwardsRequestYouTitle': undefined;
'NoForwardsRequestForwarding': undefined;
'NoForwardsRequestSaving': undefined;
'NoForwardsRequestCopying': undefined;
'ActionBotAppPlaceholder': undefined;
'ActionGiftTextUnknown': undefined;
'ActionGiftTextUnknownYou': undefined;
@ -2018,6 +2036,8 @@ export interface LangPair {
'RankEditSave': undefined;
'RankEditTextOwn': undefined;
'MenuAddCaption': undefined;
'NoForwardsRequestReject': undefined;
'NoForwardsRequestAccept': undefined;
}
export interface LangPairWithVariables<V = LangVariable> {
@ -2750,6 +2770,18 @@ export interface LangPairWithVariables<V = LangVariable> {
'ActionScreenshotTaken': {
'from': V;
};
'ActionSharingDisabled': {
'from': V;
};
'ActionSharingEnabled': {
'from': V;
};
'ContextMenuNoForwardsPeer': {
'name': V;
};
'NoForwardsRequestTitle': {
'user': V;
};
'ActionBotAllowedFromDomain': {
'domain': V;
};