fix: 搜索界面问题

This commit is contained in:
HapeLee
2026-06-14 00:21:14 +08:00
parent 318bef3649
commit fc096c92e8
5 changed files with 95 additions and 14 deletions
@@ -509,7 +509,8 @@ fun SearchScreen(
},
sharedTransitionScope = sharedTransitionScope,
animatedVisibilityScope = animatedVisibilityScope,
sharedCoverKey = sharedCoverKey
sharedCoverKey = sharedCoverKey,
sourceCount = item.book.origins.size,
)
}
@@ -84,10 +84,11 @@ class SearchViewModel(
private val bookshelfKeys = MutableStateFlow<Set<BookShelfKey>>(emptySet())
private val searchScope = SearchScope(AppConfig.searchScope)
private val searchControl = BookSearchControl()
private val searchResultBooks = LinkedHashMap<String, SearchBook>()
private val searchResultBooks = LinkedHashMap<SearchResultKey, SearchBook>()
private var searchJob: Job? = null
private var currentSearchPage = 1
private var resultCountBeforeCurrentPage = 0
private var wasSearching = false
init {
@@ -483,6 +484,7 @@ class SearchViewModel(
private fun startSearch(keyword: String, page: Int) {
searchJob?.cancel()
searchControl.resume()
resultCountBeforeCurrentPage = searchResultBooks.size
wasSearching = true
searchJob = viewModelScope.launch {
try {
@@ -517,10 +519,8 @@ class SearchViewModel(
}
is SearchRunEvent.Progress -> {
event.removedBookUrls.forEach { searchResultBooks.remove(it) }
event.upsertBooks.forEach { book ->
searchResultBooks[book.bookUrl] = book
}
removeSearchResults(event.removedBookUrls)
mergeSearchResults(event.upsertBooks)
_uiState.update {
it.copy(
results = buildSearchResultItems(
@@ -542,9 +542,16 @@ class SearchViewModel(
} else {
null
}
val hasNewPageResults = searchResultBooks.size > resultCountBeforeCurrentPage
val exactSearchShouldStopAfterFirstPage =
state.matchMode == MatchMode.EXACT &&
currentSearchPage == 1 &&
searchResultBooks.size <= EXACT_SEARCH_SINGLE_PAGE_RESULT_THRESHOLD
state.copy(
isSearching = false,
hasMore = event.hasMore,
hasMore = event.hasMore &&
hasNewPageResults &&
!exactSearchShouldStopAfterFirstPage,
emptyScopeAction = emptyAction,
)
}
@@ -697,7 +704,9 @@ class SearchViewModel(
private fun buildSearchResultItems(
shelf: Set<BookShelfKey>,
): List<SearchResultItemUi> {
return searchResultBooks.values.toList().toSearchResultItems(shelf)
return searchResultBooks.values
.sortedWithSearchPriority(_uiState.value.committedQuery, _uiState.value.matchMode)
.toSearchResultItems(shelf)
}
private fun List<SearchResultItemUi>.withShelfState(
@@ -749,4 +758,57 @@ class SearchViewModel(
private fun emitEffect(effect: SearchEffect) {
_effects.tryEmit(effect)
}
private fun mergeSearchResults(books: List<SearchBook>) {
books.forEach { book ->
val key = SearchResultKey(book.name, book.author)
val currentBook = searchResultBooks[key]
if (currentBook == null) {
searchResultBooks[key] = book
} else {
book.origins.forEach { origin -> currentBook.addOrigin(origin) }
}
}
}
private fun removeSearchResults(bookUrls: List<String>) {
if (bookUrls.isEmpty()) return
val removedUrls = bookUrls.toHashSet()
searchResultBooks.entries.removeAll { (_, book) -> book.bookUrl in removedUrls }
}
private fun Collection<SearchBook>.sortedWithSearchPriority(
keyword: String,
matchMode: MatchMode,
): List<SearchBook> {
val equalBooks = arrayListOf<SearchBook>()
val tagsBooks = arrayListOf<SearchBook>()
val containsBooks = arrayListOf<SearchBook>()
val otherBooks = arrayListOf<SearchBook>()
forEach { book ->
when {
book.name.equals(keyword, ignoreCase = true) ||
book.author.equals(keyword, ignoreCase = true) -> equalBooks.add(book)
book.kind?.contains(keyword, ignoreCase = true) == true -> tagsBooks.add(book)
book.name.contains(keyword, ignoreCase = true) ||
book.author.contains(keyword, ignoreCase = true) -> containsBooks.add(book)
matchMode == MatchMode.DEFAULT -> otherBooks.add(book)
}
}
return buildList(size) {
addAll(equalBooks.sortedByDescending { it.origins.size })
addAll(tagsBooks.sortedByDescending { it.origins.size })
addAll(containsBooks.sortedByDescending { it.origins.size })
addAll(otherBooks)
}
}
private data class SearchResultKey(
val name: String,
val author: String,
)
private companion object {
const val EXACT_SEARCH_SINGLE_PAGE_RESULT_THRESHOLD = 3
}
}
@@ -28,9 +28,11 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import io.legado.app.R
import io.legado.app.data.entities.SearchBook
import io.legado.app.domain.model.BookShelfState
import io.legado.app.ui.theme.LegadoTheme
@@ -53,6 +55,7 @@ fun SearchBookListItem(
sharedTransitionScope: SharedTransitionScope? = null,
animatedVisibilityScope: AnimatedVisibilityScope? = null,
sharedCoverKey: String? = null,
sourceCount: Int? = null,
) {
Row(
modifier = modifier
@@ -106,12 +109,25 @@ fun SearchBookListItem(
.weight(1f)
.align(Alignment.CenterVertically)
) {
AppText(
text = book.name,
style = LegadoTheme.typography.titleSmall,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
Row(verticalAlignment = Alignment.CenterVertically) {
AppText(
text = book.name,
modifier = Modifier.weight(1f),
style = LegadoTheme.typography.titleSmall,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
sourceCount?.let { count ->
Spacer(modifier = Modifier.width(8.dp))
TextCard(
text = stringResource(R.string.search_book_source_count, count),
cornerRadius = 4.dp,
horizontalPadding = 4.dp,
verticalPadding = 2.dp
)
}
}
Row {
AppText(
@@ -1724,6 +1724,7 @@
<string name="search_empty_scope_switch_all">%1$s分组搜索结果为空,是否切换到全部分组?</string>
<string name="search_type">搜索类型</string>
<string name="search_has_more">上拉或点击按钮加载更多</string>
<string name="search_book_source_count">%1$d</string>
<string name="search_layout_list">列表布局</string>
<string name="search_layout_source_grouped">来源分组</string>
<string name="download_cache_config">下载与缓存</string>
+1
View File
@@ -1760,6 +1760,7 @@
<string name="search_empty_scope_switch_all">%1$s group search returned no results. Switch to all groups?</string>
<string name="search_type">Search type</string>
<string name="search_has_more">Pull up or tap button to load more</string>
<string name="search_book_source_count">%1$d</string>
<string name="search_layout_list">List layout</string>
<string name="search_layout_source_grouped">Source grouped</string>
<string name="download_cache_config">Download &amp; Cache</string>