Migrate more preferences

This commit is contained in:
arkon 2020-04-18 11:16:26 -04:00
parent 04a178e7da
commit 53a3be0703
34 changed files with 218 additions and 295 deletions

View File

@ -76,51 +76,53 @@ class PreferencesHelper(val context: Context) {
fun rotation() = rxPrefs.getInteger(Keys.rotation, 1) 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 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) fun portraitColumns() = rxPrefs.getInteger(Keys.portraitColumns, 0)
@ -132,13 +134,13 @@ class PreferencesHelper(val context: Context) {
fun lastUsedCatalogueSource() = rxPrefs.getLong(Keys.lastUsedCatalogueSource, -1) 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 lastVersionCode() = flowPrefs.getInt("last_version_code", 0)
fun catalogueAsList() = rxPrefs.getBoolean(Keys.catalogueAsList, false) 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), "") 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 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) 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 migrateFlags() = flowPrefs.getInt("migrate_flags", Int.MAX_VALUE)
fun trustedSignatures() = flowPrefs.getStringSet("trusted_signatures", emptySet()) fun trustedSignatures() = flowPrefs.getStringSet("trusted_signatures", emptySet())
fun alwaysShowChapterTransition() = rxPrefs.getBoolean(Keys.alwaysShowChapterTransition, true)
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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.database.models.Manga
import eu.kanade.tachiyomi.data.library.LibraryUpdateService import eu.kanade.tachiyomi.data.library.LibraryUpdateService
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.databinding.LibraryControllerBinding import eu.kanade.tachiyomi.databinding.LibraryControllerBinding
import eu.kanade.tachiyomi.ui.base.controller.NucleusController import eu.kanade.tachiyomi.ui.base.controller.NucleusController
import eu.kanade.tachiyomi.ui.base.controller.RootController 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.base.controller.withFadeTransaction
import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.manga.MangaController 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.getResourceColor
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import java.io.IOException import java.io.IOException
import kotlinx.android.synthetic.main.main_activity.tabs import kotlinx.android.synthetic.main.main_activity.tabs
import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import reactivecircus.flowbinding.appcompat.queryTextChanges import reactivecircus.flowbinding.appcompat.queryTextChanges
import reactivecircus.flowbinding.viewpager.pageSelections import reactivecircus.flowbinding.viewpager.pageSelections
@ -61,8 +60,7 @@ class LibraryController(
/** /**
* Position of the active category. * Position of the active category.
*/ */
var activeCategory: Int = preferences.lastUsedCategory().getOrDefault() private var activeCategory: Int = preferences.lastUsedCategory().get()
private set
/** /**
* Action mode for selections. * Action mode for selections.
@ -154,7 +152,7 @@ class LibraryController(
preferences.lastUsedCategory().set(it) preferences.lastUsedCategory().set(it)
activeCategory = it activeCategory = it
} }
.launchInUI() .launchIn(scope)
getColumnsPreferenceForCurrentOrientation().asObservable() getColumnsPreferenceForCurrentOrientation().asObservable()
.doOnNext { mangaPerRow = it } .doOnNext { mangaPerRow = it }
@ -334,7 +332,7 @@ class LibraryController(
query = it.toString() query = it.toString()
searchRelay.call(query) searchRelay.call(query)
} }
.launchInUI() .launchIn(scope)
if (query.isNotEmpty()) { if (query.isNotEmpty()) {
searchItem.expandActionView() searchItem.expandActionView()

View File

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

View File

@ -26,7 +26,6 @@ import eu.kanade.tachiyomi.databinding.ChaptersControllerBinding
import eu.kanade.tachiyomi.ui.base.controller.NucleusController import eu.kanade.tachiyomi.ui.base.controller.NucleusController
import eu.kanade.tachiyomi.ui.manga.MangaController import eu.kanade.tachiyomi.ui.manga.MangaController
import eu.kanade.tachiyomi.ui.reader.ReaderActivity 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.getResourceColor
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.util.view.getCoordinates 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.shrinkOnScroll
import eu.kanade.tachiyomi.util.view.snack import eu.kanade.tachiyomi.util.view.snack
import eu.kanade.tachiyomi.util.view.visible import eu.kanade.tachiyomi.util.view.visible
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import reactivecircus.flowbinding.android.view.clicks import reactivecircus.flowbinding.android.view.clicks
import reactivecircus.flowbinding.swiperefreshlayout.refreshes import reactivecircus.flowbinding.swiperefreshlayout.refreshes
@ -92,7 +92,7 @@ class ChaptersController : NucleusController<ChaptersControllerBinding, Chapters
binding.swipeRefresh.refreshes() binding.swipeRefresh.refreshes()
.onEach { fetchChaptersFromSource() } .onEach { fetchChaptersFromSource() }
.launchInUI() .launchIn(scope)
binding.fab.clicks() binding.fab.clicks()
.onEach { .onEach {
@ -114,7 +114,7 @@ class ChaptersController : NucleusController<ChaptersControllerBinding, Chapters
view.context.toast(R.string.no_next_chapter) view.context.toast(R.string.no_next_chapter)
} }
} }
.launchInUI() .launchIn(scope)
binding.fab.shrinkOnScroll(binding.recycler) binding.fab.shrinkOnScroll(binding.recycler)
} }

View File

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

View File

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

View File

@ -11,7 +11,6 @@ import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.data.track.TrackService import eu.kanade.tachiyomi.data.track.TrackService
import eu.kanade.tachiyomi.data.track.model.TrackSearch import eu.kanade.tachiyomi.data.track.model.TrackSearch
import eu.kanade.tachiyomi.ui.base.controller.DialogController 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.invisible
import eu.kanade.tachiyomi.util.view.visible import eu.kanade.tachiyomi.util.view.visible
import java.util.concurrent.TimeUnit 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.android.synthetic.main.track_search_dialog.view.track_search_list
import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import reactivecircus.flowbinding.android.widget.itemClicks import reactivecircus.flowbinding.android.widget.itemClicks
@ -78,7 +78,7 @@ class TrackSearchDialog : DialogController {
.onEach { position -> .onEach { position ->
selectedItem = adapter.getItem(position) selectedItem = adapter.getItem(position)
} }
.launchInUI() .launchIn(trackController.scope)
// Do an initial search based on the manga's title // Do an initial search based on the manga's title
if (savedState == null) { if (savedState == null) {
@ -101,7 +101,7 @@ class TrackSearchDialog : DialogController {
.map { it.toString() } .map { it.toString() }
.filter { it.isNotBlank() } .filter { it.isNotBlank() }
.onEach { search(it) } .onEach { search(it) }
.launchInUI() .launchIn(trackController.scope)
} }
private fun search(query: String) { private fun search(query: String) {

View File

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

View File

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

View File

@ -6,8 +6,9 @@ import android.widget.CompoundButton
import android.widget.Spinner import android.widget.Spinner
import androidx.annotation.ArrayRes import androidx.annotation.ArrayRes
import androidx.core.widget.NestedScrollView 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.google.android.material.bottomsheet.BottomSheetDialog
import com.tfcporciuncula.flow.Preference
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault import eu.kanade.tachiyomi.data.preference.getOrDefault
@ -121,10 +122,20 @@ class ReaderSettingsSheet(private val activity: ReaderActivity) : BottomSheetDia
* Binds a checkbox or switch view with a boolean preference. * Binds a checkbox or switch view with a boolean preference.
*/ */
private fun CompoundButton.bindToPreference(pref: Preference<Boolean>) { private fun CompoundButton.bindToPreference(pref: Preference<Boolean>) {
isChecked = pref.getOrDefault() isChecked = pref.get()
setOnCheckedChangeListener { _, isChecked -> pref.set(isChecked) } setOnCheckedChangeListener { _, isChecked -> pref.set(isChecked) }
} }
/**
* Binds a spinner to an int preference with an optional offset for the value.
*/
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. * Binds a spinner to an int preference with an optional offset for the value.
*/ */
@ -132,7 +143,7 @@ class ReaderSettingsSheet(private val activity: ReaderActivity) : BottomSheetDia
onItemSelectedListener = IgnoreFirstSpinnerListener { position -> onItemSelectedListener = IgnoreFirstSpinnerListener { position ->
pref.set(position + offset) pref.set(position + offset)
} }
setSelection(pref.getOrDefault() - offset, false) setSelection(pref.get() - offset, false)
} }
/** /**
@ -143,8 +154,8 @@ class ReaderSettingsSheet(private val activity: ReaderActivity) : BottomSheetDia
private fun Spinner.bindToIntPreference(pref: Preference<Int>, @ArrayRes intValuesResource: Int) { private fun Spinner.bindToIntPreference(pref: Preference<Int>, @ArrayRes intValuesResource: Int) {
val intValues = resources.getStringArray(intValuesResource).map { it.toIntOrNull() } val intValues = resources.getStringArray(intValuesResource).map { it.toIntOrNull() }
onItemSelectedListener = IgnoreFirstSpinnerListener { position -> onItemSelectedListener = IgnoreFirstSpinnerListener { position ->
pref.set(intValues[position]) pref.set(intValues[position]!!)
} }
setSelection(intValues.indexOf(pref.getOrDefault()), false) setSelection(intValues.indexOf(pref.get()), false)
} }
} }

View File

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

View File

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

View File

@ -115,14 +115,6 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer {
return pager 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 * Called when a new page (either a [ReaderPage] or [ChapterTransition]) is marked as active
*/ */

