/* * https://github.com/morethanwords/tweb * Copyright (C) 2019-2021 Eduard Kuzmenko * https://github.com/morethanwords/tweb/blob/master/LICENSE */ import App from "../../config/app"; import { MOUNT_CLASS_TO } from "../../config/debug"; import { validateInitObject } from "../../helpers/object"; import I18n from "../langPack"; import { isObject } from "../mtproto/bin_utils"; import apiManager from "../mtproto/mtprotoworker"; import SearchIndex from "../searchIndex"; import stateStorage from "../stateStorage"; import appStateManager from "./appStateManager"; type EmojiLangPack = { keywords: { [keyword: string]: string[], }, version: number, langCode: string }; const EMOJI_LANG_PACK: EmojiLangPack = { keywords: {}, version: 0, langCode: App.langPackCode }; const RECENT_MAX_LENGTH = 36; export class AppEmojiManager { private static POPULAR_EMOJI = ["πŸ˜‚", "😘", "❀️", "😍", "😊", "😁", "πŸ‘", "☺️", "πŸ˜”", "πŸ˜„", "😭", "πŸ’‹", "πŸ˜’", "😳", "😜", "πŸ™ˆ", "πŸ˜‰", "πŸ˜ƒ", "😒", "😝", "😱", "😑", "😏", "😞", "πŸ˜…", "😚", "πŸ™Š", "😌", "πŸ˜€", "πŸ˜‹", "πŸ˜†", "πŸ‘Œ", "😐", "πŸ˜•"]; private keywordLangPacks: { [langCode: string]: EmojiLangPack } = {}; private index: SearchIndex; private indexedLangPacks: {[langCode: string]: boolean} = {}; private getKeywordsPromises: {[langCode: string]: Promise} = {}; private recent: string[]; private getRecentEmojisPromise: Promise; /* public getPopularEmoji() { return stateStorage.get('emojis_popular').then(popEmojis => { var result = [] if (popEmojis && popEmojis.length) { for (var i = 0, len = popEmojis.length; i < len; i++) { result.push({code: popEmojis[i][0], rate: popEmojis[i][1]}) } callback(result) return } return stateStorage.get('emojis_recent').then(recentEmojis => { recentEmojis = recentEmojis || popular || [] var shortcut var code for (var i = 0, len = recentEmojis.length; i < len; i++) { shortcut = recentEmojis[i] if (Array.isArray(shortcut)) { shortcut = shortcut[0] } if (shortcut && typeof shortcut === 'string') { if (shortcut.charAt(0) == ':') { shortcut = shortcut.substr(1, shortcut.length - 2) } if (code = shortcuts[shortcut]) { result.push({code: code, rate: 1}) } } } callback(result) }); }); } function pushPopularEmoji (code) { getPopularEmoji(function (popularEmoji) { var exists = false var count = popularEmoji.length var result = [] for (var i = 0; i < count; i++) { if (popularEmoji[i].code == code) { exists = true popularEmoji[i].rate++ } result.push([popularEmoji[i].code, popularEmoji[i].rate]) } if (exists) { result.sort(function (a, b) { return b[1] - a[1] }) } else { if (result.length > 41) { result = result.slice(0, 41) } result.push([code, 1]) } ConfigStorage.set({emojis_popular: result}) }) } */ public getEmojiKeywords(langCode: string = App.langPackCode) { const promise = this.getKeywordsPromises[langCode]; if(promise) { return promise; } const storageKey: any = 'emojiKeywords_' + langCode; return this.getKeywordsPromises[langCode] = stateStorage.get(storageKey).then((pack: EmojiLangPack) => { if(!isObject(pack)) { pack = {} as any; } validateInitObject(EMOJI_LANG_PACK, pack); // important pack.langCode = langCode; this.keywordLangPacks[langCode] = pack; return apiManager.invokeApi('messages.getEmojiKeywordsDifference', { lang_code: pack.langCode, from_version: pack.version }).then((keywordsDifference) => { pack.version = keywordsDifference.version; const packKeywords = pack.keywords; const keywords = keywordsDifference.keywords; for(let i = 0, length = keywords.length; i < length; ++i) { const {keyword, emoticons} = keywords[i]; packKeywords[keyword] = emoticons; } stateStorage.set({ [storageKey]: pack }); return pack; }, () => { return pack; }); }); } public getBothEmojiKeywords() { const promises: Promise[] = [ this.getEmojiKeywords() ]; if(I18n.lastRequestedLangCode !== App.langPackCode) { promises.push(this.getEmojiKeywords(I18n.lastRequestedLangCode)); } if(!this.recent) { promises.push(this.getRecentEmojis()); } return Promise.all(promises); } public indexEmojis() { if(!this.index) { this.index = new SearchIndex(false, false); } for(const langCode in this.keywordLangPacks) { if(this.indexedLangPacks[langCode]) { continue; } const pack = this.keywordLangPacks[langCode]; const keywords = pack.keywords; for(const keyword in keywords) { const emoticons = keywords[keyword]; this.index.indexObject(emoticons, keyword); } this.indexedLangPacks[langCode] = true; } } public searchEmojis(q: string) { this.indexEmojis(); q = q.toLowerCase().replace(/_/g, ' '); //const perf = performance.now(); let emojis: Array; if(q.trim()) { const set = this.index.search(q); emojis = Array.from(set).reduce((acc, v) => acc.concat(v), []); } else { emojis = this.recent.concat(AppEmojiManager.POPULAR_EMOJI).slice(0, RECENT_MAX_LENGTH); } emojis = Array.from(new Set(emojis)); //console.log('searchEmojis', q, 'time', performance.now() - perf); /* for(let i = 0, length = emojis.length; i < length; ++i) { if(emojis[i].includes(zeroWidthJoiner) && !emojis[i].includes('\ufe0f')) { emojis[i] += '\ufe0f'; } } */ return emojis; } public getRecentEmojis() { if(this.getRecentEmojisPromise) return this.getRecentEmojisPromise; return this.getRecentEmojisPromise = appStateManager.getState().then(state => { return this.recent = Array.isArray(state.recentEmoji) ? state.recentEmoji : []; }); } public pushRecentEmoji(emoji: string) { this.getRecentEmojis().then(recent => { recent.findAndSplice(e => e === emoji); recent.unshift(emoji); if(recent.length > RECENT_MAX_LENGTH) { recent.length = RECENT_MAX_LENGTH; } appStateManager.pushToState('recentEmoji', recent); }); } } const appEmojiManager = new AppEmojiManager(); MOUNT_CLASS_TO && (MOUNT_CLASS_TO.appEmojiManager = appEmojiManager); export default appEmojiManager;