Bläddra i källkod

[优化] 下载优化

HapeLee 6 månader sedan
förälder
incheckning
5ddaa70f67

+ 38 - 1
app/src/main/java/io/legado/app/model/CacheBookModel.kt

@@ -55,6 +55,7 @@ class CacheBookModel(
     private val onDownloadSet = linkedSetOf<Int>()
     private val canceledDownloadSet = hashSetOf<Int>()
     private val pausedChapterSet = linkedSetOf<Int>()
+    private val pendingReadRequestMap = hashMapOf<Int, Boolean>()
     private val chapterTasks = hashMapOf<Int, Coroutine<*>>()
     private val tasks = CompositeCoroutine()
     private val repository = CacheDownloadRepository()
@@ -197,6 +198,7 @@ class CacheBookModel(
         canceledDownloadSet.clear()
         pausedChapterSet.clear()
         chapterTasks.clear()
+        pendingReadRequestMap.clear()
         tasks.clear()
         retryCountMap.clear()
         isStopped = true
@@ -492,12 +494,17 @@ class CacheBookModel(
     ) {
         task.onSuccess {
             onSuccess(chapter)
+            (it as? String)?.let { content ->
+                emitPendingReadContent(chapter, content)
+            }
         }.onError {
             onPreError(chapter, it)
             delay(1000)
             onPostError(chapter, it)
+            emitPendingReadError(chapter, it)
         }.onCancel {
             onCancel(chapterIndex)
+            emitPendingReadCanceled(chapter)
         }.onFinally {
             chapterTasks.remove(chapterIndex)?.let { tasks.delete(it) }
             onFinally()
@@ -536,7 +543,10 @@ class CacheBookModel(
         semaphore: Semaphore?,
         resetPageOffset: Boolean = false
     ) {
-        if (!markChapterDownloadStarted(chapter.index)) return
+        if (!markChapterDownloadStarted(chapter.index)) {
+            markPendingReadRequest(chapter.index, resetPageOffset)
+            return
+        }
         repository.downloadContentTask(
             scope = scope,
             bookSource = bookSource,
@@ -551,11 +561,13 @@ class CacheBookModel(
             ReadBook.downloadedChapters.add(chapter.index)
             ReadBook.downloadFailChapters.remove(chapter.index)
             downloadFinish(chapter, content, resetPageOffset)
+            emitPendingReadContent(chapter, content)
         }.onError {
             onError(chapter, it)
             ReadBook.downloadFailChapters[chapter.index] =
                 (ReadBook.downloadFailChapters[chapter.index] ?: 0) + 1
             downloadFinish(chapter, "获取正文失败\n${it.localizedMessage}", resetPageOffset)
+            emitPendingReadError(chapter, it)
         }.onCancel {
             onCancel(chapter.index, requeue = false)
             downloadFinish(chapter, "download canceled", resetPageOffset, true)
@@ -573,6 +585,31 @@ class CacheBookModel(
         return true
     }
 
+    @Synchronized
+    private fun markPendingReadRequest(index: Int, resetPageOffset: Boolean) {
+        pendingReadRequestMap[index] = pendingReadRequestMap[index] == true || resetPageOffset
+    }
+
+    @Synchronized
+    private fun consumePendingReadRequest(index: Int): Boolean? {
+        return pendingReadRequestMap.remove(index)
+    }
+
+    private fun emitPendingReadContent(chapter: BookChapter, content: String) {
+        val resetPageOffset = consumePendingReadRequest(chapter.index) ?: return
+        downloadFinish(chapter, content, resetPageOffset)
+    }
+
+    private fun emitPendingReadError(chapter: BookChapter, error: Throwable) {
+        val resetPageOffset = consumePendingReadRequest(chapter.index) ?: return
+        downloadFinish(chapter, "获取正文失败\n${error.localizedMessage}", resetPageOffset)
+    }
+
+    private fun emitPendingReadCanceled(chapter: BookChapter) {
+        val resetPageOffset = consumePendingReadRequest(chapter.index) ?: return
+        downloadFinish(chapter, "download canceled", resetPageOffset)
+    }
+
     private fun downloadFinish(
         chapter: BookChapter,
         content: String,

+ 1 - 1
app/src/main/java/io/legado/app/model/cache/CacheDownloadRepository.kt

@@ -71,7 +71,7 @@ class CacheDownloadRepository {
         context: CoroutineContext,
         start: CoroutineStart = CoroutineStart.LAZY,
         executeContext: CoroutineContext = context,
-    ): Coroutine<Unit> {
+    ): Coroutine<String> {
         return Coroutine.async(
             scope = scope,
             context = context,

+ 16 - 5
app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt

@@ -126,15 +126,17 @@ class SearchViewModel(
             }
 
             SearchIntent.SelectAllScope -> {
+                val oldScope = searchScope.toString()
                 searchScope.update("")
-                syncScopeState()
+                syncScopeState(restartSearch = true, oldScope = oldScope)
             }
 
             is SearchIntent.ToggleScopeGroup -> toggleScopeGroup(intent.groupName)
             is SearchIntent.ToggleScopeSource -> toggleScopeSource(intent.source)
             is SearchIntent.RemoveScopeItem -> {
+                val oldScope = searchScope.toString()
                 searchScope.remove(intent.scopeName)
-                syncScopeState()
+                syncScopeState(restartSearch = true, oldScope = oldScope)
             }
 
             is SearchIntent.TogglePrecision -> {
@@ -370,6 +372,7 @@ class SearchViewModel(
     }
 
     private fun toggleScopeGroup(groupName: String) {
+        val oldScope = searchScope.toString()
         if (searchScope.isSource()) {
             searchScope.update("")
         }
@@ -380,10 +383,11 @@ class SearchViewModel(
             selected.add(groupName)
         }
         searchScope.update(selected.toList())
-        syncScopeState()
+        syncScopeState(restartSearch = true, oldScope = oldScope)
     }
 
     private fun toggleScopeSource(source: BookSourcePart) {
+        val oldScope = searchScope.toString()
         val selectedUrls = if (searchScope.isSource()) {
             searchScope.sourceUrls.toMutableSet()
         } else {
@@ -404,7 +408,7 @@ class SearchViewModel(
             }
             searchScope.updateSources(selectedSources)
         }
-        syncScopeState()
+        syncScopeState(restartSearch = true, oldScope = oldScope)
     }
 
     private fun handleEmptyScopeActionConfirmed() {
@@ -429,7 +433,11 @@ class SearchViewModel(
         }
     }
 
-    private fun syncScopeState() {
+    private fun syncScopeState(
+        restartSearch: Boolean = false,
+        oldScope: String? = null,
+    ) {
+        val scopeChanged = oldScope == null || oldScope != searchScope.toString()
         _uiState.update {
             it.copy(
                 scopeDisplay = searchScope.display,
@@ -439,6 +447,9 @@ class SearchViewModel(
                 isSourceScope = searchScope.isSource(),
             )
         }
+        if (restartSearch && scopeChanged) {
+            restartCommittedSearchIfNeeded()
+        }
     }
 
     private fun List<SearchBook>.toSearchResultItems(