refactor(manga): Removing runBlocking

This commit is contained in:
Ahmad Ansori Palembani 2024-12-08 07:53:06 +07:00
parent f114320123
commit 2f8ae26a83
Signed by: null2264
GPG key ID: BA64F8B60AF3EFB6
5 changed files with 233 additions and 209 deletions

View file

@ -101,6 +101,7 @@ import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.system.getResourceDrawable
import eu.kanade.tachiyomi.util.system.ignoredSystemInsets
import eu.kanade.tachiyomi.util.system.isImeVisible
import eu.kanade.tachiyomi.util.system.launchIO
import eu.kanade.tachiyomi.util.system.launchUI
import eu.kanade.tachiyomi.util.system.materialAlertDialog
import eu.kanade.tachiyomi.util.system.openInBrowser
@ -128,7 +129,7 @@ import eu.kanade.tachiyomi.util.view.snack
import eu.kanade.tachiyomi.util.view.text
import eu.kanade.tachiyomi.util.view.withFadeTransaction
import eu.kanade.tachiyomi.widget.EmptyView
import java.util.*
import java.util.Locale
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.roundToInt
@ -2191,11 +2192,13 @@ open class LibraryController(
*/
private fun showChangeMangaCategoriesSheet() {
val activity = activity ?: return
viewScope.launchIO {
selectedMangas.toList().moveCategories(activity) {
presenter.getLibrary()
destroyActionModeIfNeeded()
}
}
}
fun updateDownloadStatus(isRunning: Boolean) {
(activity as? MainActivity)?.downloadStatusChanged(isRunning)

View file

@ -111,12 +111,14 @@ import eu.kanade.tachiyomi.util.system.isLandscape
import eu.kanade.tachiyomi.util.system.isOnline
import eu.kanade.tachiyomi.util.system.isPromptChecked
import eu.kanade.tachiyomi.util.system.isTablet
import eu.kanade.tachiyomi.util.system.launchIO
import eu.kanade.tachiyomi.util.system.launchUI
import eu.kanade.tachiyomi.util.system.materialAlertDialog
import eu.kanade.tachiyomi.util.system.rootWindowInsetsCompat
import eu.kanade.tachiyomi.util.system.setCustomTitleAndMessage
import eu.kanade.tachiyomi.util.system.timeSpanFromNow
import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.util.system.withUIContext
import eu.kanade.tachiyomi.util.view.activityBinding
import eu.kanade.tachiyomi.util.view.copyToClipboard
import eu.kanade.tachiyomi.util.view.findChild
@ -1633,6 +1635,7 @@ class MangaDetailsController :
private fun showCategoriesSheet() {
val adding = !presenter.manga.favorite
viewScope.launchIO {
presenter.manga.moveCategories(activity!!, adding) {
updateHeader()
if (adding) {
@ -1640,17 +1643,19 @@ class MangaDetailsController :
}
}
}
}
private fun toggleMangaFavorite() {
val view = view ?: return
val activity = activity ?: return
snack?.dismiss()
viewScope.launchIO {
withUIContext { snack?.dismiss() }
snack = presenter.manga.addOrRemoveToFavorites(
presenter.preferences,
view,
activity,
presenter.sourceManager,
this,
this@MangaDetailsController,
onMangaAdded = { migrationInfo ->
migrationInfo?.let {
presenter.fetchChapters(andTracking = true)
@ -1666,12 +1671,16 @@ class MangaDetailsController :
updateHeader()
presenter.confirmDeletion()
},
scope = viewScope,
)
if (snack?.duration == Snackbar.LENGTH_INDEFINITE) {
withUIContext {
val favButton = getHeader()?.binding?.favoriteButton
(activity as? MainActivity)?.setUndoSnackBar(snack, favButton)
}
}
}
}
private fun showAddedSnack() {
val view = view ?: return

View file

@ -43,8 +43,10 @@ import eu.kanade.tachiyomi.util.addOrRemoveToFavorites
import eu.kanade.tachiyomi.util.system.connectivityManager
import eu.kanade.tachiyomi.util.system.dpToPx
import eu.kanade.tachiyomi.util.system.e
import eu.kanade.tachiyomi.util.system.launchIO
import eu.kanade.tachiyomi.util.system.openInBrowser
import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.util.system.withUIContext
import eu.kanade.tachiyomi.util.view.activityBinding
import eu.kanade.tachiyomi.util.view.applyBottomAnimatedInsets
import eu.kanade.tachiyomi.util.view.fullAppBarHeight
@ -766,24 +768,29 @@ open class BrowseSourceController(bundle: Bundle) :
val manga = (adapter?.getItem(position) as? BrowseSourceItem?)?.manga ?: return
val view = view ?: return
val activity = activity ?: return
snack?.dismiss()
viewScope.launchIO {
withUIContext { snack?.dismiss() }
snack = manga.addOrRemoveToFavorites(
preferences,
view,
activity,
presenter.sourceManager,
this,
this@BrowseSourceController,
onMangaAdded = {
adapter?.notifyItemChanged(position)
snack = view.snack(MR.strings.added_to_library)
},
onMangaMoved = { adapter?.notifyItemChanged(position) },
onMangaDeleted = { presenter.confirmDeletion(manga) },
scope = viewScope,
)
if (snack?.duration == Snackbar.LENGTH_INDEFINITE) {
withUIContext {
(activity as? MainActivity)?.setUndoSnackBar(snack)
}
}
}
}
companion object {
const val SOURCE_ID_KEY = "sourceId"

View file

@ -24,7 +24,9 @@ import eu.kanade.tachiyomi.ui.manga.MangaDetailsController
import eu.kanade.tachiyomi.ui.source.browse.BrowseSourceController
import eu.kanade.tachiyomi.util.addOrRemoveToFavorites
import eu.kanade.tachiyomi.util.system.extensionIntentForText
import eu.kanade.tachiyomi.util.system.launchIO
import eu.kanade.tachiyomi.util.system.rootWindowInsetsCompat
import eu.kanade.tachiyomi.util.system.withUIContext
import eu.kanade.tachiyomi.util.view.activityBinding
import eu.kanade.tachiyomi.util.view.isControllerVisible
import eu.kanade.tachiyomi.util.view.scrollViewWith
@ -114,18 +116,19 @@ open class GlobalSearchController(
val view = view ?: return
val activity = activity ?: return
snack?.dismiss()
viewScope.launchIO {
withUIContext { snack?.dismiss() }
snack = manga.addOrRemoveToFavorites(
preferences,
view,
activity,
presenter.sourceManager,
this,
this@GlobalSearchController,
onMangaAdded = { migrationInfo ->
migrationInfo?.let { (source, stillFaved) ->
val index = this.adapter
val index = this@GlobalSearchController.adapter
?.currentItems?.indexOfFirst { it.source.id == source } ?: return@let
val item = this.adapter?.getItem(index) ?: return@let
val item = this@GlobalSearchController.adapter?.getItem(index) ?: return@let
val oldMangaIndex = item.results?.indexOfFirst {
it.manga.title.lowercase() == manga.title.lowercase()
} ?: return@let
@ -139,11 +142,15 @@ open class GlobalSearchController(
},
onMangaMoved = { adapter.notifyItemChanged(position) },
onMangaDeleted = { presenter.confirmDeletion(manga) },
scope = viewScope,
)
if (snack?.duration == Snackbar.LENGTH_INDEFINITE) {
withUIContext {
(activity as? MainActivity)?.setUndoSnackBar(snack)
}
}
}
}
override fun showFloatingBar() =
activity !is SearchActivity ||

View file

@ -41,8 +41,9 @@ import eu.kanade.tachiyomi.util.view.withFadeTransaction
import eu.kanade.tachiyomi.widget.TriStateCheckBox
import java.util.Date
import java.util.Locale
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import yokai.domain.category.interactor.GetCategories
@ -84,26 +85,23 @@ suspend fun Manga.shouldDownloadNewChapters(prefs: PreferencesHelper, getCategor
return categoriesForManga.any { it in includedCategories }
}
fun Manga.moveCategories(activity: Activity, onMangaMoved: () -> Unit) {
suspend fun Manga.moveCategories(activity: Activity, onMangaMoved: () -> Unit) {
moveCategories(activity, false, onMangaMoved)
}
fun Manga.moveCategories(
suspend fun Manga.moveCategories(
activity: Activity,
addingToLibrary: Boolean,
onMangaMoved: () -> Unit,
) {
val getCategories: GetCategories = Injekt.get()
// FIXME: Don't do blocking
val categories = runBlocking { getCategories.await() }
val categoriesForManga = runBlocking {
this@moveCategories.id?.let { mangaId -> getCategories.awaitByMangaId(mangaId) }
.orEmpty()
}
val categories = getCategories.await()
val categoriesForManga = this.id?.let { mangaId -> getCategories.awaitByMangaId(mangaId) }.orEmpty()
val ids = categoriesForManga.mapNotNull { it.id }.toTypedArray()
withUIContext {
SetCategoriesSheet(
activity,
this,
this@moveCategories,
categories.toMutableList(),
ids,
addingToLibrary,
@ -114,24 +112,26 @@ fun Manga.moveCategories(
}
}.show()
}
}
fun List<Manga>.moveCategories(
suspend fun List<Manga>.moveCategories(
activity: Activity,
onMangaMoved: () -> Unit,
) {
if (this.isEmpty()) return
val getCategories: GetCategories = Injekt.get()
// FIXME: Don't do blocking
val categories = runBlocking { getCategories.await() }
val categories = getCategories.await()
val mangaCategories = map { manga ->
manga.id?.let { mangaId -> runBlocking { getCategories.awaitByMangaId(mangaId) } }.orEmpty()
manga.id?.let { mangaId -> getCategories.awaitByMangaId(mangaId) }.orEmpty()
}
val commonCategories = mangaCategories.reduce { set1, set2 -> set1.intersect(set2.toSet()).toMutableList() }.toSet()
val mixedCategories = mangaCategories.flatten().distinct().subtract(commonCategories).toMutableList()
withUIContext {
SetCategoriesSheet(
activity,
this,
this@moveCategories,
categories.toMutableList(),
categories.map {
when (it) {
@ -145,8 +145,9 @@ fun List<Manga>.moveCategories(
onMangaMoved()
}.show()
}
}
fun Manga.addOrRemoveToFavorites(
suspend fun Manga.addOrRemoveToFavorites(
preferences: PreferencesHelper,
view: View,
activity: Activity,
@ -160,15 +161,12 @@ fun Manga.addOrRemoveToFavorites(
setMangaCategories: SetMangaCategories = Injekt.get(),
getManga: GetManga = Injekt.get(),
updateManga: UpdateManga = Injekt.get(),
@OptIn(DelicateCoroutinesApi::class)
scope: CoroutineScope = GlobalScope,
): Snackbar? {
if (!favorite) {
if (checkForDupes) {
val duplicateManga = runBlocking(Dispatchers.IO) {
getManga.awaitDuplicateFavorite(
this@addOrRemoveToFavorites.title,
this@addOrRemoveToFavorites.source,
)
}
val duplicateManga = getManga.awaitDuplicateFavorite(this.title, this.source)
if (duplicateManga != null) {
showAddDuplicateDialog(
this,
@ -187,6 +185,7 @@ fun Manga.addOrRemoveToFavorites(
onMangaAdded,
onMangaMoved,
onMangaDeleted,
scope = scope,
)
},
migrateManga = { source, faved ->
@ -197,8 +196,7 @@ fun Manga.addOrRemoveToFavorites(
}
}
// FIXME: Don't do blocking
val categories = runBlocking { getCategories.await() }
val categories = getCategories.await()
val defaultCategoryId = preferences.defaultCategory().get()
val defaultCategory = categories.find { it.id == defaultCategoryId }
val lastUsedCategories = Category.lastCategoriesAddedTo.mapNotNull { catId ->
@ -209,8 +207,6 @@ fun Manga.addOrRemoveToFavorites(
favorite = true
date_added = Date().time
autoAddTrack(onMangaMoved)
// FIXME: Don't do blocking
runBlocking {
updateManga.await(
MangaUpdate(
id = this@addOrRemoveToFavorites.id!!,
@ -219,15 +215,18 @@ fun Manga.addOrRemoveToFavorites(
)
)
setMangaCategories.await(this@addOrRemoveToFavorites.id!!, listOf(defaultCategory.id!!.toLong()))
}
(activity as? MainActivity)?.showNotificationPermissionPrompt()
onMangaMoved()
return view.snack(activity.getString(MR.strings.added_to_, defaultCategory.name)) {
return withUIContext {
view.snack(activity.getString(MR.strings.added_to_, defaultCategory.name)) {
setAction(MR.strings.change) {
scope.launchIO {
moveCategories(activity, onMangaMoved)
}
}
}
}
}
defaultCategoryId == -2 && (
lastUsedCategories.isNotEmpty() ||
Category.lastCategoriesAddedTo.firstOrNull() == 0
@ -235,8 +234,6 @@ fun Manga.addOrRemoveToFavorites(
favorite = true
date_added = Date().time
autoAddTrack(onMangaMoved)
// FIXME: Don't do blocking
runBlocking {
updateManga.await(
MangaUpdate(
id = this@addOrRemoveToFavorites.id!!,
@ -245,10 +242,10 @@ fun Manga.addOrRemoveToFavorites(
)
)
setMangaCategories.await(this@addOrRemoveToFavorites.id!!, lastUsedCategories.map { it.id!!.toLong() })
}
(activity as? MainActivity)?.showNotificationPermissionPrompt()
onMangaMoved()
return view.snack(
return withUIContext {
view.snack(
activity.getString(
MR.strings.added_to_,
when (lastUsedCategories.size) {
@ -263,16 +260,17 @@ fun Manga.addOrRemoveToFavorites(
),
) {
setAction(MR.strings.change) {
scope.launchIO {
moveCategories(activity, onMangaMoved)
}
}
}
}
}
defaultCategoryId == 0 || categories.isEmpty() -> { // 'Default' or no category
favorite = true
date_added = Date().time
autoAddTrack(onMangaMoved)
// FIXME: Don't do blocking
runBlocking {
updateManga.await(
MangaUpdate(
id = this@addOrRemoveToFavorites.id!!,
@ -281,19 +279,22 @@ fun Manga.addOrRemoveToFavorites(
)
)
setMangaCategories.await(this@addOrRemoveToFavorites.id!!, emptyList())
}
onMangaMoved()
(activity as? MainActivity)?.showNotificationPermissionPrompt()
return if (categories.isNotEmpty()) {
return withUIContext {
if (categories.isNotEmpty()) {
view.snack(activity.getString(MR.strings.added_to_, activity.getString(MR.strings.default_value))) {
setAction(MR.strings.change) {
scope.launchIO {
moveCategories(activity, onMangaMoved)
}
}
}
} else {
view.snack(MR.strings.added_to_library)
}
}
}
else -> { // Always ask
showSetCategoriesSheet(activity, categories, onMangaAdded, onMangaMoved)
}
@ -302,8 +303,6 @@ fun Manga.addOrRemoveToFavorites(
val lastAddedDate = date_added
favorite = false
date_added = 0
// FIXME: Don't do blocking
runBlocking {
updateManga.await(
MangaUpdate(
id = this@addOrRemoveToFavorites.id!!,
@ -311,14 +310,12 @@ fun Manga.addOrRemoveToFavorites(
dateAdded = 0,
)
)
}
onMangaMoved()
return view.snack(view.context.getString(MR.strings.removed_from_library), Snackbar.LENGTH_INDEFINITE) {
setAction(MR.strings.undo) {
favorite = true
date_added = lastAddedDate
// FIXME: Don't do blocking
runBlocking {
scope.launchIO {
updateManga.await(
MangaUpdate(
id = this@addOrRemoveToFavorites.id!!,
@ -344,20 +341,20 @@ fun Manga.addOrRemoveToFavorites(
return null
}
private fun Manga.showSetCategoriesSheet(
private suspend fun Manga.showSetCategoriesSheet(
activity: Activity,
categories: List<Category>,
onMangaAdded: (Pair<Long, Boolean>?) -> Unit,
onMangaMoved: () -> Unit,
getCategories: GetCategories = Injekt.get(),
) {
// FIXME: Don't do blocking
val categoriesForManga = runBlocking { getCategories.awaitByMangaId(this@showSetCategoriesSheet.id!!) }
val categoriesForManga = getCategories.awaitByMangaId(this.id!!)
val ids = categoriesForManga.mapNotNull { it.id }.toTypedArray()
withUIContext {
SetCategoriesSheet(
activity,
this,
this@showSetCategoriesSheet,
categories.toMutableList(),
ids,
true,
@ -367,16 +364,17 @@ private fun Manga.showSetCategoriesSheet(
autoAddTrack(onMangaMoved)
}.show()
}
}
private fun showAddDuplicateDialog(
private suspend fun showAddDuplicateDialog(
newManga: Manga,
libraryManga: Manga,
activity: Activity,
sourceManager: SourceManager,
controller: Controller,
addManga: () -> Unit,
addManga: suspend () -> Unit,
migrateManga: (Long, Boolean) -> Unit,
) {
) = withUIContext {
val source = sourceManager.getOrStub(libraryManga.source)
val titles by lazy { MigrationFlags.titles(activity, libraryManga) }
@ -415,7 +413,7 @@ private fun showAddDuplicateDialog(
MangaDetailsController(libraryManga)
.withFadeTransaction(),
)
1 -> addManga()
1 -> launchIO { addManga() }
2 -> {
if (!newManga.initialized) {
activity.toast(MR.strings.must_view_details_before_migration, Toast.LENGTH_LONG)