Migrate some categories SQL calls to SQLDelight

This commit is contained in:
arkon 2022-06-19 16:38:42 -04:00
parent 005b9b595c
commit a7decdb62d
8 changed files with 138 additions and 92 deletions

View file

@ -1,6 +1,7 @@
package eu.kanade.domain.category.model package eu.kanade.domain.category.model
import java.io.Serializable import java.io.Serializable
import eu.kanade.tachiyomi.data.database.models.Category as DbCategory
data class Category( data class Category(
val id: Long, val id: Long,
@ -8,3 +9,9 @@ data class Category(
val order: Long, val order: Long,
val flags: Long, val flags: Long,
) : Serializable ) : Serializable
fun Category.toDbCategory(): DbCategory = DbCategory.create(name).also {
it.id = id.toInt()
it.order = order.toInt()
it.flags = flags.toInt()
}

View file

@ -3,7 +3,10 @@ package eu.kanade.domain.manga.interactor
import eu.kanade.domain.manga.model.Manga import eu.kanade.domain.manga.model.Manga
import eu.kanade.domain.manga.repository.MangaRepository 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? { suspend fun await(title: String, sourceId: Long): Manga? {
return mangaRepository.getDuplicateLibraryManga(title.lowercase(), sourceId) return mangaRepository.getDuplicateLibraryManga(title.lowercase(), sourceId)
} }

View file

@ -5,6 +5,7 @@ import eu.kanade.domain.manga.repository.MangaRepository
class ResetViewerFlags( class ResetViewerFlags(
private val mangaRepository: MangaRepository, private val mangaRepository: MangaRepository,
) { ) {
suspend fun await(): Boolean { suspend fun await(): Boolean {
return mangaRepository.resetViewerFlags() return mangaRepository.resetViewerFlags()
} }

View file

@ -20,6 +20,7 @@ import com.google.android.material.snackbar.Snackbar
import dev.chrisbanes.insetter.applyInsetter import dev.chrisbanes.insetter.applyInsetter
import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.items.IFlexible import eu.davidea.flexibleadapter.items.IFlexible
import eu.kanade.domain.category.model.toDbCategory
import eu.kanade.domain.source.model.Source import eu.kanade.domain.source.model.Source
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Category import eu.kanade.tachiyomi.data.database.models.Category
@ -627,42 +628,46 @@ open class BrowseSourceController(bundle: Bundle) :
private fun addToLibrary(newManga: Manga, position: Int) { private fun addToLibrary(newManga: Manga, position: Int) {
val activity = activity ?: return val activity = activity ?: return
val categories = presenter.getCategories() launchIO {
val defaultCategoryId = preferences.defaultCategory() val categories = presenter.getCategories()
val defaultCategory = categories.find { it.id == defaultCategoryId } val defaultCategoryId = preferences.defaultCategory()
val defaultCategory = categories.find { it.id == defaultCategoryId.toLong() }
when { withUIContext {
// Default category set when {
defaultCategory != null -> { // Default category set
presenter.moveMangaToCategory(newManga, defaultCategory) defaultCategory != null -> {
presenter.moveMangaToCategory(newManga, defaultCategory.toDbCategory())
presenter.changeMangaFavorite(newManga) presenter.changeMangaFavorite(newManga)
adapter?.notifyItemChanged(position) adapter?.notifyItemChanged(position)
activity.toast(activity.getString(R.string.manga_added_library)) 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
} }
}.toTypedArray()
ChangeMangaCategoriesDialog(this, listOf(newManga), categories, preselected) // Automatic 'Default' or no categories
.showDialog(router) 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)
}
}
} }
} }
} }

View file

@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.browse.source.browse
import android.os.Bundle import android.os.Bundle
import eu.davidea.flexibleadapter.items.IFlexible 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.interactor.GetDuplicateLibraryManga
import eu.kanade.domain.manga.model.toDbManga import eu.kanade.domain.manga.model.toDbManga
import eu.kanade.tachiyomi.data.cache.CoverCache 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.catch
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import logcat.LogPriority import logcat.LogPriority
@ -54,6 +56,7 @@ import rx.schedulers.Schedulers
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.util.Date import java.util.Date
import eu.kanade.domain.category.model.Category as DomainCategory
open class BrowseSourcePresenter( open class BrowseSourcePresenter(
private val sourceId: Long, private val sourceId: Long,
@ -63,6 +66,7 @@ open class BrowseSourcePresenter(
private val prefs: PreferencesHelper = Injekt.get(), private val prefs: PreferencesHelper = Injekt.get(),
private val coverCache: CoverCache = Injekt.get(), private val coverCache: CoverCache = Injekt.get(),
private val getDuplicateLibraryManga: GetDuplicateLibraryManga = Injekt.get(), private val getDuplicateLibraryManga: GetDuplicateLibraryManga = Injekt.get(),
private val getCategories: GetCategories = Injekt.get(),
) : BasePresenter<BrowseSourceController>() { ) : BasePresenter<BrowseSourceController>() {
/** /**
@ -347,8 +351,8 @@ open class BrowseSourcePresenter(
* *
* @return List of categories, not including the default category * @return List of categories, not including the default category
*/ */
fun getCategories(): List<Category> { suspend fun getCategories(): List<DomainCategory> {
return db.getCategories().executeAsBlocking() return getCategories.subscribe().firstOrNull() ?: emptyList()
} }
suspend fun getDuplicateLibraryManga(manga: Manga): Manga? { suspend fun getDuplicateLibraryManga(manga: Manga): Manga? {
@ -361,9 +365,9 @@ open class BrowseSourcePresenter(
* @param manga the manga to get categories from. * @param manga the manga to get categories from.
* @return Array of category ids the manga is in, if none returns default id * @return Array of category ids the manga is in, if none returns default id
*/ */
fun getMangaCategoryIds(manga: Manga): Array<Int?> { fun getMangaCategoryIds(manga: Manga): Array<Long?> {
val categories = db.getCategoriesForManga(manga).executeAsBlocking() val categories = db.getCategoriesForManga(manga).executeAsBlocking()
return categories.mapNotNull { it.id }.toTypedArray() return categories.mapNotNull { it?.id?.toLong() }.toTypedArray()
} }
/** /**

View file

@ -34,6 +34,7 @@ import dev.chrisbanes.insetter.applyInsetter
import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.SelectableAdapter import eu.davidea.flexibleadapter.SelectableAdapter
import eu.kanade.data.chapter.NoChaptersException import eu.kanade.data.chapter.NoChaptersException
import eu.kanade.domain.category.model.toDbCategory
import eu.kanade.domain.history.model.HistoryWithRelations import eu.kanade.domain.history.model.HistoryWithRelations
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.cache.CoverCache 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 eu.kanade.tachiyomi.widget.materialdialogs.QuadStateTextView
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.runBlocking
import logcat.LogPriority import logcat.LogPriority
import reactivecircus.flowbinding.recyclerview.scrollStateChanges import reactivecircus.flowbinding.recyclerview.scrollStateChanges
import reactivecircus.flowbinding.swiperefreshlayout.refreshes import reactivecircus.flowbinding.swiperefreshlayout.refreshes
@ -397,13 +399,16 @@ class MangaController :
} }
override fun onPrepareOptionsMenu(menu: Menu) { override fun onPrepareOptionsMenu(menu: Menu) {
// Hide options for local manga runBlocking {
menu.findItem(R.id.action_share).isVisible = !isLocalSource // Hide options for local manga
menu.findItem(R.id.download_group).isVisible = !isLocalSource menu.findItem(R.id.action_share).isVisible = !isLocalSource
menu.findItem(R.id.download_group).isVisible = !isLocalSource
// Hide options for non-library manga // 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_edit_categories).isVisible =
menu.findItem(R.id.action_migrate).isVisible = presenter.manga.favorite presenter.manga.favorite && presenter.getCategories().isNotEmpty()
menu.findItem(R.id.action_migrate).isVisible = presenter.manga.favorite
}
} }
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
@ -533,39 +538,47 @@ class MangaController :
} }
private fun addToLibrary(newManga: Manga) { private fun addToLibrary(newManga: Manga) {
val categories = presenter.getCategories() launchIO {
val defaultCategoryId = preferences.defaultCategory() val categories = presenter.getCategories()
val defaultCategory = categories.find { it.id == defaultCategoryId } val defaultCategoryId = preferences.defaultCategory()
val defaultCategory = categories.find { it.id == defaultCategoryId.toLong() }
when { withUIContext {
// Default category set when {
defaultCategory != null -> { // Default category set
toggleFavorite() defaultCategory != null -> {
presenter.moveMangaToCategory(newManga, defaultCategory) toggleFavorite()
activity?.toast(activity?.getString(R.string.manga_added_library)) presenter.moveMangaToCategory(newManga, defaultCategory.toDbCategory())
activity?.invalidateOptionsMenu() 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
} }
}.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() { fun onCategoriesClick() {
val manga = presenter.manga launchIO {
val categories = presenter.getCategories() val manga = presenter.manga
val categories = presenter.getCategories()
val ids = presenter.getMangaCategoryIds(manga) if (categories.isEmpty()) {
val preselected = categories.map { return@launchIO
if (it.id in ids) {
QuadStateTextView.State.CHECKED.ordinal
} else {
QuadStateTextView.State.UNCHECKED.ordinal
} }
}.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<Category>, preselected: Array<Int>) { private fun showChangeCategoryDialog(manga: Manga, categories: List<Category>, preselected: Array<Int>) {

View file

@ -4,6 +4,7 @@ import android.content.Context
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import com.jakewharton.rxrelay.PublishRelay import com.jakewharton.rxrelay.PublishRelay
import eu.kanade.domain.category.interactor.GetCategories
import eu.kanade.domain.chapter.interactor.GetChapterByMangaId import eu.kanade.domain.chapter.interactor.GetChapterByMangaId
import eu.kanade.domain.chapter.model.toDbChapter import eu.kanade.domain.chapter.model.toDbChapter
import eu.kanade.domain.manga.interactor.GetDuplicateLibraryManga import eu.kanade.domain.manga.interactor.GetDuplicateLibraryManga
@ -51,6 +52,7 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.supervisorScope import kotlinx.coroutines.supervisorScope
import logcat.LogPriority import logcat.LogPriority
import rx.Observable import rx.Observable
@ -61,6 +63,7 @@ import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.util.Date import java.util.Date
import eu.kanade.domain.category.model.Category as DomainCategory
class MangaPresenter( class MangaPresenter(
val manga: Manga, val manga: Manga,
@ -72,6 +75,7 @@ class MangaPresenter(
private val coverCache: CoverCache = Injekt.get(), private val coverCache: CoverCache = Injekt.get(),
private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(), private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(),
private val getDuplicateLibraryManga: GetDuplicateLibraryManga = Injekt.get(), private val getDuplicateLibraryManga: GetDuplicateLibraryManga = Injekt.get(),
private val getCategories: GetCategories = Injekt.get(),
) : BasePresenter<MangaController>() { ) : BasePresenter<MangaController>() {
/** /**
@ -255,8 +259,8 @@ class MangaPresenter(
* *
* @return List of categories, not including the default category * @return List of categories, not including the default category
*/ */
fun getCategories(): List<Category> { suspend fun getCategories(): List<DomainCategory> {
return db.getCategories().executeAsBlocking() return getCategories.subscribe().firstOrNull() ?: emptyList()
} }
/** /**
@ -265,9 +269,9 @@ class MangaPresenter(
* @param manga the manga to get categories from. * @param manga the manga to get categories from.
* @return Array of category ids the manga is in, if none returns default id * @return Array of category ids the manga is in, if none returns default id
*/ */
fun getMangaCategoryIds(manga: Manga): Array<Int> { fun getMangaCategoryIds(manga: Manga): Array<Long> {
val categories = db.getCategoriesForManga(manga).executeAsBlocking() 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. * Whether downloaded only mode is enabled.
*/ */
fun forceDownloaded(): Boolean { private fun forceDownloaded(): Boolean {
return manga.favorite && preferences.downloadedOnly().get() return manga.favorite && preferences.downloadedOnly().get()
} }
/** /**
* Whether the display only downloaded filter is enabled. * Whether the display only downloaded filter is enabled.
*/ */
fun onlyDownloaded(): State { private fun onlyDownloaded(): State {
if (forceDownloaded()) { if (forceDownloaded()) {
return State.INCLUDE return State.INCLUDE
} }
@ -675,7 +679,7 @@ class MangaPresenter(
/** /**
* Whether the display only downloaded filter is enabled. * Whether the display only downloaded filter is enabled.
*/ */
fun onlyBookmarked(): State { private fun onlyBookmarked(): State {
return when (manga.bookmarkedFilter) { return when (manga.bookmarkedFilter) {
Manga.CHAPTER_SHOW_BOOKMARKED -> State.INCLUDE Manga.CHAPTER_SHOW_BOOKMARKED -> State.INCLUDE
Manga.CHAPTER_SHOW_NOT_BOOKMARKED -> State.EXCLUDE Manga.CHAPTER_SHOW_NOT_BOOKMARKED -> State.EXCLUDE
@ -686,7 +690,7 @@ class MangaPresenter(
/** /**
* Whether the display only unread filter is enabled. * Whether the display only unread filter is enabled.
*/ */
fun onlyUnread(): State { private fun onlyUnread(): State {
return when (manga.readFilter) { return when (manga.readFilter) {
Manga.CHAPTER_SHOW_UNREAD -> State.INCLUDE Manga.CHAPTER_SHOW_UNREAD -> State.INCLUDE
Manga.CHAPTER_SHOW_READ -> State.EXCLUDE Manga.CHAPTER_SHOW_READ -> State.EXCLUDE

View file

@ -100,7 +100,7 @@ class MangaInfoHeaderAdapter(
.onEach { controller.onFavoriteClick() } .onEach { controller.onFavoriteClick() }
.launchIn(controller.viewScope) .launchIn(controller.viewScope)
if (controller.presenter.manga.favorite && controller.presenter.getCategories().isNotEmpty()) { if (controller.presenter.manga.favorite) {
binding.btnFavorite.longClicks() binding.btnFavorite.longClicks()
.onEach { controller.onCategoriesClick() } .onEach { controller.onCategoriesClick() }
.launchIn(controller.viewScope) .launchIn(controller.viewScope)