Right Search: Add infinite scroll, fix jumps
This commit is contained in:
parent
8ed75455de
commit
c95b404085
@ -15,13 +15,6 @@
|
|||||||
transition: none;
|
transition: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @optimization
|
|
||||||
&:not(:hover) {
|
|
||||||
.chat-item-clickable:not(.picker-list-item):nth-child(n + 18) {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 1275px) {
|
@media (max-width: 1275px) {
|
||||||
box-shadow: 0 .25rem .5rem .125rem var(--color-default-shadow);
|
box-shadow: 0 .25rem .5rem .125rem var(--color-default-shadow);
|
||||||
border-left: none;
|
border-left: none;
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import { getDispatch, getGlobal, withGlobal } from '../../lib/teact/teactn';
|
|||||||
|
|
||||||
import { ApiMessage, ApiUser, ApiChat } from '../../api/types';
|
import { ApiMessage, ApiUser, ApiChat } from '../../api/types';
|
||||||
|
|
||||||
|
import { MEMO_EMPTY_ARRAY } from '../../util/memo';
|
||||||
import {
|
import {
|
||||||
selectUser,
|
selectUser,
|
||||||
selectChatMessages,
|
selectChatMessages,
|
||||||
@ -16,13 +17,12 @@ import {
|
|||||||
getUserFullName,
|
getUserFullName,
|
||||||
isChatChannel,
|
isChatChannel,
|
||||||
} from '../../modules/helpers';
|
} from '../../modules/helpers';
|
||||||
import renderText from '../common/helpers/renderText';
|
|
||||||
import useLang from '../../hooks/useLang';
|
import useLang from '../../hooks/useLang';
|
||||||
import { orderBy } from '../../util/iteratees';
|
|
||||||
import { MEMO_EMPTY_ARRAY } from '../../util/memo';
|
|
||||||
import useKeyboardListNavigation from '../../hooks/useKeyboardListNavigation';
|
import useKeyboardListNavigation from '../../hooks/useKeyboardListNavigation';
|
||||||
import useHistoryBack from '../../hooks/useHistoryBack';
|
import useHistoryBack from '../../hooks/useHistoryBack';
|
||||||
|
import useInfiniteScroll from '../../hooks/useInfiniteScroll';
|
||||||
import { renderMessageSummary } from '../common/helpers/renderMessageText';
|
import { renderMessageSummary } from '../common/helpers/renderMessageText';
|
||||||
|
import renderText from '../common/helpers/renderText';
|
||||||
|
|
||||||
import InfiniteScroll from '../ui/InfiniteScroll';
|
import InfiniteScroll from '../ui/InfiniteScroll';
|
||||||
import ListItem from '../ui/ListItem';
|
import ListItem from '../ui/ListItem';
|
||||||
@ -46,13 +46,6 @@ type StateProps = {
|
|||||||
foundIds?: number[];
|
foundIds?: number[];
|
||||||
};
|
};
|
||||||
|
|
||||||
interface Result {
|
|
||||||
message: ApiMessage;
|
|
||||||
senderUser?: ApiUser;
|
|
||||||
senderChat?: ApiChat;
|
|
||||||
onClick: NoneToVoidFunction;
|
|
||||||
}
|
|
||||||
|
|
||||||
const RightSearch: FC<OwnProps & StateProps> = ({
|
const RightSearch: FC<OwnProps & StateProps> = ({
|
||||||
chatId,
|
chatId,
|
||||||
threadId,
|
threadId,
|
||||||
@ -69,14 +62,20 @@ const RightSearch: FC<OwnProps & StateProps> = ({
|
|||||||
focusMessage,
|
focusMessage,
|
||||||
} = getDispatch();
|
} = getDispatch();
|
||||||
|
|
||||||
const lang = useLang();
|
// eslint-disable-next-line no-null/no-null
|
||||||
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const foundResults = useMemo(() => {
|
const lang = useLang();
|
||||||
if (!query || !foundIds || !foundIds.length || !messagesById) {
|
useHistoryBack(isActive, onClose);
|
||||||
|
|
||||||
|
const [viewportIds, getMore] = useInfiniteScroll(searchTextMessagesLocal, foundIds);
|
||||||
|
|
||||||
|
const viewportResults = useMemo(() => {
|
||||||
|
if (!query || !viewportIds?.length || !messagesById) {
|
||||||
return MEMO_EMPTY_ARRAY;
|
return MEMO_EMPTY_ARRAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
const results = foundIds.map((id) => {
|
return viewportIds.map((id) => {
|
||||||
const message = messagesById[id];
|
const message = messagesById[id];
|
||||||
if (!message) {
|
if (!message) {
|
||||||
return undefined;
|
return undefined;
|
||||||
@ -100,19 +99,31 @@ const RightSearch: FC<OwnProps & StateProps> = ({
|
|||||||
senderChat,
|
senderChat,
|
||||||
onClick: () => focusMessage({ chatId, threadId, messageId: id }),
|
onClick: () => focusMessage({ chatId, threadId, messageId: id }),
|
||||||
};
|
};
|
||||||
}).filter(Boolean) as Result[];
|
}).filter(Boolean);
|
||||||
|
}, [query, viewportIds, messagesById, chat, focusMessage, chatId, threadId]);
|
||||||
|
|
||||||
return orderBy(results, ({ message }) => message.date, 'desc');
|
const handleKeyDown = useKeyboardListNavigation(containerRef, true, (index) => {
|
||||||
}, [chatId, threadId, focusMessage, foundIds, chat, messagesById, query]);
|
const foundResult = viewportResults?.[index === -1 ? 0 : index];
|
||||||
|
if (foundResult) {
|
||||||
|
foundResult.onClick();
|
||||||
|
}
|
||||||
|
}, '.ListItem-button', true);
|
||||||
|
|
||||||
const renderSearchResult = ({
|
const renderSearchResult = ({
|
||||||
message, senderUser, senderChat, onClick,
|
message, senderUser, senderChat, onClick,
|
||||||
}: Result) => {
|
}: {
|
||||||
|
message: ApiMessage;
|
||||||
|
senderUser?: ApiUser;
|
||||||
|
senderChat?: ApiChat;
|
||||||
|
onClick: NoneToVoidFunction;
|
||||||
|
}) => {
|
||||||
const title = senderChat ? getChatTitle(lang, senderChat) : getUserFullName(senderUser);
|
const title = senderChat ? getChatTitle(lang, senderChat) : getUserFullName(senderUser);
|
||||||
const text = renderMessageSummary(lang, message, undefined, query);
|
const text = renderMessageSummary(lang, message, undefined, query);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ListItem
|
<ListItem
|
||||||
|
key={message.id}
|
||||||
|
teactOrderKey={-message.date}
|
||||||
className="chat-item-clickable search-result-message m-0"
|
className="chat-item-clickable search-result-message m-0"
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
>
|
>
|
||||||
@ -130,39 +141,31 @@ const RightSearch: FC<OwnProps & StateProps> = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
useHistoryBack(isActive, onClose);
|
const isOnTop = viewportIds?.[0] === foundIds?.[0];
|
||||||
|
|
||||||
// eslint-disable-next-line no-null/no-null
|
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
|
||||||
const handleKeyDown = useKeyboardListNavigation(containerRef, true, (index) => {
|
|
||||||
const foundResult = foundResults?.[index === -1 ? 0 : index];
|
|
||||||
if (foundResult) {
|
|
||||||
foundResult.onClick();
|
|
||||||
}
|
|
||||||
}, '.ListItem-button', true);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InfiniteScroll
|
<InfiniteScroll
|
||||||
className="RightSearch custom-scroll"
|
|
||||||
items={foundResults}
|
|
||||||
preloadBackwards={0}
|
|
||||||
onLoadMore={searchTextMessagesLocal}
|
|
||||||
noFastList
|
|
||||||
onKeyDown={handleKeyDown}
|
|
||||||
ref={containerRef}
|
ref={containerRef}
|
||||||
|
className="RightSearch custom-scroll"
|
||||||
|
items={viewportResults}
|
||||||
|
preloadBackwards={0}
|
||||||
|
onLoadMore={getMore}
|
||||||
|
onKeyDown={handleKeyDown}
|
||||||
>
|
>
|
||||||
<p className="helper-text" dir="auto">
|
{isOnTop && (
|
||||||
{!query ? (
|
<p key="helper-text" className="helper-text" dir="auto">
|
||||||
lang('lng_dlg_search_for_messages')
|
{!query ? (
|
||||||
) : (totalCount === 0 || !foundResults.length) ? (
|
lang('lng_dlg_search_for_messages')
|
||||||
lang('lng_search_no_results')
|
) : (totalCount === 0 || !viewportResults.length) ? (
|
||||||
) : totalCount === 1 ? (
|
lang('lng_search_no_results')
|
||||||
'1 message found'
|
) : totalCount === 1 ? (
|
||||||
) : (
|
'1 message found'
|
||||||
`${(foundResults.length && (totalCount || foundResults.length))} messages found`
|
) : (
|
||||||
)}
|
`${(viewportResults.length && (totalCount || viewportResults.length))} messages found`
|
||||||
</p>
|
)}
|
||||||
{foundResults.map(renderSearchResult)}
|
</p>
|
||||||
|
)}
|
||||||
|
{viewportResults.map(renderSearchResult)}
|
||||||
</InfiniteScroll>
|
</InfiniteScroll>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -159,7 +159,7 @@ function useInfiniteScrollForSharedMedia(
|
|||||||
chatMessages,
|
chatMessages,
|
||||||
foundIds,
|
foundIds,
|
||||||
forSharedMediaType,
|
forSharedMediaType,
|
||||||
).reverse();
|
);
|
||||||
}
|
}
|
||||||
}, [chatMessages, foundIds, currentResultType, forSharedMediaType]);
|
}, [chatMessages, foundIds, currentResultType, forSharedMediaType]);
|
||||||
|
|
||||||
|
|||||||
@ -85,6 +85,10 @@ async function searchTextMessages(
|
|||||||
query?: string,
|
query?: string,
|
||||||
offsetId?: number,
|
offsetId?: number,
|
||||||
) {
|
) {
|
||||||
|
if (!query) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const result = await callApi('searchMessagesLocal', {
|
const result = await callApi('searchMessagesLocal', {
|
||||||
chatOrUser,
|
chatOrUser,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
@ -108,7 +112,7 @@ async function searchTextMessages(
|
|||||||
let global = getGlobal();
|
let global = getGlobal();
|
||||||
|
|
||||||
const currentSearch = selectCurrentTextSearch(global);
|
const currentSearch = selectCurrentTextSearch(global);
|
||||||
if (!currentSearch || (query && query !== currentSearch.query)) {
|
if (!currentSearch || query !== currentSearch.query) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -303,9 +303,7 @@ export function hasMessageLocalBlobUrl(message: ApiMessage) {
|
|||||||
export function getChatMediaMessageIds(
|
export function getChatMediaMessageIds(
|
||||||
messages: Record<number, ApiMessage>, listedIds: number[], isFromSharedMedia = false,
|
messages: Record<number, ApiMessage>, listedIds: number[], isFromSharedMedia = false,
|
||||||
) {
|
) {
|
||||||
const ids = getMessageContentIds(messages, listedIds, isFromSharedMedia ? 'media' : 'inlineMedia');
|
return getMessageContentIds(messages, listedIds, isFromSharedMedia ? 'media' : 'inlineMedia');
|
||||||
|
|
||||||
return isFromSharedMedia ? ids.reverse() : ids;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPhotoFullDimensions(photo: ApiPhoto): ApiDimensions | undefined {
|
export function getPhotoFullDimensions(photo: ApiPhoto): ApiDimensions | undefined {
|
||||||
|
|||||||
@ -158,5 +158,5 @@ export function updateLocalMediaSearchResults(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function orderFoundIds(listedIds: number[]) {
|
function orderFoundIds(listedIds: number[]) {
|
||||||
return listedIds.sort((a, b) => a - b);
|
return listedIds.sort((a, b) => b - a);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user