Improve session handling and UI state updates
Refactored JmapApi to ensure session is initialized before API calls, reducing potential errors. Updated LoginViewModel to remove all whitespace from tokens before login. MaskedEmailDetailViewModel now consistently resets isUpdating flag on data load and error, improving UI state accuracy. Added ProGuard rules to suppress warnings for Google Error Prone annotations.
This commit is contained in:
parent
5eee3a4fed
commit
d6a86a1a69
4 changed files with 26 additions and 5 deletions
6
app/proguard-rules.pro
vendored
6
app/proguard-rules.pro
vendored
|
|
@ -37,3 +37,9 @@
|
|||
# OkHttp
|
||||
-dontwarn okhttp3.**
|
||||
-dontwarn okio.**
|
||||
|
||||
# Google Tink / Error Prone annotations
|
||||
-dontwarn com.google.errorprone.annotations.CanIgnoreReturnValue
|
||||
-dontwarn com.google.errorprone.annotations.CheckReturnValue
|
||||
-dontwarn com.google.errorprone.annotations.Immutable
|
||||
-dontwarn com.google.errorprone.annotations.RestrictedApi
|
||||
|
|
|
|||
|
|
@ -33,8 +33,14 @@ class JmapApi @Inject constructor(
|
|||
|
||||
fun getApiUrl(): String = cachedSession?.apiUrl ?: JmapService.FASTMAIL_API_URL
|
||||
|
||||
private suspend fun ensureSession(token: String): String {
|
||||
cachedAccountId?.let { return it }
|
||||
getSession(token).getOrThrow()
|
||||
return cachedAccountId ?: throw IllegalStateException("Failed to get account ID from session")
|
||||
}
|
||||
|
||||
suspend fun getMaskedEmails(token: String): Result<List<MaskedEmailDto>> = runCatching {
|
||||
val accountId = cachedAccountId ?: throw IllegalStateException("Session not initialized")
|
||||
val accountId = ensureSession(token)
|
||||
val authHeader = "Bearer $token"
|
||||
|
||||
val methodCall = buildJsonArray {
|
||||
|
|
@ -63,7 +69,7 @@ class JmapApi @Inject constructor(
|
|||
token: String,
|
||||
create: MaskedEmailCreate
|
||||
): Result<MaskedEmailDto> = runCatching {
|
||||
val accountId = cachedAccountId ?: throw IllegalStateException("Session not initialized")
|
||||
val accountId = ensureSession(token)
|
||||
val authHeader = "Bearer $token"
|
||||
|
||||
val createObject = buildJsonObject {
|
||||
|
|
@ -104,7 +110,7 @@ class JmapApi @Inject constructor(
|
|||
id: String,
|
||||
update: MaskedEmailUpdate
|
||||
): Result<Unit> = runCatching {
|
||||
val accountId = cachedAccountId ?: throw IllegalStateException("Session not initialized")
|
||||
val accountId = ensureSession(token)
|
||||
val authHeader = "Bearer $token"
|
||||
|
||||
val updateObject = buildJsonObject {
|
||||
|
|
@ -140,7 +146,7 @@ class JmapApi @Inject constructor(
|
|||
}
|
||||
|
||||
suspend fun deleteMaskedEmail(token: String, id: String): Result<Unit> = runCatching {
|
||||
val accountId = cachedAccountId ?: throw IllegalStateException("Session not initialized")
|
||||
val accountId = ensureSession(token)
|
||||
val authHeader = "Bearer $token"
|
||||
|
||||
val methodCall = buildJsonArray {
|
||||
|
|
@ -227,6 +233,11 @@ class JmapApi @Inject constructor(
|
|||
setResponse.notUpdated?.get(id)?.let { error ->
|
||||
throw JmapException("Failed to update: ${error.type} - ${error.description}")
|
||||
}
|
||||
|
||||
// Verify the update actually succeeded
|
||||
if (setResponse.updated?.containsKey(id) != true) {
|
||||
throw JmapException("Update not confirmed by server - ID not found in updated response")
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseSetResponseDestroyed(response: JmapResponse, id: String) {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,8 @@ class LoginViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
fun login() {
|
||||
val token = _uiState.value.token.trim()
|
||||
// Remove all whitespace characters (spaces, newlines, tabs) from the token
|
||||
val token = _uiState.value.token.filterNot { it.isWhitespace() }
|
||||
if (token.isBlank()) {
|
||||
_uiState.update { it.copy(error = "Please enter your API token") }
|
||||
return
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ class MaskedEmailDetailViewModel @Inject constructor(
|
|||
_uiState.update {
|
||||
it.copy(
|
||||
isLoading = false,
|
||||
isUpdating = false,
|
||||
email = email,
|
||||
editedDescription = email.description ?: "",
|
||||
editedForDomain = email.forDomain ?: "",
|
||||
|
|
@ -62,6 +63,7 @@ class MaskedEmailDetailViewModel @Inject constructor(
|
|||
_uiState.update {
|
||||
it.copy(
|
||||
isLoading = false,
|
||||
isUpdating = false,
|
||||
error = "Email not found"
|
||||
)
|
||||
}
|
||||
|
|
@ -71,6 +73,7 @@ class MaskedEmailDetailViewModel @Inject constructor(
|
|||
_uiState.update {
|
||||
it.copy(
|
||||
isLoading = false,
|
||||
isUpdating = false,
|
||||
error = error.message ?: "Failed to load email"
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue