From 15e586d77250784968d0d033a4e98435b4085a50 Mon Sep 17 00:00:00 2001 From: Alexander Zinchuk Date: Thu, 15 Dec 2022 19:19:30 +0100 Subject: [PATCH] Reactions: Fix quick reactions, refetch configs (#2178) Co-authored-by: undrfined --- src/api/gramjs/apiBuilders/appConfig.ts | 2 -- src/api/gramjs/apiBuilders/misc.ts | 12 ++++++++++++ src/api/gramjs/methods/index.ts | 2 +- src/api/gramjs/methods/settings.ts | 9 +++++++++ src/api/gramjs/methods/symbols.ts | 15 +++++++-------- src/api/gramjs/updater.ts | 1 + src/api/types/misc.ts | 8 +++++++- src/api/types/updates.ts | 6 +++++- src/components/left/newChat/NewChatStep2.tsx | 12 ++++++------ .../left/settings/SettingsQuickReaction.tsx | 4 ++-- .../left/settings/SettingsStickers.tsx | 2 +- src/components/main/Main.tsx | 4 +++- src/config.ts | 3 +++ src/global/actions/api/reactions.ts | 16 +++++++++++----- src/global/actions/api/settings.ts | 19 ++++++++++++++++++- src/global/actions/api/symbols.ts | 8 ++++---- src/global/actions/apiUpdaters/misc.ts | 4 ++++ src/global/selectors/messages.ts | 2 +- src/global/types.ts | 6 +++++- src/util/requestActionTimeout.ts | 12 ++++++++++++ 20 files changed, 112 insertions(+), 35 deletions(-) create mode 100644 src/util/requestActionTimeout.ts diff --git a/src/api/gramjs/apiBuilders/appConfig.ts b/src/api/gramjs/apiBuilders/appConfig.ts index 9107dc064..4f842534d 100644 --- a/src/api/gramjs/apiBuilders/appConfig.ts +++ b/src/api/gramjs/apiBuilders/appConfig.ts @@ -22,7 +22,6 @@ interface GramJsAppConfig extends LimitsConfig { }>; emojies_send_dice: string[]; groupcall_video_participants_max: number; - reactions_default: string; reactions_uniq_max: number; chat_read_mark_size_threshold: number; chat_read_mark_expire_period: number; @@ -66,7 +65,6 @@ export function buildAppConfig(json: GramJs.TypeJSONValue): ApiAppConfig { const appConfig = buildJson(json) as GramJsAppConfig; return { - defaultReaction: appConfig.reactions_default, emojiSounds: buildEmojiSounds(appConfig), seenByMaxChatMembers: appConfig.chat_read_mark_size_threshold, seenByExpiresAt: appConfig.chat_read_mark_expire_period, diff --git a/src/api/gramjs/apiBuilders/misc.ts b/src/api/gramjs/apiBuilders/misc.ts index a314b47a9..a5d8e2ac0 100644 --- a/src/api/gramjs/apiBuilders/misc.ts +++ b/src/api/gramjs/apiBuilders/misc.ts @@ -1,6 +1,7 @@ import { Api as GramJs } from '../../../lib/gramjs'; import type { + ApiConfig, ApiCountry, ApiSession, ApiUrlAuthResult, ApiWallpaper, ApiWebSession, } from '../../types'; import type { ApiPrivacySettings, ApiPrivacyKey, PrivacyVisibility } from '../../../types'; @@ -221,3 +222,14 @@ export function buildApiUrlAuthResult(result: GramJs.TypeUrlAuthResult): ApiUrlA } return undefined; } + +export function buildApiConfig(config: GramJs.Config): ApiConfig { + const defaultReaction = config.reactionsDefault + && 'emoticon' in config.reactionsDefault ? config.reactionsDefault.emoticon : undefined; + return { + expiresAt: config.expires, + gifSearchUsername: config.gifSearchUsername, + defaultReaction, + maxGroupSize: config.chatSizeMax, + }; +} diff --git a/src/api/gramjs/methods/index.ts b/src/api/gramjs/methods/index.ts index 3f7374091..ce2a18d24 100644 --- a/src/api/gramjs/methods/index.ts +++ b/src/api/gramjs/methods/index.ts @@ -60,7 +60,7 @@ export { fetchNotificationExceptions, fetchNotificationSettings, updateContactSignUpNotification, updateNotificationSettings, fetchLanguages, fetchLangPack, fetchPrivacySettings, setPrivacySettings, registerDevice, unregisterDevice, updateIsOnline, fetchContentSettings, updateContentSettings, fetchLangStrings, fetchCountryList, fetchAppConfig, - fetchGlobalPrivacySettings, updateGlobalPrivacySettings, toggleUsername, reorderUsernames, + fetchGlobalPrivacySettings, updateGlobalPrivacySettings, toggleUsername, reorderUsernames, fetchConfig, } from './settings'; export { diff --git a/src/api/gramjs/methods/settings.ts b/src/api/gramjs/methods/settings.ts index ec30735af..7dbe5c273 100644 --- a/src/api/gramjs/methods/settings.ts +++ b/src/api/gramjs/methods/settings.ts @@ -3,6 +3,7 @@ import { Api as GramJs } from '../../../lib/gramjs'; import type { ApiAppConfig, + ApiConfig, ApiError, ApiLangString, ApiLanguage, @@ -14,6 +15,7 @@ import type { LANG_PACKS } from '../../../config'; import { BLOCKED_LIST_LIMIT, DEFAULT_LANG_PACK } from '../../../config'; import { ACCEPTABLE_USERNAME_ERRORS } from './management'; import { + buildApiConfig, buildApiCountryList, buildApiNotifyException, buildApiSession, @@ -507,6 +509,13 @@ export async function fetchAppConfig(): Promise { return buildAppConfig(result); } +export async function fetchConfig(): Promise { + const result = await invokeRequest(new GramJs.help.GetConfig()); + if (!result) return undefined; + + return buildApiConfig(result); +} + function updateLocalDb( result: ( GramJs.account.PrivacyRules | GramJs.contacts.Blocked | GramJs.contacts.BlockedSlice | diff --git a/src/api/gramjs/methods/symbols.ts b/src/api/gramjs/methods/symbols.ts index 93f054777..9271486d7 100644 --- a/src/api/gramjs/methods/symbols.ts +++ b/src/api/gramjs/methods/symbols.ts @@ -10,7 +10,7 @@ import { } from '../apiBuilders/symbols'; import { buildInputStickerSet, buildInputDocument, buildInputStickerSetShortName } from '../gramjsBuilders'; import { buildVideoFromDocument } from '../apiBuilders/messages'; -import { RECENT_STICKERS_LIMIT } from '../../../config'; +import { DEFAULT_GIF_SEARCH_BOT_USERNAME, RECENT_STICKERS_LIMIT } from '../../../config'; import localDb from '../localDb'; @@ -301,15 +301,14 @@ export async function uninstallStickerSet({ stickerSetId, accessHash }: { sticke let inputGifBot: GramJs.InputUser | undefined; -export async function searchGifs({ query, offset = '' }: { query: string; offset?: string }) { +export async function searchGifs({ + query, + offset = '', + username = DEFAULT_GIF_SEARCH_BOT_USERNAME, +}: { query: string; offset?: string; username?: string }) { if (!inputGifBot) { - const config = await invokeRequest(new GramJs.help.GetConfig()); - if (!config) { - return undefined; - } - const resolvedPeer = await invokeRequest(new GramJs.contacts.ResolveUsername({ - username: config.gifSearchUsername, + username, })); if (!resolvedPeer || !(resolvedPeer.users[0] instanceof GramJs.User)) { return undefined; diff --git a/src/api/gramjs/updater.ts b/src/api/gramjs/updater.ts index a5f4ce849..ad0463644 100644 --- a/src/api/gramjs/updater.ts +++ b/src/api/gramjs/updater.ts @@ -1031,6 +1031,7 @@ export function updater(update: Update, originRequest?: GramJs.AnyRequest) { addEntitiesWithPhotosToLocalDb(entities); dispatchUserAndChatUpdates(entities); } + onUpdate({ '@type': 'updateConfig' }); } else if (DEBUG) { const params = typeof update === 'object' && 'className' in update ? update.className : update; log('UNEXPECTED UPDATE', params); diff --git a/src/api/types/misc.ts b/src/api/types/misc.ts index 6d8e50128..c56491b7f 100644 --- a/src/api/types/misc.ts +++ b/src/api/types/misc.ts @@ -162,7 +162,6 @@ export interface ApiCountryCode extends ApiCountry { } export interface ApiAppConfig { - defaultReaction: string; emojiSounds: Record; seenByMaxChatMembers: number; seenByExpiresAt: number; @@ -178,6 +177,13 @@ export interface ApiAppConfig { limits: Record; } +export interface ApiConfig { + expiresAt: number; + defaultReaction?: string; + gifSearchUsername?: string; + maxGroupSize: number; +} + export interface GramJsEmojiInteraction { v: number; a: { diff --git a/src/api/types/updates.ts b/src/api/types/updates.ts index a79b3ce1d..56eda6ebe 100644 --- a/src/api/types/updates.ts +++ b/src/api/types/updates.ts @@ -375,6 +375,10 @@ export type ApiUpdateError = { error: ApiError; }; +export type ApiUpdateConfig = { + '@type': 'updateConfig'; +}; + export type ApiUpdateResetContacts = { '@type': 'updateResetContactList'; }; @@ -577,7 +581,7 @@ export type ApiUpdate = ( ApiUpdatePendingJoinRequests | ApiUpdatePaymentVerificationNeeded | ApiUpdatePaymentStateCompleted | ApiUpdatePhoneCall | ApiUpdatePhoneCallSignalingData | ApiUpdatePhoneCallMediaState | ApiUpdatePhoneCallConnectionState | ApiUpdateBotMenuButton | ApiUpdateTranscribedAudio | ApiUpdateUserEmojiStatus | - ApiUpdateMessageExtendedMedia + ApiUpdateMessageExtendedMedia | ApiUpdateConfig ); export type OnApiUpdate = (update: ApiUpdate) => void; diff --git a/src/components/left/newChat/NewChatStep2.tsx b/src/components/left/newChat/NewChatStep2.tsx index efcfc35f8..242bff21f 100644 --- a/src/components/left/newChat/NewChatStep2.tsx +++ b/src/components/left/newChat/NewChatStep2.tsx @@ -27,18 +27,17 @@ export type OwnProps = { type StateProps = { creationProgress?: ChatCreationProgress; creationError?: string; + maxGroupSize?: number; }; -// TODO @implement -const MAX_USERS_FOR_LEGACY_CHAT = 199; // Accounting for current user - const NewChatStep2: FC = ({ isChannel, isActive, memberIds, - onReset, + maxGroupSize, creationProgress, creationError, + onReset, }) => { const { createGroupChat, @@ -84,7 +83,7 @@ const NewChatStep2: FC = ({ return; } - if (memberIds.length > MAX_USERS_FOR_LEGACY_CHAT) { + if (maxGroupSize && memberIds.length >= maxGroupSize) { setError(chatTooManyUsersError); return; } @@ -94,7 +93,7 @@ const NewChatStep2: FC = ({ photo, memberIds, }); - }, [title, memberIds, createGroupChat, photo, chatTitleEmptyError, chatTooManyUsersError]); + }, [title, memberIds, maxGroupSize, createGroupChat, photo]); const handleCreateChannel = useCallback(() => { if (!title.length) { @@ -204,6 +203,7 @@ export default memo(withGlobal( return { creationProgress, creationError, + maxGroupSize: global.config?.maxGroupSize, }; }, )(NewChatStep2)); diff --git a/src/components/left/settings/SettingsQuickReaction.tsx b/src/components/left/settings/SettingsQuickReaction.tsx index d7bceb046..029ff9a51 100644 --- a/src/components/left/settings/SettingsQuickReaction.tsx +++ b/src/components/left/settings/SettingsQuickReaction.tsx @@ -63,12 +63,12 @@ const SettingsQuickReaction: FC = ({ export default memo(withGlobal( (global) => { - const { availableReactions, appConfig } = global; + const { availableReactions, config } = global; const isPremium = selectIsCurrentUserPremium(global); return { availableReactions, - selectedReaction: appConfig?.defaultReaction, + selectedReaction: config?.defaultReaction, isPremium, }; }, diff --git a/src/components/left/settings/SettingsStickers.tsx b/src/components/left/settings/SettingsStickers.tsx index 496329bfc..3fb44a7c8 100644 --- a/src/components/left/settings/SettingsStickers.tsx +++ b/src/components/left/settings/SettingsStickers.tsx @@ -148,7 +148,7 @@ export default memo(withGlobal( addedSetIds: global.stickers.added.setIds, customEmojiSetIds: global.customEmojis.added.setIds, stickerSetsById: global.stickers.setsById, - defaultReaction: global.appConfig?.defaultReaction, + defaultReaction: global.config?.defaultReaction, }; }, )(SettingsStickers)); diff --git a/src/components/main/Main.tsx b/src/components/main/Main.tsx index d4783672b..cf75e59a6 100644 --- a/src/components/main/Main.tsx +++ b/src/components/main/Main.tsx @@ -186,6 +186,7 @@ const Main: FC = ({ closeStickerSetModal, closeCustomEmojiSets, checkVersionNotification, + loadConfig, loadAppConfig, loadAttachBots, loadContactList, @@ -208,6 +209,7 @@ const Main: FC = ({ useEffect(() => { if (lastSyncTime) { updateIsOnline(true); + loadConfig(); loadAppConfig(); loadAvailableReactions(); loadAnimatedEmojis(); @@ -223,7 +225,7 @@ const Main: FC = ({ }, [ lastSyncTime, loadAnimatedEmojis, loadEmojiKeywords, loadNotificationExceptions, loadNotificationSettings, loadTopInlineBots, updateIsOnline, loadAvailableReactions, loadAppConfig, loadAttachBots, loadContactList, - loadPremiumGifts, checkAppVersion, + loadPremiumGifts, checkAppVersion, loadConfig, ]); // Language-based API calls diff --git a/src/config.ts b/src/config.ts index 5244c2d6a..6db148140 100644 --- a/src/config.ts +++ b/src/config.ts @@ -95,6 +95,8 @@ export const MACOS_DEFAULT_MESSAGE_TEXT_SIZE_PX = 15; export const DRAFT_DEBOUNCE = 10000; // 10s export const SEND_MESSAGE_ACTION_INTERVAL = 3000; // 3s +// 10000s from https://corefork.telegram.org/api/url-authorization#automatic-authorization +export const APP_CONFIG_REFETCH_INTERVAL = 10000 * 1000; export const EDITABLE_INPUT_ID = 'editable-message-text'; export const EDITABLE_INPUT_MODAL_ID = 'editable-message-text-modal'; @@ -218,6 +220,7 @@ export const API_CHAT_TYPES = ['bots', 'channels', 'chats', 'users'] as const; export const SERVICE_NOTIFICATIONS_USER_ID = '777000'; export const REPLIES_USER_ID = '1271266957'; // TODO For Test connection ID must be equal to 708513 export const RESTRICTED_EMOJI_SET_ID = '7173162320003080'; +export const DEFAULT_GIF_SEARCH_BOT_USERNAME = 'gif'; export const ALL_FOLDER_ID = 0; export const ARCHIVED_FOLDER_ID = 1; export const DELETED_COMMENTS_CHANNEL_ID = '-777'; diff --git a/src/global/actions/api/reactions.ts b/src/global/actions/api/reactions.ts index 35a03c8b7..5d8c4ac7a 100644 --- a/src/global/actions/api/reactions.ts +++ b/src/global/actions/api/reactions.ts @@ -1,7 +1,6 @@ import { addActionHandler, getGlobal, setGlobal } from '../../index'; import { callApi } from '../../../api/gramjs'; import * as mediaLoader from '../../../util/mediaLoader'; -import type { ApiAppConfig } from '../../../api/types'; import { ApiMediaFormat } from '../../../api/types'; import { selectChat, @@ -180,12 +179,19 @@ addActionHandler('setDefaultReaction', async (global, actions, payload) => { return; } + global = getGlobal(); + + if (!global.config) { + actions.loadConfig(); // Refetch new config, if it is somehow not loaded + return; + } + setGlobal({ - ...getGlobal(), - appConfig: { - ...global.appConfig, + ...global, + config: { + ...global.config, defaultReaction: reaction, - } as ApiAppConfig, + }, }); }); diff --git a/src/global/actions/api/settings.ts b/src/global/actions/api/settings.ts index 440efbc64..f2261c8b7 100644 --- a/src/global/actions/api/settings.ts +++ b/src/global/actions/api/settings.ts @@ -10,11 +10,13 @@ import { UPLOADING_WALLPAPER_SLUG, } from '../../../types'; -import { COUNTRIES_WITH_12H_TIME_FORMAT } from '../../../config'; +import { APP_CONFIG_REFETCH_INTERVAL, COUNTRIES_WITH_12H_TIME_FORMAT } from '../../../config'; import { callApi } from '../../../api/gramjs'; import { buildCollectionByKey } from '../../../util/iteratees'; import { subscribe, unsubscribe } from '../../../util/notifications'; import { setTimeFormat } from '../../../util/langProvider'; +import requestActionTimeout from '../../../util/requestActionTimeout'; +import { getServerTime } from '../../../util/serverTime'; import { selectChat, selectUser } from '../../selectors'; import { addUsers, addBlockedContact, updateChats, updateUser, removeBlockedContact, replaceSettings, updateNotifySettings, @@ -621,12 +623,27 @@ addActionHandler('loadAppConfig', async () => { const appConfig = await callApi('fetchAppConfig'); if (!appConfig) return; + requestActionTimeout('loadAppConfig', APP_CONFIG_REFETCH_INTERVAL); + setGlobal({ ...getGlobal(), appConfig, }); }); +addActionHandler('loadConfig', async (global) => { + const config = await callApi('fetchConfig'); + if (!config) return; + + const timeout = config.expiresAt - getServerTime(global.serverTimeOffset); + requestActionTimeout('loadConfig', timeout * 1000); + + setGlobal({ + ...getGlobal(), + config, + }); +}); + addActionHandler('loadGlobalPrivacySettings', async () => { const globalSettings = await callApi('fetchGlobalPrivacySettings'); if (!globalSettings) { diff --git a/src/global/actions/api/symbols.ts b/src/global/actions/api/symbols.ts index c1177f80e..b412e3c8e 100644 --- a/src/global/actions/api/symbols.ts +++ b/src/global/actions/api/symbols.ts @@ -516,7 +516,7 @@ addActionHandler('setGifSearchQuery', (global, actions, payload) => { if (typeof query === 'string') { void searchThrottled(() => { - searchGifs(query); + searchGifs(query, global.config?.gifSearchUsername); }); } }); @@ -526,7 +526,7 @@ addActionHandler('searchMoreGifs', (global) => { if (typeof query === 'string') { void searchThrottled(() => { - searchGifs(query, offset); + searchGifs(query, global.config?.gifSearchUsername, offset); }); } }); @@ -646,8 +646,8 @@ async function searchStickers(query: string, hash?: string) { )); } -async function searchGifs(query: string, offset?: string) { - const result = await callApi('searchGifs', { query, offset }); +async function searchGifs(query: string, botUsername?: string, offset?: string) { + const result = await callApi('searchGifs', { query, offset, username: botUsername }); if (!result) { return; } diff --git a/src/global/actions/apiUpdaters/misc.ts b/src/global/actions/apiUpdaters/misc.ts index a13c06be7..51bb7ceb4 100644 --- a/src/global/actions/apiUpdaters/misc.ts +++ b/src/global/actions/apiUpdaters/misc.ts @@ -24,6 +24,10 @@ addActionHandler('apiUpdate', (global, actions, update) => { }); break; + case 'updateConfig': + actions.loadConfig(); + break; + case 'updateFavoriteStickers': actions.loadFavoriteStickers(); break; diff --git a/src/global/selectors/messages.ts b/src/global/selectors/messages.ts index cd0eb7627..f6ecda386 100644 --- a/src/global/selectors/messages.ts +++ b/src/global/selectors/messages.ts @@ -952,7 +952,7 @@ export function selectDefaultReaction(global: GlobalState, chatId: string) { if (chatId === SERVICE_NOTIFICATIONS_USER_ID) return undefined; const isPrivate = isUserId(chatId); - const defaultReaction = global.appConfig?.defaultReaction; + const defaultReaction = global.config?.defaultReaction; const { availableReactions } = global; if (!defaultReaction || !availableReactions?.some( (l) => l.reaction === defaultReaction && !l.isInactive, diff --git a/src/global/types.ts b/src/global/types.ts index 8db5c0b60..9ebf900b2 100644 --- a/src/global/types.ts +++ b/src/global/types.ts @@ -46,6 +46,7 @@ import type { ApiChatType, ApiReceipt, ApiPaymentCredentials, + ApiConfig, } from '../api/types'; import type { FocusDirection, @@ -138,6 +139,7 @@ export type ApiLimitTypeWithModal = Exclude; export type GlobalState = { + config?: ApiConfig; appConfig?: ApiAppConfig; canInstall?: boolean; hasWebAuthTokenFailed?: boolean; @@ -1198,6 +1200,8 @@ export interface ActionPayloads { skipLockOnUnload: never; // Settings + loadConfig: never; + loadAppConfig: never; requestNextSettingsScreen: SettingsScreens; sortChatFolders: { folderIds: number[] }; closeDeleteChatFolderModal: never; @@ -1314,7 +1318,7 @@ export type NonTypedActionNames = ( 'updateWebNotificationSettings' | 'loadLanguages' | 'loadPrivacySettings' | 'setPrivacyVisibility' | 'setPrivacySettings' | 'loadNotificationExceptions' | 'setThemeSettings' | 'updateIsOnline' | 'loadContentSettings' | 'updateContentSettings' | - 'loadCountryList' | 'ensureTimeFormat' | 'loadAppConfig' | + 'loadCountryList' | 'ensureTimeFormat' | // stickers & GIFs 'setStickerSearchQuery' | 'saveGif' | 'setGifSearchQuery' | 'searchMoreGifs' | 'faveSticker' | 'unfaveSticker' | 'toggleStickerSet' | diff --git a/src/util/requestActionTimeout.ts b/src/util/requestActionTimeout.ts new file mode 100644 index 000000000..336afd305 --- /dev/null +++ b/src/util/requestActionTimeout.ts @@ -0,0 +1,12 @@ +import { getActions } from '../global'; +import type { GlobalActions } from '../global/types'; + +const callbacks = new Map(); + +export default function requestActionTimeout(action: keyof GlobalActions, timeout: number) { + clearTimeout(callbacks.get(action)); + const timerId = setTimeout(() => { + getActions()[action](); + }, timeout); + callbacks.set(action, timerId); +}