mirror of
https://github.com/null2264/yokai.git
synced 2025-06-21 10:44:42 +00:00
refactor: Use DB instead of file to store custom manga info
This commit is contained in:
parent
716cc1fac8
commit
87b8430089
16 changed files with 354 additions and 61 deletions
|
@ -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
|
||||
|
|
|
@ -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<ExtensionRepoRepository> { 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<CustomMangaRepository> { CustomMangaRepositoryImpl(get()) }
|
||||
addFactory { CreateCustomManga(get()) }
|
||||
addFactory { DeleteCustomManga(get()) }
|
||||
addFactory { GetCustomManga(get()) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<List<CustomMangaInfo>> =
|
||||
handler.subscribeToList { custom_manga_infoQueries.findAll(::mapCustomMangaInfo) }
|
||||
|
||||
override suspend fun getAll(): List<CustomMangaInfo> =
|
||||
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<CustomMangaInfo>) {
|
||||
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<Long>) =
|
||||
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())
|
||||
}
|
|
@ -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<List<CustomMangaInfo>>
|
||||
suspend fun getAll(): List<CustomMangaInfo>
|
||||
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<CustomMangaInfo>)
|
||||
suspend fun deleteCustomManga(mangaId: Long)
|
||||
suspend fun deleteBulkCustomManga(mangaIds: List<Long>)
|
||||
}
|
|
@ -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)
|
|
@ -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<CustomMangaInfo>): 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
|
||||
}
|
||||
}
|
|
@ -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<Long>) = customMangaRepository.deleteBulkCustomManga(mangaIds)
|
||||
}
|
|
@ -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()
|
||||
}
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
|
@ -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<Track>,
|
||||
backupCategories: List<BackupCategory>,
|
||||
filteredScanlators: List<String>,
|
||||
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<Track>,
|
||||
backupCategories: List<BackupCategory>,
|
||||
filteredScanlators: List<String>,
|
||||
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<Track>,
|
||||
backupCategories: List<BackupCategory>,
|
||||
filteredScanlators: List<String>,
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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<Long>()
|
||||
private var customMangaMap = mutableMapOf<Long, Manga>()
|
||||
|
||||
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<ComicList>(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<MangaList>(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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
34
app/src/main/sqldelight/tachiyomi/data/custom_manga_info.sq
Normal file
34
app/src/main/sqldelight/tachiyomi/data/custom_manga_info.sq
Normal file
|
@ -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;
|
12
app/src/main/sqldelight/tachiyomi/migrations/19.sqm
Normal file
12
app/src/main/sqldelight/tachiyomi/migrations/19.sqm
Normal file
|
@ -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
|
||||
);
|
Loading…
Add table
Add a link
Reference in a new issue