2018-01-30 19:48:26 +00:00
|
|
|
import React, { Component } from 'react';
|
2018-01-16 18:48:05 +00:00
|
|
|
import PropTypes from 'prop-types';
|
2018-01-30 19:48:26 +00:00
|
|
|
import { ScrollView } from 'react-native';
|
2018-01-16 18:48:05 +00:00
|
|
|
import ScrollableTabView from 'react-native-scrollable-tab-view';
|
2018-04-24 19:34:03 +00:00
|
|
|
import map from 'lodash/map';
|
2018-01-30 19:48:26 +00:00
|
|
|
import { emojify } from 'react-emojione';
|
2018-12-21 10:55:35 +00:00
|
|
|
import equal from 'deep-equal';
|
|
|
|
|
2018-01-16 18:48:05 +00:00
|
|
|
import TabBar from './TabBar';
|
|
|
|
import EmojiCategory from './EmojiCategory';
|
|
|
|
import styles from './styles';
|
|
|
|
import categories from './categories';
|
2019-04-04 18:08:40 +00:00
|
|
|
import database, { safeAddListener } from '../../lib/realm';
|
2018-01-30 19:48:26 +00:00
|
|
|
import { emojisByCategory } from '../../emojis';
|
2018-05-18 17:55:08 +00:00
|
|
|
import protectedFunction from '../../lib/methods/helpers/protectedFunction';
|
2018-01-16 18:48:05 +00:00
|
|
|
|
2018-01-30 19:48:26 +00:00
|
|
|
const scrollProps = {
|
2018-02-08 14:08:50 +00:00
|
|
|
keyboardShouldPersistTaps: 'always',
|
|
|
|
keyboardDismissMode: 'none'
|
2018-01-30 19:48:26 +00:00
|
|
|
};
|
2018-01-16 18:48:05 +00:00
|
|
|
|
2018-02-08 14:08:50 +00:00
|
|
|
export default class EmojiPicker extends Component {
|
2018-01-16 18:48:05 +00:00
|
|
|
static propTypes = {
|
2018-09-11 16:32:52 +00:00
|
|
|
baseUrl: PropTypes.string.isRequired,
|
2018-01-30 19:48:26 +00:00
|
|
|
onEmojiSelected: PropTypes.func,
|
|
|
|
tabEmojiStyle: PropTypes.object,
|
|
|
|
emojisPerRow: PropTypes.number,
|
|
|
|
width: PropTypes.number
|
2018-01-16 18:48:05 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
2018-12-21 10:55:35 +00:00
|
|
|
this.frequentlyUsed = database.objects('frequentlyUsedEmoji').sorted('count', true);
|
|
|
|
this.customEmojis = database.objects('customEmojis');
|
2018-01-16 18:48:05 +00:00
|
|
|
this.state = {
|
|
|
|
frequentlyUsed: [],
|
2018-12-21 10:55:35 +00:00
|
|
|
customEmojis: [],
|
|
|
|
show: false
|
2018-01-16 18:48:05 +00:00
|
|
|
};
|
|
|
|
this.updateFrequentlyUsed = this.updateFrequentlyUsed.bind(this);
|
|
|
|
this.updateCustomEmojis = this.updateCustomEmojis.bind(this);
|
|
|
|
}
|
|
|
|
|
2018-02-08 14:08:50 +00:00
|
|
|
componentDidMount() {
|
2018-12-21 10:55:35 +00:00
|
|
|
this.updateFrequentlyUsed();
|
|
|
|
this.updateCustomEmojis();
|
2018-02-08 14:08:50 +00:00
|
|
|
requestAnimationFrame(() => this.setState({ show: true }));
|
2019-04-04 18:08:40 +00:00
|
|
|
safeAddListener(this.frequentlyUsed, this.updateFrequentlyUsed);
|
|
|
|
safeAddListener(this.customEmojis, this.updateCustomEmojis);
|
2018-12-21 10:55:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
shouldComponentUpdate(nextProps, nextState) {
|
|
|
|
const { frequentlyUsed, customEmojis, show } = this.state;
|
|
|
|
const { width } = this.props;
|
|
|
|
if (nextState.show !== show) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (nextProps.width !== width) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (!equal(nextState.frequentlyUsed, frequentlyUsed)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (!equal(nextState.customEmojis, customEmojis)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2018-02-08 14:08:50 +00:00
|
|
|
}
|
2018-09-25 19:28:42 +00:00
|
|
|
|
2018-01-16 18:48:05 +00:00
|
|
|
componentWillUnmount() {
|
2018-01-30 19:48:26 +00:00
|
|
|
this.frequentlyUsed.removeAllListeners();
|
|
|
|
this.customEmojis.removeAllListeners();
|
2018-01-16 18:48:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
onEmojiSelected(emoji) {
|
2018-09-25 19:28:42 +00:00
|
|
|
const { onEmojiSelected } = this.props;
|
2018-01-16 18:48:05 +00:00
|
|
|
if (emoji.isCustom) {
|
|
|
|
const count = this._getFrequentlyUsedCount(emoji.content);
|
|
|
|
this._addFrequentlyUsed({
|
|
|
|
content: emoji.content, extension: emoji.extension, count, isCustom: true
|
|
|
|
});
|
2018-09-25 19:28:42 +00:00
|
|
|
onEmojiSelected(`:${ emoji.content }:`);
|
2018-01-16 18:48:05 +00:00
|
|
|
} else {
|
2018-01-30 19:48:26 +00:00
|
|
|
const content = emoji;
|
2018-01-16 18:48:05 +00:00
|
|
|
const count = this._getFrequentlyUsedCount(content);
|
|
|
|
this._addFrequentlyUsed({ content, count, isCustom: false });
|
2018-01-30 19:48:26 +00:00
|
|
|
const shortname = `:${ emoji }:`;
|
2018-09-25 19:28:42 +00:00
|
|
|
onEmojiSelected(emojify(shortname, { output: 'unicode' }), shortname);
|
2018-01-16 18:48:05 +00:00
|
|
|
}
|
|
|
|
}
|
2018-03-02 21:31:44 +00:00
|
|
|
|
2018-09-25 19:28:42 +00:00
|
|
|
// eslint-disable-next-line react/sort-comp
|
2018-05-18 17:55:08 +00:00
|
|
|
_addFrequentlyUsed = protectedFunction((emoji) => {
|
2018-01-16 18:48:05 +00:00
|
|
|
database.write(() => {
|
|
|
|
database.create('frequentlyUsedEmoji', emoji, true);
|
|
|
|
});
|
2018-05-18 17:55:08 +00:00
|
|
|
})
|
2018-09-25 19:28:42 +00:00
|
|
|
|
2018-01-16 18:48:05 +00:00
|
|
|
_getFrequentlyUsedCount = (content) => {
|
|
|
|
const emojiRow = this.frequentlyUsed.filtered('content == $0', content);
|
|
|
|
return emojiRow.length ? emojiRow[0].count + 1 : 1;
|
|
|
|
}
|
2018-09-25 19:28:42 +00:00
|
|
|
|
2018-01-16 18:48:05 +00:00
|
|
|
updateFrequentlyUsed() {
|
2018-04-24 19:34:03 +00:00
|
|
|
const frequentlyUsed = map(this.frequentlyUsed.slice(), (item) => {
|
2018-01-16 18:48:05 +00:00
|
|
|
if (item.isCustom) {
|
|
|
|
return item;
|
|
|
|
}
|
2018-01-30 19:48:26 +00:00
|
|
|
return emojify(`${ item.content }`, { output: 'unicode' });
|
2018-01-16 18:48:05 +00:00
|
|
|
});
|
|
|
|
this.setState({ frequentlyUsed });
|
|
|
|
}
|
|
|
|
|
|
|
|
updateCustomEmojis() {
|
2018-09-25 19:28:42 +00:00
|
|
|
const customEmojis = map(this.customEmojis.slice(), item => ({ content: item.name, extension: item.extension, isCustom: true }));
|
2018-01-16 18:48:05 +00:00
|
|
|
this.setState({ customEmojis });
|
|
|
|
}
|
|
|
|
|
|
|
|
renderCategory(category, i) {
|
2018-09-25 19:28:42 +00:00
|
|
|
const { frequentlyUsed, customEmojis } = this.state;
|
|
|
|
const { emojisPerRow, width, baseUrl } = this.props;
|
|
|
|
|
2018-01-16 18:48:05 +00:00
|
|
|
let emojis = [];
|
|
|
|
if (i === 0) {
|
2018-09-25 19:28:42 +00:00
|
|
|
emojis = frequentlyUsed;
|
2018-01-16 18:48:05 +00:00
|
|
|
} else if (i === 1) {
|
2018-09-25 19:28:42 +00:00
|
|
|
emojis = customEmojis;
|
2018-01-16 18:48:05 +00:00
|
|
|
} else {
|
|
|
|
emojis = emojisByCategory[category];
|
|
|
|
}
|
|
|
|
return (
|
2018-01-30 19:48:26 +00:00
|
|
|
<EmojiCategory
|
|
|
|
emojis={emojis}
|
|
|
|
onEmojiSelected={emoji => this.onEmojiSelected(emoji)}
|
|
|
|
style={styles.categoryContainer}
|
2018-09-25 19:28:42 +00:00
|
|
|
size={emojisPerRow}
|
|
|
|
width={width}
|
|
|
|
baseUrl={baseUrl}
|
2018-01-30 19:48:26 +00:00
|
|
|
/>
|
2018-01-16 18:48:05 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
2019-06-27 16:16:05 +00:00
|
|
|
const { show, frequentlyUsed } = this.state;
|
2018-09-25 19:28:42 +00:00
|
|
|
const { tabEmojiStyle } = this.props;
|
|
|
|
|
|
|
|
if (!show) {
|
2018-01-30 19:48:26 +00:00
|
|
|
return null;
|
|
|
|
}
|
2018-01-16 18:48:05 +00:00
|
|
|
return (
|
2018-01-30 19:48:26 +00:00
|
|
|
<ScrollableTabView
|
2018-09-25 19:28:42 +00:00
|
|
|
renderTabBar={() => <TabBar tabEmojiStyle={tabEmojiStyle} />}
|
2018-01-30 19:48:26 +00:00
|
|
|
contentProps={scrollProps}
|
2018-09-11 16:32:52 +00:00
|
|
|
style={styles.background}
|
2018-01-30 19:48:26 +00:00
|
|
|
>
|
|
|
|
{
|
|
|
|
categories.tabs.map((tab, i) => (
|
2019-06-27 16:16:05 +00:00
|
|
|
(i === 0 && frequentlyUsed.length === 0) ? null // when no frequentlyUsed don't show the tab
|
|
|
|
: (
|
|
|
|
<ScrollView
|
|
|
|
key={tab.category}
|
|
|
|
tabLabel={tab.tabLabel}
|
|
|
|
style={styles.background}
|
|
|
|
{...scrollProps}
|
|
|
|
>
|
|
|
|
{this.renderCategory(tab.category, i)}
|
|
|
|
</ScrollView>
|
|
|
|
)))
|
2018-01-30 19:48:26 +00:00
|
|
|
}
|
|
|
|
</ScrollableTabView>
|
2018-01-16 18:48:05 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|