[Refactoring] Unify AppConfig and limits (#6139)

This commit is contained in:
zubiden 2025-08-29 08:57:45 +02:00 committed by Alexander Zinchuk
parent 66fa05a002
commit 428d7bb36c
70 changed files with 375 additions and 293 deletions

View File

@ -3,20 +3,11 @@ import { Api as GramJs } from '../../../lib/gramjs';
import type { ApiAppConfig, ApiLimitType, ApiPremiumSection } from '../../types'; import type { ApiAppConfig, ApiLimitType, ApiPremiumSection } from '../../types';
import { omitUndefined } from '../../../util/iteratees';
import { import {
DEFAULT_APP_CONFIG,
DEFAULT_LIMITS, DEFAULT_LIMITS,
MAX_UNIQUE_REACTIONS, } from '../../../limits';
SERVICE_NOTIFICATIONS_USER_ID,
STORY_EXPIRE_PERIOD,
STORY_VIEWERS_EXPIRE_PERIOD,
TODO_ITEM_LENGTH_LIMIT,
TODO_ITEMS_LIMIT,
TODO_TITLE_LENGTH_LIMIT,
TON_SUGGESTED_POST_AMOUNT_MAX,
TON_SUGGESTED_POST_AMOUNT_MIN,
TON_TOPUP_URL_DEFAULT,
TON_USD_RATE_DEFAULT,
} from '../../../config';
import localDb from '../localDb'; import localDb from '../localDb';
import { buildJson } from './misc'; import { buildJson } from './misc';
@ -36,7 +27,8 @@ type Limit =
| 'chatlist_invites_limit' | 'chatlist_invites_limit'
| 'chatlist_joined_limit' | 'chatlist_joined_limit'
| 'recommended_channels_limit' | 'recommended_channels_limit'
| 'saved_dialogs_pinned_limit'; | 'saved_dialogs_pinned_limit'
| 'reactions_user_max';
type LimitKey = `${Limit}_${LimitType}`; type LimitKey = `${Limit}_${LimitType}`;
type LimitsConfig = Record<LimitKey, number>; type LimitsConfig = Record<LimitKey, number>;
@ -57,6 +49,7 @@ export interface GramJsAppConfig extends LimitsConfig {
autologin_domains: string[]; autologin_domains: string[];
autologin_token: string; autologin_token: string;
url_auth_domains: string[]; url_auth_domains: string[];
whitelisted_domains: string[];
premium_purchase_blocked: boolean; premium_purchase_blocked: boolean;
giveaway_gifts_purchase_available: boolean; giveaway_gifts_purchase_available: boolean;
giveaway_add_peers_max: number; giveaway_add_peers_max: number;
@ -74,11 +67,9 @@ export interface GramJsAppConfig extends LimitsConfig {
// Forums // Forums
topics_pinned_limit: number; topics_pinned_limit: number;
// Stories // Stories
stories_all_hidden?: boolean;
story_expire_period: number;
story_viewers_expire_period: number; story_viewers_expire_period: number;
stories_changelog_user_id?: number; stories_changelog_user_id: number;
stories_pinned_to_top_count_max?: number; stories_pinned_to_top_count_max: number;
// Boosts // Boosts
group_transcribe_level_min?: number; group_transcribe_level_min?: number;
new_noncontact_peers_require_premium_without_ownpremium?: boolean; new_noncontact_peers_require_premium_without_ownpremium?: boolean;
@ -157,14 +148,15 @@ function getLimit(appConfig: GramJsAppConfig, key: Limit, fallbackKey: ApiLimitT
export function buildAppConfig(json: GramJs.TypeJSONValue, hash: number): ApiAppConfig { export function buildAppConfig(json: GramJs.TypeJSONValue, hash: number): ApiAppConfig {
const appConfig = buildJson(json) as GramJsAppConfig; const appConfig = buildJson(json) as GramJsAppConfig;
return { const config: Partial<ApiAppConfig> = {
emojiSounds: buildEmojiSounds(appConfig), emojiSounds: buildEmojiSounds(appConfig),
seenByMaxChatMembers: appConfig.chat_read_mark_size_threshold, seenByMaxChatMembers: appConfig.chat_read_mark_size_threshold,
seenByExpiresAt: appConfig.chat_read_mark_expire_period, seenByExpiresAt: appConfig.chat_read_mark_expire_period,
readDateExpiresAt: appConfig.pm_read_date_expire_period, readDateExpiresAt: appConfig.pm_read_date_expire_period,
autologinDomains: appConfig.autologin_domains || [], autologinDomains: appConfig.autologin_domains || [],
urlAuthDomains: appConfig.url_auth_domains || [], urlAuthDomains: appConfig.url_auth_domains || [],
maxUniqueReactions: appConfig.reactions_uniq_max ?? MAX_UNIQUE_REACTIONS, whitelistedDomains: appConfig.whitelisted_domains || [],
maxUniqueReactions: appConfig.reactions_uniq_max,
premiumBotUsername: appConfig.premium_bot_username, premiumBotUsername: appConfig.premium_bot_username,
premiumInvoiceSlug: appConfig.premium_invoice_slug, premiumInvoiceSlug: appConfig.premium_invoice_slug,
premiumPromoOrder: appConfig.premium_promo_order as ApiPremiumSection[], premiumPromoOrder: appConfig.premium_promo_order as ApiPremiumSection[],
@ -172,8 +164,6 @@ export function buildAppConfig(json: GramJs.TypeJSONValue, hash: number): ApiApp
isGiveawayGiftsPurchaseAvailable: appConfig.giveaway_gifts_purchase_available, isGiveawayGiftsPurchaseAvailable: appConfig.giveaway_gifts_purchase_available,
defaultEmojiStatusesStickerSetId: appConfig.default_emoji_statuses_stickerset_id, defaultEmojiStatusesStickerSetId: appConfig.default_emoji_statuses_stickerset_id,
topicsPinnedLimit: appConfig.topics_pinned_limit, topicsPinnedLimit: appConfig.topics_pinned_limit,
maxUserReactionsDefault: appConfig.reactions_user_max_default,
maxUserReactionsPremium: appConfig.reactions_user_max_premium,
hiddenMembersMinCount: appConfig.hidden_members_group_size_min, hiddenMembersMinCount: appConfig.hidden_members_group_size_min,
giveawayAddPeersMax: appConfig.giveaway_add_peers_max, giveawayAddPeersMax: appConfig.giveaway_add_peers_max,
giveawayBoostsPerPremium: appConfig.giveaway_boosts_per_premium, giveawayBoostsPerPremium: appConfig.giveaway_boosts_per_premium,
@ -195,13 +185,12 @@ export function buildAppConfig(json: GramJs.TypeJSONValue, hash: number): ApiApp
chatlistJoined: getLimit(appConfig, 'chatlist_joined_limit', 'chatlistJoined'), chatlistJoined: getLimit(appConfig, 'chatlist_joined_limit', 'chatlistJoined'),
recommendedChannels: getLimit(appConfig, 'recommended_channels_limit', 'recommendedChannels'), recommendedChannels: getLimit(appConfig, 'recommended_channels_limit', 'recommendedChannels'),
savedDialogsPinned: getLimit(appConfig, 'saved_dialogs_pinned_limit', 'savedDialogsPinned'), savedDialogsPinned: getLimit(appConfig, 'saved_dialogs_pinned_limit', 'savedDialogsPinned'),
maxReactions: getLimit(appConfig, 'reactions_user_max', 'maxReactions'),
moreAccounts: DEFAULT_LIMITS.moreAccounts, moreAccounts: DEFAULT_LIMITS.moreAccounts,
}, },
hash, hash,
areStoriesHidden: appConfig.stories_all_hidden, storyViewersExpirePeriod: appConfig.story_viewers_expire_period,
storyExpirePeriod: appConfig.story_expire_period ?? STORY_EXPIRE_PERIOD, storyChangelogUserId: appConfig.stories_changelog_user_id?.toString(),
storyViewersExpirePeriod: appConfig.story_viewers_expire_period ?? STORY_VIEWERS_EXPIRE_PERIOD,
storyChangelogUserId: appConfig.stories_changelog_user_id?.toString() ?? SERVICE_NOTIFICATIONS_USER_ID,
maxPinnedStoriesCount: appConfig.stories_pinned_to_top_count_max, maxPinnedStoriesCount: appConfig.stories_pinned_to_top_count_max,
groupTranscribeLevelMin: appConfig.group_transcribe_level_min, groupTranscribeLevelMin: appConfig.group_transcribe_level_min,
canLimitNewMessagesWithoutPremium: appConfig.new_noncontact_peers_require_premium_without_ownpremium, canLimitNewMessagesWithoutPremium: appConfig.new_noncontact_peers_require_premium_without_ownpremium,
@ -238,18 +227,23 @@ export function buildAppConfig(json: GramJs.TypeJSONValue, hash: number): ApiApp
starsSuggestedPostFutureMax: appConfig.stars_suggested_post_future_max, starsSuggestedPostFutureMax: appConfig.stars_suggested_post_future_max,
starsSuggestedPostFutureMin: appConfig.stars_suggested_post_future_min, starsSuggestedPostFutureMin: appConfig.stars_suggested_post_future_min,
tonSuggestedPostCommissionPermille: appConfig.ton_suggested_post_commission_permille, tonSuggestedPostCommissionPermille: appConfig.ton_suggested_post_commission_permille,
tonSuggestedPostAmountMax: appConfig.ton_suggested_post_amount_max ?? TON_SUGGESTED_POST_AMOUNT_MAX, tonSuggestedPostAmountMax: appConfig.ton_suggested_post_amount_max,
tonSuggestedPostAmountMin: appConfig.ton_suggested_post_amount_min ?? TON_SUGGESTED_POST_AMOUNT_MIN, tonSuggestedPostAmountMin: appConfig.ton_suggested_post_amount_min,
tonUsdRate: appConfig.ton_usd_rate ?? TON_USD_RATE_DEFAULT, tonUsdRate: appConfig.ton_usd_rate,
tonTopupUrl: appConfig.ton_topup_url ?? TON_TOPUP_URL_DEFAULT, tonTopupUrl: appConfig.ton_topup_url,
pollMaxAnswers: appConfig.poll_answers_max, pollMaxAnswers: appConfig.poll_answers_max,
todoItemsMax: appConfig.todo_items_max ?? TODO_ITEMS_LIMIT, todoItemsMax: appConfig.todo_items_max,
todoTitleLengthMax: appConfig.todo_title_length_max ?? TODO_TITLE_LENGTH_LIMIT, todoTitleLengthMax: appConfig.todo_title_length_max,
todoItemLengthMax: appConfig.todo_item_length_max ?? TODO_ITEM_LENGTH_LIMIT, todoItemLengthMax: appConfig.todo_item_length_max,
ignoreRestrictionReasons: appConfig.ignore_restriction_reasons, ignoreRestrictionReasons: appConfig.ignore_restriction_reasons,
needAgeVideoVerification: appConfig.need_age_video_verification, needAgeVideoVerification: appConfig.need_age_video_verification,
verifyAgeBotUsername: appConfig.verify_age_bot_username, verifyAgeBotUsername: appConfig.verify_age_bot_username,
verifyAgeCountry: appConfig.verify_age_country, verifyAgeCountry: appConfig.verify_age_country,
verifyAgeMin: appConfig.verify_age_min, verifyAgeMin: appConfig.verify_age_min,
}; };
return {
...DEFAULT_APP_CONFIG,
...omitUndefined(config),
};
} }

View File

@ -6,7 +6,7 @@ import type {
ApiChat, ApiGroupCall, ApiPhoneCall, ApiUser, ApiChat, ApiGroupCall, ApiPhoneCall, ApiUser,
} from '../../types'; } from '../../types';
import { GROUP_CALL_PARTICIPANTS_LIMIT } from '../../../config'; import { GROUP_CALL_PARTICIPANTS_LIMIT } from '../../../limits';
import { import {
buildApiGroupCall, buildApiGroupCall,
buildApiGroupCallParticipant, buildCallProtocol, buildApiGroupCallParticipant, buildCallProtocol,

View File

@ -27,13 +27,13 @@ import {
ARCHIVED_FOLDER_ID, ARCHIVED_FOLDER_ID,
DEBUG, DEBUG,
GENERAL_TOPIC_ID, GENERAL_TOPIC_ID,
GLOBAL_SEARCH_CONTACTS_LIMIT,
MAX_INT_32, MAX_INT_32,
MEMBERS_LOAD_SLICE, MEMBERS_LOAD_SLICE,
SERVICE_NOTIFICATIONS_USER_ID, SERVICE_NOTIFICATIONS_USER_ID,
TOPICS_SLICE, TOPICS_SLICE,
} from '../../../config'; } from '../../../config';
import { buildCollectionByKey, omitUndefined } from '../../../util/iteratees'; import { buildCollectionByKey, omitUndefined } from '../../../util/iteratees';
import { GLOBAL_SEARCH_CONTACTS_LIMIT } from '../../../limits';
import { import {
buildApiChatBotCommands, buildApiChatBotCommands,
buildApiChatFolder, buildApiChatFolder,

View File

@ -38,13 +38,11 @@ import {
} from '../../types'; } from '../../types';
import { import {
API_GENERAL_ID_LIMIT,
DEBUG, DEBUG,
GIF_MIME_TYPE, GIF_MIME_TYPE,
MAX_INT_32, MAX_INT_32,
MENTION_UNREAD_SLICE, MENTION_UNREAD_SLICE,
MESSAGE_ID_REQUIRED_ERROR, MESSAGE_ID_REQUIRED_ERROR,
PINNED_MESSAGES_LIMIT,
REACTION_UNREAD_SLICE, REACTION_UNREAD_SLICE,
SUPPORTED_PHOTO_CONTENT_TYPES, SUPPORTED_PHOTO_CONTENT_TYPES,
SUPPORTED_VIDEO_CONTENT_TYPES, SUPPORTED_VIDEO_CONTENT_TYPES,
@ -54,6 +52,7 @@ import { compact, split } from '../../../util/iteratees';
import { getMessageKey } from '../../../util/keys/messageKey'; import { getMessageKey } from '../../../util/keys/messageKey';
import { getServerTime } from '../../../util/serverTime'; import { getServerTime } from '../../../util/serverTime';
import { interpolateArray } from '../../../util/waveform'; import { interpolateArray } from '../../../util/waveform';
import { API_GENERAL_ID_LIMIT, PINNED_MESSAGES_LIMIT } from '../../../limits';
import { import {
buildApiChatFromPreview, buildApiChatFromPreview,
buildApiSendAsPeerId, buildApiSendAsPeerId,

View File

@ -5,13 +5,13 @@ import type {
ApiChat, ApiReaction, ApiSticker, ApiChat, ApiReaction, ApiSticker,
} from '../../types'; } from '../../types';
import { split } from '../../../util/iteratees';
import { import {
API_GENERAL_ID_LIMIT, API_GENERAL_ID_LIMIT,
REACTION_LIST_LIMIT, REACTION_LIST_LIMIT,
RECENT_REACTIONS_LIMIT, RECENT_REACTIONS_LIMIT,
TOP_REACTIONS_LIMIT, TOP_REACTIONS_LIMIT,
} from '../../../config'; } from '../../../limits';
import { split } from '../../../util/iteratees';
import { import {
buildApiAvailableEffect, buildApiAvailableEffect,
buildApiAvailableReaction, buildApiAvailableReaction,

View File

@ -18,11 +18,11 @@ import type {
import { import {
ACCEPTABLE_USERNAME_ERRORS, ACCEPTABLE_USERNAME_ERRORS,
BLOCKED_LIST_LIMIT,
LANG_PACK, LANG_PACK,
MAX_INT_32, MAX_INT_32,
} from '../../../config'; } from '../../../config';
import { buildCollectionByKey } from '../../../util/iteratees'; import { buildCollectionByKey } from '../../../util/iteratees';
import { BLOCKED_LIST_LIMIT } from '../../../limits';
import { buildAppConfig } from '../apiBuilders/appConfig'; import { buildAppConfig } from '../apiBuilders/appConfig';
import { buildApiPhoto, buildPrivacyRules } from '../apiBuilders/common'; import { buildApiPhoto, buildPrivacyRules } from '../apiBuilders/common';
import { buildApiDisallowedGiftsSettings } from '../apiBuilders/gifts'; import { buildApiDisallowedGiftsSettings } from '../apiBuilders/gifts';

View File

@ -10,8 +10,9 @@ import type {
ApiTypeStory, ApiTypeStory,
} from '../../types'; } from '../../types';
import { MESSAGE_ID_REQUIRED_ERROR, STORY_LIST_LIMIT } from '../../../config'; import { MESSAGE_ID_REQUIRED_ERROR } from '../../../config';
import { buildCollectionByCallback } from '../../../util/iteratees'; import { buildCollectionByCallback } from '../../../util/iteratees';
import { STORY_LIST_LIMIT } from '../../../limits';
import { buildApiReportResult } from '../apiBuilders/messages'; import { buildApiReportResult } from '../apiBuilders/messages';
import { getApiChatIdFromMtpPeer } from '../apiBuilders/peers'; import { getApiChatIdFromMtpPeer } from '../apiBuilders/peers';
import { import {

View File

@ -205,6 +205,7 @@ export interface ApiAppConfig {
readDateExpiresAt: number; readDateExpiresAt: number;
autologinDomains: string[]; autologinDomains: string[];
urlAuthDomains: string[]; urlAuthDomains: string[];
whitelistedDomains: string[];
premiumInvoiceSlug: string; premiumInvoiceSlug: string;
premiumBotUsername: string; premiumBotUsername: string;
isPremiumPurchaseBlocked: boolean; isPremiumPurchaseBlocked: boolean;
@ -217,27 +218,24 @@ export interface ApiAppConfig {
defaultEmojiStatusesStickerSetId: string; defaultEmojiStatusesStickerSetId: string;
maxUniqueReactions: number; maxUniqueReactions: number;
topicsPinnedLimit: number; topicsPinnedLimit: number;
maxUserReactionsDefault: number;
maxUserReactionsPremium: number;
hiddenMembersMinCount: number; hiddenMembersMinCount: number;
limits: Record<ApiLimitType, readonly [number, number]>; limits: Record<ApiLimitType, readonly [number, number]>;
canDisplayAutoarchiveSetting: boolean; canDisplayAutoarchiveSetting: boolean;
areStoriesHidden?: boolean;
storyExpirePeriod: number;
storyViewersExpirePeriod: number; storyViewersExpirePeriod: number;
storyChangelogUserId: string; storyChangelogUserId: string;
maxPinnedStoriesCount?: number; maxPinnedStoriesCount: number;
groupTranscribeLevelMin?: number; groupTranscribeLevelMin: number;
canLimitNewMessagesWithoutPremium?: boolean; canLimitNewMessagesWithoutPremium: boolean;
starsPaidMessagesAvailable?: boolean; starsPaidMessagesAvailable?: boolean;
starsPaidMessageCommissionPermille?: number; starsPaidMessageCommissionPermille?: number;
starsPaidMessageAmountMax?: number; starsPaidMessageAmountMax?: number;
starsUsdWithdrawRateX1000?: number; starsUsdWithdrawRateX1000: number;
bandwidthPremiumNotifyPeriod?: number; bandwidthPremiumNotifyPeriod?: number;
bandwidthPremiumUploadSpeedup?: number; bandwidthPremiumUploadSpeedup?: number;
bandwidthPremiumDownloadSpeedup?: number; bandwidthPremiumDownloadSpeedup?: number;
channelRestrictAdsLevelMin?: number; channelRestrictAdsLevelMin?: number;
channelAutoTranslationLevelMin?: number; channelAutoTranslationLevelMin?: number;
channelLevelMax: number;
paidReactionMaxAmount?: number; paidReactionMaxAmount?: number;
isChannelRevenueWithdrawalEnabled?: boolean; isChannelRevenueWithdrawalEnabled?: boolean;
isStarsGiftEnabled?: boolean; isStarsGiftEnabled?: boolean;
@ -252,24 +250,24 @@ export interface ApiAppConfig {
starsStargiftResaleAmountMin?: number; starsStargiftResaleAmountMin?: number;
starsStargiftResaleAmountMax?: number; starsStargiftResaleAmountMax?: number;
starsStargiftResaleCommissionPermille?: number; starsStargiftResaleCommissionPermille?: number;
starsSuggestedPostAmountMax?: number; starsSuggestedPostAmountMax: number;
starsSuggestedPostAmountMin?: number; starsSuggestedPostAmountMin: number;
starsSuggestedPostCommissionPermille?: number; starsSuggestedPostCommissionPermille: number;
starsSuggestedPostAgeMin?: number; starsSuggestedPostAgeMin: number;
starsSuggestedPostFutureMax?: number; starsSuggestedPostFutureMax: number;
starsSuggestedPostFutureMin?: number; starsSuggestedPostFutureMin: number;
tonSuggestedPostCommissionPermille?: number; tonSuggestedPostCommissionPermille: number;
tonSuggestedPostAmountMax?: number; tonSuggestedPostAmountMax: number;
tonSuggestedPostAmountMin?: number; tonSuggestedPostAmountMin: number;
tonStargiftResaleAmountMax?: number; tonStargiftResaleAmountMax?: number;
tonStargiftResaleAmountMin?: number; tonStargiftResaleAmountMin?: number;
tonStargiftResaleCommissionPermille?: number; tonStargiftResaleCommissionPermille?: number;
tonUsdRate?: number; tonUsdRate?: number;
tonTopupUrl?: string; tonTopupUrl: string;
pollMaxAnswers?: number; pollMaxAnswers?: number;
todoItemsMax?: number; todoItemsMax: number;
todoTitleLengthMax?: number; todoTitleLengthMax: number;
todoItemLengthMax?: number; todoItemLengthMax: number;
ignoreRestrictionReasons?: string[]; ignoreRestrictionReasons?: string[];
needAgeVideoVerification?: boolean; needAgeVideoVerification?: boolean;
verifyAgeBotUsername?: string; verifyAgeBotUsername?: string;
@ -375,14 +373,16 @@ export type ApiLimitType =
| 'chatlistJoined' | 'chatlistJoined'
| 'recommendedChannels' | 'recommendedChannels'
| 'savedDialogsPinned' | 'savedDialogsPinned'
| 'maxReactions'
| 'moreAccounts'; | 'moreAccounts';
export type ApiLimitTypeWithModal = Exclude<ApiLimitType, ( export type ApiLimitTypeWithModal = Exclude<ApiLimitType, (
'captionLength' | 'aboutLength' | 'stickersFaved' | 'savedGifs' | 'recommendedChannels' | 'moreAccounts' 'captionLength' | 'aboutLength' | 'stickersFaved' | 'savedGifs' | 'recommendedChannels' | 'moreAccounts'
| 'maxReactions'
)>; )>;
export type ApiLimitTypeForPromo = Exclude<ApiLimitType, export type ApiLimitTypeForPromo = Exclude<ApiLimitType,
'uploadMaxFileparts' | 'chatlistInvites' | 'chatlistJoined' | 'savedDialogsPinned' 'uploadMaxFileparts' | 'chatlistInvites' | 'chatlistJoined' | 'savedDialogsPinned' | 'maxReactions'
>; >;
export type ApiPeerNotifySettings = { export type ApiPeerNotifySettings = {

View File

@ -47,7 +47,6 @@ import { MAIN_THREAD_ID } from '../../api/types';
import { import {
BASE_EMOJI_KEYWORD_LANG, BASE_EMOJI_KEYWORD_LANG,
DEFAULT_MAX_MESSAGE_LENGTH,
EDITABLE_INPUT_MODAL_ID, EDITABLE_INPUT_MODAL_ID,
HEART_REACTION, HEART_REACTION,
MAX_UPLOAD_FILEPART_SIZE, MAX_UPLOAD_FILEPART_SIZE,
@ -126,6 +125,7 @@ import parseHtmlAsFormattedText from '../../util/parseHtmlAsFormattedText';
import { insertHtmlInSelection } from '../../util/selection'; import { insertHtmlInSelection } from '../../util/selection';
import { getServerTime } from '../../util/serverTime'; import { getServerTime } from '../../util/serverTime';
import windowSize from '../../util/windowSize'; import windowSize from '../../util/windowSize';
import { DEFAULT_MAX_MESSAGE_LENGTH } from '../../limits';
import applyIosAutoCapitalizationFix from '../middle/composer/helpers/applyIosAutoCapitalizationFix'; import applyIosAutoCapitalizationFix from '../middle/composer/helpers/applyIosAutoCapitalizationFix';
import buildAttachment, { prepareAttachmentsToSend } from '../middle/composer/helpers/buildAttachment'; import buildAttachment, { prepareAttachmentsToSend } from '../middle/composer/helpers/buildAttachment';
import { buildCustomEmojiHtml } from '../middle/composer/helpers/customEmoji'; import { buildCustomEmojiHtml } from '../middle/composer/helpers/customEmoji';
@ -2622,7 +2622,7 @@ export default memo(withGlobal<OwnProps>(
isAccountFrozen, isAccountFrozen,
isAppConfigLoaded, isAppConfigLoaded,
insertingPeerIdMention, insertingPeerIdMention,
pollMaxAnswers: appConfig?.pollMaxAnswers, pollMaxAnswers: appConfig.pollMaxAnswers,
}; };
}, },
)(Composer)); )(Composer));

View File

@ -53,7 +53,7 @@ const SensitiveContentConfirmModal = ({
export default memo(withGlobal<OwnProps>((global): StateProps => { export default memo(withGlobal<OwnProps>((global): StateProps => {
const appConfig = global.appConfig; const appConfig = global.appConfig;
const verifyAgeMin = appConfig?.verifyAgeMin; const verifyAgeMin = appConfig.verifyAgeMin;
return { return {
verifyAgeMin: verifyAgeMin || VERIFY_AGE_MIN_DEFAULT, verifyAgeMin: verifyAgeMin || VERIFY_AGE_MIN_DEFAULT,

View File

@ -100,16 +100,16 @@ function PaidMessagePrice({
export default memo(withGlobal<OwnProps>( export default memo(withGlobal<OwnProps>(
(global): StateProps => { (global): StateProps => {
const starsUsdWithdrawRateX1000 = global.appConfig?.starsUsdWithdrawRateX1000; const starsUsdWithdrawRateX1000 = global.appConfig.starsUsdWithdrawRateX1000;
const starsUsdWithdrawRate = starsUsdWithdrawRateX1000 ? starsUsdWithdrawRateX1000 / 1000 : 1; const starsUsdWithdrawRate = starsUsdWithdrawRateX1000 ? starsUsdWithdrawRateX1000 / 1000 : 1;
const configStarsPaidMessageCommissionPermille = global.appConfig?.starsPaidMessageCommissionPermille; const configStarsPaidMessageCommissionPermille = global.appConfig.starsPaidMessageCommissionPermille;
const starsPaidMessageCommissionPermille = configStarsPaidMessageCommissionPermille const starsPaidMessageCommissionPermille = configStarsPaidMessageCommissionPermille
? configStarsPaidMessageCommissionPermille / 1000 : 100; ? configStarsPaidMessageCommissionPermille / 1000 : 100;
return { return {
starsPaidMessageCommissionPermille, starsPaidMessageCommissionPermille,
starsUsdWithdrawRate, starsUsdWithdrawRate,
starsPaidMessageAmountMax: global.appConfig?.starsPaidMessageAmountMax || DEFAULT_MAXIMUM_CHARGE_FOR_MESSAGES, starsPaidMessageAmountMax: global.appConfig.starsPaidMessageAmountMax || DEFAULT_MAXIMUM_CHARGE_FOR_MESSAGES,
}; };
}, },
)(PaidMessagePrice)); )(PaidMessagePrice));

View File

@ -252,10 +252,12 @@
overflow: hidden; overflow: hidden;
display: flex; display: flex;
&-summary { &-summary {
text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
flex: unset; flex: unset;
max-width: none; max-width: none;
text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
} }
.draft { .draft {
@ -280,6 +282,8 @@
} }
.media-preview--image { .media-preview--image {
flex-shrink: 0;
width: 1.25rem; width: 1.25rem;
height: 1.25rem; height: 1.25rem;
margin-inline-start: 0.125rem; margin-inline-start: 0.125rem;
@ -289,7 +293,6 @@
vertical-align: -0.25rem; vertical-align: -0.25rem;
object-fit: cover; object-fit: cover;
flex-shrink: 0;
body.is-ios & { body.is-ios & {
width: 1.125rem; width: 1.125rem;

View File

@ -241,8 +241,8 @@ export default memo(withGlobal<OwnProps>((global): StateProps => {
shouldChargeForMessages: Boolean(nonContactPeersPaidStars), shouldChargeForMessages: Boolean(nonContactPeersPaidStars),
nonContactPeersPaidStars: nonContactPeersPaidStars || DEFAULT_CHARGE_FOR_MESSAGES, nonContactPeersPaidStars: nonContactPeersPaidStars || DEFAULT_CHARGE_FOR_MESSAGES,
isCurrentUserPremium: selectIsCurrentUserPremium(global), isCurrentUserPremium: selectIsCurrentUserPremium(global),
canLimitNewMessagesWithoutPremium: global.appConfig?.canLimitNewMessagesWithoutPremium, canLimitNewMessagesWithoutPremium: global.appConfig.canLimitNewMessagesWithoutPremium,
canChargeForMessages: global.appConfig?.starsPaidMessagesAvailable, canChargeForMessages: global.appConfig.starsPaidMessagesAvailable,
noPaidReactionsForUsersCount, noPaidReactionsForUsersCount,
privacy, privacy,
}; };

View File

@ -490,12 +490,12 @@ export default memo(withGlobal<OwnProps>(
blockedCount: blocked.totalCount, blockedCount: blocked.totalCount,
webAuthCount: global.activeWebSessions.orderedHashes.length, webAuthCount: global.activeWebSessions.orderedHashes.length,
isSensitiveEnabled, isSensitiveEnabled,
canDisplayAutoarchiveSetting: Boolean(appConfig?.canDisplayAutoarchiveSetting), canDisplayAutoarchiveSetting: Boolean(appConfig.canDisplayAutoarchiveSetting),
shouldArchiveAndMuteNewNonContact, shouldArchiveAndMuteNewNonContact,
canChangeSensitive, canChangeSensitive,
shouldNewNonContactPeersRequirePremium, shouldNewNonContactPeersRequirePremium,
shouldChargeForMessages, shouldChargeForMessages,
needAgeVideoVerification: Boolean(appConfig?.needAgeVideoVerification), needAgeVideoVerification: Boolean(appConfig.needAgeVideoVerification),
privacy, privacy,
canDisplayChatInTitle, canDisplayChatInTitle,
canSetPasscode: selectCanSetPasscode(global), canSetPasscode: selectCanSetPasscode(global),

View File

@ -919,10 +919,10 @@ export default memo(withGlobal<OwnProps>((global): StateProps => {
gifts: giveawayModal?.gifts, gifts: giveawayModal?.gifts,
selectedMemberList: giveawayModal?.selectedMemberIds, selectedMemberList: giveawayModal?.selectedMemberIds,
selectedChannelList: giveawayModal?.selectedChannelIds, selectedChannelList: giveawayModal?.selectedChannelIds,
giveawayBoostPerPremiumLimit: global.appConfig?.giveawayBoostsPerPremium, giveawayBoostPerPremiumLimit: global.appConfig.giveawayBoostsPerPremium,
isStarsGiftEnabled: global.appConfig?.isStarsGiftEnabled, isStarsGiftEnabled: global.appConfig.isStarsGiftEnabled,
userSelectionLimit: global.appConfig?.giveawayAddPeersMax, userSelectionLimit: global.appConfig.giveawayAddPeersMax,
countrySelectionLimit: global.appConfig?.giveawayCountriesMax, countrySelectionLimit: global.appConfig.giveawayCountriesMax,
countryList: global.countryList.general, countryList: global.countryList.general,
prepaidGiveaway: giveawayModal?.prepaidGiveaway, prepaidGiveaway: giveawayModal?.prepaidGiveaway,
isChannel, isChannel,

View File

@ -530,9 +530,9 @@ export default memo(withGlobal<OwnProps>((global): StateProps => {
limitFolders: selectPremiumLimit(global, 'dialogFilters'), limitFolders: selectPremiumLimit(global, 'dialogFilters'),
limitPins: selectPremiumLimit(global, 'dialogFolderPinned'), limitPins: selectPremiumLimit(global, 'dialogFolderPinned'),
limitLinks: selectPremiumLimit(global, 'channelsPublic'), limitLinks: selectPremiumLimit(global, 'channelsPublic'),
limits: global.appConfig?.limits, limits: global.appConfig.limits,
premiumSlug: global.appConfig?.premiumInvoiceSlug, premiumSlug: global.appConfig.premiumInvoiceSlug,
premiumBotUsername: global.appConfig?.premiumBotUsername, premiumBotUsername: global.appConfig.premiumBotUsername,
premiumPromoOrder: global.appConfig?.premiumPromoOrder, premiumPromoOrder: global.appConfig.premiumPromoOrder,
}; };
})(PremiumMainModal)); })(PremiumMainModal));

View File

@ -219,7 +219,7 @@ const PremiumLimitReachedModal: FC<OwnProps & StateProps> = ({
export default memo(withGlobal<OwnProps>( export default memo(withGlobal<OwnProps>(
(global, { limit }): StateProps => { (global, { limit }): StateProps => {
const { limits } = global.appConfig || {}; const { limits } = global.appConfig;
const isPremium = selectIsCurrentUserPremium(global); const isPremium = selectIsCurrentUserPremium(global);
return { return {

View File

@ -9,11 +9,6 @@ import type { ApiNewMediaTodo } from '../../../api/types';
import type { ApiMessage } from '../../../api/types'; import type { ApiMessage } from '../../../api/types';
import type { TabState } from '../../../global/types/tabState'; import type { TabState } from '../../../global/types/tabState';
import {
TODO_ITEM_LENGTH_LIMIT,
TODO_ITEMS_LIMIT,
TODO_TITLE_LENGTH_LIMIT,
} from '../../../config';
import { requestMeasure, requestNextMutation } from '../../../lib/fasterdom/fasterdom'; import { requestMeasure, requestNextMutation } from '../../../lib/fasterdom/fasterdom';
import { selectChatMessage } from '../../../global/selectors'; import { selectChatMessage } from '../../../global/selectors';
import captureEscKeyListener from '../../../util/captureEscKeyListener'; import captureEscKeyListener from '../../../util/captureEscKeyListener';
@ -40,9 +35,9 @@ export type OwnProps = {
export type StateProps = { export type StateProps = {
editingMessage?: ApiMessage; editingMessage?: ApiMessage;
maxItemsCount?: number; maxItemsCount: number;
maxTitleLength?: number; maxTitleLength: number;
maxItemLength?: number; maxItemLength: number;
}; };
type Item = { type Item = {
@ -56,9 +51,9 @@ const MAX_OPTION_LENGTH = 100;
const ToDoListModal = ({ const ToDoListModal = ({
modal, modal,
maxItemsCount = TODO_ITEMS_LIMIT, maxItemsCount,
maxTitleLength = TODO_TITLE_LENGTH_LIMIT, maxTitleLength,
maxItemLength = TODO_ITEM_LENGTH_LIMIT, maxItemLength,
editingMessage, editingMessage,
onSend, onSend,
onClear, onClear,
@ -407,9 +402,9 @@ export default memo(withGlobal<OwnProps>(
const editingMessage = modal?.messageId ? selectChatMessage(global, modal.chatId, modal.messageId) : undefined; const editingMessage = modal?.messageId ? selectChatMessage(global, modal.chatId, modal.messageId) : undefined;
return { return {
editingMessage, editingMessage,
maxItemsCount: appConfig?.todoItemsMax, maxItemsCount: appConfig.todoItemsMax,
maxTitleLength: appConfig?.todoTitleLengthMax, maxTitleLength: appConfig.todoTitleLengthMax,
maxItemLength: appConfig?.todoItemLengthMax, maxItemLength: appConfig.todoItemLengthMax,
}; };
}, },
)(ToDoListModal)); )(ToDoListModal));

View File

@ -26,9 +26,6 @@ import type {
} from '../../../types'; } from '../../../types';
import { MAIN_THREAD_ID } from '../../../api/types'; import { MAIN_THREAD_ID } from '../../../api/types';
import {
TODO_ITEMS_LIMIT,
} from '../../../config';
import { PREVIEW_AVATAR_COUNT, SERVICE_NOTIFICATIONS_USER_ID } from '../../../config'; import { PREVIEW_AVATAR_COUNT, SERVICE_NOTIFICATIONS_USER_ID } from '../../../config';
import { import {
areReactionsEmpty, areReactionsEmpty,
@ -802,7 +799,7 @@ export default memo(withGlobal<OwnProps>(
const { const {
seenByExpiresAt, seenByMaxChatMembers, maxUniqueReactions, readDateExpiresAt, seenByExpiresAt, seenByMaxChatMembers, maxUniqueReactions, readDateExpiresAt,
} = global.appConfig || {}; } = global.appConfig;
const reactionsLimit = chatFullInfo?.reactionsLimit || maxUniqueReactions; const reactionsLimit = chatFullInfo?.reactionsLimit || maxUniqueReactions;
@ -899,7 +896,7 @@ export default memo(withGlobal<OwnProps>(
const canGift = selectCanGift(global, message.chatId); const canGift = selectCanGift(global, message.chatId);
const savedDialogId = selectSavedDialogIdFromMessage(global, message); const savedDialogId = selectSavedDialogIdFromMessage(global, message);
const todoItemsMax = global.appConfig?.todoItemsMax || TODO_ITEMS_LIMIT; const todoItemsMax = global.appConfig.todoItemsMax;
const canAppendTodoList = message.content.todo?.todo.othersCanAppend const canAppendTodoList = message.content.todo?.todo.othersCanAppend
&& message.content.todo?.todo.items?.length < todoItemsMax; && message.content.todo?.todo.items?.length < todoItemsMax;

View File

@ -46,7 +46,7 @@ import type { OnIntersectPinnedMessage } from '../hooks/usePinnedMessage';
import { MAIN_THREAD_ID } from '../../../api/types'; import { MAIN_THREAD_ID } from '../../../api/types';
import { AudioOrigin } from '../../../types'; import { AudioOrigin } from '../../../types';
import { EMOJI_STATUS_LOOP_LIMIT, MESSAGE_APPEARANCE_DELAY, STARS_SUGGESTED_POST_FUTURE_MIN } from '../../../config'; import { EMOJI_STATUS_LOOP_LIMIT, MESSAGE_APPEARANCE_DELAY } from '../../../config';
import { import {
areReactionsEmpty, areReactionsEmpty,
getIsDownloading, getIsDownloading,
@ -1995,7 +1995,7 @@ export default memo(withGlobal<OwnProps>(
? (chatFullInfo?.boostsApplied ?? message.senderBoosts) : message.senderBoosts; ? (chatFullInfo?.boostsApplied ?? message.senderBoosts) : message.senderBoosts;
const chatLevel = chat?.boostLevel || 0; const chatLevel = chat?.boostLevel || 0;
const transcribeMinLevel = global.appConfig?.groupTranscribeLevelMin; const transcribeMinLevel = global.appConfig.groupTranscribeLevelMin;
const canTranscribeVoice = isPremium || Boolean(transcribeMinLevel && chatLevel >= transcribeMinLevel); const canTranscribeVoice = isPremium || Boolean(transcribeMinLevel && chatLevel >= transcribeMinLevel);
const viaBusinessBot = viaBusinessBotId ? selectUser(global, viaBusinessBotId) : undefined; const viaBusinessBot = viaBusinessBotId ? selectUser(global, viaBusinessBotId) : undefined;
@ -2009,7 +2009,7 @@ export default memo(withGlobal<OwnProps>(
const lastPlaybackTimestamp = selectMessageLastPlaybackTimestamp(global, chatId, message.id); const lastPlaybackTimestamp = selectMessageLastPlaybackTimestamp(global, chatId, message.id);
const isAccountFrozen = selectIsCurrentUserFrozen(global); const isAccountFrozen = selectIsCurrentUserFrozen(global);
const minFutureTime = global.appConfig?.starsSuggestedPostFutureMin || STARS_SUGGESTED_POST_FUTURE_MIN; const minFutureTime = global.appConfig.starsSuggestedPostFutureMin;
const isMediaNsfw = selectIsMediaNsfw(global, message); const isMediaNsfw = selectIsMediaNsfw(global, message);
const isReplyMediaNsfw = replyMessage && selectIsMediaNsfw(global, replyMessage); const isReplyMediaNsfw = replyMessage && selectIsMediaNsfw(global, replyMessage);

View File

@ -310,7 +310,7 @@ const Photo = <T,>({
export default memo(withGlobal((global): StateProps => { export default memo(withGlobal((global): StateProps => {
const appConfig = global.appConfig; const appConfig = global.appConfig;
const needsAgeVerification = appConfig?.needAgeVideoVerification; const needsAgeVerification = appConfig.needAgeVideoVerification;
return { return {
needsAgeVerification, needsAgeVerification,

View File

@ -232,7 +232,7 @@ const Sticker: FC<OwnProps & StateProps> = ({
export default memo(withGlobal<OwnProps>((global): StateProps => { export default memo(withGlobal<OwnProps>((global): StateProps => {
const appConfig = global.appConfig; const appConfig = global.appConfig;
const needsAgeVerification = appConfig?.needAgeVideoVerification; const needsAgeVerification = appConfig.needAgeVideoVerification;
return { return {
needsAgeVerification, needsAgeVerification,

View File

@ -353,7 +353,7 @@ const Video = <T,>({
export default memo(withGlobal((global): StateProps => { export default memo(withGlobal((global): StateProps => {
const appConfig = global.appConfig; const appConfig = global.appConfig;
const needsAgeVerification = appConfig?.needAgeVideoVerification; const needsAgeVerification = appConfig.needAgeVideoVerification;
return { return {
needsAgeVerification, needsAgeVerification,

View File

@ -194,7 +194,7 @@ export default memo(withGlobal<OwnProps>(
canPlayAnimatedEmojis, canPlayAnimatedEmojis,
sender: giftSender || messageSender, sender: giftSender || messageSender,
recipient: giftRecipient || messageRecipient, recipient: giftRecipient || messageRecipient,
starGiftMaxConvertPeriod: global.appConfig?.starGiftMaxConvertPeriod, starGiftMaxConvertPeriod: global.appConfig.starGiftMaxConvertPeriod,
}; };
}, },
)(StarGiftAction)); )(StarGiftAction));

View File

@ -4,7 +4,7 @@ import { withGlobal } from '../../../../global';
import type { ApiMessage, ApiPeer } from '../../../../api/types'; import type { ApiMessage, ApiPeer } from '../../../../api/types';
import type { ApiMessageActionSuggestedPostApproval } from '../../../../api/types/messageActions'; import type { ApiMessageActionSuggestedPostApproval } from '../../../../api/types/messageActions';
import { STARS_SUGGESTED_POST_AGE_MIN, TON_CURRENCY_CODE } from '../../../../config'; import { TON_CURRENCY_CODE } from '../../../../config';
import { getPeerFullTitle } from '../../../../global/helpers/peers'; import { getPeerFullTitle } from '../../../../global/helpers/peers';
import { getMessageReplyInfo } from '../../../../global/helpers/replies'; import { getMessageReplyInfo } from '../../../../global/helpers/replies';
import { selectIsMonoforumAdmin, selectMonoforumChannel, import { selectIsMonoforumAdmin, selectMonoforumChannel,
@ -146,7 +146,7 @@ export default memo(withGlobal<OwnProps>(
} }
const { appConfig } = global; const { appConfig } = global;
const ageMinSeconds = appConfig?.starsSuggestedPostAgeMin || STARS_SUGGESTED_POST_AGE_MIN; const ageMinSeconds = appConfig.starsSuggestedPostAgeMin;
const isAdmin = chat ? Boolean(selectIsMonoforumAdmin(global, message.chatId)) : false; const isAdmin = chat ? Boolean(selectIsMonoforumAdmin(global, message.chatId)) : false;
return { return {

View File

@ -304,7 +304,7 @@ export default memo(withGlobal<OwnProps>((global): StateProps => {
const message = chatId && messageId ? selectChatMessage(global, chatId, messageId) : undefined; const message = chatId && messageId ? selectChatMessage(global, chatId, messageId) : undefined;
const isPrivateChat = isUserId(chatId || storyPeerId || ''); const isPrivateChat = isUserId(chatId || storyPeerId || '');
const areSomeReactionsAllowed = chatFullInfo?.enabledReactions?.type === 'some'; const areSomeReactionsAllowed = chatFullInfo?.enabledReactions?.type === 'some';
const { maxUniqueReactions } = global.appConfig || {}; const { maxUniqueReactions } = global.appConfig;
const areAllReactionsAllowed = chatFullInfo?.enabledReactions?.type === 'all' const areAllReactionsAllowed = chatFullInfo?.enabledReactions?.type === 'all'
&& chatFullInfo?.enabledReactions?.areCustomAllowed; && chatFullInfo?.enabledReactions?.areCustomAllowed;

View File

@ -153,7 +153,7 @@ export default memo(withGlobal<OwnProps>(
(global, { chatId }): StateProps => { (global, { chatId }): StateProps => {
const { availableReactions, topReactions } = global.reactions; const { availableReactions, topReactions } = global.reactions;
const { maxUniqueReactions } = global.appConfig || {}; const { maxUniqueReactions } = global.appConfig;
const { enabledReactions, isPaidReactionAvailable } = selectChatFullInfo(global, chatId) || {}; const { enabledReactions, isPaidReactionAvailable } = selectChatFullInfo(global, chatId) || {};
return { return {

View File

@ -178,7 +178,7 @@ const AboutAdsModal = ({ modal, minLevelToRestrictAds }: OwnProps & StateProps)
export default memo(withGlobal<OwnProps>( export default memo(withGlobal<OwnProps>(
(global): StateProps => { (global): StateProps => {
const minLevelToRestrictAds = global.appConfig?.channelRestrictAdsLevelMin; const minLevelToRestrictAds = global.appConfig.channelRestrictAdsLevelMin;
return { return {
minLevelToRestrictAds, minLevelToRestrictAds,

View File

@ -86,8 +86,8 @@ const AgeVerificationModal: FC<OwnProps & StateProps> = ({
export default memo(withGlobal((global): StateProps => { export default memo(withGlobal((global): StateProps => {
const appConfig = global.appConfig; const appConfig = global.appConfig;
const verifyAgeBotUsername = appConfig?.verifyAgeBotUsername; const verifyAgeBotUsername = appConfig.verifyAgeBotUsername;
const verifyAgeMin = appConfig?.verifyAgeMin || VERIFY_AGE_MIN_DEFAULT; const verifyAgeMin = appConfig.verifyAgeMin || VERIFY_AGE_MIN_DEFAULT;
return { return {
verifyAgeBotUsername, verifyAgeBotUsername,

View File

@ -63,7 +63,6 @@ const CollectibleInfoModal: FC<OwnProps & StateProps> = ({
const handleOpenUrl = useLastCallback(() => { const handleOpenUrl = useLastCallback(() => {
openUrl({ openUrl({
url: modal!.url, url: modal!.url,
shouldSkipModal: true,
}); });
handleClose(); handleClose();
}); });

View File

@ -129,8 +129,8 @@ const FrozenAccountModal = ({
export default memo(withGlobal<OwnProps>( export default memo(withGlobal<OwnProps>(
(global): StateProps => { (global): StateProps => {
const freezeUntilDate = global.appConfig?.freezeUntilDate; const freezeUntilDate = global.appConfig.freezeUntilDate;
const freezeAppealUrl = global.appConfig?.freezeAppealUrl; const freezeAppealUrl = global.appConfig.freezeAppealUrl;
const botFreezeAppeal = global.botFreezeAppealId ? selectUser(global, global.botFreezeAppealId) : undefined; const botFreezeAppeal = global.botFreezeAppealId ? selectUser(global, global.botFreezeAppealId) : undefined;
const botFreezeAppealUsername = botFreezeAppeal && getMainUsername(botFreezeAppeal); const botFreezeAppealUsername = botFreezeAppeal && getMainUsername(botFreezeAppeal);

View File

@ -428,7 +428,7 @@ export default memo(withGlobal<OwnProps>(
patternColor, patternColor,
customBackground, customBackground,
backgroundColor, backgroundColor,
captionLimit: global.appConfig?.starGiftMaxMessageLength, captionLimit: global.appConfig.starGiftMaxMessageLength,
currentUserId: global.currentUserId, currentUserId: global.currentUserId,
isPaymentFormLoading: tabState.isPaymentFormLoading, isPaymentFormLoading: tabState.isPaymentFormLoading,
paidMessagesStars, paidMessagesStars,

View File

@ -528,7 +528,7 @@ export default memo(withGlobal<OwnProps>((global, { modal }): StateProps => {
const areResaleGiftsLoading = resaleGifts.isLoading !== false; const areResaleGiftsLoading = resaleGifts.isLoading !== false;
return { return {
boostPerSentGift: global.appConfig?.boostsPerSentGift, boostPerSentGift: global.appConfig.boostsPerSentGift,
starGiftsById: starGifts?.byId, starGiftsById: starGifts?.byId,
starGiftIdsByCategory: starGifts?.idsByCategory, starGiftIdsByCategory: starGifts?.idsByCategory,
starBalance: stars?.balance, starBalance: stars?.balance,

View File

@ -10,10 +10,10 @@ import type {
} from '../../../api/types'; } from '../../../api/types';
import type { ResaleGiftsFilterOptions } from '../../../types'; import type { ResaleGiftsFilterOptions } from '../../../types';
import { RESALE_GIFTS_LIMIT } from '../../../config';
import { selectTabState, import { selectTabState,
} from '../../../global/selectors'; } from '../../../global/selectors';
import buildClassName from '../../../util/buildClassName'; import buildClassName from '../../../util/buildClassName';
import { RESALE_GIFTS_LIMIT } from '../../../limits';
import { LOCAL_TGS_URLS } from '../../common/helpers/animatedAssets'; import { LOCAL_TGS_URLS } from '../../common/helpers/animatedAssets';
import useInfiniteScroll from '../../../hooks/useInfiniteScroll'; import useInfiniteScroll from '../../../hooks/useInfiniteScroll';

View File

@ -906,8 +906,8 @@ export default memo(withGlobal<OwnProps>(
targetPeer, targetPeer,
releasedByPeer, releasedByPeer,
currentUserId, currentUserId,
starGiftMaxConvertPeriod: global.appConfig?.starGiftMaxConvertPeriod, starGiftMaxConvertPeriod: global.appConfig.starGiftMaxConvertPeriod,
tonExplorerUrl: global.appConfig?.tonExplorerUrl, tonExplorerUrl: global.appConfig.tonExplorerUrl,
hasAdminRights, hasAdminRights,
currentUserEmojiStatus, currentUserEmojiStatus,
collectibleEmojiStatuses, collectibleEmojiStatuses,

View File

@ -176,21 +176,21 @@ const GiftResalePriceComposerModal = ({
export default memo(withGlobal<OwnProps>( export default memo(withGlobal<OwnProps>(
(global): StateProps => { (global): StateProps => {
const configPermille = global.appConfig?.starsStargiftResaleCommissionPermille; const configPermille = global.appConfig.starsStargiftResaleCommissionPermille;
const starsStargiftResaleCommissionPermille = configPermille ? (configPermille / 1000) : undefined; const starsStargiftResaleCommissionPermille = configPermille ? (configPermille / 1000) : undefined;
const starsStargiftResaleAmountMin = global.appConfig?.starsStargiftResaleAmountMin || 0; const starsStargiftResaleAmountMin = global.appConfig.starsStargiftResaleAmountMin || 0;
const starsStargiftResaleAmountMax = global.appConfig?.starsStargiftResaleAmountMax; const starsStargiftResaleAmountMax = global.appConfig.starsStargiftResaleAmountMax;
const starsUsdWithdrawRateX1000 = global.appConfig?.starsUsdWithdrawRateX1000; const starsUsdWithdrawRateX1000 = global.appConfig.starsUsdWithdrawRateX1000;
const starsUsdWithdrawRate = starsUsdWithdrawRateX1000 ? starsUsdWithdrawRateX1000 / 1000 : 1; const starsUsdWithdrawRate = starsUsdWithdrawRateX1000 ? starsUsdWithdrawRateX1000 / 1000 : 1;
const tonConfigPermille = global.appConfig?.tonStargiftResaleCommissionPermille; const tonConfigPermille = global.appConfig.tonStargiftResaleCommissionPermille;
const tonStargiftResaleCommissionPermille = tonConfigPermille ? (tonConfigPermille / 1000) : 0; const tonStargiftResaleCommissionPermille = tonConfigPermille ? (tonConfigPermille / 1000) : 0;
const tonStargiftResaleAmountMin = convertTonFromNanos(global.appConfig?.tonStargiftResaleAmountMin || 0); const tonStargiftResaleAmountMin = convertTonFromNanos(global.appConfig.tonStargiftResaleAmountMin || 0);
const maxTonFromConfig = global.appConfig?.tonStargiftResaleAmountMax; const maxTonFromConfig = global.appConfig.tonStargiftResaleAmountMax;
const tonStargiftResaleAmountMax = maxTonFromConfig && convertTonFromNanos(maxTonFromConfig); const tonStargiftResaleAmountMax = maxTonFromConfig && convertTonFromNanos(maxTonFromConfig);
const tonUsdRate = global.appConfig?.tonUsdRate; const tonUsdRate = global.appConfig.tonUsdRate;
return { return {
starsStargiftResaleCommissionPermille, starsStargiftResaleCommissionPermille,

View File

@ -377,7 +377,7 @@ export default memo(withGlobal<OwnProps>(
const chat = modal && selectChat(global, modal.chatId); const chat = modal && selectChat(global, modal.chatId);
const message = modal && selectChatMessage(global, modal.chatId, modal.messageId); const message = modal && selectChatMessage(global, modal.chatId, modal.messageId);
const starBalance = global.stars?.balance; const starBalance = global.stars?.balance;
const maxAmount = global.appConfig?.paidReactionMaxAmount || MAX_REACTION_AMOUNT; const maxAmount = global.appConfig.paidReactionMaxAmount || MAX_REACTION_AMOUNT;
const defaultPrivacy = global.settings.paidReactionPrivacy; const defaultPrivacy = global.settings.paidReactionPrivacy;
const sendPaidReactionsAsPeerIds = chat?.sendPaidReactionsAsPeerIds; const sendPaidReactionsAsPeerIds = chat?.sendPaidReactionsAsPeerIds;
const currentUserId = global.currentUserId!; const currentUserId = global.currentUserId!;

View File

@ -10,8 +10,6 @@ import {
PAID_MESSAGES_PURPOSE, PAID_MESSAGES_PURPOSE,
STARS_CURRENCY_CODE, STARS_CURRENCY_CODE,
TON_CURRENCY_CODE, TON_CURRENCY_CODE,
TON_TOPUP_URL_DEFAULT,
TON_USD_RATE_DEFAULT,
} from '../../../config'; } from '../../../config';
import { getChatTitle, getUserFullName } from '../../../global/helpers'; import { getChatTitle, getUserFullName } from '../../../global/helpers';
import { getPeerTitle } from '../../../global/helpers/peers'; import { getPeerTitle } from '../../../global/helpers/peers';
@ -298,7 +296,7 @@ const StarsBalanceModal = ({
}); });
const handleTonTopUp = useLastCallback(() => { const handleTonTopUp = useLastCallback(() => {
openUrl({ url: tonTopupUrl, shouldSkipModal: true }); openUrl({ url: tonTopupUrl });
}); });
return ( return (
@ -419,8 +417,8 @@ export default memo(withGlobal<OwnProps>(
starsBalanceState: global.stars, starsBalanceState: global.stars,
tonBalanceState: global.ton, tonBalanceState: global.ton,
canBuyPremium: !selectIsPremiumPurchaseBlocked(global), canBuyPremium: !selectIsPremiumPurchaseBlocked(global),
tonUsdRate: global.appConfig?.tonUsdRate || TON_USD_RATE_DEFAULT, tonUsdRate: global.appConfig.tonUsdRate,
tonTopupUrl: global.appConfig?.tonTopupUrl || TON_TOPUP_URL_DEFAULT, tonTopupUrl: global.appConfig.tonTopupUrl,
animationLevel: selectSharedSettings(global).animationLevel, animationLevel: selectSharedSettings(global).animationLevel,
}; };
}, },

View File

@ -345,7 +345,7 @@ export default memo(withGlobal<OwnProps>(
(global, { modal }): StateProps => { (global, { modal }): StateProps => {
const peerId = modal?.transaction?.peer?.type === 'peer' && modal.transaction.peer.id; const peerId = modal?.transaction?.peer?.type === 'peer' && modal.transaction.peer.id;
const peer = peerId ? selectPeer(global, peerId) : undefined; const peer = peerId ? selectPeer(global, peerId) : undefined;
const paidMessageCommission = global.appConfig?.starsPaidMessageCommissionPermille; const paidMessageCommission = global.appConfig.starsPaidMessageCommissionPermille;
const currencyAmount = modal?.transaction.amount; const currencyAmount = modal?.transaction.amount;
const starsGiftSticker = modal?.transaction.isGift const starsGiftSticker = modal?.transaction.isGift

View File

@ -11,14 +11,8 @@ import { MAIN_THREAD_ID } from '../../../api/types';
import { import {
STARS_CURRENCY_CODE, STARS_CURRENCY_CODE,
STARS_SUGGESTED_POST_AGE_MIN,
STARS_SUGGESTED_POST_AMOUNT_MAX,
STARS_SUGGESTED_POST_AMOUNT_MIN,
STARS_SUGGESTED_POST_FUTURE_MAX,
STARS_SUGGESTED_POST_FUTURE_MIN,
TON_CURRENCY_CODE, TON_CURRENCY_CODE,
TON_SUGGESTED_POST_AMOUNT_MAX, } from '../../../config';
TON_SUGGESTED_POST_AMOUNT_MIN } from '../../../config';
import { selectIsMonoforumAdmin, selectPeer } from '../../../global/selectors'; import { selectIsMonoforumAdmin, selectPeer } from '../../../global/selectors';
import { selectDraft } from '../../../global/selectors/messages'; import { selectDraft } from '../../../global/selectors/messages';
import buildClassName from '../../../util/buildClassName'; import buildClassName from '../../../util/buildClassName';
@ -29,7 +23,9 @@ import {
formatStarsAsText, formatStarsAsText,
formatTonAsIcon, formatTonAsIcon,
formatTonAsText } from '../../../util/localization/format'; formatTonAsText } from '../../../util/localization/format';
import { getServerTime } from '../../../util/serverTime';
import useFlag from '../../../hooks/useFlag';
import useLang from '../../../hooks/useLang'; import useLang from '../../../hooks/useLang';
import useLastCallback from '../../../hooks/useLastCallback'; import useLastCallback from '../../../hooks/useLastCallback';
import useOldLang from '../../../hooks/useOldLang'; import useOldLang from '../../../hooks/useOldLang';
@ -46,8 +42,6 @@ export type OwnProps = {
modal: TabState['suggestMessageModal']; modal: TabState['suggestMessageModal'];
}; };
import useFlag from '../../../hooks/useFlag';
type StateProps = { type StateProps = {
starBalance?: ApiStarsAmount; starBalance?: ApiStarsAmount;
tonBalance?: number; tonBalance?: number;
@ -63,6 +57,9 @@ type StateProps = {
isMonoforumAdmin?: boolean; isMonoforumAdmin?: boolean;
}; };
// Add 1 minute if time is less than server min, to allow user to send the message
const FUTURE_TIME_ADJUSTMENT = 1 * 60;
const SuggestMessageModal = ({ const SuggestMessageModal = ({
modal, modal,
starBalance, starBalance,
@ -174,7 +171,9 @@ const SuggestMessageModal = ({
updateDraftSuggestedPostInfo({ updateDraftSuggestedPostInfo({
price: { currency: selectedCurrency, amount: neededAmount, nanos: 0 }, price: { currency: selectedCurrency, amount: neededAmount, nanos: 0 },
scheduleDate: scheduleDate ? scheduleDate / 1000 : undefined, scheduleDate: scheduleDate
? Math.max(scheduleDate / 1000, getServerTime() + futureMin + FUTURE_TIME_ADJUSTMENT)
: undefined,
}); });
closeSuggestMessageModal(); closeSuggestMessageModal();
@ -308,14 +307,14 @@ export default memo(withGlobal<OwnProps>(
const currentDraft = modal ? selectDraft(global, modal.chatId, MAIN_THREAD_ID) : undefined; const currentDraft = modal ? selectDraft(global, modal.chatId, MAIN_THREAD_ID) : undefined;
const { appConfig } = global; const { appConfig } = global;
const maxStarsAmount = appConfig?.starsSuggestedPostAmountMax || STARS_SUGGESTED_POST_AMOUNT_MAX; const maxStarsAmount = appConfig.starsSuggestedPostAmountMax;
const minStarsAmount = appConfig?.starsSuggestedPostAmountMin || STARS_SUGGESTED_POST_AMOUNT_MIN; const minStarsAmount = appConfig.starsSuggestedPostAmountMin;
const ageMinSeconds = appConfig?.starsSuggestedPostAgeMin || STARS_SUGGESTED_POST_AGE_MIN; const ageMinSeconds = appConfig.starsSuggestedPostAgeMin;
const futureMin = appConfig?.starsSuggestedPostFutureMin || STARS_SUGGESTED_POST_FUTURE_MIN; const futureMin = appConfig.starsSuggestedPostFutureMin;
const futureMax = appConfig?.starsSuggestedPostFutureMax || STARS_SUGGESTED_POST_FUTURE_MAX; const futureMax = appConfig.starsSuggestedPostFutureMax;
const tonMaxAmount = appConfig?.tonSuggestedPostAmountMax || TON_SUGGESTED_POST_AMOUNT_MAX; const tonMaxAmount = appConfig.tonSuggestedPostAmountMax;
const tonMinAmount = appConfig?.tonSuggestedPostAmountMin || TON_SUGGESTED_POST_AMOUNT_MIN; const tonMinAmount = appConfig.tonSuggestedPostAmountMin;
const isMonoforumAdmin = modal ? selectIsMonoforumAdmin(global, modal.chatId) : false; const isMonoforumAdmin = modal ? selectIsMonoforumAdmin(global, modal.chatId) : false;

View File

@ -4,12 +4,9 @@ import { getActions, withGlobal } from '../../../global';
import type { ApiMessage, ApiPeer } from '../../../api/types'; import type { ApiMessage, ApiPeer } from '../../../api/types';
import type { TabState } from '../../../global/types'; import type { TabState } from '../../../global/types';
import { STARS_CURRENCY_CODE, STARS_SUGGESTED_POST_AGE_MIN, import {
STARS_SUGGESTED_POST_COMMISSION_PERMILLE, STARS_CURRENCY_CODE,
STARS_SUGGESTED_POST_FUTURE_MAX,
STARS_SUGGESTED_POST_FUTURE_MIN,
TON_CURRENCY_CODE, TON_CURRENCY_CODE,
TON_SUGGESTED_POST_COMMISSION_PERMILLE,
} from '../../../config'; } from '../../../config';
import { getPeerFullTitle } from '../../../global/helpers/peers'; import { getPeerFullTitle } from '../../../global/helpers/peers';
import { selectChatMessage, selectIsMonoforumAdmin, selectSender } from '../../../global/selectors'; import { selectChatMessage, selectIsMonoforumAdmin, selectSender } from '../../../global/selectors';
@ -224,13 +221,11 @@ export default memo(withGlobal<OwnProps>(
const sender = message ? selectSender(global, message) : undefined; const sender = message ? selectSender(global, message) : undefined;
const isAdmin = modal && selectIsMonoforumAdmin(global, modal.chatId); const isAdmin = modal && selectIsMonoforumAdmin(global, modal.chatId);
const { appConfig } = global; const { appConfig } = global;
const commissionPermille = appConfig?.starsSuggestedPostCommissionPermille const commissionPermille = appConfig.starsSuggestedPostCommissionPermille;
|| STARS_SUGGESTED_POST_COMMISSION_PERMILLE; const tonCommissionPermille = appConfig.tonSuggestedPostCommissionPermille;
const tonCommissionPermille = appConfig?.tonSuggestedPostCommissionPermille const minAge = appConfig.starsSuggestedPostAgeMin;
|| TON_SUGGESTED_POST_COMMISSION_PERMILLE; const futureMin = appConfig.starsSuggestedPostFutureMin;
const minAge = appConfig?.starsSuggestedPostAgeMin || STARS_SUGGESTED_POST_AGE_MIN; const futureMax = appConfig.starsSuggestedPostFutureMax;
const futureMin = (appConfig?.starsSuggestedPostFutureMin || STARS_SUGGESTED_POST_FUTURE_MIN) * 2;
const futureMax = appConfig?.starsSuggestedPostFutureMax || STARS_SUGGESTED_POST_FUTURE_MAX;
const scheduleDate = message?.suggestedPostInfo?.scheduleDate; const scheduleDate = message?.suggestedPostInfo?.scheduleDate;
return { return {

View File

@ -386,7 +386,7 @@ const useWebAppFrame = (
if (eventType === 'web_app_verify_age') { if (eventType === 'web_app_verify_age') {
const { passed } = eventData; const { passed } = eventData;
const minAge = getGlobal().appConfig?.verifyAgeMin || VERIFY_AGE_MIN_DEFAULT; const minAge = getGlobal().appConfig.verifyAgeMin || VERIFY_AGE_MIN_DEFAULT;
const ageFromParam = eventData.age || 0; const ageFromParam = eventData.age || 0;
if (passed && ageFromParam >= minAge) { if (passed && ageFromParam >= minAge) {

View File

@ -383,7 +383,7 @@ export default memo(withGlobal<OwnProps>(
const { management } = selectTabState(global); const { management } = selectTabState(global);
const { progress } = management; const { progress } = management;
const { invites } = management.byChatId[chatId] || {}; const { invites } = management.byChatId[chatId] || {};
const minLevelToToggleAutoTranslation = global.appConfig?.channelAutoTranslationLevelMin; const minLevelToToggleAutoTranslation = global.appConfig.channelAutoTranslationLevelMin;
const hasAutoTranslation = chat?.hasAutoTranslation; const hasAutoTranslation = chat?.hasAutoTranslation;
const chatBoostLevel = chat?.level; const chatBoostLevel = chat?.level;
const canToggleAutoTranslation = chatBoostLevel && minLevelToToggleAutoTranslation const canToggleAutoTranslation = chatBoostLevel && minLevelToToggleAutoTranslation

View File

@ -280,7 +280,7 @@ export default memo(withGlobal<OwnProps>(
const { members, adminMembersById, areParticipantsHidden } = selectChatFullInfo(global, chatId) || {}; const { members, adminMembersById, areParticipantsHidden } = selectChatFullInfo(global, chatId) || {};
const isChannel = chat && isChatChannel(chat); const isChannel = chat && isChatChannel(chat);
const { userIds: localContactIds } = global.contactList || {}; const { userIds: localContactIds } = global.contactList || {};
const hiddenMembersMinCount = global.appConfig?.hiddenMembersMinCount; const hiddenMembersMinCount = global.appConfig.hiddenMembersMinCount;
const canDeleteMembers = chat && (chat.isCreator || getHasAdminRight(chat, 'banUsers')); const canDeleteMembers = chat && (chat.isCreator || getHasAdminRight(chat, 'banUsers'));

View File

@ -358,7 +358,7 @@ export default memo(withGlobal<OwnProps>(
const { progress } = selectTabState(global).management; const { progress } = selectTabState(global).management;
const paidMessagesStars = chat?.paidMessagesStars; const paidMessagesStars = chat?.paidMessagesStars;
const configStarsPaidMessageCommissionPermille = global.appConfig?.starsPaidMessageCommissionPermille; const configStarsPaidMessageCommissionPermille = global.appConfig.starsPaidMessageCommissionPermille;
return { return {
chat, chat,

View File

@ -10,9 +10,6 @@ import type {
ApiAvailableReaction, ApiChat, ApiChatReactions, ApiReaction, ApiAvailableReaction, ApiChat, ApiChatReactions, ApiReaction,
} from '../../../api/types'; } from '../../../api/types';
import {
MAX_UNIQUE_REACTIONS,
} from '../../../config';
import { isChatChannel, isSameReaction } from '../../../global/helpers'; import { isChatChannel, isSameReaction } from '../../../global/helpers';
import { selectChat, selectChatFullInfo } from '../../../global/selectors'; import { selectChat, selectChatFullInfo } from '../../../global/selectors';
@ -271,7 +268,7 @@ const ManageReactions: FC<OwnProps & StateProps> = ({
export default memo(withGlobal<OwnProps>( export default memo(withGlobal<OwnProps>(
(global, { chatId }): StateProps => { (global, { chatId }): StateProps => {
const chat = selectChat(global, chatId)!; const chat = selectChat(global, chatId)!;
const { maxUniqueReactions = MAX_UNIQUE_REACTIONS } = global.appConfig || {}; const { maxUniqueReactions } = global.appConfig;
const chatFullInfo = selectChatFullInfo(global, chatId); const chatFullInfo = selectChatFullInfo(global, chatId);
const reactionsLimit = chatFullInfo?.reactionsLimit || maxUniqueReactions; const reactionsLimit = chatFullInfo?.reactionsLimit || maxUniqueReactions;

View File

@ -429,7 +429,7 @@ export default memo(withGlobal(
const chatId = boostStatistics && boostStatistics.chatId; const chatId = boostStatistics && boostStatistics.chatId;
const chat = chatId ? selectChat(global, chatId) : undefined; const chat = chatId ? selectChat(global, chatId) : undefined;
const isChannel = chat && isChatChannel(chat); const isChannel = chat && isChatChannel(chat);
const giveawayBoostsPerPremium = global.appConfig?.giveawayBoostsPerPremium; const giveawayBoostsPerPremium = global.appConfig.giveawayBoostsPerPremium;
const { animationLevel } = selectSharedSettings(global); const { animationLevel } = selectSharedSettings(global);
return { return {

View File

@ -301,7 +301,7 @@ export default memo(withGlobal(
const statistics = tabState.statistics.monetization; const statistics = tabState.statistics.monetization;
const isChannelRevenueWithdrawalEnabled = global.appConfig?.isChannelRevenueWithdrawalEnabled; const isChannelRevenueWithdrawalEnabled = global.appConfig.isChannelRevenueWithdrawalEnabled;
return { return {
chatId: chatId!, chatId: chatId!,

View File

@ -190,7 +190,7 @@ export default memo(withGlobal<OwnProps>((global, { story }): StateProps => {
const chat = selectChat(global, story.peerId); const chat = selectChat(global, story.peerId);
const isProtected = chat?.isProtected; const isProtected = chat?.isProtected;
const { maxPinnedStoriesCount } = global.appConfig || {}; const { maxPinnedStoriesCount } = global.appConfig;
const isOwn = 'isOut' in story && story.isOut; const isOwn = 'isOut' in story && story.isOut;
const pinnedStories = selectPinnedStories(global, story.peerId); const pinnedStories = selectPinnedStories(global, story.peerId);
const isPinned = pinnedStories?.some((pinnedStory) => pinnedStory.id === story.id); const isPinned = pinnedStories?.some((pinnedStory) => pinnedStory.id === story.id);

View File

@ -981,8 +981,8 @@ export default memo(withGlobal<OwnProps>((global, {
isMuted, isMuted,
isCurrentUserPremium: selectIsCurrentUserPremium(global), isCurrentUserPremium: selectIsCurrentUserPremium(global),
shouldForcePause, shouldForcePause,
storyChangelogUserId: appConfig!.storyChangelogUserId, storyChangelogUserId: appConfig.storyChangelogUserId,
viewersExpirePeriod: appConfig!.storyExpirePeriod + appConfig!.storyViewersExpirePeriod, viewersExpirePeriod: appConfig.storyViewersExpirePeriod,
isChatExist: Boolean(chat), isChatExist: Boolean(chat),
arePeerSettingsLoaded: Boolean(userFullInfo?.settings), arePeerSettingsLoaded: Boolean(userFullInfo?.settings),
stealthMode: global.stories.stealthMode, stealthMode: global.stories.stealthMode,

View File

@ -44,7 +44,7 @@ interface StateProps {
isLoading?: boolean; isLoading?: boolean;
views?: ApiTypeStoryView[]; views?: ApiTypeStoryView[];
nextOffset?: string; nextOffset?: string;
viewersExpirePeriod: number; viewersExpireDate?: number;
isCurrentUserPremium?: boolean; isCurrentUserPremium?: boolean;
} }
@ -52,7 +52,7 @@ const REFETCH_DEBOUNCE = 250;
function StoryViewModal({ function StoryViewModal({
story, story,
viewersExpirePeriod, viewersExpireDate,
views, views,
nextOffset, nextOffset,
isLoading, isLoading,
@ -69,7 +69,7 @@ function StoryViewModal({
const lang = useOldLang(); const lang = useOldLang();
const isOpen = Boolean(story); const isOpen = Boolean(story);
const isExpired = Boolean(story?.date) && (story.date + viewersExpirePeriod) < getServerTime(); const isExpired = Boolean(viewersExpireDate) && viewersExpireDate < getServerTime();
const { viewsCount = 0, reactionsCount = 0 } = story?.views || {}; const { viewsCount = 0, reactionsCount = 0 } = story?.views || {};
const shouldShowJustContacts = story?.isPublic && viewsCount > STORY_VIEWS_MIN_CONTACTS_FILTER; const shouldShowJustContacts = story?.isPublic && viewsCount > STORY_VIEWS_MIN_CONTACTS_FILTER;
@ -275,11 +275,12 @@ export default memo(withGlobal((global) => {
storyId, views, nextOffset, isLoading, storyId, views, nextOffset, isLoading,
} = viewModal || {}; } = viewModal || {};
const story = storyId ? selectPeerStory(global, global.currentUserId!, storyId) : undefined; const story = storyId ? selectPeerStory(global, global.currentUserId!, storyId) : undefined;
const storyExpireDate = story?.['@type'] === 'story' ? story.expireDate : undefined;
return { return {
storyId, storyId,
views, views,
viewersExpirePeriod: appConfig!.storyExpirePeriod + appConfig!.storyViewersExpirePeriod, viewersExpireDate: storyExpireDate ? (storyExpireDate + appConfig.storyViewersExpirePeriod) : undefined,
story: story && 'content' in story ? story : undefined, story: story && 'content' in story ? story : undefined,
nextOffset, nextOffset,
isLoading, isLoading,

View File

@ -5,9 +5,6 @@ import { getActions, withGlobal } from '../../global';
import type { ApiStarsAmount, ApiTonAmount } from '../../api/types'; import type { ApiStarsAmount, ApiTonAmount } from '../../api/types';
import {
TON_USD_RATE_DEFAULT,
} from '../../config';
import { formatStarsAmount } from '../../global/helpers/payments'; import { formatStarsAmount } from '../../global/helpers/payments';
import buildClassName from '../../util/buildClassName'; import buildClassName from '../../util/buildClassName';
import { convertTonFromNanos, convertTonToUsd, formatCurrencyAsString } from '../../util/formatCurrency'; import { convertTonFromNanos, convertTonToUsd, formatCurrencyAsString } from '../../util/formatCurrency';
@ -30,7 +27,7 @@ export type OwnProps = {
export type StateProps = { export type StateProps = {
starBalance?: ApiStarsAmount; starBalance?: ApiStarsAmount;
tonBalance?: ApiTonAmount; tonBalance?: ApiTonAmount;
tonUsdRate: number; tonUsdRate?: number;
}; };
function ModalStarBalanceBar({ function ModalStarBalanceBar({
@ -38,8 +35,8 @@ function ModalStarBalanceBar({
tonBalance, tonBalance,
tonUsdRate, tonUsdRate,
isModalOpen, isModalOpen,
onCloseAnimationEnd,
currency, currency,
onCloseAnimationEnd,
}: StateProps & OwnProps) { }: StateProps & OwnProps) {
const { const {
openStarsBalanceModal, openStarsBalanceModal,
@ -94,7 +91,7 @@ function ModalStarBalanceBar({
)} )}
</div> </div>
<div> <div>
{isTonMode && ( {isTonMode && Boolean(tonUsdRate) && (
<div className={styles.tonInUsdDescription} style="color: var(--color-text-secondary)"> <div className={styles.tonInUsdDescription} style="color: var(--color-text-secondary)">
{`${formatCurrencyAsString( {`${formatCurrencyAsString(
convertTonToUsd((currentBalance as ApiTonAmount).amount, tonUsdRate, true), convertTonToUsd((currentBalance as ApiTonAmount).amount, tonUsdRate, true),
@ -123,7 +120,7 @@ export default memo(withGlobal(
return { return {
starBalance: stars?.balance, starBalance: stars?.balance,
tonBalance: ton?.balance, tonBalance: ton?.balance,
tonUsdRate: global.appConfig?.tonUsdRate || TON_USD_RATE_DEFAULT, tonUsdRate: global.appConfig.tonUsdRate,
}; };
}, },
)(ModalStarBalanceBar)); )(ModalStarBalanceBar));

View File

@ -1,5 +1,5 @@
import type { import type {
ApiLimitType, ApiLimitTypeForPromo, ApiPremiumSection, ApiReactionEmoji, ApiLimitTypeForPromo, ApiPremiumSection, ApiReactionEmoji,
} from './api/types'; } from './api/types';
import type { import type {
GiftProfileFilterOptions, GiftProfileFilterOptions,
@ -94,39 +94,18 @@ export const CHAT_MEDIA_SLICE = 42;
export const MESSAGE_SEARCH_SLICE = 42; export const MESSAGE_SEARCH_SLICE = 42;
export const GLOBAL_SEARCH_SLICE = 20; export const GLOBAL_SEARCH_SLICE = 20;
export const GLOBAL_TOPIC_SEARCH_SLICE = 5; export const GLOBAL_TOPIC_SEARCH_SLICE = 5;
export const GLOBAL_SEARCH_CONTACTS_LIMIT = 20;
export const MEMBERS_SLICE = 30; export const MEMBERS_SLICE = 30;
export const MEMBERS_LOAD_SLICE = 200; export const MEMBERS_LOAD_SLICE = 200;
export const PINNED_MESSAGES_LIMIT = 50;
export const BLOCKED_LIST_LIMIT = 100;
export const PROFILE_SENSITIVE_AREA = 500; export const PROFILE_SENSITIVE_AREA = 500;
export const TOPIC_LIST_SENSITIVE_AREA = 600; export const TOPIC_LIST_SENSITIVE_AREA = 600;
export const GROUP_CALL_PARTICIPANTS_LIMIT = 100;
export const STORY_LIST_LIMIT = 100;
export const API_GENERAL_ID_LIMIT = 100;
export const RESALE_GIFTS_LIMIT = 50;
export const TODO_ITEMS_LIMIT = 30;
export const TODO_TITLE_LENGTH_LIMIT = 32;
export const TODO_ITEM_LENGTH_LIMIT = 64;
// Public Posts Search defaults // Public Posts Search defaults
export const PUBLIC_POSTS_SEARCH_DEFAULT_STARS_AMOUNT = 10; export const PUBLIC_POSTS_SEARCH_DEFAULT_STARS_AMOUNT = 10;
export const PUBLIC_POSTS_SEARCH_DEFAULT_TOTAL_DAILY = 2; export const PUBLIC_POSTS_SEARCH_DEFAULT_TOTAL_DAILY = 2;
// Suggested Posts defaults // Suggested Posts defaults
export const STARS_SUGGESTED_POST_AMOUNT_MAX = 100000;
export const STARS_SUGGESTED_POST_AMOUNT_MIN = 5;
export const STARS_SUGGESTED_POST_COMMISSION_PERMILLE = 850;
export const STARS_SUGGESTED_POST_AGE_MIN = 86400; // 24 hours in seconds
export const STARS_SUGGESTED_POST_FUTURE_MAX = 2678400; // 31 days in seconds
export const STARS_SUGGESTED_POST_FUTURE_MIN = 300; // 5 minutes in seconds
export const TON_CURRENCY_CODE = 'TON'; export const TON_CURRENCY_CODE = 'TON';
export const TON_SUGGESTED_POST_COMMISSION_PERMILLE = 850;
export const TON_USD_RATE_DEFAULT = 3;
export const VERIFY_AGE_MIN_DEFAULT = 18; export const VERIFY_AGE_MIN_DEFAULT = 18;
export const TON_TOPUP_URL_DEFAULT = 'https://fragment.com/ads/topup';
export const TON_SUGGESTED_POST_AMOUNT_MIN = 10000000; // 0.01 TON in nanos
export const TON_SUGGESTED_POST_AMOUNT_MAX = 10000000000000; // 10 000 TON in nanos
export const STORY_VIEWS_MIN_SEARCH = 15; export const STORY_VIEWS_MIN_SEARCH = 15;
export const STORY_MIN_REACTIONS_SORT = 10; export const STORY_MIN_REACTIONS_SORT = 10;
@ -136,14 +115,8 @@ export const MEDIA_TIMESTAMP_SAVE_MINIMUM_DURATION = 30; // 30s
export const GLOBAL_SUGGESTED_CHANNELS_ID = 'global'; export const GLOBAL_SUGGESTED_CHANNELS_ID = 'global';
// As in Telegram for Android
// https://github.com/DrKLO/Telegram/blob/51e9947527/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java#L7799
export const TOP_REACTIONS_LIMIT = 100;
// As in Telegram for Android // As in Telegram for Android
// https://github.com/DrKLO/Telegram/blob/51e9947527/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java#L7781 // https://github.com/DrKLO/Telegram/blob/51e9947527/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java#L7781
export const RECENT_REACTIONS_LIMIT = 50;
export const REACTION_LIST_LIMIT = 100;
export const REACTION_UNREAD_SLICE = 100; export const REACTION_UNREAD_SLICE = 100;
export const MENTION_UNREAD_SLICE = 100; export const MENTION_UNREAD_SLICE = 100;
export const TOPICS_SLICE = 20; export const TOPICS_SLICE = 20;
@ -401,7 +374,6 @@ export const PEER_COLOR_BG_OPACITY = '1a';
export const PEER_COLOR_BG_ACTIVE_OPACITY = '2b'; export const PEER_COLOR_BG_ACTIVE_OPACITY = '2b';
export const PEER_COLOR_GRADIENT_STEP = 5; // px export const PEER_COLOR_GRADIENT_STEP = 5; // px
export const MAX_UPLOAD_FILEPART_SIZE = 524288; export const MAX_UPLOAD_FILEPART_SIZE = 524288;
export const MAX_UNIQUE_REACTIONS = 11;
export const IGNORE_UNHANDLED_ERRORS = new Set([ export const IGNORE_UNHANDLED_ERRORS = new Set([
'USER_CANCELED', 'USER_CANCELED',
@ -411,25 +383,6 @@ export const IGNORE_UNHANDLED_ERRORS = new Set([
export const GROUP_CALL_VOLUME_MULTIPLIER = 100; export const GROUP_CALL_VOLUME_MULTIPLIER = 100;
export const GROUP_CALL_DEFAULT_VOLUME = 100 * GROUP_CALL_VOLUME_MULTIPLIER; export const GROUP_CALL_DEFAULT_VOLUME = 100 * GROUP_CALL_VOLUME_MULTIPLIER;
export const DEFAULT_LIMITS: Record<ApiLimitType, readonly [number, number]> = {
uploadMaxFileparts: [4000, 8000],
stickersFaved: [5, 10],
savedGifs: [200, 400],
dialogFiltersChats: [100, 200],
dialogFilters: [10, 20],
dialogFolderPinned: [5, 10],
captionLength: [1024, 4096],
channels: [500, 1000],
channelsPublic: [10, 20],
aboutLength: [70, 140],
chatlistInvites: [3, 100],
chatlistJoined: [2, 20],
recommendedChannels: [10, 100],
savedDialogsPinned: [5, 100],
moreAccounts: [3, MULTIACCOUNT_MAX_SLOTS],
};
export const DEFAULT_MAX_MESSAGE_LENGTH = 4096;
export const ONE_TIME_MEDIA_TTL_SECONDS = 2147483647; export const ONE_TIME_MEDIA_TTL_SECONDS = 2147483647;
// Premium // Premium

View File

@ -1444,7 +1444,7 @@ addActionHandler('startBotFatherConversation', async (global, actions, payload):
}); });
addActionHandler('loadBotFreezeAppeal', async (global): Promise<void> => { addActionHandler('loadBotFreezeAppeal', async (global): Promise<void> => {
const botUrl = global.appConfig?.freezeAppealUrl; const botUrl = global.appConfig.freezeAppealUrl;
if (!botUrl) return; if (!botUrl) return;
const botAppealUsername = botUrl ? getUsernameFromDeepLink(botUrl) : undefined; const botAppealUsername = botUrl ? getUsernameFromDeepLink(botUrl) : undefined;
if (!botAppealUsername) return; if (!botAppealUsername) return;

View File

@ -2517,7 +2517,7 @@ addActionHandler('toggleTopicPinned', (global, actions, payload): ActionReturnTy
chatId, topicId, isPinned, tabId = getCurrentTabId(), chatId, topicId, isPinned, tabId = getCurrentTabId(),
} = payload; } = payload;
const { topicsPinnedLimit } = global.appConfig || {}; const { topicsPinnedLimit } = global.appConfig;
const chat = selectChat(global, chatId); const chat = selectChat(global, chatId);
const topics = selectTopics(global, chatId); const topics = selectTopics(global, chatId);
if (!chat || !topics || !topicsPinnedLimit) return; if (!chat || !topics || !topicsPinnedLimit) return;
@ -3375,7 +3375,7 @@ async function openChatByUsername<T extends GlobalState>(
actions.openChat({ id: TMP_CHAT_ID, tabId }); actions.openChat({ id: TMP_CHAT_ID, tabId });
} }
const starRefStartPrefixes = global.appConfig?.starRefStartPrefixes; const starRefStartPrefixes = global.appConfig.starRefStartPrefixes;
let referrer = ref; let referrer = ref;
if (startParam && starRefStartPrefixes?.length) { if (startParam && starRefStartPrefixes?.length) {
const prefix = starRefStartPrefixes.find((p) => startParam.startsWith(p)); const prefix = starRefStartPrefixes.find((p) => startParam.startsWith(p));

View File

@ -34,7 +34,6 @@ import {
RE_TELEGRAM_LINK, RE_TELEGRAM_LINK,
SERVICE_NOTIFICATIONS_USER_ID, SERVICE_NOTIFICATIONS_USER_ID,
STARS_CURRENCY_CODE, STARS_CURRENCY_CODE,
STARS_SUGGESTED_POST_FUTURE_MIN,
SUPPORTED_AUDIO_CONTENT_TYPES, SUPPORTED_AUDIO_CONTENT_TYPES,
SUPPORTED_PHOTO_CONTENT_TYPES, SUPPORTED_PHOTO_CONTENT_TYPES,
SUPPORTED_VIDEO_CONTENT_TYPES, SUPPORTED_VIDEO_CONTENT_TYPES,
@ -834,7 +833,7 @@ addActionHandler('initDraftFromSuggestedMessage', (global, actions, payload): Ac
if (message.suggestedPostInfo) { if (message.suggestedPostInfo) {
const { scheduleDate, ...messageSuggestedPost } = message.suggestedPostInfo; const { scheduleDate, ...messageSuggestedPost } = message.suggestedPostInfo;
const now = getServerTime(); const now = getServerTime();
const futureMin = global.appConfig?.starsSuggestedPostFutureMin || STARS_SUGGESTED_POST_FUTURE_MIN; const futureMin = global.appConfig.starsSuggestedPostFutureMin;
const validScheduleDate = scheduleDate && scheduleDate > now + futureMin ? scheduleDate : undefined; const validScheduleDate = scheduleDate && scheduleDate > now + futureMin ? scheduleDate : undefined;
@ -2388,22 +2387,22 @@ addActionHandler('openUrl', (global, actions, payload): ActionReturnType => {
} }
const { appConfig, config } = global; const { appConfig, config } = global;
if (appConfig) { if (config?.autologinToken && appConfig.autologinDomains.includes(parsedUrl.hostname)) {
if (config?.autologinToken && appConfig.autologinDomains.includes(parsedUrl.hostname)) { parsedUrl.searchParams.set(AUTOLOGIN_TOKEN_KEY, config.autologinToken);
parsedUrl.searchParams.set(AUTOLOGIN_TOKEN_KEY, config.autologinToken); window.open(parsedUrl.href, '_blank', 'noopener');
window.open(parsedUrl.href, '_blank', 'noopener'); return;
return;
}
if (appConfig.urlAuthDomains.includes(parsedUrl.hostname)) {
actions.closeStoryViewer({ tabId });
actions.requestLinkUrlAuth({ url, tabId });
return;
}
} }
const shouldDisplayModal = !urlWithProtocol.match(RE_TELEGRAM_LINK) && !shouldSkipModal; if (appConfig.urlAuthDomains.includes(parsedUrl.hostname)) {
actions.closeStoryViewer({ tabId });
actions.requestLinkUrlAuth({ url, tabId });
return;
}
const isWhitelisted = appConfig.whitelistedDomains.includes(parsedUrl.hostname);
const shouldDisplayModal = !urlWithProtocol.match(RE_TELEGRAM_LINK) && !shouldSkipModal && !isWhitelisted;
if (shouldDisplayModal) { if (shouldDisplayModal) {
actions.toggleSafeLinkModal({ url: isMixedScript ? parsedUrl.toString() : urlWithProtocol, tabId }); actions.toggleSafeLinkModal({ url: isMixedScript ? parsedUrl.toString() : urlWithProtocol, tabId });

View File

@ -1213,7 +1213,7 @@ addActionHandler('processStarGiftWithdrawal', async (global, actions, payload):
return; return;
} }
actions.openUrl({ url: result.url, shouldSkipModal: true, tabId }); actions.openUrl({ url: result.url, tabId });
actions.closeGiftWithdrawModal({ tabId }); actions.closeGiftWithdrawModal({ tabId });
}); });

View File

@ -4,13 +4,13 @@ import type { ActionReturnType } from '../../types';
import { import {
DEFAULT_RESALE_GIFTS_FILTER_OPTIONS, DEFAULT_RESALE_GIFTS_FILTER_OPTIONS,
RESALE_GIFTS_LIMIT,
STARS_CURRENCY_CODE, STARS_CURRENCY_CODE,
TON_CURRENCY_CODE, TON_CURRENCY_CODE,
} from '../../../config'; } from '../../../config';
import { getCurrentTabId } from '../../../util/establishMultitabRole'; import { getCurrentTabId } from '../../../util/establishMultitabRole';
import { buildCollectionByKey } from '../../../util/iteratees'; import { buildCollectionByKey } from '../../../util/iteratees';
import { callApi } from '../../../api/gramjs'; import { callApi } from '../../../api/gramjs';
import { RESALE_GIFTS_LIMIT } from '../../../limits';
import { areInputSavedGiftsEqual, getRequestInputSavedStarGift } from '../../helpers/payments'; import { areInputSavedGiftsEqual, getRequestInputSavedStarGift } from '../../helpers/payments';
import { addActionHandler, getGlobal, setGlobal } from '../../index'; import { addActionHandler, getGlobal, setGlobal } from '../../index';
import { import {
@ -485,7 +485,7 @@ addActionHandler('toggleSavedGiftPinned', async (global, actions, payload): Prom
const savedGifts = selectPeerSavedGifts(global, peerId, tabId); const savedGifts = selectPeerSavedGifts(global, peerId, tabId);
if (!savedGifts) return; if (!savedGifts) return;
const pinLimit = global.appConfig?.savedGiftPinLimit; const pinLimit = global.appConfig.savedGiftPinLimit;
const currentPinnedGifts = savedGifts.gifts.filter((g) => g.isPinned); const currentPinnedGifts = savedGifts.gifts.filter((g) => g.isPinned);
const newPinnedGifts = gift.isPinned const newPinnedGifts = gift.isPinned
? currentPinnedGifts.filter((g) => (g.gift as ApiStarGiftUnique).slug !== (gift.gift as ApiStarGiftUnique).slug) ? currentPinnedGifts.filter((g) => (g.gift as ApiStarGiftUnique).slug !== (gift.gift as ApiStarGiftUnique).slug)

View File

@ -270,7 +270,6 @@ addActionHandler('processMonetizationRevenueWithdrawalUrl', async (global, actio
if ('url' in result) { if ('url' in result) {
actions.openUrl({ actions.openUrl({
url: result.url, url: result.url,
shouldSkipModal: true,
tabId, tabId,
ignoreDeepLinks: true, ignoreDeepLinks: true,
}); });

View File

@ -877,7 +877,7 @@ addActionHandler('processPremiumFloodWait', (global, actions, payload): ActionRe
bandwidthPremiumDownloadSpeedup, bandwidthPremiumDownloadSpeedup,
bandwidthPremiumUploadSpeedup, bandwidthPremiumUploadSpeedup,
bandwidthPremiumNotifyPeriod, bandwidthPremiumNotifyPeriod,
} = global.appConfig || {}; } = global.appConfig;
const { lastPremiumBandwithNotificationDate: lastNotifiedAt } = global.settings; const { lastPremiumBandwithNotificationDate: lastNotifiedAt } = global.settings;
if (!bandwidthPremiumDownloadSpeedup || !bandwidthPremiumUploadSpeedup || !bandwidthPremiumNotifyPeriod) { if (!bandwidthPremiumDownloadSpeedup || !bandwidthPremiumUploadSpeedup || !bandwidthPremiumNotifyPeriod) {

View File

@ -13,7 +13,6 @@ import {
ALL_FOLDER_ID, ANIMATION_LEVEL_DEFAULT, ALL_FOLDER_ID, ANIMATION_LEVEL_DEFAULT,
ARCHIVED_FOLDER_ID, ARCHIVED_FOLDER_ID,
DEBUG, DEBUG,
DEFAULT_LIMITS,
GLOBAL_STATE_CACHE_ARCHIVED_CHAT_LIST_LIMIT, GLOBAL_STATE_CACHE_ARCHIVED_CHAT_LIST_LIMIT,
GLOBAL_STATE_CACHE_CHAT_LIST_LIMIT, GLOBAL_STATE_CACHE_CHAT_LIST_LIMIT,
GLOBAL_STATE_CACHE_CUSTOM_EMOJI_LIMIT, GLOBAL_STATE_CACHE_CUSTOM_EMOJI_LIMIT,
@ -213,10 +212,6 @@ function unsafeMigrateCache(cached: GlobalState, initialState: GlobalState) {
...cached.chatFolders, ...cached.chatFolders,
}; };
if (cached.appConfig && !cached.appConfig.limits) {
cached.appConfig.limits = DEFAULT_LIMITS;
}
if (!cached.chats.similarChannelsById) { if (!cached.chats.similarChannelsById) {
cached.chats.similarChannelsById = initialState.chats.similarChannelsById; cached.chats.similarChannelsById = initialState.chats.similarChannelsById;
} }
@ -230,7 +225,7 @@ function unsafeMigrateCache(cached: GlobalState, initialState: GlobalState) {
} }
// Clear old color storage to optimize cache size // Clear old color storage to optimize cache size
if (untypedCached?.appConfig?.peerColors) { if (untypedCached?.appConfig.peerColors) {
untypedCached.appConfig.peerColors = undefined; untypedCached.appConfig.peerColors = undefined;
untypedCached.appConfig.darkPeerColors = undefined; untypedCached.appConfig.darkPeerColors = undefined;
} }
@ -309,9 +304,6 @@ function unsafeMigrateCache(cached: GlobalState, initialState: GlobalState) {
cached.cacheVersion = 2; cached.cacheVersion = 2;
} }
if (cached.appConfig?.limits && !cached.appConfig.limits.moreAccounts) {
cached.appConfig.limits.moreAccounts = DEFAULT_LIMITS.moreAccounts;
}
if (!cached.chats.notifyExceptionById) { if (!cached.chats.notifyExceptionById) {
cached.chats.notifyExceptionById = initialState.chats.notifyExceptionById; cached.chats.notifyExceptionById = initialState.chats.notifyExceptionById;
} }
@ -355,6 +347,10 @@ function unsafeMigrateCache(cached: GlobalState, initialState: GlobalState) {
cachedSharedSettings.animationLevel = ANIMATION_LEVEL_DEFAULT; cachedSharedSettings.animationLevel = ANIMATION_LEVEL_DEFAULT;
cachedSharedSettings.performance = INITIAL_PERFORMANCE_STATE_MED; cachedSharedSettings.performance = INITIAL_PERFORMANCE_STATE_MED;
} }
if (!cached.appConfig) {
cached.appConfig = initialState.appConfig;
}
} }
function updateCache(force?: boolean) { function updateCache(force?: boolean) {

View File

@ -5,11 +5,11 @@ import type {
} from '../../api/types'; } from '../../api/types';
import type { GlobalState } from '../types'; import type { GlobalState } from '../types';
import { DEFAULT_LIMITS } from '../../config';
import { isUserId } from '../../util/entities/ids'; import { isUserId } from '../../util/entities/ids';
import { partition } from '../../util/iteratees'; import { partition } from '../../util/iteratees';
import { clamp } from '../../util/math'; import { clamp } from '../../util/math';
import { getAccountsInfo } from '../../util/multiaccount'; import { getAccountsInfo } from '../../util/multiaccount';
import { DEFAULT_LIMITS } from '../../limits';
import { getGlobal } from '..'; import { getGlobal } from '..';
export function buildApiInputPrivacyRules(global: GlobalState, { export function buildApiInputPrivacyRules(global: GlobalState, {
@ -51,7 +51,7 @@ export function buildApiInputPrivacyRules(global: GlobalState, {
export function getCurrentMaxAccountCount() { export function getCurrentMaxAccountCount() {
const global = getGlobal(); const global = getGlobal();
const limit = global.appConfig?.limits?.moreAccounts || DEFAULT_LIMITS.moreAccounts; const limit = global.appConfig.limits?.moreAccounts || DEFAULT_LIMITS.moreAccounts;
const accounts = getAccountsInfo(); const accounts = getAccountsInfo();
const premiumCount = Object.values(accounts).filter((account) => account.isPremium).length; const premiumCount = Object.values(accounts).filter((account) => account.isPremium).length;
// Each premium account increases the base limit by 1, up to the maximum limit. // Each premium account increases the base limit by 1, up to the maximum limit.

View File

@ -15,6 +15,7 @@ import {
MACOS_DEFAULT_MESSAGE_TEXT_SIZE_PX, MACOS_DEFAULT_MESSAGE_TEXT_SIZE_PX,
} from '../config'; } from '../config';
import { IS_IOS, IS_MAC_OS } from '../util/browser/windowEnvironment'; import { IS_IOS, IS_MAC_OS } from '../util/browser/windowEnvironment';
import { DEFAULT_APP_CONFIG } from '../limits';
export const INITIAL_PERFORMANCE_STATE_MAX: PerformanceType = { export const INITIAL_PERFORMANCE_STATE_MAX: PerformanceType = {
animatedEmoji: true, animatedEmoji: true,
@ -101,6 +102,7 @@ export const INITIAL_GLOBAL_STATE: GlobalState = {
isAppUpdateAvailable: false, isAppUpdateAvailable: false,
isElectronUpdateAvailable: false, isElectronUpdateAvailable: false,
shouldShowContextMenuHint: true, shouldShowContextMenuHint: true,
appConfig: DEFAULT_APP_CONFIG,
audioPlayer: { audioPlayer: {
lastPlaybackRate: DEFAULT_PLAYBACK_RATE, lastPlaybackRate: DEFAULT_PLAYBACK_RATE,

View File

@ -107,7 +107,7 @@ export function addStoriesForPeer<T extends GlobalState>(
if (selectIsChatWithSelf(global, peerId) if (selectIsChatWithSelf(global, peerId)
|| selectUser(global, peerId)?.isContact || selectUser(global, peerId)?.isContact
|| peerId === global.appConfig?.storyChangelogUserId) { || peerId === global.appConfig.storyChangelogUserId) {
global = updatePeerLastUpdatedAt(global, peerId); global = updatePeerLastUpdatedAt(global, peerId);
global = updateOrderedStoriesPeerIds(global, [peerId]); global = updateOrderedStoriesPeerIds(global, [peerId]);
} }

View File

@ -1,17 +1,14 @@
import type { ApiLimitType } from '../../api/types'; import type { ApiLimitType } from '../../api/types';
import type { GlobalState } from '../types'; import type { GlobalState } from '../types';
import { DEFAULT_LIMITS } from '../../config'; import { DEFAULT_LIMITS } from '../../limits';
import { selectIsCurrentUserPremium } from './users'; import { selectIsCurrentUserPremium } from './users';
export function selectCurrentLimit<T extends GlobalState>(global: T, limit: ApiLimitType) { export function selectCurrentLimit<T extends GlobalState>(global: T, limit: ApiLimitType) {
const { appConfig } = global; const { appConfig } = global;
if (!appConfig) { const { limits } = appConfig;
return DEFAULT_LIMITS[limit][0];
}
const isPremium = selectIsCurrentUserPremium(global); const isPremium = selectIsCurrentUserPremium(global);
const { limits } = appConfig;
// When there are new limits when updating a layer, until we get a new configuration, we must use the default values // When there are new limits when updating a layer, until we get a new configuration, we must use the default values
const value = limits[limit]?.[isPremium ? 1 : 0] ?? DEFAULT_LIMITS[limit][isPremium ? 1 : 0]; const value = limits[limit]?.[isPremium ? 1 : 0] ?? DEFAULT_LIMITS[limit][isPremium ? 1 : 0];

View File

@ -23,7 +23,7 @@ import type {
import { ApiMessageEntityTypes, MAIN_THREAD_ID } from '../../api/types'; import { ApiMessageEntityTypes, MAIN_THREAD_ID } from '../../api/types';
import { import {
ANONYMOUS_USER_ID, API_GENERAL_ID_LIMIT, GENERAL_TOPIC_ID, SERVICE_NOTIFICATIONS_USER_ID, ANONYMOUS_USER_ID, GENERAL_TOPIC_ID, SERVICE_NOTIFICATIONS_USER_ID,
SVG_EXTENSIONS, WEB_APP_PLATFORM, SVG_EXTENSIONS, WEB_APP_PLATFORM,
} from '../../config'; } from '../../config';
import { IS_TRANSLATION_SUPPORTED } from '../../util/browser/windowEnvironment'; import { IS_TRANSLATION_SUPPORTED } from '../../util/browser/windowEnvironment';
@ -34,6 +34,7 @@ import { getMessageKey, isLocalMessageId } from '../../util/keys/messageKey';
import { MEMO_EMPTY_ARRAY } from '../../util/memo'; import { MEMO_EMPTY_ARRAY } from '../../util/memo';
import { getServerTime } from '../../util/serverTime'; import { getServerTime } from '../../util/serverTime';
import { getDocumentExtension } from '../../components/common/helpers/documentInfo'; import { getDocumentExtension } from '../../components/common/helpers/documentInfo';
import { API_GENERAL_ID_LIMIT } from '../../limits';
import { import {
canSendReaction, canSendReaction,
getAllowedAttachmentOptions, getAllowedAttachmentOptions,
@ -77,13 +78,14 @@ import {
selectIsChatWithSelf, selectIsChatWithSelf,
selectRequestedChatTranslationLanguage, selectRequestedChatTranslationLanguage,
} from './chats'; } from './chats';
import { selectCurrentLimit } from './limits';
import { selectPeer, selectPeerPaidMessagesStars } from './peers'; import { selectPeer, selectPeerPaidMessagesStars } from './peers';
import { selectPeerStory } from './stories'; import { selectPeerStory } from './stories';
import { selectIsStickerFavorite } from './symbols'; import { selectIsStickerFavorite } from './symbols';
import { selectTabState } from './tabs'; import { selectTabState } from './tabs';
import { selectTopic } from './topics'; import { selectTopic } from './topics';
import { import {
selectBot, selectIsCurrentUserPremium, selectUser, selectUserStatus, selectBot, selectUser, selectUserStatus,
} from './users'; } from './users';
export function selectCurrentMessageList<T extends GlobalState>( export function selectCurrentMessageList<T extends GlobalState>(
@ -1349,9 +1351,7 @@ export function selectDefaultReaction<T extends GlobalState>(global: T, chatId:
} }
export function selectMaxUserReactions<T extends GlobalState>(global: T): number { export function selectMaxUserReactions<T extends GlobalState>(global: T): number {
const isPremium = selectIsCurrentUserPremium(global); return selectCurrentLimit(global, 'maxReactions');
const { maxUserReactionsPremium = 3, maxUserReactionsDefault = 1 } = global.appConfig || {};
return isPremium ? maxUserReactionsPremium : maxUserReactionsDefault;
} }
// Slow, not to be used in `withGlobal` // Slow, not to be used in `withGlobal`
@ -1580,7 +1580,7 @@ export function selectActiveRestrictionReasons<T extends GlobalState>(
): ApiRestrictionReason[] { ): ApiRestrictionReason[] {
if (!restrictionReasons) return []; if (!restrictionReasons) return [];
const { ignoreRestrictionReasons } = global.appConfig || {}; const { ignoreRestrictionReasons } = global.appConfig;
return restrictionReasons.filter((reason) => { return restrictionReasons.filter((reason) => {
const isForCurrentPlatform = reason.platform === 'all' || reason.platform === WEB_APP_PLATFORM; const isForCurrentPlatform = reason.platform === 'all' || reason.platform === WEB_APP_PLATFORM;

View File

@ -167,14 +167,14 @@ export function selectAnimatedEmojiEffect<T extends GlobalState>(global: T, emoj
} }
export function selectAnimatedEmojiSound<T extends GlobalState>(global: T, emoji: string) { export function selectAnimatedEmojiSound<T extends GlobalState>(global: T, emoji: string) {
return global?.appConfig?.emojiSounds[cleanEmoji(emoji)]; return global?.appConfig.emojiSounds[cleanEmoji(emoji)];
} }
export function selectIsAlwaysHighPriorityEmoji<T extends GlobalState>( export function selectIsAlwaysHighPriorityEmoji<T extends GlobalState>(
global: T, stickerSet: ApiStickerSetInfo | ApiStickerSet, global: T, stickerSet: ApiStickerSetInfo | ApiStickerSet,
) { ) {
if (!('id' in stickerSet)) return false; if (!('id' in stickerSet)) return false;
return stickerSet.id === global.appConfig?.defaultEmojiStatusesStickerSetId return stickerSet.id === global.appConfig.defaultEmojiStatusesStickerSetId
|| stickerSet.id === RESTRICTED_EMOJI_SET_ID; || stickerSet.id === RESTRICTED_EMOJI_SET_ID;
} }

View File

@ -36,15 +36,15 @@ export function selectIsCurrentUserPremium<T extends GlobalState>(global: T) {
} }
export function selectIsCurrentUserFrozen<T extends GlobalState>(global: T) { export function selectIsCurrentUserFrozen<T extends GlobalState>(global: T) {
return Boolean(global.appConfig?.freezeUntilDate); return Boolean(global.appConfig.freezeUntilDate);
} }
export function selectIsPremiumPurchaseBlocked<T extends GlobalState>(global: T) { export function selectIsPremiumPurchaseBlocked<T extends GlobalState>(global: T) {
return global.appConfig?.isPremiumPurchaseBlocked ?? true; return global.appConfig.isPremiumPurchaseBlocked ?? true;
} }
export function selectIsGiveawayGiftsPurchaseAvailable<T extends GlobalState>(global: T) { export function selectIsGiveawayGiftsPurchaseAvailable<T extends GlobalState>(global: T) {
return global.appConfig?.isGiveawayGiftsPurchaseAvailable ?? true; return global.appConfig.isGiveawayGiftsPurchaseAvailable ?? true;
} }
/** /**

View File

@ -76,7 +76,7 @@ export type GlobalState = {
cacheVersion: number; cacheVersion: number;
isInited: boolean; isInited: boolean;
config?: ApiConfig; config?: ApiConfig;
appConfig?: ApiAppConfig; appConfig: ApiAppConfig;
peerColors?: ApiPeerColors; peerColors?: ApiPeerColors;
timezones?: { timezones?: {
byId: Record<string, ApiTimezone>; byId: Record<string, ApiTimezone>;

161
src/limits.ts Normal file
View File

@ -0,0 +1,161 @@
import type { ApiAppConfig, ApiLimitType } from './api/types';
import { MULTIACCOUNT_MAX_SLOTS } from './config';
export const MAX_UNIQUE_REACTIONS = 11;
export const GROUP_CALL_PARTICIPANTS_LIMIT = 100;
export const STORY_LIST_LIMIT = 100;
export const API_GENERAL_ID_LIMIT = 100;
export const RESALE_GIFTS_LIMIT = 50;
export const PINNED_MESSAGES_LIMIT = 50;
export const BLOCKED_LIST_LIMIT = 100;
export const GLOBAL_SEARCH_CONTACTS_LIMIT = 20;
// As in Telegram for Android
// https://github.com/DrKLO/Telegram/blob/51e9947527/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java#L7799
export const TOP_REACTIONS_LIMIT = 100;
export const RECENT_REACTIONS_LIMIT = 50;
export const REACTION_LIST_LIMIT = 100;
export const DEFAULT_LIMITS: Record<ApiLimitType, readonly [number, number]> = {
uploadMaxFileparts: [4000, 8000],
stickersFaved: [5, 10],
savedGifs: [200, 400],
dialogFiltersChats: [100, 200],
dialogFilters: [10, 20],
dialogFolderPinned: [5, 10],
captionLength: [1024, 4096],
channels: [500, 1000],
channelsPublic: [10, 20],
aboutLength: [70, 140],
chatlistInvites: [3, 100],
chatlistJoined: [2, 20],
recommendedChannels: [10, 100],
savedDialogsPinned: [5, 100],
maxReactions: [1, 3],
moreAccounts: [3, MULTIACCOUNT_MAX_SLOTS],
};
export const DEFAULT_MAX_MESSAGE_LENGTH = 4096;
export const DEFAULT_APP_CONFIG: ApiAppConfig = {
hash: 0,
limits: {
uploadMaxFileparts: DEFAULT_LIMITS.uploadMaxFileparts,
stickersFaved: DEFAULT_LIMITS.stickersFaved,
savedGifs: DEFAULT_LIMITS.savedGifs,
dialogFiltersChats: DEFAULT_LIMITS.dialogFiltersChats,
dialogFilters: DEFAULT_LIMITS.dialogFilters,
dialogFolderPinned: DEFAULT_LIMITS.dialogFolderPinned,
captionLength: DEFAULT_LIMITS.captionLength,
channels: DEFAULT_LIMITS.channels,
channelsPublic: DEFAULT_LIMITS.channelsPublic,
aboutLength: DEFAULT_LIMITS.aboutLength,
chatlistInvites: DEFAULT_LIMITS.chatlistInvites,
chatlistJoined: DEFAULT_LIMITS.chatlistJoined,
recommendedChannels: DEFAULT_LIMITS.recommendedChannels,
savedDialogsPinned: DEFAULT_LIMITS.savedDialogsPinned,
moreAccounts: DEFAULT_LIMITS.moreAccounts,
maxReactions: DEFAULT_LIMITS.maxReactions,
},
canDisplayAutoarchiveSetting: true,
autologinDomains: [
'instantview.telegram.org',
'translations.telegram.org',
'contest.dev',
'contest.com',
'bugs.telegram.org',
'suggestions.telegram.org',
'themes.telegram.org',
'promote.telegram.org',
'ads.telegram.org',
],
channelLevelMax: 100,
boostsPerSentGift: 3,
channelRestrictAdsLevelMin: 50,
seenByExpiresAt: 604800,
seenByMaxChatMembers: 100,
defaultEmojiStatusesStickerSetId: '773947703670341676',
emojiSounds: {},
giveawayAddPeersMax: 10,
giveawayBoostsPerPremium: 4,
giveawayCountriesMax: 10,
isGiveawayGiftsPurchaseAvailable: false,
groupTranscribeLevelMin: 6,
hiddenMembersMinCount: 100,
ignoreRestrictionReasons: [],
canLimitNewMessagesWithoutPremium: false,
readDateExpiresAt: 604800,
premiumBotUsername: 'PremiumBot',
premiumInvoiceSlug: 'abc',
premiumPromoOrder: [
'stories',
'more_upload',
'double_limits',
// 'business',
'last_seen',
'voice_to_text',
'faster_download',
'translations',
'animated_emoji',
'emoji_status',
'saved_tags',
// 'peer_colors',
// 'wallpapers',
'profile_badge',
'message_privacy',
'advanced_chat_management',
'no_ads',
// 'app_icons',
'infinite_reactions',
'animated_userpics',
'premium_stickers',
'effects',
],
isPremiumPurchaseBlocked: false,
maxUniqueReactions: 11,
starGiftMaxConvertPeriod: 7776000,
starGiftMaxMessageLength: 255,
starRefStartPrefixes: [
'_tgr_',
],
isStarsGiftEnabled: true,
paidReactionMaxAmount: 2500,
starsUsdWithdrawRateX1000: 1300,
storyChangelogUserId: '777000',
maxPinnedStoriesCount: 3,
starsSuggestedPostAmountMax: 100000,
starsSuggestedPostAmountMin: 5,
starsSuggestedPostAgeMin: 86400,
starsSuggestedPostFutureMin: 300,
starsSuggestedPostFutureMax: 2678400,
starsSuggestedPostCommissionPermille: 850,
tonSuggestedPostCommissionPermille: 850,
todoItemLengthMax: 64,
todoItemsMax: 30,
todoTitleLengthMax: 32,
tonSuggestedPostAmountMax: 10000000000000,
tonSuggestedPostAmountMin: 10000000,
tonTopupUrl: 'https://fragment.com/ads/topup',
storyViewersExpirePeriod: 86400,
topicsPinnedLimit: 5,
bandwidthPremiumDownloadSpeedup: 10,
bandwidthPremiumNotifyPeriod: 3600,
bandwidthPremiumUploadSpeedup: 10,
urlAuthDomains: [
'web.telegram.org',
'web.t.me',
'k.t.me',
'z.t.me',
'a.t.me',
],
whitelistedDomains: [
'telegram.dog',
'telegram.me',
'telegram.org',
't.me',
'telesco.pe',
'fragment.com',
'translations.telegram.org',
],
};