Przeglądaj źródła

Migrate more preferences

arkon 5 lat temu
rodzic
commit
53a3be0703
34 zmienionych plików z 218 dodań i 295 usunięć
  1. 28 28
      app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt
  2. 2 0
      app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseActivity.kt
  3. 2 0
      app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseRxActivity.kt
  4. 5 0
      app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/NucleusController.kt
  5. 2 2
      app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryController.kt
  6. 3 3
      app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionController.kt
  7. 2 2
      app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionDetailsController.kt
  8. 2 3
      app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionFilterController.kt
  9. 1 2
      app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionPresenter.kt
  10. 4 6
      app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt
  11. 1 2
      app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt
  12. 3 3
      app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersController.kt
  13. 16 16
      app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt
  14. 2 2
      app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackController.kt
  15. 3 3
      app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackSearchDialog.kt
  16. 43 49
      app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt
  17. 32 63
      app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderColorFilterSheet.kt
  18. 16 5
      app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderSettingsSheet.kt
  19. 17 26
      app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ViewerConfig.kt
  20. 4 10
      app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerConfig.kt
  21. 0 8
      app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt
  22. 0 21
      app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonConfig.kt
  23. 0 1
      app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt
  24. 3 3
      app/src/main/java/eu/kanade/tachiyomi/ui/recent/updates/UpdatesController.kt
  25. 4 4
      app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsController.kt
  26. 3 3
      app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt
  27. 2 2
      app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsSecurityController.kt
  28. 4 5
      app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsSourcesController.kt
  29. 4 5
      app/src/main/java/eu/kanade/tachiyomi/ui/source/SourceController.kt
  30. 3 4
      app/src/main/java/eu/kanade/tachiyomi/ui/source/SourcePresenter.kt
  31. 2 2
      app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/BrowseSourceController.kt
  32. 2 2
      app/src/main/java/eu/kanade/tachiyomi/ui/source/global_search/GlobalSearchController.kt
  33. 3 4
      app/src/main/java/eu/kanade/tachiyomi/ui/source/global_search/GlobalSearchPresenter.kt
  34. 0 6
      app/src/main/java/eu/kanade/tachiyomi/util/lang/CoroutinesExtensions.kt

+ 28 - 28
app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt

