diff --git a/src/components/Emojis.tsx b/src/components/Emojis.tsx index 2680b5ed..a053820f 100644 --- a/src/components/Emojis.tsx +++ b/src/components/Emojis.tsx @@ -6,7 +6,7 @@ import { getInstanceFrequentEmojis } from '@utils/slices/instancesSlice' import { chunk, forEach, groupBy, sortBy } from 'lodash' import React, { PropsWithChildren, RefObject, useEffect, useReducer, useState } from 'react' import { useTranslation } from 'react-i18next' -import { Keyboard, KeyboardAvoidingView, Text, TextInput, View } from 'react-native' +import { Keyboard, KeyboardAvoidingView, TextInput, View } from 'react-native' import FastImage from 'react-native-fast-image' import { ScrollView } from 'react-native-gesture-handler' import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context' @@ -66,10 +66,7 @@ const ComponentEmojis: React.FC = ({ const frequentEmojis = useSelector(getInstanceFrequentEmojis, () => true) useEffect(() => { if (data && data.length) { - let sortedEmojis: { - title: string - data: Pick[][] - }[] = [] + let sortedEmojis: EmojisState['emojis'] = [] forEach(groupBy(sortBy(data, ['category', 'shortcode']), 'category'), (value, key) => sortedEmojis.push({ title: key, data: chunk(value, 5) }) ) @@ -79,7 +76,8 @@ const ComponentEmojis: React.FC = ({ data: chunk( frequentEmojis.map(e => e.emoji), 5 - ) + ), + type: 'frequent' }) } emojisDispatch({ type: 'load', payload: sortedEmojis }) @@ -91,7 +89,10 @@ const ComponentEmojis: React.FC = ({ const [keyboardShown, setKeyboardShown] = useState(false) useEffect(() => { const showSubscription = Keyboard.addListener('keyboardWillShow', () => { - emojisDispatch({ type: 'target', payload: null }) + const anyInputHasFocus = inputProps.filter(props => props.ref.current?.isFocused()).length + if (anyInputHasFocus) { + emojisDispatch({ type: 'target', payload: null }) + } setKeyboardShown(true) }) const hideSubscription = Keyboard.addListener('keyboardWillHide', () => { @@ -102,7 +103,7 @@ const ComponentEmojis: React.FC = ({ showSubscription.remove() hideSubscription.remove() } - }, []) + }, [inputProps]) useEffect(() => { if (focusRef) { setTimeout(() => focusRef.current?.focus(), 500) @@ -117,16 +118,10 @@ const ComponentEmojis: React.FC = ({ : } + children={emojisState.targetProps ? : } /> diff --git a/src/components/Emojis/Button.tsx b/src/components/Emojis/Button.tsx index bb0b495c..6ccc2af8 100644 --- a/src/components/Emojis/Button.tsx +++ b/src/components/Emojis/Button.tsx @@ -2,7 +2,7 @@ import Icon from '@components/Icon' import { StyleConstants } from '@utils/styles/constants' import { useTheme } from '@utils/styles/ThemeManager' import React, { useContext } from 'react' -import { Keyboard, Pressable } from 'react-native' +import { Keyboard, Pressable, View } from 'react-native' import EmojisContext from './helpers/EmojisContext' const EmojisButton: React.FC = () => { @@ -23,17 +23,29 @@ const EmojisButton: React.FC = () => { emojisDispatch({ type: 'target', payload: targetProps }) }} hitSlop={StyleConstants.Spacing.S} - style={{ alignSelf: 'flex-end', padding: StyleConstants.Spacing.Global.PagePadding }} + style={{ + alignSelf: 'flex-end', + padding: StyleConstants.Spacing.Global.PagePadding / 2 + }} children={ - + + + } /> ) diff --git a/src/components/Emojis/List.tsx b/src/components/Emojis/List.tsx index a9facb2e..3c0c838c 100644 --- a/src/components/Emojis/List.tsx +++ b/src/components/Emojis/List.tsx @@ -1,3 +1,4 @@ +import Icon from '@components/Icon' import CustomText from '@components/Text' import { useAppDispatch } from '@root/store' import { useAccessibility } from '@utils/accessibility/AccessibilityManager' @@ -5,9 +6,17 @@ import { countInstanceEmoji } from '@utils/slices/instancesSlice' import { StyleConstants } from '@utils/styles/constants' import layoutAnimation from '@utils/styles/layoutAnimation' import { useTheme } from '@utils/styles/ThemeManager' -import React, { useCallback, useContext, useEffect, useRef } from 'react' +import { chunk } from 'lodash' +import React, { useCallback, useContext, useEffect, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' -import { AccessibilityInfo, findNodeHandle, Pressable, SectionList, View } from 'react-native' +import { + AccessibilityInfo, + findNodeHandle, + Pressable, + SectionList, + TextInput, + View +} from 'react-native' import FastImage from 'react-native-fast-image' import validUrl from 'valid-url' import EmojisContext from './helpers/EmojisContext' @@ -18,8 +27,8 @@ const EmojisList = React.memo( const { reduceMotionEnabled } = useAccessibility() const { t } = useTranslation() - const { emojisState, emojisDispatch } = useContext(EmojisContext) - const { colors } = useTheme() + const { emojisState } = useContext(EmojisContext) + const { colors, mode } = useTheme() const addEmoji = (shortcode: string) => { if (!emojisState.targetProps) { @@ -70,6 +79,7 @@ const EmojisList = React.memo( addEmoji(`:${emoji.shortcode}:`) dispatch(countInstanceEmoji(emoji)) }} + style={{ padding: StyleConstants.Spacing.S }} > ) @@ -107,23 +112,97 @@ const EmojisList = React.memo( } }, [emojisState.targetProps]) + const [search, setSearch] = useState('') + const searchLength = useRef(0) + useEffect(() => { + if ( + (search.length === 0 && searchLength.current === 1) || + (search.length === 1 && searchLength.current === 0) + ) { + layoutAnimation() + } + searchLength.current = search.length + }, [search.length, searchLength.current]) + return emojisState.targetProps ? ( - item[0].shortcode} - renderSectionHeader={({ section: { title } }) => ( - - {title} - - )} - renderItem={listItem} - windowSize={4} - contentContainerStyle={{ paddingHorizontal: StyleConstants.Spacing.Global.PagePadding }} - /> + + + + + + + + e.type !== 'frequent') + .flatMap(e => + e.data.flatMap(e => e).filter(emoji => emoji.shortcode.includes(search)) + ), + 2 + ) + } + ] + : emojisState.emojis + } + keyExtractor={item => item[0]?.shortcode} + renderSectionHeader={({ section: { title } }) => ( + + {title} + + )} + renderItem={listItem} + windowSize={4} + contentContainerStyle={{ + paddingHorizontal: StyleConstants.Spacing.Global.PagePadding, + minHeight: 32 * 2 + StyleConstants.Spacing.M * 3 + }} + /> + ) : null }, () => true diff --git a/src/components/Emojis/helpers/EmojisContext.tsx b/src/components/Emojis/helpers/EmojisContext.tsx index 1f2a2800..b7afe195 100644 --- a/src/components/Emojis/helpers/EmojisContext.tsx +++ b/src/components/Emojis/helpers/EmojisContext.tsx @@ -13,6 +13,7 @@ export type EmojisState = { emojis: { title: string data: Pick[][] + type?: 'frequent' }[] targetProps: inputProps | null inputProps: inputProps[]