Skip to content

esafirm/karma

Folders and files

NameName
Last commit message
Last commit date

Latest commit

d3b0fe8 · Sep 8, 2021

History

30 Commits
Jul 18, 2021
Sep 8, 2021
Sep 8, 2021
Mar 26, 2021
Mar 19, 2021
Feb 2, 2021
Sep 8, 2021
Jan 3, 2021
Sep 8, 2021
Sep 7, 2020
Sep 7, 2020
Sep 7, 2020
Jan 18, 2021
Sep 8, 2021
Jan 18, 2021
Jan 18, 2021

Repository files navigation

OSS Karma Banner

Karma

A library that provide an opinionated way to create Android app with MVI pattern. It supports React's-ish time travel debugging and diff render.

Gradle

In your root build.gradle

allprojects {
  repositories {
    ...
    maven { url 'https://jitpack.io' }
  }
}

In your module build.gradle

dependencies {
  final karmaVersion = "1.3.0"
  implementation "com.github.esafirm.karma:karma-core:$karmaVersion"
  implementation "com.github.esafirm.karma:karma-renderer:$karmaVersion"
  implementation "com.github.esafirm.karma:karma-timetravel:$karmaVersion"
  implementation "com.github.esafirm.karma:karma-timetravel-dashboard:$karmaVersion"
}

Modules

The library currently separated into four modules:

  1. Core
  2. Renderer
  3. Time Travel
  4. Time Travel Dashboard

If we create a dependency tree, it would look like this:

        core
      ___/\___
     /        \
renderer     time travel
                \
            time travel dashboard
  • core module is standalone
  • renderer needs core
  • time travel needs core
  • time travel dasboard needs core & time travel

Usage

Core

Karma core introduce how you can create an MVI-ish application with minimal setup.

To create a screen, what you need is:

  1. A State
  2. A Presenter
  3. An Android Component to bind it all together

State refer to a view state. For example we have this simple state

data class SimpleScreenState(
  val textLineOne: String,
  val textLineTwo: String
)

Presenter is a place that we call all our action that change a state.

class SimplePresenter : UiPresenter<SimpleScreenState>(action) {

  override fun initialState() = SimpleScreenState("a", "b")

  // We change textLineOne and retain our current textLineTwo
  fun changeLineOne(text: String) = setState {
    copy(textLineOne = text)
  }
}

To initialize Karma, you need to now os how to bind all the component together

fun <S, P : KarmaPresenter<S>> bind(
  lifecycleOwner: LifecycleOwner,
  viewModelStoreOwner: ViewModelStoreOwner,
  presenterCreator: () -> P,
  render: (S, P) -> Unit
)

And this is an example of Karma.bind called in AppCompatActivity

Karma.bind(
  lifecycleOwner = this,
  viewModelStoreOwner = this,
  presenter = { SimplePresenter() },
  render = { state, presenter ->
    // do render
  }
)

Or, we could use the extension function to make it more simple

bind(
  presenter = { SimplePresenter() },
  render = renderer::render
)

Renderer

Renderer enable us to control on how we can render state

renderer<State, Presenter> {
  init {
    // This will only called once.
    // Could be used to intialize some views or setup the listener
  }

  diff(State::data) {
    // This will only be called when state.data is changed
  }
	
  event(State::event) {
    // This will use special state called SingleEvent<E> that have internal flag
	// This can be used for notification state (ex: show toast)
  }

  always {
    // This will be always called
  }
}

Time Travel

TBD

Time Travel Dashboard

TBD

Sample

You can find complete usage of Karma in :samples:app module

License

MIT @ Esa Firman