Skip to content

Instantly share code, notes, and snippets.

@folkyatina
Created August 17, 2018 17:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save folkyatina/42ed9375a2095435a6e9f595aa92e646 to your computer and use it in GitHub Desktop.
Save folkyatina/42ed9375a2095435a6e9f595aa92e646 to your computer and use it in GitHub Desktop.
Super simple MVP for Android + Navigator as an example
package com.songsterr.mvp
import android.arch.lifecycle.ViewModel
// Immutable view state
interface ViewState
interface View<in S: ViewState> {
fun render(state: S) {}
}
abstract class Presenter< S: ViewState, V: View<S>>(protected var state: S): ViewModel() {
var view: V? = null
fun takeView(view: V) {
this.view = view
view.render(state)
}
fun dropView() {
this.view = null
}
}
package com.songsterr.mvp
/**
* Here is a simple navigational module that can only safely start activities for result
*/
import android.content.Context
import android.content.Intent
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentActivity
import org.koin.android.viewmodel.ext.android.sharedViewModel
private const val RC_NAVIGATOR = 0x99
private const val FRAGMENT_TAG = "navigation"
object Navigation {
@JvmStatic
fun init(activity: FragmentActivity) {
val manager = activity.supportFragmentManager
if (manager.findFragmentByTag(FRAGMENT_TAG) == null) {
manager
.beginTransaction()
.add(NavigatorFragment(), FRAGMENT_TAG)
.commit()
}
}
}
data class NavigatorState(val intent: Intent? = null, val callback: ((Int, Intent?) -> Unit)? = null): ViewState {
fun isOccupied() : Boolean {
return intent != null || callback != null
}
}
class Navigator: Presenter<NavigatorState, NavigatorFragment>(NavigatorState()) {
fun launchActivity(intent: Intent, callbackForResult: ((Int, Intent?) -> Unit)?): Boolean {
if (state.isOccupied()) {
return false
}
state = NavigatorState(intent, callbackForResult)
view?.render(state)
return true
}
fun navigationLaunched() {
state = NavigatorState(null, callback = state.callback)
}
fun navigationResult(resultCode: Int, data: Intent?) {
state.callback?.invoke(resultCode, data)
state = NavigatorState()
}
}
class NavigatorFragment: Fragment(), View<NavigatorState> {
private val presenter: Navigator by sharedViewModel()
override fun onAttach(context: Context?) {
super.onAttach(context)
presenter.takeView(this)
}
override fun onDestroy() {
super.onDestroy()
presenter.dropView()
}
override fun render(state: NavigatorState) {
if (state.intent != null) {
startActivityForResult(state.intent, RC_NAVIGATOR)
presenter.navigationLaunched()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == RC_NAVIGATOR) {
presenter.navigationResult(resultCode, data)
} else {
super.onActivityResult(requestCode, resultCode, data)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment