Skip to content

Instantly share code, notes, and snippets.

{
"fields": [
{
"field": "email",
"error": "invalid_email"
}
]
}
// 400 error body entities
class FieldError(val field: String, val error: String)
class ValidationErrorResponse(val fields: List<FieldError>)
// repository reading data from api
class Repository(val api: Api) {
fun login(email: String, password: String): Single<User> = api.login(email, password)
}
class NoInternetConnectionException() : Exception()
class GeneralServerException(val code: Int) : Exception()
class UnexpectedException(val originalException: Exception) : Exception()
class InvalidCredentialsException : Exception()
class ValidationException(val errors: Map<String, List<String>>) : Exception()
class Repository(val api: Api) {
fun login(email: String, password: String): Single<User> {
return api.login(email, password)
.onErrorResumeNext { error: Throwable ->
val exception = when (error) {
is HttpException -> {
when (error.code()) {
401 -> InvalidCredentialsException()
400 -> {
val errorResponse: ValidationErrorResponse = error.bodyToValidationError()
fun onViewCreated() {
disposables += viewModel.observeLoginResult()
.observeOnMainThread()
.subscribe {
when (it) {
is LoginResult.LoginOk -> finishLogin()
is LoginResult.LoginError -> {
when (it.error) {
is NoInternetConnectionException -> showNoConnectionError()
is InvalidCredentialsException -> showInvalidCredentialsError()
fun <T> Single<T>.mapApiExceptions(errorCodeMapper: ((HttpException) -> Exception?)? = null): Single<T> {
return onErrorResumeNext { err: Throwable ->
val exception = when (err) {
is HttpException -> {
errorCodeMapper?.invoke(err) ?: GeneralServerException(err.code())
}
is IOException -> NoInternetConnectionException()
else -> UnexpectedException(err)
}
Single.error<T>(exception)
class Repository(val api: Api) {
fun login(email: String, password: String): Single<User> {
return api.login(email, password)
.mapApiExceptions {
when (it.code()) {
401 -> InvalidCredentialsException()
400 -> {
val errorResponse: ValidationErrorResponse = it.bodyToValidationError()
ValidationException(errorResponse.fields.groupBy({ it.error }, { it.field }))
}
fun Fragment.handleErrors(error:Throwable) {
when (error) {
is NoInternetConnectionException -> snackbar(view, R.string.general_no_connection_error)
is GeneralServerException -> snackbar(view, R.string.general_server_error)
else -> throw error
}
}
@Suppress("DEPRECATION")
val htmlSpannable = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY)
} else {
Html.fromHtml(html, null, LiTagHandler())
}
val spannableBuilder = SpannableStringBuilder(htmlSpannable)
val bulletSpans = spannableBuilder.getSpans(0, spannableBuilder.length, BulletSpan::class.java)
bulletSpans.forEach {
val start = spannableBuilder.getSpanStart(it)
<div>
<div>
First paragraph with a little of text before actual star of this demo - the list.
</div>
<ul>
<li>First option that is relatively short</li>
<li>Second option that contains as much info as the first one, but is quite long due to its representative nature</li>
<li>Three makes a crowd</li>
</ul>
<div>