diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 7ed9da937..94e151fdf 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -124,6 +124,7 @@ dependencies { compileOnly(libs.okhttp) ksp(libs.glide.compiler) + implementation(libs.zjupure.webpdecoder) implementation(libs.bundles.room) ksp(libs.androidx.room.compiler) diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/MainActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/MainActivity.kt index b52bd673e..4fcf65b7b 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/MainActivity.kt @@ -77,7 +77,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener { private var mDirs = ArrayList() private var mDirsIgnoringSearch = ArrayList() - private var mStoredAnimateGifs = true + private var mStoredAnimateGifsInFolders = true private var mStoredCropThumbnails = true private var mStoredScrollHorizontally = true private var mStoredTextColor = 0 @@ -198,8 +198,8 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener { refreshMenuItems() - if (mStoredAnimateGifs != config.animateGifs) { - getRecyclerAdapter()?.updateAnimateGifs(config.animateGifs) + if (mStoredAnimateGifsInFolders != config.animateGifsInFolders) { + getRecyclerAdapter()?.updateAnimateGifs(config.animateGifsInFolders) } if (mStoredCropThumbnails != config.cropThumbnails) { @@ -438,7 +438,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener { mStoredTextColor = getProperTextColor() mStoredPrimaryColor = getProperPrimaryColor() config.apply { - mStoredAnimateGifs = animateGifs + mStoredAnimateGifsInFolders = animateGifsInFolders mStoredCropThumbnails = cropThumbnails mStoredScrollHorizontally = scrollHorizontally mStoredStyleString = "$folderStyle$showFolderMediaCount$limitFolderTitle" diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/WidgetConfigureActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/WidgetConfigureActivity.kt index 26c093814..7e93849f3 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/WidgetConfigureActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/WidgetConfigureActivity.kt @@ -178,7 +178,7 @@ class WidgetConfigureActivity : SimpleActivity() { if (path != null) { runOnUiThread { val signature = ObjectKey(System.currentTimeMillis().toString()) - loadJpg(path, binding.configImage, config.cropThumbnails, ROUNDED_CORNERS_NONE, signature) + loadImageBase(path, binding.configImage, config.cropThumbnails, ROUNDED_CORNERS_NONE, signature) } } } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/adapters/DirectoryAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/adapters/DirectoryAdapter.kt index 80809b34d..d0382da36 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/adapters/DirectoryAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/adapters/DirectoryAdapter.kt @@ -55,7 +55,7 @@ class DirectoryAdapter( private val isListViewType = config.viewTypeFolders == VIEW_TYPE_LIST private var pinnedFolders = config.pinnedFolders private var scrollHorizontally = config.scrollHorizontally - private var animateGifs = config.animateGifs + private var animateGifs = config.animateGifsInFolders private var cropThumbnails = config.cropThumbnails private var groupDirectSubfolders = config.groupDirectSubfolders private var currentDirectoriesHash = dirs.hashCode() diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/dialogs/ChangeFileThumbnailStyleDialog.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/dialogs/ChangeFileThumbnailStyleDialog.kt index 2070f406d..4c32b4c53 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/dialogs/ChangeFileThumbnailStyleDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/dialogs/ChangeFileThumbnailStyleDialog.kt @@ -1,11 +1,14 @@ package com.simplemobiletools.gallery.pro.dialogs import android.content.DialogInterface +import android.widget.Toast import com.simplemobiletools.commons.activities.BaseSimpleActivity import com.simplemobiletools.commons.dialogs.RadioGroupDialog +import com.simplemobiletools.commons.extensions.beVisibleIf import com.simplemobiletools.commons.extensions.getAlertDialogBuilder import com.simplemobiletools.commons.extensions.setupDialogStuff import com.simplemobiletools.commons.models.RadioItem +import com.simplemobiletools.gallery.pro.R import com.simplemobiletools.gallery.pro.databinding.DialogChangeFileThumbnailStyleBinding import com.simplemobiletools.gallery.pro.extensions.config @@ -22,7 +25,10 @@ class ChangeFileThumbnailStyleDialog(val activity: BaseSimpleActivity) : DialogI dialogFileStyleShowThumbnailFileTypes.isChecked = config.showThumbnailFileTypes dialogFileStyleMarkFavoriteItems.isChecked = config.markFavoriteItems - dialogFileStyleRoundedCornersHolder.setOnClickListener { dialogFileStyleRoundedCorners.toggle() } + dialogFileStyleRoundedCornersHolder.setOnClickListener { + dialogFileStyleRoundedCorners.toggle() + updateAnimateGifsCheckbox() + } dialogFileStyleAnimateGifsHolder.setOnClickListener { dialogFileStyleAnimateGifs.toggle() } dialogFileStyleShowThumbnailVideoDurationHolder.setOnClickListener { dialogFileStyleShowThumbnailVideoDuration.toggle() } dialogFileStyleShowThumbnailFileTypesHolder.setOnClickListener { dialogFileStyleShowThumbnailFileTypes.toggle() } @@ -48,6 +54,7 @@ class ChangeFileThumbnailStyleDialog(val activity: BaseSimpleActivity) : DialogI } updateThumbnailSpacingText() + updateAnimateGifsCheckbox() activity.getAlertDialogBuilder() .setPositiveButton(com.simplemobiletools.commons.R.string.ok, this) @@ -59,13 +66,21 @@ class ChangeFileThumbnailStyleDialog(val activity: BaseSimpleActivity) : DialogI override fun onClick(dialog: DialogInterface, which: Int) { config.fileRoundedCorners = binding.dialogFileStyleRoundedCorners.isChecked - config.animateGifs = binding.dialogFileStyleAnimateGifs.isChecked + if (binding.dialogFileStyleRoundedCorners.isChecked) { + config.animateGifs = false + } else { + config.animateGifs = binding.dialogFileStyleAnimateGifs.isChecked + } config.showThumbnailVideoDuration = binding.dialogFileStyleShowThumbnailVideoDuration.isChecked config.showThumbnailFileTypes = binding.dialogFileStyleShowThumbnailFileTypes.isChecked config.markFavoriteItems = binding.dialogFileStyleMarkFavoriteItems.isChecked config.thumbnailSpacing = thumbnailSpacing } + private fun updateAnimateGifsCheckbox() { + binding.dialogFileStyleAnimateGifs.beVisibleIf(!binding.dialogFileStyleRoundedCorners.isChecked) + } + private fun updateThumbnailSpacingText() { binding.dialogFileStyleSpacing.text = "${thumbnailSpacing}x" } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/dialogs/ChangeFolderThumbnailStyleDialog.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/dialogs/ChangeFolderThumbnailStyleDialog.kt index 06173bafa..df5f152af 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/dialogs/ChangeFolderThumbnailStyleDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/dialogs/ChangeFolderThumbnailStyleDialog.kt @@ -2,6 +2,7 @@ package com.simplemobiletools.gallery.pro.dialogs import android.content.DialogInterface import android.widget.RelativeLayout +import android.widget.Toast import com.bumptech.glide.Glide import com.bumptech.glide.load.resource.bitmap.CenterCrop import com.bumptech.glide.load.resource.bitmap.RoundedCorners @@ -20,6 +21,7 @@ class ChangeFolderThumbnailStyleDialog(val activity: BaseSimpleActivity, val cal private var config = activity.config private val binding = DialogChangeFolderThumbnailStyleBinding.inflate(activity.layoutInflater).apply { dialogFolderLimitTitle.isChecked = config.limitFolderTitle + dialogAnimateGifsInFolders.isChecked = config.animateGifsInFolders } init { @@ -31,6 +33,7 @@ class ChangeFolderThumbnailStyleDialog(val activity: BaseSimpleActivity, val cal setupStyle() setupMediaCount() updateSample() + updateAnimateGifsCheckbox() } } } @@ -39,6 +42,7 @@ class ChangeFolderThumbnailStyleDialog(val activity: BaseSimpleActivity, val cal val styleRadio = binding.dialogRadioFolderStyle styleRadio.setOnCheckedChangeListener { group, checkedId -> updateSample() + updateAnimateGifsCheckbox() } val styleBtn = when (config.folderStyle) { @@ -117,10 +121,7 @@ class ChangeFolderThumbnailStyleDialog(val activity: BaseSimpleActivity, val cal } override fun onClick(dialog: DialogInterface, which: Int) { - val style = when (binding.dialogRadioFolderStyle.checkedRadioButtonId) { - R.id.dialog_radio_folder_square -> FOLDER_STYLE_SQUARE - else -> FOLDER_STYLE_ROUNDED_CORNERS - } + val style = getStyle() val count = when (binding.dialogRadioFolderCountHolder.checkedRadioButtonId) { R.id.dialog_radio_folder_count_line -> FOLDER_MEDIA_CNT_LINE @@ -131,6 +132,25 @@ class ChangeFolderThumbnailStyleDialog(val activity: BaseSimpleActivity, val cal config.folderStyle = style config.showFolderMediaCount = count config.limitFolderTitle = binding.dialogFolderLimitTitle.isChecked + + if (style == FOLDER_STYLE_ROUNDED_CORNERS) { + config.animateGifsInFolders = false + } else { + config.animateGifsInFolders = binding.dialogAnimateGifsInFolders.isChecked + } + callback() } + + private fun getStyle(): Int { + return when (binding.dialogRadioFolderStyle.checkedRadioButtonId) { + R.id.dialog_radio_folder_square -> FOLDER_STYLE_SQUARE + else -> FOLDER_STYLE_ROUNDED_CORNERS + } + } + + private fun updateAnimateGifsCheckbox() { + val style = getStyle() + binding.dialogAnimateGifsInFolders.beVisibleIf(style != FOLDER_STYLE_ROUNDED_CORNERS) + } } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/extensions/Context.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/extensions/Context.kt index 5de9b38f5..9528996b1 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/extensions/Context.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/extensions/Context.kt @@ -6,6 +6,7 @@ import android.content.Context import android.content.Intent import android.database.Cursor import android.graphics.Bitmap +import android.graphics.drawable.Drawable import android.graphics.drawable.PictureDrawable import android.media.AudioManager import android.os.Process @@ -14,12 +15,15 @@ import android.provider.MediaStore.Images import android.widget.ImageView import com.bumptech.glide.Glide import com.bumptech.glide.Priority +import com.bumptech.glide.integration.webp.decoder.WebpDrawable +import com.bumptech.glide.integration.webp.decoder.WebpDrawableTransformation import com.bumptech.glide.load.DataSource import com.bumptech.glide.load.DecodeFormat +import com.bumptech.glide.load.MultiTransformation import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.load.engine.GlideException -import com.bumptech.glide.load.resource.bitmap.BitmapTransitionOptions import com.bumptech.glide.load.resource.bitmap.CenterCrop +import com.bumptech.glide.load.resource.bitmap.FitCenter import com.bumptech.glide.load.resource.bitmap.RoundedCorners import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions import com.bumptech.glide.request.RequestListener @@ -37,7 +41,6 @@ import com.simplemobiletools.gallery.pro.interfaces.* import com.simplemobiletools.gallery.pro.models.* import com.simplemobiletools.gallery.pro.svg.SvgSoftwareLayerSetter import com.squareup.picasso.Picasso -import pl.droidsonroids.gif.GifDrawable import java.io.File import java.io.FileInputStream import java.nio.ByteBuffer @@ -45,6 +48,7 @@ import java.nio.channels.FileChannel import kotlin.collections.set import kotlin.math.max + val Context.audioManager get() = getSystemService(Context.AUDIO_SERVICE) as AudioManager fun Context.getHumanizedFilename(path: String): String { @@ -463,31 +467,11 @@ fun Context.loadImage( roundCorners: Int, signature: ObjectKey, skipMemoryCacheAtPaths: ArrayList? = null ) { target.isHorizontalScrolling = horizontalScroll - if (type == TYPE_IMAGES || type == TYPE_VIDEOS || type == TYPE_RAWS || type == TYPE_PORTRAITS) { - if (type == TYPE_IMAGES && path.isPng()) { - loadPng(path, target, cropThumbnails, roundCorners, signature, skipMemoryCacheAtPaths) - } else { - loadJpg(path, target, cropThumbnails, roundCorners, signature, skipMemoryCacheAtPaths) - } - } else if (type == TYPE_GIFS) { - if (!animateGifs) { - loadStaticGIF(path, target, cropThumbnails, roundCorners, signature, skipMemoryCacheAtPaths) - return - } - - try { - val gifDrawable = GifDrawable(path) - target.setImageDrawable(gifDrawable) - gifDrawable.start() - - target.scaleType = if (cropThumbnails) ImageView.ScaleType.CENTER_CROP else ImageView.ScaleType.FIT_CENTER - } catch (e: Exception) { - loadStaticGIF(path, target, cropThumbnails, roundCorners, signature, skipMemoryCacheAtPaths) - } catch (e: OutOfMemoryError) { - loadStaticGIF(path, target, cropThumbnails, roundCorners, signature, skipMemoryCacheAtPaths) - } - } else if (type == TYPE_SVGS) { + if (type == TYPE_SVGS) { loadSVG(path, target, cropThumbnails, roundCorners, signature) + } else { + val tryLoadingWithPicasso = type == TYPE_IMAGES && path.isPng() + loadImageBase(path, target, cropThumbnails, roundCorners, signature, skipMemoryCacheAtPaths, animateGifs, tryLoadingWithPicasso) } } @@ -512,109 +496,72 @@ fun Context.getPathLocation(path: String): Int { } } -fun Context.loadPng( +fun Context.loadImageBase( path: String, target: MySquareImageView, cropThumbnails: Boolean, roundCorners: Int, signature: ObjectKey, - skipMemoryCacheAtPaths: ArrayList? = null + skipMemoryCacheAtPaths: ArrayList? = null, + animate: Boolean = false, + tryLoadingWithPicasso: Boolean = false, + crossFadeDuration: Int = 300 ) { val options = RequestOptions() .signature(signature) .skipMemoryCache(skipMemoryCacheAtPaths?.contains(path) == true) - .diskCacheStrategy(DiskCacheStrategy.RESOURCE) .priority(Priority.LOW) + .diskCacheStrategy(DiskCacheStrategy.RESOURCE) .format(DecodeFormat.PREFER_ARGB_8888) - if (cropThumbnails) options.centerCrop() else options.fitCenter() + if (cropThumbnails) { + options.optionalTransform(CenterCrop()) + options.optionalTransform(WebpDrawable::class.java, WebpDrawableTransformation(CenterCrop())) + } else { + options.optionalTransform(FitCenter()) + options.optionalTransform(WebpDrawable::class.java, WebpDrawableTransformation(FitCenter())) + } + + // animation is only supported without rounded corners + if (animate && roundCorners == ROUNDED_CORNERS_NONE) { + // this is required to make glide cache aware of changes + options.decode(Drawable::class.java) + } else { + options.dontAnimate() + // don't animate is not enough for webp files, decode as bitmap forces first frame use in animated webps + options.decode(Bitmap::class.java) + } + + if (roundCorners != ROUNDED_CORNERS_NONE) { + val cornerSize = if (roundCorners == ROUNDED_CORNERS_SMALL) com.simplemobiletools.commons.R.dimen.rounded_corner_radius_small else com.simplemobiletools.commons.R.dimen.rounded_corner_radius_big + val cornerRadius = resources.getDimension(cornerSize).toInt() + val roundedCornersTransform = RoundedCorners(cornerRadius) + options.optionalTransform(MultiTransformation(CenterCrop(), roundedCornersTransform)) + options.optionalTransform(WebpDrawable::class.java, MultiTransformation(WebpDrawableTransformation(CenterCrop()), WebpDrawableTransformation(roundedCornersTransform))) + } + var builder = Glide.with(applicationContext) - .asBitmap() .load(path) .apply(options) - .listener(object : RequestListener { - override fun onLoadFailed(e: GlideException?, model: Any?, targetBitmap: Target, isFirstResource: Boolean): Boolean { + .transition(DrawableTransitionOptions.withCrossFade(crossFadeDuration)) + + if (tryLoadingWithPicasso) { + builder = builder.listener(object : RequestListener { + override fun onLoadFailed(e: GlideException?, model: Any?, targetBitmap: Target, isFirstResource: Boolean): Boolean { tryLoadingWithPicasso(path, target, cropThumbnails, roundCorners, signature) return true } override fun onResourceReady( - resource: Bitmap, + resource: Drawable, model: Any, - targetBitmap: Target, + targetBitmap: Target, dataSource: DataSource, isFirstResource: Boolean ): Boolean { return false } }) - - if (roundCorners != ROUNDED_CORNERS_NONE) { - val cornerSize = - if (roundCorners == ROUNDED_CORNERS_SMALL) com.simplemobiletools.commons.R.dimen.rounded_corner_radius_small else com.simplemobiletools.commons.R.dimen.rounded_corner_radius_big - val cornerRadius = resources.getDimension(cornerSize).toInt() - builder = builder.transform(CenterCrop(), RoundedCorners(cornerRadius)) - } - - builder.into(target) -} - -fun Context.loadJpg( - path: String, - target: MySquareImageView, - cropThumbnails: Boolean, - roundCorners: Int, - signature: ObjectKey, - skipMemoryCacheAtPaths: ArrayList? = null -) { - val options = RequestOptions() - .signature(signature) - .skipMemoryCache(skipMemoryCacheAtPaths?.contains(path) == true) - .priority(Priority.LOW) - .diskCacheStrategy(DiskCacheStrategy.RESOURCE) - - if (cropThumbnails) options.centerCrop() else options.fitCenter() - var builder = Glide.with(applicationContext) - .asBitmap() - .load(path) - .apply(options) - .transition(BitmapTransitionOptions.withCrossFade()) - - if (roundCorners != ROUNDED_CORNERS_NONE) { - val cornerSize = - if (roundCorners == ROUNDED_CORNERS_SMALL) com.simplemobiletools.commons.R.dimen.rounded_corner_radius_small else com.simplemobiletools.commons.R.dimen.rounded_corner_radius_big - val cornerRadius = resources.getDimension(cornerSize).toInt() - builder = builder.transform(CenterCrop(), RoundedCorners(cornerRadius)) - } - - builder.into(target) -} - -fun Context.loadStaticGIF( - path: String, - target: MySquareImageView, - cropThumbnails: Boolean, - roundCorners: Int, - signature: ObjectKey, - skipMemoryCacheAtPaths: ArrayList? = null -) { - val options = RequestOptions() - .signature(signature) - .skipMemoryCache(skipMemoryCacheAtPaths?.contains(path) == true) - .priority(Priority.LOW) - .diskCacheStrategy(DiskCacheStrategy.RESOURCE) - - if (cropThumbnails) options.centerCrop() else options.fitCenter() - var builder = Glide.with(applicationContext) - .asBitmap() // make sure the GIF wont animate - .load(path) - .apply(options) - - if (roundCorners != ROUNDED_CORNERS_NONE) { - val cornerSize = - if (roundCorners == ROUNDED_CORNERS_SMALL) com.simplemobiletools.commons.R.dimen.rounded_corner_radius_small else com.simplemobiletools.commons.R.dimen.rounded_corner_radius_big - val cornerRadius = resources.getDimension(cornerSize).toInt() - builder = builder.transform(CenterCrop(), RoundedCorners(cornerRadius)) } builder.into(target) diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/Config.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/Config.kt index b50e69740..a3928f47b 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/Config.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/Config.kt @@ -164,6 +164,10 @@ class Config(context: Context) : BaseConfig(context) { get() = prefs.getBoolean(ANIMATE_GIFS, false) set(animateGifs) = prefs.edit().putBoolean(ANIMATE_GIFS, animateGifs).apply() + var animateGifsInFolders: Boolean + get() = prefs.getBoolean(ANIMATE_GIFS_IN_FOLDERS, false) + set(animateGifsInFolders) = prefs.edit().putBoolean(ANIMATE_GIFS_IN_FOLDERS, animateGifsInFolders).apply() + var maxBrightness: Boolean get() = prefs.getBoolean(MAX_BRIGHTNESS, false) set(maxBrightness) = prefs.edit().putBoolean(MAX_BRIGHTNESS, maxBrightness).apply() diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/Constants.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/Constants.kt index d5af5d1a3..830e861e6 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/Constants.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/Constants.kt @@ -18,6 +18,7 @@ const val REMEMBER_LAST_VIDEO_POSITION = "remember_last_video_position" const val LOOP_VIDEOS = "loop_videos" const val OPEN_VIDEOS_ON_SEPARATE_SCREEN = "open_videos_on_separate_screen" const val ANIMATE_GIFS = "animate_gifs" +const val ANIMATE_GIFS_IN_FOLDERS = "animate_gifs_in_folders" const val MAX_BRIGHTNESS = "max_brightness" const val CROP_THUMBNAILS = "crop_thumbnails" const val SHOW_THUMBNAIL_VIDEO_DURATION = "show_thumbnail_video_duration" diff --git a/app/src/main/res/layout/dialog_change_folder_thumbnail_style.xml b/app/src/main/res/layout/dialog_change_folder_thumbnail_style.xml index e29763f1a..6592ab580 100644 --- a/app/src/main/res/layout/dialog_change_folder_thumbnail_style.xml +++ b/app/src/main/res/layout/dialog_change_folder_thumbnail_style.xml @@ -87,5 +87,13 @@ android:paddingBottom="@dimen/activity_margin" android:text="@string/limit_folder_title" /> + + diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9614c5767..9953c3a37 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -22,6 +22,7 @@ androidImageCropper = "4.5.0" apng = "2.25.0" awebp = "2.25.0" glideCompiler = "4.15.1" +zjupureWebpdecoder = "2.3.4.15.1" gestureviews = "a8e8fa8d27" androidsvgAar = "1.4" imagefilters = "1.0.7" @@ -71,6 +72,7 @@ sdk-panowidget = { module = "com.google.vr:sdk-panowidget", version.ref = "sdkPa apng = { module = "com.github.penfeizhou.android.animation:apng", version.ref = "apng" } awebp = { module = "com.github.penfeizhou.android.animation:awebp", version.ref = "awebp" } glide-compiler = { module = "com.github.bumptech.glide:compiler", version.ref = "glideCompiler" } +zjupure-webpdecoder = { module = "com.github.zjupure:webpdecoder", version.ref = "zjupureWebpdecoder" } picasso = { module = "com.squareup.picasso:picasso", version.ref = "picasso" } [bundles] room = [