mirror of
https://github.com/null2264/yokai.git
synced 2025-06-21 10:44:42 +00:00
refactor(chapter): Migrate more queries to SQLDelight
This commit is contained in:
parent
fac21dbab7
commit
1e68e55cf7
14 changed files with 160 additions and 95 deletions
|
@ -10,12 +10,14 @@ import eu.kanade.tachiyomi.data.library.CustomMangaManager
|
|||
import eu.kanade.tachiyomi.domain.manga.models.Manga
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import yokai.domain.chapter.interactor.GetChapter
|
||||
|
||||
class MangaBackupCreator(
|
||||
private val db: DatabaseHelper = Injekt.get(),
|
||||
private val customMangaManager: CustomMangaManager = Injekt.get(),
|
||||
private val getChapter: GetChapter = Injekt.get(),
|
||||
) {
|
||||
operator fun invoke(mangas: List<Manga>, options: BackupOptions): List<BackupManga> {
|
||||
suspend operator fun invoke(mangas: List<Manga>, options: BackupOptions): List<BackupManga> {
|
||||
if (!options.libraryEntries) return emptyList()
|
||||
|
||||
return mangas.map {
|
||||
|
@ -30,14 +32,14 @@ class MangaBackupCreator(
|
|||
* @param options options for the backup
|
||||
* @return [BackupManga] containing manga in a serializable form
|
||||
*/
|
||||
private fun backupManga(manga: Manga, options: BackupOptions): BackupManga {
|
||||
private suspend fun backupManga(manga: Manga, options: BackupOptions): BackupManga {
|
||||
// Entry for this manga
|
||||
val mangaObject = BackupManga.copyFrom(manga, if (options.customInfo) customMangaManager else null)
|
||||
|
||||
// Check if user wants chapter information in backup
|
||||
if (options.chapters) {
|
||||
// Backup all the chapters
|
||||
val chapters = db.getChapters(manga).executeAsBlocking()
|
||||
val chapters = manga.id?.let { getChapter.awaitAll(it, false) }.orEmpty()
|
||||
if (chapters.isNotEmpty()) {
|
||||
mangaObject.chapters = chapters.map { BackupChapter.copyFrom(it) }
|
||||
}
|
||||
|
@ -65,7 +67,7 @@ class MangaBackupCreator(
|
|||
val historyForManga = db.getHistoryByMangaId(manga.id!!).executeAsBlocking()
|
||||
if (historyForManga.isNotEmpty()) {
|
||||
val history = historyForManga.mapNotNull { history ->
|
||||
val url = db.getChapter(history.chapter_id).executeAsBlocking()?.url
|
||||
val url = getChapter.awaitById(history.chapter_id)?.url
|
||||
url?.let { BackupHistory(url, history.last_read, history.time_read) }
|
||||
}
|
||||
if (history.isNotEmpty()) {
|
||||
|
|
|
@ -21,6 +21,7 @@ import uy.kohesive.injekt.api.get
|
|||
import yokai.domain.category.interactor.GetCategories
|
||||
import yokai.domain.chapter.interactor.GetChapter
|
||||
import yokai.domain.chapter.interactor.InsertChapter
|
||||
import yokai.domain.chapter.interactor.UpdateChapter
|
||||
import yokai.domain.library.custom.model.CustomMangaInfo
|
||||
import yokai.domain.manga.interactor.GetManga
|
||||
import yokai.domain.manga.interactor.InsertManga
|
||||
|
@ -32,6 +33,7 @@ class MangaBackupRestorer(
|
|||
private val getCategories: GetCategories = Injekt.get(),
|
||||
private val getChapter: GetChapter = Injekt.get(),
|
||||
private val insertChapter: InsertChapter = Injekt.get(),
|
||||
private val updateChapter: UpdateChapter = Injekt.get(),
|
||||
private val getManga: GetManga = Injekt.get(),
|
||||
private val insertManga: InsertManga = Injekt.get(),
|
||||
private val updateManga: UpdateManga = Injekt.get(),
|
||||
|
@ -138,7 +140,7 @@ class MangaBackupRestorer(
|
|||
}
|
||||
|
||||
val newChapters = chapters.groupBy { it.id != null }
|
||||
newChapters[true]?.let { db.updateKnownChaptersBackup(it).executeAsBlocking() }
|
||||
newChapters[true]?.let { updateChapter.awaitAll(it.map(Chapter::toProgressUpdate)) }
|
||||
newChapters[false]?.let { insertChapter.awaitBulk(it) }
|
||||
}
|
||||
|
||||
|
@ -210,7 +212,7 @@ class MangaBackupRestorer(
|
|||
historyToBeUpdated.add(dbHistory)
|
||||
} else {
|
||||
// If not in database create
|
||||
db.getChapter(url).executeAsBlocking()?.let {
|
||||
getChapter.awaitByUrl(url, false)?.let {
|
||||
val historyToAdd = History.create(it).apply {
|
||||
last_read = lastRead
|
||||
time_read = readDuration
|
||||
|
|
|
@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.data.database.models
|
|||
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import java.io.Serializable
|
||||
import yokai.domain.chapter.models.ChapterUpdate
|
||||
|
||||
interface Chapter : SChapter, Serializable {
|
||||
|
||||
|
@ -24,6 +25,15 @@ interface Chapter : SChapter, Serializable {
|
|||
val isRecognizedNumber: Boolean
|
||||
get() = chapter_number >= 0f
|
||||
|
||||
fun toProgressUpdate() =
|
||||
ChapterUpdate(
|
||||
id = this.id!!,
|
||||
read = this.read,
|
||||
bookmark = this.bookmark,
|
||||
lastPageRead = this.last_page_read.toLong(),
|
||||
pagesLeft = this.pages_left.toLong(),
|
||||
)
|
||||
|
||||
companion object {
|
||||
|
||||
fun create(): Chapter = ChapterImpl().apply {
|
||||
|
|
|
@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.data.database.queries
|
|||
import com.pushtorefresh.storio.sqlite.queries.Query
|
||||
import eu.kanade.tachiyomi.data.database.DbProvider
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.data.database.resolvers.ChapterKnownBackupPutResolver
|
||||
import eu.kanade.tachiyomi.data.database.resolvers.ChapterProgressPutResolver
|
||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable
|
||||
import eu.kanade.tachiyomi.domain.manga.models.Manga
|
||||
|
@ -23,6 +22,7 @@ interface ChapterQueries : DbProvider {
|
|||
)
|
||||
.prepare()
|
||||
|
||||
// FIXME: Migrate to SQLDelight, on halt: in StorIO transaction
|
||||
fun getChapter(id: Long) = db.get()
|
||||
.`object`(Chapter::class.java)
|
||||
.withQuery(
|
||||
|
@ -34,54 +34,12 @@ interface ChapterQueries : DbProvider {
|
|||
)
|
||||
.prepare()
|
||||
|
||||
fun getChapter(url: String) = db.get()
|
||||
.`object`(Chapter::class.java)
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(ChapterTable.TABLE)
|
||||
.where("${ChapterTable.COL_URL} = ?")
|
||||
.whereArgs(url)
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun getChapters(url: String) = db.get()
|
||||
.listOfObjects(Chapter::class.java)
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(ChapterTable.TABLE)
|
||||
.where("${ChapterTable.COL_URL} = ?")
|
||||
.whereArgs(url)
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun getChapter(url: String, mangaId: Long) = db.get()
|
||||
.`object`(Chapter::class.java)
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(ChapterTable.TABLE)
|
||||
.where("${ChapterTable.COL_URL} = ? AND ${ChapterTable.COL_MANGA_ID} = ?")
|
||||
.whereArgs(url, mangaId)
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
|
||||
// FIXME: Migrate to SQLDelight, on halt: in StorIO transaction
|
||||
fun insertChapters(chapters: List<Chapter>) = db.put().objects(chapters).prepare()
|
||||
|
||||
fun updateKnownChaptersBackup(chapters: List<Chapter>) = db.put()
|
||||
.objects(chapters)
|
||||
.withPutResolver(ChapterKnownBackupPutResolver())
|
||||
.prepare()
|
||||
|
||||
// FIXME: Migrate to SQLDelight, on halt: in StorIO transaction
|
||||
fun updateChapterProgress(chapter: Chapter) = db.put()
|
||||
.`object`(chapter)
|
||||
.withPutResolver(ChapterProgressPutResolver())
|
||||
.prepare()
|
||||
|
||||
fun updateChaptersProgress(chapters: List<Chapter>) = db.put()
|
||||
.objects(chapters)
|
||||
.withPutResolver(ChapterProgressPutResolver())
|
||||
.prepare()
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.data.download
|
|||
|
||||
import android.content.Context
|
||||
import androidx.core.content.edit
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.download.model.Download
|
||||
import eu.kanade.tachiyomi.domain.manga.models.Manga
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
|
@ -11,6 +10,8 @@ import kotlinx.serialization.Serializable
|
|||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import yokai.domain.chapter.interactor.GetChapter
|
||||
import yokai.domain.manga.interactor.GetManga
|
||||
|
||||
/**
|
||||
* This class is used to persist active downloads across application restarts.
|
||||
|
@ -28,7 +29,8 @@ class DownloadStore(
|
|||
private val preferences = context.getSharedPreferences("active_downloads", Context.MODE_PRIVATE)
|
||||
|
||||
private val json: Json by injectLazy()
|
||||
private val db: DatabaseHelper by injectLazy()
|
||||
private val getChapter: GetChapter by injectLazy()
|
||||
private val getManga: GetManga by injectLazy()
|
||||
|
||||
/**
|
||||
* Counter used to keep the queue order.
|
||||
|
@ -78,7 +80,7 @@ class DownloadStore(
|
|||
/**
|
||||
* Returns the list of downloads to restore. It should be called in a background thread.
|
||||
*/
|
||||
fun restore(): List<Download> {
|
||||
suspend fun restore(): List<Download> {
|
||||
val objs = preferences.all
|
||||
.mapNotNull { it.value as? String }
|
||||
.mapNotNull { deserialize(it) }
|
||||
|
@ -89,10 +91,10 @@ class DownloadStore(
|
|||
val cachedManga = mutableMapOf<Long, Manga?>()
|
||||
for ((mangaId, chapterId) in objs) {
|
||||
val manga = cachedManga.getOrPut(mangaId) {
|
||||
db.getManga(mangaId).executeAsBlocking()
|
||||
getManga.awaitById(mangaId)
|
||||
} ?: continue
|
||||
val source = sourceManager.get(manga.source) as? HttpSource ?: continue
|
||||
val chapter = db.getChapter(chapterId).executeAsBlocking() ?: continue
|
||||
val chapter = getChapter.awaitById(chapterId) ?: continue
|
||||
downloads.add(Download(source, manga, chapter))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ import android.content.Intent
|
|||
import android.net.Uri
|
||||
import androidx.core.content.IntentCompat
|
||||
import eu.kanade.tachiyomi.data.backup.restore.BackupRestoreJob
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.data.download.DownloadJob
|
||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
|
@ -28,11 +27,15 @@ import eu.kanade.tachiyomi.util.chapter.updateTrackChapterMarkedAsRead
|
|||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
||||
import eu.kanade.tachiyomi.util.system.getParcelableCompat
|
||||
import eu.kanade.tachiyomi.util.system.launchIO
|
||||
import eu.kanade.tachiyomi.util.system.notificationManager
|
||||
import java.io.File
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.File
|
||||
import yokai.domain.chapter.interactor.GetChapter
|
||||
import yokai.domain.chapter.interactor.UpdateChapter
|
||||
import yokai.domain.manga.interactor.GetManga
|
||||
import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID
|
||||
|
||||
/**
|
||||
|
@ -41,6 +44,10 @@ import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID
|
|||
* NOTE: Use local broadcasts if possible.
|
||||
*/
|
||||
class NotificationReceiver : BroadcastReceiver() {
|
||||
private val getChapter: GetChapter by injectLazy()
|
||||
private val updateChapter: UpdateChapter by injectLazy()
|
||||
private val getManga: GetManga by injectLazy()
|
||||
|
||||
/**
|
||||
* Download manager.
|
||||
*/
|
||||
|
@ -204,23 +211,25 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||
* @param notificationId id of notification
|
||||
*/
|
||||
private fun markAsRead(chapterUrls: Array<String>, mangaId: Long) {
|
||||
val db: DatabaseHelper = Injekt.get()
|
||||
val preferences: PreferencesHelper = Injekt.get()
|
||||
val manga = db.getManga(mangaId).executeAsBlocking() ?: return
|
||||
val chapters = chapterUrls.map {
|
||||
val chapter = db.getChapter(it, mangaId).executeAsBlocking() ?: return
|
||||
chapter.read = true
|
||||
db.updateChapterProgress(chapter).executeAsBlocking()
|
||||
if (preferences.removeAfterMarkedAsRead().get()) {
|
||||
val sourceManager: SourceManager = Injekt.get()
|
||||
val source = sourceManager.get(manga.source) ?: return
|
||||
downloadManager.deleteChapters(listOf(chapter), manga, source)
|
||||
|
||||
launchIO {
|
||||
val manga = getManga.awaitById(mangaId) ?: return@launchIO
|
||||
val chapters = chapterUrls.map {
|
||||
val chapter = getChapter.awaitByUrlAndMangaId(it, mangaId, false) ?: return@launchIO
|
||||
chapter.read = true
|
||||
updateChapter.await(chapter.toProgressUpdate())
|
||||
if (preferences.removeAfterMarkedAsRead().get()) {
|
||||
val sourceManager: SourceManager = Injekt.get()
|
||||
val source = sourceManager.get(manga.source) ?: return@launchIO
|
||||
downloadManager.deleteChapters(listOf(chapter), manga, source)
|
||||
}
|
||||
return@map chapter
|
||||
}
|
||||
return@map chapter
|
||||
val newLastChapter = chapters.maxByOrNull { it.chapter_number.toInt() }
|
||||
LibraryUpdateJob.updateMutableFlow.tryEmit(manga.id)
|
||||
updateTrackChapterMarkedAsRead(Injekt.get(), preferences, newLastChapter, mangaId, 0)
|
||||
}
|
||||
val newLastChapter = chapters.maxByOrNull { it.chapter_number.toInt() }
|
||||
LibraryUpdateJob.updateMutableFlow.tryEmit(manga.id)
|
||||
updateTrackChapterMarkedAsRead(db, preferences, newLastChapter, mangaId, 0)
|
||||
}
|
||||
|
||||
/** Method called when user wants to stop a restore
|
||||
|
|
|
@ -64,6 +64,11 @@ import eu.kanade.tachiyomi.util.system.launchUI
|
|||
import eu.kanade.tachiyomi.util.system.withIOContext
|
||||
import eu.kanade.tachiyomi.util.system.withUIContext
|
||||
import eu.kanade.tachiyomi.widget.TriStateCheckBox
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.OutputStream
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
|
@ -78,16 +83,13 @@ import uy.kohesive.injekt.api.get
|
|||
import uy.kohesive.injekt.injectLazy
|
||||
import yokai.domain.chapter.interactor.GetAvailableScanlators
|
||||
import yokai.domain.chapter.interactor.GetChapter
|
||||
import yokai.domain.chapter.interactor.UpdateChapter
|
||||
import yokai.domain.library.custom.model.CustomMangaInfo
|
||||
import yokai.domain.manga.interactor.UpdateManga
|
||||
import yokai.domain.manga.models.MangaUpdate
|
||||
import yokai.domain.storage.StorageManager
|
||||
import yokai.i18n.MR
|
||||
import yokai.util.lang.getString
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.OutputStream
|
||||
import java.util.*
|
||||
|
||||
class MangaDetailsPresenter(
|
||||
val manga: Manga,
|
||||
|
@ -101,6 +103,7 @@ class MangaDetailsPresenter(
|
|||
) : BaseCoroutinePresenter<MangaDetailsController>(), DownloadQueue.DownloadListener {
|
||||
private val getAvailableScanlators: GetAvailableScanlators by injectLazy()
|
||||
private val getChapter: GetChapter by injectLazy()
|
||||
private val updateChapter: UpdateChapter by injectLazy()
|
||||
private val updateManga: UpdateManga by injectLazy()
|
||||
|
||||
private val customMangaManager: CustomMangaManager by injectLazy()
|
||||
|
@ -508,10 +511,11 @@ class MangaDetailsPresenter(
|
|||
*/
|
||||
fun bookmarkChapters(selectedChapters: List<ChapterItem>, bookmarked: Boolean) {
|
||||
presenterScope.launch(Dispatchers.IO) {
|
||||
selectedChapters.forEach {
|
||||
val updates = selectedChapters.map {
|
||||
it.bookmark = bookmarked
|
||||
it.toProgressUpdate()
|
||||
}
|
||||
db.updateChaptersProgress(selectedChapters).executeAsBlocking()
|
||||
updateChapter.awaitAll(updates)
|
||||
getChapters()
|
||||
withContext(Dispatchers.Main) { view?.updateChapters(chapters) }
|
||||
}
|
||||
|
@ -529,15 +533,16 @@ class MangaDetailsPresenter(
|
|||
lastRead: Int? = null,
|
||||
pagesLeft: Int? = null,
|
||||
) {
|
||||
presenterScope.launch(Dispatchers.IO) {
|
||||
selectedChapters.forEach {
|
||||
presenterScope.launchIO {
|
||||
val updates = selectedChapters.map {
|
||||
it.read = read
|
||||
if (!read) {
|
||||
it.last_page_read = lastRead ?: 0
|
||||
it.pages_left = pagesLeft ?: 0
|
||||
}
|
||||
it.toProgressUpdate()
|
||||
}
|
||||
db.updateChaptersProgress(selectedChapters).executeAsBlocking()
|
||||
updateChapter.awaitAll(updates)
|
||||
if (read && deleteNow && preferences.removeAfterMarkedAsRead().get()) {
|
||||
deleteChapters(selectedChapters, false)
|
||||
}
|
||||
|
|
|
@ -78,6 +78,8 @@ import uy.kohesive.injekt.api.get
|
|||
import uy.kohesive.injekt.injectLazy
|
||||
import yokai.domain.chapter.interactor.GetChapter
|
||||
import yokai.domain.chapter.interactor.InsertChapter
|
||||
import yokai.domain.chapter.interactor.UpdateChapter
|
||||
import yokai.domain.chapter.models.ChapterUpdate
|
||||
import yokai.domain.download.DownloadPreferences
|
||||
import yokai.domain.manga.interactor.GetManga
|
||||
import yokai.domain.manga.interactor.InsertManga
|
||||
|
@ -103,6 +105,7 @@ class ReaderViewModel(
|
|||
) : ViewModel() {
|
||||
private val getChapter: GetChapter by injectLazy()
|
||||
private val insertChapter: InsertChapter by injectLazy()
|
||||
private val updateChapter: UpdateChapter by injectLazy()
|
||||
private val getManga: GetManga by injectLazy()
|
||||
private val insertManga: InsertManga by injectLazy()
|
||||
private val updateManga: UpdateManga by injectLazy()
|
||||
|
@ -444,7 +447,16 @@ class ReaderViewModel(
|
|||
|
||||
fun toggleBookmark(chapter: Chapter) {
|
||||
chapter.bookmark = !chapter.bookmark
|
||||
db.updateChapterProgress(chapter).executeAsBlocking()
|
||||
viewModelScope.launchNonCancellableIO {
|
||||
updateChapter.await(
|
||||
ChapterUpdate(
|
||||
id = chapter.id!!,
|
||||
bookmark = chapter.bookmark,
|
||||
lastPageRead = chapter.last_page_read.toLong(),
|
||||
pagesLeft = chapter.pages_left.toLong(),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -617,6 +629,7 @@ class ReaderViewModel(
|
|||
* Saves this [readerChapter]'s progress (last read page and whether it's read).
|
||||
* If incognito mode isn't on or has at least 1 tracker
|
||||
*/
|
||||
// FIXME: Migrate to SQLDelight, on halt: in StorIO transaction
|
||||
private fun saveChapterProgress(readerChapter: ReaderChapter) {
|
||||
readerChapter.requestedPage = readerChapter.chapter.last_page_read
|
||||
db.getChapter(readerChapter.chapter.id!!).executeAsBlocking()?.let { dbChapter ->
|
||||
|
@ -630,6 +643,7 @@ class ReaderViewModel(
|
|||
/**
|
||||
* Saves this [readerChapter] last read history.
|
||||
*/
|
||||
// FIXME: Migrate to SQLDelight, on halt: in StorIO transaction
|
||||
private fun saveChapterHistory(readerChapter: ReaderChapter) {
|
||||
if (!preferences.incognitoMode().get()) {
|
||||
val readAt = Date().time
|
||||
|
|
|
@ -42,6 +42,7 @@ import uy.kohesive.injekt.api.get
|
|||
import uy.kohesive.injekt.injectLazy
|
||||
import yokai.domain.chapter.interactor.GetChapter
|
||||
import yokai.domain.chapter.interactor.RecentChapter
|
||||
import yokai.domain.chapter.interactor.UpdateChapter
|
||||
import yokai.domain.recents.RecentsPreferences
|
||||
import yokai.domain.ui.UiPreferences
|
||||
import yokai.i18n.MR
|
||||
|
@ -56,6 +57,7 @@ class RecentsPresenter(
|
|||
) : BaseCoroutinePresenter<RecentsController>(), DownloadQueue.DownloadListener {
|
||||
private val getChapter: GetChapter by injectLazy()
|
||||
private val recentChapter: RecentChapter by injectLazy()
|
||||
private val updateChapter: UpdateChapter by injectLazy()
|
||||
|
||||
private var recentsJob: Job? = null
|
||||
var recentItems = listOf<RecentMangaItem>()
|
||||
|
@ -639,7 +641,7 @@ class RecentsPresenter(
|
|||
pages_left = pagesLeft ?: 0
|
||||
}
|
||||
}
|
||||
db.updateChaptersProgress(listOf(chapter)).executeAsBlocking()
|
||||
updateChapter.await(chapter.toProgressUpdate())
|
||||
getRecents()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import kotlinx.coroutines.Job
|
|||
import kotlinx.coroutines.delay
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import yokai.domain.chapter.interactor.UpdateChapter
|
||||
|
||||
/**
|
||||
* Helper method for syncing a remote track with the local chapters, and back
|
||||
|
@ -25,20 +26,26 @@ import uy.kohesive.injekt.api.get
|
|||
* @param remoteTrack the remote Track object.
|
||||
* @param service the tracker service.
|
||||
*/
|
||||
fun syncChaptersWithTrackServiceTwoWay(db: DatabaseHelper, chapters: List<Chapter>, remoteTrack: Track, service: TrackService) {
|
||||
val sortedChapters = chapters.sortedBy { it.chapter_number }
|
||||
sortedChapters
|
||||
.filter { chapter -> chapter.chapter_number <= remoteTrack.last_chapter_read && !chapter.read }
|
||||
.forEach { it.read = true }
|
||||
db.updateChaptersProgress(sortedChapters).executeAsBlocking()
|
||||
|
||||
// only take into account continuous reading
|
||||
val localLastRead = sortedChapters.takeWhile { it.read }.lastOrNull()?.chapter_number ?: 0F
|
||||
|
||||
// update remote
|
||||
remoteTrack.last_chapter_read = localLastRead
|
||||
|
||||
fun syncChaptersWithTrackServiceTwoWay(
|
||||
db: DatabaseHelper,
|
||||
chapters: List<Chapter>,
|
||||
remoteTrack: Track,
|
||||
service: TrackService,
|
||||
updateChapter: UpdateChapter = Injekt.get(),
|
||||
) {
|
||||
launchIO {
|
||||
val sortedChapters = chapters.sortedBy { it.chapter_number }
|
||||
sortedChapters
|
||||
.filter { chapter -> chapter.chapter_number <= remoteTrack.last_chapter_read && !chapter.read }
|
||||
.forEach { it.read = true }
|
||||
updateChapter.awaitAll(sortedChapters.map(Chapter::toProgressUpdate))
|
||||
|
||||
// only take into account continuous reading
|
||||
val localLastRead = sortedChapters.takeWhile { it.read }.lastOrNull()?.chapter_number ?: 0F
|
||||
|
||||
// update remote
|
||||
remoteTrack.last_chapter_read = localLastRead
|
||||
|
||||
try {
|
||||
service.update(remoteTrack)
|
||||
db.insertTrack(remoteTrack).executeAsBlocking()
|
||||
|
|
|
@ -16,9 +16,33 @@ class ChapterRepositoryImpl(private val handler: DatabaseHandler) : ChapterRepos
|
|||
override fun getChaptersAsFlow(mangaId: Long, filterScanlators: Boolean): Flow<List<Chapter>> =
|
||||
handler.subscribeToList { chaptersQueries.getChaptersByMangaId(mangaId, filterScanlators.toInt().toLong(), Chapter::mapper) }
|
||||
|
||||
override suspend fun getChapterById(id: Long): Chapter? =
|
||||
handler.awaitOneOrNull { chaptersQueries.getChaptersById(id, Chapter::mapper) }
|
||||
|
||||
override suspend fun getChaptersByUrl(url: String, filterScanlators: Boolean): List<Chapter> =
|
||||
handler.awaitList { chaptersQueries.getChaptersByUrl(url, filterScanlators.toInt().toLong(), Chapter::mapper) }
|
||||
|
||||
override suspend fun getChapterByUrl(url: String, filterScanlators: Boolean): Chapter? =
|
||||
handler.awaitOneOrNull { chaptersQueries.getChaptersByUrl(url, filterScanlators.toInt().toLong(), Chapter::mapper) }
|
||||
|
||||
override suspend fun getChaptersByUrlAndMangaId(
|
||||
url: String,
|
||||
mangaId: Long,
|
||||
filterScanlators: Boolean
|
||||
): List<Chapter> =
|
||||
handler.awaitList {
|
||||
chaptersQueries.getChaptersByUrlAndMangaId(url, mangaId, filterScanlators.toInt().toLong(), Chapter::mapper)
|
||||
}
|
||||
|
||||
override suspend fun getChapterByUrlAndMangaId(
|
||||
url: String,
|
||||
mangaId: Long,
|
||||
filterScanlators: Boolean
|
||||
): Chapter? =
|
||||
handler.awaitOneOrNull {
|
||||
chaptersQueries.getChaptersByUrlAndMangaId(url, mangaId, filterScanlators.toInt().toLong(), Chapter::mapper)
|
||||
}
|
||||
|
||||
override suspend fun getRecents(filterScanlators: Boolean, search: String, limit: Long, offset: Long): List<MangaChapter> =
|
||||
handler.awaitList { chaptersQueries.getRecents(search, filterScanlators.toInt().toLong(), limit, offset, MangaChapter::mapper) }
|
||||
|
||||
|
|
|
@ -9,7 +9,13 @@ interface ChapterRepository {
|
|||
suspend fun getChapters(mangaId: Long, filterScanlators: Boolean): List<Chapter>
|
||||
fun getChaptersAsFlow(mangaId: Long, filterScanlators: Boolean): Flow<List<Chapter>>
|
||||
|
||||
suspend fun getChapterById(id: Long): Chapter?
|
||||
|
||||
suspend fun getChaptersByUrl(url: String, filterScanlators: Boolean): List<Chapter>
|
||||
suspend fun getChapterByUrl(url: String, filterScanlators: Boolean): Chapter?
|
||||
|
||||
suspend fun getChaptersByUrlAndMangaId(url: String, mangaId: Long, filterScanlators: Boolean): List<Chapter>
|
||||
suspend fun getChapterByUrlAndMangaId(url: String, mangaId: Long, filterScanlators: Boolean): Chapter?
|
||||
|
||||
suspend fun getRecents(filterScanlators: Boolean, search: String = "", limit: Long = 25L, offset: Long = 0L): List<MangaChapter>
|
||||
|
||||
|
|
|
@ -11,8 +11,17 @@ class GetChapter(
|
|||
suspend fun awaitAll(manga: Manga, filterScanlators: Boolean? = null) =
|
||||
awaitAll(manga.id!!, filterScanlators ?: (manga.filtered_scanlators?.isNotEmpty() == true))
|
||||
|
||||
suspend fun awaitById(id: Long) = chapterRepository.getChapterById(id)
|
||||
|
||||
suspend fun awaitAllByUrl(chapterUrl: String, filterScanlators: Boolean) =
|
||||
chapterRepository.getChaptersByUrl(chapterUrl, filterScanlators)
|
||||
suspend fun awaitByUrl(chapterUrl: String, filterScanlators: Boolean) =
|
||||
chapterRepository.getChapterByUrl(chapterUrl, filterScanlators)
|
||||
|
||||
suspend fun awaitAllByUrlAndMangaId(chapterUrl: String, mangaId: Long, filterScanlators: Boolean) =
|
||||
chapterRepository.getChaptersByUrlAndMangaId(chapterUrl, mangaId, filterScanlators)
|
||||
suspend fun awaitByUrlAndMangaId(chapterUrl: String, mangaId: Long, filterScanlators: Boolean) =
|
||||
chapterRepository.getChapterByUrlAndMangaId(chapterUrl, mangaId, filterScanlators)
|
||||
|
||||
fun subscribeAll(mangaId: Long, filterScanlators: Boolean) = chapterRepository.getChaptersAsFlow(mangaId, filterScanlators)
|
||||
}
|
||||
|
|
|
@ -32,6 +32,10 @@ AND (
|
|||
:apply_filter = 0 OR S.name IS NULL
|
||||
);
|
||||
|
||||
getChaptersById:
|
||||
SELECT * FROM chapters
|
||||
WHERE _id = :id;
|
||||
|
||||
getChaptersByUrl:
|
||||
SELECT C.*
|
||||
FROM chapters AS C
|
||||
|
@ -43,6 +47,17 @@ AND (
|
|||
:apply_filter = 0 OR S.name IS NULL
|
||||
);
|
||||
|
||||
getChaptersByUrlAndMangaId:
|
||||
SELECT C.*
|
||||
FROM chapters AS C
|
||||
LEFT JOIN scanlators_view AS S
|
||||
ON C.manga_id = S.manga_id
|
||||
AND ifnull(C.scanlator, 'N/A') = ifnull(S.name, '/<INVALID>/') -- I assume if it's N/A it shouldn't be filtered
|
||||
WHERE C.url = :url AND C.manga_id = :manga_id
|
||||
AND (
|
||||
:apply_filter = 0 OR S.name IS NULL
|
||||
);
|
||||
|
||||
getRecents:
|
||||
SELECT
|
||||
M.*,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue