diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/MangaBackupRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/MangaBackupRestorer.kt index c5877e4433..9963e264b6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/MangaBackupRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/MangaBackupRestorer.kt @@ -20,6 +20,7 @@ import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import yokai.data.DatabaseHandler import yokai.domain.category.interactor.GetCategories +import yokai.domain.category.interactor.SetMangaCategories import yokai.domain.chapter.interactor.GetChapter import yokai.domain.chapter.interactor.InsertChapter import yokai.domain.chapter.interactor.UpdateChapter @@ -36,6 +37,7 @@ class MangaBackupRestorer( private val customMangaManager: CustomMangaManager = Injekt.get(), private val handler: DatabaseHandler = Injekt.get(), private val getCategories: GetCategories = Injekt.get(), + private val setMangaCategories: SetMangaCategories = Injekt.get(), private val getChapter: GetChapter = Injekt.get(), private val insertChapter: InsertChapter = Injekt.get(), private val updateChapter: UpdateChapter = Injekt.get(), @@ -196,8 +198,7 @@ class MangaBackupRestorer( // Update database if (mangaCategoriesToUpdate.isNotEmpty()) { - db.deleteOldMangasCategories(listOf(manga)).executeAsBlocking() - db.insertMangasCategories(mangaCategoriesToUpdate).executeAsBlocking() + setMangaCategories.awaitAll(listOf(manga.id!!), mangaCategoriesToUpdate) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaCategoryQueries.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaCategoryQueries.kt index f7f91b660c..d0c021b09a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaCategoryQueries.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaCategoryQueries.kt @@ -10,11 +10,9 @@ import eu.kanade.tachiyomi.domain.manga.models.Manga interface MangaCategoryQueries : DbProvider { - fun insertMangaCategory(mangaCategory: MangaCategory) = db.put().`object`(mangaCategory).prepare() + private fun insertMangasCategories(mangasCategories: List) = db.put().objects(mangasCategories).prepare() - fun insertMangasCategories(mangasCategories: List) = db.put().objects(mangasCategories).prepare() - - fun deleteOldMangasCategories(mangas: List) = db.delete() + private fun deleteOldMangasCategories(mangas: List) = db.delete() .byQuery( DeleteQuery.builder() .table(MangaCategoryTable.TABLE) @@ -24,6 +22,7 @@ interface MangaCategoryQueries : DbProvider { ) .prepare() + // FIXME: Migrate to SQLDelight, on halt: in StorIO transaction fun setMangaCategories(mangasCategories: List, mangas: List) { db.inTransaction { deleteOldMangasCategories(mangas).executeAsBlocking() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/category/addtolibrary/SetCategoriesSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/category/addtolibrary/SetCategoriesSheet.kt index b81dc1573d..0dd4817054 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/category/addtolibrary/SetCategoriesSheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/category/addtolibrary/SetCategoriesSheet.kt @@ -28,16 +28,17 @@ import eu.kanade.tachiyomi.util.view.checkHeightThen import eu.kanade.tachiyomi.util.view.expand import eu.kanade.tachiyomi.widget.E2EBottomSheetDialog import eu.kanade.tachiyomi.widget.TriStateCheckBox -import uy.kohesive.injekt.injectLazy -import yokai.i18n.MR -import yokai.util.lang.getString -import java.util.* +import java.util.Date +import java.util.Locale import kotlin.math.max import kotlinx.coroutines.runBlocking +import uy.kohesive.injekt.injectLazy import yokai.domain.category.interactor.GetCategories -import yokai.domain.manga.interactor.InsertManga +import yokai.domain.category.interactor.SetMangaCategories import yokai.domain.manga.interactor.UpdateManga import yokai.domain.manga.models.MangaUpdate +import yokai.i18n.MR +import yokai.util.lang.getString class SetCategoriesSheet( private val activity: Activity, @@ -75,6 +76,7 @@ class SetCategoriesSheet( private val db: DatabaseHelper by injectLazy() private val getCategories: GetCategories by injectLazy() + private val setMangaCategories: SetMangaCategories by injectLazy() private val updateManga: UpdateManga by injectLazy() private val preferences: PreferencesHelper by injectLazy() @@ -300,7 +302,7 @@ class SetCategoriesSheet( Category.lastCategoriesAddedTo = addCategories.mapNotNull { it.id }.toSet().ifEmpty { setOf(0) } } - db.setMangaCategories(mangaCategories, listManga) + runBlocking { setMangaCategories.awaitAll(listManga.mapNotNull { it.id }, mangaCategories) } onMangaAdded() } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt index f142bd6b2b..9e639a8b88 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt @@ -8,7 +8,6 @@ import eu.kanade.tachiyomi.data.database.models.Category import eu.kanade.tachiyomi.data.database.models.Chapter import eu.kanade.tachiyomi.data.database.models.Chapter.Companion.copy import eu.kanade.tachiyomi.data.database.models.LibraryManga -import eu.kanade.tachiyomi.data.database.models.MangaCategory import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.database.models.removeCover import eu.kanade.tachiyomi.data.database.models.seriesType @@ -65,6 +64,7 @@ import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy import yokai.domain.category.interactor.GetCategories +import yokai.domain.category.interactor.SetMangaCategories import yokai.domain.category.interactor.UpdateCategories import yokai.domain.category.models.CategoryUpdate import yokai.domain.chapter.interactor.GetChapter @@ -93,6 +93,7 @@ class LibraryPresenter( private val trackManager: TrackManager = Injekt.get(), ) : BaseCoroutinePresenter(), DownloadQueue.DownloadListener { private val getCategories: GetCategories by injectLazy() + private val setMangaCategories: SetMangaCategories by injectLazy() private val updateCategories: UpdateCategories by injectLazy() private val getLibraryManga: GetLibraryManga by injectLazy() private val getChapter: GetChapter by injectLazy() @@ -1384,7 +1385,7 @@ class LibraryPresenter( val oldCatId = manga.category manga.category = categoryId - val mc = ArrayList() + val mc = ArrayList() val categories = if (catId == 0) { emptyList() @@ -1394,10 +1395,10 @@ class LibraryPresenter( } for (cat in categories) { - mc.add(MangaCategory.create(manga, cat)) + mc.add(cat.id!!.toLong()) } - db.setMangaCategories(mc, listOf(manga)) + setMangaCategories.await(manga.id!!, mc) if (category.mangaSort == null) { val ids = mangaIds.toMutableList() diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/MangaExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/MangaExtensions.kt index 06c6e074a9..2c12b3e4b0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/MangaExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/MangaExtensions.kt @@ -12,7 +12,6 @@ import com.google.android.material.snackbar.BaseTransientBottomBar import com.google.android.material.snackbar.Snackbar import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.models.Category -import eu.kanade.tachiyomi.data.database.models.MangaCategory import eu.kanade.tachiyomi.data.database.models.seriesType import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.track.EnhancedTrackService @@ -47,6 +46,7 @@ import kotlinx.coroutines.runBlocking import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import yokai.domain.category.interactor.GetCategories +import yokai.domain.category.interactor.SetMangaCategories import yokai.domain.chapter.interactor.GetChapter import yokai.domain.manga.interactor.GetManga import yokai.domain.manga.interactor.UpdateManga @@ -158,6 +158,7 @@ fun Manga.addOrRemoveToFavorites( onMangaMoved: () -> Unit, onMangaDeleted: () -> Unit, getCategories: GetCategories = Injekt.get(), + setMangaCategories: SetMangaCategories = Injekt.get(), getManga: GetManga = Injekt.get(), updateManga: UpdateManga = Injekt.get(), ): Snackbar? { @@ -220,9 +221,8 @@ fun Manga.addOrRemoveToFavorites( dateAdded = this@addOrRemoveToFavorites.date_added, ) ) + setMangaCategories.await(this@addOrRemoveToFavorites.id!!, listOf(defaultCategory.id!!.toLong())) } - val mc = MangaCategory.create(this, defaultCategory) - db.setMangaCategories(listOf(mc), listOf(this)) (activity as? MainActivity)?.showNotificationPermissionPrompt() onMangaMoved() return view.snack(activity.getString(MR.strings.added_to_, defaultCategory.name)) { @@ -247,11 +247,8 @@ fun Manga.addOrRemoveToFavorites( dateAdded = this@addOrRemoveToFavorites.date_added, ) ) + setMangaCategories.await(this@addOrRemoveToFavorites.id!!, lastUsedCategories.map { it.id!!.toLong() }) } - db.setMangaCategories( - lastUsedCategories.map { MangaCategory.create(this, it) }, - listOf(this), - ) (activity as? MainActivity)?.showNotificationPermissionPrompt() onMangaMoved() return view.snack( @@ -286,8 +283,8 @@ fun Manga.addOrRemoveToFavorites( dateAdded = this@addOrRemoveToFavorites.date_added, ) ) + setMangaCategories.await(this@addOrRemoveToFavorites.id!!, emptyList()) } - db.setMangaCategories(emptyList(), listOf(this)) onMangaMoved() (activity as? MainActivity)?.showNotificationPermissionPrompt() return if (categories.isNotEmpty()) { diff --git a/app/src/main/java/yokai/core/di/DomainModule.kt b/app/src/main/java/yokai/core/di/DomainModule.kt index d54f9d3b89..31e98fc4fa 100644 --- a/app/src/main/java/yokai/core/di/DomainModule.kt +++ b/app/src/main/java/yokai/core/di/DomainModule.kt @@ -12,6 +12,7 @@ import yokai.domain.category.CategoryRepository import yokai.domain.category.interactor.DeleteCategories import yokai.domain.category.interactor.GetCategories import yokai.domain.category.interactor.InsertCategories +import yokai.domain.category.interactor.SetMangaCategories import yokai.domain.category.interactor.UpdateCategories import yokai.domain.chapter.ChapterRepository import yokai.domain.chapter.interactor.DeleteChapter @@ -75,6 +76,8 @@ fun domainModule() = module { factory { InsertManga(get()) } factory { UpdateManga(get()) } + factory { SetMangaCategories(get()) } + single { ChapterRepositoryImpl(get()) } factory { DeleteChapter(get()) } factory { GetAvailableScanlators(get()) } diff --git a/app/src/main/java/yokai/data/manga/MangaRepositoryImpl.kt b/app/src/main/java/yokai/data/manga/MangaRepositoryImpl.kt index ef598d39c0..41ea95a04a 100644 --- a/app/src/main/java/yokai/data/manga/MangaRepositoryImpl.kt +++ b/app/src/main/java/yokai/data/manga/MangaRepositoryImpl.kt @@ -2,6 +2,7 @@ package yokai.data.manga import co.touchlab.kermit.Logger import eu.kanade.tachiyomi.data.database.models.LibraryManga +import eu.kanade.tachiyomi.data.database.models.MangaCategory import eu.kanade.tachiyomi.data.database.models.mapper import eu.kanade.tachiyomi.domain.manga.models.Manga import kotlinx.coroutines.flow.Flow @@ -112,4 +113,20 @@ class MangaRepositoryImpl(private val handler: DatabaseHandler) : MangaRepositor ) mangasQueries.selectLastInsertedRowId() } + + override suspend fun setCategories(mangaId: Long, categoryIds: List) = + handler.await(inTransaction = true) { + mangas_categoriesQueries.delete(mangaId) + categoryIds.forEach { id -> + mangas_categoriesQueries.insert(mangaId, id) + } + } + + override suspend fun setMultipleMangaCategories(mangaIds: List, mangaCategories: List) = + handler.await(inTransaction = true) { + mangas_categoriesQueries.deleteBulk(mangaIds) + mangaCategories.forEach { + mangas_categoriesQueries.insert(it.manga_id, it.category_id.toLong()) + } + } } diff --git a/app/src/main/java/yokai/domain/category/interactor/SetMangaCategories.kt b/app/src/main/java/yokai/domain/category/interactor/SetMangaCategories.kt new file mode 100644 index 0000000000..553afa9ca0 --- /dev/null +++ b/app/src/main/java/yokai/domain/category/interactor/SetMangaCategories.kt @@ -0,0 +1,12 @@ +package yokai.domain.category.interactor + +import eu.kanade.tachiyomi.data.database.models.MangaCategory +import yokai.domain.manga.MangaRepository + +class SetMangaCategories( + private val mangaRepository: MangaRepository, +) { + suspend fun await(mangaId: Long, categories: List) = mangaRepository.setCategories(mangaId, categories) + suspend fun awaitAll(mangaIds: List, mangaCategories: List) = + mangaRepository.setMultipleMangaCategories(mangaIds, mangaCategories) +} diff --git a/app/src/main/java/yokai/domain/manga/MangaRepository.kt b/app/src/main/java/yokai/domain/manga/MangaRepository.kt index 7d86f341b4..eda4861a13 100644 --- a/app/src/main/java/yokai/domain/manga/MangaRepository.kt +++ b/app/src/main/java/yokai/domain/manga/MangaRepository.kt @@ -1,6 +1,7 @@ package yokai.domain.manga import eu.kanade.tachiyomi.data.database.models.LibraryManga +import eu.kanade.tachiyomi.data.database.models.MangaCategory import eu.kanade.tachiyomi.domain.manga.models.Manga import kotlinx.coroutines.flow.Flow import yokai.domain.manga.models.MangaUpdate @@ -18,4 +19,6 @@ interface MangaRepository { suspend fun update(update: MangaUpdate): Boolean suspend fun updateAll(updates: List): Boolean suspend fun insert(manga: Manga): Long? + suspend fun setCategories(mangaId: Long, categoryIds: List) + suspend fun setMultipleMangaCategories(mangaIds: List, mangaCategories: List) } diff --git a/data/src/commonMain/sqldelight/tachiyomi/data/mangas_categories.sq b/data/src/commonMain/sqldelight/tachiyomi/data/mangas_categories.sq index 2984135757..889a109f9d 100644 --- a/data/src/commonMain/sqldelight/tachiyomi/data/mangas_categories.sq +++ b/data/src/commonMain/sqldelight/tachiyomi/data/mangas_categories.sq @@ -7,3 +7,15 @@ CREATE TABLE mangas_categories( FOREIGN KEY(manga_id) REFERENCES mangas (_id) ON DELETE CASCADE ); + +delete: +DELETE FROM mangas_categories +WHERE manga_id = :mangaId; + +deleteBulk: +DELETE FROM mangas_categories +WHERE manga_id IN :mangaIds; + +insert: +INSERT INTO mangas_categories(manga_id, category_id) +VALUES (:mangaId, :categoryId);