mirror of
https://github.com/mihonapp/mihon.git
synced 2025-11-13 12:38:58 +01:00
Use sqldelight in migration (#7331)
* Use sqldelight in migration * Some more changes Co-Authored-By: Ivan Iskandar <12537387+ivaniskandar@users.noreply.github.com> * Review Changes * Review changes 2 * Review Changes 3 * Review Changes 4 Co-authored-by: Ivan Iskandar <12537387+ivaniskandar@users.noreply.github.com>
This commit is contained in:
@@ -2,9 +2,21 @@ package eu.kanade.tachiyomi.ui.browse.migration.search
|
||||
|
||||
import android.os.Bundle
|
||||
import com.jakewharton.rxrelay.BehaviorRelay
|
||||
import eu.kanade.domain.category.interactor.GetCategories
|
||||
import eu.kanade.domain.category.interactor.MoveMangaToCategories
|
||||
import eu.kanade.domain.chapter.interactor.GetChapterByMangaId
|
||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
|
||||
import eu.kanade.domain.chapter.interactor.UpdateChapter
|
||||
import eu.kanade.domain.chapter.model.toChapterUpdate
|
||||
import eu.kanade.domain.manga.interactor.UpdateManga
|
||||
import eu.kanade.domain.manga.model.MangaUpdate
|
||||
import eu.kanade.domain.manga.model.hasCustomCover
|
||||
import eu.kanade.domain.manga.model.toDbManga
|
||||
import eu.kanade.domain.track.interactor.GetTracks
|
||||
import eu.kanade.domain.track.interactor.InsertTrack
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.models.MangaCategory
|
||||
import eu.kanade.tachiyomi.data.database.models.toDomainManga
|
||||
import eu.kanade.tachiyomi.data.database.models.toMangaInfo
|
||||
import eu.kanade.tachiyomi.data.track.EnhancedTrackService
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
@@ -17,8 +29,6 @@ import eu.kanade.tachiyomi.ui.browse.migration.MigrationFlags
|
||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchCardItem
|
||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchItem
|
||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchPresenter
|
||||
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
||||
import eu.kanade.tachiyomi.util.hasCustomCover
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import eu.kanade.tachiyomi.util.lang.launchUI
|
||||
import eu.kanade.tachiyomi.util.lang.withUIContext
|
||||
@@ -31,6 +41,14 @@ import java.util.Date
|
||||
class SearchPresenter(
|
||||
initialQuery: String? = "",
|
||||
private val manga: Manga,
|
||||
private val syncChaptersWithSource: SyncChaptersWithSource = Injekt.get(),
|
||||
private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(),
|
||||
private val updateChapter: UpdateChapter = Injekt.get(),
|
||||
private val updateManga: UpdateManga = Injekt.get(),
|
||||
private val getCategories: GetCategories = Injekt.get(),
|
||||
private val getTracks: GetTracks = Injekt.get(),
|
||||
private val insertTrack: InsertTrack = Injekt.get(),
|
||||
private val moveMangaToCategories: MoveMangaToCategories = Injekt.get(),
|
||||
) : GlobalSearchPresenter(initialQuery) {
|
||||
|
||||
private val replacingMangaRelay = BehaviorRelay.create<Pair<Boolean, Manga?>>()
|
||||
@@ -94,101 +112,93 @@ class SearchPresenter(
|
||||
replace: Boolean,
|
||||
) {
|
||||
val flags = preferences.migrateFlags().get()
|
||||
val migrateChapters =
|
||||
MigrationFlags.hasChapters(
|
||||
flags,
|
||||
)
|
||||
val migrateCategories =
|
||||
MigrationFlags.hasCategories(
|
||||
flags,
|
||||
)
|
||||
val migrateTracks =
|
||||
MigrationFlags.hasTracks(
|
||||
flags,
|
||||
)
|
||||
val migrateCustomCover =
|
||||
MigrationFlags.hasCustomCover(
|
||||
flags,
|
||||
)
|
||||
|
||||
val migrateChapters = MigrationFlags.hasChapters(flags)
|
||||
val migrateCategories = MigrationFlags.hasCategories(flags)
|
||||
val migrateTracks = MigrationFlags.hasTracks(flags)
|
||||
val migrateCustomCover = MigrationFlags.hasCustomCover(flags)
|
||||
|
||||
val prevDomainManga = prevManga.toDomainManga() ?: return
|
||||
val domainManga = manga.toDomainManga() ?: return
|
||||
|
||||
try {
|
||||
syncChaptersWithSource(sourceChapters, manga, source)
|
||||
syncChaptersWithSource.await(sourceChapters, domainManga, source)
|
||||
} catch (e: Exception) {
|
||||
// Worst case, chapters won't be synced
|
||||
}
|
||||
|
||||
db.inTransaction {
|
||||
// Update chapters read
|
||||
if (migrateChapters) {
|
||||
val prevMangaChapters = db.getChapters(prevManga).executeAsBlocking()
|
||||
val maxChapterRead = prevMangaChapters
|
||||
.filter { it.read }
|
||||
.maxOfOrNull { it.chapter_number } ?: 0f
|
||||
val dbChapters = db.getChapters(manga).executeAsBlocking()
|
||||
for (chapter in dbChapters) {
|
||||
if (chapter.isRecognizedNumber) {
|
||||
val prevChapter = prevMangaChapters
|
||||
.find { it.isRecognizedNumber && it.chapter_number == chapter.chapter_number }
|
||||
if (prevChapter != null) {
|
||||
chapter.date_fetch = prevChapter.date_fetch
|
||||
chapter.bookmark = prevChapter.bookmark
|
||||
}
|
||||
if (chapter.chapter_number <= maxChapterRead) {
|
||||
chapter.read = true
|
||||
}
|
||||
// Update chapters read, bookmark and dateFetch
|
||||
if (migrateChapters) {
|
||||
val prevMangaChapters = getChapterByMangaId.await(prevDomainManga.id)
|
||||
val mangaChapters = getChapterByMangaId.await(domainManga.id)
|
||||
|
||||
val maxChapterRead = prevMangaChapters
|
||||
.filter { it.read }
|
||||
.maxOfOrNull { it.chapterNumber }
|
||||
|
||||
val updatedMangaChapters = mangaChapters.map { mangaChapter ->
|
||||
var updatedChapter = mangaChapter
|
||||
if (updatedChapter.isRecognizedNumber) {
|
||||
val prevChapter = prevMangaChapters
|
||||
.find { it.isRecognizedNumber && it.chapterNumber == updatedChapter.chapterNumber }
|
||||
|
||||
if (prevChapter != null) {
|
||||
updatedChapter = updatedChapter.copy(
|
||||
dateFetch = prevChapter.dateFetch,
|
||||
bookmark = prevChapter.bookmark,
|
||||
)
|
||||
}
|
||||
|
||||
if (maxChapterRead != null && updatedChapter.chapterNumber <= maxChapterRead) {
|
||||
updatedChapter = updatedChapter.copy(read = true)
|
||||
}
|
||||
}
|
||||
db.insertChapters(dbChapters).executeAsBlocking()
|
||||
|
||||
updatedChapter
|
||||
}
|
||||
|
||||
// Update categories
|
||||
if (migrateCategories) {
|
||||
val categories = db.getCategoriesForManga(prevManga).executeAsBlocking()
|
||||
val mangaCategories = categories.map { MangaCategory.create(manga, it) }
|
||||
db.setMangaCategories(mangaCategories, listOf(manga))
|
||||
}
|
||||
|
||||
// Update track
|
||||
if (migrateTracks) {
|
||||
val tracksToUpdate = db.getTracks(prevManga.id).executeAsBlocking().mapNotNull { track ->
|
||||
track.id = null
|
||||
track.manga_id = manga.id!!
|
||||
|
||||
val service = enhancedServices
|
||||
.firstOrNull { it.isTrackFrom(track, prevManga, prevSource) }
|
||||
if (service != null) service.migrateTrack(track, manga, source)
|
||||
else track
|
||||
}
|
||||
db.insertTracks(tracksToUpdate).executeAsBlocking()
|
||||
}
|
||||
|
||||
// Update favorite status
|
||||
if (replace) {
|
||||
prevManga.favorite = false
|
||||
db.updateMangaFavorite(prevManga).executeAsBlocking()
|
||||
}
|
||||
manga.favorite = true
|
||||
|
||||
// Update reading preferences
|
||||
manga.chapter_flags = prevManga.chapter_flags
|
||||
manga.viewer_flags = prevManga.viewer_flags
|
||||
|
||||
// Update date added
|
||||
if (replace) {
|
||||
manga.date_added = prevManga.date_added
|
||||
prevManga.date_added = 0
|
||||
} else {
|
||||
manga.date_added = Date().time
|
||||
}
|
||||
|
||||
// Update custom cover
|
||||
if (migrateCustomCover) {
|
||||
coverCache.setCustomCoverToCache(manga, coverCache.getCustomCoverFile(prevManga.id).inputStream())
|
||||
}
|
||||
|
||||
// SearchPresenter#networkToLocalManga may have updated the manga title,
|
||||
// so ensure db gets updated title too
|
||||
db.insertManga(manga).executeAsBlocking()
|
||||
val chapterUpdates = updatedMangaChapters.map { it.toChapterUpdate() }
|
||||
updateChapter.awaitAll(chapterUpdates)
|
||||
}
|
||||
|
||||
// Update categories
|
||||
if (migrateCategories) {
|
||||
val categoryIds = getCategories.await(prevDomainManga.id).map { it.id }
|
||||
moveMangaToCategories.await(domainManga.id, categoryIds)
|
||||
}
|
||||
|
||||
// Update track
|
||||
if (migrateTracks) {
|
||||
val tracks = getTracks.await(prevDomainManga.id).mapNotNull { track ->
|
||||
val updatedTrack = track.copy(mangaId = domainManga.id)
|
||||
|
||||
val service = enhancedServices
|
||||
.firstOrNull { it.isTrackFrom(updatedTrack, prevDomainManga, prevSource) }
|
||||
|
||||
if (service != null) service.migrateTrack(updatedTrack, domainManga, source)
|
||||
else track
|
||||
}
|
||||
insertTrack.awaitAll(tracks)
|
||||
}
|
||||
|
||||
if (replace) {
|
||||
updateManga.await(MangaUpdate(prevDomainManga.id, favorite = false, dateAdded = 0))
|
||||
}
|
||||
|
||||
// Update custom cover (recheck if custom cover exists)
|
||||
if (migrateCustomCover && prevDomainManga.hasCustomCover()) {
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
coverCache.setCustomCoverToCache(domainManga.toDbManga(), coverCache.getCustomCoverFile(prevDomainManga.id).inputStream())
|
||||
}
|
||||
|
||||
updateManga.await(
|
||||
MangaUpdate(
|
||||
id = domainManga.id,
|
||||
favorite = true,
|
||||
chapterFlags = prevDomainManga.chapterFlags,
|
||||
viewerFlags = prevDomainManga.viewerFlags,
|
||||
dateAdded = if (replace) prevDomainManga.dateAdded else Date().time,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,12 @@ package eu.kanade.tachiyomi.ui.manga
|
||||
import android.os.Bundle
|
||||
import com.jakewharton.rxrelay.PublishRelay
|
||||
import eu.kanade.domain.category.interactor.GetCategories
|
||||
import eu.kanade.domain.chapter.interactor.GetChapterByMangaId
|
||||
import eu.kanade.domain.chapter.model.toDbChapter
|
||||
import eu.kanade.domain.manga.interactor.GetDuplicateLibraryManga
|
||||
import eu.kanade.domain.manga.interactor.GetMangaWithChapters
|
||||
import eu.kanade.domain.manga.interactor.UpdateManga
|
||||
import eu.kanade.domain.manga.model.toDbManga
|
||||
import eu.kanade.domain.manga.model.toMangaInfo
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.models.Category
|
||||
@@ -14,6 +16,7 @@ import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.models.MangaCategory
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.database.models.toDomainManga
|
||||
import eu.kanade.tachiyomi.data.database.models.toMangaInfo
|
||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
import eu.kanade.tachiyomi.data.download.model.Download
|
||||
@@ -23,7 +26,6 @@ import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.data.track.TrackService
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.model.toSChapter
|
||||
import eu.kanade.tachiyomi.source.model.toSManga
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem
|
||||
import eu.kanade.tachiyomi.ui.manga.track.TrackItem
|
||||
@@ -34,7 +36,6 @@ import eu.kanade.tachiyomi.util.chapter.syncChaptersWithTrackServiceTwoWay
|
||||
import eu.kanade.tachiyomi.util.isLocal
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import eu.kanade.tachiyomi.util.lang.withUIContext
|
||||
import eu.kanade.tachiyomi.util.prepUpdateCover
|
||||
import eu.kanade.tachiyomi.util.removeCovers
|
||||
import eu.kanade.tachiyomi.util.shouldDownloadNewChapters
|
||||
import eu.kanade.tachiyomi.util.system.logcat
|
||||
@@ -64,9 +65,10 @@ class MangaPresenter(
|
||||
private val trackManager: TrackManager = Injekt.get(),
|
||||
private val downloadManager: DownloadManager = Injekt.get(),
|
||||
private val coverCache: CoverCache = Injekt.get(),
|
||||
private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(),
|
||||
private val getMangaWithChapters: GetMangaWithChapters = Injekt.get(),
|
||||
private val getDuplicateLibraryManga: GetDuplicateLibraryManga = Injekt.get(),
|
||||
private val getCategories: GetCategories = Injekt.get(),
|
||||
private val updateManga: UpdateManga = Injekt.get(),
|
||||
) : BasePresenter<MangaController>() {
|
||||
|
||||
/**
|
||||
@@ -118,7 +120,6 @@ class MangaPresenter(
|
||||
}
|
||||
|
||||
// Manga info - start
|
||||
|
||||
getMangaObservable()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeLatestCache({ view, manga -> view.onNextMangaInfo(manga, source) })
|
||||
@@ -147,9 +148,9 @@ class MangaPresenter(
|
||||
// Keeps subscribed to changes and sends the list of chapters to the relay.
|
||||
presenterScope.launchIO {
|
||||
manga.id?.let { mangaId ->
|
||||
getChapterByMangaId.subscribe(mangaId)
|
||||
.collectLatest { domainChapters ->
|
||||
val chapterItems = domainChapters.map { it.toDbChapter().toModel() }
|
||||
getMangaWithChapters.subscribe(mangaId)
|
||||
.collectLatest { (_, chapters) ->
|
||||
val chapterItems = chapters.map { it.toDbChapter().toModel() }
|
||||
setDownloadedChapters(chapterItems)
|
||||
this@MangaPresenter.allChapters = chapterItems
|
||||
observeDownloads()
|
||||
@@ -168,7 +169,6 @@ class MangaPresenter(
|
||||
}
|
||||
|
||||
// Manga info - start
|
||||
|
||||
private fun getMangaObservable(): Observable<Manga> {
|
||||
return db.getManga(manga.url, manga.source).asRxObservable()
|
||||
}
|
||||
@@ -193,16 +193,11 @@ class MangaPresenter(
|
||||
if (fetchMangaJob?.isActive == true) return
|
||||
fetchMangaJob = presenterScope.launchIO {
|
||||
try {
|
||||
val networkManga = source.getMangaDetails(manga.toMangaInfo())
|
||||
val sManga = networkManga.toSManga()
|
||||
manga.prepUpdateCover(coverCache, sManga, manualFetch)
|
||||
manga.copyFrom(sManga)
|
||||
if (!manga.favorite) {
|
||||
// if the manga isn't a favorite, set its title from source and update in db
|
||||
manga.title = sManga.title
|
||||
manga.toDomainManga()?.let { domainManga ->
|
||||
val networkManga = source.getMangaDetails(domainManga.toMangaInfo())
|
||||
|
||||
updateManga.awaitUpdateFromSource(domainManga, networkManga, manualFetch, coverCache)
|
||||
}
|
||||
manga.initialized = true
|
||||
db.insertManga(manga).executeAsBlocking()
|
||||
|
||||
withUIContext { view?.onFetchMangaInfoDone() }
|
||||
} catch (e: Throwable) {
|
||||
|
||||
Reference in New Issue
Block a user