Просмотр исходного кода

fix: 换源功能多项修复

- getDbSearchBooks: 使用 SearchScope 解析分组,多分组回退全部查询,加入 checkAuthor 判断
- searchSource: 移除 per-book try-catch,出错书源整体跳过
- 单章换源: 添加 getDbSearchBooks 历史搜索数据支持
- 单章换源: 显示更多信息启用时按字数排序
- 单章换源: 分组选择改为确认后再搜索(draft selection 模式)
- 两个换源界面: 搜索开始前预设 totalSourceCount
HapeLee 4 месяцев назад
Родитель
Сommit
6dded05b20

+ 10 - 15
app/src/main/java/io/legado/app/domain/usecase/ChangeSourceSearchUseCase.kt

@@ -151,21 +151,16 @@ class ChangeSourceSearchUseCase(
             when {
                 loadInfo || loadToc || loadWordCount -> {
                     val book = searchBook.toBook()
-                    try {
-                        val wordCountSearchBook = loadBookInfo(
-                            source,
-                            book,
-                            loadToc,
-                            loadWordCount,
-                            oldBook,
-                            fromReadBookActivity,
-                            contentProcessor
-                        )
-                        processedBooks.add(wordCountSearchBook ?: book.toSearchBook())
-                    } catch (e: Throwable) {
-                        if (e is CancellationException) throw e
-                        processedBooks.add(searchBook)
-                    }
+                    val wordCountSearchBook = loadBookInfo(
+                        source,
+                        book,
+                        loadToc,
+                        loadWordCount,
+                        oldBook,
+                        fromReadBookActivity,
+                        contentProcessor
+                    )
+                    processedBooks.add(wordCountSearchBook ?: book.toSearchBook())
                 }
 
                 else -> {

+ 12 - 4
app/src/main/java/io/legado/app/ui/book/changesource/ChangeBookSourceComposeViewModel.kt

@@ -108,14 +108,22 @@ class ChangeBookSourceComposeViewModel(
     }
 
     private fun getDbSearchBooks(): List<SearchBook> {
-        val scopeRaw = ChangeSourceConfig.searchScope
+        val searchScope = SearchScope(ChangeSourceConfig.searchScope)
+        val group = when {
+            searchScope.isAll() || searchScope.isSource() -> ""
+            else -> {
+                val names = searchScope.displayNames
+                if (names.size == 1) names.first() else ""
+            }
+        }
+        val bookAuthor = if (checkAuthor) bookAuthor else ""
         return if (screenKey.isEmpty()) {
             io.legado.app.data.appDb.searchBookDao.changeSourceByGroup(
-                bookName, bookAuthor, scopeRaw
+                bookName, bookAuthor, group
             )
         } else {
             io.legado.app.data.appDb.searchBookDao.changeSourceSearch(
-                bookName, bookAuthor, screenKey, scopeRaw
+                bookName, bookAuthor, screenKey, group
             )
         }
     }
@@ -128,7 +136,7 @@ class ChangeBookSourceComposeViewModel(
         searchResults.clear()
         bookMap.clear()
         tocMap.clear()
-        totalSourceCount = 0
+        totalSourceCount = searchScope.getBookSourceParts().size
         _changeSourceProgress.value = 0 to ""
         _searchDataFlow.value = emptyList()
 

+ 73 - 13
app/src/main/java/io/legado/app/ui/book/changesource/ChangeChapterSourceViewModel.kt

@@ -33,6 +33,7 @@ class ChangeChapterSourceViewModel(
     val effects = _effects.asSharedFlow()
 
     // Internal state
+    private val chapterNumRegex = "^\\[(\\d+)]".toRegex()
     private var searchJob: Job? = null
     private var oldBook: Book? = null
     private var chapterIndex: Int = 0
@@ -82,7 +83,42 @@ class ChangeChapterSourceViewModel(
                 selectedSourceName = "",
             )
         }
-        startSearch()
+        if (searchJob?.isActive != true) {
+            viewModelScope.launch {
+                val dbBooks = getDbSearchBooks()
+                if (dbBooks.isNotEmpty()) {
+                    searchResults.clear()
+                    searchResults.addAll(dbBooks)
+                    searchResults.forEach { bookMap[it.primaryStr()] = it }
+                    filterResults()
+                } else {
+                    startSearch()
+                }
+            }
+        }
+    }
+
+    private fun getDbSearchBooks(): List<SearchBook> {
+        val name = oldBook?.name ?: return emptyList()
+        val author = oldBook?.author ?: return emptyList()
+        val searchScope = SearchScope(ChangeSourceConfig.searchScope)
+        val group = when {
+            searchScope.isAll() || searchScope.isSource() -> ""
+            else -> {
+                val names = searchScope.displayNames
+                if (names.size == 1) names.first() else ""
+            }
+        }
+        val bookAuthor = if (ChangeSourceConfig.checkAuthor) author else ""
+        return if (screenKey.isEmpty()) {
+            io.legado.app.data.appDb.searchBookDao.changeSourceByGroup(
+                name, bookAuthor, group
+            )
+        } else {
+            io.legado.app.data.appDb.searchBookDao.changeSourceSearch(
+                name, bookAuthor, screenKey, group
+            )
+        }
     }
 
     fun onIntent(intent: ChangeChapterSourceIntent) {
@@ -182,7 +218,7 @@ class ChangeChapterSourceViewModel(
 
             is ChangeChapterSourceIntent.SelectAllScope -> {
                 searchScope.update("")
-                saveScope()
+                updateScopeState()
             }
 
             is ChangeChapterSourceIntent.ToggleScopeGroup -> {
@@ -196,7 +232,7 @@ class ChangeChapterSourceViewModel(
                     selected.add(intent.groupName)
                 }
                 searchScope.update(selected.toList())
-                saveScope()
+                updateScopeState()
             }
 
             is ChangeChapterSourceIntent.ToggleScopeSource -> {
@@ -219,11 +255,12 @@ class ChangeChapterSourceViewModel(
                         }
                     searchScope.updateSources(selectedSources)
                 }
-                saveScope()
+                updateScopeState()
             }
 
             is ChangeChapterSourceIntent.ApplyScope -> {
-                startSearch()
+                ChangeSourceConfig.searchScope = searchScope.toString()
+                refreshResults()
             }
         }
     }
@@ -233,6 +270,13 @@ class ChangeChapterSourceViewModel(
         stopSearch()
         searchResults.clear()
         bookMap.clear()
+        val scope = SearchScope(ChangeSourceConfig.searchScope)
+        _uiState.update {
+            it.copy(
+                totalSourceCount = scope.getBookSourceParts().size,
+                searchProgress = 0 to "",
+            )
+        }
         filterResults()
 
         searchJob = viewModelScope.launch {
@@ -284,7 +328,14 @@ class ChangeChapterSourceViewModel(
     private fun refreshResults() {
         searchResults.clear()
         bookMap.clear()
-        startSearch()
+        val dbBooks = getDbSearchBooks()
+        if (dbBooks.isNotEmpty()) {
+            searchResults.addAll(dbBooks)
+            searchResults.forEach { bookMap[it.primaryStr()] = it }
+            filterResults()
+        } else {
+            startSearch()
+        }
     }
 
     private fun filterResults() {
@@ -295,20 +346,31 @@ class ChangeChapterSourceViewModel(
                 it.name.contains(screenKey) || it.originName.contains(screenKey)
             }
         }
-        // Sort by score
-        val sorted = filtered.sortedWith(
+        val comparator = if (_uiState.value.loadWordCount) {
             compareByDescending<SearchBook> { ObservableSourceConfig.getBookScore(it) }
                 .thenByDescending { io.legado.app.help.config.SourceConfig.getSourceScore(it.origin) }
+                .thenByDescending { it.chapterWordCount > 1000 }
+                .thenByDescending { getChapterNum(it.chapterWordCountText) }
+                .thenByDescending { it.chapterWordCount }
                 .thenBy { it.originOrder }
-        )
+        } else {
+            compareByDescending<SearchBook> { ObservableSourceConfig.getBookScore(it) }
+                .thenByDescending { io.legado.app.help.config.SourceConfig.getSourceScore(it.origin) }
+                .thenBy { it.originOrder }
+        }
         _uiState.update {
             it.copy(
-                searchResults = sorted.toImmutableList(),
+                searchResults = filtered.sortedWith(comparator).toImmutableList(),
                 bookMap = bookMap.toMap()
             )
         }
     }
 
+    private fun getChapterNum(text: String?): Int {
+        if (text.isNullOrBlank()) return 0
+        return chapterNumRegex.find(text)?.groupValues?.get(1)?.toIntOrNull() ?: 0
+    }
+
     private fun selectSource(searchBook: SearchBook) {
         val book = searchBook.toBook()
         _uiState.update {
@@ -376,8 +438,7 @@ class ChangeChapterSourceViewModel(
         }
     }
 
-    private fun saveScope() {
-        ChangeSourceConfig.searchScope = searchScope.toString()
+    private fun updateScopeState() {
         _uiState.update {
             it.copy(
                 scopeState = ScopeUiState(
@@ -388,7 +449,6 @@ class ChangeChapterSourceViewModel(
                 )
             )
         }
-        refreshResults()
     }
 
     fun bookScoreFlow(searchBook: SearchBook) = ObservableSourceConfig.bookScoreFlow(searchBook)

+ 1 - 1
app/src/main/java/io/legado/app/ui/book/read/sheet/ChangeChapterSourceSheet.kt

@@ -156,7 +156,7 @@ fun ChangeChapterSourceSheet(
         selectedSources = state.scopeState.sourceUrls,
         onToggleSource = { onIntent(ChangeChapterSourceIntent.ToggleScopeSource(it)) },
         isSourceScope = state.scopeState.isSource,
-        onConfirm = {
+        onApplyScope = { selection ->
             onIntent(ChangeChapterSourceIntent.ApplyScope)
             showFilterSheet = false
         }