WIP: cambiar password

This commit is contained in:
erik-everardo 2024-01-22 00:09:06 -06:00
parent 4bb6c57c38
commit 1be245cfa7
5 changed files with 178 additions and 26 deletions

View File

@ -0,0 +1,17 @@
package com.isolaatti.auth.domain
import android.content.Context
import com.isolaatti.auth.data.local.TokenStorage
import com.isolaatti.settings.domain.AccountSettingsRepository
import dagger.hilt.android.qualifiers.ActivityContext
import javax.inject.Inject
class SignOutUC @Inject constructor(
@ActivityContext private val context: Context,
private val tokenStorage: TokenStorage,
private val accountSettingsRepository: AccountSettingsRepository
) {
operator fun invoke() {
}
}

View File

@ -1,6 +1,60 @@
package com.isolaatti.settings.presentation package com.isolaatti.settings.presentation
import android.util.Log
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.isolaatti.settings.data.remote.ChangePasswordResponseDto
import com.isolaatti.settings.domain.AccountSettingsRepository
import com.isolaatti.utils.Resource
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import javax.inject.Inject
class ChangePasswordViewModel : ViewModel() { @HiltViewModel
class ChangePasswordViewModel @Inject constructor(private val accountSettingsRepository: AccountSettingsRepository) : ViewModel() {
var oldPassword = ""
var newPassword = ""
set(value) {
field = value
validatePassword(value)
}
var signOut = false
var signOutCurrent = true
val newPasswordIsValid: MutableLiveData<Boolean> = MutableLiveData()
private val passwordRules = listOf(
"[a-z]",
"[A-Z]",
"[0-9]",
"[!@#\$%^&*\\(\\)_\\+\\-\\={}<>,\\.\\|\"\"'~`:;\\\\?\\/\\[\\]]"
)
private fun validatePassword(newPassword: String) {
var count = 0
for(exp in passwordRules) {
val matches = exp.toRegex().containsMatchIn(newPassword)
Log.d("ChangePasswordViewModel", "$exp matches: $matches")
if(matches) {
count++
}
}
newPasswordIsValid.value = count > 3 && newPassword.length >= 8
}
val passwordChangeResource: MutableLiveData<Resource<ChangePasswordResponseDto>> = MutableLiveData()
fun changePassword() {
viewModelScope.launch {
accountSettingsRepository.changePassword(oldPassword, newPassword, signOut, signOutCurrent).onEach {
passwordChangeResource.postValue(it)
}.flowOn(Dispatchers.IO).launchIn(this)
}
}
} }

View File

