[Gekidou MM-46370] Fix slow response time which switching between files and messages tabs (#6579)

This commit is contained in:
Jason Frerich
2022-08-25 08:27:55 -05:00
committed by GitHub
parent f9e37c37af
commit d88bf8e535
7 changed files with 405 additions and 271 deletions

View File

@@ -3,7 +3,7 @@
import {ActionType, Post} from '@constants';
import DatabaseManager from '@database/manager';
import {getPostById, prepareDeletePost} from '@queries/servers/post';
import {getPostById, prepareDeletePost, queryPostsById} from '@queries/servers/post';
import {getCurrentUserId} from '@queries/servers/system';
import {getIsCRTEnabled, prepareThreadsFromReceivedPosts} from '@queries/servers/thread';
import {generateId} from '@utils/general';
@@ -233,3 +233,12 @@ export async function storePostsForChannel(
return {error};
}
}
export async function getPosts(serverUrl: string, ids: string[]) {
try {
const {database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
return queryPostsById(database, ids).fetch();
} catch (error) {
return [];
}
}

View File

@@ -66,7 +66,6 @@ const Files = ({canDownloadFiles, failed, filesInfo, isReplyPost, layoutWidth, l
const updateFileForGallery = (idx: number, file: FileInfo) => {
'worklet';
filesForGallery.value[idx] = file;
};

View File

@@ -0,0 +1,196 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useCallback, useEffect, useMemo, useState} from 'react';
import {StyleSheet, FlatList, ListRenderItemInfo, StyleProp, View, ViewStyle} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import File from '@components/files/file';
import NoResultsWithTerm from '@components/no_results_with_term';
import {ITEM_HEIGHT} from '@components/option_item';
import {Screens} from '@constants';
import {useTheme} from '@context/theme';
import {useIsTablet} from '@hooks/device';
import {useImageAttachments} from '@hooks/files';
import {bottomSheet, dismissBottomSheet} from '@screens/navigation';
import NavigationStore from '@store/navigation_store';
import {isImage, isVideo} from '@utils/file';
import {fileToGalleryItem, openGalleryAtIndex} from '@utils/gallery';
import {bottomSheetSnapPoint} from '@utils/helpers';
import {getViewPortWidth} from '@utils/images';
import {TabTypes} from '@utils/search';
import {preventDoubleTap} from '@utils/tap';
import FileOptions from './file_options';
import {HEADER_HEIGHT} from './file_options/header';
import type ChannelModel from '@typings/database/models/servers/channel';
const styles = StyleSheet.create({
container: {
flex: 1,
marginHorizontal: 20,
},
});
type Props = {
canDownloadFiles: boolean;
fileChannels: ChannelModel[];
fileInfos: FileInfo[];
publicLinkEnabled: boolean;
paddingTop: StyleProp<ViewStyle>;
searchValue: string;
}
const galleryIdentifier = 'search-files-location';
const FileResults = ({
canDownloadFiles,
fileChannels,
fileInfos,
publicLinkEnabled,
paddingTop,
searchValue,
}: Props) => {
const theme = useTheme();
const isTablet = useIsTablet();
const insets = useSafeAreaInsets();
const [lastViewedIndex, setLastViewedIndex] = useState<number | undefined>(undefined);
const containerStyle = useMemo(() => ({top: fileInfos.length ? 8 : 0}), [fileInfos]);
const {images: imageAttachments, nonImages: nonImageAttachments} = useImageAttachments(fileInfos, publicLinkEnabled);
const channelNames = useMemo(() => fileChannels.reduce<{[id: string]: string | undefined}>((acc, v) => {
acc[v.id] = v.displayName;
return acc;
}, {}), [fileChannels]);
const orderedFilesForGallery = useMemo(() => {
const filesForGallery = imageAttachments.concat(nonImageAttachments);
return filesForGallery.sort((a: FileInfo, b: FileInfo) => {
return (b.create_at || 0) - (a.create_at || 0);
});
}, [imageAttachments, nonImageAttachments]);
const filesForGalleryIndexes = useMemo(() => orderedFilesForGallery.reduce<{[id: string]: number | undefined}>((acc, v, idx) => {
if (v.id) {
acc[v.id] = idx;
}
return acc;
}, {}), [orderedFilesForGallery]);
const handlePreviewPress = useCallback(preventDoubleTap((idx: number) => {
const items = orderedFilesForGallery.map((f) => fileToGalleryItem(f, f.user_id));
openGalleryAtIndex(galleryIdentifier, idx, items);
}), [orderedFilesForGallery]);
const handleOptionsPress = useCallback((item: number) => {
setLastViewedIndex(item);
let numberOptions = 1;
numberOptions += canDownloadFiles ? 1 : 0;
numberOptions += publicLinkEnabled ? 1 : 0;
const renderContent = () => (
<FileOptions
fileInfo={orderedFilesForGallery[item]}
/>
);
bottomSheet({
closeButtonId: 'close-search-file-options',
renderContent,
snapPoints: [bottomSheetSnapPoint(numberOptions, ITEM_HEIGHT, insets.bottom) + HEADER_HEIGHT, 10],
theme,
title: '',
});
}, [canDownloadFiles, publicLinkEnabled, orderedFilesForGallery, theme]);
// This effect handles the case where a user has the FileOptions Modal
// open and the server changes the ability to download files or copy public
// links. Reopen the Bottom Sheet again so the new options are added or
// removed.
useEffect(() => {
if (lastViewedIndex === undefined) {
return;
}
if (NavigationStore.getNavigationTopComponentId() === Screens.BOTTOM_SHEET) {
dismissBottomSheet().then(() => {
handleOptionsPress(lastViewedIndex);
});
}
}, [canDownloadFiles, publicLinkEnabled]);
const updateFileForGallery = (idx: number, file: FileInfo) => {
'worklet';
orderedFilesForGallery[idx] = file;
};
const renderItem = useCallback(({item}: ListRenderItemInfo<FileInfo>) => {
const container: StyleProp<ViewStyle> = fileInfos.length > 1 ? styles.container : undefined;
const isSingleImage = orderedFilesForGallery.length === 1 && (isImage(orderedFilesForGallery[0]) || isVideo(orderedFilesForGallery[0]));
const isReplyPost = false;
return (
<View
style={container}
key={item.id}
>
<File
asCard={true}
canDownloadFiles={canDownloadFiles}
channelName={channelNames[item.channel_id!]}
file={item}
galleryIdentifier={galleryIdentifier}
inViewPort={true}
index={filesForGalleryIndexes[item.id!] || 0}
isSingleImage={isSingleImage}
key={item.id}
nonVisibleImagesCount={0}
onOptionsPress={handleOptionsPress}
onPress={handlePreviewPress}
publicLinkEnabled={publicLinkEnabled}
showDate={true}
updateFileForGallery={updateFileForGallery}
wrapperWidth={(getViewPortWidth(isReplyPost, isTablet) - 6)}
/>
</View>
);
}, [
(orderedFilesForGallery.length === 1) && orderedFilesForGallery[0].mime_type,
canDownloadFiles,
channelNames,
fileInfos.length > 1,
filesForGalleryIndexes,
handleOptionsPress,
handlePreviewPress,
isTablet,
publicLinkEnabled,
theme,
]);
const noResults = useMemo(() => (
<NoResultsWithTerm
term={searchValue}
type={TabTypes.FILES}
/>
), [searchValue]);
return (
<FlatList
ListEmptyComponent={noResults}
contentContainerStyle={[paddingTop, containerStyle]}
data={orderedFilesForGallery}
indicatorStyle='black'
initialNumToRender={10}
listKey={'files'}
maxToRenderPerBatch={5}
nestedScrollEnabled={true}
refreshing={false}
removeClippedSubviews={true}
renderItem={renderItem}
scrollEventThrottle={16}
scrollToOverflowEnabled={true}
showsVerticalScrollIndicator={true}
testID='search_results.post_list.flat_list'
/>
);
};
export default FileResults;

View File

@@ -8,7 +8,6 @@ import {combineLatest, of as of$} from 'rxjs';
import {map, switchMap} from 'rxjs/operators';
import {queryChannelsById} from '@queries/servers/channel';
import {queryPostsById} from '@queries/servers/post';
import {observeLicense, observeConfigBooleanValue} from '@queries/servers/system';
import {observeCurrentUser} from '@queries/servers/user';
import {getTimezone} from '@utils/user';
@@ -16,19 +15,12 @@ import {getTimezone} from '@utils/user';
import Results from './results';
import type {WithDatabaseArgs} from '@typings/database/database';
import type PostModel from '@typings/database/models/servers/post';
type enhancedProps = WithDatabaseArgs & {
postIds: string[];
fileChannelIds: string[];
}
const sortPosts = (a: PostModel, b: PostModel) => a.createAt - b.createAt;
const enhance = withObservables(['postIds', 'fileChannelIds'], ({database, postIds, fileChannelIds}: enhancedProps) => {
const posts = queryPostsById(database, postIds).observeWithColumns(['type', 'createAt']).pipe(
switchMap((pp) => of$(pp.sort(sortPosts))),
);
const enhance = withObservables(['fileChannelIds'], ({database, fileChannelIds}: enhancedProps) => {
const fileChannels = queryChannelsById(database, fileChannelIds).observeWithColumns(['displayName']);
const currentUser = observeCurrentUser(database);
@@ -45,7 +37,6 @@ const enhance = withObservables(['postIds', 'fileChannelIds'], ({database, postI
return {
currentTimezone: currentUser.pipe((switchMap((user) => of$(getTimezone(user?.timezone))))),
isTimezoneEnabled: observeConfigBooleanValue(database, 'ExperimentalTimezone'),
posts,
fileChannels,
canDownloadFiles,
publicLinkEnabled: observeConfigBooleanValue(database, 'EnablePublicLink'),

View File

@@ -0,0 +1,88 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useCallback, useMemo} from 'react';
import {FlatList, ListRenderItemInfo, StyleProp, ViewStyle} from 'react-native';
import NoResultsWithTerm from '@components/no_results_with_term';
import DateSeparator from '@components/post_list/date_separator';
import PostWithChannelInfo from '@components/post_with_channel_info';
import {Screens} from '@constants';
import {getDateForDateLine, isDateLine, selectOrderedPosts} from '@utils/post_list';
import {TabTypes} from '@utils/search';
import type PostModel from '@typings/database/models/servers/post';
type Props = {
currentTimezone: string;
isTimezoneEnabled: boolean;
posts: PostModel[];
paddingTop: StyleProp<ViewStyle>;
searchValue: string;
}
const PostResults = ({
currentTimezone,
isTimezoneEnabled,
posts,
paddingTop,
searchValue,
}: Props) => {
const orderedPosts = useMemo(() => selectOrderedPosts(posts, 0, false, '', '', false, isTimezoneEnabled, currentTimezone, false).reverse(), [posts]);
const containerStyle = useMemo(() => ({top: posts.length ? 4 : 8}), [posts]);
const renderItem = useCallback(({item}: ListRenderItemInfo<string|PostModel>) => {
if (typeof item === 'string') {
if (isDateLine(item)) {
return (
<DateSeparator
date={getDateForDateLine(item)}
timezone={isTimezoneEnabled ? currentTimezone : null}
/>
);
}
return null;
}
if ('message' in item) {
return (
<PostWithChannelInfo
location={Screens.SEARCH}
post={item}
testID='search_results.post_list'
/>
);
}
return null;
}, []);
const noResults = useMemo(() => (
<NoResultsWithTerm
term={searchValue}
type={TabTypes.MESSAGES}
/>
), [searchValue]);
return (
<FlatList
ListEmptyComponent={noResults}
contentContainerStyle={[paddingTop, containerStyle]}
data={orderedPosts}
indicatorStyle='black'
initialNumToRender={5}
listKey={'posts'}
maxToRenderPerBatch={5}
nestedScrollEnabled={true}
refreshing={false}
removeClippedSubviews={true}
renderItem={renderItem}
scrollEventThrottle={16}
scrollToOverflowEnabled={true}
showsVerticalScrollIndicator={true}
style={containerStyle}
testID='search_results.post_list.flat_list'
/>
);
};
export default PostResults;

View File

@@ -1,45 +1,41 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useCallback, useEffect, useMemo, useState} from 'react';
import {StyleSheet, FlatList, ListRenderItemInfo, StyleProp, View, ViewStyle} from 'react-native';
import Animated from 'react-native-reanimated';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import React, {useMemo} from 'react';
import {ScaledSize, StyleSheet, useWindowDimensions, View} from 'react-native';
import Animated, {useAnimatedStyle, withTiming} from 'react-native-reanimated';
import File from '@components/files/file';
import Loading from '@components/loading';
import NoResultsWithTerm from '@components/no_results_with_term';
import {ITEM_HEIGHT} from '@components/option_item';
import DateSeparator from '@components/post_list/date_separator';
import PostWithChannelInfo from '@components/post_with_channel_info';
import {Screens} from '@constants';
import Loading from '@app/components/loading';
import {useTheme} from '@context/theme';
import {useIsTablet} from '@hooks/device';
import {useImageAttachments} from '@hooks/files';
import {bottomSheet, dismissBottomSheet} from '@screens/navigation';
import NavigationStore from '@store/navigation_store';
import {isImage, isVideo} from '@utils/file';
import {fileToGalleryItem, openGalleryAtIndex} from '@utils/gallery';
import {bottomSheetSnapPoint} from '@utils/helpers';
import {getViewPortWidth} from '@utils/images';
import {getDateForDateLine, isDateLine, selectOrderedPosts} from '@utils/post_list';
import {TabTypes, TabType} from '@utils/search';
import {preventDoubleTap} from '@utils/tap';
import FileOptions from './file_options';
import {HEADER_HEIGHT} from './file_options/header';
import FileResults from './file_results';
import PostResults from './post_results';
import type ChannelModel from '@typings/database/models/servers/channel';
import type PostModel from '@typings/database/models/servers/post';
const styles = StyleSheet.create({
container: {
flex: 1,
marginHorizontal: 20,
},
});
const duration = 250;
const AnimatedFlatList = Animated.createAnimatedComponent(FlatList);
const getStyles = (dimensions: ScaledSize) => {
return StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
width: dimensions.width * 2,
},
result: {
flex: 1,
width: dimensions.width,
},
loading: {
justifyContent: 'center',
flex: 1,
width: dimensions.width,
},
});
};
type Props = {
canDownloadFiles: boolean;
@@ -50,13 +46,12 @@ type Props = {
loading: boolean;
posts: PostModel[];
publicLinkEnabled: boolean;
scrollPaddingTop: number;
searchValue: string;
selectedTab: TabType;
}
const galleryIdentifier = 'search-files-location';
const SearchResults = ({
const Results = ({
canDownloadFiles,
currentTimezone,
fileChannels,
@@ -65,207 +60,61 @@ const SearchResults = ({
loading,
posts,
publicLinkEnabled,
scrollPaddingTop,
searchValue,
selectedTab,
}: Props) => {
const dimensions = useWindowDimensions();
const theme = useTheme();
const isTablet = useIsTablet();
const insets = useSafeAreaInsets();
const [lastViewedIndex, setLastViewedIndex] = useState<number | undefined>(undefined);
const styles = useMemo(() => getStyles(dimensions), [dimensions]);
const orderedPosts = useMemo(() => selectOrderedPosts(posts, 0, false, '', '', false, isTimezoneEnabled, currentTimezone, false).reverse(), [posts]);
const {images: imageAttachments, nonImages: nonImageAttachments} = useImageAttachments(fileInfos, publicLinkEnabled);
const channelNames = useMemo(() => fileChannels.reduce<{[id: string]: string | undefined}>((acc, v) => {
acc[v.id] = v.displayName;
return acc;
}, {}), [fileChannels]);
const containerStyle = useMemo(() => {
let padding = 0;
if (selectedTab === TabTypes.MESSAGES) {
padding = posts.length ? 4 : 8;
} else {
padding = fileInfos.length ? 8 : 0;
}
return {top: padding};
}, [selectedTab, posts, fileInfos]);
const filesForGallery = useMemo(() => imageAttachments.concat(nonImageAttachments),
[imageAttachments, nonImageAttachments]);
const orderedFilesForGallery = useMemo(() => (
filesForGallery.sort((a: FileInfo, b: FileInfo) => {
return (b.create_at || 0) - (a.create_at || 0);
})
), [filesForGallery]);
const filesForGalleryIndexes = useMemo(() => orderedFilesForGallery.reduce<{[id: string]: number | undefined}>((acc, v, idx) => {
if (v.id) {
acc[v.id] = idx;
}
return acc;
}, {}), [orderedFilesForGallery]);
const handlePreviewPress = useCallback(preventDoubleTap((idx: number) => {
const items = orderedFilesForGallery.map((f) => fileToGalleryItem(f, f.user_id));
openGalleryAtIndex(galleryIdentifier, idx, items);
}), [orderedFilesForGallery]);
const snapPoints = useMemo(() => {
let numberOptions = 1;
if (canDownloadFiles) {
numberOptions += 1;
}
if (publicLinkEnabled) {
numberOptions += 1;
}
return [bottomSheetSnapPoint(numberOptions, ITEM_HEIGHT, insets.bottom) + HEADER_HEIGHT, 10];
}, [canDownloadFiles, publicLinkEnabled]);
const handleOptionsPress = useCallback((item: number) => {
setLastViewedIndex(item);
const renderContent = () => {
return (
<FileOptions
fileInfo={orderedFilesForGallery[item]}
/>
);
const transform = useAnimatedStyle(() => {
const translateX = selectedTab === TabTypes.MESSAGES ? 0 : -dimensions.width;
return {
transform: [
{translateX: withTiming(translateX, {duration})},
],
};
bottomSheet({
closeButtonId: 'close-search-file-options',
renderContent,
snapPoints,
theme,
title: '',
});
}, [orderedFilesForGallery, snapPoints, theme]);
}, [selectedTab, dimensions.width]);
// This effect handles the case where a user has the FileOptions Modal
// open and the server changes the ability to download files or copy public
// links. Reopen the Bottom Sheet again so the new options are added or
// removed.
useEffect(() => {
if (lastViewedIndex === undefined) {
return;
}
if (NavigationStore.getNavigationTopComponentId() === 'BottomSheet') {
dismissBottomSheet().then(() => {
handleOptionsPress(lastViewedIndex);
});
}
}, [canDownloadFiles, publicLinkEnabled]);
const paddingTop = useMemo(() => (
{paddingTop: scrollPaddingTop, flexGrow: 1}
), [scrollPaddingTop]);
const renderItem = useCallback(({item}: ListRenderItemInfo<string|FileInfo | Post>) => {
if (item === 'loading') {
return (
return (
<>
{loading &&
<Loading
color={theme.buttonBg}
size='large'
containerStyle={[styles.loading, paddingTop]}
/>
);
}
if (typeof item === 'string') {
if (isDateLine(item)) {
return (
<DateSeparator
date={getDateForDateLine(item)}
timezone={isTimezoneEnabled ? currentTimezone : null}
/>
);
}
return null;
}
if ('message' in item) {
return (
<PostWithChannelInfo
location={Screens.SEARCH}
post={item}
testID='search_results.post_list'
/>
);
}
const updateFileForGallery = (idx: number, file: FileInfo) => {
'worklet';
orderedFilesForGallery[idx] = file;
};
const container: StyleProp<ViewStyle> = fileInfos.length > 1 ? styles.container : undefined;
const isSingleImage = orderedFilesForGallery.length === 1 && (isImage(orderedFilesForGallery[0]) || isVideo(orderedFilesForGallery[0]));
const isReplyPost = false;
return (
<View
style={container}
key={item.id}
>
<File
channelName={channelNames[item.channel_id!]}
galleryIdentifier={galleryIdentifier}
key={item.id}
canDownloadFiles={canDownloadFiles}
file={item}
index={filesForGalleryIndexes[item.id!] || 0}
onPress={handlePreviewPress}
onOptionsPress={handleOptionsPress}
isSingleImage={isSingleImage}
showDate={true}
publicLinkEnabled={publicLinkEnabled}
updateFileForGallery={updateFileForGallery}
inViewPort={true}
wrapperWidth={(getViewPortWidth(isReplyPost, isTablet) - 6)}
nonVisibleImagesCount={0}
asCard={true}
/>
</View>
);
}, [
theme,
(orderedFilesForGallery.length === 1) && orderedFilesForGallery[0].mime_type,
handleOptionsPress,
channelNames,
filesForGalleryIndexes,
canDownloadFiles,
handlePreviewPress,
publicLinkEnabled,
isTablet,
fileInfos.length > 1,
]);
const noResults = useMemo(() => {
return (
<NoResultsWithTerm
term={searchValue}
type={selectedTab}
/>
);
}, [searchValue, selectedTab]);
let data;
if (loading) {
data = ['loading'];
} else {
data = selectedTab === TabTypes.MESSAGES ? orderedPosts : orderedFilesForGallery;
}
return (
<AnimatedFlatList
ListEmptyComponent={noResults}
data={data}
scrollToOverflowEnabled={true}
showsVerticalScrollIndicator={true}
scrollEventThrottle={16}
indicatorStyle='black'
refreshing={false}
renderItem={renderItem}
nestedScrollEnabled={true}
removeClippedSubviews={true}
style={containerStyle}
testID='search_results.post_list.flat_list'
/>
{!loading &&
<Animated.View style={[styles.container, transform]}>
<View style={styles.result} >
<PostResults
currentTimezone={currentTimezone}
isTimezoneEnabled={isTimezoneEnabled}
posts={posts}
paddingTop={paddingTop}
searchValue={searchValue}
/>
</View>
<View style={styles.result} >
<FileResults
canDownloadFiles={canDownloadFiles}
fileChannels={fileChannels}
fileInfos={fileInfos}
publicLinkEnabled={publicLinkEnabled}
paddingTop={paddingTop}
searchValue={searchValue}
/>
</View>
</Animated.View>
}
</>
);
};
export default SearchResults;
export default Results;

View File

@@ -8,6 +8,7 @@ import {FlatList, LayoutChangeEvent, Platform, StyleSheet, ViewProps} from 'reac
import Animated, {useAnimatedStyle, withTiming} from 'react-native-reanimated';
import {Edge, SafeAreaView, useSafeAreaInsets} from 'react-native-safe-area-context';
import {getPosts} from '@actions/local/post';
import {addSearchToTeamSearchHistory} from '@actions/local/team';
import {searchPosts, searchFiles} from '@actions/remote/search';
import Autocomplete from '@components/autocomplete';
@@ -27,11 +28,13 @@ import Initial from './initial';
import Results from './results';
import Header from './results/header';
import type PostModel from '@typings/database/models/servers/post';
const EDGES: Edge[] = ['bottom', 'left', 'right'];
const AnimatedFlatList = Animated.createAnimatedComponent(FlatList);
const emptyFileResults: FileInfo[] = [];
const emptyPostResults: string[] = [];
const emptyPosts: PostModel[] = [];
const emptyChannelIds: string[] = [];
const dummyData = [1];
@@ -87,8 +90,7 @@ const SearchScreen = ({teamId}: Props) => {
const [loading, setLoading] = useState(false);
const [resultsLoading, setResultsLoading] = useState(false);
const [lastSearchedValue, setLastSearchedValue] = useState('');
const [postIds, setPostIds] = useState<string[]>(emptyPostResults);
const [posts, setPosts] = useState<PostModel[]>(emptyPosts);
const [fileInfos, setFileInfos] = useState<FileInfo[]>(emptyFileResults);
const [fileChannelIds, setFileChannelIds] = useState<string[]>([]);
@@ -130,9 +132,11 @@ const SearchScreen = ({teamId}: Props) => {
]);
setFileInfos(files?.length ? files : emptyFileResults);
setPostIds(postResults?.order?.length ? postResults.order : emptyPostResults);
if (postResults.order) {
const postModels = await getPosts(serverUrl, postResults.order);
setPosts(postModels.length ? postModels : emptyPosts);
}
setFileChannelIds(channels?.length ? channels : emptyChannelIds);
handleLoading(false);
setShowResults(true);
}, [handleCancelAndClearSearch, handleLoading, showResults]);
@@ -184,29 +188,14 @@ const SearchScreen = ({teamId}: Props) => {
/>
), [searchValue, searchTeamId, handleRecentSearch, handleTextChange]);
const resultsComponent = useMemo(() => (
<Results
loading={resultsLoading}
selectedTab={selectedTab}
searchValue={lastSearchedValue}
postIds={postIds}
fileInfos={fileInfos}
fileChannelIds={fileChannelIds}
/>
), [selectedTab, lastSearchedValue, postIds, fileInfos, fileChannelIds, resultsLoading]);
const renderItem = useCallback(() => {
if (loading) {
return loadingComponent;
}
if (!showResults) {
return initialComponent;
}
return resultsComponent;
return initialComponent;
}, [
loading && loadingComponent,
!loading && !showResults && initialComponent,
!loading && showResults && resultsComponent,
initialComponent,
]);
const animated = useAnimatedStyle(() => {
@@ -243,7 +232,7 @@ const SearchScreen = ({teamId}: Props) => {
setTeamId={handleResultsTeamChange}
onTabSelect={setSelectedTab}
onFilterChanged={handleFilterChange}
numberMessages={postIds.length}
numberMessages={posts.length}
selectedTab={selectedTab}
numberFiles={fileInfos.length}
selectedFilter={filter}
@@ -300,21 +289,34 @@ const SearchScreen = ({teamId}: Props) => {
<RoundedHeaderContext/>
{header}
</Animated.View>
<AnimatedFlatList
data={dummyData}
contentContainerStyle={containerStyle}
keyboardShouldPersistTaps='handled'
keyboardDismissMode={'interactive'}
nestedScrollEnabled={true}
indicatorStyle='black'
onScroll={onScroll}
scrollEventThrottle={16}
removeClippedSubviews={false}
scrollToOverflowEnabled={true}
overScrollMode='always'
ref={scrollRef}
renderItem={renderItem}
/>
{!showResults &&
<AnimatedFlatList
data={dummyData}
contentContainerStyle={containerStyle}
keyboardShouldPersistTaps='handled'
keyboardDismissMode={'interactive'}
nestedScrollEnabled={true}
indicatorStyle='black'
onScroll={onScroll}
scrollEventThrottle={16}
removeClippedSubviews={false}
scrollToOverflowEnabled={true}
overScrollMode='always'
ref={scrollRef}
renderItem={renderItem}
/>
}
{showResults && !loading &&
<Results
loading={resultsLoading}
selectedTab={selectedTab}
searchValue={lastSearchedValue}
posts={posts}
fileInfos={fileInfos}
scrollPaddingTop={scrollPaddingTop}
fileChannelIds={fileChannelIds}
/>
}
</Animated.View>
</SafeAreaView>
</FreezeScreen>