Sample App

First, let’s define what login screen should do. It has to authenticate, and if checkbox ‘Save login’ is checked, then save login and password to Shared Preferences. Hence, on start we need to check saved credentials, and if they exist, try to make authentication using them.

Now, let’s try to model state for the screen. We need fields for login and password itself. If validation of any of them fails, we need to show errors respectively, and disable login button. Plus, flag for checkbox. When the auth request starts we need to show progress bar, and if request fails or succeeds, we also need flags for them.

data class LoginState(val login: String = "",

val loginError: String? = null,

val pass: String = "",

val passError: String? = null,

val saveUser: Boolean = false,

val isLoading: Boolean = true,

val error: String? = null,

val btnEnabled: Boolean = false,

val isLogged: Boolean = false) : State()

And this is our render function

For the sake of post length, let’s take a look at only one scenario — initialization of login screen. We need two side effects — load data from Shared Preferences and HTTP Request for auth.

class GetSavedUserCmd : Cmd()

data class LoginCmd(val login: String, val pass: String) : Cmd()

And two messages for passing results of these commands

data class UserCredentialsLoadedMsg(val login: String, val pass: String) : Msg()

data class LoginResponseMsg(val logged: Boolean) : Msg()

And here is how Init, Update and Call functions will look like

As you can see the code is very concise, and easy to follow.

Update 02.04.2019 If you liked the ideas of Elm Architecture and want to try it out in Android app, we release it as library RxElm. You can find it on github. You are very welcome to try it out, file an issues, and submit PRs ;-)

Testing

One of the main advantages of TEA is incredible testability. In an usual MVP app you normally test business logic, Use Cases, etc. What TEA gives is the ability to test UI behaviour in connection. We can simulate interactions of user with UI by simply calling function Update -> Render -> Call one by one with necessary predefined values! What you normally do with Instrumentation tests(or Espresso tests) you can do with Unit Tests!

We can easily create tests for scenarios like:

Load saved credentials -> If they exist, try to auth -> If succeeds, go to main screen

Load saved credentials -> They do not exist, hide progress bar and show login form

Load saved credentials -> If they exist, try to auth -> Auth ends with error, stop progress bar and show error

Let’s take the first one, and implement it