kotlin-maze
kotlin-maze copied to clipboard
:steam_locomotive: A simple way to implement applications using observable streams

kotlin-maze

kotlin-maze
:steam_locomotive: A simple way to implement applications using observable streams
██╗ ██╗ ██████╗ ████████╗██╗ ██╗███╗ ██╗ ███╗ ███╗ █████╗ ███████╗███████╗
██║ ██╔╝██╔═══██╗╚══██╔══╝██║ ██║████╗ ██║ ████╗ ████║██╔══██╗╚══███╔╝██╔════╝
█████╔╝ ██║ ██║ ██║ ██║ ██║██╔██╗ ██║█████╗██╔████╔██║███████║ ███╔╝ █████╗
██╔═██╗ ██║ ██║ ██║ ██║ ██║██║╚██╗██║╚════╝██║╚██╔╝██║██╔══██║ ███╔╝ ██╔══╝
██║ ██╗╚██████╔╝ ██║ ███████╗██║██║ ╚████║ ██║ ╚═╝ ██║██║ ██║███████╗███████╗
╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚══════╝╚═╝╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚══════╝
Usage
Create immutable view model
Recommend create class as comparable like
data
class
data class HelloModel(
val name: String = ""
)
Implement MazeListener
class HelloFragment : BaseFragment(), MazeListener<HelloModel> {
override val layoutId: Int = R.layout.fragment_hello
// Don't be in lifecycle of `Fragment`/`Activity`
// In this case, `BaseFragment` is set to `retainInstance = true` basically
// Set initial view model
private val maze by lazy { Maze(HelloModel()) }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
// Attach maze with user events
// Event.id is used to filter in `main` function
maze.attach(this, arrayOf(
toolbar.navigationClicks()
.map { ClickEvent(R.id.homeAsUp) },
inputName.textChanges()
.map { TextChangeEvent(R.id.inputName, it) }
))
}
override fun onDestroyView() {
// Detach
maze.detach()
super.onDestroyView()
}
// Implement main function
override fun main(sources: Sources<HelloModel>) = helloMain(sources)
// Render view model
override fun render(prev: HelloModel, curr: HelloModel) {
val hello = getString(R.string.hello_message)
textHello.text = hello.format(curr.name)
}
// Navigate somethings
override fun navigate(navigation: Navigation) {
when (navigation) {
is Back -> activity?.onBackPressed()
}
}
// Cleanup if Activity is finished
override fun finish() = maze.finish()
// Handle errors
override fun error(t: Throwable) {
t.printStackTrace()
}
}
Implement main function
Implement main logic using Observable
s
fun helloMain(sources: Sources<HelloModel>): Sinks<HelloModel> {
val model = sources.event
.textChanges(R.id.inputName)
.map(CharSequence::toString)
.withLatestFrom(sources.model,
BiFunction { name: String, model: HelloModel ->
model.copy(name = name)
})
.cacheWithInitialCapacity(1)
val navigation = sources.event
.clicks(R.id.homeAsUp)
.map { Back() }
// `model` must be `ObservableCache`
return Sinks(model, navigation)
}
Customize Navigation
s, Event
s
You can extend Navigation
s and/or Event
s if you want
Please refer to default
Navigation
s,
Event
s
More examples
- Hello, World!
- Counter
- Progress
- Animation
- Login
- HTTP
- HTTP + Infinite Scrolling
- Tests
Install
repositories {
jcenter()
}
compile "com.importre:kotlin-maze:$maze_version"
for test
testCompile "com.importre:kotlin-maze-test:$maze_version"
Slides
License
Apache 2.0 © Jaewe Heo