feature cambiar password y refactor

This commit is contained in:
erik-everardo 2024-01-26 22:59:19 -06:00
parent e33d1c279a
commit 381274a1b6
12 changed files with 100 additions and 34 deletions

View File

@ -0,0 +1,14 @@
package com.isolaatti.auth
import android.content.Context
import android.net.Uri
import androidx.browser.customtabs.CustomTabsIntent
import com.isolaatti.BuildConfig
const val RecoverPasswordRelativePath = "/recuperacion_cuenta"
fun openForgotPassword(context: Context) {
CustomTabsIntent.Builder()
.setShowTitle(true)
.build()
.launchUrl(context, Uri.parse("${BuildConfig.backend}$RecoverPasswordRelativePath"))
}

View File

@ -1,6 +1,8 @@
package com.isolaatti.auth.domain
import android.content.Context
import android.content.Intent
import com.isolaatti.MainActivity
import com.isolaatti.auth.data.local.TokenStorage
import com.isolaatti.settings.domain.AccountSettingsRepository
import dagger.hilt.android.qualifiers.ActivityContext
@ -8,10 +10,14 @@ import javax.inject.Inject
class SignOutUC @Inject constructor(
@ActivityContext private val context: Context,
private val tokenStorage: TokenStorage,
private val accountSettingsRepository: AccountSettingsRepository
private val tokenStorage: TokenStorage
) {
operator fun invoke() {
tokenStorage.removeToken()
val loginIntent = Intent(context, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
context.startActivity(loginIntent)
}
}

View File

@ -0,0 +1,4 @@
package com.isolaatti.common
@JvmInline
value class ResultDto<T>(val result: T)

View File

@ -1,18 +1,16 @@
package com.isolaatti.login
import android.app.Activity
import android.net.Uri
import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.activity.OnBackPressedCallback
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.browser.customtabs.CustomTabsIntent
import androidx.core.widget.doOnTextChanged
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.isolaatti.BuildConfig
import com.isolaatti.R
import com.isolaatti.auth.openForgotPassword
import com.isolaatti.databinding.ActivityLoginBinding
import com.isolaatti.sign_up.ui.SignUpActivity
import com.isolaatti.utils.Resource
@ -92,7 +90,7 @@ class LogInActivity : AppCompatActivity() {
}
viewBinding.forgotPasswordBtn.setOnClickListener {
openForgotPassword()
openForgotPassword(this)
}
viewBinding.signUpBtn.setOnClickListener {
@ -101,17 +99,12 @@ class LogInActivity : AppCompatActivity() {
}
private fun openForgotPassword() {
CustomTabsIntent.Builder()
.setShowTitle(true)
.build()
.launchUrl(this, Uri.parse("${BuildConfig.backend}/recuperacion_cuenta"))
}
private fun showWrongPasswordErrorMessage() {
MaterialAlertDialogBuilder(this)
.setMessage(R.string.wrong_password)
.setNeutralButton(R.string.forgot_password) {_,_ -> openForgotPassword()}
.setNeutralButton(R.string.forgot_password) {_,_ -> openForgotPassword(this)}
.setPositiveButton(R.string.dismiss, null)
.show()
}

View File

@ -33,7 +33,7 @@ class Module {
}
@Provides
fun provideAccountSettingsRepository(tokenStorage: TokenStorage, accountSettingsApi: AccountSettingsApi): AccountSettingsRepository {
return AccountSettingsRepositoryImpl(tokenStorage, accountSettingsApi)
fun provideAccountSettingsRepository(accountSettingsApi: AccountSettingsApi): AccountSettingsRepository {
return AccountSettingsRepositoryImpl(accountSettingsApi)
}
}

View File

@ -1,5 +1,6 @@
package com.isolaatti.settings.data.remote
import com.isolaatti.common.ResultDto
import retrofit2.Call
import retrofit2.http.Body
import retrofit2.http.GET
@ -15,7 +16,7 @@ interface AccountSettingsApi {
@Body changePasswordDto: ChangePasswordDto,
@Query("signOut") signOut: Boolean,
@Query("signOutCurrent") signOutCurrent: Boolean
): Call<ChangePasswordResponseDto>
): Call<ResultDto<ChangePasswordResponseDto>>
@POST("account/sign_out")
fun signOut(): Call<Any>

View File

@ -5,7 +5,6 @@ data class ChangePasswordResponseDto(
val reason: String?
) {
companion object {
const val ReasonUserDoesNotExist = "user_does_not_exist";
const val ReasonOldPasswordMismatch = "old_password_mismatch";
const val ReasonNewPasswordInvalid = "new_password_invalid";
}

View File

@ -1,6 +1,5 @@
package com.isolaatti.settings.data.repository
import com.isolaatti.auth.data.local.TokenStorage
import com.isolaatti.settings.data.remote.AccountSettingsApi
import com.isolaatti.settings.data.remote.ChangePasswordDto
import com.isolaatti.settings.data.remote.ChangePasswordResponseDto
@ -14,7 +13,6 @@ import retrofit2.awaitResponse
import javax.inject.Inject
class AccountSettingsRepositoryImpl @Inject constructor(
private val tokenStorage: TokenStorage,
private val accountSettingsApi: AccountSettingsApi
) : AccountSettingsRepository {
override fun logout(): Flow<Resource<Boolean>> = flow {
@ -26,8 +24,6 @@ class AccountSettingsRepositoryImpl @Inject constructor(
} else {
emit(Resource.Error(Resource.Error.mapErrorCode(response.code())))
}
tokenStorage.removeToken()
} catch (exception: Exception) {
emit(Resource.Error(Resource.Error.ErrorType.NetworkError))
}
@ -66,7 +62,7 @@ class AccountSettingsRepositoryImpl @Inject constructor(
try {
val response = accountSettingsApi.changePassword(ChangePasswordDto(oldPassword, newPassword), signOut, signOutCurrent).awaitResponse()
if(response.isSuccessful) {
emit(Resource.Success(response.body()))
emit(Resource.Success(response.body()?.result))
} else {
emit(Resource.Error(Resource.Error.mapErrorCode(response.code())))
}

View File

@ -9,17 +9,20 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.isolaatti.MainActivity
import com.isolaatti.R
import com.isolaatti.auth.domain.SignOutUC
import com.isolaatti.databinding.FragmentAccountSettingsBinding
import com.isolaatti.settings.presentation.AccountSettingsViewModel
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
@AndroidEntryPoint
class AccountSettingsFragment : Fragment() {
private lateinit var binding: FragmentAccountSettingsBinding
private val viewModel: AccountSettingsViewModel by viewModels()
@Inject
lateinit var signOutUC: SignOutUC
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@ -51,10 +54,7 @@ class AccountSettingsFragment : Fragment() {
viewModel.loggedOut.observe(viewLifecycleOwner) {
if(it) {
val loginIntent = Intent(requireContext(), MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
startActivity(loginIntent)
signOutUC()
viewModel.loggedOut.value = false
}
}

View File

@ -12,7 +12,9 @@ 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.auth.openForgotPassword
import com.isolaatti.databinding.FragmentSettingsChangePasswordBinding
import com.isolaatti.settings.data.remote.ChangePasswordResponseDto
import com.isolaatti.settings.presentation.ChangePasswordViewModel
import com.isolaatti.utils.Resource
import dagger.hilt.android.AndroidEntryPoint
@ -109,8 +111,8 @@ class ChangePasswordFragment : Fragment() {
viewBinding.newPasswordInputText.error = if(valid) null else getString(R.string.password_req)
}
viewModel.passwordChangeResource.observe(viewLifecycleOwner) {
when(it) {
viewModel.passwordChangeResource.observe(viewLifecycleOwner) { resource ->
when(resource) {
is Resource.Loading -> {
lockControls(true)
showLoadingDialog()
@ -124,14 +126,62 @@ class ChangePasswordFragment : Fragment() {
is Resource.Success -> {
loadingDialog?.dismiss()
loadingDialog = null
if(viewModel.signOutCurrent) {
signOut()
if(resource.data?.success == true) {
handlePasswordChangeSuccess()
} else {
findNavController().popBackStack()
handlePasswordChangeError(resource.data?.reason)
}
}
}
}
}
private fun handlePasswordChangeSuccess() {
if(viewModel.signOutCurrent) {
signOut()
} else {
findNavController().popBackStack()
}
}
private fun handlePasswordChangeError(error: String?) {
when(error) {
ChangePasswordResponseDto.ReasonOldPasswordMismatch -> {
viewBinding.switcher.showNext()
showOldPasswordIsNotCorrectDialog()
}
ChangePasswordResponseDto.ReasonNewPasswordInvalid -> {
showNewPasswordIsInvalid()
}
// No special handling for "user_does_not_exist" as this
// error should not be faced by app user
else -> {
showUnknownErrorDialog()
}
}
}
private fun showOldPasswordIsNotCorrectDialog() {
MaterialAlertDialogBuilder(requireContext())
.setMessage(R.string.old_password_not_correct)
.setNeutralButton(R.string.recover_password){_, _ ->
openForgotPassword(requireContext())
}
.setPositiveButton(R.string.dismiss, null)
.show()
}
private fun showNewPasswordIsInvalid() {
MaterialAlertDialogBuilder(requireContext())
.setMessage(R.string.new_password_is_invalid)
.setPositiveButton(R.string.dismiss, null)
.show()
}
private fun showUnknownErrorDialog() {
MaterialAlertDialogBuilder(requireContext())
.setMessage(R.string.unknown_error)
.setPositiveButton(R.string.dismiss, null)
.show()
}
}

View File

@ -142,7 +142,7 @@
android:layout_height="wrap_content"
android:text="@string/sign_out_this_device"
android:layout_marginHorizontal="16dp"
android:enabled="false"
android:enabled="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"

View File

@ -162,4 +162,7 @@
<string name="continuar">Continue</string>
<string name="password_req">Password must contain at least 8 characters an have the following: 19, a-z, A-Z, special character.</string>
<string name="changing_password">Changing password…</string>
<string name="recover_password">Recover password</string>
<string name="old_password_not_correct">Password not changed, old password did not match. If you don\'t remember your password, you can always recover it.</string>
<string name="new_password_is_invalid">New password is invalid. Please check it meets the requirements</string>
</resources>