@@ -76,51 +76,53 @@ class PreferencesHelper(val context: Context) {
 
     fun rotation() = rxPrefs.getInteger(Keys.rotation, 1)
 
-    fun pageTransitions() = rxPrefs.getBoolean(Keys.enableTransitions, true)
+    fun pageTransitions() = flowPrefs.getBoolean(Keys.enableTransitions, true)
 
-    fun doubleTapAnimSpeed() = rxPrefs.getInteger(Keys.doubleTapAnimationSpeed, 500)
+    fun doubleTapAnimSpeed() = flowPrefs.getInt(Keys.doubleTapAnimationSpeed, 500)
 
-    fun showPageNumber() = rxPrefs.getBoolean(Keys.showPageNumber, true)
+    fun showPageNumber() = flowPrefs.getBoolean(Keys.showPageNumber, true)
 
-    fun trueColor() = rxPrefs.getBoolean(Keys.trueColor, false)
+    fun trueColor() = flowPrefs.getBoolean(Keys.trueColor, false)
 
-    fun fullscreen() = rxPrefs.getBoolean(Keys.fullscreen, true)
+    fun fullscreen() = flowPrefs.getBoolean(Keys.fullscreen, true)
 
-    fun cutoutShort() = rxPrefs.getBoolean(Keys.cutoutShort, true)
+    fun cutoutShort() = flowPrefs.getBoolean(Keys.cutoutShort, true)
 
-    fun keepScreenOn() = rxPrefs.getBoolean(Keys.keepScreenOn, true)
+    fun keepScreenOn() = flowPrefs.getBoolean(Keys.keepScreenOn, true)
 
-    fun customBrightness() = rxPrefs.getBoolean(Keys.customBrightness, false)
+    fun customBrightness() = flowPrefs.getBoolean(Keys.customBrightness, false)
 
-    fun customBrightnessValue() = rxPrefs.getInteger(Keys.customBrightnessValue, 0)
+    fun customBrightnessValue() = flowPrefs.getInt(Keys.customBrightnessValue, 0)
 
-    fun colorFilter() = rxPrefs.getBoolean(Keys.colorFilter, false)
+    fun colorFilter() = flowPrefs.getBoolean(Keys.colorFilter, false)
 
-    fun colorFilterValue() = rxPrefs.getInteger(Keys.colorFilterValue, 0)
+    fun colorFilterValue() = flowPrefs.getInt(Keys.colorFilterValue, 0)
 
-    fun colorFilterMode() = rxPrefs.getInteger(Keys.colorFilterMode, 0)
+    fun colorFilterMode() = flowPrefs.getInt(Keys.colorFilterMode, 0)
 
     fun defaultViewer() = prefs.getInt(Keys.defaultViewer, 1)
 
-    fun imageScaleType() = rxPrefs.getInteger(Keys.imageScaleType, 1)
+    fun imageScaleType() = flowPrefs.getInt(Keys.imageScaleType, 1)
 
-    fun zoomStart() = rxPrefs.getInteger(Keys.zoomStart, 1)
+    fun zoomStart() = flowPrefs.getInt(Keys.zoomStart, 1)
 
-    fun readerTheme() = rxPrefs.getInteger(Keys.readerTheme, 1)
+    fun readerTheme() = flowPrefs.getInt(Keys.readerTheme, 1)
 
-    fun cropBorders() = rxPrefs.getBoolean(Keys.cropBorders, false)
+    fun alwaysShowChapterTransition() = flowPrefs.getBoolean(Keys.alwaysShowChapterTransition, true)
 
-    fun cropBordersWebtoon() = rxPrefs.getBoolean(Keys.cropBordersWebtoon, false)
+    fun cropBorders() = flowPrefs.getBoolean(Keys.cropBorders, false)
 
-    fun webtoonSidePadding() = rxPrefs.getInteger(Keys.webtoonSidePadding, 0)
+    fun cropBordersWebtoon() = flowPrefs.getBoolean(Keys.cropBordersWebtoon, false)
 
-    fun readWithTapping() = rxPrefs.getBoolean(Keys.readWithTapping, true)
+    fun webtoonSidePadding() = flowPrefs.getInt(Keys.webtoonSidePadding, 0)
 
-    fun readWithLongTap() = rxPrefs.getBoolean(Keys.readWithLongTap, true)
+    fun readWithTapping() = flowPrefs.getBoolean(Keys.readWithTapping, true)
 
-    fun readWithVolumeKeys() = rxPrefs.getBoolean(Keys.readWithVolumeKeys, false)
+    fun readWithLongTap() = flowPrefs.getBoolean(Keys.readWithLongTap, true)
 
-    fun readWithVolumeKeysInverted() = rxPrefs.getBoolean(Keys.readWithVolumeKeysInverted, false)
+    fun readWithVolumeKeys() = flowPrefs.getBoolean(Keys.readWithVolumeKeys, false)
+
+    fun readWithVolumeKeysInverted() = flowPrefs.getBoolean(Keys.readWithVolumeKeysInverted, false)
 
     fun portraitColumns() = rxPrefs.getInteger(Keys.portraitColumns, 0)
 
@@ -132,13 +134,13 @@ class PreferencesHelper(val context: Context) {
 
     fun lastUsedCatalogueSource() = rxPrefs.getLong(Keys.lastUsedCatalogueSource, -1)
 
-    fun lastUsedCategory() = rxPrefs.getInteger(Keys.lastUsedCategory, 0)
+    fun lastUsedCategory() = flowPrefs.getInt(Keys.lastUsedCategory, 0)
 
     fun lastVersionCode() = flowPrefs.getInt("last_version_code", 0)
 
     fun catalogueAsList() = rxPrefs.getBoolean(Keys.catalogueAsList, false)
 
-    fun enabledLanguages() = rxPrefs.getStringSet(Keys.enabledLanguages, setOf("en", Locale.getDefault().language))
+    fun enabledLanguages() = flowPrefs.getStringSet(Keys.enabledLanguages, setOf("en", Locale.getDefault().language))
 
     fun trackUsername(sync: TrackService) = prefs.getString(Keys.trackUsername(sync.id), "")
 
@@ -203,9 +205,9 @@ class PreferencesHelper(val context: Context) {
 
     fun lastExtCheck() = flowPrefs.getLong("last_ext_check", 0)
 
-    fun hiddenCatalogues() = rxPrefs.getStringSet("hidden_catalogues", emptySet())
+    fun hiddenCatalogues() = flowPrefs.getStringSet("hidden_catalogues", emptySet())
 
-    fun pinnedCatalogues() = rxPrefs.getStringSet("pinned_catalogues", emptySet())
+    fun pinnedCatalogues() = flowPrefs.getStringSet("pinned_catalogues", emptySet())
 
     fun downloadNew() = rxPrefs.getBoolean(Keys.downloadNew, false)
 
@@ -222,6 +224,4 @@ class PreferencesHelper(val context: Context) {
     fun migrateFlags() = flowPrefs.getInt("migrate_flags", Int.MAX_VALUE)
 
     fun trustedSignatures() = flowPrefs.getStringSet("trusted_signatures", emptySet())
-
-    fun alwaysShowChapterTransition() = rxPrefs.getBoolean(Keys.alwaysShowChapterTransition, true)
 }

+ 2 - 0
app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseActivity.kt

@@ -4,6 +4,7 @@ import android.content.res.Configuration
 import android.os.Build
 import android.os.Bundle
 import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.lifecycleScope
 import androidx.viewbinding.ViewBinding
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.preference.PreferenceValues as Values
@@ -16,6 +17,7 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
 
     val preferences: PreferencesHelper by injectLazy()
 
+    val scope = lifecycleScope
     lateinit var binding: VB
 
     @Suppress("LeakingThis")

+ 2 - 0
app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseRxActivity.kt

@@ -1,6 +1,7 @@
 package eu.kanade.tachiyomi.ui.base.activity
 
 import android.os.Bundle
+import androidx.lifecycle.lifecycleScope
 import androidx.viewbinding.ViewBinding
 import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
 import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
@@ -12,6 +13,7 @@ abstract class BaseRxActivity<VB : ViewBinding, P : BasePresenter<*>> : NucleusA
     @Suppress("LeakingThis")
     private val secureActivityDelegate = SecureActivityDelegate(this)
 
+    val scope = lifecycleScope
     lateinit var binding: VB
 
     init {

+ 5 - 0
app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/NucleusController.kt

@@ -4,6 +4,9 @@ import android.os.Bundle
 import androidx.viewbinding.ViewBinding
 import eu.kanade.tachiyomi.ui.base.presenter.NucleusConductorDelegate
 import eu.kanade.tachiyomi.ui.base.presenter.NucleusConductorLifecycleListener
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
 import nucleus.factory.PresenterFactory
 import nucleus.presenter.Presenter
 
@@ -14,6 +17,8 @@ abstract class NucleusController<VB : ViewBinding, P : Presenter<*>>(val bundle:
 
     private val delegate = NucleusConductorDelegate(this)
 
+    val scope = CoroutineScope(Job() + Dispatchers.Main)
+
     val presenter: P
         get() = delegate.presenter!!
 

+ 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
 
@@ -91,7 +91,7 @@ class CategoryController : NucleusController<CategoriesControllerBinding, Catego
             .onEach {
                 CategoryCreateDialog(this@CategoryController).showDialog(router, null)
             }
-            .launchInUI()
+            .launchIn(scope)
     }
 
     /**

+ 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
@@ -72,7 +72,7 @@ open class ExtensionController : NucleusController<ExtensionControllerBinding, E
         binding.extSwipeRefresh.isRefreshing = true
         binding.extSwipeRefresh.refreshes()
             .onEach { presenter.findAvailableExtensions() }
-            .launchInUI()
+            .launchIn(scope)
 
         // Initialize adapter, scroll listener and recycler views
         adapter = ExtensionAdapter(this)
@@ -151,7 +151,7 @@ open class ExtensionController : NucleusController<ExtensionControllerBinding, E
                 query = it.toString()
                 drawExtensions()
             }
-            .launchInUI()
+            .launchIn(scope)
 
         // 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
 
@@ -78,7 +78,7 @@ class ExtensionDetailsController(bundle: Bundle? = null) :
         extension.getApplicationIcon(context)?.let { binding.extensionIcon.setImageDrawable(it) }
         binding.extensionUninstallButton.clicks()
             .onEach { presenter.uninstallExtension() }
-            .launchInUI()
+            .launchIn(scope)
 
         if (extension.isObsolete) {
             binding.extensionObsolete.visible()

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

@@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.ui.extension
 
 import androidx.preference.PreferenceScreen
 import eu.kanade.tachiyomi.R
-import eu.kanade.tachiyomi.data.preference.getOrDefault
 import eu.kanade.tachiyomi.extension.ExtensionManager
 import eu.kanade.tachiyomi.ui.setting.SettingsController
 import eu.kanade.tachiyomi.util.preference.onChange
@@ -17,7 +16,7 @@ class ExtensionFilterController : SettingsController() {
     override fun setupPreferenceScreen(screen: PreferenceScreen) = with(screen) {
         titleRes = R.string.action_filter
 
-        val activeLangs = preferences.enabledLanguages().getOrDefault()
+        val activeLangs = preferences.enabledLanguages().get()
 
         val availableLangs =
                 Injekt.get<ExtensionManager>().availableExtensions.groupBy {
@@ -37,7 +36,7 @@ class ExtensionFilterController : SettingsController() {
 
                 onChange { newValue ->
                     val checked = newValue as Boolean
-                    val currentActiveLangs = preferences.enabledLanguages().getOrDefault()
+                    val currentActiveLangs = preferences.enabledLanguages().get()
 
                     if (checked) {
                         preferences.enabledLanguages().set(currentActiveLangs + it)

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

@@ -4,7 +4,6 @@ import android.app.Application
 import android.os.Bundle
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.preference.PreferencesHelper
-import eu.kanade.tachiyomi.data.preference.getOrDefault
 import eu.kanade.tachiyomi.extension.ExtensionManager
 import eu.kanade.tachiyomi.extension.model.Extension
 import eu.kanade.tachiyomi.extension.model.InstallStep
@@ -55,7 +54,7 @@ open class ExtensionPresenter(
     @Synchronized
     private fun toItems(tuple: ExtensionTuple): List<ExtensionItem> {
         val context = Injekt.get<Application>()
-        val activeLangs = preferences.enabledLanguages().getOrDefault()
+        val activeLangs = preferences.enabledLanguages().get()
 
         val (installed, untrusted, available) = tuple
 

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

@@ -26,7 +26,6 @@ import eu.kanade.tachiyomi.data.database.models.Category
 import eu.kanade.tachiyomi.data.database.models.Manga
 import eu.kanade.tachiyomi.data.library.LibraryUpdateService
 import eu.kanade.tachiyomi.data.preference.PreferencesHelper
-import eu.kanade.tachiyomi.data.preference.getOrDefault
 import eu.kanade.tachiyomi.databinding.LibraryControllerBinding
 import eu.kanade.tachiyomi.ui.base.controller.NucleusController
 import eu.kanade.tachiyomi.ui.base.controller.RootController
@@ -34,12 +33,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 reactivecircus.flowbinding.viewpager.pageSelections
@@ -61,8 +60,7 @@ class LibraryController(
     /**
      * Position of the active category.
      */
-    var activeCategory: Int = preferences.lastUsedCategory().getOrDefault()
-        private set
+    private var activeCategory: Int = preferences.lastUsedCategory().get()
 
     /**
      * Action mode for selections.
@@ -154,7 +152,7 @@ class LibraryController(
                 preferences.lastUsedCategory().set(it)
                 activeCategory = it
             }
-            .launchInUI()
+            .launchIn(scope)
 
         getColumnsPreferenceForCurrentOrientation().asObservable()
                 .doOnNext { mangaPerRow = it }
@@ -334,7 +332,7 @@ class LibraryController(
                 query = it.toString()
                 searchRelay.call(query)
             }
-            .launchInUI()
+            .launchIn(scope)
 
         if (query.isNotEmpty()) {
             searchItem.expandActionView()

+ 1 - 2
app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt

@@ -5,7 +5,6 @@ import android.content.Intent
 import android.os.Bundle
 import android.view.ViewGroup
 import android.widget.Toast
-import androidx.lifecycle.lifecycleScope
 import com.bluelinelabs.conductor.Conductor
 import com.bluelinelabs.conductor.Controller
 import com.bluelinelabs.conductor.ControllerChangeHandler
@@ -157,7 +156,7 @@ class MainActivity : BaseActivity<MainActivityBinding>() {
         setExtensionsBadge()
         preferences.extensionUpdatesCount().asFlow()
             .onEach { setExtensionsBadge() }
-            .launchIn(lifecycleScope)
+            .launchIn(scope)
     }
 
     override fun onNewIntent(intent: Intent) {

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

@@ -26,7 +26,6 @@ import eu.kanade.tachiyomi.databinding.ChaptersControllerBinding
 import eu.kanade.tachiyomi.ui.base.controller.NucleusController
 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,6 +33,7 @@ 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
@@ -92,7 +92,7 @@ class ChaptersController : NucleusController<ChaptersControllerBinding, Chapters
 
         binding.swipeRefresh.refreshes()
             .onEach { fetchChaptersFromSource() }
-            .launchInUI()
+            .launchIn(scope)
 
         binding.fab.clicks()
             .onEach {
@@ -114,7 +114,7 @@ class ChaptersController : NucleusController<ChaptersControllerBinding, Chapters
                     view.context.toast(R.string.no_next_chapter)
                 }
             }
-            .launchInUI()
+            .launchIn(scope)
 
         binding.fab.shrinkOnScroll(binding.recycler)
     }

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

@@ -34,13 +34,13 @@ import eu.kanade.tachiyomi.ui.recent.updates.UpdatesController
 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.gone
 import eu.kanade.tachiyomi.util.view.snack
 import eu.kanade.tachiyomi.util.view.toggle
 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.android.view.longClicks
@@ -80,12 +80,12 @@ class MangaInfoController(private val fromSource: Boolean = false) :
         // Set onclickListener to toggle favorite when favorite button clicked.
         binding.btnFavorite.clicks()
             .onEach { onFavoriteClick() }
-            .launchInUI()
+            .launchIn(scope)
 
         // Set onLongClickListener to manage categories when favorite button is clicked.
         binding.btnFavorite.longClicks()
             .onEach { onFavoriteLongClick() }
-            .launchInUI()
+            .launchIn(scope)
 
         if (presenter.source is HttpSource) {
             binding.btnWebview.visible()
@@ -93,64 +93,64 @@ class MangaInfoController(private val fromSource: Boolean = false) :
 
             binding.btnWebview.clicks()
                 .onEach { openInWebView() }
-                .launchInUI()
+                .launchIn(scope)
             binding.btnShare.clicks()
                 .onEach { shareManga() }
-                .launchInUI()
+                .launchIn(scope)
         }
 
         // Set SwipeRefresh to refresh manga data.
         binding.swipeRefresh.refreshes()
             .onEach { fetchMangaFromSource() }
-            .launchInUI()
+            .launchIn(scope)
 
         binding.mangaFullTitle.longClicks()
             .onEach {
                 copyToClipboard(view.context.getString(R.string.title), binding.mangaFullTitle.text.toString())
             }
-            .launchInUI()
+            .launchIn(scope)
 
         binding.mangaFullTitle.clicks()
             .onEach {
                 performGlobalSearch(binding.mangaFullTitle.text.toString())
             }
-            .launchInUI()
+            .launchIn(scope)
 
         binding.mangaArtist.longClicks()
             .onEach {
                 copyToClipboard(binding.mangaArtistLabel.text.toString(), binding.mangaArtist.text.toString())
             }
-            .launchInUI()
+            .launchIn(scope)
 
         binding.mangaArtist.clicks()
             .onEach {
                 performGlobalSearch(binding.mangaArtist.text.toString())
             }
-            .launchInUI()
+            .launchIn(scope)
 
         binding.mangaAuthor.longClicks()
             .onEach {
                 copyToClipboard(binding.mangaAuthor.text.toString(), binding.mangaAuthor.text.toString())
             }
-            .launchInUI()
+            .launchIn(scope)
 
         binding.mangaAuthor.clicks()
             .onEach {
                 performGlobalSearch(binding.mangaAuthor.text.toString())
             }
-            .launchInUI()
+            .launchIn(scope)
 
         binding.mangaSummary.longClicks()
             .onEach {
                 copyToClipboard(view.context.getString(R.string.description), binding.mangaSummary.text.toString())
             }
-            .launchInUI()
+            .launchIn(scope)
 
         binding.mangaCover.longClicks()
             .onEach {
                 copyToClipboard(view.context.getString(R.string.title), presenter.manga.title)
             }
-            .launchInUI()
+            .launchIn(scope)
     }
 
     /**
@@ -272,10 +272,10 @@ class MangaInfoController(private val fromSource: Boolean = false) :
             // Handle showing more or less info
             binding.mangaSummary.clicks()
                 .onEach { toggleMangaInfo(view.context) }
-                .launchInUI()
+                .launchIn(scope)
             binding.mangaInfoToggle.clicks()
                 .onEach { toggleMangaInfo(view.context) }
-                .launchInUI()
+                .launchIn(scope)
 
             // Expand manga info if navigated from source listing
             if (initialLoad && fromSource) {

+ 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
@@ -50,7 +50,7 @@ class TrackController : NucleusController<TrackControllerBinding, TrackPresenter
         binding.swipeRefresh.isEnabled = false
         binding.swipeRefresh.refreshes()
             .onEach { presenter.refresh() }
-            .launchInUI()
+            .launchIn(scope)
     }
 
     override fun onDestroyView(view: View) {

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

@@ -11,7 +11,6 @@ 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
@@ -20,6 +19,7 @@ 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
@@ -78,7 +78,7 @@ class TrackSearchDialog : DialogController {
             .onEach { position ->
                 selectedItem = adapter.getItem(position)
             }
-            .launchInUI()
+            .launchIn(trackController.scope)
 
         // Do an initial search based on the manga's title
         if (savedState == null) {
@@ -101,7 +101,7 @@ class TrackSearchDialog : DialogController {
             .map { it.toString() }
             .filter { it.isNotBlank() }
             .onEach { search(it) }
-            .launchInUI()
+            .launchIn(trackController.scope)
     }
 
     private fun search(query: String) {

+ 43 - 49
app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt

@@ -28,7 +28,6 @@ import eu.kanade.tachiyomi.data.database.models.Manga
 import eu.kanade.tachiyomi.data.notification.NotificationReceiver
 import eu.kanade.tachiyomi.data.notification.Notifications
 import eu.kanade.tachiyomi.data.preference.PreferencesHelper
-import eu.kanade.tachiyomi.data.preference.getOrDefault
 import eu.kanade.tachiyomi.databinding.ReaderActivityBinding
 import eu.kanade.tachiyomi.ui.base.activity.BaseRxActivity
 import eu.kanade.tachiyomi.ui.reader.ReaderPresenter.SetAsCoverResult.AddToLibraryFirst
@@ -57,9 +56,12 @@ import eu.kanade.tachiyomi.widget.SimpleSeekBarListener
 import java.io.File
 import java.util.concurrent.TimeUnit
 import kotlin.math.abs
+import kotlinx.coroutines.flow.drop
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.sample
 import nucleus.factory.RequiresPresenter
 import rx.Observable
-import rx.Subscription
 import rx.android.schedulers.AndroidSchedulers
 import rx.subscriptions.CompositeSubscription
 import timber.log.Timber
@@ -125,7 +127,7 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
      * Called when the activity is created. Initializes the presenter and configuration.
      */
     override fun onCreate(savedInstanceState: Bundle?) {
-        setTheme(when (preferences.readerTheme().getOrDefault()) {
+        setTheme(when (preferences.readerTheme().get()) {
             0 -> R.style.Theme_Reader_Light
             else -> R.style.Theme_Reader
         })
@@ -317,7 +319,7 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
     private fun setMenuVisibility(visible: Boolean, animate: Boolean = true) {
         menuVisible = visible
         if (visible) {
-            if (preferences.fullscreen().getOrDefault()) {
+            if (preferences.fullscreen().get()) {
                 window.showBar()
             } else {
                 resetDefaultMenuAndBar()
@@ -338,11 +340,11 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
                 binding.readerMenuBottom.startAnimation(bottomAnimation)
             }
 
-            if (preferences.showPageNumber().getOrDefault()) {
+            if (preferences.showPageNumber().get()) {
                 config?.setPageNumberVisibility(false)
             }
         } else {
-            if (preferences.fullscreen().getOrDefault()) {
+            if (preferences.fullscreen().get()) {
                 window.hideBar()
             } else {
                 resetDefaultMenuAndBar()
@@ -361,7 +363,7 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
                 binding.readerMenuBottom.startAnimation(bottomAnimation)
             }
 
-            if (preferences.showPageNumber().getOrDefault()) {
+            if (preferences.showPageNumber().get()) {
                 config?.setPageNumberVisibility(true)
             }
         }
@@ -605,16 +607,6 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
          */
         private val subscriptions = CompositeSubscription()
 
-        /**
-         * Custom brightness subscription.
-         */
-        private var customBrightnessSubscription: Subscription? = null
-
-        /**
-         * Custom color filter subscription.
-         */
-        private var customFilterColorSubscription: Subscription? = null
-
         /**
          * Initializes the reader subscriptions.
          */
@@ -627,32 +619,40 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
             subscriptions += Observable.merge(initialRotation, rotationUpdates)
                     .subscribe { setOrientation(it) }
 
-            subscriptions += preferences.readerTheme().asObservable()
-                    .skip(1) // We only care about updates
-                    .subscribe { recreate() }
+            preferences.readerTheme().asFlow()
+                .drop(1) // We only care about updates
+                .onEach { recreate() }
+                .launchIn(scope)
 
-            subscriptions += preferences.showPageNumber().asObservable()
-                    .subscribe { setPageNumberVisibility(it) }
+            preferences.showPageNumber().asFlow()
+                .onEach { setPageNumberVisibility(it) }
+                .launchIn(scope)
 
-            subscriptions += preferences.trueColor().asObservable()
-                    .subscribe { setTrueColor(it) }
+            preferences.trueColor().asFlow()
+                .onEach { setTrueColor(it) }
+                .launchIn(scope)
 
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
-                subscriptions += preferences.cutoutShort().asObservable()
-                        .subscribe { setCutoutShort(it) }
+                preferences.cutoutShort().asFlow()
+                    .onEach { setCutoutShort(it) }
+                    .launchIn(scope)
             }
 
-            subscriptions += preferences.keepScreenOn().asObservable()
-                    .subscribe { setKeepScreenOn(it) }
+            preferences.keepScreenOn().asFlow()
+                .onEach { setKeepScreenOn(it) }
+                .launchIn(scope)
 
-            subscriptions += preferences.customBrightness().asObservable()
-                    .subscribe { setCustomBrightness(it) }
+            preferences.customBrightness().asFlow()
+                .onEach { setCustomBrightness(it) }
+                .launchIn(scope)
 
-            subscriptions += preferences.colorFilter().asObservable()
-                    .subscribe { setColorFilter(it) }
+            preferences.colorFilter().asFlow()
+                .onEach { setColorFilter(it) }
+                .launchIn(scope)
 
-            subscriptions += preferences.colorFilterMode().asObservable()
-                    .subscribe { setColorFilter(preferences.colorFilter().getOrDefault()) }
+            preferences.colorFilterMode().asFlow()
+                .onEach { setColorFilter(preferences.colorFilter().get()) }
+                .launchIn(scope)
         }
 
         /**
@@ -660,8 +660,6 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
          */
         fun destroy() {
             subscriptions.unsubscribe()
-            customBrightnessSubscription = null
-            customFilterColorSubscription = null
         }
 
         /**
@@ -732,13 +730,11 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
          */
         private fun setCustomBrightness(enabled: Boolean) {
             if (enabled) {
-                customBrightnessSubscription = preferences.customBrightnessValue().asObservable()
-                        .sample(100, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
-                        .subscribe { setCustomBrightnessValue(it) }
-
-                subscriptions.add(customBrightnessSubscription)
+                preferences.customBrightnessValue().asFlow()
+                    .sample(100)
+                    .onEach { setCustomBrightnessValue(it) }
+                    .launchIn(scope)
             } else {
-                customBrightnessSubscription?.let { subscriptions.remove(it) }
                 setCustomBrightnessValue(0)
             }
         }
@@ -748,13 +744,11 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
          */
         private fun setColorFilter(enabled: Boolean) {
             if (enabled) {
-                customFilterColorSubscription = preferences.colorFilterValue().asObservable()
-                        .sample(100, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
-                        .subscribe { setColorFilterValue(it) }
-
-                subscriptions.add(customFilterColorSubscription)
+                preferences.colorFilterValue().asFlow()
+                    .sample(100)
+                    .onEach { setColorFilterValue(it) }
+                    .launchIn(scope)
             } else {
-                customFilterColorSubscription?.let { subscriptions.remove(it) }
                 binding.colorOverlay.gone()
             }
         }
@@ -794,7 +788,7 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
          */
         private fun setColorFilterValue(value: Int) {
             binding.colorOverlay.visible()
-            binding.colorOverlay.setFilterColor(value, preferences.colorFilterMode().getOrDefault())
+            binding.colorOverlay.setFilterColor(value, preferences.colorFilterMode().get())
         }
     }
 }

+ 32 - 63
app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderColorFilterSheet.kt

@@ -9,13 +9,10 @@ import com.google.android.material.bottomsheet.BottomSheetBehavior
 import com.google.android.material.bottomsheet.BottomSheetDialog
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.preference.PreferencesHelper
-import eu.kanade.tachiyomi.data.preference.getOrDefault
-import eu.kanade.tachiyomi.util.lang.plusAssign
 import eu.kanade.tachiyomi.util.view.gone
 import eu.kanade.tachiyomi.util.view.visible
 import eu.kanade.tachiyomi.widget.IgnoreFirstSpinnerListener
 import eu.kanade.tachiyomi.widget.SimpleSeekBarListener
-import java.util.concurrent.TimeUnit
 import kotlin.math.abs
 import kotlinx.android.synthetic.main.reader_color_filter.brightness_seekbar
 import kotlinx.android.synthetic.main.reader_color_filter.color_filter_mode
@@ -32,54 +29,41 @@ import kotlinx.android.synthetic.main.reader_color_filter.txt_color_filter_green
 import kotlinx.android.synthetic.main.reader_color_filter.txt_color_filter_red_value
 import kotlinx.android.synthetic.main.reader_color_filter_sheet.brightness_overlay
 import kotlinx.android.synthetic.main.reader_color_filter_sheet.color_overlay
-import rx.Subscription
-import rx.android.schedulers.AndroidSchedulers
-import rx.subscriptions.CompositeSubscription
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.sample
 import uy.kohesive.injekt.injectLazy
 
 /**
  * Color filter sheet to toggle custom filter and brightness overlay.
  */
-class ReaderColorFilterSheet(activity: ReaderActivity) : BottomSheetDialog(activity) {
+class ReaderColorFilterSheet(private val activity: ReaderActivity) : BottomSheetDialog(activity) {
 
     private val preferences by injectLazy<PreferencesHelper>()
 
     private var sheetBehavior: BottomSheetBehavior<*>? = null
 
-    /**
-     * Subscriptions used for this dialog
-     */
-    private val subscriptions = CompositeSubscription()
-
-    /**
-     * Subscription used for custom brightness overlay
-     */
-    private var customBrightnessSubscription: Subscription? = null
-
-    /**
-     * Subscription used for color filter overlay
-     */
-    private var customFilterColorSubscription: Subscription? = null
-
     init {
         val view = activity.layoutInflater.inflate(R.layout.reader_color_filter_sheet, null)
         setContentView(view)
 
         sheetBehavior = BottomSheetBehavior.from(view.parent as ViewGroup)
 
-        // Initialize subscriptions.
-        subscriptions += preferences.colorFilter().asObservable()
-                .subscribe { setColorFilter(it, view) }
+        preferences.colorFilter().asFlow()
+            .onEach { setColorFilter(it, view) }
+            .launchIn(activity.scope)
 
-        subscriptions += preferences.colorFilterMode().asObservable()
-                .subscribe { setColorFilter(preferences.colorFilter().getOrDefault(), view) }
+        preferences.colorFilterMode().asFlow()
+            .onEach { setColorFilter(preferences.colorFilter().get(), view) }
+            .launchIn(activity.scope)
 
-        subscriptions += preferences.customBrightness().asObservable()
-                .subscribe { setCustomBrightness(it, view) }
+        preferences.customBrightness().asFlow()
+            .onEach { setCustomBrightness(it, view) }
+            .launchIn(activity.scope)
 
         // Get color and update values
-        val color = preferences.colorFilterValue().getOrDefault()
-        val brightness = preferences.customBrightnessValue().getOrDefault()
+        val color = preferences.colorFilterValue().get()
+        val brightness = preferences.customBrightnessValue().get()
 
         val argb = setValues(color, view)
 
@@ -94,12 +78,12 @@ class ReaderColorFilterSheet(activity: ReaderActivity) : BottomSheetDialog(activ
         seekbar_color_filter_blue.progress = argb[3]
 
         // Set listeners
-        switch_color_filter.isChecked = preferences.colorFilter().getOrDefault()
+        switch_color_filter.isChecked = preferences.colorFilter().get()
         switch_color_filter.setOnCheckedChangeListener { _, isChecked ->
             preferences.colorFilter().set(isChecked)
         }
 
-        custom_brightness.isChecked = preferences.customBrightness().getOrDefault()
+        custom_brightness.isChecked = preferences.customBrightness().get()
         custom_brightness.setOnCheckedChangeListener { _, isChecked ->
             preferences.customBrightness().set(isChecked)
         }
@@ -107,7 +91,7 @@ class ReaderColorFilterSheet(activity: ReaderActivity) : BottomSheetDialog(activ
         color_filter_mode.onItemSelectedListener = IgnoreFirstSpinnerListener { position ->
             preferences.colorFilterMode().set(position)
         }
-        color_filter_mode.setSelection(preferences.colorFilterMode().getOrDefault(), false)
+        color_filter_mode.setSelection(preferences.colorFilterMode().get(), false)
 
         seekbar_color_filter_alpha.setOnSeekBarChangeListener(object : SimpleSeekBarListener() {
             override fun onProgressChanged(seekBar: SeekBar, value: Int, fromUser: Boolean) {
@@ -156,13 +140,6 @@ class ReaderColorFilterSheet(activity: ReaderActivity) : BottomSheetDialog(activ
         sheetBehavior?.state = BottomSheetBehavior.STATE_EXPANDED
     }
 
-    override fun onDetachedFromWindow() {
-        super.onDetachedFromWindow()
-        subscriptions.unsubscribe()
-        customBrightnessSubscription = null
-        customFilterColorSubscription = null
-    }
-
     /**
      * Set enabled status of seekBars belonging to color filter
      * @param enabled determines if seekBar gets enabled
@@ -196,15 +173,11 @@ class ReaderColorFilterSheet(activity: ReaderActivity) : BottomSheetDialog(activ
         val blue = getBlueFromColor(color)
 
         // Initialize values
-        with(view) {
-            txt_color_filter_alpha_value.text = alpha.toString()
-
-            txt_color_filter_red_value.text = red.toString()
+        txt_color_filter_alpha_value.text = alpha.toString()
+        txt_color_filter_red_value.text = red.toString()
+        txt_color_filter_green_value.text = green.toString()
+        txt_color_filter_blue_value.text = blue.toString()
 
-            txt_color_filter_green_value.text = green.toString()
-
-            txt_color_filter_blue_value.text = blue.toString()
-        }
         return arrayOf(alpha, red, green, blue)
     }
 
@@ -215,13 +188,11 @@ class ReaderColorFilterSheet(activity: ReaderActivity) : BottomSheetDialog(activ
      */
     private fun setCustomBrightness(enabled: Boolean, view: View) {
         if (enabled) {
-            customBrightnessSubscription = preferences.customBrightnessValue().asObservable()
-                    .sample(100, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
-                    .subscribe { setCustomBrightnessValue(it, view) }
-
-            subscriptions.add(customBrightnessSubscription)
+            preferences.customBrightnessValue().asFlow()
+                .sample(100)
+                .onEach { setCustomBrightnessValue(it, view) }
+                .launchIn(activity.scope)
         } else {
-            customBrightnessSubscription?.let { subscriptions.remove(it) }
             setCustomBrightnessValue(0, view, true)
         }
         setCustomBrightnessSeekBar(enabled, view)
@@ -254,13 +225,11 @@ class ReaderColorFilterSheet(activity: ReaderActivity) : BottomSheetDialog(activ
      */
     private fun setColorFilter(enabled: Boolean, view: View) {
         if (enabled) {
-            customFilterColorSubscription = preferences.colorFilterValue().asObservable()
-                    .sample(100, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
-                    .subscribe { setColorFilterValue(it, view) }
-
-            subscriptions.add(customFilterColorSubscription)
+            preferences.colorFilterValue().asFlow()
+                .sample(100)
+                .onEach { setColorFilterValue(it, view) }
+                .launchIn(activity.scope)
         } else {
-            customFilterColorSubscription?.let { subscriptions.remove(it) }
             color_overlay.gone()
         }
         setColorFilterSeekBar(enabled, view)
@@ -273,7 +242,7 @@ class ReaderColorFilterSheet(activity: ReaderActivity) : BottomSheetDialog(activ
      */
     private fun setColorFilterValue(@ColorInt color: Int, view: View) = with(view) {
         color_overlay.visible()
-        color_overlay.setFilterColor(color, preferences.colorFilterMode().getOrDefault())
+        color_overlay.setFilterColor(color, preferences.colorFilterMode().get())
         setValues(color, view)
     }
 
@@ -284,7 +253,7 @@ class ReaderColorFilterSheet(activity: ReaderActivity) : BottomSheetDialog(activ
      * @param bitShift amounts of bits that gets shifted to receive value
      */
     fun setColorValue(color: Int, mask: Long, bitShift: Int) {
-        val currentColor = preferences.colorFilterValue().getOrDefault()
+        val currentColor = preferences.colorFilterValue().get()
         val updatedColor = (color shl bitShift) or (currentColor and mask.inv().toInt())
         preferences.colorFilterValue().set(updatedColor)
     }

+ 16 - 5
app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderSettingsSheet.kt

@@ -6,8 +6,9 @@ import android.widget.CompoundButton
 import android.widget.Spinner
 import androidx.annotation.ArrayRes
 import androidx.core.widget.NestedScrollView
-import com.f2prateek.rx.preferences.Preference
+import com.f2prateek.rx.preferences.Preference as RxPreference
 import com.google.android.material.bottomsheet.BottomSheetDialog
+import com.tfcporciuncula.flow.Preference
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 import eu.kanade.tachiyomi.data.preference.getOrDefault
@@ -121,20 +122,30 @@ class ReaderSettingsSheet(private val activity: ReaderActivity) : BottomSheetDia
      * Binds a checkbox or switch view with a boolean preference.
      */
     private fun CompoundButton.bindToPreference(pref: Preference<Boolean>) {
-        isChecked = pref.getOrDefault()
+        isChecked = pref.get()
         setOnCheckedChangeListener { _, isChecked -> pref.set(isChecked) }
     }
 
     /**
      * Binds a spinner to an int preference with an optional offset for the value.
      */
-    private fun Spinner.bindToPreference(pref: Preference<Int>, offset: Int = 0) {
+    private fun Spinner.bindToPreference(pref: RxPreference<Int>, offset: Int = 0) {
         onItemSelectedListener = IgnoreFirstSpinnerListener { position ->
             pref.set(position + offset)
         }
         setSelection(pref.getOrDefault() - offset, false)
     }
 
+    /**
+     * Binds a spinner to an int preference with an optional offset for the value.
+     */
+    private fun Spinner.bindToPreference(pref: Preference<Int>, offset: Int = 0) {
+        onItemSelectedListener = IgnoreFirstSpinnerListener { position ->
+            pref.set(position + offset)
+        }
+        setSelection(pref.get() - offset, false)
+    }
+
     /**
      * Binds a spinner to an int preference. The position of the spinner item must
      * correlate with the [intValues] resource item (in arrays.xml), which is a <string-array>
@@ -143,8 +154,8 @@ class ReaderSettingsSheet(private val activity: ReaderActivity) : BottomSheetDia
     private fun Spinner.bindToIntPreference(pref: Preference<Int>, @ArrayRes intValuesResource: Int) {
         val intValues = resources.getStringArray(intValuesResource).map { it.toIntOrNull() }
         onItemSelectedListener = IgnoreFirstSpinnerListener { position ->
-            pref.set(intValues[position])
+            pref.set(intValues[position]!!)
         }
-        setSelection(intValues.indexOf(pref.getOrDefault()), false)
+        setSelection(intValues.indexOf(pref.get()), false)
     }
 }

+ 17 - 26
app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ViewerConfig.kt

@@ -2,20 +2,24 @@ package eu.kanade.tachiyomi.ui.reader.viewer
 
 import com.tfcporciuncula.flow.Preference
 import eu.kanade.tachiyomi.data.preference.PreferencesHelper
-import eu.kanade.tachiyomi.util.lang.addTo
-import eu.kanade.tachiyomi.util.lang.launchInUI
-import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
-import rx.subscriptions.CompositeSubscription
 
+/**
+ * Common configuration for all viewers.
+ */
 abstract class ViewerConfig(preferences: PreferencesHelper) {
 
-    private val subscriptions = CompositeSubscription()
+    private val scope = CoroutineScope(Job() + Dispatchers.Main)
 
     var imagePropertyChangedListener: (() -> Unit)? = null
 
     var tappingEnabled = true
     var longTapEnabled = true
+    var doubleTapAnimDuration = 500
     var volumeKeysEnabled = false
     var volumeKeysInverted = false
     var alwaysShowChapterTransition = true
@@ -27,6 +31,9 @@ abstract class ViewerConfig(preferences: PreferencesHelper) {
         preferences.readWithLongTap()
             .register({ longTapEnabled = it })
 
+        preferences.doubleTapAnimSpeed()
+            .register({ doubleTapAnimDuration = it })
+
         preferences.readWithVolumeKeys()
             .register({ volumeKeysEnabled = it })
 
@@ -37,31 +44,15 @@ abstract class ViewerConfig(preferences: PreferencesHelper) {
             .register({ alwaysShowChapterTransition = it })
     }
 
-    fun unsubscribe() {
-        subscriptions.unsubscribe()
-    }
-
-    fun <T> com.f2prateek.rx.preferences.Preference<T>.register(
-        valueAssignment: (T) -> Unit,
-        onChanged: (T) -> Unit = {}
-    ) {
-        asObservable()
-            .doOnNext(valueAssignment)
-            .skip(1)
-            .distinctUntilChanged()
-            .doOnNext(onChanged)
-            .subscribe()
-            .addTo(subscriptions)
-    }
-
     fun <T> Preference<T>.register(
         valueAssignment: (T) -> Unit,
         onChanged: (T) -> Unit = {}
     ) {
         asFlow()
-            .onEach { valueAssignment(it) }
-            .distinctUntilChanged()
-            .onEach { onChanged(it) }
-            .launchInUI()
+            .onEach {
+                valueAssignment(it)
+                onChanged(it)
+            }
+            .launchIn(scope)
     }
 }

+ 4 - 10
app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerConfig.kt

@@ -23,24 +23,18 @@ class PagerConfig(private val viewer: PagerViewer, preferences: PreferencesHelpe
     var imageCropBorders = false
         private set
 
-    var doubleTapAnimDuration = 500
-        private set
-
     init {
         preferences.pageTransitions()
-                .register({ usePageTransitions = it })
+            .register({ usePageTransitions = it })
 
         preferences.imageScaleType()
-                .register({ imageScaleType = it }, { imagePropertyChangedListener?.invoke() })
+            .register({ imageScaleType = it }, { imagePropertyChangedListener?.invoke() })
 
         preferences.zoomStart()
-                .register({ zoomTypeFromPreference(it) }, { imagePropertyChangedListener?.invoke() })
+            .register({ zoomTypeFromPreference(it) }, { imagePropertyChangedListener?.invoke() })
 
         preferences.cropBorders()
-                .register({ imageCropBorders = it }, { imagePropertyChangedListener?.invoke() })
-
-        preferences.doubleTapAnimSpeed()
-                .register({ doubleTapAnimDuration = it })
+            .register({ imageCropBorders = it }, { imagePropertyChangedListener?.invoke() })
     }
 
     private fun zoomTypeFromPreference(value: Int) {

+ 0 - 8
app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt

@@ -115,14 +115,6 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer {
         return pager
     }
 
-    /**
-     * Destroys this viewer. Called when leaving the reader or swapping viewers.
-     */
-    override fun destroy() {
-        super.destroy()
-        config.unsubscribe()
-    }
-
     /**
      * Called when a new page (either a [ReaderPage] or [ChapterTransition]) is marked as active
      */

+ 0 - 21
app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonConfig.kt

@@ -13,34 +13,13 @@ class WebtoonConfig(preferences: PreferencesHelper = Injekt.get()) : ViewerConfi
     var imageCropBorders = false
         private set
 
-    var doubleTapAnimDuration = 500
-        private set
-
     var sidePadding = 0
         private set
 
     init {
-        preferences.readWithTapping()
-            .register({ tappingEnabled = it })
-
-        preferences.readWithLongTap()
-            .register({ longTapEnabled = it })
-
         preferences.cropBordersWebtoon()
             .register({ imageCropBorders = it }, { imagePropertyChangedListener?.invoke() })
 
-        preferences.doubleTapAnimSpeed()
-            .register({ doubleTapAnimDuration = it })
-
-        preferences.readWithVolumeKeys()
-            .register({ volumeKeysEnabled = it })
-
-        preferences.readWithVolumeKeysInverted()
-            .register({ volumeKeysInverted = it })
-
-        preferences.alwaysShowChapterTransition()
-            .register({ alwaysShowChapterTransition = it })
-
         preferences.webtoonSidePadding()
             .register({ sidePadding = it }, { imagePropertyChangedListener?.invoke() })
     }

+ 0 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt

@@ -155,7 +155,6 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr
      */
     override fun destroy() {
         super.destroy()
-        config.unsubscribe()
         subscriptions.unsubscribe()
     }
 

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

@@ -24,9 +24,9 @@ import eu.kanade.tachiyomi.ui.base.controller.RootController
 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
@@ -97,7 +97,7 @@ class UpdatesController : NucleusController<UpdatesControllerBinding, UpdatesPre
                 val firstPos = layoutManager.findFirstCompletelyVisibleItemPosition()
                 binding.swipeRefresh.isEnabled = firstPos <= 0
             }
-            .launchInUI()
+            .launchIn(scope)
 
         binding.swipeRefresh.setDistanceToTriggerSync((2 * 64 * view.resources.displayMetrics.density).toInt())
         binding.swipeRefresh.refreshes()
@@ -107,7 +107,7 @@ class UpdatesController : NucleusController<UpdatesControllerBinding, UpdatesPre
                 // It can be a very long operation, so we disable swipe refresh and show a toast.
                 binding.swipeRefresh.isRefreshing = false
             }
-            .launchInUI()
+            .launchIn(scope)
     }
 
     override fun onDestroyView(view: View) {

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

@@ -15,6 +15,9 @@ 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 kotlinx.coroutines.Job
 import rx.Observable
 import rx.Subscription
 import rx.subscriptions.CompositeSubscription
@@ -24,6 +27,7 @@ import uy.kohesive.injekt.api.get
 abstract class SettingsController : PreferenceController() {
 
     val preferences: PreferencesHelper = Injekt.get()
+    val scope = CoroutineScope(Job() + Dispatchers.Main)
 
     var untilDestroySubscriptions = CompositeSubscription()
         private set
@@ -78,10 +82,6 @@ abstract class SettingsController : PreferenceController() {
         super.onChangeStarted(handler, type)
     }
 
-    fun <T> Observable<T>.subscribeUntilDestroy(): Subscription {
-        return subscribe().also { untilDestroySubscriptions.add(it) }
-    }
-
     fun <T> Observable<T>.subscribeUntilDestroy(onNext: (T) -> Unit): Subscription {
         return subscribe(onNext).also { untilDestroySubscriptions.add(it) }
     }

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

@@ -7,7 +7,6 @@ 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
@@ -19,6 +18,7 @@ import eu.kanade.tachiyomi.util.preference.preferenceCategory
 import eu.kanade.tachiyomi.util.preference.switchPreference
 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() {
@@ -147,7 +147,7 @@ class SettingsGeneralController : SettingsController() {
                 isVisible = preferences.themeMode().get() != Values.THEME_MODE_DARK
                 preferences.themeMode().asFlow()
                     .onEach { isVisible = it != Values.THEME_MODE_DARK }
-                    .launchInUI()
+                    .launchIn(scope)
 
                 onChange {
                     if (preferences.themeMode().get() != Values.THEME_MODE_DARK) {
@@ -173,7 +173,7 @@ class SettingsGeneralController : SettingsController() {
                 isVisible = preferences.themeMode().get() != Values.THEME_MODE_LIGHT
                 preferences.themeMode().asFlow()
                     .onEach { isVisible = it != Values.THEME_MODE_LIGHT }
-                    .launchInUI()
+                    .launchIn(scope)
 
                 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 }
-                    .launchInUI()
+                    .launchIn(scope)
             }
         }
 

+ 4 - 5
app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsSourcesController.kt

@@ -5,7 +5,6 @@ import androidx.preference.CheckBoxPreference
 import androidx.preference.PreferenceGroup
 import androidx.preference.PreferenceScreen
 import eu.kanade.tachiyomi.R
-import eu.kanade.tachiyomi.data.preference.getOrDefault
 import eu.kanade.tachiyomi.source.SourceManager
 import eu.kanade.tachiyomi.source.icon
 import eu.kanade.tachiyomi.source.online.HttpSource
@@ -25,7 +24,7 @@ class SettingsSourcesController : SettingsController() {
         titleRes = R.string.action_filter
 
         // Get the list of active language codes.
-        val activeLangsCodes = preferences.enabledLanguages().getOrDefault()
+        val activeLangsCodes = preferences.enabledLanguages().get()
 
         // Get a map of sources grouped by language.
         val sourcesByLang = onlineSources.groupByTo(TreeMap(), { it.lang })
@@ -49,7 +48,7 @@ class SettingsSourcesController : SettingsController() {
 
                 onChange { newValue ->
                     val checked = newValue as Boolean
-                    val current = preferences.enabledLanguages().getOrDefault()
+                    val current = preferences.enabledLanguages().get()
                     if (!checked) {
                         preferences.enabledLanguages().set(current - lang)
                         removeAll()
@@ -73,7 +72,7 @@ class SettingsSourcesController : SettingsController() {
      * @param group the language category.
      */
     private fun addLanguageSources(group: PreferenceGroup, sources: List<HttpSource>) {
-        val hiddenCatalogues = preferences.hiddenCatalogues().getOrDefault()
+        val hiddenCatalogues = preferences.hiddenCatalogues().get()
 
         sources.forEach { source ->
             val sourcePreference = CheckBoxPreference(group.context).apply {
@@ -90,7 +89,7 @@ class SettingsSourcesController : SettingsController() {
 
                 onChange { newValue ->
                     val checked = newValue as Boolean
-                    val current = preferences.hiddenCatalogues().getOrDefault()
+                    val current = preferences.hiddenCatalogues().get()
 
                     preferences.hiddenCatalogues().set(if (checked)
                         current - id

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

@@ -19,7 +19,6 @@ import eu.davidea.flexibleadapter.FlexibleAdapter
 import eu.davidea.flexibleadapter.items.IFlexible
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.preference.PreferencesHelper
-import eu.kanade.tachiyomi.data.preference.getOrDefault
 import eu.kanade.tachiyomi.databinding.SourceMainControllerBinding
 import eu.kanade.tachiyomi.source.CatalogueSource
 import eu.kanade.tachiyomi.source.Source
@@ -31,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
@@ -141,14 +140,14 @@ class SourceController : NucleusController<SourceMainControllerBinding, SourcePr
     }
 
     private fun hideCatalogue(source: Source) {
-        val current = preferences.hiddenCatalogues().getOrDefault()
+        val current = preferences.hiddenCatalogues().get()
         preferences.hiddenCatalogues().set(current + source.id.toString())
 
         presenter.updateSources()
     }
 
     private fun pinCatalogue(source: Source, isPinned: Boolean) {
-        val current = preferences.pinnedCatalogues().getOrDefault()
+        val current = preferences.pinnedCatalogues().get()
         if (isPinned) {
             preferences.pinnedCatalogues().set(current - source.id.toString())
         } else {
@@ -202,7 +201,7 @@ class SourceController : NucleusController<SourceMainControllerBinding, SourcePr
         searchView.queryTextEvents()
             .filter { it is QueryTextEvent.QuerySubmitted }
             .onEach { performGlobalSearch(it.queryText.toString()) }
-            .launchInUI()
+            .launchIn(scope)
     }
 
     fun performGlobalSearch(query: String) {

+ 3 - 4
app/src/main/java/eu/kanade/tachiyomi/ui/source/SourcePresenter.kt

@@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.ui.source
 
 import android.os.Bundle
 import eu.kanade.tachiyomi.data.preference.PreferencesHelper
-import eu.kanade.tachiyomi.data.preference.getOrDefault
 import eu.kanade.tachiyomi.source.CatalogueSource
 import eu.kanade.tachiyomi.source.LocalSource
 import eu.kanade.tachiyomi.source.SourceManager
@@ -49,7 +48,7 @@ class SourcePresenter(
         sourceSubscription?.unsubscribe()
 
         val pinnedSources = mutableListOf<SourceItem>()
-        val pinnedCatalogues = preferences.pinnedCatalogues().getOrDefault()
+        val pinnedCatalogues = preferences.pinnedCatalogues().get()
 
         val map = TreeMap<String, MutableList<CatalogueSource>> { d1, d2 ->
             // Catalogues without a lang defined will be placed at the end
@@ -102,8 +101,8 @@ class SourcePresenter(
      * @return list containing enabled sources.
      */
     private fun getEnabledSources(): List<CatalogueSource> {
-        val languages = preferences.enabledLanguages().getOrDefault()
-        val hiddenCatalogues = preferences.hiddenCatalogues().getOrDefault()
+        val languages = preferences.enabledLanguages().get()
+        val hiddenCatalogues = preferences.hiddenCatalogues().get()
 
         return sourceManager.getCatalogueSources()
                 .filter { it.lang in languages }

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

@@ -32,7 +32,6 @@ 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
@@ -43,6 +42,7 @@ 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
@@ -241,7 +241,7 @@ open class BrowseSourceController(bundle: Bundle) :
             .filter { router.backstack.lastOrNull()?.controller() == this@BrowseSourceController }
             .filter { it is QueryTextEvent.QuerySubmitted }
             .onEach { searchWithQuery(it.queryText.toString()) }
-            .launchInUI()
+            .launchIn(scope)
 
         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
@@ -120,7 +120,7 @@ open class GlobalSearchController(
                 searchItem.collapseActionView()
                 setTitle() // Update toolbar title
             }
-            .launchInUI()
+            .launchIn(scope)
     }
 
     /**

+ 3 - 4
app/src/main/java/eu/kanade/tachiyomi/ui/source/global_search/GlobalSearchPresenter.kt

@@ -4,7 +4,6 @@ import android.os.Bundle
 import eu.kanade.tachiyomi.data.database.DatabaseHelper
 import eu.kanade.tachiyomi.data.database.models.Manga
 import eu.kanade.tachiyomi.data.preference.PreferencesHelper
-import eu.kanade.tachiyomi.data.preference.getOrDefault
 import eu.kanade.tachiyomi.extension.ExtensionManager
 import eu.kanade.tachiyomi.source.CatalogueSource
 import eu.kanade.tachiyomi.source.Source
@@ -100,9 +99,9 @@ open class GlobalSearchPresenter(
      * @return list containing enabled sources.
      */
     protected open fun getEnabledSources(): List<CatalogueSource> {
-        val languages = preferences.enabledLanguages().getOrDefault()
-        val hiddenCatalogues = preferences.hiddenCatalogues().getOrDefault()
-        val pinnedCatalogues = preferences.pinnedCatalogues().getOrDefault()
+        val languages = preferences.enabledLanguages().get()
+        val hiddenCatalogues = preferences.hiddenCatalogues().get()
+        val pinnedCatalogues = preferences.pinnedCatalogues().get()
 
         return sourceManager.getCatalogueSources()
                 .filter { it.lang in languages }

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

@@ -6,14 +6,8 @@ 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)