diff --git a/app/src/main/java/eu/kanade/domain/category/model/Category.kt b/app/src/main/java/eu/kanade/domain/category/model/Category.kt index 296ac877e..d0818831c 100644 --- a/app/src/main/java/eu/kanade/domain/category/model/Category.kt +++ b/app/src/main/java/eu/kanade/domain/category/model/Category.kt @@ -1,6 +1,7 @@ package eu.kanade.domain.category.model import java.io.Serializable +import eu.kanade.tachiyomi.data.database.models.Category as DbCategory data class Category( val id: Long, @@ -8,3 +9,9 @@ data class Category( val order: Long, val flags: Long, ) : Serializable + +fun Category.toDbCategory(): DbCategory = DbCategory.create(name).also { + it.id = id.toInt() + it.order = order.toInt() + it.flags = flags.toInt() +} diff --git a/app/src/main/java/eu/kanade/domain/manga/interactor/GetDuplicateLibraryManga.kt b/app/src/main/java/eu/kanade/domain/manga/interactor/GetDuplicateLibraryManga.kt index 9a0b4a828..7193ed368 100644 --- a/app/src/main/java/eu/kanade/domain/manga/interactor/GetDuplicateLibraryManga.kt +++ b/app/src/main/java/eu/kanade/domain/manga/interactor/GetDuplicateLibraryManga.kt @@ -3,7 +3,10 @@ package eu.kanade.domain.manga.interactor import eu.kanade.domain.manga.model.Manga import eu.kanade.domain.manga.repository.MangaRepository -class GetDuplicateLibraryManga(private val mangaRepository: MangaRepository) { +class GetDuplicateLibraryManga( + private val mangaRepository: MangaRepository, +) { + suspend fun await(title: String, sourceId: Long): Manga? { return mangaRepository.getDuplicateLibraryManga(title.lowercase(), sourceId) } diff --git a/app/src/main/java/eu/kanade/domain/manga/interactor/ResetViewerFlags.kt b/app/src/main/java/eu/kanade/domain/manga/interactor/ResetViewerFlags.kt index 13b766af1..e28d10ef7 100644 --- a/app/src/main/java/eu/kanade/domain/manga/interactor/ResetViewerFlags.kt +++ b/app/src/main/java/eu/kanade/domain/manga/interactor/ResetViewerFlags.kt @@ -5,6 +5,7 @@ import eu.kanade.domain.manga.repository.MangaRepository class ResetViewerFlags( private val mangaRepository: MangaRepository, ) { + suspend fun await(): Boolean { return mangaRepository.resetViewerFlags() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceController.kt index 22f7049e8..b9b405718 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceController.kt @@ -20,6 +20,7 @@ import com.google.android.material.snackbar.Snackbar import dev.chrisbanes.insetter.applyInsetter import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.items.IFlexible +import eu.kanade.domain.category.model.toDbCategory import eu.kanade.domain.source.model.Source import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.Category @@ -627,42 +628,46 @@ open class BrowseSourceController(bundle: Bundle) : private fun addToLibrary(newManga: Manga, position: Int) { val activity = activity ?: return - val categories = presenter.getCategories() - val defaultCategoryId = preferences.defaultCategory() - val defaultCategory = categories.find { it.id == defaultCategoryId } + launchIO { + val categories = presenter.getCategories() + val defaultCategoryId = preferences.defaultCategory() + val defaultCategory = categories.find { it.id == defaultCategoryId.toLong() } - when { - // Default category set - defaultCategory != null -> { - presenter.moveMangaToCategory(newManga, defaultCategory) + withUIContext { + when { + // Default category set + defaultCategory != null -> { + presenter.moveMangaToCategory(newManga, defaultCategory.toDbCategory()) - presenter.changeMangaFavorite(newManga) - adapter?.notifyItemChanged(position) - activity.toast(activity.getString(R.string.manga_added_library)) - } - - // Automatic 'Default' or no categories - defaultCategoryId == 0 || categories.isEmpty() -> { - presenter.moveMangaToCategory(newManga, null) - - presenter.changeMangaFavorite(newManga) - adapter?.notifyItemChanged(position) - activity.toast(activity.getString(R.string.manga_added_library)) - } - - // Choose a category - else -> { - val ids = presenter.getMangaCategoryIds(newManga) - val preselected = categories.map { - if (it.id in ids) { - QuadStateTextView.State.CHECKED.ordinal - } else { - QuadStateTextView.State.UNCHECKED.ordinal + presenter.changeMangaFavorite(newManga) + adapter?.notifyItemChanged(position) + activity.toast(activity.getString(R.string.manga_added_library)) } - }.toTypedArray() - ChangeMangaCategoriesDialog(this, listOf(newManga), categories, preselected) - .showDialog(router) + // Automatic 'Default' or no categories + defaultCategoryId == 0 || categories.isEmpty() -> { + presenter.moveMangaToCategory(newManga, null) + + presenter.changeMangaFavorite(newManga) + adapter?.notifyItemChanged(position) + activity.toast(activity.getString(R.string.manga_added_library)) + } + + // Choose a category + else -> { + val ids = presenter.getMangaCategoryIds(newManga) + val preselected = categories.map { + if (it.id in ids) { + QuadStateTextView.State.CHECKED.ordinal + } else { + QuadStateTextView.State.UNCHECKED.ordinal + } + }.toTypedArray() + + ChangeMangaCategoriesDialog(this@BrowseSourceController, listOf(newManga), categories.map { it.toDbCategory() }, preselected) + .showDialog(router) + } + } } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt index 3e5d9d1e2..d087dcfbe 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt @@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.browse.source.browse import android.os.Bundle import eu.davidea.flexibleadapter.items.IFlexible +import eu.kanade.domain.category.interactor.GetCategories import eu.kanade.domain.manga.interactor.GetDuplicateLibraryManga import eu.kanade.domain.manga.model.toDbManga import eu.kanade.tachiyomi.data.cache.CoverCache @@ -45,6 +46,7 @@ import kotlinx.coroutines.flow.asFlow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import logcat.LogPriority @@ -54,6 +56,7 @@ import rx.schedulers.Schedulers import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import java.util.Date +import eu.kanade.domain.category.model.Category as DomainCategory open class BrowseSourcePresenter( private val sourceId: Long, @@ -63,6 +66,7 @@ open class BrowseSourcePresenter( private val prefs: PreferencesHelper = Injekt.get(), private val coverCache: CoverCache = Injekt.get(), private val getDuplicateLibraryManga: GetDuplicateLibraryManga = Injekt.get(), + private val getCategories: GetCategories = Injekt.get(), ) : BasePresenter() { /** @@ -347,8 +351,8 @@ open class BrowseSourcePresenter( * * @return List of categories, not including the default category */ - fun getCategories(): List { - return db.getCategories().executeAsBlocking() + suspend fun getCategories(): List { + return getCategories.subscribe().firstOrNull() ?: emptyList() } suspend fun getDuplicateLibraryManga(manga: Manga): Manga? { @@ -361,9 +365,9 @@ open class BrowseSourcePresenter( * @param manga the manga to get categories from. * @return Array of category ids the manga is in, if none returns default id */ - fun getMangaCategoryIds(manga: Manga): Array { + fun getMangaCategoryIds(manga: Manga): Array { val categories = db.getCategoriesForManga(manga).executeAsBlocking() - return categories.mapNotNull { it.id }.toTypedArray() + return categories.mapNotNull { it?.id?.toLong() }.toTypedArray() } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt index b8bd6b189..2426a50c7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt @@ -34,6 +34,7 @@ import dev.chrisbanes.insetter.applyInsetter import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.SelectableAdapter import eu.kanade.data.chapter.NoChaptersException +import eu.kanade.domain.category.model.toDbCategory import eu.kanade.domain.history.model.HistoryWithRelations import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.cache.CoverCache @@ -97,6 +98,7 @@ import eu.kanade.tachiyomi.widget.ActionModeWithToolbar import eu.kanade.tachiyomi.widget.materialdialogs.QuadStateTextView import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.runBlocking import logcat.LogPriority import reactivecircus.flowbinding.recyclerview.scrollStateChanges import reactivecircus.flowbinding.swiperefreshlayout.refreshes @@ -397,13 +399,16 @@ class MangaController : } override fun onPrepareOptionsMenu(menu: Menu) { - // Hide options for local manga - menu.findItem(R.id.action_share).isVisible = !isLocalSource - menu.findItem(R.id.download_group).isVisible = !isLocalSource + runBlocking { + // Hide options for local manga + menu.findItem(R.id.action_share).isVisible = !isLocalSource + menu.findItem(R.id.download_group).isVisible = !isLocalSource - // Hide options for non-library manga - menu.findItem(R.id.action_edit_categories).isVisible = presenter.manga.favorite && presenter.getCategories().isNotEmpty() - menu.findItem(R.id.action_migrate).isVisible = presenter.manga.favorite + // Hide options for non-library manga + menu.findItem(R.id.action_edit_categories).isVisible = + presenter.manga.favorite && presenter.getCategories().isNotEmpty() + menu.findItem(R.id.action_migrate).isVisible = presenter.manga.favorite + } } override fun onOptionsItemSelected(item: MenuItem): Boolean { @@ -533,39 +538,47 @@ class MangaController : } private fun addToLibrary(newManga: Manga) { - val categories = presenter.getCategories() - val defaultCategoryId = preferences.defaultCategory() - val defaultCategory = categories.find { it.id == defaultCategoryId } + launchIO { + val categories = presenter.getCategories() + val defaultCategoryId = preferences.defaultCategory() + val defaultCategory = categories.find { it.id == defaultCategoryId.toLong() } - when { - // Default category set - defaultCategory != null -> { - toggleFavorite() - presenter.moveMangaToCategory(newManga, defaultCategory) - activity?.toast(activity?.getString(R.string.manga_added_library)) - activity?.invalidateOptionsMenu() - } - - // Automatic 'Default' or no categories - defaultCategoryId == 0 || categories.isEmpty() -> { - toggleFavorite() - presenter.moveMangaToCategory(newManga, null) - activity?.toast(activity?.getString(R.string.manga_added_library)) - activity?.invalidateOptionsMenu() - } - - // Choose a category - else -> { - val ids = presenter.getMangaCategoryIds(newManga) - val preselected = categories.map { - if (it.id in ids) { - QuadStateTextView.State.CHECKED.ordinal - } else { - QuadStateTextView.State.UNCHECKED.ordinal + withUIContext { + when { + // Default category set + defaultCategory != null -> { + toggleFavorite() + presenter.moveMangaToCategory(newManga, defaultCategory.toDbCategory()) + activity?.toast(activity?.getString(R.string.manga_added_library)) + activity?.invalidateOptionsMenu() } - }.toTypedArray() - showChangeCategoryDialog(newManga, categories, preselected) + // Automatic 'Default' or no categories + defaultCategoryId == 0 || categories.isEmpty() -> { + toggleFavorite() + presenter.moveMangaToCategory(newManga, null) + activity?.toast(activity?.getString(R.string.manga_added_library)) + activity?.invalidateOptionsMenu() + } + + // Choose a category + else -> { + val ids = presenter.getMangaCategoryIds(newManga) + val preselected = categories.map { + if (it.id in ids) { + QuadStateTextView.State.CHECKED.ordinal + } else { + QuadStateTextView.State.UNCHECKED.ordinal + } + }.toTypedArray() + + showChangeCategoryDialog( + newManga, + categories.map { it.toDbCategory() }, + preselected, + ) + } + } } } @@ -609,18 +622,27 @@ class MangaController : } fun onCategoriesClick() { - val manga = presenter.manga - val categories = presenter.getCategories() + launchIO { + val manga = presenter.manga + val categories = presenter.getCategories() - val ids = presenter.getMangaCategoryIds(manga) - val preselected = categories.map { - if (it.id in ids) { - QuadStateTextView.State.CHECKED.ordinal - } else { - QuadStateTextView.State.UNCHECKED.ordinal + if (categories.isEmpty()) { + return@launchIO } - }.toTypedArray() - showChangeCategoryDialog(manga, categories, preselected) + + val ids = presenter.getMangaCategoryIds(manga) + val preselected = categories.map { + if (it.id in ids) { + QuadStateTextView.State.CHECKED.ordinal + } else { + QuadStateTextView.State.UNCHECKED.ordinal + } + }.toTypedArray() + + withUIContext { + showChangeCategoryDialog(manga, categories.map { it.toDbCategory() }, preselected) + } + } } private fun showChangeCategoryDialog(manga: Manga, categories: List, preselected: Array) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt index 31127a093..6119648ca 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt @@ -4,6 +4,7 @@ import android.content.Context import android.net.Uri import android.os.Bundle import com.jakewharton.rxrelay.PublishRelay +import eu.kanade.domain.category.interactor.GetCategories import eu.kanade.domain.chapter.interactor.GetChapterByMangaId import eu.kanade.domain.chapter.model.toDbChapter import eu.kanade.domain.manga.interactor.GetDuplicateLibraryManga @@ -51,6 +52,7 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.supervisorScope import logcat.LogPriority import rx.Observable @@ -61,6 +63,7 @@ import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy import java.util.Date +import eu.kanade.domain.category.model.Category as DomainCategory class MangaPresenter( val manga: Manga, @@ -72,6 +75,7 @@ class MangaPresenter( private val coverCache: CoverCache = Injekt.get(), private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(), private val getDuplicateLibraryManga: GetDuplicateLibraryManga = Injekt.get(), + private val getCategories: GetCategories = Injekt.get(), ) : BasePresenter() { /** @@ -255,8 +259,8 @@ class MangaPresenter( * * @return List of categories, not including the default category */ - fun getCategories(): List { - return db.getCategories().executeAsBlocking() + suspend fun getCategories(): List { + return getCategories.subscribe().firstOrNull() ?: emptyList() } /** @@ -265,9 +269,9 @@ class MangaPresenter( * @param manga the manga to get categories from. * @return Array of category ids the manga is in, if none returns default id */ - fun getMangaCategoryIds(manga: Manga): Array { + fun getMangaCategoryIds(manga: Manga): Array { val categories = db.getCategoriesForManga(manga).executeAsBlocking() - return categories.mapNotNull { it.id }.toTypedArray() + return categories.mapNotNull { it?.id?.toLong() }.toTypedArray() } /** @@ -654,14 +658,14 @@ class MangaPresenter( /** * Whether downloaded only mode is enabled. */ - fun forceDownloaded(): Boolean { + private fun forceDownloaded(): Boolean { return manga.favorite && preferences.downloadedOnly().get() } /** * Whether the display only downloaded filter is enabled. */ - fun onlyDownloaded(): State { + private fun onlyDownloaded(): State { if (forceDownloaded()) { return State.INCLUDE } @@ -675,7 +679,7 @@ class MangaPresenter( /** * Whether the display only downloaded filter is enabled. */ - fun onlyBookmarked(): State { + private fun onlyBookmarked(): State { return when (manga.bookmarkedFilter) { Manga.CHAPTER_SHOW_BOOKMARKED -> State.INCLUDE Manga.CHAPTER_SHOW_NOT_BOOKMARKED -> State.EXCLUDE @@ -686,7 +690,7 @@ class MangaPresenter( /** * Whether the display only unread filter is enabled. */ - fun onlyUnread(): State { + private fun onlyUnread(): State { return when (manga.readFilter) { Manga.CHAPTER_SHOW_UNREAD -> State.INCLUDE Manga.CHAPTER_SHOW_READ -> State.EXCLUDE diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoHeaderAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoHeaderAdapter.kt index 8b1fd2e5f..36a98a686 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoHeaderAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoHeaderAdapter.kt @@ -100,7 +100,7 @@ class MangaInfoHeaderAdapter( .onEach { controller.onFavoriteClick() } .launchIn(controller.viewScope) - if (controller.presenter.manga.favorite && controller.presenter.getCategories().isNotEmpty()) { + if (controller.presenter.manga.favorite) { binding.btnFavorite.longClicks() .onEach { controller.onCategoriesClick() } .launchIn(controller.viewScope)