Do not cover empty search results on Emoji picker (#6402)

This commit is contained in:
Elias Nahum
2022-06-17 05:04:07 -04:00
committed by GitHub
parent 6ea08b9dc2
commit 1ca401ef3c
6 changed files with 30 additions and 100 deletions

View File

@@ -3,24 +3,34 @@
import Fuse from 'fuse.js';
import React, {useCallback, useMemo} from 'react';
import {FlatList} from 'react-native';
import {FlatList, StyleSheet, View} from 'react-native';
import NoResultsWithTerm from '@components/no_results_with_term';
import {getEmojis, searchEmojis} from '@utils/emoji/helpers';
import EmojiItem from './emoji_item';
import NoResults from './no_results';
import type CustomEmojiModel from '@typings/database/models/servers/custom_emoji';
type Props = {
customEmojis: CustomEmojiModel[];
keyboardHeight: number;
skinTone: string;
searchTerm: string;
onEmojiPress: (emojiName: string) => void;
};
const EmojiFiltered = ({customEmojis, skinTone, searchTerm, onEmojiPress}: Props) => {
const style = StyleSheet.create({
noResultContainer: {
flexGrow: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
const EmojiFiltered = ({customEmojis, keyboardHeight, skinTone, searchTerm, onEmojiPress}: Props) => {
const emojis = useMemo(() => getEmojis(skinTone, customEmojis), [skinTone, customEmojis]);
const flatListStyle = useMemo(() => ({flexGrow: 1, paddingBottom: keyboardHeight}), [keyboardHeight]);
const fuse = useMemo(() => {
const options = {findAllMatches: true, ignoreLocation: true, includeMatches: true, shouldSort: false, includeScore: true};
@@ -37,6 +47,14 @@ const EmojiFiltered = ({customEmojis, skinTone, searchTerm, onEmojiPress}: Props
const keyExtractor = useCallback((item) => item, []);
const renderEmpty = useCallback(() => {
return (
<View style={style.noResultContainer}>
<NoResultsWithTerm term={searchTerm}/>
</View>
);
}, [searchTerm]);
const renderItem = useCallback(({item}) => {
return (
<EmojiItem
@@ -46,16 +64,15 @@ const EmojiFiltered = ({customEmojis, skinTone, searchTerm, onEmojiPress}: Props
);
}, []);
if (!data.length) {
return <NoResults searchTerm={searchTerm}/>;
}
return (
<FlatList
contentContainerStyle={flatListStyle}
data={data}
initialNumToRender={30}
keyboardDismissMode='interactive'
keyboardShouldPersistTaps='always'
keyExtractor={keyExtractor}
ListEmptyComponent={renderEmpty}
renderItem={renderItem}
removeClippedSubviews={false}
/>

View File

@@ -1,90 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {useIntl} from 'react-intl';
import {Text, View} from 'react-native';
import CompassIcon from '@components/compass_icon';
import {useTheme} from '@context/theme';
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
type Props = {
searchTerm: string;
}
const getStyleSheetFromTheme = makeStyleSheetFromTheme((theme) => {
return {
flex: {
flex: 1,
},
flexCenter: {
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
},
notFoundIcon: {
backgroundColor: changeOpacity(theme.centerChannelColor, 0.04),
width: 120,
height: 120,
borderRadius: 60,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
},
notFoundText: {
color: theme.centerChannelColor,
marginTop: 16,
},
notFoundText20: {
fontSize: 20,
fontWeight: '600',
},
notFoundText15: {
fontSize: 15,
},
};
});
const NoResults = ({searchTerm}: Props) => {
const theme = useTheme();
const intl = useIntl();
const styles = getStyleSheetFromTheme(theme);
const title = intl.formatMessage(
{
id: 'mobile.emoji_picker.search.not_found_title',
defaultMessage: 'No results found for "{searchTerm}"',
},
{
searchTerm,
},
);
const description = intl.formatMessage({
id: 'mobile.emoji_picker.search.not_found_description',
defaultMessage: 'Check the spelling or try another search.',
});
return (
<View style={[styles.flex, styles.flexCenter]}>
<View style={styles.flexCenter}>
<View style={styles.notFoundIcon}>
<CompassIcon
name='magnify'
size={72}
color={theme.buttonBg}
/>
</View>
<Text style={[styles.notFoundText, styles.notFoundText20]}>
{title}
</Text>
<Text style={[styles.notFoundText, styles.notFoundText15]}>
{description}
</Text>
</View>
</View>
);
};
export default NoResults;

View File

@@ -15,6 +15,7 @@ import {Preferences} from '@constants';
import {useServerUrl} from '@context/server';
import {useTheme} from '@context/theme';
import {debounce} from '@helpers/api/general';
import {useKeyboardHeight} from '@hooks/device';
import {queryAllCustomEmojis} from '@queries/servers/custom_emoji';
import {queryPreferencesByCategoryAndName} from '@queries/servers/preference';
import {observeConfigBooleanValue, observeRecentReactions} from '@queries/servers/system';
@@ -56,6 +57,7 @@ type Props = {
const EmojiPicker = ({customEmojis, customEmojisEnabled, onEmojiPress, recentEmojis, skinTone, testID = ''}: Props) => {
const theme = useTheme();
const serverUrl = useServerUrl();
const keyboardHeight = useKeyboardHeight();
const [width, setWidth] = useState(0);
const [searchTerm, setSearchTerm] = useState<string|undefined>();
const onLayout = useCallback(({nativeEvent}: LayoutChangeEvent) => setWidth(nativeEvent.layout.width), []);
@@ -75,6 +77,7 @@ const EmojiPicker = ({customEmojis, customEmojisEnabled, onEmojiPress, recentEmo
EmojiList = (
<EmojiFiltered
customEmojis={customEmojis}
keyboardHeight={keyboardHeight}
skinTone={skinTone}
searchTerm={searchTerm}
onEmojiPress={onEmojiPress}

View File

@@ -120,7 +120,7 @@ const Reactions = ({currentUserId, canAddReaction, canRemoveReaction, disabled,
onEmojiPress: handleAddReactionToPost,
};
showModal(Screens.EMOJI_PICKER, title, passProps);
showModal(Screens.EMOJI_PICKER, title, passProps, {modal: {swipeToDismiss: false}});
}), [intl, theme]);
const handleReactionPress = useCallback(async (emoji: string, remove: boolean) => {

View File

@@ -284,7 +284,7 @@ class CustomStatusModal extends NavigationComponent<Props, State> {
const title = intl.formatMessage({id: 'mobile.custom_status.choose_emoji', defaultMessage: 'Choose an emoji'});
const passProps = {closeButton: source, onEmojiPress: this.handleEmojiClick};
showModal(screen, title, passProps);
showModal(screen, title, passProps, {modal: {swipeToDismiss: false}});
});
});

View File

@@ -62,7 +62,7 @@ const ReactionBar = ({recentEmojis = [], postId}: QuickReactionProps) => {
const title = intl.formatMessage({id: 'mobile.post_info.add_reaction', defaultMessage: 'Add Reaction'});
const passProps = {closeButton, onEmojiPress: handleEmojiPress};
showModal(screen, title, passProps);
showModal(screen, title, passProps, {modal: {swipeToDismiss: false}});
}, [intl, theme]);
let containerSize = LARGE_CONTAINER_SIZE;