mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-03 23:58:55 +01:00 
			
		
		
		
	Mostly migrate rxbinding to Kotlin Flow version
This commit is contained in:
		@@ -232,10 +232,15 @@ dependencies {
 | 
			
		||||
 | 
			
		||||
    // RxBindings
 | 
			
		||||
    final rxbindings_version = '1.0.1'
 | 
			
		||||
    implementation "com.jakewharton.rxbinding:rxbinding-kotlin:$rxbindings_version"
 | 
			
		||||
    implementation "com.jakewharton.rxbinding:rxbinding-appcompat-v7-kotlin:$rxbindings_version"
 | 
			
		||||
    implementation "com.jakewharton.rxbinding:rxbinding-support-v4-kotlin:$rxbindings_version"
 | 
			
		||||
    implementation "com.jakewharton.rxbinding:rxbinding-recyclerview-v7-kotlin:$rxbindings_version"
 | 
			
		||||
 | 
			
		||||
    // FlowBinding
 | 
			
		||||
    final flowbinding_version = '0.10.2'
 | 
			
		||||
    implementation "io.github.reactivecircus.flowbinding:flowbinding-android:$flowbinding_version"
 | 
			
		||||
    implementation "io.github.reactivecircus.flowbinding:flowbinding-appcompat:$flowbinding_version"
 | 
			
		||||
    implementation "io.github.reactivecircus.flowbinding:flowbinding-recyclerview:$flowbinding_version"
 | 
			
		||||
    implementation "io.github.reactivecircus.flowbinding:flowbinding-swiperefreshlayout:$flowbinding_version"
 | 
			
		||||
 | 
			
		||||
    // Tests
 | 
			
		||||
    testImplementation 'junit:junit:4.13'
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,6 @@ import androidx.appcompat.view.ActionMode
 | 
			
		||||
import androidx.recyclerview.widget.LinearLayoutManager
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
import com.google.android.material.snackbar.Snackbar
 | 
			
		||||
import com.jakewharton.rxbinding.view.clicks
 | 
			
		||||
import eu.davidea.flexibleadapter.FlexibleAdapter
 | 
			
		||||
import eu.davidea.flexibleadapter.SelectableAdapter
 | 
			
		||||
import eu.davidea.flexibleadapter.helpers.UndoHelper
 | 
			
		||||
@@ -19,6 +18,11 @@ 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.system.toast
 | 
			
		||||
import kotlinx.coroutines.CoroutineScope
 | 
			
		||||
import kotlinx.coroutines.Dispatchers
 | 
			
		||||
import kotlinx.coroutines.flow.launchIn
 | 
			
		||||
import kotlinx.coroutines.flow.onEach
 | 
			
		||||
import reactivecircus.flowbinding.android.view.clicks
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Controller to manage the categories for the users' library.
 | 
			
		||||
@@ -47,6 +51,8 @@ class CategoryController : NucleusController<CategoryPresenter>(),
 | 
			
		||||
     */
 | 
			
		||||
    private var undoHelper: UndoHelper? = null
 | 
			
		||||
 | 
			
		||||
    private val uiScope = CoroutineScope(Dispatchers.Main)
 | 
			
		||||
 | 
			
		||||
    private lateinit var binding: CategoriesControllerBinding
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -87,9 +93,11 @@ class CategoryController : NucleusController<CategoryPresenter>(),
 | 
			
		||||
        adapter?.isHandleDragEnabled = true
 | 
			
		||||
        adapter?.isPermanentDelete = false
 | 
			
		||||
 | 
			
		||||
        binding.fab.clicks().subscribeUntilDestroy {
 | 
			
		||||
            CategoryCreateDialog(this@CategoryController).showDialog(router, null)
 | 
			
		||||
        }
 | 
			
		||||
        binding.fab.clicks()
 | 
			
		||||
            .onEach {
 | 
			
		||||
                CategoryCreateDialog(this@CategoryController).showDialog(router, null)
 | 
			
		||||
            }
 | 
			
		||||
            .launchIn(uiScope)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -12,8 +12,6 @@ import com.bluelinelabs.conductor.ControllerChangeHandler
 | 
			
		||||
import com.bluelinelabs.conductor.ControllerChangeType
 | 
			
		||||
import com.bluelinelabs.conductor.RouterTransaction
 | 
			
		||||
import com.bluelinelabs.conductor.changehandler.FadeChangeHandler
 | 
			
		||||
import com.jakewharton.rxbinding.support.v4.widget.refreshes
 | 
			
		||||
import com.jakewharton.rxbinding.support.v7.widget.queryTextChanges
 | 
			
		||||
import eu.davidea.flexibleadapter.FlexibleAdapter
 | 
			
		||||
import eu.davidea.flexibleadapter.items.IFlexible
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
@@ -24,6 +22,13 @@ 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 kotlinx.coroutines.CoroutineScope
 | 
			
		||||
import kotlinx.coroutines.Dispatchers
 | 
			
		||||
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
 | 
			
		||||
import uy.kohesive.injekt.Injekt
 | 
			
		||||
import uy.kohesive.injekt.api.get
 | 
			
		||||
 | 
			
		||||
@@ -47,6 +52,8 @@ open class ExtensionController : NucleusController<ExtensionPresenter>(),
 | 
			
		||||
 | 
			
		||||
    private var query = ""
 | 
			
		||||
 | 
			
		||||
    private val uiScope = CoroutineScope(Dispatchers.Main)
 | 
			
		||||
 | 
			
		||||
    private lateinit var binding: ExtensionControllerBinding
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
@@ -70,9 +77,9 @@ open class ExtensionController : NucleusController<ExtensionPresenter>(),
 | 
			
		||||
        super.onViewCreated(view)
 | 
			
		||||
 | 
			
		||||
        binding.extSwipeRefresh.isRefreshing = true
 | 
			
		||||
        binding.extSwipeRefresh.refreshes().subscribeUntilDestroy {
 | 
			
		||||
            presenter.findAvailableExtensions()
 | 
			
		||||
        }
 | 
			
		||||
        binding.extSwipeRefresh.refreshes()
 | 
			
		||||
            .onEach { presenter.findAvailableExtensions() }
 | 
			
		||||
            .launchIn(uiScope)
 | 
			
		||||
 | 
			
		||||
        // Initialize adapter, scroll listener and recycler views
 | 
			
		||||
        adapter = ExtensionAdapter(this)
 | 
			
		||||
@@ -146,11 +153,12 @@ open class ExtensionController : NucleusController<ExtensionPresenter>(),
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        searchView.queryTextChanges()
 | 
			
		||||
                .filter { router.backstack.lastOrNull()?.controller() == this }
 | 
			
		||||
                .subscribeUntilDestroy {
 | 
			
		||||
                    query = it.toString()
 | 
			
		||||
                    drawExtensions()
 | 
			
		||||
                }
 | 
			
		||||
            .filter { router.backstack.lastOrNull()?.controller() == this }
 | 
			
		||||
            .onEach {
 | 
			
		||||
                query = it.toString()
 | 
			
		||||
                drawExtensions()
 | 
			
		||||
            }
 | 
			
		||||
            .launchIn(uiScope)
 | 
			
		||||
 | 
			
		||||
        // Fixes problem with the overflow icon showing up in lieu of search
 | 
			
		||||
        searchItem.fixExpand(onExpand = { invalidateMenuOnExpand() })
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,6 @@ import androidx.preference.PreferenceScreen
 | 
			
		||||
import androidx.recyclerview.widget.DividerItemDecoration
 | 
			
		||||
import androidx.recyclerview.widget.DividerItemDecoration.VERTICAL
 | 
			
		||||
import androidx.recyclerview.widget.LinearLayoutManager
 | 
			
		||||
import com.jakewharton.rxbinding.view.clicks
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.data.preference.EmptyPreferenceDataStore
 | 
			
		||||
import eu.kanade.tachiyomi.data.preference.SharedPreferencesDataStore
 | 
			
		||||
@@ -33,6 +32,11 @@ import eu.kanade.tachiyomi.ui.base.controller.NucleusController
 | 
			
		||||
import eu.kanade.tachiyomi.util.preference.preferenceCategory
 | 
			
		||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
 | 
			
		||||
import eu.kanade.tachiyomi.util.view.visible
 | 
			
		||||
import kotlinx.coroutines.CoroutineScope
 | 
			
		||||
import kotlinx.coroutines.Dispatchers
 | 
			
		||||
import kotlinx.coroutines.flow.launchIn
 | 
			
		||||
import kotlinx.coroutines.flow.onEach
 | 
			
		||||
import reactivecircus.flowbinding.android.view.clicks
 | 
			
		||||
 | 
			
		||||
@SuppressLint("RestrictedApi")
 | 
			
		||||
class ExtensionDetailsController(bundle: Bundle? = null) :
 | 
			
		||||
@@ -44,6 +48,8 @@ class ExtensionDetailsController(bundle: Bundle? = null) :
 | 
			
		||||
 | 
			
		||||
    private var preferenceScreen: PreferenceScreen? = null
 | 
			
		||||
 | 
			
		||||
    private val uiScope = CoroutineScope(Dispatchers.Main)
 | 
			
		||||
 | 
			
		||||
    private lateinit var binding: ExtensionDetailControllerBinding
 | 
			
		||||
 | 
			
		||||
    constructor(pkgName: String) : this(Bundle().apply {
 | 
			
		||||
@@ -76,9 +82,9 @@ class ExtensionDetailsController(bundle: Bundle? = null) :
 | 
			
		||||
        binding.extensionLang.text = context.getString(R.string.ext_language_info, LocaleHelper.getDisplayName(extension.lang, context))
 | 
			
		||||
        binding.extensionPkg.text = extension.pkgName
 | 
			
		||||
        extension.getApplicationIcon(context)?.let { binding.extensionIcon.setImageDrawable(it) }
 | 
			
		||||
        binding.extensionUninstallButton.clicks().subscribeUntilDestroy {
 | 
			
		||||
            presenter.uninstallExtension()
 | 
			
		||||
        }
 | 
			
		||||
        binding.extensionUninstallButton.clicks()
 | 
			
		||||
            .onEach { presenter.uninstallExtension() }
 | 
			
		||||
            .launchIn(uiScope)
 | 
			
		||||
 | 
			
		||||
        if (extension.isObsolete) {
 | 
			
		||||
            binding.extensionObsolete.visible()
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,6 @@ import com.bluelinelabs.conductor.ControllerChangeType
 | 
			
		||||
import com.f2prateek.rx.preferences.Preference
 | 
			
		||||
import com.google.android.material.tabs.TabLayout
 | 
			
		||||
import com.jakewharton.rxbinding.support.v4.view.pageSelections
 | 
			
		||||
import com.jakewharton.rxbinding.support.v7.widget.queryTextChanges
 | 
			
		||||
import com.jakewharton.rxrelay.BehaviorRelay
 | 
			
		||||
import com.jakewharton.rxrelay.PublishRelay
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
@@ -40,6 +39,12 @@ 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.CoroutineScope
 | 
			
		||||
import kotlinx.coroutines.Dispatchers
 | 
			
		||||
import kotlinx.coroutines.flow.filter
 | 
			
		||||
import kotlinx.coroutines.flow.launchIn
 | 
			
		||||
import kotlinx.coroutines.flow.onEach
 | 
			
		||||
import reactivecircus.flowbinding.appcompat.queryTextChanges
 | 
			
		||||
import rx.Subscription
 | 
			
		||||
import timber.log.Timber
 | 
			
		||||
import uy.kohesive.injekt.Injekt
 | 
			
		||||
@@ -123,7 +128,7 @@ class LibraryController(
 | 
			
		||||
 | 
			
		||||
    private var tabsVisibilitySubscription: Subscription? = null
 | 
			
		||||
 | 
			
		||||
    private var searchViewSubscription: Subscription? = null
 | 
			
		||||
    private val uiScope = CoroutineScope(Dispatchers.Main)
 | 
			
		||||
 | 
			
		||||
    private lateinit var binding: LibraryControllerBinding
 | 
			
		||||
 | 
			
		||||
@@ -335,14 +340,14 @@ class LibraryController(
 | 
			
		||||
        // Mutate the filter icon because it needs to be tinted and the resource is shared.
 | 
			
		||||
        menu.findItem(R.id.action_filter).icon.mutate()
 | 
			
		||||
 | 
			
		||||
        searchViewSubscription?.unsubscribe()
 | 
			
		||||
        searchViewSubscription = searchView.queryTextChanges()
 | 
			
		||||
                // Ignore events if this controller isn't at the top
 | 
			
		||||
                .filter { router.backstack.lastOrNull()?.controller() == this }
 | 
			
		||||
                .subscribeUntilDestroy {
 | 
			
		||||
                    query = it.toString()
 | 
			
		||||
                    searchRelay.call(query)
 | 
			
		||||
                }
 | 
			
		||||
        searchView.queryTextChanges()
 | 
			
		||||
            // Ignore events if this controller isn't at the top
 | 
			
		||||
            .filter { router.backstack.lastOrNull()?.controller() == this }
 | 
			
		||||
            .onEach {
 | 
			
		||||
                query = it.toString()
 | 
			
		||||
                searchRelay.call(query)
 | 
			
		||||
            }
 | 
			
		||||
            .launchIn(uiScope)
 | 
			
		||||
 | 
			
		||||
        searchItem.fixExpand(onExpand = { invalidateMenuOnExpand() })
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -16,8 +16,6 @@ import androidx.core.graphics.drawable.DrawableCompat
 | 
			
		||||
import androidx.recyclerview.widget.DividerItemDecoration
 | 
			
		||||
import androidx.recyclerview.widget.LinearLayoutManager
 | 
			
		||||
import com.google.android.material.snackbar.Snackbar
 | 
			
		||||
import com.jakewharton.rxbinding.support.v4.widget.refreshes
 | 
			
		||||
import com.jakewharton.rxbinding.view.clicks
 | 
			
		||||
import eu.davidea.flexibleadapter.FlexibleAdapter
 | 
			
		||||
import eu.davidea.flexibleadapter.SelectableAdapter
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
@@ -36,6 +34,12 @@ 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.CoroutineScope
 | 
			
		||||
import kotlinx.coroutines.Dispatchers
 | 
			
		||||
import kotlinx.coroutines.flow.launchIn
 | 
			
		||||
import kotlinx.coroutines.flow.onEach
 | 
			
		||||
import reactivecircus.flowbinding.android.view.clicks
 | 
			
		||||
import reactivecircus.flowbinding.swiperefreshlayout.refreshes
 | 
			
		||||
import timber.log.Timber
 | 
			
		||||
 | 
			
		||||
class ChaptersController : NucleusController<ChaptersPresenter>(),
 | 
			
		||||
@@ -62,6 +66,8 @@ class ChaptersController : NucleusController<ChaptersPresenter>(),
 | 
			
		||||
 | 
			
		||||
    private var lastClickPosition = -1
 | 
			
		||||
 | 
			
		||||
    private val uiScope = CoroutineScope(Dispatchers.Main)
 | 
			
		||||
 | 
			
		||||
    private lateinit var binding: ChaptersControllerBinding
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
@@ -91,27 +97,32 @@ class ChaptersController : NucleusController<ChaptersPresenter>(),
 | 
			
		||||
        binding.recycler.setHasFixedSize(true)
 | 
			
		||||
        adapter?.fastScroller = binding.fastScroller
 | 
			
		||||
 | 
			
		||||
        binding.swipeRefresh.refreshes().subscribeUntilDestroy { fetchChaptersFromSource() }
 | 
			
		||||
        binding.swipeRefresh.refreshes()
 | 
			
		||||
            .onEach { fetchChaptersFromSource() }
 | 
			
		||||
            .launchIn(uiScope)
 | 
			
		||||
 | 
			
		||||
        binding.fab.clicks().subscribeUntilDestroy {
 | 
			
		||||
            val item = presenter.getNextUnreadChapter()
 | 
			
		||||
            if (item != null) {
 | 
			
		||||
                // Create animation listener
 | 
			
		||||
                val revealAnimationListener: Animator.AnimatorListener = object : AnimatorListenerAdapter() {
 | 
			
		||||
                    override fun onAnimationStart(animation: Animator?) {
 | 
			
		||||
                        openChapter(item.chapter, true)
 | 
			
		||||
        binding.fab.clicks()
 | 
			
		||||
            .onEach {
 | 
			
		||||
                val item = presenter.getNextUnreadChapter()
 | 
			
		||||
                if (item != null) {
 | 
			
		||||
                    // Create animation listener
 | 
			
		||||
                    val revealAnimationListener: Animator.AnimatorListener = object : AnimatorListenerAdapter() {
 | 
			
		||||
                        override fun onAnimationStart(animation: Animator?) {
 | 
			
		||||
                            openChapter(item.chapter, true)
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Get coordinates and start animation
 | 
			
		||||
                val coordinates = binding.fab.getCoordinates()
 | 
			
		||||
                if (!binding.revealView.showRevealEffect(coordinates.x, coordinates.y, revealAnimationListener)) {
 | 
			
		||||
                    openChapter(item.chapter)
 | 
			
		||||
                    // Get coordinates and start animation
 | 
			
		||||
                    val coordinates = binding.fab.getCoordinates()
 | 
			
		||||
                    if (!binding.revealView.showRevealEffect(coordinates.x, coordinates.y, revealAnimationListener)) {
 | 
			
		||||
                        openChapter(item.chapter)
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    view.context.toast(R.string.no_next_chapter)
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                view.context.toast(R.string.no_next_chapter)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
            .launchIn(uiScope)
 | 
			
		||||
 | 
			
		||||
        binding.fab.shrinkOnScroll(binding.recycler)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -27,9 +27,6 @@ import com.bumptech.glide.load.resource.bitmap.RoundedCorners
 | 
			
		||||
import com.bumptech.glide.request.target.CustomTarget
 | 
			
		||||
import com.bumptech.glide.request.transition.Transition
 | 
			
		||||
import com.google.android.material.chip.Chip
 | 
			
		||||
import com.jakewharton.rxbinding.support.v4.widget.refreshes
 | 
			
		||||
import com.jakewharton.rxbinding.view.clicks
 | 
			
		||||
import com.jakewharton.rxbinding.view.longClicks
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Category
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Manga
 | 
			
		||||
@@ -56,6 +53,13 @@ import eu.kanade.tachiyomi.util.system.toast
 | 
			
		||||
import eu.kanade.tachiyomi.util.view.snack
 | 
			
		||||
import eu.kanade.tachiyomi.util.view.visible
 | 
			
		||||
import jp.wasabeef.glide.transformations.CropSquareTransformation
 | 
			
		||||
import kotlinx.coroutines.CoroutineScope
 | 
			
		||||
import kotlinx.coroutines.Dispatchers
 | 
			
		||||
import kotlinx.coroutines.flow.launchIn
 | 
			
		||||
import kotlinx.coroutines.flow.onEach
 | 
			
		||||
import reactivecircus.flowbinding.android.view.clicks
 | 
			
		||||
import reactivecircus.flowbinding.android.view.longClicks
 | 
			
		||||
import reactivecircus.flowbinding.swiperefreshlayout.refreshes
 | 
			
		||||
import uy.kohesive.injekt.Injekt
 | 
			
		||||
import uy.kohesive.injekt.api.get
 | 
			
		||||
import uy.kohesive.injekt.injectLazy
 | 
			
		||||
@@ -70,6 +74,8 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
 | 
			
		||||
 | 
			
		||||
    private val preferences: PreferencesHelper by injectLazy()
 | 
			
		||||
 | 
			
		||||
    private val uiScope = CoroutineScope(Dispatchers.Main)
 | 
			
		||||
 | 
			
		||||
    private lateinit var binding: MangaInfoControllerBinding
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
@@ -91,53 +97,79 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
 | 
			
		||||
        super.onViewCreated(view)
 | 
			
		||||
 | 
			
		||||
        // Set onclickListener to toggle favorite when favorite button clicked.
 | 
			
		||||
        binding.btnFavorite.clicks().subscribeUntilDestroy { onFavoriteClick() }
 | 
			
		||||
        binding.btnFavorite.clicks()
 | 
			
		||||
            .onEach { onFavoriteClick() }
 | 
			
		||||
            .launchIn(uiScope)
 | 
			
		||||
 | 
			
		||||
        // Set onLongClickListener to manage categories when favorite button is clicked.
 | 
			
		||||
        binding.btnFavorite.longClicks().subscribeUntilDestroy { onFavoriteLongClick() }
 | 
			
		||||
        binding.btnFavorite.longClicks()
 | 
			
		||||
            .onEach { onFavoriteLongClick() }
 | 
			
		||||
            .launchIn(uiScope)
 | 
			
		||||
 | 
			
		||||
        if (presenter.source is HttpSource) {
 | 
			
		||||
            binding.btnWebview.visible()
 | 
			
		||||
            binding.btnShare.visible()
 | 
			
		||||
 | 
			
		||||
            binding.btnWebview.clicks().subscribeUntilDestroy { openInWebView() }
 | 
			
		||||
            binding.btnShare.clicks().subscribeUntilDestroy { shareManga() }
 | 
			
		||||
            binding.btnWebview.clicks()
 | 
			
		||||
                .onEach { openInWebView() }
 | 
			
		||||
                .launchIn(uiScope)
 | 
			
		||||
            binding.btnShare.clicks()
 | 
			
		||||
                .onEach { shareManga() }
 | 
			
		||||
                .launchIn(uiScope)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Set SwipeRefresh to refresh manga data.
 | 
			
		||||
        binding.swipeRefresh.refreshes().subscribeUntilDestroy { fetchMangaFromSource() }
 | 
			
		||||
        binding.swipeRefresh.refreshes()
 | 
			
		||||
            .onEach { fetchMangaFromSource() }
 | 
			
		||||
            .launchIn(uiScope)
 | 
			
		||||
 | 
			
		||||
        binding.mangaFullTitle.longClicks().subscribeUntilDestroy {
 | 
			
		||||
            copyToClipboard(view.context.getString(R.string.title), binding.mangaFullTitle.text.toString())
 | 
			
		||||
        }
 | 
			
		||||
        binding.mangaFullTitle.longClicks()
 | 
			
		||||
            .onEach {
 | 
			
		||||
                copyToClipboard(view.context.getString(R.string.title), binding.mangaFullTitle.text.toString())
 | 
			
		||||
            }
 | 
			
		||||
            .launchIn(uiScope)
 | 
			
		||||
 | 
			
		||||
        binding.mangaFullTitle.clicks().subscribeUntilDestroy {
 | 
			
		||||
            performGlobalSearch(binding.mangaFullTitle.text.toString())
 | 
			
		||||
        }
 | 
			
		||||
        binding.mangaFullTitle.clicks()
 | 
			
		||||
            .onEach {
 | 
			
		||||
                performGlobalSearch(binding.mangaFullTitle.text.toString())
 | 
			
		||||
            }
 | 
			
		||||
            .launchIn(uiScope)
 | 
			
		||||
 | 
			
		||||
        binding.mangaArtist.longClicks().subscribeUntilDestroy {
 | 
			
		||||
            copyToClipboard(binding.mangaArtistLabel.text.toString(), binding.mangaArtist.text.toString())
 | 
			
		||||
        }
 | 
			
		||||
        binding.mangaArtist.longClicks()
 | 
			
		||||
            .onEach {
 | 
			
		||||
                copyToClipboard(binding.mangaArtistLabel.text.toString(), binding.mangaArtist.text.toString())
 | 
			
		||||
            }
 | 
			
		||||
            .launchIn(uiScope)
 | 
			
		||||
 | 
			
		||||
        binding.mangaArtist.clicks().subscribeUntilDestroy {
 | 
			
		||||
            performGlobalSearch(binding.mangaArtist.text.toString())
 | 
			
		||||
        }
 | 
			
		||||
        binding.mangaArtist.clicks()
 | 
			
		||||
            .onEach {
 | 
			
		||||
                performGlobalSearch(binding.mangaArtist.text.toString())
 | 
			
		||||
            }
 | 
			
		||||
            .launchIn(uiScope)
 | 
			
		||||
 | 
			
		||||
        binding.mangaAuthor.longClicks().subscribeUntilDestroy {
 | 
			
		||||
            copyToClipboard(binding.mangaAuthor.text.toString(), binding.mangaAuthor.text.toString())
 | 
			
		||||
        }
 | 
			
		||||
        binding.mangaAuthor.longClicks()
 | 
			
		||||
            .onEach {
 | 
			
		||||
                copyToClipboard(binding.mangaAuthor.text.toString(), binding.mangaAuthor.text.toString())
 | 
			
		||||
            }
 | 
			
		||||
            .launchIn(uiScope)
 | 
			
		||||
 | 
			
		||||
        binding.mangaAuthor.clicks().subscribeUntilDestroy {
 | 
			
		||||
            performGlobalSearch(binding.mangaAuthor.text.toString())
 | 
			
		||||
        }
 | 
			
		||||
        binding.mangaAuthor.clicks()
 | 
			
		||||
            .onEach {
 | 
			
		||||
                performGlobalSearch(binding.mangaAuthor.text.toString())
 | 
			
		||||
            }
 | 
			
		||||
            .launchIn(uiScope)
 | 
			
		||||
 | 
			
		||||
        binding.mangaSummary.longClicks().subscribeUntilDestroy {
 | 
			
		||||
            copyToClipboard(view.context.getString(R.string.description), binding.mangaSummary.text.toString())
 | 
			
		||||
        }
 | 
			
		||||
        binding.mangaSummary.longClicks()
 | 
			
		||||
            .onEach {
 | 
			
		||||
                copyToClipboard(view.context.getString(R.string.description), binding.mangaSummary.text.toString())
 | 
			
		||||
            }
 | 
			
		||||
            .launchIn(uiScope)
 | 
			
		||||
 | 
			
		||||
        binding.mangaCover.longClicks().subscribeUntilDestroy {
 | 
			
		||||
            copyToClipboard(view.context.getString(R.string.title), presenter.manga.title)
 | 
			
		||||
        }
 | 
			
		||||
        binding.mangaCover.longClicks()
 | 
			
		||||
            .onEach {
 | 
			
		||||
                copyToClipboard(view.context.getString(R.string.title), presenter.manga.title)
 | 
			
		||||
            }
 | 
			
		||||
            .launchIn(uiScope)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
 | 
			
		||||
 
 | 
			
		||||
@@ -6,13 +6,17 @@ import android.view.LayoutInflater
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import androidx.recyclerview.widget.LinearLayoutManager
 | 
			
		||||
import com.jakewharton.rxbinding.support.v4.widget.refreshes
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
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.system.toast
 | 
			
		||||
import kotlinx.coroutines.CoroutineScope
 | 
			
		||||
import kotlinx.coroutines.Dispatchers
 | 
			
		||||
import kotlinx.coroutines.flow.launchIn
 | 
			
		||||
import kotlinx.coroutines.flow.onEach
 | 
			
		||||
import reactivecircus.flowbinding.swiperefreshlayout.refreshes
 | 
			
		||||
import timber.log.Timber
 | 
			
		||||
 | 
			
		||||
class TrackController : NucleusController<TrackPresenter>(),
 | 
			
		||||
@@ -23,6 +27,8 @@ class TrackController : NucleusController<TrackPresenter>(),
 | 
			
		||||
 | 
			
		||||
    private var adapter: TrackAdapter? = null
 | 
			
		||||
 | 
			
		||||
    private val uiScope = CoroutineScope(Dispatchers.Main)
 | 
			
		||||
 | 
			
		||||
    private lateinit var binding: TrackControllerBinding
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
@@ -47,7 +53,9 @@ class TrackController : NucleusController<TrackPresenter>(),
 | 
			
		||||
        binding.trackRecycler.layoutManager = LinearLayoutManager(view.context)
 | 
			
		||||
        binding.trackRecycler.adapter = adapter
 | 
			
		||||
        binding.swipeRefresh.isEnabled = false
 | 
			
		||||
        binding.swipeRefresh.refreshes().subscribeUntilDestroy { presenter.refresh() }
 | 
			
		||||
        binding.swipeRefresh.refreshes()
 | 
			
		||||
            .onEach { presenter.refresh() }
 | 
			
		||||
            .launchIn(uiScope)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onDestroyView(view: View) {
 | 
			
		||||
 
 | 
			
		||||
@@ -4,24 +4,27 @@ import android.app.Dialog
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.view.View
 | 
			
		||||
import com.afollestad.materialdialogs.MaterialDialog
 | 
			
		||||
import com.jakewharton.rxbinding.widget.itemClicks
 | 
			
		||||
import com.jakewharton.rxbinding.widget.textChanges
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Track
 | 
			
		||||
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.plusAssign
 | 
			
		||||
import eu.kanade.tachiyomi.util.view.invisible
 | 
			
		||||
import eu.kanade.tachiyomi.util.view.visible
 | 
			
		||||
import java.util.concurrent.TimeUnit
 | 
			
		||||
import kotlinx.android.synthetic.main.track_search_dialog.view.progress
 | 
			
		||||
import kotlinx.android.synthetic.main.track_search_dialog.view.track_search
 | 
			
		||||
import kotlinx.android.synthetic.main.track_search_dialog.view.track_search_list
 | 
			
		||||
import rx.Subscription
 | 
			
		||||
import rx.android.schedulers.AndroidSchedulers
 | 
			
		||||
import rx.subscriptions.CompositeSubscription
 | 
			
		||||
import kotlinx.coroutines.CoroutineScope
 | 
			
		||||
import kotlinx.coroutines.Dispatchers
 | 
			
		||||
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
 | 
			
		||||
import reactivecircus.flowbinding.android.widget.textChanges
 | 
			
		||||
import uy.kohesive.injekt.Injekt
 | 
			
		||||
import uy.kohesive.injekt.api.get
 | 
			
		||||
 | 
			
		||||
@@ -35,13 +38,11 @@ class TrackSearchDialog : DialogController {
 | 
			
		||||
 | 
			
		||||
    private val service: TrackService
 | 
			
		||||
 | 
			
		||||
    private var subscriptions = CompositeSubscription()
 | 
			
		||||
 | 
			
		||||
    private var searchTextSubscription: Subscription? = null
 | 
			
		||||
 | 
			
		||||
    private val trackController
 | 
			
		||||
        get() = targetController as TrackController
 | 
			
		||||
 | 
			
		||||
    private val uiScope = CoroutineScope(Dispatchers.Main)
 | 
			
		||||
 | 
			
		||||
    constructor(target: TrackController, service: TrackService) : super(Bundle().apply {
 | 
			
		||||
        putInt(KEY_SERVICE, service.id)
 | 
			
		||||
    }) {
 | 
			
		||||
@@ -64,10 +65,6 @@ class TrackSearchDialog : DialogController {
 | 
			
		||||
                .onNeutral { _, _ -> onRemoveButtonClick() }
 | 
			
		||||
                .build()
 | 
			
		||||
 | 
			
		||||
        if (subscriptions.isUnsubscribed) {
 | 
			
		||||
            subscriptions = CompositeSubscription()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        dialogView = dialog.view
 | 
			
		||||
        onViewCreated(dialog.view, savedViewState)
 | 
			
		||||
 | 
			
		||||
@@ -83,9 +80,11 @@ class TrackSearchDialog : DialogController {
 | 
			
		||||
        // Set listeners
 | 
			
		||||
        selectedItem = null
 | 
			
		||||
 | 
			
		||||
        subscriptions += view.track_search_list.itemClicks().subscribe { position ->
 | 
			
		||||
            selectedItem = adapter.getItem(position)
 | 
			
		||||
        }
 | 
			
		||||
        view.track_search_list.itemClicks()
 | 
			
		||||
            .onEach { position ->
 | 
			
		||||
                selectedItem = adapter.getItem(position)
 | 
			
		||||
            }
 | 
			
		||||
            .launchIn(uiScope)
 | 
			
		||||
 | 
			
		||||
        // Do an initial search based on the manga's title
 | 
			
		||||
        if (savedState == null) {
 | 
			
		||||
@@ -97,24 +96,18 @@ class TrackSearchDialog : DialogController {
 | 
			
		||||
 | 
			
		||||
    override fun onDestroyView(view: View) {
 | 
			
		||||
        super.onDestroyView(view)
 | 
			
		||||
        subscriptions.unsubscribe()
 | 
			
		||||
        dialogView = null
 | 
			
		||||
        adapter = null
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onAttach(view: View) {
 | 
			
		||||
        super.onAttach(view)
 | 
			
		||||
        searchTextSubscription = dialogView!!.track_search.textChanges()
 | 
			
		||||
                .skip(1)
 | 
			
		||||
                .debounce(1, TimeUnit.SECONDS, AndroidSchedulers.mainThread())
 | 
			
		||||
        dialogView!!.track_search.textChanges(false)
 | 
			
		||||
                .debounce(TimeUnit.SECONDS.toMillis(1))
 | 
			
		||||
                .map { it.toString() }
 | 
			
		||||
                .filter(String::isNotBlank)
 | 
			
		||||
                .subscribe { search(it) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onDetach(view: View) {
 | 
			
		||||
        super.onDetach(view)
 | 
			
		||||
        searchTextSubscription?.unsubscribe()
 | 
			
		||||
                .filter { it.isNotBlank() }
 | 
			
		||||
                .onEach { search(it) }
 | 
			
		||||
                .launchIn(uiScope)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun search(query: String) {
 | 
			
		||||
 
 | 
			
		||||
@@ -10,8 +10,6 @@ import androidx.appcompat.app.AppCompatActivity
 | 
			
		||||
import androidx.appcompat.view.ActionMode
 | 
			
		||||
import androidx.recyclerview.widget.DividerItemDecoration
 | 
			
		||||
import androidx.recyclerview.widget.LinearLayoutManager
 | 
			
		||||
import com.jakewharton.rxbinding.support.v4.widget.refreshes
 | 
			
		||||
import com.jakewharton.rxbinding.support.v7.widget.scrollStateChanges
 | 
			
		||||
import eu.davidea.flexibleadapter.FlexibleAdapter
 | 
			
		||||
import eu.davidea.flexibleadapter.SelectableAdapter
 | 
			
		||||
import eu.davidea.flexibleadapter.items.IFlexible
 | 
			
		||||
@@ -29,6 +27,12 @@ import eu.kanade.tachiyomi.ui.manga.MangaController
 | 
			
		||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
 | 
			
		||||
import eu.kanade.tachiyomi.util.system.notificationManager
 | 
			
		||||
import eu.kanade.tachiyomi.util.system.toast
 | 
			
		||||
import kotlinx.coroutines.CoroutineScope
 | 
			
		||||
import kotlinx.coroutines.Dispatchers
 | 
			
		||||
import kotlinx.coroutines.flow.launchIn
 | 
			
		||||
import kotlinx.coroutines.flow.onEach
 | 
			
		||||
import reactivecircus.flowbinding.recyclerview.scrollStateChanges
 | 
			
		||||
import reactivecircus.flowbinding.swiperefreshlayout.refreshes
 | 
			
		||||
import timber.log.Timber
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -57,6 +61,8 @@ class UpdatesController : NucleusController<UpdatesPresenter>(),
 | 
			
		||||
    var adapter: UpdatesAdapter? = null
 | 
			
		||||
        private set
 | 
			
		||||
 | 
			
		||||
    private val uiScope = CoroutineScope(Dispatchers.Main)
 | 
			
		||||
 | 
			
		||||
    private lateinit var binding: UpdatesControllerBinding
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
@@ -92,19 +98,23 @@ class UpdatesController : NucleusController<UpdatesPresenter>(),
 | 
			
		||||
        adapter = UpdatesAdapter(this@UpdatesController)
 | 
			
		||||
        binding.recycler.adapter = adapter
 | 
			
		||||
 | 
			
		||||
        binding.recycler.scrollStateChanges().subscribeUntilDestroy {
 | 
			
		||||
            // Disable swipe refresh when view is not at the top
 | 
			
		||||
            val firstPos = layoutManager.findFirstCompletelyVisibleItemPosition()
 | 
			
		||||
            binding.swipeRefresh.isEnabled = firstPos <= 0
 | 
			
		||||
        }
 | 
			
		||||
        binding.recycler.scrollStateChanges()
 | 
			
		||||
            .onEach {
 | 
			
		||||
                // Disable swipe refresh when view is not at the top
 | 
			
		||||
                val firstPos = layoutManager.findFirstCompletelyVisibleItemPosition()
 | 
			
		||||
                binding.swipeRefresh.isEnabled = firstPos <= 0
 | 
			
		||||
            }
 | 
			
		||||
            .launchIn(uiScope)
 | 
			
		||||
 | 
			
		||||
        binding.swipeRefresh.setDistanceToTriggerSync((2 * 64 * view.resources.displayMetrics.density).toInt())
 | 
			
		||||
        binding.swipeRefresh.refreshes().subscribeUntilDestroy {
 | 
			
		||||
            updateLibrary()
 | 
			
		||||
        binding.swipeRefresh.refreshes()
 | 
			
		||||
            .onEach {
 | 
			
		||||
                updateLibrary()
 | 
			
		||||
 | 
			
		||||
            // It can be a very long operation, so we disable swipe refresh and show a toast.
 | 
			
		||||
            binding.swipeRefresh.isRefreshing = false
 | 
			
		||||
        }
 | 
			
		||||
                // It can be a very long operation, so we disable swipe refresh and show a toast.
 | 
			
		||||
                binding.swipeRefresh.isRefreshing = false
 | 
			
		||||
            }
 | 
			
		||||
            .launchIn(uiScope)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onDestroyView(view: View) {
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,6 @@ import com.bluelinelabs.conductor.ControllerChangeHandler
 | 
			
		||||
import com.bluelinelabs.conductor.ControllerChangeType
 | 
			
		||||
import com.bluelinelabs.conductor.RouterTransaction
 | 
			
		||||
import com.bluelinelabs.conductor.changehandler.FadeChangeHandler
 | 
			
		||||
import com.jakewharton.rxbinding.support.v7.widget.queryTextChangeEvents
 | 
			
		||||
import eu.davidea.flexibleadapter.FlexibleAdapter
 | 
			
		||||
import eu.davidea.flexibleadapter.items.IFlexible
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
@@ -31,6 +30,13 @@ 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 kotlinx.coroutines.CoroutineScope
 | 
			
		||||
import kotlinx.coroutines.Dispatchers
 | 
			
		||||
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
 | 
			
		||||
import uy.kohesive.injekt.Injekt
 | 
			
		||||
import uy.kohesive.injekt.api.get
 | 
			
		||||
 | 
			
		||||
@@ -54,6 +60,8 @@ class SourceController : NucleusController<SourcePresenter>(),
 | 
			
		||||
     */
 | 
			
		||||
    private var adapter: SourceAdapter? = null
 | 
			
		||||
 | 
			
		||||
    private val uiScope = CoroutineScope(Dispatchers.Main)
 | 
			
		||||
 | 
			
		||||
    private lateinit var binding: SourceMainControllerBinding
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
@@ -192,9 +200,10 @@ class SourceController : NucleusController<SourcePresenter>(),
 | 
			
		||||
        searchView.queryHint = applicationContext?.getString(R.string.action_global_search_hint)
 | 
			
		||||
 | 
			
		||||
        // Create query listener which opens the global search view.
 | 
			
		||||
        searchView.queryTextChangeEvents()
 | 
			
		||||
                .filter { it.isSubmitted }
 | 
			
		||||
                .subscribeUntilDestroy { performGlobalSearch(it.queryText().toString()) }
 | 
			
		||||
        searchView.queryTextEvents()
 | 
			
		||||
            .filter { it is QueryTextEvent.QuerySubmitted }
 | 
			
		||||
            .onEach { performGlobalSearch(it.queryText.toString()) }
 | 
			
		||||
            .launchIn(uiScope)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun performGlobalSearch(query: String) {
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,6 @@ import android.view.View
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import androidx.appcompat.widget.SearchView
 | 
			
		||||
import androidx.recyclerview.widget.LinearLayoutManager
 | 
			
		||||
import com.jakewharton.rxbinding.support.v7.widget.queryTextChangeEvents
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Manga
 | 
			
		||||
import eu.kanade.tachiyomi.databinding.GlobalSearchControllerBinding
 | 
			
		||||
@@ -17,6 +16,13 @@ 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 kotlinx.coroutines.CoroutineScope
 | 
			
		||||
import kotlinx.coroutines.Dispatchers
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This controller shows and manages the different search result in global search.
 | 
			
		||||
@@ -34,6 +40,8 @@ open class GlobalSearchController(
 | 
			
		||||
     */
 | 
			
		||||
    protected var adapter: GlobalSearchAdapter? = null
 | 
			
		||||
 | 
			
		||||
    private val uiScope = CoroutineScope(Dispatchers.Main)
 | 
			
		||||
 | 
			
		||||
    private lateinit var binding: GlobalSearchControllerBinding
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -119,13 +127,14 @@ open class GlobalSearchController(
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
        searchView.queryTextChangeEvents()
 | 
			
		||||
                .filter { it.isSubmitted }
 | 
			
		||||
                .subscribeUntilDestroy {
 | 
			
		||||
                    presenter.search(it.queryText().toString())
 | 
			
		||||
                    searchItem.collapseActionView()
 | 
			
		||||
                    setTitle() // Update toolbar title
 | 
			
		||||
                }
 | 
			
		||||
        searchView.queryTextEvents()
 | 
			
		||||
            .filter { it is QueryTextEvent.QuerySubmitted }
 | 
			
		||||
            .onEach {
 | 
			
		||||
                presenter.search(it.queryText.toString())
 | 
			
		||||
                searchItem.collapseActionView()
 | 
			
		||||
                setTitle() // Update toolbar title
 | 
			
		||||
            }
 | 
			
		||||
            .launchIn(uiScope)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user