Show better errors when loading notifications fails (#3448)

* Show better errors with notification loading fails

The errors are returned as a JSON object, parse it, and show the error
message it contains.

Handle the cases where there might be no error message, or the JSON may be
malformed.

Add tests.

Fixes #3445

* Lint
This commit is contained in:
Nik Clayton 2023-03-18 10:25:41 +01:00 committed by GitHub
commit 81f725667e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 192 additions and 3 deletions

View file

@ -20,6 +20,7 @@ package com.keylesspalace.tusky.components.notifications
import android.util.Log
import androidx.paging.PagingSource
import androidx.paging.PagingState
import com.google.gson.Gson
import com.keylesspalace.tusky.entity.Notification
import com.keylesspalace.tusky.network.MastodonApi
import com.keylesspalace.tusky.util.HttpHeaderLink
@ -35,6 +36,7 @@ data class Links(val next: String?, val prev: String?)
/** [PagingSource] for Mastodon Notifications, identified by the Notification ID */
class NotificationsPagingSource @Inject constructor(
private val mastodonApi: MastodonApi,
private val gson: Gson,
private val notificationFilter: Set<Notification.Type>
) : PagingSource<String, Notification>() {
override suspend fun load(params: LoadParams<String>): LoadResult<String, Notification> {
@ -58,7 +60,23 @@ class NotificationsPagingSource @Inject constructor(
}
if (!response.isSuccessful) {
return LoadResult.Error(Throwable(response.errorBody()?.string()))
val code = response.code()
val msg = response.errorBody()?.string()?.let { errorBody ->
if (errorBody.isBlank()) return@let "no reason given"
val error = try {
gson.fromJson(errorBody, com.keylesspalace.tusky.entity.Error::class.java)
} catch (e: Exception) {
return@let "$errorBody ($e)"
}
when (val desc = error.error_description) {
null -> error.error
else -> "${error.error}: $desc"
}
} ?: "no reason given"
return LoadResult.Error(Throwable("HTTP $code: $msg"))
}
val links = getPageLinks(response.headers()["link"])

View file

@ -23,6 +23,7 @@ import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import androidx.paging.PagingSource
import com.google.gson.Gson
import com.keylesspalace.tusky.entity.Notification
import com.keylesspalace.tusky.network.MastodonApi
import kotlinx.coroutines.flow.Flow
@ -31,7 +32,8 @@ import retrofit2.Response
import javax.inject.Inject
class NotificationsRepository @Inject constructor(
private val mastodonApi: MastodonApi
private val mastodonApi: MastodonApi,
private val gson: Gson
) {
private var factory: InvalidatingPagingSourceFactory<String, Notification>? = null
@ -47,7 +49,7 @@ class NotificationsRepository @Inject constructor(
Log.d(TAG, "getNotificationsStream(), filtering: $filter")
factory = InvalidatingPagingSourceFactory {
NotificationsPagingSource(mastodonApi, filter)
NotificationsPagingSource(mastodonApi, gson, filter)
}
return Pager(

View file

@ -0,0 +1,24 @@
/*
* Copyright 2023 Tusky Contributors
*
* This file is a part of Tusky.
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see <http://www.gnu.org/licenses>.
*/
package com.keylesspalace.tusky.entity
/** @see [Error](https://docs.joinmastodon.org/entities/Error/) */
data class Error(
val error: String,
val error_description: String?
)