-
Notifications
You must be signed in to change notification settings - Fork 721
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Loading status checks…
migrate update password screen to compose
migrate update password screen to compose migrate update password screen to compose migrate update password screen to compose Migration of update password screen to compose Migration of update password screen to compose migrate update update password to compose migration of Update password screen to compose Refractor: Migration of Update Password to compose Refractor: Migration of Update Password to compose migration of update password to compose migrate Update password to compose update Password to compose migration update password screen from XML to Compose
Showing
12 changed files
with
450 additions
and
237 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
229 changes: 0 additions & 229 deletions
229
app/src/main/java/org/mifos/mobile/ui/fragments/UpdatePasswordFragment.kt
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
26 changes: 26 additions & 0 deletions
26
app/src/main/java/org/mifos/mobile/ui/update_password/UpdatePasswordActivity.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package org.mifos.mobile.ui.update_password | ||
|
||
import android.os.Bundle | ||
import org.mifos.mobile.R | ||
import org.mifos.mobile.databinding.ActivityContainerBinding | ||
import org.mifos.mobile.ui.activities.base.BaseActivity | ||
|
||
class UpdatePasswordActivity : BaseActivity() { | ||
private lateinit var binding: ActivityContainerBinding | ||
|
||
override fun onCreate(savedInstanceState: Bundle?) { | ||
super.onCreate(savedInstanceState) | ||
binding = ActivityContainerBinding.inflate(layoutInflater) | ||
setContentView(binding.root) | ||
replaceFragment(UpdatePasswordFragment.newInstance(), false, R.id.container) | ||
} | ||
|
||
override fun onBackPressed() { | ||
super.onBackPressed() | ||
if (fragmentManager?.backStackEntryCount!! > 0) { | ||
fragmentManager?.popBackStack() | ||
} else { | ||
super.onBackPressed() | ||
} | ||
} | ||
} |
209 changes: 209 additions & 0 deletions
209
app/src/main/java/org/mifos/mobile/ui/update_password/UpdatePasswordFragment.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,209 @@ | ||
package org.mifos.mobile.ui.update_password | ||
|
||
import android.os.Bundle | ||
import android.view.LayoutInflater | ||
import android.view.View | ||
import android.view.ViewGroup | ||
import android.widget.Toast | ||
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.SettingsFragment | ||
import org.mifos.mobile.ui.fragments.base.BaseFragment | ||
import org.mifos.mobile.utils.Network | ||
import org.mifos.mobile.utils.RegistrationUiState | ||
import org.mifos.mobile.utils.Toaster | ||
|
||
/* | ||
* Created by saksham on 13/July/2018 | ||
*/ | ||
@AndroidEntryPoint | ||
class UpdatePasswordFragment : BaseFragment() { | ||
|
||
private lateinit var viewModel: UpdatePasswordViewModel | ||
|
||
private lateinit var newPasswordContent: String | ||
private lateinit var confirmPasswordContent: String | ||
|
||
override fun onCreateView( | ||
inflater: LayoutInflater, | ||
container: ViewGroup?, | ||
savedInstanceState: Bundle?, | ||
): View { | ||
viewModel = ViewModelProvider(this)[UpdatePasswordViewModel::class.java] | ||
return ComposeView(requireContext()).apply { | ||
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) | ||
setContent { | ||
MifosMobileTheme { | ||
UpdatePasswordScreen( | ||
changePassword = { newPassword, confirmPassword -> | ||
newPasswordContent = newPassword | ||
confirmPasswordContent = confirmPassword | ||
updatePassword() | ||
}, | ||
getNewPasswordError = { newPassword -> | ||
newPasswordContent = newPassword | ||
showNewPasswordError() | ||
}, | ||
getConfirmPasswordError = { confirmPassword -> | ||
confirmPasswordContent = confirmPassword | ||
showConfirmPasswordError() | ||
}, | ||
getBackToPreviousScreen = { | ||
navigateBack() | ||
} | ||
) | ||
} | ||
} | ||
} | ||
} | ||
|
||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | ||
super.onViewCreated(view, savedInstanceState) | ||
|
||
viewLifecycleOwner.lifecycleScope.launch { | ||
repeatOnLifecycle(Lifecycle.State.STARTED) { | ||
viewModel.updatePasswordUiState.collect { state -> | ||
when (state) { | ||
RegistrationUiState.Loading -> showProgress() | ||
|
||
RegistrationUiState.Success -> { | ||
hideProgress() | ||
showPasswordUpdatedSuccessfully() | ||
} | ||
|
||
is RegistrationUiState.Error -> { | ||
hideProgress() | ||
showError(getString(state.exception)) | ||
} | ||
|
||
RegistrationUiState.Initial -> {} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
private fun updatePassword() { | ||
val newPassword = newPasswordContent | ||
val confirmPassword = confirmPasswordContent | ||
|
||
if (Network.isConnected(activity)) { | ||
if (passwordMatches()) { | ||
viewModel.updateAccountPassword(newPassword, confirmPassword) | ||
} else { | ||
showError(getString(R.string.error_password_not_match)) | ||
} | ||
} else { | ||
Toaster.show(view, getString(R.string.no_internet_connection)) | ||
} | ||
} | ||
|
||
private fun passwordMatches(): Boolean { | ||
return viewModel.validatePasswordMatch(newPasswordContent, confirmPasswordContent) | ||
} | ||
|
||
private fun showNewPasswordError(): String { | ||
var passwordError = "" | ||
when { | ||
viewModel.isInputFieldEmpty(newPasswordContent) -> { | ||
passwordError = getString( | ||
R.string.error_validation_blank, | ||
getString(R.string.new_password), | ||
) | ||
} | ||
|
||
viewModel.isInputLengthInadequate(newPasswordContent) -> { | ||
passwordError = getString( | ||
R.string.error_validation_minimum_chars, | ||
getString(R.string.new_password), | ||
resources.getInteger(R.integer.password_minimum_length), | ||
) | ||
} | ||
} | ||
return passwordError | ||
} | ||
|
||
private fun showConfirmPasswordError(): String { | ||
var passwordError = "" | ||
when { | ||
viewModel.isInputFieldEmpty(confirmPasswordContent) -> { | ||
passwordError = getString( | ||
R.string.error_validation_blank, | ||
getString(R.string.confirm_password), | ||
) | ||
} | ||
|
||
viewModel.isInputLengthInadequate(confirmPasswordContent) -> { | ||
passwordError = getString( | ||
R.string.error_validation_minimum_chars, | ||
getString(R.string.confirm_password), | ||
resources.getInteger(R.integer.password_minimum_length), | ||
) | ||
} | ||
} | ||
return passwordError | ||
} | ||
|
||
fun showError(message: String?) { | ||
var errorMessage = message | ||
Toaster.show(view, errorMessage) | ||
} | ||
|
||
private fun showPasswordUpdatedSuccessfully() { | ||
Toast.makeText( | ||
context, | ||
getString( | ||
R.string.string_changed_successfully, | ||
getString(R.string.password), | ||
), | ||
Toast.LENGTH_SHORT, | ||
).show() | ||
(activity as BaseActivity).clearFragmentBackStack() | ||
(activity as BaseActivity).replaceFragment( | ||
SettingsFragment.newInstance(), | ||
true, | ||
R.id.container, | ||
) | ||
} | ||
|
||
private fun navigateBack() { | ||
/* | ||
If we navigate to update password from user profile there is nothing in backStackEntry | ||
But when we migrate from settings to update password there is one backStackEntry | ||
Since, we need a code to work for both we used this condition here. | ||
*/ | ||
if (fragmentManager?.backStackEntryCount!! > 0) { | ||
fragmentManager?.popBackStack() | ||
} else { | ||
activity?.finish() | ||
} | ||
} | ||
|
||
fun showProgress() { | ||
showMifosProgressDialog(getString(R.string.progress_message_loading)) | ||
} | ||
|
||
fun hideProgress() { | ||
hideMifosProgressDialog() | ||
} | ||
|
||
override fun onResume() { | ||
super.onResume() | ||
(activity as? BaseActivity)?.hideToolbar() | ||
} | ||
|
||
companion object { | ||
fun newInstance(): UpdatePasswordFragment { | ||
return UpdatePasswordFragment() | ||
} | ||
} | ||
} |
198 changes: 198 additions & 0 deletions
198
app/src/main/java/org/mifos/mobile/ui/update_password/UpdatePasswordScreen.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
package org.mifos.mobile.ui.update_password | ||
|
||
import androidx.compose.foundation.isSystemInDarkTheme | ||
import androidx.compose.foundation.layout.Column | ||
import androidx.compose.foundation.layout.PaddingValues | ||
import androidx.compose.foundation.layout.Spacer | ||
import androidx.compose.foundation.layout.fillMaxSize | ||
import androidx.compose.foundation.layout.fillMaxWidth | ||
import androidx.compose.foundation.layout.height | ||
import androidx.compose.foundation.layout.padding | ||
import androidx.compose.material.icons.Icons | ||
import androidx.compose.material.icons.filled.Error | ||
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.Scaffold | ||
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.Modifier | ||
import androidx.compose.ui.graphics.Color | ||
import androidx.compose.ui.res.stringResource | ||
import androidx.compose.ui.text.input.KeyboardType | ||
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 org.mifos.mobile.R | ||
import org.mifos.mobile.core.ui.component.MifosOutlinedTextField | ||
import org.mifos.mobile.core.ui.component.MifosTopBar | ||
|
||
@Composable | ||
fun UpdatePasswordScreen( | ||
changePassword: (newPassword: String, confirmPassword: String) -> Unit, | ||
getNewPasswordError: (newPassword: String) -> String, | ||
getConfirmPasswordError: (confirmPassword: String) -> String, | ||
getBackToPreviousScreen: () -> Unit | ||
) { | ||
var newPassword by rememberSaveable(stateSaver = TextFieldValue.Saver) { | ||
mutableStateOf( | ||
TextFieldValue("") | ||
) | ||
} | ||
var confirmPassword by rememberSaveable(stateSaver = TextFieldValue.Saver) { | ||
mutableStateOf( | ||
TextFieldValue("") | ||
) | ||
} | ||
var viewNewPassword by rememberSaveable { | ||
mutableStateOf(false) | ||
} | ||
var viewConfirmPassword by rememberSaveable { | ||
mutableStateOf(false) | ||
} | ||
|
||
var newPasswordError by rememberSaveable { mutableStateOf(false) } | ||
var confirmPasswordError by rememberSaveable { mutableStateOf(false) } | ||
|
||
var newPasswordErrorContent by rememberSaveable { | ||
mutableStateOf("") | ||
} | ||
var confirmPasswordErrorContent by rememberSaveable { | ||
mutableStateOf("") | ||
} | ||
|
||
Column( | ||
modifier = Modifier | ||
.fillMaxSize() | ||
) { | ||
MifosTopBar( | ||
title = { | ||
Text(text = stringResource(id = R.string.change_password)) | ||
}, | ||
navigateBack = getBackToPreviousScreen | ||
) | ||
|
||
MifosOutlinedTextField( | ||
value = newPassword, | ||
onValueChange = { | ||
newPassword = it | ||
newPasswordError = false | ||
}, | ||
label = R.string.new_password, | ||
supportingText = newPasswordErrorContent, | ||
icon = R.drawable.ic_lock_black_24dp, | ||
trailingIcon = { | ||
var image = if (viewNewPassword) Icons.Filled.Visibility | ||
else Icons.Filled.VisibilityOff | ||
|
||
if (!newPasswordError) { | ||
IconButton(onClick = { viewNewPassword = !viewNewPassword }) { | ||
Icon( | ||
imageVector = image, | ||
contentDescription = "password visibility button" | ||
) | ||
} | ||
} else { | ||
Icon(imageVector = Icons.Filled.Error, contentDescription = null) | ||
} | ||
}, | ||
error = newPasswordError, | ||
visualTransformation = if (viewNewPassword) VisualTransformation.None else PasswordVisualTransformation(), | ||
keyboardType = KeyboardType.Password | ||
) | ||
|
||
Spacer(modifier = Modifier.height(8.dp)) | ||
|
||
MifosOutlinedTextField( | ||
value = confirmPassword, | ||
onValueChange = { | ||
confirmPassword = it | ||
confirmPasswordError = false | ||
}, | ||
label = R.string.confirm_password, | ||
supportingText = confirmPasswordErrorContent, | ||
icon = R.drawable.ic_lock_black_24dp, | ||
trailingIcon = { | ||
var image = if (viewConfirmPassword) Icons.Filled.Visibility | ||
else Icons.Filled.VisibilityOff | ||
|
||
if (!confirmPasswordError) { | ||
IconButton(onClick = { viewConfirmPassword = !viewConfirmPassword }) { | ||
Icon(imageVector = image, contentDescription = "password visibility Button") | ||
} | ||
} else { | ||
Icon(imageVector = Icons.Filled.Error, contentDescription = null) | ||
} | ||
}, | ||
error = confirmPasswordError, | ||
visualTransformation = if (viewConfirmPassword) VisualTransformation.None else PasswordVisualTransformation(), | ||
keyboardType = KeyboardType.Password | ||
|
||
) | ||
|
||
Spacer(modifier = Modifier.height(8.dp)) | ||
|
||
Button( | ||
onClick = { | ||
newPasswordErrorContent = getNewPasswordError.invoke(newPassword.text) | ||
confirmPasswordErrorContent = getConfirmPasswordError.invoke(confirmPassword.text) | ||
|
||
when { | ||
newPasswordErrorContent.isEmpty() && confirmPasswordErrorContent.isEmpty() -> { | ||
changePassword.invoke( | ||
newPassword.text, | ||
confirmPassword.text | ||
) | ||
} | ||
|
||
newPasswordErrorContent.isEmpty() && confirmPasswordErrorContent.isNotEmpty() -> { | ||
confirmPasswordError = true | ||
} | ||
|
||
newPasswordErrorContent.isNotEmpty() && confirmPasswordErrorContent.isEmpty() -> { | ||
newPasswordError = true | ||
} | ||
|
||
else -> { | ||
confirmPasswordError = true | ||
newPasswordError = true | ||
} | ||
} | ||
}, | ||
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.change_password)) | ||
} | ||
|
||
} | ||
} | ||
|
||
|
||
@Composable | ||
@Preview(showBackground = true) | ||
fun PreviewUpdatePasswordScreen() { | ||
UpdatePasswordScreen( | ||
changePassword = { newPassword, confirmPassword -> }, | ||
getNewPasswordError = { "" }, | ||
getConfirmPasswordError = { "" }, | ||
getBackToPreviousScreen = { } | ||
) | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters