Horis há 1 ano atrás
pai
commit
b34adb82d9

+ 54 - 60
app/src/main/java/io/legado/app/model/ReadBook.kt

@@ -85,7 +85,7 @@ object ReadBook : CoroutineScope by MainScope() {
     var readStartTime: Long = System.currentTimeMillis()
     var readStartTime: Long = System.currentTimeMillis()
 
 
     /* 跳转进度前进度记录 */
     /* 跳转进度前进度记录 */
-    var lastBookPress: BookProgress? = null
+    var lastBookProgress: BookProgress? = null
 
 
     /* web端阅读进度记录 */
     /* web端阅读进度记录 */
     var webBookProgress: BookProgress? = null
     var webBookProgress: BookProgress? = null
@@ -98,20 +98,6 @@ object ReadBook : CoroutineScope by MainScope() {
     val preDownloadSemaphore = Semaphore(2)
     val preDownloadSemaphore = Semaphore(2)
     val executor = globalExecutor
     val executor = globalExecutor
 
 
-    //暂时保存跳转前进度
-    fun saveCurrentBookProcess() {
-        if (lastBookPress != null) return //避免进度条连续跳转不能覆盖最初的进度记录
-        lastBookPress = book?.let { BookProgress(it) }
-    }
-
-    //恢复跳转前进度
-    fun restoreLastBookProcess() {
-        lastBookPress?.let {
-            setProgress(it)
-            lastBookPress = null
-        }
-    }
-
     fun resetData(book: Book) {
     fun resetData(book: Book) {
         ReadBook.book = book
         ReadBook.book = book
         readRecord.bookName = book.name
         readRecord.bookName = book.name
@@ -131,7 +117,7 @@ object ReadBook : CoroutineScope by MainScope() {
         callBack?.upMenuView()
         callBack?.upMenuView()
         callBack?.upPageAnim()
         callBack?.upPageAnim()
         upWebBook(book)
         upWebBook(book)
-        lastBookPress = null
+        lastBookProgress = null
         webBookProgress = null
         webBookProgress = null
         TextFile.clear()
         TextFile.clear()
         synchronized(this) {
         synchronized(this) {
@@ -219,6 +205,20 @@ object ReadBook : CoroutineScope by MainScope() {
         }
         }
     }
     }
 
 
+    //暂时保存跳转前进度
+    fun saveCurrentBookProgress() {
+        if (lastBookProgress != null) return //避免进度条连续跳转不能覆盖最初的进度记录
+        lastBookProgress = book?.let { BookProgress(it) }
+    }
+
+    //恢复跳转前进度
+    fun restoreLastBookProgress() {
+        lastBookProgress?.let {
+            setProgress(it)
+            lastBookProgress = null
+        }
+    }
+
     fun clearTextChapter() {
     fun clearTextChapter() {
         prevTextChapter = null
         prevTextChapter = null
         curTextChapter = null
         curTextChapter = null
@@ -558,29 +558,27 @@ object ReadBook : CoroutineScope by MainScope() {
         resetPageOffset: Boolean = false,
         resetPageOffset: Boolean = false,
         success: (() -> Unit)? = null
         success: (() -> Unit)? = null
     ) {
     ) {
-        if (addLoading(index)) {
-            Coroutine.async {
-                val book = book!!
-                appDb.bookChapterDao.getChapter(book.bookUrl, index)?.let { chapter ->
-                    BookHelp.getContent(book, chapter)?.let {
-                        contentLoadFinish(
-                            book,
-                            chapter,
-                            it,
-                            upContent,
-                            resetPageOffset,
-                            success = success
-                        )
-                    } ?: download(
-                        downloadScope,
+        Coroutine.async {
+            val book = book!!
+            val chapter = appDb.bookChapterDao.getChapter(book.bookUrl, index) ?: return@async
+            if (addLoading(index)) {
+                BookHelp.getContent(book, chapter)?.let {
+                    contentLoadFinish(
+                        book,
                         chapter,
                         chapter,
-                        resetPageOffset
+                        it,
+                        upContent,
+                        resetPageOffset,
+                        success = success
                     )
                     )
-                } ?: removeLoading(index)
-            }.onError {
-                removeLoading(index)
-                AppLog.put("加载正文出错\n${it.localizedMessage}")
+                } ?: download(
+                    downloadScope,
+                    chapter,
+                    resetPageOffset
+                )
             }
             }
+        }.onError {
+            AppLog.put("加载正文出错\n${it.localizedMessage}")
         }
         }
     }
     }
 
 
@@ -615,20 +613,13 @@ object ReadBook : CoroutineScope by MainScope() {
             return
             return
         }
         }
         val book = book ?: return
         val book = book ?: return
-        if (addLoading(index)) {
-            try {
-                appDb.bookChapterDao.getChapter(book.bookUrl, index)?.let { chapter ->
-                    if (BookHelp.hasContent(book, chapter)) {
-                        removeLoading(chapter.index)
-                        downloadedChapters.add(chapter.index)
-                    } else {
-                        delay(1000)
-                        download(downloadScope, chapter, false, preDownloadSemaphore)
-                    }
-                } ?: removeLoading(index)
-            } catch (_: Exception) {
-                removeLoading(index)
-                coroutineContext.ensureActive()
+        val chapter = appDb.bookChapterDao.getChapter(book.bookUrl, index) ?: return
+        if (BookHelp.hasContent(book, chapter)) {
+            addDownloadedChapter(chapter.index)
+        } else {
+            delay(1000)
+            if (addLoading(index)) {
+                download(downloadScope, chapter, false, preDownloadSemaphore)
             }
             }
         }
         }
     }
     }
@@ -670,18 +661,21 @@ object ReadBook : CoroutineScope by MainScope() {
         }
         }
     }
     }
 
 
