Refactoring

Remove glide dependency + protect against cell reuse bugs
This commit is contained in:
Valere 2020-07-09 10:08:55 +02:00
parent bf2d937ad6
commit aa3e68f3fd
9 changed files with 279 additions and 189 deletions

View file

@ -58,9 +58,7 @@ android {
} }
dependencies { dependencies {
// implementation 'com.github.MikeOrtiz:TouchImageView:3.0.2'
implementation 'com.github.chrisbanes:PhotoView:2.0.0' 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:rxkotlin:2.3.0'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'

View file

@ -16,16 +16,9 @@
package im.vector.riotx.attachmentviewer package im.vector.riotx.attachmentviewer
import android.graphics.drawable.Animatable
import android.graphics.drawable.Drawable
import android.view.View import android.view.View
import android.widget.ImageView import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.ProgressBar 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) : class AnimatedImageViewHolder constructor(itemView: View) :
BaseViewHolder(itemView) { BaseViewHolder(itemView) {
@ -33,34 +26,5 @@ class AnimatedImageViewHolder constructor(itemView: View) :
val touchImageView: ImageView = itemView.findViewById(R.id.imageView) val touchImageView: ImageView = itemView.findViewById(R.id.imageView)
val imageLoaderProgress: ProgressBar = itemView.findViewById(R.id.imageLoaderProgress) val imageLoaderProgress: ProgressBar = itemView.findViewById(R.id.imageLoaderProgress)
val customTargetView = object : CustomViewTarget<ImageView, Drawable>(touchImageView) { internal val target = DefaultImageLoaderTarget(this, this.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<in Drawable>?) {
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) {
}
} }

View file

@ -19,15 +19,12 @@ package im.vector.riotx.attachmentviewer
import android.content.Context import android.content.Context
import android.view.View import android.view.View
sealed class AttachmentInfo { sealed class AttachmentInfo(open val uid: String) {
data class Image(val url: String, val data: Any?) : AttachmentInfo() data class Image(override val uid: String, val url: String, val data: Any?) : AttachmentInfo(uid)
data class AnimatedImage(val url: String, val data: Any?) : AttachmentInfo() data class AnimatedImage(override val uid: String, val url: String, val data: Any?) : AttachmentInfo(uid)
data class Video(val url: String, val data: Any, val thumbnail: Image?) : AttachmentInfo() data class Video(override val uid: String, val url: String, val data: Any, val thumbnail: Image?) : AttachmentInfo(uid)
data class Audio(val url: String, val data: Any) : AttachmentInfo() data class Audio(override val uid: String, val url: String, val data: Any) : AttachmentInfo(uid)
data class File(val url: String, val data: Any) : AttachmentInfo() data class File(override val uid: String, val url: String, val data: Any) : AttachmentInfo(uid)
fun bind() {
}
} }
interface AttachmentSourceProvider { interface AttachmentSourceProvider {
@ -36,11 +33,13 @@ interface AttachmentSourceProvider {
fun getAttachmentInfoAt(position: Int): AttachmentInfo 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)
} }

View file

@ -24,8 +24,10 @@ import androidx.recyclerview.widget.RecyclerView
abstract class BaseViewHolder constructor(itemView: View) : abstract class BaseViewHolder constructor(itemView: View) :
RecyclerView.ViewHolder(itemView) { RecyclerView.ViewHolder(itemView) {
open fun bind(attachmentInfo: AttachmentInfo) {} open fun onRecycled() {
open fun onRecycled() {} boundResourceUid = null
}
open fun onAttached() {} open fun onAttached() {}
open fun onDetached() {} open fun onDetached() {}
open fun entersBackground() {} open fun entersBackground() {}
@ -33,16 +35,17 @@ abstract class BaseViewHolder constructor(itemView: View) :
open fun onSelected(selected: Boolean) {} open fun onSelected(selected: Boolean) {}
open fun handleCommand(commands: AttachmentCommands) {} open fun handleCommand(commands: AttachmentCommands) {}
}
class AttachmentViewHolder constructor(itemView: View) : var boundResourceUid: String? = null
BaseViewHolder(itemView) {
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<BaseViewHolder>() { class AttachmentsAdapter() : RecyclerView.Adapter<BaseViewHolder>() {
var attachmentSourceProvider: AttachmentSourceProvider? = null var attachmentSourceProvider: AttachmentSourceProvider? = null
@ -65,21 +68,21 @@ class AttachmentsAdapter() : RecyclerView.Adapter<BaseViewHolder>() {
val inflater = LayoutInflater.from(parent.context) val inflater = LayoutInflater.from(parent.context)
val itemView = inflater.inflate(viewType, parent, false) val itemView = inflater.inflate(viewType, parent, false)
return when (viewType) { 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_animated_image_attachment -> AnimatedImageViewHolder(itemView)
R.layout.item_video_attachment -> VideoViewHolder(itemView) R.layout.item_video_attachment -> VideoViewHolder(itemView)
else -> AttachmentViewHolder(itemView) else -> AttachmentViewHolder(itemView)
} }
} }
override fun getItemViewType(position: Int): Int { override fun getItemViewType(position: Int): Int {
val info = attachmentSourceProvider!!.getAttachmentInfoAt(position) val info = attachmentSourceProvider!!.getAttachmentInfoAt(position)
return when (info) { return when (info) {
is AttachmentInfo.Image -> R.layout.item_image_attachment is AttachmentInfo.Image -> R.layout.item_image_attachment
is AttachmentInfo.Video -> R.layout.item_video_attachment is AttachmentInfo.Video -> R.layout.item_video_attachment
is AttachmentInfo.AnimatedImage -> R.layout.item_animated_image_attachment is AttachmentInfo.AnimatedImage -> R.layout.item_animated_image_attachment
is AttachmentInfo.Audio -> TODO() is AttachmentInfo.Audio -> TODO()
is AttachmentInfo.File -> TODO() is AttachmentInfo.File -> TODO()
} }
} }
@ -91,16 +94,17 @@ class AttachmentsAdapter() : RecyclerView.Adapter<BaseViewHolder>() {
attachmentSourceProvider?.getAttachmentInfoAt(position)?.let { attachmentSourceProvider?.getAttachmentInfoAt(position)?.let {
holder.bind(it) holder.bind(it)
when (it) { when (it) {
is AttachmentInfo.Image -> { is AttachmentInfo.Image -> {
attachmentSourceProvider?.loadImage(holder as ZoomableImageViewHolder, it) attachmentSourceProvider?.loadImage((holder as ZoomableImageViewHolder).target, it)
} }
is AttachmentInfo.AnimatedImage -> { is AttachmentInfo.AnimatedImage -> {
attachmentSourceProvider?.loadImage(holder as AnimatedImageViewHolder, it) attachmentSourceProvider?.loadImage((holder as AnimatedImageViewHolder).target, it)
} }
is AttachmentInfo.Video -> { is AttachmentInfo.Video -> {
attachmentSourceProvider?.loadVideo(holder as VideoViewHolder, it) attachmentSourceProvider?.loadVideo((holder as VideoViewHolder).target, it)
}
else -> {
} }
else -> {}
} }
} }
} }
@ -134,35 +138,4 @@ class AttachmentsAdapter() : RecyclerView.Adapter<BaseViewHolder>() {
val holder = recyclerView?.findViewHolderForAdapterPosition(position) as? BaseViewHolder val holder = recyclerView?.findViewHolderForAdapterPosition(position) as? BaseViewHolder
holder?.entersForeground() 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()
// }
// }
// }

View file

@ -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)
}
}
}

