diff --git a/app/containers/EmojiPicker/EmojiCategory.tsx b/app/containers/EmojiPicker/EmojiCategory.tsx
index 1f5e74829..8be880ebf 100644
--- a/app/containers/EmojiPicker/EmojiCategory.tsx
+++ b/app/containers/EmojiPicker/EmojiCategory.tsx
@@ -3,14 +3,13 @@ import { Text, Pressable } from 'react-native';
import { FlatList } from 'react-native-gesture-handler';
import shortnameToUnicode from '../../lib/methods/helpers/shortnameToUnicode';
-import styles from './styles';
+import styles, { MIN_EMOJI_SIZE, MAX_EMOJI_SIZE } from './styles';
import CustomEmoji from './CustomEmoji';
import scrollPersistTaps from '../../lib/methods/helpers/scrollPersistTaps';
import { IEmoji, IEmojiCategory } from '../../definitions/IEmoji';
import { useTheme } from '../../theme';
import { isIOS } from '../../lib/methods/helpers';
-
-const MAX_EMOJI_SIZE = 50;
+import { useDimensions } from '../../dimensions';
interface IEmojiProps {
emoji: string | IEmoji;
@@ -18,7 +17,7 @@ interface IEmojiProps {
baseUrl: string;
}
-const Emoji = React.memo(({ emoji, size, baseUrl }: IEmojiProps) => {
+const Emoji = ({ emoji, size, baseUrl }: IEmojiProps): React.ReactElement => {
if (typeof emoji === 'string')
return (
@@ -28,12 +27,14 @@ const Emoji = React.memo(({ emoji, size, baseUrl }: IEmojiProps) => {
return (
);
-});
+};
-const EmojiCategory = ({ baseUrl, onEmojiSelected, emojis, width, tabsCount }: IEmojiCategory): React.ReactElement | null => {
- const emojiSize = width ? Math.min(width / tabsCount, MAX_EMOJI_SIZE) : MAX_EMOJI_SIZE;
- const numColumns = Math.trunc(width ? width / emojiSize : tabsCount);
+const EmojiCategory = ({ baseUrl, onEmojiSelected, emojis, tabsCount }: IEmojiCategory): React.ReactElement | null => {
const { colors } = useTheme();
+ const { width } = useDimensions();
+ const emojiSize = Math.min(Math.max(width / tabsCount, MIN_EMOJI_SIZE), MAX_EMOJI_SIZE);
+ const numColumns = Math.trunc(width / emojiSize);
+ const marginHorizontal = (width - numColumns * emojiSize) / 2;
const renderItem = (emoji: IEmoji | string) => (
(item?.isCustom && item.content) || item}
+ keyExtractor={item => (typeof item === 'string' ? item : item.content)}
data={emojis}
extraData={{ baseUrl, width }}
renderItem={({ item }) => renderItem(item)}
numColumns={numColumns}
initialNumToRender={45}
removeClippedSubviews
+ contentContainerStyle={{ marginHorizontal }}
{...scrollPersistTaps}
keyboardDismissMode={'none'}
/>
diff --git a/app/containers/EmojiPicker/frequentlyUsedEmojis.ts b/app/containers/EmojiPicker/frequentlyUsedEmojis.ts
index 6b6b574ca..89bb15787 100644
--- a/app/containers/EmojiPicker/frequentlyUsedEmojis.ts
+++ b/app/containers/EmojiPicker/frequentlyUsedEmojis.ts
@@ -1,11 +1,12 @@
import { useEffect, useState } from 'react';
import orderBy from 'lodash/orderBy';
+import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
import database from '../../lib/database';
import shortnameToUnicode from '../../lib/methods/helpers/shortnameToUnicode';
-import { IEmoji } from '../../definitions';
+import { IEmoji, TFrequentlyUsedEmojiModel } from '../../definitions';
-const useFrequentlyUsedEmoji = (): {
+export const useFrequentlyUsedEmoji = (): {
frequentlyUsed: (string | IEmoji)[];
loaded: boolean;
} => {
@@ -30,4 +31,29 @@ const useFrequentlyUsedEmoji = (): {
return { frequentlyUsed, loaded };
};
-export default useFrequentlyUsedEmoji;
+export const addFrequentlyUsed = async (emoji: IEmoji) => {
+ const db = database.active;
+ const freqEmojiCollection = db.get('frequently_used_emojis');
+ let freqEmojiRecord: TFrequentlyUsedEmojiModel;
+ try {
+ freqEmojiRecord = await freqEmojiCollection.find(emoji.content || emoji.name);
+ } catch (error) {
+ // Do nothing
+ }
+
+ await db.write(async () => {
+ if (freqEmojiRecord) {
+ await freqEmojiRecord.update(f => {
+ if (f.count) {
+ f.count += 1;
+ }
+ });
+ } else {
+ await freqEmojiCollection.create(f => {
+ f._raw = sanitizedRaw({ id: emoji.content || emoji.name }, freqEmojiCollection.schema);
+ Object.assign(f, emoji);
+ f.count = 1;
+ });
+ }
+ });
+};
diff --git a/app/containers/EmojiPicker/index.tsx b/app/containers/EmojiPicker/index.tsx
index 293363b90..c99a78bae 100644
--- a/app/containers/EmojiPicker/index.tsx
+++ b/app/containers/EmojiPicker/index.tsx
@@ -1,7 +1,6 @@
-import React, { useMemo, useState } from 'react';
+import React, { useMemo } from 'react';
import { View } from 'react-native';
import ScrollableTabView from 'react-native-scrollable-tab-view';
-import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
import { shallowEqual } from 'react-redux';
import TabBar from './TabBar';
@@ -9,15 +8,14 @@ import EmojiCategory from './EmojiCategory';
import Footer from './Footer';
import styles from './styles';
import categories from './categories';
-import database from '../../lib/database';
import { emojisByCategory } from './emojis';
import shortnameToUnicode from '../../lib/methods/helpers/shortnameToUnicode';
import log from '../../lib/methods/helpers/log';
import { useTheme } from '../../theme';
-import { IEmoji, ICustomEmojis, TFrequentlyUsedEmojiModel } from '../../definitions';
+import { IEmoji, ICustomEmojis } from '../../definitions';
import { useAppSelector } from '../../lib/hooks';
import { IEmojiPickerProps, EventTypes } from './interfaces';
-import useFrequentlyUsedEmoji from './frequentlyUsedEmojis';
+import { useFrequentlyUsedEmoji, addFrequentlyUsed } from './frequentlyUsedEmojis';
const EmojiPicker = ({
onItemClicked,
@@ -26,7 +24,6 @@ const EmojiPicker = ({
searching = false,
searchedEmojis = []
}: IEmojiPickerProps): React.ReactElement | null => {
- const [width, setWidth] = useState(null);
const { colors } = useTheme();
const { frequentlyUsed, loaded } = useFrequentlyUsedEmoji();
@@ -45,33 +42,6 @@ const EmojiPicker = ({
[allCustomEmojis]
);
- const addFrequentlyUsed = async (emoji: IEmoji) => {
- const db = database.active;
- const freqEmojiCollection = db.get('frequently_used_emojis');
- let freqEmojiRecord: TFrequentlyUsedEmojiModel;
- try {
- freqEmojiRecord = await freqEmojiCollection.find(emoji.content);
- } catch (error) {
- // Do nothing
- }
-
- await db.write(async () => {
- if (freqEmojiRecord) {
- await freqEmojiRecord.update(f => {
- if (f.count) {
- f.count += 1;
- }
- });
- } else {
- await freqEmojiCollection.create(f => {
- f._raw = sanitizedRaw({ id: emoji.content }, freqEmojiCollection.schema);
- Object.assign(f, emoji);
- f.count = 1;
- });
- }
- });
- };
-
const handleEmojiSelect = (emoji: IEmoji | string) => {
try {
if (typeof emoji === 'string') {
@@ -81,7 +51,7 @@ const EmojiPicker = ({
} else {
addFrequentlyUsed({
content: emoji.content,
- name: emoji.content,
+ name: emoji.name,
extension: emoji.extension,
isCustom: true
});
@@ -92,12 +62,6 @@ const EmojiPicker = ({
}
};
- const onLayout = ({
- nativeEvent: {
- layout: { width }
- }
- }: any) => setWidth(width);
-
const renderCategory = (category: keyof typeof emojisByCategory, i: number, label: string, tabsCount: number) => {
let emojis = [];
if (i === 0) {
@@ -112,7 +76,6 @@ const EmojiPicker = ({
emojis={emojis}
onEmojiSelected={(emoji: IEmoji | string) => handleEmojiSelect(emoji)}
style={styles.categoryContainer}
- width={width}
baseUrl={baseUrl}
tabLabel={label}
tabsCount={tabsCount}
@@ -127,13 +90,12 @@ const EmojiPicker = ({
const tabsCount = frequentlyUsed.length === 0 ? categories.tabs.length - 1 : categories.tabs.length;
return (
-
+
{searching ? (
handleEmojiSelect(emoji)}
style={styles.categoryContainer}
- width={width}
baseUrl={baseUrl}
tabLabel={'searching'}
tabsCount={tabsCount}
diff --git a/app/containers/EmojiPicker/styles.ts b/app/containers/EmojiPicker/styles.ts
index 073a226f1..d104d4cb9 100644
--- a/app/containers/EmojiPicker/styles.ts
+++ b/app/containers/EmojiPicker/styles.ts
@@ -2,6 +2,9 @@ import { StyleSheet } from 'react-native';
import sharedStyles from '../../views/Styles';
+export const MAX_EMOJI_SIZE = 50;
+export const MIN_EMOJI_SIZE = 42;
+
export default StyleSheet.create({
container: {
flex: 1
@@ -14,7 +17,8 @@ export default StyleSheet.create({
flex: 1,
alignItems: 'center',
justifyContent: 'center',
- paddingVertical: 10
+ paddingVertical: 10,
+ width: 44
},
tabEmoji: {
fontSize: 20,
@@ -66,5 +70,6 @@ export default StyleSheet.create({
width: 44,
justifyContent: 'center',
alignItems: 'center'
- }
+ },
+ emojiPickerContainer: { flex: 1 }
});
diff --git a/app/containers/MessageBox/EmojiSearchbar.tsx b/app/containers/MessageBox/EmojiSearchbar.tsx
index 074f1150e..69fadaf31 100644
--- a/app/containers/MessageBox/EmojiSearchbar.tsx
+++ b/app/containers/MessageBox/EmojiSearchbar.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from 'react';
+import React, { useState } from 'react';
import { View, Text, Pressable, TextInput, FlatList } from 'react-native';
import { FormTextInput } from '../TextInput/FormTextInput';
@@ -9,7 +9,7 @@ import { IEmoji } from '../../definitions';
import shortnameToUnicode from '../../lib/methods/helpers/shortnameToUnicode';
import CustomEmoji from '../EmojiPicker/CustomEmoji';
import styles from './styles';
-import useFrequentlyUsedEmoji from '../EmojiPicker/frequentlyUsedEmojis';
+import { useFrequentlyUsedEmoji, addFrequentlyUsed } from '../EmojiPicker/frequentlyUsedEmojis';
import { DEFAULT_EMOJIS } from '../EmojiPicker/emojis';
const BUTTON_HIT_SLOP = { top: 4, right: 4, bottom: 4, left: 4 };
@@ -37,14 +37,33 @@ const Emoji = ({ emoji, baseUrl }: { emoji: IEmoji | string; baseUrl: string }):
);
}
- return ;
+ return (
+
+ );
};
const ListItem = ({ emoji, onEmojiSelected, baseUrl }: IListItem): React.ReactElement => {
const key = typeof emoji === 'string' ? emoji : emoji?.name || emoji?.content;
+ const onPress = () => {
+ onEmojiSelected(emoji);
+ if (typeof emoji === 'string') {
+ addFrequentlyUsed({ content: emoji, name: emoji, isCustom: false });
+ } else {
+ addFrequentlyUsed({
+ content: emoji?.content || emoji?.name,
+ name: emoji?.name,
+ extension: emoji.extension,
+ isCustom: true
+ });
+ }
+ };
return (
- onEmojiSelected(emoji)}>
+
@@ -55,20 +74,14 @@ const EmojiSearchBar = React.forwardRef(
({ openEmoji, onChangeText, emojis, onEmojiSelected, baseUrl }, ref) => {
const { colors } = useTheme();
const [searchText, setSearchText] = useState('');
- const [frequentlyUsedEmojis, setFrequentlyUsed] = useState<(string | IEmoji)[]>();
- const { frequentlyUsed, loaded } = useFrequentlyUsedEmoji();
+ const { frequentlyUsed } = useFrequentlyUsedEmoji();
- useEffect(() => {
- if (loaded) {
- const frequentlyUsedWithDefaultEmojis = frequentlyUsed
- .filter(emoji => {
- if (typeof emoji === 'string') return !DEFAULT_EMOJIS.includes(emoji);
- return !DEFAULT_EMOJIS.includes(emoji.name);
- })
- .concat(DEFAULT_EMOJIS);
- setFrequentlyUsed(frequentlyUsedWithDefaultEmojis);
- }
- }, [loaded]);
+ const frequentlyUsedWithDefaultEmojis = frequentlyUsed
+ .filter(emoji => {
+ if (typeof emoji === 'string') return !DEFAULT_EMOJIS.includes(emoji);
+ return !DEFAULT_EMOJIS.includes(emoji.name);
+ })
+ .concat(DEFAULT_EMOJIS);
const handleTextChange = (text: string) => {
setSearchText(text);
@@ -76,10 +89,12 @@ const EmojiSearchBar = React.forwardRef(
};
return (
-
+
}
showsHorizontalScrollIndicator={false}
ListEmptyComponent={() => (
@@ -101,7 +116,7 @@ const EmojiSearchBar = React.forwardRef(
>
-
+
void;
- width: number | null;
style: StyleProp;
tabLabel: string;
tabsCount: number;
diff --git a/app/views/RoomView/styles.ts b/app/views/RoomView/styles.ts
index da52e8f37..ef9d03eb2 100644
--- a/app/views/RoomView/styles.ts
+++ b/app/views/RoomView/styles.ts
@@ -69,6 +69,7 @@ export default StyleSheet.create({
paddingHorizontal: 15
},
reactionPickerSearchbar: {
- paddingHorizontal: 20
+ paddingHorizontal: 20,
+ minHeight: 48
}
});