View File

@ -13,34 +13,13 @@ class WebtoonConfig(preferences: PreferencesHelper = Injekt.get()) : ViewerConfi
var imageCropBorders = false var imageCropBorders = false
private set private set
var doubleTapAnimDuration = 500
private set
var sidePadding = 0 var sidePadding = 0
private set private set
init { init {
preferences.readWithTapping()
.register({ tappingEnabled = it })
preferences.readWithLongTap()
.register({ longTapEnabled = it })
preferences.cropBordersWebtoon() preferences.cropBordersWebtoon()
.register({ imageCropBorders = it }, { imagePropertyChangedListener?.invoke() }) .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() preferences.webtoonSidePadding()
.register({ sidePadding = it }, { imagePropertyChangedListener?.invoke() }) .register({ sidePadding = it }, { imagePropertyChangedListener?.invoke() })
} }

View File

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

View File

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

View File

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

View File

@ -7,7 +7,6 @@ import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
import eu.kanade.tachiyomi.data.preference.PreferenceValues as Values 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.defaultValue
import eu.kanade.tachiyomi.util.preference.entriesRes import eu.kanade.tachiyomi.util.preference.entriesRes
import eu.kanade.tachiyomi.util.preference.intListPreference 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.switchPreference
import eu.kanade.tachiyomi.util.preference.titleRes import eu.kanade.tachiyomi.util.preference.titleRes
import eu.kanade.tachiyomi.util.system.LocaleHelper import eu.kanade.tachiyomi.util.system.LocaleHelper
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
class SettingsGeneralController : SettingsController() { class SettingsGeneralController : SettingsController() {
@ -147,7 +147,7 @@ class SettingsGeneralController : SettingsController() {
isVisible = preferences.themeMode().get() != Values.THEME_MODE_DARK isVisible = preferences.themeMode().get() != Values.THEME_MODE_DARK
preferences.themeMode().asFlow() preferences.themeMode().asFlow()
.onEach { isVisible = it != Values.THEME_MODE_DARK } .onEach { isVisible = it != Values.THEME_MODE_DARK }
.launchInUI() .launchIn(scope)
onChange { onChange {
if (preferences.themeMode().get() != Values.THEME_MODE_DARK) { if (preferences.themeMode().get() != Values.THEME_MODE_DARK) {
@ -173,7 +173,7 @@ class SettingsGeneralController : SettingsController() {
isVisible = preferences.themeMode().get() != Values.THEME_MODE_LIGHT isVisible = preferences.themeMode().get() != Values.THEME_MODE_LIGHT
preferences.themeMode().asFlow() preferences.themeMode().asFlow()
.onEach { isVisible = it != Values.THEME_MODE_LIGHT } .onEach { isVisible = it != Values.THEME_MODE_LIGHT }
.launchInUI() .launchIn(scope)
onChange { onChange {
if (preferences.themeMode().get() != Values.THEME_MODE_LIGHT) { if (preferences.themeMode().get() != Values.THEME_MODE_LIGHT) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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.NucleusController
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
import eu.kanade.tachiyomi.ui.manga.MangaController import eu.kanade.tachiyomi.ui.manga.MangaController
import eu.kanade.tachiyomi.util.lang.launchInUI
import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import reactivecircus.flowbinding.appcompat.QueryTextEvent import reactivecircus.flowbinding.appcompat.QueryTextEvent
import reactivecircus.flowbinding.appcompat.queryTextEvents import reactivecircus.flowbinding.appcompat.queryTextEvents
@ -120,7 +120,7 @@ open class GlobalSearchController(
searchItem.collapseActionView() searchItem.collapseActionView()
setTitle() // Update toolbar title setTitle() // Update toolbar title
} }
.launchInUI() .launchIn(scope)
} }
/** /**

View File

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

View File

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