Skip to content

Commit

Permalink
MBL-1420: Webp format now supported for animated gifs (#2039)
Browse files Browse the repository at this point in the history
  • Loading branch information
Arkariang authored May 15, 2024
1 parent 9ded302 commit 4ce4997
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 16 deletions.
2 changes: 2 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,8 @@ dependencies {

// GLIDE
final glide_version = "4.16.0"
// webpdecoder
implementation "com.github.zjupure:webpdecoder:2.6.$glide_version"
implementation "com.github.bumptech.glide:glide:$glide_version"
annotationProcessor "com.github.bumptech.glide:compiler:$glide_version"
kapt "com.github.bumptech.glide:compiler:$glide_version"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,15 @@ fun String?.parseToDouble(): Double {
}

/**
* Returns a boolean that reflects if the string is an email address
* Returns a boolean that reflects if the string contains the .webp extension
*/
fun String.isWebp(): Boolean {
val gifPattern = "(?:\\/\\/.*\\.(?:webp))"
return gifPattern.toRegex().find(this) != null
}

/**
* Returns a boolean that reflects if the string contains the .gif extension
*/
fun String.isGif(): Boolean {
val gifPattern = "(?:\\/\\/.*\\.(?:gif))"
Expand Down
36 changes: 27 additions & 9 deletions app/src/main/java/com/kickstarter/ui/extensions/ImageViewExt.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,17 @@ import android.graphics.drawable.Drawable
import android.widget.ImageView
import androidx.appcompat.widget.AppCompatImageView
import com.bumptech.glide.Glide
import com.bumptech.glide.integration.webp.decoder.WebpDrawable
import com.bumptech.glide.integration.webp.decoder.WebpDrawableTransformation
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.Target
import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.kickstarter.R
import com.kickstarter.libs.utils.extensions.isKSApplication
import javax.sql.DataSource

fun ImageView.loadCircleImage(url: String?) {
url?.let {
Expand Down Expand Up @@ -80,7 +82,7 @@ fun ImageView.loadImageWithResize(
}
}
}
fun ImageView.loadImage(url: String?, context: Context, imageViewPlaceholder: AppCompatImageView? = null) {
fun ImageView.loadImage(url: String?, context: Context, imageZoomablePlaceholder: AppCompatImageView? = null) {
url?.let {
val targetView = this
if (context.applicationContext.isKSApplication()) {
Expand All @@ -95,7 +97,8 @@ fun ImageView.loadImage(url: String?, context: Context, imageViewPlaceholder: Ap
dataSource: com.bumptech.glide.load.DataSource,
isFirstResource: Boolean
): Boolean {
imageViewPlaceholder?.setImageDrawable(resource)
targetView.setImageDrawable(resource)
imageZoomablePlaceholder?.setImageDrawable(resource)
return isFirstResource
}

Expand All @@ -106,12 +109,11 @@ fun ImageView.loadImage(url: String?, context: Context, imageViewPlaceholder: Ap
isFirstResource: Boolean
): Boolean {
targetView.setImageDrawable(null)
imageViewPlaceholder?.setImageDrawable(null)
imageZoomablePlaceholder?.setImageDrawable(null)
return isFirstResource
}
})
.placeholder(ColorDrawable(Color.TRANSPARENT))
.diskCacheStrategy(DiskCacheStrategy.ALL)
.diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
.load(url)
.into(this)
} catch (e: Exception) {
Expand All @@ -125,15 +127,31 @@ fun ImageView.loadImage(url: String?, context: Context, imageViewPlaceholder: Ap
}
}

fun ImageView.loadWebp(url: String?, context: Context) {
url?.let {
try {
val roundedCorners = RoundedCorners(1)
Glide.with(this)
.load(it)
.optionalTransform(roundedCorners)
.optionalTransform(WebpDrawable::class.java, WebpDrawableTransformation(roundedCorners))
.diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
.into(this)
} catch (e: Exception) {
this.setImageResource(R.drawable.image_placeholder)
FirebaseCrashlytics.getInstance().setCustomKey("ImageView.loadImageWithResize", " with url: $url ${e.message ?: ""}")
FirebaseCrashlytics.getInstance().recordException(e)
}
}
}
fun ImageView.loadGifImage(url: String?, context: Context) {
url?.let {
if (context.applicationContext.isKSApplication()) {
try {
Glide.with(context)
.asGif()
.placeholder(ColorDrawable(Color.TRANSPARENT))
.diskCacheStrategy(DiskCacheStrategy.ALL)
.load(url)
.load(it)
.diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
.into(this)
} catch (e: Exception) {
this.setImageResource(R.drawable.image_placeholder)
Expand Down
20 changes: 14 additions & 6 deletions app/src/main/java/com/kickstarter/ui/views/ImageWithCaptionView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ import com.aghajari.zoomhelper.ZoomHelper
import com.kickstarter.R
import com.kickstarter.databinding.ViewImageWithCaptionBinding
import com.kickstarter.libs.utils.extensions.isGif
import com.kickstarter.libs.utils.extensions.isWebp
import com.kickstarter.ui.extensions.loadGifImage
import com.kickstarter.ui.extensions.loadImage
import com.kickstarter.ui.extensions.loadWebp
import com.kickstarter.ui.extensions.makeLinks

@SuppressLint("ClickableViewAccessibility")
Expand All @@ -35,12 +37,18 @@ class ImageWithCaptionView @JvmOverloads constructor(
binding.imageView.setImageDrawable(null)
binding.imageViewPlaceholder.setImageDrawable(null)
} else {
if (src.isGif()) {
binding.imageView.loadGifImage(src, context)
} else {
binding.imageView.loadImage(src, context, binding.imageViewPlaceholder)
ZoomHelper.addZoomableView(binding.imageView)
ZoomHelper.removeZoomableView(binding.imageViewPlaceholder)
when {
src.isWebp() -> {
binding.imageView.loadWebp(src, context)
}
src.isGif() -> {
binding.imageView.loadGifImage(src, context)
}
else -> {
binding.imageView.loadImage(src, context, binding.imageViewPlaceholder)
ZoomHelper.addZoomableView(binding.imageView)
ZoomHelper.removeZoomableView(binding.imageViewPlaceholder)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package com.kickstarter.libs.htmlparser

import com.kickstarter.libs.utils.extensions.isGif
import com.kickstarter.libs.utils.extensions.isWebp
import junit.framework.TestCase
import junit.framework.TestCase.assertEquals
import junit.framework.TestCase.assertTrue
import org.junit.Test
import java.net.URI

Expand Down Expand Up @@ -344,4 +347,27 @@ class HTMLParserTest {
assert(h6.components[0].styles[0] == TextComponent.TextStyleType.HEADER6)
assert(h6.components[0].text == "This is heading 6")
}

@Test
fun given_HTML_withGifAndWebpExtensions_HtmlParser_returns_ImageViewElement_with_URL() {
val htmlGif = "<div class=\"template asset\" contenteditable=\"false\" data-alt-text=\"\" data-caption=\"\" data-id=\"44904170\">\n" +
" <figure class=\"image\">\n" +
" <img alt=\"\" class=\"fit js-lazy-image\" data-src=\"https://i.kickstarter.com/assets/044/904/170/8f34ecce9f82c23fde692cc4142c4630_original.gif?fit=scale-down&amp;amp;origin=ugc&amp;amp;q=92&amp;amp;width=700&amp;amp;sig=ZqRtxdLrF0UP7iJ0za7PZozt0HPUbVshM%2Bnphli8oTA%3D\" src=\"https://i.kickstarter.com/assets/044/904/170/8f34ecce9f82c23fde692cc4142c4630_original.gif?anim=false&amp;amp;fit=scale-down&amp;amp;origin=ugc&amp;amp;q=92&amp;amp;width=700&amp;amp;sig=%2FNSNA716ADltGnCen9XnFGjlOi6nSy36sef7hdFe9eQ%3D\" > \n" +
" </figure>\n" +
"</div>\n"
val htmlWebMP =
"<div class=\"template asset\" contenteditable=\"false\" data-alt-text=\"\" data-caption=\"\" data-id=\"44690634\">\n" +
" <figure class=\"image\">\n" +
" <img alt=\"\" class=\"fit\" src=\"https://i.kickstarter.com/assets/044/690/634/1a2c5e757fa2a5b0db60876b56e11295_original.webp?fit=scale-down&amp;amp;origin=ugc&amp;amp;q=92&amp;amp;width=700&amp;amp;sig=4V3Wnp7WocWKYQWv9ErXnbB4%2FPeGiCv59bBv3e04Kqs%3D\">\n" +
" </figure>\n" +
"</div>"

val listOfElements = HTMLParser().parse(htmlGif + htmlWebMP)
assert(listOfElements.size == 2)
val imageViewGif: ImageViewElement = listOfElements.first() as ImageViewElement
val imageViewWebp: ImageViewElement = listOfElements.last() as ImageViewElement

assertTrue(imageViewGif.src.isGif())
assertTrue(imageViewWebp.src.isWebp())
}
}

0 comments on commit 4ce4997

Please sign in to comment.