Skip to content

Instantly share code, notes, and snippets.

interface RecipesApiDescription {
@GET("recipes")
suspend fun recipes(): List<ApiRecipe>
@GET("recipes/{recipeId}")
suspend fun recipeDetail(@Path("recipeId") recipeId: String): ApiRecipe
}
/**
* This method will be called whenn the HTML parser encounters
* a tag that it does not know how to interpret.
*/
public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader);
override fun handleTag(opening: Boolean, tag: String, output: Editable, xmlReader: XMLReader) {
if (tag == "li" && opening) {
output.setSpan(Bullet(), output.length, output.length, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
}
if (tag == "li" && !opening) {
output.append("\n\n")
val lastMark = output.getSpans(0, output.length, Bullet::class.java).lastOrNull()
lastMark?.let {
val start = output.getSpanStart(it)
output.removeSpan(it)
Html.fromHtml(html, null,
Html.TagHandler { opening, tag, output, xmlReader ->
if (tag == "ul" && !opening) output.append("\n")
if (tag == "li" && opening) output.append("\n\t• ")
})
<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>
@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)
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
}
}
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 <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)
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()