feat: Improve api error handling

This commit is contained in:
Peter Vacho 2024-12-23 19:04:09 +01:00
parent ddf4468a7f
commit 0e5d52b66b
Signed by: school
GPG key ID: 8CFC3837052871B4
2 changed files with 56 additions and 10 deletions

View file

@ -2,14 +2,18 @@ package com.p_vacho.neat_calendar
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.p_vacho.neat_calendar.auth.AuthRepository
import com.p_vacho.neat_calendar.auth.LoginResult
import com.p_vacho.neat_calendar.auth.RegisterResult
import com.p_vacho.neat_calendar.auth.TokenManager
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@ -56,11 +60,33 @@ class LoginActivity : AppCompatActivity() {
private fun performLogin(username: String, password: String) {
CoroutineScope(Dispatchers.Main).launch {
val success = authRepository.login(username, password)
if (success) {
navigateToMainActivity()
} else {
Toast.makeText(this@LoginActivity, "Login failed. Please try again.", Toast.LENGTH_LONG).show()
val result = authRepository.login(username, password)
when (result) {
is LoginResult.Success -> {
navigateToMainActivity()
}
is LoginResult.ValidationError -> {
val errorMessages = result.errorData.detail.joinToString("\n") { detail ->
val field = detail.loc.lastOrNull() ?: "Unknown field"
"$field: ${detail.msg}"
}
// Show the errors in a dialog
AlertDialog.Builder(this@LoginActivity)
.setTitle("Validation Errors")
.setMessage(errorMessages)
.setPositiveButton("OK", null)
.show()
}
is LoginResult.UnknownError -> {
Toast.makeText(
this@LoginActivity,
"Login failed. Please try again.",
Toast.LENGTH_LONG
).show()
}
}
}
}

View file

@ -13,24 +13,44 @@ import com.google.gson.Gson
sealed class RegisterResult {
data class Success(val response: RegisterResponse) : RegisterResult()
data class ValidationError(val errorData: com.p_vacho.neat_calendar.auth.ValidationError) : RegisterResult()
object UserAlreadyExists : RegisterResult()
data object UserAlreadyExists : RegisterResult()
data class UnknownError(val exception: Throwable) : RegisterResult()
}
sealed class LoginResult {
data object Success : LoginResult()
data class ValidationError(val errorData: com.p_vacho.neat_calendar.auth.ValidationError) : LoginResult()
data class UnknownError(val exception: Throwable) : LoginResult()
}
class AuthRepository(private val tokenManager: TokenManager) {
// Login user and store tokens
suspend fun login(username: String, password: String): Boolean {
suspend fun login(username: String, password: String): LoginResult {
return withContext(Dispatchers.IO) {
try {
val response = RetrofitClient.authService.login(username, password)
tokenManager.storeAccessToken(response.access_token, response.expires_in)
tokenManager.storeRefreshToken(response.refresh_token, response.refresh_token_expires_in)
Log.i("API", "Login successful")
true
LoginResult.Success
} catch (e: HttpException) {
when (e.code()) {
422 -> {
val errorBody = e.response()?.errorBody()?.string()
val validationError = Gson().fromJson(errorBody, ValidationError::class.java)
Log.w("API", "Validation error: $validationError")
LoginResult.ValidationError(validationError)
}
else -> {
Log.w("API", "Login request failed (${e.message()})", e)
LoginResult.UnknownError(e)
}
}
} catch (e: Exception) {
Log.w("API", "Login request failed", e)
false
Log.e("API", "Unexpected error during login", e)
LoginResult.UnknownError(e)
}
}
}