diff options
Diffstat (limited to 'app/src/main/kotlin/com/pitchedapps/frost/views')
-rw-r--r-- | app/src/main/kotlin/com/pitchedapps/frost/views/FrostContentView.kt | 116 | ||||
-rw-r--r-- | app/src/main/kotlin/com/pitchedapps/frost/views/FrostRecyclerView.kt | 12 |
2 files changed, 73 insertions, 55 deletions
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostContentView.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostContentView.kt index d17a424c..9619eecc 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostContentView.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostContentView.kt @@ -39,12 +39,14 @@ import com.pitchedapps.frost.facebook.FbItem import com.pitchedapps.frost.facebook.WEB_LOAD_DELAY import com.pitchedapps.frost.utils.L import com.pitchedapps.frost.utils.Prefs -import io.reactivex.android.schedulers.AndroidSchedulers -import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.Disposable -import io.reactivex.rxkotlin.addTo -import io.reactivex.subjects.BehaviorSubject -import io.reactivex.subjects.PublishSubject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.channels.BroadcastChannel +import kotlinx.coroutines.channels.ReceiveChannel +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext class FrostContentWeb @JvmOverloads constructor( context: Context, @@ -66,6 +68,7 @@ class FrostContentRecycler @JvmOverloads constructor( override val layoutRes: Int = R.layout.view_content_base_recycler } +@UseExperimental(ExperimentalCoroutinesApi::class) abstract class FrostContentView<out T> @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, @@ -81,11 +84,11 @@ abstract class FrostContentView<out T> @JvmOverloads constructor( override val core: FrostContentCore get() = coreView - override val progressObservable: PublishSubject<Int> = PublishSubject.create() - override val refreshObservable: PublishSubject<Boolean> = PublishSubject.create() - override val titleObservable: BehaviorSubject<String> = BehaviorSubject.create() + override val refreshChannel: BroadcastChannel<Boolean> = BroadcastChannel(100) + override val progressChannel: BroadcastChannel<Int> = BroadcastChannel(100) + override val titleChannel: BroadcastChannel<String> = BroadcastChannel(100) - private val compositeDisposable = CompositeDisposable() + override lateinit var scope: CoroutineScope override lateinit var baseUrl: String override var baseEnum: FbItem? = null @@ -107,24 +110,6 @@ abstract class FrostContentView<out T> @JvmOverloads constructor( protected fun init() { inflate(context, layoutRes, this) coreView.parent = this - - // bind observables - progressObservable.observeOn(AndroidSchedulers.mainThread()).subscribe { - progress.invisibleIf(it == 100) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) - progress.setProgress(it, true) - else - progress.progress = it - }.addTo(compositeDisposable) - - refreshObservable - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - refresh.isRefreshing = it - refresh.isEnabled = true - }.addTo(compositeDisposable) - refresh.setOnRefreshListener { coreView.reload(true) } - reloadThemeSelf() } @@ -132,7 +117,38 @@ abstract class FrostContentView<out T> @JvmOverloads constructor( baseUrl = container.baseUrl baseEnum = container.baseEnum init() + scope = container core.bind(container) + refresh.setOnRefreshListener { + with(coreView) { + reload(true) + } + } + // Begin subscription in the main thread + val refreshReceiver = refreshChannel.openSubscription() + val progressReceiver = progressChannel.openSubscription() + + scope.launch(Dispatchers.Default) { + launch { + for (r in refreshReceiver) { + withContext(Dispatchers.Main) { + refresh.isRefreshing = r + refresh.isEnabled = true + } + } + } + launch { + for (p in progressReceiver) { + withContext(Dispatchers.Main) { + progress.invisibleIf(p == 100) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) + progress.setProgress(p, true) + else + progress.progress = p + } + } + } + } } override fun reloadTheme() { @@ -155,15 +171,15 @@ abstract class FrostContentView<out T> @JvmOverloads constructor( } override fun destroy() { - titleObservable.onComplete() - progressObservable.onComplete() - refreshObservable.onComplete() + titleChannel.close() + progressChannel.close() + refreshChannel.close() core.destroy() - compositeDisposable.dispose() } private var dispose: Disposable? = null private var transitionStart: Long = -1 + private var refreshReceiver: ReceiveChannel<Boolean>? = null /** * Hook onto the refresh observable for one cycle @@ -171,32 +187,32 @@ abstract class FrostContentView<out T> @JvmOverloads constructor( * The cycle only starts on the first load since there may have been another process when this is registered */ override fun registerTransition(urlChanged: Boolean, animate: Boolean): Boolean { - if (!urlChanged && dispose != null) { + if (!urlChanged && refreshReceiver != null) { L.v { "Consuming url load" } return false // still in progress; do not bother with load } L.v { "Registered transition" } with(coreView) { - var loading = dispose != null - dispose?.dispose() - dispose = refreshObservable - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - if (it) { - loading = true - transitionStart = System.currentTimeMillis() - clearAnimation() - if (isVisible) - fadeOut(duration = 200L) - } else if (loading) { - loading = false - if (animate && Prefs.animate) circularReveal(offset = WEB_LOAD_DELAY) - else fadeIn(duration = 200L, offset = WEB_LOAD_DELAY) - L.v { "Transition loaded in ${System.currentTimeMillis() - transitionStart} ms" } - dispose?.dispose() - dispose = null + refreshReceiver = refreshChannel.openSubscription().also { receiver -> + scope.launch(Dispatchers.Main) { + var loading = false + for (r in receiver) { + if (r) { + loading = true + transitionStart = System.currentTimeMillis() + clearAnimation() + if (isVisible) + fadeOut(duration = 200L) + } else if (loading) { + if (animate && Prefs.animate) circularReveal(offset = WEB_LOAD_DELAY) + else fadeIn(duration = 200L, offset = WEB_LOAD_DELAY) + L.v { "Transition loaded in ${System.currentTimeMillis() - transitionStart} ms" } + receiver.cancel() + refreshReceiver = null + } } } + } } return true } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostRecyclerView.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostRecyclerView.kt index 2b9e8f9c..f7cb2214 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostRecyclerView.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostRecyclerView.kt @@ -28,6 +28,7 @@ import com.pitchedapps.frost.contracts.FrostContentCore import com.pitchedapps.frost.contracts.FrostContentParent import com.pitchedapps.frost.fragments.RecyclerContentContract import com.pitchedapps.frost.utils.Prefs +import kotlinx.coroutines.launch /** * Created by Allan Wang on 2017-05-29. @@ -69,11 +70,12 @@ class FrostRecyclerView @JvmOverloads constructor( override fun reloadBase(animate: Boolean) { if (Prefs.animate) fadeOut(onFinish = onReloadClear) - parent.refreshObservable.onNext(true) - recyclerContract.reload({ parent.progressObservable.onNext(it) }) { - parent.progressObservable.onNext(100) - parent.refreshObservable.onNext(false) - if (Prefs.animate) post { circularReveal() } + scope.launch { + parent.refreshChannel.offer(true) + val loaded = recyclerContract.reload { parent.progressChannel.offer(it) } + parent.progressChannel.offer(100) + parent.refreshChannel.offer(false) + if (Prefs.animate) circularReveal() } } |