From aa3e68f3fd433099e10c1ef8f4818e3ac48ba9b6 Mon Sep 17 00:00:00 2001 From: Valere Date: Thu, 9 Jul 2020 10:08:55 +0200 Subject: [PATCH] Refactoring Remove glide dependency + protect against cell reuse bugs --- attachment-viewer/build.gradle | 2 - .../AnimatedImageViewHolder.kt | 38 +------ .../AttachmentSourceProvider.kt | 25 ++--- .../attachmentviewer/AttachmentsAdapter.kt | 75 ++++--------- .../attachmentviewer/ImageLoaderTarget.kt | 103 ++++++++++++++++++ .../attachmentviewer/VideoLoaderTarget.kt | 76 +++++++++++++ .../riotx/attachmentviewer/VideoViewHolder.kt | 33 +----- .../ZoomableImageViewHolder.kt | 34 +----- .../features/media/RoomAttachmentProvider.kt | 82 +++++++++----- 9 files changed, 279 insertions(+), 189 deletions(-) create mode 100644 attachment-viewer/src/main/java/im/vector/riotx/attachmentviewer/ImageLoaderTarget.kt create mode 100644 attachment-viewer/src/main/java/im/vector/riotx/attachmentviewer/VideoLoaderTarget.kt diff --git a/attachment-viewer/build.gradle b/attachment-viewer/build.gradle index 6b64e661fa..3a5c3298d4 100644 --- a/attachment-viewer/build.gradle +++ b/attachment-viewer/build.gradle @@ -58,9 +58,7 @@ android { } dependencies { -// implementation 'com.github.MikeOrtiz:TouchImageView:3.0.2' implementation 'com.github.chrisbanes:PhotoView:2.0.0' - implementation "com.github.bumptech.glide:glide:4.10.0" implementation 'io.reactivex.rxjava2:rxkotlin:2.3.0' implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' diff --git a/attachment-viewer/src/main/java/im/vector/riotx/attachmentviewer/AnimatedImageViewHolder.kt b/attachment-viewer/src/main/java/im/vector/riotx/attachmentviewer/AnimatedImageViewHolder.kt index 9f512e78be..f00a4eff30 100644 --- a/attachment-viewer/src/main/java/im/vector/riotx/attachmentviewer/AnimatedImageViewHolder.kt +++ b/attachment-viewer/src/main/java/im/vector/riotx/attachmentviewer/AnimatedImageViewHolder.kt @@ -16,16 +16,9 @@ package im.vector.riotx.attachmentviewer -import android.graphics.drawable.Animatable -import android.graphics.drawable.Drawable 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 class AnimatedImageViewHolder constructor(itemView: View) : BaseViewHolder(itemView) { @@ -33,34 +26,5 @@ class AnimatedImageViewHolder constructor(itemView: View) : 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) { - } + internal val target = DefaultImageLoaderTarget(this, this.touchImageView) } diff --git a/attachment-viewer/src/main/java/im/vector/riotx/attachmentviewer/AttachmentSourceProvider.kt b/attachment-viewer/src/main/java/im/vector/riotx/attachmentviewer/AttachmentSourceProvider.kt index 930fc62658..ce725afec2 100644 --- a/attachment-viewer/src/main/java/im/vector/riotx/attachmentviewer/AttachmentSourceProvider.kt +++ b/attachment-viewer/src/main/java/im/vector/riotx/attachmentviewer/AttachmentSourceProvider.kt @@ -19,15 +19,12 @@ package im.vector.riotx.attachmentviewer import android.content.Context import android.view.View -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, val thumbnail: Image?) : AttachmentInfo() - data class Audio(val url: String, val data: Any) : AttachmentInfo() - data class File(val url: String, val data: Any) : AttachmentInfo() - - fun bind() { - } +sealed class AttachmentInfo(open val uid: String) { + data class Image(override val uid: String, val url: String, val data: Any?) : AttachmentInfo(uid) + data class AnimatedImage(override val uid: String, val url: String, val data: Any?) : AttachmentInfo(uid) + data class Video(override val uid: String, val url: String, val data: Any, val thumbnail: Image?) : AttachmentInfo(uid) + data class Audio(override val uid: String, val url: String, val data: Any) : AttachmentInfo(uid) + data class File(override val uid: String, val url: String, val data: Any) : AttachmentInfo(uid) } interface AttachmentSourceProvider { @@ -36,11 +33,13 @@ interface AttachmentSourceProvider { fun getAttachmentInfoAt(position: Int): AttachmentInfo - fun loadImage(holder: ZoomableImageViewHolder, info: AttachmentInfo.Image) + fun loadImage(target: ImageLoaderTarget, info: AttachmentInfo.Image) - fun loadImage(holder: AnimatedImageViewHolder, info: AttachmentInfo.AnimatedImage) + fun loadImage(target: ImageLoaderTarget, info: AttachmentInfo.AnimatedImage) - fun loadVideo(holder: VideoViewHolder, info: AttachmentInfo.Video) + fun loadVideo(target: VideoLoaderTarget, info: AttachmentInfo.Video) - fun overlayViewAtPosition(context: Context, position: Int) : View? + fun overlayViewAtPosition(context: Context, position: Int): View? + + fun clear(id: String) } diff --git a/attachment-viewer/src/main/java/im/vector/riotx/attachmentviewer/AttachmentsAdapter.kt b/attachment-viewer/src/main/java/im/vector/riotx/attachmentviewer/AttachmentsAdapter.kt index b0cb5193e8..2f453b58a8 100644 --- a/attachment-viewer/src/main/java/im/vector/riotx/attachmentviewer/AttachmentsAdapter.kt +++ b/attachment-viewer/src/main/java/im/vector/riotx/attachmentviewer/AttachmentsAdapter.kt @@ -24,8 +24,10 @@ import androidx.recyclerview.widget.RecyclerView abstract class BaseViewHolder constructor(itemView: View) : RecyclerView.ViewHolder(itemView) { - open fun bind(attachmentInfo: AttachmentInfo) {} - open fun onRecycled() {} + open fun onRecycled() { + boundResourceUid = null + } + open fun onAttached() {} open fun onDetached() {} open fun entersBackground() {} @@ -33,16 +35,17 @@ abstract class BaseViewHolder constructor(itemView: View) : open fun onSelected(selected: Boolean) {} open fun handleCommand(commands: AttachmentCommands) {} -} -class AttachmentViewHolder constructor(itemView: View) : - BaseViewHolder(itemView) { + var boundResourceUid: String? = null - override fun bind(attachmentInfo: AttachmentInfo) { + open fun bind(attachmentInfo: AttachmentInfo) { + boundResourceUid = attachmentInfo.uid } } -// class AttachmentsAdapter(fragmentManager: FragmentManager, lifecycle: Lifecycle) : FragmentStateAdapter(fragmentManager, lifecycle) { +class AttachmentViewHolder constructor(itemView: View) : + BaseViewHolder(itemView) + class AttachmentsAdapter() : RecyclerView.Adapter() { var attachmentSourceProvider: AttachmentSourceProvider? = null @@ -65,21 +68,21 @@ 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 -> ZoomableImageViewHolder(itemView) + R.layout.item_image_attachment -> ZoomableImageViewHolder(itemView) R.layout.item_animated_image_attachment -> AnimatedImageViewHolder(itemView) - R.layout.item_video_attachment -> VideoViewHolder(itemView) - else -> AttachmentViewHolder(itemView) + R.layout.item_video_attachment -> VideoViewHolder(itemView) + else -> AttachmentViewHolder(itemView) } } override fun getItemViewType(position: Int): Int { val info = attachmentSourceProvider!!.getAttachmentInfoAt(position) return when (info) { - is AttachmentInfo.Image -> R.layout.item_image_attachment - is AttachmentInfo.Video -> R.layout.item_video_attachment + 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() + is AttachmentInfo.Audio -> TODO() + is AttachmentInfo.File -> TODO() } } @@ -91,16 +94,17 @@ class AttachmentsAdapter() : RecyclerView.Adapter() { attachmentSourceProvider?.getAttachmentInfoAt(position)?.let { holder.bind(it) when (it) { - is AttachmentInfo.Image -> { - attachmentSourceProvider?.loadImage(holder as ZoomableImageViewHolder, it) + is AttachmentInfo.Image -> { + attachmentSourceProvider?.loadImage((holder as ZoomableImageViewHolder).target, it) } is AttachmentInfo.AnimatedImage -> { - attachmentSourceProvider?.loadImage(holder as AnimatedImageViewHolder, it) + attachmentSourceProvider?.loadImage((holder as AnimatedImageViewHolder).target, it) } - is AttachmentInfo.Video -> { - attachmentSourceProvider?.loadVideo(holder as VideoViewHolder, it) + is AttachmentInfo.Video -> { + attachmentSourceProvider?.loadVideo((holder as VideoViewHolder).target, it) + } + else -> { } - else -> {} } } } @@ -134,35 +138,4 @@ class AttachmentsAdapter() : RecyclerView.Adapter() { val holder = recyclerView?.findViewHolderForAdapterPosition(position) as? BaseViewHolder holder?.entersForeground() } -// override fun getItemCount(): Int { -// return 8 -// } -// -// override fun createFragment(position: Int): Fragment { -// // Return a NEW fragment instance in createFragment(int) -// val fragment = DemoObjectFragment() -// fragment.arguments = Bundle().apply { -// // Our object is just an integer :-P -// putInt(ARG_OBJECT, position + 1) -// } -// return fragment -// } } - -// private const val ARG_OBJECT = "object" -// -// // Instances of this class are fragments representing a single -// // object in our collection. -// class DemoObjectFragment : Fragment() { -// -// override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { -// return inflater.inflate(R.layout.view_image_attachment, container, false) -// } -// -// override fun onViewCreated(view: View, savedInstanceState: Bundle?) { -// arguments?.takeIf { it.containsKey(ARG_OBJECT) }?.apply { -// val textView: TextView = view.findViewById(R.id.testPage) -// textView.text = getInt(ARG_OBJECT).toString() -// } -// } -// } diff --git a/attachment-viewer/src/main/java/im/vector/riotx/attachmentviewer/ImageLoaderTarget.kt b/attachment-viewer/src/main/java/im/vector/riotx/attachmentviewer/ImageLoaderTarget.kt new file mode 100644 index 0000000000..bb59c9e01e --- /dev/null +++ b/attachment-viewer/src/main/java/im/vector/riotx/attachmentviewer/ImageLoaderTarget.kt @@ -0,0 +1,103 @@ +/* + * 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.attachmentviewer + +import android.graphics.drawable.Animatable +import android.graphics.drawable.Drawable +import android.widget.ImageView +import android.widget.LinearLayout +import androidx.core.view.isVisible +import androidx.core.view.updateLayoutParams + +interface ImageLoaderTarget { + + fun contextView(): ImageView + + fun onResourceLoading(uid: String, placeholder: Drawable?) + + fun onLoadFailed(uid: String, errorDrawable: Drawable?) + + fun onResourceCleared(uid: String, placeholder: Drawable?) + + fun onResourceReady(uid: String, resource: Drawable) +} + +internal class DefaultImageLoaderTarget(val holder: AnimatedImageViewHolder, private val contextView: ImageView) + : ImageLoaderTarget { + override fun contextView(): ImageView { + return contextView + } + + override fun onResourceLoading(uid: String, placeholder: Drawable?) { + if (holder.boundResourceUid != uid) return + holder.imageLoaderProgress.isVisible = true + } + + override fun onLoadFailed(uid: String, errorDrawable: Drawable?) { + if (holder.boundResourceUid != uid) return + holder.imageLoaderProgress.isVisible = false + } + + override fun onResourceCleared(uid: String, placeholder: Drawable?) { + if (holder.boundResourceUid != uid) return + holder.touchImageView.setImageDrawable(placeholder) + } + + override fun onResourceReady(uid: String, resource: Drawable) { + if (holder.boundResourceUid != uid) return + holder.imageLoaderProgress.isVisible = false + // Glide mess up the view size :/ + holder.touchImageView.updateLayoutParams { + width = LinearLayout.LayoutParams.MATCH_PARENT + height = LinearLayout.LayoutParams.MATCH_PARENT + } + holder.touchImageView.setImageDrawable(resource) + if (resource is Animatable) { + resource.start() + } + } + + internal class ZoomableImageTarget(val holder: ZoomableImageViewHolder, private val contextView: ImageView) : ImageLoaderTarget { + override fun contextView() = contextView + + override fun onResourceLoading(uid: String, placeholder: Drawable?) { + if (holder.boundResourceUid != uid) return + holder.imageLoaderProgress.isVisible = true + } + + override fun onLoadFailed(uid: String, errorDrawable: Drawable?) { + if (holder.boundResourceUid != uid) return + holder.imageLoaderProgress.isVisible = false + } + + override fun onResourceCleared(uid: String, placeholder: Drawable?) { + if (holder.boundResourceUid != uid) return + holder.touchImageView.setImageDrawable(placeholder) + } + + override fun onResourceReady(uid: String, resource: Drawable) { + if (holder.boundResourceUid != uid) return + holder.imageLoaderProgress.isVisible = false + // Glide mess up the view size :/ + holder.touchImageView.updateLayoutParams { + width = LinearLayout.LayoutParams.MATCH_PARENT + height = LinearLayout.LayoutParams.MATCH_PARENT + } + holder.touchImageView.setImageDrawable(resource) + } + } +} diff --git a/attachment-viewer/src/main/java/im/vector/riotx/attachmentviewer/VideoLoaderTarget.kt b/attachment-viewer/src/main/java/im/vector/riotx/attachmentviewer/VideoLoaderTarget.kt new file mode 100644 index 0000000000..548c6431e5 --- /dev/null +++ b/attachment-viewer/src/main/java/im/vector/riotx/attachmentviewer/VideoLoaderTarget.kt @@ -0,0 +1,76 @@ +/* + * 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.attachmentviewer + +import android.graphics.drawable.Drawable +import android.widget.ImageView +import androidx.core.view.isVisible +import java.io.File + +interface VideoLoaderTarget { + fun contextView(): ImageView + + fun onThumbnailResourceLoading(uid: String, placeholder: Drawable?) + + fun onThumbnailLoadFailed(uid: String, errorDrawable: Drawable?) + + fun onThumbnailResourceCleared(uid: String, placeholder: Drawable?) + + fun onThumbnailResourceReady(uid: String, resource: Drawable) + + fun onVideoFileLoading(uid: String) + fun onVideoFileLoadFailed(uid: String) + fun onVideoFileReady(uid: String, file: File) +} + +internal class DefaultVideoLoaderTarget(val holder: VideoViewHolder, private val contextView: ImageView) : VideoLoaderTarget { + override fun contextView(): ImageView = contextView + + override fun onThumbnailResourceLoading(uid: String, placeholder: Drawable?) { + } + + override fun onThumbnailLoadFailed(uid: String, errorDrawable: Drawable?) { + } + + override fun onThumbnailResourceCleared(uid: String, placeholder: Drawable?) { + } + + override fun onThumbnailResourceReady(uid: String, resource: Drawable) { + if (holder.boundResourceUid != uid) return + holder.thumbnailImage.setImageDrawable(resource) + } + + override fun onVideoFileLoading(uid: String) { + if (holder.boundResourceUid != uid) return + holder.thumbnailImage.isVisible = true + holder.loaderProgressBar.isVisible = true + holder.videoView.isVisible = false + } + + override fun onVideoFileLoadFailed(uid: String) { + if (holder.boundResourceUid != uid) return + holder.videoFileLoadError() + } + + override fun onVideoFileReady(uid: String, file: File) { + if (holder.boundResourceUid != uid) return + holder.thumbnailImage.isVisible = false + holder.loaderProgressBar.isVisible = false + holder.videoView.isVisible = true + holder.videoReady(file) + } +} diff --git a/attachment-viewer/src/main/java/im/vector/riotx/attachmentviewer/VideoViewHolder.kt b/attachment-viewer/src/main/java/im/vector/riotx/attachmentviewer/VideoViewHolder.kt index 5718147bab..2b417baecc 100644 --- a/attachment-viewer/src/main/java/im/vector/riotx/attachmentviewer/VideoViewHolder.kt +++ b/attachment-viewer/src/main/java/im/vector/riotx/attachmentviewer/VideoViewHolder.kt @@ -44,38 +44,13 @@ class VideoViewHolder constructor(itemView: View) : var eventListener: WeakReference? = null -// interface Target { -// fun onResourceLoading(progress: Int, total: Int) -// fun onLoadFailed() -// fun onResourceReady(file: File) -// fun onThumbnailReady(thumbnail: Drawable?) -// } - - init { - } - val thumbnailImage: ImageView = itemView.findViewById(R.id.videoThumbnailImage) val videoView: VideoView = itemView.findViewById(R.id.videoView) val loaderProgressBar: ProgressBar = itemView.findViewById(R.id.videoLoaderProgress) val videoControlIcon: ImageView = itemView.findViewById(R.id.videoControlIcon) val errorTextView: TextView = itemView.findViewById(R.id.videoMediaViewerErrorView) -// val videoTarget = object : Target { -// override fun onResourceLoading(progress: Int, total: Int) { -// videoView.isVisible = false -// loaderProgressBar.isVisible = true -// } -// -// override fun onLoadFailed() { -// loaderProgressBar.isVisible = false -// } -// -// override fun onResourceReady(file: File) { -// } -// -// override fun onThumbnailReady(thumbnail: Drawable?) { -// } -// } + internal val target = DefaultVideoLoaderTarget(this, thumbnailImage) override fun onRecycled() { super.onRecycled() @@ -91,6 +66,9 @@ class VideoViewHolder constructor(itemView: View) : } } + fun videoFileLoadError() { + } + override fun entersBackground() { if (videoView.isPlaying) { progress = videoView.currentPosition @@ -162,7 +140,7 @@ class VideoViewHolder constructor(itemView: View) : wasPaused = true videoView.pause() } - is AttachmentCommands.SeekTo -> { + is AttachmentCommands.SeekTo -> { val duration = videoView.duration if (duration > 0) { val seekDuration = duration * (commands.percentProgress / 100f) @@ -173,6 +151,7 @@ class VideoViewHolder constructor(itemView: View) : } override fun bind(attachmentInfo: AttachmentInfo) { + super.bind(attachmentInfo) progress = 0 wasPaused = false } diff --git a/attachment-viewer/src/main/java/im/vector/riotx/attachmentviewer/ZoomableImageViewHolder.kt b/attachment-viewer/src/main/java/im/vector/riotx/attachmentviewer/ZoomableImageViewHolder.kt index 00a8ad275a..aeaf612bbc 100644 --- a/attachment-viewer/src/main/java/im/vector/riotx/attachmentviewer/ZoomableImageViewHolder.kt +++ b/attachment-viewer/src/main/java/im/vector/riotx/attachmentviewer/ZoomableImageViewHolder.kt @@ -16,15 +16,9 @@ package im.vector.riotx.attachmentviewer -import android.graphics.drawable.Drawable import android.util.Log import android.view.View -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 ZoomableImageViewHolder constructor(itemView: View) : @@ -45,31 +39,5 @@ class ZoomableImageViewHolder constructor(itemView: View) : touchImageView.setAllowParentInterceptOnEdge(true) } - 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) - } - } - - override fun bind(attachmentInfo: AttachmentInfo) { - } + internal val target = DefaultImageLoaderTarget.ZoomableImageTarget(this, touchImageView) } 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 4e30e0179a..f7299bf714 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 @@ -35,11 +35,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.attachmentviewer.AnimatedImageViewHolder import im.vector.riotx.attachmentviewer.AttachmentInfo import im.vector.riotx.attachmentviewer.AttachmentSourceProvider -import im.vector.riotx.attachmentviewer.VideoViewHolder -import im.vector.riotx.attachmentviewer.ZoomableImageViewHolder +import im.vector.riotx.attachmentviewer.ImageLoaderTarget +import im.vector.riotx.attachmentviewer.VideoLoaderTarget import im.vector.riotx.core.date.VectorDateFormatter import im.vector.riotx.core.extensions.localDateTime import java.io.File @@ -86,13 +85,15 @@ class RoomAttachmentProvider( ) if (content.mimeType == "image/gif") { AttachmentInfo.AnimatedImage( - content.url ?: "", - data + uid = it.eventId, + url = content.url ?: "", + data = data ) } else { AttachmentInfo.Image( - content.url ?: "", - data + uid = it.eventId, + url = content.url ?: "", + data = data ) } } else if (content is MessageVideoContent) { @@ -117,9 +118,11 @@ class RoomAttachmentProvider( thumbnailMediaData = thumbnailData ) AttachmentInfo.Video( - content.getFileUrl() ?: "", - data, - AttachmentInfo.Image( + uid = it.eventId, + url = content.getFileUrl() ?: "", + data = data, + thumbnail = AttachmentInfo.Image( + uid = it.eventId, url = content.videoInfo?.thumbnailFile?.url ?: content.videoInfo?.thumbnailUrl ?: "", data = thumbnailData @@ -128,49 +131,72 @@ class RoomAttachmentProvider( ) } else { AttachmentInfo.Image( - "", - null + uid = it.eventId, + url = "", + data = null ) } } } - override fun loadImage(holder: ZoomableImageViewHolder, info: AttachmentInfo.Image) { + override fun loadImage(target: ImageLoaderTarget, info: AttachmentInfo.Image) { (info.data as? ImageContentRenderer.Data)?.let { - imageContentRenderer.render(it, holder.touchImageView, holder.customTargetView as CustomViewTarget<*, Drawable>) + imageContentRenderer.render(it, target.contextView(), object : CustomViewTarget(target.contextView()) { + override fun onLoadFailed(errorDrawable: Drawable?) { + target.onLoadFailed(info.uid, errorDrawable) + } + + override fun onResourceCleared(placeholder: Drawable?) { + target.onResourceCleared(info.uid, placeholder) + } + + override fun onResourceReady(resource: Drawable, transition: Transition?) { + target.onResourceReady(info.uid, resource) + } + }) } } - override fun loadImage(holder: AnimatedImageViewHolder, info: AttachmentInfo.AnimatedImage) { + override fun loadImage(target: ImageLoaderTarget, info: AttachmentInfo.AnimatedImage) { (info.data as? ImageContentRenderer.Data)?.let { - imageContentRenderer.render(it, holder.touchImageView, holder.customTargetView as CustomViewTarget<*, Drawable>) + imageContentRenderer.render(it, target.contextView(), object : CustomViewTarget(target.contextView()) { + override fun onLoadFailed(errorDrawable: Drawable?) { + target.onLoadFailed(info.uid, errorDrawable) + } + + override fun onResourceCleared(placeholder: Drawable?) { + target.onResourceCleared(info.uid, placeholder) + } + + override fun onResourceReady(resource: Drawable, transition: Transition?) { + target.onResourceReady(info.uid, resource) + } + }) } } - override fun loadVideo(holder: VideoViewHolder, info: AttachmentInfo.Video) { + override fun loadVideo(target: VideoLoaderTarget, info: AttachmentInfo.Video) { val data = info.data as? VideoContentRenderer.Data ?: return // videoContentRenderer.render(data, // holder.thumbnailImage, // holder.loaderProgressBar, // holder.videoView, // holder.errorTextView) - imageContentRenderer.render(data.thumbnailMediaData, holder.thumbnailImage, object : CustomViewTarget(holder.thumbnailImage) { + imageContentRenderer.render(data.thumbnailMediaData, target.contextView(), object : CustomViewTarget(target.contextView()) { override fun onLoadFailed(errorDrawable: Drawable?) { - holder.thumbnailImage.setImageDrawable(errorDrawable) + target.onThumbnailLoadFailed(info.uid, errorDrawable) } override fun onResourceCleared(placeholder: Drawable?) { + target.onThumbnailResourceCleared(info.uid, placeholder) } override fun onResourceReady(resource: Drawable, transition: Transition?) { - holder.thumbnailImage.setImageDrawable(resource) + target.onThumbnailResourceReady(info.uid, resource) } }) - holder.thumbnailImage.isVisible = false - holder.loaderProgressBar.isVisible = false - holder.videoView.isVisible = false - + target.onVideoFileLoading(info.uid) fileService.downloadFile( downloadMode = FileService.DownloadMode.FOR_INTERNAL_USE, id = data.eventId, @@ -180,11 +206,11 @@ class RoomAttachmentProvider( url = data.url, callback = object : MatrixCallback { override fun onSuccess(data: File) { - holder.videoReady(data) + target.onVideoFileReady(info.uid, data) } override fun onFailure(failure: Throwable) { - holder.videoView.isVisible = false + target.onVideoFileLoadFailed(info.uid) } } ) @@ -214,6 +240,10 @@ class RoomAttachmentProvider( overlayView?.videoControlsGroup?.isVisible = item.root.isVideoMessage() return overlayView } + + override fun clear(id: String) { + // TODO("Not yet implemented") + } } class RoomAttachmentProviderFactory @Inject constructor(