import { addReducer, getGlobal, setGlobal } from '../../../lib/teact/teactn'; import { ApiSticker } from '../../../api/types'; import { LangCode } from '../../../types'; import { callApi } from '../../../api/gramjs'; import { pause, throttle } from '../../../util/schedulers'; import { updateStickerSets, updateStickerSet, replaceAnimatedEmojis, updateGifSearch, updateStickersForEmoji, rebuildStickersForEmoji, } from '../../reducers'; import searchWords from '../../../util/searchWords'; import { selectStickerSet } from '../../selectors'; const ADDED_SETS_THROTTLE = 500; const ADDED_SETS_THROTTLE_CHUNK = 50; const searchThrottled = throttle((cb) => cb(), 500, false); addReducer('loadStickerSets', (global) => { const { hash } = global.stickers.added || {}; void loadStickerSets(hash); }); addReducer('loadAddedStickers', (global, actions) => { const { setIds: addedSetIds } = global.stickers.added; if (!addedSetIds || !addedSetIds.length) { return; } (async () => { for (let i = 0; i < addedSetIds.length; i++) { actions.loadStickers({ stickerSetId: addedSetIds[i] }); if (i % ADDED_SETS_THROTTLE_CHUNK === 0 && i > 0) { await pause(ADDED_SETS_THROTTLE); } } })(); }); addReducer('loadRecentStickers', (global) => { const { hash } = global.stickers.recent || {}; void loadRecentStickers(hash); }); addReducer('loadFavoriteStickers', (global) => { const { hash } = global.stickers.favorite || {}; void loadFavoriteStickers(hash); }); addReducer('loadFeaturedStickers', (global) => { const { hash } = global.stickers.featured || {}; void loadFeaturedStickers(hash); }); addReducer('loadStickers', (global, actions, payload) => { const { stickerSetId } = payload!; let { stickerSetAccessHash } = payload!; if (!stickerSetAccessHash) { const stickerSet = selectStickerSet(global, stickerSetId); if (!stickerSet) { return; } stickerSetAccessHash = stickerSet.accessHash; } void loadStickers(stickerSetId, stickerSetAccessHash); }); addReducer('loadAnimatedEmojis', () => { void loadAnimatedEmojis(); }); addReducer('loadSavedGifs', (global) => { const { hash } = global.gifs.saved; void loadSavedGifs(hash); }); addReducer('faveSticker', (global, actions, payload) => { const { sticker } = payload!; if (sticker) { void callApi('faveSticker', { sticker }); } }); addReducer('unfaveSticker', (global, actions, payload) => { const { sticker } = payload!; if (sticker) { void unfaveSticker(sticker); } }); addReducer('toggleStickerSet', (global, actions, payload) => { const { stickerSetId } = payload!; const stickerSet = selectStickerSet(global, stickerSetId); if (!stickerSet) { return; } const { accessHash, installedDate } = stickerSet; void callApi(!installedDate ? 'installStickerSet' : 'uninstallStickerSet', { stickerSetId, accessHash }); }); addReducer('loadEmojiKeywords', (global, actions, payload: { language: LangCode }) => { const { language } = payload; let currentEmojiKeywords = global.emojiKeywords[language]; if (currentEmojiKeywords && currentEmojiKeywords.isLoading) { return; } setGlobal({ ...global, emojiKeywords: { ...global.emojiKeywords, [language]: { ...currentEmojiKeywords, isLoading: true, }, }, }); (async () => { const emojiKeywords = await callApi('fetchEmojiKeywords', { language, fromVersion: currentEmojiKeywords ? currentEmojiKeywords.version : 0, }); global = getGlobal(); currentEmojiKeywords = global.emojiKeywords[language]; if (!emojiKeywords) { setGlobal({ ...global, emojiKeywords: { ...global.emojiKeywords, [language]: { ...currentEmojiKeywords, isLoading: false, }, }, }); return; } setGlobal({ ...global, emojiKeywords: { ...global.emojiKeywords, [language]: { isLoading: false, version: emojiKeywords.version, keywords: { ...(currentEmojiKeywords && currentEmojiKeywords.keywords), ...emojiKeywords.keywords, }, }, }, }); })(); }); async function loadStickerSets(hash = 0) { const addedStickers = await callApi('fetchStickerSets', { hash }); if (!addedStickers) { return; } setGlobal(updateStickerSets( getGlobal(), 'added', addedStickers.hash, addedStickers.sets, )); } async function loadRecentStickers(hash = 0) { const recentStickers = await callApi('fetchRecentStickers', { hash }); if (!recentStickers) { return; } const global = getGlobal(); setGlobal({ ...global, stickers: { ...global.stickers, recent: recentStickers, }, }); } async function loadFavoriteStickers(hash = 0) { const favoriteStickers = await callApi('fetchFavoriteStickers', { hash }); if (!favoriteStickers) { return; } const global = getGlobal(); setGlobal({ ...global, stickers: { ...global.stickers, favorite: favoriteStickers, }, }); } async function loadFeaturedStickers(hash = 0) { const featuredStickers = await callApi('fetchFeaturedStickers', { hash }); if (!featuredStickers) { return; } setGlobal(updateStickerSets( getGlobal(), 'featured', featuredStickers.hash, featuredStickers.sets, )); } async function loadStickers(stickerSetId: string, accessHash: string) { const stickerSet = await callApi('fetchStickers', { stickerSetId, accessHash }); if (!stickerSet) { return; } const { set, stickers, packs } = stickerSet; let global = getGlobal(); global = updateStickerSet(global, set.id, { ...set, stickers, packs }); const currentEmoji = global.stickers.forEmoji.emoji; if (currentEmoji && packs[currentEmoji]) { global = rebuildStickersForEmoji(global); } setGlobal(global); } async function loadAnimatedEmojis() { const stickerSet = await callApi('fetchAnimatedEmojis'); if (!stickerSet) { return; } const { set, stickers } = stickerSet; setGlobal(replaceAnimatedEmojis(getGlobal(), { ...set, stickers })); } function unfaveSticker(sticker: ApiSticker) { const global = getGlobal(); // Remove sticker preemptively to get instant feedback when user removes sticker // from favorites while in Sticker Picker setGlobal({ ...global, stickers: { ...global.stickers, favorite: { ...global.stickers.favorite, stickers: global.stickers.favorite.stickers.filter(({ id }) => id !== sticker.id), }, }, }); void callApi('faveSticker', { sticker, unfave: true }); } addReducer('setStickerSearchQuery', (global, actions, payload) => { const { query } = payload!; if (query) { void searchThrottled(() => { searchStickers(query); }); } }); addReducer('setGifSearchQuery', (global, actions, payload) => { const { query } = payload!; if (typeof query === 'string') { void searchThrottled(() => { searchGifs(query); }); } }); addReducer('searchMoreGifs', (global) => { const { query, offset } = global.gifs.search; if (typeof query === 'string') { void searchThrottled(() => { searchGifs(query, offset); }); } }); addReducer('loadStickersForEmoji', (global, actions, payload) => { const { emoji } = payload!; const { hash } = global.stickers.forEmoji; void searchThrottled(() => { loadStickersForEmoji(emoji, hash); }); }); addReducer('clearStickersForEmoji', (global) => { return { ...global, stickers: { ...global.stickers, forEmoji: {}, }, }; }); async function searchStickers(query: string, hash = 0) { const result = await callApi('searchStickers', { query, hash }); if (!result) { return; } const global = getGlobal(); const { setsById, added } = global.stickers; const resultIds = result.sets.map(({ id }) => id); if (added.setIds) { added.setIds.forEach((id) => { if (!resultIds.includes(id)) { const { title } = setsById[id] || {}; if (title && searchWords(title, query)) { resultIds.unshift(id); } } }); } setGlobal(updateStickerSets( global, 'search', result.hash, result.sets, resultIds, )); } async function searchGifs(query: string, offset?: string) { const result = await callApi('searchGifs', { query, offset }); if (!result) { return; } setGlobal(updateGifSearch(getGlobal(), !offset, result.gifs, result.nextOffset)); } async function loadSavedGifs(hash = 0) { const savedGifs = await callApi('fetchSavedGifs', { hash }); if (!savedGifs) { return; } const global = getGlobal(); setGlobal({ ...global, gifs: { ...global.gifs, saved: savedGifs, }, }); } async function loadStickersForEmoji(emoji: string, hash = 0) { let global = getGlobal(); setGlobal({ ...global, stickers: { ...global.stickers, forEmoji: { ...global.stickers.forEmoji, emoji, }, }, }); const result = await callApi('fetchStickersForEmoji', { emoji, hash }); global = getGlobal(); if (!result || global.stickers.forEmoji.emoji !== emoji) { return; } global = updateStickersForEmoji(global, emoji, result.stickers, result.hash); setGlobal(global); }