LoginFragment.kt
package chat.rocket.android.authentication.login.ui
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import chat.rocket.android.R
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.authentication.login.presentation.LoginPresenter
import chat.rocket.android.authentication.login.presentation.LoginView
import chat.rocket.android.authentication.ui.AuthenticationActivity
import chat.rocket.android.helper.getCredentials
import chat.rocket.android.helper.hasCredentialsSupport
import chat.rocket.android.helper.requestStoredCredentials
import chat.rocket.android.helper.saveCredentials
import chat.rocket.android.util.extension.asObservable
import chat.rocket.android.util.extensions.clearLightStatusBar
import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.textContent
import chat.rocket.android.util.extensions.ui
import dagger.android.support.AndroidSupportInjection
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.Observables
import kotlinx.android.synthetic.main.app_bar.*
import kotlinx.android.synthetic.main.fragment_authentication_log_in.*
import javax.inject.Inject
private const val SERVER_NAME = "server_name"
internal const val REQUEST_CODE_FOR_SIGN_IN_REQUIRED = 1
internal const val REQUEST_CODE_FOR_MULTIPLE_ACCOUNTS_RESOLUTION = 2
internal const val REQUEST_CODE_FOR_SAVE_RESOLUTION = 3
fun newInstance(serverName: String): Fragment = LoginFragment().apply {
arguments = Bundle(1).apply {
putString(SERVER_NAME, serverName)
}
}
class LoginFragment : Fragment(), LoginView {
@Inject
lateinit var presenter: LoginPresenter
@Inject
lateinit var analyticsManager: AnalyticsManager
private var serverName: String? = null
private val editTextsDisposable = CompositeDisposable()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
AndroidSupportInjection.inject(this)
arguments?.run {
serverName = getString(SERVER_NAME)
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? = container?.inflate(R.layout.fragment_authentication_log_in)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupToolbar()
presenter.setupView()
subscribeEditTexts()
setupOnClickListener()
analyticsManager.logScreenView(ScreenViewEvent.Login)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (resultCode == Activity.RESULT_OK) {
if (data != null) {
when (requestCode) {
REQUEST_CODE_FOR_MULTIPLE_ACCOUNTS_RESOLUTION ->
getCredentials(data)?.let {
onCredentialRetrieved(it.first, it.second)
}
REQUEST_CODE_FOR_SIGN_IN_REQUIRED ->
getCredentials(data)?.let { credential ->
text_username_or_email.setText(credential.first)
text_password.setText(credential.second)
}
REQUEST_CODE_FOR_SAVE_RESOLUTION -> showMessage(getString(R.string.msg_credentials_saved_successfully))
}
}
}
}
override fun onResume() {
super.onResume()
if (hasCredentialsSupport()) {
// NOTE: Disabling the GLS feature for now. Needs to improve its behaviour on the app.
// requestStoredCredentials()
}
}
override fun onDestroyView() {
super.onDestroyView()
unsubscribeEditTexts()
}
private fun setupToolbar() {
with(activity as AuthenticationActivity) {
this.clearLightStatusBar()
toolbar.isVisible = true
toolbar.title = serverName?.replace(getString(R.string.default_protocol), "")
}
}
override fun showLoading() {
ui {
disableUserInput()
view_loading.isVisible = true
}
}
override fun hideLoading() {
ui {
view_loading.isVisible = false
enableUserInput()
}
}
override fun showMessage(resId: Int) {
ui {
showToast(resId)
}
}
override fun showMessage(message: String) {
ui {
showToast(message)
}
}
override fun showGenericErrorMessage() = showMessage(R.string.msg_generic_error)
private fun setupOnClickListener() =
ui {
button_log_in.setOnClickListener {
presenter.authenticateWithUserAndPassword(
text_username_or_email.textContent,
text_password.textContent
)
}
}
override fun showForgotPasswordView() {
ui {
button_forgot_your_password.isVisible = true
button_forgot_your_password.setOnClickListener { presenter.forgotPassword() }
}
}
override fun enableButtonLogin() {
context?.let {
ViewCompat.setBackgroundTintList(
button_log_in, ContextCompat.getColorStateList(it, R.color.colorAccent)
)
button_log_in.isEnabled = true
}
}
override fun disableButtonLogin() {
context?.let {
ViewCompat.setBackgroundTintList(
button_log_in,
ContextCompat.getColorStateList(it, R.color.colorAuthenticationButtonDisabled)
)
button_log_in.isEnabled = false
}
}
override fun enableButtonForgetPassword() {
context?.let {
button_forgot_your_password.isEnabled = true
button_forgot_your_password.setTextColor(
ContextCompat.getColorStateList(it, R.color.colorAccent)
)
}
}
override fun disableButtonForgetPassword() {
context?.let {
button_forgot_your_password.isEnabled = false
button_forgot_your_password.setTextColor(
ContextCompat.getColorStateList(it, R.color.colorAuthenticationButtonDisabled)
)
}
}
private fun requestStoredCredentials() {
activity?.requestStoredCredentials()?.let { credentials ->
onCredentialRetrieved(credentials.first, credentials.second)
}
}
private fun onCredentialRetrieved(id: String, password: String) {
presenter.authenticateWithUserAndPassword(id, password)
}
override fun saveSmartLockCredentials(id: String, password: String) {
activity?.saveCredentials(id, password)
}
private fun subscribeEditTexts() {
editTextsDisposable.add(
Observables.combineLatest(
text_username_or_email.asObservable(),
text_password.asObservable()
) { text_username_or_email, text_password ->
return@combineLatest (
text_username_or_email.isNotBlank() && text_password.isNotBlank()
)
}.subscribe { isValid ->
if (isValid) {
enableButtonLogin()
} else {
disableButtonLogin()
}
})
}
private fun unsubscribeEditTexts() = editTextsDisposable.clear()
private fun enableUserInput() {
ui {
enableButtonLogin()
enableButtonForgetPassword()
text_username_or_email.isEnabled = true
text_password.isEnabled = true
}
}
private fun disableUserInput() {
ui {
disableButtonLogin()
disableButtonForgetPassword()
text_username_or_email.isEnabled = false
text_password.isEnabled = false
}
}
}