Explorar el Código

Extension function instead of redefining uiScope everywhere

arkon hace 5 años
padre
commit
d9f44c1f7d
Se han modificado 17 ficheros con 57 adiciones y 59 borrados
  1. 2 2
      app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryController.kt
  2. 3 3
      app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionController.kt
  3. 2 2
      app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionDetailsController.kt
  4. 2 2
      app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt
  5. 3 3
      app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersController.kt
  6. 14 14
      app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt
  7. 2 2
      app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackController.kt
  8. 7 7
      app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackSearchDialog.kt
  9. 3 3
      app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesController.kt
  10. 2 6
      app/src/main/java/eu/kanade/tachiyomi/ui/security/SecureActivityDelegate.kt
  11. 0 4
      app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsController.kt
  12. 3 3
      app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt
  13. 2 2
      app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsSecurityController.kt
  14. 2 2
      app/src/main/java/eu/kanade/tachiyomi/ui/source/SourceController.kt
  15. 2 2
      app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/BrowseSourceController.kt
  16. 2 2
      app/src/main/java/eu/kanade/tachiyomi/ui/source/global_search/GlobalSearchController.kt
  17. 6 0
      app/src/main/java/eu/kanade/tachiyomi/util/lang/CoroutinesExtensions.kt

+ 2 - 2
app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryController.kt

@@ -17,8 +17,8 @@ import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.database.models.Category
 import eu.kanade.tachiyomi.databinding.CategoriesControllerBinding
 import eu.kanade.tachiyomi.ui.base.controller.NucleusController
+import eu.kanade.tachiyomi.util.lang.launchInUI
 import eu.kanade.tachiyomi.util.system.toast
-import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 import reactivecircus.flowbinding.android.view.clicks
 
@@ -93,7 +93,7 @@ class CategoryController : NucleusController<CategoryPresenter>(),
             .onEach {
                 CategoryCreateDialog(this@CategoryController).showDialog(router, null)
             }
