Make a coroutine presenter

This commit is contained in:
Jobobby04 2020-12-20 18:56:09 -05:00
parent d302a0fbc7
commit 644140b617
4 changed files with 71 additions and 32 deletions

View File

@ -181,7 +181,7 @@ private suspend fun <T> Observable<T>.awaitOne(): T = suspendCancellableCoroutin
internal fun <T> CancellableContinuation<T>.unsubscribeOnCancellation(sub: Subscription) =
invokeOnCancellation { sub.unsubscribe() }
fun <T : Any> Observable<T>.asFlow(): Flow<T> = callbackFlow {
fun <T : Any?> Observable<T>.asFlow(): Flow<T> = callbackFlow {
val observer = object : Observer<T> {
override fun onNext(t: T) {
offer(t)
@ -199,7 +199,7 @@ fun <T : Any> Observable<T>.asFlow(): Flow<T> = callbackFlow {
awaitClose { subscription.unsubscribe() }
}
fun <T : Any> Flow<T>.asObservable(backpressureMode: Emitter.BackpressureMode = Emitter.BackpressureMode.NONE): Observable<T> {
fun <T : Any?> Flow<T>.asObservable(backpressureMode: Emitter.BackpressureMode = Emitter.BackpressureMode.NONE): Observable<T> {
return Observable.create(
{ emitter ->
/*

View File

@ -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<V> : Presenter<V>() {
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 <F> Flow<F>.onEachView(block: (V, F) -> Unit) = onEach {
view?.let { view -> block(view, it) }
}
fun <F, P> Flow<F>.mapView(block: (V, F) -> P): Flow<P> = mapNotNull {
view?.let { view -> block(view, it) }
}
@CallSuper
override fun destroy() {
super.destroy()
scope.cancel()
}
}

View File

@ -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<MetadataViewControllerBinding,
binding.recycler.setHasFixedSize(true)
}
fun onNextMetaInfo(flatMetadata: FlatMetadata) {
val mainSource = presenter.source.getMainSource()
if (mainSource is MetadataSource<*, *>) {
presenter.meta = flatMetadata.raise(mainSource.metaClass)
}
}
fun onNextMangaInfo(meta: RaisedSearchMetadata?) {
val context = view?.context ?: return
data = meta?.getExtraInfoPairs(context).orEmpty()

View File

@ -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<MetadataViewController>() {
) : CoroutinePresenter<MetadataViewController>() {
var meta: RaisedSearchMetadata? = null
val meta = MutableStateFlow<RaisedSearchMetadata?>(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<Manga> {
return db.getManga(manga.url, manga.source).asRxObservable()
}
private fun getMangaMetaObservable(): Observable<FlatMetadata?> {
val mangaId = manga.id
return if (mangaId != null) {
db.getFlatMetadataForManga(mangaId).asRxObservable()
.observeOn(AndroidSchedulers.mainThread())
} else Observable.just(null)
private fun getMangaMetaObservable(): Flow<FlatMetadata?> {
return db.getFlatMetadataForManga(manga.id!!).asRxObservable().asFlow()
}
}