Make a coroutine presenter
This commit is contained in:
parent
d302a0fbc7
commit
644140b617
@ -181,7 +181,7 @@ private suspend fun <T> Observable<T>.awaitOne(): T = suspendCancellableCoroutin
|
|||||||
internal fun <T> CancellableContinuation<T>.unsubscribeOnCancellation(sub: Subscription) =
|
internal fun <T> CancellableContinuation<T>.unsubscribeOnCancellation(sub: Subscription) =
|
||||||
invokeOnCancellation { sub.unsubscribe() }
|
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> {
|
val observer = object : Observer<T> {
|
||||||
override fun onNext(t: T) {
|
override fun onNext(t: T) {
|
||||||
offer(t)
|
offer(t)
|
||||||
@ -199,7 +199,7 @@ fun <T : Any> Observable<T>.asFlow(): Flow<T> = callbackFlow {
|
|||||||
awaitClose { subscription.unsubscribe() }
|
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(
|
return Observable.create(
|
||||||
{ emitter ->
|
{ emitter ->
|
||||||
/*
|
/*
|
||||||
|
41
app/src/main/java/exh/ui/base/CoroutinePresenter.kt
Normal file
41
app/src/main/java/exh/ui/base/CoroutinePresenter.kt
Normal 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()
|
||||||
|
}
|
||||||
|
}
|
@ -11,12 +11,9 @@ import eu.kanade.tachiyomi.data.database.models.Manga
|
|||||||
import eu.kanade.tachiyomi.databinding.MetadataViewControllerBinding
|
import eu.kanade.tachiyomi.databinding.MetadataViewControllerBinding
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
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.base.controller.NucleusController
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
import exh.metadata.metadata.base.FlatMetadata
|
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
import exh.source.getMainSource
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
@ -74,13 +71,6 @@ class MetadataViewController : NucleusController<MetadataViewControllerBinding,
|
|||||||
binding.recycler.setHasFixedSize(true)
|
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?) {
|
fun onNextMangaInfo(meta: RaisedSearchMetadata?) {
|
||||||
val context = view?.context ?: return
|
val context = view?.context ?: return
|
||||||
data = meta?.getExtraInfoPairs(context).orEmpty()
|
data = meta?.getExtraInfoPairs(context).orEmpty()
|
||||||
|
@ -1,17 +1,23 @@
|
|||||||
package exh.ui.metadata
|
package exh.ui.metadata
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import com.elvishew.xlog.XLog
|
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.source.Source
|
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.FlatMetadata
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
import exh.metadata.metadata.base.getFlatMetadataForManga
|
import exh.metadata.metadata.base.getFlatMetadataForManga
|
||||||
import rx.Observable
|
import exh.source.getMainSource
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
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.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
@ -20,29 +26,31 @@ class MetadataViewPresenter(
|
|||||||
val source: Source,
|
val source: Source,
|
||||||
val preferences: PreferencesHelper = Injekt.get(),
|
val preferences: PreferencesHelper = Injekt.get(),
|
||||||
private val db: DatabaseHelper = 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?) {
|
override fun onCreate(savedState: Bundle?) {
|
||||||
super.onCreate(savedState)
|
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()
|
meta
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.onEachView { view, metadata ->
|
||||||
.subscribeLatestCache({ view, _ -> view.onNextMangaInfo(meta) })
|
view.onNextMangaInfo(metadata)
|
||||||
|
}
|
||||||
|
.launchIn(scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getMangaObservable(): Observable<Manga> {
|
private fun getMangaMetaObservable(): Flow<FlatMetadata?> {
|
||||||
return db.getManga(manga.url, manga.source).asRxObservable()
|
return db.getFlatMetadataForManga(manga.id!!).asRxObservable().asFlow()
|
||||||
}
|
|
||||||
|
|
||||||
private fun getMangaMetaObservable(): Observable<FlatMetadata?> {
|
|
||||||
val mangaId = manga.id
|
|
||||||
return if (mangaId != null) {
|
|
||||||
db.getFlatMetadataForManga(mangaId).asRxObservable()
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
} else Observable.just(null)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user