From 644140b6173f99d037504e15aab111beae0de9c9 Mon Sep 17 00:00:00 2001 From: Jobobby04 Date: Sun, 20 Dec 2020 18:56:09 -0500 Subject: [PATCH] Make a coroutine presenter --- .../tachiyomi/util/lang/RxCoroutineBridge.kt | 4 +- .../java/exh/ui/base/CoroutinePresenter.kt | 41 ++++++++++++++++ .../exh/ui/metadata/MetadataViewController.kt | 10 ---- .../exh/ui/metadata/MetadataViewPresenter.kt | 48 +++++++++++-------- 4 files changed, 71 insertions(+), 32 deletions(-) create mode 100644 app/src/main/java/exh/ui/base/CoroutinePresenter.kt diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/lang/RxCoroutineBridge.kt b/app/src/main/java/eu/kanade/tachiyomi/util/lang/RxCoroutineBridge.kt index 8ec5ccfa2..9fc395d73 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/lang/RxCoroutineBridge.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/lang/RxCoroutineBridge.kt @@ -181,7 +181,7 @@ private suspend fun Observable.awaitOne(): T = suspendCancellableCoroutin internal fun CancellableContinuation.unsubscribeOnCancellation(sub: Subscription) = invokeOnCancellation { sub.unsubscribe() } -fun Observable.asFlow(): Flow = callbackFlow { +fun Observable.asFlow(): Flow = callbackFlow { val observer = object : Observer { override fun onNext(t: T) { offer(t) @@ -199,7 +199,7 @@ fun Observable.asFlow(): Flow = callbackFlow { awaitClose { subscription.unsubscribe() } } -fun Flow.asObservable(backpressureMode: Emitter.BackpressureMode = Emitter.BackpressureMode.NONE): Observable { +fun Flow.asObservable(backpressureMode: Emitter.BackpressureMode = Emitter.BackpressureMode.NONE): Observable { return Observable.create( { emitter -> /* diff --git a/app/src/main/java/exh/ui/base/CoroutinePresenter.kt b/app/src/main/java/exh/ui/base/CoroutinePresenter.kt new file mode 100644 index 000000000..2ad6238b2 --- /dev/null +++ b/app/src/main/java/exh/ui/base/CoroutinePresenter.kt @@ -0,0 +1,41 @@ +package exh.ui.base + +import androidx.annotation.CallSuper +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.cancel +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.mapNotNull +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch +import nucleus.presenter.Presenter + +@Suppress("DEPRECATION") +open class CoroutinePresenter : Presenter() { + val scope = CoroutineScope(Job() + Dispatchers.Main) + + @Suppress("DeprecatedCallableAddReplaceWith") + @Deprecated("Use launchInView") + override fun getView(): V? { + return super.getView() + } + + fun launchInView(block: (CoroutineScope, V) -> Unit) = scope.launch(Dispatchers.Main) { + view?.let { block.invoke(this, it) } + } + + fun Flow.onEachView(block: (V, F) -> Unit) = onEach { + view?.let { view -> block(view, it) } + } + + fun Flow.mapView(block: (V, F) -> P): Flow

= mapNotNull { + view?.let { view -> block(view, it) } + } + + @CallSuper + override fun destroy() { + super.destroy() + scope.cancel() + } +} diff --git a/app/src/main/java/exh/ui/metadata/MetadataViewController.kt b/app/src/main/java/exh/ui/metadata/MetadataViewController.kt index 33cb90f4f..802b23c39 100644 --- a/app/src/main/java/exh/ui/metadata/MetadataViewController.kt +++ b/app/src/main/java/exh/ui/metadata/MetadataViewController.kt @@ -11,12 +11,9 @@ import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.databinding.MetadataViewControllerBinding import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.SourceManager -import eu.kanade.tachiyomi.source.online.MetadataSource import eu.kanade.tachiyomi.ui.base.controller.NucleusController import eu.kanade.tachiyomi.ui.manga.MangaController -import exh.metadata.metadata.base.FlatMetadata import exh.metadata.metadata.base.RaisedSearchMetadata -import exh.source.getMainSource import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -74,13 +71,6 @@ class MetadataViewController : NucleusController) { - presenter.meta = flatMetadata.raise(mainSource.metaClass) - } - } - fun onNextMangaInfo(meta: RaisedSearchMetadata?) { val context = view?.context ?: return data = meta?.getExtraInfoPairs(context).orEmpty() diff --git a/app/src/main/java/exh/ui/metadata/MetadataViewPresenter.kt b/app/src/main/java/exh/ui/metadata/MetadataViewPresenter.kt index 1cae1e40d..a040e9fd3 100644 --- a/app/src/main/java/exh/ui/metadata/MetadataViewPresenter.kt +++ b/app/src/main/java/exh/ui/metadata/MetadataViewPresenter.kt @@ -1,17 +1,23 @@ package exh.ui.metadata import android.os.Bundle -import com.elvishew.xlog.XLog import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.source.Source -import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter +import eu.kanade.tachiyomi.source.online.MetadataSource +import eu.kanade.tachiyomi.util.lang.asFlow import exh.metadata.metadata.base.FlatMetadata import exh.metadata.metadata.base.RaisedSearchMetadata import exh.metadata.metadata.base.getFlatMetadataForManga -import rx.Observable -import rx.android.schedulers.AndroidSchedulers +import exh.source.getMainSource +import exh.ui.base.CoroutinePresenter +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.plus import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -20,29 +26,31 @@ class MetadataViewPresenter( val source: Source, val preferences: PreferencesHelper = Injekt.get(), private val db: DatabaseHelper = Injekt.get() -) : BasePresenter() { +) : CoroutinePresenter() { - var meta: RaisedSearchMetadata? = null + val meta = MutableStateFlow(null) override fun onCreate(savedState: Bundle?) { super.onCreate(savedState) - getMangaMetaObservable().subscribeLatestCache({ view, flatMetadata -> if (flatMetadata != null) view.onNextMetaInfo(flatMetadata) else XLog.tag("MetadataViewPresenter").disableStackTrace().d("Invalid metadata") }) + getMangaMetaObservable() + .onEach { + if (it == null) return@onEach + val mainSource = source.getMainSource() + if (mainSource is MetadataSource<*, *>) { + meta.value = it.raise(mainSource.metaClass) + } + } + .launchIn(scope + Dispatchers.IO) - getMangaObservable() - .observeOn(AndroidSchedulers.mainThread()) - .subscribeLatestCache({ view, _ -> view.onNextMangaInfo(meta) }) + meta + .onEachView { view, metadata -> + view.onNextMangaInfo(metadata) + } + .launchIn(scope) } - private fun getMangaObservable(): Observable { - return db.getManga(manga.url, manga.source).asRxObservable() - } - - private fun getMangaMetaObservable(): Observable { - val mangaId = manga.id - return if (mangaId != null) { - db.getFlatMetadataForManga(mangaId).asRxObservable() - .observeOn(AndroidSchedulers.mainThread()) - } else Observable.just(null) + private fun getMangaMetaObservable(): Flow { + return db.getFlatMetadataForManga(manga.id!!).asRxObservable().asFlow() } }