feat(search): add keyword highlighting to PostCard and improve QRCodeScanner
Some checks failed
Frontend CI / build-and-push-web (push) Successful in 4m39s
Frontend CI / ota-android (push) Successful in 11m22s
Frontend CI / build-android-apk (push) Failing after 14m58s

Add HighlightText component for search result highlighting in PostCard.
Refactor QRCodeScanner to use async permission methods with better error
handling. Improve SearchScreen with stable function refs and pass
highlightKeyword to PostCard. Modernize MessageListScreen search UI with
SearchBar and TabBar components. Add emoji virtualization to EmojiPanel
and auto-focus input after inserting emoji.

BREAKING CHANGE: EmojiPanel onFocusInput prop added for focus management
This commit is contained in:
lafay
2026-04-21 12:31:51 +08:00
parent b16759a147
commit 30c493c88f
9 changed files with 243 additions and 134 deletions

View File

@@ -4,7 +4,7 @@
* 支持响应式布局,宽屏下显示更大的搜索结果区域
*/
import React, { useState, useCallback, useEffect, useMemo } from 'react';
import React, { useState, useCallback, useEffect, useMemo, useRef } from 'react';
import {
View,
FlatList,
@@ -80,7 +80,8 @@ export const SearchScreen: React.FC<SearchScreenProps> = ({ onBack }) => {
// 保存当前搜索关键词用于Tab切换时重新搜索
const [currentKeyword, setCurrentKeyword] = useState('');
// 使用游标分页进行帖子搜索
const searchExtraParams = useMemo(() => ({ query: currentKeyword }), [currentKeyword]);
const {
list: searchResults,
isLoading,
@@ -100,20 +101,25 @@ export const SearchScreen: React.FC<SearchScreenProps> = ({ onBack }) => {
});
return response;
},
{ pageSize: DEFAULT_PAGE_SIZE },
{ query: '' }
{ pageSize: DEFAULT_PAGE_SIZE, autoLoad: false },
searchExtraParams
);
// 用户搜索结果(保持原有分页方式)
const [userResults, setUserResults] = useState<User[]>([]);
const [userLoading, setUserLoading] = useState(false);
const refreshRef = useRef(refresh);
refreshRef.current = refresh;
const resetRef = useRef(reset);
resetRef.current = reset;
// 当搜索词变化时重置
useEffect(() => {
if (currentKeyword) {
refresh();
refreshRef.current();
} else {
reset();
resetRef.current();
}
}, [currentKeyword]);
@@ -132,11 +138,7 @@ export const SearchScreen: React.FC<SearchScreenProps> = ({ onBack }) => {
try {
const searchType = getSearchType();
if (searchType === 'posts') {
// 帖子搜索由 useCursorPagination 处理,这里只需触发刷新
refresh();
} else if (searchType === 'users') {
// 用户搜索保持原有方式
if (searchType === 'users') {
setUserLoading(true);
const usersResponse = await authService.searchUsers(trimmedKeyword, 1, 20);
setUserResults(usersResponse.list || []);
@@ -259,6 +261,7 @@ export const SearchScreen: React.FC<SearchScreenProps> = ({ onBack }) => {
onAction={(action) => handlePostAction(post, action)}
variant="list"
features={isMobile ? 'compact' : 'full'}
highlightKeyword={currentKeyword}
/>
))}
</ResponsiveGrid>
@@ -281,6 +284,7 @@ export const SearchScreen: React.FC<SearchScreenProps> = ({ onBack }) => {
onAction={(action) => handlePostAction(item, action)}
variant="list"
features="compact"
highlightKeyword={currentKeyword}
/>
)}
keyExtractor={item => item.id}