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

Bug + Refactor: Features-> Auth Module . #2239

Merged
merged 12 commits into from
Nov 19, 2024
9 changes: 9 additions & 0 deletions feature/auth/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
/*
* Copyright 2024 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* See https://github.com/openMF/android-client/blob/master/LICENSE.md
*/
plugins {
alias(libs.plugins.mifos.android.feature)
alias(libs.plugins.mifos.android.library.compose)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
/*
* Copyright 2024 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* See https://github.com/openMF/android-client/blob/master/LICENSE.md
*/
package com.mifos.feature.auth

import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4

import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith

import org.junit.Assert.*

/**
* Instrumented test, which will execute on an Android device.
*
Expand All @@ -21,4 +28,4 @@ class ExampleInstrumentedTest {
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.mifos.feature.auth.test", appContext.packageName)
}
}
}
9 changes: 9 additions & 0 deletions feature/auth/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2024 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file,
You can obtain one at https://mozilla.org/MPL/2.0/.
See https://github.com/openMF/android-client/blob/master/LICENSE.md
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

</manifest>
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
/*
* Copyright 2024 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* See https://github.com/openMF/android-client/blob/master/LICENSE.md
*/
package com.mifos.feature.auth.login

import androidx.compose.foundation.isSystemInDarkTheme
Expand Down Expand Up @@ -71,13 +80,13 @@ import com.mifos.feature.auth.R
*/

@Composable
fun LoginScreen(
internal fun LoginScreen(
homeIntent: () -> Unit,
passcodeIntent: () -> Unit,
onClickToUpdateServerConfig: () -> Unit,
modifier: Modifier = Modifier,
loginViewModel: LoginViewModel = hiltViewModel(),
) {

val loginViewModel: LoginViewModel = hiltViewModel()
val state = loginViewModel.loginUiState.collectAsState().value
val context = LocalContext.current

Expand All @@ -87,12 +96,12 @@ fun LoginScreen(

var userName by rememberSaveable(stateSaver = TextFieldValue.Saver) {
mutableStateOf(
TextFieldValue("")
TextFieldValue(""),
)
}
var password by rememberSaveable(stateSaver = TextFieldValue.Saver) {
mutableStateOf(
TextFieldValue("")
TextFieldValue(""),
)
}
var passwordVisibility: Boolean by remember { mutableStateOf(false) }
Expand Down Expand Up @@ -130,45 +139,44 @@ fun LoginScreen(
}
}


Scaffold(
modifier = Modifier
modifier = modifier
.fillMaxSize()
.padding(16.dp),
containerColor = Color.White,
snackbarHost = { SnackbarHost(snackbarHostState) },
bottomBar = {
Box(
modifier = Modifier.fillMaxWidth(),
contentAlignment = Alignment.Center
contentAlignment = Alignment.Center,
) {
FilledTonalButton(
onClick = onClickToUpdateServerConfig,
modifier = Modifier
.align(Alignment.Center),
colors = ButtonDefaults.filledTonalButtonColors(
containerColor = MaterialTheme.colorScheme.tertiaryContainer,
contentColor = MaterialTheme.colorScheme.tertiary
)
contentColor = MaterialTheme.colorScheme.tertiary,
),
) {
Text(text = "Update Server Configuration")

Spacer(modifier = Modifier.width(4.dp))

Icon(
imageVector = Icons.AutoMirrored.Filled.ArrowForward,
contentDescription = "ArrowForward"
contentDescription = "ArrowForward",
)
}
}
}
},
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(it)
.verticalScroll(rememberScrollState()),
horizontalAlignment = Alignment.CenterHorizontally
horizontalAlignment = Alignment.CenterHorizontally,

) {
Spacer(modifier = Modifier.height(80.dp))
Expand All @@ -185,8 +193,8 @@ fun LoginScreen(
fontSize = 16.sp,
fontWeight = FontWeight.Bold,
fontStyle = FontStyle.Normal,
color = DarkGray
)
color = DarkGray,
),
)

Spacer(modifier = Modifier.height(16.dp))
Expand All @@ -203,7 +211,7 @@ fun LoginScreen(
if (usernameError.value != null) {
Icon(imageVector = Icons.Filled.Error, contentDescription = null)
}
}
},
)

Spacer(modifier = Modifier.height(6.dp))
Expand All @@ -219,16 +227,18 @@ fun LoginScreen(
error = passwordError.value,
trailingIcon = {
if (passwordError.value == null) {
val image = if (passwordVisibility)
val image = if (passwordVisibility) {
Icons.Filled.Visibility
else Icons.Filled.VisibilityOff
} else {
Icons.Filled.VisibilityOff
}
IconButton(onClick = { passwordVisibility = !passwordVisibility }) {
Icon(imageVector = image, null)
}
} else {
Icon(imageVector = Icons.Filled.Error, contentDescription = null)
}
}
},
)

