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 {
// 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'

View File

@ -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<ImageView, Drawable>(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) {
}
internal val target = DefaultImageLoaderTarget(this, this.touchImageView)
}

View File

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

View File

@ -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<BaseViewHolder>() {
var attachmentSourceProvider: AttachmentSourceProvider? = null
@ -65,21 +68,21 @@ class AttachmentsAdapter() : RecyclerView.Adapter<BaseViewHolder>() {
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<BaseViewHolder>() {
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<BaseViewHolder>() {
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()
// }
// }
// }

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
// 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
}

View File

@ -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<PhotoView, Drawable>(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) {
}
internal val target = DefaultImageLoaderTarget.ZoomableImageTarget(this, touchImageView)
}

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.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<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 {
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
// videoContentRenderer.render(data,
// holder.thumbnailImage,
// holder.loaderProgressBar,
// holder.videoView,
// 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?) {
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<in Drawable>?) {
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<File> {
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(