diff --git a/app/build.gradle b/app/build.gradle
index e276955ac..6c97f265a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -116,6 +116,7 @@ dependencies {
//Country Code picker
implementation "com.hbb20:ccp:$rootProject.countryCodePicker"
+ implementation 'com.github.ParveshSandila:CountryCodeChooser:1.0'
//Square dependencies
implementation("com.squareup.retrofit2:retrofit:$rootProject.retrofitVersion") {
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 1ca6da262..533e1b8ba 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -72,7 +72,7 @@
android:windowSoftInputMode="adjustResize" />
diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/RegistrationFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/RegistrationFragment.kt
deleted file mode 100644
index 5e700f1d5..000000000
--- a/app/src/main/java/org/mifos/mobile/ui/fragments/RegistrationFragment.kt
+++ /dev/null
@@ -1,304 +0,0 @@
-package org.mifos.mobile.ui.fragments
-
-import android.graphics.PorterDuff
-import android.os.Bundle
-import android.text.Editable
-import android.text.TextWatcher
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.RadioButton
-import android.widget.TextView
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.ViewModelProvider
-import androidx.lifecycle.lifecycleScope
-import androidx.lifecycle.repeatOnLifecycle
-import com.hbb20.CountryCodePicker
-import dagger.hilt.android.AndroidEntryPoint
-import kotlinx.coroutines.launch
-import org.mifos.mobile.R
-import org.mifos.mobile.databinding.FragmentRegistrationBinding
-import org.mifos.mobile.ui.activities.base.BaseActivity
-import org.mifos.mobile.ui.fragments.base.BaseFragment
-import org.mifos.mobile.utils.Network
-import org.mifos.mobile.utils.PasswordStrength
-import org.mifos.mobile.utils.RegistrationUiState
-import org.mifos.mobile.utils.Toaster
-import org.mifos.mobile.viewModels.RegistrationViewModel
-
-/**
- * Created by dilpreet on 31/7/17.
- */
-@AndroidEntryPoint
-class RegistrationFragment : BaseFragment() {
- private var _binding: FragmentRegistrationBinding? = null
- private val binding get() = _binding!!
- private lateinit var viewModel: RegistrationViewModel
-
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?,
- ): View {
- _binding = FragmentRegistrationBinding.inflate(inflater, container, false)
- val rootView = binding.root
- viewModel = ViewModelProvider(this)[RegistrationViewModel::class.java]
- with(binding) {
- etPassword.addTextChangedListener(object : TextWatcher {
- override fun beforeTextChanged(
- charSequence: CharSequence, i: Int, i1: Int, i2: Int
- ) {
- }
-
- override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
- if (charSequence.isEmpty()) {
- progressBar.visibility = View.GONE
- passwordStrength.visibility = View.GONE
- } else {
- progressBar.visibility = View.VISIBLE
- passwordStrength.visibility = View.VISIBLE
- updatePasswordStrengthView(charSequence.toString())
- }
- }
-
- override fun afterTextChanged(editable: Editable) {}
- })
- }
- return rootView
- }
-
- private fun updatePasswordStrengthView(password: String) {
- with(binding) {
- if (TextView.VISIBLE != passwordStrength.visibility) return
- if (password.isEmpty()) {
- passwordStrength.text = ""
- progressBar.progress = 0
- return
- }
- val str = PasswordStrength.calculateStrength(password)
- passwordStrength.text = str.getText(context)
- passwordStrength.setTextColor(str.color)
- val mode = PorterDuff.Mode.SRC_IN
- progressBar.progressDrawable?.setColorFilter(str.color, mode)
- when (str.getText(context)) {
- getString(R.string.password_strength_weak) -> progressBar.progress = 25
- getString(R.string.password_strength_medium) -> progressBar.progress = 50
- getString(R.string.password_strength_strong) -> progressBar.progress = 75
- else -> progressBar.progress = 100
- }
- }
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
-
- viewLifecycleOwner.lifecycleScope.launch {
- repeatOnLifecycle(Lifecycle.State.STARTED) {
- viewModel.registrationUiState.collect { state ->
- when (state) {
- RegistrationUiState.Loading -> showProgress()
-
- RegistrationUiState.Success -> {
- hideProgress()
- showRegisteredSuccessfully()
- }
-
- is RegistrationUiState.Error -> {
- hideProgress()
- showError(getString(state.exception))
- }
-
- RegistrationUiState.Initial -> {}
- }
- }
- }
- }
-
- binding.btnRegister.setOnClickListener {
- registerClicked()
- }
- }
-
- private fun registerClicked() {
- if (areFieldsValidated()) {
- with(binding) {
- val radioButton = rgVerificationMode.checkedRadioButtonId.let {
- root.findViewById(it)
- }
- val accountNumber = etAccountNumber.text.toString()
- val authenticationMode = radioButton?.text.toString()
- val email = etEmail.text.toString()
- val firstName = etFirstName.text.toString()
- val lastName = etLastName.text.toString()
- val mobileNumber =
- countryCodePicker.selectedCountryCode.toString() + etPhoneNumber.text.toString()
- if (etPassword.text.toString() != etConfirmPassword.text.toString()) {
- Toaster.show(root, getString(R.string.error_password_not_match))
- return
- }
- val password = etPassword.text.toString()
- val username = etUsername.text.toString().replace(" ", "")
-
- if (Network.isConnected(context)) {
- viewModel.registerUser(
- accountNumber,
- authenticationMode,
- email,
- firstName,
- lastName,
- mobileNumber,
- password,
- username
- )
- } else {
- Toaster.show(root, getString(R.string.no_internet_connection))
- }
- }
- }
- }
-
- private fun areFieldsValidated(): Boolean {
- val rootView = binding.root
- with(binding) {
- return when {
- viewModel.isInputFieldBlank(etAccountNumber.text.toString()) -> {
- Toaster.show(
- rootView,
- getString(
- R.string.error_validation_blank, getString(R.string.account_number)
- ),
- )
- false
- }
-
- viewModel.isInputFieldBlank(etUsername.text.toString()) -> {
- Toaster.show(
- rootView,
- getString(R.string.error_validation_blank, getString(R.string.username)),
- )
- false
- }
-
- viewModel.isInputLengthInadequate(etUsername.text.toString()) -> {
- Toaster.show(rootView, getString(R.string.error_username_greater_than_six))
- false
- }
-
- viewModel.inputHasSpaces(etUsername.text.toString()) -> {
- Toaster.show(
- rootView,
- getString(
- R.string.error_validation_cannot_contain_spaces,
- getString(R.string.username),
- getString(R.string.not_contain_username),
- ),
- )
- false
- }
-
- viewModel.isInputFieldBlank(etFirstName.text.toString()) -> {
- Toaster.show(
- rootView,
- getString(R.string.error_validation_blank, getString(R.string.first_name)),
- )
- false
- }
-
- viewModel.isInputFieldBlank(etLastName.text.toString()) -> {
- Toaster.show(
- rootView,
- getString(R.string.error_validation_blank, getString(R.string.last_name)),
- )
- false
- }
-
- viewModel.isInputFieldBlank(etEmail.text.toString()) -> {
- Toaster.show(
- rootView,
- getString(R.string.error_validation_blank, getString(R.string.email)),
- )
- false
- }
-
- viewModel.isInputFieldBlank(etPassword.text.toString()) -> {
- Toaster.show(
- rootView,
- getString(R.string.error_validation_blank, getString(R.string.password)),
- )
- false
- }
-
- viewModel.hasLeadingTrailingSpaces(etPassword.text.toString()) -> {
- Toaster.show(
- rootView,
- getString(
- R.string.error_validation_cannot_contain_leading_or_trailing_spaces,
- getString(R.string.password),
- ),
- )
- false
- }
-
- viewModel.isEmailInvalid(etEmail.text.toString()) -> {
- Toaster.show(rootView, getString(R.string.error_invalid_email))
- false
- }
-
- viewModel.isInputLengthInadequate(etPassword.text.toString()) -> {
- Toaster.show(
- rootView,
- getString(
- R.string.error_validation_minimum_chars,
- getString(R.string.password),
- resources.getInteger(R.integer.password_minimum_length),
- ),
- )
- return false
- }
-
- (!isPhoneNumberValid(countryCodePicker)) -> {
- Toaster.show(rootView, getString(R.string.invalid_phn_number))
- return false
- }
-
- else -> true
- }
- }
- }
-
- private fun showRegisteredSuccessfully() {
- (activity as BaseActivity?)?.replaceFragment(
- RegistrationVerificationFragment.newInstance(),
- true,
- R.id.container,
- )
- }
-
- fun showError(msg: String?) {
- Toaster.show(binding.root, msg)
- }
-
- fun showProgress() {
- showMifosProgressDialog(getString(R.string.sign_up))
- }
-
- fun hideProgress() {
- hideMifosProgressDialog()
- }
-
- override fun onDestroyView() {
- super.onDestroyView()
- _binding = null
- }
-
- private fun isPhoneNumberValid(ccp: CountryCodePicker): Boolean {
- binding.countryCodePicker.registerCarrierNumberEditText(binding.etPhoneNumber)
- return ccp.isValidFullNumber
- }
-
- companion object {
- fun newInstance(): RegistrationFragment {
- return RegistrationFragment()
- }
- }
-}
diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/RegistrationVerificationFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/RegistrationVerificationFragment.kt
index 0907a3a14..9f0cbc77b 100644
--- a/app/src/main/java/org/mifos/mobile/ui/fragments/RegistrationVerificationFragment.kt
+++ b/app/src/main/java/org/mifos/mobile/ui/fragments/RegistrationVerificationFragment.kt
@@ -18,7 +18,7 @@ import org.mifos.mobile.ui.login.LoginActivity
import org.mifos.mobile.ui.fragments.base.BaseFragment
import org.mifos.mobile.utils.RegistrationUiState
import org.mifos.mobile.utils.Toaster
-import org.mifos.mobile.viewModels.RegistrationViewModel
+import org.mifos.mobile.ui.registration.RegistrationViewModel
/**
* Created by dilpreet on 31/7/17.
diff --git a/app/src/main/java/org/mifos/mobile/ui/login/LoginActivity.kt b/app/src/main/java/org/mifos/mobile/ui/login/LoginActivity.kt
index 7e6ebdbec..b1301642b 100644
--- a/app/src/main/java/org/mifos/mobile/ui/login/LoginActivity.kt
+++ b/app/src/main/java/org/mifos/mobile/ui/login/LoginActivity.kt
@@ -14,7 +14,7 @@ import org.mifos.mobile.MifosSelfServiceApp.Companion.context
import org.mifos.mobile.R
import org.mifos.mobile.core.ui.theme.MifosMobileTheme
import org.mifos.mobile.ui.activities.PassCodeActivity
-import org.mifos.mobile.ui.activities.RegistrationActivity
+import org.mifos.mobile.ui.registration.RegistrationActivity
import org.mifos.mobile.ui.activities.base.BaseActivity
import org.mifos.mobile.utils.Constants
import org.mifos.mobile.utils.LoginUiState
diff --git a/app/src/main/java/org/mifos/mobile/ui/activities/RegistrationActivity.kt b/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationActivity.kt
similarity index 88%
rename from app/src/main/java/org/mifos/mobile/ui/activities/RegistrationActivity.kt
rename to app/src/main/java/org/mifos/mobile/ui/registration/RegistrationActivity.kt
index 31c8d2f1c..46aecc922 100644
--- a/app/src/main/java/org/mifos/mobile/ui/activities/RegistrationActivity.kt
+++ b/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationActivity.kt
@@ -1,11 +1,10 @@
-package org.mifos.mobile.ui.activities
+package org.mifos.mobile.ui.registration
-import android.content.DialogInterface
import android.os.Bundle
import org.mifos.mobile.R
import org.mifos.mobile.databinding.ActivityRegistrationBinding
import org.mifos.mobile.ui.activities.base.BaseActivity
-import org.mifos.mobile.ui.fragments.RegistrationFragment
+import org.mifos.mobile.ui.registration.RegistrationFragment
import org.mifos.mobile.utils.MaterialDialog
class RegistrationActivity : BaseActivity() {
diff --git a/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationFragment.kt b/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationFragment.kt
new file mode 100644
index 000000000..66d58b960
--- /dev/null
+++ b/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationFragment.kt
@@ -0,0 +1,256 @@
+package org.mifos.mobile.ui.registration
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.compose.ui.platform.ComposeView
+import androidx.compose.ui.platform.ViewCompositionStrategy
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.launch
+import org.mifos.mobile.R
+import org.mifos.mobile.core.ui.theme.MifosMobileTheme
+import org.mifos.mobile.ui.activities.base.BaseActivity
+import org.mifos.mobile.ui.fragments.RegistrationVerificationFragment
+import org.mifos.mobile.ui.fragments.base.BaseFragment
+import org.mifos.mobile.utils.Network
+import org.mifos.mobile.utils.PasswordStrength
+import org.mifos.mobile.utils.RegistrationUiState
+import org.mifos.mobile.utils.Toaster
+
+/**
+ * Created by dilpreet on 31/7/17.
+ */
+@AndroidEntryPoint
+class RegistrationFragment : BaseFragment() {
+
+ private lateinit var viewModel: RegistrationViewModel
+
+ private lateinit var accountNumberContent: String
+ private lateinit var usernameContent: String
+ private lateinit var firstNameContent: String
+ private lateinit var lastNameContent: String
+ private lateinit var phoneNumberContent: String
+ private lateinit var emailContent: String
+ private lateinit var passwordContent: String
+ private lateinit var authenticationModeContent: String
+ private lateinit var countryCodeContent: String
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?,
+ ): View {
+ viewModel = ViewModelProvider(this)[RegistrationViewModel::class.java]
+ return ComposeView(requireContext()).apply {
+ setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
+ setContent {
+ MifosMobileTheme {
+ RegistrationScreen(
+ register = { account, username, firstname, lastname, phoneNumber, email, password, authenticationMode, countryCode ->
+ accountNumberContent = account
+ usernameContent = username
+ firstNameContent = firstname
+ lastNameContent = lastname
+ phoneNumberContent = phoneNumber
+ emailContent = email
+ passwordContent = password
+ authenticationModeContent = authenticationMode
+ countryCodeContent = countryCode
+ registerClicked()
+ },
+ progress = { updatePasswordStrengthView(it) }
+ )
+ }
+ }
+ }
+ }
+
+ private fun updatePasswordStrengthView(password: String): Float {
+ val str = PasswordStrength.calculateStrength(password)
+ return when (str.getText(context)) {
+ getString(R.string.password_strength_weak) -> 0.25f
+ getString(R.string.password_strength_medium) -> 0.5f
+ getString(R.string.password_strength_strong) -> 0.75f
+ else -> 1f
+ }
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ viewLifecycleOwner.lifecycleScope.launch {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ viewModel.registrationUiState.collect { state ->
+ when (state) {
+ RegistrationUiState.Loading -> showProgress()
+
+ RegistrationUiState.Success -> {
+ hideProgress()
+ showRegisteredSuccessfully()
+ }
+
+ is RegistrationUiState.Error -> {
+ hideProgress()
+ showError(getString(state.exception))
+ }
+
+ RegistrationUiState.Initial -> {}
+ }
+ }
+ }
+ }
+
+ }
+
+ private fun registerClicked() {
+ if (areFieldsValidated()) {
+ if (Network.isConnected(context)) {
+ viewModel.registerUser(
+ accountNumberContent,
+ authenticationModeContent,
+ emailContent,
+ firstNameContent,
+ lastNameContent,
+ phoneNumberContent,
+ passwordContent,
+ usernameContent
+ )
+ } else {
+ Toaster.show(view, getString(R.string.no_internet_connection))
+ }
+
+ }
+ }
+
+ private fun areFieldsValidated(): Boolean {
+ return when {
+ viewModel.isInputFieldBlank(accountNumberContent) -> {
+ Toaster.show(
+ view,
+ getString(
+ R.string.error_validation_blank, getString(R.string.account_number)
+ ),
+ )
+ false
+ }
+
+ viewModel.isInputFieldBlank(usernameContent) -> {
+ Toaster.show(
+ view,
+ getString(R.string.error_validation_blank, getString(R.string.username)),
+ )
+ false
+ }
+
+ viewModel.isInputLengthInadequate(usernameContent) -> {
+ Toaster.show(view, getString(R.string.error_username_greater_than_six))
+ false
+ }
+
+ viewModel.inputHasSpaces(usernameContent) -> {
+ Toaster.show(
+ view,
+ getString(
+ R.string.error_validation_cannot_contain_spaces,
+ getString(R.string.username),
+ getString(R.string.not_contain_username),
+ ),
+ )
+ false
+ }
+
+ viewModel.isInputFieldBlank(firstNameContent) -> {
+ Toaster.show(
+ view,
+ getString(R.string.error_validation_blank, getString(R.string.first_name)),
+ )
+ false
+ }
+
+ viewModel.isInputFieldBlank(lastNameContent) -> {
+ Toaster.show(
+ view,
+ getString(R.string.error_validation_blank, getString(R.string.last_name)),
+ )
+ false
+ }
+
+ viewModel.isInputFieldBlank(emailContent) -> {
+ Toaster.show(
+ view,
+ getString(R.string.error_validation_blank, getString(R.string.email)),
+ )
+ false
+ }
+
+ viewModel.isInputFieldBlank(passwordContent) -> {
+ Toaster.show(
+ view,
+ getString(R.string.error_validation_blank, getString(R.string.password)),
+ )
+ false
+ }
+
+ viewModel.hasLeadingTrailingSpaces(passwordContent) -> {
+ Toaster.show(
+ view,
+ getString(
+ R.string.error_validation_cannot_contain_leading_or_trailing_spaces,
+ getString(R.string.password),
+ ),
+ )
+ false
+ }
+
+ viewModel.isEmailInvalid(emailContent) -> {
+ Toaster.show(view, getString(R.string.error_invalid_email))
+ false
+ }
+
+ viewModel.isInputLengthInadequate(passwordContent) -> {
+ Toaster.show(
+ view,
+ getString(
+ R.string.error_validation_minimum_chars,
+ getString(R.string.password),
+ resources.getInteger(R.integer.password_minimum_length),
+ ),
+ )
+ return false
+ }
+
+ else -> true
+ }
+ }
+
+ private fun showRegisteredSuccessfully() {
+ (activity as BaseActivity?)?.replaceFragment(
+ RegistrationVerificationFragment.newInstance(),
+ true,
+ R.id.container,
+ )
+ }
+
+ fun showError(msg: String?) {
+ Toaster.show(view, msg)
+ }
+
+ fun showProgress() {
+ showMifosProgressDialog(getString(R.string.sign_up))
+ }
+
+ fun hideProgress() {
+ hideMifosProgressDialog()
+ }
+
+ companion object {
+ fun newInstance(): RegistrationFragment {
+ return RegistrationFragment()
+ }
+ }
+}
diff --git a/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationScreen.kt b/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationScreen.kt
new file mode 100644
index 000000000..55f6b0f1e
--- /dev/null
+++ b/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationScreen.kt
@@ -0,0 +1,271 @@
+package org.mifos.mobile.ui.registration
+
+import android.content.res.Configuration
+import androidx.compose.foundation.border
+import androidx.compose.foundation.gestures.detectTapGestures
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+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.shape.RoundedCornerShape
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Visibility
+import androidx.compose.material.icons.filled.VisibilityOff
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.LinearProgressIndicator
+import androidx.compose.material3.RadioButton
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+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.input.pointer.pointerInput
+import androidx.compose.ui.platform.LocalSoftwareKeyboardController
+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.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.owlbuddy.www.countrycodechooser.CountryCodeChooser
+import com.owlbuddy.www.countrycodechooser.utils.enums.CountryCodeType
+import org.mifos.mobile.R
+import org.mifos.mobile.core.ui.component.MifosOutlinedTextField
+
+/**
+ * @author pratyush
+ * @since 28/12/2023
+ */
+
+@Composable
+fun RegistrationScreen(
+ register: (accountNumber: String, username: String, firstName: String, lastName: String, phoneNumber: String, email: String, password: String, authMode: String, countryCode: String) -> Unit,
+ progress: (String) -> Float,
+) {
+
+ val keyboardController = LocalSoftwareKeyboardController.current
+
+ var accountNumber by rememberSaveable(stateSaver = TextFieldValue.Saver) {
+ mutableStateOf(TextFieldValue(""))
+ }
+ var username by rememberSaveable(stateSaver = TextFieldValue.Saver) {
+ mutableStateOf(TextFieldValue(""))
+ }
+ var firstName by rememberSaveable(stateSaver = TextFieldValue.Saver) {
+ mutableStateOf(TextFieldValue(""))
+ }
+ var lastName by rememberSaveable(stateSaver = TextFieldValue.Saver) {
+ mutableStateOf(TextFieldValue(""))
+ }
+ var phoneNumber by rememberSaveable(stateSaver = TextFieldValue.Saver) {
+ mutableStateOf(TextFieldValue(""))
+ }
+ var email by rememberSaveable(stateSaver = TextFieldValue.Saver) {
+ mutableStateOf(TextFieldValue(""))
+ }
+ var password by rememberSaveable(stateSaver = TextFieldValue.Saver) {
+ mutableStateOf(TextFieldValue(""))
+ }
+ var onValueChangePassword by rememberSaveable {
+ mutableStateOf(false)
+ }
+ var confirmPassword by rememberSaveable(stateSaver = TextFieldValue.Saver) {
+ mutableStateOf(TextFieldValue(""))
+ }
+ var countryCode by rememberSaveable {
+ mutableStateOf("")
+ }
+ val radioOptions =
+ listOf(stringResource(id = R.string.rb_email), stringResource(id = R.string.rb_mobile))
+ var authenticationMode by remember { mutableStateOf(radioOptions[0]) }
+
+ val progressIndicator = progress(password.text)
+ var passwordVisibility: Boolean by remember { mutableStateOf(false) }
+ var confirmPasswordVisibility: Boolean by remember { mutableStateOf(false) }
+
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(bottom = 12.dp)
+ .pointerInput(Unit) {
+ detectTapGestures(onTap = {
+ keyboardController?.hide()
+ })
+ }) {
+ MifosOutlinedTextField(
+ value = accountNumber,
+ onValueChange = { accountNumber = it },
+ label = R.string.account_number,
+ supportingText = ""
+ )
+ MifosOutlinedTextField(
+ value = username,
+ onValueChange = { username = it },
+ label = R.string.username,
+ supportingText = ""
+ )
+ MifosOutlinedTextField(
+ value = firstName,
+ onValueChange = { firstName = it },
+ label = R.string.first_name,
+ supportingText = ""
+ )
+ MifosOutlinedTextField(
+ value = lastName,
+ onValueChange = { lastName = it },
+ label = R.string.last_name,
+ supportingText = ""
+ )
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.Center
+ ) {
+ CountryCodeChooser(
+ modifier = Modifier
+ .padding(start = 16.dp)
+ .border(
+ width = 1.dp,
+ shape = RoundedCornerShape(5.dp),
+ color = Color.Gray
+ )
+ .padding(10.dp),
+ defaultCountryCode = "91",
+ countryCodeType = CountryCodeType.FLAG,
+ onCountyCodeSelected = { code, codeWithPrefix ->
+ countryCode = code
+ }
+ )
+ MifosOutlinedTextField(
+ value = phoneNumber,
+ onValueChange = { phoneNumber = it },
+ label = R.string.phone_number,
+ supportingText = ""
+ )
+ }
+ MifosOutlinedTextField(
+ value = email,
+ onValueChange = { email = it },
+ label = R.string.email,
+ supportingText = ""
+ )
+ MifosOutlinedTextField(
+ value = password,
+ onValueChange = {
+ password = it
+ onValueChangePassword = true
+ },
+ label = R.string.password,
+ supportingText = "",
+ visualTransformation = if (passwordVisibility) VisualTransformation.None else PasswordVisualTransformation(),
+ trailingIcon = {
+ val image = if (passwordVisibility)
+ Icons.Filled.Visibility
+ else Icons.Filled.VisibilityOff
+ IconButton(onClick = { passwordVisibility = !passwordVisibility }) {
+ Icon(imageVector = image, null)
+ }
+ }
+ )
+
+ if (onValueChangePassword) {
+ LinearProgressIndicator(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(start = 16.dp, end = 16.dp),
+ color = when (progressIndicator) {
+ 0.25f -> Color.Red
+ 0.5f -> Color(alpha = 255, red = 220, green = 185, blue = 0)
+ 0.75f -> Color.Green
+ else -> Color.Blue
+ },
+ progress = progressIndicator,
+ trackColor = Color.White
+ )
+ }
+
+ MifosOutlinedTextField(
+ value = confirmPassword,
+ onValueChange = { confirmPassword = it },
+ label = R.string.confirm_password,
+ supportingText = "",
+ visualTransformation = if (confirmPasswordVisibility) VisualTransformation.None else PasswordVisualTransformation(),
+ trailingIcon = {
+ val image = if (confirmPasswordVisibility)
+ Icons.Filled.Visibility
+ else Icons.Filled.VisibilityOff
+ IconButton(onClick = { confirmPasswordVisibility = !confirmPasswordVisibility }) {
+ Icon(imageVector = image, null)
+ }
+ }
+ )
+
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(start = 16.dp),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Text(
+ text = stringResource(id = R.string.verification_mode),
+ modifier = Modifier.padding(end = 8.dp),
+ color = if (isSystemInDarkTheme()) Color.White else Color.Black
+ )
+ radioOptions.forEach { authMode ->
+ RadioButton(
+ selected = (authMode == authenticationMode),
+ onClick = { authenticationMode = authMode }
+ )
+ Text(
+ text = authMode,
+ color = if (isSystemInDarkTheme()) Color.White else Color.Black
+ )
+ }
+ }
+
+ Button(
+ onClick = {
+ register.invoke(
+ accountNumber.text,
+ username.text,
+ firstName.text,
+ lastName.text,
+ phoneNumber.text,
+ email.text,
+ password.text,
+ authenticationMode,
+ countryCode
+ )
+ keyboardController?.hide()
+ },
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(start = 16.dp, end = 16.dp, top = 4.dp),
+ contentPadding = PaddingValues(12.dp),
+ colors = ButtonDefaults.buttonColors(
+ containerColor = if (isSystemInDarkTheme()) Color(
+ 0xFF9bb1e3
+ ) else Color(0xFF325ca8)
+ )
+ ) {
+ Text(text = stringResource(id = R.string.register))
+ }
+ }
+}
+
+@Preview(showSystemUi = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
+@Composable
+fun RegistrationScreenPreview() {
+ RegistrationScreen({ _, _, _, _, _, _, _, _, _ -> }, { 0f })
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/mifos/mobile/viewModels/RegistrationViewModel.kt b/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationViewModel.kt
similarity index 96%
rename from app/src/main/java/org/mifos/mobile/viewModels/RegistrationViewModel.kt
rename to app/src/main/java/org/mifos/mobile/ui/registration/RegistrationViewModel.kt
index 2fbaac8cc..2b4299f99 100644
--- a/app/src/main/java/org/mifos/mobile/viewModels/RegistrationViewModel.kt
+++ b/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationViewModel.kt
@@ -1,8 +1,6 @@
-package org.mifos.mobile.viewModels
+package org.mifos.mobile.ui.registration
import androidx.core.util.PatternsCompat
-import androidx.lifecycle.LiveData
-import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
diff --git a/app/src/main/res/layout/activity_registration.xml b/app/src/main/res/layout/activity_registration.xml
index 6950fd158..3183031d2 100644
--- a/app/src/main/res/layout/activity_registration.xml
+++ b/app/src/main/res/layout/activity_registration.xml
@@ -2,8 +2,7 @@
+ android:layout_height="match_parent">