@ -4,14 +4,22 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import androidx.core.widget.doOnTextChanged import androidx.core.widget.doOnTextChanged
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.isolaatti.R
import com.isolaatti.auth.domain.SignOutUC
import com.isolaatti.databinding.FragmentSettingsChangePasswordBinding import com.isolaatti.databinding.FragmentSettingsChangePasswordBinding
import com.isolaatti.settings.presentation.ChangePasswordViewModel import com.isolaatti.settings.presentation.ChangePasswordViewModel
import com.isolaatti.utils.Resource
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
class ChangePasswordFragment : Fragment() { @AndroidEntryPoint
class ChangePasswordFragment @Inject constructor(private val signOutUC: SignOutUC) : Fragment() {
lateinit var viewBinding: FragmentSettingsChangePasswordBinding lateinit var viewBinding: FragmentSettingsChangePasswordBinding
private val viewModel: ChangePasswordViewModel by viewModels() private val viewModel: ChangePasswordViewModel by viewModels()
@ -38,6 +46,7 @@ class ChangePasswordFragment : Fragment() {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
setupListeners() setupListeners()
setupObservers()
viewBinding.continueCurrentPassword.isEnabled = !viewBinding.currentPasswordTextInput.editText?.text.isNullOrBlank() viewBinding.continueCurrentPassword.isEnabled = !viewBinding.currentPasswordTextInput.editText?.text.isNullOrBlank()
} }
@ -50,16 +59,76 @@ class ChangePasswordFragment : Fragment() {
viewBinding.prevNewPasswordButton.setOnClickListener(clickListener) viewBinding.prevNewPasswordButton.setOnClickListener(clickListener)
viewBinding.currentPasswordTextInput.editText?.doOnTextChanged { text, start, before, count -> viewBinding.currentPasswordTextInput.editText?.doOnTextChanged { text, start, before, count ->
viewModel.oldPassword = text.toString()
viewBinding.continueCurrentPassword.isEnabled = !text.isNullOrBlank() viewBinding.continueCurrentPassword.isEnabled = !text.isNullOrBlank()
} }
viewBinding.newPasswordInputText.editText?.doOnTextChanged { text, start, before, count -> viewBinding.newPasswordInputText.editText?.doOnTextChanged { text, start, before, count ->
viewModel.newPassword = text.toString()
} }
viewBinding.newPasswordInputTextConfirm.editText?.doOnTextChanged { text, start, before, count -> viewBinding.signOutAll.setOnCheckedChangeListener { buttonView, isChecked ->
viewBinding.signOutCurrent.isEnabled = isChecked
viewModel.signOutCurrent = isChecked
if(!isChecked){
viewBinding.signOutCurrent.isChecked = false
}
}
viewBinding.signOutCurrent.setOnCheckedChangeListener { buttonView, isChecked ->
viewModel.signOutCurrent = isChecked
}
viewBinding.continueNewPasswordButton.setOnClickListener {
viewModel.changePassword()
} }
} }
private fun lockControls(lock: Boolean) {
viewBinding.prevNewPasswordButton.isEnabled = !lock
viewBinding.continueNewPasswordButton.isEnabled = !lock
viewBinding.newPasswordInputText.isEnabled = !lock
}
private var loadingDialog: AlertDialog? = null
private fun showLoadingDialog() {
loadingDialog = MaterialAlertDialogBuilder(requireContext()).setMessage(R.string.changing_password).setCancelable(false).show()
}
private fun signOut() {
signOutUC()
}
private fun setupObservers() {
viewModel.newPasswordIsValid.observe(viewLifecycleOwner) { valid ->
viewBinding.continueNewPasswordButton.isEnabled = valid
viewBinding.newPasswordInputText.error = if(valid) null else getString(R.string.password_req)
}
viewModel.passwordChangeResource.observe(viewLifecycleOwner) {
when(it) {
is Resource.Loading -> {
lockControls(true)
showLoadingDialog()
}
is Resource.Error -> {
lockControls(false)
loadingDialog?.dismiss()
loadingDialog = null
}
is Resource.Success -> {
loadingDialog?.dismiss()
loadingDialog = null
if(viewModel.signOutCurrent) {
signOut()
} else {
findNavController().popBackStack()
}
}
}
}
}
} }

View File

@ -108,45 +108,51 @@
android:inputType="textPassword" /> android:inputType="textPassword" />
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/new_password_input_text_confirm"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:hint="Confirm your new password"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/new_password_input_text"
app:passwordToggleEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/prev_new_password_button" android:id="@+id/prev_new_password_button"
style="?attr/materialIconButtonFilledTonalStyle" style="?attr/materialIconButtonFilledTonalStyle"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp" android:layout_marginBottom="16dp"
android:text="Previous" android:layout_marginTop="16dp"
android:text="@string/previous"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/continue_new_password_button" app:layout_constraintEnd_toStartOf="@+id/continue_new_password_button"
app:layout_constraintHorizontal_bias="0.5" app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/new_password_input_text_confirm" /> app:layout_constraintTop_toBottomOf="@+id/sign_out_current" />
<com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/sign_out_all"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/sign_out_all_sessions"
android:layout_marginTop="24dp"
android:layout_marginHorizontal="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/new_password_input_text" />
<com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/sign_out_current"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/sign_out_this_device"
android:layout_marginHorizontal="16dp"
android:enabled="false"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/sign_out_all" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/continue_new_password_button" android:id="@+id/continue_new_password_button"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="16dp" android:layout_marginBottom="16dp"
android:text="Continue" android:text="@string/continuar"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5" app:layout_constraintHorizontal_bias="0.5"

View File

@ -156,4 +156,10 @@
<string name="delete_sessions">Delete sessions</string> <string name="delete_sessions">Delete sessions</string>
<string name="delete_sessions_conf_dialog_message">The selected sessions will become invalid, sign out those devices.</string> <string name="delete_sessions_conf_dialog_message">The selected sessions will become invalid, sign out those devices.</string>
<string name="current">Current</string> <string name="current">Current</string>
<string name="sign_out_all_sessions">Sign out all sessions</string>
<string name="previous">Previous</string>
<string name="sign_out_this_device">Sign out this device</string>
<string name="continuar">Continue</string>
<string name="password_req">Password must contain at least 8 characters an have the following: 1-9, a-z, A-Z, special character.</string>
<string name="changing_password">Changing password...</string>
</resources> </resources>