Creating the login view

Now we have to work on LoginActivity. As we are building this application utilizing the MVP pattern, LoginActivity is effectively a view.  Obviously, LoginActivity is quite different from any generic view. It is a view that is concerned with login procedures. We can identify a set of necessary behaviors that a view presenting a login interface to a user must possess. Such behaviors are:

  • It must show a progress bar to a user when the login is in progress
  • It must be capable of hiding the progress bar when the need arises
  • It must be able to show appropriate field errors to users when encountered
  • It must be able to navigate the user to his home screen
  • It must be able to navigate an unregistered user to a signup screen

Having identified the preceding behaviors, we must ensure that LoginActivity—as a login view—exhibits such behaviors. A perfect way to do this is to utilize an interface. Create a LoginView interface in the login package containing the following content:

package com.example.messenger.ui.login

interface LoginView {
fun showProgress()
fun hideProgress()
fun setUsernameError()
fun setPasswordError()
fun navigateToSignUp()
fun navigateToHome()
}

So far, so good with LoginView. There are a few issues with our interface though. A LoginView must have the ability to bind its layout views to appropriate object representations. In addition, a LoginView must be able to provide feedback to the user if an authentication error occurs. You may be thinking that neither of these two behaviors should be distinct to a LoginView. You are right. All views should have the ability to bind layout elements to programmatic objects. In addition, a signup view should also be able to provide the user with some kind of feedback if there is a problem during authentication.

We will create two distinct interfaces to enforce these behaviors. We will name the first interface BaseView. Create a base package in com.example.messenger.ui and add an interface named BaseView to the package with the following content:

package com.example.messenger.ui.base

import android.content.Context

interface BaseView {
fun bindViews()
fun getContext(): Context
}

The BaseView interface enforces that an implementing class declares bindViews() and getContext() functions for view bindings and context retrievals, respectively.

Now create an auth package in com.example.messenger.ui and add an interface named AuthView to the package with the following content:

package com.example.messenger.ui.auth

interface AuthView {
fun showAuthError()
}

Fantastic job! Now go back to the LoginView interface and ensure that it extends BaseView and AuthView, as follows:

package com.example.messenger.ui.login

import com.example.messenger.ui.auth.AuthView
import com.example.messenger.ui.base.BaseView

interface LoginView : BaseView, AuthView {
fun showProgress()
fun hideProgress()
fun setUsernameError()
fun setPasswordError()
fun navigateToSignUp()
fun navigateToHome()
}

By declaring the LoginView interface as an extension of BaseView and AuthView, we ensure that every class that implements LoginView must declare the bindViews(), getContext(), and showAuthError() functions in addition to those declared in LoginView. It is important to note that any class that implements LoginView is effectively of the LoginView, BaseView, and AuthView type. The characteristic of a class possessing many types is known as polymorphism.

Having set up the LoginView, we can go ahead and work on LoginActivity. Firstly we will create LoginActivity to implement the methods declared in  BaseView and AuthView after which we will add the methods specific to a LoginView. LoginActivity is shown in the following code:

package com.example.messenger.ui.login

import android.content.Context
import android.content.Intent
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.ProgressBar
import android.widget.Toast
import com.example.messenger.R

class LoginActivity : AppCompatActivity(), LoginView, View.OnClickListener {

private lateinit var etUsername: EditText
private lateinit var etPassword: EditText
private lateinit var btnLogin: Button
private lateinit var btnSignUp: Button
private lateinit var progressBar: ProgressBar

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)

bindViews()
}

Binds layout view object references to view elements when invoked:


override fun bindViews() {
etUsername = findViewById(R.id.et_username)
etPassword = findViewById(R.id.et_password)
btnLogin = findViewById(R.id.btn_login)
btnSignUp = findViewById(R.id.btn_sign_up)
progressBar = findViewById(R.id.progress_bar)
btnLogin.setOnClickListener(this)
btnSignUp.setOnClickListener(this)
}

/**
* Shows an appropriate Authentication error message when invoked.
*/
override fun showAuthError() {
Toast.makeText(this, "Invalid username and password combination.", Toast.LENGTH_LONG).show()
}

override fun onClick(view: View) {

}

override fun getContext(): Context {
return this
}
}

So far so good. We have successfully implemented BaseView and AuthView methods in LoginActivity. We still must work on the LoginView specific methods showProgress(), hideProgress(), setUsernameError(), setPasswordError(), navigateToSignUp() and navigateToHome(). The required implementation of these  methods is given below. Go ahead and add them to LoginActivity.

override fun hideProgress() {
progressBar.visibility = View.GONE
}

override fun showProgress() {
progressBar.visibility = View.VISIBLE
}

override fun setUsernameError() {
etUsername.error = "Username field cannot be empty"
}

override fun setPasswordError() {
etPassword.error = "Password field cannot be empty"
}

override fun navigateToSignUp() {

}

override fun navigateToHome() {

}

Adding all the defined methods earlier, you have made the LoginActivity class to implement LoginView as well as the View.OnClickListener interface. As such, LoginActivity provides implementations for functions declared within these interfaces. Notice how the current instance of the LoginActivity is passed as an argument to btnLogin.setOnClickListener() via this. We can do this because we have declared LoginActivity to implement the View.OnClickListener interface. As such, LoginActivity is a valid View.OnClickListener instance (this is a perfect example of polymorphism at work). 

Now that we have done some reasonable work on the login view, we must create an appropriate model to handle login logic. We must also create the necessary services and data repositories that this model will communicate with. We will first work on the required services and then develop the necessary data repositories before we build the interactor.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.237.123