Skip to content

Commit

Permalink
Refactor login module (#2639)
Browse files Browse the repository at this point in the history
* refactor: Login module

* refactor: Login module
  • Loading branch information
akashmeruva9 authored Jul 5, 2024
1 parent ec8d6b8 commit 89d5a39
Show file tree
Hide file tree
Showing 28 changed files with 513 additions and 273 deletions.
4 changes: 1 addition & 3 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -76,17 +76,15 @@ dependencies {
implementation(projects.core.data)
implementation(projects.core.datastore)
implementation(projects.ui)

implementation(projects.feature.loan)
implementation(projects.feature.login)
implementation(projects.feature.registration)
implementation(projects.feature.beneficiary)
implementation(projects.feature.guarantor)
implementation(projects.feature.savings)
implementation(projects.feature.qr)
implementation(projects.feature.transferProcess)



implementation("androidx.legacy:legacy-support-v4:1.0.0")
implementation(libs.androidx.lifecycle.ktx)
implementation(libs.androidx.lifecycle.extensions)
Expand Down
185 changes: 5 additions & 180 deletions app/src/main/java/org/mifos/mobile/ui/login/LoginActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,13 @@ package org.mifos.mobile.ui.login

import android.content.Intent
import android.os.Bundle
import android.widget.Toast
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import org.mifos.mobile.MifosSelfServiceApp.Companion.context
import org.mifos.mobile.R
import org.mifos.mobile.core.ui.theme.MifosMobileTheme
import org.mifos.mobile.feature.login.screens.LoginScreen
import org.mifos.mobile.ui.activities.PassCodeActivity
import org.mifos.mobile.ui.registration.RegistrationActivity
import org.mifos.mobile.ui.activities.base.BaseActivity
import org.mifos.mobile.utils.LoginUiState
import org.mifos.mobile.core.common.Network

/**
* @author Vishwajeet
Expand All @@ -26,189 +17,22 @@ import org.mifos.mobile.core.common.Network
@AndroidEntryPoint
class LoginActivity : BaseActivity() {

private val viewModel: LoginViewModel by viewModels()

private lateinit var usernameContent: String
private lateinit var passwordContent: String

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MifosMobileTheme {

LoginScreen(
login = { username, password ->
usernameContent = username
passwordContent = password
onLoginClicked()
},
createAccount = { onRegisterClicked() },
getUsernameError = { validateUsername(it) },
getPasswordError = { validatePassword(it) }
startRegisterActivity = { onRegisterClicked() },
startPassCodeActivity = { startPassCodeActivity() },
)
}
}

lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.loginUiState.collect { state ->
when (state) {
LoginUiState.Loading -> showProgress()

LoginUiState.Error -> {
hideProgress()
showMessage(context?.getString(R.string.login_failed))
}

LoginUiState.LoginSuccess -> {
onLoginSuccess()
}

is LoginUiState.LoadClientSuccess -> {
hideProgress()
showPassCodeActivity(state.clientName)
}

LoginUiState.Initial -> {}
}
}
}
}
}

/**
* Called when Login is user has successfully logged in
*/
private fun onLoginSuccess() {
viewModel.loadClient()
}

/**
* Shows ProgressDialog when called
*/
private fun showProgress() {
showProgressDialog(getString(R.string.progress_message_login))
}

/**
* Hides the progressDialog which is being shown
*/
private fun hideProgress() {
hideProgressDialog()
}

/**
* Starts [PassCodeActivity]
*/
private fun showPassCodeActivity(clientName: String?) {
showToast(getString(R.string.toast_welcome, clientName))
startPassCodeActivity()
}

/**
* It is called whenever any error occurs while executing a request
*
* @param errorMessage Error message that tells the user about the problem.
*/
private fun showMessage(errorMessage: String?) {
showToast(errorMessage!!, Toast.LENGTH_LONG)
}

/**
* Called when Login Button is clicked, used for logging in the user
*/

private fun onLoginClicked() {
if (Network.isConnected(this)) {
if (isCredentialsValid(usernameContent, passwordContent))
viewModel.login(usernameContent, passwordContent)
} else {
showMessage(context?.getString(R.string.no_internet_connection))
}
}

private fun isCredentialsValid(username: String, password: String): Boolean {
var credentialValid = true
when {
viewModel.isFieldEmpty(username) -> {
credentialValid = false
}

viewModel.isUsernameLengthInadequate(username) -> {
credentialValid = false
}

viewModel.usernameHasSpaces(username) -> {
credentialValid = false
}
}

when {
viewModel.isFieldEmpty(password) -> {
credentialValid = false
}

viewModel.isPasswordLengthInadequate(password) -> {
credentialValid = false
}
}
return credentialValid
}

private fun validateUsername(username: String): String {
var usernameError = ""
when {
viewModel.isFieldEmpty(username) -> {
usernameError = context?.getString(
R.string.error_validation_blank,
context?.getString(R.string.username),
).toString()
}

viewModel.isUsernameLengthInadequate(username) -> {
usernameError = context?.getString(
R.string.error_validation_minimum_chars,
resources?.getString(R.string.username),
resources?.getInteger(R.integer.username_minimum_length),
).toString()
}

viewModel.usernameHasSpaces(username) -> {
usernameError = context?.getString(
R.string.error_validation_cannot_contain_spaces,
resources?.getString(R.string.username),
context?.getString(R.string.not_contain_username),
).toString()
}
}
return usernameError
}

private fun validatePassword(password: String): String {
var passwordError = ""
when {
viewModel.isFieldEmpty(password) -> {
passwordError = context?.getString(
R.string.error_validation_blank,
context?.getString(R.string.password),
).toString()

}

viewModel.isPasswordLengthInadequate(password) -> {
passwordError = context?.getString(
R.string.error_validation_minimum_chars,
resources?.getString(R.string.password),
resources?.getInteger(R.integer.password_minimum_length),
).toString()
}
}
return passwordError
}

private fun onRegisterClicked() {
startActivity(Intent(this@LoginActivity, RegistrationActivity::class.java))
}

/**
* Starts [PassCodeActivity] with `Constans.INTIAL_LOGIN` as true
*/
Expand All @@ -219,4 +43,5 @@ class LoginActivity : BaseActivity() {
startActivity(intent)
finish()
}

}
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package org.mifos.mobile.ui.registration

import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.view.WindowInsets
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.runtime.DisposableEffect
import androidx.compose.ui.platform.LocalView
import androidx.core.view.WindowCompat
import androidx.navigation.compose.rememberNavController
import org.mifos.mobile.core.ui.theme.MifosMobileTheme
import org.mifos.mobile.feature.registration.navigation.RegistrationNavGraph
Expand All @@ -14,6 +19,8 @@ import org.mifos.mobile.ui.login.LoginActivity
class RegistrationActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

WindowCompat.setDecorFitsSystemWindows(window, false)
enableEdgeToEdge()
setContent {
MifosMobileTheme {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ import org.mifos.mobile.feature.savings.savings_account_transaction.SavingAccoun
import java.time.Instant
import javax.inject.Inject


/**
* Created by dilpreet on 6/3/17.
*/
Expand Down
9 changes: 0 additions & 9 deletions app/src/main/java/org/mifos/mobile/utils/LoginUiState.kt

This file was deleted.

50 changes: 27 additions & 23 deletions app/src/test/java/org/mifos/mobile/viewModels/LoginViewModelTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@ import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.test.setMain
import org.junit.*
import org.junit.runner.RunWith
import com.mifos.mobile.core.data.utils.FakeRemoteDataSource
import org.mifos.mobile.models.Page
import org.mifos.mobile.models.User
import org.mifos.mobile.models.client.Client
import org.mifos.mobile.repositories.ClientRepository
import org.mifos.mobile.repositories.UserAuthRepository
import org.mifos.mobile.ui.login.LoginViewModel
import org.mifos.mobile.core.data.repositories.ClientRepository
import org.mifos.mobile.core.data.repositories.UserAuthRepository
import org.mifos.mobile.core.model.entity.Page
import org.mifos.mobile.core.model.entity.User
import org.mifos.mobile.core.model.entity.client.Client
import org.mifos.mobile.feature.login.utils.LoginState
import org.mifos.mobile.feature.login.viewmodel.LoginViewModel
import org.mifos.mobile.util.RxSchedulersOverrideRule
import org.mifos.mobile.utils.FakeRemoteDataSource
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.mock
Expand Down Expand Up @@ -48,10 +49,13 @@ class LoginViewModelTest {
@Before
fun setUp() {
MockitoAnnotations.openMocks(this)
loginViewModel = LoginViewModel(userAuthRepositoryImp, clientRepositoryImp)
mockUser = com.mifos.mobile.core.data.utils.FakeRemoteDataSource.user
emptyClientPage = com.mifos.mobile.core.data.utils.FakeRemoteDataSource.noClients
clientPage = com.mifos.mobile.core.data.utils.FakeRemoteDataSource.clients
loginViewModel = LoginViewModel(
userAuthRepositoryImp,
clientRepositoryImp
)
mockUser = FakeRemoteDataSource.user
emptyClientPage = FakeRemoteDataSource.noClients
clientPage = FakeRemoteDataSource.clients
}

@Test
Expand Down Expand Up @@ -110,8 +114,8 @@ class LoginViewModelTest {
).thenReturn(flowOf(mockUser))
loginViewModel.loginUiState.test {
loginViewModel.login("username", "password")
Assert.assertEquals(LoginUiState.Initial, awaitItem())
Assert.assertEquals(LoginUiState.LoginSuccess, awaitItem())
Assert.assertEquals(LoginState.Initial, awaitItem())
Assert.assertEquals(LoginState.LoginSuccess, awaitItem())
cancelAndIgnoreRemainingEvents()
}
Dispatchers.resetMain()
Expand All @@ -125,8 +129,8 @@ class LoginViewModelTest {
).thenThrow(Exception("Error occurred"))
loginViewModel.loginUiState.test {
loginViewModel.login("username", "password")
Assert.assertEquals(LoginUiState.Initial, awaitItem())
Assert.assertEquals(LoginUiState.Error, awaitItem())
Assert.assertEquals(LoginState.Initial, awaitItem())
Assert.assertEquals(LoginState.Error, awaitItem())
cancelAndIgnoreRemainingEvents()
}
Dispatchers.resetMain()
Expand All @@ -140,9 +144,9 @@ class LoginViewModelTest {
).thenThrow(Exception("Error occurred"))
loginViewModel.loginUiState.test {
loginViewModel.loadClient()
Assert.assertEquals(LoginUiState.Initial, awaitItem())
Assert.assertEquals(LoginUiState.Loading, awaitItem())
Assert.assertEquals(LoginUiState.Error, awaitItem())
Assert.assertEquals(LoginState.Initial, awaitItem())
Assert.assertEquals(LoginState.Loading, awaitItem())
Assert.assertEquals(LoginState.Error, awaitItem())
cancelAndIgnoreRemainingEvents()
}
Mockito.verify(clientRepositoryImp).clearPrefHelper()
Expand All @@ -158,9 +162,9 @@ class LoginViewModelTest {
).thenThrow(Exception("Error occurred"))
loginViewModel.loginUiState.test {
loginViewModel.loadClient()
Assert.assertEquals(LoginUiState.Initial, awaitItem())
Assert.assertEquals(LoginUiState.Loading, awaitItem())
Assert.assertEquals(LoginUiState.Error, awaitItem())
Assert.assertEquals(LoginState.Initial, awaitItem())
Assert.assertEquals(LoginState.Loading, awaitItem())
Assert.assertEquals(LoginState.Error, awaitItem())
cancelAndIgnoreRemainingEvents()
}
Dispatchers.resetMain()
Expand Down Expand Up @@ -188,8 +192,8 @@ class LoginViewModelTest {
)
loginViewModel.loginUiState.test {
loginViewModel.loadClient()
Assert.assertEquals(LoginUiState.Initial, awaitItem())
Assert.assertEquals(LoginUiState.LoadClientSuccess(clientName), awaitItem())
Assert.assertEquals(LoginState.Initial, awaitItem())
Assert.assertEquals(LoginState.LoadClientSuccess(clientName), awaitItem())
cancelAndIgnoreRemainingEvents()
}
Dispatchers.resetMain()
Expand Down
6 changes: 6 additions & 0 deletions core/common/src/main/res/values/dimens.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<resources>

<dimen name="account_status_width">25dp</dimen>
<dimen name="account_status_height">25dp</dimen>

</resources>
Loading

0 comments on commit 89d5a39

Please sign in to comment.