Spacer(modifier = Modifier.height(8.dp))
Expand All @@ -241,8 +251,8 @@ fun LoginScreen(
.padding(start = 16.dp, end = 16.dp),
contentPadding = PaddingValues(),
colors = ButtonDefaults.buttonColors(
containerColor = if (isSystemInDarkTheme()) BluePrimaryDark else BluePrimary
)
containerColor = if (isSystemInDarkTheme()) BluePrimaryDark else BluePrimary,
),
) {
Text(text = "Login", fontSize = 16.sp)
}
Expand All @@ -252,8 +262,8 @@ fun LoginScreen(
onDismissRequest = { showDialog.value },
properties = DialogProperties(
dismissOnBackPress = false,
dismissOnClickOutside = false
)
dismissOnClickOutside = false,
),
) {
CircularProgressIndicator(color = White)
}
Expand All @@ -263,6 +273,6 @@ fun LoginScreen(

@Preview(showSystemUi = true, device = "id:pixel_7")
@Composable
fun LoginScreenPreview() {
private fun LoginScreenPreview() {
LoginScreen({}, {}, {})
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
/*
* Copyright 2024 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* See https://github.com/openMF/android-client/blob/master/LICENSE.md
*/
package com.mifos.feature.auth.login

/**
Expand All @@ -18,5 +27,4 @@ sealed class LoginUiState {
data object HomeActivityIntent : LoginUiState()

data object PassCodeActivityIntent : LoginUiState()

}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
/*
* Copyright 2024 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* See https://github.com/openMF/android-client/blob/master/LICENSE.md
*/
package com.mifos.feature.auth.login

import android.content.Context
Expand Down Expand Up @@ -31,16 +40,14 @@ class LoginViewModel @Inject constructor(
private val usernameValidationUseCase: UsernameValidationUseCase,
private val passwordValidationUseCase: PasswordValidationUseCase,
private val baseApiManager: BaseApiManager,
private val loginUseCase: com.mifos.core.domain.use_cases.LoginUseCase
private val loginUseCase: com.mifos.core.domain.use_cases.LoginUseCase,
) :
ViewModel() {

private val _loginUiState = MutableStateFlow<LoginUiState>(LoginUiState.Empty)
val loginUiState = _loginUiState.asStateFlow()


fun validateUserInputs(username: String, password: String) {

val usernameValidationResult = usernameValidationUseCase(username)
val passwordValidationResult = passwordValidationUseCase(password)

Expand All @@ -50,7 +57,7 @@ class LoginViewModel @Inject constructor(
if (hasError) {
_loginUiState.value = LoginUiState.ShowValidationError(
usernameValidationResult.message,
passwordValidationResult.message
passwordValidationResult.message,
)
return
}
Expand All @@ -66,7 +73,7 @@ class LoginViewModel @Inject constructor(
password,
prefManager.getServerConfig.getInstanceUrl(),
prefManager.getServerConfig.tenant,
true
true,
)
if (Network.isOnline(context)) {
login(username, password)
Expand All @@ -76,7 +83,6 @@ class LoginViewModel @Inject constructor(
}
}


fun login(username: String, password: String) {
viewModelScope.launch(Dispatchers.IO) {
loginUseCase(username, password).collect { result ->
Expand All @@ -98,11 +104,10 @@ class LoginViewModel @Inject constructor(
}
}


private fun onLoginSuccessful(
user: PostAuthenticationResponse,
username: String,
password: String
password: String,
) {
// Saving username password
prefManager.usernamePassword = Pair(username, password)
Expand All @@ -119,5 +124,4 @@ class LoginViewModel @Inject constructor(
_loginUiState.value = LoginUiState.PassCodeActivityIntent
}
}

}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
/*
* Copyright 2024 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* See https://github.com/openMF/android-client/blob/master/LICENSE.md
*/
package com.mifos.feature.auth.navigation

import androidx.navigation.NavController
Expand All @@ -9,37 +18,36 @@ import com.mifos.feature.auth.login.LoginScreen
fun NavGraphBuilder.authNavGraph(
navigateHome: () -> Unit,
navigatePasscode: () -> Unit,
updateServerConfig: () -> Unit
updateServerConfig: () -> Unit,
) {
navigation(
startDestination = AuthScreens.LoginScreen.route,
route = AuthScreens.LoginScreenRoute.route
route = AuthScreens.LoginScreenRoute.route,
) {
loginRoute(
navigatePasscode = navigatePasscode,
navigateHome = navigateHome,
updateServerConfig = updateServerConfig
updateServerConfig = updateServerConfig,
)
}

}

fun NavGraphBuilder.loginRoute(
private fun NavGraphBuilder.loginRoute(
navigateHome: () -> Unit,
navigatePasscode: () -> Unit,
updateServerConfig: () -> Unit
updateServerConfig: () -> Unit,
) {
composable(
route = AuthScreens.LoginScreen.route
route = AuthScreens.LoginScreen.route,
) {
LoginScreen(
homeIntent = navigateHome,
passcodeIntent = navigatePasscode,
onClickToUpdateServerConfig = updateServerConfig
onClickToUpdateServerConfig = updateServerConfig,
)
}
}

fun NavController.navigateToLogin() {
navigate(AuthScreens.LoginScreen.route)
}
}
Loading
Loading