mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-31 14:27:57 +01:00 
			
		
		
		
	Mostly migrate rxbinding to Kotlin Flow version
This commit is contained in:
		| @@ -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