+    @Synchronized
     private fun addLoading(index: Int): Boolean {
     private fun addLoading(index: Int): Boolean {
-        synchronized(this) {
-            if (loadingChapters.contains(index)) return false
-            loadingChapters.add(index)
-            return true
-        }
+        if (loadingChapters.contains(index)) return false
+        loadingChapters.add(index)
+        return true
     }
     }
 
 
+    @Synchronized
     fun removeLoading(index: Int) {
     fun removeLoading(index: Int) {
-        synchronized(this) {
-            loadingChapters.remove(index)
-        }
+        loadingChapters.remove(index)
+    }
+
+    @Synchronized
+    fun addDownloadedChapter(index: Int) {
+        downloadedChapters.add(index)
     }
     }
 
 
     /**
     /**
@@ -901,7 +895,7 @@ object ReadBook : CoroutineScope by MainScope() {
                 launch {
                 launch {
                     val maxChapterIndex =
                     val maxChapterIndex =
                         min(durChapterIndex + AppConfig.preDownloadNum, chapterSize)
                         min(durChapterIndex + AppConfig.preDownloadNum, chapterSize)
-                    for (i in durChapterIndex.plus(1)..maxChapterIndex) {
+                    for (i in durChapterIndex.plus(2)..maxChapterIndex) {
                         if (downloadedChapters.contains(i)) continue
                         if (downloadedChapters.contains(i)) continue
                         if ((downloadFailChapters[i] ?: 0) >= 3) continue
                         if ((downloadFailChapters[i] ?: 0) >= 3) continue
                         downloadIndex(i)
                         downloadIndex(i)
@@ -909,7 +903,7 @@ object ReadBook : CoroutineScope by MainScope() {
                 }
                 }
                 launch {
                 launch {
                     val minChapterIndex = durChapterIndex - min(5, AppConfig.preDownloadNum)
                     val minChapterIndex = durChapterIndex - min(5, AppConfig.preDownloadNum)
-                    for (i in durChapterIndex.minus(1) downTo minChapterIndex) {
+                    for (i in durChapterIndex.minus(2) downTo minChapterIndex) {
                         if (downloadedChapters.contains(i)) continue
                         if (downloadedChapters.contains(i)) continue
                         if ((downloadFailChapters[i] ?: 0) >= 3) continue
                         if ((downloadFailChapters[i] ?: 0) >= 3) continue
                         downloadIndex(i)
                         downloadIndex(i)

+ 93 - 97
app/src/main/java/io/legado/app/model/ReadManga.kt

@@ -70,64 +70,44 @@ object ReadManga : CoroutineScope by MainScope() {
     val mangaContents get() = buildContentList()
     val mangaContents get() = buildContentList()
     val hasNextChapter get() = durChapterIndex < simulatedChapterSize - 1
     val hasNextChapter get() = durChapterIndex < simulatedChapterSize - 1
 
 
-    fun saveRead(pageChanged: Boolean = false) {
-        executor.execute {
-            val book = book ?: return@execute
-            book.lastCheckCount = 0
-            book.durChapterTime = System.currentTimeMillis()
-            val chapterChanged = book.durChapterIndex != durChapterIndex
-            book.durChapterIndex = durChapterIndex
-            book.durChapterPos = durChapterPos
-            if (!pageChanged || chapterChanged) {
-                appDb.bookChapterDao.getChapter(book.bookUrl, durChapterIndex)?.let {
-                    book.durChapterTitle = it.getDisplayTitle(
-                        ContentProcessor.get(book.name, book.origin).getTitleReplaceRules(),
-                        book.getUseReplaceRule()
-                    )
-                }
-            }
-            appDb.bookDao.update(book)
-        }
-    }
-
-    fun upData(book: Book) {
+    fun resetData(book: Book) {
         ReadManga.book = book
         ReadManga.book = book
+        readRecord.bookName = book.name
+        readRecord.readTime = appDb.readRecordDao.getReadTime(book.name) ?: 0
         chapterSize = appDb.bookChapterDao.getChapterCount(book.bookUrl)
         chapterSize = appDb.bookChapterDao.getChapterCount(book.bookUrl)
         simulatedChapterSize = if (book.readSimulating()) {
         simulatedChapterSize = if (book.readSimulating()) {
             book.simulatedTotalChapterNum()
             book.simulatedTotalChapterNum()
         } else {
         } else {
             chapterSize
             chapterSize
         }
         }
-
-        if (durChapterIndex != book.durChapterIndex || tocChanged) {
-            durChapterIndex = book.durChapterIndex
-            durChapterPos = book.durChapterPos
-            clearMangaChapter()
-        }
+        durChapterIndex = book.durChapterIndex
+        durChapterPos = book.durChapterPos
+        clearMangaChapter()
         upWebBook(book)
         upWebBook(book)
         synchronized(this) {
         synchronized(this) {
             loadingChapters.clear()
             loadingChapters.clear()
+            downloadedChapters.clear()
+            downloadFailChapters.clear()
         }
         }
     }
     }
 
 
-    fun resetData(book: Book) {
+    fun upData(book: Book) {
         ReadManga.book = book
         ReadManga.book = book
-        readRecord.bookName = book.name
-        readRecord.readTime = appDb.readRecordDao.getReadTime(book.name) ?: 0
         chapterSize = appDb.bookChapterDao.getChapterCount(book.bookUrl)
         chapterSize = appDb.bookChapterDao.getChapterCount(book.bookUrl)
         simulatedChapterSize = if (book.readSimulating()) {
         simulatedChapterSize = if (book.readSimulating()) {
             book.simulatedTotalChapterNum()
             book.simulatedTotalChapterNum()
         } else {
         } else {
             chapterSize
             chapterSize
         }
         }
-        durChapterIndex = book.durChapterIndex
-        durChapterPos = book.durChapterPos
-        clearMangaChapter()
+
+        if (durChapterIndex != book.durChapterIndex || tocChanged) {
+            durChapterIndex = book.durChapterIndex
+            durChapterPos = book.durChapterPos
+            clearMangaChapter()
+        }
         upWebBook(book)
         upWebBook(book)
         synchronized(this) {
         synchronized(this) {
             loadingChapters.clear()
             loadingChapters.clear()
-            downloadedChapters.clear()
-            downloadFailChapters.clear()
         }
         }
     }
     }
 
 
@@ -159,43 +139,21 @@ object ReadManga : CoroutineScope by MainScope() {
         }
         }
     }
     }
 
 
+    @Synchronized
     private fun addLoading(index: Int): Boolean {
     private fun addLoading(index: Int): Boolean {
-        synchronized(this) {
-            if (loadingChapters.contains(index)) return false
-            loadingChapters.add(index)
-            return true
-        }
+        if (loadingChapters.contains(index)) return false
+        loadingChapters.add(index)
+        return true
     }
     }
 
 
+    @Synchronized
     fun removeLoading(index: Int) {
     fun removeLoading(index: Int) {
-        synchronized(this) {
-            loadingChapters.remove(index)
-        }
+        loadingChapters.remove(index)
     }
     }
 
 
-    /**
-     * 获取正文
-     */
-    private fun download(
-        scope: CoroutineScope,
-        chapter: BookChapter,
-        semaphore: Semaphore? = null,
-    ) {
-        val book = book ?: return removeLoading(chapter.index)
-        val bookSource = bookSource
-        if (bookSource != null) {
-            downloadNetworkContent(bookSource, scope, chapter, book, semaphore, success = {
-                downloadedChapters.add(chapter.index)
-                downloadFailChapters.remove(chapter.index)
-                contentLoadFinish(chapter, it)
-            }, error = {
-                downloadFailChapters[chapter.index] =
-                    (downloadFailChapters[chapter.index] ?: 0) + 1
-                contentLoadFinish(chapter, null)
-            }, cancel = {
-                contentLoadFinish(chapter, null, true)
-            })
-        }
+    @Synchronized
+    fun addDownloadedChapter(index: Int) {
+        downloadedChapters.add(index)
     }
     }
 
 
     fun loadContent() {
     fun loadContent() {
@@ -220,21 +178,18 @@ object ReadManga : CoroutineScope by MainScope() {
     }
     }
 
 
     private fun loadContent(index: Int) {
     private fun loadContent(index: Int) {
-        if (addLoading(index)) {
-            Coroutine.async {
-                val book = book!!
-                appDb.bookChapterDao.getChapter(book.bookUrl, index)?.let { chapter ->
-                    BookHelp.getContent(book, chapter)?.let {
-                        contentLoadFinish(chapter, it)
-                    } ?: download(
-                        downloadScope,
-                        chapter,
-                    )
-                } ?: removeLoading(index)
-            }.onError {
-                removeLoading(index)
-                AppLog.put("加载正文出错\n${it.localizedMessage}")
+        Coroutine.async {
+            val book = book!!
+            val chapter = appDb.bookChapterDao.getChapter(book.bookUrl, index) ?: return@async
+            if (addLoading(index)) {
+                BookHelp.getContent(book, chapter)?.let {
+                    contentLoadFinish(chapter, it)
+                } ?: run {
+                    download(downloadScope, chapter)
+                }
             }
             }
+        }.onError {
+            AppLog.put("加载正文出错\n${it.localizedMessage}")
         }
         }
     }
     }
 
 
@@ -244,6 +199,7 @@ object ReadManga : CoroutineScope by MainScope() {
     suspend fun contentLoadFinish(
     suspend fun contentLoadFinish(
         chapter: BookChapter,
         chapter: BookChapter,
         content: String?,
         content: String?,
+        errorMsg: String = "加载内容失败",
         canceled: Boolean = false
         canceled: Boolean = false
     ) {
     ) {
         removeLoading(chapter.index)
         removeLoading(chapter.index)
@@ -253,7 +209,7 @@ object ReadManga : CoroutineScope by MainScope() {
         when (val offset = chapter.index - durChapterIndex) {
         when (val offset = chapter.index - durChapterIndex) {
             0 -> {
             0 -> {
                 if (content == null) {
                 if (content == null) {
-                    mCallback?.loadFail("加载内容失败")
+                    mCallback?.loadFail(errorMsg)
                     return
                     return
                 }
                 }
                 if (content.isEmpty()) {
                 if (content.isEmpty()) {
@@ -354,6 +310,26 @@ object ReadManga : CoroutineScope by MainScope() {
         preDownload()
         preDownload()
     }
     }
 
 
+    fun saveRead(pageChanged: Boolean = false) {
+        executor.execute {
+            val book = book ?: return@execute
+            book.lastCheckCount = 0
+            book.durChapterTime = System.currentTimeMillis()
+            val chapterChanged = book.durChapterIndex != durChapterIndex
+            book.durChapterIndex = durChapterIndex
+            book.durChapterPos = durChapterPos
+            if (!pageChanged || chapterChanged) {
+                appDb.bookChapterDao.getChapter(book.bookUrl, durChapterIndex)?.let {
+                    book.durChapterTitle = it.getDisplayTitle(
+                        ContentProcessor.get(book.name, book.origin).getTitleReplaceRules(),
+                        book.getUseReplaceRule()
+                    )
+                }
+            }
+            appDb.bookDao.update(book)
+        }
+    }
+
     private fun downloadNetworkContent(
     private fun downloadNetworkContent(
         bookSource: BookSource,
         bookSource: BookSource,
         scope: CoroutineScope,
         scope: CoroutineScope,
@@ -393,7 +369,7 @@ object ReadManga : CoroutineScope by MainScope() {
                 launch {
                 launch {
                     val maxChapterIndex =
                     val maxChapterIndex =
                         min(durChapterIndex + AppConfig.preDownloadNum, chapterSize)
                         min(durChapterIndex + AppConfig.preDownloadNum, chapterSize)
-                    for (i in durChapterIndex.plus(1)..maxChapterIndex) {
+                    for (i in durChapterIndex.plus(2)..maxChapterIndex) {
                         if (downloadedChapters.contains(i)) continue
                         if (downloadedChapters.contains(i)) continue
                         if ((downloadFailChapters[i] ?: 0) >= 3) continue
                         if ((downloadFailChapters[i] ?: 0) >= 3) continue
                         downloadIndex(i)
                         downloadIndex(i)
@@ -401,7 +377,7 @@ object ReadManga : CoroutineScope by MainScope() {
                 }
                 }
                 launch {
                 launch {
                     val minChapterIndex = durChapterIndex - min(5, AppConfig.preDownloadNum)
                     val minChapterIndex = durChapterIndex - min(5, AppConfig.preDownloadNum)
-                    for (i in durChapterIndex.minus(1) downTo minChapterIndex) {
+                    for (i in durChapterIndex.minus(2) downTo minChapterIndex) {
                         if (downloadedChapters.contains(i)) continue
                         if (downloadedChapters.contains(i)) continue
                         if ((downloadFailChapters[i] ?: 0) >= 3) continue
                         if ((downloadFailChapters[i] ?: 0) >= 3) continue
                         downloadIndex(i)
                         downloadIndex(i)
@@ -425,24 +401,44 @@ object ReadManga : CoroutineScope by MainScope() {
             return
             return
         }
         }
         val book = book ?: return
         val book = book ?: return
-        if (addLoading(index)) {
-            try {
-                appDb.bookChapterDao.getChapter(book.bookUrl, index)?.let { chapter ->
-                    if (BookHelp.hasContent(book, chapter)) {
-                        removeLoading(chapter.index)
-                        downloadedChapters.add(chapter.index)
-                    } else {
-                        delay(1000)
-                        download(downloadScope, chapter, preDownloadSemaphore)
-                    }
-                } ?: removeLoading(index)
-            } catch (_: Exception) {
-                removeLoading(index)
-                coroutineContext.ensureActive()
+        val chapter = appDb.bookChapterDao.getChapter(book.bookUrl, index) ?: return
+        if (BookHelp.hasContent(book, chapter)) {
+            addDownloadedChapter(chapter.index)
+        } else {
+            delay(1000)
+            if (addLoading(index)) {
+                download(downloadScope, chapter, preDownloadSemaphore)
             }
             }
         }
         }
     }
     }
 
 
+    /**
+     * 获取正文
+     */
+    private suspend fun download(
+        scope: CoroutineScope,
+        chapter: BookChapter,
+        semaphore: Semaphore? = null,
+    ) {
+        val book = book ?: return removeLoading(chapter.index)
+        val bookSource = bookSource
+        if (bookSource != null) {
+            downloadNetworkContent(bookSource, scope, chapter, book, semaphore, success = {
+                downloadedChapters.add(chapter.index)
+                downloadFailChapters.remove(chapter.index)
+                contentLoadFinish(chapter, it)
+            }, error = {
+                downloadFailChapters[chapter.index] =
+                    (downloadFailChapters[chapter.index] ?: 0) + 1
+                contentLoadFinish(chapter, null)
+            }, cancel = {
+                contentLoadFinish(chapter, null, canceled =  true)
+            })
+        } else {
+            contentLoadFinish(chapter, null, "加载内容失败 没有书源")
+        }
+    }
+
     @Synchronized
     @Synchronized
     fun upToc() {
     fun upToc() {
         val bookSource = bookSource ?: return
         val bookSource = bookSource ?: return

+ 7 - 7
app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt

@@ -186,7 +186,7 @@ class ReadBookActivity : BaseReadBookActivity(),
                     viewModel.searchResultIndex = index
                     viewModel.searchResultIndex = index
                     binding.searchMenu.updateSearchResultIndex(index)
                     binding.searchMenu.updateSearchResultIndex(index)
                     binding.searchMenu.selectedSearchResult?.let { currentResult ->
                     binding.searchMenu.selectedSearchResult?.let { currentResult ->
-                        ReadBook.saveCurrentBookProcess() //退出全文搜索恢复此时进度
+                        ReadBook.saveCurrentBookProgress() //退出全文搜索恢复此时进度
                         skipToSearch(currentResult)
                         skipToSearch(currentResult)
                         showActionMenu()
                         showActionMenu()
                     }
                     }
@@ -269,7 +269,7 @@ class ReadBookActivity : BaseReadBookActivity(),
                 return@addCallback
                 return@addCallback
             }
             }
             //拦截返回供恢复阅读进度
             //拦截返回供恢复阅读进度
-            if (ReadBook.lastBookPress != null && confirmRestoreProcess != false) {
+            if (ReadBook.lastBookProgress != null && confirmRestoreProcess != false) {
                 restoreLastBookProcess()
                 restoreLastBookProcess()
                 return@addCallback
                 return@addCallback
             }
             }
@@ -1239,20 +1239,20 @@ class ReadBookActivity : BaseReadBookActivity(),
     /* 恢复到 全文搜索/进度条跳转前的位置 */
     /* 恢复到 全文搜索/进度条跳转前的位置 */
     private fun restoreLastBookProcess() {
     private fun restoreLastBookProcess() {
         if (confirmRestoreProcess == true) {
         if (confirmRestoreProcess == true) {
-            ReadBook.restoreLastBookProcess()
+            ReadBook.restoreLastBookProgress()
         } else if (confirmRestoreProcess == null) {
         } else if (confirmRestoreProcess == null) {
             alert(R.string.draw) {
             alert(R.string.draw) {
                 setMessage(R.string.restore_last_book_process)
                 setMessage(R.string.restore_last_book_process)
                 yesButton {
                 yesButton {
                     confirmRestoreProcess = true
                     confirmRestoreProcess = true
-                    ReadBook.restoreLastBookProcess() //恢复启动全文搜索前的进度
+                    ReadBook.restoreLastBookProgress() //恢复启动全文搜索前的进度
                 }
                 }
                 noButton {
                 noButton {
-                    ReadBook.lastBookPress = null
+                    ReadBook.lastBookProgress = null
                     confirmRestoreProcess = false
                     confirmRestoreProcess = false
                 }
                 }
                 onCancelled {
                 onCancelled {
-                    ReadBook.lastBookPress = null
+                    ReadBook.lastBookProgress = null
                     confirmRestoreProcess = false
                     confirmRestoreProcess = false
                 }
                 }
             }
             }
@@ -1451,7 +1451,7 @@ class ReadBookActivity : BaseReadBookActivity(),
 
 
     /* 进度条跳转到指定章节 */
     /* 进度条跳转到指定章节 */
     override fun skipToChapter(index: Int) {
     override fun skipToChapter(index: Int) {
-        ReadBook.saveCurrentBookProcess() //退出章节跳转恢复此时进度
+        ReadBook.saveCurrentBookProgress() //退出章节跳转恢复此时进度
         viewModel.openChapter(index)
         viewModel.openChapter(index)
     }
     }