diff --git a/app/actions/remote/channel.ts b/app/actions/remote/channel.ts index f53e6bd866..0835b22cb4 100644 --- a/app/actions/remote/channel.ts +++ b/app/actions/remote/channel.ts @@ -1147,7 +1147,7 @@ export async function switchToLastChannel(serverUrl: string, teamId?: string) { } } -export async function searchChannels(serverUrl: string, term: string) { +export async function searchChannels(serverUrl: string, term: string, isSearch = false) { const database = DatabaseManager.serverDatabases[serverUrl]?.database; if (!database) { return {error: `${serverUrl} database not found`}; @@ -1162,7 +1162,8 @@ export async function searchChannels(serverUrl: string, term: string) { try { const currentTeamId = await getCurrentTeamId(database); - const channels = await client.autocompleteChannels(currentTeamId, term); + const autoCompleteFunc = isSearch ? client.autocompleteChannelsForSearch : client.autocompleteChannels; + const channels = await autoCompleteFunc(currentTeamId, term); return {channels}; } catch (error) { return {error}; diff --git a/app/components/autocomplete/autocomplete.tsx b/app/components/autocomplete/autocomplete.tsx index d3897d094b..050e83ae77 100644 --- a/app/components/autocomplete/autocomplete.tsx +++ b/app/components/autocomplete/autocomplete.tsx @@ -55,6 +55,7 @@ const getStyleFromTheme = makeStyleSheetFromTheme((theme) => { type Props = { cursorPosition: number; postInputTop: number; + paddingTop?: number; rootId?: string; channelId?: string; fixedBottomPosition?: boolean; @@ -72,6 +73,7 @@ type Props = { const Autocomplete = ({ cursorPosition, postInputTop, + paddingTop, rootId, channelId, isSearch = false, @@ -124,10 +126,10 @@ const Autocomplete = ({ s.push(style.shadow); } if (isSearch) { - s.push(style.base, style.searchContainer, {height: maxListHeight}); + s.push(style.base, paddingTop ? {top: paddingTop} : style.searchContainer, {maxHeight: maxListHeight}); } return s; - }, [style, isSearch && maxListHeight, hasElements]); + }, [style, isSearch && maxListHeight, paddingTop]); const containerStyles = useMemo(() => { const s = []; diff --git a/app/components/autocomplete/channel_mention/channel_mention.tsx b/app/components/autocomplete/channel_mention/channel_mention.tsx index 48aaf80d1e..d783e82c6f 100644 --- a/app/components/autocomplete/channel_mention/channel_mention.tsx +++ b/app/components/autocomplete/channel_mention/channel_mention.tsx @@ -218,7 +218,7 @@ const ChannelMention = ({ const runSearch = useMemo(() => debounce(async (sUrl: string, term: string) => { setLoading(true); - const {channels: receivedChannels, error} = await searchChannels(sUrl, term); + const {channels: receivedChannels, error} = await searchChannels(sUrl, term, isSearch); setUseLocal(Boolean(error)); if (error) { diff --git a/app/screens/home/search/search.tsx b/app/screens/home/search/search.tsx index b6d1b0c4c9..8b01a16aa3 100644 --- a/app/screens/home/search/search.tsx +++ b/app/screens/home/search/search.tsx @@ -10,6 +10,7 @@ import {Edge, SafeAreaView} from 'react-native-safe-area-context'; import {addSearchToTeamSearchHistory} from '@actions/local/team'; import {searchPosts, searchFiles} from '@actions/remote/search'; +import Autocomplete from '@components/autocomplete'; import FreezeScreen from '@components/freeze_screen'; import Loading from '@components/loading'; import NavigationHeader from '@components/navigation_header'; @@ -33,6 +34,9 @@ const emptyChannelIds: string[] = []; const dummyData = [1]; +const AutocompletePaddingTop = -4; +const AutocompleteZindex = 11; + type Props = { teamId: string; } @@ -69,6 +73,7 @@ const SearchScreen = ({teamId}: Props) => { const serverUrl = useServerUrl(); const searchTerm = (nav.getState().routes[stateIndex].params as any)?.searchTerm; + const [cursorPosition, setCursorPosition] = useState(searchTerm?.length); const [searchValue, setSearchValue] = useState(searchTerm); const [searchTeamId, setSearchTeamId] = useState(teamId); const [selectedTab, setSelectedTab] = useState(TabTypes.MESSAGES); @@ -88,11 +93,16 @@ const SearchScreen = ({teamId}: Props) => { const {scrollPaddingTop, scrollRef, scrollValue, onScroll, headerHeight, hideHeader} = useCollapsibleHeader(true, onSnap); + const handleTextChange = useCallback((newValue: string) => { + setSearchValue(newValue); + setCursorPosition(newValue.length); + }, []); + const handleClearSearch = useCallback(() => { - setSearchValue(''); + handleTextChange(''); setLastSearchedValue(''); setFilter(FileFilters.ALL); - }, []); + }, [handleTextChange]); const handleCancelSearch = useCallback(() => { handleClearSearch(); @@ -127,9 +137,9 @@ const SearchScreen = ({teamId}: Props) => { }, [handleSearch, searchTeamId, searchValue]); const handleRecentSearch = useCallback((text: string) => { - setSearchValue(text); + handleTextChange(text); handleSearch(searchTeamId, text); - }, [handleSearch, searchTeamId]); + }, [handleSearch, handleTextChange, searchTeamId]); const handleFilterChange = useCallback(async (filterValue: FileFilter) => { setLoading(true); @@ -159,11 +169,11 @@ const SearchScreen = ({teamId}: Props) => { - ), [searchValue, searchTeamId, handleRecentSearch]); + ), [searchValue, searchTeamId, handleRecentSearch, handleTextChange]); const resultsComponent = useMemo(() => ( { /> ); } + const autocomplete = useMemo(() => ( + + ), [cursorPosition, handleTextChange, searchValue]); return ( @@ -239,7 +260,7 @@ const SearchScreen = ({teamId}: Props) => { hasSearch={true} scrollValue={scrollValue} hideHeader={hideHeader} - onChangeText={setSearchValue} + onChangeText={handleTextChange} onSubmitEditing={onSubmit} blurOnSubmit={true} placeholder={intl.formatMessage({id: 'screen.search.placeholder', defaultMessage: 'Search messages & files'})} @@ -247,6 +268,9 @@ const SearchScreen = ({teamId}: Props) => { onCancel={handleCancelSearch} defaultValue={searchValue} /> + + {autocomplete} +