Fix custom emoji in emoji picker, persist skin tone (#5258)

pull/165/head
Eugen Rochko 2017-10-07 19:02:30 +02:00 committed by GitHub
parent 967e70663f
commit d2dee6ea43
4 changed files with 66 additions and 22 deletions

View File

@ -31,6 +31,19 @@ let EmojiPicker, Emoji; // load asynchronously
const backgroundImageFn = () => `${assetHost}/emoji/sheet.png`; const backgroundImageFn = () => `${assetHost}/emoji/sheet.png`;
const listenerOptions = detectPassiveEvents.hasSupport ? { passive: true } : false; const listenerOptions = detectPassiveEvents.hasSupport ? { passive: true } : false;
const categoriesSort = [
'recent',
'custom',
'people',
'nature',
'foods',
'activity',
'places',
'objects',
'symbols',
'flags',
];
class ModifierPickerMenu extends React.PureComponent { class ModifierPickerMenu extends React.PureComponent {
static propTypes = { static propTypes = {
@ -141,6 +154,9 @@ class EmojiPickerMenu extends React.PureComponent {
arrowOffsetLeft: PropTypes.string, arrowOffsetLeft: PropTypes.string,
arrowOffsetTop: PropTypes.string, arrowOffsetTop: PropTypes.string,
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
skinTone: PropTypes.number.isRequired,
onSkinTone: PropTypes.func.isRequired,
autoPlay: PropTypes.bool,
}; };
static defaultProps = { static defaultProps = {
@ -151,7 +167,6 @@ class EmojiPickerMenu extends React.PureComponent {
state = { state = {
modifierOpen: false, modifierOpen: false,
modifier: 1,
}; };
handleDocumentClick = e => { handleDocumentClick = e => {
@ -214,20 +229,18 @@ class EmojiPickerMenu extends React.PureComponent {
} }
handleModifierChange = modifier => { handleModifierChange = modifier => {
if (modifier !== this.state.modifier) { this.props.onSkinTone(modifier);
this.setState({ modifier });
}
} }
render () { render () {
const { loading, style, intl } = this.props; const { loading, style, intl, custom_emojis, autoPlay, skinTone } = this.props;
if (loading) { if (loading) {
return <div style={{ width: 299 }} />; return <div style={{ width: 299 }} />;
} }
const title = intl.formatMessage(messages.emoji); const title = intl.formatMessage(messages.emoji);
const { modifierOpen, modifier } = this.state; const { modifierOpen } = this.state;
return ( return (
<div className={classNames('emoji-picker-dropdown__menu', { selecting: modifierOpen })} style={style} ref={this.setRef}> <div className={classNames('emoji-picker-dropdown__menu', { selecting: modifierOpen })} style={style} ref={this.setRef}>
@ -235,20 +248,22 @@ class EmojiPickerMenu extends React.PureComponent {
perLine={8} perLine={8}
emojiSize={22} emojiSize={22}
sheetSize={32} sheetSize={32}
custom={buildCustomEmojis(custom_emojis, autoPlay)}
color='' color=''
emoji='' emoji=''
set='twitter' set='twitter'
title={title} title={title}
i18n={this.getI18n()} i18n={this.getI18n()}
onClick={this.handleClick} onClick={this.handleClick}
skin={modifier} include={categoriesSort}
skin={skinTone}
showPreview={false} showPreview={false}
backgroundImageFn={backgroundImageFn} backgroundImageFn={backgroundImageFn}
/> />
<ModifierPicker <ModifierPicker
active={modifierOpen} active={modifierOpen}
modifier={modifier} modifier={skinTone}
onOpen={this.handleModifierOpen} onOpen={this.handleModifierOpen}
onClose={this.handleModifierClose} onClose={this.handleModifierClose}
onChange={this.handleModifierChange} onChange={this.handleModifierChange}
@ -267,6 +282,8 @@ export default class EmojiPickerDropdown extends React.PureComponent {
autoPlay: PropTypes.bool, autoPlay: PropTypes.bool,
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
onPickEmoji: PropTypes.func.isRequired, onPickEmoji: PropTypes.func.isRequired,
onSkinTone: PropTypes.func.isRequired,
skinTone: PropTypes.number.isRequired,
}; };
state = { state = {
@ -279,8 +296,6 @@ export default class EmojiPickerDropdown extends React.PureComponent {
} }
onShowDropdown = () => { onShowDropdown = () => {
const { autoPlay } = this.props;
this.setState({ active: true }); this.setState({ active: true });
if (!EmojiPicker) { if (!EmojiPicker) {
@ -289,8 +304,7 @@ export default class EmojiPickerDropdown extends React.PureComponent {
EmojiPickerAsync().then(EmojiMart => { EmojiPickerAsync().then(EmojiMart => {
EmojiPicker = EmojiMart.Picker; EmojiPicker = EmojiMart.Picker;
Emoji = EmojiMart.Emoji; Emoji = EmojiMart.Emoji;
// populate custom emoji in search
EmojiMart.emojiIndex.search('', { custom: buildCustomEmojis(this.props.custom_emojis, autoPlay) });
this.setState({ loading: false }); this.setState({ loading: false });
}).catch(() => { }).catch(() => {
this.setState({ loading: false }); this.setState({ loading: false });
@ -327,7 +341,7 @@ export default class EmojiPickerDropdown extends React.PureComponent {
} }
render () { render () {
const { intl, onPickEmoji } = this.props; const { intl, onPickEmoji, autoPlay, onSkinTone, skinTone } = this.props;
const title = intl.formatMessage(messages.emoji); const title = intl.formatMessage(messages.emoji);
const { active, loading } = this.state; const { active, loading } = this.state;
@ -347,6 +361,9 @@ export default class EmojiPickerDropdown extends React.PureComponent {
loading={loading} loading={loading}
onClose={this.onHideDropdown} onClose={this.onHideDropdown}
onPick={onPickEmoji} onPick={onPickEmoji}
autoPlay={autoPlay}
onSkinTone={onSkinTone}
skinTone={skinTone}
/> />
</Overlay> </Overlay>
</div> </div>

View File

@ -1,9 +1,17 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import EmojiPickerDropdown from '../components/emoji_picker_dropdown'; import EmojiPickerDropdown from '../components/emoji_picker_dropdown';
import { changeSetting } from '../../../actions/settings';
const mapStateToProps = state => ({ const mapStateToProps = state => ({
custom_emojis: state.get('custom_emojis'), custom_emojis: state.get('custom_emojis'),
autoPlay: state.getIn(['meta', 'auto_play_gif']), autoPlay: state.getIn(['meta', 'auto_play_gif']),
skinTone: state.getIn(['settings', 'skinTone']),
}); });
export default connect(mapStateToProps)(EmojiPickerDropdown); const mapDispatchToProps = dispatch => ({
onSkinTone: skinTone => {
dispatch(changeSetting(['skinTone'], skinTone));
},
});
export default connect(mapStateToProps, mapDispatchToProps)(EmojiPickerDropdown);

View File

@ -7,6 +7,8 @@ import uuid from '../uuid';
const initialState = ImmutableMap({ const initialState = ImmutableMap({
onboarded: false, onboarded: false,
skinTone: 1,
home: ImmutableMap({ home: ImmutableMap({
shows: ImmutableMap({ shows: ImmutableMap({
reblog: true, reblog: true,

View File

@ -2653,19 +2653,36 @@ button.icon-button.active i.fa-retweet {
flex-direction: column; flex-direction: column;
} }
@keyframes pulse { @keyframes heartbeat {
0% { from {
opacity: 1; transform: scale(1);
transform-origin: center center;
animation-timing-function: ease-out;
} }
100% { 10% {
opacity: 0.5; transform: scale(0.91);
animation-timing-function: ease-in;
}
17% {
transform: scale(0.98);
animation-timing-function: ease-out;
}
33% {
transform: scale(0.87);
animation-timing-function: ease-in;
}
45% {
transform: scale(1);
animation-timing-function: ease-out;
} }
} }
.pulse-loading { .pulse-loading {
animation: pulse 1s ease-in-out infinite; animation: heartbeat 1.5s ease-in-out infinite both;
animation-direction: alternate;
} }
.emoji-picker-dropdown__menu { .emoji-picker-dropdown__menu {