From 6d3b2806ed1707404df5c90726b75eb7957be753 Mon Sep 17 00:00:00 2001 From: Hafiz Date: Mon, 14 Jul 2025 11:45:07 -0500 Subject: [PATCH] Show inline password error on account reset failure - Add showIncorrectPasswordError() in HabiticaAccountDialog to display a field-level error message - Update resetAccount() in the fragment to dismiss the spinner on both outcomes and, on failure, keep the sheet open and call showIncorrectPasswordError("Incorrect password.") rather than closing the dialog --- .../habitrpg/android/habitica/data/ApiClient.kt | 2 +- .../android/habitica/data/UserRepository.kt | 2 +- .../data/implementation/ApiClientImpl.kt | 14 ++++++++++++-- .../data/implementation/UserRepositoryImpl.kt | 10 +++++++--- .../preferences/AccountPreferenceFragment.kt | 16 ++++++++++++---- .../preferences/HabiticaAccountDialog.kt | 9 +++++++++ 6 files changed, 42 insertions(+), 11 deletions(-) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/ApiClient.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/ApiClient.kt index ddaf6c638..e59aa95c5 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/ApiClient.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/ApiClient.kt @@ -395,7 +395,7 @@ interface ApiClient { suspend fun reroll(): User? - suspend fun resetAccount(password: String): Void? + suspend fun resetAccount(password: String): Boolean suspend fun deleteAccount(password: String): Void? diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/UserRepository.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/UserRepository.kt index fd3b59252..e1a0d8c3a 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/UserRepository.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/UserRepository.kt @@ -87,7 +87,7 @@ interface UserRepository : BaseRepository { suspend fun updateLanguage(languageCode: String): User? - suspend fun resetAccount(password: String): User? + suspend fun resetAccount(password: String): Boolean? suspend fun deleteAccount(password: String): Void? diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.kt index ebae405fb..351499a74 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.kt @@ -97,6 +97,16 @@ class ApiClientImpl( return null } + private suspend fun processWithIfSuccess(apiCall: suspend () -> HabitResponse): Boolean { + try { + processResponse(apiCall()) + return true + } catch (throwable: Throwable) { + accept(throwable) + return false + } + } + override var languageCode: String? = null private var lastAPICallURL: String? = null @@ -994,10 +1004,10 @@ class ApiClientImpl( override suspend fun reroll(): User? = process { apiService.reroll() } - override suspend fun resetAccount(password: String): Void? { + override suspend fun resetAccount(password: String): Boolean { val updateObject = HashMap() updateObject["password"] = password - return process { apiService.resetAccount(updateObject) } + return processWithIfSuccess { apiService.resetAccount(updateObject) } } override suspend fun deleteAccount(password: String): Void? { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImpl.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImpl.kt index 9cf61a464..cef767e2a 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImpl.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImpl.kt @@ -273,9 +273,13 @@ class UserRepositoryImpl( return mergeWithExistingUser(user) } - override suspend fun resetAccount(password: String): User? { - apiClient.resetAccount(password) - return retrieveUser(withTasks = true, forced = true) + override suspend fun resetAccount(password: String): Boolean { + val resetAccountSuccessful = apiClient.resetAccount(password) + if (resetAccountSuccessful) { + retrieveUser(withTasks = true, forced = true) + return true + } + return false } override suspend fun deleteAccount(password: String) = apiClient.deleteAccount(password) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/AccountPreferenceFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/AccountPreferenceFragment.kt index 82b954ba2..72d9b33b1 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/AccountPreferenceFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/AccountPreferenceFragment.kt @@ -52,7 +52,9 @@ import com.habitrpg.common.habitica.helpers.ExceptionHandler import com.habitrpg.common.habitica.helpers.MainNavigationController import com.habitrpg.common.habitica.helpers.launchCatching import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import retrofit2.HttpException import javax.inject.Inject @@ -602,11 +604,17 @@ class AccountPreferenceFragment : } private fun resetAccount(confirmationString: String) { - val dialog = activity?.let { HabiticaProgressDialog.show(it, R.string.resetting_account) } + val progressDialog = activity?.let { HabiticaProgressDialog.show(it, R.string.resetting_account) } lifecycleScope.launch(ExceptionHandler.coroutine()) { - userRepository.resetAccount(confirmationString) - dialog?.dismiss() - accountDialog.dismiss() + val resetAccountSuccess = userRepository.resetAccount(confirmationString) ?: false + progressDialog?.dismiss() + if (resetAccountSuccess) { + accountDialog.dismiss() + } else { + accountDialog.showIncorrectPasswordError( + getString(R.string.incorrect_password) + ) + } } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/HabiticaAccountDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/HabiticaAccountDialog.kt index 2841968fa..46b757960 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/HabiticaAccountDialog.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/HabiticaAccountDialog.kt @@ -287,6 +287,15 @@ class HabiticaAccountDialog(private var thisContext: Context) : } } + fun showIncorrectPasswordError(message: String) { + if (viewBinding == null) return + + binding.confirmationTextInputLayout.apply { + error = message + isErrorEnabled = true + } + } + override fun getTheme(): Int { return R.style.HabiticaAlertDialogTheme }