mirror of
https://github.com/szkolny-eu/szkolny-android.git
synced 2025-01-31 05:48:19 +01:00
[Errors] Update error details dialog, implement error reporting.
This commit is contained in:
parent
f350a86946
commit
6f95eb3c3f
@ -424,6 +424,11 @@ fun CharSequence?.asItalicSpannable(): Spannable {
|
||||
spannable.setSpan(StyleSpan(Typeface.ITALIC), 0, spannable.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
return spannable
|
||||
}
|
||||
fun CharSequence?.asBoldSpannable(): Spannable {
|
||||
val spannable = SpannableString(this)
|
||||
spannable.setSpan(StyleSpan(Typeface.BOLD), 0, spannable.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
return spannable
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new read-only list only of those given elements, that are not empty.
|
||||
|
@ -8,6 +8,8 @@ import android.content.Context
|
||||
import com.google.gson.JsonObject
|
||||
import im.wangchao.mhttp.Request
|
||||
import im.wangchao.mhttp.Response
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.request.ErrorReportRequest
|
||||
import pl.szczodrzynski.edziennik.stackTraceString
|
||||
|
||||
class ApiError(val tag: String, val errorCode: Int) {
|
||||
var profileId: Int? = null
|
||||
@ -52,6 +54,15 @@ class ApiError(val tag: String, val errorCode: Int) {
|
||||
)
|
||||
}
|
||||
|
||||
fun getStringText(context: Context): String {
|
||||
return context.resources.getIdentifier("error_${errorCode}", "string", context.packageName).let {
|
||||
if (it != 0)
|
||||
context.getString(it)
|
||||
else
|
||||
"?"
|
||||
}
|
||||
}
|
||||
|
||||
fun getStringReason(context: Context): String {
|
||||
return context.resources.getIdentifier("error_${errorCode}_reason", "string", context.packageName).let {
|
||||
if (it != 0)
|
||||
@ -65,5 +76,31 @@ class ApiError(val tag: String, val errorCode: Int) {
|
||||
return "ApiError(tag='$tag', errorCode=$errorCode, profileId=$profileId, throwable=$throwable, apiResponse=$apiResponse, request=$request, response=$response, isCritical=$isCritical)"
|
||||
}
|
||||
|
||||
fun toReportableError(context: Context): ErrorReportRequest.Error {
|
||||
val requestString = request?.let {
|
||||
it.method() + " " + it.url() + "\n" + it.headers()
|
||||
}
|
||||
val responseString = response?.let {
|
||||
if (it.parserErrorBody == null) {
|
||||
try {
|
||||
it.parserErrorBody = it.raw().body()?.string()
|
||||
} catch (e: Exception) {
|
||||
it.parserErrorBody = e.stackTraceString
|
||||
}
|
||||
}
|
||||
"HTTP "+it.code()+" "+it.message()+"\n" + it.headers() + "\n\n" + it.parserErrorBody
|
||||
}
|
||||
return ErrorReportRequest.Error(
|
||||
tag = tag,
|
||||
errorCode = errorCode,
|
||||
errorText = getStringText(context),
|
||||
errorReason = getStringReason(context),
|
||||
stackTrace = throwable?.stackTraceString,
|
||||
request = requestString,
|
||||
response = responseString,
|
||||
apiResponse = apiResponse,
|
||||
isCritical = isCritical
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import pl.szczodrzynski.edziennik.BuildConfig
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.adapter.DateAdapter
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.adapter.TimeAdapter
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.SignatureInterceptor
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.request.ErrorReportRequest
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.request.EventShareRequest
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.request.ServerSyncRequest
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.request.WebPushRequest
|
||||
@ -164,4 +165,11 @@ class SzkolnyApi(val app: App) {
|
||||
|
||||
return response?.data?.browsers ?: emptyList()
|
||||
}
|
||||
|
||||
fun errorReport(errors: List<ErrorReportRequest.Error>): ApiResponse<Nothing>? {
|
||||
return api.errorReport(ErrorReportRequest(
|
||||
deviceId = app.deviceId,
|
||||
errors = errors
|
||||
)).execute().body()
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.szkolny
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.request.ErrorReportRequest
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.request.EventShareRequest
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.request.ServerSyncRequest
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.request.WebPushRequest
|
||||
@ -24,4 +25,7 @@ interface SzkolnyService {
|
||||
|
||||
@POST("webPush")
|
||||
fun webPush(@Body request: WebPushRequest): Call<ApiResponse<WebPushResponse>>
|
||||
|
||||
@POST("errorReport")
|
||||
fun errorReport(@Body request: ErrorReportRequest): Call<ApiResponse<Nothing>>
|
||||
}
|
||||
|
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-12-31.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.szkolny.request
|
||||
|
||||
data class ErrorReportRequest(
|
||||
val deviceId: String,
|
||||
val errors: List<Error>
|
||||
) {
|
||||
data class Error(
|
||||
val tag: String,
|
||||
val errorCode: Int,
|
||||
val errorText: String?,
|
||||
val errorReason: String?,
|
||||
val stackTrace: String?,
|
||||
val request: String?,
|
||||
val response: String?,
|
||||
val apiResponse: String?,
|
||||
val isCritical: Boolean
|
||||
)
|
||||
}
|
@ -5,18 +5,20 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.error
|
||||
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import androidx.core.graphics.ColorUtils
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import kotlinx.coroutines.*
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.stackTraceString
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
|
||||
import pl.szczodrzynski.navlib.getColorFromAttr
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class ErrorSnackbar(val activity: AppCompatActivity) {
|
||||
class ErrorSnackbar(val activity: AppCompatActivity) : CoroutineScope {
|
||||
companion object {
|
||||
private const val TAG = "ErrorSnackbar"
|
||||
}
|
||||
@ -25,16 +27,26 @@ class ErrorSnackbar(val activity: AppCompatActivity) {
|
||||
private lateinit var coordinator: CoordinatorLayout
|
||||
private val errors = mutableListOf<ApiError>()
|
||||
|
||||
private val job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Main
|
||||
|
||||
private val api by lazy { SzkolnyApi(activity.applicationContext as App) }
|
||||
|
||||
fun setCoordinator(coordinatorLayout: CoordinatorLayout, showAbove: View? = null) {
|
||||
this.coordinator = coordinatorLayout
|
||||
snackbar = Snackbar.make(coordinator, R.string.snackbar_error_text, Snackbar.LENGTH_INDEFINITE)
|
||||
snackbar?.setAction(R.string.more) {
|
||||
if (errors.isNotEmpty()) {
|
||||
val message = errors.map {
|
||||
if (App.devMode) it.throwable?.stackTraceString
|
||||
?: it.throwable?.localizedMessage ?: ""
|
||||
else it.throwable?.localizedMessage
|
||||
}.joinToString("\n")
|
||||
listOf(
|
||||
it.getStringReason(activity).asBoldSpannable(),
|
||||
if (App.devMode)
|
||||
it.throwable?.stackTraceString ?: it.throwable?.localizedMessage
|
||||
else
|
||||
it.throwable?.localizedMessage
|
||||
).concat("\n")
|
||||
}.concat("\n\n")
|
||||
|
||||
MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.dialog_error_details_title)
|
||||
@ -43,6 +55,20 @@ class ErrorSnackbar(val activity: AppCompatActivity) {
|
||||
errors.clear()
|
||||
dialog.dismiss()
|
||||
}
|
||||
.setNeutralButton(R.string.report) { dialog, _ ->
|
||||
launch {
|
||||
val response = withContext(Dispatchers.Default) {
|
||||
api.errorReport(errors.map { it.toReportableError(activity) })
|
||||
}
|
||||
|
||||
response?.errors?.ifNotEmpty {
|
||||
Toast.makeText(activity, "Error: " + it[0].reason, Toast.LENGTH_SHORT).show()
|
||||
return@launch
|
||||
}
|
||||
errors.clear()
|
||||
dialog.dismiss()
|
||||
}
|
||||
}
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user