diff --git a/CHANGELOG.md b/CHANGELOG.md index 90b83403df..b2d1a83d08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,3 +17,4 @@ Please backup your data before updating to this version. ## Other - Migrate to SQLDelight +- Custom manga info is now stored in the database diff --git a/app/src/main/java/dev/yokai/core/di/DomainModule.kt b/app/src/main/java/dev/yokai/core/di/DomainModule.kt index 5d8f0aedba..2febf1ffe5 100644 --- a/app/src/main/java/dev/yokai/core/di/DomainModule.kt +++ b/app/src/main/java/dev/yokai/core/di/DomainModule.kt @@ -2,6 +2,7 @@ package dev.yokai.core.di import dev.yokai.domain.extension.repo.ExtensionRepoRepository import dev.yokai.data.extension.repo.ExtensionRepoRepositoryImpl +import dev.yokai.data.library.custom.CustomMangaRepositoryImpl import dev.yokai.domain.extension.interactor.TrustExtension import dev.yokai.domain.extension.repo.interactor.CreateExtensionRepo import dev.yokai.domain.extension.repo.interactor.DeleteExtensionRepo @@ -9,6 +10,10 @@ import dev.yokai.domain.extension.repo.interactor.GetExtensionRepo import dev.yokai.domain.extension.repo.interactor.GetExtensionRepoCount import dev.yokai.domain.extension.repo.interactor.ReplaceExtensionRepo import dev.yokai.domain.extension.repo.interactor.UpdateExtensionRepo +import dev.yokai.domain.library.custom.CustomMangaRepository +import dev.yokai.domain.library.custom.interactor.CreateCustomManga +import dev.yokai.domain.library.custom.interactor.DeleteCustomManga +import dev.yokai.domain.library.custom.interactor.GetCustomManga import uy.kohesive.injekt.api.InjektModule import uy.kohesive.injekt.api.InjektRegistrar import uy.kohesive.injekt.api.addFactory @@ -17,6 +22,8 @@ import uy.kohesive.injekt.api.get class DomainModule : InjektModule { override fun InjektRegistrar.registerInjectables() { + addFactory { TrustExtension(get(), get()) } + addSingletonFactory { ExtensionRepoRepositoryImpl(get()) } addFactory { CreateExtensionRepo(get()) } addFactory { DeleteExtensionRepo(get()) } @@ -25,6 +32,9 @@ class DomainModule : InjektModule { addFactory { ReplaceExtensionRepo(get()) } addFactory { UpdateExtensionRepo(get(), get()) } - addFactory { TrustExtension(get(), get()) } + addSingletonFactory { CustomMangaRepositoryImpl(get()) } + addFactory { CreateCustomManga(get()) } + addFactory { DeleteCustomManga(get()) } + addFactory { GetCustomManga(get()) } } } diff --git a/app/src/main/java/dev/yokai/data/library/custom/CustomMangaRepositoryImpl.kt b/app/src/main/java/dev/yokai/data/library/custom/CustomMangaRepositoryImpl.kt new file mode 100644 index 0000000000..eedb649ff6 --- /dev/null +++ b/app/src/main/java/dev/yokai/data/library/custom/CustomMangaRepositoryImpl.kt @@ -0,0 +1,75 @@ +package dev.yokai.data.library.custom + +import android.database.sqlite.SQLiteException +import dev.yokai.data.DatabaseHandler +import dev.yokai.domain.library.custom.CustomMangaRepository +import dev.yokai.domain.library.custom.exception.SaveCustomMangaException +import dev.yokai.domain.library.custom.model.CustomMangaInfo +import kotlinx.coroutines.flow.Flow +import timber.log.Timber + +class CustomMangaRepositoryImpl(private val handler: DatabaseHandler) : CustomMangaRepository { + override fun subscribeAll(): Flow> = + handler.subscribeToList { custom_manga_infoQueries.findAll(::mapCustomMangaInfo) } + + override suspend fun getAll(): List = + handler.awaitList { custom_manga_infoQueries.findAll(::mapCustomMangaInfo) } + + override suspend fun insertCustomManga( + mangaId: Long, + title: String?, + author: String?, + artist: String?, + description: String?, + genre: String?, + status: Int? + ) { + try { + handler.await { custom_manga_infoQueries.insert(mangaId, title, author, artist, description, genre, status?.toLong()) } + } catch (exc: SQLiteException) { + Timber.e(exc) + throw SaveCustomMangaException(exc) + } + } + + override suspend fun insertBulkCustomManga(mangaList: List) { + try { + handler.await(true) { + for (customMangaInfo in mangaList) { + custom_manga_infoQueries.insert( + customMangaInfo.mangaId, + customMangaInfo.title, + customMangaInfo.author, + customMangaInfo.artist, + customMangaInfo.description, + customMangaInfo.genre, + customMangaInfo.status?.toLong(), + ) + } + } + } catch (exc: SQLiteException) { + Timber.e(exc) + throw SaveCustomMangaException(exc) + } + } + + override suspend fun deleteCustomManga(mangaId: Long) = + handler.await { custom_manga_infoQueries.delete(mangaId) } + + override suspend fun deleteBulkCustomManga(mangaIds: List) = + handler.await(true) { + for (mangaId in mangaIds) { + custom_manga_infoQueries.delete(mangaId) + } + } + + private fun mapCustomMangaInfo( + mangaId: Long, + title: String?, + author: String?, + artist: String?, + description: String?, + genre: String?, + status: Long? + ): CustomMangaInfo = CustomMangaInfo(mangaId, title, author, artist, description, genre, status?.toInt()) +} diff --git a/app/src/main/java/dev/yokai/domain/library/custom/CustomMangaRepository.kt b/app/src/main/java/dev/yokai/domain/library/custom/CustomMangaRepository.kt new file mode 100644 index 0000000000..e0506d4071 --- /dev/null +++ b/app/src/main/java/dev/yokai/domain/library/custom/CustomMangaRepository.kt @@ -0,0 +1,31 @@ +package dev.yokai.domain.library.custom + +import dev.yokai.domain.library.custom.model.CustomMangaInfo +import kotlinx.coroutines.flow.Flow + +interface CustomMangaRepository { + fun subscribeAll(): Flow> + suspend fun getAll(): List + suspend fun insertCustomManga( + mangaId: Long, + title: String? = null, + author: String? = null, + artist: String? = null, + description: String? = null, + genre: String? = null, + status: Int? = null, + ) + suspend fun insertCustomManga(mangaInfo: CustomMangaInfo) = + insertCustomManga( + mangaInfo.mangaId, + mangaInfo.title, + mangaInfo.author, + mangaInfo.artist, + mangaInfo.description, + mangaInfo.genre, + mangaInfo.status, + ) + suspend fun insertBulkCustomManga(mangaList: List) + suspend fun deleteCustomManga(mangaId: Long) + suspend fun deleteBulkCustomManga(mangaIds: List) +} diff --git a/app/src/main/java/dev/yokai/domain/library/custom/exception/SaveCustomMangaException.kt b/app/src/main/java/dev/yokai/domain/library/custom/exception/SaveCustomMangaException.kt new file mode 100644 index 0000000000..d4af3e5a18 --- /dev/null +++ b/app/src/main/java/dev/yokai/domain/library/custom/exception/SaveCustomMangaException.kt @@ -0,0 +1,10 @@ +package dev.yokai.domain.library.custom.exception + +import java.io.IOException + +/** + * Exception to abstract over SQLiteException and SQLiteConstraintException for multiplatform. + * + * @param throwable the source throwable to include for tracing. + */ +class SaveCustomMangaException(throwable: Throwable) : IOException("Error Saving Custom Manga Info to Database", throwable) diff --git a/app/src/main/java/dev/yokai/domain/library/custom/interactor/CreateCustomManga.kt b/app/src/main/java/dev/yokai/domain/library/custom/interactor/CreateCustomManga.kt new file mode 100644 index 0000000000..a1bf1f392d --- /dev/null +++ b/app/src/main/java/dev/yokai/domain/library/custom/interactor/CreateCustomManga.kt @@ -0,0 +1,32 @@ +package dev.yokai.domain.library.custom.interactor + +import dev.yokai.domain.library.custom.CustomMangaRepository +import dev.yokai.domain.library.custom.exception.SaveCustomMangaException +import dev.yokai.domain.library.custom.model.CustomMangaInfo + +class CreateCustomManga( + private val customMangaRepository: CustomMangaRepository, +) { + suspend fun await(mangaInfo: CustomMangaInfo): Result { + try { + customMangaRepository.insertCustomManga(mangaInfo) + return Result.Success + } catch (exc: SaveCustomMangaException) { + return Result.Error + } + } + + suspend fun bulk(mangaList: List): Result { + try { + customMangaRepository.insertBulkCustomManga(mangaList) + return Result.Success + } catch (exc: SaveCustomMangaException) { + return Result.Error + } + } + + sealed interface Result { + data object Success : Result + data object Error : Result + } +} diff --git a/app/src/main/java/dev/yokai/domain/library/custom/interactor/DeleteCustomManga.kt b/app/src/main/java/dev/yokai/domain/library/custom/interactor/DeleteCustomManga.kt new file mode 100644 index 0000000000..5551f4d4d7 --- /dev/null +++ b/app/src/main/java/dev/yokai/domain/library/custom/interactor/DeleteCustomManga.kt @@ -0,0 +1,10 @@ +package dev.yokai.domain.library.custom.interactor + +import dev.yokai.domain.library.custom.CustomMangaRepository + +class DeleteCustomManga( + private val customMangaRepository: CustomMangaRepository, +) { + suspend fun await(mangaId: Long) = customMangaRepository.deleteCustomManga(mangaId) + suspend fun bulk(mangaIds: List) = customMangaRepository.deleteBulkCustomManga(mangaIds) +} diff --git a/app/src/main/java/dev/yokai/domain/library/custom/interactor/GetCustomManga.kt b/app/src/main/java/dev/yokai/domain/library/custom/interactor/GetCustomManga.kt new file mode 100644 index 0000000000..a01fbfc38b --- /dev/null +++ b/app/src/main/java/dev/yokai/domain/library/custom/interactor/GetCustomManga.kt @@ -0,0 +1,11 @@ +package dev.yokai.domain.library.custom.interactor + +import dev.yokai.domain.library.custom.CustomMangaRepository + +class GetCustomManga( + private val customMangaRepository: CustomMangaRepository, +) { + fun subscribeAll() = customMangaRepository.subscribeAll() + + suspend fun getAll() = customMangaRepository.getAll() +} diff --git a/app/src/main/java/dev/yokai/domain/library/custom/model/CustomMangaInfo.kt b/app/src/main/java/dev/yokai/domain/library/custom/model/CustomMangaInfo.kt new file mode 100644 index 0000000000..82b4014da0 --- /dev/null +++ b/app/src/main/java/dev/yokai/domain/library/custom/model/CustomMangaInfo.kt @@ -0,0 +1,37 @@ +package dev.yokai.domain.library.custom.model + +import eu.kanade.tachiyomi.data.database.models.Manga +import eu.kanade.tachiyomi.data.database.models.MangaImpl + +data class CustomMangaInfo( + var mangaId: Long, + val title: String? = null, + val author: String? = null, + val artist: String? = null, + val description: String? = null, + val genre: String? = null, + val status: Int? = null, +) { + fun toManga() = MangaImpl().apply { + id = this@CustomMangaInfo.mangaId + title = this@CustomMangaInfo.title ?: "" + author = this@CustomMangaInfo.author + artist = this@CustomMangaInfo.artist + description = this@CustomMangaInfo.description + genre = this@CustomMangaInfo.genre + status = this@CustomMangaInfo.status ?: -1 + } + + companion object { + fun Manga.getMangaInfo() = + CustomMangaInfo( + mangaId = id!!, + title = title, + author = author, + artist = artist, + description = description, + genre = genre, + status = status, + ) + } +} 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 3579d86a26..acbbd98398 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 @@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.data.backup import android.content.Context import android.net.Uri +import dev.yokai.domain.library.custom.model.CustomMangaInfo import dev.yokai.domain.ui.settings.ReaderPreferences import dev.yokai.domain.ui.settings.ReaderPreferences.CutoutBehaviour import eu.kanade.tachiyomi.R @@ -37,6 +38,7 @@ import eu.kanade.tachiyomi.util.BackupUtil import eu.kanade.tachiyomi.util.chapter.ChapterUtil import eu.kanade.tachiyomi.util.manga.MangaUtil import eu.kanade.tachiyomi.util.system.createFileInCacheDir +import eu.kanade.tachiyomi.util.system.launchNow import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.isActive import kotlinx.serialization.protobuf.ProtoBuf @@ -198,7 +200,7 @@ class BackupRestorer(val context: Context, val notifier: BackupNotifier) { tracks: List, backupCategories: List, filteredScanlators: List, - customManga: CustomMangaManager.ComicList.ComicInfoYokai?, + customManga: CustomMangaInfo?, ) { val fetchedManga = manga.also { it.initialized = it.description != null @@ -218,7 +220,7 @@ class BackupRestorer(val context: Context, val notifier: BackupNotifier) { tracks: List, backupCategories: List, filteredScanlators: List, - customManga: CustomMangaManager.ComicList.ComicInfoYokai?, + customManga: CustomMangaInfo?, ) { restoreChapters(backupManga, chapters) restoreExtras(backupManga, categories, history, tracks, backupCategories, filteredScanlators, customManga) @@ -258,14 +260,18 @@ class BackupRestorer(val context: Context, val notifier: BackupNotifier) { tracks: List, backupCategories: List, filteredScanlators: List, - customManga: CustomMangaManager.ComicList.ComicInfoYokai?, + customManga: CustomMangaInfo?, ) { restoreCategories(manga, categories, backupCategories) restoreHistoryForManga(history) restoreTrackForManga(manga, tracks) restoreFilteredScanlatorsForManga(manga, filteredScanlators) - customManga?.id = manga.id!! - customManga?.let { customMangaManager.saveMangaInfo(it) } + customManga?.let { + it.mangaId = manga.id!! + launchNow { + customMangaManager.saveMangaInfo(it) + } + } } /** 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 d156246bc6..57d32c64df 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 @@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.data.backup.models import dev.yokai.core.metadata.ComicInfo import dev.yokai.core.metadata.ComicInfoPublishingStatus +import dev.yokai.domain.library.custom.model.CustomMangaInfo import eu.kanade.tachiyomi.data.database.models.ChapterImpl import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.MangaImpl @@ -85,7 +86,7 @@ data class BackupManga( } } - fun getCustomMangaInfo(): CustomMangaManager.ComicList.ComicInfoYokai? { + fun getCustomMangaInfo(): CustomMangaInfo? { if (customTitle != null || customArtist != null || customAuthor != null || @@ -93,13 +94,13 @@ data class BackupManga( customGenre != null || customStatus != 0 ) { - return CustomMangaManager.ComicList.ComicInfoYokai.create( - id = 0L, + return CustomMangaInfo( + mangaId= 0L, title = customTitle, author = customAuthor, artist = customArtist, description = customDescription, - genre = customGenre?.toTypedArray(), + genre = customGenre?.joinToString(), status = customStatus, ) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/library/CustomMangaManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/library/CustomMangaManager.kt index 2146864697..6a37f30bf9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/library/CustomMangaManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/library/CustomMangaManager.kt @@ -6,9 +6,16 @@ import dev.yokai.core.metadata.COMIC_INFO_EDITS_FILE import dev.yokai.core.metadata.ComicInfo import dev.yokai.core.metadata.ComicInfoPublishingStatus import dev.yokai.core.metadata.copyFromComicInfo +import dev.yokai.domain.library.custom.interactor.CreateCustomManga +import dev.yokai.domain.library.custom.interactor.DeleteCustomManga +import dev.yokai.domain.library.custom.interactor.GetCustomManga +import dev.yokai.domain.library.custom.model.CustomMangaInfo +import dev.yokai.domain.library.custom.model.CustomMangaInfo.Companion.getMangaInfo import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.MangaImpl -import eu.kanade.tachiyomi.util.system.writeText +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json import kotlinx.serialization.json.decodeFromStream @@ -17,44 +24,46 @@ import nl.adaptivity.xmlutil.serialization.XML import nl.adaptivity.xmlutil.serialization.XmlSerialName import nl.adaptivity.xmlutil.serialization.XmlValue import uy.kohesive.injekt.injectLazy -import java.io.InputStream import java.nio.charset.StandardCharsets class CustomMangaManager(val context: Context) { + private val scope = CoroutineScope(Dispatchers.IO) + private val xml: XML by injectLazy() private val externalDir = UniFile.fromFile(context.getExternalFilesDir(null)) + private var removedCustomManga = mutableListOf() private var customMangaMap = mutableMapOf() + private val createCustomManga: CreateCustomManga by injectLazy() + private val deleteCustomManga: DeleteCustomManga by injectLazy() + private val getCustomManga: GetCustomManga by injectLazy() + init { - fetchCustomData() + scope.launch { + fetchCustomData() + } } companion object { const val EDIT_JSON_FILE = "edits.json" - - fun Manga.toComicInfo(): ComicList.ComicInfoYokai { - return ComicList.ComicInfoYokai.create( - id = id!!, - title = title, - author = author, - artist = artist, - description = description, - genre = genre.orEmpty(), - status = status, - ) - } } fun getManga(manga: Manga): Manga? = customMangaMap[manga.id] - private fun fetchCustomData() { + private suspend fun fetchCustomData() { val comicInfoEdits = externalDir?.findFile(COMIC_INFO_EDITS_FILE) val editJson = externalDir?.findFile(EDIT_JSON_FILE) + val dbMangaInfo = getCustomManga.getAll() + customMangaMap = dbMangaInfo.associate { info -> + val id = info.mangaId + id to info.toManga() + }.toMutableMap() + if (comicInfoEdits != null && comicInfoEdits.exists() && comicInfoEdits.isFile) { - fetchFromComicInfo(comicInfoEdits.openInputStream()) + fetchFromComicInfo(comicInfoEdits) return } @@ -65,20 +74,22 @@ class CustomMangaManager(val context: Context) { } } - private fun fetchFromComicInfo(stream: InputStream) { - val comicInfoEdits = AndroidXmlReader(stream, StandardCharsets.UTF_8.name()).use { + private suspend fun fetchFromComicInfo(comicInfoFile: UniFile) { + val comicInfoEdits = AndroidXmlReader(comicInfoFile.openInputStream(), StandardCharsets.UTF_8.name()).use { xml.decodeFromReader(it) } if (comicInfoEdits.comics == null) return - customMangaMap = comicInfoEdits.comics.mapNotNull { obj -> + comicInfoEdits.comics.mapNotNull { obj -> val id = obj.id ?: return@mapNotNull null - id to mangaFromComicInfoObject(id, obj.value) - }.toMap().toMutableMap() + customMangaMap[id] = mangaFromComicInfoObject(id, obj.value) + } + + saveCustomInfo { comicInfoFile.delete() } } - private fun fetchFromLegacyJson(jsonFile: UniFile) { + private suspend fun fetchFromLegacyJson(jsonFile: UniFile) { val json = try { Json.decodeFromStream(jsonFile.openInputStream()) } catch (e: Exception) { @@ -86,36 +97,41 @@ class CustomMangaManager(val context: Context) { } ?: return val mangasJson = json.mangas ?: return - customMangaMap = mangasJson.mapNotNull { mangaObject -> + mangasJson.mapNotNull { mangaObject -> val id = mangaObject.id ?: return@mapNotNull null - id to mangaObject.toManga() - }.toMap().toMutableMap() + customMangaMap[id] = mangaObject.toManga() + } saveCustomInfo { jsonFile.delete() } } - fun saveMangaInfo(manga: ComicList.ComicInfoYokai) { - val mangaId = manga.id ?: return - if (manga.value.series == null && - manga.value.writer == null && - manga.value.penciller == null && - manga.value.summary == null && - manga.value.genre == null && - (manga.value.publishingStatus?.value ?: "Invalid") == "Invalid" + suspend fun saveMangaInfo(manga: CustomMangaInfo) { + val mangaId = manga.mangaId ?: return + if (manga.title == null && + manga.author == null && + manga.artist == null && + manga.description == null && + manga.genre == null && + (manga.status ?: -1) == -1 ) { - customMangaMap.remove(mangaId) + customMangaMap[mangaId]?.let { + removedCustomManga.add(mangaId) + customMangaMap.remove(mangaId) + } } else { - customMangaMap[mangaId] = mangaFromComicInfoObject(mangaId, manga.value) + customMangaMap[mangaId] = manga.toManga() } saveCustomInfo() } - private fun saveCustomInfo(onComplete: () -> Unit = {}) { - val comicInfoEdits = externalDir?.createFile(COMIC_INFO_EDITS_FILE) ?: return + private suspend fun saveCustomInfo(onComplete: () -> Unit = {}) { + deleteCustomManga.bulk(removedCustomManga) + removedCustomManga = mutableListOf() - val edits = customMangaMap.values.map { it.toComicInfo() } - if (edits.isNotEmpty() && comicInfoEdits.exists()) { - comicInfoEdits.writeText(xml.encodeToString(ComicList.serializer(), ComicList(edits)), onComplete = onComplete) + val edits = customMangaMap.values.map { it.getMangaInfo() } + if (edits.isNotEmpty()) { + createCustomManga.bulk(edits) + onComplete() } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsPresenter.kt index 742afb7ca2..f02aeec829 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsPresenter.kt @@ -10,6 +10,7 @@ import coil3.request.CachePolicy import coil3.request.ImageRequest import coil3.request.SuccessResult import com.hippo.unifile.UniFile +import dev.yokai.domain.library.custom.model.CustomMangaInfo import dev.yokai.domain.storage.StorageManager import eu.kanade.tachiyomi.BuildConfig import eu.kanade.tachiyomi.R @@ -55,6 +56,7 @@ import eu.kanade.tachiyomi.util.storage.DiskUtil import eu.kanade.tachiyomi.util.system.ImageUtil import eu.kanade.tachiyomi.util.system.executeOnIO import eu.kanade.tachiyomi.util.system.launchIO +import eu.kanade.tachiyomi.util.system.launchNow import eu.kanade.tachiyomi.util.system.launchUI import eu.kanade.tachiyomi.util.system.withUIContext import eu.kanade.tachiyomi.widget.TriStateCheckBox @@ -712,13 +714,13 @@ class MangaDetailsPresenter( fun confirmDeletion() { launchIO { coverCache.deleteFromCache(manga) - customMangaManager.saveMangaInfo(CustomMangaManager.ComicList.ComicInfoYokai.create( - id = manga.id!!, + customMangaManager.saveMangaInfo(CustomMangaInfo( + mangaId = manga.id!!, title = null, author = null, artist = null, description = null, - genre = null as String?, + genre = null, status = null, )) downloadManager.deleteManga(manga, source) @@ -801,20 +803,22 @@ class MangaDetailsPresenter( null } if (seriesType != null) { - genre = setSeriesType(seriesType, genre?.joinToString(", ")) + genre = setSeriesType(seriesType, genre?.joinToString()) manga.viewer_flags = -1 db.updateViewerFlags(manga).executeAsBlocking() } - val manga = CustomMangaManager.ComicList.ComicInfoYokai.create( - id = manga.id!!, + val manga = CustomMangaInfo( + mangaId = manga.id!!, title?.trimOrNull(), author?.trimOrNull(), artist?.trimOrNull(), description?.trimOrNull(), - genre, + genre?.joinToString(), if (status != this.manga.originalStatus) status else null, ) - customMangaManager.saveMangaInfo(manga) + launchNow { + customMangaManager.saveMangaInfo(manga) + } } if (uri != null) { editCoverWithStream(uri) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcessAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcessAdapter.kt index 214cb9649c..3c526b63ba 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcessAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcessAdapter.kt @@ -1,6 +1,7 @@ package eu.kanade.tachiyomi.ui.migration.manga.process import android.view.MenuItem +import dev.yokai.domain.library.custom.model.CustomMangaInfo.Companion.getMangaInfo import dev.yokai.domain.ui.UiPreferences import eu.davidea.flexibleadapter.FlexibleAdapter import eu.kanade.tachiyomi.data.cache.CoverCache @@ -9,13 +10,13 @@ import eu.kanade.tachiyomi.data.database.models.History import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.MangaCategory import eu.kanade.tachiyomi.data.library.CustomMangaManager -import eu.kanade.tachiyomi.data.library.CustomMangaManager.Companion.toComicInfo import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.track.EnhancedTrackService import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.ui.migration.MigrationFlags +import eu.kanade.tachiyomi.util.system.launchNow import eu.kanade.tachiyomi.util.system.launchUI import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.cancel @@ -229,7 +230,9 @@ class MigrationProcessAdapter( } customMangaManager.getManga(prevManga)?.let { customManga -> customManga.id = manga.id!! - customMangaManager.saveMangaInfo(customManga.toComicInfo()) + launchNow { + customMangaManager.saveMangaInfo(customManga.getMangaInfo()) + } } } diff --git a/app/src/main/sqldelight/tachiyomi/data/custom_manga_info.sq b/app/src/main/sqldelight/tachiyomi/data/custom_manga_info.sq new file mode 100644 index 0000000000..2a7273a41f --- /dev/null +++ b/app/src/main/sqldelight/tachiyomi/data/custom_manga_info.sq @@ -0,0 +1,34 @@ +CREATE TABLE custom_manga_info ( + manga_id INTEGER NOT NULL PRIMARY KEY, + title TEXT, + author TEXT, + artist TEXT, + description TEXT, + genre TEXT, + status INTEGER, + UNIQUE (manga_id) ON CONFLICT REPLACE, + FOREIGN KEY(manga_id) REFERENCES mangas (_id) + ON DELETE CASCADE +); + +findAll: +SELECT * +FROM custom_manga_info; + +insert: +INSERT INTO custom_manga_info(manga_id, title, author, artist, description, genre, status) +VALUES (:manga_id, :title, :author, :artist, :description, :genre, :status) +ON CONFLICT (manga_id) +DO UPDATE +SET + title = :title, + author = :author, + artist = :artist, + description = :description, + genre = :genre, + status = :status +WHERE manga_id = :manga_id; + +delete: +DELETE FROM custom_manga_info +WHERE manga_id = :manga_id; diff --git a/app/src/main/sqldelight/tachiyomi/migrations/19.sqm b/app/src/main/sqldelight/tachiyomi/migrations/19.sqm new file mode 100644 index 0000000000..4535fd2757 --- /dev/null +++ b/app/src/main/sqldelight/tachiyomi/migrations/19.sqm @@ -0,0 +1,12 @@ +CREATE TABLE custom_manga_info ( + manga_id INTEGER NOT NULL PRIMARY KEY, + title TEXT, + author TEXT, + artist TEXT, + description TEXT, + genre TEXT, + status INTEGER, + UNIQUE (manga_id) ON CONFLICT REPLACE, + FOREIGN KEY(manga_id) REFERENCES mangas (_id) + ON DELETE CASCADE +);