Chore: Evaluate emoji picker - TypeScript (#4069)

This commit is contained in:
Alex Junior 2022-05-06 22:06:08 -03:00 committed by GitHub
parent e36413c445
commit 8ca73e273a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 100 additions and 131 deletions

View File

@ -1,7 +1,7 @@
import { Action } from 'redux'; import { Action } from 'redux';
import { ICustomEmojis } from '../reducers/customEmojis';
import { SET_CUSTOM_EMOJIS } from './actionsTypes'; import { SET_CUSTOM_EMOJIS } from './actionsTypes';
import { ICustomEmojis } from '../definitions';
export interface ISetCustomEmojis extends Action { export interface ISetCustomEmojis extends Action {
emojis: ICustomEmojis; emojis: ICustomEmojis;

View File

@ -8,7 +8,6 @@ const CustomEmoji = React.memo(
<FastImage <FastImage
style={style} style={style}
source={{ source={{
// @ts-ignore
uri: `${baseUrl}/emoji-custom/${encodeURIComponent(emoji.content || emoji.name)}.${emoji.extension}`, uri: `${baseUrl}/emoji-custom/${encodeURIComponent(emoji.content || emoji.name)}.${emoji.extension}`,
priority: FastImage.priority.high priority: FastImage.priority.high
}} }}

View File

@ -26,16 +26,17 @@ const renderEmoji = (emoji: IEmoji, size: number, baseUrl: string) => {
); );
}; };
class EmojiCategory extends React.Component<Partial<IEmojiCategory>> { class EmojiCategory extends React.Component<IEmojiCategory> {
renderItem(emoji: any) { renderItem(emoji: IEmoji) {
const { baseUrl, onEmojiSelected } = this.props; const { baseUrl, onEmojiSelected } = this.props;
return ( return (
<TouchableOpacity <TouchableOpacity
activeOpacity={0.7} activeOpacity={0.7}
// @ts-ignore
key={emoji && emoji.isCustom ? emoji.content : emoji} key={emoji && emoji.isCustom ? emoji.content : emoji}
onPress={() => onEmojiSelected!(emoji)} onPress={() => onEmojiSelected(emoji)}
testID={`reaction-picker-${emoji && emoji.isCustom ? emoji.content : emoji}`}> testID={`reaction-picker-${emoji && emoji.isCustom ? emoji.content : emoji}`}>
{renderEmoji(emoji, EMOJI_SIZE, baseUrl!)} {renderEmoji(emoji, EMOJI_SIZE, baseUrl)}
</TouchableOpacity> </TouchableOpacity>
); );
} }
@ -51,7 +52,6 @@ class EmojiCategory extends React.Component<Partial<IEmojiCategory>> {
const marginHorizontal = (width - numColumns * EMOJI_SIZE) / 2; const marginHorizontal = (width - numColumns * EMOJI_SIZE) / 2;
return ( return (
// @ts-ignore
<FlatList <FlatList
contentContainerStyle={{ marginHorizontal }} contentContainerStyle={{ marginHorizontal }}
// rerender FlatList in case of width changes // rerender FlatList in case of width changes

View File

@ -1,20 +1,20 @@
import React from 'react'; import React from 'react';
import { Text, TouchableOpacity, View } from 'react-native'; import { StyleProp, Text, TextStyle, TouchableOpacity, View } from 'react-native';
import styles from './styles'; import styles from './styles';
import { themes } from '../../lib/constants'; import { themes } from '../../lib/constants';
import { TSupportedThemes } from '../../theme'; import { TSupportedThemes } from '../../theme';
interface ITabBarProps { interface ITabBarProps {
goToPage: Function; goToPage?: (page: number) => void;
activeTab: number; activeTab?: number;
tabs: []; tabs?: string[];
tabEmojiStyle: object; tabEmojiStyle: StyleProp<TextStyle>;
theme: TSupportedThemes; theme: TSupportedThemes;
} }
export default class TabBar extends React.Component<Partial<ITabBarProps>> { export default class TabBar extends React.Component<ITabBarProps> {
shouldComponentUpdate(nextProps: any) { shouldComponentUpdate(nextProps: ITabBarProps) {
const { activeTab, theme } = this.props; const { activeTab, theme } = this.props;
if (nextProps.activeTab !== activeTab) { if (nextProps.activeTab !== activeTab) {
return true; return true;
@ -30,16 +30,20 @@ export default class TabBar extends React.Component<Partial<ITabBarProps>> {
return ( return (
<View style={styles.tabsContainer}> <View style={styles.tabsContainer}>
{tabs!.map((tab, i) => ( {tabs?.map((tab, i) => (
<TouchableOpacity <TouchableOpacity
activeOpacity={0.7} activeOpacity={0.7}
key={tab} key={tab}
onPress={() => goToPage!(i)} onPress={() => {
if (goToPage) {
goToPage(i);
}
}}
style={styles.tab} style={styles.tab}
testID={`reaction-picker-${tab}`}> testID={`reaction-picker-${tab}`}>
<Text style={[styles.tabEmoji, tabEmojiStyle]}>{tab}</Text> <Text style={[styles.tabEmoji, tabEmojiStyle]}>{tab}</Text>
{activeTab === i ? ( {activeTab === i ? (
<View style={[styles.activeTabLine, { backgroundColor: themes[theme!].tintColor }]} /> <View style={[styles.activeTabLine, { backgroundColor: themes[theme].tintColor }]} />
) : ( ) : (
<View style={styles.tabLine} /> <View style={styles.tabLine} />
)} )}

View File

@ -1,4 +1,4 @@
export const emojisByCategory: any = { export const emojisByCategory = {
people: [ people: [
'grinning', 'grinning',
'grimacing', 'grimacing',

View File

@ -1,38 +1,34 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { View } from 'react-native'; import { StyleProp, TextStyle, View } from 'react-native';
import ScrollableTabView from 'react-native-scrollable-tab-view'; import ScrollableTabView from 'react-native-scrollable-tab-view';
import { dequal } from 'dequal'; import { dequal } from 'dequal';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import orderBy from 'lodash/orderBy'; import orderBy from 'lodash/orderBy';
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord'; import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
import { ImageStyle } from '@rocket.chat/react-native-fast-image';
import TabBar from './TabBar'; import TabBar from './TabBar';
import EmojiCategory from './EmojiCategory'; import EmojiCategory from './EmojiCategory';
import styles from './styles'; import styles from './styles';
import categories from './categories'; import categories from './categories';
import database from '../../lib/database'; import database from '../../lib/database';
import { emojisByCategory } from '../../emojis'; import { emojisByCategory } from './emojis';
import protectedFunction from '../../lib/methods/helpers/protectedFunction'; import protectedFunction from '../../lib/methods/helpers/protectedFunction';
import shortnameToUnicode from '../../utils/shortnameToUnicode'; import shortnameToUnicode from '../../utils/shortnameToUnicode';
import log from '../../utils/log'; import log from '../../utils/log';
import { themes } from '../../lib/constants'; import { themes } from '../../lib/constants';
import { TSupportedThemes, withTheme } from '../../theme'; import { TSupportedThemes, withTheme } from '../../theme';
import { IEmoji } from '../../definitions/IEmoji'; import { IEmoji, TGetCustomEmoji, IApplicationState, ICustomEmojis, TFrequentlyUsedEmojiModel } from '../../definitions';
const scrollProps = {
keyboardShouldPersistTaps: 'always',
keyboardDismissMode: 'none'
};
interface IEmojiPickerProps { interface IEmojiPickerProps {
isMessageContainsOnlyEmoji: boolean; isMessageContainsOnlyEmoji?: boolean;
getCustomEmoji?: Function; getCustomEmoji?: TGetCustomEmoji;
baseUrl: string; baseUrl: string;
customEmojis?: any; customEmojis: ICustomEmojis;
style: object; style?: StyleProp<ImageStyle>;
theme: TSupportedThemes; theme: TSupportedThemes;
onEmojiSelected?: ((emoji: any) => void) | ((keyboardId: any, params?: any) => void); onEmojiSelected: (emoji: string, shortname?: string) => void;
tabEmojiStyle?: object; tabEmojiStyle?: StyleProp<TextStyle>;
} }
interface IEmojiPickerState { interface IEmojiPickerState {
@ -65,7 +61,7 @@ class EmojiPicker extends Component<IEmojiPickerProps, IEmojiPickerState> {
this.setState({ show: true }); this.setState({ show: true });
} }
shouldComponentUpdate(nextProps: any, nextState: any) { shouldComponentUpdate(nextProps: IEmojiPickerProps, nextState: IEmojiPickerState) {
const { frequentlyUsed, show, width } = this.state; const { frequentlyUsed, show, width } = this.state;
const { theme } = this.props; const { theme } = this.props;
if (nextProps.theme !== theme) { if (nextProps.theme !== theme) {
@ -92,12 +88,12 @@ class EmojiPicker extends Component<IEmojiPickerProps, IEmojiPickerState> {
extension: emoji.extension, extension: emoji.extension,
isCustom: true isCustom: true
}); });
onEmojiSelected!(`:${emoji.content}:`); onEmojiSelected(`:${emoji.content}:`);
} else { } else {
const content = emoji; const content = emoji;
this._addFrequentlyUsed({ content, isCustom: false }); this._addFrequentlyUsed({ content, isCustom: false });
const shortname = `:${emoji}:`; const shortname = `:${emoji}:`;
onEmojiSelected!(shortnameToUnicode(shortname), shortname); onEmojiSelected(shortnameToUnicode(shortname), shortname);
} }
} catch (e) { } catch (e) {
log(e); log(e);
@ -107,9 +103,8 @@ class EmojiPicker extends Component<IEmojiPickerProps, IEmojiPickerState> {
_addFrequentlyUsed = protectedFunction(async (emoji: IEmoji) => { _addFrequentlyUsed = protectedFunction(async (emoji: IEmoji) => {
const db = database.active; const db = database.active;
const freqEmojiCollection = db.get('frequently_used_emojis'); const freqEmojiCollection = db.get('frequently_used_emojis');
let freqEmojiRecord: any; let freqEmojiRecord: TFrequentlyUsedEmojiModel;
try { try {
// @ts-ignore
freqEmojiRecord = await freqEmojiCollection.find(emoji.content); freqEmojiRecord = await freqEmojiCollection.find(emoji.content);
} catch (error) { } catch (error) {
// Do nothing // Do nothing
@ -117,11 +112,13 @@ class EmojiPicker extends Component<IEmojiPickerProps, IEmojiPickerState> {
await db.write(async () => { await db.write(async () => {
if (freqEmojiRecord) { if (freqEmojiRecord) {
await freqEmojiRecord.update((f: any) => { await freqEmojiRecord.update(f => {
if (f.count) {
f.count += 1; f.count += 1;
}
}); });
} else { } else {
await freqEmojiCollection.create((f: any) => { await freqEmojiCollection.create(f => {
f._raw = sanitizedRaw({ id: emoji.content }, freqEmojiCollection.schema); f._raw = sanitizedRaw({ id: emoji.content }, freqEmojiCollection.schema);
Object.assign(f, emoji); Object.assign(f, emoji);
f.count = 1; f.count = 1;
@ -149,7 +146,7 @@ class EmojiPicker extends Component<IEmojiPickerProps, IEmojiPickerState> {
} }
}: any) => this.setState({ width }); }: any) => this.setState({ width });
renderCategory(category: any, i: number, label: string) { renderCategory(category: keyof typeof emojisByCategory, i: number, label: string) {
const { frequentlyUsed, customEmojis, width } = this.state; const { frequentlyUsed, customEmojis, width } = this.state;
const { baseUrl } = this.props; const { baseUrl } = this.props;
@ -166,7 +163,7 @@ class EmojiPicker extends Component<IEmojiPickerProps, IEmojiPickerState> {
emojis={emojis} emojis={emojis}
onEmojiSelected={(emoji: IEmoji) => this.onEmojiSelected(emoji)} onEmojiSelected={(emoji: IEmoji) => this.onEmojiSelected(emoji)}
style={styles.categoryContainer} style={styles.categoryContainer}
width={width!} width={width}
baseUrl={baseUrl} baseUrl={baseUrl}
tabLabel={label} tabLabel={label}
/> />
@ -184,10 +181,12 @@ class EmojiPicker extends Component<IEmojiPickerProps, IEmojiPickerState> {
<View onLayout={this.onLayout} style={{ flex: 1 }}> <View onLayout={this.onLayout} style={{ flex: 1 }}>
<ScrollableTabView <ScrollableTabView
renderTabBar={() => <TabBar tabEmojiStyle={tabEmojiStyle} theme={theme} />} renderTabBar={() => <TabBar tabEmojiStyle={tabEmojiStyle} theme={theme} />}
/* @ts-ignore*/ contentProps={{
contentProps={scrollProps} keyboardShouldPersistTaps: 'always',
keyboardDismissMode: 'none'
}}
style={{ backgroundColor: themes[theme].focusedBackground }}> style={{ backgroundColor: themes[theme].focusedBackground }}>
{categories.tabs.map((tab, i) => {categories.tabs.map((tab: any, i) =>
i === 0 && frequentlyUsed.length === 0 i === 0 && frequentlyUsed.length === 0
? null // when no frequentlyUsed don't show the tab ? null // when no frequentlyUsed don't show the tab
: this.renderCategory(tab.category, i, tab.tabLabel) : this.renderCategory(tab.category, i, tab.tabLabel)
@ -198,9 +197,8 @@ class EmojiPicker extends Component<IEmojiPickerProps, IEmojiPickerState> {
} }
} }
const mapStateToProps = (state: any) => ({ const mapStateToProps = (state: IApplicationState) => ({
customEmojis: state.customEmojis customEmojis: state.customEmojis
}); });
// TODO - remove this as any, at the new PR to fix the HOC erros export default connect(mapStateToProps)(withTheme(EmojiPicker));
export default connect(mapStateToProps)(withTheme(EmojiPicker)) as any;

View File

@ -10,9 +10,7 @@ import database from '../../lib/database';
import { Button } from '../ActionSheet'; import { Button } from '../ActionSheet';
import { useDimensions } from '../../dimensions'; import { useDimensions } from '../../dimensions';
import sharedStyles from '../../views/Styles'; import sharedStyles from '../../views/Styles';
import { TFrequentlyUsedEmojiModel } from '../../definitions/IFrequentlyUsedEmoji'; import { TAnyMessageModel, TFrequentlyUsedEmojiModel } from '../../definitions';
import { TAnyMessageModel } from '../../definitions';
import { IEmoji } from '../../definitions/IEmoji';
type TItem = TFrequentlyUsedEmojiModel | string; type TItem = TFrequentlyUsedEmojiModel | string;
@ -83,7 +81,7 @@ const HeaderItem = ({ item, onReaction, server, theme }: THeaderItem) => {
style={[styles.headerItem, { backgroundColor: themes[theme].auxiliaryBackground }]} style={[styles.headerItem, { backgroundColor: themes[theme].auxiliaryBackground }]}
theme={theme}> theme={theme}>
{emojiModel?.isCustom ? ( {emojiModel?.isCustom ? (
<CustomEmoji style={styles.customEmoji} emoji={emojiModel as IEmoji} baseUrl={server} /> <CustomEmoji style={styles.customEmoji} emoji={emojiModel} baseUrl={server} />
) : ( ) : (
<Text style={styles.headerIcon}>{shortnameToUnicode(`:${emoji}:`)}</Text> <Text style={styles.headerIcon}>{shortnameToUnicode(`:${emoji}:`)}</Text>
)} )}

View File

@ -7,7 +7,6 @@ import EmojiPicker from '../EmojiPicker';
import styles from './styles'; import styles from './styles';
import { themes } from '../../lib/constants'; import { themes } from '../../lib/constants';
import { TSupportedThemes, withTheme } from '../../theme'; import { TSupportedThemes, withTheme } from '../../theme';
import { IEmoji } from '../../definitions/IEmoji';
interface IMessageBoxEmojiKeyboard { interface IMessageBoxEmojiKeyboard {
theme: TSupportedThemes; theme: TSupportedThemes;
@ -22,7 +21,7 @@ export default class EmojiKeyboard extends React.PureComponent<IMessageBoxEmojiK
this.baseUrl = state.share.server.server || state.server.server; this.baseUrl = state.share.server.server || state.server.server;
} }
onEmojiSelected = (emoji: IEmoji) => { onEmojiSelected = (emoji: string) => {
KeyboardRegistry.onItemSelected('EmojiKeyboard', { emoji }); KeyboardRegistry.onItemSelected('EmojiKeyboard', { emoji });
}; };
@ -32,7 +31,7 @@ export default class EmojiKeyboard extends React.PureComponent<IMessageBoxEmojiK
<View <View
style={[styles.emojiKeyboardContainer, { borderTopColor: themes[theme].borderColor }]} style={[styles.emojiKeyboardContainer, { borderTopColor: themes[theme].borderColor }]}
testID='messagebox-keyboard-emoji'> testID='messagebox-keyboard-emoji'>
<EmojiPicker onEmojiSelected={this.onEmojiSelected} baseUrl={this.baseUrl} /> <EmojiPicker onEmojiSelected={this.onEmojiSelected} baseUrl={this.baseUrl} theme={theme} />
</View> </View>
); );
} }

View File

@ -13,7 +13,7 @@ import TextInput, { IThemedTextInput } from '../../presentation/TextInput';
import { userTyping as userTypingAction } from '../../actions/room'; import { userTyping as userTypingAction } from '../../actions/room';
import styles from './styles'; import styles from './styles';
import database from '../../lib/database'; import database from '../../lib/database';
import { emojis } from '../../emojis'; import { emojis } from '../EmojiPicker/emojis';
import log, { events, logEvent } from '../../utils/log'; import log, { events, logEvent } from '../../utils/log';
import RecordAudio from './RecordAudio'; import RecordAudio from './RecordAudio';
import I18n from '../../i18n'; import I18n from '../../i18n';
@ -49,7 +49,7 @@ import { sanitizeLikeString } from '../../lib/database/utils';
import { CustomIcon } from '../CustomIcon'; import { CustomIcon } from '../CustomIcon';
import { IMessage } from '../../definitions/IMessage'; import { IMessage } from '../../definitions/IMessage';
import { forceJpgExtension } from './forceJpgExtension'; import { forceJpgExtension } from './forceJpgExtension';
import { IBaseScreen, IPreviewItem, IUser, TSubscriptionModel, TThreadModel } from '../../definitions'; import { IBaseScreen, IPreviewItem, IUser, TGetCustomEmoji, TSubscriptionModel, TThreadModel } from '../../definitions';
import { MasterDetailInsideStackParamList } from '../../stacks/MasterDetailStack/types'; import { MasterDetailInsideStackParamList } from '../../stacks/MasterDetailStack/types';
import { getPermalinkMessage, hasPermission, search, sendFileMessage } from '../../lib/methods'; import { getPermalinkMessage, hasPermission, search, sendFileMessage } from '../../lib/methods';
import { Services } from '../../lib/services'; import { Services } from '../../lib/services';
@ -92,7 +92,7 @@ export interface IMessageBoxProps extends IBaseScreen<MasterDetailInsideStackPar
FileUpload_MediaTypeWhiteList: string; FileUpload_MediaTypeWhiteList: string;
FileUpload_MaxFileSize: number; FileUpload_MaxFileSize: number;
Message_AudioRecorderEnabled: boolean; Message_AudioRecorderEnabled: boolean;
getCustomEmoji: Function; getCustomEmoji: TGetCustomEmoji;
editCancel: Function; editCancel: Function;
editRequest: Function; editRequest: Function;
onSubmit: Function; onSubmit: Function;
@ -537,7 +537,7 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
} }
}; };
onEmojiSelected = (keyboardId: any, params: any) => { onEmojiSelected = (keyboardId: string, params: { emoji: string }) => {
const { text } = this; const { text } = this;
const { emoji } = params; const { emoji } = params;
let newText = ''; let newText = '';

View File

@ -8,8 +8,7 @@ import debounce from '../../utils/debounce';
import { getMessageTranslation } from './utils'; import { getMessageTranslation } from './utils';
import { TSupportedThemes, withTheme } from '../../theme'; import { TSupportedThemes, withTheme } from '../../theme';
import openLink from '../../utils/openLink'; import openLink from '../../utils/openLink';
import { TGetCustomEmoji } from '../../definitions/IEmoji'; import { IAttachment, TAnyMessageModel, TGetCustomEmoji } from '../../definitions';
import { IAttachment, TAnyMessageModel } from '../../definitions';
import { IRoomInfoParam } from '../../views/SearchMessagesView'; import { IRoomInfoParam } from '../../views/SearchMessagesView';
import { E2E_MESSAGE_TYPE, E2E_STATUS, messagesStatus } from '../../lib/constants'; import { E2E_MESSAGE_TYPE, E2E_STATUS, messagesStatus } from '../../lib/constants';

View File

@ -1,11 +0,0 @@
import Model from '@nozbe/watermelondb/Model';
export interface ICustomEmoji {
_id: string;
name?: string;
aliases?: string[];
extension: string;
_updatedAt: Date;
}
export type TCustomEmojiModel = ICustomEmoji & Model;

View File

@ -1,31 +1,43 @@
// TODO: evaluate unification with IEmoji import Model from '@nozbe/watermelondb/Model';
import { StyleProp } from 'react-native';
import { ImageStyle } from '@rocket.chat/react-native-fast-image';
export interface IEmoji { export interface IEmoji {
content?: string; content: string;
name?: string; name: string;
extension?: string; extension: string;
isCustom?: boolean; isCustom: boolean;
count?: number;
}
export interface ICustomEmojis {
[key: string]: Pick<IEmoji, 'name' | 'extension'>;
} }
export interface ICustomEmoji { export interface ICustomEmoji {
baseUrl?: string; baseUrl?: string;
emoji: IEmoji; emoji: IEmoji;
style: any; style: StyleProp<ImageStyle>;
}
export interface ICustomEmojiModel {
_id: string;
name?: string;
aliases?: string[];
extension: string;
_updatedAt: Date;
} }
export interface IEmojiCategory { export interface IEmojiCategory {
baseUrl: string; baseUrl: string;
emojis: IEmoji[]; emojis: IEmoji[];
onEmojiSelected: Function; onEmojiSelected: (emoji: IEmoji) => void;
emojisPerRow: number; width: number | null;
width: number; style: StyleProp<ImageStyle>;
style: any;
tabLabel: string; tabLabel: string;
} }
// TODO: copied from reducers/customEmojis. We can unify later.
export interface IReduxEmoji {
name: string;
extension: any;
}
export type TGetCustomEmoji = (name: string) => any; export type TGetCustomEmoji = (name: string) => any;
export type TFrequentlyUsedEmojiModel = IEmoji & Model;
export type TCustomEmojiModel = ICustomEmojiModel & Model;

View File

@ -1,11 +0,0 @@
import Model from '@nozbe/watermelondb/Model';
// TODO: evaluate unification with IEmoji
export interface IFrequentlyUsedEmoji {
content?: string;
extension?: string;
isCustom: boolean;
count: number;
}
export type TFrequentlyUsedEmojiModel = IFrequentlyUsedEmoji & Model;

View File

@ -12,8 +12,7 @@ export * from './IRoom';
export * from './IMessage'; export * from './IMessage';
export * from './IThread'; export * from './IThread';
export * from './IThreadMessage'; export * from './IThreadMessage';
export * from './ICustomEmoji'; export * from './IEmoji';
export * from './IFrequentlyUsedEmoji';
export * from './IUpload'; export * from './IUpload';
export * from './ISettings'; export * from './ISettings';
export * from './IRole'; export * from './IRole';

View File

@ -1,12 +1,11 @@
import orderBy from 'lodash/orderBy'; import orderBy from 'lodash/orderBy';
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord'; import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
import { ICustomEmojis } from '../../reducers/customEmojis';
import { store as reduxStore } from '../store/auxStore'; import { store as reduxStore } from '../store/auxStore';
import database from '../database'; import database from '../database';
import log from '../../utils/log'; import log from '../../utils/log';
import { setCustomEmojis as setCustomEmojisAction } from '../../actions/customEmojis'; import { setCustomEmojis as setCustomEmojisAction } from '../../actions/customEmojis';
import { ICustomEmoji, TCustomEmojiModel } from '../../definitions'; import { ICustomEmojiModel, TCustomEmojiModel, ICustomEmojis } from '../../definitions';
import sdk from '../services/sdk'; import sdk from '../services/sdk';
import { compareServerVersion } from './helpers/compareServerVersion'; import { compareServerVersion } from './helpers/compareServerVersion';
@ -16,7 +15,7 @@ interface IUpdateEmojis {
allRecords: TCustomEmojiModel[]; allRecords: TCustomEmojiModel[];
} }
const getUpdatedSince = (allEmojis: ICustomEmoji[]) => { const getUpdatedSince = (allEmojis: ICustomEmojiModel[]) => {
if (!allEmojis.length) { if (!allEmojis.length) {
return null; return null;
} }

View File

@ -1,6 +1,7 @@
import { setCustomEmojis } from '../actions/customEmojis'; import { setCustomEmojis } from '../actions/customEmojis';
import { ICustomEmojis, initialState } from './customEmojis'; import { initialState } from './customEmojis';
import { mockedStore } from './mockedStore'; import { mockedStore } from './mockedStore';
import { ICustomEmojis } from '../definitions';
describe('test reducer', () => { describe('test reducer', () => {
it('should return initial state', () => { it('should return initial state', () => {

View File

@ -1,15 +1,5 @@
import { SET_CUSTOM_EMOJIS } from '../actions/actionsTypes'; import { SET_CUSTOM_EMOJIS } from '../actions/actionsTypes';
import { TApplicationActions } from '../definitions'; import { ICustomEmojis, TApplicationActions } from '../definitions';
// There are at least three interfaces for emoji, but none of them includes only this data.
interface IEmoji {
name: string;
extension: string;
}
export interface ICustomEmojis {
[key: string]: IEmoji;
}
export const initialState: ICustomEmojis = {}; export const initialState: ICustomEmojis = {};

View File

@ -19,10 +19,8 @@ import SafeAreaView from '../../containers/SafeAreaView';
import getThreadName from '../../lib/methods/getThreadName'; import getThreadName from '../../lib/methods/getThreadName';
import styles from './styles'; import styles from './styles';
import { ChatsStackParamList } from '../../stacks/types'; import { ChatsStackParamList } from '../../stacks/types';
import { ISubscription, SubscriptionType } from '../../definitions/ISubscription';
import { IEmoji } from '../../definitions/IEmoji';
import { IRoomInfoParam } from '../SearchMessagesView'; import { IRoomInfoParam } from '../SearchMessagesView';
import { TMessageModel, IUrl } from '../../definitions'; import { TMessageModel, IEmoji, ISubscription, SubscriptionType, IUrl } from '../../definitions';
import { Services } from '../../lib/services'; import { Services } from '../../lib/services';
interface IMessagesViewProps { interface IMessagesViewProps {

View File

@ -19,7 +19,7 @@ interface IReactionPickerProps {
show: boolean; show: boolean;
isMasterDetail: boolean; isMasterDetail: boolean;
reactionClose: () => void; reactionClose: () => void;
onEmojiSelected: Function; // TODO: properly type this onEmojiSelected: (shortname: string, id: string) => void;
width: number; width: number;
height: number; height: number;
theme: TSupportedThemes; theme: TSupportedThemes;
@ -31,7 +31,7 @@ class ReactionPicker extends React.Component<IReactionPickerProps> {
return nextProps.show !== show || width !== nextProps.width || height !== nextProps.height; return nextProps.show !== show || width !== nextProps.width || height !== nextProps.height;
} }
onEmojiSelected = (emoji: string, shortname: string) => { onEmojiSelected = (emoji: string, shortname?: string) => {
// standard emojis: `emoji` is unicode and `shortname` is :joy: // standard emojis: `emoji` is unicode and `shortname` is :joy:
// custom emojis: only `emoji` is returned with shortname type (:joy:) // custom emojis: only `emoji` is returned with shortname type (:joy:)
// to set reactions, we need shortname type // to set reactions, we need shortname type
@ -70,11 +70,7 @@ class ReactionPicker extends React.Component<IReactionPickerProps> {
} }
]} ]}
testID='reaction-picker'> testID='reaction-picker'>
<EmojiPicker <EmojiPicker theme={theme} onEmojiSelected={this.onEmojiSelected} baseUrl={baseUrl} />
// tabEmojiStyle={tabEmojiStyle}
onEmojiSelected={this.onEmojiSelected}
baseUrl={baseUrl}
/>
</View> </View>
</Modal> </Modal>
) : null; ) : null;

View File

@ -9,7 +9,6 @@ import { dequal } from 'dequal';
import { EdgeInsets, withSafeAreaInsets } from 'react-native-safe-area-context'; import { EdgeInsets, withSafeAreaInsets } from 'react-native-safe-area-context';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { IReduxEmoji } from '../../definitions/IEmoji';
import Touch from '../../utils/touch'; import Touch from '../../utils/touch';
import { replyBroadcast } from '../../actions/messages'; import { replyBroadcast } from '../../actions/messages';
import database from '../../lib/database'; import database from '../../lib/database';
@ -76,9 +75,10 @@ import {
TAnyMessageModel, TAnyMessageModel,
TMessageModel, TMessageModel,
TSubscriptionModel, TSubscriptionModel,
TThreadModel TThreadModel,
IEmoji,
ICustomEmojis
} from '../../definitions'; } from '../../definitions';
import { ICustomEmojis } from '../../reducers/customEmojis';
import { E2E_MESSAGE_TYPE, E2E_STATUS, MESSAGE_TYPE_ANY_LOAD, MessageTypeLoad, themes } from '../../lib/constants'; import { E2E_MESSAGE_TYPE, E2E_STATUS, MESSAGE_TYPE_ANY_LOAD, MessageTypeLoad, themes } from '../../lib/constants';
import { TListRef } from './List/List'; import { TListRef } from './List/List';
import { ModalStackParamList } from '../../stacks/MasterDetailStack/types'; import { ModalStackParamList } from '../../stacks/MasterDetailStack/types';
@ -931,8 +931,7 @@ class RoomView extends React.Component<IRoomViewProps, IRoomViewState> {
}); });
}; };
// TODO: We need to unify getCustomEmoji = (name: string): Pick<IEmoji, 'name' | 'extension'> | null => {
getCustomEmoji = (name: string): IReduxEmoji | null => {
const { customEmojis } = this.props; const { customEmojis } = this.props;
const emoji = customEmojis[name]; const emoji = customEmojis[name];
if (emoji) { if (emoji) {