Verification: Support bot verification (#5396)
Co-authored-by: Alexander Zinchuk <alx.zinchuk@gmail.com>
This commit is contained in:
parent
683384074a
commit
1e68ce4da7
@ -27,7 +27,7 @@ import { pick, pickTruthy } from '../../../util/iteratees';
|
||||
import { getServerTime, getServerTimeOffset } from '../../../util/serverTime';
|
||||
import { addPhotoToLocalDb, addUserToLocalDb, serializeBytes } from '../helpers';
|
||||
import {
|
||||
buildApiFormattedText, buildApiPhoto, buildApiUsernames, buildAvatarPhotoId,
|
||||
buildApiBotVerification, buildApiFormattedText, buildApiPhoto, buildApiUsernames, buildAvatarPhotoId,
|
||||
} from './common';
|
||||
import { omitVirtualClassFields } from './helpers';
|
||||
import {
|
||||
@ -65,6 +65,8 @@ function buildApiChatFieldsFromPeerEntity(
|
||||
const isForum = Boolean('forum' in peerEntity && peerEntity.forum);
|
||||
const areStoriesHidden = Boolean('storiesHidden' in peerEntity && peerEntity.storiesHidden);
|
||||
const maxStoryId = 'storiesMaxId' in peerEntity ? peerEntity.storiesMaxId : undefined;
|
||||
const botVerificationIconId = 'botVerificationIconId' in peerEntity
|
||||
? peerEntity.botVerificationIconId?.toString() : undefined;
|
||||
const storiesUnavailable = Boolean('storiesUnavailable' in peerEntity && peerEntity.storiesUnavailable);
|
||||
const color = ('color' in peerEntity && peerEntity.color) ? buildApiPeerColor(peerEntity.color) : undefined;
|
||||
const emojiStatus = ('emojiStatus' in peerEntity && peerEntity.emojiStatus)
|
||||
@ -105,6 +107,7 @@ function buildApiChatFieldsFromPeerEntity(
|
||||
hasStories: Boolean(maxStoryId) && !storiesUnavailable,
|
||||
emojiStatus,
|
||||
boostLevel,
|
||||
botVerificationIconId,
|
||||
subscriptionUntil,
|
||||
};
|
||||
}
|
||||
@ -685,7 +688,7 @@ export function buildApiSponsoredMessageReportResult(
|
||||
export function buildApiChatInviteInfo(invite: GramJs.ChatInvite): ApiChatInviteInfo {
|
||||
const {
|
||||
color, participants, participantsCount, photo, title, about, scam, fake, verified, megagroup, channel, broadcast,
|
||||
requestNeeded, subscriptionFormId, subscriptionPricing, canRefulfillSubscription,
|
||||
requestNeeded, subscriptionFormId, subscriptionPricing, canRefulfillSubscription, botVerification,
|
||||
} = invite;
|
||||
|
||||
let apiPhoto;
|
||||
@ -714,6 +717,7 @@ export function buildApiChatInviteInfo(invite: GramJs.ChatInvite): ApiChatInvite
|
||||
subscriptionPricing: subscriptionPricing && buildApiStarsSubscriptionPricing(subscriptionPricing),
|
||||
canRefulfillSubscription,
|
||||
participantIds: participants?.map((participant) => buildApiPeerId(participant.id, 'user')).filter(Boolean),
|
||||
botVerification: botVerification && buildApiBotVerification(botVerification),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@ import { Api as GramJs } from '../../../lib/gramjs';
|
||||
import { strippedPhotoToJpg } from '../../../lib/gramjs/Utils';
|
||||
|
||||
import type {
|
||||
ApiBotVerification,
|
||||
ApiFormattedText,
|
||||
ApiMessageEntity,
|
||||
ApiMessageEntityDefault,
|
||||
@ -299,3 +300,11 @@ export function buildAvatarPhotoId(photo: GramJs.TypeUserProfilePhoto | GramJs.T
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function buildApiBotVerification(botVerification: GramJs.BotVerification): ApiBotVerification {
|
||||
return {
|
||||
botId: buildApiPeerId(botVerification.botId, 'user'),
|
||||
iconId: botVerification.icon.toString(),
|
||||
description: botVerification.description,
|
||||
};
|
||||
}
|
||||
|
||||
@ -11,7 +11,9 @@ import type {
|
||||
|
||||
import { buildApiBotInfo } from './bots';
|
||||
import { buildApiBusinessIntro, buildApiBusinessLocation, buildApiBusinessWorkHours } from './business';
|
||||
import { buildApiPhoto, buildApiUsernames, buildAvatarPhotoId } from './common';
|
||||
import {
|
||||
buildApiBotVerification, buildApiPhoto, buildApiUsernames, buildAvatarPhotoId,
|
||||
} from './common';
|
||||
import { omitVirtualClassFields } from './helpers';
|
||||
import { buildApiEmojiStatus, buildApiPeerColor, buildApiPeerId } from './peers';
|
||||
|
||||
@ -22,7 +24,7 @@ export function buildApiUserFullInfo(mtpUserFull: GramJs.users.UserFull): ApiUse
|
||||
profilePhoto, voiceMessagesForbidden, premiumGifts, hasScheduled,
|
||||
fallbackPhoto, personalPhoto, translationsDisabled, storiesPinnedAvailable,
|
||||
contactRequirePremium, businessWorkHours, businessLocation, businessIntro,
|
||||
birthday, personalChannelId, personalChannelMessage, sponsoredEnabled, stargiftsCount,
|
||||
birthday, personalChannelId, personalChannelMessage, sponsoredEnabled, stargiftsCount, botVerification,
|
||||
},
|
||||
users,
|
||||
} = mtpUserFull;
|
||||
@ -49,6 +51,7 @@ export function buildApiUserFullInfo(mtpUserFull: GramJs.users.UserFull): ApiUse
|
||||
businessIntro: businessIntro && buildApiBusinessIntro(businessIntro),
|
||||
personalChannelId: personalChannelId && buildApiPeerId(personalChannelId, 'channel'),
|
||||
personalChannelMessageId: personalChannelMessage,
|
||||
botVerification: botVerification && buildApiBotVerification(botVerification),
|
||||
areAdsEnabled: sponsoredEnabled,
|
||||
starGiftCount: stargiftsCount,
|
||||
hasScheduledMessages: hasScheduled,
|
||||
@ -62,7 +65,7 @@ export function buildApiUser(mtpUser: GramJs.TypeUser): ApiUser | undefined {
|
||||
|
||||
const {
|
||||
id, firstName, lastName, fake, scam, support, closeFriend, storiesUnavailable, storiesMaxId,
|
||||
bot, botActiveUsers, botInlinePlaceholder, botAttachMenu, botCanEdit,
|
||||
bot, botActiveUsers, botVerificationIcon, botInlinePlaceholder, botAttachMenu, botCanEdit,
|
||||
} = mtpUser;
|
||||
const hasVideoAvatar = mtpUser.photo instanceof GramJs.UserProfilePhoto ? Boolean(mtpUser.photo.hasVideo) : undefined;
|
||||
const avatarPhotoId = mtpUser.photo && buildAvatarPhotoId(mtpUser.photo);
|
||||
@ -99,6 +102,7 @@ export function buildApiUser(mtpUser: GramJs.TypeUser): ApiUser | undefined {
|
||||
...(bot && botInlinePlaceholder && { botPlaceholder: botInlinePlaceholder }),
|
||||
...(bot && botAttachMenu && { isAttachBot: botAttachMenu }),
|
||||
botActiveUsers,
|
||||
botVerificationIconId: botVerificationIcon?.toString(),
|
||||
color: mtpUser.color && buildApiPeerColor(mtpUser.color),
|
||||
};
|
||||
}
|
||||
|
||||
@ -49,7 +49,7 @@ import {
|
||||
buildChatMembers,
|
||||
getPeerKey,
|
||||
} from '../apiBuilders/chats';
|
||||
import { buildApiPhoto } from '../apiBuilders/common';
|
||||
import { buildApiBotVerification, buildApiPhoto } from '../apiBuilders/common';
|
||||
import { buildApiMessage, buildMessageDraft } from '../apiBuilders/messages';
|
||||
import { buildApiPeerId, getApiChatIdFromMtpPeer } from '../apiBuilders/peers';
|
||||
import { buildStickerSet } from '../apiBuilders/symbols';
|
||||
@ -603,6 +603,7 @@ async function getFullChannelInfo(
|
||||
emojiset,
|
||||
boostsApplied,
|
||||
boostsUnrestrict,
|
||||
botVerification,
|
||||
canViewRevenue: canViewMonetization,
|
||||
paidReactionsAvailable,
|
||||
hasScheduled,
|
||||
@ -695,6 +696,7 @@ async function getFullChannelInfo(
|
||||
hasPinnedStories: Boolean(storiesPinnedAvailable),
|
||||
boostsApplied,
|
||||
boostsToUnrestrict: boostsUnrestrict,
|
||||
botVerification: botVerification && buildApiBotVerification(botVerification),
|
||||
isPaidReactionAvailable: paidReactionsAvailable,
|
||||
hasScheduledMessages: hasScheduled,
|
||||
},
|
||||
|
||||
@ -2,7 +2,7 @@ import type { ApiBotCommand } from './bots';
|
||||
import type {
|
||||
ApiChatReactions, ApiFormattedText, ApiInputMessageReplyInfo, ApiPhoto, ApiStickerSet,
|
||||
} from './messages';
|
||||
import type { ApiChatInviteImporter } from './misc';
|
||||
import type { ApiBotVerification, ApiChatInviteImporter } from './misc';
|
||||
import type {
|
||||
ApiEmojiStatus, ApiFakeType, ApiUser, ApiUsername,
|
||||
} from './users';
|
||||
@ -48,6 +48,7 @@ export interface ApiChat {
|
||||
isForum?: boolean;
|
||||
isForumAsMessages?: true;
|
||||
boostLevel?: number;
|
||||
botVerificationIconId?: string;
|
||||
|
||||
// Calls
|
||||
isCallActive?: boolean;
|
||||
@ -143,6 +144,7 @@ export interface ApiChatFullInfo {
|
||||
|
||||
boostsApplied?: number;
|
||||
boostsToUnrestrict?: number;
|
||||
botVerification?: ApiBotVerification;
|
||||
}
|
||||
|
||||
export interface ApiChatMember {
|
||||
|
||||
@ -175,6 +175,7 @@ export type ApiChatInviteInfo = {
|
||||
subscriptionFormId?: string;
|
||||
canRefulfillSubscription?: boolean;
|
||||
subscriptionPricing?: ApiStarsSubscriptionPricing;
|
||||
botVerification?: ApiBotVerification;
|
||||
};
|
||||
|
||||
export type ApiChatInviteImporter = {
|
||||
@ -321,6 +322,12 @@ export interface ApiPeerPhotos {
|
||||
isLoading?: boolean;
|
||||
}
|
||||
|
||||
export interface ApiBotVerification {
|
||||
botId: string;
|
||||
iconId: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export type ApiLimitType =
|
||||
| 'uploadMaxFileparts'
|
||||
| 'stickersFaved'
|
||||
|
||||
@ -3,6 +3,7 @@ import type { ApiBotInfo } from './bots';
|
||||
import type { ApiBusinessIntro, ApiBusinessLocation, ApiBusinessWorkHours } from './business';
|
||||
import type { ApiPeerColor } from './chats';
|
||||
import type { ApiDocument, ApiPhoto } from './messages';
|
||||
import type { ApiBotVerification } from './misc';
|
||||
import type { ApiUserStarGift } from './payments';
|
||||
|
||||
export interface ApiUser {
|
||||
@ -36,6 +37,7 @@ export interface ApiUser {
|
||||
canEditBot?: boolean;
|
||||
hasMainMiniApp?: boolean;
|
||||
botActiveUsers?: number;
|
||||
botVerificationIconId?: string;
|
||||
}
|
||||
|
||||
export interface ApiUserFullInfo {
|
||||
@ -61,6 +63,7 @@ export interface ApiUserFullInfo {
|
||||
businessIntro?: ApiBusinessIntro;
|
||||
starGiftCount?: number;
|
||||
hasScheduledMessages?: boolean;
|
||||
botVerification?: ApiBotVerification;
|
||||
}
|
||||
|
||||
export type ApiFakeType = 'fake' | 'scam';
|
||||
|
||||
@ -107,9 +107,18 @@ const FullNameTitle: FC<OwnProps> = ({
|
||||
|
||||
return undefined;
|
||||
}, [customPeer, isSavedDialog, isSavedMessages, lang, realPeer]);
|
||||
const botVerificationIconId = realPeer?.botVerificationIconId;
|
||||
|
||||
return (
|
||||
<div className={buildClassName('title', styles.root, className)}>
|
||||
{botVerificationIconId && (
|
||||
<CustomEmoji
|
||||
documentId={botVerificationIconId}
|
||||
size={emojiStatusSize}
|
||||
loopLimit={!noLoopLimit ? EMOJI_STATUS_LOOP_LIMIT : undefined}
|
||||
observeIntersectionForLoading={observeIntersection}
|
||||
/>
|
||||
)}
|
||||
<h3
|
||||
dir="auto"
|
||||
role="button"
|
||||
|
||||
@ -24,11 +24,21 @@
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.botVerificationSection,
|
||||
.sectionInfo {
|
||||
color: var(--color-text-secondary);
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.botVerificationSection {
|
||||
padding-inline: 1.25rem;
|
||||
}
|
||||
|
||||
.botVerificationIcon {
|
||||
--custom-emoji-size: 1rem;
|
||||
padding-inline-end: 0.125rem;
|
||||
}
|
||||
|
||||
.personalChannelSubscribers {
|
||||
grid-column: 2;
|
||||
grid-row: 1;
|
||||
|
||||
@ -5,6 +5,7 @@ import React, {
|
||||
import { getActions, withGlobal } from '../../../global';
|
||||
|
||||
import type {
|
||||
ApiBotVerification,
|
||||
ApiChat, ApiCountryCode, ApiUser, ApiUserFullInfo, ApiUsername,
|
||||
} from '../../../api/types';
|
||||
import { MAIN_THREAD_ID } from '../../../api/types';
|
||||
@ -49,6 +50,7 @@ import Button from '../../ui/Button';
|
||||
import ListItem from '../../ui/ListItem';
|
||||
import Skeleton from '../../ui/placeholder/Skeleton';
|
||||
import Switcher from '../../ui/Switcher';
|
||||
import CustomEmoji from '../CustomEmoji';
|
||||
import SafeLink from '../SafeLink';
|
||||
import BusinessHours from './BusinessHours';
|
||||
import UserBirthday from './UserBirthday';
|
||||
@ -75,6 +77,7 @@ type StateProps = {
|
||||
hasSavedMessages?: boolean;
|
||||
personalChannel?: ApiChat;
|
||||
hasMainMiniApp?: boolean;
|
||||
botVerification?: ApiBotVerification;
|
||||
};
|
||||
|
||||
const DEFAULT_MAP_CONFIG = {
|
||||
@ -84,6 +87,7 @@ const DEFAULT_MAP_CONFIG = {
|
||||
};
|
||||
|
||||
const runDebounced = debounce((cb) => cb(), 500, false);
|
||||
const BOT_VERIFICATION_ICON_SIZE = 16;
|
||||
|
||||
const ChatExtra: FC<OwnProps & StateProps> = ({
|
||||
chatOrUserId,
|
||||
@ -101,6 +105,7 @@ const ChatExtra: FC<OwnProps & StateProps> = ({
|
||||
hasSavedMessages,
|
||||
personalChannel,
|
||||
hasMainMiniApp,
|
||||
botVerification,
|
||||
}) => {
|
||||
const {
|
||||
showNotification,
|
||||
@ -437,6 +442,16 @@ const ChatExtra: FC<OwnProps & StateProps> = ({
|
||||
<span>{oldLang('SavedMessagesTab')}</span>
|
||||
</ListItem>
|
||||
)}
|
||||
{botVerification && (
|
||||
<div className={styles.botVerificationSection}>
|
||||
<CustomEmoji
|
||||
className={styles.botVerificationIcon}
|
||||
documentId={botVerification.iconId}
|
||||
size={BOT_VERIFICATION_ICON_SIZE}
|
||||
/>
|
||||
{botVerification.description}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@ -455,6 +470,8 @@ export default memo(withGlobal<OwnProps>(
|
||||
const chatFullInfo = chat && selectChatFullInfo(global, chat.id);
|
||||
const userFullInfo = user && selectUserFullInfo(global, user.id);
|
||||
|
||||
const botVerification = userFullInfo?.botVerification || chatFullInfo?.botVerification;
|
||||
|
||||
const chatInviteLink = chatFullInfo?.inviteLink;
|
||||
|
||||
const description = userFullInfo?.bio || chatFullInfo?.about;
|
||||
@ -488,6 +505,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
hasSavedMessages,
|
||||
personalChannel,
|
||||
hasMainMiniApp,
|
||||
botVerification,
|
||||
};
|
||||
},
|
||||
)(ChatExtra));
|
||||
|
||||
@ -22,6 +22,7 @@ import { applyAnimationState, type PaneState } from './hooks/useHeaderPane';
|
||||
import GroupCallTopPane from '../calls/group/GroupCallTopPane';
|
||||
import AudioPlayer from './panes/AudioPlayer';
|
||||
import BotAdPane from './panes/BotAdPane';
|
||||
import BotVerificationPane from './panes/BotVerificationPane';
|
||||
import ChatReportPane from './panes/ChatReportPane';
|
||||
import HeaderPinnedMessage from './panes/HeaderPinnedMessage';
|
||||
|
||||
@ -65,6 +66,7 @@ const MiddleHeaderPanes = ({
|
||||
const [getGroupCallState, setGroupCallState] = useSignal<PaneState>(FALLBACK_PANE_STATE);
|
||||
const [getChatReportState, setChatReportState] = useSignal<PaneState>(FALLBACK_PANE_STATE);
|
||||
const [getBotAdState, setBotAdState] = useSignal<PaneState>(FALLBACK_PANE_STATE);
|
||||
const [getBotVerificationState, setBotVerificationState] = useSignal<PaneState>(FALLBACK_PANE_STATE);
|
||||
|
||||
const isPinnedMessagesFullWidth = isAudioPlayerRendered || !isDesktop;
|
||||
|
||||
@ -84,13 +86,15 @@ const MiddleHeaderPanes = ({
|
||||
|
||||
useSignalEffect(() => {
|
||||
const audioPlayerState = getAudioPlayerState();
|
||||
const botVerificationState = getBotVerificationState();
|
||||
const pinnedState = getPinnedState();
|
||||
const groupCallState = getGroupCallState();
|
||||
const chatReportState = getChatReportState();
|
||||
const botAdState = getBotAdState();
|
||||
|
||||
// Keep in sync with the order of the panes in the DOM
|
||||
const stateArray = [audioPlayerState, groupCallState, chatReportState, pinnedState, botAdState];
|
||||
const stateArray = [audioPlayerState, groupCallState,
|
||||
chatReportState, botVerificationState, pinnedState, botAdState];
|
||||
|
||||
const isFirstRender = isFirstRenderRef.current;
|
||||
const totalHeight = stateArray.reduce((acc, state) => acc + state.height, 0);
|
||||
@ -103,7 +107,8 @@ const MiddleHeaderPanes = ({
|
||||
setExtraStyles(middleColumn, {
|
||||
'--middle-header-panes-height': `${totalHeight}px`,
|
||||
});
|
||||
}, [getAudioPlayerState, getGroupCallState, getPinnedState, getChatReportState, getBotAdState]);
|
||||
}, [getAudioPlayerState, getGroupCallState, getPinnedState,
|
||||
getChatReportState, getBotAdState, getBotVerificationState]);
|
||||
|
||||
if (!shouldRender) return undefined;
|
||||
|
||||
@ -128,6 +133,10 @@ const MiddleHeaderPanes = ({
|
||||
isAutoArchived={settings?.isAutoArchived}
|
||||
onPaneStateChange={setChatReportState}
|
||||
/>
|
||||
<BotVerificationPane
|
||||
peerId={chatId}
|
||||
onPaneStateChange={setBotVerificationState}
|
||||
/>
|
||||
<HeaderPinnedMessage
|
||||
chatId={chatId}
|
||||
threadId={threadId}
|
||||
|
||||
18
src/components/middle/panes/BotVerificationPane.module.scss
Normal file
18
src/components/middle/panes/BotVerificationPane.module.scss
Normal file
@ -0,0 +1,18 @@
|
||||
@use "../../../styles/mixins";
|
||||
|
||||
.root {
|
||||
@include mixins.header-pane;
|
||||
|
||||
display: flex;
|
||||
height: auto;
|
||||
justify-content: center;
|
||||
|
||||
padding-inline: 1rem;
|
||||
color: var(--color-text-secondary);
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.icon {
|
||||
--custom-emoji-size: 1rem;
|
||||
padding-inline-end: 0.125rem;
|
||||
}
|
||||
80
src/components/middle/panes/BotVerificationPane.tsx
Normal file
80
src/components/middle/panes/BotVerificationPane.tsx
Normal file
@ -0,0 +1,80 @@
|
||||
import type { FC } from '../../../lib/teact/teact';
|
||||
import React, { memo } from '../../../lib/teact/teact';
|
||||
import { getActions, withGlobal } from '../../../global';
|
||||
|
||||
import type { ApiBotVerification } from '../../../api/types';
|
||||
|
||||
import {
|
||||
selectPeerFullInfo,
|
||||
} from '../../../global/selectors';
|
||||
|
||||
import useTimeout from '../../../hooks/schedulers/useTimeout';
|
||||
import useLastCallback from '../../../hooks/useLastCallback';
|
||||
import useHeaderPane, { type PaneState } from '../hooks/useHeaderPane';
|
||||
|
||||
import CustomEmoji from '../../common/CustomEmoji';
|
||||
|
||||
import styles from './BotVerificationPane.module.scss';
|
||||
|
||||
type OwnProps = {
|
||||
peerId: string;
|
||||
onPaneStateChange?: (state: PaneState) => void;
|
||||
};
|
||||
|
||||
type StateProps = {
|
||||
wasShown: boolean;
|
||||
botVerification?: ApiBotVerification;
|
||||
};
|
||||
const BOT_VERIFICATION_ICON_SIZE = 16;
|
||||
const DISPLAY_DURATION_MS = 5000; // 5 sec
|
||||
|
||||
const BotVerificationPane: FC<OwnProps & StateProps> = ({
|
||||
peerId,
|
||||
wasShown,
|
||||
botVerification,
|
||||
onPaneStateChange,
|
||||
}) => {
|
||||
const isOpen = Boolean(!wasShown && botVerification);
|
||||
|
||||
const {
|
||||
markBotVerificationInfoShown,
|
||||
} = getActions();
|
||||
|
||||
const { ref, shouldRender } = useHeaderPane({
|
||||
isOpen,
|
||||
onStateChange: onPaneStateChange,
|
||||
});
|
||||
|
||||
const markAsShowed = useLastCallback(() => {
|
||||
markBotVerificationInfoShown({ peerId });
|
||||
});
|
||||
useTimeout(markAsShowed, !wasShown ? DISPLAY_DURATION_MS : undefined);
|
||||
|
||||
if (!shouldRender || !botVerification) return undefined;
|
||||
|
||||
return (
|
||||
<div ref={ref} className={styles.root}>
|
||||
<span className={styles.icon}>
|
||||
<CustomEmoji
|
||||
documentId={botVerification.iconId}
|
||||
size={BOT_VERIFICATION_ICON_SIZE}
|
||||
/>
|
||||
</span>
|
||||
{botVerification.description}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(withGlobal<OwnProps>(
|
||||
(global, { peerId }): StateProps => {
|
||||
const peerFullInfo = selectPeerFullInfo(global, peerId);
|
||||
|
||||
const botVerification = peerFullInfo?.botVerification;
|
||||
const wasShown = global.settings.botVerificationShownPeerIds.includes(peerId);
|
||||
|
||||
return {
|
||||
botVerification,
|
||||
wasShown,
|
||||
};
|
||||
},
|
||||
)(BotVerificationPane));
|
||||
@ -21,6 +21,7 @@ export const DEBUG = process.env.APP_ENV !== 'production';
|
||||
export const DEBUG_MORE = false;
|
||||
export const DEBUG_LOG_FILENAME = 'tt-log.json';
|
||||
export const STRICTERDOM_ENABLED = DEBUG;
|
||||
export const BOT_VERIFICATION_PEERS_LIMIT = 20;
|
||||
|
||||
export const BETA_CHANGELOG_URL = 'https://telegra.ph/WebA-Beta-03-20';
|
||||
export const ELECTRON_HOST_URL = process.env.ELECTRON_HOST_URL!;
|
||||
|
||||
@ -2,6 +2,7 @@ import type { ApiUser } from '../../../api/types';
|
||||
import type { ActionReturnType } from '../../types';
|
||||
import { ManagementProgress } from '../../../types';
|
||||
|
||||
import { BOT_VERIFICATION_PEERS_LIMIT } from '../../../config';
|
||||
import { getCurrentTabId } from '../../../util/establishMultitabRole';
|
||||
import { buildCollectionByKey, unique } from '../../../util/iteratees';
|
||||
import * as langProvider from '../../../util/oldLangProvider';
|
||||
@ -9,11 +10,7 @@ import { throttle } from '../../../util/schedulers';
|
||||
import { getServerTime } from '../../../util/serverTime';
|
||||
import { callApi } from '../../../api/gramjs';
|
||||
import { isUserBot, isUserId } from '../../helpers';
|
||||
import {
|
||||
addActionHandler,
|
||||
getGlobal,
|
||||
setGlobal,
|
||||
} from '../../index';
|
||||
import { addActionHandler, getGlobal, setGlobal } from '../../index';
|
||||
import {
|
||||
addUserStatuses,
|
||||
closeNewContactDialog,
|
||||
@ -508,3 +505,20 @@ addActionHandler('openSuggestedStatusModal', async (global, actions, payload): P
|
||||
}, tabId);
|
||||
setGlobal(global);
|
||||
});
|
||||
|
||||
addActionHandler('markBotVerificationInfoShown', (global, actions, payload): ActionReturnType => {
|
||||
const { peerId } = payload;
|
||||
|
||||
const currentPeerIds = global.settings.botVerificationShownPeerIds;
|
||||
const newPeerIds = unique([peerId, ...currentPeerIds]).slice(0, BOT_VERIFICATION_PEERS_LIMIT);
|
||||
|
||||
global = {
|
||||
...global,
|
||||
settings: {
|
||||
...global.settings,
|
||||
botVerificationShownPeerIds: newPeerIds,
|
||||
},
|
||||
};
|
||||
|
||||
setGlobal(global);
|
||||
});
|
||||
|
||||
@ -260,6 +260,9 @@ function unsafeMigrateCache(cached: GlobalState, initialState: GlobalState) {
|
||||
if (!cached.messages.pollById) {
|
||||
cached.messages.pollById = initialState.messages.pollById;
|
||||
}
|
||||
if (!cached.settings.botVerificationShownPeerIds) {
|
||||
cached.settings.botVerificationShownPeerIds = initialState.settings.botVerificationShownPeerIds;
|
||||
}
|
||||
}
|
||||
|
||||
function updateCache(force?: boolean) {
|
||||
@ -610,7 +613,9 @@ function omitLocalMedia(message: ApiMessage): ApiMessage {
|
||||
}
|
||||
|
||||
function reduceSettings<T extends GlobalState>(global: T): GlobalState['settings'] {
|
||||
const { byKey, themes, performance } = global.settings;
|
||||
const {
|
||||
byKey, themes, performance, botVerificationShownPeerIds,
|
||||
} = global.settings;
|
||||
|
||||
return {
|
||||
byKey,
|
||||
@ -618,6 +623,7 @@ function reduceSettings<T extends GlobalState>(global: T): GlobalState['settings
|
||||
performance,
|
||||
privacy: {},
|
||||
notifyExceptions: {},
|
||||
botVerificationShownPeerIds,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -296,6 +296,7 @@ export const INITIAL_GLOBAL_STATE: GlobalState = {
|
||||
performance: INITIAL_PERFORMANCE_STATE_MAX,
|
||||
privacy: {},
|
||||
notifyExceptions: {},
|
||||
botVerificationShownPeerIds: [],
|
||||
},
|
||||
|
||||
serviceNotifications: [],
|
||||
|
||||
@ -269,6 +269,9 @@ export interface ActionPayloads {
|
||||
saveCloseFriends: {
|
||||
userIds: string[];
|
||||
};
|
||||
markBotVerificationInfoShown: {
|
||||
peerId: string;
|
||||
};
|
||||
|
||||
// Message search
|
||||
openMiddleSearch: WithTabId | undefined;
|
||||
|
||||
@ -401,6 +401,7 @@ export type GlobalState = {
|
||||
lastPremiumBandwithNotificationDate?: number;
|
||||
paidReactionPrivacy?: boolean;
|
||||
languages?: ApiLanguage[];
|
||||
botVerificationShownPeerIds: string[];
|
||||
};
|
||||
|
||||
push?: {
|
||||
|
||||
@ -10,7 +10,8 @@ import useResizeObserver from '../useResizeObserver';
|
||||
const TRANSITION_PROPERTY = 'color';
|
||||
const TRANSITION_STYLE = `50ms ${TRANSITION_PROPERTY} linear`;
|
||||
|
||||
export default function useDynamicColorListener(ref: React.RefObject<HTMLElement>, isDisabled?: boolean) {
|
||||
export default function useDynamicColorListener(ref: React.RefObject<HTMLElement>,
|
||||
isDisabled?: boolean) {
|
||||
const [hexColor, setHexColor] = useState<string | undefined>();
|
||||
|
||||
const updateColor = useLastCallback(() => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user