From 2d4a728af47898f77579b26530b5519ae5caac42 Mon Sep 17 00:00:00 2001 From: Valere Date: Mon, 6 Jul 2020 09:45:42 +0200 Subject: [PATCH] Gif support --- .../AnimatedImageViewHolder.kt | 68 +++++++++++++++++++ .../AttachmentSourceProvider.kt | 4 +- .../attachment_viewer/AttachmentsAdapter.kt | 17 +++-- ...ewHolder.kt => ZoomableImageViewHolder.kt} | 2 +- .../layout/item_animated_image_attachment.xml | 22 ++++++ .../features/media/RoomAttachmentProvider.kt | 26 +++++-- 6 files changed, 127 insertions(+), 12 deletions(-) create mode 100644 attachment-viewer/src/main/java/im/vector/riotx/attachment_viewer/AnimatedImageViewHolder.kt rename attachment-viewer/src/main/java/im/vector/riotx/attachment_viewer/{ImageViewHolder.kt => ZoomableImageViewHolder.kt} (97%) create mode 100644 attachment-viewer/src/main/res/layout/item_animated_image_attachment.xml diff --git a/attachment-viewer/src/main/java/im/vector/riotx/attachment_viewer/AnimatedImageViewHolder.kt b/attachment-viewer/src/main/java/im/vector/riotx/attachment_viewer/AnimatedImageViewHolder.kt new file mode 100644 index 0000000000..10b3cf8ffc --- /dev/null +++ b/attachment-viewer/src/main/java/im/vector/riotx/attachment_viewer/AnimatedImageViewHolder.kt @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.riotx.attachment_viewer + +import android.graphics.drawable.Animatable +import android.graphics.drawable.Drawable +import android.util.Log +import android.view.View +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.ProgressBar +import androidx.core.view.isVisible +import androidx.core.view.updateLayoutParams +import com.bumptech.glide.request.target.CustomViewTarget +import com.bumptech.glide.request.transition.Transition +import com.github.chrisbanes.photoview.PhotoView + +class AnimatedImageViewHolder constructor(itemView: View) : + BaseViewHolder(itemView) { + + val touchImageView: ImageView = itemView.findViewById(R.id.imageView) + val imageLoaderProgress: ProgressBar = itemView.findViewById(R.id.imageLoaderProgress) + + val customTargetView = object : CustomViewTarget(touchImageView) { + + override fun onResourceLoading(placeholder: Drawable?) { + imageLoaderProgress.isVisible = true + } + + override fun onLoadFailed(errorDrawable: Drawable?) { + imageLoaderProgress.isVisible = false + } + + override fun onResourceCleared(placeholder: Drawable?) { + touchImageView.setImageDrawable(placeholder) + } + + override fun onResourceReady(resource: Drawable, transition: Transition?) { + imageLoaderProgress.isVisible = false + // Glide mess up the view size :/ + touchImageView.updateLayoutParams { + width = LinearLayout.LayoutParams.MATCH_PARENT + height = LinearLayout.LayoutParams.MATCH_PARENT + } + touchImageView.setImageDrawable(resource) + if (resource is Animatable) { + resource.start(); + } + } + } + + override fun bind(attachmentInfo: AttachmentInfo) { + } +} diff --git a/attachment-viewer/src/main/java/im/vector/riotx/attachment_viewer/AttachmentSourceProvider.kt b/attachment-viewer/src/main/java/im/vector/riotx/attachment_viewer/AttachmentSourceProvider.kt index 9fd2902970..f88083f818 100644 --- a/attachment-viewer/src/main/java/im/vector/riotx/attachment_viewer/AttachmentSourceProvider.kt +++ b/attachment-viewer/src/main/java/im/vector/riotx/attachment_viewer/AttachmentSourceProvider.kt @@ -18,6 +18,7 @@ package im.vector.riotx.attachment_viewer sealed class AttachmentInfo { data class Image(val url: String, val data: Any?) : AttachmentInfo() + data class AnimatedImage(val url: String, val data: Any?) : AttachmentInfo() data class Video(val url: String, val data: Any) : AttachmentInfo() data class Audio(val url: String, val data: Any) : AttachmentInfo() data class File(val url: String, val data: Any) : AttachmentInfo() @@ -32,5 +33,6 @@ interface AttachmentSourceProvider { fun getAttachmentInfoAt(position: Int): AttachmentInfo - fun loadImage(holder: ImageViewHolder, info: AttachmentInfo.Image) + fun loadImage(holder: ZoomableImageViewHolder, info: AttachmentInfo.Image) + fun loadImage(holder: AnimatedImageViewHolder, info: AttachmentInfo.AnimatedImage) } diff --git a/attachment-viewer/src/main/java/im/vector/riotx/attachment_viewer/AttachmentsAdapter.kt b/attachment-viewer/src/main/java/im/vector/riotx/attachment_viewer/AttachmentsAdapter.kt index b9914e4dda..f762a6ea3e 100644 --- a/attachment-viewer/src/main/java/im/vector/riotx/attachment_viewer/AttachmentsAdapter.kt +++ b/attachment-viewer/src/main/java/im/vector/riotx/attachment_viewer/AttachmentsAdapter.kt @@ -60,7 +60,8 @@ class AttachmentsAdapter() : RecyclerView.Adapter() { val inflater = LayoutInflater.from(parent.context) val itemView = inflater.inflate(viewType, parent, false) return when (viewType) { - R.layout.item_image_attachment -> ImageViewHolder(itemView) + R.layout.item_image_attachment -> ZoomableImageViewHolder(itemView) + R.layout.item_animated_image_attachment -> AnimatedImageViewHolder(itemView) else -> AttachmentViewHolder(itemView) } } @@ -70,6 +71,7 @@ class AttachmentsAdapter() : RecyclerView.Adapter() { return when (info) { is AttachmentInfo.Image -> R.layout.item_image_attachment is AttachmentInfo.Video -> R.layout.item_video_attachment + is AttachmentInfo.AnimatedImage -> R.layout.item_animated_image_attachment is AttachmentInfo.Audio -> TODO() is AttachmentInfo.File -> TODO() } @@ -83,15 +85,22 @@ class AttachmentsAdapter() : RecyclerView.Adapter() { override fun onBindViewHolder(holder: BaseViewHolder, position: Int) { attachmentSourceProvider?.getAttachmentInfoAt(position)?.let { holder.bind(it) - if (it is AttachmentInfo.Image) { - attachmentSourceProvider?.loadImage(holder as ImageViewHolder, it) + when(it) { + is AttachmentInfo.Image -> { + attachmentSourceProvider?.loadImage(holder as ZoomableImageViewHolder, it) + } + is AttachmentInfo.AnimatedImage -> { + attachmentSourceProvider?.loadImage(holder as AnimatedImageViewHolder, it) + } + else -> {} } + } } fun isScaled(position: Int): Boolean { val holder = recyclerView?.findViewHolderForAdapterPosition(position) - if (holder is ImageViewHolder) { + if (holder is ZoomableImageViewHolder) { return holder.touchImageView.attacher.scale > 1f } return false diff --git a/attachment-viewer/src/main/java/im/vector/riotx/attachment_viewer/ImageViewHolder.kt b/attachment-viewer/src/main/java/im/vector/riotx/attachment_viewer/ZoomableImageViewHolder.kt similarity index 97% rename from attachment-viewer/src/main/java/im/vector/riotx/attachment_viewer/ImageViewHolder.kt rename to attachment-viewer/src/main/java/im/vector/riotx/attachment_viewer/ZoomableImageViewHolder.kt index cac6a4fd9e..6dd387b870 100644 --- a/attachment-viewer/src/main/java/im/vector/riotx/attachment_viewer/ImageViewHolder.kt +++ b/attachment-viewer/src/main/java/im/vector/riotx/attachment_viewer/ZoomableImageViewHolder.kt @@ -27,7 +27,7 @@ import com.bumptech.glide.request.target.CustomViewTarget import com.bumptech.glide.request.transition.Transition import com.github.chrisbanes.photoview.PhotoView -class ImageViewHolder constructor(itemView: View) : +class ZoomableImageViewHolder constructor(itemView: View) : BaseViewHolder(itemView) { val touchImageView: PhotoView = itemView.findViewById(R.id.touchImageView) diff --git a/attachment-viewer/src/main/res/layout/item_animated_image_attachment.xml b/attachment-viewer/src/main/res/layout/item_animated_image_attachment.xml new file mode 100644 index 0000000000..1096267124 --- /dev/null +++ b/attachment-viewer/src/main/res/layout/item_animated_image_attachment.xml @@ -0,0 +1,22 @@ + + + + + + + + \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotx/features/media/RoomAttachmentProvider.kt b/vector/src/main/java/im/vector/riotx/features/media/RoomAttachmentProvider.kt index 991ecaafde..079c435001 100644 --- a/vector/src/main/java/im/vector/riotx/features/media/RoomAttachmentProvider.kt +++ b/vector/src/main/java/im/vector/riotx/features/media/RoomAttachmentProvider.kt @@ -24,9 +24,10 @@ import im.vector.matrix.android.api.session.room.model.message.MessageWithAttach import im.vector.matrix.android.api.session.room.model.message.getFileUrl import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.matrix.android.internal.crypto.attachments.toElementToDecrypt +import im.vector.riotx.attachment_viewer.AnimatedImageViewHolder import im.vector.riotx.attachment_viewer.AttachmentInfo import im.vector.riotx.attachment_viewer.AttachmentSourceProvider -import im.vector.riotx.attachment_viewer.ImageViewHolder +import im.vector.riotx.attachment_viewer.ZoomableImageViewHolder import javax.inject.Inject class RoomAttachmentProvider( @@ -53,14 +54,27 @@ class RoomAttachmentProvider( width = null, height = null ) - AttachmentInfo.Image( - content?.url ?: "", - data - ) + if (content?.mimeType == "image/gif") { + AttachmentInfo.AnimatedImage( + content.url ?: "", + data + ) + } else { + AttachmentInfo.Image( + content?.url ?: "", + data + ) + } } } - override fun loadImage(holder: ImageViewHolder, info: AttachmentInfo.Image) { + override fun loadImage(holder: ZoomableImageViewHolder, info: AttachmentInfo.Image) { + (info.data as? ImageContentRenderer.Data)?.let { + imageContentRenderer.render(it, holder.touchImageView, holder.customTargetView as CustomViewTarget<*, Drawable>) + } + } + + override fun loadImage(holder: AnimatedImageViewHolder, info: AttachmentInfo.AnimatedImage) { (info.data as? ImageContentRenderer.Data)?.let { imageContentRenderer.render(it, holder.touchImageView, holder.customTargetView as CustomViewTarget<*, Drawable>) }