From dfdb688b437c38954b1072b7a1df15921a437868 Mon Sep 17 00:00:00 2001 From: Andreas Date: Sun, 19 Mar 2023 18:11:58 +0100 Subject: [PATCH] Migrate things to use newer data models (#9239) * Remove old database models from Coil * Remove old database models from TrackInfoDialogHome * Remove old database models from Backup Manager --- .../eu/kanade/domain/chapter/model/Chapter.kt | 11 ++ .../presentation/track/TrackInfoDialogHome.kt | 17 +- app/src/main/java/eu/kanade/tachiyomi/App.kt | 5 +- .../tachiyomi/data/backup/BackupManager.kt | 171 +++++++++--------- .../tachiyomi/data/backup/BackupRestorer.kt | 10 +- .../data/backup/models/BackupChapter.kt | 28 +-- .../data/backup/models/BackupManga.kt | 43 +++-- .../data/backup/models/BackupTracking.kt | 35 ++-- .../tachiyomi/data/coil/MangaCoverFetcher.kt | 30 +-- .../tachiyomi/data/coil/MangaCoverKeyer.kt | 20 +- .../tachiyomi/data/database/models/Manga.kt | 62 ------- .../data/database/models/MangaImpl.kt | 55 ------ .../source/model/SMangaExtensions.kt | 31 ++++ .../tachiyomi/ui/manga/MangaScreenModel.kt | 4 +- .../ui/manga/track/TrackInfoDialog.kt | 55 +++--- .../tachiyomi/ui/manga/track/TrackItem.kt | 2 +- 16 files changed, 231 insertions(+), 348 deletions(-) delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/data/database/models/Manga.kt delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaImpl.kt diff --git a/app/src/main/java/eu/kanade/domain/chapter/model/Chapter.kt b/app/src/main/java/eu/kanade/domain/chapter/model/Chapter.kt index 3492443ddd..b3c7edb714 100644 --- a/app/src/main/java/eu/kanade/domain/chapter/model/Chapter.kt +++ b/app/src/main/java/eu/kanade/domain/chapter/model/Chapter.kt @@ -2,6 +2,7 @@ package eu.kanade.domain.chapter.model import eu.kanade.tachiyomi.data.database.models.ChapterImpl import eu.kanade.tachiyomi.source.model.SChapter +import tachiyomi.data.Chapters import tachiyomi.domain.chapter.model.Chapter import eu.kanade.tachiyomi.data.database.models.Chapter as DbChapter @@ -26,6 +27,16 @@ fun Chapter.copyFromSChapter(sChapter: SChapter): Chapter { ) } +fun Chapter.copyFrom(other: Chapters): Chapter { + return copy( + name = other.name, + url = other.url, + dateUpload = other.date_upload, + chapterNumber = other.chapter_number, + scanlator = other.scanlator?.ifBlank { null }, + ) +} + fun Chapter.toDbChapter(): DbChapter = ChapterImpl().also { it.id = id it.manga_id = mangaId diff --git a/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHome.kt b/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHome.kt index c64d1ef122..39268ffbb2 100644 --- a/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHome.kt +++ b/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHome.kt @@ -43,6 +43,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp +import eu.kanade.domain.track.model.toDbTrack import eu.kanade.presentation.components.DropdownMenu import eu.kanade.presentation.track.components.TrackLogoIcon import eu.kanade.tachiyomi.R @@ -84,10 +85,10 @@ fun TrackInfoDialogHome( TrackInfoItem( title = item.track.title, service = item.service, - status = item.service.getStatus(item.track.status), + status = item.service.getStatus(item.track.status.toInt()), onStatusClick = { onStatusClick(item) }, - chapters = "${item.track.last_chapter_read.toInt()}".let { - val totalChapters = item.track.total_chapters + chapters = "${item.track.lastChapterRead.toInt()}".let { + val totalChapters = item.track.totalChapters if (totalChapters > 0) { // Add known total chapter count "$it / $totalChapters" @@ -96,16 +97,16 @@ fun TrackInfoDialogHome( } }, onChaptersClick = { onChapterClick(item) }, - score = item.service.displayScore(item.track) + score = item.service.displayScore(item.track.toDbTrack()) .takeIf { supportsScoring && item.track.score != 0F }, onScoreClick = { onScoreClick(item) } .takeIf { supportsScoring }, - startDate = remember(item.track.started_reading_date) { dateFormat.format(item.track.started_reading_date) } - .takeIf { supportsReadingDates && item.track.started_reading_date != 0L }, + startDate = remember(item.track.startDate) { dateFormat.format(item.track.startDate) } + .takeIf { supportsReadingDates && item.track.startDate != 0L }, onStartDateClick = { onStartDateEdit(item) } // TODO .takeIf { supportsReadingDates }, - endDate = dateFormat.format(item.track.finished_reading_date) - .takeIf { supportsReadingDates && item.track.finished_reading_date != 0L }, + endDate = dateFormat.format(item.track.finishDate) + .takeIf { supportsReadingDates && item.track.finishDate != 0L }, onEndDateClick = { onEndDateEdit(item) } .takeIf { supportsReadingDates }, onNewSearch = { onNewSearch(item) }, diff --git a/app/src/main/java/eu/kanade/tachiyomi/App.kt b/app/src/main/java/eu/kanade/tachiyomi/App.kt index 2ea40a2abe..590a97816b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/App.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/App.kt @@ -28,7 +28,6 @@ import eu.kanade.domain.ui.UiPreferences import eu.kanade.domain.ui.model.setAppCompatDelegateThemeMode import eu.kanade.tachiyomi.crash.CrashActivity import eu.kanade.tachiyomi.crash.GlobalExceptionHandler -import eu.kanade.tachiyomi.data.coil.DomainMangaKeyer import eu.kanade.tachiyomi.data.coil.MangaCoverFetcher import eu.kanade.tachiyomi.data.coil.MangaCoverKeyer import eu.kanade.tachiyomi.data.coil.MangaKeyer @@ -143,11 +142,9 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory { add(GifDecoder.Factory()) } add(TachiyomiImageDecoder.Factory()) - add(MangaCoverFetcher.Factory(lazy(callFactoryInit), lazy(diskCacheInit))) - add(MangaCoverFetcher.DomainMangaFactory(lazy(callFactoryInit), lazy(diskCacheInit))) + add(MangaCoverFetcher.MangaFactory(lazy(callFactoryInit), lazy(diskCacheInit))) add(MangaCoverFetcher.MangaCoverFactory(lazy(callFactoryInit), lazy(diskCacheInit))) add(MangaKeyer()) - add(DomainMangaKeyer()) add(MangaCoverKeyer()) } callFactory(callFactoryInit) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt index 0422c7b2a5..7631de36a7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt @@ -4,6 +4,8 @@ import android.Manifest import android.content.Context import android.net.Uri import com.hippo.unifile.UniFile +import eu.kanade.domain.chapter.model.copyFrom +import eu.kanade.domain.manga.model.copyFrom import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CATEGORY import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CATEGORY_MASK @@ -22,9 +24,6 @@ import eu.kanade.tachiyomi.data.backup.models.BackupSource import eu.kanade.tachiyomi.data.backup.models.backupCategoryMapper import eu.kanade.tachiyomi.data.backup.models.backupChapterMapper import eu.kanade.tachiyomi.data.backup.models.backupTrackMapper -import eu.kanade.tachiyomi.data.database.models.Chapter -import eu.kanade.tachiyomi.data.database.models.Manga -import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.source.model.copyFrom import eu.kanade.tachiyomi.util.system.hasPermission import kotlinx.serialization.protobuf.ProtoBuf @@ -44,13 +43,13 @@ import tachiyomi.domain.category.model.Category import tachiyomi.domain.history.model.HistoryUpdate import tachiyomi.domain.library.service.LibraryPreferences import tachiyomi.domain.manga.interactor.GetFavorites +import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.source.service.SourceManager import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import java.io.FileOutputStream import java.util.Date import kotlin.math.max -import tachiyomi.domain.manga.model.Manga as DomainManga class BackupManager( private val context: Context, @@ -136,12 +135,12 @@ class BackupManager( } } - private fun backupExtensionInfo(mangas: List): List { + private fun backupExtensionInfo(mangas: List): List { return mangas .asSequence() - .map { it.source } + .map(Manga::source) .distinct() - .map { sourceManager.getOrStub(it) } + .map(sourceManager::getOrStub) .map { BackupSource.copyFrom(it) } .toList() } @@ -162,7 +161,7 @@ class BackupManager( } } - private suspend fun backupMangas(mangas: List, flags: Int): List { + private suspend fun backupMangas(mangas: List, flags: Int): List { return mangas.map { backupManga(it, flags) } @@ -175,7 +174,7 @@ class BackupManager( * @param options options for the backup * @return [BackupManga] containing manga in a serializable form */ - private suspend fun backupManga(manga: DomainManga, options: Int): BackupManga { + private suspend fun backupManga(manga: Manga, options: Int): BackupManga { // Entry for this manga val mangaObject = BackupManga.copyFrom(manga) @@ -222,10 +221,11 @@ class BackupManager( return mangaObject } - internal suspend fun restoreExistingManga(manga: Manga, dbManga: Mangas) { - manga.id = dbManga._id - manga.copyFrom(dbManga) + internal suspend fun restoreExistingManga(manga: Manga, dbManga: Mangas): Manga { + var manga = manga.copy(id = dbManga._id) + manga = manga.copyFrom(dbManga) updateManga(manga) + return manga } /** @@ -235,10 +235,10 @@ class BackupManager( * @return Updated manga info. */ internal suspend fun restoreNewManga(manga: Manga): Manga { - return manga.also { - it.initialized = it.description != null - it.id = insertManga(it) - } + return manga.copy( + initialized = manga.description != null, + id = insertManga(manga), + ) } /** @@ -369,28 +369,28 @@ class BackupManager( * @param manga the manga whose sync have to be restored. * @param tracks the track list to restore. */ - internal suspend fun restoreTracking(manga: Manga, tracks: List) { + internal suspend fun restoreTracking(manga: Manga, tracks: List) { // Fix foreign keys with the current manga id - tracks.map { it.manga_id = manga.id!! } + val tracks = tracks.map { it.copy(mangaId = manga.id!!) } // Get tracks from database val dbTracks = handler.awaitList { manga_syncQueries.getTracksByMangaId(manga.id!!) } val toUpdate = mutableListOf() - val toInsert = mutableListOf() + val toInsert = mutableListOf() tracks.forEach { track -> var isInDatabase = false for (dbTrack in dbTracks) { - if (track.sync_id == dbTrack.sync_id.toInt()) { + if (track.syncId == dbTrack.sync_id) { // The sync is already in the db, only update its fields var temp = dbTrack - if (track.media_id != dbTrack.remote_id) { - temp = temp.copy(remote_id = track.media_id) + if (track.remoteId != dbTrack.remote_id) { + temp = temp.copy(remote_id = track.remoteId) } - if (track.library_id != dbTrack.library_id) { - temp = temp.copy(library_id = track.library_id) + if (track.libraryId != dbTrack.library_id) { + temp = temp.copy(library_id = track.libraryId) } - temp = temp.copy(last_chapter_read = max(dbTrack.last_chapter_read, track.last_chapter_read.toDouble())) + temp = temp.copy(last_chapter_read = max(dbTrack.last_chapter_read, track.lastChapterRead)) isInDatabase = true toUpdate.add(temp) break @@ -398,8 +398,7 @@ class BackupManager( } if (!isInDatabase) { // Insert new sync. Let the db assign the id - track.id = null - toInsert.add(track) + toInsert.add(track.copy(id = 0)) } } // Update database @@ -428,47 +427,47 @@ class BackupManager( handler.await(true) { toInsert.forEach { track -> manga_syncQueries.insert( - track.manga_id, - track.sync_id.toLong(), - track.media_id, - track.library_id, + track.mangaId, + track.syncId, + track.remoteId, + track.libraryId, track.title, - track.last_chapter_read.toDouble(), - track.total_chapters.toLong(), - track.status.toLong(), + track.lastChapterRead, + track.totalChapters, + track.status, track.score, - track.tracking_url, - track.started_reading_date, - track.finished_reading_date, + track.remoteUrl, + track.startDate, + track.finishDate, ) } } } } - internal suspend fun restoreChapters(manga: Manga, chapters: List) { + internal suspend fun restoreChapters(manga: Manga, chapters: List) { val dbChapters = handler.awaitList { chaptersQueries.getChaptersByMangaId(manga.id!!) } - chapters.forEach { chapter -> + val processed = chapters.map { chapter -> + var chapter = chapter val dbChapter = dbChapters.find { it.url == chapter.url } if (dbChapter != null) { - chapter.id = dbChapter._id - chapter.copyFrom(dbChapter) + chapter = chapter.copy(id = dbChapter._id) + chapter = chapter.copyFrom(dbChapter) if (dbChapter.read && !chapter.read) { - chapter.read = dbChapter.read - chapter.last_page_read = dbChapter.last_page_read.toInt() - } else if (chapter.last_page_read == 0 && dbChapter.last_page_read != 0L) { - chapter.last_page_read = dbChapter.last_page_read.toInt() + chapter = chapter.copy(read = dbChapter.read, lastPageRead = dbChapter.last_page_read) + } else if (chapter.lastPageRead == 0L && dbChapter.last_page_read != 0L) { + chapter = chapter.copy(lastPageRead = dbChapter.last_page_read) } if (!chapter.bookmark && dbChapter.bookmark) { - chapter.bookmark = dbChapter.bookmark + chapter = chapter.copy(bookmark = dbChapter.bookmark) } } - chapter.manga_id = manga.id + chapter.copy(mangaId = manga.id ?: -1) } - val newChapters = chapters.groupBy { it.id != null } + val newChapters = processed.groupBy { it.id > 0 } newChapters[true]?.let { updateKnownChapters(it) } newChapters[false]?.let { insertChapters(it) } } @@ -495,19 +494,19 @@ class BackupManager( artist = manga.artist, author = manga.author, description = manga.description, - genre = manga.getGenres(), + genre = manga.genre, title = manga.title, - status = manga.status.toLong(), - thumbnailUrl = manga.thumbnail_url, + status = manga.status, + thumbnailUrl = manga.thumbnailUrl, favorite = manga.favorite, - lastUpdate = manga.last_update, + lastUpdate = manga.lastUpdate, nextUpdate = 0L, initialized = manga.initialized, - viewerFlags = manga.viewer_flags.toLong(), - chapterFlags = manga.chapter_flags.toLong(), - coverLastModified = manga.cover_last_modified, - dateAdded = manga.date_added, - updateStrategy = manga.update_strategy, + viewerFlags = manga.viewerFlags, + chapterFlags = manga.chapterFlags, + coverLastModified = manga.coverLastModified, + dateAdded = manga.dateAdded, + updateStrategy = manga.updateStrategy, ) mangasQueries.selectLastInsertedRowId() } @@ -521,42 +520,42 @@ class BackupManager( artist = manga.artist, author = manga.author, description = manga.description, - genre = manga.genre, + genre = manga.genre?.joinToString(separator = ", "), title = manga.title, - status = manga.status.toLong(), - thumbnailUrl = manga.thumbnail_url, + status = manga.status, + thumbnailUrl = manga.thumbnailUrl, favorite = manga.favorite.toLong(), - lastUpdate = manga.last_update, + lastUpdate = manga.lastUpdate, initialized = manga.initialized.toLong(), - viewer = manga.viewer_flags.toLong(), - chapterFlags = manga.chapter_flags.toLong(), - coverLastModified = manga.cover_last_modified, - dateAdded = manga.date_added, - mangaId = manga.id!!, - updateStrategy = manga.update_strategy.let(updateStrategyAdapter::encode), + viewer = manga.viewerFlags, + chapterFlags = manga.chapterFlags, + coverLastModified = manga.coverLastModified, + dateAdded = manga.dateAdded, + mangaId = manga.id, + updateStrategy = manga.updateStrategy.let(updateStrategyAdapter::encode), ) } - return manga.id!! + return manga.id } /** * Inserts list of chapters */ - private suspend fun insertChapters(chapters: List) { + private suspend fun insertChapters(chapters: List) { handler.await(true) { chapters.forEach { chapter -> chaptersQueries.insert( - chapter.manga_id!!, + chapter.mangaId, chapter.url, chapter.name, chapter.scanlator, chapter.read, chapter.bookmark, - chapter.last_page_read.toLong(), - chapter.chapter_number, - chapter.source_order.toLong(), - chapter.date_fetch, - chapter.date_upload, + chapter.lastPageRead, + chapter.chapterNumber, + chapter.sourceOrder, + chapter.dateFetch, + chapter.dateUpload, ) } } @@ -565,22 +564,22 @@ class BackupManager( /** * Updates a list of chapters */ - private suspend fun updateChapters(chapters: List) { + private suspend fun updateChapters(chapters: List) { handler.await(true) { chapters.forEach { chapter -> chaptersQueries.update( - chapter.manga_id!!, + chapter.mangaId, chapter.url, chapter.name, chapter.scanlator, chapter.read.toLong(), chapter.bookmark.toLong(), - chapter.last_page_read.toLong(), - chapter.chapter_number.toDouble(), - chapter.source_order.toLong(), - chapter.date_fetch, - chapter.date_upload, - chapter.id!!, + chapter.lastPageRead, + chapter.chapterNumber.toDouble(), + chapter.sourceOrder, + chapter.dateFetch, + chapter.dateUpload, + chapter.id, ) } } @@ -589,7 +588,7 @@ class BackupManager( /** * Updates a list of chapters with known database ids */ - private suspend fun updateKnownChapters(chapters: List) { + private suspend fun updateKnownChapters(chapters: List) { handler.await(true) { chapters.forEach { chapter -> chaptersQueries.update( @@ -599,12 +598,12 @@ class BackupManager( scanlator = null, read = chapter.read.toLong(), bookmark = chapter.bookmark.toLong(), - lastPageRead = chapter.last_page_read.toLong(), + lastPageRead = chapter.lastPageRead, chapterNumber = null, sourceOrder = null, dateFetch = null, dateUpload = null, - chapterId = chapter.id!!, + chapterId = chapter.id, ) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt index e515bf99fa..29880a3e1b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt @@ -7,13 +7,13 @@ import eu.kanade.tachiyomi.data.backup.models.BackupCategory import eu.kanade.tachiyomi.data.backup.models.BackupHistory import eu.kanade.tachiyomi.data.backup.models.BackupManga import eu.kanade.tachiyomi.data.backup.models.BackupSource -import eu.kanade.tachiyomi.data.database.models.Chapter -import eu.kanade.tachiyomi.data.database.models.Manga -import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.util.BackupUtil import eu.kanade.tachiyomi.util.system.createFileInCacheDir import kotlinx.coroutines.Job import okio.source +import tachiyomi.domain.chapter.model.Chapter +import tachiyomi.domain.manga.model.Manga +import tachiyomi.domain.track.model.Track import java.io.File import java.text.SimpleDateFormat import java.util.Date @@ -127,7 +127,7 @@ class BackupRestorer( } else { // Manga in database // Copy information from manga already in database - backupManager.restoreExistingManga(manga, dbManga) + val manga = backupManager.restoreExistingManga(manga, dbManga) // Fetch rest of manga information restoreNewManga(manga, chapters, categories, history, tracks, backupCategories) } @@ -156,8 +156,6 @@ class BackupRestorer( backupCategories: List, ) { val fetchedManga = backupManager.restoreNewManga(manga) - fetchedManga.id ?: return - backupManager.restoreChapters(fetchedManga, chapters) restoreExtras(fetchedManga, categories, history, tracks, backupCategories) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupChapter.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupChapter.kt index 19a81fc601..a70121a8ca 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupChapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupChapter.kt @@ -1,8 +1,8 @@ package eu.kanade.tachiyomi.data.backup.models -import eu.kanade.tachiyomi.data.database.models.ChapterImpl import kotlinx.serialization.Serializable import kotlinx.serialization.protobuf.ProtoNumber +import tachiyomi.domain.chapter.model.Chapter @Serializable data class BackupChapter( @@ -21,19 +21,19 @@ data class BackupChapter( @ProtoNumber(9) var chapterNumber: Float = 0F, @ProtoNumber(10) var sourceOrder: Long = 0, ) { - fun toChapterImpl(): ChapterImpl { - return ChapterImpl().apply { - url = this@BackupChapter.url - name = this@BackupChapter.name - chapter_number = this@BackupChapter.chapterNumber - scanlator = this@BackupChapter.scanlator - read = this@BackupChapter.read - bookmark = this@BackupChapter.bookmark - last_page_read = this@BackupChapter.lastPageRead.toInt() - date_fetch = this@BackupChapter.dateFetch - date_upload = this@BackupChapter.dateUpload - source_order = this@BackupChapter.sourceOrder.toInt() - } + fun toChapterImpl(): Chapter { + return Chapter.create().copy( + url = this@BackupChapter.url, + name = this@BackupChapter.name, + chapterNumber = this@BackupChapter.chapterNumber, + scanlator = this@BackupChapter.scanlator, + read = this@BackupChapter.read, + bookmark = this@BackupChapter.bookmark, + lastPageRead = this@BackupChapter.lastPageRead, + dateFetch = this@BackupChapter.dateFetch, + dateUpload = this@BackupChapter.dateUpload, + sourceOrder = this@BackupChapter.sourceOrder, + ) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupManga.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupManga.kt index f821f8e452..cef57a31bc 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupManga.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupManga.kt @@ -1,13 +1,12 @@ package eu.kanade.tachiyomi.data.backup.models -import eu.kanade.tachiyomi.data.database.models.ChapterImpl -import eu.kanade.tachiyomi.data.database.models.MangaImpl -import eu.kanade.tachiyomi.data.database.models.TrackImpl import eu.kanade.tachiyomi.source.model.UpdateStrategy import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType import kotlinx.serialization.Serializable import kotlinx.serialization.protobuf.ProtoNumber +import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.manga.model.Manga +import tachiyomi.domain.track.model.Track @Suppress("DEPRECATION") @Serializable @@ -41,32 +40,32 @@ data class BackupManga( @ProtoNumber(104) var history: List = emptyList(), @ProtoNumber(105) var updateStrategy: UpdateStrategy = UpdateStrategy.ALWAYS_UPDATE, ) { - fun getMangaImpl(): MangaImpl { - return MangaImpl().apply { - url = this@BackupManga.url - title = this@BackupManga.title - artist = this@BackupManga.artist - author = this@BackupManga.author - description = this@BackupManga.description - genre = this@BackupManga.genre.joinToString() - status = this@BackupManga.status - thumbnail_url = this@BackupManga.thumbnailUrl - favorite = this@BackupManga.favorite - source = this@BackupManga.source - date_added = this@BackupManga.dateAdded - viewer_flags = this@BackupManga.viewer_flags ?: this@BackupManga.viewer - chapter_flags = this@BackupManga.chapterFlags - update_strategy = this@BackupManga.updateStrategy - } + fun getMangaImpl(): Manga { + return Manga.create().copy( + url = this@BackupManga.url, + title = this@BackupManga.title, + artist = this@BackupManga.artist, + author = this@BackupManga.author, + description = this@BackupManga.description, + genre = this@BackupManga.genre, + status = this@BackupManga.status.toLong(), + thumbnailUrl = this@BackupManga.thumbnailUrl, + favorite = this@BackupManga.favorite, + source = this@BackupManga.source, + dateAdded = this@BackupManga.dateAdded, + viewerFlags = (this@BackupManga.viewer_flags ?: this@BackupManga.viewer).toLong(), + chapterFlags = this@BackupManga.chapterFlags.toLong(), + updateStrategy = this@BackupManga.updateStrategy, + ) } - fun getChaptersImpl(): List { + fun getChaptersImpl(): List { return chapters.map { it.toChapterImpl() } } - fun getTrackingImpl(): List { + fun getTrackingImpl(): List { return tracking.map { it.getTrackingImpl() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupTracking.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupTracking.kt index d6a041a4d8..08e03d9253 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupTracking.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupTracking.kt @@ -1,8 +1,8 @@ package eu.kanade.tachiyomi.data.backup.models -import eu.kanade.tachiyomi.data.database.models.TrackImpl import kotlinx.serialization.Serializable import kotlinx.serialization.protobuf.ProtoNumber +import tachiyomi.domain.track.model.Track @Serializable data class BackupTracking( @@ -29,25 +29,26 @@ data class BackupTracking( @ProtoNumber(100) var mediaId: Long = 0, ) { - fun getTrackingImpl(): TrackImpl { - return TrackImpl().apply { - sync_id = this@BackupTracking.syncId - @Suppress("DEPRECATION") - media_id = if (this@BackupTracking.mediaIdInt != 0) { + fun getTrackingImpl(): Track { + return Track( + id = -1, + mangaId = -1, + syncId = this@BackupTracking.syncId.toLong(), + remoteId = if (this@BackupTracking.mediaIdInt != 0) { this@BackupTracking.mediaIdInt.toLong() } else { this@BackupTracking.mediaId - } - library_id = this@BackupTracking.libraryId - title = this@BackupTracking.title - last_chapter_read = this@BackupTracking.lastChapterRead - total_chapters = this@BackupTracking.totalChapters - score = this@BackupTracking.score - status = this@BackupTracking.status - started_reading_date = this@BackupTracking.startedReadingDate - finished_reading_date = this@BackupTracking.finishedReadingDate - tracking_url = this@BackupTracking.trackingUrl - } + }, + libraryId = this@BackupTracking.libraryId, + title = this@BackupTracking.title, + lastChapterRead = this@BackupTracking.lastChapterRead.toDouble(), + totalChapters = this@BackupTracking.totalChapters.toLong(), + score = this@BackupTracking.score, + status = this@BackupTracking.status.toLong(), + startDate = this@BackupTracking.startedReadingDate, + finishDate = this@BackupTracking.finishedReadingDate, + remoteUrl = this@BackupTracking.trackingUrl, + ) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/coil/MangaCoverFetcher.kt b/app/src/main/java/eu/kanade/tachiyomi/data/coil/MangaCoverFetcher.kt index 616a97a44c..d68a11ccb9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/coil/MangaCoverFetcher.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/coil/MangaCoverFetcher.kt @@ -12,7 +12,6 @@ import coil.request.Options import coil.request.Parameters import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.coil.MangaCoverFetcher.Companion.USE_CUSTOM_COVER -import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.source.online.HttpSource import logcat.LogPriority @@ -26,11 +25,11 @@ import okio.Source import okio.buffer import okio.sink import tachiyomi.core.util.system.logcat +import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.MangaCover import tachiyomi.domain.source.service.SourceManager import uy.kohesive.injekt.injectLazy import java.io.File -import tachiyomi.domain.manga.model.Manga as DomainManga /** * A [Fetcher] that fetches cover image for [Manga] object. @@ -261,7 +260,7 @@ class MangaCoverFetcher( File, URL } - class Factory( + class MangaFactory( private val callFactoryLazy: Lazy, private val diskCacheLazy: Lazy, ) : Fetcher.Factory { @@ -270,36 +269,13 @@ class MangaCoverFetcher( private val sourceManager: SourceManager by injectLazy() override fun create(data: Manga, options: Options, imageLoader: ImageLoader): Fetcher { - return MangaCoverFetcher( - url = data.thumbnail_url, - isLibraryManga = data.favorite, - options = options, - coverFileLazy = lazy { coverCache.getCoverFile(data.thumbnail_url) }, - customCoverFileLazy = lazy { coverCache.getCustomCoverFile(data.id) }, - diskCacheKeyLazy = lazy { MangaKeyer().key(data, options) }, - sourceLazy = lazy { sourceManager.get(data.source) as? HttpSource }, - callFactoryLazy = callFactoryLazy, - diskCacheLazy = diskCacheLazy, - ) - } - } - - class DomainMangaFactory( - private val callFactoryLazy: Lazy, - private val diskCacheLazy: Lazy, - ) : Fetcher.Factory { - - private val coverCache: CoverCache by injectLazy() - private val sourceManager: SourceManager by injectLazy() - - override fun create(data: DomainManga, options: Options, imageLoader: ImageLoader): Fetcher { return MangaCoverFetcher( url = data.thumbnailUrl, isLibraryManga = data.favorite, options = options, coverFileLazy = lazy { coverCache.getCoverFile(data.thumbnailUrl) }, customCoverFileLazy = lazy { coverCache.getCustomCoverFile(data.id) }, - diskCacheKeyLazy = lazy { DomainMangaKeyer().key(data, options) }, + diskCacheKeyLazy = lazy { MangaKeyer().key(data, options) }, sourceLazy = lazy { sourceManager.get(data.source) as? HttpSource }, callFactoryLazy = callFactoryLazy, diskCacheLazy = diskCacheLazy, diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/coil/MangaCoverKeyer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/coil/MangaCoverKeyer.kt index 068d88581f..bc85b22f47 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/coil/MangaCoverKeyer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/coil/MangaCoverKeyer.kt @@ -4,24 +4,12 @@ import coil.key.Keyer import coil.request.Options import eu.kanade.domain.manga.model.hasCustomCover import eu.kanade.tachiyomi.data.cache.CoverCache -import eu.kanade.tachiyomi.data.database.models.Manga -import eu.kanade.tachiyomi.data.database.models.toDomainManga import tachiyomi.domain.manga.model.MangaCover import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import tachiyomi.domain.manga.model.Manga as DomainManga -class MangaKeyer : Keyer { - override fun key(data: Manga, options: Options): String { - return if (data.toDomainManga()!!.hasCustomCover()) { - "${data.id};${data.cover_last_modified}" - } else { - "${data.thumbnail_url};${data.cover_last_modified}" - } - } -} - -class DomainMangaKeyer : Keyer { +class MangaKeyer : Keyer { override fun key(data: DomainManga, options: Options): String { return if (data.hasCustomCover()) { "${data.id};${data.coverLastModified}" @@ -31,9 +19,11 @@ class DomainMangaKeyer : Keyer { } } -class MangaCoverKeyer : Keyer { +class MangaCoverKeyer( + private val coverCache: CoverCache = Injekt.get(), +) : Keyer { override fun key(data: MangaCover, options: Options): String { - return if (Injekt.get().getCustomCoverFile(data.mangaId).exists()) { + return if (coverCache.getCustomCoverFile(data.mangaId).exists()) { "${data.mangaId};${data.lastModified}" } else { "${data.url};${data.lastModified}" diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Manga.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Manga.kt deleted file mode 100644 index d6557894b7..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Manga.kt +++ /dev/null @@ -1,62 +0,0 @@ -package eu.kanade.tachiyomi.data.database.models - -import eu.kanade.tachiyomi.source.model.SManga -import eu.kanade.tachiyomi.ui.reader.setting.OrientationType -import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType -import tachiyomi.domain.manga.model.Manga as DomainManga - -interface Manga : SManga { - - var id: Long? - - var source: Long - - var favorite: Boolean - - // last time the chapter list changed in any way - var last_update: Long - - var date_added: Long - - var viewer_flags: Int - - var chapter_flags: Int - - var cover_last_modified: Long - - private fun setViewerFlags(flag: Int, mask: Int) { - viewer_flags = viewer_flags and mask.inv() or (flag and mask) - } - - var readingModeType: Int - get() = viewer_flags and ReadingModeType.MASK - set(readingMode) = setViewerFlags(readingMode, ReadingModeType.MASK) - - var orientationType: Int - get() = viewer_flags and OrientationType.MASK - set(rotationType) = setViewerFlags(rotationType, OrientationType.MASK) -} - -fun Manga.toDomainManga(): DomainManga? { - val mangaId = id ?: return null - return DomainManga( - id = mangaId, - source = source, - favorite = favorite, - lastUpdate = last_update, - dateAdded = date_added, - viewerFlags = viewer_flags.toLong(), - chapterFlags = chapter_flags.toLong(), - coverLastModified = cover_last_modified, - url = url, - title = title, - artist = artist, - author = author, - description = description, - genre = getGenres(), - status = status.toLong(), - thumbnailUrl = thumbnail_url, - updateStrategy = update_strategy, - initialized = initialized, - ) -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaImpl.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaImpl.kt deleted file mode 100644 index 7cc286bba0..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaImpl.kt +++ /dev/null @@ -1,55 +0,0 @@ -package eu.kanade.tachiyomi.data.database.models - -import eu.kanade.tachiyomi.source.model.UpdateStrategy - -open class MangaImpl : Manga { - - override var id: Long? = null - - override var source: Long = -1 - - override lateinit var url: String - - override lateinit var title: String - - override var artist: String? = null - - override var author: String? = null - - override var description: String? = null - - override var genre: String? = null - - override var status: Int = 0 - - override var thumbnail_url: String? = null - - override var favorite: Boolean = false - - override var last_update: Long = 0 - - override var date_added: Long = 0 - - override var update_strategy: UpdateStrategy = UpdateStrategy.ALWAYS_UPDATE - - override var initialized: Boolean = false - - override var viewer_flags: Int = 0 - - override var chapter_flags: Int = 0 - - override var cover_last_modified: Long = 0 - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || javaClass != other.javaClass) return false - - val manga = other as Manga - if (url != manga.url) return false - return id == manga.id - } - - override fun hashCode(): Int { - return url.hashCode() + id.hashCode() - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/model/SMangaExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/source/model/SMangaExtensions.kt index e6e8d7bc66..7147db9dec 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/model/SMangaExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/model/SMangaExtensions.kt @@ -1,6 +1,7 @@ package eu.kanade.tachiyomi.source.model import tachiyomi.data.Mangas +import tachiyomi.domain.manga.model.Manga fun SManga.copyFrom(other: Mangas) { if (other.author != null) { @@ -29,3 +30,33 @@ fun SManga.copyFrom(other: Mangas) { initialized = other.initialized } } + +fun Manga.copyFrom(other: Mangas): Manga { + var manga = this + if (other.author != null) { + manga = manga.copy(author = other.author) + } + + if (other.artist != null) { + manga = manga.copy(artist = other.artist) + } + + if (other.description != null) { + manga = manga.copy(description = other.description) + } + + if (other.genre != null) { + manga = manga.copy(genre = other.genre) + } + + if (other.thumbnail_url != null) { + manga = manga.copy(thumbnailUrl = other.thumbnail_url) + } + + manga = manga.copy(status = other.status) + + if (!initialized) { + manga = manga.copy(initialized = other.initialized) + } + return manga +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt index 6e9836436c..25465884cf 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt @@ -16,7 +16,6 @@ import eu.kanade.domain.manga.interactor.UpdateManga import eu.kanade.domain.manga.model.downloadedFilter import eu.kanade.domain.manga.model.isLocal import eu.kanade.domain.manga.model.toSManga -import eu.kanade.domain.track.model.toDbTrack import eu.kanade.domain.ui.UiPreferences import eu.kanade.presentation.manga.DownloadAction import eu.kanade.presentation.manga.components.ChapterDownloadAction @@ -883,10 +882,9 @@ class MangaInfoScreenModel( getTracks.subscribe(manga.id) .catch { logcat(LogPriority.ERROR, it) } .map { tracks -> - val dbTracks = tracks.map { it.toDbTrack() } loggedServices // Map to TrackItem - .map { service -> TrackItem(dbTracks.find { it.sync_id.toLong() == service.id }, service) } + .map { service -> TrackItem(tracks.find { it.syncId == service.id }, service) } // Show only if the service supports this manga's source .filter { (it.service as? EnhancedTrackService)?.accept(source!!) ?: true } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt index 0bbe71eaeb..568fddbd33 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt @@ -47,7 +47,6 @@ import eu.kanade.presentation.track.TrackServiceSearch import eu.kanade.presentation.track.TrackStatusSelector import eu.kanade.presentation.util.Screen import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.track.EnhancedTrackService import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.TrackService @@ -71,6 +70,7 @@ import tachiyomi.domain.source.service.SourceManager import tachiyomi.domain.track.interactor.DeleteTrack import tachiyomi.domain.track.interactor.GetTracks import tachiyomi.domain.track.interactor.InsertTrack +import tachiyomi.domain.track.model.Track import tachiyomi.presentation.core.components.material.AlertDialogContent import tachiyomi.presentation.core.components.material.padding import uy.kohesive.injekt.Injekt @@ -149,7 +149,7 @@ data class TrackInfoDialogHomeScreen( TrackServiceSearchScreen( mangaId = mangaId, initialQuery = it.track?.title ?: mangaTitle, - currentUrl = it.track?.tracking_url, + currentUrl = it.track?.remoteUrl, serviceId = it.service.id, ), ) @@ -163,7 +163,7 @@ data class TrackInfoDialogHomeScreen( * Opens registered tracker url in browser */ private fun openTrackerInBrowser(context: Context, trackItem: TrackItem) { - val url = trackItem.track?.tracking_url ?: return + val url = trackItem.track?.remoteUrl ?: return if (url.isNotBlank()) { context.openInBrowser(url) } @@ -218,7 +218,7 @@ data class TrackInfoDialogHomeScreen( for (trackItem in trackItems) { try { val track = trackItem.track ?: continue - val domainTrack = trackItem.service.refresh(track).toDomainTrack() ?: continue + val domainTrack = trackItem.service.refresh(track.toDbTrack()).toDomainTrack() ?: continue insertTrack.await(domainTrack) if (trackItem.service is EnhancedTrackService) { @@ -247,13 +247,12 @@ data class TrackInfoDialogHomeScreen( } } - private fun List.mapToTrackItem(): List { - val dbTracks = map { it.toDbTrack() } + private fun List.mapToTrackItem(): List { val loggedServices = Injekt.get().services.filter { it.isLogged } val source = Injekt.get().getOrStub(sourceId) return loggedServices // Map to TrackItem - .map { service -> TrackItem(dbTracks.find { it.sync_id.toLong() == service.id }, service) } + .map { service -> TrackItem(find { it.syncId == service.id }, service) } // Show only if the service supports this manga's source .filter { (it.service as? EnhancedTrackService)?.accept(source) ?: true } } @@ -291,7 +290,7 @@ private data class TrackStatusSelectorScreen( private class Model( private val track: Track, private val service: TrackService, - ) : StateScreenModel(State(track.status)) { + ) : StateScreenModel(State(track.status.toInt())) { fun getSelections(): Map { return service.getStatusList().associateWith { service.getStatus(it) } @@ -303,7 +302,7 @@ private data class TrackStatusSelectorScreen( fun setStatus() { coroutineScope.launchNonCancellable { - service.setRemoteStatus(track, state.value.selection) + service.setRemoteStatus(track.toDbTrack(), state.value.selection) } } @@ -341,15 +340,15 @@ private data class TrackChapterSelectorScreen( private class Model( private val track: Track, private val service: TrackService, - ) : StateScreenModel(State(track.last_chapter_read.toInt())) { + ) : StateScreenModel(State(track.lastChapterRead.toInt())) { fun getRange(): Iterable { - val endRange = if (track.total_chapters > 0) { - track.total_chapters + val endRange = if (track.totalChapters > 0) { + track.totalChapters } else { 10000 } - return 0..endRange + return 0..endRange.toInt() } fun setSelection(selection: Int) { @@ -358,7 +357,7 @@ private data class TrackChapterSelectorScreen( fun setChapter() { coroutineScope.launchNonCancellable { - service.setRemoteLastChapterRead(track, state.value.selection) + service.setRemoteLastChapterRead(track.toDbTrack(), state.value.selection) } } @@ -396,7 +395,7 @@ private data class TrackScoreSelectorScreen( private class Model( private val track: Track, private val service: TrackService, - ) : StateScreenModel(State(service.displayScore(track))) { + ) : StateScreenModel(State(service.displayScore(track.toDbTrack()))) { fun getSelections(): List { return service.getScoreList() @@ -408,7 +407,7 @@ private data class TrackScoreSelectorScreen( fun setScore() { coroutineScope.launchNonCancellable { - service.setRemoteScore(track, state.value.selection) + service.setRemoteScore(track.toDbTrack(), state.value.selection) } } @@ -436,9 +435,9 @@ private data class TrackDateSelectorScreen( } val canRemove = if (start) { - track.started_reading_date > 0 + track.startDate > 0 } else { - track.finished_reading_date > 0 + track.finishDate > 0 } TrackDateSelector( title = if (start) { @@ -457,15 +456,15 @@ private data class TrackDateSelectorScreen( return@TrackDateSelector false } - if (start && track.finished_reading_date > 0) { + if (start && track.finishDate > 0) { // Disallow start date to be set later than finish date - val dateFinished = Instant.ofEpochMilli(track.finished_reading_date) + val dateFinished = Instant.ofEpochMilli(track.finishDate) .atZone(ZoneId.systemDefault()) .toLocalDate() dateToCheck <= dateFinished - } else if (!start && track.started_reading_date > 0) { + } else if (!start && track.startDate > 0) { // Disallow end date to be set earlier than start date - val dateStarted = Instant.ofEpochMilli(track.started_reading_date) + val dateStarted = Instant.ofEpochMilli(track.startDate) .atZone(ZoneId.systemDefault()) .toLocalDate() dateToCheck >= dateStarted @@ -489,7 +488,7 @@ private data class TrackDateSelectorScreen( // In UTC val initialSelection: Long get() { - val millis = (if (start) track.started_reading_date else track.finished_reading_date) + val millis = (if (start) track.startDate else track.finishDate) .takeIf { it != 0L } ?: Instant.now().toEpochMilli() return convertEpochMillisZone(millis, ZoneOffset.systemDefault(), ZoneOffset.UTC) @@ -501,9 +500,9 @@ private data class TrackDateSelectorScreen( val localMillis = convertEpochMillisZone(millis, ZoneOffset.UTC, ZoneOffset.systemDefault()) coroutineScope.launchNonCancellable { if (start) { - service.setRemoteStartDate(track, localMillis) + service.setRemoteStartDate(track.toDbTrack(), localMillis) } else { - service.setRemoteFinishDate(track, localMillis) + service.setRemoteFinishDate(track.toDbTrack(), localMillis) } } } @@ -600,9 +599,9 @@ private data class TrackDateRemoverScreen( fun removeDate() { coroutineScope.launchNonCancellable { if (start) { - service.setRemoteStartDate(track, 0) + service.setRemoteStartDate(track.toDbTrack(), 0) } else { - service.setRemoteFinishDate(track, 0) + service.setRemoteFinishDate(track.toDbTrack(), 0) } } } @@ -679,7 +678,7 @@ data class TrackServiceSearchScreen( } } - fun registerTracking(item: Track) { + fun registerTracking(item: TrackSearch) { coroutineScope.launchNonCancellable { service.registerTracking(item, mangaId) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackItem.kt index a751434d9e..d0883e5937 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackItem.kt @@ -1,6 +1,6 @@ package eu.kanade.tachiyomi.ui.manga.track -import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.track.TrackService +import tachiyomi.domain.track.model.Track data class TrackItem(val track: Track?, val service: TrackService)