From 9a53f9eaf4cabb917842f83a91ecb63e78c89a50 Mon Sep 17 00:00:00 2001 From: HapeLee <63206378+HapeLee@users.noreply.github.com> Date: Tue, 9 Jun 2026 00:45:14 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E7=94=B5=E9=87=8F=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E5=8D=A1=E4=BD=8F=E5=8F=8A=E9=98=85=E8=AF=BB=E8=AE=B0=E5=BD=95?= =?UTF-8?q?=E4=B8=A2=E5=A4=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/io/legado/app/model/ReadBook.kt | 31 +++++++++++++++---- .../app/ui/book/read/ReadBookController.kt | 6 +++- .../app/ui/book/read/ReadBookRouteScreen.kt | 5 +++ 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/ReadBook.kt b/app/src/main/java/io/legado/app/model/ReadBook.kt index 367cb8250..cc35dbd69 100644 --- a/app/src/main/java/io/legado/app/model/ReadBook.kt +++ b/app/src/main/java/io/legado/app/model/ReadBook.kt @@ -109,7 +109,7 @@ object ReadBook : CoroutineScope by MainScope(), KoinComponent { val executor = globalExecutor - private val ioScope = CoroutineScope(IO) + private val ioScope = CoroutineScope(SupervisorJob() + IO) private var autoSaveJob: Job? = null @@ -376,27 +376,46 @@ object ReadBook : CoroutineScope by MainScope(), KoinComponent { } fun commitReadSession() { + val sessionToCommit = currentActiveSession ?: return + currentActiveSession = null ioScope.launch { - commitSessionInternal() + saveSessionToDb(sessionToCommit) } } /** - * 内部提交逻辑 + * 内部提交逻辑(auto-save 专用):保存后立即创建新 session 保证连续记录 */ private suspend fun commitSessionInternal() { val sessionToSave = currentActiveSession ?: return val sessionDuration = sessionToSave.endTime - sessionToSave.startTime if (sessionDuration < MIN_READ_DURATION) { - currentActiveSession = null return } try { readRecordRepository.saveReadSession(sessionToSave) } catch (e: Exception) { AppLog.put("保存阅读会话出错: ${sessionToSave.bookName}", e) - } finally { - currentActiveSession = null + return + } + // 保存成功后立即创建新 session,避免 auto-save 空窗期 + currentActiveSession = sessionToSave.copy( + startTime = sessionToSave.endTime, + endTime = sessionToSave.endTime, + words = durChapterIndex.toLong() + ) + } + + /** + * 将 session 写入数据库(pause 专用,不重建 session) + */ + private suspend fun saveSessionToDb(session: ReadRecordSession) { + val sessionDuration = session.endTime - session.startTime + if (sessionDuration < MIN_READ_DURATION) return + try { + readRecordRepository.saveReadSession(session) + } catch (e: Exception) { + AppLog.put("保存阅读会话出错: ${session.bookName}", e) } } diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookController.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookController.kt index 039a524e4..485c7c93d 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookController.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookController.kt @@ -11,6 +11,7 @@ import android.view.MotionEvent import android.view.View import android.view.WindowInsets import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.ContextCompat import androidx.core.view.HapticFeedbackConstantsCompat import androidx.core.view.WindowInsetsCompat import androidx.core.view.doOnAttach @@ -1014,7 +1015,10 @@ class ReadBookController( private fun registerTimeBatteryReceiver() { if (timeBatteryReceiverRegistered) return - activity.registerReceiver(timeBatteryReceiver, timeBatteryReceiver.filter) + ContextCompat.registerReceiver( + activity, timeBatteryReceiver, timeBatteryReceiver.filter, + ContextCompat.RECEIVER_EXPORTED + ) timeBatteryReceiverRegistered = true } diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookRouteScreen.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookRouteScreen.kt index 7ea96c5bf..aca69e227 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookRouteScreen.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookRouteScreen.kt @@ -25,6 +25,7 @@ import com.kyant.backdrop.backdrops.rememberLayerBackdrop import dev.chrisbanes.haze.HazeState import dev.chrisbanes.haze.hazeSource import io.legado.app.R +import io.legado.app.constant.AppLog import io.legado.app.constant.ReadMenuBlurMode import io.legado.app.help.IntentData import io.legado.app.help.IntentHelp @@ -235,6 +236,7 @@ fun ReadBookRouteScreen( coroutineScope { val collector = launch { viewModel.effects.collect { effect -> + try { when (effect) { // Launcher-dependent effects — handled directly by route is ReadBookEffect.OpenChapterList -> { @@ -346,6 +348,9 @@ fun ReadBookRouteScreen( // All other effects — delegate to bridge (View/Window/Activity operations) else -> controller.handleEffect(effect) } + } catch (e: Exception) { + AppLog.put("ReadBook effect处理异常: ${effect::class.simpleName}", e) + } } } yield()