Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[2656] - Refactor login module #2639

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading