Chore: Evaluate emoji picker - TypeScript (#4069)
This commit is contained in:
parent
e36413c445
commit
8ca73e273a
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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} />
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
export const emojisByCategory: any = {
|
export const emojisByCategory = {
|
||||||
people: [
|
people: [
|
||||||
'grinning',
|
'grinning',
|
||||||
'grimacing',
|
'grimacing',
|
|
@ -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 => {
|
||||||
f.count += 1;
|
if (f.count) {
|
||||||
|
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;
|
|
||||||
|
|
|
@ -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>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 = '';
|
||||||
|
|
|
@ -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';
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
|
|
@ -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';
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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', () => {
|
||||||
|
|
|
@ -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 = {};
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue