Reader: Save reading progress with SQLDelight (#7185)

* Use SQLDelight in reader to update history

* Move chapter progress to sqldelight

* Review Changes

Co-Authored-By: inorichi <len@kanade.eu>

* Review Changes 2

Co-authored-by: FourTOne5 <59261191+FourTOne5@users.noreply.github.com>
Co-authored-by: inorichi <len@kanade.eu>
This commit is contained in:
AntsyLich
2022-05-28 19:09:27 +06:00
committed by GitHub
parent 6b14f38cfa
commit 809da49301
22 changed files with 309 additions and 67 deletions

View File

@@ -232,7 +232,7 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>() {
}
override fun onPause() {
presenter.saveProgress()
presenter.saveCurrentChapterReadingProgress()
super.onPause()
}
@@ -242,6 +242,7 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>() {
*/
override fun onResume() {
super.onResume()
presenter.setReadStartTime()
setMenuVisibility(menuVisible, animate = false)
}

View File

@@ -4,9 +4,12 @@ import android.app.Application
import android.net.Uri
import android.os.Bundle
import com.jakewharton.rxrelay.BehaviorRelay
import eu.kanade.domain.chapter.interactor.UpdateChapter
import eu.kanade.domain.chapter.model.ChapterUpdate
import eu.kanade.domain.history.interactor.UpsertHistory
import eu.kanade.domain.history.model.HistoryUpdate
import eu.kanade.tachiyomi.data.cache.CoverCache
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.History
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
@@ -62,6 +65,8 @@ class ReaderPresenter(
private val coverCache: CoverCache = Injekt.get(),
private val preferences: PreferencesHelper = Injekt.get(),
private val delayedTrackingStore: DelayedTrackingStore = Injekt.get(),
private val upsertHistory: UpsertHistory = Injekt.get(),
private val updateChapter: UpdateChapter = Injekt.get(),
) : BasePresenter<ReaderActivity>() {
/**
@@ -80,6 +85,11 @@ class ReaderPresenter(
*/
private var loader: ChapterLoader? = null
/**
* The time the chapter was started reading
*/
private var chapterReadStartTime: Long? = null
/**
* Subscription to prevent setting chapters as active from multiple threads.
*/
@@ -168,8 +178,7 @@ class ReaderPresenter(
val currentChapters = viewerChaptersRelay.value
if (currentChapters != null) {
currentChapters.unref()
saveChapterProgress(currentChapters.currChapter)
saveChapterHistory(currentChapters.currChapter)
saveReadingProgress(currentChapters.currChapter)
}
}
@@ -200,7 +209,9 @@ class ReaderPresenter(
*/
fun onSaveInstanceStateNonConfigurationChange() {
val currentChapter = getCurrentChapter() ?: return
saveChapterProgress(currentChapter)
launchIO {
saveChapterProgress(currentChapter)
}
}
/**
@@ -397,7 +408,7 @@ class ReaderPresenter(
if (selectedChapter != currentChapters.currChapter) {
logcat { "Setting ${selectedChapter.chapter.url} as active" }
onChapterChanged(currentChapters.currChapter)
saveReadingProgress(currentChapters.currChapter)
loadNewChapter(selectedChapter)
}
}
@@ -429,43 +440,57 @@ class ReaderPresenter(
}
}
/**
* Called when a chapter changed from [fromChapter] to [toChapter]. It updates [fromChapter]
* on the database.
*/
private fun onChapterChanged(fromChapter: ReaderChapter) {
saveChapterProgress(fromChapter)
saveChapterHistory(fromChapter)
fun saveCurrentChapterReadingProgress() {
getCurrentChapter()?.let { saveReadingProgress(it) }
}
/**
* Saves this [chapter] progress (last read page and whether it's read).
* Called when reader chapter is changed in reader or when activity is paused.
*/
private fun saveReadingProgress(readerChapter: ReaderChapter) {
launchIO {
saveChapterProgress(readerChapter)
saveChapterHistory(readerChapter)
}
}
/**
* Saves this [readerChapter] progress (last read page and whether it's read).
* If incognito mode isn't on or has at least 1 tracker
*/
private fun saveChapterProgress(chapter: ReaderChapter) {
private suspend fun saveChapterProgress(readerChapter: ReaderChapter) {
if (!incognitoMode || hasTrackers) {
db.updateChapterProgress(chapter.chapter).asRxCompletable()
.onErrorComplete()
.subscribeOn(Schedulers.io())
.subscribe()
val chapter = readerChapter.chapter
updateChapter.await(
ChapterUpdate(
id = chapter.id!!,
read = chapter.read,
bookmark = chapter.bookmark,
lastPageRead = chapter.last_page_read.toLong(),
),
)
}
}
/**
* Saves this [chapter] last read history if incognito mode isn't on.
* Saves this [readerChapter] last read history if incognito mode isn't on.
*/
private fun saveChapterHistory(chapter: ReaderChapter) {
private suspend fun saveChapterHistory(readerChapter: ReaderChapter) {
if (!incognitoMode) {
val history = History.create(chapter.chapter).apply { last_read = Date().time }
db.upsertHistoryLastRead(history).asRxCompletable()
.onErrorComplete()
.subscribeOn(Schedulers.io())
.subscribe()
val chapterId = readerChapter.chapter.id!!
val readAt = Date()
val sessionReadDuration = chapterReadStartTime?.let { readAt.time - it } ?: 0
upsertHistory.await(
HistoryUpdate(chapterId, readAt, sessionReadDuration),
).also {
chapterReadStartTime = null
}
}
}
fun saveProgress() {
getCurrentChapter()?.let { onChapterChanged(it) }
fun setReadStartTime() {
chapterReadStartTime = Date().time
}
/**
@@ -633,7 +658,7 @@ class ReaderPresenter(
* Shares the image of this [page] and notifies the UI with the path of the file to share.
* The image must be first copied to the internal partition because there are many possible
* formats it can come from, like a zipped chapter, in which case it's not possible to directly
* get a path to the file and it has to be decompresssed somewhere first. Only the last shared
* get a path to the file and it has to be decompressed somewhere first. Only the last shared
* image will be kept so it won't be taking lots of internal disk space.
*/
fun shareImage(page: ReaderPage) {