Last active
February 15, 2016 09:55
-
-
Save marcin-kozinski/8650511284841867e397 to your computer and use it in GitHub Desktop.
Half-baked toy Cycle.js implementation on Android, based on first 10 lessons of André Staltz's egghead.io course
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.app.Activity | |
import android.os.Bundle | |
import android.view.View | |
import android.widget.TextView | |
import com.jakewharton.rxbinding.view.clicks | |
import com.jakewharton.rxbinding.widget.text | |
import rx.Observable | |
import rx.android.schedulers.AndroidSchedulers.mainThread | |
import rx.subjects.BehaviorSubject | |
import java.util.concurrent.TimeUnit.SECONDS | |
class CycleActivity : Activity() { | |
override fun onCreate(savedInstanceState: Bundle?) { | |
super.onCreate(savedInstanceState) | |
setContentView(R.layout.activity_cycle) | |
// Logic (functional) | |
fun main(source: Source) = | |
source.select(R.id.app, View::clicks) | |
.startWith(rx.Observable.just<Unit>(null)) | |
.switchMap { rx.Observable.interval(0, 1, SECONDS) } | |
.map { ViewModel("Seconds elapsed\n" + it) } | |
// Effects (imperative) | |
fun androidActivityDriver(viewModelStream: Observable<ViewModel>): (Int) -> View { | |
(findViewById(R.id.app) as TextView).let { app -> | |
val textStream = viewModelStream.onBackpressureDrop() | |
.observeOn(mainThread()) | |
.map { it.label } | |
.distinctUntilChanged() | |
textStream.subscribe(app.text()) | |
} | |
return fun(viewId: Int) = findViewById(viewId) | |
} | |
fun <T> run(main: (Source) -> rx.Observable<T>, driver: (rx.Observable<T>) -> (Int) -> View) { | |
val eventualSelector = BehaviorSubject.create<(Int) -> View>() | |
val sink = main(ProxySource(eventualSelector.asObservable())) | |
val selector = driver(sink) | |
eventualSelector.onNext(selector) | |
} | |
run(::main, ::androidActivityDriver) | |
} | |
} | |
private data class ViewModel(val label: String) | |
private interface Source { | |
fun <V : View, R> select(id: Int, binding: V.() -> rx.Observable<R>): Observable<R> | |
} | |
private class ProxySource(val eventualSelector: Observable<(Int) -> View>) : Source { | |
override fun <V : View, R> select(id: Int, binding: V.() -> rx.Observable<R>) = | |
eventualSelector.map { select -> select(id) } | |
.switchMap { it -> @Suppress("UNCHECKED_CAST") (it as V).binding() } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
It's very early, just half a Sunday of hacking, following along the lessons from https://egghead.io/series/cycle-js-fundamentals
I only got up to lesson 10, I didn't even try to port the virtual DOM approach to Android and I only have one source and sink for now, because my head hurt when I tried to think how to do it in a type-safe language. But it works! It displays the countdown and resets if you click it, just as in the course.