-            .launchIn(uiScope)
+            .launchInUI()
     }
 
     /**

+ 3 - 3
app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionController.kt

@@ -21,8 +21,8 @@ import eu.kanade.tachiyomi.extension.ExtensionUpdateJob
 import eu.kanade.tachiyomi.extension.model.Extension
 import eu.kanade.tachiyomi.ui.base.controller.NucleusController
 import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
+import eu.kanade.tachiyomi.util.lang.launchInUI
 import kotlinx.coroutines.flow.filter
-import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 import reactivecircus.flowbinding.appcompat.queryTextChanges
 import reactivecircus.flowbinding.swiperefreshlayout.refreshes
@@ -74,7 +74,7 @@ open class ExtensionController : NucleusController<ExtensionPresenter>(),
         binding.extSwipeRefresh.isRefreshing = true
         binding.extSwipeRefresh.refreshes()
             .onEach { presenter.findAvailableExtensions() }
-            .launchIn(uiScope)
+            .launchInUI()
 
         // Initialize adapter, scroll listener and recycler views
         adapter = ExtensionAdapter(this)
@@ -153,7 +153,7 @@ open class ExtensionController : NucleusController<ExtensionPresenter>(),
                 query = it.toString()
                 drawExtensions()
             }
-            .launchIn(uiScope)
+            .launchInUI()
 
         // Fixes problem with the overflow icon showing up in lieu of search
         searchItem.fixExpand(onExpand = { invalidateMenuOnExpand() })

+ 2 - 2
app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionDetailsController.kt

@@ -29,10 +29,10 @@ import eu.kanade.tachiyomi.databinding.ExtensionDetailControllerBinding
 import eu.kanade.tachiyomi.source.ConfigurableSource
 import eu.kanade.tachiyomi.source.Source
 import eu.kanade.tachiyomi.ui.base.controller.NucleusController
+import eu.kanade.tachiyomi.util.lang.launchInUI
 import eu.kanade.tachiyomi.util.preference.preferenceCategory
 import eu.kanade.tachiyomi.util.system.LocaleHelper
 import eu.kanade.tachiyomi.util.view.visible
-import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 import reactivecircus.flowbinding.android.view.clicks
 
@@ -80,7 +80,7 @@ class ExtensionDetailsController(bundle: Bundle? = null) :
         extension.getApplicationIcon(context)?.let { binding.extensionIcon.setImageDrawable(it) }
         binding.extensionUninstallButton.clicks()
             .onEach { presenter.uninstallExtension() }
-            .launchIn(uiScope)
+            .launchInUI()
 
         if (extension.isObsolete) {
             binding.extensionObsolete.visible()

+ 2 - 2
app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt

@@ -35,12 +35,12 @@ import eu.kanade.tachiyomi.ui.base.controller.TabbedController
 import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
 import eu.kanade.tachiyomi.ui.main.MainActivity
 import eu.kanade.tachiyomi.ui.manga.MangaController
+import eu.kanade.tachiyomi.util.lang.launchInUI
 import eu.kanade.tachiyomi.util.system.getResourceColor
 import eu.kanade.tachiyomi.util.system.toast
 import java.io.IOException
 import kotlinx.android.synthetic.main.main_activity.tabs
 import kotlinx.coroutines.flow.filter
-import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 import reactivecircus.flowbinding.appcompat.queryTextChanges
 import rx.Subscription
@@ -343,7 +343,7 @@ class LibraryController(
                 query = it.toString()
                 searchRelay.call(query)
             }
-            .launchIn(uiScope)
+            .launchInUI()
 
         searchItem.fixExpand(onExpand = { invalidateMenuOnExpand() })
     }

+ 3 - 3
app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersController.kt

@@ -27,6 +27,7 @@ import eu.kanade.tachiyomi.ui.base.controller.NucleusController
 import eu.kanade.tachiyomi.ui.base.controller.popControllerWithTag
 import eu.kanade.tachiyomi.ui.manga.MangaController
 import eu.kanade.tachiyomi.ui.reader.ReaderActivity
+import eu.kanade.tachiyomi.util.lang.launchInUI
 import eu.kanade.tachiyomi.util.system.getResourceColor
 import eu.kanade.tachiyomi.util.system.toast
 import eu.kanade.tachiyomi.util.view.getCoordinates
@@ -34,7 +35,6 @@ import eu.kanade.tachiyomi.util.view.gone
 import eu.kanade.tachiyomi.util.view.shrinkOnScroll
 import eu.kanade.tachiyomi.util.view.snack
 import eu.kanade.tachiyomi.util.view.visible
-import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 import reactivecircus.flowbinding.android.view.clicks
 import reactivecircus.flowbinding.swiperefreshlayout.refreshes
@@ -95,7 +95,7 @@ class ChaptersController : NucleusController<ChaptersPresenter>(),
 
         binding.swipeRefresh.refreshes()
             .onEach { fetchChaptersFromSource() }
-            .launchIn(uiScope)
+            .launchInUI()
 
         binding.fab.clicks()
             .onEach {
@@ -117,7 +117,7 @@ class ChaptersController : NucleusController<ChaptersPresenter>(),
                     view.context.toast(R.string.no_next_chapter)
                 }
             }
-            .launchIn(uiScope)
+            .launchInUI()
 
         binding.fab.shrinkOnScroll(binding.recycler)
     }

+ 14 - 14
app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt

@@ -48,12 +48,12 @@ import eu.kanade.tachiyomi.ui.manga.MangaController
 import eu.kanade.tachiyomi.ui.source.browse.BrowseSourceController
 import eu.kanade.tachiyomi.ui.source.global_search.GlobalSearchController
 import eu.kanade.tachiyomi.ui.webview.WebViewActivity
+import eu.kanade.tachiyomi.util.lang.launchInUI
 import eu.kanade.tachiyomi.util.lang.truncateCenter
 import eu.kanade.tachiyomi.util.system.toast
 import eu.kanade.tachiyomi.util.view.snack
 import eu.kanade.tachiyomi.util.view.visible
 import jp.wasabeef.glide.transformations.CropSquareTransformation
-import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 import reactivecircus.flowbinding.android.view.clicks
 import reactivecircus.flowbinding.android.view.longClicks
@@ -95,12 +95,12 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
         // Set onclickListener to toggle favorite when favorite button clicked.
         binding.btnFavorite.clicks()
             .onEach { onFavoriteClick() }
-            .launchIn(uiScope)
+            .launchInUI()
 
         // Set onLongClickListener to manage categories when favorite button is clicked.
         binding.btnFavorite.longClicks()
             .onEach { onFavoriteLongClick() }
-            .launchIn(uiScope)
+            .launchInUI()
 
         if (presenter.source is HttpSource) {
             binding.btnWebview.visible()
@@ -108,64 +108,64 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
 
             binding.btnWebview.clicks()
                 .onEach { openInWebView() }
-                .launchIn(uiScope)
+                .launchInUI()
             binding.btnShare.clicks()
                 .onEach { shareManga() }
-                .launchIn(uiScope)
+                .launchInUI()
         }
 
         // Set SwipeRefresh to refresh manga data.
         binding.swipeRefresh.refreshes()
             .onEach { fetchMangaFromSource() }
-            .launchIn(uiScope)
+            .launchInUI()
 
         binding.mangaFullTitle.longClicks()
             .onEach {
                 copyToClipboard(view.context.getString(R.string.title), binding.mangaFullTitle.text.toString())
             }
-            .launchIn(uiScope)
+            .launchInUI()
 
         binding.mangaFullTitle.clicks()
             .onEach {
                 performGlobalSearch(binding.mangaFullTitle.text.toString())
             }
-            .launchIn(uiScope)
+            .launchInUI()
 
         binding.mangaArtist.longClicks()
             .onEach {
                 copyToClipboard(binding.mangaArtistLabel.text.toString(), binding.mangaArtist.text.toString())
             }
-            .launchIn(uiScope)
+            .launchInUI()
 
         binding.mangaArtist.clicks()
             .onEach {
                 performGlobalSearch(binding.mangaArtist.text.toString())
             }
-            .launchIn(uiScope)
+            .launchInUI()
 
         binding.mangaAuthor.longClicks()
             .onEach {
                 copyToClipboard(binding.mangaAuthor.text.toString(), binding.mangaAuthor.text.toString())
             }
-            .launchIn(uiScope)
+            .launchInUI()
 
         binding.mangaAuthor.clicks()
             .onEach {
                 performGlobalSearch(binding.mangaAuthor.text.toString())
             }
-            .launchIn(uiScope)
+            .launchInUI()
 
         binding.mangaSummary.longClicks()
             .onEach {
                 copyToClipboard(view.context.getString(R.string.description), binding.mangaSummary.text.toString())
             }
-            .launchIn(uiScope)
+            .launchInUI()
 
         binding.mangaCover.longClicks()
             .onEach {
                 copyToClipboard(view.context.getString(R.string.title), presenter.manga.title)
             }
-            .launchIn(uiScope)
+            .launchInUI()
     }
 
     override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {

+ 2 - 2
app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackController.kt

@@ -11,8 +11,8 @@ import eu.kanade.tachiyomi.data.track.model.TrackSearch
 import eu.kanade.tachiyomi.databinding.TrackControllerBinding
 import eu.kanade.tachiyomi.ui.base.controller.NucleusController
 import eu.kanade.tachiyomi.ui.manga.MangaController
+import eu.kanade.tachiyomi.util.lang.launchInUI
 import eu.kanade.tachiyomi.util.system.toast
-import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 import reactivecircus.flowbinding.swiperefreshlayout.refreshes
 import timber.log.Timber
@@ -51,7 +51,7 @@ class TrackController : NucleusController<TrackPresenter>(),
         binding.swipeRefresh.isEnabled = false
         binding.swipeRefresh.refreshes()
             .onEach { presenter.refresh() }
-            .launchIn(uiScope)
+            .launchInUI()
     }
 
     override fun onDestroyView(view: View) {

+ 7 - 7
app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackSearchDialog.kt

@@ -10,6 +10,7 @@ import eu.kanade.tachiyomi.data.track.TrackManager
 import eu.kanade.tachiyomi.data.track.TrackService
 import eu.kanade.tachiyomi.data.track.model.TrackSearch
 import eu.kanade.tachiyomi.ui.base.controller.DialogController
+import eu.kanade.tachiyomi.util.lang.launchInUI
 import eu.kanade.tachiyomi.util.view.invisible
 import eu.kanade.tachiyomi.util.view.visible
 import java.util.concurrent.TimeUnit
@@ -18,7 +19,6 @@ import kotlinx.android.synthetic.main.track_search_dialog.view.track_search
 import kotlinx.android.synthetic.main.track_search_dialog.view.track_search_list
 import kotlinx.coroutines.flow.debounce
 import kotlinx.coroutines.flow.filter
-import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onEach
 import reactivecircus.flowbinding.android.widget.itemClicks
@@ -80,7 +80,7 @@ class TrackSearchDialog : DialogController {
             .onEach { position ->
                 selectedItem = adapter.getItem(position)
             }
-            .launchIn(uiScope)
+            .launchInUI()
 
         // Do an initial search based on the manga's title
         if (savedState == null) {
@@ -99,11 +99,11 @@ class TrackSearchDialog : DialogController {
     override fun onAttach(view: View) {
         super.onAttach(view)
         dialogView!!.track_search.textChanges()
-                .debounce(TimeUnit.SECONDS.toMillis(1))
-                .map { it.toString() }
-                .filter { it.isNotBlank() }
-                .onEach { search(it) }
-                .launchIn(uiScope)
+            .debounce(TimeUnit.SECONDS.toMillis(1))
+            .map { it.toString() }
+            .filter { it.isNotBlank() }
+            .onEach { search(it) }
+            .launchInUI()
     }
 
     private fun search(query: String) {

+ 3 - 3
app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesController.kt

@@ -25,9 +25,9 @@ import eu.kanade.tachiyomi.ui.base.controller.popControllerWithTag
 import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
 import eu.kanade.tachiyomi.ui.manga.MangaController
 import eu.kanade.tachiyomi.ui.reader.ReaderActivity
+import eu.kanade.tachiyomi.util.lang.launchInUI
 import eu.kanade.tachiyomi.util.system.notificationManager
 import eu.kanade.tachiyomi.util.system.toast
-import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 import reactivecircus.flowbinding.recyclerview.scrollStateChanges
 import reactivecircus.flowbinding.swiperefreshlayout.refreshes
@@ -100,7 +100,7 @@ class UpdatesController : NucleusController<UpdatesPresenter>(),
                 val firstPos = layoutManager.findFirstCompletelyVisibleItemPosition()
                 binding.swipeRefresh.isEnabled = firstPos <= 0
             }
-            .launchIn(uiScope)
+            .launchInUI()
 
         binding.swipeRefresh.setDistanceToTriggerSync((2 * 64 * view.resources.displayMetrics.density).toInt())
         binding.swipeRefresh.refreshes()
@@ -110,7 +110,7 @@ class UpdatesController : NucleusController<UpdatesPresenter>(),
                 // It can be a very long operation, so we disable swipe refresh and show a toast.
                 binding.swipeRefresh.isRefreshing = false
             }
-            .launchIn(uiScope)
+            .launchInUI()
     }
 
     override fun onDestroyView(view: View) {

+ 2 - 6
app/src/main/java/eu/kanade/tachiyomi/ui/security/SecureActivityDelegate.kt

@@ -5,10 +5,8 @@ import android.view.WindowManager
 import androidx.biometric.BiometricManager
 import androidx.fragment.app.FragmentActivity
 import eu.kanade.tachiyomi.data.preference.PreferencesHelper
+import eu.kanade.tachiyomi.util.lang.launchInUI
 import java.util.Date
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 import uy.kohesive.injekt.injectLazy
 
@@ -16,8 +14,6 @@ class SecureActivityDelegate(private val activity: FragmentActivity) {
 
     private val preferences by injectLazy<PreferencesHelper>()
 
-    private val uiScope = CoroutineScope(Dispatchers.Main)
-
     fun onCreate() {
         preferences.secureScreen().asFlow()
             .onEach {
@@ -27,7 +23,7 @@ class SecureActivityDelegate(private val activity: FragmentActivity) {
                     activity.window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
                 }
             }
-            .launchIn(uiScope)
+            .launchInUI()
     }
 
     fun onResume() {

+ 0 - 4
app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsController.kt

@@ -15,8 +15,6 @@ import com.bluelinelabs.conductor.ControllerChangeType
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 import eu.kanade.tachiyomi.ui.base.controller.BaseController
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
 import rx.Observable
 import rx.Subscription
 import rx.subscriptions.CompositeSubscription
@@ -27,8 +25,6 @@ abstract class SettingsController : PreferenceController() {
 
     val preferences: PreferencesHelper = Injekt.get()
 
-    val uiScope = CoroutineScope(Dispatchers.Main)
-
     var untilDestroySubscriptions = CompositeSubscription()
         private set
 

+ 3 - 3
app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt

@@ -7,6 +7,7 @@ import androidx.preference.PreferenceScreen
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
 import eu.kanade.tachiyomi.data.preference.PreferenceValues as Values
+import eu.kanade.tachiyomi.util.lang.launchInUI
 import eu.kanade.tachiyomi.util.preference.defaultValue
 import eu.kanade.tachiyomi.util.preference.entriesRes
 import eu.kanade.tachiyomi.util.preference.intListPreference
@@ -17,7 +18,6 @@ import eu.kanade.tachiyomi.util.preference.preference
 import eu.kanade.tachiyomi.util.preference.preferenceCategory
 import eu.kanade.tachiyomi.util.preference.titleRes
 import eu.kanade.tachiyomi.util.system.LocaleHelper
-import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 
 class SettingsGeneralController : SettingsController() {
@@ -142,7 +142,7 @@ class SettingsGeneralController : SettingsController() {
                 isVisible = preferences.themeMode().get() != Values.THEME_MODE_DARK
                 preferences.themeMode().asFlow()
                     .onEach { isVisible = it != Values.THEME_MODE_DARK }
-                    .launchIn(uiScope)
+                    .launchInUI()
 
                 onChange {
                     if (preferences.themeMode().get() != Values.THEME_MODE_DARK) {
@@ -168,7 +168,7 @@ class SettingsGeneralController : SettingsController() {
                 isVisible = preferences.themeMode().get() != Values.THEME_MODE_LIGHT
                 preferences.themeMode().asFlow()
                     .onEach { isVisible = it != Values.THEME_MODE_LIGHT }
-                    .launchIn(uiScope)
+                    .launchInUI()
 
                 onChange {
                     if (preferences.themeMode().get() != Values.THEME_MODE_LIGHT) {

+ 2 - 2
app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsSecurityController.kt

@@ -4,12 +4,12 @@ import androidx.biometric.BiometricManager
 import androidx.preference.PreferenceScreen
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
+import eu.kanade.tachiyomi.util.lang.launchInUI
 import eu.kanade.tachiyomi.util.preference.defaultValue
 import eu.kanade.tachiyomi.util.preference.intListPreference
 import eu.kanade.tachiyomi.util.preference.summaryRes
 import eu.kanade.tachiyomi.util.preference.switchPreference
 import eu.kanade.tachiyomi.util.preference.titleRes
-import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 
 class SettingsSecurityController : SettingsController() {
@@ -41,7 +41,7 @@ class SettingsSecurityController : SettingsController() {
                 isVisible = preferences.useBiometricLock().get()
                 preferences.useBiometricLock().asFlow()
                     .onEach { isVisible = it }
-                    .launchIn(uiScope)
+                    .launchInUI()
             }
         }
 

+ 2 - 2
app/src/main/java/eu/kanade/tachiyomi/ui/source/SourceController.kt

@@ -30,8 +30,8 @@ import eu.kanade.tachiyomi.ui.setting.SettingsSourcesController
 import eu.kanade.tachiyomi.ui.source.browse.BrowseSourceController
 import eu.kanade.tachiyomi.ui.source.global_search.GlobalSearchController
 import eu.kanade.tachiyomi.ui.source.latest.LatestUpdatesController
+import eu.kanade.tachiyomi.util.lang.launchInUI
 import kotlinx.coroutines.flow.filter
-import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 import reactivecircus.flowbinding.appcompat.QueryTextEvent
 import reactivecircus.flowbinding.appcompat.queryTextEvents
@@ -199,7 +199,7 @@ class SourceController : NucleusController<SourcePresenter>(),
         searchView.queryTextEvents()
             .filter { it is QueryTextEvent.QuerySubmitted }
             .onEach { performGlobalSearch(it.queryText.toString()) }
-            .launchIn(uiScope)
+            .launchInUI()
     }
 
     fun performGlobalSearch(query: String) {

+ 2 - 2
app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/BrowseSourceController.kt

@@ -31,6 +31,7 @@ import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
 import eu.kanade.tachiyomi.ui.library.ChangeMangaCategoriesDialog
 import eu.kanade.tachiyomi.ui.manga.MangaController
 import eu.kanade.tachiyomi.ui.webview.WebViewActivity
+import eu.kanade.tachiyomi.util.lang.launchInUI
 import eu.kanade.tachiyomi.util.system.connectivityManager
 import eu.kanade.tachiyomi.util.system.toast
 import eu.kanade.tachiyomi.util.view.gone
@@ -41,7 +42,6 @@ import eu.kanade.tachiyomi.util.view.visible
 import eu.kanade.tachiyomi.widget.AutofitRecyclerView
 import eu.kanade.tachiyomi.widget.EmptyView
 import kotlinx.coroutines.flow.filter
-import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 import reactivecircus.flowbinding.appcompat.QueryTextEvent
 import reactivecircus.flowbinding.appcompat.queryTextEvents
@@ -242,7 +242,7 @@ open class BrowseSourceController(bundle: Bundle) :
             .filter { router.backstack.lastOrNull()?.controller() == this@BrowseSourceController }
             .filter { it is QueryTextEvent.QuerySubmitted }
             .onEach { searchWithQuery(it.queryText.toString()) }
-            .launchIn(uiScope)
+            .launchInUI()
 
         searchItem.fixExpand(
                 onExpand = { invalidateMenuOnExpand() },

+ 2 - 2
app/src/main/java/eu/kanade/tachiyomi/ui/source/global_search/GlobalSearchController.kt

@@ -16,8 +16,8 @@ import eu.kanade.tachiyomi.source.CatalogueSource
 import eu.kanade.tachiyomi.ui.base.controller.NucleusController
 import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
 import eu.kanade.tachiyomi.ui.manga.MangaController
+import eu.kanade.tachiyomi.util.lang.launchInUI
 import kotlinx.coroutines.flow.filter
-import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 import reactivecircus.flowbinding.appcompat.QueryTextEvent
 import reactivecircus.flowbinding.appcompat.queryTextEvents
@@ -130,7 +130,7 @@ open class GlobalSearchController(
                 searchItem.collapseActionView()
                 setTitle() // Update toolbar title
             }
-            .launchIn(uiScope)
+            .launchInUI()
     }
 
     /**

+ 6 - 0
app/src/main/java/eu/kanade/tachiyomi/util/lang/CoroutinesExtensions.kt

@@ -6,8 +6,14 @@ import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.GlobalScope
 import kotlinx.coroutines.Job
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.launch
 
+fun <T> Flow<T>.launchInUI(): Job = CoroutineScope(Dispatchers.Main).launch {
+        collect() // tail-call
+}
+
 fun launchUI(block: suspend CoroutineScope.() -> Unit): Job =
         GlobalScope.launch(Dispatchers.Main, CoroutineStart.DEFAULT, block)