Chat: Fix restriction validation (#6078)
Co-authored-by: Dmitry Kabanov <dmitrykabanovdev@gmail.com>
This commit is contained in:
parent
6e69765a51
commit
9857dc0ec7
@ -120,6 +120,11 @@ export interface GramJsAppConfig extends LimitsConfig {
|
||||
todo_items_max?: number;
|
||||
todo_title_length_max?: number;
|
||||
todo_item_length_max?: number;
|
||||
ignore_restriction_reasons?: string[];
|
||||
need_age_video_verification?: boolean;
|
||||
verify_age_bot_username?: string;
|
||||
verify_age_country?: string;
|
||||
verify_age_min?: number;
|
||||
}
|
||||
|
||||
function buildEmojiSounds(appConfig: GramJsAppConfig) {
|
||||
@ -235,5 +240,10 @@ export function buildAppConfig(json: GramJs.TypeJSONValue, hash: number): ApiApp
|
||||
todoItemsMax: appConfig.todo_items_max ?? TODO_ITEMS_LIMIT,
|
||||
todoTitleLengthMax: appConfig.todo_title_length_max ?? TODO_TITLE_LENGTH_LIMIT,
|
||||
todoItemLengthMax: appConfig.todo_item_length_max ?? TODO_ITEM_LENGTH_LIMIT,
|
||||
ignoreRestrictionReasons: appConfig.ignore_restriction_reasons,
|
||||
needAgeVideoVerification: appConfig.need_age_video_verification,
|
||||
verifyAgeBotUsername: appConfig.verify_age_bot_username,
|
||||
verifyAgeCountry: appConfig.verify_age_country,
|
||||
verifyAgeMin: appConfig.verify_age_min,
|
||||
};
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ import type {
|
||||
ApiTopic,
|
||||
} from '../../types';
|
||||
|
||||
import { pick, pickTruthy } from '../../../util/iteratees';
|
||||
import { pickTruthy } from '../../../util/iteratees';
|
||||
import { getServerTimeOffset } from '../../../util/serverTime';
|
||||
import { addPhotoToLocalDb, addUserToLocalDb } from '../helpers/localDb';
|
||||
import { serializeBytes } from '../helpers/misc';
|
||||
@ -31,7 +31,7 @@ import {
|
||||
buildApiBotVerification, buildApiFormattedText, buildApiPhoto, buildApiUsernames, buildAvatarPhotoId,
|
||||
} from './common';
|
||||
import { omitVirtualClassFields } from './helpers';
|
||||
import { buildApiPeerNotifySettings } from './misc';
|
||||
import { buildApiPeerNotifySettings, buildApiRestrictionReasons } from './misc';
|
||||
import {
|
||||
buildApiEmojiStatus,
|
||||
buildApiPeerColor,
|
||||
@ -196,7 +196,7 @@ function buildApiChatRestrictions(peerEntity: Entity): {
|
||||
isNotJoined?: boolean;
|
||||
isForbidden?: boolean;
|
||||
isRestricted?: boolean;
|
||||
restrictionReason?: ApiRestrictionReason;
|
||||
restrictionReasons?: ApiRestrictionReason[];
|
||||
} {
|
||||
if (peerEntity instanceof GramJs.ChatForbidden) {
|
||||
return {
|
||||
@ -213,11 +213,10 @@ function buildApiChatRestrictions(peerEntity: Entity): {
|
||||
const restrictions = {};
|
||||
|
||||
if ('restricted' in peerEntity && !peerEntity.min) {
|
||||
const restrictionReason = buildApiChatRestrictionReason(peerEntity.restrictionReason);
|
||||
const restrictionReasons = buildApiRestrictionReasons(peerEntity.restrictionReason);
|
||||
|
||||
Object.assign(restrictions, {
|
||||
isRestricted: peerEntity.restricted,
|
||||
restrictionReason,
|
||||
restrictionReasons,
|
||||
});
|
||||
}
|
||||
|
||||
@ -261,17 +260,6 @@ function buildApiChatMigrationInfo(peerEntity: Entity): {
|
||||
return {};
|
||||
}
|
||||
|
||||
function buildApiChatRestrictionReason(
|
||||
restrictionReasons?: GramJs.RestrictionReason[],
|
||||
): ApiRestrictionReason | undefined {
|
||||
if (!restrictionReasons) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const targetReason = restrictionReasons.find(({ platform }) => platform === 'all');
|
||||
return targetReason ? pick(targetReason, ['reason', 'text']) : undefined;
|
||||
}
|
||||
|
||||
export function buildApiChatFromPreview(
|
||||
preview: GramJs.TypeChat | GramJs.TypeUser,
|
||||
isSupport = false,
|
||||
|
||||
@ -70,6 +70,7 @@ import {
|
||||
import { type OmitVirtualFields } from './helpers';
|
||||
import { buildApiMessageAction } from './messageActions';
|
||||
import { buildMessageContent, buildMessageMediaContent, buildMessageTextContent } from './messageContent';
|
||||
import { buildApiRestrictionReasons } from './misc';
|
||||
import { buildApiPeerColor, buildApiPeerId, getApiChatIdFromMtpPeer } from './peers';
|
||||
import { buildMessageReactions } from './reactions';
|
||||
|
||||
@ -230,6 +231,8 @@ export function buildApiMessageWithChatId(
|
||||
|
||||
const savedPeerId = mtpMessage.savedPeerId && getApiChatIdFromMtpPeer(mtpMessage.savedPeerId);
|
||||
|
||||
const restrictionReasons = buildApiRestrictionReasons(mtpMessage.restrictionReason);
|
||||
|
||||
return {
|
||||
id: mtpMessage.id,
|
||||
chatId,
|
||||
@ -277,6 +280,7 @@ export function buildApiMessageWithChatId(
|
||||
isVideoProcessingPending,
|
||||
reportDeliveryUntilDate: mtpMessage.reportDeliveryUntilDate,
|
||||
paidMessageStars: mtpMessage.paidMessageStars?.toJSNumber(),
|
||||
restrictionReasons,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -10,6 +10,7 @@ import type {
|
||||
ApiPeerColors,
|
||||
ApiPeerNotifySettings,
|
||||
ApiPrivacyKey,
|
||||
ApiRestrictionReason,
|
||||
ApiSession,
|
||||
ApiTimezone,
|
||||
ApiUrlAuthResult,
|
||||
@ -347,3 +348,15 @@ export function buildApiCollectibleInfo(info: GramJs.fragment.TypeCollectibleInf
|
||||
url,
|
||||
};
|
||||
}
|
||||
|
||||
export function buildApiRestrictionReasons(
|
||||
restrictionReasons?: GramJs.RestrictionReason[],
|
||||
): ApiRestrictionReason[] | undefined {
|
||||
if (!restrictionReasons) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return restrictionReasons.map((
|
||||
{ reason, text, platform }) =>
|
||||
({ reason, text, platform }));
|
||||
}
|
||||
|
||||
@ -314,8 +314,6 @@ export async function fetchProfilePhotos({
|
||||
};
|
||||
}
|
||||
|
||||
if (chat?.isRestricted) return undefined;
|
||||
|
||||
const result = await searchMessagesInChat({
|
||||
peer,
|
||||
type: 'profilePhoto',
|
||||
|
||||
@ -2,7 +2,7 @@ import type { ApiBotCommand } from './bots';
|
||||
import type {
|
||||
ApiChatReactions, ApiFormattedText, ApiInputMessageReplyInfo, ApiInputSuggestedPostInfo, ApiPhoto, ApiStickerSet,
|
||||
} from './messages';
|
||||
import type { ApiBotVerification, ApiChatInviteImporter, ApiPeerNotifySettings } from './misc';
|
||||
import type { ApiBotVerification, ApiChatInviteImporter, ApiPeerNotifySettings, ApiRestrictionReason } from './misc';
|
||||
import type {
|
||||
ApiEmojiStatusType, ApiFakeType, ApiUser, ApiUsername,
|
||||
} from './users';
|
||||
@ -66,7 +66,7 @@ export interface ApiChat {
|
||||
isCreator?: boolean;
|
||||
isForbidden?: boolean; // Forbidden - can't send messages (user was kicked, for example)
|
||||
isRestricted?: boolean; // Restricted - can't access the chat (user was banned or chat is violating rules)
|
||||
restrictionReason?: ApiRestrictionReason;
|
||||
restrictionReasons?: ApiRestrictionReason[];
|
||||
adminRights?: ApiChatAdminRights;
|
||||
currentUserBannedRights?: ApiChatBannedRights;
|
||||
defaultBannedRights?: ApiChatBannedRights;
|
||||
@ -212,11 +212,6 @@ export interface ApiChatBannedRights {
|
||||
untilDate?: number;
|
||||
}
|
||||
|
||||
export interface ApiRestrictionReason {
|
||||
reason: string;
|
||||
text: string;
|
||||
}
|
||||
|
||||
export interface ApiChatFolder {
|
||||
id: number;
|
||||
title: ApiFormattedText;
|
||||
|
||||
@ -6,6 +6,7 @@ import type {
|
||||
} from './bots';
|
||||
import type { ApiPeerColor } from './chats';
|
||||
import type { ApiMessageAction } from './messageActions';
|
||||
import type { ApiRestrictionReason } from './misc';
|
||||
import type {
|
||||
ApiLabeledPrice,
|
||||
} from './payments';
|
||||
@ -642,6 +643,7 @@ export interface ApiMessage {
|
||||
areReactionsPossible?: true;
|
||||
reportDeliveryUntilDate?: number;
|
||||
paidMessageStars?: number;
|
||||
restrictionReasons?: ApiRestrictionReason[];
|
||||
}
|
||||
|
||||
export interface ApiReactions {
|
||||
|
||||
@ -267,6 +267,11 @@ export interface ApiAppConfig {
|
||||
todoItemsMax?: number;
|
||||
todoTitleLengthMax?: number;
|
||||
todoItemLengthMax?: number;
|
||||
ignoreRestrictionReasons?: string[];
|
||||
needAgeVideoVerification?: boolean;
|
||||
verifyAgeBotUsername?: string;
|
||||
verifyAgeCountry?: string;
|
||||
verifyAgeMin?: number;
|
||||
}
|
||||
|
||||
export interface ApiConfig {
|
||||
@ -385,3 +390,9 @@ export type ApiPeerNotifySettings = {
|
||||
};
|
||||
|
||||
export type ApiNotifyPeerType = 'users' | 'groups' | 'channels';
|
||||
|
||||
export interface ApiRestrictionReason {
|
||||
reason: string;
|
||||
text: string;
|
||||
platform: string;
|
||||
}
|
||||
|
||||
@ -2141,3 +2141,15 @@
|
||||
"ButtonTopUpViaFragment" = "Top-Up Via Fragment";
|
||||
"TonModalHint" = "You can top-up your TON using Fragment.";
|
||||
"TonGiftReceived" = "TON Top-Up";
|
||||
"MediaSpoilerSensitive" = "18+";
|
||||
"TitleSensitiveModal" = "18+ content";
|
||||
"TextSensitiveModal" = "This media may contain sensitive content suitable only for adults. Do you still want to view it?";
|
||||
"ButtonSensitiveAlways" = "Always show 18+ media";
|
||||
"ButtonSensitiveView" = "View Anyway";
|
||||
"TitleAgeVerificationModal" = "Age Verification";
|
||||
"TextAgeVerificationModal_one" = "To access such content, you must confirm that you are at least **{count}** year old as required by UK law.";
|
||||
"TextAgeVerificationModal_other" = "To access such content, you must confirm that you are at least **{count}** years old as required by UK law.";
|
||||
"DescriptionAgeVerificationModal" = "This is a one-time process using your phone's camera. Your selfie will not be stored by Telegram.";
|
||||
"TitleAgeCheckFailed" = "Age Check Failed";
|
||||
"TitleAgeCheckSuccess" = "Age Check Success";
|
||||
"ButtonAgeVerification" = "Verify My Age";
|
||||
@ -24,6 +24,7 @@ export { default as SuggestedStatusModal } from '../components/modals/suggestedS
|
||||
export { default as BoostModal } from '../components/modals/boost/BoostModal';
|
||||
export { default as GiftCodeModal } from '../components/modals/giftcode/GiftCodeModal';
|
||||
export { default as DeleteAccountModal } from '../components/modals/deleteAccount/DeleteAccountModal';
|
||||
export { default as AgeVerificationModal } from '../components/modals/ageVerification/AgeVerificationModal';
|
||||
export { default as ChatlistModal } from '../components/modals/chatlist/ChatlistModal';
|
||||
export { default as ChatInviteModal } from '../components/modals/chatInvite/ChatInviteModal';
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import type { FC } from '../../lib/teact/teact';
|
||||
import type React from '../../lib/teact/teact';
|
||||
import { memo, useEffect, useMemo } from '../../lib/teact/teact';
|
||||
import { getActions, withGlobal } from '../../global';
|
||||
import { getActions, getGlobal, withGlobal } from '../../global';
|
||||
|
||||
import type {
|
||||
ApiChat, ApiThreadInfo, ApiTopic, ApiTypingStatus, ApiUser,
|
||||
@ -19,6 +19,7 @@ import {
|
||||
selectChat,
|
||||
selectChatMessages,
|
||||
selectChatOnlineCount,
|
||||
selectIsChatRestricted,
|
||||
selectMonoforumChannel,
|
||||
selectThreadInfo,
|
||||
selectThreadMessagesCount,
|
||||
@ -126,7 +127,8 @@ const GroupChatInfo: FC<OwnProps & StateProps> = ({
|
||||
|
||||
const isSuperGroup = chat && isChatSuperGroup(chat);
|
||||
const isTopic = Boolean(chat?.isForum && threadInfo && topic);
|
||||
const { id: chatId, isMin, isRestricted } = chat || {};
|
||||
const { id: chatId, isMin } = chat || {};
|
||||
const isRestricted = selectIsChatRestricted(getGlobal(), chatId!);
|
||||
|
||||
useEffect(() => {
|
||||
if (chatId && !isMin) {
|
||||
|
||||
@ -1,11 +1,14 @@
|
||||
.root {
|
||||
|
||||
--click-shift-x: 0px;
|
||||
--click-shift-y: 0px;
|
||||
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
background-color: var(--color-text-secondary); // Fallback before canvas is prepared
|
||||
}
|
||||
|
||||
@ -33,6 +36,28 @@
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.nsfw {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
align-items: center;
|
||||
|
||||
padding: 0.125rem 0.5rem;
|
||||
border-radius: 1rem;
|
||||
|
||||
color: white;
|
||||
|
||||
background-color: rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
.nsfwIcon {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.dots {
|
||||
--x-direction: var(--background-size);
|
||||
--y-direction: 0;
|
||||
|
||||
@ -6,15 +6,19 @@ import { requestMutation } from '../../lib/fasterdom/fasterdom';
|
||||
import buildClassName from '../../util/buildClassName';
|
||||
|
||||
import useCanvasBlur from '../../hooks/useCanvasBlur';
|
||||
import useLang from '../../hooks/useLang';
|
||||
import useLastCallback from '../../hooks/useLastCallback';
|
||||
import useShowTransitionDeprecated from '../../hooks/useShowTransitionDeprecated';
|
||||
|
||||
import Icon from './icons/Icon';
|
||||
|
||||
import styles from './MediaSpoiler.module.scss';
|
||||
|
||||
type OwnProps = {
|
||||
isVisible: boolean;
|
||||
withAnimation?: boolean;
|
||||
thumbDataUri?: string;
|
||||
isNsfw?: boolean;
|
||||
width?: number;
|
||||
height?: number;
|
||||
className?: string;
|
||||
@ -27,12 +31,15 @@ const MediaSpoiler: FC<OwnProps> = ({
|
||||
isVisible,
|
||||
withAnimation,
|
||||
thumbDataUri,
|
||||
isNsfw,
|
||||
className,
|
||||
width,
|
||||
height,
|
||||
}) => {
|
||||
const ref = useRef<HTMLDivElement>();
|
||||
|
||||
const lang = useLang();
|
||||
|
||||
const { shouldRender, transitionClassNames } = useShowTransitionDeprecated(
|
||||
isVisible, undefined, true, withAnimation ? false : undefined, undefined, ANIMATION_DURATION,
|
||||
);
|
||||
@ -68,6 +75,12 @@ const MediaSpoiler: FC<OwnProps> = ({
|
||||
height={height}
|
||||
/>
|
||||
<div className={styles.dots} />
|
||||
{isNsfw && (
|
||||
<span className={styles.nsfw}>
|
||||
<Icon name="eye-crossed-outline" className={styles.nsfwIcon} />
|
||||
{lang('MediaSpoilerSensitive')}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -0,0 +1,4 @@
|
||||
.checkBox {
|
||||
margin-top: 1rem;
|
||||
margin-inline: -1.125rem;
|
||||
}
|
||||
47
src/components/common/SensitiveContentConfirmModal.tsx
Normal file
47
src/components/common/SensitiveContentConfirmModal.tsx
Normal file
@ -0,0 +1,47 @@
|
||||
import type { FC } from '../../lib/teact/teact';
|
||||
import { memo } from '../../lib/teact/teact';
|
||||
|
||||
import useLang from '../../hooks/useLang';
|
||||
|
||||
import Checkbox from '../ui/Checkbox';
|
||||
import ConfirmDialog from '../ui/ConfirmDialog';
|
||||
|
||||
import styles from './SensitiveContentConfirmModal.module.scss';
|
||||
|
||||
type OwnProps = {
|
||||
isOpen: boolean;
|
||||
onClose: NoneToVoidFunction;
|
||||
shouldAlwaysShow: boolean;
|
||||
onAlwaysShowChanged: (value: boolean) => void;
|
||||
confirmHandler: NoneToVoidFunction;
|
||||
};
|
||||
|
||||
const SensitiveContentConfirmModal: FC<OwnProps> = ({
|
||||
isOpen,
|
||||
onClose,
|
||||
shouldAlwaysShow,
|
||||
onAlwaysShowChanged,
|
||||
confirmHandler,
|
||||
}) => {
|
||||
const lang = useLang();
|
||||
|
||||
return (
|
||||
<ConfirmDialog
|
||||
title={lang('TitleSensitiveModal')}
|
||||
confirmLabel={lang('ButtonSensitiveView')}
|
||||
isOpen={isOpen}
|
||||
onClose={onClose}
|
||||
confirmHandler={confirmHandler}
|
||||
>
|
||||
{lang('TextSensitiveModal')}
|
||||
<Checkbox
|
||||
className={styles.checkBox}
|
||||
label={lang('ButtonSensitiveAlways')}
|
||||
checked={shouldAlwaysShow}
|
||||
onCheck={onAlwaysShowChanged}
|
||||
/>
|
||||
</ConfirmDialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(SensitiveContentConfirmModal);
|
||||
@ -64,6 +64,7 @@ type OwnProps = {
|
||||
chatTranslations?: ChatTranslatedMessages;
|
||||
requestedChatTranslationLanguage?: string;
|
||||
isOpen?: boolean;
|
||||
isMediaNsfw?: boolean;
|
||||
observeIntersectionForLoading?: ObserveFn;
|
||||
observeIntersectionForPlaying?: ObserveFn;
|
||||
onClick: ((e: React.MouseEvent) => void);
|
||||
@ -88,6 +89,7 @@ const EmbeddedMessage: FC<OwnProps> = ({
|
||||
noUserColors,
|
||||
chatTranslations,
|
||||
requestedChatTranslationLanguage,
|
||||
isMediaNsfw,
|
||||
observeIntersectionForLoading,
|
||||
observeIntersectionForPlaying,
|
||||
onClick,
|
||||
@ -114,7 +116,7 @@ const EmbeddedMessage: FC<OwnProps> = ({
|
||||
const mediaThumbnail = useThumbnail(containedMedia);
|
||||
|
||||
const isRoundVideo = Boolean(containedMedia && getMessageRoundVideo(containedMedia));
|
||||
const isSpoiler = Boolean(containedMedia && getMessageIsSpoiler(containedMedia));
|
||||
const isSpoiler = Boolean(containedMedia && getMessageIsSpoiler(containedMedia)) || isMediaNsfw;
|
||||
const isQuote = Boolean(replyInfo?.type === 'message' && replyInfo.isQuote);
|
||||
const replyForwardInfo = replyInfo?.type === 'message' ? replyInfo.replyFrom : undefined;
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@ import type { FC } from '../../../lib/teact/teact';
|
||||
import {
|
||||
memo, useMemo,
|
||||
} from '../../../lib/teact/teact';
|
||||
import { getActions, withGlobal } from '../../../global';
|
||||
import { getActions, getGlobal, withGlobal } from '../../../global';
|
||||
|
||||
import type {
|
||||
ApiBotVerification,
|
||||
@ -29,6 +29,7 @@ import {
|
||||
selectChat,
|
||||
selectChatFullInfo,
|
||||
selectCurrentMessageList,
|
||||
selectIsChatRestricted,
|
||||
selectNotifyDefaults,
|
||||
selectNotifyException,
|
||||
selectTopicLink,
|
||||
@ -273,7 +274,8 @@ const ChatExtra: FC<OwnProps & StateProps> = ({
|
||||
),
|
||||
}, { withNodes: true });
|
||||
|
||||
if (chat?.isRestricted || (isSelf && !isInSettings)) {
|
||||
const isRestricted = chatId ? selectIsChatRestricted(getGlobal(), chatId) : false;
|
||||
if (isRestricted || (isSelf && !isInSettings)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
@ -20,6 +20,7 @@ import useLastCallback from '../../../hooks/useLastCallback.ts';
|
||||
import useOldLang from '../../../hooks/useOldLang';
|
||||
|
||||
import StarIcon from '../../common/icons/StarIcon';
|
||||
import Button from '../../ui/Button';
|
||||
import Checkbox from '../../ui/Checkbox';
|
||||
import ListItem from '../../ui/ListItem';
|
||||
|
||||
@ -43,6 +44,7 @@ type StateProps = {
|
||||
shouldChargeForMessages: boolean;
|
||||
canDisplayChatInTitle?: boolean;
|
||||
isCurrentUserFrozen?: boolean;
|
||||
needAgeVideoVerification?: boolean;
|
||||
privacy: GlobalState['settings']['privacy'];
|
||||
accountDaysTtl?: number;
|
||||
};
|
||||
@ -64,6 +66,7 @@ const SettingsPrivacy: FC<OwnProps & StateProps> = ({
|
||||
shouldChargeForMessages,
|
||||
canDisplayChatInTitle,
|
||||
canSetPasscode,
|
||||
needAgeVideoVerification,
|
||||
privacy,
|
||||
onReset,
|
||||
isCurrentUserFrozen,
|
||||
@ -73,7 +76,6 @@ const SettingsPrivacy: FC<OwnProps & StateProps> = ({
|
||||
openDeleteAccountModal,
|
||||
loadPrivacySettings,
|
||||
loadBlockedUsers,
|
||||
loadContentSettings,
|
||||
updateContentSettings,
|
||||
loadGlobalPrivacySettings,
|
||||
updateGlobalPrivacySettings,
|
||||
@ -81,13 +83,13 @@ const SettingsPrivacy: FC<OwnProps & StateProps> = ({
|
||||
setSharedSettingOption,
|
||||
openSettingsScreen,
|
||||
loadAccountDaysTtl,
|
||||
openAgeVerificationModal,
|
||||
} = getActions();
|
||||
|
||||
useEffect(() => {
|
||||
if (!isCurrentUserFrozen) {
|
||||
loadBlockedUsers();
|
||||
loadPrivacySettings();
|
||||
loadContentSettings();
|
||||
loadWebAuthorizations();
|
||||
}
|
||||
}, [isCurrentUserFrozen]);
|
||||
@ -123,6 +125,10 @@ const SettingsPrivacy: FC<OwnProps & StateProps> = ({
|
||||
updateContentSettings({ isSensitiveEnabled: isChecked });
|
||||
}, [updateContentSettings]);
|
||||
|
||||
const handleAgeVerification = useCallback(() => {
|
||||
openAgeVerificationModal();
|
||||
}, [openAgeVerificationModal]);
|
||||
|
||||
const handleOpenDeleteAccountModal = useLastCallback(() => {
|
||||
if (!accountDaysTtl) return;
|
||||
openDeleteAccountModal({ days: accountDaysTtl });
|
||||
@ -384,7 +390,7 @@ const SettingsPrivacy: FC<OwnProps & StateProps> = ({
|
||||
</div>
|
||||
|
||||
{canChangeSensitive && (
|
||||
<div className="settings-item">
|
||||
<div className="settings-item fluid-container">
|
||||
<h4 className="settings-item-header" dir={oldLang.isRtl ? 'rtl' : undefined}>
|
||||
{oldLang('lng_settings_sensitive_title')}
|
||||
</h4>
|
||||
@ -392,9 +398,23 @@ const SettingsPrivacy: FC<OwnProps & StateProps> = ({
|
||||
label={oldLang('lng_settings_sensitive_disable_filtering')}
|
||||
subLabel={oldLang('lng_settings_sensitive_about')}
|
||||
checked={Boolean(isSensitiveEnabled)}
|
||||
disabled={!canChangeSensitive}
|
||||
disabled={!canChangeSensitive || (!isSensitiveEnabled && needAgeVideoVerification)}
|
||||
onCheck={handleUpdateContentSettings}
|
||||
/>
|
||||
{!isSensitiveEnabled && needAgeVideoVerification && (
|
||||
<Button
|
||||
color="primary"
|
||||
fluid
|
||||
size="smaller"
|
||||
noForcedUpperCase
|
||||
className="settings-unlock-button"
|
||||
onClick={handleAgeVerification}
|
||||
>
|
||||
<span className="settings-unlock-button-title">
|
||||
{lang('ButtonAgeVerification')}
|
||||
</span>
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -475,6 +495,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
canChangeSensitive,
|
||||
shouldNewNonContactPeersRequirePremium,
|
||||
shouldChargeForMessages,
|
||||
needAgeVideoVerification: Boolean(appConfig?.needAgeVideoVerification),
|
||||
privacy,
|
||||
canDisplayChatInTitle,
|
||||
canSetPasscode: selectCanSetPasscode(global),
|
||||
|
||||
@ -257,6 +257,7 @@ const Main = ({
|
||||
loadAllChats,
|
||||
loadAllStories,
|
||||
loadAllHiddenStories,
|
||||
loadContentSettings,
|
||||
} = getActions();
|
||||
|
||||
if (DEBUG && !DEBUG_isLogged) {
|
||||
@ -329,6 +330,7 @@ const Main = ({
|
||||
loadAllChats({ listType: 'saved' });
|
||||
loadAllStories();
|
||||
loadAllHiddenStories();
|
||||
loadContentSettings();
|
||||
loadRecentReactions();
|
||||
loadDefaultTagReactions();
|
||||
loadAttachBots();
|
||||
|
||||
@ -22,6 +22,7 @@ import {
|
||||
selectChat,
|
||||
selectChatFullInfo,
|
||||
selectIsChatBotNotStarted,
|
||||
selectIsChatRestricted,
|
||||
selectIsChatWithSelf,
|
||||
selectIsCurrentUserFrozen,
|
||||
selectIsInSelectMode,
|
||||
@ -477,7 +478,8 @@ export default memo(withGlobal<OwnProps>(
|
||||
const isPrivate = isUserId(chatId);
|
||||
const { doNotTranslate } = global.settings.byKey;
|
||||
|
||||
if (!chat || chat.isRestricted || selectIsInSelectMode(global)) {
|
||||
const isRestricted = selectIsChatRestricted(global, chatId);
|
||||
if (!chat || isRestricted || selectIsInSelectMode(global)) {
|
||||
return {
|
||||
noMenu: true,
|
||||
language,
|
||||
|
||||
@ -32,6 +32,7 @@ import {
|
||||
selectChat,
|
||||
selectChatFullInfo,
|
||||
selectCurrentMessageList,
|
||||
selectIsChatRestricted,
|
||||
selectIsChatWithSelf,
|
||||
selectIsCurrentUserFrozen,
|
||||
selectIsRightColumnShown,
|
||||
@ -842,7 +843,8 @@ const HeaderMenuContainer: FC<OwnProps & StateProps> = ({
|
||||
export default memo(withGlobal<OwnProps>(
|
||||
(global, { chatId, threadId }): StateProps => {
|
||||
const chat = selectChat(global, chatId);
|
||||
if (!chat || chat.isRestricted) {
|
||||
const isRestricted = selectIsChatRestricted(global, chatId);
|
||||
if (!chat || isRestricted) {
|
||||
return {};
|
||||
}
|
||||
const isPrivate = isUserId(chat.id);
|
||||
|
||||
@ -58,6 +58,8 @@ import {
|
||||
selectTranslationLanguage,
|
||||
selectUserFullInfo,
|
||||
} from '../../global/selectors';
|
||||
import { selectIsChatRestricted } from '../../global/selectors/chats';
|
||||
import { selectActiveRestrictionReasons } from '../../global/selectors/messages';
|
||||
import animateScroll, { isAnimatingScroll, restartCurrentScrollAnimation } from '../../util/animateScroll';
|
||||
import buildClassName from '../../util/buildClassName';
|
||||
import { isUserId } from '../../util/entities/ids';
|
||||
@ -125,7 +127,7 @@ type StateProps = {
|
||||
firstUnreadId?: number;
|
||||
isViewportNewest?: boolean;
|
||||
isRestricted?: boolean;
|
||||
restrictionReason?: ApiRestrictionReason;
|
||||
restrictionReasons?: ApiRestrictionReason[];
|
||||
focusingId?: number;
|
||||
isSelectModeActive?: boolean;
|
||||
lastMessage?: ApiMessage;
|
||||
@ -189,7 +191,7 @@ const MessageList: FC<OwnProps & StateProps> = ({
|
||||
isComments,
|
||||
isViewportNewest,
|
||||
isRestricted,
|
||||
restrictionReason,
|
||||
restrictionReasons,
|
||||
isEmptyThread,
|
||||
focusingId,
|
||||
isSelectModeActive,
|
||||
@ -719,7 +721,7 @@ const MessageList: FC<OwnProps & StateProps> = ({
|
||||
{isRestricted ? (
|
||||
<div className="empty">
|
||||
<span>
|
||||
{restrictionReason ? restrictionReason.text : `This is a private ${isChannelChat ? 'channel' : 'chat'}`}
|
||||
{restrictionReasons?.[0]?.text || `This is a private ${isChannelChat ? 'channel' : 'chat'}`}
|
||||
</span>
|
||||
</div>
|
||||
) : paidMessagesStars && !hasMessages && !hasCustomGreeting ? (
|
||||
@ -802,7 +804,8 @@ export default memo(withGlobal<OwnProps>(
|
||||
return { currentUserId };
|
||||
}
|
||||
|
||||
const { isRestricted, restrictionReason } = chat;
|
||||
const isRestricted = selectIsChatRestricted(global, chatId);
|
||||
const restrictionReasons = selectActiveRestrictionReasons(global, chat?.restrictionReasons);
|
||||
const lastMessage = selectChatLastMessage(global, chatId, isSavedDialog ? 'saved' : 'all');
|
||||
const focusingId = selectFocusedMessageId(global, chatId);
|
||||
|
||||
@ -836,7 +839,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
areAdsEnabled,
|
||||
isChatLoaded: true,
|
||||
isRestricted,
|
||||
restrictionReason,
|
||||
restrictionReasons,
|
||||
isChannelChat: isChatChannel(chat),
|
||||
isChatMonoforum: isChatMonoforum(chat),
|
||||
isGroupChat: isChatGroup(chat),
|
||||
|
||||
@ -22,6 +22,7 @@ import {
|
||||
selectForwardedSender,
|
||||
selectIsChatWithSelf,
|
||||
selectIsCurrentUserPremium,
|
||||
selectIsMediaNsfw,
|
||||
selectSender,
|
||||
selectTabState,
|
||||
} from '../../../global/selectors';
|
||||
@ -67,14 +68,15 @@ type StateProps = {
|
||||
currentUserId?: string;
|
||||
forwardMessageIds?: number[];
|
||||
fromChatId?: string;
|
||||
isMediaNsfw?: boolean;
|
||||
};
|
||||
|
||||
type OwnProps = {
|
||||
onClear?: () => void;
|
||||
shouldForceShowEditing?: boolean;
|
||||
chatId: string;
|
||||
threadId: ThreadId;
|
||||
messageListType: MessageListType;
|
||||
onClear?: () => void;
|
||||
};
|
||||
|
||||
const CLOSE_DURATION = 350;
|
||||
@ -94,7 +96,6 @@ const ComposerEmbeddedMessage: FC<OwnProps & StateProps> = ({
|
||||
isCurrentUserPremium,
|
||||
isContextMenuDisabled,
|
||||
isReplyToDiscussion,
|
||||
onClear,
|
||||
isInChangingRecipientMode,
|
||||
shouldPreventComposerAnimation,
|
||||
senderChat,
|
||||
@ -103,6 +104,8 @@ const ComposerEmbeddedMessage: FC<OwnProps & StateProps> = ({
|
||||
isSenderChannel,
|
||||
forwardMessageIds,
|
||||
fromChatId,
|
||||
isMediaNsfw,
|
||||
onClear,
|
||||
}) => {
|
||||
const {
|
||||
resetDraftReplyInfo,
|
||||
@ -301,6 +304,7 @@ const ComposerEmbeddedMessage: FC<OwnProps & StateProps> = ({
|
||||
className="inside-input"
|
||||
replyInfo={replyInfo}
|
||||
suggestedPostInfo={suggestedPostInfo}
|
||||
isMediaNsfw={isMediaNsfw}
|
||||
isInComposer
|
||||
message={strippedMessage}
|
||||
sender={!noAuthors ? sender : undefined}
|
||||
@ -495,6 +499,8 @@ export default memo(withGlobal<OwnProps>(
|
||||
|
||||
const isReplyToDiscussion = replyInfo?.replyToMsgId === threadId && !replyInfo.replyToPeerId;
|
||||
|
||||
const isMediaNsfw = message && selectIsMediaNsfw(global, message);
|
||||
|
||||
return {
|
||||
replyInfo,
|
||||
suggestedPostInfo,
|
||||
@ -516,6 +522,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
isSenderChannel,
|
||||
forwardMessageIds,
|
||||
fromChatId,
|
||||
isMediaNsfw,
|
||||
};
|
||||
},
|
||||
)(ComposerEmbeddedMessage));
|
||||
|
||||
@ -86,11 +86,13 @@ import {
|
||||
selectDefaultReaction,
|
||||
selectForwardedSender,
|
||||
selectIsChatProtected,
|
||||
selectIsChatRestricted,
|
||||
selectIsChatWithSelf,
|
||||
selectIsCurrentUserFrozen,
|
||||
selectIsCurrentUserPremium,
|
||||
selectIsDocumentGroupSelected,
|
||||
selectIsInSelectMode,
|
||||
selectIsMediaNsfw,
|
||||
selectIsMessageFocused,
|
||||
selectIsMessageProtected,
|
||||
selectIsMessageSelected,
|
||||
@ -211,9 +213,6 @@ type MessagePositionProperties = {
|
||||
type OwnProps =
|
||||
{
|
||||
message: ApiMessage;
|
||||
observeIntersectionForBottom?: ObserveFn;
|
||||
observeIntersectionForLoading?: ObserveFn;
|
||||
observeIntersectionForPlaying?: ObserveFn;
|
||||
album?: IAlbum;
|
||||
noAvatars?: boolean;
|
||||
withAvatar?: boolean;
|
||||
@ -226,6 +225,9 @@ type OwnProps =
|
||||
isJustAdded: boolean;
|
||||
memoFirstUnreadIdRef?: { current: number | undefined };
|
||||
getIsMessageListReady?: Signal<boolean>;
|
||||
observeIntersectionForBottom?: ObserveFn;
|
||||
observeIntersectionForLoading?: ObserveFn;
|
||||
observeIntersectionForPlaying?: ObserveFn;
|
||||
onIntersectPinnedMessage?: OnIntersectPinnedMessage;
|
||||
}
|
||||
& MessagePositionProperties;
|
||||
@ -316,6 +318,8 @@ type StateProps = {
|
||||
isChatWithUser?: boolean;
|
||||
isAccountFrozen?: boolean;
|
||||
minFutureTime?: number;
|
||||
isMediaNsfw?: boolean;
|
||||
isReplyMediaNsfw?: boolean;
|
||||
};
|
||||
|
||||
type MetaPosition =
|
||||
@ -437,11 +441,13 @@ const Message: FC<OwnProps & StateProps> = ({
|
||||
poll,
|
||||
maxTimestamp,
|
||||
lastPlaybackTimestamp,
|
||||
onIntersectPinnedMessage,
|
||||
isMediaNsfw,
|
||||
isReplyMediaNsfw,
|
||||
paidMessageStars,
|
||||
isChatWithUser,
|
||||
isAccountFrozen,
|
||||
minFutureTime,
|
||||
onIntersectPinnedMessage,
|
||||
}) => {
|
||||
const {
|
||||
toggleMessageSelection,
|
||||
@ -1119,6 +1125,7 @@ const Message: FC<OwnProps & StateProps> = ({
|
||||
senderChat={replyMessageChat}
|
||||
forwardSender={replyMessageForwardSender}
|
||||
chatTranslations={chatTranslations}
|
||||
isMediaNsfw={isReplyMediaNsfw}
|
||||
requestedChatTranslationLanguage={requestedChatTranslationLanguage}
|
||||
observeIntersectionForLoading={observeIntersectionForLoading}
|
||||
observeIntersectionForPlaying={observeIntersectionForPlaying}
|
||||
@ -1145,6 +1152,7 @@ const Message: FC<OwnProps & StateProps> = ({
|
||||
shouldLoop={shouldLoopStickers}
|
||||
shouldPlayEffect={shouldPlayEffect}
|
||||
withEffect={withAnimatedEffects}
|
||||
isMediaNsfw={isMediaNsfw}
|
||||
onStopEffect={hideEffect}
|
||||
/>
|
||||
)}
|
||||
@ -1443,6 +1451,7 @@ const Message: FC<OwnProps & StateProps> = ({
|
||||
isProtected={isProtected}
|
||||
asForwarded={asForwarded}
|
||||
theme={theme}
|
||||
isMediaNsfw={isMediaNsfw}
|
||||
forcedWidth={contentWidth}
|
||||
onClick={handlePhotoMediaClick}
|
||||
onCancelUpload={handleCancelUpload}
|
||||
@ -1462,6 +1471,7 @@ const Message: FC<OwnProps & StateProps> = ({
|
||||
isDownloading={isDownloading}
|
||||
isProtected={isProtected}
|
||||
asForwarded={asForwarded}
|
||||
isMediaNsfw={isMediaNsfw}
|
||||
lastPlaybackTimestamp={lastPlaybackTimestamp}
|
||||
onClick={handleVideoMediaClick}
|
||||
onCancelUpload={handleCancelUpload}
|
||||
@ -1895,7 +1905,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
const replyMessageChat = replyToPeerId ? selectChat(global, replyToPeerId) : undefined;
|
||||
const isReplyPrivate = !isSystemBotChat && !isAnonymousForwards && replyMessageChat
|
||||
&& !isChatPublic(replyMessageChat)
|
||||
&& (replyMessageChat.isNotJoined || replyMessageChat.isRestricted);
|
||||
&& (replyMessageChat.isNotJoined || selectIsChatRestricted(global, replyMessageChat.id));
|
||||
const isReplyToTopicStart = replyMessage?.content.action?.type === 'topicCreate';
|
||||
const replyStory = storyReplyId && storyReplyPeerId
|
||||
? selectPeerStory(global, storyReplyPeerId, storyReplyId)
|
||||
@ -1982,6 +1992,9 @@ export default memo(withGlobal<OwnProps>(
|
||||
|
||||
const minFutureTime = global.appConfig?.starsSuggestedPostFutureMin || STARS_SUGGESTED_POST_FUTURE_MIN;
|
||||
|
||||
const isMediaNsfw = selectIsMediaNsfw(global, message);
|
||||
const isReplyMediaNsfw = replyMessage && selectIsMediaNsfw(global, replyMessage);
|
||||
|
||||
return {
|
||||
theme: selectTheme(global),
|
||||
forceSenderName,
|
||||
@ -2076,6 +2089,8 @@ export default memo(withGlobal<OwnProps>(
|
||||
paidMessageStars,
|
||||
isChatWithUser,
|
||||
isAccountFrozen,
|
||||
isMediaNsfw,
|
||||
isReplyMediaNsfw,
|
||||
};
|
||||
},
|
||||
)(Message));
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import type React from '../../../lib/teact/teact';
|
||||
import { useEffect, useRef, useState } from '../../../lib/teact/teact';
|
||||
import { memo, useEffect, useRef, useState } from '../../../lib/teact/teact';
|
||||
import { getActions, withGlobal } from '../../../global';
|
||||
|
||||
import type { ApiMediaExtendedPreview, ApiPhoto } from '../../../api/types';
|
||||
import type { ObserveFn } from '../../../hooks/useIntersectionObserver';
|
||||
@ -28,6 +29,7 @@ import useBlurredMediaThumbRef from './hooks/useBlurredMediaThumbRef';
|
||||
|
||||
import Icon from '../../common/icons/Icon';
|
||||
import MediaSpoiler from '../../common/MediaSpoiler';
|
||||
import SensitiveContentConfirmModal from '../../common/SensitiveContentConfirmModal';
|
||||
import ProgressSpinner from '../../ui/ProgressSpinner';
|
||||
|
||||
export type OwnProps<T> = {
|
||||
@ -36,7 +38,6 @@ export type OwnProps<T> = {
|
||||
isInWebPage?: boolean;
|
||||
messageText?: string;
|
||||
isOwn?: boolean;
|
||||
observeIntersection?: ObserveFn;
|
||||
noAvatars?: boolean;
|
||||
canAutoLoad?: boolean;
|
||||
isInSelectMode?: boolean;
|
||||
@ -53,16 +54,21 @@ export type OwnProps<T> = {
|
||||
theme: ThemeKey;
|
||||
className?: string;
|
||||
clickArg?: T;
|
||||
isMediaNsfw?: boolean;
|
||||
observeIntersection?: ObserveFn;
|
||||
onClick?: (arg: T, e: React.MouseEvent<HTMLElement>) => void;
|
||||
onCancelUpload?: (arg: T) => void;
|
||||
};
|
||||
|
||||
type StateProps = {
|
||||
needsAgeVerification?: boolean;
|
||||
};
|
||||
|
||||
const Photo = <T,>({
|
||||
id,
|
||||
photo,
|
||||
messageText,
|
||||
isOwn,
|
||||
observeIntersection,
|
||||
noAvatars,
|
||||
canAutoLoad,
|
||||
isInSelectMode,
|
||||
@ -80,9 +86,12 @@ const Photo = <T,>({
|
||||
isInWebPage,
|
||||
clickArg,
|
||||
className,
|
||||
isMediaNsfw,
|
||||
observeIntersection,
|
||||
onClick,
|
||||
onCancelUpload,
|
||||
}: OwnProps<T>) => {
|
||||
needsAgeVerification,
|
||||
}: OwnProps<T> & StateProps) => {
|
||||
const ref = useRef<HTMLDivElement>();
|
||||
const isPaidPreview = photo.mediaType === 'extendedMediaPreview';
|
||||
|
||||
@ -106,15 +115,29 @@ const Photo = <T,>({
|
||||
const blurredBackgroundRef = useBlurredMediaThumbRef(photo, !withBlurredBackground);
|
||||
const thumbDataUri = getMediaThumbUri(photo);
|
||||
|
||||
const [isSpoilerShown, showSpoiler, hideSpoiler] = useFlag(isPaidPreview || photo.isSpoiler);
|
||||
const { updateContentSettings, openAgeVerificationModal } = getActions();
|
||||
const [isNsfwModalOpen, openNsfwModal, closeNsfwModal] = useFlag();
|
||||
const [shouldAlwaysShowNsfw, setShouldAlwaysShowNsfw] = useState(false);
|
||||
|
||||
const shouldShowSpoiler = isPaidPreview || photo.isSpoiler || isMediaNsfw;
|
||||
const [isSpoilerShown, showSpoiler, hideSpoiler] = useFlag(shouldShowSpoiler);
|
||||
|
||||
useEffect(() => {
|
||||
if (isPaidPreview || photo.isSpoiler) {
|
||||
if (shouldShowSpoiler) {
|
||||
showSpoiler();
|
||||
} else {
|
||||
hideSpoiler();
|
||||
}
|
||||
}, [isPaidPreview, photo]);
|
||||
}, [shouldShowSpoiler]);
|
||||
|
||||
const handleNsfwConfirm = useLastCallback(() => {
|
||||
closeNsfwModal();
|
||||
hideSpoiler();
|
||||
|
||||
if (shouldAlwaysShowNsfw) {
|
||||
updateContentSettings({ isSensitiveEnabled: true });
|
||||
}
|
||||
});
|
||||
|
||||
const {
|
||||
loadProgress: downloadProgress,
|
||||
@ -162,6 +185,14 @@ const Photo = <T,>({
|
||||
}
|
||||
|
||||
if (isSpoilerShown) {
|
||||
if (isMediaNsfw) {
|
||||
if (needsAgeVerification) {
|
||||
openAgeVerificationModal();
|
||||
return;
|
||||
}
|
||||
openNsfwModal();
|
||||
return;
|
||||
}
|
||||
hideSpoiler();
|
||||
return;
|
||||
}
|
||||
@ -250,6 +281,7 @@ const Photo = <T,>({
|
||||
width={width}
|
||||
height={height}
|
||||
className="media-spoiler"
|
||||
isNsfw={isMediaNsfw}
|
||||
/>
|
||||
{isTransferring && (
|
||||
<span className="message-transfer-progress">
|
||||
@ -257,8 +289,22 @@ const Photo = <T,>({
|
||||
%
|
||||
</span>
|
||||
)}
|
||||
<SensitiveContentConfirmModal
|
||||
isOpen={isNsfwModalOpen}
|
||||
onClose={closeNsfwModal}
|
||||
shouldAlwaysShow={shouldAlwaysShowNsfw}
|
||||
onAlwaysShowChanged={setShouldAlwaysShowNsfw}
|
||||
confirmHandler={handleNsfwConfirm}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Photo;
|
||||
export default memo(withGlobal((global): StateProps => {
|
||||
const appConfig = global.appConfig;
|
||||
const needsAgeVerification = appConfig?.needAgeVideoVerification;
|
||||
|
||||
return {
|
||||
needsAgeVerification,
|
||||
};
|
||||
})(Photo));
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
import type { FC } from '../../../lib/teact/teact';
|
||||
import { useEffect, useRef } from '../../../lib/teact/teact';
|
||||
import { getActions } from '../../../global';
|
||||
import { memo, useEffect, useRef, useState } from '../../../lib/teact/teact';
|
||||
import { getActions, withGlobal } from '../../../global';
|
||||
|
||||
import type { ApiMessage } from '../../../api/types';
|
||||
import type { ObserveFn } from '../../../hooks/useIntersectionObserver';
|
||||
import { ApiMediaFormat } from '../../../api/types';
|
||||
|
||||
import { getStickerMediaHash } from '../../../global/helpers';
|
||||
import { getMediaThumbUri, getStickerMediaHash } from '../../../global/helpers';
|
||||
import { IS_WEBM_SUPPORTED } from '../../../util/browser/windowEnvironment';
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
import { getStickerDimensions } from '../../common/helpers/mediaDimensions';
|
||||
@ -20,6 +20,8 @@ import useOldLang from '../../../hooks/useOldLang';
|
||||
import useOverlayPosition from './hooks/useOverlayPosition';
|
||||
|
||||
import AnimatedSticker from '../../common/AnimatedSticker';
|
||||
import MediaSpoiler from '../../common/MediaSpoiler';
|
||||
import SensitiveContentConfirmModal from '../../common/SensitiveContentConfirmModal';
|
||||
import StickerView from '../../common/StickerView';
|
||||
import Portal from '../../ui/Portal';
|
||||
|
||||
@ -30,19 +32,31 @@ const EFFECT_SIZE_MULTIPLIER = 1 + 0.245 * 2;
|
||||
|
||||
type OwnProps = {
|
||||
message: ApiMessage;
|
||||
observeIntersection: ObserveFn;
|
||||
observeIntersectionForPlaying: ObserveFn;
|
||||
shouldLoop?: boolean;
|
||||
shouldPlayEffect?: boolean;
|
||||
withEffect?: boolean;
|
||||
isMediaNsfw?: boolean;
|
||||
observeIntersection: ObserveFn;
|
||||
observeIntersectionForPlaying: ObserveFn;
|
||||
onStopEffect?: VoidFunction;
|
||||
};
|
||||
|
||||
const Sticker: FC<OwnProps> = ({
|
||||
message, observeIntersection, observeIntersectionForPlaying, shouldLoop,
|
||||
shouldPlayEffect, withEffect, onStopEffect,
|
||||
type StateProps = {
|
||||
needsAgeVerification?: boolean;
|
||||
};
|
||||
|
||||
const Sticker: FC<OwnProps & StateProps> = ({
|
||||
message,
|
||||
shouldLoop,
|
||||
shouldPlayEffect,
|
||||
withEffect,
|
||||
isMediaNsfw,
|
||||
onStopEffect,
|
||||
observeIntersection,
|
||||
observeIntersectionForPlaying,
|
||||
needsAgeVerification,
|
||||
}) => {
|
||||
const { showNotification, openStickerSet } = getActions();
|
||||
const { showNotification, openStickerSet, updateContentSettings, openAgeVerificationModal } = getActions();
|
||||
|
||||
const lang = useOldLang();
|
||||
const { isMobile } = useAppLayout();
|
||||
@ -55,6 +69,29 @@ const Sticker: FC<OwnProps> = ({
|
||||
const { stickerSetInfo, isVideo, hasEffect } = sticker;
|
||||
const isMirrored = !message.isOutgoing;
|
||||
|
||||
const [isNsfwModalOpen, openNsfwModal, closeNsfwModal] = useFlag();
|
||||
const [shouldAlwaysShowNsfw, setShouldAlwaysShowNsfw] = useState(false);
|
||||
|
||||
const shouldShowSpoiler = isMediaNsfw;
|
||||
const [isSpoilerShown, showSpoiler, hideSpoiler] = useFlag(shouldShowSpoiler);
|
||||
|
||||
useEffect(() => {
|
||||
if (shouldShowSpoiler) {
|
||||
showSpoiler();
|
||||
} else {
|
||||
hideSpoiler();
|
||||
}
|
||||
}, [shouldShowSpoiler]);
|
||||
|
||||
const handleNsfwConfirm = useLastCallback(() => {
|
||||
closeNsfwModal();
|
||||
hideSpoiler();
|
||||
|
||||
if (shouldAlwaysShowNsfw) {
|
||||
updateContentSettings({ isSensitiveEnabled: true });
|
||||
}
|
||||
});
|
||||
|
||||
const mediaHash = sticker.isPreloadedGlobally ? undefined : (
|
||||
getStickerMediaHash(sticker, isVideo && !IS_WEBM_SUPPORTED ? 'pictogram' : 'inline')
|
||||
);
|
||||
@ -69,6 +106,8 @@ const Sticker: FC<OwnProps> = ({
|
||||
);
|
||||
const [isPlayingEffect, startPlayingEffect, stopPlayingEffect] = useFlag();
|
||||
|
||||
const thumbDataUri = getMediaThumbUri(sticker);
|
||||
|
||||
const handleEffectEnded = useLastCallback(() => {
|
||||
stopPlayingEffect();
|
||||
onStopEffect?.();
|
||||
@ -95,6 +134,19 @@ const Sticker: FC<OwnProps> = ({
|
||||
});
|
||||
|
||||
const handleClick = useLastCallback(() => {
|
||||
if (isSpoilerShown) {
|
||||
if (isMediaNsfw) {
|
||||
if (needsAgeVerification) {
|
||||
openAgeVerificationModal();
|
||||
return;
|
||||
}
|
||||
openNsfwModal();
|
||||
return;
|
||||
}
|
||||
hideSpoiler();
|
||||
return;
|
||||
}
|
||||
|
||||
if (hasEffect) {
|
||||
if (isPlayingEffect || !withEffect) {
|
||||
showNotification({
|
||||
@ -143,6 +195,15 @@ const Sticker: FC<OwnProps> = ({
|
||||
noPlay={!canPlay}
|
||||
withSharedAnimation
|
||||
/>
|
||||
<MediaSpoiler
|
||||
isVisible={isSpoilerShown}
|
||||
withAnimation
|
||||
thumbDataUri={thumbDataUri}
|
||||
width={width}
|
||||
height={height}
|
||||
className="media-spoiler"
|
||||
isNsfw={isMediaNsfw}
|
||||
/>
|
||||
{shouldRenderEffect && (
|
||||
<Portal>
|
||||
<AnimatedSticker
|
||||
@ -158,8 +219,22 @@ const Sticker: FC<OwnProps> = ({
|
||||
/>
|
||||
</Portal>
|
||||
)}
|
||||
<SensitiveContentConfirmModal
|
||||
isOpen={isNsfwModalOpen}
|
||||
onClose={closeNsfwModal}
|
||||
shouldAlwaysShow={shouldAlwaysShowNsfw}
|
||||
onAlwaysShowChanged={setShouldAlwaysShowNsfw}
|
||||
confirmHandler={handleNsfwConfirm}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Sticker;
|
||||
export default memo(withGlobal<OwnProps>((global): StateProps => {
|
||||
const appConfig = global.appConfig;
|
||||
const needsAgeVerification = appConfig?.needAgeVideoVerification;
|
||||
|
||||
return {
|
||||
needsAgeVerification,
|
||||
};
|
||||
})(Sticker));
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import type React from '../../../lib/teact/teact';
|
||||
import { useEffect, useRef, useState } from '../../../lib/teact/teact';
|
||||
import { getActions } from '../../../global';
|
||||
import { memo, useEffect, useRef, useState } from '../../../lib/teact/teact';
|
||||
import { getActions, withGlobal } from '../../../global';
|
||||
|
||||
import type { ApiMediaExtendedPreview, ApiVideo } from '../../../api/types';
|
||||
import type { ObserveFn } from '../../../hooks/useIntersectionObserver';
|
||||
@ -29,6 +29,7 @@ import useBlurredMediaThumbRef from './hooks/useBlurredMediaThumbRef';
|
||||
|
||||
import Icon from '../../common/icons/Icon';
|
||||
import MediaSpoiler from '../../common/MediaSpoiler';
|
||||
import SensitiveContentConfirmModal from '../../common/SensitiveContentConfirmModal';
|
||||
import OptimizedVideo from '../../ui/OptimizedVideo';
|
||||
import ProgressSpinner from '../../ui/ProgressSpinner';
|
||||
|
||||
@ -38,8 +39,6 @@ export type OwnProps<T> = {
|
||||
lastPlaybackTimestamp?: number;
|
||||
isOwn?: boolean;
|
||||
isInWebPage?: boolean;
|
||||
observeIntersectionForLoading?: ObserveFn;
|
||||
observeIntersectionForPlaying?: ObserveFn;
|
||||
noAvatars?: boolean;
|
||||
canAutoLoad?: boolean;
|
||||
canAutoPlay?: boolean;
|
||||
@ -51,17 +50,22 @@ export type OwnProps<T> = {
|
||||
isProtected?: boolean;
|
||||
className?: string;
|
||||
clickArg?: T;
|
||||
isMediaNsfw?: boolean;
|
||||
observeIntersectionForLoading?: ObserveFn;
|
||||
observeIntersectionForPlaying?: ObserveFn;
|
||||
onClick?: (arg: T, e: React.MouseEvent<HTMLElement>) => void;
|
||||
onCancelUpload?: (arg: T) => void;
|
||||
};
|
||||
|
||||
type StateProps = {
|
||||
needsAgeVerification?: boolean;
|
||||
};
|
||||
|
||||
const Video = <T,>({
|
||||
id,
|
||||
video,
|
||||
isOwn,
|
||||
isInWebPage,
|
||||
observeIntersectionForLoading,
|
||||
observeIntersectionForPlaying,
|
||||
noAvatars,
|
||||
canAutoLoad,
|
||||
canAutoPlay,
|
||||
@ -74,26 +78,42 @@ const Video = <T,>({
|
||||
className,
|
||||
lastPlaybackTimestamp,
|
||||
clickArg,
|
||||
isMediaNsfw,
|
||||
observeIntersectionForLoading,
|
||||
observeIntersectionForPlaying,
|
||||
onClick,
|
||||
onCancelUpload,
|
||||
}: OwnProps<T>) => {
|
||||
const { cancelMediaDownload } = getActions();
|
||||
needsAgeVerification,
|
||||
}: OwnProps<T> & StateProps) => {
|
||||
const { cancelMediaDownload, updateContentSettings, openAgeVerificationModal } = getActions();
|
||||
const ref = useRef<HTMLDivElement>();
|
||||
const videoRef = useRef<HTMLVideoElement>();
|
||||
const [isNsfwModalOpen, openNsfwModal, closeNsfwModal] = useFlag();
|
||||
const [shouldAlwaysShowNsfw, setShouldAlwaysShowNsfw] = useState(false);
|
||||
|
||||
const isPaidPreview = video.mediaType === 'extendedMediaPreview';
|
||||
|
||||
const localBlobUrl = !isPaidPreview ? video.blobUrl : undefined;
|
||||
|
||||
const [isSpoilerShown, showSpoiler, hideSpoiler] = useFlag(isPaidPreview || video.isSpoiler);
|
||||
const shouldShowSpoiler = isPaidPreview || video.isSpoiler || isMediaNsfw;
|
||||
const [isSpoilerShown, showSpoiler, hideSpoiler] = useFlag(shouldShowSpoiler);
|
||||
|
||||
useEffect(() => {
|
||||
if (isPaidPreview || video.isSpoiler) {
|
||||
if (shouldShowSpoiler) {
|
||||
showSpoiler();
|
||||
} else {
|
||||
hideSpoiler();
|
||||
}
|
||||
}, [isPaidPreview, video]);
|
||||
}, [shouldShowSpoiler]);
|
||||
|
||||
const handleNsfwConfirm = useLastCallback(() => {
|
||||
closeNsfwModal();
|
||||
hideSpoiler();
|
||||
|
||||
if (shouldAlwaysShowNsfw) {
|
||||
updateContentSettings({ isSensitiveEnabled: true });
|
||||
}
|
||||
});
|
||||
|
||||
const isIntersectingForLoading = useIsIntersecting(ref, observeIntersectionForLoading);
|
||||
const isIntersectingForPlaying = (
|
||||
@ -204,6 +224,14 @@ const Video = <T,>({
|
||||
}
|
||||
|
||||
if (isSpoilerShown) {
|
||||
if (isMediaNsfw) {
|
||||
if (needsAgeVerification) {
|
||||
openAgeVerificationModal();
|
||||
return;
|
||||
}
|
||||
openNsfwModal();
|
||||
return;
|
||||
}
|
||||
hideSpoiler();
|
||||
return;
|
||||
}
|
||||
@ -278,6 +306,7 @@ const Video = <T,>({
|
||||
isVisible={isSpoilerShown}
|
||||
withAnimation
|
||||
thumbDataUri={thumbDataUri}
|
||||
isNsfw={isMediaNsfw}
|
||||
width={width}
|
||||
height={height}
|
||||
className="media-spoiler"
|
||||
@ -309,8 +338,22 @@ const Video = <T,>({
|
||||
style={`--_progress: ${Math.floor((lastPlaybackTimestamp / duration) * 100)}%`}
|
||||
/>
|
||||
)}
|
||||
<SensitiveContentConfirmModal
|
||||
isOpen={isNsfwModalOpen}
|
||||
onClose={closeNsfwModal}
|
||||
shouldAlwaysShow={shouldAlwaysShowNsfw}
|
||||
onAlwaysShowChanged={setShouldAlwaysShowNsfw}
|
||||
confirmHandler={handleNsfwConfirm}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Video;
|
||||
export default memo(withGlobal((global): StateProps => {
|
||||
const appConfig = global.appConfig;
|
||||
const needsAgeVerification = appConfig?.needAgeVideoVerification;
|
||||
|
||||
return {
|
||||
needsAgeVerification,
|
||||
};
|
||||
})(Video));
|
||||
|
||||
@ -10,6 +10,7 @@ import { pick } from '../../util/iteratees';
|
||||
import VerificationMonetizationModal from '../common/VerificationMonetizationModal.async';
|
||||
import WebAppsCloseConfirmationModal from '../main/WebAppsCloseConfirmationModal.async';
|
||||
import AboutAdsModal from './aboutAds/AboutAdsModal.async';
|
||||
import AgeVerificationModal from './ageVerification/AgeVerificationModal.async';
|
||||
import AttachBotInstallModal from './attachBotInstall/AttachBotInstallModal.async';
|
||||
import BoostModal from './boost/BoostModal.async';
|
||||
import ChatInviteModal from './chatInvite/ChatInviteModal.async';
|
||||
@ -89,7 +90,8 @@ type ModalKey = keyof Pick<TabState,
|
||||
'giftTransferModal' |
|
||||
'chatRefundModal' |
|
||||
'isFrozenAccountModalOpen' |
|
||||
'deleteAccountModal'
|
||||
'deleteAccountModal' |
|
||||
'isAgeVerificationModalOpen'
|
||||
>;
|
||||
|
||||
type StateProps = {
|
||||
@ -145,6 +147,7 @@ const MODALS: ModalRegistry = {
|
||||
chatRefundModal: ChatRefundModal,
|
||||
isFrozenAccountModalOpen: FrozenAccountModal,
|
||||
deleteAccountModal: DeleteAccountModal,
|
||||
isAgeVerificationModalOpen: AgeVerificationModal,
|
||||
};
|
||||
const MODAL_KEYS = Object.keys(MODALS) as ModalKey[];
|
||||
const MODAL_ENTRIES = Object.entries(MODALS) as Entries<ModalRegistry>;
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
import type { FC } from '../../../lib/teact/teact';
|
||||
import { memo } from '../../../lib/teact/teact';
|
||||
|
||||
import type { OwnProps } from './AgeVerificationModal';
|
||||
|
||||
import { Bundles } from '../../../util/moduleLoader';
|
||||
|
||||
import useModuleLoader from '../../../hooks/useModuleLoader';
|
||||
|
||||
const AgeVerificationModalAsync: FC<OwnProps> = memo((props) => {
|
||||
const { modal } = props;
|
||||
|
||||
const AgeVerificationModal = useModuleLoader(Bundles.Extra, 'AgeVerificationModal', !modal);
|
||||
|
||||
return AgeVerificationModal ? <AgeVerificationModal {...props} /> : undefined;
|
||||
});
|
||||
|
||||
export default AgeVerificationModalAsync;
|
||||
@ -0,0 +1,41 @@
|
||||
.root {
|
||||
:global(.modal-dialog) {
|
||||
max-width: 25rem;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 1rem 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.iconWrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
width: 4rem;
|
||||
height: 4rem;
|
||||
border-radius: 50%;
|
||||
|
||||
background-color: var(--accent-color);
|
||||
}
|
||||
|
||||
.icon {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
font-size: 2rem;
|
||||
color: var(--color-white);
|
||||
}
|
||||
|
||||
.mainText,
|
||||
.description {
|
||||
font-size: 0.9375rem;
|
||||
color: var(--color-text);
|
||||
}
|
||||
@ -0,0 +1,93 @@
|
||||
import type { FC } from '../../../lib/teact/teact';
|
||||
import { memo } from '../../../lib/teact/teact';
|
||||
import { getActions, withGlobal } from '../../../global';
|
||||
|
||||
import type { TabState } from '../../../global/types';
|
||||
|
||||
import useLang from '../../../hooks/useLang';
|
||||
import useLastCallback from '../../../hooks/useLastCallback';
|
||||
|
||||
import Icon from '../../common/icons/Icon';
|
||||
import Button from '../../ui/Button';
|
||||
import Modal from '../../ui/Modal';
|
||||
|
||||
import styles from './AgeVerificationModal.module.scss';
|
||||
|
||||
export type OwnProps = {
|
||||
modal: TabState['isAgeVerificationModalOpen'];
|
||||
};
|
||||
|
||||
type StateProps = {
|
||||
verifyAgeBotUsername?: string;
|
||||
};
|
||||
|
||||
const AGE_REQUIRED = 18;
|
||||
|
||||
const AgeVerificationModal: FC<OwnProps & StateProps> = ({
|
||||
modal,
|
||||
verifyAgeBotUsername,
|
||||
}) => {
|
||||
const { closeAgeVerificationModal, openChatByUsername } = getActions();
|
||||
const lang = useLang();
|
||||
const isOpen = Boolean(modal);
|
||||
const ageRequired = AGE_REQUIRED;
|
||||
|
||||
const handleVerifyAge = useLastCallback(() => {
|
||||
if (verifyAgeBotUsername) {
|
||||
openChatByUsername({
|
||||
shouldStartMainApp: true,
|
||||
username: verifyAgeBotUsername,
|
||||
});
|
||||
}
|
||||
closeAgeVerificationModal();
|
||||
});
|
||||
|
||||
const handleClose = useLastCallback(() => {
|
||||
closeAgeVerificationModal();
|
||||
});
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
onClose={handleClose}
|
||||
className={styles.root}
|
||||
>
|
||||
<div className={styles.content}>
|
||||
<div className={styles.header}>
|
||||
<div className={styles.iconWrapper}>
|
||||
<Icon name="user" className={styles.icon} />
|
||||
</div>
|
||||
</div>
|
||||
<h2 className={styles.title}>
|
||||
{lang('TitleAgeVerificationModal')}
|
||||
</h2>
|
||||
<p className={styles.mainText}>
|
||||
{lang('TextAgeVerificationModal', { count: ageRequired }, {
|
||||
withMarkdown: true,
|
||||
withNodes: true,
|
||||
pluralValue: ageRequired,
|
||||
})}
|
||||
</p>
|
||||
<p className={styles.description}>
|
||||
{lang('DescriptionAgeVerificationModal')}
|
||||
</p>
|
||||
</div>
|
||||
<div className="dialog-buttons mt-2">
|
||||
<Button
|
||||
onClick={handleVerifyAge}
|
||||
>
|
||||
{lang('ButtonAgeVerification')}
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(withGlobal((global): StateProps => {
|
||||
const appConfig = global.appConfig;
|
||||
const verifyAgeBotUsername = appConfig?.verifyAgeBotUsername;
|
||||
|
||||
return {
|
||||
verifyAgeBotUsername,
|
||||
};
|
||||
})(AgeVerificationModal));
|
||||
@ -50,6 +50,7 @@ const useWebAppFrame = (
|
||||
closeWebApp,
|
||||
openSuggestedStatusModal,
|
||||
updateWebApp,
|
||||
updateContentSettings,
|
||||
} = getActions();
|
||||
|
||||
const isReloadSupported = useRef<boolean>(false);
|
||||
@ -382,6 +383,25 @@ const useWebAppFrame = (
|
||||
});
|
||||
}
|
||||
|
||||
if (eventType === 'web_app_verify_age') {
|
||||
const { passed } = eventData;
|
||||
|
||||
if (passed) {
|
||||
showNotification({
|
||||
message: {
|
||||
key: 'TitleAgeCheckSuccess',
|
||||
},
|
||||
});
|
||||
updateContentSettings({ isSensitiveEnabled: true });
|
||||
} else {
|
||||
showNotification({
|
||||
message: {
|
||||
key: 'TitleAgeCheckFailed',
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onEvent(data);
|
||||
} catch (err) {
|
||||
// Ignore other messages
|
||||
|
||||
@ -48,6 +48,7 @@ import {
|
||||
selectChatFullInfo,
|
||||
selectChatMessages,
|
||||
selectCurrentSharedMediaSearch,
|
||||
selectIsChatRestricted,
|
||||
selectIsCurrentUserPremium,
|
||||
selectIsRightColumnShown,
|
||||
selectMonoforumChannel,
|
||||
@ -995,6 +996,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
const peerGifts = selectTabState(global).savedGifts.giftsByPeerId[chatId];
|
||||
|
||||
const monoforumChannel = selectMonoforumChannel(global, chatId);
|
||||
const isRestricted = chat && selectIsChatRestricted(global, chat.id);
|
||||
|
||||
return {
|
||||
theme: selectTheme(global),
|
||||
@ -1012,7 +1014,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
canDeleteMembers,
|
||||
currentUserId: global.currentUserId,
|
||||
isRightColumnShown: selectIsRightColumnShown(global, isMobile),
|
||||
isRestricted: chat?.isRestricted,
|
||||
isRestricted,
|
||||
activeDownloads,
|
||||
usersById,
|
||||
userStatusesById,
|
||||
|
||||
@ -3,7 +3,7 @@ import type { FC } from '../../../lib/teact/teact';
|
||||
import {
|
||||
memo, useEffect, useMemo, useState,
|
||||
} from '../../../lib/teact/teact';
|
||||
import { getActions, withGlobal } from '../../../global';
|
||||
import { getActions, getGlobal, withGlobal } from '../../../global';
|
||||
|
||||
import type {
|
||||
ApiAvailableReaction, ApiChat, ApiChatFullInfo, ApiExportedInvite,
|
||||
@ -12,7 +12,7 @@ import { ApiMediaFormat } from '../../../api/types';
|
||||
import { ManagementProgress, ManagementScreens } from '../../../types';
|
||||
|
||||
import { getChatAvatarHash, getHasAdminRight, isChatChannel, isChatPublic } from '../../../global/helpers';
|
||||
import { selectChat, selectChatFullInfo, selectTabState } from '../../../global/selectors';
|
||||
import { selectChat, selectChatFullInfo, selectIsChatRestricted, selectTabState } from '../../../global/selectors';
|
||||
import { formatInteger } from '../../../util/textFormat';
|
||||
|
||||
import useFlag from '../../../hooks/useFlag';
|
||||
@ -217,7 +217,8 @@ const ManageChannel: FC<OwnProps & StateProps> = ({
|
||||
}, [availableReactions, chatFullInfo?.enabledReactions, lang]);
|
||||
const isChannelPublic = useMemo(() => isChatPublic(chat), [chat]);
|
||||
|
||||
if (chat.isRestricted || chat.isForbidden) {
|
||||
const isRestricted = selectIsChatRestricted(getGlobal(), chatId);
|
||||
if (isRestricted || chat.isForbidden) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ import type { FC } from '../../../lib/teact/teact';
|
||||
import {
|
||||
memo, useEffect, useMemo, useRef, useState,
|
||||
} from '../../../lib/teact/teact';
|
||||
import { getActions, withGlobal } from '../../../global';
|
||||
import { getActions, getGlobal, withGlobal } from '../../../global';
|
||||
|
||||
import type {
|
||||
ApiAvailableReaction, ApiChat, ApiChatBannedRights, ApiChatFullInfo, ApiExportedInvite,
|
||||
@ -17,7 +17,7 @@ import {
|
||||
isChatBasicGroup,
|
||||
isChatPublic,
|
||||
} from '../../../global/helpers';
|
||||
import { selectChat, selectChatFullInfo, selectTabState } from '../../../global/selectors';
|
||||
import { selectChat, selectChatFullInfo, selectIsChatRestricted, selectTabState } from '../../../global/selectors';
|
||||
import { debounce } from '../../../util/schedulers';
|
||||
import { formatInteger } from '../../../util/textFormat';
|
||||
import renderText from '../../common/helpers/renderText';
|
||||
@ -312,7 +312,8 @@ const ManageGroup: FC<OwnProps & StateProps> = ({
|
||||
openChat({ id: undefined });
|
||||
});
|
||||
|
||||
if (chat.isRestricted || chat.isForbidden) {
|
||||
const isRestricted = selectIsChatRestricted(getGlobal(), chatId);
|
||||
if (isRestricted || chat.isForbidden) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
@ -344,6 +344,8 @@ export const TME_WEB_DOMAINS = new Set(['t.me', 'web.t.me', 'a.t.me', 'k.t.me',
|
||||
export const WEB_APP_PLATFORM = 'weba';
|
||||
export const LANG_PACK = 'weba';
|
||||
|
||||
export const NSFW_RESTRICTION_REASON = 'sensitive';
|
||||
|
||||
// eslint-disable-next-line @stylistic/max-len
|
||||
export const COUNTRIES_WITH_12H_TIME_FORMAT = new Set(['AU', 'BD', 'CA', 'CO', 'EG', 'HN', 'IE', 'IN', 'JO', 'MX', 'MY', 'NI', 'NZ', 'PH', 'PK', 'SA', 'SV', 'US']);
|
||||
|
||||
|
||||
@ -1633,7 +1633,8 @@ addActionHandler('acceptChatInvite', async (global, actions, payload): Promise<v
|
||||
|
||||
addActionHandler('openChatByUsername', async (global, actions, payload): Promise<void> => {
|
||||
const {
|
||||
username, messageId, commentId, startParam, startAttach, attach, threadId, originalParts, startApp, mode,
|
||||
username, messageId, commentId, startParam, startAttach, attach, threadId, originalParts,
|
||||
startApp, shouldStartMainApp, mode,
|
||||
text, onChatChanged, choose, ref, timestamp,
|
||||
tabId = getCurrentTabId(),
|
||||
} = payload;
|
||||
@ -1661,7 +1662,7 @@ addActionHandler('openChatByUsername', async (global, actions, payload): Promise
|
||||
return;
|
||||
}
|
||||
|
||||
if (startApp !== undefined && !webAppName) {
|
||||
if ((startApp !== undefined && !webAppName) || shouldStartMainApp) {
|
||||
const theme = extractCurrentThemeParams();
|
||||
const chatByUsername = await fetchChatByUsername(global, username);
|
||||
global = getGlobal();
|
||||
|
||||
@ -126,6 +126,7 @@ import {
|
||||
selectForwardsCanBeSentToChat,
|
||||
selectForwardsContainVoiceMessages,
|
||||
selectIsChatBotNotStarted,
|
||||
selectIsChatRestricted,
|
||||
selectIsChatWithSelf,
|
||||
selectIsCurrentUserFrozen,
|
||||
selectIsCurrentUserPremium,
|
||||
@ -187,8 +188,9 @@ addActionHandler('loadViewportMessages', (global, actions, payload): ActionRetur
|
||||
}
|
||||
|
||||
const chat = selectChat(global, chatId);
|
||||
// TODO Revise if `chat.isRestricted` check is needed
|
||||
if (!chat || chat.isRestricted) {
|
||||
const isRestricted = selectIsChatRestricted(global, chatId);
|
||||
// TODO Revise if `isRestricted` check is needed
|
||||
if (!chat || isRestricted) {
|
||||
onError?.();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -31,6 +31,7 @@ import { updateTabState } from '../../reducers/tabs';
|
||||
import {
|
||||
selectChat,
|
||||
selectChatFullInfo,
|
||||
selectIsChatRestricted,
|
||||
selectIsCurrentUserFrozen,
|
||||
selectIsCurrentUserPremium,
|
||||
selectPeer,
|
||||
@ -309,6 +310,10 @@ addActionHandler('loadMoreProfilePhotos', async (global, actions, payload): Prom
|
||||
const user = isPrivate ? selectUser(global, peerId) : undefined;
|
||||
const chat = !isPrivate ? selectChat(global, peerId) : undefined;
|
||||
const peer = user || chat;
|
||||
|
||||
if (chat && selectIsChatRestricted(global, peerId)) {
|
||||
return;
|
||||
}
|
||||
const profilePhotos = selectPeerPhotos(global, peerId);
|
||||
if (!peer?.avatarPhotoId) {
|
||||
return;
|
||||
|
||||
@ -44,7 +44,7 @@ import {
|
||||
|
||||
const TYPING_STATUS_CLEAR_DELAY = 6000; // 6 seconds
|
||||
const INVALIDATE_FULL_CHAT_FIELDS = new Set<keyof ApiChat>([
|
||||
'boostLevel', 'isForum', 'isLinkedInDiscussion', 'fakeType', 'restrictionReason', 'isJoinToSend', 'isJoinRequest',
|
||||
'boostLevel', 'isForum', 'isLinkedInDiscussion', 'fakeType', 'restrictionReasons', 'isJoinToSend', 'isJoinRequest',
|
||||
'type',
|
||||
]);
|
||||
|
||||
|
||||
@ -41,3 +41,19 @@ addActionHandler('closeDeleteAccountModal', (global, actions, payload): ActionRe
|
||||
deleteAccountModal: undefined,
|
||||
}, tabId);
|
||||
});
|
||||
|
||||
addActionHandler('openAgeVerificationModal', (global, actions, payload): ActionReturnType => {
|
||||
const { tabId = getCurrentTabId() } = payload || {};
|
||||
|
||||
return updateTabState(global, {
|
||||
isAgeVerificationModalOpen: true,
|
||||
}, tabId);
|
||||
});
|
||||
|
||||
addActionHandler('closeAgeVerificationModal', (global, actions, payload): ActionReturnType => {
|
||||
const { tabId = getCurrentTabId() } = payload || {};
|
||||
|
||||
return updateTabState(global, {
|
||||
isAgeVerificationModalOpen: false,
|
||||
}, tabId);
|
||||
});
|
||||
|
||||
@ -25,6 +25,7 @@ import {
|
||||
import { formatDateToString, formatTime } from '../../util/dates/dateFormat';
|
||||
import { getPeerIdDividend, isUserId } from '../../util/entities/ids';
|
||||
import { getServerTime } from '../../util/serverTime';
|
||||
import { selectIsChatRestricted } from '../selectors';
|
||||
import { getGlobal } from '..';
|
||||
import { isSystemBot } from './bots';
|
||||
import { getMainUsername } from './users';
|
||||
@ -155,7 +156,9 @@ export function getCanPostInChat(
|
||||
}
|
||||
}
|
||||
|
||||
if (chat.isRestricted || chat.isForbidden || chat.migratedTo
|
||||
const global = getGlobal();
|
||||
const isRestricted = selectIsChatRestricted(global, chat.id);
|
||||
if (isRestricted || chat.isForbidden || chat.migratedTo
|
||||
|| (chat.isNotJoined && !isChatMonoforum(chat) && !isMessageThread)
|
||||
|| isSystemBot(chat.id) || isAnonymousForwardsChat(chat.id)) {
|
||||
return false;
|
||||
@ -380,7 +383,9 @@ export function getGroupStatus(lang: OldLangFn, chat: ApiChat) {
|
||||
const chatTypeString = lang(getChatTypeString(chat));
|
||||
const { membersCount } = chat;
|
||||
|
||||
if (chat.isRestricted) {
|
||||
const global = getGlobal();
|
||||
const isRestricted = selectIsChatRestricted(global, chat.id);
|
||||
if (isRestricted) {
|
||||
return chatTypeString === 'Channel' ? 'channel is inaccessible' : 'group is inaccessible';
|
||||
}
|
||||
|
||||
|
||||
@ -20,6 +20,7 @@ import {
|
||||
isUserBot,
|
||||
isUserOnline,
|
||||
} from '../helpers';
|
||||
import { selectActiveRestrictionReasons } from './messages';
|
||||
import { selectTabState } from './tabs';
|
||||
import {
|
||||
selectBot, selectIsCurrentUserPremium, selectUser, selectUserFullInfo,
|
||||
@ -374,3 +375,11 @@ export function selectMonoforumChannel<T extends GlobalState>(
|
||||
|
||||
return chat.isMonoforum ? selectChat(global, chat.linkedMonoforumId!) : undefined;
|
||||
}
|
||||
|
||||
export function selectIsChatRestricted<T extends GlobalState>(global: T, chatId: string): boolean {
|
||||
const chat = selectChat(global, chatId);
|
||||
if (!chat) return false;
|
||||
|
||||
const activeRestrictions = selectActiveRestrictionReasons(global, chat.restrictionReasons);
|
||||
return activeRestrictions.length > 0;
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ import {
|
||||
isAnonymousForwardsChat,
|
||||
isChatAdmin, isChatGroup, isUserBot,
|
||||
} from '../helpers';
|
||||
import { selectChat, selectIsChatWithSelf } from './chats';
|
||||
import { selectChat, selectIsChatRestricted, selectIsChatWithSelf } from './chats';
|
||||
import { selectCurrentMessageList } from './messages';
|
||||
import { selectTabState } from './tabs';
|
||||
import { selectBot, selectUser } from './users';
|
||||
@ -72,7 +72,8 @@ export function selectCanManage<T extends GlobalState>(
|
||||
chatId: string,
|
||||
) {
|
||||
const chat = selectChat(global, chatId);
|
||||
if (!chat || chat.isRestricted || chat.isMonoforum) return false;
|
||||
const isRestricted = selectIsChatRestricted(global, chatId);
|
||||
if (!chat || isRestricted || chat.isMonoforum) return false;
|
||||
|
||||
const isPrivate = isUserId(chat.id);
|
||||
const user = isPrivate ? selectUser(global, chatId) : undefined;
|
||||
|
||||
@ -5,7 +5,7 @@ import type {
|
||||
ApiMessageEntityCustomEmoji,
|
||||
ApiMessageForwardInfo,
|
||||
ApiMessageOutgoingStatus,
|
||||
ApiPeer, ApiSponsoredMessage,
|
||||
ApiPeer, ApiRestrictionReason, ApiSponsoredMessage,
|
||||
ApiStickerSetInfo,
|
||||
} from '../../api/types';
|
||||
import type {
|
||||
@ -22,8 +22,8 @@ import type {
|
||||
import { ApiMessageEntityTypes, MAIN_THREAD_ID } from '../../api/types';
|
||||
|
||||
import {
|
||||
ANONYMOUS_USER_ID, API_GENERAL_ID_LIMIT, GENERAL_TOPIC_ID, SERVICE_NOTIFICATIONS_USER_ID,
|
||||
SVG_EXTENSIONS,
|
||||
ANONYMOUS_USER_ID, API_GENERAL_ID_LIMIT, GENERAL_TOPIC_ID, NSFW_RESTRICTION_REASON, SERVICE_NOTIFICATIONS_USER_ID,
|
||||
SVG_EXTENSIONS, WEB_APP_PLATFORM,
|
||||
} from '../../config';
|
||||
import { IS_TRANSLATION_SUPPORTED } from '../../util/browser/windowEnvironment';
|
||||
import { isUserId } from '../../util/entities/ids';
|
||||
@ -72,11 +72,13 @@ import {
|
||||
selectChat,
|
||||
selectChatFullInfo,
|
||||
selectChatLastMessageId,
|
||||
selectIsChatRestricted,
|
||||
selectIsChatWithBot,
|
||||
selectIsChatWithSelf,
|
||||
selectRequestedChatTranslationLanguage,
|
||||
} from './chats';
|
||||
import { selectPeer, selectPeerPaidMessagesStars } from './peers';
|
||||
import { selectSettingsKeys } from './settings';
|
||||
import { selectPeerStory } from './stories';
|
||||
import { selectIsStickerFavorite } from './symbols';
|
||||
import { selectTabState } from './tabs';
|
||||
@ -587,7 +589,8 @@ export function selectThreadIdFromMessage<T extends GlobalState>(global: T, mess
|
||||
|
||||
export function selectCanReplyToMessage<T extends GlobalState>(global: T, message: ApiMessage, threadId: ThreadId) {
|
||||
const chat = selectChat(global, message.chatId);
|
||||
if (!chat || chat.isRestricted || chat.isForbidden) return false;
|
||||
const isRestricted = selectIsChatRestricted(global, message.chatId);
|
||||
if (!chat || isRestricted || chat.isForbidden) return false;
|
||||
|
||||
const isLocal = isMessageLocal(message);
|
||||
const isServiceNotification = isServiceNotificationMessage(message);
|
||||
@ -632,7 +635,8 @@ export function selectAllowedMessageActionsSlow<T extends GlobalState>(
|
||||
global: T, message: ApiMessage, threadId: ThreadId,
|
||||
) {
|
||||
const chat = selectChat(global, message.chatId);
|
||||
if (!chat || chat.isRestricted) {
|
||||
const isRestricted = selectIsChatRestricted(global, message.chatId);
|
||||
if (!chat || isRestricted) {
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -1563,3 +1567,31 @@ export function selectMessageLastPlaybackTimestamp<T extends GlobalState>(
|
||||
) {
|
||||
return global.messages.playbackByChatId[chatId]?.byId[messageId];
|
||||
}
|
||||
|
||||
export function selectActiveRestrictionReasons<T extends GlobalState>(
|
||||
global: T, restrictionReasons?: ApiRestrictionReason[],
|
||||
): ApiRestrictionReason[] {
|
||||
if (!restrictionReasons) return [];
|
||||
|
||||
const { ignoreRestrictionReasons } = global.appConfig || {};
|
||||
|
||||
return restrictionReasons.filter((reason) => {
|
||||
const isForCurrentPlatform = reason.platform === 'all' || reason.platform === WEB_APP_PLATFORM;
|
||||
if (!isForCurrentPlatform) return false;
|
||||
|
||||
const shouldIgnore = ignoreRestrictionReasons?.includes(reason.reason);
|
||||
return !shouldIgnore;
|
||||
});
|
||||
}
|
||||
|
||||
export function selectIsMediaNsfw<T extends GlobalState>(global: T, message: ApiMessage) {
|
||||
const { isSensitiveEnabled } = selectSettingsKeys(global);
|
||||
const chat = selectChat(global, message.chatId);
|
||||
if (isSensitiveEnabled) return false;
|
||||
|
||||
const chatActiveRestrictions = selectActiveRestrictionReasons(global, chat?.restrictionReasons);
|
||||
const messageActiveRestrictions = selectActiveRestrictionReasons(global, message.restrictionReasons);
|
||||
|
||||
return chatActiveRestrictions.some((reason) => reason.reason === NSFW_RESTRICTION_REASON)
|
||||
|| messageActiveRestrictions.some((reason) => reason.reason === NSFW_RESTRICTION_REASON);
|
||||
}
|
||||
|
||||
@ -656,6 +656,7 @@ export interface ActionPayloads {
|
||||
startAttach?: string;
|
||||
attach?: string;
|
||||
startApp?: string;
|
||||
shouldStartMainApp?: boolean;
|
||||
mode?: string;
|
||||
choose?: ApiChatType[];
|
||||
text?: string;
|
||||
@ -1081,6 +1082,8 @@ export interface ActionPayloads {
|
||||
days: number;
|
||||
} & WithTabId | undefined;
|
||||
closeDeleteAccountModal: WithTabId | undefined;
|
||||
openAgeVerificationModal: WithTabId | undefined;
|
||||
closeAgeVerificationModal: WithTabId | undefined;
|
||||
setAccountTTL: {
|
||||
days: number;
|
||||
} & WithTabId | undefined;
|
||||
|
||||
@ -754,6 +754,8 @@ export type TabState = {
|
||||
selfDestructAccountDays: number;
|
||||
};
|
||||
|
||||
isAgeVerificationModalOpen?: boolean;
|
||||
|
||||
paidReactionModal?: {
|
||||
chatId: string;
|
||||
messageId: number;
|
||||
|
||||
@ -4,7 +4,7 @@ import { getActions, getGlobal } from '../../global';
|
||||
import type { ApiChat, ApiUser } from '../../api/types';
|
||||
|
||||
import { isChatChannel, isUserBot } from '../../global/helpers';
|
||||
import { selectPeer, selectUserStatus } from '../../global/selectors';
|
||||
import { selectIsChatRestricted, selectPeer, selectUserStatus } from '../../global/selectors';
|
||||
import { isUserId } from '../../util/entities/ids';
|
||||
import { throttle } from '../../util/schedulers';
|
||||
|
||||
@ -54,7 +54,8 @@ export default function usePeerStoriesPolling(ids?: string[]) {
|
||||
return !user.isContact && !user.isSelf && !isUserBot(user) && !peer.isSupport && isStatusAvailable;
|
||||
} else {
|
||||
const chat = peer as ApiChat;
|
||||
return isChatChannel(chat) && !chat.isRestricted;
|
||||
const isRestricted = selectIsChatRestricted(global, chat.id);
|
||||
return isChatChannel(chat) && !isRestricted;
|
||||
}
|
||||
}).map((user) => user.id);
|
||||
}, [peers]);
|
||||
|
||||
@ -12,6 +12,6 @@ for (const tl of Object.values(Api)) {
|
||||
}
|
||||
}
|
||||
|
||||
export const LAYER = 207;
|
||||
export const LAYER = 210;
|
||||
|
||||
export { tlobjects };
|
||||
|
||||
137
src/lib/gramjs/tl/api.d.ts
vendored
137
src/lib/gramjs/tl/api.d.ts
vendored
@ -397,6 +397,8 @@ namespace Api {
|
||||
export type TypeTodoList = TodoList;
|
||||
export type TypeTodoCompletion = TodoCompletion;
|
||||
export type TypeSuggestedPost = SuggestedPost;
|
||||
export type TypeStarsRating = StarsRating;
|
||||
export type TypeStarGiftCollection = StarGiftCollection;
|
||||
export type TypeResPQ = ResPQ;
|
||||
export type TypeP_Q_inner_data = PQInnerData | PQInnerDataDc | PQInnerDataTemp | PQInnerDataTempDc;
|
||||
export type TypeServer_DH_Params = ServerDHParamsFail | ServerDHParamsOk;
|
||||
@ -612,6 +614,7 @@ namespace Api {
|
||||
export type TypeSavedStarGifts = payments.SavedStarGifts;
|
||||
export type TypeStarGiftWithdrawalUrl = payments.StarGiftWithdrawalUrl;
|
||||
export type TypeResaleStarGifts = payments.ResaleStarGifts;
|
||||
export type TypeStarGiftCollections = payments.StarGiftCollectionsNotModified | payments.StarGiftCollections;
|
||||
}
|
||||
|
||||
export namespace phone {
|
||||
@ -3918,6 +3921,7 @@ namespace Api {
|
||||
botVerification?: Api.TypeBotVerification;
|
||||
sendPaidMessagesStars?: long;
|
||||
disallowedGifts?: Api.TypeDisallowedGiftsSettings;
|
||||
starsRating?: Api.TypeStarsRating;
|
||||
}> {
|
||||
// flags: Api.Type;
|
||||
blocked?: true;
|
||||
@ -3969,7 +3973,8 @@ namespace Api {
|
||||
botVerification?: Api.TypeBotVerification;
|
||||
sendPaidMessagesStars?: long;
|
||||
disallowedGifts?: Api.TypeDisallowedGiftsSettings;
|
||||
CONSTRUCTOR_ID: 2582085701;
|
||||
starsRating?: Api.TypeStarsRating;
|
||||
CONSTRUCTOR_ID: 702447806;
|
||||
SUBCLASS_OF_ID: 524706233;
|
||||
className: 'UserFull';
|
||||
|
||||
@ -13347,6 +13352,7 @@ namespace Api {
|
||||
quoteText?: string;
|
||||
quoteEntities?: Api.TypeMessageEntity[];
|
||||
quoteOffset?: int;
|
||||
todoItemId?: int;
|
||||
} | void> {
|
||||
// flags: Api.Type;
|
||||
replyToScheduled?: true;
|
||||
@ -13360,7 +13366,8 @@ namespace Api {
|
||||
quoteText?: string;
|
||||
quoteEntities?: Api.TypeMessageEntity[];
|
||||
quoteOffset?: int;
|
||||
CONSTRUCTOR_ID: 2948336091;
|
||||
todoItemId?: int;
|
||||
CONSTRUCTOR_ID: 1763137035;
|
||||
SUBCLASS_OF_ID: 1531810151;
|
||||
className: 'MessageReplyHeader';
|
||||
|
||||
@ -15261,6 +15268,7 @@ namespace Api {
|
||||
quoteEntities?: Api.TypeMessageEntity[];
|
||||
quoteOffset?: int;
|
||||
monoforumPeerId?: Api.TypeInputPeer;
|
||||
todoItemId?: int;
|
||||
}> {
|
||||
// flags: Api.Type;
|
||||
replyToMsgId: int;
|
||||
@ -15270,7 +15278,8 @@ namespace Api {
|
||||
quoteEntities?: Api.TypeMessageEntity[];
|
||||
quoteOffset?: int;
|
||||
monoforumPeerId?: Api.TypeInputPeer;
|
||||
CONSTRUCTOR_ID: 2960144560;
|
||||
todoItemId?: int;
|
||||
CONSTRUCTOR_ID: 2258615824;
|
||||
SUBCLASS_OF_ID: 2356220701;
|
||||
className: 'InputReplyToMessage';
|
||||
|
||||
@ -16754,6 +16763,8 @@ namespace Api {
|
||||
limited?: true;
|
||||
soldOut?: true;
|
||||
birthday?: true;
|
||||
requirePremium?: true;
|
||||
limitedPerUser?: true;
|
||||
id: long;
|
||||
sticker: Api.TypeDocument;
|
||||
stars: long;
|
||||
@ -16767,11 +16778,15 @@ namespace Api {
|
||||
resellMinStars?: long;
|
||||
title?: string;
|
||||
releasedBy?: Api.TypePeer;
|
||||
perUserTotal?: int;
|
||||
perUserRemains?: int;
|
||||
}> {
|
||||
// flags: Api.Type;
|
||||
limited?: true;
|
||||
soldOut?: true;
|
||||
birthday?: true;
|
||||
requirePremium?: true;
|
||||
limitedPerUser?: true;
|
||||
id: long;
|
||||
sticker: Api.TypeDocument;
|
||||
stars: long;
|
||||
@ -16785,7 +16800,9 @@ namespace Api {
|
||||
resellMinStars?: long;
|
||||
title?: string;
|
||||
releasedBy?: Api.TypePeer;
|
||||
CONSTRUCTOR_ID: 2139438098;
|
||||
perUserTotal?: int;
|
||||
perUserRemains?: int;
|
||||
CONSTRUCTOR_ID: 12386139;
|
||||
SUBCLASS_OF_ID: 3273414923;
|
||||
className: 'StarGift';
|
||||
|
||||
@ -16793,6 +16810,7 @@ namespace Api {
|
||||
}
|
||||
export class StarGiftUnique extends VirtualClass<{
|
||||
// flags: Api.Type;
|
||||
requirePremium?: true;
|
||||
id: long;
|
||||
title: string;
|
||||
slug: string;
|
||||
@ -16808,6 +16826,7 @@ namespace Api {
|
||||
releasedBy?: Api.TypePeer;
|
||||
}> {
|
||||
// flags: Api.Type;
|
||||
requirePremium?: true;
|
||||
id: long;
|
||||
title: string;
|
||||
slug: string;
|
||||
@ -17079,6 +17098,7 @@ namespace Api {
|
||||
transferStars?: long;
|
||||
canTransferAt?: int;
|
||||
canResellAt?: int;
|
||||
collectionId?: int[];
|
||||
}> {
|
||||
// flags: Api.Type;
|
||||
nameHidden?: true;
|
||||
@ -17098,7 +17118,8 @@ namespace Api {
|
||||
transferStars?: long;
|
||||
canTransferAt?: int;
|
||||
canResellAt?: int;
|
||||
CONSTRUCTOR_ID: 3755607193;
|
||||
collectionId?: int[];
|
||||
CONSTRUCTOR_ID: 514213599;
|
||||
SUBCLASS_OF_ID: 2385198100;
|
||||
className: 'SavedStarGift';
|
||||
|
||||
@ -17378,6 +17399,44 @@ namespace Api {
|
||||
|
||||
static fromReader(reader: Reader): SuggestedPost;
|
||||
}
|
||||
export class StarsRating extends VirtualClass<{
|
||||
// flags: Api.Type;
|
||||
level: int;
|
||||
currentLevelStars: long;
|
||||
stars: long;
|
||||
nextLevelStars?: long;
|
||||
}> {
|
||||
// flags: Api.Type;
|
||||
level: int;
|
||||
currentLevelStars: long;
|
||||
stars: long;
|
||||
nextLevelStars?: long;
|
||||
CONSTRUCTOR_ID: 453922567;
|
||||
SUBCLASS_OF_ID: 1668506656;
|
||||
className: 'StarsRating';
|
||||
|
||||
static fromReader(reader: Reader): StarsRating;
|
||||
}
|
||||
export class StarGiftCollection extends VirtualClass<{
|
||||
// flags: Api.Type;
|
||||
collectionId: int;
|
||||
title: string;
|
||||
icon?: Api.TypeDocument;
|
||||
giftsCount: int;
|
||||
hash: long;
|
||||
}> {
|
||||
// flags: Api.Type;
|
||||
collectionId: int;
|
||||
title: string;
|
||||
icon?: Api.TypeDocument;
|
||||
giftsCount: int;
|
||||
hash: long;
|
||||
CONSTRUCTOR_ID: 2641040304;
|
||||
SUBCLASS_OF_ID: 1138805578;
|
||||
className: 'StarGiftCollection';
|
||||
|
||||
static fromReader(reader: Reader): StarGiftCollection;
|
||||
}
|
||||
export class ResPQ extends VirtualClass<{
|
||||
nonce: int128;
|
||||
serverNonce: int128;
|
||||
@ -21385,6 +21444,23 @@ namespace Api {
|
||||
|
||||
static fromReader(reader: Reader): ResaleStarGifts;
|
||||
}
|
||||
export class StarGiftCollectionsNotModified extends VirtualClass<void> {
|
||||
CONSTRUCTOR_ID: 2696564503;
|
||||
SUBCLASS_OF_ID: 4028047852;
|
||||
className: 'StarGiftCollectionsNotModified';
|
||||
|
||||
static fromReader(reader: Reader): StarGiftCollectionsNotModified;
|
||||
}
|
||||
export class StarGiftCollections extends VirtualClass<{
|
||||
collections: Api.TypeStarGiftCollection[];
|
||||
}> {
|
||||
collections: Api.TypeStarGiftCollection[];
|
||||
CONSTRUCTOR_ID: 2317955827;
|
||||
SUBCLASS_OF_ID: 4028047852;
|
||||
className: 'StarGiftCollections';
|
||||
|
||||
static fromReader(reader: Reader): StarGiftCollections;
|
||||
}
|
||||
}
|
||||
|
||||
export namespace phone {
|
||||
@ -27128,6 +27204,7 @@ namespace Api {
|
||||
excludeUnique?: true;
|
||||
sortByValue?: true;
|
||||
peer: Api.TypeInputPeer;
|
||||
collectionId?: int;
|
||||
offset: string;
|
||||
limit: int;
|
||||
}, payments.TypeSavedStarGifts> {
|
||||
@ -27139,6 +27216,7 @@ namespace Api {
|
||||
excludeUnique?: true;
|
||||
sortByValue?: true;
|
||||
peer: Api.TypeInputPeer;
|
||||
collectionId?: int;
|
||||
offset: string;
|
||||
limit: int;
|
||||
}
|
||||
@ -27201,6 +27279,53 @@ namespace Api {
|
||||
stargift: Api.TypeInputSavedStarGift;
|
||||
resellStars: long;
|
||||
}
|
||||
export class CreateStarGiftCollection extends Request<{
|
||||
peer: Api.TypeInputPeer;
|
||||
title: string;
|
||||
stargift: Api.TypeInputSavedStarGift[];
|
||||
}, Api.TypeStarGiftCollection> {
|
||||
peer: Api.TypeInputPeer;
|
||||
title: string;
|
||||
stargift: Api.TypeInputSavedStarGift[];
|
||||
}
|
||||
export class UpdateStarGiftCollection extends Request<{
|
||||
// flags: Api.Type;
|
||||
peer: Api.TypeInputPeer;
|
||||
collectionId: int;
|
||||
title?: string;
|
||||
deleteStargift?: Api.TypeInputSavedStarGift[];
|
||||
addStargift?: Api.TypeInputSavedStarGift[];
|
||||
order?: Api.TypeInputSavedStarGift[];
|
||||
}, Api.TypeStarGiftCollection> {
|
||||
// flags: Api.Type;
|
||||
peer: Api.TypeInputPeer;
|
||||
collectionId: int;
|
||||
title?: string;
|
||||
deleteStargift?: Api.TypeInputSavedStarGift[];
|
||||
addStargift?: Api.TypeInputSavedStarGift[];
|
||||
order?: Api.TypeInputSavedStarGift[];
|
||||
}
|
||||
export class ReorderStarGiftCollections extends Request<{
|
||||
peer: Api.TypeInputPeer;
|
||||
order: int[];
|
||||
}, Bool> {
|
||||
peer: Api.TypeInputPeer;
|
||||
order: int[];
|
||||
}
|
||||
export class DeleteStarGiftCollection extends Request<{
|
||||
peer: Api.TypeInputPeer;
|
||||
collectionId: int;
|
||||
}, Bool> {
|
||||
peer: Api.TypeInputPeer;
|
||||
collectionId: int;
|
||||
}
|
||||
export class GetStarGiftCollections extends Request<{
|
||||
peer: Api.TypeInputPeer;
|
||||
hash: long;
|
||||
}, payments.TypeStarGiftCollections> {
|
||||
peer: Api.TypeInputPeer;
|
||||
hash: long;
|
||||
}
|
||||
}
|
||||
|
||||
export namespace stickers {
|
||||
@ -28196,7 +28321,7 @@ namespace Api {
|
||||
| help.GetConfig | help.GetNearestDc | help.GetAppUpdate | help.GetInviteText | help.GetSupport | help.SetBotUpdatesStatus | help.GetCdnConfig | help.GetRecentMeUrls | help.GetTermsOfServiceUpdate | help.AcceptTermsOfService | help.GetDeepLinkInfo | help.GetAppConfig | help.SaveAppLog | help.GetPassportConfig | help.GetSupportName | help.GetUserInfo | help.EditUserInfo | help.GetPromoData | help.HidePromoData | help.DismissSuggestion | help.GetCountriesList | help.GetPremiumPromo | help.GetPeerColors | help.GetPeerProfileColors | help.GetTimezonesList
|
||||
| channels.ReadHistory | channels.DeleteMessages | channels.ReportSpam | channels.GetMessages | channels.GetParticipants | channels.GetParticipant | channels.GetChannels | channels.GetFullChannel | channels.CreateChannel | channels.EditAdmin | channels.EditTitle | channels.EditPhoto | channels.CheckUsername | channels.UpdateUsername | channels.JoinChannel | channels.LeaveChannel | channels.InviteToChannel | channels.DeleteChannel | channels.ExportMessageLink | channels.ToggleSignatures | channels.GetAdminedPublicChannels | channels.EditBanned | channels.GetAdminLog | channels.SetStickers | channels.ReadMessageContents | channels.DeleteHistory | channels.TogglePreHistoryHidden | channels.GetLeftChannels | channels.GetGroupsForDiscussion | channels.SetDiscussionGroup | channels.EditCreator | channels.EditLocation | channels.ToggleSlowMode | channels.GetInactiveChannels | channels.ConvertToGigagroup | channels.GetSendAs | channels.DeleteParticipantHistory | channels.ToggleJoinToSend | channels.ToggleJoinRequest | channels.ReorderUsernames | channels.ToggleUsername | channels.DeactivateAllUsernames | channels.ToggleForum | channels.CreateForumTopic | channels.GetForumTopics | channels.GetForumTopicsByID | channels.EditForumTopic | channels.UpdatePinnedForumTopic | channels.DeleteTopicHistory | channels.ReorderPinnedForumTopics | channels.ToggleAntiSpam | channels.ReportAntiSpamFalsePositive | channels.ToggleParticipantsHidden | channels.UpdateColor | channels.ToggleViewForumAsMessages | channels.GetChannelRecommendations | channels.UpdateEmojiStatus | channels.SetBoostsToUnblockRestrictions | channels.SetEmojiStickers | channels.RestrictSponsoredMessages | channels.SearchPosts | channels.UpdatePaidMessagesPrice | channels.ToggleAutotranslation | channels.GetMessageAuthor
|
||||
| bots.SendCustomRequest | bots.AnswerWebhookJSONQuery | bots.SetBotCommands | bots.ResetBotCommands | bots.GetBotCommands | bots.SetBotMenuButton | bots.GetBotMenuButton | bots.SetBotBroadcastDefaultAdminRights | bots.SetBotGroupDefaultAdminRights | bots.SetBotInfo | bots.GetBotInfo | bots.ReorderUsernames | bots.ToggleUsername | bots.CanSendMessage | bots.AllowSendMessage | bots.InvokeWebViewCustomMethod | bots.GetPopularAppBots | bots.AddPreviewMedia | bots.EditPreviewMedia | bots.DeletePreviewMedia | bots.ReorderPreviewMedias | bots.GetPreviewInfo | bots.GetPreviewMedias | bots.UpdateUserEmojiStatus | bots.ToggleUserEmojiStatusPermission | bots.CheckDownloadFileParams | bots.GetAdminedBots | bots.UpdateStarRefProgram | bots.SetCustomVerification | bots.GetBotRecommendations
|
||||
| payments.GetPaymentForm | payments.GetPaymentReceipt | payments.ValidateRequestedInfo | payments.SendPaymentForm | payments.GetSavedInfo | payments.ClearSavedInfo | payments.GetBankCardData | payments.ExportInvoice | payments.AssignAppStoreTransaction | payments.AssignPlayMarketTransaction | payments.GetPremiumGiftCodeOptions | payments.CheckGiftCode | payments.ApplyGiftCode | payments.GetGiveawayInfo | payments.LaunchPrepaidGiveaway | payments.GetStarsTopupOptions | payments.GetStarsStatus | payments.GetStarsTransactions | payments.SendStarsForm | payments.RefundStarsCharge | payments.GetStarsRevenueStats | payments.GetStarsRevenueWithdrawalUrl | payments.GetStarsRevenueAdsAccountUrl | payments.GetStarsTransactionsByID | payments.GetStarsGiftOptions | payments.GetStarsSubscriptions | payments.ChangeStarsSubscription | payments.FulfillStarsSubscription | payments.GetStarsGiveawayOptions | payments.GetStarGifts | payments.SaveStarGift | payments.ConvertStarGift | payments.BotCancelStarsSubscription | payments.GetConnectedStarRefBots | payments.GetConnectedStarRefBot | payments.GetSuggestedStarRefBots | payments.ConnectStarRefBot | payments.EditConnectedStarRefBot | payments.GetStarGiftUpgradePreview | payments.UpgradeStarGift | payments.TransferStarGift | payments.GetUniqueStarGift | payments.GetSavedStarGifts | payments.GetSavedStarGift | payments.GetStarGiftWithdrawalUrl | payments.ToggleChatStarGiftNotifications | payments.ToggleStarGiftsPinnedToTop | payments.CanPurchaseStore | payments.GetResaleStarGifts | payments.UpdateStarGiftPrice
|
||||
| payments.GetPaymentForm | payments.GetPaymentReceipt | payments.ValidateRequestedInfo | payments.SendPaymentForm | payments.GetSavedInfo | payments.ClearSavedInfo | payments.GetBankCardData | payments.ExportInvoice | payments.AssignAppStoreTransaction | payments.AssignPlayMarketTransaction | payments.GetPremiumGiftCodeOptions | payments.CheckGiftCode | payments.ApplyGiftCode | payments.GetGiveawayInfo | payments.LaunchPrepaidGiveaway | payments.GetStarsTopupOptions | payments.GetStarsStatus | payments.GetStarsTransactions | payments.SendStarsForm | payments.RefundStarsCharge | payments.GetStarsRevenueStats | payments.GetStarsRevenueWithdrawalUrl | payments.GetStarsRevenueAdsAccountUrl | payments.GetStarsTransactionsByID | payments.GetStarsGiftOptions | payments.GetStarsSubscriptions | payments.ChangeStarsSubscription | payments.FulfillStarsSubscription | payments.GetStarsGiveawayOptions | payments.GetStarGifts | payments.SaveStarGift | payments.ConvertStarGift | payments.BotCancelStarsSubscription | payments.GetConnectedStarRefBots | payments.GetConnectedStarRefBot | payments.GetSuggestedStarRefBots | payments.ConnectStarRefBot | payments.EditConnectedStarRefBot | payments.GetStarGiftUpgradePreview | payments.UpgradeStarGift | payments.TransferStarGift | payments.GetUniqueStarGift | payments.GetSavedStarGifts | payments.GetSavedStarGift | payments.GetStarGiftWithdrawalUrl | payments.ToggleChatStarGiftNotifications | payments.ToggleStarGiftsPinnedToTop | payments.CanPurchaseStore | payments.GetResaleStarGifts | payments.UpdateStarGiftPrice | payments.CreateStarGiftCollection | payments.UpdateStarGiftCollection | payments.ReorderStarGiftCollections | payments.DeleteStarGiftCollection | payments.GetStarGiftCollections
|
||||
| stickers.CreateStickerSet | stickers.RemoveStickerFromSet | stickers.ChangeStickerPosition | stickers.AddStickerToSet | stickers.SetStickerSetThumb | stickers.CheckShortName | stickers.SuggestShortName | stickers.ChangeSticker | stickers.RenameStickerSet | stickers.DeleteStickerSet | stickers.ReplaceSticker
|
||||
| phone.GetCallConfig | phone.RequestCall | phone.AcceptCall | phone.ConfirmCall | phone.ReceivedCall | phone.DiscardCall | phone.SetCallRating | phone.SaveCallDebug | phone.SendSignalingData | phone.CreateGroupCall | phone.JoinGroupCall | phone.LeaveGroupCall | phone.InviteToGroupCall | phone.DiscardGroupCall | phone.ToggleGroupCallSettings | phone.GetGroupCall | phone.GetGroupParticipants | phone.CheckGroupCall | phone.ToggleGroupCallRecord | phone.EditGroupCallParticipant | phone.EditGroupCallTitle | phone.GetGroupCallJoinAs | phone.ExportGroupCallInvite | phone.ToggleGroupCallStartSubscription | phone.StartScheduledGroupCall | phone.SaveDefaultGroupCallJoinAs | phone.JoinGroupCallPresentation | phone.LeaveGroupCallPresentation | phone.GetGroupCallStreamChannels | phone.GetGroupCallStreamRtmpUrl | phone.SaveCallLog | phone.CreateConferenceCall | phone.DeleteConferenceCallParticipants | phone.SendConferenceCallBroadcast | phone.InviteConferenceCallParticipant | phone.DeclineConferenceCallInvite | phone.GetGroupCallChainBlocks
|
||||
| langpack.GetLangPack | langpack.GetStrings | langpack.GetDifference | langpack.GetLanguages | langpack.GetLanguage
|
||||
|
||||
@ -208,7 +208,7 @@ inputReportReasonGeoIrrelevant#dbd4feed = ReportReason;
|
||||
inputReportReasonFake#f5ddd6e7 = ReportReason;
|
||||
inputReportReasonIllegalDrugs#a8eb2be = ReportReason;
|
||||
inputReportReasonPersonalDetails#9ec7863d = ReportReason;
|
||||
userFull#99e78045 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 can_view_revenue:flags2.9?true bot_can_manage_emoji_status:flags2.10?true display_gifts_button:flags2.16?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 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 stargifts_count:flags2.8?int starref_program:flags2.11?StarRefProgram bot_verification:flags2.12?BotVerification send_paid_messages_stars:flags2.14?long disallowed_gifts:flags2.15?DisallowedGiftsSettings = UserFull;
|
||||
userFull#29de80be 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 can_view_revenue:flags2.9?true bot_can_manage_emoji_status:flags2.10?true display_gifts_button:flags2.16?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 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 stargifts_count:flags2.8?int starref_program:flags2.11?StarRefProgram bot_verification:flags2.12?BotVerification send_paid_messages_stars:flags2.14?long disallowed_gifts:flags2.15?DisallowedGiftsSettings stars_rating:flags2.17?StarsRating = UserFull;
|
||||
contact#145ade0b user_id:long mutual:Bool = Contact;
|
||||
importedContact#c13e3c50 user_id:long client_id:long = ImportedContact;
|
||||
contactStatus#16d9703b user_id:long status:UserStatus = ContactStatus;
|
||||
@ -1051,7 +1051,7 @@ help.countriesList#87d0759e countries:Vector<help.Country> hash:int = help.Count
|
||||
messageViews#455b853d flags:# views:flags.0?int forwards:flags.1?int replies:flags.2?MessageReplies = MessageViews;
|
||||
messages.messageViews#b6c4f543 views:Vector<MessageViews> chats:Vector<Chat> users:Vector<User> = messages.MessageViews;
|
||||
messages.discussionMessage#a6341782 flags:# messages:Vector<Message> max_id:flags.0?int read_inbox_max_id:flags.1?int read_outbox_max_id:flags.2?int unread_count:int chats:Vector<Chat> users:Vector<User> = messages.DiscussionMessage;
|
||||
messageReplyHeader#afbc09db flags:# reply_to_scheduled:flags.2?true forum_topic:flags.3?true quote:flags.9?true reply_to_msg_id:flags.4?int reply_to_peer_id:flags.0?Peer reply_from:flags.5?MessageFwdHeader reply_media:flags.8?MessageMedia reply_to_top_id:flags.1?int quote_text:flags.6?string quote_entities:flags.7?Vector<MessageEntity> quote_offset:flags.10?int = MessageReplyHeader;
|
||||
messageReplyHeader#6917560b flags:# reply_to_scheduled:flags.2?true forum_topic:flags.3?true quote:flags.9?true reply_to_msg_id:flags.4?int reply_to_peer_id:flags.0?Peer reply_from:flags.5?MessageFwdHeader reply_media:flags.8?MessageMedia reply_to_top_id:flags.1?int quote_text:flags.6?string quote_entities:flags.7?Vector<MessageEntity> quote_offset:flags.10?int todo_item_id:flags.11?int = MessageReplyHeader;
|
||||
messageReplyStoryHeader#e5af939 peer:Peer story_id:int = MessageReplyHeader;
|
||||
messageReplies#83d60fc2 flags:# comments:flags.0?true replies:int replies_pts:int recent_repliers:flags.1?Vector<Peer> channel_id:flags.0?long max_id:flags.2?int read_max_id:flags.3?int = MessageReplies;
|
||||
peerBlocked#e8fd8014 peer_id:Peer date:int = PeerBlocked;
|
||||
@ -1245,7 +1245,7 @@ storyViewPublicForward#9083670b flags:# blocked:flags.0?true blocked_my_stories_
|
||||
storyViewPublicRepost#bd74cf49 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true peer_id:Peer story:StoryItem = StoryView;
|
||||
stories.storyViewsList#59d78fc5 flags:# count:int views_count:int forwards_count:int reactions_count:int views:Vector<StoryView> chats:Vector<Chat> users:Vector<User> next_offset:flags.0?string = stories.StoryViewsList;
|
||||
stories.storyViews#de9eed1d views:Vector<StoryViews> users:Vector<User> = stories.StoryViews;
|
||||
inputReplyToMessage#b07038b0 flags:# reply_to_msg_id:int top_msg_id:flags.0?int reply_to_peer_id:flags.1?InputPeer quote_text:flags.2?string quote_entities:flags.3?Vector<MessageEntity> quote_offset:flags.4?int monoforum_peer_id:flags.5?InputPeer = InputReplyTo;
|
||||
inputReplyToMessage#869fbe10 flags:# reply_to_msg_id:int top_msg_id:flags.0?int reply_to_peer_id:flags.1?InputPeer quote_text:flags.2?string quote_entities:flags.3?Vector<MessageEntity> quote_offset:flags.4?int monoforum_peer_id:flags.5?InputPeer todo_item_id:flags.6?int = InputReplyTo;
|
||||
inputReplyToStory#5881323a peer:InputPeer story_id:int = InputReplyTo;
|
||||
inputReplyToMonoForum#69d66c45 monoforum_peer_id:InputPeer = InputReplyTo;
|
||||
exportedStoryLink#3fc9053b link:string = ExportedStoryLink;
|
||||
@ -1386,8 +1386,8 @@ starsSubscription#2e6eab1a flags:# canceled:flags.0?true can_refulfill:flags.1?t
|
||||
messageReactor#4ba3a95a flags:# top:flags.0?true my:flags.1?true anonymous:flags.2?true peer_id:flags.3?Peer count:int = MessageReactor;
|
||||
starsGiveawayOption#94ce852a flags:# extended:flags.0?true default:flags.1?true stars:long yearly_boosts:int store_product:flags.2?string currency:string amount:long winners:Vector<StarsGiveawayWinnersOption> = StarsGiveawayOption;
|
||||
starsGiveawayWinnersOption#54236209 flags:# default:flags.0?true users:int per_user_stars:long = StarsGiveawayWinnersOption;
|
||||
starGift#7f853c12 flags:# limited:flags.0?true sold_out:flags.1?true birthday:flags.2?true id:long sticker:Document stars:long availability_remains:flags.0?int availability_total:flags.0?int availability_resale:flags.4?long convert_stars:long first_sale_date:flags.1?int last_sale_date:flags.1?int upgrade_stars:flags.3?long resell_min_stars:flags.4?long title:flags.5?string released_by:flags.6?Peer = StarGift;
|
||||
starGiftUnique#f63778ae flags:# id:long title:string slug:string num:int owner_id:flags.0?Peer owner_name:flags.1?string owner_address:flags.2?string attributes:Vector<StarGiftAttribute> availability_issued:int availability_total:int gift_address:flags.3?string resell_stars:flags.4?long released_by:flags.5?Peer = StarGift;
|
||||
starGift#bcff5b flags:# limited:flags.0?true sold_out:flags.1?true birthday:flags.2?true require_premium:flags.7?true limited_per_user:flags.8?true id:long sticker:Document stars:long availability_remains:flags.0?int availability_total:flags.0?int availability_resale:flags.4?long convert_stars:long first_sale_date:flags.1?int last_sale_date:flags.1?int upgrade_stars:flags.3?long resell_min_stars:flags.4?long title:flags.5?string released_by:flags.6?Peer per_user_total:flags.8?int per_user_remains:flags.8?int = StarGift;
|
||||
starGiftUnique#f63778ae flags:# require_premium:flags.6?true id:long title:string slug:string num:int owner_id:flags.0?Peer owner_name:flags.1?string owner_address:flags.2?string attributes:Vector<StarGiftAttribute> availability_issued:int availability_total:int gift_address:flags.3?string resell_stars:flags.4?long released_by:flags.5?Peer = StarGift;
|
||||
payments.starGiftsNotModified#a388a368 = payments.StarGifts;
|
||||
payments.starGifts#2ed82995 hash:int gifts:Vector<StarGift> chats:Vector<Chat> users:Vector<User> = payments.StarGifts;
|
||||
messageReportOption#7903e3d9 text:string option:bytes = MessageReportOption;
|
||||
@ -1416,7 +1416,7 @@ users.users#62d706b8 users:Vector<User> = users.Users;
|
||||
users.usersSlice#315a4974 count:int users:Vector<User> = users.Users;
|
||||
payments.uniqueStarGift#caa2f60b gift:StarGift users:Vector<User> = payments.UniqueStarGift;
|
||||
messages.webPagePreview#b53e8b21 media:MessageMedia users:Vector<User> = messages.WebPagePreview;
|
||||
savedStarGift#dfda0499 flags:# name_hidden:flags.0?true unsaved:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true pinned_to_top:flags.12?true from_id:flags.1?Peer date:int gift:StarGift message:flags.2?TextWithEntities msg_id:flags.3?int saved_id:flags.11?long convert_stars:flags.4?long upgrade_stars:flags.6?long can_export_at:flags.7?int transfer_stars:flags.8?long can_transfer_at:flags.13?int can_resell_at:flags.14?int = SavedStarGift;
|
||||
savedStarGift#1ea646df flags:# name_hidden:flags.0?true unsaved:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true pinned_to_top:flags.12?true from_id:flags.1?Peer date:int gift:StarGift message:flags.2?TextWithEntities msg_id:flags.3?int saved_id:flags.11?long convert_stars:flags.4?long upgrade_stars:flags.6?long can_export_at:flags.7?int transfer_stars:flags.8?long can_transfer_at:flags.13?int can_resell_at:flags.14?int collection_id:flags.15?Vector<int> = SavedStarGift;
|
||||
payments.savedStarGifts#95f389b1 flags:# count:int chat_notifications_enabled:flags.1?Bool gifts:Vector<SavedStarGift> next_offset:flags.0?string chats:Vector<Chat> users:Vector<User> = payments.SavedStarGifts;
|
||||
inputSavedStarGiftUser#69279795 msg_id:int = InputSavedStarGift;
|
||||
inputSavedStarGiftChat#f101aa7f peer:InputPeer saved_id:long = InputSavedStarGift;
|
||||
@ -1445,6 +1445,10 @@ todoItem#cba9a52f id:int title:TextWithEntities = TodoItem;
|
||||
todoList#49b92a26 flags:# others_can_append:flags.0?true others_can_complete:flags.1?true title:TextWithEntities list:Vector<TodoItem> = TodoList;
|
||||
todoCompletion#4cc120b7 id:int completed_by:long date:int = TodoCompletion;
|
||||
suggestedPost#e8e37e5 flags:# accepted:flags.1?true rejected:flags.2?true price:flags.3?StarsAmount schedule_date:flags.0?int = SuggestedPost;
|
||||
starsRating#1b0e4f07 flags:# level:int current_level_stars:long stars:long next_level_stars:flags.0?long = StarsRating;
|
||||
starGiftCollection#9d6b13b0 flags:# collection_id:int title:string icon:flags.0?Document gifts_count:int hash:long = StarGiftCollection;
|
||||
payments.starGiftCollectionsNotModified#a0ba4f17 = payments.StarGiftCollections;
|
||||
payments.starGiftCollections#8a2932f3 collections:Vector<StarGiftCollection> = payments.StarGiftCollections;
|
||||
---functions---
|
||||
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
|
||||
initConnection#c1cd5ea9 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy params:flags.1?JSONValue query:!X = X;
|
||||
@ -1779,7 +1783,7 @@ payments.getStarGiftUpgradePreview#9c9abcb1 gift_id:long = payments.StarGiftUpgr
|
||||
payments.upgradeStarGift#aed6e4f5 flags:# keep_original_details:flags.0?true stargift:InputSavedStarGift = Updates;
|
||||
payments.transferStarGift#7f18176a stargift:InputSavedStarGift to_id:InputPeer = Updates;
|
||||
payments.getUniqueStarGift#a1974d72 slug:string = payments.UniqueStarGift;
|
||||
payments.getSavedStarGifts#23830de9 flags:# exclude_unsaved:flags.0?true exclude_saved:flags.1?true exclude_unlimited:flags.2?true exclude_limited:flags.3?true exclude_unique:flags.4?true sort_by_value:flags.5?true peer:InputPeer offset:string limit:int = payments.SavedStarGifts;
|
||||
payments.getSavedStarGifts#a319e569 flags:# exclude_unsaved:flags.0?true exclude_saved:flags.1?true exclude_unlimited:flags.2?true exclude_limited:flags.3?true exclude_unique:flags.4?true sort_by_value:flags.5?true peer:InputPeer collection_id:flags.6?int offset:string limit:int = payments.SavedStarGifts;
|
||||
payments.getStarGiftWithdrawalUrl#d06e93a8 stargift:InputSavedStarGift password:InputCheckPasswordSRP = payments.StarGiftWithdrawalUrl;
|
||||
payments.toggleStarGiftsPinnedToTop#1513e7b0 peer:InputPeer stargift:Vector<InputSavedStarGift> = Bool;
|
||||
payments.getResaleStarGifts#7a5fa236 flags:# sort_by_price:flags.1?true sort_by_num:flags.2?true attributes_hash:flags.0?long gift_id:long attributes:flags.3?Vector<StarGiftAttributeId> offset:string limit:int = payments.ResaleStarGifts;
|
||||
|
||||
@ -248,7 +248,7 @@ inputReportReasonFake#f5ddd6e7 = ReportReason;
|
||||
inputReportReasonIllegalDrugs#a8eb2be = ReportReason;
|
||||
inputReportReasonPersonalDetails#9ec7863d = ReportReason;
|
||||
|
||||
userFull#99e78045 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 can_view_revenue:flags2.9?true bot_can_manage_emoji_status:flags2.10?true display_gifts_button:flags2.16?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 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 stargifts_count:flags2.8?int starref_program:flags2.11?StarRefProgram bot_verification:flags2.12?BotVerification send_paid_messages_stars:flags2.14?long disallowed_gifts:flags2.15?DisallowedGiftsSettings = UserFull;
|
||||
userFull#29de80be 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 can_view_revenue:flags2.9?true bot_can_manage_emoji_status:flags2.10?true display_gifts_button:flags2.16?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 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 stargifts_count:flags2.8?int starref_program:flags2.11?StarRefProgram bot_verification:flags2.12?BotVerification send_paid_messages_stars:flags2.14?long disallowed_gifts:flags2.15?DisallowedGiftsSettings stars_rating:flags2.17?StarsRating = UserFull;
|
||||
|
||||
contact#145ade0b user_id:long mutual:Bool = Contact;
|
||||
|
||||
@ -1344,7 +1344,7 @@ messages.messageViews#b6c4f543 views:Vector<MessageViews> chats:Vector<Chat> use
|
||||
|
||||
messages.discussionMessage#a6341782 flags:# messages:Vector<Message> max_id:flags.0?int read_inbox_max_id:flags.1?int read_outbox_max_id:flags.2?int unread_count:int chats:Vector<Chat> users:Vector<User> = messages.DiscussionMessage;
|
||||
|
||||
messageReplyHeader#afbc09db flags:# reply_to_scheduled:flags.2?true forum_topic:flags.3?true quote:flags.9?true reply_to_msg_id:flags.4?int reply_to_peer_id:flags.0?Peer reply_from:flags.5?MessageFwdHeader reply_media:flags.8?MessageMedia reply_to_top_id:flags.1?int quote_text:flags.6?string quote_entities:flags.7?Vector<MessageEntity> quote_offset:flags.10?int = MessageReplyHeader;
|
||||
messageReplyHeader#6917560b flags:# reply_to_scheduled:flags.2?true forum_topic:flags.3?true quote:flags.9?true reply_to_msg_id:flags.4?int reply_to_peer_id:flags.0?Peer reply_from:flags.5?MessageFwdHeader reply_media:flags.8?MessageMedia reply_to_top_id:flags.1?int quote_text:flags.6?string quote_entities:flags.7?Vector<MessageEntity> quote_offset:flags.10?int todo_item_id:flags.11?int = MessageReplyHeader;
|
||||
messageReplyStoryHeader#e5af939 peer:Peer story_id:int = MessageReplyHeader;
|
||||
|
||||
messageReplies#83d60fc2 flags:# comments:flags.0?true replies:int replies_pts:int recent_repliers:flags.1?Vector<Peer> channel_id:flags.0?long max_id:flags.2?int read_max_id:flags.3?int = MessageReplies;
|
||||
@ -1649,7 +1649,7 @@ stories.storyViewsList#59d78fc5 flags:# count:int views_count:int forwards_count
|
||||
|
||||
stories.storyViews#de9eed1d views:Vector<StoryViews> users:Vector<User> = stories.StoryViews;
|
||||
|
||||
inputReplyToMessage#b07038b0 flags:# reply_to_msg_id:int top_msg_id:flags.0?int reply_to_peer_id:flags.1?InputPeer quote_text:flags.2?string quote_entities:flags.3?Vector<MessageEntity> quote_offset:flags.4?int monoforum_peer_id:flags.5?InputPeer = InputReplyTo;
|
||||
inputReplyToMessage#869fbe10 flags:# reply_to_msg_id:int top_msg_id:flags.0?int reply_to_peer_id:flags.1?InputPeer quote_text:flags.2?string quote_entities:flags.3?Vector<MessageEntity> quote_offset:flags.4?int monoforum_peer_id:flags.5?InputPeer todo_item_id:flags.6?int = InputReplyTo;
|
||||
inputReplyToStory#5881323a peer:InputPeer story_id:int = InputReplyTo;
|
||||
inputReplyToMonoForum#69d66c45 monoforum_peer_id:InputPeer = InputReplyTo;
|
||||
|
||||
@ -1890,8 +1890,8 @@ starsGiveawayOption#94ce852a flags:# extended:flags.0?true default:flags.1?true
|
||||
|
||||
starsGiveawayWinnersOption#54236209 flags:# default:flags.0?true users:int per_user_stars:long = StarsGiveawayWinnersOption;
|
||||
|
||||
starGift#7f853c12 flags:# limited:flags.0?true sold_out:flags.1?true birthday:flags.2?true id:long sticker:Document stars:long availability_remains:flags.0?int availability_total:flags.0?int availability_resale:flags.4?long convert_stars:long first_sale_date:flags.1?int last_sale_date:flags.1?int upgrade_stars:flags.3?long resell_min_stars:flags.4?long title:flags.5?string released_by:flags.6?Peer = StarGift;
|
||||
starGiftUnique#f63778ae flags:# id:long title:string slug:string num:int owner_id:flags.0?Peer owner_name:flags.1?string owner_address:flags.2?string attributes:Vector<StarGiftAttribute> availability_issued:int availability_total:int gift_address:flags.3?string resell_stars:flags.4?long released_by:flags.5?Peer = StarGift;
|
||||
starGift#bcff5b flags:# limited:flags.0?true sold_out:flags.1?true birthday:flags.2?true require_premium:flags.7?true limited_per_user:flags.8?true id:long sticker:Document stars:long availability_remains:flags.0?int availability_total:flags.0?int availability_resale:flags.4?long convert_stars:long first_sale_date:flags.1?int last_sale_date:flags.1?int upgrade_stars:flags.3?long resell_min_stars:flags.4?long title:flags.5?string released_by:flags.6?Peer per_user_total:flags.8?int per_user_remains:flags.8?int = StarGift;
|
||||
starGiftUnique#f63778ae flags:# require_premium:flags.6?true id:long title:string slug:string num:int owner_id:flags.0?Peer owner_name:flags.1?string owner_address:flags.2?string attributes:Vector<StarGiftAttribute> availability_issued:int availability_total:int gift_address:flags.3?string resell_stars:flags.4?long released_by:flags.5?Peer = StarGift;
|
||||
|
||||
payments.starGiftsNotModified#a388a368 = payments.StarGifts;
|
||||
payments.starGifts#2ed82995 hash:int gifts:Vector<StarGift> chats:Vector<Chat> users:Vector<User> = payments.StarGifts;
|
||||
@ -1940,7 +1940,7 @@ payments.uniqueStarGift#caa2f60b gift:StarGift users:Vector<User> = payments.Uni
|
||||
|
||||
messages.webPagePreview#b53e8b21 media:MessageMedia users:Vector<User> = messages.WebPagePreview;
|
||||
|
||||
savedStarGift#dfda0499 flags:# name_hidden:flags.0?true unsaved:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true pinned_to_top:flags.12?true from_id:flags.1?Peer date:int gift:StarGift message:flags.2?TextWithEntities msg_id:flags.3?int saved_id:flags.11?long convert_stars:flags.4?long upgrade_stars:flags.6?long can_export_at:flags.7?int transfer_stars:flags.8?long can_transfer_at:flags.13?int can_resell_at:flags.14?int = SavedStarGift;
|
||||
savedStarGift#1ea646df flags:# name_hidden:flags.0?true unsaved:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true pinned_to_top:flags.12?true from_id:flags.1?Peer date:int gift:StarGift message:flags.2?TextWithEntities msg_id:flags.3?int saved_id:flags.11?long convert_stars:flags.4?long upgrade_stars:flags.6?long can_export_at:flags.7?int transfer_stars:flags.8?long can_transfer_at:flags.13?int can_resell_at:flags.14?int collection_id:flags.15?Vector<int> = SavedStarGift;
|
||||
|
||||
payments.savedStarGifts#95f389b1 flags:# count:int chat_notifications_enabled:flags.1?Bool gifts:Vector<SavedStarGift> next_offset:flags.0?string chats:Vector<Chat> users:Vector<User> = payments.SavedStarGifts;
|
||||
|
||||
@ -1989,6 +1989,13 @@ todoCompletion#4cc120b7 id:int completed_by:long date:int = TodoCompletion;
|
||||
|
||||
suggestedPost#e8e37e5 flags:# accepted:flags.1?true rejected:flags.2?true price:flags.3?StarsAmount schedule_date:flags.0?int = SuggestedPost;
|
||||
|
||||
starsRating#1b0e4f07 flags:# level:int current_level_stars:long stars:long next_level_stars:flags.0?long = StarsRating;
|
||||
|
||||
starGiftCollection#9d6b13b0 flags:# collection_id:int title:string icon:flags.0?Document gifts_count:int hash:long = StarGiftCollection;
|
||||
|
||||
payments.starGiftCollectionsNotModified#a0ba4f17 = payments.StarGiftCollections;
|
||||
payments.starGiftCollections#8a2932f3 collections:Vector<StarGiftCollection> = payments.StarGiftCollections;
|
||||
|
||||
---functions---
|
||||
|
||||
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
|
||||
@ -2000,7 +2007,7 @@ invokeWithMessagesRange#365275f2 {X:Type} range:MessageRange query:!X = X;
|
||||
invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X;
|
||||
invokeWithBusinessConnection#dd289f8e {X:Type} connection_id:string query:!X = X;
|
||||
invokeWithGooglePlayIntegrity#1df92984 {X:Type} nonce:string token:string query:!X = X;
|
||||
invokeWithApnsSecret#dae54f8 {X:Type} nonce:string secret:string query:!X = X;
|
||||
invokeWithApnsSecret#0dae54f8 {X:Type} nonce:string secret:string query:!X = X;
|
||||
invokeWithReCaptcha#adbb0f94 {X:Type} token:string query:!X = X;
|
||||
|
||||
auth.sendCode#a677244f phone_number:string api_id:int api_hash:string settings:CodeSettings = auth.SentCode;
|
||||
@ -2590,7 +2597,7 @@ payments.getStarGiftUpgradePreview#9c9abcb1 gift_id:long = payments.StarGiftUpgr
|
||||
payments.upgradeStarGift#aed6e4f5 flags:# keep_original_details:flags.0?true stargift:InputSavedStarGift = Updates;
|
||||
payments.transferStarGift#7f18176a stargift:InputSavedStarGift to_id:InputPeer = Updates;
|
||||
payments.getUniqueStarGift#a1974d72 slug:string = payments.UniqueStarGift;
|
||||
payments.getSavedStarGifts#23830de9 flags:# exclude_unsaved:flags.0?true exclude_saved:flags.1?true exclude_unlimited:flags.2?true exclude_limited:flags.3?true exclude_unique:flags.4?true sort_by_value:flags.5?true peer:InputPeer offset:string limit:int = payments.SavedStarGifts;
|
||||
payments.getSavedStarGifts#a319e569 flags:# exclude_unsaved:flags.0?true exclude_saved:flags.1?true exclude_unlimited:flags.2?true exclude_limited:flags.3?true exclude_unique:flags.4?true sort_by_value:flags.5?true peer:InputPeer collection_id:flags.6?int offset:string limit:int = payments.SavedStarGifts;
|
||||
payments.getSavedStarGift#b455a106 stargift:Vector<InputSavedStarGift> = payments.SavedStarGifts;
|
||||
payments.getStarGiftWithdrawalUrl#d06e93a8 stargift:InputSavedStarGift password:InputCheckPasswordSRP = payments.StarGiftWithdrawalUrl;
|
||||
payments.toggleChatStarGiftNotifications#60eaefa1 flags:# enabled:flags.0?true peer:InputPeer = Bool;
|
||||
@ -2598,6 +2605,11 @@ payments.toggleStarGiftsPinnedToTop#1513e7b0 peer:InputPeer stargift:Vector<Inpu
|
||||
payments.canPurchaseStore#4fdc5ea7 purpose:InputStorePaymentPurpose = Bool;
|
||||
payments.getResaleStarGifts#7a5fa236 flags:# sort_by_price:flags.1?true sort_by_num:flags.2?true attributes_hash:flags.0?long gift_id:long attributes:flags.3?Vector<StarGiftAttributeId> offset:string limit:int = payments.ResaleStarGifts;
|
||||
payments.updateStarGiftPrice#3baea4e1 stargift:InputSavedStarGift resell_stars:long = Updates;
|
||||
payments.createStarGiftCollection#1f4a0e87 peer:InputPeer title:string stargift:Vector<InputSavedStarGift> = StarGiftCollection;
|
||||
payments.updateStarGiftCollection#4fddbee7 flags:# peer:InputPeer collection_id:int title:flags.0?string delete_stargift:flags.1?Vector<InputSavedStarGift> add_stargift:flags.2?Vector<InputSavedStarGift> order:flags.3?Vector<InputSavedStarGift> = StarGiftCollection;
|
||||
payments.reorderStarGiftCollections#c32af4cc peer:InputPeer order:Vector<int> = Bool;
|
||||
payments.deleteStarGiftCollection#ad5648e8 peer:InputPeer collection_id:int = Bool;
|
||||
payments.getStarGiftCollections#981b91dd peer:InputPeer hash:long = payments.StarGiftCollections;
|
||||
|
||||
stickers.createStickerSet#9021ab67 flags:# masks:flags.0?true emojis:flags.5?true text_color:flags.6?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector<InputStickerSetItem> software:flags.3?string = messages.StickerSet;
|
||||
stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet;
|
||||
@ -2718,4 +2730,4 @@ smsjobs.getStatus#10a698e8 = smsjobs.Status;
|
||||
smsjobs.getSmsJob#778d902f job_id:string = SmsJob;
|
||||
smsjobs.finishJob#4f1ebf24 flags:# job_id:string error:flags.0?string = Bool;
|
||||
|
||||
fragment.getCollectibleInfo#be1e85ba collectible:InputCollectible = fragment.CollectibleInfo;
|
||||
fragment.getCollectibleInfo#be1e85ba collectible:InputCollectible = fragment.CollectibleInfo;
|
||||
13
src/types/language.d.ts
vendored
13
src/types/language.d.ts
vendored
@ -1600,6 +1600,16 @@ export interface LangPair {
|
||||
'ButtonTopUpViaFragment': undefined;
|
||||
'TonModalHint': undefined;
|
||||
'TonGiftReceived': undefined;
|
||||
'MediaSpoilerSensitive': undefined;
|
||||
'TitleSensitiveModal': undefined;
|
||||
'TextSensitiveModal': undefined;
|
||||
'ButtonSensitiveAlways': undefined;
|
||||
'ButtonSensitiveView': undefined;
|
||||
'TitleAgeVerificationModal': undefined;
|
||||
'DescriptionAgeVerificationModal': undefined;
|
||||
'TitleAgeCheckFailed': undefined;
|
||||
'TitleAgeCheckSuccess': undefined;
|
||||
'ButtonAgeVerification': undefined;
|
||||
}
|
||||
|
||||
export interface LangPairWithVariables<V = LangVariable> {
|
||||
@ -3089,6 +3099,9 @@ export interface LangPairPluralWithVariables<V = LangVariable> {
|
||||
'MessageActionTodoTaskCount': {
|
||||
'count': V;
|
||||
};
|
||||
'TextAgeVerificationModal': {
|
||||
'count': V;
|
||||
};
|
||||
}
|
||||
export type RegularLangKey = keyof LangPair;
|
||||
export type RegularLangKeyWithVariables = keyof LangPairWithVariables;
|
||||
|
||||
@ -91,6 +91,7 @@ interface WebAppInboundEventMap {
|
||||
web_app_biometry_request_auth: { reason: string };
|
||||
web_app_biometry_update_token: { token: string };
|
||||
web_app_set_emoji_status: { custom_emoji_id: string; duration?: number };
|
||||
web_app_verify_age: { passed: boolean; age?: number };
|
||||
web_app_request_file_download: { url: string; file_name: string };
|
||||
web_app_send_prepared_message: { id: string };
|
||||
web_app_device_storage_save_key: {
|
||||
|
||||
@ -14,6 +14,7 @@ import {
|
||||
import { getIsChatMuted } from '../global/helpers/notifications';
|
||||
import {
|
||||
selectChatLastMessage,
|
||||
selectIsChatRestricted,
|
||||
selectNotifyDefaults,
|
||||
selectTabState,
|
||||
selectTopics,
|
||||
@ -527,10 +528,11 @@ function buildChatSummary<T extends GlobalState>(
|
||||
isRemovedFromSaved?: boolean,
|
||||
): ChatSummary {
|
||||
const {
|
||||
id, type, isRestricted, isNotJoined, migratedTo, folderId,
|
||||
id, type, isNotJoined, migratedTo, folderId,
|
||||
unreadCount: chatUnreadCount, unreadMentionsCount: chatUnreadMentionsCount, hasUnreadMark,
|
||||
isForum,
|
||||
} = chat;
|
||||
const isRestricted = selectIsChatRestricted(global, id);
|
||||
const topics = selectTopics(global, chat.id);
|
||||
|
||||
const { unreadCount, unreadMentionsCount } = isForum
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user