fix: move auth code to Auth module

This commit is contained in:
Rajan Maurya 2024-03-22 16:43:21 -04:00 committed by Rajan Maurya
parent 41eadbbf91
commit f1b615b220
86 changed files with 1838 additions and 308 deletions

View File

@ -27,6 +27,8 @@ class AndroidFeatureConventionPlugin : Plugin<Project> {
add("implementation", libs.findLibrary("androidx.hilt.navigation.compose").get())
add("implementation", libs.findLibrary("androidx.lifecycle.runtimeCompose").get())
add("implementation", libs.findLibrary("androidx.lifecycle.viewModelCompose").get())
add("androidTestImplementation", libs.findLibrary("androidx.lifecycle.runtimeTesting").get())
}
}
}

View File

@ -29,7 +29,7 @@ plugins {
id("io.gitlab.arturbosch.detekt").version("1.18.1")
}
val detektProjectBaseline by tasks.registering(io.gitlab.arturbosch.detekt.DetektCreateBaselineTask::class) {
val detektProjectBaseline by tasks.registering(DetektCreateBaselineTask::class) {
description = "Overrides current baseline."
ignoreFailures.set(true)
parallel.set(true)

View File

@ -1,6 +1,4 @@
package org.mifos.mobilewallet.mifospay.utils
import org.mifos.mobilewallet.mifospay.R
package org.mifos.mobilewallet.mifospay.common
/**
* Created by naman on 17/6/17.
@ -169,8 +167,8 @@ object Constants {
const val TAP_TO_REVEAL = "Tap to Reveal"
const val NAME = "Name : "
const val ERROR_FETCHING_TRANSACTION_DETAILS = "Error fetching details"
const val WHITE_BACK_BUTTON = R.drawable.ic_arrow_back_white_24dp
const val BLACK_BACK_BUTTON = R.drawable.ic_arrow_back_black_24dp
// const val WHITE_BACK_BUTTON = R.drawable.ic_arrow_back_white_24dp
// const val BLACK_BACK_BUTTON = R.drawable.ic_arrow_back_black_24dp
const val VIEW = "View"
const val CURRENT_PASSCODE = "current passcode"
const val UPDATE_PASSCODE = "update passcode"

View File

@ -20,9 +20,13 @@ dependencies {
api(libs.androidx.compose.material.iconsExtended)
api(libs.androidx.compose.material3)
api(libs.androidx.compose.runtime)
api(libs.androidx.compose.ui.tooling.preview)
api(libs.androidx.compose.ui.util)
api(libs.androidx.hilt.navigation.compose)
debugApi(libs.androidx.compose.ui.tooling)
api(libs.androidx.compose.ui.tooling.preview)
api(libs.androidx.hilt.navigation.compose)
// testImplementation(libs.androidx.compose.ui.test)
// androidTestImplementation(libs.androidx.compose.ui.test)
}

View File

@ -11,10 +11,16 @@ apply(from = "${project.rootDir}/config/quality/quality.gradle")
dependencies {
implementation(projects.core.data)
implementation(libs.compose.country.code.picker)
implementation("com.mifos.mobile:mifos-passcode:0.3.0")
implementation("com.google.android.gms:play-services-auth:20.7.0")
// we need it for country picker library
implementation("androidx.compose.material:material:1.6.0")
implementation(libs.compose.country.code.picker) // remove after moving auth code to module
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)

View File

@ -1,154 +1,19 @@
package org.mifos.mobilewallet.mifospay.feature.auth.login
import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.mifos.mobile.passcode.utils.PasscodePreferencesHelper
import androidx.appcompat.app.AppCompatActivity
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import org.mifos.mobilewallet.mifospay.designsystem.theme.MifosTheme
/**
* Created by naman on 16/6/17.
*/
@AndroidEntryPoint
class LoginActivity : ComponentActivity() {
private val viewModel by viewModels<LoginViewModel>()
private var usernameContent: String = ""
private var passwordContent: String = ""
class LoginActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MifosTheme {
LoginScreen({ username, password ->
usernameContent = username
passwordContent = password
onLoginClicked()
}, {
onSignupClicked()
})
}
}
val pref = PasscodePreferencesHelper(applicationContext)
if (pref.passCode.isNotEmpty()) {
startPassCodeActivity()
}
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect { uiState ->
when(uiState) {
is LoginViewModel.LoginUiState.Success -> {
loginSuccess()
}
is LoginViewModel.LoginUiState.Error -> {
}
is LoginViewModel.LoginUiState.Loading -> {
}
is LoginViewModel.LoginUiState.None -> {
}
}
}
LoginScreen()
}
}
}
private fun loginSuccess() {
//hideProgressDialog()
//hideSoftKeyboard(this)
startPassCodeActivity()
}
private fun onLoginClicked() {
// hideSoftKeyboard(this)
// showProgressDialog(Constants.LOGGING_IN)
viewModel.loginUser(usernameContent, passwordContent)
}
private fun onSignupClicked() {
/*val signupMethod = SignupMethod()
signupMethod.show(supportFragmentManager, Constants.CHOOSE_SIGNUP_METHOD)*/
}
fun loginFail(message: String?) {
/*hideSoftKeyboard(this)
hideProgressDialog()
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()*/
}
/**
* Starts [PassCodeActivity] with `Constans.INTIAL_LOGIN` as true
*/
private fun startPassCodeActivity() {
/*val intent = Intent(this@LoginActivity, PassCodeActivity::class.java)
intent.putExtra(PassCodeConstants.PASSCODE_INITIAL_LOGIN, true)
startActivity(intent)*/
}
fun signupUsingGoogleAccount(mifosSavingsProductId: Int) {
/*showProgressDialog(Constants.PLEASE_WAIT)
mMifosSavingProductId = mifosSavingsProductId
val gso = GoogleSignInOptions.Builder(
GoogleSignInOptions.DEFAULT_SIGN_IN
).requestIdToken(getString(R.string.default_web_client_id)).requestEmail().build()
googleSignInClient = GoogleSignIn.getClient(this, gso)
val signInIntent = googleSignInClient!!.getSignInIntent()
hideProgressDialog()
startActivityForResult(signInIntent, 11)*/
}
public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
/*showProgressDialog(Constants.PLEASE_WAIT)
// Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);
if (requestCode == 11) {
val task = GoogleSignIn.getSignedInAccountFromIntent(data)
try {
// Google Sign In was successful, authenticate with Firebase
account = task.getResult(ApiException::class.java)
hideProgressDialog()
signup(mMifosSavingProductId)
} catch (e: Exception) {
// Google Sign In failed, update UI appropriately
DebugUtil.log(Constants.GOOGLE_SIGN_IN_FAILED, e.message)
Toaster.showToast(this, Constants.GOOGLE_SIGN_IN_FAILED)
hideProgressDialog()
}
}*/
}
fun signup(mifosSavingsProductId: Int) {
/*showProgressDialog(Constants.PLEASE_WAIT)
val intent = Intent(this@LoginActivity, MobileVerificationActivity::class.java)
mMifosSavingProductId = mifosSavingsProductId
intent.putExtra(Constants.MIFOS_SAVINGS_PRODUCT_ID, mMifosSavingProductId)
if (account != null) {
intent.putExtra(Constants.GOOGLE_PHOTO_URI, account!!.photoUrl)
intent.putExtra(Constants.GOOGLE_DISPLAY_NAME, account!!.displayName)
intent.putExtra(Constants.GOOGLE_EMAIL, account!!.email)
intent.putExtra(Constants.GOOGLE_FAMILY_NAME, account!!.familyName)
intent.putExtra(Constants.GOOGLE_GIVEN_NAME, account!!.givenName)
}
hideProgressDialog()
startActivity(intent)
if (googleSignInClient != null) {
googleSignInClient!!.signOut()
.addOnCompleteListener(this, OnCompleteListener { account = null })
}*/
}
}
}

View File