View file

@ -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)
}
}

View file

@ -44,38 +44,13 @@ class VideoViewHolder constructor(itemView: View) :
var eventListener: WeakReference<AttachmentEventListener>? = null var eventListener: WeakReference<AttachmentEventListener>? = 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 thumbnailImage: ImageView = itemView.findViewById(R.id.videoThumbnailImage)
val videoView: VideoView = itemView.findViewById(R.id.videoView) val videoView: VideoView = itemView.findViewById(R.id.videoView)
val loaderProgressBar: ProgressBar = itemView.findViewById(R.id.videoLoaderProgress) val loaderProgressBar: ProgressBar = itemView.findViewById(R.id.videoLoaderProgress)
val videoControlIcon: ImageView = itemView.findViewById(R.id.videoControlIcon) val videoControlIcon: ImageView = itemView.findViewById(R.id.videoControlIcon)
val errorTextView: TextView = itemView.findViewById(R.id.videoMediaViewerErrorView) val errorTextView: TextView = itemView.findViewById(R.id.videoMediaViewerErrorView)
// val videoTarget = object : Target { internal val target = DefaultVideoLoaderTarget(this, thumbnailImage)
// 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?) {
// }
// }
override fun onRecycled() { override fun onRecycled() {
super.onRecycled() super.onRecycled()
@ -91,6 +66,9 @@ class VideoViewHolder constructor(itemView: View) :
} }
} }
fun videoFileLoadError() {
}
override fun entersBackground() { override fun entersBackground() {
if (videoView.isPlaying) { if (videoView.isPlaying) {
progress = videoView.currentPosition progress = videoView.currentPosition
@ -162,7 +140,7 @@ class VideoViewHolder constructor(itemView: View) :
wasPaused = true wasPaused = true
videoView.pause() videoView.pause()
} }
is AttachmentCommands.SeekTo -> { is AttachmentCommands.SeekTo -> {
val duration = videoView.duration val duration = videoView.duration
if (duration > 0) { if (duration > 0) {
val seekDuration = duration * (commands.percentProgress / 100f) val seekDuration = duration * (commands.percentProgress / 100f)
@ -173,6 +151,7 @@ class VideoViewHolder constructor(itemView: View) :
} }
override fun bind(attachmentInfo: AttachmentInfo) { override fun bind(attachmentInfo: AttachmentInfo) {
super.bind(attachmentInfo)
progress = 0 progress = 0
wasPaused = false wasPaused = false
} }

View file

@ -16,15 +16,9 @@
package im.vector.riotx.attachmentviewer package im.vector.riotx.attachmentviewer
import android.graphics.drawable.Drawable
import android.util.Log import android.util.Log
import android.view.View import android.view.View
import android.widget.LinearLayout
import android.widget.ProgressBar 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 import com.github.chrisbanes.photoview.PhotoView
class ZoomableImageViewHolder constructor(itemView: View) : class ZoomableImageViewHolder constructor(itemView: View) :
@ -45,31 +39,5 @@ class ZoomableImageViewHolder constructor(itemView: View) :
touchImageView.setAllowParentInterceptOnEdge(true) touchImageView.setAllowParentInterceptOnEdge(true)
} }
val customTargetView = object : CustomViewTarget<PhotoView, Drawable>(touchImageView) { internal val target = DefaultImageLoaderTarget.ZoomableImageTarget(this, 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<in Drawable>?) {
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) {
}
} }

View file

@ -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.model.message.getFileUrl
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
import im.vector.matrix.android.internal.crypto.attachments.toElementToDecrypt 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.AttachmentInfo
import im.vector.riotx.attachmentviewer.AttachmentSourceProvider import im.vector.riotx.attachmentviewer.AttachmentSourceProvider
import im.vector.riotx.attachmentviewer.VideoViewHolder import im.vector.riotx.attachmentviewer.ImageLoaderTarget
import im.vector.riotx.attachmentviewer.ZoomableImageViewHolder import im.vector.riotx.attachmentviewer.VideoLoaderTarget
import im.vector.riotx.core.date.VectorDateFormatter import im.vector.riotx.core.date.VectorDateFormatter
import im.vector.riotx.core.extensions.localDateTime import im.vector.riotx.core.extensions.localDateTime
import java.io.File import java.io.File
@ -86,13 +85,15 @@ class RoomAttachmentProvider(
) )
if (content.mimeType == "image/gif") { if (content.mimeType == "image/gif") {
AttachmentInfo.AnimatedImage( AttachmentInfo.AnimatedImage(
content.url ?: "", uid = it.eventId,
data url = content.url ?: "",
data = data
) )
} else { } else {
AttachmentInfo.Image( AttachmentInfo.Image(
content.url ?: "", uid = it.eventId,
data url = content.url ?: "",
data = data
) )
} }
} else if (content is MessageVideoContent) { } else if (content is MessageVideoContent) {
@ -117,9 +118,11 @@ class RoomAttachmentProvider(
thumbnailMediaData = thumbnailData thumbnailMediaData = thumbnailData
) )
AttachmentInfo.Video( AttachmentInfo.Video(
content.getFileUrl() ?: "", uid = it.eventId,
data, url = content.getFileUrl() ?: "",
AttachmentInfo.Image( data = data,
thumbnail = AttachmentInfo.Image(
uid = it.eventId,
url = content.videoInfo?.thumbnailFile?.url url = content.videoInfo?.thumbnailFile?.url
?: content.videoInfo?.thumbnailUrl ?: "", ?: content.videoInfo?.thumbnailUrl ?: "",
data = thumbnailData data = thumbnailData
@ -128,49 +131,72 @@ class RoomAttachmentProvider(
) )
} else { } else {
AttachmentInfo.Image( AttachmentInfo.Image(
"", uid = it.eventId,
null 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 { (info.data as? ImageContentRenderer.Data)?.let {
imageContentRenderer.render(it, holder.touchImageView, holder.customTargetView as CustomViewTarget<*, Drawable>) imageContentRenderer.render(it, target.contextView(), object : CustomViewTarget<ImageView, Drawable>(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<in Drawable>?) {
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 { (info.data as? ImageContentRenderer.Data)?.let {
imageContentRenderer.render(it, holder.touchImageView, holder.customTargetView as CustomViewTarget<*, Drawable>) imageContentRenderer.render(it, target.contextView(), object : CustomViewTarget<ImageView, Drawable>(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<in Drawable>?) {
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 val data = info.data as? VideoContentRenderer.Data ?: return
// videoContentRenderer.render(data, // videoContentRenderer.render(data,
// holder.thumbnailImage, // holder.thumbnailImage,
// holder.loaderProgressBar, // holder.loaderProgressBar,
// holder.videoView, // holder.videoView,
// holder.errorTextView) // holder.errorTextView)
imageContentRenderer.render(data.thumbnailMediaData, holder.thumbnailImage, object : CustomViewTarget<ImageView, Drawable>(holder.thumbnailImage) { imageContentRenderer.render(data.thumbnailMediaData, target.contextView(), object : CustomViewTarget<ImageView, Drawable>(target.contextView()) {
override fun onLoadFailed(errorDrawable: Drawable?) { override fun onLoadFailed(errorDrawable: Drawable?) {
holder.thumbnailImage.setImageDrawable(errorDrawable) target.onThumbnailLoadFailed(info.uid, errorDrawable)
} }
override fun onResourceCleared(placeholder: Drawable?) { override fun onResourceCleared(placeholder: Drawable?) {
target.onThumbnailResourceCleared(info.uid, placeholder)
} }
override fun onResourceReady(resource: Drawable, transition: Transition<in Drawable>?) { override fun onResourceReady(resource: Drawable, transition: Transition<in Drawable>?) {
holder.thumbnailImage.setImageDrawable(resource) target.onThumbnailResourceReady(info.uid, resource)
} }
}) })
holder.thumbnailImage.isVisible = false target.onVideoFileLoading(info.uid)
holder.loaderProgressBar.isVisible = false
holder.videoView.isVisible = false
fileService.downloadFile( fileService.downloadFile(
downloadMode = FileService.DownloadMode.FOR_INTERNAL_USE, downloadMode = FileService.DownloadMode.FOR_INTERNAL_USE,
id = data.eventId, id = data.eventId,
@ -180,11 +206,11 @@ class RoomAttachmentProvider(
url = data.url, url = data.url,
callback = object : MatrixCallback<File> { callback = object : MatrixCallback<File> {
override fun onSuccess(data: File) { override fun onSuccess(data: File) {
holder.videoReady(data) target.onVideoFileReady(info.uid, data)
} }
override fun onFailure(failure: Throwable) { 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() overlayView?.videoControlsGroup?.isVisible = item.root.isVideoMessage()
return overlayView return overlayView
} }
override fun clear(id: String) {
// TODO("Not yet implemented")
}
} }
class RoomAttachmentProviderFactory @Inject constructor( class RoomAttachmentProviderFactory @Inject constructor(