@ -1,8 +1,12 @@
package org.mifos.mobilewallet.mifospay.feature.auth.login
import android.content.Context
import android.content.Intent
import android.widget.Toast
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
@ -28,27 +32,64 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import org.mifos.mobilewallet.mifospay.feature.auth.R
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.mifos.mobile.passcode.utils.PassCodeConstants
import org.mifos.mobilewallet.mifospay.designsystem.component.MfOverlayLoadingWheel
import org.mifos.mobilewallet.mifospay.designsystem.component.MifosOutlinedTextField
import org.mifos.mobilewallet.mifospay.designsystem.theme.MifosTheme
import org.mifos.mobilewallet.mifospay.designsystem.theme.grey
import org.mifos.mobilewallet.mifospay.designsystem.theme.styleMedium16sp
import org.mifos.mobilewallet.mifospay.designsystem.theme.styleMedium30sp
import org.mifos.mobilewallet.mifospay.designsystem.theme.styleNormal18sp
import org.mifos.mobilewallet.mifospay.feature.auth.R
import org.mifos.mobilewallet.mifospay.feature.auth.social_signup.SocialSignupMethodContentScreen
@Composable
fun LoginScreen(
login: (username: String, password: String) -> Unit,
signUp: () -> Unit
viewModel: LoginViewModel = hiltViewModel()
) {
val context = LocalContext.current
val showProgress by viewModel.showProgress.collectAsStateWithLifecycle()
val isLoginSuccess by viewModel.isLoginSuccess.collectAsStateWithLifecycle()
if (viewModel.isPassCodeExist) {
startPassCodeActivity(context)
}
LoginScreenContent(
showProgress = showProgress,
login = { username, password ->
viewModel.loginUser(
username = username,
password = password,
onLoginFailed = { message ->
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
}
)
}
)
if (isLoginSuccess) {
startPassCodeActivity(context)
}
}
@Composable
fun LoginScreenContent(
showProgress: Boolean,
login: (username: String, password: String) -> Unit,
) {
var showSignUpScreen by rememberSaveable { mutableStateOf(false) }
var userName by rememberSaveable(stateSaver = TextFieldValue.Saver) {
mutableStateOf(
TextFieldValue("")
@ -61,7 +102,13 @@ fun LoginScreen(
}
var passwordVisibility: Boolean by remember { mutableStateOf(false) }
MifosTheme {
if (showSignUpScreen) {
SocialSignupMethodContentScreen {
showSignUpScreen = false
}
}
Box {
Column(
modifier = Modifier
.fillMaxWidth()
@ -126,7 +173,7 @@ fun LoginScreen(
)
}
// Hide reset password for now
Text(
/*Text(
modifier = Modifier
.fillMaxWidth()
.padding(top = 32.dp),
@ -143,7 +190,7 @@ fun LoginScreen(
text = "OR",
textAlign = TextAlign.Center,
style = styleMedium16sp.copy(color = grey)
)
)*/
Row(
modifier = Modifier
.fillMaxWidth()
@ -156,7 +203,7 @@ fun LoginScreen(
)
Text(
modifier = Modifier.clickable {
signUp.invoke()
showSignUpScreen = true
},
text = stringResource(id = R.string.feature_auth_sign_up),
style = styleMedium16sp.copy(
@ -165,11 +212,32 @@ fun LoginScreen(
)
}
}
if (showProgress) {
MfOverlayLoadingWheel(
contentDesc = stringResource(id = R.string.feature_auth_logging_in)
)
}
}
}
/**
* Starts [PassCodeActivity] with `Constans.INTIAL_LOGIN` as true
*/
private fun startPassCodeActivity(context: Context) {
/* val intent = Intent(context, PassCodeActivity::class.java)
intent.putExtra(PassCodeConstants.PASSCODE_INITIAL_LOGIN, true)
context.startActivity(intent)*/
}
@Preview(showSystemUi = true, device = "id:pixel_5")
@Composable
fun LoanScreenPreview() {
LoginScreen({ _, _ -> }, {})
MifosTheme {
LoginScreenContent(
showProgress = false,
login = { _, _ -> }
)
}
}

View File

@ -1,108 +1,153 @@
package org.mifos.mobilewallet.mifospay.feature.auth.login
import androidx.lifecycle.SavedStateHandle
import android.util.Log
import androidx.lifecycle.ViewModel
import com.mifos.mobile.passcode.utils.PasscodePreferencesHelper
import com.mifos.mobilewallet.model.domain.user.User
import com.mifos.mobilewallet.model.entity.UserWithRole
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import org.mifos.mobilewallet.core.base.UseCase
import com.mifos.mobilewallet.model.entity.UserWithRole
import org.mifos.mobilewallet.mifospay.core.datastore.PreferencesHelper
import com.mifos.mobilewallet.model.domain.user.User
import kotlinx.coroutines.flow.update
import org.mifos.mobilewallet.core.base.UseCase.UseCaseCallback
import org.mifos.mobilewallet.core.base.UseCaseHandler
import org.mifos.mobilewallet.core.domain.usecase.client.FetchClientData
import org.mifos.mobilewallet.core.domain.usecase.user.AuthenticateUser
import org.mifos.mobilewallet.core.domain.usecase.user.FetchUserDetails
import org.mifos.mobilewallet.core.utils.Constants
import org.mifos.mobilewallet.mifospay.core.datastore.PreferencesHelper
import javax.inject.Inject
/**
* Created by naman on 16/6/17.
*/
@HiltViewModel
class LoginViewModel @Inject constructor(
private val savedStateHandle: SavedStateHandle,
private val mUsecaseHandler: UseCaseHandler,
private val authenticateUserUseCase: AuthenticateUser,
private val fetchClientDataUseCase: FetchClientData,
private var fetchUserDetailsUseCase: FetchUserDetails,
private val preferencesHelper: PreferencesHelper
private val fetchUserDetailsUseCase: FetchUserDetails,
private val preferencesHelper: PreferencesHelper,
private val passcodePreferencesHelper: PasscodePreferencesHelper,
) : ViewModel() {
private val _uiState = MutableStateFlow<LoginUiState>(LoginUiState.None)
val uiState: StateFlow<LoginUiState> = _uiState
private val _showProgress = MutableStateFlow(false)
val showProgress: StateFlow<Boolean> = _showProgress
private val _isLoginSuccess = MutableStateFlow(false)
val isLoginSuccess: StateFlow<Boolean> = _isLoginSuccess
val isPassCodeExist = passcodePreferencesHelper.passCode.isNotEmpty()
fun updateProgressState(isVisible: Boolean) {
_showProgress.update { isVisible }
}
fun updateIsLoginSuccess(isLoginSuccess: Boolean) {
_isLoginSuccess.update { isLoginSuccess }
}
/**
* Authenticate User with username and password
* @param username
* @param password
* Note: username and password can't be empty or null when we pass to API
*/
fun loginUser(
username: String,
password: String,
onLoginFailed: (String) -> Unit
) {
updateProgressState(true)
authenticateUserUseCase.walletRequestValues =
AuthenticateUser.RequestValues(username, password)
fun loginUser(username: String?, password: String?) {
authenticateUserUseCase.walletRequestValues = AuthenticateUser.RequestValues(username, password)
val requestValue = authenticateUserUseCase.walletRequestValues
mUsecaseHandler.execute(authenticateUserUseCase, requestValue,
object : UseCase.UseCaseCallback<AuthenticateUser.ResponseValue> {
object : UseCaseCallback<AuthenticateUser.ResponseValue> {
override fun onSuccess(response: AuthenticateUser.ResponseValue) {
createAuthenticatedService(response.user)
fetchClientData()
saveAuthTokenInPref(response.user)
fetchClientData(response.user)
fetchUserDetails(response.user)
}
override fun onError(message: String) {
_uiState.value = LoginUiState.Error(message)
updateProgressState(false)
onLoginFailed(message)
}
})
}
/**
* Fetch user details return by authenticated user
* @param user
*/
private fun fetchUserDetails(user: User) {
mUsecaseHandler.execute(fetchUserDetailsUseCase,
FetchUserDetails.RequestValues(user.userId),
object : UseCase.UseCaseCallback<FetchUserDetails.ResponseValue> {
object : UseCaseCallback<FetchUserDetails.ResponseValue> {
override fun onSuccess(response: FetchUserDetails.ResponseValue) {
saveUserDetails(user, response.userWithRole)
}
override fun onError(message: String) {
//DebugUtil.log(message)
updateProgressState(false)
Log.d("Login User Detailed: ", message)
}
})
}
private fun fetchClientData() {
mUsecaseHandler.execute(fetchClientDataUseCase, null,
object : UseCase.UseCaseCallback<FetchClientData.ResponseValue> {
/**
* Fetch client details return by authenticated user
* Client Id: user.clients.firstOrNull() ?: 0
* @param user
*/
private fun fetchClientData(user: User) {
mUsecaseHandler.execute(
fetchClientDataUseCase,
FetchClientData.RequestValues(user.clients.firstOrNull()),
object : UseCaseCallback<FetchClientData.ResponseValue> {
override fun onSuccess(response: FetchClientData.ResponseValue) {
saveClientDetails(response.clientDetails)
updateProgressState(false)
if (response.clientDetails.name != "") {
_uiState.value = LoginUiState.Success
updateIsLoginSuccess(true)
}
}
override fun onError(message: String) {}
override fun onError(message: String) {
updateProgressState(false)
}
})
}
private fun createAuthenticatedService(user: User) {
val authToken = Constants.BASIC +
user.authenticationKey
preferencesHelper.saveToken(authToken)
//FineractApiManager.createSelfService(preferencesHelper.token)
private fun saveAuthTokenInPref(user: User) {
preferencesHelper.saveToken("Basic " + user.base64EncodedAuthenticationKey)
}
/**
* TODO remove userName, userId and Email from pref and use from saved User
*/
private fun saveUserDetails(
user: User,
userWithRole: UserWithRole
) {
val userName = user.userName
val userName = user.username
val userID = user.userId
preferencesHelper.saveUsername(userName)
preferencesHelper.userId = userID
preferencesHelper.saveEmail(userWithRole.email)
preferencesHelper.user = user
}
private fun saveClientDetails(client: com.mifos.mobilewallet.model.domain.client.Client) {
preferencesHelper.saveFullName(client.name)
preferencesHelper.clientId = client.clientId
/**
* TODO remove name, clientId and mobileNo from pref and use from saved Client
*/
private fun saveClientDetails(client: com.mifos.mobilewallet.model.domain.client.Client?) {
preferencesHelper.saveFullName(client?.name)
preferencesHelper.clientId = client?.clientId!!
preferencesHelper.saveMobile(client.mobileNo)
}
// Represents different states for the LatestNews screen
sealed interface LoginUiState {
data object None: LoginUiState
data object Loading: LoginUiState
data object Success : LoginUiState
data class Error(val exception: String) : LoginUiState
preferencesHelper.client = client
}
}

View File

@ -0,0 +1,61 @@
package org.mifos.mobilewallet.mifospay.feature.auth.mobile_verify
import android.content.Intent
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import dagger.hilt.android.AndroidEntryPoint
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.designsystem.theme.MifosTheme
import org.mifos.mobilewallet.mifospay.feature.auth.signup.SignupActivity
@AndroidEntryPoint
class MobileVerificationActivity : AppCompatActivity() {
val viewModel: MobileVerificationViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MifosTheme {
MobileVerificationScreen { fullNumber ->
onOtpVerificationSuccess(fullNumber)
}
}
}
}
private fun onOtpVerificationSuccess(fullNumber: String) {
val intent = Intent(this@MobileVerificationActivity, SignupActivity::class.java)
intent.putExtra(
Constants.MIFOS_SAVINGS_PRODUCT_ID,
getIntent().getIntExtra(Constants.MIFOS_SAVINGS_PRODUCT_ID, 0)
)
/* intent.putExtra(
Constants.GOOGLE_PHOTO_URI, getIntent().getParcelableExtra<Parcelable>(
Constants.GOOGLE_PHOTO_URI
).toString()
)*/
intent.putExtra(
Constants.GOOGLE_DISPLAY_NAME,
getIntent().getStringExtra(Constants.GOOGLE_DISPLAY_NAME)
)
intent.putExtra(
Constants.GOOGLE_EMAIL,
getIntent().getStringExtra(Constants.GOOGLE_EMAIL)
)
intent.putExtra(
Constants.GOOGLE_FAMILY_NAME,
getIntent().getStringExtra(Constants.GOOGLE_FAMILY_NAME)
)
intent.putExtra(
Constants.GOOGLE_GIVEN_NAME,
getIntent().getStringExtra(Constants.GOOGLE_GIVEN_NAME)
)
intent.putExtra(Constants.COUNTRY, "Canada")
intent.putExtra(Constants.MOBILE_NUMBER, fullNumber)
startActivity(intent)
finish()
}
}

View File

@ -0,0 +1,271 @@
package org.mifos.mobilewallet.mifospay.feature.auth.mobile_verify
import android.widget.Toast
import androidx.compose.foundation.background
import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.material.TextFieldDefaults
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.togitech.ccp.component.TogiCountryCodePicker
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.designsystem.component.MifosLoadingWheel
import org.mifos.mobilewallet.mifospay.designsystem.component.MifosOutlinedTextField
import org.mifos.mobilewallet.mifospay.designsystem.theme.MifosTheme
import org.mifos.mobilewallet.mifospay.designsystem.theme.styleMedium16sp
import org.mifos.mobilewallet.mifospay.feature.auth.R
@Composable
fun MobileVerificationScreen(
viewModel: MobileVerificationViewModel = hiltViewModel(),
onOtpVerificationSuccess: (String) -> Unit
) {
val context = LocalContext.current
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
MobileVerificationScreen(uiState = uiState,
showProgressState = viewModel.showProgress,
verifyMobileAndRequestOtp = { phone, fullPhone ->
viewModel.verifyMobileAndRequestOtp(fullPhone, phone) {
it?.let {
Toast.makeText(context, it, Toast.LENGTH_SHORT).show()
}
}
},
verifyOtp = { validatedOtp, fullNumber ->
viewModel.verifyOTP(validatedOtp) {
onOtpVerificationSuccess(fullNumber)
}
}
)
}
@Composable
fun MobileVerificationScreen(
uiState: MobileVerificationUiState,
showProgressState: Boolean = false,
verifyMobileAndRequestOtp: (String, String) -> Unit,
verifyOtp: (String, String) -> Unit
) {
var phoneNumber by rememberSaveable { mutableStateOf("") }
var fullPhoneNumber by rememberSaveable { mutableStateOf("") }
var isNumberValid: Boolean by rememberSaveable { mutableStateOf(false) }
var isOtpValidated by rememberSaveable { mutableStateOf(false) }
var validatedOtp by rememberSaveable { mutableStateOf("") }
fun verifyMobileOrOtp() {
if (uiState == MobileVerificationUiState.VerifyPhone && isNumberValid) {
verifyMobileAndRequestOtp(phoneNumber, fullPhoneNumber)
} else if (isOtpValidated) {
verifyOtp(validatedOtp, fullPhoneNumber)
}
}
Box {
Column(
modifier = Modifier
.fillMaxSize()
.background(color = Color.White)
.focusable(!showProgressState),
) {
Column(
modifier = Modifier
.fillMaxWidth()
.background(color = MaterialTheme.colorScheme.onBackground),
verticalArrangement = Arrangement.Top
) {
Text(
modifier = Modifier.padding(top = 48.dp, start = 24.dp, end = 24.dp),
text = if (uiState == MobileVerificationUiState.VerifyPhone) {
stringResource(id = R.string.feature_auth_enter_mobile_number)
} else {
stringResource(id = R.string.feature_auth_enter_otp)
},
style = MaterialTheme.typography.titleLarge.copy(color = Color.White)
)
Text(
modifier = Modifier.padding(
top = 4.dp, bottom = 32.dp, start = 24.dp, end = 24.dp
),
text = if (uiState == MobileVerificationUiState.VerifyPhone) {
stringResource(id = R.string.feature_auth_enter_mobile_number_description)
} else {
stringResource(id = R.string.feature_auth_enter_otp_received_on_your_registered_device)
},
style = MaterialTheme.typography.bodySmall.copy(color = Color.White)
)
}
when (uiState) {
MobileVerificationUiState.VerifyPhone -> {
EnterPhoneScreen(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 16.dp),
onNumberUpdated = { phone, fullPhone, valid ->
phoneNumber = phone
fullPhoneNumber = fullPhone
isNumberValid = valid
}
)
}
MobileVerificationUiState.VerifyOtp -> {
EnterOtpScreen(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 48.dp, vertical = 24.dp)
) { isValidated, otp ->
isOtpValidated = isValidated
validatedOtp = otp
}
}
}
Button(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 32.dp, vertical = 16.dp),
colors = ButtonDefaults.buttonColors(containerColor = Color.Black),
enabled = if (uiState == MobileVerificationUiState.VerifyPhone) {
isNumberValid
} else {
isOtpValidated
},
onClick = { verifyMobileOrOtp() },
contentPadding = PaddingValues(12.dp),
) {
Text(
text = if (uiState == MobileVerificationUiState.VerifyPhone) {
stringResource(id = R.string.feature_auth_verify_phone).uppercase()
} else {
stringResource(id = R.string.feature_auth_verify_otp).uppercase()
}, style = styleMedium16sp.copy(color = Color.White)
)
}
}
if (showProgressState) {
ShowProgressScreen(uiState = uiState)
}
}
}
@Composable
fun EnterPhoneScreen(
modifier: Modifier,
onNumberUpdated: (String, String, Boolean) -> Unit
) {
val keyboardController = LocalSoftwareKeyboardController.current
TogiCountryCodePicker(
modifier = modifier,
shape = RoundedCornerShape(8.dp),
colors = TextFieldDefaults.outlinedTextFieldColors(
focusedBorderColor = MaterialTheme.colorScheme.primary
),
onValueChange = { (code, phone), isValid ->
onNumberUpdated(phone, code + phone, isValid)
},
label = { Text(stringResource(id = R.string.feature_auth_phone_number)) },
keyboardActions = KeyboardActions { keyboardController?.hide() }
)
}
@Composable
fun EnterOtpScreen(
modifier: Modifier,
onOtpValidated: (Boolean, String) -> Unit
) {
val keyboardController = LocalSoftwareKeyboardController.current
var otp by rememberSaveable(stateSaver = TextFieldValue.Saver) {
mutableStateOf(TextFieldValue(""))
}
MifosOutlinedTextField(
modifier = modifier,
value = otp,
onValueChange = {
otp = it
onOtpValidated(otp.text.length == 6, otp.text)
},
label = R.string.feature_auth_enter_otp,
keyboardActions = KeyboardActions { keyboardController?.hide() }
)
}
@Composable
fun ShowProgressScreen(
uiState: MobileVerificationUiState,
) {
Box(
modifier = Modifier
.fillMaxSize()
.background(color = Color.Black.copy(alpha = 0.6f))
.focusable(),
contentAlignment = Alignment.Center
) {
MifosLoadingWheel(
modifier = Modifier.wrapContentSize(),
contentDesc = if (uiState == MobileVerificationUiState.VerifyPhone) {
Constants.SENDING_OTP_TO_YOUR_MOBILE_NUMBER
} else {
Constants.VERIFYING_OTP
}
)
}
}
@Preview
@Composable
fun MobileVerificationScreenVerifyPhonePreview() {
MifosTheme {
MobileVerificationScreen(uiState = MobileVerificationUiState.VerifyPhone,
showProgressState = false,
verifyMobileAndRequestOtp = { _, _ -> },
verifyOtp = { _, _ -> }
)
}
}
@Preview
@Composable
fun MobileVerificationScreenVerifyOtpPreview() {
MifosTheme {
MobileVerificationScreen(uiState = MobileVerificationUiState.VerifyOtp,
showProgressState = false,
verifyMobileAndRequestOtp = { _, _ -> },
verifyOtp = { _, _ -> }
)
}
}

View File

@ -0,0 +1,82 @@
package org.mifos.mobilewallet.mifospay.feature.auth.mobile_verify
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import org.mifos.mobilewallet.core.base.UseCase
import org.mifos.mobilewallet.core.base.UseCaseHandler
import org.mifos.mobilewallet.core.domain.usecase.client.SearchClient
import javax.inject.Inject
@HiltViewModel
class MobileVerificationViewModel @Inject constructor(
private val mUseCaseHandler: UseCaseHandler,
private val searchClientUseCase: SearchClient
) : ViewModel() {
private val _uiState =
MutableStateFlow<MobileVerificationUiState>(MobileVerificationUiState.VerifyPhone)
val uiState: StateFlow<MobileVerificationUiState> = _uiState
var showProgress by mutableStateOf(false)
/**
* Verify Mobile number that it already exist or not then request otp
*/
fun verifyMobileAndRequestOtp(
fullNumber: String, mobileNo: String,
onError: (String?) -> Unit
) {
showProgress = true
mUseCaseHandler.execute(searchClientUseCase,
fullNumber.let { SearchClient.RequestValues(it) },
object : UseCase.UseCaseCallback<SearchClient.ResponseValue> {
override fun onSuccess(response: SearchClient.ResponseValue) {
onError("Mobile number already exists.")
showProgress = false
}
override fun onError(message: String) {
requestOtp(fullNumber)
}
})
}
/**
* Request Otp from server
*/
fun requestOtp(fullNumber: String) {
viewModelScope.launch {
delay(2000)
showProgress = false
_uiState.update {
MobileVerificationUiState.VerifyOtp
}
}
}
/**
* Verify Otp
*/
fun verifyOTP(otp: String?, onOtpVerifySuccess: () -> Unit) {
showProgress = true
viewModelScope.launch {
delay(2000)
showProgress = false
onOtpVerifySuccess()
}
}
}
sealed interface MobileVerificationUiState {
data object VerifyOtp : MobileVerificationUiState
data object VerifyPhone : MobileVerificationUiState
}

View File

@ -0,0 +1,62 @@
package org.mifos.mobilewallet.mifospay.feature.auth.signup
import android.content.Intent
import android.os.Bundle
import android.widget.Toast
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import com.mifos.mobile.passcode.utils.PassCodeConstants
import dagger.hilt.android.AndroidEntryPoint
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.designsystem.theme.MifosTheme
import org.mifos.mobilewallet.mifospay.feature.auth.login.LoginActivity
//import org.mifos.mobilewallet.mifospay.passcode.PassCodeActivity
@AndroidEntryPoint
class SignupActivity : AppCompatActivity() {
private val viewModel: SignupViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel.initSignupData(
savingProductId = intent.getIntExtra(Constants.MIFOS_SAVINGS_PRODUCT_ID, 0),
mobileNumber = intent.getStringExtra(Constants.MOBILE_NUMBER) ?: "",
countryName = intent.getStringExtra(Constants.COUNTRY) ?: "",
email = intent.getStringExtra(Constants.GOOGLE_EMAIL) ?: "",
firstName = intent.getStringExtra(Constants.GOOGLE_GIVEN_NAME) ?: "",
lastName = intent.getStringExtra(Constants.GOOGLE_FAMILY_NAME) ?: "",
businessName = intent.getStringExtra(Constants.GOOGLE_DISPLAY_NAME) ?: ""
)
setContent {
MifosTheme {
SignupScreen {
loginSuccess()
}
}
}
}
fun onRegisterSuccess(s: String?) {
// registered but unable to login or user not updated with client
// TODO :: Consider this case
// 1. User not updated: when logging in update user
// 2. User unable to login (must be caused due to server)
Toast.makeText(this, "Registered successfully.", Toast.LENGTH_SHORT).show()
startActivity(Intent(this@SignupActivity, LoginActivity::class.java))
finish()
}
private fun loginSuccess() {
Toast.makeText(this, "Registered successfully.", Toast.LENGTH_SHORT).show()
/*val intent = Intent(this@SignupActivity, PassCodeActivity::class.java).apply {
putExtra(PassCodeConstants.PASSCODE_INITIAL_LOGIN, true)
}
startActivity(intent)*/
finish()
}
}

View File

@ -0,0 +1,460 @@
package org.mifos.mobilewallet.mifospay.feature.auth.signup
import android.widget.Toast
import androidx.compose.foundation.background
import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.mifos.mobilewallet.model.State
import com.mifos.mobilewallet.model.signup.PasswordStrength
import com.mifos.mobilewallet.model.signup.SignupData
import org.mifos.mobilewallet.core.utils.Constants.MIFOS_MERCHANT_SAVINGS_PRODUCT_ID
import org.mifos.mobilewallet.mifospay.designsystem.component.MfOutlinedTextField
import org.mifos.mobilewallet.mifospay.designsystem.component.MfOverlayLoadingWheel
import org.mifos.mobilewallet.mifospay.designsystem.component.MfPasswordTextField
import org.mifos.mobilewallet.mifospay.designsystem.theme.styleMedium16sp
import org.mifos.mobilewallet.mifospay.feature.auth.R
import org.mifos.mobilewallet.mifospay.feature.auth.utils.ValidateUtil.isValidEmail
import java.util.Locale
@Composable
fun SignupScreen(
viewModel: SignupViewModel = hiltViewModel(),
onLoginSuccess: () -> Unit
) {
val context = LocalContext.current
val stateList by viewModel.states.collectAsStateWithLifecycle()
LaunchedEffect(viewModel.isLoginSuccess) {
if (viewModel.isLoginSuccess) {
onLoginSuccess.invoke()
}
}
SignupScreen(
showProgressState = viewModel.showProgress,
data = viewModel.signupData,
stateList = stateList,
onCompleteRegistration = {
viewModel.registerUser(it) { message ->
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
}
}
)
}
@Composable
fun SignupScreen(
showProgressState: Boolean = false,
data: SignupData,
stateList: List<State>,
onCompleteRegistration: (SignupData) -> Unit
) {
val context = LocalContext.current
var firstName by rememberSaveable { mutableStateOf(data.firstName ?: "") }
var lastName by rememberSaveable { mutableStateOf(data.lastName ?: "") }
var email by rememberSaveable { mutableStateOf(data.email ?: "") }
var userName by rememberSaveable {
mutableStateOf(data.email?.ifEmpty { "" }
?: data.email?.let { it.substring(0, it.indexOf('@')) } ?: ""
)
}
var addressLine1 by rememberSaveable { mutableStateOf("") }
var addressLine2 by rememberSaveable { mutableStateOf("") }
var pinCode by rememberSaveable { mutableStateOf("") }
var nameOfBusiness by rememberSaveable { mutableStateOf(data.businessName ?: "") }
var password by rememberSaveable { mutableStateOf("") }
var confirmPassword by rememberSaveable { mutableStateOf("") }
var isPasswordVisible by rememberSaveable { mutableStateOf(false) }
var isConfirmPasswordVisible by rememberSaveable { mutableStateOf(false) }
var selectedState by rememberSaveable { mutableStateOf<State?>(null) }
fun validateAllFields() {
val isAnyFieldEmpty = firstName.isEmpty() || lastName.isEmpty() || email.isEmpty()
|| userName.isEmpty() || addressLine1.isEmpty() || addressLine2.isEmpty()
|| pinCode.isEmpty() || password.isEmpty() || confirmPassword.isEmpty()
|| selectedState == null
val isNameOfBusinessEmpty = data.mifosSavingsProductId == MIFOS_MERCHANT_SAVINGS_PRODUCT_ID
&& nameOfBusiness.isEmpty()
if (!email.isValidEmail()) {
Toast.makeText(
context, context.getString(R.string.feature_auth_validate_email), Toast.LENGTH_SHORT
).show()
return
}
if (isAnyFieldEmpty || isNameOfBusinessEmpty) {
Toast.makeText(
context,
context.getString(R.string.feature_auth_all_fields_are_mandatory),
Toast.LENGTH_SHORT
).show()
return
}
}
fun completeRegistration() {
val signUpData = data.copy(
firstName = firstName,
lastName = lastName,
email = email,
userName = userName,
addressLine1 = addressLine1,
addressLine2 = addressLine2,
pinCode = pinCode,
businessName = nameOfBusiness,
password = password,
stateId = selectedState?.id
)
onCompleteRegistration.invoke(signUpData)
}
Box {
Column(
modifier = Modifier
.fillMaxSize()
.background(color = Color.White)
.verticalScroll(rememberScrollState())
.focusable(!showProgressState),
) {
Column(
modifier = Modifier
.fillMaxWidth()
.background(color = MaterialTheme.colorScheme.onBackground),
verticalArrangement = Arrangement.Top
) {
Text(
modifier = Modifier.padding(top = 48.dp, start = 24.dp, end = 24.dp),
text = stringResource(id = R.string.feature_auth_complete_your_registration),
style = MaterialTheme.typography.titleLarge.copy(color = Color.White)
)
Text(
modifier = Modifier.padding(
top = 4.dp, bottom = 32.dp, start = 24.dp, end = 24.dp
),
text = stringResource(id = R.string.feature_auth_all_fields_are_mandatory),
style = MaterialTheme.typography.bodySmall.copy(color = Color.White)
)
}
Column(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 32.dp)
.focusable(!showProgressState)
) {
UserInfoTextField(
modifier = Modifier
.fillMaxWidth()
.padding(top = 16.dp),
label = stringResource(id = R.string.feature_auth_first_name),
value = firstName
) {
firstName = it
}
UserInfoTextField(
modifier = Modifier
.fillMaxWidth()
.padding(top = 8.dp),
label = stringResource(id = R.string.feature_auth_last_name),
value = lastName
) {
lastName = it
}
UserInfoTextField(
modifier = Modifier
.fillMaxWidth()
.padding(top = 8.dp),
label = stringResource(id = R.string.feature_auth_username),
value = userName
) {
userName = it
}
PasswordAndConfirmPassword(
password = password,
onPasswordChange = { password = it },
confirmPassword = confirmPassword,
onConfirmPasswordChange = { confirmPassword = it },
isPasswordVisible = isPasswordVisible,
onTogglePasswordVisibility = { isPasswordVisible = !isPasswordVisible },
isConfirmPasswordVisible = isConfirmPasswordVisible,
onConfirmTogglePasswordVisibility = {
isConfirmPasswordVisible = !isConfirmPasswordVisible
},
)
UserInfoTextField(
modifier = Modifier
.fillMaxWidth()
.padding(top = 8.dp),
label = stringResource(id = R.string.feature_auth_email),
value = email
) {
email = it
}
if (data.mifosSavingsProductId == MIFOS_MERCHANT_SAVINGS_PRODUCT_ID) {
UserInfoTextField(
modifier = Modifier
.fillMaxWidth()
.padding(top = 8.dp),
label = stringResource(id = R.string.feature_auth_name_of_business),
value = nameOfBusiness
) {
nameOfBusiness = it
}
}
UserInfoTextField(
modifier = Modifier
.fillMaxWidth()
.padding(top = 8.dp),
label = stringResource(id = R.string.feature_auth_address_line_1),
value = addressLine1
) {
addressLine1 = it
}
UserInfoTextField(
modifier = Modifier
.fillMaxWidth()
.padding(top = 8.dp),
label = stringResource(id = R.string.feature_auth_address_line_2),
value = addressLine2
) {
addressLine2 = it
}
UserInfoTextField(
modifier = Modifier.padding(top = 8.dp),
label = stringResource(id = R.string.feature_auth_pin_code),
value = pinCode
) {
pinCode = it
}
HorizontalDivider(thickness = 8.dp, color = Color.White)
MifosStateDropDownOutlinedTextField(
value = selectedState?.name ?: "",
label = stringResource(id = R.string.feature_auth_state),
stateList = stateList
) {
selectedState = it
}
HorizontalDivider(thickness = 24.dp, color = Color.White)
Button(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
colors = ButtonDefaults.buttonColors(containerColor = Color.Black),
enabled = true,
onClick = {
validateAllFields()
completeRegistration()
},
contentPadding = PaddingValues(12.dp),
) {
Text(
text = stringResource(id = R.string.feature_auth_complete),
style = styleMedium16sp.copy(color = Color.White)
)
}
}
}
if (showProgressState) {
MfOverlayLoadingWheel(stringResource(id = R.string.feature_auth_please_wait))
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MifosStateDropDownOutlinedTextField(
modifier: Modifier = Modifier,
value: String,
label: String,
stateList: List<State>,
onSelectedState: (State) -> Unit
) {
var expanded by rememberSaveable { mutableStateOf(false) }
ExposedDropdownMenuBox(
expanded = expanded,
onExpandedChange = {
expanded = !expanded
}
) {
OutlinedTextField(
modifier = modifier.menuAnchor(),
value = value,
onValueChange = { },
readOnly = true,
label = { Text(label) },
trailingIcon = {
ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded)
}
)
DropdownMenu(
expanded = expanded,
onDismissRequest = {
expanded = false
})
{
stateList.forEach {
DropdownMenuItem(
text = { Text(text = it.name) },
onClick = {
expanded = false
onSelectedState(it)
}
)
}
}
}
}
@Composable
fun UserInfoTextField(
modifier: Modifier = Modifier,
label: String,
value: String,
onValueChange: (String) -> Unit
) {
MfOutlinedTextField(
modifier = modifier,
value = value,
label = label,
isError = value.isEmpty(),
errorMessage = stringResource(id = R.string.feature_auth_mandatory),
onValueChange = onValueChange
)
}
@Composable
fun PasswordAndConfirmPassword(
password: String,
onPasswordChange: (String) -> Unit,
confirmPassword: String,
onConfirmPasswordChange: (String) -> Unit,
isPasswordVisible: Boolean,
onTogglePasswordVisibility: () -> Unit,
isConfirmPasswordVisible: Boolean,
onConfirmTogglePasswordVisibility: () -> Unit,
) {
Column {
MfPasswordTextField(
modifier = Modifier.fillMaxWidth(),
password = password,
label = stringResource(id = R.string.feature_auth_password),
isError = password.isEmpty() || password.length < 6,
errorMessage = if (password.isEmpty()) {
stringResource(id = R.string.feature_auth_password_cannot_be_empty)
} else if (password.length < 6) {
stringResource(id = R.string.feature_auth_password_must_be_least_6_characters)
} else null,
onPasswordChange = onPasswordChange,
isPasswordVisible = isPasswordVisible,
onTogglePasswordVisibility = onTogglePasswordVisibility
)
MfPasswordTextField(
modifier = Modifier.fillMaxWidth(),
password = confirmPassword,
label = stringResource(id = R.string.feature_auth_confirm_password),
isError = confirmPassword.isEmpty() || password != confirmPassword,
errorMessage = if (confirmPassword.isEmpty()) {
stringResource(id = R.string.feature_auth_confirm_password_cannot_empty)
} else if (password != confirmPassword) {
stringResource(id = R.string.feature_auth_passwords_do_not_match)
} else null,
onPasswordChange = onConfirmPasswordChange,
isPasswordVisible = isConfirmPasswordVisible,
onTogglePasswordVisibility = onConfirmTogglePasswordVisibility
)
if (password.length >= 6) {
Text(
modifier = Modifier.padding(top = 8.dp),
text = "${stringResource(id = R.string.feature_auth_password_strength)}${
getPasswordStrength(password).replaceFirstChar {
if (it.isLowerCase()) it.titlecase(
Locale.ENGLISH
) else it.toString()
}
}",
color = getPasswordStrengthColor(password),
)
}
}
}
private fun getPasswordStrength(password: String): String {
val hasUpperCase = password.any { it.isUpperCase() }
val hasLowerCase = password.any { it.isLowerCase() }
val hasNumbers = password.any { it.isDigit() }
val hasSymbols = password.any { !it.isLetterOrDigit() }
val numTypesPresent = intArrayOf(
hasUpperCase.toInt(),
hasLowerCase.toInt(),
hasNumbers.toInt(),
hasSymbols.toInt()
).sum()
return PasswordStrength.entries[numTypesPresent].name
}
fun Boolean.toInt() = if (this) 1 else 0
private fun getPasswordStrengthColor(password: String): Color {
val strength = getPasswordStrength(password)
return when (PasswordStrength.valueOf(strength)) {
PasswordStrength.WEAK -> Color.Red
PasswordStrength.MODERATE -> Color.DarkGray
PasswordStrength.STRONG -> Color.Green
PasswordStrength.VERY_STRONG -> Color.Blue
PasswordStrength.EXCELLENT -> Color.Magenta
else -> Color.Black
}
}
@Preview
@Composable
fun SignupScreenPreview() {
SignupScreen(
showProgressState = false,
data = SignupData(),
stateList = listOf(),
onCompleteRegistration = { }
)
}

View File

@ -0,0 +1,266 @@
package org.mifos.mobilewallet.mifospay.feature.auth.signup
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.mifos.mobilewallet.model.State
import com.mifos.mobilewallet.model.domain.user.NewUser
import com.mifos.mobilewallet.model.domain.user.UpdateUserEntityClients
import com.mifos.mobilewallet.model.domain.user.User
import com.mifos.mobilewallet.model.entity.UserWithRole
import com.mifos.mobilewallet.model.signup.SignupData
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import org.mifos.mobilewallet.core.base.UseCase
import org.mifos.mobilewallet.core.base.UseCaseHandler
import org.mifos.mobilewallet.core.domain.usecase.client.CreateClient
import org.mifos.mobilewallet.core.domain.usecase.client.FetchClientData
import org.mifos.mobilewallet.core.domain.usecase.client.SearchClient
import org.mifos.mobilewallet.core.domain.usecase.user.AuthenticateUser
import org.mifos.mobilewallet.core.domain.usecase.user.CreateUser
import org.mifos.mobilewallet.core.domain.usecase.user.DeleteUser
import org.mifos.mobilewallet.core.domain.usecase.user.FetchUserDetails
import org.mifos.mobilewallet.core.domain.usecase.user.UpdateUser
import org.mifos.mobilewallet.core.repository.local.LocalAssetRepository
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.common.DebugUtil
import org.mifos.mobilewallet.mifospay.core.datastore.PreferencesHelper
import javax.inject.Inject
@HiltViewModel
class SignupViewModel @Inject constructor(
localAssetRepository: LocalAssetRepository,
private val useCaseHandler: UseCaseHandler,
private val preferencesHelper: PreferencesHelper,
private val searchClientUseCase: SearchClient,
private val createClientUseCase: CreateClient,
private val createUserUseCase: CreateUser,
private val updateUserUseCase: UpdateUser,
private val authenticateUserUseCase: AuthenticateUser,
private val fetchClientDataUseCase: FetchClientData,
private val deleteUserUseCase: DeleteUser,
private val fetchUserDetailsUseCase: FetchUserDetails
) : ViewModel() {
var showProgress by mutableStateOf(false)
var isLoginSuccess by mutableStateOf(false)
var signupData by mutableStateOf(SignupData())
var state by mutableStateOf<State?>(null)
fun initSignupData(
savingProductId: Int,
mobileNumber: String,
countryName: String?,
email: String?,
firstName: String?,
lastName: String?,
businessName: String?
) {
signupData = signupData.copy(
mifosSavingsProductId = savingProductId,
mobileNumber = mobileNumber,
countryName = countryName,
email = email,
firstName = firstName!!,
lastName = lastName!!,
businessName = businessName
)
}
val states: StateFlow<List<State>> = combine(
localAssetRepository.getCountries(),
localAssetRepository.getStateList(),
::Pair
)
.map {
val countries = it.first
signupData = signupData.copy(
countryId = countries.find { it.name == signupData.countryName }?.id ?: ""
)
it.second.filter { it.countryId == signupData.countryId }
}
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = emptyList(),
)
fun registerUser(data: SignupData, showToastMessage: (String) -> Unit) {
signupData = data
// 0. Unique Mobile Number (checked in MOBILE VERIFICATION ACTIVITY)
// 1. Check for unique external id and username
// 2. Create user
// 3. Create Client
// 4. Update User and connect client with user
useCaseHandler.execute(searchClientUseCase,
SearchClient.RequestValues("${signupData.userName}@mifos"),
object : UseCase.UseCaseCallback<SearchClient.ResponseValue> {
override fun onSuccess(response: SearchClient.ResponseValue) {
showToastMessage("Username already exists.")
}
override fun onError(message: String) {
createUser(showToastMessage)
}
})
}
private fun createUser(showToastMessage: (String) -> Unit) {
val newUser = NewUser(
signupData.userName, signupData.firstName, signupData.lastName,
signupData.email, signupData.password
)
useCaseHandler.execute(createUserUseCase, CreateUser.RequestValues(newUser),
object : UseCase.UseCaseCallback<CreateUser.ResponseValue> {
override fun onSuccess(response: CreateUser.ResponseValue) {
createClient(response.userId, showToastMessage)
}
override fun onError(message: String) {
DebugUtil.log(message)
showToastMessage(message)
}
})
}
private fun createClient(userId: Int, showToastMessage: (String) -> Unit) {
val newClient = com.mifos.mobilewallet.model.domain.client.NewClient(
signupData.businessName, signupData.userName, signupData.addressLine1,
signupData.addressLine2, signupData.city, signupData.pinCode, signupData.stateId,
signupData.countryId, signupData.mobileNumber, signupData.mifosSavingsProductId
)
useCaseHandler.execute(createClientUseCase,
CreateClient.RequestValues(newClient),
object : UseCase.UseCaseCallback<CreateClient.ResponseValue> {
override fun onSuccess(response: CreateClient.ResponseValue) {
response.clientId.let { DebugUtil.log(it) }
val clients = ArrayList<Int>()
response.clientId.let { clients.add(it) }
updateClient(clients, userId, showToastMessage)
}
override fun onError(message: String) {
// delete user
DebugUtil.log(message)
showToastMessage(message)
deleteUser(userId)
}
})
}
private fun updateClient(
clients: ArrayList<Int>,
userId: Int,
showToastMessage: (String) -> Unit
) {
useCaseHandler.execute(updateUserUseCase,
UpdateUser.RequestValues(UpdateUserEntityClients(clients), userId),
object : UseCase.UseCaseCallback<UpdateUser.ResponseValue?> {
override fun onSuccess(response: UpdateUser.ResponseValue?) {
loginUser(signupData.userName, signupData.password, showToastMessage)
}
override fun onError(message: String) {
// connect client later
DebugUtil.log(message)
showToastMessage("update client error")
}
})
}
private fun loginUser(
username: String?,
password: String?,
showToastMessage: (String) -> Unit
) {
authenticateUserUseCase.walletRequestValues = AuthenticateUser.RequestValues(username!!, password!!)
val requestValue = authenticateUserUseCase.walletRequestValues
useCaseHandler.execute(authenticateUserUseCase, requestValue,
object : UseCase.UseCaseCallback<AuthenticateUser.ResponseValue> {
override fun onSuccess(response: AuthenticateUser.ResponseValue) {
response?.user?.let { createAuthenticatedService(it) }
fetchClientData(showToastMessage)
response?.user?.let { fetchUserDetails(it) }
}
override fun onError(message: String) {
showToastMessage("Login Failed")
}
})
}
private fun fetchUserDetails(user: User) {
useCaseHandler.execute(fetchUserDetailsUseCase,
FetchUserDetails.RequestValues(user.userId),
object : UseCase.UseCaseCallback<FetchUserDetails.ResponseValue> {
override fun onSuccess(response: FetchUserDetails.ResponseValue) {
saveUserDetails(user, response.userWithRole)
}
override fun onError(message: String) {
DebugUtil.log(message)
}
})
}
private fun fetchClientData(showToastMessage: (String) -> Unit) {
useCaseHandler.execute(fetchClientDataUseCase, null,
object : UseCase.UseCaseCallback<FetchClientData.ResponseValue> {
override fun onSuccess(response: FetchClientData.ResponseValue) {
saveClientDetails(response.clientDetails)
if (response.clientDetails.name != "") {
isLoginSuccess = true
}
}
override fun onError(message: String) {
showToastMessage("Fetch Client Error")
}
})
}
private fun createAuthenticatedService(user: User) {
val authToken = Constants.BASIC + user.base64EncodedAuthenticationKey
preferencesHelper.saveToken(authToken)
}
private fun saveUserDetails(
user: User,
userWithRole: UserWithRole
) {
val userName = user.username
val userID = user.userId
preferencesHelper.saveUsername(userName)
preferencesHelper.userId = userID
preferencesHelper.saveEmail(userWithRole.email)
}
private fun saveClientDetails(client: com.mifos.mobilewallet.model.domain.client.Client) {
preferencesHelper.saveFullName(client.name)
preferencesHelper.clientId = client.clientId
preferencesHelper.saveMobile(client.mobileNo)
}
private fun deleteUser(userId: Int) {
useCaseHandler.execute(deleteUserUseCase, DeleteUser.RequestValues(userId),
object : UseCase.UseCaseCallback<DeleteUser.ResponseValue> {
override fun onSuccess(response: DeleteUser.ResponseValue) {}
override fun onError(message: String) {}
})
}
}
sealed interface SignupUiState {
data object None : SignupUiState
data object Success : SignupUiState
data class Error(val exception: String) : SignupUiState
}

View File

@ -0,0 +1,26 @@
package org.mifos.mobilewallet.mifospay.feature.auth.social_signup
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.util.Log
import androidx.activity.result.contract.ActivityResultContract
import com.google.android.gms.auth.api.signin.GoogleSignIn
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
import com.google.android.gms.auth.api.signin.GoogleSignInClient
import com.google.android.gms.tasks.Task
class GoogleApiContract(private val googleSignInClient: GoogleSignInClient) :
ActivityResultContract<Int, Task<GoogleSignInAccount>?>() {
override fun parseResult(resultCode: Int, intent: Intent?): Task<GoogleSignInAccount>? {
Log.e("GoogleApiContract", "parseResult: $resultCode")
return when (resultCode) {
Activity.RESULT_OK -> GoogleSignIn.getSignedInAccountFromIntent(intent)
else -> null
}
}
override fun createIntent(context: Context, input: Int): Intent {
return googleSignInClient.signInIntent.putExtra("input", input)
}
}

View File

@ -0,0 +1,276 @@
package org.mifos.mobilewallet.mifospay.feature.auth.social_signup
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Checkbox
import androidx.compose.material3.CheckboxDefaults
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Divider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.google.android.gms.auth.api.signin.GoogleSignIn
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
import com.google.android.gms.auth.api.signin.GoogleSignInOptions
import com.google.android.gms.common.api.ApiException
import org.mifos.mobilewallet.core.utils.Constants.MIFOS_CONSUMER_SAVINGS_PRODUCT_ID
import org.mifos.mobilewallet.core.utils.Constants.MIFOS_MERCHANT_SAVINGS_PRODUCT_ID
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.common.DebugUtil
import org.mifos.mobilewallet.mifospay.designsystem.component.MifosBottomSheet
import org.mifos.mobilewallet.mifospay.feature.auth.R
import org.mifos.mobilewallet.mifospay.feature.auth.mobile_verify.MobileVerificationActivity
const val REQUEST_CODE_SIGN_IN = 1
@Composable
fun SocialSignupMethodContentScreen(
onDismissSignUp: () -> Unit
) {
SocialSignupMethodScreen(onDismissSignUp = onDismissSignUp)
}
@Composable
fun SocialSignupMethodScreen(
onDismissSignUp: () -> Unit
) {
val context = LocalContext.current
var mifosSavingProductId by remember { mutableIntStateOf(0) }
var showProgress by remember { mutableStateOf(false) }
val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(context.getString(R.string.feature_auth_default_web_client_id))
.requestEmail()
.build()
val googleSignInClient by remember { mutableStateOf(GoogleSignIn.getClient(context, gso)) }
var googleSignInAccount by remember { mutableStateOf<GoogleSignInAccount?>(null) }
fun signUpWithMifos() {
googleSignInAccount.signUpWithMifos(context, mifosSavingProductId) {
googleSignInClient.signOut().addOnCompleteListener(context as Activity) {
googleSignInAccount = null
}
onDismissSignUp.invoke()
}
}
val launchGoogleSignup = rememberLauncherForActivityResult(
contract = GoogleApiContract(googleSignInClient)
) { task ->
try {
// Google Sign In was successful, authenticate with Firebase
googleSignInAccount = task?.getResult(ApiException::class.java)
if (googleSignInAccount != null) {
signUpWithMifos()
} else {
Toast.makeText(context, Constants.GOOGLE_SIGN_IN_FAILED, Toast.LENGTH_SHORT).show()
}
} catch (e: Exception) {
// Google Sign In failed, update UI appropriately
e.message?.let { DebugUtil.log(Constants.GOOGLE_SIGN_IN_FAILED, it) }
Toast.makeText(context, Constants.GOOGLE_SIGN_IN_FAILED, Toast.LENGTH_SHORT).show()
}
onDismissSignUp.invoke()
}
fun signUp(checkedGoogleAccount: Boolean) {
if (checkedGoogleAccount) {
launchGoogleSignup.launch(REQUEST_CODE_SIGN_IN)
} else {
signUpWithMifos()
}
showProgress = true
}
MifosBottomSheet(
content = {
SignupMethodContentScreen(
showProgress = showProgress,
onSignUpAsMerchant = { checkedGoogleAccount ->
mifosSavingProductId = MIFOS_MERCHANT_SAVINGS_PRODUCT_ID
signUp(checkedGoogleAccount)
},
onSignupAsCustomer = { checkedGoogleAccount ->
mifosSavingProductId = MIFOS_CONSUMER_SAVINGS_PRODUCT_ID
signUp(checkedGoogleAccount)
}
)
},
onDismiss = {
onDismissSignUp.invoke()
}
)
}
@Composable
fun SignupMethodContentScreen(
showProgress: Boolean,
onSignUpAsMerchant: (Boolean) -> Unit,
onSignupAsCustomer: (Boolean) -> Unit,
) {
var checkedGoogleAccountState by remember { mutableStateOf(true) }
Box(
modifier = Modifier,
) {
Column(
modifier = Modifier
.fillMaxSize()
.background(color = Color.White),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
modifier = Modifier.padding(top = 16.dp),
text = stringResource(id = R.string.feature_auth_create_an_account)
)
OutlinedButton(
modifier = Modifier.padding(top = 48.dp),
onClick = {
onSignUpAsMerchant.invoke(checkedGoogleAccountState)
},
border = BorderStroke(1.dp, Color.LightGray),
shape = RoundedCornerShape(4.dp),
colors = ButtonDefaults.outlinedButtonColors(contentColor = Color.Black)
) {
Text(
text = stringResource(id = R.string.feature_auth_sign_up_as_merchant).uppercase(),
style = MaterialTheme.typography.labelMedium
)
}
Row(
modifier = Modifier
.fillMaxWidth()
.padding(top = 24.dp),
verticalAlignment = Alignment.CenterVertically
) {
Divider(
modifier = Modifier
.padding(start = 24.dp, end = 8.dp)
.weight(.4f),
thickness = 1.dp
)
Text(
modifier = Modifier
.wrapContentWidth()
.weight(.1f),
text = stringResource(id = R.string.feature_auth_or)
)
Divider(
modifier = Modifier
.padding(start = 8.dp, end = 24.dp)
.weight(.4f),
thickness = 1.dp
)
}
OutlinedButton(
modifier = Modifier.padding(top = 24.dp),
onClick = {
onSignupAsCustomer.invoke(checkedGoogleAccountState)
},
border = BorderStroke(1.dp, Color.LightGray),
shape = RoundedCornerShape(4.dp),
colors = ButtonDefaults.outlinedButtonColors(contentColor = Color.Black)
) {
Text(
text = stringResource(id = R.string.feature_auth_sign_up_as_customer).uppercase(),
style = MaterialTheme.typography.labelMedium
)
}
Row(
modifier = Modifier
.padding(top = 24.dp, start = 16.dp, end = 16.dp)
.clickable {
checkedGoogleAccountState = !checkedGoogleAccountState
},
verticalAlignment = Alignment.CenterVertically
) {
Checkbox(
checked = checkedGoogleAccountState,
onCheckedChange = {
checkedGoogleAccountState = !checkedGoogleAccountState
},
colors = CheckboxDefaults.colors(Color.Black)
)
Text(
text = stringResource(id = R.string.feature_auth_ease_my_sign_up_using_google_account),
style = MaterialTheme.typography.labelSmall
)
}
Divider(thickness = 48.dp, color = Color.Transparent)
}
if (showProgress) {
Box(
modifier = Modifier
.fillMaxWidth()
.padding(top = 140.dp),
contentAlignment = Alignment.Center
) {
CircularProgressIndicator(
modifier = Modifier.size(64.dp),
color = Color.Black,
trackColor = MaterialTheme.colorScheme.surfaceVariant,
)
}
}
}
}
fun GoogleSignInAccount?.signUpWithMifos(
context: Context,
mifosSavingsProductId: Int,
signOutGoogleClient: () -> Unit
) {
val googleSignInAccount = this
val intent = Intent(context, MobileVerificationActivity::class.java)
intent.putExtra(Constants.MIFOS_SAVINGS_PRODUCT_ID, mifosSavingsProductId)
if (googleSignInAccount != null) {
intent.putExtra(Constants.GOOGLE_PHOTO_URI, googleSignInAccount.photoUrl)
intent.putExtra(Constants.GOOGLE_DISPLAY_NAME, googleSignInAccount.displayName)
intent.putExtra(Constants.GOOGLE_EMAIL, googleSignInAccount.email)
intent.putExtra(Constants.GOOGLE_FAMILY_NAME, googleSignInAccount.familyName)
intent.putExtra(Constants.GOOGLE_GIVEN_NAME, googleSignInAccount.givenName)
}
context.startActivity(intent)
signOutGoogleClient.invoke()
}
@Preview
@Composable
fun SignupMethodContentScreenPreview() {
MaterialTheme {
SignupMethodContentScreen(true, {}, {})
}
}

View File

@ -0,0 +1,7 @@
package org.mifos.mobilewallet.mifospay.feature.auth.utils
import android.util.Patterns
object ValidateUtil {
fun String.isValidEmail() = this.isNotEmpty() && Patterns.EMAIL_ADDRESS.matcher(this).matches()
}

View File

@ -5,4 +5,40 @@
<string name="feature_auth_sign_up">Sign up.</string>
<string name="feature_auth_password">Password</string>
<string name="feature_auth_username">Username</string>
<string name="feature_auth_logging_in">Logging In…</string>
<string name="feature_auth_default_web_client_id"></string>
<string name="feature_auth_create_an_account">Create an account</string>
<string name="feature_auth_sign_up_as_merchant">Sign up as merchant</string>
<string name="feature_auth_sign_up_as_customer">Sign up as customer</string>
<string name="feature_auth_or">or</string>
<string name="feature_auth_ease_my_sign_up_using_google_account">Ease my sign up using Google Account</string>
<string name="feature_auth_validate_email">Please enter a valid email address</string>
<string name="feature_auth_all_fields_are_mandatory">All fields are mandatory.</string>
<string name="feature_auth_complete_your_registration">Complete your registration</string>
<string name="feature_auth_first_name">First Name</string>
<string name="feature_auth_last_name">Last Name</string>
<string name="feature_auth_email">E-mail</string>
<string name="feature_auth_confirm_password">Confirm Password</string>
<string name="feature_auth_name_of_business">Name of Business</string>
<string name="feature_auth_address_line_1">Address Line 1</string>
<string name="feature_auth_address_line_2">Address Line 2</string>
<string name="feature_auth_pin_code">Pin Code</string>
<string name="feature_auth_state">State</string>
<string name="feature_auth_complete">Complete</string>
<string name="feature_auth_please_wait">Please wait…</string>
<string name="feature_auth_mandatory">Mandatory field</string>
<string name="feature_auth_password_cannot_be_empty">Password cannot be empty</string>
<string name="feature_auth_password_must_be_least_6_characters">Password must be at least 6 characters</string>
<string name="feature_auth_confirm_password_cannot_empty">Confirm password cannot be empty</string>
<string name="feature_auth_passwords_do_not_match">Passwords do not match</string>
<string name="feature_auth_password_strength">Password Strength:</string>
<string name="feature_auth_enter_mobile_number">Enter Mobile Number</string>
<string name="feature_auth_enter_otp">Enter OTP</string>
<string name="feature_auth_enter_mobile_number_description">It should be currently activated on your device
and linked with your bank account as well.
</string>
<string name="feature_auth_enter_otp_received_on_your_registered_device">Enter otp received on your registered device</string>
<string name="feature_auth_verify_phone">Verify Phone</string>
<string name="feature_auth_verify_otp">Verify Otp</string>
<string name="feature_auth_phone_number">Phone Number</string>
</resources>

View File

@ -51,6 +51,7 @@ compose_country_code_picker = "2.2.8"
protobuf = "3.25.2"
protobufPlugin = "0.9.4"
androidxDataStore = "1.0.0"
detekt = "1.18.1"
[libraries]
androidx-activity-ktx = { module = "androidx.activity:activity-ktx", version.ref = "activityVersion" }
@ -72,12 +73,14 @@ androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-
androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling"}
androidx-compose-runtime = { group = "androidx.compose.runtime", name = "runtime" }
hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
hilt-android-testing = { group = "com.google.dagger", name = "hilt-android-testing", version.ref = "hilt" }
hilt-compiler = { group = "com.google.dagger", name = "hilt-android-compiler", version.ref = "hilt" }
androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview"}
androidx-compose-ui-util = { group = "androidx.compose.ui", name = "ui-util"}
androidx-hilt-navigation-compose = { module = "androidx.hilt:hilt-navigation-compose", version.ref = "androidxHilt" }
androidx-lifecycle-runtimeCompose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "androidxLifecycle" }
androidx-lifecycle-viewModelCompose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "androidxLifecycle" }
androidx-lifecycle-runtimeTesting = { group = "androidx.lifecycle", name = "lifecycle-runtime-testing", version.ref = "androidxLifecycle" }
androidx-lifecycle-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "lifecycleVersion" }
androidx-lifecycle-extensions = { module = "androidx.lifecycle:lifecycle-extensions", version.ref = "lifecycleExtensionsVersion" }
jakewharton-butterknife = { module = "com.jakewharton:butterknife", version.ref = "butterKnifeVersion" }
@ -141,6 +144,7 @@ roborazzi = { id = "io.github.takahirom.roborazzi", version.ref = "roborazzi" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp"}
room = { id = "androidx.room", version.ref = "room" }
protobuf = { id = "com.google.protobuf", version.ref = "protobufPlugin" }
detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt"}
# Plugins defined by this project
mifospay-android-application = { id = "mifospay.android.application", version = "unspecified" }

View File

@ -79,7 +79,7 @@
android:name=".qr.ui.ReadQrActivity"
android:theme="@style/AppTheme" />
<activity
android:name=".passcode.ui.PassCodeActivity"
android:name=".passcode.PassCodeActivity"
android:theme="@style/AppTheme" />
<activity
android:name=".receipt.ui.ReceiptActivity"

View File

@ -1,28 +1,18 @@
package org.mifos.mobilewallet.mifospay.auth
import android.os.Bundle
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.activity.compose.setContent
import dagger.hilt.android.AndroidEntryPoint
import org.mifos.mobilewallet.mifospay.base.BaseActivity
import org.mifos.mobilewallet.mifospay.databinding.ActivityLoginBinding
import org.mifos.mobilewallet.mifospay.theme.MifosTheme
@AndroidEntryPoint
class LoginActivity : BaseActivity() {
private lateinit var binding: ActivityLoginBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityLoginBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.loginCompose.apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
MifosTheme {
LoginScreen()
}
setContent {
MifosTheme {
LoginScreen()
}
}
}

View File

@ -46,7 +46,7 @@ import com.mifos.mobile.passcode.utils.PassCodeConstants
import org.mifos.mobilewallet.mifospay.R
import org.mifos.mobilewallet.mifospay.designsystem.component.MfOverlayLoadingWheel
import org.mifos.mobilewallet.mifospay.designsystem.component.MifosOutlinedTextField
import org.mifos.mobilewallet.mifospay.passcode.ui.PassCodeActivity
import org.mifos.mobilewallet.mifospay.passcode.PassCodeActivity
import org.mifos.mobilewallet.mifospay.registration.SignupMethodContentScreen
import org.mifos.mobilewallet.mifospay.theme.MifosTheme
import org.mifos.mobilewallet.mifospay.theme.grey

View File

@ -14,7 +14,7 @@ import org.mifos.mobilewallet.core.domain.usecase.client.FetchClientData
import org.mifos.mobilewallet.core.domain.usecase.user.AuthenticateUser
import org.mifos.mobilewallet.core.domain.usecase.user.FetchUserDetails
import org.mifos.mobilewallet.mifospay.core.datastore.PreferencesHelper
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.DebugUtil
import javax.inject.Inject

View File

@ -20,7 +20,7 @@ import org.mifos.mobilewallet.mifospay.bank.BankContract.DebitCardView
import org.mifos.mobilewallet.mifospay.bank.presenter.DebitCardPresenter
import org.mifos.mobilewallet.mifospay.bank.ui.SetupUpiPinActivity
import org.mifos.mobilewallet.mifospay.base.BaseFragment
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.Toaster
import javax.inject.Inject

View File

@ -14,7 +14,7 @@ import dagger.hilt.android.AndroidEntryPoint
import org.mifos.mobilewallet.mifospay.R
import org.mifos.mobilewallet.mifospay.bank.ui.SetupUpiPinActivity
import org.mifos.mobilewallet.mifospay.base.BaseFragment
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.Toaster
/**

View File

@ -13,7 +13,7 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import dagger.hilt.android.AndroidEntryPoint
import org.mifos.mobilewallet.mifospay.R
import org.mifos.mobilewallet.mifospay.bank.adapters.UpiPinPagerAdapter
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
/**
* Created by ankur on 16/July/2018

View File

@ -17,7 +17,7 @@ import org.mifos.mobilewallet.mifospay.bank.BankContract.UpiPinView
import org.mifos.mobilewallet.mifospay.bank.presenter.UpiPinPresenter
import org.mifos.mobilewallet.mifospay.bank.ui.SetupUpiPinActivity
import org.mifos.mobilewallet.mifospay.base.BaseFragment
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.Toaster
import javax.inject.Inject

View File

@ -22,7 +22,7 @@ import org.mifos.mobilewallet.mifospay.bank.BankContract.BankAccountsView
import org.mifos.mobilewallet.mifospay.bank.adapters.BankAccountsAdapter
import org.mifos.mobilewallet.mifospay.bank.presenter.BankAccountsPresenter
import org.mifos.mobilewallet.mifospay.base.BaseFragment
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.DebugUtil
import org.mifos.mobilewallet.mifospay.utils.RecyclerItemClickListener
import javax.inject.Inject

View File

@ -17,7 +17,7 @@ import org.mifos.mobilewallet.mifospay.bank.BankContract
import org.mifos.mobilewallet.mifospay.bank.BankContract.BankAccountDetailView
import org.mifos.mobilewallet.mifospay.bank.presenter.BankAccountDetailPresenter
import org.mifos.mobilewallet.mifospay.base.BaseActivity
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.DebugUtil
import org.mifos.mobilewallet.mifospay.utils.Toaster
import javax.inject.Inject

View File

@ -25,7 +25,7 @@ import org.mifos.mobilewallet.mifospay.bank.adapters.PopularBankAdapter
import org.mifos.mobilewallet.mifospay.bank.presenter.LinkBankAccountPresenter
import org.mifos.mobilewallet.mifospay.base.BaseActivity
import org.mifos.mobilewallet.mifospay.domain.model.Bank
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.DebugUtil
import org.mifos.mobilewallet.mifospay.utils.FileUtils
import org.mifos.mobilewallet.mifospay.utils.RecyclerItemClickListener

View File

@ -20,7 +20,7 @@ import org.mifos.mobilewallet.mifospay.bank.fragment.UpiPinFragment
import org.mifos.mobilewallet.mifospay.bank.presenter.SetupUpiPinPresenter
import org.mifos.mobilewallet.mifospay.base.BaseActivity
import org.mifos.mobilewallet.mifospay.utils.AnimationUtil
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.Toaster
import javax.inject.Inject

View File

@ -9,7 +9,7 @@ import androidx.fragment.app.FragmentManager
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.mifos.mobile.passcode.BasePassCodeActivity
import org.mifos.mobilewallet.mifospay.R
import org.mifos.mobilewallet.mifospay.passcode.ui.PassCodeActivity
import org.mifos.mobilewallet.mifospay.passcode.PassCodeActivity
/**
* Created by naman on 16/6/17.

View File

@ -18,12 +18,11 @@ import butterknife.BindView
import butterknife.ButterKnife
import dagger.hilt.android.AndroidEntryPoint
import org.mifos.mobilewallet.mifospay.R
import org.mifos.mobilewallet.mifospay.base.BaseActivity
import org.mifos.mobilewallet.mifospay.common.TransferContract
import org.mifos.mobilewallet.mifospay.common.presenter.MakeTransferPresenter
import org.mifos.mobilewallet.mifospay.data.local.LocalRepository
import org.mifos.mobilewallet.mifospay.payments.ui.SendFragment
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.Toaster
import javax.inject.Inject

View File

@ -16,7 +16,7 @@ import org.mifos.mobilewallet.mifospay.base.BaseActivity
import org.mifos.mobilewallet.mifospay.common.SearchContract
import org.mifos.mobilewallet.mifospay.common.presenter.SearchPresenter
import org.mifos.mobilewallet.mifospay.common.ui.adapter.SearchAdapter
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.Toaster
import javax.inject.Inject

View File

@ -33,9 +33,9 @@ import org.mifos.mobilewallet.mifospay.base.BaseActivity
import org.mifos.mobilewallet.mifospay.editprofile.EditProfileContract
import org.mifos.mobilewallet.mifospay.editprofile.EditProfileContract.EditProfileView
import org.mifos.mobilewallet.mifospay.editprofile.presenter.EditProfilePresenter
import org.mifos.mobilewallet.mifospay.passcode.ui.PassCodeActivity
import org.mifos.mobilewallet.mifospay.passcode.PassCodeActivity
import org.mifos.mobilewallet.mifospay.password.ui.EditPasswordActivity
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.DialogBox
import org.mifos.mobilewallet.mifospay.utils.TextDrawable
import org.mifos.mobilewallet.mifospay.utils.Toaster

View File

@ -7,7 +7,6 @@ import org.mifos.mobilewallet.core.base.UseCaseFactory
import com.mifos.mobilewallet.model.domain.Transaction
import org.mifos.mobilewallet.core.base.UseCaseHandler
import org.mifos.mobilewallet.core.domain.usecase.account.FetchAccountTransfer
import org.mifos.mobilewallet.core.domain.usecase.client.FetchClientDetails
import org.mifos.mobilewallet.core.utils.Constants
import org.mifos.mobilewallet.mifospay.R
import org.mifos.mobilewallet.mifospay.base.BaseView
@ -48,7 +47,7 @@ class SpecificTransactionsPresenter @Inject constructor(
as UseCase<FetchAccountTransfer.RequestValues, FetchAccountTransfer.ResponseValue>,
values = FetchAccountTransfer.RequestValues(transferId!!),
taskData = TaskData(
org.mifos.mobilewallet.mifospay.utils.Constants.TRANSFER_DETAILS, i
org.mifos.mobilewallet.mifospay.common.Constants.TRANSFER_DETAILS, i
)
)
}
@ -58,7 +57,7 @@ class SpecificTransactionsPresenter @Inject constructor(
taskData: TaskData, response: R
) {
when (taskData.taskName) {
org.mifos.mobilewallet.mifospay.utils.Constants.TRANSFER_DETAILS -> {
org.mifos.mobilewallet.mifospay.common.Constants.TRANSFER_DETAILS -> {
val responseValue = response as FetchAccountTransfer.ResponseValue
val index = taskData.taskId
transactions[index]?.transferDetail = responseValue.transferDetail

View File

@ -6,7 +6,7 @@ import org.mifos.mobilewallet.core.domain.usecase.account.FetchAccountTransfer
import org.mifos.mobilewallet.mifospay.base.BaseView
import org.mifos.mobilewallet.mifospay.history.HistoryContract
import org.mifos.mobilewallet.mifospay.history.HistoryContract.TransactionDetailView
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import javax.inject.Inject
/**

View File

@ -24,7 +24,7 @@ import org.mifos.mobilewallet.mifospay.history.HistoryContract.HistoryView
import org.mifos.mobilewallet.mifospay.history.HistoryContract.TransactionsHistoryPresenter
import org.mifos.mobilewallet.mifospay.history.presenter.HistoryPresenter
import org.mifos.mobilewallet.mifospay.history.ui.adapter.HistoryAdapter
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.RecyclerItemClickListener
import javax.inject.Inject

View File

@ -21,7 +21,7 @@ import org.mifos.mobilewallet.mifospay.history.HistoryContract.SpecificTransacti
import org.mifos.mobilewallet.mifospay.history.presenter.SpecificTransactionsPresenter
import org.mifos.mobilewallet.mifospay.history.ui.adapter.SpecificTransactionsAdapter
import org.mifos.mobilewallet.mifospay.receipt.ui.ReceiptActivity
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.RecyclerItemClickListener
import javax.inject.Inject

View File

@ -27,7 +27,7 @@ import org.mifos.mobilewallet.mifospay.history.HistoryContract
import org.mifos.mobilewallet.mifospay.history.HistoryContract.TransactionDetailView
import org.mifos.mobilewallet.mifospay.history.presenter.TransactionDetailPresenter
import org.mifos.mobilewallet.mifospay.receipt.ui.ReceiptActivity
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.Toaster
import org.mifos.mobilewallet.mifospay.utils.Utils.getFormattedAccountBalance
import javax.inject.Inject

View File

@ -12,7 +12,7 @@ import butterknife.ButterKnife
import com.mifos.mobilewallet.model.domain.Transaction
import com.mifos.mobilewallet.model.domain.TransactionType
import org.mifos.mobilewallet.mifospay.R
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.Utils.getFormattedAccountBalance
import javax.inject.Inject

View File

@ -15,7 +15,7 @@ import butterknife.ButterKnife
import com.mifos.mobilewallet.model.domain.Transaction
import com.mifos.mobilewallet.model.domain.TransactionType
import org.mifos.mobilewallet.mifospay.R
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.Utils.getFormattedAccountBalance
import javax.inject.Inject

View File

@ -21,7 +21,7 @@ import org.mifos.mobilewallet.mifospay.history.HistoryContract.TransactionsHisto
import org.mifos.mobilewallet.mifospay.history.TransactionsHistory
import org.mifos.mobilewallet.mifospay.home.BaseHomeContract
import org.mifos.mobilewallet.mifospay.home.BaseHomeContract.HomeView
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import javax.inject.Inject
/**

View File

@ -30,7 +30,7 @@ import org.mifos.mobilewallet.mifospay.home.BaseHomeContract.HomeView
import org.mifos.mobilewallet.mifospay.home.presenter.HomeViewModel
import org.mifos.mobilewallet.mifospay.payments.ui.SendActivity
import org.mifos.mobilewallet.mifospay.qr.ui.ShowQrActivity
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.Toaster
import org.mifos.mobilewallet.mifospay.utils.Utils.getFormattedAccountBalance
import javax.inject.Inject

View File

@ -21,7 +21,7 @@ import org.mifos.mobilewallet.mifospay.home.ui.HomeFragment.Companion.newInstanc
import org.mifos.mobilewallet.mifospay.home.ui.PaymentsFragment.Companion.newInstance
import org.mifos.mobilewallet.mifospay.merchants.ui.MerchantsFragment
import org.mifos.mobilewallet.mifospay.settings.ui.SettingsActivity
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import javax.inject.Inject
/**

View File

@ -15,7 +15,7 @@ import org.mifos.mobilewallet.mifospay.editprofile.ui.EditProfileActivity
import org.mifos.mobilewallet.mifospay.home.presenter.ProfileViewModel
import org.mifos.mobilewallet.mifospay.settings.ui.SettingsActivity
import org.mifos.mobilewallet.mifospay.theme.MifosTheme
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
/**
* Created by naman on 7/9/17.

View File

@ -9,7 +9,7 @@ import org.mifos.mobilewallet.mifospay.base.BaseView
import org.mifos.mobilewallet.mifospay.core.datastore.PreferencesHelper
import org.mifos.mobilewallet.mifospay.invoice.InvoiceContract
import org.mifos.mobilewallet.mifospay.invoice.InvoiceContract.InvoicesView
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import javax.inject.Inject
/**

View File

@ -19,7 +19,7 @@ import org.mifos.mobilewallet.mifospay.invoice.InvoiceContract
import org.mifos.mobilewallet.mifospay.invoice.InvoiceContract.InvoiceView
import org.mifos.mobilewallet.mifospay.invoice.presenter.InvoicePresenter
import org.mifos.mobilewallet.mifospay.receipt.ui.ReceiptActivity
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.Toaster
import javax.inject.Inject

View File

@ -12,7 +12,7 @@ import butterknife.ButterKnife
import com.mifos.mobilewallet.model.entity.Invoice
import com.mifos.mobilewallet.model.utils.DateHelper
import org.mifos.mobilewallet.mifospay.R
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import javax.inject.Inject
/**

View File

@ -8,7 +8,7 @@ import org.mifos.mobilewallet.mifospay.base.BaseView
import org.mifos.mobilewallet.mifospay.data.local.LocalRepository
import org.mifos.mobilewallet.mifospay.kyc.KYCContract
import org.mifos.mobilewallet.mifospay.kyc.KYCContract.KYCLevel1View
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import javax.inject.Inject
/**

View File

@ -12,7 +12,7 @@ import org.mifos.mobilewallet.mifospay.base.BaseView
import org.mifos.mobilewallet.mifospay.core.datastore.PreferencesHelper
import org.mifos.mobilewallet.mifospay.kyc.KYCContract
import org.mifos.mobilewallet.mifospay.kyc.KYCContract.KYCLevel2View
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.FileUtils
import java.io.File
import javax.inject.Inject

View File

@ -18,7 +18,7 @@ import org.mifos.mobilewallet.mifospay.base.BaseFragment
import org.mifos.mobilewallet.mifospay.kyc.KYCContract
import org.mifos.mobilewallet.mifospay.kyc.KYCContract.KYCLevel1View
import org.mifos.mobilewallet.mifospay.kyc.presenter.KYCLevel1Presenter
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.Toaster
import org.mifos.mobilewallet.mifospay.utils.Utils.hideSoftKeyboard
import java.text.SimpleDateFormat

View File

@ -21,7 +21,7 @@ import org.mifos.mobilewallet.mifospay.base.BaseFragment
import org.mifos.mobilewallet.mifospay.kyc.KYCContract
import org.mifos.mobilewallet.mifospay.kyc.KYCContract.KYCLevel2View
import org.mifos.mobilewallet.mifospay.kyc.presenter.KYCLevel2Presenter
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.Toaster
import javax.inject.Inject

View File

@ -18,7 +18,7 @@ import org.mifos.mobilewallet.mifospay.history.HistoryContract.TransactionsHisto
import org.mifos.mobilewallet.mifospay.history.TransactionsHistory
import org.mifos.mobilewallet.mifospay.home.BaseHomeContract
import org.mifos.mobilewallet.mifospay.home.BaseHomeContract.MerchantTransferView
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import javax.inject.Inject
/**

View File

@ -23,7 +23,7 @@ import org.mifos.mobilewallet.mifospay.history.ui.adapter.SpecificTransactionsAd
import org.mifos.mobilewallet.mifospay.home.BaseHomeContract
import org.mifos.mobilewallet.mifospay.home.BaseHomeContract.MerchantTransferView
import org.mifos.mobilewallet.mifospay.merchants.presenter.MerchantTransferPresenter
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.TextDrawable
import org.mifos.mobilewallet.mifospay.utils.Toaster
import javax.inject.Inject

View File

@ -27,7 +27,7 @@ import org.mifos.mobilewallet.mifospay.base.BaseFragment
import org.mifos.mobilewallet.mifospay.merchants.MerchantsContract
import org.mifos.mobilewallet.mifospay.merchants.adapter.MerchantsAdapter
import org.mifos.mobilewallet.mifospay.merchants.presenter.MerchantsPresenter
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.RecyclerItemClickListener
import java.util.*
import javax.inject.Inject

View File

@ -15,7 +15,7 @@ import org.mifos.mobilewallet.mifospay.base.BaseActivity
import org.mifos.mobilewallet.mifospay.notification.NotificationContract
import org.mifos.mobilewallet.mifospay.notification.NotificationContract.NotificationView
import org.mifos.mobilewallet.mifospay.notification.presenter.NotificationPresenter
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.DebugUtil
import org.mifos.mobilewallet.mifospay.utils.Toaster
import javax.inject.Inject

View File

@ -1,11 +1,12 @@
package org.mifos.mobilewallet.mifospay.passcode.ui
package org.mifos.mobilewallet.mifospay.passcode
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import androidx.appcompat.app.AlertDialog
import android.view.View
import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.app.AlertDialog
import butterknife.ButterKnife
import com.mifos.mobile.passcode.MifosPassCodeActivity
import com.mifos.mobile.passcode.utils.EncryptionUtil
@ -15,27 +16,19 @@ import dagger.hilt.android.AndroidEntryPoint
import org.mifos.mobilewallet.mifospay.R
import org.mifos.mobilewallet.mifospay.auth.LoginActivity
import org.mifos.mobilewallet.mifospay.home.ui.MainActivity
import org.mifos.mobilewallet.mifospay.passcode.PassCodeContract
import org.mifos.mobilewallet.mifospay.passcode.PassCodeContract.PassCodeView
import org.mifos.mobilewallet.mifospay.passcode.presenter.PassCodePresenter
import org.mifos.mobilewallet.mifospay.receipt.ui.ReceiptActivity
import org.mifos.mobilewallet.mifospay.utils.Constants
import javax.inject.Inject
/**
* Created by ankur on 15/May/2018
*/
import org.mifos.mobilewallet.mifospay.common.Constants
@AndroidEntryPoint
class PassCodeActivity : MifosPassCodeActivity(), PassCodeView {
@JvmField
@Inject
var mPresenter: PassCodePresenter? = null
private var mPassCodePresenter: PassCodeContract.PassCodePresenter? = null
class PassCodeActivity : MifosPassCodeActivity() {
private var deepLinkURI: String? = null
private var currPass: String? = ""
private var updatePassword = false
private var isInitialScreen = false
val viewModel: PassCodeViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -95,10 +88,6 @@ class PassCodeActivity : MifosPassCodeActivity(), PassCodeView {
return EncryptionUtil.DEFAULT
}
override fun setPresenter(presenter: PassCodeContract.PassCodePresenter?) {
mPassCodePresenter = mPresenter
}
private fun saveCurrentPasscode() {
if (updatePassword && currPass?.isNotEmpty() == true) {
val helper = PasscodePreferencesHelper(this)

View File

@ -0,0 +1,17 @@
package org.mifos.mobilewallet.mifospay.passcode
import androidx.lifecycle.ViewModel
import com.mifos.mobile.passcode.utils.PasscodePreferencesHelper
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
@HiltViewModel
class PassCodeViewModel @Inject constructor(
val passcodePreferencesHelper: PasscodePreferencesHelper
): ViewModel() {
fun savePassCode() {
}
}

View File

@ -9,7 +9,7 @@ import org.mifos.mobilewallet.mifospay.base.BaseView
import org.mifos.mobilewallet.mifospay.core.datastore.PreferencesHelper
import org.mifos.mobilewallet.mifospay.password.EditPasswordContract
import org.mifos.mobilewallet.mifospay.password.EditPasswordContract.EditPasswordView
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import javax.inject.Inject
class EditPasswordPresenter @Inject constructor(

View File

@ -11,7 +11,7 @@ import org.mifos.mobilewallet.mifospay.databinding.ActivityEditPasswordBinding
import org.mifos.mobilewallet.mifospay.password.EditPasswordContract
import org.mifos.mobilewallet.mifospay.password.EditPasswordContract.EditPasswordView
import org.mifos.mobilewallet.mifospay.password.presenter.EditPasswordPresenter
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.Toaster
import javax.inject.Inject

View File

@ -8,7 +8,7 @@ import org.mifos.mobilewallet.core.domain.usecase.account.FetchAccount
import org.mifos.mobilewallet.mifospay.base.BaseView
import org.mifos.mobilewallet.mifospay.data.local.LocalRepository
import org.mifos.mobilewallet.mifospay.home.BaseHomeContract
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import javax.inject.Inject
/**

View File

@ -18,10 +18,9 @@ import org.mifos.mobilewallet.mifospay.base.BaseFragment
import org.mifos.mobilewallet.mifospay.home.BaseHomeContract
import org.mifos.mobilewallet.mifospay.payments.presenter.TransferPresenter
import org.mifos.mobilewallet.mifospay.qr.ui.ShowQrActivity
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.Toaster
import java.util.Locale
import javax.inject.Inject
@AndroidEntryPoint
class RequestFragment : BaseFragment(), BaseHomeContract.TransferView {

View File

@ -6,7 +6,7 @@ import androidx.fragment.app.commit
import dagger.hilt.android.AndroidEntryPoint
import org.mifos.mobilewallet.mifospay.R
import org.mifos.mobilewallet.mifospay.base.BaseActivity
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
@AndroidEntryPoint
class SendActivity : BaseActivity() {

View File

@ -32,7 +32,7 @@ import org.mifos.mobilewallet.mifospay.common.ui.MakeTransferFragment.Companion.
import org.mifos.mobilewallet.mifospay.home.BaseHomeContract
import org.mifos.mobilewallet.mifospay.payments.presenter.TransferPresenter
import org.mifos.mobilewallet.mifospay.qr.ui.ReadQrActivity
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.Toaster
import org.mifos.mobilewallet.mifospay.utils.Utils.hideSoftKeyboard

View File

@ -6,7 +6,7 @@ import com.google.zxing.MultiFormatWriter
import com.google.zxing.WriterException
import com.google.zxing.common.BitMatrix
import org.mifos.mobilewallet.core.base.UseCase
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import javax.inject.Inject
/**

View File

@ -25,7 +25,7 @@ import org.mifos.mobilewallet.mifospay.base.BaseActivity
import org.mifos.mobilewallet.mifospay.qr.QrContract
import org.mifos.mobilewallet.mifospay.qr.QrContract.ReadQrView
import org.mifos.mobilewallet.mifospay.qr.presenter.ReadQrPresenter
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import java.io.FileNotFoundException
import javax.inject.Inject

View File

@ -27,7 +27,7 @@ import org.mifos.mobilewallet.mifospay.base.BaseActivity
import org.mifos.mobilewallet.mifospay.qr.QrContract
import org.mifos.mobilewallet.mifospay.qr.QrContract.ShowQrView
import org.mifos.mobilewallet.mifospay.qr.presenter.ShowQrPresenter
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import java.io.File
import java.io.FileOutputStream
import java.io.IOException

View File

@ -9,7 +9,7 @@ import org.mifos.mobilewallet.mifospay.base.BaseView
import org.mifos.mobilewallet.mifospay.core.datastore.PreferencesHelper
import org.mifos.mobilewallet.mifospay.receipt.ReceiptContract
import org.mifos.mobilewallet.mifospay.receipt.ReceiptContract.ReceiptView
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import javax.inject.Inject
/**

View File

@ -28,11 +28,11 @@ import com.mifos.mobilewallet.model.domain.Transaction
import com.mifos.mobilewallet.model.domain.TransactionType
import org.mifos.mobilewallet.mifospay.R
import org.mifos.mobilewallet.mifospay.base.BaseActivity
import org.mifos.mobilewallet.mifospay.passcode.ui.PassCodeActivity
import org.mifos.mobilewallet.mifospay.passcode.PassCodeActivity
import org.mifos.mobilewallet.mifospay.receipt.ReceiptContract
import org.mifos.mobilewallet.mifospay.receipt.ReceiptContract.ReceiptView
import org.mifos.mobilewallet.mifospay.receipt.presenter.ReceiptPresenter
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.FileUtils
import org.mifos.mobilewallet.mifospay.utils.Toaster
import org.mifos.mobilewallet.mifospay.utils.Utils.getFormattedAccountBalance

View File

@ -40,7 +40,7 @@ import org.mifos.mobilewallet.mifospay.designsystem.component.MifosLoadingWheel
import org.mifos.mobilewallet.mifospay.designsystem.component.MifosOutlinedTextField
import org.mifos.mobilewallet.mifospay.theme.MifosTheme
import org.mifos.mobilewallet.mifospay.theme.styleMedium16sp
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
@Composable

View File

@ -46,10 +46,10 @@ import org.mifos.mobilewallet.core.utils.Constants.MIFOS_MERCHANT_SAVINGS_PRODUC
import org.mifos.mobilewallet.mifospay.R
import org.mifos.mobilewallet.mifospay.designsystem.component.MifosBottomSheet
import org.mifos.mobilewallet.mifospay.registration.ui.MobileVerificationActivity
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.DebugUtil
import org.mifos.mobilewallet.mifospay.utils.Toaster
import org.mifos.mobilewallet.mifospay.utils.Constants as MifosConstant
import org.mifos.mobilewallet.mifospay.common.Constants as MifosConstant
const val REQUEST_CODE_SIGN_IN = 1

View File

@ -29,7 +29,7 @@ import org.mifos.mobilewallet.core.domain.usecase.user.FetchUserDetails
import org.mifos.mobilewallet.core.domain.usecase.user.UpdateUser
import org.mifos.mobilewallet.core.repository.local.LocalAssetRepository
import org.mifos.mobilewallet.mifospay.core.datastore.PreferencesHelper
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.DebugUtil
import javax.inject.Inject

View File

@ -2,7 +2,6 @@ package org.mifos.mobilewallet.mifospay.registration.ui
import android.content.Intent
import android.os.Bundle
import android.os.Parcelable
import androidx.activity.viewModels
import dagger.hilt.android.AndroidEntryPoint
import org.mifos.mobilewallet.mifospay.base.BaseActivity
@ -10,7 +9,7 @@ import org.mifos.mobilewallet.mifospay.databinding.ActivityMobileVerificationBin
import org.mifos.mobilewallet.mifospay.registration.MobileVerificationScreen
import org.mifos.mobilewallet.mifospay.registration.MobileVerificationViewModel
import org.mifos.mobilewallet.mifospay.theme.MifosTheme
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
@AndroidEntryPoint
class MobileVerificationActivity : BaseActivity() {

View File

@ -29,17 +29,16 @@ import org.json.JSONObject
import org.mifos.mobilewallet.mifospay.R
import org.mifos.mobilewallet.mifospay.auth.LoginActivity
import org.mifos.mobilewallet.mifospay.base.BaseActivity
import org.mifos.mobilewallet.mifospay.passcode.ui.PassCodeActivity
import org.mifos.mobilewallet.mifospay.passcode.PassCodeActivity
import org.mifos.mobilewallet.mifospay.registration.RegistrationContract
import org.mifos.mobilewallet.mifospay.registration.RegistrationContract.SignupView
import org.mifos.mobilewallet.mifospay.registration.SignupScreen
import org.mifos.mobilewallet.mifospay.registration.SignupViewModel
import org.mifos.mobilewallet.mifospay.theme.MifosTheme
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.FileUtils
import org.mifos.mobilewallet.mifospay.utils.Toaster
import org.mifos.mobilewallet.mifospay.utils.ValidateUtil.isValidEmail
import javax.inject.Inject
@AndroidEntryPoint
class SignupActivity : BaseActivity(), SignupView {
@ -121,7 +120,7 @@ class SignupActivity : BaseActivity(), SignupView {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_signup)
ButterKnife.bind(this)
showColoredBackButton(Constants.BLACK_BACK_BUTTON)
showColoredBackButton(R.drawable.ic_arrow_back_black_24dp)
setToolbarTitle("Registration")
viewModel.initSignupData(

View File

@ -12,7 +12,7 @@ import org.mifos.mobilewallet.mifospay.base.BaseView
import org.mifos.mobilewallet.mifospay.data.local.LocalRepository
import org.mifos.mobilewallet.mifospay.savedcards.CardsContract
import org.mifos.mobilewallet.mifospay.savedcards.CardsContract.CardsView
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import javax.inject.Inject
/**

View File

@ -19,7 +19,7 @@ import org.mifos.mobilewallet.core.domain.usecase.savedcards.EditCard
import org.mifos.mobilewallet.core.domain.usecase.savedcards.FetchSavedCards
import org.mifos.mobilewallet.mifospay.common.CreditCardUtils.validateCreditCardNumber
import org.mifos.mobilewallet.mifospay.data.local.LocalRepository
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import javax.inject.Inject
@HiltViewModel

View File

@ -21,7 +21,7 @@ import com.google.android.material.textfield.TextInputLayout
import com.mifos.mobilewallet.model.entity.savedcards.Card
import org.mifos.mobilewallet.mifospay.R
import org.mifos.mobilewallet.mifospay.savedcards.CardsContract
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.Toaster
import java.util.Calendar

View File

@ -10,7 +10,7 @@ import org.mifos.mobilewallet.mifospay.settings.SettingsContract
import org.mifos.mobilewallet.mifospay.settings.SettingsContract.SettingsView
import org.mifos.mobilewallet.mifospay.settings.presenter.SettingsPresenter
import org.mifos.mobilewallet.mifospay.theme.MifosTheme
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import javax.inject.Inject
@AndroidEntryPoint

View File

@ -8,7 +8,7 @@ import android.view.ViewGroup
import android.widget.TextView
import com.mifos.mobilewallet.model.entity.standinginstruction.StandingInstruction
import org.mifos.mobilewallet.mifospay.R
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
/**
* Created by Devansh on 08/06/2020

View File

@ -8,11 +8,9 @@ import android.os.Build
import android.os.Bundle
import androidx.core.content.ContextCompat
import android.view.View
import android.widget.Button
import android.widget.Toast
import androidx.databinding.DataBindingUtil
import butterknife.ButterKnife
import com.google.android.gms.common.util.DataUtils
import dagger.hilt.android.AndroidEntryPoint
import org.mifos.mobilewallet.mifospay.R
import org.mifos.mobilewallet.mifospay.base.BaseActivity
@ -20,9 +18,9 @@ import org.mifos.mobilewallet.mifospay.databinding.ActivityNewSiBinding
import org.mifos.mobilewallet.mifospay.qr.ui.ReadQrActivity
import org.mifos.mobilewallet.mifospay.standinginstruction.StandingInstructionContract
import org.mifos.mobilewallet.mifospay.standinginstruction.presenter.NewSIPresenter
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.utils.Constants.REQUEST_CAMERA
import org.mifos.mobilewallet.mifospay.utils.Constants.SCAN_QR_REQUEST_CODE
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.common.Constants.REQUEST_CAMERA
import org.mifos.mobilewallet.mifospay.common.Constants.SCAN_QR_REQUEST_CODE
import org.mifos.mobilewallet.mifospay.utils.Toaster
import org.mifos.mobilewallet.mifospay.utils.Utils
import java.util.*

View File

@ -18,7 +18,7 @@ import org.mifos.mobilewallet.mifospay.base.BaseActivity
import org.mifos.mobilewallet.mifospay.databinding.ActivitySiDetailsBinding
import org.mifos.mobilewallet.mifospay.standinginstruction.StandingInstructionContract
import org.mifos.mobilewallet.mifospay.standinginstruction.presenter.StandingInstructionDetailsPresenter
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.DialogBox
import org.mifos.mobilewallet.mifospay.utils.Utils
import java.util.*

View File

@ -14,11 +14,10 @@ import org.mifos.mobilewallet.mifospay.R
import org.mifos.mobilewallet.mifospay.base.BaseActivity
import org.mifos.mobilewallet.mifospay.base.BaseFragment
import org.mifos.mobilewallet.mifospay.databinding.FragmentSiBinding
import org.mifos.mobilewallet.mifospay.databinding.PlaceholderStateBinding
import org.mifos.mobilewallet.mifospay.standinginstruction.StandingInstructionContract
import org.mifos.mobilewallet.mifospay.standinginstruction.adapter.StandingInstructionAdapter
import org.mifos.mobilewallet.mifospay.standinginstruction.presenter.StandingInstructionsPresenter
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.RecyclerItemClickListener
import javax.inject.Inject

View File

@ -11,6 +11,7 @@ import android.provider.MediaStore
import android.util.Base64
import android.util.Log
import org.json.JSONObject
import org.mifos.mobilewallet.mifospay.common.Constants
import org.mifos.mobilewallet.mifospay.utils.DebugUtil.log
import java.io.BufferedOutputStream
import java.io.File

View File

@ -18,6 +18,7 @@ import android.util.Log
import android.util.Patterns
import androidx.core.app.NotificationCompat
import org.mifos.mobilewallet.mifospay.R
import org.mifos.mobilewallet.mifospay.common.Constants
import java.io.IOException
import java.net.HttpURLConnection
import java.net.URL

View File

@ -8,6 +8,7 @@ import android.widget.Toast
import com.google.android.material.snackbar.Snackbar
import org.mifos.mobilewallet.mifospay.MifosPayApp.Companion.context
import org.mifos.mobilewallet.mifospay.R
import org.mifos.mobilewallet.mifospay.common.Constants
/**
* Created by ankur on 23/May/2018